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),
227 ModuleObject->Length);
228 if (!NT_SUCCESS(Status))
230 DPRINT1("IopInitializeDriver() failed (Status %lx)\n", Status);
231 LdrUnloadModule(ModuleObject);
232 IopFreeDeviceNode(DeviceNode);
240 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName)
242 DPRINT("DriverServiceName: '%wZ'\n", DriverServiceName);
244 return(STATUS_NOT_IMPLEMENTED);
248 static NTSTATUS STDCALL
249 IopCreateGroupListEntry(PWSTR ValueName,
256 PSERVICE_GROUP Group;
258 if (ValueType == REG_SZ)
260 DPRINT("GroupName: '%S'\n", (PWCHAR)ValueData);
262 Group = ExAllocatePool(NonPagedPool,
263 sizeof(SERVICE_GROUP));
266 return(STATUS_INSUFFICIENT_RESOURCES);
269 RtlZeroMemory(Group, sizeof(SERVICE_GROUP));
271 if (!RtlCreateUnicodeString(&Group->GroupName,
274 return(STATUS_INSUFFICIENT_RESOURCES);
278 InsertTailList(&GroupListHead,
279 &Group->GroupListEntry);
282 return(STATUS_SUCCESS);
286 static NTSTATUS STDCALL
287 IopCreateServiceListEntry(PUNICODE_STRING ServiceName)
289 RTL_QUERY_REGISTRY_TABLE QueryTable[6];
293 DPRINT("ServiceName: '%wZ'\n", ServiceName);
295 /* Allocate service entry */
296 Service = (PSERVICE)ExAllocatePool(NonPagedPool, sizeof(SERVICE));
299 DPRINT1("ExAllocatePool() failed\n");
300 return(STATUS_INSUFFICIENT_RESOURCES);
302 RtlZeroMemory(Service, sizeof(SERVICE));
304 /* Get service data */
305 RtlZeroMemory(&QueryTable,
308 QueryTable[0].Name = L"Start";
309 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
310 QueryTable[0].EntryContext = &Service->Start;
312 QueryTable[1].Name = L"Type";
313 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
314 QueryTable[1].EntryContext = &Service->Type;
316 QueryTable[2].Name = L"ErrorControl";
317 QueryTable[2].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
318 QueryTable[2].EntryContext = &Service->ErrorControl;
320 QueryTable[3].Name = L"Group";
321 QueryTable[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
322 QueryTable[3].EntryContext = &Service->ServiceGroup;
324 QueryTable[4].Name = L"ImagePath";
325 QueryTable[4].Flags = RTL_QUERY_REGISTRY_DIRECT;
326 QueryTable[4].EntryContext = &Service->ImagePath;
328 Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
333 if (!NT_SUCCESS(Status) || Service->Start > 1)
335 RtlFreeUnicodeString(&Service->ServiceGroup);
336 RtlFreeUnicodeString(&Service->ImagePath);
341 /* Copy service name */
342 Service->ServiceName.Length = ServiceName->Length;
343 Service->ServiceName.MaximumLength = ServiceName->Length + sizeof(WCHAR);
344 Service->ServiceName.Buffer = ExAllocatePool(NonPagedPool,
345 Service->ServiceName.MaximumLength);
346 RtlCopyMemory(Service->ServiceName.Buffer,
348 ServiceName->Length);
349 Service->ServiceName.Buffer[ServiceName->Length / sizeof(WCHAR)] = 0;
351 /* Build registry path */
352 Service->RegistryPath.MaximumLength = MAX_PATH * sizeof(WCHAR);
353 Service->RegistryPath.Buffer = ExAllocatePool(NonPagedPool,
354 MAX_PATH * sizeof(WCHAR));
355 wcscpy(Service->RegistryPath.Buffer,
356 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
357 wcscat(Service->RegistryPath.Buffer,
358 Service->ServiceName.Buffer);
359 Service->RegistryPath.Length = wcslen(Service->RegistryPath.Buffer) * sizeof(WCHAR);
361 DPRINT("ServiceName: '%wZ'\n", &Service->ServiceName);
362 DPRINT("RegistryPath: '%wZ'\n", &Service->RegistryPath);
363 DPRINT("ServiceGroup: '%wZ'\n", &Service->ServiceGroup);
364 DPRINT("ImagePath: '%wZ'\n", &Service->ImagePath);
365 DPRINT("Start %lx Type %lx ErrorControl %lx\n",
366 Service->Start, Service->Type, Service->ErrorControl);
368 /* Append service entry */
369 InsertTailList(&ServiceListHead,
370 &Service->ServiceListEntry);
372 return(STATUS_SUCCESS);
377 IoCreateDriverList(VOID)
379 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
380 PKEY_BASIC_INFORMATION KeyInfo = NULL;
381 OBJECT_ATTRIBUTES ObjectAttributes;
382 UNICODE_STRING ServicesKeyName;
383 UNICODE_STRING SubKeyName;
388 ULONG KeyInfoLength = 0;
389 ULONG ReturnedLength;
391 DPRINT("IoCreateDriverList() called\n");
393 /* Initialize basic variables */
394 InitializeListHead(&GroupListHead);
395 InitializeListHead(&ServiceListHead);
397 /* Build group order list */
398 RtlZeroMemory(&QueryTable,
401 QueryTable[0].Name = L"List";
402 QueryTable[0].QueryRoutine = IopCreateGroupListEntry;
404 Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
405 L"ServiceGroupOrder",
409 if (!NT_SUCCESS(Status))
412 /* Enumerate services and create the service list */
413 RtlInitUnicodeStringFromLiteral(&ServicesKeyName,
414 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services");
416 InitializeObjectAttributes(&ObjectAttributes,
418 OBJ_CASE_INSENSITIVE,
422 Status = NtOpenKey(&KeyHandle,
425 if (!NT_SUCCESS(Status))
430 KeyInfoLength = sizeof(KEY_BASIC_INFORMATION) + MAX_PATH * sizeof(WCHAR);
431 KeyInfo = ExAllocatePool(NonPagedPool, KeyInfoLength);
435 return(STATUS_INSUFFICIENT_RESOURCES);
441 Status = NtEnumerateKey(KeyHandle,
447 if (NT_SUCCESS(Status))
449 if (KeyInfo->NameLength < MAX_PATH * sizeof(WCHAR))
452 SubKeyName.Length = KeyInfo->NameLength;
453 SubKeyName.MaximumLength = KeyInfo->NameLength + sizeof(WCHAR);
454 SubKeyName.Buffer = KeyInfo->Name;
455 SubKeyName.Buffer[SubKeyName.Length / sizeof(WCHAR)] = 0;
457 DPRINT("KeyName: '%wZ'\n", &SubKeyName);
458 IopCreateServiceListEntry(&SubKeyName);
462 if (!NT_SUCCESS(Status))
471 DPRINT("IoCreateDriverList() done\n");
473 return(STATUS_SUCCESS);
478 LdrLoadAutoConfigDrivers(VOID)
480 PLIST_ENTRY GroupEntry;
481 PLIST_ENTRY ServiceEntry;
482 PSERVICE_GROUP CurrentGroup;
483 PSERVICE CurrentService;
486 CHAR TextBuffer [256];
489 DPRINT("LdrLoadAutoConfigDrivers() called\n");
491 GroupEntry = GroupListHead.Flink;
492 while (GroupEntry != &GroupListHead)
494 CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry);
496 DPRINT("Group: %wZ\n", &CurrentGroup->GroupName);
498 ServiceEntry = ServiceListHead.Flink;
499 while (ServiceEntry != &ServiceListHead)
501 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
503 if ((RtlCompareUnicodeString(&CurrentGroup->GroupName, &CurrentService->ServiceGroup, TRUE) == 0) &&
504 (CurrentService->Start == 1 /*SERVICE_SYSTEM_START*/))
507 HalQueryDisplayParameters(&x, &y, &cx, &cy);
508 RtlFillMemory(TextBuffer, x, ' ');
509 TextBuffer[x] = '\0';
510 HalSetDisplayParameters(0, y-1);
511 HalDisplayString(TextBuffer);
513 sprintf(TextBuffer, "Loading %S...\n", CurrentService->ServiceName.Buffer);
514 HalSetDisplayParameters(0, y-1);
515 HalDisplayString(TextBuffer);
516 HalSetDisplayParameters(cx, cy);
518 DPRINT(" Path: %wZ\n", &CurrentService->RegistryPath);
519 Status = NtLoadDriver(&CurrentService->RegistryPath);
520 if (!NT_SUCCESS(Status))
522 DPRINT("NtLoadDriver() failed (Status %lx)\n", Status);
524 if (CurrentService->ErrorControl == 1)
529 else if (CurrentService->ErrorControl == 2)
531 if (IsLastKnownGood == FALSE)
533 /* Boot last known good configuration */
537 else if (CurrentService->ErrorControl == 3)
539 if (IsLastKnownGood == FALSE)
541 /* Boot last known good configuration */
553 ServiceEntry = ServiceEntry->Flink;
556 GroupEntry = GroupEntry->Flink;
559 DPRINT("LdrLoadAutoConfigDrivers() done\n");
564 IoDestroyDriverList(VOID)
566 PLIST_ENTRY GroupEntry;
567 PLIST_ENTRY ServiceEntry;
568 PSERVICE_GROUP CurrentGroup;
569 PSERVICE CurrentService;
571 DPRINT("IoDestroyDriverList() called\n");
573 /* Destroy group list */
574 GroupEntry = GroupListHead.Flink;
575 while (GroupEntry != &GroupListHead)
577 CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry);
579 RtlFreeUnicodeString(&CurrentGroup->GroupName);
580 RemoveEntryList(GroupEntry);
581 ExFreePool(CurrentGroup);
583 GroupEntry = GroupListHead.Flink;
586 /* Destroy service list */
587 ServiceEntry = ServiceListHead.Flink;
588 while (ServiceEntry != &ServiceListHead)
590 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
592 RtlFreeUnicodeString(&CurrentService->ServiceName);
593 RtlFreeUnicodeString(&CurrentService->RegistryPath);
594 RtlFreeUnicodeString(&CurrentService->ServiceGroup);
595 RtlFreeUnicodeString(&CurrentService->ImagePath);
596 RemoveEntryList(ServiceEntry);
597 ExFreePool(CurrentService);
599 ServiceEntry = ServiceListHead.Flink;
602 DPRINT("IoDestroyDriverList() done\n");
604 return(STATUS_SUCCESS);