95ddcbe68026e0602ec0718f7eb16c656c42e827
[reactos.git] / reactos / 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 = ZwSetValueKey(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 = ZwSetValueKey(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 = ZwSetValueKey(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 /* Turbo-channel */
236 case TcAdapter:
237
238 /* Fixup information */
239 Interface = TurboChannel;
240 Bus = CmpTypeCount[TurboChannel]++;
241 break;
242
243 /* ISA, PCI, etc busses */
244 case MultiFunctionAdapter:
245
246 /* Check if we have an identifier */
247 if (Component->Identifier)
248 {
249 /* Loop each multi-function adapter type */
250 for (i = 0; CmpMultifunctionTypes[i].Identifier; i++)
251 {
252 /* Check for a name match */
253 if (!_stricmp(CmpMultifunctionTypes[i].Identifier,
254 Component->Identifier))
255 {
256 /* Match found */
257 break;
258 }
259 }
260
261 /* Fix up information */
262 Interface = CmpMultifunctionTypes[i].InterfaceType;
263 Bus = CmpMultifunctionTypes[i].Count++;
264 }
265 break;
266
267 /* SCSI Bus */
268 case ScsiAdapter:
269
270 /* Fix up */
271 Interface = Internal;
272 Bus = CmpTypeCount[ScsiAdapter]++;
273 break;
274
275 /* Unknown */
276 default:
277 Interface = -1;
278 Bus = CmpUnknownBusCount++;
279 break;
280 }
281 }
282
283 /* Dump information on the component */
284
285 /* Setup the hardware node */
286 Status = CmpInitializeRegistryNode(CurrentEntry,
287 ParentHandle,
288 &NewHandle,
289 Interface,
290 Bus,
291 DeviceIndexTable);
292 if (!NT_SUCCESS(Status)) return Status;
293
294 /* Check for children */
295 if (CurrentEntry->Child)
296 {
297 /* Recurse child */
298 Status = CmpSetupConfigurationTree(CurrentEntry->Child,
299 NewHandle,
300 Interface,
301 Bus);
302 if (!NT_SUCCESS(Status))
303 {
304 /* Fail */
305 NtClose(NewHandle);
306 return Status;
307 }
308 }
309
310 /* Get to the next entry */
311 NtClose(NewHandle);
312 CurrentEntry = CurrentEntry->Sibling;
313 }
314
315 /* We're done */
316 return STATUS_SUCCESS;
317 }
318
319 NTSTATUS
320 NTAPI
321 INIT_FUNCTION
322 CmpInitializeHardwareConfiguration(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
323 {
324 NTSTATUS Status;
325 OBJECT_ATTRIBUTES ObjectAttributes;
326 HANDLE KeyHandle;
327 ULONG Disposition;
328 UNICODE_STRING KeyName;
329
330 /* Setup the key name */
331 RtlInitUnicodeString(&KeyName,
332 L"\\Registry\\Machine\\Hardware\\DeviceMap");
333 InitializeObjectAttributes(&ObjectAttributes,
334 &KeyName,
335 OBJ_CASE_INSENSITIVE,
336 NULL,
337 NULL);
338
339 /* Create the device map key */
340 Status = NtCreateKey(&KeyHandle,
341 KEY_READ | KEY_WRITE,
342 &ObjectAttributes,
343 0,
344 NULL,
345 0,
346 &Disposition);
347 if (!NT_SUCCESS(Status)) return Status;
348 NtClose(KeyHandle);
349
350 /* Nobody should've created this key yet! */
351 ASSERT(Disposition == REG_CREATED_NEW_KEY);
352
353 /* Setup the key name */
354 RtlInitUnicodeString(&KeyName,
355 L"\\Registry\\Machine\\Hardware\\Description");
356 InitializeObjectAttributes(&ObjectAttributes,
357 &KeyName,
358 OBJ_CASE_INSENSITIVE,
359 NULL,
360 NULL);
361
362 /* Create the description key */
363 Status = NtCreateKey(&KeyHandle,
364 KEY_READ | KEY_WRITE,
365 &ObjectAttributes,
366 0,
367 NULL,
368 0,
369 &Disposition);
370 if (!NT_SUCCESS(Status)) return Status;
371
372 /* Nobody should've created this key yet! */
373 ASSERT(Disposition == REG_CREATED_NEW_KEY);
374
375 /* Allocate the configuration data buffer */
376 CmpConfigurationData = ExAllocatePoolWithTag(PagedPool,
377 CmpConfigurationAreaSize,
378 TAG_CM);
379 if (!CmpConfigurationData) return STATUS_INSUFFICIENT_RESOURCES;
380
381 /* Check if we got anything from NTLDR */
382 if (LoaderBlock->ConfigurationRoot)
383 {
384 /* Setup the configuration tree */
385 Status = CmpSetupConfigurationTree(LoaderBlock->ConfigurationRoot,
386 KeyHandle,
387 -1,
388 -1);
389 }
390 else
391 {
392 /* Nothing else to do */
393 Status = STATUS_SUCCESS;
394 }
395
396 /* Close our handle, free the buffer and return status */
397 ExFreePoolWithTag(CmpConfigurationData, TAG_CM);
398 NtClose(KeyHandle);
399 return Status;
400 }