1/*
2 * X.org/XFree86 specific extensions to init.c/init301.c
3 *
4 * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1) Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2) Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3) The name of the author may not be used to endorse or promote products
15 *    derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Author: 	Thomas Winischhofer <thomas@winischhofer.net>
29 *
30 */
31
32#ifdef HAVE_CONFIG_H
33#include "config.h"
34#endif
35
36#include "initextx.h"
37
38static void
39SiS_MakeClockRegs(ScrnInfoPtr pScrn, int clock, unsigned char *p2b, unsigned char *p2c)
40{
41   int          out_n, out_dn, out_div, out_sbit, out_scale;
42   unsigned int vclk[5];
43
44#define Midx         0
45#define Nidx         1
46#define VLDidx       2
47#define Pidx         3
48#define PSNidx       4
49
50   if(SiS_compute_vclk(clock, &out_n, &out_dn, &out_div, &out_sbit, &out_scale)) {
51      (*p2b) = (out_div == 2) ? 0x80 : 0x00;
52      (*p2b) |= ((out_n - 1) & 0x7f);
53      (*p2c) = (out_dn - 1) & 0x1f;
54      (*p2c) |= (((out_scale - 1) & 3) << 5);
55      (*p2c) |= ((out_sbit & 0x01) << 7);
56#ifdef TWDEBUG
57      xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Clock %d: n %d dn %d div %d sb %d sc %d\n",
58        	 clock, out_n, out_dn, out_div, out_sbit, out_scale);
59#endif
60   } else {
61      SiSCalcClock(pScrn, clock, 2, vclk);
62      (*p2b) = (vclk[VLDidx] == 2) ? 0x80 : 0x00;
63      (*p2b) |= (vclk[Midx] - 1) & 0x7f;
64      (*p2c) = (vclk[Nidx] - 1) & 0x1f;
65      if(vclk[Pidx] <= 4) {
66	 /* postscale 1,2,3,4 */
67	 (*p2c) |= ((vclk[Pidx] - 1) & 3) << 5;
68      } else {
69	 /* postscale 6,8 */
70	 (*p2c) |= (((vclk[Pidx] / 2) - 1) & 3) << 5;
71	 (*p2c) |= 0x80;
72      }
73#ifdef TWDEBUG
74      xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Clock %d: n %d dn %d div %d sc %d\n",
75		clock, vclk[Midx], vclk[Nidx], vclk[VLDidx], vclk[Pidx]);
76#endif
77   }
78}
79
80unsigned short
81SiS_CheckBuildCustomMode(ScrnInfoPtr pScrn, DisplayModePtr mode, unsigned int VBFlags)
82{
83   SISPtr pSiS = SISPTR(pScrn);
84   int    depth = pSiS->CurrentLayout.bitsPerPixel;
85
86   pSiS->SiS_Pr->CModeFlag = 0;
87
88   pSiS->SiS_Pr->CDClock = mode->Clock;
89
90   pSiS->SiS_Pr->CHDisplay = mode->HDisplay;
91   pSiS->SiS_Pr->CHSyncStart = mode->HSyncStart;
92   pSiS->SiS_Pr->CHSyncEnd = mode->HSyncEnd;
93   pSiS->SiS_Pr->CHTotal = mode->HTotal;
94
95   pSiS->SiS_Pr->CVDisplay = mode->VDisplay;
96   pSiS->SiS_Pr->CVSyncStart = mode->VSyncStart;
97   pSiS->SiS_Pr->CVSyncEnd = mode->VSyncEnd;
98   pSiS->SiS_Pr->CVTotal = mode->VTotal;
99
100   pSiS->SiS_Pr->CFlags = mode->Flags;
101
102   if(pSiS->SiS_Pr->CFlags & V_INTERLACE) {
103      pSiS->SiS_Pr->CVDisplay >>= 1;
104      pSiS->SiS_Pr->CVSyncStart >>= 1;
105      pSiS->SiS_Pr->CVSyncEnd >>= 1;
106      pSiS->SiS_Pr->CVTotal >>= 1;
107   } else if(pSiS->SiS_Pr->CFlags & V_DBLSCAN) {
108      pSiS->SiS_Pr->CVDisplay <<= 1;
109      pSiS->SiS_Pr->CVSyncStart <<= 1;
110      pSiS->SiS_Pr->CVSyncEnd <<= 1;
111      pSiS->SiS_Pr->CVTotal <<= 1;
112   }
113
114   pSiS->SiS_Pr->CHBlankStart = pSiS->SiS_Pr->CHDisplay;
115   pSiS->SiS_Pr->CHBlankEnd = pSiS->SiS_Pr->CHTotal;
116   pSiS->SiS_Pr->CVBlankStart = pSiS->SiS_Pr->CVSyncStart - 1;
117   pSiS->SiS_Pr->CVBlankEnd = pSiS->SiS_Pr->CVTotal;
118
119   if((!(mode->type & M_T_BUILTIN)) && (mode->HDisplay <= 512)) {
120      pSiS->SiS_Pr->CModeFlag |= HalfDCLK;
121      pSiS->SiS_Pr->CDClock <<= 1;
122   }
123
124   /* Note: For CRT2, HDisplay, HSync* and HTotal must be shifted left
125    * in HalfDCLK mode.
126    */
127
128   SiS_MakeClockRegs(pScrn, pSiS->SiS_Pr->CDClock, &pSiS->SiS_Pr->CSR2B, &pSiS->SiS_Pr->CSR2C);
129
130   pSiS->SiS_Pr->CSRClock = (pSiS->SiS_Pr->CDClock / 1000) + 1;
131
132   SiS_CalcCRRegisters(pSiS->SiS_Pr, depth);
133
134   switch(depth) {
135   case  8: pSiS->SiS_Pr->CModeFlag |= 0x223b; break;
136   case 16: pSiS->SiS_Pr->CModeFlag |= 0x227d; break;
137   case 32: pSiS->SiS_Pr->CModeFlag |= 0x22ff; break;
138   default: return 0;
139   }
140
141   if(pSiS->SiS_Pr->CFlags & V_DBLSCAN)
142      pSiS->SiS_Pr->CModeFlag |= DoubleScanMode;
143
144   if((pSiS->SiS_Pr->CVDisplay >= 1024)	||
145      (pSiS->SiS_Pr->CVTotal >= 1024)   ||
146      (pSiS->SiS_Pr->CHDisplay >= 1024))
147      pSiS->SiS_Pr->CModeFlag |= LineCompareOff;
148
149   pSiS->SiS_Pr->CInfoFlag = 0x0007;
150
151   if(pSiS->SiS_Pr->CFlags & V_NHSYNC)
152      pSiS->SiS_Pr->CInfoFlag |= 0x4000;
153
154   if(pSiS->SiS_Pr->CFlags & V_NVSYNC)
155      pSiS->SiS_Pr->CInfoFlag |= 0x8000;
156
157   if(pSiS->SiS_Pr->CFlags & V_INTERLACE)
158      pSiS->SiS_Pr->CInfoFlag |= InterlaceMode;
159
160   pSiS->SiS_Pr->UseCustomMode = TRUE;
161#ifdef TWDEBUG
162   xf86DrvMsg(0, X_INFO, "Custom mode %dx%d:\n",
163	pSiS->SiS_Pr->CHDisplay,pSiS->SiS_Pr->CVDisplay);
164   xf86DrvMsg(0, X_INFO, "Modeflag %04x, Infoflag %04x\n",
165	pSiS->SiS_Pr->CModeFlag, pSiS->SiS_Pr->CInfoFlag);
166   xf86DrvMsg(0, X_INFO, " {{0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,\n",
167	pSiS->SiS_Pr->CCRT1CRTC[0], pSiS->SiS_Pr->CCRT1CRTC[1],
168	pSiS->SiS_Pr->CCRT1CRTC[2], pSiS->SiS_Pr->CCRT1CRTC[3],
169	pSiS->SiS_Pr->CCRT1CRTC[4], pSiS->SiS_Pr->CCRT1CRTC[5],
170	pSiS->SiS_Pr->CCRT1CRTC[6], pSiS->SiS_Pr->CCRT1CRTC[7]);
171   xf86DrvMsg(0, X_INFO, "  0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,\n",
172	pSiS->SiS_Pr->CCRT1CRTC[8], pSiS->SiS_Pr->CCRT1CRTC[9],
173	pSiS->SiS_Pr->CCRT1CRTC[10], pSiS->SiS_Pr->CCRT1CRTC[11],
174	pSiS->SiS_Pr->CCRT1CRTC[12], pSiS->SiS_Pr->CCRT1CRTC[13],
175	pSiS->SiS_Pr->CCRT1CRTC[14], pSiS->SiS_Pr->CCRT1CRTC[15]);
176   xf86DrvMsg(0, X_INFO, "  0x%02x}},\n", pSiS->SiS_Pr->CCRT1CRTC[16]);
177   xf86DrvMsg(0, X_INFO, "Clock: 0x%02x, 0x%02x, %d\n",
178	pSiS->SiS_Pr->CSR2B, pSiS->SiS_Pr->CSR2C, pSiS->SiS_Pr->CSRClock);
179#endif
180   return 1;
181}
182
183/* Build a list of supported modes:
184 * Built-in modes for which we have all data are M_T_DEFAULT,
185 * modes derived from DDC or database data are M_T_BUILTIN
186 */
187DisplayModePtr
188SiSBuildBuiltInModeList(ScrnInfoPtr pScrn, BOOLEAN includelcdmodes, BOOLEAN isfordvi,
189			BOOLEAN fakecrt2modes, BOOLEAN IsForCRT2)
190{
191   SISPtr	  pSiS = SISPTR(pScrn);
192   unsigned char  sr2b, sr2c;
193   float	  num, denum, postscalar, divider;
194   int		  i, j, k, l, index, vclkindex, UseWide;
195   DisplayModePtr new = NULL, current = NULL, first = NULL;
196   BOOLEAN	  done = FALSE, IsHDCLK;
197#if 0
198   DisplayModePtr backup = NULL;
199#endif
200
201   pSiS->backupmodelist = NULL;
202   pSiS->AddedPlasmaModes = FALSE;
203
204   UseWide = pSiS->SiS_Pr->SiS_UseWide;
205   if(IsForCRT2) UseWide = pSiS->SiS_Pr->SiS_UseWideCRT2;
206
207   if(!SiSInitPtr(pSiS->SiS_Pr)) return NULL;
208
209   i = 0;
210   while(pSiS->SiS_Pr->SiS_RefIndex[i].Ext_InfoFlag != 0xFFFF) {
211
212      if(pSiS->SiS_Pr->SiS_RefIndex[i].Ext_InfoFlag & HaveWideTiming) {
213	 if(UseWide == 1) {
214	    if((pSiS->SiS_Pr->SiS_RefIndex[i].Ext_CRT1CRTC_WIDE == 0xff) &&
215	       (pSiS->SiS_Pr->SiS_RefIndex[i].Ext_CRTVCLK_WIDE == 0xff)) {
216	       i++;
217	       continue;
218	    }
219	 } else {
220	    if((pSiS->SiS_Pr->SiS_RefIndex[i].Ext_CRT1CRTC_NORM == 0xff) &&
221	       (pSiS->SiS_Pr->SiS_RefIndex[i].Ext_CRTVCLK_NORM == 0xff)) {
222	       i++;
223	       continue;
224	    }
225	 }
226      }
227
228      index = SiS_GetRefCRT1CRTC(pSiS->SiS_Pr, i, UseWide);
229      if(fakecrt2modes) {
230	 if(pSiS->SiS_Pr->SiS_RefIndex[i].Ext_FakeCRT2CRTC) {
231	    index = pSiS->SiS_Pr->SiS_RefIndex[i].Ext_FakeCRT2CRTC;
232	 }
233      }
234
235      /* 0x5a (320x240) for FTSN - skip, is bad for CRT1 */
236      if(pSiS->SiS_Pr->SiS_RefIndex[i].ModeID == 0x5a)  {
237	 i++;
238	 continue;
239      }
240
241      if(!(new = malloc(sizeof(DisplayModeRec)))) return first;
242      memset(new, 0, sizeof(DisplayModeRec));
243      if(!(new->name = malloc(10))) {
244	 free(new);
245	 return first;
246      }
247      if(!first) first = new;
248      if(current) {
249	 current->next = new;
250	 new->prev = current;
251      }
252
253      current = new;
254
255      sprintf(current->name, "%hu%hu", pSiS->SiS_Pr->SiS_RefIndex[i].XRes,
256				      pSiS->SiS_Pr->SiS_RefIndex[i].YRes);
257
258      current->status = MODE_OK;
259
260      current->type = M_T_DEFAULT;
261
262      vclkindex = SiS_GetRefCRTVCLK(pSiS->SiS_Pr, i, UseWide);
263      if(fakecrt2modes) {
264	 if(pSiS->SiS_Pr->SiS_RefIndex[i].Ext_FakeCRT2Clk) {
265	    vclkindex = pSiS->SiS_Pr->SiS_RefIndex[i].Ext_FakeCRT2Clk;
266	 }
267      }
268
269      sr2b = pSiS->SiS_Pr->SiS_VCLKData[vclkindex].SR2B;
270      sr2c = pSiS->SiS_Pr->SiS_VCLKData[vclkindex].SR2C;
271
272      divider = (sr2b & 0x80) ? 2.0 : 1.0;
273      postscalar = (sr2c & 0x80) ?
274              ( (((sr2c >> 5) & 0x03) == 0x02) ? 6.0 : 8.0) : (((sr2c >> 5) & 0x03) + 1.0);
275      num = (sr2b & 0x7f) + 1.0;
276      denum = (sr2c & 0x1f) + 1.0;
277
278#ifdef TWDEBUG
279      xf86DrvMsg(0, X_INFO, "------------\n");
280      xf86DrvMsg(0, X_INFO, "sr2b: %x sr2c %x div %f ps %f num %f denum %f\n",
281         sr2b, sr2c, divider, postscalar, num, denum);
282#endif
283
284      current->Clock = (int)(14318 * (divider / postscalar) * (num / denum));
285
286      SiS_Generic_ConvertCRData(pSiS->SiS_Pr,
287			(unsigned char *)&pSiS->SiS_Pr->SiS_CRT1Table[index].CR[0],
288			pSiS->SiS_Pr->SiS_RefIndex[i].XRes,
289			pSiS->SiS_Pr->SiS_RefIndex[i].YRes, current);
290
291      if(pSiS->SiS_Pr->SiS_RefIndex[i].Ext_InfoFlag & 0x4000)
292	  current->Flags |= V_NHSYNC;
293      else
294	  current->Flags |= V_PHSYNC;
295
296      if(pSiS->SiS_Pr->SiS_RefIndex[i].Ext_InfoFlag & 0x8000)
297	  current->Flags |= V_NVSYNC;
298      else
299	  current->Flags |= V_PVSYNC;
300
301      if(pSiS->SiS_Pr->SiS_RefIndex[i].Ext_InfoFlag & 0x0080)
302          current->Flags |= V_INTERLACE;
303
304      j = 0;
305      IsHDCLK = FALSE;
306      while(pSiS->SiS_Pr->SiS_EModeIDTable[j].Ext_ModeID != 0xff) {
307	  if(pSiS->SiS_Pr->SiS_EModeIDTable[j].Ext_ModeID ==
308				pSiS->SiS_Pr->SiS_RefIndex[i].ModeID) {
309	     if(pSiS->SiS_Pr->SiS_EModeIDTable[j].Ext_ModeFlag & DoubleScanMode) {
310		  current->Flags |= V_DBLSCAN;
311	      }
312	      if(pSiS->SiS_Pr->SiS_EModeIDTable[j].Ext_ModeFlag & HalfDCLK) {
313		  IsHDCLK = TRUE;
314	      }
315	      break;
316	  }
317	  j++;
318      }
319
320      if(current->Flags & V_INTERLACE) {
321	 current->VDisplay <<= 1;
322	 current->VSyncStart <<= 1;
323	 current->VSyncEnd <<= 1;
324	 current->VTotal <<= 1;
325	 current->VTotal |= 1;
326      }
327
328      if(IsHDCLK) {
329	 current->Clock >>= 1;
330      }
331
332      if(current->Flags & V_DBLSCAN) {
333	 current->VDisplay >>= 1;
334	 current->VSyncStart >>= 1;
335	 current->VSyncEnd >>= 1;
336	 current->VTotal >>= 1;
337      }
338
339#ifdef TWDEBUG
340      xf86DrvMsg(pScrn->scrnIndex, X_INFO,
341	"Built-in: %s %.2f %d %d %d %d %d %d %d %d\n",
342	current->name, (float)current->Clock / 1000,
343	current->HDisplay, current->HSyncStart, current->HSyncEnd, current->HTotal,
344	current->VDisplay, current->VSyncStart, current->VSyncEnd, current->VTotal);
345#endif
346
347      i++;
348   }
349
350   /* Add non-standard LCD modes for panel's detailed timings */
351
352   if(!includelcdmodes) return first;
353
354   if(pSiS->SiS_Pr->CP_Vendor) {
355      xf86DrvMsg(0, X_INFO, "Checking database for vendor %x, product %x\n",
356         pSiS->SiS_Pr->CP_Vendor, pSiS->SiS_Pr->CP_Product);
357   }
358
359   i = 0;
360   while((!done) && (SiS_PlasmaTable[i].vendor) && (pSiS->SiS_Pr->CP_Vendor)) {
361
362     if(SiS_PlasmaTable[i].vendor == pSiS->SiS_Pr->CP_Vendor) {
363
364	for(j=0; j<SiS_PlasmaTable[i].productnum; j++) {
365
366	    if(SiS_PlasmaTable[i].product[j] == pSiS->SiS_Pr->CP_Product) {
367
368	       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
369		  "Identified %s panel, adding specific modes\n",
370		  SiS_PlasmaTable[i].plasmaname);
371
372	       for(k=0; k<SiS_PlasmaTable[i].modenum; k++) {
373
374		  if(isfordvi) {
375		     if(!(SiS_PlasmaTable[i].plasmamodes[k] & 0x80)) continue;
376		  } else {
377		     if(!(SiS_PlasmaTable[i].plasmamodes[k] & 0x40)) continue;
378		  }
379
380		  l = SiS_PlasmaTable[i].plasmamodes[k] & 0x3f;
381
382		  if(!(pSiS->VBFlags2 & VB2_LCDOVER1280BRIDGE)) {
383		     if(isfordvi) {
384		        if(SiS_PlasmaMode[l].VDisplay > 1024) continue;
385		     }
386		  }
387
388		  if(!(new = malloc(sizeof(DisplayModeRec)))) return first;
389
390		  memset(new, 0, sizeof(DisplayModeRec));
391		  if(!(new->name = malloc(12))) {
392		     free(new);
393		     return first;
394		  }
395		  if(!first) first = new;
396		  if(current) {
397		     current->next = new;
398		     new->prev = current;
399		  }
400
401		  current = new;
402
403		  pSiS->AddedPlasmaModes = TRUE;
404
405		  strcpy(current->name, SiS_PlasmaMode[l].name);
406
407		  current->status = MODE_OK;
408
409		  current->type = M_T_BUILTIN;
410
411		  current->Clock = SiS_PlasmaMode[l].clock;
412		  current->SynthClock = current->Clock;
413
414		  current->HDisplay   = SiS_PlasmaMode[l].HDisplay;
415		  current->HSyncStart = current->HDisplay + SiS_PlasmaMode[l].HFrontPorch;
416		  current->HSyncEnd   = current->HSyncStart + SiS_PlasmaMode[l].HSyncWidth;
417		  current->HTotal     = SiS_PlasmaMode[l].HTotal;
418
419		  current->VDisplay   = SiS_PlasmaMode[l].VDisplay;
420		  current->VSyncStart = current->VDisplay + SiS_PlasmaMode[l].VFrontPorch;
421		  current->VSyncEnd   = current->VSyncStart + SiS_PlasmaMode[l].VSyncWidth;
422		  current->VTotal     = SiS_PlasmaMode[l].VTotal;
423
424		  current->CrtcHDisplay = current->HDisplay;
425		  current->CrtcHBlankStart = current->HSyncStart;
426		  current->CrtcHSyncStart = current->HSyncStart;
427		  current->CrtcHSyncEnd = current->HSyncEnd;
428		  current->CrtcHBlankEnd = current->HSyncEnd;
429		  current->CrtcHTotal = current->HTotal;
430
431		  current->CrtcVDisplay = current->VDisplay;
432		  current->CrtcVBlankStart = current->VSyncStart;
433		  current->CrtcVSyncStart = current->VSyncStart;
434		  current->CrtcVSyncEnd = current->VSyncEnd;
435		  current->CrtcVBlankEnd = current->VSyncEnd;
436		  current->CrtcVTotal = current->VTotal;
437
438		  if(SiS_PlasmaMode[l].SyncFlags & SIS_PL_HSYNCP)
439		     current->Flags |= V_PHSYNC;
440		  else
441		     current->Flags |= V_NHSYNC;
442
443		  if(SiS_PlasmaMode[l].SyncFlags & SIS_PL_VSYNCP)
444		     current->Flags |= V_PVSYNC;
445		  else
446		     current->Flags |= V_NVSYNC;
447
448		  if(current->HDisplay > pSiS->LCDwidth)
449		     pSiS->LCDwidth = pSiS->SiS_Pr->CP_MaxX = current->HDisplay;
450		  if(current->VDisplay > pSiS->LCDheight)
451		     pSiS->LCDheight = pSiS->SiS_Pr->CP_MaxY = current->VDisplay;
452
453		  xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
454			"\tAdding \"%s\" to list of built-in modes\n", current->name);
455
456	       }
457	       done = TRUE;
458	       break;
459	    }
460	}
461     }
462
463     i++;
464
465   }
466
467   if(pSiS->SiS_Pr->CP_HaveCustomData) {
468
469      for(i=0; i<7; i++) {
470
471	 if(pSiS->SiS_Pr->CP_DataValid[i]) {
472
473	    if(!(new = malloc(sizeof(DisplayModeRec)))) return first;
474
475	    memset(new, 0, sizeof(DisplayModeRec));
476	    if(!(new->name = malloc(10))) {
477	       free(new);
478	       return first;
479	    }
480	    if(!first) first = new;
481	    if(current) {
482	       current->next = new;
483	       new->prev = current;
484	    }
485
486	    current = new;
487
488	    sprintf(current->name, "%dx%d", pSiS->SiS_Pr->CP_HDisplay[i],
489				pSiS->SiS_Pr->CP_VDisplay[i]);
490
491	    current->status = MODE_OK;
492
493	    current->type = M_T_BUILTIN;
494
495	    current->Clock = pSiS->SiS_Pr->CP_Clock[i];
496	    current->SynthClock = current->Clock;
497
498	    current->HDisplay   = pSiS->SiS_Pr->CP_HDisplay[i];
499	    current->HSyncStart = pSiS->SiS_Pr->CP_HSyncStart[i];
500	    current->HSyncEnd   = pSiS->SiS_Pr->CP_HSyncEnd[i];
501	    current->HTotal     = pSiS->SiS_Pr->CP_HTotal[i];
502
503	    current->VDisplay   = pSiS->SiS_Pr->CP_VDisplay[i];
504	    current->VSyncStart = pSiS->SiS_Pr->CP_VSyncStart[i];
505	    current->VSyncEnd   = pSiS->SiS_Pr->CP_VSyncEnd[i];
506	    current->VTotal     = pSiS->SiS_Pr->CP_VTotal[i];
507
508	    current->CrtcHDisplay = current->HDisplay;
509	    current->CrtcHBlankStart = pSiS->SiS_Pr->CP_HBlankStart[i];
510	    current->CrtcHSyncStart = current->HSyncStart;
511	    current->CrtcHSyncEnd = current->HSyncEnd;
512	    current->CrtcHBlankEnd = pSiS->SiS_Pr->CP_HBlankEnd[i];
513	    current->CrtcHTotal = current->HTotal;
514
515	    current->CrtcVDisplay = current->VDisplay;
516	    current->CrtcVBlankStart = pSiS->SiS_Pr->CP_VBlankStart[i];
517	    current->CrtcVSyncStart = current->VSyncStart;
518	    current->CrtcVSyncEnd = current->VSyncEnd;
519	    current->CrtcVBlankEnd = pSiS->SiS_Pr->CP_VBlankEnd[i];
520	    current->CrtcVTotal = current->VTotal;
521
522	    if(pSiS->SiS_Pr->CP_SyncValid[i]) {
523	       if(pSiS->SiS_Pr->CP_HSync_P[i])
524		  current->Flags |= V_PHSYNC;
525	       else
526		  current->Flags |= V_NHSYNC;
527
528	       if(pSiS->SiS_Pr->CP_VSync_P[i])
529		  current->Flags |= V_PVSYNC;
530	       else
531		  current->Flags |= V_NVSYNC;
532	    } else {
533	       /* No sync data? Use positive sync... */
534	       current->Flags |= V_PHSYNC;
535	       current->Flags |= V_PVSYNC;
536	    }
537	 }
538      }
539   }
540
541   return first;
542
543}
544
545/* Translate a mode number into the VESA pendant */
546int
547SiSTranslateToVESA(ScrnInfoPtr pScrn, int modenumber)
548{
549   SISPtr pSiS = SISPTR(pScrn);
550   int    i = 0;
551
552   if(!SiSInitPtr(pSiS->SiS_Pr)) return -1;
553
554   if(modenumber <= 0x13) return modenumber;
555
556#ifdef SIS315H
557   if(pSiS->ROM661New) { /* Not XGI! */
558      while(SiS_EModeIDTable661[i].Ext_ModeID != 0xff) {
559	 if(SiS_EModeIDTable661[i].Ext_ModeID == modenumber) {
560	    return (int)SiS_EModeIDTable661[i].Ext_VESAID;
561	 }
562	 i++;
563      }
564   } else {
565#endif
566      while(pSiS->SiS_Pr->SiS_EModeIDTable[i].Ext_ModeID != 0xff) {
567	 if(pSiS->SiS_Pr->SiS_EModeIDTable[i].Ext_ModeID == modenumber) {
568	    return (int)pSiS->SiS_Pr->SiS_EModeIDTable[i].Ext_VESAID;
569	 }
570	 i++;
571      }
572#ifdef SIS315H
573   }
574#endif
575   return -1;
576}
577
578/* Translate a new (SiS or XGI) BIOS mode number into the driver's pendant */
579int
580SiSTranslateToOldMode(int modenumber)
581{
582#ifdef SIS315H
583   int    i = 0;
584
585   while(SiS_EModeIDTable661[i].Ext_ModeID != 0xff) {
586      if(SiS_EModeIDTable661[i].Ext_ModeID == modenumber) {
587	 if(SiS_EModeIDTable661[i].Ext_MyModeID)
588	    return (int)SiS_EModeIDTable661[i].Ext_MyModeID;
589	 else
590	    return modenumber;
591      }
592      i++;
593   }
594#endif
595   return modenumber;
596}
597
598BOOLEAN
599SiS_GetPanelID(struct SiS_Private *SiS_Pr)
600{
601  unsigned short tempax, tempbx, temp;
602  static const unsigned short PanelTypeTable300[16] = {
603      0xc101, 0xc117, 0x0121, 0xc135, 0xc142, 0xc152, 0xc162, 0xc072,
604      0xc181, 0xc192, 0xc1a1, 0xc1b6, 0xc1c2, 0xc0d2, 0xc1e2, 0xc1f2
605  };
606  static const unsigned short PanelTypeTable31030x[16] = {
607      0xc102, 0xc112, 0x0122, 0xc132, 0xc142, 0xc152, 0xc169, 0xc179,
608      0x0189, 0xc192, 0xc1a2, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
609  };
610  static const unsigned short PanelTypeTable310LVDS[16] = {
611      0xc111, 0xc122, 0xc133, 0xc144, 0xc155, 0xc166, 0xc177, 0xc188,
612      0xc199, 0xc0aa, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
613  };
614
615  if(SiS_Pr->ChipType < SIS_315H) {
616
617     tempbx = SiS_GetReg(SiS_Pr->SiS_P3c4,0x18);
618     if(!(tempbx & 0x10)) {
619	if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
620	   tempbx = 0;
621	   temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x38);
622	   if(temp & 0x40) tempbx |= 0x08;
623	   if(temp & 0x20) tempbx |= 0x02;
624	   if(temp & 0x01) tempbx |= 0x01;
625	   temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x39);
626	   if(temp & 0x80) tempbx |= 0x04;
627	} else {
628	   return FALSE;
629	}
630     }
631     tempbx = PanelTypeTable300[(tempbx & 0x0f)] | LCDSync;
632     SiS_SetReg(SiS_Pr->SiS_P3d4,0x36,tempbx);
633     SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x37,~(LCDSyncBit|LCDRGB18Bit),(tempbx >> 8));
634
635  } else {
636
637     if(SiS_Pr->ChipType >= SIS_661) return FALSE;
638
639     tempax = (SiS_GetReg(SiS_Pr->SiS_P3c4,0x1a) & 0x1e) >> 1;
640     if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
641	if(tempax == 0) return FALSE;
642	tempbx = PanelTypeTable310LVDS[tempax - 1];
643	temp = tempax & 0xff;
644     } else {
645	tempbx = PanelTypeTable31030x[tempax];
646	temp = tempbx & 0xff;
647     }
648     SiS_SetReg(SiS_Pr->SiS_P3d4,0x36,temp);
649     tempbx >>= 8;
650     SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x37,~(LCDSyncBit|LCDRGB18Bit),(tempbx & 0xc1));
651     if(SiS_Pr->SiS_VBType & VB_SISVB) {
652	SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x39,0xfb,(tempbx & 0x04));
653     }
654
655  }
656  return TRUE;
657}
658
659/* LCD and VGA2 detection */
660
661static BOOLEAN
662checkedid1(unsigned char *buffer)
663{
664   /* Check header */
665   if((buffer[0] != 0x00) ||
666      (buffer[1] != 0xff) ||
667      (buffer[2] != 0xff) ||
668      (buffer[3] != 0xff) ||
669      (buffer[4] != 0xff) ||
670      (buffer[5] != 0xff) ||
671      (buffer[6] != 0xff) ||
672      (buffer[7] != 0x00))
673      return FALSE;
674
675   /* Check EDID version and revision */
676   if((buffer[0x12] != 1) || (buffer[0x13] > 4)) return FALSE;
677
678   /* Check week of manufacture for sanity */
679   if(buffer[0x10] > 54) return FALSE;
680
681   /* Check year of manufacture for sanity */
682   if(buffer[0x11] > 40) return FALSE;
683
684   return TRUE;
685}
686
687static BOOLEAN
688checkedid2(unsigned char *buffer)
689{
690   unsigned short year = buffer[6] | (buffer[7] << 8);
691
692   /* Check EDID version */
693   if((buffer[0] & 0xf0) != 0x20) return FALSE;
694
695   /* Check week of manufacture for sanity */
696   if(buffer[5] > 54) return FALSE;
697
698   /* Check year of manufacture for sanity */
699   if((year != 0) && ((year < 1990) || (year > 2030))) return FALSE;
700
701   return TRUE;
702}
703
704static int
705SiS_FindPanelFromDB(SISPtr pSiS, unsigned short panelvendor, unsigned short panelproduct,
706			int *maxx, int *maxy, int *prefx, int *prefy)
707{
708   int i, j;
709   BOOLEAN done = FALSE;
710
711   i = 0;
712   while((!done) && (SiS_PlasmaTable[i].vendor) && panelvendor) {
713      if(SiS_PlasmaTable[i].vendor == panelvendor) {
714	 for(j=0; j<SiS_PlasmaTable[i].productnum; j++) {
715	    if(SiS_PlasmaTable[i].product[j] == panelproduct) {
716	       if(SiS_PlasmaTable[i].maxx && SiS_PlasmaTable[i].maxy) {
717		  (*maxx) = (int)SiS_PlasmaTable[i].maxx;
718		  (*maxy) = (int)SiS_PlasmaTable[i].maxy;
719		  (*prefx) = (int)SiS_PlasmaTable[i].prefx;
720		  (*prefy) = (int)SiS_PlasmaTable[i].prefy;
721		  done = TRUE;
722		  xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
723			"Identified %s, correcting max X res %d, max Y res %d\n",
724			 SiS_PlasmaTable[i].plasmaname,
725			 SiS_PlasmaTable[i].maxx, SiS_PlasmaTable[i].maxy);
726		  break;
727	       }
728	    }
729	 }
730      }
731      i++;
732   }
733   return (done) ? 1 : 0;
734}
735
736/* Sense the LCD parameters (CR36, CR37) via DDC */
737/* SiS TMDS bridges only */
738unsigned short
739SiS_SenseLCDDDC(struct SiS_Private *SiS_Pr, SISPtr pSiS)
740{
741   unsigned short DDCdatatype, paneltype, adapternum, flag, xres=0, yres=0;
742   unsigned short index, myindex, lumsize, numcodes, panelvendor, panelproduct;
743   int maxx=0, maxy=0, prefx=0, prefy=0;
744   unsigned char cr37=0, seekcode;
745   BOOLEAN checkexpand = FALSE;
746   BOOLEAN havesync = FALSE;
747   BOOLEAN indb = FALSE;
748   int retry, i;
749   int panel1280x960 = (pSiS->VGAEngine == SIS_315_VGA) ? Panel310_1280x960 : Panel300_1280x960;
750   unsigned char buffer[256];
751
752   for(i=0; i<7; i++) SiS_Pr->CP_DataValid[i] = FALSE;
753   SiS_Pr->CP_HaveCustomData = FALSE;
754   SiS_Pr->CP_MaxX = SiS_Pr->CP_MaxY = SiS_Pr->CP_MaxClock = 0;
755   SiS_Pr->CP_PreferredX = SiS_Pr->CP_PreferredY = 0;
756   SiS_Pr->CP_PreferredIndex = -1;
757   SiS_Pr->CP_PrefClock = 0;
758   SiS_Pr->PanelSelfDetected = FALSE;
759
760   if(!(pSiS->VBFlags2 & VB2_SISTMDSBRIDGE)) return 0;
761   if(pSiS->VBFlags2 & VB2_30xBDH) return 0;
762
763   /* Specific for XGI_40/Rev 2/A01 (XGI V3XT A01): This card has CRT1's
764    * and CRT2's DDC ports physically connected to each other. There
765    * is no connection to the video bridge's DDC port, both DDC
766    * channels are routed to the GPU. Smart. If both CRT1 (CRT) and
767    * CRT2 (VGA or LCD) are connected, DDC will fail. Hence, no
768    * reliable panel detection here...
769    */
770   adapternum = 1;
771   if(SiS_Pr->DDCPortMixup) adapternum = 0;
772
773   if(SiS_InitDDCRegs(SiS_Pr, pSiS->VBFlags, pSiS->VGAEngine, adapternum, 0, FALSE, pSiS->VBFlags2) == 0xFFFF)
774      return 0;
775
776   SiS_Pr->SiS_DDC_SecAddr = 0x00;
777
778   /* Probe supported DA's */
779   flag = SiS_ProbeDDC(SiS_Pr);
780#ifdef TWDEBUG
781   xf86DrvMsg(pSiS->pScrn->scrnIndex, X_INFO,
782	"CRT2 DDC capabilities 0x%x\n", flag);
783#endif
784   if(flag & 0x10) {
785      SiS_Pr->SiS_DDC_DeviceAddr = 0xa6;	/* EDID V2 (FP) */
786      DDCdatatype = 4;
787   } else if(flag & 0x08) {
788      SiS_Pr->SiS_DDC_DeviceAddr = 0xa2;	/* EDID V2 (P&D-D Monitor) */
789      DDCdatatype = 3;
790   } else if(flag & 0x02) {
791      SiS_Pr->SiS_DDC_DeviceAddr = 0xa0;	/* EDID V1 */
792      DDCdatatype = 1;
793   } else return 0;				/* no DDC support (or no device attached) */
794
795   /* Read the entire EDID */
796   retry = 2;
797   do {
798      if(SiS_ReadDDC(SiS_Pr, DDCdatatype, buffer)) {
799	 xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
800		"CRT2: DDC read failed (attempt %d), %s\n",
801		(3-retry), (retry == 1) ? "giving up" : "retrying");
802	 retry--;
803	 if(retry == 0) return 0xFFFF;
804      } else break;
805   } while(1);
806
807#ifdef TWDEBUG
808   for(i=0; i<256; i+=16) {
809      xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
810	"%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
811	buffer[i],    buffer[i+1], buffer[i+2], buffer[i+3],
812	buffer[i+4],  buffer[i+5], buffer[i+6], buffer[i+7],
813	buffer[i+8],  buffer[i+9], buffer[i+10], buffer[i+11],
814	buffer[i+12], buffer[i+13], buffer[i+14], buffer[i+15]);
815   }
816#endif
817
818   /* Analyze EDID and retrieve LCD panel information */
819   paneltype = 0;
820   switch(DDCdatatype) {
821   case 1:							/* Analyze EDID V1 */
822      /* Catch a few clear cases: */
823      if(!(checkedid1(buffer))) {
824	xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
825	 	"LCD sense: EDID corrupt\n");
826	 return 0;
827      }
828
829      if(!(buffer[0x14] & 0x80)) {
830	 xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
831		"LCD sense: Attached display expects analog input (0x%02x)\n",
832		buffer[0x14]);
833	 return 0;
834      }
835
836      /* Save given gamma */
837      pSiS->CRT2LCDMonitorGamma = (buffer[0x17] + 100) * 10;
838
839      /* Now analyze the first Detailed Timing Block and see
840       * if the preferred timing mode is stored there. If so,
841       * check if this is a standard panel for which we already
842       * know the timing.
843       */
844
845      paneltype = Panel_Custom;
846      checkexpand = FALSE;
847
848      panelvendor = buffer[9] | (buffer[8] << 8);
849      panelproduct = buffer[10] | (buffer[11] << 8);
850
851      /* Overrule bogus preferred modes from database */
852      if((indb = SiS_FindPanelFromDB(pSiS, panelvendor, panelproduct, &maxx, &maxy, &prefx, &prefy))) {
853	 if(prefx) SiS_Pr->CP_PreferredX = xres = prefx;
854	 if(prefy) SiS_Pr->CP_PreferredY = yres = prefy;
855      }
856
857      if(buffer[0x18] & 0x02) {
858
859	 unsigned short pclk = (buffer[0x36] | (buffer[0x37] << 8));
860	 unsigned short phb  = (buffer[0x39] | ((buffer[0x3a] & 0x0f) << 8));
861	 unsigned short pvb  = (buffer[0x3c] | ((buffer[0x3d] & 0x0f) << 8));
862
863	 if(!xres) SiS_Pr->CP_PreferredX = xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4);
864	 if(!yres) SiS_Pr->CP_PreferredY = yres = buffer[0x3b] | ((buffer[0x3d] & 0xf0) << 4);
865
866	 switch(xres) {
867	    case 1024:
868	        if(yres == 768) {
869		   paneltype = Panel_1024x768;
870		   checkexpand = TRUE;
871	        }
872	        break;
873	    case 1280:
874		if(yres == 1024) {
875		   paneltype = Panel_1280x1024;
876		   checkexpand = TRUE;
877		} else if(yres == 960) {
878		   paneltype = panel1280x960;
879		} else if(yres == 768) {
880		   if( (pclk == 8100) &&
881		       (phb == (1688 - 1280)) &&
882		       (pvb == (802 - 768)) ) {
883		      paneltype = Panel_1280x768;
884		      checkexpand = FALSE;
885		      cr37 |= 0x10;
886		   }
887		} else if(yres == 800) {
888		   if( (pclk == 6900) &&
889		       (phb == (1408 - 1280)) &&
890		       (pvb == (816 - 800)) ) {
891		      paneltype = Panel_1280x800;
892		   }
893		}
894		break;
895	    case 1400:
896		if(pSiS->VGAEngine == SIS_315_VGA) {
897		   if(yres == 1050) {
898		      paneltype = Panel310_1400x1050;
899		      checkexpand = TRUE;
900		   }
901		}
902		break;
903	    case 1600:
904		if((pSiS->VGAEngine == SIS_315_VGA) && (pSiS->VBFlags2 & VB2_30xC)) {
905		   if(yres == 1200) {
906		      if( (pclk == 16200) &&
907			  (phb == (2160 - 1600)) &&
908			  (pvb == (1250 - 1200)) ) {
909			 paneltype = Panel310_1600x1200;
910			 checkexpand = TRUE;
911		      }
912		   }
913		}
914		break;
915	 }
916
917	 /* Save sync: This is used if "Pass 1:1" is off; in this case
918	  * we always use the panel's native mode = this "preferred mode"
919	  * we just have been analysing. Hence, we also need its sync.
920	  */
921	 if((buffer[0x47] & 0x18) == 0x18) {
922	    cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20);
923	    havesync = TRUE;
924	 } else {
925	    /* What now? There is no digital separate output timing... */
926	    xf86DrvMsg(pSiS->pScrn->scrnIndex, X_WARNING,
927		   "LCD sense: Unable to retrieve Sync polarity information\n");
928	    cr37 |= 0xc0;  /* Default */
929	 }
930
931      }
932
933      /* Check against our database; eg. Sanyo Z2 projector reports
934       * 1024x768 as preferred mode, although it supports 1280x720
935       * natively in non-HDCP mode. Treat such wrongly reporting
936       * panels as custom and fixup actual maximum resolutions.
937       */
938      if(paneltype != Panel_Custom) {
939	 if(indb) {
940	    paneltype = Panel_Custom;
941	    SiS_Pr->CP_MaxX = maxx;
942	    SiS_Pr->CP_MaxY = maxy;
943	    /* Leave preferred unchanged (MUST contain a valid mode!) */
944	 }
945      }
946
947      /* If we still don't know what panel this is, we take it
948       * as a custom panel and derive the timing data from the
949       * detailed timing blocks
950       */
951      if(paneltype == Panel_Custom) {
952
953	 int i, temp, base = 0x36;
954	 unsigned long estpack;
955	 static const unsigned short estx[] = {
956		720, 720, 640, 640, 640, 640, 800, 800,
957		800, 800, 832,1024,1024,1024,1024,1280,
958		1152
959	 };
960	 static const unsigned short esty[] = {
961		400, 400, 480, 480, 480, 480, 600, 600,
962		600, 600, 624, 768, 768, 768, 768,1024,
963		870
964	 };
965	 static const int estclk[] = {
966		    0,     0, 25100,   0, 31500, 31500, 36100, 40000,
967		50100, 49500,     0,   0, 65100, 75200, 78700,135200,
968		0
969	 };
970
971	 paneltype = 0;
972	 SiS_Pr->CP_Supports64048075 = TRUE;
973
974	 /* Find the maximum resolution */
975
976	 /* 1. From Established timings */
977	 estpack = (buffer[0x23] << 9) | (buffer[0x24] << 1) | ((buffer[0x25] >> 7) & 0x01);
978	 for(i=16; i>=0; i--) {
979	     if(estpack & (1 << i)) {
980		if(estx[16 - i] > SiS_Pr->CP_MaxX) SiS_Pr->CP_MaxX = estx[16 - i];
981		if(esty[16 - i] > SiS_Pr->CP_MaxY) SiS_Pr->CP_MaxY = esty[16 - i];
982		if(estclk[16 - i] > SiS_Pr->CP_MaxClock) SiS_Pr->CP_MaxClock = estclk[16 - i];
983	     }
984	 }
985
986	 /* By default we drive the LCD at 75Hz in 640x480 mode; if
987	  * the panel does not provide this mode, use 60hz
988	  */
989	 if(!(buffer[0x23] & 0x04)) SiS_Pr->CP_Supports64048075 = FALSE;
990
991	 /* 2. From Standard Timings */
992	 for(i=0x26; i < 0x36; i+=2) {
993	    if((buffer[i] != 0x01) && (buffer[i+1] != 0x01)) {
994	       temp = (buffer[i] + 31) * 8;
995	       if(temp > SiS_Pr->CP_MaxX) SiS_Pr->CP_MaxX = temp;
996	       switch((buffer[i+1] & 0xc0) >> 6) {
997	       case 0x03: temp = temp * 9 / 16; break;
998	       case 0x02: temp = temp * 4 / 5;  break;
999	       case 0x01: temp = temp * 3 / 4;  break;
1000	       }
1001	       if(temp > SiS_Pr->CP_MaxY) SiS_Pr->CP_MaxY = temp;
1002	    }
1003	 }
1004
1005	 /* Now extract the Detailed Timings and convert them into modes */
1006
1007	for(i = 0; i < 4; i++, base += 18) {
1008
1009	    /* Is this a detailed timing block or a monitor descriptor? */
1010	    if(buffer[base] || buffer[base+1] || buffer[base+2]) {
1011
1012	       xres = buffer[base+2] | ((buffer[base+4] & 0xf0) << 4);
1013	       yres = buffer[base+5] | ((buffer[base+7] & 0xf0) << 4);
1014
1015	       SiS_Pr->CP_HDisplay[i] = xres;
1016	       SiS_Pr->CP_HSyncStart[i] = xres + (buffer[base+8] | ((buffer[base+11] & 0xc0) << 2));
1017	       SiS_Pr->CP_HSyncEnd[i]   = SiS_Pr->CP_HSyncStart[i] + (buffer[base+9] | ((buffer[base+11] & 0x30) << 4));
1018	       SiS_Pr->CP_HTotal[i] = xres + (buffer[base+3] | ((buffer[base+4] & 0x0f) << 8));
1019	       SiS_Pr->CP_HBlankStart[i] = xres + 1;
1020	       SiS_Pr->CP_HBlankEnd[i] = SiS_Pr->CP_HTotal[i];
1021
1022	       SiS_Pr->CP_VDisplay[i] = yres;
1023	       SiS_Pr->CP_VSyncStart[i] = yres + (((buffer[base+10] & 0xf0) >> 4) | ((buffer[base+11] & 0x0c) << 2));
1024	       SiS_Pr->CP_VSyncEnd[i] = SiS_Pr->CP_VSyncStart[i] + ((buffer[base+10] & 0x0f) | ((buffer[base+11] & 0x03) << 4));
1025	       SiS_Pr->CP_VTotal[i] = yres + (buffer[base+6] | ((buffer[base+7] & 0x0f) << 8));
1026	       SiS_Pr->CP_VBlankStart[i] = yres + 1;
1027	       SiS_Pr->CP_VBlankEnd[i] = SiS_Pr->CP_VTotal[i];
1028
1029	       SiS_Pr->CP_Clock[i] = (buffer[base] | (buffer[base+1] << 8)) * 10;
1030
1031	       SiS_Pr->CP_DataValid[i] = TRUE;
1032
1033	       /* Sort out invalid timings, interlace and too high clocks */
1034	       if((SiS_Pr->CP_HDisplay[i] & 7)						  ||
1035		  (SiS_Pr->CP_HDisplay[i] > SiS_Pr->CP_HSyncStart[i])			  ||
1036		  (SiS_Pr->CP_HDisplay[i] >= SiS_Pr->CP_HSyncEnd[i])			  ||
1037		  (SiS_Pr->CP_HDisplay[i] >= SiS_Pr->CP_HTotal[i])			  ||
1038		  (SiS_Pr->CP_HSyncStart[i] >= SiS_Pr->CP_HSyncEnd[i])			  ||
1039		  (SiS_Pr->CP_HSyncStart[i] > SiS_Pr->CP_HTotal[i])			  ||
1040		  (SiS_Pr->CP_HSyncEnd[i] > SiS_Pr->CP_HTotal[i])			  ||
1041		  (SiS_Pr->CP_VDisplay[i] > SiS_Pr->CP_VSyncStart[i])			  ||
1042		  (SiS_Pr->CP_VDisplay[i] >= SiS_Pr->CP_VSyncEnd[i])			  ||
1043		  (SiS_Pr->CP_VDisplay[i] >= SiS_Pr->CP_VTotal[i])			  ||
1044		  (SiS_Pr->CP_VSyncStart[i] > SiS_Pr->CP_VSyncEnd[i])			  ||
1045		  (SiS_Pr->CP_VSyncStart[i] > SiS_Pr->CP_VTotal[i])			  ||
1046		  (SiS_Pr->CP_VSyncEnd[i] > SiS_Pr->CP_VTotal[i])			  ||
1047		  (((pSiS->VBFlags2 & VB2_30xC) && (SiS_Pr->CP_Clock[i] > 162500)) ||
1048		   ((!(pSiS->VBFlags2 & VB2_30xC))        &&
1049		    ( (SiS_Pr->CP_Clock[i] > 110500)  ||		/* TODO for 307 */
1050		      (SiS_Pr->CP_VDisplay[i] > 1024) ||
1051		      (SiS_Pr->CP_HDisplay[i] > 1600) )))				  ||
1052		  (buffer[base+17] & 0x80)) {
1053
1054		  SiS_Pr->CP_DataValid[i] = FALSE;
1055
1056	       } else {
1057
1058		  SiS_Pr->CP_HaveCustomData = TRUE;
1059
1060		  if(xres > SiS_Pr->CP_MaxX) SiS_Pr->CP_MaxX = xres;
1061		  if(yres > SiS_Pr->CP_MaxY) SiS_Pr->CP_MaxY = yres;
1062		  if(SiS_Pr->CP_Clock[i] > SiS_Pr->CP_MaxClock) SiS_Pr->CP_MaxClock = SiS_Pr->CP_Clock[i];
1063
1064		  if((SiS_Pr->CP_PreferredX == xres) && (SiS_Pr->CP_PreferredY == yres)) {
1065		     SiS_Pr->CP_PreferredIndex = i;
1066		     SiS_MakeClockRegs(pSiS->pScrn, SiS_Pr->CP_Clock[i], &SiS_Pr->CP_PrefSR2B, &SiS_Pr->CP_PrefSR2C);
1067		     SiS_Pr->CP_PrefClock = (SiS_Pr->CP_Clock[i] / 1000) + 1;
1068		  }
1069
1070		  /* Extract the sync polarisation information. This only works
1071		   * if the Flags indicate a digital separate output.
1072		   */
1073		  if((buffer[base+17] & 0x18) == 0x18) {
1074		     SiS_Pr->CP_HSync_P[i] = (buffer[base+17] & 0x02) ? TRUE : FALSE;
1075		     SiS_Pr->CP_VSync_P[i] = (buffer[base+17] & 0x04) ? TRUE : FALSE;
1076		     SiS_Pr->CP_SyncValid[i] = TRUE;
1077		     if((i == SiS_Pr->CP_PreferredIndex) && (!havesync)) {
1078			cr37 |= ((((buffer[base+17] & 0x06) ^ 0x06) << 5) | 0x20);
1079			havesync = TRUE;
1080		     }
1081		  } else {
1082		     SiS_Pr->CP_SyncValid[i] = FALSE;
1083		  }
1084
1085	       }
1086
1087	    } else if((!buffer[base]) && (!buffer[base+1]) && (!buffer[base+2]) && (!buffer[base+4])) {
1088
1089	       /* Maximum pixclock from Monitor Range Limits */
1090	       if((buffer[base+3] == 0xfd) && (buffer[base+9] != 0xff)) {
1091		  int maxclk = buffer[base+9] * 10;
1092		  /* More than 170 is not supported anyway */
1093		  if(maxclk <= 170) SiS_Pr->CP_MaxClock = maxclk * 1000;
1094	       }
1095
1096	    }
1097
1098	 }
1099
1100	 if(SiS_Pr->CP_MaxX && SiS_Pr->CP_MaxY) {
1101	    paneltype = Panel_Custom;
1102	    checkexpand = FALSE;
1103	    cr37 |= 0x10;
1104	    SiS_Pr->CP_Vendor = panelvendor;
1105	    SiS_Pr->CP_Product = panelproduct;
1106	 }
1107
1108      }
1109
1110      if(paneltype && checkexpand) {
1111	 /* If any of the Established low-res modes is supported, the
1112	  * panel can scale automatically. For 800x600 panels, we only
1113	  * check the even lower ones.
1114	  */
1115	 if(paneltype == Panel_800x600) {
1116	    if(buffer[0x23] & 0xfc) cr37 |= 0x10;
1117	 } else {
1118	    if(buffer[0x23])	    cr37 |= 0x10;
1119	 }
1120      }
1121
1122      break;
1123
1124   case 3:							/* Analyze EDID V2 */
1125   case 4:
1126      index = 0;
1127
1128      if(!(checkedid2(buffer))) {
1129	 xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
1130	 	"LCD sense: EDID corrupt\n");
1131	 return 0;
1132      }
1133
1134      if((buffer[0x41] & 0x0f) == 0x03) {
1135	 index = 0x42 + 3;
1136	 xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
1137	 	"LCD sense: Display supports TMDS input on primary interface\n");
1138      } else if((buffer[0x41] & 0xf0) == 0x30) {
1139	 index = 0x46 + 3;
1140	 xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
1141	 	"LCD sense: Display supports TMDS input on secondary interface\n");
1142      } else {
1143	 xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
1144		"LCD sense: Display does not support TMDS video interface (0x%02x)\n",
1145		buffer[0x41]);
1146	 return 0;
1147      }
1148
1149      /* Save given gamma */
1150      pSiS->CRT2LCDMonitorGamma = (buffer[0x56] + 100) * 10;
1151
1152      SiS_Pr->CP_Vendor = panelvendor = buffer[2] | (buffer[1] << 8);
1153      SiS_Pr->CP_Product = panelproduct = buffer[3] | (buffer[4] << 8);
1154
1155      paneltype = Panel_Custom;
1156      SiS_Pr->CP_MaxX = SiS_Pr->CP_PreferredX = xres = buffer[0x76] | (buffer[0x77] << 8);
1157      SiS_Pr->CP_MaxY = SiS_Pr->CP_PreferredY = yres = buffer[0x78] | (buffer[0x79] << 8);
1158
1159      switch(xres) {
1160         case 1024:
1161	     if(yres == 768) {
1162		paneltype = Panel_1024x768;
1163		checkexpand = TRUE;
1164	     }
1165	     break;
1166	 case 1280:
1167	     if(yres == 960) {
1168		paneltype = panel1280x960;
1169	     } else if(yres == 1024) {
1170		paneltype = Panel_1280x1024;
1171		checkexpand = TRUE;
1172	     }
1173	     /* 1280x768, 1280x800 treated as custom here */
1174	     break;
1175	 case 1400:
1176	     if(pSiS->VGAEngine == SIS_315_VGA) {
1177		if(yres == 1050) {
1178		   paneltype = Panel310_1400x1050;
1179		   checkexpand = TRUE;
1180		}
1181	     }
1182	     break;
1183	 /* 1600x1200 treated as custom */
1184      }
1185
1186      /* Determine if RGB18 or RGB24 */
1187      if(index) {
1188	 if((buffer[index] == 0x20) || (buffer[index] == 0x34)) {
1189	    cr37 |= 0x01;
1190	 }
1191      }
1192
1193      if(checkexpand) {
1194	 /* TODO - for now, we let the panel scale */
1195	 cr37 |= 0x10;
1196      }
1197
1198      /* Now seek 4-Byte Timing codes and extract sync pol info */
1199      index = 0x80;
1200      if(buffer[0x7e] & 0x20) {			    /* skip Luminance Table (if provided) */
1201	 lumsize = buffer[0x80] & 0x1f;
1202	 if(buffer[0x80] & 0x80) lumsize *= 3;
1203	 lumsize++;  /* luminance header byte */
1204	 index += lumsize;
1205      }
1206#if 0 /* "pixel rate" = pixel clock? */
1207      if(buffer[0x7e] & 0x1c) {
1208	 for(i=0; i<((buffer[0x7e] & 0x1c) >> 2); i++) {
1209	    if(buffer[index + (i*8) + 6] && (buffer[index + (i*8) + 7] & 0x0f)) {
1210	       int clk = (buffer[index + (i*8) + 6] | ((buffer[index + (i*8) + 7] & 0x0f) << 4)) * 1000;
1211	       if(clk > SiS_Pr->CP_MaxClock) SiS_Pr->CP_MaxClock = clk;
1212	    }
1213	 }
1214      }
1215#endif
1216      index += (((buffer[0x7e] & 0x1c) >> 2) * 8);   /* skip Frequency Ranges */
1217      if(buffer[0x7e] & 0x03) {
1218	 for(i=0; i<(buffer[0x7e] & 0x03); i++) {
1219	    if((buffer[index + (i*27) + 9]) || (buffer[index + (i*27) + 10])) {
1220	       int clk = ((buffer[index + (i*27) + 9]) | ((buffer[index + (i*27) + 9]) << 8)) * 10;
1221	       if(clk > SiS_Pr->CP_MaxClock) SiS_Pr->CP_MaxClock = clk;
1222	    }
1223	 }
1224      }
1225      index += ((buffer[0x7e] & 0x03) * 27);         /* skip Detailed Range Limits */
1226      numcodes = (buffer[0x7f] & 0xf8) >> 3;
1227      if(numcodes) {
1228	 myindex = index;
1229	 seekcode = (xres - 256) / 16;
1230	 for(i=0; i<numcodes; i++) {
1231	    if(buffer[myindex] == seekcode) break;
1232	    myindex += 4;
1233	 }
1234	 if(buffer[myindex] == seekcode) {
1235	    cr37 |= ((((buffer[myindex + 1] & 0x0c) ^ 0x0c) << 4) | 0x20);
1236	    havesync = TRUE;
1237	 } else {
1238	    xf86DrvMsg(pSiS->pScrn->scrnIndex, X_WARNING,
1239		"LCD sense: Unable to retrieve Sync polarity information\n");
1240	 }
1241      } else {
1242         xf86DrvMsg(pSiS->pScrn->scrnIndex, X_WARNING,
1243	     "LCD sense: Unable to retrieve Sync polarity information\n");
1244      }
1245
1246      /* Check against our database; Eg. Sanyo projector reports
1247       * 1024x768 in non-HDPC mode, although it supports 1280x720.
1248       * Treat such wrongly reporting panels as custom.
1249       */
1250      if(paneltype != Panel_Custom) {
1251	 int maxx, maxy, prefx, prefy;
1252	 if((SiS_FindPanelFromDB(pSiS, panelvendor, panelproduct, &maxx, &maxy, &prefx, &prefy))) {
1253	    paneltype = Panel_Custom;
1254	    SiS_Pr->CP_MaxX = maxx;
1255	    SiS_Pr->CP_MaxY = maxy;
1256	    cr37 |= 0x10;
1257	    /* Leave preferred unchanged (MUST be a valid mode!) */
1258	 }
1259      }
1260
1261      /* Now seek the detailed timing descriptions for custom panels */
1262      if(paneltype == Panel_Custom) {
1263
1264         SiS_Pr->CP_Supports64048075 = TRUE;
1265
1266         index += (numcodes * 4);
1267	 numcodes = buffer[0x7f] & 0x07;
1268	 for(i=0; i<numcodes; i++, index += 18) {
1269	    xres = buffer[index+2] | ((buffer[index+4] & 0xf0) << 4);
1270            yres = buffer[index+5] | ((buffer[index+7] & 0xf0) << 4);
1271
1272	    SiS_Pr->CP_HDisplay[i] = xres;
1273	    SiS_Pr->CP_HSyncStart[i] = xres + (buffer[index+8] | ((buffer[index+11] & 0xc0) << 2));
1274            SiS_Pr->CP_HSyncEnd[i] = SiS_Pr->CP_HSyncStart[i] + (buffer[index+9] | ((buffer[index+11] & 0x30) << 4));
1275	    SiS_Pr->CP_HTotal[i] = xres + (buffer[index+3] | ((buffer[index+4] & 0x0f) << 8));
1276	    SiS_Pr->CP_HBlankStart[i] = xres + 1;
1277	    SiS_Pr->CP_HBlankEnd[i] = SiS_Pr->CP_HTotal[i];
1278
1279	    SiS_Pr->CP_VDisplay[i] = yres;
1280            SiS_Pr->CP_VSyncStart[i] = yres + (((buffer[index+10] & 0xf0) >> 4) | ((buffer[index+11] & 0x0c) << 2));
1281            SiS_Pr->CP_VSyncEnd[i] = SiS_Pr->CP_VSyncStart[i] + ((buffer[index+10] & 0x0f) | ((buffer[index+11] & 0x03) << 4));
1282	    SiS_Pr->CP_VTotal[i] = yres + (buffer[index+6] | ((buffer[index+7] & 0x0f) << 8));
1283	    SiS_Pr->CP_VBlankStart[i] = yres + 1;
1284	    SiS_Pr->CP_VBlankEnd[i] = SiS_Pr->CP_VTotal[i];
1285
1286	    SiS_Pr->CP_Clock[i] = (buffer[index] | (buffer[index+1] << 8)) * 10;
1287
1288	    SiS_Pr->CP_DataValid[i] = TRUE;
1289
1290	    if((SiS_Pr->CP_HDisplay[i] & 7)						||
1291	       (SiS_Pr->CP_HDisplay[i] > SiS_Pr->CP_HSyncStart[i])  			||
1292	       (SiS_Pr->CP_HDisplay[i] >= SiS_Pr->CP_HSyncEnd[i])   			||
1293	       (SiS_Pr->CP_HDisplay[i] >= SiS_Pr->CP_HTotal[i])     			||
1294	       (SiS_Pr->CP_HSyncStart[i] >= SiS_Pr->CP_HSyncEnd[i]) 			||
1295	       (SiS_Pr->CP_HSyncStart[i] > SiS_Pr->CP_HTotal[i])    			||
1296	       (SiS_Pr->CP_HSyncEnd[i] > SiS_Pr->CP_HTotal[i])      			||
1297	       (SiS_Pr->CP_VDisplay[i] > SiS_Pr->CP_VSyncStart[i])  			||
1298	       (SiS_Pr->CP_VDisplay[i] >= SiS_Pr->CP_VSyncEnd[i])   			||
1299	       (SiS_Pr->CP_VDisplay[i] >= SiS_Pr->CP_VTotal[i])     			||
1300	       (SiS_Pr->CP_VSyncStart[i] > SiS_Pr->CP_VSyncEnd[i])  			||
1301	       (SiS_Pr->CP_VSyncStart[i] > SiS_Pr->CP_VTotal[i])    			||
1302	       (SiS_Pr->CP_VSyncEnd[i] > SiS_Pr->CP_VTotal[i])      			||
1303	       (((pSiS->VBFlags2 & VB2_30xC) && (SiS_Pr->CP_Clock[i] > 162500)) ||
1304	        ((!(pSiS->VBFlags2 & VB2_30xC))        &&
1305		 ( (SiS_Pr->CP_Clock[i] > 110500)  ||
1306		   (SiS_Pr->CP_VDisplay[i] > 1024) ||
1307		   (SiS_Pr->CP_HDisplay[i] > 1600) )))					||
1308	       (buffer[index + 17] & 0x80)) {
1309
1310	       SiS_Pr->CP_DataValid[i] = FALSE;
1311
1312	    } else {
1313
1314	       SiS_Pr->CP_HaveCustomData = TRUE;
1315
1316	       if(SiS_Pr->CP_Clock[i] > SiS_Pr->CP_MaxClock) SiS_Pr->CP_MaxClock = SiS_Pr->CP_Clock[i];
1317
1318	       if((SiS_Pr->CP_PreferredX == xres) && (SiS_Pr->CP_PreferredY == yres)) {
1319		  SiS_Pr->CP_PreferredIndex = i;
1320		  SiS_MakeClockRegs(pSiS->pScrn, SiS_Pr->CP_Clock[i], &SiS_Pr->CP_PrefSR2B, &SiS_Pr->CP_PrefSR2C);
1321		  SiS_Pr->CP_PrefClock = (SiS_Pr->CP_Clock[i] / 1000) + 1;
1322		  if(!havesync) {
1323		     cr37 |= ((((buffer[index + 17] & 0x06) ^ 0x06) << 5) | 0x20);
1324		     havesync = TRUE;
1325		  }
1326	       }
1327
1328	       SiS_Pr->CP_HSync_P[i] = (buffer[index + 17] & 0x02) ? TRUE : FALSE;
1329	       SiS_Pr->CP_VSync_P[i] = (buffer[index + 17] & 0x04) ? TRUE : FALSE;
1330	       SiS_Pr->CP_SyncValid[i] = TRUE;
1331
1332	    }
1333	 }
1334
1335	 cr37 |= 0x10;
1336
1337      }
1338
1339      break;
1340
1341   }
1342
1343   /* 1280x960 panels are always RGB24, unable to scale and use
1344    * high active sync polarity. (Check is save, other panel types
1345    * for other chipset series not being set up)
1346    */
1347   if(paneltype == panel1280x960) cr37 &= 0x0e;
1348
1349   for(i = 0; i < 7; i++) {
1350      if(SiS_Pr->CP_DataValid[i]) {
1351	 xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
1352	    "Non-standard LCD/DVI-D timing data no. %d:\n", i);
1353	 xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
1354	    "   HDisplay %d HSync %d HSyncEnd %d HTotal %d\n",
1355	    SiS_Pr->CP_HDisplay[i], SiS_Pr->CP_HSyncStart[i],
1356	    SiS_Pr->CP_HSyncEnd[i], SiS_Pr->CP_HTotal[i]);
1357	 xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
1358	    "   VDisplay %d VSync %d VSyncEnd %d VTotal %d\n",
1359	    SiS_Pr->CP_VDisplay[i], SiS_Pr->CP_VSyncStart[i],
1360	    SiS_Pr->CP_VSyncEnd[i], SiS_Pr->CP_VTotal[i]);
1361	 xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
1362	    "   Pixel clock: %3.3fMhz\n", (float)SiS_Pr->CP_Clock[i] / 1000);
1363	 xf86DrvMsg(pSiS->pScrn->scrnIndex, X_INFO,
1364	    "   To use this, add \"%dx%d\" to the Modes list in the Screen section\n",
1365	    SiS_Pr->CP_HDisplay[i],
1366	    SiS_Pr->CP_VDisplay[i]);
1367      }
1368   }
1369
1370   if(paneltype) {
1371       if(!SiS_Pr->CP_PreferredX) SiS_Pr->CP_PreferredX = SiS_Pr->CP_MaxX;
1372       if(!SiS_Pr->CP_PreferredY) SiS_Pr->CP_PreferredY = SiS_Pr->CP_MaxY;
1373       SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x32,0x08);
1374       SiS_SetReg(SiS_Pr->SiS_P3d4,0x36,paneltype);
1375       cr37 &= 0xf1;
1376       SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x37,0x0c,cr37);
1377       SiS_Pr->PanelSelfDetected = TRUE;
1378#ifdef TWDEBUG
1379       xf86DrvMsgVerb(pSiS->pScrn->scrnIndex, X_PROBED, 3,
1380	   "LCD sense: [DDC LCD results: 0x%02x, 0x%02x]\n", paneltype, cr37);
1381#endif
1382   } else {
1383       SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x32,~0x08);
1384       SiS_SetReg(SiS_Pr->SiS_P3d4,0x36,0x00);
1385   }
1386   return 0;
1387}
1388
1389unsigned short
1390SiS_SenseVGA2DDC(struct SiS_Private *SiS_Pr, SISPtr pSiS)
1391{
1392   unsigned short DDCdatatype, flag;
1393   BOOLEAN foundcrt = FALSE;
1394   int retry;
1395   unsigned char buffer[256];
1396
1397   if(!(pSiS->VBFlags2 & VB2_SISVGA2BRIDGE)) return 0;
1398
1399   /* Specific for XGI_40/Rev 2/A01 (XGI V3XT A01): This card has CRT1's
1400    * and CRT2's DDC ports physically connected to each other. There
1401    * is no connection to the video bridge's DDC port, both DDC
1402    * channels are routed to the GPU. Smart. If both CRT1 (CRT) and
1403    * CRT2 (VGA or LCD) are connected, DDC will fail. If a CRT is
1404    * connected to the DVI-I port, it will report "analog" as well,
1405    * so we never know if the monitor is connected to CRT1 or CRT2.
1406    * Hence, no reliable CRT detection here... we need to fall back to
1407    * the sensing stuff in sis_vb.c.
1408    */
1409   if(SiS_Pr->DDCPortMixup) return 0;
1410
1411   if(SiS_InitDDCRegs(SiS_Pr, pSiS->VBFlags, pSiS->VGAEngine, 2, 0, FALSE, pSiS->VBFlags2) == 0xFFFF)
1412      return 0;
1413
1414   SiS_Pr->SiS_DDC_SecAddr = 0x00;
1415
1416   /* Probe supported DA's */
1417   flag = SiS_ProbeDDC(SiS_Pr);
1418   if(flag & 0x10) {
1419      SiS_Pr->SiS_DDC_DeviceAddr = 0xa6;	/* EDID V2 (FP) */
1420      DDCdatatype = 4;
1421   } else if(flag & 0x08) {
1422      SiS_Pr->SiS_DDC_DeviceAddr = 0xa2;	/* EDID V2 (P&D-D Monitor) */
1423      DDCdatatype = 3;
1424   } else if(flag & 0x02) {
1425      SiS_Pr->SiS_DDC_DeviceAddr = 0xa0;	/* EDID V1 */
1426      DDCdatatype = 1;
1427   } else {
1428	xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
1429		"VGA2 sense: Do DDC answer\n");
1430	return 0;				/* no DDC support (or no device attached) */
1431   }
1432
1433   /* Read the entire EDID */
1434   retry = 2;
1435   do {
1436      if(SiS_ReadDDC(SiS_Pr, DDCdatatype, buffer)) {
1437	 xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED,
1438		"VGA2 sense: DDC read failed (attempt %d), %s\n",
1439		(3-retry), (retry == 1) ? "giving up" : "retrying");
1440	 retry--;
1441	 if(retry == 0) return 0xFFFF;
1442      } else break;
1443   } while(1);
1444
1445   /* Analyze EDID. We don't have many chances to
1446    * distinguish a flat panel from a CRT...
1447    */
1448   switch(DDCdatatype) {
1449
1450   case 1:
1451      if(!(checkedid1(buffer))) {
1452	  xf86DrvMsg(pSiS->pScrn->scrnIndex, X_ERROR,
1453		"VGA2 sense: EDID corrupt\n");
1454	  return 0;
1455      }
1456      if(buffer[0x14] & 0x80) {		/* Display uses digital input */
1457	  xf86DrvMsg(pSiS->pScrn->scrnIndex, X_ERROR,
1458		"VGA2 sense: Attached display expects digital input\n");
1459	  return 0;
1460      }
1461      SiS_Pr->CP_Vendor = buffer[9] | (buffer[8] << 8);
1462      SiS_Pr->CP_Product = buffer[10] | (buffer[11] << 8);
1463      foundcrt = TRUE;
1464
1465      /* Save given gamma */
1466      pSiS->CRT2VGAMonitorGamma = (buffer[0x17] + 100) * 10;
1467
1468      break;
1469
1470   case 3:
1471   case 4:
1472      if(!(checkedid2(buffer))) {
1473	  xf86DrvMsg(pSiS->pScrn->scrnIndex, X_ERROR,
1474		"VGA2 sense: EDID corrupt\n");
1475	  return 0;
1476      }
1477      if( ((buffer[0x41] & 0x0f) != 0x01) &&  	/* Display does not support analog input */
1478	  ((buffer[0x41] & 0x0f) != 0x02) &&
1479	  ((buffer[0x41] & 0xf0) != 0x10) &&
1480	  ((buffer[0x41] & 0xf0) != 0x20) ) {
1481	  xf86DrvMsg(pSiS->pScrn->scrnIndex, X_ERROR,
1482		"VGA2 sense: Attached display does not support analog input (0x%02x)\n",
1483		buffer[0x41]);
1484	  return 0;
1485      }
1486      SiS_Pr->CP_Vendor = buffer[2] | (buffer[1] << 8);
1487      SiS_Pr->CP_Product = buffer[3] | (buffer[4] << 8);
1488      foundcrt = TRUE;
1489
1490      /* Save given gamma */
1491      pSiS->CRT2VGAMonitorGamma = (buffer[0x56] + 100) * 10;
1492
1493      break;
1494   }
1495
1496   if(foundcrt) {
1497      SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x32,0x10);
1498   }
1499   return(0);
1500}
1501
1502/* 4-tap scaler for 301C and later */
1503
1504static float
1505rcos(float x)
1506{
1507   double pi = 3.14159265358979;
1508   float  r = 0.5, y;
1509
1510    if(x == 0.0) {
1511       y = 1.0;
1512    } else if(x == -1.0 || x == 1.0) {
1513       y = 0.0;
1514    } else {
1515       y = sin(pi * x) / (pi * x) * cos(r * pi * x) / (1 - x * x);
1516    }
1517
1518    return y;
1519}
1520
1521static int
1522roundandconv(float in)
1523{
1524    int a = ((int)(in)) * 10;
1525    int b = (int)(in * 10.0);
1526
1527    if (in >= 0) {
1528      if((b - a) < 5)  return (a / 10);
1529      else             return (a / 10) + 1;
1530    } else {
1531      if((b - a) > -5) return (a / 10);
1532      else             return (a / 10) -1;
1533    }
1534}
1535
1536void
1537SiS_CalcXTapScaler(struct SiS_Private *SiS_Pr, int srcsize, int destsize, int taps, Bool ishoriz)
1538{
1539   float scale = (float)srcsize / (float)destsize;
1540   int   coe_bit_number = 6;
1541   float fixnumber = (float)(1 << (coe_bit_number - 1));
1542   float ops, WW, W[8];
1543   int   WeightMat[16][8];
1544   int   i, j, index;
1545
1546   /* For now: */
1547   if(taps != 4) taps = 4;
1548
1549   if(scale < 1.0)      scale = 1.0;
1550   else if(scale > 1.0) scale *= 1.1;
1551
1552   for(i = 0; i < 16; i++) {
1553
1554      ops = (float)i / (16.0 * scale);
1555
1556      switch(taps) {
1557      case 4:
1558	 W[0] = rcos( 1.0 / scale + ops);
1559	 W[1] = rcos( 0.0 / scale + ops);
1560	 W[2] = rcos(-1.0 / scale + ops);
1561	 W[3] = rcos(-2.0 / scale + ops);
1562
1563	 WW = W[0] + W[1] + W[2] + W[3];
1564
1565	 WeightMat[i][0] = roundandconv(W[0] / WW * fixnumber);
1566	 WeightMat[i][1] = roundandconv(W[1] / WW * fixnumber);
1567	 WeightMat[i][2] = roundandconv(W[2] / WW * fixnumber);
1568	 WeightMat[i][3] = (int)fixnumber - WeightMat[i][0] - WeightMat[i][1] - WeightMat[i][2];
1569	 break;
1570#if 0 /* For future use */
1571     case 8:
1572	 W[0] = rcos( 3.0/scale + ops);
1573	 W[1] = rcos( 2.0/scale + ops);
1574	 W[2] = rcos( 1.0/scale + ops);
1575	 W[3] = rcos( 0.0/scale + ops);
1576	 W[4] = rcos(-1.0/scale + ops);
1577	 W[5] = rcos(-2.0/scale + ops);
1578	 W[6] = rcos(-3.0/scale + ops);
1579	 W[7] = rcos(-4.0/scale + ops);
1580
1581	 WW = W[0] + W[1] + W[2] + W[3] + W[4] + W[5] + W[6] + W[7];
1582
1583	 WeightMat[i][0] = roundandconv(W[0]/WW * fixnumber);
1584	 WeightMat[i][1] = roundandconv(W[1]/WW * fixnumber);
1585	 WeightMat[i][2] = roundandconv(W[2]/WW * fixnumber);
1586	 WeightMat[i][3] = roundandconv(W[3]/WW * fixnumber);
1587	 WeightMat[i][4] = roundandconv(W[4]/WW * fixnumber);
1588	 WeightMat[i][5] = roundandconv(W[5]/WW * fixnumber);
1589	 WeightMat[i][6] = roundandconv(W[6]/WW * fixnumber);
1590	 WeightMat[i][7] = (int)fixnumber - WeightMat[i][0] - WeightMat[i][1] -
1591					    WeightMat[i][2] - WeightMat[i][3] -
1592					    WeightMat[i][4] - WeightMat[i][5] - WeightMat[i][6];
1593	 break;
1594#endif
1595      }
1596   }
1597
1598   index = ishoriz ? 0x80 : 0xc0;
1599   for(i = 0; i < 16; i++) {
1600      for(j = 0; j < 4 /* taps! */; j++) {
1601         if(WeightMat[i][j] < 0) {
1602	    WeightMat[i][j] = ((~(-WeightMat[i][j])) + 1) & 0x7f;
1603         }
1604         SiS_SetReg(SiS_Pr->SiS_Part2Port, index++, WeightMat[i][j]);
1605      }
1606   }
1607
1608}
1609
1610void
1611SiS_SetGroup2_C_ELV(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex,
1612	      	    unsigned short RefreshRateTableIndex)
1613{
1614   unsigned char temp;
1615
1616   if(!(SiS_Pr->SiS_VBType & VB_SISTAP4SCALER)) return;
1617
1618   SiS_CalcXTapScaler(SiS_Pr, SiS_Pr->SiS_VGAHDE, SiS_Pr->SiS_HDE, 4, TRUE);
1619   if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
1620      SiS_CalcXTapScaler(SiS_Pr, SiS_Pr->SiS_VGAVDE, SiS_Pr->SiS_VDE, 4, FALSE);
1621   }
1622
1623   temp = 0x10;
1624   if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) temp |= 0x04;
1625   SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x4e,0xeb,temp);
1626}
1627
1628
1629