Automagically select computer type (UP/MP) during first stage setup
[reactos.git] / reactos / subsys / system / usetup / settings.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2004 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* COPYRIGHT: See COPYING in the top level directory
20 * PROJECT: ReactOS text-mode setup
21 * FILE: subsys/system/usetup/settings.c
22 * PURPOSE: Device settings support functions
23 * PROGRAMMER: Eric Kohl
24 */
25
26 /* INCLUDES *****************************************************************/
27
28 #include <usetup.h>
29
30 #define NDEBUG
31 #include <debug.h>
32
33 /* FUNCTIONS ****************************************************************/
34
35 static BOOLEAN
36 GetComputerIdentifier(PWSTR Identifier,
37 ULONG IdentifierLength)
38 {
39 OBJECT_ATTRIBUTES ObjectAttributes;
40 UNICODE_STRING KeyName;
41 LPCWSTR ComputerIdentifier;
42 HANDLE ProcessorsKey;
43 PKEY_FULL_INFORMATION pFullInfo;
44 ULONG Size, SizeNeeded;
45 NTSTATUS Status;
46
47 DPRINT("GetComputerIdentifier() called\n");
48
49 Size = sizeof(KEY_FULL_INFORMATION);
50 pFullInfo = (PKEY_FULL_INFORMATION)RtlAllocateHeap(RtlGetProcessHeap(), 0, Size);
51 if (!pFullInfo)
52 {
53 DPRINT("RtlAllocateHeap() failed\n");
54 return FALSE;
55 }
56
57 /* Open the processors key */
58 RtlInitUnicodeString(&KeyName,
59 L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor");
60 InitializeObjectAttributes(&ObjectAttributes,
61 &KeyName,
62 OBJ_CASE_INSENSITIVE,
63 NULL,
64 NULL);
65 Status = NtOpenKey(&ProcessorsKey,
66 KEY_QUERY_VALUE ,
67 &ObjectAttributes);
68 if (!NT_SUCCESS(Status))
69 {
70 DPRINT("NtOpenKey() failed (Status 0x%lx)\n", Status);
71 RtlFreeHeap(RtlGetProcessHeap(), 0, pFullInfo);
72 return FALSE;
73 }
74
75 /* Get number of subkeys */
76 Status = NtQueryKey(
77 ProcessorsKey,
78 KeyFullInformation,
79 pFullInfo,
80 Size,
81 &Size);
82 NtClose(ProcessorsKey);
83 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW)
84 {
85 DPRINT("NtQueryKey() failed (Status 0x%lx)\n", Status);
86 RtlFreeHeap(RtlGetProcessHeap(), 0, pFullInfo);
87 return FALSE;
88 }
89
90 /* Find computer identifier */
91 if (pFullInfo->SubKeys == 0)
92 {
93 /* Something strange happened. No processor detected */
94 RtlFreeHeap(RtlGetProcessHeap(), 0, pFullInfo);
95 return FALSE;
96 }
97
98 if (pFullInfo->SubKeys == 1)
99 {
100 /* Computer is mono-CPU */
101 ComputerIdentifier = L"PC UP";
102 }
103 else
104 {
105 /* Computer is multi-CPUs */
106 ComputerIdentifier = L"PC MP";
107 }
108 RtlFreeHeap(RtlGetProcessHeap(), 0, pFullInfo);
109
110 /* Copy computer identifier to return buffer */
111 SizeNeeded = (wcslen(ComputerIdentifier) + 1) * sizeof(WCHAR);
112 if (SizeNeeded > IdentifierLength)
113 return FALSE;
114 RtlCopyMemory(Identifier, ComputerIdentifier, SizeNeeded);
115 return TRUE;
116 }
117
118
119 PGENERIC_LIST
120 CreateComputerTypeList(HINF InfFile)
121 {
122 CHAR Buffer[128];
123 PGENERIC_LIST List;
124 INFCONTEXT Context;
125 PWCHAR KeyName;
126 PWCHAR KeyValue;
127 PWCHAR UserData;
128 WCHAR ComputerIdentifier[128];
129 WCHAR ComputerKey[32];
130
131 /* Get the computer identification */
132 if (!GetComputerIdentifier(ComputerIdentifier, 128))
133 {
134 ComputerIdentifier[0] = 0;
135 }
136
137 DPRINT("Computer identifier: '%S'\n", ComputerIdentifier);
138
139 /* Search for matching device identifier */
140 if (!InfFindFirstLine(InfFile, L"Map.Computer", NULL, &Context))
141 {
142 /* FIXME: error message */
143 return NULL;
144 }
145
146 do
147 {
148 if (!InfGetDataField(&Context, 1, &KeyValue))
149 {
150 /* FIXME: Handle error! */
151 DPRINT("InfGetDataField() failed\n");
152 return NULL;
153 }
154
155 DPRINT("KeyValue: %S\n", KeyValue);
156 if (wcsstr(ComputerIdentifier, KeyValue))
157 {
158 if (!InfGetDataField(&Context, 0, &KeyName))
159 {
160 /* FIXME: Handle error! */
161 DPRINT("InfGetDataField() failed\n");
162 return NULL;
163 }
164
165 DPRINT("Computer key: %S\n", KeyName);
166 wcscpy(ComputerKey, KeyName);
167 }
168 }
169 while (InfFindNextLine(&Context, &Context));
170
171 List = CreateGenericList();
172 if (List == NULL)
173 return NULL;
174
175 if (!InfFindFirstLine (InfFile, L"Computer", NULL, &Context))
176 {
177 DestroyGenericList(List, FALSE);
178 return NULL;
179 }
180
181 do
182 {
183 if (!InfGetData (&Context, &KeyName, &KeyValue))
184 {
185 /* FIXME: Handle error! */
186 DPRINT("InfGetData() failed\n");
187 break;
188 }
189
190 UserData = RtlAllocateHeap(ProcessHeap,
191 0,
192 (wcslen(KeyName) + 1) * sizeof(WCHAR));
193 if (UserData == NULL)
194 {
195 /* FIXME: Handle error! */
196 }
197
198 wcscpy(UserData, KeyName);
199
200 sprintf(Buffer, "%S", KeyValue);
201 AppendGenericListEntry(List, Buffer, UserData,
202 _wcsicmp(KeyName, ComputerKey) ? FALSE : TRUE);
203 }
204 while (InfFindNextLine(&Context, &Context));
205
206 return List;
207 }
208
209
210 static BOOLEAN
211 GetDisplayIdentifier(PWSTR Identifier,
212 ULONG IdentifierLength)
213 {
214 OBJECT_ATTRIBUTES ObjectAttributes;
215 UNICODE_STRING KeyName;
216 WCHAR Buffer[32];
217 HANDLE BusKey;
218 HANDLE BusInstanceKey;
219 HANDLE ControllerKey;
220 HANDLE ControllerInstanceKey;
221 ULONG BusInstance;
222 ULONG ControllerInstance;
223 ULONG BufferLength;
224 ULONG ReturnedLength;
225 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
226 NTSTATUS Status;
227
228 DPRINT("GetDisplayIdentifier() called\n");
229
230 /* Open the bus key */
231 RtlInitUnicodeString(&KeyName,
232 L"\\Registry\\Machine\\HARDWARE\\Description\\System\\MultifunctionAdapter");
233 InitializeObjectAttributes(&ObjectAttributes,
234 &KeyName,
235 OBJ_CASE_INSENSITIVE,
236 NULL,
237 NULL);
238 Status = NtOpenKey(&BusKey,
239 KEY_ALL_ACCESS,
240 &ObjectAttributes);
241 if (!NT_SUCCESS(Status))
242 {
243 DPRINT("NtOpenKey() failed (Status %lx)\n", Status);
244 return FALSE;
245 }
246
247 BusInstance = 0;
248 while (TRUE)
249 {
250 swprintf(Buffer, L"%lu", BusInstance);
251 RtlInitUnicodeString(&KeyName,
252 Buffer);
253 InitializeObjectAttributes(&ObjectAttributes,
254 &KeyName,
255 OBJ_CASE_INSENSITIVE,
256 BusKey,
257 NULL);
258 Status = NtOpenKey(&BusInstanceKey,
259 KEY_ALL_ACCESS,
260 &ObjectAttributes);
261 if (!NT_SUCCESS(Status))
262 {
263 DPRINT("NtOpenKey() failed (Status %lx)\n", Status);
264 NtClose(BusKey);
265 return FALSE;
266 }
267
268 /* Open the controller type key */
269 RtlInitUnicodeString(&KeyName,
270 L"DisplayController");
271 InitializeObjectAttributes(&ObjectAttributes,
272 &KeyName,
273 OBJ_CASE_INSENSITIVE,
274 BusInstanceKey,
275 NULL);
276 Status = NtOpenKey(&ControllerKey,
277 KEY_ALL_ACCESS,
278 &ObjectAttributes);
279 if (NT_SUCCESS(Status))
280 {
281 ControllerInstance = 0;
282 while (TRUE)
283 {
284 /* Open the pointer controller instance key */
285 swprintf(Buffer, L"%lu", ControllerInstance);
286 RtlInitUnicodeString(&KeyName,
287 Buffer);
288 InitializeObjectAttributes(&ObjectAttributes,
289 &KeyName,
290 OBJ_CASE_INSENSITIVE,
291 ControllerKey,
292 NULL);
293 Status = NtOpenKey(&ControllerInstanceKey,
294 KEY_ALL_ACCESS,
295 &ObjectAttributes);
296 if (!NT_SUCCESS(Status))
297 {
298 DPRINT("NtOpenKey() failed (Status %lx)\n", Status);
299 NtClose(ControllerKey);
300 NtClose(BusInstanceKey);
301 NtClose(BusKey);
302 return FALSE;
303 }
304
305 /* Get controller identifier */
306 RtlInitUnicodeString(&KeyName,
307 L"Identifier");
308
309 BufferLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
310 256 * sizeof(WCHAR);
311 ValueInfo = RtlAllocateHeap(RtlGetProcessHeap(),
312 0,
313 BufferLength);
314 if (ValueInfo == NULL)
315 {
316 DPRINT("RtlAllocateHeap() failed\n");
317 NtClose(ControllerInstanceKey);
318 NtClose(ControllerKey);
319 NtClose(BusInstanceKey);
320 NtClose(BusKey);
321 return FALSE;
322 }
323
324 Status = NtQueryValueKey(ControllerInstanceKey,
325 &KeyName,
326 KeyValuePartialInformation,
327 ValueInfo,
328 BufferLength,
329 &ReturnedLength);
330 if (NT_SUCCESS(Status))
331 {
332 DPRINT("Identifier: %S\n", (PWSTR)ValueInfo->Data);
333
334 BufferLength = min(ValueInfo->DataLength / sizeof(WCHAR), IdentifierLength);
335 RtlCopyMemory (Identifier,
336 ValueInfo->Data,
337 BufferLength * sizeof(WCHAR));
338 Identifier[BufferLength] = 0;
339
340 RtlFreeHeap(RtlGetProcessHeap(),
341 0,
342 ValueInfo);
343 NtClose(ControllerInstanceKey);
344 NtClose(ControllerKey);
345 NtClose(BusInstanceKey);
346 NtClose(BusKey);
347 return TRUE;
348 }
349
350 NtClose(ControllerInstanceKey);
351
352 ControllerInstance++;
353 }
354
355 NtClose(ControllerKey);
356 }
357
358 NtClose(BusInstanceKey);
359
360 BusInstance++;
361 }
362
363 NtClose(BusKey);
364
365 return FALSE;
366 }
367
368
369 PGENERIC_LIST
370 CreateDisplayDriverList(HINF InfFile)
371 {
372 CHAR Buffer[128];
373 PGENERIC_LIST List;
374 INFCONTEXT Context;
375 PWCHAR KeyName;
376 PWCHAR KeyValue;
377 PWCHAR UserData;
378 WCHAR DisplayIdentifier[128];
379 WCHAR DisplayKey[32];
380
381 /* Get the display identification */
382 if (!GetDisplayIdentifier(DisplayIdentifier, 128))
383 {
384 DisplayIdentifier[0] = 0;
385 }
386
387 DPRINT("Display identifier: '%S'\n", DisplayIdentifier);
388
389 /* Search for matching device identifier */
390 if (!InfFindFirstLine(InfFile, L"Map.Display", NULL, &Context))
391 {
392 /* FIXME: error message */
393 return NULL;
394 }
395
396 do
397 {
398 if (!InfGetDataField(&Context, 1, &KeyValue))
399 {
400 /* FIXME: Handle error! */
401 DPRINT("InfGetDataField() failed\n");
402 return NULL;
403 }
404
405 DPRINT("KeyValue: %S\n", KeyValue);
406 if (wcsstr(DisplayIdentifier, KeyValue))
407 {
408 if (!InfGetDataField(&Context, 0, &KeyName))
409 {
410 /* FIXME: Handle error! */
411 DPRINT("InfGetDataField() failed\n");
412 return NULL;
413 }
414
415 DPRINT("Display key: %S\n", KeyName);
416 wcscpy(DisplayKey, KeyName);
417 }
418 }
419 while (InfFindNextLine(&Context, &Context));
420
421
422 List = CreateGenericList();
423 if (List == NULL)
424 return NULL;
425
426 if (!InfFindFirstLine (InfFile, L"Display", NULL, &Context))
427 {
428 DestroyGenericList(List, FALSE);
429 return NULL;
430 }
431
432 do
433 {
434 if (!InfGetDataField(&Context, 0, &KeyName))
435 {
436 DPRINT1("InfGetDataField() failed\n");
437 break;
438 }
439
440 if (!InfGetDataField(&Context, 1, &KeyValue))
441 {
442 DPRINT1("InfGetDataField() failed\n");
443 break;
444 }
445
446 UserData = RtlAllocateHeap(ProcessHeap,
447 0,
448 (wcslen(KeyName) + 1) * sizeof(WCHAR));
449 if (UserData == NULL)
450 {
451 DPRINT1("RtlAllocateHeap() failed\n");
452 DestroyGenericList(List, TRUE);
453 return NULL;
454 }
455
456 wcscpy(UserData, KeyName);
457
458 sprintf(Buffer, "%S", KeyValue);
459 AppendGenericListEntry(List,
460 Buffer,
461 UserData,
462 _wcsicmp(KeyName, DisplayKey) ? FALSE : TRUE);
463 }
464 while (InfFindNextLine(&Context, &Context));
465
466 #if 0
467 AppendGenericListEntry(List, "Other display driver", NULL, TRUE);
468 #endif
469
470 return List;
471 }
472
473 BOOLEAN
474 ProcessComputerFiles(HINF InfFile, PGENERIC_LIST List, PWCHAR* AdditionalSectionName)
475 {
476 PGENERIC_LIST_ENTRY Entry;
477 static WCHAR SectionName[128];
478
479 DPRINT("ProcessComputerFiles() called\n");
480
481 Entry = GetGenericListEntry(List);
482 if (Entry == NULL)
483 {
484 DPRINT("GetGenericListEntry() failed\n");
485 return FALSE;
486 }
487
488 wcscpy(SectionName, L"Files.");
489 wcscat(SectionName, Entry->UserData);
490 *AdditionalSectionName = SectionName;
491
492 return TRUE;
493 }
494
495
496 BOOLEAN
497 ProcessDisplayRegistry(HINF InfFile, PGENERIC_LIST List)
498 {
499 PGENERIC_LIST_ENTRY Entry;
500 INFCONTEXT Context;
501 PWCHAR ServiceName;
502 ULONG StartValue;
503 NTSTATUS Status;
504
505 DPRINT("ProcessDisplayRegistry() called\n");
506
507 Entry = GetGenericListEntry(List);
508 if (Entry == NULL)
509 {
510 DPRINT("GetGenericListEntry() failed\n");
511 return FALSE;
512 }
513
514 if (!InfFindFirstLine(InfFile, L"Display", Entry->UserData, &Context))
515 {
516 DPRINT("InfFindFirstLine() failed\n");
517 return FALSE;
518 }
519
520 if (!InfGetDataField(&Context, 3, &ServiceName))
521 {
522 DPRINT("InfGetDataField() failed\n");
523 return FALSE;
524 }
525
526 DPRINT("Service name: %S\n", ServiceName);
527
528 StartValue = 1;
529 Status = RtlWriteRegistryValue(RTL_REGISTRY_SERVICES,
530 ServiceName,
531 L"Start",
532 REG_DWORD,
533 &StartValue,
534 sizeof(ULONG));
535 if (!NT_SUCCESS(Status))
536 {
537 DPRINT("RtlWriteRegistryValue() failed (Status %lx)\n", Status);
538 return FALSE;
539 }
540
541 DPRINT("ProcessDisplayRegistry() done\n");
542
543 return TRUE;
544 }
545
546
547 PGENERIC_LIST
548 CreateKeyboardDriverList(HINF InfFile)
549 {
550 CHAR Buffer[128];
551 PGENERIC_LIST List;
552 INFCONTEXT Context;
553 PWCHAR KeyName;
554 PWCHAR KeyValue;
555 PWCHAR UserData;
556
557 List = CreateGenericList();
558 if (List == NULL)
559 return NULL;
560
561 if (!InfFindFirstLine (InfFile, L"Keyboard", NULL, &Context))
562 {
563 DestroyGenericList(List, FALSE);
564 return NULL;
565 }
566
567 do
568 {
569 if (!InfGetData (&Context, &KeyName, &KeyValue))
570 {
571 /* FIXME: Handle error! */
572 DPRINT("InfGetData() failed\n");
573 break;
574 }
575
576 UserData = RtlAllocateHeap(ProcessHeap,
577 0,
578 (wcslen(KeyName) + 1) * sizeof(WCHAR));
579 if (UserData == NULL)
580 {
581 /* FIXME: Handle error! */
582 }
583
584 wcscpy(UserData, KeyName);
585
586 sprintf(Buffer, "%S", KeyValue);
587 AppendGenericListEntry(List, Buffer, UserData, FALSE);
588 }
589 while (InfFindNextLine(&Context, &Context));
590
591 return List;
592 }
593
594
595 PGENERIC_LIST
596 CreateKeyboardLayoutList(HINF InfFile)
597 {
598 CHAR Buffer[128];
599 PGENERIC_LIST List;
600 INFCONTEXT Context;
601 PWCHAR KeyName;
602 PWCHAR KeyValue;
603 PWCHAR UserData;
604 WCHAR DefaultLayout[20];
605
606 /* Get default layout id */
607 if (!InfFindFirstLine (InfFile, L"NLS", L"DefaultLayout", &Context))
608 return NULL;
609
610 if (!InfGetData (&Context, NULL, &KeyValue))
611 return NULL;
612
613 wcscpy(DefaultLayout, KeyValue);
614
615 List = CreateGenericList();
616 if (List == NULL)
617 return NULL;
618
619 if (!InfFindFirstLine (InfFile, L"KeyboardLayout", NULL, &Context))
620 {
621 DestroyGenericList(List, FALSE);
622 return NULL;
623 }
624
625 do
626 {
627 if (!InfGetData (&Context, &KeyName, &KeyValue))
628 {
629 /* FIXME: Handle error! */
630 DPRINT("InfGetData() failed\n");
631 break;
632 }
633
634 UserData = RtlAllocateHeap(ProcessHeap,
635 0,
636 (wcslen(KeyName) + 1) * sizeof(WCHAR));
637 if (UserData == NULL)
638 {
639 /* FIXME: Handle error! */
640 }
641
642 wcscpy(UserData, KeyName);
643
644 sprintf(Buffer, "%S", KeyValue);
645 AppendGenericListEntry(List,
646 Buffer,
647 UserData,
648 _wcsicmp(KeyName, DefaultLayout) ? FALSE : TRUE);
649 }
650 while (InfFindNextLine(&Context, &Context));
651
652 return List;
653 }
654
655
656 BOOLEAN
657 ProcessKeyboardLayoutRegistry(PGENERIC_LIST List)
658 {
659 PGENERIC_LIST_ENTRY Entry;
660 PWCHAR LanguageId;
661 OBJECT_ATTRIBUTES ObjectAttributes;
662 UNICODE_STRING KeyName;
663 UNICODE_STRING ValueName;
664 HANDLE KeyHandle;
665 NTSTATUS Status;
666
667 Entry = GetGenericListEntry(List);
668 if (Entry == NULL)
669 return FALSE;
670
671 LanguageId = (PWCHAR)Entry->UserData;
672 if (LanguageId == NULL)
673 return FALSE;
674
675 /* Open the nls language key */
676 RtlInitUnicodeString(&KeyName,
677 L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\NLS\\Language");
678 InitializeObjectAttributes(&ObjectAttributes,
679 &KeyName,
680 OBJ_CASE_INSENSITIVE,
681 NULL,
682 NULL);
683 Status = NtOpenKey(&KeyHandle,
684 KEY_ALL_ACCESS,
685 &ObjectAttributes);
686 if (!NT_SUCCESS(Status))
687 {
688 DPRINT1("NtOpenKey() failed (Status %lx)\n", Status);
689 return FALSE;
690 }
691
692 /* Set default language */
693 RtlInitUnicodeString(&ValueName,
694 L"Default");
695 Status = NtSetValueKey (KeyHandle,
696 &ValueName,
697 0,
698 REG_SZ,
699 (PVOID)(LanguageId + 4),
700 8);
701 if (!NT_SUCCESS(Status))
702 {
703 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
704 NtClose(KeyHandle);
705 return FALSE;
706 }
707
708 /* Set install language */
709 RtlInitUnicodeString(&ValueName,
710 L"InstallLanguage");
711 Status = NtSetValueKey (KeyHandle,
712 &ValueName,
713 0,
714 REG_SZ,
715 (PVOID)(LanguageId + 4),
716 8);
717 if (!NT_SUCCESS(Status))
718 {
719 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
720 NtClose(KeyHandle);
721 return FALSE;
722 }
723
724 NtClose(KeyHandle);
725
726 return TRUE;
727 }
728
729
730 #if 0
731 BOOLEAN
732 ProcessKeyboardLayoutFiles(PGENERIC_LIST List)
733 {
734 return TRUE;
735 }
736 #endif
737
738 /* EOF */