1 /* $Id: driver.c,v 1.11 2002/09/07 15:12:52 chorns Exp $
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 ****************************************************************/
17 #include <internal/debug.h>
20 typedef struct _SERVICE_GROUP
22 LIST_ENTRY GroupListEntry
;
23 UNICODE_STRING GroupName
;
25 BOOLEAN ServicesRunning
;
27 } SERVICE_GROUP
, *PSERVICE_GROUP
;
30 typedef struct _SERVICE
32 LIST_ENTRY ServiceListEntry
;
33 UNICODE_STRING ServiceName
;
34 UNICODE_STRING RegistryPath
;
35 UNICODE_STRING ServiceGroup
;
36 UNICODE_STRING ImagePath
;
43 BOOLEAN ServiceRunning
; // needed ??
48 /* GLOBALS *******************************************************************/
50 static LIST_ENTRY GroupListHead
= {NULL
, NULL
};
51 static LIST_ENTRY ServiceListHead
= {NULL
, NULL
};
53 POBJECT_TYPE IoDriverObjectType
= NULL
;
55 #define TAG_DRIVER TAG('D', 'R', 'V', 'R')
56 #define TAG_DRIVER_EXTENSION TAG('D', 'R', 'V', 'E')
59 /* FUNCTIONS ***************************************************************/
62 IopCreateDriver(PVOID ObjectBody
,
65 POBJECT_ATTRIBUTES ObjectAttributes
)
67 DPRINT("LdrCreateModule(ObjectBody %x, Parent %x, RemainingPath %S)\n",
71 if (RemainingPath
!= NULL
&& wcschr(RemainingPath
+ 1, '\\') != NULL
)
73 return(STATUS_UNSUCCESSFUL
);
76 return(STATUS_SUCCESS
);
81 IopInitDriverImplementation(VOID
)
83 /* Register the process object type */
84 IoDriverObjectType
= ExAllocatePool(NonPagedPool
, sizeof(OBJECT_TYPE
));
85 IoDriverObjectType
->Tag
= TAG('D', 'R', 'V', 'R');
86 IoDriverObjectType
->TotalObjects
= 0;
87 IoDriverObjectType
->TotalHandles
= 0;
88 IoDriverObjectType
->MaxObjects
= ULONG_MAX
;
89 IoDriverObjectType
->MaxHandles
= ULONG_MAX
;
90 IoDriverObjectType
->PagedPoolCharge
= 0;
91 IoDriverObjectType
->NonpagedPoolCharge
= sizeof(DRIVER_OBJECT
);
92 IoDriverObjectType
->Dump
= NULL
;
93 IoDriverObjectType
->Open
= NULL
;
94 IoDriverObjectType
->Close
= NULL
;
95 IoDriverObjectType
->Delete
= NULL
;
96 IoDriverObjectType
->Parse
= NULL
;
97 IoDriverObjectType
->Security
= NULL
;
98 IoDriverObjectType
->QueryName
= NULL
;
99 IoDriverObjectType
->OkayToClose
= NULL
;
100 IoDriverObjectType
->Create
= IopCreateDriver
;
101 IoDriverObjectType
->DuplicationNotify
= NULL
;
102 RtlInitUnicodeStringFromLiteral(&IoDriverObjectType
->TypeName
, L
"Driver");
105 /**********************************************************************
110 * Loads a device driver.
114 * Name of the service to load (registry key).
122 NtLoadDriver(IN PUNICODE_STRING DriverServiceName
)
124 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
125 WCHAR FullImagePathBuffer
[MAX_PATH
];
126 UNICODE_STRING ImagePath
;
127 UNICODE_STRING FullImagePath
;
130 PDEVICE_NODE DeviceNode
;
131 PMODULE_OBJECT ModuleObject
;
134 DPRINT("NtLoadDriver(%wZ) called\n", DriverServiceName
);
136 RtlInitUnicodeString(&ImagePath
, NULL
);
138 /* Get service data */
139 RtlZeroMemory(&QueryTable
,
142 QueryTable
[0].Name
= L
"Type";
143 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
144 QueryTable
[0].EntryContext
= &Type
;
146 QueryTable
[1].Name
= L
"ImagePath";
147 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
148 QueryTable
[1].EntryContext
= &ImagePath
;
150 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
151 DriverServiceName
->Buffer
,
155 if (!NT_SUCCESS(Status
))
157 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
158 RtlFreeUnicodeString(&ImagePath
);
162 if (ImagePath
.Length
== 0)
164 wcscpy(FullImagePathBuffer
, L
"\\SystemRoot\\system32\\drivers");
165 wcscat(FullImagePathBuffer
, wcsrchr(DriverServiceName
->Buffer
, L
'\\'));
166 wcscat(FullImagePathBuffer
, L
".sys");
168 else if (ImagePath
.Buffer
[0] != L
'\\')
170 wcscpy(FullImagePathBuffer
, L
"\\SystemRoot\\");
171 wcscat(FullImagePathBuffer
, ImagePath
.Buffer
);
175 wcscpy(FullImagePathBuffer
, ImagePath
.Buffer
);
178 RtlFreeUnicodeString(&ImagePath
);
179 RtlInitUnicodeString(&FullImagePath
, FullImagePathBuffer
);
181 DPRINT("FullImagePath: '%S'\n", FullImagePathBuffer
);
182 DPRINT("Type %lx\n", Type
);
184 /* Use IopRootDeviceNode for now */
185 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &DeviceNode
);
186 if (!NT_SUCCESS(Status
))
188 DPRINT1("IopCreateDeviceNode() failed (Status %lx)\n", Status
);
192 ModuleObject
= LdrGetModuleObject(DriverServiceName
);
193 if (ModuleObject
!= NULL
)
195 return(STATUS_IMAGE_ALREADY_LOADED
);
198 Status
= LdrLoadModule(&FullImagePath
, &ModuleObject
);
199 if (!NT_SUCCESS(Status
))
201 DPRINT1("LdrLoadModule() failed (Status %lx)\n", Status
);
202 IopFreeDeviceNode(DeviceNode
);
206 /* Set a service name for the device node */
207 Start
= wcsrchr(DriverServiceName
->Buffer
, L
'\\');
209 Start
= DriverServiceName
->Buffer
;
212 RtlCreateUnicodeString(&DeviceNode
->ServiceName
, Start
);
214 Status
= IopInitializeDriver(ModuleObject
->EntryPoint
,
216 (Type
== 2 || Type
== 8));
217 if (!NT_SUCCESS(Status
))
219 DPRINT1("IopInitializeDriver() failed (Status %lx)\n", Status
);
220 LdrUnloadModule(ModuleObject
);
221 IopFreeDeviceNode(DeviceNode
);
229 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName
)
231 DPRINT("DriverServiceName: '%wZ'\n", DriverServiceName
);
233 return(STATUS_NOT_IMPLEMENTED
);
237 static NTSTATUS STDCALL
238 IopCreateGroupListEntry(PWSTR ValueName
,
245 PSERVICE_GROUP Group
;
247 if (ValueType
== REG_SZ
)
249 DPRINT("GroupName: '%S'\n", (PWCHAR
)ValueData
);
251 Group
= ExAllocatePool(NonPagedPool
,
252 sizeof(SERVICE_GROUP
));
255 return(STATUS_INSUFFICIENT_RESOURCES
);
258 RtlZeroMemory(Group
, sizeof(SERVICE_GROUP
));
260 if (!RtlCreateUnicodeString(&Group
->GroupName
,
263 return(STATUS_INSUFFICIENT_RESOURCES
);
267 InsertTailList(&GroupListHead
,
268 &Group
->GroupListEntry
);
271 return(STATUS_SUCCESS
);
275 static NTSTATUS STDCALL
276 IopCreateServiceListEntry(PUNICODE_STRING ServiceName
)
278 RTL_QUERY_REGISTRY_TABLE QueryTable
[6];
282 DPRINT("ServiceName: '%wZ'\n", ServiceName
);
284 /* Allocate service entry */
285 Service
= (PSERVICE
)ExAllocatePool(NonPagedPool
, sizeof(SERVICE
));
288 DPRINT1("ExAllocatePool() failed\n");
289 return(STATUS_INSUFFICIENT_RESOURCES
);
291 RtlZeroMemory(Service
, sizeof(SERVICE
));
293 /* Get service data */
294 RtlZeroMemory(&QueryTable
,
297 QueryTable
[0].Name
= L
"Start";
298 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
299 QueryTable
[0].EntryContext
= &Service
->Start
;
301 QueryTable
[1].Name
= L
"Type";
302 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
303 QueryTable
[1].EntryContext
= &Service
->Type
;
305 QueryTable
[2].Name
= L
"ErrorControl";
306 QueryTable
[2].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
307 QueryTable
[2].EntryContext
= &Service
->ErrorControl
;
309 QueryTable
[3].Name
= L
"Group";
310 QueryTable
[3].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
311 QueryTable
[3].EntryContext
= &Service
->ServiceGroup
;
313 QueryTable
[4].Name
= L
"ImagePath";
314 QueryTable
[4].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
315 QueryTable
[4].EntryContext
= &Service
->ImagePath
;
317 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
322 if (!NT_SUCCESS(Status
) || Service
->Start
> 1)
324 RtlFreeUnicodeString(&Service
->ServiceGroup
);
325 RtlFreeUnicodeString(&Service
->ImagePath
);
330 /* Copy service name */
331 Service
->ServiceName
.Length
= ServiceName
->Length
;
332 Service
->ServiceName
.MaximumLength
= ServiceName
->Length
+ sizeof(WCHAR
);
333 Service
->ServiceName
.Buffer
= ExAllocatePool(NonPagedPool
,
334 Service
->ServiceName
.MaximumLength
);
335 RtlCopyMemory(Service
->ServiceName
.Buffer
,
337 ServiceName
->Length
);
338 Service
->ServiceName
.Buffer
[ServiceName
->Length
/ sizeof(WCHAR
)] = 0;
340 /* Build registry path */
341 Service
->RegistryPath
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
342 Service
->RegistryPath
.Buffer
= ExAllocatePool(NonPagedPool
,
343 MAX_PATH
* sizeof(WCHAR
));
344 wcscpy(Service
->RegistryPath
.Buffer
,
345 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
346 wcscat(Service
->RegistryPath
.Buffer
,
347 Service
->ServiceName
.Buffer
);
348 Service
->RegistryPath
.Length
= wcslen(Service
->RegistryPath
.Buffer
) * sizeof(WCHAR
);
350 DPRINT("ServiceName: '%wZ'\n", &Service
->ServiceName
);
351 DPRINT("RegistryPath: '%wZ'\n", &Service
->RegistryPath
);
352 DPRINT("ServiceGroup: '%wZ'\n", &Service
->ServiceGroup
);
353 DPRINT("ImagePath: '%wZ'\n", &Service
->ImagePath
);
354 DPRINT("Start %lx Type %lx ErrorControl %lx\n",
355 Service
->Start
, Service
->Type
, Service
->ErrorControl
);
357 /* Append service entry */
358 InsertTailList(&ServiceListHead
,
359 &Service
->ServiceListEntry
);
361 return(STATUS_SUCCESS
);
366 IoCreateDriverList(VOID
)
368 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
369 PKEY_BASIC_INFORMATION KeyInfo
= NULL
;
370 OBJECT_ATTRIBUTES ObjectAttributes
;
371 UNICODE_STRING ServicesKeyName
;
372 UNICODE_STRING SubKeyName
;
377 ULONG KeyInfoLength
= 0;
378 ULONG ReturnedLength
;
380 DPRINT("IoCreateDriverList() called\n");
382 /* Initialize basic variables */
383 InitializeListHead(&GroupListHead
);
384 InitializeListHead(&ServiceListHead
);
386 /* Build group order list */
387 RtlZeroMemory(&QueryTable
,
390 QueryTable
[0].Name
= L
"List";
391 QueryTable
[0].QueryRoutine
= IopCreateGroupListEntry
;
393 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
394 L
"ServiceGroupOrder",
398 if (!NT_SUCCESS(Status
))
401 /* Enumerate services and create the service list */
402 RtlInitUnicodeStringFromLiteral(&ServicesKeyName
,
403 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services");
405 InitializeObjectAttributes(&ObjectAttributes
,
407 OBJ_CASE_INSENSITIVE
,
411 Status
= NtOpenKey(&KeyHandle
,
414 if (!NT_SUCCESS(Status
))
419 KeyInfoLength
= sizeof(KEY_BASIC_INFORMATION
) + MAX_PATH
* sizeof(WCHAR
);
420 KeyInfo
= ExAllocatePool(NonPagedPool
, KeyInfoLength
);
424 return(STATUS_INSUFFICIENT_RESOURCES
);
430 Status
= NtEnumerateKey(KeyHandle
,
436 if (NT_SUCCESS(Status
))
438 if (KeyInfo
->NameLength
< MAX_PATH
* sizeof(WCHAR
))
441 SubKeyName
.Length
= KeyInfo
->NameLength
;
442 SubKeyName
.MaximumLength
= KeyInfo
->NameLength
+ sizeof(WCHAR
);
443 SubKeyName
.Buffer
= KeyInfo
->Name
;
444 SubKeyName
.Buffer
[SubKeyName
.Length
/ sizeof(WCHAR
)] = 0;
446 DPRINT("KeyName: '%wZ'\n", &SubKeyName
);
447 IopCreateServiceListEntry(&SubKeyName
);
451 if (!NT_SUCCESS(Status
))
460 DPRINT("IoCreateDriverList() done\n");
462 return(STATUS_SUCCESS
);
467 LdrLoadAutoConfigDrivers(VOID
)
469 PLIST_ENTRY GroupEntry
;
470 PLIST_ENTRY ServiceEntry
;
471 PSERVICE_GROUP CurrentGroup
;
472 PSERVICE CurrentService
;
475 CHAR TextBuffer
[256];
478 DPRINT("LdrLoadAutoConfigDrivers() called\n");
480 GroupEntry
= GroupListHead
.Flink
;
481 while (GroupEntry
!= &GroupListHead
)
483 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
485 DPRINT("Group: %wZ\n", &CurrentGroup
->GroupName
);
487 ServiceEntry
= ServiceListHead
.Flink
;
488 while (ServiceEntry
!= &ServiceListHead
)
490 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
492 if ((RtlCompareUnicodeString(&CurrentGroup
->GroupName
, &CurrentService
->ServiceGroup
, TRUE
) == 0) &&
493 (CurrentService
->Start
== 1 /*SERVICE_SYSTEM_START*/))
496 HalQueryDisplayParameters(&x
, &y
, &cx
, &cy
);
497 RtlFillMemory(TextBuffer
, x
, ' ');
498 TextBuffer
[x
] = '\0';
499 HalSetDisplayParameters(0, y
-1);
500 HalDisplayString(TextBuffer
);
502 sprintf(TextBuffer
, "Loading %S...\n", CurrentService
->ServiceName
.Buffer
);
503 HalSetDisplayParameters(0, y
-1);
504 HalDisplayString(TextBuffer
);
505 HalSetDisplayParameters(cx
, cy
);
507 DPRINT(" Path: %wZ\n", &CurrentService
->RegistryPath
);
508 Status
= NtLoadDriver(&CurrentService
->RegistryPath
);
509 if (!NT_SUCCESS(Status
))
511 DPRINT("NtLoadDriver() failed (Status %lx)\n", Status
);
513 if (CurrentService
->ErrorControl
== 1)
518 else if (CurrentService
->ErrorControl
== 2)
520 if (IsLastKnownGood
== FALSE
)
522 /* Boot last known good configuration */
526 else if (CurrentService
->ErrorControl
== 3)
528 if (IsLastKnownGood
== FALSE
)
530 /* Boot last known good configuration */
542 ServiceEntry
= ServiceEntry
->Flink
;
545 GroupEntry
= GroupEntry
->Flink
;
548 DPRINT("LdrLoadAutoConfigDrivers() done\n");
553 IoDestroyDriverList(VOID
)
555 PLIST_ENTRY GroupEntry
;
556 PLIST_ENTRY ServiceEntry
;
557 PSERVICE_GROUP CurrentGroup
;
558 PSERVICE CurrentService
;
560 DPRINT("IoDestroyDriverList() called\n");
562 /* Destroy group list */
563 GroupEntry
= GroupListHead
.Flink
;
564 while (GroupEntry
!= &GroupListHead
)
566 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
568 RtlFreeUnicodeString(&CurrentGroup
->GroupName
);
569 RemoveEntryList(GroupEntry
);
570 ExFreePool(CurrentGroup
);
572 GroupEntry
= GroupListHead
.Flink
;
575 /* Destroy service list */
576 ServiceEntry
= ServiceListHead
.Flink
;
577 while (ServiceEntry
!= &ServiceListHead
)
579 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
581 RtlFreeUnicodeString(&CurrentService
->ServiceName
);
582 RtlFreeUnicodeString(&CurrentService
->RegistryPath
);
583 RtlFreeUnicodeString(&CurrentService
->ServiceGroup
);
584 RtlFreeUnicodeString(&CurrentService
->ImagePath
);
585 RemoveEntryList(ServiceEntry
);
586 ExFreePool(CurrentService
);
588 ServiceEntry
= ServiceListHead
.Flink
;
591 DPRINT("IoDestroyDriverList() done\n");
593 return(STATUS_SUCCESS
);