📄 dalddc.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 dalddc.c
* Project ATI Display Abstraction Layer
* Device RageProPNP / Rage128 (Win95/98 & WinNT 4.0/5.0)
*
* Description source file for Display Abstraction Layer 0.87
* contains functions for processing DDC queries
*
* Copyright (c) 1998-2000 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.
*
* Refer to DAL Developers Guide & Programming Reference Rev 0.87 for usage
\****************************************************************************/
#include "dal.h"
#include "daldef.h"
#include "dalddc.h"
#include "cwddedi.h"
// Define structure passed as a context to DDC query callback function.
//
typedef struct _DALDDC_DDCCONTEXT
{
LPHW_DAL_EXTENSION lpHDE;
LPDEVGDO lpDisplay;
LPUCHAR lpucQueryBuffer;
ULONG ulLength; // Size if query buffer in bytes
} DALDDC_DDCCONTEXT, *LPDALDDC_DDCCONTEXT;
// These are private functions implementing DDC. Declare them as static.
//
static BOOL FilterEdidData (LPEDID_BUFFER lpEDIDBuf);
static BOOL DDCQuery (LPHW_DAL_EXTENSION lpHDE, LPDEVGDO lpDisplay,
LPEDID_BUFFER lpEDIDBuf);
static BOOL DDCQueryCallback (LPDALDDC_DDCCONTEXT lpddcContext);
static BOOL DDCStart (LPDEVGDO lpDisplay);
static BOOL DDCStop (LPDEVGDO lpDisplay);
static BOOL DDCRead (LPDEVGDO lpDisplay, LPUCHAR lpucBuf, ULONG ulLen, UCHAR ucReadAddr);
static BOOL DDCWrite (LPDEVGDO lpDisplay, LPUCHAR lpucBuf, ULONG ulLen);
static BOOL DDCReadByte (LPDEVGDO lpDisplay, LPUCHAR lpucByte, BOOL bMore);
static BOOL DDCWriteByte (LPDEVGDO lpDisplay, UCHAR ucByte);
static BOOL DDCWaitForClockLineHigh (LPDEVGDO lpDisplay);
//
// Allow swapping.
//
#if defined (ALLOC_PRAGMA)
#pragma alloc_text(PAGE_DDC, bIsDisplayDDCPhysicallyConnected)
#pragma alloc_text(PAGE_DDC, bGetEdidData)
#pragma alloc_text(PAGE_DDC, GetStandardEdidLength)
#pragma alloc_text(PAGE_DDC, GetDisplayTypeFromEdid)
#pragma alloc_text(PAGE_DDC, FilterEdidData)
#pragma alloc_text(PAGE_DDC, DDCQuery)
#pragma alloc_text(PAGE_DDC, DDCQueryCallback)
#pragma alloc_text(PAGE_DDC, DDCStart)
#pragma alloc_text(PAGE_DDC, DDCStop)
#pragma alloc_text(PAGE_DDC, DDCRead)
#pragma alloc_text(PAGE_DDC, DDCWrite)
#pragma alloc_text(PAGE_DDC, DDCReadByte)
#pragma alloc_text(PAGE_DDC, DDCWriteByte)
#pragma alloc_text(PAGE_DDC, DDCWaitForClockLineHigh)
#endif // defined (ALLOC_PRAGMA)
/******************************Public*Routine******************************\
* BOOL bUseDalBasedDdc(LPDEVGDO lpDisplay)
*
* Check whether GDO supports DDC queries (old style GDO) (1) or it supports
* additional hooks allowing for DDC implementation in DAL (2).
* (1) : Must export GetEdidData hook
* (2) : Must export DDCReadLine, DDCWriteLine instead of GetEdidData;
* Can export SetNextDisplayConnector if supports multiple connectors;
* Optioanally may export PreDDCQuery, PostDDCQuery;
* Return FALSE for (1) and TRUE for (2)
*
\**************************************************************************/
BOOL
bUseDalBasedDdc(
LPDEVGDO lpDisplay)
{
if ((GDO_HOOK2_DDCREADLINE | GDO_HOOK2_DDCWRITELINE)
== (lpDisplay->lpHWED->ulFunctionHooks2 &
(GDO_HOOK2_DDCREADLINE | GDO_HOOK2_DDCWRITELINE)))
{
// Assert the old DDC GetEdidData hook is not exported. Not fatal.
//
DALASSERT(!(lpDisplay->lpHWED->ulFunctionHooks & GDO_HOOK_GET_EDID_DATA),
"Old GetEdidData hook ignored");
return TRUE;
}
else
{ // Try to use the old style GetEdidData hook (it can be still missing)
// Assert there are no any new DDC hooks. This is not fatal.
//
DALASSERT(0 == (lpDisplay->lpHWED->ulFunctionHooks2 &
(GDO_HOOK2_DDCPREDDCQUERY | GDO_HOOK2_DDCREADLINE |
GDO_HOOK2_DDCWRITELINE | GDO_HOOK2_DDCPOSTDDCQUERY |
GDO_HOOK2_SETDSPLCONNECTOR)),
"Required DDCReadLine and/or DDCWriteLine hooks missing. "
"Ignoring new hooks.");
return FALSE;
}
} // bUseDalBasedDdc()
/******************************Public*Routine******************************\
* BOOL bIsDisplayDDCPhysicallyConnected(LPHW_DAL_EXTENSION lpHDE,
* LPDEVGDO lpDisplay)
*
* Make a DDC query. If the query succeeds and display type reported in
* the query coinsides with GDO's type then there is a connection. If DDC
* query fails then call GDO (it might know how to detect if it is connected
* or not). First tries to query over DVI and then if this fails - over VGA
* connector.
*
\**************************************************************************/
BOOL
bIsDisplayDDCPhysicallyConnected(
LPHW_DAL_EXTENSION lpHDE, // DAL instance
LPDEVGDO lpDisplay) // Display structure
{
DALDEBUG((DALDBG_ENTRY_EXIT, "bIsDisplayDDCPhysicallyConnected- Entry"));
// Can use new style DDC implementation - must have all three following
// hooks in place.
//
if (bUseDalBasedDdc(lpDisplay))
{ // Only DAL knows how to accomplish DDC query
EDID_BUFFER EdidQueryBuffer;
// This will cause bGetEdidData to try all connectors in turn till success
//
lpDisplay->ulFlags &= ~GDO_CONNECTOR_ESTABLISHED;
// NOTE: REDSTONE and other test environment options are GDO's responsibility:
// DO NOT HOOK IF CANNOT SUPPORT (Alright if test environment flags cannot be
// changed dynamically - read from registry at enable time (once))
// TBD: Make rather a quick query
if(!bGetEdidData(lpHDE, lpDisplay, &EdidQueryBuffer))
{ // Failed DDC query on all connectors
DALDEBUG((DALDBG_NORMAL, "Could not detect connection through DDC, ask GDO as last resort"));
DALDEBUG((DALDBG_ENTRY_EXIT, "bIsDisplayDDCPhysicallyConnected- Exit"));
return lpDisplay->lpHWED->pfnIsDisplayPhysicallyConnected(lpDisplay->hGDO);
}
// Return TRUE if DDC-reported display type is expected
//
//if (lpDisplay->lpHWED->ulDisplayType
// & ulEdidGetDisplayType(&EdidQueryBuffer))
// return TRUE;
DALDEBUG((DALDBG_ENTRY_EXIT, "bIsDisplayDDCPhysicallyConnected- Exit"));
return TRUE;
}
else
{ // GDO implements DDC (obsolete), just call GDO
DALDEBUG((DALDBG_ENTRY_EXIT, "bIsDisplayDDCPhysicallyConnected- Exit"));
return lpDisplay->lpHWED->pfnIsDisplayPhysicallyConnected(lpDisplay->hGDO);
}
} // bIsDisplayDDCPhysicallyConnected()
/******************************Public*Routine******************************\
* BOOL bGetEdidData(LPHW_DAL_EXTENSION lpHDE, LPDEVGDO lpDisplay,
* LPEDID_BUFFER lpEDIDBuf)
*
* This function will call the NO-BIOS code to get the EDID information.
*
\**************************************************************************/
BOOL
bGetEdidData(
LPHW_DAL_EXTENSION lpHDE, // DAL instance
LPDEVGDO lpDisplay, // Display structure
LPEDID_BUFFER lpEDIDBuf) // Uninitialized EDID buffer structure
{
DALDEBUG((DALDBG_ENTRY_EXIT, "bGetEdidData- Entry"));
DALASSERT(NULL != lpHDE, "lpHDE is NULL!");
DALASSERT(NULL != lpDisplay, "lpDisplay is NULL!");
// Can use new style DDC implementation - must have all three following
// hooks in place.
//
if (bUseDalBasedDdc(lpDisplay))
{
BOOL bOK = FALSE;
// Initialize EDID_BUFFER structure
//
lpEDIDBuf->ulSize = sizeof(lpEDIDBuf->aucEdidDataBuffer); // Maximum available size
// BUGBUG: = EDID_DATA_SIZE; // Maximum required EDID size
lpEDIDBuf->ulFormatId = 0; // Assume unknown (invalid) format
// Make a standard DDC query, try different connectors
//
if ((lpDisplay->lpHWED->ulFunctionHooks2 & GDO_HOOK2_SETDSPLCONNECTOR)
&& !(lpDisplay->ulFlags & GDO_CONNECTOR_ESTABLISHED))
{ // Display has more than one connector. None of them has been
// tried (established) yet
USHORT usConnectorIndex;
BOOL bUntriedConnectors = TRUE;
for(usConnectorIndex = 0;
bUntriedConnectors;
usConnectorIndex++)
{
bUntriedConnectors = (*lpDisplay->lpHWED->pfnSetDisplayConnector)(lpDisplay->hGDO, usConnectorIndex);
if(TRUE == (bOK = DDCQuery(lpHDE, lpDisplay, lpEDIDBuf)))
{
DALDEBUG((DALDBG_NORMAL, "Connected on %d connector", usConnectorIndex));
break;
}
}
}
else
{
bOK = DDCQuery(lpHDE, lpDisplay, lpEDIDBuf);
}
if (FALSE == bOK)
{
DALDEBUG((DALDBG_ENTRY_EXIT, "bGetEdidData- Exit"));
return FALSE;
}
lpDisplay->ulFlags |= GDO_CONNECTOR_ESTABLISHED;
// Analyze and patch EDID data if necessary
//
if (FALSE == FilterEdidData(lpEDIDBuf))
{
DALDEBUG((DALDBG_ENTRY_EXIT, "bGetEdidData- Exit"));
return FALSE;
}
DALDEBUG((DALDBG_ENTRY_EXIT, "bGetEdidData- Exit"));
return TRUE;
}
else
{ // Old DDC-style GDO
if (lpDisplay->lpHWED->ulFunctionHooks & GDO_HOOK_GET_EDID_DATA)
{ // Obsolete hook is supported by GDO: use it rather than new
// DDC implementation in DAL
DALDEBUG((DALDBG_ENTRY_EXIT, "bGetEdidData- Exit"));
return (*lpDisplay->lpHWED->pfnGetEdidData)(lpDisplay->hGDO, lpEDIDBuf);
}
}
DALDEBUG((DALDBG_ENTRY_EXIT, "bGetEdidData- Exit"));
return FALSE;
} // bGetEdidData()
/******************************Public*Routine******************************\
* ULONG GetStandardEdidLength(LPUCHAR lpucEdidDataBuf)
*
* Determine standard EDID data buffer length according to EDID version.
* Version 1 has 128 bytes and version 2 has 256 bytes. 8 first bytes of
* EDID data must be available.
*
\**************************************************************************/
ULONG
GetStandardEdidLength(LPUCHAR lpucEdidDataBuf)
{
if (0x00 == lpucEdidDataBuf[0]
&& 0xff == lpucEdidDataBuf[1]
&& 0xff == lpucEdidDataBuf[2]
&& 0xff == lpucEdidDataBuf[3]
&& 0xff == lpucEdidDataBuf[4]
&& 0xff == lpucEdidDataBuf[5]
&& 0xff == lpucEdidDataBuf[6]
&& 0x00 == lpucEdidDataBuf[7])
return EDID_VER_1_STDLEN;
else
{
if (0x20 == lpucEdidDataBuf[0])
return EDID_VER_2_STDLEN;
}
return 0; // Unknown format
} // GetStandardEdidLength()
/******************************Public*Routine******************************\
* ULONG GetDisplayTypeFromEdid(LPEDID_BUFFER lpEDIDBuf)
*
* Return display type flag from EDID data. Full standard length of EDID
* data must be available.
*
\**************************************************************************/
ULONG
GetDisplayTypeFromEdid(LPEDID_BUFFER lpEDIDBuf)
{
DALASSERT(lpEDIDBuf != NULL,
"GetDisplayTypeFromEdid: lpEDIDBuf is invalid ");
switch (lpEDIDBuf->ulFormatId & ~EDID_VER_REVMASK)
{
case EDID_VER_10 & ~EDID_VER_REVMASK:
{ // Version 1: Byte 0x14, Bit 7, Analog = 0, Digital = 1
if(lpEDIDBuf->ulSize < 0x14 + 1)
{
DALASSERT(FALSE, "EDID buffer too short");
return HW_DISPLAY_UNKNOWN;
}
if (lpEDIDBuf->aucEdidDataBuffer[0x14] >> 7)
return HW_DISPLAY_TYPES_DIGITAL_MASK;
else
return HW_DISPLAY_TYPES_CRT_MASK;
}
case EDID_VER_20 & ~EDID_VER_REVMASK:
{ // Version 2: Byte 0x4F, Bits 7 - 4, CRT = 0, LCD = 1
if(lpEDIDBuf->ulSize < 0x4F + 1)
{
DALASSERT(FALSE, "EDID buffer too short");
return HW_DISPLAY_UNKNOWN;
}
if (lpEDIDBuf->aucEdidDataBuffer[0x4F] >> 4)
return HW_DISPLAY_TYPES_DIGITAL_MASK;
else
return HW_DISPLAY_TYPES_CRT_MASK;
}
default :
return HW_DISPLAY_UNKNOWN;
}
} // GetDisplayTypeFromEdid
/******************************Private*Routine*****************************\
* BOOL FilterEdidData(LPEDID_BUFFER lpEDIDBuf)
*
* Fix misreported EDID data or do any change to it before it is reported
* to DAL / Windows. Return FALSE to fail DDC query if necessary.
*
\**************************************************************************/
static BOOL
FilterEdidData(
LPEDID_BUFFER lpEDIDBuf)
{
if (EDID_VER_1_STDLEN == lpEDIDBuf->ulSize)
{ // Version 1
// HP M50 monitor fix. Some of the M50 monitors report and EDID version 2.1
// when it really should be 1.2.
//
if (lpEDIDBuf->ulFormatId == 0x00000201)
{
// Check to see if this is an HP M50 monitor
//
if ((lpEDIDBuf->aucEdidDataBuffer[8]== DDC_HP_ID_BYTE1) &&
(lpEDIDBuf->aucEdidDataBuffer[9]== DDC_HP_ID_BYTE2) &&
(((lpEDIDBuf->aucEdidDataBuffer[10]== DDC_HP_M50_ID_BYTE1) &&
(lpEDIDBuf->aucEdidDataBuffer[11]== DDC_HP_M50_ID_BYTE2)) ||
((lpEDIDBuf->aucEdidDataBuffer[10] == DDC_HP_M50_ID2_BYTE1) &&
(lpEDIDBuf->aucEdidDataBuffer[11] == DDC_HP_M50_ID2_BYTE2))))
{
lpEDIDBuf->ulFormatId = EDID_VER_12; // 0x102
}
}
}
return TRUE;
} // FilterEdidData()
/******************************Private*Routine*****************************\
* BOOL DDCQuery(LPHW_DAL_EXTENSION lpHDE, LPDEVGDO lpDisplay,
* LPEDID_BUFFER lpEdidBuf)
*
* Make a DDC query.
*
\**************************************************************************/
static BOOL
DDCQuery(
LPHW_DAL_EXTENSION lpHDE, // DAL instance
LPDEVGDO lpDisplay, // Display structure
LPEDID_BUFFER lpEDIDBuf) // EDID exchange buffer structure
{
DALDDC_DDCCONTEXT ddcContext;
BOOL bRetCode;
ULONG ulMaxDDCTries;
DALDEBUG((DALDBG_ENTRY_EXIT, "DDCQuery- Entry"));
DALASSERT(NULL != lpEDIDBuf, "lpEDIDBuf is NULL!");
// Cannot do it here, must be done in GDO.
// The proper way of doing this would be just not enabling the DCM hooks:
// GDO_HOOK_GET_EDID_DATA
// GDO_HOOK2_DDCPREDDCQUERY, GDO_HOOK2_DDCREADLINE, GDO_HOOK2_DDCWRITELINE
// if running on Redstone return FALSE. It hangs on NT
// if (lpR6Crt->ulTestEnvr == GCOGDO_TESTENVR_REDSTONE)
// {
// return FALSE;
// }
ddcContext.lpHDE = lpHDE;
ddcContext.lpDisplay = lpDisplay;
ddcContext.lpucQueryBuffer = lpEDIDBuf->aucEdidDataBuffer;
ddcContext.ulLength = lpEDIDBuf->ulSize;
ulMaxDDCTries = 1;
if ( (DALRULE2_DDC1SUPPORT & lpHDE->ulDalRule2)
&&(HW_DISPLAY_TYPES_CRT_MASK & lpDisplay->lpHWED->ulDisplayType))
// only support DDC1 for analog display devices.
{
ulMaxDDCTries = MAX_DDC1_TRIES;
}
// Call GDO to prepare the DDC line
if (lpDisplay->lpHWED->ulFunctionHooks2
& GDO_HOOK2_DDCPREDDCQUERY)
{
if (FALSE == lpDisplay->
lpHWED->pfnDDC_I2C_PreDDCQuery(lpDisplay->hGDO))
{
DALDEBUG((DALDBG_ENTRY_EXIT, "DDCQuery- Exit"));
return FALSE;
}
}
do
{
bRetCode = DDCQueryCallback(&ddcContext);
// bRetCode = (BOOL) SYNCEXECUTION(lpHDE->hDDL, VpLowPriority, (PMINIPORT_SYNCHRONIZE_ROUTINE)DDCQueryCallback, &ddcContext);
if (bRetCode)
{
break;
}
DDC_DELAY_MILLISECONDS(2);
} while (ulMaxDDCTries--);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -