Enscript Output

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.