IopInvalidDeviceRequest must return STATUS_INVALID_DEVICE_REQUEST.
[reactos.git] / reactos / ntoskrnl / io / driver.c
index a6a59f8..7378a2c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: driver.c,v 1.31 2003/11/17 02:12:51 hyperion Exp $
+/* $Id: driver.c,v 1.51 2004/09/07 11:48:16 ekohl Exp $
  *
  * COPYRIGHT:      See COPYING in the top level directory
  * PROJECT:        ReactOS kernel
 
 /* INCLUDES *******************************************************************/
 
-#include <limits.h>
-#include <ddk/ntddk.h>
-#include <internal/io.h>
-#include <internal/po.h>
-#include <internal/ldr.h>
-#include <internal/id.h>
-#include <internal/pool.h>
-#include <internal/se.h>
-#include <internal/mm.h>
-#include <internal/ke.h>
-#include <internal/kd.h>
-#include <rosrtl/string.h>
-
-#include <roscfg.h>
-
+#include <ntoskrnl.h>
 #define NDEBUG
 #include <internal/debug.h>
 
 /* ke/main.c */
 extern LOADER_PARAMETER_BLOCK EXPORTED KeLoaderBlock;
 
-NTSTATUS
-IopInitializeService(
-  PDEVICE_NODE DeviceNode,
-  PUNICODE_STRING ImagePath);
-
 NTSTATUS
 LdrProcessModule(PVOID ModuleLoadBase,
                 PUNICODE_STRING ModuleName,
@@ -66,8 +47,20 @@ typedef struct _SERVICE
 /*  BOOLEAN ServiceRunning;*/  // needed ??
 } SERVICE, *PSERVICE;
 
+typedef struct _DRIVER_REINIT_ITEM
+{
+  LIST_ENTRY ItemEntry;
+  PDRIVER_OBJECT DriverObject;
+  PDRIVER_REINITIALIZE ReinitRoutine;
+  PVOID Context;
+} DRIVER_REINIT_ITEM, *PDRIVER_REINIT_ITEM;
+
 /* GLOBALS ********************************************************************/
 
+static LIST_ENTRY DriverReinitListHead;
+static PLIST_ENTRY DriverReinitTailEntry;
+static KSPIN_LOCK DriverReinitListLock;
+
 static LIST_ENTRY GroupListHead = {NULL, NULL};
 static LIST_ENTRY ServiceListHead  = {NULL, NULL};
 
@@ -76,52 +69,640 @@ POBJECT_TYPE EXPORTED IoDriverObjectType = NULL;
 #define TAG_DRIVER             TAG('D', 'R', 'V', 'R')
 #define TAG_DRIVER_EXTENSION   TAG('D', 'R', 'V', 'E')
 
+/* DECLARATIONS ***************************************************************/
+
+NTSTATUS STDCALL
+IopCreateDriver(
+   PVOID ObjectBody,
+   PVOID Parent,
+   PWSTR RemainingPath,
+   POBJECT_ATTRIBUTES ObjectAttributes);
+
+VOID STDCALL
+IopDeleteDriver(PVOID ObjectBody);
+
 /* PRIVATE FUNCTIONS **********************************************************/
 
+VOID INIT_FUNCTION
+IopInitDriverImplementation(VOID)
+{
+   /* Register the process object type */
+   IoDriverObjectType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
+   IoDriverObjectType->Tag = TAG('D', 'R', 'V', 'R');
+   IoDriverObjectType->TotalObjects = 0;
+   IoDriverObjectType->TotalHandles = 0;
+   IoDriverObjectType->MaxObjects = ULONG_MAX;
+   IoDriverObjectType->MaxHandles = ULONG_MAX;
+   IoDriverObjectType->PagedPoolCharge = 0;
+   IoDriverObjectType->NonpagedPoolCharge = sizeof(DRIVER_OBJECT);
+   IoDriverObjectType->Dump = NULL;
+   IoDriverObjectType->Open = NULL;
+   IoDriverObjectType->Close = NULL;
+   IoDriverObjectType->Delete = IopDeleteDriver;
+   IoDriverObjectType->Parse = NULL;
+   IoDriverObjectType->Security = NULL;
+   IoDriverObjectType->QueryName = NULL;
+   IoDriverObjectType->OkayToClose = NULL;
+   IoDriverObjectType->Create = IopCreateDriver;
+   IoDriverObjectType->DuplicationNotify = NULL;
+   RtlRosInitUnicodeStringFromLiteral(&IoDriverObjectType->TypeName, L"Driver");
+
+   ObpCreateTypeObject(IoDriverObjectType);
+
+   InitializeListHead(&DriverReinitListHead);
+   KeInitializeSpinLock(&DriverReinitListLock);
+   DriverReinitTailEntry = NULL;
+}
+
 NTSTATUS STDCALL
-IopCreateDriver(PVOID ObjectBody,
-               PVOID Parent,
-               PWSTR RemainingPath,
-               POBJECT_ATTRIBUTES ObjectAttributes)
+IopInvalidDeviceRequest(
+   PDEVICE_OBJECT DeviceObject,
+   PIRP Irp)
 {
-  DPRINT("LdrCreateModule(ObjectBody %x, Parent %x, RemainingPath %S)\n",
-        ObjectBody,
-        Parent,
-        RemainingPath);
-  if (RemainingPath != NULL && wcschr(RemainingPath + 1, '\\') != NULL)
-    {
-      return(STATUS_UNSUCCESSFUL);
-    }
+   Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
+   Irp->IoStatus.Information = 0;
+   IoCompleteRequest(Irp, IO_NO_INCREMENT);
+   return STATUS_INVALID_DEVICE_REQUEST;
+}
 
-  return(STATUS_SUCCESS);
+NTSTATUS STDCALL
+IopCreateDriver(
+   PVOID ObjectBody,
+   PVOID Parent,
+   PWSTR RemainingPath,
+   POBJECT_ATTRIBUTES ObjectAttributes)
+{
+   PDRIVER_OBJECT Object = ObjectBody;
+   ULONG i;
+
+   DPRINT("IopCreateDriver(ObjectBody %x, Parent %x, RemainingPath %S)\n",
+      ObjectBody, Parent, RemainingPath);
+
+   if (RemainingPath != NULL && wcschr(RemainingPath + 1, '\\') != NULL)
+      return STATUS_UNSUCCESSFUL;
+
+   /* Create driver extension */
+   Object->DriverExtension = (PDRIVER_EXTENSION)
+      ExAllocatePoolWithTag(
+         NonPagedPool,
+         sizeof(DRIVER_EXTENSION),
+         TAG_DRIVER_EXTENSION);
+
+   if (Object->DriverExtension == NULL)
+   {
+      return STATUS_NO_MEMORY;
+   }
+
+   RtlZeroMemory(Object->DriverExtension, sizeof(DRIVER_EXTENSION));
+
+   Object->Type = InternalDriverType;
+
+   for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
+      Object->MajorFunction[i] = IopInvalidDeviceRequest;
+
+   return STATUS_SUCCESS;
 }
 
+VOID STDCALL
+IopDeleteDriver(PVOID ObjectBody)
+{
+   PDRIVER_OBJECT Object = ObjectBody;
+   KIRQL OldIrql;
+   PPRIVATE_DRIVER_EXTENSIONS DriverExtension, NextDriverExtension;
 
-VOID INIT_FUNCTION
-IopInitDriverImplementation(VOID)
+   DPRINT("IopDeleteDriver(ObjectBody %x)\n", ObjectBody);
+
+   ExFreePool(Object->DriverExtension);
+
+   OldIrql = KeRaiseIrqlToDpcLevel();
+
+   for (DriverExtension = Object->DriverSection;
+        DriverExtension != NULL;
+        DriverExtension = NextDriverExtension)
+   {
+      NextDriverExtension = DriverExtension->Link;
+      ExFreePool(DriverExtension);
+   }
+
+   KfLowerIrql(OldIrql);
+}
+
+NTSTATUS FASTCALL
+IopCreateDriverObject(
+   PDRIVER_OBJECT *DriverObject,
+   PUNICODE_STRING ServiceName,
+   BOOLEAN FileSystem,
+   PVOID DriverImageStart,
+   ULONG DriverImageSize)
+{
+   PDRIVER_OBJECT Object;
+   WCHAR NameBuffer[MAX_PATH];
+   UNICODE_STRING DriverName;
+   OBJECT_ATTRIBUTES ObjectAttributes;
+   NTSTATUS Status;
+
+   DPRINT("IopCreateDriverObject(%p '%wZ' %x %p %x)\n",
+      DriverObject, ServiceName, FileSystem, DriverImageStart, DriverImageSize);
+
+   *DriverObject = NULL;
+
+   /* Create ModuleName string */
+   if (ServiceName != NULL && ServiceName->Buffer != NULL)
+   {
+      if (FileSystem == TRUE)
+         wcscpy(NameBuffer, FILESYSTEM_ROOT_NAME);
+      else
+         wcscpy(NameBuffer, DRIVER_ROOT_NAME);
+      wcscat(NameBuffer, ServiceName->Buffer);
+
+      RtlInitUnicodeString(&DriverName, NameBuffer);
+      DPRINT("Driver name: '%wZ'\n", &DriverName);
+   }
+   else
+   {
+      RtlInitUnicodeString(&DriverName, NULL);
+   }
+
+   /* Initialize ObjectAttributes for driver object */
+   InitializeObjectAttributes(
+      &ObjectAttributes,
+      &DriverName,
+      OBJ_PERMANENT,
+      NULL,
+      NULL);
+
+   /* Create driver object */
+   Status = ObCreateObject(
+      KernelMode,
+      IoDriverObjectType,
+      &ObjectAttributes,
+      KernelMode,
+      NULL,
+      sizeof(DRIVER_OBJECT),
+      0,
+      0,
+      (PVOID*)&Object);
+
+   if (!NT_SUCCESS(Status))
+   {
+      return Status;
+   }
+
+   Object->DriverStart = DriverImageStart;
+   Object->DriverSize = DriverImageSize;
+
+   *DriverObject = Object;
+
+   return STATUS_SUCCESS;
+}
+
+/*
+ * IopDisplayLoadingMessage
+ *
+ * Display 'Loading XXX...' message.
+ */
+
+VOID FASTCALL
+IopDisplayLoadingMessage(PWCHAR ServiceName)
+{
+   CHAR TextBuffer[256];
+   sprintf(TextBuffer, "Loading %S...\n", ServiceName);
+   HalDisplayString(TextBuffer);
+}
+
+/*
+ * IopNormalizeImagePath
+ *
+ * Normalize an image path to contain complete path.
+ *
+ * Parameters
+ *    ImagePath
+ *       The input path and on exit the result path. ImagePath.Buffer
+ *       must be allocated by ExAllocatePool on input. Caller is responsible
+ *       for freeing the buffer when it's no longer needed.
+ *
+ *    ServiceName
+ *       Name of the service that ImagePath belongs to.
+ *
+ * Return Value
+ *    Status
+ *
+ * Remarks
+ *    The input image path isn't freed on error.
+ */
+
+NTSTATUS FASTCALL
+IopNormalizeImagePath(
+   IN OUT PUNICODE_STRING ImagePath,
+   IN PUNICODE_STRING ServiceName)
 {
-  /*  Register the process object type  */
-  IoDriverObjectType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
-  IoDriverObjectType->Tag = TAG('D', 'R', 'V', 'R');
-  IoDriverObjectType->TotalObjects = 0;
-  IoDriverObjectType->TotalHandles = 0;
-  IoDriverObjectType->MaxObjects = ULONG_MAX;
-  IoDriverObjectType->MaxHandles = ULONG_MAX;
-  IoDriverObjectType->PagedPoolCharge = 0;
-  IoDriverObjectType->NonpagedPoolCharge = sizeof(DRIVER_OBJECT);
-  IoDriverObjectType->Dump = NULL;
-  IoDriverObjectType->Open = NULL;
-  IoDriverObjectType->Close = NULL;
-  IoDriverObjectType->Delete = NULL;
-  IoDriverObjectType->Parse = NULL;
-  IoDriverObjectType->Security = NULL;
-  IoDriverObjectType->QueryName = NULL;
-  IoDriverObjectType->OkayToClose = NULL;
-  IoDriverObjectType->Create = IopCreateDriver;
-  IoDriverObjectType->DuplicationNotify = NULL;
-  RtlRosInitUnicodeStringFromLiteral(&IoDriverObjectType->TypeName, L"Driver");
-
-  ObpCreateTypeObject(IoDriverObjectType);
+   UNICODE_STRING InputImagePath;
+
+   RtlCopyMemory(
+      &InputImagePath,
+      ImagePath,
+      sizeof(UNICODE_STRING));
+
+   if (InputImagePath.Length == 0)
+   {
+      ImagePath->Length = (33 * sizeof(WCHAR)) + ServiceName->Length;
+      ImagePath->MaximumLength = ImagePath->Length + sizeof(UNICODE_NULL);
+      ImagePath->Buffer = ExAllocatePool(NonPagedPool, ImagePath->MaximumLength);
+      if (ImagePath->Buffer == NULL)
+         return STATUS_NO_MEMORY;
+
+      wcscpy(ImagePath->Buffer, L"\\SystemRoot\\system32\\drivers\\");
+      wcscat(ImagePath->Buffer, ServiceName->Buffer);
+      wcscat(ImagePath->Buffer, L".sys");
+   } else
+   if (InputImagePath.Buffer[0] != L'\\')
+   {
+      ImagePath->Length = (12 * sizeof(WCHAR)) + InputImagePath.Length;
+      ImagePath->MaximumLength = ImagePath->Length + sizeof(UNICODE_NULL);
+      ImagePath->Buffer = ExAllocatePool(NonPagedPool, ImagePath->MaximumLength);
+      if (ImagePath->Buffer == NULL)
+         return STATUS_NO_MEMORY;
+
+      wcscpy(ImagePath->Buffer, L"\\SystemRoot\\");
+      wcscat(ImagePath->Buffer, InputImagePath.Buffer);
+      RtlFreeUnicodeString(&InputImagePath);
+   }
+
+   return STATUS_SUCCESS;
+}
+
+/*
+ * IopLoadServiceModule
+ *
+ * Load a module specified by registry settings for service.
+ *
+ * Parameters
+ *    ServiceName
+ *       Name of the service to load.
+ *
+ * Return Value
+ *    Status
+ */
+
+NTSTATUS FASTCALL
+IopLoadServiceModule(
+   IN PUNICODE_STRING ServiceName,
+   OUT PMODULE_OBJECT *ModuleObject)
+{
+   RTL_QUERY_REGISTRY_TABLE QueryTable[3];
+   ULONG ServiceStart;
+   UNICODE_STRING ServiceImagePath;
+   NTSTATUS Status;
+
+   DPRINT("IopLoadServiceModule(%wZ, %x)\n", ServiceName, ModuleObject);
+
+   /*
+    * Get information about the service.
+    */
+
+   RtlZeroMemory(QueryTable, sizeof(QueryTable));
+
+   RtlInitUnicodeString(&ServiceImagePath, NULL);
+
+   QueryTable[0].Name = L"Start";
+   QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
+   QueryTable[0].EntryContext = &ServiceStart;
+
+   QueryTable[1].Name = L"ImagePath";
+   QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
+   QueryTable[1].EntryContext = &ServiceImagePath;
+
+   Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
+      ServiceName->Buffer, QueryTable, NULL, NULL);
+
+   if (!NT_SUCCESS(Status))
+   {
+      DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status);
+      return Status;
+   }
+
+   IopDisplayLoadingMessage(ServiceName->Buffer);
+
+   /*
+    * Normalize the image path for all later processing.
+    */
+
+   Status = IopNormalizeImagePath(&ServiceImagePath, ServiceName);
+
+   if (!NT_SUCCESS(Status))
+   {
+      DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status);
+      return Status;
+   }
+
+   /*
+    * Load the module.
+    */
+
+   *ModuleObject = LdrGetModuleObject(&ServiceImagePath);
+
+   if (*ModuleObject == NULL)
+   {
+      Status = STATUS_UNSUCCESSFUL;
+
+      /*
+       * Special case for boot modules that were loaded by boot loader.
+       */
+
+      if (ServiceStart == 0)
+      {
+         ULONG i;
+         CHAR SearchName[256];
+         PCHAR ModuleName;
+         PLOADER_MODULE KeLoaderModules =
+            (PLOADER_MODULE)KeLoaderBlock.ModsAddr;
+
+         /*
+          * FIXME:
+          * Improve this searching algorithm by using the image name
+          * stored in registry entry ImageName and use the whole path
+          * (requires change in FreeLoader).
+          */
+
+         _snprintf(SearchName, sizeof(SearchName), "%wZ.sys", ServiceName);
+         for (i = 1; i < KeLoaderBlock.ModsCount; i++)
+         {
+            ModuleName = (PCHAR)KeLoaderModules[i].String;
+            if (!_stricmp(ModuleName, SearchName))
+            {
+               DPRINT("Initializing boot module\n");
+
+               /* Tell, that the module is already loaded */
+               KeLoaderModules[i].Reserved = 1;
+
+               Status = LdrProcessModule(
+                  (PVOID)KeLoaderModules[i].ModStart,
+                  &ServiceImagePath,
+                  ModuleObject);
+
+               break;
+            }
+         }
+      }
+
+      /*
+       * Case for rest of the drivers (except disabled)
+       */
+
+      else if (ServiceStart < 4)
+      {
+         DPRINT("Loading module\n");
+         Status = LdrLoadModule(&ServiceImagePath, ModuleObject);
+      }
+   }
+   else
+   {
+      DPRINT("Module already loaded\n");
+      Status = STATUS_SUCCESS;
+   }
+
+   RtlFreeUnicodeString(&ServiceImagePath);
+
+   /*
+    * Now check if the module was loaded successfully.
+    */
+
+   if (!NT_SUCCESS(Status))
+   {
+      DPRINT("Module loading failed (Status %x)\n", Status);
+   }
+
+   DPRINT("Module loading (Status %x)\n", Status);
+
+   return Status;
+}
+
+/*
+ * IopInitializeDriverModule
+ *
+ * Initalize a loaded driver.
+ *
+ * Parameters
+ *    DeviceNode
+ *       Pointer to device node.
+ *
+ *    ModuleObject
+ *       Module object representing the driver. It can be retrieve by
+ *       IopLoadServiceModule.
+ *
+ *    FileSystemDriver
+ *       Set to TRUE for file system drivers.
+ *
+ *    DriverObject
+ *       On successful return this contains the driver object representing
+ *       the loaded driver.
+ */
+
+NTSTATUS FASTCALL
+IopInitializeDriverModule(
+   IN PDEVICE_NODE DeviceNode,
+   IN PMODULE_OBJECT ModuleObject,
+   IN BOOLEAN FileSystemDriver,
+   OUT PDRIVER_OBJECT *DriverObject)
+{
+   UNICODE_STRING RegistryKey;
+   PDRIVER_INITIALIZE DriverEntry = ModuleObject->EntryPoint;
+   NTSTATUS Status;
+   WCHAR ServicesKeyName[] = L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
+
+   Status = IopCreateDriverObject(
+      DriverObject,
+      &DeviceNode->ServiceName,
+      FileSystemDriver,
+      ModuleObject->Base,
+      ModuleObject->Length);
+
+   if (!NT_SUCCESS(Status))
+   {
+      DPRINT("IopCreateDriverObject failed (Status %x)\n", Status);
+      return Status;
+   }
+
+   if (DeviceNode->ServiceName.Buffer)
+   {
+      RegistryKey.Length = DeviceNode->ServiceName.Length +
+         sizeof(ServicesKeyName);
+      RegistryKey.MaximumLength = RegistryKey.Length + sizeof(UNICODE_NULL);
+      RegistryKey.Buffer = ExAllocatePool(PagedPool, RegistryKey.MaximumLength);
+      wcscpy(RegistryKey.Buffer, ServicesKeyName);
+      wcscat(RegistryKey.Buffer, DeviceNode->ServiceName.Buffer);
+   }
+   else
+   {
+      RtlInitUnicodeString(&RegistryKey, NULL);
+   }
+
+   DPRINT("RegistryKey: %wZ\n", &RegistryKey);
+   DPRINT("Calling driver entrypoint at %08lx\n", DriverEntry);
+
+   IopMarkLastReinitializeDriver();
+
+   Status = DriverEntry(*DriverObject, &RegistryKey);
+   if (!NT_SUCCESS(Status))
+   {
+      ObMakeTemporaryObject(*DriverObject);
+      ObDereferenceObject(*DriverObject);
+      return Status;
+   }
+
+   IopReinitializeDrivers();
+
+   return STATUS_SUCCESS;
+}
+
+/*
+ * IopAttachFilterDriversCallback
+ *
+ * Internal routine used by IopAttachFilterDrivers.
+ */
+
+NTSTATUS STDCALL
+IopAttachFilterDriversCallback(
+   PWSTR ValueName,
+   ULONG ValueType,
+   PVOID ValueData,
+   ULONG ValueLength,
+   PVOID Context,
+   PVOID EntryContext)
+{
+   PDEVICE_NODE DeviceNode = Context;
+   UNICODE_STRING ServiceName;
+   PWCHAR Filters;
+   PMODULE_OBJECT ModuleObject;
+   PDRIVER_OBJECT DriverObject;
+   NTSTATUS Status;
+   
+   for (Filters = ValueData;
+        ((ULONG_PTR)Filters - (ULONG_PTR)ValueData) < ValueLength &&
+        *Filters != 0;
+        Filters += (ServiceName.Length / sizeof(WCHAR)) + 1)
+   {
+      DPRINT("Filter Driver: %S (%wZ)\n", Filters, &DeviceNode->InstancePath);
+      ServiceName.Buffer = Filters;
+      ServiceName.MaximumLength = 
+      ServiceName.Length = wcslen(Filters) * sizeof(WCHAR);
+
+      /* Load and initialize the filter driver */
+      Status = IopLoadServiceModule(&ServiceName, &ModuleObject);
+      if (!NT_SUCCESS(Status))
+         continue;
+
+      Status = IopInitializeDriverModule(DeviceNode, ModuleObject, FALSE, &DriverObject);
+      if (!NT_SUCCESS(Status))
+         continue;
+
+      Status = IopInitializeDevice(DeviceNode, DriverObject);
+      if (!NT_SUCCESS(Status))
+         continue;
+   }
+
+   return STATUS_SUCCESS;
+}
+
+/*
+ * IopAttachFilterDrivers
+ *
+ * Load filter drivers for specified device node.
+ *
+ * Parameters
+ *    Lower
+ *       Set to TRUE for loading lower level filters or FALSE for upper
+ *       level filters.
+ */
+
+NTSTATUS FASTCALL
+IopAttachFilterDrivers(
+   PDEVICE_NODE DeviceNode,
+   BOOLEAN Lower)
+{
+   RTL_QUERY_REGISTRY_TABLE QueryTable[2];
+   PWCHAR KeyBuffer;
+   UNICODE_STRING Class;
+   WCHAR ClassBuffer[40];
+   NTSTATUS Status;
+
+   /*
+    * First load the device filters
+    */
+   
+   QueryTable[0].QueryRoutine = IopAttachFilterDriversCallback;
+   if (Lower)
+     QueryTable[0].Name = L"LowerFilters";
+   else
+     QueryTable[0].Name = L"UpperFilters";
+   QueryTable[0].EntryContext = NULL;
+   QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
+   QueryTable[1].QueryRoutine = NULL;
+   QueryTable[1].Name = NULL;
+
+   KeyBuffer = ExAllocatePool(
+      PagedPool, 
+      (49 * sizeof(WCHAR)) + DeviceNode->InstancePath.Length);
+   wcscpy(KeyBuffer, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
+   wcscat(KeyBuffer, DeviceNode->InstancePath.Buffer);  
+
+   RtlQueryRegistryValues(
+      RTL_REGISTRY_ABSOLUTE,
+      KeyBuffer,
+      QueryTable,
+      DeviceNode,
+      NULL);
+
+   /*
+    * Now get the class GUID
+    */
+
+   Class.Length = 0;
+   Class.MaximumLength = 40 * sizeof(WCHAR);
+   Class.Buffer = ClassBuffer;
+   QueryTable[0].QueryRoutine = NULL;
+   QueryTable[0].Name = L"ClassGUID";
+   QueryTable[0].EntryContext = &Class;
+   QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT;
+
+   Status = RtlQueryRegistryValues(
+      RTL_REGISTRY_ABSOLUTE,
+      KeyBuffer,
+      QueryTable,
+      DeviceNode,
+      NULL);
+
+   ExFreePool(KeyBuffer);
+
+   /*
+    * Load the class filter driver
+    */
+
+   if (NT_SUCCESS(Status))
+   {
+      QueryTable[0].QueryRoutine = IopAttachFilterDriversCallback;
+      if (Lower)
+         QueryTable[0].Name = L"LowerFilters";
+      else
+         QueryTable[0].Name = L"UpperFilters";
+      QueryTable[0].EntryContext = NULL;
+      QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
+
+      KeyBuffer = ExAllocatePool(PagedPool, (58 * sizeof(WCHAR)) + Class.Length);
+      wcscpy(KeyBuffer, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\");
+      wcscat(KeyBuffer, ClassBuffer);
+
+      RtlQueryRegistryValues(
+         RTL_REGISTRY_ABSOLUTE,
+         KeyBuffer,
+         QueryTable,
+         DeviceNode,
+         NULL);
+
+      ExFreePool(KeyBuffer);
+   }
+   
+   return STATUS_SUCCESS;
 }
 
 static NTSTATUS STDCALL
@@ -400,26 +981,12 @@ IoDestroyDriverList(VOID)
 VOID STATIC
 MiFreeBootDriverMemory(PVOID StartAddress, ULONG Length)
 {
-  ULONG i;
-
-  for (i = 0; i < PAGE_ROUND_UP(Length)/PAGE_SIZE; i++)
-  {
-     MmDeleteVirtualMapping(NULL, StartAddress + i * PAGE_SIZE, TRUE, NULL, NULL);
-  }
-}
-
-/*
- * IopDisplayLoadingMessage
- *
- * Display 'Loading XXX...' message.
- */
+   ULONG i;
 
-VOID
-IopDisplayLoadingMessage(PWCHAR ServiceName)
-{
-   CHAR TextBuffer[256];
-   sprintf(TextBuffer, "Loading %S...\n", ServiceName);
-   HalDisplayString(TextBuffer);
+   for (i = 0; i < PAGE_ROUND_UP(Length) / PAGE_SIZE; i++)
+   {
+      MmDeleteVirtualMapping(NULL, (char*)StartAddress + i * PAGE_SIZE, TRUE, NULL, NULL);
+   }
 }
 
 /*
@@ -428,7 +995,7 @@ IopDisplayLoadingMessage(PWCHAR ServiceName)
  * Initialize a driver that is already loaded in memory.
  */
 
-NTSTATUS INIT_FUNCTION
+NTSTATUS FASTCALL
 IopInitializeBuiltinDriver(
    PDEVICE_NODE ModuleDeviceNode,
    PVOID ModuleLoadBase,
@@ -437,6 +1004,7 @@ IopInitializeBuiltinDriver(
 {
    PMODULE_OBJECT ModuleObject;
    PDEVICE_NODE DeviceNode;
+   PDRIVER_OBJECT DriverObject;
    NTSTATUS Status;
    CHAR TextBuffer[256];
    PCHAR FileNameWithoutPath;
@@ -448,12 +1016,14 @@ IopInitializeBuiltinDriver(
    /*
     * Display 'Initializing XXX...' message
     */
+
    sprintf(TextBuffer, "Initializing %s...\n", FileName);
    HalDisplayString(TextBuffer);
 
    /*
     * Determine the right device object
     */
+
    if (ModuleDeviceNode == NULL)
    {
       /* Use IopRootDeviceNode for now */
@@ -471,6 +1041,7 @@ IopInitializeBuiltinDriver(
    /*
     * Generate filename without path (not needed by freeldr)
     */
+
    FileNameWithoutPath = strrchr(FileName, '\\');
    if (FileNameWithoutPath == NULL)
    {
@@ -480,6 +1051,7 @@ IopInitializeBuiltinDriver(
    /*
     * Load the module
     */
+
    RtlCreateUnicodeStringFromAsciiz(&DeviceNode->ServiceName,
       FileNameWithoutPath);
    Status = LdrProcessModule(ModuleLoadBase, &DeviceNode->ServiceName,
@@ -495,25 +1067,31 @@ IopInitializeBuiltinDriver(
    /*
     * Strip the file extension from ServiceName
     */
+
    FileExtension = wcsrchr(DeviceNode->ServiceName.Buffer, '.');
    if (FileExtension != NULL)
    {
-      DeviceNode->ServiceName.Length -= wcslen(DeviceNode->ServiceName.Buffer);
+      DeviceNode->ServiceName.Length -= wcslen(FileExtension) * sizeof(WCHAR);
       FileExtension[0] = 0;
    }
 
    /*
     * Initialize the driver
     */
-   Status = IopInitializeDriver(ModuleObject->EntryPoint, DeviceNode,
-      FALSE, ModuleObject->Base, ModuleObject->Length, TRUE);
+
+   Status = IopInitializeDriverModule(DeviceNode, ModuleObject, FALSE,
+      &DriverObject);
+   
    if (!NT_SUCCESS(Status))
    {
       if (ModuleDeviceNode == NULL)
          IopFreeDeviceNode(DeviceNode);
       CPRINT("Driver load failed, status (%x)\n", Status);
+      return Status;
    }
 
+   Status = IopInitializeDevice(DeviceNode, DriverObject);
+
    return Status;
 }
 
@@ -529,7 +1107,7 @@ IopInitializeBuiltinDriver(
  *    None
  */
 
-VOID INIT_FUNCTION
+VOID FASTCALL
 IopInitializeBootDrivers(VOID)
 {
    ULONG BootDriverCount;
@@ -557,6 +1135,7 @@ IopInitializeBootDrivers(VOID)
       /*
        * Pass symbol files to kernel debugger
        */
+
       if (!_stricmp(Extension, ".sym"))
       {
          KDB_SYMBOLFILE_HOOK((PVOID)ModuleStart, ModuleName, ModuleSize);
@@ -565,6 +1144,7 @@ IopInitializeBootDrivers(VOID)
       /*
        * Load builtin driver
        */
+
       if (!_stricmp(Extension, ".sys"))
       {
          if (!ModuleLoaded)
@@ -578,303 +1158,104 @@ IopInitializeBootDrivers(VOID)
       /*
        * Free memory for all boot files, except ntoskrnl.exe and hal.dll
        */
+
 #ifdef KDBG
       /*
        * Do not free the memory from symbol files, if the kernel debugger
        * is active
        */
-      if (!_stricmp(Extension, ".sym"))
+      if (_stricmp(Extension, ".sym"))
 #endif
       {
          MiFreeBootDriverMemory((PVOID)KeLoaderModules[i].ModStart,
-            KeLoaderModules[i].ModEnd - KeLoaderModules[i].ModStart);
-      }
-   }
-
-   if (BootDriverCount == 0)
-   {
-      DbgPrint("No boot drivers available.\n");
-      KEBUGCHECK(0);
-   }
-}
-
-/*
- * IopInitializeSystemDrivers
- *
- * Load drivers marked as system start.
- *
- * Parameters
- *    None
- *             
- * Return Value
- *    None
- */
-
-VOID INIT_FUNCTION
-IopInitializeSystemDrivers(VOID)
-{
-   PLIST_ENTRY GroupEntry;
-   PLIST_ENTRY ServiceEntry;
-   PSERVICE_GROUP CurrentGroup;
-   PSERVICE CurrentService;
-   NTSTATUS Status;
-
-   DPRINT("IopInitializeSystemDrivers()\n");
-
-   GroupEntry = GroupListHead.Flink;
-   while (GroupEntry != &GroupListHead)
-   {
-      CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry);
-
-      DPRINT("Group: %wZ\n", &CurrentGroup->GroupName);
-
-      ServiceEntry = ServiceListHead.Flink;
-      while (ServiceEntry != &ServiceListHead)
-      {
-         CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
-
-         if ((RtlCompareUnicodeString(&CurrentGroup->GroupName,
-              &CurrentService->ServiceGroup, TRUE) == 0) &&
-            (CurrentService->Start == 1 /*SERVICE_SYSTEM_START*/))
-        {
-            DPRINT("  Path: %wZ\n", &CurrentService->RegistryPath);
-            IopDisplayLoadingMessage(CurrentService->ServiceName.Buffer);
-            Status = NtLoadDriver(&CurrentService->RegistryPath);
-            if (!NT_SUCCESS(Status))
-            {
-               DPRINT("NtLoadDriver() failed (Status %lx)\n", Status);
-#if 0
-               if (CurrentService->ErrorControl == 1)
-               {
-                  /* Log error */
-               } else
-               if (CurrentService->ErrorControl == 2)
-               {
-                  if (IsLastKnownGood == FALSE)
-                  {
-                     /* Boot last known good configuration */
-                  }
-               } else
-               if (CurrentService->ErrorControl == 3)
-               {
-                  if (IsLastKnownGood == FALSE)
-                  {
-                     /* Boot last known good configuration */
-                  } else
-                  {
-                     /* BSOD! */
-                  }
-               }
-#endif
-            }
-        }
-         ServiceEntry = ServiceEntry->Flink;
-      }
-
-      GroupEntry = GroupEntry->Flink;
-   }
-
-   DPRINT("IopInitializeSystemDrivers() done\n");
-}
-
-/*
- * IopGetDriverNameFromServiceKey
- *
- * Returns a module path from service registry key.
- *
- * Parameters
- *    RelativeTo
- *       Relative path identifier.
- *    PathName
- *       Relative key path name.
- *    ImagePath
- *       The result path.
- *
- * Return Value
- *    Status
- */
-
-NTSTATUS STDCALL
-IopGetDriverNameFromServiceKey(
-  ULONG RelativeTo,
-  PWSTR PathName,
-  PUNICODE_STRING ImagePath)
-{
-   RTL_QUERY_REGISTRY_TABLE QueryTable[2];
-   UNICODE_STRING RegistryImagePath;
-   NTSTATUS Status;
-   PWSTR ServiceName;
-
-   RtlZeroMemory(&QueryTable, sizeof(QueryTable));
-   RtlInitUnicodeString(&RegistryImagePath, NULL);
-
-   QueryTable[0].Name = L"ImagePath";
-   QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
-   QueryTable[0].EntryContext = &RegistryImagePath;
-
-   Status = RtlQueryRegistryValues(RelativeTo,
-      PathName, QueryTable, NULL, NULL);
-   if (!NT_SUCCESS(Status))
-   {
-      DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
-      RtlFreeUnicodeString(&RegistryImagePath);
-      return STATUS_UNSUCCESSFUL;
-   }
-
-   if (RegistryImagePath.Length == 0)
-   {
-      ServiceName = wcsrchr(PathName, L'\\');
-      if (ServiceName == NULL)
-      {
-         ServiceName = PathName;
-      }
-      else
-      {
-         ServiceName++;
-      }
-      
-      ImagePath->Length = (33 + wcslen(ServiceName)) * sizeof(WCHAR);
-      ImagePath->MaximumLength = ImagePath->Length + sizeof(UNICODE_NULL);
-      ImagePath->Buffer = ExAllocatePool(NonPagedPool, ImagePath->MaximumLength);
-      if (ImagePath->Buffer == NULL)
-      {
-         return STATUS_UNSUCCESSFUL;
-      }
-      wcscpy(ImagePath->Buffer, L"\\SystemRoot\\system32\\drivers\\");
-      wcscat(ImagePath->Buffer, ServiceName);
-      wcscat(ImagePath->Buffer, L".sys");
-   } else
-   if (RegistryImagePath.Buffer[0] != L'\\')
-   {
-      ImagePath->Length = (12 + wcslen(RegistryImagePath.Buffer)) * sizeof(WCHAR);
-      ImagePath->MaximumLength = ImagePath->Length + sizeof(UNICODE_NULL);
-      ImagePath->Buffer = ExAllocatePool(NonPagedPool, ImagePath->MaximumLength);
-      if (ImagePath->Buffer == NULL)
-      {
-         RtlFreeUnicodeString(&RegistryImagePath);
-         return STATUS_UNSUCCESSFUL;
-      }
-      wcscpy(ImagePath->Buffer, L"\\SystemRoot\\");
-      wcscat(ImagePath->Buffer, RegistryImagePath.Buffer);
-      RtlFreeUnicodeString(&RegistryImagePath);
-   } else
-   {
-      ImagePath->Length = RegistryImagePath.Length;
-      ImagePath->MaximumLength = RegistryImagePath.MaximumLength;
-      ImagePath->Buffer = RegistryImagePath.Buffer;
+            KeLoaderModules[i].ModEnd - KeLoaderModules[i].ModStart);
+      }
    }
 
-   return STATUS_SUCCESS;
+   if (BootDriverCount == 0)
+   {
+      DbgPrint("No boot drivers available.\n");
+      KEBUGCHECK(0);
+   }
 }
 
 /*
- * IopInitializeDeviceNodeService
+ * IopInitializeSystemDrivers
  *
- * Initialize service for given device node.
+ * Load drivers marked as system start.
  *
  * Parameters
- *    DeviceNode
- *       The device node to initialize service for.
- *    BootDriverOnly
- *       Initialize driver only if it's marked as boot start.
- *
+ *    None
+ *             
  * Return Value
- *    Status
+ *    None
  */
 
-NTSTATUS
-IopInitializeDeviceNodeService(PDEVICE_NODE DeviceNode, BOOLEAN BootDriverOnly)
+VOID FASTCALL
+IopInitializeSystemDrivers(VOID)
 {
+   PLIST_ENTRY GroupEntry;
+   PLIST_ENTRY ServiceEntry;
+   PSERVICE_GROUP CurrentGroup;
+   PSERVICE CurrentService;
    NTSTATUS Status;
 
-   if (DeviceNode->ServiceName.Buffer == NULL)
-   {
-      return STATUS_UNSUCCESSFUL;
-   }
+   DPRINT("IopInitializeSystemDrivers()\n");
 
-   if (BootDriverOnly)
+   GroupEntry = GroupListHead.Flink;
+   while (GroupEntry != &GroupListHead)
    {
-      ULONG ServiceStart;
-      RTL_QUERY_REGISTRY_TABLE QueryTable[2];
-      PLOADER_MODULE KeLoaderModules = (PLOADER_MODULE)KeLoaderBlock.ModsAddr;
+      CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry);
 
-      /*
-       * Get service start value
-       */
-      RtlZeroMemory(QueryTable, sizeof(QueryTable));
-      QueryTable[0].Name = L"Start";
-      QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
-      QueryTable[0].EntryContext = &ServiceStart;
-      Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
-         DeviceNode->ServiceName.Buffer, QueryTable, NULL, NULL);
-      if (!NT_SUCCESS(Status))
-      {
-         DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status);
-         return Status;
-      }
+      DPRINT("Group: %wZ\n", &CurrentGroup->GroupName);
 
-      /*
-       * Find and initialize boot driver
-       */
-      if (ServiceStart == 0 /*SERVICE_BOOT_START*/)
+      ServiceEntry = ServiceListHead.Flink;
+      while (ServiceEntry != &ServiceListHead)
       {
-         ULONG i;
-         CHAR SearchName[256];
-         ULONG ModuleStart, ModuleSize;
-         PCHAR ModuleName;
+         CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
 
-         /* FIXME: Guard for buffer overflow */
-         sprintf(SearchName, "%S.sys", DeviceNode->ServiceName.Buffer);
-         for (i = 1; i < KeLoaderBlock.ModsCount; i++)
-         {
-            ModuleStart = KeLoaderModules[i].ModStart;
-            ModuleSize = KeLoaderModules[i].ModEnd - ModuleStart;
-            ModuleName = (PCHAR)KeLoaderModules[i].String;
-            if (!strcmp(ModuleName, SearchName))
+         if ((RtlCompareUnicodeString(&CurrentGroup->GroupName,
+              &CurrentService->ServiceGroup, TRUE) == 0) &&
+            (CurrentService->Start == 1 /*SERVICE_SYSTEM_START*/))
+        {
+            DPRINT("  Path: %wZ\n", &CurrentService->RegistryPath);
+            IopDisplayLoadingMessage(CurrentService->ServiceName.Buffer);
+            Status = NtLoadDriver(&CurrentService->RegistryPath);
+            if (!NT_SUCCESS(Status))
             {
-               IopInitializeBuiltinDriver(DeviceNode,
-                  (PVOID)ModuleStart, ModuleName, ModuleSize);
-               /* Tell, that the module is already loaded */
-               KeLoaderModules[i].Reserved = 1;
+               DPRINT("NtLoadDriver() failed (Status %lx)\n", Status);
+#if 0
+               if (CurrentService->ErrorControl == 1)
+               {
+                  /* Log error */
+               } else
+               if (CurrentService->ErrorControl == 2)
+               {
+                  if (IsLastKnownGood == FALSE)
+                  {
+                     /* Boot last known good configuration */
+                  }
+               } else
+               if (CurrentService->ErrorControl == 3)
+               {
+                  if (IsLastKnownGood == FALSE)
+                  {
+                     /* Boot last known good configuration */
+                  } else
+                  {
+                     /* BSOD! */
+                  }
+               }
+#endif
             }
-         }
-         return STATUS_SUCCESS;
-      } else
-      {
-         return STATUS_UNSUCCESSFUL;
-      }
-   } else
-   {
-      UNICODE_STRING ImagePath;
-
-      /*
-       * Get service path
-       */
-      Status = IopGetDriverNameFromServiceKey(RTL_REGISTRY_SERVICES,
-          DeviceNode->ServiceName.Buffer, &ImagePath);
-      if (!NT_SUCCESS(Status))
-      {
-         DPRINT("IopGetDriverNameFromKeyNode() failed (Status %x)\n", Status);
-         return Status;
+        }
+         ServiceEntry = ServiceEntry->Flink;
       }
 
-      /*
-       * Display loading message
-       */
-      IopDisplayLoadingMessage(DeviceNode->ServiceName.Buffer);
-
-      /*
-       * Load the service
-       */
-      Status = IopInitializeService(DeviceNode, &ImagePath);
-
-      /*
-       * Free the service path
-       */
-      RtlFreeUnicodeString(&ImagePath);
+      GroupEntry = GroupEntry->Flink;
    }
 
-   return Status;
+   DPRINT("IopInitializeSystemDrivers() done\n");
 }
 
 /*
@@ -885,6 +1266,7 @@ IopInitializeDeviceNodeService(PDEVICE_NODE DeviceNode, BOOLEAN BootDriverOnly)
  * Parameters
  *    DriverServiceName
  *       Name of the service to unload (registry key).
+ *
  *    UnloadPnpDrivers
  *       Whether to unload Plug & Plug or only legacy drivers. If this
  *       parameter is set to FALSE, the routine will unload only legacy
@@ -900,7 +1282,9 @@ IopInitializeDeviceNodeService(PDEVICE_NODE DeviceNode, BOOLEAN BootDriverOnly)
 NTSTATUS STDCALL
 IopUnloadDriver(PUNICODE_STRING DriverServiceName, BOOLEAN UnloadPnpDrivers)
 {
+   RTL_QUERY_REGISTRY_TABLE QueryTable[2];
    UNICODE_STRING ImagePath;
+   UNICODE_STRING ServiceName;
    UNICODE_STRING ObjectName;
    PDRIVER_OBJECT DriverObject;
    PMODULE_OBJECT ModuleObject;
@@ -910,17 +1294,21 @@ IopUnloadDriver(PUNICODE_STRING DriverServiceName, BOOLEAN UnloadPnpDrivers)
    DPRINT("IopUnloadDriver('%wZ', %d)\n", DriverServiceName, UnloadPnpDrivers);
 
    /*
-    * Get the service name from the module name
+    * Get the service name from the registry key name
     */
+
    Start = wcsrchr(DriverServiceName->Buffer, L'\\');
    if (Start == NULL)
       Start = DriverServiceName->Buffer;
    else
       Start++;
 
+   RtlInitUnicodeString(&ServiceName, Start);
+
    /*
     * Construct the driver object name
     */
+
    ObjectName.Length = (wcslen(Start) + 8) * sizeof(WCHAR);
    ObjectName.MaximumLength = ObjectName.Length + sizeof(WCHAR);
    ObjectName.Buffer = ExAllocatePool(NonPagedPool, ObjectName.MaximumLength);
@@ -931,8 +1319,10 @@ IopUnloadDriver(PUNICODE_STRING DriverServiceName, BOOLEAN UnloadPnpDrivers)
    /*
     * Find the driver object
     */
+
    Status = ObReferenceObjectByName(&ObjectName, 0, 0, 0, IoDriverObjectType,
       KernelMode, 0, (PVOID*)&DriverObject);
+
    if (!NT_SUCCESS(Status))
    {
       DPRINT("Can't locate driver object for %wZ\n", ObjectName);
@@ -942,22 +1332,46 @@ IopUnloadDriver(PUNICODE_STRING DriverServiceName, BOOLEAN UnloadPnpDrivers)
    /*
     * Free the buffer for driver object name
     */
+
    ExFreePool(ObjectName.Buffer);
 
    /*
     * Get path of service...
     */
-   Status = IopGetDriverNameFromServiceKey(RTL_REGISTRY_ABSOLUTE,
-       DriverServiceName->Buffer, &ImagePath);
+
+   RtlZeroMemory(QueryTable, sizeof(QueryTable));
+
+   RtlInitUnicodeString(&ImagePath, NULL);
+
+   QueryTable[0].Name = L"ImagePath";
+   QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
+   QueryTable[0].EntryContext = &ImagePath;
+
+   Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
+       DriverServiceName->Buffer, QueryTable, NULL, NULL);
+
+   if (!NT_SUCCESS(Status))
+   {
+      DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status);
+      return Status;
+   }
+
+   /*
+    * Normalize the image path for all later processing.
+    */
+
+   Status = IopNormalizeImagePath(&ImagePath, &ServiceName);
+
    if (!NT_SUCCESS(Status))
    {
-      DPRINT("IopGetDriverNameFromKeyNode() failed (Status %x)\n", Status);
+      DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status);
       return Status;
    }
 
    /*
     * ... and check if it's loaded
     */
+
    ModuleObject = LdrGetModuleObject(&ImagePath);
    if (ModuleObject == NULL)
    {
@@ -967,11 +1381,13 @@ IopUnloadDriver(PUNICODE_STRING DriverServiceName, BOOLEAN UnloadPnpDrivers)
    /*
     * Free the service path
     */
+
    RtlFreeUnicodeString(&ImagePath);
 
    /*
     * Unload the module and release the references to the device object
     */
+
    if (DriverObject->DriverUnload)
       (*DriverObject->DriverUnload)(DriverObject);
    ObDereferenceObject(DriverObject);
@@ -981,7 +1397,100 @@ IopUnloadDriver(PUNICODE_STRING DriverServiceName, BOOLEAN UnloadPnpDrivers)
    return STATUS_SUCCESS;
 }
 
-/* FUNCTIONS ******************************************************************/
+VOID FASTCALL
+IopMarkLastReinitializeDriver(VOID)
+{
+  KIRQL Irql;
+
+  KeAcquireSpinLock(&DriverReinitListLock,
+                   &Irql);
+
+  if (IsListEmpty(&DriverReinitListHead))
+  {
+    DriverReinitTailEntry = NULL;
+  }
+  else
+  {
+    DriverReinitTailEntry = DriverReinitListHead.Blink;
+  }
+
+  KeReleaseSpinLock(&DriverReinitListLock,
+                   Irql);
+}
+
+
+VOID FASTCALL
+IopReinitializeDrivers(VOID)
+{
+  PDRIVER_REINIT_ITEM ReinitItem;
+  PLIST_ENTRY Entry;
+  KIRQL Irql;
+
+  KeAcquireSpinLock(&DriverReinitListLock,
+                   &Irql);
+
+  if (DriverReinitTailEntry == NULL)
+  {
+    KeReleaseSpinLock(&DriverReinitListLock,
+                     Irql);
+    return;
+  }
+
+  KeReleaseSpinLock(&DriverReinitListLock,
+                   Irql);
+
+  for (;;)
+  {
+    Entry = ExInterlockedRemoveHeadList(&DriverReinitListHead,
+                                       &DriverReinitListLock);
+    if (Entry == NULL)
+      return;
+
+    ReinitItem = (PDRIVER_REINIT_ITEM)CONTAINING_RECORD(Entry, DRIVER_REINIT_ITEM, ItemEntry);
+
+    /* Increment reinitialization counter */
+    ReinitItem->DriverObject->DriverExtension->Count++;
+
+    ReinitItem->ReinitRoutine(ReinitItem->DriverObject,
+                             ReinitItem->Context,
+                             ReinitItem->DriverObject->DriverExtension->Count);
+
+    ExFreePool(Entry);
+
+    if (Entry == DriverReinitTailEntry)
+      return;
+  }
+}
+
+/* PUBLIC FUNCTIONS ***********************************************************/
+
+
+/*
+ * @unimplemented
+ */
+NTSTATUS
+STDCALL
+IoCreateDriver (
+       IN PUNICODE_STRING DriverName,   OPTIONAL
+       IN PDRIVER_INITIALIZE InitializationFunction
+       )
+{
+       UNIMPLEMENTED;
+       return STATUS_NOT_IMPLEMENTED;
+}
+
+/*
+ * @unimplemented
+ */
+VOID
+STDCALL
+IoDeleteDriver (
+       IN PDRIVER_OBJECT DriverObject
+       )
+{
+       UNIMPLEMENTED;
+}
+
 
 /*
  * NtLoadDriver
@@ -994,17 +1503,22 @@ IopUnloadDriver(PUNICODE_STRING DriverServiceName, BOOLEAN UnloadPnpDrivers)
  *             
  * Return Value
  *    Status
+ *
+ * Status
+ *    implemented
  */
 
 NTSTATUS STDCALL
 NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
 {
-   RTL_QUERY_REGISTRY_TABLE QueryTable[2];
+   RTL_QUERY_REGISTRY_TABLE QueryTable[3];
    UNICODE_STRING ImagePath;
+   UNICODE_STRING ServiceName;
    NTSTATUS Status;
    ULONG Type;
    PDEVICE_NODE DeviceNode;
    PMODULE_OBJECT ModuleObject;
+   PDRIVER_OBJECT DriverObject;
    LPWSTR Start;
 
    DPRINT("NtLoadDriver('%wZ')\n", DriverServiceName);
@@ -1012,22 +1526,49 @@ NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
    /*
     * Check security privileges
     */
+
+/* FIXME: Uncomment when privileges will be correctly implemented. */
 #if 0
    if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, KeGetPreviousMode()))
+   {
+      DPRINT("Privilege not held\n");
       return STATUS_PRIVILEGE_NOT_HELD;
+   }
 #endif
 
    RtlInitUnicodeString(&ImagePath, NULL);
 
    /*
-    * Get service type
+    * Get the service name from the registry key name.
+    */
+
+   Start = wcsrchr(DriverServiceName->Buffer, L'\\');
+   if (Start == NULL)
+      Start = DriverServiceName->Buffer;
+   else
+      Start++;
+
+   RtlInitUnicodeString(&ServiceName, Start);
+
+   /*
+    * Get service type.
     */
+
    RtlZeroMemory(&QueryTable, sizeof(QueryTable));
+
+   RtlInitUnicodeString(&ImagePath, NULL);
+
    QueryTable[0].Name = L"Type";
    QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
    QueryTable[0].EntryContext = &Type;
+
+   QueryTable[1].Name = L"ImagePath";
+   QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
+   QueryTable[1].EntryContext = &ImagePath;
+
    Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
       DriverServiceName->Buffer, QueryTable, NULL, NULL);
+
    if (!NT_SUCCESS(Status))
    {
       DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
@@ -1036,13 +1577,14 @@ NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
    }
 
    /*
-    * Get module path
+    * Normalize the image path for all later processing.
     */
-   Status = IopGetDriverNameFromServiceKey(RTL_REGISTRY_ABSOLUTE,
-      DriverServiceName->Buffer, &ImagePath);
+
+   Status = IopNormalizeImagePath(&ImagePath, &ServiceName);
+
    if (!NT_SUCCESS(Status))
    {
-      DPRINT("IopGetDriverNameFromKeyNode() failed (Status %x)\n", Status);
+      DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status);
       return Status;
    }
 
@@ -1052,17 +1594,21 @@ NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
    /*
     * See, if the driver module isn't already loaded
     */
+
    ModuleObject = LdrGetModuleObject(&ImagePath);
    if (ModuleObject != NULL)
    {
+      DPRINT("Image already loaded\n");
       return STATUS_IMAGE_ALREADY_LOADED;
    }
 
    /*
     * Create device node
     */
+
    /* Use IopRootDeviceNode for now */
    Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, &DeviceNode);
+
    if (!NT_SUCCESS(Status))
    {
       DPRINT("IopCreateDeviceNode() failed (Status %lx)\n", Status);
@@ -1072,7 +1618,9 @@ NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
    /*
     * Load the driver module
     */
+
    Status = LdrLoadModule(&ImagePath, &ModuleObject);
+
    if (!NT_SUCCESS(Status))
    {
       DPRINT("LdrLoadModule() failed (Status %lx)\n", Status);
@@ -1083,6 +1631,7 @@ NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
    /*
     * Set a service name for the device node
     */
+
    Start = wcsrchr(DriverServiceName->Buffer, L'\\');
    if (Start == NULL)
       Start = DriverServiceName->Buffer;
@@ -1093,21 +1642,24 @@ NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
    /*
     * Initialize the driver module
     */
-   Status = IopInitializeDriver(
-      ModuleObject->EntryPoint,
+
+   Status = IopInitializeDriverModule(
       DeviceNode,
-      (Type == 2 /*SERVICE_FILE_SYSTEM_DRIVER*/ ||
-       Type == 8 /*SERVICE_RECOGNIZER_DRIVER*/),
-      ModuleObject->Base,
-      ModuleObject->Length,
-      FALSE);
+      ModuleObject,
+      (Type == 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
+       Type == 8 /* SERVICE_RECOGNIZER_DRIVER */),
+      &DriverObject);
+
    if (!NT_SUCCESS(Status))
    {
-      DPRINT1("IopInitializeDriver() failed (Status %lx)\n", Status);
+      DPRINT("IopInitializeDriver() failed (Status %lx)\n", Status);
       LdrUnloadModule(ModuleObject);
       IopFreeDeviceNode(DeviceNode);
+      return Status;
    }
 
+   IopInitializeDevice(DeviceNode, DriverObject);
+
    return Status;
 }
 
@@ -1122,6 +1674,9 @@ NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
  *             
  * Return Value
  *    Status
+ *
+ * Status
+ *    implemented
  */
 
 NTSTATUS STDCALL
@@ -1130,4 +1685,120 @@ NtUnloadDriver(IN PUNICODE_STRING DriverServiceName)
    return IopUnloadDriver(DriverServiceName, FALSE);
 }
 
+/*
+ * IoRegisterDriverReinitialization
+ *
+ * Status
+ *    @implemented
+ */
+
+VOID STDCALL
+IoRegisterDriverReinitialization(
+   PDRIVER_OBJECT DriverObject,
+   PDRIVER_REINITIALIZE ReinitRoutine,
+   PVOID Context)
+{
+   PDRIVER_REINIT_ITEM ReinitItem;
+
+   ReinitItem = ExAllocatePool(NonPagedPool, sizeof(DRIVER_REINIT_ITEM));
+   if (ReinitItem == NULL)
+      return;
+
+   ReinitItem->DriverObject = DriverObject;
+   ReinitItem->ReinitRoutine = ReinitRoutine;
+   ReinitItem->Context = Context;
+
+   ExInterlockedInsertTailList(
+      &DriverReinitListHead,
+      &ReinitItem->ItemEntry,
+      &DriverReinitListLock);
+}
+
+/*
+ * IoAllocateDriverObjectExtension
+ *
+ * Status
+ *    @implemented
+ */
+
+NTSTATUS STDCALL
+IoAllocateDriverObjectExtension(
+   PDRIVER_OBJECT DriverObject,
+   PVOID ClientIdentificationAddress,
+   ULONG DriverObjectExtensionSize,
+   PVOID *DriverObjectExtension)
+{
+   KIRQL OldIrql;
+   PPRIVATE_DRIVER_EXTENSIONS DriverExtensions;
+   PPRIVATE_DRIVER_EXTENSIONS NewDriverExtension;
+
+   NewDriverExtension = ExAllocatePoolWithTag(
+      NonPagedPool,
+      sizeof(PRIVATE_DRIVER_EXTENSIONS) - sizeof(CHAR) +
+      DriverObjectExtensionSize,
+      TAG_DRIVER_EXTENSION);
+
+   if (NewDriverExtension == NULL)
+   {
+      return STATUS_INSUFFICIENT_RESOURCES;             
+   }
+   
+   OldIrql = KeRaiseIrqlToDpcLevel();
+
+   NewDriverExtension->Link = DriverObject->DriverSection;
+   NewDriverExtension->ClientIdentificationAddress = ClientIdentificationAddress;
+
+   for (DriverExtensions = DriverObject->DriverSection;
+        DriverExtensions != NULL;
+        DriverExtensions = DriverExtensions->Link)
+   {
+      if (DriverExtensions->ClientIdentificationAddress ==
+          ClientIdentificationAddress)
+      {
+         KfLowerIrql(OldIrql);
+         return STATUS_OBJECT_NAME_COLLISION;
+      }
+   }
+
+   DriverObject->DriverSection = NewDriverExtension;
+
+   KfLowerIrql(OldIrql);
+
+   *DriverObjectExtension = &NewDriverExtension->Extension;
+
+   return STATUS_SUCCESS;      
+}
+
+/*
+ * IoGetDriverObjectExtension
+ *
+ * Status
+ *    @implemented
+ */
+
+PVOID STDCALL
+IoGetDriverObjectExtension(
+   PDRIVER_OBJECT DriverObject,
+   PVOID ClientIdentificationAddress)
+{
+   KIRQL OldIrql;
+   PPRIVATE_DRIVER_EXTENSIONS DriverExtensions;
+
+   OldIrql = KeRaiseIrqlToDpcLevel();
+
+   for (DriverExtensions = DriverObject->DriverSection;
+        DriverExtensions != NULL &&
+        DriverExtensions->ClientIdentificationAddress !=
+          ClientIdentificationAddress;
+        DriverExtensions = DriverExtensions->Link)
+      ;
+
+   KfLowerIrql(OldIrql);
+
+   if (DriverExtensions == NULL)
+      return NULL;
+
+   return &DriverExtensions->Extension;
+}
+
 /* EOF */