1 /* $Id: driver.c,v 1.21 2003/10/06 18:49:50 navaraf 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),
227 ModuleObject
->Length
,
229 if (!NT_SUCCESS(Status
))
231 DPRINT1("IopInitializeDriver() failed (Status %lx)\n", Status
);
232 LdrUnloadModule(ModuleObject
);
233 IopFreeDeviceNode(DeviceNode
);
241 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName
)
243 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
244 WCHAR FullImagePathBuffer
[MAX_PATH
];
245 UNICODE_STRING ImagePath
;
246 UNICODE_STRING FullImagePath
;
247 UNICODE_STRING ObjectName
;
248 PDRIVER_OBJECT DriverObject
;
250 PMODULE_OBJECT ModuleObject
;
253 DPRINT("DriverServiceName: '%wZ'\n", DriverServiceName
);
255 /* Get the service name from the module name */
256 Start
= wcsrchr(DriverServiceName
->Buffer
, L
'\\');
258 Start
= DriverServiceName
->Buffer
;
262 ObjectName
.Length
= wcslen(Start
) + 8;
263 ObjectName
.Buffer
= ExAllocatePool(NonPagedPool
,
264 ObjectName
.Length
* sizeof(WCHAR
));
265 wcscpy(ObjectName
.Buffer
, L
"\\Driver\\");
266 memcpy(ObjectName
.Buffer
+ 8, Start
, (ObjectName
.Length
- 8) * sizeof(WCHAR
));
268 /* Find the driver object */
269 Status
= ObReferenceObjectByName(&ObjectName
, 0, 0, 0, IoDriverObjectType
,
270 KernelMode
, 0, (PVOID
*)&DriverObject
);
271 if (!NT_SUCCESS(Status
))
273 DPRINT("Can't locate driver object for %wZ\n", ObjectName
);
276 ObDereferenceObject(DriverObject
);
278 RtlInitUnicodeString(&ImagePath
, NULL
);
280 /* Get service data */
281 RtlZeroMemory(&QueryTable
,
284 QueryTable
[0].Name
= L
"ImagePath";
285 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
286 QueryTable
[0].EntryContext
= &ImagePath
;
288 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
289 DriverServiceName
->Buffer
,
293 if (!NT_SUCCESS(Status
))
295 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
296 RtlFreeUnicodeString(&ImagePath
);
300 if (ImagePath
.Length
== 0)
302 wcscpy(FullImagePathBuffer
, L
"\\SystemRoot\\system32\\drivers");
303 wcscat(FullImagePathBuffer
, wcsrchr(DriverServiceName
->Buffer
, L
'\\'));
304 wcscat(FullImagePathBuffer
, L
".sys");
306 else if (ImagePath
.Buffer
[0] != L
'\\')
308 wcscpy(FullImagePathBuffer
, L
"\\SystemRoot\\");
309 wcscat(FullImagePathBuffer
, ImagePath
.Buffer
);
313 wcscpy(FullImagePathBuffer
, ImagePath
.Buffer
);
316 RtlFreeUnicodeString(&ImagePath
);
317 RtlInitUnicodeString(&FullImagePath
, FullImagePathBuffer
);
319 ModuleObject
= LdrGetModuleObject(DriverServiceName
);
320 if (ModuleObject
== NULL
)
322 return STATUS_UNSUCCESSFUL
;
325 /* Unload the module and release the references to the device object */
327 if (DriverObject
->DriverUnload
)
328 (*DriverObject
->DriverUnload
)(DriverObject
);
329 ObDereferenceObject(DriverObject
);
330 ObDereferenceObject(DriverObject
);
331 LdrUnloadModule(ModuleObject
);
333 return STATUS_SUCCESS
;
337 static NTSTATUS STDCALL
338 IopCreateGroupListEntry(PWSTR ValueName
,
345 PSERVICE_GROUP Group
;
347 if (ValueType
== REG_SZ
)
349 DPRINT("GroupName: '%S'\n", (PWCHAR
)ValueData
);
351 Group
= ExAllocatePool(NonPagedPool
,
352 sizeof(SERVICE_GROUP
));
355 return(STATUS_INSUFFICIENT_RESOURCES
);
358 RtlZeroMemory(Group
, sizeof(SERVICE_GROUP
));
360 if (!RtlCreateUnicodeString(&Group
->GroupName
,
363 return(STATUS_INSUFFICIENT_RESOURCES
);
367 InsertTailList(&GroupListHead
,
368 &Group
->GroupListEntry
);
371 return(STATUS_SUCCESS
);
375 static NTSTATUS STDCALL
376 IopCreateServiceListEntry(PUNICODE_STRING ServiceName
)
378 RTL_QUERY_REGISTRY_TABLE QueryTable
[6];
382 DPRINT("ServiceName: '%wZ'\n", ServiceName
);
384 /* Allocate service entry */
385 Service
= (PSERVICE
)ExAllocatePool(NonPagedPool
, sizeof(SERVICE
));
388 DPRINT1("ExAllocatePool() failed\n");
389 return(STATUS_INSUFFICIENT_RESOURCES
);
391 RtlZeroMemory(Service
, sizeof(SERVICE
));
393 /* Get service data */
394 RtlZeroMemory(&QueryTable
,
397 QueryTable
[0].Name
= L
"Start";
398 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
399 QueryTable
[0].EntryContext
= &Service
->Start
;
401 QueryTable
[1].Name
= L
"Type";
402 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
403 QueryTable
[1].EntryContext
= &Service
->Type
;
405 QueryTable
[2].Name
= L
"ErrorControl";
406 QueryTable
[2].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
407 QueryTable
[2].EntryContext
= &Service
->ErrorControl
;
409 QueryTable
[3].Name
= L
"Group";
410 QueryTable
[3].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
411 QueryTable
[3].EntryContext
= &Service
->ServiceGroup
;
413 QueryTable
[4].Name
= L
"ImagePath";
414 QueryTable
[4].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
415 QueryTable
[4].EntryContext
= &Service
->ImagePath
;
417 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
422 if (!NT_SUCCESS(Status
) || Service
->Start
> 1)
424 RtlFreeUnicodeString(&Service
->ServiceGroup
);
425 RtlFreeUnicodeString(&Service
->ImagePath
);
430 /* Copy service name */
431 Service
->ServiceName
.Length
= ServiceName
->Length
;
432 Service
->ServiceName
.MaximumLength
= ServiceName
->Length
+ sizeof(WCHAR
);
433 Service
->ServiceName
.Buffer
= ExAllocatePool(NonPagedPool
,
434 Service
->ServiceName
.MaximumLength
);
435 RtlCopyMemory(Service
->ServiceName
.Buffer
,
437 ServiceName
->Length
);
438 Service
->ServiceName
.Buffer
[ServiceName
->Length
/ sizeof(WCHAR
)] = 0;
440 /* Build registry path */
441 Service
->RegistryPath
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
442 Service
->RegistryPath
.Buffer
= ExAllocatePool(NonPagedPool
,
443 MAX_PATH
* sizeof(WCHAR
));
444 wcscpy(Service
->RegistryPath
.Buffer
,
445 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
446 wcscat(Service
->RegistryPath
.Buffer
,
447 Service
->ServiceName
.Buffer
);
448 Service
->RegistryPath
.Length
= wcslen(Service
->RegistryPath
.Buffer
) * sizeof(WCHAR
);
450 DPRINT("ServiceName: '%wZ'\n", &Service
->ServiceName
);
451 DPRINT("RegistryPath: '%wZ'\n", &Service
->RegistryPath
);
452 DPRINT("ServiceGroup: '%wZ'\n", &Service
->ServiceGroup
);
453 DPRINT("ImagePath: '%wZ'\n", &Service
->ImagePath
);
454 DPRINT("Start %lx Type %lx ErrorControl %lx\n",
455 Service
->Start
, Service
->Type
, Service
->ErrorControl
);
457 /* Append service entry */
458 InsertTailList(&ServiceListHead
,
459 &Service
->ServiceListEntry
);
461 return(STATUS_SUCCESS
);
466 IoCreateDriverList(VOID
)
468 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
469 PKEY_BASIC_INFORMATION KeyInfo
= NULL
;
470 OBJECT_ATTRIBUTES ObjectAttributes
;
471 UNICODE_STRING ServicesKeyName
;
472 UNICODE_STRING SubKeyName
;
477 ULONG KeyInfoLength
= 0;
478 ULONG ReturnedLength
;
480 DPRINT("IoCreateDriverList() called\n");
482 /* Initialize basic variables */
483 InitializeListHead(&GroupListHead
);
484 InitializeListHead(&ServiceListHead
);
486 /* Build group order list */
487 RtlZeroMemory(&QueryTable
,
490 QueryTable
[0].Name
= L
"List";
491 QueryTable
[0].QueryRoutine
= IopCreateGroupListEntry
;
493 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
494 L
"ServiceGroupOrder",
498 if (!NT_SUCCESS(Status
))
501 /* Enumerate services and create the service list */
502 RtlInitUnicodeStringFromLiteral(&ServicesKeyName
,
503 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services");
505 InitializeObjectAttributes(&ObjectAttributes
,
507 OBJ_CASE_INSENSITIVE
,
511 Status
= NtOpenKey(&KeyHandle
,
514 if (!NT_SUCCESS(Status
))
519 KeyInfoLength
= sizeof(KEY_BASIC_INFORMATION
) + MAX_PATH
* sizeof(WCHAR
);
520 KeyInfo
= ExAllocatePool(NonPagedPool
, KeyInfoLength
);
524 return(STATUS_INSUFFICIENT_RESOURCES
);
530 Status
= NtEnumerateKey(KeyHandle
,
536 if (NT_SUCCESS(Status
))
538 if (KeyInfo
->NameLength
< MAX_PATH
* sizeof(WCHAR
))
541 SubKeyName
.Length
= KeyInfo
->NameLength
;
542 SubKeyName
.MaximumLength
= KeyInfo
->NameLength
+ sizeof(WCHAR
);
543 SubKeyName
.Buffer
= KeyInfo
->Name
;
544 SubKeyName
.Buffer
[SubKeyName
.Length
/ sizeof(WCHAR
)] = 0;
546 DPRINT("KeyName: '%wZ'\n", &SubKeyName
);
547 IopCreateServiceListEntry(&SubKeyName
);
551 if (!NT_SUCCESS(Status
))
560 DPRINT("IoCreateDriverList() done\n");
562 return(STATUS_SUCCESS
);
567 LdrLoadAutoConfigDrivers(VOID
)
569 PLIST_ENTRY GroupEntry
;
570 PLIST_ENTRY ServiceEntry
;
571 PSERVICE_GROUP CurrentGroup
;
572 PSERVICE CurrentService
;
575 CHAR TextBuffer
[256];
578 DPRINT("LdrLoadAutoConfigDrivers() called\n");
580 GroupEntry
= GroupListHead
.Flink
;
581 while (GroupEntry
!= &GroupListHead
)
583 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
585 DPRINT("Group: %wZ\n", &CurrentGroup
->GroupName
);
587 ServiceEntry
= ServiceListHead
.Flink
;
588 while (ServiceEntry
!= &ServiceListHead
)
590 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
592 if ((RtlCompareUnicodeString(&CurrentGroup
->GroupName
, &CurrentService
->ServiceGroup
, TRUE
) == 0) &&
593 (CurrentService
->Start
== 1 /*SERVICE_SYSTEM_START*/))
596 HalQueryDisplayParameters(&x
, &y
, &cx
, &cy
);
597 RtlFillMemory(TextBuffer
, x
, ' ');
598 TextBuffer
[x
] = '\0';
599 HalSetDisplayParameters(0, y
-1);
600 HalDisplayString(TextBuffer
);
602 sprintf(TextBuffer
, "Loading %S...\n", CurrentService
->ServiceName
.Buffer
);
603 HalSetDisplayParameters(0, y
-1);
604 HalDisplayString(TextBuffer
);
605 HalSetDisplayParameters(cx
, cy
);
607 DPRINT(" Path: %wZ\n", &CurrentService
->RegistryPath
);
608 Status
= NtLoadDriver(&CurrentService
->RegistryPath
);
609 if (!NT_SUCCESS(Status
))
611 DPRINT("NtLoadDriver() failed (Status %lx)\n", Status
);
613 if (CurrentService
->ErrorControl
== 1)
618 else if (CurrentService
->ErrorControl
== 2)
620 if (IsLastKnownGood
== FALSE
)
622 /* Boot last known good configuration */
626 else if (CurrentService
->ErrorControl
== 3)
628 if (IsLastKnownGood
== FALSE
)
630 /* Boot last known good configuration */
642 ServiceEntry
= ServiceEntry
->Flink
;
645 GroupEntry
= GroupEntry
->Flink
;
648 DPRINT("LdrLoadAutoConfigDrivers() done\n");
653 IoDestroyDriverList(VOID
)
655 PLIST_ENTRY GroupEntry
;
656 PLIST_ENTRY ServiceEntry
;
657 PSERVICE_GROUP CurrentGroup
;
658 PSERVICE CurrentService
;
660 DPRINT("IoDestroyDriverList() called\n");
662 /* Destroy group list */
663 GroupEntry
= GroupListHead
.Flink
;
664 while (GroupEntry
!= &GroupListHead
)
666 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
668 RtlFreeUnicodeString(&CurrentGroup
->GroupName
);
669 RemoveEntryList(GroupEntry
);
670 ExFreePool(CurrentGroup
);
672 GroupEntry
= GroupListHead
.Flink
;
675 /* Destroy service list */
676 ServiceEntry
= ServiceListHead
.Flink
;
677 while (ServiceEntry
!= &ServiceListHead
)
679 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
681 RtlFreeUnicodeString(&CurrentService
->ServiceName
);
682 RtlFreeUnicodeString(&CurrentService
->RegistryPath
);
683 RtlFreeUnicodeString(&CurrentService
->ServiceGroup
);
684 RtlFreeUnicodeString(&CurrentService
->ImagePath
);
685 RemoveEntryList(ServiceEntry
);
686 ExFreePool(CurrentService
);
688 ServiceEntry
= ServiceListHead
.Flink
;
691 DPRINT("IoDestroyDriverList() done\n");
693 return(STATUS_SUCCESS
);