windows-nt/Source/XPSP1/NT/base/busdrv/pci/pmeintf.c

411 lines
8.2 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1997-2000 Microsoft Corporation
Module Name:
gpeintf.c
Abstract:
This module implements the "PME" interfaces supported
by the PCI driver.
Author:
Stephane Plante (splante) Feb-1-1999
Revision History:
--*/
#include "pcip.h"
NTSTATUS
PciPmeInterfaceConstructor(
PVOID DeviceExtension,
PVOID PciInterface,
PVOID InterfaceSpecificData,
USHORT Version,
USHORT Size,
PINTERFACE InterfaceReturn
);
VOID
PciPmeInterfaceDereference(
IN PVOID Context
);
NTSTATUS
PciPmeInterfaceInitializer(
IN PPCI_ARBITER_INSTANCE Instance
);
VOID
PciPmeInterfaceReference(
IN PVOID Context
);
VOID
PciPmeUpdateEnable(
IN PDEVICE_OBJECT Pdo,
IN BOOLEAN PmeEnable
);
//
// Define the Pci PME interface "interface" structure
//
PCI_INTERFACE PciPmeInterface = {
&GUID_PCI_PME_INTERFACE, // Interface Type
sizeof(PCI_PME_INTERFACE), // Mininum Size
PCI_PME_INTRF_STANDARD_VER, // Minimum Version
PCI_PME_INTRF_STANDARD_VER, // Maximum Version
PCIIF_FDO | PCIIF_ROOT, // Flags
0, // ReferenceCount
PciInterface_PmeHandler, // Signature
PciPmeInterfaceConstructor, // Constructor
PciPmeInterfaceInitializer // Instance Initializer
};
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, PciPmeInterfaceConstructor)
#pragma alloc_text(PAGE, PciPmeInterfaceDereference)
#pragma alloc_text(PAGE, PciPmeInterfaceInitializer)
#pragma alloc_text(PAGE, PciPmeInterfaceReference)
#endif
VOID
PciPmeAdjustPmeEnable(
IN PPCI_PDO_EXTENSION PdoExtension,
IN BOOLEAN Enable,
IN BOOLEAN ClearStatusOnly
)
/*++
Routine Description:
This is the only routine in the the PCI driver that is allowed to set
the PME Enable pin for a device.
Arguments:
PdoExtension - The device that wants to have the PME enable set
Enable - Turn on the PME pin or not
ClearStatusOnly - Only clear the status --- ignore the Enable bit
Return Value:
VOID
--*/
{
PCI_PM_CAPABILITY pmCap;
UCHAR pmCapPtr = 0;
//
// Are there any pm capabilities?
//
if (!(PdoExtension->HackFlags & PCI_HACK_NO_PM_CAPS) ) {
pmCapPtr = PciReadDeviceCapability(
PdoExtension,
PdoExtension->CapabilitiesPtr,
PCI_CAPABILITY_ID_POWER_MANAGEMENT,
&pmCap,
sizeof(pmCap)
);
}
if (pmCapPtr == 0) {
return;
}
//
// Set or clear the PMEEnable bit depending on the value of Enable
//
if (!ClearStatusOnly) {
pmCap.PMCSR.ControlStatus.PMEEnable = (Enable != 0);
}
//
// Write back what we read to clear the PME Status.
//
PciWriteDeviceConfig(
PdoExtension,
&(pmCap.PMCSR.ControlStatus),
pmCapPtr + FIELD_OFFSET(PCI_PM_CAPABILITY, PMCSR.ControlStatus),
sizeof(pmCap.PMCSR.ControlStatus)
);
}
VOID
PciPmeClearPmeStatus(
IN PDEVICE_OBJECT Pdo
)
/*++
Routine Description:
This routine explicitly clears the PME status bit from a device
Arguments:
Pdo - The device whose pin we are to clear
Return Value:
VOID
--*/
{
PPCI_PDO_EXTENSION pdoExtension = (PPCI_PDO_EXTENSION) Pdo->DeviceExtension;
ASSERT_PCI_PDO_EXTENSION( pdoExtension );
//
// Call the Adjust function to do the actual work. Note that passing
// in the 3rd argument as TRUE means that the 2nd argument is ignored
//
PciPmeAdjustPmeEnable( pdoExtension, FALSE, TRUE );
}
VOID
PciPmeGetInformation(
IN PDEVICE_OBJECT Pdo,
OUT PBOOLEAN PmeCapable,
OUT PBOOLEAN PmeStatus,
OUT PBOOLEAN PmeEnable
)
/*++
Routine Description:
Supplies the information regarding a PDO's PME capabilities
Arguments:
Pdo - The device object whose capabilities we care about
PmeCapable - Can the device generate a PME?
PmeStatus - Is the PME status for the device on?
PmeEnable - Is the PME enable for the device on?
Return Value:
None
--*/
{
BOOLEAN pmeCapable = FALSE;
BOOLEAN pmeEnable = FALSE;
BOOLEAN pmeStatus = FALSE;
NTSTATUS status;
PCI_PM_CAPABILITY pmCap;
PPCI_PDO_EXTENSION pdoExtension = (PPCI_PDO_EXTENSION) Pdo->DeviceExtension;
UCHAR pmCapPtr = 0;
ASSERT_PCI_PDO_EXTENSION( pdoExtension );
//
// Get the current power management capabilities from the device
//
if (!(pdoExtension->HackFlags & PCI_HACK_NO_PM_CAPS) ) {
pmCapPtr = PciReadDeviceCapability(
pdoExtension,
pdoExtension->CapabilitiesPtr,
PCI_CAPABILITY_ID_POWER_MANAGEMENT,
&pmCap,
sizeof(pmCap)
);
}
if (pmCapPtr == 0) {
//
// No Pdo capabilities
//
goto PciPmeGetInformationExit;
}
//
// At this point, we are found to be PME capable
//
pmeCapable = TRUE;
//
// Are enabled for PME?
//
if (pmCap.PMCSR.ControlStatus.PMEEnable == 1) {
pmeEnable = TRUE;
}
//
// Is the PME Status pin set?
//
if (pmCap.PMCSR.ControlStatus.PMEStatus == 1) {
pmeStatus = TRUE;
}
PciPmeGetInformationExit:
if (PmeCapable != NULL) {
*PmeCapable = pmeCapable;
}
if (PmeStatus != NULL) {
*PmeStatus = pmeStatus;
}
if (PmeEnable != NULL) {
*PmeEnable = pmeEnable;
}
return;
}
NTSTATUS
PciPmeInterfaceConstructor(
PVOID DeviceExtension,
PVOID PciInterface,
PVOID InterfaceSpecificData,
USHORT Version,
USHORT Size,
PINTERFACE InterfaceReturn
)
/*++
Routine Description:
Initialize the PCI_PME_INTERFACE fields.
Arguments:
PciInterface Pointer to the PciInterface record for this
interface type.
InterfaceSpecificData
InterfaceReturn
Return Value:
Status
--*/
{
PPCI_PME_INTERFACE standard = (PPCI_PME_INTERFACE) InterfaceReturn;
switch(Version) {
case PCI_PME_INTRF_STANDARD_VER:
standard->GetPmeInformation = PciPmeGetInformation;
standard->ClearPmeStatus = PciPmeClearPmeStatus;
standard->UpdateEnable = PciPmeUpdateEnable;
break;
default:
return STATUS_NOINTERFACE;
}
standard->Size = sizeof( PCI_PME_INTERFACE );
standard->Version = Version;
standard->Context = DeviceExtension;
standard->InterfaceReference = PciPmeInterfaceReference;
standard->InterfaceDereference = PciPmeInterfaceDereference;
return STATUS_SUCCESS;
}
VOID
PciPmeInterfaceDereference(
IN PVOID Context
)
{
return;
}
NTSTATUS
PciPmeInterfaceInitializer(
IN PPCI_ARBITER_INSTANCE Instance
)
/*++
Routine Description:
For bus interface, does nothing, shouldn't actually be called.
Arguments:
Instance Pointer to the PDO extension.
Return Value:
Returns the status of this operation.
--*/
{
ASSERTMSG("PCI PciPmeInterfaceInitializer, unexpected call.", 0);
return STATUS_UNSUCCESSFUL;
}
VOID
PciPmeInterfaceReference(
IN PVOID Context
)
{
return;
}
VOID
PciPmeUpdateEnable(
IN PDEVICE_OBJECT Pdo,
IN BOOLEAN PmeEnable
)
/*++
Routine Description:
This routine sets or clears the PME Enable bit on the specified
device object
Arguments:
Pdo - The device object whose PME enable we care about
PmeEnable - Wether or not we should enable PME on the device
Return Value:
None
--*/
{
PPCI_PDO_EXTENSION pdoExtension = (PPCI_PDO_EXTENSION) Pdo->DeviceExtension;
ASSERT_PCI_PDO_EXTENSION( pdoExtension );
//
// Mark the device as not having its PME managed by PCI any more...
//
pdoExtension->NoTouchPmeEnable = 1;
//
// Call the interface that does the real work. Note that we always need
// to supply the 3rd argument as FALSE --- we don't to just clear the
// PME Status bit
//
PciPmeAdjustPmeEnable( pdoExtension, PmeEnable, FALSE );
}