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

📄 lcdddc.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    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 + -