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