extern BOOLEAN ExpInTextModeSetup;
extern BOOLEAN PnpSystemInit;
+USHORT IopGroupIndex;
+PLIST_ENTRY IopGroupTable;
+
/* PRIVATE FUNCTIONS **********************************************************/
NTSTATUS NTAPI
return STATUS_SUCCESS;
}
+/*
+ * RETURNS
+ * TRUE if String2 contains String1 as a suffix.
+ */
+BOOLEAN
+NTAPI
+IopSuffixUnicodeString(
+ IN PCUNICODE_STRING String1,
+ IN PCUNICODE_STRING String2)
+{
+ PWCHAR pc1;
+ PWCHAR pc2;
+ ULONG Length;
+
+ if (String2->Length < String1->Length)
+ return FALSE;
+
+ Length = String1->Length / 2;
+ pc1 = String1->Buffer;
+ pc2 = &String2->Buffer[String2->Length / sizeof(WCHAR) - Length];
+
+ if (pc1 && pc2)
+ {
+ while (Length--)
+ {
+ if( *pc1++ != *pc2++ )
+ return FALSE;
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
/*
* IopDisplayLoadingMessage
*
* Display 'Loading XXX...' message.
*/
-VOID
+VOID
FASTCALL
INIT_FUNCTION
-IopDisplayLoadingMessage(PVOID ServiceName,
- BOOLEAN Unicode)
+IopDisplayLoadingMessage(PUNICODE_STRING ServiceName)
{
CHAR TextBuffer[256];
- PCHAR Extra = ".sys";
+ UNICODE_STRING DotSys = RTL_CONSTANT_STRING(L".SYS");
if (ExpInTextModeSetup) return;
- if (Unicode)
- {
- if (wcsstr(_wcsupr(ServiceName), L".SYS")) Extra = "";
- sprintf(TextBuffer,
- "%s%s%s\\%S%s\n",
- KeLoaderBlock->ArcBootDeviceName,
- KeLoaderBlock->NtBootPathName,
- "System32\\Drivers",
- (PWCHAR)ServiceName,
- Extra);
- }
- else
- {
- if (strstr(_strupr(ServiceName), ".SYS")) Extra = "";
- sprintf(TextBuffer,
- "%s%s%s\\%s%s\n",
- KeLoaderBlock->ArcBootDeviceName,
- KeLoaderBlock->NtBootPathName,
- "System32\\Drivers",
- (PCHAR)ServiceName,
- Extra);
- }
+ if (!KeLoaderBlock) return;
+ RtlUpcaseUnicodeString(ServiceName, ServiceName, FALSE);
+ snprintf(TextBuffer, sizeof(TextBuffer),
+ "%s%sSystem32\\Drivers\\%wZ%s\n",
+ KeLoaderBlock->ArcBootDeviceName,
+ KeLoaderBlock->NtBootPathName,
+ ServiceName,
+ IopSuffixUnicodeString(&DotSys, ServiceName) ? "" : ".SYS");
HalDisplayString(TextBuffer);
}
{
UNICODE_STRING InputImagePath;
+ DPRINT("Normalizing image path '%wZ' for service '%wZ'\n", ImagePath, ServiceName);
+
RtlCopyMemory(
&InputImagePath,
ImagePath,
/* Free caller's string */
ExFreePoolWithTag(InputImagePath.Buffer, TAG_RTLREGISTRY);
}
+
+ DPRINT("Normalized image path is '%wZ' for service '%wZ'\n", ImagePath, ServiceName);
return STATUS_SUCCESS;
}
return STATUS_UNSUCCESSFUL;
}
- /* Open CurrentControlSet */
- RtlInitUnicodeString(&CCSName,
- L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services");
- Status = IopOpenRegistryKeyEx(&CCSKey, NULL, &CCSName, KEY_READ);
- if (!NT_SUCCESS(Status))
+ if (ExpInTextModeSetup)
{
- DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
- return Status;
- }
+ /* We have no registry, but luckily we know where all the drivers are */
- /* Open service key */
- Status = IopOpenRegistryKeyEx(&ServiceKey, CCSKey, ServiceName, KEY_READ);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
- ZwClose(CCSKey);
- return Status;
+ /* ServiceStart < 4 is all that matters */
+ ServiceStart = 0;
+
+ /* IopNormalizeImagePath will do all of the work for us if we give it an empty string */
+ ServiceImagePath.Length = ServiceImagePath.MaximumLength = 0;
+ ServiceImagePath.Buffer = NULL;
}
+ else
+ {
+ /* Open CurrentControlSet */
+ RtlInitUnicodeString(&CCSName,
+ L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services");
+ Status = IopOpenRegistryKeyEx(&CCSKey, NULL, &CCSName, KEY_READ);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
+ return Status;
+ }
- /*
- * Get information about the service.
- */
+ /* Open service key */
+ Status = IopOpenRegistryKeyEx(&ServiceKey, CCSKey, ServiceName, KEY_READ);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
+ ZwClose(CCSKey);
+ return Status;
+ }
- RtlZeroMemory(QueryTable, sizeof(QueryTable));
+ /*
+ * Get information about the service.
+ */
- RtlInitUnicodeString(&ServiceImagePath, NULL);
+ RtlZeroMemory(QueryTable, sizeof(QueryTable));
- QueryTable[0].Name = L"Start";
- QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
- QueryTable[0].EntryContext = &ServiceStart;
+ RtlInitUnicodeString(&ServiceImagePath, NULL);
- QueryTable[1].Name = L"ImagePath";
- QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
- QueryTable[1].EntryContext = &ServiceImagePath;
+ QueryTable[0].Name = L"Start";
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ QueryTable[0].EntryContext = &ServiceStart;
- Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
- (PWSTR)ServiceKey, QueryTable, NULL, NULL);
+ QueryTable[1].Name = L"ImagePath";
+ QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ QueryTable[1].EntryContext = &ServiceImagePath;
- ZwClose(ServiceKey);
- ZwClose(CCSKey);
+ Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
+ (PWSTR)ServiceKey, QueryTable, NULL, NULL);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status);
- return Status;
+ ZwClose(ServiceKey);
+ ZwClose(CCSKey);
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status);
+ return Status;
+ }
}
/*
return Status;
}
- /*
- * Case for disabled drivers
- */
-
- if (ServiceStart >= 4)
- {
- /* FIXME: Check if it is the right status code */
- Status = STATUS_PLUGPLAY_NO_DEVICE;
- }
- else
- {
- DPRINT("Loading module\n");
- Status = MmLoadSystemImage(&ServiceImagePath, NULL, NULL, 0, (PVOID)ModuleObject, &BaseAddress);
- }
+ /*
+ * Case for disabled drivers
+ */
+
+ if (ServiceStart >= 4)
+ {
+ /* FIXME: Check if it is the right status code */
+ Status = STATUS_PLUGPLAY_NO_DEVICE;
+ }
+ else
+ {
+ DPRINT("Loading module from %wZ\n", &ServiceImagePath);
+ Status = MmLoadSystemImage(&ServiceImagePath, NULL, NULL, 0, (PVOID)ModuleObject, &BaseAddress);
+ if (NT_SUCCESS(Status))
+ {
+ IopDisplayLoadingMessage(ServiceName);
+ }
+ }
ExFreePool(ServiceImagePath.Buffer);
UNICODE_STRING RegistryKey;
PDRIVER_INITIALIZE DriverEntry;
PDRIVER_OBJECT Driver;
- PDEVICE_OBJECT DeviceObject;
NTSTATUS Status;
DriverEntry = ModuleObject->EntryPoint;
DriverName.Length > 0 ? &DriverName : NULL,
DriverEntry,
&RegistryKey,
- ModuleObject->DllBase,
- ModuleObject->SizeOfImage,
+ ModuleObject,
&Driver);
RtlFreeUnicodeString(&RegistryKey);
}
/* Set the driver as initialized */
- Driver->Flags |= DRVO_INITIALIZED;
- DeviceObject = Driver->DeviceObject;
- while (DeviceObject)
- {
- /* Set every device as initialized too */
- DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
- DeviceObject = DeviceObject->NextDevice;
- }
+ IopReadyDeviceObjects(Driver);
if (PnpSystemInit) IopReinitializeDrivers();
DPRINT("Filter Driver: %S (%wZ)\n", Filters, &DeviceNode->InstancePath);
ServiceName.Buffer = Filters;
ServiceName.MaximumLength =
- ServiceName.Length = wcslen(Filters) * sizeof(WCHAR);
+ ServiceName.Length = (USHORT)wcslen(Filters) * sizeof(WCHAR);
/* Load and initialize the filter driver */
Status = IopLoadServiceModule(&ServiceName, &ModuleObject);
//
NTSTATUS
NTAPI
+INIT_FUNCTION
LdrProcessDriverModule(PLDR_DATA_TABLE_ENTRY LdrEntry,
PUNICODE_STRING FileName,
PLDR_DATA_TABLE_ENTRY *ModuleObject)
{
NTSTATUS Status;
- PLDR_DATA_TABLE_ENTRY NewEntry;
UNICODE_STRING BaseName, BaseDirectory;
PLOAD_IMPORTS LoadedImports = (PVOID)-2;
PCHAR MissingApiName, Buffer;
BaseDirectory.Length -= BaseName.Length;
BaseDirectory.MaximumLength = BaseDirectory.Length;
- NewEntry = LdrEntry;
-
/* Resolve imports */
MissingApiName = Buffer;
Status = MiResolveImageReferences(DriverBase,
NTSTATUS
NTAPI
+INIT_FUNCTION
IopInitializeBuiltinDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
{
PDEVICE_NODE DeviceNode;
/*
* Display 'Loading XXX...' message
*/
- IopDisplayLoadingMessage(ModuleName->Buffer, TRUE);
+ IopDisplayLoadingMessage(ModuleName);
+ InbvIndicateProgress();
/*
* Generate filename without path (not needed by freeldr)
FileExtension = wcsrchr(ServiceName.Buffer, '.');
if (FileExtension != NULL)
{
- ServiceName.Length -= wcslen(FileExtension) * sizeof(WCHAR);
+ ServiceName.Length -= (USHORT)wcslen(FileExtension) * sizeof(WCHAR);
FileExtension[0] = 0;
}
DPRINT1("Driver '%wZ' load failed, status (%x)\n", ModuleName, Status);
return(Status);
}
- DeviceNode->ServiceName = ServiceName;
/*
* Initialize the driver
*/
VOID
FASTCALL
+INIT_FUNCTION
IopInitializeBootDrivers(VOID)
{
- PLIST_ENTRY ListHead, NextEntry;
+ PLIST_ENTRY ListHead, NextEntry, NextEntry2;
PLDR_DATA_TABLE_ENTRY LdrEntry;
PDEVICE_NODE DeviceNode;
PDRIVER_OBJECT DriverObject;
LDR_DATA_TABLE_ENTRY ModuleObject;
NTSTATUS Status;
UNICODE_STRING DriverName;
-
+ ULONG i, Index;
+ PDRIVER_INFORMATION DriverInfo, DriverInfoTag;
+ HANDLE KeyHandle;
+ PBOOT_DRIVER_LIST_ENTRY BootEntry;
DPRINT("IopInitializeBootDrivers()\n");
/* Use IopRootDeviceNode for now */
return;
}
+ /* Get highest group order index */
+ IopGroupIndex = PpInitGetGroupOrderIndex(NULL);
+ if (IopGroupIndex == 0xFFFF) ASSERT(FALSE);
+
+ /* Allocate the group table */
+ IopGroupTable = ExAllocatePoolWithTag(PagedPool,
+ IopGroupIndex * sizeof(LIST_ENTRY),
+ TAG_IO);
+ if (IopGroupTable == NULL) ASSERT(FALSE);
+
+ /* Initialize the group table lists */
+ for (i = 0; i < IopGroupIndex; i++) InitializeListHead(&IopGroupTable[i]);
+
/* Loop the boot modules */
ListHead = &KeLoaderBlock->LoadOrderListHead;
NextEntry = ListHead->Flink;
LDR_DATA_TABLE_ENTRY,
InLoadOrderLinks);
- /*
- * HACK: Make sure we're loading a driver
- * (we should be using BootDriverListHead!)
- */
- if (wcsstr(_wcsupr(LdrEntry->BaseDllName.Buffer), L".SYS"))
+ /* Check if the DLL needs to be initialized */
+ if (LdrEntry->Flags & LDRP_DRIVER_DEPENDENT_DLL)
{
- /* Make sure we didn't load this driver already */
- if (!(LdrEntry->Flags & LDRP_ENTRY_INSERTED))
+ /* Call its entrypoint */
+ MmCallDllInitialize(LdrEntry, NULL);
+ }
+
+ /* Go to the next driver */
+ NextEntry = NextEntry->Flink;
+ }
+
+ /* Loop the boot drivers */
+ ListHead = &KeLoaderBlock->BootDriverListHead;
+ NextEntry = ListHead->Flink;
+ while (ListHead != NextEntry)
+ {
+ /* Get the entry */
+ BootEntry = CONTAINING_RECORD(NextEntry,
+ BOOT_DRIVER_LIST_ENTRY,
+ Link);
+
+ /* Get the driver loader entry */
+ LdrEntry = BootEntry->LdrEntry;
+
+ /* Allocate our internal accounting structure */
+ DriverInfo = ExAllocatePoolWithTag(PagedPool,
+ sizeof(DRIVER_INFORMATION),
+ TAG_IO);
+ if (DriverInfo)
+ {
+ /* Zero it and initialize it */
+ RtlZeroMemory(DriverInfo, sizeof(DRIVER_INFORMATION));
+ InitializeListHead(&DriverInfo->Link);
+ DriverInfo->DataTableEntry = BootEntry;
+
+ /* Open the registry key */
+ Status = IopOpenRegistryKeyEx(&KeyHandle,
+ NULL,
+ &BootEntry->RegistryPath,
+ KEY_READ);
+ if ((NT_SUCCESS(Status)) || /* ReactOS HACK for SETUPLDR */
+ ((KeLoaderBlock->SetupLdrBlock) && ((KeyHandle = (PVOID)1)))) // yes, it's an assignment!
{
- DPRINT("Initializing bootdriver %wZ\n", &LdrEntry->BaseDllName);
- /* Initialize it */
- IopInitializeBuiltinDriver(LdrEntry);
+ /* Save the handle */
+ DriverInfo->ServiceHandle = KeyHandle;
+
+ /* Get the group oder index */
+ Index = PpInitGetGroupOrderIndex(KeyHandle);
+
+ /* Get the tag position */
+ DriverInfo->TagPosition = PipGetDriverTagPriority(KeyHandle);
+
+ /* Insert it into the list, at the right place */
+ ASSERT(Index < IopGroupIndex);
+ NextEntry2 = IopGroupTable[Index].Flink;
+ while (NextEntry2 != &IopGroupTable[Index])
+ {
+ /* Get the driver info */
+ DriverInfoTag = CONTAINING_RECORD(NextEntry2,
+ DRIVER_INFORMATION,
+ Link);
+
+ /* Check if we found the right tag position */
+ if (DriverInfoTag->TagPosition > DriverInfo->TagPosition)
+ {
+ /* We're done */
+ break;
+ }
+
+ /* Next entry */
+ NextEntry2 = NextEntry2->Flink;
+ }
+
+ /* Insert us right before the next entry */
+ NextEntry2 = NextEntry2->Blink;
+ InsertHeadList(NextEntry2, &DriverInfo->Link);
}
}
NextEntry = NextEntry->Flink;
}
+ /* Loop each group index */
+ for (i = 0; i < IopGroupIndex; i++)
+ {
+ /* Loop each group table */
+ NextEntry = IopGroupTable[i].Flink;
+ while (NextEntry != &IopGroupTable[i])
+ {
+ /* Get the entry */
+ DriverInfo = CONTAINING_RECORD(NextEntry,
+ DRIVER_INFORMATION,
+ Link);
+
+ /* Get the driver loader entry */
+ LdrEntry = DriverInfo->DataTableEntry->LdrEntry;
+
+ /* Initialize it */
+ IopInitializeBuiltinDriver(LdrEntry);
+
+ /* Next entry */
+ NextEntry = NextEntry->Flink;
+ }
+ }
+
/* In old ROS, the loader list became empty after this point. Simulate. */
InitializeListHead(&KeLoaderBlock->LoadOrderListHead);
}
+VOID
+FASTCALL
+INIT_FUNCTION
+IopInitializeSystemDrivers(VOID)
+{
+ PUNICODE_STRING *DriverList, *SavedList;
+
+ /* No system drivers on the boot cd */
+ if (KeLoaderBlock->SetupLdrBlock) return;
+
+ /* Get the driver list */
+ SavedList = DriverList = CmGetSystemDriverList();
+ ASSERT(DriverList);
+
+ /* Loop it */
+ while (*DriverList)
+ {
+ /* Load the driver */
+ ZwLoadDriver(*DriverList);
+
+ /* Free the entry */
+ RtlFreeUnicodeString(*DriverList);
+ ExFreePool(*DriverList);
+
+ /* Next entry */
+ InbvIndicateProgress();
+ DriverList++;
+ }
+
+ /* Free the list */
+ ExFreePool(SavedList);
+}
+
/*
* IopUnloadDriver
*
* Construct the driver object name
*/
- ObjectName.Length = (wcslen(Start) + 8) * sizeof(WCHAR);
+ ObjectName.Length = ((USHORT)wcslen(Start) + 8) * sizeof(WCHAR);
ObjectName.MaximumLength = ObjectName.Length + sizeof(WCHAR);
ObjectName.Buffer = ExAllocatePool(PagedPool, ObjectName.MaximumLength);
if (!ObjectName.Buffer) return STATUS_INSUFFICIENT_RESOURCES;
0,
(PVOID*)&DriverObject);
- /*
- * Free the buffer for driver object name
- */
- ExFreePool(ObjectName.Buffer);
-
if (!NT_SUCCESS(Status))
{
DPRINT1("Can't locate driver object for %wZ\n", &ObjectName);
+ ExFreePool(ObjectName.Buffer);
return Status;
}
+ /*
+ * Free the buffer for driver object name
+ */
+ ExFreePool(ObjectName.Buffer);
+
/* Check that driver is not already unloading */
if (DriverObject->Flags & DRVO_UNLOAD_INVOKED)
{
IopCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL,
IN PDRIVER_INITIALIZE InitializationFunction,
IN PUNICODE_STRING RegistryPath,
- IN PVOID DllBase,
- IN ULONG SizeOfImage,
+ PLDR_DATA_TABLE_ENTRY ModuleObject,
OUT PDRIVER_OBJECT *pDriverObject)
{
WCHAR NameBuffer[100];
DriverObject->DriverExtension = (PDRIVER_EXTENSION)(DriverObject + 1);
DriverObject->DriverExtension->DriverObject = DriverObject;
DriverObject->DriverInit = InitializationFunction;
-
+ DriverObject->DriverSection = ModuleObject;
/* Loop all Major Functions */
for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
{
ZwClose(hDriver);
DriverObject->HardwareDatabase = &IopHardwareDatabaseKey;
- DriverObject->DriverStart = DllBase;
- DriverObject->DriverSize = SizeOfImage;
+ DriverObject->DriverStart = ModuleObject ? ModuleObject->DllBase : 0;
+ DriverObject->DriverSize = ModuleObject ? ModuleObject->SizeOfImage : 0;
/* Finally, call its init function */
DPRINT("RegistryKey: %wZ\n", RegistryPath);
{
/* If it didn't work, then kill the object */
DPRINT1("'%wZ' initialization failed, status (0x%08lx)\n", DriverName, Status);
+ DriverObject->DriverSection = NULL;
ObMakeTemporaryObject(DriverObject);
ObDereferenceObject(DriverObject);
}
* Doing so is illegal; drivers shouldn't touch entry points they
* do not implement.
*/
- ASSERT(DriverObject->MajorFunction[i] != NULL);
/* Check if it did so anyway */
- if (!DriverObject->MajorFunction[i])
+ if (!DriverObject->MajorFunction[i])
{
+ /* Print a warning in the debug log */
+ DPRINT1("Driver <%wZ> set DriverObject->MajorFunction[%d] to NULL!\n",
+ &DriverObject->DriverName, i);
+
/* Fix it up */
DriverObject->MajorFunction[i] = IopInvalidDeviceRequest;
}
IN PDRIVER_INITIALIZE InitializationFunction)
{
PDRIVER_OBJECT DriverObject;
- return IopCreateDriver(DriverName, InitializationFunction, NULL, 0, 0, &DriverObject);
+ return IopCreateDriver(DriverName, InitializationFunction, NULL, NULL, &DriverObject);
}
/*
DPRINT("FullImagePath: '%wZ'\n", &ImagePath);
DPRINT("Type: %lx\n", Type);
- /*
- * Create device node
- */
-
- /* Use IopRootDeviceNode for now */
- Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, &ServiceName, &DeviceNode);
-
- if (!NT_SUCCESS(Status))
- {
- DPRINT("IopCreateDeviceNode() failed (Status %lx)\n", Status);
- LoadParams->Status = Status;
- (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
- return;
- }
-
/* Get existing DriverObject pointer (in case the driver has
already been loaded and initialized) */
Status = IopGetDriverObject(
* Load the driver module
*/
+ DPRINT("Loading module from %wZ\n", &ImagePath);
Status = MmLoadSystemImage(&ImagePath, NULL, NULL, 0, (PVOID)&ModuleObject, &BaseAddress);
+
if (!NT_SUCCESS(Status) && Status != STATUS_IMAGE_ALREADY_LOADED)
{
DPRINT("MmLoadSystemImage() failed (Status %lx)\n", Status);
- IopFreeDeviceNode(DeviceNode);
LoadParams->Status = Status;
(VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
return;
}
- /*
- * Set a service name for the device node
- */
-
- RtlCreateUnicodeString(&DeviceNode->ServiceName, ServiceName.Buffer);
-
/*
* Initialize the driver module if it's loaded for the first time
*/
if (Status != STATUS_IMAGE_ALREADY_LOADED)
{
+ Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, &ServiceName, &DeviceNode);
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("IopCreateDeviceNode() failed (Status %lx)\n", Status);
+ MmUnloadSystemImage(ModuleObject);
+ LoadParams->Status = Status;
+ (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
+ return;
+ }
+
+ IopDisplayLoadingMessage(&DeviceNode->ServiceName);
+
Status = IopInitializeDriverModule(
DeviceNode,
ModuleObject,
(VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
return;
}
- }
-
- /* Store its DriverSection, so that it could be unloaded */
- DriverObject->DriverSection = ModuleObject;
- /* Initialize and start device */
- IopInitializeDevice(DeviceNode, DriverObject);
- Status = IopStartDevice(DeviceNode);
+ /* Initialize and start device */
+ IopInitializeDevice(DeviceNode, DriverObject);
+ Status = IopStartDevice(DeviceNode);
+ }
}
else
{
/* IopGetDriverObject references the DriverObject, so dereference it */
ObDereferenceObject(DriverObject);
-
- /* Free device node since driver loading failed */
- IopFreeDeviceNode(DeviceNode);
}
/* Pass status to the caller and signal the event */