return !(HackFlags & PCI_HACK_NO_PM_CAPS);
}
+PCI_DEVICE_TYPES
+NTAPI
+PciClassifyDeviceType(IN PPCI_PDO_EXTENSION PdoExtension)
+{
+ ASSERT(PdoExtension->ExtensionType == PciPdoExtensionType);
+
+ /* Differenriate between devices and bridges */
+ if (PdoExtension->BaseClass != PCI_CLASS_BRIDGE_DEV) return PciTypeDevice;
+
+ /* The PCI Bus driver handles only CardBus and PCI bridges (plus host) */
+ if (PdoExtension->SubClass == PCI_SUBCLASS_BR_HOST) return PciTypeHostBridge;
+ if (PdoExtension->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI) return PciTypePciBridge;
+ if (PdoExtension->SubClass == PCI_SUBCLASS_BR_CARDBUS) return PciTypeCardbusBridge;
+
+ /* Any other kind of bridge is treated like a device */
+ return PciTypeDevice;
+}
+
ULONG_PTR
NTAPI
PciExecuteCriticalSystemRoutine(IN ULONG_PTR IpiContext)
return FoundSlot;
}
+ULONG
+NTAPI
+PciGetLengthFromBar(IN ULONG Bar)
+{
+ ULONG Length;
+
+ /* I/O addresses vs. memory addresses start differently due to alignment */
+ Length = 1 << ((Bar & PCI_ADDRESS_IO_SPACE) ? 2 : 4);
+
+ /* Keep going until a set bit */
+ while (!(Length & Bar) && (Length)) Length <<= 1;
+
+ /* Return the length (might be 0 on 64-bit because it's the low-word) */
+ if ((Bar & PCI_ADDRESS_MEMORY_TYPE_MASK) != PCI_TYPE_64BIT) ASSERT(Length);
+ return Length;
+}
+
+BOOLEAN
+NTAPI
+PciCreateIoDescriptorFromBarLimit(PIO_RESOURCE_DESCRIPTOR ResourceDescriptor,
+ IN PULONG BarArray,
+ IN BOOLEAN Rom)
+{
+ ULONG CurrentBar, BarLength, BarMask;
+ BOOLEAN Is64BitBar = FALSE;
+
+ /* Check if the BAR is nor I/O nor memory */
+ CurrentBar = BarArray[0];
+ if (!(CurrentBar & ~PCI_ADDRESS_IO_SPACE))
+ {
+ /* Fail this descriptor */
+ ResourceDescriptor->Type = CmResourceTypeNull;
+ return FALSE;
+ }
+
+ /* Set default flag and clear high words */
+ ResourceDescriptor->Flags = 0;
+ ResourceDescriptor->u.Generic.MaximumAddress.HighPart = 0;
+ ResourceDescriptor->u.Generic.MinimumAddress.LowPart = 0;
+ ResourceDescriptor->u.Generic.MinimumAddress.HighPart = 0;
+
+ /* Check for ROM Address */
+ if (Rom)
+ {
+ /* Clean up the BAR to get just the address */
+ CurrentBar &= PCI_ADDRESS_ROM_ADDRESS_MASK;
+ if (!CurrentBar)
+ {
+ /* Invalid ar, fail this descriptor */
+ ResourceDescriptor->Type = CmResourceTypeNull;
+ return FALSE;
+ }
+
+ /* ROM Addresses are always read only */
+ ResourceDescriptor->Flags = CM_RESOURCE_MEMORY_READ_ONLY;
+ }
+
+ /* Compute the length, assume it's the alignment for now */
+ BarLength = PciGetLengthFromBar(CurrentBar);
+ ResourceDescriptor->u.Generic.Length = BarLength;
+ ResourceDescriptor->u.Generic.Alignment = BarLength;
+
+ /* Check what kind of BAR this is */
+ if (CurrentBar & PCI_ADDRESS_IO_SPACE)
+ {
+ /* Use correct mask to decode the address */
+ BarMask = PCI_ADDRESS_IO_ADDRESS_MASK;
+
+ /* Set this as an I/O Port descriptor */
+ ResourceDescriptor->Type = CmResourceTypePort;
+ ResourceDescriptor->Flags = CM_RESOURCE_PORT_IO;
+ }
+ else
+ {
+ /* Use correct mask to decode the address */
+ BarMask = PCI_ADDRESS_MEMORY_ADDRESS_MASK;
+
+ /* Set this as a memory descriptor */
+ ResourceDescriptor->Type = CmResourceTypeMemory;
+
+ /* Check if it's 64-bit or 20-bit decode */
+ if ((CurrentBar & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_64BIT)
+ {
+ /* The next BAR has the high word, read it */
+ ResourceDescriptor->u.Port.MaximumAddress.HighPart = BarArray[1];
+ Is64BitBar = TRUE;
+ }
+ else if ((CurrentBar & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_20BIT)
+ {
+ /* Use the correct mask to decode the address */
+ BarMask = ~0xFFF0000F;
+ }
+
+ /* Check if the BAR is listed as prefetchable memory */
+ if (CurrentBar & PCI_ADDRESS_MEMORY_PREFETCHABLE)
+ {
+ /* Mark the descriptor in the same way */
+ ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE;
+ }
+ }
+
+ /* Now write down the maximum address based on the base + length */
+ ResourceDescriptor->u.Port.MaximumAddress.QuadPart = (CurrentBar & BarMask) +
+ BarLength - 1;
+
+ /* Return if this is a 64-bit BAR, so the loop code knows to skip the next one */
+ return Is64BitBar;
+}
+
VOID
NTAPI
PciDecodeEnable(IN PPCI_PDO_EXTENSION PdoExtension,
}
}
+NTSTATUS
+NTAPI
+PciQueryBusInformation(IN PPCI_PDO_EXTENSION PdoExtension,
+ IN PPNP_BUS_INFORMATION* Buffer)
+{
+ PPNP_BUS_INFORMATION BusInfo;
+
+ /* Allocate a structure for the bus information */
+ BusInfo = ExAllocatePoolWithTag(PagedPool,
+ sizeof(PNP_BUS_INFORMATION),
+ 'BicP');
+ if (!BusInfo) return STATUS_INSUFFICIENT_RESOURCES;
+
+ /* Write the correct GUID and bus type identifier, and fill the bus number */
+ BusInfo->BusTypeGuid = GUID_BUS_TYPE_PCI;
+ BusInfo->LegacyBusType = PCIBus;
+ BusInfo->BusNumber = PdoExtension->ParentFdoExtension->BaseBus;
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+PciDetermineSlotNumber(IN PPCI_PDO_EXTENSION PdoExtension,
+ OUT PULONG SlotNumber)
+{
+ PPCI_FDO_EXTENSION ParentExtension;
+ ULONG ResultLength;
+ NTSTATUS Status;
+ PSLOT_INFO SlotInfo;
+
+ /* Check if a $PIR from the BIOS is used (legacy IRQ routing) */
+ ParentExtension = PdoExtension->ParentFdoExtension;
+ DPRINT1("Slot lookup for %d.%d.%d\n",
+ ParentExtension ? ParentExtension->BaseBus : -1,
+ PdoExtension->Slot.u.bits.DeviceNumber,
+ PdoExtension->Slot.u.bits.FunctionNumber);
+ if ((PciIrqRoutingTable) && (ParentExtension))
+ {
+ /* Read every slot information entry */
+ SlotInfo = &PciIrqRoutingTable->Slot[0];
+ DPRINT1("PIR$ %p is %lx bytes, slot 0 is at: %lx\n",
+ PciIrqRoutingTable, PciIrqRoutingTable->TableSize, SlotInfo);
+ while (SlotInfo < (PSLOT_INFO)((ULONG_PTR)PciIrqRoutingTable +
+ PciIrqRoutingTable->TableSize))
+ {
+ DPRINT1("Slot Info: %d.%d->#%d\n",
+ SlotInfo->BusNumber,
+ SlotInfo->DeviceNumber,
+ SlotInfo->SlotNumber);
+
+ /* Check if this slot information matches the PDO being queried */
+ if ((ParentExtension->BaseBus == SlotInfo->BusNumber) &&
+ (PdoExtension->Slot.u.bits.DeviceNumber == SlotInfo->DeviceNumber >> 3) &&
+ (SlotInfo->SlotNumber))
+ {
+ /* We found it, return it and return success */
+ *SlotNumber = SlotInfo->SlotNumber;
+ return STATUS_SUCCESS;
+ }
+
+ /* Try the next slot */
+ SlotInfo++;
+ }
+ }
+
+ /* Otherwise, grab the parent FDO and check if it's the root */
+ if (PCI_IS_ROOT_FDO(ParentExtension))
+ {
+ /* The root FDO doesn't have a slot number */
+ Status = STATUS_UNSUCCESSFUL;
+ }
+ else
+ {
+ /* Otherwise, query the slot/UI address/number as a device property */
+ Status = IoGetDeviceProperty(ParentExtension->PhysicalDeviceObject,
+ DevicePropertyUINumber,
+ sizeof(ULONG),
+ SlotNumber,
+ &ResultLength);
+ }
+
+ /* Return the status of this endeavour */
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+PciGetDeviceCapabilities(IN PDEVICE_OBJECT DeviceObject,
+ IN OUT PDEVICE_CAPABILITIES DeviceCapability)
+{
+ PIRP Irp;
+ NTSTATUS Status;
+ KEVENT Event;
+ PDEVICE_OBJECT AttachedDevice;
+ PIO_STACK_LOCATION IoStackLocation;
+ IO_STATUS_BLOCK IoStatusBlock;
+ PAGED_CODE();
+
+ /* Zero out capabilities and set undefined values to start with */
+ RtlZeroMemory(DeviceCapability, sizeof(DEVICE_CAPABILITIES));
+ DeviceCapability->Size = sizeof(DEVICE_CAPABILITIES);
+ DeviceCapability->Version = 1;
+ DeviceCapability->Address = -1;
+ DeviceCapability->UINumber = -1;
+
+ /* Build the wait event for the IOCTL */
+ KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
+
+ /* Find the device the PDO is attached to */
+ AttachedDevice = IoGetAttachedDeviceReference(DeviceObject);
+
+ /* And build an IRP for it */
+ Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
+ AttachedDevice,
+ NULL,
+ 0,
+ NULL,
+ &Event,
+ &IoStatusBlock);
+ if (!Irp)
+ {
+ /* The IRP failed, fail the request as well */
+ ObDereferenceObject(AttachedDevice);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ /* Set default status */
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
+
+ /* Get a stack location in this IRP */
+ IoStackLocation = IoGetNextIrpStackLocation(Irp);
+ ASSERT(IoStackLocation);
+
+ /* Initialize it as a query capabilities IRP, with no completion routine */
+ RtlZeroMemory(IoStackLocation, sizeof(IO_STACK_LOCATION));
+ IoStackLocation->MajorFunction = IRP_MJ_PNP;
+ IoStackLocation->MinorFunction = IRP_MN_QUERY_CAPABILITIES;
+ IoStackLocation->Parameters.DeviceCapabilities.Capabilities = DeviceCapability;
+ IoSetCompletionRoutine(Irp, NULL, NULL, FALSE, FALSE, FALSE);
+
+ /* Send the IOCTL to the driver */
+ Status = IoCallDriver(AttachedDevice, Irp);
+ if (Status == STATUS_PENDING)
+ {
+ /* Wait for a response and update the actual status */
+ KeWaitForSingleObject(&Event,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ Status = Irp->IoStatus.Status;
+ }
+
+ /* Done, dereference the attached device and return the final result */
+ ObDereferenceObject(AttachedDevice);
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+PciQueryPowerCapabilities(IN PPCI_PDO_EXTENSION PdoExtension,
+ IN PDEVICE_CAPABILITIES DeviceCapability)
+{
+ PDEVICE_OBJECT DeviceObject;
+ NTSTATUS Status;
+ DEVICE_CAPABILITIES AttachedCaps;
+ DEVICE_POWER_STATE NewPowerState, DevicePowerState, DeviceWakeLevel, DeviceWakeState;
+ SYSTEM_POWER_STATE SystemWakeState, DeepestWakeState, CurrentState;
+
+ /* Nothing is known at first */
+ DeviceWakeState = PowerDeviceUnspecified;
+ SystemWakeState = DeepestWakeState = PowerSystemUnspecified;
+
+ /* Get the PCI capabilities for the parent PDO */
+ DeviceObject = PdoExtension->ParentFdoExtension->PhysicalDeviceObject;
+ Status = PciGetDeviceCapabilities(DeviceObject, &AttachedCaps);
+ ASSERT(NT_SUCCESS(Status));
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* Check if there's not an existing device state for S0 */
+ if (!AttachedCaps.DeviceState[PowerSystemWorking])
+ {
+ /* Set D0<->S0 mapping */
+ AttachedCaps.DeviceState[PowerSystemWorking] = PowerDeviceD0;
+ }
+
+ /* Check if there's not an existing device state for S3 */
+ if (!AttachedCaps.DeviceState[PowerSystemShutdown])
+ {
+ /* Set D3<->S3 mapping */
+ AttachedCaps.DeviceState[PowerSystemShutdown] = PowerDeviceD3;
+ }
+
+ /* Check for a PDO with broken, or no, power capabilities */
+ if (PdoExtension->HackFlags & PCI_HACK_NO_PM_CAPS)
+ {
+ /* Unknown wake device states */
+ DeviceCapability->DeviceWake = PowerDeviceUnspecified;
+ DeviceCapability->SystemWake = PowerSystemUnspecified;
+
+ /* No device state support */
+ DeviceCapability->DeviceD1 = FALSE;
+ DeviceCapability->DeviceD2 = FALSE;
+
+ /* No waking from any low-power device state is supported */
+ DeviceCapability->WakeFromD0 = FALSE;
+ DeviceCapability->WakeFromD1 = FALSE;
+ DeviceCapability->WakeFromD2 = FALSE;
+ DeviceCapability->WakeFromD3 = FALSE;
+
+ /* For the rest, copy whatever the parent PDO had */
+ RtlCopyMemory(DeviceCapability->DeviceState,
+ AttachedCaps.DeviceState,
+ sizeof(DeviceCapability->DeviceState));
+ return STATUS_SUCCESS;
+ }
+
+ /* The PCI Device has power capabilities, so read which ones are supported */
+ DeviceCapability->DeviceD1 = PdoExtension->PowerCapabilities.Support.D1;
+ DeviceCapability->DeviceD2 = PdoExtension->PowerCapabilities.Support.D2;
+ DeviceCapability->WakeFromD0 = PdoExtension->PowerCapabilities.Support.PMED0;
+ DeviceCapability->WakeFromD1 = PdoExtension->PowerCapabilities.Support.PMED1;
+ DeviceCapability->WakeFromD2 = PdoExtension->PowerCapabilities.Support.PMED2;
+
+ /* Can the attached device wake from D3? */
+ if (AttachedCaps.DeviceWake != PowerDeviceD3)
+ {
+ /* It can't, so check if this PDO supports hot D3 wake */
+ DeviceCapability->WakeFromD3 = PdoExtension->PowerCapabilities.Support.PMED3Hot;
+ }
+ else
+ {
+ /* It can, is this the root bus? */
+ if (PCI_IS_ROOT_FDO(PdoExtension->ParentFdoExtension))
+ {
+ /* This is the root bus, so just check if it supports hot D3 wake */
+ DeviceCapability->WakeFromD3 = PdoExtension->PowerCapabilities.Support.PMED3Hot;
+ }
+ else
+ {
+ /* Take the minimums? -- need to check with briang at work */
+ UNIMPLEMENTED;
+ }
+ }
+
+ /* Now loop each system power state to determine its device state mapping */
+ for (CurrentState = PowerSystemWorking;
+ CurrentState < PowerSystemMaximum;
+ CurrentState++)
+ {
+ /* Read the current mapping from the attached device */
+ DevicePowerState = AttachedCaps.DeviceState[CurrentState];
+ NewPowerState = DevicePowerState;
+
+ /* The attachee suports D1, but this PDO does not */
+ if ((NewPowerState == PowerDeviceD1) &&
+ !(PdoExtension->PowerCapabilities.Support.D1))
+ {
+ /* Fall back to D2 */
+ NewPowerState = PowerDeviceD2;
+ }
+
+ /* The attachee supports D2, but this PDO does not */
+ if ((NewPowerState == PowerDeviceD2) &&
+ !(PdoExtension->PowerCapabilities.Support.D2))
+ {
+ /* Fall back to D3 */
+ NewPowerState = PowerDeviceD3;
+ }
+
+ /* Set the mapping based on the best state supported */
+ DeviceCapability->DeviceState[CurrentState] = NewPowerState;
+
+ /* Check if sleep states are being processed, and a mapping was found */
+ if ((CurrentState < PowerSystemHibernate) &&
+ (NewPowerState != PowerDeviceUnspecified))
+ {
+ /* Save this state as being the deepest one found until now */
+ DeepestWakeState = CurrentState;
+ }
+
+ /*
+ * Finally, check if the computed sleep state is within the states that
+ * this device can wake the system from, and if it's higher or equal to
+ * the sleep state mapping that came from the attachee, assuming that it
+ * had a valid mapping to begin with.
+ *
+ * It this is the case, then make sure that the computed sleep state is
+ * matched by the device's ability to actually wake from that state.
+ *
+ * For devices that support D3, the PCI device only needs Hot D3 as long
+ * as the attachee's state is less than D3. Otherwise, if the attachee
+ * might also be at D3, this would require a Cold D3 wake, so check that
+ * the device actually support this.
+ */
+ if ((CurrentState < AttachedCaps.SystemWake) &&
+ (NewPowerState >= DevicePowerState) &&
+ (DevicePowerState != PowerDeviceUnspecified) &&
+ (((NewPowerState == PowerDeviceD0) && (DeviceCapability->WakeFromD0)) ||
+ ((NewPowerState == PowerDeviceD1) && (DeviceCapability->WakeFromD1)) ||
+ ((NewPowerState == PowerDeviceD2) && (DeviceCapability->WakeFromD2)) ||
+ ((NewPowerState == PowerDeviceD3) &&
+ (PdoExtension->PowerCapabilities.Support.PMED3Hot) &&
+ ((DevicePowerState < PowerDeviceD3) ||
+ (PdoExtension->PowerCapabilities.Support.PMED3Cold)))))
+ {
+ /* The mapping is valid, so this will be the lowest wake state */
+ SystemWakeState = CurrentState;
+ DeviceWakeState = NewPowerState;
+ }
+ }
+
+ /* Read the current wake level */
+ DeviceWakeLevel = PdoExtension->PowerState.DeviceWakeLevel;
+
+ /* Check if the attachee's wake levels are valid, and the PDO's is higher */
+ if ((AttachedCaps.SystemWake != PowerSystemUnspecified) &&
+ (AttachedCaps.DeviceWake != PowerDeviceUnspecified) &&
+ (DeviceWakeLevel != PowerDeviceUnspecified) &&
+ (DeviceWakeLevel >= AttachedCaps.DeviceWake))
+ {
+ /* Inherit the system wake from the attachee, and this PDO's wake level */
+ DeviceCapability->SystemWake = AttachedCaps.SystemWake;
+ DeviceCapability->DeviceWake = DeviceWakeLevel;
+
+ /* Now check if the wake level is D0, but the PDO doesn't support it */
+ if ((DeviceCapability->DeviceWake == PowerDeviceD0) &&
+ !(DeviceCapability->WakeFromD0))
+ {
+ /* Bump to D1 */
+ DeviceCapability->DeviceWake = PowerDeviceD1;
+ }
+
+ /* Now check if the wake level is D1, but the PDO doesn't support it */
+ if ((DeviceCapability->DeviceWake == PowerDeviceD1) &&
+ !(DeviceCapability->WakeFromD1))
+ {
+ /* Bump to D2 */
+ DeviceCapability->DeviceWake = PowerDeviceD2;
+ }
+
+ /* Now check if the wake level is D2, but the PDO doesn't support it */
+ if ((DeviceCapability->DeviceWake == PowerDeviceD2) &&
+ !(DeviceCapability->WakeFromD2))
+ {
+ /* Bump it to D3 */
+ DeviceCapability->DeviceWake = PowerDeviceD3;
+ }
+
+ /* Now check if the wake level is D3, but the PDO doesn't support it */
+ if ((DeviceCapability->DeviceWake == PowerDeviceD3) &&
+ !(DeviceCapability->WakeFromD3))
+ {
+ /* Then no valid wake state exists */
+ DeviceCapability->DeviceWake = PowerDeviceUnspecified;
+ DeviceCapability->SystemWake = PowerSystemUnspecified;
+ }
+
+ /* Check if no valid wake state was found */
+ if ((DeviceCapability->DeviceWake == PowerDeviceUnspecified) ||
+ (DeviceCapability->SystemWake == PowerSystemUnspecified))
+ {
+ /* Check if one was computed earlier */
+ if ((SystemWakeState != PowerSystemUnspecified) &&
+ (DeviceWakeState != PowerDeviceUnspecified))
+ {
+ /* Use the wake state that had been computed earlier */
+ DeviceCapability->DeviceWake = DeviceWakeState;
+ DeviceCapability->SystemWake = SystemWakeState;
+
+ /* If that state was D3, then the device supports Hot/Cold D3 */
+ if (DeviceWakeState == PowerDeviceD3) DeviceCapability->WakeFromD3 = TRUE;
+ }
+ }
+
+ /*
+ * Finally, check for off states (lower than S3, such as hibernate) and
+ * make sure that the device both supports waking from D3 as well as
+ * supports a Cold wake
+ */
+ if ((DeviceCapability->SystemWake > PowerSystemSleeping3) &&
+ ((DeviceCapability->DeviceWake != PowerDeviceD3) ||
+ !(PdoExtension->PowerCapabilities.Support.PMED3Cold)))
+ {
+ /* It doesn't, so pick the computed lowest wake state from earlier */
+ DeviceCapability->SystemWake = DeepestWakeState;
+ }
+
+ /* Set the PCI Specification mandated maximum latencies for transitions */
+ DeviceCapability->D1Latency = 0;
+ DeviceCapability->D2Latency = 2;
+ DeviceCapability->D3Latency = 100;
+
+ /* Sanity check */
+ ASSERT(DeviceCapability->DeviceState[PowerSystemWorking] == PowerDeviceD0);
+ }
+ else
+ {
+ /* No valid sleep states, no latencies to worry about */
+ DeviceCapability->D1Latency = 0;
+ DeviceCapability->D2Latency = 0;
+ DeviceCapability->D3Latency = 0;
+ }
+
+ /* This function always succeeds, even without power management support */
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+PciQueryCapabilities(IN PPCI_PDO_EXTENSION PdoExtension,
+ IN OUT PDEVICE_CAPABILITIES DeviceCapability)
+{
+ NTSTATUS Status;
+
+ /* A PDO ID is never unique, and its address is its function and device */
+ DeviceCapability->UniqueID = FALSE;
+ DeviceCapability->Address = PdoExtension->Slot.u.bits.FunctionNumber |
+ (PdoExtension->Slot.u.bits.DeviceNumber << 16);
+
+ /* Check for host bridges */
+ if ((PdoExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
+ (PdoExtension->SubClass == PCI_SUBCLASS_BR_HOST))
+ {
+ /* Raw device opens to a host bridge are acceptable */
+ DeviceCapability->RawDeviceOK = TRUE;
+ }
+ else
+ {
+ /* Otherwise, other PDOs cannot be directly opened */
+ DeviceCapability->RawDeviceOK = FALSE;
+ }
+
+ /* PCI PDOs are pretty fixed things */
+ DeviceCapability->LockSupported = FALSE;
+ DeviceCapability->EjectSupported = FALSE;
+ DeviceCapability->Removable = FALSE;
+ DeviceCapability->DockDevice = FALSE;
+
+ /* The slot number is stored as a device property, go query it */
+ PciDetermineSlotNumber(PdoExtension, &DeviceCapability->UINumber);
+
+ /* Finally, query and power capabilities and convert them for PnP usage */
+ Status = PciQueryPowerCapabilities(PdoExtension, DeviceCapability);
+
+ /* Dump the capabilities if it all worked, and return the status */
+ if (NT_SUCCESS(Status)) PciDebugDumpQueryCapabilities(DeviceCapability);
+ return Status;
+}
+
/* EOF */