windows-nt/Source/XPSP1/NT/drivers/video/ms/s3/mini/ddc.c
2020-09-26 16:20:57 +08:00

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);
}