/***************************************************************************\ * * ************************ * * MINIPORT SAMPLE CODE * * ************************ * * Module Name: * * power.c * * Abstract: * * This module contains the code that implements the power management features * * * Environment: * * Kernel mode * * * Copyright (c) 1994-1999 3Dlabs Inc. Ltd. All rights reserved. * Copyright (c) 1995-2003 Microsoft Corporation. All Rights Reserved. * \***************************************************************************/ #include "perm3.h" #if defined(ALLOC_PRAGMA) #pragma alloc_text(PAGE,Perm3GetPowerState) #pragma alloc_text(PAGE,Perm3SetPowerState) #pragma alloc_text(PAGE,Perm3GetChildDescriptor) #pragma alloc_text(PAGE,ProgramDFP) #pragma alloc_text(PAGE,GetDFPEdid) #pragma alloc_text(PAGE,I2CWriteClock) #pragma alloc_text(PAGE,I2CWriteData) #pragma alloc_text(PAGE,I2CReadClock) #pragma alloc_text(PAGE,I2CReadData) #pragma alloc_text(PAGE,I2CWriteClockDFP) #pragma alloc_text(PAGE,I2CWriteDataDFP) #pragma alloc_text(PAGE,I2CReadClockDFP) #pragma alloc_text(PAGE,I2CReadDataDFP) #endif DDC_CONTROL DDCControlCRT = { sizeof(DDC_CONTROL), I2CWriteClock, I2CWriteData, I2CReadClock, I2CReadData, 0 }; DDC_CONTROL DDCControlDFP = { sizeof(DDC_CONTROL), I2CWriteClockDFP, I2CWriteDataDFP, I2CReadClockDFP, I2CReadDataDFP, 0 }; VP_STATUS Perm3GetPowerState( PVOID HwDeviceExtension, ULONG HwId, PVIDEO_POWER_MANAGEMENT VideoPowerControl ) /*+++ Routine Description: Queries whether the device can support the requested power state. Arguments: HwDeviceExtension Pointer to our hardware device extension structure. HwId Points to a 32-bit number that uniquely identifies the device that the miniport should query. VideoPowerControl Points to a VIDEO_POWER_MANAGEMENT structure that specifies the power state for which support is being queried. Return Value: NO_ERROR, if the device supports the requested power state, or error code. ---*/ { VP_STATUS status; PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension; VideoDebugPrint((3, "Perm3: Perm3GetPowerState: hwId(0x%x) state = %d\n", HwId, VideoPowerControl->PowerState )); switch(HwId) { case PERM3_DDC_MONITOR: case PERM3_NONDDC_MONITOR: switch ( VideoPowerControl->PowerState ) { case VideoPowerOn: case VideoPowerStandBy: case VideoPowerSuspend: case VideoPowerOff: case VideoPowerHibernate: case VideoPowerShutdown: status = NO_ERROR; break; default: VideoDebugPrint((0, "Perm3: Perm3GetPowerState: Unknown monitor PowerState = %d\n", VideoPowerControl->PowerState )); ASSERT(FALSE); status = ERROR_INVALID_PARAMETER; } break; case DISPLAY_ADAPTER_HW_ID: switch ( VideoPowerControl->PowerState ) { case VideoPowerOn: case VideoPowerStandBy: case VideoPowerSuspend: case VideoPowerOff: case VideoPowerHibernate: case VideoPowerShutdown: status = NO_ERROR; break; default: VideoDebugPrint((0, "Perm3: Perm3GetPowerState: Unknown adapter PowerState = %d\n", VideoPowerControl->PowerState )); ASSERT(FALSE); status = ERROR_INVALID_PARAMETER; } break; default: VideoDebugPrint((0, "Perm3: Perm3GetPowerState: Unknown hwId(0x%x)", HwId)); ASSERT(FALSE); status = ERROR_INVALID_PARAMETER; } return(status); } VP_STATUS Perm3SetPowerState( PVOID HwDeviceExtension, ULONG HwId, PVIDEO_POWER_MANAGEMENT VideoPowerControl ) /*+++ Routine Description: Sets the power state of the specified device. Arguments: HwDeviceExtension Pointer to our hardware device extension structure. HwId Points to a 32-bit number that uniquely identifies the device for which the miniport should set the power state. VideoPowerControl Points to a VIDEO_POWER_MANAGEMENT structure that specifies the power state to be set. Return Value: NO_ERROR ---*/ { PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension; ULONG Polarity; pPerm3ControlRegMap pCtrlRegs = hwDeviceExtension->ctrlRegBase[0]; VideoDebugPrint((3, "Perm3: Perm3SetPowerState: hwId(0x%x) state = %d\n", HwId, VideoPowerControl->PowerState)); switch(HwId) { case PERM3_DDC_MONITOR: case PERM3_NONDDC_MONITOR: Polarity = VideoPortReadRegisterUlong(VIDEO_CONTROL); Polarity &= ~VC_DPMS_MASK; switch (VideoPowerControl->PowerState) { case VideoPowerOn: VideoPortWriteRegisterUlong(VIDEO_CONTROL, Polarity | hwDeviceExtension->VideoControlMonitorON); break; case VideoPowerStandBy: VideoPortWriteRegisterUlong(VIDEO_CONTROL, Polarity | VC_DPMS_STANDBY); break; case VideoPowerSuspend: VideoPortWriteRegisterUlong(VIDEO_CONTROL, Polarity | VC_DPMS_SUSPEND); break; case VideoPowerShutdown: case VideoPowerOff: VideoPortWriteRegisterUlong(VIDEO_CONTROL, Polarity | VC_DPMS_OFF); break; case VideoPowerHibernate: // // The monitor for the vga enabled video device must // stay on at hibernate. // break; default: VideoDebugPrint((0, "Perm3: Perm3GetPowerState: Unknown monitor PowerState(0x%x)\n", VideoPowerControl->PowerState)); ASSERT(FALSE); } // // Track the current monitor power state // hwDeviceExtension->bMonitorPoweredOn = (VideoPowerControl->PowerState == VideoPowerOn) || (VideoPowerControl->PowerState == VideoPowerHibernate); break; case DISPLAY_ADAPTER_HW_ID: switch (VideoPowerControl->PowerState) { case VideoPowerOn: if ((hwDeviceExtension->PreviousPowerState == VideoPowerOff) || (hwDeviceExtension->PreviousPowerState == VideoPowerSuspend) || (hwDeviceExtension->PreviousPowerState == VideoPowerHibernate)){ // // Turn off the monitor while we power back up so // the user doesn't see any screen corruption // Polarity = VideoPortReadRegisterUlong(VIDEO_CONTROL); Polarity &= ~VC_DPMS_MASK; VideoPortWriteRegisterUlong(VIDEO_CONTROL, Polarity | VC_DPMS_OFF); // // Miniport driver can not rely on video bios to // initialize the device registers while resuming // from VideoPowerOff and VideoPowerSuspend. // // This is also true for the secondary (vga disabled) // video device while resuming from VideoPowerHibernate // InitializePostRegisters(hwDeviceExtension); } break; case VideoPowerStandBy: case VideoPowerSuspend: case VideoPowerOff: case VideoPowerHibernate: break; case VideoPowerShutdown: // // We need to make sure no interrupts will be generated // after the device being powered down // VideoPortWriteRegisterUlong(INT_ENABLE, 0); break; default: VideoDebugPrint((0, "Perm3: Perm3GetPowerState: Unknown adapter PowerState(0x%x)\n", VideoPowerControl->PowerState)); ASSERT(FALSE); } hwDeviceExtension->PreviousPowerState = VideoPowerControl->PowerState; break; default: VideoDebugPrint((0, "Perm3: Perm3SetPowerState: Unknown hwId(0x%x)\n", HwId)); ASSERT(FALSE); } return(NO_ERROR); } ULONG Perm3GetChildDescriptor( PVOID HwDeviceExtension, PVIDEO_CHILD_ENUM_INFO pChildInfo, PVIDEO_CHILD_TYPE pChildType, PUCHAR pChildDescriptor, PULONG pUId, PULONG Unused ) /*+++ Routine Description: Enumerates all child devices attached to the specified device. 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 Pointer to VIDEO_CHILD_ENUM_INFO structure that describes the device being enumerated. pChildType Points to a location in which the miniport returns the type of child being enumerated. pChildDescriptor Points to a buffer in which the miniport can return data that identifies the device. pUId Points to the location in which the miniport returns a unique 32-bit identifier for this device. pUnused Is unused and must be set to zero. Return Value: ERROR_MORE_DATA There are more devices to be enumerated. ERROR_NO_MORE_DEVICES There are no more devices to be enumerated. ERROR_INVALID_NAME The miniport could not enumerate the child device identified in ChildEnumInfo but does have more devices to be enumerated. ---*/ { PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension; VideoDebugPrint((3, "Perm3: Perm3GetChildDescriptor called\n")); switch(pChildInfo->ChildIndex) { case 0: // // Case 0 is used to enumerate devices found by the ACPI firmware. // We don't currently support ACPI devices // break; case 1: // // Treat index 1 as monitor // *pChildType = Monitor; // // First we search for a DFP monitor // if (GetDFPEdid(hwDeviceExtension, pChildDescriptor, pChildInfo->ChildDescriptorSize)) { // // found a DFP monitor // *pUId = PERM3_DFP_MONITOR; return(VIDEO_ENUM_MORE_DEVICES); } // // If we didn't find a DFP, try to detect a DDC CRT monitor // if(VideoPortDDCMonitorHelper(HwDeviceExtension, &DDCControlCRT, pChildDescriptor, pChildInfo->ChildDescriptorSize)) { // // found a DDC monitor // *pUId = PERM3_DDC_MONITOR; } else { // // failed: assume non-DDC monitor // *pUId = PERM3_NONDDC_MONITOR; } return(VIDEO_ENUM_MORE_DEVICES); } return(ERROR_NO_MORE_DEVICES); } VOID ProgramDFP( PHW_DEVICE_EXTENSION hwDeviceExtension ) /*+++ Routine Description: Program the Perm3 chip to use DFP or not use DFP, depending on whether PERM3_DFP and PERM3_DFP_MON_ATTACHED are enabled in Perm3Capabilities. ---*/ { // // We only try this on boards that are DFP-capable. // if (hwDeviceExtension->Perm3Capabilities & PERM3_DFP) { ULONG rdMisc, vsConf, vsBCtl; pPerm3ControlRegMap pCtrlRegs = hwDeviceExtension->ctrlRegBase[0]; P3RDRAMDAC *pP3RDRegs = (P3RDRAMDAC *)hwDeviceExtension->pRamdac; // // Get values of registers that we are going to trash // P3RD_READ_INDEX_REG(P3RD_MISC_CONTROL, rdMisc); // // Find out the values of the registers // vsConf = VideoPortReadRegisterUlong(VSTREAM_CONFIG); vsBCtl = VideoPortReadRegisterUlong(VSTREAM_B_CONTROL); // // Clear these bits // rdMisc &= ~P3RD_MISC_CONTROL_VSB_OUTPUT_ENABLED; vsConf &= ~VSTREAM_CONFIG_UNITMODE_MASK; vsBCtl &= ~VSTREAM_B_CONTROL_RAMDAC_ENABLE; if (hwDeviceExtension->Perm3Capabilities & PERM3_DFP_MON_ATTACHED) { // // Enable flat panel output as follows: // rdMisc |= P3RD_MISC_CONTROL_VSB_OUTPUT_ENABLED; vsConf |= VSTREAM_CONFIG_UNITMODE_FP; vsBCtl |= VSTREAM_B_CONTROL_RAMDAC_ENABLE; } else { // // set up the registers for non-DFP mode. // rdMisc &= (~P3RD_MISC_CONTROL_VSB_OUTPUT_ENABLED); vsConf |= VSTREAM_CONFIG_UNITMODE_CRT; vsBCtl |= VSTREAM_B_CONTROL_RAMDAC_DISABLE; } VideoDebugPrint((3, "Perm3: P3RD_ProgramDFP: PXRXCaps 0x%x, misc 0x%x, conf 0x%x, ctl 0x%x\n", hwDeviceExtension->Perm3Capabilities, rdMisc, vsConf, vsBCtl)); // // Program the registers // P3RD_LOAD_INDEX_REG(P3RD_MISC_CONTROL, rdMisc); VideoPortWriteRegisterUlong(VSTREAM_CONFIG, vsConf); VideoPortWriteRegisterUlong(VSTREAM_B_CONTROL, vsBCtl); } } VOID I2CWriteClock( PVOID HwDeviceExtension, UCHAR data ) { const ULONG nbitClock = 3; const ULONG ClockMask = 1 << nbitClock; PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension; ULONG ul; pPerm3ControlRegMap pCtrlRegs = hwDeviceExtension->ctrlRegBase[0]; ul = VideoPortReadRegisterUlong(DDC_DATA); ul &= ~ClockMask; ul |= (data & 1) << nbitClock; VideoPortWriteRegisterUlong(DDC_DATA, ul); } VOID I2CWriteData( PVOID HwDeviceExtension, UCHAR data ) { const ULONG nbitData = 2; const ULONG DataMask = 1 << nbitData; PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension; ULONG ul; pPerm3ControlRegMap pCtrlRegs = hwDeviceExtension->ctrlRegBase[0]; ul = VideoPortReadRegisterUlong(DDC_DATA); ul &= ~DataMask; ul |= ((data & 1) << nbitData); VideoPortWriteRegisterUlong(DDC_DATA, ul); } BOOLEAN I2CReadClock( PVOID HwDeviceExtension ) { const ULONG nbitClock = 1; const ULONG ClockMask = 1 << nbitClock; PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension; ULONG ul; pPerm3ControlRegMap pCtrlRegs = hwDeviceExtension->ctrlRegBase[0]; ul = VideoPortReadRegisterUlong(DDC_DATA); ul &= ClockMask; ul >>= nbitClock; return((BOOLEAN)ul); } BOOLEAN I2CReadData( PVOID HwDeviceExtension ) { const ULONG nbitData = 0; const ULONG DataMask = 1 << nbitData; PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension; ULONG ul; pPerm3ControlRegMap pCtrlRegs = hwDeviceExtension->ctrlRegBase[0]; ul = VideoPortReadRegisterUlong(DDC_DATA); ul &= DataMask; ul >>= nbitData; return((BOOLEAN)ul); } BOOLEAN I2CReadDataDFP( PHW_DEVICE_EXTENSION hwDeviceExtension ) { ULONG ul; pPerm3ControlRegMap pCtrlRegs = hwDeviceExtension->ctrlRegBase[0]; ul = VideoPortReadRegisterUlong(VSTREAM_SERIAL_CONTROL); ul &= VSTREAM_SERIAL_CONTROL_DATAIN; return (ul != 0); } BOOLEAN I2CReadClockDFP( PHW_DEVICE_EXTENSION hwDeviceExtension ) { ULONG ul; pPerm3ControlRegMap pCtrlRegs = hwDeviceExtension->ctrlRegBase[0]; ul = VideoPortReadRegisterUlong(VSTREAM_SERIAL_CONTROL); ul &= VSTREAM_SERIAL_CONTROL_CLKIN; return (ul != 0); } VOID I2CWriteDataDFP( PHW_DEVICE_EXTENSION hwDeviceExtension, UCHAR data ) { ULONG ul = 0x0000E000; pPerm3ControlRegMap pCtrlRegs = hwDeviceExtension->ctrlRegBase[0]; ul |= VideoPortReadRegisterUlong(VSTREAM_SERIAL_CONTROL); ul &= ~VSTREAM_SERIAL_CONTROL_DATAOUT; if(data & 1) ul |= VSTREAM_SERIAL_CONTROL_DATAOUT; VideoPortWriteRegisterUlong (VSTREAM_SERIAL_CONTROL, ul); } VOID I2CWriteClockDFP( PHW_DEVICE_EXTENSION hwDeviceExtension, UCHAR data ) { ULONG ul = 0x0000E000; pPerm3ControlRegMap pCtrlRegs = hwDeviceExtension->ctrlRegBase[0]; ul |= VideoPortReadRegisterUlong(VSTREAM_SERIAL_CONTROL); ul &= ~VSTREAM_SERIAL_CONTROL_CLKOUT; if (data & 1) ul |= VSTREAM_SERIAL_CONTROL_CLKOUT; VideoPortWriteRegisterUlong (VSTREAM_SERIAL_CONTROL, ul); } BOOLEAN GetDFPEdid( PHW_DEVICE_EXTENSION hwDeviceExtension, PUCHAR EdidBuffer, LONG EdidSize ) { BOOLEAN DFPPresent = FALSE; // // If this board is capable of driving a DFP then try using DDC to see // if there is a monitor there. // if (hwDeviceExtension->Perm3Capabilities & PERM3_DFP) { // // Let's say that we have a monitor attached // hwDeviceExtension->Perm3Capabilities |= PERM3_DFP_MON_ATTACHED; // // Set up the DFP accordingly // ProgramDFP(hwDeviceExtension); DFPPresent = VideoPortDDCMonitorHelper(hwDeviceExtension, &DDCControlDFP, EdidBuffer, EdidSize); } // // If the board doesn't support flat panel or one isn't attached then // configure ourselves for non-DFP working. // if (!DFPPresent) { // // Well DDC says we don't have a DFP monitor attached, clear this bit // hwDeviceExtension->Perm3Capabilities &= ~PERM3_DFP_MON_ATTACHED; // // Set up the DFP accordingly // ProgramDFP(hwDeviceExtension); } return (DFPPresent); }