mirror of
https://github.com/X11Libre/xf86-video-xgi.git
synced 2026-03-24 01:24:35 +00:00
[Tormod: Remove unnecessary else and fix spelling in messages] Signed-off-by: Tormod Volden <debian.tormod@gmail.com> Reviewed-by: Jeremy Huddleston <jeremyhu@apple.com>
1896 lines
52 KiB
C
Executable File
1896 lines
52 KiB
C
Executable File
/* Jong 03/12/2009; added for supporting Xorg 7.0 */
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "osdef.h"
|
|
#include "vgatypes.h"
|
|
/* #include "vb_util.h" */ /* Jong@08032009 */
|
|
#include "vb_def.h"
|
|
|
|
#ifdef WIN2000
|
|
#include <dderror.h>
|
|
#include <devioctl.h>
|
|
#include <miniport.h>
|
|
#include <ntddvdeo.h>
|
|
#include <video.h>
|
|
#include "xgiv.h"
|
|
#include "dd_i2c.h"
|
|
#include "tools.h"
|
|
#endif /* WIN2000 */
|
|
|
|
#ifdef LINUX_XF86
|
|
#include "xf86.h"
|
|
#include "xf86PciInfo.h"
|
|
#include "xgi.h"
|
|
#include "xgi_regs.h"
|
|
#include "vb_i2c.h"
|
|
#endif
|
|
|
|
#ifdef LINUX_KERNEL
|
|
#include <linux/version.h>
|
|
#include <asm/io.h>
|
|
#include <linux/types.h>
|
|
#include "vb_i2c.h"
|
|
|
|
/* Jong@08052009 */
|
|
/* #include <linux/delay.h> */ /* udelay */
|
|
|
|
#include "XGIfb.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*char I2CAccessBuffer(PXGI_HW_DEVICE_INFO pHWDE, PI2CControl I2CCntl, ULONG DevAddr, ULONG Offset, PUCHAR pBuffer, ULONG ulSize); */
|
|
char vGetEDIDExtensionBlocks(PXGI_HW_DEVICE_INFO pHWDE, PI2CControl pI2C, PUCHAR pjBuffer, ULONG ulBufferSize);
|
|
char vGetEnhancedEDIDBlock(PXGI_HW_DEVICE_INFO pHWDE, PI2CControl pI2C, ULONG ulBlockID, ULONG ulBlockTag, PUCHAR pjBuffer, ULONG ulBufferSize);
|
|
|
|
char I2COpen (PXGI_HW_DEVICE_INFO pHWDE,ULONG ulI2CEnable, ULONG ulChannelID, PI2CControl pI2CControl);
|
|
char I2CAccess(PXGI_HW_DEVICE_INFO pHWDE, PI2CControl pI2CControl);
|
|
BOOLEAN I2CNull( PXGI_HW_DEVICE_INFO pHWDE, PI2CControl pI2CControl);
|
|
BOOLEAN I2CRead(PXGI_HW_DEVICE_INFO pHWDE, PI2CControl pI2CControl);
|
|
BOOLEAN I2CWrite(PXGI_HW_DEVICE_INFO pHWDE, PI2CControl pI2CControl);
|
|
BOOLEAN ResetI2C(PXGI_HW_DEVICE_INFO pHWDE, PI2CControl pI2CControl);
|
|
BOOLEAN I2CRead(PXGI_HW_DEVICE_INFO pHWDE,PI2CControl pI2CControl);
|
|
BOOLEAN I2CWrite(PXGI_HW_DEVICE_INFO pHWDE, PI2CControl pI2CControl);
|
|
BOOLEAN ResetI2C(PXGI_HW_DEVICE_INFO pHWDE, PI2CControl pI2CControl);
|
|
BOOLEAN Ack (PXGI_HW_DEVICE_INFO pHWDE, bool fPut);
|
|
BOOLEAN NoAck(PXGI_HW_DEVICE_INFO pHWDE);
|
|
BOOLEAN Start( PXGI_HW_DEVICE_INFO pHWDE);
|
|
BOOLEAN Stop(PXGI_HW_DEVICE_INFO pHWDE);
|
|
BOOLEAN WriteUCHARI2C(PXGI_HW_DEVICE_INFO pHWDE, UCHAR cData);
|
|
BOOLEAN ReadUCHARI2C(PXGI_HW_DEVICE_INFO pHWDE, PUCHAR pBuffer);
|
|
UCHAR ReverseUCHAR(UCHAR data);
|
|
|
|
VOID vWriteClockLineDVI(PXGI_HW_DEVICE_INFO pHWDE, UCHAR data);
|
|
VOID vWriteDataLineDVI(PXGI_HW_DEVICE_INFO pHWDE, UCHAR data);
|
|
BOOLEAN bReadClockLineDVI(PXGI_HW_DEVICE_INFO pHWDE);
|
|
BOOLEAN bReadDataLineDVI(PXGI_HW_DEVICE_INFO pHWDE);
|
|
|
|
BOOLEAN bEDIDCheckSum(PUCHAR pjEDIDBuf,ULONG ulBufSize);
|
|
|
|
VOID vWriteClockLineCRT(PXGI_HW_DEVICE_INFO pHWDE, UCHAR data);
|
|
VOID vWriteDataLineCRT(PXGI_HW_DEVICE_INFO pHWDE, UCHAR data);
|
|
BOOLEAN bReadClockLineCRT(PXGI_HW_DEVICE_INFO pHWDE);
|
|
BOOLEAN bReadDataLineCRT(PXGI_HW_DEVICE_INFO pHWDE);
|
|
|
|
/* Jong@08102009 */
|
|
VOID vWriteClockLineFCNT(PXGI_HW_DEVICE_INFO pHWDE, UCHAR data);
|
|
VOID vWriteDataLineFCNT(PXGI_HW_DEVICE_INFO pHWDE, UCHAR data);
|
|
BOOLEAN bReadClockLineFCNT(PXGI_HW_DEVICE_INFO pHWDE);
|
|
BOOLEAN bReadDataLineFCNT(PXGI_HW_DEVICE_INFO pHWDE);
|
|
|
|
/* #define CRT_I2C */
|
|
VOID vWriteClockLine(PXGI_HW_DEVICE_INFO pHWDE, UCHAR data);
|
|
VOID vWriteDataLine(PXGI_HW_DEVICE_INFO pHWDE, UCHAR data);
|
|
BOOLEAN bReadClockLine(PXGI_HW_DEVICE_INFO pHWDE);
|
|
BOOLEAN bReadDataLine(PXGI_HW_DEVICE_INFO pHWDE);
|
|
|
|
/* Jong@08052009 */
|
|
extern UCHAR XGI_GetRegByte(XGIIOADDRESS port);
|
|
|
|
/* Jong@08052009 */
|
|
void I2C_DelayUS(ULONG MicroSeconds)
|
|
{
|
|
ErrorF("");
|
|
/* udelay(MicroSeconds); */
|
|
}
|
|
|
|
|
|
typedef enum _I2C_ACCESS_CMD
|
|
{
|
|
I2C_WRITE = 0,
|
|
I2C_READ
|
|
/* Jong 08/18/2008; for XFree86 */
|
|
/* WRITE = 0,
|
|
READ */
|
|
} I2C_ACCESS_CMD;
|
|
|
|
/* For XG21 */
|
|
|
|
#define ENABLE_GPIOA 0x01
|
|
#define ENABLE_GPIOB 0x02
|
|
#define ENABLE_GPIOC 0x04
|
|
VOID
|
|
EnableGPIOA(
|
|
PUCHAR pjIOPort, I2C_ACCESS_CMD CmdType)
|
|
{
|
|
PDEBUGI2C(ErrorF("EnableGPIOA()-pjIOPort=0x%x...\n", pjIOPort));
|
|
|
|
UCHAR ujCR4A = XGI_GetReg(pjIOPort, IND_CR4A_GPIO_REG_III);
|
|
|
|
if (CmdType == I2C_WRITE)
|
|
{
|
|
ujCR4A &= ~ENABLE_GPIOA;
|
|
}
|
|
else
|
|
{
|
|
ujCR4A |= ENABLE_GPIOA;
|
|
}
|
|
|
|
XGI_SetReg(pjIOPort, IND_CR4A_GPIO_REG_III, ujCR4A);
|
|
}
|
|
|
|
VOID
|
|
EnableGPIOB(
|
|
PUCHAR pjIOPort, I2C_ACCESS_CMD CmdType)
|
|
{
|
|
UCHAR ujCR4A = XGI_GetReg(pjIOPort, IND_CR4A_GPIO_REG_III);
|
|
|
|
if (CmdType == I2C_WRITE)
|
|
{
|
|
ujCR4A &= ~ENABLE_GPIOB;
|
|
}
|
|
else
|
|
{
|
|
ujCR4A |= ENABLE_GPIOB;
|
|
}
|
|
|
|
XGI_SetReg(pjIOPort, IND_CR4A_GPIO_REG_III, ujCR4A);
|
|
}
|
|
|
|
VOID
|
|
EnableGPIOC(
|
|
PUCHAR pjIOPort, I2C_ACCESS_CMD CmdType)
|
|
{
|
|
UCHAR ujCR4A = XGI_GetReg(pjIOPort, IND_CR4A_GPIO_REG_III);
|
|
|
|
if (CmdType == I2C_WRITE)
|
|
{
|
|
ujCR4A &= ~ENABLE_GPIOC;
|
|
}
|
|
else
|
|
{
|
|
ujCR4A |= ENABLE_GPIOC;
|
|
}
|
|
|
|
XGI_SetReg(pjIOPort, IND_CR4A_GPIO_REG_III, ujCR4A);
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
* Function: getGPIORWTranser()
|
|
*
|
|
* Description: This function is used based on Z9. Because of wrongly wired deployment by HW
|
|
* the CR4A and CR48 for GPIO pins have reverse sequence. For example,
|
|
* D[7:0] for read function is ordered as GPIOA to GPIOH, but D[7:0] for read
|
|
* is as GPIOH~GPIOA
|
|
*/
|
|
UCHAR
|
|
getGPIORWTransfer(
|
|
UCHAR ujDate)
|
|
{
|
|
UCHAR ujRet = 0;
|
|
UCHAR i = 0;
|
|
|
|
for (i=0; i<8; i++)
|
|
{
|
|
ujRet = ujRet << 1;
|
|
ujRet |= GETBITS(ujDate >> i, 0:0);
|
|
}
|
|
|
|
return ujRet;
|
|
}
|
|
|
|
|
|
|
|
char I2CAccessBuffer(PXGI_HW_DEVICE_INFO pHWDE, PI2CControl pI2CControl, ULONG ulDevAddr,
|
|
ULONG ulOffset, PUCHAR pBuffer,ULONG ulSize)
|
|
{
|
|
|
|
I2CControl I2C;
|
|
ULONG i;
|
|
|
|
if ((ulSize == 0) || (pBuffer == NULL)) {
|
|
return -1;
|
|
}
|
|
if (ulDevAddr & 1) {
|
|
return -1;
|
|
}
|
|
if ((ulDevAddr > 0xFF) || (ulOffset > 0xFF)) {
|
|
return -1;
|
|
}
|
|
|
|
I2C.Command = pI2CControl->Command;
|
|
I2C.dwCookie = pI2CControl->dwCookie;
|
|
I2C.Data = pI2CControl->Data;
|
|
I2C. Flags = pI2CControl->Flags;
|
|
I2C.Status = pI2CControl->Status;
|
|
I2C.ClockRate = pI2CControl->ClockRate;
|
|
switch (pI2CControl->Command) {
|
|
case I2C_COMMAND_READ:
|
|
/* Reset I2C Bus */
|
|
I2C.Command = I2C_COMMAND_RESET;
|
|
I2CAccess(pHWDE, &I2C);
|
|
if (I2C.Status != I2C_STATUS_NOERROR) {
|
|
pI2CControl->Status = I2C.Status;
|
|
break;
|
|
}
|
|
|
|
/* Write Device Address */
|
|
I2C.Command = I2C_COMMAND_WRITE;
|
|
I2C.Flags = I2C_FLAGS_START | I2C_FLAGS_ACK;
|
|
I2C.Data = (UCHAR)ulDevAddr;
|
|
I2CAccess(pHWDE, &I2C);
|
|
if (I2C.Status != I2C_STATUS_NOERROR) {
|
|
pI2CControl->Status = I2C.Status;
|
|
break;
|
|
}
|
|
|
|
/* Write Register Offset */
|
|
I2C.Command = I2C_COMMAND_WRITE;
|
|
I2C.Flags = I2C_FLAGS_ACK | I2C_FLAGS_STOP;
|
|
I2C.Data = (UCHAR)ulOffset;
|
|
I2CAccess(pHWDE, &I2C);
|
|
if (I2C.Status != I2C_STATUS_NOERROR) {
|
|
pI2CControl->Status = I2C.Status;
|
|
break;
|
|
}
|
|
|
|
/* Write Device Read Address */
|
|
I2C.Command = I2C_COMMAND_WRITE;
|
|
I2C.Flags = I2C_FLAGS_START | I2C_FLAGS_ACK;
|
|
I2C.Data = (UCHAR)ulDevAddr + 1;
|
|
I2CAccess(pHWDE, &I2C);
|
|
if (I2C.Status != I2C_STATUS_NOERROR) {
|
|
pI2CControl->Status = I2C.Status;
|
|
break;
|
|
}
|
|
|
|
/* Read Data */
|
|
for (i=0; i< ulSize; i++) {
|
|
I2C.Command = I2C_COMMAND_READ;
|
|
I2C.Flags = I2C_FLAGS_ACK;
|
|
if (i == ulSize - 1) { /* Read Last UCHAR */
|
|
I2C.Flags |= I2C_FLAGS_STOP;
|
|
}
|
|
I2CAccess(pHWDE, &I2C);
|
|
if (I2C.Status != I2C_STATUS_NOERROR) {
|
|
pI2CControl->Status = I2C.Status;
|
|
break;
|
|
}
|
|
*pBuffer = I2C.Data;
|
|
pBuffer++;
|
|
}
|
|
pI2CControl->Status = I2C.Status;
|
|
break;
|
|
|
|
case I2C_COMMAND_WRITE:
|
|
/* Reset I2C Bus */
|
|
I2C.Command = I2C_COMMAND_RESET;
|
|
I2CAccess(pHWDE, &I2C);
|
|
if (I2C.Status != I2C_STATUS_NOERROR) {
|
|
pI2CControl->Status = I2C.Status;
|
|
break;
|
|
}
|
|
|
|
/* Write Device Address */
|
|
I2C.Command = I2C_COMMAND_WRITE;
|
|
I2C.Flags = I2C_FLAGS_START | I2C_FLAGS_ACK;
|
|
I2C.Data = (UCHAR)ulDevAddr;
|
|
I2CAccess(pHWDE, &I2C);
|
|
if (I2C.Status != I2C_STATUS_NOERROR) {
|
|
pI2CControl->Status = I2C.Status;
|
|
break;
|
|
}
|
|
|
|
/* Write Register Offset */
|
|
I2C.Command = I2C_COMMAND_WRITE;
|
|
I2C.Flags = I2C_FLAGS_ACK;
|
|
I2C.Data = (UCHAR)ulOffset;
|
|
I2CAccess(pHWDE, &I2C);
|
|
if (I2C.Status != I2C_STATUS_NOERROR) {
|
|
pI2CControl->Status = I2C.Status;
|
|
break;
|
|
}
|
|
|
|
/* Write Data */
|
|
for (i=0; i< ulSize; i++) {
|
|
I2C.Command = I2C_COMMAND_WRITE;
|
|
I2C.Flags = I2C_FLAGS_ACK;
|
|
if (i == ulSize - 1) { /* Read Last UCHAR */
|
|
I2C.Flags |= I2C_FLAGS_STOP;
|
|
}
|
|
I2C.Data = *pBuffer;
|
|
I2CAccess(pHWDE, &I2C);
|
|
if (I2C.Status != I2C_STATUS_NOERROR) {
|
|
pI2CControl->Status = I2C.Status;
|
|
break;
|
|
}
|
|
pBuffer++;
|
|
}
|
|
pI2CControl->Status = I2C.Status;
|
|
break;
|
|
}
|
|
|
|
if (pI2CControl->Status == I2C_STATUS_NOERROR)
|
|
{
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
|
|
/*************************************************************************
|
|
// char vGetEDIDExtensionBlocks
|
|
//
|
|
// Routine Description:
|
|
// Reads the extension part behind a 128KB block of EDID which is in 1.3
|
|
// format. The extension part can be distributed into 128KB-blocks.
|
|
//
|
|
// Arguments:
|
|
// pHWDE - Hardware extension object pointer
|
|
// pI2C - I2C pointer
|
|
// pjBuffer - EDID Buffer
|
|
// ulBufferSize - Buffer size
|
|
//
|
|
//
|
|
// Return Value:
|
|
// Status of returning EDID.
|
|
// NO_ERROR - success
|
|
// ERROR_INVALID_PARAMETER - failed
|
|
//
|
|
****************************************************************************/
|
|
char vGetEDIDExtensionBlocks(
|
|
PXGI_HW_DEVICE_INFO pHWDE,
|
|
PI2CControl pI2C,
|
|
PUCHAR pjBuffer,
|
|
ULONG ulBufferSize)
|
|
{
|
|
char status;
|
|
ULONG ulBlockTag;
|
|
ULONG i;
|
|
PUCHAR pBlockMap;
|
|
|
|
|
|
if ((ulBufferSize < 128) || (pjBuffer == NULL))
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
pI2C->Command = I2C_COMMAND_READ;
|
|
status = I2CAccessBuffer(pHWDE, pI2C, 0xA0, 128, pjBuffer, 128);
|
|
if ((status != 0) || (pI2C->Status != I2C_STATUS_NOERROR))
|
|
{
|
|
return status;
|
|
}
|
|
|
|
if (bEDIDCheckSum(pjBuffer, 128) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
if (*pjBuffer == 0xF0)
|
|
{ /* A Block Map, we should read other extension blocks*/
|
|
pBlockMap = pjBuffer;
|
|
for (i=1; i<=126; i++)
|
|
{
|
|
ulBlockTag = *(pBlockMap + i);
|
|
if (ulBlockTag)
|
|
{
|
|
pjBuffer += 128;
|
|
ulBufferSize -= 128;
|
|
status = vGetEnhancedEDIDBlock(pHWDE, pI2C, i+1, ulBlockTag, pjBuffer, ulBufferSize);
|
|
if ((status != 0) || (pI2C->Status != I2C_STATUS_NOERROR))
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (i > 1)
|
|
{
|
|
return 0; /* All Extension blocks must be sequential, no holes allowed. (VESA E-EDID)*/
|
|
}
|
|
else
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
/* We should read block # 128 */
|
|
pjBuffer += 128;
|
|
ulBufferSize -= 128;
|
|
ulBlockTag = 0xF0;
|
|
status = vGetEnhancedEDIDBlock(pHWDE, pI2C, 128, ulBlockTag, pjBuffer, ulBufferSize);
|
|
if ((status != 0) || (pI2C->Status != I2C_STATUS_NOERROR))
|
|
{
|
|
return 0; /* Monitor may has only 128 blocks (0~127) */
|
|
}
|
|
|
|
pBlockMap = pjBuffer;
|
|
for (i=1; i<=126; i++)
|
|
{ /* Read Block # 128 ~ 254 */
|
|
ulBlockTag = *(pBlockMap + i);
|
|
if (ulBlockTag)
|
|
{
|
|
pjBuffer += 128;
|
|
ulBufferSize -= 128;
|
|
status = vGetEnhancedEDIDBlock(pHWDE, pI2C, i+128, ulBlockTag, pjBuffer, ulBufferSize);
|
|
if ((status != 0) || (pI2C->Status != I2C_STATUS_NOERROR))
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (i > 1)
|
|
{
|
|
return 0; /* All Extension blocks must be sequential, no holes allowed. (VESA E-EDID) */
|
|
}
|
|
else
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*************************************************************************
|
|
// char vGetEnhancedEDIDBlock
|
|
//
|
|
// Routine Description:
|
|
// Get the EDID which is in Enhanced-EDID format via I2C. The parse-in block
|
|
// tag(ulBlockTag) and the first UCHAR of the retrieved buffer should be identical.
|
|
// Returns error when they are not, otherwise return NO_ERROR.
|
|
//
|
|
// Arguments:
|
|
// pHWDE - Hardware extension object pointer
|
|
// pI2C - I2C pointer
|
|
// ulBlockID - Block ID
|
|
// ulBlockTag - Block Tag
|
|
// pjBuffer - EDID Buffer
|
|
// ulBufferSize - Buffer size
|
|
//
|
|
//
|
|
// Return Value:
|
|
// Status of returning EDID.
|
|
// NO_ERROR - success
|
|
// ERROR_INVALID_PARAMETER - failed
|
|
//
|
|
****************************************************************************/
|
|
char vGetEnhancedEDIDBlock(
|
|
PXGI_HW_DEVICE_INFO pHWDE,
|
|
PI2CControl pI2C,
|
|
ULONG ulBlockID,
|
|
ULONG ulBlockTag,
|
|
PUCHAR pjBuffer,
|
|
ULONG ulBufferSize)
|
|
{
|
|
ULONG ulOffset, SegmentID;
|
|
char status;
|
|
|
|
if ((ulBufferSize < 128) || (pjBuffer == NULL))
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
SegmentID = ulBlockID / 2;
|
|
ulOffset = (ulBlockID % 2) * 128;
|
|
|
|
pI2C->Command = I2C_COMMAND_WRITE;
|
|
status = I2CAccessBuffer(pHWDE, pI2C, 0x60, 0, (PUCHAR)&SegmentID, 1);
|
|
if ((status == NO_ERROR) && (pI2C->Status == I2C_STATUS_NOERROR))
|
|
{
|
|
pI2C->Command = I2C_COMMAND_READ;
|
|
status = I2CAccessBuffer(pHWDE, pI2C, 0xA0, ulOffset, pjBuffer, 128);
|
|
if ((status == 0) && (pI2C->Status == I2C_STATUS_NOERROR))
|
|
{
|
|
if (*pjBuffer != (UCHAR)ulBlockTag)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
if (bEDIDCheckSum(pjBuffer, 128) != 0)
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
|
|
return NO_ERROR;
|
|
}
|
|
char I2COpen (PXGI_HW_DEVICE_INFO pHWDE, ULONG ulI2CEnable, ULONG ulChannelID, PI2CControl pI2CControl)
|
|
{
|
|
/*
|
|
// printk("\nI2COpen(%d) : Channel ID = %d\n", ulI2CEnable, ulChannelID);
|
|
// we need to determine the Context area for each command we receive
|
|
// i.e. which hardware I2C bus is the command for.
|
|
// this is unimplemented here!
|
|
*/
|
|
if (ulChannelID >= MAX_I2C_CHANNEL)
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
if (ulI2CEnable) /* Open I2C Port */
|
|
{
|
|
/* // verify clock rate. If you cannot implement the given rate,
|
|
// enable a lower clock rate closest to the request clock rate.
|
|
//
|
|
// put a better check here if your device can only do discrete
|
|
// clock rate values.
|
|
*/
|
|
if (pI2CControl->ClockRate > I2C_MAX_CLOCK_RATE)
|
|
{
|
|
pI2CControl->ClockRate = I2C_MAX_CLOCK_RATE;
|
|
}
|
|
pI2CControl->Status = I2C_STATUS_NOERROR;
|
|
}
|
|
else /* Close I2C Port*/
|
|
{
|
|
/* Set Acquired state to FALSE */
|
|
|
|
pI2CControl->dwCookie = 0;
|
|
/* Set status */
|
|
pI2CControl->Status = I2C_STATUS_NOERROR;
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
}
|
|
/* end of I2COpen */
|
|
char I2CAccess(PXGI_HW_DEVICE_INFO pHWDE, PI2CControl pI2CControl)
|
|
{
|
|
ULONG ulChannel = pI2CControl->dwCookie % MAX_I2C_CHANNEL;
|
|
|
|
|
|
if (pI2CControl->ClockRate > I2C_MAX_CLOCK_RATE)
|
|
{
|
|
pI2CControl->ClockRate = I2C_MAX_CLOCK_RATE;
|
|
}
|
|
if (pI2CControl->ClockRate == 0) {
|
|
pI2CControl->ClockRate = 20000;
|
|
}
|
|
|
|
pHWDE->I2CDelay = (1000000 / pI2CControl->ClockRate) * 10 * 2; /* in 100ns */
|
|
/* pHWDE->I2CDelay = (1000000 / pI2CControl->ClockRate) * 10; */ /* in 100ns */
|
|
/* pHWDE->I2CDelay = 100; */
|
|
/* PDEBUG(ErrorF("I2CAccess()-I2CDelay = %d...\n", pHWDE->I2CDelay)); */
|
|
|
|
/* pHWDE->I2CDelay = 100; */ /* Jong@08032009 */
|
|
|
|
switch (pI2CControl->Command)
|
|
{
|
|
/* Issue a STOP or START without a READ or WRITE Command */
|
|
case I2C_COMMAND_NULL:
|
|
if (I2CNull(pHWDE, pI2CControl) == FALSE) break;
|
|
/* if (pI2CControl->Flags & I2C_FLAGS_STOP) {
|
|
pI2CContext->dwI2CPortAcquired = FALSE;
|
|
}
|
|
*/ break;
|
|
|
|
/* READ or WRITE Command */
|
|
case I2C_COMMAND_READ:
|
|
if (I2CRead(pHWDE, pI2CControl) == FALSE) break;
|
|
/* if (pI2CControl->Flags & I2C_FLAGS_STOP) {
|
|
pI2CContext->dwI2CPortAcquired = FALSE;
|
|
}
|
|
*/ break;
|
|
|
|
case I2C_COMMAND_WRITE:
|
|
if (I2CWrite(pHWDE, pI2CControl) == FALSE) break;
|
|
/* if (pI2CControl->Flags & I2C_FLAGS_STOP) {
|
|
pI2CContext->dwI2CPortAcquired = FALSE;
|
|
}
|
|
*/ break;
|
|
|
|
case I2C_COMMAND_STATUS:
|
|
pI2CControl->Status = I2C_STATUS_NOERROR;
|
|
break;
|
|
|
|
case I2C_COMMAND_RESET:
|
|
/* Reset I2C bus */
|
|
if (ResetI2C(pHWDE, pI2CControl) == FALSE) break;
|
|
break;
|
|
|
|
default:
|
|
/* Invalid Command */
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
|
|
/* printk("\nI2CAccess(): I2C Cmd = 0x%X I2C Flags = 0x%X I2C Status = 0x%X I2C Data = 0x%X", pI2CControl->Command, pI2CControl->Flags, pI2CControl->Status, pI2CControl->Data); */
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
/*^^*
|
|
* Function: I2CNull
|
|
*
|
|
* Purpose: To complete an I2C instruction.
|
|
*
|
|
* Inputs: lpI2C_ContextData : PI2C_CONTEXT, pointer to data struct associated
|
|
* with card being accessed
|
|
* I2CCntl : PI2CControl, pointer to I2C control structure
|
|
*
|
|
* Outputs: void.
|
|
*^^*/
|
|
BOOLEAN I2CNull( PXGI_HW_DEVICE_INFO pHWDE, PI2CControl pI2CControl)
|
|
{
|
|
pI2CControl->Status = I2C_STATUS_ERROR;
|
|
|
|
/*///// Issue STOP - START, if I2C_FLAGS_DATACHAINING ////////*/
|
|
if (pI2CControl->Flags & I2C_FLAGS_DATACHAINING)
|
|
{
|
|
if (Stop(pHWDE) == FALSE) return FALSE;
|
|
if (Start(pHWDE) == FALSE) return FALSE;
|
|
}
|
|
|
|
/*///// Issue START ////////*/
|
|
if (pI2CControl->Flags & I2C_FLAGS_START)
|
|
{
|
|
if (Start(pHWDE) == FALSE) return FALSE;
|
|
}
|
|
|
|
/*////// Issue STOP /////////*/
|
|
if (pI2CControl->Flags & I2C_FLAGS_STOP)
|
|
{
|
|
if (Stop(pHWDE) == FALSE) return FALSE;
|
|
}
|
|
|
|
pI2CControl->Status = I2C_STATUS_NOERROR;
|
|
return TRUE;
|
|
}/* end of I2CNull()*/
|
|
|
|
/*^^*
|
|
* Function: I2CRead
|
|
*
|
|
* Purpose: To complete an I2C instruction.
|
|
*
|
|
* Inputs: lpI2C_ContextData : PI2C_CONTEXT, pointer to data struct associated
|
|
* with card being accessed
|
|
* I2CCntl : PI2CControl, pointer to I2C control structure
|
|
*
|
|
* Outputs: void.
|
|
*^^*/
|
|
BOOLEAN I2CRead(PXGI_HW_DEVICE_INFO pHWDE, PI2CControl pI2CControl)
|
|
{
|
|
pI2CControl->Status = I2C_STATUS_ERROR;
|
|
|
|
/*///// Issue STOP - START, if I2C_FLAGS_DATACHAINING ////////*/
|
|
if (pI2CControl->Flags & I2C_FLAGS_DATACHAINING)
|
|
{
|
|
if (Stop(pHWDE) == FALSE) return FALSE;
|
|
if (Start(pHWDE) == FALSE) return FALSE;
|
|
}
|
|
|
|
/*///// Issue START ////////*/
|
|
if (pI2CControl->Flags & I2C_FLAGS_START)
|
|
{
|
|
if (Start(pHWDE) == FALSE) return FALSE;
|
|
}
|
|
|
|
/*///// Read Command ///////*/
|
|
if (ReadUCHARI2C(pHWDE, &pI2CControl->Data) == FALSE)
|
|
return FALSE;
|
|
|
|
if (pI2CControl->Flags & I2C_FLAGS_STOP) {
|
|
if (NoAck(pHWDE) == FALSE) return FALSE;
|
|
}
|
|
else { /* Should we issue ACK*/
|
|
if (pI2CControl->Flags & I2C_FLAGS_ACK) {
|
|
if (Ack(pHWDE, SEND_ACK) == FALSE) return FALSE;
|
|
}
|
|
}
|
|
|
|
/*////// Issue STOP /////////*/
|
|
if (pI2CControl->Flags & I2C_FLAGS_STOP)
|
|
{
|
|
if (Stop(pHWDE) == FALSE) return FALSE;
|
|
}
|
|
|
|
pI2CControl->Status = I2C_STATUS_NOERROR;
|
|
return TRUE;
|
|
} /* end of I2CRead() */
|
|
|
|
/*^^*
|
|
* Function: I2CWrite
|
|
*
|
|
* Purpose: To complete an I2C instruction.
|
|
*
|
|
* Inputs: lpI2C_ContextData : PI2C_CONTEXT, pointer to data struct associated
|
|
* with card being accessed
|
|
* I2CCntl : PI2CControl, pointer to I2C control structure
|
|
*
|
|
* Outputs: void.
|
|
*^^*/
|
|
BOOLEAN I2CWrite(PXGI_HW_DEVICE_INFO pHWDE, PI2CControl pI2CControl)
|
|
{
|
|
pI2CControl->Status = I2C_STATUS_ERROR;
|
|
|
|
/*///// Issue STOP - START, if I2C_FLAGS_DATACHAINING ////////*/
|
|
if (pI2CControl->Flags & I2C_FLAGS_DATACHAINING)
|
|
{
|
|
if (Stop(pHWDE) == FALSE)
|
|
{
|
|
|
|
return FALSE;
|
|
}
|
|
if (Start(pHWDE) == FALSE)
|
|
{
|
|
|
|
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/*///// Issue START ////////*/
|
|
if (pI2CControl->Flags & I2C_FLAGS_START)
|
|
{
|
|
if (Start(pHWDE) == FALSE)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/*///// Write Command ///////*/
|
|
if (WriteUCHARI2C(pHWDE, pI2CControl->Data) == FALSE)
|
|
{
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
if (pI2CControl->Flags & I2C_FLAGS_ACK) {
|
|
if (Ack(pHWDE, RECV_ACK) == FALSE)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/*////// Issue STOP /////////*/
|
|
if (pI2CControl->Flags & I2C_FLAGS_STOP)
|
|
{
|
|
if (Stop(pHWDE) == FALSE)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
pI2CControl->Status = I2C_STATUS_NOERROR;
|
|
return TRUE;
|
|
} /* end of I2CWrite() */
|
|
|
|
/*^^*
|
|
* Function: ResetI2C
|
|
*
|
|
* Purpose: To reset I2CBus
|
|
*
|
|
* Inputs: lpI2C_ContextData : PI2C_CONTEXT, pointer to data struct associated with
|
|
* lpI2C_ContextData being accessed
|
|
*
|
|
* Outputs: UCHAR, the data that was read.
|
|
*^^*/
|
|
BOOLEAN ResetI2C(PXGI_HW_DEVICE_INFO pHWDE, PI2CControl pI2CControl)
|
|
{
|
|
|
|
if (Stop(pHWDE) == TRUE) {
|
|
pI2CControl->Status = I2C_STATUS_NOERROR;
|
|
return TRUE;
|
|
}
|
|
else {
|
|
pI2CControl->Status = I2C_STATUS_ERROR;
|
|
return FALSE;
|
|
}
|
|
} /* ResetI2C() */
|
|
|
|
|
|
|
|
|
|
/*^^*
|
|
* Function: Ack
|
|
*
|
|
* Purpose: To ask the I2C bus for an acknowledge.
|
|
*
|
|
* Inputs: lpI2C_ContextData : PI2C_CONTEXT, pointer to data struct associated with
|
|
* lpI2C_ContextData being accessed
|
|
*
|
|
* Outputs: char, ack status.
|
|
*^^*/
|
|
BOOLEAN Ack (PXGI_HW_DEVICE_INFO pHWDE, bool fPut)
|
|
{
|
|
BOOLEAN status = FALSE;
|
|
ULONG i, delay, delay2;
|
|
ULONG ack;
|
|
|
|
delay = pHWDE->I2CDelay / 10 / 2;
|
|
if (fPut == SEND_ACK) /* Send Ack into I2C bus */
|
|
{
|
|
vWriteDataLine(pHWDE, LODAT);
|
|
I2C_DelayUS(delay);
|
|
|
|
vWriteClockLine(pHWDE, HICLK);
|
|
I2C_DelayUS(delay);
|
|
if (bReadClockLine(pHWDE) != HICLK) {
|
|
i = 0;
|
|
delay2 = delay * 2;
|
|
I2C_DelayUS(delay2); /* Jong@08052008 */
|
|
do {
|
|
vWriteClockLine(pHWDE, HICLK);
|
|
I2C_DelayUS(delay2);
|
|
if (bReadClockLine(pHWDE) == HICLK) break;
|
|
i++;
|
|
delay2 *= 2;
|
|
if (i >= I2C_RETRY_COUNT) return FALSE;
|
|
} while (1);
|
|
}
|
|
|
|
|
|
I2C_DelayUS(delay); /* Jong@08052008 */
|
|
vWriteClockLine(pHWDE, LOCLK);
|
|
I2C_DelayUS(delay);
|
|
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
/* Receive Ack from I2C bus */
|
|
vWriteDataLine(pHWDE, HIDAT);
|
|
I2C_DelayUS(delay);
|
|
ack = bReadDataLine(pHWDE);
|
|
|
|
I2C_DelayUS(delay); /* Jong@08052008 */
|
|
vWriteClockLine(pHWDE, HICLK);
|
|
I2C_DelayUS(delay);
|
|
if (bReadClockLine(pHWDE) != HICLK) {
|
|
i = 0;
|
|
delay2 = delay * 2;
|
|
do {
|
|
I2C_DelayUS(delay2); /* Jong@08052008 */
|
|
vWriteClockLine(pHWDE, HICLK);
|
|
I2C_DelayUS(delay2);
|
|
if (bReadClockLine(pHWDE) == HICLK) break;
|
|
i++;
|
|
delay2 *= 2;
|
|
if (i >= I2C_RETRY_COUNT) return FALSE;
|
|
} while (1);
|
|
}
|
|
|
|
I2C_DelayUS(delay); /* Jong@08052008 */
|
|
status = bReadDataLine(pHWDE);
|
|
|
|
I2C_DelayUS(delay); /* Jong@08052008 */
|
|
vWriteClockLine(pHWDE, LOCLK);
|
|
I2C_DelayUS(delay);
|
|
|
|
if (status != LODAT) {
|
|
if (ack == LODAT) {
|
|
status = LODAT;
|
|
}
|
|
|
|
else {
|
|
|
|
}
|
|
|
|
}
|
|
return (BOOLEAN)(status == LODAT);
|
|
}
|
|
}/* end of Ack() */
|
|
|
|
|
|
BOOLEAN NoAck(PXGI_HW_DEVICE_INFO pHWDE)
|
|
{
|
|
ULONG i, delay, delay2;
|
|
|
|
delay = pHWDE->I2CDelay / 10 / 2;
|
|
|
|
vWriteDataLine(pHWDE, HIDAT);
|
|
I2C_DelayUS(delay);
|
|
|
|
vWriteClockLine(pHWDE, HICLK);
|
|
I2C_DelayUS(delay);
|
|
if (bReadClockLine(pHWDE) != HICLK) {
|
|
delay2 = delay * 2;
|
|
i = 0;
|
|
do {
|
|
I2C_DelayUS(delay2); /* Jong@08052008 */
|
|
vWriteClockLine(pHWDE, HICLK);
|
|
I2C_DelayUS(delay2);
|
|
if (bReadClockLine(pHWDE) == HICLK) break;
|
|
i++;
|
|
delay2 *= 2;
|
|
if (i >= I2C_RETRY_COUNT) return FALSE;
|
|
} while (1);
|
|
}
|
|
|
|
I2C_DelayUS(delay); /* Jong@08052008 */
|
|
vWriteClockLine(pHWDE, LOCLK);
|
|
I2C_DelayUS(delay);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*^^*
|
|
* Function: Start
|
|
*
|
|
* Purpose: To start a transfer on the I2C bus.
|
|
*
|
|
* Inputs: lpI2C_ContextData : PI2C_CONTEXT, pointer to data struct associated with
|
|
* lpI2C_ContextData being accessed
|
|
*
|
|
* Outputs: void.
|
|
*^^*/
|
|
BOOLEAN Start( PXGI_HW_DEVICE_INFO pHWDE)
|
|
{
|
|
ULONG i, delay, delay2;
|
|
|
|
delay = pHWDE->I2CDelay / 10 / 2;
|
|
|
|
vWriteDataLine(pHWDE, HIDAT);
|
|
I2C_DelayUS(delay);
|
|
if (bReadDataLine(pHWDE) != HIDAT) {
|
|
delay2 = delay * 2;
|
|
i = 0;
|
|
do {
|
|
I2C_DelayUS(delay2); /* Jong@08052008 */
|
|
vWriteDataLine(pHWDE, HIDAT);
|
|
I2C_DelayUS(delay2);
|
|
if (bReadDataLine(pHWDE) == HIDAT) break;
|
|
i++;
|
|
delay2 *= 2;
|
|
if (i >= I2C_RETRY_COUNT) return FALSE;
|
|
} while (1);
|
|
}
|
|
|
|
I2C_DelayUS(delay); /* Jong@08052008 */
|
|
vWriteClockLine(pHWDE, HICLK);
|
|
I2C_DelayUS(delay);
|
|
if (bReadClockLine(pHWDE) != HICLK) {
|
|
delay2 = delay * 2;
|
|
i = 0;
|
|
do {
|
|
I2C_DelayUS(delay2); /* Jong@08052008 */
|
|
vWriteClockLine(pHWDE, HICLK);
|
|
I2C_DelayUS(delay2);
|
|
if (bReadClockLine(pHWDE) == HICLK) break;
|
|
i++;
|
|
delay2 *= 2;
|
|
if (i >= I2C_RETRY_COUNT) return FALSE;
|
|
} while (1);
|
|
}
|
|
|
|
I2C_DelayUS(delay); /* Jong@08052008 */
|
|
vWriteDataLine(pHWDE, LODAT);
|
|
I2C_DelayUS(delay);
|
|
|
|
vWriteClockLine(pHWDE, LOCLK);
|
|
I2C_DelayUS(delay);
|
|
|
|
return TRUE;
|
|
}/* end of Start */
|
|
|
|
/*^^*
|
|
* Function: Stop
|
|
*
|
|
* Purpose: To stop a transfer on the I2C bus.
|
|
*
|
|
* Inputs: lpI2C_ContextData : PI2C_CONTEXT, pointer to data struct associated with
|
|
* lpI2C_ContextData being accessed
|
|
*
|
|
* Outputs: void.
|
|
*^^*/
|
|
BOOLEAN Stop(PXGI_HW_DEVICE_INFO pHWDE)
|
|
{
|
|
ULONG i, delay, delay2;
|
|
|
|
delay = pHWDE->I2CDelay / 10 / 2;
|
|
PDEBUGI2C(ErrorF("Stop()-begin-pHWDE->I2CDelay=%d, delay=%d...\n", pHWDE->I2CDelay, delay));
|
|
|
|
vWriteDataLine(pHWDE, LODAT);
|
|
I2C_DelayUS(delay);
|
|
|
|
vWriteClockLine(pHWDE, HICLK);
|
|
I2C_DelayUS(delay);
|
|
if (bReadClockLine(pHWDE) != HICLK) {
|
|
i = 0;
|
|
delay2 = delay * 2;
|
|
do {
|
|
I2C_DelayUS(delay2); /* Jong@08052008 */
|
|
vWriteClockLine(pHWDE, HICLK);
|
|
I2C_DelayUS(delay2);
|
|
if (bReadClockLine(pHWDE) == HICLK) break;
|
|
i++;
|
|
delay2 *= 2;
|
|
if (i >= I2C_RETRY_COUNT) return FALSE;
|
|
} while (1);
|
|
}
|
|
|
|
I2C_DelayUS(delay); /* Jong@08052008 */
|
|
vWriteDataLine(pHWDE, HIDAT);
|
|
I2C_DelayUS(delay);
|
|
|
|
return (BOOLEAN)(bReadDataLine(pHWDE) == HIDAT);
|
|
}/* end of Stop*/
|
|
|
|
/*^^*
|
|
* Function: WriteUCHARI2C
|
|
*
|
|
* Purpose: To write a UCHAR of data to the I2C bus.
|
|
*
|
|
* Inputs: lpI2C_ContextData : PI2C_CONTEXT, pointer to data struct associated with
|
|
* lpI2C_ContextData being accessed
|
|
* cData: UCHAR, the data to write
|
|
*
|
|
* Outputs: void.
|
|
*^^*/
|
|
BOOLEAN WriteUCHARI2C(PXGI_HW_DEVICE_INFO pHWDE, UCHAR cData)
|
|
{
|
|
ULONG i, j, delay, delay2;
|
|
|
|
cData = ReverseUCHAR(cData);
|
|
|
|
delay = pHWDE->I2CDelay / 10 / 2;
|
|
|
|
for (j=0; j<8; j++, cData>>=1)
|
|
{
|
|
I2C_DelayUS(delay); /* Jong@08052008 */
|
|
vWriteDataLine(pHWDE, cData);
|
|
I2C_DelayUS(delay);
|
|
|
|
vWriteClockLine(pHWDE, HICLK);
|
|
I2C_DelayUS(delay);
|
|
if (bReadClockLine(pHWDE) != HICLK) {
|
|
i = 0;
|
|
delay2 = delay * 2;
|
|
do {
|
|
I2C_DelayUS(delay2); /* Jong@08052008 */
|
|
vWriteClockLine(pHWDE, HICLK);
|
|
I2C_DelayUS(delay2);
|
|
if (bReadClockLine(pHWDE) == HICLK) break;
|
|
i++;
|
|
delay2 *= 2;
|
|
if (i >= I2C_RETRY_COUNT) return FALSE;
|
|
} while (1);
|
|
}
|
|
|
|
I2C_DelayUS(delay); /* Jong@08052008 */
|
|
vWriteClockLine(pHWDE, LOCLK);
|
|
I2C_DelayUS(delay);
|
|
}
|
|
return TRUE;
|
|
}/* end of WriteUCHARI2C */
|
|
|
|
/*^^*
|
|
* Function: ReadUCHARI2C
|
|
*
|
|
* Purpose: To read a UCHAR of data from the I2C bus.
|
|
*
|
|
* Inputs: lpI2C_ContextData : PI2C_CONTEXT, pointer to data struct associated with
|
|
* lpI2C_ContextData being accessed
|
|
*
|
|
* Outputs: UCHAR, the data that was read.
|
|
*^^*/
|
|
BOOLEAN ReadUCHARI2C(PXGI_HW_DEVICE_INFO pHWDE, PUCHAR pBuffer)
|
|
{
|
|
ULONG ulReadData, data, i, j, delay, delay2;
|
|
|
|
delay = pHWDE->I2CDelay / 10 / 2;
|
|
|
|
vWriteDataLine(pHWDE, HIDAT);
|
|
I2C_DelayUS(delay);
|
|
|
|
ulReadData = 0;
|
|
for (j = 0; j < 8; j++)
|
|
{
|
|
vWriteClockLine(pHWDE, HICLK);
|
|
I2C_DelayUS(delay);
|
|
if (bReadClockLine(pHWDE) != HICLK) {
|
|
i = 0;
|
|
delay2 = delay * 2;
|
|
do {
|
|
I2C_DelayUS(delay2); /* Jong@08052008 */
|
|
vWriteClockLine(pHWDE, HICLK);
|
|
I2C_DelayUS(delay2);
|
|
if (bReadClockLine(pHWDE) == HICLK) break;
|
|
i++;
|
|
delay2 *= 2;
|
|
if (i >= I2C_RETRY_COUNT) return FALSE;
|
|
} while (1);
|
|
}
|
|
|
|
I2C_DelayUS(delay); /* Jong@08052008 */
|
|
data = bReadDataLine(pHWDE);
|
|
ulReadData = (ulReadData << 1) | (data & 1);
|
|
|
|
I2C_DelayUS(delay); /* Jong@08052008 */
|
|
vWriteClockLine(pHWDE, LOCLK);
|
|
I2C_DelayUS(delay);
|
|
|
|
vWriteDataLine(pHWDE, HIDAT);
|
|
I2C_DelayUS(delay);
|
|
}
|
|
|
|
*pBuffer = (UCHAR) ulReadData;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
UCHAR ReverseUCHAR(UCHAR data)
|
|
{
|
|
UCHAR rdata = 0;
|
|
int i;
|
|
|
|
for (i=0; i<8; i++)
|
|
{
|
|
rdata <<= 1;
|
|
rdata |= (data & 1);
|
|
data >>= 1;
|
|
}
|
|
|
|
return(rdata);
|
|
}
|
|
|
|
/************************************************************************************
|
|
For DVI I2C Interface
|
|
***************************************************************************************/
|
|
|
|
/*************************************************************************
|
|
// VOID vWriteClockLineDVI()
|
|
// IOReg xx14, index 0F is defined as follows:
|
|
//
|
|
// ... 1 0
|
|
// --------|------|-------|
|
|
// ...| Data | Clock |
|
|
// ------------------------
|
|
*************************************************************************/
|
|
VOID vWriteClockLineDVI(PXGI_HW_DEVICE_INFO pHWDE, UCHAR data)
|
|
{
|
|
UCHAR temp;
|
|
PUCHAR pjI2cIOBase;
|
|
|
|
PDEBUGI2C(ErrorF("vWriteClockLineDVI()...begin\n"));
|
|
|
|
if ((pHWDE->jChipType < XG21)&&(pHWDE->jChipType != XG27))
|
|
{
|
|
ErrorF("vWriteClockLineDVI()...0\n");
|
|
}
|
|
else
|
|
{
|
|
PDEBUGI2C(ErrorF("vWriteClockLineDVI()...1\n"));
|
|
pjI2cIOBase = pHWDE->pjIOAddress + CRTC_ADDRESS_PORT_COLOR;
|
|
|
|
/* Enable GPIOA Write */
|
|
|
|
EnableGPIOA(pjI2cIOBase, I2C_WRITE);
|
|
|
|
PDEBUGI2C(ErrorF("*1 - pHWDE->ucI2cDVI = %d\n", pHWDE->ucI2cDVI));
|
|
pHWDE->ucI2cDVI = (pHWDE->ucI2cDVI & MASK(1:1)) | SETBITS(data, 0:0);
|
|
PDEBUGI2C(ErrorF("*2 - pHWDE->ucI2cDVI = %d\n", pHWDE->ucI2cDVI));
|
|
|
|
temp = XGI_GetReg(pjI2cIOBase, IND_CR48_GPIO_REG_I);
|
|
PDEBUGI2C(ErrorF("IND_CR48_GPIO_REG_I = %d\n", temp));
|
|
|
|
{
|
|
UCHAR temp2 = getGPIORWTransfer(temp);
|
|
PDEBUGI2C(ErrorF("temp2 = %d\n", temp2));
|
|
temp = temp2;
|
|
}
|
|
|
|
temp = (temp & (~MASK(1:0))) | pHWDE->ucI2cDVI;
|
|
PDEBUGI2C(ErrorF("temp= %d\n", temp));
|
|
XGI_SetReg(pjI2cIOBase,IND_CR48_GPIO_REG_I, temp);
|
|
}
|
|
|
|
PDEBUGI2C(ErrorF("vWriteClockLineDVI()...end\n"));
|
|
}
|
|
|
|
/*************************************************************************
|
|
// VOID vWriteDataLineDVI()
|
|
// IOReg xx14, index 0F is defined as follows:
|
|
//
|
|
// ... 1 0
|
|
// --------|------|-------|
|
|
// ...| Data | Clock |
|
|
// ------------------------
|
|
*************************************************************************/
|
|
VOID vWriteDataLineDVI(PXGI_HW_DEVICE_INFO pHWDE, UCHAR data)
|
|
{
|
|
UCHAR temp;
|
|
PUCHAR pjI2cIOBase;
|
|
|
|
PDEBUGI2C(ErrorF("vWriteDataLineDVI()...begin\n"));
|
|
|
|
if ((pHWDE->jChipType < XG21)&&(pHWDE->jChipType != XG27))
|
|
{
|
|
ErrorF("vWriteDataLineDVI()...0\n");
|
|
}
|
|
else
|
|
{
|
|
PDEBUGI2C(ErrorF("vWriteDataLineDVI()...1\n"));
|
|
pjI2cIOBase = pHWDE->pjIOAddress + CRTC_ADDRESS_PORT_COLOR;
|
|
|
|
|
|
/* Enable GPIOB Write */
|
|
|
|
EnableGPIOB(pjI2cIOBase, I2C_WRITE);
|
|
|
|
PDEBUGI2C(ErrorF("*1 - pHWDE->ucI2cDVI = %d\n", pHWDE->ucI2cDVI));
|
|
pHWDE->ucI2cDVI = (pHWDE->ucI2cDVI & MASK(0:0)) | SETBITS(data, 1:1);
|
|
PDEBUGI2C(ErrorF("*2 - pHWDE->ucI2cDVI = %d\n", pHWDE->ucI2cDVI));
|
|
|
|
temp = XGI_GetReg(pjI2cIOBase, IND_CR48_GPIO_REG_I);
|
|
PDEBUGI2C(ErrorF("IND_CR48_GPIO_REG_I = %d\n", temp));
|
|
|
|
{
|
|
UCHAR temp2 = getGPIORWTransfer(temp);
|
|
PDEBUGI2C(ErrorF("temp2 = %d\n", temp2));
|
|
|
|
temp = temp2;
|
|
}
|
|
|
|
temp = (temp & (~MASK(1:0))) | pHWDE->ucI2cDVI;
|
|
PDEBUGI2C(ErrorF("temp = %d\n", temp));
|
|
|
|
XGI_SetReg(pjI2cIOBase,IND_CR48_GPIO_REG_I, temp);
|
|
}
|
|
|
|
PDEBUGI2C(ErrorF("vWriteDataLineDVI()...end\n"));
|
|
}
|
|
|
|
/*************************************************************************
|
|
// BOOLEAN bReadClockLineDVI()
|
|
// IOReg xx14, index 0F is defined as follows:
|
|
//
|
|
// ... 1 0
|
|
// --------|------|-------|
|
|
// ...| Data | Clock |
|
|
// ------------------------
|
|
*************************************************************************/
|
|
BOOLEAN bReadClockLineDVI(PXGI_HW_DEVICE_INFO pHWDE)
|
|
{
|
|
UCHAR cPortData;
|
|
PUCHAR pjI2cIOBase;
|
|
|
|
PDEBUGI2C(ErrorF("bReadClockLineDVI()...begin\n"));
|
|
|
|
if ((pHWDE->jChipType != XG21)&&(pHWDE->jChipType != XG27))
|
|
{
|
|
ErrorF("bReadClockLineDVI()...0\n");
|
|
}
|
|
else
|
|
{
|
|
PDEBUGI2C(ErrorF("bReadClockLineDVI()...1\n"));
|
|
pjI2cIOBase = pHWDE->pjIOAddress + CRTC_ADDRESS_PORT_COLOR;
|
|
|
|
/* Enable GPIOA READ */
|
|
|
|
EnableGPIOA(pjI2cIOBase, I2C_READ);
|
|
|
|
cPortData = XGI_GetReg(pjI2cIOBase, IND_CR48_GPIO_REG_I);
|
|
PDEBUGI2C(ErrorF("*1 - cPortData = %d...\n", cPortData));
|
|
|
|
cPortData = GETBITS(cPortData, 7:7);
|
|
PDEBUGI2C(ErrorF("*2 - cPortData = %d...\n", cPortData));
|
|
}
|
|
|
|
PDEBUGI2C(ErrorF("bReadClockLineDVI()...return(cPortData=%d)\n", cPortData));
|
|
return cPortData;
|
|
}
|
|
|
|
/*************************************************************************
|
|
// BOOLEAN bReadDataLineDVI()
|
|
// IOReg xx14, index 0F is defined as follows:
|
|
//
|
|
// ... 1 0
|
|
// --------|------|-------|
|
|
// ...| Data | Clock |
|
|
// ------------------------
|
|
*************************************************************************/
|
|
BOOLEAN bReadDataLineDVI(PXGI_HW_DEVICE_INFO pHWDE)
|
|
{
|
|
UCHAR cPortData;
|
|
PUCHAR pjI2cIOBase;
|
|
|
|
PDEBUGI2C(ErrorF("bReadDataLineDVI()...begin\n"));
|
|
|
|
if ((pHWDE->jChipType != XG21)&&(pHWDE->jChipType != XG27))
|
|
{
|
|
ErrorF("bReadDataLineDVI()...0\n");
|
|
}
|
|
else
|
|
{
|
|
PDEBUGI2C(ErrorF("bReadDataLineDVI()...1\n"));
|
|
pjI2cIOBase = pHWDE->pjIOAddress + CRTC_ADDRESS_PORT_COLOR;
|
|
|
|
|
|
/* Enable GPIOB Write */
|
|
|
|
EnableGPIOB(pjI2cIOBase, I2C_READ);
|
|
|
|
cPortData = XGI_GetReg(pjI2cIOBase, IND_CR48_GPIO_REG_I);
|
|
PDEBUGI2C(ErrorF("*1 - cPortData = %d...\n", cPortData));
|
|
cPortData = GETBITS(cPortData, 6:6);
|
|
PDEBUGI2C(ErrorF("*2 - cPortData = %d...\n", cPortData));
|
|
}
|
|
|
|
|
|
PDEBUGI2C(ErrorF("bReadDataLineDVI()...return(cPortData=%d)\n", cPortData));
|
|
return cPortData;
|
|
}
|
|
|
|
//*************************************************************************//
|
|
// VOID vWaitForCRT1VsyncActive()
|
|
// IoReg 3DA
|
|
// ... 3 ...
|
|
// --------|--------------|-------|
|
|
// ...| Vertical Sync| |
|
|
// --------------------------------
|
|
//*************************************************************************//
|
|
VOID vWaitForCRT1HsyncActive(PXGI_HW_DEVICE_INFO pHWDE)
|
|
{
|
|
PUCHAR pjPort = pHWDE->pjIOAddress + INPUT_STATUS_1_COLOR;
|
|
ULONG i;
|
|
|
|
for (i = 0; i < 0x00FFFF; i++)
|
|
{
|
|
if ( (XGI_GetRegByte(pjPort) & 0x01) == 0)
|
|
{
|
|
// Inactive
|
|
break;
|
|
} //if
|
|
} //for-loop
|
|
|
|
for (i = 0; i < 0x00FFFF; i++)
|
|
{
|
|
if ( (XGI_GetRegByte(pjPort) & 0x01) != 0)
|
|
{
|
|
// active
|
|
break;
|
|
} //if
|
|
} //for-loop
|
|
|
|
} //vWaitForCRT1HsyncActive()
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// For CRT I2C Interface
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//*************************************************************************//
|
|
// VOID vWriteClockLineCRT()
|
|
// IOReg SR11 is defined as follows:
|
|
//
|
|
// ... 1 0
|
|
// --------|------|-------|
|
|
// ...| Data | Clock |
|
|
// ------------------------
|
|
//*************************************************************************//
|
|
VOID vWriteClockLineCRT(PXGI_HW_DEVICE_INFO pHWDE, UCHAR data)
|
|
{
|
|
UCHAR temp, ujSR1F;
|
|
PUCHAR pjI2cIOBase = pHWDE->pjIOAddress + SEQ_ADDRESS_PORT;
|
|
|
|
PDEBUGI2C(ErrorF("I2C:Write CRT clock = %x\n", data & 1));
|
|
|
|
ujSR1F = XGI_GetReg(pjI2cIOBase, IND_SR1F_POWER_MANAGEMENT);
|
|
|
|
pHWDE->ucI2cCRT = (pHWDE->ucI2cCRT & MASK(1:1)) | SETBITS(data, 0:0);
|
|
|
|
temp = XGI_GetReg(pjI2cIOBase, IND_SR11_DDC_REG);
|
|
temp = (temp & (~MASK(1:0))) | pHWDE->ucI2cCRT;
|
|
|
|
//wait for CRT1 retrace only when CRT1 is enabled!
|
|
/* if (pHWDE->bMonitorPoweredOn) */ /* jong@08042009; ignore here */
|
|
{
|
|
if(!(data & 1) && ((ujSR1F & 0xC0)==0) )
|
|
{
|
|
vWaitForCRT1HsyncActive(pHWDE);
|
|
}
|
|
}
|
|
|
|
XGI_SetReg(pjI2cIOBase, IND_SR11_DDC_REG, temp);
|
|
}
|
|
|
|
//*************************************************************************//
|
|
// VOID vWriteDataLineCRT()
|
|
// IOReg SR11 is defined as follows:
|
|
//
|
|
// ... 1 0
|
|
// --------|------|-------|
|
|
// ...| Data | Clock |
|
|
// ------------------------
|
|
//*************************************************************************//
|
|
VOID vWriteDataLineCRT(PXGI_HW_DEVICE_INFO pHWDE, UCHAR data)
|
|
{
|
|
UCHAR temp, ujSR1F;
|
|
PUCHAR pjI2cIOBase = pHWDE->pjIOAddress + SEQ_ADDRESS_PORT;
|
|
|
|
PDEBUGI2C(ErrorF("I2C:Write CRT data = %x\n", data & 1));
|
|
|
|
ujSR1F = XGI_GetReg(pHWDE->pjIOAddress + SEQ_ADDRESS_PORT, IND_SR1F_POWER_MANAGEMENT);
|
|
|
|
pHWDE->ucI2cCRT = (pHWDE->ucI2cCRT & MASK(0:0)) | SETBITS(data, 1:1);
|
|
temp = XGI_GetReg(pjI2cIOBase, IND_SR11_DDC_REG);
|
|
temp = (temp & (~MASK(1:0))) | pHWDE->ucI2cCRT;
|
|
|
|
//wait for CRT1 retrace only when CRT1 is enabled!
|
|
/* if (pHWDE->bMonitorPoweredOn) */ /* Jong@08042009; ignore checking */
|
|
{
|
|
if(!(data & 1) && ((ujSR1F & 0xC0)==0) )
|
|
{
|
|
vWaitForCRT1HsyncActive(pHWDE);
|
|
}
|
|
}
|
|
|
|
XGI_SetReg(pjI2cIOBase, IND_SR11_DDC_REG, temp);
|
|
}
|
|
|
|
//*************************************************************************//
|
|
// BOOLEAN bReadClockLineCRT()
|
|
// IOReg SR11 is defined as follows:
|
|
//
|
|
// ... 1 0
|
|
// --------|------|-------|
|
|
// ...| Data | Clock |
|
|
// ------------------------
|
|
//*************************************************************************//
|
|
BOOLEAN bReadClockLineCRT(PXGI_HW_DEVICE_INFO pHWDE)
|
|
{
|
|
UCHAR cPortData;
|
|
PUCHAR pjI2cIOBase = pHWDE->pjIOAddress + SEQ_ADDRESS_PORT;
|
|
|
|
cPortData = XGI_GetReg(pjI2cIOBase, IND_SR11_DDC_REG);
|
|
cPortData = GETBITS(cPortData, 0:0);
|
|
|
|
PDEBUGI2C(ErrorF("I2C:Read Channel CRT clock = %x\n", cPortData));
|
|
|
|
return cPortData;
|
|
}
|
|
|
|
//*************************************************************************//
|
|
// BOOLEAN bReadDataLineCRT()
|
|
// IOReg SR11 is defined as follows:
|
|
//
|
|
// ... 1 0
|
|
// --------|------|-------|
|
|
// ...| Data | Clock |
|
|
// ------------------------
|
|
//*************************************************************************//
|
|
BOOLEAN bReadDataLineCRT(PXGI_HW_DEVICE_INFO pHWDE)
|
|
{
|
|
UCHAR cPortData;
|
|
PUCHAR pjI2cIOBase = pHWDE->pjIOAddress + SEQ_ADDRESS_PORT;
|
|
|
|
cPortData = XGI_GetReg(pjI2cIOBase, IND_SR11_DDC_REG);
|
|
cPortData = GETBITS(cPortData, 1:1);
|
|
|
|
PDEBUGI2C(ErrorF("I2C:Read Channel CRT data = %x\n", cPortData));
|
|
|
|
return cPortData;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// For Feature Connector I2C Interface
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//*************************************************************************//
|
|
// VOID vWriteClockLineFCNT()
|
|
// IOReg SR11 is defined as follows:
|
|
//
|
|
// ... 3 2 ...
|
|
// --------|------|-------|-------|
|
|
// ...| Data | Clock | |
|
|
// --------------------------------
|
|
//*************************************************************************//
|
|
VOID vWriteClockLineFCNT(PXGI_HW_DEVICE_INFO pHWDE, UCHAR data)
|
|
{
|
|
UCHAR temp;
|
|
PUCHAR pjI2cIOBase = pHWDE->pjIOAddress + SEQ_ADDRESS_PORT;
|
|
|
|
PDEBUGI2C(ErrorF("I2C:Write FCNT clock = %x\n", data & 1));
|
|
|
|
pHWDE->ucI2cFCNT = (pHWDE->ucI2cFCNT & MASK(3:3)) | SETBITS(data, 2:2);
|
|
|
|
temp = XGI_GetReg(pjI2cIOBase, IND_SR11_DDC_REG);
|
|
temp = (temp & (~MASK(3:2))) | pHWDE->ucI2cFCNT;
|
|
|
|
XGI_SetReg(pjI2cIOBase, IND_SR11_DDC_REG, temp);
|
|
}
|
|
|
|
//*************************************************************************//
|
|
// VOID vWriteDataLineFCNT()
|
|
// IOReg SR11 is defined as follows:
|
|
//
|
|
// ... 3 2 ...
|
|
// --------|------|-------|-------|
|
|
// ...| Data | Clock | |
|
|
// --------------------------------
|
|
//*************************************************************************//
|
|
VOID vWriteDataLineFCNT(PXGI_HW_DEVICE_INFO pHWDE, UCHAR data)
|
|
{
|
|
UCHAR temp, temp2, temp3;
|
|
PUCHAR pjI2cIOBase = pHWDE->pjIOAddress + SEQ_ADDRESS_PORT;
|
|
|
|
PDEBUGI2C(ErrorF("I2C:Write FCNT data = %x\n", data & 1));
|
|
|
|
pHWDE->ucI2cFCNT = (pHWDE->ucI2cFCNT & MASK(2:2)) | SETBITS(data, 3:3);
|
|
|
|
temp = XGI_GetReg(pjI2cIOBase, IND_SR11_DDC_REG);
|
|
temp = (temp & (~MASK(3:2))) | pHWDE->ucI2cFCNT;
|
|
|
|
XGI_SetReg(pjI2cIOBase, IND_SR11_DDC_REG, temp);
|
|
}
|
|
|
|
//*************************************************************************//
|
|
// BOOLEAN bReadClockLineFCNT()
|
|
// IOReg SR11 is defined as follows:
|
|
//
|
|
// ... 3 2 ...
|
|
// --------|------|-------|-------|
|
|
// ...| Data | Clock | |
|
|
// --------------------------------
|
|
//*************************************************************************//
|
|
BOOLEAN bReadClockLineFCNT(PXGI_HW_DEVICE_INFO pHWDE)
|
|
{
|
|
UCHAR cPortData;
|
|
PUCHAR pjI2cIOBase = pHWDE->pjIOAddress + SEQ_ADDRESS_PORT;
|
|
|
|
cPortData = XGI_GetReg(pjI2cIOBase, IND_SR11_DDC_REG);
|
|
cPortData = GETBITS(cPortData, 2:2);
|
|
|
|
PDEBUGI2C(ErrorF("I2C:Read Channel FCNT clock = %x\n", cPortData));
|
|
|
|
return cPortData;
|
|
}
|
|
|
|
//*************************************************************************//
|
|
// BOOLEAN bReadDataLineFCNT()
|
|
// IOReg SR11 is defined as follows:
|
|
//
|
|
// ... 3 2 ...
|
|
// --------|------|-------|-------|
|
|
// ...| Data | Clock | |
|
|
// --------------------------------
|
|
//*************************************************************************//
|
|
BOOLEAN bReadDataLineFCNT(PXGI_HW_DEVICE_INFO pHWDE)
|
|
{
|
|
UCHAR cPortData;
|
|
PUCHAR pjI2cIOBase = pHWDE->pjIOAddress + SEQ_ADDRESS_PORT;
|
|
|
|
cPortData = XGI_GetReg(pjI2cIOBase, IND_SR11_DDC_REG);
|
|
cPortData = GETBITS(cPortData, 3:3);
|
|
|
|
PDEBUGI2C(ErrorF("I2C:Read Channel FCNT data = %x\n", cPortData));
|
|
|
|
return cPortData;
|
|
}
|
|
|
|
/*=======================================================*/
|
|
VOID vWriteClockLine(PXGI_HW_DEVICE_INFO pHWDE, UCHAR data)
|
|
{
|
|
if(pHWDE->crtno == 0)
|
|
vWriteClockLineCRT(pHWDE, data);
|
|
else if(pHWDE->crtno == 1)
|
|
vWriteClockLineDVI(pHWDE, data);
|
|
else if(pHWDE->crtno == 2)
|
|
vWriteClockLineFCNT(pHWDE, data);
|
|
|
|
ErrorF("Error(XGI) : Unknown output device!\n");
|
|
}
|
|
|
|
VOID vWriteDataLine(PXGI_HW_DEVICE_INFO pHWDE, UCHAR data)
|
|
{
|
|
if(pHWDE->crtno == 0)
|
|
vWriteDataLineCRT(pHWDE, data);
|
|
else if(pHWDE->crtno == 1)
|
|
vWriteDataLineDVI(pHWDE, data);
|
|
else if(pHWDE->crtno == 2)
|
|
vWriteDataLineFCNT(pHWDE, data);
|
|
|
|
ErrorF("Error(XGI) : Unknown output device!\n");
|
|
}
|
|
|
|
BOOLEAN bReadClockLine(PXGI_HW_DEVICE_INFO pHWDE)
|
|
{
|
|
if(pHWDE->crtno == 0)
|
|
return(bReadClockLineCRT(pHWDE));
|
|
else if(pHWDE->crtno == 1)
|
|
return(bReadClockLineDVI(pHWDE));
|
|
else if(pHWDE->crtno == 2)
|
|
return(bReadClockLineFCNT(pHWDE));
|
|
|
|
ErrorF("Error(XGI) : Unknown output device!\n");
|
|
return FALSE;
|
|
}
|
|
|
|
BOOLEAN bReadDataLine(PXGI_HW_DEVICE_INFO pHWDE)
|
|
{
|
|
if(pHWDE->crtno == 0)
|
|
return(bReadDataLineCRT(pHWDE));
|
|
else if(pHWDE->crtno == 1)
|
|
return(bReadDataLineDVI(pHWDE));
|
|
else if(pHWDE->crtno == 2)
|
|
return(bReadDataLineFCNT(pHWDE));
|
|
|
|
ErrorF("Error(XGI) : Unknown output device!\n");
|
|
return FALSE;
|
|
}
|
|
|
|
BOOLEAN bEDIDCheckSum(PUCHAR pjEDIDBuf,ULONG ulBufSize)
|
|
{
|
|
ULONG i;
|
|
UCHAR ujSum = 0;
|
|
PUCHAR pujPtr;
|
|
|
|
pujPtr = pjEDIDBuf;
|
|
|
|
for (i = 0; i < ulBufSize; i++)
|
|
{
|
|
/* printk("pujPtr=%x, ",*pujPtr); */
|
|
ujSum += *(pujPtr++);
|
|
} /*for-loop */
|
|
|
|
return(ujSum);
|
|
|
|
}
|
|
|
|
/* Jong 08/03/2009; Get EDID functions; ported from MS Windows */
|
|
//*************************************************************************\\
|
|
// VP_STATUS vGetEDID_1
|
|
//
|
|
// Routine Description:
|
|
// Get the EDID which is in version 1.x format via I2C.
|
|
//
|
|
// Arguments:
|
|
// pHWDE - Hardware extension object pointer
|
|
// pI2C - I2C pointer
|
|
// pjBuffer - EDID Buffer
|
|
// ulBufferSize - Buffer size
|
|
//
|
|
//
|
|
// Return Value:
|
|
// Status of returning EDID.
|
|
// NO_ERROR - success
|
|
// ERROR_INVALID_PARAMETER - failed
|
|
//
|
|
//****************************************************************************
|
|
VP_STATUS vGetEDID_1(
|
|
PXGI_HW_DEVICE_INFO pHWDE,
|
|
PI2CControl pI2C,
|
|
PUCHAR pjBuffer,
|
|
ULONG ulBufferSize)
|
|
{
|
|
VP_STATUS status;
|
|
|
|
PDEBUGI2C(ErrorF("vGetEDID_1()\n"));
|
|
|
|
if ((ulBufferSize < 128) || (pjBuffer == NULL)) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
// Set Segment Block ID as 0 if Monitor support Enhanced-EDID
|
|
/*
|
|
pI2C->Command = I2C_COMMAND_WRITE_SEGMENT; // to replace I2C_COMMAND_WRITE
|
|
pI2C->Data = 0;
|
|
I2CAccessBuffer(pHWDE, pI2C, 0x60, 0, &(pI2C->Data), 0);
|
|
*/
|
|
pI2C->Command = I2C_COMMAND_WRITE;
|
|
pI2C->Data = 0;
|
|
I2CAccessBuffer(pHWDE, pI2C, 0x60, 0, &(pI2C->Data), 0);
|
|
|
|
pI2C->Command = I2C_COMMAND_READ;
|
|
status = I2CAccessBuffer(pHWDE, pI2C, 0xA0, 0, pjBuffer, 128);
|
|
if ((status == NO_ERROR) && (pI2C->Status == I2C_STATUS_NOERROR))
|
|
{
|
|
// Check Block 0 EDID Header and its checksum
|
|
if ((*((PULONG)(pjBuffer )) != 0xFFFFFF00) ||
|
|
(*((PULONG)(pjBuffer+4)) != 0x00FFFFFF))
|
|
{
|
|
PDEBUGI2C(ErrorF("vGetEDID_1(): EDID Header Incorrect!!\n"));
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (bEDIDCheckSum(pjBuffer, 128) != 0)
|
|
{
|
|
if ((*((PULONG)(pjBuffer+0x60)) ==0x4d636e79)&& (*((PULONG)(pjBuffer+0x64)) ==0x65747361))
|
|
{
|
|
return NO_ERROR; //To Fix SyncMaster Checksum error issue
|
|
}
|
|
|
|
PDEBUGI2C(ErrorF("vGetEDID_1(): EDID Checksum Error!!\n"));
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
PDEBUGI2C(ErrorF("vGetEDID_1 : call I2CAccessBuffer(0xA0) fail !!!\n"));
|
|
return status;
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
//*************************************************************************\\
|
|
// VP_STATUS vGetEDID_2
|
|
//
|
|
// Routine Description:
|
|
// Get the EDID which is in version 2.0 format via I2C.
|
|
//
|
|
// Arguments:
|
|
// pHWDE - Hardware extension object pointer
|
|
// pI2C - I2C pointer
|
|
// pjBuffer - EDID Buffer
|
|
// ulBufferSize - Buffer size
|
|
//
|
|
//
|
|
// Return Value:
|
|
// Status of returning EDID.
|
|
// NO_ERROR - success
|
|
// ERROR_INVALID_PARAMETER - failed
|
|
//
|
|
//****************************************************************************
|
|
VP_STATUS vGetEDID_2(
|
|
PXGI_HW_DEVICE_INFO pHWDE,
|
|
PI2CControl pI2C,
|
|
PUCHAR pjBuffer,
|
|
ULONG ulBufferSize)
|
|
{
|
|
VP_STATUS status;
|
|
|
|
PDEBUGI2C(ErrorF("vGetEDID_2()\n"));
|
|
|
|
if ((ulBufferSize < 256) || (pjBuffer == NULL)) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
pI2C->Command = I2C_COMMAND_READ;
|
|
status = I2CAccessBuffer(pHWDE, pI2C, 0xA2, 0, pjBuffer, 256);
|
|
if ((status != NO_ERROR) || (pI2C->Status != I2C_STATUS_NOERROR)) {
|
|
PDEBUGI2C(ErrorF("vGetEDID_2 : call I2CAccessBuffer(0xA2) fail !!!\n"));
|
|
usleep(5);
|
|
status = I2CAccessBuffer(pHWDE, pI2C, 0xA6, 0, pjBuffer, 256);
|
|
if ((status != NO_ERROR) || (pI2C->Status != I2C_STATUS_NOERROR)) {
|
|
PDEBUGI2C(ErrorF("vGetEDID_2 : call I2CAccessBuffer(0xA6) fail !!!\n"));
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
if (*pjBuffer != 0x20)
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (bEDIDCheckSum(pjBuffer, 256) != 0)
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
//*************************************************************************\\
|
|
// BOOLEAN bGetEDID
|
|
//
|
|
// Routine Description:
|
|
// For driver to get the monitor EDID through I2C. This function works similar
|
|
// with VideoPortDDCMonitorHelper() does.
|
|
//
|
|
//
|
|
// Arguments:
|
|
// pHWDE - Hardware extension object pointer
|
|
// ulChannelID - Channel ID
|
|
// pjEDIDBuffer - EDID Buffer
|
|
// ulBufferSize - Buffer size
|
|
//
|
|
//
|
|
// Return Value:
|
|
// Status of returning EDID.
|
|
// TRUE - success
|
|
// FALSE - failed
|
|
//
|
|
//****************************************************************************
|
|
BOOLEAN bGetEDID(
|
|
PXGI_HW_DEVICE_INFO pHWDE,
|
|
ULONG ulChannelID,
|
|
PUCHAR pjEDIDBuffer,
|
|
ULONG ulBufferSize)
|
|
{
|
|
I2CControl I2C;
|
|
VP_STATUS status;
|
|
|
|
PDEBUGI2C(ErrorF("bGetEDID() is called.\n"));
|
|
|
|
if ((ulBufferSize != 0) && (pjEDIDBuffer != NULL))
|
|
{
|
|
memset(pjEDIDBuffer, 0, ulBufferSize);
|
|
}
|
|
else
|
|
{
|
|
PDEBUGI2C(ErrorF("bGetEDID()-(ulBufferSize == 0) || (pjEDIDBuffer == NULL)\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
if (I2COpen(pHWDE, I2C_OPEN, ulChannelID, &I2C) != NO_ERROR)
|
|
{
|
|
PDEBUGI2C(ErrorF("bGetEDID()-I2COpen()-fail!\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
// Force Monitor using DDC2 protocal...
|
|
I2C.ClockRate = I2C_MAX_CLOCK_RATE;
|
|
I2C.Command = I2C_COMMAND_WRITE;
|
|
I2C.Flags = I2C_FLAGS_STOP;
|
|
I2C.Data = 0xFF;
|
|
I2CAccess(pHWDE, &I2C);
|
|
|
|
// Reset I2C bus
|
|
I2C.Command = I2C_COMMAND_RESET;
|
|
I2CAccess(pHWDE, &I2C);
|
|
if (I2C.Status != I2C_STATUS_NOERROR)
|
|
{
|
|
PDEBUGI2C(ErrorF("bGetEDID() fail: Reset I2C bus fail.\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
status = vGetEDID_2(pHWDE, &I2C, pjEDIDBuffer, ulBufferSize);
|
|
PDEBUGI2C(ErrorF("bGetEDID()-vGetEDID_2-status=%d\n", status == NO_ERROR ? 1:0));
|
|
|
|
if (status != NO_ERROR)
|
|
{
|
|
usleep(5);
|
|
status = vGetEDID_1(pHWDE, &I2C, pjEDIDBuffer, ulBufferSize);
|
|
PDEBUGI2C(ErrorF("bGetEDID()-vGetEDID_1-status=%d\n", status == NO_ERROR ? 1:0));
|
|
|
|
if (status == NO_ERROR)
|
|
{
|
|
if (*(pjEDIDBuffer+0x7E) != 0)
|
|
{
|
|
vGetEDIDExtensionBlocks(pHWDE, &I2C, pjEDIDBuffer+128, ulBufferSize-128);
|
|
PDEBUGI2C(ErrorF("bGetEDID()-vGetEDIDExtensionBlocks()\n"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ErrorF( "bGetEDID() fail !!\n");
|
|
}
|
|
}
|
|
|
|
I2COpen(pHWDE, I2C_CLOSE, ulChannelID, &I2C);
|
|
|
|
PDEBUGI2C(ErrorF("bGetEDID()-return(%d)\n", status == NO_ERROR ? 1:0));
|
|
return (status == NO_ERROR);
|
|
}
|