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