9da721e2413bd5af4f2b91f6e4a5b24aaf129dbe
[reactos.git] / ntoskrnl / config / cmconfig.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/config/cmconfig.c
5 * PURPOSE: Configuration Manager - System Configuration Routines
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include "ntoskrnl.h"
12 #define NDEBUG
13 #include "debug.h"
14
15 /* FUNCTIONS *****************************************************************/
16
17 NTSTATUS
18 NTAPI
19 INIT_FUNCTION
20 CmpInitializeRegistryNode(IN PCONFIGURATION_COMPONENT_DATA CurrentEntry,
21 IN HANDLE NodeHandle,
22 OUT PHANDLE NewHandle,
23 IN INTERFACE_TYPE InterfaceType,
24 IN ULONG BusNumber,
25 IN PUSHORT DeviceIndexTable)
26 {
27 NTSTATUS Status;
28 OBJECT_ATTRIBUTES ObjectAttributes;
29 UNICODE_STRING KeyName, ValueName, ValueData;
30 HANDLE KeyHandle, ParentHandle;
31 ANSI_STRING TempString;
32 CHAR TempBuffer[12];
33 WCHAR Buffer[12];
34 PCONFIGURATION_COMPONENT Component;
35 ULONG Disposition, Length = 0;
36
37 /* Get the component */
38 Component = &CurrentEntry->ComponentEntry;
39
40 /* Set system class components to ARC system type */
41 if (Component->Class == SystemClass) Component->Type = ArcSystem;
42
43 /* Create a key for the component */
44 InitializeObjectAttributes(&ObjectAttributes,
45 &CmTypeName[Component->Type],
46 OBJ_CASE_INSENSITIVE,
47 NodeHandle,
48 NULL);
49 Status = NtCreateKey(&KeyHandle,
50 KEY_READ | KEY_WRITE,
51 &ObjectAttributes,
52 0,
53 NULL,
54 0,
55 &Disposition);
56 if (!NT_SUCCESS(Status)) return Status;
57
58 /* Check if this is anything but a system class component */
59 if (Component->Class != SystemClass)
60 {
61 /* Build the sub-component string */
62 RtlIntegerToChar(DeviceIndexTable[Component->Type]++,
63 10,
64 12,
65 TempBuffer);
66 RtlInitAnsiString(&TempString, TempBuffer);
67
68 /* Convert it to Unicode */
69 RtlInitEmptyUnicodeString(&KeyName, Buffer, sizeof(Buffer));
70 Status = RtlAnsiStringToUnicodeString(&KeyName, &TempString, FALSE);
71 if (!NT_SUCCESS(Status))
72 {
73 NtClose(KeyHandle);
74 return Status;
75 }
76
77 /* Create the key */
78 ParentHandle = KeyHandle;
79 InitializeObjectAttributes(&ObjectAttributes,
80 &KeyName,
81 OBJ_CASE_INSENSITIVE,
82 ParentHandle,
83 NULL);
84 Status = NtCreateKey(&KeyHandle,
85 KEY_READ | KEY_WRITE,
86 &ObjectAttributes,
87 0,
88 NULL,
89 0,
90 &Disposition);
91 NtClose(ParentHandle);
92
93 /* Fail if the key couldn't be created, and make sure it's a new key */
94 if (!NT_SUCCESS(Status)) return Status;
95 ASSERT(Disposition == REG_CREATED_NEW_KEY);
96 }
97
98 /* Setup the component information key */
99 RtlInitUnicodeString(&ValueName, L"Component Information");
100 Status = NtSetValueKey(KeyHandle,
101 &ValueName,
102 0,
103 REG_BINARY,
104 &Component->Flags,
105 FIELD_OFFSET(CONFIGURATION_COMPONENT,
106 ConfigurationDataLength) -
107 FIELD_OFFSET(CONFIGURATION_COMPONENT, Flags));
108 if (!NT_SUCCESS(Status))
109 {
110 /* Fail */
111 NtClose(KeyHandle);
112 return Status;
113 }
114
115 /* Check if we have an identifier */
116 if (Component->IdentifierLength)
117 {
118 /* Build the string and convert it to Unicode */
119 RtlInitUnicodeString(&ValueName, L"Identifier");
120 RtlInitAnsiString(&TempString, Component->Identifier);
121 Status = RtlAnsiStringToUnicodeString(&ValueData,
122 &TempString,
123 TRUE);
124 if (NT_SUCCESS(Status))
125 {
126 /* Save the identifier in the registry */
127 Status = NtSetValueKey(KeyHandle,
128 &ValueName,
129 0,
130 REG_SZ,
131 ValueData.Buffer,
132 ValueData.Length + sizeof(UNICODE_NULL));
133 RtlFreeUnicodeString(&ValueData);
134 }
135
136 /* Check for failure during conversion or registry write */
137 if (!NT_SUCCESS(Status))
138 {
139 /* Fail */
140 NtClose(KeyHandle);
141 return Status;
142 }
143 }
144
145 /* Setup the configuration data string */
146 RtlInitUnicodeString(&ValueName, L"Configuration Data");
147
148 /* Check if we got configuration data */
149 if (CurrentEntry->ConfigurationData)
150 {
151 /* Calculate the total length and check if it fits into our buffer */
152 Length = Component->ConfigurationDataLength +
153 FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList);
154 if (Length > CmpConfigurationAreaSize)
155 {
156 ASSERTMSG("Component too large -- need reallocation!", FALSE);
157 }
158 else
159 {
160 /* Copy the data */
161 RtlCopyMemory(&CmpConfigurationData->PartialResourceList.Version,
162 CurrentEntry->ConfigurationData,
163 Component->ConfigurationDataLength);
164 }
165 }
166 else
167 {
168 /* No configuration data, setup defaults */
169 CmpConfigurationData->PartialResourceList.Version = 0;
170 CmpConfigurationData->PartialResourceList.Revision = 0;
171 CmpConfigurationData->PartialResourceList.Count = 0;
172 Length = FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors) +
173 FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList);
174 }
175
176 /* Set the interface type and bus number */
177 CmpConfigurationData->InterfaceType = InterfaceType;
178 CmpConfigurationData->BusNumber = BusNumber;
179
180 /* Save the actual data */
181 Status = NtSetValueKey(KeyHandle,
182 &ValueName,
183 0,
184 REG_FULL_RESOURCE_DESCRIPTOR,
185 CmpConfigurationData,
186 Length);
187 if (!NT_SUCCESS(Status))
188 {
189 /* Fail */
190 NtClose(KeyHandle);
191 }
192 else
193 {
194 /* Return the new handle */
195 *NewHandle = KeyHandle;
196 }
197
198 /* Return status */
199 return Status;
200 }
201
202 NTSTATUS
203 NTAPI
204 INIT_FUNCTION
205 CmpSetupConfigurationTree(IN PCONFIGURATION_COMPONENT_DATA CurrentEntry,
206 IN HANDLE ParentHandle,
207 IN INTERFACE_TYPE InterfaceType,
208 IN ULONG BusNumber)
209 {
210 PCONFIGURATION_COMPONENT Component;
211 USHORT DeviceIndexTable[MaximumType + 1] = {0};
212 ULONG Interface = InterfaceType, Bus = BusNumber, i;
213 NTSTATUS Status;
214 HANDLE NewHandle;
215
216 /* Loop each entry */
217 while (CurrentEntry)
218 {
219 /* Check if this is an adapter */
220 Component = &CurrentEntry->ComponentEntry;
221 if ((Component->Class == AdapterClass) &&
222 (CurrentEntry->Parent->ComponentEntry.Class == SystemClass))
223 {
224 /* Check what kind of adapter it is */
225 switch (Component->Type)
226 {
227 /* EISA */
228 case EisaAdapter:
229 {
230 /* Fixup information */
231 Interface = Eisa;
232 Bus = CmpTypeCount[EisaAdapter]++;
233 break;
234 }
235
236 /* Turbo-channel */
237 case TcAdapter:
238 {
239 /* Fixup information */
240 Interface = TurboChannel;
241 Bus = CmpTypeCount[TurboChannel]++;
242 break;
243 }
244
245 /* ISA, PCI, etc busses */
246 case MultiFunctionAdapter:
247 {
248 /* Check if we have an identifier */
249 if (Component->Identifier)
250 {
251 /* Loop each multi-function adapter type */
252 for (i = 0; CmpMultifunctionTypes[i].Identifier; i++)
253 {
254 /* Check for a name match */
255 if (!_stricmp(CmpMultifunctionTypes[i].Identifier,
256 Component->Identifier))
257 {
258 /* Match found */
259 break;
260 }
261 }
262
263 /* Fix up information */
264 Interface = CmpMultifunctionTypes[i].InterfaceType;
265 Bus = CmpMultifunctionTypes[i].Count++;
266 }
267 break;
268 }
269
270 /* SCSI Bus */
271 case ScsiAdapter:
272 {
273 /* Fix up */
274 Interface = Internal;
275 Bus = CmpTypeCount[ScsiAdapter]++;
276 break;
277 }
278
279 /* Unknown */
280 default:
281 {
282 Interface = -1;
283 Bus = CmpUnknownBusCount++;
284 break;
285 }
286 }
287 }
288
289 /* Dump information on the component */
290
291 /* Setup the hardware node */
292 Status = CmpInitializeRegistryNode(CurrentEntry,
293 ParentHandle,
294 &NewHandle,
295 Interface,
296 Bus,
297 DeviceIndexTable);
298 if (!NT_SUCCESS(Status)) return Status;
299
300 /* Check for children */
301 if (CurrentEntry->Child)
302 {
303 /* Recurse child */
304 Status = CmpSetupConfigurationTree(CurrentEntry->Child,
305 NewHandle,
306 Interface,
307 Bus);
308 if (!NT_SUCCESS(Status))
309 {
310 /* Fail */
311 NtClose(NewHandle);
312 return Status;
313 }
314 }
315
316 /* Get to the next entry */
317 NtClose(NewHandle);
318 CurrentEntry = CurrentEntry->Sibling;
319 }
320
321 /* We're done */
322 return STATUS_SUCCESS;
323 }
324
325 NTSTATUS
326 NTAPI
327 INIT_FUNCTION
328 CmpInitializeHardwareConfiguration(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
329 {
330 NTSTATUS Status;
331 OBJECT_ATTRIBUTES ObjectAttributes;
332 HANDLE KeyHandle;
333 ULONG Disposition;
334 UNICODE_STRING KeyName;
335
336 /* Setup the key name */
337 RtlInitUnicodeString(&KeyName,
338 L"\\Registry\\Machine\\Hardware\\DeviceMap");
339 InitializeObjectAttributes(&ObjectAttributes,
340 &KeyName,
341 OBJ_CASE_INSENSITIVE,
342 NULL,
343 NULL);
344
345 /* Create the device map key */
346 Status = NtCreateKey(&KeyHandle,
347 KEY_READ | KEY_WRITE,
348 &ObjectAttributes,
349 0,
350 NULL,
351 0,
352 &Disposition);
353 if (!NT_SUCCESS(Status))
354 return Status;
355 NtClose(KeyHandle);
356
357 /* Nobody should've created this key yet! */
358 ASSERT(Disposition == REG_CREATED_NEW_KEY);
359
360 /* Setup the key name */
361 RtlInitUnicodeString(&KeyName,
362 L"\\Registry\\Machine\\Hardware\\Description");
363 InitializeObjectAttributes(&ObjectAttributes,
364 &KeyName,
365 OBJ_CASE_INSENSITIVE,
366 NULL,
367 NULL);
368
369 /* Create the description key */
370 Status = NtCreateKey(&KeyHandle,
371 KEY_READ | KEY_WRITE,
372 &ObjectAttributes,
373 0,
374 NULL,
375 0,
376 &Disposition);
377 if (!NT_SUCCESS(Status))
378 return Status;
379
380 /* Nobody should've created this key yet! */
381 ASSERT(Disposition == REG_CREATED_NEW_KEY);
382
383 /* Allocate the configuration data buffer */
384 CmpConfigurationData = ExAllocatePoolWithTag(PagedPool,
385 CmpConfigurationAreaSize,
386 TAG_CM);
387 if (!CmpConfigurationData)
388 {
389 NtClose(KeyHandle);
390 return STATUS_INSUFFICIENT_RESOURCES;
391 }
392
393 /* Check if we got anything from NTLDR */
394 if (LoaderBlock->ConfigurationRoot)
395 {
396 /* Setup the configuration tree */
397 Status = CmpSetupConfigurationTree(LoaderBlock->ConfigurationRoot,
398 KeyHandle,
399 -1,
400 -1);
401 }
402 else
403 {
404 /* Nothing else to do */
405 Status = STATUS_SUCCESS;
406 }
407
408 /* Free the buffer, close our handle and return status */
409 ExFreePoolWithTag(CmpConfigurationData, TAG_CM);
410 NtClose(KeyHandle);
411 return Status;
412 }