You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
414 lines
8.6 KiB
414 lines
8.6 KiB
/*++
|
|
|
|
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;
|
|
PCI_PM_CAPABILITY pmCap = {0};
|
|
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 power 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.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PCI_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 );
|
|
}
|