- Cleanup and reformat parts of pnpmgr (no code change)
[reactos.git] / reactos / ntoskrnl / io / pnpmgr / pnproot.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * COPYRIGHT: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/pnpmgr/pnproot.c
5 * PURPOSE: PnP manager root device
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Copyright 2007 Hervé Poussineau (hpoussin@reactos.org)
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <internal/debug.h>
15
16 /* GLOBALS *******************************************************************/
17
18 #define ENUM_NAME_ROOT L"Root"
19
20 /* DATA **********************************************************************/
21
22 typedef struct _PNPROOT_DEVICE
23 {
24 // Entry on device list
25 LIST_ENTRY ListEntry;
26 // Physical Device Object of device
27 PDEVICE_OBJECT Pdo;
28 // Device ID
29 UNICODE_STRING DeviceID;
30 // Instance ID
31 UNICODE_STRING InstanceID;
32 // Device description
33 UNICODE_STRING DeviceDescription;
34 // Resource requirement list
35 PIO_RESOURCE_REQUIREMENTS_LIST ResourceRequirementsList;
36 ULONG ResourceRequirementsListSize;
37 // Associated resource list
38 PCM_RESOURCE_LIST ResourceList;
39 ULONG ResourceListSize;
40 } PNPROOT_DEVICE, *PPNPROOT_DEVICE;
41
42 typedef enum
43 {
44 dsStopped,
45 dsStarted,
46 dsPaused,
47 dsRemoved,
48 dsSurpriseRemoved
49 } PNPROOT_DEVICE_STATE;
50
51 typedef struct _PNPROOT_COMMON_DEVICE_EXTENSION
52 {
53 // Wether this device extension is for an FDO or PDO
54 BOOLEAN IsFDO;
55 } PNPROOT_COMMON_DEVICE_EXTENSION, *PPNPROOT_COMMON_DEVICE_EXTENSION;
56
57 /* Physical Device Object device extension for a child device */
58 typedef struct _PNPROOT_PDO_DEVICE_EXTENSION
59 {
60 // Common device data
61 PNPROOT_COMMON_DEVICE_EXTENSION Common;
62 // Informations about the device
63 PPNPROOT_DEVICE DeviceInfo;
64 } PNPROOT_PDO_DEVICE_EXTENSION, *PPNPROOT_PDO_DEVICE_EXTENSION;
65
66 /* Physical Device Object device extension for the Root bus device object */
67 typedef struct _PNPROOT_FDO_DEVICE_EXTENSION
68 {
69 // Common device data
70 PNPROOT_COMMON_DEVICE_EXTENSION Common;
71 // Lower device object
72 PDEVICE_OBJECT Ldo;
73 // Current state of the driver
74 PNPROOT_DEVICE_STATE State;
75 // Namespace device list
76 LIST_ENTRY DeviceListHead;
77 // Number of (not removed) devices in device list
78 ULONG DeviceListCount;
79 // Lock for namespace device list
80 KGUARDED_MUTEX DeviceListLock;
81 } PNPROOT_FDO_DEVICE_EXTENSION, *PPNPROOT_FDO_DEVICE_EXTENSION;
82
83 typedef struct _BUFFER
84 {
85 PVOID *Data;
86 PULONG Length;
87 } BUFFER, *PBUFFER;
88
89 static PDEVICE_OBJECT PnpRootDeviceObject = NULL;
90
91 /* FUNCTIONS *****************************************************************/
92
93 static NTSTATUS
94 LocateChildDevice(
95 IN PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension,
96 IN PCWSTR DeviceId,
97 IN PCWSTR InstanceId,
98 OUT PPNPROOT_DEVICE* ChildDevice)
99 {
100 PPNPROOT_DEVICE Device;
101 UNICODE_STRING DeviceIdU, InstanceIdU;
102
103 RtlInitUnicodeString(&DeviceIdU, DeviceId);
104 RtlInitUnicodeString(&InstanceIdU, InstanceId);
105
106 LIST_FOR_EACH(Device, &DeviceExtension->DeviceListHead, PNPROOT_DEVICE, ListEntry)
107 {
108 if (RtlEqualUnicodeString(&DeviceIdU, &Device->DeviceID, TRUE)
109 && RtlEqualUnicodeString(&InstanceIdU, &Device->InstanceID, TRUE))
110 {
111 *ChildDevice = Device;
112 return STATUS_SUCCESS;
113 }
114 }
115
116 return STATUS_NO_SUCH_DEVICE;
117 }
118
119 /* Creates a new PnP device for a legacy driver */
120 NTSTATUS
121 PnpRootCreateDevice(
122 IN PUNICODE_STRING ServiceName,
123 IN PDEVICE_OBJECT *PhysicalDeviceObject)
124 {
125 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension;
126 UNICODE_STRING UnknownServiceName = RTL_CONSTANT_STRING(L"UNKNOWN");
127 PUNICODE_STRING LocalServiceName;
128 PPNPROOT_PDO_DEVICE_EXTENSION PdoDeviceExtension;
129 WCHAR DevicePath[MAX_PATH + 1];
130 WCHAR InstancePath[5];
131 PPNPROOT_DEVICE Device = NULL;
132 NTSTATUS Status;
133 ULONG i;
134
135 DeviceExtension = PnpRootDeviceObject->DeviceExtension;
136 KeAcquireGuardedMutex(&DeviceExtension->DeviceListLock);
137
138 if (ServiceName)
139 LocalServiceName = ServiceName;
140 else
141 LocalServiceName = &UnknownServiceName;
142
143 DPRINT("Creating a PnP root device for service '%wZ'\n", LocalServiceName);
144
145 /* Search for a free instance ID */
146 _snwprintf(DevicePath, sizeof(DevicePath) / sizeof(WCHAR), L"%s\\LEGACY_%wZ", REGSTR_KEY_ROOTENUM, LocalServiceName);
147 for (i = 0; i < 9999; i++)
148 {
149 _snwprintf(InstancePath, sizeof(InstancePath) / sizeof(WCHAR), L"%04lu", i);
150 Status = LocateChildDevice(DeviceExtension, DevicePath, InstancePath, &Device);
151 if (Status == STATUS_NO_SUCH_DEVICE)
152 break;
153 }
154 if (i > 9999)
155 {
156 DPRINT1("Too much legacy devices reported for service '%wZ'\n", &LocalServiceName);
157 Status = STATUS_INSUFFICIENT_RESOURCES;
158 goto cleanup;
159 }
160
161 /* Initialize a PNPROOT_DEVICE structure */
162 Device = ExAllocatePoolWithTag(PagedPool, sizeof(PNPROOT_DEVICE), TAG_PNP_ROOT);
163 if (!Device)
164 {
165 DPRINT("ExAllocatePoolWithTag() failed\n");
166 Status = STATUS_NO_MEMORY;
167 goto cleanup;
168 }
169 RtlZeroMemory(Device, sizeof(PNPROOT_DEVICE));
170 if (!RtlCreateUnicodeString(&Device->DeviceID, DevicePath))
171 {
172 Status = STATUS_NO_MEMORY;
173 goto cleanup;
174 }
175 if (!RtlCreateUnicodeString(&Device->InstanceID, InstancePath))
176 {
177 Status = STATUS_NO_MEMORY;
178 goto cleanup;
179 }
180
181 /* Initialize a device object */
182 Status = IoCreateDevice(
183 PnpRootDeviceObject->DriverObject,
184 sizeof(PNPROOT_PDO_DEVICE_EXTENSION),
185 NULL,
186 FILE_DEVICE_CONTROLLER,
187 FILE_AUTOGENERATED_DEVICE_NAME,
188 FALSE,
189 &Device->Pdo);
190 if (!NT_SUCCESS(Status))
191 {
192 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status);
193 Status = STATUS_NO_MEMORY;
194 goto cleanup;
195 }
196
197 PdoDeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)Device->Pdo->DeviceExtension;
198 RtlZeroMemory(PdoDeviceExtension, sizeof(PNPROOT_PDO_DEVICE_EXTENSION));
199 PdoDeviceExtension->Common.IsFDO = FALSE;
200 PdoDeviceExtension->DeviceInfo = Device;
201
202 Device->Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
203 Device->Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
204
205 InsertTailList(
206 &DeviceExtension->DeviceListHead,
207 &Device->ListEntry);
208 DeviceExtension->DeviceListCount++;
209
210 *PhysicalDeviceObject = Device->Pdo;
211 DPRINT("Created PDO %p (%wZ\\%wZ)\n", *PhysicalDeviceObject, &Device->DeviceID, &Device->InstanceID);
212 Device = NULL;
213 Status = STATUS_SUCCESS;
214
215 cleanup:
216 KeReleaseGuardedMutex(&DeviceExtension->DeviceListLock);
217 if (Device)
218 {
219 if (Device->Pdo)
220 IoDeleteDevice(Device->Pdo);
221 RtlFreeUnicodeString(&Device->DeviceID);
222 RtlFreeUnicodeString(&Device->InstanceID);
223 ExFreePoolWithTag(Device, TAG_PNP_ROOT);
224 }
225 return Status;
226 }
227
228 static NTSTATUS NTAPI
229 QueryStringCallback(
230 IN PWSTR ValueName,
231 IN ULONG ValueType,
232 IN PVOID ValueData,
233 IN ULONG ValueLength,
234 IN PVOID Context,
235 IN PVOID EntryContext)
236 {
237 PUNICODE_STRING Destination = (PUNICODE_STRING)EntryContext;
238 UNICODE_STRING Source;
239
240 if (ValueType != REG_SZ || ValueLength == 0 || ValueLength % sizeof(WCHAR) != 0)
241 return STATUS_SUCCESS;
242
243 Source.MaximumLength = Source.Length = ValueLength;
244 Source.Buffer = ValueData;
245 if (Source.Length > 0 && Source.Buffer[Source.Length / sizeof(WCHAR) - 1] == UNICODE_NULL)
246 Source.Length -= sizeof(WCHAR);
247 return RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, &Source, Destination);
248 }
249
250 static NTSTATUS NTAPI
251 QueryBinaryValueCallback(
252 IN PWSTR ValueName,
253 IN ULONG ValueType,
254 IN PVOID ValueData,
255 IN ULONG ValueLength,
256 IN PVOID Context,
257 IN PVOID EntryContext)
258 {
259 PBUFFER Buffer = (PBUFFER)EntryContext;
260 PVOID BinaryValue;
261
262 if (ValueLength == 0)
263 {
264 *Buffer->Data = NULL;
265 return STATUS_SUCCESS;
266 }
267
268 BinaryValue = ExAllocatePoolWithTag(PagedPool, ValueLength, TAG_PNP_ROOT);
269 if (BinaryValue == NULL)
270 return STATUS_NO_MEMORY;
271 RtlCopyMemory(BinaryValue, ValueData, ValueLength);
272 *Buffer->Data = BinaryValue;
273 if (Buffer->Length) *Buffer->Length = ValueLength;
274 return STATUS_SUCCESS;
275 }
276
277 static NTSTATUS
278 EnumerateDevices(
279 IN PDEVICE_OBJECT DeviceObject)
280 {
281 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension;
282 PKEY_BASIC_INFORMATION KeyInfo = NULL, SubKeyInfo = NULL;
283 UNICODE_STRING LegacyU = RTL_CONSTANT_STRING(L"LEGACY_");
284 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\" REGSTR_PATH_SYSTEMENUM L"\\" REGSTR_KEY_ROOTENUM);
285 UNICODE_STRING SubKeyName;
286 WCHAR DevicePath[MAX_PATH + 1];
287 RTL_QUERY_REGISTRY_TABLE QueryTable[5];
288 PPNPROOT_DEVICE Device = NULL;
289 HANDLE KeyHandle = INVALID_HANDLE_VALUE;
290 HANDLE SubKeyHandle = INVALID_HANDLE_VALUE;
291 HANDLE DeviceKeyHandle = INVALID_HANDLE_VALUE;
292 ULONG BufferSize;
293 ULONG ResultSize;
294 ULONG Index1, Index2;
295 BUFFER Buffer1, Buffer2;
296 NTSTATUS Status = STATUS_UNSUCCESSFUL;
297
298 DPRINT("EnumerateDevices(FDO %p)\n", DeviceObject);
299
300 DeviceExtension = (PPNPROOT_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
301 KeAcquireGuardedMutex(&DeviceExtension->DeviceListLock);
302
303 BufferSize = sizeof(KEY_BASIC_INFORMATION) + (MAX_PATH + 1) * sizeof(WCHAR);
304 KeyInfo = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_PNP_ROOT);
305 if (!KeyInfo)
306 {
307 DPRINT("ExAllocatePoolWithTag() failed\n");
308 Status = STATUS_NO_MEMORY;
309 goto cleanup;
310 }
311 SubKeyInfo = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_PNP_ROOT);
312 if (!SubKeyInfo)
313 {
314 DPRINT("ExAllocatePoolWithTag() failed\n");
315 Status = STATUS_NO_MEMORY;
316 goto cleanup;
317 }
318
319 Status = IopOpenRegistryKeyEx(&KeyHandle, NULL, &KeyName, KEY_ENUMERATE_SUB_KEYS);
320 if (!NT_SUCCESS(Status))
321 {
322 DPRINT("IopOpenRegistryKeyEx(%wZ) failed with status 0x%08lx\n", &KeyName, Status);
323 goto cleanup;
324 }
325
326 /* Devices are sub-sub-keys of 'KeyName'. KeyName is already opened as
327 * KeyHandle. We'll first do a first enumeration to have first level keys,
328 * and an inner one to have the real devices list.
329 */
330 Index1 = 0;
331 while (TRUE)
332 {
333 Status = ZwEnumerateKey(
334 KeyHandle,
335 Index1,
336 KeyBasicInformation,
337 KeyInfo,
338 BufferSize,
339 &ResultSize);
340 if (Status == STATUS_NO_MORE_ENTRIES)
341 {
342 Status = STATUS_SUCCESS;
343 break;
344 }
345 else if (!NT_SUCCESS(Status))
346 {
347 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
348 goto cleanup;
349 }
350
351 /* Terminate the string */
352 KeyInfo->Name[KeyInfo->NameLength / sizeof(WCHAR)] = 0;
353
354 /* Check if it is a legacy driver */
355 RtlInitUnicodeString(&SubKeyName, KeyInfo->Name);
356 if (RtlPrefixUnicodeString(&LegacyU, &SubKeyName, FALSE))
357 {
358 DPRINT("Ignoring legacy driver '%wZ'\n", &SubKeyName);
359 Index1++;
360 continue;
361 }
362
363 /* Open the key */
364 Status = IopOpenRegistryKeyEx(&SubKeyHandle, KeyHandle, &SubKeyName, KEY_ENUMERATE_SUB_KEYS);
365 if (!NT_SUCCESS(Status))
366 {
367 DPRINT("IopOpenRegistryKeyEx() failed with status 0x%08lx\n", Status);
368 break;
369 }
370
371 /* Enumerate the sub-keys */
372 Index2 = 0;
373 while (TRUE)
374 {
375 Status = ZwEnumerateKey(
376 SubKeyHandle,
377 Index2,
378 KeyBasicInformation,
379 SubKeyInfo,
380 BufferSize,
381 &ResultSize);
382 if (Status == STATUS_NO_MORE_ENTRIES)
383 break;
384 else if (!NT_SUCCESS(Status))
385 {
386 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
387 break;
388 }
389
390 /* Terminate the string */
391 SubKeyInfo->Name[SubKeyInfo->NameLength / sizeof(WCHAR)] = 0;
392
393 _snwprintf(
394 DevicePath,
395 sizeof(DevicePath) / sizeof(WCHAR),
396 L"%s\\%s", REGSTR_KEY_ROOTENUM, KeyInfo->Name);
397 DPRINT("Found device %S\\%s!\n", DevicePath, SubKeyInfo->Name);
398 if (LocateChildDevice(DeviceExtension, DevicePath, SubKeyInfo->Name, &Device) == STATUS_NO_SUCH_DEVICE)
399 {
400 /* Create a PPNPROOT_DEVICE object, and add if in the list of known devices */
401 Device = (PPNPROOT_DEVICE)ExAllocatePoolWithTag(PagedPool, sizeof(PNPROOT_DEVICE), TAG_PNP_ROOT);
402 if (!Device)
403 {
404 DPRINT("ExAllocatePoolWithTag() failed\n");
405 Status = STATUS_NO_MEMORY;
406 goto cleanup;
407 }
408 RtlZeroMemory(Device, sizeof(PNPROOT_DEVICE));
409
410 /* Fill device ID and instance ID */
411 if (!RtlCreateUnicodeString(&Device->DeviceID, DevicePath))
412 {
413 DPRINT("RtlCreateUnicodeString() failed\n");
414 Status = STATUS_NO_MEMORY;
415 goto cleanup;
416 }
417
418 if (!RtlCreateUnicodeString(&Device->InstanceID, SubKeyInfo->Name))
419 {
420 DPRINT("RtlCreateUnicodeString() failed\n");
421 Status = STATUS_NO_MEMORY;
422 goto cleanup;
423 }
424
425 /* Open registry key to fill other informations */
426 Status = IopOpenRegistryKeyEx(&DeviceKeyHandle, SubKeyHandle, &Device->InstanceID, KEY_READ);
427 if (!NT_SUCCESS(Status))
428 {
429 DPRINT("IopOpenRegistryKeyEx() failed with status 0x%08lx\n", Status);
430 break;
431 }
432
433 /* Fill other informations */
434 Buffer1.Data = (PVOID *)&Device->ResourceRequirementsList;
435 Buffer1.Length = NULL;
436 Buffer2.Data = (PVOID *)&Device->ResourceList;
437 Buffer2.Length = &Device->ResourceListSize;
438 RtlZeroMemory(QueryTable, sizeof(QueryTable));
439 QueryTable[0].QueryRoutine = QueryStringCallback;
440 QueryTable[0].Name = L"DeviceDesc";
441 QueryTable[0].EntryContext = &Device->DeviceDescription;
442 QueryTable[1].Flags = RTL_QUERY_REGISTRY_SUBKEY;
443 QueryTable[1].Name = L"LogConf";
444 QueryTable[2].QueryRoutine = QueryBinaryValueCallback;
445 QueryTable[2].Name = L"BasicConfigVector";
446 QueryTable[2].EntryContext = &Buffer1;
447 QueryTable[3].QueryRoutine = QueryBinaryValueCallback;
448 QueryTable[3].Name = L"BootConfig";
449 QueryTable[3].EntryContext = &Buffer2;
450
451 Status = RtlQueryRegistryValues(
452 RTL_REGISTRY_HANDLE,
453 (PCWSTR)DeviceKeyHandle,
454 QueryTable,
455 NULL,
456 NULL);
457 if (!NT_SUCCESS(Status))
458 {
459 DPRINT("RtlQueryRegistryValues() failed with status 0x%08lx\n", Status);
460 break;
461 }
462
463 ZwClose(DeviceKeyHandle);
464 DeviceKeyHandle = INVALID_HANDLE_VALUE;
465
466 /* Insert the newly created device into the list */
467 InsertTailList(
468 &DeviceExtension->DeviceListHead,
469 &Device->ListEntry);
470 DeviceExtension->DeviceListCount++;
471 }
472 Device = NULL;
473
474 Index2++;
475 }
476
477 ZwClose(SubKeyHandle);
478 SubKeyHandle = INVALID_HANDLE_VALUE;
479 Index1++;
480 }
481
482 cleanup:
483 if (Device)
484 {
485 /* We have a device that has not been added to device list. We need to clean it up */
486 /* FIXME */
487 ExFreePoolWithTag(Device, TAG_PNP_ROOT);
488 }
489 if (DeviceKeyHandle != INVALID_HANDLE_VALUE)
490 ZwClose(DeviceKeyHandle);
491 if (SubKeyHandle != INVALID_HANDLE_VALUE)
492 ZwClose(SubKeyHandle);
493 if (KeyHandle != INVALID_HANDLE_VALUE)
494 ZwClose(KeyHandle);
495 ExFreePoolWithTag(KeyInfo, TAG_PNP_ROOT);
496 ExFreePoolWithTag(SubKeyInfo, TAG_PNP_ROOT);
497 KeReleaseGuardedMutex(&DeviceExtension->DeviceListLock);
498 return Status;
499 }
500
501 /* FUNCTION: Handle IRP_MN_QUERY_DEVICE_RELATIONS IRPs for the root bus device object
502 * ARGUMENTS:
503 * DeviceObject = Pointer to functional device object of the root bus driver
504 * Irp = Pointer to IRP that should be handled
505 * RETURNS:
506 * Status
507 */
508 static NTSTATUS
509 PnpRootQueryDeviceRelations(
510 IN PDEVICE_OBJECT DeviceObject,
511 IN PIRP Irp)
512 {
513 PPNPROOT_PDO_DEVICE_EXTENSION PdoDeviceExtension;
514 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension;
515 PDEVICE_RELATIONS Relations = NULL, OtherRelations = (PDEVICE_RELATIONS)Irp->IoStatus.Information;
516 PPNPROOT_DEVICE Device = NULL;
517 ULONG Size;
518 NTSTATUS Status;
519
520 DPRINT("PnpRootQueryDeviceRelations(FDO %p, Irp %p)\n", DeviceObject, Irp);
521
522 Status = EnumerateDevices(DeviceObject);
523 if (!NT_SUCCESS(Status))
524 {
525 DPRINT("EnumerateDevices() failed with status 0x%08lx\n", Status);
526 return Status;
527 }
528
529 DeviceExtension = (PPNPROOT_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
530
531 Size = FIELD_OFFSET(DEVICE_RELATIONS, Objects) + sizeof(PDEVICE_OBJECT) * DeviceExtension->DeviceListCount;
532 if (OtherRelations)
533 {
534 /* Another bus driver has already created a DEVICE_RELATIONS
535 * structure so we must merge this structure with our own */
536
537 Size += sizeof(PDEVICE_OBJECT) * OtherRelations->Count;
538 }
539 Relations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool, Size);
540 if (!Relations)
541 {
542 DPRINT("ExAllocatePoolWithTag() failed\n");
543 Status = STATUS_NO_MEMORY;
544 goto cleanup;
545 }
546 RtlZeroMemory(Relations, Size);
547 if (OtherRelations)
548 {
549 Relations->Count = OtherRelations->Count;
550 RtlCopyMemory(Relations->Objects, OtherRelations->Objects, sizeof(PDEVICE_OBJECT) * OtherRelations->Count);
551 }
552
553 KeAcquireGuardedMutex(&DeviceExtension->DeviceListLock);
554 LIST_FOR_EACH(Device, &DeviceExtension->DeviceListHead, PNPROOT_DEVICE, ListEntry)
555 {
556 if (!Device->Pdo)
557 {
558 /* Create a physical device object for the
559 * device as it does not already have one */
560 Status = IoCreateDevice(
561 DeviceObject->DriverObject,
562 sizeof(PNPROOT_PDO_DEVICE_EXTENSION),
563 NULL,
564 FILE_DEVICE_CONTROLLER,
565 FILE_AUTOGENERATED_DEVICE_NAME,
566 FALSE,
567 &Device->Pdo);
568 if (!NT_SUCCESS(Status))
569 {
570 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status);
571 break;
572 }
573
574 PdoDeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)Device->Pdo->DeviceExtension;
575 RtlZeroMemory(PdoDeviceExtension, sizeof(PNPROOT_PDO_DEVICE_EXTENSION));
576 PdoDeviceExtension->Common.IsFDO = FALSE;
577 PdoDeviceExtension->DeviceInfo = Device;
578
579 Device->Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
580 Device->Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
581 }
582
583 /* Reference the physical device object. The PnP manager
584 will dereference it again when it is no longer needed */
585 ObReferenceObject(Device->Pdo);
586
587 Relations->Objects[Relations->Count++] = Device->Pdo;
588 }
589 KeReleaseGuardedMutex(&DeviceExtension->DeviceListLock);
590
591 Irp->IoStatus.Information = (ULONG_PTR)Relations;
592
593 cleanup:
594 if (!NT_SUCCESS(Status))
595 {
596 if (OtherRelations)
597 ExFreePool(OtherRelations);
598 if (Relations)
599 ExFreePool(Relations);
600 if (Device && Device->Pdo)
601 {
602 IoDeleteDevice(Device->Pdo);
603 Device->Pdo = NULL;
604 }
605 }
606
607 return Status;
608 }
609
610 /*
611 * FUNCTION: Handle Plug and Play IRPs for the root bus device object
612 * ARGUMENTS:
613 * DeviceObject = Pointer to functional device object of the root bus driver
614 * Irp = Pointer to IRP that should be handled
615 * RETURNS:
616 * Status
617 */
618 static NTSTATUS
619 PnpRootFdoPnpControl(
620 IN PDEVICE_OBJECT DeviceObject,
621 IN PIRP Irp)
622 {
623 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension;
624 PIO_STACK_LOCATION IrpSp;
625 NTSTATUS Status;
626
627 DeviceExtension = (PPNPROOT_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
628 Status = Irp->IoStatus.Status;
629 IrpSp = IoGetCurrentIrpStackLocation(Irp);
630
631 switch (IrpSp->MinorFunction)
632 {
633 case IRP_MN_QUERY_DEVICE_RELATIONS:
634 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS\n");
635 Status = PnpRootQueryDeviceRelations(DeviceObject, Irp);
636 break;
637
638 case IRP_MN_START_DEVICE:
639 DPRINT("IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
640 if (!IoForwardIrpSynchronously(DeviceExtension->Ldo, Irp))
641 Status = STATUS_UNSUCCESSFUL;
642 else
643 {
644 Status = Irp->IoStatus.Status;
645 if (NT_SUCCESS(Status))
646 DeviceExtension->State = dsStarted;
647 }
648 break;
649
650 case IRP_MN_STOP_DEVICE:
651 DPRINT("IRP_MJ_PNP / IRP_MN_STOP_DEVICE\n");
652 /* Root device cannot be stopped */
653 Status = STATUS_NOT_SUPPORTED;
654 break;
655
656 default:
657 DPRINT("IRP_MJ_PNP / Unknown minor function 0x%lx\n", IrpSp->MinorFunction);
658 Status = STATUS_NOT_IMPLEMENTED;
659 break;
660 }
661
662 if (Status != STATUS_PENDING)
663 {
664 Irp->IoStatus.Status = Status;
665 IoCompleteRequest(Irp, IO_NO_INCREMENT);
666 }
667
668 return Status;
669 }
670
671 static NTSTATUS
672 PdoQueryDeviceRelations(
673 IN PDEVICE_OBJECT DeviceObject,
674 IN PIRP Irp,
675 IN PIO_STACK_LOCATION IrpSp)
676 {
677 PDEVICE_RELATIONS Relations;
678 DEVICE_RELATION_TYPE RelationType;
679 NTSTATUS Status = Irp->IoStatus.Status;
680
681 RelationType = IrpSp->Parameters.QueryDeviceRelations.Type;
682
683 switch (RelationType)
684 {
685 /* FIXME: remove */
686 case BusRelations:
687 {
688 if (IoGetAttachedDevice(DeviceObject) != DeviceObject)
689 {
690 /* We're not alone in the stack */
691 DPRINT1("PnP is misbehaving ; don't know how to handle IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n");
692 }
693 break;
694 }
695
696 case TargetDeviceRelation:
697 {
698 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / TargetDeviceRelation\n");
699 Relations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool, sizeof(DEVICE_RELATIONS));
700 if (!Relations)
701 {
702 DPRINT("ExAllocatePoolWithTag() failed\n");
703 Status = STATUS_NO_MEMORY;
704 }
705 else
706 {
707 ObReferenceObject(DeviceObject);
708 Relations->Count = 1;
709 Relations->Objects[0] = DeviceObject;
710 Status = STATUS_SUCCESS;
711 Irp->IoStatus.Information = (ULONG_PTR)Relations;
712 }
713 break;
714 }
715
716 default:
717 {
718 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / unknown relation type 0x%lx\n", RelationType);
719 }
720 }
721
722 return Status;
723 }
724
725 static NTSTATUS
726 PdoQueryCapabilities(
727 IN PDEVICE_OBJECT DeviceObject,
728 IN PIRP Irp,
729 IN PIO_STACK_LOCATION IrpSp)
730 {
731 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension;
732 PDEVICE_CAPABILITIES DeviceCapabilities;
733
734 DeviceExtension = (PPNPROOT_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
735 DeviceCapabilities = IrpSp->Parameters.DeviceCapabilities.Capabilities;
736
737 if (DeviceCapabilities->Version != 1)
738 return STATUS_REVISION_MISMATCH;
739
740 DeviceCapabilities->UniqueID = TRUE;
741 /* FIXME: Fill other fields */
742
743 return STATUS_SUCCESS;
744 }
745
746 static NTSTATUS
747 PdoQueryResources(
748 IN PDEVICE_OBJECT DeviceObject,
749 IN PIRP Irp,
750 IN PIO_STACK_LOCATION IrpSp)
751 {
752 PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension;
753 PCM_RESOURCE_LIST ResourceList;
754
755 DeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
756
757 if (DeviceExtension->DeviceInfo->ResourceList == NULL)
758 {
759 /* Create an empty resource list */
760 ResourceList = ExAllocatePool(PagedPool, sizeof(CM_RESOURCE_LIST));
761 if (!ResourceList)
762 return STATUS_NO_MEMORY;
763
764 ResourceList->Count = 0;
765
766 Irp->IoStatus.Information = (ULONG_PTR)ResourceList;
767 }
768 else
769 {
770 /* Copy existing resource requirement list */
771 ResourceList = ExAllocatePool(
772 PagedPool,
773 FIELD_OFFSET(CM_RESOURCE_LIST, List) + DeviceExtension->DeviceInfo->ResourceListSize);
774 if (!ResourceList)
775 return STATUS_NO_MEMORY;
776
777 ResourceList->Count = 1;
778 RtlCopyMemory(
779 &ResourceList->List,
780 DeviceExtension->DeviceInfo->ResourceList,
781 DeviceExtension->DeviceInfo->ResourceListSize);
782 Irp->IoStatus.Information = (ULONG_PTR)ResourceList;
783 }
784
785 return STATUS_SUCCESS;
786 }
787
788 static NTSTATUS
789 PdoQueryResourceRequirements(
790 IN PDEVICE_OBJECT DeviceObject,
791 IN PIRP Irp,
792 IN PIO_STACK_LOCATION IrpSp)
793 {
794 PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension;
795 PIO_RESOURCE_REQUIREMENTS_LIST ResourceList;
796 ULONG ResourceListSize = FIELD_OFFSET(IO_RESOURCE_REQUIREMENTS_LIST, List);
797
798 DeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
799
800 if (DeviceExtension->DeviceInfo->ResourceRequirementsList == NULL)
801 {
802 /* Create an empty resource list */
803 ResourceList = ExAllocatePool(PagedPool, ResourceListSize);
804 if (!ResourceList)
805 return STATUS_NO_MEMORY;
806
807 RtlZeroMemory(ResourceList, ResourceListSize);
808 ResourceList->ListSize = ResourceListSize;
809
810 Irp->IoStatus.Information = (ULONG_PTR)ResourceList;
811 }
812 else
813 {
814 /* Copy existing resource requirement list */
815 ResourceList = ExAllocatePool(PagedPool, DeviceExtension->DeviceInfo->ResourceRequirementsList->ListSize);
816 if (!ResourceList)
817 return STATUS_NO_MEMORY;
818
819 RtlCopyMemory(
820 ResourceList,
821 DeviceExtension->DeviceInfo->ResourceRequirementsList,
822 DeviceExtension->DeviceInfo->ResourceRequirementsList->ListSize);
823 Irp->IoStatus.Information = (ULONG_PTR)ResourceList;
824 }
825
826 return STATUS_SUCCESS;
827 }
828
829 static NTSTATUS
830 PdoQueryDeviceText(
831 IN PDEVICE_OBJECT DeviceObject,
832 IN PIRP Irp,
833 IN PIO_STACK_LOCATION IrpSp)
834 {
835 PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension;
836 DEVICE_TEXT_TYPE DeviceTextType;
837 NTSTATUS Status = Irp->IoStatus.Status;
838
839 DeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
840 DeviceTextType = IrpSp->Parameters.QueryDeviceText.DeviceTextType;
841
842 switch (DeviceTextType)
843 {
844 case DeviceTextDescription:
845 {
846 UNICODE_STRING String;
847 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / DeviceTextDescription\n");
848
849 Status = RtlDuplicateUnicodeString(
850 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
851 &DeviceExtension->DeviceInfo->DeviceDescription,
852 &String);
853 Irp->IoStatus.Information = (ULONG_PTR)String.Buffer;
854 break;
855 }
856
857 case DeviceTextLocationInformation:
858 {
859 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / DeviceTextLocationInformation\n");
860 Status = STATUS_NOT_SUPPORTED;
861 break;
862 }
863
864 default:
865 {
866 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / unknown query id type 0x%lx\n", DeviceTextType);
867 }
868 }
869
870 return Status;
871 }
872
873 static NTSTATUS
874 PdoQueryId(
875 IN PDEVICE_OBJECT DeviceObject,
876 IN PIRP Irp,
877 IN PIO_STACK_LOCATION IrpSp)
878 {
879 PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension;
880 BUS_QUERY_ID_TYPE IdType;
881 NTSTATUS Status = Irp->IoStatus.Status;
882
883 DeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
884 IdType = IrpSp->Parameters.QueryId.IdType;
885
886 switch (IdType)
887 {
888 case BusQueryDeviceID:
889 {
890 UNICODE_STRING String;
891 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryDeviceID\n");
892
893 Status = RtlDuplicateUnicodeString(
894 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
895 &DeviceExtension->DeviceInfo->DeviceID,
896 &String);
897 Irp->IoStatus.Information = (ULONG_PTR)String.Buffer;
898 break;
899 }
900
901 case BusQueryHardwareIDs:
902 case BusQueryCompatibleIDs:
903 {
904 /* Optional, do nothing */
905 break;
906 }
907
908 case BusQueryInstanceID:
909 {
910 UNICODE_STRING String;
911 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryInstanceID\n");
912
913 Status = RtlDuplicateUnicodeString(
914 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
915 &DeviceExtension->DeviceInfo->InstanceID,
916 &String);
917 Irp->IoStatus.Information = (ULONG_PTR)String.Buffer;
918 break;
919 }
920
921 default:
922 {
923 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_ID / unknown query id type 0x%lx\n", IdType);
924 }
925 }
926
927 return Status;
928 }
929
930 static NTSTATUS
931 PdoQueryBusInformation(
932 IN PDEVICE_OBJECT DeviceObject,
933 IN PIRP Irp,
934 IN PIO_STACK_LOCATION IrpSp)
935 {
936 PPNP_BUS_INFORMATION BusInfo;
937 NTSTATUS Status;
938
939 BusInfo = (PPNP_BUS_INFORMATION)ExAllocatePoolWithTag(PagedPool, sizeof(PNP_BUS_INFORMATION), TAG_PNP_ROOT);
940 if (!BusInfo)
941 Status = STATUS_NO_MEMORY;
942 else
943 {
944 RtlCopyMemory(
945 &BusInfo->BusTypeGuid,
946 &GUID_BUS_TYPE_INTERNAL,
947 sizeof(BusInfo->BusTypeGuid));
948 BusInfo->LegacyBusType = PNPBus;
949 /* We're the only root bus enumerator on the computer */
950 BusInfo->BusNumber = 0;
951 Irp->IoStatus.Information = (ULONG_PTR)BusInfo;
952 Status = STATUS_SUCCESS;
953 }
954
955 return Status;
956 }
957
958 /*
959 * FUNCTION: Handle Plug and Play IRPs for the child device
960 * ARGUMENTS:
961 * DeviceObject = Pointer to physical device object of the child device
962 * Irp = Pointer to IRP that should be handled
963 * RETURNS:
964 * Status
965 */
966 static NTSTATUS
967 PnpRootPdoPnpControl(
968 IN PDEVICE_OBJECT DeviceObject,
969 IN PIRP Irp)
970 {
971 PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension;
972 PIO_STACK_LOCATION IrpSp;
973 NTSTATUS Status;
974
975 DeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
976 Status = Irp->IoStatus.Status;
977 IrpSp = IoGetCurrentIrpStackLocation(Irp);
978
979 switch (IrpSp->MinorFunction)
980 {
981 case IRP_MN_START_DEVICE: /* 0x00 */
982 DPRINT("IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
983 Status = STATUS_SUCCESS;
984 break;
985
986 case IRP_MN_QUERY_DEVICE_RELATIONS: /* 0x07 */
987 Status = PdoQueryDeviceRelations(DeviceObject, Irp, IrpSp);
988 break;
989
990 case IRP_MN_QUERY_CAPABILITIES: /* 0x09 */
991 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_CAPABILITIES\n");
992 Status = PdoQueryCapabilities(DeviceObject, Irp, IrpSp);
993 break;
994
995 case IRP_MN_QUERY_RESOURCES: /* 0x0a */
996 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_RESOURCES\n");
997 Status = PdoQueryResources(DeviceObject, Irp, IrpSp);
998 break;
999
1000 case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: /* 0x0b */
1001 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
1002 Status = PdoQueryResourceRequirements(DeviceObject, Irp, IrpSp);
1003 break;
1004
1005 case IRP_MN_QUERY_DEVICE_TEXT: /* 0x0c */
1006 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
1007 Status = PdoQueryDeviceText(DeviceObject, Irp, IrpSp);
1008 break;
1009
1010 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: /* 0x0d */
1011 DPRINT("IRP_MJ_PNP / IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
1012 break;
1013
1014 case IRP_MN_QUERY_ID: /* 0x13 */
1015 Status = PdoQueryId(DeviceObject, Irp, IrpSp);
1016 break;
1017
1018 case IRP_MN_QUERY_BUS_INFORMATION: /* 0x15 */
1019 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_BUS_INFORMATION\n");
1020 Status = PdoQueryBusInformation(DeviceObject, Irp, IrpSp);
1021 break;
1022
1023 default:
1024 DPRINT1("IRP_MJ_PNP / Unknown minor function 0x%lx\n", IrpSp->MinorFunction);
1025 Status = STATUS_NOT_IMPLEMENTED;
1026 break;
1027 }
1028
1029 if (Status != STATUS_PENDING)
1030 {
1031 Irp->IoStatus.Status = Status;
1032 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1033 }
1034
1035 return Status;
1036 }
1037
1038 /*
1039 * FUNCTION: Handle Plug and Play IRPs
1040 * ARGUMENTS:
1041 * DeviceObject = Pointer to PDO or FDO
1042 * Irp = Pointer to IRP that should be handled
1043 * RETURNS:
1044 * Status
1045 */
1046 static NTSTATUS NTAPI
1047 PnpRootPnpControl(
1048 IN PDEVICE_OBJECT DeviceObject,
1049 IN PIRP Irp)
1050 {
1051 PPNPROOT_COMMON_DEVICE_EXTENSION DeviceExtension;
1052 NTSTATUS Status;
1053
1054 DeviceExtension = (PPNPROOT_COMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1055
1056 if (DeviceExtension->IsFDO)
1057 Status = PnpRootFdoPnpControl(DeviceObject, Irp);
1058 else
1059 Status = PnpRootPdoPnpControl(DeviceObject, Irp);
1060
1061 return Status;
1062 }
1063
1064 NTSTATUS
1065 STDCALL
1066 PnpRootAddDevice(
1067 IN PDRIVER_OBJECT DriverObject,
1068 IN PDEVICE_OBJECT PhysicalDeviceObject)
1069 {
1070 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension;
1071 NTSTATUS Status;
1072
1073 DPRINT("PnpRootAddDevice(DriverObject %p, Pdo %p)\n", DriverObject, PhysicalDeviceObject);
1074
1075 if (!PhysicalDeviceObject)
1076 {
1077 DPRINT("PhysicalDeviceObject 0x%p\n", PhysicalDeviceObject);
1078 Status = STATUS_INSUFFICIENT_RESOURCES;
1079 KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
1080 }
1081
1082 Status = IoCreateDevice(
1083 DriverObject,
1084 sizeof(PNPROOT_FDO_DEVICE_EXTENSION),
1085 NULL,
1086 FILE_DEVICE_BUS_EXTENDER,
1087 FILE_DEVICE_SECURE_OPEN,
1088 TRUE,
1089 &PnpRootDeviceObject);
1090 if (!NT_SUCCESS(Status))
1091 {
1092 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status);
1093 KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
1094 }
1095 DPRINT("Created FDO %p\n", PnpRootDeviceObject);
1096
1097 DeviceExtension = (PPNPROOT_FDO_DEVICE_EXTENSION)PnpRootDeviceObject->DeviceExtension;
1098 RtlZeroMemory(DeviceExtension, sizeof(PNPROOT_FDO_DEVICE_EXTENSION));
1099
1100 DeviceExtension->Common.IsFDO = TRUE;
1101 DeviceExtension->State = dsStopped;
1102 InitializeListHead(&DeviceExtension->DeviceListHead);
1103 DeviceExtension->DeviceListCount = 0;
1104 KeInitializeGuardedMutex(&DeviceExtension->DeviceListLock);
1105
1106 Status = IoAttachDeviceToDeviceStackSafe(
1107 PnpRootDeviceObject,
1108 PhysicalDeviceObject,
1109 &DeviceExtension->Ldo);
1110 if (!NT_SUCCESS(Status))
1111 {
1112 DPRINT("IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status);
1113 KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
1114 }
1115
1116 PnpRootDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
1117
1118 DPRINT("Done AddDevice()\n");
1119
1120 return STATUS_SUCCESS;
1121 }
1122
1123 NTSTATUS NTAPI
1124 PnpRootDriverEntry(
1125 IN PDRIVER_OBJECT DriverObject,
1126 IN PUNICODE_STRING RegistryPath)
1127 {
1128 DPRINT("PnpRootDriverEntry(%p %wZ)\n", DriverObject, RegistryPath);
1129
1130 DriverObject->DriverExtension->AddDevice = PnpRootAddDevice;
1131
1132 DriverObject->MajorFunction[IRP_MJ_PNP] = PnpRootPnpControl;
1133 //DriverObject->MajorFunction[IRP_MJ_POWER] = PnpRootPowerControl;
1134
1135 return STATUS_SUCCESS;
1136 }