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