1 /* $Id: driver.c,v 1.13 2003/07/10 15:47:00 royce 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 ***************************************************************/
74 IopCreateDriver(PVOID ObjectBody
,
77 POBJECT_ATTRIBUTES ObjectAttributes
)
79 DPRINT("LdrCreateModule(ObjectBody %x, Parent %x, RemainingPath %S)\n",
83 if (RemainingPath
!= NULL
&& wcschr(RemainingPath
+ 1, '\\') != NULL
)
85 return(STATUS_UNSUCCESSFUL
);
88 return(STATUS_SUCCESS
);
93 IopInitDriverImplementation(VOID
)
95 /* Register the process object type */
96 IoDriverObjectType
= ExAllocatePool(NonPagedPool
, sizeof(OBJECT_TYPE
));
97 IoDriverObjectType
->Tag
= TAG('D', 'R', 'V', 'R');
98 IoDriverObjectType
->TotalObjects
= 0;
99 IoDriverObjectType
->TotalHandles
= 0;
100 IoDriverObjectType
->MaxObjects
= ULONG_MAX
;
101 IoDriverObjectType
->MaxHandles
= ULONG_MAX
;
102 IoDriverObjectType
->PagedPoolCharge
= 0;
103 IoDriverObjectType
->NonpagedPoolCharge
= sizeof(DRIVER_OBJECT
);
104 IoDriverObjectType
->Dump
= NULL
;
105 IoDriverObjectType
->Open
= NULL
;
106 IoDriverObjectType
->Close
= NULL
;
107 IoDriverObjectType
->Delete
= NULL
;
108 IoDriverObjectType
->Parse
= NULL
;
109 IoDriverObjectType
->Security
= NULL
;
110 IoDriverObjectType
->QueryName
= NULL
;
111 IoDriverObjectType
->OkayToClose
= NULL
;
112 IoDriverObjectType
->Create
= IopCreateDriver
;
113 IoDriverObjectType
->DuplicationNotify
= NULL
;
114 RtlInitUnicodeStringFromLiteral(&IoDriverObjectType
->TypeName
, L
"Driver");
117 /**********************************************************************
122 * Loads a device driver.
126 * Name of the service to load (registry key).
136 NtLoadDriver(IN PUNICODE_STRING DriverServiceName
)
138 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
139 WCHAR FullImagePathBuffer
[MAX_PATH
];
140 UNICODE_STRING ImagePath
;
141 UNICODE_STRING FullImagePath
;
144 PDEVICE_NODE DeviceNode
;
145 PMODULE_OBJECT ModuleObject
;
148 DPRINT("NtLoadDriver(%wZ) called\n", DriverServiceName
);
150 RtlInitUnicodeString(&ImagePath
, NULL
);
152 /* Get service data */
153 RtlZeroMemory(&QueryTable
,
156 QueryTable
[0].Name
= L
"Type";
157 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
158 QueryTable
[0].EntryContext
= &Type
;
160 QueryTable
[1].Name
= L
"ImagePath";
161 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
162 QueryTable
[1].EntryContext
= &ImagePath
;
164 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
165 DriverServiceName
->Buffer
,
169 if (!NT_SUCCESS(Status
))
171 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
172 RtlFreeUnicodeString(&ImagePath
);
176 if (ImagePath
.Length
== 0)
178 wcscpy(FullImagePathBuffer
, L
"\\SystemRoot\\system32\\drivers");
179 wcscat(FullImagePathBuffer
, wcsrchr(DriverServiceName
->Buffer
, L
'\\'));
180 wcscat(FullImagePathBuffer
, L
".sys");
182 else if (ImagePath
.Buffer
[0] != L
'\\')
184 wcscpy(FullImagePathBuffer
, L
"\\SystemRoot\\");
185 wcscat(FullImagePathBuffer
, ImagePath
.Buffer
);
189 wcscpy(FullImagePathBuffer
, ImagePath
.Buffer
);
192 RtlFreeUnicodeString(&ImagePath
);
193 RtlInitUnicodeString(&FullImagePath
, FullImagePathBuffer
);
195 DPRINT("FullImagePath: '%S'\n", FullImagePathBuffer
);
196 DPRINT("Type %lx\n", Type
);
198 /* Use IopRootDeviceNode for now */
199 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &DeviceNode
);
200 if (!NT_SUCCESS(Status
))
202 DPRINT1("IopCreateDeviceNode() failed (Status %lx)\n", Status
);
206 ModuleObject
= LdrGetModuleObject(DriverServiceName
);
207 if (ModuleObject
!= NULL
)
209 return(STATUS_IMAGE_ALREADY_LOADED
);
212 Status
= LdrLoadModule(&FullImagePath
, &ModuleObject
);
213 if (!NT_SUCCESS(Status
))
215 DPRINT1("LdrLoadModule() failed (Status %lx)\n", Status
);
216 IopFreeDeviceNode(DeviceNode
);
220 /* Set a service name for the device node */
221 Start
= wcsrchr(DriverServiceName
->Buffer
, L
'\\');
223 Start
= DriverServiceName
->Buffer
;
226 RtlCreateUnicodeString(&DeviceNode
->ServiceName
, Start
);
228 Status
= IopInitializeDriver(ModuleObject
->EntryPoint
,
230 (Type
== 2 || Type
== 8));
231 if (!NT_SUCCESS(Status
))
233 DPRINT1("IopInitializeDriver() failed (Status %lx)\n", Status
);
234 LdrUnloadModule(ModuleObject
);
235 IopFreeDeviceNode(DeviceNode
);
246 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName
)
248 DPRINT("DriverServiceName: '%wZ'\n", DriverServiceName
);
250 return(STATUS_NOT_IMPLEMENTED
);
257 static NTSTATUS STDCALL
258 IopCreateGroupListEntry(PWSTR ValueName
,
265 PSERVICE_GROUP Group
;
267 if (ValueType
== REG_SZ
)
269 DPRINT("GroupName: '%S'\n", (PWCHAR
)ValueData
);
271 Group
= ExAllocatePool(NonPagedPool
,
272 sizeof(SERVICE_GROUP
));
275 return(STATUS_INSUFFICIENT_RESOURCES
);
278 RtlZeroMemory(Group
, sizeof(SERVICE_GROUP
));
280 if (!RtlCreateUnicodeString(&Group
->GroupName
,
283 return(STATUS_INSUFFICIENT_RESOURCES
);
287 InsertTailList(&GroupListHead
,
288 &Group
->GroupListEntry
);
291 return(STATUS_SUCCESS
);
298 static NTSTATUS STDCALL
299 IopCreateServiceListEntry(PUNICODE_STRING ServiceName
)
301 RTL_QUERY_REGISTRY_TABLE QueryTable
[6];
305 DPRINT("ServiceName: '%wZ'\n", ServiceName
);
307 /* Allocate service entry */
308 Service
= (PSERVICE
)ExAllocatePool(NonPagedPool
, sizeof(SERVICE
));
311 DPRINT1("ExAllocatePool() failed\n");
312 return(STATUS_INSUFFICIENT_RESOURCES
);
314 RtlZeroMemory(Service
, sizeof(SERVICE
));
316 /* Get service data */
317 RtlZeroMemory(&QueryTable
,
320 QueryTable
[0].Name
= L
"Start";
321 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
322 QueryTable
[0].EntryContext
= &Service
->Start
;
324 QueryTable
[1].Name
= L
"Type";
325 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
326 QueryTable
[1].EntryContext
= &Service
->Type
;
328 QueryTable
[2].Name
= L
"ErrorControl";
329 QueryTable
[2].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
330 QueryTable
[2].EntryContext
= &Service
->ErrorControl
;
332 QueryTable
[3].Name
= L
"Group";
333 QueryTable
[3].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
334 QueryTable
[3].EntryContext
= &Service
->ServiceGroup
;
336 QueryTable
[4].Name
= L
"ImagePath";
337 QueryTable
[4].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
338 QueryTable
[4].EntryContext
= &Service
->ImagePath
;
340 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
345 if (!NT_SUCCESS(Status
) || Service
->Start
> 1)
347 RtlFreeUnicodeString(&Service
->ServiceGroup
);
348 RtlFreeUnicodeString(&Service
->ImagePath
);
353 /* Copy service name */
354 Service
->ServiceName
.Length
= ServiceName
->Length
;
355 Service
->ServiceName
.MaximumLength
= ServiceName
->Length
+ sizeof(WCHAR
);
356 Service
->ServiceName
.Buffer
= ExAllocatePool(NonPagedPool
,
357 Service
->ServiceName
.MaximumLength
);
358 RtlCopyMemory(Service
->ServiceName
.Buffer
,
360 ServiceName
->Length
);
361 Service
->ServiceName
.Buffer
[ServiceName
->Length
/ sizeof(WCHAR
)] = 0;
363 /* Build registry path */
364 Service
->RegistryPath
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
365 Service
->RegistryPath
.Buffer
= ExAllocatePool(NonPagedPool
,
366 MAX_PATH
* sizeof(WCHAR
));
367 wcscpy(Service
->RegistryPath
.Buffer
,
368 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
369 wcscat(Service
->RegistryPath
.Buffer
,
370 Service
->ServiceName
.Buffer
);
371 Service
->RegistryPath
.Length
= wcslen(Service
->RegistryPath
.Buffer
) * sizeof(WCHAR
);
373 DPRINT("ServiceName: '%wZ'\n", &Service
->ServiceName
);
374 DPRINT("RegistryPath: '%wZ'\n", &Service
->RegistryPath
);
375 DPRINT("ServiceGroup: '%wZ'\n", &Service
->ServiceGroup
);
376 DPRINT("ImagePath: '%wZ'\n", &Service
->ImagePath
);
377 DPRINT("Start %lx Type %lx ErrorControl %lx\n",
378 Service
->Start
, Service
->Type
, Service
->ErrorControl
);
380 /* Append service entry */
381 InsertTailList(&ServiceListHead
,
382 &Service
->ServiceListEntry
);
384 return(STATUS_SUCCESS
);
389 IoCreateDriverList(VOID
)
391 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
392 PKEY_BASIC_INFORMATION KeyInfo
= NULL
;
393 OBJECT_ATTRIBUTES ObjectAttributes
;
394 UNICODE_STRING ServicesKeyName
;
395 UNICODE_STRING SubKeyName
;
400 ULONG KeyInfoLength
= 0;
401 ULONG ReturnedLength
;
403 DPRINT("IoCreateDriverList() called\n");
405 /* Initialize basic variables */
406 InitializeListHead(&GroupListHead
);
407 InitializeListHead(&ServiceListHead
);
409 /* Build group order list */
410 RtlZeroMemory(&QueryTable
,
413 QueryTable
[0].Name
= L
"List";
414 QueryTable
[0].QueryRoutine
= IopCreateGroupListEntry
;
416 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
417 L
"ServiceGroupOrder",
421 if (!NT_SUCCESS(Status
))
424 /* Enumerate services and create the service list */
425 RtlInitUnicodeStringFromLiteral(&ServicesKeyName
,
426 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services");
428 InitializeObjectAttributes(&ObjectAttributes
,
430 OBJ_CASE_INSENSITIVE
,
434 Status
= NtOpenKey(&KeyHandle
,
437 if (!NT_SUCCESS(Status
))
442 KeyInfoLength
= sizeof(KEY_BASIC_INFORMATION
) + MAX_PATH
* sizeof(WCHAR
);
443 KeyInfo
= ExAllocatePool(NonPagedPool
, KeyInfoLength
);
447 return(STATUS_INSUFFICIENT_RESOURCES
);
453 Status
= NtEnumerateKey(KeyHandle
,
459 if (NT_SUCCESS(Status
))
461 if (KeyInfo
->NameLength
< MAX_PATH
* sizeof(WCHAR
))
464 SubKeyName
.Length
= KeyInfo
->NameLength
;
465 SubKeyName
.MaximumLength
= KeyInfo
->NameLength
+ sizeof(WCHAR
);
466 SubKeyName
.Buffer
= KeyInfo
->Name
;
467 SubKeyName
.Buffer
[SubKeyName
.Length
/ sizeof(WCHAR
)] = 0;
469 DPRINT("KeyName: '%wZ'\n", &SubKeyName
);
470 IopCreateServiceListEntry(&SubKeyName
);
474 if (!NT_SUCCESS(Status
))
483 DPRINT("IoCreateDriverList() done\n");
485 return(STATUS_SUCCESS
);
490 LdrLoadAutoConfigDrivers(VOID
)
492 PLIST_ENTRY GroupEntry
;
493 PLIST_ENTRY ServiceEntry
;
494 PSERVICE_GROUP CurrentGroup
;
495 PSERVICE CurrentService
;
498 CHAR TextBuffer
[256];
501 DPRINT("LdrLoadAutoConfigDrivers() called\n");
503 GroupEntry
= GroupListHead
.Flink
;
504 while (GroupEntry
!= &GroupListHead
)
506 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
508 DPRINT("Group: %wZ\n", &CurrentGroup
->GroupName
);
510 ServiceEntry
= ServiceListHead
.Flink
;
511 while (ServiceEntry
!= &ServiceListHead
)
513 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
515 if ((RtlCompareUnicodeString(&CurrentGroup
->GroupName
, &CurrentService
->ServiceGroup
, TRUE
) == 0) &&
516 (CurrentService
->Start
== 1 /*SERVICE_SYSTEM_START*/))
519 HalQueryDisplayParameters(&x
, &y
, &cx
, &cy
);
520 RtlFillMemory(TextBuffer
, x
, ' ');
521 TextBuffer
[x
] = '\0';
522 HalSetDisplayParameters(0, y
-1);
523 HalDisplayString(TextBuffer
);
525 sprintf(TextBuffer
, "Loading %S...\n", CurrentService
->ServiceName
.Buffer
);
526 HalSetDisplayParameters(0, y
-1);
527 HalDisplayString(TextBuffer
);
528 HalSetDisplayParameters(cx
, cy
);
530 DPRINT(" Path: %wZ\n", &CurrentService
->RegistryPath
);
531 Status
= NtLoadDriver(&CurrentService
->RegistryPath
);
532 if (!NT_SUCCESS(Status
))
534 DPRINT("NtLoadDriver() failed (Status %lx)\n", Status
);
536 if (CurrentService
->ErrorControl
== 1)
541 else if (CurrentService
->ErrorControl
== 2)
543 if (IsLastKnownGood
== FALSE
)
545 /* Boot last known good configuration */
549 else if (CurrentService
->ErrorControl
== 3)
551 if (IsLastKnownGood
== FALSE
)
553 /* Boot last known good configuration */
565 ServiceEntry
= ServiceEntry
->Flink
;
568 GroupEntry
= GroupEntry
->Flink
;
571 DPRINT("LdrLoadAutoConfigDrivers() done\n");
576 IoDestroyDriverList(VOID
)
578 PLIST_ENTRY GroupEntry
;
579 PLIST_ENTRY ServiceEntry
;
580 PSERVICE_GROUP CurrentGroup
;
581 PSERVICE CurrentService
;
583 DPRINT("IoDestroyDriverList() called\n");
585 /* Destroy group list */
586 GroupEntry
= GroupListHead
.Flink
;
587 while (GroupEntry
!= &GroupListHead
)
589 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
591 RtlFreeUnicodeString(&CurrentGroup
->GroupName
);
592 RemoveEntryList(GroupEntry
);
593 ExFreePool(CurrentGroup
);
595 GroupEntry
= GroupListHead
.Flink
;
598 /* Destroy service list */
599 ServiceEntry
= ServiceListHead
.Flink
;
600 while (ServiceEntry
!= &ServiceListHead
)
602 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
604 RtlFreeUnicodeString(&CurrentService
->ServiceName
);
605 RtlFreeUnicodeString(&CurrentService
->RegistryPath
);
606 RtlFreeUnicodeString(&CurrentService
->ServiceGroup
);
607 RtlFreeUnicodeString(&CurrentService
->ImagePath
);
608 RemoveEntryList(ServiceEntry
);
609 ExFreePool(CurrentService
);
611 ServiceEntry
= ServiceListHead
.Flink
;
614 DPRINT("IoDestroyDriverList() done\n");
616 return(STATUS_SUCCESS
);