291 lines
7.6 KiB
C
291 lines
7.6 KiB
C
/*++
|
|
|
|
Copyright (c) 1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ddc.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the code that support DDC querying..
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "s3.h"
|
|
#include "s3ddc.h"
|
|
|
|
#if defined(ALLOC_PRAGMA)
|
|
#pragma alloc_text(PAGE,GetDdcInformation)
|
|
#endif
|
|
|
|
VOID WriteClockLine(PHW_DEVICE_EXTENSION HwDeviceExtension, UCHAR ucData);
|
|
VOID WriteDataLine(PHW_DEVICE_EXTENSION HwDeviceExtension, UCHAR ucData);
|
|
|
|
BOOLEAN ReadClockLine(PHW_DEVICE_EXTENSION HwDeviceExtension);
|
|
BOOLEAN ReadDataLine(PHW_DEVICE_EXTENSION HwDeviceExtension);
|
|
|
|
VOID WaitForVsyncActive(PHW_DEVICE_EXTENSION HwDeviceExtension);
|
|
|
|
/****************************************************************
|
|
; DDC register
|
|
;
|
|
; 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 WriteClockLine(PHW_DEVICE_EXTENSION HwDeviceExtension, UCHAR ucData)
|
|
{
|
|
UCHAR ucPortData;
|
|
|
|
//
|
|
// read the current value and reset the clock line.
|
|
//
|
|
|
|
ucPortData = (VideoPortReadRegisterUchar(MMFF20) & 0xFE) | ucData;
|
|
|
|
VideoPortWriteRegisterUchar(MMFF20, ucPortData);
|
|
|
|
}
|
|
|
|
VOID WriteDataLine(PHW_DEVICE_EXTENSION HwDeviceExtension, UCHAR ucData)
|
|
{
|
|
UCHAR ucPortData;
|
|
|
|
//
|
|
// read the current value and reset the data line.
|
|
//
|
|
|
|
ucPortData = (VideoPortReadRegisterUchar(MMFF20) & 0xFD) | (ucData << 1);
|
|
|
|
VideoPortWriteRegisterUchar(MMFF20, ucPortData);
|
|
}
|
|
|
|
BOOLEAN ReadClockLine(PHW_DEVICE_EXTENSION HwDeviceExtension)
|
|
{
|
|
return ((VideoPortReadRegisterUchar(MMFF20) & 0x04) >> 2);
|
|
}
|
|
|
|
|
|
BOOLEAN ReadDataLine(PHW_DEVICE_EXTENSION HwDeviceExtension)
|
|
{
|
|
return ((VideoPortReadRegisterUchar(MMFF20) & 0x08) >> 3);
|
|
}
|
|
|
|
VOID WaitForVsyncActive(PHW_DEVICE_EXTENSION HwDeviceExtension)
|
|
{
|
|
PUCHAR InStatPort = SYSTEM_CONTROL_REG;
|
|
|
|
while ((VideoPortReadPortUchar(InStatPort) & VSYNC_ACTIVE) != 0) ;
|
|
while ((VideoPortReadPortUchar(InStatPort) & VSYNC_ACTIVE) == 0) ;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
BOOLEAN
|
|
GetDdcInformation(
|
|
PHW_DEVICE_EXTENSION HwDeviceExtension,
|
|
PUCHAR QueryBuffer,
|
|
ULONG BufferSize)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reads the basic EDID structure from the monitor using DDC2.
|
|
|
|
Arguments:
|
|
|
|
HwDeviceExtension - Points to per-adapter device extension.
|
|
|
|
QueryBuffer - Buffer where information will be stored.
|
|
|
|
BufferSize - Size of the buffer to fill.
|
|
|
|
Return Value:
|
|
|
|
Whether the call succeeded or not.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG ulKey;
|
|
UCHAR ucOldCr40;
|
|
UCHAR ucOldCr53;
|
|
UCHAR ucOldCr55;
|
|
UCHAR ucOldCr5C;
|
|
UCHAR ucOldSr0D;
|
|
UCHAR ucOldSr08;
|
|
UCHAR ucOldSeqIdx;
|
|
UCHAR ucOldMMFF20;
|
|
UCHAR ucData;
|
|
|
|
BOOLEAN bRet = FALSE;
|
|
I2C_FNC_TABLE i2c;
|
|
ULONG i;
|
|
|
|
//
|
|
// Right now we only support DDC querying for newer than 732
|
|
//
|
|
|
|
if (HwDeviceExtension->SubTypeID == SUBTYPE_765) {
|
|
|
|
//
|
|
// unlock the Extended registers
|
|
//
|
|
|
|
ulKey = UnlockExtendedRegs(HwDeviceExtension);
|
|
|
|
//
|
|
// save the Sequencer index register
|
|
//
|
|
|
|
ucOldSeqIdx = VideoPortReadPortUchar (SEQ_ADDRESS_REG);
|
|
|
|
//
|
|
// unlock the Sequencer registers
|
|
//
|
|
|
|
VideoPortWritePortUchar (SEQ_ADDRESS_REG, UNLOCK_SEQREG);
|
|
ucOldSr08 = VideoPortReadPortUchar (SEQ_DATA_REG);
|
|
VideoPortWritePortUchar (SEQ_DATA_REG, UNLOCK_SEQ);
|
|
|
|
|
|
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;
|
|
ucData |= 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);
|
|
|
|
//
|
|
// Map the MmIoSpace so that we can use it in DDC detectin.
|
|
//
|
|
|
|
HwDeviceExtension->MmIoBase =
|
|
VideoPortGetDeviceBase(HwDeviceExtension,
|
|
HwDeviceExtension->PhysicalMmIoAddress,
|
|
HwDeviceExtension->MmIoLength,
|
|
0);
|
|
|
|
if (HwDeviceExtension->MmIoBase) {
|
|
|
|
//
|
|
// enable the serial port
|
|
//
|
|
|
|
ucOldMMFF20 = VideoPortReadRegisterUchar (MMFF20);
|
|
VideoPortWriteRegisterUchar (MMFF20, 0x13);
|
|
|
|
//
|
|
// Get DDC Information if all the registers are setup properly.
|
|
//
|
|
|
|
i2c.WriteClockLine = WriteClockLine;
|
|
i2c.WriteDataLine = WriteDataLine;
|
|
i2c.ReadClockLine = ReadClockLine;
|
|
i2c.ReadDataLine = ReadDataLine;
|
|
i2c.WaitVsync = WaitForVsyncActive;
|
|
|
|
i2c.Size = sizeof(I2C_FNC_TABLE);
|
|
|
|
bRet = VideoPortDDCMonitorHelper(HwDeviceExtension,
|
|
&i2c,
|
|
QueryBuffer,
|
|
BufferSize);
|
|
|
|
//
|
|
// restore the original register values
|
|
//
|
|
|
|
VideoPortWriteRegisterUchar (MMFF20, ucOldMMFF20);
|
|
|
|
VideoPortFreeDeviceBase(HwDeviceExtension,
|
|
HwDeviceExtension->MmIoBase);
|
|
}
|
|
|
|
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);
|
|
|
|
VideoPortWritePortUchar (SEQ_ADDRESS_REG, ucOldSeqIdx);
|
|
|
|
LockExtendedRegs(HwDeviceExtension, ulKey);
|
|
}
|
|
|
|
return (bRet);
|
|
}
|