sis_driver.c revision e35772b2
1/*
2 * SiS driver main code
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 *	- driver entirely rewritten since 2001, only basic structure taken from
30 *	  old code (except sis_dri.c, sis_shadow.c, sis_accel.c and parts of
31 *	  sis_dga.c; these were mostly taken over; sis_dri.c was changed for
32 *	  new versions of the DRI layer)
33 *
34 * This notice covers the entire driver code unless indicated otherwise.
35 *
36 * Formerly based on code which was
37 * 	     Copyright (C) 1998, 1999 by Alan Hourihane, Wigan, England.
38 * 	     Written by:
39 *           Alan Hourihane <alanh@fairlite.demon.co.uk>,
40 *           Mike Chapman <mike@paranoia.com>,
41 *           Juanjo Santamarta <santamarta@ctv.es>,
42 *           Mitani Hiroshi <hmitani@drl.mei.co.jp>,
43 *           David Thomas <davtom@dream.org.uk>.
44 */
45
46#ifdef HAVE_CONFIG_H
47#include "config.h"
48#endif
49
50#include "sis.h"
51
52#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 6
53#include "xf86RAC.h"
54#endif
55#include "dixstruct.h"
56#include "shadowfb.h"
57#include "fb.h"
58#include "micmap.h"
59#include "mipointer.h"
60#include "mibstore.h"
61#include "edid.h"
62
63#define SIS_NEED_inSISREG
64#define SIS_NEED_inSISIDXREG
65#define SIS_NEED_outSISIDXREG
66#define SIS_NEED_orSISIDXREG
67#define SIS_NEED_andSISIDXREG
68#define SIS_NEED_setSISIDXREG
69#define SIS_NEED_outSISREG
70#define SIS_NEED_MYMMIO
71#define SIS_NEED_sisclearvram
72#include "sis_regs.h"
73#include "sis_dac.h"
74
75#include "sis_driver.h"
76
77#define _XF86DGA_SERVER_
78#include <X11/extensions/xf86dgastr.h>
79
80#include "globals.h"
81
82#ifdef HAVE_XEXTPROTO_71
83#include <X11/extensions/dpmsconst.h>
84#else
85#define DPMS_SERVER
86#include <X11/extensions/dpms.h>
87#endif
88
89
90#ifdef XF86DRI
91#include "dri.h"
92#endif
93
94/* Globals (yes, these ARE really required to be global) */
95
96#ifdef SISUSEDEVPORT
97int 		sisdevport = 0;
98#endif
99
100#ifdef SISDUALHEAD
101static int	SISEntityIndex = -1;
102#endif
103
104#ifdef SISMERGED
105#ifdef SISXINERAMA
106static Bool 		SiSnoPanoramiXExtension = TRUE;
107static int		SiSXineramaNumScreens = 0;
108static SiSXineramaData	*SiSXineramadataPtr = NULL;
109static int		SiSXineramaGeneration;
110
111static int SiSProcXineramaQueryVersion(ClientPtr client);
112static int SiSProcXineramaGetState(ClientPtr client);
113static int SiSProcXineramaGetScreenCount(ClientPtr client);
114static int SiSProcXineramaGetScreenSize(ClientPtr client);
115static int SiSProcXineramaIsActive(ClientPtr client);
116static int SiSProcXineramaQueryScreens(ClientPtr client);
117static int SiSSProcXineramaDispatch(ClientPtr client);
118#endif
119#endif
120
121/*
122 * This is intentionally screen-independent.  It indicates the binding
123 * choice made in the first PreInit.
124 */
125static int pix24bpp = 0;
126
127/*
128 * This contains the functions needed by the server after loading the driver
129 * module.  It must be supplied, and gets passed back by the SetupProc
130 * function in the dynamic case.  In the static case, a reference to this
131 * is compiled in, and this requires that the name of this DriverRec be
132 * an upper-case version of the driver name.
133 */
134
135#ifdef _X_EXPORT
136_X_EXPORT
137#endif
138DriverRec SIS = {
139    SIS_CURRENT_VERSION,
140    SIS_DRIVER_NAME,
141    SISIdentify,
142    SISProbe,
143    SISAvailableOptions,
144    NULL,
145    0
146#ifdef SIS_HAVE_DRIVER_FUNC
147     ,
148    SISDriverFunc
149#endif
150};
151
152static SymTabRec SISChipsets[] = {
153    { PCI_CHIP_SIS5597,     "SIS5597/5598" },
154    { PCI_CHIP_SIS530,      "SIS530/620" },
155    { PCI_CHIP_SIS6326,     "SIS6326/AGP/DVD" },
156    { PCI_CHIP_SIS300,      "SIS300/305" },
157    { PCI_CHIP_SIS630,      "SIS630/730" },
158    { PCI_CHIP_SIS540,      "SIS540" },
159    { PCI_CHIP_SIS315,      "SIS315" },
160    { PCI_CHIP_SIS315H,     "SIS315H" },
161    { PCI_CHIP_SIS315PRO,   "SIS315PRO/E" },
162    { PCI_CHIP_SIS550,	    "SIS550" },
163    { PCI_CHIP_SIS650,      "SIS650/M650/651/740" },
164    { PCI_CHIP_SIS330,      "SIS330(Xabre)" },
165    { PCI_CHIP_SIS660,      "SIS660/[M]661[F|M]X/[M]670/[M]741[GX]/[M]760[GX]/[M]761[GX]/[M]770[GX]" },
166    { PCI_CHIP_SIS340,      "SIS340" },
167    { -1,                   NULL }
168};
169
170static PciChipsets SISPciChipsets[] = {
171    { PCI_CHIP_SIS5597,     PCI_CHIP_SIS5597,   RES_SHARED_VGA },
172    { PCI_CHIP_SIS530,      PCI_CHIP_SIS530,    RES_SHARED_VGA },
173    { PCI_CHIP_SIS6326,     PCI_CHIP_SIS6326,   RES_SHARED_VGA },
174    { PCI_CHIP_SIS300,      PCI_CHIP_SIS300,    RES_SHARED_VGA },
175    { PCI_CHIP_SIS630,      PCI_CHIP_SIS630,    RES_SHARED_VGA },
176    { PCI_CHIP_SIS540,      PCI_CHIP_SIS540,    RES_SHARED_VGA },
177    { PCI_CHIP_SIS550,      PCI_CHIP_SIS550,    RES_SHARED_VGA },
178    { PCI_CHIP_SIS315,      PCI_CHIP_SIS315,    RES_SHARED_VGA },
179    { PCI_CHIP_SIS315H,     PCI_CHIP_SIS315H,   RES_SHARED_VGA },
180    { PCI_CHIP_SIS315PRO,   PCI_CHIP_SIS315PRO, RES_SHARED_VGA },
181    { PCI_CHIP_SIS650,      PCI_CHIP_SIS650,    RES_SHARED_VGA },
182    { PCI_CHIP_SIS330,      PCI_CHIP_SIS330,    RES_SHARED_VGA },
183    { PCI_CHIP_SIS660,      PCI_CHIP_SIS660,    RES_SHARED_VGA },
184    { PCI_CHIP_SIS340,      PCI_CHIP_SIS340,    RES_SHARED_VGA },
185    { -1,                   -1,                 RES_UNDEFINED }
186};
187
188static SymTabRec XGIChipsets[] = {
189    { PCI_CHIP_XGIXG20,     "Volari Z7 (XG20)" },
190    { PCI_CHIP_XGIXG40,     "Volari V3XT/V5/V8/Duo (XG40)" },
191    { -1,                   NULL }
192};
193
194static PciChipsets XGIPciChipsets[] = {
195    { PCI_CHIP_XGIXG20,     PCI_CHIP_XGIXG20,   RES_SHARED_VGA },
196    { PCI_CHIP_XGIXG40,     PCI_CHIP_XGIXG40,   RES_SHARED_VGA },
197    { -1,                   -1,                 RES_UNDEFINED }
198};
199
200#ifdef XFree86LOADER
201
202static MODULESETUPPROTO(sisSetup);
203
204static XF86ModuleVersionInfo sisVersRec =
205{
206    SIS_DRIVER_NAME,
207    MODULEVENDORSTRING,
208    MODINFOSTRING1,
209    MODINFOSTRING2,
210#ifdef XORG_VERSION_CURRENT
211    XORG_VERSION_CURRENT,
212#else
213    XF86_VERSION_CURRENT,
214#endif
215    SIS_MAJOR_VERSION, SIS_MINOR_VERSION, SIS_PATCHLEVEL,
216    ABI_CLASS_VIDEODRV,         /* This is a video driver */
217    ABI_VIDEODRV_VERSION,
218    MOD_CLASS_VIDEODRV,
219    {0,0,0,0}
220};
221
222#ifdef _X_EXPORT
223_X_EXPORT
224#endif
225XF86ModuleData sisModuleData = { &sisVersRec, sisSetup, NULL };
226
227pointer
228sisSetup(pointer module, pointer opts, int *errmaj, int *errmin)
229{
230    static Bool setupDone = FALSE;
231
232    if(!setupDone) {
233       setupDone = TRUE;
234       xf86AddDriver(&SIS, module, SIS_HaveDriverFuncs);
235       return (pointer)TRUE;
236    }
237
238    if(errmaj) *errmaj = LDR_ONCEONLY;
239    return NULL;
240}
241
242#endif /* XFree86LOADER */
243
244/* Mandatory */
245static void
246SISIdentify(int flags)
247{
248    xf86PrintChipsets(SIS_NAME, "driver for SiS chipsets", SISChipsets);
249    xf86PrintChipsets(SIS_NAME, "driver for XGI chipsets", XGIChipsets);
250}
251
252#ifdef SIS_HAVE_DRIVER_FUNC
253static Bool
254SISDriverFunc(ScrnInfoPtr pScrn, xorgDriverFuncOp op, pointer ptr)
255{
256    CARD32 *flag;
257
258    switch(op) {
259    case RR_GET_INFO:
260	break;
261    case RR_SET_CONFIG:
262	break;
263    case GET_REQUIRED_HW_INTERFACES:
264	break;
265    }
266    return TRUE;
267}
268#endif
269
270static Bool
271SISGetRec(ScrnInfoPtr pScrn)
272{
273    /* Allocate an SISRec, and hook it into pScrn->driverPrivate.
274     * pScrn->driverPrivate is initialised to NULL, so we can check if
275     * the allocation has already been done.
276     */
277    if(pScrn->driverPrivate != NULL) return TRUE;
278
279    pScrn->driverPrivate = xnfcalloc(sizeof(SISRec), 1);
280
281    /* Initialise it to 0 */
282    memset(pScrn->driverPrivate, 0, sizeof(SISRec));
283
284    return TRUE;
285}
286
287static void
288SISFreeRec(ScrnInfoPtr pScrn)
289{
290    SISPtr pSiS = SISPTR(pScrn);
291#ifdef SISDUALHEAD
292    SISEntPtr pSiSEnt = NULL;
293#endif
294
295    /* Just to make sure... */
296    if(!pSiS) return;
297
298#ifdef SISDUALHEAD
299    pSiSEnt = pSiS->entityPrivate;
300#endif
301
302    if(pSiS->pstate) xfree(pSiS->pstate);
303    pSiS->pstate = NULL;
304    if(pSiS->fonts) xfree(pSiS->fonts);
305    pSiS->fonts = NULL;
306
307#ifdef SISDUALHEAD
308    if(pSiSEnt) {
309       if(!pSiS->SecondHead) {
310	  /* Free memory only if we are first head; in case of an error
311	   * during init of the second head, the server will continue -
312	   * and we need the BIOS image and SiS_Private for the first
313	   * head.
314	   */
315	  if(pSiSEnt->BIOS) xfree(pSiSEnt->BIOS);
316	  pSiSEnt->BIOS = pSiS->BIOS = NULL;
317	  if(pSiSEnt->SiS_Pr) xfree(pSiSEnt->SiS_Pr);
318	  pSiSEnt->SiS_Pr = pSiS->SiS_Pr = NULL;
319	  if(pSiSEnt->RenderAccelArray) xfree(pSiSEnt->RenderAccelArray);
320	  pSiSEnt->RenderAccelArray = pSiS->RenderAccelArray = NULL;
321	  pSiSEnt->pScrn_1 = NULL;
322       } else {
323	  pSiS->BIOS = NULL;
324	  pSiS->SiS_Pr = NULL;
325	  pSiS->RenderAccelArray = NULL;
326	  pSiSEnt->pScrn_2 = NULL;
327       }
328    } else {
329#endif
330       if(pSiS->BIOS) xfree(pSiS->BIOS);
331       pSiS->BIOS = NULL;
332       if(pSiS->SiS_Pr) xfree(pSiS->SiS_Pr);
333       pSiS->SiS_Pr = NULL;
334       if(pSiS->RenderAccelArray) xfree(pSiS->RenderAccelArray);
335       pSiS->RenderAccelArray = NULL;
336#ifdef SISDUALHEAD
337    }
338#endif
339#ifdef SISMERGED
340    if(pSiS->CRT2HSync) xfree(pSiS->CRT2HSync);
341    pSiS->CRT2HSync = NULL;
342    if(pSiS->CRT2VRefresh) xfree(pSiS->CRT2VRefresh);
343    pSiS->CRT2VRefresh = NULL;
344    if(pSiS->MetaModes) xfree(pSiS->MetaModes);
345    pSiS->MetaModes = NULL;
346    if(pSiS->CRT2pScrn) {
347       if(pSiS->CRT2pScrn->modes) {
348	  while(pSiS->CRT2pScrn->modes)
349	     xf86DeleteMode(&pSiS->CRT2pScrn->modes, pSiS->CRT2pScrn->modes);
350       }
351       if(pSiS->CRT2pScrn->monitor) {
352	  if(pSiS->CRT2pScrn->monitor->Modes) {
353	     while(pSiS->CRT2pScrn->monitor->Modes)
354	        xf86DeleteMode(&pSiS->CRT2pScrn->monitor->Modes, pSiS->CRT2pScrn->monitor->Modes);
355	  }
356	  if(pSiS->CRT2pScrn->monitor->DDC) xfree(pSiS->CRT2pScrn->monitor->DDC);
357	  xfree(pSiS->CRT2pScrn->monitor);
358       }
359       xfree(pSiS->CRT2pScrn);
360       pSiS->CRT2pScrn = NULL;
361    }
362    if(pSiS->CRT1Modes) {
363       if(pSiS->CRT1Modes != pScrn->modes) {
364	  if(pScrn->modes) {
365	     pScrn->currentMode = pScrn->modes;
366	     do {
367	        DisplayModePtr p = pScrn->currentMode->next;
368	        if(pScrn->currentMode->Private)
369	 	  xfree(pScrn->currentMode->Private);
370	        xfree(pScrn->currentMode);
371	        pScrn->currentMode = p;
372	     } while(pScrn->currentMode != pScrn->modes);
373	  }
374	  pScrn->currentMode = pSiS->CRT1CurrentMode;
375	  pScrn->modes = pSiS->CRT1Modes;
376	  pSiS->CRT1CurrentMode = NULL;
377	  pSiS->CRT1Modes = NULL;
378       }
379    }
380#endif
381    while(pSiS->SISVESAModeList) {
382       sisModeInfoPtr mp = pSiS->SISVESAModeList->next;
383       xfree(pSiS->SISVESAModeList);
384       pSiS->SISVESAModeList = mp;
385    }
386    if(pSiS->pVbe) vbeFree(pSiS->pVbe);
387    pSiS->pVbe = NULL;
388
389#ifdef SISUSEDEVPORT
390    if(pSiS->sisdevportopen)   close(sisdevport);
391#endif
392
393    if(pScrn->driverPrivate == NULL)
394        return;
395    xfree(pScrn->driverPrivate);
396    pScrn->driverPrivate = NULL;
397}
398
399static void
400SISErrorLog(ScrnInfoPtr pScrn, const char *format, ...)
401{
402    va_list ap;
403    static const char *str = "**************************************************\n";
404
405    va_start(ap, format);
406    xf86DrvMsg(pScrn->scrnIndex, X_ERROR, str);
407    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
408	"                      ERROR:\n");
409    xf86VDrvMsgVerb(pScrn->scrnIndex, X_ERROR, 1, format, ap);
410    va_end(ap);
411    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
412	"                  END OF MESSAGE\n");
413    xf86DrvMsg(pScrn->scrnIndex, X_ERROR, str);
414}
415
416static void
417SiS_SiSFB_Lock(ScrnInfoPtr pScrn, Bool lock)
418{
419    SISPtr  pSiS = SISPTR(pScrn);
420    int     fd;
421    CARD32  parm;
422
423    if(!pSiS->sisfbfound) return;
424    if(!pSiS->sisfb_havelock) return;
425
426    if((fd = open(pSiS->sisfbdevname, O_RDONLY)) != -1) {
427       parm = lock ? 1 : 0;
428       ioctl(fd, SISFB_SET_LOCK, &parm);
429       close(fd);
430    }
431}
432
433/* Probe()
434 *
435 * Mandatory
436 */
437static Bool
438SISProbe(DriverPtr drv, int flags)
439{
440    int     i;
441    GDevPtr *devSections;
442    int     *usedChipsSiS, *usedChipsXGI;
443    int     numDevSections;
444    int     numUsed, numUsedSiS, numUsedXGI;
445    Bool    foundScreen = FALSE;
446
447    /*
448     * The aim here is to find all cards that this driver can handle,
449     * and for the ones not already claimed by another driver, claim the
450     * slot, and allocate a ScrnInfoRec.
451     *
452     * This should be a minimal probe, and it should under no circumstances
453     * change the state of the hardware.  Because a device is found, don't
454     * assume that it will be used.  Don't do any initialisations other than
455     * the required ScrnInfoRec initialisations.  Don't allocate any new
456     * data structures.
457     *
458     */
459
460    /*
461     * Next we check, if there has been a chipset override in the config file.
462     * For this we must find out if there is an active device section which
463     * is relevant, i.e., which has no driver specified or has THIS driver
464     * specified.
465     */
466
467    if((numDevSections = xf86MatchDevice(SIS_DRIVER_NAME, &devSections)) <= 0) {
468       /*
469        * There's no matching device section in the config file, so quit
470        * now.
471        */
472       return FALSE;
473    }
474
475    /*
476     * We need to probe the hardware first.  We then need to see how this
477     * fits in with what is given in the config file, and allow the config
478     * file info to override any contradictions.
479     */
480
481    /*
482     * All of the cards this driver supports are PCI, so the "probing" just
483     * amounts to checking the PCI data that the server has already collected.
484     */
485#ifndef XSERVER_LIBPCIACCESS
486    if(xf86GetPciVideoInfo() == NULL) {
487       /*
488        * We won't let anything in the config file override finding no
489        * PCI video cards at all.
490        */
491       return FALSE;
492    }
493#endif
494
495    numUsedSiS = xf86MatchPciInstances(SIS_NAME, PCI_VENDOR_SIS,
496			SISChipsets, SISPciChipsets, devSections,
497			numDevSections, drv, &usedChipsSiS);
498
499    numUsedXGI = xf86MatchPciInstances(SIS_NAME, PCI_VENDOR_XGI,
500			XGIChipsets, XGIPciChipsets, devSections,
501			numDevSections, drv, &usedChipsXGI);
502
503    /* Free it since we don't need that list after this */
504    xfree(devSections);
505
506    numUsed = numUsedSiS + numUsedXGI;
507
508    if(numUsed <= 0)
509       return FALSE;
510
511    if(flags & PROBE_DETECT) {
512
513	foundScreen = TRUE;
514
515    } else for(i = 0; i < numUsed; i++) {
516
517	ScrnInfoPtr pScrn;
518#ifdef SISDUALHEAD
519	EntityInfoPtr pEnt;
520#endif
521
522	/* Allocate a ScrnInfoRec and claim the slot */
523	pScrn = NULL;
524
525	if((pScrn = xf86ConfigPciEntity(pScrn, 0,
526			(i < numUsedSiS) ? usedChipsSiS[i] : usedChipsXGI[i-numUsedSiS],
527			(i < numUsedSiS) ? SISPciChipsets  : XGIPciChipsets,
528			NULL, NULL, NULL, NULL, NULL))) {
529	    /* Fill in what we can of the ScrnInfoRec */
530	    pScrn->driverVersion    = SIS_CURRENT_VERSION;
531	    pScrn->driverName       = SIS_DRIVER_NAME;
532	    pScrn->name             = SIS_NAME;
533	    pScrn->Probe            = SISProbe;
534	    pScrn->PreInit          = SISPreInit;
535	    pScrn->ScreenInit       = SISScreenInit;
536	    pScrn->SwitchMode       = SISSwitchMode;
537	    pScrn->AdjustFrame      = SISAdjustFrame;
538	    pScrn->EnterVT          = SISEnterVT;
539	    pScrn->LeaveVT          = SISLeaveVT;
540	    pScrn->FreeScreen       = SISFreeScreen;
541	    pScrn->ValidMode        = SISValidMode;
542
543	    foundScreen = TRUE;
544	}
545
546#ifdef SISDUALHEAD
547	pEnt = xf86GetEntityInfo((i < numUsedSiS) ? usedChipsSiS[i] : usedChipsXGI[i-numUsedSiS]);
548
549	if(pEnt->chipset == PCI_CHIP_SIS630 || pEnt->chipset == PCI_CHIP_SIS540 ||
550	   pEnt->chipset == PCI_CHIP_SIS650 || pEnt->chipset == PCI_CHIP_SIS550 ||
551	   pEnt->chipset == PCI_CHIP_SIS315 || pEnt->chipset == PCI_CHIP_SIS315H ||
552	   pEnt->chipset == PCI_CHIP_SIS315PRO || pEnt->chipset == PCI_CHIP_SIS330 ||
553	   pEnt->chipset == PCI_CHIP_SIS300 || pEnt->chipset == PCI_CHIP_SIS660 ||
554	   pEnt->chipset == PCI_CHIP_SIS340 || pEnt->chipset == PCI_CHIP_XGIXG40) {
555
556	    SISEntPtr pSiSEnt = NULL;
557	    DevUnion  *pPriv;
558
559	    xf86SetEntitySharable((i < numUsedSiS) ? usedChipsSiS[i] : usedChipsXGI[i-numUsedSiS]);
560	    if(SISEntityIndex < 0) {
561	       SISEntityIndex = xf86AllocateEntityPrivateIndex();
562	    }
563	    pPriv = xf86GetEntityPrivate(pScrn->entityList[0], SISEntityIndex);
564	    if(!pPriv->ptr) {
565	       pPriv->ptr = xnfcalloc(sizeof(SISEntRec), 1);
566	       pSiSEnt = pPriv->ptr;
567	       memset(pSiSEnt, 0, sizeof(SISEntRec));
568	       pSiSEnt->lastInstance = -1;
569	    } else {
570	       pSiSEnt = pPriv->ptr;
571	    }
572	    pSiSEnt->lastInstance++;
573	    xf86SetEntityInstanceForScreen(pScrn, pScrn->entityList[0],
574	                                   pSiSEnt->lastInstance);
575	}
576#endif /* DUALHEAD */
577
578    }
579
580    if(usedChipsSiS) xfree(usedChipsSiS);
581    if(usedChipsXGI) xfree(usedChipsXGI);
582
583    return foundScreen;
584}
585
586/* Various helpers */
587
588static unsigned short
589calcgammaval(int j, int nramp, float invgamma, float bri, float c)
590{
591    float k = (float)j;
592    float nrm1 = (float)(nramp - 1);
593    float con = c * nrm1 / 3.0;
594    float l, v;
595
596    if(con != 0.0) {
597       l = nrm1 / 2.0;
598       if(con <= 0.0) {
599          k -= l;
600          k *= (l + con) / l;
601       } else {
602          l -= 1.0;
603          k -= l;
604          k *= l / (l - con);
605       }
606       k += l;
607       if(k < 0.0) k = 0.0;
608    }
609
610    if(invgamma == 1.0) {
611       v = k / nrm1 * 65535.0;
612    } else {
613       v = pow(k / nrm1, invgamma) * 65535.0 + 0.5;
614    }
615
616    v += (bri * (65535.0 / 3.0)) ;
617
618    if(v < 0.0) v = 0.0;
619    else if(v > 65535.0) v = 65535.0;
620
621    return (unsigned short)v;
622}
623
624#ifdef SISGAMMARAMP
625void
626SISCalculateGammaRamp(ScreenPtr pScreen, ScrnInfoPtr pScrn)
627{
628   SISPtr pSiS = SISPTR(pScrn);
629   int    i, j, nramp;
630   UShort *ramp[3];
631   float  gamma_max[3], framp;
632   Bool   newmethod = FALSE;
633
634   if(!(pSiS->SiS_SD3_Flags & SiS_SD3_OLDGAMMAINUSE)) {
635      newmethod = TRUE;
636   } else {
637      gamma_max[0] = (float)pSiS->GammaBriR / 1000;
638      gamma_max[1] = (float)pSiS->GammaBriG / 1000;
639      gamma_max[2] = (float)pSiS->GammaBriB / 1000;
640   }
641
642   if(!(nramp = xf86GetGammaRampSize(pScreen))) return;
643
644   for(i=0; i<3; i++) {
645      ramp[i] = (UShort *)xalloc(nramp * sizeof(UShort));
646      if(!ramp[i]) {
647	 if(ramp[0]) { xfree(ramp[0]); ramp[0] = NULL; }
648	 if(ramp[1]) { xfree(ramp[1]); ramp[1] = NULL; }
649	 return;
650      }
651   }
652
653   if(newmethod) {
654
655      for(i = 0; i < 3; i++) {
656
657         float invgamma = 0.0, bri = 0.0, con = 0.0;
658
659         switch(i) {
660         case 0: invgamma = 1. / pScrn->gamma.red;
661		 bri = pSiS->NewGammaBriR;
662		 con = pSiS->NewGammaConR;
663		 break;
664         case 1: invgamma = 1. / pScrn->gamma.green;
665		 bri = pSiS->NewGammaBriG;
666		 con = pSiS->NewGammaConG;
667		 break;
668         case 2: invgamma = 1. / pScrn->gamma.blue;
669		 bri = pSiS->NewGammaBriB;
670                 con = pSiS->NewGammaConB;
671		 break;
672         }
673
674	 for(j = 0; j < nramp; j++) {
675	    ramp[i][j] = calcgammaval(j, nramp, invgamma, bri, con);
676	 }
677
678      }
679
680   } else {
681
682      for(i = 0; i < 3; i++) {
683         int fullscale = 65535 * gamma_max[i];
684         float dramp = 1. / (nramp - 1);
685         float invgamma = 0.0, v;
686
687         switch(i) {
688         case 0: invgamma = 1. / pScrn->gamma.red; break;
689         case 1: invgamma = 1. / pScrn->gamma.green; break;
690         case 2: invgamma = 1. / pScrn->gamma.blue; break;
691         }
692
693         for(j = 0; j < nramp; j++) {
694	    framp = pow(j * dramp, invgamma);
695
696	    v = (fullscale < 0) ? (65535 + fullscale * framp) :
697			       fullscale * framp;
698	    if(v < 0) v = 0;
699	    else if(v > 65535) v = 65535;
700	    ramp[i][j] = (UShort)v;
701         }
702      }
703
704   }
705
706   xf86ChangeGammaRamp(pScreen, nramp, ramp[0], ramp[1], ramp[2]);
707
708   xfree(ramp[0]);
709   xfree(ramp[1]);
710   xfree(ramp[2]);
711   ramp[0] = ramp[1] = ramp[2] = NULL;
712}
713#endif
714
715void
716SISCalculateGammaRampCRT2(ScrnInfoPtr pScrn)
717{
718   SISPtr pSiS = SISPTR(pScrn);
719   int    i;
720   int    myshift = 16 - pScrn->rgbBits;
721   int    maxvalue = (1 << pScrn->rgbBits) - 1;
722   int    reds = pScrn->mask.red >> pScrn->offset.red;
723   int    greens = pScrn->mask.green >> pScrn->offset.green;
724   int    blues = pScrn->mask.blue >> pScrn->offset.blue;
725   float  framp, invgamma1, invgamma2, invgamma3, v;
726
727   invgamma1  = 1. / pSiS->GammaR2;
728   invgamma2  = 1. / pSiS->GammaG2;
729   invgamma3  = 1. / pSiS->GammaB2;
730
731   if(!(pSiS->SiS_SD3_Flags & SiS_SD3_OLDGAMMAINUSE)) {
732
733      for(i = 0; i < pSiS->CRT2ColNum; i++) {
734         pSiS->crt2gcolortable[i].red = calcgammaval(i, pSiS->CRT2ColNum, invgamma1,
735			pSiS->NewGammaBriR2, pSiS->NewGammaConR2) >> myshift;
736         pSiS->crt2gcolortable[i].green = calcgammaval(i, pSiS->CRT2ColNum, invgamma2,
737			pSiS->NewGammaBriG2, pSiS->NewGammaConG2) >> myshift;
738         pSiS->crt2gcolortable[i].blue = calcgammaval(i, pSiS->CRT2ColNum, invgamma3,
739			pSiS->NewGammaBriB2, pSiS->NewGammaConB2) >> myshift;
740      }
741
742   } else {
743
744      int fullscale1 = 65536 * (float)pSiS->GammaBriR2 / 1000;
745      int fullscale2 = 65536 * (float)pSiS->GammaBriG2 / 1000;
746      int fullscale3 = 65536 * (float)pSiS->GammaBriB2 / 1000;
747
748      float dramp = 1. / (pSiS->CRT2ColNum - 1);
749
750      for(i = 0; i < pSiS->CRT2ColNum; i++) {
751         framp = pow(i * dramp, invgamma1);
752         v = (fullscale1 < 0) ? (65535 + fullscale1 * framp) : fullscale1 * framp;
753         if(v < 0) v = 0;
754         else if(v > 65535) v = 65535;
755         pSiS->crt2gcolortable[i].red = ((UShort)v) >> myshift;
756         framp = pow(i * dramp, invgamma2);
757         v = (fullscale2 < 0) ? (65535 + fullscale2 * framp) : fullscale2 * framp;
758         if(v < 0) v = 0;
759         else if(v > 65535) v = 65535;
760         pSiS->crt2gcolortable[i].green = ((UShort)v) >> myshift;
761         framp = pow(i * dramp, invgamma3);
762         v = (fullscale3 < 0) ? (65535 + fullscale3 * framp) : fullscale3 * framp;
763         if(v < 0) v = 0;
764         else if(v > 65535) v = 65535;
765         pSiS->crt2gcolortable[i].blue = ((UShort)v) >> myshift;
766      }
767
768   }
769
770   for(i = 0; i < pSiS->CRT2ColNum; i++) {
771      pSiS->crt2colors[i].red =
772         pSiS->crt2gcolortable[i * maxvalue / reds].red;
773      pSiS->crt2colors[i].green =
774         pSiS->crt2gcolortable[i * maxvalue / greens].green;
775      pSiS->crt2colors[i].blue  =
776         pSiS->crt2gcolortable[i * maxvalue / blues].blue;
777   }
778}
779
780/* If monitor section has no HSync/VRefresh data,
781 * derive it from DDC data.
782 */
783static void
784SiSSetSyncRangeFromEdid(ScrnInfoPtr pScrn, int flag)
785{
786   MonPtr      mon = pScrn->monitor;
787   xf86MonPtr  ddc = mon->DDC;
788   float       myhhigh = 0.0, myhlow = 0.0, htest;
789   int         myvhigh = 0, myvlow = 0, vtest, i;
790   UChar temp;
791   const myhddctiming myhtiming[12] = {
792       { 1, 0x20, 31.6 }, /* rounded up by .1 */
793       { 1, 0x80, 31.6 },
794       { 1, 0x02, 35.3 },
795       { 1, 0x04, 37.6 },
796       { 1, 0x08, 38.0 },
797       { 1, 0x01, 38.0 },
798       { 2, 0x40, 47.0 },
799       { 2, 0x80, 48.2 },
800       { 2, 0x08, 48.5 },
801       { 2, 0x04, 56.6 },
802       { 2, 0x02, 60.1 },
803       { 2, 0x01, 80.1 }
804   };
805   const myvddctiming myvtiming[11] = {
806       { 1, 0x02, 56 },
807       { 1, 0x01, 60 },
808       { 2, 0x08, 60 },
809       { 2, 0x04, 70 },
810       { 1, 0x80, 71 },
811       { 1, 0x08, 72 },
812       { 2, 0x80, 72 },
813       { 1, 0x04, 75 },
814       { 2, 0x40, 75 },
815       { 2, 0x02, 75 },
816       { 2, 0x01, 75 }
817   };
818
819   if(flag) { /* HSync */
820
821      for(i = 0; i < 4; i++) {
822	 if(ddc->det_mon[i].type == DS_RANGES) {
823	    mon->nHsync = 1;
824	    mon->hsync[0].lo = ddc->det_mon[i].section.ranges.min_h;
825	    mon->hsync[0].hi = ddc->det_mon[i].section.ranges.max_h;
826	    if(mon->hsync[0].lo > 32.0 || mon->hsync[0].hi < 31.0) {
827	       if(ddc->timings1.t1 & 0x80) {
828		  mon->nHsync++;
829		  mon->hsync[1].lo = 31.0;
830		  mon->hsync[1].hi = 32.0;
831	       }
832	    }
833	    return;
834	 }
835      }
836
837      /* If no sync ranges detected in detailed timing table, we
838       * derive them from supported VESA modes.
839       */
840
841      for(i = 0; i < 12; i++) {
842	 if(myhtiming[i].whichone == 1) temp = ddc->timings1.t1;
843	 else                           temp = ddc->timings1.t2;
844	 if(temp & myhtiming[i].mask) {
845	    if((i == 0) || (myhlow > myhtiming[i].rate))
846	       myhlow = myhtiming[i].rate;
847	 }
848	 if(myhtiming[11-i].whichone == 1) temp = ddc->timings1.t1;
849	 else                              temp = ddc->timings1.t2;
850	 if(temp & myhtiming[11-i].mask) {
851	    if((i == 0) || (myhhigh < myhtiming[11-i].rate))
852	       myhhigh = myhtiming[11-i].rate;
853	 }
854      }
855
856      for(i = 0; i < STD_TIMINGS; i++) {
857	 if(ddc->timings2[i].hsize > 256) {
858	    htest = ddc->timings2[i].refresh * 1.05 * ddc->timings2[i].vsize / 1000.0;
859	    if(htest < myhlow)  myhlow  = htest;
860	    if(htest > myhhigh) myhhigh = htest;
861	 }
862      }
863
864      if((myhhigh > 0.0) && (myhlow > 0.0)) {
865	 mon->nHsync = 1;
866	 mon->hsync[0].lo = myhlow - 0.1;
867	 mon->hsync[0].hi = myhhigh;
868      }
869
870
871   } else {  /* Vrefresh */
872
873      for(i = 0; i < 4; i++) {
874         if(ddc->det_mon[i].type == DS_RANGES) {
875	    mon->nVrefresh = 1;
876	    mon->vrefresh[0].lo = ddc->det_mon[i].section.ranges.min_v;
877	    mon->vrefresh[0].hi = ddc->det_mon[i].section.ranges.max_v;
878	    if(mon->vrefresh[0].lo > 72 || mon->vrefresh[0].hi < 70) {
879	       if(ddc->timings1.t1 & 0x80) {
880		  mon->nVrefresh++;
881		  mon->vrefresh[1].lo = 71;
882		  mon->vrefresh[1].hi = 71;
883	       }
884	    }
885	    return;
886         }
887      }
888
889      for(i = 0; i < 11; i++) {
890	 if(myvtiming[i].whichone == 1) temp = ddc->timings1.t1;
891	 else                           temp = ddc->timings1.t2;
892	 if(temp & myvtiming[i].mask) {
893	    if((i == 0) || (myvlow > myvtiming[i].rate))
894	       myvlow = myvtiming[i].rate;
895	 }
896	 if(myvtiming[10-i].whichone == 1) temp = ddc->timings1.t1;
897	 else                              temp = ddc->timings1.t2;
898	 if(temp & myvtiming[10-i].mask) {
899	    if((i == 0) || (myvhigh < myvtiming[10-i].rate))
900	       myvhigh = myvtiming[10-i].rate;
901	 }
902      }
903
904      for(i = 0; i < STD_TIMINGS; i++) {
905	 if(ddc->timings2[i].hsize > 256) {
906	    vtest = ddc->timings2[i].refresh;
907	    if(vtest < myvlow)  myvlow  = vtest;
908	    if(vtest > myvhigh) myvhigh = vtest;
909	 }
910      }
911
912      if((myvhigh > 0) && (myvlow > 0)) {
913	 mon->nVrefresh = 1;
914	 mon->vrefresh[0].lo = myvlow;
915	 mon->vrefresh[0].hi = myvhigh;
916      }
917
918   }
919}
920
921static Bool
922SiSAllowSyncOverride(SISPtr pSiS, Bool fromDDC)
923{
924   if(!(pSiS->VBFlags2 & VB2_VIDEOBRIDGE)) return FALSE;
925
926#ifdef SISDUALHEAD
927   if(pSiS->DualHeadMode) {
928      if(pSiS->SecondHead) {
929         if((pSiS->VBFlags & CRT1_LCDA) && (!fromDDC)) return TRUE;
930      } else {
931         if((pSiS->VBFlags & CRT2_TV) ||
932	    ((pSiS->VBFlags & CRT2_LCD) && (!fromDDC))) return TRUE;
933      }
934      return FALSE;
935   }
936#endif
937
938#ifdef SISMERGED
939   if(pSiS->MergedFB) {
940      if((pSiS->VBFlags & CRT1_LCDA) && (!fromDDC)) return TRUE;
941      return FALSE;
942   }
943#endif
944
945   if(!(pSiS->VBFlags & DISPTYPE_CRT1)) {
946      if( (pSiS->VBFlags & CRT2_TV) ||
947	  ((pSiS->VBFlags & CRT2_LCD) && (!fromDDC)) ) return TRUE;
948   } else if((pSiS->VBFlags & CRT1_LCDA) && (!fromDDC)) return TRUE;
949
950   return FALSE;
951}
952
953static Bool
954SiSCheckForH(float hsync, MonPtr monitor)
955{
956   int i;
957   for(i = 0; i < monitor->nHsync; i++) {
958      if((hsync > monitor->hsync[i].lo * (1.0 - SYNC_TOLERANCE)) &&
959	 (hsync < monitor->hsync[i].hi * (1.0 + SYNC_TOLERANCE)))
960	 break;
961   }
962   if(i == monitor->nHsync) return FALSE;
963   return TRUE;
964}
965
966static Bool
967SiSCheckForV(float vrefresh, MonPtr monitor)
968{
969   int i;
970   for(i = 0; i < monitor->nVrefresh; i++) {
971      if((vrefresh > monitor->vrefresh[i].lo * (1.0 - SYNC_TOLERANCE)) &&
972	 (vrefresh < monitor->vrefresh[i].hi * (1.0 + SYNC_TOLERANCE)))
973	 break;
974   }
975   if(i == monitor->nVrefresh) return FALSE;
976   return TRUE;
977}
978
979static Bool
980CheckAndOverruleH(ScrnInfoPtr pScrn, MonPtr monitor)
981{
982   DisplayModePtr mode = monitor->Modes;
983   float mymin = 30.0, mymax = 80.0, hsync;
984   Bool doit = FALSE;
985
986   for(hsync = mymin; hsync <= mymax; hsync += .5) {
987      if(!SiSCheckForH(hsync, monitor)) doit = TRUE;
988   }
989
990   if(mode) {
991      do {
992         if(mode->type & M_T_BUILTIN) {
993	    hsync = (float)mode->Clock / (float)mode->HTotal;
994	    if(!SiSCheckForH(hsync, monitor)) {
995	       doit = TRUE;
996	       if(hsync < mymin) mymin = hsync;
997	       if(hsync > mymax) mymax = hsync;
998	    }
999	 }
1000      } while((mode = mode->next));
1001   }
1002
1003   if(doit) {
1004      monitor->nHsync = 1;
1005      monitor->hsync[0].lo = mymin;
1006      monitor->hsync[0].hi = mymax;
1007      return TRUE;
1008   }
1009
1010   return FALSE;
1011}
1012
1013static Bool
1014CheckAndOverruleV(ScrnInfoPtr pScrn, MonPtr monitor)
1015{
1016   DisplayModePtr mode = monitor->Modes;
1017   float mymin = 59.0, mymax = 61.0, vrefresh;
1018   Bool doit = FALSE, ret = FALSE;
1019
1020   for(vrefresh = mymin; vrefresh <= mymax; vrefresh += 1.0) {
1021      if(!SiSCheckForV(vrefresh, monitor)) doit = TRUE;
1022   }
1023
1024   if(mode) {
1025      do {
1026         if(mode->type & M_T_BUILTIN) {
1027	    vrefresh = mode->Clock * 1000.0 / (mode->HTotal * mode->VTotal);
1028	    if(mode->Flags & V_INTERLACE) vrefresh *= 2.0;
1029	    if(mode->Flags & V_DBLSCAN) vrefresh /= 2.0;
1030	    if(!SiSCheckForH(vrefresh, monitor)) {
1031	       doit = TRUE;
1032	       if(vrefresh < mymin) mymin = vrefresh;
1033	       if(vrefresh > mymax) mymax = vrefresh;
1034	    }
1035	 }
1036      } while((mode = mode->next));
1037   }
1038
1039   if(doit) {
1040      monitor->nVrefresh = 1;
1041      monitor->vrefresh[0].lo = mymin;
1042      monitor->vrefresh[0].hi = mymax;
1043      ret = TRUE;
1044   }
1045
1046   /* special for 640x400/320x200/@70Hz (VGA/IBM 720x480) */
1047   if( (!SiSCheckForV(71, monitor)) &&
1048       (monitor->nVrefresh < MAX_VREFRESH) ) {
1049      monitor->vrefresh[monitor->nVrefresh].lo = 71;
1050      monitor->vrefresh[monitor->nVrefresh].hi = 71;
1051      monitor->nVrefresh++;
1052      ret = TRUE;
1053   }
1054   return ret;
1055}
1056
1057/* Some helper functions for MergedFB mode */
1058
1059#ifdef SISMERGED
1060
1061/* Helper function for CRT2 monitor vrefresh/hsync options
1062 * (Code base from mga driver)
1063 */
1064static int
1065SiSStrToRanges(range *r, char *s, int max)
1066{
1067   float num = 0.0;
1068   int rangenum = 0;
1069   Bool gotdash = FALSE;
1070   Bool nextdash = FALSE;
1071   char *strnum = NULL;
1072   do {
1073      switch(*s) {
1074      case '0':
1075      case '1':
1076      case '2':
1077      case '3':
1078      case '4':
1079      case '5':
1080      case '6':
1081      case '7':
1082      case '8':
1083      case '9':
1084      case '.':
1085         if(strnum == NULL) {
1086            strnum = s;
1087            gotdash = nextdash;
1088            nextdash = FALSE;
1089         }
1090         break;
1091      case '-':
1092      case ' ':
1093      case 0:
1094         if(strnum == NULL) break;
1095         sscanf(strnum, "%f", &num);
1096	 strnum = NULL;
1097         if(gotdash) {
1098            r[rangenum - 1].hi = num;
1099         } else {
1100            r[rangenum].lo = num;
1101            r[rangenum].hi = num;
1102            rangenum++;
1103         }
1104         if(*s == '-') nextdash = (rangenum != 0);
1105	 else if(rangenum >= max) return rangenum;
1106         break;
1107      default:
1108         return 0;
1109      }
1110
1111   } while(*(s++) != 0);
1112
1113   return rangenum;
1114}
1115
1116/* Copy and link two modes (i, j) for mergedfb mode
1117 * (Code base taken from mga driver)
1118 *
1119 * - Copy mode i, merge j to copy of i, link the result to dest
1120 * - Link i and j in private record.
1121 * - If dest is NULL, return value is copy of i linked to itself.
1122 * - For mergedfb auto-config, we only check the dimension
1123 *   against virtualX/Y, if they were user-provided.
1124 * - No special treatment required for CRTxxOffs.
1125 * - Provide fake dotclock in order to distinguish between similar
1126 *   looking MetaModes (for RandR and VidMode extensions)
1127 * - Set unique VRefresh of dest mode for RandR
1128 */
1129static DisplayModePtr
1130SiSCopyModeNLink(ScrnInfoPtr pScrn, DisplayModePtr dest,
1131                 DisplayModePtr i, DisplayModePtr j,
1132		 SiSScrn2Rel srel)
1133{
1134    SISPtr pSiS = SISPTR(pScrn);
1135    DisplayModePtr mode;
1136    int dx = 0,dy = 0;
1137
1138    if(!((mode = xalloc(sizeof(DisplayModeRec))))) return dest;
1139    memcpy(mode, i, sizeof(DisplayModeRec));
1140    if(!((mode->Private = xalloc(sizeof(SiSMergedDisplayModeRec))))) {
1141       xfree(mode);
1142       return dest;
1143    }
1144    ((SiSMergedDisplayModePtr)mode->Private)->CRT1 = i;
1145    ((SiSMergedDisplayModePtr)mode->Private)->CRT2 = j;
1146    ((SiSMergedDisplayModePtr)mode->Private)->CRT2Position = srel;
1147    mode->PrivSize = 0;
1148
1149    switch(srel) {
1150    case sisLeftOf:
1151    case sisRightOf:
1152       if(!(pScrn->display->virtualX)) {
1153          dx = i->HDisplay + j->HDisplay;
1154       } else {
1155          dx = min(pScrn->virtualX, i->HDisplay + j->HDisplay);
1156       }
1157       dx -= mode->HDisplay;
1158       if(!(pScrn->display->virtualY)) {
1159          dy = max(i->VDisplay, j->VDisplay);
1160       } else {
1161          dy = min(pScrn->virtualY, max(i->VDisplay, j->VDisplay));
1162       }
1163       dy -= mode->VDisplay;
1164       break;
1165    case sisAbove:
1166    case sisBelow:
1167       if(!(pScrn->display->virtualY)) {
1168          dy = i->VDisplay + j->VDisplay;
1169       } else {
1170          dy = min(pScrn->virtualY, i->VDisplay + j->VDisplay);
1171       }
1172       dy -= mode->VDisplay;
1173       if(!(pScrn->display->virtualX)) {
1174          dx = max(i->HDisplay, j->HDisplay);
1175       } else {
1176          dx = min(pScrn->virtualX, max(i->HDisplay, j->HDisplay));
1177       }
1178       dx -= mode->HDisplay;
1179       break;
1180    case sisClone:
1181       if(!(pScrn->display->virtualX)) {
1182          dx = max(i->HDisplay, j->HDisplay);
1183       } else {
1184          dx = min(pScrn->virtualX, max(i->HDisplay, j->HDisplay));
1185       }
1186       dx -= mode->HDisplay;
1187       if(!(pScrn->display->virtualY)) {
1188          dy = max(i->VDisplay, j->VDisplay);
1189       } else {
1190	  dy = min(pScrn->virtualY, max(i->VDisplay, j->VDisplay));
1191       }
1192       dy -= mode->VDisplay;
1193       break;
1194    }
1195    mode->HDisplay += dx;
1196    mode->HSyncStart += dx;
1197    mode->HSyncEnd += dx;
1198    mode->HTotal += dx;
1199    mode->VDisplay += dy;
1200    mode->VSyncStart += dy;
1201    mode->VSyncEnd += dy;
1202    mode->VTotal += dy;
1203
1204    mode->type = M_T_DEFAULT;
1205#if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4,2,99,2,0)
1206    /* Set up as user defined (ie fake that the mode has been named in the
1207     * Modes-list in the screen section; corrects cycling with CTRL-ALT-[-+]
1208     * when source mode has not been listed there.)
1209     */
1210    mode->type |= M_T_USERDEF;
1211#endif
1212
1213    /* Set the VRefresh field (in order to make RandR use it for the rates). We
1214     * simply set this to the refresh rate for the CRT1 mode (since CRT2 will
1215     * mostly be LCD or TV anyway).
1216     */
1217    mode->VRefresh = SiSCalcVRate(i);
1218
1219    if( ((mode->HDisplay * ((pScrn->bitsPerPixel + 7) / 8) * mode->VDisplay) > pSiS->maxxfbmem) ||
1220	(mode->HDisplay > 4088) ||
1221	(mode->VDisplay > 4096) ) {
1222
1223       xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1224		"Skipped \"%s\" (%dx%d), not enough video RAM or beyond hardware specs\n",
1225		mode->name, mode->HDisplay, mode->VDisplay);
1226       xfree(mode->Private);
1227       xfree(mode);
1228
1229       return dest;
1230    }
1231
1232#ifdef SISXINERAMA
1233    if(srel != sisClone) {
1234       pSiS->AtLeastOneNonClone = TRUE;
1235    }
1236#endif
1237
1238    /* Now see if the resulting mode would be discarded as a "size" by the
1239     * RandR extension, and increase its clock by 1000 in case it does.
1240     */
1241    if(dest) {
1242       DisplayModePtr t = dest;
1243       do {
1244          if((t->HDisplay == mode->HDisplay) &&
1245	     (t->VDisplay == mode->VDisplay) &&
1246	     ((int)(t->VRefresh + .5) == (int)(mode->VRefresh + .5))) {
1247	     mode->VRefresh += 1000.0;
1248	  }
1249	  t = t->next;
1250       } while((t) && (t != dest));
1251    }
1252
1253    /* Provide a fake but unique DotClock in order to trick the vidmode
1254     * extension to allow selecting among a number of modes whose merged result
1255     * looks identical but consists of different modes for CRT1 and CRT2
1256     */
1257    mode->Clock = (int)(mode->VRefresh * 1000.0);
1258
1259    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1260	"Merged \"%s\" (%dx%d) and \"%s\" (%dx%d) to %dx%d (%d)%s\n",
1261	i->name, i->HDisplay, i->VDisplay, j->name, j->HDisplay, j->VDisplay,
1262	mode->HDisplay, mode->VDisplay, (int)mode->VRefresh,
1263	(srel == sisClone) ? " (Clone)" : "");
1264
1265    mode->next = mode;
1266    mode->prev = mode;
1267
1268    if(dest) {
1269       mode->next = dest->next; 	/* Insert node after "dest" */
1270       dest->next->prev = mode;
1271       mode->prev = dest;
1272       dest->next = mode;
1273    }
1274
1275    return mode;
1276}
1277
1278/* Helper function to find a mode from a given name
1279 * (Code base taken from mga driver)
1280 */
1281static DisplayModePtr
1282SiSGetModeFromName(char* str, DisplayModePtr i)
1283{
1284    DisplayModePtr c = i;
1285    if(!i) return NULL;
1286    do {
1287       if(strcmp(str, c->name) == 0) return c;
1288       c = c->next;
1289    } while(c != i);
1290    return NULL;
1291}
1292
1293static DisplayModePtr
1294SiSFindWidestTallestMode(DisplayModePtr i, Bool tallest)
1295{
1296    DisplayModePtr c = i, d = NULL;
1297    int max = 0;
1298    if(!i) return NULL;
1299    do {
1300       if(tallest) {
1301          if(c->VDisplay > max) {
1302	     max = c->VDisplay;
1303	     d = c;
1304          }
1305       } else {
1306          if(c->HDisplay > max) {
1307	     max = c->HDisplay;
1308	     d = c;
1309          }
1310       }
1311       c = c->next;
1312    } while(c != i);
1313    return d;
1314}
1315
1316static void
1317SiSFindWidestTallestCommonMode(DisplayModePtr i, DisplayModePtr j, Bool tallest,
1318				DisplayModePtr *a, DisplayModePtr *b)
1319{
1320    DisplayModePtr c = i, d;
1321    int max = 0;
1322    Bool foundone;
1323
1324    (*a) = (*b) = NULL;
1325
1326    if(!i || !j) return;
1327
1328    do {
1329       d = j;
1330       foundone = FALSE;
1331       do {
1332	  if( (c->HDisplay == d->HDisplay) &&
1333	      (c->VDisplay == d->VDisplay) ) {
1334	     foundone = TRUE;
1335	     break;
1336	  }
1337	  d = d->next;
1338       } while(d != j);
1339       if(foundone) {
1340	  if(tallest) {
1341	     if(c->VDisplay > max) {
1342		max = c->VDisplay;
1343		(*a) = c;
1344		(*b) = d;
1345	     }
1346	  } else {
1347	     if(c->HDisplay > max) {
1348		max = c->HDisplay;
1349		(*a) = c;
1350		(*b) = d;
1351	     }
1352	  }
1353       }
1354       c = c->next;
1355    } while(c != i);
1356}
1357
1358static DisplayModePtr
1359SiSGenerateModeListFromLargestModes(ScrnInfoPtr pScrn,
1360		    DisplayModePtr i, DisplayModePtr j,
1361		    SiSScrn2Rel srel)
1362{
1363#ifdef SISXINERAMA
1364    SISPtr pSiS = SISPTR(pScrn);
1365#endif
1366    DisplayModePtr mode1 = NULL;
1367    DisplayModePtr mode2 = NULL;
1368    DisplayModePtr mode3 = NULL;
1369    DisplayModePtr mode4 = NULL;
1370    DisplayModePtr result = NULL;
1371
1372#ifdef SISXINERAMA
1373    pSiS->AtLeastOneNonClone = FALSE;
1374#endif
1375
1376    /* Now build a default list of MetaModes.
1377     * - Non-clone: If the user enabled NonRectangular, we use the
1378     * largest mode for each CRT1 and CRT2. If not, we use the largest
1379     * common mode for CRT1 and CRT2 (if available). Additionally, and
1380     * regardless if the above, we produce a clone mode consisting of
1381     * the largest common mode (if available) in order to use DGA.
1382     * - Clone: If the (global) CRT2Position is Clone, we use the
1383     * largest common mode if available, otherwise the first two modes
1384     * in each list.
1385     */
1386
1387    switch(srel) {
1388    case sisLeftOf:
1389    case sisRightOf:
1390       mode1 = SiSFindWidestTallestMode(i, FALSE);
1391       mode2 = SiSFindWidestTallestMode(j, FALSE);
1392       SiSFindWidestTallestCommonMode(i, j, FALSE, &mode3, &mode4);
1393       break;
1394    case sisAbove:
1395    case sisBelow:
1396       mode1 = SiSFindWidestTallestMode(i, TRUE);
1397       mode2 = SiSFindWidestTallestMode(j, TRUE);
1398       SiSFindWidestTallestCommonMode(i, j, TRUE, &mode3, &mode4);
1399       break;
1400    case sisClone:
1401       SiSFindWidestTallestCommonMode(i, j, FALSE, &mode3, &mode4);
1402       if(mode3 && mode4) {
1403	  mode1 = mode3;
1404	  mode2 = mode4;
1405       } else {
1406	  mode1 = i;
1407	  mode2 = j;
1408       }
1409    }
1410
1411    if(srel != sisClone) {
1412       if(mode3 && mode4 && !pSiS->NonRect) {
1413	  mode1 = mode3;
1414	  mode2 = mode2;
1415       }
1416    }
1417
1418    if(mode1 && mode2) {
1419       result = SiSCopyModeNLink(pScrn, result, mode1, mode2, srel);
1420    }
1421
1422    if(srel != sisClone) {
1423       if(mode3 && mode4) {
1424	  result = SiSCopyModeNLink(pScrn, result, mode3, mode4, sisClone);
1425       }
1426    }
1427
1428    return result;
1429}
1430
1431/* Generate the merged-fb mode modelist
1432 * (Taken from mga driver)
1433 */
1434static DisplayModePtr
1435SiSGenerateModeListFromMetaModes(ScrnInfoPtr pScrn, char* str,
1436		    DisplayModePtr i, DisplayModePtr j,
1437		    SiSScrn2Rel srel)
1438{
1439#ifdef SISXINERAMA
1440    SISPtr pSiS = SISPTR(pScrn);
1441#endif
1442    char* strmode = str;
1443    char modename[256];
1444    Bool gotdash = FALSE;
1445    char gotsep = 0;
1446    SiSScrn2Rel sr;
1447    DisplayModePtr mode1 = NULL;
1448    DisplayModePtr mode2 = NULL;
1449    DisplayModePtr result = NULL;
1450    int myslen;
1451
1452#ifdef SISXINERAMA
1453    pSiS->AtLeastOneNonClone = FALSE;
1454#endif
1455
1456    do {
1457        switch(*str) {
1458        case 0:
1459        case '-':
1460	case '+':
1461        case ' ':
1462	case ',':
1463	case ';':
1464           if(strmode != str) {
1465
1466              myslen = str - strmode;
1467              if(myslen > 255) myslen = 255;
1468  	      strncpy(modename, strmode, myslen);
1469  	      modename[myslen] = 0;
1470
1471              if(gotdash) {
1472                 if(mode1 == NULL) {
1473  	             xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1474  	                        "Error parsing MetaModes parameter\n");
1475  	             return NULL;
1476  	         }
1477                 mode2 = SiSGetModeFromName(modename, j);
1478                 if(!mode2) {
1479                    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1480                        "Mode \"%s\" is not a supported mode for CRT2\n", modename);
1481                    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1482                        "\t(Skipping metamode \"%s%c%s\")\n", mode1->name, gotsep, modename);
1483                    mode1 = NULL;
1484		    gotsep = 0;
1485                 }
1486              } else {
1487                 mode1 = SiSGetModeFromName(modename, i);
1488                 if(!mode1) {
1489                    char* tmps = str;
1490                    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1491                        "Mode \"%s\" is not a supported mode for CRT1\n", modename);
1492                    while(*tmps == ' ' || *tmps == ';') tmps++;
1493                    /* skip the next mode */
1494  	            if(*tmps == '-' || *tmps == '+' || *tmps == ',') {
1495                       tmps++;
1496		       /* skip spaces */
1497		       while(*tmps == ' ' || *tmps == ';') tmps++;
1498		       /* skip modename */
1499		       while(*tmps && *tmps != ' ' && *tmps != ';' && *tmps != '-' && *tmps != '+' && *tmps != ',') tmps++;
1500  	               myslen = tmps - strmode;
1501  	               if(myslen > 255) myslen = 255;
1502  	               strncpy(modename,strmode,myslen);
1503  	               modename[myslen] = 0;
1504                       str = tmps - 1;
1505                    }
1506                    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1507                        "\t(Skipping metamode \"%s\")\n", modename);
1508                    mode1 = NULL;
1509		    gotsep = 0;
1510                 }
1511              }
1512              gotdash = FALSE;
1513           }
1514           strmode = str + 1;
1515           gotdash |= (*str == '-' || *str == '+' || *str == ',');
1516	   if (*str == '-' || *str == '+' || *str == ',')
1517  	      gotsep = *str;
1518
1519           if(*str != 0) break;
1520	   /* Fall through otherwise */
1521
1522        default:
1523           if(!gotdash && mode1) {
1524              sr = srel;
1525	      if(gotsep == '+') sr = sisClone;
1526              if(!mode2) {
1527                 mode2 = SiSGetModeFromName(mode1->name, j);
1528                 sr = sisClone;
1529              }
1530              if(!mode2) {
1531                 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1532                     "Mode \"%s\" is not a supported mode for CRT2\n", mode1->name);
1533                 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1534                     "\t(Skipping metamode \"%s\")\n", modename);
1535                 mode1 = NULL;
1536              } else {
1537                 result = SiSCopyModeNLink(pScrn, result, mode1, mode2, sr);
1538                 mode1 = NULL;
1539                 mode2 = NULL;
1540              }
1541	      gotsep = 0;
1542           }
1543           break;
1544
1545        }
1546
1547    } while(*(str++) != 0);
1548
1549    return result;
1550}
1551
1552static DisplayModePtr
1553SiSGenerateModeList(ScrnInfoPtr pScrn, char* str,
1554		    DisplayModePtr i, DisplayModePtr j,
1555		    SiSScrn2Rel srel)
1556{
1557   SISPtr pSiS = SISPTR(pScrn);
1558
1559   if(str != NULL) {
1560      return(SiSGenerateModeListFromMetaModes(pScrn, str, i, j, srel));
1561   } else {
1562      xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1563	"No MetaModes given, linking %s modes by default\n",
1564	(srel == sisClone) ? "largest common" :
1565	   (pSiS->NonRect ?
1566		(((srel == sisLeftOf) || (srel == sisRightOf)) ? "widest" :  "tallest")
1567		:
1568		(((srel == sisLeftOf) || (srel == sisRightOf)) ? "widest common" :  "tallest common")) );
1569      return(SiSGenerateModeListFromLargestModes(pScrn, i, j, srel));
1570   }
1571}
1572
1573static void
1574SiSRecalcDefaultVirtualSize(ScrnInfoPtr pScrn)
1575{
1576    SISPtr pSiS = SISPTR(pScrn);
1577    DisplayModePtr mode, bmode;
1578    int maxh, maxv;
1579    static const char *str = "MergedFB: Virtual %s %d\n";
1580    static const char *errstr = "Virtual %s to small for given CRT2Position offset\n";
1581
1582    mode = bmode = pScrn->modes;
1583    maxh = maxv = 0;
1584    do {
1585       if(mode->HDisplay > maxh) maxh = mode->HDisplay;
1586       if(mode->VDisplay > maxv) maxv = mode->VDisplay;
1587       mode = mode->next;
1588    } while(mode != bmode);
1589
1590    maxh += pSiS->CRT1XOffs + pSiS->CRT2XOffs;
1591    maxv += pSiS->CRT1YOffs + pSiS->CRT2YOffs;
1592
1593    if(!(pScrn->display->virtualX)) {
1594       if(maxh > 4088) {
1595	  xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1596		"Virtual width with CRT2Position offset beyond hardware specs\n");
1597	  pSiS->CRT1XOffs = pSiS->CRT2XOffs = 0;
1598	  maxh -= (pSiS->CRT1XOffs + pSiS->CRT2XOffs);
1599       }
1600       pScrn->virtualX = maxh;
1601       pScrn->displayWidth = maxh;
1602       xf86DrvMsg(pScrn->scrnIndex, X_PROBED, str, "width", maxh);
1603    } else {
1604       if(maxh < pScrn->display->virtualX) {
1605	  xf86DrvMsg(pScrn->scrnIndex, X_ERROR, errstr, "width");
1606	  pSiS->CRT1XOffs = pSiS->CRT2XOffs = 0;
1607       }
1608    }
1609
1610    if(!(pScrn->display->virtualY)) {
1611       pScrn->virtualY = maxv;
1612       xf86DrvMsg(pScrn->scrnIndex, X_PROBED, str, "height", maxv);
1613    } else {
1614       if(maxv < pScrn->display->virtualY) {
1615	  xf86DrvMsg(pScrn->scrnIndex, X_ERROR, errstr, "height");
1616	  pSiS->CRT1YOffs = pSiS->CRT2YOffs = 0;
1617       }
1618    }
1619}
1620
1621static void
1622SiSMergedFBSetDpi(ScrnInfoPtr pScrn1, ScrnInfoPtr pScrn2, SiSScrn2Rel srel)
1623{
1624   SISPtr pSiS = SISPTR(pScrn1);
1625   MessageType from = X_DEFAULT;
1626   xf86MonPtr DDC1 = (xf86MonPtr)(pScrn1->monitor->DDC);
1627   xf86MonPtr DDC2 = (xf86MonPtr)(pScrn2->monitor->DDC);
1628   int ddcWidthmm = 0, ddcHeightmm = 0;
1629   const char *dsstr = "MergedFB: Display dimensions: (%d, %d) mm\n";
1630
1631   /* This sets the DPI for MergedFB mode. The problem is that
1632    * this can never be exact, because the output devices may
1633    * have different dimensions. This function tries to compromise
1634    * through a few assumptions, and it just calculates an average DPI
1635    * value for both monitors.
1636    */
1637
1638   /* Given DisplaySize should regard BOTH monitors */
1639   pScrn1->widthmm = pScrn1->monitor->widthmm;
1640   pScrn1->heightmm = pScrn1->monitor->heightmm;
1641
1642   /* Get DDC display size; if only either CRT1 or CRT2 provided these,
1643    * assume equal dimensions for both, otherwise add dimensions
1644    */
1645   if( (DDC1 && (DDC1->features.hsize > 0 && DDC1->features.vsize > 0)) &&
1646       (DDC2 && (DDC2->features.hsize > 0 && DDC2->features.vsize > 0)) ) {
1647      ddcWidthmm = max(DDC1->features.hsize, DDC2->features.hsize) * 10;
1648      ddcHeightmm = max(DDC1->features.vsize, DDC2->features.vsize) * 10;
1649      switch(srel) {
1650      case sisLeftOf:
1651      case sisRightOf:
1652	 ddcWidthmm = (DDC1->features.hsize + DDC2->features.hsize) * 10;
1653	 break;
1654      case sisAbove:
1655      case sisBelow:
1656	 ddcHeightmm = (DDC1->features.vsize + DDC2->features.vsize) * 10;
1657      default:
1658	 break;
1659      }
1660   } else if(DDC1 && (DDC1->features.hsize > 0 && DDC1->features.vsize > 0)) {
1661      ddcWidthmm = DDC1->features.hsize * 10;
1662      ddcHeightmm = DDC1->features.vsize * 10;
1663      switch(srel) {
1664      case sisLeftOf:
1665      case sisRightOf:
1666	 ddcWidthmm *= 2;
1667	 break;
1668      case sisAbove:
1669      case sisBelow:
1670	 ddcHeightmm *= 2;
1671      default:
1672	 break;
1673      }
1674   } else if(DDC2 && (DDC2->features.hsize > 0 && DDC2->features.vsize > 0) ) {
1675      ddcWidthmm = DDC2->features.hsize * 10;
1676      ddcHeightmm = DDC2->features.vsize * 10;
1677      switch(srel) {
1678      case sisLeftOf:
1679      case sisRightOf:
1680	 ddcWidthmm *= 2;
1681	 break;
1682      case sisAbove:
1683      case sisBelow:
1684	 ddcHeightmm *= 2;
1685      default:
1686	 break;
1687      }
1688   }
1689
1690   if(monitorResolution > 0) {
1691
1692      /* Set command line given values (overrules given options) */
1693      pScrn1->xDpi = monitorResolution;
1694      pScrn1->yDpi = monitorResolution;
1695      from = X_CMDLINE;
1696
1697   } else if(pSiS->MergedFBXDPI) {
1698
1699      /* Set option-wise given values (overrule DisplaySize) */
1700      pScrn1->xDpi = pSiS->MergedFBXDPI;
1701      pScrn1->yDpi = pSiS->MergedFBYDPI;
1702      from = X_CONFIG;
1703
1704   } else if(pScrn1->widthmm > 0 || pScrn1->heightmm > 0) {
1705
1706      /* Set values calculated from given DisplaySize */
1707      from = X_CONFIG;
1708      if(pScrn1->widthmm > 0) {
1709	 pScrn1->xDpi = (int)((double)pScrn1->virtualX * 25.4 / pScrn1->widthmm);
1710      }
1711      if(pScrn1->heightmm > 0) {
1712	 pScrn1->yDpi = (int)((double)pScrn1->virtualY * 25.4 / pScrn1->heightmm);
1713      }
1714      xf86DrvMsg(pScrn1->scrnIndex, from, dsstr, pScrn1->widthmm, pScrn1->heightmm);
1715
1716    } else if(ddcWidthmm && ddcHeightmm) {
1717
1718      /* Set values from DDC-provided display size */
1719      from = X_PROBED;
1720      xf86DrvMsg(pScrn1->scrnIndex, from, dsstr, ddcWidthmm, ddcHeightmm );
1721      pScrn1->widthmm = ddcWidthmm;
1722      pScrn1->heightmm = ddcHeightmm;
1723      if(pScrn1->widthmm > 0) {
1724	 pScrn1->xDpi = (int)((double)pScrn1->virtualX * 25.4 / pScrn1->widthmm);
1725      }
1726      if(pScrn1->heightmm > 0) {
1727	 pScrn1->yDpi = (int)((double)pScrn1->virtualY * 25.4 / pScrn1->heightmm);
1728      }
1729
1730    } else {
1731
1732      pScrn1->xDpi = pScrn1->yDpi = DEFAULT_DPI;
1733
1734    }
1735
1736    /* Sanity check */
1737    if(pScrn1->xDpi > 0 && pScrn1->yDpi <= 0)
1738       pScrn1->yDpi = pScrn1->xDpi;
1739    if(pScrn1->yDpi > 0 && pScrn1->xDpi <= 0)
1740       pScrn1->xDpi = pScrn1->yDpi;
1741
1742    pScrn2->xDpi = pScrn1->xDpi;
1743    pScrn2->yDpi = pScrn1->yDpi;
1744
1745    xf86DrvMsg(pScrn1->scrnIndex, from, "MergedFB: DPI set to (%d, %d)\n",
1746		pScrn1->xDpi, pScrn1->yDpi);
1747}
1748
1749/* Pseudo-Xinerama extension for MergedFB mode */
1750#ifdef SISXINERAMA
1751
1752static void
1753SiSUpdateXineramaScreenInfo(ScrnInfoPtr pScrn1)
1754{
1755    SISPtr pSiS = SISPTR(pScrn1);
1756    int crt1scrnnum = 0, crt2scrnnum = 1;
1757    int x1=0, x2=0, y1=0, y2=0, h1=0, h2=0, w1=0, w2=0;
1758    int realvirtX, realvirtY;
1759    DisplayModePtr currentMode, firstMode;
1760    Bool infochanged = FALSE;
1761    Bool usenonrect = pSiS->NonRect;
1762    const char *rectxine = "\t... setting up rectangular Xinerama layout\n";
1763
1764    pSiS->MBXNR1XMAX = pSiS->MBXNR1YMAX = pSiS->MBXNR2XMAX = pSiS->MBXNR2YMAX = 65536;
1765    pSiS->HaveNonRect = pSiS->HaveOffsRegions = FALSE;
1766
1767    if(!pSiS->MergedFB) return;
1768
1769    if(SiSnoPanoramiXExtension) return;
1770
1771    if(!SiSXineramadataPtr) return;
1772
1773    if(pSiS->CRT2IsScrn0) {
1774       crt1scrnnum = 1;
1775       crt2scrnnum = 0;
1776    }
1777
1778    /* Attention: Usage of RandR may lead to virtual X and Y dimensions
1779     * actually smaller than our MetaModes. To avoid this, we calculate
1780     * the maxCRT fields here (and not somewhere else, like in CopyNLink)
1781     *
1782     * *** Note: RandR is disabled if one of CRTxxOffs is non-zero.
1783     */
1784
1785    /* "Real" virtual: Virtual without the Offset */
1786    realvirtX = pScrn1->virtualX - pSiS->CRT1XOffs - pSiS->CRT2XOffs;
1787    realvirtY = pScrn1->virtualY - pSiS->CRT1YOffs - pSiS->CRT2YOffs;
1788
1789    if((pSiS->SiSXineramaVX != pScrn1->virtualX) || (pSiS->SiSXineramaVY != pScrn1->virtualY)) {
1790
1791       if(!(pScrn1->modes)) return;
1792
1793       pSiS->maxCRT1_X1 = pSiS->maxCRT1_X2 = 0;
1794       pSiS->maxCRT1_Y1 = pSiS->maxCRT1_Y2 = 0;
1795       pSiS->maxCRT2_X1 = pSiS->maxCRT2_X2 = 0;
1796       pSiS->maxCRT2_Y1 = pSiS->maxCRT2_Y2 = 0;
1797       pSiS->maxClone_X1 = pSiS->maxClone_X2 = 0;
1798       pSiS->maxClone_Y1 = pSiS->maxClone_Y2 = 0;
1799
1800       currentMode = firstMode = pScrn1->modes;
1801
1802       do {
1803
1804          DisplayModePtr p = currentMode->next;
1805          DisplayModePtr i = ((SiSMergedDisplayModePtr)currentMode->Private)->CRT1;
1806          DisplayModePtr j = ((SiSMergedDisplayModePtr)currentMode->Private)->CRT2;
1807          SiSScrn2Rel srel = ((SiSMergedDisplayModePtr)currentMode->Private)->CRT2Position;
1808
1809          if((currentMode->HDisplay <= realvirtX) && (currentMode->VDisplay <= realvirtY) &&
1810	     (i->HDisplay <= realvirtX) && (j->HDisplay <= realvirtX) &&
1811	     (i->VDisplay <= realvirtY) && (j->VDisplay <= realvirtY)) {
1812
1813	     if(srel != sisClone) {
1814		if(pSiS->maxCRT1_X1 == i->HDisplay) {
1815		   if(pSiS->maxCRT1_X2 < j->HDisplay) {
1816		      pSiS->maxCRT1_X2 = j->HDisplay;   /* Widest CRT2 mode displayed with widest CRT1 mode */
1817		   }
1818		} else if(pSiS->maxCRT1_X1 < i->HDisplay) {
1819		   pSiS->maxCRT1_X1 = i->HDisplay;      /* Widest CRT1 mode */
1820		   pSiS->maxCRT1_X2 = j->HDisplay;
1821		}
1822		if(pSiS->maxCRT2_X2 == j->HDisplay) {
1823		   if(pSiS->maxCRT2_X1 < i->HDisplay) {
1824		      pSiS->maxCRT2_X1 = i->HDisplay;   /* Widest CRT1 mode displayed with widest CRT2 mode */
1825		   }
1826		} else if(pSiS->maxCRT2_X2 < j->HDisplay) {
1827		   pSiS->maxCRT2_X2 = j->HDisplay;      /* Widest CRT2 mode */
1828		   pSiS->maxCRT2_X1 = i->HDisplay;
1829		}
1830		if(pSiS->maxCRT1_Y1 == i->VDisplay) {   /* Same as above, but tallest instead of widest */
1831		   if(pSiS->maxCRT1_Y2 < j->VDisplay) {
1832		      pSiS->maxCRT1_Y2 = j->VDisplay;
1833		   }
1834		} else if(pSiS->maxCRT1_Y1 < i->VDisplay) {
1835		   pSiS->maxCRT1_Y1 = i->VDisplay;
1836		   pSiS->maxCRT1_Y2 = j->VDisplay;
1837		}
1838		if(pSiS->maxCRT2_Y2 == j->VDisplay) {
1839		   if(pSiS->maxCRT2_Y1 < i->VDisplay) {
1840		      pSiS->maxCRT2_Y1 = i->VDisplay;
1841		   }
1842		} else if(pSiS->maxCRT2_Y2 < j->VDisplay) {
1843		   pSiS->maxCRT2_Y2 = j->VDisplay;
1844		   pSiS->maxCRT2_Y1 = i->VDisplay;
1845		}
1846	     } else {
1847		if(pSiS->maxClone_X1 < i->HDisplay) {
1848		   pSiS->maxClone_X1 = i->HDisplay;
1849		}
1850		if(pSiS->maxClone_X2 < j->HDisplay) {
1851		   pSiS->maxClone_X2 = j->HDisplay;
1852		}
1853		if(pSiS->maxClone_Y1 < i->VDisplay) {
1854		   pSiS->maxClone_Y1 = i->VDisplay;
1855		}
1856		if(pSiS->maxClone_Y2 < j->VDisplay) {
1857		   pSiS->maxClone_Y2 = j->VDisplay;
1858		}
1859	     }
1860	  }
1861	  currentMode = p;
1862
1863       } while((currentMode) && (currentMode != firstMode));
1864
1865       pSiS->SiSXineramaVX = pScrn1->virtualX;
1866       pSiS->SiSXineramaVY = pScrn1->virtualY;
1867       infochanged = TRUE;
1868
1869    }
1870
1871    if((usenonrect) && (pSiS->CRT2Position != sisClone) && pSiS->maxCRT1_X1) {
1872       switch(pSiS->CRT2Position) {
1873       case sisLeftOf:
1874       case sisRightOf:
1875	  if((pSiS->maxCRT1_Y1 != realvirtY) && (pSiS->maxCRT2_Y2 != realvirtY)) {
1876	     usenonrect = FALSE;
1877	  }
1878	  break;
1879       case sisAbove:
1880       case sisBelow:
1881	  if((pSiS->maxCRT1_X1 != realvirtX) && (pSiS->maxCRT2_X2 != realvirtX)) {
1882	     usenonrect = FALSE;
1883	  }
1884	  break;
1885       case sisClone:
1886	  break;
1887       }
1888       if(infochanged && !usenonrect) {
1889	  xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
1890			"Virtual screen size does not match maximum display modes...\n");
1891	  xf86DrvMsg(pScrn1->scrnIndex, X_INFO, rectxine);
1892
1893       }
1894    } else if(infochanged && usenonrect) {
1895       usenonrect = FALSE;
1896       xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
1897		"Only clone modes available for this virtual screen size...\n");
1898       xf86DrvMsg(pScrn1->scrnIndex, X_INFO, rectxine);
1899    }
1900
1901    if(pSiS->maxCRT1_X1) {		/* Means we have at least one non-clone mode */
1902       switch(pSiS->CRT2Position) {
1903       case sisLeftOf:
1904	  x1 = min(pSiS->maxCRT1_X2, pScrn1->virtualX - pSiS->maxCRT1_X1);
1905	  if(x1 < 0) x1 = 0;
1906	  y1 = pSiS->CRT1YOffs;
1907	  w1 = pScrn1->virtualX - x1;
1908	  h1 = realvirtY;
1909	  if((usenonrect) && (pSiS->maxCRT1_Y1 != realvirtY)) {
1910	     h1 = pSiS->MBXNR1YMAX = pSiS->maxCRT1_Y1;
1911	     pSiS->NonRectDead.x0 = x1;
1912	     pSiS->NonRectDead.x1 = x1 + w1 - 1;
1913	     pSiS->NonRectDead.y0 = y1 + h1;
1914	     pSiS->NonRectDead.y1 = pScrn1->virtualY - 1;
1915	     pSiS->HaveNonRect = TRUE;
1916	  }
1917	  x2 = 0;
1918	  y2 = pSiS->CRT2YOffs;
1919	  w2 = max(pSiS->maxCRT2_X2, pScrn1->virtualX - pSiS->maxCRT2_X1);
1920	  if(w2 > pScrn1->virtualX) w2 = pScrn1->virtualX;
1921	  h2 = realvirtY;
1922	  if((usenonrect) && (pSiS->maxCRT2_Y2 != realvirtY)) {
1923	     h2 = pSiS->MBXNR2YMAX = pSiS->maxCRT2_Y2;
1924	     pSiS->NonRectDead.x0 = x2;
1925	     pSiS->NonRectDead.x1 = x2 + w2 - 1;
1926	     pSiS->NonRectDead.y0 = y2 + h2;
1927	     pSiS->NonRectDead.y1 = pScrn1->virtualY - 1;
1928	     pSiS->HaveNonRect = TRUE;
1929	  }
1930	  break;
1931       case sisRightOf:
1932	  x1 = 0;
1933	  y1 = pSiS->CRT1YOffs;
1934	  w1 = max(pSiS->maxCRT1_X1, pScrn1->virtualX - pSiS->maxCRT1_X2);
1935	  if(w1 > pScrn1->virtualX) w1 = pScrn1->virtualX;
1936	  h1 = realvirtY;
1937	  if((usenonrect) && (pSiS->maxCRT1_Y1 != realvirtY)) {
1938	     h1 = pSiS->MBXNR1YMAX = pSiS->maxCRT1_Y1;
1939	     pSiS->NonRectDead.x0 = x1;
1940	     pSiS->NonRectDead.x1 = x1 + w1 - 1;
1941	     pSiS->NonRectDead.y0 = y1 + h1;
1942	     pSiS->NonRectDead.y1 = pScrn1->virtualY - 1;
1943	     pSiS->HaveNonRect = TRUE;
1944	  }
1945	  x2 = min(pSiS->maxCRT2_X1, pScrn1->virtualX - pSiS->maxCRT2_X2);
1946	  if(x2 < 0) x2 = 0;
1947	  y2 = pSiS->CRT2YOffs;
1948	  w2 = pScrn1->virtualX - x2;
1949	  h2 = realvirtY;
1950	  if((usenonrect) && (pSiS->maxCRT2_Y2 != realvirtY)) {
1951	     h2 = pSiS->MBXNR2YMAX = pSiS->maxCRT2_Y2;
1952	     pSiS->NonRectDead.x0 = x2;
1953	     pSiS->NonRectDead.x1 = x2 + w2 - 1;
1954	     pSiS->NonRectDead.y0 = y2 + h2;
1955	     pSiS->NonRectDead.y1 = pScrn1->virtualY - 1;
1956	     pSiS->HaveNonRect = TRUE;
1957	  }
1958	  break;
1959       case sisAbove:
1960	  x1 = pSiS->CRT1XOffs;
1961	  y1 = min(pSiS->maxCRT1_Y2, pScrn1->virtualY - pSiS->maxCRT1_Y1);
1962	  if(y1 < 0) y1 = 0;
1963	  w1 = realvirtX;
1964	  h1 = pScrn1->virtualY - y1;
1965	  if((usenonrect) && (pSiS->maxCRT1_X1 != realvirtX)) {
1966	     w1 = pSiS->MBXNR1XMAX = pSiS->maxCRT1_X1;
1967	     pSiS->NonRectDead.x0 = x1 + w1;
1968	     pSiS->NonRectDead.x1 = pScrn1->virtualX - 1;
1969	     pSiS->NonRectDead.y0 = y1;
1970	     pSiS->NonRectDead.y1 = y1 + h1 - 1;
1971	     pSiS->HaveNonRect = TRUE;
1972	  }
1973	  x2 = pSiS->CRT2XOffs;
1974	  y2 = 0;
1975	  w2 = realvirtX;
1976	  h2 = max(pSiS->maxCRT2_Y2, pScrn1->virtualY - pSiS->maxCRT2_Y1);
1977	  if(h2 > pScrn1->virtualY) h2 = pScrn1->virtualY;
1978	  if((usenonrect) && (pSiS->maxCRT2_X2 != realvirtX)) {
1979	     w2 = pSiS->MBXNR2XMAX = pSiS->maxCRT2_X2;
1980	     pSiS->NonRectDead.x0 = x2 + w2;
1981	     pSiS->NonRectDead.x1 = pScrn1->virtualX - 1;
1982	     pSiS->NonRectDead.y0 = y2;
1983	     pSiS->NonRectDead.y1 = y2 + h2 - 1;
1984	     pSiS->HaveNonRect = TRUE;
1985	  }
1986	  break;
1987       case sisBelow:
1988	  x1 = pSiS->CRT1XOffs;
1989	  y1 = 0;
1990	  w1 = realvirtX;
1991	  h1 = max(pSiS->maxCRT1_Y1, pScrn1->virtualY - pSiS->maxCRT1_Y2);
1992	  if(h1 > pScrn1->virtualY) h1 = pScrn1->virtualY;
1993	  if((usenonrect) && (pSiS->maxCRT1_X1 != realvirtX)) {
1994	     w1 = pSiS->MBXNR1XMAX = pSiS->maxCRT1_X1;
1995	     pSiS->NonRectDead.x0 = x1 + w1;
1996	     pSiS->NonRectDead.x1 = pScrn1->virtualX - 1;
1997	     pSiS->NonRectDead.y0 = y1;
1998	     pSiS->NonRectDead.y1 = y1 + h1 - 1;
1999	     pSiS->HaveNonRect = TRUE;
2000	  }
2001	  x2 = pSiS->CRT2XOffs;
2002	  y2 = min(pSiS->maxCRT2_Y1, pScrn1->virtualY - pSiS->maxCRT2_Y2);
2003	  if(y2 < 0) y2 = 0;
2004	  w2 = realvirtX;
2005	  h2 = pScrn1->virtualY - y2;
2006	  if((usenonrect) && (pSiS->maxCRT2_X2 != realvirtX)) {
2007	     w2 = pSiS->MBXNR2XMAX = pSiS->maxCRT2_X2;
2008	     pSiS->NonRectDead.x0 = x2 + w2;
2009	     pSiS->NonRectDead.x1 = pScrn1->virtualX - 1;
2010	     pSiS->NonRectDead.y0 = y2;
2011	     pSiS->NonRectDead.y1 = y2 + h2 - 1;
2012	     pSiS->HaveNonRect = TRUE;
2013	  }
2014       default:
2015	  break;
2016       }
2017
2018       switch(pSiS->CRT2Position) {
2019       case sisLeftOf:
2020       case sisRightOf:
2021	  if(pSiS->CRT1YOffs) {
2022	     pSiS->OffDead1.x0 = x1;
2023	     pSiS->OffDead1.x1 = x1 + w1 - 1;
2024	     pSiS->OffDead1.y0 = 0;
2025	     pSiS->OffDead1.y1 = y1 - 1;
2026	     pSiS->OffDead2.x0 = x2;
2027	     pSiS->OffDead2.x1 = x2 + w2 - 1;
2028	     pSiS->OffDead2.y0 = y2 + h2;
2029	     pSiS->OffDead2.y1 = pScrn1->virtualY - 1;
2030	     pSiS->HaveOffsRegions = TRUE;
2031	  } else if(pSiS->CRT2YOffs) {
2032	     pSiS->OffDead1.x0 = x2;
2033	     pSiS->OffDead1.x1 = x2 + w2 - 1;
2034	     pSiS->OffDead1.y0 = 0;
2035	     pSiS->OffDead1.y1 = y2 - 1;
2036	     pSiS->OffDead2.x0 = x1;
2037	     pSiS->OffDead2.x1 = x1 + w1 - 1;
2038	     pSiS->OffDead2.y0 = y1 + h1;
2039	     pSiS->OffDead2.y1 = pScrn1->virtualY - 1;
2040	     pSiS->HaveOffsRegions = TRUE;
2041	  }
2042	  break;
2043       case sisAbove:
2044       case sisBelow:
2045	  if(pSiS->CRT1XOffs) {
2046	     pSiS->OffDead1.x0 = x2 + w2;
2047	     pSiS->OffDead1.x1 = pScrn1->virtualX - 1;
2048	     pSiS->OffDead1.y0 = y2;
2049	     pSiS->OffDead1.y1 = y2 + h2 - 1;
2050	     pSiS->OffDead2.x0 = 0;
2051	     pSiS->OffDead2.x1 = x1 - 1;
2052	     pSiS->OffDead2.y0 = y1;
2053	     pSiS->OffDead2.y1 = y1 + h1 - 1;
2054	     pSiS->HaveOffsRegions = TRUE;
2055	  } else if(pSiS->CRT2XOffs) {
2056	     pSiS->OffDead1.x0 = x1 + w1;
2057	     pSiS->OffDead1.x1 = pScrn1->virtualX - 1;
2058	     pSiS->OffDead1.y0 = y1;
2059	     pSiS->OffDead1.y1 = y1 + h1 - 1;
2060	     pSiS->OffDead2.x0 = 0;
2061	     pSiS->OffDead2.x1 = x2 - 1;
2062	     pSiS->OffDead2.y0 = y2;
2063	     pSiS->OffDead2.y1 = y2 + h2 - 1;
2064	     pSiS->HaveOffsRegions = TRUE;
2065	  }
2066       default:
2067	  break;
2068       }
2069
2070    } else {	/* Only clone-modes left */
2071
2072       x1 = x2 = 0;
2073       y1 = y2 = 0;
2074       w1 = w2 = max(pSiS->maxClone_X1, pSiS->maxClone_X2);
2075       h1 = h2 = max(pSiS->maxClone_Y1, pSiS->maxClone_Y2);
2076
2077    }
2078
2079    SiSXineramadataPtr[crt1scrnnum].x = x1;
2080    SiSXineramadataPtr[crt1scrnnum].y = y1;
2081    SiSXineramadataPtr[crt1scrnnum].width = w1;
2082    SiSXineramadataPtr[crt1scrnnum].height = h1;
2083    SiSXineramadataPtr[crt2scrnnum].x = x2;
2084    SiSXineramadataPtr[crt2scrnnum].y = y2;
2085    SiSXineramadataPtr[crt2scrnnum].width = w2;
2086    SiSXineramadataPtr[crt2scrnnum].height = h2;
2087
2088    if(infochanged) {
2089       xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
2090	  "Pseudo-Xinerama: CRT1 (Screen %d) (%d,%d)-(%d,%d)\n",
2091	  crt1scrnnum, x1, y1, w1+x1-1, h1+y1-1);
2092       xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
2093	  "Pseudo-Xinerama: CRT2 (Screen %d) (%d,%d)-(%d,%d)\n",
2094	  crt2scrnnum, x2, y2, w2+x2-1, h2+y2-1);
2095       if(pSiS->HaveNonRect) {
2096	  xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
2097		"Pseudo-Xinerama: Inaccessible area (%d,%d)-(%d,%d)\n",
2098		pSiS->NonRectDead.x0, pSiS->NonRectDead.y0,
2099		pSiS->NonRectDead.x1, pSiS->NonRectDead.y1);
2100       }
2101       if(pSiS->HaveOffsRegions) {
2102	  xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
2103		"Pseudo-Xinerama: Inaccessible offset area (%d,%d)-(%d,%d)\n",
2104		pSiS->OffDead1.x0, pSiS->OffDead1.y0,
2105		pSiS->OffDead1.x1, pSiS->OffDead1.y1);
2106	  xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
2107		"Pseudo-Xinerama: Inaccessible offset area (%d,%d)-(%d,%d)\n",
2108		pSiS->OffDead2.x0, pSiS->OffDead2.y0,
2109		pSiS->OffDead2.x1, pSiS->OffDead2.y1);
2110       }
2111       if(pSiS->HaveNonRect || pSiS->HaveOffsRegions) {
2112	  xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
2113		"Mouse restriction for inaccessible areas is %s\n",
2114		pSiS->MouseRestrictions ? "enabled" : "disabled");
2115       }
2116    }
2117}
2118
2119/* Proc */
2120
2121int
2122SiSProcXineramaQueryVersion(ClientPtr client)
2123{
2124    xPanoramiXQueryVersionReply	  rep;
2125    register int		  n;
2126
2127    REQUEST_SIZE_MATCH(xPanoramiXQueryVersionReq);
2128    rep.type = X_Reply;
2129    rep.length = 0;
2130    rep.sequenceNumber = client->sequence;
2131    rep.majorVersion = SIS_XINERAMA_MAJOR_VERSION;
2132    rep.minorVersion = SIS_XINERAMA_MINOR_VERSION;
2133    if(client->swapped) {
2134        swaps(&rep.sequenceNumber, n);
2135        swapl(&rep.length, n);
2136        swaps(&rep.majorVersion, n);
2137        swaps(&rep.minorVersion, n);
2138    }
2139    WriteToClient(client, sizeof(xPanoramiXQueryVersionReply), (char *)&rep);
2140    return (client->noClientException);
2141}
2142
2143int
2144SiSProcXineramaGetState(ClientPtr client)
2145{
2146    REQUEST(xPanoramiXGetStateReq);
2147    WindowPtr			pWin;
2148    xPanoramiXGetStateReply	rep;
2149    register int		n;
2150
2151    REQUEST_SIZE_MATCH(xPanoramiXGetStateReq);
2152    pWin = LookupWindow(stuff->window, client);
2153    if(!pWin) return BadWindow;
2154
2155    rep.type = X_Reply;
2156    rep.length = 0;
2157    rep.sequenceNumber = client->sequence;
2158    rep.state = !SiSnoPanoramiXExtension;
2159    if(client->swapped) {
2160       swaps (&rep.sequenceNumber, n);
2161       swapl (&rep.length, n);
2162       swaps (&rep.state, n);
2163    }
2164    WriteToClient(client, sizeof(xPanoramiXGetStateReply), (char *)&rep);
2165    return client->noClientException;
2166}
2167
2168int
2169SiSProcXineramaGetScreenCount(ClientPtr client)
2170{
2171    REQUEST(xPanoramiXGetScreenCountReq);
2172    WindowPtr				pWin;
2173    xPanoramiXGetScreenCountReply	rep;
2174    register int			n;
2175
2176    REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq);
2177    pWin = LookupWindow(stuff->window, client);
2178    if(!pWin) return BadWindow;
2179
2180    rep.type = X_Reply;
2181    rep.length = 0;
2182    rep.sequenceNumber = client->sequence;
2183    rep.ScreenCount = SiSXineramaNumScreens;
2184    if(client->swapped) {
2185       swaps(&rep.sequenceNumber, n);
2186       swapl(&rep.length, n);
2187       swaps(&rep.ScreenCount, n);
2188    }
2189    WriteToClient(client, sizeof(xPanoramiXGetScreenCountReply), (char *)&rep);
2190    return client->noClientException;
2191}
2192
2193int
2194SiSProcXineramaGetScreenSize(ClientPtr client)
2195{
2196    REQUEST(xPanoramiXGetScreenSizeReq);
2197    WindowPtr				pWin;
2198    xPanoramiXGetScreenSizeReply	rep;
2199    register int			n;
2200
2201    REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq);
2202    pWin = LookupWindow (stuff->window, client);
2203    if(!pWin)  return BadWindow;
2204
2205    rep.type = X_Reply;
2206    rep.length = 0;
2207    rep.sequenceNumber = client->sequence;
2208    rep.width  = SiSXineramadataPtr[stuff->screen].width;
2209    rep.height = SiSXineramadataPtr[stuff->screen].height;
2210    if(client->swapped) {
2211       swaps(&rep.sequenceNumber, n);
2212       swapl(&rep.length, n);
2213       swaps(&rep.width, n);
2214       swaps(&rep.height, n);
2215    }
2216    WriteToClient(client, sizeof(xPanoramiXGetScreenSizeReply), (char *)&rep);
2217    return client->noClientException;
2218}
2219
2220int
2221SiSProcXineramaIsActive(ClientPtr client)
2222{
2223    xXineramaIsActiveReply	rep;
2224
2225    REQUEST_SIZE_MATCH(xXineramaIsActiveReq);
2226
2227    rep.type = X_Reply;
2228    rep.length = 0;
2229    rep.sequenceNumber = client->sequence;
2230    rep.state = !SiSnoPanoramiXExtension;
2231    if(client->swapped) {
2232	register int n;
2233	swaps(&rep.sequenceNumber, n);
2234	swapl(&rep.length, n);
2235	swapl(&rep.state, n);
2236    }
2237    WriteToClient(client, sizeof(xXineramaIsActiveReply), (char *) &rep);
2238    return client->noClientException;
2239}
2240
2241int
2242SiSProcXineramaQueryScreens(ClientPtr client)
2243{
2244    xXineramaQueryScreensReply	rep;
2245
2246    REQUEST_SIZE_MATCH(xXineramaQueryScreensReq);
2247
2248    rep.type = X_Reply;
2249    rep.sequenceNumber = client->sequence;
2250    rep.number = (SiSnoPanoramiXExtension) ? 0 : SiSXineramaNumScreens;
2251    rep.length = rep.number * sz_XineramaScreenInfo >> 2;
2252    if(client->swapped) {
2253       register int n;
2254       swaps(&rep.sequenceNumber, n);
2255       swapl(&rep.length, n);
2256       swapl(&rep.number, n);
2257    }
2258    WriteToClient(client, sizeof(xXineramaQueryScreensReply), (char *)&rep);
2259
2260    if(!SiSnoPanoramiXExtension) {
2261       xXineramaScreenInfo scratch;
2262       int i;
2263
2264       for(i = 0; i < SiSXineramaNumScreens; i++) {
2265	  scratch.x_org  = SiSXineramadataPtr[i].x;
2266	  scratch.y_org  = SiSXineramadataPtr[i].y;
2267	  scratch.width  = SiSXineramadataPtr[i].width;
2268	  scratch.height = SiSXineramadataPtr[i].height;
2269	  if(client->swapped) {
2270	     register int n;
2271	     swaps(&scratch.x_org, n);
2272	     swaps(&scratch.y_org, n);
2273	     swaps(&scratch.width, n);
2274	     swaps(&scratch.height, n);
2275	  }
2276	  WriteToClient(client, sz_XineramaScreenInfo, (char *)&scratch);
2277       }
2278    }
2279
2280    return client->noClientException;
2281}
2282
2283static int
2284SiSProcXineramaDispatch(ClientPtr client)
2285{
2286    REQUEST(xReq);
2287    switch (stuff->data) {
2288	case X_PanoramiXQueryVersion:
2289	     return SiSProcXineramaQueryVersion(client);
2290	case X_PanoramiXGetState:
2291	     return SiSProcXineramaGetState(client);
2292	case X_PanoramiXGetScreenCount:
2293	     return SiSProcXineramaGetScreenCount(client);
2294	case X_PanoramiXGetScreenSize:
2295	     return SiSProcXineramaGetScreenSize(client);
2296	case X_XineramaIsActive:
2297	     return SiSProcXineramaIsActive(client);
2298	case X_XineramaQueryScreens:
2299	     return SiSProcXineramaQueryScreens(client);
2300    }
2301    return BadRequest;
2302}
2303
2304/* SProc */
2305
2306static int
2307SiSSProcXineramaQueryVersion (ClientPtr client)
2308{
2309    REQUEST(xPanoramiXQueryVersionReq);
2310    register int n;
2311    swaps(&stuff->length,n);
2312    REQUEST_SIZE_MATCH (xPanoramiXQueryVersionReq);
2313    return SiSProcXineramaQueryVersion(client);
2314}
2315
2316static int
2317SiSSProcXineramaGetState(ClientPtr client)
2318{
2319    REQUEST(xPanoramiXGetStateReq);
2320    register int n;
2321    swaps (&stuff->length, n);
2322    REQUEST_SIZE_MATCH(xPanoramiXGetStateReq);
2323    return SiSProcXineramaGetState(client);
2324}
2325
2326static int
2327SiSSProcXineramaGetScreenCount(ClientPtr client)
2328{
2329    REQUEST(xPanoramiXGetScreenCountReq);
2330    register int n;
2331    swaps (&stuff->length, n);
2332    REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq);
2333    return SiSProcXineramaGetScreenCount(client);
2334}
2335
2336static int
2337SiSSProcXineramaGetScreenSize(ClientPtr client)
2338{
2339    REQUEST(xPanoramiXGetScreenSizeReq);
2340    register int n;
2341    swaps (&stuff->length, n);
2342    REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq);
2343    return SiSProcXineramaGetScreenSize(client);
2344}
2345
2346static int
2347SiSSProcXineramaIsActive(ClientPtr client)
2348{
2349    REQUEST(xXineramaIsActiveReq);
2350    register int n;
2351    swaps (&stuff->length, n);
2352    REQUEST_SIZE_MATCH(xXineramaIsActiveReq);
2353    return SiSProcXineramaIsActive(client);
2354}
2355
2356static int
2357SiSSProcXineramaQueryScreens(ClientPtr client)
2358{
2359    REQUEST(xXineramaQueryScreensReq);
2360    register int n;
2361    swaps (&stuff->length, n);
2362    REQUEST_SIZE_MATCH(xXineramaQueryScreensReq);
2363    return SiSProcXineramaQueryScreens(client);
2364}
2365
2366int
2367SiSSProcXineramaDispatch(ClientPtr client)
2368{
2369    REQUEST(xReq);
2370    switch (stuff->data) {
2371	case X_PanoramiXQueryVersion:
2372	     return SiSSProcXineramaQueryVersion(client);
2373	case X_PanoramiXGetState:
2374	     return SiSSProcXineramaGetState(client);
2375	case X_PanoramiXGetScreenCount:
2376	     return SiSSProcXineramaGetScreenCount(client);
2377	case X_PanoramiXGetScreenSize:
2378	     return SiSSProcXineramaGetScreenSize(client);
2379	case X_XineramaIsActive:
2380	     return SiSSProcXineramaIsActive(client);
2381	case X_XineramaQueryScreens:
2382	     return SiSSProcXineramaQueryScreens(client);
2383    }
2384    return BadRequest;
2385}
2386
2387static void
2388SiSXineramaResetProc(ExtensionEntry* extEntry)
2389{
2390    /* Called by CloseDownExtensions() */
2391    if(SiSXineramadataPtr) {
2392       Xfree(SiSXineramadataPtr);
2393       SiSXineramadataPtr = NULL;
2394    }
2395}
2396
2397static void
2398SiSXineramaExtensionInit(ScrnInfoPtr pScrn)
2399{
2400    SISPtr	pSiS = SISPTR(pScrn);
2401    Bool	success = FALSE;
2402
2403    if(!(SiSXineramadataPtr)) {
2404
2405       if(!pSiS->MergedFB) {
2406	  SiSnoPanoramiXExtension = TRUE;
2407	  pSiS->MouseRestrictions = FALSE;
2408	  return;
2409       }
2410
2411#ifdef PANORAMIX
2412       if(!noPanoramiXExtension) {
2413	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2414	     "Xinerama active, not initializing SiS Pseudo-Xinerama\n");
2415	  SiSnoPanoramiXExtension = TRUE;
2416	  pSiS->MouseRestrictions = FALSE;
2417	  return;
2418       }
2419#endif
2420
2421       if(SiSnoPanoramiXExtension) {
2422	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2423	      "SiS Pseudo-Xinerama disabled\n");
2424	  pSiS->MouseRestrictions = FALSE;
2425	  return;
2426       }
2427
2428       if(pSiS->CRT2Position == sisClone) {
2429	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2430	     "Running MergedFB in Clone mode, SiS Pseudo-Xinerama disabled\n");
2431	  SiSnoPanoramiXExtension = TRUE;
2432	  pSiS->MouseRestrictions = FALSE;
2433	  return;
2434       }
2435
2436       if(!(pSiS->AtLeastOneNonClone)) {
2437	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2438	     "Only Clone modes defined, SiS Pseudo-Xinerama disabled\n");
2439	  SiSnoPanoramiXExtension = TRUE;
2440	  pSiS->MouseRestrictions = FALSE;
2441	  return;
2442       }
2443
2444       SiSXineramaNumScreens = 2;
2445
2446       while(SiSXineramaGeneration != serverGeneration) {
2447
2448	  pSiS->XineramaExtEntry = AddExtension(PANORAMIX_PROTOCOL_NAME, 0,0,
2449					SiSProcXineramaDispatch,
2450					SiSSProcXineramaDispatch,
2451					SiSXineramaResetProc,
2452					StandardMinorOpcode);
2453
2454	  if(!pSiS->XineramaExtEntry) break;
2455
2456	  if(!(SiSXineramadataPtr = (SiSXineramaData *)
2457	        xcalloc(SiSXineramaNumScreens, sizeof(SiSXineramaData)))) break;
2458
2459	  SiSXineramaGeneration = serverGeneration;
2460	  success = TRUE;
2461       }
2462
2463       if(!success) {
2464	  SISErrorLog(pScrn, "Failed to initialize SiS Pseudo-Xinerama extension\n");
2465	  SiSnoPanoramiXExtension = TRUE;
2466	  pSiS->MouseRestrictions = FALSE;
2467	  return;
2468       }
2469
2470       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2471	  "SiS Pseudo-Xinerama extension initialized\n");
2472
2473       pSiS->SiSXineramaVX = 0;
2474       pSiS->SiSXineramaVY = 0;
2475
2476    }
2477
2478    SiSUpdateXineramaScreenInfo(pScrn);
2479
2480}
2481#endif  /* End of PseudoXinerama */
2482
2483static void
2484SiSFreeCRT2Structs(SISPtr pSiS)
2485{
2486    if(pSiS->CRT2pScrn) {
2487       if(pSiS->CRT2pScrn->modes) {
2488	  while(pSiS->CRT2pScrn->modes)
2489	     xf86DeleteMode(&pSiS->CRT2pScrn->modes, pSiS->CRT2pScrn->modes);
2490       }
2491       if(pSiS->CRT2pScrn->monitor) {
2492	  if(pSiS->CRT2pScrn->monitor->Modes) {
2493	     while(pSiS->CRT2pScrn->monitor->Modes)
2494		xf86DeleteMode(&pSiS->CRT2pScrn->monitor->Modes, pSiS->CRT2pScrn->monitor->Modes);
2495	  }
2496	  if(pSiS->CRT2pScrn->monitor->DDC) xfree(pSiS->CRT2pScrn->monitor->DDC);
2497	  xfree(pSiS->CRT2pScrn->monitor);
2498       }
2499       xfree(pSiS->CRT2pScrn);
2500       pSiS->CRT2pScrn = NULL;
2501   }
2502}
2503
2504#endif	/* End of MergedFB helpers */
2505
2506static xf86MonPtr
2507SiSInternalDDC(ScrnInfoPtr pScrn, int crtno)
2508{
2509   SISPtr     pSiS = SISPTR(pScrn);
2510   xf86MonPtr pMonitor = NULL;
2511   UShort     temp = 0xffff, temp1, i, realcrtno = crtno;
2512   UChar      buffer[256];
2513
2514   /* If CRT1 is off, skip DDC */
2515   if((pSiS->CRT1off) && (!crtno)) return NULL;
2516
2517   if(crtno) {
2518      if(pSiS->VBFlags & CRT2_LCD)      realcrtno = 1;
2519      else if(pSiS->VBFlags & CRT2_VGA) realcrtno = 2;
2520      else				return NULL;
2521      if(pSiS->SiS_Pr->DDCPortMixup) realcrtno = 0;
2522   } else {
2523      /* If CRT1 is LCDA, skip DDC (except 301C: DDC allowed, but uses CRT2 port!) */
2524      if(pSiS->VBFlags & CRT1_LCDA) {
2525         if(pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE) realcrtno = 1;
2526         else return NULL;
2527      }
2528   }
2529
2530   i = 3; /* Number of retrys */
2531   do {
2532      temp1 = SiS_HandleDDC(pSiS->SiS_Pr, pSiS->VBFlags, pSiS->VGAEngine,
2533			realcrtno, 0, &buffer[0], pSiS->VBFlags2);
2534      if((temp1) && (temp1 != 0xffff)) temp = temp1;
2535   } while((temp == 0xffff) && i--);
2536   if(temp != 0xffff) {
2537      xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "CRT%d DDC supported\n", crtno + 1);
2538      xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "CRT%d DDC level: %s%s%s%s\n",
2539	     crtno + 1,
2540	     (temp & 0x1a) ? "" : "[none of the supported]",
2541	     (temp & 0x02) ? "2 " : "",
2542	     (temp & 0x08) ? "D&P" : "",
2543             (temp & 0x10) ? "FPDI-2" : "");
2544      if(temp & 0x02) {
2545	 i = 5;  /* Number of retrys */
2546	 do {
2547	    temp = SiS_HandleDDC(pSiS->SiS_Pr, pSiS->VBFlags, pSiS->VGAEngine,
2548				realcrtno, 1, &buffer[0], pSiS->VBFlags2);
2549	 } while((temp) && i--);
2550         if(!temp) {
2551	    if((pMonitor = xf86InterpretEDID(pScrn->scrnIndex, &buffer[0]))) {
2552	       int tempvgagamma = 0, templcdgamma = 0;
2553	       if(buffer[0x14] & 0x80) {
2554	          templcdgamma = (buffer[0x17] + 100) * 10;
2555	       } else {
2556	          tempvgagamma = (buffer[0x17] + 100) * 10;;
2557	       }
2558	       if(crtno == 0) {
2559		  if(tempvgagamma) pSiS->CRT1VGAMonitorGamma = tempvgagamma;
2560		  /* LCD never via (demanded) CRT1 DDC port */
2561	       } else {
2562	          if(tempvgagamma) pSiS->CRT2VGAMonitorGamma = tempvgagamma;
2563	          if(templcdgamma) pSiS->CRT2LCDMonitorGamma = templcdgamma;
2564	       }
2565	       return(pMonitor);
2566	    } else {
2567	       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2568	           "CRT%d DDC EDID corrupt\n", crtno + 1);
2569	    }
2570	 } else if(temp == 0xFFFE) {
2571	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2572	    	"CRT%d DDC data is from wrong device type (%s)\n",
2573			crtno + 1,
2574			(realcrtno == 1) ? "analog instead of digital" : "digital instead of analog");
2575	 } else {
2576            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
2577	    	"CRT%d DDC reading failed\n", crtno + 1);
2578	 }
2579      } else if(temp & 0x18) {
2580         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2581	      "DDC for VESA D&P and FPDI-2 not supported yet.\n");
2582      }
2583   } else {
2584      xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
2585                "CRT%d DDC probing failed\n", crtno + 1);
2586   }
2587   return(NULL);
2588}
2589
2590static xf86MonPtr
2591SiSDoPrivateDDC(ScrnInfoPtr pScrn, int *crtnum)
2592{
2593    SISPtr pSiS = SISPTR(pScrn);
2594
2595#ifdef SISDUALHEAD
2596    if(pSiS->DualHeadMode) {
2597       if(pSiS->SecondHead) {
2598          *crtnum = 1;
2599	  return(SiSInternalDDC(pScrn, 0));
2600       } else {
2601          *crtnum = 2;
2602	  return(SiSInternalDDC(pScrn, 1));
2603       }
2604    } else
2605#endif
2606    if((pSiS->CRT1off) || (!pSiS->CRT1Detected)) {
2607       *crtnum = 2;
2608       return(SiSInternalDDC(pScrn, 1));
2609    } else {
2610       *crtnum = 1;
2611       return(SiSInternalDDC(pScrn, 0));
2612    }
2613}
2614
2615static void
2616SiSFindAspect(ScrnInfoPtr pScrn, xf86MonPtr pMonitor, int crtnum)
2617{
2618    SISPtr pSiS = SISPTR(pScrn);
2619    int UseWide = 0;
2620    int aspect = 0;
2621    Bool fromdim = FALSE;
2622
2623    if((pSiS->VGAEngine == SIS_315_VGA) && (!DIGITAL(pMonitor->features.input_type))) {
2624       if(pMonitor->features.hsize && pMonitor->features.vsize) {
2625	  aspect = (pMonitor->features.hsize * 1000) / pMonitor->features.vsize;
2626	  if(aspect >= 1400) UseWide = 1;
2627	  fromdim = TRUE;
2628       } else if((PREFERRED_TIMING_MODE(pMonitor->features.msc)) &&
2629		 (pMonitor->det_mon[0].type == DT)) {
2630	  aspect = (pMonitor->det_mon[0].section.d_timings.h_active * 1000) /
2631			pMonitor->det_mon[0].section.d_timings.v_active;
2632	  if(aspect >= 1400) UseWide = 1;
2633       }
2634       if(aspect) {
2635	  xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
2636		"According to %s, CRT%d aspect ratio is %.2f:1 (%s)\n",
2637		fromdim ? "DDC size" : "preferred mode",
2638		crtnum, (float)aspect / 1000.0, UseWide ? "wide" : "normal");
2639       } else {
2640	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2641		"Unable to determine CRT%d aspect ratio, assuming \"normal\"\n",
2642		crtnum);
2643       }
2644    }
2645
2646    if((crtnum == 1) && (pSiS->SiS_Pr->SiS_UseWide == -1)) {
2647       pSiS->SiS_Pr->SiS_UseWide = UseWide;
2648    } else if((crtnum == 2) && (pSiS->SiS_Pr->SiS_UseWideCRT2 == -1)) {
2649       pSiS->SiS_Pr->SiS_UseWideCRT2 = UseWide;
2650    }
2651}
2652
2653static Bool
2654SiSMakeOwnModeList(ScrnInfoPtr pScrn, Bool acceptcustommodes, Bool includelcdmodes,
2655                   Bool isfordvi, Bool *havecustommodes, Bool fakecrt2modes, Bool IsForCRT2)
2656{
2657    DisplayModePtr tempmode, delmode, mymodes;
2658
2659    if((mymodes = SiSBuildBuiltInModeList(pScrn, includelcdmodes, isfordvi, fakecrt2modes, IsForCRT2))) {
2660       if(!acceptcustommodes) {
2661	  while(pScrn->monitor->Modes)
2662             xf86DeleteMode(&pScrn->monitor->Modes, pScrn->monitor->Modes);
2663	  pScrn->monitor->Modes = mymodes;
2664       } else {
2665	  delmode = pScrn->monitor->Modes;
2666	  while(delmode) {
2667	     if(delmode->type & M_T_DEFAULT) {
2668	        tempmode = delmode->next;
2669	        xf86DeleteMode(&pScrn->monitor->Modes, delmode);
2670	        delmode = tempmode;
2671	     } else {
2672	        delmode = delmode->next;
2673	     }
2674	  }
2675	  /* Link default modes AFTER user ones */
2676	  if((tempmode = pScrn->monitor->Modes)) {
2677	     *havecustommodes = TRUE;
2678	     while(tempmode) {
2679	        if(!tempmode->next) break;
2680	        else tempmode = tempmode->next;
2681	     }
2682	     tempmode->next = mymodes;
2683	     mymodes->prev = tempmode;
2684	  } else {
2685	     pScrn->monitor->Modes = mymodes;
2686	  }
2687#if 0
2688	  pScrn->monitor->Modes = mymodes;
2689	  while(mymodes) {
2690	     if(!mymodes->next) break;
2691	     else mymodes = mymodes->next;
2692	  }
2693	  mymodes->next = tempmode;
2694	  if(tempmode) {
2695	     tempmode->prev = mymodes;
2696	  }
2697#endif
2698       }
2699       return TRUE;
2700    } else
2701       return FALSE;
2702}
2703
2704static void
2705SiSPrintModes(ScrnInfoPtr pScrn)
2706{
2707    DisplayModePtr p;
2708    float hsync, refresh = 0.0;
2709    char *desc, *desc2, *prefix, *uprefix, *output;
2710
2711    xf86DrvMsg(pScrn->scrnIndex, pScrn->virtualFrom, "Virtual size is %dx%d "
2712	       "(pitch %d)\n", pScrn->virtualX, pScrn->virtualY,
2713	       pScrn->displayWidth);
2714
2715    if((p = pScrn->modes) == NULL) return;
2716
2717    do {
2718	desc = desc2 = "";
2719	uprefix = " ";
2720	prefix = "Mode";
2721	output = "For CRT device: ";
2722	if(p->HSync > 0.0)      hsync = p->HSync;
2723	else if (p->HTotal > 0) hsync = (float)p->Clock / (float)p->HTotal;
2724	else	                hsync = 0.0;
2725	refresh = 0.0;
2726        if(p->VRefresh > 0.0)   refresh = p->VRefresh;
2727        else if (p->HTotal > 0 && p->VTotal > 0) {
2728	   refresh = p->Clock * 1000.0 / p->HTotal / p->VTotal;
2729	   if(p->Flags & V_INTERLACE) refresh *= 2.0;
2730	   if(p->Flags & V_DBLSCAN)   refresh /= 2.0;
2731	   if(p->VScan > 1)  	      refresh /= p->VScan;
2732        }
2733	if(p->Flags & V_INTERLACE) desc = " (I)";
2734	if(p->Flags & V_DBLSCAN)   desc = " (D)";
2735	if(p->VScan > 1) 	   desc2 = " (VScan)";
2736#ifdef M_T_USERDEF
2737	if(p->type & M_T_USERDEF)  uprefix = "*";
2738#endif
2739	if(p->type & M_T_BUILTIN)       {
2740	   prefix = "Built-in mode";
2741	   output = "";
2742	} else if (p->type & M_T_DEFAULT) {
2743	   prefix = "Default mode";
2744	} else {
2745	   output = "";
2746	}
2747
2748	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
2749		"%s%s \"%s\" (%dx%d) (%s%.1f MHz, %.1f kHz, %.1f Hz%s%s)\n",
2750		uprefix, prefix, p->name, p->HDisplay, p->VDisplay, output,
2751		p->Clock / 1000.0, hsync, refresh, desc, desc2);
2752
2753	p = p->next;
2754    } while (p != NULL && p != pScrn->modes);
2755}
2756
2757Bool SISDetermineLCDACap(ScrnInfoPtr pScrn)
2758{
2759    SISPtr pSiS = SISPTR(pScrn);
2760
2761    if( ((pSiS->ChipType == SIS_650)    ||
2762         (pSiS->ChipType == SIS_315PRO) ||
2763         (pSiS->ChipType >= SIS_661))		&&
2764	(pSiS->ChipType != XGI_20)		&&
2765        (pSiS->VBFlags2 & VB2_SISLCDABRIDGE)	&&
2766	(pSiS->VESA != 1) ) {
2767       return TRUE;
2768    }
2769    return FALSE;
2770}
2771
2772void SISSaveDetectedDevices(ScrnInfoPtr pScrn)
2773{
2774    SISPtr  pSiS = SISPTR(pScrn);
2775    /* Backup detected CRT2 devices */
2776    pSiS->detectedCRT2Devices = pSiS->VBFlags & (CRT2_LCD|CRT2_TV|CRT2_VGA|TV_AVIDEO|TV_SVIDEO|
2777                                                 TV_SCART|TV_HIVISION|TV_YPBPR);
2778}
2779
2780static Bool
2781SISCheckBIOS(SISPtr pSiS, UShort mypciid, UShort mypcivendor, int biossize)
2782{
2783    UShort romptr, pciid;
2784
2785    if(!pSiS->BIOS) return FALSE;
2786
2787    if((pSiS->BIOS[0] != 0x55) || (pSiS->BIOS[1] != 0xaa)) return FALSE;
2788
2789    romptr = pSiS->BIOS[0x18] | (pSiS->BIOS[0x19] << 8);
2790    if(romptr > (biossize - 8)) return FALSE;
2791    if((pSiS->BIOS[romptr]   != 'P') || (pSiS->BIOS[romptr+1] != 'C') ||
2792       (pSiS->BIOS[romptr+2] != 'I') || (pSiS->BIOS[romptr+3] != 'R')) return FALSE;
2793
2794    pciid = pSiS->BIOS[romptr+4] | (pSiS->BIOS[romptr+5] << 8);
2795    if(pciid != mypcivendor) return FALSE;
2796
2797    pciid = pSiS->BIOS[romptr+6] | (pSiS->BIOS[romptr+7] << 8);
2798    if(pciid != mypciid) return FALSE;
2799
2800    return TRUE;
2801}
2802
2803static void
2804SiS_LoadInitVBE(ScrnInfoPtr pScrn)
2805{
2806    SISPtr pSiS = SISPTR(pScrn);
2807
2808    /* Don't load the VBE module for secondary
2809     * cards which sisfb POSTed. We don't want
2810     * int10 to overwrite our set up (such as
2811     * disabled a0000 memory address decoding).
2812     * We don't need the VBE anyway because
2813     * the card will never be in text mode,
2814     * and we can restore graphics modes just
2815     * perfectly.
2816     */
2817    if( !pSiS->Primary &&
2818        pSiS->sisfbcardposted)
2819       return;
2820
2821    if(pSiS->pVbe) return;
2822
2823    if(xf86LoadSubModule(pScrn, "vbe")) {
2824#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,99,0,0)
2825       pSiS->pVbe = VBEInit(pSiS->pInt, pSiS->pEnt->index);
2826#else
2827       pSiS->pVbe = VBEExtendedInit(pSiS->pInt, pSiS->pEnt->index,
2828	                SET_BIOS_SCRATCH | RESTORE_BIOS_SCRATCH);
2829#endif
2830    }
2831
2832    if(!pSiS->pVbe) {
2833       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2834	   "Failed to load/initialize vbe module\n");
2835    }
2836}
2837
2838#ifdef SIS_PC_PLATFORM
2839static void
2840SiS_MapVGAMem(ScrnInfoPtr pScrn)
2841{
2842    SISPtr pSiS = SISPTR(pScrn);
2843
2844    /* Map 64k VGA window for saving/restoring CGA fonts */
2845    pSiS->VGAMapSize = 0x10000;
2846    pSiS->VGAMapPhys = 0;	/* Default */
2847    if((!pSiS->Primary) || (!pSiS->VGADecodingEnabled)) {
2848       /* If card is secondary or if a0000-address decoding
2849        * is disabled, set Phys to beginning of our video RAM.
2850	*/
2851       pSiS->VGAMapPhys = PCI_REGION_BASE(pSiS->PciInfo, 0, REGION_MEM);
2852    }
2853    if(!SiSVGAMapMem(pScrn)) {
2854       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2855	  "Failed to map VGA memory (0x%lx), can't save/restore console fonts\n",
2856	  pSiS->VGAMapPhys);
2857    }
2858}
2859#endif
2860
2861static void
2862SiS_CheckKernelFB(ScrnInfoPtr pScrn)
2863{
2864    SISPtr pSiS = SISPTR(pScrn);
2865    int        fd, i;
2866    CARD32     sisfbinfosize = 0, sisfbversion;
2867    sisfb_info *mysisfbinfo;
2868    char       name[16];
2869
2870    pSiS->donttrustpdc = FALSE;
2871    pSiS->sisfbpdc = 0xff;
2872    pSiS->sisfbpdca = 0xff;
2873    pSiS->sisfblcda = 0xff;
2874    pSiS->sisfbscalelcd = -1;
2875    pSiS->sisfbspecialtiming = CUT_NONE;
2876    pSiS->sisfb_haveemi = FALSE;
2877    pSiS->sisfbfound = FALSE;
2878    pSiS->sisfb_tvposvalid = FALSE;
2879    pSiS->sisfbdevname[0] = 0;
2880    pSiS->sisfb_havelock = FALSE;
2881    pSiS->sisfbHaveNewHeapDef = FALSE;
2882    pSiS->sisfbHeapSize = 0;
2883    pSiS->sisfbVideoOffset = 0;
2884    pSiS->sisfbxSTN = FALSE;
2885    pSiS->sisfbcanpost = FALSE;   /* (Old) sisfb can't POST card */
2886    pSiS->sisfbcardposted = TRUE; /* If (old) sisfb is running, card must have been POSTed */
2887    pSiS->sisfbprimary = FALSE;   /* (Old) sisfb doesn't know */
2888
2889    if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
2890
2891       i = 0;
2892       do {
2893
2894	  if(i <= 7) {
2895             sprintf(name, "/dev/fb%1d", i);
2896	  } else {
2897	     sprintf(name, "/dev/fb/%1d", (i - 8));
2898	  }
2899
2900          if((fd = open(name, O_RDONLY)) != -1) {
2901
2902	     Bool gotit = FALSE;
2903
2904 	     if(!ioctl(fd, SISFB_GET_INFO_SIZE, &sisfbinfosize)) {
2905 		if((mysisfbinfo = xalloc(sisfbinfosize))) {
2906 		   if(!ioctl(fd, (SISFB_GET_INFO | (sisfbinfosize << 16)), mysisfbinfo)) {
2907 		      gotit = TRUE;
2908 		   } else {
2909 		      xfree(mysisfbinfo);
2910 		      mysisfbinfo = NULL;
2911 		   }
2912 		}
2913 	     } else {
2914 		if((mysisfbinfo = xalloc(sizeof(*mysisfbinfo) + 16))) {
2915 		   if(!ioctl(fd, SISFB_GET_INFO_OLD, mysisfbinfo)) {
2916 		      gotit = TRUE;
2917		      xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2918				"Possibly old version of sisfb detected. Please update.\n");
2919		   } else {
2920		      xfree(mysisfbinfo);
2921		      mysisfbinfo = NULL;
2922		   }
2923		}
2924	     }
2925
2926	     if(gotit) {
2927
2928		if(mysisfbinfo->sisfb_id == SISFB_ID) {
2929
2930		   sisfbversion = (mysisfbinfo->sisfb_version << 16) |
2931				  (mysisfbinfo->sisfb_revision << 8) |
2932				  (mysisfbinfo->sisfb_patchlevel);
2933
2934	           if(sisfbversion >= SISFB_VERSION(1, 5, 8)) {
2935		      /* Added PCI bus/slot/func into in sisfb Version 1.5.08.
2936		       * Check this to make sure we run on the same card as sisfb
2937		       */
2938		      if((mysisfbinfo->sisfb_pcibus  == pSiS->PciBus)    &&
2939			 (mysisfbinfo->sisfb_pcislot == pSiS->PciDevice) &&
2940			 (mysisfbinfo->sisfb_pcifunc == pSiS->PciFunc)) {
2941			 pSiS->sisfbfound = TRUE;
2942		      }
2943		   } else pSiS->sisfbfound = TRUE;
2944
2945		   if(pSiS->sisfbfound) {
2946		      xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
2947			     "%s: SiS kernel fb driver (sisfb) %d.%d.%d detected (PCI:%02d:%02d.%d)\n",
2948				&name[5],
2949				mysisfbinfo->sisfb_version,
2950				mysisfbinfo->sisfb_revision,
2951				mysisfbinfo->sisfb_patchlevel,
2952				pSiS->PciBus,
2953				pSiS->PciDevice,
2954				pSiS->PciFunc);
2955
2956		      /* Added version/rev/pl in sisfb 1.4.0 */
2957		      if(mysisfbinfo->sisfb_version == 0) {
2958			 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2959				"Old version of sisfb found. Please update.\n");
2960		      }
2961		      /* Basically, we can't trust the pdc register if sisfb is loaded */
2962		      pSiS->donttrustpdc = TRUE;
2963		      pSiS->sisfbHeapStart = mysisfbinfo->heapstart;
2964
2965		      if(sisfbversion >= SISFB_VERSION(1, 7, 20)) {
2966			 pSiS->sisfbHeapSize = mysisfbinfo->sisfb_heapsize;
2967			 pSiS->sisfbVideoOffset = mysisfbinfo->sisfb_videooffset;
2968			 pSiS->sisfbHaveNewHeapDef = TRUE;
2969			 pSiS->sisfbFSTN = mysisfbinfo->sisfb_curfstn;
2970			 pSiS->sisfbDSTN = mysisfbinfo->sisfb_curdstn;
2971			 pSiS->sisfbxSTN = TRUE;
2972			 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
2973				"sisfb: memory heap at %dKB, size %dKB, viewport at %dKB\n",
2974				(int)pSiS->sisfbHeapStart, (int)pSiS->sisfbHeapSize,
2975				(int)pSiS->sisfbVideoOffset/1024);
2976		      } else {
2977			 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
2978				"sisfb: memory heap at %dKB\n", (int)pSiS->sisfbHeapStart);
2979		      }
2980		      xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
2981				"sisfb: using video mode 0x%02x\n", mysisfbinfo->fbvidmode);
2982		      pSiS->OldMode = mysisfbinfo->fbvidmode;
2983		      if(sisfbversion >= SISFB_VERSION(1, 5, 6)) {
2984			 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
2985				"sisfb: using %s, reserved %dK\n",
2986				(mysisfbinfo->sisfb_caps & 0x40) ? "SiS300 series Turboqueue" :
2987				   (mysisfbinfo->sisfb_caps & 0x20) ? "SiS315/330/340 series AGP command queue" :
2988				      (mysisfbinfo->sisfb_caps & 0x10) ? "SiS315/330/340 series VRAM command queue" :
2989					(mysisfbinfo->sisfb_caps & 0x08) ? "SiS315/330/340 series MMIO mode" :
2990					   "no command queue",
2991				(int)mysisfbinfo->sisfb_tqlen);
2992		      }
2993		      if(sisfbversion >= SISFB_VERSION(1, 5, 10)) {
2994			 /* We can trust the pdc value if sisfb is of recent version */
2995			 if(pSiS->VGAEngine == SIS_300_VGA) pSiS->donttrustpdc = FALSE;
2996		      }
2997		      if(sisfbversion >= SISFB_VERSION(1, 5, 11)) {
2998			 if(pSiS->VGAEngine == SIS_300_VGA) {
2999			    /* As of 1.5.11, sisfb saved the register for us (300 series) */
3000			    pSiS->sisfbpdc = mysisfbinfo->sisfb_lcdpdc;
3001			    if(!pSiS->sisfbpdc) pSiS->sisfbpdc = 0xff;
3002			 }
3003		      }
3004		      if(sisfbversion >= SISFB_VERSION(1, 5, 14)) {
3005			 if(pSiS->VGAEngine == SIS_315_VGA) {
3006			    pSiS->sisfblcda = mysisfbinfo->sisfb_lcda;
3007			 }
3008		      }
3009		      if(sisfbversion >= SISFB_VERSION(1, 6, 13)) {
3010			 pSiS->sisfbscalelcd = mysisfbinfo->sisfb_scalelcd;
3011			 pSiS->sisfbspecialtiming = mysisfbinfo->sisfb_specialtiming;
3012		      }
3013		      if(sisfbversion >= SISFB_VERSION(1, 6, 16)) {
3014			 if(pSiS->VGAEngine == SIS_315_VGA) {
3015			    pSiS->donttrustpdc = FALSE;
3016			    pSiS->sisfbpdc = mysisfbinfo->sisfb_lcdpdc;
3017			    if(sisfbversion >= SISFB_VERSION(1, 6, 24)) {
3018			       pSiS->sisfb_haveemi = mysisfbinfo->sisfb_haveemi ? TRUE : FALSE;
3019			       pSiS->sisfb_haveemilcd = TRUE;  /* will match most cases */
3020			       pSiS->sisfb_emi30 = mysisfbinfo->sisfb_emi30;
3021			       pSiS->sisfb_emi31 = mysisfbinfo->sisfb_emi31;
3022			       pSiS->sisfb_emi32 = mysisfbinfo->sisfb_emi32;
3023			       pSiS->sisfb_emi33 = mysisfbinfo->sisfb_emi33;
3024			    }
3025			    if(sisfbversion >= SISFB_VERSION(1, 6, 25)) {
3026			       pSiS->sisfb_haveemilcd = mysisfbinfo->sisfb_haveemilcd ? TRUE : FALSE;
3027			    }
3028			    if(sisfbversion >= SISFB_VERSION(1, 6, 31)) {
3029			       pSiS->sisfbpdca = mysisfbinfo->sisfb_lcdpdca;
3030			    } else {
3031			       if(pSiS->sisfbpdc) {
3032				  pSiS->sisfbpdca = (pSiS->sisfbpdc & 0xf0) >> 3;
3033				  pSiS->sisfbpdc  = (pSiS->sisfbpdc & 0x0f) << 1;
3034			       } else {
3035				  pSiS->sisfbpdca = pSiS->sisfbpdc = 0xff;
3036			       }
3037			    }
3038			 }
3039		      }
3040		      if(sisfbversion >= SISFB_VERSION(1, 7, 0)) {
3041		         pSiS->sisfb_havelock = TRUE;
3042			 if(sisfbversion >= SISFB_VERSION(1, 7, 1)) {
3043			    pSiS->sisfb_tvxpos = mysisfbinfo->sisfb_tvxpos;
3044			    pSiS->sisfb_tvypos = mysisfbinfo->sisfb_tvypos;
3045			    pSiS->sisfb_tvposvalid = TRUE;
3046			 }
3047		      }
3048		      if(sisfbversion >= SISFB_VERSION(1, 8, 7)) {
3049			 pSiS->sisfbcanpost = (mysisfbinfo->sisfb_can_post) ? TRUE : FALSE;
3050			 pSiS->sisfbcardposted = (mysisfbinfo->sisfb_card_posted) ? TRUE : FALSE;
3051			 pSiS->sisfbprimary = (mysisfbinfo->sisfb_was_boot_device) ? TRUE : FALSE;
3052			 /* Validity check */
3053			 if(!pSiS->sisfbcardposted) {
3054			    pSiS->sisfbprimary = FALSE;
3055			 }
3056		      }
3057		   }
3058	        }
3059		xfree(mysisfbinfo);
3060		mysisfbinfo = NULL;
3061	     }
3062	     close (fd);
3063          }
3064	  i++;
3065       } while((i <= 15) && (!pSiS->sisfbfound));
3066
3067       if(pSiS->sisfbfound) {
3068          strncpy(pSiS->sisfbdevname, name, 15);
3069       } else {
3070          xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "sisfb not found\n");
3071       }
3072    }
3073
3074    if(!pSiS->sisfbfound) {
3075       pSiS->sisfbcardposted = FALSE;
3076    }
3077}
3078
3079static void
3080SiSPseudo(ScrnInfoPtr pScrn)
3081{
3082}
3083
3084/* PreInit()
3085 *
3086 * Mandatory
3087 */
3088static Bool
3089SISPreInit(ScrnInfoPtr pScrn, int flags)
3090{
3091    SISPtr pSiS;
3092#ifdef SISDUALHEAD
3093    SISEntPtr pSiSEnt = NULL;
3094#endif
3095    MessageType from;
3096    UChar usScratchCR17, usScratchCR32, usScratchCR63;
3097    UChar usScratchSR1F, srlockReg, crlockReg;
3098    unsigned int i;
3099    int pix24flags, temp;
3100    ClockRangePtr clockRanges;
3101    xf86MonPtr pMonitor = NULL;
3102    Bool didddc2, fromDDC, crt1freqoverruled = FALSE;
3103    UChar CR5F, tempreg;
3104#if defined(SISMERGED) || defined(SISDUALHEAD)
3105    DisplayModePtr first, p, n;
3106#endif
3107#ifdef SISMERGED
3108    Bool crt2freqoverruled = FALSE;
3109#endif
3110
3111    static const char *ddcsstr = "CRT%d DDC monitor info: *******************************************\n";
3112    static const char *ddcestr = "End of CRT%d DDC monitor info *************************************\n";
3113    static const char *subshstr = "Substituting missing CRT%d monitor HSync range by DDC data\n";
3114    static const char *subsvstr = "Substituting missing CRT%d monitor VRefresh range by DDC data\n";
3115    static const char *saneh = "Correcting %s CRT%d monitor HSync range\n";
3116    static const char *sanev = "Correcting %s CRT%d monitor VRefresh range\n";
3117#ifdef SISMERGED
3118    static const char *mergednocrt1 = "CRT1 not detected or forced off. %s.\n";
3119    static const char *mergednocrt2 = "No CRT2 output selected or no video bridge detected. %s.\n";
3120    static const char *mergeddisstr = "MergedFB mode disabled";
3121    static const char *modesforstr = "Modes for CRT%d: **************************************************\n";
3122    static const char *crtsetupstr = "*************************** CRT%d setup ***************************\n";
3123    static const char *crt2monname = "CRT2";
3124#endif
3125#if defined(SISDUALHEAD) || defined(SISMERGED)
3126    static const char *notsuitablestr = "Not using mode \"%s\" (not suitable for %s mode)\n";
3127#endif
3128
3129    if(flags & PROBE_DETECT) {
3130
3131       vbeInfoPtr   pVbe;
3132
3133       if(xf86LoadSubModule(pScrn, "vbe")) {
3134          int index = xf86GetEntityInfo(pScrn->entityList[0])->index;
3135#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,99,0,0)
3136	  if((pVbe = VBEInit(NULL, index)))
3137#else
3138          if((pVbe = VBEExtendedInit(NULL, index, 0)))
3139#endif
3140          {
3141             ConfiguredMonitor = vbeDoEDID(pVbe, NULL);
3142             vbeFree(pVbe);
3143          }
3144       }
3145       return TRUE;
3146    }
3147
3148    /*
3149     * Note: This function is only called once at server startup, and
3150     * not at the start of each server generation.  This means that
3151     * only things that are persistent across server generations can
3152     * be initialised here.  xf86Screens[] is the array of all screens,
3153     * (pScrn is a pointer to one of these).  Privates allocated using
3154     * xf86AllocateScrnInfoPrivateIndex() are too, and should be used
3155     * for data that must persist across server generations.
3156     *
3157     * Per-generation data should be allocated with
3158     * AllocateScreenPrivateIndex() from the ScreenInit() function.
3159     */
3160
3161    /* Check the number of entities, and fail if it isn't one. */
3162    if(pScrn->numEntities != 1) {
3163       SISErrorLog(pScrn, "Number of entities is not 1\n");
3164       return FALSE;
3165    }
3166
3167    /* Due to the liberal license terms this is needed for
3168     * keeping the copyright notice readable and intact in
3169     * binary distributions. Removing this is a copyright
3170     * infringement. Please read the license terms above.
3171     */
3172
3173    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3174	"SiS driver (%d/%02d/%02d-%d, compiled for " SISMYSERVERNAME " %d.%d.%d.%d)\n",
3175	SISDRIVERVERSIONYEAR + 2000, SISDRIVERVERSIONMONTH,
3176	SISDRIVERVERSIONDAY, SISDRIVERREVISION,
3177#ifdef XORG_VERSION_CURRENT
3178	XORG_VERSION_MAJOR, XORG_VERSION_MINOR,
3179	XORG_VERSION_PATCH, XORG_VERSION_SNAP
3180#else
3181	XF86_VERSION_MAJOR, XF86_VERSION_MINOR,
3182	XF86_VERSION_PATCH, XF86_VERSION_SNAP
3183#endif
3184	);
3185    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3186	"Copyright (C) 2001-2005 Thomas Winischhofer <thomas@winischhofer.net> and others\n");
3187    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3188	"*** See http://www.winischhofer.eu/linuxsisvga.shtml\n");
3189    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3190	"*** for documentation and updates.\n");
3191
3192#ifdef XORG_VERSION_CURRENT
3193#if 0  /* no prototype yet */
3194    if(xorgGetVersion() != XORG_VERSION_CURRENT) {
3195       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
3196         "This driver binary is not compiled for this version of " SISMYSERVERNAME "\n");
3197    }
3198#endif
3199#else
3200#if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4,2,99,0,0)
3201    if(xf86GetVersion() != XF86_VERSION_CURRENT) {
3202       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
3203         "This driver binary is not compiled for this version of " SISMYSERVERNAME "\n");
3204    }
3205#endif
3206#endif
3207
3208    /* Allocate the SISRec driverPrivate */
3209    if(!SISGetRec(pScrn)) {
3210       SISErrorLog(pScrn, "Could not allocate memory for pSiS private\n");
3211       return FALSE;
3212    }
3213    pSiS = SISPTR(pScrn);
3214    pSiS->pScrn = pScrn;
3215
3216    pSiS->pInt = NULL;
3217
3218    /* Save PCI Domain Base */
3219#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,99,0,0)
3220    pSiS->IODBase = 0;
3221#else
3222    pSiS->IODBase = pScrn->domainIOBase;
3223#endif
3224
3225    /* Get the entity, and make sure it is PCI. */
3226    pSiS->pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
3227    if(pSiS->pEnt->location.type != BUS_PCI) {
3228       SISErrorLog(pScrn, "Entity's bus type is not PCI\n");
3229       goto my_error_0;
3230    }
3231
3232#ifdef SISDUALHEAD
3233    /* Allocate an entity private if necessary */
3234    if(xf86IsEntityShared(pScrn->entityList[0])) {
3235       pSiSEnt = xf86GetEntityPrivate(pScrn->entityList[0], SISEntityIndex)->ptr;
3236       pSiS->entityPrivate = pSiSEnt;
3237
3238       /* If something went wrong, quit here */
3239       if((pSiSEnt->DisableDual) || (pSiSEnt->ErrorAfterFirst)) {
3240	  SISErrorLog(pScrn, "First head encountered fatal error, aborting...\n");
3241	  goto my_error_0;
3242       }
3243    }
3244#endif
3245
3246    /* Find the PCI info for this screen */
3247    pSiS->PciInfo = xf86GetPciInfoForEntity(pSiS->pEnt->index);
3248    pSiS->PciBus = PCI_CFG_BUS(pSiS->PciInfo);    /*SIS_PCI_BUS(pSiS->PciInfo);*/
3249    pSiS->PciDevice = PCI_CFG_DEV(pSiS->PciInfo); /*SIS_PCI_DEVICE(pSiS->PciInfo);*/
3250    pSiS->PciFunc = PCI_CFG_FUNC(pSiS->PciInfo);  /*SIS_PCI_FUNC(pSiS->PciInfo);*/
3251
3252    pSiS->PciTag = pciTag(PCI_DEV_BUS(pSiS->PciInfo),
3253			  PCI_DEV_DEV(pSiS->PciInfo),
3254			  PCI_DEV_FUNC(pSiS->PciInfo));
3255
3256#ifdef SIS_NEED_MAP_IOP
3257    /********************************************/
3258    /*     THIS IS BROKEN AND WON'T WORK        */
3259    /* Reasons:                                 */
3260    /* 1) MIPS and ARM have no i/o ports but    */
3261    /* use memory mapped i/o only. The inX/outX */
3262    /* macros in compiler.h are smart enough to */
3263    /* add "IOPortBase" to the port number, but */
3264    /* "IOPortBase" is never initialized.       */
3265    /* 2) IOPortBase is declared in compiler.h  */
3266    /* itself. So until somebody fixes all      */
3267    /* modules that #include compiler.h to set  */
3268    /* IOPortBase, vga support for MIPS and ARM */
3269    /* is unusable.                             */
3270    /* (In this driver this is solvable because */
3271    /* we have our own vgaHW routines. However, */
3272    /* we use /dev/port for now instead.)       */
3273    /********************************************/
3274    pSiS->IOPAddress = pSiS->IODBase + pSiS->PciInfo->ioBase[2];
3275    if(!SISMapIOPMem(pScrn)) {
3276       SISErrorLog(pScrn, "Could not map I/O port area at 0x%x\n", pSiS->IOPAddress);
3277       goto my_error_0;
3278    } else {
3279       xf86DrvMsg(pScrn->scrnIndex, X_INFO, "I/O port area mapped to %p, size 128\n", pSiS->IOPBase);
3280#if defined(__mips__) || defined(__arm32__)
3281       /* inX/outX macros on these use IOPortBase as offset */
3282       /* This is entirely skrewed. */
3283       IOPortBase = (unsigned int)pSiS->IOPBase;
3284#endif
3285    }
3286#endif
3287
3288    /* Set up i/o port access (for non-x86) */
3289#ifdef SISUSEDEVPORT
3290    if((sisdevport = open("/dev/port", O_RDWR, 0)) == -1) {
3291       SISErrorLog(pScrn, "Failed to open /dev/port for read/write\n");
3292       goto my_error_0;
3293    }
3294    pSiS->sisdevportopen = TRUE;
3295#endif
3296
3297    /*
3298     * Set the Chipset and ChipRev, allowing config file entries to
3299     * override. DANGEROUS!
3300     */
3301    {
3302       SymTabRec *myChipsets = SISChipsets;
3303
3304       if(PCI_DEV_VENDOR_ID(pSiS->PciInfo) == PCI_VENDOR_XGI) {
3305          myChipsets = XGIChipsets;
3306       }
3307
3308       if(pSiS->pEnt->device->chipset && *pSiS->pEnt->device->chipset) {
3309
3310          pScrn->chipset = pSiS->pEnt->device->chipset;
3311          pSiS->Chipset = xf86StringToToken(myChipsets, pScrn->chipset);
3312
3313       } else if(pSiS->pEnt->device->chipID >= 0) {
3314
3315          pSiS->Chipset = pSiS->pEnt->device->chipID;
3316          pScrn->chipset = (char *)xf86TokenToString(myChipsets, pSiS->Chipset);
3317
3318          xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipID override: 0x%04X\n",
3319								pSiS->Chipset);
3320       } else {
3321
3322          pSiS->Chipset = PCI_DEV_DEVICE_ID(pSiS->PciInfo);
3323          pScrn->chipset = (char *)xf86TokenToString(myChipsets, pSiS->Chipset);
3324
3325       }
3326    }
3327
3328    if(pSiS->pEnt->device->chipRev >= 0) {
3329
3330       pSiS->ChipRev = pSiS->pEnt->device->chipRev;
3331       xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipRev override: %d\n",
3332								pSiS->ChipRev);
3333    } else {
3334
3335       pSiS->ChipRev = PCI_DEV_REVISION(pSiS->PciInfo);
3336
3337    }
3338
3339    /*
3340     * This shouldn't happen because such problems should be caught in
3341     * SISProbe(), but check it just in case the user has overridden them.
3342     */
3343    if(pScrn->chipset == NULL) {
3344       SISErrorLog(pScrn, "ChipID 0x%04X is not recognised\n", pSiS->Chipset);
3345       goto my_error_0;
3346    }
3347    if(pSiS->Chipset < 0) {
3348       SISErrorLog(pScrn, "Chipset \"%s\" is not recognised\n", pScrn->chipset);
3349       goto my_error_0;
3350    }
3351
3352    pSiS->SiS6326Flags = 0;
3353
3354    /* Determine VGA engine generation */
3355    switch(pSiS->Chipset) {
3356       case PCI_CHIP_SIS300:
3357       case PCI_CHIP_SIS540:
3358       case PCI_CHIP_SIS630: /* 630 + 730 */
3359          pSiS->VGAEngine = SIS_300_VGA;
3360	  break;
3361       case PCI_CHIP_SIS315H:
3362       case PCI_CHIP_SIS315:
3363       case PCI_CHIP_SIS315PRO:
3364       case PCI_CHIP_SIS550:
3365       case PCI_CHIP_SIS650: /* 650 + 740 */
3366       case PCI_CHIP_SIS330:
3367       case PCI_CHIP_SIS660: /* 660, 661, 741, 760, 761, 670(?), 770 */
3368       case PCI_CHIP_SIS340:
3369       case PCI_CHIP_XGIXG20:
3370       case PCI_CHIP_XGIXG40:
3371          pSiS->VGAEngine = SIS_315_VGA;
3372	  break;
3373       case PCI_CHIP_SIS530:
3374          pSiS->VGAEngine = SIS_530_VGA;
3375	  break;
3376       case PCI_CHIP_SIS6326:
3377          /* Determine SiS6326 revision. According to SiS the differences are:
3378	   * Chip name     Chip type      TV-Out       MPEG II decoder
3379	   * 6326 AGP      Rev. G0/H0     no           no
3380	   * 6326 DVD      Rev. D2        yes          yes
3381	   * 6326          Rev. Cx        yes          yes
3382	   */
3383	  xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3384		"Chipset is SiS6326 %s (revision 0x%02x)\n",
3385		(pSiS->ChipRev == 0xaf) ? "(Ax)" :
3386		   ((pSiS->ChipRev == 0x0a) ? "AGP (G0)" :
3387		      ((pSiS->ChipRev == 0x0b) ? "AGP (H0)" :
3388			 (((pSiS->ChipRev & 0xf0) == 0xd0) ? "DVD (Dx/H0)" :
3389			    (((pSiS->ChipRev & 0xf0) == 0x90) ? "(9x)" :
3390			       (((pSiS->ChipRev & 0xf0) == 0xc0) ? "(Cx)" :
3391				  "(unknown)"))))),
3392		pSiS->ChipRev);
3393	  if((pSiS->ChipRev != 0x0a) && (pSiS->ChipRev != 0x0b)) {
3394	     pSiS->SiS6326Flags |= SIS6326_HASTV;
3395	  }
3396	  /* fall through */
3397       default:
3398	  pSiS->VGAEngine = SIS_OLD_VGA;
3399    }
3400
3401    /* We don't know about the current mode yet */
3402    pSiS->OldMode = 0;
3403
3404    /* Determine whether this is the primary or a secondary
3405     * display adapter. And right here the problem starts:
3406     * On machines with integrated SiS chipsets, the system BIOS
3407     * usually sets VGA_EN on all PCI-to-PCI bridges in the system
3408     * (of which there usually are two: PCI and AGP). This and
3409     * the fact that any PCI card POSTed by sisfb naturally has
3410     * its PCI resources enabled, leads to X assuming that
3411     * there are more than one "primary" cards in the system.
3412     * In this case, X treats ALL cards as "secondary" -
3413     * which by no means is desireable. If sisfb is running,
3414     * we can determine which card really is "primary" (in
3415     * terms of if it's the one that occupies the A0000 area
3416     * etc.) in a better way (Linux 2.6.12 or later). See below.
3417     */
3418    if(!(pSiS->Primary = xf86IsPrimaryPci(pSiS->PciInfo))) {
3419       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3420	   SISMYSERVERNAME " assumes this adapter to be secondary\n");
3421    }
3422
3423    /* Now check if sisfb is running, and if so, retrieve
3424     * all possible info from it. This also resets all
3425     * sisfb_* entries in pSiS regardless of the chipset.
3426     */
3427    SiS_CheckKernelFB(pScrn);
3428
3429    /* Now for that primary/secondary mess: Linux kernel
3430     * 2.6.12 and later knows what card is primary, and so
3431     * does any recent version of sisfb. XFree86/X.org takes
3432     * all adapters as "secondary" if more than one card's
3433     * memory and i/o resources are enabled, and more than
3434     * one PCI bridge in the system has VGA_EN set at server
3435     * start. So, let's start thinking: What is this
3436     * primary/secondary classification needed for anyway?
3437     * (This list might be incomplete for the entire server
3438     * infrastructure, but it's complete as regards the driver's
3439     * purposes of primary/secondary classification.)
3440     *    1) VGA/console font restoring: Here it's irrelevant
3441     *       whether more than one card's resources are enabled
3442     *       at server start or not. Relevant is whether the card
3443     *       occupies the A0000 area at this time. Assuming (?)
3444     *       that this does not change during machine up-time,
3445     *       it suffices to know which device was the boot video
3446     *       device (as determined by Linux 2.6.12 and later).
3447     *       Also, this is only relevant if the card is in text
3448     *       mode; if it's in graphics mode, fonts aren't saved
3449     *       or restored anyway.
3450     *       sisfb tells us if that card is considered the boot
3451     *       video device. The hardware registers tell us if
3452     *       the card's A0000 address decoding is enabled, and if
3453     *       the card currently is in text mode. These three bits
3454     *       of information are enough to decide on whether or not
3455     *       to save/restore fonts.
3456     *    2) POSTing. Same here. Relevant is only whether or not
3457     *       the card has been POSTed once before. POSTing cards
3458     *       on every server start is pretty ugly, especially
3459     *       if a framebuffer driver is already handling it.
3460     * SiS/XGI cards POSTed by sisfb can coexist well with other
3461     * active adapters. So we trust sisfb's information more
3462     * than X's (especially as we only use this information for
3463     * console font restoring and eventual POSTing.)
3464     * What we still need is a way to find out about all this if
3465     * sisfb is not running....
3466     */
3467    if(!pSiS->Primary && pSiS->sisfbprimary) {
3468       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3469		"sisfb reports this adapter to be primary. Seems more reliable.\n");
3470       pSiS->Primary = TRUE;
3471    }
3472
3473    /* If the card is "secondary" and has not been
3474     * POSTed by sisfb, POST it now through int10.
3475     * For cards POSTed by sisfb, we definitely don't
3476     * want that as it messes up our set up (eg. the
3477     * disabled A0000 area).
3478     * The int10 module decides on its own if the
3479     * card is primary or secondary. Since it uses
3480     * the generic technique described above, and since
3481     * for "secondary" cards it needs a real PCI BIOS
3482     * ROM, and since integrated chips don't have such
3483     * a PCI BIOS ROM, int10 will naturally fail to
3484     * find/read the BIOS on such machines. Great.
3485     * Using the integrated graphics as "secondary"
3486     * (which it will be as soon as X finds more than
3487     * one card's mem and i/o resources enabled, and more
3488     * than one PCI bridge's VGA_EN bit set during server
3489     * start) will therefore prevent us from restoring
3490     * the mode using the VBE. That means real fun if
3491     * the integrated chip is set up to use the video
3492     * bridge output for text mode (which is something
3493     * the driver doesn't really support since it's done
3494     * pretty much differently on every machine.)
3495     */
3496#if !defined(__alpha__)
3497    if(!pSiS->Primary) {
3498       if(!pSiS->sisfbcardposted) {
3499	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3500		"Initializing adapter through int10\n");
3501	  if(xf86LoadSubModule(pScrn, "int10")) {
3502	     pSiS->pInt = xf86InitInt10(pSiS->pEnt->index);
3503	  } else {
3504	     SISErrorLog(pScrn, "Failed to load int10 module\n");
3505	  }
3506       } else {
3507	  xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3508		"Adapter already initialized by sisfb\n");
3509       }
3510    }
3511#endif
3512
3513    /* Get the address of our relocated IO registers.
3514     * These are enabled by the hardware during cold boot, and
3515     * by the BIOS. So we can pretty much rely on that these
3516     * are enabled.
3517     */
3518    pSiS->RelIO = (SISIOADDRESS)(PCI_REGION_BASE(pSiS->PciInfo, 2, REGION_IO) + pSiS->IODBase);
3519    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Relocated I/O registers at 0x%lX\n",
3520           (ULong)pSiS->RelIO);
3521
3522    /* Unlock extended registers */
3523    sisSaveUnlockExtRegisterLock(pSiS, &srlockReg, &crlockReg);
3524
3525    /* Is a0000 memory address decoding enabled? */
3526    pSiS->VGADecodingEnabled = TRUE;
3527    switch(pSiS->VGAEngine) {
3528    case SIS_OLD_VGA:
3529       /* n/a */
3530       break;
3531    case SIS_530_VGA:
3532       inSISIDXREG(SISSR, 0x3d, tempreg);
3533       if(tempreg & 0x04) pSiS->VGADecodingEnabled = FALSE;
3534       break;
3535    case SIS_300_VGA:
3536    case SIS_315_VGA:
3537       inSISIDXREG(SISSR, 0x20, tempreg);
3538       if(tempreg & 0x04) pSiS->VGADecodingEnabled = FALSE;
3539       break;
3540    }
3541
3542    if(!pSiS->VGADecodingEnabled) {
3543       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3544		"Standard VGA (0xA0000) memory address decoding is disabled\n");
3545    }
3546
3547#ifdef SIS_PC_PLATFORM
3548    /* Map 64k VGA window for saving/restoring CGA fonts.
3549     * For secondary cards or if A0000 address decoding
3550     * is disabled, this will map the beginning of the
3551     * linear (PCI) video RAM instead.
3552     */
3553    SiS_MapVGAMem(pScrn);
3554#endif
3555
3556#ifndef XSERVER_LIBPCIACCESS
3557    /* Set operating state */
3558
3559    /* 1. memory */
3560    /* [ResUnusedOpr: Resource decoded by hw, but not used]
3561     * [ResDisableOpr: Resource is not decoded by hw]
3562     * So, if a0000 memory decoding is disabled, one could
3563     * argue that we may say so, too. Hm. Quite likely that
3564     * the VBE (via int10) will eventually enable it. So we
3565     * cowardly say unused instead.
3566     */
3567    xf86SetOperatingState(resVgaMem, pSiS->pEnt->index, ResUnusedOpr);
3568
3569    /* 2. i/o */
3570    /* Although we only use the relocated i/o ports, the hardware
3571     * also decodes the standard VGA port range. This could in
3572     * theory be disabled, but I don't dare to do this; in case of
3573     * a server crash, the card would be entirely dead. Also, this
3574     * would prevent int10 and the VBE from working at all. Generic
3575     * access control through the PCI configuration registers does
3576     * nicely anyway.
3577     */
3578    xf86SetOperatingState(resVgaIo, pSiS->pEnt->index, ResUnusedOpr);
3579
3580    /* Operations for which memory access is required */
3581    pScrn->racMemFlags = RAC_FB | RAC_COLORMAP | RAC_CURSOR | RAC_VIEWPORT;
3582
3583    /* Operations for which I/O access is required */
3584    pScrn->racIoFlags = RAC_COLORMAP | RAC_CURSOR | RAC_VIEWPORT;
3585
3586#endif
3587
3588    /* Load ramdac module */
3589    if(!xf86LoadSubModule(pScrn, "ramdac")) {
3590       SISErrorLog(pScrn, "Could not load ramdac module\n");
3591       goto my_error_1;
3592    }
3593
3594    /* Set pScrn->monitor */
3595    pScrn->monitor = pScrn->confScreen->monitor;
3596
3597    /* Reset some entries */
3598    pSiS->SiSFastVidCopy = SiSVidCopyGetDefault();
3599    pSiS->SiSFastMemCopy = SiSVidCopyGetDefault();
3600    pSiS->SiSFastVidCopyFrom = SiSVidCopyGetDefault();
3601    pSiS->SiSFastMemCopyFrom = SiSVidCopyGetDefault();
3602    pSiS->SiSFastVidCopyDone = FALSE;
3603#ifdef SIS_USE_XAA
3604    pSiS->RenderCallback = NULL;
3605#endif
3606#ifdef SIS_USE_EXA
3607    pSiS->ExaRenderCallback = NULL;
3608#endif
3609    pSiS->InitAccel = SiSPseudo;
3610    pSiS->SyncAccel = SiSPseudo;
3611    pSiS->FillRect  = NULL;
3612    pSiS->BlitRect  = NULL;
3613
3614    /* Always do a ValidMode() inside Switchmode() */
3615    pSiS->skipswitchcheck = FALSE;
3616
3617    /* Determine chipset and its capabilities in detail */
3618    pSiS->ChipFlags = 0;
3619    pSiS->SiS_SD_Flags = pSiS->SiS_SD2_Flags = 0;
3620    pSiS->SiS_SD3_Flags = pSiS->SiS_SD4_Flags = 0;
3621    pSiS->HWCursorMBufNum = pSiS->HWCursorCBufNum = 0;
3622    pSiS->NeedFlush = FALSE;
3623    pSiS->NewCRLayout = FALSE;
3624    pSiS->mmioSize = 64;
3625
3626    switch(pSiS->Chipset) {
3627       case PCI_CHIP_SIS530:
3628	  pSiS->ChipType = SIS_530;
3629	  break;
3630       case PCI_CHIP_SIS300:
3631	  pSiS->ChipType = SIS_300;
3632	  pSiS->SiS_SD_Flags |= SiS_SD_IS300SERIES;
3633	  break;
3634       case PCI_CHIP_SIS540:
3635	  pSiS->ChipType = SIS_540;
3636	  pSiS->SiS_SD_Flags |= SiS_SD_IS300SERIES;
3637	  break;
3638       case PCI_CHIP_SIS630: /* 630 + 730 */
3639	  pSiS->ChipType = SIS_630;
3640	  if(sis_pci_read_host_bridge_u32(0x00) == 0x07301039) {
3641	     pSiS->ChipType = SIS_730;
3642	  }
3643	  pSiS->SiS_SD_Flags |= SiS_SD_IS300SERIES;
3644	  break;
3645       case PCI_CHIP_SIS315H:
3646	  pSiS->ChipType = SIS_315H;
3647	  pSiS->ChipFlags |= (SiSCF_315Core | SiSCF_MMIOPalette);
3648	  pSiS->SiS_SD_Flags |= SiS_SD_IS315SERIES;
3649	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3650	  pSiS->myCR63 = 0x63;
3651	  break;
3652       case PCI_CHIP_SIS315:
3653	  /* Override for simplicity */
3654	  pSiS->Chipset = PCI_CHIP_SIS315H;
3655	  pSiS->ChipType = SIS_315;
3656	  pSiS->ChipFlags |= (SiSCF_315Core | SiSCF_MMIOPalette);
3657	  pSiS->SiS_SD_Flags |= SiS_SD_IS315SERIES;
3658	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3659	  pSiS->myCR63 = 0x63;
3660	  break;
3661       case PCI_CHIP_SIS315PRO:
3662	  /* Override for simplicity */
3663	  pSiS->Chipset = PCI_CHIP_SIS315H;
3664	  pSiS->ChipType = SIS_315PRO;
3665	  pSiS->ChipFlags |= (SiSCF_315Core | SiSCF_MMIOPalette);
3666	  pSiS->SiS_SD_Flags |= SiS_SD_IS315SERIES;
3667	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3668	  pSiS->myCR63 = 0x63;
3669	  break;
3670       case PCI_CHIP_SIS550:
3671	  pSiS->ChipType = SIS_550;
3672	  pSiS->ChipFlags |= (SiSCF_Integrated | SiSCF_MMIOPalette);
3673	  pSiS->SiS_SD_Flags |= SiS_SD_IS315SERIES;
3674	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3675	  pSiS->myCR63 = 0x63;
3676	  break;
3677       case PCI_CHIP_SIS650: /* 650 + 740 */
3678	  pSiS->ChipType = SIS_650;
3679	  if(sis_pci_read_host_bridge_u32(0x00) == 0x07401039) {
3680	     pSiS->ChipType = SIS_740;
3681	  }
3682	  pSiS->ChipFlags |= (SiSCF_Integrated | SiSCF_Real256ECore | SiSCF_MMIOPalette);
3683	  pSiS->SiS_SD_Flags |= SiS_SD_IS315SERIES;
3684	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3685	  pSiS->myCR63 = 0x63;
3686	  break;
3687       case PCI_CHIP_SIS330:
3688	  pSiS->ChipType = SIS_330;
3689	  pSiS->ChipFlags |= (SiSCF_XabreCore | SiSCF_MMIOPalette);
3690	  pSiS->SiS_SD_Flags |= SiS_SD_IS330SERIES;
3691	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3692	  pSiS->SiS_SD3_Flags |= SiS_SD3_CRT1SATGAIN; /* FIXME ? */
3693	  pSiS->myCR63 = 0x53; /* sic! */
3694	  break;
3695       case PCI_CHIP_SIS660: /* 660, 661, 741, 760, 761, 670(?) */
3696	  {
3697	     ULong hpciid = sis_pci_read_host_bridge_u32(0x00);
3698	     switch(hpciid) {
3699	     case 0x06601039:
3700		pSiS->ChipType = SIS_660;
3701		pSiS->ChipFlags |= SiSCF_Ultra256Core;
3702		pSiS->NeedFlush = TRUE;
3703		break;
3704	     case 0x07601039:
3705		pSiS->ChipType = SIS_760;
3706		pSiS->ChipFlags |= SiSCF_Ultra256Core;
3707		pSiS->NeedFlush = TRUE;
3708		break;
3709	     case 0x07611039:
3710		pSiS->ChipType = SIS_761;
3711		pSiS->ChipFlags |= SiSCF_Ultra256Core;
3712		pSiS->NeedFlush = TRUE;
3713		break;
3714	     case 0x07701039:
3715		pSiS->ChipType = SIS_770;
3716		pSiS->ChipFlags |= SiSCF_Ultra256Core;
3717		pSiS->NeedFlush = TRUE;
3718		break;
3719	     case 0x07411039:
3720		pSiS->ChipType = SIS_741;
3721		pSiS->ChipFlags |= SiSCF_Real256ECore;
3722		break;
3723	     case 0x06611039:
3724	     default:
3725		pSiS->ChipType = SIS_661;
3726		pSiS->ChipFlags |= SiSCF_Real256ECore;
3727		break;
3728	     case 0x06701039:
3729		pSiS->ChipType = SIS_670;
3730		pSiS->ChipFlags |= SiSCF_Real256ECore;
3731	     }
3732	     /* Detection could also be done by CR5C & 0xf8:
3733	      * 0x10 = 661 (CR5F & 0xc0: 0x00 both A0 and A1)
3734	      * 0x80 = 760 (CR5F & 0xc0: 0x00 A0, 0x40 A1)
3735	      * 0x90 = 741 (CR5F & 0xc0: 0x00 A0,A1 0x40 A2)
3736	      * other: 660 (CR5F & 0xc0: 0x00 A0 0x40 A1) (DOA?)
3737	      */
3738	     pSiS->ChipFlags |= (SiSCF_Integrated | SiSCF_MMIOPalette);
3739	     pSiS->SiS_SD_Flags |= SiS_SD_IS330SERIES;
3740	     pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3741	     pSiS->SiS_SD3_Flags |= SiS_SD3_CRT1SATGAIN;
3742	     pSiS->myCR63 = 0x53; /* sic! */
3743	     pSiS->NewCRLayout = TRUE;
3744	  }
3745	  break;
3746       case PCI_CHIP_SIS340:
3747	  pSiS->ChipType = SIS_340;
3748	  pSiS->ChipFlags |= (SiSCF_XabreCore | SiSCF_MMIOPalette);
3749	  pSiS->SiS_SD_Flags |= SiS_SD_IS340SERIES;
3750	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3751	  pSiS->SiS_SD3_Flags |= SiS_SD3_CRT1SATGAIN;
3752	  pSiS->myCR63 = 0x53;
3753	  pSiS->NewCRLayout = TRUE;
3754	  break;
3755       case PCI_CHIP_XGIXG20:
3756	  pSiS->ChipType = XGI_20;
3757	  pSiS->ChipFlags |= (SiSCF_XabreCore | SiSCF_MMIOPalette | SiSCF_IsXGI);
3758	  pSiS->SiS_SD2_Flags |= (SiS_SD2_NOOVERLAY | SiS_SD2_ISXGI);
3759	  pSiS->myCR63 = 0x53;
3760	  pSiS->NewCRLayout = TRUE;
3761	  break;
3762       case PCI_CHIP_XGIXG40:
3763	  pSiS->ChipType = XGI_40;
3764	  pSiS->ChipFlags |= (SiSCF_XabreCore | SiSCF_MMIOPalette | SiSCF_IsXGI);
3765	  pSiS->SiS_SD2_Flags |= (SiS_SD2_SUPPORTXVHUESAT | SiS_SD2_ISXGI);
3766	  pSiS->SiS_SD3_Flags |= SiS_SD3_CRT1SATGAIN;
3767	  pSiS->myCR63 = 0x53;
3768	  pSiS->NewCRLayout = TRUE;
3769	  if(pSiS->ChipRev == 2) pSiS->ChipFlags |= SiSCF_IsXGIV3;
3770	  break;
3771       default:
3772	  pSiS->ChipType = SIS_OLD;
3773	  break;
3774    }
3775
3776    /*
3777     * Now back to real business: Figure out the depth, bpp, etc.
3778     * Set SupportConvert... flags since we use the fb layer which
3779     * supports this conversion. (24to32 seems not implemented though)
3780     * Additionally, determine the size of the HWCursor memory area.
3781     */
3782    switch(pSiS->VGAEngine) {
3783       case SIS_300_VGA:
3784	  pSiS->CursorSize = 4096;
3785	  pix24flags = Support32bppFb;
3786	  break;
3787       case SIS_315_VGA:
3788	  pSiS->CursorSize = 16384;
3789	  pix24flags = Support32bppFb;
3790	  break;
3791       case SIS_530_VGA:
3792	  pSiS->CursorSize = 2048;
3793	  pix24flags = Support32bppFb	  |
3794		       Support24bppFb	  |
3795		       SupportConvert32to24;
3796          break;
3797       default:
3798	  pSiS->CursorSize = 2048;
3799	  pix24flags = Support24bppFb	    |
3800		       SupportConvert32to24 |
3801		       PreferConvert32to24;
3802	  break;
3803    }
3804
3805#ifdef SISDUALHEAD
3806    /* In case of Dual Head, we need to determine if we are the "master" head or
3807     * the "slave" head. In order to do that, we set PrimInit to DONE in the
3808     * shared entity at the end of the first initialization. The second
3809     * initialization then knows that some things have already been done. THIS
3810     * ALWAYS ASSUMES THAT THE FIRST DEVICE INITIALIZED IS THE MASTER!
3811     */
3812    if(xf86IsEntityShared(pScrn->entityList[0])) {
3813       if(pSiSEnt->lastInstance > 0) {
3814	  if(!xf86IsPrimInitDone(pScrn->entityList[0])) {
3815	     /* First Head (always CRT2) */
3816	     pSiS->SecondHead = FALSE;
3817	     pSiSEnt->pScrn_1 = pScrn;
3818	     pSiSEnt->CRT1ModeNo = pSiSEnt->CRT2ModeNo = -1;
3819	     pSiSEnt->CRT2ModeSet = FALSE;
3820	     pSiS->DualHeadMode = TRUE;
3821	     pSiSEnt->DisableDual = FALSE;
3822	     pSiSEnt->BIOS = NULL;
3823	     pSiSEnt->ROM661New = FALSE;
3824	     pSiSEnt->HaveXGIBIOS = FALSE;
3825	     pSiSEnt->SiS_Pr = NULL;
3826	     pSiSEnt->RenderAccelArray = NULL;
3827	     pSiSEnt->SiSFastVidCopy = pSiSEnt->SiSFastMemCopy = NULL;
3828	     pSiSEnt->SiSFastVidCopyFrom = pSiSEnt->SiSFastMemCopyFrom = NULL;
3829	  } else {
3830	     /* Second Head (always CRT1) */
3831	     pSiS->SecondHead = TRUE;
3832	     pSiSEnt->pScrn_2 = pScrn;
3833	     pSiS->DualHeadMode = TRUE;
3834	  }
3835       } else {
3836	  /* Only one screen in config file - disable dual head mode */
3837	  pSiS->SecondHead = FALSE;
3838	  pSiS->DualHeadMode = FALSE;
3839	  pSiSEnt->DisableDual = TRUE;
3840       }
3841    } else {
3842       /* Entity is not shared - disable dual head mode */
3843       pSiS->SecondHead = FALSE;
3844       pSiS->DualHeadMode = FALSE;
3845    }
3846#endif
3847
3848    /* Save the name of our Device section for SiSCtrl usage */
3849    {
3850       int ttt = 0;
3851       GDevPtr device = xf86GetDevFromEntity(pScrn->entityList[0],
3852						pScrn->entityInstanceList[0]);
3853       if(device && device->identifier) {
3854          if((ttt = strlen(device->identifier)) > 31) ttt = 31;
3855	  strncpy(&pSiS->devsectname[0], device->identifier, 31);
3856       }
3857       pSiS->devsectname[ttt] = 0;
3858    }
3859
3860    pSiS->ForceCursorOff = FALSE;
3861
3862    /* Allocate SiS_Private (for mode switching code) and initialize it */
3863    pSiS->SiS_Pr = NULL;
3864#ifdef SISDUALHEAD
3865    if(pSiSEnt) {
3866       if(pSiSEnt->SiS_Pr) pSiS->SiS_Pr = pSiSEnt->SiS_Pr;
3867    }
3868#endif
3869    if(!pSiS->SiS_Pr) {
3870       if(!(pSiS->SiS_Pr = xnfcalloc(sizeof(struct SiS_Private), 1))) {
3871	  SISErrorLog(pScrn, "Could not allocate memory for SiS_Pr structure\n");
3872	  goto my_error_1;
3873       }
3874#ifdef SISDUALHEAD
3875       if(pSiSEnt) pSiSEnt->SiS_Pr = pSiS->SiS_Pr;
3876#endif
3877       memset(pSiS->SiS_Pr, 0, sizeof(struct SiS_Private));
3878       pSiS->SiS_Pr->PciTag = pSiS->PciTag;
3879       pSiS->SiS_Pr->ChipType = pSiS->ChipType;
3880       pSiS->SiS_Pr->ChipRevision = pSiS->ChipRev;
3881       pSiS->SiS_Pr->SiS_Backup70xx = 0xff;
3882       pSiS->SiS_Pr->SiS_CHOverScan = -1;
3883       pSiS->SiS_Pr->SiS_ChSW = FALSE;
3884       pSiS->SiS_Pr->SiS_CustomT = CUT_NONE;
3885       pSiS->SiS_Pr->SiS_UseWide = -1;
3886       pSiS->SiS_Pr->SiS_UseWideCRT2 = -1;
3887       pSiS->SiS_Pr->SiS_TVBlue = -1;
3888       pSiS->SiS_Pr->PanelSelfDetected = FALSE;
3889       pSiS->SiS_Pr->UsePanelScaler = -1;
3890       pSiS->SiS_Pr->CenterScreen = -1;
3891       pSiS->SiS_Pr->CRT1UsesCustomMode = FALSE;
3892       pSiS->SiS_Pr->PDC = pSiS->SiS_Pr->PDCA = -1;
3893       pSiS->SiS_Pr->LVDSHL = -1;
3894       pSiS->SiS_Pr->HaveEMI = FALSE;
3895       pSiS->SiS_Pr->HaveEMILCD = FALSE;
3896       pSiS->SiS_Pr->OverruleEMI = FALSE;
3897       pSiS->SiS_Pr->SiS_SensibleSR11 = FALSE;
3898       if(pSiS->ChipType >= SIS_661) {
3899          pSiS->SiS_Pr->SiS_SensibleSR11 = TRUE;
3900       }
3901       pSiS->SiS_Pr->SiS_MyCR63 = pSiS->myCR63;
3902       pSiS->SiS_Pr->DDCPortMixup = FALSE;
3903    }
3904
3905    /* Copy IO address to SiS_Pr and init the structure for
3906     * routines inside init.c/init301.c
3907     */
3908    pSiS->SiS_Pr->IOAddress = (SISIOADDRESS)(pSiS->RelIO + 0x30);
3909    SiSRegInit(pSiS->SiS_Pr, pSiS->RelIO + 0x30);
3910
3911    /* The following identifies the old chipsets. This is only
3912     * partly used since the really old chips are not supported,
3913     * but I keep it here for future use.
3914     * 205, 215 and 225 are to be treated the same way, 201 and 202
3915     * are different.
3916     */
3917    if(pSiS->VGAEngine == SIS_OLD_VGA || pSiS->VGAEngine == SIS_530_VGA) {
3918       switch(pSiS->Chipset) {
3919       case PCI_CHIP_SG86C201:
3920	  pSiS->oldChipset = OC_SIS86201; break;
3921       case PCI_CHIP_SG86C202:
3922	  pSiS->oldChipset = OC_SIS86202; break;
3923       case PCI_CHIP_SG86C205:
3924	  inSISIDXREG(SISSR, 0x10, tempreg);
3925	  if(tempreg & 0x80) pSiS->oldChipset = OC_SIS6205B;
3926	  else pSiS->oldChipset = (pSiS->ChipRev == 0x11) ?
3927					OC_SIS6205C : OC_SIS6205A;
3928	  break;
3929       case PCI_CHIP_SIS82C204:
3930	  pSiS->oldChipset = OC_SIS82204; break;
3931       case 0x6225:
3932	  pSiS->oldChipset = OC_SIS6225; break;
3933       case PCI_CHIP_SIS5597:
3934	  pSiS->oldChipset = OC_SIS5597; break;
3935       case PCI_CHIP_SIS6326:
3936	  pSiS->oldChipset = OC_SIS6326; break;
3937       case PCI_CHIP_SIS530:
3938	  if(sis_pci_read_host_bridge_u32(0x00) == 0x06201039) {
3939	     pSiS->oldChipset = OC_SIS620;
3940	  } else {
3941	     if((pSiS->ChipRev & 0x0f) < 0x0a)
3942		   pSiS->oldChipset = OC_SIS530A;
3943	     else  pSiS->oldChipset = OC_SIS530B;
3944	  }
3945	  break;
3946       default:
3947	  pSiS->oldChipset = OC_UNKNOWN;
3948       }
3949    }
3950
3951    if(!xf86SetDepthBpp(pScrn, 0, 0, 0, pix24flags)) {
3952       SISErrorLog(pScrn, "xf86SetDepthBpp() error\n");
3953       goto my_error_1;
3954    }
3955
3956    /* Check that the returned depth is one we support */
3957    temp = 0;
3958    switch(pScrn->depth) {
3959       case 8:
3960       case 16:
3961       case 24:
3962          break;
3963       case 15:
3964	  if((pSiS->VGAEngine == SIS_300_VGA) ||
3965	     (pSiS->VGAEngine == SIS_315_VGA)) {
3966	     temp = 1;
3967	  }
3968	  break;
3969       default:
3970	  temp = 1;
3971    }
3972
3973    if(temp) {
3974       SISErrorLog(pScrn,
3975            "Given color depth (%d) is not supported by this driver/chipset\n",
3976            pScrn->depth);
3977       goto my_error_1;
3978    }
3979
3980    xf86PrintDepthBpp(pScrn);
3981
3982    if( (((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) &&
3983         (pScrn->bitsPerPixel == 24)) ||
3984	((pSiS->VGAEngine == SIS_OLD_VGA) && (pScrn->bitsPerPixel == 32)) ) {
3985       SISErrorLog(pScrn,
3986            "Framebuffer bpp %d not supported for this chipset\n", pScrn->bitsPerPixel);
3987       goto my_error_1;
3988    }
3989
3990    /* Get the depth24 pixmap format */
3991    if(pScrn->depth == 24 && pix24bpp == 0) {
3992       pix24bpp = xf86GetBppFromDepth(pScrn, 24);
3993    }
3994
3995    /*
3996     * This must happen after pScrn->display has been set because
3997     * xf86SetWeight references it.
3998     */
3999    if(pScrn->depth > 8) {
4000        /* The defaults are OK for us */
4001        rgb zeros = {0, 0, 0};
4002
4003        if(!xf86SetWeight(pScrn, zeros, zeros)) {
4004	    SISErrorLog(pScrn, "xf86SetWeight() error\n");
4005	    goto my_error_1;
4006        } else {
4007	   Bool ret = FALSE;
4008	   switch(pScrn->depth) {
4009	   case 15:
4010	      if((pScrn->weight.red != 5) ||
4011	         (pScrn->weight.green != 5) ||
4012		 (pScrn->weight.blue != 5)) ret = TRUE;
4013	      break;
4014	   case 16:
4015	      if((pScrn->weight.red != 5) ||
4016	         (pScrn->weight.green != 6) ||
4017		 (pScrn->weight.blue != 5)) ret = TRUE;
4018	      break;
4019	   case 24:
4020	      if((pScrn->weight.red != 8) ||
4021	         (pScrn->weight.green != 8) ||
4022		 (pScrn->weight.blue != 8)) ret = TRUE;
4023	      break;
4024	   }
4025	   if(ret) {
4026	      SISErrorLog(pScrn,
4027		   "RGB weight %d%d%d at depth %d not supported by hardware\n",
4028		   (int)pScrn->weight.red, (int)pScrn->weight.green,
4029		   (int)pScrn->weight.blue, pScrn->depth);
4030	      goto my_error_1;
4031	   }
4032        }
4033    }
4034
4035    /* Set the current layout parameters */
4036    pSiS->CurrentLayout.bitsPerPixel = pScrn->bitsPerPixel;
4037    pSiS->CurrentLayout.depth        = pScrn->depth;
4038    /* (Inside this function, we can use pScrn's contents anyway) */
4039
4040    if(!xf86SetDefaultVisual(pScrn, -1)) {
4041       SISErrorLog(pScrn, "xf86SetDefaultVisual() error\n");
4042       goto my_error_1;
4043    } else {
4044       /* We don't support DirectColor at > 8bpp */
4045       if(pScrn->depth > 8 && pScrn->defaultVisual != TrueColor) {
4046	  SISErrorLog(pScrn,
4047	       "Given default visual (%s) is not supported at depth %d\n",
4048	        xf86GetVisualName(pScrn->defaultVisual), pScrn->depth);
4049	  goto my_error_1;
4050       }
4051    }
4052
4053#ifdef SISDUALHEAD
4054    /* Due to palette & timing problems we don't support 8bpp in DHM */
4055    if((pSiS->DualHeadMode) && (pScrn->bitsPerPixel <= 8)) {
4056       SISErrorLog(pScrn, "Color depth %d not supported in Dual Head mode.\n",
4057			pScrn->bitsPerPixel);
4058       goto my_error_1;
4059    }
4060#endif
4061
4062    /* Read BIOS for 300/315/330/340 series customization */
4063    pSiS->SiS_Pr->VirtualRomBase = NULL;
4064    pSiS->BIOS = NULL;
4065    pSiS->SiS_Pr->UseROM = FALSE;
4066    pSiS->ROM661New = FALSE;
4067    pSiS->HaveXGIBIOS = FALSE;
4068
4069    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
4070#ifdef SISDUALHEAD
4071       if(pSiSEnt) {
4072	  if(pSiSEnt->BIOS) {
4073	     pSiS->BIOS = pSiSEnt->BIOS;
4074	     pSiS->SiS_Pr->VirtualRomBase = pSiS->BIOS;
4075	     pSiS->ROM661New = pSiSEnt->ROM661New;
4076	     pSiS->HaveXGIBIOS = pSiSEnt->HaveXGIBIOS;
4077	  }
4078       }
4079#endif
4080       if(!pSiS->BIOS) {
4081	  if(!(pSiS->BIOS = xcalloc(1, BIOS_SIZE))) {
4082	     xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
4083		"Could not allocate memory for video BIOS image\n");
4084	  } else {
4085	     UShort mypciid = pSiS->Chipset;
4086	     UShort mypcivendor = (pSiS->ChipFlags & SiSCF_IsXGI) ? PCI_VENDOR_XGI : PCI_VENDOR_SIS;
4087	     Bool   found = FALSE, readpci = FALSE;
4088	     int    biossize = BIOS_SIZE;
4089
4090	     switch(pSiS->ChipType) {
4091	     case SIS_315:    mypciid = PCI_CHIP_SIS315;
4092			      readpci = TRUE;
4093			      break;
4094	     case SIS_315PRO: mypciid = PCI_CHIP_SIS315PRO;
4095			      readpci = TRUE;
4096			      break;
4097	     case SIS_300:
4098	     case SIS_315H:
4099	     case SIS_330:
4100	     case SIS_340:
4101	     case SIS_650:
4102	     case SIS_760:
4103	     case XGI_40:     readpci = TRUE;
4104			      break;
4105	     case XGI_20:     readpci = TRUE;
4106			      biossize = 0x8000;
4107			      break;
4108	     }
4109#if XSERVER_LIBPCIACCESS
4110	     if(readpci) {
4111		pSiS->PciInfo->rom_size = biossize;
4112		pci_device_read_rom(pSiS->PciInfo, pSiS->BIOS);
4113		if(SISCheckBIOS(pSiS, mypciid, mypcivendor, biossize)) {
4114		   found = TRUE;
4115		}
4116	     }
4117#else
4118	     if(readpci) {
4119		xf86ReadPciBIOS(0, pSiS->PciTag, 0, pSiS->BIOS, biossize);
4120		if(SISCheckBIOS(pSiS, mypciid, mypcivendor, biossize)) {
4121		   found = TRUE;
4122		}
4123	     }
4124
4125	     if(!found) {
4126	        ULong  segstart;
4127		for(segstart = BIOS_BASE; segstart < 0x000f0000; segstart += 0x00001000) {
4128
4129#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,99,0,0)
4130		   if(xf86ReadBIOS(segstart, 0, pSiS->BIOS, biossize) != biossize) continue;
4131#else
4132		   if(xf86ReadDomainMemory(pSiS->PciTag, segstart, biossize, pSiS->BIOS) != biossize) continue;
4133#endif
4134
4135		   if(!SISCheckBIOS(pSiS, mypciid, mypcivendor, biossize)) continue;
4136
4137		   found = TRUE;
4138		   break;
4139		}
4140             }
4141#endif
4142	     if(found) {
4143		UShort romptr = pSiS->BIOS[0x16] | (pSiS->BIOS[0x17] << 8);
4144		pSiS->SiS_Pr->VirtualRomBase = pSiS->BIOS;
4145		if(pSiS->ChipFlags & SiSCF_IsXGI) {
4146		   pSiS->HaveXGIBIOS = pSiS->SiS_Pr->SiS_XGIROM = TRUE;
4147		   pSiS->SiS_Pr->UseROM = FALSE;
4148		   if(pSiS->ChipFlags & SiSCF_IsXGIV3) {
4149		      if(!(pSiS->BIOS[0x1d1] & 0x01)) {
4150			 pSiS->SiS_Pr->DDCPortMixup = TRUE;
4151		      }
4152	           }
4153	        } else {
4154		   pSiS->ROM661New = SiSDetermineROMLayout661(pSiS->SiS_Pr);
4155		}
4156		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4157			"Video BIOS version \"%7s\" found (%s data layout)\n",
4158			&pSiS->BIOS[romptr], pSiS->ROM661New ? "new SiS" :
4159				(pSiS->HaveXGIBIOS ? "XGI" : "old SiS"));
4160		if(pSiS->SiS_Pr->DDCPortMixup) {
4161		   xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
4162			"*** Buggy XGI V3XT card detected: If VGA and DVI are connected at the\n");
4163		   xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
4164			"*** same time, BIOS and driver will be unable to detect DVI connection.\n");
4165		}
4166#ifdef SISDUALHEAD
4167		if(pSiSEnt) {
4168		   pSiSEnt->BIOS = pSiS->BIOS;
4169		   pSiSEnt->ROM661New = pSiS->ROM661New;
4170		   pSiSEnt->HaveXGIBIOS = pSiS->HaveXGIBIOS;
4171		}
4172#endif
4173	     } else {
4174	        xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
4175			 "Could not find/read video BIOS\n");
4176		xfree(pSiS->BIOS);
4177		pSiS->BIOS = NULL;
4178	     }
4179          }
4180       }
4181
4182       if(!(pSiS->ChipFlags & SiSCF_IsXGI)) {
4183          if(pSiS->BIOS) pSiS->SiS_Pr->UseROM = TRUE;
4184          else           pSiS->SiS_Pr->UseROM = FALSE;
4185       }
4186    }
4187
4188    /* Evaluate options */
4189    SiSOptions(pScrn);
4190
4191#ifdef SISMERGED
4192    /* Due to palette & timing problems we don't support 8bpp in MFBM */
4193    if((pSiS->MergedFB) && (pScrn->bitsPerPixel <= 8)) {
4194       SISErrorLog(pScrn, "MergedFB: Color depth %d not supported, %s\n",
4195			pScrn->bitsPerPixel, mergeddisstr);
4196       pSiS->MergedFB = pSiS->MergedFBAuto = FALSE;
4197    }
4198#endif
4199
4200    /* Probe CPU features */
4201#ifdef SISDUALHEAD
4202    if(pSiS->DualHeadMode) {
4203       pSiS->CPUFlags = pSiSEnt->CPUFlags;
4204    }
4205#endif
4206    if(!pSiS->CPUFlags) {
4207       pSiS->CPUFlags = SiSGetCPUFlags(pScrn);
4208       pSiS->CPUFlags |= SIS_CPUFL_FLAG;
4209#ifdef SISDUALHEAD
4210       if(pSiS->DualHeadMode) pSiSEnt->CPUFlags = pSiS->CPUFlags;
4211#endif
4212    }
4213
4214    /* We use a programamble clock */
4215    pScrn->progClock = TRUE;
4216
4217    /* Set the bits per RGB for 8bpp mode */
4218    if(pScrn->depth == 8) pScrn->rgbBits = 8;
4219
4220#ifdef SISDUALHEAD
4221    if(pSiS->DualHeadMode) {
4222       if(!pSiS->SecondHead) {
4223	  /* Copy some option settings to entity private */
4224	  pSiSEnt->HWCursor = pSiS->HWCursor;
4225	  pSiSEnt->NoAccel = pSiS->NoAccel;
4226	  pSiSEnt->useEXA = pSiS->useEXA;
4227	  pSiSEnt->restorebyset = pSiS->restorebyset;
4228	  pSiSEnt->OptROMUsage = pSiS->OptROMUsage;
4229	  pSiSEnt->OptUseOEM = pSiS->OptUseOEM;
4230	  pSiSEnt->TurboQueue = pSiS->TurboQueue;
4231	  pSiSEnt->forceCRT1 = pSiS->forceCRT1;
4232	  pSiSEnt->ForceCRT1Type = pSiS->ForceCRT1Type;
4233	  pSiSEnt->CRT1TypeForced = pSiS->CRT1TypeForced;
4234	  pSiSEnt->ForceCRT2Type = pSiS->ForceCRT2Type;
4235	  pSiSEnt->ForceTVType = pSiS->ForceTVType;
4236	  pSiSEnt->ForceYPbPrType = pSiS->ForceYPbPrType;
4237	  pSiSEnt->ForceYPbPrAR = pSiS->ForceYPbPrAR;
4238	  pSiSEnt->UsePanelScaler = pSiS->UsePanelScaler;
4239	  pSiSEnt->CenterLCD = pSiS->CenterLCD;
4240	  pSiSEnt->DSTN = pSiS->DSTN;
4241	  pSiSEnt->FSTN = pSiS->FSTN;
4242	  pSiSEnt->OptTVStand = pSiS->OptTVStand;
4243	  pSiSEnt->NonDefaultPAL = pSiS->NonDefaultPAL;
4244	  pSiSEnt->NonDefaultNTSC = pSiS->NonDefaultNTSC;
4245	  pSiSEnt->chtvtype = pSiS->chtvtype;
4246	  pSiSEnt->OptTVOver = pSiS->OptTVOver;
4247	  pSiSEnt->OptTVSOver = pSiS->OptTVSOver;
4248	  pSiSEnt->chtvlumabandwidthcvbs = pSiS->chtvlumabandwidthcvbs;
4249	  pSiSEnt->chtvlumabandwidthsvideo = pSiS->chtvlumabandwidthsvideo;
4250	  pSiSEnt->chtvlumaflickerfilter = pSiS->chtvlumaflickerfilter;
4251	  pSiSEnt->chtvchromabandwidth = pSiS->chtvchromabandwidth;
4252	  pSiSEnt->chtvchromaflickerfilter = pSiS->chtvchromaflickerfilter;
4253	  pSiSEnt->chtvtextenhance = pSiS->chtvtextenhance;
4254	  pSiSEnt->chtvcontrast = pSiS->chtvcontrast;
4255	  pSiSEnt->chtvcvbscolor = pSiS->chtvcvbscolor;
4256	  pSiSEnt->sistvedgeenhance = pSiS->sistvedgeenhance;
4257	  pSiSEnt->sistvantiflicker = pSiS->sistvantiflicker;
4258	  pSiSEnt->sistvsaturation = pSiS->sistvsaturation;
4259	  pSiSEnt->sistvcfilter = pSiS->sistvcfilter;
4260	  pSiSEnt->sistvyfilter = pSiS->sistvyfilter;
4261	  pSiSEnt->sistvcolcalibc = pSiS->sistvcolcalibc;
4262	  pSiSEnt->sistvcolcalibf = pSiS->sistvcolcalibf;
4263	  pSiSEnt->tvxpos = pSiS->tvxpos;
4264	  pSiSEnt->tvypos = pSiS->tvypos;
4265	  pSiSEnt->tvxscale = pSiS->tvxscale;
4266	  pSiSEnt->tvyscale = pSiS->tvyscale;
4267	  pSiSEnt->siscrt1satgain = pSiS->siscrt1satgain;
4268	  pSiSEnt->crt1satgaingiven = pSiS->crt1satgaingiven;
4269	  pSiSEnt->CRT1gamma = pSiS->CRT1gamma;
4270	  pSiSEnt->CRT1gammaGiven = pSiS->CRT1gammaGiven;
4271	  pSiSEnt->XvGammaRed = pSiS->XvGammaRed;
4272	  pSiSEnt->XvGammaGreen = pSiS->XvGammaGreen;
4273	  pSiSEnt->XvGammaBlue = pSiS->XvGammaBlue;
4274	  pSiSEnt->XvGamma = pSiS->XvGamma;
4275	  pSiSEnt->XvGammaGiven = pSiS->XvGammaGiven;
4276	  pSiSEnt->CRT2gamma = pSiS->CRT2gamma;
4277	  pSiSEnt->XvOnCRT2 = pSiS->XvOnCRT2;
4278	  pSiSEnt->AllowHotkey = pSiS->AllowHotkey;
4279	  pSiSEnt->enablesisctrl = pSiS->enablesisctrl;
4280	  pSiSEnt->SenseYPbPr = pSiS->SenseYPbPr;
4281	  pSiSEnt->XvUseMemcpy = pSiS->XvUseMemcpy;
4282	  pSiSEnt->BenchMemCpy = pSiS->BenchMemCpy;
4283#ifdef SIS_CP
4284	  SIS_CP_DRIVER_COPYOPTIONSENT
4285#endif
4286       } else {
4287	  /* We always use same cursor type on both screens */
4288	  pSiS->HWCursor = pSiSEnt->HWCursor;
4289	  /* We need identical NoAccel setting */
4290	  pSiS->NoAccel = pSiSEnt->NoAccel;
4291	  pSiS->useEXA = pSiSEnt->useEXA;
4292	  pSiS->TurboQueue = pSiSEnt->TurboQueue;
4293	  pSiS->restorebyset = pSiSEnt->restorebyset;
4294	  pSiS->AllowHotkey = pSiS->AllowHotkey;
4295	  pSiS->OptROMUsage = pSiSEnt->OptROMUsage;
4296	  pSiS->OptUseOEM = pSiSEnt->OptUseOEM;
4297	  pSiS->forceCRT1 = pSiSEnt->forceCRT1;
4298	  pSiS->nocrt2ddcdetection = FALSE;
4299	  pSiS->forcecrt2redetection = FALSE;
4300	  pSiS->ForceCRT1Type = pSiSEnt->ForceCRT1Type;
4301	  pSiS->ForceCRT2Type = pSiSEnt->ForceCRT2Type;
4302	  pSiS->CRT1TypeForced = pSiSEnt->CRT1TypeForced;
4303	  pSiS->UsePanelScaler = pSiSEnt->UsePanelScaler;
4304	  pSiS->CenterLCD = pSiSEnt->CenterLCD;
4305	  pSiS->DSTN = pSiSEnt->DSTN;
4306	  pSiS->FSTN = pSiSEnt->FSTN;
4307	  pSiS->OptTVStand = pSiSEnt->OptTVStand;
4308	  pSiS->NonDefaultPAL = pSiSEnt->NonDefaultPAL;
4309	  pSiS->NonDefaultNTSC = pSiSEnt->NonDefaultNTSC;
4310	  pSiS->chtvtype = pSiSEnt->chtvtype;
4311	  pSiS->ForceTVType = pSiSEnt->ForceTVType;
4312	  pSiS->ForceYPbPrType = pSiSEnt->ForceYPbPrType;
4313	  pSiS->ForceYPbPrAR = pSiSEnt->ForceYPbPrAR;
4314	  pSiS->OptTVOver = pSiSEnt->OptTVOver;
4315	  pSiS->OptTVSOver = pSiSEnt->OptTVSOver;
4316	  pSiS->chtvlumabandwidthcvbs = pSiSEnt->chtvlumabandwidthcvbs;
4317	  pSiS->chtvlumabandwidthsvideo = pSiSEnt->chtvlumabandwidthsvideo;
4318	  pSiS->chtvlumaflickerfilter = pSiSEnt->chtvlumaflickerfilter;
4319	  pSiS->chtvchromabandwidth = pSiSEnt->chtvchromabandwidth;
4320	  pSiS->chtvchromaflickerfilter = pSiSEnt->chtvchromaflickerfilter;
4321	  pSiS->chtvcvbscolor = pSiSEnt->chtvcvbscolor;
4322	  pSiS->chtvtextenhance = pSiSEnt->chtvtextenhance;
4323	  pSiS->chtvcontrast = pSiSEnt->chtvcontrast;
4324	  pSiS->sistvedgeenhance = pSiSEnt->sistvedgeenhance;
4325	  pSiS->sistvantiflicker = pSiSEnt->sistvantiflicker;
4326	  pSiS->sistvsaturation = pSiSEnt->sistvsaturation;
4327	  pSiS->sistvcfilter = pSiSEnt->sistvcfilter;
4328	  pSiS->sistvyfilter = pSiSEnt->sistvyfilter;
4329	  pSiS->sistvcolcalibc = pSiSEnt->sistvcolcalibc;
4330	  pSiS->sistvcolcalibf = pSiSEnt->sistvcolcalibf;
4331	  pSiS->tvxpos = pSiSEnt->tvxpos;
4332	  pSiS->tvypos = pSiSEnt->tvypos;
4333	  pSiS->tvxscale = pSiSEnt->tvxscale;
4334	  pSiS->tvyscale = pSiSEnt->tvyscale;
4335	  pSiS->SenseYPbPr = pSiSEnt->SenseYPbPr;
4336	  if(!pSiS->CRT1gammaGiven) {
4337	     if(pSiSEnt->CRT1gammaGiven)
4338	        pSiS->CRT1gamma = pSiSEnt->CRT1gamma;
4339	  }
4340	  pSiS->CRT2gamma = pSiSEnt->CRT2gamma;
4341	  if(!pSiS->XvGammaGiven) {
4342	     if(pSiSEnt->XvGammaGiven) {
4343		pSiS->XvGamma = pSiSEnt->XvGamma;
4344		pSiS->XvGammaRed = pSiS->XvGammaRedDef = pSiSEnt->XvGammaRed;
4345		pSiS->XvGammaGreen = pSiS->XvGammaGreenDef = pSiSEnt->XvGammaGreen;
4346		pSiS->XvGammaBlue = pSiS->XvGammaBlueDef = pSiSEnt->XvGammaBlue;
4347	     }
4348	  }
4349	  if(!pSiS->crt1satgaingiven) {
4350	     if(pSiSEnt->crt1satgaingiven)
4351	        pSiS->siscrt1satgain = pSiSEnt->siscrt1satgain;
4352	  }
4353	  pSiS->XvOnCRT2 = pSiSEnt->XvOnCRT2;
4354	  pSiS->enablesisctrl = pSiSEnt->enablesisctrl;
4355	  pSiS->XvUseMemcpy = pSiSEnt->XvUseMemcpy;
4356	  pSiS->BenchMemCpy = pSiSEnt->BenchMemCpy;
4357	  /* Copy gamma brightness to Ent (sic!) for Xinerama */
4358	  pSiSEnt->GammaBriR = pSiS->GammaBriR;
4359	  pSiSEnt->GammaBriG = pSiS->GammaBriG;
4360	  pSiSEnt->GammaBriB = pSiS->GammaBriB;
4361	  pSiSEnt->NewGammaBriR = pSiS->NewGammaBriR;
4362	  pSiSEnt->NewGammaBriG = pSiS->NewGammaBriG;
4363	  pSiSEnt->NewGammaBriB = pSiS->NewGammaBriB;
4364	  pSiSEnt->NewGammaConR = pSiS->NewGammaConR;
4365	  pSiSEnt->NewGammaConG = pSiS->NewGammaConG;
4366	  pSiSEnt->NewGammaConB = pSiS->NewGammaConB;
4367#ifdef SIS_CP
4368	  SIS_CP_DRIVER_COPYOPTIONS
4369#endif
4370       }
4371    }
4372#endif
4373
4374    /* Handle UseROMData, NoOEM and UsePanelScaler options */
4375    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
4376       from = X_PROBED;
4377       if(pSiS->OptROMUsage == 0) {
4378	  pSiS->SiS_Pr->UseROM = FALSE;
4379	  from = X_CONFIG;
4380	  xf86DrvMsg(pScrn->scrnIndex, from, "Video ROM data usage is disabled\n");
4381       }
4382
4383       if(!pSiS->OptUseOEM) {
4384	  xf86DrvMsg(pScrn->scrnIndex, from, "Internal OEM LCD/TV/VGA2 data usage is disabled\n");
4385       }
4386
4387       pSiS->SiS_Pr->UsePanelScaler = pSiS->UsePanelScaler;
4388       pSiS->SiS_Pr->CenterScreen = pSiS->CenterLCD;
4389    }
4390
4391    /* Do some HW configuration detection (memory amount & type, clock, etc) */
4392    SiSSetup(pScrn);
4393
4394    /* Get framebuffer address */
4395    if(pSiS->pEnt->device->MemBase != 0) {
4396       /*
4397	* XXX Should check that the config file value matches one of the
4398	* PCI base address values.
4399	*/
4400       pSiS->FbAddress = pSiS->pEnt->device->MemBase;
4401       from = X_CONFIG;
4402    } else {
4403       pSiS->FbAddress = PCI_REGION_BASE(pSiS->PciInfo, 0, REGION_MEM) & 0xFFFFFFF0;
4404       from = X_PROBED;
4405    }
4406
4407#ifdef SISDUALHEAD
4408    if(pSiS->DualHeadMode)
4409       xf86DrvMsg(pScrn->scrnIndex, from, "Global linear framebuffer at 0x%lX\n",
4410	   (ULong)pSiS->FbAddress);
4411    else
4412#endif
4413       xf86DrvMsg(pScrn->scrnIndex, from, "Linear framebuffer at 0x%lX\n",
4414	   (ULong)pSiS->FbAddress);
4415
4416    pSiS->realFbAddress = pSiS->FbAddress;
4417
4418    /* Get MMIO address */
4419    if(pSiS->pEnt->device->IOBase != 0) {
4420       /*
4421	* XXX Should check that the config file value matches one of the
4422	* PCI base address values.
4423	*/
4424       pSiS->IOAddress = pSiS->pEnt->device->IOBase;
4425       from = X_CONFIG;
4426    } else {
4427       pSiS->IOAddress = PCI_REGION_BASE(pSiS->PciInfo, 1, REGION_MEM) & 0xFFFFFFF0;
4428       from = X_PROBED;
4429    }
4430    xf86DrvMsg(pScrn->scrnIndex, from, "MMIO registers at 0x%lX (size %ldK)\n",
4431	   (ULong)pSiS->IOAddress, pSiS->mmioSize);
4432
4433#ifndef XSERVER_LIBPCIACCESS
4434    /* Register the PCI-assigned resources */
4435    if(xf86RegisterResources(pSiS->pEnt->index, NULL, ResExclusive)) {
4436       SISErrorLog(pScrn, "PCI resource conflicts detected\n");
4437#ifdef SISDUALHEAD
4438       if(pSiSEnt) pSiSEnt->ErrorAfterFirst = TRUE;
4439#endif
4440       sisRestoreExtRegisterLock(pSiS,srlockReg,crlockReg);
4441       if(pSiS->pInt) xf86FreeInt10(pSiS->pInt);
4442       SISFreeRec(pScrn);
4443       return FALSE;
4444    }
4445#endif
4446
4447    from = X_PROBED;
4448    if(pSiS->pEnt->device->videoRam != 0) {
4449       if(pSiS->Chipset == PCI_CHIP_SIS6326) {
4450	  pScrn->videoRam = pSiS->pEnt->device->videoRam;
4451	  from = X_CONFIG;
4452       } else {
4453	  xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
4454		"Option \"VideoRAM\" ignored\n");
4455       }
4456    }
4457
4458    pSiS->RealVideoRam = pScrn->videoRam;
4459
4460    if((pSiS->Chipset == PCI_CHIP_SIS6326) &&
4461       (pScrn->videoRam > 4096)            &&
4462       (from != X_CONFIG)) {
4463       pScrn->videoRam = 4096;
4464       xf86DrvMsg(pScrn->scrnIndex, from,
4465	   "SiS6326: Detected %d KB VideoRAM, limiting to %d KB\n",
4466	   pSiS->RealVideoRam, pScrn->videoRam);
4467    } else {
4468       xf86DrvMsg(pScrn->scrnIndex, from, "VideoRAM: %d KB\n", pScrn->videoRam);
4469    }
4470
4471    if((pSiS->Chipset == PCI_CHIP_SIS6326) &&
4472       (pScrn->videoRam > 4096)) {
4473       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
4474	   "SiS6326 engines do not support more than 4096KB RAM, therefore\n");
4475       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
4476	   "TurboQueue, HWCursor, 2D acceleration and XVideo are disabled.\n");
4477       pSiS->TurboQueue = FALSE;
4478       pSiS->HWCursor   = FALSE;
4479       pSiS->NoXvideo   = TRUE;
4480       pSiS->NoAccel    = TRUE;
4481    }
4482
4483    pSiS->FbMapSize = pSiS->availMem = pScrn->videoRam * 1024;
4484
4485    /* Calculate real availMem according to Accel/TurboQueue and
4486     * HWCursur setting. Also, initialize some variables used
4487     * in other modules.
4488     */
4489    pSiS->cursorOffset = 0;
4490    pSiS->CurARGBDest = NULL;
4491    pSiS->CurMonoSrc = NULL;
4492    pSiS->CurFGCol = pSiS->CurBGCol = 0;
4493    pSiS->FbBaseOffset = 0;
4494
4495    switch(pSiS->VGAEngine) {
4496
4497      case SIS_300_VGA:
4498	pSiS->TurboQueueLen = 512;
4499	if(pSiS->TurboQueue) {
4500	   pSiS->availMem -= (pSiS->TurboQueueLen*1024);
4501	   pSiS->cursorOffset = 512;
4502	}
4503	if(pSiS->HWCursor) {
4504	   pSiS->availMem -= pSiS->CursorSize;
4505	   if(pSiS->OptUseColorCursor) pSiS->availMem -= pSiS->CursorSize;
4506	}
4507	pSiS->CmdQueLenMask = 0xFFFF;
4508	pSiS->CmdQueLenFix  = 0;
4509	pSiS->cursorBufferNum = 0;
4510#ifdef SISDUALHEAD
4511	if(pSiSEnt) pSiSEnt->cursorBufferNum = 0;
4512#endif
4513	break;
4514
4515      case SIS_315_VGA:
4516#ifdef SISVRAMQ		/* VRAM queue */
4517	pSiS->cmdQueueSizeMask = pSiS->cmdQueueSize - 1;	/* VRAM Command Queue is variable (in therory) */
4518	pSiS->cmdQueueOffset = (pScrn->videoRam * 1024) - pSiS->cmdQueueSize;
4519	pSiS->cmdQueueLen = 0;
4520	pSiS->cmdQueueSize_div2 = pSiS->cmdQueueSize / 2;
4521	pSiS->cmdQueueSize_div4 = pSiS->cmdQueueSize / 4;
4522	pSiS->cmdQueueSize_4_3 = (pSiS->cmdQueueSize / 4) * 3;
4523	pSiS->availMem -= pSiS->cmdQueueSize;
4524	pSiS->cursorOffset = (pSiS->cmdQueueSize / 1024);
4525
4526	/* Set up shared pointer to current offset */
4527#ifdef SISDUALHEAD
4528	if(pSiS->DualHeadMode)
4529	   pSiS->cmdQ_SharedWritePort = &(pSiSEnt->cmdQ_SharedWritePort_2D);
4530	else
4531#endif
4532	   pSiS->cmdQ_SharedWritePort = &(pSiS->cmdQ_SharedWritePort_2D);
4533
4534
4535#else			/* MMIO */
4536	if(pSiS->TurboQueue) {
4537	   pSiS->availMem -= (512*1024);			/* MMIO Command Queue is 512k (variable in theory) */
4538	   pSiS->cursorOffset = 512;
4539	}
4540#endif
4541	if(pSiS->HWCursor) {
4542	   pSiS->availMem -= (pSiS->CursorSize * 2);
4543	   if(pSiS->OptUseColorCursor) pSiS->availMem -= (pSiS->CursorSize * 2);
4544	}
4545	pSiS->cursorBufferNum = 0;
4546#ifdef SISDUALHEAD
4547	if(pSiSEnt) pSiSEnt->cursorBufferNum = 0;
4548#endif
4549
4550	if((pSiS->SiS76xLFBSize) && (pSiS->SiS76xUMASize)) {
4551	   pSiS->availMem -= pSiS->SiS76xUMASize;
4552	   pSiS->FbBaseOffset = pSiS->SiS76xUMASize;
4553	}
4554
4555	break;
4556
4557      default:
4558	/* cursorOffset not used in cursor functions for 530 and
4559	 * older chips, because the cursor is *above* the TQ.
4560	 * On 5597 and older revisions of the 6326, the TQ is
4561	 * max 32K, on newer 6326 revisions and the 530 either 30
4562	 * (or 32?) or 62K (or 64?). However, to make sure, we
4563	 * use only 30K (or 32?), but reduce the available memory
4564	 * by 64, and locate the TQ at the beginning of this last
4565	 * 64K block. (We do this that way even when using the
4566	 * HWCursor, because the cursor only takes 2K and the
4567	 * queue does not seem to last that far anyway.)
4568	 * The TQ must be located at 32KB boundaries.
4569	 */
4570	if(pSiS->RealVideoRam < 3072) {
4571	   if(pSiS->TurboQueue) {
4572	      xf86DrvMsg(pScrn->scrnIndex, X_INFO,
4573		    "Not enough video RAM for TurboQueue. TurboQueue disabled\n");
4574	      pSiS->TurboQueue = FALSE;
4575	   }
4576	}
4577	pSiS->CmdQueMaxLen = 32;
4578	if(pSiS->TurboQueue) {
4579			      pSiS->availMem -= (64*1024);
4580			      pSiS->CmdQueMaxLen = 900;   /* To make sure; should be 992 */
4581	} else if(pSiS->HWCursor) {
4582			      pSiS->availMem -= pSiS->CursorSize;
4583	}
4584	if(pSiS->Chipset == PCI_CHIP_SIS530) {
4585		/* Check if Flat Panel is enabled */
4586		inSISIDXREG(SISSR, 0x0e, tempreg);
4587		if(!(tempreg & 0x04)) pSiS->availMem -= pSiS->CursorSize;
4588
4589		/* Set up mask for MMIO register */
4590		pSiS->CmdQueLenMask = (pSiS->TurboQueue) ? 0x1FFF : 0x00FF;
4591	} else {
4592	        /* TQ is never used on 6326/5597, because the accelerator
4593		 * always Syncs. So this is just cosmentic work. (And I
4594		 * am not even sure that 0x7fff is correct. MMIO 0x83a8
4595		 * holds 0xec0 if (30k) TQ is enabled, 0x20 if TQ disabled.
4596		 * The datasheet has no real explanation on the queue length
4597		 * if the TQ is enabled. Not syncing and waiting for a
4598		 * suitable queue length instead does not work.
4599		 */
4600	        pSiS->CmdQueLenMask = (pSiS->TurboQueue) ? 0x7FFF : 0x003F;
4601	}
4602
4603	/* This is to be subtracted from MMIO queue length register contents
4604	 * for getting the real Queue length.
4605	 */
4606	pSiS->CmdQueLenFix  = (pSiS->TurboQueue) ? 32 : 0;
4607    }
4608
4609
4610#ifdef SISDUALHEAD
4611    /* In dual head mode, we share availMem equally - so align it
4612     * to 8KB; this way, the address of the FB of the second
4613     * head is aligned to 4KB for mapping.
4614     */
4615   if(pSiS->DualHeadMode) pSiS->availMem &= 0xFFFFE000;
4616#endif
4617
4618    /* Check MaxXFBMem setting */
4619#ifdef SISDUALHEAD
4620    if(pSiS->DualHeadMode) {
4621        /* 1. Since DRI is not supported in dual head mode, we
4622	 *    don't need the MaxXFBMem setting - ignore it.
4623	 */
4624	if(pSiS->maxxfbmem) {
4625	   xf86DrvMsg(pScrn->scrnIndex, X_INFO,
4626		"MaxXFBMem ignored in Dual Head mode\n");
4627	}
4628	pSiS->maxxfbmem = pSiS->availMem;
4629    } else
4630#endif
4631	   if((pSiS->sisfbHeapStart) || (pSiS->sisfbHaveNewHeapDef)) {
4632
4633       /*
4634	* 2. We have memory layout info from sisfb - ignore MaxXFBMem
4635	*/
4636	if(pSiS->maxxfbmem) {
4637	   xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
4638		"Got memory layout info from sisfb, ignoring MaxXFBMem option\n");
4639	}
4640	if((pSiS->FbBaseOffset) && (!pSiS->sisfbHaveNewHeapDef)) {
4641	   xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
4642		"Incompatible sisfb version detected, DRI disabled\n");
4643	   pSiS->loadDRI = FALSE;
4644	   pSiS->maxxfbmem = pSiS->availMem;
4645	} else {
4646	   if(pSiS->FbBaseOffset) {
4647	      /* Revert our changes to FbBaseOffset and availMem; use sisfb's info */
4648	      pSiS->availMem += pSiS->FbBaseOffset;
4649	      pSiS->FbBaseOffset = 0;
4650	   }
4651	   if(pSiS->sisfbVideoOffset) {
4652	      /* a. DRI heap BELOW framebuffer */
4653	      pSiS->FbBaseOffset = pSiS->sisfbVideoOffset;
4654	      pSiS->availMem -= pSiS->FbBaseOffset;
4655	      pSiS->maxxfbmem = pSiS->availMem;
4656	   } else {
4657	      /* b. DRI heap ABOVE framebuffer (traditional layout) */
4658	      if(pSiS->availMem < (pSiS->sisfbHeapStart * 1024)) {
4659		 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
4660			"Internal error - sisfb memory layout corrupt\n");
4661		 pSiS->loadDRI = FALSE;
4662		 pSiS->maxxfbmem = pSiS->availMem;
4663	      } else {
4664	         pSiS->maxxfbmem = pSiS->sisfbHeapStart * 1024;
4665	      }
4666	   }
4667	}
4668
4669    } else if(pSiS->maxxfbmem) {
4670
4671       /*
4672	* 3. No sisfb, but user gave "MaxXFBMem"
4673	*/
4674	if(pSiS->FbBaseOffset) {
4675	   /* a. DRI heap BELOW framebuffer */
4676	   if(pSiS->maxxfbmem > (pSiS->availMem + pSiS->FbBaseOffset - pSiS->SiS76xUMASize)) {
4677	      xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
4678			"Invalid MaxXFBMem setting\n");
4679	      pSiS->maxxfbmem = pSiS->availMem;
4680	   } else {
4681	      /* Revert our changes */
4682	      pSiS->availMem += pSiS->FbBaseOffset;
4683	      /* Use user's MaxXFBMem setting */
4684	      pSiS->FbBaseOffset = pSiS->availMem - pSiS->maxxfbmem;
4685	      pSiS->availMem -= pSiS->FbBaseOffset;
4686	   }
4687	} else {
4688	   /* b. DRI heap ABOVE framebuffer (traditional layout) */
4689	   if(pSiS->maxxfbmem > pSiS->availMem) {
4690	      xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
4691			 "Invalid MaxXFBMem setting.\n");
4692	      pSiS->maxxfbmem = pSiS->availMem;
4693	   }
4694	}
4695
4696    } else {
4697
4698       /*
4699	* 4. No MaxXFBMem, no sisfb: Use all memory
4700	*/
4701	pSiS->maxxfbmem = pSiS->availMem;
4702
4703	/* ... except on chipsets, for which DRI is
4704	 * supported: If DRI is enabled, we now limit
4705	 * ourselves to a reasonable default:
4706	 */
4707
4708	if(pSiS->loadDRI) {
4709	   if(pSiS->FbBaseOffset) {
4710	      /* a. DRI heap BELOW framebuffer */
4711	      /* See how much UMA and LFB memory we have,
4712	       * and calculate a reasonable default. We
4713	       * use more vram for ourselves because these
4714	       * chips are eg. capable of larger Xv
4715	       * overlays, etc.
4716	       */
4717	      unsigned long total = (pSiS->SiS76xLFBSize + pSiS->SiS76xUMASize) / 1024;
4718	      unsigned long mymax;
4719	      if(total <= 16384)			/* <= 16MB: Use 8MB for X */
4720	         mymax = 8192 * 1024;
4721	      else if(total <= 32768)			/* <= 32MB: Use 16MB for X */
4722	         mymax = 16384 * 1024;
4723	      else					/* Otherwise: Use 20MB for X */
4724	         mymax = 20 * 1024 * 1024;
4725	      /* availMem is right now adjusted to not use the UMA
4726	       * area. Make sure that our default doesn't reach
4727	       * into the UMA area either.
4728	       */
4729	      if(pSiS->availMem > mymax) {
4730		 /* Write our default to maxxfbmem */
4731		 pSiS->maxxfbmem = mymax;
4732		 /* Revert our changes to availMem */
4733		 pSiS->availMem += pSiS->FbBaseOffset;
4734		 /* Use our default setting */
4735		 pSiS->FbBaseOffset = pSiS->availMem - pSiS->maxxfbmem;
4736		 pSiS->availMem -= pSiS->FbBaseOffset;
4737	      }
4738	   } else {
4739	      /* b. DRI heap ABOVE framebuffer (traditional layout) */
4740	      /* See how much video memory we have, and calculate
4741	       * a reasonable default.
4742	       * Since DRI is pointless with less than 4MB of total
4743	       * video RAM, we disable it in that case.
4744	       */
4745	      if(pScrn->videoRam <= 4096)
4746	         pSiS->loadDRI = FALSE;
4747	      else if(pScrn->videoRam <= 8192)		/* <= 8MB: Use 4MB for X */
4748	         pSiS->maxxfbmem = 4096 * 1024;
4749	      else if(pScrn->videoRam <= 16384)		/* <= 16MB: Use 8MB for X */
4750	         pSiS->maxxfbmem = 8192 * 1024;
4751#ifdef SISMERGED					/* Otherwise: --- */
4752	      else if(pSiS->MergedFB) {
4753	         if(pScrn->videoRam <= 65536)
4754	            pSiS->maxxfbmem = 16384 * 1024;	/* If MergedFB and <=64MB, use 16MB for X */
4755		 else
4756		    pSiS->maxxfbmem = 20 * 1024 * 1024;	/* If MergedFB and > 64MB, use 20MB for X */
4757	      }
4758#endif
4759	        else if(pSiS->VGAEngine == SIS_315_VGA) {
4760	         if(pScrn->videoRam <= 65536)
4761	            pSiS->maxxfbmem = 16384 * 1024;	/* On >=315 series and <=64MB, use 16MB */
4762		 else
4763		    pSiS->maxxfbmem = 20 * 1024 * 1024;	/* On >=315 series and > 64MB, use 20MB */
4764	      } else
4765	         pSiS->maxxfbmem = 12288 * 1024;	/* On <315 series, use 12MB */
4766
4767	      /* A final check */
4768	      if(pSiS->maxxfbmem > pSiS->availMem) {
4769		 pSiS->maxxfbmem = pSiS->availMem;
4770		 pSiS->loadDRI = FALSE;
4771	      }
4772	   }
4773
4774	}
4775    }
4776
4777    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using %dK of framebuffer memory at offset %dK\n",
4778				pSiS->maxxfbmem / 1024, pSiS->FbBaseOffset / 1024);
4779
4780    /* Find out about sub-classes of some chipsets and check
4781     * if the chipset supports two video overlays
4782     */
4783    if(pSiS->VGAEngine == SIS_300_VGA    ||
4784       pSiS->VGAEngine == SIS_315_VGA    ||
4785       pSiS->Chipset == PCI_CHIP_SIS530  ||
4786       pSiS->Chipset == PCI_CHIP_SIS6326 ||
4787       pSiS->Chipset == PCI_CHIP_SIS5597)  {
4788       pSiS->hasTwoOverlays = FALSE;
4789       switch(pSiS->Chipset) {
4790	 case PCI_CHIP_SIS300:
4791	 case PCI_CHIP_SIS540:  /* ? (If not, need to add the SwitchCRT Xv attribute!) */
4792	 case PCI_CHIP_SIS630:
4793	 case PCI_CHIP_SIS550:
4794	   pSiS->hasTwoOverlays = TRUE;
4795	   pSiS->SiS_SD_Flags |= SiS_SD_SUPPORT2OVL;
4796	   break;
4797	 case PCI_CHIP_SIS315PRO:
4798	   pSiS->ChipFlags |= SiSCF_LARGEOVERLAY;
4799	   break;
4800	 case PCI_CHIP_SIS330:
4801	   pSiS->ChipFlags |= (SiSCF_CRT2HWCKaputt | SiSCF_LARGEOVERLAY);
4802	   break;
4803	 case PCI_CHIP_SIS340:
4804	 case PCI_CHIP_XGIXG40: /* Verified: only 1 overlay */
4805	   pSiS->ChipFlags |= SiSCF_LARGEOVERLAY;
4806	   break;
4807	 case PCI_CHIP_SIS650:
4808	   {
4809	     UChar tempreg1, tempreg2;
4810	     static const char *id650str[] = {
4811		"650",       "650",       "650",       "650",
4812		"650 A0 AA", "650 A2 CA", "650",       "650",
4813		"M650 A0",   "M650 A1 AA","651 A0 AA", "651 A1 AA",
4814		"M650",      "65?",       "651",       "65?"
4815	     };
4816	     pSiS->ChipFlags |= SiSCF_LARGEOVERLAY;
4817	     if(pSiS->ChipType == SIS_650) {
4818		inSISIDXREG(SISCR, 0x5f, CR5F);
4819		CR5F &= 0xf0;
4820		andSISIDXREG(SISCR, 0x5c, 0x07);
4821		inSISIDXREG(SISCR, 0x5c, tempreg1);
4822		tempreg1 &= 0xf8;
4823		orSISIDXREG(SISCR, 0x5c, 0xf8);
4824		inSISIDXREG(SISCR, 0x5c, tempreg2);
4825		tempreg2 &= 0xf8;
4826		if((!tempreg1) || (tempreg2)) {
4827		   xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4828		      "SiS650 revision ID %x (%s)\n", CR5F, id650str[CR5F >> 4]);
4829		   if(CR5F & 0x80) {
4830		      pSiS->hasTwoOverlays = TRUE;  /* M650 or 651 */
4831		      pSiS->SiS_SD_Flags |= SiS_SD_SUPPORT2OVL;
4832		   }
4833		   switch(CR5F) {
4834		      case 0xa0:
4835		      case 0xb0:
4836		      case 0xe0:
4837		         pSiS->ChipFlags |= SiSCF_Is651;
4838		         break;
4839		      case 0x80:
4840		      case 0x90:
4841		      case 0xc0:
4842		         pSiS->ChipFlags |= SiSCF_IsM650;
4843		         break;
4844		   }
4845		} else {
4846		   pSiS->hasTwoOverlays = TRUE;
4847		   pSiS->SiS_SD_Flags |= SiS_SD_SUPPORT2OVL;
4848		   switch(CR5F) {
4849		      case 0x90:
4850			 inSISIDXREG(SISCR, 0x5c, tempreg1);
4851			 tempreg1 &= 0xf8;
4852			 switch(tempreg1) {
4853			    case 0x00:
4854			       pSiS->ChipFlags |= SiSCF_IsM652;
4855			       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4856			           "SiSM652 revision ID %x\n", CR5F);
4857			       break;
4858			    case 0x40:
4859			       pSiS->ChipFlags |= SiSCF_IsM653;
4860			       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4861			           "SiSM653 revision ID %x\n", CR5F);
4862			       break;
4863			    default:
4864			       pSiS->ChipFlags |= SiSCF_IsM650;
4865			       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4866			           "SiSM650 revision ID %x\n", CR5F);
4867			       break;
4868			 }
4869			 break;
4870		      case 0xb0:
4871			 pSiS->ChipFlags |= SiSCF_Is652;
4872			 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4873			     "SiS652 revision ID %x\n", CR5F);
4874			 break;
4875		      default:
4876			 pSiS->ChipFlags |= SiSCF_IsM650;
4877			 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4878			     "SiSM650 revision ID %x\n", CR5F);
4879			 break;
4880		   }
4881		}
4882	     }
4883	     break;
4884	   }
4885	 case PCI_CHIP_SIS660:
4886	   {
4887	     pSiS->ChipFlags |= SiSCF_LARGEOVERLAY;
4888	     pSiS->hasTwoOverlays = TRUE;
4889	     pSiS->SiS_SD_Flags |= SiS_SD_SUPPORT2OVL;
4890	     /* 760/761:  - UMA only: one/two overlays - dotclock dependent
4891			  - UMA+LFB:  two overlays if video data in LFB
4892			  - LFB only: two overlays
4893		If UMA only: Must switch between one/two overlays on the fly (done
4894			     in PostSetMode())
4895		If LFB+UMA:  We use LFB memory only and leave UMA to an eventually
4896			     written DRI driver.
4897	      */
4898	     break;
4899	   }
4900       }
4901
4902       if(!(pSiS->SiS_SD2_Flags & SiS_SD2_NOOVERLAY)) {
4903          xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4904		"Hardware supports %s video overlay%s\n",
4905		pSiS->hasTwoOverlays ? "two" : "one",
4906		pSiS->hasTwoOverlays ? "s" : "");
4907       }
4908
4909       if(pSiS->SiS_SD2_Flags & SiS_SD2_SUPPORT760OO) {
4910	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
4911		"\n\tDear SiS76x user, your machine is using a shared memory framebuffer.\n"
4912		  "\tDue to hardware limitations of the SiS chip in combination with the\n"
4913		  "\tAMD CPU, video overlay support is very limited on this machine. If you\n"
4914		  "\texperience flashing lines in the video and/or the graphics display\n"
4915		  "\tduring video playback, reduce the color depth and/or the resolution\n"
4916		  "\tand/or the refresh rate. Alternatively, use the video blitter.\n");
4917       }
4918
4919    }
4920
4921    /* Backup VB connection and CRT1 on/off register */
4922    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
4923       inSISIDXREG(SISSR, 0x1f, pSiS->oldSR1F);
4924       inSISIDXREG(SISCR, 0x17, pSiS->oldCR17);
4925       inSISIDXREG(SISCR, 0x32, pSiS->oldCR32);
4926       inSISIDXREG(SISCR, 0x36, pSiS->oldCR36);
4927       inSISIDXREG(SISCR, 0x37, pSiS->oldCR37);
4928       if(pSiS->VGAEngine == SIS_315_VGA) {
4929          inSISIDXREG(SISCR, pSiS->myCR63, pSiS->oldCR63);
4930       }
4931
4932       pSiS->postVBCR32 = pSiS->oldCR32;
4933    }
4934
4935    /* There are some machines out there which require a special
4936     * setup of the GPIO registers in order to make the Chrontel
4937     * work. Try to find out if we're running on such a machine.
4938     * Furthermore, there is some highly customized hardware,
4939     * which requires some non-standard LVDS timing. Since the
4940     * vendors don't seem to care about PCI subsystem ID's we
4941     * need to find out using the BIOS version and date strings.
4942     */
4943    pSiS->SiS_Pr->SiS_ChSW = FALSE;
4944    if(pSiS->Chipset == PCI_CHIP_SIS630) {
4945       int i = 0;
4946       do {
4947	  if(mychswtable[i].subsysVendor == PCI_SUB_VENDOR_ID(pSiS->PciInfo) &&
4948	     mychswtable[i].subsysCard == PCI_SUB_DEVICE_ID(pSiS->PciInfo)) {
4949	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
4950	         "PCI subsystem ID found in list for Chrontel/GPIO setup:\n");
4951	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4952		 "\tVendor/Card: %s %s (ID %04x)\n",
4953		  mychswtable[i].vendorName,
4954		  mychswtable[i].cardName,
4955		  PCI_SUB_DEVICE_ID(pSiS->PciInfo));
4956	     pSiS->SiS_Pr->SiS_ChSW = TRUE;
4957	     break;
4958          }
4959          i++;
4960       } while(mychswtable[i].subsysVendor != 0);
4961    }
4962
4963    if(pSiS->SiS_Pr->SiS_CustomT == CUT_NONE) {
4964       int    i = 0, j;
4965       UShort bversptr = 0;
4966       Bool   footprint;
4967       CARD32 chksum = 0;
4968
4969       if(pSiS->SiS_Pr->UseROM) {
4970          bversptr = pSiS->BIOS[0x16] | (pSiS->BIOS[0x17] << 8);
4971          for(i=0; i<32768; i++) chksum += pSiS->BIOS[i];
4972       }
4973
4974       i = 0;
4975       do {
4976	  if( (SiS_customttable[i].chipID == pSiS->ChipType)                            &&
4977	      ((!strlen(SiS_customttable[i].biosversion)) ||
4978	       (pSiS->SiS_Pr->UseROM &&
4979	       (!strncmp(SiS_customttable[i].biosversion, (char *)&pSiS->BIOS[bversptr],
4980	                strlen(SiS_customttable[i].biosversion)))))                     &&
4981	      ((!strlen(SiS_customttable[i].biosdate)) ||
4982	       (pSiS->SiS_Pr->UseROM &&
4983	       (!strncmp(SiS_customttable[i].biosdate, (char *)&pSiS->BIOS[0x2c],
4984	                strlen(SiS_customttable[i].biosdate)))))			      &&
4985	      ((!SiS_customttable[i].bioschksum) ||
4986	       (pSiS->SiS_Pr->UseROM &&
4987	       (SiS_customttable[i].bioschksum == chksum)))			      &&
4988	      (SiS_customttable[i].pcisubsysvendor == PCI_SUB_VENDOR_ID(pSiS->PciInfo))      &&
4989	      (SiS_customttable[i].pcisubsyscard == PCI_SUB_DEVICE_ID(pSiS->PciInfo)) ) {
4990	     footprint = TRUE;
4991	     for(j=0; j<5; j++) {
4992	        if(SiS_customttable[i].biosFootprintAddr[j]) {
4993		   if(pSiS->SiS_Pr->UseROM) {
4994		      if(pSiS->BIOS[SiS_customttable[i].biosFootprintAddr[j]] !=
4995						SiS_customttable[i].biosFootprintData[j])
4996		         footprint = FALSE;
4997		   } else footprint = FALSE;
4998	        }
4999	     }
5000	     if(footprint) {
5001	        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5002	           "Identified %s %s, special timing applies\n",
5003		   SiS_customttable[i].vendorName, SiS_customttable[i].cardName);
5004	        pSiS->SiS_Pr->SiS_CustomT = SiS_customttable[i].SpecialID;
5005	        break;
5006	     }
5007          }
5008          i++;
5009       } while(SiS_customttable[i].chipID);
5010    }
5011
5012    /* Handle ForceCRT1 option */
5013    if(pSiS->forceCRT1 != -1) {
5014       if(pSiS->forceCRT1) pSiS->CRT1off = 0;
5015       else                pSiS->CRT1off = 1;
5016    } else                 pSiS->CRT1off = -1;
5017
5018    /* Detect video bridge and sense TV/VGA2 */
5019    SISVGAPreInit(pScrn);
5020
5021    /* Detect CRT1 (via DDC1 and DDC2, hence via VGA port; regardless of LCDA) */
5022    SISCRT1PreInit(pScrn);
5023
5024    /* Detect LCD (connected via CRT2, regardless of LCDA) and LCD resolution */
5025    SISLCDPreInit(pScrn, FALSE);
5026
5027    /* LCDA only supported under these conditions: */
5028    if(pSiS->ForceCRT1Type == CRT1_LCDA) {
5029       if(!SISDetermineLCDACap(pScrn)) {
5030	  xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5031		"Chipset/Video bridge does not support LCD-via-CRT1\n");
5032	  pSiS->ForceCRT1Type = CRT1_VGA;
5033       } else if(!(pSiS->VBFlags & CRT2_LCD)) {
5034	  xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5035		"No digital LCD panel found, LCD-via-CRT1 disabled\n");
5036	  pSiS->ForceCRT1Type = CRT1_VGA;
5037       }
5038    }
5039
5040    /* Setup SD flags */
5041    pSiS->SiS_SD_Flags |= SiS_SD_ADDLSUPFLAG;
5042
5043    pSiS->SiS_SD2_Flags |= SiS_SD2_MERGEDUCLOCK;
5044    pSiS->SiS_SD2_Flags |= SiS_SD2_USEVBFLAGS2;
5045    pSiS->SiS_SD2_Flags |= SiS_SD2_VBINVB2ONLY;
5046    pSiS->SiS_SD2_Flags |= SiS_SD2_HAVESD34;
5047    pSiS->SiS_SD2_Flags |= SiS_SD2_NEWGAMMABRICON;
5048
5049    pSiS->SiS_SD3_Flags |= SiS_SD3_MFBALLOWOFFCL;
5050
5051    if(pSiS->VBFlags2 & VB2_VIDEOBRIDGE) {
5052       pSiS->SiS_SD2_Flags |= SiS_SD2_VIDEOBRIDGE;
5053       if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
5054	  pSiS->SiS_SD2_Flags |= ( SiS_SD2_SISBRIDGE     |
5055				   SiS_SD2_SUPPORTGAMMA2 );
5056	  if(pSiS->VBFlags2 & VB2_SISLVDSBRIDGE) {
5057	     pSiS->SiS_SD2_Flags |= ( SiS_SD2_LCDLVDS    |
5058				      SiS_SD2_SUPPORTLCD );
5059	  } else if(pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) {
5060	     if(!(pSiS->VBFlags2 & VB2_30xBDH)) {
5061		pSiS->SiS_SD2_Flags |= ( SiS_SD2_LCDTMDS    |
5062					 SiS_SD2_SUPPORTLCD );
5063	     } else if(pSiS->VBFlags & CRT2_LCD) {
5064		pSiS->SiS_SD2_Flags |= ( SiS_SD2_THIRDPARTYLVDS |
5065				         SiS_SD2_SUPPORTLCD );
5066	     }
5067	  }
5068       } else if(pSiS->VBFlags2 & VB2_LVDS) {
5069	  pSiS->SiS_SD2_Flags |= ( SiS_SD2_THIRDPARTYLVDS |
5070				   SiS_SD2_SUPPORTLCD );
5071       }
5072
5073       if(pSiS->VBFlags2 & (VB2_SISTVBRIDGE | VB2_CHRONTEL)) {
5074	  pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTTV;
5075	  if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
5076	     pSiS->SiS_SD2_Flags |= ( SiS_SD2_SUPPORTTVTYPE |
5077				      SiS_SD2_SUPPORTTVSIZE );
5078	     if(!(pSiS->VBFlags2 & VB2_301)) {
5079		pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPTVSAT;
5080	     } else {
5081		pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPTVEDGE;
5082	     }
5083	  }
5084       }
5085    }
5086
5087#ifdef ENABLE_YPBPR
5088    if((pSiS->VGAEngine == SIS_315_VGA) &&
5089       (pSiS->VBFlags2 & VB2_SISYPBPRBRIDGE)) {
5090       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTYPBPR;
5091       pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORT625I;
5092       pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORT625P;
5093       if(pSiS->VBFlags2 & VB2_SISYPBPRARBRIDGE) {
5094          pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTYPBPRAR;
5095       }
5096    }
5097    if(pSiS->VBFlags2 & VB2_SISHIVISIONBRIDGE) {
5098       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTHIVISION;
5099    }
5100#endif
5101
5102    if((pSiS->VGAEngine != SIS_300_VGA) || (!(pSiS->VBFlags2 & VB2_TRUMPION))) {
5103       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTSCALE;
5104       if((pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) &&
5105          (!(pSiS->VBFlags2 & VB2_30xBDH))) {
5106          pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTCENTER;
5107       }
5108    }
5109
5110#ifdef SISDUALHEAD
5111    if(!pSiS->DualHeadMode) {
5112       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTREDETECT;
5113    }
5114#endif
5115
5116#ifndef SISCHECKOSSSE
5117    pSiS->SiS_SD2_Flags |= SiS_SD2_NEEDUSESSE;
5118#endif
5119
5120#ifdef TWDEBUG	/* FOR TESTING */
5121    pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTYPBPRAR;
5122    xf86DrvMsg(0, X_INFO, "TEST: Support Aspect Ratio\n");
5123#endif
5124
5125    /* Detect CRT2-TV and PAL/NTSC mode */
5126    SISTVPreInit(pScrn, FALSE);
5127
5128    /* Detect CRT2-VGA */
5129    SISCRT2PreInit(pScrn, FALSE);
5130
5131    /* Backup detected CRT2 devices */
5132    SISSaveDetectedDevices(pScrn);
5133
5134    if(!(pSiS->SiS_SD_Flags & SiS_SD_SUPPORTYPBPR)) {
5135       if((pSiS->ForceTVType != -1) && (pSiS->ForceTVType & TV_YPBPR)) {
5136	  pSiS->ForceTVType = -1;
5137	  xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "YPbPr TV output not supported\n");
5138       }
5139    }
5140
5141    if(!(pSiS->SiS_SD_Flags & SiS_SD_SUPPORTHIVISION)) {
5142       if((pSiS->ForceTVType != -1) && (pSiS->ForceTVType & TV_HIVISION)) {
5143	  pSiS->ForceTVType = -1;
5144	  xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "HiVision TV output not supported\n");
5145       }
5146    }
5147
5148    if((pSiS->VBFlags2 & VB2_SISTVBRIDGE) ||
5149       ((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->ChrontelType == CHRONTEL_701x))) {
5150       pSiS->SiS_SD_Flags |= (SiS_SD_SUPPORTPALMN | SiS_SD_SUPPORTNTSCJ);
5151    }
5152    if((pSiS->VBFlags2 & VB2_SISTVBRIDGE) ||
5153       ((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->ChrontelType == CHRONTEL_700x))) {
5154       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTTVPOS;
5155    }
5156    if(pSiS->VBFlags2 & VB2_SISVGA2BRIDGE) {
5157       pSiS->SiS_SD_Flags |= (SiS_SD_SUPPORTSCART | SiS_SD_SUPPORTVGA2);
5158    }
5159    if(pSiS->VBFlags2 & VB2_CHRONTEL) {
5160       pSiS->SiS_SD_Flags  |= SiS_SD_SUPPORTOVERSCAN;
5161       pSiS->SiS_SD2_Flags |= SiS_SD2_CHRONTEL;
5162       if(pSiS->ChrontelType == CHRONTEL_700x) {
5163	  pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTSOVER;
5164       }
5165    }
5166
5167    /* Determine if chipset LCDA-capable */
5168    pSiS->SiS_SD_Flags &= ~SiS_SD_SUPPORTLCDA;
5169    if(SISDetermineLCDACap(pScrn)) {
5170       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTLCDA;
5171    }
5172
5173    /* Default to LCDA if LCD detected and
5174     * - TV detected (hence default to LCDA+TV), or
5175     * - in single head mode, on LCD panels with xres > 1600
5176     *   (Don't do this in MergedFB or DHM; LCDA and CRT1/VGA
5177     *   are mutually exclusive; if no TV is detected, the
5178     *   code below will default to VGA+LCD, so LCD is driven
5179     *   via CRT2.)
5180     *   (TODO: This might need some modification for the
5181     *   307 bridges, if these are capable of driving
5182     *   LCDs > 1600 via channel B)
5183     */
5184    if((pSiS->SiS_SD_Flags & SiS_SD_SUPPORTLCDA) &&
5185       (pSiS->VBFlags & CRT2_LCD) &&
5186       (pSiS->SiS_Pr->SiS_CustomT != CUT_UNKNOWNLCD)) {
5187       if((!pSiS->CRT1TypeForced) && (pSiS->ForceCRT2Type == CRT2_DEFAULT)) {
5188	  if(pSiS->VBFlags & CRT2_TV) {
5189	     /* If both LCD and TV present, default to LCDA+TV */
5190	     pSiS->ForceCRT1Type = CRT1_LCDA;
5191	     pSiS->ForceCRT2Type = CRT2_TV;
5192	  } else if(pSiS->LCDwidth > 1600) {
5193	     /* If LCD is > 1600, default to LCDA if we don't need CRT1/VGA for other head */
5194	     Bool NeedCRT1VGA = FALSE;
5195#ifdef SISDUALHEAD
5196	     if(pSiS->DualHeadMode) NeedCRT1VGA = TRUE;
5197#endif
5198#ifdef SISMERGED
5199	     if(pSiS->MergedFB &&
5200		(!pSiS->MergedFBAuto || pSiS->CRT1Detected)) NeedCRT1VGA = TRUE;
5201#endif
5202	     if(!NeedCRT1VGA) {
5203		pSiS->ForceCRT1Type = CRT1_LCDA;
5204	     }
5205	  }
5206       }
5207    }
5208
5209    /* Set up pseudo-panel if LCDA forced on TMDS bridges */
5210    if(pSiS->SiS_SD_Flags & SiS_SD_SUPPORTLCDA) {
5211       if(pSiS->ForceCRT1Type == CRT1_LCDA) {
5212          if(pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE) {
5213	     if(!(pSiS->VBLCDFlags)) {
5214		SiSSetupPseudoPanel(pScrn);
5215		pSiS->detectedCRT2Devices |= CRT2_LCD;
5216	     }
5217	  } else if(!(pSiS->VBLCDFlags)) {
5218	     pSiS->ForceCRT1Type = CRT1_VGA;
5219	  }
5220       }
5221    } else {
5222       pSiS->ForceCRT1Type = CRT1_VGA;
5223    }
5224
5225    pSiS->VBFlags |= pSiS->ForceCRT1Type;
5226
5227#ifdef TWDEBUG
5228    xf86DrvMsg(0, X_INFO, "SDFlags %lx\n", pSiS->SiS_SD_Flags);
5229#endif
5230
5231    /* Eventually overrule detected CRT2 type
5232     * If no type forced, use the detected devices in the order TV->LCD->VGA2
5233     * Since the Chrontel 7005 sometimes delivers wrong detection results,
5234     * we use a different order on such machines (LCD->TV)
5235     */
5236    if(pSiS->ForceCRT2Type == CRT2_DEFAULT) {
5237       if((pSiS->VBFlags & CRT2_TV) && (!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VGAEngine == SIS_300_VGA))))
5238	  pSiS->ForceCRT2Type = CRT2_TV;
5239       else if((pSiS->VBFlags & CRT2_LCD) && (pSiS->ForceCRT1Type == CRT1_VGA))
5240	  pSiS->ForceCRT2Type = CRT2_LCD;
5241       else if(pSiS->VBFlags & CRT2_TV)
5242	  pSiS->ForceCRT2Type = CRT2_TV;
5243       else if((pSiS->VBFlags & CRT2_VGA) && (pSiS->ForceCRT1Type == CRT1_VGA))
5244	  pSiS->ForceCRT2Type = CRT2_VGA;
5245    }
5246
5247    switch(pSiS->ForceCRT2Type) {
5248       case CRT2_TV:
5249	  pSiS->VBFlags &= ~(CRT2_LCD | CRT2_VGA);
5250	  if(pSiS->VBFlags2 & (VB2_SISTVBRIDGE | VB2_CHRONTEL)) {
5251	     pSiS->VBFlags |= CRT2_TV;
5252	  } else {
5253	     pSiS->VBFlags &= ~(CRT2_TV);
5254	     xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
5255		"Hardware does not support TV output\n");
5256	  }
5257	  break;
5258       case CRT2_LCD:
5259	  pSiS->VBFlags &= ~(CRT2_TV | CRT2_VGA);
5260	  if((pSiS->VBFlags2 & VB2_VIDEOBRIDGE) && (pSiS->VBLCDFlags)) {
5261	     pSiS->VBFlags |= CRT2_LCD;
5262	  } else if((pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) && (!(pSiS->VBFlags2 & VB2_30xBDH))) {
5263	     SiSSetupPseudoPanel(pScrn);
5264	     pSiS->detectedCRT2Devices |= CRT2_LCD;
5265	  } else {
5266	     pSiS->VBFlags &= ~(CRT2_LCD);
5267	     xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
5268		"Can't force CRT2 to LCD, no LCD detected\n");
5269	  }
5270	  break;
5271       case CRT2_VGA:
5272	  pSiS->VBFlags &= ~(CRT2_TV | CRT2_LCD);
5273	  if(pSiS->VBFlags2 & VB2_SISVGA2BRIDGE) {
5274	     pSiS->VBFlags |= CRT2_VGA;
5275	  } else {
5276	     pSiS->VBFlags &= ~(CRT2_VGA);
5277	     xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
5278		 "Hardware does not support secondary VGA\n");
5279	  }
5280	  break;
5281       default:
5282	  pSiS->VBFlags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
5283    }
5284
5285    /* Setup gamma (the cmap layer needs this to be initialised) */
5286    /* (Do this after evaluating options) */
5287    {
5288       Gamma zeros = {0.0, 0.0, 0.0};
5289       xf86SetGamma(pScrn, zeros);
5290    }
5291
5292#ifdef SISDUALHEAD
5293    if((!pSiS->DualHeadMode) || (pSiS->SecondHead)) {
5294#endif
5295       xf86DrvMsg(pScrn->scrnIndex, pSiS->CRT1gammaGiven ? X_CONFIG : X_INFO,
5296	     "%samma correction is %s\n",
5297	     (pSiS->VBFlags2 & VB2_VIDEOBRIDGE) ? "CRT1 g" : "G",
5298	     pSiS->CRT1gamma ? "enabled" : "disabled");
5299
5300       if((pSiS->VGAEngine == SIS_315_VGA)	&&
5301          (!(pSiS->NoXvideo))			&&
5302	  (!(pSiS->SiS_SD2_Flags & SiS_SD2_NOOVERLAY))) {
5303	  xf86DrvMsg(pScrn->scrnIndex, pSiS->XvGammaGiven ? X_CONFIG : X_INFO,
5304		"Separate Xv gamma correction %sis %s\n",
5305		(pSiS->VBFlags2 & VB2_VIDEOBRIDGE) ? "for CRT1 " : "",
5306		pSiS->XvGamma ? "enabled" : "disabled");
5307	  if(pSiS->XvGamma) {
5308	     xf86DrvMsg(pScrn->scrnIndex, pSiS->XvGammaGiven ? X_CONFIG : X_INFO,
5309		"Xv gamma correction: %.3f %.3f %.3f\n",
5310		(float)((float)pSiS->XvGammaRed / 1000),
5311		(float)((float)pSiS->XvGammaGreen / 1000),
5312		(float)((float)pSiS->XvGammaBlue / 1000));
5313	     if(!pSiS->CRT1gamma) {
5314		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5315		   "Xv gamma correction requires %samma correction enabled\n",
5316		   (pSiS->VBFlags2 & VB2_VIDEOBRIDGE) ? "CRT1 g" : "G");
5317	     }
5318	  }
5319       }
5320#ifdef SISDUALHEAD
5321    }
5322#endif
5323
5324#ifdef SISDUALHEAD
5325    if(pSiS->DualHeadMode) pSiS->CRT2SepGamma = FALSE;
5326#endif
5327
5328#ifdef SISDUALHEAD
5329    if((!pSiS->DualHeadMode) || (!pSiS->SecondHead))
5330#endif
5331    {
5332       Bool isDH = FALSE;
5333       if(pSiS->CRT2gamma) {
5334          if( ((pSiS->VGAEngine != SIS_300_VGA) && (pSiS->VGAEngine != SIS_315_VGA)) ||
5335              (!(pSiS->VBFlags2 & VB2_SISBRIDGE)) ) {
5336	     if(pSiS->VBFlags2 & VB2_VIDEOBRIDGE) {
5337	        xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5338			"CRT2 gamma correction not supported by hardware\n");
5339	     }
5340	     pSiS->CRT2gamma = pSiS->CRT2SepGamma = FALSE;
5341          } else if((pSiS->VBFlags2 & VB2_30xBDH) && (pSiS->VBFlags & CRT2_LCD)) {
5342	     isDH = TRUE;
5343	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5344			"CRT2 gamma correction not supported for LCD\n");
5345	     /* But leave it on, will be caught in LoadPalette */
5346          }
5347       }
5348       if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
5349	  xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CRT2 gamma correction is %s%s%s\n",
5350		pSiS->CRT2gamma ? "enabled" : "disabled",
5351		isDH ? " (for TV and VGA2) " : "",
5352		pSiS->CRT2SepGamma ? " (separate from CRT1)" : "");
5353       }
5354    }
5355
5356    /* Eventually overrule TV Type (SVIDEO, COMPOSITE, SCART, HIVISION, YPBPR) */
5357    if(pSiS->VBFlags2 & VB2_SISTVBRIDGE) {
5358       if(pSiS->ForceTVType != -1) {
5359	  pSiS->VBFlags &= ~(TV_INTERFACE);
5360	  if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) {
5361	     pSiS->VBFlags &= ~(TV_CHSCART | TV_CHYPBPR525I);
5362	  }
5363	  pSiS->VBFlags |= pSiS->ForceTVType;
5364	  if(pSiS->VBFlags & TV_YPBPR) {
5365	     pSiS->VBFlags &= ~(TV_STANDARD);
5366	     pSiS->VBFlags &= ~(TV_YPBPRAR);
5367	     pSiS->VBFlags |= pSiS->ForceYPbPrType;
5368	     pSiS->VBFlags |= pSiS->ForceYPbPrAR;
5369	  }
5370       }
5371    }
5372
5373    /* Handle ForceCRT1 option (part 2) */
5374    pSiS->CRT1changed = FALSE;
5375    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
5376       usScratchCR17 = pSiS->oldCR17;
5377       usScratchCR63 = pSiS->oldCR63;
5378       usScratchSR1F = pSiS->oldSR1F;
5379       usScratchCR32 = pSiS->postVBCR32;
5380       if(pSiS->VESA != 1) {
5381          /* Copy forceCRT1 option to CRT1off if option is given */
5382#ifdef SISDUALHEAD
5383          /* In DHM, handle this option only for master head, not the slave */
5384          if( (pSiS->forceCRT1 != -1) &&
5385	       (!(pSiS->DualHeadMode && pSiS->SecondHead)) ) {
5386#else
5387          if(pSiS->forceCRT1 != -1) {
5388#endif
5389	     xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
5390		 "CRT1 detection overruled by ForceCRT1 option\n");
5391	     if(pSiS->forceCRT1) {
5392		 pSiS->CRT1off = 0;
5393		 if(pSiS->VGAEngine == SIS_300_VGA) {
5394		    if(!(usScratchCR17 & 0x80)) pSiS->CRT1changed = TRUE;
5395		 } else {
5396		    if(usScratchCR63 & 0x40) pSiS->CRT1changed = TRUE;
5397		 }
5398		 usScratchCR17 |= 0x80;
5399		 usScratchCR32 |= 0x20;
5400		 usScratchCR63 &= ~0x40;
5401		 usScratchSR1F &= ~0xc0;
5402	     } else {
5403		 if( ! ( (pScrn->bitsPerPixel == 8) &&
5404		         ( (pSiS->VBFlags2 & (VB2_LVDS | VB2_CHRONTEL)) ||
5405		           ((pSiS->VBFlags2 & VB2_30xBDH) && (pSiS->VBFlags & CRT2_LCD)) ) ) ) {
5406		    pSiS->CRT1off = 1;
5407		    if(pSiS->VGAEngine == SIS_300_VGA) {
5408		       if(usScratchCR17 & 0x80) pSiS->CRT1changed = TRUE;
5409		    } else {
5410		       if(!(usScratchCR63 & 0x40)) pSiS->CRT1changed = TRUE;
5411		    }
5412		    usScratchCR32 &= ~0x20;
5413		    /* We must not actually switch off CRT1 before we changed the mode! */
5414		 }
5415	     }
5416	     /* Here we can write to CR17 even on 315 series as we only ENABLE
5417	      * the bit here
5418	      */
5419	     outSISIDXREG(SISCR, 0x17, usScratchCR17);
5420	     if(pSiS->VGAEngine == SIS_315_VGA) {
5421		outSISIDXREG(SISCR, pSiS->myCR63, usScratchCR63);
5422	     }
5423	     outSISIDXREG(SISCR, 0x32, usScratchCR32);
5424	     if(pSiS->CRT1changed) {
5425		outSISIDXREG(SISSR, 0x00, 0x01);    /* Synchronous Reset */
5426		usleep(10000);
5427		outSISIDXREG(SISSR, 0x00, 0x03);    /* End Reset */
5428		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5429			"CRT1 status changed by ForceCRT1 option\n");
5430	     }
5431	     outSISIDXREG(SISSR, 0x1f, usScratchSR1F);
5432          }
5433       }
5434       /* Store the new VB connection register contents for later mode changes */
5435       pSiS->newCR32 = usScratchCR32;
5436    }
5437
5438    /* Check if CRT1 used (or needed; this eg. if no CRT2 detected) */
5439    if(pSiS->VBFlags2 & VB2_VIDEOBRIDGE) {
5440
5441        /* No CRT2 output? Then we NEED CRT1!
5442	 * We also need CRT1 if depth = 8 and bridge=LVDS|301B-DH
5443	 */
5444	if( (!(pSiS->VBFlags & (CRT2_VGA | CRT2_LCD | CRT2_TV))) ||
5445	    ( (pScrn->bitsPerPixel == 8) &&
5446	      ( (pSiS->VBFlags2 & (VB2_LVDS | VB2_CHRONTEL)) ||
5447	        ((pSiS->VBFlags2 & VB2_30xBDH) && (pSiS->VBFlags & CRT2_LCD)) ) ) ) {
5448	    pSiS->CRT1off = 0;
5449	}
5450	/* No CRT2 output? Then we can't use Xv on CRT2 */
5451	if(!(pSiS->VBFlags & (CRT2_VGA | CRT2_LCD | CRT2_TV))) {
5452	    pSiS->XvOnCRT2 = FALSE;
5453	}
5454
5455    } else { /* no video bridge? */
5456	/* Then we NEED CRT1... */
5457	pSiS->CRT1off = 0;
5458	/* ... and can't use CRT2 for Xv output */
5459	pSiS->XvOnCRT2 = FALSE;
5460    }
5461
5462    /* LCDA? Then we don't switch off CRT1 */
5463    if(pSiS->VBFlags & CRT1_LCDA) pSiS->CRT1off = 0;
5464
5465    /* Handle TVStandard option */
5466    if((pSiS->NonDefaultPAL != -1) || (pSiS->NonDefaultNTSC != -1)) {
5467       if( (!(pSiS->VBFlags2 & VB2_SISTVBRIDGE)) &&
5468	   (!((pSiS->VBFlags2 & VB2_CHRONTEL)) && (pSiS->ChrontelType == CHRONTEL_701x)) ) {
5469	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5470	   	"PALM, PALN and NTSCJ not supported on this hardware\n");
5471	  pSiS->NonDefaultPAL = pSiS->NonDefaultNTSC = -1;
5472	  pSiS->VBFlags &= ~(TV_PALN | TV_PALM | TV_NTSCJ);
5473	  pSiS->SiS_SD_Flags &= ~(SiS_SD_SUPPORTPALMN | SiS_SD_SUPPORTNTSCJ);
5474       }
5475    }
5476    if(pSiS->OptTVStand != -1) {
5477       if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
5478	  if( (!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & (TV_CHSCART | TV_CHYPBPR525I)))) &&
5479	      (!(pSiS->VBFlags & (TV_HIVISION | TV_YPBPR))) ) {
5480	     pSiS->VBFlags &= ~(TV_PAL | TV_NTSC | TV_PALN | TV_PALM | TV_NTSCJ);
5481	     if(pSiS->OptTVStand) {
5482	        pSiS->VBFlags |= TV_PAL;
5483	        if(pSiS->NonDefaultPAL == 1)  pSiS->VBFlags |= TV_PALM;
5484	        else if(!pSiS->NonDefaultPAL) pSiS->VBFlags |= TV_PALN;
5485	     } else {
5486	        pSiS->VBFlags |= TV_NTSC;
5487		if(pSiS->NonDefaultNTSC == 1) pSiS->VBFlags |= TV_NTSCJ;
5488	     }
5489	  } else {
5490	     pSiS->OptTVStand = pSiS->NonDefaultPAL = -1;
5491	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5492	    	 "Option TVStandard ignored for YPbPr, HiVision and Chrontel-SCART\n");
5493	  }
5494       } else if(pSiS->Chipset == PCI_CHIP_SIS6326) {
5495	  pSiS->SiS6326Flags &= ~SIS6326_TVPAL;
5496	  if(pSiS->OptTVStand) pSiS->SiS6326Flags |= SIS6326_TVPAL;
5497       }
5498    }
5499
5500    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
5501       /* Default to PAL */
5502       if(pSiS->VBFlags & (TV_SVIDEO | TV_AVIDEO)) {
5503          if(!(pSiS->VBFlags & (TV_PAL | TV_NTSC))) {
5504	     pSiS->VBFlags &= ~(TV_PAL | TV_NTSC | TV_PALN | TV_PALM | TV_NTSCJ);
5505	     pSiS->VBFlags |= TV_PAL;
5506	  }
5507       }
5508       /* SCART only supported for PAL */
5509       if((pSiS->VBFlags2 & VB2_SISBRIDGE) && (pSiS->VBFlags & TV_SCART)) {
5510	  pSiS->VBFlags &= ~(TV_NTSC | TV_PALN | TV_PALM | TV_NTSCJ);
5511	  pSiS->VBFlags |= TV_PAL;
5512	  pSiS->OptTVStand = 1;
5513	  pSiS->NonDefaultPAL = pSiS->NonDefaultNTSC = -1;
5514       }
5515    }
5516
5517#ifdef SIS_CP
5518    SIS_CP_DRIVER_RECONFIGOPT
5519#endif
5520
5521    if((pSiS->Chipset == PCI_CHIP_SIS6326) && (pSiS->SiS6326Flags & SIS6326_HASTV)) {
5522       if(pSiS->sis6326tvplug != -1) {
5523          pSiS->SiS6326Flags &= ~(SIS6326_TVSVIDEO | SIS6326_TVCVBS);
5524	  pSiS->SiS6326Flags |= SIS6326_TVDETECTED;
5525	  if(pSiS->sis6326tvplug == 1) 	pSiS->SiS6326Flags |= SIS6326_TVCVBS;
5526	  else 				pSiS->SiS6326Flags |= SIS6326_TVSVIDEO;
5527	  xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
5528	      "SiS6326 TV plug type detection overruled by %s\n",
5529	      (pSiS->SiS6326Flags & SIS6326_TVCVBS) ? "COMPOSITE" : "SVIDEO");
5530       }
5531    }
5532
5533    /* Do some checks */
5534    if(pSiS->OptTVOver != -1) {
5535       if(pSiS->VBFlags2 & VB2_CHRONTEL) {
5536	  pSiS->UseCHOverScan = pSiS->OptTVOver;
5537       } else {
5538	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5539	      "CHTVOverscan only supported on CHRONTEL 70xx\n");
5540	  pSiS->UseCHOverScan = -1;
5541       }
5542    } else pSiS->UseCHOverScan = -1;
5543
5544    if(pSiS->sistvedgeenhance != -1) {
5545       if(!(pSiS->VBFlags2 & VB2_301)) {
5546	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5547	      "SISTVEdgeEnhance only supported on SiS301\n");
5548	  pSiS->sistvedgeenhance = -1;
5549       }
5550    }
5551    if(pSiS->sistvsaturation != -1) {
5552       if(pSiS->VBFlags2 & VB2_301) {
5553	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5554	      "SISTVSaturation not supported on SiS301\n");
5555	  pSiS->sistvsaturation = -1;
5556       }
5557    }
5558
5559    /* Do some MergedFB mode initialisation */
5560#ifdef SISMERGED
5561    if(pSiS->MergedFB) {
5562       pSiS->CRT2pScrn = xalloc(sizeof(ScrnInfoRec));
5563       if(!pSiS->CRT2pScrn) {
5564          SISErrorLog(pScrn, "Failed to allocate memory for 2nd pScrn, %s\n", mergeddisstr);
5565	  pSiS->MergedFB = FALSE;
5566       } else {
5567          memcpy(pSiS->CRT2pScrn, pScrn, sizeof(ScrnInfoRec));
5568       }
5569    }
5570#endif
5571
5572    /* Determine CRT1<>CRT2 mode
5573     *     Note: When using VESA or if the bridge is in slavemode, display
5574     *           is ALWAYS in MIRROR_MODE!
5575     *           This requires extra checks in functions using this flag!
5576     *           (see sis_video.c for example)
5577     */
5578    if(pSiS->VBFlags & DISPTYPE_DISP2) {
5579        if(pSiS->CRT1off) {	/* CRT2 only ------------------------------- */
5580#ifdef SISDUALHEAD
5581	     if(pSiS->DualHeadMode) {
5582		SISErrorLog(pScrn,
5583		    "CRT1 not detected or forced off. Dual Head mode can't initialize.\n");
5584		if(pSiSEnt) pSiSEnt->DisableDual = TRUE;
5585		goto my_error_1;
5586	     }
5587#endif
5588#ifdef SISMERGED
5589	     if(pSiS->MergedFB) {
5590		if(pSiS->MergedFBAuto) {
5591		   xf86DrvMsg(pScrn->scrnIndex, X_INFO, mergednocrt1, mergeddisstr);
5592		} else {
5593		   SISErrorLog(pScrn, mergednocrt1, mergeddisstr);
5594		}
5595		if(pSiS->CRT2pScrn) xfree(pSiS->CRT2pScrn);
5596		pSiS->CRT2pScrn = NULL;
5597		pSiS->MergedFB = FALSE;
5598	     }
5599#endif
5600	     pSiS->VBFlags |= VB_DISPMODE_SINGLE;
5601	     /* No CRT1? Then we use the video overlay on CRT2 */
5602	     pSiS->XvOnCRT2 = TRUE;
5603	} else			/* CRT1 and CRT2 - mirror or dual head ----- */
5604#ifdef SISDUALHEAD
5605	     if(pSiS->DualHeadMode) {
5606		pSiS->VBFlags |= (VB_DISPMODE_DUAL | DISPTYPE_CRT1);
5607		if(pSiS->VESA != -1) {
5608		    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5609			"VESA option not used in Dual Head mode. VESA disabled.\n");
5610		}
5611		if(pSiSEnt) pSiSEnt->DisableDual = FALSE;
5612		pSiS->VESA = 0;
5613	     } else
5614#endif
5615#ifdef SISMERGED
5616		    if(pSiS->MergedFB) {
5617		 pSiS->VBFlags |= (VB_DISPMODE_MIRROR | DISPTYPE_CRT1);
5618		 if(pSiS->VESA != -1) {
5619		    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5620			"VESA option not used in MergedFB mode. VESA disabled.\n");
5621		 }
5622		 pSiS->VESA = 0;
5623	     } else
5624#endif
5625		 pSiS->VBFlags |= (VB_DISPMODE_MIRROR | DISPTYPE_CRT1);
5626    } else {			/* CRT1 only ------------------------------- */
5627#ifdef SISDUALHEAD
5628	     if(pSiS->DualHeadMode) {
5629		SISErrorLog(pScrn,
5630		   "No CRT2 output selected or no bridge detected. "
5631		   "Dual Head mode can't initialize.\n");
5632		goto my_error_1;
5633	     }
5634#endif
5635#ifdef SISMERGED
5636	     if(pSiS->MergedFB) {
5637		if(pSiS->MergedFBAuto) {
5638		   xf86DrvMsg(pScrn->scrnIndex, X_INFO, mergednocrt2, mergeddisstr);
5639		} else {
5640		   SISErrorLog(pScrn, mergednocrt2, mergeddisstr);
5641		}
5642		if(pSiS->CRT2pScrn) xfree(pSiS->CRT2pScrn);
5643		pSiS->CRT2pScrn = NULL;
5644		pSiS->MergedFB = FALSE;
5645	     }
5646#endif
5647             pSiS->VBFlags |= (VB_DISPMODE_SINGLE | DISPTYPE_CRT1);
5648    }
5649
5650    if((pSiS->VGAEngine == SIS_315_VGA) || (pSiS->VGAEngine == SIS_300_VGA)) {
5651       if((!pSiS->NoXvideo)		&&
5652          (!pSiS->hasTwoOverlays)	&&
5653	  (!(pSiS->SiS_SD2_Flags & SiS_SD2_NOOVERLAY))) {
5654	  xf86DrvMsg(pScrn->scrnIndex, from,
5655	      "Using Xv overlay by default on CRT%d\n",
5656	      pSiS->XvOnCRT2 ? 2 : 1);
5657       }
5658    }
5659
5660    /* Init ptrs for Save/Restore functions and calc MaxClock */
5661    SISDACPreInit(pScrn);
5662
5663    /* ********** end of VBFlags setup ********** */
5664
5665    /* VBFlags are initialized now. Back them up for SlaveMode modes. */
5666    pSiS->VBFlags_backup = pSiS->VBFlags;
5667
5668    /* Backup CR32,36,37 (in order to write them back after a VT switch) */
5669    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
5670       inSISIDXREG(SISCR,0x32,pSiS->myCR32);
5671       inSISIDXREG(SISCR,0x36,pSiS->myCR36);
5672       inSISIDXREG(SISCR,0x37,pSiS->myCR37);
5673    }
5674
5675    /* Find out about paneldelaycompensation and evaluate option */
5676#ifdef SISDUALHEAD
5677    if((!pSiS->DualHeadMode) || (!pSiS->SecondHead)) {
5678#endif
5679       if(pSiS->VGAEngine == SIS_300_VGA) {
5680
5681          if(pSiS->VBFlags2 & (VB2_LVDS | VB2_30xBDH)) {
5682
5683	     /* Save the current PDC if the panel is used at the moment.
5684	      * This seems by far the safest way to find out about it.
5685	      * If the system is using an old version of sisfb, we can't
5686	      * trust the pdc register value. If sisfb saved the pdc for
5687	      * us, use it.
5688	      */
5689	     if(pSiS->sisfbpdc != 0xff) {
5690	        pSiS->SiS_Pr->PDC = pSiS->sisfbpdc;
5691	     } else {
5692	        if(!(pSiS->donttrustpdc)) {
5693	           UChar tmp;
5694	           inSISIDXREG(SISCR, 0x30, tmp);
5695	           if(tmp & 0x20) {
5696	              inSISIDXREG(SISPART1, 0x13, pSiS->SiS_Pr->PDC);
5697                   } else {
5698	             xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5699		          "Unable to detect LCD PanelDelayCompensation, LCD is not active\n");
5700	           }
5701	        } else {
5702	           xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5703		        "Unable to detect LCD PanelDelayCompensation, please update sisfb\n");
5704	        }
5705	     }
5706	     if(pSiS->SiS_Pr->PDC != -1) {
5707	        pSiS->SiS_Pr->PDC &= 0x3c;
5708	        xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5709		     "Detected LCD PanelDelayCompensation 0x%02x\n",
5710		     pSiS->SiS_Pr->PDC);
5711	     }
5712
5713	     /* If we haven't been able to find out, use our other methods */
5714	     if(pSiS->SiS_Pr->PDC == -1) {
5715		int i=0;
5716		do {
5717		   if(mypdctable[i].subsysVendor == PCI_SUB_VENDOR_ID(pSiS->PciInfo) &&
5718		      mypdctable[i].subsysCard == PCI_SUB_DEVICE_ID(pSiS->PciInfo)) {
5719			 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5720			    "PCI card/vendor identified for non-default PanelDelayCompensation\n");
5721			 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5722			     "Vendor: %s, card: %s (ID %04x), PanelDelayCompensation: 0x%02x\n",
5723			     mypdctable[i].vendorName, mypdctable[i].cardName,
5724			     PCI_SUB_DEVICE_ID(pSiS->PciInfo), mypdctable[i].pdc);
5725			 if(pSiS->PDC == -1) {
5726			    pSiS->PDC = mypdctable[i].pdc;
5727			 } else {
5728			    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
5729				"PanelDelayCompensation overruled by option\n");
5730			 }
5731			 break;
5732		   }
5733		   i++;
5734		} while(mypdctable[i].subsysVendor != 0);
5735	     }
5736
5737	     if(pSiS->PDC != -1) {
5738		if(pSiS->BIOS) {
5739		   if(pSiS->VBFlags2 & VB2_LVDS) {
5740		      if(pSiS->BIOS[0x220] & 0x80) {
5741			 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5742			     "BIOS uses OEM LCD Panel Delay Compensation 0x%02x\n",
5743			     pSiS->BIOS[0x220] & 0x3c);
5744			 pSiS->BIOS[0x220] &= 0x7f;
5745		      }
5746		   }
5747		   if(pSiS->VBFlags2 & (VB2_301B | VB2_302B)) {
5748		      if(pSiS->BIOS[0x220] & 0x80) {
5749			 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5750			     "BIOS uses OEM LCD Panel Delay Compensation 0x%02x\n",
5751			       (  (pSiS->VBLCDFlags & VB_LCD_1280x1024) ?
5752			                 pSiS->BIOS[0x223] : pSiS->BIOS[0x224]  ) & 0x3c);
5753			 pSiS->BIOS[0x220] &= 0x7f;
5754		      }
5755		   }
5756		}
5757		pSiS->SiS_Pr->PDC = (pSiS->PDC & 0x3c);
5758		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
5759		      "Using LCD Panel Delay Compensation 0x%02x\n", pSiS->SiS_Pr->PDC);
5760	     }
5761	  }
5762
5763       }  /* SIS_300_VGA */
5764
5765       if(pSiS->VGAEngine == SIS_315_VGA) {
5766
5767	  UChar tmp, tmp2;
5768	  inSISIDXREG(SISCR, 0x30, tmp);
5769
5770	  /* Save the current PDC if the panel is used at the moment. */
5771	  if(pSiS->VBFlags2 & VB2_SISLVDSBRIDGE) {
5772
5773	     if(pSiS->sisfbpdc != 0xff) {
5774	        pSiS->SiS_Pr->PDC = pSiS->sisfbpdc;
5775	     }
5776	     if(pSiS->sisfbpdca != 0xff) {
5777	        pSiS->SiS_Pr->PDCA = pSiS->sisfbpdca;
5778	     }
5779
5780	     if(!pSiS->donttrustpdc) {
5781	        if((pSiS->sisfbpdc == 0xff) && (pSiS->sisfbpdca == 0xff)) {
5782		   CARD16 tempa, tempb;
5783		   inSISIDXREG(SISPART1,0x2d,tmp2);
5784		   tempa = (tmp2 & 0xf0) >> 3;
5785		   tempb = (tmp2 & 0x0f) << 1;
5786		   inSISIDXREG(SISPART1,0x20,tmp2);
5787		   tempa |= ((tmp2 & 0x40) >> 6);
5788		   inSISIDXREG(SISPART1,0x35,tmp2);
5789		   tempb |= ((tmp2 & 0x80) >> 7);
5790		   inSISIDXREG(SISPART1,0x13,tmp2);
5791		   if(!pSiS->ROM661New) {
5792		      if((tmp2 & 0x04) || (tmp & 0x20)) {
5793		         pSiS->SiS_Pr->PDCA = tempa;
5794		         pSiS->SiS_Pr->PDC  = tempb;
5795		      } else {
5796			 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5797			     "Unable to detect PanelDelayCompensation, LCD is not active\n");
5798		      }
5799		   } else {
5800		      if(tmp2 & 0x04) {
5801		         pSiS->SiS_Pr->PDCA = tempa;
5802		      } else if(tmp & 0x20) {
5803		         pSiS->SiS_Pr->PDC  = tempb;
5804		      } else {
5805			 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5806			     "Unable to detect PanelDelayCompensation, LCD is not active\n");
5807		      }
5808		   }
5809		}
5810	     } else {
5811		xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5812		    "Unable to detect PanelDelayCompensation, please update sisfb\n");
5813	     }
5814	     if(pSiS->SiS_Pr->PDC != -1) {
5815		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5816		     "Detected LCD PanelDelayCompensation 0x%02x (for LCD=CRT2)\n",
5817		     pSiS->SiS_Pr->PDC);
5818	     }
5819	     if(pSiS->SiS_Pr->PDCA != -1) {
5820		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5821		     "Detected LCD PanelDelayCompensation1 0x%02x (for LCD=CRT1)\n",
5822		     pSiS->SiS_Pr->PDCA);
5823	     }
5824	  }
5825
5826	  /* Let user override (for all bridges) */
5827	  if(pSiS->VBFlags2 & VB2_30xBLV) {
5828	     if(pSiS->PDC != -1) {
5829	        pSiS->SiS_Pr->PDC = pSiS->PDC & 0x1f;
5830		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
5831		     "Using LCD PanelDelayCompensation 0x%02x (for LCD=CRT2)\n",
5832		     pSiS->SiS_Pr->PDC);
5833	     }
5834	     if(pSiS->PDCA != -1) {
5835		pSiS->SiS_Pr->PDCA = pSiS->PDCA & 0x1f;
5836		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
5837		     "Using LCD PanelDelayCompensation1 0x%02x (for LCD=CRT1)\n",
5838		     pSiS->SiS_Pr->PDCA);
5839	     }
5840          }
5841
5842 	  /* Read the current EMI (if not overruled) */
5843	  if(pSiS->VBFlags2 & VB2_SISEMIBRIDGE) {
5844	     MessageType from = X_PROBED;
5845	     if(pSiS->EMI != -1) {
5846		pSiS->SiS_Pr->EMI_30 = (pSiS->EMI >> 24) & 0x60;
5847		pSiS->SiS_Pr->EMI_31 = (pSiS->EMI >> 16) & 0xff;
5848		pSiS->SiS_Pr->EMI_32 = (pSiS->EMI >> 8)  & 0xff;
5849		pSiS->SiS_Pr->EMI_33 = pSiS->EMI & 0xff;
5850		pSiS->SiS_Pr->HaveEMI = pSiS->SiS_Pr->HaveEMILCD = TRUE;
5851		pSiS->SiS_Pr->OverruleEMI = TRUE;
5852		from = X_CONFIG;
5853	     } else if((pSiS->sisfbfound) && (pSiS->sisfb_haveemi)) {
5854		pSiS->SiS_Pr->EMI_30 = pSiS->sisfb_emi30;
5855		pSiS->SiS_Pr->EMI_31 = pSiS->sisfb_emi31;
5856		pSiS->SiS_Pr->EMI_32 = pSiS->sisfb_emi32;
5857		pSiS->SiS_Pr->EMI_33 = pSiS->sisfb_emi33;
5858		pSiS->SiS_Pr->HaveEMI = TRUE;
5859		if(pSiS->sisfb_haveemilcd) pSiS->SiS_Pr->HaveEMILCD = TRUE;
5860		pSiS->SiS_Pr->OverruleEMI = FALSE;
5861	     } else {
5862		inSISIDXREG(SISPART4, 0x30, pSiS->SiS_Pr->EMI_30);
5863		inSISIDXREG(SISPART4, 0x31, pSiS->SiS_Pr->EMI_31);
5864		inSISIDXREG(SISPART4, 0x32, pSiS->SiS_Pr->EMI_32);
5865		inSISIDXREG(SISPART4, 0x33, pSiS->SiS_Pr->EMI_33);
5866		pSiS->SiS_Pr->HaveEMI = TRUE;
5867		if(tmp & 0x20) pSiS->SiS_Pr->HaveEMILCD = TRUE;
5868		pSiS->SiS_Pr->OverruleEMI = FALSE;
5869	     }
5870	     xf86DrvMsg(pScrn->scrnIndex, from,
5871		   "302LV/302ELV: Using EMI 0x%02x%02x%02x%02x%s\n",
5872		   pSiS->SiS_Pr->EMI_30,pSiS->SiS_Pr->EMI_31,
5873		   pSiS->SiS_Pr->EMI_32,pSiS->SiS_Pr->EMI_33,
5874		   pSiS->SiS_Pr->HaveEMILCD ? " (LCD)" : "");
5875	  }
5876
5877       } /* SIS_315_VGA */
5878#ifdef SISDUALHEAD
5879    }
5880#endif
5881
5882
5883    /* In dual head mode, both heads (currently) share the maxxfbmem equally.
5884     * If memory sharing is done differently, the following has to be changed;
5885     * the other modules (eg. accel and Xv) use dhmOffset for hardware
5886     * pointer settings relative to VideoRAM start and won't need to be changed.
5887     *
5888     * Addendum: dhmoffset is also used for skipping the UMA area on SiS76x.
5889     */
5890
5891    pSiS->dhmOffset = pSiS->FbBaseOffset;
5892    pSiS->FbAddress += pSiS->dhmOffset;
5893
5894#ifdef SISDUALHEAD
5895    if(pSiS->DualHeadMode) {
5896       pSiS->FbAddress = pSiS->realFbAddress;
5897       if(!pSiS->SecondHead) {
5898	  /* ===== First head (always CRT2) ===== */
5899	  /* We use only half of the memory available */
5900	  pSiS->maxxfbmem /= 2;
5901	  /* dhmOffset is 0 (or LFB-base for SiS76x UMA skipping) */
5902	  pSiS->FbAddress += pSiS->dhmOffset;
5903	  xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5904	      "%dKB video RAM at 0x%lx available for master head (CRT2)\n",
5905	      pSiS->maxxfbmem/1024, pSiS->FbAddress);
5906       } else {
5907	  /* ===== Second head (always CRT1) ===== */
5908	  /* We use only half of the memory available */
5909	  pSiS->maxxfbmem /= 2;
5910	  /* Initialize dhmOffset */
5911	  pSiS->dhmOffset += pSiS->maxxfbmem;
5912	  /* Adapt FBAddress */
5913	  pSiS->FbAddress += pSiS->dhmOffset;
5914	  xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5915	     "%dKB video RAM at 0x%lx available for slave head (CRT1)\n",
5916	     pSiS->maxxfbmem/1024,  pSiS->FbAddress);
5917       }
5918    }
5919#endif
5920
5921    /* Note: Do not use availMem for anything from now. Use
5922     * maxxfbmem instead. (availMem does not take dual head
5923     * mode into account.)
5924     */
5925
5926    if(pSiS->FbBaseOffset) {
5927       /* Doubt that the DRM memory manager can deal
5928        * with a heap start of 0...
5929	*/
5930       pSiS->DRIheapstart = 16;
5931       pSiS->DRIheapend = pSiS->FbBaseOffset;
5932    } else {
5933       pSiS->DRIheapstart = pSiS->maxxfbmem;
5934       pSiS->DRIheapend = pSiS->availMem;
5935    }
5936#ifdef SISDUALHEAD
5937    if(pSiS->DualHeadMode) {
5938       pSiS->DRIheapstart = pSiS->DRIheapend = 0;
5939    } else
5940#endif
5941           if(pSiS->DRIheapstart >= pSiS->DRIheapend) {
5942#if 0  /* For future use */
5943       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5944	  "No memory for DRI heap. Please set the option \"MaxXFBMem\" to\n"
5945	  "\tlimit the memory X should use and leave the rest to DRI\n");
5946#endif
5947       pSiS->DRIheapstart = pSiS->DRIheapend = 0;
5948    }
5949
5950    /* Now for something completely different: DDC.
5951     * For 300 and 315/330/340 series, we provide our
5952     * own functions (in order to probe CRT2 as well)
5953     * If these fail, use the VBE.
5954     * All other chipsets will use VBE. No need to re-invent
5955     * the wheel there.
5956     */
5957
5958    pSiS->pVbe = NULL;
5959    didddc2 = FALSE;
5960
5961    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
5962       if(xf86LoadSubModule(pScrn, "ddc")) {
5963	  int crtnum = 0;
5964	  if((pMonitor = SiSDoPrivateDDC(pScrn, &crtnum))) {
5965	     didddc2 = TRUE;
5966	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED, ddcsstr, crtnum);
5967	     xf86PrintEDID(pMonitor);
5968	     xf86SetDDCproperties(pScrn, pMonitor);
5969	     pScrn->monitor->DDC = pMonitor;
5970	     /* Now try to find out aspect ratio */
5971	     SiSFindAspect(pScrn, pMonitor, crtnum);
5972	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED, ddcestr, crtnum);
5973	  }
5974       }
5975    }
5976
5977#ifdef SISDUALHEAD
5978    /* In dual head mode, probe DDC using VBE only for CRT1 (second head) */
5979    if((pSiS->DualHeadMode) && (!didddc2) && (!pSiS->SecondHead)) {
5980       didddc2 = TRUE;
5981    }
5982#endif
5983
5984    if(!didddc2) {
5985       /* If CRT1 is off or LCDA, skip DDC via VBE */
5986       if((pSiS->CRT1off) || (pSiS->VBFlags & CRT1_LCDA)) {
5987          didddc2 = TRUE;
5988       }
5989    }
5990
5991    /* Now (re-)load and initialize the DDC module */
5992    if(!didddc2) {
5993
5994       if(xf86LoadSubModule(pScrn, "ddc")) {
5995
5996	  /* Now load and initialize VBE module. */
5997	  SiS_LoadInitVBE(pScrn);
5998
5999	  if(pSiS->pVbe) {
6000	     if((pMonitor = vbeDoEDID(pSiS->pVbe,NULL))) {
6001		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
6002		      "VBE CRT1 DDC monitor info:\n");
6003		xf86SetDDCproperties(pScrn, xf86PrintEDID(pMonitor));
6004		pScrn->monitor->DDC = pMonitor;
6005		/* Now try to find out aspect ratio */
6006		SiSFindAspect(pScrn, pMonitor, 1);
6007		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
6008		      "End of VBE CRT1 DDC monitor info\n");
6009	     }
6010	  } else {
6011	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6012		 "Failed to read DDC data\n");
6013	  }
6014       }
6015    }
6016
6017#ifdef SISMERGED
6018    if(pSiS->MergedFB) {
6019       pSiS->CRT2pScrn->monitor = xalloc(sizeof(MonRec));
6020       if(pSiS->CRT2pScrn->monitor) {
6021	  DisplayModePtr tempm = NULL, currentm = NULL, newm = NULL;
6022	  memcpy(pSiS->CRT2pScrn->monitor, pScrn->monitor, sizeof(MonRec));
6023	  pSiS->CRT2pScrn->monitor->DDC = NULL;
6024	  pSiS->CRT2pScrn->monitor->Modes = NULL;
6025	  pSiS->CRT2pScrn->monitor->id = (char *)crt2monname;
6026	  tempm = pScrn->monitor->Modes;
6027	  while(tempm) {
6028	     if(!(newm = xalloc(sizeof(DisplayModeRec)))) break;
6029	     memcpy(newm, tempm, sizeof(DisplayModeRec));
6030	     if(!(newm->name = xalloc(strlen(tempm->name) + 1))) {
6031	        xfree(newm);
6032		break;
6033	     }
6034	     strcpy(newm->name, tempm->name);
6035	     if(!pSiS->CRT2pScrn->monitor->Modes) pSiS->CRT2pScrn->monitor->Modes = newm;
6036	     if(currentm) {
6037	        currentm->next = newm;
6038		newm->prev = currentm;
6039	     }
6040	     currentm = newm;
6041	     tempm = tempm->next;
6042	  }
6043	  if(pSiS->CRT2HSync) {
6044	     pSiS->CRT2pScrn->monitor->nHsync =
6045		SiSStrToRanges(pSiS->CRT2pScrn->monitor->hsync, pSiS->CRT2HSync, MAX_HSYNC);
6046	  }
6047	  if(pSiS->CRT2VRefresh) {
6048	     pSiS->CRT2pScrn->monitor->nVrefresh =
6049		SiSStrToRanges(pSiS->CRT2pScrn->monitor->vrefresh, pSiS->CRT2VRefresh, MAX_VREFRESH);
6050	  }
6051	  if((pMonitor = SiSInternalDDC(pSiS->CRT2pScrn, 1))) {
6052	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED, ddcsstr, 2);
6053	     xf86PrintEDID(pMonitor);
6054	     xf86SetDDCproperties(pSiS->CRT2pScrn, pMonitor);
6055	     pSiS->CRT2pScrn->monitor->DDC = pMonitor;
6056	     /* Now try to find out aspect ratio */
6057	     SiSFindAspect(pScrn, pMonitor, 2);
6058	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED, ddcestr, 2);
6059	     /* use DDC data if no ranges in config file */
6060	     if(!pSiS->CRT2HSync) {
6061	        pSiS->CRT2pScrn->monitor->nHsync = 0;
6062	     }
6063	     if(!pSiS->CRT2VRefresh) {
6064	        pSiS->CRT2pScrn->monitor->nVrefresh = 0;
6065	     }
6066	  } else {
6067	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
6068		"Failed to read DDC data for CRT2\n");
6069	  }
6070       } else {
6071	  SISErrorLog(pScrn, "Failed to allocate memory for CRT2 monitor, %s.\n",
6072	  		mergeddisstr);
6073	  if(pSiS->CRT2pScrn) xfree(pSiS->CRT2pScrn);
6074	  pSiS->CRT2pScrn = NULL;
6075	  pSiS->MergedFB = FALSE;
6076       }
6077    }
6078#endif
6079
6080    /* Copy our detected monitor gammas, part 1. Note that device redetection
6081     * is not supported in DHM, so there is no need to do that anytime later.
6082     */
6083#ifdef SISDUALHEAD
6084    if(pSiS->DualHeadMode) {
6085       if(!pSiS->SecondHead) {
6086          /* CRT2: Got gamma for LCD or VGA2 */
6087	  pSiSEnt->CRT2VGAMonitorGamma = pSiS->CRT2VGAMonitorGamma;
6088       } else {
6089          /* CRT1: Got gamma for LCD or VGA */
6090	  pSiSEnt->CRT1VGAMonitorGamma = pSiS->CRT1VGAMonitorGamma;
6091       }
6092       if(pSiS->CRT2LCDMonitorGamma) pSiSEnt->CRT2LCDMonitorGamma = pSiS->CRT2LCDMonitorGamma;
6093    }
6094#endif
6095
6096    /* end of DDC */
6097
6098    /* From here, we mainly deal with clocks and modes */
6099
6100#ifdef SISMERGED
6101    if(pSiS->MergedFB) xf86DrvMsg(pScrn->scrnIndex, X_INFO, crtsetupstr, 1);
6102#endif
6103
6104    /* Set the min pixel clock */
6105    pSiS->MinClock = 5000;
6106    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
6107       pSiS->MinClock = 10000;
6108    }
6109    xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "Min pixel clock is %d MHz\n",
6110                pSiS->MinClock / 1000);
6111
6112    /* If the user has specified ramdac speed in the config
6113     * file, we respect that setting.
6114     */
6115    from = X_PROBED;
6116    if(pSiS->pEnt->device->dacSpeeds[0]) {
6117       int speed = 0;
6118       switch(pScrn->bitsPerPixel) {
6119       case 8:  speed = pSiS->pEnt->device->dacSpeeds[DAC_BPP8];
6120                break;
6121       case 16: speed = pSiS->pEnt->device->dacSpeeds[DAC_BPP16];
6122                break;
6123       case 24: speed = pSiS->pEnt->device->dacSpeeds[DAC_BPP24];
6124                break;
6125       case 32: speed = pSiS->pEnt->device->dacSpeeds[DAC_BPP32];
6126                break;
6127       }
6128       if(speed == 0) pSiS->MaxClock = pSiS->pEnt->device->dacSpeeds[0];
6129       else           pSiS->MaxClock = speed;
6130       from = X_CONFIG;
6131    }
6132    xf86DrvMsg(pScrn->scrnIndex, from, "Max pixel clock is %d MHz\n",
6133                pSiS->MaxClock / 1000);
6134
6135    /*
6136     * Setup the ClockRanges, which describe what clock ranges are available,
6137     * and what sort of modes they can be used for.
6138     */
6139    clockRanges = xnfcalloc(sizeof(ClockRange), 1);
6140    clockRanges->next = NULL;
6141    clockRanges->minClock = pSiS->MinClock;
6142    clockRanges->maxClock = pSiS->MaxClock;
6143    clockRanges->clockIndex = -1;               /* programmable */
6144    clockRanges->interlaceAllowed = TRUE;
6145    clockRanges->doubleScanAllowed = TRUE;
6146
6147    /*
6148     * Since we have lots of built-in modes for 300/315/330/340 series
6149     * with vb support, we replace the given default mode list with our
6150     * own. In case the video bridge is to be used, we only allow other
6151     * modes if
6152     *   -) vbtype is 301, 301B, 301C or 302B, and
6153     *   -) crt2 device is not TV, and
6154     *   -) crt1 is not LCDA, unless bridge is TMDS/LCDA capable (301C)
6155     */
6156    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
6157       if(!(pSiS->noInternalModes)) {
6158          Bool acceptcustommodes = TRUE;  /* Accept user modelines */
6159	  Bool includelcdmodes   = TRUE;  /* Include modes reported by DDC */
6160	  Bool isfordvi          = FALSE; /* Is for digital DVI output */
6161	  Bool fakecrt2modes     = FALSE; /* Fake some modes for CRT2 */
6162	  Bool IsForCRT2	 = FALSE;
6163	  if(pSiS->UseVESA) {
6164	     acceptcustommodes = FALSE;
6165	     includelcdmodes   = FALSE;
6166	  }
6167#ifdef SISDUALHEAD  /* Dual head is static. Output devices will not change. */
6168	  if(pSiS->DualHeadMode) {
6169	     if(!pSiS->SecondHead) {  /* CRT2: */
6170	        if(pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) {
6171		   if(!(pSiS->VBFlags2 & VB2_30xBDH)) {
6172		      if(!(pSiS->VBFlags & (CRT2_LCD|CRT2_VGA))) includelcdmodes   = FALSE;
6173		      if(pSiS->VBFlags & CRT2_LCD)               isfordvi          = TRUE;
6174		      if(pSiS->VBFlags & CRT2_TV)                acceptcustommodes = FALSE;
6175		   } else {
6176		      if(pSiS->VBFlags & (CRT2_TV|CRT2_LCD)) {
6177		         acceptcustommodes = FALSE;
6178		         includelcdmodes   = FALSE;
6179			 fakecrt2modes = TRUE;
6180		      }
6181		   }
6182		} else {
6183		   acceptcustommodes = FALSE;
6184		   includelcdmodes   = FALSE;
6185		   if(pSiS->VBFlags & (CRT2_TV|CRT2_LCD)) {
6186		      fakecrt2modes = TRUE;
6187		   }
6188		}
6189		clockRanges->interlaceAllowed = FALSE;
6190		IsForCRT2 = TRUE;
6191	     } else {		/* CRT1: */
6192	        if(pSiS->VBFlags & CRT1_LCDA) {
6193		   if(!(pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE)) {
6194		      acceptcustommodes = FALSE;
6195		      includelcdmodes   = FALSE;
6196		      fakecrt2modes     = TRUE;
6197		      /* Will handle i-lace in mode-switching code */
6198		   } else {
6199		      isfordvi = TRUE;
6200		      /* Don't allow i-lace modes */
6201		      clockRanges->interlaceAllowed = FALSE;
6202		   }
6203		} else {
6204		   includelcdmodes = FALSE;
6205		}
6206	     }
6207	  } else
6208#endif
6209#ifdef SISMERGED  /* MergedFB mode is not static. Output devices may change. */
6210          if(pSiS->MergedFB) {
6211	     if(pSiS->VBFlags & CRT1_LCDA) {
6212	        if(!(pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE)) {
6213		   acceptcustommodes = FALSE;
6214		   includelcdmodes   = FALSE;
6215		   fakecrt2modes     = TRUE;
6216		   /* Will handle i-lace in mode-switching code */
6217		} else {
6218		   isfordvi = TRUE;
6219		   /* Don't allow i-lace custom modes */
6220		   clockRanges->interlaceAllowed = FALSE;
6221		}
6222	     } else {
6223	        includelcdmodes = FALSE;
6224	     }
6225          } else
6226#endif		 /* Mirror mode is not static. Output devices may change. */
6227          if(pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) {
6228	     if(!(pSiS->VBFlags2 & VB2_30xBDH)) {
6229		if(!(pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE)) {
6230		   if(!(pSiS->VBFlags & (CRT2_LCD|CRT2_VGA))) includelcdmodes = FALSE;
6231		   if(pSiS->VBFlags & CRT2_LCD)               isfordvi        = TRUE;
6232		} else {
6233		   if(!(pSiS->VBFlags & (CRT2_LCD|CRT2_VGA|CRT1_LCDA))) includelcdmodes = FALSE;
6234		   if(pSiS->VBFlags & (CRT2_LCD|CRT1_LCDA))             isfordvi        = TRUE;
6235		}
6236		if((!(pSiS->VBFlags & DISPTYPE_CRT1)) && (!(pSiS->VBFlags & CRT1_LCDA))) {
6237		   IsForCRT2 = TRUE;
6238		}
6239		/* Allow user modes, even if CRT2 is TV. Will be filtered through ValidMode();
6240		 * leaving the user modes here might have the advantage that such a mode, if
6241		 * it matches in resolution with a supported TV mode, allows us to drive eg.
6242		 * non standard panels, and still permits switching to TV. This mode will be
6243		 * "mapped" to a supported mode of identical resolution for TV. All this is
6244		 * taken care of by ValidMode() and ModeInit()/PresetMode().
6245		 */
6246	     } else {
6247		if(pSiS->VBFlags & (CRT2_TV|CRT2_LCD)) {
6248		   acceptcustommodes = FALSE;
6249		   includelcdmodes   = FALSE;
6250		   if(!(pSiS->VBFlags & DISPTYPE_CRT1)) {
6251		      fakecrt2modes = TRUE;
6252		      IsForCRT2 = TRUE;
6253		   }
6254		}
6255	     }
6256	  } else if(pSiS->VBFlags & (CRT2_ENABLE | CRT1_LCDA)) {
6257	     acceptcustommodes = FALSE;
6258	     includelcdmodes   = FALSE;
6259	     if((pSiS->VBFlags & CRT1_LCDA) || (!(pSiS->VBFlags & DISPTYPE_CRT1))) {
6260		fakecrt2modes = TRUE;
6261		IsForCRT2 = TRUE;
6262	     }
6263	  } else {
6264	     includelcdmodes   = FALSE;
6265	  }
6266	  /* Ignore interlace, mode switching code will handle this */
6267
6268	  pSiS->HaveCustomModes = FALSE;
6269	  if(SiSMakeOwnModeList(pScrn, acceptcustommodes, includelcdmodes,
6270			isfordvi, &pSiS->HaveCustomModes, FALSE /*fakecrt2modes*/, IsForCRT2)) {
6271	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6272		 "Replaced %s mode list with built-in modes\n",
6273	     pSiS->HaveCustomModes ? "default" : "entire");
6274	     if(pSiS->VGAEngine == SIS_315_VGA) {
6275		int UseWide = pSiS->SiS_Pr->SiS_UseWide;
6276		if(IsForCRT2) UseWide = pSiS->SiS_Pr->SiS_UseWideCRT2;
6277		if((!IsForCRT2) || (pSiS->VBFlags2 & VB2_SISVGA2BRIDGE)) {
6278		   xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6279			"Using %s widescreen modes for CRT%d VGA devices\n",
6280			UseWide ? "real" : "fake", IsForCRT2 ? 2 : 1);
6281		   xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6282			"\tUse option \"ForceCRT%dVGAAspect\" to overrule\n",
6283			IsForCRT2 ? 2 : 1);
6284		}
6285	     }
6286#ifdef TWDEBUG
6287             pScrn->modes = pScrn->monitor->Modes;
6288	     xf86PrintModes(pScrn);
6289	     pScrn->modes = NULL;
6290#endif
6291          } else {
6292	     xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
6293		"Building list of built-in modes failed, using server defaults\n");
6294	  }
6295       } else {
6296          pSiS->HaveCustomModes = TRUE;
6297       }
6298    }
6299
6300    /* Add our built-in hi-res and TV modes on the 6326 */
6301    if(pSiS->Chipset == PCI_CHIP_SIS6326) {
6302       if(pScrn->bitsPerPixel == 8) {
6303	  SiS6326SIS1600x1200_60Mode.next = pScrn->monitor->Modes;
6304	  pScrn->monitor->Modes = &SiS6326SIS1600x1200_60Mode;
6305	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6306	  	"Adding mode \"SIS1600x1200-60\" (depth 8 only)\n");
6307       }
6308       if(pScrn->bitsPerPixel <= 16) {
6309	  SiS6326SIS1280x1024_75Mode.next = pScrn->monitor->Modes;
6310	  pScrn->monitor->Modes = &SiS6326SIS1280x1024_75Mode;
6311	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6312	  	"Adding mode \"SIS1280x1024-75\" (depths 8, 15 and 16 only)\n");
6313       }
6314       if((pSiS->SiS6326Flags & SIS6326_HASTV) &&
6315	  (pSiS->SiS6326Flags & SIS6326_TVDETECTED)) {
6316	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6317		"Adding %s TV modes to mode list:\n",
6318		(pSiS->SiS6326Flags & SIS6326_TVPAL) ? "PAL" : "NTSC");
6319	  if(pSiS->SiS6326Flags & SIS6326_TVPAL) {
6320	     SiS6326PAL800x600Mode.next = pScrn->monitor->Modes;
6321	     pScrn->monitor->Modes = &SiS6326PAL640x480Mode;
6322	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6323		"\t\"PAL800x600\" \"PAL800x600U\" \"PAL720x540\" \"PAL640x480\"\n");
6324	  } else {
6325	     SiS6326NTSC640x480Mode.next = pScrn->monitor->Modes;
6326	     pScrn->monitor->Modes = &SiS6326NTSC640x400Mode;
6327	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6328		"\t\"NTSC640x480\" \"NTSC640x480U\" \"NTSC640x400\"\n");
6329	  }
6330       }
6331    }
6332
6333   /* If there is no HSync or VRefresh data for the monitor,
6334    * derive it from DDC data. Essentially done by common layer
6335    * since 4.3.99.14, but this is not usable since it is done
6336    * too late (in ValidateModes()).
6337    * Addendum: I overrule the ranges now in any case unless
6338    * it would affect a CRT output device or DDC data is available.
6339    * Hence, for LCD(A) and TV, we always get proper ranges. This
6340    * is entirely harmless. However, option "NoOverruleRanges" will
6341    * disable this behavior.
6342    * This should "fix" the - by far - most common configuration
6343    * mistakes.
6344    */
6345
6346    crt1freqoverruled = FALSE;
6347
6348    fromDDC = FALSE;
6349    if((pScrn->monitor->nHsync <= 0) || (pSiS->OverruleRanges)) {
6350       if((pScrn->monitor->nHsync <= 0) && (pScrn->monitor->DDC)) {
6351	  SiSSetSyncRangeFromEdid(pScrn, 1);
6352	  if(pScrn->monitor->nHsync > 0) {
6353	     xf86DrvMsg(pScrn->scrnIndex, X_INFO, subshstr,
6354#ifdef SISDUALHEAD
6355			pSiS->DualHeadMode ? (pSiS->SecondHead ? 1 : 2) :
6356#endif
6357				pSiS->CRT1off ? 2 : 1);
6358	     fromDDC = TRUE;
6359	  }
6360       }
6361       if((pScrn->monitor->nHsync <= 0) || (pSiS->OverruleRanges)) {
6362	  if(SiSAllowSyncOverride(pSiS, fromDDC)) {
6363	     Bool HaveNoRanges = (pScrn->monitor->nHsync <= 0);
6364	     /* Set sane ranges for LCD and TV
6365	      * (our strict checking will filter out invalid ones anyway)
6366	      */
6367	     if((crt1freqoverruled = CheckAndOverruleH(pScrn, pScrn->monitor))) {
6368		xf86DrvMsg(pScrn->scrnIndex, X_INFO, saneh,
6369			HaveNoRanges ? "missing" : "bogus",
6370#ifdef SISDUALHEAD
6371			pSiS->DualHeadMode ? (pSiS->SecondHead ? 1 : 2) :
6372#endif
6373				pSiS->CRT1off ? 2 : 1);
6374	     }
6375	  }
6376       }
6377    }
6378
6379    fromDDC = FALSE;
6380    if((pScrn->monitor->nVrefresh <= 0) || (pSiS->OverruleRanges)) {
6381       if((pScrn->monitor->nVrefresh <= 0) && (pScrn->monitor->DDC)) {
6382	  SiSSetSyncRangeFromEdid(pScrn, 0);
6383	  if(pScrn->monitor->nVrefresh > 0) {
6384	     xf86DrvMsg(pScrn->scrnIndex, X_INFO, subsvstr,
6385#ifdef SISDUALHEAD
6386			pSiS->DualHeadMode ? (pSiS->SecondHead ? 1 : 2) :
6387#endif
6388				pSiS->CRT1off ? 2 : 1);
6389	     fromDDC = TRUE;
6390          }
6391       }
6392       if((pScrn->monitor->nVrefresh <= 0) || (pSiS->OverruleRanges)) {
6393	  if(SiSAllowSyncOverride(pSiS, fromDDC)) {
6394	     Bool HaveNoRanges = (pScrn->monitor->nVrefresh <= 0);
6395	     /* Set sane ranges for LCD and TV */
6396	     if((crt1freqoverruled = CheckAndOverruleV(pScrn, pScrn->monitor))) {
6397		xf86DrvMsg(pScrn->scrnIndex, X_INFO, sanev,
6398			HaveNoRanges ? "missing" : "bogus",
6399#ifdef SISDUALHEAD
6400			pSiS->DualHeadMode ? (pSiS->SecondHead ? 1 : 2) :
6401#endif
6402				pSiS->CRT1off ? 2 : 1);
6403	     }
6404	  }
6405       }
6406    }
6407
6408    if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
6409       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6410	  "\"Unknown reason\" in the following list means that the mode\n");
6411       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6412	  "is not supported on the chipset/bridge/current output device.\n");
6413    }
6414
6415    /*
6416     * xf86ValidateModes will check that the mode HTotal and VTotal values
6417     * don't exceed the chipset's limit if pScrn->maxHValue and
6418     * pScrn->maxVValue are set.  Since our SISValidMode() already takes
6419     * care of this, we don't worry about setting them here.
6420     */
6421
6422    /* Select valid modes from those available */
6423    /*
6424     * Assuming min pitch 256, min height 128
6425     */
6426    {
6427       int minpitch, maxpitch, minheight, maxheight;
6428       pointer backupddc = pScrn->monitor->DDC;
6429
6430       minpitch = 256;
6431       minheight = 128;
6432       switch(pSiS->VGAEngine) {
6433       case SIS_OLD_VGA:
6434       case SIS_530_VGA:
6435          maxpitch = 2040;
6436          maxheight = 2048;
6437          break;
6438       case SIS_300_VGA:
6439       case SIS_315_VGA:
6440          maxpitch = 4088;
6441          maxheight = 4096;
6442          break;
6443       default:
6444          maxpitch = 2048;
6445          maxheight = 2048;
6446          break;
6447       }
6448
6449#ifdef SISMERGED
6450       pSiS->CheckForCRT2 = FALSE;
6451#endif
6452
6453       /* Suppress bogus DDC warning */
6454       if(crt1freqoverruled) pScrn->monitor->DDC = NULL;
6455
6456       i = xf86ValidateModes(pScrn, pScrn->monitor->Modes,
6457			pScrn->display->modes, clockRanges, NULL,
6458			minpitch, maxpitch,
6459			pScrn->bitsPerPixel * 8,
6460			minheight, maxheight,
6461			pScrn->display->virtualX,
6462			pScrn->display->virtualY,
6463			pSiS->maxxfbmem,
6464			LOOKUP_BEST_REFRESH);
6465
6466       pScrn->monitor->DDC = backupddc;
6467    }
6468
6469    if(i == -1) {
6470       SISErrorLog(pScrn, "xf86ValidateModes() error\n");
6471       goto my_error_1;
6472    }
6473
6474    /* Check the virtual screen against the available memory */
6475    {
6476       ULong memreq = (pScrn->virtualX * ((pScrn->bitsPerPixel + 7) / 8)) * pScrn->virtualY;
6477
6478       if(memreq > pSiS->maxxfbmem) {
6479	  SISErrorLog(pScrn,
6480	     "Virtual screen too big for memory; %ldK needed, %ldK available\n",
6481	     memreq/1024, pSiS->maxxfbmem/1024);
6482	  goto my_error_1;
6483       }
6484    }
6485
6486    /* Dual Head:
6487     * -) Go through mode list and mark all those modes as bad,
6488     *    which are unsuitable for dual head mode.
6489     * -) Find the highest used pixelclock on the master head.
6490     */
6491#ifdef SISDUALHEAD
6492    if((pSiS->DualHeadMode) && (!pSiS->SecondHead)) {
6493
6494       pSiSEnt->maxUsedClock = 0;
6495
6496       if((p = first = pScrn->modes)) {
6497
6498	  do {
6499
6500	     n = p->next;
6501
6502	     /* Modes that require the bridge to operate in SlaveMode
6503	      * are not suitable for Dual Head mode.
6504	      */
6505	     if( (pSiS->VGAEngine == SIS_300_VGA) &&
6506		 ( (strcmp(p->name, "320x200") == 0) ||
6507		   (strcmp(p->name, "320x240") == 0) ||
6508		   (strcmp(p->name, "400x300") == 0) ||
6509		   (strcmp(p->name, "512x384") == 0) ||
6510		   (strcmp(p->name, "640x400") == 0) ) )  {
6511		p->status = MODE_BAD;
6512		xf86DrvMsg(pScrn->scrnIndex, X_INFO, notsuitablestr, p->name, "dual head");
6513	     }
6514
6515	     /* Search for the highest clock on first head in order to calculate
6516	      * max clock for second head (CRT1)
6517	      */
6518	     if((p->status == MODE_OK) && (p->Clock > pSiSEnt->maxUsedClock)) {
6519		pSiSEnt->maxUsedClock = p->Clock;
6520	     }
6521
6522	     p = n;
6523
6524	  } while (p != NULL && p != first);
6525
6526       }
6527    }
6528#endif
6529
6530    /* Prune the modes marked as invalid */
6531    xf86PruneDriverModes(pScrn);
6532
6533    if(i == 0 || pScrn->modes == NULL) {
6534       SISErrorLog(pScrn, "No valid modes found - check VertRefresh/HorizSync\n");
6535       goto my_error_1;
6536    }
6537
6538    xf86SetCrtcForModes(pScrn, INTERLACE_HALVE_V);
6539
6540    /* Set the current mode to the first in the list */
6541    pScrn->currentMode = pScrn->modes;
6542
6543    /* Copy to CurrentLayout */
6544    pSiS->CurrentLayout.mode = pScrn->currentMode;
6545    pSiS->CurrentLayout.displayWidth = pScrn->displayWidth;
6546    pSiS->CurrentLayout.displayHeight = pScrn->virtualY;
6547
6548#ifdef SISMERGED
6549    if(pSiS->MergedFB) {
6550       xf86DrvMsg(pScrn->scrnIndex, X_INFO, modesforstr, 1);
6551    }
6552#endif
6553
6554    /* Print the list of modes being used */
6555    {
6556       Bool usemyprint = FALSE;
6557
6558#ifdef SISDUALHEAD
6559       if(pSiS->DualHeadMode) {
6560	  if(pSiS->SecondHead) {
6561	     if(pSiS->VBFlags & CRT1_LCDA) usemyprint = TRUE;
6562	  } else {
6563	     if(pSiS->VBFlags & (CRT2_LCD | CRT2_TV)) usemyprint = TRUE;
6564	  }
6565       } else
6566#endif
6567#ifdef SISMERGED
6568       if(pSiS->MergedFB) {
6569	  if(pSiS->VBFlags & CRT1_LCDA) usemyprint = TRUE;
6570       } else
6571#endif
6572       {
6573	  if( (pSiS->VBFlags & (CRT2_LCD | CRT2_TV)) &&
6574	      (!(pSiS->VBFlags & DISPTYPE_DISP1)) )
6575	     usemyprint = TRUE;
6576       }
6577
6578       if(usemyprint) {
6579	  SiSPrintModes(pScrn);
6580       } else {
6581	  xf86PrintModes(pScrn);
6582       }
6583    }
6584
6585#ifdef SISMERGED
6586    if(pSiS->MergedFB) {
6587       Bool acceptcustommodes = TRUE;
6588       Bool includelcdmodes   = TRUE;
6589       Bool isfordvi          = FALSE;
6590       Bool fakecrt2modes     = FALSE;
6591
6592       xf86DrvMsg(pScrn->scrnIndex, X_INFO, crtsetupstr, 2);
6593
6594       clockRanges->next = NULL;
6595       clockRanges->minClock = pSiS->MinClock;
6596       clockRanges->maxClock = SiSMemBandWidth(pSiS->CRT2pScrn, TRUE);
6597       clockRanges->clockIndex = -1;
6598       clockRanges->interlaceAllowed = FALSE;
6599       clockRanges->doubleScanAllowed = FALSE;
6600       if(pSiS->VGAEngine == SIS_315_VGA) {
6601          clockRanges->doubleScanAllowed = TRUE;
6602       }
6603
6604       xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "Min pixel clock for CRT2 is %d MHz\n",
6605                clockRanges->minClock / 1000);
6606       xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "Max pixel clock for CRT2 is %d MHz\n",
6607                clockRanges->maxClock / 1000);
6608
6609       if(pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) {
6610          if(!(pSiS->VBFlags2 & VB2_30xBDH)) {
6611             if(!(pSiS->VBFlags & (CRT2_LCD|CRT2_VGA))) includelcdmodes   = FALSE;
6612	     if(pSiS->VBFlags & CRT2_LCD)               isfordvi          = TRUE;
6613	     /* See above for a remark on handling CRT2 = TV */
6614	  } else {
6615	     if(pSiS->VBFlags & (CRT2_LCD|CRT2_TV)) {
6616		includelcdmodes   = FALSE;
6617		acceptcustommodes = FALSE;
6618		fakecrt2modes     = TRUE;
6619	     }
6620	  }
6621       } else {
6622	  includelcdmodes   = FALSE;
6623	  acceptcustommodes = FALSE;
6624	  if(pSiS->VBFlags & (CRT2_LCD|CRT2_TV)) {
6625	     fakecrt2modes = TRUE;
6626	  }
6627       }
6628
6629       pSiS->HaveCustomModes2 = FALSE;
6630       if(!SiSMakeOwnModeList(pSiS->CRT2pScrn, acceptcustommodes, includelcdmodes,
6631				isfordvi, &pSiS->HaveCustomModes2, FALSE /* fakecrt2modes */, TRUE )) {
6632
6633	  SISErrorLog(pScrn, "Building list of built-in modes for CRT2 failed, %s\n",
6634				mergeddisstr);
6635	  SiSFreeCRT2Structs(pSiS);
6636	  pSiS->MergedFB = FALSE;
6637
6638       } else {
6639	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6640		 "Replaced %s mode list for CRT2 with built-in modes\n",
6641		 pSiS->HaveCustomModes2 ? "default" : "entire");
6642	  if((pSiS->VGAEngine == SIS_315_VGA) && (pSiS->VBFlags2 & VB2_SISVGA2BRIDGE)) {
6643	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6644		 "Using %s widescreen modes for CRT2 VGA devices\n",
6645		 pSiS->SiS_Pr->SiS_UseWideCRT2 ? "real" : "fake");
6646	  } else pSiS->SiS_Pr->SiS_UseWideCRT2 = 0;
6647       }
6648
6649    }
6650
6651    if(pSiS->MergedFB) {
6652
6653       pointer backupddc;
6654
6655       crt2freqoverruled = FALSE;
6656
6657       fromDDC = FALSE;
6658       if((pSiS->CRT2pScrn->monitor->nHsync <= 0) || (pSiS->OverruleRanges)) {
6659          if((pSiS->CRT2pScrn->monitor->nHsync <= 0) && (pSiS->CRT2pScrn->monitor->DDC)) {
6660	     SiSSetSyncRangeFromEdid(pSiS->CRT2pScrn, 1);
6661	     if(pSiS->CRT2pScrn->monitor->nHsync > 0) {
6662		xf86DrvMsg(pScrn->scrnIndex, X_INFO, subshstr, 2);
6663		fromDDC = TRUE;
6664	     }
6665	  }
6666	  if((pSiS->CRT2pScrn->monitor->nHsync <= 0) || (pSiS->OverruleRanges)) {
6667	     if( (pSiS->VBFlags & CRT2_TV) ||
6668	         ((pSiS->VBFlags & CRT2_LCD) && (!fromDDC)) ) {
6669		Bool HaveNoRanges = (pSiS->CRT2pScrn->monitor->nHsync <= 0);
6670		/* Set sane ranges for LCD and TV */
6671		if((crt2freqoverruled = CheckAndOverruleH(pScrn, pSiS->CRT2pScrn->monitor))) {
6672		   xf86DrvMsg(pScrn->scrnIndex, X_INFO, saneh,
6673			HaveNoRanges ? "missing" : "bogus", 2);
6674		}
6675	     }
6676	  }
6677       }
6678
6679       fromDDC = FALSE;
6680       if((pSiS->CRT2pScrn->monitor->nVrefresh <= 0) || (pSiS->OverruleRanges)) {
6681	  if((pSiS->CRT2pScrn->monitor->nVrefresh <= 0) && (pSiS->CRT2pScrn->monitor->DDC)) {
6682	     SiSSetSyncRangeFromEdid(pSiS->CRT2pScrn, 0);
6683	     if(pSiS->CRT2pScrn->monitor->nVrefresh > 0) {
6684		xf86DrvMsg(pScrn->scrnIndex, X_INFO, subsvstr, 2);
6685		fromDDC = TRUE;
6686	     }
6687          }
6688	  if((pSiS->CRT2pScrn->monitor->nVrefresh <= 0) || (pSiS->OverruleRanges)) {
6689	     if( (pSiS->VBFlags & CRT2_TV) ||
6690	         ((pSiS->VBFlags & CRT2_LCD) && (!fromDDC)) ) {
6691		Bool HaveNoRanges = (pSiS->CRT2pScrn->monitor->nVrefresh <= 0);
6692		/* Set sane ranges for LCD and TV */
6693		if((crt2freqoverruled = CheckAndOverruleV(pScrn, pSiS->CRT2pScrn->monitor))) {
6694		   xf86DrvMsg(pScrn->scrnIndex, X_INFO, sanev,
6695			 HaveNoRanges ? "missing" : "bogus", 2);
6696	        }
6697	     }
6698	  }
6699       }
6700
6701       backupddc = pSiS->CRT2pScrn->monitor->DDC;
6702
6703       /* Suppress bogus DDC warning */
6704       if(crt2freqoverruled) pSiS->CRT2pScrn->monitor->DDC = NULL;
6705
6706       pSiS->CheckForCRT2 = TRUE;
6707
6708       i = xf86ValidateModes(pSiS->CRT2pScrn, pSiS->CRT2pScrn->monitor->Modes,
6709			pSiS->CRT2pScrn->display->modes, clockRanges,
6710			NULL, 256, 4088,
6711			pSiS->CRT2pScrn->bitsPerPixel * 8, 128, 4096,
6712			pScrn->display->virtualX ? pScrn->virtualX : 0,
6713			pScrn->display->virtualY ? pScrn->virtualY : 0,
6714			pSiS->maxxfbmem,
6715			LOOKUP_BEST_REFRESH);
6716
6717       pSiS->CheckForCRT2 = FALSE;
6718       pSiS->CRT2pScrn->monitor->DDC = backupddc;
6719
6720       if(i == -1) {
6721	  SISErrorLog(pScrn, "xf86ValidateModes() error, %s.\n", mergeddisstr);
6722	  SiSFreeCRT2Structs(pSiS);
6723	  pSiS->MergedFB = FALSE;
6724       }
6725
6726    }
6727
6728    if(pSiS->MergedFB) {
6729
6730       if((p = first = pSiS->CRT2pScrn->modes)) {
6731          do {
6732	     n = p->next;
6733	     if( (pSiS->VGAEngine == SIS_300_VGA) &&
6734		 ( (strcmp(p->name, "320x200") == 0) ||
6735		   (strcmp(p->name, "320x240") == 0) ||
6736		   (strcmp(p->name, "400x300") == 0) ||
6737		   (strcmp(p->name, "512x384") == 0) ||
6738		   (strcmp(p->name, "640x400") == 0) ) )  {
6739		p->status = MODE_BAD;
6740		xf86DrvMsg(pScrn->scrnIndex, X_INFO, notsuitablestr, p->name, "MergedFB");
6741	     }
6742	     p = n;
6743	  } while (p != NULL && p != first);
6744       }
6745
6746       xf86PruneDriverModes(pSiS->CRT2pScrn);
6747
6748       if(i == 0 || pSiS->CRT2pScrn->modes == NULL) {
6749	  SISErrorLog(pScrn, "No valid modes found for CRT2; %s\n", mergeddisstr);
6750	  SiSFreeCRT2Structs(pSiS);
6751	  pSiS->MergedFB = FALSE;
6752       }
6753
6754    }
6755
6756    if(pSiS->MergedFB) {
6757
6758       xf86SetCrtcForModes(pSiS->CRT2pScrn, INTERLACE_HALVE_V);
6759
6760       xf86DrvMsg(pScrn->scrnIndex, X_INFO, modesforstr, 2);
6761
6762       if(pSiS->VBFlags & (CRT2_LCD | CRT2_TV)) {
6763	  SiSPrintModes(pSiS->CRT2pScrn);
6764       } else {
6765	  xf86PrintModes(pSiS->CRT2pScrn);
6766       }
6767
6768       pSiS->CRT1Modes = pScrn->modes;
6769       pSiS->CRT1CurrentMode = pScrn->currentMode;
6770
6771       xf86DrvMsg(pScrn->scrnIndex, X_INFO, "MergedFB: Generating mode list\n");
6772
6773       pScrn->modes = SiSGenerateModeList(pScrn, pSiS->MetaModes,
6774					  pSiS->CRT1Modes, pSiS->CRT2pScrn->modes,
6775					  pSiS->CRT2Position);
6776
6777       if(!pScrn->modes) {
6778
6779	  SISErrorLog(pScrn, "Failed to parse MetaModes or no modes found. %s.\n",
6780			mergeddisstr);
6781	  SiSFreeCRT2Structs(pSiS);
6782	  pScrn->modes = pSiS->CRT1Modes;
6783	  pSiS->CRT1Modes = NULL;
6784	  pSiS->MergedFB = FALSE;
6785
6786       }
6787
6788    }
6789
6790    if(pSiS->MergedFB) {
6791
6792       /* If no virtual dimension was given by the user,
6793	* calculate a sane one now. Adapts pScrn->virtualX,
6794	* pScrn->virtualY and pScrn->displayWidth.
6795	*/
6796       SiSRecalcDefaultVirtualSize(pScrn);
6797
6798       pScrn->modes = pScrn->modes->next;  /* We get the last from GenerateModeList(), skip to first */
6799       pScrn->currentMode = pScrn->modes;
6800
6801       /* Update CurrentLayout */
6802       pSiS->CurrentLayout.mode = pScrn->currentMode;
6803       pSiS->CurrentLayout.displayWidth = pScrn->displayWidth;
6804       pSiS->CurrentLayout.displayHeight = pScrn->virtualY;
6805
6806    }
6807#endif
6808
6809    /* Set display resolution */
6810#ifdef SISMERGED
6811    if(pSiS->MergedFB) {
6812       SiSMergedFBSetDpi(pScrn, pSiS->CRT2pScrn, pSiS->CRT2Position);
6813    } else
6814#endif
6815       xf86SetDpi(pScrn, 0, 0);
6816
6817    /* Load fb module */
6818    switch(pScrn->bitsPerPixel) {
6819      case 8:
6820      case 16:
6821      case 24:
6822      case 32:
6823	if(!xf86LoadSubModule(pScrn, "fb")) {
6824           SISErrorLog(pScrn, "Failed to load fb module");
6825	   goto my_error_1;
6826	}
6827	break;
6828      default:
6829	SISErrorLog(pScrn, "Unsupported framebuffer bpp (%d)\n", pScrn->bitsPerPixel);
6830	goto my_error_1;
6831    }
6832
6833    /* Load XAA/EXA (if needed) */
6834    if(!pSiS->NoAccel) {
6835#ifdef SIS_USE_XAA
6836       if(!pSiS->useEXA) {
6837	  if (!xf86LoadSubModule(pScrn, "xaa")) {
6838	    SISErrorLog(pScrn, "Could not load xaa module\n");
6839	    goto my_error_1;
6840	  }
6841       }
6842#endif
6843#ifdef SIS_USE_EXA
6844       if(pSiS->useEXA) {
6845	  XF86ModReqInfo req;
6846	  int errmaj, errmin;
6847
6848	  memset(&req, 0, sizeof(req));
6849	  req.majorversion = 2;
6850	  req.minorversion = 0;
6851	  if (!LoadSubModule(pScrn->module, "exa", NULL, NULL, NULL, &req,
6852	    &errmaj, &errmin)) {
6853	    LoaderErrorMsg(NULL, "exa", errmaj, errmin);
6854	    goto my_error_1;
6855	  }
6856       }
6857#endif
6858       xf86DrvMsg(pScrn->scrnIndex, X_INFO, "2D acceleration enabled\n");
6859    }
6860
6861    /* Load shadowfb (if needed) */
6862    if(pSiS->ShadowFB) {
6863       if(!xf86LoadSubModule(pScrn, "shadowfb")) {
6864	  SISErrorLog(pScrn, "Could not load shadowfb module\n");
6865	  goto my_error_1;
6866       }
6867    }
6868
6869    /* Load the dri and glx modules if requested. */
6870#ifdef XF86DRI
6871    if(pSiS->loadDRI) {
6872       if(!xf86LoaderCheckSymbol("DRIScreenInit")) {
6873	  if(xf86LoadSubModule(pScrn, "dri")) {
6874	     if(!xf86LoaderCheckSymbol("GlxSetVisualConfigs")) {
6875	        if(!xf86LoadSubModule(pScrn, "glx")) {
6876		   SISErrorLog(pScrn, "Failed to load glx module\n");
6877		}
6878	     }
6879	  } else {
6880	     SISErrorLog(pScrn, "Failed to load dri module\n");
6881	  }
6882       }
6883    }
6884#endif
6885
6886    /* Now load and initialize VBE module for VESA mode switching */
6887    pSiS->UseVESA = 0;
6888    if(pSiS->VESA == 1) {
6889       SiS_LoadInitVBE(pScrn);
6890       if(pSiS->pVbe) {
6891	  VbeInfoBlock *vbe;
6892	  if((vbe = VBEGetVBEInfo(pSiS->pVbe))) {
6893	     pSiS->vesamajor = (unsigned)(vbe->VESAVersion >> 8);
6894	     pSiS->vesaminor = vbe->VESAVersion & 0xff;
6895	     SiSBuildVesaModeList(pScrn, pSiS->pVbe, vbe);
6896	     VBEFreeVBEInfo(vbe);
6897	     pSiS->UseVESA = 1;
6898	  } else {
6899	     xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
6900	     	 "Failed to read VBE Info Block\n");
6901	  }
6902       }
6903       if(pSiS->UseVESA == 0) {
6904	  xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
6905	      "VESA mode switching disabled.\n");
6906       }
6907    }
6908
6909    if(pSiS->pVbe) {
6910       vbeFree(pSiS->pVbe);
6911       pSiS->pVbe = NULL;
6912    }
6913
6914#ifdef SISDUALHEAD
6915    xf86SetPrimInitDone(pScrn->entityList[0]);
6916#endif
6917
6918    sisRestoreExtRegisterLock(pSiS,srlockReg,crlockReg);
6919
6920    if(pSiS->pInt) xf86FreeInt10(pSiS->pInt);
6921    pSiS->pInt = NULL;
6922
6923    if(pSiS->VGAEngine == SIS_315_VGA) {
6924       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTXVGAMMA1;
6925    }
6926
6927#ifdef SISDUALHEAD
6928    if(pSiS->DualHeadMode) {
6929	pSiS->SiS_SD_Flags |= SiS_SD_ISDUALHEAD;
6930	if(pSiS->SecondHead) pSiS->SiS_SD_Flags |= SiS_SD_ISDHSECONDHEAD;
6931	else		     pSiS->SiS_SD_Flags &= ~(SiS_SD_SUPPORTXVGAMMA1);
6932#ifdef PANORAMIX
6933	if(!noPanoramiXExtension) {
6934	   pSiS->SiS_SD_Flags |= SiS_SD_ISDHXINERAMA;
6935	   /* pSiS->SiS_SD_Flags &= ~(SiS_SD_SUPPORTXVGAMMA1); */
6936	}
6937#endif
6938    }
6939#endif
6940
6941#ifdef SISMERGED
6942    if(pSiS->MergedFB) pSiS->SiS_SD_Flags |= SiS_SD_ISMERGEDFB;
6943#endif
6944
6945    /* Try to determine if this is a laptop   */
6946    /* (only used for SiSCtrl visualisations) */
6947    pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPLTFLAG;
6948    pSiS->SiS_SD2_Flags &= ~SiS_SD2_ISLAPTOP;
6949    if(pSiS->detectedCRT2Devices & CRT2_LCD) {
6950       if(pSiS->VBFlags2 & (VB2_SISLVDSBRIDGE | VB2_LVDS | VB2_30xBDH)) {
6951	  /* 1. By bridge type: LVDS in 99% of all cases;
6952	   * exclude unusual setups like Barco projectors
6953	   * and parallel flat panels. TODO: Exclude
6954	   * Sony W1, V1.
6955	   */
6956	  if((pSiS->SiS_Pr->SiS_CustomT != CUT_BARCO1366) &&
6957	     (pSiS->SiS_Pr->SiS_CustomT != CUT_BARCO1024) &&
6958	     (pSiS->SiS_Pr->SiS_CustomT != CUT_PANEL848)  &&
6959	     (pSiS->SiS_Pr->SiS_CustomT != CUT_PANEL856)  &&
6960	     (pSiS->SiS_Pr->SiS_CustomT != CUT_AOP8060)   &&
6961	     ( (pSiS->ChipType != SIS_550) ||
6962	       (!pSiS->DSTN && !pSiS->FSTN) ) ) {
6963	     pSiS->SiS_SD2_Flags |= SiS_SD2_ISLAPTOP;
6964	  }
6965       } else if((pSiS->VBFlags2 & (VB2_301 | VB2_301C)) &&
6966                 (pSiS->VBLCDFlags & (VB_LCD_1280x960  |
6967				      VB_LCD_1400x1050 |
6968				      VB_LCD_1024x600  |
6969				      VB_LCD_1280x800  |
6970				      VB_LCD_1280x854))) {
6971	  /* 2. By (odd) LCD resolutions on TMDS bridges
6972	   * (eg Averatec). TODO: Exclude IBM Netvista.
6973	   */
6974	  pSiS->SiS_SD2_Flags |= SiS_SD2_ISLAPTOP;
6975       }
6976    }
6977
6978    if(pSiS->enablesisctrl) pSiS->SiS_SD_Flags |= SiS_SD_ENABLED;
6979
6980    pSiS->currentModeLast = pScrn->currentMode;
6981    pSiS->VBFlagsInit = pSiS->VBFlags;
6982
6983    return TRUE;
6984
6985    /* ---- */
6986
6987my_error_1:
6988    sisRestoreExtRegisterLock(pSiS, srlockReg, crlockReg);
6989my_error_0:
6990#ifdef SISDUALHEAD
6991    if(pSiSEnt) pSiSEnt->ErrorAfterFirst = TRUE;
6992#endif
6993    if(pSiS->pInt) xf86FreeInt10(pSiS->pInt);
6994    pSiS->pInt = NULL;
6995    SISFreeRec(pScrn);
6996    return FALSE;
6997}
6998
6999/*
7000 * Map I/O port area for non-PC platforms
7001 */
7002#ifdef SIS_NEED_MAP_IOP
7003static Bool
7004SISMapIOPMem(ScrnInfoPtr pScrn)
7005{
7006    SISPtr pSiS = SISPTR(pScrn);
7007#ifdef SISDUALHEAD
7008    SISEntPtr pSiSEnt = pSiS->entityPrivate;
7009
7010    if(pSiS->DualHeadMode) {
7011        pSiSEnt->MapCountIOPBase++;
7012        if(!(pSiSEnt->IOPBase)) {
7013	     /* Only map if not mapped previously */
7014#ifndef XSERVER_LIBPCIACCESS
7015	     pSiSEnt->IOPBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
7016			pSiS->PciTag, pSiS->IOPAddress, 128);
7017#else
7018	     {
7019	       void **result = (void **)&pSiSEnt->IOPBase;
7020	       int err = pci_device_map_range(pSiS->PciInfo,
7021					      pSiS->IOPAddress,
7022					      128,
7023					      PCI_DEV_MAP_FLAG_WRITABLE,
7024					      result);
7025
7026	       if (err) {
7027                 xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
7028                             "Unable to map IO aperture. %s (%d)\n",
7029                             strerror (err), err);
7030	       }
7031	     }
7032#endif
7033        }
7034        pSiS->IOPBase = pSiSEnt->IOPBase;
7035    } else
7036#endif
7037#ifndef XSERVER_LIBPCIACCESS
7038	     pSiS->IOPBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
7039					   pSiS->PciTag, pSiS->IOPAddress, 128);
7040#else
7041	     {
7042	       void **result = (void **)&pSiS->IOPBase;
7043	       int err = pci_device_map_range(pSiS->PciInfo,
7044					      pSiS->IOPAddress,
7045					      128,
7046					      PCI_DEV_MAP_FLAG_WRITABLE,
7047					      result);
7048
7049	       if (err) {
7050                 xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
7051                             "Unable to map IO aperture. %s (%d)\n",
7052                             strerror (err), err);
7053	       }
7054	     }
7055#endif
7056    if(pSiS->IOPBase == NULL) {
7057	SISErrorLog(pScrn, "Could not map I/O port area\n");
7058	return FALSE;
7059    }
7060
7061    return TRUE;
7062}
7063
7064static Bool
7065SISUnmapIOPMem(ScrnInfoPtr pScrn)
7066{
7067    SISPtr pSiS = SISPTR(pScrn);
7068#ifdef SISDUALHEAD
7069    SISEntPtr pSiSEnt = pSiS->entityPrivate;;
7070#endif
7071
7072/* In dual head mode, we must not unmap if the other head still
7073 * assumes memory as mapped
7074 */
7075#ifdef SISDUALHEAD
7076    if(pSiS->DualHeadMode) {
7077        if(pSiSEnt->MapCountIOPBase) {
7078	    pSiSEnt->MapCountIOPBase--;
7079	    if((pSiSEnt->MapCountIOPBase == 0) || (pSiSEnt->forceUnmapIOPBase)) {
7080		xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiSEnt->IOPBase, 2048);
7081		pSiSEnt->IOPBase = NULL;
7082		pSiSEnt->MapCountIOPBase = 0;
7083		pSiSEnt->forceUnmapIOPBase = FALSE;
7084	    }
7085	    pSiS->IOPBase = NULL;
7086	}
7087    } else {
7088#endif
7089	xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiS->IOPBase, 2048);
7090	pSiS->IOPBase = NULL;
7091#ifdef SISDUALHEAD
7092    }
7093#endif
7094    return TRUE;
7095}
7096#endif
7097
7098/*
7099 * Map the framebuffer and MMIO memory
7100 */
7101
7102static Bool
7103SISMapMem(ScrnInfoPtr pScrn)
7104{
7105    SISPtr pSiS = SISPTR(pScrn);
7106    int mmioFlags = VIDMEM_MMIO;
7107#ifdef SISDUALHEAD
7108    SISEntPtr pSiSEnt = pSiS->entityPrivate;
7109#endif
7110
7111    /*
7112     * Map IO registers to virtual address space
7113     * (For Alpha, we need to map SPARSE memory, since we need
7114     * byte/short access.)
7115     */
7116#if defined(__alpha__)
7117    mmioFlags |= VIDMEM_SPARSE;
7118#endif
7119
7120#ifdef SISDUALHEAD
7121    if(pSiS->DualHeadMode) {
7122        pSiSEnt->MapCountIOBase++;
7123        if(!(pSiSEnt->IOBase)) {
7124	     /* Only map if not mapped previously */
7125#ifndef XSERVER_LIBPCIACCESS
7126    	     pSiSEnt->IOBase = xf86MapPciMem(pScrn->scrnIndex, mmioFlags,
7127                         pSiS->PciTag, pSiS->IOAddress, (pSiS->mmioSize * 1024));
7128#else
7129	     void **result = (void **)&pSiSEnt->IOBase;
7130	     int err = pci_device_map_range(pSiS->PciInfo,
7131 	                                    pSiS->IOAddress,
7132	                                    (pSiS->mmioSize * 1024),
7133                                            PCI_DEV_MAP_FLAG_WRITABLE,
7134                                            result);
7135
7136             if (err) {
7137                 xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
7138                             "Unable to map IO aperture. %s (%d)\n",
7139                             strerror (err), err);
7140	     }
7141#endif
7142        }
7143        pSiS->IOBase = pSiSEnt->IOBase;
7144    } else
7145#endif
7146#ifndef XSERVER_LIBPCIACCESS
7147    	pSiS->IOBase = xf86MapPciMem(pScrn->scrnIndex, mmioFlags,
7148                        pSiS->PciTag, pSiS->IOAddress, (pSiS->mmioSize * 1024));
7149#else
7150       {
7151	     void **result = (void **)&pSiS->IOBase;
7152	     int err = pci_device_map_range(pSiS->PciInfo,
7153 	                                    pSiS->IOAddress,
7154	                                    (pSiS->mmioSize * 1024),
7155                                            PCI_DEV_MAP_FLAG_WRITABLE,
7156                                            result);
7157
7158             if (err) {
7159                 xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
7160                             "Unable to map IO aperture. %s (%d)\n",
7161                             strerror (err), err);
7162	     }
7163       }
7164#endif
7165
7166    if(pSiS->IOBase == NULL) {
7167    	SISErrorLog(pScrn, "Could not map MMIO area\n");
7168        return FALSE;
7169    }
7170
7171#ifdef __alpha__
7172    /*
7173     * for Alpha, we need to map DENSE memory as well, for
7174     * setting CPUToScreenColorExpandBase.
7175     */
7176#ifdef SISDUALHEAD
7177    if(pSiS->DualHeadMode) {
7178        pSiSEnt->MapCountIOBaseDense++;
7179        if(!(pSiSEnt->IOBaseDense)) {
7180	     /* Only map if not mapped previously */
7181#ifndef XSERVER_LIBPCIACCESS
7182	     pSiSEnt->IOBaseDense = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
7183                    pSiS->PciTag, pSiS->IOAddress, (pSiS->mmioSize * 1024));
7184#else
7185	     void **result = (void **)&pSiSEnt->IOBaseDense;
7186	     int err = pci_device_map_range(pSiS->PciInfo,
7187 	                                    pSiS->IOAddress,
7188	                                    (pSiS->mmioSize * 1024),
7189                                            PCI_DEV_MAP_FLAG_WRITABLE,
7190                                            result);
7191
7192             if (err) {
7193                 xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
7194                             "Unable to map IO dense aperture. %s (%d)\n",
7195                             strerror (err), err);
7196	     }
7197#endif /* XSERVER_LIBPCIACCESS */
7198	}
7199	pSiS->IOBaseDense = pSiSEnt->IOBaseDense;
7200    } else {
7201#endif /* SISDUALHEAD */
7202#ifndef XSERVER_LIBPCIACCESS
7203	     pSiS->IOBaseDense = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
7204                    pSiS->PciTag, pSiS->IOAddress, (pSiS->mmioSize * 1024));
7205#else
7206	     void **result = (void **)&pSiS->IOBaseDense;
7207	     int err = pci_device_map_range(pSiS->PciInfo,
7208 	                                    pSiS->IOAddress,
7209	                                    (pSiS->mmioSize * 1024),
7210                                            PCI_DEV_MAP_FLAG_WRITABLE,
7211                                            result);
7212
7213             if (err) {
7214                 xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
7215                             "Unable to map IO dense aperture. %s (%d)\n",
7216                             strerror (err), err);
7217	     }
7218#endif /* XSERVER_LIBPCIACCESS */
7219#ifdef SISDUALHEAD
7220    }
7221#endif
7222    if(pSiS->IOBaseDense == NULL) {
7223       SISErrorLog(pScrn, "Could not map MMIO dense area\n");
7224       return FALSE;
7225    }
7226#endif /* __alpha__ */
7227
7228#ifdef SISDUALHEAD
7229    if(pSiS->DualHeadMode) {
7230	pSiSEnt->MapCountFbBase++;
7231	if(!(pSiSEnt->FbBase)) {
7232	     /* Only map if not mapped previously */
7233#ifndef XSERVER_LIBPCIACCESS
7234	     pSiSEnt->FbBase = pSiSEnt->RealFbBase =
7235			xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
7236			 pSiS->PciTag, (ULong)pSiS->realFbAddress,
7237			 pSiS->FbMapSize);
7238#else
7239         int err = pci_device_map_range(pSiS->PciInfo,
7240                                   (ULong)pSiS->realFbAddress,
7241                                   pSiS->FbMapSize,
7242                                   PCI_DEV_MAP_FLAG_WRITABLE |
7243                                   PCI_DEV_MAP_FLAG_WRITE_COMBINE,
7244                                   (void *)&pSiSEnt->FbBase);
7245	if (err) {
7246            xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
7247                        "Unable to map FB aperture. %s (%d)\n",
7248                        strerror (err), err);
7249            return FALSE;
7250        }
7251	pSiSEnt->RealFbBase = pSiSEnt->FbBase;
7252#endif
7253	}
7254	pSiS->FbBase = pSiS->RealFbBase = pSiSEnt->FbBase;
7255	/* Adapt FbBase (for DHM and SiS76x UMA skipping; dhmOffset is 0 otherwise) */
7256	pSiS->FbBase += pSiS->dhmOffset;
7257    } else {
7258#endif
7259
7260#ifndef XSERVER_LIBPCIACCESS
7261      pSiS->FbBase = pSiS->RealFbBase =
7262			xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
7263			 pSiS->PciTag, (ULong)pSiS->realFbAddress,
7264			 pSiS->FbMapSize);
7265#else
7266         int err = pci_device_map_range(pSiS->PciInfo,
7267                                   (ULong)pSiS->realFbAddress,
7268                                   pSiS->FbMapSize,
7269                                   PCI_DEV_MAP_FLAG_WRITABLE |
7270                                   PCI_DEV_MAP_FLAG_WRITE_COMBINE,
7271                                   (void *)&pSiS->FbBase);
7272	if (err) {
7273            xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
7274                        "Unable to map FB aperture. %s (%d)\n",
7275                        strerror (err), err);
7276            return FALSE;
7277        }
7278	pSiS->RealFbBase = pSiS->FbBase;
7279#endif
7280	pSiS->FbBase += pSiS->dhmOffset;
7281
7282#ifdef SISDUALHEAD
7283    }
7284#endif
7285
7286    if(pSiS->FbBase == NULL) {
7287       SISErrorLog(pScrn, "Could not map framebuffer area\n");
7288       return FALSE;
7289    }
7290
7291#ifdef TWDEBUG
7292    xf86DrvMsg(0, 0, "Framebuffer mapped to %p\n", pSiS->FbBase);
7293#endif
7294
7295    return TRUE;
7296}
7297
7298
7299/*
7300 * Unmap the framebuffer and MMIO memory.
7301 */
7302
7303static Bool
7304SISUnmapMem(ScrnInfoPtr pScrn)
7305{
7306    SISPtr pSiS = SISPTR(pScrn);
7307#ifdef SISDUALHEAD
7308    SISEntPtr pSiSEnt = pSiS->entityPrivate;
7309#endif
7310
7311/* In dual head mode, we must not unmap if the other head still
7312 * assumes memory as mapped
7313 */
7314#ifdef SISDUALHEAD
7315    if(pSiS->DualHeadMode) {
7316        if(pSiSEnt->MapCountIOBase) {
7317	    pSiSEnt->MapCountIOBase--;
7318	    if((pSiSEnt->MapCountIOBase == 0) || (pSiSEnt->forceUnmapIOBase)) {
7319		xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiSEnt->IOBase, (pSiS->mmioSize * 1024));
7320		pSiSEnt->IOBase = NULL;
7321		pSiSEnt->MapCountIOBase = 0;
7322		pSiSEnt->forceUnmapIOBase = FALSE;
7323	    }
7324	    pSiS->IOBase = NULL;
7325	}
7326#ifdef __alpha__
7327	if(pSiSEnt->MapCountIOBaseDense) {
7328	    pSiSEnt->MapCountIOBaseDense--;
7329	    if((pSiSEnt->MapCountIOBaseDense == 0) || (pSiSEnt->forceUnmapIOBaseDense)) {
7330		xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiSEnt->IOBaseDense, (pSiS->mmioSize * 1024));
7331		pSiSEnt->IOBaseDense = NULL;
7332		pSiSEnt->MapCountIOBaseDense = 0;
7333		pSiSEnt->forceUnmapIOBaseDense = FALSE;
7334	    }
7335	    pSiS->IOBaseDense = NULL;
7336	}
7337#endif /* __alpha__ */
7338	if(pSiSEnt->MapCountFbBase) {
7339	    pSiSEnt->MapCountFbBase--;
7340	    if((pSiSEnt->MapCountFbBase == 0) || (pSiSEnt->forceUnmapFbBase)) {
7341		xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiSEnt->RealFbBase, pSiS->FbMapSize);
7342		pSiSEnt->FbBase = pSiSEnt->RealFbBase = NULL;
7343		pSiSEnt->MapCountFbBase = 0;
7344		pSiSEnt->forceUnmapFbBase = FALSE;
7345
7346	    }
7347	    pSiS->FbBase = pSiS->RealFbBase = NULL;
7348	}
7349    } else {
7350#endif
7351	xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiS->IOBase, (pSiS->mmioSize * 1024));
7352	pSiS->IOBase = NULL;
7353#ifdef __alpha__
7354	xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiS->IOBaseDense, (pSiS->mmioSize * 1024));
7355	pSiS->IOBaseDense = NULL;
7356#endif
7357	xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiS->RealFbBase, pSiS->FbMapSize);
7358	pSiS->FbBase = pSiS->RealFbBase = NULL;
7359#ifdef SISDUALHEAD
7360    }
7361#endif
7362    return TRUE;
7363}
7364
7365/*
7366 * This function saves the video state.
7367 */
7368static void
7369SISSave(ScrnInfoPtr pScrn)
7370{
7371    SISPtr pSiS = SISPTR(pScrn);
7372    SISRegPtr sisReg;
7373    int flags;
7374
7375#ifdef SISDUALHEAD
7376    /* We always save master & slave */
7377    if(pSiS->DualHeadMode && pSiS->SecondHead) return;
7378#endif
7379
7380    sisReg = &pSiS->SavedReg;
7381
7382    if( ((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) &&
7383        ((pSiS->VBFlags2 & VB2_VIDEOBRIDGE) && (SiSBridgeIsInSlaveMode(pScrn))) ) {
7384       SiSVGASave(pScrn, sisReg, SISVGA_SR_CMAP | SISVGA_SR_MODE);
7385#ifdef SIS_PC_PLATFORM
7386       if(pSiS->VGAMemBase) {
7387          SiSRegInit(pSiS->SiS_Pr, pSiS->RelIO+0x30);
7388          SiSSetLVDSetc(pSiS->SiS_Pr, 0);
7389          SiS_GetVBType(pSiS->SiS_Pr);
7390          SiS_DisableBridge(pSiS->SiS_Pr);
7391          SiSVGASave(pScrn, sisReg, SISVGA_SR_FONTS);
7392          SiS_EnableBridge(pSiS->SiS_Pr);
7393       }
7394#endif
7395    } else {
7396       flags = SISVGA_SR_CMAP | SISVGA_SR_MODE;
7397#ifdef SIS_PC_PLATFORM
7398       if(pSiS->VGAMemBase) flags |= SISVGA_SR_FONTS;
7399#endif
7400       SiSVGASave(pScrn, sisReg, flags);
7401    }
7402
7403    sisSaveUnlockExtRegisterLock(pSiS, &sisReg->sisRegs3C4[0x05], &sisReg->sisRegs3D4[0x80]);
7404
7405    (*pSiS->SiSSave)(pScrn, sisReg);
7406
7407    if(pSiS->UseVESA) SISVESASaveRestore(pScrn, MODE_SAVE);
7408
7409    /* "Save" these again as they may have been changed prior to SISSave() call */
7410    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
7411       sisReg->sisRegs3C4[0x1f] = pSiS->oldSR1F;
7412       sisReg->sisRegs3D4[0x17] = pSiS->oldCR17;
7413       sisReg->sisRegs3D4[0x32] = pSiS->oldCR32;
7414       sisReg->sisRegs3D4[0x36] = pSiS->oldCR36;
7415       sisReg->sisRegs3D4[0x37] = pSiS->oldCR37;
7416       if(pSiS->VGAEngine == SIS_315_VGA) {
7417	  sisReg->sisRegs3D4[pSiS->myCR63] = pSiS->oldCR63;
7418       }
7419    }
7420}
7421
7422/* VESASaveRestore taken from vesa driver */
7423static void
7424SISVESASaveRestore(ScrnInfoPtr pScrn, vbeSaveRestoreFunction function)
7425{
7426    SISPtr pSiS = SISPTR(pScrn);
7427
7428    /* Query amount of memory to save state */
7429    if((function == MODE_QUERY) ||
7430       (function == MODE_SAVE && pSiS->state == NULL)) {
7431
7432       /* Make sure we save at least this information in case of failure */
7433       (void)VBEGetVBEMode(pSiS->pVbe, &pSiS->stateMode);
7434       SiSVGASaveFonts(pScrn);
7435
7436       if(pSiS->vesamajor > 1) {
7437	  if(!VBESaveRestore(pSiS->pVbe, function, (pointer)&pSiS->state,
7438				&pSiS->stateSize, &pSiS->statePage)) {
7439	     return;
7440	  }
7441       }
7442    }
7443
7444    /* Save/Restore Super VGA state */
7445    if(function != MODE_QUERY) {
7446
7447       if(pSiS->vesamajor > 1) {
7448	  if(function == MODE_RESTORE) {
7449	     memcpy(pSiS->state, pSiS->pstate, pSiS->stateSize);
7450	  }
7451
7452	  if(VBESaveRestore(pSiS->pVbe,function,(pointer)&pSiS->state,
7453			    &pSiS->stateSize,&pSiS->statePage) &&
7454	     (function == MODE_SAVE)) {
7455	     /* don't rely on the memory not being touched */
7456	     if(!pSiS->pstate) {
7457		pSiS->pstate = xalloc(pSiS->stateSize);
7458	     }
7459	     memcpy(pSiS->pstate, pSiS->state, pSiS->stateSize);
7460	  }
7461       }
7462
7463       if(function == MODE_RESTORE) {
7464	  VBESetVBEMode(pSiS->pVbe, pSiS->stateMode, NULL);
7465	  SiSVGARestoreFonts(pScrn);
7466       }
7467
7468    }
7469}
7470
7471/*
7472 * Initialise a new mode.  This is currently done using the
7473 * "initialise struct, restore/write struct to HW" model for
7474 * the old chipsets (5597/530/6326). For newer chipsets,
7475 * we use our own mode switching code.
7476 */
7477
7478static Bool
7479SISModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
7480{
7481    SISPtr pSiS = SISPTR(pScrn);
7482    SISRegPtr sisReg;
7483#ifdef SISDUALHEAD
7484    SISEntPtr pSiSEnt = NULL;
7485#endif
7486
7487    andSISIDXREG(SISCR,0x11,0x7f);	/* Unlock CRTC registers */
7488
7489    SISModifyModeInfo(mode);		/* Quick check of the mode parameters */
7490
7491    if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
7492       SiSRegInit(pSiS->SiS_Pr, pSiS->RelIO+0x30);
7493    }
7494
7495    if(pSiS->UseVESA) {  /* With VESA: */
7496
7497#ifdef SISDUALHEAD
7498       /* No dual head mode when using VESA */
7499       if(pSiS->SecondHead) return TRUE;
7500#endif
7501
7502       pScrn->vtSema = TRUE;
7503
7504       /*
7505	* This order is required:
7506	* The video bridge needs to be adjusted before the
7507	* BIOS is run as the BIOS sets up CRT2 according to
7508	* these register settings.
7509	* After the BIOS is run, the bridges and turboqueue
7510	* registers need to be readjusted as the BIOS may
7511	* very probably have messed them up.
7512	*/
7513       if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
7514	  SiSPreSetMode(pScrn, mode, SIS_MODE_SIMU);
7515       }
7516       if(!SiSSetVESAMode(pScrn, mode)) {
7517	  SISErrorLog(pScrn, "SiSSetVESAMode() failed\n");
7518	  return FALSE;
7519       }
7520       sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
7521       if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
7522	  SiSPreSetMode(pScrn, mode, SIS_MODE_SIMU);
7523	  SiSPostSetMode(pScrn, &pSiS->ModeReg);
7524       }
7525#ifdef TWDEBUG
7526       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
7527		   "REAL REGISTER CONTENTS AFTER SETMODE:\n");
7528#endif
7529       if(!(*pSiS->ModeInit)(pScrn, mode)) {
7530	  SISErrorLog(pScrn, "ModeInit() failed\n");
7531	  return FALSE;
7532       }
7533
7534       SiSVGAProtect(pScrn, TRUE);
7535       (*pSiS->SiSRestore)(pScrn, &pSiS->ModeReg);
7536       SiSVGAProtect(pScrn, FALSE);
7537
7538    } else { /* Without VESA: */
7539
7540#ifdef SISDUALHEAD
7541       if(pSiS->DualHeadMode) {
7542
7543	  if(!(*pSiS->ModeInit)(pScrn, mode)) {
7544	     SISErrorLog(pScrn, "ModeInit() failed\n");
7545	     return FALSE;
7546	  }
7547
7548	  pScrn->vtSema = TRUE;
7549
7550	  pSiSEnt = pSiS->entityPrivate;
7551
7552	  if(!(pSiS->SecondHead)) {
7553	     /* Head 1 (master) is always CRT2 */
7554	     SiSPreSetMode(pScrn, mode, SIS_MODE_CRT2);
7555	     if(!SiSBIOSSetModeCRT2(pSiS->SiS_Pr, pScrn, mode, pSiS->IsCustom)) {
7556		SISErrorLog(pScrn, "SiSBIOSSetModeCRT2() failed\n");
7557		return FALSE;
7558	     }
7559	     SiSPostSetMode(pScrn, &pSiS->ModeReg);
7560	     if(pSiSEnt->pScrn_2) {
7561		SISAdjustFrame(pSiSEnt->pScrn_2->scrnIndex,
7562			       pSiSEnt->pScrn_2->frameX0,
7563			       pSiSEnt->pScrn_2->frameY0, 0);
7564	     }
7565	  } else {
7566	     /* Head 2 (slave) is always CRT1 */
7567	     SiSPreSetMode(pScrn, mode, SIS_MODE_CRT1);
7568	     if(!SiSBIOSSetModeCRT1(pSiS->SiS_Pr, pScrn, mode, pSiS->IsCustom)) {
7569		SISErrorLog(pScrn, "SiSBIOSSetModeCRT1() failed\n");
7570		return FALSE;
7571	     }
7572	     SiSPostSetMode(pScrn, &pSiS->ModeReg);
7573	     if(pSiSEnt->pScrn_1) {
7574		SISAdjustFrame(pSiSEnt->pScrn_1->scrnIndex,
7575			       pSiSEnt->pScrn_1->frameX0,
7576			       pSiSEnt->pScrn_1->frameY0, 0);
7577	     }
7578	  }
7579
7580       } else {
7581#endif
7582
7583	  if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
7584
7585	     if(!(*pSiS->ModeInit)(pScrn, mode)) {
7586		SISErrorLog(pScrn, "ModeInit() failed\n");
7587	        return FALSE;
7588	     }
7589
7590	     pScrn->vtSema = TRUE;
7591
7592#ifdef SISMERGED
7593	     if(pSiS->MergedFB) {
7594
7595		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Setting MergedFB mode %dx%d\n",
7596				mode->HDisplay, mode->VDisplay);
7597
7598		SiSPreSetMode(pScrn, mode, SIS_MODE_CRT1);
7599
7600		if(!SiSBIOSSetModeCRT1(pSiS->SiS_Pr, pScrn,
7601		                       ((SiSMergedDisplayModePtr)mode->Private)->CRT1,
7602				       pSiS->IsCustom)) {
7603		   SISErrorLog(pScrn, "SiSBIOSSetModeCRT1() failed\n");
7604		   return FALSE;
7605		}
7606
7607		SiSPreSetMode(pScrn, mode, SIS_MODE_CRT2);
7608
7609		if(!SiSBIOSSetModeCRT2(pSiS->SiS_Pr, pScrn,
7610		                       ((SiSMergedDisplayModePtr)mode->Private)->CRT2,
7611				       pSiS->IsCustom)) {
7612		   SISErrorLog(pScrn, "SiSBIOSSetModeCRT2() failed\n");
7613		   return FALSE;
7614		}
7615
7616	     } else {
7617#endif
7618
7619		if((pSiS->VBFlags & CRT1_LCDA) || (!(mode->type & M_T_DEFAULT))) {
7620
7621		   SiSPreSetMode(pScrn, mode, SIS_MODE_CRT1);
7622
7623		   if(!SiSBIOSSetModeCRT1(pSiS->SiS_Pr, pScrn,
7624				mode, pSiS->IsCustom)) {
7625		      SISErrorLog(pScrn, "SiSBIOSSetModeCRT1() failed\n");
7626		      return FALSE;
7627		   }
7628
7629		   SiSPreSetMode(pScrn, mode, SIS_MODE_CRT2);
7630
7631		   if(!SiSBIOSSetModeCRT2(pSiS->SiS_Pr, pScrn,
7632				mode, pSiS->IsCustom)) {
7633		      SISErrorLog(pScrn, "SiSBIOSSetModeCRT2() failed\n");
7634		      return FALSE;
7635		   }
7636
7637		} else {
7638
7639		   SiSPreSetMode(pScrn, mode, SIS_MODE_SIMU);
7640
7641		   if(!SiSBIOSSetMode(pSiS->SiS_Pr, pScrn,
7642				mode, pSiS->IsCustom)) {
7643		      SISErrorLog(pScrn, "SiSBIOSSetMode() failed\n");
7644		      return FALSE;
7645		   }
7646
7647		}
7648
7649#ifdef SISMERGED
7650	     }
7651#endif
7652
7653	     SiSPostSetMode(pScrn, &pSiS->ModeReg);
7654
7655#ifdef TWDEBUG
7656	     xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VBFlags %lx\n", pSiS->VBFlags);
7657	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
7658			"REAL REGISTER CONTENTS AFTER SETMODE:\n");
7659             (*pSiS->ModeInit)(pScrn, mode);
7660#endif
7661
7662	  } else {
7663
7664	     /* For other chipsets, use the old method */
7665
7666	     /* Prepare the register contents */
7667	     if(!(*pSiS->ModeInit)(pScrn, mode)) {
7668	        SISErrorLog(pScrn, "ModeInit() failed\n");
7669	        return FALSE;
7670	     }
7671
7672	     pScrn->vtSema = TRUE;
7673
7674	     /* Program the registers */
7675	     SiSVGAProtect(pScrn, TRUE);
7676	     sisReg = &pSiS->ModeReg;
7677
7678	     sisReg->sisRegsATTR[0x10] = 0x01;
7679	     if(pScrn->bitsPerPixel > 8) {
7680		sisReg->sisRegsGR[0x05] = 0x00;
7681	     }
7682
7683	     SiSVGARestore(pScrn, sisReg, SISVGA_SR_MODE);
7684
7685	     (*pSiS->SiSRestore)(pScrn, sisReg);
7686
7687	     if((pSiS->Chipset == PCI_CHIP_SIS6326) && (pSiS->SiS6326Flags & SIS6326_HASTV)) {
7688	        SiS6326PostSetMode(pScrn, &pSiS->ModeReg);
7689	     }
7690
7691#ifdef TWDEBUG
7692	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
7693			"REAL REGISTER CONTENTS AFTER SETMODE:\n");
7694	     (*pSiS->ModeInit)(pScrn, mode);
7695#endif
7696
7697	     SiSVGAProtect(pScrn, FALSE);
7698
7699	  }
7700
7701#ifdef SISDUALHEAD
7702       }
7703#endif
7704    }
7705
7706    /* Update Currentlayout */
7707    pSiS->CurrentLayout.mode = pSiS->currentModeLast = mode;
7708
7709    return TRUE;
7710}
7711
7712static Bool
7713SiSSetVESAMode(ScrnInfoPtr pScrn, DisplayModePtr pMode)
7714{
7715    SISPtr pSiS;
7716    int mode;
7717
7718    pSiS = SISPTR(pScrn);
7719
7720    if(!(mode = SiSCalcVESAModeIndex(pScrn, pMode))) return FALSE;
7721
7722    mode |= (1 << 15);	/* Don't clear framebuffer */
7723    mode |= (1 << 14); 	/* Use linear adressing */
7724
7725    if(VBESetVBEMode(pSiS->pVbe, mode, NULL) == FALSE) {
7726       SISErrorLog(pScrn, "Setting VESA mode 0x%x failed\n",
7727	             	mode & 0x0fff);
7728       return (FALSE);
7729    }
7730
7731    if(pMode->HDisplay != pScrn->virtualX) {
7732       VBESetLogicalScanline(pSiS->pVbe, pScrn->virtualX);
7733    }
7734
7735    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
7736    	"Setting VESA mode 0x%x succeeded\n",
7737	mode & 0x0fff);
7738
7739    return (TRUE);
7740}
7741
7742static void
7743SISSpecialRestore(ScrnInfoPtr pScrn)
7744{
7745    SISPtr    pSiS = SISPTR(pScrn);
7746    SISRegPtr sisReg = &pSiS->SavedReg;
7747    UChar temp;
7748    int i;
7749
7750    /* 1.11.04 and later for 651 and 301B(DH) do strange register
7751     * fiddling after the usual mode change. This happens
7752     * depending on the result of a call of int 2f (with
7753     * ax=0x1680) and if modeno <= 0x13. I have no idea if
7754     * that is specific for the 651 or that very machine.
7755     * So this perhaps requires some more checks in the beginning
7756     * (although it should not do any harm on other chipsets/bridges
7757     * etc.) However, even if I call the VBE to restore mode 0x03,
7758     * these registers don't get restored correctly, possibly
7759     * because that int-2f-call for some reason results non-zero. So
7760     * what I do here is to restore these few registers
7761     * manually.
7762     */
7763
7764    if(!(pSiS->ChipFlags & SiSCF_Is65x)) return;
7765    inSISIDXREG(SISCR, 0x34, temp);
7766    temp &= 0x7f;
7767    if(temp > 0x13) return;
7768
7769#ifdef UNLOCK_ALWAYS
7770    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
7771#endif
7772
7773    SiS_UnLockCRT2(pSiS->SiS_Pr);
7774
7775    outSISIDXREG(SISCAP, 0x3f, sisReg->sisCapt[0x3f]);
7776    outSISIDXREG(SISCAP, 0x00, sisReg->sisCapt[0x00]);
7777    for(i = 0; i < 0x4f; i++) {
7778       outSISIDXREG(SISCAP, i, sisReg->sisCapt[i]);
7779    }
7780    outSISIDXREG(SISVID, 0x32, (sisReg->sisVid[0x32] & ~0x05));
7781    outSISIDXREG(SISVID, 0x30, sisReg->sisVid[0x30]);
7782    outSISIDXREG(SISVID, 0x32, ((sisReg->sisVid[0x32] & ~0x04) | 0x01));
7783    outSISIDXREG(SISVID, 0x30, sisReg->sisVid[0x30]);
7784
7785    if(!(pSiS->ChipFlags & SiSCF_Is651)) return;
7786    if(!(pSiS->VBFlags2 & VB2_SISBRIDGE)) return;
7787
7788    inSISIDXREG(SISCR, 0x30, temp);
7789    if(temp & 0x40) {
7790       UChar myregs[] = {
7791       		0x2f, 0x08, 0x09, 0x03, 0x0a, 0x0c,
7792		0x0b, 0x0d, 0x0e, 0x12, 0x0f, 0x10,
7793		0x11, 0x04, 0x05, 0x06, 0x07, 0x00,
7794		0x2e
7795       };
7796       for(i = 0; i <= 18; i++) {
7797          outSISIDXREG(SISPART1, myregs[i], sisReg->VBPart1[myregs[i]]);
7798       }
7799    } else if((temp & 0x20) || (temp & 0x9c)) {
7800       UChar myregs[] = {
7801       		0x04, 0x05, 0x06, 0x07, 0x00, 0x2e
7802       };
7803       for(i = 0; i <= 5; i++) {
7804          outSISIDXREG(SISPART1, myregs[i], sisReg->VBPart1[myregs[i]]);
7805       }
7806    }
7807}
7808
7809/* Fix SR11 for 661 and later */
7810static void
7811SiSFixupSR11(ScrnInfoPtr pScrn)
7812{
7813    SISPtr pSiS = SISPTR(pScrn);
7814    CARD8  tmpreg;
7815
7816#ifdef UNLOCK_ALWAYS
7817    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
7818#endif
7819
7820    if(pSiS->ChipType >= SIS_661) {
7821       inSISIDXREG(SISSR,0x11,tmpreg);
7822       if(tmpreg & 0x20) {
7823          inSISIDXREG(SISSR,0x3e,tmpreg);
7824	  tmpreg = (tmpreg + 1) & 0xff;
7825	  outSISIDXREG(SISSR,0x3e,tmpreg);
7826       }
7827
7828       inSISIDXREG(SISSR,0x11,tmpreg);
7829       if(tmpreg & 0xf0) {
7830          andSISIDXREG(SISSR,0x11,0x0f);
7831       }
7832    }
7833}
7834
7835/* Subroutine for restoring sisfb's TV parameters (used by SiSRestore()) */
7836
7837static void
7838SiSRestore_SiSFB_TVParms(ScrnInfoPtr pScrn)
7839{
7840    SISPtr  pSiS = SISPTR(pScrn);
7841    int     fd;
7842    CARD32  parm;
7843
7844    if(!pSiS->sisfbfound) return;
7845    if(!pSiS->sisfb_tvposvalid) return;
7846    if(!(pSiS->sisfbdevname[0])) return;
7847
7848    if((fd = open(pSiS->sisfbdevname, O_RDONLY)) != -1) {
7849       parm = (CARD32)((pSiS->sisfb_tvxpos << 16) | (pSiS->sisfb_tvypos & 0xffff));
7850       ioctl(fd, SISFB_SET_TVPOSOFFSET, &parm);
7851       close(fd);
7852    }
7853}
7854
7855/*
7856 * Restore the initial mode. To be used internally only!
7857 */
7858static void
7859SISRestore(ScrnInfoPtr pScrn)
7860{
7861    SISPtr    pSiS = SISPTR(pScrn);
7862    SISRegPtr sisReg = &pSiS->SavedReg;
7863    Bool      doit = FALSE, doitlater = FALSE;
7864    Bool      vesasuccess = FALSE;
7865    int	      flags;
7866
7867    /* WARNING: Don't ever touch this. It now seems to work on
7868     * all chipset/bridge combinations - but finding out the
7869     * correct combination was pure hell.
7870     */
7871
7872    /* Wait for the accelerators */
7873    (*pSiS->SyncAccel)(pScrn);
7874
7875    /* Set up restore flags */
7876    flags = SISVGA_SR_MODE | SISVGA_SR_CMAP;
7877#ifdef SIS_PC_PLATFORM
7878    /* We now restore ALL to overcome the vga=extended problem */
7879    if(pSiS->VGAMemBase) flags |= SISVGA_SR_FONTS;
7880#endif
7881
7882    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
7883
7884#ifdef SISDUALHEAD
7885       /* We always restore master AND slave */
7886       if(pSiS->DualHeadMode && pSiS->SecondHead) return;
7887#endif
7888
7889#ifdef UNLOCK_ALWAYS
7890       sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
7891#endif
7892
7893       /* We must not disable the sequencer if the bridge is in SlaveMode! */
7894       if(!(SiSBridgeIsInSlaveMode(pScrn))) {
7895	  SiSVGAProtect(pScrn, TRUE);
7896       }
7897
7898       /* First, restore CRT1 on/off and VB connection registers */
7899       outSISIDXREG(SISCR, 0x32, pSiS->oldCR32);
7900       if(!(pSiS->oldCR17 & 0x80)) {			/* CRT1 was off */
7901	  if(!(SiSBridgeIsInSlaveMode(pScrn))) {        /* Bridge is NOT in SlaveMode now -> do it */
7902	     doit = TRUE;
7903	  } else {
7904	     doitlater = TRUE;
7905	  }
7906       } else {						/* CRT1 was on -> do it now */
7907	  doit = TRUE;
7908       }
7909
7910       if(doit) {
7911	  outSISIDXREG(SISCR, 0x17, pSiS->oldCR17);
7912       }
7913       if(pSiS->VGAEngine == SIS_315_VGA) {
7914	  outSISIDXREG(SISCR, pSiS->myCR63, pSiS->oldCR63);
7915       }
7916
7917       outSISIDXREG(SISSR, 0x1f, pSiS->oldSR1F);
7918
7919       /* For 30xB/LV, restoring the registers does not
7920	* work. We "manually" set the old mode, instead.
7921	* The same applies for SiS730 machines with LVDS.
7922	* Finally, this behavior can be forced by setting
7923	* the option RestoreBySetMode.
7924	*/
7925	if( ( (pSiS->restorebyset) ||
7926	      (pSiS->VBFlags2 & VB2_30xBLV) ||
7927	      ((pSiS->ChipType == SIS_730) && (pSiS->VBFlags2 & VB2_LVDS)) )     &&
7928	    (pSiS->OldMode) ) {
7929
7930	   Bool changedmode = FALSE;
7931
7932	   xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
7933	         "Restoring by setting old mode 0x%02x\n", pSiS->OldMode);
7934
7935	   if(((pSiS->OldMode <= 0x13) || (!pSiS->sisfbfound)) && (pSiS->pVbe)) {
7936	      int vmode = SiSTranslateToVESA(pScrn, pSiS->OldMode);
7937	      if(vmode > 0) {
7938		 if(vmode > 0x13) vmode |= ((1 << 15) | (1 << 14));
7939		 if(VBESetVBEMode(pSiS->pVbe, vmode, NULL) == TRUE) {
7940		    SISSpecialRestore(pScrn);
7941		    SiS_GetSetModeID(pScrn,pSiS->OldMode);
7942		    vesasuccess = TRUE;
7943		 } else {
7944		    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
7945			"VBE failed to restore mode 0x%x\n", pSiS->OldMode);
7946		 }
7947	      } else {
7948		 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
7949		 	"Can't identify VESA mode number for mode 0x%x\n", pSiS->OldMode);
7950	      }
7951	   }
7952
7953	   if(vesasuccess == FALSE) {
7954
7955	      int backupscaler = pSiS->SiS_Pr->UsePanelScaler;
7956	      int backupcenter = pSiS->SiS_Pr->CenterScreen;
7957	      ULong backupspecialtiming = pSiS->SiS_Pr->SiS_CustomT;
7958	      int mymode = pSiS->OldMode;
7959
7960	      if((pSiS->VGAEngine == SIS_315_VGA)			&&
7961	         ((pSiS->ROM661New) || (pSiS->ChipFlags & SiSCF_IsXGI)) &&
7962		 (!pSiS->sisfbfound)) {
7963	         /* New SiS BIOS or XGI BIOS has set mode, therefore eventually translate number */
7964	         mymode = SiSTranslateToOldMode(mymode);
7965	      }
7966
7967 	      if((pSiS->VBFlags2 & VB2_30xBLV)) {
7968	        /* !!! REQUIRED for 630+301B-DH, otherwise the text modes
7969	         *     will not be restored correctly !!!
7970	         * !!! Do this ONLY for LCD; VGA2 will not be restored
7971	         *     correctly otherwise.
7972	         */
7973	         UChar temp;
7974	         inSISIDXREG(SISCR, 0x30, temp);
7975	         if(temp & 0x20) {
7976	            if(mymode == 0x03) {
7977		       mymode = 0x13;
7978		       changedmode = TRUE;
7979	            }
7980	         }
7981	      }
7982
7983	      pSiS->SiS_Pr->UseCustomMode = FALSE;
7984	      pSiS->SiS_Pr->CRT1UsesCustomMode = FALSE;
7985	      pSiS->SiS_Pr->CenterScreen = 0;
7986	      if(pSiS->sisfbfound) {
7987		 pSiS->SiS_Pr->UsePanelScaler = pSiS->sisfbscalelcd;
7988		 pSiS->SiS_Pr->SiS_CustomT = pSiS->sisfbspecialtiming;
7989	      } else {
7990		 pSiS->SiS_Pr->UsePanelScaler = -1;
7991		 /* Leave CustomT as it is */
7992	      }
7993	      SiS_SetEnableDstn(pSiS->SiS_Pr, FALSE);
7994	      SiS_SetEnableFstn(pSiS->SiS_Pr, FALSE);
7995	      if((pSiS->ChipType == SIS_550) && (pSiS->sisfbfound)) {
7996		 if(pSiS->sisfbxSTN) {
7997		    SiS_SetEnableDstn(pSiS->SiS_Pr, pSiS->sisfbDSTN);
7998		    SiS_SetEnableFstn(pSiS->SiS_Pr, pSiS->sisfbFSTN);
7999		 } else if(mymode == 0x5a || mymode == 0x5b) {
8000		    SiS_SetEnableFstn(pSiS->SiS_Pr, TRUE);
8001		 }
8002	      }
8003	      SiSSetMode(pSiS->SiS_Pr, pScrn, mymode, FALSE);
8004	      if(changedmode) {
8005		 outSISIDXREG(SISCR,0x34,0x03);
8006	      }
8007	      SISSpecialRestore(pScrn);
8008	      SiS_GetSetModeID(pScrn, pSiS->OldMode); /* NOT mymode! */
8009	      pSiS->SiS_Pr->UsePanelScaler = backupscaler;
8010	      pSiS->SiS_Pr->CenterScreen = backupcenter;
8011	      pSiS->SiS_Pr->SiS_CustomT = backupspecialtiming;
8012	      SiS_SiSFB_Lock(pScrn, FALSE);
8013	      SiSRestore_SiSFB_TVParms(pScrn);
8014	      SiS_SiSFB_Lock(pScrn, TRUE);
8015
8016	   }
8017
8018	   /* Restore CRT1 status */
8019	   if(pSiS->VGAEngine == SIS_315_VGA) {
8020              outSISIDXREG(SISCR, pSiS->myCR63, pSiS->oldCR63);
8021           }
8022           outSISIDXREG(SISSR, 0x1f, pSiS->oldSR1F);
8023
8024#ifdef SISVRAMQ
8025	   /* Restore queue mode registers on 315/330/340 series */
8026	   /* (This became necessary due to the switch to VRAM queue) */
8027	   SiSRestoreQueueMode(pSiS, sisReg);
8028#endif
8029
8030        } else {
8031
8032	   if(pSiS->VBFlags2 & VB2_VIDEOBRIDGE) {
8033	      /* If a video bridge is present, we need to restore
8034	       * non-extended (=standard VGA) SR and CR registers
8035	       * before restoring the extended ones and the bridge
8036	       * registers.
8037	       */
8038	      if(!(SiSBridgeIsInSlaveMode(pScrn))) {
8039                 SiSVGAProtect(pScrn, TRUE);
8040	         SiSVGARestore(pScrn, sisReg, SISVGA_SR_MODE);
8041              }
8042	   }
8043
8044           (*pSiS->SiSRestore)(pScrn, sisReg);
8045
8046        }
8047
8048	if(doitlater) {
8049           outSISIDXREG(SISCR, 0x17, pSiS->oldCR17);
8050	}
8051
8052
8053
8054	if((pSiS->VBFlags2 & VB2_VIDEOBRIDGE) && (SiSBridgeIsInSlaveMode(pScrn))) {
8055
8056	   /* IMPORTANT: The 30xLV does not handle well being disabled if in
8057	    * LCDA mode! In LCDA mode, the bridge is NOT in slave mode,
8058	    * so this is the only safe way: Disable the bridge ONLY if
8059	    * in Slave Mode, and don't bother if not.
8060	    */
8061
8062	   if(flags & SISVGA_SR_FONTS) {
8063              SiSRegInit(pSiS->SiS_Pr, pSiS->RelIO+0x30);
8064	      SiSSetLVDSetc(pSiS->SiS_Pr, 0);
8065	      SiS_GetVBType(pSiS->SiS_Pr);
8066	      SiS_DisableBridge(pSiS->SiS_Pr);
8067	      SiSVGAProtect(pScrn, TRUE);
8068	   }
8069
8070	   SiSVGARestore(pScrn, sisReg, flags);
8071
8072	   if(flags & SISVGA_SR_FONTS) {
8073	      SiSVGAProtect(pScrn, FALSE);
8074	      SiS_EnableBridge(pSiS->SiS_Pr);
8075	      andSISIDXREG(SISSR, 0x01, ~0x20);  /* Display on */
8076	   }
8077
8078	} else {
8079
8080	   SiSVGAProtect(pScrn, TRUE);
8081	   SiSVGARestore(pScrn, sisReg, flags);
8082           SiSVGAProtect(pScrn, FALSE);
8083
8084	}
8085
8086	SiSFixupSR11(pScrn);
8087
8088#ifdef TWDEBUG
8089	{
8090	  SISRegPtr pReg = &pSiS->ModeReg;
8091	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
8092		"REAL REGISTER CONTENTS AFTER RESTORE BY SETMODE:\n");
8093	  (*pSiS->SiSSave)(pScrn, pReg);
8094	}
8095#endif
8096
8097	sisRestoreExtRegisterLock(pSiS,sisReg->sisRegs3C4[0x05],sisReg->sisRegs3D4[0x80]);
8098
8099    } else {	/* All other chipsets */
8100
8101        SiSVGAProtect(pScrn, TRUE);
8102
8103#ifdef UNLOCK_ALWAYS
8104        sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
8105#endif
8106
8107        (*pSiS->SiSRestore)(pScrn, sisReg);
8108
8109        SiSVGAProtect(pScrn, TRUE);
8110
8111	SiSVGARestore(pScrn, sisReg, flags);
8112
8113	/* Restore TV. This is rather complicated, but if we don't do it,
8114	 * TV output will flicker terribly
8115	 */
8116        if((pSiS->Chipset == PCI_CHIP_SIS6326) && (pSiS->SiS6326Flags & SIS6326_HASTV)) {
8117	   if(sisReg->sis6326tv[0] & 0x04) {
8118	      UChar tmp;
8119	      int val;
8120
8121              orSISIDXREG(SISSR, 0x01, 0x20);
8122              tmp = SiS6326GetTVReg(pScrn,0x00);
8123              tmp &= ~0x04;
8124              while(!(inSISREG(SISINPSTAT) & 0x08));  /* Wait while NOT vb */
8125              SiS6326SetTVReg(pScrn,0x00,tmp);
8126              for(val=0; val < 2; val++) {
8127                 while(!(inSISREG(SISINPSTAT) & 0x08));  /* Wait while NOT vb */
8128                 while(inSISREG(SISINPSTAT) & 0x08);     /* wait while vb     */
8129              }
8130              SiS6326SetTVReg(pScrn, 0x00, sisReg->sis6326tv[0]);
8131              tmp = inSISREG(SISINPSTAT);
8132              outSISREG(SISAR, 0x20);
8133              tmp = inSISREG(SISINPSTAT);
8134              while(inSISREG(SISINPSTAT) & 0x01);
8135              while(!(inSISREG(SISINPSTAT) & 0x01));
8136              andSISIDXREG(SISSR, 0x01, ~0x20);
8137              for(val=0; val < 10; val++) {
8138                 while(!(inSISREG(SISINPSTAT) & 0x08));  /* Wait while NOT vb */
8139                 while(inSISREG(SISINPSTAT) & 0x08);     /* wait while vb     */
8140              }
8141              andSISIDXREG(SISSR, 0x01, ~0x20);
8142	   }
8143        }
8144
8145        sisRestoreExtRegisterLock(pSiS,sisReg->sisRegs3C4[5],sisReg->sisRegs3D4[0x80]);
8146
8147        SiSVGAProtect(pScrn, FALSE);
8148    }
8149}
8150
8151static void
8152SISVESARestore(ScrnInfoPtr pScrn)
8153{
8154   SISPtr pSiS = SISPTR(pScrn);
8155#ifdef SISVRAMQ
8156   SISRegPtr sisReg = &pSiS->SavedReg;
8157#endif
8158
8159   if(pSiS->UseVESA) {
8160      SISVESASaveRestore(pScrn, MODE_RESTORE);
8161#ifdef SISVRAMQ
8162      /* Restore queue mode registers on 315/330/340 series */
8163      /* (This became necessary due to the switch to VRAM queue) */
8164      SiSRestoreQueueMode(pSiS, sisReg);
8165#endif
8166   }
8167}
8168
8169/* Restore bridge config registers - to be called BEFORE VESARestore */
8170static void
8171SISBridgeRestore(ScrnInfoPtr pScrn)
8172{
8173    SISPtr pSiS = SISPTR(pScrn);
8174
8175#ifdef SISDUALHEAD
8176    /* We only restore for master head */
8177    if(pSiS->DualHeadMode && pSiS->SecondHead) return;
8178#endif
8179
8180    if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
8181	SiSRestoreBridge(pScrn, &pSiS->SavedReg);
8182    }
8183}
8184
8185/* Our BlockHandler */
8186static void
8187SISBlockHandler(int i, pointer blockData, pointer pTimeout, pointer pReadmask)
8188{
8189    ScreenPtr pScreen = screenInfo.screens[i];
8190    ScrnInfoPtr pScrn = xf86Screens[i];
8191    SISPtr pSiS = SISPTR(pScrn);
8192
8193    pScreen->BlockHandler = pSiS->BlockHandler;
8194    (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask);
8195    pScreen->BlockHandler = SISBlockHandler;
8196
8197#ifdef SISDUALHEAD
8198    if(pSiS->NeedCopyFastVidCpy) {
8199       SISEntPtr pSiSEnt = pSiS->entityPrivate;
8200       if(pSiSEnt->HaveFastVidCpy) {
8201	  pSiS->NeedCopyFastVidCpy = FALSE;
8202	  pSiS->SiSFastVidCopy = pSiSEnt->SiSFastVidCopy;
8203	  pSiS->SiSFastMemCopy = pSiSEnt->SiSFastMemCopy;
8204	  pSiS->SiSFastVidCopyFrom = pSiSEnt->SiSFastVidCopyFrom;
8205	  pSiS->SiSFastMemCopyFrom = pSiSEnt->SiSFastMemCopyFrom;
8206       }
8207    }
8208#endif
8209
8210    if(pSiS->VideoTimerCallback) {
8211       (*pSiS->VideoTimerCallback)(pScrn, currentTime.milliseconds);
8212    }
8213
8214#ifdef SIS_USE_XAA
8215    if(pSiS->RenderCallback) {
8216       (*pSiS->RenderCallback)(pScrn);
8217    }
8218#endif
8219#ifdef SIS_USE_EXA
8220    if(pSiS->ExaRenderCallback) {
8221       (*pSiS->ExaRenderCallback)(pScrn);
8222    }
8223#endif
8224}
8225
8226
8227
8228/* Do screen blanking; DPMS handling
8229 *
8230 * Mandatory; latter optional
8231 */
8232
8233static void
8234SiSHandleBackLight(SISPtr pSiS, Bool blon)
8235{
8236    UChar sr11mask = (pSiS->SiS_Pr->SiS_SensibleSR11) ? 0x03 : 0xf3;
8237
8238    if(pSiS->VBFlags2 & VB2_SISLVDSBRIDGE) {
8239
8240       if(!blon) {
8241	  SiS_SiS30xBLOff(pSiS->SiS_Pr);
8242       } else {
8243	  SiS_SiS30xBLOn(pSiS->SiS_Pr);
8244       }
8245
8246    } else if( ((pSiS->VGAEngine == SIS_300_VGA) &&
8247	        (pSiS->VBFlags2 & (VB2_LVDS | VB2_30xBDH))) ||
8248	       ((pSiS->VGAEngine == SIS_315_VGA) &&
8249	        ((pSiS->VBFlags2 & (VB2_LVDS | VB2_CHRONTEL)) == VB2_LVDS)) ) {
8250
8251       if(!blon) {
8252	  setSISIDXREG(SISSR, 0x11, sr11mask, 0x08);
8253       } else {
8254	  setSISIDXREG(SISSR, 0x11, sr11mask, 0x00);
8255       }
8256
8257    } else if((pSiS->VGAEngine == SIS_315_VGA) &&
8258	      (pSiS->VBFlags2 & VB2_CHRONTEL)) {
8259
8260       if(!blon) {
8261	  SiS_Chrontel701xBLOff(pSiS->SiS_Pr);
8262       } else {
8263	  SiS_Chrontel701xBLOn(pSiS->SiS_Pr);
8264       }
8265
8266    }
8267}
8268
8269static Bool
8270SISSaveScreen(ScreenPtr pScreen, int mode)
8271{
8272    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
8273    SISPtr pSiS;
8274    Bool IsUnblank = xf86IsUnblank(mode) ? TRUE : FALSE;
8275
8276    if((pScrn == NULL) || (!pScrn->vtSema)) return TRUE;
8277
8278    pSiS = SISPTR(pScrn);
8279
8280#ifdef UNLOCK_ALWAYS
8281    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
8282#endif
8283
8284    if(pSiS->VBFlags & (CRT2_LCD | CRT1_LCDA)) {
8285       SiSHandleBackLight(pSiS, IsUnblank);
8286    }
8287
8288    if(!SiSBridgeIsInSlaveMode(pScrn)) {
8289       return SiSVGASaveScreen(pScreen, mode);
8290    }
8291
8292    return TRUE;
8293}
8294
8295#ifdef SISDUALHEAD
8296/* SaveScreen for dual head mode */
8297static Bool
8298SISSaveScreenDH(ScreenPtr pScreen, int mode)
8299{
8300    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
8301    SISPtr pSiS;
8302    Bool IsUnblank = xf86IsUnblank(mode) ? TRUE : FALSE;
8303
8304    if((pScrn == NULL) || (!pScrn->vtSema)) return TRUE;
8305
8306    pSiS = SISPTR(pScrn);
8307
8308    if( (pSiS->SecondHead) &&
8309        ((!(pSiS->VBFlags & CRT1_LCDA)) || (pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE)) ) {
8310
8311       /* Slave head is always CRT1 */
8312       /* (No backlight handling on TMDS bridges) */
8313       return SiSVGASaveScreen(pScreen, mode);
8314
8315    } else {
8316
8317       /* Master head is always CRT2 */
8318       /* But we land here for LCDA, too (if bridge is SiS LVDS type) */
8319
8320       /* We can only blank LCD, not other CRT2 devices */
8321       if(pSiS->VBFlags & (CRT2_LCD|CRT1_LCDA)) {
8322
8323#ifdef UNLOCK_ALWAYS
8324	  sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
8325#endif
8326	  SiSHandleBackLight(pSiS, IsUnblank);
8327
8328       }
8329
8330    }
8331    return TRUE;
8332}
8333#endif
8334
8335static void
8336SISDisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode, int flags)
8337{
8338    SISPtr pSiS = SISPTR(pScrn);
8339    Bool   docrt1 = TRUE, docrt2 = TRUE, backlight = TRUE;
8340    UChar  sr1=0, cr17=0, cr63=0, pmreg=0, sr7=0;
8341    UChar  p1_13=0, p2_0=0, oldpmreg=0;
8342
8343    if(!pScrn->vtSema) return;
8344
8345    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 4,
8346          "SISDisplayPowerManagementSet(%d)\n", PowerManagementMode);
8347
8348#ifdef SISDUALHEAD
8349    if(pSiS->DualHeadMode) {
8350       if(pSiS->SecondHead) docrt2 = FALSE;
8351       else                 docrt1 = FALSE;
8352    }
8353#endif
8354
8355    /* FIXME: in old servers, DPMSSet was supposed to be called without open
8356     * the correct PCI bridges before access the hardware. Now we have this
8357     * hook wrapped by the vga arbiter which should do all the work, in
8358     * kernels that implement it. For this case we might not want this hack
8359     * bellow.
8360     */
8361    outSISIDXREG(SISSR,0x05,0x86);
8362    inSISIDXREG(SISSR,0x05,pmreg);
8363    if(pmreg != 0xa1) return;
8364
8365#ifdef UNLOCK_ALWAYS
8366    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
8367#endif
8368
8369    switch(PowerManagementMode) {
8370
8371       case DPMSModeOn:      /* HSync: On, VSync: On */
8372	  sr1   = 0x00;
8373	  cr17  = 0x80;
8374	  pmreg = 0x00;
8375	  cr63  = 0x00;
8376	  sr7   = 0x10;
8377	  p2_0  = 0x20;
8378	  p1_13 = 0x00;
8379	  backlight = TRUE;
8380	  break;
8381
8382       case DPMSModeSuspend: /* HSync: On, VSync: Off */
8383	  sr1   = 0x20;
8384	  cr17  = 0x80;
8385	  pmreg = 0x80;
8386	  cr63  = 0x40;
8387	  sr7   = 0x00;
8388	  p2_0  = 0x40;
8389	  p1_13 = 0x80;
8390	  backlight = FALSE;
8391	  break;
8392
8393       case DPMSModeStandby: /* HSync: Off, VSync: On */
8394	  sr1   = 0x20;
8395	  cr17  = 0x80;
8396	  pmreg = 0x40;
8397	  cr63  = 0x40;
8398	  sr7   = 0x00;
8399	  p2_0  = 0x80;
8400	  p1_13 = 0x40;
8401	  backlight = FALSE;
8402	  break;
8403
8404       case DPMSModeOff:     /* HSync: Off, VSync: Off */
8405	  sr1   = 0x20;
8406	  cr17  = 0x00;
8407	  pmreg = 0xc0;
8408	  cr63  = 0x40;
8409	  sr7   = 0x00;
8410	  p2_0  = 0xc0;
8411	  p1_13 = 0xc0;
8412	  backlight = FALSE;
8413	  break;
8414
8415       default:
8416	    return;
8417    }
8418
8419    oldpmreg = pmreg;
8420
8421    if((docrt2 && (pSiS->VBFlags & CRT2_LCD)) ||
8422       (docrt1 && (pSiS->VBFlags & CRT1_LCDA))) {
8423       SiSHandleBackLight(pSiS, backlight);
8424    }
8425
8426    if(docrt1) {
8427       switch(pSiS->VGAEngine) {
8428       case SIS_OLD_VGA:
8429       case SIS_530_VGA:
8430	    setSISIDXREG(SISSR, 0x01, ~0x20, sr1);    /* Set/Clear "Display On" bit */
8431	    inSISIDXREG(SISSR, 0x11, oldpmreg);
8432	    setSISIDXREG(SISCR, 0x17, 0x7f, cr17);
8433	    setSISIDXREG(SISSR, 0x11, 0x3f, pmreg);
8434	    break;
8435       case SIS_315_VGA:
8436	    if( (!pSiS->CRT1off) &&
8437	        ((!(pSiS->VBFlags & CRT1_LCDA)) || (pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE)) ) {
8438	       setSISIDXREG(SISCR, pSiS->myCR63, 0xbf, cr63);
8439	       setSISIDXREG(SISSR, 0x07, 0xef, sr7);
8440	    }
8441	    /* fall through */
8442       default:
8443	    if(!SiSBridgeIsInSlaveMode(pScrn)) {
8444	       setSISIDXREG(SISSR, 0x01, ~0x20, sr1);    /* Set/Clear "Display On" bit */
8445	    }
8446	    if((!(pSiS->VBFlags & CRT1_LCDA)) || (pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE)) {
8447	       inSISIDXREG(SISSR, 0x1f, oldpmreg);
8448	       if((!pSiS->CRT1off) && (!SiSBridgeIsInSlaveMode(pScrn))) {
8449		  setSISIDXREG(SISSR, 0x1f, 0x3f, pmreg);
8450	       }
8451	    }
8452       }
8453       oldpmreg &= 0xc0;
8454    }
8455
8456    if(docrt2) {
8457       if(pSiS->VBFlags & CRT2_LCD) {
8458          if((pSiS->VBFlags2 & VB2_SISBRIDGE) &&
8459	     (!(pSiS->VBFlags2 & VB2_30xBDH))) {
8460	     if(pSiS->VGAEngine == SIS_300_VGA) {
8461	        SiS_UnLockCRT2(pSiS->SiS_Pr);
8462	        setSISIDXREG(SISPART1, 0x13, 0x3f, p1_13);
8463	     }
8464	     if(pSiS->VBFlags2 & VB2_SISLVDSBRIDGE) p2_0 |= 0x20;
8465	     setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
8466	  }
8467       } else if(pSiS->VBFlags & (CRT2_VGA | CRT2_TV)) {
8468	  if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
8469	     setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
8470	  }
8471       }
8472    }
8473
8474    if( (docrt1) &&
8475        (pmreg != oldpmreg) &&
8476        ((!(pSiS->VBFlags & CRT1_LCDA)) || (pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE)) ) {
8477       outSISIDXREG(SISSR, 0x00, 0x01);    /* Synchronous Reset */
8478       usleep(10000);
8479       outSISIDXREG(SISSR, 0x00, 0x03);    /* End Reset */
8480    }
8481
8482}
8483
8484/* Mandatory
8485 * This gets called at the start of each server generation
8486 *
8487 * We use pScrn and not CurrentLayout here, because the
8488 * properties we use have not changed (displayWidth,
8489 * depth, bitsPerPixel)
8490 */
8491static Bool
8492SISScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
8493{
8494    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
8495    SISPtr pSiS = SISPTR(pScrn);
8496    VisualPtr visual;
8497    ULong OnScreenSize;
8498    int ret, height, width, displayWidth;
8499    UChar *FBStart;
8500#ifdef SISDUALHEAD
8501    SISEntPtr pSiSEnt = NULL;
8502#endif
8503
8504#ifdef SISDUALHEAD
8505    if((!pSiS->DualHeadMode) || (!pSiS->SecondHead)) {
8506#endif
8507       SiS_LoadInitVBE(pScrn);
8508#ifdef SISDUALHEAD
8509    }
8510#endif
8511
8512#ifdef SISDUALHEAD
8513    if(pSiS->DualHeadMode) {
8514       pSiSEnt = pSiS->entityPrivate;
8515       pSiSEnt->refCount++;
8516    }
8517#endif
8518
8519#ifdef SIS_PC_PLATFORM
8520    /* Map 64k VGA window for saving/restoring CGA fonts */
8521    SiS_MapVGAMem(pScrn);
8522#endif
8523
8524    /* Map the SiS memory and MMIO areas */
8525    if(!SISMapMem(pScrn)) {
8526       SISErrorLog(pScrn, "SiSMapMem() failed\n");
8527       return FALSE;
8528    }
8529
8530    SiS_SiSFB_Lock(pScrn, TRUE);
8531
8532#ifdef UNLOCK_ALWAYS
8533    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
8534#endif
8535
8536    /* Enable TurboQueue so that SISSave() saves it in enabled
8537     * state. If we don't do this, X will hang after a restart!
8538     * (Happens for some unknown reason only when using VESA
8539     * for mode switching; assumingly a BIOS issue.)
8540     * This is done on 300 and 315 series only.
8541     */
8542    if(pSiS->UseVESA) {
8543#ifdef SISVRAMQ
8544       if(pSiS->VGAEngine != SIS_315_VGA)
8545#endif
8546          SiSEnableTurboQueue(pScrn);
8547    }
8548
8549    /* Save the current state */
8550    SISSave(pScrn);
8551
8552    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
8553
8554       if(!pSiS->OldMode) {
8555
8556          /* Try to find out current (=old) mode number
8557	   * (Do this only if not sisfb has told us its mode yet)
8558	   */
8559
8560	  /* Read 0:449 which the BIOS sets to the current mode number
8561	   * Unfortunately, this not reliable since the int10 emulation
8562	   * does not change this. So if we call the VBE later, this
8563	   * byte won't be touched (which is why we set this manually
8564	   * then).
8565	   */
8566          UChar myoldmode = SiS_GetSetModeID(pScrn, 0xFF);
8567	  UChar cr30, cr31;
8568
8569          /* Read CR34 which the BIOS sets to the current mode number for CRT2
8570	   * This is - of course - not reliable if the machine has no video
8571	   * bridge...
8572	   */
8573          inSISIDXREG(SISCR, 0x34, pSiS->OldMode);
8574	  inSISIDXREG(SISCR, 0x30, cr30);
8575	  inSISIDXREG(SISCR, 0x31, cr31);
8576
8577	  /* What if CR34 is different from the BIOS scratch byte? */
8578	  if(pSiS->OldMode != myoldmode) {
8579	     /* If no bridge output is active, trust the BIOS scratch byte */
8580	     if( (!(pSiS->VBFlags2 & VB2_VIDEOBRIDGE)) ||
8581	         (pSiS->OldMode == 0)                  ||
8582	         (!cr31 && !cr30)                      ||
8583		 (cr31 & 0x20) ) {
8584		pSiS->OldMode = myoldmode;
8585 	     }
8586	     /* ..else trust CR34 */
8587	  }
8588
8589	  /* Newer 650 BIOSes set CR34 to 0xff if the mode has been
8590	   * "patched", for instance for 80x50 text mode. (That mode
8591	   * has no number of its own, it's 0x03 like 80x25). In this
8592	   * case, we trust the BIOS scratch byte (provided that any
8593	   * of these two is valid).
8594	   */
8595	  if(pSiS->OldMode > 0x7f) {
8596	     pSiS->OldMode = myoldmode;
8597	  }
8598       }
8599#ifdef SISDUALHEAD
8600       if(pSiS->DualHeadMode) {
8601          if(!pSiS->SecondHead) pSiSEnt->OldMode = pSiS->OldMode;
8602          else                  pSiS->OldMode = pSiSEnt->OldMode;
8603       }
8604#endif
8605    }
8606
8607    /* RandR resets screen mode and size in CloseScreen(), hence
8608     * we need to adapt our VBFlags to the initial state if the
8609     * current mode has changed since closescreen() (or Screeninit()
8610     * for the first instance)
8611     */
8612    if(pScrn->currentMode != pSiS->currentModeLast) {
8613       pSiS->VBFlags = pSiS->VBFlags_backup = pSiS->VBFlagsInit;
8614    }
8615
8616    /* Copy our detected monitor gammas, part 2. Note that device redetection
8617     * is not supported in DHM, so there is no need to do that anytime later.
8618     */
8619#ifdef SISDUALHEAD
8620    if(pSiS->DualHeadMode) {
8621       if(!pSiS->SecondHead) {
8622          /* CRT2 */
8623	  pSiS->CRT1VGAMonitorGamma = pSiSEnt->CRT1VGAMonitorGamma;
8624       } else {
8625          /* CRT1 */
8626	  pSiS->CRT2VGAMonitorGamma = pSiSEnt->CRT2VGAMonitorGamma;
8627       }
8628       if(!pSiS->CRT2LCDMonitorGamma) pSiS->CRT2LCDMonitorGamma = pSiSEnt->CRT2LCDMonitorGamma;
8629    }
8630#endif
8631
8632    /* Initialize the first mode */
8633    if(!SISModeInit(pScrn, pScrn->currentMode)) {
8634       SISErrorLog(pScrn, "SiSModeInit() failed\n");
8635       return FALSE;
8636    }
8637
8638    /* Darken the screen for aesthetic reasons */
8639    /* Not using Dual Head variant on purpose; we darken
8640     * the screen for both displays, and un-darken
8641     * it when the second head is finished
8642     */
8643    SISSaveScreen(pScreen, SCREEN_SAVER_ON);
8644
8645    /* Set the viewport */
8646    SISAdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
8647
8648    /* Reset visual list. */
8649    miClearVisualTypes();
8650
8651    /* Setup the visuals we support. */
8652
8653    /*
8654     * For bpp > 8, the default visuals are not acceptable because we only
8655     * support TrueColor and not DirectColor.
8656     */
8657    if(!miSetVisualTypes(pScrn->depth,
8658			 (pScrn->bitsPerPixel > 8) ?
8659				TrueColorMask : miGetDefaultVisualMask(pScrn->depth),
8660			 pScrn->rgbBits, pScrn->defaultVisual)) {
8661       SISSaveScreen(pScreen, SCREEN_SAVER_OFF);
8662       SISErrorLog(pScrn, "miSetVisualTypes() failed (bpp %d)\n",
8663			pScrn->bitsPerPixel);
8664       return FALSE;
8665    }
8666
8667    width = pScrn->virtualX;
8668    height = pScrn->virtualY;
8669    displayWidth = pScrn->displayWidth;
8670
8671    if(pSiS->Rotate) {
8672       height = pScrn->virtualX;
8673       width = pScrn->virtualY;
8674    }
8675
8676    if(pSiS->ShadowFB) {
8677       pSiS->ShadowPitch = BitmapBytePad(pScrn->bitsPerPixel * width);
8678       pSiS->ShadowPtr = xalloc(pSiS->ShadowPitch * height);
8679       displayWidth = pSiS->ShadowPitch / (pScrn->bitsPerPixel >> 3);
8680       FBStart = pSiS->ShadowPtr;
8681    } else {
8682       pSiS->ShadowPtr = NULL;
8683       FBStart = pSiS->FbBase;
8684    }
8685
8686    if(!miSetPixmapDepths()) {
8687       SISSaveScreen(pScreen, SCREEN_SAVER_OFF);
8688       SISErrorLog(pScrn, "miSetPixmapDepths() failed\n");
8689       return FALSE;
8690    }
8691
8692    /* Point cmdQueuePtr to pSiSEnt for shared usage
8693     * (same technique is then eventually used in DRIScreeninit)
8694     * For 315/330 series, this is done in EnableTurboQueue
8695     * which has already been called during ModeInit().
8696     */
8697#ifdef SISDUALHEAD
8698    if(pSiS->SecondHead)
8699       pSiS->cmdQueueLenPtr = &(SISPTR(pSiSEnt->pScrn_1)->cmdQueueLen);
8700    else
8701#endif
8702       pSiS->cmdQueueLenPtr = &(pSiS->cmdQueueLen);
8703
8704    pSiS->cmdQueueLen = 0; /* Force an EngineIdle() at start */
8705
8706#ifdef XF86DRI
8707    if(pSiS->loadDRI) {
8708#ifdef SISDUALHEAD
8709       /* No DRI in dual head mode */
8710       if(pSiS->DualHeadMode) {
8711	  pSiS->directRenderingEnabled = FALSE;
8712	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
8713		"DRI not supported in Dual Head mode\n");
8714       } else
8715#endif
8716	      if(pSiS->VGAEngine != SIS_315_VGA) {
8717	  /* Force the initialization of the context */
8718	  pSiS->directRenderingEnabled = SISDRIScreenInit(pScreen);
8719       } else {
8720	  xf86DrvMsg(pScrn->scrnIndex, X_NOT_IMPLEMENTED,
8721		"DRI not supported on this chipset\n");
8722	  pSiS->directRenderingEnabled = FALSE;
8723       }
8724    }
8725#endif
8726
8727    /* Call the framebuffer layer's ScreenInit function and fill in other
8728     * pScreen fields.
8729     */
8730    switch(pScrn->bitsPerPixel) {
8731       case 24:
8732	  if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
8733	     ret = FALSE;
8734	     break;
8735	  }
8736	  /* fall through */
8737       case 8:
8738       case 16:
8739       case 32:
8740	  ret = fbScreenInit(pScreen, FBStart, width,
8741			height, pScrn->xDpi, pScrn->yDpi,
8742			displayWidth, pScrn->bitsPerPixel);
8743	  break;
8744       default:
8745	  ret = FALSE;
8746	  break;
8747    }
8748    if(!ret) {
8749       SISErrorLog(pScrn, "Unsupported bpp (%d) or fbScreenInit() failed\n",
8750			pScrn->bitsPerPixel);
8751       SISSaveScreen(pScreen, SCREEN_SAVER_OFF);
8752       return FALSE;
8753    }
8754
8755    /* Fixup RGB ordering */
8756    if(pScrn->bitsPerPixel > 8) {
8757       visual = pScreen->visuals + pScreen->numVisuals;
8758       while (--visual >= pScreen->visuals) {
8759          if((visual->class | DynamicClass) == DirectColor) {
8760             visual->offsetRed = pScrn->offset.red;
8761             visual->offsetGreen = pScrn->offset.green;
8762             visual->offsetBlue = pScrn->offset.blue;
8763             visual->redMask = pScrn->mask.red;
8764             visual->greenMask = pScrn->mask.green;
8765             visual->blueMask = pScrn->mask.blue;
8766          }
8767       }
8768    }
8769
8770    /* Initialize RENDER extension (must be after RGB ordering fixed) */
8771    fbPictureInit(pScreen, 0, 0);
8772
8773    /* Hardware cursor needs to wrap this layer */
8774    if(!pSiS->ShadowFB) SISDGAInit(pScreen);
8775
8776    xf86SetBlackWhitePixels(pScreen);
8777
8778    /* Initialize the accelerators */
8779    switch(pSiS->VGAEngine) {
8780    case SIS_530_VGA:
8781    case SIS_300_VGA:
8782       SiS300AccelInit(pScreen);
8783       break;
8784    case SIS_315_VGA:
8785       SiS315AccelInit(pScreen);
8786       break;
8787    default:
8788       SiSAccelInit(pScreen);
8789    }
8790
8791#ifdef TWDEBUG
8792    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CPUFlags %x\n", pSiS->CPUFlags);
8793#endif
8794
8795    /* Benchmark memcpy() methods (needs FB manager initialized) */
8796    /* Dual head: Do this AFTER the mode for CRT1 has been set */
8797    pSiS->NeedCopyFastVidCpy = FALSE;
8798    if(!pSiS->SiSFastVidCopyDone) {
8799#ifdef SISDUALHEAD
8800       if(pSiS->DualHeadMode) {
8801	  if(pSiS->SecondHead) {
8802	     pSiSEnt->SiSFastVidCopy = SiSVidCopyInit(pScreen, &pSiSEnt->SiSFastMemCopy, FALSE);
8803	     pSiSEnt->SiSFastVidCopyFrom = SiSVidCopyGetDefault();
8804	     pSiSEnt->SiSFastMemCopyFrom = SiSVidCopyGetDefault();
8805#ifdef SIS_USE_EXA
8806	     if(pSiS->useEXA) {
8807	        pSiSEnt->SiSFastVidCopyFrom = SiSVidCopyInit(pScreen, &pSiSEnt->SiSFastMemCopyFrom, TRUE);
8808	     }
8809#endif /* EXA */
8810	     pSiSEnt->HaveFastVidCpy = TRUE;
8811	     pSiS->SiSFastVidCopy = pSiSEnt->SiSFastVidCopy;
8812	     pSiS->SiSFastMemCopy = pSiSEnt->SiSFastMemCopy;
8813	     pSiS->SiSFastVidCopyFrom = pSiSEnt->SiSFastVidCopyFrom;
8814	     pSiS->SiSFastMemCopyFrom = pSiSEnt->SiSFastMemCopyFrom;
8815	  } else {
8816	     pSiS->NeedCopyFastVidCpy = TRUE;
8817	  }
8818       } else {
8819#endif
8820	  pSiS->SiSFastVidCopy = SiSVidCopyInit(pScreen, &pSiS->SiSFastMemCopy, FALSE);
8821	  pSiS->SiSFastVidCopyFrom = SiSVidCopyGetDefault();
8822	  pSiS->SiSFastMemCopyFrom = SiSVidCopyGetDefault();
8823#ifdef SIS_USE_EXA
8824	  if(pSiS->useEXA) {
8825	     pSiS->SiSFastVidCopyFrom = SiSVidCopyInit(pScreen, &pSiS->SiSFastMemCopyFrom, TRUE);
8826	  }
8827#endif /* EXA */
8828#ifdef SISDUALHEAD
8829       }
8830#endif
8831    }
8832    pSiS->SiSFastVidCopyDone = TRUE;
8833
8834    miInitializeBackingStore(pScreen);
8835    xf86SetBackingStore(pScreen);
8836    xf86SetSilkenMouse(pScreen);
8837
8838    /* Initialise cursor functions */
8839    miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
8840
8841    if(pSiS->HWCursor) {
8842       SiSHWCursorInit(pScreen);
8843    }
8844
8845#ifdef SISDUALHEAD
8846    if(!pSiS->DualHeadMode) {
8847#endif
8848       if((pSiS->VBFlags2 & VB2_SISBRIDGE) && (pScrn->depth > 8)) {
8849
8850	  pSiS->CRT2ColNum = 1 << pScrn->rgbBits;
8851
8852	  if((pSiS->crt2gcolortable = xalloc(pSiS->CRT2ColNum * 2 * sizeof(LOCO)))) {
8853	     pSiS->crt2colors = &pSiS->crt2gcolortable[pSiS->CRT2ColNum];
8854	     if((pSiS->crt2cindices = xalloc(256 * sizeof(int)))) {
8855		int i = pSiS->CRT2ColNum;
8856		SISCalculateGammaRampCRT2(pScrn);
8857		while(i--) pSiS->crt2cindices[i] = i;
8858	     } else {
8859		xfree(pSiS->crt2gcolortable);
8860		pSiS->crt2gcolortable = NULL;
8861		pSiS->CRT2SepGamma = FALSE;
8862	     }
8863	  } else {
8864	     pSiS->CRT2SepGamma = FALSE;
8865	  }
8866
8867	  if(!pSiS->crt2cindices) {
8868	     xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
8869	  	"Failed to allocate cmap for CRT2, separate gamma correction disabled\n");
8870	  }
8871
8872       }
8873#ifdef SISDUALHEAD
8874    } else pSiS->CRT2SepGamma = FALSE;
8875#endif
8876
8877    /* Initialise default colormap */
8878    if(!miCreateDefColormap(pScreen)) {
8879       SISSaveScreen(pScreen, SCREEN_SAVER_OFF);
8880       SISErrorLog(pScrn, "miCreateDefColormap() failed\n");
8881       return FALSE;
8882    }
8883
8884    if(!xf86HandleColormaps(pScreen, 256, (pScrn->depth == 8) ? 8 : pScrn->rgbBits,
8885                    SISLoadPalette, NULL,
8886                    CMAP_PALETTED_TRUECOLOR | CMAP_RELOAD_ON_MODE_SWITCH)) {
8887       SISSaveScreen(pScreen, SCREEN_SAVER_OFF);
8888       SISErrorLog(pScrn, "xf86HandleColormaps() failed\n");
8889       return FALSE;
8890    }
8891
8892    /* Recalculate our gamma ramp for brightness feature */
8893#ifdef SISGAMMARAMP
8894    if((pSiS->GammaBriR != 1000) ||
8895       (pSiS->GammaBriB != 1000) ||
8896       (pSiS->GammaBriG != 1000) ||
8897       (pSiS->NewGammaBriR != 0.0) ||
8898       (pSiS->NewGammaBriG != 0.0) ||
8899       (pSiS->NewGammaBriB != 0.0) ||
8900       (pSiS->NewGammaConR != 0.0) ||
8901       (pSiS->NewGammaConG != 0.0) ||
8902       (pSiS->NewGammaConB != 0.0)) {
8903       SISCalculateGammaRamp(pScreen, pScrn);
8904    }
8905#endif
8906
8907    /* Initialize Shadow framebuffer and screen rotation/reflection */
8908    if(pSiS->ShadowFB) {
8909       RefreshAreaFuncPtr refreshArea = SISRefreshArea;
8910
8911       if(pSiS->Rotate) {
8912	  if(!pSiS->PointerMoved) pSiS->PointerMoved = pScrn->PointerMoved;
8913	  pScrn->PointerMoved = SISPointerMoved;
8914	  switch(pScrn->bitsPerPixel) {
8915	     case 8:  refreshArea = SISRefreshArea8;  break;
8916	     case 16: refreshArea = SISRefreshArea16; break;
8917	     case 24: refreshArea = SISRefreshArea24; break;
8918	     case 32: refreshArea = SISRefreshArea32; break;
8919	  }
8920#if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4,3,0,0,0)
8921	  xf86DisableRandR();
8922	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
8923		"Driver rotation enabled, disabling RandR\n");
8924#endif
8925       } else if(pSiS->Reflect) {
8926          switch(pScrn->bitsPerPixel) {
8927	  case 8:
8928	  case 16:
8929	  case 32:
8930             if(!pSiS->PointerMoved) pSiS->PointerMoved = pScrn->PointerMoved;
8931	     pScrn->PointerMoved = SISPointerMovedReflect;
8932	     refreshArea = SISRefreshAreaReflect;
8933#if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4,3,0,0,0)
8934	     xf86DisableRandR();
8935	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
8936		  "Driver reflection enabled, disabling RandR\n");
8937#endif
8938	     break;
8939	  default:
8940	     xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
8941	     	  "Reflection not supported at this framebuffer depth\n");
8942	  }
8943       }
8944
8945       ShadowFBInit(pScreen, refreshArea);
8946    }
8947
8948    xf86DPMSInit(pScreen, (DPMSSetProcPtr)SISDisplayPowerManagementSet, 0);
8949
8950    /* Init memPhysBase and fbOffset in pScrn */
8951    pScrn->memPhysBase = pSiS->FbAddress;
8952    pScrn->fbOffset = 0;
8953
8954    /* Initialize Xv */
8955    pSiS->ResetXv = pSiS->ResetXvGamma = pSiS->ResetXvDisplay = NULL;
8956#if (XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4,3,99,0,0)) || (defined(XvExtension))
8957    if((!pSiS->NoXvideo) && (!(pSiS->SiS_SD2_Flags & SiS_SD2_NOOVERLAY))) {
8958
8959       if((pSiS->VGAEngine == SIS_300_VGA) ||
8960	  (pSiS->VGAEngine == SIS_315_VGA)) {
8961
8962	  const char *using = "Using SiS300/315/330/340 series HW Xv";
8963
8964#ifdef SISDUALHEAD
8965	  if(pSiS->DualHeadMode) {
8966	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
8967		    "%s on CRT%d\n", using, (pSiS->SecondHead ? 1 : 2));
8968	     if(!pSiS->hasTwoOverlays) {
8969		if( (pSiS->XvOnCRT2 && pSiS->SecondHead) ||
8970		    (!pSiS->XvOnCRT2 && !pSiS->SecondHead) ) {
8971		   xf86DrvMsg(pScrn->scrnIndex, X_INFO,
8972			   "However, video overlay will by default only be visible on CRT%d\n",
8973			   pSiS->XvOnCRT2 ? 2 : 1);
8974		}
8975	     }
8976	  } else {
8977#endif
8978	     if(pSiS->hasTwoOverlays) {
8979		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s\n", using);
8980	     } else {
8981		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s by default on CRT%d\n",
8982			using, (pSiS->XvOnCRT2 ? 2 : 1));
8983	     }
8984#ifdef SISDUALHEAD
8985	  }
8986#endif
8987
8988	  SISInitVideo(pScreen);
8989
8990	  if(pSiS->blitadaptor) {
8991	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
8992		     "Default Xv adaptor is Video %s\n",
8993		     pSiS->XvDefAdaptorBlit ? "Blitter" : "Overlay");
8994	  }
8995
8996       } else if(pSiS->Chipset == PCI_CHIP_SIS530  ||
8997		 pSiS->Chipset == PCI_CHIP_SIS6326 ||
8998		 pSiS->Chipset == PCI_CHIP_SIS5597) {
8999
9000	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
9001		        "Using SiS5597/5598/6326/530/620 HW Xv\n" );
9002
9003	  SIS6326InitVideo(pScreen);
9004
9005       } else { /* generic Xv */
9006
9007	  XF86VideoAdaptorPtr *ptr;
9008	  int n = xf86XVListGenericAdaptors(pScrn, &ptr);
9009
9010	  if(n) {
9011	     xf86XVScreenInit(pScreen, ptr, n);
9012	     xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using generic Xv\n" );
9013          }
9014
9015       }
9016    }
9017#endif
9018
9019#ifdef XF86DRI
9020    if(pSiS->loadDRI) {
9021       if(pSiS->directRenderingEnabled) {
9022          /* Now that mi, drm and others have done their thing,
9023           * complete the DRI setup.
9024           */
9025          pSiS->directRenderingEnabled = SISDRIFinishScreenInit(pScreen);
9026       }
9027       xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Direct rendering %s\n",
9028		pSiS->directRenderingEnabled ? "enabled" : "disabled");
9029       /* TODO */
9030       /* if(pSiS->directRenderingEnabled) SISSetLFBConfig(pSiS); */
9031    }
9032#endif
9033
9034    /* Wrap some funcs, initialize pseudo-Xinerama and setup remaining SD flags */
9035
9036    pSiS->SiS_SD_Flags &= ~(SiS_SD_PSEUDOXINERAMA);
9037#ifdef SISMERGED
9038    if(pSiS->MergedFB) {
9039       pSiS->PointerMoved = pScrn->PointerMoved;
9040       pScrn->PointerMoved = SISMergedPointerMoved;
9041       pSiS->Rotate = 0;
9042       pSiS->Reflect = 0;
9043       pSiS->ShadowFB = FALSE;
9044#if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4,3,0,0,0)
9045       if(pSiS->CRT1XOffs || pSiS->CRT1YOffs || pSiS->CRT2XOffs || pSiS->CRT2YOffs) {
9046	  xf86DisableRandR();
9047	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
9048		"MergedFB: CRT2Position offset used, disabling RandR\n");
9049       }
9050#endif
9051#ifdef SISXINERAMA
9052       if(pSiS->UseSiSXinerama) {
9053	  SiSnoPanoramiXExtension = FALSE;
9054	  SiSXineramaExtensionInit(pScrn);
9055	  if(!SiSnoPanoramiXExtension) {
9056	     pSiS->SiS_SD_Flags |= SiS_SD_PSEUDOXINERAMA;
9057	     if(pSiS->HaveNonRect) {
9058		/* Reset the viewport (now eventually non-recangular) */
9059		SISAdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
9060	     }
9061	  }
9062       } else {
9063	  pSiS->MouseRestrictions = FALSE;
9064       }
9065#endif
9066    }
9067#endif
9068
9069    /* Wrap CloseScreen and set up SaveScreen */
9070    pSiS->CloseScreen = pScreen->CloseScreen;
9071    pScreen->CloseScreen = SISCloseScreen;
9072#ifdef SISDUALHEAD
9073    if(pSiS->DualHeadMode)
9074       pScreen->SaveScreen = SISSaveScreenDH;
9075    else
9076#endif
9077       pScreen->SaveScreen = SISSaveScreen;
9078
9079    /* Install BlockHandler */
9080    pSiS->BlockHandler = pScreen->BlockHandler;
9081    pScreen->BlockHandler = SISBlockHandler;
9082
9083    /* Report any unused options (only for the first generation) */
9084    if(serverGeneration == 1) {
9085       xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
9086    }
9087
9088    /* Clear frame buffer */
9089    /* For CRT2, we don't do that at this point in dual head
9090     * mode since the mode isn't switched at this time (it will
9091     * be reset when setting the CRT1 mode). Hence, we just
9092     * save the necessary data and clear the screen when
9093     * going through this for CRT1.
9094     */
9095
9096    OnScreenSize = pScrn->displayWidth * pScrn->currentMode->VDisplay
9097                               * (pScrn->bitsPerPixel >> 3);
9098
9099    /* Turn on the screen now */
9100    /* We do this in dual head mode after second head is finished */
9101#ifdef SISDUALHEAD
9102    if(pSiS->DualHeadMode) {
9103       if(pSiS->SecondHead) {
9104	  sisclearvram(pSiS->FbBase, OnScreenSize);
9105	  sisclearvram(pSiSEnt->FbBase1, pSiSEnt->OnScreenSize1);
9106	  SISSaveScreen(pScreen, SCREEN_SAVER_OFF);
9107       } else {
9108	  pSiSEnt->FbBase1 = pSiS->FbBase;
9109	  pSiSEnt->OnScreenSize1 = OnScreenSize;
9110       }
9111    } else {
9112#endif
9113       SISSaveScreen(pScreen, SCREEN_SAVER_OFF);
9114       sisclearvram(pSiS->FbBase, OnScreenSize);
9115#ifdef SISDUALHEAD
9116    }
9117#endif
9118
9119    pSiS->SiS_SD_Flags &= ~SiS_SD_SUPPORTSGRCRT2;
9120#ifdef SISDUALHEAD
9121    if(!pSiS->DualHeadMode) {
9122#endif
9123       if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
9124          if((pSiS->crt2cindices) && (pSiS->crt2gcolortable)) {
9125             pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTSGRCRT2;
9126	  }
9127       }
9128#ifdef SISDUALHEAD
9129    }
9130#endif
9131
9132    pSiS->SiS_SD_Flags &= ~SiS_SD_ISDEPTH8;
9133    if(pSiS->CurrentLayout.bitsPerPixel == 8) {
9134       pSiS->SiS_SD_Flags |= SiS_SD_ISDEPTH8;
9135       pSiS->SiS_SD_Flags &= ~SiS_SD_SUPPORTXVGAMMA1;
9136       pSiS->SiS_SD_Flags &= ~SiS_SD_SUPPORTSGRCRT2;
9137    }
9138
9139#ifdef SISGAMMARAMP
9140    pSiS->SiS_SD_Flags |= SiS_SD_CANSETGAMMA;
9141#else
9142    pSiS->SiS_SD_Flags &= ~SiS_SD_CANSETGAMMA;
9143#endif
9144
9145    SiSCtrlExtInit(pScrn);
9146
9147    return TRUE;
9148}
9149
9150/* Usually mandatory */
9151Bool
9152SISSwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
9153{
9154    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
9155    SISPtr pSiS = SISPTR(pScrn);
9156
9157    if(!pSiS->skipswitchcheck) {
9158       if(SISValidMode(scrnIndex, mode, TRUE, flags) != MODE_OK) {
9159          return FALSE;
9160       }
9161    }
9162
9163    (*pSiS->SyncAccel)(pScrn);
9164
9165    if(!(SISModeInit(xf86Screens[scrnIndex], mode))) return FALSE;
9166
9167    /* Since RandR (indirectly) uses SwitchMode(), we need to
9168     * update our Xinerama info here, too, in case of resizing
9169     */
9170#ifdef SISMERGED
9171#ifdef SISXINERAMA
9172    if(pSiS->MergedFB) {
9173       SiSUpdateXineramaScreenInfo(pScrn);
9174    }
9175#endif
9176#endif
9177    return TRUE;
9178}
9179
9180static void
9181SISSetStartAddressCRT1(SISPtr pSiS, ULong base)
9182{
9183    UChar cr11backup;
9184
9185    inSISIDXREG(SISCR,  0x11, cr11backup);  /* Unlock CRTC registers */
9186    andSISIDXREG(SISCR, 0x11, 0x7F);
9187    outSISIDXREG(SISCR, 0x0D, base & 0xFF);
9188    outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF);
9189    outSISIDXREG(SISSR, 0x0D, (base >> 16) & 0xFF);
9190    if(pSiS->VGAEngine == SIS_315_VGA) {
9191       setSISIDXREG(SISSR, 0x37, 0xFE, (base >> 24) & 0x01);
9192    }
9193    /* Eventually lock CRTC registers */
9194    setSISIDXREG(SISCR, 0x11, 0x7F,(cr11backup & 0x80));
9195}
9196
9197static void
9198SISSetStartAddressCRT2(SISPtr pSiS, ULong base)
9199{
9200    SiS_UnLockCRT2(pSiS->SiS_Pr);
9201    outSISIDXREG(SISPART1, 0x06, GETVAR8(base));
9202    outSISIDXREG(SISPART1, 0x05, GETBITS(base, 15:8));
9203    outSISIDXREG(SISPART1, 0x04, GETBITS(base, 23:16));
9204    if(pSiS->VGAEngine == SIS_315_VGA) {
9205       setSISIDXREG(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7);
9206    }
9207    SiS_LockCRT2(pSiS->SiS_Pr);
9208}
9209
9210#ifdef SISMERGED
9211static Bool
9212InRegion(int x, int y, region r)
9213{
9214    return (r.x0 <= x) && (x <= r.x1) && (r.y0 <= y) && (y <= r.y1);
9215}
9216
9217static void
9218SISAdjustFrameHW_CRT1(ScrnInfoPtr pScrn, int x, int y)
9219{
9220    SISPtr pSiS = SISPTR(pScrn);
9221    ULong base;
9222
9223    base = y * pSiS->CurrentLayout.displayWidth + x;
9224    switch(pSiS->CurrentLayout.bitsPerPixel) {
9225       case 16:  base >>= 1; 	break;
9226       case 32:  		break;
9227       default:  base >>= 2;
9228    }
9229    base += (pSiS->dhmOffset/4);
9230    SISSetStartAddressCRT1(pSiS, base);
9231}
9232
9233static void
9234SISAdjustFrameHW_CRT2(ScrnInfoPtr pScrn, int x, int y)
9235{
9236    SISPtr pSiS = SISPTR(pScrn);
9237    ULong base;
9238
9239    base = y * pSiS->CurrentLayout.displayWidth + x;
9240    switch(pSiS->CurrentLayout.bitsPerPixel) {
9241       case 16:  base >>= 1; 	break;
9242       case 32:  		break;
9243       default:  base >>= 2;
9244    }
9245    base += (pSiS->dhmOffset/4);
9246    SISSetStartAddressCRT2(pSiS, base);
9247}
9248
9249static void
9250SISMergedPointerMoved(int scrnIndex, int x, int y)
9251{
9252  ScrnInfoPtr	pScrn1 = xf86Screens[scrnIndex];
9253  SISPtr	pSiS = SISPTR(pScrn1);
9254  ScrnInfoPtr	pScrn2 = pSiS->CRT2pScrn;
9255  region	out, in1, in2, f2, f1;
9256  int		deltax, deltay;
9257  int		temp1, temp2;
9258  int		old1x0, old1y0, old2x0, old2y0;
9259  int		CRT1XOffs = 0, CRT1YOffs = 0, CRT2XOffs = 0, CRT2YOffs = 0;
9260  int		HVirt = pScrn1->virtualX;
9261  int		VVirt = pScrn1->virtualY;
9262  int		sigstate;
9263  Bool		doit = FALSE, HaveNonRect = FALSE, HaveOffsRegions = FALSE;
9264  SiSScrn2Rel   srel = ((SiSMergedDisplayModePtr)pSiS->CurrentLayout.mode->Private)->CRT2Position;
9265
9266  if(pSiS->DGAactive) {
9267     return;
9268     /* DGA: There is no cursor and no panning while DGA is active. */
9269     /* If it were, we would need to do: */
9270     /* HVirt = pSiS->CurrentLayout.displayWidth;
9271        VVirt = pSiS->CurrentLayout.displayHeight;
9272        BOUND(x, pSiS->CurrentLayout.DGAViewportX, HVirt);
9273        BOUND(y, pSiS->CurrentLayout.DGAViewportY, VVirt); */
9274  } else {
9275     CRT1XOffs = pSiS->CRT1XOffs;
9276     CRT1YOffs = pSiS->CRT1YOffs;
9277     CRT2XOffs = pSiS->CRT2XOffs;
9278     CRT2YOffs = pSiS->CRT2YOffs;
9279     HaveNonRect = pSiS->HaveNonRect;
9280     HaveOffsRegions = pSiS->HaveOffsRegions;
9281  }
9282
9283  /* Check if the pointer is inside our dead areas */
9284  if((pSiS->MouseRestrictions) && (srel != sisClone) && !SiSnoPanoramiXExtension) {
9285     if(HaveNonRect) {
9286	if(InRegion(x, y, pSiS->NonRectDead)) {
9287	   switch(srel) {
9288	   case sisLeftOf:
9289	   case sisRightOf: y = pSiS->NonRectDead.y0 - 1;
9290			    doit = TRUE;
9291			    break;
9292	   case sisAbove:
9293	   case sisBelow:   x = pSiS->NonRectDead.x0 - 1;
9294			    doit = TRUE;
9295	   default:	    break;
9296	   }
9297	}
9298     }
9299     if(HaveOffsRegions) {
9300	if(InRegion(x, y, pSiS->OffDead1)) {
9301	   switch(srel) {
9302	   case sisLeftOf:
9303	   case sisRightOf: y = pSiS->OffDead1.y1;
9304			    doit = TRUE;
9305			    break;
9306	   case sisAbove:
9307	   case sisBelow:   x = pSiS->OffDead1.x1;
9308			    doit = TRUE;
9309	   default:	    break;
9310	   }
9311	} else if(InRegion(x, y, pSiS->OffDead2)) {
9312	   switch(srel) {
9313	   case sisLeftOf:
9314	   case sisRightOf: y = pSiS->OffDead2.y0 - 1;
9315			    doit = TRUE;
9316			    break;
9317	   case sisAbove:
9318	   case sisBelow:   x = pSiS->OffDead2.x0 - 1;
9319			    doit = TRUE;
9320	   default:	    break;
9321	   }
9322	}
9323     }
9324     if(doit) {
9325	UpdateCurrentTime();
9326	sigstate = xf86BlockSIGIO();
9327	miPointerAbsoluteCursor(x, y, currentTime.milliseconds);
9328	xf86UnblockSIGIO(sigstate);
9329	return;
9330     }
9331  }
9332
9333  f1.x0 = old1x0 = pSiS->CRT1frameX0;
9334  f1.x1 = pSiS->CRT1frameX1;
9335  f1.y0 = old1y0 = pSiS->CRT1frameY0;
9336  f1.y1 = pSiS->CRT1frameY1;
9337  f2.x0 = old2x0 = pScrn2->frameX0;
9338  f2.x1 = pScrn2->frameX1;
9339  f2.y0 = old2y0 = pScrn2->frameY0;
9340  f2.y1 = pScrn2->frameY1;
9341
9342  /* Define the outer region. Crossing this causes all frames to move */
9343  out.x0 = pScrn1->frameX0;
9344  out.x1 = pScrn1->frameX1;
9345  out.y0 = pScrn1->frameY0;
9346  out.y1 = pScrn1->frameY1;
9347
9348  /*
9349   * Define the inner sliding window. Being outsize both frames but
9350   * inside the outer clipping window will slide corresponding frame
9351   */
9352  in1 = out;
9353  in2 = out;
9354  switch(srel) {
9355     case sisLeftOf:
9356        in1.x0 = f1.x0;
9357        in2.x1 = f2.x1;
9358        break;
9359     case sisRightOf:
9360        in1.x1 = f1.x1;
9361        in2.x0 = f2.x0;
9362        break;
9363     case sisBelow:
9364        in1.y1 = f1.y1;
9365        in2.y0 = f2.y0;
9366        break;
9367     case sisAbove:
9368        in1.y0 = f1.y0;
9369        in2.y1 = f2.y1;
9370        break;
9371     case sisClone:
9372        break;
9373  }
9374
9375  deltay = 0;
9376  deltax = 0;
9377
9378  if(InRegion(x, y, out)) {	/* inside outer region */
9379
9380     if(InRegion(x, y, in1) && !InRegion(x, y, f1)) {
9381	REBOUND(f1.x0, f1.x1, x);
9382	REBOUND(f1.y0, f1.y1, y);
9383	deltax = 1;
9384     }
9385     if(InRegion(x, y, in2) && !InRegion(x, y, f2)) {
9386	REBOUND(f2.x0, f2.x1, x);
9387	REBOUND(f2.y0, f2.y1, y);
9388	deltax = 1;
9389     }
9390
9391  } else {			/* outside outer region */
9392
9393     if(out.x0 > x) {
9394	deltax = x - out.x0;
9395     }
9396     if(out.x1 < x) {
9397	deltax = x - out.x1;
9398     }
9399     if(deltax) {
9400	pScrn1->frameX0 += deltax;
9401	pScrn1->frameX1 += deltax;
9402	f1.x0 += deltax;
9403	f1.x1 += deltax;
9404	f2.x0 += deltax;
9405	f2.x1 += deltax;
9406     }
9407
9408     if(out.y0 > y) {
9409	deltay = y - out.y0;
9410     }
9411     if(out.y1 < y) {
9412	deltay = y - out.y1;
9413     }
9414     if(deltay) {
9415	pScrn1->frameY0 += deltay;
9416	pScrn1->frameY1 += deltay;
9417	f1.y0 += deltay;
9418	f1.y1 += deltay;
9419	f2.y0 += deltay;
9420	f2.y1 += deltay;
9421     }
9422
9423     switch(srel) {
9424	case sisLeftOf:
9425	   if(x >= f1.x0) { REBOUND(f1.y0, f1.y1, y); }
9426	   if(x <= f2.x1) { REBOUND(f2.y0, f2.y1, y); }
9427	   break;
9428	case sisRightOf:
9429	   if(x <= f1.x1) { REBOUND(f1.y0, f1.y1, y); }
9430	   if(x >= f2.x0) { REBOUND(f2.y0, f2.y1, y); }
9431	   break;
9432	case sisBelow:
9433	   if(y <= f1.y1) { REBOUND(f1.x0, f1.x1, x); }
9434	   if(y >= f2.y0) { REBOUND(f2.x0, f2.x1, x); }
9435	   break;
9436	case sisAbove:
9437	   if(y >= f1.y0) { REBOUND(f1.x0, f1.x1, x); }
9438	   if(y <= f2.y1) { REBOUND(f2.x0, f2.x1, x); }
9439	   break;
9440	case sisClone:
9441	   break;
9442     }
9443
9444  }
9445
9446  if(deltax || deltay) {
9447     pSiS->CRT1frameX0 = f1.x0;
9448     pSiS->CRT1frameY0 = f1.y0;
9449     pScrn2->frameX0 = f2.x0;
9450     pScrn2->frameY0 = f2.y0;
9451
9452     switch(srel) {
9453	case sisLeftOf:
9454	case sisRightOf:
9455	   if(CRT1YOffs || CRT2YOffs || HaveNonRect) {
9456	      if(pSiS->CRT1frameY0 != old1y0) {
9457	         if(pSiS->CRT1frameY0 < CRT1YOffs)
9458	            pSiS->CRT1frameY0 = CRT1YOffs;
9459
9460	         temp1 = pSiS->CRT1frameY0 + CDMPTR->CRT1->VDisplay;
9461	         temp2 = min((VVirt - CRT2YOffs), (CRT1YOffs + pSiS->MBXNR1YMAX));
9462	         if(temp1 > temp2)
9463	            pSiS->CRT1frameY0 -= (temp1 - temp2);
9464	      }
9465	      if(pScrn2->frameY0 != old2y0) {
9466	         if(pScrn2->frameY0 < CRT2YOffs)
9467	            pScrn2->frameY0 = CRT2YOffs;
9468
9469	         temp1 = pScrn2->frameY0 + CDMPTR->CRT2->VDisplay;
9470	         temp2 = min((VVirt - CRT1YOffs), (CRT2YOffs + pSiS->MBXNR2YMAX));
9471	         if(temp1 > temp2)
9472	            pScrn2->frameY0 -= (temp1 - temp2);
9473	      }
9474	   }
9475	   break;
9476	case sisBelow:
9477	case sisAbove:
9478	   if(CRT1XOffs || CRT2XOffs || HaveNonRect) {
9479	      if(pSiS->CRT1frameX0 != old1x0) {
9480	         if(pSiS->CRT1frameX0 < CRT1XOffs)
9481	            pSiS->CRT1frameX0 = CRT1XOffs;
9482
9483	         temp1 = pSiS->CRT1frameX0 + CDMPTR->CRT1->HDisplay;
9484	         temp2 = min((HVirt - CRT2XOffs), (CRT1XOffs + pSiS->MBXNR1XMAX));
9485	         if(temp1 > temp2)
9486	            pSiS->CRT1frameX0 -= (temp1 - temp2);
9487	      }
9488	      if(pScrn2->frameX0 != old2x0) {
9489	         if(pScrn2->frameX0 < CRT2XOffs)
9490	            pScrn2->frameX0 = CRT2XOffs;
9491
9492	         temp1 = pScrn2->frameX0 + CDMPTR->CRT2->HDisplay;
9493	         temp2 = min((HVirt - CRT1XOffs), (CRT2XOffs + pSiS->MBXNR2XMAX));
9494	         if(temp1 > temp2)
9495	            pScrn2->frameX0 -= (temp1 - temp2);
9496	      }
9497	   }
9498	   break;
9499	case sisClone:
9500	   break;
9501     }
9502
9503     pSiS->CRT1frameX1 = pSiS->CRT1frameX0 + CDMPTR->CRT1->HDisplay - 1;
9504     pSiS->CRT1frameY1 = pSiS->CRT1frameY0 + CDMPTR->CRT1->VDisplay - 1;
9505     pScrn2->frameX1   = pScrn2->frameX0   + CDMPTR->CRT2->HDisplay - 1;
9506     pScrn2->frameY1   = pScrn2->frameY0   + CDMPTR->CRT2->VDisplay - 1;
9507
9508     /* No need to update pScrn1->frame?1, done above */
9509
9510     SISAdjustFrameHW_CRT1(pScrn1, pSiS->CRT1frameX0, pSiS->CRT1frameY0);
9511     SISAdjustFrameHW_CRT2(pScrn1, pScrn2->frameX0, pScrn2->frameY0);
9512  }
9513}
9514
9515static void
9516SISAdjustFrameMerged(int scrnIndex, int x, int y, int flags)
9517{
9518    ScrnInfoPtr pScrn1 = xf86Screens[scrnIndex];
9519    SISPtr pSiS = SISPTR(pScrn1);
9520    ScrnInfoPtr pScrn2 = pSiS->CRT2pScrn;
9521    int HTotal = pSiS->CurrentLayout.mode->HDisplay;
9522    int VTotal = pSiS->CurrentLayout.mode->VDisplay;
9523    int HMax = HTotal;
9524    int VMax = VTotal;
9525    int HVirt = pScrn1->virtualX;
9526    int VVirt = pScrn1->virtualY;
9527    int x1 = x, x2 = x;
9528    int y1 = y, y2 = y;
9529    int CRT1XOffs = 0, CRT1YOffs = 0, CRT2XOffs = 0, CRT2YOffs = 0;
9530    int MBXNR1XMAX = 65536, MBXNR1YMAX = 65536, MBXNR2XMAX = 65536, MBXNR2YMAX = 65536;
9531
9532    if(pSiS->DGAactive) {
9533       HVirt = pSiS->CurrentLayout.displayWidth;
9534       VVirt = pSiS->CurrentLayout.displayHeight;
9535    } else {
9536       CRT1XOffs = pSiS->CRT1XOffs;
9537       CRT1YOffs = pSiS->CRT1YOffs;
9538       CRT2XOffs = pSiS->CRT2XOffs;
9539       CRT2YOffs = pSiS->CRT2YOffs;
9540       MBXNR1XMAX = pSiS->MBXNR1XMAX;
9541       MBXNR1YMAX = pSiS->MBXNR1YMAX;
9542       MBXNR2XMAX = pSiS->MBXNR2XMAX;
9543       MBXNR2YMAX = pSiS->MBXNR2YMAX;
9544    }
9545
9546    BOUND(x, 0, HVirt - HTotal);
9547    BOUND(y, 0, VVirt - VTotal);
9548    if(SDMPTR(pScrn1)->CRT2Position != sisClone) {
9549       BOUND(x1, CRT1XOffs, min(HVirt, MBXNR1XMAX + CRT1XOffs) - min(HTotal, MBXNR1XMAX) - CRT2XOffs);
9550       BOUND(y1, CRT1YOffs, min(VVirt, MBXNR1YMAX + CRT1YOffs) - min(VTotal, MBXNR1YMAX) - CRT2YOffs);
9551       BOUND(x2, CRT2XOffs, min(HVirt, MBXNR2XMAX + CRT2XOffs) - min(HTotal, MBXNR2XMAX) - CRT1XOffs);
9552       BOUND(y2, CRT2YOffs, min(VVirt, MBXNR2YMAX + CRT2YOffs) - min(VTotal, MBXNR2YMAX) - CRT1YOffs);
9553    }
9554
9555    switch(SDMPTR(pScrn1)->CRT2Position) {
9556        case sisLeftOf:
9557            pScrn2->frameX0 = x2;
9558            BOUND(pScrn2->frameY0,   y2, y2 + min(VMax, MBXNR2YMAX) - CDMPTR->CRT2->VDisplay);
9559            pSiS->CRT1frameX0 = x1 + CDMPTR->CRT2->HDisplay;
9560            BOUND(pSiS->CRT1frameY0, y1, y1 + min(VMax, MBXNR1YMAX) - CDMPTR->CRT1->VDisplay);
9561            break;
9562        case sisRightOf:
9563            pSiS->CRT1frameX0 = x1;
9564            BOUND(pSiS->CRT1frameY0, y1, y1 + min(VMax, MBXNR1YMAX) - CDMPTR->CRT1->VDisplay);
9565            pScrn2->frameX0 = x2 + CDMPTR->CRT1->HDisplay;
9566            BOUND(pScrn2->frameY0,   y2, y2 + min(VMax, MBXNR2YMAX) - CDMPTR->CRT2->VDisplay);
9567            break;
9568        case sisAbove:
9569            BOUND(pScrn2->frameX0,   x2, x2 + min(HMax, MBXNR2XMAX) - CDMPTR->CRT2->HDisplay);
9570            pScrn2->frameY0 = y2;
9571            BOUND(pSiS->CRT1frameX0, x1, x1 + min(HMax, MBXNR1XMAX) - CDMPTR->CRT1->HDisplay);
9572            pSiS->CRT1frameY0 = y1 + CDMPTR->CRT2->VDisplay;
9573            break;
9574        case sisBelow:
9575            BOUND(pSiS->CRT1frameX0, x1, x1 + min(HMax, MBXNR1XMAX) - CDMPTR->CRT1->HDisplay);
9576            pSiS->CRT1frameY0 = y1;
9577            BOUND(pScrn2->frameX0,   x2, x2 + min(HMax, MBXNR2XMAX) - CDMPTR->CRT2->HDisplay);
9578            pScrn2->frameY0 = y2 + CDMPTR->CRT1->VDisplay;
9579            break;
9580        case sisClone:
9581            BOUND(pSiS->CRT1frameX0, x,  x + HMax - CDMPTR->CRT1->HDisplay);
9582            BOUND(pSiS->CRT1frameY0, y,  y + VMax - CDMPTR->CRT1->VDisplay);
9583            BOUND(pScrn2->frameX0,   x,  x + HMax - CDMPTR->CRT2->HDisplay);
9584            BOUND(pScrn2->frameY0,   y,  y + VMax - CDMPTR->CRT2->VDisplay);
9585            break;
9586    }
9587
9588    BOUND(pSiS->CRT1frameX0, 0, HVirt - CDMPTR->CRT1->HDisplay);
9589    BOUND(pSiS->CRT1frameY0, 0, VVirt - CDMPTR->CRT1->VDisplay);
9590    BOUND(pScrn2->frameX0,   0, HVirt - CDMPTR->CRT2->HDisplay);
9591    BOUND(pScrn2->frameY0,   0, VVirt - CDMPTR->CRT2->VDisplay);
9592
9593    pScrn1->frameX0 = x;
9594    pScrn1->frameY0 = y;
9595
9596    pSiS->CRT1frameX1 = pSiS->CRT1frameX0 + CDMPTR->CRT1->HDisplay - 1;
9597    pSiS->CRT1frameY1 = pSiS->CRT1frameY0 + CDMPTR->CRT1->VDisplay - 1;
9598    pScrn2->frameX1   = pScrn2->frameX0   + CDMPTR->CRT2->HDisplay - 1;
9599    pScrn2->frameY1   = pScrn2->frameY0   + CDMPTR->CRT2->VDisplay - 1;
9600
9601    pScrn1->frameX1   = pScrn1->frameX0   + pSiS->CurrentLayout.mode->HDisplay  - 1;
9602    pScrn1->frameY1   = pScrn1->frameY0   + pSiS->CurrentLayout.mode->VDisplay  - 1;
9603    if(SDMPTR(pScrn1)->CRT2Position != sisClone) {
9604       pScrn1->frameX1 += CRT1XOffs + CRT2XOffs;
9605       pScrn1->frameY1 += CRT1YOffs + CRT2YOffs;
9606    }
9607
9608    SISAdjustFrameHW_CRT1(pScrn1, pSiS->CRT1frameX0, pSiS->CRT1frameY0);
9609    SISAdjustFrameHW_CRT2(pScrn1, pScrn2->frameX0, pScrn2->frameY0);
9610}
9611#endif
9612
9613/*
9614 * This function is used to initialize the Start Address - the first
9615 * displayed location in the video memory.
9616 *
9617 * Usually mandatory
9618 */
9619void
9620SISAdjustFrame(int scrnIndex, int x, int y, int flags)
9621{
9622    ScrnInfoPtr   pScrn = xf86Screens[scrnIndex];
9623    SISPtr        pSiS = SISPTR(pScrn);
9624    ULong base;
9625    UChar temp, cr11backup;
9626
9627#ifdef SISMERGED
9628    if(pSiS->MergedFB) {
9629	SISAdjustFrameMerged(scrnIndex, x, y, flags);
9630	return;
9631    }
9632#endif
9633
9634    if(pSiS->UseVESA) {
9635	VBESetDisplayStart(pSiS->pVbe, x, y, TRUE);
9636	return;
9637    }
9638
9639    if(pScrn->bitsPerPixel < 8) {
9640       base = (y * pSiS->CurrentLayout.displayWidth + x + 3) >> 3;
9641    } else {
9642       base  = y * pSiS->CurrentLayout.displayWidth + x;
9643
9644       /* calculate base bpp dep. */
9645       switch(pSiS->CurrentLayout.bitsPerPixel) {
9646          case 16:
9647     	     base >>= 1;
9648             break;
9649          case 24:
9650             base = ((base * 3)) >> 2;
9651             base -= base % 6;
9652             break;
9653          case 32:
9654             break;
9655          default:      /* 8bpp */
9656             base >>= 2;
9657             break;
9658       }
9659    }
9660
9661#ifdef UNLOCK_ALWAYS
9662    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
9663#endif
9664
9665    base += (pSiS->dhmOffset/4);
9666
9667#ifdef TWDEBUG
9668    xf86DrvMsg(0, 0, "AdjustFrame: x %d y %d bpp %d dw %d base %d, dhmOffset %d\n",
9669    			x, y, pSiS->CurrentLayout.bitsPerPixel, pSiS->CurrentLayout.displayWidth, base, pSiS->dhmOffset);
9670#endif
9671
9672#ifdef SISDUALHEAD
9673    if(pSiS->DualHeadMode) {
9674       if(!pSiS->SecondHead) {
9675	  /* Head 1 (master) is always CRT2 */
9676	  SISSetStartAddressCRT2(pSiS, base);
9677       } else {
9678	  /* Head 2 (slave) is always CRT1 */
9679	  SISSetStartAddressCRT1(pSiS, base);
9680       }
9681    } else {
9682#endif
9683       switch(pSiS->VGAEngine) {
9684	  case SIS_300_VGA:
9685	  case SIS_315_VGA:
9686	     SISSetStartAddressCRT1(pSiS, base);
9687	     if(pSiS->VBFlags & CRT2_ENABLE) {
9688		if(!SiSBridgeIsInSlaveMode(pScrn)) {
9689		   SISSetStartAddressCRT2(pSiS, base);
9690		}
9691	     }
9692	     break;
9693	  default:
9694	     /* Unlock CRTC registers */
9695	     inSISIDXREG(SISCR,  0x11, cr11backup);
9696	     andSISIDXREG(SISCR, 0x11, 0x7F);
9697	     outSISIDXREG(SISCR, 0x0D, base & 0xFF);
9698	     outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF);
9699	     inSISIDXREG(SISSR,  0x27, temp);
9700	     temp &= 0xF0;
9701	     temp |= (base & 0x0F0000) >> 16;
9702	     outSISIDXREG(SISSR, 0x27, temp);
9703	     /* Eventually lock CRTC registers */
9704	     setSISIDXREG(SISCR, 0x11, 0x7F, (cr11backup & 0x80));
9705       }
9706#ifdef SISDUALHEAD
9707    }
9708#endif
9709
9710}
9711
9712/*
9713 * This is called when VT switching back to the X server.  Its job is
9714 * to reinitialise the video mode.
9715 * Mandatory!
9716 */
9717static Bool
9718SISEnterVT(int scrnIndex, int flags)
9719{
9720    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
9721    SISPtr pSiS = SISPTR(pScrn);
9722
9723    SiS_SiSFB_Lock(pScrn, TRUE);
9724
9725    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
9726
9727    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
9728       outSISIDXREG(SISCR,0x32,pSiS->myCR32);
9729       outSISIDXREG(SISCR,0x36,pSiS->myCR36);
9730       outSISIDXREG(SISCR,0x37,pSiS->myCR37);
9731    }
9732
9733    if(!SISModeInit(pScrn, pScrn->currentMode)) {
9734       SISErrorLog(pScrn, "SiSEnterVT: SISModeInit() failed\n");
9735       return FALSE;
9736    }
9737
9738    SISAdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
9739
9740#ifdef XF86DRI
9741    if(pSiS->directRenderingEnabled) {
9742       DRIUnlock(screenInfo.screens[scrnIndex]);
9743    }
9744#endif
9745
9746#ifdef SISDUALHEAD
9747    if((!pSiS->DualHeadMode) || (!pSiS->SecondHead))
9748#endif
9749       if(pSiS->ResetXv) {
9750          (pSiS->ResetXv)(pScrn);
9751       }
9752
9753    return TRUE;
9754}
9755
9756/*
9757 * This is called when VT switching away from the X server.  Its job is
9758 * to restore the previous (text) mode.
9759 * Mandatory!
9760 */
9761static void
9762SISLeaveVT(int scrnIndex, int flags)
9763{
9764    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
9765    SISPtr pSiS = SISPTR(pScrn);
9766#ifdef XF86DRI
9767    ScreenPtr pScreen;
9768
9769    if(pSiS->directRenderingEnabled) {
9770       pScreen = screenInfo.screens[scrnIndex];
9771       DRILock(pScreen, 0);
9772    }
9773#endif
9774
9775#ifdef SISDUALHEAD
9776    if(pSiS->DualHeadMode && pSiS->SecondHead) return;
9777#endif
9778
9779    if(pSiS->CursorInfoPtr) {
9780#ifdef SISDUALHEAD
9781       if(pSiS->DualHeadMode) {
9782          if(!pSiS->SecondHead) {
9783	     pSiS->ForceCursorOff = TRUE;
9784	     pSiS->CursorInfoPtr->HideCursor(pScrn);
9785	     SISWaitVBRetrace(pScrn);
9786	     pSiS->ForceCursorOff = FALSE;
9787	  }
9788       } else {
9789#endif
9790          pSiS->CursorInfoPtr->HideCursor(pScrn);
9791          SISWaitVBRetrace(pScrn);
9792#ifdef SISDUALHEAD
9793       }
9794#endif
9795    }
9796
9797    SISBridgeRestore(pScrn);
9798
9799    if(pSiS->UseVESA) {
9800
9801       /* This is a q&d work-around for a BIOS bug. In case we disabled CRT2,
9802    	* VBESaveRestore() does not restore CRT1. So we set any mode now,
9803	* because VBESetVBEMode correctly restores CRT1. Afterwards, we
9804	* can call VBESaveRestore to restore original mode.
9805	*/
9806       if((pSiS->VBFlags2 & VB2_VIDEOBRIDGE) && (!(pSiS->VBFlags & DISPTYPE_DISP2)))
9807	  VBESetVBEMode(pSiS->pVbe, (pSiS->SISVESAModeList->n) | 0xc000, NULL);
9808
9809       SISVESARestore(pScrn);
9810
9811    } else {
9812
9813       SISRestore(pScrn);
9814
9815    }
9816
9817    /* We use (otherwise unused) bit 7 to indicate that we are running
9818     * to keep sisfb to change the displaymode (this would result in
9819     * lethal display corruption upon quitting X or changing to a VT
9820     * until a reboot)
9821     */
9822    if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
9823       orSISIDXREG(SISCR,0x34,0x80);
9824    }
9825
9826    SISVGALock(pSiS);
9827
9828    SiS_SiSFB_Lock(pScrn, FALSE);
9829}
9830
9831
9832/*
9833 * This is called at the end of each server generation.  It restores the
9834 * original (text) mode.  It should really also unmap the video memory too.
9835 * Mandatory!
9836 */
9837static Bool
9838SISCloseScreen(int scrnIndex, ScreenPtr pScreen)
9839{
9840    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
9841    SISPtr pSiS = SISPTR(pScrn);
9842#ifdef SISDUALHEAD
9843    SISEntPtr pSiSEnt = pSiS->entityPrivate;
9844#endif
9845
9846    if(pSiS->SiSCtrlExtEntry) {
9847       SiSCtrlExtUnregister(pSiS, pScrn->scrnIndex);
9848    }
9849
9850#ifdef XF86DRI
9851    if(pSiS->directRenderingEnabled) {
9852       SISDRICloseScreen(pScreen);
9853       pSiS->directRenderingEnabled = FALSE;
9854    }
9855#endif
9856
9857    if(pScrn->vtSema) {
9858
9859        if(pSiS->CursorInfoPtr) {
9860#ifdef SISDUALHEAD
9861           if(pSiS->DualHeadMode) {
9862              if(!pSiS->SecondHead) {
9863	         pSiS->ForceCursorOff = TRUE;
9864	         pSiS->CursorInfoPtr->HideCursor(pScrn);
9865	         SISWaitVBRetrace(pScrn);
9866	         pSiS->ForceCursorOff = FALSE;
9867	      }
9868           } else {
9869#endif
9870             pSiS->CursorInfoPtr->HideCursor(pScrn);
9871             SISWaitVBRetrace(pScrn);
9872#ifdef SISDUALHEAD
9873           }
9874#endif
9875	}
9876
9877        SISBridgeRestore(pScrn);
9878
9879	if(pSiS->UseVESA) {
9880
9881	  /* This is a q&d work-around for a BIOS bug. In case we disabled CRT2,
9882    	   * VBESaveRestore() does not restore CRT1. So we set any mode now,
9883	   * because VBESetVBEMode correctly restores CRT1. Afterwards, we
9884	   * can call VBESaveRestore to restore original mode.
9885	   */
9886           if((pSiS->VBFlags2 & VB2_VIDEOBRIDGE) && (!(pSiS->VBFlags & DISPTYPE_DISP2)))
9887	      VBESetVBEMode(pSiS->pVbe, (pSiS->SISVESAModeList->n) | 0xc000, NULL);
9888
9889	   SISVESARestore(pScrn);
9890
9891	} else {
9892
9893	   SISRestore(pScrn);
9894
9895	}
9896
9897        SISVGALock(pSiS);
9898
9899    }
9900
9901    SiS_SiSFB_Lock(pScrn, FALSE);
9902
9903    /* We should restore the mode number in case vtsema = false as well,
9904     * but since we haven't register access then we can't do it. I think
9905     * I need to rework the save/restore stuff, like saving the video
9906     * status when returning to the X server and by that save me the
9907     * trouble if sisfb was started from a textmode VT while X was on.
9908     */
9909
9910    SISUnmapMem(pScrn);
9911#ifdef SIS_PC_PLATFORM
9912    SiSVGAUnmapMem(pScrn);
9913#endif
9914
9915#ifdef SISDUALHEAD
9916    if(pSiS->DualHeadMode) {
9917       pSiSEnt = pSiS->entityPrivate;
9918       pSiSEnt->refCount--;
9919    }
9920#endif
9921
9922    if(pSiS->pInt) {
9923       xf86FreeInt10(pSiS->pInt);
9924       pSiS->pInt = NULL;
9925    }
9926
9927#ifdef SIS_USE_XAA
9928    if(!pSiS->useEXA) {
9929       if(pSiS->AccelLinearScratch) {
9930          xf86FreeOffscreenLinear(pSiS->AccelLinearScratch);
9931          pSiS->AccelLinearScratch = NULL;
9932       }
9933       if(pSiS->AccelInfoPtr) {
9934          XAADestroyInfoRec(pSiS->AccelInfoPtr);
9935          pSiS->AccelInfoPtr = NULL;
9936       }
9937    }
9938#endif
9939
9940#ifdef SIS_USE_EXA
9941    if(pSiS->useEXA) {
9942       if(pSiS->EXADriverPtr) {
9943          exaDriverFini(pScreen);
9944          xfree(pSiS->EXADriverPtr);
9945          pSiS->EXADriverPtr = NULL;
9946          pSiS->exa_scratch = NULL;
9947       }
9948    }
9949#endif
9950
9951    if(pSiS->CursorInfoPtr) {
9952       xf86DestroyCursorInfoRec(pSiS->CursorInfoPtr);
9953       pSiS->CursorInfoPtr = NULL;
9954    }
9955
9956    if(pSiS->ShadowPtr) {
9957       xfree(pSiS->ShadowPtr);
9958       pSiS->ShadowPtr = NULL;
9959    }
9960
9961    if(pSiS->DGAModes) {
9962       xfree(pSiS->DGAModes);
9963       pSiS->DGAModes = NULL;
9964    }
9965
9966    if(pSiS->adaptor) {
9967       xfree(pSiS->adaptor);
9968       pSiS->adaptor = NULL;
9969       pSiS->ResetXv = pSiS->ResetXvGamma = pSiS->ResetXvDisplay = NULL;
9970    }
9971
9972    if(pSiS->blitadaptor) {
9973       xfree(pSiS->blitadaptor);
9974       pSiS->blitadaptor = NULL;
9975    }
9976
9977    if(pSiS->crt2gcolortable) {
9978       xfree(pSiS->crt2gcolortable);
9979       pSiS->crt2gcolortable = NULL;
9980    }
9981
9982    if(pSiS->crt2cindices) {
9983       xfree(pSiS->crt2cindices);
9984       pSiS->crt2cindices = NULL;
9985    }
9986
9987    pScrn->vtSema = FALSE;
9988
9989    /* Restore Blockhandler */
9990    pScreen->BlockHandler = pSiS->BlockHandler;
9991
9992    pScreen->CloseScreen = pSiS->CloseScreen;
9993
9994    return(*pScreen->CloseScreen)(scrnIndex, pScreen);
9995}
9996
9997
9998/* Free up any per-generation data structures */
9999
10000/* Optional */
10001static void
10002SISFreeScreen(int scrnIndex, int flags)
10003{
10004#ifdef SIS_NEED_MAP_IOP
10005    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
10006    SISPtr pSiS = SISPTR(pScrn);
10007
10008    if(pSiS) {
10009#ifdef SISDUALHEAD
10010       SISEntPtr pSiSEnt = pSiS->entityPrivate;
10011       if(pSiSEnt) {
10012          pSiSEnt->forceUnmapIOPBase = TRUE;
10013       }
10014#endif
10015       SISUnmapIOPMem(pScrn);
10016    }
10017#endif
10018
10019    SISFreeRec(xf86Screens[scrnIndex]);
10020}
10021
10022
10023/* Checks if a mode is suitable for the selected chipset. */
10024
10025static ModeStatus
10026SISValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags)
10027{
10028    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
10029    SISPtr pSiS = SISPTR(pScrn);
10030
10031    if(pSiS->UseVESA) {
10032       if(SiSCalcVESAModeIndex(pScrn, mode))
10033	  return(MODE_OK);
10034       else
10035	  return(MODE_BAD);
10036    }
10037
10038    if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
10039#ifdef SISDUALHEAD
10040       if(pSiS->DualHeadMode) {
10041          if(pSiS->SecondHead) {
10042	     if(SiS_CheckModeCRT1(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
10043	        return(MODE_BAD);
10044	  } else {
10045	     if(SiS_CheckModeCRT2(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
10046	        return(MODE_BAD);
10047	  }
10048       } else
10049#endif
10050#ifdef SISMERGED
10051       if(pSiS->MergedFB) {
10052	  if(!mode->Private) {
10053	     if(!pSiS->CheckForCRT2) {
10054	        if(SiS_CheckModeCRT1(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
10055	           return(MODE_BAD);
10056	     } else {
10057	        if(SiS_CheckModeCRT2(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes2) < 0x14)
10058	           return(MODE_BAD);
10059	     }
10060	  } else {
10061	     if(SiS_CheckModeCRT1(pScrn, ((SiSMergedDisplayModePtr)mode->Private)->CRT1,
10062		                  pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
10063	        return(MODE_BAD);
10064
10065	     if(SiS_CheckModeCRT2(pScrn, ((SiSMergedDisplayModePtr)mode->Private)->CRT2,
10066		                  pSiS->VBFlags, pSiS->HaveCustomModes2) < 0x14)
10067	        return(MODE_BAD);
10068 	  }
10069       } else
10070#endif
10071       {
10072	  if(SiS_CheckModeCRT1(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
10073	     return(MODE_BAD);
10074
10075	  if(SiS_CheckModeCRT2(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
10076	     return(MODE_BAD);
10077       }
10078    }
10079
10080    return(MODE_OK);
10081}
10082
10083#ifdef DEBUG
10084static void
10085SiSDumpModeInfo(ScrnInfoPtr pScrn, DisplayModePtr mode)
10086{
10087    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Clock : %x\n", mode->Clock);
10088    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Display : %x\n", mode->CrtcHDisplay);
10089    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Blank Start : %x\n", mode->CrtcHBlankStart);
10090    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Sync Start : %x\n", mode->CrtcHSyncStart);
10091    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Sync End : %x\n", mode->CrtcHSyncEnd);
10092    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Blank End : %x\n", mode->CrtcHBlankEnd);
10093    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Total : %x\n", mode->CrtcHTotal);
10094    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Skew : %x\n", mode->CrtcHSkew);
10095    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz HAdjusted : %x\n", mode->CrtcHAdjusted);
10096    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Display : %x\n", mode->CrtcVDisplay);
10097    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Blank Start : %x\n", mode->CrtcVBlankStart);
10098    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Sync Start : %x\n", mode->CrtcVSyncStart);
10099    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Sync End : %x\n", mode->CrtcVSyncEnd);
10100    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Blank End : %x\n", mode->CrtcVBlankEnd);
10101    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Total : %x\n", mode->CrtcVTotal);
10102    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt VAdjusted : %x\n", mode->CrtcVAdjusted);
10103}
10104#endif
10105
10106static void
10107SISModifyModeInfo(DisplayModePtr mode)
10108{
10109    if(mode->CrtcHBlankStart == mode->CrtcHDisplay)
10110        mode->CrtcHBlankStart++;
10111    if(mode->CrtcHBlankEnd == mode->CrtcHTotal)
10112        mode->CrtcHBlankEnd--;
10113    if(mode->CrtcVBlankStart == mode->CrtcVDisplay)
10114        mode->CrtcVBlankStart++;
10115    if(mode->CrtcVBlankEnd == mode->CrtcVTotal)
10116        mode->CrtcVBlankEnd--;
10117}
10118
10119/* Enable the Turboqueue/Commandqueue (For 300 and 315/330/340 series only) */
10120static void
10121SiSEnableTurboQueue(ScrnInfoPtr pScrn)
10122{
10123    SISPtr pSiS = SISPTR(pScrn);
10124    UShort SR26, SR27;
10125    ULong  temp;
10126
10127    switch(pSiS->VGAEngine) {
10128	case SIS_300_VGA:
10129	   if((!pSiS->NoAccel) && (pSiS->TurboQueue)) {
10130		/* TQ size is always 512k */
10131		temp = (pScrn->videoRam/64) - 8;
10132		SR26 = temp & 0xFF;
10133		inSISIDXREG(SISSR, 0x27, SR27);
10134		SR27 &= 0xFC;
10135		SR27 |= (0xF0 | ((temp >> 8) & 3));
10136		outSISIDXREG(SISSR, 0x26, SR26);
10137		outSISIDXREG(SISSR, 0x27, SR27);
10138	   }
10139	   break;
10140
10141	case SIS_315_VGA:
10142	   if(!pSiS->NoAccel) {
10143	      /* On 315/330/340 series, there are three queue modes available
10144	       * which are chosen by setting bits 7:5 in SR26:
10145	       * 1. MMIO queue mode (bit 5, 0x20). The hardware will keep
10146	       *    track of the queue, the FIFO, command parsing and so
10147	       *    on. This is the one comparable to the 300 series.
10148	       * 2. VRAM queue mode (bit 6, 0x40). In this case, one will
10149	       *    have to do queue management himself.
10150	       * 3. AGP queue mode (bit 7, 0x80). Works as 2., but keeps the
10151	       *    queue in AGP memory space.
10152	       * We go VRAM or MMIO here.
10153	       * SR26 bit 4 is called "Bypass H/W queue".
10154	       * SR26 bit 1 is called "Enable Command Queue Auto Correction"
10155	       * SR26 bit 0 resets the queue
10156	       * Size of queue memory is encoded in bits 3:2 like this:
10157	       *    00  (0x00)  512K
10158	       *    01  (0x04)  1M
10159	       *    10  (0x08)  2M
10160	       *    11  (0x0C)  4M
10161	       * The queue location is to be written to 0x85C0.
10162	       */
10163#ifdef SISVRAMQ
10164	      /* We use VRAM Cmd Queue, not MMIO or AGP */
10165	      UChar tempCR55 = 0;
10166
10167	      /* Set Command Queue Threshold to max value 11111b (?) */
10168	      outSISIDXREG(SISSR, 0x27, 0x1F);
10169
10170	      /* Disable queue flipping */
10171	      inSISIDXREG(SISCR, 0x55, tempCR55);
10172	      andSISIDXREG(SISCR, 0x55, 0x33);
10173	      /* Synchronous reset for Command Queue */
10174	      outSISIDXREG(SISSR, 0x26, 0x01);
10175	      SIS_MMIO_OUT32(pSiS->IOBase, 0x85c4, 0);
10176	      /* Enable VRAM Command Queue mode */
10177	      if(pSiS->ChipType == XGI_20) {
10178		 /* On XGI_20, always 128K */
10179		 SR26 = 0x40 | 0x04 | 0x01;
10180	      } else {
10181	         switch(pSiS->cmdQueueSize) {
10182		    case 1*1024*1024: SR26 = (0x40 | 0x04 | 0x01); break;
10183		    case 2*1024*1024: SR26 = (0x40 | 0x08 | 0x01); break;
10184		    case 4*1024*1024: SR26 = (0x40 | 0x0C | 0x01); break;
10185		    default:
10186		                      pSiS->cmdQueueSize = 512 * 1024;
10187		    case    512*1024: SR26 = (0x40 | 0x00 | 0x01);
10188	         }
10189	      }
10190	      outSISIDXREG(SISSR, 0x26, SR26);
10191	      SR26 &= 0xfe;
10192	      outSISIDXREG(SISSR, 0x26, SR26);
10193	      *(pSiS->cmdQ_SharedWritePort) = (unsigned int)(SIS_MMIO_IN32(pSiS->IOBase, 0x85c8));
10194	      SIS_MMIO_OUT32(pSiS->IOBase, 0x85c4, (CARD32)(*(pSiS->cmdQ_SharedWritePort)));
10195	      SIS_MMIO_OUT32(pSiS->IOBase, 0x85C0, pSiS->cmdQueueOffset);
10196	      temp = (ULong)pSiS->RealFbBase;
10197#ifdef SISDUALHEAD
10198	      if(pSiS->DualHeadMode) {
10199	         SISEntPtr pSiSEnt = pSiS->entityPrivate;
10200	         temp = (ULong)pSiSEnt->RealFbBase;
10201	      }
10202#endif
10203	      temp += pSiS->cmdQueueOffset;
10204	      pSiS->cmdQueueBase = (unsigned int *)temp;
10205	      outSISIDXREG(SISCR, 0x55, tempCR55);
10206#ifdef TWDEBUG
10207	      xf86DrvMsg(0, 0, "CmdQueueOffs 0x%x, CmdQueueAdd %p, shwrp 0x%x, status %x, base %p\n",
10208		pSiS->cmdQueueOffset, pSiS->cmdQueueBase, *(pSiS->cmdQ_SharedWritePort),
10209		SIS_MMIO_IN32(pSiS->IOBase, 0x85cc), (ULong *)temp);
10210#endif
10211#else
10212	      /* For MMIO */
10213	      /* Syncronous reset for Command Queue */
10214	      orSISIDXREG(SISSR, 0x26, 0x01);
10215	      /* Set Command Queue Threshold to max value 11111b */
10216	      outSISIDXREG(SISSR, 0x27, 0x1F);
10217	      /* Do some magic (cp readport to writeport) */
10218	      temp = SIS_MMIO_IN32(pSiS->IOBase, 0x85C8);
10219	      SIS_MMIO_OUT32(pSiS->IOBase, 0x85C4, temp);
10220	      /* Enable MMIO Command Queue mode (0x20),
10221	       * Enable_command_queue_auto_correction (0x02)
10222	       *        (no idea, but sounds good, so use it)
10223	       * 512k (0x00) (does this apply to MMIO mode?) */
10224	      outSISIDXREG(SISSR, 0x26, 0x22);
10225	      /* Calc Command Queue position (Q is always 512k)*/
10226	      temp = (pScrn->videoRam - 512) * 1024;
10227	      /* Set Q position */
10228	      SIS_MMIO_OUT32(pSiS->IOBase, 0x85C0, temp);
10229#endif
10230	   }
10231	   break;
10232	default:
10233	   break;
10234    }
10235}
10236
10237#ifdef SISVRAMQ
10238static void
10239SiSRestoreQueueMode(SISPtr pSiS, SISRegPtr sisReg)
10240{
10241    UChar tempCR55=0;
10242
10243    if(pSiS->VGAEngine == SIS_315_VGA) {
10244       inSISIDXREG(SISCR,0x55,tempCR55);
10245       andSISIDXREG(SISCR,0x55,0x33);
10246       outSISIDXREG(SISSR,0x26,0x01);
10247       SIS_MMIO_OUT32(pSiS->IOBase, 0x85c4, 0);
10248       outSISIDXREG(SISSR,0x27,sisReg->sisRegs3C4[0x27]);
10249       outSISIDXREG(SISSR,0x26,sisReg->sisRegs3C4[0x26]);
10250       SIS_MMIO_OUT32(pSiS->IOBase, 0x85C0, sisReg->sisMMIO85C0);
10251       outSISIDXREG(SISCR,0x55,tempCR55);
10252    }
10253}
10254#endif
10255
10256/* Things to do before a ModeSwitch. We set up the
10257 * video bridge configuration and the TurboQueue.
10258 */
10259void SiSPreSetMode(ScrnInfoPtr pScrn, DisplayModePtr mode, int viewmode)
10260{
10261    SISPtr pSiS = SISPTR(pScrn);
10262    UChar  CR30, CR31, CR32, CR33;
10263    UChar  CR39 = 0, CR3B = 0;
10264    UChar  CR17, CR38 = 0;
10265    UChar  CR35 = 0, CR79 = 0;
10266    int    temp = 0, crt1rateindex = 0;
10267    ULong  vbflag = pSiS->VBFlags;
10268    Bool   hcm = pSiS->HaveCustomModes;
10269    DisplayModePtr mymode = mode;
10270
10271    pSiS->IsCustom = FALSE;
10272
10273    /* NEVER call this with viewmode = SIS_MODE_SIMU
10274     * if mode->type is not M_T_DEFAULT!
10275     */
10276
10277#ifdef SISMERGED
10278    if(pSiS->MergedFB) {
10279       switch(viewmode) {
10280       case SIS_MODE_CRT1:
10281	  mymode = ((SiSMergedDisplayModePtr)mode->Private)->CRT1;
10282	  break;
10283       case SIS_MODE_CRT2:
10284	  mymode = ((SiSMergedDisplayModePtr)mode->Private)->CRT2;
10285	  hcm = pSiS->HaveCustomModes2;
10286       }
10287    }
10288#endif
10289
10290    switch(viewmode) {
10291    case SIS_MODE_CRT1:
10292       if(SiS_CheckModeCRT1(pScrn, mymode, vbflag, hcm) == 0xfe) {
10293          pSiS->IsCustom = TRUE;
10294       }
10295       break;
10296    case SIS_MODE_CRT2:
10297       if(vbflag & CRT2_ENABLE) {
10298          if(SiS_CheckModeCRT2(pScrn, mymode, vbflag, hcm) == 0xfe) {
10299	     pSiS->IsCustom = TRUE;
10300          }
10301       } else {
10302          /* This can only happen in mirror mode */
10303          if(SiS_CheckModeCRT1(pScrn, mymode, vbflag, hcm) == 0xfe) {
10304             pSiS->IsCustom = TRUE;
10305          }
10306       }
10307    }
10308
10309#ifdef UNLOCK_ALWAYS
10310    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);    /* Unlock Registers */
10311#endif
10312
10313    inSISIDXREG(SISCR, 0x30, CR30);
10314    inSISIDXREG(SISCR, 0x31, CR31);
10315    CR32 = pSiS->newCR32;
10316    inSISIDXREG(SISCR, 0x33, CR33);
10317
10318    if(pSiS->NewCRLayout) {
10319
10320       inSISIDXREG(SISCR, 0x35, CR35);
10321       inSISIDXREG(SISCR, 0x38, CR38);
10322       inSISIDXREG(SISCR, 0x39, CR39);
10323
10324       xf86DrvMsgVerb(pScrn->scrnIndex, X_PROBED, SISVERBLEVEL,
10325	   "Before: CR30=0x%02x,CR31=0x%02x,CR32=0x%02x,CR33=0x%02x,CR35=0x%02x,CR38=0x%02x\n",
10326              CR30, CR31, CR32, CR33, CR35, CR38);
10327
10328       CR38 &= ~0x07;
10329
10330    } else {
10331
10332       if(pSiS->Chipset != PCI_CHIP_SIS300) {
10333          switch(pSiS->VGAEngine) {
10334             case SIS_300_VGA: temp = 0x35; break;
10335             case SIS_315_VGA: temp = 0x38; break;
10336          }
10337          if(temp) inSISIDXREG(SISCR, temp, CR38);
10338       }
10339       if(pSiS->VGAEngine == SIS_315_VGA) {
10340          inSISIDXREG(SISCR, 0x79, CR79);
10341          CR38 &= ~0x3b;   			/* Clear LCDA/DualEdge and YPbPr bits */
10342       }
10343       inSISIDXREG(SISCR, 0x3b, CR3B);
10344
10345       xf86DrvMsgVerb(pScrn->scrnIndex, X_PROBED, SISVERBLEVEL,
10346	   "Before: CR30=0x%02x, CR31=0x%02x, CR32=0x%02x, CR33=0x%02x, CR%02x=0x%02x\n",
10347              CR30, CR31, CR32, CR33, temp, CR38);
10348    }
10349
10350    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, SISVERBLEVEL, "VBFlags=0x%x\n", pSiS->VBFlags);
10351
10352    CR30 = 0x00;
10353    CR31 &= ~0x60;  /* Clear VB_Drivermode & VB_OutputDisable */
10354    CR31 |= 0x04;   /* Set VB_NotSimuMode (not for 30xB/1400x1050?) */
10355    CR35 = 0x00;
10356
10357    if(!pSiS->NewCRLayout) {
10358       if(!pSiS->AllowHotkey) {
10359          CR31 |= 0x80;   /* Disable hotkey-switch */
10360       }
10361       CR79 &= ~0x10;     /* Enable Backlight control on 315 series */
10362    }
10363
10364    SiS_SetEnableDstn(pSiS->SiS_Pr, FALSE);
10365    SiS_SetEnableFstn(pSiS->SiS_Pr, FALSE);
10366
10367    if((vbflag & CRT1_LCDA) && (viewmode == SIS_MODE_CRT1)) {
10368
10369       CR38 |= 0x02;
10370
10371    } else {
10372
10373       switch(vbflag & (CRT2_TV|CRT2_LCD|CRT2_VGA)) {
10374
10375       case CRT2_TV:
10376
10377          CR38 &= ~0xC0; 	/* Clear Pal M/N bits */
10378
10379          if((pSiS->VBFlags2 & VB2_CHRONTEL) && (vbflag & TV_CHSCART)) {		/* Chrontel */
10380	     CR30 |= 0x10;
10381	     CR38 |= 0x04;
10382	     CR38 &= ~0x08;
10383	     CR31 |= 0x01;
10384	  } else if((pSiS->VBFlags2 & VB2_CHRONTEL) && (vbflag & TV_CHYPBPR525I)) {	/* Chrontel */
10385	     CR38 |= 0x08;
10386	     CR38 &= ~0x04;
10387	     CR31 &= ~0x01;
10388          } else if(vbflag & TV_HIVISION) {	/* SiS bridge */
10389	     if(pSiS->NewCRLayout) {
10390	        CR38 |= 0x04;
10391	        CR35 |= 0x60;
10392	     } else {
10393	        CR30 |= 0x80;
10394		if(pSiS->VGAEngine == SIS_315_VGA) {
10395		   if(pSiS->VBFlags2 & VB2_SISYPBPRBRIDGE) {
10396		      CR38 |= (0x08 | 0x30);
10397		   }
10398		}
10399	     }
10400	     CR31 |= 0x01;
10401	     CR35 |= 0x01;
10402	  } else if(vbflag & TV_YPBPR) {					/* SiS bridge */
10403	     if(pSiS->NewCRLayout) {
10404		CR38 |= 0x04;
10405		CR31 &= ~0x01;
10406		CR35 &= ~0x01;
10407		if(vbflag & (TV_YPBPR525P | TV_YPBPR625P)) CR35 |= 0x20;
10408		else if(vbflag & TV_YPBPR750P)             CR35 |= 0x40;
10409		else if(vbflag & TV_YPBPR1080I)            CR35 |= 0x60;
10410
10411		if(vbflag & (TV_YPBPR625I | TV_YPBPR625P)) {
10412		   CR31 |= 0x01;
10413		   CR35 |= 0x01;
10414		}
10415
10416		CR39 &= ~0x03;
10417		if((vbflag & TV_YPBPRAR) == TV_YPBPR43LB)     CR39 |= 0x00;
10418		else if((vbflag & TV_YPBPRAR) == TV_YPBPR43)  CR39 |= 0x01;
10419		else if((vbflag & TV_YPBPRAR) == TV_YPBPR169) CR39 |= 0x02;
10420		else					      CR39 |= 0x03;
10421	     } else if(pSiS->SiS_SD_Flags & SiS_SD_SUPPORTYPBPR) {
10422		CR30 |= 0x80;
10423		CR38 |= 0x08;
10424		CR31 &= ~0x01;
10425		if(vbflag & (TV_YPBPR525P|TV_YPBPR625P)) CR38 |= 0x10;
10426		else if(vbflag & TV_YPBPR750P)  	 CR38 |= 0x20;
10427		else if(vbflag & TV_YPBPR1080I)		 CR38 |= 0x30;
10428
10429		if(vbflag & (TV_YPBPR625I | TV_YPBPR625P)) CR31 |= 0x01;
10430
10431		if(pSiS->SiS_SD_Flags & SiS_SD_SUPPORTYPBPRAR) {
10432		   CR3B &= ~0x03;
10433		   if((vbflag & TV_YPBPRAR) == TV_YPBPR43LB)     CR3B |= 0x00;
10434		   else if((vbflag & TV_YPBPRAR) == TV_YPBPR43)  CR3B |= 0x03;
10435		   else if((vbflag & TV_YPBPRAR) == TV_YPBPR169) CR3B |= 0x01;
10436		   else					         CR3B |= 0x03;
10437		}
10438	     }
10439          } else {								/* All */
10440	     if(vbflag & TV_SCART)  CR30 |= 0x10;
10441	     if(vbflag & TV_SVIDEO) CR30 |= 0x08;
10442	     if(vbflag & TV_AVIDEO) CR30 |= 0x04;
10443	     if(!(CR30 & 0x1C))	    CR30 |= 0x08;    /* default: SVIDEO */
10444
10445	     if(vbflag & TV_PAL) {
10446		CR31 |= 0x01;
10447		CR35 |= 0x01;
10448		if( (pSiS->VBFlags2 & VB2_SISBRIDGE) ||
10449		    ((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->ChrontelType == CHRONTEL_701x)) )  {
10450		   if(vbflag & TV_PALM) {
10451		      CR38 |= 0x40;
10452		      CR35 |= 0x04;
10453		   } else if(vbflag & TV_PALN) {
10454		      CR38 |= 0x80;
10455		      CR35 |= 0x08;
10456		   }
10457	        }
10458	     } else {
10459		CR31 &= ~0x01;
10460		CR35 &= ~0x01;
10461		if(vbflag & TV_NTSCJ) {
10462		   CR38 |= 0x40;  /* TW, not BIOS */
10463		   CR35 |= 0x02;
10464		}
10465	     }
10466	     if(vbflag & TV_SCART) {
10467		CR31 |= 0x01;
10468		CR35 |= 0x01;
10469	     }
10470	  }
10471
10472	  CR31 &= ~0x04;   /* Clear NotSimuMode */
10473	  pSiS->SiS_Pr->SiS_CHOverScan = pSiS->UseCHOverScan;
10474	  if((pSiS->OptTVSOver == 1) && (pSiS->ChrontelType == CHRONTEL_700x)) {
10475	     pSiS->SiS_Pr->SiS_CHSOverScan = TRUE;
10476	  } else {
10477	     pSiS->SiS_Pr->SiS_CHSOverScan = FALSE;
10478	  }
10479#ifdef SIS_CP
10480	  SIS_CP_DRIVER_CONFIG
10481#endif
10482	  break;
10483
10484       case CRT2_LCD:
10485	  CR30 |= 0x20;
10486	  SiS_SetEnableDstn(pSiS->SiS_Pr, pSiS->DSTN);
10487	  SiS_SetEnableFstn(pSiS->SiS_Pr, pSiS->FSTN);
10488	  break;
10489
10490       case CRT2_VGA:
10491	  CR30 |= 0x40;
10492	  break;
10493
10494       default:
10495	  CR30 |= 0x00;
10496	  CR31 |= 0x20;    /* VB_OUTPUT_DISABLE */
10497	  if(pSiS->UseVESA) {
10498	     crt1rateindex = SISSearchCRT1Rate(pScrn, mymode);
10499	  }
10500       }
10501
10502    }
10503
10504    if(vbflag & CRT1_LCDA) {
10505       switch(viewmode) {
10506       case SIS_MODE_CRT1:
10507	  CR38 |= 0x01;
10508	  break;
10509       case SIS_MODE_CRT2:
10510	  if(vbflag & (CRT2_TV|CRT2_VGA)) {
10511	     CR30 |= 0x02;
10512	     CR38 |= 0x01;
10513	  } else {
10514	     CR38 |= 0x03;
10515	  }
10516	  break;
10517       case SIS_MODE_SIMU:
10518       default:
10519	  if(vbflag & (CRT2_TV|CRT2_LCD|CRT2_VGA)) {
10520	     CR30 |= 0x01;
10521	  }
10522	  break;
10523       }
10524    } else {
10525       if(vbflag & (CRT2_TV|CRT2_LCD|CRT2_VGA)) {
10526          CR30 |= 0x01;
10527       }
10528    }
10529
10530    if(pSiS->UseVESA) {
10531       CR31 &= ~0x40;   /* Clear Drivermode */
10532       CR31 |= 0x06;    /* Set SlaveMode, Enable SimuMode in Slavemode */
10533#ifdef TWDEBUG
10534       CR31 |= 0x40;    /* DEBUG (for non-slave mode VESA) */
10535       crt1rateindex = SISSearchCRT1Rate(pScrn, mymode);
10536#endif
10537    } else {
10538       CR31 |=  0x40;  /* Set Drivermode */
10539       CR31 &=  ~0x06; /* Disable SlaveMode, disable SimuMode in SlaveMode */
10540       if(!pSiS->IsCustom) {
10541          crt1rateindex = SISSearchCRT1Rate(pScrn, mymode);
10542       }
10543    }
10544
10545    switch(viewmode) {
10546	case SIS_MODE_SIMU:
10547	   CR33 = 0;
10548	   if(!(vbflag & CRT1_LCDA)) {
10549	      CR33 |= (crt1rateindex & 0x0f);
10550	   }
10551	   if(vbflag & CRT2_VGA) {
10552	      CR33 |= ((crt1rateindex & 0x0f) << 4);
10553	   }
10554	   break;
10555	case SIS_MODE_CRT1:
10556	   CR33 &= 0xf0;
10557	   if(!(vbflag & CRT1_LCDA)) {
10558	      CR33 |= (crt1rateindex & 0x0f);
10559	   }
10560	   break;
10561	case SIS_MODE_CRT2:
10562	   CR33 &= 0x0f;
10563	   if(vbflag & CRT2_VGA) {
10564	      CR33 |= ((crt1rateindex & 0x0f) << 4);
10565	   }
10566	   break;
10567     }
10568
10569     if((!pSiS->UseVESA) && (vbflag & CRT2_ENABLE)) {
10570	if(pSiS->CRT1off) CR33 &= 0xf0;
10571     }
10572
10573     if(pSiS->NewCRLayout) {
10574
10575	CR31 &= 0xfe;   /* Clear PAL flag (now in CR35) */
10576	CR38 &= 0x07;   /* Use only LCDA and HiVision/YPbPr bits */
10577	outSISIDXREG(SISCR, 0x30, CR30);
10578	outSISIDXREG(SISCR, 0x31, CR31);
10579	outSISIDXREG(SISCR, 0x33, CR33);
10580	outSISIDXREG(SISCR, 0x35, CR35);
10581	setSISIDXREG(SISCR, 0x38, 0xf8, CR38);
10582	outSISIDXREG(SISCR, 0x39, CR39);
10583
10584	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, SISVERBLEVEL,
10585		"After:  CR30=0x%02x,CR31=0x%02x,CR33=0x%02x,CR35=0x%02x,CR38=%02x\n",
10586		    CR30, CR31, CR33, CR35, CR38);
10587
10588     } else {
10589
10590	outSISIDXREG(SISCR, 0x30, CR30);
10591	outSISIDXREG(SISCR, 0x31, CR31);
10592	outSISIDXREG(SISCR, 0x33, CR33);
10593	if(temp) {
10594	   outSISIDXREG(SISCR, temp, CR38);
10595	}
10596	if(pSiS->VGAEngine == SIS_315_VGA) {
10597	   outSISIDXREG(SISCR, 0x3b, CR3B);
10598	   outSISIDXREG(SISCR, 0x79, CR79);
10599	}
10600
10601	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, SISVERBLEVEL,
10602		"After:  CR30=0x%02x,CR31=0x%02x,CR33=0x%02x,CR%02x=%02x\n",
10603		    CR30, CR31, CR33, temp, CR38);
10604     }
10605
10606     pSiS->SiS_Pr->SiS_UseOEM = pSiS->OptUseOEM;
10607
10608     /* Enable TurboQueue */
10609#ifdef SISVRAMQ
10610     if(pSiS->VGAEngine != SIS_315_VGA)
10611#endif
10612	SiSEnableTurboQueue(pScrn);
10613
10614     if((!pSiS->UseVESA) && (pSiS->VBFlags & CRT2_ENABLE)) {
10615	/* Switch on CRT1 for modes that require the bridge in SlaveMode */
10616	andSISIDXREG(SISSR,0x1f,0x3f);
10617	inSISIDXREG(SISCR, 0x17, CR17);
10618	if(!(CR17 & 0x80)) {
10619	   orSISIDXREG(SISCR, 0x17, 0x80);
10620	   outSISIDXREG(SISSR, 0x00, 0x01);
10621	   usleep(10000);
10622	   outSISIDXREG(SISSR, 0x00, 0x03);
10623	}
10624     }
10625}
10626
10627/* Functions for adjusting various TV settings */
10628
10629/* These are used by the PostSetMode() functions as well as
10630 * the display properties tool SiSCtrl.
10631 *
10632 * There is each a Set and a Get routine. The Set functions
10633 * take a value of the same range as the corresponding option.
10634 * The Get routines return a value of the same range (although
10635 * not necessarily the same value as previously set because
10636 * of the lower resolution of the respective setting compared
10637 * to the valid range).
10638 * The Get routines return -2 on error (eg. hardware does not
10639 * support this setting).
10640 * Note: The x and y positioning routines accept a position
10641 * RELATIVE to the default position. All other routines
10642 * take ABSOLUTE values.
10643 *
10644 * The Set functions will store the property regardless if TV is
10645 * currently used or not and if the hardware supports the property
10646 * or not. The Get routines will return this stored
10647 * value if TV is not currently used (because the register does
10648 * not contain the correct value then) or if the hardware supports
10649 * the respective property. This should make it easier for the
10650 * display property tool because it does not have to know the
10651 * hardware features.
10652 *
10653 * All the routines are dual head aware. It does not matter
10654 * if the function is called from the CRT1 or CRT2 session.
10655 * The values will be in pSiSEnt anyway, and read from there
10656 * if we're running dual head.
10657 */
10658
10659void SiS_SetCHTVlumabandwidthcvbs(ScrnInfoPtr pScrn, int val)
10660{
10661   SISPtr pSiS = SISPTR(pScrn);
10662#ifdef SISDUALHEAD
10663   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10664#endif
10665
10666   pSiS->chtvlumabandwidthcvbs = val;
10667#ifdef SISDUALHEAD
10668   if(pSiSEnt) pSiSEnt->chtvlumabandwidthcvbs = val;
10669#endif
10670
10671   if(!(pSiS->VBFlags & CRT2_TV)) return;
10672   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
10673
10674#ifdef UNLOCK_ALWAYS
10675   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10676#endif
10677
10678   switch(pSiS->ChrontelType) {
10679       case CHRONTEL_700x:
10680           val /= 8;
10681           if((val == 0) || (val == 1)) {
10682	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, val, 0xFE);
10683           }
10684	   break;
10685       case CHRONTEL_701x:
10686           val /= 4;
10687	   if((val >= 0) && (val <= 3)) {
10688	       SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x02, val, 0xFC);
10689	   }
10690           break;
10691   }
10692}
10693
10694int SiS_GetCHTVlumabandwidthcvbs(ScrnInfoPtr pScrn)
10695{
10696   SISPtr pSiS = SISPTR(pScrn);
10697#ifdef SISDUALHEAD
10698   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10699#endif
10700
10701   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
10702#ifdef SISDUALHEAD
10703      if(pSiSEnt && pSiS->DualHeadMode)
10704           return (int)pSiSEnt->chtvlumabandwidthcvbs;
10705      else
10706#endif
10707           return (int)pSiS->chtvlumabandwidthcvbs;
10708   } else {
10709#ifdef UNLOCK_ALWAYS
10710      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10711#endif
10712      switch(pSiS->ChrontelType) {
10713      case CHRONTEL_700x:
10714           return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x03) & 0x01) * 8);
10715      case CHRONTEL_701x:
10716	   return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x02) & 0x03) * 4);
10717      default:
10718           return (int)pSiS->chtvlumabandwidthcvbs;
10719      }
10720   }
10721}
10722
10723void SiS_SetCHTVlumabandwidthsvideo(ScrnInfoPtr pScrn, int val)
10724{
10725   SISPtr pSiS = SISPTR(pScrn);
10726#ifdef SISDUALHEAD
10727   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10728#endif
10729
10730   pSiS->chtvlumabandwidthsvideo = val;
10731#ifdef SISDUALHEAD
10732   if(pSiSEnt) pSiSEnt->chtvlumabandwidthsvideo = val;
10733#endif
10734
10735   if(!(pSiS->VBFlags & CRT2_TV)) return;
10736   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
10737
10738#ifdef UNLOCK_ALWAYS
10739   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10740#endif
10741
10742   switch(pSiS->ChrontelType) {
10743       case CHRONTEL_700x:
10744           val /= 6;
10745           if((val >= 0) && (val <= 2)) {
10746	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, (val << 1), 0xF9);
10747           }
10748	   break;
10749       case CHRONTEL_701x:
10750           val /= 4;
10751	   if((val >= 0) && (val <= 3)) {
10752	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x02, (val << 2), 0xF3);
10753	   }
10754           break;
10755   }
10756}
10757
10758int SiS_GetCHTVlumabandwidthsvideo(ScrnInfoPtr pScrn)
10759{
10760   SISPtr pSiS = SISPTR(pScrn);
10761#ifdef SISDUALHEAD
10762   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10763#endif
10764
10765   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
10766#ifdef SISDUALHEAD
10767      if(pSiSEnt && pSiS->DualHeadMode)
10768           return (int)pSiSEnt->chtvlumabandwidthsvideo;
10769      else
10770#endif
10771           return (int)pSiS->chtvlumabandwidthsvideo;
10772   } else {
10773#ifdef UNLOCK_ALWAYS
10774      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10775#endif
10776      switch(pSiS->ChrontelType) {
10777      case CHRONTEL_700x:
10778           return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x03) & 0x06) >> 1) * 6);
10779      case CHRONTEL_701x:
10780	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x02) & 0x0c) >> 2) * 4);
10781      default:
10782           return (int)pSiS->chtvlumabandwidthsvideo;
10783      }
10784   }
10785}
10786
10787void SiS_SetCHTVlumaflickerfilter(ScrnInfoPtr pScrn, int val)
10788{
10789   SISPtr pSiS = SISPTR(pScrn);
10790#ifdef SISDUALHEAD
10791   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10792#endif
10793
10794   pSiS->chtvlumaflickerfilter = val;
10795#ifdef SISDUALHEAD
10796   if(pSiSEnt) pSiSEnt->chtvlumaflickerfilter = val;
10797#endif
10798
10799   if(!(pSiS->VBFlags & CRT2_TV)) return;
10800   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
10801
10802#ifdef UNLOCK_ALWAYS
10803   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10804#endif
10805
10806   switch(pSiS->ChrontelType) {
10807       case CHRONTEL_700x:
10808           val /= 6;
10809           if((val >= 0) && (val <= 2)) {
10810	      UShort reg = 0;
10811	      reg = SiS_GetCH70xx(pSiS->SiS_Pr, 0x01);
10812	      reg = (reg & 0xf0) | ((reg & 0x0c) >> 2) | (val << 2);
10813              SiS_SetCH70xx(pSiS->SiS_Pr, 0x01, reg);
10814           }
10815	   break;
10816       case CHRONTEL_701x:
10817           val /= 4;
10818	   if((val >= 0) && (val <= 3)) {
10819	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x01, (val << 2), 0xF3);
10820	   }
10821           break;
10822   }
10823}
10824
10825int SiS_GetCHTVlumaflickerfilter(ScrnInfoPtr pScrn)
10826{
10827   SISPtr pSiS = SISPTR(pScrn);
10828#ifdef SISDUALHEAD
10829   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10830#endif
10831
10832   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
10833#ifdef SISDUALHEAD
10834      if(pSiSEnt && pSiS->DualHeadMode)
10835          return (int)pSiSEnt->chtvlumaflickerfilter;
10836      else
10837#endif
10838          return (int)pSiS->chtvlumaflickerfilter;
10839   } else {
10840#ifdef UNLOCK_ALWAYS
10841      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10842#endif
10843      switch(pSiS->ChrontelType) {
10844      case CHRONTEL_700x:
10845           return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x01) & 0x03) * 6);
10846      case CHRONTEL_701x:
10847	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x01) & 0x0c) >> 2) * 4);
10848      default:
10849           return (int)pSiS->chtvlumaflickerfilter;
10850      }
10851   }
10852}
10853
10854void SiS_SetCHTVchromabandwidth(ScrnInfoPtr pScrn, int val)
10855{
10856   SISPtr pSiS = SISPTR(pScrn);
10857#ifdef SISDUALHEAD
10858   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10859#endif
10860
10861   pSiS->chtvchromabandwidth = val;
10862#ifdef SISDUALHEAD
10863   if(pSiSEnt) pSiSEnt->chtvchromabandwidth = val;
10864#endif
10865
10866   if(!(pSiS->VBFlags & CRT2_TV)) return;
10867   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
10868
10869#ifdef UNLOCK_ALWAYS
10870   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10871#endif
10872
10873   switch(pSiS->ChrontelType) {
10874       case CHRONTEL_700x:
10875           val /= 4;
10876           if((val >= 0) && (val <= 3)) {
10877              SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, (val << 4), 0xCF);
10878           }
10879	   break;
10880       case CHRONTEL_701x:
10881           val /= 8;
10882	   if((val >= 0) && (val <= 1)) {
10883	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x02, (val << 4), 0xEF);
10884	   }
10885           break;
10886   }
10887}
10888
10889int SiS_GetCHTVchromabandwidth(ScrnInfoPtr pScrn)
10890{
10891   SISPtr pSiS = SISPTR(pScrn);
10892#ifdef SISDUALHEAD
10893   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10894#endif
10895
10896   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
10897#ifdef SISDUALHEAD
10898      if(pSiSEnt && pSiS->DualHeadMode)
10899           return (int)pSiSEnt->chtvchromabandwidth;
10900      else
10901#endif
10902           return (int)pSiS->chtvchromabandwidth;
10903   } else {
10904#ifdef UNLOCK_ALWAYS
10905      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10906#endif
10907      switch(pSiS->ChrontelType) {
10908      case CHRONTEL_700x:
10909           return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x03) & 0x30) >> 4) * 4);
10910      case CHRONTEL_701x:
10911	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x02) & 0x10) >> 4) * 8);
10912      default:
10913           return (int)pSiS->chtvchromabandwidth;
10914      }
10915   }
10916}
10917
10918void SiS_SetCHTVchromaflickerfilter(ScrnInfoPtr pScrn, int val)
10919{
10920   SISPtr pSiS = SISPTR(pScrn);
10921#ifdef SISDUALHEAD
10922   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10923#endif
10924
10925   pSiS->chtvchromaflickerfilter = val;
10926#ifdef SISDUALHEAD
10927   if(pSiSEnt) pSiSEnt->chtvchromaflickerfilter = val;
10928#endif
10929
10930   if(!(pSiS->VBFlags & CRT2_TV)) return;
10931   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
10932
10933#ifdef UNLOCK_ALWAYS
10934   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10935#endif
10936
10937   switch(pSiS->ChrontelType) {
10938       case CHRONTEL_700x:
10939           val /= 6;
10940           if((val >= 0) && (val <= 2)) {
10941	      UShort reg = 0;
10942	      reg = SiS_GetCH70xx(pSiS->SiS_Pr, 0x01);
10943	      reg = (reg & 0xc0) | ((reg & 0x0c) >> 2) | ((reg & 0x03) << 2) | (val << 4);
10944              SiS_SetCH70xx(pSiS->SiS_Pr, 0x01, reg);
10945           }
10946	   break;
10947       case CHRONTEL_701x:
10948           val /= 4;
10949	   if((val >= 0) && (val <= 3)) {
10950	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x01, (val << 4), 0xCF);
10951	   }
10952           break;
10953   }
10954}
10955
10956int SiS_GetCHTVchromaflickerfilter(ScrnInfoPtr pScrn)
10957{
10958   SISPtr pSiS = SISPTR(pScrn);
10959#ifdef SISDUALHEAD
10960   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10961#endif
10962
10963   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
10964#ifdef SISDUALHEAD
10965      if(pSiSEnt && pSiS->DualHeadMode)
10966           return (int)pSiSEnt->chtvchromaflickerfilter;
10967      else
10968#endif
10969           return (int)pSiS->chtvchromaflickerfilter;
10970   } else {
10971#ifdef UNLOCK_ALWAYS
10972      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10973#endif
10974      switch(pSiS->ChrontelType) {
10975      case CHRONTEL_700x:
10976           return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x01) & 0x30) >> 4) * 6);
10977      case CHRONTEL_701x:
10978	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x01) & 0x30) >> 4) * 4);
10979      default:
10980           return (int)pSiS->chtvchromaflickerfilter;
10981      }
10982   }
10983}
10984
10985void SiS_SetCHTVcvbscolor(ScrnInfoPtr pScrn, int val)
10986{
10987   SISPtr pSiS = SISPTR(pScrn);
10988#ifdef SISDUALHEAD
10989   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10990#endif
10991
10992   pSiS->chtvcvbscolor = val ? 1 : 0;
10993#ifdef SISDUALHEAD
10994   if(pSiSEnt) pSiSEnt->chtvcvbscolor = pSiS->chtvcvbscolor;
10995#endif
10996
10997   if(!(pSiS->VBFlags & CRT2_TV)) return;
10998   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
10999
11000#ifdef UNLOCK_ALWAYS
11001   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11002#endif
11003
11004   switch(pSiS->ChrontelType) {
11005       case CHRONTEL_700x:
11006           if(!val)  SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, 0x40, 0x00);
11007           else      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, 0x00, ~0x40);
11008	   break;
11009       case CHRONTEL_701x:
11010           if(!val)  SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x02, 0x00, ~0x20);
11011	   else      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x02, 0x20, 0x00);
11012           break;
11013   }
11014}
11015
11016int SiS_GetCHTVcvbscolor(ScrnInfoPtr pScrn)
11017{
11018   SISPtr pSiS = SISPTR(pScrn);
11019#ifdef SISDUALHEAD
11020   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11021#endif
11022
11023   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
11024#ifdef SISDUALHEAD
11025      if(pSiSEnt && pSiS->DualHeadMode)
11026           return (int)pSiSEnt->chtvcvbscolor;
11027      else
11028#endif
11029           return (int)pSiS->chtvcvbscolor;
11030   } else {
11031#ifdef UNLOCK_ALWAYS
11032      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11033#endif
11034      switch(pSiS->ChrontelType) {
11035      case CHRONTEL_700x:
11036           return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x03) & 0x40) >> 6) ^ 0x01);
11037      case CHRONTEL_701x:
11038	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x02) & 0x20) >> 5) ^ 0x01);
11039      default:
11040           return (int)pSiS->chtvcvbscolor;
11041      }
11042   }
11043}
11044
11045void SiS_SetCHTVtextenhance(ScrnInfoPtr pScrn, int val)
11046{
11047   SISPtr pSiS = SISPTR(pScrn);
11048#ifdef SISDUALHEAD
11049   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11050#endif
11051
11052   pSiS->chtvtextenhance = val;
11053#ifdef SISDUALHEAD
11054   if(pSiSEnt) pSiSEnt->chtvtextenhance = val;
11055#endif
11056
11057   if(!(pSiS->VBFlags & CRT2_TV)) return;
11058   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
11059
11060#ifdef UNLOCK_ALWAYS
11061   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11062#endif
11063
11064   switch(pSiS->ChrontelType) {
11065       case CHRONTEL_700x:
11066           val /= 6;
11067           if((val >= 0) && (val <= 2)) {
11068	      UShort reg = 0;
11069	      reg = SiS_GetCH70xx(pSiS->SiS_Pr, 0x01);
11070	      reg = (reg & 0xf0) | ((reg & 0x03) << 2) | val;
11071              SiS_SetCH70xx(pSiS->SiS_Pr, 0x01, reg);
11072           }
11073	   break;
11074       case CHRONTEL_701x:
11075           val /= 2;
11076	   if((val >= 0) && (val <= 7)) {
11077	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, val, 0xF8);
11078	   }
11079           break;
11080   }
11081}
11082
11083int SiS_GetCHTVtextenhance(ScrnInfoPtr pScrn)
11084{
11085   SISPtr pSiS = SISPTR(pScrn);
11086#ifdef SISDUALHEAD
11087   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11088#endif
11089
11090   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
11091#ifdef SISDUALHEAD
11092      if(pSiSEnt && pSiS->DualHeadMode)
11093           return (int)pSiSEnt->chtvtextenhance;
11094      else
11095#endif
11096           return (int)pSiS->chtvtextenhance;
11097   } else {
11098#ifdef UNLOCK_ALWAYS
11099      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11100#endif
11101      switch(pSiS->ChrontelType) {
11102      case CHRONTEL_700x:
11103	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x01) & 0x0c) >> 2) * 6);
11104      case CHRONTEL_701x:
11105	   return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x03) & 0x07) * 2);
11106      default:
11107           return (int)pSiS->chtvtextenhance;
11108      }
11109   }
11110}
11111
11112void SiS_SetCHTVcontrast(ScrnInfoPtr pScrn, int val)
11113{
11114   SISPtr pSiS = SISPTR(pScrn);
11115#ifdef SISDUALHEAD
11116   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11117#endif
11118
11119   pSiS->chtvcontrast = val;
11120#ifdef SISDUALHEAD
11121   if(pSiSEnt) pSiSEnt->chtvcontrast = val;
11122#endif
11123
11124   if(!(pSiS->VBFlags & CRT2_TV)) return;
11125   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
11126
11127#ifdef UNLOCK_ALWAYS
11128   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11129#endif
11130
11131   val /= 2;
11132   if((val >= 0) && (val <= 7)) {
11133       switch(pSiS->ChrontelType) {
11134       case CHRONTEL_700x:
11135              SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x11, val, 0xF8);
11136	      break;
11137       case CHRONTEL_701x:
11138	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x08, val, 0xF8);
11139              break;
11140       }
11141       SiS_DDC2Delay(pSiS->SiS_Pr, 1000);
11142   }
11143}
11144
11145int SiS_GetCHTVcontrast(ScrnInfoPtr pScrn)
11146{
11147   SISPtr pSiS = SISPTR(pScrn);
11148#ifdef SISDUALHEAD
11149   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11150#endif
11151
11152   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
11153#ifdef SISDUALHEAD
11154      if(pSiSEnt && pSiS->DualHeadMode)
11155           return (int)pSiSEnt->chtvcontrast;
11156      else
11157#endif
11158           return (int)pSiS->chtvcontrast;
11159   } else {
11160#ifdef UNLOCK_ALWAYS
11161      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11162#endif
11163      switch(pSiS->ChrontelType) {
11164      case CHRONTEL_700x:
11165           return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x11) & 0x07) * 2);
11166      case CHRONTEL_701x:
11167	   return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x08) & 0x07) * 2);
11168      default:
11169           return (int)pSiS->chtvcontrast;
11170      }
11171   }
11172}
11173
11174void SiS_SetSISTVedgeenhance(ScrnInfoPtr pScrn, int val)
11175{
11176   SISPtr pSiS = SISPTR(pScrn);
11177#ifdef SISDUALHEAD
11178   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11179#endif
11180
11181   pSiS->sistvedgeenhance = val;
11182#ifdef SISDUALHEAD
11183   if(pSiSEnt) pSiSEnt->sistvedgeenhance = val;
11184#endif
11185
11186   if(!(pSiS->VBFlags2 & VB2_301))  return;
11187   if(!(pSiS->VBFlags & CRT2_TV))   return;
11188
11189#ifdef UNLOCK_ALWAYS
11190   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11191#endif
11192
11193   val /= 2;
11194   if((val >= 0) && (val <= 7)) {
11195      setSISIDXREG(SISPART2,0x3A, 0x1F, (val << 5));
11196   }
11197}
11198
11199int SiS_GetSISTVedgeenhance(ScrnInfoPtr pScrn)
11200{
11201   SISPtr pSiS = SISPTR(pScrn);
11202   int result = pSiS->sistvedgeenhance;
11203   UChar temp;
11204#ifdef SISDUALHEAD
11205   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11206
11207   if(pSiSEnt && pSiS->DualHeadMode) result = pSiSEnt->sistvedgeenhance;
11208#endif
11209
11210   if(!(pSiS->VBFlags2 & VB2_301))  return result;
11211   if(!(pSiS->VBFlags & CRT2_TV))   return result;
11212
11213#ifdef UNLOCK_ALWAYS
11214   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11215#endif
11216   inSISIDXREG(SISPART2, 0x3a, temp);
11217   return(int)(((temp & 0xe0) >> 5) * 2);
11218}
11219
11220void SiS_SetSISTVantiflicker(ScrnInfoPtr pScrn, int val)
11221{
11222   SISPtr pSiS = SISPTR(pScrn);
11223#ifdef SISDUALHEAD
11224   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11225#endif
11226
11227   pSiS->sistvantiflicker = val;
11228#ifdef SISDUALHEAD
11229   if(pSiSEnt) pSiSEnt->sistvantiflicker = val;
11230#endif
11231
11232   if(!(pSiS->VBFlags & CRT2_TV))      return;
11233   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE)) return;
11234   if(pSiS->VBFlags & TV_HIVISION)     return;
11235   if((pSiS->VBFlags & TV_YPBPR) &&
11236      (pSiS->VBFlags & (TV_YPBPR525P | TV_YPBPR625P | TV_YPBPR750P | TV_YPBPR1080I))) return;
11237
11238#ifdef UNLOCK_ALWAYS
11239   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11240#endif
11241
11242   /* Valid values: 0=off, 1=low, 2=med, 3=high, 4=adaptive */
11243   if((val >= 0) && (val <= 4)) {
11244      setSISIDXREG(SISPART2,0x0A,0x8F, (val << 4));
11245   }
11246}
11247
11248int SiS_GetSISTVantiflicker(ScrnInfoPtr pScrn)
11249{
11250   SISPtr pSiS = SISPTR(pScrn);
11251   int result = pSiS->sistvantiflicker;
11252   UChar temp;
11253#ifdef SISDUALHEAD
11254   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11255
11256   if(pSiSEnt && pSiS->DualHeadMode) result = pSiSEnt->sistvantiflicker;
11257#endif
11258
11259   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE)) return result;
11260   if(!(pSiS->VBFlags & CRT2_TV))        return result;
11261   if(pSiS->VBFlags & TV_HIVISION)       return result;
11262   if((pSiS->VBFlags & TV_YPBPR) &&
11263      (pSiS->VBFlags & (TV_YPBPR525P | TV_YPBPR625P | TV_YPBPR750P | TV_YPBPR1080I))) return result;
11264
11265#ifdef UNLOCK_ALWAYS
11266   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11267#endif
11268   inSISIDXREG(SISPART2, 0x0a, temp);
11269   return(int)((temp & 0x70) >> 4);
11270}
11271
11272void SiS_SetSISTVsaturation(ScrnInfoPtr pScrn, int val)
11273{
11274   SISPtr pSiS = SISPTR(pScrn);
11275#ifdef SISDUALHEAD
11276   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11277#endif
11278
11279   pSiS->sistvsaturation = val;
11280#ifdef SISDUALHEAD
11281   if(pSiSEnt) pSiSEnt->sistvsaturation = val;
11282#endif
11283
11284   if(!(pSiS->VBFlags & CRT2_TV)) return;
11285   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE)) return;
11286   if(pSiS->VBFlags2 & VB2_301) return;
11287
11288#ifdef UNLOCK_ALWAYS
11289   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11290#endif
11291
11292   val /= 2;
11293   if((val >= 0) && (val <= 7)) {
11294      setSISIDXREG(SISPART4,0x21,0xF8, val);
11295   }
11296}
11297
11298int SiS_GetSISTVsaturation(ScrnInfoPtr pScrn)
11299{
11300   SISPtr pSiS = SISPTR(pScrn);
11301   int result = pSiS->sistvsaturation;
11302   UChar temp;
11303#ifdef SISDUALHEAD
11304   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11305
11306   if(pSiSEnt && pSiS->DualHeadMode)  result = pSiSEnt->sistvsaturation;
11307#endif
11308
11309   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE)) return result;
11310   if(pSiS->VBFlags2 & VB2_301)          return result;
11311   if(!(pSiS->VBFlags & CRT2_TV))        return result;
11312
11313#ifdef UNLOCK_ALWAYS
11314   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11315#endif
11316   inSISIDXREG(SISPART4, 0x21, temp);
11317   return(int)((temp & 0x07) * 2);
11318}
11319
11320void SiS_SetSISTVcolcalib(ScrnInfoPtr pScrn, int val, Bool coarse)
11321{
11322   SISPtr pSiS = SISPTR(pScrn);
11323#ifdef SISDUALHEAD
11324   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11325#endif
11326   int ccoarse, cfine, cbase = pSiS->sistvccbase;
11327   /* UChar temp; */
11328
11329#ifdef SISDUALHEAD
11330   if(pSiSEnt && pSiS->DualHeadMode) cbase = pSiSEnt->sistvccbase;
11331#endif
11332
11333   if(coarse) {
11334      pSiS->sistvcolcalibc = ccoarse = val;
11335      cfine = pSiS->sistvcolcalibf;
11336#ifdef SISDUALHEAD
11337      if(pSiSEnt) {
11338         pSiSEnt->sistvcolcalibc = val;
11339	 if(pSiS->DualHeadMode) cfine = pSiSEnt->sistvcolcalibf;
11340      }
11341#endif
11342   } else {
11343      pSiS->sistvcolcalibf = cfine = val;
11344      ccoarse = pSiS->sistvcolcalibc;
11345#ifdef SISDUALHEAD
11346      if(pSiSEnt) {
11347         pSiSEnt->sistvcolcalibf = val;
11348         if(pSiS->DualHeadMode) ccoarse = pSiSEnt->sistvcolcalibc;
11349      }
11350#endif
11351   }
11352
11353   if(!(pSiS->VBFlags & CRT2_TV))               return;
11354   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE))        return;
11355   if(pSiS->VBFlags & (TV_HIVISION | TV_YPBPR)) return;
11356
11357#ifdef UNLOCK_ALWAYS
11358   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11359#endif
11360
11361   if((cfine >= -128) && (cfine <= 127) && (ccoarse >= -120) && (ccoarse <= 120)) {
11362      long finalcc = cbase + (((ccoarse * 256) + cfine) * 256);
11363
11364#if 0
11365      inSISIDXREG(SISPART4,0x1f,temp);
11366      if(!(temp & 0x01)) {
11367         if(pSiS->VBFlags & TV_NTSC) finalcc += 0x21ed8620;
11368	 else if(pSiS->VBFlags & TV_PALM) finalcc += ?;
11369	 else if(pSiS->VBFlags & TV_PALM) finalcc += ?;
11370	 else finalcc += 0x2a05d300;
11371      }
11372#endif
11373      setSISIDXREG(SISPART2,0x31,0x80,((finalcc >> 24) & 0x7f));
11374      outSISIDXREG(SISPART2,0x32,((finalcc >> 16) & 0xff));
11375      outSISIDXREG(SISPART2,0x33,((finalcc >> 8) & 0xff));
11376      outSISIDXREG(SISPART2,0x34,(finalcc & 0xff));
11377   }
11378}
11379
11380int SiS_GetSISTVcolcalib(ScrnInfoPtr pScrn, Bool coarse)
11381{
11382   SISPtr pSiS = SISPTR(pScrn);
11383#ifdef SISDUALHEAD
11384   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11385
11386   if(pSiSEnt && pSiS->DualHeadMode)
11387      if(coarse)  return (int)pSiSEnt->sistvcolcalibc;
11388      else        return (int)pSiSEnt->sistvcolcalibf;
11389   else
11390#endif
11391   if(coarse)     return (int)pSiS->sistvcolcalibc;
11392   else           return (int)pSiS->sistvcolcalibf;
11393}
11394
11395void SiS_SetSISTVcfilter(ScrnInfoPtr pScrn, int val)
11396{
11397   SISPtr pSiS = SISPTR(pScrn);
11398#ifdef SISDUALHEAD
11399   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11400#endif
11401
11402   pSiS->sistvcfilter = val ? 1 : 0;
11403#ifdef SISDUALHEAD
11404   if(pSiSEnt) pSiSEnt->sistvcfilter = pSiS->sistvcfilter;
11405#endif
11406
11407   if(!(pSiS->VBFlags & CRT2_TV))               return;
11408   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE))        return;
11409   if(pSiS->VBFlags & (TV_HIVISION | TV_YPBPR)) return;
11410
11411#ifdef UNLOCK_ALWAYS
11412   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11413#endif
11414
11415   setSISIDXREG(SISPART2,0x30,~0x10,((pSiS->sistvcfilter << 4) & 0x10));
11416}
11417
11418int SiS_GetSISTVcfilter(ScrnInfoPtr pScrn)
11419{
11420   SISPtr pSiS = SISPTR(pScrn);
11421   int result = pSiS->sistvcfilter;
11422   UChar temp;
11423#ifdef SISDUALHEAD
11424   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11425
11426   if(pSiSEnt && pSiS->DualHeadMode) result = pSiSEnt->sistvcfilter;
11427#endif
11428
11429   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE))        return result;
11430   if(!(pSiS->VBFlags & CRT2_TV))               return result;
11431   if(pSiS->VBFlags & (TV_HIVISION | TV_YPBPR)) return result;
11432
11433#ifdef UNLOCK_ALWAYS
11434   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11435#endif
11436   inSISIDXREG(SISPART2, 0x30, temp);
11437   return (int)((temp & 0x10) ? 1 : 0);
11438}
11439
11440void SiS_SetSISTVyfilter(ScrnInfoPtr pScrn, int val)
11441{
11442   SISPtr pSiS = SISPTR(pScrn);
11443#ifdef SISDUALHEAD
11444   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11445#endif
11446   UChar p35,p36,p37,p38,p48,p49,p4a,p30;
11447   int i,j;
11448
11449   pSiS->sistvyfilter = val;
11450#ifdef SISDUALHEAD
11451   if(pSiSEnt) pSiSEnt->sistvyfilter = pSiS->sistvyfilter;
11452#endif
11453
11454   if(!(pSiS->VBFlags & CRT2_TV))               return;
11455   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE))        return;
11456   if(pSiS->VBFlags & (TV_HIVISION | TV_YPBPR)) return;
11457
11458   p35 = pSiS->p2_35; p36 = pSiS->p2_36;
11459   p37 = pSiS->p2_37; p38 = pSiS->p2_38;
11460   p48 = pSiS->p2_48; p49 = pSiS->p2_49;
11461   p4a = pSiS->p2_4a; p30 = pSiS->p2_30;
11462#ifdef SISDUALHEAD
11463   if(pSiSEnt && pSiS->DualHeadMode) {
11464      p35 = pSiSEnt->p2_35; p36 = pSiSEnt->p2_36;
11465      p37 = pSiSEnt->p2_37; p38 = pSiSEnt->p2_38;
11466      p48 = pSiSEnt->p2_48; p49 = pSiSEnt->p2_49;
11467      p4a = pSiSEnt->p2_4a; p30 = pSiSEnt->p2_30;
11468   }
11469#endif
11470   p30 &= 0x20;
11471
11472#ifdef UNLOCK_ALWAYS
11473   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11474#endif
11475
11476   switch(pSiS->sistvyfilter) {
11477   case 0:
11478      andSISIDXREG(SISPART2,0x30,0xdf);
11479      break;
11480   case 1:
11481      outSISIDXREG(SISPART2,0x35,p35);
11482      outSISIDXREG(SISPART2,0x36,p36);
11483      outSISIDXREG(SISPART2,0x37,p37);
11484      outSISIDXREG(SISPART2,0x38,p38);
11485      if(!(pSiS->VBFlags2 & VB2_301)) {
11486         outSISIDXREG(SISPART2,0x48,p48);
11487         outSISIDXREG(SISPART2,0x49,p49);
11488         outSISIDXREG(SISPART2,0x4a,p4a);
11489      }
11490      setSISIDXREG(SISPART2,0x30,0xdf,p30);
11491      break;
11492   case 2:
11493   case 3:
11494   case 4:
11495   case 5:
11496   case 6:
11497   case 7:
11498   case 8:
11499      if(!(pSiS->VBFlags & (TV_PALM | TV_PALN | TV_NTSCJ))) {
11500         int yindex301 = -1, yindex301B = -1;
11501	 UChar p3d4_34;
11502
11503	 inSISIDXREG(SISCR,0x34,p3d4_34);
11504
11505	 switch((p3d4_34 & 0x7f)) {
11506	 case 0x59:  /* 320x200 */
11507	 case 0x41:
11508	 case 0x4f:
11509	 case 0x50:  /* 320x240 */
11510	 case 0x56:
11511	 case 0x53:
11512	    yindex301  = (pSiS->VBFlags & TV_NTSC) ? 0 : 4;
11513	    break;
11514	 case 0x2f:  /* 640x400 */
11515	 case 0x5d:
11516	 case 0x5e:
11517	 case 0x2e:  /* 640x480 */
11518	 case 0x44:
11519	 case 0x62:
11520	    yindex301  = (pSiS->VBFlags & TV_NTSC) ? 1 : 5;
11521	    yindex301B = (pSiS->VBFlags & TV_NTSC) ? 0 : 4;
11522	    break;
11523	 case 0x31:   /* 720x480 */
11524	 case 0x33:
11525	 case 0x35:
11526	 case 0x32:   /* 720x576 */
11527	 case 0x34:
11528	 case 0x36:
11529	 case 0x5f:   /* 768x576 */
11530	 case 0x60:
11531	 case 0x61:
11532	    yindex301  = (pSiS->VBFlags & TV_NTSC) ? 2 : 6;
11533	    yindex301B = (pSiS->VBFlags & TV_NTSC) ? 1 : 5;
11534	    break;
11535	 case 0x51:   /* 400x300 */
11536	 case 0x57:
11537	 case 0x54:
11538	 case 0x30:   /* 800x600 */
11539	 case 0x47:
11540	 case 0x63:
11541	    yindex301  = (pSiS->VBFlags & TV_NTSC) ? 3 : 7;
11542	    yindex301B = (pSiS->VBFlags & TV_NTSC) ? 2 : 6;
11543	    break;
11544	 case 0x52:   /* 512x384 */
11545	 case 0x58:
11546	 case 0x5c:
11547	 case 0x38:   /* 1024x768 */
11548	 case 0x4a:
11549	 case 0x64:
11550	    yindex301B = (pSiS->VBFlags & TV_NTSC) ? 3 : 7;
11551	    break;
11552	 }
11553         if(pSiS->VBFlags2 & VB2_301) {
11554            if(yindex301 >= 0) {
11555	       for(i=0, j=0x35; i<=3; i++, j++) {
11556	          outSISIDXREG(SISPART2,j,(SiSTVFilter301[yindex301].filter[pSiS->sistvyfilter-2][i]));
11557	       }
11558	    }
11559         } else {
11560            if(yindex301B >= 0) {
11561	       for(i=0, j=0x35; i<=3; i++, j++) {
11562	          outSISIDXREG(SISPART2,j,(SiSTVFilter301B[yindex301B].filter[pSiS->sistvyfilter-2][i]));
11563	       }
11564	       for(i=4, j=0x48; i<=6; i++, j++) {
11565	          outSISIDXREG(SISPART2,j,(SiSTVFilter301B[yindex301B].filter[pSiS->sistvyfilter-2][i]));
11566	       }
11567	    }
11568         }
11569         orSISIDXREG(SISPART2,0x30,0x20);
11570      }
11571   }
11572}
11573
11574int SiS_GetSISTVyfilter(ScrnInfoPtr pScrn)
11575{
11576   SISPtr pSiS = SISPTR(pScrn);
11577#ifdef SISDUALHEAD
11578   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11579
11580   if(pSiSEnt && pSiS->DualHeadMode)
11581      return (int)pSiSEnt->sistvyfilter;
11582   else
11583#endif
11584      return (int)pSiS->sistvyfilter;
11585}
11586
11587void SiS_SetSIS6326TVantiflicker(ScrnInfoPtr pScrn, int val)
11588{
11589   SISPtr pSiS = SISPTR(pScrn);
11590   UChar tmp;
11591
11592   pSiS->sistvantiflicker = val;
11593
11594   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) return;
11595
11596#ifdef UNLOCK_ALWAYS
11597   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11598#endif
11599
11600   tmp = SiS6326GetTVReg(pScrn,0x00);
11601   if(!(tmp & 0x04)) return;
11602
11603   /* Valid values: 0=off, 1=low, 2=med, 3=high, 4=adaptive */
11604   if(val >= 0 && val <= 4) {
11605      tmp &= 0x1f;
11606      tmp |= (val << 5);
11607      SiS6326SetTVReg(pScrn,0x00,tmp);
11608   }
11609}
11610
11611int SiS_GetSIS6326TVantiflicker(ScrnInfoPtr pScrn)
11612{
11613   SISPtr pSiS = SISPTR(pScrn);
11614   UChar tmp;
11615
11616   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) {
11617      return (int)pSiS->sistvantiflicker;
11618   }
11619
11620#ifdef UNLOCK_ALWAYS
11621   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11622#endif
11623
11624   tmp = SiS6326GetTVReg(pScrn,0x00);
11625   if(!(tmp & 0x04)) {
11626      return (int)pSiS->sistvantiflicker;
11627   } else {
11628      return (int)((tmp >> 5) & 0x07);
11629   }
11630}
11631
11632void SiS_SetSIS6326TVenableyfilter(ScrnInfoPtr pScrn, int val)
11633{
11634   SISPtr pSiS = SISPTR(pScrn);
11635   UChar tmp;
11636
11637   if(val) val = 1;
11638   pSiS->sis6326enableyfilter = val;
11639
11640   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) return;
11641
11642#ifdef UNLOCK_ALWAYS
11643   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11644#endif
11645
11646   tmp = SiS6326GetTVReg(pScrn,0x00);
11647   if(!(tmp & 0x04)) return;
11648
11649   tmp = SiS6326GetTVReg(pScrn,0x43);
11650   tmp &= ~0x10;
11651   tmp |= ((val & 0x01) << 4);
11652   SiS6326SetTVReg(pScrn,0x43,tmp);
11653}
11654
11655int SiS_GetSIS6326TVenableyfilter(ScrnInfoPtr pScrn)
11656{
11657   SISPtr pSiS = SISPTR(pScrn);
11658   UChar tmp;
11659
11660   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) {
11661      return (int)pSiS->sis6326enableyfilter;
11662   }
11663
11664#ifdef UNLOCK_ALWAYS
11665   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11666#endif
11667
11668   tmp = SiS6326GetTVReg(pScrn,0x00);
11669   if(!(tmp & 0x04)) {
11670      return (int)pSiS->sis6326enableyfilter;
11671   } else {
11672      tmp = SiS6326GetTVReg(pScrn,0x43);
11673      return (int)((tmp >> 4) & 0x01);
11674   }
11675}
11676
11677void SiS_SetSIS6326TVyfilterstrong(ScrnInfoPtr pScrn, int val)
11678{
11679   SISPtr pSiS = SISPTR(pScrn);
11680   UChar tmp;
11681
11682   if(val) val = 1;
11683   pSiS->sis6326yfilterstrong = val;
11684
11685   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) return;
11686
11687#ifdef UNLOCK_ALWAYS
11688   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11689#endif
11690
11691   tmp = SiS6326GetTVReg(pScrn,0x00);
11692   if(!(tmp & 0x04)) return;
11693
11694   tmp = SiS6326GetTVReg(pScrn,0x43);
11695   if(tmp & 0x10) {
11696      tmp &= ~0x40;
11697      tmp |= ((val & 0x01) << 6);
11698      SiS6326SetTVReg(pScrn,0x43,tmp);
11699   }
11700}
11701
11702int SiS_GetSIS6326TVyfilterstrong(ScrnInfoPtr pScrn)
11703{
11704   SISPtr pSiS = SISPTR(pScrn);
11705   UChar tmp;
11706
11707   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) {
11708      return (int)pSiS->sis6326yfilterstrong;
11709   }
11710
11711#ifdef UNLOCK_ALWAYS
11712   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11713#endif
11714
11715   tmp = SiS6326GetTVReg(pScrn,0x00);
11716   if(!(tmp & 0x04)) {
11717      return (int)pSiS->sis6326yfilterstrong;
11718   } else {
11719      tmp = SiS6326GetTVReg(pScrn,0x43);
11720      if(!(tmp & 0x10)) {
11721         return (int)pSiS->sis6326yfilterstrong;
11722      } else {
11723         return (int)((tmp >> 6) & 0x01);
11724      }
11725   }
11726}
11727
11728void SiS_SetTVxposoffset(ScrnInfoPtr pScrn, int val)
11729{
11730   SISPtr pSiS = SISPTR(pScrn);
11731#ifdef SISDUALHEAD
11732   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11733#endif
11734
11735#ifdef UNLOCK_ALWAYS
11736   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11737#endif
11738
11739   pSiS->tvxpos = val;
11740#ifdef SISDUALHEAD
11741   if(pSiSEnt) pSiSEnt->tvxpos = val;
11742#endif
11743
11744   if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
11745
11746      if(pSiS->VBFlags & CRT2_TV) {
11747
11748         if(pSiS->VBFlags2 & VB2_CHRONTEL) {
11749
11750	    int x = pSiS->tvx;
11751#ifdef SISDUALHEAD
11752	    if(pSiSEnt && pSiS->DualHeadMode) x = pSiSEnt->tvx;
11753#endif
11754	    switch(pSiS->ChrontelType) {
11755	    case CHRONTEL_700x:
11756	       if((val >= -32) && (val <= 32)) {
11757		   x += val;
11758		   if(x < 0) x = 0;
11759		   SiS_SetCH700x(pSiS->SiS_Pr, 0x0a, (x & 0xff));
11760		   SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x08, ((x & 0x0100) >> 7), 0xFD);
11761	       }
11762	       break;
11763	    case CHRONTEL_701x:
11764	       /* Not supported by hardware */
11765	       break;
11766	    }
11767
11768	 } else if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
11769
11770	    if((val >= -32) && (val <= 32)) {
11771
11772	        UChar p2_1f,p2_20,p2_2b,p2_42,p2_43;
11773		UShort temp;
11774		int mult;
11775
11776		p2_1f = pSiS->p2_1f;
11777		p2_20 = pSiS->p2_20;
11778		p2_2b = pSiS->p2_2b;
11779		p2_42 = pSiS->p2_42;
11780		p2_43 = pSiS->p2_43;
11781#ifdef SISDUALHEAD
11782	        if(pSiSEnt && pSiS->DualHeadMode) {
11783		   p2_1f = pSiSEnt->p2_1f;
11784		   p2_20 = pSiSEnt->p2_20;
11785		   p2_2b = pSiSEnt->p2_2b;
11786		   p2_42 = pSiSEnt->p2_42;
11787		   p2_43 = pSiSEnt->p2_43;
11788		}
11789#endif
11790		mult = 2;
11791		if(pSiS->VBFlags & TV_YPBPR) {
11792		   if(pSiS->VBFlags & (TV_YPBPR1080I | TV_YPBPR750P)) {
11793		      mult = 4;
11794		   }
11795		}
11796
11797		temp = p2_1f | ((p2_20 & 0xf0) << 4);
11798		temp += (val * mult);
11799		p2_1f = temp & 0xff;
11800		p2_20 = (temp & 0xf00) >> 4;
11801		p2_2b = ((p2_2b & 0x0f) + (val * mult)) & 0x0f;
11802		temp = p2_43 | ((p2_42 & 0xf0) << 4);
11803		temp += (val * mult);
11804		p2_43 = temp & 0xff;
11805		p2_42 = (temp & 0xf00) >> 4;
11806		SISWaitRetraceCRT2(pScrn);
11807	        outSISIDXREG(SISPART2,0x1f,p2_1f);
11808		setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
11809		setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
11810		setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
11811		outSISIDXREG(SISPART2,0x43,p2_43);
11812	     }
11813	 }
11814      }
11815
11816   } else if(pSiS->Chipset == PCI_CHIP_SIS6326) {
11817
11818      if(pSiS->SiS6326Flags & SIS6326_TVDETECTED) {
11819
11820         UChar tmp;
11821	 UShort temp1, temp2, temp3;
11822
11823         tmp = SiS6326GetTVReg(pScrn,0x00);
11824         if(tmp & 0x04) {
11825
11826	    temp1 = pSiS->tvx1;
11827            temp2 = pSiS->tvx2;
11828            temp3 = pSiS->tvx3;
11829            if((val >= -16) && (val <= 16)) {
11830	       if(val > 0) {
11831	          temp1 += (val * 4);
11832	          temp2 += (val * 4);
11833	          while((temp1 > 0x0fff) || (temp2 > 0x0fff)) {
11834	             temp1 -= 4;
11835		     temp2 -= 4;
11836	          }
11837	       } else {
11838	          val = -val;
11839	          temp3 += (val * 4);
11840	          while(temp3 > 0x03ff) {
11841	     	     temp3 -= 4;
11842	          }
11843	       }
11844            }
11845            SiS6326SetTVReg(pScrn,0x3a,(temp1 & 0xff));
11846            tmp = SiS6326GetTVReg(pScrn,0x3c);
11847            tmp &= 0xf0;
11848            tmp |= ((temp1 & 0x0f00) >> 8);
11849            SiS6326SetTVReg(pScrn,0x3c,tmp);
11850            SiS6326SetTVReg(pScrn,0x26,(temp2 & 0xff));
11851            tmp = SiS6326GetTVReg(pScrn,0x27);
11852            tmp &= 0x0f;
11853            tmp |= ((temp2 & 0x0f00) >> 4);
11854            SiS6326SetTVReg(pScrn,0x27,tmp);
11855            SiS6326SetTVReg(pScrn,0x12,(temp3 & 0xff));
11856            tmp = SiS6326GetTVReg(pScrn,0x13);
11857            tmp &= ~0xC0;
11858            tmp |= ((temp3 & 0x0300) >> 2);
11859            SiS6326SetTVReg(pScrn,0x13,tmp);
11860	 }
11861      }
11862   }
11863}
11864
11865int SiS_GetTVxposoffset(ScrnInfoPtr pScrn)
11866{
11867   SISPtr pSiS = SISPTR(pScrn);
11868#ifdef SISDUALHEAD
11869   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11870
11871   if(pSiSEnt && pSiS->DualHeadMode)
11872        return (int)pSiSEnt->tvxpos;
11873   else
11874#endif
11875        return (int)pSiS->tvxpos;
11876}
11877
11878void SiS_SetTVyposoffset(ScrnInfoPtr pScrn, int val)
11879{
11880   SISPtr pSiS = SISPTR(pScrn);
11881#ifdef SISDUALHEAD
11882   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11883#endif
11884
11885#ifdef UNLOCK_ALWAYS
11886   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11887#endif
11888
11889   pSiS->tvypos = val;
11890#ifdef SISDUALHEAD
11891   if(pSiSEnt) pSiSEnt->tvypos = val;
11892#endif
11893
11894   if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
11895
11896      if(pSiS->VBFlags & CRT2_TV) {
11897
11898         if(pSiS->VBFlags2 & VB2_CHRONTEL) {
11899
11900	    int y = pSiS->tvy;
11901#ifdef SISDUALHEAD
11902	    if(pSiSEnt && pSiS->DualHeadMode) y = pSiSEnt->tvy;
11903#endif
11904	    switch(pSiS->ChrontelType) {
11905	    case CHRONTEL_700x:
11906	       if((val >= -32) && (val <= 32)) {
11907		   y -= val;
11908		   if(y < 0) y = 0;
11909		   SiS_SetCH700x(pSiS->SiS_Pr, 0x0b, (y & 0xff));
11910		   SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x08, ((y & 0x0100) >> 8), 0xFE);
11911	       }
11912	       break;
11913	    case CHRONTEL_701x:
11914	       /* Not supported by hardware */
11915	       break;
11916	    }
11917
11918	 } else if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
11919
11920	    if((val >= -32) && (val <= 32)) {
11921		char p2_01, p2_02;
11922
11923		if( (pSiS->VBFlags & TV_HIVISION) ||
11924		    ((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & (TV_YPBPR1080I|TV_YPBPR750P))) ) {
11925		   val *= 2;
11926		} else {
11927		   val /= 2;  /* 4 */
11928		}
11929
11930		p2_01 = pSiS->p2_01;
11931		p2_02 = pSiS->p2_02;
11932#ifdef SISDUALHEAD
11933	        if(pSiSEnt && pSiS->DualHeadMode) {
11934		   p2_01 = pSiSEnt->p2_01;
11935		   p2_02 = pSiSEnt->p2_02;
11936		}
11937#endif
11938		p2_01 += val; /* val * 2 */
11939		p2_02 += val; /* val * 2 */
11940		if(!(pSiS->VBFlags & (TV_YPBPR | TV_HIVISION))) {
11941		   while((p2_01 <= 0) || (p2_02 <= 0)) {
11942		      p2_01 += 2;
11943		      p2_02 += 2;
11944		   }
11945		} else if((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR1080I)) {
11946		   while(p2_01 <= 8) {
11947		      p2_01 += 2;
11948		      p2_02 += 2;
11949		   }
11950		} else if((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR750P)) {
11951		   while(p2_01 <= 10) {
11952		      p2_01 += 2;
11953		      p2_02 += 2;
11954		   }
11955		}
11956
11957		SISWaitRetraceCRT2(pScrn);
11958		outSISIDXREG(SISPART2,0x01,p2_01);
11959		outSISIDXREG(SISPART2,0x02,p2_02);
11960	     }
11961	 }
11962
11963      }
11964
11965   } else if(pSiS->Chipset == PCI_CHIP_SIS6326) {
11966
11967      if(pSiS->SiS6326Flags & SIS6326_TVDETECTED) {
11968
11969         UChar tmp;
11970	 int temp1, limit;
11971
11972         tmp = SiS6326GetTVReg(pScrn,0x00);
11973         if(tmp & 0x04) {
11974
11975	    if((val >= -16) && (val <= 16)) {
11976	      temp1 = (UShort)pSiS->tvy1;
11977	      limit = (pSiS->SiS6326Flags & SIS6326_TVPAL) ? 625 : 525;
11978	      if(val > 0) {
11979                temp1 += (val * 4);
11980	        if(temp1 > limit) temp1 -= limit;
11981	      } else {
11982	        val = -val;
11983	        temp1 -= (val * 2);
11984	        if(temp1 <= 0) temp1 += (limit -1);
11985	      }
11986	      SiS6326SetTVReg(pScrn,0x11,(temp1 & 0xff));
11987	      tmp = SiS6326GetTVReg(pScrn,0x13);
11988	      tmp &= ~0x30;
11989	      tmp |= ((temp1 & 0x300) >> 4);
11990	      SiS6326SetTVReg(pScrn,0x13,tmp);
11991	      if(temp1 == 1)                                 tmp = 0x10;
11992	      else {
11993	       if(pSiS->SiS6326Flags & SIS6326_TVPAL) {
11994	         if((temp1 <= 3) || (temp1 >= (limit - 2)))  tmp = 0x08;
11995	         else if(temp1 < 22)		 	     tmp = 0x02;
11996	         else 					     tmp = 0x04;
11997	       } else {
11998	         if((temp1 <= 5) || (temp1 >= (limit - 4)))  tmp = 0x08;
11999	         else if(temp1 < 19)			     tmp = 0x02;
12000	         else 					     tmp = 0x04;
12001	       }
12002	     }
12003	     SiS6326SetTVReg(pScrn,0x21,tmp);
12004           }
12005	 }
12006      }
12007   }
12008}
12009
12010int SiS_GetTVyposoffset(ScrnInfoPtr pScrn)
12011{
12012   SISPtr pSiS = SISPTR(pScrn);
12013#ifdef SISDUALHEAD
12014   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12015
12016   if(pSiSEnt && pSiS->DualHeadMode)
12017        return (int)pSiSEnt->tvypos;
12018   else
12019#endif
12020        return (int)pSiS->tvypos;
12021}
12022
12023void SiS_SetTVxscale(ScrnInfoPtr pScrn, int val)
12024{
12025   SISPtr pSiS = SISPTR(pScrn);
12026#ifdef SISDUALHEAD
12027   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12028#endif
12029
12030#ifdef UNLOCK_ALWAYS
12031   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
12032#endif
12033
12034   pSiS->tvxscale = val;
12035#ifdef SISDUALHEAD
12036   if(pSiSEnt) pSiSEnt->tvxscale = val;
12037#endif
12038
12039   if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
12040
12041      if((pSiS->VBFlags & CRT2_TV) && (pSiS->VBFlags2 & VB2_SISBRIDGE)) {
12042
12043	 if((val >= -16) && (val <= 16)) {
12044
12045	    UChar p2_44,p2_45,p2_46;
12046	    int scalingfactor, mult;
12047
12048	    p2_44 = pSiS->p2_44;
12049	    p2_45 = pSiS->p2_45 & 0x3f;
12050	    p2_46 = pSiS->p2_46 & 0x07;
12051#ifdef SISDUALHEAD
12052	    if(pSiSEnt && pSiS->DualHeadMode) {
12053	       p2_44 = pSiSEnt->p2_44;
12054	       p2_45 = pSiSEnt->p2_45 & 0x3f;
12055	       p2_46 = pSiSEnt->p2_46 & 0x07;
12056	    }
12057#endif
12058	    scalingfactor = (p2_46 << 13) | ((p2_45 & 0x1f) << 8) | p2_44;
12059
12060	    mult = 64;
12061	    if(pSiS->VBFlags & TV_YPBPR) {
12062	       if(pSiS->VBFlags & TV_YPBPR1080I) {
12063	          mult = 190;
12064	       } else if(pSiS->VBFlags & TV_YPBPR750P) {
12065	          mult = 360;
12066	       }
12067	    } else if(pSiS->VBFlags & TV_HIVISION) {
12068	       mult = 190;
12069	    }
12070
12071	    if(val < 0) {
12072	       p2_45 &= 0xdf;
12073	       scalingfactor += ((-val) * mult);
12074	       if(scalingfactor > 0xffff) scalingfactor = 0xffff;
12075	    } else if(val > 0) {
12076	       p2_45 &= 0xdf;
12077	       scalingfactor -= (val * mult);
12078	       if(scalingfactor < 1) scalingfactor = 1;
12079	    }
12080
12081	    p2_44 = scalingfactor & 0xff;
12082	    p2_45 &= 0xe0;
12083	    p2_45 |= ((scalingfactor >> 8) & 0x1f);
12084	    p2_46 = ((scalingfactor >> 13) & 0x07);
12085
12086	    SISWaitRetraceCRT2(pScrn);
12087	    outSISIDXREG(SISPART2,0x44,p2_44);
12088	    setSISIDXREG(SISPART2,0x45,0xC0,p2_45);
12089	    if(!(pSiS->VBFlags2 & VB2_301)) {
12090	       setSISIDXREG(SISPART2,0x46,0xF8,p2_46);
12091	    }
12092
12093	 }
12094
12095      }
12096
12097   }
12098}
12099
12100int SiS_GetTVxscale(ScrnInfoPtr pScrn)
12101{
12102   SISPtr pSiS = SISPTR(pScrn);
12103#ifdef SISDUALHEAD
12104   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12105
12106   if(pSiSEnt && pSiS->DualHeadMode)
12107        return (int)pSiSEnt->tvxscale;
12108   else
12109#endif
12110        return (int)pSiS->tvxscale;
12111}
12112
12113void SiS_SetTVyscale(ScrnInfoPtr pScrn, int val)
12114{
12115   SISPtr pSiS = SISPTR(pScrn);
12116#ifdef SISDUALHEAD
12117   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12118#endif
12119
12120#ifdef UNLOCK_ALWAYS
12121   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
12122#endif
12123
12124   if(val < -4) val = -4;
12125   if(val > 3)  val = 3;
12126
12127   pSiS->tvyscale = val;
12128#ifdef SISDUALHEAD
12129   if(pSiSEnt) pSiSEnt->tvyscale = val;
12130#endif
12131
12132   if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
12133
12134      if((pSiS->VBFlags & CRT2_TV) && (pSiS->VBFlags2 & VB2_SISBRIDGE)) {
12135
12136	 int srindex = -1, newvde, i = 0, j, vlimit, temp, vdediv;
12137	 int hdclk = 0;
12138	 UChar p3d4_34;
12139	 Bool found = FALSE;
12140	 Bool usentsc = FALSE;
12141	 Bool is750p = FALSE;
12142	 Bool is1080i = FALSE;
12143	 Bool skipmoveup = FALSE;
12144
12145	 SiS_UnLockCRT2(pSiS->SiS_Pr);
12146
12147	 if((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR525P)) {
12148	    vlimit = 525 - 7;
12149	    vdediv = 1;
12150	    usentsc = TRUE;
12151	 } else if((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR625P)) {
12152	    vlimit = 625 - 7;
12153	    vdediv = 1;
12154	 } else if((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR750P)) {
12155	    vlimit = 750 - 7;
12156	    vdediv = 1;
12157	    is750p = TRUE;
12158	 } else if(((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR1080I)) ||
12159	           (pSiS->VBFlags & TV_HIVISION)) {
12160	    vlimit = (1125 - 7) / 2;
12161	    vdediv = 2;
12162	    is1080i = TRUE;
12163	 } else {
12164	    if( ((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR525I)) ||
12165	        ((!(pSiS->VBFlags & TV_YPBPR)) && (pSiS->VBFlags & (TV_NTSC | TV_PALM))) ) {
12166	       usentsc = TRUE;
12167	    }
12168	    vlimit = usentsc ? 259 : 309;
12169	    vdediv = 2;
12170	 }
12171
12172	 inSISIDXREG(SISCR,0x34,p3d4_34);
12173
12174	 switch((p3d4_34 & 0x7f)) {
12175	 case 0x50:   /* 320x240 */
12176	 case 0x56:
12177	 case 0x53:
12178	    hdclk = 1;
12179	    /* fall through */
12180	 case 0x2e:   /* 640x480 */
12181	 case 0x44:
12182	 case 0x62:
12183	    if(is1080i) {
12184	       srindex = 98;
12185	    } else if(is750p) {
12186	       srindex = 42;
12187	    } else {
12188	       srindex  = usentsc ? 0 : 21;
12189	    }
12190	    break;
12191	 case 0x31:   /* 720x480 */
12192	 case 0x33:
12193	 case 0x35:
12194	    if(is1080i) {
12195	       /* n/a */
12196	    } else if(is750p) {
12197	       srindex = 49;
12198	    } else {
12199	       srindex = usentsc ? 7 : 21;
12200	    }
12201	    break;
12202	 case 0x32:   /* 720x576 */
12203	 case 0x34:
12204	 case 0x36:
12205	 case 0x5f:   /* 768x576 */
12206	 case 0x60:
12207	 case 0x61:
12208	    if(is1080i) {
12209	       /* n/a */
12210	    } else if(is750p) {
12211	       srindex = 56;
12212	    } else {
12213	       srindex  = usentsc ? 147 : 28;
12214	    }
12215	    break;
12216	 case 0x70:   /* 800x480 */
12217	 case 0x7a:
12218	 case 0x76:
12219	    if(is1080i) {
12220	       srindex = 105;
12221	    } else if(is750p) {
12222	       srindex = 63;
12223	    } else {
12224	       srindex = usentsc ? 175 : 21;
12225	    }
12226	    break;
12227	 case 0x51:   /* 400x300 - hdclk mode */
12228	 case 0x57:
12229	 case 0x54:
12230	    hdclk = 1;
12231	    /* fall through */
12232	 case 0x30:   /* 800x600 */
12233	 case 0x47:
12234	 case 0x63:
12235	    if(is1080i) {
12236	       srindex = 112;
12237	    } else if(is750p) {
12238	       srindex = 70;
12239	    } else {
12240	       srindex = usentsc ? 14 : 35;
12241	    }
12242	    break;
12243	 case 0x1d:	/* 960x540 */
12244	 case 0x1e:
12245	 case 0x1f:
12246	    if(is1080i) {
12247	       srindex = 196;
12248	       skipmoveup = TRUE;
12249	    }
12250	    break;
12251	 case 0x20:	/* 960x600 */
12252	 case 0x21:
12253	 case 0x22:
12254	    if(pSiS->VGAEngine == SIS_315_VGA && is1080i) {
12255	       srindex = 203;
12256	    }
12257	    break;
12258	 case 0x71:	/* 1024x576 */
12259	 case 0x74:
12260	 case 0x77:
12261	    if(is1080i) {
12262	       srindex = 119;
12263	    } else if(is750p) {
12264	       srindex = 77;
12265	    } else {
12266	       srindex  = usentsc ? 182 : 189;
12267	    }
12268	    break;
12269	 case 0x52:	/* 512x384 */
12270	 case 0x58:
12271	 case 0x5c:
12272	    hdclk = 1;
12273	    /* fall through */
12274	 case 0x38:	/* 1024x768 */
12275	 case 0x4a:
12276	 case 0x64:
12277	    if(is1080i) {
12278	       srindex = 126;
12279	    } else if(is750p) {
12280	       srindex = 84;
12281	    } else if(!usentsc) {
12282	       srindex = 154;
12283	    } else if(vdediv == 1) {
12284	       if(!hdclk) srindex = 168;
12285	    } else {
12286	       if(!hdclk) srindex = 161;
12287	    }
12288	    break;
12289	 case 0x79:	/* 1280x720 */
12290	 case 0x75:
12291	 case 0x78:
12292	    if(is1080i) {
12293	       srindex = 133;
12294	    } else if(is750p) {
12295	       srindex = 91;
12296	    }
12297	    break;
12298	 case 0x3a:	/* 1280x1024 */
12299	 case 0x4d:
12300	 case 0x65:
12301	    if(is1080i) {
12302	       srindex = 140;
12303	    }
12304	    break;
12305	 }
12306
12307	 if(srindex < 0) return;
12308
12309	 if(pSiS->tvyscale != 0) {
12310	    for(j = 0; j <= 1; j++) {
12311	       for(i = 0; i <= 6; i++) {
12312		  if(SiSTVVScale[srindex+i].sindex == pSiS->tvyscale) {
12313		     found = TRUE;
12314		     break;
12315		  }
12316	       }
12317	       if(found) break;
12318	       if(pSiS->tvyscale > 0) pSiS->tvyscale--;
12319	       else pSiS->tvyscale++;
12320	    }
12321	 }
12322
12323#ifdef SISDUALHEAD
12324	 if(pSiSEnt) pSiSEnt->tvyscale = pSiS->tvyscale;
12325#endif
12326
12327	 if(pSiS->tvyscale == 0) {
12328	    UChar p2_0a = pSiS->p2_0a;
12329	    UChar p2_2f = pSiS->p2_2f;
12330	    UChar p2_30 = pSiS->p2_30;
12331	    UChar p2_46 = pSiS->p2_46;
12332	    UChar p2_47 = pSiS->p2_47;
12333	    UChar p1scaling[9], p4scaling[9];
12334	    UChar *p2scaling;
12335
12336	    for(i = 0; i < 9; i++) {
12337	        p1scaling[i] = pSiS->scalingp1[i];
12338		p4scaling[i] = pSiS->scalingp4[i];
12339	    }
12340	    p2scaling = &pSiS->scalingp2[0];
12341
12342#ifdef SISDUALHEAD
12343	    if(pSiSEnt && pSiS->DualHeadMode) {
12344	       p2_0a = pSiSEnt->p2_0a;
12345	       p2_2f = pSiSEnt->p2_2f;
12346	       p2_30 = pSiSEnt->p2_30;
12347	       p2_46 = pSiSEnt->p2_46;
12348	       p2_47 = pSiSEnt->p2_47;
12349	       for(i = 0; i < 9; i++) {
12350		  p1scaling[i] = pSiSEnt->scalingp1[i];
12351		  p4scaling[i] = pSiSEnt->scalingp4[i];
12352	       }
12353	       p2scaling = &pSiSEnt->scalingp2[0];
12354	    }
12355#endif
12356            SISWaitRetraceCRT2(pScrn);
12357	    if(pSiS->VBFlags2 & VB2_SISTAP4SCALER) {
12358	       for(i = 0; i < 64; i++) {
12359	          outSISIDXREG(SISPART2,(0xc0 + i),p2scaling[i]);
12360	       }
12361	    }
12362	    for(i = 0; i < 9; i++) {
12363	       outSISIDXREG(SISPART1,SiSScalingP1Regs[i],p1scaling[i]);
12364	    }
12365	    for(i = 0; i < 9; i++) {
12366	       outSISIDXREG(SISPART4,SiSScalingP4Regs[i],p4scaling[i]);
12367	    }
12368
12369	    setSISIDXREG(SISPART2,0x0a,0x7f,(p2_0a & 0x80));
12370	    outSISIDXREG(SISPART2,0x2f,p2_2f);
12371	    setSISIDXREG(SISPART2,0x30,0x3f,(p2_30 & 0xc0));
12372	    if(!(pSiS->VBFlags2 & VB2_301)) {
12373	       setSISIDXREG(SISPART2,0x46,0x9f,(p2_46 & 0x60));
12374	       outSISIDXREG(SISPART2,0x47,p2_47);
12375	    }
12376
12377	 } else {
12378
12379	    int realvde, myypos, watchdog = 32;
12380	    unsigned short temp1, temp2, vgahde, vgaht, vgavt;
12381	    int p1div = 1;
12382	    ULong calctemp;
12383
12384	    srindex += i;
12385	    newvde = SiSTVVScale[srindex].ScaleVDE;
12386	    realvde = SiSTVVScale[srindex].RealVDE;
12387
12388	    if(vdediv == 1) p1div = 2;
12389
12390	    if(!skipmoveup) {
12391	       do {
12392	          inSISIDXREG(SISPART2,0x01,temp);
12393	          temp = vlimit - ((temp & 0x7f) / p1div);
12394	          if((temp - (((newvde / vdediv) - 2) + 9)) > 0) break;
12395	          myypos = pSiS->tvypos - 1;
12396#ifdef SISDUALHEAD
12397	          if(pSiSEnt && pSiS->DualHeadMode) myypos = pSiSEnt->tvypos - 1;
12398#endif
12399	          SiS_SetTVyposoffset(pScrn, myypos);
12400	       } while(watchdog--);
12401	    }
12402
12403	    SISWaitRetraceCRT2(pScrn);
12404
12405	    if(pSiS->VBFlags2 & VB2_SISTAP4SCALER) {
12406	       SiS_CalcXTapScaler(pSiS->SiS_Pr, realvde, newvde, 4, FALSE);
12407	    }
12408
12409	    if(!(pSiS->VBFlags2 & VB2_301)) {
12410	       temp = (newvde / vdediv) - 3;
12411	       setSISIDXREG(SISPART2,0x46,0x9f,((temp & 0x0300) >> 3));
12412	       outSISIDXREG(SISPART2,0x47,(temp & 0xff));
12413	    }
12414
12415	    inSISIDXREG(SISPART1,0x0a,temp1);
12416	    inSISIDXREG(SISPART1,0x0c,temp2);
12417	    vgahde = ((temp2 & 0xf0) << 4) | temp1;
12418	    if(pSiS->VGAEngine == SIS_300_VGA) {
12419	       vgahde -= 12;
12420	    } else {
12421	       vgahde -= 16;
12422	       if(hdclk) vgahde <<= 1;
12423	    }
12424
12425	    vgaht = SiSTVVScale[srindex].reg[0];
12426	    temp1 = vgaht;
12427	    if((pSiS->VGAEngine == SIS_315_VGA) && hdclk) temp1 >>= 1;
12428	    temp1--;
12429	    outSISIDXREG(SISPART1,0x08,(temp1 & 0xff));
12430	    setSISIDXREG(SISPART1,0x09,0x0f,((temp1 >> 4) & 0xf0));
12431
12432	    temp2 = (vgaht - vgahde) >> 2;
12433	    if(pSiS->VGAEngine == SIS_300_VGA) {
12434	       temp1 = vgahde + 12 + temp2;
12435	       temp2 = temp1 + (temp2 << 1);
12436	    } else {
12437	       temp1 = vgahde;
12438	       if(hdclk) {
12439		  temp1 >>= 1;
12440		  temp2 >>= 1;
12441	       }
12442	       temp2 >>= 1;
12443	       temp1 = temp1 + 16 + temp2;
12444	       temp2 = temp1 + temp2;
12445	    }
12446	    outSISIDXREG(SISPART1,0x0b,(temp1 & 0xff));
12447	    setSISIDXREG(SISPART1,0x0c,0xf0,((temp1 >> 8) & 0x0f));
12448	    outSISIDXREG(SISPART1,0x0d,(temp2 & 0xff));
12449
12450	    vgavt = SiSTVVScale[srindex].reg[1];
12451	    temp1 = vgavt - 1;
12452	    if(pSiS->VGAEngine == SIS_315_VGA) temp1--;
12453	    outSISIDXREG(SISPART1,0x0e,(temp1 & 0xff));
12454	    setSISIDXREG(SISPART1,0x12,0xf8,((temp1 >> 8 ) & 0x07));
12455	    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->ChipType >= SIS_661)) {
12456	       temp1 = (vgavt + SiSTVVScale[srindex].RealVDE) >> 1;
12457	       temp2 = ((vgavt - SiSTVVScale[srindex].RealVDE) >> 4) + temp1 + 1;
12458	    } else {
12459	       temp1 = (vgavt - SiSTVVScale[srindex].RealVDE) >> 2;
12460	       temp2 = (temp1 < 4) ? 4 : temp1;
12461	       temp1 += SiSTVVScale[srindex].RealVDE;
12462	       temp2 = (temp2 >> 2) + temp1 + 1;
12463	    }
12464	    outSISIDXREG(SISPART1,0x10,(temp1 & 0xff));
12465	    setSISIDXREG(SISPART1,0x11,0x8f,((temp1 >> 4) & 0x70));
12466	    setSISIDXREG(SISPART1,0x11,0xf0,(temp2 & 0x0f));
12467
12468	    setSISIDXREG(SISPART2,0x0a,0x7f,((SiSTVVScale[srindex].reg[2] >> 8) & 0x80));
12469	    outSISIDXREG(SISPART2,0x2f,((newvde / vdediv) - 2));
12470	    setSISIDXREG(SISPART2,0x30,0x3f,((((newvde / vdediv) - 2) >> 2) & 0xc0));
12471
12472	    outSISIDXREG(SISPART4,0x13,(SiSTVVScale[srindex].reg[2] & 0xff));
12473	    outSISIDXREG(SISPART4,0x14,(SiSTVVScale[srindex].reg[3] & 0xff));
12474	    setSISIDXREG(SISPART4,0x15,0x7f,((SiSTVVScale[srindex].reg[3] >> 1) & 0x80));
12475
12476	    temp1 = vgaht - 1;
12477	    outSISIDXREG(SISPART4,0x16,(temp1 & 0xff));
12478	    setSISIDXREG(SISPART4,0x15,0x87,((temp1 >> 5) & 0x78));
12479
12480	    temp1 = vgavt - 1;
12481	    outSISIDXREG(SISPART4,0x17,(temp1 & 0xff));
12482	    setSISIDXREG(SISPART4,0x15,0xf8,((temp1 >> 8) & 0x07));
12483
12484	    outSISIDXREG(SISPART4,0x18,0x00);
12485	    setSISIDXREG(SISPART4,0x19,0xf0,0x00);
12486
12487	    inSISIDXREG(SISPART4,0x0e,temp1);
12488	    if(is1080i) {
12489	       if(!(temp1 & 0xe0)) newvde >>= 1;
12490	    }
12491
12492	    temp = 0x40;
12493	    if(realvde <= newvde) temp = 0;
12494	    else realvde -= newvde;
12495
12496	    calctemp = (realvde * 256 * 1024) / newvde;
12497	    if((realvde * 256 * 1024) % newvde) calctemp++;
12498	    outSISIDXREG(SISPART4,0x1b,(calctemp & 0xff));
12499	    outSISIDXREG(SISPART4,0x1a,((calctemp >> 8) & 0xff));
12500	    setSISIDXREG(SISPART4,0x19,0x8f,(((calctemp >> 12) & 0x70) | temp));
12501	 }
12502
12503      }
12504
12505   }
12506}
12507
12508int SiS_GetTVyscale(ScrnInfoPtr pScrn)
12509{
12510   SISPtr pSiS = SISPTR(pScrn);
12511#ifdef SISDUALHEAD
12512   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12513
12514   if(pSiSEnt && pSiS->DualHeadMode)
12515        return (int)pSiSEnt->tvyscale;
12516   else
12517#endif
12518        return (int)pSiS->tvyscale;
12519}
12520
12521void SiS_SetSISCRT1SaturationGain(ScrnInfoPtr pScrn, int val)
12522{
12523   SISPtr pSiS = SISPTR(pScrn);
12524#ifdef SISDUALHEAD
12525   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12526#endif
12527
12528   pSiS->siscrt1satgain = val;
12529#ifdef SISDUALHEAD
12530   if(pSiSEnt) pSiSEnt->siscrt1satgain = val;
12531#endif
12532
12533   if(!(pSiS->SiS_SD3_Flags & SiS_SD3_CRT1SATGAIN)) return;
12534
12535#ifdef UNLOCK_ALWAYS
12536   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
12537#endif
12538
12539   if((val >= 0) && (val <= 7)) {
12540      setSISIDXREG(SISCR,0x53,0xE3, (val << 2));
12541   }
12542}
12543
12544int SiS_GetSISCRT1SaturationGain(ScrnInfoPtr pScrn)
12545{
12546   SISPtr pSiS = SISPTR(pScrn);
12547   int result = pSiS->siscrt1satgain;
12548   UChar temp;
12549#ifdef SISDUALHEAD
12550   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12551
12552   if(pSiSEnt && pSiS->DualHeadMode)  result = pSiSEnt->siscrt1satgain;
12553#endif
12554
12555   if(!(pSiS->SiS_SD3_Flags & SiS_SD3_CRT1SATGAIN)) return result;
12556
12557#ifdef UNLOCK_ALWAYS
12558   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
12559#endif
12560   inSISIDXREG(SISCR, 0x53, temp);
12561   return (int)((temp >> 2) & 0x07);
12562}
12563
12564/* Calc dotclock from registers */
12565static int
12566SiSGetClockFromRegs(UChar sr2b, UChar sr2c)
12567{
12568   float num, denum, postscalar, divider;
12569   int   myclock;
12570
12571   divider = (sr2b & 0x80) ? 2.0 : 1.0;
12572   postscalar = (sr2c & 0x80) ?
12573              ( (((sr2c >> 5) & 0x03) == 0x02) ? 6.0 : 8.0 ) :
12574	      ( ((sr2c >> 5) & 0x03) + 1.0 );
12575   num = (sr2b & 0x7f) + 1.0;
12576   denum = (sr2c & 0x1f) + 1.0;
12577   myclock = (int)((14318 * (divider / postscalar) * (num / denum)) / 1000);
12578   return myclock;
12579}
12580
12581#ifdef SISDUALHEAD
12582static void
12583SiS_SetDHFlags(SISPtr pSiS, unsigned int misc, unsigned int sd2)
12584{
12585   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12586
12587   if(pSiS->DualHeadMode) {
12588      if(pSiSEnt->pScrn_1) {
12589	 SISPTR(pSiSEnt->pScrn_1)->MiscFlags |= misc;
12590	 SISPTR(pSiSEnt->pScrn_1)->SiS_SD2_Flags |= sd2;
12591      }
12592      if(pSiSEnt->pScrn_2) {
12593	 SISPTR(pSiSEnt->pScrn_2)->MiscFlags |= misc;
12594	 SISPTR(pSiSEnt->pScrn_2)->SiS_SD2_Flags |= sd2;
12595      }
12596   }
12597}
12598#endif
12599
12600/* PostSetMode:
12601 * -) Disable CRT1 for saving bandwidth. This doesn't work with VESA;
12602 *    VESA uses the bridge in SlaveMode and switching CRT1 off while
12603 *    the bridge is in SlaveMode not that clever...
12604 * -) Check if overlay can be used (depending on dotclock)
12605 * -) Check if Panel Scaler is active on LVDS for overlay re-scaling
12606 * -) Save TV registers for further processing
12607 * -) Apply TV settings
12608 */
12609static void
12610SiSPostSetMode(ScrnInfoPtr pScrn, SISRegPtr sisReg)
12611{
12612    SISPtr pSiS = SISPTR(pScrn);
12613#ifdef SISDUALHEAD
12614    SISEntPtr pSiSEnt = pSiS->entityPrivate;
12615#endif
12616    UChar usScratchCR17, sr2b, sr2c, tmpreg;
12617    int   myclock1, myclock2, mycoldepth1, mycoldepth2, temp;
12618    Bool  flag = FALSE;
12619    Bool  doit = TRUE;
12620    Bool  IsInSlaveMode;
12621
12622#ifdef TWDEBUG
12623    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
12624    	"CRT1off is %d\n", pSiS->CRT1off);
12625#endif
12626    pSiS->CRT1isoff = pSiS->CRT1off;
12627
12628#ifdef UNLOCK_ALWAYS
12629    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
12630#endif
12631
12632    SiSFixupSR11(pScrn);
12633
12634    IsInSlaveMode = SiSBridgeIsInSlaveMode(pScrn);
12635
12636    if((!pSiS->UseVESA) && (pSiS->VBFlags & CRT2_ENABLE)) {
12637
12638	if(pSiS->VBFlags != pSiS->VBFlags_backup) {
12639	   pSiS->VBFlags = pSiS->VBFlags_backup;
12640	   xf86DrvMsg(pScrn->scrnIndex, X_INFO,
12641			"VBFlags restored to %0x\n", pSiS->VBFlags);
12642	}
12643
12644	/* -) We can't switch off CRT1 if bridge is in SlaveMode.
12645	 * -) If we change to a SlaveMode-Mode (like 512x384), we
12646	 *    need to adapt VBFlags for eg. Xv.
12647	 */
12648#ifdef SISDUALHEAD
12649	if(!pSiS->DualHeadMode) {
12650#endif
12651	   if(IsInSlaveMode) {
12652	      doit = FALSE;
12653	      temp = pSiS->VBFlags;
12654	      pSiS->VBFlags &= (~VB_DISPMODE_SINGLE);
12655	      pSiS->VBFlags |= (VB_DISPMODE_MIRROR | DISPTYPE_DISP1);
12656              if(temp != pSiS->VBFlags) {
12657		 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
12658		 	"VBFlags changed to 0x%0x\n", pSiS->VBFlags);
12659	      }
12660	   }
12661#ifdef SISDUALHEAD
12662	}
12663#endif
12664
12665	if(pSiS->VGAEngine == SIS_315_VGA) {
12666
12667	   if((pSiS->CRT1off) && (doit)) {
12668	      orSISIDXREG(SISCR,pSiS->myCR63,0x40);
12669	      orSISIDXREG(SISSR,0x1f,0xc0);
12670	      andSISIDXREG(SISSR,0x07,~0x10);
12671	      andSISIDXREG(SISSR,0x06,0xe2);
12672	      andSISIDXREG(SISSR,0x31,0xcf);
12673	      outSISIDXREG(SISSR,0x2b,0x1b);
12674	      outSISIDXREG(SISSR,0x2c,0xe1);
12675	      outSISIDXREG(SISSR,0x2d,0x01);
12676	      outSISIDXREG(SISSR, 0x00, 0x01);    /* Synchronous Reset */
12677	      usleep(10000);
12678	      outSISIDXREG(SISSR, 0x00, 0x03);    /* End Reset */
12679	   } else {
12680	      andSISIDXREG(SISCR,pSiS->myCR63,0xBF);
12681	      andSISIDXREG(SISSR,0x1f,0x3f);
12682	      orSISIDXREG(SISSR,0x07,0x10);
12683	   }
12684
12685	} else {
12686
12687	   if(doit) {
12688	      inSISIDXREG(SISCR, 0x17, usScratchCR17);
12689	      if(pSiS->CRT1off) {
12690		 if(usScratchCR17 & 0x80) {
12691		    flag = TRUE;
12692		    usScratchCR17 &= ~0x80;
12693		 }
12694		 orSISIDXREG(SISSR,0x1f,0xc0);
12695	      } else {
12696		 if(!(usScratchCR17 & 0x80)) {
12697		    flag = TRUE;
12698		    usScratchCR17 |= 0x80;
12699		 }
12700		 andSISIDXREG(SISSR,0x1f,0x3f);
12701	      }
12702	      /* Reset only if status changed */
12703	      if(flag) {
12704		 outSISIDXREG(SISCR, 0x17, usScratchCR17);
12705		 outSISIDXREG(SISSR, 0x00, 0x01);    /* Synchronous Reset */
12706		 usleep(10000);
12707		 outSISIDXREG(SISSR, 0x00, 0x03);    /* End Reset */
12708	      }
12709	   }
12710	}
12711
12712    }
12713
12714    /* Set bridge to "disable CRT2" mode if CRT2 is disabled, LCD-A is enabled */
12715    /* (Not needed for CRT1=VGA since CRT2 will really be disabled then) */
12716#ifdef SISDUALHEAD
12717    if(!pSiS->DualHeadMode) {
12718#endif
12719       if((pSiS->VGAEngine == SIS_315_VGA)  && (pSiS->VBFlags2 & VB2_SISLCDABRIDGE)) {
12720	  if((!pSiS->UseVESA) && (!(pSiS->VBFlags & CRT2_ENABLE)) && (pSiS->VBFlags & CRT1_LCDA)) {
12721	     if(!IsInSlaveMode) {
12722	        andSISIDXREG(SISPART4,0x0d,~0x07);
12723	     }
12724	  }
12725       }
12726#ifdef SISDUALHEAD
12727    }
12728#endif
12729
12730    /* Reset flags */
12731    pSiS->MiscFlags &= ~( MISC_CRT1OVERLAY      |
12732			  MISC_CRT2OVERLAY      |
12733			  MISC_CRT1OVERLAYGAMMA |
12734			  MISC_SIS760ONEOVERLAY |
12735			  MISC_PANELLINKSCALER  |
12736			  MISC_STNMODE		|
12737			  MISC_TVNTSC1024);
12738
12739    pSiS->SiS_SD2_Flags &= ~SiS_SD2_SIS760ONEOVL;
12740
12741#ifdef SISDUALHEAD
12742    if(pSiS->DualHeadMode) {
12743       if(pSiSEnt->pScrn_1) {
12744	  SISPTR(pSiSEnt->pScrn_1)->MiscFlags &= ~(MISC_SIS760ONEOVERLAY	|
12745						   MISC_CRT1OVERLAY		|
12746						   MISC_CRT2OVERLAY		|
12747						   MISC_CRT1OVERLAYGAMMA	|
12748						   MISC_PANELLINKSCALER		|
12749						   MISC_STNMODE			|
12750						   MISC_TVNTSC1024);
12751	  SISPTR(pSiSEnt->pScrn_1)->SiS_SD2_Flags &= ~SiS_SD2_SIS760ONEOVL;
12752       }
12753       if(pSiSEnt->pScrn_2) {
12754	  SISPTR(pSiSEnt->pScrn_2)->MiscFlags &= ~(MISC_SIS760ONEOVERLAY	|
12755						   MISC_CRT1OVERLAY		|
12756						   MISC_CRT2OVERLAY		|
12757						   MISC_CRT1OVERLAYGAMMA	|
12758						   MISC_PANELLINKSCALER		|
12759						   MISC_STNMODE			|
12760						   MISC_TVNTSC1024);
12761	  SISPTR(pSiSEnt->pScrn_2)->SiS_SD2_Flags &= ~SiS_SD2_SIS760ONEOVL;
12762       }
12763    }
12764#endif
12765
12766    /* Determine if the video overlay can be used */
12767    if(!pSiS->NoXvideo) {
12768
12769       int clklimit1=0, clklimit2=0, clklimitg=0;
12770       Bool OverlayHandled = FALSE;
12771
12772       inSISIDXREG(SISSR,0x2b,sr2b);
12773       inSISIDXREG(SISSR,0x2c,sr2c);
12774       myclock1 = myclock2 = SiSGetClockFromRegs(sr2b, sr2c);
12775       inSISIDXREG(SISSR,0x06,tmpreg);
12776       switch((tmpreg & 0x1c) >> 2) {
12777       case 0:  mycoldepth1 = 1; break;
12778       case 1:
12779       case 2:  mycoldepth1 = 2; break;
12780       default: mycoldepth1 = 4;
12781       }
12782       mycoldepth2 = mycoldepth1;
12783
12784       if((!IsInSlaveMode) && (pSiS->VBFlags & CRT2_ENABLE)) {
12785	  if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
12786	     inSISIDXREG(SISPART4,0x0a,sr2b);
12787	     inSISIDXREG(SISPART4,0x0b,sr2c);
12788	  } else {
12789	     inSISIDXREG(SISSR,0x2e,sr2b);
12790	     inSISIDXREG(SISSR,0x2f,sr2c);
12791	  }
12792	  myclock2 = SiSGetClockFromRegs(sr2b, sr2c);
12793	  inSISIDXREG(SISPART1,0x00,tmpreg);
12794	  tmpreg &= 0x0f;
12795	  switch(tmpreg) {
12796	  case 8:  mycoldepth2 = 1; break;
12797	  case 4:
12798	  case 2:  mycoldepth2 = 2; break;
12799	  default: mycoldepth2 = 4;
12800	  }
12801       }
12802
12803       switch(pSiS->ChipType) {
12804
12805	 case SIS_300:
12806	 case SIS_540:
12807	 case SIS_630:
12808	 case SIS_730:
12809	    clklimit1 = clklimit2 = clklimitg = 150;
12810	    break;
12811
12812	 case SIS_550:
12813	 case SIS_650:
12814	 case SIS_740:
12815	    clklimit1 = clklimit2 = 175;  /* verified for 65x */
12816	    clklimitg = 166;		  /* ? */
12817	    break;
12818
12819	 case SIS_661:
12820	 case SIS_741:
12821	    clklimit1 = clklimit2 = 190;  /* ? */
12822	    clklimitg = 180;		  /* ? */
12823	    break;
12824
12825	 case SIS_760:
12826	 case SIS_761:
12827	    clklimit1 = clklimit2 = 190;    /* ? */
12828	    if(pSiS->ChipFlags & SiSCF_760LFB) {		/* LFB only or hybrid */
12829	       clklimit1 = clklimit2 = 220; /* ? */
12830	    }
12831	    clklimitg = 200;		    /* ? */
12832
12833	    if(pSiS->SiS_SD2_Flags & SiS_SD2_SUPPORT760OO) {	/* UMA only */
12834
12835	       Bool OnlyOne = FALSE, NoOverlay = FALSE;
12836	       int dotclocksum = 0;
12837
12838	       if(pSiS->VBFlags & DISPTYPE_CRT1)                     dotclocksum += myclock1;
12839	       if((!IsInSlaveMode) && (pSiS->VBFlags & CRT2_ENABLE)) dotclocksum += myclock2;
12840
12841	       /* TODO: Find out under what circumstances only one
12842		*	overlay is usable in UMA-only mode.
12843		*	This is not entirely accurate; the overlay
12844		*	scaler also requires some time, so even though
12845		*	the dotclocks are below these values, some
12846		*	distortions in the overlay may occure.
12847		*	Solution: Don't use a 760 with shared memory.
12848		*/
12849	       if( (pSiS->VBFlags & DISPTYPE_CRT1) &&
12850		   (pSiS->VBFlags & CRT2_ENABLE) &&
12851		   (mycoldepth1 != mycoldepth2) ) {
12852
12853		  /* 0. If coldepths are different (only possible in dual head mode),
12854		   *    I have no idea to calculate the limits; hence, allow only one
12855		   *    overlay in all cases.
12856		   */
12857		  OnlyOne = TRUE;
12858
12859	       } else if(pSiS->MemClock < 150000) {
12860
12861		  /* 1. MCLK <150: If someone seriously considers using such
12862		   *    slow RAM, so be it. Only one overlay in call cases.
12863		   */
12864		  OnlyOne = TRUE;
12865
12866	       } else if(pSiS->MemClock < 170000) {
12867
12868		  /* 2. MCLK 166 */
12869		  switch(pSiS->CurrentLayout.bitsPerPixel) {
12870		     case 32: if(dotclocksum > 133) OnlyOne = TRUE;		/* One overlay; verified */
12871			      if(dotclocksum > 180) NoOverlay = TRUE;		/* No overlay; verified */
12872			      break;
12873		     case 16: if(dotclocksum > 175) OnlyOne = TRUE;		/* One overlay; verified */
12874			      if(dotclocksum > 260) NoOverlay = TRUE;;		/* No overlay; FIXME */
12875			      break;
12876		  }
12877
12878	       } else if(pSiS->MemClock < 210000) {
12879
12880		  /* 3. MCLK 200 */
12881		  switch(pSiS->CurrentLayout.bitsPerPixel) {
12882		     case 32: if(dotclocksum > 160) OnlyOne = TRUE;		/* One overlay; FIXME */
12883			      if(dotclocksum > 216) NoOverlay = TRUE;;		/* No overlay; FIXME */
12884			      break;
12885		     case 16: if(dotclocksum > 210) OnlyOne = TRUE;		/* One overlay; FIXME */
12886			      if(dotclocksum > 312) NoOverlay = TRUE;;		/* No overlay; FIXME */
12887			      break;
12888		  }
12889
12890	       }
12891
12892	       if(OnlyOne || NoOverlay) {
12893
12894		  ULong tmpflags = 0;
12895
12896		  if(!NoOverlay) {
12897		     if(myclock1 <= clklimit1) tmpflags |= MISC_CRT1OVERLAY;
12898		     if(myclock2 <= clklimit2) tmpflags |= MISC_CRT2OVERLAY;
12899		     if(myclock1 <= clklimitg) tmpflags |= MISC_CRT1OVERLAYGAMMA;
12900		     pSiS->MiscFlags |= tmpflags;
12901		  }
12902		  pSiS->MiscFlags |= MISC_SIS760ONEOVERLAY;
12903		  pSiS->SiS_SD2_Flags |= SiS_SD2_SIS760ONEOVL;
12904#ifdef SISDUALHEAD
12905		  SiS_SetDHFlags(pSiS, (tmpflags | MISC_SIS760ONEOVERLAY), SiS_SD2_SIS760ONEOVL);
12906#endif
12907		  OverlayHandled = TRUE;
12908	       }
12909
12910	       xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
12911			"SiS76x/UMA: %s video overlay(s) available in current mode\n",
12912			NoOverlay ? "no" : ((pSiS->MiscFlags & MISC_SIS760ONEOVERLAY) ? "one" : "two"));
12913
12914#ifdef TWDEBUG
12915	       xf86DrvMsg(0, 0, "SiS760: Memclock %d, c1 %d/%d c2 %d/%d, sum %d / %x\n",
12916			pSiS->MemClock, myclock1, mycoldepth1,
12917			myclock2, mycoldepth2, dotclocksum, pSiS->SiS_SD2_Flags);
12918#endif
12919	    }
12920	    break;
12921
12922	 case SIS_660:
12923	    clklimit1 = clklimit2 = 200;  /* ? */
12924	    if(pSiS->ChipFlags & SiSCF_760LFB) {		/* LFB only */
12925	       clklimit1 = clklimit2 = 220;
12926	    }
12927	    clklimitg = 200;		  /* ? */
12928	    break;
12929
12930	 case SIS_315H:
12931	 case SIS_315:
12932	 case SIS_315PRO:
12933	 case SIS_330:
12934	    clklimit1 = clklimit2 = 180;  /* ? */
12935	    clklimitg = 166;		  /* ? */
12936	    break;
12937
12938	 case SIS_340: /* ? */
12939	 case XGI_20:
12940	 case XGI_40:
12941	    clklimit1 = clklimit2 = 240;  /* ? */
12942	    clklimitg = 200;		  /* ? */
12943	    break;
12944       }
12945
12946       if(!OverlayHandled) {
12947          ULong tmpflags = 0;
12948          if(myclock1 <= clklimit1) tmpflags |= MISC_CRT1OVERLAY;
12949          if(myclock2 <= clklimit2) tmpflags |= MISC_CRT2OVERLAY;
12950          if(myclock1 <= clklimitg) tmpflags |= MISC_CRT1OVERLAYGAMMA;
12951	  pSiS->MiscFlags |= tmpflags;
12952#ifdef SISDUALHEAD
12953	  SiS_SetDHFlags(pSiS, tmpflags, 0);
12954#endif
12955          if(!(pSiS->MiscFlags & MISC_CRT1OVERLAY)) {
12956#ifdef SISDUALHEAD
12957             if((!pSiS->DualHeadMode) || (pSiS->SecondHead))
12958#endif
12959		xf86DrvMsgVerb(pScrn->scrnIndex, X_WARNING, 3,
12960		   "Current dotclock (%dMhz) too high for video overlay on CRT1\n",
12961		   myclock1);
12962          }
12963          if((pSiS->VBFlags & CRT2_ENABLE) && (!(pSiS->MiscFlags & MISC_CRT2OVERLAY))) {
12964#ifdef SISDUALHEAD
12965	     if((!pSiS->DualHeadMode) || (!pSiS->SecondHead))
12966#endif
12967		xf86DrvMsgVerb(pScrn->scrnIndex, X_WARNING, 3,
12968		   "Current dotclock (%dMhz) too high for video overlay on CRT2\n",
12969		   myclock2);
12970	  }
12971       }
12972
12973    }
12974
12975    /* Determine if the Panel Link scaler is active */
12976
12977    if(pSiS->VBFlags & (CRT2_LCD | CRT1_LCDA)) {
12978       ULong tmpflags = 0;
12979       if(pSiS->VGAEngine == SIS_300_VGA) {
12980	  if(pSiS->VBFlags2 & (VB2_LVDS | VB2_30xBDH)) {
12981	     inSISIDXREG(SISPART1,0x1e,tmpreg);
12982	     tmpreg &= 0x3f;
12983	     if(tmpreg) tmpflags |= MISC_PANELLINKSCALER;
12984	  }
12985       } else {
12986	  if((pSiS->VBFlags2 & (VB2_LVDS | VB2_30xBDH)) || (pSiS->VBFlags & CRT1_LCDA)) {
12987	     inSISIDXREG(SISPART1,0x35,tmpreg);
12988	     tmpreg &= 0x04;
12989	     if(!tmpreg)  tmpflags |= MISC_PANELLINKSCALER;
12990	  }
12991       }
12992       pSiS->MiscFlags |= tmpflags;
12993#ifdef SISDUALHEAD
12994       SiS_SetDHFlags(pSiS, tmpflags, 0);
12995#endif
12996    }
12997
12998    /* Determine if STN is active */
12999    if(pSiS->ChipType == SIS_550) {
13000       if((pSiS->VBFlags & CRT2_LCD) && (pSiS->FSTN || pSiS->DSTN)) {
13001	  inSISIDXREG(SISCR,0x34,tmpreg);
13002	  tmpreg &= 0x7f;
13003	  if(tmpreg == 0x5a || tmpreg == 0x5b) {
13004	     pSiS->MiscFlags |= MISC_STNMODE;
13005#ifdef SISDUALHEAD
13006	     SiS_SetDHFlags(pSiS, MISC_STNMODE, 0);
13007#endif
13008	  }
13009       }
13010    }
13011
13012    /* Determine if our very special TV mode is active */
13013    if((pSiS->VBFlags2 & VB2_SISBRIDGE) && (pSiS->VBFlags & CRT2_TV) && (!(pSiS->VBFlags & TV_HIVISION))) {
13014       if( ((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR525I)) ||
13015	   ((!(pSiS->VBFlags & TV_YPBPR)) && (pSiS->VBFlags & (TV_NTSC | TV_PALM))) ) {
13016	  inSISIDXREG(SISCR,0x34,tmpreg);
13017	  tmpreg &= 0x7f;
13018	  if((tmpreg == 0x64) || (tmpreg == 0x4a) || (tmpreg == 0x38)) {
13019	     pSiS->MiscFlags |= MISC_TVNTSC1024;
13020#ifdef SISDUALHEAD
13021	     SiS_SetDHFlags(pSiS, MISC_TVNTSC1024, 0);
13022#endif
13023	  }
13024       }
13025    }
13026
13027    if(pSiS->VGAEngine == SIS_315_VGA) {
13028       int i;
13029#ifdef SISVRAMQ
13030       /* Re-Enable and reset command queue */
13031       SiSEnableTurboQueue(pScrn);
13032#endif
13033       /* Get HWCursor register contents for backup */
13034       for(i = 0; i < 16; i++) {
13035          pSiS->HWCursorBackup[i] = SIS_MMIO_IN32(pSiS->IOBase, 0x8500 + (i << 2));
13036       }
13037       if(pSiS->ChipType >= SIS_330) {
13038          /* Enable HWCursor protection (Y pos as trigger) */
13039          andSISIDXREG(SISCR, 0x5b, ~0x30);
13040       }
13041    }
13042
13043    /* Re-initialize accelerator engine */
13044    /* (We are sync'ed here) */
13045    if(!pSiS->NoAccel) {
13046       if(pSiS->InitAccel) {
13047          (pSiS->InitAccel)(pScrn);
13048       }
13049    }
13050
13051    /* Set display device gamma (for SISCTRL) */
13052    if(pSiS->VBFlags & CRT1_LCDA)
13053       pSiS->CRT1MonGamma = pSiS->CRT2LCDMonitorGamma;
13054    else
13055       pSiS->CRT1MonGamma = pSiS->CRT1VGAMonitorGamma;
13056
13057    if(pSiS->VBFlags & CRT2_LCD)
13058       pSiS->CRT2MonGamma = pSiS->CRT2LCDMonitorGamma;
13059    else if(pSiS->VBFlags & CRT2_TV) {
13060       if(pSiS->VBFlags & TV_YPBPR)
13061          pSiS->CRT2MonGamma = 2200; /* */
13062       else if(pSiS->VBFlags & TV_HIVISION)
13063          pSiS->CRT2MonGamma = 2200; /* ? */
13064       else if(pSiS->VBFlags & TV_NTSC)
13065          pSiS->CRT2MonGamma = 2200; /* NTSC */
13066       else
13067          pSiS->CRT2MonGamma = 2800; /* All PAL modes? */
13068    } else if(pSiS->VBFlags & CRT2_VGA)
13069       pSiS->CRT2MonGamma = pSiS->CRT2VGAMonitorGamma;
13070    else
13071       pSiS->CRT2MonGamma = 0; /* Unknown */
13072
13073    /* Reset XV display properties (such as number of overlays, etc) */
13074    /* (And copy monitor gamma) */
13075#ifdef SISDUALHEAD
13076    if(pSiS->DualHeadMode) {
13077       if(pSiSEnt->pScrn_1) {
13078	  if(SISPTR(pSiSEnt->pScrn_1)->ResetXvDisplay) {
13079	     (SISPTR(pSiSEnt->pScrn_1)->ResetXvDisplay)(pSiSEnt->pScrn_1);
13080	  }
13081	  SISPTR(pSiSEnt->pScrn_1)->CRT1MonGamma = pSiS->CRT1MonGamma;
13082	  SISPTR(pSiSEnt->pScrn_1)->CRT2MonGamma = pSiS->CRT2MonGamma;
13083       }
13084       if(pSiSEnt->pScrn_2) {
13085	  if(SISPTR(pSiSEnt->pScrn_2)->ResetXvDisplay) {
13086	     (SISPTR(pSiSEnt->pScrn_1)->ResetXvDisplay)(pSiSEnt->pScrn_2);
13087	  }
13088	  SISPTR(pSiSEnt->pScrn_2)->CRT1MonGamma = pSiS->CRT1MonGamma;
13089	  SISPTR(pSiSEnt->pScrn_2)->CRT2MonGamma = pSiS->CRT2MonGamma;
13090       }
13091    } else {
13092#endif
13093       if(pSiS->ResetXvDisplay) {
13094	  (pSiS->ResetXvDisplay)(pScrn);
13095       }
13096#ifdef SISDUALHEAD
13097    }
13098#endif
13099
13100    /* Reset XV gamma correction */
13101    if(pSiS->ResetXvGamma) {
13102       (pSiS->ResetXvGamma)(pScrn);
13103    }
13104
13105    /* Reset various display parameters */
13106    {
13107       int val = pSiS->siscrt1satgain;
13108#ifdef SISDUALHEAD
13109       if(pSiS->DualHeadMode && pSiSEnt) val = pSiSEnt->siscrt1satgain;
13110#endif
13111       SiS_SetSISCRT1SaturationGain(pScrn, val);
13112    }
13113
13114    /*  Apply TV settings given by options
13115           Do this even in DualHeadMode:
13116	   - if this is called by SetModeCRT1, CRT2 mode has been reset by SetModeCRT1
13117	   - if this is called by SetModeCRT2, CRT2 mode has changed (duh!)
13118	   -> Hence, in both cases, the settings must be re-applied.
13119     */
13120
13121    if(pSiS->VBFlags & CRT2_TV) {
13122       int val;
13123       if(pSiS->VBFlags2 & VB2_CHRONTEL) {
13124	  int mychtvlumabandwidthcvbs = pSiS->chtvlumabandwidthcvbs;
13125	  int mychtvlumabandwidthsvideo = pSiS->chtvlumabandwidthsvideo;
13126	  int mychtvlumaflickerfilter = pSiS->chtvlumaflickerfilter;
13127	  int mychtvchromabandwidth = pSiS->chtvchromabandwidth;
13128	  int mychtvchromaflickerfilter = pSiS->chtvchromaflickerfilter;
13129	  int mychtvcvbscolor = pSiS->chtvcvbscolor;
13130	  int mychtvtextenhance = pSiS->chtvtextenhance;
13131	  int mychtvcontrast = pSiS->chtvcontrast;
13132	  int mytvxpos = pSiS->tvxpos;
13133	  int mytvypos = pSiS->tvypos;
13134#ifdef SISDUALHEAD
13135	  if(pSiSEnt && pSiS->DualHeadMode) {
13136	     mychtvlumabandwidthcvbs = pSiSEnt->chtvlumabandwidthcvbs;
13137	     mychtvlumabandwidthsvideo = pSiSEnt->chtvlumabandwidthsvideo;
13138	     mychtvlumaflickerfilter = pSiSEnt->chtvlumaflickerfilter;
13139	     mychtvchromabandwidth = pSiSEnt->chtvchromabandwidth;
13140	     mychtvchromaflickerfilter = pSiSEnt->chtvchromaflickerfilter;
13141	     mychtvcvbscolor = pSiSEnt->chtvcvbscolor;
13142	     mychtvtextenhance = pSiSEnt->chtvtextenhance;
13143	     mychtvcontrast = pSiSEnt->chtvcontrast;
13144	     mytvxpos = pSiSEnt->tvxpos;
13145	     mytvypos = pSiSEnt->tvypos;
13146	  }
13147#endif
13148	  if((val = mychtvlumabandwidthcvbs) != -1) {
13149	     SiS_SetCHTVlumabandwidthcvbs(pScrn, val);
13150	  }
13151	  if((val = mychtvlumabandwidthsvideo) != -1) {
13152	     SiS_SetCHTVlumabandwidthsvideo(pScrn, val);
13153	  }
13154	  if((val = mychtvlumaflickerfilter) != -1) {
13155	     SiS_SetCHTVlumaflickerfilter(pScrn, val);
13156	  }
13157	  if((val = mychtvchromabandwidth) != -1) {
13158	     SiS_SetCHTVchromabandwidth(pScrn, val);
13159	  }
13160	  if((val = mychtvchromaflickerfilter) != -1) {
13161	     SiS_SetCHTVchromaflickerfilter(pScrn, val);
13162	  }
13163	  if((val = mychtvcvbscolor) != -1) {
13164	     SiS_SetCHTVcvbscolor(pScrn, val);
13165	  }
13166	  if((val = mychtvtextenhance) != -1) {
13167	     SiS_SetCHTVtextenhance(pScrn, val);
13168	  }
13169	  if((val = mychtvcontrast) != -1) {
13170	     SiS_SetCHTVcontrast(pScrn, val);
13171	  }
13172	  /* Backup default TV position registers */
13173	  switch(pSiS->ChrontelType) {
13174	  case CHRONTEL_700x:
13175	     pSiS->tvx = SiS_GetCH700x(pSiS->SiS_Pr, 0x0a);
13176	     pSiS->tvx |= (((SiS_GetCH700x(pSiS->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
13177	     pSiS->tvy = SiS_GetCH700x(pSiS->SiS_Pr, 0x0b);
13178	     pSiS->tvy |= ((SiS_GetCH700x(pSiS->SiS_Pr, 0x08) & 0x01) << 8);
13179#ifdef SISDUALHEAD
13180	     if(pSiSEnt) {
13181		pSiSEnt->tvx = pSiS->tvx;
13182		pSiSEnt->tvy = pSiS->tvy;
13183	     }
13184#endif
13185	     break;
13186	  case CHRONTEL_701x:
13187	     /* Not supported by hardware */
13188	     break;
13189	  }
13190	  if((val = mytvxpos) != 0) {
13191	     SiS_SetTVxposoffset(pScrn, val);
13192	  }
13193	  if((val = mytvypos) != 0) {
13194	     SiS_SetTVyposoffset(pScrn, val);
13195	  }
13196       }
13197       if(pSiS->VBFlags2 & VB2_301) {
13198          int mysistvedgeenhance = pSiS->sistvedgeenhance;
13199#ifdef SISDUALHEAD
13200          if(pSiSEnt && pSiS->DualHeadMode) {
13201	     mysistvedgeenhance = pSiSEnt->sistvedgeenhance;
13202	  }
13203#endif
13204          if((val = mysistvedgeenhance) != -1) {
13205	     SiS_SetSISTVedgeenhance(pScrn, val);
13206	  }
13207       }
13208       if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
13209          int mysistvantiflicker = pSiS->sistvantiflicker;
13210	  int mysistvsaturation = pSiS->sistvsaturation;
13211	  int mysistvcolcalibf = pSiS->sistvcolcalibf;
13212	  int mysistvcolcalibc = pSiS->sistvcolcalibc;
13213	  int mysistvcfilter = pSiS->sistvcfilter;
13214	  int mysistvyfilter = pSiS->sistvyfilter;
13215	  int mytvxpos = pSiS->tvxpos;
13216	  int mytvypos = pSiS->tvypos;
13217	  int mytvxscale = pSiS->tvxscale;
13218	  int mytvyscale = pSiS->tvyscale;
13219	  int i;
13220	  ULong cbase;
13221	  UChar ctemp;
13222#ifdef SISDUALHEAD
13223          if(pSiSEnt && pSiS->DualHeadMode) {
13224	     mysistvantiflicker = pSiSEnt->sistvantiflicker;
13225	     mysistvsaturation = pSiSEnt->sistvsaturation;
13226	     mysistvcolcalibf = pSiSEnt->sistvcolcalibf;
13227	     mysistvcolcalibc = pSiSEnt->sistvcolcalibc;
13228	     mysistvcfilter = pSiSEnt->sistvcfilter;
13229	     mysistvyfilter = pSiSEnt->sistvyfilter;
13230	     mytvxpos = pSiSEnt->tvxpos;
13231	     mytvypos = pSiSEnt->tvypos;
13232	     mytvxscale = pSiSEnt->tvxscale;
13233	     mytvyscale = pSiSEnt->tvyscale;
13234	  }
13235#endif
13236          /* Backup default TV position, scale and colcalib registers */
13237	  inSISIDXREG(SISPART2,0x1f,pSiS->p2_1f);
13238	  inSISIDXREG(SISPART2,0x20,pSiS->p2_20);
13239	  inSISIDXREG(SISPART2,0x2b,pSiS->p2_2b);
13240	  inSISIDXREG(SISPART2,0x42,pSiS->p2_42);
13241	  inSISIDXREG(SISPART2,0x43,pSiS->p2_43);
13242	  inSISIDXREG(SISPART2,0x01,pSiS->p2_01);
13243	  inSISIDXREG(SISPART2,0x02,pSiS->p2_02);
13244	  inSISIDXREG(SISPART2,0x44,pSiS->p2_44);
13245	  inSISIDXREG(SISPART2,0x45,pSiS->p2_45);
13246	  if(!(pSiS->VBFlags2 & VB2_301)) {
13247	     inSISIDXREG(SISPART2,0x46,pSiS->p2_46);
13248	  } else {
13249	     pSiS->p2_46 = 0;
13250	  }
13251	  inSISIDXREG(SISPART2,0x0a,pSiS->p2_0a);
13252	  inSISIDXREG(SISPART2,0x31,cbase);
13253	  cbase = (cbase & 0x7f) << 8;
13254	  inSISIDXREG(SISPART2,0x32,ctemp);
13255	  cbase = (cbase | ctemp) << 8;
13256	  inSISIDXREG(SISPART2,0x33,ctemp);
13257	  cbase = (cbase | ctemp) << 8;
13258	  inSISIDXREG(SISPART2,0x34,ctemp);
13259	  pSiS->sistvccbase = (cbase | ctemp);
13260	  inSISIDXREG(SISPART2,0x35,pSiS->p2_35);
13261	  inSISIDXREG(SISPART2,0x36,pSiS->p2_36);
13262	  inSISIDXREG(SISPART2,0x37,pSiS->p2_37);
13263	  inSISIDXREG(SISPART2,0x38,pSiS->p2_38);
13264	  if(!(pSiS->VBFlags2 & VB2_301)) {
13265	     inSISIDXREG(SISPART2,0x47,pSiS->p2_47);
13266	     inSISIDXREG(SISPART2,0x48,pSiS->p2_48);
13267	     inSISIDXREG(SISPART2,0x49,pSiS->p2_49);
13268	     inSISIDXREG(SISPART2,0x4a,pSiS->p2_4a);
13269	  }
13270	  inSISIDXREG(SISPART2,0x2f,pSiS->p2_2f);
13271	  inSISIDXREG(SISPART2,0x30,pSiS->p2_30);
13272	  for(i=0; i<9; i++) {
13273	     inSISIDXREG(SISPART1,SiSScalingP1Regs[i],pSiS->scalingp1[i]);
13274	  }
13275	  for(i=0; i<9; i++) {
13276	     inSISIDXREG(SISPART4,SiSScalingP4Regs[i],pSiS->scalingp4[i]);
13277	  }
13278	  if(pSiS->VBFlags2 & VB2_SISTAP4SCALER) {
13279	     for(i=0; i<64; i++) {
13280	        inSISIDXREG(SISPART2,(0xc0 + i),pSiS->scalingp2[i]);
13281  	     }
13282	  }
13283#ifdef SISDUALHEAD
13284	  if(pSiSEnt) {
13285	     pSiSEnt->p2_1f = pSiS->p2_1f; pSiSEnt->p2_20 = pSiS->p2_20;
13286	     pSiSEnt->p2_42 = pSiS->p2_42; pSiSEnt->p2_43 = pSiS->p2_43;
13287	     pSiSEnt->p2_2b = pSiS->p2_2b;
13288	     pSiSEnt->p2_01 = pSiS->p2_01; pSiSEnt->p2_02 = pSiS->p2_02;
13289	     pSiSEnt->p2_44 = pSiS->p2_44; pSiSEnt->p2_45 = pSiS->p2_45;
13290	     pSiSEnt->p2_46 = pSiS->p2_46; pSiSEnt->p2_0a = pSiS->p2_0a;
13291	     pSiSEnt->sistvccbase = pSiS->sistvccbase;
13292	     pSiSEnt->p2_35 = pSiS->p2_35; pSiSEnt->p2_36 = pSiS->p2_36;
13293	     pSiSEnt->p2_37 = pSiS->p2_37; pSiSEnt->p2_38 = pSiS->p2_38;
13294	     pSiSEnt->p2_48 = pSiS->p2_48; pSiSEnt->p2_49 = pSiS->p2_49;
13295	     pSiSEnt->p2_4a = pSiS->p2_4a; pSiSEnt->p2_2f = pSiS->p2_2f;
13296	     pSiSEnt->p2_30 = pSiS->p2_30; pSiSEnt->p2_47 = pSiS->p2_47;
13297	     for(i=0; i<9; i++) {
13298	        pSiSEnt->scalingp1[i] = pSiS->scalingp1[i];
13299	     }
13300	     for(i=0; i<9; i++) {
13301	        pSiSEnt->scalingp4[i] = pSiS->scalingp4[i];
13302	     }
13303	     if(pSiS->VBFlags2 & VB2_SISTAP4SCALER) {
13304	        for(i=0; i<64; i++) {
13305	           pSiSEnt->scalingp2[i] = pSiS->scalingp2[i];
13306  	        }
13307	     }
13308	  }
13309#endif
13310          if((val = mysistvantiflicker) != -1) {
13311	     SiS_SetSISTVantiflicker(pScrn, val);
13312	  }
13313	  if((val = mysistvsaturation) != -1) {
13314	     SiS_SetSISTVsaturation(pScrn, val);
13315	  }
13316	  if((val = mysistvcfilter) != -1) {
13317	     SiS_SetSISTVcfilter(pScrn, val);
13318	  }
13319	  if((val = mysistvyfilter) != 1) {
13320	     SiS_SetSISTVyfilter(pScrn, val);
13321	  }
13322	  if((val = mysistvcolcalibc) != 0) {
13323	     SiS_SetSISTVcolcalib(pScrn, val, TRUE);
13324	  }
13325	  if((val = mysistvcolcalibf) != 0) {
13326	     SiS_SetSISTVcolcalib(pScrn, val, FALSE);
13327	  }
13328	  if((val = mytvxpos) != 0) {
13329	     SiS_SetTVxposoffset(pScrn, val);
13330	  }
13331	  if((val = mytvypos) != 0) {
13332	     SiS_SetTVyposoffset(pScrn, val);
13333	  }
13334	  if((val = mytvxscale) != 0) {
13335	     SiS_SetTVxscale(pScrn, val);
13336	  }
13337	  if((val = mytvyscale) != 0) {
13338	     SiS_SetTVyscale(pScrn, val);
13339	  }
13340       }
13341    }
13342
13343}
13344
13345/* Post-set SiS6326 TV registers */
13346static void
13347SiS6326PostSetMode(ScrnInfoPtr pScrn, SISRegPtr sisReg)
13348{
13349    SISPtr pSiS = SISPTR(pScrn);
13350    UChar tmp;
13351    int val;
13352
13353    if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) return;
13354
13355#ifdef UNLOCK_ALWAYS
13356    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
13357#endif
13358
13359    /* Backup default TV position registers */
13360    pSiS->tvx1 = SiS6326GetTVReg(pScrn,0x3a);
13361    pSiS->tvx1 |= ((SiS6326GetTVReg(pScrn,0x3c) & 0x0f) << 8);
13362    pSiS->tvx2 = SiS6326GetTVReg(pScrn,0x26);
13363    pSiS->tvx2 |= ((SiS6326GetTVReg(pScrn,0x27) & 0xf0) << 4);
13364    pSiS->tvx3 = SiS6326GetTVReg(pScrn,0x12);
13365    pSiS->tvx3 |= ((SiS6326GetTVReg(pScrn,0x13) & 0xC0) << 2);
13366    pSiS->tvy1 = SiS6326GetTVReg(pScrn,0x11);
13367    pSiS->tvy1 |= ((SiS6326GetTVReg(pScrn,0x13) & 0x30) << 4);
13368
13369    /* Handle TVPosOffset options (BEFORE switching on TV) */
13370    if((val = pSiS->tvxpos) != 0) {
13371       SiS_SetTVxposoffset(pScrn, val);
13372    }
13373    if((val = pSiS->tvypos) != 0) {
13374       SiS_SetTVyposoffset(pScrn, val);
13375    }
13376
13377    /* Switch on TV output. This is rather complicated, but
13378     * if we don't do it, TV output will flicker terribly.
13379     */
13380    if(pSiS->SiS6326Flags & SIS6326_TVON) {
13381       orSISIDXREG(SISSR, 0x01, 0x20);
13382       tmp = SiS6326GetTVReg(pScrn,0x00);
13383       tmp &= ~0x04;
13384       while(!(inSISREG(SISINPSTAT) & 0x08));    /* Wait while NOT vb */
13385       SiS6326SetTVReg(pScrn,0x00,tmp);
13386       for(val=0; val < 2; val++) {
13387         while(!(inSISREG(SISINPSTAT) & 0x08));  /* Wait while NOT vb */
13388         while(inSISREG(SISINPSTAT) & 0x08);     /* wait while vb     */
13389       }
13390       SiS6326SetTVReg(pScrn, 0x00, sisReg->sis6326tv[0]);
13391       tmp = inSISREG(SISINPSTAT);
13392       outSISREG(SISAR, 0x20);
13393       tmp = inSISREG(SISINPSTAT);
13394       while(inSISREG(SISINPSTAT) & 0x01);
13395       while(!(inSISREG(SISINPSTAT) & 0x01));
13396       andSISIDXREG(SISSR, 0x01, ~0x20);
13397       for(val=0; val < 10; val++) {
13398         while(!(inSISREG(SISINPSTAT) & 0x08));  /* Wait while NOT vb */
13399         while(inSISREG(SISINPSTAT) & 0x08);     /* wait while vb     */
13400       }
13401       andSISIDXREG(SISSR, 0x01, ~0x20);
13402    }
13403
13404    tmp = SiS6326GetTVReg(pScrn,0x00);
13405    if(!(tmp & 0x04)) return;
13406
13407    /* Apply TV settings given by options */
13408    if((val = pSiS->sistvantiflicker) != -1) {
13409       SiS_SetSIS6326TVantiflicker(pScrn, val);
13410    }
13411    if((val = pSiS->sis6326enableyfilter) != -1) {
13412       SiS_SetSIS6326TVenableyfilter(pScrn, val);
13413    }
13414    if((val = pSiS->sis6326yfilterstrong) != -1) {
13415       SiS_SetSIS6326TVyfilterstrong(pScrn, val);
13416    }
13417
13418}
13419
13420/* Check if video bridge is in slave mode */
13421Bool
13422SiSBridgeIsInSlaveMode(ScrnInfoPtr pScrn)
13423{
13424    SISPtr pSiS = SISPTR(pScrn);
13425    UChar  usScrP1_00;
13426
13427    if(!(pSiS->VBFlags2 & VB2_VIDEOBRIDGE)) return FALSE;
13428
13429    inSISIDXREG(SISPART1,0x00,usScrP1_00);
13430    if( ((pSiS->VGAEngine == SIS_300_VGA) && (usScrP1_00 & 0xa0) == 0x20) ||
13431        ((pSiS->VGAEngine == SIS_315_VGA) && (usScrP1_00 & 0x50) == 0x10) ) {
13432       return TRUE;
13433    }
13434
13435    return FALSE;
13436}
13437
13438/* Build a list of the VESA modes the BIOS reports as valid */
13439static void
13440SiSBuildVesaModeList(ScrnInfoPtr pScrn, vbeInfoPtr pVbe, VbeInfoBlock *vbe)
13441{
13442    SISPtr pSiS = SISPTR(pScrn);
13443    int i = 0;
13444
13445    while(vbe->VideoModePtr[i] != 0xffff) {
13446       sisModeInfoPtr m;
13447       VbeModeInfoBlock *mode;
13448       int id = vbe->VideoModePtr[i++];
13449
13450       if((mode = VBEGetModeInfo(pVbe, id)) == NULL) {
13451	  continue;
13452       }
13453
13454       m = xnfcalloc(sizeof(sisModeInfoRec), 1);
13455       if(!m) {
13456	  VBEFreeModeInfo(mode);
13457	  continue;
13458       }
13459       m->width = mode->XResolution;
13460       m->height = mode->YResolution;
13461       m->bpp = mode->BitsPerPixel;
13462       m->n = id;
13463       m->next = pSiS->SISVESAModeList;
13464
13465       pSiS->SISVESAModeList = m;
13466
13467       VBEFreeModeInfo(mode);
13468
13469       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
13470	   "VESA BIOS supports mode number 0x%x: %ix%i (%i bpp)\n",
13471	   m->n, m->width, m->height, m->bpp);
13472    }
13473}
13474
13475/* Get VESA mode number from given resolution/depth */
13476static UShort
13477SiSCalcVESAModeIndex(ScrnInfoPtr pScrn, DisplayModePtr mode)
13478{
13479    SISPtr pSiS = SISPTR(pScrn);
13480    sisModeInfoPtr m = pSiS->SISVESAModeList;
13481    UShort i = (pScrn->bitsPerPixel+7)/8 - 1;
13482    UShort ModeNumber = 0;
13483    int j;
13484
13485    while(m) {
13486       if( (pScrn->bitsPerPixel == m->bpp) &&
13487	   (mode->HDisplay == m->width)    &&
13488	   (mode->VDisplay == m->height) )
13489	  return m->n;
13490       m = m->next;
13491    }
13492
13493    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
13494        "No valid VESA BIOS mode found for %dx%d (%d bpp)\n",
13495        mode->HDisplay, mode->VDisplay, pScrn->bitsPerPixel);
13496
13497    if(!pSiS->ROM661New) {  /* VESA numbers changed! */
13498       j = 0;
13499       while(VESAModeIndices[j] != 9999) {
13500          if( (mode->HDisplay == VESAModeIndices[j]) &&
13501	      (mode->VDisplay == VESAModeIndices[j+1]) ) {
13502	     ModeNumber = VESAModeIndices[j + 2 + i];
13503	     break;
13504          }
13505          j += 6;
13506       }
13507
13508       if(!ModeNumber) {
13509	  xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
13510	      "No valid mode found for %dx%dx%d in built-in table either.\n",
13511	      mode->HDisplay, mode->VDisplay, pScrn->bitsPerPixel);
13512       }
13513    }
13514
13515    return(ModeNumber);
13516}
13517
13518UShort
13519SiS_GetModeNumber(ScrnInfoPtr pScrn, DisplayModePtr mode, unsigned int VBFlags)
13520{
13521   SISPtr pSiS = SISPTR(pScrn);
13522   UShort i = (pSiS->CurrentLayout.bitsPerPixel+7)/8 - 1;
13523   BOOLEAN FSTN = pSiS->FSTN ? TRUE : FALSE;
13524
13525#ifdef SISDUALHEAD
13526   if(pSiS->DualHeadMode && pSiS->SecondHead) FSTN = FALSE;
13527#endif
13528
13529   return(SiS_GetModeID(pSiS->VGAEngine, VBFlags, mode->HDisplay, mode->VDisplay,
13530			i, FSTN, pSiS->LCDwidth, pSiS->LCDheight));
13531}
13532
13533static Bool
13534SiSValidLCDUserMode(SISPtr pSiS, unsigned int VBFlags, DisplayModePtr mode, Bool isforlcda)
13535{
13536   if(mode->Flags & V_INTERLACE) return FALSE;
13537
13538   if(mode->HDisplay > 2048) return FALSE;
13539   if(mode->VDisplay > 1536) return FALSE;
13540
13541   if(pSiS->VBFlags2 & VB2_LCD162MHZBRIDGE) {
13542      if(mode->Clock > 162500) return FALSE;
13543#ifdef VB_FORBID_CRT2LCD_OVER_1600
13544      if(!isforlcda) {
13545         if(mode->HDisplay > 1600) return FALSE;
13546      }
13547#endif
13548   } else { /* 301, 301B, 302B (no LCDA!) */
13549      if(mode->Clock > 130000)  return FALSE;
13550      if(mode->Clock > 111000) {
13551         xf86DrvMsg(pSiS->pScrn->scrnIndex, X_WARNING,
13552	 	"WARNING: Mode clock beyond video bridge specs (%dMHz). Hardware damage might occure.\n",
13553		mode->Clock / 1000);
13554      }
13555      if(mode->HDisplay > 1600) return FALSE;
13556      if(mode->VDisplay > 1024) return FALSE;
13557   }
13558
13559   return TRUE;
13560}
13561
13562static Bool
13563SiSValidVGA2UserMode(SISPtr pSiS, unsigned int VBFlags, DisplayModePtr mode)
13564{
13565   if(mode->Flags & V_INTERLACE) return FALSE;
13566
13567   if(mode->HDisplay > 2048) return FALSE;
13568   if(mode->VDisplay > 1536) return FALSE;
13569
13570   if(pSiS->VBFlags2 & VB2_RAMDAC202MHZBRIDGE) {
13571      if(mode->Clock > 203000) return FALSE;
13572   } else if(pSiS->VBFlags2 & VB2_30xBLV) {
13573      if(mode->Clock > 162500) return FALSE;
13574   } else {
13575      if(mode->Clock > 135500) return FALSE;
13576   }
13577
13578   return TRUE;
13579}
13580
13581UShort
13582SiS_CheckModeCRT1(ScrnInfoPtr pScrn, DisplayModePtr mode, unsigned int VBFlags, Bool havecustommodes)
13583{
13584   SISPtr pSiS = SISPTR(pScrn);
13585   UShort i = (pSiS->CurrentLayout.bitsPerPixel+7)/8 - 1;
13586   int j;
13587
13588   if(!(VBFlags & CRT1_LCDA)) {
13589
13590      if((havecustommodes) && (!(mode->type & M_T_DEFAULT))) {
13591         return 0xfe;
13592      }
13593
13594   } else if(pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE) {
13595
13596      if(pSiS->ChipType < SIS_661) {  /* < 661 only? */
13597         if(!(mode->type & M_T_DEFAULT)) {
13598            if(mode->HTotal > 2055) return 0;
13599	    /* (Default mode will be caught in mode switching code) */
13600	 }
13601      }
13602
13603      if(pSiS->SiS_Pr->CP_HaveCustomData) {
13604         for(j=0; j<7; j++) {
13605            if((pSiS->SiS_Pr->CP_DataValid[j]) &&
13606               (mode->HDisplay == pSiS->SiS_Pr->CP_HDisplay[j]) &&
13607               (mode->VDisplay == pSiS->SiS_Pr->CP_VDisplay[j]) &&
13608               (mode->type & M_T_BUILTIN))
13609               return 0xfe;
13610	 }
13611      }
13612
13613      if((pSiS->AddedPlasmaModes) && (mode->type & M_T_BUILTIN))
13614         return 0xfe;
13615
13616      if((havecustommodes) &&
13617         (pSiS->LCDwidth)  &&	/* = test if LCD present */
13618         (!(mode->type & M_T_DEFAULT)) &&
13619	 (SiSValidLCDUserMode(pSiS, VBFlags, mode, TRUE)))
13620         return 0xfe;
13621
13622      if((mode->HDisplay > pSiS->LCDwidth) ||
13623         (mode->VDisplay > pSiS->LCDheight)) {
13624	 return 0;
13625      }
13626
13627   } else {
13628
13629      if((mode->HDisplay > pSiS->LCDwidth) ||
13630         (mode->VDisplay > pSiS->LCDheight)) {
13631	 return 0;
13632      }
13633
13634   }
13635
13636   return(SiS_GetModeID(pSiS->VGAEngine, VBFlags, mode->HDisplay, mode->VDisplay,
13637   			i, pSiS->FSTN, pSiS->LCDwidth, pSiS->LCDheight));
13638}
13639
13640UShort
13641SiS_CheckModeCRT2(ScrnInfoPtr pScrn, DisplayModePtr mode, unsigned int VBFlags, Bool havecustommodes)
13642{
13643   SISPtr pSiS = SISPTR(pScrn);
13644   UShort i = (pSiS->CurrentLayout.bitsPerPixel+7)/8 - 1;
13645   UShort ModeIndex = 0;
13646   int    j;
13647
13648#ifdef TWDEBUG
13649   xf86DrvMsg(0, X_INFO, "Inside CheckCalcModeIndex (VBFlags %lx, mode %dx%d)\n",
13650	VBFlags,mode->HDisplay, mode->VDisplay);
13651#endif
13652
13653   if(VBFlags & CRT2_LCD) {			/* CRT2 is LCD */
13654
13655      if((pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) && (!(pSiS->VBFlags2 & VB2_30xBDH))) {
13656
13657         if(pSiS->SiS_Pr->CP_HaveCustomData) {
13658            for(j=0; j<7; j++) {
13659               if((pSiS->SiS_Pr->CP_DataValid[j]) &&
13660                  (mode->HDisplay == pSiS->SiS_Pr->CP_HDisplay[j]) &&
13661                  (mode->VDisplay == pSiS->SiS_Pr->CP_VDisplay[j]) &&
13662#ifdef VB_FORBID_CRT2LCD_OVER_1600
13663		  (mode->HDisplay <= 1600) 			   &&
13664#endif
13665                  (mode->type & M_T_BUILTIN))
13666                  return 0xfe;
13667	    }
13668         }
13669
13670	 /* All plasma modes have HDisplay <= 1600 */
13671         if((pSiS->AddedPlasmaModes) && (mode->type & M_T_BUILTIN))
13672            return 0xfe;
13673
13674         if((havecustommodes) &&
13675            (pSiS->LCDwidth)  &&	/* = test if LCD present */
13676	    (!(mode->type & M_T_DEFAULT)) &&
13677	    (SiSValidLCDUserMode(pSiS, VBFlags, mode, FALSE)))
13678            return 0xfe;
13679
13680      }
13681
13682      if( ((mode->HDisplay <= pSiS->LCDwidth) &&
13683           (mode->VDisplay <= pSiS->LCDheight)) ||
13684	  ((pSiS->SiS_Pr->SiS_CustomT == CUT_PANEL848) &&
13685	   (((mode->HDisplay == 1360) && (mode->HDisplay == 768)) ||
13686	    ((mode->HDisplay == 1024) && (mode->HDisplay == 768)) ||
13687	    ((mode->HDisplay ==  800) && (mode->HDisplay == 600)))) ||
13688	  ((pSiS->SiS_Pr->SiS_CustomT == CUT_PANEL856) &&
13689	   (((mode->HDisplay == 1024) && (mode->HDisplay == 768)) ||
13690	    ((mode->HDisplay ==  800) && (mode->HDisplay == 600)))) ) {
13691
13692	 ModeIndex = SiS_GetModeID_LCD(pSiS->VGAEngine, VBFlags, mode->HDisplay, mode->VDisplay, i,
13693				pSiS->FSTN, pSiS->SiS_Pr->SiS_CustomT, pSiS->LCDwidth, pSiS->LCDheight,
13694				pSiS->VBFlags2);
13695
13696      }
13697
13698   } else if(VBFlags & CRT2_TV) {		/* CRT2 is TV */
13699
13700      ModeIndex = SiS_GetModeID_TV(pSiS->VGAEngine, VBFlags, mode->HDisplay, mode->VDisplay, i,
13701					pSiS->VBFlags2);
13702
13703   } else if(VBFlags & CRT2_VGA) {		/* CRT2 is VGA2 */
13704
13705      if((pSiS->AddedPlasmaModes) && (mode->type & M_T_BUILTIN))
13706	 return 0xfe;
13707
13708      if((havecustommodes) &&
13709	 (!(mode->type & M_T_DEFAULT)) &&
13710	 (SiSValidVGA2UserMode(pSiS, VBFlags, mode)))
13711         return 0xfe;
13712
13713      ModeIndex = SiS_GetModeID_VGA2(pSiS->VGAEngine, VBFlags, mode->HDisplay, mode->VDisplay, i,
13714					pSiS->VBFlags2);
13715
13716   } else {					/* no CRT2 */
13717
13718      /* Return a valid mode number */
13719      ModeIndex = 0xfe;
13720
13721   }
13722
13723   return(ModeIndex);
13724}
13725
13726/* Calculate the vertical refresh rate from a mode */
13727float
13728SiSCalcVRate(DisplayModePtr mode)
13729{
13730   float hsync, refresh = 0;
13731
13732   if(mode->HSync > 0.0)
13733       	hsync = mode->HSync;
13734   else if(mode->HTotal > 0)
13735       	hsync = (float)mode->Clock / (float)mode->HTotal;
13736   else
13737       	hsync = 0.0;
13738
13739   if(mode->VTotal > 0)
13740       	refresh = hsync * 1000.0 / mode->VTotal;
13741
13742   if(mode->Flags & V_INTERLACE)
13743       	refresh *= 2.0;
13744
13745   if(mode->Flags & V_DBLSCAN)
13746       	refresh /= 2.0;
13747
13748   if(mode->VScan > 1)
13749        refresh /= mode->VScan;
13750
13751   if(mode->VRefresh > 0.0)
13752	refresh = mode->VRefresh;
13753
13754   if(hsync == 0.0 || refresh == 0.0) return 0.0;
13755
13756   return refresh;
13757}
13758
13759/* Calculate CR33 (rate index) for CRT1.
13760 * Calculation is done using currentmode, therefore it is
13761 * recommended to set VertRefresh and HorizSync to correct
13762 * values in config file.
13763 */
13764UChar
13765SISSearchCRT1Rate(ScrnInfoPtr pScrn, DisplayModePtr mode)
13766{
13767   SISPtr  pSiS = SISPTR(pScrn);
13768   int     i = 0, irefresh;
13769   UShort  xres = mode->HDisplay;
13770   UShort  yres = mode->VDisplay;
13771   UChar   index, defindex;
13772   Bool    checksis730 = FALSE;
13773
13774   defindex = (xres == 800 || xres == 1024 || xres == 1280) ? 0x02 : 0x01;
13775
13776   irefresh = (int)SiSCalcVRate(mode);
13777   if(!irefresh) return defindex;
13778
13779   /* SiS730 has troubles on CRT2 if CRT1 is at 32bpp */
13780   if( (pSiS->ChipType == SIS_730)        &&
13781       (pSiS->VBFlags2 & VB2_VIDEOBRIDGE) &&
13782       (pSiS->CurrentLayout.bitsPerPixel == 32) ) {
13783#ifdef SISDUALHEAD
13784      if(pSiS->DualHeadMode) {
13785         if(pSiS->SecondHead) {
13786	    checksis730 = TRUE;
13787	 }
13788      } else
13789#endif
13790      if((!pSiS->UseVESA) && (pSiS->VBFlags & CRT2_ENABLE) && (!pSiS->CRT1off)) {
13791         checksis730 = TRUE;
13792      }
13793   }
13794
13795#ifdef TWDEBUG
13796   xf86DrvMsg(0, X_INFO, "Debug: CalcVRate returned %d\n", irefresh);
13797#endif
13798
13799   /* We need the REAL refresh rate here */
13800   if(mode->Flags & V_INTERLACE) irefresh /= 2;
13801
13802   /* Do not multiply by 2 when DBLSCAN! */
13803
13804#ifdef TWDEBUG
13805   xf86DrvMsg(0, X_INFO, "Debug: Rate after correction = %d\n", irefresh);
13806#endif
13807
13808   index = 0;
13809   while((sisx_vrate[i].idx != 0) && (sisx_vrate[i].xres <= xres)) {
13810      if((sisx_vrate[i].xres == xres) && (sisx_vrate[i].yres == yres)) {
13811	 if((checksis730 == FALSE) || (sisx_vrate[i].SiS730valid32bpp == TRUE)) {
13812	    if(sisx_vrate[i].refresh == irefresh) {
13813	       index = sisx_vrate[i].idx;
13814	       break;
13815	    } else if(sisx_vrate[i].refresh > irefresh) {
13816	       if((sisx_vrate[i].refresh - irefresh) <= 3) {
13817		  index = sisx_vrate[i].idx;
13818	       } else if( ((checksis730 == FALSE) || (sisx_vrate[i - 1].SiS730valid32bpp == TRUE)) &&
13819		          ((irefresh - sisx_vrate[i - 1].refresh) <=  2) &&
13820			  (sisx_vrate[i].idx != 1) ) {
13821		  index = sisx_vrate[i - 1].idx;
13822	       }
13823	       break;
13824	    } else if((irefresh - sisx_vrate[i].refresh) <= 2) {
13825	       index = sisx_vrate[i].idx;
13826	       break;
13827	    }
13828	 }
13829      }
13830      i++;
13831   }
13832
13833   if(index > 0) return index;
13834   else          return defindex;
13835}
13836
13837void
13838SISWaitRetraceCRT1(ScrnInfoPtr pScrn)
13839{
13840   SISPtr pSiS = SISPTR(pScrn);
13841   int    watchdog;
13842   UChar  temp;
13843
13844   inSISIDXREG(SISCR,0x17,temp);
13845   if(!(temp & 0x80)) return;
13846
13847   inSISIDXREG(SISSR,0x1f,temp);
13848   if(temp & 0xc0) return;
13849
13850   watchdog = 65536;
13851   while((inSISREG(SISINPSTAT) & 0x08) && --watchdog);
13852   watchdog = 65536;
13853   while((!(inSISREG(SISINPSTAT) & 0x08)) && --watchdog);
13854}
13855
13856void
13857SISWaitRetraceCRT2(ScrnInfoPtr pScrn)
13858{
13859   SISPtr pSiS = SISPTR(pScrn);
13860   int    watchdog;
13861   UChar  temp, reg;
13862
13863   if(SiSBridgeIsInSlaveMode(pScrn)) {
13864      SISWaitRetraceCRT1(pScrn);
13865      return;
13866   }
13867
13868   switch(pSiS->VGAEngine) {
13869   case SIS_300_VGA:
13870   	reg = 0x25;
13871	break;
13872   case SIS_315_VGA:
13873   	reg = 0x30;
13874	break;
13875   default:
13876        return;
13877   }
13878
13879   watchdog = 65536;
13880   do {
13881   	inSISIDXREG(SISPART1, reg, temp);
13882	if(!(temp & 0x02)) break;
13883   } while(--watchdog);
13884   watchdog = 65536;
13885   do {
13886   	inSISIDXREG(SISPART1, reg, temp);
13887	if(temp & 0x02) break;
13888   } while(--watchdog);
13889}
13890
13891static void
13892SISWaitVBRetrace(ScrnInfoPtr pScrn)
13893{
13894   SISPtr  pSiS = SISPTR(pScrn);
13895
13896   if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
13897#ifdef SISDUALHEAD
13898      if(pSiS->DualHeadMode) {
13899   	 if(pSiS->SecondHead)
13900	    SISWaitRetraceCRT1(pScrn);
13901         else
13902	    SISWaitRetraceCRT2(pScrn);
13903      } else {
13904#endif
13905	 if(pSiS->VBFlags & DISPTYPE_DISP1) {
13906	    SISWaitRetraceCRT1(pScrn);
13907	 }
13908	 if(pSiS->VBFlags & DISPTYPE_DISP2) {
13909	    if(!(SiSBridgeIsInSlaveMode(pScrn))) {
13910	       SISWaitRetraceCRT2(pScrn);
13911	    }
13912	 }
13913#ifdef SISDUALHEAD
13914      }
13915#endif
13916   } else {
13917      SISWaitRetraceCRT1(pScrn);
13918   }
13919}
13920
13921#define MODEID_OFF 0x449
13922
13923UChar
13924SiS_GetSetBIOSScratch(ScrnInfoPtr pScrn, UShort offset, UChar value)
13925{
13926    UChar ret = 0;
13927#ifdef SIS_USE_BIOS_SCRATCH
13928    UChar *base;
13929#endif
13930
13931    /* For some reasons (like detecting the current display mode),
13932     * we need to read (or write-back) values from the BIOS
13933     * scratch area. This area is only valid for the primary
13934     * graphics card. For the secondary, we just return some
13935     * defaults and ignore requests to write data. As regards
13936     * the display mode: If sisfb is loaded for the secondary
13937     * card, it very probably has set a mode, but in any case
13938     * informed us via its info packet. So this here will not be
13939     * called for mode detection in this case.
13940     */
13941
13942    switch(offset) {
13943    case 0x489:
13944       ret = 0x11;  /* Default VGA Info */
13945       break;
13946    case MODEID_OFF:
13947       ret = 0x03;  /* Default current display mode */
13948       break;
13949    }
13950
13951#ifdef SIS_USE_BIOS_SCRATCH
13952    if(SISPTR(pScrn)->Primary) {
13953       base = xf86MapVidMem(pScrn->scrnIndex, VIDMEM_MMIO, 0, 0x2000);
13954       if(!base) {
13955          SISErrorLog(pScrn, "(Could not map BIOS scratch area)\n");
13956          return ret;
13957       }
13958
13959       ret = *(base + offset);
13960
13961       /* value != 0xff means: set register */
13962       if(value != 0xff) {
13963          *(base + offset) = value;
13964       }
13965
13966       xf86UnMapVidMem(pScrn->scrnIndex, base, 0x2000);
13967    }
13968#endif
13969    return ret;
13970}
13971
13972UChar
13973SiS_GetSetModeID(ScrnInfoPtr pScrn, UChar id)
13974{
13975    return(SiS_GetSetBIOSScratch(pScrn, MODEID_OFF, id));
13976}
13977
13978void
13979SiSMemCopyToVideoRam(SISPtr pSiS, UChar *to, UChar *from, int size)
13980{
13981   if((ULong)to & 15) (*pSiS->SiSFastMemCopy)(to, from, size);
13982   else       	      (*pSiS->SiSFastVidCopy)(to, from, size);
13983}
13984
13985void
13986SiSMemCopyFromVideoRam(SISPtr pSiS, UChar *to, UChar *from, int size)
13987{
13988   if((ULong)to & 15) (*pSiS->SiSFastMemCopyFrom)(to, from, size);
13989   else       	      (*pSiS->SiSFastVidCopyFrom)(to, from, size);
13990}
13991
13992void
13993sisSaveUnlockExtRegisterLock(SISPtr pSiS, UChar *reg1, UChar *reg2)
13994{
13995    register UChar val;
13996    ULong mylockcalls;
13997#ifdef TWDEBUG
13998    UChar val1, val2;
13999    int i;
14000#endif
14001
14002    pSiS->lockcalls++;
14003    mylockcalls = pSiS->lockcalls;
14004
14005    /* check if already unlocked */
14006    inSISIDXREG(SISSR, 0x05, val);
14007
14008    if(val != 0xa1) {
14009
14010       /* save State */
14011       if(reg1) *reg1 = val;
14012
14013       /* unlock */
14014       outSISIDXREG(SISSR, 0x05, 0x86);
14015
14016       /* Now check again */
14017       inSISIDXREG(SISSR, 0x05, val);
14018
14019       if(val != 0xA1) {
14020
14021          xf86DrvMsg(pSiS->pScrn->scrnIndex, X_WARNING,
14022               "Failed to unlock SR registers at relocated i/o ports\n");
14023
14024#ifdef TWDEBUG
14025          for(i = 0; i <= 0x3f; i++) {
14026		inSISIDXREG(SISSR, i, val1);
14027		inSISIDXREG(0x3c4, i, val2);
14028		xf86DrvMsg(pSiS->pScrn->scrnIndex, X_INFO,
14029			"SR%02d: RelIO=0x%02x 0x3c4=0x%02x (%ld)\n",
14030			i, val1, val2, mylockcalls);
14031	  }
14032#endif
14033
14034	  /* Emergency measure: unlock at 0x3c4, and try to enable relocated IO ports */
14035	  switch(pSiS->VGAEngine) {
14036          case SIS_OLD_VGA:
14037	  case SIS_530_VGA:
14038	     outSISIDXREG(0x3c4, 0x05, 0x86);
14039	     andSISIDXREG(0x3c4, 0x33, ~0x20);
14040	     break;
14041	  case SIS_300_VGA:
14042	  case SIS_315_VGA:
14043	     outSISIDXREG(0x3c4, 0x05, 0x86);
14044	     orSISIDXREG(0x3c4, 0x20, 0x20);
14045	     break;
14046          }
14047	  outSISIDXREG(SISSR, 0x05, 0x86);
14048	  inSISIDXREG(SISSR, 0x05, val);
14049	  if(val != 0xa1) {
14050	     SISErrorLog(pSiS->pScrn,
14051			"Failed to unlock SR registers (%p, %lx, 0x%02x; %ld)\n",
14052			(void *)pSiS, (ULong)pSiS->RelIO, val, mylockcalls);
14053	     /* Now await doom... */
14054	  }
14055       }
14056    }
14057    if((pSiS->VGAEngine == SIS_OLD_VGA) || (pSiS->VGAEngine == SIS_530_VGA)) {
14058       inSISIDXREG(SISCR, 0x80, val);
14059       if(val != 0xa1) {
14060          /* save State */
14061          if(reg2) *reg2 = val;
14062          outSISIDXREG(SISCR, 0x80, 0x86);
14063	  inSISIDXREG(SISCR, 0x80, val);
14064	  if(val != 0xA1) {
14065	     SISErrorLog(pSiS->pScrn,
14066	        "Failed to unlock cr registers (%p, %lx, 0x%02x)\n",
14067	       (void *)pSiS, (ULong)pSiS->RelIO, val);
14068	  }
14069       }
14070    }
14071}
14072
14073void
14074sisRestoreExtRegisterLock(SISPtr pSiS, UChar reg1, UChar reg2)
14075{
14076    /* restore lock */
14077#ifndef UNLOCK_ALWAYS
14078    outSISIDXREG(SISSR, 0x05, reg1 == 0xA1 ? 0x86 : 0x00);
14079    if((pSiS->VGAEngine == SIS_OLD_VGA) || (pSiS->VGAEngine == SIS_530_VGA)) {
14080       outSISIDXREG(SISCR, 0x80, reg2 == 0xA1 ? 0x86 : 0x00);
14081    }
14082#endif
14083}
14084
14085