3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/io/driver.c
6 * PURPOSE: Manage devices
7 * PROGRAMMER: David Welch (welch@cwcom.net)
12 /* INCLUDES ****************************************************************/
15 #include <ddk/ntddk.h>
16 #include <internal/io.h>
17 #include <internal/po.h>
18 #include <internal/ldr.h>
19 #include <internal/id.h>
20 #include <internal/pool.h>
21 #include <internal/registry.h>
26 #include <internal/debug.h>
29 typedef struct _SERVICE_GROUP
31 LIST_ENTRY GroupListEntry;
32 UNICODE_STRING GroupName;
34 BOOLEAN ServicesRunning;
36 } SERVICE_GROUP, *PSERVICE_GROUP;
39 typedef struct _SERVICE
41 LIST_ENTRY ServiceListEntry;
42 UNICODE_STRING ServiceName;
43 UNICODE_STRING RegistryPath;
44 UNICODE_STRING ServiceGroup;
45 UNICODE_STRING ImagePath;
52 BOOLEAN ServiceRunning; // needed ??
57 /* GLOBALS *******************************************************************/
59 static LIST_ENTRY GroupListHead = {NULL, NULL};
60 static LIST_ENTRY ServiceListHead = {NULL, NULL};
62 POBJECT_TYPE EXPORTED IoDriverObjectType = NULL;
64 #define TAG_DRIVER TAG('D', 'R', 'V', 'R')
65 #define TAG_DRIVER_EXTENSION TAG('D', 'R', 'V', 'E')
68 /* FUNCTIONS ***************************************************************/
71 IopCreateDriver(PVOID ObjectBody,
74 POBJECT_ATTRIBUTES ObjectAttributes)
76 DPRINT("LdrCreateModule(ObjectBody %x, Parent %x, RemainingPath %S)\n",
80 if (RemainingPath != NULL && wcschr(RemainingPath + 1, '\\') != NULL)
82 return(STATUS_UNSUCCESSFUL);
85 return(STATUS_SUCCESS);
90 IopInitDriverImplementation(VOID)
92 /* Register the process object type */
93 IoDriverObjectType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
94 IoDriverObjectType->Tag = TAG('D', 'R', 'V', 'R');
95 IoDriverObjectType->TotalObjects = 0;
96 IoDriverObjectType->TotalHandles = 0;
97 IoDriverObjectType->MaxObjects = ULONG_MAX;
98 IoDriverObjectType->MaxHandles = ULONG_MAX;
99 IoDriverObjectType->PagedPoolCharge = 0;
100 IoDriverObjectType->NonpagedPoolCharge = sizeof(DRIVER_OBJECT);
101 IoDriverObjectType->Dump = NULL;
102 IoDriverObjectType->Open = NULL;
103 IoDriverObjectType->Close = NULL;
104 IoDriverObjectType->Delete = NULL;
105 IoDriverObjectType->Parse = NULL;
106 IoDriverObjectType->Security = NULL;
107 IoDriverObjectType->QueryName = NULL;
108 IoDriverObjectType->OkayToClose = NULL;
109 IoDriverObjectType->Create = IopCreateDriver;
110 IoDriverObjectType->DuplicationNotify = NULL;
111 RtlInitUnicodeStringFromLiteral(&IoDriverObjectType->TypeName, L"Driver");
114 /**********************************************************************
119 * Loads a device driver.
123 * Name of the service to load (registry key).
131 NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
133 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
134 WCHAR FullImagePathBuffer[MAX_PATH];
135 UNICODE_STRING ImagePath;
136 UNICODE_STRING FullImagePath;
139 PDEVICE_NODE DeviceNode;
140 PMODULE_OBJECT ModuleObject;
143 DPRINT("NtLoadDriver(%wZ) called\n", DriverServiceName);
145 RtlInitUnicodeString(&ImagePath, NULL);
147 /* Get service data */
148 RtlZeroMemory(&QueryTable,
151 QueryTable[0].Name = L"Type";
152 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
153 QueryTable[0].EntryContext = &Type;
155 QueryTable[1].Name = L"ImagePath";
156 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
157 QueryTable[1].EntryContext = &ImagePath;
159 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
160 DriverServiceName->Buffer,
164 if (!NT_SUCCESS(Status))
166 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
167 RtlFreeUnicodeString(&ImagePath);
171 if (ImagePath.Length == 0)
173 wcscpy(FullImagePathBuffer, L"\\SystemRoot\\system32\\drivers");
174 wcscat(FullImagePathBuffer, wcsrchr(DriverServiceName->Buffer, L'\\'));
175 wcscat(FullImagePathBuffer, L".sys");
177 else if (ImagePath.Buffer[0] != L'\\')
179 wcscpy(FullImagePathBuffer, L"\\SystemRoot\\");
180 wcscat(FullImagePathBuffer, ImagePath.Buffer);
184 wcscpy(FullImagePathBuffer, ImagePath.Buffer);
187 RtlFreeUnicodeString(&ImagePath);
188 RtlInitUnicodeString(&FullImagePath, FullImagePathBuffer);
190 DPRINT("FullImagePath: '%S'\n", FullImagePathBuffer);
191 DPRINT("Type %lx\n", Type);
193 /* Use IopRootDeviceNode for now */
194 Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, &DeviceNode);
195 if (!NT_SUCCESS(Status))
197 DPRINT1("IopCreateDeviceNode() failed (Status %lx)\n", Status);
201 ModuleObject = LdrGetModuleObject(DriverServiceName);
202 if (ModuleObject != NULL)
204 return(STATUS_IMAGE_ALREADY_LOADED);
207 Status = LdrLoadModule(&FullImagePath, &ModuleObject);
208 if (!NT_SUCCESS(Status))
210 DPRINT1("LdrLoadModule() failed (Status %lx)\n", Status);
211 IopFreeDeviceNode(DeviceNode);
215 /* Set a service name for the device node */
216 Start = wcsrchr(DriverServiceName->Buffer, L'\\');
218 Start = DriverServiceName->Buffer;
221 RtlCreateUnicodeString(&DeviceNode->ServiceName, Start);
223 Status = IopInitializeDriver(ModuleObject->EntryPoint,
225 (Type == 2 || Type == 8));
226 if (!NT_SUCCESS(Status))
228 DPRINT1("IopInitializeDriver() failed (Status %lx)\n", Status);
229 LdrUnloadModule(ModuleObject);
230 IopFreeDeviceNode(DeviceNode);
238 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName)
240 DPRINT("DriverServiceName: '%wZ'\n", DriverServiceName);
242 return(STATUS_NOT_IMPLEMENTED);
246 static NTSTATUS STDCALL
247 IopCreateGroupListEntry(PWSTR ValueName,
254 PSERVICE_GROUP Group;
256 if (ValueType == REG_SZ)
258 DPRINT("GroupName: '%S'\n", (PWCHAR)ValueData);
260 Group = ExAllocatePool(NonPagedPool,
261 sizeof(SERVICE_GROUP));
264 return(STATUS_INSUFFICIENT_RESOURCES);
267 RtlZeroMemory(Group, sizeof(SERVICE_GROUP));
269 if (!RtlCreateUnicodeString(&Group->GroupName,
272 return(STATUS_INSUFFICIENT_RESOURCES);
276 InsertTailList(&GroupListHead,
277 &Group->GroupListEntry);
280 return(STATUS_SUCCESS);
284 static NTSTATUS STDCALL
285 IopCreateServiceListEntry(PUNICODE_STRING ServiceName)
287 RTL_QUERY_REGISTRY_TABLE QueryTable[6];
291 DPRINT("ServiceName: '%wZ'\n", ServiceName);
293 /* Allocate service entry */
294 Service = (PSERVICE)ExAllocatePool(NonPagedPool, sizeof(SERVICE));
297 DPRINT1("ExAllocatePool() failed\n");
298 return(STATUS_INSUFFICIENT_RESOURCES);
300 RtlZeroMemory(Service, sizeof(SERVICE));
302 /* Get service data */
303 RtlZeroMemory(&QueryTable,
306 QueryTable[0].Name = L"Start";
307 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
308 QueryTable[0].EntryContext = &Service->Start;
310 QueryTable[1].Name = L"Type";
311 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
312 QueryTable[1].EntryContext = &Service->Type;
314 QueryTable[2].Name = L"ErrorControl";
315 QueryTable[2].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
316 QueryTable[2].EntryContext = &Service->ErrorControl;
318 QueryTable[3].Name = L"Group";
319 QueryTable[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
320 QueryTable[3].EntryContext = &Service->ServiceGroup;
322 QueryTable[4].Name = L"ImagePath";
323 QueryTable[4].Flags = RTL_QUERY_REGISTRY_DIRECT;
324 QueryTable[4].EntryContext = &Service->ImagePath;
326 Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
331 if (!NT_SUCCESS(Status) || Service->Start > 1)
333 RtlFreeUnicodeString(&Service->ServiceGroup);
334 RtlFreeUnicodeString(&Service->ImagePath);
339 /* Copy service name */
340 Service->ServiceName.Length = ServiceName->Length;
341 Service->ServiceName.MaximumLength = ServiceName->Length + sizeof(WCHAR);
342 Service->ServiceName.Buffer = ExAllocatePool(NonPagedPool,
343 Service->ServiceName.MaximumLength);
344 RtlCopyMemory(Service->ServiceName.Buffer,
346 ServiceName->Length);
347 Service->ServiceName.Buffer[ServiceName->Length / sizeof(WCHAR)] = 0;
349 /* Build registry path */
350 Service->RegistryPath.MaximumLength = MAX_PATH * sizeof(WCHAR);
351 Service->RegistryPath.Buffer = ExAllocatePool(NonPagedPool,
352 MAX_PATH * sizeof(WCHAR));
353 wcscpy(Service->RegistryPath.Buffer,
354 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
355 wcscat(Service->RegistryPath.Buffer,
356 Service->ServiceName.Buffer);
357 Service->RegistryPath.Length = wcslen(Service->RegistryPath.Buffer) * sizeof(WCHAR);
359 DPRINT("ServiceName: '%wZ'\n", &Service->ServiceName);
360 DPRINT("RegistryPath: '%wZ'\n", &Service->RegistryPath);
361 DPRINT("ServiceGroup: '%wZ'\n", &Service->ServiceGroup);
362 DPRINT("ImagePath: '%wZ'\n", &Service->ImagePath);
363 DPRINT("Start %lx Type %lx ErrorControl %lx\n",
364 Service->Start, Service->Type, Service->ErrorControl);
366 /* Append service entry */
367 InsertTailList(&ServiceListHead,
368 &Service->ServiceListEntry);
370 return(STATUS_SUCCESS);
375 IoCreateDriverList(VOID)
377 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
378 PKEY_BASIC_INFORMATION KeyInfo = NULL;
379 OBJECT_ATTRIBUTES ObjectAttributes;
380 UNICODE_STRING ServicesKeyName;
381 UNICODE_STRING SubKeyName;
386 ULONG KeyInfoLength = 0;
387 ULONG ReturnedLength;
389 DPRINT("IoCreateDriverList() called\n");
391 /* Initialize basic variables */
392 InitializeListHead(&GroupListHead);
393 InitializeListHead(&ServiceListHead);
395 /* Build group order list */
396 RtlZeroMemory(&QueryTable,
399 QueryTable[0].Name = L"List";
400 QueryTable[0].QueryRoutine = IopCreateGroupListEntry;
402 Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
403 L"ServiceGroupOrder",
407 if (!NT_SUCCESS(Status))
410 /* Enumerate services and create the service list */
411 RtlInitUnicodeStringFromLiteral(&ServicesKeyName,
412 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services");
414 InitializeObjectAttributes(&ObjectAttributes,
416 OBJ_CASE_INSENSITIVE,
420 Status = NtOpenKey(&KeyHandle,
423 if (!NT_SUCCESS(Status))
428 KeyInfoLength = sizeof(KEY_BASIC_INFORMATION) + MAX_PATH * sizeof(WCHAR);
429 KeyInfo = ExAllocatePool(NonPagedPool, KeyInfoLength);
433 return(STATUS_INSUFFICIENT_RESOURCES);
439 Status = NtEnumerateKey(KeyHandle,
445 if (NT_SUCCESS(Status))
447 if (KeyInfo->NameLength < MAX_PATH * sizeof(WCHAR))
450 SubKeyName.Length = KeyInfo->NameLength;
451 SubKeyName.MaximumLength = KeyInfo->NameLength + sizeof(WCHAR);
452 SubKeyName.Buffer = KeyInfo->Name;
453 SubKeyName.Buffer[SubKeyName.Length / sizeof(WCHAR)] = 0;
455 DPRINT("KeyName: '%wZ'\n", &SubKeyName);
456 IopCreateServiceListEntry(&SubKeyName);
460 if (!NT_SUCCESS(Status))
469 DPRINT("IoCreateDriverList() done\n");
471 return(STATUS_SUCCESS);
476 LdrLoadAutoConfigDrivers(VOID)
478 PLIST_ENTRY GroupEntry;
479 PLIST_ENTRY ServiceEntry;
480 PSERVICE_GROUP CurrentGroup;
481 PSERVICE CurrentService;
484 CHAR TextBuffer [256];
487 DPRINT("LdrLoadAutoConfigDrivers() called\n");
489 GroupEntry = GroupListHead.Flink;
490 while (GroupEntry != &GroupListHead)
492 CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry);
494 DPRINT("Group: %wZ\n", &CurrentGroup->GroupName);
496 ServiceEntry = ServiceListHead.Flink;
497 while (ServiceEntry != &ServiceListHead)
499 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
501 if ((RtlCompareUnicodeString(&CurrentGroup->GroupName, &CurrentService->ServiceGroup, TRUE) == 0) &&
502 (CurrentService->Start == 1 /*SERVICE_SYSTEM_START*/))
505 HalQueryDisplayParameters(&x, &y, &cx, &cy);
506 RtlFillMemory(TextBuffer, x, ' ');
507 TextBuffer[x] = '\0';
508 HalSetDisplayParameters(0, y-1);
509 HalDisplayString(TextBuffer);
511 sprintf(TextBuffer, "Loading %S...\n", CurrentService->ServiceName.Buffer);
512 HalSetDisplayParameters(0, y-1);
513 HalDisplayString(TextBuffer);
514 HalSetDisplayParameters(cx, cy);
516 DPRINT(" Path: %wZ\n", &CurrentService->RegistryPath);
517 Status = NtLoadDriver(&CurrentService->RegistryPath);
518 if (!NT_SUCCESS(Status))
520 DPRINT("NtLoadDriver() failed (Status %lx)\n", Status);
522 if (CurrentService->ErrorControl == 1)
527 else if (CurrentService->ErrorControl == 2)
529 if (IsLastKnownGood == FALSE)
531 /* Boot last known good configuration */
535 else if (CurrentService->ErrorControl == 3)
537 if (IsLastKnownGood == FALSE)
539 /* Boot last known good configuration */
551 ServiceEntry = ServiceEntry->Flink;
554 GroupEntry = GroupEntry->Flink;
557 DPRINT("LdrLoadAutoConfigDrivers() done\n");
562 IoDestroyDriverList(VOID)
564 PLIST_ENTRY GroupEntry;
565 PLIST_ENTRY ServiceEntry;
566 PSERVICE_GROUP CurrentGroup;
567 PSERVICE CurrentService;
569 DPRINT("IoDestroyDriverList() called\n");
571 /* Destroy group list */
572 GroupEntry = GroupListHead.Flink;
573 while (GroupEntry != &GroupListHead)
575 CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry);
577 RtlFreeUnicodeString(&CurrentGroup->GroupName);
578 RemoveEntryList(GroupEntry);
579 ExFreePool(CurrentGroup);
581 GroupEntry = GroupListHead.Flink;
584 /* Destroy service list */
585 ServiceEntry = ServiceListHead.Flink;
586 while (ServiceEntry != &ServiceListHead)
588 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
590 RtlFreeUnicodeString(&CurrentService->ServiceName);
591 RtlFreeUnicodeString(&CurrentService->RegistryPath);
592 RtlFreeUnicodeString(&CurrentService->ServiceGroup);
593 RtlFreeUnicodeString(&CurrentService->ImagePath);
594 RemoveEntryList(ServiceEntry);
595 ExFreePool(CurrentService);
597 ServiceEntry = ServiceListHead.Flink;
600 DPRINT("IoDestroyDriverList() done\n");
602 return(STATUS_SUCCESS);