Leaked source code of windows server 2003
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.
 
 
 
 
 
 

843 lines
22 KiB

//***************************************************************************
//
// Module Name:
//
// power.c
//
// Abstract:
// This module contains the code that implements the Plug & Play and
// power management features
//
// Environment:
//
// Kernel mode
//
//
// Copyright (c) 1994-1998 3Dlabs Inc. Ltd. All rights reserved.
// Copyright (c) 1995-1999 Microsoft Corporation. All Rights Reserved.
//
//***************************************************************************
#include "permedia.h"
#define VESA_POWER_FUNCTION 0x4f10
#define VESA_POWER_ON 0x0000
#define VESA_POWER_STANDBY 0x0100
#define VESA_POWER_SUSPEND 0x0200
#define VESA_POWER_OFF 0x0400
#define VESA_GET_POWER_FUNC 0x0000
#define VESA_SET_POWER_FUNC 0x0001
#define VESA_STATUS_SUCCESS 0x004f
//
// all our IDs begin with 0x1357bd so they are readily identifiable as our own
//
#define P2_DDC_MONITOR (0x1357bd00)
#define P2_NONDDC_MONITOR (0x1357bd01)
BOOLEAN PowerOnReset( PHW_DEVICE_EXTENSION hwDeviceExtension );
VOID SaveDeviceState( PHW_DEVICE_EXTENSION hwDeviceExtension );
VOID RestoreDeviceState( PHW_DEVICE_EXTENSION hwDeviceExtension );
VOID I2CWriteClock(PVOID HwDeviceExtension, UCHAR data);
VOID I2CWriteData(PVOID HwDeviceExtension, UCHAR data);
BOOLEAN I2CReadClock(PVOID HwDeviceExtension);
BOOLEAN I2CReadData(PVOID HwDeviceExtension);
VOID I2CWaitVSync(PVOID HwDeviceExtension);
#if defined(ALLOC_PRAGMA)
#pragma alloc_text(PAGE, PowerOnReset)
#pragma alloc_text(PAGE, SaveDeviceState)
#pragma alloc_text(PAGE, RestoreDeviceState)
#pragma alloc_text(PAGE, Permedia2GetPowerState)
#pragma alloc_text(PAGE, Permedia2SetPowerState)
#pragma alloc_text(PAGE, Permedia2GetChildDescriptor)
#pragma alloc_text(PAGE, I2CWriteClock)
#pragma alloc_text(PAGE, I2CWriteData)
#pragma alloc_text(PAGE, I2CReadClock)
#pragma alloc_text(PAGE, I2CReadData)
#pragma alloc_text(PAGE, I2CWaitVSync)
#endif
I2C_FNC_TABLE I2CFunctionTable =
{
sizeof(I2C_FNC_TABLE),
I2CWriteClock,
I2CWriteData,
I2CReadClock,
I2CReadData,
I2CWaitVSync,
NULL
};
VP_STATUS Permedia2GetPowerState (
PVOID HwDeviceExtension,
ULONG HwId,
PVIDEO_POWER_MANAGEMENT VideoPowerControl
)
/*++
Routine Description:
Returns power state information.
Arguments:
HwDeviceExtension - Pointer to our hardware device extension structure.
HwId - Private unique 32 bit ID identifing the device.
VideoPowerControl - Points to a VIDEO_POWER_MANAGEMENT structure that
specifies the power state for which support is
being queried.
Return Value:
VP_STATUS value (NO_ERROR or error value)
--*/
{
VIDEO_X86_BIOS_ARGUMENTS biosArguments;
VP_STATUS status;
PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
DEBUG_PRINT((2, "Permedia2GetPowerState: hwId(%xh) state = %d\n",
(int)HwId, (int)VideoPowerControl->PowerState));
switch((int)HwId)
{
case P2_DDC_MONITOR:
case P2_NONDDC_MONITOR:
switch (VideoPowerControl->PowerState)
{
case VideoPowerOn:
case VideoPowerStandBy:
case VideoPowerSuspend:
case VideoPowerOff:
case VideoPowerHibernate:
case VideoPowerShutdown:
status = NO_ERROR;
break;
default:
DEBUG_PRINT((2, "Permedia2GetPowerState: Unknown monitor PowerState(%xh)\n",
(int)VideoPowerControl->PowerState));
ASSERT(FALSE);
status = ERROR_INVALID_PARAMETER;
}
break;
case DISPLAY_ADAPTER_HW_ID:
//
// only support ON at the moment
//
switch (VideoPowerControl->PowerState)
{
case VideoPowerOn:
case VideoPowerStandBy:
case VideoPowerSuspend:
case VideoPowerHibernate:
case VideoPowerShutdown:
status = NO_ERROR;
break;
case VideoPowerOff:
if( hwDeviceExtension->HardwiredSubSystemId )
{
status = NO_ERROR;
}
else
{
//
// If SubSystemId is not hardwired in a read-only way,
// it is possible we'll see a different value when
// system comes back form S3 mode. This will cause
// problem since os will assume this is a different
// device
//
DEBUG_PRINT((2, "Permedia2GetPowerState: VideoPowerOff is not suported by this card!\n"));
status = ERROR_INVALID_FUNCTION;
}
break;
default:
DEBUG_PRINT((2, "Permedia2GetPowerState: Unknown adapter PowerState(%xh)\n",
(int)VideoPowerControl->PowerState));
ASSERT(FALSE);
status = ERROR_INVALID_PARAMETER;
}
break;
default:
DEBUG_PRINT((1, "Permedia2GetPowerState: Unknown hwId(%xh)",
(int)HwId));
ASSERT(FALSE);
status = ERROR_INVALID_PARAMETER;
}
DEBUG_PRINT((2, "Permedia2GetPowerState: returning %xh\n", status));
return(status);
}
VP_STATUS Permedia2SetPowerState (
PVOID HwDeviceExtension,
ULONG HwId,
PVIDEO_POWER_MANAGEMENT VideoPowerControl
)
/*++
Routine Description:
Set the power state for a given device.
Arguments:
HwDeviceExtension - Pointer to our hardware device extension structure.
HwId - Private unique 32 bit ID identifing the device.
VideoPowerControl - Points to a VIDEO_POWER_MANAGEMENT structure that
specifies the power state to be set.
Return Value:
VP_STATUS value (NO_ERROR, if all's well)
--*/
{
PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
ULONG Polarity;
VIDEO_X86_BIOS_ARGUMENTS biosArguments;
VP_STATUS status;
P2_DECL;
DEBUG_PRINT((2, "Permedia2SetPowerState: hwId(%xh) state = %d\n",
(int)HwId, (int)VideoPowerControl->PowerState));
switch((int)HwId)
{
case P2_DDC_MONITOR:
case P2_NONDDC_MONITOR:
Polarity = VideoPortReadRegisterUlong(VIDEO_CONTROL);
Polarity &= ~((1 << 5) | (1 << 3) | 1);
switch (VideoPowerControl->PowerState)
{
case VideoPowerHibernate:
case VideoPowerShutdown:
//
// Do nothing for hibernate as the monitor must stay on.
//
status = NO_ERROR;
break;
case VideoPowerOn:
RestoreDeviceState(hwDeviceExtension);
status = NO_ERROR;
break;
case VideoPowerStandBy:
//
// hsync low, vsync active high, video disabled
//
SaveDeviceState(hwDeviceExtension);
VideoPortWriteRegisterUlong(VIDEO_CONTROL,
Polarity | (1 << 5) | (2 << 3) | 0);
status = NO_ERROR;
break;
case VideoPowerSuspend:
//
// vsync low, hsync active high, video disabled
//
VideoPortWriteRegisterUlong(VIDEO_CONTROL,
Polarity | (2 << 5) | (1 << 3) | 0);
status = NO_ERROR;
break;
case VideoPowerOff:
//
// vsync low, hsync low, video disabled
//
VideoPortWriteRegisterUlong(VIDEO_CONTROL,
Polarity | (2 << 5) | (2 << 3) | 0);
status = NO_ERROR;
break;
default:
DEBUG_PRINT((2, "Permedia2GetPowerState: Unknown monitor PowerState(%xh)\n",
(int)VideoPowerControl->PowerState));
ASSERT(FALSE);
status = ERROR_INVALID_PARAMETER;
}
//
// Track the current monitor power state
//
hwDeviceExtension->bMonitorPoweredOn =
(VideoPowerControl->PowerState == VideoPowerOn) ||
(VideoPowerControl->PowerState == VideoPowerHibernate);
Polarity = VideoPortReadRegisterUlong(VIDEO_CONTROL);
break;
case DISPLAY_ADAPTER_HW_ID:
switch (VideoPowerControl->PowerState)
{
case VideoPowerHibernate:
status = NO_ERROR;
break;
case VideoPowerShutdown:
//
// We need to make sure no interrupts will be generated
// after the device being powered down
//
VideoPortWriteRegisterUlong(INT_ENABLE, 0);
status = NO_ERROR;
break;
case VideoPowerOn:
if ((hwDeviceExtension->PreviousPowerState == VideoPowerOff) ||
(hwDeviceExtension->PreviousPowerState == VideoPowerSuspend) ||
(hwDeviceExtension->PreviousPowerState == VideoPowerHibernate))
{
PowerOnReset(hwDeviceExtension);
}
status = NO_ERROR;
break;
case VideoPowerStandBy:
status = NO_ERROR;
break;
case VideoPowerSuspend:
status = NO_ERROR;
break;
case VideoPowerOff:
status = NO_ERROR;
break;
default:
DEBUG_PRINT((2, "Permedia2GetPowerState: Unknown adapter PowerState(%xh)\n",
(int)VideoPowerControl->PowerState));
ASSERT(FALSE);
status = ERROR_INVALID_PARAMETER;
}
hwDeviceExtension->PreviousPowerState =
VideoPowerControl->PowerState;
break;
default:
DEBUG_PRINT((1, "Permedia2SetPowerState: Unknown hwId(%xh)\n",
(int)HwId));
ASSERT(FALSE);
status = ERROR_INVALID_PARAMETER;
}
return(status);
}
BOOLEAN PowerOnReset(
PHW_DEVICE_EXTENSION hwDeviceExtension
)
/*++
Routine Description:
Called when the adapter is powered on
--*/
{
int i;
ULONG ulValue;
BOOLEAN bOK;
P2_DECL;
if(!hwDeviceExtension->bVGAEnabled ||
!hwDeviceExtension->bDMAEnabled)
{
PCI_COMMON_CONFIG PciData;
//
// in a multi-adapter system we'll need to turn on the DMA and
// memory space for the secondary adapters
//
DEBUG_PRINT((1, "PowerOnReset() enabling memory space access for the secondary card\n"));
VideoPortGetBusData( hwDeviceExtension,
PCIConfiguration,
0,
&PciData,
0,
PCI_COMMON_HDR_LENGTH);
PciData.Command |= PCI_ENABLE_MEMORY_SPACE;
PciData.Command |= PCI_ENABLE_BUS_MASTER;
VideoPortSetBusData( hwDeviceExtension,
PCIConfiguration,
0,
&PciData,
0,
PCI_COMMON_HDR_LENGTH );
#if DBG
DumpPCIConfigSpace(hwDeviceExtension, hwDeviceExtension->pciBus,
(ULONG)hwDeviceExtension->pciSlot.u.AsULONG);
#endif
}
//
// While waking up from hibernation, we usually don't need
// to reset perm2 and call ProcessInitializationTable()
// for the primary card since video bios will get posted.
// We do so here because we saw cases that the perm2 bios
// failed to worked correctly on some machines.
//
//
// reset the device
//
VideoPortWriteRegisterUlong(RESET_STATUS, 0);
for(i = 0; i < 100000; ++i)
{
ulValue = VideoPortReadRegisterUlong(RESET_STATUS);
if (ulValue == 0)
break;
}
if(ulValue)
{
DEBUG_PRINT((1, "PowerOnReset() Read RESET_STATUS(%xh) - failed to reset\n",
ulValue));
ASSERT(FALSE);
bOK = FALSE;
}
else
{
//
// reload registers given in ROM
//
if(hwDeviceExtension->culTableEntries)
{
ProcessInitializationTable(hwDeviceExtension);
}
//
// set-up other registers not set in InitializeVideo
//
VideoPortWriteRegisterUlong(BYPASS_WRITE_MASK, 0xFFFFFFFF);
VideoPortWriteRegisterUlong(APERTURE_ONE, 0x0);
VideoPortWriteRegisterUlong(APERTURE_TWO, 0x0);
bOK = TRUE;
}
return(bOK);
}
VOID SaveDeviceState(PHW_DEVICE_EXTENSION hwDeviceExtension)
/*++
Routine Description:
Save any registers that will be destroyed when we power down the monitor
--*/
{
P2_DECL;
DEBUG_PRINT((2, "SaveDeviceState() called\n"));
//
// hwDeviceExtension->VideoControl should be set in InitializeVideo,
// just in case we get here before InitializeVideo
//
if( !(hwDeviceExtension->VideoControl) )
{
hwDeviceExtension->VideoControl =
VideoPortReadRegisterUlong(VIDEO_CONTROL);
}
hwDeviceExtension->IntEnable = VideoPortReadRegisterUlong(INT_ENABLE);
}
VOID RestoreDeviceState(PHW_DEVICE_EXTENSION hwDeviceExtension)
/*++
Routine Description:
Restore registers saved before monitor power down
--*/
{
P2_DECL;
DEBUG_PRINT((2, "RestoreDeviceState() called\n"));
VideoPortWriteRegisterUlong(VIDEO_CONTROL, hwDeviceExtension->VideoControl);
VideoPortWriteRegisterUlong(INT_ENABLE, hwDeviceExtension->IntEnable);
}
ULONG
Permedia2GetChildDescriptor(
PVOID HwDeviceExtension,
PVIDEO_CHILD_ENUM_INFO ChildEnumInfo,
PVIDEO_CHILD_TYPE pChildType,
PVOID pChildDescriptor,
PULONG pUId,
PULONG pUnused )
/*++
Routine Description:
Enumerate all child devices controlled by the Permedia 2 chip.
This includes DDC monitors attached to the board, as well as other devices
which may be connected to a proprietary bus.
Arguments:
HwDeviceExtension -
Pointer to our hardware device extension structure.
ChildEnumInfo -
Information about the device that should be enumerated.
pChildType -
Type of child we are enumerating - monitor, I2C ...
pChildDescriptor -
Identification structure of the device (EDID, string)
pUId -
Private unique 32 bit ID to passed back to the miniport
pUnused -
Do not use
Return Value:
ERROR_NO_MORE_DEVICES -
if no more child devices exist.
ERROR_INVALID_NAME -
The miniport could not enumerate the child device identified in
ChildEnumInfo but does have more devices to be enumerated.
ERROR_MORE_DATA -
There are more devices to be enumerated.
Note:
In the event of a failure return, none of the fields are valid except for
the return value and the pMoreChildren field.
--*/
{
PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
DEBUG_PRINT((2, "Permedia2GetChildDescriptor called\n"));
switch (ChildEnumInfo->ChildIndex)
{
case 0:
//
// Case 0 is used to enumerate devices found by the ACPI firmware.
// We do not currently support ACPI devices
//
return ERROR_NO_MORE_DEVICES;
case 1:
//
// Treat index 1 as the monitor
//
*pChildType = Monitor;
//
// if it's a DDC monitor we return its EDID in pjBuffer
// (always 128 bytes)
//
if(VideoPortDDCMonitorHelper(HwDeviceExtension,
&I2CFunctionTable,
pChildDescriptor,
ChildEnumInfo->ChildDescriptorSize))
{
//
// found a DDC monitor
//
DEBUG_PRINT((2, "Permedia2GetChildDescriptor: found a DDC monitor\n"));
*pUId = P2_DDC_MONITOR;
}
else
{
//
// failed: assume non-DDC monitor
//
DEBUG_PRINT((2, "Permedia2GetChildDescriptor: found a non-DDC monitor\n"));
*pUId = P2_NONDDC_MONITOR;
}
return ERROR_MORE_DATA;
default:
return ERROR_NO_MORE_DEVICES;
}
}
VOID I2CWriteClock(PVOID HwDeviceExtension, UCHAR data)
{
const ULONG nbitClock = 3;
const ULONG Clock = 1 << nbitClock;
PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
ULONG ul;
P2_DECL;
ul = VideoPortReadRegisterUlong(DDC_DATA);
ul &= ~Clock;
ul |= (data & 1) << nbitClock;
VideoPortWriteRegisterUlong(DDC_DATA, ul);
}
VOID I2CWriteData(PVOID HwDeviceExtension, UCHAR data)
{
const ULONG nbitData = 2;
const ULONG Data = 1 << nbitData;
PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
ULONG ul;
P2_DECL;
ul = VideoPortReadRegisterUlong(DDC_DATA);
ul &= ~Data;
ul |= ((data & 1) << nbitData);
VideoPortWriteRegisterUlong(DDC_DATA, ul);
}
BOOLEAN I2CReadClock(PVOID HwDeviceExtension)
{
const ULONG nbitClock = 1;
const ULONG Clock = 1 << nbitClock;
PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
ULONG ul;
P2_DECL;
ul = VideoPortReadRegisterUlong(DDC_DATA);
ul &= Clock;
ul >>= nbitClock;
return((BOOLEAN)ul);
}
BOOLEAN I2CReadData(PVOID HwDeviceExtension)
{
const ULONG nbitData = 0;
const ULONG Data = 1 << nbitData;
PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
ULONG ul;
P2_DECL;
ul = VideoPortReadRegisterUlong(DDC_DATA);
ul &= Data;
ul >>= nbitData;
return((BOOLEAN)ul);
}
VOID I2CWaitVSync(PVOID HwDeviceExtension)
{
PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
UCHAR jIndexSaved, jStatus;
P2_DECL;
if(hwDeviceExtension->bVGAEnabled)
{
//
// VGA run on this board, is it currently in VGA or VTG mode?
//
jIndexSaved = VideoPortReadRegisterUchar(PERMEDIA_MMVGA_INDEX_REG);
VideoPortWriteRegisterUchar(PERMEDIA_MMVGA_INDEX_REG,
PERMEDIA_VGA_CTRL_INDEX);
jStatus = VideoPortReadRegisterUchar(PERMEDIA_MMVGA_DATA_REG);
VideoPortWriteRegisterUchar(PERMEDIA_MMVGA_INDEX_REG, jIndexSaved);
}
else
{
//
// VGA not run
//
jStatus = 0;
}
if(jStatus & PERMEDIA_VGA_ENABLE)
{
//
// in VGA, so check VSync via the VGA registers
// 1. if we're in VSync, wait for it to end
//
while( (VideoPortReadRegisterUchar(PERMEDIA_MMVGA_STAT_REG) &
PERMEDIA_VGA_STAT_VSYNC) == 1);
//
// 2. wait for the start of VSync
//
while( (VideoPortReadRegisterUchar(PERMEDIA_MMVGA_STAT_REG) &
PERMEDIA_VGA_STAT_VSYNC) == 0);
}
else
{
if(!hwDeviceExtension->bVTGRunning)
{
//
// time to set-up the VTG - we'll need a valid mode to do this,
// so we;ll choose 640x480x8 we get here (at boot-up only) if
// the secondary card has VGA disabled: GetChildDescriptor is
// called before InitializeVideo so that the VTG hasn't been
// programmed yet
//
DEBUG_PRINT((2, "I2CWaitVSync() - VGA nor VTG running: attempting to setup VTG\n"));
if(hwDeviceExtension->pFrequencyDefault == NULL)
{
DEBUG_PRINT((1, "I2CWaitVSync() - no valid modes to use: can't set-up VTG\n"));
return;
}
Permedia2GetClockSpeeds(HwDeviceExtension);
ZeroMemAndDac(hwDeviceExtension, 0);
if (!InitializeVideo( HwDeviceExtension,
hwDeviceExtension->pFrequencyDefault) )
{
DEBUG_PRINT((1, "I2CWaitVSync() - InitializeVideo failed\n"));
return;
}
}
//
// VTG has been set-up: check via the control registers
//
VideoPortWriteRegisterUlong ( INT_FLAGS,
INTR_VBLANK_SET );
while (( (VideoPortReadRegisterUlong (INT_FLAGS) ) &
INTR_VBLANK_SET ) == 0 );
}
}