/*++ 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); }