extractedLnx/linux-2.6.13/drivers/video/sis/init301.c_SiS_SenseLCDDDC.c
USHORT
SiS_SenseLCDDDC(SiS_Private *SiS_Pr, SISPtr pSiS)
{
USHORT DDCdatatype, paneltype, flag, xres=0, yres=0;
USHORT index, myindex, lumsize, numcodes, panelvendor, panelproduct;
int maxx=0, maxy=0, prefx=0, prefy=0;
unsigned char cr37=0, seekcode;
BOOLEAN checkexpand = FALSE;
BOOLEAN havesync = FALSE;
BOOLEAN indb = FALSE;
int retry, i;
unsigned char buffer[256];
for(i=0; i<7; i++) SiS_Pr->CP_DataValid[i] = FALSE;
SiS_Pr->CP_HaveCustomData = FALSE;
SiS_Pr->CP_MaxX = SiS_Pr->CP_MaxY = SiS_Pr->CP_MaxClock = 0;
SiS_Pr->CP_PreferredX = SiS_Pr->CP_PreferredY = 0;
SiS_Pr->CP_PreferredIndex = -1;
SiS_Pr->CP_PrefClock = 0;
SiS_Pr->PanelSelfDetected = FALSE;
if(!(pSiS->VBFlags & (VB_301|VB_301B|VB_301C|VB_302B))) return 0;
if(pSiS->VBFlags & VB_30xBDH) return 0;
if(SiS_InitDDCRegs(SiS_Pr, pSiS->VBFlags, pSiS->VGAEngine, 1, 0, FALSE) == 0xFFFF) return 0;
SiS_Pr->SiS_DDC_SecAddr = 0x00;
/* Probe supported DA's */
flag = SiS_ProbeDDC(SiS_Pr);
#ifdef TWDEBUG
xf86DrvMsg(pSiS->pScrn->scrnIndex, X_INFO,
"CRT2 DDC capabilities 0x%x\n", flag);
#endif
if(flag & 0x10) {
SiS_Pr->SiS_DDC_DeviceAddr = 0xa6; /* EDID V2 (FP) */
DDCdatatype = 4;
} else if(flag & 0x08) {
SiS_Pr->SiS_DDC_DeviceAddr = 0xa2; /* EDID V2 (P&D-D Monitor) */
DDCdatatype = 3;
} else if(flag & 0x02) {
SiS_Pr->SiS_DDC_DeviceAddr = 0xa0; /* EDID V1 */
DDCdatatype = 1;
} else return 0; /* no DDC support (or no device attached) */
/* Read the entire EDID */
retry = 2;
do {
if(SiS_ReadDDC(SiS_Pr, DDCdatatype, buffer)) {
xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
"CRT2: DDC read failed (attempt %d), %s\n",
(3-retry), (retry == 1) ? "giving up" : "retrying");
retry--;
if(retry == 0) return 0xFFFF;
} else break;
} while(1);
#ifdef TWDEBUG
for(i=0; i<256; i+=16) {
xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
"%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
buffer[i], buffer[i+1], buffer[i+2], buffer[i+3],
buffer[i+4], buffer[i+5], buffer[i+6], buffer[i+7],
buffer[i+8], buffer[i+9], buffer[i+10], buffer[i+11],
buffer[i+12], buffer[i+13], buffer[i+14], buffer[i+15]);
}
#endif
/* Analyze EDID and retrieve LCD panel information */
paneltype = 0;
switch(DDCdatatype) {
case 1: /* Analyze EDID V1 */
/* Catch a few clear cases: */
if(!(checkedid1(buffer))) {
xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
"LCD sense: EDID corrupt\n");
return 0;
}
if(!(buffer[0x14] & 0x80)) {
xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
"LCD sense: Attached display expects analog input (0x%02x)\n",
buffer[0x14]);
return 0;
}
if((buffer[0x18] & 0x18) != 0x08) {
xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
"LCD sense: Warning: Attached display is not of RGB but of %s type (0x%02x)\n",
((buffer[0x18] & 0x18) == 0x00) ? "monochrome/greyscale" :
( ((buffer[0x18] & 0x18) == 0x10) ? "non-RGB multicolor" :
"undefined"),
buffer[0x18]);
}
/* Now analyze the first Detailed Timing Block and see
* if the preferred timing mode is stored there. If so,
* check if this is a standard panel for which we already
* know the timing.
*/
paneltype = Panel_Custom;
checkexpand = FALSE;
panelvendor = buffer[9] | (buffer[8] << 8);
panelproduct = buffer[10] | (buffer[11] << 8);
/* Overrule bogus preferred modes from database */
if((indb = SiS_FindPanelFromDB(pSiS, panelvendor, panelproduct, &maxx, &maxy, &prefx, &prefy))) {
if(prefx) SiS_Pr->CP_PreferredX = xres = prefx;
if(prefy) SiS_Pr->CP_PreferredY = yres = prefy;
}
if(buffer[0x18] & 0x02) {
USHORT pclk = (buffer[0x36] | (buffer[0x37] << 8));
USHORT phb = (buffer[0x39] | ((buffer[0x3a] & 0x0f) << 8));
USHORT pvb = (buffer[0x3c] | ((buffer[0x3d] & 0x0f) << 8));
if(!xres) SiS_Pr->CP_PreferredX = xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4);
if(!yres) SiS_Pr->CP_PreferredY = yres = buffer[0x3b] | ((buffer[0x3d] & 0xf0) << 4);
switch(xres) {
#if 0 /* Treat as custom */
case 800:
if(yres == 600) {
paneltype = Panel_800x600;
checkexpand = TRUE;
}
break;
#endif
case 1024:
if(yres == 768) {
paneltype = Panel_1024x768;
checkexpand = TRUE;
}
break;
case 1280:
if(yres == 1024) {
paneltype = Panel_1280x1024;
checkexpand = TRUE;
} else if(yres == 960) {
if(pSiS->VGAEngine == SIS_300_VGA) {
paneltype = Panel300_1280x960;
} else {
paneltype = Panel310_1280x960;
}
} else if(yres == 768) {
if( (pclk == 8100) &&
(phb == (1688 - 1280)) &&
(pvb == (802 - 768)) ) {
paneltype = Panel_1280x768;
checkexpand = FALSE;
cr37 |= 0x10;
}
} else if(yres == 800) {
if( (pclk == 6900) &&
(phb == (1408 - 1280)) &&
(pvb == (816 - 800)) ) {
paneltype = Panel_1280x800;
}
}
break;
case 1400:
if(pSiS->VGAEngine == SIS_315_VGA) {
if(yres == 1050) {
paneltype = Panel310_1400x1050;
checkexpand = TRUE;
}
}
break;
case 1600:
if(pSiS->VGAEngine == SIS_315_VGA) {
if(pSiS->VBFlags & VB_301C) {
if(yres == 1200) {
paneltype = Panel310_1600x1200;
checkexpand = TRUE;
}
}
}
break;
}
/* Save sync: This is used if "Pass 1:1" is off; in this case
* we always use the panel's native mode = this "preferred mode"
* we just have been analysing. Hence, we also need its sync.
*/
if((buffer[0x47] & 0x18) == 0x18) {
cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20);
havesync = TRUE;
} else {
/* What now? There is no digital separate output timing... */
xf86DrvMsg(pSiS->pScrn->scrnIndex, X_WARNING,
"LCD sense: Unable to retrieve Sync polarity information\n");
cr37 |= 0xc0; /* Default */
}
}
/* Check against our database; eg. Sanyo Z2 projector reports
* 1024x768 as preferred mode, although it supports 1280x720
* natively in non-HDCP mode. Treat such wrongly reporting
* panels as custom and fixup actual maximum resolutions.
*/
if(paneltype != Panel_Custom) {
if(indb) {
paneltype = Panel_Custom;
SiS_Pr->CP_MaxX = maxx;
SiS_Pr->CP_MaxY = maxy;
/* Leave preferred unchanged (MUST contain a valid mode!) */
}
}
/* If we still don't know what panel this is, we take it
* as a custom panel and derive the timing data from the
* detailed timing blocks
*/
if(paneltype == Panel_Custom) {
int i, temp, base = 0x36;
unsigned long estpack;
const unsigned short estx[] = {
720, 720, 640, 640, 640, 640, 800, 800,
800, 800, 832,1024,1024,1024,1024,1280,
1152
};
const unsigned short esty[] = {
400, 400, 480, 480, 480, 480, 600, 600,
600, 600, 624, 768, 768, 768, 768,1024,
870
};
const int estclk[] = {
0, 0, 25100, 0, 31500, 31500, 36100, 40000,
50100, 49500, 0, 0, 65100, 75200, 78700,135200,
0
};
paneltype = 0;
SiS_Pr->CP_Supports64048075 = TRUE;
/* Find the maximum resolution */
/* 1. From Established timings */
estpack = (buffer[0x23] << 9) | (buffer[0x24] << 1) | ((buffer[0x25] >> 7) & 0x01);
for(i=16; i>=0; i--) {
if(estpack & (1 << i)) {
if(estx[16 - i] > SiS_Pr->CP_MaxX) SiS_Pr->CP_MaxX = estx[16 - i];
if(esty[16 - i] > SiS_Pr->CP_MaxY) SiS_Pr->CP_MaxY = esty[16 - i];
if(estclk[16 - i] > SiS_Pr->CP_MaxClock) SiS_Pr->CP_MaxClock = estclk[16 - i];
}
}
/* By default we drive the LCD at 75Hz in 640x480 mode; if
* the panel does not provide this mode, use 60hz
*/
if(!(buffer[0x23] & 0x04)) SiS_Pr->CP_Supports64048075 = FALSE;
/* 2. From Standard Timings */
for(i=0x26; i < 0x36; i+=2) {
if((buffer[i] != 0x01) && (buffer[i+1] != 0x01)) {
temp = (buffer[i] + 31) * 8;
if(temp > SiS_Pr->CP_MaxX) SiS_Pr->CP_MaxX = temp;
switch((buffer[i+1] & 0xc0) >> 6) {
case 0x03: temp = temp * 9 / 16; break;
case 0x02: temp = temp * 4 / 5; break;
case 0x01: temp = temp * 3 / 4; break;
}
if(temp > SiS_Pr->CP_MaxY) SiS_Pr->CP_MaxY = temp;
}
}
/* Now extract the Detailed Timings and convert them into modes */
for(i = 0; i < 4; i++, base += 18) {
/* Is this a detailed timing block or a monitor descriptor? */
if(buffer[base] || buffer[base+1] || buffer[base+2]) {
xres = buffer[base+2] | ((buffer[base+4] & 0xf0) << 4);
yres = buffer[base+5] | ((buffer[base+7] & 0xf0) << 4);
SiS_Pr->CP_HDisplay[i] = xres;
SiS_Pr->CP_HSyncStart[i] = xres + (buffer[base+8] | ((buffer[base+11] & 0xc0) << 2));
SiS_Pr->CP_HSyncEnd[i] = SiS_Pr->CP_HSyncStart[i] + (buffer[base+9] | ((buffer[base+11] & 0x30) << 4));
SiS_Pr->CP_HTotal[i] = xres + (buffer[base+3] | ((buffer[base+4] & 0x0f) << 8));
SiS_Pr->CP_HBlankStart[i] = xres + 1;
SiS_Pr->CP_HBlankEnd[i] = SiS_Pr->CP_HTotal[i];
SiS_Pr->CP_VDisplay[i] = yres;
SiS_Pr->CP_VSyncStart[i] = yres + (((buffer[base+10] & 0xf0) >> 4) | ((buffer[base+11] & 0x0c) << 2));
SiS_Pr->CP_VSyncEnd[i] = SiS_Pr->CP_VSyncStart[i] + ((buffer[base+10] & 0x0f) | ((buffer[base+11] & 0x03) << 4));
SiS_Pr->CP_VTotal[i] = yres + (buffer[base+6] | ((buffer[base+7] & 0x0f) << 8));
SiS_Pr->CP_VBlankStart[i] = yres + 1;
SiS_Pr->CP_VBlankEnd[i] = SiS_Pr->CP_VTotal[i];
SiS_Pr->CP_Clock[i] = (buffer[base] | (buffer[base+1] << 8)) * 10;
SiS_Pr->CP_DataValid[i] = TRUE;
/* Sort out invalid timings, interlace and too high clocks */
if((SiS_Pr->CP_HDisplay[i] & 7) ||
(SiS_Pr->CP_HDisplay[i] > SiS_Pr->CP_HSyncStart[i]) ||
(SiS_Pr->CP_HDisplay[i] >= SiS_Pr->CP_HSyncEnd[i]) ||
(SiS_Pr->CP_HDisplay[i] >= SiS_Pr->CP_HTotal[i]) ||
(SiS_Pr->CP_HSyncStart[i] >= SiS_Pr->CP_HSyncEnd[i]) ||
(SiS_Pr->CP_HSyncStart[i] > SiS_Pr->CP_HTotal[i]) ||
(SiS_Pr->CP_HSyncEnd[i] > SiS_Pr->CP_HTotal[i]) ||
(SiS_Pr->CP_VDisplay[i] > SiS_Pr->CP_VSyncStart[i]) ||
(SiS_Pr->CP_VDisplay[i] >= SiS_Pr->CP_VSyncEnd[i]) ||
(SiS_Pr->CP_VDisplay[i] >= SiS_Pr->CP_VTotal[i]) ||
(SiS_Pr->CP_VSyncStart[i] > SiS_Pr->CP_VSyncEnd[i]) ||
(SiS_Pr->CP_VSyncStart[i] > SiS_Pr->CP_VTotal[i]) ||
(SiS_Pr->CP_VSyncEnd[i] > SiS_Pr->CP_VTotal[i]) ||
(((pSiS->VBFlags & VB_301C) && (SiS_Pr->CP_Clock[i] > 162500)) ||
((!(pSiS->VBFlags & VB_301C)) &&
((SiS_Pr->CP_Clock[i] > 108200) || (SiS_Pr->CP_VDisplay[i] > 1024) ||
(SiS_Pr->CP_HDisplay[i] > 1600)))) ||
(buffer[base+17] & 0x80)) {
SiS_Pr->CP_DataValid[i] = FALSE;
} else {
SiS_Pr->CP_HaveCustomData = TRUE;
if(xres > SiS_Pr->CP_MaxX) SiS_Pr->CP_MaxX = xres;
if(yres > SiS_Pr->CP_MaxY) SiS_Pr->CP_MaxY = yres;
if(SiS_Pr->CP_Clock[i] > SiS_Pr->CP_MaxClock) SiS_Pr->CP_MaxClock = SiS_Pr->CP_Clock[i];
if((SiS_Pr->CP_PreferredX == xres) && (SiS_Pr->CP_PreferredY == yres)) {
SiS_Pr->CP_PreferredIndex = i;
SiS_MakeClockRegs(pSiS->pScrn, SiS_Pr->CP_Clock[i], &SiS_Pr->CP_PrefSR2B, &SiS_Pr->CP_PrefSR2C);
SiS_Pr->CP_PrefClock = (SiS_Pr->CP_Clock[i] / 1000) + 1;
}
/* Extract the sync polarisation information. This only works
* if the Flags indicate a digital separate output.
*/
if((buffer[base+17] & 0x18) == 0x18) {
SiS_Pr->CP_HSync_P[i] = (buffer[base+17] & 0x02) ? TRUE : FALSE;
SiS_Pr->CP_VSync_P[i] = (buffer[base+17] & 0x04) ? TRUE : FALSE;
SiS_Pr->CP_SyncValid[i] = TRUE;
if((i == SiS_Pr->CP_PreferredIndex) && (!havesync)) {
cr37 |= ((((buffer[base+17] & 0x06) ^ 0x06) << 5) | 0x20);
havesync = TRUE;
}
} else {
SiS_Pr->CP_SyncValid[i] = FALSE;
}
}
} else if((!buffer[base]) && (!buffer[base+1]) && (!buffer[base+2]) && (!buffer[base+4])) {
/* Maximum pixclock from Monitor Range Limits */
if((buffer[base+3] == 0xfd) && (buffer[base+9] != 0xff)) {
int maxclk = buffer[base+9] * 10;
/* More than 170 is not supported anyway */
if(maxclk <= 170) SiS_Pr->CP_MaxClock = maxclk * 1000;
}
}
}
if(SiS_Pr->CP_MaxX && SiS_Pr->CP_MaxY) {
paneltype = Panel_Custom;
checkexpand = FALSE;
cr37 |= 0x10;
SiS_Pr->CP_Vendor = panelvendor;
SiS_Pr->CP_Product = panelproduct;
}
}
if(paneltype && checkexpand) {
/* If any of the Established low-res modes is supported, the
* panel can scale automatically. For 800x600 panels, we only
* check the even lower ones.
*/
if(paneltype == Panel_800x600) {
if(buffer[0x23] & 0xfc) cr37 |= 0x10;
} else {
if(buffer[0x23]) cr37 |= 0x10;
}
}
break;
case 3: /* Analyze EDID V2 */
case 4:
index = 0;
if(!(checkedid2(buffer))) {
xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
"LCD sense: EDID corrupt\n");
return 0;
}
if((buffer[0x41] & 0x0f) == 0x03) {
index = 0x42 + 3;
xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
"LCD sense: Display supports TMDS input on primary interface\n");
} else if((buffer[0x41] & 0xf0) == 0x30) {
index = 0x46 + 3;
xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
"LCD sense: Display supports TMDS input on secondary interface\n");
} else {
xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
"LCD sense: Display does not support TMDS video interface (0x%02x)\n",
buffer[0x41]);
return 0;
}
SiS_Pr->CP_Vendor = panelvendor = buffer[2] | (buffer[1] << 8);
SiS_Pr->CP_Product = panelproduct = buffer[3] | (buffer[4] << 8);
paneltype = Panel_Custom;
SiS_Pr->CP_MaxX = SiS_Pr->CP_PreferredX = xres = buffer[0x76] | (buffer[0x77] << 8);
SiS_Pr->CP_MaxY = SiS_Pr->CP_PreferredY = yres = buffer[0x78] | (buffer[0x79] << 8);
switch(xres) {
#if 0
case 800:
if(yres == 600) {
paneltype = Panel_800x600;
checkexpand = TRUE;
}
break;
#endif
case 1024:
if(yres == 768) {
paneltype = Panel_1024x768;
checkexpand = TRUE;
}
break;
case 1280:
if(yres == 960) {
if(pSiS->VGAEngine == SIS_315_VGA) {
paneltype = Panel310_1280x960;
} else {
paneltype = Panel300_1280x960;
}
} else if(yres == 1024) {
paneltype = Panel_1280x1024;
checkexpand = TRUE;
}
/* 1280x768 treated as custom here */
break;
case 1400:
if(pSiS->VGAEngine == SIS_315_VGA) {
if(yres == 1050) {
paneltype = Panel310_1400x1050;
checkexpand = TRUE;
}
}
break;
case 1600:
if(pSiS->VGAEngine == SIS_315_VGA) {
if(pSiS->VBFlags & VB_301C) {
if(yres == 1200) {
paneltype = Panel310_1600x1200;
checkexpand = TRUE;
}
}
}
break;
}
/* Determine if RGB18 or RGB24 */
if(index) {
if((buffer[index] == 0x20) || (buffer[index] == 0x34)) {
cr37 |= 0x01;
}
}
if(checkexpand) {
/* TODO - for now, we let the panel scale */
cr37 |= 0x10;
}
/* Now seek 4-Byte Timing codes and extract sync pol info */
index = 0x80;
if(buffer[0x7e] & 0x20) { /* skip Luminance Table (if provided) */
lumsize = buffer[0x80] & 0x1f;
if(buffer[0x80] & 0x80) lumsize *= 3;
lumsize++; /* luminance header byte */
index += lumsize;
}
#if 0 /* "pixel rate" = pixel clock? */
if(buffer[0x7e] & 0x1c) {
for(i=0; i<((buffer[0x7e] & 0x1c) >> 2); i++) {
if(buffer[index + (i*8) + 6] && (buffer[index + (i*8) + 7] & 0x0f)) {
int clk = (buffer[index + (i*8) + 6] | ((buffer[index + (i*8) + 7] & 0x0f) << 4)) * 1000;
if(clk > SiS_Pr->CP_MaxClock) SiS_Pr->CP_MaxClock = clk;
}
}
}
#endif
index += (((buffer[0x7e] & 0x1c) >> 2) * 8); /* skip Frequency Ranges */
if(buffer[0x7e] & 0x03) {
for(i=0; i<(buffer[0x7e] & 0x03); i++) {
if((buffer[index + (i*27) + 9]) || (buffer[index + (i*27) + 10])) {
int clk = ((buffer[index + (i*27) + 9]) | ((buffer[index + (i*27) + 9]) << 8)) * 10;
if(clk > SiS_Pr->CP_MaxClock) SiS_Pr->CP_MaxClock = clk;
}
}
}
index += ((buffer[0x7e] & 0x03) * 27); /* skip Detailed Range Limits */
numcodes = (buffer[0x7f] & 0xf8) >> 3;
if(numcodes) {
myindex = index;
seekcode = (xres - 256) / 16;
for(i=0; i<numcodes; i++) {
if(buffer[myindex] == seekcode) break;
myindex += 4;
}
if(buffer[myindex] == seekcode) {
cr37 |= ((((buffer[myindex + 1] & 0x0c) ^ 0x0c) << 4) | 0x20);
havesync = TRUE;
} else {
xf86DrvMsg(pSiS->pScrn->scrnIndex, X_WARNING,
"LCD sense: Unable to retrieve Sync polarity information\n");
}
} else {
xf86DrvMsg(pSiS->pScrn->scrnIndex, X_WARNING,
"LCD sense: Unable to retrieve Sync polarity information\n");
}
/* Check against our database; Eg. Sanyo projector reports
* 1024x768 in non-HDPC mode, although it supports 1280x720.
* Treat such wrongly reporting panels as custom.
*/
if(paneltype != Panel_Custom) {
int maxx, maxy, prefx, prefy;
if((SiS_FindPanelFromDB(pSiS, panelvendor, panelproduct, &maxx, &maxy, &prefx, &prefy))) {
paneltype = Panel_Custom;
SiS_Pr->CP_MaxX = maxx;
SiS_Pr->CP_MaxY = maxy;
cr37 |= 0x10;
/* Leave preferred unchanged (MUST be a valid mode!) */
}
}
/* Now seek the detailed timing descriptions for custom panels */
if(paneltype == Panel_Custom) {
SiS_Pr->CP_Supports64048075 = TRUE;
index += (numcodes * 4);
numcodes = buffer[0x7f] & 0x07;
for(i=0; i<numcodes; i++, index += 18) {
xres = buffer[index+2] | ((buffer[index+4] & 0xf0) << 4);
yres = buffer[index+5] | ((buffer[index+7] & 0xf0) << 4);
SiS_Pr->CP_HDisplay[i] = xres;
SiS_Pr->CP_HSyncStart[i] = xres + (buffer[index+8] | ((buffer[index+11] & 0xc0) << 2));
SiS_Pr->CP_HSyncEnd[i] = SiS_Pr->CP_HSyncStart[i] + (buffer[index+9] | ((buffer[index+11] & 0x30) << 4));
SiS_Pr->CP_HTotal[i] = xres + (buffer[index+3] | ((buffer[index+4] & 0x0f) << 8));
SiS_Pr->CP_HBlankStart[i] = xres + 1;
SiS_Pr->CP_HBlankEnd[i] = SiS_Pr->CP_HTotal[i];
SiS_Pr->CP_VDisplay[i] = yres;
SiS_Pr->CP_VSyncStart[i] = yres + (((buffer[index+10] & 0xf0) >> 4) | ((buffer[index+11] & 0x0c) << 2));
SiS_Pr->CP_VSyncEnd[i] = SiS_Pr->CP_VSyncStart[i] + ((buffer[index+10] & 0x0f) | ((buffer[index+11] & 0x03) << 4));
SiS_Pr->CP_VTotal[i] = yres + (buffer[index+6] | ((buffer[index+7] & 0x0f) << 8));
SiS_Pr->CP_VBlankStart[i] = yres + 1;
SiS_Pr->CP_VBlankEnd[i] = SiS_Pr->CP_VTotal[i];
SiS_Pr->CP_Clock[i] = (buffer[index] | (buffer[index+1] << 8)) * 10;
SiS_Pr->CP_DataValid[i] = TRUE;
if((SiS_Pr->CP_HDisplay[i] & 7) ||
(SiS_Pr->CP_HDisplay[i] > SiS_Pr->CP_HSyncStart[i]) ||
(SiS_Pr->CP_HDisplay[i] >= SiS_Pr->CP_HSyncEnd[i]) ||
(SiS_Pr->CP_HDisplay[i] >= SiS_Pr->CP_HTotal[i]) ||
(SiS_Pr->CP_HSyncStart[i] >= SiS_Pr->CP_HSyncEnd[i]) ||
(SiS_Pr->CP_HSyncStart[i] > SiS_Pr->CP_HTotal[i]) ||
(SiS_Pr->CP_HSyncEnd[i] > SiS_Pr->CP_HTotal[i]) ||
(SiS_Pr->CP_VDisplay[i] > SiS_Pr->CP_VSyncStart[i]) ||
(SiS_Pr->CP_VDisplay[i] >= SiS_Pr->CP_VSyncEnd[i]) ||
(SiS_Pr->CP_VDisplay[i] >= SiS_Pr->CP_VTotal[i]) ||
(SiS_Pr->CP_VSyncStart[i] > SiS_Pr->CP_VSyncEnd[i]) ||
(SiS_Pr->CP_VSyncStart[i] > SiS_Pr->CP_VTotal[i]) ||
(SiS_Pr->CP_VSyncEnd[i] > SiS_Pr->CP_VTotal[i]) ||
(((pSiS->VBFlags & VB_301C) && (SiS_Pr->CP_Clock[i] > 162500)) ||
((!(pSiS->VBFlags & VB_301C)) &&
((SiS_Pr->CP_Clock[i] > 108200) || (SiS_Pr->CP_VDisplay[i] > 1024)))) ||
(buffer[index + 17] & 0x80)) {
SiS_Pr->CP_DataValid[i] = FALSE;
} else {
SiS_Pr->CP_HaveCustomData = TRUE;
if(SiS_Pr->CP_Clock[i] > SiS_Pr->CP_MaxClock) SiS_Pr->CP_MaxClock = SiS_Pr->CP_Clock[i];
if((SiS_Pr->CP_PreferredX == xres) && (SiS_Pr->CP_PreferredY == yres)) {
SiS_Pr->CP_PreferredIndex = i;
SiS_MakeClockRegs(pSiS->pScrn, SiS_Pr->CP_Clock[i], &SiS_Pr->CP_PrefSR2B, &SiS_Pr->CP_PrefSR2C);
SiS_Pr->CP_PrefClock = (SiS_Pr->CP_Clock[i] / 1000) + 1;
if(!havesync) {
cr37 |= ((((buffer[index + 17] & 0x06) ^ 0x06) << 5) | 0x20);
havesync = TRUE;
}
}
SiS_Pr->CP_HSync_P[i] = (buffer[index + 17] & 0x02) ? TRUE : FALSE;
SiS_Pr->CP_VSync_P[i] = (buffer[index + 17] & 0x04) ? TRUE : FALSE;
SiS_Pr->CP_SyncValid[i] = TRUE;
}
}
cr37 |= 0x10;
}
break;
}
/* 1280x960 panels are always RGB24, unable to scale and use
* high active sync polarity
*/
if(pSiS->VGAEngine == SIS_315_VGA) {
if(paneltype == Panel310_1280x960) cr37 &= 0x0e;
} else {
if(paneltype == Panel300_1280x960) cr37 &= 0x0e;
}
for(i = 0; i < 7; i++) {
if(SiS_Pr->CP_DataValid[i]) {
xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
"Non-standard LCD/DVI-D timing data no. %d:\n", i);
xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
" HDisplay %d HSync %d HSyncEnd %d HTotal %d\n",
SiS_Pr->CP_HDisplay[i], SiS_Pr->CP_HSyncStart[i],
SiS_Pr->CP_HSyncEnd[i], SiS_Pr->CP_HTotal[i]);
xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
" VDisplay %d VSync %d VSyncEnd %d VTotal %d\n",
SiS_Pr->CP_VDisplay[i], SiS_Pr->CP_VSyncStart[i],
SiS_Pr->CP_VSyncEnd[i], SiS_Pr->CP_VTotal[i]);
xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
" Pixel clock: %3.3fMhz\n", (float)SiS_Pr->CP_Clock[i] / 1000);
xf86DrvMsg(pSiS->pScrn->scrnIndex, X_INFO,
" To use this, add \"%dx%d\" to the list of Modes in the Screen section\n",
SiS_Pr->CP_HDisplay[i],
SiS_Pr->CP_VDisplay[i]);
}
}
if(paneltype) {
if(!SiS_Pr->CP_PreferredX) SiS_Pr->CP_PreferredX = SiS_Pr->CP_MaxX;
if(!SiS_Pr->CP_PreferredY) SiS_Pr->CP_PreferredY = SiS_Pr->CP_MaxY;
SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x32,0x08);
SiS_SetReg(SiS_Pr->SiS_P3d4,0x36,paneltype);
cr37 &= 0xf1;
SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x37,0x0c,cr37);
SiS_Pr->PanelSelfDetected = TRUE;
#ifdef TWDEBUG
xf86DrvMsgVerb(pSiS->pScrn->scrnIndex, X_PROBED, 3,
"LCD sense: [DDC LCD results: 0x%02x, 0x%02x]\n", paneltype, cr37);
#endif
} else {
SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x32,~0x08);
SiS_SetReg(SiS_Pr->SiS_P3d4,0x36,0x00);
}
return 0;
}
Generated by GNU enscript 1.6.4.