2408d4b6605f1301cf57427bd34648590aa2c603
[reactos.git] / reactos / ntoskrnl / io / pnpmgr.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/io/pnpmgr.c
5 * PURPOSE: Initializes the PnP manager
6 *
7 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
8 * Hervé Poussineau (hpoussin@reactos.org)
9 */
10
11 /* INCLUDES ******************************************************************/
12
13 #include <ntoskrnl.h>
14
15 #define NDEBUG
16 #include <internal/debug.h>
17
18 /* GLOBALS *******************************************************************/
19
20 PDEVICE_NODE IopRootDeviceNode;
21 KSPIN_LOCK IopDeviceTreeLock;
22
23 /* DATA **********************************************************************/
24
25 PDRIVER_OBJECT IopRootDriverObject;
26 PIO_BUS_TYPE_GUID_LIST IopBusTypeGuidList = NULL;
27
28 // Static CRC table
29 ULONG crc32Table[256] =
30 {
31 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
32 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
33 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
34 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
35 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
36 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
37 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
38 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
39 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
40 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
41 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
42 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
43 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
44 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
45 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
46 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
47
48 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
49 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
50 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
51 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
52 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
53 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
54 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
55 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
56 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
57 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
58 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
59 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
60 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
61 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
62 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
63 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
64
65 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
66 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
67 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
68 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
69 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
70 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
71 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
72 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
73 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
74 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
75 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
76 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
77 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
78 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
79 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
80 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
81
82 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
83 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
84 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
85 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
86 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
87 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
88 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
89 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
90 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
91 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
92 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
93 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
94 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
95 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
96 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
97 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D,
98 };
99
100
101 /* FUNCTIONS *****************************************************************/
102
103 PDEVICE_NODE FASTCALL
104 IopGetDeviceNode(
105 PDEVICE_OBJECT DeviceObject)
106 {
107 return ((PEXTENDED_DEVOBJ_EXTENSION)DeviceObject->DeviceObjectExtension)->DeviceNode;
108 }
109
110 NTSTATUS
111 STDCALL
112 IopQueryDeviceCapabilities(PDEVICE_NODE DeviceNode,
113 PDEVICE_CAPABILITIES DeviceCaps)
114 {
115 IO_STATUS_BLOCK StatusBlock;
116 IO_STACK_LOCATION Stack;
117
118 /* Set up the Header */
119 RtlZeroMemory(DeviceCaps, sizeof(DEVICE_CAPABILITIES));
120 DeviceCaps->Size = sizeof(DEVICE_CAPABILITIES);
121 DeviceCaps->Version = 1;
122 DeviceCaps->Address = -1;
123 DeviceCaps->UINumber = -1;
124
125 /* Set up the Stack */
126 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
127 Stack.Parameters.DeviceCapabilities.Capabilities = DeviceCaps;
128
129 /* Send the IRP */
130 return IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
131 &StatusBlock,
132 IRP_MN_QUERY_CAPABILITIES,
133 &Stack);
134 }
135
136 /*
137 * @implemented
138 */
139 VOID
140 STDCALL
141 IoInvalidateDeviceRelations(
142 IN PDEVICE_OBJECT DeviceObject,
143 IN DEVICE_RELATION_TYPE Type)
144 {
145 IopInvalidateDeviceRelations(IopGetDeviceNode(DeviceObject), Type);
146 }
147
148 /*
149 * @unimplemented
150 */
151 NTSTATUS
152 STDCALL
153 IoGetDeviceProperty(
154 IN PDEVICE_OBJECT DeviceObject,
155 IN DEVICE_REGISTRY_PROPERTY DeviceProperty,
156 IN ULONG BufferLength,
157 OUT PVOID PropertyBuffer,
158 OUT PULONG ResultLength)
159 {
160 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
161 DEVICE_CAPABILITIES DeviceCaps;
162 ULONG Length;
163 PVOID Data = NULL;
164 PWSTR Ptr;
165 NTSTATUS Status;
166
167 DPRINT("IoGetDeviceProperty(0x%p %d)\n", DeviceObject, DeviceProperty);
168
169 if (DeviceNode == NULL)
170 return STATUS_INVALID_DEVICE_REQUEST;
171
172 switch (DeviceProperty)
173 {
174 case DevicePropertyBusNumber:
175 Length = sizeof(ULONG);
176 Data = &DeviceNode->ChildBusNumber;
177 break;
178
179 /* Complete, untested */
180 case DevicePropertyBusTypeGuid:
181 /* Sanity check */
182 if ((DeviceNode->ChildBusTypeIndex != 0xFFFF) &&
183 (DeviceNode->ChildBusTypeIndex < IopBusTypeGuidList->GuidCount))
184 {
185 /* Return the GUID */
186 *ResultLength = sizeof(GUID);
187
188 /* Check if the buffer given was large enough */
189 if (BufferLength < *ResultLength)
190 {
191 return STATUS_BUFFER_TOO_SMALL;
192 }
193
194 /* Copy the GUID */
195 RtlCopyMemory(PropertyBuffer,
196 &(IopBusTypeGuidList->Guids[DeviceNode->ChildBusTypeIndex]),
197 sizeof(GUID));
198 return STATUS_SUCCESS;
199 }
200 else
201 {
202 return STATUS_OBJECT_NAME_NOT_FOUND;
203 }
204 break;
205
206 case DevicePropertyLegacyBusType:
207 Length = sizeof(INTERFACE_TYPE);
208 Data = &DeviceNode->ChildInterfaceType;
209 break;
210
211 case DevicePropertyAddress:
212
213 /* Query the device caps */
214 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCaps);
215 if (NT_SUCCESS(Status) && (DeviceCaps.Address != -1))
216 {
217 /* Return length */
218 *ResultLength = sizeof(ULONG);
219
220 /* Check if the buffer given was large enough */
221 if (BufferLength < *ResultLength)
222 {
223 return STATUS_BUFFER_TOO_SMALL;
224 }
225
226 /* Return address */
227 *(PULONG)PropertyBuffer = DeviceCaps.Address;
228 return STATUS_SUCCESS;
229 }
230 else
231 {
232 return STATUS_OBJECT_NAME_NOT_FOUND;
233 }
234 break;
235
236 // case DevicePropertyUINumber:
237 // if (DeviceNode->CapabilityFlags == NULL)
238 // return STATUS_INVALID_DEVICE_REQUEST;
239 // Length = sizeof(ULONG);
240 // Data = &DeviceNode->CapabilityFlags->UINumber;
241 // break;
242
243 case DevicePropertyClassName:
244 case DevicePropertyClassGuid:
245 case DevicePropertyDriverKeyName:
246 case DevicePropertyManufacturer:
247 case DevicePropertyFriendlyName:
248 case DevicePropertyHardwareID:
249 case DevicePropertyCompatibleIDs:
250 case DevicePropertyDeviceDescription:
251 case DevicePropertyLocationInformation:
252 case DevicePropertyUINumber:
253 {
254 LPWSTR RegistryPropertyName, KeyNameBuffer;
255 UNICODE_STRING KeyName, ValueName;
256 OBJECT_ATTRIBUTES ObjectAttributes;
257 KEY_VALUE_PARTIAL_INFORMATION *ValueInformation;
258 ULONG ValueInformationLength;
259 HANDLE KeyHandle;
260 NTSTATUS Status;
261
262 switch (DeviceProperty)
263 {
264 case DevicePropertyClassName:
265 RegistryPropertyName = L"Class"; break;
266 case DevicePropertyClassGuid:
267 RegistryPropertyName = L"ClassGuid"; break;
268 case DevicePropertyDriverKeyName:
269 RegistryPropertyName = L"Driver"; break;
270 case DevicePropertyManufacturer:
271 RegistryPropertyName = L"Mfg"; break;
272 case DevicePropertyFriendlyName:
273 RegistryPropertyName = L"FriendlyName"; break;
274 case DevicePropertyHardwareID:
275 RegistryPropertyName = L"HardwareID"; break;
276 case DevicePropertyCompatibleIDs:
277 RegistryPropertyName = L"CompatibleIDs"; break;
278 case DevicePropertyDeviceDescription:
279 RegistryPropertyName = L"DeviceDesc"; break;
280 case DevicePropertyLocationInformation:
281 RegistryPropertyName = L"LocationInformation"; break;
282 case DevicePropertyUINumber:
283 RegistryPropertyName = L"UINumber"; break;
284 default:
285 RegistryPropertyName = NULL; break;
286 }
287
288 KeyNameBuffer = ExAllocatePool(PagedPool,
289 (49 * sizeof(WCHAR)) + DeviceNode->InstancePath.Length);
290
291 DPRINT("KeyNameBuffer: 0x%p, value %S\n",
292 KeyNameBuffer, RegistryPropertyName);
293
294 if (KeyNameBuffer == NULL)
295 return STATUS_INSUFFICIENT_RESOURCES;
296
297 wcscpy(KeyNameBuffer, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
298 wcscat(KeyNameBuffer, DeviceNode->InstancePath.Buffer);
299 RtlInitUnicodeString(&KeyName, KeyNameBuffer);
300 InitializeObjectAttributes(&ObjectAttributes, &KeyName,
301 OBJ_CASE_INSENSITIVE, NULL, NULL);
302
303 Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
304 ExFreePool(KeyNameBuffer);
305 if (!NT_SUCCESS(Status))
306 return Status;
307
308 RtlInitUnicodeString(&ValueName, RegistryPropertyName);
309 ValueInformationLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,
310 Data[0]) + BufferLength;
311 ValueInformation = ExAllocatePool(PagedPool, ValueInformationLength);
312 if (ValueInformation == NULL)
313 {
314 ZwClose(KeyHandle);
315 return STATUS_INSUFFICIENT_RESOURCES;
316 }
317
318 Status = ZwQueryValueKey(KeyHandle, &ValueName,
319 KeyValuePartialInformation, ValueInformation,
320 ValueInformationLength,
321 &ValueInformationLength);
322 *ResultLength = ValueInformation->DataLength;
323 ZwClose(KeyHandle);
324
325 if (!NT_SUCCESS(Status))
326 {
327 ExFreePool(ValueInformation);
328 return Status;
329 }
330
331 if (ValueInformation->DataLength > BufferLength)
332 {
333 ExFreePool(ValueInformation);
334 return STATUS_BUFFER_TOO_SMALL;
335 }
336
337 /* FIXME: Verify the value (NULL-terminated, correct format). */
338
339 RtlCopyMemory(PropertyBuffer, ValueInformation->Data,
340 ValueInformation->DataLength);
341 ExFreePool(ValueInformation);
342
343 return STATUS_SUCCESS;
344 }
345
346 case DevicePropertyBootConfiguration:
347 Length = 0;
348 if (DeviceNode->BootResources->Count != 0)
349 {
350 Length = CM_RESOURCE_LIST_SIZE(DeviceNode->BootResources);
351 }
352 Data = &DeviceNode->BootResources;
353 break;
354
355 /* FIXME: use a translated boot configuration instead */
356 case DevicePropertyBootConfigurationTranslated:
357 Length = 0;
358 if (DeviceNode->BootResources->Count != 0)
359 {
360 Length = CM_RESOURCE_LIST_SIZE(DeviceNode->BootResources);
361 }
362 Data = &DeviceNode->BootResources;
363 break;
364
365 case DevicePropertyEnumeratorName:
366 Ptr = wcschr(DeviceNode->InstancePath.Buffer, L'\\');
367 if (Ptr != NULL)
368 {
369 Length = (ULONG)((ULONG_PTR)Ptr - (ULONG_PTR)DeviceNode->InstancePath.Buffer) + sizeof(WCHAR);
370 Data = DeviceNode->InstancePath.Buffer;
371 }
372 else
373 {
374 Length = 0;
375 Data = NULL;
376 }
377 break;
378
379 case DevicePropertyPhysicalDeviceObjectName:
380 Length = DeviceNode->InstancePath.Length + sizeof(WCHAR);
381 Data = DeviceNode->InstancePath.Buffer;
382 break;
383
384 default:
385 return STATUS_INVALID_PARAMETER_2;
386 }
387
388 *ResultLength = Length;
389 if (BufferLength < Length)
390 return STATUS_BUFFER_TOO_SMALL;
391 RtlCopyMemory(PropertyBuffer, Data, Length);
392
393 /* Terminate the string */
394 if (DeviceProperty == DevicePropertyEnumeratorName
395 || DeviceProperty == DevicePropertyPhysicalDeviceObjectName)
396 {
397 Ptr = (PWSTR)PropertyBuffer;
398 Ptr[(Length / sizeof(WCHAR)) - 1] = 0;
399 }
400
401 return STATUS_SUCCESS;
402 }
403
404 /*
405 * @unimplemented
406 */
407 VOID
408 STDCALL
409 IoInvalidateDeviceState(
410 IN PDEVICE_OBJECT PhysicalDeviceObject)
411 {
412 }
413
414 /**
415 * @name IoOpenDeviceRegistryKey
416 *
417 * Open a registry key unique for a specified driver or device instance.
418 *
419 * @param DeviceObject Device to get the registry key for.
420 * @param DevInstKeyType Type of the key to return.
421 * @param DesiredAccess Access mask (eg. KEY_READ | KEY_WRITE).
422 * @param DevInstRegKey Handle to the opened registry key on
423 * successful return.
424 *
425 * @return Status.
426 *
427 * @implemented
428 */
429 NTSTATUS
430 STDCALL
431 IoOpenDeviceRegistryKey(
432 IN PDEVICE_OBJECT DeviceObject,
433 IN ULONG DevInstKeyType,
434 IN ACCESS_MASK DesiredAccess,
435 OUT PHANDLE DevInstRegKey)
436 {
437 static WCHAR RootKeyName[] =
438 L"\\Registry\\Machine\\System\\CurrentControlSet\\";
439 static WCHAR ProfileKeyName[] =
440 L"Hardware Profiles\\Current\\System\\CurrentControlSet\\";
441 static WCHAR ClassKeyName[] = L"Control\\Class\\";
442 static WCHAR EnumKeyName[] = L"Enum\\";
443 static WCHAR DeviceParametersKeyName[] = L"Device Parameters\\";
444 ULONG KeyNameLength;
445 LPWSTR KeyNameBuffer;
446 UNICODE_STRING KeyName;
447 ULONG DriverKeyLength;
448 OBJECT_ATTRIBUTES ObjectAttributes;
449 PDEVICE_NODE DeviceNode = NULL;
450 NTSTATUS Status;
451
452 if ((DevInstKeyType & (PLUGPLAY_REGKEY_DEVICE | PLUGPLAY_REGKEY_DRIVER)) == 0)
453 return STATUS_INVALID_PARAMETER;
454
455 /*
456 * Calculate the length of the base key name. This is the full
457 * name for driver key or the name excluding "Device Parameters"
458 * subkey for device key.
459 */
460
461 KeyNameLength = sizeof(RootKeyName);
462 if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE)
463 KeyNameLength += sizeof(ProfileKeyName) - sizeof(UNICODE_NULL);
464 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
465 {
466 KeyNameLength += sizeof(ClassKeyName) - sizeof(UNICODE_NULL);
467 Status = IoGetDeviceProperty(DeviceObject, DevicePropertyDriverKeyName,
468 0, NULL, &DriverKeyLength);
469 if (Status != STATUS_BUFFER_TOO_SMALL)
470 return Status;
471 KeyNameLength += DriverKeyLength;
472 }
473 else
474 {
475 DeviceNode = IopGetDeviceNode(DeviceObject);
476 KeyNameLength += sizeof(EnumKeyName) - sizeof(UNICODE_NULL) +
477 DeviceNode->InstancePath.Length;
478 }
479
480 /*
481 * Now allocate the buffer for the key name...
482 */
483
484 KeyNameBuffer = ExAllocatePool(PagedPool, KeyNameLength);
485 if (KeyNameBuffer == NULL)
486 return STATUS_INSUFFICIENT_RESOURCES;
487
488 KeyName.Length = 0;
489 KeyName.MaximumLength = KeyNameLength;
490 KeyName.Buffer = KeyNameBuffer;
491
492 /*
493 * ...and build the key name.
494 */
495
496 KeyName.Length += sizeof(RootKeyName) - sizeof(UNICODE_NULL);
497 RtlCopyMemory(KeyNameBuffer, RootKeyName, KeyName.Length);
498
499 if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE)
500 RtlAppendUnicodeToString(&KeyName, ProfileKeyName);
501
502 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
503 {
504 RtlAppendUnicodeToString(&KeyName, ClassKeyName);
505 Status = IoGetDeviceProperty(DeviceObject, DevicePropertyDriverKeyName,
506 DriverKeyLength, KeyNameBuffer +
507 (KeyName.Length / sizeof(WCHAR)),
508 &DriverKeyLength);
509 if (!NT_SUCCESS(Status))
510 {
511 ExFreePool(KeyNameBuffer);
512 return Status;
513 }
514 KeyName.Length += DriverKeyLength - sizeof(UNICODE_NULL);
515 }
516 else
517 {
518 RtlAppendUnicodeToString(&KeyName, EnumKeyName);
519 Status = RtlAppendUnicodeStringToString(&KeyName, &DeviceNode->InstancePath);
520 if (DeviceNode->InstancePath.Length == 0)
521 {
522 ExFreePool(KeyNameBuffer);
523 return Status;
524 }
525 }
526
527 /*
528 * Open the base key.
529 */
530
531 InitializeObjectAttributes(&ObjectAttributes, &KeyName,
532 OBJ_CASE_INSENSITIVE, NULL, NULL);
533 Status = ZwOpenKey(DevInstRegKey, DesiredAccess, &ObjectAttributes);
534 ExFreePool(KeyNameBuffer);
535
536 /*
537 * For driver key we're done now. Also if the base key doesn't
538 * exist we can bail out with error...
539 */
540
541 if ((DevInstKeyType & PLUGPLAY_REGKEY_DRIVER) || !NT_SUCCESS(Status))
542 return Status;
543
544 /*
545 * Let's go further. For device key we must open "Device Parameters"
546 * subkey and create it if it doesn't exist yet.
547 */
548
549 RtlInitUnicodeString(&KeyName, DeviceParametersKeyName);
550 InitializeObjectAttributes(&ObjectAttributes, &KeyName,
551 OBJ_CASE_INSENSITIVE, *DevInstRegKey, NULL);
552 Status = ZwCreateKey(DevInstRegKey, DesiredAccess, &ObjectAttributes,
553 0, NULL, REG_OPTION_NON_VOLATILE, NULL);
554 ZwClose(ObjectAttributes.RootDirectory);
555
556 return Status;
557 }
558
559 /*
560 * @unimplemented
561 */
562 VOID
563 STDCALL
564 IoRequestDeviceEject(
565 IN PDEVICE_OBJECT PhysicalDeviceObject
566 )
567 {
568 UNIMPLEMENTED;
569 }
570
571
572 NTSTATUS
573 IopGetSystemPowerDeviceObject(PDEVICE_OBJECT *DeviceObject)
574 {
575 KIRQL OldIrql;
576
577 if (PopSystemPowerDeviceNode)
578 {
579 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
580 *DeviceObject = PopSystemPowerDeviceNode->PhysicalDeviceObject;
581 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
582
583 return STATUS_SUCCESS;
584 }
585
586 return STATUS_UNSUCCESSFUL;
587 }
588
589 USHORT
590 STDCALL
591 IopGetBusTypeGuidIndex(LPGUID BusTypeGuid)
592 {
593 USHORT i = 0, FoundIndex = 0xFFFF;
594 ULONG NewSize;
595 PVOID NewList;
596
597 /* Acquire the lock */
598 ExAcquireFastMutex(&IopBusTypeGuidList->Lock);
599
600 /* Loop all entries */
601 while (i < IopBusTypeGuidList->GuidCount)
602 {
603 /* Try to find a match */
604 if (RtlCompareMemory(BusTypeGuid,
605 &IopBusTypeGuidList->Guids[i],
606 sizeof(GUID)))
607 {
608 /* Found it */
609 FoundIndex = i;
610 goto Quickie;
611 }
612 i++;
613 }
614
615 /* Check if we have to grow the list */
616 if (IopBusTypeGuidList->GuidCount)
617 {
618 /* Calculate the new size */
619 NewSize = sizeof(IO_BUS_TYPE_GUID_LIST) +
620 (sizeof(GUID) * IopBusTypeGuidList->GuidCount);
621
622 /* Allocate the new copy */
623 NewList = ExAllocatePool(PagedPool, NewSize);
624
625 /* Now copy them, decrease the size too */
626 NewSize -= sizeof(GUID);
627 RtlCopyMemory(NewList, IopBusTypeGuidList, NewSize);
628
629 /* Free the old list */
630 ExFreePool(IopBusTypeGuidList);
631
632 /* Use the new buffer */
633 IopBusTypeGuidList = NewList;
634 }
635
636 /* Copy the new GUID */
637 RtlCopyMemory(&IopBusTypeGuidList->Guids[IopBusTypeGuidList->GuidCount],
638 BusTypeGuid,
639 sizeof(GUID));
640
641 /* The new entry is the index */
642 FoundIndex = IopBusTypeGuidList->GuidCount;
643 IopBusTypeGuidList->GuidCount++;
644
645 Quickie:
646 ExReleaseFastMutex(&IopBusTypeGuidList->Lock);
647 return FoundIndex;
648 }
649
650 /*
651 * DESCRIPTION
652 * Creates a device node
653 *
654 * ARGUMENTS
655 * ParentNode = Pointer to parent device node
656 * PhysicalDeviceObject = Pointer to PDO for device object. Pass NULL
657 * to have the root device node create one
658 * (eg. for legacy drivers)
659 * DeviceNode = Pointer to storage for created device node
660 *
661 * RETURN VALUE
662 * Status
663 */
664 NTSTATUS
665 IopCreateDeviceNode(PDEVICE_NODE ParentNode,
666 PDEVICE_OBJECT PhysicalDeviceObject,
667 PDEVICE_NODE *DeviceNode)
668 {
669 PDEVICE_NODE Node;
670 NTSTATUS Status;
671 KIRQL OldIrql;
672
673 DPRINT("ParentNode 0x%p PhysicalDeviceObject 0x%p\n",
674 ParentNode, PhysicalDeviceObject);
675
676 Node = (PDEVICE_NODE)ExAllocatePool(NonPagedPool, sizeof(DEVICE_NODE));
677 if (!Node)
678 {
679 return STATUS_INSUFFICIENT_RESOURCES;
680 }
681
682 RtlZeroMemory(Node, sizeof(DEVICE_NODE));
683
684 if (!PhysicalDeviceObject)
685 {
686 Status = PnpRootCreateDevice(&PhysicalDeviceObject);
687 if (!NT_SUCCESS(Status))
688 {
689 ExFreePool(Node);
690 return Status;
691 }
692
693 /* This is for drivers passed on the command line to ntoskrnl.exe */
694 IopDeviceNodeSetFlag(Node, DNF_STARTED);
695 IopDeviceNodeSetFlag(Node, DNF_LEGACY_DRIVER);
696 }
697
698 Node->PhysicalDeviceObject = PhysicalDeviceObject;
699
700 ((PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode = Node;
701
702 if (ParentNode)
703 {
704 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
705 Node->Parent = ParentNode;
706 Node->NextSibling = ParentNode->Child;
707 if (ParentNode->Child != NULL)
708 {
709 ParentNode->Child->PrevSibling = Node;
710 }
711 ParentNode->Child = Node;
712 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
713 Node->Level = ParentNode->Level + 1;
714 }
715
716 *DeviceNode = Node;
717
718 return STATUS_SUCCESS;
719 }
720
721 NTSTATUS
722 IopFreeDeviceNode(PDEVICE_NODE DeviceNode)
723 {
724 KIRQL OldIrql;
725
726 /* All children must be deleted before a parent is deleted */
727 ASSERT(!DeviceNode->Child);
728
729 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
730
731 ASSERT(DeviceNode->PhysicalDeviceObject);
732
733 ObDereferenceObject(DeviceNode->PhysicalDeviceObject);
734
735 /* Unlink from parent if it exists */
736
737 if ((DeviceNode->Parent) && (DeviceNode->Parent->Child == DeviceNode))
738 {
739 DeviceNode->Parent->Child = DeviceNode->NextSibling;
740 }
741
742 /* Unlink from sibling list */
743
744 if (DeviceNode->PrevSibling)
745 {
746 DeviceNode->PrevSibling->NextSibling = DeviceNode->NextSibling;
747 }
748
749 if (DeviceNode->NextSibling)
750 {
751 DeviceNode->NextSibling->PrevSibling = DeviceNode->PrevSibling;
752 }
753
754 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
755
756 RtlFreeUnicodeString(&DeviceNode->InstancePath);
757
758 RtlFreeUnicodeString(&DeviceNode->ServiceName);
759
760 if (DeviceNode->ResourceList)
761 {
762 ExFreePool(DeviceNode->ResourceList);
763 }
764
765 if (DeviceNode->ResourceListTranslated)
766 {
767 ExFreePool(DeviceNode->ResourceListTranslated);
768 }
769
770 if (DeviceNode->ResourceRequirements)
771 {
772 ExFreePool(DeviceNode->ResourceRequirements);
773 }
774
775 if (DeviceNode->BootResources)
776 {
777 ExFreePool(DeviceNode->BootResources);
778 }
779
780 ExFreePool(DeviceNode);
781
782 return STATUS_SUCCESS;
783 }
784
785 NTSTATUS
786 IopInitiatePnpIrp(
787 PDEVICE_OBJECT DeviceObject,
788 PIO_STATUS_BLOCK IoStatusBlock,
789 ULONG MinorFunction,
790 PIO_STACK_LOCATION Stack OPTIONAL)
791 {
792 PDEVICE_OBJECT TopDeviceObject;
793 PIO_STACK_LOCATION IrpSp;
794 NTSTATUS Status;
795 KEVENT Event;
796 PIRP Irp;
797
798 /* Always call the top of the device stack */
799 TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject);
800
801 KeInitializeEvent(
802 &Event,
803 NotificationEvent,
804 FALSE);
805
806 Irp = IoBuildSynchronousFsdRequest(
807 IRP_MJ_PNP,
808 TopDeviceObject,
809 NULL,
810 0,
811 NULL,
812 &Event,
813 IoStatusBlock);
814
815 /* PNP IRPs are always initialized with a status code of
816 STATUS_NOT_IMPLEMENTED */
817 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
818 Irp->IoStatus.Information = 0;
819
820 IrpSp = IoGetNextIrpStackLocation(Irp);
821 IrpSp->MinorFunction = MinorFunction;
822
823 if (Stack)
824 {
825 RtlMoveMemory(
826 &IrpSp->Parameters,
827 &Stack->Parameters,
828 sizeof(Stack->Parameters));
829 }
830
831 Status = IoCallDriver(TopDeviceObject, Irp);
832 if (Status == STATUS_PENDING)
833 {
834 KeWaitForSingleObject(
835 &Event,
836 Executive,
837 KernelMode,
838 FALSE,
839 NULL);
840 Status = IoStatusBlock->Status;
841 }
842
843 ObDereferenceObject(TopDeviceObject);
844
845 return Status;
846 }
847
848
849 NTSTATUS
850 IopTraverseDeviceTreeNode(
851 PDEVICETREE_TRAVERSE_CONTEXT Context)
852 {
853 PDEVICE_NODE ParentDeviceNode;
854 PDEVICE_NODE ChildDeviceNode;
855 NTSTATUS Status;
856
857 /* Copy context data so we don't overwrite it in subsequent calls to this function */
858 ParentDeviceNode = Context->DeviceNode;
859
860 /* Call the action routine */
861 Status = (Context->Action)(ParentDeviceNode, Context->Context);
862 if (!NT_SUCCESS(Status))
863 {
864 return Status;
865 }
866
867 /* Traversal of all children nodes */
868 for (ChildDeviceNode = ParentDeviceNode->Child;
869 ChildDeviceNode != NULL;
870 ChildDeviceNode = ChildDeviceNode->NextSibling)
871 {
872 /* Pass the current device node to the action routine */
873 Context->DeviceNode = ChildDeviceNode;
874
875 Status = IopTraverseDeviceTreeNode(Context);
876 if (!NT_SUCCESS(Status))
877 {
878 return Status;
879 }
880 }
881
882 return Status;
883 }
884
885
886 NTSTATUS
887 IopTraverseDeviceTree(
888 PDEVICETREE_TRAVERSE_CONTEXT Context)
889 {
890 NTSTATUS Status;
891
892 DPRINT("Context 0x%p\n", Context);
893
894 DPRINT("IopTraverseDeviceTree(DeviceNode 0x%p FirstDeviceNode 0x%p Action %x Context 0x%p)\n",
895 Context->DeviceNode, Context->FirstDeviceNode, Context->Action, Context->Context);
896
897 /* Start from the specified device node */
898 Context->DeviceNode = Context->FirstDeviceNode;
899
900 /* Recursively traverse the device tree */
901 Status = IopTraverseDeviceTreeNode(Context);
902 if (Status == STATUS_UNSUCCESSFUL)
903 {
904 /* The action routine just wanted to terminate the traversal with status
905 code STATUS_SUCCESS */
906 Status = STATUS_SUCCESS;
907 }
908
909 return Status;
910 }
911
912
913 static NTSTATUS
914 IopCreateDeviceKeyPath(PWSTR Path,
915 PHANDLE Handle)
916 {
917 OBJECT_ATTRIBUTES ObjectAttributes;
918 WCHAR KeyBuffer[MAX_PATH];
919 UNICODE_STRING KeyName;
920 HANDLE KeyHandle;
921 NTSTATUS Status;
922 PWCHAR Current;
923 PWCHAR Next;
924
925 *Handle = NULL;
926
927 if (_wcsnicmp(Path, L"\\Registry\\", 10) != 0)
928 {
929 return STATUS_INVALID_PARAMETER;
930 }
931
932 wcsncpy (KeyBuffer, Path, MAX_PATH-1);
933
934 /* Skip \\Registry\\ */
935 Current = KeyBuffer;
936 Current = wcschr (Current, L'\\') + 1;
937 Current = wcschr (Current, L'\\') + 1;
938
939 while (TRUE)
940 {
941 Next = wcschr (Current, L'\\');
942 if (Next == NULL)
943 {
944 /* The end */
945 }
946 else
947 {
948 *Next = 0;
949 }
950
951 RtlInitUnicodeString (&KeyName, KeyBuffer);
952 InitializeObjectAttributes (&ObjectAttributes,
953 &KeyName,
954 OBJ_CASE_INSENSITIVE,
955 NULL,
956 NULL);
957
958 DPRINT("Create '%S'\n", KeyName.Buffer);
959
960 Status = ZwCreateKey (&KeyHandle,
961 KEY_ALL_ACCESS,
962 &ObjectAttributes,
963 0,
964 NULL,
965 0,
966 NULL);
967 if (!NT_SUCCESS (Status))
968 {
969 DPRINT ("ZwCreateKey() failed with status %x\n", Status);
970 return Status;
971 }
972
973 if (Next == NULL)
974 {
975 *Handle = KeyHandle;
976 return STATUS_SUCCESS;
977 }
978 else
979 {
980 ZwClose (KeyHandle);
981 *Next = L'\\';
982 }
983
984 Current = Next + 1;
985 }
986
987 return STATUS_UNSUCCESSFUL;
988 }
989
990
991 static NTSTATUS
992 IopSetDeviceInstanceData(HANDLE InstanceKey,
993 PDEVICE_NODE DeviceNode)
994 {
995 OBJECT_ATTRIBUTES ObjectAttributes;
996 UNICODE_STRING KeyName;
997 HANDLE LogConfKey;
998 ULONG ResCount;
999 ULONG ListSize;
1000 NTSTATUS Status;
1001
1002 DPRINT("IopSetDeviceInstanceData() called\n");
1003
1004 /* Create the 'LogConf' key */
1005 RtlInitUnicodeString(&KeyName,
1006 L"LogConf");
1007 InitializeObjectAttributes(&ObjectAttributes,
1008 &KeyName,
1009 OBJ_CASE_INSENSITIVE,
1010 InstanceKey,
1011 NULL);
1012 Status = ZwCreateKey(&LogConfKey,
1013 KEY_ALL_ACCESS,
1014 &ObjectAttributes,
1015 0,
1016 NULL,
1017 0,
1018 NULL);
1019 if (NT_SUCCESS(Status))
1020 {
1021 /* Set 'BootConfig' value */
1022 if (DeviceNode->BootResources != NULL)
1023 {
1024 ResCount = DeviceNode->BootResources->Count;
1025 if (ResCount != 0)
1026 {
1027 ListSize = CM_RESOURCE_LIST_SIZE(DeviceNode->BootResources);
1028
1029 RtlInitUnicodeString(&KeyName,
1030 L"BootConfig");
1031 Status = ZwSetValueKey(LogConfKey,
1032 &KeyName,
1033 0,
1034 REG_RESOURCE_LIST,
1035 &DeviceNode->BootResources,
1036 ListSize);
1037 }
1038 }
1039
1040 /* Set 'BasicConfigVector' value */
1041 if (DeviceNode->ResourceRequirements != NULL &&
1042 DeviceNode->ResourceRequirements->ListSize != 0)
1043 {
1044 RtlInitUnicodeString(&KeyName,
1045 L"BasicConfigVector");
1046 Status = ZwSetValueKey(LogConfKey,
1047 &KeyName,
1048 0,
1049 REG_RESOURCE_REQUIREMENTS_LIST,
1050 DeviceNode->ResourceRequirements,
1051 DeviceNode->ResourceRequirements->ListSize);
1052 }
1053
1054 ZwClose(LogConfKey);
1055 }
1056
1057 #if 0
1058 if (DeviceNode->PhysicalDeviceObject != NULL)
1059 {
1060 /* Create the 'Control' key */
1061 RtlInitUnicodeString(&KeyName,
1062 L"Control");
1063 InitializeObjectAttributes(&ObjectAttributes,
1064 &KeyName,
1065 OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
1066 InstanceKey,
1067 NULL);
1068 Status = ZwCreateKey(&LogConfKey,
1069 KEY_ALL_ACCESS,
1070 &ObjectAttributes,
1071 0,
1072 NULL,
1073 REG_OPTION_VOLATILE,
1074 NULL);
1075 if (NT_SUCCESS(Status))
1076 {
1077 ULONG Reference = (ULONG)DeviceNode->PhysicalDeviceObject;
1078 RtlInitUnicodeString(&KeyName,
1079 L"DeviceReference");
1080 Status = ZwSetValueKey(LogConfKey,
1081 &KeyName,
1082 0,
1083 REG_DWORD,
1084 &Reference,
1085 sizeof(PVOID));
1086
1087 ZwClose(LogConfKey);
1088 }
1089 }
1090 #endif
1091
1092 DPRINT("IopSetDeviceInstanceData() done\n");
1093
1094 return STATUS_SUCCESS;
1095 }
1096
1097
1098 NTSTATUS
1099 IopAssignDeviceResources(
1100 PDEVICE_NODE DeviceNode)
1101 {
1102 PIO_RESOURCE_LIST ResourceList;
1103 PIO_RESOURCE_DESCRIPTOR ResourceDescriptor;
1104 PCM_PARTIAL_RESOURCE_DESCRIPTOR DescriptorRaw, DescriptorTranslated;
1105 ULONG NumberOfResources = 0;
1106 ULONG i;
1107 NTSTATUS Status;
1108
1109 /* Fill DeviceNode->ResourceList and DeviceNode->ResourceListTranslated;
1110 * by using DeviceNode->ResourceRequirements */
1111
1112 if (!DeviceNode->ResourceRequirements
1113 || DeviceNode->ResourceRequirements->AlternativeLists == 0)
1114 {
1115 DeviceNode->ResourceList = DeviceNode->ResourceListTranslated = NULL;
1116 return STATUS_SUCCESS;
1117 }
1118
1119 /* FIXME: that's here that PnP arbiter should go */
1120 /* Actually, simply use resource list #0 as assigned resource list */
1121 ResourceList = &DeviceNode->ResourceRequirements->List[0];
1122 if (ResourceList->Version != 1 || ResourceList->Revision != 1)
1123 {
1124 Status = STATUS_REVISION_MISMATCH;
1125 goto ByeBye;
1126 }
1127
1128 DeviceNode->ResourceList = ExAllocatePool(PagedPool,
1129 sizeof(CM_RESOURCE_LIST) + ResourceList->Count * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
1130 if (!DeviceNode->ResourceList)
1131 {
1132 Status = STATUS_INSUFFICIENT_RESOURCES;
1133 goto ByeBye;
1134 }
1135
1136 DeviceNode->ResourceListTranslated = ExAllocatePool(PagedPool,
1137 sizeof(CM_RESOURCE_LIST) + ResourceList->Count * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
1138 if (!DeviceNode->ResourceListTranslated)
1139 {
1140 Status = STATUS_INSUFFICIENT_RESOURCES;
1141 goto ByeBye;
1142 }
1143
1144 DeviceNode->ResourceList->Count = 1;
1145 DeviceNode->ResourceList->List[0].InterfaceType = DeviceNode->ResourceRequirements->InterfaceType;
1146 DeviceNode->ResourceList->List[0].BusNumber = DeviceNode->ResourceRequirements->BusNumber;
1147 DeviceNode->ResourceList->List[0].PartialResourceList.Version = 1;
1148 DeviceNode->ResourceList->List[0].PartialResourceList.Revision = 1;
1149
1150 DeviceNode->ResourceListTranslated->Count = 1;
1151 DeviceNode->ResourceListTranslated->List[0].InterfaceType = DeviceNode->ResourceRequirements->InterfaceType;
1152 DeviceNode->ResourceListTranslated->List[0].BusNumber = DeviceNode->ResourceRequirements->BusNumber;
1153 DeviceNode->ResourceListTranslated->List[0].PartialResourceList.Version = 1;
1154 DeviceNode->ResourceListTranslated->List[0].PartialResourceList.Revision = 1;
1155
1156 for (i = 0; i < ResourceList->Count; i++)
1157 {
1158 ResourceDescriptor = &ResourceList->Descriptors[i];
1159
1160 if (ResourceDescriptor->Option == 0 || ResourceDescriptor->Option == IO_RESOURCE_PREFERRED)
1161 {
1162 DescriptorRaw = &DeviceNode->ResourceList->List[0].PartialResourceList.PartialDescriptors[NumberOfResources];
1163 DescriptorTranslated = &DeviceNode->ResourceListTranslated->List[0].PartialResourceList.PartialDescriptors[NumberOfResources];
1164 NumberOfResources++;
1165
1166 /* Copy ResourceDescriptor to DescriptorRaw and DescriptorTranslated */
1167 DescriptorRaw->Type = DescriptorTranslated->Type = ResourceDescriptor->Type;
1168 DescriptorRaw->ShareDisposition = DescriptorTranslated->ShareDisposition = ResourceDescriptor->ShareDisposition;
1169 DescriptorRaw->Flags = DescriptorTranslated->Flags = ResourceDescriptor->Flags;
1170 switch (ResourceDescriptor->Type)
1171 {
1172 case CmResourceTypePort:
1173 {
1174 ULONG AddressSpace = 0; /* IO space */
1175 DescriptorRaw->u.Port.Start = ResourceDescriptor->u.Port.MinimumAddress;
1176 DescriptorRaw->u.Port.Length = DescriptorTranslated->u.Port.Length
1177 = ResourceDescriptor->u.Port.Length;
1178 if (!HalTranslateBusAddress(
1179 DeviceNode->ResourceRequirements->InterfaceType,
1180 DeviceNode->ResourceRequirements->BusNumber,
1181 DescriptorRaw->u.Port.Start,
1182 &AddressSpace,
1183 &DescriptorTranslated->u.Port.Start))
1184 {
1185 Status = STATUS_UNSUCCESSFUL;
1186 goto ByeBye;
1187 }
1188 break;
1189 }
1190 case CmResourceTypeInterrupt:
1191 {
1192 INTERFACE_TYPE BusType;
1193 ULONG SlotNumber;
1194 ULONG ret;
1195 UCHAR Irq;
1196
1197 DescriptorRaw->u.Interrupt.Level = 0;
1198 DescriptorRaw->u.Interrupt.Vector = ResourceDescriptor->u.Interrupt.MinimumVector;
1199 /* FIXME: HACK: if we have a PCI device, we try
1200 * to keep the IRQ assigned by the BIOS */
1201 if (NT_SUCCESS(IoGetDeviceProperty(
1202 DeviceNode->PhysicalDeviceObject,
1203 DevicePropertyLegacyBusType,
1204 sizeof(INTERFACE_TYPE),
1205 &BusType,
1206 &ret)) && BusType == PCIBus)
1207 {
1208 /* We have a PCI bus */
1209 if (NT_SUCCESS(IoGetDeviceProperty(
1210 DeviceNode->PhysicalDeviceObject,
1211 DevicePropertyAddress,
1212 sizeof(ULONG),
1213 &SlotNumber,
1214 &ret)) && SlotNumber > 0)
1215 {
1216 /* We have a good slot number */
1217 ret = HalGetBusDataByOffset(PCIConfiguration,
1218 DeviceNode->ResourceRequirements->BusNumber,
1219 SlotNumber,
1220 &Irq,
1221 0x3c /* PCI_INTERRUPT_LINE */,
1222 sizeof(UCHAR));
1223 if (ret != 0 && ret != 2
1224 && ResourceDescriptor->u.Interrupt.MinimumVector <= Irq
1225 && ResourceDescriptor->u.Interrupt.MaximumVector >= Irq)
1226 {
1227 /* The device already has an assigned IRQ */
1228 DescriptorRaw->u.Interrupt.Vector = Irq;
1229 }
1230 else
1231 {
1232 DPRINT1("Trying to assign IRQ 0x%lx to %wZ\n",
1233 DescriptorRaw->u.Interrupt.Vector,
1234 &DeviceNode->InstancePath);
1235 Irq = (UCHAR)DescriptorRaw->u.Interrupt.Vector;
1236 ret = HalSetBusDataByOffset(PCIConfiguration,
1237 DeviceNode->ResourceRequirements->BusNumber,
1238 SlotNumber,
1239 &Irq,
1240 0x3c /* PCI_INTERRUPT_LINE */,
1241 sizeof(UCHAR));
1242 if (ret == 0 || ret == 2)
1243 KEBUGCHECK(0);
1244 }
1245 }
1246 }
1247
1248 DescriptorTranslated->u.Interrupt.Level = 0;
1249 DescriptorTranslated->u.Interrupt.Vector = HalGetInterruptVector(
1250 DeviceNode->ResourceRequirements->InterfaceType,
1251 DeviceNode->ResourceRequirements->BusNumber,
1252 DescriptorRaw->u.Interrupt.Level,
1253 DescriptorRaw->u.Interrupt.Vector,
1254 (PKIRQL)&DescriptorTranslated->u.Interrupt.Level,
1255 &DescriptorRaw->u.Interrupt.Affinity);
1256 DescriptorTranslated->u.Interrupt.Affinity = DescriptorRaw->u.Interrupt.Affinity;
1257 break;
1258 }
1259 case CmResourceTypeMemory:
1260 {
1261 ULONG AddressSpace = 1; /* Memory space */
1262 DescriptorRaw->u.Memory.Start = ResourceDescriptor->u.Memory.MinimumAddress;
1263 DescriptorRaw->u.Memory.Length = DescriptorTranslated->u.Memory.Length
1264 = ResourceDescriptor->u.Memory.Length;
1265 if (!HalTranslateBusAddress(
1266 DeviceNode->ResourceRequirements->InterfaceType,
1267 DeviceNode->ResourceRequirements->BusNumber,
1268 DescriptorRaw->u.Memory.Start,
1269 &AddressSpace,
1270 &DescriptorTranslated->u.Memory.Start))
1271 {
1272 Status = STATUS_UNSUCCESSFUL;
1273 goto ByeBye;
1274 }
1275 break;
1276 }
1277 case CmResourceTypeDma:
1278 {
1279 DescriptorRaw->u.Dma.Channel = DescriptorTranslated->u.Dma.Channel
1280 = ResourceDescriptor->u.Dma.MinimumChannel;
1281 DescriptorRaw->u.Dma.Port = DescriptorTranslated->u.Dma.Port
1282 = 0; /* FIXME */
1283 DescriptorRaw->u.Dma.Reserved1 = DescriptorTranslated->u.Dma.Reserved1
1284 = 0;
1285 break;
1286 }
1287 case CmResourceTypeBusNumber:
1288 {
1289 DescriptorRaw->u.BusNumber.Start = DescriptorTranslated->u.BusNumber.Start
1290 = ResourceDescriptor->u.BusNumber.MinBusNumber;
1291 DescriptorRaw->u.BusNumber.Length = DescriptorTranslated->u.BusNumber.Length
1292 = ResourceDescriptor->u.BusNumber.Length;
1293 DescriptorRaw->u.BusNumber.Reserved = DescriptorTranslated->u.BusNumber.Reserved
1294 = ResourceDescriptor->u.BusNumber.Reserved;
1295 break;
1296 }
1297 /*CmResourceTypeDevicePrivate:
1298 case CmResourceTypePcCardConfig:
1299 case CmResourceTypeMfCardConfig:
1300 {
1301 RtlCopyMemory(
1302 &DescriptorRaw->u.DevicePrivate,
1303 &ResourceDescriptor->u.DevicePrivate,
1304 sizeof(ResourceDescriptor->u.DevicePrivate));
1305 RtlCopyMemory(
1306 &DescriptorTranslated->u.DevicePrivate,
1307 &ResourceDescriptor->u.DevicePrivate,
1308 sizeof(ResourceDescriptor->u.DevicePrivate));
1309 break;
1310 }*/
1311 default:
1312 DPRINT1("IopAssignDeviceResources(): unknown resource descriptor type 0x%x\n", ResourceDescriptor->Type);
1313 NumberOfResources--;
1314 }
1315 }
1316
1317 }
1318
1319 DeviceNode->ResourceList->List[0].PartialResourceList.Count = NumberOfResources;
1320 DeviceNode->ResourceListTranslated->List[0].PartialResourceList.Count = NumberOfResources;
1321
1322 return STATUS_SUCCESS;
1323
1324 ByeBye:
1325 if (DeviceNode->ResourceList)
1326 {
1327 ExFreePool(DeviceNode->ResourceList);
1328 DeviceNode->ResourceList = NULL;
1329 }
1330 if (DeviceNode->ResourceListTranslated)
1331 {
1332 ExFreePool(DeviceNode->ResourceListTranslated);
1333 DeviceNode->ResourceListTranslated = NULL;
1334 }
1335
1336 return Status;
1337 }
1338
1339
1340 /*
1341 * IopGetParentIdPrefix
1342 *
1343 * Retrieve (or create) a string which identifies a device.
1344 *
1345 * Parameters
1346 * DeviceNode
1347 * Pointer to device node.
1348 * ParentIdPrefix
1349 * Pointer to the string where is returned the parent node identifier
1350 *
1351 * Remarks
1352 * If the return code is STATUS_SUCCESS, the ParentIdPrefix string is
1353 * valid and its Buffer field is NULL-terminated. The caller needs to
1354 * to free the string with RtlFreeUnicodeString when it is no longer
1355 * needed.
1356 */
1357
1358 NTSTATUS
1359 IopGetParentIdPrefix(
1360 PDEVICE_NODE DeviceNode,
1361 PUNICODE_STRING ParentIdPrefix)
1362 {
1363 ULONG KeyNameBufferLength;
1364 PWSTR KeyNameBuffer = NULL;
1365 PKEY_VALUE_PARTIAL_INFORMATION ParentIdPrefixInformation = NULL;
1366 UNICODE_STRING KeyName;
1367 UNICODE_STRING KeyValue;
1368 UNICODE_STRING ValueName;
1369 OBJECT_ATTRIBUTES ObjectAttributes;
1370 HANDLE hKey = INVALID_HANDLE_VALUE;
1371 PBYTE currentByte;
1372 ULONG crc32 = 0;
1373 ULONG i;
1374 NTSTATUS Status;
1375
1376 /* HACK: As long as some devices have a NULL device
1377 * instance path, the following test is required :(
1378 */
1379 if (DeviceNode->Parent->InstancePath.Length == 0)
1380 return STATUS_UNSUCCESSFUL;
1381
1382 /* 1. Try to retrieve ParentIdPrefix from registry */
1383 KeyNameBufferLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) + MAX_PATH * sizeof(WCHAR);
1384 ParentIdPrefixInformation = ExAllocatePool(PagedPool, KeyNameBufferLength + sizeof(WCHAR));
1385 if (!ParentIdPrefixInformation)
1386 {
1387 Status = STATUS_INSUFFICIENT_RESOURCES;
1388 goto cleanup;
1389 }
1390 KeyNameBuffer = ExAllocatePool(PagedPool, (49 * sizeof(WCHAR)) + DeviceNode->Parent->InstancePath.Length);
1391 if (!KeyNameBuffer)
1392 {
1393 Status = STATUS_INSUFFICIENT_RESOURCES;
1394 goto cleanup;
1395 }
1396 wcscpy(KeyNameBuffer, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
1397 wcscat(KeyNameBuffer, DeviceNode->Parent->InstancePath.Buffer);
1398 RtlInitUnicodeString(&KeyName, KeyNameBuffer);
1399 InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
1400 Status = ZwOpenKey(&hKey, KEY_QUERY_VALUE | KEY_SET_VALUE, &ObjectAttributes);
1401 if (!NT_SUCCESS(Status))
1402 goto cleanup;
1403 RtlInitUnicodeString(&ValueName, L"ParentIdPrefix");
1404 Status = ZwQueryValueKey(
1405 hKey, &ValueName,
1406 KeyValuePartialInformation, ParentIdPrefixInformation,
1407 KeyNameBufferLength, &KeyNameBufferLength);
1408 if (NT_SUCCESS(Status))
1409 {
1410 if (ParentIdPrefixInformation->Type != REG_SZ)
1411 Status = STATUS_UNSUCCESSFUL;
1412 goto cleanup;
1413 }
1414 if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
1415 goto cleanup;
1416
1417 /* 2. Create the ParentIdPrefix value */
1418 currentByte = (PBYTE)DeviceNode->Parent->InstancePath.Buffer;
1419 for (i = 0; i < DeviceNode->Parent->InstancePath.Length; i++, currentByte++)
1420 crc32 = (crc32 >> 8) ^ crc32Table[*currentByte ^ (crc32 & 0xff)];
1421 crc32 = ~crc32;
1422 KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data;
1423 swprintf(KeyValue.Buffer, L"%lx&%lx", DeviceNode->Parent->Level, crc32);
1424
1425 /* 3. Try to write the ParentIdPrefix to registry */
1426 RtlInitUnicodeString(&KeyValue, KeyValue.Buffer);
1427 Status = ZwSetValueKey(
1428 hKey, &ValueName,
1429 0, REG_SZ,
1430 (PVOID)KeyValue.Buffer,
1431 (wcslen(KeyValue.Buffer) + 1) * sizeof(WCHAR));
1432
1433 cleanup:
1434 if (NT_SUCCESS(Status))
1435 {
1436 /* Duplicate the string to return it */
1437 KeyValue.Length = KeyValue.MaximumLength = ParentIdPrefixInformation->DataLength;
1438 KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data;
1439 Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, &KeyValue, ParentIdPrefix);
1440 }
1441 ExFreePool(ParentIdPrefixInformation);
1442 ExFreePool(KeyNameBuffer);
1443 if (hKey != INVALID_HANDLE_VALUE)
1444 ZwClose(hKey);
1445 return Status;
1446 }
1447
1448
1449 /*
1450 * IopActionInterrogateDeviceStack
1451 *
1452 * Retrieve information for all (direct) child nodes of a parent node.
1453 *
1454 * Parameters
1455 * DeviceNode
1456 * Pointer to device node.
1457 * Context
1458 * Pointer to parent node to retrieve child node information for.
1459 *
1460 * Remarks
1461 * We only return a status code indicating an error (STATUS_UNSUCCESSFUL)
1462 * when we reach a device node which is not a direct child of the device
1463 * node for which we retrieve information of child nodes for. Any errors
1464 * that occur is logged instead so that all child services have a chance
1465 * of being interrogated.
1466 */
1467
1468 NTSTATUS
1469 IopActionInterrogateDeviceStack(
1470 PDEVICE_NODE DeviceNode,
1471 PVOID Context)
1472 {
1473 IO_STATUS_BLOCK IoStatusBlock;
1474 PDEVICE_NODE ParentDeviceNode;
1475 WCHAR InstancePath[MAX_PATH];
1476 IO_STACK_LOCATION Stack;
1477 NTSTATUS Status;
1478 PWSTR KeyBuffer;
1479 PWSTR Ptr;
1480 USHORT Length;
1481 USHORT TotalLength;
1482 ULONG RequiredLength;
1483 LCID LocaleId;
1484 HANDLE InstanceKey = NULL;
1485 UNICODE_STRING ValueName;
1486 UNICODE_STRING ParentIdPrefix = { 0 };
1487 DEVICE_CAPABILITIES DeviceCapabilities;
1488
1489 DPRINT("IopActionInterrogateDeviceStack(%p, %p)\n", DeviceNode, Context);
1490 DPRINT("PDO 0x%p\n", DeviceNode->PhysicalDeviceObject);
1491
1492 ParentDeviceNode = (PDEVICE_NODE)Context;
1493
1494 /*
1495 * We are called for the parent too, but we don't need to do special
1496 * handling for this node
1497 */
1498
1499 if (DeviceNode == ParentDeviceNode)
1500 {
1501 DPRINT("Success\n");
1502 return STATUS_SUCCESS;
1503 }
1504
1505 /*
1506 * Make sure this device node is a direct child of the parent device node
1507 * that is given as an argument
1508 */
1509
1510 if (DeviceNode->Parent != ParentDeviceNode)
1511 {
1512 /* Stop the traversal immediately and indicate successful operation */
1513 DPRINT("Stop\n");
1514 return STATUS_UNSUCCESSFUL;
1515 }
1516
1517 /* Get Locale ID */
1518 Status = ZwQueryDefaultLocale(FALSE, &LocaleId);
1519 if (!NT_SUCCESS(Status))
1520 {
1521 DPRINT("ZwQueryDefaultLocale() failed with status 0x%lx\n", Status);
1522 return Status;
1523 }
1524
1525 /*
1526 * FIXME: For critical errors, cleanup and disable device, but always
1527 * return STATUS_SUCCESS.
1528 */
1529
1530 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryDeviceID to device stack\n");
1531
1532 Stack.Parameters.QueryId.IdType = BusQueryDeviceID;
1533 Status = IopInitiatePnpIrp(
1534 DeviceNode->PhysicalDeviceObject,
1535 &IoStatusBlock,
1536 IRP_MN_QUERY_ID,
1537 &Stack);
1538 if (NT_SUCCESS(Status))
1539 {
1540 /* Copy the device id string */
1541 wcscpy(InstancePath, (PWSTR)IoStatusBlock.Information);
1542
1543 /*
1544 * FIXME: Check for valid characters, if there is invalid characters
1545 * then bugcheck.
1546 */
1547 }
1548 else
1549 {
1550 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1551 }
1552
1553 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack\n");
1554
1555 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCapabilities);
1556 if (!NT_SUCCESS(Status))
1557 {
1558 DPRINT("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status);
1559 }
1560
1561 DeviceNode->CapabilityFlags = *(PULONG)((ULONG_PTR)&DeviceCapabilities + 4);
1562
1563 if (!DeviceCapabilities.UniqueID)
1564 {
1565 /* Device has not a unique ID. We need to prepend parent bus unique identifier */
1566 DPRINT("Instance ID is not unique\n");
1567 Status = IopGetParentIdPrefix(DeviceNode, &ParentIdPrefix);
1568 if (!NT_SUCCESS(Status))
1569 {
1570 DPRINT("IopGetParentIdPrefix() failed (Status 0x%08lx)\n", Status);
1571 }
1572 }
1573
1574 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryInstanceID to device stack\n");
1575
1576 Stack.Parameters.QueryId.IdType = BusQueryInstanceID;
1577 Status = IopInitiatePnpIrp(
1578 DeviceNode->PhysicalDeviceObject,
1579 &IoStatusBlock,
1580 IRP_MN_QUERY_ID,
1581 &Stack);
1582 if (NT_SUCCESS(Status))
1583 {
1584 /* Append the instance id string */
1585 wcscat(InstancePath, L"\\");
1586 if (ParentIdPrefix.Length > 0)
1587 {
1588 /* Add information from parent bus device to InstancePath */
1589 wcscat(InstancePath, ParentIdPrefix.Buffer);
1590 if (*(PWSTR)IoStatusBlock.Information)
1591 wcscat(InstancePath, L"&");
1592 }
1593 wcscat(InstancePath, (PWSTR)IoStatusBlock.Information);
1594
1595 /*
1596 * FIXME: Check for valid characters, if there is invalid characters
1597 * then bugcheck
1598 */
1599 }
1600 else
1601 {
1602 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1603 }
1604 RtlFreeUnicodeString(&ParentIdPrefix);
1605
1606 if (!RtlCreateUnicodeString(&DeviceNode->InstancePath, InstancePath))
1607 {
1608 DPRINT("No resources\n");
1609 /* FIXME: Cleanup and disable device */
1610 }
1611
1612 DPRINT("InstancePath is %S\n", DeviceNode->InstancePath.Buffer);
1613
1614 /*
1615 * Create registry key for the instance id, if it doesn't exist yet
1616 */
1617 KeyBuffer = ExAllocatePool(
1618 PagedPool,
1619 (49 * sizeof(WCHAR)) + DeviceNode->InstancePath.Length);
1620 wcscpy(KeyBuffer, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
1621 wcscat(KeyBuffer, DeviceNode->InstancePath.Buffer);
1622 Status = IopCreateDeviceKeyPath(KeyBuffer,
1623 &InstanceKey);
1624 ExFreePool(KeyBuffer);
1625 if (!NT_SUCCESS(Status))
1626 {
1627 DPRINT1("Failed to create the instance key! (Status %lx)\n", Status);
1628 }
1629
1630
1631 {
1632 /* Set 'Capabilities' value */
1633 RtlInitUnicodeString(&ValueName,
1634 L"Capabilities");
1635 Status = ZwSetValueKey(InstanceKey,
1636 &ValueName,
1637 0,
1638 REG_DWORD,
1639 (PVOID)&DeviceNode->CapabilityFlags,
1640 sizeof(ULONG));
1641
1642 /* Set 'UINumber' value */
1643 if (DeviceCapabilities.UINumber != (ULONG)-1)
1644 {
1645 RtlInitUnicodeString(&ValueName,
1646 L"UINumber");
1647 Status = ZwSetValueKey(InstanceKey,
1648 &ValueName,
1649 0,
1650 REG_DWORD,
1651 &DeviceCapabilities.UINumber,
1652 sizeof(ULONG));
1653 }
1654 }
1655
1656 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryHardwareIDs to device stack\n");
1657
1658 Stack.Parameters.QueryId.IdType = BusQueryHardwareIDs;
1659 Status = IopInitiatePnpIrp(
1660 DeviceNode->PhysicalDeviceObject,
1661 &IoStatusBlock,
1662 IRP_MN_QUERY_ID,
1663 &Stack);
1664 if (NT_SUCCESS(Status))
1665 {
1666 /*
1667 * FIXME: Check for valid characters, if there is invalid characters
1668 * then bugcheck.
1669 */
1670 TotalLength = 0;
1671 Ptr = (PWSTR)IoStatusBlock.Information;
1672 DPRINT("Hardware IDs:\n");
1673 while (*Ptr)
1674 {
1675 DPRINT(" %S\n", Ptr);
1676 Length = wcslen(Ptr) + 1;
1677
1678 Ptr += Length;
1679 TotalLength += Length;
1680 }
1681 DPRINT("TotalLength: %hu\n", TotalLength);
1682 DPRINT("\n");
1683
1684 RtlInitUnicodeString(&ValueName,
1685 L"HardwareID");
1686 Status = ZwSetValueKey(InstanceKey,
1687 &ValueName,
1688 0,
1689 REG_MULTI_SZ,
1690 (PVOID)IoStatusBlock.Information,
1691 (TotalLength + 1) * sizeof(WCHAR));
1692 if (!NT_SUCCESS(Status))
1693 {
1694 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status);
1695 }
1696 }
1697 else
1698 {
1699 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1700 }
1701
1702 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryCompatibleIDs to device stack\n");
1703
1704 Stack.Parameters.QueryId.IdType = BusQueryCompatibleIDs;
1705 Status = IopInitiatePnpIrp(
1706 DeviceNode->PhysicalDeviceObject,
1707 &IoStatusBlock,
1708 IRP_MN_QUERY_ID,
1709 &Stack);
1710 if (NT_SUCCESS(Status))
1711 {
1712 /*
1713 * FIXME: Check for valid characters, if there is invalid characters
1714 * then bugcheck.
1715 */
1716 TotalLength = 0;
1717 Ptr = (PWSTR)IoStatusBlock.Information;
1718 DPRINT("Compatible IDs:\n");
1719 while (*Ptr)
1720 {
1721 DPRINT(" %S\n", Ptr);
1722 Length = wcslen(Ptr) + 1;
1723
1724 Ptr += Length;
1725 TotalLength += Length;
1726 }
1727 DPRINT("TotalLength: %hu\n", TotalLength);
1728 DPRINT("\n");
1729
1730 RtlInitUnicodeString(&ValueName,
1731 L"CompatibleIDs");
1732 Status = ZwSetValueKey(InstanceKey,
1733 &ValueName,
1734 0,
1735 REG_MULTI_SZ,
1736 (PVOID)IoStatusBlock.Information,
1737 (TotalLength + 1) * sizeof(WCHAR));
1738 if (!NT_SUCCESS(Status))
1739 {
1740 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status);
1741 }
1742 }
1743 else
1744 {
1745 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1746 }
1747
1748
1749 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextDescription to device stack\n");
1750
1751 Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextDescription;
1752 Stack.Parameters.QueryDeviceText.LocaleId = LocaleId;
1753 Status = IopInitiatePnpIrp(
1754 DeviceNode->PhysicalDeviceObject,
1755 &IoStatusBlock,
1756 IRP_MN_QUERY_DEVICE_TEXT,
1757 &Stack);
1758 if (NT_SUCCESS(Status))
1759 {
1760 RtlInitUnicodeString(&ValueName, L"DeviceDesc");
1761 if (ZwQueryValueKey(InstanceKey, &ValueName, KeyValueBasicInformation, NULL, 0, &RequiredLength) == STATUS_OBJECT_NAME_NOT_FOUND)
1762 {
1763 /* This key is overriden when a driver is installed. Don't write the
1764 * new description if another one already exists */
1765 Status = ZwSetValueKey(InstanceKey,
1766 &ValueName,
1767 0,
1768 REG_SZ,
1769 (PVOID)IoStatusBlock.Information,
1770 (wcslen((PWSTR)IoStatusBlock.Information) + 1) * sizeof(WCHAR));
1771 }
1772 if (!NT_SUCCESS(Status))
1773 {
1774 DPRINT1("ZwSetValueKey() failed (Status 0x%lx)\n", Status);
1775 }
1776 }
1777 else
1778 {
1779 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1780 }
1781
1782 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextLocation to device stack\n");
1783
1784 Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextLocationInformation;
1785 Stack.Parameters.QueryDeviceText.LocaleId = LocaleId;
1786 Status = IopInitiatePnpIrp(
1787 DeviceNode->PhysicalDeviceObject,
1788 &IoStatusBlock,
1789 IRP_MN_QUERY_DEVICE_TEXT,
1790 &Stack);
1791 if (NT_SUCCESS(Status))
1792 {
1793 DPRINT("LocationInformation: %S\n", (PWSTR)IoStatusBlock.Information);
1794 RtlInitUnicodeString(&ValueName,
1795 L"LocationInformation");
1796 Status = ZwSetValueKey(InstanceKey,
1797 &ValueName,
1798 0,
1799 REG_SZ,
1800 (PVOID)IoStatusBlock.Information,
1801 (wcslen((PWSTR)IoStatusBlock.Information) + 1) * sizeof(WCHAR));
1802 if (!NT_SUCCESS(Status))
1803 {
1804 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status);
1805 }
1806 }
1807 else
1808 {
1809 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1810 }
1811
1812 DPRINT("Sending IRP_MN_QUERY_BUS_INFORMATION to device stack\n");
1813
1814 Status = IopInitiatePnpIrp(
1815 DeviceNode->PhysicalDeviceObject,
1816 &IoStatusBlock,
1817 IRP_MN_QUERY_BUS_INFORMATION,
1818 NULL);
1819 if (NT_SUCCESS(Status))
1820 {
1821 PPNP_BUS_INFORMATION BusInformation =
1822 (PPNP_BUS_INFORMATION)IoStatusBlock.Information;
1823
1824 DeviceNode->ChildBusNumber = BusInformation->BusNumber;
1825 DeviceNode->ChildInterfaceType = BusInformation->LegacyBusType;
1826 DeviceNode->ChildBusTypeIndex = IopGetBusTypeGuidIndex(&BusInformation->BusTypeGuid);
1827 ExFreePool(BusInformation);
1828 }
1829 else
1830 {
1831 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1832
1833 DeviceNode->ChildBusNumber = 0xFFFFFFF0;
1834 DeviceNode->ChildInterfaceType = InterfaceTypeUndefined;
1835 DeviceNode->ChildBusTypeIndex = -1;
1836 }
1837
1838 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
1839
1840 Status = IopInitiatePnpIrp(
1841 DeviceNode->PhysicalDeviceObject,
1842 &IoStatusBlock,
1843 IRP_MN_QUERY_RESOURCES,
1844 NULL);
1845 if (NT_SUCCESS(Status))
1846 {
1847 DeviceNode->BootResources =
1848 (PCM_RESOURCE_LIST)IoStatusBlock.Information;
1849 DeviceNode->Flags |= DNF_HAS_BOOT_CONFIG;
1850 }
1851 else
1852 {
1853 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1854 DeviceNode->BootResources = NULL;
1855 }
1856
1857 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
1858
1859 Status = IopInitiatePnpIrp(
1860 DeviceNode->PhysicalDeviceObject,
1861 &IoStatusBlock,
1862 IRP_MN_QUERY_RESOURCE_REQUIREMENTS,
1863 NULL);
1864 if (NT_SUCCESS(Status))
1865 {
1866 DeviceNode->ResourceRequirements =
1867 (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information;
1868 }
1869 else
1870 {
1871 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1872 DeviceNode->ResourceRequirements = NULL;
1873 }
1874
1875
1876 if (InstanceKey != NULL)
1877 {
1878 IopSetDeviceInstanceData(InstanceKey, DeviceNode);
1879 }
1880
1881 ZwClose(InstanceKey);
1882
1883 Status = IopAssignDeviceResources(DeviceNode);
1884 if (!NT_SUCCESS(Status))
1885 {
1886 DPRINT("IopAssignDeviceResources() failed (Status %x)\n", Status);
1887 }
1888
1889 DeviceNode->Flags |= DNF_PROCESSED;
1890
1891 /* Report the device to the user-mode pnp manager */
1892 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL,
1893 &DeviceNode->InstancePath);
1894
1895 return STATUS_SUCCESS;
1896 }
1897
1898 /*
1899 * IopActionConfigureChildServices
1900 *
1901 * Retrieve configuration for all (direct) child nodes of a parent node.
1902 *
1903 * Parameters
1904 * DeviceNode
1905 * Pointer to device node.
1906 * Context
1907 * Pointer to parent node to retrieve child node configuration for.
1908 *
1909 * Remarks
1910 * We only return a status code indicating an error (STATUS_UNSUCCESSFUL)
1911 * when we reach a device node which is not a direct child of the device
1912 * node for which we configure child services for. Any errors that occur is
1913 * logged instead so that all child services have a chance of beeing
1914 * configured.
1915 */
1916
1917 NTSTATUS
1918 IopActionConfigureChildServices(
1919 PDEVICE_NODE DeviceNode,
1920 PVOID Context)
1921 {
1922 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
1923 PDEVICE_NODE ParentDeviceNode;
1924 PUNICODE_STRING Service;
1925 NTSTATUS Status;
1926
1927 DPRINT("IopActionConfigureChildServices(%p, %p)\n", DeviceNode, Context);
1928
1929 ParentDeviceNode = (PDEVICE_NODE)Context;
1930
1931 /*
1932 * We are called for the parent too, but we don't need to do special
1933 * handling for this node
1934 */
1935 if (DeviceNode == ParentDeviceNode)
1936 {
1937 DPRINT("Success\n");
1938 return STATUS_SUCCESS;
1939 }
1940
1941 /*
1942 * Make sure this device node is a direct child of the parent device node
1943 * that is given as an argument
1944 */
1945 if (DeviceNode->Parent != ParentDeviceNode)
1946 {
1947 /* Stop the traversal immediately and indicate successful operation */
1948 DPRINT("Stop\n");
1949 return STATUS_UNSUCCESSFUL;
1950 }
1951
1952 if (!IopDeviceNodeHasFlag(DeviceNode, DNF_DISABLED))
1953 {
1954 WCHAR RegKeyBuffer[MAX_PATH];
1955 UNICODE_STRING RegKey;
1956
1957 RegKey.Length = 0;
1958 RegKey.MaximumLength = sizeof(RegKeyBuffer);
1959 RegKey.Buffer = RegKeyBuffer;
1960
1961 /*
1962 * Retrieve configuration from Enum key
1963 */
1964
1965 Service = &DeviceNode->ServiceName;
1966
1967 RtlZeroMemory(QueryTable, sizeof(QueryTable));
1968 RtlInitUnicodeString(Service, NULL);
1969
1970 QueryTable[0].Name = L"Service";
1971 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
1972 QueryTable[0].EntryContext = Service;
1973
1974 RtlAppendUnicodeToString(&RegKey, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
1975 RtlAppendUnicodeStringToString(&RegKey, &DeviceNode->InstancePath);
1976
1977 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
1978 RegKey.Buffer, QueryTable, NULL, NULL);
1979
1980 if (!NT_SUCCESS(Status))
1981 {
1982 DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status);
1983 /* FIXME: Log the error */
1984 CPRINT("Could not retrieve configuration for device %S (Status %x)\n",
1985 DeviceNode->InstancePath.Buffer, Status);
1986 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
1987 return STATUS_SUCCESS;
1988 }
1989
1990 if (Service->Buffer == NULL)
1991 {
1992 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
1993 return STATUS_SUCCESS;
1994 }
1995
1996 DPRINT("Got Service %S\n", Service->Buffer);
1997 }
1998
1999 return STATUS_SUCCESS;
2000 }
2001
2002 /*
2003 * IopActionInitChildServices
2004 *
2005 * Initialize the service for all (direct) child nodes of a parent node
2006 *
2007 * Parameters
2008 * DeviceNode
2009 * Pointer to device node.
2010 * Context
2011 * Pointer to parent node to initialize child node services for.
2012 * BootDrivers
2013 * Load only driver marked as boot start.
2014 *
2015 * Remarks
2016 * If the driver image for a service is not loaded and initialized
2017 * it is done here too. We only return a status code indicating an
2018 * error (STATUS_UNSUCCESSFUL) when we reach a device node which is
2019 * not a direct child of the device node for which we initialize
2020 * child services for. Any errors that occur is logged instead so
2021 * that all child services have a chance of being initialized.
2022 */
2023
2024 NTSTATUS
2025 IopActionInitChildServices(
2026 PDEVICE_NODE DeviceNode,
2027 PVOID Context,
2028 BOOLEAN BootDrivers)
2029 {
2030 PDEVICE_NODE ParentDeviceNode;
2031 NTSTATUS Status;
2032
2033 DPRINT("IopActionInitChildServices(%p, %p, %d)\n", DeviceNode, Context,
2034 BootDrivers);
2035
2036 ParentDeviceNode = (PDEVICE_NODE)Context;
2037
2038 /*
2039 * We are called for the parent too, but we don't need to do special
2040 * handling for this node
2041 */
2042 if (DeviceNode == ParentDeviceNode)
2043 {
2044 DPRINT("Success\n");
2045 return STATUS_SUCCESS;
2046 }
2047
2048 /*
2049 * Make sure this device node is a direct child of the parent device node
2050 * that is given as an argument
2051 */
2052 #if 0
2053 if (DeviceNode->Parent != ParentDeviceNode)
2054 {
2055 /*
2056 * Stop the traversal immediately and indicate unsuccessful operation
2057 */
2058 DPRINT("Stop\n");
2059 return STATUS_UNSUCCESSFUL;
2060 }
2061 #endif
2062
2063 if (!IopDeviceNodeHasFlag(DeviceNode, DNF_DISABLED) &&
2064 !IopDeviceNodeHasFlag(DeviceNode, DNF_ADDED) &&
2065 !IopDeviceNodeHasFlag(DeviceNode, DNF_STARTED))
2066 {
2067 PLDR_DATA_TABLE_ENTRY ModuleObject;
2068 PDRIVER_OBJECT DriverObject;
2069
2070 Status = IopLoadServiceModule(&DeviceNode->ServiceName, &ModuleObject);
2071 if (NT_SUCCESS(Status) || Status == STATUS_IMAGE_ALREADY_LOADED)
2072 {
2073 if (Status != STATUS_IMAGE_ALREADY_LOADED)
2074 Status = IopInitializeDriverModule(DeviceNode, ModuleObject,
2075 &DeviceNode->ServiceName, FALSE, &DriverObject);
2076 else
2077 {
2078 /* get existing DriverObject pointer */
2079 Status = IopGetDriverObject(
2080 &DriverObject,
2081 &DeviceNode->ServiceName,
2082 FALSE);
2083 }
2084 if (NT_SUCCESS(Status))
2085 {
2086 /* Attach lower level filter drivers. */
2087 IopAttachFilterDrivers(DeviceNode, TRUE);
2088 /* Initialize the function driver for the device node */
2089 Status = IopInitializeDevice(DeviceNode, DriverObject);
2090 if (NT_SUCCESS(Status))
2091 {
2092 /* Attach upper level filter drivers. */
2093 IopAttachFilterDrivers(DeviceNode, FALSE);
2094 IopDeviceNodeSetFlag(DeviceNode, DNF_STARTED);
2095
2096 Status = IopStartDevice(DeviceNode);
2097 }
2098 }
2099 }
2100 else
2101 {
2102 /*
2103 * Don't disable when trying to load only boot drivers
2104 */
2105 if (!BootDrivers)
2106 {
2107 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
2108 IopDeviceNodeSetFlag(DeviceNode, DNF_START_FAILED);
2109 }
2110 /* FIXME: Log the error (possibly in IopInitializeDeviceNodeService) */
2111 CPRINT("Initialization of service %S failed (Status %x)\n",
2112 DeviceNode->ServiceName.Buffer, Status);
2113 }
2114 } else
2115 {
2116 DPRINT("Service %S is disabled or already initialized\n",
2117 DeviceNode->ServiceName.Buffer);
2118 }
2119
2120 return STATUS_SUCCESS;
2121 }
2122
2123 /*
2124 * IopActionInitAllServices
2125 *
2126 * Initialize the service for all (direct) child nodes of a parent node. This
2127 * function just calls IopActionInitChildServices with BootDrivers = FALSE.
2128 */
2129
2130 NTSTATUS
2131 IopActionInitAllServices(
2132 PDEVICE_NODE DeviceNode,
2133 PVOID Context)
2134 {
2135 return IopActionInitChildServices(DeviceNode, Context, FALSE);
2136 }
2137
2138 /*
2139 * IopActionInitBootServices
2140 *
2141 * Initialize the boot start services for all (direct) child nodes of a
2142 * parent node. This function just calls IopActionInitChildServices with
2143 * BootDrivers = TRUE.
2144 */
2145 NTSTATUS
2146 IopActionInitBootServices(
2147 PDEVICE_NODE DeviceNode,
2148 PVOID Context)
2149 {
2150 return IopActionInitChildServices(DeviceNode, Context, TRUE);
2151 }
2152
2153 /*
2154 * IopInitializePnpServices
2155 *
2156 * Initialize services for discovered children
2157 *
2158 * Parameters
2159 * DeviceNode
2160 * Top device node to start initializing services.
2161 *
2162 * BootDrivers
2163 * When set to TRUE, only drivers marked as boot start will
2164 * be loaded. Otherwise, all drivers will be loaded.
2165 *
2166 * Return Value
2167 * Status
2168 */
2169 NTSTATUS
2170 IopInitializePnpServices(
2171 IN PDEVICE_NODE DeviceNode,
2172 IN BOOLEAN BootDrivers)
2173 {
2174 DEVICETREE_TRAVERSE_CONTEXT Context;
2175
2176 DPRINT("IopInitializePnpServices(%p, %d)\n", DeviceNode, BootDrivers);
2177
2178 if (BootDrivers)
2179 {
2180 IopInitDeviceTreeTraverseContext(
2181 &Context,
2182 DeviceNode,
2183 IopActionInitBootServices,
2184 DeviceNode);
2185 }
2186 else
2187 {
2188 IopInitDeviceTreeTraverseContext(
2189 &Context,
2190 DeviceNode,
2191 IopActionInitAllServices,
2192 DeviceNode);
2193 }
2194
2195 return IopTraverseDeviceTree(&Context);
2196 }
2197
2198
2199 NTSTATUS
2200 IopInvalidateDeviceRelations(
2201 IN PDEVICE_NODE DeviceNode,
2202 IN DEVICE_RELATION_TYPE Type)
2203 {
2204 DEVICETREE_TRAVERSE_CONTEXT Context;
2205 PDEVICE_RELATIONS DeviceRelations;
2206 IO_STATUS_BLOCK IoStatusBlock;
2207 PDEVICE_NODE ChildDeviceNode;
2208 IO_STACK_LOCATION Stack;
2209 BOOL BootDrivers;
2210 OBJECT_ATTRIBUTES ObjectAttributes;
2211 UNICODE_STRING LinkName;
2212 HANDLE Handle;
2213 NTSTATUS Status;
2214 ULONG i;
2215
2216 DPRINT("DeviceNode 0x%p\n", DeviceNode);
2217
2218 DPRINT("Sending IRP_MN_QUERY_DEVICE_RELATIONS to device stack\n");
2219
2220 Stack.Parameters.QueryDeviceRelations.Type = Type/*BusRelations*/;
2221
2222 Status = IopInitiatePnpIrp(
2223 DeviceNode->PhysicalDeviceObject,
2224 &IoStatusBlock,
2225 IRP_MN_QUERY_DEVICE_RELATIONS,
2226 &Stack);
2227 if (!NT_SUCCESS(Status))
2228 {
2229 DPRINT("IopInitiatePnpIrp() failed\n");
2230 return Status;
2231 }
2232
2233 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
2234
2235 if ((!DeviceRelations) || (DeviceRelations->Count <= 0))
2236 {
2237 DPRINT("No PDOs\n");
2238 if (DeviceRelations)
2239 {
2240 ExFreePool(DeviceRelations);
2241 }
2242 return STATUS_SUCCESS;
2243 }
2244
2245 DPRINT("Got %d PDOs\n", DeviceRelations->Count);
2246
2247 /*
2248 * Create device nodes for all discovered devices
2249 */
2250
2251 for (i = 0; i < DeviceRelations->Count; i++)
2252 {
2253 Status = IopCreateDeviceNode(
2254 DeviceNode,
2255 DeviceRelations->Objects[i],
2256 &ChildDeviceNode);
2257 DeviceNode->Flags |= DNF_ENUMERATED;
2258 if (!NT_SUCCESS(Status))
2259 {
2260 DPRINT("No resources\n");
2261 for (i = 0; i < DeviceRelations->Count; i++)
2262 ObDereferenceObject(DeviceRelations->Objects[i]);
2263 ExFreePool(DeviceRelations);
2264 return STATUS_INSUFFICIENT_RESOURCES;
2265 }
2266 }
2267 ExFreePool(DeviceRelations);
2268
2269 /*
2270 * Retrieve information about all discovered children from the bus driver
2271 */
2272
2273 IopInitDeviceTreeTraverseContext(
2274 &Context,
2275 DeviceNode,
2276 IopActionInterrogateDeviceStack,
2277 DeviceNode);
2278
2279 Status = IopTraverseDeviceTree(&Context);
2280 if (!NT_SUCCESS(Status))
2281 {
2282 DPRINT("IopTraverseDeviceTree() failed with status (%x)\n", Status);
2283 return Status;
2284 }
2285
2286 /*
2287 * Retrieve configuration from the registry for discovered children
2288 */
2289
2290 IopInitDeviceTreeTraverseContext(
2291 &Context,
2292 DeviceNode,
2293 IopActionConfigureChildServices,
2294 DeviceNode);
2295
2296 Status = IopTraverseDeviceTree(&Context);
2297 if (!NT_SUCCESS(Status))
2298 {
2299 DPRINT("IopTraverseDeviceTree() failed with status (%x)\n", Status);
2300 return Status;
2301 }
2302
2303 /*
2304 * Get the state of the system boot. If the \\SystemRoot link isn't
2305 * created yet, we will assume that it's possible to load only boot
2306 * drivers.
2307 */
2308
2309 RtlInitUnicodeString(&LinkName, L"\\SystemRoot");
2310
2311 InitializeObjectAttributes(
2312 &ObjectAttributes,
2313 &LinkName,
2314 0,
2315 NULL,
2316 NULL);
2317
2318 Status = ZwOpenFile(
2319 &Handle,
2320 FILE_ALL_ACCESS,
2321 &ObjectAttributes,
2322 &IoStatusBlock,
2323 0,
2324 0);
2325 if(NT_SUCCESS(Status))
2326 {
2327 BootDrivers = FALSE;
2328 ZwClose(Handle);
2329 }
2330 else
2331 BootDrivers = TRUE;
2332
2333 /*
2334 * Initialize services for discovered children. Only boot drivers will
2335 * be loaded from boot driver!
2336 */
2337
2338 Status = IopInitializePnpServices(DeviceNode, BootDrivers);
2339 if (!NT_SUCCESS(Status))
2340 {
2341 DPRINT("IopInitializePnpServices() failed with status (%x)\n", Status);
2342 return Status;
2343 }
2344
2345 return STATUS_SUCCESS;
2346 }
2347
2348
2349 static NTSTATUS INIT_FUNCTION
2350 IopSetRootDeviceInstanceData(PDEVICE_NODE DeviceNode)
2351 {
2352 #if 0
2353 PWSTR KeyBuffer;
2354 HANDLE InstanceKey = NULL;
2355 NTSTATUS Status;
2356
2357 /* Create registry key for the instance id, if it doesn't exist yet */
2358 KeyBuffer = ExAllocatePool(PagedPool,
2359 (49 * sizeof(WCHAR)) + DeviceNode->InstancePath.Length);
2360 wcscpy(KeyBuffer, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
2361 wcscat(KeyBuffer, DeviceNode->InstancePath.Buffer);
2362 Status = IopCreateDeviceKeyPath(KeyBuffer,
2363 &InstanceKey);
2364 ExFreePool(KeyBuffer);
2365 if (!NT_SUCCESS(Status))
2366 {
2367 DPRINT1("Failed to create the instance key! (Status %lx)\n", Status);
2368 return Status;
2369 }
2370
2371 /* FIXME: Set 'ConfigFlags' value */
2372
2373 ZwClose(InstanceKey);
2374
2375 return Status;
2376 #endif
2377 return STATUS_SUCCESS;
2378 }
2379
2380
2381 VOID INIT_FUNCTION
2382 PnpInit(VOID)
2383 {
2384 PDEVICE_OBJECT Pdo;
2385 NTSTATUS Status;
2386
2387 DPRINT("PnpInit()\n");
2388
2389 KeInitializeSpinLock(&IopDeviceTreeLock);
2390
2391 /* Initialize the Bus Type GUID List */
2392 IopBusTypeGuidList = ExAllocatePool(PagedPool, sizeof(IO_BUS_TYPE_GUID_LIST));
2393 RtlZeroMemory(IopBusTypeGuidList, sizeof(IO_BUS_TYPE_GUID_LIST));
2394 ExInitializeFastMutex(&IopBusTypeGuidList->Lock);
2395
2396 /* Initialize PnP-Event notification support */
2397 Status = IopInitPlugPlayEvents();
2398 if (!NT_SUCCESS(Status))
2399 {
2400 CPRINT("IopInitPlugPlayEvents() failed\n");
2401 KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
2402 }
2403
2404 /*
2405 * Create root device node
2406 */
2407
2408 Status = IopCreateDriverObject(&IopRootDriverObject, NULL, 0, FALSE, NULL, 0);
2409 if (!NT_SUCCESS(Status))
2410 {
2411 CPRINT("IoCreateDriverObject() failed\n");
2412 KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
2413 }
2414
2415 Status = IoCreateDevice(IopRootDriverObject, 0, NULL, FILE_DEVICE_CONTROLLER,
2416 0, FALSE, &Pdo);
2417 if (!NT_SUCCESS(Status))
2418 {
2419 CPRINT("IoCreateDevice() failed\n");
2420 KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
2421 }
2422
2423 Status = IopCreateDeviceNode(NULL, Pdo, &IopRootDeviceNode);
2424 if (!NT_SUCCESS(Status))
2425 {
2426 CPRINT("Insufficient resources\n");
2427 KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
2428 }
2429
2430 if (!RtlCreateUnicodeString(&IopRootDeviceNode->InstancePath,
2431 L"HTREE\\ROOT\\0"))
2432 {
2433 CPRINT("Failed to create the instance path!\n");
2434 KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED, STATUS_UNSUCCESSFUL, 0, 0, 0);
2435 }
2436
2437 /* Report the device to the user-mode pnp manager */
2438 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL,
2439 &IopRootDeviceNode->InstancePath);
2440
2441 IopRootDeviceNode->PhysicalDeviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE;
2442 PnpRootDriverEntry(IopRootDriverObject, NULL);
2443 IopRootDriverObject->DriverExtension->AddDevice(
2444 IopRootDriverObject,
2445 IopRootDeviceNode->PhysicalDeviceObject);
2446 }
2447
2448
2449 VOID INIT_FUNCTION
2450 PnpInit2(VOID)
2451 {
2452 NTSTATUS Status;
2453
2454 /* Set root device instance data */
2455 Status = IopSetRootDeviceInstanceData(IopRootDeviceNode);
2456 if (!NT_SUCCESS(Status))
2457 {
2458 CPRINT("Failed to set instance data\n");
2459 KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
2460 }
2461 }
2462
2463 /* EOF */