📄 lcdddc.c
字号:
LCDDDC2_I2CWriteClockLine(hGDO, hDDL, 1); // Set SCL high
DDC2_I2C_DELAY();
if (LCDDDC2_I2CWaitForClockLineHigh(hGDO, hDDL) == FALSE)
{
DALDEBUG((DALDBG_DETAIL, "LCDDDC2_I2CReadByte: SCL didn't take - ACK failed"));
return FALSE;
}
LCDDDC2_I2CWriteClockLine(hGDO, hDDL, 0); // Set SCL low
DDC2_I2C_DELAY();
LCDDDC2_I2CWriteDataLine(hGDO, hDDL, 1); // Set SDA high
DDC2_I2C_DELAY();
return TRUE;
} // LCDDDC2_I2CReadByte()
BOOLEAN
LCDDDC2_I2CWaitForClockLineHigh(
HGDO hGDO,
HDDL hDDL
)
//
// DESCRIPTION:
// Waits till SCL goes high (SCL low period can be stretched by slow monitors).
//
// PARAMETERS:
// hDDL Points to per-adapter device extension.
//
// RETURN VALUE:
// TRUE OK - SCL high.
// FALSE SCL didn't take.
//
{
ULONG ulCount;
DALASSERT(NULL != hDDL, "hDDL is NULL!");
for (ulCount = 0; ulCount < DDC2_I2C_SCL_READ_RETRIES; ulCount++)
{
if (LCDDDC2_I2CReadClockLine(hGDO, hDDL) == TRUE)
return TRUE;
DDC2_I2C_DELAY();
}
return FALSE;
} // LCDDDC2_I2CWaitForClockLineHigh
#endif // _WIN32_WINNT >= 0x500
// Rage LT Pro and Rage Mobility:
//
// DDC through GP_IO:
//
// SCL = Pin GPIO13
// SDA = Pin GPIO12
//
// GP_IO + 1: Bit 5 = SCL Read
// Bit 4 = SDA Read
//
// GP_IO + 3: Bit 5 = SCL Direction, 0 = Input, 1 = Output
// Bit 4 = SDA Direction, 0 = Input, 1 = Output
//
// Rage XL and Rage XC:
//
// DDC through Test_IO register in LCD_INDEX.
//
// NOTE:
// For DDC communication we are the I2C master and we drive the SCL line.
// Setting I2C line to input direction drives it high (releases it high - default).
// Setting I2C line to output direction drives it low (pulls it to ground).
//
//
// TODO: Verify if there is no conflict between I2C/GP_IO Interface functions and DDC Helper functions.
// If there is a chance of conflict we should use VideoPortSynchronizeExecution() callback functions for
// I2C read/write.
//
VOID
LCDDDC2_I2CWriteClockLine(
HGDO hGDO,
HDDL hDDL,
UCHAR ucData
)
//
// DESCRIPTION:
// Sets DDC I2C clock line (SCL) low / high.
//
// PARAMETERS:
// hDDL Points to per-adapter device extension.
// ucData 0 = drive SCL low, 1 = drive SCL high.
//
{
LPGDO_RAGE_LCD hGDORageLCD;
UCHAR ucTemp;
DALASSERT(NULL != hDDL, "hDDL is NULL!");
hGDORageLCD = (LPGDO_RAGE_LCD)hGDO;
ucData &= 0x01; // Mask
ucData ^= 0x01; // Invert
if( hGDORageLCD->ulChipFamily == FAMILY_LT_PRO||
hGDORageLCD->ulChipFamily == FAMILY_RAGE_MOBILITY)
{
//
// Set the SCL enable line.
//
ucTemp = (MMREADUCHAR(hGDORageLCD->lpMMR, GP_IO, 3) &
~(0x20))| (ucData << 5);
MMWRITEUCHAR(hGDORageLCD->lpMMR,
GP_IO, ucTemp, 3
);
}
else
{
//
// Set SCL line.
//
// Set LCD_DATA register to index 28 (LCD_INDEX_TestIO).
MMWRITEUCHAR(hGDORageLCD->lpMMR, LCD_INDEX, LCD_INDEX_TestIO, 0);
//
// Set the SCL enable line (Rage XL).
//
ucTemp = (MMREADUCHAR(hGDORageLCD->lpMMR, LCD_DATA, 1) &
~(0x01))| ucData;
if (ucData)
{
ucTemp &= ~(0x04);
}
MMWRITEUCHAR(hGDORageLCD->lpMMR,
LCD_DATA, ucTemp, 1
);
}
} // LCDDDC2_I2CWriteClockLine()
VOID
LCDDDC2_I2CWriteDataLine(
HGDO hGDO,
HDDL hDDL,
UCHAR ucData
)
//
// DESCRIPTION:
// Sets DDC I2C data line (SDA) low / high.
//
// PARAMETERS:
// hDDL Points to per-adapter device extension.
// ucData 0 = drive SDA low, 1 = drive SDA high.
//
{
LPGDO_RAGE_LCD hGDORageLCD;
UCHAR ucTemp;
DALASSERT(NULL != hDDL, "hDDL is NULL!");
hGDORageLCD = (LPGDO_RAGE_LCD)hGDO;
ucData &= 0x01; // Mask
ucData ^= 0x01; // Invert
if( hGDORageLCD->ulChipFamily == FAMILY_LT_PRO||
hGDORageLCD->ulChipFamily == FAMILY_RAGE_MOBILITY)
{
//
// Set the SDA enable line.
//
ucTemp = (MMREADUCHAR(hGDORageLCD->lpMMR, GP_IO, 3) &
~(0x10)) | (ucData << 4);
MMWRITEUCHAR(hGDORageLCD->lpMMR,
GP_IO, ucTemp, 3
);
}
else
{
//
// Set SDA line.
//
// Set LCD_DATA register to index 28 (LCD_INDEX_TEST_IO).
MMWRITEUCHAR(hGDORageLCD->lpMMR, LCD_INDEX, LCD_INDEX_TestIO, 0);
//
// Set the SDA enable line (Rage XL).
//
ucTemp = (MMREADUCHAR(hGDORageLCD->lpMMR, LCD_DATA, 1) &
~(0x02)) | (ucData << 1);
if (ucData)
{
ucTemp &= ~(0x08);
}
MMWRITEUCHAR(hGDORageLCD->lpMMR,
LCD_DATA, ucTemp, 1
);
}
} // LCDDDC2_I2CWriteDataLine()
BOOLEAN
LCDDDC2_I2CReadClockLine(
HGDO hGDO,
HDDL hDDL
)
//
// DESCRIPTION:
// Reads DDC I2C clock line (SCL).
//
// PARAMETERS:
// hDDL Points to per-adapter device extension.
//
// RETURN VALUE:
// TRUE SCL high.
// FALSE SCL low.
//
{
LPGDO_RAGE_LCD hGDORageLCD;
DALASSERT(NULL != hDDL, "hDDL is NULL!");
hGDORageLCD = (LPGDO_RAGE_LCD)hGDO;
if( hGDORageLCD->ulChipFamily == FAMILY_LT_PRO||
hGDORageLCD->ulChipFamily == FAMILY_RAGE_MOBILITY)
{
//
// Read from the SCL line and return.
//
return (BOOLEAN)((MMREADUCHAR(hGDORageLCD->lpMMR,
GP_IO, 1) >> 5) & 0x01);
}
else
{
// Set LCD_DATA register to index 28 (LCD_INDEX_TEST_IO).
MMWRITEUCHAR(hGDORageLCD->lpMMR, LCD_INDEX, LCD_INDEX_TestIO, 0);
//
// Read from the SCL line and return (Rage XL).
//
return (BOOLEAN)((MMREADUCHAR(hGDORageLCD->lpMMR,
LCD_DATA, 1) >> 2) & 0x01);
}
} // LCDDDC2_I2CReadClockLine()
BOOLEAN
LCDDDC2_I2CReadDataLine(
HGDO hGDO,
HDDL hDDL
)
//
// DESCRIPTION:
// Reads DDC I2C data line (SDA).
//
// PARAMETERS:
// hDDL Points to per-adapter device extension.
//
// RETURN VALUE:
// TRUE SDA high.
// FALSE SDA low.
//
{
LPGDO_RAGE_LCD hGDORageLCD;
DALASSERT(NULL != hDDL, "hDDL is NULL!");
hGDORageLCD = (LPGDO_RAGE_LCD)hGDO;
if( hGDORageLCD->ulChipFamily == FAMILY_LT_PRO||
hGDORageLCD->ulChipFamily == FAMILY_RAGE_MOBILITY)
{
//
// Read from the SDA line and return.
//
return (BOOLEAN)((MMREADUCHAR(hGDORageLCD->lpMMR,
GP_IO, 1) >> 4) & 0x01);
}
else
{
// Set LCD_DATA register to index 28 (LCD_INDEX_TEST_IO).
MMWRITEUCHAR(hGDORageLCD->lpMMR, LCD_INDEX, LCD_INDEX_TestIO, 0);
//
// Read from the SDA line and return (Rage XL).
//
return (BOOLEAN)((MMREADUCHAR(hGDORageLCD->lpMMR,
LCD_DATA, 1) >> 3) & 0x01);
}
} // LCDDDC2_I2CReadDataLine()
VOID
LCDWaitForVerticalBlank(
HGDO hGDO,
HDDL hDDL
)
//
// DESCRIPTION:
// Waits for beginning of new vertical blank.
//
// PARAMETERS:
// hDDL Points to per-adapter device extension.
//
{
LPGDO_RAGE_LCD hGDORageLCD;
DALASSERT(NULL != hDDL, "hDDL is NULL!");
hGDORageLCD = (LPGDO_RAGE_LCD)hGDO;
//
// To do: Need to find out how to detect a v-blank for LCD panel.
//
}
VOID
LCD_DDC2_Select_SOFTWARE_I2C(
HGDO hGDO
)
//
// DESCRIPTION:
// Set I2C_SEL(0) bit to 1 (Use software I2C).
//
// PARAMETERS:
// hDDL Points to per-adapter device extension.
//
{
LPGDO_RAGE_LCD hGDORageLCD;
ULONG ulData;
hGDORageLCD = (LPGDO_RAGE_LCD)hGDO;
if( hGDORageLCD->ulChipFamily == FAMILY_LT_PRO||
hGDORageLCD->ulChipFamily == FAMILY_RAGE_MOBILITY)
{
//
// Restet bit 10, 12, 13, 26, 28, and 29 bits.
//
ulData = MMREADULONG(hGDORageLCD->lpMMR, GP_IO);
ulData &= (~0x34003400);
MMWRITEULONG(hGDORageLCD->lpMMR, GP_IO, ulData);
//
// Enable software I2C.
//
hGDORageLCD->ulI2CCntl1Data =
ulData = MMREADULONG(hGDORageLCD->lpMMR, CNTL_1);
ulData |= CNTL_1__I2C_SEL0;
MMWRITEULONG(hGDORageLCD->lpMMR, CNTL_1, ulData);
ulData &= (~CNTL_1__I2C_SEL1);
MMWRITEULONG(hGDORageLCD->lpMMR, CNTL_1, ulData);
//
// Set software control for SCL and SDA.
//
hGDORageLCD->ulI2CCntl0Data =
ulData = MMREADULONG(hGDORageLCD->lpMMR, CNTL_0);
ulData |= CNTL_0__I2C_CNTL_SDA;
MMWRITEULONG(hGDORageLCD->lpMMR, CNTL_0, ulData);
ulData |= CNTL_0__I2C_CNTL_SCL;
MMWRITEULONG(hGDORageLCD->lpMMR, CNTL_0, ulData);
}
} // End of LCD_DDC2_Select_SOFTWARE_I2C
VOID
LCD_DDC2_Restore_SOFTWARE_I2C(
HGDO hGDO
)
//
// DESCRIPTION:
// Restore I2C_CNTL_0 and I2C_CNTL_1 registers.
//
// PARAMETERS:
// hDDL Points to per-adapter device extension.
//
{
LPGDO_RAGE_LCD hGDORageLCD;
hGDORageLCD = (LPGDO_RAGE_LCD)hGDO;
if( hGDORageLCD->ulChipFamily == FAMILY_LT_PRO||
hGDORageLCD->ulChipFamily == FAMILY_RAGE_MOBILITY)
{
//
// Restore I2C_CNTL_0 register.
//
MMWRITEULONG(hGDORageLCD->lpMMR, CNTL_0, hGDORageLCD->ulI2CCntl0Data);
//
// Restore I2C_CNTL_1 register.
//
MMWRITEULONG(hGDORageLCD->lpMMR, CNTL_1, hGDORageLCD->ulI2CCntl1Data);
}
} // End of LCD_DDC2_Restore_SOFTWARE_I2C
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -