⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ltddc.c

📁 此代码为WCE5.0下显示器的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
//
// 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    LTDDC.C
*  Project        3D RAGE PRO/LT Rage Pro
*  Device         Rage
*  Device         Rage
*
*  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.
*
*  LOG OF CHANGES
*
*  1.0  03/30/98    [MM]    Initial revision
*
\*****************************************************************************/

#include "dal.h"
#include "ltddc.h"
#include "ltcrtl.h"
#include "rprod.h"

//
// DDC routines are very time sensitive. We try to put them on the same page, so when DDC2Query() 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, DDC2Query)
#if TRUE  //(_WIN32_WINNT < 0x500) [cd]:Temporary until DDC detection fixed for Win2K
#pragma alloc_text(PAGE_DDC, DDC2QueryCallback)
#pragma alloc_text(PAGE_DDC, DDC2_I2CStart)
#pragma alloc_text(PAGE_DDC, DDC2_I2CStop)
#pragma alloc_text(PAGE_DDC, DDC2_I2CWrite)
#pragma alloc_text(PAGE_DDC, DDC2_I2CWriteByte)
#pragma alloc_text(PAGE_DDC, DDC2_I2CRead)
#pragma alloc_text(PAGE_DDC, DDC2_I2CReadByte)
#pragma alloc_text(PAGE_DDC, DDC2_I2CWaitForClockLineHigh)
#endif  // _WIN32_WINNT < 0x500
#pragma alloc_text(PAGE_DDC, DDC2_I2CWriteClockLine)
#pragma alloc_text(PAGE_DDC, DDC2_I2CWriteDataLine)
#pragma alloc_text(PAGE_DDC, DDC2_I2CReadClockLine)
#pragma alloc_text(PAGE_DDC, DDC2_I2CReadDataLine)
#pragma alloc_text(PAGE_DDC, WaitForVerticalBlank)
#endif  // defined (ALLOC_PRAGMA)


#if FALSE  //(_WIN32_WINNT >= 0x500) [cd]:Temporary until DDC detection fixed for Win2K

BOOLEAN
DDC2Query(
    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 = DDC2_I2CWriteClockLine;
    i2c.WriteDataLine  = DDC2_I2CWriteDataLine;
    i2c.ReadClockLine  = DDC2_I2CReadClockLine;
    i2c.ReadDataLine   = DDC2_I2CReadDataLine;
    i2c.WaitVsync      = WaitForVerticalBlank;
    i2c.Size           = sizeof (I2C_FNC_TABLE);

    if (VideoPortDDCMonitorHelper(hDDL, &i2c, lpucQueryBuffer, ulLength) == FALSE)
    {
        DALDEBUG((DALDBG_DETAIL, "DDC2Query: DDC query failed"));
        return FALSE;
    }

    DALDEBUG((DALDBG_DETAIL, "DDC2Query: DDC query OK"));
    //[MF]DebugDumpHex(DEBUG_NORMAL, "DDC2Query: EDID", lpucQueryBuffer, ulLength);

    return TRUE;
}   // DDC2Query()

#else   // _WIN32_WINNT >= 0x500

BOOLEAN
DDC2Query(
    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 ddcQueryContext;

    DALASSERT(NULL != hDDL, "hDDL is NULL!");
    DALASSERT(NULL != lpucQueryBuffer, "lpucQueryBuffer is NULL!");

    ddcQueryContext.hGDO            = hGDO;
    ddcQueryContext.hDDL            = hDDL;
    ddcQueryContext.lpucQueryBuffer = lpucQueryBuffer;
    ddcQueryContext.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, DDC2QueryCallback, (LPVOID)&ddcQueryContext);
#else
    return FALSE;   // DDC not supported in WinCE
#endif
}   // DDC2Query()

BOOLEAN
DDC2QueryCallback(
    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
	ULONG ulRetryCounter;
    BOOLEAN bWriteStartAddress;
    LPGDO_RAGE_CRT hGDORageCRT;

    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!");

    hGDORageCRT = (LPGDO_RAGE_CRT)lpDdcQueryContext->hGDO;

    // EPR 40230
	// Initialize GPIO_15 and GPIO_16
    // Ensure CRTC_ON bit is set.
    //
    vInitializeLT_GIO( lpDdcQueryContext->hGDO );
    vEnsureCRTON( 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.
    //

    DDC2_I2CWriteDataLine(lpDdcQueryContext->hGDO,
                          lpDdcQueryContext->hDDL,
                          1);

    DDC2_I2CWriteClockLine(lpDdcQueryContext->hGDO,
                           lpDdcQueryContext->hDDL,
                           0);

    DELAY_MILLISECONDS(15);
    DDC2_I2CWriteClockLine(lpDdcQueryContext->hGDO,
                           lpDdcQueryContext->hDDL,
                           1);

    if (DDC2_I2CWaitForClockLineHigh(lpDdcQueryContext->hGDO,
                                     lpDdcQueryContext->hDDL) == FALSE)
    {
        DALDEBUG((DALDBG_DETAIL, "DDC2_QueryCallback: Can't switch to DDC2"));
        vRestoreCRTON( lpDdcQueryContext->hGDO );
		return FALSE;
    }

    //
    // Tell the monitor that we want to talk to it and give the address we want to start with.
    //

    lpDdcQueryContext->lpucQueryBuffer[0] = (UCHAR)DDC2_I2C_MONITOR_ADDRESS_WRITE;
    lpDdcQueryContext->lpucQueryBuffer[1] = (UCHAR)DDC2_I2C_EDID_START_ADDRESS;

	// EPR 40230
    // Some monitor may take longer to acknowledge this write When CRT_ON bit is
    // just turned on. So we have to keep trying here until monitor acknowledge.
    //

    ulRetryCounter = hGDORageCRT->ulRetryCounter;
    bWriteStartAddress = FALSE;
    while ( ulRetryCounter > 0 && bWriteStartAddress == FALSE )
    {
        DELAY_MILLISECONDS(10);
        bWriteStartAddress = (DDC2_I2CWrite(lpDdcQueryContext->hGDO,
                                 lpDdcQueryContext->hDDL,
                                 lpDdcQueryContext->lpucQueryBuffer,
                                 2));
        --ulRetryCounter;
    }

    if ( bWriteStartAddress == FALSE )
    {
        DALDEBUG((DALDBG_DETAIL, "DDC2_QueryCallback: Can't write - DDC2 not supported"));
        vRestoreCRTON( lpDdcQueryContext->hGDO );
        return FALSE;
    }
    
    //
    // Read EDID from the monitor.
    //

    ZEROMEMORY(lpDdcQueryContext->lpucQueryBuffer, lpDdcQueryContext->ulLength);

    if (DDC2_I2CRead(lpDdcQueryContext->hGDO,
                     lpDdcQueryContext->hDDL,
                     lpDdcQueryContext->lpucQueryBuffer,
                     lpDdcQueryContext->ulLength) == FALSE)
    {
        DALDEBUG((DALDBG_DETAIL, "DDC2_QueryCallback: Can't read - DDC2 not supported"));
        vRestoreCRTON( lpDdcQueryContext->hGDO );
		return FALSE;
    }

    //[MF]DebugDumpHex(DEBUG_NORMAL, "DDC2QueryCallback: 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, "DDC2_QueryCallback: EDID checksum = 0x%08X", ulChecksum));

    if ((ulChecksum & 0xFF) || (0 == ulChecksum))
    {
		vRestoreCRTON( lpDdcQueryContext->hGDO );
        return FALSE;
	}

    vRestoreCRTON( lpDdcQueryContext->hGDO );
    return TRUE;
}   // DDC2QueryCallback()

// EPR 32286
BOOLEAN
DDC2DETQuery(
    HGDO hGDO,
    HDDL hDDL,
    LPUCHAR lpucQueryBuffer
    )
//
// DESCRIPTION:
//  Reads the partial EDID structure from the monitor using DDC.
//
// PARAMETERS:
//  hDDL            Points to per-adapter device extension.
//  lpucQueryBuffer Buffer where information will be stored.
//
// RETURN VALUE:
//  TRUE        DDC read OK.
//  FALSE       DDC read failed.
//
{
    DDC2_QUERY_CONTEXT ddcQueryContext;

    DALASSERT(NULL != hDDL, "hDDL is NULL!");
    DALASSERT(NULL != lpucQueryBuffer, "lpucQueryBuffer is NULL!");

    ddcQueryContext.hGDO            = hGDO;
    ddcQueryContext.hDDL            = hDDL;
    ddcQueryContext.lpucQueryBuffer = lpucQueryBuffer;

    //
    // 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, DDC2DETQueryCallback, (LPVOID)&ddcQueryContext);
#else
    return FALSE;  // DDC not supported on WinCE
#endif
}   // DDC2DETQuery()

// EPR 32286
BOOLEAN
DDC2DETQueryCallback(
    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_CRT hGDORageCRT;

    DALASSERT(NULL != lpDdcQueryContext, "pDdcQueryContext is NULL!");
    DALASSERT(NULL != lpDdcQueryContext->hDDL, "hDDL is NULL!");

    hGDORageCRT = (LPGDO_RAGE_CRT)lpDdcQueryContext->hGDO;

	
    // EPR 40230
	// Initialize GPIO_15 and GPIO_16
    // Ensure CRTC_ON bit is set.
	//
    vInitializeLT_GIO( lpDdcQueryContext->hGDO );
    vEnsureCRTON( 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.
    //

    DDC2_I2CWriteDataLine(lpDdcQueryContext->hGDO,
                          lpDdcQueryContext->hDDL,
                          1);

    DDC2_I2CWriteClockLine(lpDdcQueryContext->hGDO,
                           lpDdcQueryContext->hDDL,
                           0);

    DELAY_MILLISECONDS(15);
    DDC2_I2CWriteClockLine(lpDdcQueryContext->hGDO,
                           lpDdcQueryContext->hDDL,
                           1);

    if (DDC2_I2CWaitForClockLineHigh(lpDdcQueryContext->hGDO,
                                     lpDdcQueryContext->hDDL) == FALSE)
    {
        DALDEBUG((DALDBG_DETAIL, "DDC2_QueryCallback: Can't switch to DDC2"));
        vRestoreCRTON( lpDdcQueryContext->hGDO );
		return FALSE;
    }

    //
    // Tell the monitor that we want to talk to it and give the address we want to start with.
    //

    lpDdcQueryContext->lpucQueryBuffer[0] = (UCHAR)DDC2_I2C_MONITOR_ADDRESS_WRITE;
    lpDdcQueryContext->lpucQueryBuffer[1] = (UCHAR)DDC2_I2C_EDID_START_ADDRESS;
    lpDdcQueryContext->ulLength = 21;

	DELAY_MILLISECONDS(10);
    if (DDC2_I2CWrite(lpDdcQueryContext->hGDO,
                      lpDdcQueryContext->hDDL,
                      lpDdcQueryContext->lpucQueryBuffer,
                      2) == FALSE)
    {
        DALDEBUG((DALDBG_DETAIL, "DDC2DETQueryCallback: Can't write - DDC2 not supported"));
        vRestoreCRTON( lpDdcQueryContext->hGDO );
		return FALSE;
    }

    //
    // Read partial EDID from the monitor.
    //

    ZEROMEMORY(lpDdcQueryContext->lpucQueryBuffer, lpDdcQueryContext->ulLength);

    if (DDC2_I2CRead(lpDdcQueryContext->hGDO,
                     lpDdcQueryContext->hDDL,
                     lpDdcQueryContext->lpucQueryBuffer,
                     lpDdcQueryContext->ulLength) == FALSE)
    {
        DALDEBUG((DALDBG_DETAIL, "DDC2DETQueryCallback: Can't read - DDC2 not supported"));
        vRestoreCRTON( lpDdcQueryContext->hGDO );
		return FALSE;
    }
    
	vRestoreCRTON( lpDdcQueryContext->hGDO );
    return TRUE;
}   // DDC2DETQueryCallback()

BOOLEAN
DDC2_I2CStart(
    HGDO hGDO,
    HDDL hDDL
    )
//
// DESCRIPTION:
//  Starts I2C communication.
//
// PARAMETERS:
//  hDDL  Points to per-adapter device extension.
//
// RETURN VALUE:
//  TRUE        OK.
//  FALSE       Failed.
//
{
    ULONG ulRetry;

    DALASSERT(NULL != hDDL, "hDDL is NULL!");

    //
    // The I2C communications start signal is a SDA high->low while the SCL is high.
    //

    for (ulRetry = 0; ulRetry <= DDC2_I2C_START_RETRIES; ulRetry++)
    {
        DDC2_I2CWriteDataLine(hGDO, hDDL, 1);           // Set SDA high
        DDC2_I2C_DELAY();
        if (DDC2_I2CReadDataLine(hGDO, hDDL) == FALSE)  // SDA didn't take - retry
            continue;
        DDC2_I2CWriteClockLine(hGDO, hDDL, 1);          // Set SCL high

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -