xref: /reactos/drivers/bus/pcix/fdo.c (revision c2c66aff)
1 /*
2  * PROJECT:         ReactOS PCI Bus Driver
3  * LICENSE:         BSD - See COPYING.ARM in the top level directory
4  * FILE:            drivers/bus/pci/fdo.c
5  * PURPOSE:         FDO Device Management
6  * PROGRAMMERS:     ReactOS Portable Systems Group
7  */
8 
9 /* INCLUDES *******************************************************************/
10 
11 #include <pci.h>
12 
13 #define NDEBUG
14 #include <debug.h>
15 
16 /* GLOBALS ********************************************************************/
17 
18 SINGLE_LIST_ENTRY PciFdoExtensionListHead;
19 BOOLEAN PciBreakOnDefault;
20 
21 PCI_MN_DISPATCH_TABLE PciFdoDispatchPowerTable[] =
22 {
23     {IRP_DISPATCH, (PCI_DISPATCH_FUNCTION)PciFdoWaitWake},
24     {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
25     {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciFdoSetPowerState},
26     {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciFdoIrpQueryPower},
27     {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported}
28 };
29 
30 PCI_MN_DISPATCH_TABLE PciFdoDispatchPnpTable[] =
31 {
32     {IRP_UPWARD,   (PCI_DISPATCH_FUNCTION)PciFdoIrpStartDevice},
33     {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciFdoIrpQueryRemoveDevice},
34     {IRP_DISPATCH, (PCI_DISPATCH_FUNCTION)PciFdoIrpRemoveDevice},
35     {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciFdoIrpCancelRemoveDevice},
36     {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciFdoIrpStopDevice},
37     {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciFdoIrpQueryStopDevice},
38     {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciFdoIrpCancelStopDevice},
39     {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciFdoIrpQueryDeviceRelations},
40     {IRP_DISPATCH, (PCI_DISPATCH_FUNCTION)PciFdoIrpQueryInterface},
41     {IRP_UPWARD,   (PCI_DISPATCH_FUNCTION)PciFdoIrpQueryCapabilities},
42     {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
43     {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
44     {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
45     {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
46     {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
47     {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
48     {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
49     {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
50     {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
51     {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
52     {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
53     {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
54     {IRP_UPWARD,   (PCI_DISPATCH_FUNCTION)PciFdoIrpDeviceUsageNotification},
55     {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciFdoIrpSurpriseRemoval},
56     {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciFdoIrpQueryLegacyBusInformation},
57     {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported}
58 };
59 
60 PCI_MJ_DISPATCH_TABLE PciFdoDispatchTable =
61 {
62     IRP_MN_QUERY_LEGACY_BUS_INFORMATION,
63     PciFdoDispatchPnpTable,
64     IRP_MN_QUERY_POWER,
65     PciFdoDispatchPowerTable,
66     IRP_DOWNWARD,
67     (PCI_DISPATCH_FUNCTION)PciIrpNotSupported,
68     IRP_DOWNWARD,
69     (PCI_DISPATCH_FUNCTION)PciIrpNotSupported
70 };
71 
72 /* FUNCTIONS ******************************************************************/
73 
74 NTSTATUS
75 NTAPI
PciFdoIrpStartDevice(IN PIRP Irp,IN PIO_STACK_LOCATION IoStackLocation,IN PPCI_FDO_EXTENSION DeviceExtension)76 PciFdoIrpStartDevice(IN PIRP Irp,
77                      IN PIO_STACK_LOCATION IoStackLocation,
78                      IN PPCI_FDO_EXTENSION DeviceExtension)
79 {
80     NTSTATUS Status;
81     PCM_RESOURCE_LIST Resources;
82     PAGED_CODE();
83 
84     /* The device stack must be starting the FDO in a success path */
85     if (!NT_SUCCESS(Irp->IoStatus.Status)) return STATUS_NOT_SUPPORTED;
86 
87     /* Attempt to switch the state machine to the started state */
88     Status = PciBeginStateTransition(DeviceExtension, PciStarted);
89     if (!NT_SUCCESS(Status)) return Status;
90 
91     /* Check for any boot-provided resources */
92     Resources = IoStackLocation->Parameters.StartDevice.AllocatedResources;
93     if ((Resources) && !(PCI_IS_ROOT_FDO(DeviceExtension)))
94     {
95         /* These resources would only be for non-root FDOs, unhandled for now */
96         ASSERT(Resources->Count == 1);
97         UNIMPLEMENTED_DBGBREAK();
98     }
99 
100     /* Initialize the arbiter for this FDO */
101     Status = PciInitializeArbiterRanges(DeviceExtension, Resources);
102     if (!NT_SUCCESS(Status))
103     {
104         /* Cancel the transition if this failed */
105         PciCancelStateTransition(DeviceExtension, PciStarted);
106         return Status;
107     }
108 
109     /* Again, check for boot-provided resources for non-root FDO */
110     if ((Resources) && !(PCI_IS_ROOT_FDO(DeviceExtension)))
111     {
112         /* Unhandled for now */
113         ASSERT(Resources->Count == 1);
114         UNIMPLEMENTED_DBGBREAK();
115     }
116 
117     /* Commit the transition to the started state */
118     PciCommitStateTransition(DeviceExtension, PciStarted);
119     return STATUS_SUCCESS;
120 }
121 
122 NTSTATUS
123 NTAPI
PciFdoIrpQueryRemoveDevice(IN PIRP Irp,IN PIO_STACK_LOCATION IoStackLocation,IN PPCI_FDO_EXTENSION DeviceExtension)124 PciFdoIrpQueryRemoveDevice(IN PIRP Irp,
125                            IN PIO_STACK_LOCATION IoStackLocation,
126                            IN PPCI_FDO_EXTENSION DeviceExtension)
127 {
128     UNREFERENCED_PARAMETER(Irp);
129     UNREFERENCED_PARAMETER(IoStackLocation);
130     UNREFERENCED_PARAMETER(DeviceExtension);
131 
132     UNIMPLEMENTED;
133     return STATUS_NOT_SUPPORTED;
134 }
135 
136 NTSTATUS
137 NTAPI
PciFdoIrpRemoveDevice(IN PIRP Irp,IN PIO_STACK_LOCATION IoStackLocation,IN PPCI_FDO_EXTENSION DeviceExtension)138 PciFdoIrpRemoveDevice(IN PIRP Irp,
139                       IN PIO_STACK_LOCATION IoStackLocation,
140                       IN PPCI_FDO_EXTENSION DeviceExtension)
141 {
142     UNREFERENCED_PARAMETER(Irp);
143     UNREFERENCED_PARAMETER(IoStackLocation);
144     UNREFERENCED_PARAMETER(DeviceExtension);
145 
146     UNIMPLEMENTED_DBGBREAK();
147     return STATUS_NOT_SUPPORTED;
148 }
149 
150 NTSTATUS
151 NTAPI
PciFdoIrpCancelRemoveDevice(IN PIRP Irp,IN PIO_STACK_LOCATION IoStackLocation,IN PPCI_FDO_EXTENSION DeviceExtension)152 PciFdoIrpCancelRemoveDevice(IN PIRP Irp,
153                             IN PIO_STACK_LOCATION IoStackLocation,
154                             IN PPCI_FDO_EXTENSION DeviceExtension)
155 {
156     UNREFERENCED_PARAMETER(Irp);
157     UNREFERENCED_PARAMETER(IoStackLocation);
158     UNREFERENCED_PARAMETER(DeviceExtension);
159 
160     UNIMPLEMENTED_DBGBREAK();
161     return STATUS_NOT_SUPPORTED;
162 }
163 
164 NTSTATUS
165 NTAPI
PciFdoIrpStopDevice(IN PIRP Irp,IN PIO_STACK_LOCATION IoStackLocation,IN PPCI_FDO_EXTENSION DeviceExtension)166 PciFdoIrpStopDevice(IN PIRP Irp,
167                     IN PIO_STACK_LOCATION IoStackLocation,
168                     IN PPCI_FDO_EXTENSION DeviceExtension)
169 {
170     UNREFERENCED_PARAMETER(Irp);
171     UNREFERENCED_PARAMETER(IoStackLocation);
172     UNREFERENCED_PARAMETER(DeviceExtension);
173 
174     UNIMPLEMENTED_DBGBREAK();
175     return STATUS_NOT_SUPPORTED;
176 }
177 
178 NTSTATUS
179 NTAPI
PciFdoIrpQueryStopDevice(IN PIRP Irp,IN PIO_STACK_LOCATION IoStackLocation,IN PPCI_FDO_EXTENSION DeviceExtension)180 PciFdoIrpQueryStopDevice(IN PIRP Irp,
181                          IN PIO_STACK_LOCATION IoStackLocation,
182                          IN PPCI_FDO_EXTENSION DeviceExtension)
183 {
184     UNREFERENCED_PARAMETER(Irp);
185     UNREFERENCED_PARAMETER(IoStackLocation);
186     UNREFERENCED_PARAMETER(DeviceExtension);
187 
188     UNIMPLEMENTED_DBGBREAK();
189     return STATUS_NOT_SUPPORTED;
190 }
191 
192 NTSTATUS
193 NTAPI
PciFdoIrpCancelStopDevice(IN PIRP Irp,IN PIO_STACK_LOCATION IoStackLocation,IN PPCI_FDO_EXTENSION DeviceExtension)194 PciFdoIrpCancelStopDevice(IN PIRP Irp,
195                           IN PIO_STACK_LOCATION IoStackLocation,
196                           IN PPCI_FDO_EXTENSION DeviceExtension)
197 {
198     UNREFERENCED_PARAMETER(Irp);
199     UNREFERENCED_PARAMETER(IoStackLocation);
200     UNREFERENCED_PARAMETER(DeviceExtension);
201 
202     UNIMPLEMENTED_DBGBREAK();
203     return STATUS_NOT_SUPPORTED;
204 }
205 
206 NTSTATUS
207 NTAPI
PciFdoIrpQueryDeviceRelations(IN PIRP Irp,IN PIO_STACK_LOCATION IoStackLocation,IN PPCI_FDO_EXTENSION DeviceExtension)208 PciFdoIrpQueryDeviceRelations(IN PIRP Irp,
209                               IN PIO_STACK_LOCATION IoStackLocation,
210                               IN PPCI_FDO_EXTENSION DeviceExtension)
211 {
212     NTSTATUS Status;
213     PAGED_CODE();
214 
215     /* Are bus relations being queried? */
216     if (IoStackLocation->Parameters.QueryDeviceRelations.Type != BusRelations)
217     {
218         /* The FDO is a bus, so only bus relations can be obtained */
219         Status = STATUS_NOT_SUPPORTED;
220     }
221     else
222     {
223         /* Scan the PCI bus and build the device relations for the caller */
224         Status = PciQueryDeviceRelations(DeviceExtension,
225                                          (PDEVICE_RELATIONS*)
226                                          &Irp->IoStatus.Information);
227     }
228 
229     /* Return the enumeration status back */
230     return Status;
231 }
232 
233 NTSTATUS
234 NTAPI
PciFdoIrpQueryInterface(IN PIRP Irp,IN PIO_STACK_LOCATION IoStackLocation,IN PPCI_FDO_EXTENSION DeviceExtension)235 PciFdoIrpQueryInterface(IN PIRP Irp,
236                         IN PIO_STACK_LOCATION IoStackLocation,
237                         IN PPCI_FDO_EXTENSION DeviceExtension)
238 {
239     NTSTATUS Status;
240     PAGED_CODE();
241     ASSERT(DeviceExtension->ExtensionType == PciFdoExtensionType);
242 
243     /* Deleted extensions don't respond to IRPs */
244     if (DeviceExtension->DeviceState == PciDeleted)
245     {
246         /* Hand it back to try to deal with it */
247         return PciPassIrpFromFdoToPdo(DeviceExtension, Irp);
248     }
249 
250     /* Query our driver for this interface */
251     Status = PciQueryInterface(DeviceExtension,
252                                IoStackLocation->Parameters.QueryInterface.
253                                InterfaceType,
254                                IoStackLocation->Parameters.QueryInterface.
255                                Size,
256                                IoStackLocation->Parameters.QueryInterface.
257                                Version,
258                                IoStackLocation->Parameters.QueryInterface.
259                                InterfaceSpecificData,
260                                IoStackLocation->Parameters.QueryInterface.
261                                Interface,
262                                FALSE);
263     if (NT_SUCCESS(Status))
264     {
265         /* We found it, let the PDO handle it */
266         Irp->IoStatus.Status = Status;
267         return PciPassIrpFromFdoToPdo(DeviceExtension, Irp);
268     }
269     else if (Status == STATUS_NOT_SUPPORTED)
270     {
271         /* Otherwise, we can't handle it, let someone else down the stack try */
272         Status = PciCallDownIrpStack(DeviceExtension, Irp);
273         if (Status == STATUS_NOT_SUPPORTED)
274         {
275             /* They can't either, try a last-resort interface lookup */
276             Status = PciQueryInterface(DeviceExtension,
277                                        IoStackLocation->Parameters.QueryInterface.
278                                        InterfaceType,
279                                        IoStackLocation->Parameters.QueryInterface.
280                                        Size,
281                                        IoStackLocation->Parameters.QueryInterface.
282                                        Version,
283                                        IoStackLocation->Parameters.QueryInterface.
284                                        InterfaceSpecificData,
285                                        IoStackLocation->Parameters.QueryInterface.
286                                        Interface,
287                                        TRUE);
288         }
289     }
290 
291     /* Has anyone claimed this interface yet? */
292     if (Status == STATUS_NOT_SUPPORTED)
293     {
294         /* No, return the original IRP status */
295         Status = Irp->IoStatus.Status;
296     }
297     else
298     {
299         /* Yes, set the new IRP status */
300         Irp->IoStatus.Status = Status;
301     }
302 
303     /* Complete this IRP */
304     IoCompleteRequest(Irp, IO_NO_INCREMENT);
305     return Status;
306 }
307 
308 NTSTATUS
309 NTAPI
PciFdoIrpQueryCapabilities(IN PIRP Irp,IN PIO_STACK_LOCATION IoStackLocation,IN PPCI_FDO_EXTENSION DeviceExtension)310 PciFdoIrpQueryCapabilities(IN PIRP Irp,
311                            IN PIO_STACK_LOCATION IoStackLocation,
312                            IN PPCI_FDO_EXTENSION DeviceExtension)
313 {
314     PDEVICE_CAPABILITIES Capabilities;
315     PAGED_CODE();
316     ASSERT_FDO(DeviceExtension);
317 
318     UNREFERENCED_PARAMETER(Irp);
319 
320     /* Get the capabilities */
321     Capabilities = IoStackLocation->Parameters.DeviceCapabilities.Capabilities;
322 
323     /* Inherit wake levels and power mappings from the higher-up capabilities */
324     DeviceExtension->PowerState.SystemWakeLevel = Capabilities->SystemWake;
325     DeviceExtension->PowerState.DeviceWakeLevel = Capabilities->DeviceWake;
326     RtlCopyMemory(DeviceExtension->PowerState.SystemStateMapping,
327                   Capabilities->DeviceState,
328                   sizeof(DeviceExtension->PowerState.SystemStateMapping));
329 
330     /* Dump the capabilities and return success */
331     PciDebugDumpQueryCapabilities(Capabilities);
332     return STATUS_SUCCESS;
333 }
334 
335 NTSTATUS
336 NTAPI
PciFdoIrpDeviceUsageNotification(IN PIRP Irp,IN PIO_STACK_LOCATION IoStackLocation,IN PPCI_FDO_EXTENSION DeviceExtension)337 PciFdoIrpDeviceUsageNotification(IN PIRP Irp,
338                                  IN PIO_STACK_LOCATION IoStackLocation,
339                                  IN PPCI_FDO_EXTENSION DeviceExtension)
340 {
341     UNREFERENCED_PARAMETER(Irp);
342     UNREFERENCED_PARAMETER(IoStackLocation);
343     UNREFERENCED_PARAMETER(DeviceExtension);
344 
345     UNIMPLEMENTED_DBGBREAK();
346     return STATUS_NOT_SUPPORTED;
347 }
348 
349 NTSTATUS
350 NTAPI
PciFdoIrpSurpriseRemoval(IN PIRP Irp,IN PIO_STACK_LOCATION IoStackLocation,IN PPCI_FDO_EXTENSION DeviceExtension)351 PciFdoIrpSurpriseRemoval(IN PIRP Irp,
352                          IN PIO_STACK_LOCATION IoStackLocation,
353                          IN PPCI_FDO_EXTENSION DeviceExtension)
354 {
355     UNREFERENCED_PARAMETER(Irp);
356     UNREFERENCED_PARAMETER(IoStackLocation);
357     UNREFERENCED_PARAMETER(DeviceExtension);
358 
359     UNIMPLEMENTED_DBGBREAK();
360     return STATUS_NOT_SUPPORTED;
361 }
362 
363 NTSTATUS
364 NTAPI
PciFdoIrpQueryLegacyBusInformation(IN PIRP Irp,IN PIO_STACK_LOCATION IoStackLocation,IN PPCI_FDO_EXTENSION DeviceExtension)365 PciFdoIrpQueryLegacyBusInformation(IN PIRP Irp,
366                                    IN PIO_STACK_LOCATION IoStackLocation,
367                                    IN PPCI_FDO_EXTENSION DeviceExtension)
368 {
369     UNREFERENCED_PARAMETER(Irp);
370     UNREFERENCED_PARAMETER(IoStackLocation);
371     UNREFERENCED_PARAMETER(DeviceExtension);
372 
373     UNIMPLEMENTED_DBGBREAK();
374     return STATUS_NOT_SUPPORTED;
375 }
376 
377 VOID
378 NTAPI
PciGetHotPlugParameters(IN PPCI_FDO_EXTENSION FdoExtension)379 PciGetHotPlugParameters(IN PPCI_FDO_EXTENSION FdoExtension)
380 {
381     ACPI_EVAL_INPUT_BUFFER InputBuffer;
382     PACPI_EVAL_OUTPUT_BUFFER OutputBuffer;
383     ULONG Length;
384     NTSTATUS Status;
385     PAGED_CODE();
386 
387     /* We should receive 4 parameters, per the HPP specification */
388     Length = sizeof(ACPI_EVAL_OUTPUT_BUFFER) + 4 * sizeof(ACPI_METHOD_ARGUMENT);
389 
390     /* Allocate the buffer to hold the parameters */
391     OutputBuffer = ExAllocatePoolWithTag(PagedPool, Length, PCI_POOL_TAG);
392     if (!OutputBuffer) return;
393 
394     /* Initialize the output and input buffers. The method is _HPP */
395     RtlZeroMemory(OutputBuffer, Length);
396     *(PULONG)InputBuffer.MethodName = 'PPH_';
397     InputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE;
398     do
399     {
400         /* Send the IOCTL to the ACPI driver */
401         Status = PciSendIoctl(FdoExtension->PhysicalDeviceObject,
402                               IOCTL_ACPI_EVAL_METHOD,
403                               &InputBuffer,
404                               sizeof(InputBuffer),
405                               OutputBuffer,
406                               Length);
407         if (!NT_SUCCESS(Status))
408         {
409             /* The method failed, check if we can salvage data from parent */
410             if (!PCI_IS_ROOT_FDO(FdoExtension))
411             {
412                 /* Copy the root bus' hot plug parameters */
413                 FdoExtension->HotPlugParameters = FdoExtension->ParentFdoExtension->HotPlugParameters;
414             }
415 
416             /* Nothing more to do on this path */
417             break;
418         }
419 
420         /* ACPI sent back some data. 4 parameters are expected in the output */
421         if (OutputBuffer->Count != 4) break;
422 
423         /* HotPlug PCI Support not yet implemented */
424         UNIMPLEMENTED_DBGBREAK();
425     } while (FALSE);
426 
427     /* Free the buffer and return */
428     ExFreePoolWithTag(OutputBuffer, 0);
429 }
430 
431 VOID
432 NTAPI
PciInitializeFdoExtensionCommonFields(PPCI_FDO_EXTENSION FdoExtension,IN PDEVICE_OBJECT DeviceObject,IN PDEVICE_OBJECT PhysicalDeviceObject)433 PciInitializeFdoExtensionCommonFields(PPCI_FDO_EXTENSION FdoExtension,
434                                       IN PDEVICE_OBJECT DeviceObject,
435                                       IN PDEVICE_OBJECT PhysicalDeviceObject)
436 {
437     /* Initialize the extension */
438     RtlZeroMemory(FdoExtension, sizeof(PCI_FDO_EXTENSION));
439 
440     /* Setup the common fields */
441     FdoExtension->PhysicalDeviceObject = PhysicalDeviceObject;
442     FdoExtension->FunctionalDeviceObject = DeviceObject;
443     FdoExtension->ExtensionType = PciFdoExtensionType;
444     FdoExtension->PowerState.CurrentSystemState = PowerSystemWorking;
445     FdoExtension->PowerState.CurrentDeviceState = PowerDeviceD0;
446     FdoExtension->IrpDispatchTable = &PciFdoDispatchTable;
447 
448     /* Initialize the extension locks */
449     KeInitializeEvent(&FdoExtension->SecondaryExtLock, SynchronizationEvent, TRUE);
450     KeInitializeEvent(&FdoExtension->ChildListLock, SynchronizationEvent, TRUE);
451 
452     /* Initialize the default state */
453     PciInitializeState(FdoExtension);
454 }
455 
456 NTSTATUS
457 NTAPI
PciAddDevice(IN PDRIVER_OBJECT DriverObject,IN PDEVICE_OBJECT PhysicalDeviceObject)458 PciAddDevice(IN PDRIVER_OBJECT DriverObject,
459              IN PDEVICE_OBJECT PhysicalDeviceObject)
460 {
461     PCM_RESOURCE_LIST Descriptor;
462     PDEVICE_OBJECT AttachedTo;
463     PPCI_FDO_EXTENSION FdoExtension;
464     PPCI_FDO_EXTENSION ParentExtension;
465     PPCI_PDO_EXTENSION PdoExtension;
466     PDEVICE_OBJECT DeviceObject;
467     UCHAR Buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)];
468     PKEY_VALUE_PARTIAL_INFORMATION ValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)Buffer;
469     NTSTATUS Status;
470     HANDLE KeyHandle;
471     UNICODE_STRING ValueName;
472     ULONG ResultLength;
473     PAGED_CODE();
474     DPRINT1("PCI - AddDevice (a new bus). PDO: %p (Driver: %wZ)\n",
475             PhysicalDeviceObject, &PhysicalDeviceObject->DriverObject->DriverName);
476 
477     /* Zero out variables so failure path knows what to do */
478     AttachedTo = NULL;
479     FdoExtension = NULL;
480     PdoExtension = NULL;
481     DeviceObject = NULL;
482 
483     do
484     {
485         /* Check if there's already a device extension for this bus */
486         ParentExtension = PciFindParentPciFdoExtension(PhysicalDeviceObject,
487                                                        &PciGlobalLock);
488         if (ParentExtension)
489         {
490             /* Make sure we find a real PDO */
491             PdoExtension = PhysicalDeviceObject->DeviceExtension;
492             ASSERT_PDO(PdoExtension);
493 
494             /* Make sure it's a PCI-to-PCI bridge */
495             if ((PdoExtension->BaseClass != PCI_CLASS_BRIDGE_DEV) ||
496                 (PdoExtension->SubClass != PCI_SUBCLASS_BR_PCI_TO_PCI))
497             {
498                 /* This should never happen */
499                 DPRINT1("PCI - PciAddDevice for Non-Root/Non-PCI-PCI bridge,\n"
500                         "      Class %02x, SubClass %02x, will not add.\n",
501                         PdoExtension->BaseClass,
502                         PdoExtension->SubClass);
503                 ASSERT((PdoExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
504                        (PdoExtension->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI));
505 
506                 /* Enter the failure path */
507                 Status = STATUS_INVALID_DEVICE_REQUEST;
508                 break;
509             }
510 
511             /* Subordinate bus on the bridge */
512             DPRINT1("PCI - AddDevice (new bus is child of bus 0x%x).\n",
513                     ParentExtension->BaseBus);
514 
515             /* Make sure PCI bus numbers are configured */
516             if (!PciAreBusNumbersConfigured(PdoExtension))
517             {
518                 /* This is a critical failure */
519                 DPRINT1("PCI - Bus numbers not configured for bridge (0x%x.0x%x.0x%x)\n",
520                         ParentExtension->BaseBus,
521                         PdoExtension->Slot.u.bits.DeviceNumber,
522                         PdoExtension->Slot.u.bits.FunctionNumber);
523 
524                 /* Enter the failure path */
525                 Status = STATUS_INVALID_DEVICE_REQUEST;
526                 break;
527             }
528         }
529 
530         /* Create the FDO for the bus */
531         Status = IoCreateDevice(DriverObject,
532                                 sizeof(PCI_FDO_EXTENSION),
533                                 NULL,
534                                 FILE_DEVICE_BUS_EXTENDER,
535                                 0,
536                                 0,
537                                 &DeviceObject);
538         if (!NT_SUCCESS(Status)) break;
539 
540         /* Initialize the extension for the FDO */
541         FdoExtension = DeviceObject->DeviceExtension;
542         PciInitializeFdoExtensionCommonFields(DeviceObject->DeviceExtension,
543                                               DeviceObject,
544                                               PhysicalDeviceObject);
545 
546         /* Attach to the root PDO */
547         Status = STATUS_NO_SUCH_DEVICE;
548         AttachedTo = IoAttachDeviceToDeviceStack(DeviceObject,
549                                                  PhysicalDeviceObject);
550         ASSERT(AttachedTo != NULL);
551         if (!AttachedTo) break;
552         FdoExtension->AttachedDeviceObject = AttachedTo;
553 
554         /* Check if this is a child bus, or the root */
555         if (ParentExtension)
556         {
557             /* The child inherits root data */
558             FdoExtension->BaseBus = PdoExtension->Dependent.type1.SecondaryBus;
559             FdoExtension->BusRootFdoExtension = ParentExtension->BusRootFdoExtension;
560             PdoExtension->BridgeFdoExtension = FdoExtension;
561             FdoExtension->ParentFdoExtension = ParentExtension;
562         }
563         else
564         {
565             /* Query the boot configuration */
566             Status = PciGetDeviceProperty(PhysicalDeviceObject,
567                                           DevicePropertyBootConfiguration,
568                                           (PVOID*)&Descriptor);
569             if (!NT_SUCCESS(Status))
570             {
571                 /* No configuration has been set */
572                 Descriptor = NULL;
573             }
574             else
575             {
576                 /* Root PDO in ReactOS does not assign boot resources */
577                 UNIMPLEMENTED_DBGBREAK("Encountered during setup\n");
578                 Descriptor = NULL;
579             }
580 
581             if (Descriptor)
582             {
583                 /* Root PDO in ReactOS does not assign boot resources */
584                 UNIMPLEMENTED_DBGBREAK();
585             }
586             else
587             {
588                 /* Default configuration isn't the normal path on Windows */
589                 if (PciBreakOnDefault)
590                 {
591                     /* If a second bus is found and there's still no data, crash */
592                     KeBugCheckEx(PCI_BUS_DRIVER_INTERNAL,
593                                  0xDEAD0010u,
594                                  (ULONG_PTR)DeviceObject,
595                                  0,
596                                  0);
597                 }
598 
599                 /* Warn that a default configuration will be used, and set bus 0 */
600                 DPRINT1("PCI   Will use default configuration.\n");
601                 PciBreakOnDefault = TRUE;
602                 FdoExtension->BaseBus = 0;
603             }
604 
605             /* This is the root bus */
606             FdoExtension->BusRootFdoExtension = FdoExtension;
607         }
608 
609         /* Get the HAL or ACPI Bus Handler Callbacks for Configuration Access */
610         Status = PciGetConfigHandlers(FdoExtension);
611         if (!NT_SUCCESS(Status)) break;
612 
613         /* Initialize all the supported PCI arbiters */
614         Status = PciInitializeArbiters(FdoExtension);
615         if (!NT_SUCCESS(Status)) break;
616 
617         /* This is a real FDO, insert it into the list */
618         FdoExtension->Fake = FALSE;
619         PciInsertEntryAtTail(&PciFdoExtensionListHead,
620                              FdoExtension,
621                              &PciGlobalLock);
622 
623         /* Open the device registry key so that we can query the errata flags */
624         IoOpenDeviceRegistryKey(DeviceObject,
625                                 PLUGPLAY_REGKEY_DEVICE,
626                                 KEY_ALL_ACCESS,
627                                 &KeyHandle),
628 
629         /* Open the value that contains errata flags for this bus instance */
630         RtlInitUnicodeString(&ValueName, L"HackFlags");
631         Status = ZwQueryValueKey(KeyHandle,
632                                  &ValueName,
633                                  KeyValuePartialInformation,
634                                  ValueInfo,
635                                  sizeof(Buffer),
636                                  &ResultLength);
637         ZwClose(KeyHandle);
638         if (NT_SUCCESS(Status))
639         {
640             /* Make sure the data is of expected type and size */
641             if ((ValueInfo->Type == REG_DWORD) &&
642                 (ValueInfo->DataLength == sizeof(ULONG)))
643             {
644                 /* Read the flags for this bus */
645                 FdoExtension->BusHackFlags = *(PULONG)&ValueInfo->Data;
646             }
647         }
648 
649         /* Query ACPI for PCI HotPlug Support */
650         PciGetHotPlugParameters(FdoExtension);
651 
652         /* The Bus FDO is now initialized */
653         DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
654         return STATUS_SUCCESS;
655     } while (FALSE);
656 
657     /* This is the failure path */
658     ASSERT(!NT_SUCCESS(Status));
659 
660     /* Check if the FDO extension exists */
661     if (FdoExtension) DPRINT1("Should destroy secondaries\n");
662 
663     /* Delete device objects */
664     if (AttachedTo) IoDetachDevice(AttachedTo);
665     if (DeviceObject) IoDeleteDevice(DeviceObject);
666     return Status;
667 }
668 
669 /* EOF */
670