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