📄 lcdddc.c
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
/*****************************************************************************\
*
* Module Name LCDDDC.C
* Project LT Rage Pro/ Rage Mobility/ Rage XC/ Rage XL
*
* Description Retrieves EDID data from the monitor.
*
* (c) 1997 ATI Technologies Inc. (unpublished)
*
* All rights reserved. This notice is intended as a precaution against
* inadvertent publication and does not imply publication or any waiver
* of confidentiality. The year included in the foregoing notice is the
* year of creation of the work.
*
*
\*****************************************************************************/
#include "dal.h"
#include "lcdddc.h"
#include "ltlcdl.h"
#include "rprod.h"
//
// DDC routines are very time sensitive. We try to put them on the same page,
// so when LCDDDC2Query() is called we'll have a good chance they won't
// be paged out.
//
//
// Allow swapping.
//
#if defined (ALLOC_PRAGMA)
#pragma alloc_text(PAGE_DDC, LCDDDC2Query)
#if TRUE //(_WIN32_WINNT < 0x500) [cd]:Temporary until DDC detection fixed for Win2K
#pragma alloc_text(PAGE_DDC, LCDDDC2QueryCallback)
#pragma alloc_text(PAGE_DDC, LCDDDC2_I2CStart)
#pragma alloc_text(PAGE_DDC, LCDDDC2_I2CStop)
#pragma alloc_text(PAGE_DDC, LCDDDC2_I2CWrite)
#pragma alloc_text(PAGE_DDC, LCDDDC2_I2CWriteByte)
#pragma alloc_text(PAGE_DDC, LCDDDC2_I2CRead)
#pragma alloc_text(PAGE_DDC, LCDDDC2_I2CReadByte)
#pragma alloc_text(PAGE_DDC, LCDDDC2_I2CWaitForClockLineHigh)
#pragma alloc_text(PAGE_DDC, LCDDETQuery)
#pragma alloc_text(PAGE_DDC, LCDDETQueryCallback)
#endif // _WIN32_WINNT < 0x500
#pragma alloc_text(PAGE_DDC, LCDDDC2_I2CWriteClockLine)
#pragma alloc_text(PAGE_DDC, LCDDDC2_I2CWriteDataLine)
#pragma alloc_text(PAGE_DDC, LCDDDC2_I2CReadClockLine)
#pragma alloc_text(PAGE_DDC, LCDDDC2_I2CReadDataLine)
#pragma alloc_text(PAGE_DDC, LCDWaitForVerticalBlank)
#endif // defined (ALLOC_PRAGMA)
#if FALSE //(_WIN32_WINNT >= 0x500)
BOOLEAN
LCDDDC2Query(
HGDO hGDO,
HDDL hDDL,
LPUCHAR lpucQueryBuffer,
ULONG ulLength
)
//
// DESCRIPTION:
// Reads the basic EDID structure from the monitor using DDC.
//
// PARAMETERS:
// hDDL Points to per-adapter device extension.
// lpucQueryBuffer Buffer where information will be stored.
// ulLength Size of the buffer to fill.
//
// RETURN VALUE:
// TRUE DDC read OK.
// FALSE DDC read failed.
//
{
I2C_FNC_TABLE i2c;
DALASSERT(NULL != hDDL, "hDDL is NULL!");
DALASSERT(NULL != lpucQueryBuffer, "lpucQueryBuffer is NULL!");
i2c.WriteClockLine = LCDDDC2_I2CWriteClockLine;
i2c.WriteDataLine = LCDDDC2_I2CWriteDataLine;
i2c.ReadClockLine = LCDDDC2_I2CReadClockLine;
i2c.ReadDataLine = LCDDDC2_I2CReadDataLine;
i2c.WaitVsync = LCDWaitForVerticalBlank;
i2c.Size = sizeof (I2C_FNC_TABLE);
if (VideoPortDDCMonitorHelper(hDDL, &i2c, lpucQueryBuffer, ulLength) == FALSE)
{
DALDEBUG((DALDBG_DETAIL, "LCDDDC2Query: DDC query failed"));
return FALSE;
}
DALDEBUG((DALDBG_DETAIL, "LCDDDC2Query: DDC query OK"));
//[MF]DebugDumpHex(DEBUG_NORMAL, "LCDDDC2Query: EDID", lpucQueryBuffer, ulLength);
return TRUE;
} // LCDDDC2Query()
#else // _WIN32_WINNT >= 0x500
BOOLEAN
LCDDDC2Query(
HGDO hGDO,
HDDL hDDL,
LPUCHAR lpucQueryBuffer,
ULONG ulLength
)
//
// DESCRIPTION:
// Reads the basic EDID structure from the monitor using DDC.
//
// PARAMETERS:
// hDDL Points to per-adapter device extension.
// lpucQueryBuffer Buffer where information will be stored.
// ulLength Size of the buffer to fill.
//
// RETURN VALUE:
// TRUE DDC read OK.
// FALSE DDC read failed.
//
{
DDC2_QUERY_CONTEXT lcdddcQueryContext;
DALASSERT(NULL != hDDL, "hDDL is NULL!");
DALASSERT(NULL != lpucQueryBuffer, "lpucQueryBuffer is NULL!");
lcdddcQueryContext.hGDO = hGDO;
lcdddcQueryContext.hDDL = hDDL;
lcdddcQueryContext.lpucQueryBuffer = lpucQueryBuffer;
lcdddcQueryContext.ulLength = ulLength;
//
// Use a low priority on our critical section because it is long enough to risk problems if we disable interrupts.
//
#ifndef CE_BUILD
return SYNCEXECUTION(hDDL, VpLowPriority, LCDDDC2QueryCallback, (LPVOID)&lcdddcQueryContext);
#else
return FALSE; // DDC not supported on WinCE
#endif
} // LCDDDC2Query()
BOOLEAN
LCDDDC2QueryCallback(
LPDDC2_QUERY_CONTEXT lpDdcQueryContext
)
//
// DESCRIPTION:
// Allowes EDID to be read through VideoPortSynchronizeExecution().
//
// PARAMETERS:
// pDdcQueryContext Points to query context.
//
// RETURN VALUE:
// TRUE DDC read OK.
// FALSE DDC read failed.
//
// NOTE:
// Some monitors are extremely sensitive to timing during a DDC query. Adding debug print statements within
// the query routine will throw off the timing enough to confuse the monitor, causing the DDC query to fail.
//
{
ULONG ulChecksum; // EDID checksum
ULONG ulScratch; // Temp variable
LPGDO_RAGE_LCD hGDORageLCD;
UCHAR ucEdidWriteAddress;
DALASSERT(NULL != lpDdcQueryContext, "pDdcQueryContext is NULL!");
DALASSERT(NULL != lpDdcQueryContext->hDDL, "hDDL is NULL!");
DALASSERT(NULL != lpDdcQueryContext->lpucQueryBuffer, "lpucQueryBuffer is NULL!");
DALASSERT(lpDdcQueryContext->ulLength >= EDID_SIZE, "ulLength is too large!");
hGDORageLCD = (LPGDO_RAGE_LCD)lpDdcQueryContext->hGDO;
//
// Enable "use software I2C".
//
LCD_DDC2_Select_SOFTWARE_I2C(lpDdcQueryContext->hGDO);
//
// Initialize SDA and SCL lines to default state of released high (input).
// Drive SCL low for 15ms to switch DDC2-capable monitor to DDC2 mode.
//
LCDDDC2_I2CWriteDataLine(lpDdcQueryContext->hGDO,
lpDdcQueryContext->hDDL,
1);
LCDDDC2_I2CWriteClockLine(lpDdcQueryContext->hGDO,
lpDdcQueryContext->hDDL,
0);
DELAY_MILLISECONDS(15);
LCDDDC2_I2CWriteClockLine(lpDdcQueryContext->hGDO,
lpDdcQueryContext->hDDL,
1);
if (LCDDDC2_I2CWaitForClockLineHigh(lpDdcQueryContext->hGDO,
lpDdcQueryContext->hDDL) == FALSE)
{
//
// Restore I2C_CNTL_0 and I2C_CNTL_1 for "use software I2C".
//
LCD_DDC2_Restore_SOFTWARE_I2C(lpDdcQueryContext->hGDO);
DALDEBUG((DALDBG_DETAIL, "LCDDDC2_QueryCallback: Can't switch to DDC2"));
return FALSE;
}
//
// Tell the monitor that we want to talk to it and give the address we want to start with.
//
ucEdidWriteAddress = DDC2_I2C_MONITOR_ADDRESS_WRITE2;
lpDdcQueryContext->ulLength = 256;
if (LCDDDC2_I2CWrite(lpDdcQueryContext->hGDO,
lpDdcQueryContext->hDDL,
ucEdidWriteAddress) == FALSE)
{
ucEdidWriteAddress = DDC2_I2C_MONITOR_ADDRESS_WRITE6;
lpDdcQueryContext->ulLength = 256;
if (LCDDDC2_I2CWrite(lpDdcQueryContext->hGDO,
lpDdcQueryContext->hDDL,
ucEdidWriteAddress) == FALSE)
{
ucEdidWriteAddress = DDC2_I2C_MONITOR_ADDRESS_WRITE0;
lpDdcQueryContext->ulLength = 128;
if (LCDDDC2_I2CWrite(lpDdcQueryContext->hGDO,
lpDdcQueryContext->hDDL,
ucEdidWriteAddress) == FALSE)
{
//
// Restore I2C_CNTL_0 and I2C_CNTL_1 for "use software I2C".
//
LCD_DDC2_Restore_SOFTWARE_I2C(lpDdcQueryContext->hGDO);
DALDEBUG((DALDBG_DETAIL, "LCDDDC2_QueryCallback: Can't write (110398) - DDC2 not supported"));
return FALSE;
}
}
}
//
// Read EDID from the monitor.
//
ZEROMEMORY(lpDdcQueryContext->lpucQueryBuffer,lpDdcQueryContext->ulLength);
if (LCDDDC2_I2CRead(lpDdcQueryContext->hGDO,
lpDdcQueryContext->hDDL,
lpDdcQueryContext->lpucQueryBuffer,
lpDdcQueryContext->ulLength,
ucEdidWriteAddress) == FALSE)
{
//
// Restore I2C_CNTL_0 and I2C_CNTL_1 for "use software I2C".
//
LCD_DDC2_Restore_SOFTWARE_I2C(lpDdcQueryContext->hGDO);
DALDEBUG((DALDBG_DETAIL, "LCDDDC2_QueryCallback: Can't read - DDC2 not supported"));
return FALSE;
}
//[MF]DebugDumpHex(DEBUG_NORMAL, "LCDDDC2QueryCallback: EDID", pDdcQueryContext->lpucQueryBuffer, pDdcQueryContext->ulLength);
//
// Calculate the EDID checksum. We should have 0x00 in LSB for proper EDID.
// Note: we don't have to preset EDID buffer since we know we can talk to the monitor.
//
ulChecksum = 0;
for (ulScratch = 0; ulScratch < lpDdcQueryContext->ulLength; ulScratch++)
ulChecksum += lpDdcQueryContext->lpucQueryBuffer[ulScratch];
DALDEBUG((DALDBG_DETAIL, "LCDDDC2_QueryCallback: EDID checksum = 0x%08X", ulChecksum));
//
// Restore I2C_CNTL_0 and I2C_CNTL_1 for "use software I2C".
//
LCD_DDC2_Restore_SOFTWARE_I2C(lpDdcQueryContext->hGDO);
if ((ulChecksum & 0xFF) || (0 == ulChecksum))
return FALSE;
return TRUE;
} // LCDDDC2QueryCallback()
BOOLEAN
LCDDETQuery(
HGDO hGDO,
HDDL hDDL,
LPUCHAR lpucQueryBuffer
)
//
// DESCRIPTION:
// Reads the basic EDID structure from the monitor using DDC.
//
// PARAMETERS:
// hDDL Points to per-adapter device extension.
// lpucQueryBuffer Buffer where information will be stored.
// ulLength Size of the buffer to fill.
//
// RETURN VALUE:
// TRUE DDC read OK.
// FALSE DDC read failed.
//
{
DDC2_QUERY_CONTEXT lcdddcQueryContext;
DALASSERT(NULL != hDDL, "hDDL is NULL!");
lcdddcQueryContext.hGDO = hGDO;
lcdddcQueryContext.hDDL = hDDL;
lcdddcQueryContext.lpucQueryBuffer = lpucQueryBuffer; // EPR 35356
//
// Use a low priority on our critical section because it is long enough to risk problems if we disable interrupts.
//
#ifndef CE_BUILD
return SYNCEXECUTION(hDDL, VpLowPriority, LCDDETQueryCallback, (LPVOID)&lcdddcQueryContext);
#else
return FALSE; // DDC not supported on WinCE
#endif
} // LCDDETQuery()
BOOLEAN
LCDDETQueryCallback(
LPDDC2_QUERY_CONTEXT lpDdcQueryContext
)
//
// DESCRIPTION:
// Allowes EDID to be read through VideoPortSynchronizeExecution().
//
// PARAMETERS:
// pDdcQueryContext Points to query context.
//
// RETURN VALUE:
// TRUE DDC read OK.
// FALSE DDC read failed.
//
// NOTE:
// Some monitors are extremely sensitive to timing during a DDC query. Adding debug print statements within
// the query routine will throw off the timing enough to confuse the monitor, causing the DDC query to fail.
//
{
LPGDO_RAGE_LCD hGDORageLCD;
UCHAR ucEdidWriteAddress;
DALASSERT(NULL != lpDdcQueryContext, "pDdcQueryContext is NULL!");
DALASSERT(NULL != lpDdcQueryContext->hDDL, "hDDL is NULL!");
hGDORageLCD = (LPGDO_RAGE_LCD)lpDdcQueryContext->hGDO;
//
// Enable "use software I2C".
//
LCD_DDC2_Select_SOFTWARE_I2C(lpDdcQueryContext->hGDO);
//
// Initialize SDA and SCL lines to default state of released high (input).
// Drive SCL low for 15ms to switch DDC2-capable monitor to DDC2 mode.
//
LCDDDC2_I2CWriteDataLine(lpDdcQueryContext->hGDO,
lpDdcQueryContext->hDDL,
1);
LCDDDC2_I2CWriteClockLine(lpDdcQueryContext->hGDO,
lpDdcQueryContext->hDDL,
0);
DELAY_MILLISECONDS(15);
LCDDDC2_I2CWriteClockLine(lpDdcQueryContext->hGDO,
lpDdcQueryContext->hDDL,
1);
if (LCDDDC2_I2CWaitForClockLineHigh(lpDdcQueryContext->hGDO,
lpDdcQueryContext->hDDL) == FALSE)
{
//
// Restore I2C_CNTL_0 and I2C_CNTL_1 for "use software I2C".
//
LCD_DDC2_Restore_SOFTWARE_I2C(lpDdcQueryContext->hGDO);
DALDEBUG((DALDBG_DETAIL, "LCDDDC2_QueryCallback: Can't switch to DDC2"));
return FALSE;
}
//
// Tell the monitor that we want to talk to it and give the address we want to start with.
//
ucEdidWriteAddress = DDC2_I2C_MONITOR_ADDRESS_WRITE2;
lpDdcQueryContext->ulLength = 80; // EPR 35356, EPR 36724
if (LCDDDC2_I2CWrite(lpDdcQueryContext->hGDO,
lpDdcQueryContext->hDDL,
ucEdidWriteAddress) == FALSE)
{
ucEdidWriteAddress = DDC2_I2C_MONITOR_ADDRESS_WRITE6;
lpDdcQueryContext->ulLength = 80; // EPR 35356
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -