📄 dalddc.c
字号:
if (lpDisplay->lpHWED->ulFunctionHooks2
& GDO_HOOK2_DDCPOSTDDCQUERY)
{
lpDisplay->
lpHWED->pfnDDC_I2C_PostDDCQuery(lpDisplay->hGDO, bRetCode);
}
if (FALSE == bRetCode)
{
DALDEBUG((DALDBG_ENTRY_EXIT, "DDCQuery- Exit"));
return FALSE;
}
else if(lpDisplay ->lpHWED ->ulDisplayType & HW_DISPLAY_TYPE_CV)
{
DALDEBUG((DALDBG_ENTRY_EXIT, "DDCQuery- Exit"));
return TRUE;
}
// Verify that the data obtained is valid
//
lpEDIDBuf->ulSize = GetStandardEdidLength(lpEDIDBuf->aucEdidDataBuffer);
if(sizeof(lpEDIDBuf->aucEdidDataBuffer) < lpEDIDBuf->ulSize)
{
DALASSERT(FALSE, "Available Edid buffer is too small for this EDID version!");
DALDEBUG((DALDBG_ENTRY_EXIT, "DDCQuery- Exit"));
return FALSE;
}
if (EDID_VER_1_STDLEN == lpEDIDBuf->ulSize)
{ // Version 1
// Was bug (DFP): ulFormatId = EDID_VERSION_11 (0x101)
lpEDIDBuf->ulFormatId = (lpEDIDBuf->aucEdidDataBuffer[0x12] << 8)
| lpEDIDBuf->aucEdidDataBuffer[0x13];
//lpEDIDBuf->ulSize = EDID_VERSION_1_STDLEN; // Was bug (CRT): set only if 0x101
}
else if (EDID_VER_2_STDLEN == lpEDIDBuf->ulSize)
{ // Version 2
lpEDIDBuf->ulFormatId = EDID_VER_20;
// Do not support Version 2 for CRTs (Why??)
//
if(lpDisplay->lpHWED->ulDisplayType & HW_DISPLAY_TYPES_CRT_MASK)
{
DALDEBUG((DALDBG_ENTRY_EXIT, "DDCQuery- Exit"));
return FALSE;
}
}
else
{ // Unknown
DALDEBUG((DALDBG_NORMAL, "Unknown EDID version"));
DALDEBUG((DALDBG_ENTRY_EXIT, "DDCQuery- Exit"));
return FALSE;
}
// ulDFPSupportsDDC in DFP GDO is no longer used
// Return TRUE *only* if DDC-reported display type is expected
//
if (!(lpDisplay->lpHWED->ulDisplayType
& GetDisplayTypeFromEdid(lpEDIDBuf)))
{
DALDEBUG((DALDBG_ENTRY_EXIT, "DDCQuery- Exit"));
return FALSE;
}
DALDEBUG((DALDBG_ENTRY_EXIT, "DDCQuery- Exit"));
return TRUE;
} // DDCQuery()
/******************************Private*Routine*****************************\
* BOOL DDCQueryCallback(LPDALDDC_DDCCONTEXT lpddcContext)
*
* Synchronized callback used by DDCQuery()
*
\**************************************************************************/
static BOOL
DDCQueryCallback(
LPDALDDC_DDCCONTEXT lpddcContext) // Contains all DDCQuery() parameters
{
ULONG ulChecksum; // EDID checksum
ULONG ulScratch; // Temp variable
ULONG ulAddr, ulStartAddr;
BOOL bRes = FALSE;
PFNDDCREADLINE pfnReadLine =
lpddcContext->lpDisplay->lpHWED->pfnDDC_I2C_ReadLine;
PFNDDCWRITELINE pfnWriteLine =
lpddcContext->lpDisplay->lpHWED->pfnDDC_I2C_WriteLine;
HGDO hGDO = lpddcContext->lpDisplay->hGDO;
LPUCHAR lpucQueryBuffer = lpddcContext->lpucQueryBuffer;
ULONG ulLength = lpddcContext->ulLength;
DALDEBUG((DALDBG_ENTRY_EXIT, "DDCQueryCallback- Entry"));
DALASSERT(NULL != lpddcContext, "lpddcContext is NULL!");
// This is a little fix that gets some older DDC monitors to respond
// properly to DDC queries. Set the clock line low, wait 15 ms then set
// the clock line high.
//
pfnWriteLine(hGDO, 0, DAL_DDC_I2C_LINE_SCL);
DDC_DELAY_MILLISECONDS(15);
pfnWriteLine(hGDO, 1, DAL_DDC_I2C_LINE_SCL);
// 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.
//
pfnWriteLine(hGDO, 1, DAL_DDC_I2C_LINE_SDA);
pfnWriteLine(hGDO, 0, DAL_DDC_I2C_LINE_SCL);
DDC_DELAY_MILLISECONDS(15);
pfnWriteLine(hGDO, 1, DAL_DDC_I2C_LINE_SCL);
if (DDCWaitForClockLineHigh(lpddcContext->lpDisplay) == FALSE)
{
DALDEBUG((DALDBG_DETAIL, "DDCQueryCallback: Can't switch to DDC2"));
DALDEBUG((DALDBG_ENTRY_EXIT, "DDCQueryCallback- Exit"));
return FALSE;
}
// Tell the monitor that we want to talk to it and give the
// address we want to start with. If DFP then try different addresses
// starting from high.
//
ulAddr = (lpddcContext->lpDisplay->lpHWED->ulDisplayType & HW_DISPLAY_TYPES_DFP_MASK) ?
DDC_I2C_MONITOR_ADDRESS_WRITE_A2 : DDC_I2C_MONITOR_ADDRESS_WRITE_A0;
if(lpddcContext->lpDisplay->lpHWED->ulDisplayType & HW_DISPLAY_TYPE_CV)
{
//We might use other chips, add more check later.
ulAddr = lpddcContext->lpDisplay->lpHWED->usI2CWriteLastAddr;
ulStartAddr = lpddcContext->lpDisplay->lpHWED->usI2CWriteStartAddr;
lpddcContext->ulLength = 2; //Write 2 bytes
ulLength = 1; //Only query 1 byte.
}
else
ulStartAddr = DDC_I2C_MONITOR_ADDRESS_WRITE_A0 ;
for(; ulAddr >= ulStartAddr; ulAddr -=2)
{
ULONG ulRetryCounter = lpddcContext->lpHDE->ulRetryDDCWriteTimes;
lpucQueryBuffer[0] = (UCHAR)ulAddr;
lpucQueryBuffer[1] = (UCHAR)DDC_I2C_EDID_START_ADDRESS;
while (FALSE == (bRes = DDCWrite(lpddcContext->lpDisplay,
lpucQueryBuffer, 2))
&& ulRetryCounter--);
if (FALSE == bRes)
continue;
// Read EDID from the monitor. The read address is always write address + 1
//
ZEROMEMORY(lpucQueryBuffer, ulLength);
if (FALSE == DDCRead(lpddcContext->lpDisplay,
lpucQueryBuffer, ulLength, (UCHAR)(ulAddr + 1)))
{
DALDEBUG((DALDBG_DETAIL, "DDCQueryCallback: Can't read - DDC2 not supported"));
DALDEBUG((DALDBG_ENTRY_EXIT, "DDCQueryCallback- Exit"));
return FALSE;
}
break;
}
if (FALSE == bRes)
{
DALDEBUG((DALDBG_DETAIL, "DDCQueryCallback: Can't write - DDC2 not supported"));
DALDEBUG((DALDBG_ENTRY_EXIT, "DDCQueryCallback- Exit"));
return FALSE;
}
if(lpddcContext->lpDisplay->lpHWED->ulDisplayType & HW_DISPLAY_TYPE_CV)
{
//Inform GDO about I2C addr update for later set Mode ID use.
if (GDO_HOOK2_I2C_SUPPORT & lpddcContext->lpDisplay->lpHWED->ulFunctionHooks2)
{
UCHAR ucAddr = (UCHAR)(ulAddr);
(*lpddcContext->lpDisplay->lpHWED->pfnGetSetI2CData)
(lpddcContext->lpDisplay->hGDO, &ucAddr, 1, DAL_I2C_SET_ADDR_TO_GDO);
(*lpddcContext->lpDisplay->lpHWED->pfnGetSetI2CData)
(lpddcContext->lpDisplay->hGDO, lpucQueryBuffer, 1, DAL_I2C_SET_DATA_TO_GDO);
}
DALDEBUG((DALDBG_ENTRY_EXIT, "DDCQueryCallback- Exit"));
return TRUE;
}
// Calculate the EDID checksum. We should have 0x00 in LSB for
// proper EDID.
// There are two versions of the EDID buffer structure. Version
// 1 has a buffer size of 128 bytes while version 2 has a buffer
// size of 256 bytes.
// Note: we don't have to preset EDID buffer since we know we
// can talk to the monitor.
//
ulChecksum = 0x00;
// Identify EDID Version
// Using the first eight bytes of the EDID buffer, the version of
// the EDID can be determine. Version 1 has the first eight bytes
// dedicated as a flag, 0x00FFFFFFFFFFFF00, while version 2 has
// the first byte set aside as a revision field.
//
// BUGBUG: won't work on alpha (big indian) machine
//
//lpHeader = (LPULONG) lpucQueryBuffer;
//if (*lpHeader++ == DDC_EDID_LSD_HEADER_VERSION_1)
//{
// if (*lpHeader == DDC_EDID_MSD_HEADER_VERSION_1)
// { // Version 1 - Buffer size is only 128 bytes
//
// ulLength = 128;
// }
//}
{
ULONG ulStdLength = GetStandardEdidLength(lpucQueryBuffer);
// Cannot proceed if supplied buffer was smaller (was a bug!)
//
if (ulLength < ulStdLength)
{
DALDEBUG((DALDBG_ENTRY_EXIT, "DDCQueryCallback- Exit"));
return FALSE;
}
ulLength = ulStdLength;
}
// Verify EDID Buffer
// Do a simple checksum on the buffer the LSB should be zero.
//
for (ulScratch = 0; ulScratch < ulLength; ulScratch++)
{
ulChecksum += lpucQueryBuffer[ulScratch];
}
DALDEBUG((DALDBG_DETAIL,
"DDCQueryCallback: EDID checksum = 0x%08X", ulChecksum));
// We need to make sure that the LSB of the checksum is 0
// AS WELL AS ensuring that the checksum does not equal the
// value that we inititally set it to (zero). Since we zeroed
// the buffer before we called the routine to get the DDC buffer,
// if the monitor didn't respond at all but we thought it did then
// the checksum would be zero and if we didn't check to make sure the
// upper part of the dword was not 0 we could be passing back a bad
// buffer.
//
if ((ulChecksum & 0xFF) || (ulChecksum == 0 ))
{
DALDEBUG((DALDBG_ENTRY_EXIT, "DDCQueryCallback- Exit"));
return FALSE;
}
DALDEBUG((DALDBG_ENTRY_EXIT, "DDCQueryCallback- Exit"));
return TRUE;
} // DDCQueryCallback()
/******************************Private*Routine*****************************\
* BOOL DDCStart(LPDEVGDO lpDisplay)
*
* Start DDC communication.
*
\**************************************************************************/
static BOOL
DDCStart(
LPDEVGDO lpDisplay) // Display structure
{
ULONG ulRetry;
PFNDDCREADLINE pfnReadLine = lpDisplay->lpHWED->pfnDDC_I2C_ReadLine;
PFNDDCWRITELINE pfnWriteLine = lpDisplay->lpHWED->pfnDDC_I2C_WriteLine;
DALDEBUG((DALDBG_ENTRY_EXIT, "DDCStart- Entry"));
//
// The I2C communications start signal is a SDA high->low while the SCL is high.
//
// this is a little fix that gets some marginal DDC monitors to respond
// properly to DDC queries. Set the clock line low, wait 15 ms then set
// the clock line high, wait, set clock low.
//
// Set SCL high
//
pfnWriteLine(lpDisplay->hGDO, 1, DAL_DDC_I2C_LINE_SCL);
for (ulRetry = 0; ulRetry <= DDC_I2C_START_RETRIES; ulRetry++)
{
// Set SDA high
//
pfnWriteLine(lpDisplay->hGDO, 1, DAL_DDC_I2C_LINE_SDA);
DDC_DELAY_MICROSECONDS(13);
if (pfnReadLine(lpDisplay->hGDO, DAL_DDC_I2C_LINE_SDA) == FALSE)
continue; // SDA didn't take - retry
// Set SCL high
//
pfnWriteLine(lpDisplay->hGDO, 1, DAL_DDC_I2C_LINE_SCL);
DDC_I2C_DELAY();
if (DDCWaitForClockLineHigh(lpDisplay) == FALSE)
{
DALDEBUG((DALDBG_DETAIL, "DDCStart: SCL didn't take"));
break;
}
// Set SDA low
//
pfnWriteLine(lpDisplay->hGDO, 0, DAL_DDC_I2C_LINE_SDA);
DDC_I2C_DELAY();
// Set SCL low
//
pfnWriteLine(lpDisplay->hGDO, 0, DAL_DDC_I2C_LINE_SCL);
DDC_I2C_DELAY();
// Set SDA high
//
pfnWriteLine(lpDisplay->hGDO, 1, DAL_DDC_I2C_LINE_SDA);
DDC_I2C_DELAY();
DALDEBUG((DALDBG_ENTRY_EXIT, "DDCStart- Exit"));
return TRUE;
}
DALDEBUG((DALDBG_DETAIL, "DDCStart: Failed"));
DALDEBUG((DALDBG_ENTRY_EXIT, "DDCStart- Exit"));
return FALSE;
} // DDCStart()
/******************************Private*Routine*****************************\
* BOOL DDCStop(LPDEVGDO lpDisplay)
*
* Stop DDC communication.
*
\**************************************************************************/
static BOOL
DDCStop(
LPDEVGDO lpDisplay) // Display structure
{
PFNDDCREADLINE pfnReadLine = lpDisplay->lpHWED->pfnDDC_I2C_ReadLine;
PFNDDCWRITELINE pfnWriteLine = lpDisplay->lpHWED->pfnDDC_I2C_WriteLine;
DALDEBUG((DALDBG_ENTRY_EXIT, "DDCStop- Entry"));
//
// The I2C communications stop signal is a SDA low->high while the SCL is high.
//
pfnWriteLine(lpDisplay->hGDO, 0, DAL_DDC_I2C_LINE_SCL);
// Set SDA low
//
pfnWriteLine(lpDisplay->hGDO, 0, DAL_DDC_I2C_LINE_SDA);
DDC_I2C_DELAY();
// Set SCL high
//
pfnWriteLine(lpDisplay->hGDO, 1, DAL_DDC_I2C_LINE_SCL);
DDC_I2C_DELAY();
if (DDCWaitForClockLineHigh(lpDisplay) == FALSE)
{
DALDEBUG((DALDBG_DETAIL, "DDCStop: SCL didn't take"));
DALDEBUG((DALDBG_ENTRY_EXIT, "DDCStop- Exit"));
return FALSE;
}
// Set SDA high
//
pfnWriteLine(lpDisplay->hGDO, 1, DAL_DDC_I2C_LINE_SDA);
DDC_I2C_DELAY();
if (pfnReadLine(lpDisplay->hGDO, DAL_DDC_I2C_LINE_SDA) == FALSE)
{
DALDEBUG((DALDBG_DETAIL, "DDCStop: SDA didn't take"));
DALDEBUG((DALDBG_ENTRY_EXIT, "DDCStop- Exit"));
return FALSE;
}
DALDEBUG((DALDBG_ENTRY_EXIT, "DDCStop- Exit"));
return TRUE;
} // DDCStop()
/******************************Private*Routine*****************************\
* BOOL DDCRead(LPDEVGDO lpDisplay, LPUCHAR lpucBuf, ULONG ulLen,
* UCHAR ucReadAddr)
*
* Read byte block of EDID data.
*
\**************************************************************************/
static BOOL
DDCRead(
LPDEVGDO lpDisplay, // Display structure
LPUCHAR lpucBuf, // Buffer to read to
ULONG ulLen, // Buffer length
UCHAR ucReadAddr)
{
BOOL bRet;
ULONG ulCount;
DALDEBUG((DALDBG_ENTRY_EXIT, "DDCRead- Entry"));
DALASSERT(NULL != lpucBuf, "lpucBuf is NULL!");
// Try to start I2C bus a number of times. Should succeed every time,
// otherwise fail. Really paranoid.
//
bRet = DDCStart(lpDisplay);
ulCount = DDC_RETRIES;
while ((bRet) && (ulCount > 0))
{
bRet = DDCStart(lpDisplay);
ulCount--;
}
if (bRet == FALSE)
{
DALDEBUG((DALDBG_ENTRY_EXIT, "DDCRead- Exit"));
return FALSE;
}
// Tell the monitor that we want to listen to it.
//
if (FALSE == DDCWriteByte(lpDisplay, ucReadAddr))
{
DDCStop(lpDisplay);
DALDEBUG((DALDBG_ENTRY_EXIT, "DDCRead- Exit"));
return FALSE;
}
// On all but the last byte, we must send an ACK in order to ensure that the sending device will
// send subsequent data bytes. On the last byte, we must send a NAK so that it will shut up.
//
for (ulCount = 0; ulCount < ulLen; ulCount++)
{
if (FALSE == (bRet = DDCReadByte(lpDisplay, lpucBuf + ulCount, ulCount < ulLen - 1)))
break;
// Make sure we don't attempt to read beyond the standard EDID length.
// Doing this may hang certain monitors.
//
// NOTE:
// Should read EDID data in portions at high level (bGetEdidData())
// if want to save the overhead of rereading/restarting:
// 1. Read 8 first bytes
// 2. Read EDID data of standard length less 8 bytes
// 3. Read any optional data less read data
// In such implementation Start() and Stop() are called at high level
// and this check is moved there as well.
//
if (EDID_VER_1_HDRLEN - 1 == ulCount)
{
ULONG ulStdLen = GetStandardEdidLength(lpucBuf);
if (ulStdLen != 0
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -