1638 lines
39 KiB
C
1638 lines
39 KiB
C
//***************************************************************************
|
|
// Module Name: s3ddc.c
|
|
//
|
|
// Description: This module checks for a DDC monitor, and returns the
|
|
// 128 bytes of EDID table if found.
|
|
//
|
|
// Notes: The routine, DdcSetupRefresh, keeps track of resolution
|
|
// changes in the registry. On a resolution change,
|
|
// DdcSetupRefresh will select the optimal refresh rate. If
|
|
// there is NOT any change in the resolution, the user can
|
|
// select any refresh rate, as long as the monitor and
|
|
// driver can support it.
|
|
//
|
|
// Copyright (c) 1996 S3, Inc.
|
|
//
|
|
//***************************************************************************
|
|
//@@BEGIN_S3MSINTERNAL
|
|
//
|
|
// Revision History:
|
|
//
|
|
// $Log: Q:/SOFTDEV/VCS/NT/MINIPORT/s3ddc.c_v $
|
|
//
|
|
// Rev 1.13 04 Feb 1997 23:40:52 kkarnos
|
|
//Added BEGIN/END S3MSINTERNAL blocks.
|
|
//
|
|
// Rev 1.12 30 Jan 1997 14:56:24 bryhti
|
|
//Fixed the refresh frequency calculation in the Detailed Timing section
|
|
//of DdcMaxRefresh - was causing problems in NT 3.51.
|
|
//
|
|
// Rev 1.11 30 Jan 1997 09:47:36 bryhti
|
|
//Fixed the "for" loop count for Standard Timings in DdcMaxRefresh.
|
|
//
|
|
// Rev 1.10 16 Jan 1997 09:21:28 bryhti
|
|
//Added CheckDDCType routine to return monitor DDC type.
|
|
//
|
|
// Rev 1.9 11 Dec 1996 10:24:38 kkarnos
|
|
//
|
|
//Fix Set_VSYNC.
|
|
//
|
|
// Rev 1.8 10 Dec 1996 16:45:42 kkarnos
|
|
//Just added a comment to explain the source of some odd 764 code (EKL input)
|
|
//
|
|
// Rev 1.7 10 Dec 1996 16:37:08 kkarnos
|
|
//Use register and register bit defines. Correct assignment of SET VSYNC bit
|
|
//
|
|
// Rev 1.6 02 Dec 1996 07:46:16 bryhti
|
|
//
|
|
//Moved GetDdcInformation () prototype to S3.H. Added code to
|
|
//DdcMaxRefresh () to also check the Detailed Timing Descriptions.
|
|
//
|
|
// Rev 1.5 13 Nov 1996 10:14:08 bryhti
|
|
//Major cleanup/rewrite to get DDC1 and DDC2 support on M65. Also got DDC1
|
|
//support working on 765.
|
|
//
|
|
// Rev 1.4 02 Oct 1996 13:56:42 elau
|
|
//765 and new chips support DDC; the newer chip must have a serial port at FF20
|
|
//
|
|
// Rev 1.3 22 Aug 1996 11:44:40 elau
|
|
//Change int to ULONG to remove warning
|
|
//
|
|
// Rev 1.2 18 Aug 1996 16:30:42 elau
|
|
//Use HW default setting for DDC if supports
|
|
//
|
|
// Rev 1.1 24 Jul 1996 15:37:42 elau
|
|
//DDC support for 764
|
|
//
|
|
// Rev 1.0 12 Jul 1996 11:52:36 elau
|
|
//Initial revision.
|
|
//
|
|
//@@END_S3MSINTERNAL
|
|
//***************************************************************************
|
|
|
|
#include "s3.h"
|
|
#include "cmdcnst.h"
|
|
|
|
#include "s3ddc.h"
|
|
|
|
#define MMFF20 (PVOID) ((ULONG)(HwDeviceExtension->MmIoBase) + SERIAL_PORT_MM)
|
|
|
|
#define NO_FLAGS 0
|
|
#define VERIFY_CHECKSUM 1
|
|
|
|
//
|
|
// Function Prototypes
|
|
//
|
|
VOID I2C_Out (PHW_DEVICE_EXTENSION HwDeviceExtension, UCHAR ucData);
|
|
VOID I2C_Setup (PHW_DEVICE_EXTENSION HwDeviceExtension);
|
|
VOID I2C_StartService (PHW_DEVICE_EXTENSION HwDeviceExtension);
|
|
VOID I2C_StopService (PHW_DEVICE_EXTENSION HwDeviceExtension);
|
|
VOID I2C_BitWrite (PHW_DEVICE_EXTENSION HwDeviceExtension, UCHAR ucData);
|
|
VOID I2C_AckWrite (PHW_DEVICE_EXTENSION HwDeviceExtension);
|
|
VOID I2C_NackWrite (PHW_DEVICE_EXTENSION HwDeviceExtension);
|
|
UCHAR I2C_ByteWrite (PHW_DEVICE_EXTENSION HwDeviceExtension, UCHAR ucData);
|
|
UCHAR I2C_BitRead (PHW_DEVICE_EXTENSION HwDeviceExtension);
|
|
UCHAR I2C_ByteRead (PHW_DEVICE_EXTENSION HwDeviceExtension);
|
|
UCHAR I2C_Data_Request (PHW_DEVICE_EXTENSION, UCHAR, long, long, UCHAR *);
|
|
|
|
VOID Wait_For_Active (PHW_DEVICE_EXTENSION HwDeviceExtension);
|
|
VOID Set_Vsync (PHW_DEVICE_EXTENSION HwDeviceExtension, UCHAR ucFlag);
|
|
VOID Provide_Fake_VSYNC (PHW_DEVICE_EXTENSION HwDeviceExtension);
|
|
UCHAR Read_EDID_Byte (PHW_DEVICE_EXTENSION HwDeviceExtension);
|
|
VOID Disable_DAC_Video (PHW_DEVICE_EXTENSION HwDeviceExtension);
|
|
VOID Enable_DAC_Video (PHW_DEVICE_EXTENSION HwDeviceExtension);
|
|
UCHAR Read_EDID_Bit (PHW_DEVICE_EXTENSION HwDeviceExtension);
|
|
UCHAR Read_EDID_Byte (PHW_DEVICE_EXTENSION HwDeviceExtension);
|
|
|
|
UCHAR Sync_EDID_Header (PHW_DEVICE_EXTENSION HwDeviceExtension);
|
|
UCHAR EDID_Buffer_Xfer (PHW_DEVICE_EXTENSION HwDeviceExtension, UCHAR* pBuffer);
|
|
|
|
UCHAR Check_DDC1_Monitor (PHW_DEVICE_EXTENSION HwDeviceExtension);
|
|
UCHAR Configure_Chip_DDC_Caps (PHW_DEVICE_EXTENSION HwDeviceExtension);
|
|
UCHAR GetDdcInformation (PHW_DEVICE_EXTENSION HwDeviceExtension, UCHAR* pBuffer);
|
|
|
|
|
|
/****************************************************************
|
|
; I2C_Out
|
|
;
|
|
; Controls the individual toggling of bits in MMFF20 to produce
|
|
; clock and data pulses, and in the end provides a delay.
|
|
;
|
|
; MMIO FF20h is defined as follows:
|
|
;
|
|
; ... 3 2 1 0 SCW = CLK Write
|
|
; --------|---|---|---|---| SDW = DATA Write
|
|
; ...|SDR|SCR|SDW|SCW| SCR = CLK Read
|
|
; ------------------------- SDR = DATA Read
|
|
;
|
|
; Input:
|
|
; Using MMIO Base in PHW_DEVICE_EXTENSION
|
|
; UCHAR ucData
|
|
; Bit 7:2 = 0
|
|
; Bit 1 = SDA
|
|
; Bit 0 = SCL
|
|
; Output:
|
|
;
|
|
;****************************************************************/
|
|
|
|
VOID I2C_Out (PHW_DEVICE_EXTENSION HwDeviceExtension, UCHAR ucData)
|
|
{
|
|
|
|
UCHAR ucPortData;
|
|
unsigned int uCount;
|
|
|
|
//
|
|
// read the current value, clear the clock and data bits, and add
|
|
// the new clock and data values
|
|
//
|
|
|
|
ucPortData = (VideoPortReadRegisterUchar (MMFF20) & 0xFC) | ucData;
|
|
|
|
VideoPortWriteRegisterUchar (MMFF20, ucPortData);
|
|
|
|
//
|
|
// if we set the clock high, wait for target to set clock high
|
|
//
|
|
|
|
if (ucData & 0x01)
|
|
{
|
|
uCount = 2000;
|
|
do
|
|
{
|
|
--uCount;
|
|
ucPortData = VideoPortReadRegisterUchar (MMFF20) & 0x04;
|
|
|
|
} while ( !ucPortData && uCount );
|
|
}
|
|
|
|
VideoPortStallExecution(5);
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************
|
|
; I2C_Setup
|
|
;
|
|
; Allow one very long low clock pulse so that monitor has time
|
|
; to switch to DDC2 mode.
|
|
;
|
|
; Input:
|
|
; Using MMIO Base in PHW_DEVICE_EXTENSION
|
|
;
|
|
; Output:
|
|
;
|
|
;****************************************************************/
|
|
|
|
VOID I2C_Setup (PHW_DEVICE_EXTENSION HwDeviceExtension)
|
|
{
|
|
//
|
|
// CLK=low, DATA=high
|
|
//
|
|
|
|
I2C_Out (HwDeviceExtension, 0x02);
|
|
|
|
Wait_For_Active (HwDeviceExtension);
|
|
Wait_For_Active (HwDeviceExtension);
|
|
|
|
//
|
|
// CLK=high, DATA=high
|
|
//
|
|
|
|
I2C_Out (HwDeviceExtension, 0x03);
|
|
|
|
Wait_For_Active (HwDeviceExtension);
|
|
Wait_For_Active (HwDeviceExtension);
|
|
|
|
}
|
|
|
|
/****************************************************************
|
|
; I2C_StartService
|
|
;
|
|
; Provide start sequence for talking to I2C bus.
|
|
;
|
|
; Input:
|
|
; Using MMIO Base in PHW_DEVICE_EXTENSION
|
|
;
|
|
; Output:
|
|
;
|
|
;****************************************************************/
|
|
|
|
VOID I2C_StartService (PHW_DEVICE_EXTENSION HwDeviceExtension)
|
|
{
|
|
//
|
|
// CLK=low, DATA=high
|
|
//
|
|
|
|
I2C_Out (HwDeviceExtension, 0x02);
|
|
|
|
//
|
|
// CLK=high, DATA=high
|
|
//
|
|
|
|
I2C_Out (HwDeviceExtension, 0x03);
|
|
|
|
|
|
//
|
|
// CLK=high, DATA=low
|
|
//
|
|
|
|
I2C_Out (HwDeviceExtension, 0x01);
|
|
|
|
//
|
|
// CLK=low, DATA=low
|
|
//
|
|
|
|
I2C_Out (HwDeviceExtension, 0x00);
|
|
|
|
}
|
|
|
|
/****************************************************************
|
|
; I2C_StopService
|
|
;
|
|
; Provide stop sequence to the I2C bus.
|
|
;
|
|
; Input:
|
|
; Using MMIO Base in PHW_DEVICE_EXTENSION
|
|
;
|
|
; Output:
|
|
;
|
|
;***************************************************************/
|
|
|
|
VOID I2C_StopService (PHW_DEVICE_EXTENSION HwDeviceExtension)
|
|
{
|
|
//
|
|
// CLK=low, DATA=low
|
|
//
|
|
|
|
I2C_Out (HwDeviceExtension, 0x00);
|
|
|
|
//
|
|
// CLK=high, DATA=low
|
|
//
|
|
|
|
I2C_Out (HwDeviceExtension, 0x01);
|
|
|
|
//
|
|
// CLK=high, DATA=high
|
|
//
|
|
|
|
I2C_Out (HwDeviceExtension, 0x03);
|
|
|
|
//
|
|
// CLK=low, DATA=high
|
|
//
|
|
|
|
I2C_Out (HwDeviceExtension, 0x02);
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************
|
|
; I2C_BitWrite
|
|
;
|
|
; Writes one SDA bit to the I2C bus.
|
|
;
|
|
; Input:
|
|
; Using MMIO Base in PHW_DEVICE_EXTENSION
|
|
; Bit 1 of ucData = Bit to be written.
|
|
;
|
|
; Output:
|
|
;
|
|
;***************************************************************/
|
|
|
|
VOID I2C_BitWrite (PHW_DEVICE_EXTENSION HwDeviceExtension, UCHAR ucData)
|
|
{
|
|
|
|
//
|
|
// save valid data bit
|
|
//
|
|
|
|
ucData &= 0x02;
|
|
|
|
//
|
|
// CLK=low, DATA=xxxx
|
|
//
|
|
|
|
I2C_Out (HwDeviceExtension, ucData);
|
|
|
|
//
|
|
// CLK=high, DATA=xxxx
|
|
//
|
|
|
|
I2C_Out (HwDeviceExtension, (UCHAR) (ucData | 0x01));
|
|
|
|
//
|
|
// CLK=low, DATA=xxxx
|
|
//
|
|
|
|
I2C_Out(HwDeviceExtension, ucData);
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************
|
|
; I2C_ByteWrite
|
|
;
|
|
; Output a byte of information to the Display.
|
|
;
|
|
; Input:
|
|
; Using MMIO Base in PHW_DEVICE_EXTENSION
|
|
; ucData = Byte to be written.
|
|
;
|
|
; Output:
|
|
; TRUE - write successfully
|
|
; FALSE - write failure
|
|
;
|
|
;***************************************************************/
|
|
|
|
UCHAR I2C_ByteWrite (PHW_DEVICE_EXTENSION HwDeviceExtension, UCHAR ucData)
|
|
{
|
|
UCHAR uOutData;
|
|
int i;
|
|
|
|
uOutData = ucData;
|
|
|
|
//
|
|
// send MSB first
|
|
//
|
|
|
|
for (i=6; i >= 0; i--)
|
|
{
|
|
//
|
|
// move data bit to bit 1
|
|
//
|
|
|
|
uOutData = (ucData >> i);
|
|
I2C_BitWrite (HwDeviceExtension, uOutData);
|
|
}
|
|
|
|
//
|
|
// now send LSB
|
|
//
|
|
|
|
uOutData = (ucData << 1);
|
|
I2C_BitWrite (HwDeviceExtension, uOutData);
|
|
|
|
//
|
|
// float the data line high for ACK
|
|
//
|
|
|
|
I2C_BitWrite (HwDeviceExtension, 2);
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
/****************************************************************
|
|
; I2C_AckWrite
|
|
;
|
|
; Send Acknowledgement when reading info.
|
|
;
|
|
; Input:
|
|
; Using MMIO Base in PHW_DEVICE_EXTENSION
|
|
;
|
|
; Output:
|
|
;
|
|
;***************************************************************/
|
|
|
|
VOID I2C_AckWrite (PHW_DEVICE_EXTENSION HwDeviceExtension)
|
|
{
|
|
I2C_BitWrite (HwDeviceExtension, 0);
|
|
}
|
|
|
|
|
|
/****************************************************************
|
|
; I2C_NackWrite
|
|
;
|
|
; Send Not ACKnowledgement when reading information.
|
|
; A NACK is DATA high during one clock pulse.
|
|
;
|
|
; Input:
|
|
; Using MMIO Base in PHW_DEVICE_EXTENSION
|
|
;
|
|
; Output:
|
|
;
|
|
;***************************************************************/
|
|
|
|
VOID I2C_NackWrite (PHW_DEVICE_EXTENSION HwDeviceExtension)
|
|
{
|
|
|
|
I2C_BitWrite (HwDeviceExtension, 02);
|
|
}
|
|
|
|
|
|
/****************************************************************
|
|
; I2C_BitRead
|
|
;
|
|
; Reads in 1 bit from SDA via the GIP.
|
|
;
|
|
; Input:
|
|
; Using MMIO Base in PHW_DEVICE_EXTENSION
|
|
;
|
|
; Output:
|
|
; Bit 0 of return value contains bit read
|
|
;
|
|
;***************************************************************/
|
|
|
|
UCHAR I2C_BitRead (PHW_DEVICE_EXTENSION HwDeviceExtension)
|
|
{
|
|
UCHAR ucRetval;
|
|
|
|
//
|
|
// CLK=low, DATA=high
|
|
//
|
|
|
|
I2C_Out (HwDeviceExtension, 0x02);
|
|
|
|
//
|
|
// CLK=high, DATA=high
|
|
//
|
|
|
|
I2C_Out (HwDeviceExtension, 0x03);
|
|
|
|
//
|
|
// now read in the data bit
|
|
//
|
|
|
|
ucRetval = (VideoPortReadRegisterUchar (MMFF20) & 0x08) >> 3;
|
|
|
|
//
|
|
// CLK=low, DATA=high
|
|
//
|
|
|
|
I2C_Out (HwDeviceExtension, 0x02);
|
|
|
|
return (ucRetval);
|
|
}
|
|
|
|
|
|
/****************************************************************
|
|
; I2C_ByteRead
|
|
;
|
|
; Read a byte of information from the Display
|
|
;
|
|
; Input:
|
|
; Using MMIO Base in PHW_DEVICE_EXTENSION
|
|
;
|
|
; Output:
|
|
; return value is the byte read
|
|
;
|
|
;***************************************************************/
|
|
|
|
UCHAR I2C_ByteRead (PHW_DEVICE_EXTENSION HwDeviceExtension)
|
|
{
|
|
UCHAR ucRetval;
|
|
int i;
|
|
|
|
ucRetval = 0;
|
|
for (i=0; i < 8; i++)
|
|
{
|
|
ucRetval <<= 1;
|
|
ucRetval |= I2C_BitRead (HwDeviceExtension);
|
|
}
|
|
|
|
return (ucRetval);
|
|
|
|
}
|
|
|
|
|
|
/****************************************************************
|
|
; I2C_DATA_Request
|
|
;
|
|
; Setup Display to query EDID or VDIF information depending
|
|
; upon the offset given.
|
|
;
|
|
; Input:
|
|
; Using MMIO Base in PHW_DEVICE_EXTENSION
|
|
; ucWriteAddr Write Address of info
|
|
; lLength Length to read,
|
|
; lFlags VERIFY_CHECKSUM
|
|
; pBuffer pointer to buffer to receive data
|
|
;
|
|
; Output:
|
|
; TRUE successful read
|
|
; FALSE read failure or bad checksum
|
|
;
|
|
;****************************************************************/
|
|
|
|
UCHAR I2C_Data_Request ( PHW_DEVICE_EXTENSION HwDeviceExtension,
|
|
UCHAR ucWriteAddr,
|
|
long lLength,
|
|
long lFlags,
|
|
UCHAR *pBuffer )
|
|
{
|
|
UCHAR ucData;
|
|
UCHAR ucCheckSum = 0;
|
|
long lCount;
|
|
|
|
I2C_StartService (HwDeviceExtension);
|
|
I2C_ByteWrite (HwDeviceExtension, 0xA0); //Send Device Address + write
|
|
|
|
I2C_ByteWrite (HwDeviceExtension, ucWriteAddr); //Send Write Address
|
|
|
|
I2C_StartService (HwDeviceExtension);
|
|
I2C_ByteWrite (HwDeviceExtension, 0xA1); //Send Device Address + read
|
|
|
|
for (lCount = 0; lCount < lLength - 1; lCount++)
|
|
{
|
|
ucData= I2C_ByteRead (HwDeviceExtension);
|
|
I2C_AckWrite (HwDeviceExtension);
|
|
*pBuffer++ = ucData;
|
|
ucCheckSum += ucData;
|
|
}
|
|
|
|
ucData= I2C_ByteRead (HwDeviceExtension);
|
|
I2C_NackWrite (HwDeviceExtension);
|
|
*pBuffer = ucData;
|
|
ucCheckSum += ucData;
|
|
I2C_StopService (HwDeviceExtension);
|
|
|
|
|
|
if (lFlags & VERIFY_CHECKSUM)
|
|
{
|
|
if (ucCheckSum)
|
|
{
|
|
return (FALSE); // bad checksum
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
|
|
}
|
|
|
|
|
|
/****************************************************************
|
|
; GetDdcInformation
|
|
;
|
|
; Get 128 bytes EDID information if the monitor supports it.
|
|
; The caller is responsible for allocating the memory.
|
|
;
|
|
; Input:
|
|
; Using MMIO Base in PHW_DEVICE_EXTENSION
|
|
; Buffer to receive information
|
|
;
|
|
; Output:
|
|
; TRUE successful
|
|
; FALSE cannot get DdcInformation
|
|
;
|
|
;***************************************************************/
|
|
|
|
UCHAR GetDdcInformation (PHW_DEVICE_EXTENSION HwDeviceExtension, UCHAR* pBuffer)
|
|
{
|
|
UCHAR ucOldCr40;
|
|
UCHAR ucOldCr53;
|
|
UCHAR ucOldCr55;
|
|
UCHAR ucOldCr5C;
|
|
UCHAR ucOldSr0D;
|
|
UCHAR ucOldSr08;
|
|
UCHAR ucOldMMFF20;
|
|
UCHAR ucData;
|
|
UCHAR ucRetval;
|
|
|
|
//
|
|
// unlock the Sequencer registers
|
|
//
|
|
|
|
VideoPortWritePortUchar (SEQ_ADDRESS_REG, UNLOCK_SEQREG);
|
|
ucOldSr08 = ucData = VideoPortReadPortUchar (SEQ_DATA_REG);
|
|
ucData = UNLOCK_SEQ;
|
|
VideoPortWritePortUchar (SEQ_DATA_REG, ucData);
|
|
|
|
|
|
VideoPortWritePortUchar (SEQ_ADDRESS_REG, SRD_SEQREG);
|
|
ucOldSr0D = ucData = VideoPortReadPortUchar (SEQ_DATA_REG);
|
|
ucData &= DISAB_FEATURE_BITS; // Disable feature connector
|
|
|
|
VideoPortWritePortUchar (SEQ_DATA_REG, ucData);
|
|
|
|
//
|
|
// Enable access to the enhanced registers
|
|
//
|
|
|
|
VideoPortWritePortUchar (CRT_ADDRESS_REG, SYS_CONFIG_S3EXTREG);
|
|
ucOldCr40 = ucData = VideoPortReadPortUchar (CRT_DATA_REG);
|
|
ucData |= ENABLE_ENH_REG_ACCESS;
|
|
VideoPortWritePortUchar (CRT_DATA_REG, ucData);
|
|
|
|
//
|
|
// Enable MMIO
|
|
//
|
|
|
|
VideoPortWritePortUchar (CRT_ADDRESS_REG, EXT_MEM_CTRL1_S3EXTREG);
|
|
ucOldCr53 = ucData = VideoPortReadPortUchar (CRT_DATA_REG);
|
|
ucData |= (ENABLE_OLDMMIO | ENABLE_NEWMMIO);
|
|
VideoPortWritePortUchar (CRT_DATA_REG, ucData);
|
|
|
|
//
|
|
// GOP_1:0=00b, select MUX channel 0
|
|
//
|
|
|
|
VideoPortWritePortUchar (CRT_ADDRESS_REG, GENERAL_OUT_S3EXTREG);
|
|
ucOldCr5C = ucData = VideoPortReadPortUchar (CRT_DATA_REG);
|
|
ucData |= 0x03;
|
|
VideoPortWritePortUchar (CRT_DATA_REG, ucData);
|
|
|
|
//
|
|
// enable general input port
|
|
//
|
|
|
|
VideoPortWritePortUchar (CRT_ADDRESS_REG, EXT_DAC_S3EXTREG);
|
|
ucOldCr55 = VideoPortReadPortUchar (CRT_DATA_REG);
|
|
|
|
//
|
|
// the 764 doesn't support MMFF20
|
|
//
|
|
// enable the General Input Port
|
|
//
|
|
|
|
if (HwDeviceExtension->SubTypeID == SUBTYPE_764)
|
|
{
|
|
VideoPortWritePortUchar (CRT_DATA_REG,
|
|
(UCHAR) (ucOldCr55 | ENABLE_GEN_INPORT_READ));
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// enable the serial port
|
|
//
|
|
|
|
ucOldMMFF20 = VideoPortReadRegisterUchar (MMFF20);
|
|
VideoPortWriteRegisterUchar (MMFF20, 0x13);
|
|
}
|
|
|
|
//
|
|
// determine DDC capabilities and branch accordingly
|
|
//
|
|
|
|
switch ( Configure_Chip_DDC_Caps (HwDeviceExtension) )
|
|
{
|
|
case DDC2:
|
|
I2C_Setup (HwDeviceExtension);
|
|
|
|
ucRetval = I2C_Data_Request (
|
|
HwDeviceExtension,
|
|
0, // address offset
|
|
128, // read 128 bytes
|
|
VERIFY_CHECKSUM, // verify checksum
|
|
pBuffer); // buffer to put data
|
|
break;
|
|
|
|
case DDC1:
|
|
Disable_DAC_Video (HwDeviceExtension);
|
|
|
|
//
|
|
// first try to sync with the EDID header
|
|
//
|
|
|
|
if (ucRetval = Sync_EDID_Header (HwDeviceExtension))
|
|
{
|
|
//
|
|
// now read in the remainder of the information
|
|
//
|
|
|
|
ucRetval = EDID_Buffer_Xfer (HwDeviceExtension, pBuffer);
|
|
}
|
|
Enable_DAC_Video (HwDeviceExtension);
|
|
break;
|
|
|
|
default:
|
|
ucRetval = FALSE; // failure
|
|
break;
|
|
|
|
}
|
|
|
|
//
|
|
// restore the original register values
|
|
//
|
|
|
|
if (HwDeviceExtension->SubTypeID != SUBTYPE_764)
|
|
{
|
|
VideoPortWriteRegisterUchar (MMFF20, ucOldMMFF20);
|
|
}
|
|
|
|
VideoPortWritePortUchar (CRT_ADDRESS_REG, EXT_DAC_S3EXTREG);
|
|
VideoPortWritePortUchar (CRT_DATA_REG, ucOldCr55);
|
|
|
|
|
|
VideoPortWritePortUchar (CRT_ADDRESS_REG, GENERAL_OUT_S3EXTREG);
|
|
VideoPortWritePortUchar (CRT_DATA_REG, ucOldCr5C);
|
|
|
|
VideoPortWritePortUchar (CRT_ADDRESS_REG, EXT_MEM_CTRL1_S3EXTREG);
|
|
VideoPortWritePortUchar (CRT_DATA_REG, ucOldCr53);
|
|
|
|
VideoPortWritePortUchar (CRT_ADDRESS_REG, SYS_CONFIG_S3EXTREG);
|
|
VideoPortWritePortUchar (CRT_DATA_REG, ucOldCr40);
|
|
|
|
VideoPortWritePortUchar (SEQ_ADDRESS_REG, SRD_SEQREG);
|
|
VideoPortWritePortUchar (SEQ_DATA_REG, ucOldSr0D);
|
|
|
|
VideoPortWritePortUchar (SEQ_ADDRESS_REG, UNLOCK_SEQREG);
|
|
VideoPortWritePortUchar (SEQ_DATA_REG, ucOldSr08);
|
|
|
|
return (ucRetval);
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************
|
|
; Wait_For_Active
|
|
;
|
|
; Use two loop method to find VSYNC then return just after the
|
|
; falling edge.
|
|
;
|
|
; Input:
|
|
; Using MMIO Base in PHW_DEVICE_EXTENSION
|
|
;
|
|
; Output:
|
|
;
|
|
;***************************************************************/
|
|
|
|
VOID Wait_For_Active (PHW_DEVICE_EXTENSION HwDeviceExtension)
|
|
{
|
|
PUCHAR InStatPort = SYSTEM_CONTROL_REG;
|
|
|
|
while ((VideoPortReadPortUchar (InStatPort) & VSYNC_ACTIVE) != 0) ;
|
|
while ((VideoPortReadPortUchar (InStatPort) & VSYNC_ACTIVE) == 0) ;
|
|
}
|
|
|
|
/****************************************************************
|
|
; Set_VSYNC
|
|
;
|
|
; Read the current polarity of the sync, then toggle it on
|
|
; if ucFlag=1, or off if ucFlag=0.
|
|
;
|
|
; Input:
|
|
; using Seq. registers PHW_DEVICE_EXTENSION
|
|
; ucFlag - see above comment
|
|
;
|
|
; Output:
|
|
;
|
|
;****************************************************************/
|
|
|
|
VOID Set_Vsync (PHW_DEVICE_EXTENSION HwDeviceExtension, UCHAR ucFlag)
|
|
{
|
|
|
|
UCHAR ucData;
|
|
|
|
//
|
|
// read Sequencer Register D and clear VSYNC bits
|
|
//
|
|
|
|
VideoPortWritePortUchar (SEQ_ADDRESS_REG, SRD_SEQREG);
|
|
ucData = VideoPortReadPortUchar (SEQ_DATA_REG) & CLEAR_VSYNC;
|
|
|
|
//
|
|
// set VSYNC per the input flag
|
|
//
|
|
|
|
if (ucFlag)
|
|
ucData = ((ucData & CLEAR_VSYNC) | SET_VSYNC1);
|
|
else
|
|
ucData = ((ucData & CLEAR_VSYNC) | SET_VSYNC0);
|
|
|
|
VideoPortWritePortUchar (SEQ_DATA_REG, ucData);
|
|
}
|
|
|
|
/****************************************************************
|
|
; Provide_Fake_VSYNC
|
|
;
|
|
; Use loop delays to create a fake VSYNC signal. (~14.9KHz)
|
|
;
|
|
; Input:
|
|
; using Seq. registers PHW_DEVICE_EXTENSION
|
|
;
|
|
; Output:
|
|
;
|
|
;***************************************************************/
|
|
|
|
VOID Provide_Fake_VSYNC (PHW_DEVICE_EXTENSION HwDeviceExtension)
|
|
{
|
|
int i;
|
|
|
|
Set_Vsync (HwDeviceExtension, 0x01); // Turn on VSYNC
|
|
VideoPortStallExecution(5);
|
|
|
|
Set_Vsync (HwDeviceExtension, 0x00); // Turn off VSYNC
|
|
VideoPortStallExecution(5);
|
|
|
|
}
|
|
|
|
|
|
/****************************************************************
|
|
; Disable_DAC_Video
|
|
;
|
|
; Disable the DAC video driving BLANK active high. This is
|
|
; done by setting bit D5 of sequencer register 01.
|
|
;****************************************************************/
|
|
|
|
VOID Disable_DAC_Video (PHW_DEVICE_EXTENSION HwDeviceExtension)
|
|
{
|
|
UCHAR ucIndex;
|
|
UCHAR ucData;
|
|
|
|
|
|
ucIndex = VideoPortReadPortUchar (SEQ_ADDRESS_REG);
|
|
|
|
|
|
VideoPortWritePortUchar (SEQ_ADDRESS_REG, CLK_MODE_SEQREG);
|
|
|
|
//
|
|
// set screen off bit
|
|
//
|
|
|
|
ucData = VideoPortReadPortUchar (SEQ_DATA_REG) | SCREEN_OFF_BIT;
|
|
|
|
VideoPortWritePortUchar (SEQ_DATA_REG, ucData);
|
|
|
|
//
|
|
// restore old index value
|
|
//
|
|
|
|
VideoPortWritePortUchar (SEQ_ADDRESS_REG, ucIndex);
|
|
|
|
}
|
|
|
|
/****************************************************************
|
|
; Disable_DAC_Video
|
|
;
|
|
; Enable the DAC video by clearing bit D5 in sequencer register 01
|
|
;***************************************************************/
|
|
|
|
VOID Enable_DAC_Video (PHW_DEVICE_EXTENSION HwDeviceExtension)
|
|
{
|
|
UCHAR ucIndex;
|
|
UCHAR ucData;
|
|
|
|
|
|
ucIndex = VideoPortReadPortUchar (SEQ_ADDRESS_REG);
|
|
|
|
|
|
VideoPortWritePortUchar (SEQ_ADDRESS_REG, CLK_MODE_SEQREG);
|
|
|
|
//
|
|
// clear screen off bit
|
|
//
|
|
|
|
ucData = VideoPortReadPortUchar (SEQ_DATA_REG) & (~SCREEN_OFF_BIT);
|
|
|
|
VideoPortWritePortUchar (SEQ_DATA_REG, ucData);
|
|
|
|
//
|
|
// restore old Index value
|
|
//
|
|
|
|
VideoPortWritePortUchar (SEQ_ADDRESS_REG, ucIndex);
|
|
|
|
}
|
|
|
|
|
|
/****************************************************************
|
|
; Read_EDID_Bit:
|
|
;
|
|
; Read the next DDC1 EDID data bit
|
|
;
|
|
; Inputs:
|
|
; PHW_DEVICE_EXTENSION HwDeviceExtension
|
|
;
|
|
; Return:
|
|
; UCHAR ucData - data in bit 0
|
|
;
|
|
;***************************************************************/
|
|
|
|
UCHAR Read_EDID_Bit (PHW_DEVICE_EXTENSION HwDeviceExtension)
|
|
|
|
{
|
|
switch (HwDeviceExtension->SubTypeID)
|
|
{
|
|
case SUBTYPE_764:
|
|
return (VideoPortReadPortUchar (DAC_ADDRESS_WRITE_PORT) & 1);
|
|
break;
|
|
|
|
default:
|
|
return ((VideoPortReadRegisterUchar (MMFF20) & 8) >> 3);
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
/****************************************************************
|
|
; Read_EDID_Byte
|
|
;
|
|
; Reads eight bits from the EDID string
|
|
;
|
|
; Input:
|
|
; Using MMIO Base in PHW_DEVICE_EXTENSION
|
|
;
|
|
; Output:
|
|
; return byte value
|
|
;
|
|
;****************************************************************/
|
|
|
|
UCHAR Read_EDID_Byte (PHW_DEVICE_EXTENSION HwDeviceExtension)
|
|
{
|
|
long i;
|
|
UCHAR ucRetData;
|
|
|
|
ucRetData = 0;
|
|
for (i=0; i < 8; i++)
|
|
{
|
|
ucRetData <<= 1;
|
|
Provide_Fake_VSYNC (HwDeviceExtension);
|
|
ucRetData |= Read_EDID_Bit (HwDeviceExtension);
|
|
}
|
|
|
|
return (ucRetData);
|
|
}
|
|
|
|
|
|
/****************************************************************
|
|
; Sync_EDID_Header
|
|
;
|
|
; Find and sync to the header - 00 FF FF FF FF FF FF 00
|
|
;
|
|
; Inputs:
|
|
; Using MMIO Base in PHW_DEVICE_EXTENSION
|
|
;
|
|
; Outputs:
|
|
; TRUE = Header Found
|
|
; FALSE = Header NOT Found
|
|
;
|
|
;***************************************************************/
|
|
|
|
UCHAR Sync_EDID_Header (PHW_DEVICE_EXTENSION HwDeviceExtension)
|
|
{
|
|
|
|
long lBitCount;
|
|
long lEndCount;
|
|
UCHAR uInSync;
|
|
UCHAR ucEdidData;
|
|
|
|
//
|
|
// there are 8 * 128 bits total, but we could start reading near
|
|
// the end of the header and realize the error after starting into
|
|
// the beginning of the header and have to read the entire header
|
|
// again, so we will try reading up to 144 bytes for safety
|
|
//
|
|
// the header is 00 FF FF FF FF FF FF 00
|
|
//
|
|
|
|
lBitCount = 0; // init bit counter
|
|
do
|
|
{
|
|
uInSync = TRUE; // assume found header
|
|
|
|
//
|
|
// looking for 00
|
|
// checking first bit
|
|
//
|
|
|
|
for (lEndCount = lBitCount + 8; lBitCount < lEndCount; lBitCount++)
|
|
{
|
|
Provide_Fake_VSYNC (HwDeviceExtension);
|
|
ucEdidData = Read_EDID_Bit (HwDeviceExtension);
|
|
|
|
if (ucEdidData == 1)
|
|
{
|
|
uInSync = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!uInSync)
|
|
continue; // start all over
|
|
|
|
//
|
|
// send ACK
|
|
//
|
|
|
|
Provide_Fake_VSYNC (HwDeviceExtension);
|
|
|
|
//
|
|
// looking for FF FF FF FF FF FF
|
|
// 8 data bits
|
|
// 1 bit of acknowledgement
|
|
//
|
|
|
|
for (lEndCount = lBitCount + 6 * 8; lBitCount < lEndCount; lBitCount++)
|
|
{
|
|
Provide_Fake_VSYNC (HwDeviceExtension);
|
|
ucEdidData = Read_EDID_Bit (HwDeviceExtension);
|
|
|
|
if (ucEdidData == 0)
|
|
{
|
|
uInSync = FALSE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// send an ACK if we have read 8 bits
|
|
//
|
|
|
|
if (!((lEndCount - lBitCount + 1) % 8))
|
|
{
|
|
Provide_Fake_VSYNC (HwDeviceExtension);
|
|
}
|
|
|
|
}
|
|
if (!uInSync)
|
|
continue; // start all over
|
|
|
|
//
|
|
// now looking for last 00 of header
|
|
//
|
|
|
|
for (lEndCount = lBitCount + 8; lBitCount < lEndCount; lBitCount++)
|
|
{
|
|
Provide_Fake_VSYNC (HwDeviceExtension);
|
|
ucEdidData = Read_EDID_Bit (HwDeviceExtension);
|
|
|
|
if (ucEdidData == 1)
|
|
{
|
|
uInSync = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(!uInSync)
|
|
continue; // start all over
|
|
|
|
//
|
|
// Acknowledgment
|
|
//
|
|
|
|
Provide_Fake_VSYNC (HwDeviceExtension);
|
|
|
|
|
|
} while ( (!uInSync) && (lBitCount < (8 * 144)) );
|
|
|
|
return (uInSync);
|
|
}
|
|
|
|
|
|
/****************************************************************
|
|
; EDID_Buffer_Xfer
|
|
;
|
|
; Transfer all EDID data to pBuffer. Caller must allocate enough
|
|
; memory to receive 128 bytes.
|
|
;
|
|
; Input:
|
|
; Using MMIO Base in PHW_DEVICE_EXTENSION
|
|
; Pointer to receive buffer
|
|
;
|
|
; Output:
|
|
; TRUE data in buffer & checksum is correct
|
|
; FALSE error or bad checksum
|
|
;
|
|
;****************************************************************/
|
|
|
|
UCHAR EDID_Buffer_Xfer (PHW_DEVICE_EXTENSION HwDeviceExtension, UCHAR* pBuffer)
|
|
{
|
|
UCHAR ucChecksum = 0x0FA;
|
|
UCHAR ucEdidData;
|
|
unsigned int uCount;
|
|
|
|
//
|
|
// put the 8 header bytes in the buffer
|
|
//
|
|
|
|
*pBuffer = 0;
|
|
for (uCount = 1; uCount < 7; uCount++)
|
|
*(pBuffer+uCount) = 0xFF;
|
|
|
|
*(pBuffer+uCount) = 0x00;
|
|
|
|
for (uCount = 8; uCount < 128; uCount++)
|
|
{
|
|
ucEdidData = Read_EDID_Byte (HwDeviceExtension);
|
|
|
|
//
|
|
// send Acknowledgment
|
|
// add data to buffer
|
|
// add data to checksum
|
|
//
|
|
|
|
Provide_Fake_VSYNC (HwDeviceExtension);
|
|
*(pBuffer+uCount) = ucEdidData;
|
|
ucChecksum += ucEdidData;
|
|
}
|
|
|
|
if (!ucChecksum)
|
|
{
|
|
return (TRUE); // checksum is OK
|
|
}
|
|
|
|
return (FALSE); // checksum is NOT
|
|
}
|
|
|
|
|
|
/****************************************************************
|
|
; Check_DDC1_Monitor
|
|
;
|
|
; Check for a DDC1 monitor using current vsync.
|
|
;
|
|
; Input:
|
|
; Using MMIO Base in PHW_DEVICE_EXTENSION
|
|
;
|
|
; Output:
|
|
; TRUE possible DDC1 monitor
|
|
; FALSE no EDID data detected on input port
|
|
;
|
|
;****************************************************************/
|
|
|
|
UCHAR Check_DDC1_Monitor (PHW_DEVICE_EXTENSION HwDeviceExtension)
|
|
{
|
|
|
|
UCHAR ucSaveOldData;
|
|
UCHAR ucData;
|
|
UCHAR ucGD0;
|
|
unsigned int uCount;
|
|
UCHAR ucDDC1;
|
|
|
|
//
|
|
// assume not DDC1
|
|
//
|
|
|
|
ucDDC1 = FALSE;
|
|
|
|
switch (HwDeviceExtension->SubTypeID)
|
|
{
|
|
//
|
|
// use reads from 3C8 on the 764 (undocumented, but this use
|
|
// of the DAC register comes from the 764 BIOS source code).
|
|
//
|
|
|
|
case SUBTYPE_764:
|
|
ucSaveOldData = VideoPortReadPortUchar (MISC_OUTPUT_REG_READ);
|
|
|
|
//
|
|
// Bit 7 = 0 Positive VSYNC
|
|
//
|
|
VideoPortWritePortUchar (MISC_OUTPUT_REG_WRITE,
|
|
(UCHAR) (ucSaveOldData & SEL_POS_VSYNC));
|
|
Wait_For_Active (HwDeviceExtension);
|
|
|
|
|
|
ucData = VideoPortReadPortUchar (DAC_ADDRESS_WRITE_PORT);
|
|
|
|
//
|
|
// Another read for VL systems. (Data left on the GD/SD lines)
|
|
//
|
|
|
|
ucGD0 = VideoPortReadPortUchar (DAC_ADDRESS_WRITE_PORT) & 0x01;
|
|
|
|
//
|
|
// read up to 350 bits looking for the data to toggle, indicating
|
|
// DDC1 data is being sent
|
|
//
|
|
|
|
for (uCount = 0; uCount < 350; uCount++)
|
|
{
|
|
Wait_For_Active (HwDeviceExtension);
|
|
ucData = VideoPortReadPortUchar (DAC_ADDRESS_WRITE_PORT) & 0x01;
|
|
if (ucData != ucGD0)
|
|
{
|
|
//
|
|
// data line toggled, assume DDC1 data is being sent
|
|
//
|
|
|
|
ucDDC1 = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// restore old value
|
|
//
|
|
|
|
VideoPortWritePortUchar (MISC_OUTPUT_REG_WRITE, ucSaveOldData);
|
|
break;
|
|
|
|
//
|
|
// else use MMFF20 on the other chips
|
|
//
|
|
|
|
default:
|
|
Disable_DAC_Video (HwDeviceExtension);
|
|
Provide_Fake_VSYNC (HwDeviceExtension);
|
|
ucGD0 = VideoPortReadRegisterUchar (MMFF20) & 8;
|
|
|
|
for (uCount = 0; uCount < 350; uCount++)
|
|
{
|
|
Provide_Fake_VSYNC (HwDeviceExtension);
|
|
ucData = VideoPortReadRegisterUchar (MMFF20) & 8;
|
|
|
|
if (ucData != ucGD0)
|
|
{
|
|
//
|
|
// data line toggled, assume DDC1 data is being sent
|
|
//
|
|
|
|
ucDDC1 = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
Enable_DAC_Video (HwDeviceExtension);
|
|
break;
|
|
|
|
}
|
|
|
|
return (ucDDC1);
|
|
|
|
}
|
|
|
|
/****************************************************************
|
|
; Configure_Chip_DDC_Caps
|
|
;
|
|
; Determine DDC capabilities of display.
|
|
;
|
|
; Input:
|
|
; Using MMIO Base in PHW_DEVICE_EXTENSION
|
|
;
|
|
; Output:
|
|
; NO_DDC
|
|
; DDC1: Support DDC1
|
|
; DDC2: Support DDC2
|
|
;
|
|
;****************************************************************/
|
|
|
|
UCHAR Configure_Chip_DDC_Caps (PHW_DEVICE_EXTENSION HwDeviceExtension)
|
|
{
|
|
UCHAR ucBuffer[2];
|
|
|
|
//
|
|
// we will only use DDC1 on 764
|
|
//
|
|
|
|
if (HwDeviceExtension->SubTypeID != SUBTYPE_764)
|
|
{
|
|
//
|
|
// first check if DDC2 capable
|
|
//
|
|
|
|
I2C_Setup (HwDeviceExtension);
|
|
I2C_Data_Request ( HwDeviceExtension,
|
|
0, // address offset
|
|
2, // look at first 2 bytes
|
|
NO_FLAGS, // don't verify checksum
|
|
ucBuffer ); // buffer to place data
|
|
|
|
//
|
|
// check if the first 2 bytes of the EDID header look correct
|
|
//
|
|
|
|
if ( (ucBuffer [0] == 0) &&
|
|
(ucBuffer [1] == 0xFF) )
|
|
{
|
|
return (DDC2); // assume DDC2 capable
|
|
}
|
|
}
|
|
|
|
//
|
|
// try DDC1
|
|
//
|
|
|
|
if (Check_DDC1_Monitor (HwDeviceExtension))
|
|
{
|
|
return (DDC1);
|
|
}
|
|
|
|
return (NO_DDC);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
ULONG DdcMaxRefresh(ULONG uXresolution, UCHAR * pEdid)
|
|
{
|
|
ULONG uMaxFreq = 0;
|
|
ULONG uEdidRes;
|
|
ULONG uEdidFreq;
|
|
ULONG HorRes, VertRes;
|
|
ULONG i, Index;
|
|
|
|
//
|
|
// Detailed timing
|
|
//
|
|
|
|
for (i = 0; i < 4; ++i) // 4 Detailed Descriptions
|
|
{
|
|
Index = 54 + i * 18;
|
|
if ( (pEdid [Index] == 0) &&
|
|
(pEdid [Index + 1] == 0) &&
|
|
(pEdid [Index + 2] == 0) )
|
|
{
|
|
continue; // Monitor descriptor block, skip it
|
|
}
|
|
|
|
HorRes = ((ULONG) (pEdid [Index + 4] & 0xF0)) << 4;
|
|
HorRes += (ULONG) pEdid [Index + 2];
|
|
|
|
if (HorRes == uXresolution)
|
|
{
|
|
//
|
|
// add Horizontal blanking
|
|
//
|
|
|
|
HorRes += (ULONG) pEdid [Index + 3];
|
|
HorRes += ((ULONG) (pEdid [Index + 4] & 0x0F)) << 8;
|
|
|
|
//
|
|
// now get Vertical Total (Active & Blanking)
|
|
//
|
|
|
|
VertRes = ((ULONG) (pEdid [Index + 7] & 0xF0)) << 4;
|
|
VertRes += ((ULONG) (pEdid [Index + 7] & 0x0F)) << 8;
|
|
VertRes += (ULONG) pEdid [Index + 5];
|
|
VertRes += (ULONG) pEdid [Index + 6];
|
|
|
|
uEdidFreq = (((ULONG) pEdid [Index + 1]) << 8) +
|
|
((ULONG) pEdid [Index]);
|
|
|
|
uEdidFreq = uEdidFreq * 10000 / HorRes / VertRes;
|
|
|
|
if (uEdidFreq > uMaxFreq)
|
|
{
|
|
uMaxFreq = uEdidFreq;
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// Standard timing id.
|
|
//
|
|
|
|
for (i = 38; i < 54; i += 2)
|
|
{
|
|
uEdidRes = (((ULONG) pEdid[i]) + 31) * 8;
|
|
if (uXresolution == uEdidRes)
|
|
{
|
|
uEdidFreq = (((ULONG) pEdid[i+1]) & 0x3F) + 60;
|
|
if (uEdidFreq > uMaxFreq)
|
|
{
|
|
uMaxFreq = uEdidFreq;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Established timing
|
|
//
|
|
|
|
switch (uXresolution)
|
|
{
|
|
case 640:
|
|
uEdidFreq = (ULONG)pEdid[0x23];
|
|
if (uEdidFreq & 0x020)
|
|
{
|
|
if (uMaxFreq < 60)
|
|
{
|
|
uMaxFreq = 60;
|
|
}
|
|
}
|
|
if (uEdidFreq & 0x08)
|
|
{
|
|
if (uMaxFreq < 72)
|
|
{
|
|
uMaxFreq = 72;
|
|
}
|
|
}
|
|
if (uEdidFreq & 0x04)
|
|
{
|
|
if (uMaxFreq < 75)
|
|
{
|
|
uMaxFreq = 75;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 800:
|
|
uEdidFreq = (ULONG)pEdid[0x23];
|
|
if (uEdidFreq & 0x02)
|
|
{
|
|
if (uMaxFreq < 56)
|
|
{
|
|
uMaxFreq = 56;
|
|
}
|
|
}
|
|
if (uEdidFreq & 0x01)
|
|
{
|
|
if (uMaxFreq < 60)
|
|
{
|
|
uMaxFreq = 60;
|
|
}
|
|
}
|
|
|
|
uEdidFreq = (ULONG)pEdid[0x24];
|
|
if (uEdidFreq & 0x80)
|
|
{
|
|
if (uMaxFreq < 72)
|
|
{
|
|
uMaxFreq = 72;
|
|
}
|
|
}
|
|
if (uEdidFreq & 0x40)
|
|
{
|
|
if (uMaxFreq < 75)
|
|
{
|
|
uMaxFreq = 75;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 1024:
|
|
uEdidFreq = (ULONG)pEdid[0x24];
|
|
if (uEdidFreq & 0x08)
|
|
{
|
|
if (uMaxFreq < 60)
|
|
{
|
|
uMaxFreq = 60;
|
|
}
|
|
}
|
|
if (uEdidFreq & 0x04)
|
|
{
|
|
if (uMaxFreq < 70)
|
|
{
|
|
uMaxFreq = 70;
|
|
}
|
|
}
|
|
if (uEdidFreq & 0x02)
|
|
{
|
|
if (uMaxFreq < 75)
|
|
{
|
|
uMaxFreq = 75;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 1280:
|
|
uEdidFreq = (ULONG)pEdid[0x24];
|
|
if (uEdidFreq & 0x01)
|
|
{
|
|
if (uMaxFreq < 75)
|
|
{
|
|
uMaxFreq = 75;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return(uMaxFreq);
|
|
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
ULONG DdcRefresh (PHW_DEVICE_EXTENSION hwDeviceExtension, ULONG uXResolution)
|
|
{
|
|
|
|
ULONG lRefresh = 0;
|
|
char szBuffer[200];
|
|
|
|
|
|
if (GetDdcInformation (hwDeviceExtension, szBuffer))
|
|
{
|
|
lRefresh = DdcMaxRefresh (uXResolution, szBuffer);
|
|
}
|
|
|
|
return lRefresh;
|
|
}
|
|
|
|
|
|
/****************************************************************
|
|
; CheckDDCType
|
|
;
|
|
; Check the monitor for DDC type.
|
|
;
|
|
; Input:
|
|
; Using MMIO Base in PHW_DEVICE_EXTENSION
|
|
;
|
|
; Output:
|
|
; NO_DDC non-DDC monitor
|
|
; DDC1 DDC1 monitor
|
|
; DDC2 DDC2 monitor
|
|
;
|
|
;***************************************************************/
|
|
|
|
UCHAR CheckDDCType (PHW_DEVICE_EXTENSION HwDeviceExtension)
|
|
{
|
|
UCHAR ucOldCr40;
|
|
UCHAR ucOldCr53;
|
|
UCHAR ucOldCr55;
|
|
UCHAR ucOldCr5C;
|
|
UCHAR ucOldSr0D;
|
|
UCHAR ucOldSr08;
|
|
UCHAR ucOldMMFF20;
|
|
UCHAR ucData;
|
|
UCHAR ucRetval;
|
|
|
|
//
|
|
// unlock the Sequencer registers
|
|
//
|
|
|
|
VideoPortWritePortUchar (SEQ_ADDRESS_REG, UNLOCK_SEQREG);
|
|
ucOldSr08 = ucData = VideoPortReadPortUchar (SEQ_DATA_REG);
|
|
ucData = UNLOCK_SEQ;
|
|
VideoPortWritePortUchar (SEQ_DATA_REG, ucData);
|
|
|
|
|
|
VideoPortWritePortUchar (SEQ_ADDRESS_REG, SRD_SEQREG);
|
|
ucOldSr0D = ucData = VideoPortReadPortUchar (SEQ_DATA_REG);
|
|
ucData &= DISAB_FEATURE_BITS; // Disable feature connector
|
|
|
|
VideoPortWritePortUchar (SEQ_DATA_REG, ucData);
|
|
|
|
//
|
|
// Enable access to the enhanced registers
|
|
//
|
|
|
|
VideoPortWritePortUchar (CRT_ADDRESS_REG, SYS_CONFIG_S3EXTREG);
|
|
ucOldCr40 = ucData = VideoPortReadPortUchar (CRT_DATA_REG);
|
|
ucData |= ENABLE_ENH_REG_ACCESS;
|
|
VideoPortWritePortUchar (CRT_DATA_REG, ucData);
|
|
|
|
//
|
|
// Enable MMIO
|
|
//
|
|
|
|
VideoPortWritePortUchar (CRT_ADDRESS_REG, EXT_MEM_CTRL1_S3EXTREG);
|
|
ucOldCr53 = ucData = VideoPortReadPortUchar (CRT_DATA_REG);
|
|
ucData |= (ENABLE_OLDMMIO | ENABLE_NEWMMIO);
|
|
VideoPortWritePortUchar (CRT_DATA_REG, ucData);
|
|
|
|
//
|
|
// GOP_1:0=00b, select MUX channel 0
|
|
//
|
|
|
|
VideoPortWritePortUchar (CRT_ADDRESS_REG, GENERAL_OUT_S3EXTREG);
|
|
ucOldCr5C = ucData = VideoPortReadPortUchar (CRT_DATA_REG);
|
|
ucData |= 0x03;
|
|
VideoPortWritePortUchar (CRT_DATA_REG, ucData);
|
|
|
|
//
|
|
// enable general input port
|
|
//
|
|
|
|
VideoPortWritePortUchar (CRT_ADDRESS_REG, EXT_DAC_S3EXTREG);
|
|
ucOldCr55 = VideoPortReadPortUchar (CRT_DATA_REG);
|
|
|
|
//
|
|
// the 764 doesn't support MMFF20
|
|
//
|
|
// enable the General Input Port
|
|
//
|
|
|
|
if (HwDeviceExtension->SubTypeID == SUBTYPE_764)
|
|
{
|
|
VideoPortWritePortUchar (CRT_DATA_REG,
|
|
(UCHAR) (ucOldCr55 | ENABLE_GEN_INPORT_READ));
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// enable the serial port
|
|
//
|
|
|
|
ucOldMMFF20 = VideoPortReadRegisterUchar (MMFF20);
|
|
VideoPortWriteRegisterUchar (MMFF20, 0x13);
|
|
}
|
|
|
|
//
|
|
// determine DDC capabilities and branch accordingly
|
|
//
|
|
|
|
ucRetval = Configure_Chip_DDC_Caps (HwDeviceExtension);
|
|
|
|
//
|
|
// restore the original register values
|
|
//
|
|
|
|
if (HwDeviceExtension->SubTypeID != SUBTYPE_764)
|
|
{
|
|
VideoPortWriteRegisterUchar (MMFF20, ucOldMMFF20);
|
|
}
|
|
|
|
VideoPortWritePortUchar (CRT_ADDRESS_REG, EXT_DAC_S3EXTREG);
|
|
VideoPortWritePortUchar (CRT_DATA_REG, ucOldCr55);
|
|
|
|
|
|
VideoPortWritePortUchar (CRT_ADDRESS_REG, GENERAL_OUT_S3EXTREG);
|
|
VideoPortWritePortUchar (CRT_DATA_REG, ucOldCr5C);
|
|
|
|
VideoPortWritePortUchar (CRT_ADDRESS_REG, EXT_MEM_CTRL1_S3EXTREG);
|
|
VideoPortWritePortUchar (CRT_DATA_REG, ucOldCr53);
|
|
|
|
VideoPortWritePortUchar (CRT_ADDRESS_REG, SYS_CONFIG_S3EXTREG);
|
|
VideoPortWritePortUchar (CRT_DATA_REG, ucOldCr40);
|
|
|
|
VideoPortWritePortUchar (SEQ_ADDRESS_REG, SRD_SEQREG);
|
|
VideoPortWritePortUchar (SEQ_DATA_REG, ucOldSr0D);
|
|
|
|
VideoPortWritePortUchar (SEQ_ADDRESS_REG, UNLOCK_SEQREG);
|
|
VideoPortWritePortUchar (SEQ_DATA_REG, ucOldSr08);
|
|
|
|
return (ucRetval);
|
|
|
|
}
|