New macros InitializeUnicodeString(), RtlInitUnicodeStringFromLiteral() and UNICODE_S...
[reactos.git] / reactos / ntoskrnl / io / driver.c
1 /* $Id: driver.c,v 1.10 2002/08/20 20:37:12 hyperion Exp $
2 *
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)
8 * UPDATE HISTORY:
9 * 15/05/98: Created
10 */
11
12 /* INCLUDES ****************************************************************/
13
14 #include <limits.h>
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>
22
23 #include <roscfg.h>
24
25 #define NDEBUG
26 #include <internal/debug.h>
27
28
29 typedef struct _SERVICE_GROUP
30 {
31 LIST_ENTRY GroupListEntry;
32 UNICODE_STRING GroupName;
33
34 BOOLEAN ServicesRunning;
35
36 } SERVICE_GROUP, *PSERVICE_GROUP;
37
38
39 typedef struct _SERVICE
40 {
41 LIST_ENTRY ServiceListEntry;
42 UNICODE_STRING ServiceName;
43 UNICODE_STRING RegistryPath;
44 UNICODE_STRING ServiceGroup;
45 UNICODE_STRING ImagePath;
46
47 ULONG Start;
48 ULONG Type;
49 ULONG ErrorControl;
50 ULONG Tag;
51
52 BOOLEAN ServiceRunning; // needed ??
53
54 } SERVICE, *PSERVICE;
55
56
57 /* GLOBALS *******************************************************************/
58
59 static LIST_ENTRY GroupListHead = {NULL, NULL};
60 static LIST_ENTRY ServiceListHead = {NULL, NULL};
61
62 POBJECT_TYPE EXPORTED IoDriverObjectType = NULL;
63
64 #define TAG_DRIVER TAG('D', 'R', 'V', 'R')
65 #define TAG_DRIVER_EXTENSION TAG('D', 'R', 'V', 'E')
66
67
68 /* FUNCTIONS ***************************************************************/
69
70 NTSTATUS STDCALL
71 IopCreateDriver(PVOID ObjectBody,
72 PVOID Parent,
73 PWSTR RemainingPath,
74 POBJECT_ATTRIBUTES ObjectAttributes)
75 {
76 DPRINT("LdrCreateModule(ObjectBody %x, Parent %x, RemainingPath %S)\n",
77 ObjectBody,
78 Parent,
79 RemainingPath);
80 if (RemainingPath != NULL && wcschr(RemainingPath + 1, '\\') != NULL)
81 {
82 return(STATUS_UNSUCCESSFUL);
83 }
84
85 return(STATUS_SUCCESS);
86 }
87
88
89 VOID
90 IopInitDriverImplementation(VOID)
91 {
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");
112 }
113
114 /**********************************************************************
115 * NAME EXPORTED
116 * NtLoadDriver
117 *
118 * DESCRIPTION
119 * Loads a device driver.
120 *
121 * ARGUMENTS
122 * DriverServiceName
123 * Name of the service to load (registry key).
124 *
125 * RETURN VALUE
126 * Status.
127 *
128 * REVISIONS
129 */
130 NTSTATUS STDCALL
131 NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
132 {
133 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
134 WCHAR FullImagePathBuffer[MAX_PATH];
135 UNICODE_STRING ImagePath;
136 UNICODE_STRING FullImagePath;
137 NTSTATUS Status;
138 ULONG Type;
139 PDEVICE_NODE DeviceNode;
140 PMODULE_OBJECT ModuleObject;
141 LPWSTR Start;
142
143 DPRINT("NtLoadDriver(%wZ) called\n", DriverServiceName);
144
145 RtlInitUnicodeString(&ImagePath, NULL);
146
147 /* Get service data */
148 RtlZeroMemory(&QueryTable,
149 sizeof(QueryTable));
150
151 QueryTable[0].Name = L"Type";
152 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
153 QueryTable[0].EntryContext = &Type;
154
155 QueryTable[1].Name = L"ImagePath";
156 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
157 QueryTable[1].EntryContext = &ImagePath;
158
159 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
160 DriverServiceName->Buffer,
161 QueryTable,
162 NULL,
163 NULL);
164 if (!NT_SUCCESS(Status))
165 {
166 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
167 RtlFreeUnicodeString(&ImagePath);
168 return(Status);
169 }
170
171 if (ImagePath.Length == 0)
172 {
173 wcscpy(FullImagePathBuffer, L"\\SystemRoot\\system32\\drivers");
174 wcscat(FullImagePathBuffer, wcsrchr(DriverServiceName->Buffer, L'\\'));
175 wcscat(FullImagePathBuffer, L".sys");
176 }
177 else if (ImagePath.Buffer[0] != L'\\')
178 {
179 wcscpy(FullImagePathBuffer, L"\\SystemRoot\\");
180 wcscat(FullImagePathBuffer, ImagePath.Buffer);
181 }
182 else
183 {
184 wcscpy(FullImagePathBuffer, ImagePath.Buffer);
185 }
186
187 RtlFreeUnicodeString(&ImagePath);
188 RtlInitUnicodeString(&FullImagePath, FullImagePathBuffer);
189
190 DPRINT("FullImagePath: '%S'\n", FullImagePathBuffer);
191 DPRINT("Type %lx\n", Type);
192
193 /* Use IopRootDeviceNode for now */
194 Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, &DeviceNode);
195 if (!NT_SUCCESS(Status))
196 {
197 DPRINT1("IopCreateDeviceNode() failed (Status %lx)\n", Status);
198 return(Status);
199 }
200
201 ModuleObject = LdrGetModuleObject(DriverServiceName);
202 if (ModuleObject != NULL)
203 {
204 return(STATUS_IMAGE_ALREADY_LOADED);
205 }
206
207 Status = LdrLoadModule(&FullImagePath, &ModuleObject);
208 if (!NT_SUCCESS(Status))
209 {
210 DPRINT1("LdrLoadModule() failed (Status %lx)\n", Status);
211 IopFreeDeviceNode(DeviceNode);
212 return(Status);
213 }
214
215 /* Set a service name for the device node */
216 Start = wcsrchr(DriverServiceName->Buffer, L'\\');
217 if (Start == NULL)
218 Start = DriverServiceName->Buffer;
219 else
220 Start++;
221 RtlCreateUnicodeString(&DeviceNode->ServiceName, Start);
222
223 Status = IopInitializeDriver(ModuleObject->EntryPoint,
224 DeviceNode,
225 (Type == 2 || Type == 8));
226 if (!NT_SUCCESS(Status))
227 {
228 DPRINT1("IopInitializeDriver() failed (Status %lx)\n", Status);
229 LdrUnloadModule(ModuleObject);
230 IopFreeDeviceNode(DeviceNode);
231 }
232
233 return(Status);
234 }
235
236
237 NTSTATUS STDCALL
238 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName)
239 {
240 DPRINT("DriverServiceName: '%wZ'\n", DriverServiceName);
241
242 return(STATUS_NOT_IMPLEMENTED);
243 }
244
245
246 static NTSTATUS STDCALL
247 IopCreateGroupListEntry(PWSTR ValueName,
248 ULONG ValueType,
249 PVOID ValueData,
250 ULONG ValueLength,
251 PVOID Context,
252 PVOID EntryContext)
253 {
254 PSERVICE_GROUP Group;
255
256 if (ValueType == REG_SZ)
257 {
258 DPRINT("GroupName: '%S'\n", (PWCHAR)ValueData);
259
260 Group = ExAllocatePool(NonPagedPool,
261 sizeof(SERVICE_GROUP));
262 if (Group == NULL)
263 {
264 return(STATUS_INSUFFICIENT_RESOURCES);
265 }
266
267 RtlZeroMemory(Group, sizeof(SERVICE_GROUP));
268
269 if (!RtlCreateUnicodeString(&Group->GroupName,
270 (PWSTR)ValueData))
271 {
272 return(STATUS_INSUFFICIENT_RESOURCES);
273 }
274
275
276 InsertTailList(&GroupListHead,
277 &Group->GroupListEntry);
278 }
279
280 return(STATUS_SUCCESS);
281 }
282
283
284 static NTSTATUS STDCALL
285 IopCreateServiceListEntry(PUNICODE_STRING ServiceName)
286 {
287 RTL_QUERY_REGISTRY_TABLE QueryTable[6];
288 PSERVICE Service;
289 NTSTATUS Status;
290
291 DPRINT("ServiceName: '%wZ'\n", ServiceName);
292
293 /* Allocate service entry */
294 Service = (PSERVICE)ExAllocatePool(NonPagedPool, sizeof(SERVICE));
295 if (Service == NULL)
296 {
297 DPRINT1("ExAllocatePool() failed\n");
298 return(STATUS_INSUFFICIENT_RESOURCES);
299 }
300 RtlZeroMemory(Service, sizeof(SERVICE));
301
302 /* Get service data */
303 RtlZeroMemory(&QueryTable,
304 sizeof(QueryTable));
305
306 QueryTable[0].Name = L"Start";
307 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
308 QueryTable[0].EntryContext = &Service->Start;
309
310 QueryTable[1].Name = L"Type";
311 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
312 QueryTable[1].EntryContext = &Service->Type;
313
314 QueryTable[2].Name = L"ErrorControl";
315 QueryTable[2].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
316 QueryTable[2].EntryContext = &Service->ErrorControl;
317
318 QueryTable[3].Name = L"Group";
319 QueryTable[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
320 QueryTable[3].EntryContext = &Service->ServiceGroup;
321
322 QueryTable[4].Name = L"ImagePath";
323 QueryTable[4].Flags = RTL_QUERY_REGISTRY_DIRECT;
324 QueryTable[4].EntryContext = &Service->ImagePath;
325
326 Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
327 ServiceName->Buffer,
328 QueryTable,
329 NULL,
330 NULL);
331 if (!NT_SUCCESS(Status) || Service->Start > 1)
332 {
333 RtlFreeUnicodeString(&Service->ServiceGroup);
334 RtlFreeUnicodeString(&Service->ImagePath);
335 ExFreePool(Service);
336 return(Status);
337 }
338
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,
345 ServiceName->Buffer,
346 ServiceName->Length);
347 Service->ServiceName.Buffer[ServiceName->Length / sizeof(WCHAR)] = 0;
348
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);
358
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);
365
366 /* Append service entry */
367 InsertTailList(&ServiceListHead,
368 &Service->ServiceListEntry);
369
370 return(STATUS_SUCCESS);
371 }
372
373
374 NTSTATUS
375 IoCreateDriverList(VOID)
376 {
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;
382 HANDLE KeyHandle;
383 NTSTATUS Status;
384 ULONG Index;
385
386 ULONG KeyInfoLength = 0;
387 ULONG ReturnedLength;
388
389 DPRINT("IoCreateDriverList() called\n");
390
391 /* Initialize basic variables */
392 InitializeListHead(&GroupListHead);
393 InitializeListHead(&ServiceListHead);
394
395 /* Build group order list */
396 RtlZeroMemory(&QueryTable,
397 sizeof(QueryTable));
398
399 QueryTable[0].Name = L"List";
400 QueryTable[0].QueryRoutine = IopCreateGroupListEntry;
401
402 Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
403 L"ServiceGroupOrder",
404 QueryTable,
405 NULL,
406 NULL);
407 if (!NT_SUCCESS(Status))
408 return(Status);
409
410 /* Enumerate services and create the service list */
411 RtlInitUnicodeStringFromLiteral(&ServicesKeyName,
412 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services");
413
414 InitializeObjectAttributes(&ObjectAttributes,
415 &ServicesKeyName,
416 OBJ_CASE_INSENSITIVE,
417 NULL,
418 NULL);
419
420 Status = NtOpenKey(&KeyHandle,
421 0x10001,
422 &ObjectAttributes);
423 if (!NT_SUCCESS(Status))
424 {
425 return(Status);
426 }
427
428 KeyInfoLength = sizeof(KEY_BASIC_INFORMATION) + MAX_PATH * sizeof(WCHAR);
429 KeyInfo = ExAllocatePool(NonPagedPool, KeyInfoLength);
430 if (KeyInfo == NULL)
431 {
432 NtClose(KeyHandle);
433 return(STATUS_INSUFFICIENT_RESOURCES);
434 }
435
436 Index = 0;
437 while (TRUE)
438 {
439 Status = NtEnumerateKey(KeyHandle,
440 Index,
441 KeyBasicInformation,
442 KeyInfo,
443 KeyInfoLength,
444 &ReturnedLength);
445 if (NT_SUCCESS(Status))
446 {
447 if (KeyInfo->NameLength < MAX_PATH * sizeof(WCHAR))
448 {
449
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;
454
455 DPRINT("KeyName: '%wZ'\n", &SubKeyName);
456 IopCreateServiceListEntry(&SubKeyName);
457 }
458 }
459
460 if (!NT_SUCCESS(Status))
461 break;
462
463 Index++;
464 }
465
466 ExFreePool(KeyInfo);
467 NtClose(KeyHandle);
468
469 DPRINT("IoCreateDriverList() done\n");
470
471 return(STATUS_SUCCESS);
472 }
473
474
475 VOID
476 LdrLoadAutoConfigDrivers(VOID)
477 {
478 PLIST_ENTRY GroupEntry;
479 PLIST_ENTRY ServiceEntry;
480 PSERVICE_GROUP CurrentGroup;
481 PSERVICE CurrentService;
482 NTSTATUS Status;
483
484 CHAR TextBuffer [256];
485 ULONG x, y, cx, cy;
486
487 DPRINT("LdrLoadAutoConfigDrivers() called\n");
488
489 GroupEntry = GroupListHead.Flink;
490 while (GroupEntry != &GroupListHead)
491 {
492 CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry);
493
494 DPRINT("Group: %wZ\n", &CurrentGroup->GroupName);
495
496 ServiceEntry = ServiceListHead.Flink;
497 while (ServiceEntry != &ServiceListHead)
498 {
499 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
500
501 if ((RtlCompareUnicodeString(&CurrentGroup->GroupName, &CurrentService->ServiceGroup, TRUE) == 0) &&
502 (CurrentService->Start == 1 /*SERVICE_SYSTEM_START*/))
503 {
504
505 HalQueryDisplayParameters(&x, &y, &cx, &cy);
506 RtlFillMemory(TextBuffer, x, ' ');
507 TextBuffer[x] = '\0';
508 HalSetDisplayParameters(0, y-1);
509 HalDisplayString(TextBuffer);
510
511 sprintf(TextBuffer, "Loading %S...\n", CurrentService->ServiceName.Buffer);
512 HalSetDisplayParameters(0, y-1);
513 HalDisplayString(TextBuffer);
514 HalSetDisplayParameters(cx, cy);
515
516 DPRINT(" Path: %wZ\n", &CurrentService->RegistryPath);
517 Status = NtLoadDriver(&CurrentService->RegistryPath);
518 if (!NT_SUCCESS(Status))
519 {
520 DPRINT("NtLoadDriver() failed (Status %lx)\n", Status);
521 #if 0
522 if (CurrentService->ErrorControl == 1)
523 {
524 /* Log error */
525
526 }
527 else if (CurrentService->ErrorControl == 2)
528 {
529 if (IsLastKnownGood == FALSE)
530 {
531 /* Boot last known good configuration */
532
533 }
534 }
535 else if (CurrentService->ErrorControl == 3)
536 {
537 if (IsLastKnownGood == FALSE)
538 {
539 /* Boot last known good configuration */
540
541 }
542 else
543 {
544 /* BSOD! */
545
546 }
547 }
548 #endif
549 }
550 }
551 ServiceEntry = ServiceEntry->Flink;
552 }
553
554 GroupEntry = GroupEntry->Flink;
555 }
556
557 DPRINT("LdrLoadAutoConfigDrivers() done\n");
558 }
559
560
561 NTSTATUS
562 IoDestroyDriverList(VOID)
563 {
564 PLIST_ENTRY GroupEntry;
565 PLIST_ENTRY ServiceEntry;
566 PSERVICE_GROUP CurrentGroup;
567 PSERVICE CurrentService;
568
569 DPRINT("IoDestroyDriverList() called\n");
570
571 /* Destroy group list */
572 GroupEntry = GroupListHead.Flink;
573 while (GroupEntry != &GroupListHead)
574 {
575 CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry);
576
577 RtlFreeUnicodeString(&CurrentGroup->GroupName);
578 RemoveEntryList(GroupEntry);
579 ExFreePool(CurrentGroup);
580
581 GroupEntry = GroupListHead.Flink;
582 }
583
584 /* Destroy service list */
585 ServiceEntry = ServiceListHead.Flink;
586 while (ServiceEntry != &ServiceListHead)
587 {
588 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
589
590 RtlFreeUnicodeString(&CurrentService->ServiceName);
591 RtlFreeUnicodeString(&CurrentService->RegistryPath);
592 RtlFreeUnicodeString(&CurrentService->ServiceGroup);
593 RtlFreeUnicodeString(&CurrentService->ImagePath);
594 RemoveEntryList(ServiceEntry);
595 ExFreePool(CurrentService);
596
597 ServiceEntry = ServiceListHead.Flink;
598 }
599
600 DPRINT("IoDestroyDriverList() done\n");
601
602 return(STATUS_SUCCESS);
603 }
604
605 /* EOF */