1 /* $Id: driver.c,v 1.12 2002/09/08 10:23:24 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 ****************************************************************/
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
);