247 lines
6.1 KiB
C
247 lines
6.1 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 <dderror.h>
|
|
#include <devioctl.h>
|
|
#include <miniport.h>
|
|
|
|
#include <ntddvdeo.h>
|
|
#include <video.h>
|
|
|
|
#include <cirrus.h>
|
|
|
|
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 Sr8 to produce
|
|
; clock and data pulses.
|
|
;
|
|
; Sr8 is defined as follows:
|
|
;
|
|
; 7 ... 2 1 0 SCW = CLK Write
|
|
; |---|---|---|---|---| SDW = DATA Write
|
|
; |SDR ...|SCR|SDW|SCW| SCR = CLK Read
|
|
; --------------------- SDR = DATA Read
|
|
;
|
|
;****************************************************************/
|
|
|
|
#define DDC_PORT (HwDeviceExtension->IOAddress + SEQ_DATA_PORT)
|
|
#define STATUS_PORT (HwDeviceExtension->IOAddress + INPUT_STATUS_1_COLOR)
|
|
|
|
#define VSYNC_ACTIVE 0x08
|
|
|
|
VOID WriteClockLine(PHW_DEVICE_EXTENSION HwDeviceExtension, UCHAR ucData)
|
|
{
|
|
UCHAR ucPortData;
|
|
|
|
//
|
|
// read the current value and reset the clock line.
|
|
//
|
|
|
|
ucPortData = (VideoPortReadPortUchar(DDC_PORT) & 0xFE) | ucData;
|
|
|
|
VideoPortWritePortUchar(DDC_PORT, ucPortData);
|
|
}
|
|
|
|
VOID WriteDataLine(PHW_DEVICE_EXTENSION HwDeviceExtension, UCHAR ucData)
|
|
{
|
|
UCHAR ucPortData;
|
|
|
|
//
|
|
// read the current value and reset the data line.
|
|
//
|
|
|
|
ucPortData = (VideoPortReadPortUchar(DDC_PORT) & 0xFD) | (ucData << 1);
|
|
|
|
VideoPortWritePortUchar(DDC_PORT, ucPortData);
|
|
}
|
|
|
|
BOOLEAN ReadClockLine(PHW_DEVICE_EXTENSION HwDeviceExtension)
|
|
{
|
|
UCHAR uc;
|
|
|
|
uc = VideoPortReadPortUchar(DDC_PORT);
|
|
|
|
//VideoDebugPrint((0, "Read = 0x%x\n", uc));
|
|
|
|
return ((VideoPortReadPortUchar(DDC_PORT) & 0x04) >> 2);
|
|
}
|
|
|
|
|
|
BOOLEAN ReadDataLine(PHW_DEVICE_EXTENSION HwDeviceExtension)
|
|
{
|
|
UCHAR uc;
|
|
|
|
uc = VideoPortReadPortUchar(DDC_PORT);
|
|
|
|
//VideoDebugPrint((0, "Read = 0x%x\n", uc));
|
|
|
|
return ((VideoPortReadPortUchar(DDC_PORT) & 0x80) >> 7);
|
|
}
|
|
|
|
VOID WaitForVsyncActive(PHW_DEVICE_EXTENSION HwDeviceExtension)
|
|
{
|
|
while ((VideoPortReadPortUchar(STATUS_PORT) & VSYNC_ACTIVE) != 0);
|
|
while ((VideoPortReadPortUchar(STATUS_PORT) & 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.
|
|
|
|
--*/
|
|
|
|
{
|
|
UCHAR ucData;
|
|
|
|
BOOLEAN bRet = FALSE;
|
|
I2C_FNC_TABLE i2c;
|
|
ULONG i;
|
|
|
|
UCHAR OldSeqIdx;
|
|
UCHAR ucSr6;
|
|
UCHAR ucSr8;
|
|
|
|
// workaround for Cirrus HW problem (part 1/2)
|
|
static UCHAR onceQueryBuffer [512]; // EDID length is expected to be 128 or 256 bytes
|
|
static UCHAR onceReadAttempt = FALSE;
|
|
static UCHAR onceReturnedValue;
|
|
|
|
if (onceReadAttempt) {
|
|
VideoDebugPrint((1, "CIRRUS: ONCE READ => returning previously obtained data\n"));
|
|
memcpy (QueryBuffer, onceQueryBuffer, BufferSize);
|
|
return onceReturnedValue;
|
|
}
|
|
// end of the workaround (part 1/2)
|
|
|
|
OldSeqIdx = VideoPortReadPortUchar(HwDeviceExtension->IOAddress
|
|
+ SEQ_ADDRESS_PORT);
|
|
|
|
//
|
|
// Make sure the extension registers are unlocked.
|
|
//
|
|
|
|
VideoPortWritePortUchar(
|
|
HwDeviceExtension->IOAddress + SEQ_ADDRESS_PORT,
|
|
0x6);
|
|
|
|
ucSr6 = VideoPortReadPortUchar(
|
|
HwDeviceExtension->IOAddress + SEQ_DATA_PORT);
|
|
|
|
VideoPortWritePortUchar(
|
|
HwDeviceExtension->IOAddress + SEQ_DATA_PORT,
|
|
0x12);
|
|
|
|
VideoPortWritePortUchar(
|
|
HwDeviceExtension->IOAddress + SEQ_ADDRESS_PORT,
|
|
0x08);
|
|
|
|
ucSr8 = VideoPortReadPortUchar(
|
|
HwDeviceExtension->IOAddress + SEQ_DATA_PORT);
|
|
|
|
VideoPortWritePortUchar(
|
|
HwDeviceExtension->IOAddress + SEQ_DATA_PORT,
|
|
(UCHAR)(ucSr8 | 0x40));
|
|
|
|
i2c.WriteClockLine = WriteClockLine;
|
|
i2c.WriteDataLine = WriteDataLine;
|
|
i2c.ReadClockLine = ReadClockLine;
|
|
i2c.ReadDataLine = ReadDataLine;
|
|
i2c.WaitVsync = WaitForVsyncActive;
|
|
|
|
i2c.Size = sizeof(I2C_FNC_TABLE);
|
|
|
|
// 5430/5440 has a problem doing DDC unless we wait for vsync first.
|
|
|
|
if (HwDeviceExtension->ChipType == CL543x && HwDeviceExtension->ChipRevision == CL5430_ID)
|
|
{
|
|
WaitForVsyncActive(HwDeviceExtension);
|
|
}
|
|
|
|
bRet = VideoPortDDCMonitorHelper(HwDeviceExtension,
|
|
&i2c,
|
|
QueryBuffer,
|
|
BufferSize);
|
|
|
|
VideoPortWritePortUchar(
|
|
HwDeviceExtension->IOAddress + SEQ_ADDRESS_PORT,
|
|
0x08);
|
|
|
|
VideoPortWritePortUchar(
|
|
HwDeviceExtension->IOAddress + SEQ_DATA_PORT,
|
|
ucSr8);
|
|
|
|
VideoPortWritePortUchar(
|
|
HwDeviceExtension->IOAddress + SEQ_ADDRESS_PORT,
|
|
0x6);
|
|
|
|
VideoPortWritePortUchar(
|
|
HwDeviceExtension->IOAddress + SEQ_DATA_PORT,
|
|
ucSr6);
|
|
|
|
VideoPortWritePortUchar(
|
|
HwDeviceExtension->IOAddress + SEQ_ADDRESS_PORT,
|
|
OldSeqIdx);
|
|
|
|
// workaround for Cirrus HW problem (part 2/2)
|
|
onceReadAttempt = TRUE;
|
|
onceReturnedValue = bRet;
|
|
|
|
VideoDebugPrint((1, "CIRRUS: first EDID reading attempt "));
|
|
if (onceReturnedValue)
|
|
VideoDebugPrint((1, "succeeded"));
|
|
else
|
|
VideoDebugPrint((1, "failed"));
|
|
VideoDebugPrint((1, " - the result saved\n"));
|
|
memcpy (onceQueryBuffer, QueryBuffer, BufferSize);
|
|
// end of the workaround (part 1/2)
|
|
|
|
return bRet;
|
|
}
|