sis_driver.c revision 5788ca14
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#include <X11/extensions/xf86dgaproto.h>
78
79#include "globals.h"
80
81#ifdef HAVE_XEXTPROTO_71
82#include <X11/extensions/dpmsconst.h>
83#else
84#define DPMS_SERVER
85#include <X11/extensions/dpms.h>
86#endif
87
88#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 5
89#include <inputstr.h> /* for inputInfo */
90#endif
91
92
93#ifdef SISDRI
94#include "dri.h"
95#endif
96
97/*
98 * LookupWindow was removed with video abi 11.
99 */
100#if (GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 4)
101#ifndef DixGetAttrAccess
102#define DixGetAttrAccess   (1<<4)
103#endif
104#endif
105
106#if (GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 2)
107static inline int
108dixLookupWindow(WindowPtr *pWin, XID id, ClientPtr client, Mask access)
109{
110    *pWin = LookupWindow(id, client);
111    if (!*pWin)
112	return BadWindow;
113    return Success;
114}
115#endif
116
117/* Globals (yes, these ARE really required to be global) */
118
119#ifdef SISUSEDEVPORT
120int 		sisdevport = 0;
121#endif
122
123#ifdef SISDUALHEAD
124static int	SISEntityIndex = -1;
125#endif
126
127#ifdef SISMERGED
128#ifdef SISXINERAMA
129static Bool 		SiSnoPanoramiXExtension = TRUE;
130static int		SiSXineramaNumScreens = 0;
131static SiSXineramaData	*SiSXineramadataPtr = NULL;
132static int		SiSXineramaGeneration;
133
134static int SiSProcXineramaQueryVersion(ClientPtr client);
135static int SiSProcXineramaGetState(ClientPtr client);
136static int SiSProcXineramaGetScreenCount(ClientPtr client);
137static int SiSProcXineramaGetScreenSize(ClientPtr client);
138static int SiSProcXineramaIsActive(ClientPtr client);
139static int SiSProcXineramaQueryScreens(ClientPtr client);
140static int SiSSProcXineramaDispatch(ClientPtr client);
141#endif
142#endif
143
144/*
145 * This is intentionally screen-independent.  It indicates the binding
146 * choice made in the first PreInit.
147 */
148static int pix24bpp = 0;
149
150/*
151 * This contains the functions needed by the server after loading the driver
152 * module.  It must be supplied, and gets passed back by the SetupProc
153 * function in the dynamic case.  In the static case, a reference to this
154 * is compiled in, and this requires that the name of this DriverRec be
155 * an upper-case version of the driver name.
156 */
157
158#ifdef _X_EXPORT
159_X_EXPORT
160#endif
161DriverRec SIS = {
162    SIS_CURRENT_VERSION,
163    SIS_DRIVER_NAME,
164    SISIdentify,
165    SISProbe,
166    SISAvailableOptions,
167    NULL,
168    0
169#ifdef SIS_HAVE_DRIVER_FUNC
170     ,
171    SISDriverFunc
172#endif
173};
174
175static SymTabRec SISChipsets[] = {
176    { PCI_CHIP_SIS5597,     "SIS5597/5598" },
177    { PCI_CHIP_SIS530,      "SIS530/620" },
178    { PCI_CHIP_SIS6326,     "SIS6326/AGP/DVD" },
179    { PCI_CHIP_SIS300,      "SIS300/305" },
180    { PCI_CHIP_SIS630,      "SIS630/730" },
181    { PCI_CHIP_SIS540,      "SIS540" },
182    { PCI_CHIP_SIS315,      "SIS315" },
183    { PCI_CHIP_SIS315H,     "SIS315H" },
184    { PCI_CHIP_SIS315PRO,   "SIS315PRO/E" },
185    { PCI_CHIP_SIS550,	    "SIS550" },
186    { PCI_CHIP_SIS650,      "SIS650/M650/651/740" },
187    { PCI_CHIP_SIS330,      "SIS330(Xabre)" },
188    { PCI_CHIP_SIS660,      "SIS660/[M]661[F|M]X/[M]670/[M]741[GX]/[M]760[GX]/[M]761[GX]/[M]770[GX]" },
189    { PCI_CHIP_SIS340,      "SIS340" },
190    { -1,                   NULL }
191};
192
193static PciChipsets SISPciChipsets[] = {
194    { PCI_CHIP_SIS5597,     PCI_CHIP_SIS5597,   RES_SHARED_VGA },
195    { PCI_CHIP_SIS530,      PCI_CHIP_SIS530,    RES_SHARED_VGA },
196    { PCI_CHIP_SIS6326,     PCI_CHIP_SIS6326,   RES_SHARED_VGA },
197    { PCI_CHIP_SIS300,      PCI_CHIP_SIS300,    RES_SHARED_VGA },
198    { PCI_CHIP_SIS630,      PCI_CHIP_SIS630,    RES_SHARED_VGA },
199    { PCI_CHIP_SIS540,      PCI_CHIP_SIS540,    RES_SHARED_VGA },
200    { PCI_CHIP_SIS550,      PCI_CHIP_SIS550,    RES_SHARED_VGA },
201    { PCI_CHIP_SIS315,      PCI_CHIP_SIS315,    RES_SHARED_VGA },
202    { PCI_CHIP_SIS315H,     PCI_CHIP_SIS315H,   RES_SHARED_VGA },
203    { PCI_CHIP_SIS315PRO,   PCI_CHIP_SIS315PRO, RES_SHARED_VGA },
204    { PCI_CHIP_SIS650,      PCI_CHIP_SIS650,    RES_SHARED_VGA },
205    { PCI_CHIP_SIS330,      PCI_CHIP_SIS330,    RES_SHARED_VGA },
206    { PCI_CHIP_SIS660,      PCI_CHIP_SIS660,    RES_SHARED_VGA },
207    { PCI_CHIP_SIS340,      PCI_CHIP_SIS340,    RES_SHARED_VGA },
208    { -1,                   -1,                 RES_UNDEFINED }
209};
210
211static SymTabRec XGIChipsets[] = {
212    { PCI_CHIP_XGIXG20,     "Volari Z7 (XG20)" },
213    { PCI_CHIP_XGIXG40,     "Volari V3XT/V5/V8/Duo (XG40)" },
214    { -1,                   NULL }
215};
216
217static PciChipsets XGIPciChipsets[] = {
218    { PCI_CHIP_XGIXG20,     PCI_CHIP_XGIXG20,   RES_SHARED_VGA },
219    { PCI_CHIP_XGIXG40,     PCI_CHIP_XGIXG40,   RES_SHARED_VGA },
220    { -1,                   -1,                 RES_UNDEFINED }
221};
222
223#ifdef XFree86LOADER
224
225static MODULESETUPPROTO(sisSetup);
226
227static XF86ModuleVersionInfo sisVersRec =
228{
229    SIS_DRIVER_NAME,
230    MODULEVENDORSTRING,
231    MODINFOSTRING1,
232    MODINFOSTRING2,
233#ifdef XORG_VERSION_CURRENT
234    XORG_VERSION_CURRENT,
235#else
236    XF86_VERSION_CURRENT,
237#endif
238    SIS_MAJOR_VERSION, SIS_MINOR_VERSION, SIS_PATCHLEVEL,
239    ABI_CLASS_VIDEODRV,         /* This is a video driver */
240    ABI_VIDEODRV_VERSION,
241    MOD_CLASS_VIDEODRV,
242    {0,0,0,0}
243};
244
245#ifdef _X_EXPORT
246_X_EXPORT
247#endif
248XF86ModuleData sisModuleData = { &sisVersRec, sisSetup, NULL };
249
250pointer
251sisSetup(pointer module, pointer opts, int *errmaj, int *errmin)
252{
253    static Bool setupDone = FALSE;
254
255    if(!setupDone) {
256       setupDone = TRUE;
257       xf86AddDriver(&SIS, module, SIS_HaveDriverFuncs);
258       return (pointer)TRUE;
259    }
260
261    if(errmaj) *errmaj = LDR_ONCEONLY;
262    return NULL;
263}
264
265#endif /* XFree86LOADER */
266
267/* Mandatory */
268static void
269SISIdentify(int flags)
270{
271    xf86PrintChipsets(SIS_NAME, "driver for SiS chipsets", SISChipsets);
272    xf86PrintChipsets(SIS_NAME, "driver for XGI chipsets", XGIChipsets);
273}
274
275#ifdef SIS_HAVE_DRIVER_FUNC
276static Bool
277SISDriverFunc(ScrnInfoPtr pScrn, xorgDriverFuncOp op, pointer ptr)
278{
279    CARD32 *flag;
280
281    switch(op) {
282    case RR_GET_INFO:
283	break;
284    case RR_SET_CONFIG:
285	break;
286    case GET_REQUIRED_HW_INTERFACES:
287	break;
288    }
289    return TRUE;
290}
291#endif
292
293static Bool
294SISGetRec(ScrnInfoPtr pScrn)
295{
296    /* Allocate an SISRec, and hook it into pScrn->driverPrivate.
297     * pScrn->driverPrivate is initialised to NULL, so we can check if
298     * the allocation has already been done.
299     */
300    if(pScrn->driverPrivate != NULL) return TRUE;
301
302    pScrn->driverPrivate = xnfcalloc(sizeof(SISRec), 1);
303
304    /* Initialise it to 0 */
305    memset(pScrn->driverPrivate, 0, sizeof(SISRec));
306
307    return TRUE;
308}
309
310static void
311SISFreeRec(ScrnInfoPtr pScrn)
312{
313    SISPtr pSiS = SISPTR(pScrn);
314#ifdef SISDUALHEAD
315    SISEntPtr pSiSEnt = NULL;
316#endif
317
318    /* Just to make sure... */
319    if(!pSiS) return;
320
321#ifdef SISDUALHEAD
322    pSiSEnt = pSiS->entityPrivate;
323#endif
324
325    if(pSiS->pstate) free(pSiS->pstate);
326    pSiS->pstate = NULL;
327    if(pSiS->fonts) free(pSiS->fonts);
328    pSiS->fonts = NULL;
329
330#ifdef SISDUALHEAD
331    if(pSiSEnt) {
332       if(!pSiS->SecondHead) {
333	  /* Free memory only if we are first head; in case of an error
334	   * during init of the second head, the server will continue -
335	   * and we need the BIOS image and SiS_Private for the first
336	   * head.
337	   */
338	  if(pSiSEnt->BIOS) free(pSiSEnt->BIOS);
339	  pSiSEnt->BIOS = pSiS->BIOS = NULL;
340	  if(pSiSEnt->SiS_Pr) free(pSiSEnt->SiS_Pr);
341	  pSiSEnt->SiS_Pr = pSiS->SiS_Pr = NULL;
342	  if(pSiSEnt->RenderAccelArray) free(pSiSEnt->RenderAccelArray);
343	  pSiSEnt->RenderAccelArray = pSiS->RenderAccelArray = NULL;
344	  pSiSEnt->pScrn_1 = NULL;
345       } else {
346	  pSiS->BIOS = NULL;
347	  pSiS->SiS_Pr = NULL;
348	  pSiS->RenderAccelArray = NULL;
349	  pSiSEnt->pScrn_2 = NULL;
350       }
351    } else {
352#endif
353       if(pSiS->BIOS) free(pSiS->BIOS);
354       pSiS->BIOS = NULL;
355       if(pSiS->SiS_Pr) free(pSiS->SiS_Pr);
356       pSiS->SiS_Pr = NULL;
357       if(pSiS->RenderAccelArray) free(pSiS->RenderAccelArray);
358       pSiS->RenderAccelArray = NULL;
359#ifdef SISDUALHEAD
360    }
361#endif
362#ifdef SISMERGED
363    if(pSiS->CRT2HSync) free(pSiS->CRT2HSync);
364    pSiS->CRT2HSync = NULL;
365    if(pSiS->CRT2VRefresh) free(pSiS->CRT2VRefresh);
366    pSiS->CRT2VRefresh = NULL;
367    if(pSiS->MetaModes) free(pSiS->MetaModes);
368    pSiS->MetaModes = NULL;
369    if(pSiS->CRT2pScrn) {
370       if(pSiS->CRT2pScrn->modes) {
371	  while(pSiS->CRT2pScrn->modes)
372	     xf86DeleteMode(&pSiS->CRT2pScrn->modes, pSiS->CRT2pScrn->modes);
373       }
374       if(pSiS->CRT2pScrn->monitor) {
375	  if(pSiS->CRT2pScrn->monitor->Modes) {
376	     while(pSiS->CRT2pScrn->monitor->Modes)
377	        xf86DeleteMode(&pSiS->CRT2pScrn->monitor->Modes, pSiS->CRT2pScrn->monitor->Modes);
378	  }
379	  if(pSiS->CRT2pScrn->monitor->DDC) free(pSiS->CRT2pScrn->monitor->DDC);
380	  free(pSiS->CRT2pScrn->monitor);
381       }
382       free(pSiS->CRT2pScrn);
383       pSiS->CRT2pScrn = NULL;
384    }
385    if(pSiS->CRT1Modes) {
386       if(pSiS->CRT1Modes != pScrn->modes) {
387	  if(pScrn->modes) {
388	     pScrn->currentMode = pScrn->modes;
389	     do {
390	        DisplayModePtr p = pScrn->currentMode->next;
391	        if(pScrn->currentMode->Private)
392	 	  free(pScrn->currentMode->Private);
393	        free(pScrn->currentMode);
394	        pScrn->currentMode = p;
395	     } while(pScrn->currentMode != pScrn->modes);
396	  }
397	  pScrn->currentMode = pSiS->CRT1CurrentMode;
398	  pScrn->modes = pSiS->CRT1Modes;
399	  pSiS->CRT1CurrentMode = NULL;
400	  pSiS->CRT1Modes = NULL;
401       }
402    }
403#endif
404    while(pSiS->SISVESAModeList) {
405       sisModeInfoPtr mp = pSiS->SISVESAModeList->next;
406       free(pSiS->SISVESAModeList);
407       pSiS->SISVESAModeList = mp;
408    }
409    if(pSiS->pVbe) vbeFree(pSiS->pVbe);
410    pSiS->pVbe = NULL;
411
412#ifdef SISUSEDEVPORT
413    if(pSiS->sisdevportopen)   close(sisdevport);
414#endif
415
416    if(pScrn->driverPrivate == NULL)
417        return;
418    free(pScrn->driverPrivate);
419    pScrn->driverPrivate = NULL;
420}
421
422static void
423SISErrorLog(ScrnInfoPtr pScrn, const char *format, ...)
424{
425    va_list ap;
426    static const char *str = "**************************************************\n";
427
428    va_start(ap, format);
429    xf86DrvMsg(pScrn->scrnIndex, X_ERROR, str);
430    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
431	"                      ERROR:\n");
432    xf86VDrvMsgVerb(pScrn->scrnIndex, X_ERROR, 1, format, ap);
433    va_end(ap);
434    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
435	"                  END OF MESSAGE\n");
436    xf86DrvMsg(pScrn->scrnIndex, X_ERROR, str);
437}
438
439static void
440SiS_SiSFB_Lock(ScrnInfoPtr pScrn, Bool lock)
441{
442    SISPtr  pSiS = SISPTR(pScrn);
443    int     fd;
444    CARD32  parm;
445
446    if(!pSiS->sisfbfound) return;
447    if(!pSiS->sisfb_havelock) return;
448
449    if((fd = open(pSiS->sisfbdevname, O_RDONLY)) != -1) {
450       parm = lock ? 1 : 0;
451       ioctl(fd, SISFB_SET_LOCK, &parm);
452       close(fd);
453    }
454}
455
456/* Probe()
457 *
458 * Mandatory
459 */
460static Bool
461SISProbe(DriverPtr drv, int flags)
462{
463    int     i;
464    GDevPtr *devSections;
465    int     *usedChipsSiS, *usedChipsXGI;
466    int     numDevSections;
467    int     numUsed, numUsedSiS, numUsedXGI;
468    Bool    foundScreen = FALSE;
469
470    /*
471     * The aim here is to find all cards that this driver can handle,
472     * and for the ones not already claimed by another driver, claim the
473     * slot, and allocate a ScrnInfoRec.
474     *
475     * This should be a minimal probe, and it should under no circumstances
476     * change the state of the hardware.  Because a device is found, don't
477     * assume that it will be used.  Don't do any initialisations other than
478     * the required ScrnInfoRec initialisations.  Don't allocate any new
479     * data structures.
480     *
481     */
482
483    /*
484     * Next we check, if there has been a chipset override in the config file.
485     * For this we must find out if there is an active device section which
486     * is relevant, i.e., which has no driver specified or has THIS driver
487     * specified.
488     */
489
490    if((numDevSections = xf86MatchDevice(SIS_DRIVER_NAME, &devSections)) <= 0) {
491       /*
492        * There's no matching device section in the config file, so quit
493        * now.
494        */
495       return FALSE;
496    }
497
498    /*
499     * We need to probe the hardware first.  We then need to see how this
500     * fits in with what is given in the config file, and allow the config
501     * file info to override any contradictions.
502     */
503
504    /*
505     * All of the cards this driver supports are PCI, so the "probing" just
506     * amounts to checking the PCI data that the server has already collected.
507     */
508#ifndef XSERVER_LIBPCIACCESS
509    if(xf86GetPciVideoInfo() == NULL) {
510       /*
511        * We won't let anything in the config file override finding no
512        * PCI video cards at all.
513        */
514       return FALSE;
515    }
516#endif
517
518    numUsedSiS = xf86MatchPciInstances(SIS_NAME, PCI_VENDOR_SIS,
519			SISChipsets, SISPciChipsets, devSections,
520			numDevSections, drv, &usedChipsSiS);
521
522    numUsedXGI = xf86MatchPciInstances(SIS_NAME, PCI_VENDOR_XGI,
523			XGIChipsets, XGIPciChipsets, devSections,
524			numDevSections, drv, &usedChipsXGI);
525
526    /* Free it since we don't need that list after this */
527    free(devSections);
528
529    numUsed = numUsedSiS + numUsedXGI;
530
531    if(numUsed <= 0)
532       return FALSE;
533
534    if(flags & PROBE_DETECT) {
535
536	foundScreen = TRUE;
537
538    } else for(i = 0; i < numUsed; i++) {
539
540	ScrnInfoPtr pScrn;
541#ifdef SISDUALHEAD
542	EntityInfoPtr pEnt;
543#endif
544
545	/* Allocate a ScrnInfoRec and claim the slot */
546	pScrn = NULL;
547
548	if((pScrn = xf86ConfigPciEntity(pScrn, 0,
549			(i < numUsedSiS) ? usedChipsSiS[i] : usedChipsXGI[i-numUsedSiS],
550			(i < numUsedSiS) ? SISPciChipsets  : XGIPciChipsets,
551			NULL, NULL, NULL, NULL, NULL))) {
552	    /* Fill in what we can of the ScrnInfoRec */
553	    pScrn->driverVersion    = SIS_CURRENT_VERSION;
554	    pScrn->driverName       = SIS_DRIVER_NAME;
555	    pScrn->name             = SIS_NAME;
556	    pScrn->Probe            = SISProbe;
557	    pScrn->PreInit          = SISPreInit;
558	    pScrn->ScreenInit       = SISScreenInit;
559	    pScrn->SwitchMode       = SISSwitchMode;
560	    pScrn->AdjustFrame      = SISAdjustFrame;
561	    pScrn->EnterVT          = SISEnterVT;
562	    pScrn->LeaveVT          = SISLeaveVT;
563	    pScrn->FreeScreen       = SISFreeScreen;
564	    pScrn->ValidMode        = SISValidMode;
565
566	    foundScreen = TRUE;
567	}
568
569#ifdef SISDUALHEAD
570	pEnt = xf86GetEntityInfo((i < numUsedSiS) ? usedChipsSiS[i] : usedChipsXGI[i-numUsedSiS]);
571
572	if(pEnt->chipset == PCI_CHIP_SIS630 || pEnt->chipset == PCI_CHIP_SIS540 ||
573	   pEnt->chipset == PCI_CHIP_SIS650 || pEnt->chipset == PCI_CHIP_SIS550 ||
574	   pEnt->chipset == PCI_CHIP_SIS315 || pEnt->chipset == PCI_CHIP_SIS315H ||
575	   pEnt->chipset == PCI_CHIP_SIS315PRO || pEnt->chipset == PCI_CHIP_SIS330 ||
576	   pEnt->chipset == PCI_CHIP_SIS300 || pEnt->chipset == PCI_CHIP_SIS660 ||
577	   pEnt->chipset == PCI_CHIP_SIS340 || pEnt->chipset == PCI_CHIP_XGIXG40) {
578
579	    SISEntPtr pSiSEnt = NULL;
580	    DevUnion  *pPriv;
581
582	    xf86SetEntitySharable((i < numUsedSiS) ? usedChipsSiS[i] : usedChipsXGI[i-numUsedSiS]);
583	    if(SISEntityIndex < 0) {
584	       SISEntityIndex = xf86AllocateEntityPrivateIndex();
585	    }
586	    pPriv = xf86GetEntityPrivate(pScrn->entityList[0], SISEntityIndex);
587	    if(!pPriv->ptr) {
588	       pPriv->ptr = xnfcalloc(sizeof(SISEntRec), 1);
589	       pSiSEnt = pPriv->ptr;
590	       memset(pSiSEnt, 0, sizeof(SISEntRec));
591	       pSiSEnt->lastInstance = -1;
592	    } else {
593	       pSiSEnt = pPriv->ptr;
594	    }
595	    pSiSEnt->lastInstance++;
596	    xf86SetEntityInstanceForScreen(pScrn, pScrn->entityList[0],
597	                                   pSiSEnt->lastInstance);
598	}
599#endif /* DUALHEAD */
600
601    }
602
603    if(usedChipsSiS) free(usedChipsSiS);
604    if(usedChipsXGI) free(usedChipsXGI);
605
606    return foundScreen;
607}
608
609/* Various helpers */
610
611static unsigned short
612calcgammaval(int j, int nramp, float invgamma, float bri, float c)
613{
614    float k = (float)j;
615    float nrm1 = (float)(nramp - 1);
616    float con = c * nrm1 / 3.0;
617    float l, v;
618
619    if(con != 0.0) {
620       l = nrm1 / 2.0;
621       if(con <= 0.0) {
622          k -= l;
623          k *= (l + con) / l;
624       } else {
625          l -= 1.0;
626          k -= l;
627          k *= l / (l - con);
628       }
629       k += l;
630       if(k < 0.0) k = 0.0;
631    }
632
633    if(invgamma == 1.0) {
634       v = k / nrm1 * 65535.0;
635    } else {
636       v = pow(k / nrm1, invgamma) * 65535.0 + 0.5;
637    }
638
639    v += (bri * (65535.0 / 3.0)) ;
640
641    if(v < 0.0) v = 0.0;
642    else if(v > 65535.0) v = 65535.0;
643
644    return (unsigned short)v;
645}
646
647#ifdef SISGAMMARAMP
648void
649SISCalculateGammaRamp(ScreenPtr pScreen, ScrnInfoPtr pScrn)
650{
651   SISPtr pSiS = SISPTR(pScrn);
652   int    i, j, nramp;
653   UShort *ramp[3];
654   float  gamma_max[3], framp;
655   Bool   newmethod = FALSE;
656
657   if(!(pSiS->SiS_SD3_Flags & SiS_SD3_OLDGAMMAINUSE)) {
658      newmethod = TRUE;
659   } else {
660      gamma_max[0] = (float)pSiS->GammaBriR / 1000;
661      gamma_max[1] = (float)pSiS->GammaBriG / 1000;
662      gamma_max[2] = (float)pSiS->GammaBriB / 1000;
663   }
664
665   if(!(nramp = xf86GetGammaRampSize(pScreen))) return;
666
667   for(i=0; i<3; i++) {
668      ramp[i] = (UShort *)malloc(nramp * sizeof(UShort));
669      if(!ramp[i]) {
670	 if(ramp[0]) { free(ramp[0]); ramp[0] = NULL; }
671	 if(ramp[1]) { free(ramp[1]); ramp[1] = NULL; }
672	 return;
673      }
674   }
675
676   if(newmethod) {
677
678      for(i = 0; i < 3; i++) {
679
680         float invgamma = 0.0, bri = 0.0, con = 0.0;
681
682         switch(i) {
683         case 0: invgamma = 1. / pScrn->gamma.red;
684		 bri = pSiS->NewGammaBriR;
685		 con = pSiS->NewGammaConR;
686		 break;
687         case 1: invgamma = 1. / pScrn->gamma.green;
688		 bri = pSiS->NewGammaBriG;
689		 con = pSiS->NewGammaConG;
690		 break;
691         case 2: invgamma = 1. / pScrn->gamma.blue;
692		 bri = pSiS->NewGammaBriB;
693                 con = pSiS->NewGammaConB;
694		 break;
695         }
696
697	 for(j = 0; j < nramp; j++) {
698	    ramp[i][j] = calcgammaval(j, nramp, invgamma, bri, con);
699	 }
700
701      }
702
703   } else {
704
705      for(i = 0; i < 3; i++) {
706         int fullscale = 65535 * gamma_max[i];
707         float dramp = 1. / (nramp - 1);
708         float invgamma = 0.0, v;
709
710         switch(i) {
711         case 0: invgamma = 1. / pScrn->gamma.red; break;
712         case 1: invgamma = 1. / pScrn->gamma.green; break;
713         case 2: invgamma = 1. / pScrn->gamma.blue; break;
714         }
715
716         for(j = 0; j < nramp; j++) {
717	    framp = pow(j * dramp, invgamma);
718
719	    v = (fullscale < 0) ? (65535 + fullscale * framp) :
720			       fullscale * framp;
721	    if(v < 0) v = 0;
722	    else if(v > 65535) v = 65535;
723	    ramp[i][j] = (UShort)v;
724         }
725      }
726
727   }
728
729   xf86ChangeGammaRamp(pScreen, nramp, ramp[0], ramp[1], ramp[2]);
730
731   free(ramp[0]);
732   free(ramp[1]);
733   free(ramp[2]);
734   ramp[0] = ramp[1] = ramp[2] = NULL;
735}
736#endif
737
738void
739SISCalculateGammaRampCRT2(ScrnInfoPtr pScrn)
740{
741   SISPtr pSiS = SISPTR(pScrn);
742   int    i;
743   int    myshift = 16 - pScrn->rgbBits;
744   int    maxvalue = (1 << pScrn->rgbBits) - 1;
745   int    reds = pScrn->mask.red >> pScrn->offset.red;
746   int    greens = pScrn->mask.green >> pScrn->offset.green;
747   int    blues = pScrn->mask.blue >> pScrn->offset.blue;
748   float  framp, invgamma1, invgamma2, invgamma3, v;
749
750   invgamma1  = 1. / pSiS->GammaR2;
751   invgamma2  = 1. / pSiS->GammaG2;
752   invgamma3  = 1. / pSiS->GammaB2;
753
754   if(!(pSiS->SiS_SD3_Flags & SiS_SD3_OLDGAMMAINUSE)) {
755
756      for(i = 0; i < pSiS->CRT2ColNum; i++) {
757         pSiS->crt2gcolortable[i].red = calcgammaval(i, pSiS->CRT2ColNum, invgamma1,
758			pSiS->NewGammaBriR2, pSiS->NewGammaConR2) >> myshift;
759         pSiS->crt2gcolortable[i].green = calcgammaval(i, pSiS->CRT2ColNum, invgamma2,
760			pSiS->NewGammaBriG2, pSiS->NewGammaConG2) >> myshift;
761         pSiS->crt2gcolortable[i].blue = calcgammaval(i, pSiS->CRT2ColNum, invgamma3,
762			pSiS->NewGammaBriB2, pSiS->NewGammaConB2) >> myshift;
763      }
764
765   } else {
766
767      int fullscale1 = 65536 * (float)pSiS->GammaBriR2 / 1000;
768      int fullscale2 = 65536 * (float)pSiS->GammaBriG2 / 1000;
769      int fullscale3 = 65536 * (float)pSiS->GammaBriB2 / 1000;
770
771      float dramp = 1. / (pSiS->CRT2ColNum - 1);
772
773      for(i = 0; i < pSiS->CRT2ColNum; i++) {
774         framp = pow(i * dramp, invgamma1);
775         v = (fullscale1 < 0) ? (65535 + fullscale1 * framp) : fullscale1 * framp;
776         if(v < 0) v = 0;
777         else if(v > 65535) v = 65535;
778         pSiS->crt2gcolortable[i].red = ((UShort)v) >> myshift;
779         framp = pow(i * dramp, invgamma2);
780         v = (fullscale2 < 0) ? (65535 + fullscale2 * framp) : fullscale2 * framp;
781         if(v < 0) v = 0;
782         else if(v > 65535) v = 65535;
783         pSiS->crt2gcolortable[i].green = ((UShort)v) >> myshift;
784         framp = pow(i * dramp, invgamma3);
785         v = (fullscale3 < 0) ? (65535 + fullscale3 * framp) : fullscale3 * framp;
786         if(v < 0) v = 0;
787         else if(v > 65535) v = 65535;
788         pSiS->crt2gcolortable[i].blue = ((UShort)v) >> myshift;
789      }
790
791   }
792
793   for(i = 0; i < pSiS->CRT2ColNum; i++) {
794      pSiS->crt2colors[i].red =
795         pSiS->crt2gcolortable[i * maxvalue / reds].red;
796      pSiS->crt2colors[i].green =
797         pSiS->crt2gcolortable[i * maxvalue / greens].green;
798      pSiS->crt2colors[i].blue  =
799         pSiS->crt2gcolortable[i * maxvalue / blues].blue;
800   }
801}
802
803/* If monitor section has no HSync/VRefresh data,
804 * derive it from DDC data.
805 */
806static void
807SiSSetSyncRangeFromEdid(ScrnInfoPtr pScrn, int flag)
808{
809   MonPtr      mon = pScrn->monitor;
810   xf86MonPtr  ddc = mon->DDC;
811   float       myhhigh = 0.0, myhlow = 0.0, htest;
812   int         myvhigh = 0, myvlow = 0, vtest, i;
813   UChar temp;
814   const myhddctiming myhtiming[12] = {
815       { 1, 0x20, 31.6 }, /* rounded up by .1 */
816       { 1, 0x80, 31.6 },
817       { 1, 0x02, 35.3 },
818       { 1, 0x04, 37.6 },
819       { 1, 0x08, 38.0 },
820       { 1, 0x01, 38.0 },
821       { 2, 0x40, 47.0 },
822       { 2, 0x80, 48.2 },
823       { 2, 0x08, 48.5 },
824       { 2, 0x04, 56.6 },
825       { 2, 0x02, 60.1 },
826       { 2, 0x01, 80.1 }
827   };
828   const myvddctiming myvtiming[11] = {
829       { 1, 0x02, 56 },
830       { 1, 0x01, 60 },
831       { 2, 0x08, 60 },
832       { 2, 0x04, 70 },
833       { 1, 0x80, 71 },
834       { 1, 0x08, 72 },
835       { 2, 0x80, 72 },
836       { 1, 0x04, 75 },
837       { 2, 0x40, 75 },
838       { 2, 0x02, 75 },
839       { 2, 0x01, 75 }
840   };
841
842   if(flag) { /* HSync */
843
844      for(i = 0; i < 4; i++) {
845	 if(ddc->det_mon[i].type == DS_RANGES) {
846	    mon->nHsync = 1;
847	    mon->hsync[0].lo = ddc->det_mon[i].section.ranges.min_h;
848	    mon->hsync[0].hi = ddc->det_mon[i].section.ranges.max_h;
849	    if(mon->hsync[0].lo > 32.0 || mon->hsync[0].hi < 31.0) {
850	       if(ddc->timings1.t1 & 0x80) {
851		  mon->nHsync++;
852		  mon->hsync[1].lo = 31.0;
853		  mon->hsync[1].hi = 32.0;
854	       }
855	    }
856	    return;
857	 }
858      }
859
860      /* If no sync ranges detected in detailed timing table, we
861       * derive them from supported VESA modes.
862       */
863
864      for(i = 0; i < 12; i++) {
865	 if(myhtiming[i].whichone == 1) temp = ddc->timings1.t1;
866	 else                           temp = ddc->timings1.t2;
867	 if(temp & myhtiming[i].mask) {
868	    if((i == 0) || (myhlow > myhtiming[i].rate))
869	       myhlow = myhtiming[i].rate;
870	 }
871	 if(myhtiming[11-i].whichone == 1) temp = ddc->timings1.t1;
872	 else                              temp = ddc->timings1.t2;
873	 if(temp & myhtiming[11-i].mask) {
874	    if((i == 0) || (myhhigh < myhtiming[11-i].rate))
875	       myhhigh = myhtiming[11-i].rate;
876	 }
877      }
878
879      for(i = 0; i < STD_TIMINGS; i++) {
880	 if(ddc->timings2[i].hsize > 256) {
881	    htest = ddc->timings2[i].refresh * 1.05 * ddc->timings2[i].vsize / 1000.0;
882	    if(htest < myhlow)  myhlow  = htest;
883	    if(htest > myhhigh) myhhigh = htest;
884	 }
885      }
886
887      if((myhhigh > 0.0) && (myhlow > 0.0)) {
888	 mon->nHsync = 1;
889	 mon->hsync[0].lo = myhlow - 0.1;
890	 mon->hsync[0].hi = myhhigh;
891      }
892
893
894   } else {  /* Vrefresh */
895
896      for(i = 0; i < 4; i++) {
897         if(ddc->det_mon[i].type == DS_RANGES) {
898	    mon->nVrefresh = 1;
899	    mon->vrefresh[0].lo = ddc->det_mon[i].section.ranges.min_v;
900	    mon->vrefresh[0].hi = ddc->det_mon[i].section.ranges.max_v;
901	    if(mon->vrefresh[0].lo > 72 || mon->vrefresh[0].hi < 70) {
902	       if(ddc->timings1.t1 & 0x80) {
903		  mon->nVrefresh++;
904		  mon->vrefresh[1].lo = 71;
905		  mon->vrefresh[1].hi = 71;
906	       }
907	    }
908	    return;
909         }
910      }
911
912      for(i = 0; i < 11; i++) {
913	 if(myvtiming[i].whichone == 1) temp = ddc->timings1.t1;
914	 else                           temp = ddc->timings1.t2;
915	 if(temp & myvtiming[i].mask) {
916	    if((i == 0) || (myvlow > myvtiming[i].rate))
917	       myvlow = myvtiming[i].rate;
918	 }
919	 if(myvtiming[10-i].whichone == 1) temp = ddc->timings1.t1;
920	 else                              temp = ddc->timings1.t2;
921	 if(temp & myvtiming[10-i].mask) {
922	    if((i == 0) || (myvhigh < myvtiming[10-i].rate))
923	       myvhigh = myvtiming[10-i].rate;
924	 }
925      }
926
927      for(i = 0; i < STD_TIMINGS; i++) {
928	 if(ddc->timings2[i].hsize > 256) {
929	    vtest = ddc->timings2[i].refresh;
930	    if(vtest < myvlow)  myvlow  = vtest;
931	    if(vtest > myvhigh) myvhigh = vtest;
932	 }
933      }
934
935      if((myvhigh > 0) && (myvlow > 0)) {
936	 mon->nVrefresh = 1;
937	 mon->vrefresh[0].lo = myvlow;
938	 mon->vrefresh[0].hi = myvhigh;
939      }
940
941   }
942}
943
944static Bool
945SiSAllowSyncOverride(SISPtr pSiS, Bool fromDDC)
946{
947   if(!(pSiS->VBFlags2 & VB2_VIDEOBRIDGE)) return FALSE;
948
949#ifdef SISDUALHEAD
950   if(pSiS->DualHeadMode) {
951      if(pSiS->SecondHead) {
952         if((pSiS->VBFlags & CRT1_LCDA) && (!fromDDC)) return TRUE;
953      } else {
954         if((pSiS->VBFlags & CRT2_TV) ||
955	    ((pSiS->VBFlags & CRT2_LCD) && (!fromDDC))) return TRUE;
956      }
957      return FALSE;
958   }
959#endif
960
961#ifdef SISMERGED
962   if(pSiS->MergedFB) {
963      if((pSiS->VBFlags & CRT1_LCDA) && (!fromDDC)) return TRUE;
964      return FALSE;
965   }
966#endif
967
968   if(!(pSiS->VBFlags & DISPTYPE_CRT1)) {
969      if( (pSiS->VBFlags & CRT2_TV) ||
970	  ((pSiS->VBFlags & CRT2_LCD) && (!fromDDC)) ) return TRUE;
971   } else if((pSiS->VBFlags & CRT1_LCDA) && (!fromDDC)) return TRUE;
972
973   return FALSE;
974}
975
976static Bool
977SiSCheckForH(float hsync, MonPtr monitor)
978{
979   int i;
980   for(i = 0; i < monitor->nHsync; i++) {
981      if((hsync > monitor->hsync[i].lo * (1.0 - SYNC_TOLERANCE)) &&
982	 (hsync < monitor->hsync[i].hi * (1.0 + SYNC_TOLERANCE)))
983	 break;
984   }
985   if(i == monitor->nHsync) return FALSE;
986   return TRUE;
987}
988
989static Bool
990SiSCheckForV(float vrefresh, MonPtr monitor)
991{
992   int i;
993   for(i = 0; i < monitor->nVrefresh; i++) {
994      if((vrefresh > monitor->vrefresh[i].lo * (1.0 - SYNC_TOLERANCE)) &&
995	 (vrefresh < monitor->vrefresh[i].hi * (1.0 + SYNC_TOLERANCE)))
996	 break;
997   }
998   if(i == monitor->nVrefresh) return FALSE;
999   return TRUE;
1000}
1001
1002static Bool
1003CheckAndOverruleH(ScrnInfoPtr pScrn, MonPtr monitor)
1004{
1005   DisplayModePtr mode = monitor->Modes;
1006   float mymin = 30.0, mymax = 80.0, hsync;
1007   Bool doit = FALSE;
1008
1009   for(hsync = mymin; hsync <= mymax; hsync += .5) {
1010      if(!SiSCheckForH(hsync, monitor)) doit = TRUE;
1011   }
1012
1013   if(mode) {
1014      do {
1015         if(mode->type & M_T_BUILTIN) {
1016	    hsync = (float)mode->Clock / (float)mode->HTotal;
1017	    if(!SiSCheckForH(hsync, monitor)) {
1018	       doit = TRUE;
1019	       if(hsync < mymin) mymin = hsync;
1020	       if(hsync > mymax) mymax = hsync;
1021	    }
1022	 }
1023      } while((mode = mode->next));
1024   }
1025
1026   if(doit) {
1027      monitor->nHsync = 1;
1028      monitor->hsync[0].lo = mymin;
1029      monitor->hsync[0].hi = mymax;
1030      return TRUE;
1031   }
1032
1033   return FALSE;
1034}
1035
1036static Bool
1037CheckAndOverruleV(ScrnInfoPtr pScrn, MonPtr monitor)
1038{
1039   DisplayModePtr mode = monitor->Modes;
1040   float mymin = 59.0, mymax = 61.0, vrefresh;
1041   Bool doit = FALSE, ret = FALSE;
1042
1043   for(vrefresh = mymin; vrefresh <= mymax; vrefresh += 1.0) {
1044      if(!SiSCheckForV(vrefresh, monitor)) doit = TRUE;
1045   }
1046
1047   if(mode) {
1048      do {
1049         if(mode->type & M_T_BUILTIN) {
1050	    vrefresh = mode->Clock * 1000.0 / (mode->HTotal * mode->VTotal);
1051	    if(mode->Flags & V_INTERLACE) vrefresh *= 2.0;
1052	    if(mode->Flags & V_DBLSCAN) vrefresh /= 2.0;
1053	    if(!SiSCheckForH(vrefresh, monitor)) {
1054	       doit = TRUE;
1055	       if(vrefresh < mymin) mymin = vrefresh;
1056	       if(vrefresh > mymax) mymax = vrefresh;
1057	    }
1058	 }
1059      } while((mode = mode->next));
1060   }
1061
1062   if(doit) {
1063      monitor->nVrefresh = 1;
1064      monitor->vrefresh[0].lo = mymin;
1065      monitor->vrefresh[0].hi = mymax;
1066      ret = TRUE;
1067   }
1068
1069   /* special for 640x400/320x200/@70Hz (VGA/IBM 720x480) */
1070   if( (!SiSCheckForV(71, monitor)) &&
1071       (monitor->nVrefresh < MAX_VREFRESH) ) {
1072      monitor->vrefresh[monitor->nVrefresh].lo = 71;
1073      monitor->vrefresh[monitor->nVrefresh].hi = 71;
1074      monitor->nVrefresh++;
1075      ret = TRUE;
1076   }
1077   return ret;
1078}
1079
1080/* Some helper functions for MergedFB mode */
1081
1082#ifdef SISMERGED
1083
1084/* Helper function for CRT2 monitor vrefresh/hsync options
1085 * (Code base from mga driver)
1086 */
1087static int
1088SiSStrToRanges(range *r, char *s, int max)
1089{
1090   float num = 0.0;
1091   int rangenum = 0;
1092   Bool gotdash = FALSE;
1093   Bool nextdash = FALSE;
1094   char *strnum = NULL;
1095   do {
1096      switch(*s) {
1097      case '0':
1098      case '1':
1099      case '2':
1100      case '3':
1101      case '4':
1102      case '5':
1103      case '6':
1104      case '7':
1105      case '8':
1106      case '9':
1107      case '.':
1108         if(strnum == NULL) {
1109            strnum = s;
1110            gotdash = nextdash;
1111            nextdash = FALSE;
1112         }
1113         break;
1114      case '-':
1115      case ' ':
1116      case 0:
1117         if(strnum == NULL) break;
1118         sscanf(strnum, "%f", &num);
1119	 strnum = NULL;
1120         if(gotdash) {
1121            r[rangenum - 1].hi = num;
1122         } else {
1123            r[rangenum].lo = num;
1124            r[rangenum].hi = num;
1125            rangenum++;
1126         }
1127         if(*s == '-') nextdash = (rangenum != 0);
1128	 else if(rangenum >= max) return rangenum;
1129         break;
1130      default:
1131         return 0;
1132      }
1133
1134   } while(*(s++) != 0);
1135
1136   return rangenum;
1137}
1138
1139/* Copy and link two modes (i, j) for mergedfb mode
1140 * (Code base taken from mga driver)
1141 *
1142 * - Copy mode i, merge j to copy of i, link the result to dest
1143 * - Link i and j in private record.
1144 * - If dest is NULL, return value is copy of i linked to itself.
1145 * - For mergedfb auto-config, we only check the dimension
1146 *   against virtualX/Y, if they were user-provided.
1147 * - No special treatment required for CRTxxOffs.
1148 * - Provide fake dotclock in order to distinguish between similar
1149 *   looking MetaModes (for RandR and VidMode extensions)
1150 * - Set unique VRefresh of dest mode for RandR
1151 */
1152static DisplayModePtr
1153SiSCopyModeNLink(ScrnInfoPtr pScrn, DisplayModePtr dest,
1154                 DisplayModePtr i, DisplayModePtr j,
1155		 SiSScrn2Rel srel)
1156{
1157    SISPtr pSiS = SISPTR(pScrn);
1158    DisplayModePtr mode;
1159    int dx = 0,dy = 0;
1160
1161    if(!((mode = malloc(sizeof(DisplayModeRec))))) return dest;
1162    memcpy(mode, i, sizeof(DisplayModeRec));
1163    if(!((mode->Private = malloc(sizeof(SiSMergedDisplayModeRec))))) {
1164       free(mode);
1165       return dest;
1166    }
1167    ((SiSMergedDisplayModePtr)mode->Private)->CRT1 = i;
1168    ((SiSMergedDisplayModePtr)mode->Private)->CRT2 = j;
1169    ((SiSMergedDisplayModePtr)mode->Private)->CRT2Position = srel;
1170    mode->PrivSize = 0;
1171
1172    switch(srel) {
1173    case sisLeftOf:
1174    case sisRightOf:
1175       if(!(pScrn->display->virtualX)) {
1176          dx = i->HDisplay + j->HDisplay;
1177       } else {
1178          dx = min(pScrn->virtualX, i->HDisplay + j->HDisplay);
1179       }
1180       dx -= mode->HDisplay;
1181       if(!(pScrn->display->virtualY)) {
1182          dy = max(i->VDisplay, j->VDisplay);
1183       } else {
1184          dy = min(pScrn->virtualY, max(i->VDisplay, j->VDisplay));
1185       }
1186       dy -= mode->VDisplay;
1187       break;
1188    case sisAbove:
1189    case sisBelow:
1190       if(!(pScrn->display->virtualY)) {
1191          dy = i->VDisplay + j->VDisplay;
1192       } else {
1193          dy = min(pScrn->virtualY, i->VDisplay + j->VDisplay);
1194       }
1195       dy -= mode->VDisplay;
1196       if(!(pScrn->display->virtualX)) {
1197          dx = max(i->HDisplay, j->HDisplay);
1198       } else {
1199          dx = min(pScrn->virtualX, max(i->HDisplay, j->HDisplay));
1200       }
1201       dx -= mode->HDisplay;
1202       break;
1203    case sisClone:
1204       if(!(pScrn->display->virtualX)) {
1205          dx = max(i->HDisplay, j->HDisplay);
1206       } else {
1207          dx = min(pScrn->virtualX, max(i->HDisplay, j->HDisplay));
1208       }
1209       dx -= mode->HDisplay;
1210       if(!(pScrn->display->virtualY)) {
1211          dy = max(i->VDisplay, j->VDisplay);
1212       } else {
1213	  dy = min(pScrn->virtualY, max(i->VDisplay, j->VDisplay));
1214       }
1215       dy -= mode->VDisplay;
1216       break;
1217    }
1218    mode->HDisplay += dx;
1219    mode->HSyncStart += dx;
1220    mode->HSyncEnd += dx;
1221    mode->HTotal += dx;
1222    mode->VDisplay += dy;
1223    mode->VSyncStart += dy;
1224    mode->VSyncEnd += dy;
1225    mode->VTotal += dy;
1226
1227    mode->type = M_T_DEFAULT;
1228#if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4,2,99,2,0)
1229    /* Set up as user defined (ie fake that the mode has been named in the
1230     * Modes-list in the screen section; corrects cycling with CTRL-ALT-[-+]
1231     * when source mode has not been listed there.)
1232     */
1233    mode->type |= M_T_USERDEF;
1234#endif
1235
1236    /* Set the VRefresh field (in order to make RandR use it for the rates). We
1237     * simply set this to the refresh rate for the CRT1 mode (since CRT2 will
1238     * mostly be LCD or TV anyway).
1239     */
1240    mode->VRefresh = SiSCalcVRate(i);
1241
1242    if( ((mode->HDisplay * ((pScrn->bitsPerPixel + 7) / 8) * mode->VDisplay) > pSiS->maxxfbmem) ||
1243	(mode->HDisplay > 4088) ||
1244	(mode->VDisplay > 4096) ) {
1245
1246       xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1247		"Skipped \"%s\" (%dx%d), not enough video RAM or beyond hardware specs\n",
1248		mode->name, mode->HDisplay, mode->VDisplay);
1249       free(mode->Private);
1250       free(mode);
1251
1252       return dest;
1253    }
1254
1255#ifdef SISXINERAMA
1256    if(srel != sisClone) {
1257       pSiS->AtLeastOneNonClone = TRUE;
1258    }
1259#endif
1260
1261    /* Now see if the resulting mode would be discarded as a "size" by the
1262     * RandR extension, and increase its clock by 1000 in case it does.
1263     */
1264    if(dest) {
1265       DisplayModePtr t = dest;
1266       do {
1267          if((t->HDisplay == mode->HDisplay) &&
1268	     (t->VDisplay == mode->VDisplay) &&
1269	     ((int)(t->VRefresh + .5) == (int)(mode->VRefresh + .5))) {
1270	     mode->VRefresh += 1000.0;
1271	  }
1272	  t = t->next;
1273       } while((t) && (t != dest));
1274    }
1275
1276    /* Provide a fake but unique DotClock in order to trick the vidmode
1277     * extension to allow selecting among a number of modes whose merged result
1278     * looks identical but consists of different modes for CRT1 and CRT2
1279     */
1280    mode->Clock = (int)(mode->VRefresh * 1000.0);
1281
1282    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1283	"Merged \"%s\" (%dx%d) and \"%s\" (%dx%d) to %dx%d (%d)%s\n",
1284	i->name, i->HDisplay, i->VDisplay, j->name, j->HDisplay, j->VDisplay,
1285	mode->HDisplay, mode->VDisplay, (int)mode->VRefresh,
1286	(srel == sisClone) ? " (Clone)" : "");
1287
1288    mode->next = mode;
1289    mode->prev = mode;
1290
1291    if(dest) {
1292       mode->next = dest->next; 	/* Insert node after "dest" */
1293       dest->next->prev = mode;
1294       mode->prev = dest;
1295       dest->next = mode;
1296    }
1297
1298    return mode;
1299}
1300
1301/* Helper function to find a mode from a given name
1302 * (Code base taken from mga driver)
1303 */
1304static DisplayModePtr
1305SiSGetModeFromName(char* str, DisplayModePtr i)
1306{
1307    DisplayModePtr c = i;
1308    if(!i) return NULL;
1309    do {
1310       if(strcmp(str, c->name) == 0) return c;
1311       c = c->next;
1312    } while(c != i);
1313    return NULL;
1314}
1315
1316static DisplayModePtr
1317SiSFindWidestTallestMode(DisplayModePtr i, Bool tallest)
1318{
1319    DisplayModePtr c = i, d = NULL;
1320    int max = 0;
1321    if(!i) return NULL;
1322    do {
1323       if(tallest) {
1324          if(c->VDisplay > max) {
1325	     max = c->VDisplay;
1326	     d = c;
1327          }
1328       } else {
1329          if(c->HDisplay > max) {
1330	     max = c->HDisplay;
1331	     d = c;
1332          }
1333       }
1334       c = c->next;
1335    } while(c != i);
1336    return d;
1337}
1338
1339static void
1340SiSFindWidestTallestCommonMode(DisplayModePtr i, DisplayModePtr j, Bool tallest,
1341				DisplayModePtr *a, DisplayModePtr *b)
1342{
1343    DisplayModePtr c = i, d;
1344    int max = 0;
1345    Bool foundone;
1346
1347    (*a) = (*b) = NULL;
1348
1349    if(!i || !j) return;
1350
1351    do {
1352       d = j;
1353       foundone = FALSE;
1354       do {
1355	  if( (c->HDisplay == d->HDisplay) &&
1356	      (c->VDisplay == d->VDisplay) ) {
1357	     foundone = TRUE;
1358	     break;
1359	  }
1360	  d = d->next;
1361       } while(d != j);
1362       if(foundone) {
1363	  if(tallest) {
1364	     if(c->VDisplay > max) {
1365		max = c->VDisplay;
1366		(*a) = c;
1367		(*b) = d;
1368	     }
1369	  } else {
1370	     if(c->HDisplay > max) {
1371		max = c->HDisplay;
1372		(*a) = c;
1373		(*b) = d;
1374	     }
1375	  }
1376       }
1377       c = c->next;
1378    } while(c != i);
1379}
1380
1381static DisplayModePtr
1382SiSGenerateModeListFromLargestModes(ScrnInfoPtr pScrn,
1383		    DisplayModePtr i, DisplayModePtr j,
1384		    SiSScrn2Rel srel)
1385{
1386#ifdef SISXINERAMA
1387    SISPtr pSiS = SISPTR(pScrn);
1388#endif
1389    DisplayModePtr mode1 = NULL;
1390    DisplayModePtr mode2 = NULL;
1391    DisplayModePtr mode3 = NULL;
1392    DisplayModePtr mode4 = NULL;
1393    DisplayModePtr result = NULL;
1394
1395#ifdef SISXINERAMA
1396    pSiS->AtLeastOneNonClone = FALSE;
1397#endif
1398
1399    /* Now build a default list of MetaModes.
1400     * - Non-clone: If the user enabled NonRectangular, we use the
1401     * largest mode for each CRT1 and CRT2. If not, we use the largest
1402     * common mode for CRT1 and CRT2 (if available). Additionally, and
1403     * regardless if the above, we produce a clone mode consisting of
1404     * the largest common mode (if available) in order to use DGA.
1405     * - Clone: If the (global) CRT2Position is Clone, we use the
1406     * largest common mode if available, otherwise the first two modes
1407     * in each list.
1408     */
1409
1410    switch(srel) {
1411    case sisLeftOf:
1412    case sisRightOf:
1413       mode1 = SiSFindWidestTallestMode(i, FALSE);
1414       mode2 = SiSFindWidestTallestMode(j, FALSE);
1415       SiSFindWidestTallestCommonMode(i, j, FALSE, &mode3, &mode4);
1416       break;
1417    case sisAbove:
1418    case sisBelow:
1419       mode1 = SiSFindWidestTallestMode(i, TRUE);
1420       mode2 = SiSFindWidestTallestMode(j, TRUE);
1421       SiSFindWidestTallestCommonMode(i, j, TRUE, &mode3, &mode4);
1422       break;
1423    case sisClone:
1424       SiSFindWidestTallestCommonMode(i, j, FALSE, &mode3, &mode4);
1425       if(mode3 && mode4) {
1426	  mode1 = mode3;
1427	  mode2 = mode4;
1428       } else {
1429	  mode1 = i;
1430	  mode2 = j;
1431       }
1432    }
1433
1434    if(srel != sisClone) {
1435       if(mode3 && mode4 && !pSiS->NonRect) {
1436	  mode1 = mode3;
1437	  mode2 = mode2;
1438       }
1439    }
1440
1441    if(mode1 && mode2) {
1442       result = SiSCopyModeNLink(pScrn, result, mode1, mode2, srel);
1443    }
1444
1445    if(srel != sisClone) {
1446       if(mode3 && mode4) {
1447	  result = SiSCopyModeNLink(pScrn, result, mode3, mode4, sisClone);
1448       }
1449    }
1450
1451    return result;
1452}
1453
1454/* Generate the merged-fb mode modelist
1455 * (Taken from mga driver)
1456 */
1457static DisplayModePtr
1458SiSGenerateModeListFromMetaModes(ScrnInfoPtr pScrn, char* str,
1459		    DisplayModePtr i, DisplayModePtr j,
1460		    SiSScrn2Rel srel)
1461{
1462#ifdef SISXINERAMA
1463    SISPtr pSiS = SISPTR(pScrn);
1464#endif
1465    char* strmode = str;
1466    char modename[256];
1467    Bool gotdash = FALSE;
1468    char gotsep = 0;
1469    SiSScrn2Rel sr;
1470    DisplayModePtr mode1 = NULL;
1471    DisplayModePtr mode2 = NULL;
1472    DisplayModePtr result = NULL;
1473    int myslen;
1474
1475#ifdef SISXINERAMA
1476    pSiS->AtLeastOneNonClone = FALSE;
1477#endif
1478
1479    do {
1480        switch(*str) {
1481        case 0:
1482        case '-':
1483	case '+':
1484        case ' ':
1485	case ',':
1486	case ';':
1487           if(strmode != str) {
1488
1489              myslen = str - strmode;
1490              if(myslen > 255) myslen = 255;
1491  	      strncpy(modename, strmode, myslen);
1492  	      modename[myslen] = 0;
1493
1494              if(gotdash) {
1495                 if(mode1 == NULL) {
1496  	             xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1497  	                        "Error parsing MetaModes parameter\n");
1498  	             return NULL;
1499  	         }
1500                 mode2 = SiSGetModeFromName(modename, j);
1501                 if(!mode2) {
1502                    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1503                        "Mode \"%s\" is not a supported mode for CRT2\n", modename);
1504                    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1505                        "\t(Skipping metamode \"%s%c%s\")\n", mode1->name, gotsep, modename);
1506                    mode1 = NULL;
1507		    gotsep = 0;
1508                 }
1509              } else {
1510                 mode1 = SiSGetModeFromName(modename, i);
1511                 if(!mode1) {
1512                    char* tmps = str;
1513                    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1514                        "Mode \"%s\" is not a supported mode for CRT1\n", modename);
1515                    while(*tmps == ' ' || *tmps == ';') tmps++;
1516                    /* skip the next mode */
1517  	            if(*tmps == '-' || *tmps == '+' || *tmps == ',') {
1518                       tmps++;
1519		       /* skip spaces */
1520		       while(*tmps == ' ' || *tmps == ';') tmps++;
1521		       /* skip modename */
1522		       while(*tmps && *tmps != ' ' && *tmps != ';' && *tmps != '-' && *tmps != '+' && *tmps != ',') tmps++;
1523  	               myslen = tmps - strmode;
1524  	               if(myslen > 255) myslen = 255;
1525  	               strncpy(modename,strmode,myslen);
1526  	               modename[myslen] = 0;
1527                       str = tmps - 1;
1528                    }
1529                    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1530                        "\t(Skipping metamode \"%s\")\n", modename);
1531                    mode1 = NULL;
1532		    gotsep = 0;
1533                 }
1534              }
1535              gotdash = FALSE;
1536           }
1537           strmode = str + 1;
1538           gotdash |= (*str == '-' || *str == '+' || *str == ',');
1539	   if (*str == '-' || *str == '+' || *str == ',')
1540  	      gotsep = *str;
1541
1542           if(*str != 0) break;
1543	   /* Fall through otherwise */
1544
1545        default:
1546           if(!gotdash && mode1) {
1547              sr = srel;
1548	      if(gotsep == '+') sr = sisClone;
1549              if(!mode2) {
1550                 mode2 = SiSGetModeFromName(mode1->name, j);
1551                 sr = sisClone;
1552              }
1553              if(!mode2) {
1554                 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1555                     "Mode \"%s\" is not a supported mode for CRT2\n", mode1->name);
1556                 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1557                     "\t(Skipping metamode \"%s\")\n", modename);
1558                 mode1 = NULL;
1559              } else {
1560                 result = SiSCopyModeNLink(pScrn, result, mode1, mode2, sr);
1561                 mode1 = NULL;
1562                 mode2 = NULL;
1563              }
1564	      gotsep = 0;
1565           }
1566           break;
1567
1568        }
1569
1570    } while(*(str++) != 0);
1571
1572    return result;
1573}
1574
1575static DisplayModePtr
1576SiSGenerateModeList(ScrnInfoPtr pScrn, char* str,
1577		    DisplayModePtr i, DisplayModePtr j,
1578		    SiSScrn2Rel srel)
1579{
1580   SISPtr pSiS = SISPTR(pScrn);
1581
1582   if(str != NULL) {
1583      return(SiSGenerateModeListFromMetaModes(pScrn, str, i, j, srel));
1584   } else {
1585      xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1586	"No MetaModes given, linking %s modes by default\n",
1587	(srel == sisClone) ? "largest common" :
1588	   (pSiS->NonRect ?
1589		(((srel == sisLeftOf) || (srel == sisRightOf)) ? "widest" :  "tallest")
1590		:
1591		(((srel == sisLeftOf) || (srel == sisRightOf)) ? "widest common" :  "tallest common")) );
1592      return(SiSGenerateModeListFromLargestModes(pScrn, i, j, srel));
1593   }
1594}
1595
1596static void
1597SiSRecalcDefaultVirtualSize(ScrnInfoPtr pScrn)
1598{
1599    SISPtr pSiS = SISPTR(pScrn);
1600    DisplayModePtr mode, bmode;
1601    int maxh, maxv;
1602    static const char *str = "MergedFB: Virtual %s %d\n";
1603    static const char *errstr = "Virtual %s to small for given CRT2Position offset\n";
1604
1605    mode = bmode = pScrn->modes;
1606    maxh = maxv = 0;
1607    do {
1608       if(mode->HDisplay > maxh) maxh = mode->HDisplay;
1609       if(mode->VDisplay > maxv) maxv = mode->VDisplay;
1610       mode = mode->next;
1611    } while(mode != bmode);
1612
1613    maxh += pSiS->CRT1XOffs + pSiS->CRT2XOffs;
1614    maxv += pSiS->CRT1YOffs + pSiS->CRT2YOffs;
1615
1616    if(!(pScrn->display->virtualX)) {
1617       if(maxh > 4088) {
1618	  xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1619		"Virtual width with CRT2Position offset beyond hardware specs\n");
1620	  pSiS->CRT1XOffs = pSiS->CRT2XOffs = 0;
1621	  maxh -= (pSiS->CRT1XOffs + pSiS->CRT2XOffs);
1622       }
1623       pScrn->virtualX = maxh;
1624       pScrn->displayWidth = maxh;
1625       xf86DrvMsg(pScrn->scrnIndex, X_PROBED, str, "width", maxh);
1626    } else {
1627       if(maxh < pScrn->display->virtualX) {
1628	  xf86DrvMsg(pScrn->scrnIndex, X_ERROR, errstr, "width");
1629	  pSiS->CRT1XOffs = pSiS->CRT2XOffs = 0;
1630       }
1631    }
1632
1633    if(!(pScrn->display->virtualY)) {
1634       pScrn->virtualY = maxv;
1635       xf86DrvMsg(pScrn->scrnIndex, X_PROBED, str, "height", maxv);
1636    } else {
1637       if(maxv < pScrn->display->virtualY) {
1638	  xf86DrvMsg(pScrn->scrnIndex, X_ERROR, errstr, "height");
1639	  pSiS->CRT1YOffs = pSiS->CRT2YOffs = 0;
1640       }
1641    }
1642}
1643
1644static void
1645SiSMergedFBSetDpi(ScrnInfoPtr pScrn1, ScrnInfoPtr pScrn2, SiSScrn2Rel srel)
1646{
1647   SISPtr pSiS = SISPTR(pScrn1);
1648   MessageType from = X_DEFAULT;
1649   xf86MonPtr DDC1 = (xf86MonPtr)(pScrn1->monitor->DDC);
1650   xf86MonPtr DDC2 = (xf86MonPtr)(pScrn2->monitor->DDC);
1651   int ddcWidthmm = 0, ddcHeightmm = 0;
1652   const char *dsstr = "MergedFB: Display dimensions: (%d, %d) mm\n";
1653
1654   /* This sets the DPI for MergedFB mode. The problem is that
1655    * this can never be exact, because the output devices may
1656    * have different dimensions. This function tries to compromise
1657    * through a few assumptions, and it just calculates an average DPI
1658    * value for both monitors.
1659    */
1660
1661   /* Given DisplaySize should regard BOTH monitors */
1662   pScrn1->widthmm = pScrn1->monitor->widthmm;
1663   pScrn1->heightmm = pScrn1->monitor->heightmm;
1664
1665   /* Get DDC display size; if only either CRT1 or CRT2 provided these,
1666    * assume equal dimensions for both, otherwise add dimensions
1667    */
1668   if( (DDC1 && (DDC1->features.hsize > 0 && DDC1->features.vsize > 0)) &&
1669       (DDC2 && (DDC2->features.hsize > 0 && DDC2->features.vsize > 0)) ) {
1670      ddcWidthmm = max(DDC1->features.hsize, DDC2->features.hsize) * 10;
1671      ddcHeightmm = max(DDC1->features.vsize, DDC2->features.vsize) * 10;
1672      switch(srel) {
1673      case sisLeftOf:
1674      case sisRightOf:
1675	 ddcWidthmm = (DDC1->features.hsize + DDC2->features.hsize) * 10;
1676	 break;
1677      case sisAbove:
1678      case sisBelow:
1679	 ddcHeightmm = (DDC1->features.vsize + DDC2->features.vsize) * 10;
1680      default:
1681	 break;
1682      }
1683   } else if(DDC1 && (DDC1->features.hsize > 0 && DDC1->features.vsize > 0)) {
1684      ddcWidthmm = DDC1->features.hsize * 10;
1685      ddcHeightmm = DDC1->features.vsize * 10;
1686      switch(srel) {
1687      case sisLeftOf:
1688      case sisRightOf:
1689	 ddcWidthmm *= 2;
1690	 break;
1691      case sisAbove:
1692      case sisBelow:
1693	 ddcHeightmm *= 2;
1694      default:
1695	 break;
1696      }
1697   } else if(DDC2 && (DDC2->features.hsize > 0 && DDC2->features.vsize > 0) ) {
1698      ddcWidthmm = DDC2->features.hsize * 10;
1699      ddcHeightmm = DDC2->features.vsize * 10;
1700      switch(srel) {
1701      case sisLeftOf:
1702      case sisRightOf:
1703	 ddcWidthmm *= 2;
1704	 break;
1705      case sisAbove:
1706      case sisBelow:
1707	 ddcHeightmm *= 2;
1708      default:
1709	 break;
1710      }
1711   }
1712
1713   if(monitorResolution > 0) {
1714
1715      /* Set command line given values (overrules given options) */
1716      pScrn1->xDpi = monitorResolution;
1717      pScrn1->yDpi = monitorResolution;
1718      from = X_CMDLINE;
1719
1720   } else if(pSiS->MergedFBXDPI) {
1721
1722      /* Set option-wise given values (overrule DisplaySize) */
1723      pScrn1->xDpi = pSiS->MergedFBXDPI;
1724      pScrn1->yDpi = pSiS->MergedFBYDPI;
1725      from = X_CONFIG;
1726
1727   } else if(pScrn1->widthmm > 0 || pScrn1->heightmm > 0) {
1728
1729      /* Set values calculated from given DisplaySize */
1730      from = X_CONFIG;
1731      if(pScrn1->widthmm > 0) {
1732	 pScrn1->xDpi = (int)((double)pScrn1->virtualX * 25.4 / pScrn1->widthmm);
1733      }
1734      if(pScrn1->heightmm > 0) {
1735	 pScrn1->yDpi = (int)((double)pScrn1->virtualY * 25.4 / pScrn1->heightmm);
1736      }
1737      xf86DrvMsg(pScrn1->scrnIndex, from, dsstr, pScrn1->widthmm, pScrn1->heightmm);
1738
1739    } else if(ddcWidthmm && ddcHeightmm) {
1740
1741      /* Set values from DDC-provided display size */
1742      from = X_PROBED;
1743      xf86DrvMsg(pScrn1->scrnIndex, from, dsstr, ddcWidthmm, ddcHeightmm );
1744      pScrn1->widthmm = ddcWidthmm;
1745      pScrn1->heightmm = ddcHeightmm;
1746      if(pScrn1->widthmm > 0) {
1747	 pScrn1->xDpi = (int)((double)pScrn1->virtualX * 25.4 / pScrn1->widthmm);
1748      }
1749      if(pScrn1->heightmm > 0) {
1750	 pScrn1->yDpi = (int)((double)pScrn1->virtualY * 25.4 / pScrn1->heightmm);
1751      }
1752
1753    } else {
1754
1755      pScrn1->xDpi = pScrn1->yDpi = DEFAULT_DPI;
1756
1757    }
1758
1759    /* Sanity check */
1760    if(pScrn1->xDpi > 0 && pScrn1->yDpi <= 0)
1761       pScrn1->yDpi = pScrn1->xDpi;
1762    if(pScrn1->yDpi > 0 && pScrn1->xDpi <= 0)
1763       pScrn1->xDpi = pScrn1->yDpi;
1764
1765    pScrn2->xDpi = pScrn1->xDpi;
1766    pScrn2->yDpi = pScrn1->yDpi;
1767
1768    xf86DrvMsg(pScrn1->scrnIndex, from, "MergedFB: DPI set to (%d, %d)\n",
1769		pScrn1->xDpi, pScrn1->yDpi);
1770}
1771
1772/* Pseudo-Xinerama extension for MergedFB mode */
1773#ifdef SISXINERAMA
1774
1775static void
1776SiSUpdateXineramaScreenInfo(ScrnInfoPtr pScrn1)
1777{
1778    SISPtr pSiS = SISPTR(pScrn1);
1779    int crt1scrnnum = 0, crt2scrnnum = 1;
1780    int x1=0, x2=0, y1=0, y2=0, h1=0, h2=0, w1=0, w2=0;
1781    int realvirtX, realvirtY;
1782    DisplayModePtr currentMode, firstMode;
1783    Bool infochanged = FALSE;
1784    Bool usenonrect = pSiS->NonRect;
1785    const char *rectxine = "\t... setting up rectangular Xinerama layout\n";
1786
1787    pSiS->MBXNR1XMAX = pSiS->MBXNR1YMAX = pSiS->MBXNR2XMAX = pSiS->MBXNR2YMAX = 65536;
1788    pSiS->HaveNonRect = pSiS->HaveOffsRegions = FALSE;
1789
1790    if(!pSiS->MergedFB) return;
1791
1792    if(SiSnoPanoramiXExtension) return;
1793
1794    if(!SiSXineramadataPtr) return;
1795
1796    if(pSiS->CRT2IsScrn0) {
1797       crt1scrnnum = 1;
1798       crt2scrnnum = 0;
1799    }
1800
1801    /* Attention: Usage of RandR may lead to virtual X and Y dimensions
1802     * actually smaller than our MetaModes. To avoid this, we calculate
1803     * the maxCRT fields here (and not somewhere else, like in CopyNLink)
1804     *
1805     * *** Note: RandR is disabled if one of CRTxxOffs is non-zero.
1806     */
1807
1808    /* "Real" virtual: Virtual without the Offset */
1809    realvirtX = pScrn1->virtualX - pSiS->CRT1XOffs - pSiS->CRT2XOffs;
1810    realvirtY = pScrn1->virtualY - pSiS->CRT1YOffs - pSiS->CRT2YOffs;
1811
1812    if((pSiS->SiSXineramaVX != pScrn1->virtualX) || (pSiS->SiSXineramaVY != pScrn1->virtualY)) {
1813
1814       if(!(pScrn1->modes)) return;
1815
1816       pSiS->maxCRT1_X1 = pSiS->maxCRT1_X2 = 0;
1817       pSiS->maxCRT1_Y1 = pSiS->maxCRT1_Y2 = 0;
1818       pSiS->maxCRT2_X1 = pSiS->maxCRT2_X2 = 0;
1819       pSiS->maxCRT2_Y1 = pSiS->maxCRT2_Y2 = 0;
1820       pSiS->maxClone_X1 = pSiS->maxClone_X2 = 0;
1821       pSiS->maxClone_Y1 = pSiS->maxClone_Y2 = 0;
1822
1823       currentMode = firstMode = pScrn1->modes;
1824
1825       do {
1826
1827          DisplayModePtr p = currentMode->next;
1828          DisplayModePtr i = ((SiSMergedDisplayModePtr)currentMode->Private)->CRT1;
1829          DisplayModePtr j = ((SiSMergedDisplayModePtr)currentMode->Private)->CRT2;
1830          SiSScrn2Rel srel = ((SiSMergedDisplayModePtr)currentMode->Private)->CRT2Position;
1831
1832          if((currentMode->HDisplay <= realvirtX) && (currentMode->VDisplay <= realvirtY) &&
1833	     (i->HDisplay <= realvirtX) && (j->HDisplay <= realvirtX) &&
1834	     (i->VDisplay <= realvirtY) && (j->VDisplay <= realvirtY)) {
1835
1836	     if(srel != sisClone) {
1837		if(pSiS->maxCRT1_X1 == i->HDisplay) {
1838		   if(pSiS->maxCRT1_X2 < j->HDisplay) {
1839		      pSiS->maxCRT1_X2 = j->HDisplay;   /* Widest CRT2 mode displayed with widest CRT1 mode */
1840		   }
1841		} else if(pSiS->maxCRT1_X1 < i->HDisplay) {
1842		   pSiS->maxCRT1_X1 = i->HDisplay;      /* Widest CRT1 mode */
1843		   pSiS->maxCRT1_X2 = j->HDisplay;
1844		}
1845		if(pSiS->maxCRT2_X2 == j->HDisplay) {
1846		   if(pSiS->maxCRT2_X1 < i->HDisplay) {
1847		      pSiS->maxCRT2_X1 = i->HDisplay;   /* Widest CRT1 mode displayed with widest CRT2 mode */
1848		   }
1849		} else if(pSiS->maxCRT2_X2 < j->HDisplay) {
1850		   pSiS->maxCRT2_X2 = j->HDisplay;      /* Widest CRT2 mode */
1851		   pSiS->maxCRT2_X1 = i->HDisplay;
1852		}
1853		if(pSiS->maxCRT1_Y1 == i->VDisplay) {   /* Same as above, but tallest instead of widest */
1854		   if(pSiS->maxCRT1_Y2 < j->VDisplay) {
1855		      pSiS->maxCRT1_Y2 = j->VDisplay;
1856		   }
1857		} else if(pSiS->maxCRT1_Y1 < i->VDisplay) {
1858		   pSiS->maxCRT1_Y1 = i->VDisplay;
1859		   pSiS->maxCRT1_Y2 = j->VDisplay;
1860		}
1861		if(pSiS->maxCRT2_Y2 == j->VDisplay) {
1862		   if(pSiS->maxCRT2_Y1 < i->VDisplay) {
1863		      pSiS->maxCRT2_Y1 = i->VDisplay;
1864		   }
1865		} else if(pSiS->maxCRT2_Y2 < j->VDisplay) {
1866		   pSiS->maxCRT2_Y2 = j->VDisplay;
1867		   pSiS->maxCRT2_Y1 = i->VDisplay;
1868		}
1869	     } else {
1870		if(pSiS->maxClone_X1 < i->HDisplay) {
1871		   pSiS->maxClone_X1 = i->HDisplay;
1872		}
1873		if(pSiS->maxClone_X2 < j->HDisplay) {
1874		   pSiS->maxClone_X2 = j->HDisplay;
1875		}
1876		if(pSiS->maxClone_Y1 < i->VDisplay) {
1877		   pSiS->maxClone_Y1 = i->VDisplay;
1878		}
1879		if(pSiS->maxClone_Y2 < j->VDisplay) {
1880		   pSiS->maxClone_Y2 = j->VDisplay;
1881		}
1882	     }
1883	  }
1884	  currentMode = p;
1885
1886       } while((currentMode) && (currentMode != firstMode));
1887
1888       pSiS->SiSXineramaVX = pScrn1->virtualX;
1889       pSiS->SiSXineramaVY = pScrn1->virtualY;
1890       infochanged = TRUE;
1891
1892    }
1893
1894    if((usenonrect) && (pSiS->CRT2Position != sisClone) && pSiS->maxCRT1_X1) {
1895       switch(pSiS->CRT2Position) {
1896       case sisLeftOf:
1897       case sisRightOf:
1898	  if((pSiS->maxCRT1_Y1 != realvirtY) && (pSiS->maxCRT2_Y2 != realvirtY)) {
1899	     usenonrect = FALSE;
1900	  }
1901	  break;
1902       case sisAbove:
1903       case sisBelow:
1904	  if((pSiS->maxCRT1_X1 != realvirtX) && (pSiS->maxCRT2_X2 != realvirtX)) {
1905	     usenonrect = FALSE;
1906	  }
1907	  break;
1908       case sisClone:
1909	  break;
1910       }
1911       if(infochanged && !usenonrect) {
1912	  xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
1913			"Virtual screen size does not match maximum display modes...\n");
1914	  xf86DrvMsg(pScrn1->scrnIndex, X_INFO, rectxine);
1915
1916       }
1917    } else if(infochanged && usenonrect) {
1918       usenonrect = FALSE;
1919       xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
1920		"Only clone modes available for this virtual screen size...\n");
1921       xf86DrvMsg(pScrn1->scrnIndex, X_INFO, rectxine);
1922    }
1923
1924    if(pSiS->maxCRT1_X1) {		/* Means we have at least one non-clone mode */
1925       switch(pSiS->CRT2Position) {
1926       case sisLeftOf:
1927	  x1 = min(pSiS->maxCRT1_X2, pScrn1->virtualX - pSiS->maxCRT1_X1);
1928	  if(x1 < 0) x1 = 0;
1929	  y1 = pSiS->CRT1YOffs;
1930	  w1 = pScrn1->virtualX - x1;
1931	  h1 = realvirtY;
1932	  if((usenonrect) && (pSiS->maxCRT1_Y1 != realvirtY)) {
1933	     h1 = pSiS->MBXNR1YMAX = pSiS->maxCRT1_Y1;
1934	     pSiS->NonRectDead.x0 = x1;
1935	     pSiS->NonRectDead.x1 = x1 + w1 - 1;
1936	     pSiS->NonRectDead.y0 = y1 + h1;
1937	     pSiS->NonRectDead.y1 = pScrn1->virtualY - 1;
1938	     pSiS->HaveNonRect = TRUE;
1939	  }
1940	  x2 = 0;
1941	  y2 = pSiS->CRT2YOffs;
1942	  w2 = max(pSiS->maxCRT2_X2, pScrn1->virtualX - pSiS->maxCRT2_X1);
1943	  if(w2 > pScrn1->virtualX) w2 = pScrn1->virtualX;
1944	  h2 = realvirtY;
1945	  if((usenonrect) && (pSiS->maxCRT2_Y2 != realvirtY)) {
1946	     h2 = pSiS->MBXNR2YMAX = pSiS->maxCRT2_Y2;
1947	     pSiS->NonRectDead.x0 = x2;
1948	     pSiS->NonRectDead.x1 = x2 + w2 - 1;
1949	     pSiS->NonRectDead.y0 = y2 + h2;
1950	     pSiS->NonRectDead.y1 = pScrn1->virtualY - 1;
1951	     pSiS->HaveNonRect = TRUE;
1952	  }
1953	  break;
1954       case sisRightOf:
1955	  x1 = 0;
1956	  y1 = pSiS->CRT1YOffs;
1957	  w1 = max(pSiS->maxCRT1_X1, pScrn1->virtualX - pSiS->maxCRT1_X2);
1958	  if(w1 > pScrn1->virtualX) w1 = pScrn1->virtualX;
1959	  h1 = realvirtY;
1960	  if((usenonrect) && (pSiS->maxCRT1_Y1 != realvirtY)) {
1961	     h1 = pSiS->MBXNR1YMAX = pSiS->maxCRT1_Y1;
1962	     pSiS->NonRectDead.x0 = x1;
1963	     pSiS->NonRectDead.x1 = x1 + w1 - 1;
1964	     pSiS->NonRectDead.y0 = y1 + h1;
1965	     pSiS->NonRectDead.y1 = pScrn1->virtualY - 1;
1966	     pSiS->HaveNonRect = TRUE;
1967	  }
1968	  x2 = min(pSiS->maxCRT2_X1, pScrn1->virtualX - pSiS->maxCRT2_X2);
1969	  if(x2 < 0) x2 = 0;
1970	  y2 = pSiS->CRT2YOffs;
1971	  w2 = pScrn1->virtualX - x2;
1972	  h2 = realvirtY;
1973	  if((usenonrect) && (pSiS->maxCRT2_Y2 != realvirtY)) {
1974	     h2 = pSiS->MBXNR2YMAX = pSiS->maxCRT2_Y2;
1975	     pSiS->NonRectDead.x0 = x2;
1976	     pSiS->NonRectDead.x1 = x2 + w2 - 1;
1977	     pSiS->NonRectDead.y0 = y2 + h2;
1978	     pSiS->NonRectDead.y1 = pScrn1->virtualY - 1;
1979	     pSiS->HaveNonRect = TRUE;
1980	  }
1981	  break;
1982       case sisAbove:
1983	  x1 = pSiS->CRT1XOffs;
1984	  y1 = min(pSiS->maxCRT1_Y2, pScrn1->virtualY - pSiS->maxCRT1_Y1);
1985	  if(y1 < 0) y1 = 0;
1986	  w1 = realvirtX;
1987	  h1 = pScrn1->virtualY - y1;
1988	  if((usenonrect) && (pSiS->maxCRT1_X1 != realvirtX)) {
1989	     w1 = pSiS->MBXNR1XMAX = pSiS->maxCRT1_X1;
1990	     pSiS->NonRectDead.x0 = x1 + w1;
1991	     pSiS->NonRectDead.x1 = pScrn1->virtualX - 1;
1992	     pSiS->NonRectDead.y0 = y1;
1993	     pSiS->NonRectDead.y1 = y1 + h1 - 1;
1994	     pSiS->HaveNonRect = TRUE;
1995	  }
1996	  x2 = pSiS->CRT2XOffs;
1997	  y2 = 0;
1998	  w2 = realvirtX;
1999	  h2 = max(pSiS->maxCRT2_Y2, pScrn1->virtualY - pSiS->maxCRT2_Y1);
2000	  if(h2 > pScrn1->virtualY) h2 = pScrn1->virtualY;
2001	  if((usenonrect) && (pSiS->maxCRT2_X2 != realvirtX)) {
2002	     w2 = pSiS->MBXNR2XMAX = pSiS->maxCRT2_X2;
2003	     pSiS->NonRectDead.x0 = x2 + w2;
2004	     pSiS->NonRectDead.x1 = pScrn1->virtualX - 1;
2005	     pSiS->NonRectDead.y0 = y2;
2006	     pSiS->NonRectDead.y1 = y2 + h2 - 1;
2007	     pSiS->HaveNonRect = TRUE;
2008	  }
2009	  break;
2010       case sisBelow:
2011	  x1 = pSiS->CRT1XOffs;
2012	  y1 = 0;
2013	  w1 = realvirtX;
2014	  h1 = max(pSiS->maxCRT1_Y1, pScrn1->virtualY - pSiS->maxCRT1_Y2);
2015	  if(h1 > pScrn1->virtualY) h1 = pScrn1->virtualY;
2016	  if((usenonrect) && (pSiS->maxCRT1_X1 != realvirtX)) {
2017	     w1 = pSiS->MBXNR1XMAX = pSiS->maxCRT1_X1;
2018	     pSiS->NonRectDead.x0 = x1 + w1;
2019	     pSiS->NonRectDead.x1 = pScrn1->virtualX - 1;
2020	     pSiS->NonRectDead.y0 = y1;
2021	     pSiS->NonRectDead.y1 = y1 + h1 - 1;
2022	     pSiS->HaveNonRect = TRUE;
2023	  }
2024	  x2 = pSiS->CRT2XOffs;
2025	  y2 = min(pSiS->maxCRT2_Y1, pScrn1->virtualY - pSiS->maxCRT2_Y2);
2026	  if(y2 < 0) y2 = 0;
2027	  w2 = realvirtX;
2028	  h2 = pScrn1->virtualY - y2;
2029	  if((usenonrect) && (pSiS->maxCRT2_X2 != realvirtX)) {
2030	     w2 = pSiS->MBXNR2XMAX = pSiS->maxCRT2_X2;
2031	     pSiS->NonRectDead.x0 = x2 + w2;
2032	     pSiS->NonRectDead.x1 = pScrn1->virtualX - 1;
2033	     pSiS->NonRectDead.y0 = y2;
2034	     pSiS->NonRectDead.y1 = y2 + h2 - 1;
2035	     pSiS->HaveNonRect = TRUE;
2036	  }
2037       default:
2038	  break;
2039       }
2040
2041       switch(pSiS->CRT2Position) {
2042       case sisLeftOf:
2043       case sisRightOf:
2044	  if(pSiS->CRT1YOffs) {
2045	     pSiS->OffDead1.x0 = x1;
2046	     pSiS->OffDead1.x1 = x1 + w1 - 1;
2047	     pSiS->OffDead1.y0 = 0;
2048	     pSiS->OffDead1.y1 = y1 - 1;
2049	     pSiS->OffDead2.x0 = x2;
2050	     pSiS->OffDead2.x1 = x2 + w2 - 1;
2051	     pSiS->OffDead2.y0 = y2 + h2;
2052	     pSiS->OffDead2.y1 = pScrn1->virtualY - 1;
2053	     pSiS->HaveOffsRegions = TRUE;
2054	  } else if(pSiS->CRT2YOffs) {
2055	     pSiS->OffDead1.x0 = x2;
2056	     pSiS->OffDead1.x1 = x2 + w2 - 1;
2057	     pSiS->OffDead1.y0 = 0;
2058	     pSiS->OffDead1.y1 = y2 - 1;
2059	     pSiS->OffDead2.x0 = x1;
2060	     pSiS->OffDead2.x1 = x1 + w1 - 1;
2061	     pSiS->OffDead2.y0 = y1 + h1;
2062	     pSiS->OffDead2.y1 = pScrn1->virtualY - 1;
2063	     pSiS->HaveOffsRegions = TRUE;
2064	  }
2065	  break;
2066       case sisAbove:
2067       case sisBelow:
2068	  if(pSiS->CRT1XOffs) {
2069	     pSiS->OffDead1.x0 = x2 + w2;
2070	     pSiS->OffDead1.x1 = pScrn1->virtualX - 1;
2071	     pSiS->OffDead1.y0 = y2;
2072	     pSiS->OffDead1.y1 = y2 + h2 - 1;
2073	     pSiS->OffDead2.x0 = 0;
2074	     pSiS->OffDead2.x1 = x1 - 1;
2075	     pSiS->OffDead2.y0 = y1;
2076	     pSiS->OffDead2.y1 = y1 + h1 - 1;
2077	     pSiS->HaveOffsRegions = TRUE;
2078	  } else if(pSiS->CRT2XOffs) {
2079	     pSiS->OffDead1.x0 = x1 + w1;
2080	     pSiS->OffDead1.x1 = pScrn1->virtualX - 1;
2081	     pSiS->OffDead1.y0 = y1;
2082	     pSiS->OffDead1.y1 = y1 + h1 - 1;
2083	     pSiS->OffDead2.x0 = 0;
2084	     pSiS->OffDead2.x1 = x2 - 1;
2085	     pSiS->OffDead2.y0 = y2;
2086	     pSiS->OffDead2.y1 = y2 + h2 - 1;
2087	     pSiS->HaveOffsRegions = TRUE;
2088	  }
2089       default:
2090	  break;
2091       }
2092
2093    } else {	/* Only clone-modes left */
2094
2095       x1 = x2 = 0;
2096       y1 = y2 = 0;
2097       w1 = w2 = max(pSiS->maxClone_X1, pSiS->maxClone_X2);
2098       h1 = h2 = max(pSiS->maxClone_Y1, pSiS->maxClone_Y2);
2099
2100    }
2101
2102    SiSXineramadataPtr[crt1scrnnum].x = x1;
2103    SiSXineramadataPtr[crt1scrnnum].y = y1;
2104    SiSXineramadataPtr[crt1scrnnum].width = w1;
2105    SiSXineramadataPtr[crt1scrnnum].height = h1;
2106    SiSXineramadataPtr[crt2scrnnum].x = x2;
2107    SiSXineramadataPtr[crt2scrnnum].y = y2;
2108    SiSXineramadataPtr[crt2scrnnum].width = w2;
2109    SiSXineramadataPtr[crt2scrnnum].height = h2;
2110
2111    if(infochanged) {
2112       xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
2113	  "Pseudo-Xinerama: CRT1 (Screen %d) (%d,%d)-(%d,%d)\n",
2114	  crt1scrnnum, x1, y1, w1+x1-1, h1+y1-1);
2115       xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
2116	  "Pseudo-Xinerama: CRT2 (Screen %d) (%d,%d)-(%d,%d)\n",
2117	  crt2scrnnum, x2, y2, w2+x2-1, h2+y2-1);
2118       if(pSiS->HaveNonRect) {
2119	  xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
2120		"Pseudo-Xinerama: Inaccessible area (%d,%d)-(%d,%d)\n",
2121		pSiS->NonRectDead.x0, pSiS->NonRectDead.y0,
2122		pSiS->NonRectDead.x1, pSiS->NonRectDead.y1);
2123       }
2124       if(pSiS->HaveOffsRegions) {
2125	  xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
2126		"Pseudo-Xinerama: Inaccessible offset area (%d,%d)-(%d,%d)\n",
2127		pSiS->OffDead1.x0, pSiS->OffDead1.y0,
2128		pSiS->OffDead1.x1, pSiS->OffDead1.y1);
2129	  xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
2130		"Pseudo-Xinerama: Inaccessible offset area (%d,%d)-(%d,%d)\n",
2131		pSiS->OffDead2.x0, pSiS->OffDead2.y0,
2132		pSiS->OffDead2.x1, pSiS->OffDead2.y1);
2133       }
2134       if(pSiS->HaveNonRect || pSiS->HaveOffsRegions) {
2135	  xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
2136		"Mouse restriction for inaccessible areas is %s\n",
2137		pSiS->MouseRestrictions ? "enabled" : "disabled");
2138       }
2139    }
2140}
2141
2142/* Proc */
2143
2144int
2145SiSProcXineramaQueryVersion(ClientPtr client)
2146{
2147    xPanoramiXQueryVersionReply	  rep;
2148    register int		  n;
2149
2150    REQUEST_SIZE_MATCH(xPanoramiXQueryVersionReq);
2151    rep.type = X_Reply;
2152    rep.length = 0;
2153    rep.sequenceNumber = client->sequence;
2154    rep.majorVersion = SIS_XINERAMA_MAJOR_VERSION;
2155    rep.minorVersion = SIS_XINERAMA_MINOR_VERSION;
2156    if(client->swapped) {
2157        _swaps(&rep.sequenceNumber, n);
2158        _swapl(&rep.length, n);
2159        _swaps(&rep.majorVersion, n);
2160        _swaps(&rep.minorVersion, n);
2161    }
2162    WriteToClient(client, sizeof(xPanoramiXQueryVersionReply), (char *)&rep);
2163    return (client->noClientException);
2164}
2165
2166int
2167SiSProcXineramaGetState(ClientPtr client)
2168{
2169    REQUEST(xPanoramiXGetStateReq);
2170    WindowPtr			pWin;
2171    xPanoramiXGetStateReply	rep;
2172    register int		n;
2173    int				rc;
2174
2175    REQUEST_SIZE_MATCH(xPanoramiXGetStateReq);
2176    rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
2177    if (rc != Success)
2178        return rc;
2179
2180    rep.type = X_Reply;
2181    rep.length = 0;
2182    rep.sequenceNumber = client->sequence;
2183    rep.state = !SiSnoPanoramiXExtension;
2184    if(client->swapped) {
2185       _swaps (&rep.sequenceNumber, n);
2186       _swapl (&rep.length, n);
2187    }
2188    WriteToClient(client, sizeof(xPanoramiXGetStateReply), (char *)&rep);
2189    return client->noClientException;
2190}
2191
2192int
2193SiSProcXineramaGetScreenCount(ClientPtr client)
2194{
2195    REQUEST(xPanoramiXGetScreenCountReq);
2196    WindowPtr				pWin;
2197    xPanoramiXGetScreenCountReply	rep;
2198    register int			n;
2199    int					rc;
2200
2201    REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq);
2202    rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
2203    if (rc != Success)
2204        return rc;
2205
2206    rep.type = X_Reply;
2207    rep.length = 0;
2208    rep.sequenceNumber = client->sequence;
2209    rep.ScreenCount = SiSXineramaNumScreens;
2210    if(client->swapped) {
2211       _swaps(&rep.sequenceNumber, n);
2212       _swapl(&rep.length, n);
2213    }
2214    WriteToClient(client, sizeof(xPanoramiXGetScreenCountReply), (char *)&rep);
2215    return client->noClientException;
2216}
2217
2218int
2219SiSProcXineramaGetScreenSize(ClientPtr client)
2220{
2221    REQUEST(xPanoramiXGetScreenSizeReq);
2222    WindowPtr				pWin;
2223    xPanoramiXGetScreenSizeReply	rep;
2224    register int			n;
2225    int					rc;
2226
2227    REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq);
2228    rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
2229    if (rc != Success)
2230        return rc;
2231
2232    rep.type = X_Reply;
2233    rep.length = 0;
2234    rep.sequenceNumber = client->sequence;
2235    rep.width  = SiSXineramadataPtr[stuff->screen].width;
2236    rep.height = SiSXineramadataPtr[stuff->screen].height;
2237    if(client->swapped) {
2238       _swaps(&rep.sequenceNumber, n);
2239       _swapl(&rep.length, n);
2240       _swapl(&rep.width, n);
2241       _swapl(&rep.height, n);
2242    }
2243    WriteToClient(client, sizeof(xPanoramiXGetScreenSizeReply), (char *)&rep);
2244    return client->noClientException;
2245}
2246
2247int
2248SiSProcXineramaIsActive(ClientPtr client)
2249{
2250    xXineramaIsActiveReply	rep;
2251
2252    REQUEST_SIZE_MATCH(xXineramaIsActiveReq);
2253
2254    rep.type = X_Reply;
2255    rep.length = 0;
2256    rep.sequenceNumber = client->sequence;
2257    rep.state = !SiSnoPanoramiXExtension;
2258    if(client->swapped) {
2259	register int n;
2260	_swaps(&rep.sequenceNumber, n);
2261	_swapl(&rep.length, n);
2262	_swapl(&rep.state, n);
2263    }
2264    WriteToClient(client, sizeof(xXineramaIsActiveReply), (char *) &rep);
2265    return client->noClientException;
2266}
2267
2268int
2269SiSProcXineramaQueryScreens(ClientPtr client)
2270{
2271    xXineramaQueryScreensReply	rep;
2272
2273    REQUEST_SIZE_MATCH(xXineramaQueryScreensReq);
2274
2275    rep.type = X_Reply;
2276    rep.sequenceNumber = client->sequence;
2277    rep.number = (SiSnoPanoramiXExtension) ? 0 : SiSXineramaNumScreens;
2278    rep.length = rep.number * sz_XineramaScreenInfo >> 2;
2279    if(client->swapped) {
2280       register int n;
2281       _swaps(&rep.sequenceNumber, n);
2282       _swapl(&rep.length, n);
2283       _swapl(&rep.number, n);
2284    }
2285    WriteToClient(client, sizeof(xXineramaQueryScreensReply), (char *)&rep);
2286
2287    if(!SiSnoPanoramiXExtension) {
2288       xXineramaScreenInfo scratch;
2289       int i;
2290
2291       for(i = 0; i < SiSXineramaNumScreens; i++) {
2292	  scratch.x_org  = SiSXineramadataPtr[i].x;
2293	  scratch.y_org  = SiSXineramadataPtr[i].y;
2294	  scratch.width  = SiSXineramadataPtr[i].width;
2295	  scratch.height = SiSXineramadataPtr[i].height;
2296	  if(client->swapped) {
2297	     register int n;
2298	     _swaps(&scratch.x_org, n);
2299	     _swaps(&scratch.y_org, n);
2300	     _swaps(&scratch.width, n);
2301	     _swaps(&scratch.height, n);
2302	  }
2303	  WriteToClient(client, sz_XineramaScreenInfo, (char *)&scratch);
2304       }
2305    }
2306
2307    return client->noClientException;
2308}
2309
2310static int
2311SiSProcXineramaDispatch(ClientPtr client)
2312{
2313    REQUEST(xReq);
2314    switch (stuff->data) {
2315	case X_PanoramiXQueryVersion:
2316	     return SiSProcXineramaQueryVersion(client);
2317	case X_PanoramiXGetState:
2318	     return SiSProcXineramaGetState(client);
2319	case X_PanoramiXGetScreenCount:
2320	     return SiSProcXineramaGetScreenCount(client);
2321	case X_PanoramiXGetScreenSize:
2322	     return SiSProcXineramaGetScreenSize(client);
2323	case X_XineramaIsActive:
2324	     return SiSProcXineramaIsActive(client);
2325	case X_XineramaQueryScreens:
2326	     return SiSProcXineramaQueryScreens(client);
2327    }
2328    return BadRequest;
2329}
2330
2331/* SProc */
2332
2333static int
2334SiSSProcXineramaQueryVersion (ClientPtr client)
2335{
2336    REQUEST(xPanoramiXQueryVersionReq);
2337    register int n;
2338    _swaps(&stuff->length,n);
2339    REQUEST_SIZE_MATCH (xPanoramiXQueryVersionReq);
2340    return SiSProcXineramaQueryVersion(client);
2341}
2342
2343static int
2344SiSSProcXineramaGetState(ClientPtr client)
2345{
2346    REQUEST(xPanoramiXGetStateReq);
2347    register int n;
2348    _swaps (&stuff->length, n);
2349    REQUEST_SIZE_MATCH(xPanoramiXGetStateReq);
2350    return SiSProcXineramaGetState(client);
2351}
2352
2353static int
2354SiSSProcXineramaGetScreenCount(ClientPtr client)
2355{
2356    REQUEST(xPanoramiXGetScreenCountReq);
2357    register int n;
2358    _swaps (&stuff->length, n);
2359    REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq);
2360    return SiSProcXineramaGetScreenCount(client);
2361}
2362
2363static int
2364SiSSProcXineramaGetScreenSize(ClientPtr client)
2365{
2366    REQUEST(xPanoramiXGetScreenSizeReq);
2367    register int n;
2368    _swaps (&stuff->length, n);
2369    REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq);
2370    return SiSProcXineramaGetScreenSize(client);
2371}
2372
2373static int
2374SiSSProcXineramaIsActive(ClientPtr client)
2375{
2376    REQUEST(xXineramaIsActiveReq);
2377    register int n;
2378    _swaps (&stuff->length, n);
2379    REQUEST_SIZE_MATCH(xXineramaIsActiveReq);
2380    return SiSProcXineramaIsActive(client);
2381}
2382
2383static int
2384SiSSProcXineramaQueryScreens(ClientPtr client)
2385{
2386    REQUEST(xXineramaQueryScreensReq);
2387    register int n;
2388    _swaps (&stuff->length, n);
2389    REQUEST_SIZE_MATCH(xXineramaQueryScreensReq);
2390    return SiSProcXineramaQueryScreens(client);
2391}
2392
2393int
2394SiSSProcXineramaDispatch(ClientPtr client)
2395{
2396    REQUEST(xReq);
2397    switch (stuff->data) {
2398	case X_PanoramiXQueryVersion:
2399	     return SiSSProcXineramaQueryVersion(client);
2400	case X_PanoramiXGetState:
2401	     return SiSSProcXineramaGetState(client);
2402	case X_PanoramiXGetScreenCount:
2403	     return SiSSProcXineramaGetScreenCount(client);
2404	case X_PanoramiXGetScreenSize:
2405	     return SiSSProcXineramaGetScreenSize(client);
2406	case X_XineramaIsActive:
2407	     return SiSSProcXineramaIsActive(client);
2408	case X_XineramaQueryScreens:
2409	     return SiSSProcXineramaQueryScreens(client);
2410    }
2411    return BadRequest;
2412}
2413
2414static void
2415SiSXineramaResetProc(ExtensionEntry* extEntry)
2416{
2417    /* Called by CloseDownExtensions() */
2418    if(SiSXineramadataPtr) {
2419       free(SiSXineramadataPtr);
2420       SiSXineramadataPtr = NULL;
2421    }
2422}
2423
2424static void
2425SiSXineramaExtensionInit(ScrnInfoPtr pScrn)
2426{
2427    SISPtr	pSiS = SISPTR(pScrn);
2428    Bool	success = FALSE;
2429
2430    if(!(SiSXineramadataPtr)) {
2431
2432       if(!pSiS->MergedFB) {
2433	  SiSnoPanoramiXExtension = TRUE;
2434	  pSiS->MouseRestrictions = FALSE;
2435	  return;
2436       }
2437
2438#ifdef PANORAMIX
2439       if(!noPanoramiXExtension) {
2440	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2441	     "Xinerama active, not initializing SiS Pseudo-Xinerama\n");
2442	  SiSnoPanoramiXExtension = TRUE;
2443	  pSiS->MouseRestrictions = FALSE;
2444	  return;
2445       }
2446#endif
2447
2448       if(SiSnoPanoramiXExtension) {
2449	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2450	      "SiS Pseudo-Xinerama disabled\n");
2451	  pSiS->MouseRestrictions = FALSE;
2452	  return;
2453       }
2454
2455       if(pSiS->CRT2Position == sisClone) {
2456	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2457	     "Running MergedFB in Clone mode, SiS Pseudo-Xinerama disabled\n");
2458	  SiSnoPanoramiXExtension = TRUE;
2459	  pSiS->MouseRestrictions = FALSE;
2460	  return;
2461       }
2462
2463       if(!(pSiS->AtLeastOneNonClone)) {
2464	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2465	     "Only Clone modes defined, SiS Pseudo-Xinerama disabled\n");
2466	  SiSnoPanoramiXExtension = TRUE;
2467	  pSiS->MouseRestrictions = FALSE;
2468	  return;
2469       }
2470
2471       SiSXineramaNumScreens = 2;
2472
2473       while(SiSXineramaGeneration != serverGeneration) {
2474
2475	  pSiS->XineramaExtEntry = AddExtension(PANORAMIX_PROTOCOL_NAME, 0,0,
2476					SiSProcXineramaDispatch,
2477					SiSSProcXineramaDispatch,
2478					SiSXineramaResetProc,
2479					StandardMinorOpcode);
2480
2481	  if(!pSiS->XineramaExtEntry) break;
2482
2483	  if(!(SiSXineramadataPtr = (SiSXineramaData *)
2484	        calloc(SiSXineramaNumScreens, sizeof(SiSXineramaData)))) break;
2485
2486	  SiSXineramaGeneration = serverGeneration;
2487	  success = TRUE;
2488       }
2489
2490       if(!success) {
2491	  SISErrorLog(pScrn, "Failed to initialize SiS Pseudo-Xinerama extension\n");
2492	  SiSnoPanoramiXExtension = TRUE;
2493	  pSiS->MouseRestrictions = FALSE;
2494	  return;
2495       }
2496
2497       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2498	  "SiS Pseudo-Xinerama extension initialized\n");
2499
2500       pSiS->SiSXineramaVX = 0;
2501       pSiS->SiSXineramaVY = 0;
2502
2503    }
2504
2505    SiSUpdateXineramaScreenInfo(pScrn);
2506
2507}
2508#endif  /* End of PseudoXinerama */
2509
2510static void
2511SiSFreeCRT2Structs(SISPtr pSiS)
2512{
2513    if(pSiS->CRT2pScrn) {
2514       if(pSiS->CRT2pScrn->modes) {
2515	  while(pSiS->CRT2pScrn->modes)
2516	     xf86DeleteMode(&pSiS->CRT2pScrn->modes, pSiS->CRT2pScrn->modes);
2517       }
2518       if(pSiS->CRT2pScrn->monitor) {
2519	  if(pSiS->CRT2pScrn->monitor->Modes) {
2520	     while(pSiS->CRT2pScrn->monitor->Modes)
2521		xf86DeleteMode(&pSiS->CRT2pScrn->monitor->Modes, pSiS->CRT2pScrn->monitor->Modes);
2522	  }
2523	  if(pSiS->CRT2pScrn->monitor->DDC) free(pSiS->CRT2pScrn->monitor->DDC);
2524	  free(pSiS->CRT2pScrn->monitor);
2525       }
2526       free(pSiS->CRT2pScrn);
2527       pSiS->CRT2pScrn = NULL;
2528   }
2529}
2530
2531#endif	/* End of MergedFB helpers */
2532
2533static xf86MonPtr
2534SiSInternalDDC(ScrnInfoPtr pScrn, int crtno)
2535{
2536   SISPtr     pSiS = SISPTR(pScrn);
2537   xf86MonPtr pMonitor = NULL;
2538   UShort     temp = 0xffff, temp1, i, realcrtno = crtno;
2539   UChar      buffer[256];
2540
2541   /* If CRT1 is off, skip DDC */
2542   if((pSiS->CRT1off) && (!crtno)) return NULL;
2543
2544   if(crtno) {
2545      if(pSiS->VBFlags & CRT2_LCD)      realcrtno = 1;
2546      else if(pSiS->VBFlags & CRT2_VGA) realcrtno = 2;
2547      else				return NULL;
2548      if(pSiS->SiS_Pr->DDCPortMixup) realcrtno = 0;
2549   } else {
2550      /* If CRT1 is LCDA, skip DDC (except 301C: DDC allowed, but uses CRT2 port!) */
2551      if(pSiS->VBFlags & CRT1_LCDA) {
2552         if(pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE) realcrtno = 1;
2553         else return NULL;
2554      }
2555   }
2556
2557   i = 3; /* Number of retrys */
2558   do {
2559      temp1 = SiS_HandleDDC(pSiS->SiS_Pr, pSiS->VBFlags, pSiS->VGAEngine,
2560			realcrtno, 0, &buffer[0], pSiS->VBFlags2);
2561      if((temp1) && (temp1 != 0xffff)) temp = temp1;
2562   } while((temp == 0xffff) && i--);
2563   if(temp != 0xffff) {
2564      xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "CRT%d DDC supported\n", crtno + 1);
2565      xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "CRT%d DDC level: %s%s%s%s\n",
2566	     crtno + 1,
2567	     (temp & 0x1a) ? "" : "[none of the supported]",
2568	     (temp & 0x02) ? "2 " : "",
2569	     (temp & 0x08) ? "D&P" : "",
2570             (temp & 0x10) ? "FPDI-2" : "");
2571      if(temp & 0x02) {
2572	 i = 5;  /* Number of retrys */
2573	 do {
2574	    temp = SiS_HandleDDC(pSiS->SiS_Pr, pSiS->VBFlags, pSiS->VGAEngine,
2575				realcrtno, 1, &buffer[0], pSiS->VBFlags2);
2576	 } while((temp) && i--);
2577         if(!temp) {
2578	    if((pMonitor = xf86InterpretEDID(pScrn->scrnIndex, &buffer[0]))) {
2579	       int tempvgagamma = 0, templcdgamma = 0;
2580	       if(buffer[0x14] & 0x80) {
2581	          templcdgamma = (buffer[0x17] + 100) * 10;
2582	       } else {
2583	          tempvgagamma = (buffer[0x17] + 100) * 10;;
2584	       }
2585	       if(crtno == 0) {
2586		  if(tempvgagamma) pSiS->CRT1VGAMonitorGamma = tempvgagamma;
2587		  /* LCD never via (demanded) CRT1 DDC port */
2588	       } else {
2589	          if(tempvgagamma) pSiS->CRT2VGAMonitorGamma = tempvgagamma;
2590	          if(templcdgamma) pSiS->CRT2LCDMonitorGamma = templcdgamma;
2591	       }
2592	       return(pMonitor);
2593	    } else {
2594	       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2595	           "CRT%d DDC EDID corrupt\n", crtno + 1);
2596	    }
2597	 } else if(temp == 0xFFFE) {
2598	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2599	    	"CRT%d DDC data is from wrong device type (%s)\n",
2600			crtno + 1,
2601			(realcrtno == 1) ? "analog instead of digital" : "digital instead of analog");
2602	 } else {
2603            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
2604	    	"CRT%d DDC reading failed\n", crtno + 1);
2605	 }
2606      } else if(temp & 0x18) {
2607         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2608	      "DDC for VESA D&P and FPDI-2 not supported yet.\n");
2609      }
2610   } else {
2611      xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
2612                "CRT%d DDC probing failed\n", crtno + 1);
2613   }
2614   return(NULL);
2615}
2616
2617static xf86MonPtr
2618SiSDoPrivateDDC(ScrnInfoPtr pScrn, int *crtnum)
2619{
2620    SISPtr pSiS = SISPTR(pScrn);
2621
2622#ifdef SISDUALHEAD
2623    if(pSiS->DualHeadMode) {
2624       if(pSiS->SecondHead) {
2625          *crtnum = 1;
2626	  return(SiSInternalDDC(pScrn, 0));
2627       } else {
2628          *crtnum = 2;
2629	  return(SiSInternalDDC(pScrn, 1));
2630       }
2631    } else
2632#endif
2633    if((pSiS->CRT1off) || (!pSiS->CRT1Detected)) {
2634       *crtnum = 2;
2635       return(SiSInternalDDC(pScrn, 1));
2636    } else {
2637       *crtnum = 1;
2638       return(SiSInternalDDC(pScrn, 0));
2639    }
2640}
2641
2642static void
2643SiSFindAspect(ScrnInfoPtr pScrn, xf86MonPtr pMonitor, int crtnum)
2644{
2645    SISPtr pSiS = SISPTR(pScrn);
2646    int UseWide = 0;
2647    int aspect = 0;
2648    Bool fromdim = FALSE;
2649
2650    if((pSiS->VGAEngine == SIS_315_VGA) && (!DIGITAL(pMonitor->features.input_type))) {
2651       if(pMonitor->features.hsize && pMonitor->features.vsize) {
2652	  aspect = (pMonitor->features.hsize * 1000) / pMonitor->features.vsize;
2653	  if(aspect >= 1400) UseWide = 1;
2654	  fromdim = TRUE;
2655       } else if((PREFERRED_TIMING_MODE(pMonitor->features.msc)) &&
2656		 (pMonitor->det_mon[0].type == DT)) {
2657	  aspect = (pMonitor->det_mon[0].section.d_timings.h_active * 1000) /
2658			pMonitor->det_mon[0].section.d_timings.v_active;
2659	  if(aspect >= 1400) UseWide = 1;
2660       }
2661       if(aspect) {
2662	  xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
2663		"According to %s, CRT%d aspect ratio is %.2f:1 (%s)\n",
2664		fromdim ? "DDC size" : "preferred mode",
2665		crtnum, (float)aspect / 1000.0, UseWide ? "wide" : "normal");
2666       } else {
2667	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2668		"Unable to determine CRT%d aspect ratio, assuming \"normal\"\n",
2669		crtnum);
2670       }
2671    }
2672
2673    if((crtnum == 1) && (pSiS->SiS_Pr->SiS_UseWide == -1)) {
2674       pSiS->SiS_Pr->SiS_UseWide = UseWide;
2675    } else if((crtnum == 2) && (pSiS->SiS_Pr->SiS_UseWideCRT2 == -1)) {
2676       pSiS->SiS_Pr->SiS_UseWideCRT2 = UseWide;
2677    }
2678}
2679
2680static Bool
2681SiSMakeOwnModeList(ScrnInfoPtr pScrn, Bool acceptcustommodes, Bool includelcdmodes,
2682                   Bool isfordvi, Bool *havecustommodes, Bool fakecrt2modes, Bool IsForCRT2)
2683{
2684    DisplayModePtr tempmode, delmode, mymodes;
2685
2686    if((mymodes = SiSBuildBuiltInModeList(pScrn, includelcdmodes, isfordvi, fakecrt2modes, IsForCRT2))) {
2687       if(!acceptcustommodes) {
2688	  while(pScrn->monitor->Modes)
2689             xf86DeleteMode(&pScrn->monitor->Modes, pScrn->monitor->Modes);
2690	  pScrn->monitor->Modes = mymodes;
2691       } else {
2692	  delmode = pScrn->monitor->Modes;
2693	  while(delmode) {
2694	     if(delmode->type & M_T_DEFAULT) {
2695	        tempmode = delmode->next;
2696	        xf86DeleteMode(&pScrn->monitor->Modes, delmode);
2697	        delmode = tempmode;
2698	     } else {
2699	        delmode = delmode->next;
2700	     }
2701	  }
2702	  /* Link default modes AFTER user ones */
2703	  if((tempmode = pScrn->monitor->Modes)) {
2704	     *havecustommodes = TRUE;
2705	     while(tempmode) {
2706	        if(!tempmode->next) break;
2707	        else tempmode = tempmode->next;
2708	     }
2709	     tempmode->next = mymodes;
2710	     mymodes->prev = tempmode;
2711	  } else {
2712	     pScrn->monitor->Modes = mymodes;
2713	  }
2714#if 0
2715	  pScrn->monitor->Modes = mymodes;
2716	  while(mymodes) {
2717	     if(!mymodes->next) break;
2718	     else mymodes = mymodes->next;
2719	  }
2720	  mymodes->next = tempmode;
2721	  if(tempmode) {
2722	     tempmode->prev = mymodes;
2723	  }
2724#endif
2725       }
2726       return TRUE;
2727    } else
2728       return FALSE;
2729}
2730
2731static void
2732SiSPrintModes(ScrnInfoPtr pScrn)
2733{
2734    DisplayModePtr p;
2735    float hsync, refresh = 0.0;
2736    char *desc, *desc2, *prefix, *uprefix, *output;
2737
2738    xf86DrvMsg(pScrn->scrnIndex, pScrn->virtualFrom, "Virtual size is %dx%d "
2739	       "(pitch %d)\n", pScrn->virtualX, pScrn->virtualY,
2740	       pScrn->displayWidth);
2741
2742    if((p = pScrn->modes) == NULL) return;
2743
2744    do {
2745	desc = desc2 = "";
2746	uprefix = " ";
2747	prefix = "Mode";
2748	output = "For CRT device: ";
2749	if(p->HSync > 0.0)      hsync = p->HSync;
2750	else if (p->HTotal > 0) hsync = (float)p->Clock / (float)p->HTotal;
2751	else	                hsync = 0.0;
2752	refresh = 0.0;
2753        if(p->VRefresh > 0.0)   refresh = p->VRefresh;
2754        else if (p->HTotal > 0 && p->VTotal > 0) {
2755	   refresh = p->Clock * 1000.0 / p->HTotal / p->VTotal;
2756	   if(p->Flags & V_INTERLACE) refresh *= 2.0;
2757	   if(p->Flags & V_DBLSCAN)   refresh /= 2.0;
2758	   if(p->VScan > 1)  	      refresh /= p->VScan;
2759        }
2760	if(p->Flags & V_INTERLACE) desc = " (I)";
2761	if(p->Flags & V_DBLSCAN)   desc = " (D)";
2762	if(p->VScan > 1) 	   desc2 = " (VScan)";
2763#ifdef M_T_USERDEF
2764	if(p->type & M_T_USERDEF)  uprefix = "*";
2765#endif
2766	if(p->type & M_T_BUILTIN)       {
2767	   prefix = "Built-in mode";
2768	   output = "";
2769	} else if (p->type & M_T_DEFAULT) {
2770	   prefix = "Default mode";
2771	} else {
2772	   output = "";
2773	}
2774
2775	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
2776		"%s%s \"%s\" (%dx%d) (%s%.1f MHz, %.1f kHz, %.1f Hz%s%s)\n",
2777		uprefix, prefix, p->name, p->HDisplay, p->VDisplay, output,
2778		p->Clock / 1000.0, hsync, refresh, desc, desc2);
2779
2780	p = p->next;
2781    } while (p != NULL && p != pScrn->modes);
2782}
2783
2784Bool SISDetermineLCDACap(ScrnInfoPtr pScrn)
2785{
2786    SISPtr pSiS = SISPTR(pScrn);
2787
2788    if( ((pSiS->ChipType == SIS_650)    ||
2789         (pSiS->ChipType == SIS_315PRO) ||
2790         (pSiS->ChipType >= SIS_661))		&&
2791	(pSiS->ChipType != XGI_20)		&&
2792        (pSiS->VBFlags2 & VB2_SISLCDABRIDGE)	&&
2793	(pSiS->VESA != 1) ) {
2794       return TRUE;
2795    }
2796    return FALSE;
2797}
2798
2799void SISSaveDetectedDevices(ScrnInfoPtr pScrn)
2800{
2801    SISPtr  pSiS = SISPTR(pScrn);
2802    /* Backup detected CRT2 devices */
2803    pSiS->detectedCRT2Devices = pSiS->VBFlags & (CRT2_LCD|CRT2_TV|CRT2_VGA|TV_AVIDEO|TV_SVIDEO|
2804                                                 TV_SCART|TV_HIVISION|TV_YPBPR);
2805}
2806
2807static Bool
2808SISCheckBIOS(SISPtr pSiS, UShort mypciid, UShort mypcivendor, int biossize)
2809{
2810    UShort romptr, pciid;
2811
2812    if(!pSiS->BIOS) return FALSE;
2813
2814    if((pSiS->BIOS[0] != 0x55) || (pSiS->BIOS[1] != 0xaa)) return FALSE;
2815
2816    romptr = pSiS->BIOS[0x18] | (pSiS->BIOS[0x19] << 8);
2817    if(romptr > (biossize - 8)) return FALSE;
2818    if((pSiS->BIOS[romptr]   != 'P') || (pSiS->BIOS[romptr+1] != 'C') ||
2819       (pSiS->BIOS[romptr+2] != 'I') || (pSiS->BIOS[romptr+3] != 'R')) return FALSE;
2820
2821    pciid = pSiS->BIOS[romptr+4] | (pSiS->BIOS[romptr+5] << 8);
2822    if(pciid != mypcivendor) return FALSE;
2823
2824    pciid = pSiS->BIOS[romptr+6] | (pSiS->BIOS[romptr+7] << 8);
2825    if(pciid != mypciid) return FALSE;
2826
2827    return TRUE;
2828}
2829
2830static void
2831SiS_LoadInitVBE(ScrnInfoPtr pScrn)
2832{
2833    SISPtr pSiS = SISPTR(pScrn);
2834
2835    /* Don't load the VBE module for secondary
2836     * cards which sisfb POSTed. We don't want
2837     * int10 to overwrite our set up (such as
2838     * disabled a0000 memory address decoding).
2839     * We don't need the VBE anyway because
2840     * the card will never be in text mode,
2841     * and we can restore graphics modes just
2842     * perfectly.
2843     */
2844    if( !pSiS->Primary &&
2845        pSiS->sisfbcardposted)
2846       return;
2847
2848    if(pSiS->pVbe) return;
2849
2850    if(xf86LoadSubModule(pScrn, "vbe")) {
2851#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,99,0,0)
2852       pSiS->pVbe = VBEInit(pSiS->pInt, pSiS->pEnt->index);
2853#else
2854       pSiS->pVbe = VBEExtendedInit(pSiS->pInt, pSiS->pEnt->index,
2855	                SET_BIOS_SCRATCH | RESTORE_BIOS_SCRATCH);
2856#endif
2857    }
2858
2859    if(!pSiS->pVbe) {
2860       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2861	   "Failed to load/initialize vbe module\n");
2862    }
2863}
2864
2865#ifdef SIS_PC_PLATFORM
2866static void
2867SiS_MapVGAMem(ScrnInfoPtr pScrn)
2868{
2869    SISPtr pSiS = SISPTR(pScrn);
2870
2871    /* Map 64k VGA window for saving/restoring CGA fonts */
2872    pSiS->VGAMapSize = 0x10000;
2873    pSiS->VGAMapPhys = 0;	/* Default */
2874    if((!pSiS->Primary) || (!pSiS->VGADecodingEnabled)) {
2875       /* If card is secondary or if a0000-address decoding
2876        * is disabled, set Phys to beginning of our video RAM.
2877	*/
2878       pSiS->VGAMapPhys = PCI_REGION_BASE(pSiS->PciInfo, 0, REGION_MEM);
2879    }
2880    if(!SiSVGAMapMem(pScrn)) {
2881       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2882	  "Failed to map VGA memory (0x%lx), can't save/restore console fonts\n",
2883	  pSiS->VGAMapPhys);
2884    }
2885}
2886#endif
2887
2888static void
2889SiS_CheckKernelFB(ScrnInfoPtr pScrn)
2890{
2891    SISPtr pSiS = SISPTR(pScrn);
2892    int        fd, i;
2893    CARD32     sisfbinfosize = 0, sisfbversion;
2894    sisfb_info *mysisfbinfo;
2895    char       name[16];
2896
2897    pSiS->donttrustpdc = FALSE;
2898    pSiS->sisfbpdc = 0xff;
2899    pSiS->sisfbpdca = 0xff;
2900    pSiS->sisfblcda = 0xff;
2901    pSiS->sisfbscalelcd = -1;
2902    pSiS->sisfbspecialtiming = CUT_NONE;
2903    pSiS->sisfb_haveemi = FALSE;
2904    pSiS->sisfbfound = FALSE;
2905    pSiS->sisfb_tvposvalid = FALSE;
2906    pSiS->sisfbdevname[0] = 0;
2907    pSiS->sisfb_havelock = FALSE;
2908    pSiS->sisfbHaveNewHeapDef = FALSE;
2909    pSiS->sisfbHeapSize = 0;
2910    pSiS->sisfbVideoOffset = 0;
2911    pSiS->sisfbxSTN = FALSE;
2912    pSiS->sisfbcanpost = FALSE;   /* (Old) sisfb can't POST card */
2913    pSiS->sisfbcardposted = TRUE; /* If (old) sisfb is running, card must have been POSTed */
2914    pSiS->sisfbprimary = FALSE;   /* (Old) sisfb doesn't know */
2915
2916    if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
2917
2918       i = 0;
2919       do {
2920
2921	  if(i <= 7) {
2922             sprintf(name, "/dev/fb%1d", i);
2923	  } else {
2924	     sprintf(name, "/dev/fb/%1d", (i - 8));
2925	  }
2926
2927          if((fd = open(name, O_RDONLY)) != -1) {
2928
2929	     Bool gotit = FALSE;
2930
2931 	     if(!ioctl(fd, SISFB_GET_INFO_SIZE, &sisfbinfosize)) {
2932 		if((mysisfbinfo = malloc(sisfbinfosize))) {
2933 		   if(!ioctl(fd, (SISFB_GET_INFO | (sisfbinfosize << 16)), mysisfbinfo)) {
2934 		      gotit = TRUE;
2935 		   } else {
2936 		      free(mysisfbinfo);
2937 		      mysisfbinfo = NULL;
2938 		   }
2939 		}
2940 	     } else {
2941 		if((mysisfbinfo = malloc(sizeof(*mysisfbinfo) + 16))) {
2942 		   if(!ioctl(fd, SISFB_GET_INFO_OLD, mysisfbinfo)) {
2943 		      gotit = TRUE;
2944		      xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2945				"Possibly old version of sisfb detected. Please update.\n");
2946		   } else {
2947		      free(mysisfbinfo);
2948		      mysisfbinfo = NULL;
2949		   }
2950		}
2951	     }
2952
2953	     if(gotit) {
2954
2955		if(mysisfbinfo->sisfb_id == SISFB_ID) {
2956
2957		   sisfbversion = (mysisfbinfo->sisfb_version << 16) |
2958				  (mysisfbinfo->sisfb_revision << 8) |
2959				  (mysisfbinfo->sisfb_patchlevel);
2960
2961	           if(sisfbversion >= SISFB_VERSION(1, 5, 8)) {
2962		      /* Added PCI bus/slot/func into in sisfb Version 1.5.08.
2963		       * Check this to make sure we run on the same card as sisfb
2964		       */
2965		      if((mysisfbinfo->sisfb_pcibus  == pSiS->PciBus)    &&
2966			 (mysisfbinfo->sisfb_pcislot == pSiS->PciDevice) &&
2967			 (mysisfbinfo->sisfb_pcifunc == pSiS->PciFunc)) {
2968			 pSiS->sisfbfound = TRUE;
2969		      }
2970		   } else pSiS->sisfbfound = TRUE;
2971
2972		   if(pSiS->sisfbfound) {
2973		      xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
2974			     "%s: SiS kernel fb driver (sisfb) %d.%d.%d detected (PCI:%02d:%02d.%d)\n",
2975				&name[5],
2976				mysisfbinfo->sisfb_version,
2977				mysisfbinfo->sisfb_revision,
2978				mysisfbinfo->sisfb_patchlevel,
2979				pSiS->PciBus,
2980				pSiS->PciDevice,
2981				pSiS->PciFunc);
2982
2983		      /* Added version/rev/pl in sisfb 1.4.0 */
2984		      if(mysisfbinfo->sisfb_version == 0) {
2985			 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2986				"Old version of sisfb found. Please update.\n");
2987		      }
2988		      /* Basically, we can't trust the pdc register if sisfb is loaded */
2989		      pSiS->donttrustpdc = TRUE;
2990		      pSiS->sisfbHeapStart = mysisfbinfo->heapstart;
2991
2992		      if(sisfbversion >= SISFB_VERSION(1, 7, 20)) {
2993			 pSiS->sisfbHeapSize = mysisfbinfo->sisfb_heapsize;
2994			 pSiS->sisfbVideoOffset = mysisfbinfo->sisfb_videooffset;
2995			 pSiS->sisfbHaveNewHeapDef = TRUE;
2996			 pSiS->sisfbFSTN = mysisfbinfo->sisfb_curfstn;
2997			 pSiS->sisfbDSTN = mysisfbinfo->sisfb_curdstn;
2998			 pSiS->sisfbxSTN = TRUE;
2999			 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3000				"sisfb: memory heap at %dKB, size %dKB, viewport at %dKB\n",
3001				(int)pSiS->sisfbHeapStart, (int)pSiS->sisfbHeapSize,
3002				(int)pSiS->sisfbVideoOffset/1024);
3003		      } else {
3004			 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3005				"sisfb: memory heap at %dKB\n", (int)pSiS->sisfbHeapStart);
3006		      }
3007		      xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3008				"sisfb: using video mode 0x%02x\n", mysisfbinfo->fbvidmode);
3009		      pSiS->OldMode = mysisfbinfo->fbvidmode;
3010		      if(sisfbversion >= SISFB_VERSION(1, 5, 6)) {
3011			 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3012				"sisfb: using %s, reserved %dK\n",
3013				(mysisfbinfo->sisfb_caps & 0x40) ? "SiS300 series Turboqueue" :
3014				   (mysisfbinfo->sisfb_caps & 0x20) ? "SiS315/330/340 series AGP command queue" :
3015				      (mysisfbinfo->sisfb_caps & 0x10) ? "SiS315/330/340 series VRAM command queue" :
3016					(mysisfbinfo->sisfb_caps & 0x08) ? "SiS315/330/340 series MMIO mode" :
3017					   "no command queue",
3018				(int)mysisfbinfo->sisfb_tqlen);
3019		      }
3020		      if(sisfbversion >= SISFB_VERSION(1, 5, 10)) {
3021			 /* We can trust the pdc value if sisfb is of recent version */
3022			 if(pSiS->VGAEngine == SIS_300_VGA) pSiS->donttrustpdc = FALSE;
3023		      }
3024		      if(sisfbversion >= SISFB_VERSION(1, 5, 11)) {
3025			 if(pSiS->VGAEngine == SIS_300_VGA) {
3026			    /* As of 1.5.11, sisfb saved the register for us (300 series) */
3027			    pSiS->sisfbpdc = mysisfbinfo->sisfb_lcdpdc;
3028			    if(!pSiS->sisfbpdc) pSiS->sisfbpdc = 0xff;
3029			 }
3030		      }
3031		      if(sisfbversion >= SISFB_VERSION(1, 5, 14)) {
3032			 if(pSiS->VGAEngine == SIS_315_VGA) {
3033			    pSiS->sisfblcda = mysisfbinfo->sisfb_lcda;
3034			 }
3035		      }
3036		      if(sisfbversion >= SISFB_VERSION(1, 6, 13)) {
3037			 pSiS->sisfbscalelcd = mysisfbinfo->sisfb_scalelcd;
3038			 pSiS->sisfbspecialtiming = mysisfbinfo->sisfb_specialtiming;
3039		      }
3040		      if(sisfbversion >= SISFB_VERSION(1, 6, 16)) {
3041			 if(pSiS->VGAEngine == SIS_315_VGA) {
3042			    pSiS->donttrustpdc = FALSE;
3043			    pSiS->sisfbpdc = mysisfbinfo->sisfb_lcdpdc;
3044			    if(sisfbversion >= SISFB_VERSION(1, 6, 24)) {
3045			       pSiS->sisfb_haveemi = mysisfbinfo->sisfb_haveemi ? TRUE : FALSE;
3046			       pSiS->sisfb_haveemilcd = TRUE;  /* will match most cases */
3047			       pSiS->sisfb_emi30 = mysisfbinfo->sisfb_emi30;
3048			       pSiS->sisfb_emi31 = mysisfbinfo->sisfb_emi31;
3049			       pSiS->sisfb_emi32 = mysisfbinfo->sisfb_emi32;
3050			       pSiS->sisfb_emi33 = mysisfbinfo->sisfb_emi33;
3051			    }
3052			    if(sisfbversion >= SISFB_VERSION(1, 6, 25)) {
3053			       pSiS->sisfb_haveemilcd = mysisfbinfo->sisfb_haveemilcd ? TRUE : FALSE;
3054			    }
3055			    if(sisfbversion >= SISFB_VERSION(1, 6, 31)) {
3056			       pSiS->sisfbpdca = mysisfbinfo->sisfb_lcdpdca;
3057			    } else {
3058			       if(pSiS->sisfbpdc) {
3059				  pSiS->sisfbpdca = (pSiS->sisfbpdc & 0xf0) >> 3;
3060				  pSiS->sisfbpdc  = (pSiS->sisfbpdc & 0x0f) << 1;
3061			       } else {
3062				  pSiS->sisfbpdca = pSiS->sisfbpdc = 0xff;
3063			       }
3064			    }
3065			 }
3066		      }
3067		      if(sisfbversion >= SISFB_VERSION(1, 7, 0)) {
3068		         pSiS->sisfb_havelock = TRUE;
3069			 if(sisfbversion >= SISFB_VERSION(1, 7, 1)) {
3070			    pSiS->sisfb_tvxpos = mysisfbinfo->sisfb_tvxpos;
3071			    pSiS->sisfb_tvypos = mysisfbinfo->sisfb_tvypos;
3072			    pSiS->sisfb_tvposvalid = TRUE;
3073			 }
3074		      }
3075		      if(sisfbversion >= SISFB_VERSION(1, 8, 7)) {
3076			 pSiS->sisfbcanpost = (mysisfbinfo->sisfb_can_post) ? TRUE : FALSE;
3077			 pSiS->sisfbcardposted = (mysisfbinfo->sisfb_card_posted) ? TRUE : FALSE;
3078			 pSiS->sisfbprimary = (mysisfbinfo->sisfb_was_boot_device) ? TRUE : FALSE;
3079			 /* Validity check */
3080			 if(!pSiS->sisfbcardposted) {
3081			    pSiS->sisfbprimary = FALSE;
3082			 }
3083		      }
3084		   }
3085	        }
3086		free(mysisfbinfo);
3087		mysisfbinfo = NULL;
3088	     }
3089	     close (fd);
3090          }
3091	  i++;
3092       } while((i <= 15) && (!pSiS->sisfbfound));
3093
3094       if(pSiS->sisfbfound) {
3095          strncpy(pSiS->sisfbdevname, name, 15);
3096       } else {
3097          xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "sisfb not found\n");
3098       }
3099    }
3100
3101    if(!pSiS->sisfbfound) {
3102       pSiS->sisfbcardposted = FALSE;
3103    }
3104}
3105
3106static void
3107SiSPseudo(ScrnInfoPtr pScrn)
3108{
3109}
3110
3111/* PreInit()
3112 *
3113 * Mandatory
3114 */
3115static Bool
3116SISPreInit(ScrnInfoPtr pScrn, int flags)
3117{
3118    SISPtr pSiS;
3119#ifdef SISDUALHEAD
3120    SISEntPtr pSiSEnt = NULL;
3121#endif
3122    MessageType from;
3123    UChar usScratchCR17, usScratchCR32, usScratchCR63;
3124    UChar usScratchSR1F, srlockReg, crlockReg;
3125    unsigned int i;
3126    int pix24flags, temp;
3127    ClockRangePtr clockRanges;
3128    xf86MonPtr pMonitor = NULL;
3129    Bool didddc2, fromDDC, crt1freqoverruled = FALSE;
3130    UChar CR5F, tempreg;
3131#if defined(SISMERGED) || defined(SISDUALHEAD)
3132    DisplayModePtr first, p, n;
3133#endif
3134#ifdef SISMERGED
3135    Bool crt2freqoverruled = FALSE;
3136#endif
3137
3138    static const char *ddcsstr = "CRT%d DDC monitor info: *******************************************\n";
3139    static const char *ddcestr = "End of CRT%d DDC monitor info *************************************\n";
3140    static const char *subshstr = "Substituting missing CRT%d monitor HSync range by DDC data\n";
3141    static const char *subsvstr = "Substituting missing CRT%d monitor VRefresh range by DDC data\n";
3142    static const char *saneh = "Correcting %s CRT%d monitor HSync range\n";
3143    static const char *sanev = "Correcting %s CRT%d monitor VRefresh range\n";
3144#ifdef SISMERGED
3145    static const char *mergednocrt1 = "CRT1 not detected or forced off. %s.\n";
3146    static const char *mergednocrt2 = "No CRT2 output selected or no video bridge detected. %s.\n";
3147    static const char *mergeddisstr = "MergedFB mode disabled";
3148    static const char *modesforstr = "Modes for CRT%d: **************************************************\n";
3149    static const char *crtsetupstr = "*************************** CRT%d setup ***************************\n";
3150    static const char *crt2monname = "CRT2";
3151#endif
3152#if defined(SISDUALHEAD) || defined(SISMERGED)
3153    static const char *notsuitablestr = "Not using mode \"%s\" (not suitable for %s mode)\n";
3154#endif
3155
3156    if(flags & PROBE_DETECT) {
3157
3158       vbeInfoPtr   pVbe;
3159
3160       if(xf86LoadSubModule(pScrn, "vbe")) {
3161          int index = xf86GetEntityInfo(pScrn->entityList[0])->index;
3162#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,99,0,0)
3163	  if((pVbe = VBEInit(NULL, index)))
3164#else
3165          if((pVbe = VBEExtendedInit(NULL, index, 0)))
3166#endif
3167          {
3168             ConfiguredMonitor = vbeDoEDID(pVbe, NULL);
3169             vbeFree(pVbe);
3170          }
3171       }
3172       return TRUE;
3173    }
3174
3175    /*
3176     * Note: This function is only called once at server startup, and
3177     * not at the start of each server generation.  This means that
3178     * only things that are persistent across server generations can
3179     * be initialised here.  xf86Screens[] is the array of all screens,
3180     * (pScrn is a pointer to one of these).  Privates allocated using
3181     * xf86AllocateScrnInfoPrivateIndex() are too, and should be used
3182     * for data that must persist across server generations.
3183     *
3184     * Per-generation data should be allocated with
3185     * AllocateScreenPrivateIndex() from the ScreenInit() function.
3186     */
3187
3188    /* Check the number of entities, and fail if it isn't one. */
3189    if(pScrn->numEntities != 1) {
3190       SISErrorLog(pScrn, "Number of entities is not 1\n");
3191       return FALSE;
3192    }
3193
3194    /* Due to the liberal license terms this is needed for
3195     * keeping the copyright notice readable and intact in
3196     * binary distributions. Removing this is a copyright
3197     * infringement. Please read the license terms above.
3198     */
3199
3200    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3201	"SiS driver (%d/%02d/%02d-%d, compiled for " SISMYSERVERNAME " %d.%d.%d.%d)\n",
3202	SISDRIVERVERSIONYEAR + 2000, SISDRIVERVERSIONMONTH,
3203	SISDRIVERVERSIONDAY, SISDRIVERREVISION,
3204#ifdef XORG_VERSION_CURRENT
3205	XORG_VERSION_MAJOR, XORG_VERSION_MINOR,
3206	XORG_VERSION_PATCH, XORG_VERSION_SNAP
3207#else
3208	XF86_VERSION_MAJOR, XF86_VERSION_MINOR,
3209	XF86_VERSION_PATCH, XF86_VERSION_SNAP
3210#endif
3211	);
3212    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3213	"Copyright (C) 2001-2005 Thomas Winischhofer <thomas@winischhofer.net> and others\n");
3214    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3215	"*** See http://www.winischhofer.eu/linuxsisvga.shtml\n");
3216    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3217	"*** for documentation and updates.\n");
3218
3219#ifdef XORG_VERSION_CURRENT
3220#if 0  /* no prototype yet */
3221    if(xorgGetVersion() != XORG_VERSION_CURRENT) {
3222       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
3223         "This driver binary is not compiled for this version of " SISMYSERVERNAME "\n");
3224    }
3225#endif
3226#else
3227#if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4,2,99,0,0)
3228    if(xf86GetVersion() != XF86_VERSION_CURRENT) {
3229       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
3230         "This driver binary is not compiled for this version of " SISMYSERVERNAME "\n");
3231    }
3232#endif
3233#endif
3234
3235    /* Allocate the SISRec driverPrivate */
3236    if(!SISGetRec(pScrn)) {
3237       SISErrorLog(pScrn, "Could not allocate memory for pSiS private\n");
3238       return FALSE;
3239    }
3240    pSiS = SISPTR(pScrn);
3241    pSiS->pScrn = pScrn;
3242
3243    pSiS->pInt = NULL;
3244
3245    /* Save PCI Domain Base */
3246#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,99,0,0) || GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 12
3247    pSiS->IODBase = 0;
3248#else
3249    pSiS->IODBase = pScrn->domainIOBase;
3250#endif
3251
3252    /* Get the entity, and make sure it is PCI. */
3253    pSiS->pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
3254    if(pSiS->pEnt->location.type != BUS_PCI) {
3255       SISErrorLog(pScrn, "Entity's bus type is not PCI\n");
3256       goto my_error_0;
3257    }
3258
3259#ifdef SISDUALHEAD
3260    /* Allocate an entity private if necessary */
3261    if(xf86IsEntityShared(pScrn->entityList[0])) {
3262       pSiSEnt = xf86GetEntityPrivate(pScrn->entityList[0], SISEntityIndex)->ptr;
3263       pSiS->entityPrivate = pSiSEnt;
3264
3265       /* If something went wrong, quit here */
3266       if((pSiSEnt->DisableDual) || (pSiSEnt->ErrorAfterFirst)) {
3267	  SISErrorLog(pScrn, "First head encountered fatal error, aborting...\n");
3268	  goto my_error_0;
3269       }
3270    }
3271#endif
3272
3273    /* Find the PCI info for this screen */
3274    pSiS->PciInfo = xf86GetPciInfoForEntity(pSiS->pEnt->index);
3275    pSiS->PciBus = PCI_CFG_BUS(pSiS->PciInfo);    /*SIS_PCI_BUS(pSiS->PciInfo);*/
3276    pSiS->PciDevice = PCI_CFG_DEV(pSiS->PciInfo); /*SIS_PCI_DEVICE(pSiS->PciInfo);*/
3277    pSiS->PciFunc = PCI_CFG_FUNC(pSiS->PciInfo);  /*SIS_PCI_FUNC(pSiS->PciInfo);*/
3278
3279    pSiS->PciTag = pciTag(PCI_DEV_BUS(pSiS->PciInfo),
3280			  PCI_DEV_DEV(pSiS->PciInfo),
3281			  PCI_DEV_FUNC(pSiS->PciInfo));
3282
3283#ifdef SIS_NEED_MAP_IOP
3284    /********************************************/
3285    /*     THIS IS BROKEN AND WON'T WORK        */
3286    /* Reasons:                                 */
3287    /* 1) MIPS and ARM have no i/o ports but    */
3288    /* use memory mapped i/o only. The inX/outX */
3289    /* macros in compiler.h are smart enough to */
3290    /* add "IOPortBase" to the port number, but */
3291    /* "IOPortBase" is never initialized.       */
3292    /* 2) IOPortBase is declared in compiler.h  */
3293    /* itself. So until somebody fixes all      */
3294    /* modules that #include compiler.h to set  */
3295    /* IOPortBase, vga support for MIPS and ARM */
3296    /* is unusable.                             */
3297    /* (In this driver this is solvable because */
3298    /* we have our own vgaHW routines. However, */
3299    /* we use /dev/port for now instead.)       */
3300    /********************************************/
3301    pSiS->IOPAddress = pSiS->IODBase + pSiS->PciInfo->ioBase[2];
3302    if(!SISMapIOPMem(pScrn)) {
3303       SISErrorLog(pScrn, "Could not map I/O port area at 0x%x\n", pSiS->IOPAddress);
3304       goto my_error_0;
3305    } else {
3306       xf86DrvMsg(pScrn->scrnIndex, X_INFO, "I/O port area mapped to %p, size 128\n", pSiS->IOPBase);
3307#if defined(__mips__) || defined(__arm32__)
3308       /* inX/outX macros on these use IOPortBase as offset */
3309       /* This is entirely skrewed. */
3310       IOPortBase = (unsigned int)pSiS->IOPBase;
3311#endif
3312    }
3313#endif
3314
3315    /* Set up i/o port access (for non-x86) */
3316#ifdef SISUSEDEVPORT
3317    if((sisdevport = open("/dev/port", O_RDWR, 0)) == -1) {
3318       SISErrorLog(pScrn, "Failed to open /dev/port for read/write\n");
3319       goto my_error_0;
3320    }
3321    pSiS->sisdevportopen = TRUE;
3322#endif
3323
3324    /*
3325     * Set the Chipset and ChipRev, allowing config file entries to
3326     * override. DANGEROUS!
3327     */
3328    {
3329       SymTabRec *myChipsets = SISChipsets;
3330
3331       if(PCI_DEV_VENDOR_ID(pSiS->PciInfo) == PCI_VENDOR_XGI) {
3332          myChipsets = XGIChipsets;
3333       }
3334
3335       if(pSiS->pEnt->device->chipset && *pSiS->pEnt->device->chipset) {
3336
3337          pScrn->chipset = pSiS->pEnt->device->chipset;
3338          pSiS->Chipset = xf86StringToToken(myChipsets, pScrn->chipset);
3339
3340       } else if(pSiS->pEnt->device->chipID >= 0) {
3341
3342          pSiS->Chipset = pSiS->pEnt->device->chipID;
3343          pScrn->chipset = (char *)xf86TokenToString(myChipsets, pSiS->Chipset);
3344
3345          xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipID override: 0x%04X\n",
3346								pSiS->Chipset);
3347       } else {
3348
3349          pSiS->Chipset = PCI_DEV_DEVICE_ID(pSiS->PciInfo);
3350          pScrn->chipset = (char *)xf86TokenToString(myChipsets, pSiS->Chipset);
3351
3352       }
3353    }
3354
3355    if(pSiS->pEnt->device->chipRev >= 0) {
3356
3357       pSiS->ChipRev = pSiS->pEnt->device->chipRev;
3358       xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipRev override: %d\n",
3359								pSiS->ChipRev);
3360    } else {
3361
3362       pSiS->ChipRev = PCI_DEV_REVISION(pSiS->PciInfo);
3363
3364    }
3365
3366    /*
3367     * This shouldn't happen because such problems should be caught in
3368     * SISProbe(), but check it just in case the user has overridden them.
3369     */
3370    if(pScrn->chipset == NULL) {
3371       SISErrorLog(pScrn, "ChipID 0x%04X is not recognised\n", pSiS->Chipset);
3372       goto my_error_0;
3373    }
3374    if(pSiS->Chipset < 0) {
3375       SISErrorLog(pScrn, "Chipset \"%s\" is not recognised\n", pScrn->chipset);
3376       goto my_error_0;
3377    }
3378
3379    pSiS->SiS6326Flags = 0;
3380
3381    /* Determine VGA engine generation */
3382    switch(pSiS->Chipset) {
3383       case PCI_CHIP_SIS300:
3384       case PCI_CHIP_SIS540:
3385       case PCI_CHIP_SIS630: /* 630 + 730 */
3386          pSiS->VGAEngine = SIS_300_VGA;
3387	  break;
3388       case PCI_CHIP_SIS315H:
3389       case PCI_CHIP_SIS315:
3390       case PCI_CHIP_SIS315PRO:
3391       case PCI_CHIP_SIS550:
3392       case PCI_CHIP_SIS650: /* 650 + 740 */
3393       case PCI_CHIP_SIS330:
3394       case PCI_CHIP_SIS660: /* 660, 661, 741, 760, 761, 670(?), 770 */
3395       case PCI_CHIP_SIS340:
3396       case PCI_CHIP_XGIXG20:
3397       case PCI_CHIP_XGIXG40:
3398          pSiS->VGAEngine = SIS_315_VGA;
3399	  break;
3400       case PCI_CHIP_SIS530:
3401          pSiS->VGAEngine = SIS_530_VGA;
3402	  break;
3403       case PCI_CHIP_SIS6326:
3404          /* Determine SiS6326 revision. According to SiS the differences are:
3405	   * Chip name     Chip type      TV-Out       MPEG II decoder
3406	   * 6326 AGP      Rev. G0/H0     no           no
3407	   * 6326 DVD      Rev. D2        yes          yes
3408	   * 6326          Rev. Cx        yes          yes
3409	   */
3410	  xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3411		"Chipset is SiS6326 %s (revision 0x%02x)\n",
3412		(pSiS->ChipRev == 0xaf) ? "(Ax)" :
3413		   ((pSiS->ChipRev == 0x0a) ? "AGP (G0)" :
3414		      ((pSiS->ChipRev == 0x0b) ? "AGP (H0)" :
3415			 (((pSiS->ChipRev & 0xf0) == 0xd0) ? "DVD (Dx/H0)" :
3416			    (((pSiS->ChipRev & 0xf0) == 0x90) ? "(9x)" :
3417			       (((pSiS->ChipRev & 0xf0) == 0xc0) ? "(Cx)" :
3418				  "(unknown)"))))),
3419		pSiS->ChipRev);
3420	  if((pSiS->ChipRev != 0x0a) && (pSiS->ChipRev != 0x0b)) {
3421	     pSiS->SiS6326Flags |= SIS6326_HASTV;
3422	  }
3423	  /* fall through */
3424       default:
3425	  pSiS->VGAEngine = SIS_OLD_VGA;
3426    }
3427
3428    /* We don't know about the current mode yet */
3429    pSiS->OldMode = 0;
3430
3431    /* Determine whether this is the primary or a secondary
3432     * display adapter. And right here the problem starts:
3433     * On machines with integrated SiS chipsets, the system BIOS
3434     * usually sets VGA_EN on all PCI-to-PCI bridges in the system
3435     * (of which there usually are two: PCI and AGP). This and
3436     * the fact that any PCI card POSTed by sisfb naturally has
3437     * its PCI resources enabled, leads to X assuming that
3438     * there are more than one "primary" cards in the system.
3439     * In this case, X treats ALL cards as "secondary" -
3440     * which by no means is desireable. If sisfb is running,
3441     * we can determine which card really is "primary" (in
3442     * terms of if it's the one that occupies the A0000 area
3443     * etc.) in a better way (Linux 2.6.12 or later). See below.
3444     */
3445    if(!(pSiS->Primary = xf86IsPrimaryPci(pSiS->PciInfo))) {
3446       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3447	   SISMYSERVERNAME " assumes this adapter to be secondary\n");
3448    }
3449
3450    /* Now check if sisfb is running, and if so, retrieve
3451     * all possible info from it. This also resets all
3452     * sisfb_* entries in pSiS regardless of the chipset.
3453     */
3454    SiS_CheckKernelFB(pScrn);
3455
3456    /* Now for that primary/secondary mess: Linux kernel
3457     * 2.6.12 and later knows what card is primary, and so
3458     * does any recent version of sisfb. XFree86/X.org takes
3459     * all adapters as "secondary" if more than one card's
3460     * memory and i/o resources are enabled, and more than
3461     * one PCI bridge in the system has VGA_EN set at server
3462     * start. So, let's start thinking: What is this
3463     * primary/secondary classification needed for anyway?
3464     * (This list might be incomplete for the entire server
3465     * infrastructure, but it's complete as regards the driver's
3466     * purposes of primary/secondary classification.)
3467     *    1) VGA/console font restoring: Here it's irrelevant
3468     *       whether more than one card's resources are enabled
3469     *       at server start or not. Relevant is whether the card
3470     *       occupies the A0000 area at this time. Assuming (?)
3471     *       that this does not change during machine up-time,
3472     *       it suffices to know which device was the boot video
3473     *       device (as determined by Linux 2.6.12 and later).
3474     *       Also, this is only relevant if the card is in text
3475     *       mode; if it's in graphics mode, fonts aren't saved
3476     *       or restored anyway.
3477     *       sisfb tells us if that card is considered the boot
3478     *       video device. The hardware registers tell us if
3479     *       the card's A0000 address decoding is enabled, and if
3480     *       the card currently is in text mode. These three bits
3481     *       of information are enough to decide on whether or not
3482     *       to save/restore fonts.
3483     *    2) POSTing. Same here. Relevant is only whether or not
3484     *       the card has been POSTed once before. POSTing cards
3485     *       on every server start is pretty ugly, especially
3486     *       if a framebuffer driver is already handling it.
3487     * SiS/XGI cards POSTed by sisfb can coexist well with other
3488     * active adapters. So we trust sisfb's information more
3489     * than X's (especially as we only use this information for
3490     * console font restoring and eventual POSTing.)
3491     * What we still need is a way to find out about all this if
3492     * sisfb is not running....
3493     */
3494    if(!pSiS->Primary && pSiS->sisfbprimary) {
3495       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3496		"sisfb reports this adapter to be primary. Seems more reliable.\n");
3497       pSiS->Primary = TRUE;
3498    }
3499
3500    /* If the card is "secondary" and has not been
3501     * POSTed by sisfb, POST it now through int10.
3502     * For cards POSTed by sisfb, we definitely don't
3503     * want that as it messes up our set up (eg. the
3504     * disabled A0000 area).
3505     * The int10 module decides on its own if the
3506     * card is primary or secondary. Since it uses
3507     * the generic technique described above, and since
3508     * for "secondary" cards it needs a real PCI BIOS
3509     * ROM, and since integrated chips don't have such
3510     * a PCI BIOS ROM, int10 will naturally fail to
3511     * find/read the BIOS on such machines. Great.
3512     * Using the integrated graphics as "secondary"
3513     * (which it will be as soon as X finds more than
3514     * one card's mem and i/o resources enabled, and more
3515     * than one PCI bridge's VGA_EN bit set during server
3516     * start) will therefore prevent us from restoring
3517     * the mode using the VBE. That means real fun if
3518     * the integrated chip is set up to use the video
3519     * bridge output for text mode (which is something
3520     * the driver doesn't really support since it's done
3521     * pretty much differently on every machine.)
3522     */
3523#if !defined(__alpha__)
3524    if(!pSiS->Primary) {
3525       if(!pSiS->sisfbcardposted) {
3526	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3527		"Initializing adapter through int10\n");
3528	  if(xf86LoadSubModule(pScrn, "int10")) {
3529	     pSiS->pInt = xf86InitInt10(pSiS->pEnt->index);
3530	  } else {
3531	     SISErrorLog(pScrn, "Failed to load int10 module\n");
3532	  }
3533       } else {
3534	  xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3535		"Adapter already initialized by sisfb\n");
3536       }
3537    }
3538#endif
3539
3540    /* Get the address of our relocated IO registers.
3541     * These are enabled by the hardware during cold boot, and
3542     * by the BIOS. So we can pretty much rely on that these
3543     * are enabled.
3544     */
3545    pSiS->RelIO = (SISIOADDRESS)(PCI_REGION_BASE(pSiS->PciInfo, 2, REGION_IO) + pSiS->IODBase);
3546    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Relocated I/O registers at 0x%lX\n",
3547           (ULong)pSiS->RelIO);
3548
3549    /* Unlock extended registers */
3550    sisSaveUnlockExtRegisterLock(pSiS, &srlockReg, &crlockReg);
3551
3552    /* Is a0000 memory address decoding enabled? */
3553    pSiS->VGADecodingEnabled = TRUE;
3554    switch(pSiS->VGAEngine) {
3555    case SIS_OLD_VGA:
3556       /* n/a */
3557       break;
3558    case SIS_530_VGA:
3559       inSISIDXREG(SISSR, 0x3d, tempreg);
3560       if(tempreg & 0x04) pSiS->VGADecodingEnabled = FALSE;
3561       break;
3562    case SIS_300_VGA:
3563    case SIS_315_VGA:
3564       inSISIDXREG(SISSR, 0x20, tempreg);
3565       if(tempreg & 0x04) pSiS->VGADecodingEnabled = FALSE;
3566       break;
3567    }
3568
3569    if(!pSiS->VGADecodingEnabled) {
3570       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3571		"Standard VGA (0xA0000) memory address decoding is disabled\n");
3572    }
3573
3574#ifdef SIS_PC_PLATFORM
3575    /* Map 64k VGA window for saving/restoring CGA fonts.
3576     * For secondary cards or if A0000 address decoding
3577     * is disabled, this will map the beginning of the
3578     * linear (PCI) video RAM instead.
3579     */
3580    SiS_MapVGAMem(pScrn);
3581#endif
3582
3583#ifndef XSERVER_LIBPCIACCESS
3584    /* Set operating state */
3585
3586    /* 1. memory */
3587    /* [ResUnusedOpr: Resource decoded by hw, but not used]
3588     * [ResDisableOpr: Resource is not decoded by hw]
3589     * So, if a0000 memory decoding is disabled, one could
3590     * argue that we may say so, too. Hm. Quite likely that
3591     * the VBE (via int10) will eventually enable it. So we
3592     * cowardly say unused instead.
3593     */
3594    xf86SetOperatingState(resVgaMem, pSiS->pEnt->index, ResUnusedOpr);
3595
3596    /* 2. i/o */
3597    /* Although we only use the relocated i/o ports, the hardware
3598     * also decodes the standard VGA port range. This could in
3599     * theory be disabled, but I don't dare to do this; in case of
3600     * a server crash, the card would be entirely dead. Also, this
3601     * would prevent int10 and the VBE from working at all. Generic
3602     * access control through the PCI configuration registers does
3603     * nicely anyway.
3604     */
3605    xf86SetOperatingState(resVgaIo, pSiS->pEnt->index, ResUnusedOpr);
3606
3607    /* Operations for which memory access is required */
3608    pScrn->racMemFlags = RAC_FB | RAC_COLORMAP | RAC_CURSOR | RAC_VIEWPORT;
3609
3610    /* Operations for which I/O access is required */
3611    pScrn->racIoFlags = RAC_COLORMAP | RAC_CURSOR | RAC_VIEWPORT;
3612
3613#endif
3614
3615    /* Load ramdac module */
3616    if(!xf86LoadSubModule(pScrn, "ramdac")) {
3617       SISErrorLog(pScrn, "Could not load ramdac module\n");
3618       goto my_error_1;
3619    }
3620
3621    /* Set pScrn->monitor */
3622    pScrn->monitor = pScrn->confScreen->monitor;
3623
3624    /* Reset some entries */
3625    pSiS->SiSFastVidCopy = SiSVidCopyGetDefault();
3626    pSiS->SiSFastMemCopy = SiSVidCopyGetDefault();
3627    pSiS->SiSFastVidCopyFrom = SiSVidCopyGetDefault();
3628    pSiS->SiSFastMemCopyFrom = SiSVidCopyGetDefault();
3629    pSiS->SiSFastVidCopyDone = FALSE;
3630#ifdef SIS_USE_XAA
3631    pSiS->RenderCallback = NULL;
3632#endif
3633#ifdef SIS_USE_EXA
3634    pSiS->ExaRenderCallback = NULL;
3635#endif
3636    pSiS->InitAccel = SiSPseudo;
3637    pSiS->SyncAccel = SiSPseudo;
3638    pSiS->FillRect  = NULL;
3639    pSiS->BlitRect  = NULL;
3640
3641    /* Always do a ValidMode() inside Switchmode() */
3642    pSiS->skipswitchcheck = FALSE;
3643
3644    /* Determine chipset and its capabilities in detail */
3645    pSiS->ChipFlags = 0;
3646    pSiS->SiS_SD_Flags = pSiS->SiS_SD2_Flags = 0;
3647    pSiS->SiS_SD3_Flags = pSiS->SiS_SD4_Flags = 0;
3648    pSiS->HWCursorMBufNum = pSiS->HWCursorCBufNum = 0;
3649    pSiS->NeedFlush = FALSE;
3650    pSiS->NewCRLayout = FALSE;
3651    pSiS->mmioSize = 64;
3652
3653    switch(pSiS->Chipset) {
3654       case PCI_CHIP_SIS530:
3655	  pSiS->ChipType = SIS_530;
3656	  break;
3657       case PCI_CHIP_SIS300:
3658	  pSiS->ChipType = SIS_300;
3659	  pSiS->SiS_SD_Flags |= SiS_SD_IS300SERIES;
3660	  break;
3661       case PCI_CHIP_SIS540:
3662	  pSiS->ChipType = SIS_540;
3663	  pSiS->SiS_SD_Flags |= SiS_SD_IS300SERIES;
3664	  break;
3665       case PCI_CHIP_SIS630: /* 630 + 730 */
3666	  pSiS->ChipType = SIS_630;
3667	  if(sis_pci_read_host_bridge_u32(0x00) == 0x07301039) {
3668	     pSiS->ChipType = SIS_730;
3669	  }
3670	  pSiS->SiS_SD_Flags |= SiS_SD_IS300SERIES;
3671	  break;
3672       case PCI_CHIP_SIS315H:
3673	  pSiS->ChipType = SIS_315H;
3674	  pSiS->ChipFlags |= (SiSCF_315Core | SiSCF_MMIOPalette);
3675	  pSiS->SiS_SD_Flags |= SiS_SD_IS315SERIES;
3676	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3677	  pSiS->myCR63 = 0x63;
3678	  break;
3679       case PCI_CHIP_SIS315:
3680	  /* Override for simplicity */
3681	  pSiS->Chipset = PCI_CHIP_SIS315H;
3682	  pSiS->ChipType = SIS_315;
3683	  pSiS->ChipFlags |= (SiSCF_315Core | SiSCF_MMIOPalette);
3684	  pSiS->SiS_SD_Flags |= SiS_SD_IS315SERIES;
3685	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3686	  pSiS->myCR63 = 0x63;
3687	  break;
3688       case PCI_CHIP_SIS315PRO:
3689	  /* Override for simplicity */
3690	  pSiS->Chipset = PCI_CHIP_SIS315H;
3691	  pSiS->ChipType = SIS_315PRO;
3692	  pSiS->ChipFlags |= (SiSCF_315Core | SiSCF_MMIOPalette);
3693	  pSiS->SiS_SD_Flags |= SiS_SD_IS315SERIES;
3694	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3695	  pSiS->myCR63 = 0x63;
3696	  break;
3697       case PCI_CHIP_SIS550:
3698	  pSiS->ChipType = SIS_550;
3699	  pSiS->ChipFlags |= (SiSCF_Integrated | SiSCF_MMIOPalette);
3700	  pSiS->SiS_SD_Flags |= SiS_SD_IS315SERIES;
3701	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3702	  pSiS->myCR63 = 0x63;
3703	  break;
3704       case PCI_CHIP_SIS650: /* 650 + 740 */
3705	  pSiS->ChipType = SIS_650;
3706	  if(sis_pci_read_host_bridge_u32(0x00) == 0x07401039) {
3707	     pSiS->ChipType = SIS_740;
3708	  }
3709	  pSiS->ChipFlags |= (SiSCF_Integrated | SiSCF_Real256ECore | SiSCF_MMIOPalette);
3710	  pSiS->SiS_SD_Flags |= SiS_SD_IS315SERIES;
3711	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3712	  pSiS->myCR63 = 0x63;
3713	  break;
3714       case PCI_CHIP_SIS330:
3715	  pSiS->ChipType = SIS_330;
3716	  pSiS->ChipFlags |= (SiSCF_XabreCore | SiSCF_MMIOPalette);
3717	  pSiS->SiS_SD_Flags |= SiS_SD_IS330SERIES;
3718	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3719	  pSiS->SiS_SD3_Flags |= SiS_SD3_CRT1SATGAIN; /* FIXME ? */
3720	  pSiS->myCR63 = 0x53; /* sic! */
3721	  break;
3722       case PCI_CHIP_SIS660: /* 660, 661, 741, 760, 761, 670(?) */
3723	  {
3724	     ULong hpciid = sis_pci_read_host_bridge_u32(0x00);
3725	     switch(hpciid) {
3726	     case 0x06601039:
3727		pSiS->ChipType = SIS_660;
3728		pSiS->ChipFlags |= SiSCF_Ultra256Core;
3729		pSiS->NeedFlush = TRUE;
3730		break;
3731	     case 0x07601039:
3732		pSiS->ChipType = SIS_760;
3733		pSiS->ChipFlags |= SiSCF_Ultra256Core;
3734		pSiS->NeedFlush = TRUE;
3735		break;
3736	     case 0x07611039:
3737		pSiS->ChipType = SIS_761;
3738		pSiS->ChipFlags |= SiSCF_Ultra256Core;
3739		pSiS->NeedFlush = TRUE;
3740		break;
3741	     case 0x07701039:
3742		pSiS->ChipType = SIS_770;
3743		pSiS->ChipFlags |= SiSCF_Ultra256Core;
3744		pSiS->NeedFlush = TRUE;
3745		break;
3746	     case 0x07411039:
3747		pSiS->ChipType = SIS_741;
3748		pSiS->ChipFlags |= SiSCF_Real256ECore;
3749		break;
3750	     case 0x06611039:
3751	     default:
3752		pSiS->ChipType = SIS_661;
3753		pSiS->ChipFlags |= SiSCF_Real256ECore;
3754		break;
3755	     case 0x06701039:
3756		pSiS->ChipType = SIS_670;
3757		pSiS->ChipFlags |= SiSCF_Real256ECore;
3758	     }
3759	     /* Detection could also be done by CR5C & 0xf8:
3760	      * 0x10 = 661 (CR5F & 0xc0: 0x00 both A0 and A1)
3761	      * 0x80 = 760 (CR5F & 0xc0: 0x00 A0, 0x40 A1)
3762	      * 0x90 = 741 (CR5F & 0xc0: 0x00 A0,A1 0x40 A2)
3763	      * other: 660 (CR5F & 0xc0: 0x00 A0 0x40 A1) (DOA?)
3764	      */
3765	     pSiS->ChipFlags |= (SiSCF_Integrated | SiSCF_MMIOPalette);
3766	     pSiS->SiS_SD_Flags |= SiS_SD_IS330SERIES;
3767	     pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3768	     pSiS->SiS_SD3_Flags |= SiS_SD3_CRT1SATGAIN;
3769	     pSiS->myCR63 = 0x53; /* sic! */
3770	     pSiS->NewCRLayout = TRUE;
3771	  }
3772	  break;
3773       case PCI_CHIP_SIS340:
3774	  pSiS->ChipType = SIS_340;
3775	  pSiS->ChipFlags |= (SiSCF_XabreCore | SiSCF_MMIOPalette);
3776	  pSiS->SiS_SD_Flags |= SiS_SD_IS340SERIES;
3777	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3778	  pSiS->SiS_SD3_Flags |= SiS_SD3_CRT1SATGAIN;
3779	  pSiS->myCR63 = 0x53;
3780	  pSiS->NewCRLayout = TRUE;
3781	  break;
3782       case PCI_CHIP_XGIXG20:
3783	  pSiS->ChipType = XGI_20;
3784	  pSiS->ChipFlags |= (SiSCF_XabreCore | SiSCF_MMIOPalette | SiSCF_IsXGI);
3785	  pSiS->SiS_SD2_Flags |= (SiS_SD2_NOOVERLAY | SiS_SD2_ISXGI);
3786	  pSiS->myCR63 = 0x53;
3787	  pSiS->NewCRLayout = TRUE;
3788	  break;
3789       case PCI_CHIP_XGIXG40:
3790	  pSiS->ChipType = XGI_40;
3791	  pSiS->ChipFlags |= (SiSCF_XabreCore | SiSCF_MMIOPalette | SiSCF_IsXGI);
3792	  pSiS->SiS_SD2_Flags |= (SiS_SD2_SUPPORTXVHUESAT | SiS_SD2_ISXGI);
3793	  pSiS->SiS_SD3_Flags |= SiS_SD3_CRT1SATGAIN;
3794	  pSiS->myCR63 = 0x53;
3795	  pSiS->NewCRLayout = TRUE;
3796	  if(pSiS->ChipRev == 2) pSiS->ChipFlags |= SiSCF_IsXGIV3;
3797	  break;
3798       default:
3799	  pSiS->ChipType = SIS_OLD;
3800	  break;
3801    }
3802
3803    /*
3804     * Now back to real business: Figure out the depth, bpp, etc.
3805     * Set SupportConvert... flags since we use the fb layer which
3806     * supports this conversion. (24to32 seems not implemented though)
3807     * Additionally, determine the size of the HWCursor memory area.
3808     */
3809    switch(pSiS->VGAEngine) {
3810       case SIS_300_VGA:
3811	  pSiS->CursorSize = 4096;
3812	  pix24flags = Support32bppFb;
3813	  break;
3814       case SIS_315_VGA:
3815	  pSiS->CursorSize = 16384;
3816	  pix24flags = Support32bppFb;
3817	  break;
3818       case SIS_530_VGA:
3819	  pSiS->CursorSize = 2048;
3820	  pix24flags = Support32bppFb	  |
3821		       Support24bppFb	  |
3822		       SupportConvert32to24;
3823          break;
3824       default:
3825	  pSiS->CursorSize = 2048;
3826	  pix24flags = Support24bppFb	    |
3827		       SupportConvert32to24 |
3828		       PreferConvert32to24;
3829	  break;
3830    }
3831
3832#ifdef SISDUALHEAD
3833    /* In case of Dual Head, we need to determine if we are the "master" head or
3834     * the "slave" head. In order to do that, we set PrimInit to DONE in the
3835     * shared entity at the end of the first initialization. The second
3836     * initialization then knows that some things have already been done. THIS
3837     * ALWAYS ASSUMES THAT THE FIRST DEVICE INITIALIZED IS THE MASTER!
3838     */
3839    if(xf86IsEntityShared(pScrn->entityList[0])) {
3840       if(pSiSEnt->lastInstance > 0) {
3841	  if(!xf86IsPrimInitDone(pScrn->entityList[0])) {
3842	     /* First Head (always CRT2) */
3843	     pSiS->SecondHead = FALSE;
3844	     pSiSEnt->pScrn_1 = pScrn;
3845	     pSiSEnt->CRT1ModeNo = pSiSEnt->CRT2ModeNo = -1;
3846	     pSiSEnt->CRT2ModeSet = FALSE;
3847	     pSiS->DualHeadMode = TRUE;
3848	     pSiSEnt->DisableDual = FALSE;
3849	     pSiSEnt->BIOS = NULL;
3850	     pSiSEnt->ROM661New = FALSE;
3851	     pSiSEnt->HaveXGIBIOS = FALSE;
3852	     pSiSEnt->SiS_Pr = NULL;
3853	     pSiSEnt->RenderAccelArray = NULL;
3854	     pSiSEnt->SiSFastVidCopy = pSiSEnt->SiSFastMemCopy = NULL;
3855	     pSiSEnt->SiSFastVidCopyFrom = pSiSEnt->SiSFastMemCopyFrom = NULL;
3856	  } else {
3857	     /* Second Head (always CRT1) */
3858	     pSiS->SecondHead = TRUE;
3859	     pSiSEnt->pScrn_2 = pScrn;
3860	     pSiS->DualHeadMode = TRUE;
3861	  }
3862       } else {
3863	  /* Only one screen in config file - disable dual head mode */
3864	  pSiS->SecondHead = FALSE;
3865	  pSiS->DualHeadMode = FALSE;
3866	  pSiSEnt->DisableDual = TRUE;
3867       }
3868    } else {
3869       /* Entity is not shared - disable dual head mode */
3870       pSiS->SecondHead = FALSE;
3871       pSiS->DualHeadMode = FALSE;
3872    }
3873#endif
3874
3875    /* Save the name of our Device section for SiSCtrl usage */
3876    {
3877       int ttt = 0;
3878       GDevPtr device = xf86GetDevFromEntity(pScrn->entityList[0],
3879						pScrn->entityInstanceList[0]);
3880       if(device && device->identifier) {
3881          if((ttt = strlen(device->identifier)) > 31) ttt = 31;
3882	  strncpy(&pSiS->devsectname[0], device->identifier, 31);
3883       }
3884       pSiS->devsectname[ttt] = 0;
3885    }
3886
3887    pSiS->ForceCursorOff = FALSE;
3888
3889    /* Allocate SiS_Private (for mode switching code) and initialize it */
3890    pSiS->SiS_Pr = NULL;
3891#ifdef SISDUALHEAD
3892    if(pSiSEnt) {
3893       if(pSiSEnt->SiS_Pr) pSiS->SiS_Pr = pSiSEnt->SiS_Pr;
3894    }
3895#endif
3896    if(!pSiS->SiS_Pr) {
3897       if(!(pSiS->SiS_Pr = xnfcalloc(sizeof(struct SiS_Private), 1))) {
3898	  SISErrorLog(pScrn, "Could not allocate memory for SiS_Pr structure\n");
3899	  goto my_error_1;
3900       }
3901#ifdef SISDUALHEAD
3902       if(pSiSEnt) pSiSEnt->SiS_Pr = pSiS->SiS_Pr;
3903#endif
3904       memset(pSiS->SiS_Pr, 0, sizeof(struct SiS_Private));
3905       pSiS->SiS_Pr->PciTag = pSiS->PciTag;
3906       pSiS->SiS_Pr->ChipType = pSiS->ChipType;
3907       pSiS->SiS_Pr->ChipRevision = pSiS->ChipRev;
3908       pSiS->SiS_Pr->SiS_Backup70xx = 0xff;
3909       pSiS->SiS_Pr->SiS_CHOverScan = -1;
3910       pSiS->SiS_Pr->SiS_ChSW = FALSE;
3911       pSiS->SiS_Pr->SiS_CustomT = CUT_NONE;
3912       pSiS->SiS_Pr->SiS_UseWide = -1;
3913       pSiS->SiS_Pr->SiS_UseWideCRT2 = -1;
3914       pSiS->SiS_Pr->SiS_TVBlue = -1;
3915       pSiS->SiS_Pr->PanelSelfDetected = FALSE;
3916       pSiS->SiS_Pr->UsePanelScaler = -1;
3917       pSiS->SiS_Pr->CenterScreen = -1;
3918       pSiS->SiS_Pr->CRT1UsesCustomMode = FALSE;
3919       pSiS->SiS_Pr->PDC = pSiS->SiS_Pr->PDCA = -1;
3920       pSiS->SiS_Pr->LVDSHL = -1;
3921       pSiS->SiS_Pr->HaveEMI = FALSE;
3922       pSiS->SiS_Pr->HaveEMILCD = FALSE;
3923       pSiS->SiS_Pr->OverruleEMI = FALSE;
3924       pSiS->SiS_Pr->SiS_SensibleSR11 = FALSE;
3925       if(pSiS->ChipType >= SIS_661) {
3926          pSiS->SiS_Pr->SiS_SensibleSR11 = TRUE;
3927       }
3928       pSiS->SiS_Pr->SiS_MyCR63 = pSiS->myCR63;
3929       pSiS->SiS_Pr->DDCPortMixup = FALSE;
3930    }
3931
3932    /* Copy IO address to SiS_Pr and init the structure for
3933     * routines inside init.c/init301.c
3934     */
3935    pSiS->SiS_Pr->IOAddress = (SISIOADDRESS)(pSiS->RelIO + 0x30);
3936    SiSRegInit(pSiS->SiS_Pr, pSiS->RelIO + 0x30);
3937
3938    /* The following identifies the old chipsets. This is only
3939     * partly used since the really old chips are not supported,
3940     * but I keep it here for future use.
3941     * 205, 215 and 225 are to be treated the same way, 201 and 202
3942     * are different.
3943     */
3944    if(pSiS->VGAEngine == SIS_OLD_VGA || pSiS->VGAEngine == SIS_530_VGA) {
3945       switch(pSiS->Chipset) {
3946       case PCI_CHIP_SG86C201:
3947	  pSiS->oldChipset = OC_SIS86201; break;
3948       case PCI_CHIP_SG86C202:
3949	  pSiS->oldChipset = OC_SIS86202; break;
3950       case PCI_CHIP_SG86C205:
3951	  inSISIDXREG(SISSR, 0x10, tempreg);
3952	  if(tempreg & 0x80) pSiS->oldChipset = OC_SIS6205B;
3953	  else pSiS->oldChipset = (pSiS->ChipRev == 0x11) ?
3954					OC_SIS6205C : OC_SIS6205A;
3955	  break;
3956       case PCI_CHIP_SIS82C204:
3957	  pSiS->oldChipset = OC_SIS82204; break;
3958       case 0x6225:
3959	  pSiS->oldChipset = OC_SIS6225; break;
3960       case PCI_CHIP_SIS5597:
3961	  pSiS->oldChipset = OC_SIS5597; break;
3962       case PCI_CHIP_SIS6326:
3963	  pSiS->oldChipset = OC_SIS6326; break;
3964       case PCI_CHIP_SIS530:
3965	  if(sis_pci_read_host_bridge_u32(0x00) == 0x06201039) {
3966	     pSiS->oldChipset = OC_SIS620;
3967	  } else {
3968	     if((pSiS->ChipRev & 0x0f) < 0x0a)
3969		   pSiS->oldChipset = OC_SIS530A;
3970	     else  pSiS->oldChipset = OC_SIS530B;
3971	  }
3972	  break;
3973       default:
3974	  pSiS->oldChipset = OC_UNKNOWN;
3975       }
3976    }
3977
3978    if(!xf86SetDepthBpp(pScrn, 0, 0, 0, pix24flags)) {
3979       SISErrorLog(pScrn, "xf86SetDepthBpp() error\n");
3980       goto my_error_1;
3981    }
3982
3983    /* Check that the returned depth is one we support */
3984    temp = 0;
3985    switch(pScrn->depth) {
3986       case 8:
3987       case 16:
3988       case 24:
3989          break;
3990       case 15:
3991	  if((pSiS->VGAEngine == SIS_300_VGA) ||
3992	     (pSiS->VGAEngine == SIS_315_VGA)) {
3993	     temp = 1;
3994	  }
3995	  break;
3996       default:
3997	  temp = 1;
3998    }
3999
4000    if(temp) {
4001       SISErrorLog(pScrn,
4002            "Given color depth (%d) is not supported by this driver/chipset\n",
4003            pScrn->depth);
4004       goto my_error_1;
4005    }
4006
4007    xf86PrintDepthBpp(pScrn);
4008
4009    if( (((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) &&
4010         (pScrn->bitsPerPixel == 24)) ||
4011	((pSiS->VGAEngine == SIS_OLD_VGA) && (pScrn->bitsPerPixel == 32)) ) {
4012       SISErrorLog(pScrn,
4013            "Framebuffer bpp %d not supported for this chipset\n", pScrn->bitsPerPixel);
4014       goto my_error_1;
4015    }
4016
4017    /* Get the depth24 pixmap format */
4018    if(pScrn->depth == 24 && pix24bpp == 0) {
4019       pix24bpp = xf86GetBppFromDepth(pScrn, 24);
4020    }
4021
4022    /*
4023     * This must happen after pScrn->display has been set because
4024     * xf86SetWeight references it.
4025     */
4026    if(pScrn->depth > 8) {
4027        /* The defaults are OK for us */
4028        rgb zeros = {0, 0, 0};
4029
4030        if(!xf86SetWeight(pScrn, zeros, zeros)) {
4031	    SISErrorLog(pScrn, "xf86SetWeight() error\n");
4032	    goto my_error_1;
4033        } else {
4034	   Bool ret = FALSE;
4035	   switch(pScrn->depth) {
4036	   case 15:
4037	      if((pScrn->weight.red != 5) ||
4038	         (pScrn->weight.green != 5) ||
4039		 (pScrn->weight.blue != 5)) ret = TRUE;
4040	      break;
4041	   case 16:
4042	      if((pScrn->weight.red != 5) ||
4043	         (pScrn->weight.green != 6) ||
4044		 (pScrn->weight.blue != 5)) ret = TRUE;
4045	      break;
4046	   case 24:
4047	      if((pScrn->weight.red != 8) ||
4048	         (pScrn->weight.green != 8) ||
4049		 (pScrn->weight.blue != 8)) ret = TRUE;
4050	      break;
4051	   }
4052	   if(ret) {
4053	      SISErrorLog(pScrn,
4054		   "RGB weight %d%d%d at depth %d not supported by hardware\n",
4055		   (int)pScrn->weight.red, (int)pScrn->weight.green,
4056		   (int)pScrn->weight.blue, pScrn->depth);
4057	      goto my_error_1;
4058	   }
4059        }
4060    }
4061
4062    /* Set the current layout parameters */
4063    pSiS->CurrentLayout.bitsPerPixel = pScrn->bitsPerPixel;
4064    pSiS->CurrentLayout.depth        = pScrn->depth;
4065    /* (Inside this function, we can use pScrn's contents anyway) */
4066
4067    if(!xf86SetDefaultVisual(pScrn, -1)) {
4068       SISErrorLog(pScrn, "xf86SetDefaultVisual() error\n");
4069       goto my_error_1;
4070    } else {
4071       /* We don't support DirectColor at > 8bpp */
4072       if(pScrn->depth > 8 && pScrn->defaultVisual != TrueColor) {
4073	  SISErrorLog(pScrn,
4074	       "Given default visual (%s) is not supported at depth %d\n",
4075	        xf86GetVisualName(pScrn->defaultVisual), pScrn->depth);
4076	  goto my_error_1;
4077       }
4078    }
4079
4080#ifdef SISDUALHEAD
4081    /* Due to palette & timing problems we don't support 8bpp in DHM */
4082    if((pSiS->DualHeadMode) && (pScrn->bitsPerPixel <= 8)) {
4083       SISErrorLog(pScrn, "Color depth %d not supported in Dual Head mode.\n",
4084			pScrn->bitsPerPixel);
4085       goto my_error_1;
4086    }
4087#endif
4088
4089    /* Read BIOS for 300/315/330/340 series customization */
4090    pSiS->SiS_Pr->VirtualRomBase = NULL;
4091    pSiS->BIOS = NULL;
4092    pSiS->SiS_Pr->UseROM = FALSE;
4093    pSiS->ROM661New = FALSE;
4094    pSiS->HaveXGIBIOS = FALSE;
4095
4096    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
4097#ifdef SISDUALHEAD
4098       if(pSiSEnt) {
4099	  if(pSiSEnt->BIOS) {
4100	     pSiS->BIOS = pSiSEnt->BIOS;
4101	     pSiS->SiS_Pr->VirtualRomBase = pSiS->BIOS;
4102	     pSiS->ROM661New = pSiSEnt->ROM661New;
4103	     pSiS->HaveXGIBIOS = pSiSEnt->HaveXGIBIOS;
4104	  }
4105       }
4106#endif
4107       if(!pSiS->BIOS) {
4108	  if(!(pSiS->BIOS = calloc(1, BIOS_SIZE))) {
4109	     xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
4110		"Could not allocate memory for video BIOS image\n");
4111	  } else {
4112	     UShort mypciid = pSiS->Chipset;
4113	     UShort mypcivendor = (pSiS->ChipFlags & SiSCF_IsXGI) ? PCI_VENDOR_XGI : PCI_VENDOR_SIS;
4114	     Bool   found = FALSE, readpci = FALSE;
4115	     int    biossize = BIOS_SIZE;
4116
4117	     switch(pSiS->ChipType) {
4118	     case SIS_315:    mypciid = PCI_CHIP_SIS315;
4119			      readpci = TRUE;
4120			      break;
4121	     case SIS_315PRO: mypciid = PCI_CHIP_SIS315PRO;
4122			      readpci = TRUE;
4123			      break;
4124	     case SIS_300:
4125	     case SIS_315H:
4126	     case SIS_330:
4127	     case SIS_340:
4128	     case SIS_650:
4129	     case SIS_760:
4130	     case XGI_40:     readpci = TRUE;
4131			      break;
4132	     case XGI_20:     readpci = TRUE;
4133			      biossize = 0x8000;
4134			      break;
4135	     }
4136#if XSERVER_LIBPCIACCESS
4137	     if(readpci) {
4138		pSiS->PciInfo->rom_size = biossize;
4139		pci_device_read_rom(pSiS->PciInfo, pSiS->BIOS);
4140		if(SISCheckBIOS(pSiS, mypciid, mypcivendor, biossize)) {
4141		   found = TRUE;
4142		}
4143	     }
4144#else
4145	     if(readpci) {
4146		xf86ReadPciBIOS(0, pSiS->PciTag, 0, pSiS->BIOS, biossize);
4147		if(SISCheckBIOS(pSiS, mypciid, mypcivendor, biossize)) {
4148		   found = TRUE;
4149		}
4150	     }
4151
4152	     if(!found) {
4153	        ULong  segstart;
4154		for(segstart = BIOS_BASE; segstart < 0x000f0000; segstart += 0x00001000) {
4155
4156#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,99,0,0)
4157		   if(xf86ReadBIOS(segstart, 0, pSiS->BIOS, biossize) != biossize) continue;
4158#else
4159		   if(xf86ReadDomainMemory(pSiS->PciTag, segstart, biossize, pSiS->BIOS) != biossize) continue;
4160#endif
4161
4162		   if(!SISCheckBIOS(pSiS, mypciid, mypcivendor, biossize)) continue;
4163
4164		   found = TRUE;
4165		   break;
4166		}
4167             }
4168#endif
4169	     if(found) {
4170		UShort romptr = pSiS->BIOS[0x16] | (pSiS->BIOS[0x17] << 8);
4171		pSiS->SiS_Pr->VirtualRomBase = pSiS->BIOS;
4172		if(pSiS->ChipFlags & SiSCF_IsXGI) {
4173		   pSiS->HaveXGIBIOS = pSiS->SiS_Pr->SiS_XGIROM = TRUE;
4174		   pSiS->SiS_Pr->UseROM = FALSE;
4175		   if(pSiS->ChipFlags & SiSCF_IsXGIV3) {
4176		      if(!(pSiS->BIOS[0x1d1] & 0x01)) {
4177			 pSiS->SiS_Pr->DDCPortMixup = TRUE;
4178		      }
4179	           }
4180	        } else {
4181		   pSiS->ROM661New = SiSDetermineROMLayout661(pSiS->SiS_Pr);
4182		}
4183		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4184			"Video BIOS version \"%7s\" found (%s data layout)\n",
4185			&pSiS->BIOS[romptr], pSiS->ROM661New ? "new SiS" :
4186				(pSiS->HaveXGIBIOS ? "XGI" : "old SiS"));
4187		if(pSiS->SiS_Pr->DDCPortMixup) {
4188		   xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
4189			"*** Buggy XGI V3XT card detected: If VGA and DVI are connected at the\n");
4190		   xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
4191			"*** same time, BIOS and driver will be unable to detect DVI connection.\n");
4192		}
4193#ifdef SISDUALHEAD
4194		if(pSiSEnt) {
4195		   pSiSEnt->BIOS = pSiS->BIOS;
4196		   pSiSEnt->ROM661New = pSiS->ROM661New;
4197		   pSiSEnt->HaveXGIBIOS = pSiS->HaveXGIBIOS;
4198		}
4199#endif
4200	     } else {
4201	        xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
4202			 "Could not find/read video BIOS\n");
4203		free(pSiS->BIOS);
4204		pSiS->BIOS = NULL;
4205	     }
4206          }
4207       }
4208
4209       if(!(pSiS->ChipFlags & SiSCF_IsXGI)) {
4210          if(pSiS->BIOS) pSiS->SiS_Pr->UseROM = TRUE;
4211          else           pSiS->SiS_Pr->UseROM = FALSE;
4212       }
4213    }
4214
4215    /* Evaluate options */
4216    SiSOptions(pScrn);
4217
4218#ifdef SISMERGED
4219    /* Due to palette & timing problems we don't support 8bpp in MFBM */
4220    if((pSiS->MergedFB) && (pScrn->bitsPerPixel <= 8)) {
4221       SISErrorLog(pScrn, "MergedFB: Color depth %d not supported, %s\n",
4222			pScrn->bitsPerPixel, mergeddisstr);
4223       pSiS->MergedFB = pSiS->MergedFBAuto = FALSE;
4224    }
4225#endif
4226
4227    /* Probe CPU features */
4228#ifdef SISDUALHEAD
4229    if(pSiS->DualHeadMode) {
4230       pSiS->CPUFlags = pSiSEnt->CPUFlags;
4231    }
4232#endif
4233    if(!pSiS->CPUFlags) {
4234       pSiS->CPUFlags = SiSGetCPUFlags(pScrn);
4235       pSiS->CPUFlags |= SIS_CPUFL_FLAG;
4236#ifdef SISDUALHEAD
4237       if(pSiS->DualHeadMode) pSiSEnt->CPUFlags = pSiS->CPUFlags;
4238#endif
4239    }
4240
4241    /* We use a programamble clock */
4242    pScrn->progClock = TRUE;
4243
4244    /* Set the bits per RGB for 8bpp mode */
4245    if(pScrn->depth == 8) pScrn->rgbBits = 8;
4246
4247#ifdef SISDUALHEAD
4248    if(pSiS->DualHeadMode) {
4249       if(!pSiS->SecondHead) {
4250	  /* Copy some option settings to entity private */
4251	  pSiSEnt->HWCursor = pSiS->HWCursor;
4252	  pSiSEnt->NoAccel = pSiS->NoAccel;
4253	  pSiSEnt->useEXA = pSiS->useEXA;
4254	  pSiSEnt->restorebyset = pSiS->restorebyset;
4255	  pSiSEnt->OptROMUsage = pSiS->OptROMUsage;
4256	  pSiSEnt->OptUseOEM = pSiS->OptUseOEM;
4257	  pSiSEnt->TurboQueue = pSiS->TurboQueue;
4258	  pSiSEnt->forceCRT1 = pSiS->forceCRT1;
4259	  pSiSEnt->ForceCRT1Type = pSiS->ForceCRT1Type;
4260	  pSiSEnt->CRT1TypeForced = pSiS->CRT1TypeForced;
4261	  pSiSEnt->ForceCRT2Type = pSiS->ForceCRT2Type;
4262	  pSiSEnt->ForceTVType = pSiS->ForceTVType;
4263	  pSiSEnt->ForceYPbPrType = pSiS->ForceYPbPrType;
4264	  pSiSEnt->ForceYPbPrAR = pSiS->ForceYPbPrAR;
4265	  pSiSEnt->UsePanelScaler = pSiS->UsePanelScaler;
4266	  pSiSEnt->CenterLCD = pSiS->CenterLCD;
4267	  pSiSEnt->DSTN = pSiS->DSTN;
4268	  pSiSEnt->FSTN = pSiS->FSTN;
4269	  pSiSEnt->OptTVStand = pSiS->OptTVStand;
4270	  pSiSEnt->NonDefaultPAL = pSiS->NonDefaultPAL;
4271	  pSiSEnt->NonDefaultNTSC = pSiS->NonDefaultNTSC;
4272	  pSiSEnt->chtvtype = pSiS->chtvtype;
4273	  pSiSEnt->OptTVOver = pSiS->OptTVOver;
4274	  pSiSEnt->OptTVSOver = pSiS->OptTVSOver;
4275	  pSiSEnt->chtvlumabandwidthcvbs = pSiS->chtvlumabandwidthcvbs;
4276	  pSiSEnt->chtvlumabandwidthsvideo = pSiS->chtvlumabandwidthsvideo;
4277	  pSiSEnt->chtvlumaflickerfilter = pSiS->chtvlumaflickerfilter;
4278	  pSiSEnt->chtvchromabandwidth = pSiS->chtvchromabandwidth;
4279	  pSiSEnt->chtvchromaflickerfilter = pSiS->chtvchromaflickerfilter;
4280	  pSiSEnt->chtvtextenhance = pSiS->chtvtextenhance;
4281	  pSiSEnt->chtvcontrast = pSiS->chtvcontrast;
4282	  pSiSEnt->chtvcvbscolor = pSiS->chtvcvbscolor;
4283	  pSiSEnt->sistvedgeenhance = pSiS->sistvedgeenhance;
4284	  pSiSEnt->sistvantiflicker = pSiS->sistvantiflicker;
4285	  pSiSEnt->sistvsaturation = pSiS->sistvsaturation;
4286	  pSiSEnt->sistvcfilter = pSiS->sistvcfilter;
4287	  pSiSEnt->sistvyfilter = pSiS->sistvyfilter;
4288	  pSiSEnt->sistvcolcalibc = pSiS->sistvcolcalibc;
4289	  pSiSEnt->sistvcolcalibf = pSiS->sistvcolcalibf;
4290	  pSiSEnt->tvxpos = pSiS->tvxpos;
4291	  pSiSEnt->tvypos = pSiS->tvypos;
4292	  pSiSEnt->tvxscale = pSiS->tvxscale;
4293	  pSiSEnt->tvyscale = pSiS->tvyscale;
4294	  pSiSEnt->siscrt1satgain = pSiS->siscrt1satgain;
4295	  pSiSEnt->crt1satgaingiven = pSiS->crt1satgaingiven;
4296	  pSiSEnt->CRT1gamma = pSiS->CRT1gamma;
4297	  pSiSEnt->CRT1gammaGiven = pSiS->CRT1gammaGiven;
4298	  pSiSEnt->XvGammaRed = pSiS->XvGammaRed;
4299	  pSiSEnt->XvGammaGreen = pSiS->XvGammaGreen;
4300	  pSiSEnt->XvGammaBlue = pSiS->XvGammaBlue;
4301	  pSiSEnt->XvGamma = pSiS->XvGamma;
4302	  pSiSEnt->XvGammaGiven = pSiS->XvGammaGiven;
4303	  pSiSEnt->CRT2gamma = pSiS->CRT2gamma;
4304	  pSiSEnt->XvOnCRT2 = pSiS->XvOnCRT2;
4305	  pSiSEnt->AllowHotkey = pSiS->AllowHotkey;
4306	  pSiSEnt->enablesisctrl = pSiS->enablesisctrl;
4307	  pSiSEnt->SenseYPbPr = pSiS->SenseYPbPr;
4308	  pSiSEnt->XvUseMemcpy = pSiS->XvUseMemcpy;
4309	  pSiSEnt->BenchMemCpy = pSiS->BenchMemCpy;
4310#ifdef SIS_CP
4311	  SIS_CP_DRIVER_COPYOPTIONSENT
4312#endif
4313       } else {
4314	  /* We always use same cursor type on both screens */
4315	  pSiS->HWCursor = pSiSEnt->HWCursor;
4316	  /* We need identical NoAccel setting */
4317	  pSiS->NoAccel = pSiSEnt->NoAccel;
4318	  pSiS->useEXA = pSiSEnt->useEXA;
4319	  pSiS->TurboQueue = pSiSEnt->TurboQueue;
4320	  pSiS->restorebyset = pSiSEnt->restorebyset;
4321	  pSiS->AllowHotkey = pSiS->AllowHotkey;
4322	  pSiS->OptROMUsage = pSiSEnt->OptROMUsage;
4323	  pSiS->OptUseOEM = pSiSEnt->OptUseOEM;
4324	  pSiS->forceCRT1 = pSiSEnt->forceCRT1;
4325	  pSiS->nocrt2ddcdetection = FALSE;
4326	  pSiS->forcecrt2redetection = FALSE;
4327	  pSiS->ForceCRT1Type = pSiSEnt->ForceCRT1Type;
4328	  pSiS->ForceCRT2Type = pSiSEnt->ForceCRT2Type;
4329	  pSiS->CRT1TypeForced = pSiSEnt->CRT1TypeForced;
4330	  pSiS->UsePanelScaler = pSiSEnt->UsePanelScaler;
4331	  pSiS->CenterLCD = pSiSEnt->CenterLCD;
4332	  pSiS->DSTN = pSiSEnt->DSTN;
4333	  pSiS->FSTN = pSiSEnt->FSTN;
4334	  pSiS->OptTVStand = pSiSEnt->OptTVStand;
4335	  pSiS->NonDefaultPAL = pSiSEnt->NonDefaultPAL;
4336	  pSiS->NonDefaultNTSC = pSiSEnt->NonDefaultNTSC;
4337	  pSiS->chtvtype = pSiSEnt->chtvtype;
4338	  pSiS->ForceTVType = pSiSEnt->ForceTVType;
4339	  pSiS->ForceYPbPrType = pSiSEnt->ForceYPbPrType;
4340	  pSiS->ForceYPbPrAR = pSiSEnt->ForceYPbPrAR;
4341	  pSiS->OptTVOver = pSiSEnt->OptTVOver;
4342	  pSiS->OptTVSOver = pSiSEnt->OptTVSOver;
4343	  pSiS->chtvlumabandwidthcvbs = pSiSEnt->chtvlumabandwidthcvbs;
4344	  pSiS->chtvlumabandwidthsvideo = pSiSEnt->chtvlumabandwidthsvideo;
4345	  pSiS->chtvlumaflickerfilter = pSiSEnt->chtvlumaflickerfilter;
4346	  pSiS->chtvchromabandwidth = pSiSEnt->chtvchromabandwidth;
4347	  pSiS->chtvchromaflickerfilter = pSiSEnt->chtvchromaflickerfilter;
4348	  pSiS->chtvcvbscolor = pSiSEnt->chtvcvbscolor;
4349	  pSiS->chtvtextenhance = pSiSEnt->chtvtextenhance;
4350	  pSiS->chtvcontrast = pSiSEnt->chtvcontrast;
4351	  pSiS->sistvedgeenhance = pSiSEnt->sistvedgeenhance;
4352	  pSiS->sistvantiflicker = pSiSEnt->sistvantiflicker;
4353	  pSiS->sistvsaturation = pSiSEnt->sistvsaturation;
4354	  pSiS->sistvcfilter = pSiSEnt->sistvcfilter;
4355	  pSiS->sistvyfilter = pSiSEnt->sistvyfilter;
4356	  pSiS->sistvcolcalibc = pSiSEnt->sistvcolcalibc;
4357	  pSiS->sistvcolcalibf = pSiSEnt->sistvcolcalibf;
4358	  pSiS->tvxpos = pSiSEnt->tvxpos;
4359	  pSiS->tvypos = pSiSEnt->tvypos;
4360	  pSiS->tvxscale = pSiSEnt->tvxscale;
4361	  pSiS->tvyscale = pSiSEnt->tvyscale;
4362	  pSiS->SenseYPbPr = pSiSEnt->SenseYPbPr;
4363	  if(!pSiS->CRT1gammaGiven) {
4364	     if(pSiSEnt->CRT1gammaGiven)
4365	        pSiS->CRT1gamma = pSiSEnt->CRT1gamma;
4366	  }
4367	  pSiS->CRT2gamma = pSiSEnt->CRT2gamma;
4368	  if(!pSiS->XvGammaGiven) {
4369	     if(pSiSEnt->XvGammaGiven) {
4370		pSiS->XvGamma = pSiSEnt->XvGamma;
4371		pSiS->XvGammaRed = pSiS->XvGammaRedDef = pSiSEnt->XvGammaRed;
4372		pSiS->XvGammaGreen = pSiS->XvGammaGreenDef = pSiSEnt->XvGammaGreen;
4373		pSiS->XvGammaBlue = pSiS->XvGammaBlueDef = pSiSEnt->XvGammaBlue;
4374	     }
4375	  }
4376	  if(!pSiS->crt1satgaingiven) {
4377	     if(pSiSEnt->crt1satgaingiven)
4378	        pSiS->siscrt1satgain = pSiSEnt->siscrt1satgain;
4379	  }
4380	  pSiS->XvOnCRT2 = pSiSEnt->XvOnCRT2;
4381	  pSiS->enablesisctrl = pSiSEnt->enablesisctrl;
4382	  pSiS->XvUseMemcpy = pSiSEnt->XvUseMemcpy;
4383	  pSiS->BenchMemCpy = pSiSEnt->BenchMemCpy;
4384	  /* Copy gamma brightness to Ent (sic!) for Xinerama */
4385	  pSiSEnt->GammaBriR = pSiS->GammaBriR;
4386	  pSiSEnt->GammaBriG = pSiS->GammaBriG;
4387	  pSiSEnt->GammaBriB = pSiS->GammaBriB;
4388	  pSiSEnt->NewGammaBriR = pSiS->NewGammaBriR;
4389	  pSiSEnt->NewGammaBriG = pSiS->NewGammaBriG;
4390	  pSiSEnt->NewGammaBriB = pSiS->NewGammaBriB;
4391	  pSiSEnt->NewGammaConR = pSiS->NewGammaConR;
4392	  pSiSEnt->NewGammaConG = pSiS->NewGammaConG;
4393	  pSiSEnt->NewGammaConB = pSiS->NewGammaConB;
4394#ifdef SIS_CP
4395	  SIS_CP_DRIVER_COPYOPTIONS
4396#endif
4397       }
4398    }
4399#endif
4400
4401    /* Handle UseROMData, NoOEM and UsePanelScaler options */
4402    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
4403       from = X_PROBED;
4404       if(pSiS->OptROMUsage == 0) {
4405	  pSiS->SiS_Pr->UseROM = FALSE;
4406	  from = X_CONFIG;
4407	  xf86DrvMsg(pScrn->scrnIndex, from, "Video ROM data usage is disabled\n");
4408       }
4409
4410       if(!pSiS->OptUseOEM) {
4411	  xf86DrvMsg(pScrn->scrnIndex, from, "Internal OEM LCD/TV/VGA2 data usage is disabled\n");
4412       }
4413
4414       pSiS->SiS_Pr->UsePanelScaler = pSiS->UsePanelScaler;
4415       pSiS->SiS_Pr->CenterScreen = pSiS->CenterLCD;
4416    }
4417
4418    /* Do some HW configuration detection (memory amount & type, clock, etc) */
4419    SiSSetup(pScrn);
4420
4421    /* Get framebuffer address */
4422    if(pSiS->pEnt->device->MemBase != 0) {
4423       /*
4424	* XXX Should check that the config file value matches one of the
4425	* PCI base address values.
4426	*/
4427       pSiS->FbAddress = pSiS->pEnt->device->MemBase;
4428       from = X_CONFIG;
4429    } else {
4430       pSiS->FbAddress = PCI_REGION_BASE(pSiS->PciInfo, 0, REGION_MEM) & 0xFFFFFFF0;
4431       from = X_PROBED;
4432    }
4433
4434#ifdef SISDUALHEAD
4435    if(pSiS->DualHeadMode)
4436       xf86DrvMsg(pScrn->scrnIndex, from, "Global linear framebuffer at 0x%lX\n",
4437	   (ULong)pSiS->FbAddress);
4438    else
4439#endif
4440       xf86DrvMsg(pScrn->scrnIndex, from, "Linear framebuffer at 0x%lX\n",
4441	   (ULong)pSiS->FbAddress);
4442
4443    pSiS->realFbAddress = pSiS->FbAddress;
4444
4445    /* Get MMIO address */
4446    if(pSiS->pEnt->device->IOBase != 0) {
4447       /*
4448	* XXX Should check that the config file value matches one of the
4449	* PCI base address values.
4450	*/
4451       pSiS->IOAddress = pSiS->pEnt->device->IOBase;
4452       from = X_CONFIG;
4453    } else {
4454       pSiS->IOAddress = PCI_REGION_BASE(pSiS->PciInfo, 1, REGION_MEM) & 0xFFFFFFF0;
4455       from = X_PROBED;
4456    }
4457    xf86DrvMsg(pScrn->scrnIndex, from, "MMIO registers at 0x%lX (size %ldK)\n",
4458	   (ULong)pSiS->IOAddress, pSiS->mmioSize);
4459
4460#ifndef XSERVER_LIBPCIACCESS
4461    /* Register the PCI-assigned resources */
4462    if(xf86RegisterResources(pSiS->pEnt->index, NULL, ResExclusive)) {
4463       SISErrorLog(pScrn, "PCI resource conflicts detected\n");
4464#ifdef SISDUALHEAD
4465       if(pSiSEnt) pSiSEnt->ErrorAfterFirst = TRUE;
4466#endif
4467       sisRestoreExtRegisterLock(pSiS,srlockReg,crlockReg);
4468       if(pSiS->pInt) xf86FreeInt10(pSiS->pInt);
4469       SISFreeRec(pScrn);
4470       return FALSE;
4471    }
4472#endif
4473
4474    from = X_PROBED;
4475    if(pSiS->pEnt->device->videoRam != 0) {
4476       if(pSiS->Chipset == PCI_CHIP_SIS6326) {
4477	  pScrn->videoRam = pSiS->pEnt->device->videoRam;
4478	  from = X_CONFIG;
4479       } else {
4480	  xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
4481		"Option \"VideoRAM\" ignored\n");
4482       }
4483    }
4484
4485    pSiS->RealVideoRam = pScrn->videoRam;
4486
4487    if((pSiS->Chipset == PCI_CHIP_SIS6326) &&
4488       (pScrn->videoRam > 4096)            &&
4489       (from != X_CONFIG)) {
4490       pScrn->videoRam = 4096;
4491       xf86DrvMsg(pScrn->scrnIndex, from,
4492	   "SiS6326: Detected %d KB VideoRAM, limiting to %d KB\n",
4493	   pSiS->RealVideoRam, pScrn->videoRam);
4494    } else {
4495       xf86DrvMsg(pScrn->scrnIndex, from, "VideoRAM: %d KB\n", pScrn->videoRam);
4496    }
4497
4498    if((pSiS->Chipset == PCI_CHIP_SIS6326) &&
4499       (pScrn->videoRam > 4096)) {
4500       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
4501	   "SiS6326 engines do not support more than 4096KB RAM, therefore\n");
4502       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
4503	   "TurboQueue, HWCursor, 2D acceleration and XVideo are disabled.\n");
4504       pSiS->TurboQueue = FALSE;
4505       pSiS->HWCursor   = FALSE;
4506       pSiS->NoXvideo   = TRUE;
4507       pSiS->NoAccel    = TRUE;
4508    }
4509
4510    pSiS->FbMapSize = pSiS->availMem = pScrn->videoRam * 1024;
4511
4512    /* Calculate real availMem according to Accel/TurboQueue and
4513     * HWCursur setting. Also, initialize some variables used
4514     * in other modules.
4515     */
4516    pSiS->cursorOffset = 0;
4517    pSiS->CurARGBDest = NULL;
4518    pSiS->CurMonoSrc = NULL;
4519    pSiS->CurFGCol = pSiS->CurBGCol = 0;
4520    pSiS->FbBaseOffset = 0;
4521
4522    switch(pSiS->VGAEngine) {
4523
4524      case SIS_300_VGA:
4525	pSiS->TurboQueueLen = 512;
4526	if(pSiS->TurboQueue) {
4527	   pSiS->availMem -= (pSiS->TurboQueueLen*1024);
4528	   pSiS->cursorOffset = 512;
4529	}
4530	if(pSiS->HWCursor) {
4531	   pSiS->availMem -= pSiS->CursorSize;
4532	   if(pSiS->OptUseColorCursor) pSiS->availMem -= pSiS->CursorSize;
4533	}
4534	pSiS->CmdQueLenMask = 0xFFFF;
4535	pSiS->CmdQueLenFix  = 0;
4536	pSiS->cursorBufferNum = 0;
4537#ifdef SISDUALHEAD
4538	if(pSiSEnt) pSiSEnt->cursorBufferNum = 0;
4539#endif
4540	break;
4541
4542      case SIS_315_VGA:
4543#ifdef SISVRAMQ		/* VRAM queue */
4544	pSiS->cmdQueueSizeMask = pSiS->cmdQueueSize - 1;	/* VRAM Command Queue is variable (in therory) */
4545	pSiS->cmdQueueOffset = (pScrn->videoRam * 1024) - pSiS->cmdQueueSize;
4546	pSiS->cmdQueueLen = 0;
4547	pSiS->cmdQueueSize_div2 = pSiS->cmdQueueSize / 2;
4548	pSiS->cmdQueueSize_div4 = pSiS->cmdQueueSize / 4;
4549	pSiS->cmdQueueSize_4_3 = (pSiS->cmdQueueSize / 4) * 3;
4550	pSiS->availMem -= pSiS->cmdQueueSize;
4551	pSiS->cursorOffset = (pSiS->cmdQueueSize / 1024);
4552
4553	/* Set up shared pointer to current offset */
4554#ifdef SISDUALHEAD
4555	if(pSiS->DualHeadMode)
4556	   pSiS->cmdQ_SharedWritePort = &(pSiSEnt->cmdQ_SharedWritePort_2D);
4557	else
4558#endif
4559	   pSiS->cmdQ_SharedWritePort = &(pSiS->cmdQ_SharedWritePort_2D);
4560
4561
4562#else			/* MMIO */
4563	if(pSiS->TurboQueue) {
4564	   pSiS->availMem -= (512*1024);			/* MMIO Command Queue is 512k (variable in theory) */
4565	   pSiS->cursorOffset = 512;
4566	}
4567#endif
4568	if(pSiS->HWCursor) {
4569	   pSiS->availMem -= (pSiS->CursorSize * 2);
4570	   if(pSiS->OptUseColorCursor) pSiS->availMem -= (pSiS->CursorSize * 2);
4571	}
4572	pSiS->cursorBufferNum = 0;
4573#ifdef SISDUALHEAD
4574	if(pSiSEnt) pSiSEnt->cursorBufferNum = 0;
4575#endif
4576
4577	if((pSiS->SiS76xLFBSize) && (pSiS->SiS76xUMASize)) {
4578	   pSiS->availMem -= pSiS->SiS76xUMASize;
4579	   pSiS->FbBaseOffset = pSiS->SiS76xUMASize;
4580	}
4581
4582	break;
4583
4584      default:
4585	/* cursorOffset not used in cursor functions for 530 and
4586	 * older chips, because the cursor is *above* the TQ.
4587	 * On 5597 and older revisions of the 6326, the TQ is
4588	 * max 32K, on newer 6326 revisions and the 530 either 30
4589	 * (or 32?) or 62K (or 64?). However, to make sure, we
4590	 * use only 30K (or 32?), but reduce the available memory
4591	 * by 64, and locate the TQ at the beginning of this last
4592	 * 64K block. (We do this that way even when using the
4593	 * HWCursor, because the cursor only takes 2K and the
4594	 * queue does not seem to last that far anyway.)
4595	 * The TQ must be located at 32KB boundaries.
4596	 */
4597	if(pSiS->RealVideoRam < 3072) {
4598	   if(pSiS->TurboQueue) {
4599	      xf86DrvMsg(pScrn->scrnIndex, X_INFO,
4600		    "Not enough video RAM for TurboQueue. TurboQueue disabled\n");
4601	      pSiS->TurboQueue = FALSE;
4602	   }
4603	}
4604	pSiS->CmdQueMaxLen = 32;
4605	if(pSiS->TurboQueue) {
4606			      pSiS->availMem -= (64*1024);
4607			      pSiS->CmdQueMaxLen = 900;   /* To make sure; should be 992 */
4608	} else if(pSiS->HWCursor) {
4609			      pSiS->availMem -= pSiS->CursorSize;
4610	}
4611	if(pSiS->Chipset == PCI_CHIP_SIS530) {
4612		/* Check if Flat Panel is enabled */
4613		inSISIDXREG(SISSR, 0x0e, tempreg);
4614		if(!(tempreg & 0x04)) pSiS->availMem -= pSiS->CursorSize;
4615
4616		/* Set up mask for MMIO register */
4617		pSiS->CmdQueLenMask = (pSiS->TurboQueue) ? 0x1FFF : 0x00FF;
4618	} else {
4619	        /* TQ is never used on 6326/5597, because the accelerator
4620		 * always Syncs. So this is just cosmentic work. (And I
4621		 * am not even sure that 0x7fff is correct. MMIO 0x83a8
4622		 * holds 0xec0 if (30k) TQ is enabled, 0x20 if TQ disabled.
4623		 * The datasheet has no real explanation on the queue length
4624		 * if the TQ is enabled. Not syncing and waiting for a
4625		 * suitable queue length instead does not work.
4626		 */
4627	        pSiS->CmdQueLenMask = (pSiS->TurboQueue) ? 0x7FFF : 0x003F;
4628	}
4629
4630	/* This is to be subtracted from MMIO queue length register contents
4631	 * for getting the real Queue length.
4632	 */
4633	pSiS->CmdQueLenFix  = (pSiS->TurboQueue) ? 32 : 0;
4634    }
4635
4636
4637#ifdef SISDUALHEAD
4638    /* In dual head mode, we share availMem equally - so align it
4639     * to 8KB; this way, the address of the FB of the second
4640     * head is aligned to 4KB for mapping.
4641     */
4642   if(pSiS->DualHeadMode) pSiS->availMem &= 0xFFFFE000;
4643#endif
4644
4645    /* Check MaxXFBMem setting */
4646#ifdef SISDUALHEAD
4647    if(pSiS->DualHeadMode) {
4648        /* 1. Since DRI is not supported in dual head mode, we
4649	 *    don't need the MaxXFBMem setting - ignore it.
4650	 */
4651	if(pSiS->maxxfbmem) {
4652	   xf86DrvMsg(pScrn->scrnIndex, X_INFO,
4653		"MaxXFBMem ignored in Dual Head mode\n");
4654	}
4655	pSiS->maxxfbmem = pSiS->availMem;
4656    } else
4657#endif
4658	   if((pSiS->sisfbHeapStart) || (pSiS->sisfbHaveNewHeapDef)) {
4659
4660       /*
4661	* 2. We have memory layout info from sisfb - ignore MaxXFBMem
4662	*/
4663	if(pSiS->maxxfbmem) {
4664	   xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
4665		"Got memory layout info from sisfb, ignoring MaxXFBMem option\n");
4666	}
4667	if((pSiS->FbBaseOffset) && (!pSiS->sisfbHaveNewHeapDef)) {
4668	   xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
4669		"Incompatible sisfb version detected, DRI disabled\n");
4670	   pSiS->loadDRI = FALSE;
4671	   pSiS->maxxfbmem = pSiS->availMem;
4672	} else {
4673	   if(pSiS->FbBaseOffset) {
4674	      /* Revert our changes to FbBaseOffset and availMem; use sisfb's info */
4675	      pSiS->availMem += pSiS->FbBaseOffset;
4676	      pSiS->FbBaseOffset = 0;
4677	   }
4678	   if(pSiS->sisfbVideoOffset) {
4679	      /* a. DRI heap BELOW framebuffer */
4680	      pSiS->FbBaseOffset = pSiS->sisfbVideoOffset;
4681	      pSiS->availMem -= pSiS->FbBaseOffset;
4682	      pSiS->maxxfbmem = pSiS->availMem;
4683	   } else {
4684	      /* b. DRI heap ABOVE framebuffer (traditional layout) */
4685	      if(pSiS->availMem < (pSiS->sisfbHeapStart * 1024)) {
4686		 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
4687			"Internal error - sisfb memory layout corrupt\n");
4688		 pSiS->loadDRI = FALSE;
4689		 pSiS->maxxfbmem = pSiS->availMem;
4690	      } else {
4691	         pSiS->maxxfbmem = pSiS->sisfbHeapStart * 1024;
4692	      }
4693	   }
4694	}
4695
4696    } else if(pSiS->maxxfbmem) {
4697
4698       /*
4699	* 3. No sisfb, but user gave "MaxXFBMem"
4700	*/
4701	if(pSiS->FbBaseOffset) {
4702	   /* a. DRI heap BELOW framebuffer */
4703	   if(pSiS->maxxfbmem > (pSiS->availMem + pSiS->FbBaseOffset - pSiS->SiS76xUMASize)) {
4704	      xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
4705			"Invalid MaxXFBMem setting\n");
4706	      pSiS->maxxfbmem = pSiS->availMem;
4707	   } else {
4708	      /* Revert our changes */
4709	      pSiS->availMem += pSiS->FbBaseOffset;
4710	      /* Use user's MaxXFBMem setting */
4711	      pSiS->FbBaseOffset = pSiS->availMem - pSiS->maxxfbmem;
4712	      pSiS->availMem -= pSiS->FbBaseOffset;
4713	   }
4714	} else {
4715	   /* b. DRI heap ABOVE framebuffer (traditional layout) */
4716	   if(pSiS->maxxfbmem > pSiS->availMem) {
4717	      xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
4718			 "Invalid MaxXFBMem setting.\n");
4719	      pSiS->maxxfbmem = pSiS->availMem;
4720	   }
4721	}
4722
4723    } else {
4724
4725       /*
4726	* 4. No MaxXFBMem, no sisfb: Use all memory
4727	*/
4728	pSiS->maxxfbmem = pSiS->availMem;
4729
4730	/* ... except on chipsets, for which DRI is
4731	 * supported: If DRI is enabled, we now limit
4732	 * ourselves to a reasonable default:
4733	 */
4734
4735	if(pSiS->loadDRI) {
4736	   if(pSiS->FbBaseOffset) {
4737	      /* a. DRI heap BELOW framebuffer */
4738	      /* See how much UMA and LFB memory we have,
4739	       * and calculate a reasonable default. We
4740	       * use more vram for ourselves because these
4741	       * chips are eg. capable of larger Xv
4742	       * overlays, etc.
4743	       */
4744	      unsigned long total = (pSiS->SiS76xLFBSize + pSiS->SiS76xUMASize) / 1024;
4745	      unsigned long mymax;
4746	      if(total <= 16384)			/* <= 16MB: Use 8MB for X */
4747	         mymax = 8192 * 1024;
4748	      else if(total <= 32768)			/* <= 32MB: Use 16MB for X */
4749	         mymax = 16384 * 1024;
4750	      else					/* Otherwise: Use 20MB for X */
4751	         mymax = 20 * 1024 * 1024;
4752	      /* availMem is right now adjusted to not use the UMA
4753	       * area. Make sure that our default doesn't reach
4754	       * into the UMA area either.
4755	       */
4756	      if(pSiS->availMem > mymax) {
4757		 /* Write our default to maxxfbmem */
4758		 pSiS->maxxfbmem = mymax;
4759		 /* Revert our changes to availMem */
4760		 pSiS->availMem += pSiS->FbBaseOffset;
4761		 /* Use our default setting */
4762		 pSiS->FbBaseOffset = pSiS->availMem - pSiS->maxxfbmem;
4763		 pSiS->availMem -= pSiS->FbBaseOffset;
4764	      }
4765	   } else {
4766	      /* b. DRI heap ABOVE framebuffer (traditional layout) */
4767	      /* See how much video memory we have, and calculate
4768	       * a reasonable default.
4769	       * Since DRI is pointless with less than 4MB of total
4770	       * video RAM, we disable it in that case.
4771	       */
4772	      if(pScrn->videoRam <= 4096)
4773	         pSiS->loadDRI = FALSE;
4774	      else if(pScrn->videoRam <= 8192)		/* <= 8MB: Use 4MB for X */
4775	         pSiS->maxxfbmem = 4096 * 1024;
4776	      else if(pScrn->videoRam <= 16384)		/* <= 16MB: Use 8MB for X */
4777	         pSiS->maxxfbmem = 8192 * 1024;
4778#ifdef SISMERGED					/* Otherwise: --- */
4779	      else if(pSiS->MergedFB) {
4780	         if(pScrn->videoRam <= 65536)
4781	            pSiS->maxxfbmem = 16384 * 1024;	/* If MergedFB and <=64MB, use 16MB for X */
4782		 else
4783		    pSiS->maxxfbmem = 20 * 1024 * 1024;	/* If MergedFB and > 64MB, use 20MB for X */
4784	      }
4785#endif
4786	        else if(pSiS->VGAEngine == SIS_315_VGA) {
4787	         if(pScrn->videoRam <= 65536)
4788	            pSiS->maxxfbmem = 16384 * 1024;	/* On >=315 series and <=64MB, use 16MB */
4789		 else
4790		    pSiS->maxxfbmem = 20 * 1024 * 1024;	/* On >=315 series and > 64MB, use 20MB */
4791	      } else
4792	         pSiS->maxxfbmem = 12288 * 1024;	/* On <315 series, use 12MB */
4793
4794	      /* A final check */
4795	      if(pSiS->maxxfbmem > pSiS->availMem) {
4796		 pSiS->maxxfbmem = pSiS->availMem;
4797		 pSiS->loadDRI = FALSE;
4798	      }
4799	   }
4800
4801	}
4802    }
4803
4804    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using %dK of framebuffer memory at offset %dK\n",
4805				pSiS->maxxfbmem / 1024, pSiS->FbBaseOffset / 1024);
4806
4807    /* Find out about sub-classes of some chipsets and check
4808     * if the chipset supports two video overlays
4809     */
4810    if(pSiS->VGAEngine == SIS_300_VGA    ||
4811       pSiS->VGAEngine == SIS_315_VGA    ||
4812       pSiS->Chipset == PCI_CHIP_SIS530  ||
4813       pSiS->Chipset == PCI_CHIP_SIS6326 ||
4814       pSiS->Chipset == PCI_CHIP_SIS5597)  {
4815       pSiS->hasTwoOverlays = FALSE;
4816       switch(pSiS->Chipset) {
4817	 case PCI_CHIP_SIS300:
4818	 case PCI_CHIP_SIS540:  /* ? (If not, need to add the SwitchCRT Xv attribute!) */
4819	 case PCI_CHIP_SIS630:
4820	 case PCI_CHIP_SIS550:
4821	   pSiS->hasTwoOverlays = TRUE;
4822	   pSiS->SiS_SD_Flags |= SiS_SD_SUPPORT2OVL;
4823	   break;
4824	 case PCI_CHIP_SIS315PRO:
4825	   pSiS->ChipFlags |= SiSCF_LARGEOVERLAY;
4826	   break;
4827	 case PCI_CHIP_SIS330:
4828	   pSiS->ChipFlags |= (SiSCF_CRT2HWCKaputt | SiSCF_LARGEOVERLAY);
4829	   break;
4830	 case PCI_CHIP_SIS340:
4831	 case PCI_CHIP_XGIXG40: /* Verified: only 1 overlay */
4832	   pSiS->ChipFlags |= SiSCF_LARGEOVERLAY;
4833	   break;
4834	 case PCI_CHIP_SIS650:
4835	   {
4836	     UChar tempreg1, tempreg2;
4837	     static const char *id650str[] = {
4838		"650",       "650",       "650",       "650",
4839		"650 A0 AA", "650 A2 CA", "650",       "650",
4840		"M650 A0",   "M650 A1 AA","651 A0 AA", "651 A1 AA",
4841		"M650",      "65?",       "651",       "65?"
4842	     };
4843	     pSiS->ChipFlags |= SiSCF_LARGEOVERLAY;
4844	     if(pSiS->ChipType == SIS_650) {
4845		inSISIDXREG(SISCR, 0x5f, CR5F);
4846		CR5F &= 0xf0;
4847		andSISIDXREG(SISCR, 0x5c, 0x07);
4848		inSISIDXREG(SISCR, 0x5c, tempreg1);
4849		tempreg1 &= 0xf8;
4850		orSISIDXREG(SISCR, 0x5c, 0xf8);
4851		inSISIDXREG(SISCR, 0x5c, tempreg2);
4852		tempreg2 &= 0xf8;
4853		if((!tempreg1) || (tempreg2)) {
4854		   xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4855		      "SiS650 revision ID %x (%s)\n", CR5F, id650str[CR5F >> 4]);
4856		   if(CR5F & 0x80) {
4857		      pSiS->hasTwoOverlays = TRUE;  /* M650 or 651 */
4858		      pSiS->SiS_SD_Flags |= SiS_SD_SUPPORT2OVL;
4859		   }
4860		   switch(CR5F) {
4861		      case 0xa0:
4862		      case 0xb0:
4863		      case 0xe0:
4864		         pSiS->ChipFlags |= SiSCF_Is651;
4865		         break;
4866		      case 0x80:
4867		      case 0x90:
4868		      case 0xc0:
4869		         pSiS->ChipFlags |= SiSCF_IsM650;
4870		         break;
4871		   }
4872		} else {
4873		   pSiS->hasTwoOverlays = TRUE;
4874		   pSiS->SiS_SD_Flags |= SiS_SD_SUPPORT2OVL;
4875		   switch(CR5F) {
4876		      case 0x90:
4877			 inSISIDXREG(SISCR, 0x5c, tempreg1);
4878			 tempreg1 &= 0xf8;
4879			 switch(tempreg1) {
4880			    case 0x00:
4881			       pSiS->ChipFlags |= SiSCF_IsM652;
4882			       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4883			           "SiSM652 revision ID %x\n", CR5F);
4884			       break;
4885			    case 0x40:
4886			       pSiS->ChipFlags |= SiSCF_IsM653;
4887			       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4888			           "SiSM653 revision ID %x\n", CR5F);
4889			       break;
4890			    default:
4891			       pSiS->ChipFlags |= SiSCF_IsM650;
4892			       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4893			           "SiSM650 revision ID %x\n", CR5F);
4894			       break;
4895			 }
4896			 break;
4897		      case 0xb0:
4898			 pSiS->ChipFlags |= SiSCF_Is652;
4899			 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4900			     "SiS652 revision ID %x\n", CR5F);
4901			 break;
4902		      default:
4903			 pSiS->ChipFlags |= SiSCF_IsM650;
4904			 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4905			     "SiSM650 revision ID %x\n", CR5F);
4906			 break;
4907		   }
4908		}
4909	     }
4910	     break;
4911	   }
4912	 case PCI_CHIP_SIS660:
4913	   {
4914	     pSiS->ChipFlags |= SiSCF_LARGEOVERLAY;
4915	     pSiS->hasTwoOverlays = TRUE;
4916	     pSiS->SiS_SD_Flags |= SiS_SD_SUPPORT2OVL;
4917	     /* 760/761:  - UMA only: one/two overlays - dotclock dependent
4918			  - UMA+LFB:  two overlays if video data in LFB
4919			  - LFB only: two overlays
4920		If UMA only: Must switch between one/two overlays on the fly (done
4921			     in PostSetMode())
4922		If LFB+UMA:  We use LFB memory only and leave UMA to an eventually
4923			     written DRI driver.
4924	      */
4925	     break;
4926	   }
4927       }
4928
4929       if(!(pSiS->SiS_SD2_Flags & SiS_SD2_NOOVERLAY)) {
4930          xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4931		"Hardware supports %s video overlay%s\n",
4932		pSiS->hasTwoOverlays ? "two" : "one",
4933		pSiS->hasTwoOverlays ? "s" : "");
4934       }
4935
4936       if(pSiS->SiS_SD2_Flags & SiS_SD2_SUPPORT760OO) {
4937	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
4938		"\n\tDear SiS76x user, your machine is using a shared memory framebuffer.\n"
4939		  "\tDue to hardware limitations of the SiS chip in combination with the\n"
4940		  "\tAMD CPU, video overlay support is very limited on this machine. If you\n"
4941		  "\texperience flashing lines in the video and/or the graphics display\n"
4942		  "\tduring video playback, reduce the color depth and/or the resolution\n"
4943		  "\tand/or the refresh rate. Alternatively, use the video blitter.\n");
4944       }
4945
4946    }
4947
4948    /* Backup VB connection and CRT1 on/off register */
4949    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
4950       inSISIDXREG(SISSR, 0x1f, pSiS->oldSR1F);
4951       inSISIDXREG(SISCR, 0x17, pSiS->oldCR17);
4952       inSISIDXREG(SISCR, 0x32, pSiS->oldCR32);
4953       inSISIDXREG(SISCR, 0x36, pSiS->oldCR36);
4954       inSISIDXREG(SISCR, 0x37, pSiS->oldCR37);
4955       if(pSiS->VGAEngine == SIS_315_VGA) {
4956          inSISIDXREG(SISCR, pSiS->myCR63, pSiS->oldCR63);
4957       }
4958
4959       pSiS->postVBCR32 = pSiS->oldCR32;
4960    }
4961
4962    /* There are some machines out there which require a special
4963     * setup of the GPIO registers in order to make the Chrontel
4964     * work. Try to find out if we're running on such a machine.
4965     * Furthermore, there is some highly customized hardware,
4966     * which requires some non-standard LVDS timing. Since the
4967     * vendors don't seem to care about PCI subsystem ID's we
4968     * need to find out using the BIOS version and date strings.
4969     */
4970    pSiS->SiS_Pr->SiS_ChSW = FALSE;
4971    if(pSiS->Chipset == PCI_CHIP_SIS630) {
4972       int i = 0;
4973       do {
4974	  if(mychswtable[i].subsysVendor == PCI_SUB_VENDOR_ID(pSiS->PciInfo) &&
4975	     mychswtable[i].subsysCard == PCI_SUB_DEVICE_ID(pSiS->PciInfo)) {
4976	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
4977	         "PCI subsystem ID found in list for Chrontel/GPIO setup:\n");
4978	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4979		 "\tVendor/Card: %s %s (ID %04x)\n",
4980		  mychswtable[i].vendorName,
4981		  mychswtable[i].cardName,
4982		  PCI_SUB_DEVICE_ID(pSiS->PciInfo));
4983	     pSiS->SiS_Pr->SiS_ChSW = TRUE;
4984	     break;
4985          }
4986          i++;
4987       } while(mychswtable[i].subsysVendor != 0);
4988    }
4989
4990    if(pSiS->SiS_Pr->SiS_CustomT == CUT_NONE) {
4991       int    i = 0, j;
4992       UShort bversptr = 0;
4993       Bool   footprint;
4994       CARD32 chksum = 0;
4995
4996       if(pSiS->SiS_Pr->UseROM) {
4997          bversptr = pSiS->BIOS[0x16] | (pSiS->BIOS[0x17] << 8);
4998          for(i=0; i<32768; i++) chksum += pSiS->BIOS[i];
4999       }
5000
5001       i = 0;
5002       do {
5003	  if( (SiS_customttable[i].chipID == pSiS->ChipType)                            &&
5004	      ((!strlen(SiS_customttable[i].biosversion)) ||
5005	       (pSiS->SiS_Pr->UseROM &&
5006	       (!strncmp(SiS_customttable[i].biosversion, (char *)&pSiS->BIOS[bversptr],
5007	                strlen(SiS_customttable[i].biosversion)))))                     &&
5008	      ((!strlen(SiS_customttable[i].biosdate)) ||
5009	       (pSiS->SiS_Pr->UseROM &&
5010	       (!strncmp(SiS_customttable[i].biosdate, (char *)&pSiS->BIOS[0x2c],
5011	                strlen(SiS_customttable[i].biosdate)))))			      &&
5012	      ((!SiS_customttable[i].bioschksum) ||
5013	       (pSiS->SiS_Pr->UseROM &&
5014	       (SiS_customttable[i].bioschksum == chksum)))			      &&
5015	      (SiS_customttable[i].pcisubsysvendor == PCI_SUB_VENDOR_ID(pSiS->PciInfo))      &&
5016	      (SiS_customttable[i].pcisubsyscard == PCI_SUB_DEVICE_ID(pSiS->PciInfo)) ) {
5017	     footprint = TRUE;
5018	     for(j=0; j<5; j++) {
5019	        if(SiS_customttable[i].biosFootprintAddr[j]) {
5020		   if(pSiS->SiS_Pr->UseROM) {
5021		      if(pSiS->BIOS[SiS_customttable[i].biosFootprintAddr[j]] !=
5022						SiS_customttable[i].biosFootprintData[j])
5023		         footprint = FALSE;
5024		   } else footprint = FALSE;
5025	        }
5026	     }
5027	     if(footprint) {
5028	        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5029	           "Identified %s %s, special timing applies\n",
5030		   SiS_customttable[i].vendorName, SiS_customttable[i].cardName);
5031	        pSiS->SiS_Pr->SiS_CustomT = SiS_customttable[i].SpecialID;
5032	        break;
5033	     }
5034          }
5035          i++;
5036       } while(SiS_customttable[i].chipID);
5037    }
5038
5039    /* Handle ForceCRT1 option */
5040    if(pSiS->forceCRT1 != -1) {
5041       if(pSiS->forceCRT1) pSiS->CRT1off = 0;
5042       else                pSiS->CRT1off = 1;
5043    } else                 pSiS->CRT1off = -1;
5044
5045    /* Detect video bridge and sense TV/VGA2 */
5046    SISVGAPreInit(pScrn);
5047
5048    /* Detect CRT1 (via DDC1 and DDC2, hence via VGA port; regardless of LCDA) */
5049    SISCRT1PreInit(pScrn);
5050
5051    /* Detect LCD (connected via CRT2, regardless of LCDA) and LCD resolution */
5052    SISLCDPreInit(pScrn, FALSE);
5053
5054    /* LCDA only supported under these conditions: */
5055    if(pSiS->ForceCRT1Type == CRT1_LCDA) {
5056       if(!SISDetermineLCDACap(pScrn)) {
5057	  xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5058		"Chipset/Video bridge does not support LCD-via-CRT1\n");
5059	  pSiS->ForceCRT1Type = CRT1_VGA;
5060       } else if(!(pSiS->VBFlags & CRT2_LCD)) {
5061	  xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5062		"No digital LCD panel found, LCD-via-CRT1 disabled\n");
5063	  pSiS->ForceCRT1Type = CRT1_VGA;
5064       }
5065    }
5066
5067    /* Setup SD flags */
5068    pSiS->SiS_SD_Flags |= SiS_SD_ADDLSUPFLAG;
5069
5070    pSiS->SiS_SD2_Flags |= SiS_SD2_MERGEDUCLOCK;
5071    pSiS->SiS_SD2_Flags |= SiS_SD2_USEVBFLAGS2;
5072    pSiS->SiS_SD2_Flags |= SiS_SD2_VBINVB2ONLY;
5073    pSiS->SiS_SD2_Flags |= SiS_SD2_HAVESD34;
5074    pSiS->SiS_SD2_Flags |= SiS_SD2_NEWGAMMABRICON;
5075
5076    pSiS->SiS_SD3_Flags |= SiS_SD3_MFBALLOWOFFCL;
5077
5078    if(pSiS->VBFlags2 & VB2_VIDEOBRIDGE) {
5079       pSiS->SiS_SD2_Flags |= SiS_SD2_VIDEOBRIDGE;
5080       if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
5081	  pSiS->SiS_SD2_Flags |= ( SiS_SD2_SISBRIDGE     |
5082				   SiS_SD2_SUPPORTGAMMA2 );
5083	  if(pSiS->VBFlags2 & VB2_SISLVDSBRIDGE) {
5084	     pSiS->SiS_SD2_Flags |= ( SiS_SD2_LCDLVDS    |
5085				      SiS_SD2_SUPPORTLCD );
5086	  } else if(pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) {
5087	     if(!(pSiS->VBFlags2 & VB2_30xBDH)) {
5088		pSiS->SiS_SD2_Flags |= ( SiS_SD2_LCDTMDS    |
5089					 SiS_SD2_SUPPORTLCD );
5090	     } else if(pSiS->VBFlags & CRT2_LCD) {
5091		pSiS->SiS_SD2_Flags |= ( SiS_SD2_THIRDPARTYLVDS |
5092				         SiS_SD2_SUPPORTLCD );
5093	     }
5094	  }
5095       } else if(pSiS->VBFlags2 & VB2_LVDS) {
5096	  pSiS->SiS_SD2_Flags |= ( SiS_SD2_THIRDPARTYLVDS |
5097				   SiS_SD2_SUPPORTLCD );
5098       }
5099
5100       if(pSiS->VBFlags2 & (VB2_SISTVBRIDGE | VB2_CHRONTEL)) {
5101	  pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTTV;
5102	  if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
5103	     pSiS->SiS_SD2_Flags |= ( SiS_SD2_SUPPORTTVTYPE |
5104				      SiS_SD2_SUPPORTTVSIZE );
5105	     if(!(pSiS->VBFlags2 & VB2_301)) {
5106		pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPTVSAT;
5107	     } else {
5108		pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPTVEDGE;
5109	     }
5110	  }
5111       }
5112    }
5113
5114#ifdef ENABLE_YPBPR
5115    if((pSiS->VGAEngine == SIS_315_VGA) &&
5116       (pSiS->VBFlags2 & VB2_SISYPBPRBRIDGE)) {
5117       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTYPBPR;
5118       pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORT625I;
5119       pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORT625P;
5120       if(pSiS->VBFlags2 & VB2_SISYPBPRARBRIDGE) {
5121          pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTYPBPRAR;
5122       }
5123    }
5124    if(pSiS->VBFlags2 & VB2_SISHIVISIONBRIDGE) {
5125       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTHIVISION;
5126    }
5127#endif
5128
5129    if((pSiS->VGAEngine != SIS_300_VGA) || (!(pSiS->VBFlags2 & VB2_TRUMPION))) {
5130       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTSCALE;
5131       if((pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) &&
5132          (!(pSiS->VBFlags2 & VB2_30xBDH))) {
5133          pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTCENTER;
5134       }
5135    }
5136
5137#ifdef SISDUALHEAD
5138    if(!pSiS->DualHeadMode) {
5139       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTREDETECT;
5140    }
5141#endif
5142
5143#ifndef SISCHECKOSSSE
5144    pSiS->SiS_SD2_Flags |= SiS_SD2_NEEDUSESSE;
5145#endif
5146
5147#ifdef TWDEBUG	/* FOR TESTING */
5148    pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTYPBPRAR;
5149    xf86DrvMsg(0, X_INFO, "TEST: Support Aspect Ratio\n");
5150#endif
5151
5152    /* Detect CRT2-TV and PAL/NTSC mode */
5153    SISTVPreInit(pScrn, FALSE);
5154
5155    /* Detect CRT2-VGA */
5156    SISCRT2PreInit(pScrn, FALSE);
5157
5158    /* Backup detected CRT2 devices */
5159    SISSaveDetectedDevices(pScrn);
5160
5161    if(!(pSiS->SiS_SD_Flags & SiS_SD_SUPPORTYPBPR)) {
5162       if((pSiS->ForceTVType != -1) && (pSiS->ForceTVType & TV_YPBPR)) {
5163	  pSiS->ForceTVType = -1;
5164	  xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "YPbPr TV output not supported\n");
5165       }
5166    }
5167
5168    if(!(pSiS->SiS_SD_Flags & SiS_SD_SUPPORTHIVISION)) {
5169       if((pSiS->ForceTVType != -1) && (pSiS->ForceTVType & TV_HIVISION)) {
5170	  pSiS->ForceTVType = -1;
5171	  xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "HiVision TV output not supported\n");
5172       }
5173    }
5174
5175    if((pSiS->VBFlags2 & VB2_SISTVBRIDGE) ||
5176       ((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->ChrontelType == CHRONTEL_701x))) {
5177       pSiS->SiS_SD_Flags |= (SiS_SD_SUPPORTPALMN | SiS_SD_SUPPORTNTSCJ);
5178    }
5179    if((pSiS->VBFlags2 & VB2_SISTVBRIDGE) ||
5180       ((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->ChrontelType == CHRONTEL_700x))) {
5181       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTTVPOS;
5182    }
5183    if(pSiS->VBFlags2 & VB2_SISVGA2BRIDGE) {
5184       pSiS->SiS_SD_Flags |= (SiS_SD_SUPPORTSCART | SiS_SD_SUPPORTVGA2);
5185    }
5186    if(pSiS->VBFlags2 & VB2_CHRONTEL) {
5187       pSiS->SiS_SD_Flags  |= SiS_SD_SUPPORTOVERSCAN;
5188       pSiS->SiS_SD2_Flags |= SiS_SD2_CHRONTEL;
5189       if(pSiS->ChrontelType == CHRONTEL_700x) {
5190	  pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTSOVER;
5191       }
5192    }
5193
5194    /* Determine if chipset LCDA-capable */
5195    pSiS->SiS_SD_Flags &= ~SiS_SD_SUPPORTLCDA;
5196    if(SISDetermineLCDACap(pScrn)) {
5197       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTLCDA;
5198    }
5199
5200    /* Default to LCDA if LCD detected and
5201     * - TV detected (hence default to LCDA+TV), or
5202     * - in single head mode, on LCD panels with xres > 1600
5203     *   (Don't do this in MergedFB or DHM; LCDA and CRT1/VGA
5204     *   are mutually exclusive; if no TV is detected, the
5205     *   code below will default to VGA+LCD, so LCD is driven
5206     *   via CRT2.)
5207     *   (TODO: This might need some modification for the
5208     *   307 bridges, if these are capable of driving
5209     *   LCDs > 1600 via channel B)
5210     */
5211    if((pSiS->SiS_SD_Flags & SiS_SD_SUPPORTLCDA) &&
5212       (pSiS->VBFlags & CRT2_LCD) &&
5213       (pSiS->SiS_Pr->SiS_CustomT != CUT_UNKNOWNLCD)) {
5214       if((!pSiS->CRT1TypeForced) && (pSiS->ForceCRT2Type == CRT2_DEFAULT)) {
5215	  if(pSiS->VBFlags & CRT2_TV) {
5216	     /* If both LCD and TV present, default to LCDA+TV */
5217	     pSiS->ForceCRT1Type = CRT1_LCDA;
5218	     pSiS->ForceCRT2Type = CRT2_TV;
5219	  } else if(pSiS->LCDwidth > 1600) {
5220	     /* If LCD is > 1600, default to LCDA if we don't need CRT1/VGA for other head */
5221	     Bool NeedCRT1VGA = FALSE;
5222#ifdef SISDUALHEAD
5223	     if(pSiS->DualHeadMode) NeedCRT1VGA = TRUE;
5224#endif
5225#ifdef SISMERGED
5226	     if(pSiS->MergedFB &&
5227		(!pSiS->MergedFBAuto || pSiS->CRT1Detected)) NeedCRT1VGA = TRUE;
5228#endif
5229	     if(!NeedCRT1VGA) {
5230		pSiS->ForceCRT1Type = CRT1_LCDA;
5231	     }
5232	  }
5233       }
5234    }
5235
5236    /* Set up pseudo-panel if LCDA forced on TMDS bridges */
5237    if(pSiS->SiS_SD_Flags & SiS_SD_SUPPORTLCDA) {
5238       if(pSiS->ForceCRT1Type == CRT1_LCDA) {
5239          if(pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE) {
5240	     if(!(pSiS->VBLCDFlags)) {
5241		SiSSetupPseudoPanel(pScrn);
5242		pSiS->detectedCRT2Devices |= CRT2_LCD;
5243	     }
5244	  } else if(!(pSiS->VBLCDFlags)) {
5245	     pSiS->ForceCRT1Type = CRT1_VGA;
5246	  }
5247       }
5248    } else {
5249       pSiS->ForceCRT1Type = CRT1_VGA;
5250    }
5251
5252    pSiS->VBFlags |= pSiS->ForceCRT1Type;
5253
5254#ifdef TWDEBUG
5255    xf86DrvMsg(0, X_INFO, "SDFlags %lx\n", pSiS->SiS_SD_Flags);
5256#endif
5257
5258    /* Eventually overrule detected CRT2 type
5259     * If no type forced, use the detected devices in the order TV->LCD->VGA2
5260     * Since the Chrontel 7005 sometimes delivers wrong detection results,
5261     * we use a different order on such machines (LCD->TV)
5262     */
5263    if(pSiS->ForceCRT2Type == CRT2_DEFAULT) {
5264       if((pSiS->VBFlags & CRT2_TV) && (!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VGAEngine == SIS_300_VGA))))
5265	  pSiS->ForceCRT2Type = CRT2_TV;
5266       else if((pSiS->VBFlags & CRT2_LCD) && (pSiS->ForceCRT1Type == CRT1_VGA))
5267	  pSiS->ForceCRT2Type = CRT2_LCD;
5268       else if(pSiS->VBFlags & CRT2_TV)
5269	  pSiS->ForceCRT2Type = CRT2_TV;
5270       else if((pSiS->VBFlags & CRT2_VGA) && (pSiS->ForceCRT1Type == CRT1_VGA))
5271	  pSiS->ForceCRT2Type = CRT2_VGA;
5272    }
5273
5274    switch(pSiS->ForceCRT2Type) {
5275       case CRT2_TV:
5276	  pSiS->VBFlags &= ~(CRT2_LCD | CRT2_VGA);
5277	  if(pSiS->VBFlags2 & (VB2_SISTVBRIDGE | VB2_CHRONTEL)) {
5278	     pSiS->VBFlags |= CRT2_TV;
5279	  } else {
5280	     pSiS->VBFlags &= ~(CRT2_TV);
5281	     xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
5282		"Hardware does not support TV output\n");
5283	  }
5284	  break;
5285       case CRT2_LCD:
5286	  pSiS->VBFlags &= ~(CRT2_TV | CRT2_VGA);
5287	  if((pSiS->VBFlags2 & VB2_VIDEOBRIDGE) && (pSiS->VBLCDFlags)) {
5288	     pSiS->VBFlags |= CRT2_LCD;
5289	  } else if((pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) && (!(pSiS->VBFlags2 & VB2_30xBDH))) {
5290	     SiSSetupPseudoPanel(pScrn);
5291	     pSiS->detectedCRT2Devices |= CRT2_LCD;
5292	  } else {
5293	     pSiS->VBFlags &= ~(CRT2_LCD);
5294	     xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
5295		"Can't force CRT2 to LCD, no LCD detected\n");
5296	  }
5297	  break;
5298       case CRT2_VGA:
5299	  pSiS->VBFlags &= ~(CRT2_TV | CRT2_LCD);
5300	  if(pSiS->VBFlags2 & VB2_SISVGA2BRIDGE) {
5301	     pSiS->VBFlags |= CRT2_VGA;
5302	  } else {
5303	     pSiS->VBFlags &= ~(CRT2_VGA);
5304	     xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
5305		 "Hardware does not support secondary VGA\n");
5306	  }
5307	  break;
5308       default:
5309	  pSiS->VBFlags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
5310    }
5311
5312    /* Setup gamma (the cmap layer needs this to be initialised) */
5313    /* (Do this after evaluating options) */
5314    {
5315       Gamma zeros = {0.0, 0.0, 0.0};
5316       xf86SetGamma(pScrn, zeros);
5317    }
5318
5319#ifdef SISDUALHEAD
5320    if((!pSiS->DualHeadMode) || (pSiS->SecondHead)) {
5321#endif
5322       xf86DrvMsg(pScrn->scrnIndex, pSiS->CRT1gammaGiven ? X_CONFIG : X_INFO,
5323	     "%samma correction is %s\n",
5324	     (pSiS->VBFlags2 & VB2_VIDEOBRIDGE) ? "CRT1 g" : "G",
5325	     pSiS->CRT1gamma ? "enabled" : "disabled");
5326
5327       if((pSiS->VGAEngine == SIS_315_VGA)	&&
5328          (!(pSiS->NoXvideo))			&&
5329	  (!(pSiS->SiS_SD2_Flags & SiS_SD2_NOOVERLAY))) {
5330	  xf86DrvMsg(pScrn->scrnIndex, pSiS->XvGammaGiven ? X_CONFIG : X_INFO,
5331		"Separate Xv gamma correction %sis %s\n",
5332		(pSiS->VBFlags2 & VB2_VIDEOBRIDGE) ? "for CRT1 " : "",
5333		pSiS->XvGamma ? "enabled" : "disabled");
5334	  if(pSiS->XvGamma) {
5335	     xf86DrvMsg(pScrn->scrnIndex, pSiS->XvGammaGiven ? X_CONFIG : X_INFO,
5336		"Xv gamma correction: %.3f %.3f %.3f\n",
5337		(float)((float)pSiS->XvGammaRed / 1000),
5338		(float)((float)pSiS->XvGammaGreen / 1000),
5339		(float)((float)pSiS->XvGammaBlue / 1000));
5340	     if(!pSiS->CRT1gamma) {
5341		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5342		   "Xv gamma correction requires %samma correction enabled\n",
5343		   (pSiS->VBFlags2 & VB2_VIDEOBRIDGE) ? "CRT1 g" : "G");
5344	     }
5345	  }
5346       }
5347#ifdef SISDUALHEAD
5348    }
5349#endif
5350
5351#ifdef SISDUALHEAD
5352    if(pSiS->DualHeadMode) pSiS->CRT2SepGamma = FALSE;
5353#endif
5354
5355#ifdef SISDUALHEAD
5356    if((!pSiS->DualHeadMode) || (!pSiS->SecondHead))
5357#endif
5358    {
5359       Bool isDH = FALSE;
5360       if(pSiS->CRT2gamma) {
5361          if( ((pSiS->VGAEngine != SIS_300_VGA) && (pSiS->VGAEngine != SIS_315_VGA)) ||
5362              (!(pSiS->VBFlags2 & VB2_SISBRIDGE)) ) {
5363	     if(pSiS->VBFlags2 & VB2_VIDEOBRIDGE) {
5364	        xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5365			"CRT2 gamma correction not supported by hardware\n");
5366	     }
5367	     pSiS->CRT2gamma = pSiS->CRT2SepGamma = FALSE;
5368          } else if((pSiS->VBFlags2 & VB2_30xBDH) && (pSiS->VBFlags & CRT2_LCD)) {
5369	     isDH = TRUE;
5370	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5371			"CRT2 gamma correction not supported for LCD\n");
5372	     /* But leave it on, will be caught in LoadPalette */
5373          }
5374       }
5375       if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
5376	  xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CRT2 gamma correction is %s%s%s\n",
5377		pSiS->CRT2gamma ? "enabled" : "disabled",
5378		isDH ? " (for TV and VGA2) " : "",
5379		pSiS->CRT2SepGamma ? " (separate from CRT1)" : "");
5380       }
5381    }
5382
5383    /* Eventually overrule TV Type (SVIDEO, COMPOSITE, SCART, HIVISION, YPBPR) */
5384    if(pSiS->VBFlags2 & VB2_SISTVBRIDGE) {
5385       if(pSiS->ForceTVType != -1) {
5386	  pSiS->VBFlags &= ~(TV_INTERFACE);
5387	  if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) {
5388	     pSiS->VBFlags &= ~(TV_CHSCART | TV_CHYPBPR525I);
5389	  }
5390	  pSiS->VBFlags |= pSiS->ForceTVType;
5391	  if(pSiS->VBFlags & TV_YPBPR) {
5392	     pSiS->VBFlags &= ~(TV_STANDARD);
5393	     pSiS->VBFlags &= ~(TV_YPBPRAR);
5394	     pSiS->VBFlags |= pSiS->ForceYPbPrType;
5395	     pSiS->VBFlags |= pSiS->ForceYPbPrAR;
5396	  }
5397       }
5398    }
5399
5400    /* Handle ForceCRT1 option (part 2) */
5401    pSiS->CRT1changed = FALSE;
5402    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
5403       usScratchCR17 = pSiS->oldCR17;
5404       usScratchCR63 = pSiS->oldCR63;
5405       usScratchSR1F = pSiS->oldSR1F;
5406       usScratchCR32 = pSiS->postVBCR32;
5407       if(pSiS->VESA != 1) {
5408          /* Copy forceCRT1 option to CRT1off if option is given */
5409#ifdef SISDUALHEAD
5410          /* In DHM, handle this option only for master head, not the slave */
5411          if( (pSiS->forceCRT1 != -1) &&
5412	       (!(pSiS->DualHeadMode && pSiS->SecondHead)) ) {
5413#else
5414          if(pSiS->forceCRT1 != -1) {
5415#endif
5416	     xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
5417		 "CRT1 detection overruled by ForceCRT1 option\n");
5418	     if(pSiS->forceCRT1) {
5419		 pSiS->CRT1off = 0;
5420		 if(pSiS->VGAEngine == SIS_300_VGA) {
5421		    if(!(usScratchCR17 & 0x80)) pSiS->CRT1changed = TRUE;
5422		 } else {
5423		    if(usScratchCR63 & 0x40) pSiS->CRT1changed = TRUE;
5424		 }
5425		 usScratchCR17 |= 0x80;
5426		 usScratchCR32 |= 0x20;
5427		 usScratchCR63 &= ~0x40;
5428		 usScratchSR1F &= ~0xc0;
5429	     } else {
5430		 if( ! ( (pScrn->bitsPerPixel == 8) &&
5431		         ( (pSiS->VBFlags2 & (VB2_LVDS | VB2_CHRONTEL)) ||
5432		           ((pSiS->VBFlags2 & VB2_30xBDH) && (pSiS->VBFlags & CRT2_LCD)) ) ) ) {
5433		    pSiS->CRT1off = 1;
5434		    if(pSiS->VGAEngine == SIS_300_VGA) {
5435		       if(usScratchCR17 & 0x80) pSiS->CRT1changed = TRUE;
5436		    } else {
5437		       if(!(usScratchCR63 & 0x40)) pSiS->CRT1changed = TRUE;
5438		    }
5439		    usScratchCR32 &= ~0x20;
5440		    /* We must not actually switch off CRT1 before we changed the mode! */
5441		 }
5442	     }
5443	     /* Here we can write to CR17 even on 315 series as we only ENABLE
5444	      * the bit here
5445	      */
5446	     outSISIDXREG(SISCR, 0x17, usScratchCR17);
5447	     if(pSiS->VGAEngine == SIS_315_VGA) {
5448		outSISIDXREG(SISCR, pSiS->myCR63, usScratchCR63);
5449	     }
5450	     outSISIDXREG(SISCR, 0x32, usScratchCR32);
5451	     if(pSiS->CRT1changed) {
5452		outSISIDXREG(SISSR, 0x00, 0x01);    /* Synchronous Reset */
5453		usleep(10000);
5454		outSISIDXREG(SISSR, 0x00, 0x03);    /* End Reset */
5455		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5456			"CRT1 status changed by ForceCRT1 option\n");
5457	     }
5458	     outSISIDXREG(SISSR, 0x1f, usScratchSR1F);
5459          }
5460       }
5461       /* Store the new VB connection register contents for later mode changes */
5462       pSiS->newCR32 = usScratchCR32;
5463    }
5464
5465    /* Check if CRT1 used (or needed; this eg. if no CRT2 detected) */
5466    if(pSiS->VBFlags2 & VB2_VIDEOBRIDGE) {
5467
5468        /* No CRT2 output? Then we NEED CRT1!
5469	 * We also need CRT1 if depth = 8 and bridge=LVDS|301B-DH
5470	 */
5471	if( (!(pSiS->VBFlags & (CRT2_VGA | CRT2_LCD | CRT2_TV))) ||
5472	    ( (pScrn->bitsPerPixel == 8) &&
5473	      ( (pSiS->VBFlags2 & (VB2_LVDS | VB2_CHRONTEL)) ||
5474	        ((pSiS->VBFlags2 & VB2_30xBDH) && (pSiS->VBFlags & CRT2_LCD)) ) ) ) {
5475	    pSiS->CRT1off = 0;
5476	}
5477	/* No CRT2 output? Then we can't use Xv on CRT2 */
5478	if(!(pSiS->VBFlags & (CRT2_VGA | CRT2_LCD | CRT2_TV))) {
5479	    pSiS->XvOnCRT2 = FALSE;
5480	}
5481
5482    } else { /* no video bridge? */
5483	/* Then we NEED CRT1... */
5484	pSiS->CRT1off = 0;
5485	/* ... and can't use CRT2 for Xv output */
5486	pSiS->XvOnCRT2 = FALSE;
5487    }
5488
5489    /* LCDA? Then we don't switch off CRT1 */
5490    if(pSiS->VBFlags & CRT1_LCDA) pSiS->CRT1off = 0;
5491
5492    /* Handle TVStandard option */
5493    if((pSiS->NonDefaultPAL != -1) || (pSiS->NonDefaultNTSC != -1)) {
5494       if( (!(pSiS->VBFlags2 & VB2_SISTVBRIDGE)) &&
5495	   (!((pSiS->VBFlags2 & VB2_CHRONTEL)) && (pSiS->ChrontelType == CHRONTEL_701x)) ) {
5496	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5497	   	"PALM, PALN and NTSCJ not supported on this hardware\n");
5498	  pSiS->NonDefaultPAL = pSiS->NonDefaultNTSC = -1;
5499	  pSiS->VBFlags &= ~(TV_PALN | TV_PALM | TV_NTSCJ);
5500	  pSiS->SiS_SD_Flags &= ~(SiS_SD_SUPPORTPALMN | SiS_SD_SUPPORTNTSCJ);
5501       }
5502    }
5503    if(pSiS->OptTVStand != -1) {
5504       if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
5505	  if( (!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & (TV_CHSCART | TV_CHYPBPR525I)))) &&
5506	      (!(pSiS->VBFlags & (TV_HIVISION | TV_YPBPR))) ) {
5507	     pSiS->VBFlags &= ~(TV_PAL | TV_NTSC | TV_PALN | TV_PALM | TV_NTSCJ);
5508	     if(pSiS->OptTVStand) {
5509	        pSiS->VBFlags |= TV_PAL;
5510	        if(pSiS->NonDefaultPAL == 1)  pSiS->VBFlags |= TV_PALM;
5511	        else if(!pSiS->NonDefaultPAL) pSiS->VBFlags |= TV_PALN;
5512	     } else {
5513	        pSiS->VBFlags |= TV_NTSC;
5514		if(pSiS->NonDefaultNTSC == 1) pSiS->VBFlags |= TV_NTSCJ;
5515	     }
5516	  } else {
5517	     pSiS->OptTVStand = pSiS->NonDefaultPAL = -1;
5518	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5519	    	 "Option TVStandard ignored for YPbPr, HiVision and Chrontel-SCART\n");
5520	  }
5521       } else if(pSiS->Chipset == PCI_CHIP_SIS6326) {
5522	  pSiS->SiS6326Flags &= ~SIS6326_TVPAL;
5523	  if(pSiS->OptTVStand) pSiS->SiS6326Flags |= SIS6326_TVPAL;
5524       }
5525    }
5526
5527    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
5528       /* Default to PAL */
5529       if(pSiS->VBFlags & (TV_SVIDEO | TV_AVIDEO)) {
5530          if(!(pSiS->VBFlags & (TV_PAL | TV_NTSC))) {
5531	     pSiS->VBFlags &= ~(TV_PAL | TV_NTSC | TV_PALN | TV_PALM | TV_NTSCJ);
5532	     pSiS->VBFlags |= TV_PAL;
5533	  }
5534       }
5535       /* SCART only supported for PAL */
5536       if((pSiS->VBFlags2 & VB2_SISBRIDGE) && (pSiS->VBFlags & TV_SCART)) {
5537	  pSiS->VBFlags &= ~(TV_NTSC | TV_PALN | TV_PALM | TV_NTSCJ);
5538	  pSiS->VBFlags |= TV_PAL;
5539	  pSiS->OptTVStand = 1;
5540	  pSiS->NonDefaultPAL = pSiS->NonDefaultNTSC = -1;
5541       }
5542    }
5543
5544#ifdef SIS_CP
5545    SIS_CP_DRIVER_RECONFIGOPT
5546#endif
5547
5548    if((pSiS->Chipset == PCI_CHIP_SIS6326) && (pSiS->SiS6326Flags & SIS6326_HASTV)) {
5549       if(pSiS->sis6326tvplug != -1) {
5550          pSiS->SiS6326Flags &= ~(SIS6326_TVSVIDEO | SIS6326_TVCVBS);
5551	  pSiS->SiS6326Flags |= SIS6326_TVDETECTED;
5552	  if(pSiS->sis6326tvplug == 1) 	pSiS->SiS6326Flags |= SIS6326_TVCVBS;
5553	  else 				pSiS->SiS6326Flags |= SIS6326_TVSVIDEO;
5554	  xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
5555	      "SiS6326 TV plug type detection overruled by %s\n",
5556	      (pSiS->SiS6326Flags & SIS6326_TVCVBS) ? "COMPOSITE" : "SVIDEO");
5557       }
5558    }
5559
5560    /* Do some checks */
5561    if(pSiS->OptTVOver != -1) {
5562       if(pSiS->VBFlags2 & VB2_CHRONTEL) {
5563	  pSiS->UseCHOverScan = pSiS->OptTVOver;
5564       } else {
5565	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5566	      "CHTVOverscan only supported on CHRONTEL 70xx\n");
5567	  pSiS->UseCHOverScan = -1;
5568       }
5569    } else pSiS->UseCHOverScan = -1;
5570
5571    if(pSiS->sistvedgeenhance != -1) {
5572       if(!(pSiS->VBFlags2 & VB2_301)) {
5573	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5574	      "SISTVEdgeEnhance only supported on SiS301\n");
5575	  pSiS->sistvedgeenhance = -1;
5576       }
5577    }
5578    if(pSiS->sistvsaturation != -1) {
5579       if(pSiS->VBFlags2 & VB2_301) {
5580	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5581	      "SISTVSaturation not supported on SiS301\n");
5582	  pSiS->sistvsaturation = -1;
5583       }
5584    }
5585
5586    /* Do some MergedFB mode initialisation */
5587#ifdef SISMERGED
5588    if(pSiS->MergedFB) {
5589       pSiS->CRT2pScrn = malloc(sizeof(ScrnInfoRec));
5590       if(!pSiS->CRT2pScrn) {
5591          SISErrorLog(pScrn, "Failed to allocate memory for 2nd pScrn, %s\n", mergeddisstr);
5592	  pSiS->MergedFB = FALSE;
5593       } else {
5594          memcpy(pSiS->CRT2pScrn, pScrn, sizeof(ScrnInfoRec));
5595       }
5596    }
5597#endif
5598
5599    /* Determine CRT1<>CRT2 mode
5600     *     Note: When using VESA or if the bridge is in slavemode, display
5601     *           is ALWAYS in MIRROR_MODE!
5602     *           This requires extra checks in functions using this flag!
5603     *           (see sis_video.c for example)
5604     */
5605    if(pSiS->VBFlags & DISPTYPE_DISP2) {
5606        if(pSiS->CRT1off) {	/* CRT2 only ------------------------------- */
5607#ifdef SISDUALHEAD
5608	     if(pSiS->DualHeadMode) {
5609		SISErrorLog(pScrn,
5610		    "CRT1 not detected or forced off. Dual Head mode can't initialize.\n");
5611		if(pSiSEnt) pSiSEnt->DisableDual = TRUE;
5612		goto my_error_1;
5613	     }
5614#endif
5615#ifdef SISMERGED
5616	     if(pSiS->MergedFB) {
5617		if(pSiS->MergedFBAuto) {
5618		   xf86DrvMsg(pScrn->scrnIndex, X_INFO, mergednocrt1, mergeddisstr);
5619		} else {
5620		   SISErrorLog(pScrn, mergednocrt1, mergeddisstr);
5621		}
5622		if(pSiS->CRT2pScrn) free(pSiS->CRT2pScrn);
5623		pSiS->CRT2pScrn = NULL;
5624		pSiS->MergedFB = FALSE;
5625	     }
5626#endif
5627	     pSiS->VBFlags |= VB_DISPMODE_SINGLE;
5628	     /* No CRT1? Then we use the video overlay on CRT2 */
5629	     pSiS->XvOnCRT2 = TRUE;
5630	} else			/* CRT1 and CRT2 - mirror or dual head ----- */
5631#ifdef SISDUALHEAD
5632	     if(pSiS->DualHeadMode) {
5633		pSiS->VBFlags |= (VB_DISPMODE_DUAL | DISPTYPE_CRT1);
5634		if(pSiS->VESA != -1) {
5635		    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5636			"VESA option not used in Dual Head mode. VESA disabled.\n");
5637		}
5638		if(pSiSEnt) pSiSEnt->DisableDual = FALSE;
5639		pSiS->VESA = 0;
5640	     } else
5641#endif
5642#ifdef SISMERGED
5643		    if(pSiS->MergedFB) {
5644		 pSiS->VBFlags |= (VB_DISPMODE_MIRROR | DISPTYPE_CRT1);
5645		 if(pSiS->VESA != -1) {
5646		    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5647			"VESA option not used in MergedFB mode. VESA disabled.\n");
5648		 }
5649		 pSiS->VESA = 0;
5650	     } else
5651#endif
5652		 pSiS->VBFlags |= (VB_DISPMODE_MIRROR | DISPTYPE_CRT1);
5653    } else {			/* CRT1 only ------------------------------- */
5654#ifdef SISDUALHEAD
5655	     if(pSiS->DualHeadMode) {
5656		SISErrorLog(pScrn,
5657		   "No CRT2 output selected or no bridge detected. "
5658		   "Dual Head mode can't initialize.\n");
5659		goto my_error_1;
5660	     }
5661#endif
5662#ifdef SISMERGED
5663	     if(pSiS->MergedFB) {
5664		if(pSiS->MergedFBAuto) {
5665		   xf86DrvMsg(pScrn->scrnIndex, X_INFO, mergednocrt2, mergeddisstr);
5666		} else {
5667		   SISErrorLog(pScrn, mergednocrt2, mergeddisstr);
5668		}
5669		if(pSiS->CRT2pScrn) free(pSiS->CRT2pScrn);
5670		pSiS->CRT2pScrn = NULL;
5671		pSiS->MergedFB = FALSE;
5672	     }
5673#endif
5674             pSiS->VBFlags |= (VB_DISPMODE_SINGLE | DISPTYPE_CRT1);
5675    }
5676
5677    if((pSiS->VGAEngine == SIS_315_VGA) || (pSiS->VGAEngine == SIS_300_VGA)) {
5678       if((!pSiS->NoXvideo)		&&
5679          (!pSiS->hasTwoOverlays)	&&
5680	  (!(pSiS->SiS_SD2_Flags & SiS_SD2_NOOVERLAY))) {
5681	  xf86DrvMsg(pScrn->scrnIndex, from,
5682	      "Using Xv overlay by default on CRT%d\n",
5683	      pSiS->XvOnCRT2 ? 2 : 1);
5684       }
5685    }
5686
5687    /* Init ptrs for Save/Restore functions and calc MaxClock */
5688    SISDACPreInit(pScrn);
5689
5690    /* ********** end of VBFlags setup ********** */
5691
5692    /* VBFlags are initialized now. Back them up for SlaveMode modes. */
5693    pSiS->VBFlags_backup = pSiS->VBFlags;
5694
5695    /* Backup CR32,36,37 (in order to write them back after a VT switch) */
5696    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
5697       inSISIDXREG(SISCR,0x32,pSiS->myCR32);
5698       inSISIDXREG(SISCR,0x36,pSiS->myCR36);
5699       inSISIDXREG(SISCR,0x37,pSiS->myCR37);
5700    }
5701
5702    /* Find out about paneldelaycompensation and evaluate option */
5703#ifdef SISDUALHEAD
5704    if((!pSiS->DualHeadMode) || (!pSiS->SecondHead)) {
5705#endif
5706       if(pSiS->VGAEngine == SIS_300_VGA) {
5707
5708          if(pSiS->VBFlags2 & (VB2_LVDS | VB2_30xBDH)) {
5709
5710	     /* Save the current PDC if the panel is used at the moment.
5711	      * This seems by far the safest way to find out about it.
5712	      * If the system is using an old version of sisfb, we can't
5713	      * trust the pdc register value. If sisfb saved the pdc for
5714	      * us, use it.
5715	      */
5716	     if(pSiS->sisfbpdc != 0xff) {
5717	        pSiS->SiS_Pr->PDC = pSiS->sisfbpdc;
5718	     } else {
5719	        if(!(pSiS->donttrustpdc)) {
5720	           UChar tmp;
5721	           inSISIDXREG(SISCR, 0x30, tmp);
5722	           if(tmp & 0x20) {
5723	              inSISIDXREG(SISPART1, 0x13, pSiS->SiS_Pr->PDC);
5724                   } else {
5725	             xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5726		          "Unable to detect LCD PanelDelayCompensation, LCD is not active\n");
5727	           }
5728	        } else {
5729	           xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5730		        "Unable to detect LCD PanelDelayCompensation, please update sisfb\n");
5731	        }
5732	     }
5733	     if(pSiS->SiS_Pr->PDC != -1) {
5734	        pSiS->SiS_Pr->PDC &= 0x3c;
5735	        xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5736		     "Detected LCD PanelDelayCompensation 0x%02x\n",
5737		     pSiS->SiS_Pr->PDC);
5738	     }
5739
5740	     /* If we haven't been able to find out, use our other methods */
5741	     if(pSiS->SiS_Pr->PDC == -1) {
5742		int i=0;
5743		do {
5744		   if(mypdctable[i].subsysVendor == PCI_SUB_VENDOR_ID(pSiS->PciInfo) &&
5745		      mypdctable[i].subsysCard == PCI_SUB_DEVICE_ID(pSiS->PciInfo)) {
5746			 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5747			    "PCI card/vendor identified for non-default PanelDelayCompensation\n");
5748			 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5749			     "Vendor: %s, card: %s (ID %04x), PanelDelayCompensation: 0x%02x\n",
5750			     mypdctable[i].vendorName, mypdctable[i].cardName,
5751			     PCI_SUB_DEVICE_ID(pSiS->PciInfo), mypdctable[i].pdc);
5752			 if(pSiS->PDC == -1) {
5753			    pSiS->PDC = mypdctable[i].pdc;
5754			 } else {
5755			    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
5756				"PanelDelayCompensation overruled by option\n");
5757			 }
5758			 break;
5759		   }
5760		   i++;
5761		} while(mypdctable[i].subsysVendor != 0);
5762	     }
5763
5764	     if(pSiS->PDC != -1) {
5765		if(pSiS->BIOS) {
5766		   if(pSiS->VBFlags2 & VB2_LVDS) {
5767		      if(pSiS->BIOS[0x220] & 0x80) {
5768			 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5769			     "BIOS uses OEM LCD Panel Delay Compensation 0x%02x\n",
5770			     pSiS->BIOS[0x220] & 0x3c);
5771			 pSiS->BIOS[0x220] &= 0x7f;
5772		      }
5773		   }
5774		   if(pSiS->VBFlags2 & (VB2_301B | VB2_302B)) {
5775		      if(pSiS->BIOS[0x220] & 0x80) {
5776			 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5777			     "BIOS uses OEM LCD Panel Delay Compensation 0x%02x\n",
5778			       (  (pSiS->VBLCDFlags & VB_LCD_1280x1024) ?
5779			                 pSiS->BIOS[0x223] : pSiS->BIOS[0x224]  ) & 0x3c);
5780			 pSiS->BIOS[0x220] &= 0x7f;
5781		      }
5782		   }
5783		}
5784		pSiS->SiS_Pr->PDC = (pSiS->PDC & 0x3c);
5785		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
5786		      "Using LCD Panel Delay Compensation 0x%02x\n", pSiS->SiS_Pr->PDC);
5787	     }
5788	  }
5789
5790       }  /* SIS_300_VGA */
5791
5792       if(pSiS->VGAEngine == SIS_315_VGA) {
5793
5794	  UChar tmp, tmp2;
5795	  inSISIDXREG(SISCR, 0x30, tmp);
5796
5797	  /* Save the current PDC if the panel is used at the moment. */
5798	  if(pSiS->VBFlags2 & VB2_SISLVDSBRIDGE) {
5799
5800	     if(pSiS->sisfbpdc != 0xff) {
5801	        pSiS->SiS_Pr->PDC = pSiS->sisfbpdc;
5802	     }
5803	     if(pSiS->sisfbpdca != 0xff) {
5804	        pSiS->SiS_Pr->PDCA = pSiS->sisfbpdca;
5805	     }
5806
5807	     if(!pSiS->donttrustpdc) {
5808	        if((pSiS->sisfbpdc == 0xff) && (pSiS->sisfbpdca == 0xff)) {
5809		   CARD16 tempa, tempb;
5810		   inSISIDXREG(SISPART1,0x2d,tmp2);
5811		   tempa = (tmp2 & 0xf0) >> 3;
5812		   tempb = (tmp2 & 0x0f) << 1;
5813		   inSISIDXREG(SISPART1,0x20,tmp2);
5814		   tempa |= ((tmp2 & 0x40) >> 6);
5815		   inSISIDXREG(SISPART1,0x35,tmp2);
5816		   tempb |= ((tmp2 & 0x80) >> 7);
5817		   inSISIDXREG(SISPART1,0x13,tmp2);
5818		   if(!pSiS->ROM661New) {
5819		      if((tmp2 & 0x04) || (tmp & 0x20)) {
5820		         pSiS->SiS_Pr->PDCA = tempa;
5821		         pSiS->SiS_Pr->PDC  = tempb;
5822		      } else {
5823			 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5824			     "Unable to detect PanelDelayCompensation, LCD is not active\n");
5825		      }
5826		   } else {
5827		      if(tmp2 & 0x04) {
5828		         pSiS->SiS_Pr->PDCA = tempa;
5829		      } else if(tmp & 0x20) {
5830		         pSiS->SiS_Pr->PDC  = tempb;
5831		      } else {
5832			 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5833			     "Unable to detect PanelDelayCompensation, LCD is not active\n");
5834		      }
5835		   }
5836		}
5837	     } else {
5838		xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5839		    "Unable to detect PanelDelayCompensation, please update sisfb\n");
5840	     }
5841	     if(pSiS->SiS_Pr->PDC != -1) {
5842		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5843		     "Detected LCD PanelDelayCompensation 0x%02x (for LCD=CRT2)\n",
5844		     pSiS->SiS_Pr->PDC);
5845	     }
5846	     if(pSiS->SiS_Pr->PDCA != -1) {
5847		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5848		     "Detected LCD PanelDelayCompensation1 0x%02x (for LCD=CRT1)\n",
5849		     pSiS->SiS_Pr->PDCA);
5850	     }
5851	  }
5852
5853	  /* Let user override (for all bridges) */
5854	  if(pSiS->VBFlags2 & VB2_30xBLV) {
5855	     if(pSiS->PDC != -1) {
5856	        pSiS->SiS_Pr->PDC = pSiS->PDC & 0x1f;
5857		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
5858		     "Using LCD PanelDelayCompensation 0x%02x (for LCD=CRT2)\n",
5859		     pSiS->SiS_Pr->PDC);
5860	     }
5861	     if(pSiS->PDCA != -1) {
5862		pSiS->SiS_Pr->PDCA = pSiS->PDCA & 0x1f;
5863		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
5864		     "Using LCD PanelDelayCompensation1 0x%02x (for LCD=CRT1)\n",
5865		     pSiS->SiS_Pr->PDCA);
5866	     }
5867          }
5868
5869 	  /* Read the current EMI (if not overruled) */
5870	  if(pSiS->VBFlags2 & VB2_SISEMIBRIDGE) {
5871	     MessageType from = X_PROBED;
5872	     if(pSiS->EMI != -1) {
5873		pSiS->SiS_Pr->EMI_30 = (pSiS->EMI >> 24) & 0x60;
5874		pSiS->SiS_Pr->EMI_31 = (pSiS->EMI >> 16) & 0xff;
5875		pSiS->SiS_Pr->EMI_32 = (pSiS->EMI >> 8)  & 0xff;
5876		pSiS->SiS_Pr->EMI_33 = pSiS->EMI & 0xff;
5877		pSiS->SiS_Pr->HaveEMI = pSiS->SiS_Pr->HaveEMILCD = TRUE;
5878		pSiS->SiS_Pr->OverruleEMI = TRUE;
5879		from = X_CONFIG;
5880	     } else if((pSiS->sisfbfound) && (pSiS->sisfb_haveemi)) {
5881		pSiS->SiS_Pr->EMI_30 = pSiS->sisfb_emi30;
5882		pSiS->SiS_Pr->EMI_31 = pSiS->sisfb_emi31;
5883		pSiS->SiS_Pr->EMI_32 = pSiS->sisfb_emi32;
5884		pSiS->SiS_Pr->EMI_33 = pSiS->sisfb_emi33;
5885		pSiS->SiS_Pr->HaveEMI = TRUE;
5886		if(pSiS->sisfb_haveemilcd) pSiS->SiS_Pr->HaveEMILCD = TRUE;
5887		pSiS->SiS_Pr->OverruleEMI = FALSE;
5888	     } else {
5889		inSISIDXREG(SISPART4, 0x30, pSiS->SiS_Pr->EMI_30);
5890		inSISIDXREG(SISPART4, 0x31, pSiS->SiS_Pr->EMI_31);
5891		inSISIDXREG(SISPART4, 0x32, pSiS->SiS_Pr->EMI_32);
5892		inSISIDXREG(SISPART4, 0x33, pSiS->SiS_Pr->EMI_33);
5893		pSiS->SiS_Pr->HaveEMI = TRUE;
5894		if(tmp & 0x20) pSiS->SiS_Pr->HaveEMILCD = TRUE;
5895		pSiS->SiS_Pr->OverruleEMI = FALSE;
5896	     }
5897	     xf86DrvMsg(pScrn->scrnIndex, from,
5898		   "302LV/302ELV: Using EMI 0x%02x%02x%02x%02x%s\n",
5899		   pSiS->SiS_Pr->EMI_30,pSiS->SiS_Pr->EMI_31,
5900		   pSiS->SiS_Pr->EMI_32,pSiS->SiS_Pr->EMI_33,
5901		   pSiS->SiS_Pr->HaveEMILCD ? " (LCD)" : "");
5902	  }
5903
5904       } /* SIS_315_VGA */
5905#ifdef SISDUALHEAD
5906    }
5907#endif
5908
5909
5910    /* In dual head mode, both heads (currently) share the maxxfbmem equally.
5911     * If memory sharing is done differently, the following has to be changed;
5912     * the other modules (eg. accel and Xv) use dhmOffset for hardware
5913     * pointer settings relative to VideoRAM start and won't need to be changed.
5914     *
5915     * Addendum: dhmoffset is also used for skipping the UMA area on SiS76x.
5916     */
5917
5918    pSiS->dhmOffset = pSiS->FbBaseOffset;
5919    pSiS->FbAddress += pSiS->dhmOffset;
5920
5921#ifdef SISDUALHEAD
5922    if(pSiS->DualHeadMode) {
5923       pSiS->FbAddress = pSiS->realFbAddress;
5924       if(!pSiS->SecondHead) {
5925	  /* ===== First head (always CRT2) ===== */
5926	  /* We use only half of the memory available */
5927	  pSiS->maxxfbmem /= 2;
5928	  /* dhmOffset is 0 (or LFB-base for SiS76x UMA skipping) */
5929	  pSiS->FbAddress += pSiS->dhmOffset;
5930	  xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5931	      "%dKB video RAM at 0x%lx available for master head (CRT2)\n",
5932	      pSiS->maxxfbmem/1024, pSiS->FbAddress);
5933       } else {
5934	  /* ===== Second head (always CRT1) ===== */
5935	  /* We use only half of the memory available */
5936	  pSiS->maxxfbmem /= 2;
5937	  /* Initialize dhmOffset */
5938	  pSiS->dhmOffset += pSiS->maxxfbmem;
5939	  /* Adapt FBAddress */
5940	  pSiS->FbAddress += pSiS->dhmOffset;
5941	  xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5942	     "%dKB video RAM at 0x%lx available for slave head (CRT1)\n",
5943	     pSiS->maxxfbmem/1024,  pSiS->FbAddress);
5944       }
5945    }
5946#endif
5947
5948    /* Note: Do not use availMem for anything from now. Use
5949     * maxxfbmem instead. (availMem does not take dual head
5950     * mode into account.)
5951     */
5952
5953    if(pSiS->FbBaseOffset) {
5954       /* Doubt that the DRM memory manager can deal
5955        * with a heap start of 0...
5956	*/
5957       pSiS->DRIheapstart = 16;
5958       pSiS->DRIheapend = pSiS->FbBaseOffset;
5959    } else {
5960       pSiS->DRIheapstart = pSiS->maxxfbmem;
5961       pSiS->DRIheapend = pSiS->availMem;
5962    }
5963#ifdef SISDUALHEAD
5964    if(pSiS->DualHeadMode) {
5965       pSiS->DRIheapstart = pSiS->DRIheapend = 0;
5966    } else
5967#endif
5968           if(pSiS->DRIheapstart >= pSiS->DRIheapend) {
5969#if 0  /* For future use */
5970       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5971	  "No memory for DRI heap. Please set the option \"MaxXFBMem\" to\n"
5972	  "\tlimit the memory X should use and leave the rest to DRI\n");
5973#endif
5974       pSiS->DRIheapstart = pSiS->DRIheapend = 0;
5975    }
5976
5977    /* Now for something completely different: DDC.
5978     * For 300 and 315/330/340 series, we provide our
5979     * own functions (in order to probe CRT2 as well)
5980     * If these fail, use the VBE.
5981     * All other chipsets will use VBE. No need to re-invent
5982     * the wheel there.
5983     */
5984
5985    pSiS->pVbe = NULL;
5986    didddc2 = FALSE;
5987
5988    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
5989       if(xf86LoadSubModule(pScrn, "ddc")) {
5990	  int crtnum = 0;
5991	  if((pMonitor = SiSDoPrivateDDC(pScrn, &crtnum))) {
5992	     didddc2 = TRUE;
5993	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED, ddcsstr, crtnum);
5994	     xf86PrintEDID(pMonitor);
5995	     xf86SetDDCproperties(pScrn, pMonitor);
5996	     pScrn->monitor->DDC = pMonitor;
5997	     /* Now try to find out aspect ratio */
5998	     SiSFindAspect(pScrn, pMonitor, crtnum);
5999	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED, ddcestr, crtnum);
6000	  }
6001       }
6002    }
6003
6004#ifdef SISDUALHEAD
6005    /* In dual head mode, probe DDC using VBE only for CRT1 (second head) */
6006    if((pSiS->DualHeadMode) && (!didddc2) && (!pSiS->SecondHead)) {
6007       didddc2 = TRUE;
6008    }
6009#endif
6010
6011    if(!didddc2) {
6012       /* If CRT1 is off or LCDA, skip DDC via VBE */
6013       if((pSiS->CRT1off) || (pSiS->VBFlags & CRT1_LCDA)) {
6014          didddc2 = TRUE;
6015       }
6016    }
6017
6018    /* Now (re-)load and initialize the DDC module */
6019    if(!didddc2) {
6020
6021       if(xf86LoadSubModule(pScrn, "ddc")) {
6022
6023	  /* Now load and initialize VBE module. */
6024	  SiS_LoadInitVBE(pScrn);
6025
6026	  if(pSiS->pVbe) {
6027	     if((pMonitor = vbeDoEDID(pSiS->pVbe,NULL))) {
6028		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
6029		      "VBE CRT1 DDC monitor info:\n");
6030		xf86SetDDCproperties(pScrn, xf86PrintEDID(pMonitor));
6031		pScrn->monitor->DDC = pMonitor;
6032		/* Now try to find out aspect ratio */
6033		SiSFindAspect(pScrn, pMonitor, 1);
6034		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
6035		      "End of VBE CRT1 DDC monitor info\n");
6036	     }
6037	  } else {
6038	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6039		 "Failed to read DDC data\n");
6040	  }
6041       }
6042    }
6043
6044#ifdef SISMERGED
6045    if(pSiS->MergedFB) {
6046       pSiS->CRT2pScrn->monitor = malloc(sizeof(MonRec));
6047       if(pSiS->CRT2pScrn->monitor) {
6048	  DisplayModePtr tempm = NULL, currentm = NULL, newm = NULL;
6049	  memcpy(pSiS->CRT2pScrn->monitor, pScrn->monitor, sizeof(MonRec));
6050	  pSiS->CRT2pScrn->monitor->DDC = NULL;
6051	  pSiS->CRT2pScrn->monitor->Modes = NULL;
6052	  pSiS->CRT2pScrn->monitor->id = (char *)crt2monname;
6053	  tempm = pScrn->monitor->Modes;
6054	  while(tempm) {
6055	     if(!(newm = malloc(sizeof(DisplayModeRec)))) break;
6056	     memcpy(newm, tempm, sizeof(DisplayModeRec));
6057	     if(!(newm->name = malloc(strlen(tempm->name) + 1))) {
6058	        free(newm);
6059		break;
6060	     }
6061	     strcpy(newm->name, tempm->name);
6062	     if(!pSiS->CRT2pScrn->monitor->Modes) pSiS->CRT2pScrn->monitor->Modes = newm;
6063	     if(currentm) {
6064	        currentm->next = newm;
6065		newm->prev = currentm;
6066	     }
6067	     currentm = newm;
6068	     tempm = tempm->next;
6069	  }
6070	  if(pSiS->CRT2HSync) {
6071	     pSiS->CRT2pScrn->monitor->nHsync =
6072		SiSStrToRanges(pSiS->CRT2pScrn->monitor->hsync, pSiS->CRT2HSync, MAX_HSYNC);
6073	  }
6074	  if(pSiS->CRT2VRefresh) {
6075	     pSiS->CRT2pScrn->monitor->nVrefresh =
6076		SiSStrToRanges(pSiS->CRT2pScrn->monitor->vrefresh, pSiS->CRT2VRefresh, MAX_VREFRESH);
6077	  }
6078	  if((pMonitor = SiSInternalDDC(pSiS->CRT2pScrn, 1))) {
6079	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED, ddcsstr, 2);
6080	     xf86PrintEDID(pMonitor);
6081	     xf86SetDDCproperties(pSiS->CRT2pScrn, pMonitor);
6082	     pSiS->CRT2pScrn->monitor->DDC = pMonitor;
6083	     /* Now try to find out aspect ratio */
6084	     SiSFindAspect(pScrn, pMonitor, 2);
6085	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED, ddcestr, 2);
6086	     /* use DDC data if no ranges in config file */
6087	     if(!pSiS->CRT2HSync) {
6088	        pSiS->CRT2pScrn->monitor->nHsync = 0;
6089	     }
6090	     if(!pSiS->CRT2VRefresh) {
6091	        pSiS->CRT2pScrn->monitor->nVrefresh = 0;
6092	     }
6093	  } else {
6094	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
6095		"Failed to read DDC data for CRT2\n");
6096	  }
6097       } else {
6098	  SISErrorLog(pScrn, "Failed to allocate memory for CRT2 monitor, %s.\n",
6099	  		mergeddisstr);
6100	  if(pSiS->CRT2pScrn) free(pSiS->CRT2pScrn);
6101	  pSiS->CRT2pScrn = NULL;
6102	  pSiS->MergedFB = FALSE;
6103       }
6104    }
6105#endif
6106
6107    /* Copy our detected monitor gammas, part 1. Note that device redetection
6108     * is not supported in DHM, so there is no need to do that anytime later.
6109     */
6110#ifdef SISDUALHEAD
6111    if(pSiS->DualHeadMode) {
6112       if(!pSiS->SecondHead) {
6113          /* CRT2: Got gamma for LCD or VGA2 */
6114	  pSiSEnt->CRT2VGAMonitorGamma = pSiS->CRT2VGAMonitorGamma;
6115       } else {
6116          /* CRT1: Got gamma for LCD or VGA */
6117	  pSiSEnt->CRT1VGAMonitorGamma = pSiS->CRT1VGAMonitorGamma;
6118       }
6119       if(pSiS->CRT2LCDMonitorGamma) pSiSEnt->CRT2LCDMonitorGamma = pSiS->CRT2LCDMonitorGamma;
6120    }
6121#endif
6122
6123    /* end of DDC */
6124
6125    /* From here, we mainly deal with clocks and modes */
6126
6127#ifdef SISMERGED
6128    if(pSiS->MergedFB) xf86DrvMsg(pScrn->scrnIndex, X_INFO, crtsetupstr, 1);
6129#endif
6130
6131    /* Set the min pixel clock */
6132    pSiS->MinClock = 5000;
6133    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
6134       pSiS->MinClock = 10000;
6135    }
6136    xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "Min pixel clock is %d MHz\n",
6137                pSiS->MinClock / 1000);
6138
6139    /* If the user has specified ramdac speed in the config
6140     * file, we respect that setting.
6141     */
6142    from = X_PROBED;
6143    if(pSiS->pEnt->device->dacSpeeds[0]) {
6144       int speed = 0;
6145       switch(pScrn->bitsPerPixel) {
6146       case 8:  speed = pSiS->pEnt->device->dacSpeeds[DAC_BPP8];
6147                break;
6148       case 16: speed = pSiS->pEnt->device->dacSpeeds[DAC_BPP16];
6149                break;
6150       case 24: speed = pSiS->pEnt->device->dacSpeeds[DAC_BPP24];
6151                break;
6152       case 32: speed = pSiS->pEnt->device->dacSpeeds[DAC_BPP32];
6153                break;
6154       }
6155       if(speed == 0) pSiS->MaxClock = pSiS->pEnt->device->dacSpeeds[0];
6156       else           pSiS->MaxClock = speed;
6157       from = X_CONFIG;
6158    }
6159    xf86DrvMsg(pScrn->scrnIndex, from, "Max pixel clock is %d MHz\n",
6160                pSiS->MaxClock / 1000);
6161
6162    /*
6163     * Setup the ClockRanges, which describe what clock ranges are available,
6164     * and what sort of modes they can be used for.
6165     */
6166    clockRanges = xnfcalloc(sizeof(ClockRange), 1);
6167    clockRanges->next = NULL;
6168    clockRanges->minClock = pSiS->MinClock;
6169    clockRanges->maxClock = pSiS->MaxClock;
6170    clockRanges->clockIndex = -1;               /* programmable */
6171    clockRanges->interlaceAllowed = TRUE;
6172    clockRanges->doubleScanAllowed = TRUE;
6173
6174    /*
6175     * Since we have lots of built-in modes for 300/315/330/340 series
6176     * with vb support, we replace the given default mode list with our
6177     * own. In case the video bridge is to be used, we only allow other
6178     * modes if
6179     *   -) vbtype is 301, 301B, 301C or 302B, and
6180     *   -) crt2 device is not TV, and
6181     *   -) crt1 is not LCDA, unless bridge is TMDS/LCDA capable (301C)
6182     */
6183    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
6184       if(!(pSiS->noInternalModes)) {
6185          Bool acceptcustommodes = TRUE;  /* Accept user modelines */
6186	  Bool includelcdmodes   = TRUE;  /* Include modes reported by DDC */
6187	  Bool isfordvi          = FALSE; /* Is for digital DVI output */
6188	  Bool fakecrt2modes     = FALSE; /* Fake some modes for CRT2 */
6189	  Bool IsForCRT2	 = FALSE;
6190	  if(pSiS->UseVESA) {
6191	     acceptcustommodes = FALSE;
6192	     includelcdmodes   = FALSE;
6193	  }
6194#ifdef SISDUALHEAD  /* Dual head is static. Output devices will not change. */
6195	  if(pSiS->DualHeadMode) {
6196	     if(!pSiS->SecondHead) {  /* CRT2: */
6197	        if(pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) {
6198		   if(!(pSiS->VBFlags2 & VB2_30xBDH)) {
6199		      if(!(pSiS->VBFlags & (CRT2_LCD|CRT2_VGA))) includelcdmodes   = FALSE;
6200		      if(pSiS->VBFlags & CRT2_LCD)               isfordvi          = TRUE;
6201		      if(pSiS->VBFlags & CRT2_TV)                acceptcustommodes = FALSE;
6202		   } else {
6203		      if(pSiS->VBFlags & (CRT2_TV|CRT2_LCD)) {
6204		         acceptcustommodes = FALSE;
6205		         includelcdmodes   = FALSE;
6206			 fakecrt2modes = TRUE;
6207		      }
6208		   }
6209		} else {
6210		   acceptcustommodes = FALSE;
6211		   includelcdmodes   = FALSE;
6212		   if(pSiS->VBFlags & (CRT2_TV|CRT2_LCD)) {
6213		      fakecrt2modes = TRUE;
6214		   }
6215		}
6216		clockRanges->interlaceAllowed = FALSE;
6217		IsForCRT2 = TRUE;
6218	     } else {		/* CRT1: */
6219	        if(pSiS->VBFlags & CRT1_LCDA) {
6220		   if(!(pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE)) {
6221		      acceptcustommodes = FALSE;
6222		      includelcdmodes   = FALSE;
6223		      fakecrt2modes     = TRUE;
6224		      /* Will handle i-lace in mode-switching code */
6225		   } else {
6226		      isfordvi = TRUE;
6227		      /* Don't allow i-lace modes */
6228		      clockRanges->interlaceAllowed = FALSE;
6229		   }
6230		} else {
6231		   includelcdmodes = FALSE;
6232		}
6233	     }
6234	  } else
6235#endif
6236#ifdef SISMERGED  /* MergedFB mode is not static. Output devices may change. */
6237          if(pSiS->MergedFB) {
6238	     if(pSiS->VBFlags & CRT1_LCDA) {
6239	        if(!(pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE)) {
6240		   acceptcustommodes = FALSE;
6241		   includelcdmodes   = FALSE;
6242		   fakecrt2modes     = TRUE;
6243		   /* Will handle i-lace in mode-switching code */
6244		} else {
6245		   isfordvi = TRUE;
6246		   /* Don't allow i-lace custom modes */
6247		   clockRanges->interlaceAllowed = FALSE;
6248		}
6249	     } else {
6250	        includelcdmodes = FALSE;
6251	     }
6252          } else
6253#endif		 /* Mirror mode is not static. Output devices may change. */
6254          if(pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) {
6255	     if(!(pSiS->VBFlags2 & VB2_30xBDH)) {
6256		if(!(pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE)) {
6257		   if(!(pSiS->VBFlags & (CRT2_LCD|CRT2_VGA))) includelcdmodes = FALSE;
6258		   if(pSiS->VBFlags & CRT2_LCD)               isfordvi        = TRUE;
6259		} else {
6260		   if(!(pSiS->VBFlags & (CRT2_LCD|CRT2_VGA|CRT1_LCDA))) includelcdmodes = FALSE;
6261		   if(pSiS->VBFlags & (CRT2_LCD|CRT1_LCDA))             isfordvi        = TRUE;
6262		}
6263		if((!(pSiS->VBFlags & DISPTYPE_CRT1)) && (!(pSiS->VBFlags & CRT1_LCDA))) {
6264		   IsForCRT2 = TRUE;
6265		}
6266		/* Allow user modes, even if CRT2 is TV. Will be filtered through ValidMode();
6267		 * leaving the user modes here might have the advantage that such a mode, if
6268		 * it matches in resolution with a supported TV mode, allows us to drive eg.
6269		 * non standard panels, and still permits switching to TV. This mode will be
6270		 * "mapped" to a supported mode of identical resolution for TV. All this is
6271		 * taken care of by ValidMode() and ModeInit()/PresetMode().
6272		 */
6273	     } else {
6274		if(pSiS->VBFlags & (CRT2_TV|CRT2_LCD)) {
6275		   acceptcustommodes = FALSE;
6276		   includelcdmodes   = FALSE;
6277		   if(!(pSiS->VBFlags & DISPTYPE_CRT1)) {
6278		      fakecrt2modes = TRUE;
6279		      IsForCRT2 = TRUE;
6280		   }
6281		}
6282	     }
6283	  } else if(pSiS->VBFlags & (CRT2_ENABLE | CRT1_LCDA)) {
6284	     acceptcustommodes = FALSE;
6285	     includelcdmodes   = FALSE;
6286	     if((pSiS->VBFlags & CRT1_LCDA) || (!(pSiS->VBFlags & DISPTYPE_CRT1))) {
6287		fakecrt2modes = TRUE;
6288		IsForCRT2 = TRUE;
6289	     }
6290	  } else {
6291	     includelcdmodes   = FALSE;
6292	  }
6293	  /* Ignore interlace, mode switching code will handle this */
6294
6295	  pSiS->HaveCustomModes = FALSE;
6296	  if(SiSMakeOwnModeList(pScrn, acceptcustommodes, includelcdmodes,
6297			isfordvi, &pSiS->HaveCustomModes, FALSE /*fakecrt2modes*/, IsForCRT2)) {
6298	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6299		 "Replaced %s mode list with built-in modes\n",
6300	     pSiS->HaveCustomModes ? "default" : "entire");
6301	     if(pSiS->VGAEngine == SIS_315_VGA) {
6302		int UseWide = pSiS->SiS_Pr->SiS_UseWide;
6303		if(IsForCRT2) UseWide = pSiS->SiS_Pr->SiS_UseWideCRT2;
6304		if((!IsForCRT2) || (pSiS->VBFlags2 & VB2_SISVGA2BRIDGE)) {
6305		   xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6306			"Using %s widescreen modes for CRT%d VGA devices\n",
6307			UseWide ? "real" : "fake", IsForCRT2 ? 2 : 1);
6308		   xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6309			"\tUse option \"ForceCRT%dVGAAspect\" to overrule\n",
6310			IsForCRT2 ? 2 : 1);
6311		}
6312	     }
6313#ifdef TWDEBUG
6314             pScrn->modes = pScrn->monitor->Modes;
6315	     xf86PrintModes(pScrn);
6316	     pScrn->modes = NULL;
6317#endif
6318          } else {
6319	     xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
6320		"Building list of built-in modes failed, using server defaults\n");
6321	  }
6322       } else {
6323          pSiS->HaveCustomModes = TRUE;
6324       }
6325    }
6326
6327    /* Add our built-in hi-res and TV modes on the 6326 */
6328    if(pSiS->Chipset == PCI_CHIP_SIS6326) {
6329       if(pScrn->bitsPerPixel == 8) {
6330	  SiS6326SIS1600x1200_60Mode.next = pScrn->monitor->Modes;
6331	  pScrn->monitor->Modes = &SiS6326SIS1600x1200_60Mode;
6332	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6333	  	"Adding mode \"SIS1600x1200-60\" (depth 8 only)\n");
6334       }
6335       if(pScrn->bitsPerPixel <= 16) {
6336	  SiS6326SIS1280x1024_75Mode.next = pScrn->monitor->Modes;
6337	  pScrn->monitor->Modes = &SiS6326SIS1280x1024_75Mode;
6338	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6339	  	"Adding mode \"SIS1280x1024-75\" (depths 8, 15 and 16 only)\n");
6340       }
6341       if((pSiS->SiS6326Flags & SIS6326_HASTV) &&
6342	  (pSiS->SiS6326Flags & SIS6326_TVDETECTED)) {
6343	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6344		"Adding %s TV modes to mode list:\n",
6345		(pSiS->SiS6326Flags & SIS6326_TVPAL) ? "PAL" : "NTSC");
6346	  if(pSiS->SiS6326Flags & SIS6326_TVPAL) {
6347	     SiS6326PAL800x600Mode.next = pScrn->monitor->Modes;
6348	     pScrn->monitor->Modes = &SiS6326PAL640x480Mode;
6349	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6350		"\t\"PAL800x600\" \"PAL800x600U\" \"PAL720x540\" \"PAL640x480\"\n");
6351	  } else {
6352	     SiS6326NTSC640x480Mode.next = pScrn->monitor->Modes;
6353	     pScrn->monitor->Modes = &SiS6326NTSC640x400Mode;
6354	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6355		"\t\"NTSC640x480\" \"NTSC640x480U\" \"NTSC640x400\"\n");
6356	  }
6357       }
6358    }
6359
6360   /* If there is no HSync or VRefresh data for the monitor,
6361    * derive it from DDC data. Essentially done by common layer
6362    * since 4.3.99.14, but this is not usable since it is done
6363    * too late (in ValidateModes()).
6364    * Addendum: I overrule the ranges now in any case unless
6365    * it would affect a CRT output device or DDC data is available.
6366    * Hence, for LCD(A) and TV, we always get proper ranges. This
6367    * is entirely harmless. However, option "NoOverruleRanges" will
6368    * disable this behavior.
6369    * This should "fix" the - by far - most common configuration
6370    * mistakes.
6371    */
6372
6373    crt1freqoverruled = FALSE;
6374
6375    fromDDC = FALSE;
6376    if((pScrn->monitor->nHsync <= 0) || (pSiS->OverruleRanges)) {
6377       if((pScrn->monitor->nHsync <= 0) && (pScrn->monitor->DDC)) {
6378	  SiSSetSyncRangeFromEdid(pScrn, 1);
6379	  if(pScrn->monitor->nHsync > 0) {
6380	     xf86DrvMsg(pScrn->scrnIndex, X_INFO, subshstr,
6381#ifdef SISDUALHEAD
6382			pSiS->DualHeadMode ? (pSiS->SecondHead ? 1 : 2) :
6383#endif
6384				pSiS->CRT1off ? 2 : 1);
6385	     fromDDC = TRUE;
6386	  }
6387       }
6388       if((pScrn->monitor->nHsync <= 0) || (pSiS->OverruleRanges)) {
6389	  if(SiSAllowSyncOverride(pSiS, fromDDC)) {
6390	     Bool HaveNoRanges = (pScrn->monitor->nHsync <= 0);
6391	     /* Set sane ranges for LCD and TV
6392	      * (our strict checking will filter out invalid ones anyway)
6393	      */
6394	     if((crt1freqoverruled = CheckAndOverruleH(pScrn, pScrn->monitor))) {
6395		xf86DrvMsg(pScrn->scrnIndex, X_INFO, saneh,
6396			HaveNoRanges ? "missing" : "bogus",
6397#ifdef SISDUALHEAD
6398			pSiS->DualHeadMode ? (pSiS->SecondHead ? 1 : 2) :
6399#endif
6400				pSiS->CRT1off ? 2 : 1);
6401	     }
6402	  }
6403       }
6404    }
6405
6406    fromDDC = FALSE;
6407    if((pScrn->monitor->nVrefresh <= 0) || (pSiS->OverruleRanges)) {
6408       if((pScrn->monitor->nVrefresh <= 0) && (pScrn->monitor->DDC)) {
6409	  SiSSetSyncRangeFromEdid(pScrn, 0);
6410	  if(pScrn->monitor->nVrefresh > 0) {
6411	     xf86DrvMsg(pScrn->scrnIndex, X_INFO, subsvstr,
6412#ifdef SISDUALHEAD
6413			pSiS->DualHeadMode ? (pSiS->SecondHead ? 1 : 2) :
6414#endif
6415				pSiS->CRT1off ? 2 : 1);
6416	     fromDDC = TRUE;
6417          }
6418       }
6419       if((pScrn->monitor->nVrefresh <= 0) || (pSiS->OverruleRanges)) {
6420	  if(SiSAllowSyncOverride(pSiS, fromDDC)) {
6421	     Bool HaveNoRanges = (pScrn->monitor->nVrefresh <= 0);
6422	     /* Set sane ranges for LCD and TV */
6423	     if((crt1freqoverruled = CheckAndOverruleV(pScrn, pScrn->monitor))) {
6424		xf86DrvMsg(pScrn->scrnIndex, X_INFO, sanev,
6425			HaveNoRanges ? "missing" : "bogus",
6426#ifdef SISDUALHEAD
6427			pSiS->DualHeadMode ? (pSiS->SecondHead ? 1 : 2) :
6428#endif
6429				pSiS->CRT1off ? 2 : 1);
6430	     }
6431	  }
6432       }
6433    }
6434
6435    if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
6436       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6437	  "\"Unknown reason\" in the following list means that the mode\n");
6438       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6439	  "is not supported on the chipset/bridge/current output device.\n");
6440    }
6441
6442    /*
6443     * xf86ValidateModes will check that the mode HTotal and VTotal values
6444     * don't exceed the chipset's limit if pScrn->maxHValue and
6445     * pScrn->maxVValue are set.  Since our SISValidMode() already takes
6446     * care of this, we don't worry about setting them here.
6447     */
6448
6449    /* Select valid modes from those available */
6450    /*
6451     * Assuming min pitch 256, min height 128
6452     */
6453    {
6454       int minpitch, maxpitch, minheight, maxheight;
6455       pointer backupddc = pScrn->monitor->DDC;
6456
6457       minpitch = 256;
6458       minheight = 128;
6459       switch(pSiS->VGAEngine) {
6460       case SIS_OLD_VGA:
6461       case SIS_530_VGA:
6462          maxpitch = 2040;
6463          maxheight = 2048;
6464          break;
6465       case SIS_300_VGA:
6466       case SIS_315_VGA:
6467          maxpitch = 4088;
6468          maxheight = 4096;
6469          break;
6470       default:
6471          maxpitch = 2048;
6472          maxheight = 2048;
6473          break;
6474       }
6475
6476#ifdef SISMERGED
6477       pSiS->CheckForCRT2 = FALSE;
6478#endif
6479
6480       /* Suppress bogus DDC warning */
6481       if(crt1freqoverruled) pScrn->monitor->DDC = NULL;
6482
6483       i = xf86ValidateModes(pScrn, pScrn->monitor->Modes,
6484			pScrn->display->modes, clockRanges, NULL,
6485			minpitch, maxpitch,
6486			pScrn->bitsPerPixel * 8,
6487			minheight, maxheight,
6488			pScrn->display->virtualX,
6489			pScrn->display->virtualY,
6490			pSiS->maxxfbmem,
6491			LOOKUP_BEST_REFRESH);
6492
6493       pScrn->monitor->DDC = backupddc;
6494    }
6495
6496    if(i == -1) {
6497       SISErrorLog(pScrn, "xf86ValidateModes() error\n");
6498       goto my_error_1;
6499    }
6500
6501    /* Check the virtual screen against the available memory */
6502    {
6503       ULong memreq = (pScrn->virtualX * ((pScrn->bitsPerPixel + 7) / 8)) * pScrn->virtualY;
6504
6505       if(memreq > pSiS->maxxfbmem) {
6506	  SISErrorLog(pScrn,
6507	     "Virtual screen too big for memory; %ldK needed, %ldK available\n",
6508	     memreq/1024, pSiS->maxxfbmem/1024);
6509	  goto my_error_1;
6510       }
6511    }
6512
6513    /* Dual Head:
6514     * -) Go through mode list and mark all those modes as bad,
6515     *    which are unsuitable for dual head mode.
6516     * -) Find the highest used pixelclock on the master head.
6517     */
6518#ifdef SISDUALHEAD
6519    if((pSiS->DualHeadMode) && (!pSiS->SecondHead)) {
6520
6521       pSiSEnt->maxUsedClock = 0;
6522
6523       if((p = first = pScrn->modes)) {
6524
6525	  do {
6526
6527	     n = p->next;
6528
6529	     /* Modes that require the bridge to operate in SlaveMode
6530	      * are not suitable for Dual Head mode.
6531	      */
6532	     if( (pSiS->VGAEngine == SIS_300_VGA) &&
6533		 ( (strcmp(p->name, "320x200") == 0) ||
6534		   (strcmp(p->name, "320x240") == 0) ||
6535		   (strcmp(p->name, "400x300") == 0) ||
6536		   (strcmp(p->name, "512x384") == 0) ||
6537		   (strcmp(p->name, "640x400") == 0) ) )  {
6538		p->status = MODE_BAD;
6539		xf86DrvMsg(pScrn->scrnIndex, X_INFO, notsuitablestr, p->name, "dual head");
6540	     }
6541
6542	     /* Search for the highest clock on first head in order to calculate
6543	      * max clock for second head (CRT1)
6544	      */
6545	     if((p->status == MODE_OK) && (p->Clock > pSiSEnt->maxUsedClock)) {
6546		pSiSEnt->maxUsedClock = p->Clock;
6547	     }
6548
6549	     p = n;
6550
6551	  } while (p != NULL && p != first);
6552
6553       }
6554    }
6555#endif
6556
6557    /* Prune the modes marked as invalid */
6558    xf86PruneDriverModes(pScrn);
6559
6560    if(i == 0 || pScrn->modes == NULL) {
6561       SISErrorLog(pScrn, "No valid modes found - check VertRefresh/HorizSync\n");
6562       goto my_error_1;
6563    }
6564
6565    xf86SetCrtcForModes(pScrn, INTERLACE_HALVE_V);
6566
6567    /* Set the current mode to the first in the list */
6568    pScrn->currentMode = pScrn->modes;
6569
6570    /* Copy to CurrentLayout */
6571    pSiS->CurrentLayout.mode = pScrn->currentMode;
6572    pSiS->CurrentLayout.displayWidth = pScrn->displayWidth;
6573    pSiS->CurrentLayout.displayHeight = pScrn->virtualY;
6574
6575#ifdef SISMERGED
6576    if(pSiS->MergedFB) {
6577       xf86DrvMsg(pScrn->scrnIndex, X_INFO, modesforstr, 1);
6578    }
6579#endif
6580
6581    /* Print the list of modes being used */
6582    {
6583       Bool usemyprint = FALSE;
6584
6585#ifdef SISDUALHEAD
6586       if(pSiS->DualHeadMode) {
6587	  if(pSiS->SecondHead) {
6588	     if(pSiS->VBFlags & CRT1_LCDA) usemyprint = TRUE;
6589	  } else {
6590	     if(pSiS->VBFlags & (CRT2_LCD | CRT2_TV)) usemyprint = TRUE;
6591	  }
6592       } else
6593#endif
6594#ifdef SISMERGED
6595       if(pSiS->MergedFB) {
6596	  if(pSiS->VBFlags & CRT1_LCDA) usemyprint = TRUE;
6597       } else
6598#endif
6599       {
6600	  if( (pSiS->VBFlags & (CRT2_LCD | CRT2_TV)) &&
6601	      (!(pSiS->VBFlags & DISPTYPE_DISP1)) )
6602	     usemyprint = TRUE;
6603       }
6604
6605       if(usemyprint) {
6606	  SiSPrintModes(pScrn);
6607       } else {
6608	  xf86PrintModes(pScrn);
6609       }
6610    }
6611
6612#ifdef SISMERGED
6613    if(pSiS->MergedFB) {
6614       Bool acceptcustommodes = TRUE;
6615       Bool includelcdmodes   = TRUE;
6616       Bool isfordvi          = FALSE;
6617       Bool fakecrt2modes     = FALSE;
6618
6619       xf86DrvMsg(pScrn->scrnIndex, X_INFO, crtsetupstr, 2);
6620
6621       clockRanges->next = NULL;
6622       clockRanges->minClock = pSiS->MinClock;
6623       clockRanges->maxClock = SiSMemBandWidth(pSiS->CRT2pScrn, TRUE);
6624       clockRanges->clockIndex = -1;
6625       clockRanges->interlaceAllowed = FALSE;
6626       clockRanges->doubleScanAllowed = FALSE;
6627       if(pSiS->VGAEngine == SIS_315_VGA) {
6628          clockRanges->doubleScanAllowed = TRUE;
6629       }
6630
6631       xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "Min pixel clock for CRT2 is %d MHz\n",
6632                clockRanges->minClock / 1000);
6633       xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "Max pixel clock for CRT2 is %d MHz\n",
6634                clockRanges->maxClock / 1000);
6635
6636       if(pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) {
6637          if(!(pSiS->VBFlags2 & VB2_30xBDH)) {
6638             if(!(pSiS->VBFlags & (CRT2_LCD|CRT2_VGA))) includelcdmodes   = FALSE;
6639	     if(pSiS->VBFlags & CRT2_LCD)               isfordvi          = TRUE;
6640	     /* See above for a remark on handling CRT2 = TV */
6641	  } else {
6642	     if(pSiS->VBFlags & (CRT2_LCD|CRT2_TV)) {
6643		includelcdmodes   = FALSE;
6644		acceptcustommodes = FALSE;
6645		fakecrt2modes     = TRUE;
6646	     }
6647	  }
6648       } else {
6649	  includelcdmodes   = FALSE;
6650	  acceptcustommodes = FALSE;
6651	  if(pSiS->VBFlags & (CRT2_LCD|CRT2_TV)) {
6652	     fakecrt2modes = TRUE;
6653	  }
6654       }
6655
6656       pSiS->HaveCustomModes2 = FALSE;
6657       if(!SiSMakeOwnModeList(pSiS->CRT2pScrn, acceptcustommodes, includelcdmodes,
6658				isfordvi, &pSiS->HaveCustomModes2, FALSE /* fakecrt2modes */, TRUE )) {
6659
6660	  SISErrorLog(pScrn, "Building list of built-in modes for CRT2 failed, %s\n",
6661				mergeddisstr);
6662	  SiSFreeCRT2Structs(pSiS);
6663	  pSiS->MergedFB = FALSE;
6664
6665       } else {
6666	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6667		 "Replaced %s mode list for CRT2 with built-in modes\n",
6668		 pSiS->HaveCustomModes2 ? "default" : "entire");
6669	  if((pSiS->VGAEngine == SIS_315_VGA) && (pSiS->VBFlags2 & VB2_SISVGA2BRIDGE)) {
6670	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6671		 "Using %s widescreen modes for CRT2 VGA devices\n",
6672		 pSiS->SiS_Pr->SiS_UseWideCRT2 ? "real" : "fake");
6673	  } else pSiS->SiS_Pr->SiS_UseWideCRT2 = 0;
6674       }
6675
6676    }
6677
6678    if(pSiS->MergedFB) {
6679
6680       pointer backupddc;
6681
6682       crt2freqoverruled = FALSE;
6683
6684       fromDDC = FALSE;
6685       if((pSiS->CRT2pScrn->monitor->nHsync <= 0) || (pSiS->OverruleRanges)) {
6686          if((pSiS->CRT2pScrn->monitor->nHsync <= 0) && (pSiS->CRT2pScrn->monitor->DDC)) {
6687	     SiSSetSyncRangeFromEdid(pSiS->CRT2pScrn, 1);
6688	     if(pSiS->CRT2pScrn->monitor->nHsync > 0) {
6689		xf86DrvMsg(pScrn->scrnIndex, X_INFO, subshstr, 2);
6690		fromDDC = TRUE;
6691	     }
6692	  }
6693	  if((pSiS->CRT2pScrn->monitor->nHsync <= 0) || (pSiS->OverruleRanges)) {
6694	     if( (pSiS->VBFlags & CRT2_TV) ||
6695	         ((pSiS->VBFlags & CRT2_LCD) && (!fromDDC)) ) {
6696		Bool HaveNoRanges = (pSiS->CRT2pScrn->monitor->nHsync <= 0);
6697		/* Set sane ranges for LCD and TV */
6698		if((crt2freqoverruled = CheckAndOverruleH(pScrn, pSiS->CRT2pScrn->monitor))) {
6699		   xf86DrvMsg(pScrn->scrnIndex, X_INFO, saneh,
6700			HaveNoRanges ? "missing" : "bogus", 2);
6701		}
6702	     }
6703	  }
6704       }
6705
6706       fromDDC = FALSE;
6707       if((pSiS->CRT2pScrn->monitor->nVrefresh <= 0) || (pSiS->OverruleRanges)) {
6708	  if((pSiS->CRT2pScrn->monitor->nVrefresh <= 0) && (pSiS->CRT2pScrn->monitor->DDC)) {
6709	     SiSSetSyncRangeFromEdid(pSiS->CRT2pScrn, 0);
6710	     if(pSiS->CRT2pScrn->monitor->nVrefresh > 0) {
6711		xf86DrvMsg(pScrn->scrnIndex, X_INFO, subsvstr, 2);
6712		fromDDC = TRUE;
6713	     }
6714          }
6715	  if((pSiS->CRT2pScrn->monitor->nVrefresh <= 0) || (pSiS->OverruleRanges)) {
6716	     if( (pSiS->VBFlags & CRT2_TV) ||
6717	         ((pSiS->VBFlags & CRT2_LCD) && (!fromDDC)) ) {
6718		Bool HaveNoRanges = (pSiS->CRT2pScrn->monitor->nVrefresh <= 0);
6719		/* Set sane ranges for LCD and TV */
6720		if((crt2freqoverruled = CheckAndOverruleV(pScrn, pSiS->CRT2pScrn->monitor))) {
6721		   xf86DrvMsg(pScrn->scrnIndex, X_INFO, sanev,
6722			 HaveNoRanges ? "missing" : "bogus", 2);
6723	        }
6724	     }
6725	  }
6726       }
6727
6728       backupddc = pSiS->CRT2pScrn->monitor->DDC;
6729
6730       /* Suppress bogus DDC warning */
6731       if(crt2freqoverruled) pSiS->CRT2pScrn->monitor->DDC = NULL;
6732
6733       pSiS->CheckForCRT2 = TRUE;
6734
6735       i = xf86ValidateModes(pSiS->CRT2pScrn, pSiS->CRT2pScrn->monitor->Modes,
6736			pSiS->CRT2pScrn->display->modes, clockRanges,
6737			NULL, 256, 4088,
6738			pSiS->CRT2pScrn->bitsPerPixel * 8, 128, 4096,
6739			pScrn->display->virtualX ? pScrn->virtualX : 0,
6740			pScrn->display->virtualY ? pScrn->virtualY : 0,
6741			pSiS->maxxfbmem,
6742			LOOKUP_BEST_REFRESH);
6743
6744       pSiS->CheckForCRT2 = FALSE;
6745       pSiS->CRT2pScrn->monitor->DDC = backupddc;
6746
6747       if(i == -1) {
6748	  SISErrorLog(pScrn, "xf86ValidateModes() error, %s.\n", mergeddisstr);
6749	  SiSFreeCRT2Structs(pSiS);
6750	  pSiS->MergedFB = FALSE;
6751       }
6752
6753    }
6754
6755    if(pSiS->MergedFB) {
6756
6757       if((p = first = pSiS->CRT2pScrn->modes)) {
6758          do {
6759	     n = p->next;
6760	     if( (pSiS->VGAEngine == SIS_300_VGA) &&
6761		 ( (strcmp(p->name, "320x200") == 0) ||
6762		   (strcmp(p->name, "320x240") == 0) ||
6763		   (strcmp(p->name, "400x300") == 0) ||
6764		   (strcmp(p->name, "512x384") == 0) ||
6765		   (strcmp(p->name, "640x400") == 0) ) )  {
6766		p->status = MODE_BAD;
6767		xf86DrvMsg(pScrn->scrnIndex, X_INFO, notsuitablestr, p->name, "MergedFB");
6768	     }
6769	     p = n;
6770	  } while (p != NULL && p != first);
6771       }
6772
6773       xf86PruneDriverModes(pSiS->CRT2pScrn);
6774
6775       if(i == 0 || pSiS->CRT2pScrn->modes == NULL) {
6776	  SISErrorLog(pScrn, "No valid modes found for CRT2; %s\n", mergeddisstr);
6777	  SiSFreeCRT2Structs(pSiS);
6778	  pSiS->MergedFB = FALSE;
6779       }
6780
6781    }
6782
6783    if(pSiS->MergedFB) {
6784
6785       xf86SetCrtcForModes(pSiS->CRT2pScrn, INTERLACE_HALVE_V);
6786
6787       xf86DrvMsg(pScrn->scrnIndex, X_INFO, modesforstr, 2);
6788
6789       if(pSiS->VBFlags & (CRT2_LCD | CRT2_TV)) {
6790	  SiSPrintModes(pSiS->CRT2pScrn);
6791       } else {
6792	  xf86PrintModes(pSiS->CRT2pScrn);
6793       }
6794
6795       pSiS->CRT1Modes = pScrn->modes;
6796       pSiS->CRT1CurrentMode = pScrn->currentMode;
6797
6798       xf86DrvMsg(pScrn->scrnIndex, X_INFO, "MergedFB: Generating mode list\n");
6799
6800       pScrn->modes = SiSGenerateModeList(pScrn, pSiS->MetaModes,
6801					  pSiS->CRT1Modes, pSiS->CRT2pScrn->modes,
6802					  pSiS->CRT2Position);
6803
6804       if(!pScrn->modes) {
6805
6806	  SISErrorLog(pScrn, "Failed to parse MetaModes or no modes found. %s.\n",
6807			mergeddisstr);
6808	  SiSFreeCRT2Structs(pSiS);
6809	  pScrn->modes = pSiS->CRT1Modes;
6810	  pSiS->CRT1Modes = NULL;
6811	  pSiS->MergedFB = FALSE;
6812
6813       }
6814
6815    }
6816
6817    if(pSiS->MergedFB) {
6818
6819       /* If no virtual dimension was given by the user,
6820	* calculate a sane one now. Adapts pScrn->virtualX,
6821	* pScrn->virtualY and pScrn->displayWidth.
6822	*/
6823       SiSRecalcDefaultVirtualSize(pScrn);
6824
6825       pScrn->modes = pScrn->modes->next;  /* We get the last from GenerateModeList(), skip to first */
6826       pScrn->currentMode = pScrn->modes;
6827
6828       /* Update CurrentLayout */
6829       pSiS->CurrentLayout.mode = pScrn->currentMode;
6830       pSiS->CurrentLayout.displayWidth = pScrn->displayWidth;
6831       pSiS->CurrentLayout.displayHeight = pScrn->virtualY;
6832
6833    }
6834#endif
6835
6836    /* Set display resolution */
6837#ifdef SISMERGED
6838    if(pSiS->MergedFB) {
6839       SiSMergedFBSetDpi(pScrn, pSiS->CRT2pScrn, pSiS->CRT2Position);
6840    } else
6841#endif
6842       xf86SetDpi(pScrn, 0, 0);
6843
6844    /* Load fb module */
6845    switch(pScrn->bitsPerPixel) {
6846      case 8:
6847      case 16:
6848      case 24:
6849      case 32:
6850	if(!xf86LoadSubModule(pScrn, "fb")) {
6851           SISErrorLog(pScrn, "Failed to load fb module");
6852	   goto my_error_1;
6853	}
6854	break;
6855      default:
6856	SISErrorLog(pScrn, "Unsupported framebuffer bpp (%d)\n", pScrn->bitsPerPixel);
6857	goto my_error_1;
6858    }
6859
6860    /* Load XAA/EXA (if needed) */
6861    if(!pSiS->NoAccel) {
6862#ifdef SIS_USE_XAA
6863       if(!pSiS->useEXA) {
6864	  if (!xf86LoadSubModule(pScrn, "xaa")) {
6865	      xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6866			 "Falling back to shadowfb\n");
6867	      pSiS->NoAccel = 1;
6868	      pSiS->ShadowFB = 1;
6869	  }
6870       }
6871#endif
6872#ifdef SIS_USE_EXA
6873       if(pSiS->useEXA) {
6874	  XF86ModReqInfo req;
6875	  int errmaj, errmin;
6876
6877	  memset(&req, 0, sizeof(req));
6878	  req.majorversion = 2;
6879	  req.minorversion = 0;
6880	  if (!LoadSubModule(pScrn->module, "exa", NULL, NULL, NULL, &req,
6881	    &errmaj, &errmin)) {
6882	    LoaderErrorMsg(NULL, "exa", errmaj, errmin);
6883	    goto my_error_1;
6884	  }
6885       }
6886#endif
6887    }
6888
6889    /* Load shadowfb (if needed) */
6890    if(pSiS->ShadowFB) {
6891       if(!xf86LoadSubModule(pScrn, "shadowfb")) {
6892	  SISErrorLog(pScrn, "Could not load shadowfb module\n");
6893	  goto my_error_1;
6894       }
6895    }
6896
6897    /* Load the dri and glx modules if requested. */
6898#ifdef SISDRI
6899    if(pSiS->loadDRI) {
6900       if(!xf86LoaderCheckSymbol("DRIScreenInit")) {
6901	  if(xf86LoadSubModule(pScrn, "dri")) {
6902	     if(!xf86LoaderCheckSymbol("GlxSetVisualConfigs")) {
6903	        if(!xf86LoadSubModule(pScrn, "glx")) {
6904		   SISErrorLog(pScrn, "Failed to load glx module\n");
6905		}
6906	     }
6907	  } else {
6908	     SISErrorLog(pScrn, "Failed to load dri module\n");
6909	  }
6910       }
6911    }
6912#endif
6913
6914    /* Now load and initialize VBE module for VESA mode switching */
6915    pSiS->UseVESA = 0;
6916    if(pSiS->VESA == 1) {
6917       SiS_LoadInitVBE(pScrn);
6918       if(pSiS->pVbe) {
6919	  VbeInfoBlock *vbe;
6920	  if((vbe = VBEGetVBEInfo(pSiS->pVbe))) {
6921	     pSiS->vesamajor = (unsigned)(vbe->VESAVersion >> 8);
6922	     pSiS->vesaminor = vbe->VESAVersion & 0xff;
6923	     SiSBuildVesaModeList(pScrn, pSiS->pVbe, vbe);
6924	     VBEFreeVBEInfo(vbe);
6925	     pSiS->UseVESA = 1;
6926	  } else {
6927	     xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
6928	     	 "Failed to read VBE Info Block\n");
6929	  }
6930       }
6931       if(pSiS->UseVESA == 0) {
6932	  xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
6933	      "VESA mode switching disabled.\n");
6934       }
6935    }
6936
6937    if(pSiS->pVbe) {
6938       vbeFree(pSiS->pVbe);
6939       pSiS->pVbe = NULL;
6940    }
6941
6942#ifdef SISDUALHEAD
6943    xf86SetPrimInitDone(pScrn->entityList[0]);
6944#endif
6945
6946    sisRestoreExtRegisterLock(pSiS,srlockReg,crlockReg);
6947
6948    if(pSiS->pInt) xf86FreeInt10(pSiS->pInt);
6949    pSiS->pInt = NULL;
6950
6951    if(pSiS->VGAEngine == SIS_315_VGA) {
6952       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTXVGAMMA1;
6953    }
6954
6955#ifdef SISDUALHEAD
6956    if(pSiS->DualHeadMode) {
6957	pSiS->SiS_SD_Flags |= SiS_SD_ISDUALHEAD;
6958	if(pSiS->SecondHead) pSiS->SiS_SD_Flags |= SiS_SD_ISDHSECONDHEAD;
6959	else		     pSiS->SiS_SD_Flags &= ~(SiS_SD_SUPPORTXVGAMMA1);
6960#ifdef PANORAMIX
6961	if(!noPanoramiXExtension) {
6962	   pSiS->SiS_SD_Flags |= SiS_SD_ISDHXINERAMA;
6963	   /* pSiS->SiS_SD_Flags &= ~(SiS_SD_SUPPORTXVGAMMA1); */
6964	}
6965#endif
6966    }
6967#endif
6968
6969#ifdef SISMERGED
6970    if(pSiS->MergedFB) pSiS->SiS_SD_Flags |= SiS_SD_ISMERGEDFB;
6971#endif
6972
6973    /* Try to determine if this is a laptop   */
6974    /* (only used for SiSCtrl visualisations) */
6975    pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPLTFLAG;
6976    pSiS->SiS_SD2_Flags &= ~SiS_SD2_ISLAPTOP;
6977    if(pSiS->detectedCRT2Devices & CRT2_LCD) {
6978       if(pSiS->VBFlags2 & (VB2_SISLVDSBRIDGE | VB2_LVDS | VB2_30xBDH)) {
6979	  /* 1. By bridge type: LVDS in 99% of all cases;
6980	   * exclude unusual setups like Barco projectors
6981	   * and parallel flat panels. TODO: Exclude
6982	   * Sony W1, V1.
6983	   */
6984	  if((pSiS->SiS_Pr->SiS_CustomT != CUT_BARCO1366) &&
6985	     (pSiS->SiS_Pr->SiS_CustomT != CUT_BARCO1024) &&
6986	     (pSiS->SiS_Pr->SiS_CustomT != CUT_PANEL848)  &&
6987	     (pSiS->SiS_Pr->SiS_CustomT != CUT_PANEL856)  &&
6988	     (pSiS->SiS_Pr->SiS_CustomT != CUT_AOP8060)   &&
6989	     ( (pSiS->ChipType != SIS_550) ||
6990	       (!pSiS->DSTN && !pSiS->FSTN) ) ) {
6991	     pSiS->SiS_SD2_Flags |= SiS_SD2_ISLAPTOP;
6992	  }
6993       } else if((pSiS->VBFlags2 & (VB2_301 | VB2_301C)) &&
6994                 (pSiS->VBLCDFlags & (VB_LCD_1280x960  |
6995				      VB_LCD_1400x1050 |
6996				      VB_LCD_1024x600  |
6997				      VB_LCD_1280x800  |
6998				      VB_LCD_1280x854))) {
6999	  /* 2. By (odd) LCD resolutions on TMDS bridges
7000	   * (eg Averatec). TODO: Exclude IBM Netvista.
7001	   */
7002	  pSiS->SiS_SD2_Flags |= SiS_SD2_ISLAPTOP;
7003       }
7004    }
7005
7006    if(pSiS->enablesisctrl) pSiS->SiS_SD_Flags |= SiS_SD_ENABLED;
7007
7008    pSiS->currentModeLast = pScrn->currentMode;
7009    pSiS->VBFlagsInit = pSiS->VBFlags;
7010
7011    return TRUE;
7012
7013    /* ---- */
7014
7015my_error_1:
7016    sisRestoreExtRegisterLock(pSiS, srlockReg, crlockReg);
7017my_error_0:
7018#ifdef SISDUALHEAD
7019    if(pSiSEnt) pSiSEnt->ErrorAfterFirst = TRUE;
7020#endif
7021    if(pSiS->pInt) xf86FreeInt10(pSiS->pInt);
7022    pSiS->pInt = NULL;
7023    SISFreeRec(pScrn);
7024    return FALSE;
7025}
7026
7027/*
7028 * Map I/O port area for non-PC platforms
7029 */
7030#ifdef SIS_NEED_MAP_IOP
7031static Bool
7032SISMapIOPMem(ScrnInfoPtr pScrn)
7033{
7034    SISPtr pSiS = SISPTR(pScrn);
7035#ifdef SISDUALHEAD
7036    SISEntPtr pSiSEnt = pSiS->entityPrivate;
7037
7038    if(pSiS->DualHeadMode) {
7039        pSiSEnt->MapCountIOPBase++;
7040        if(!(pSiSEnt->IOPBase)) {
7041	     /* Only map if not mapped previously */
7042#ifndef XSERVER_LIBPCIACCESS
7043	     pSiSEnt->IOPBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
7044			pSiS->PciTag, pSiS->IOPAddress, 128);
7045#else
7046	     {
7047	       void **result = (void **)&pSiSEnt->IOPBase;
7048	       int err = pci_device_map_range(pSiS->PciInfo,
7049					      pSiS->IOPAddress,
7050					      128,
7051					      PCI_DEV_MAP_FLAG_WRITABLE,
7052					      result);
7053
7054	       if (err) {
7055                 xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
7056                             "Unable to map IO aperture. %s (%d)\n",
7057                             strerror (err), err);
7058	       }
7059	     }
7060#endif
7061        }
7062        pSiS->IOPBase = pSiSEnt->IOPBase;
7063    } else
7064#endif
7065#ifndef XSERVER_LIBPCIACCESS
7066	     pSiS->IOPBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
7067					   pSiS->PciTag, pSiS->IOPAddress, 128);
7068#else
7069	     {
7070	       void **result = (void **)&pSiS->IOPBase;
7071	       int err = pci_device_map_range(pSiS->PciInfo,
7072					      pSiS->IOPAddress,
7073					      128,
7074					      PCI_DEV_MAP_FLAG_WRITABLE,
7075					      result);
7076
7077	       if (err) {
7078                 xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
7079                             "Unable to map IO aperture. %s (%d)\n",
7080                             strerror (err), err);
7081	       }
7082	     }
7083#endif
7084    if(pSiS->IOPBase == NULL) {
7085	SISErrorLog(pScrn, "Could not map I/O port area\n");
7086	return FALSE;
7087    }
7088
7089    return TRUE;
7090}
7091
7092static Bool
7093SISUnmapIOPMem(ScrnInfoPtr pScrn)
7094{
7095    SISPtr pSiS = SISPTR(pScrn);
7096#ifdef SISDUALHEAD
7097    SISEntPtr pSiSEnt = pSiS->entityPrivate;;
7098#endif
7099
7100/* In dual head mode, we must not unmap if the other head still
7101 * assumes memory as mapped
7102 */
7103#ifdef SISDUALHEAD
7104    if(pSiS->DualHeadMode) {
7105        if(pSiSEnt->MapCountIOPBase) {
7106	    pSiSEnt->MapCountIOPBase--;
7107	    if((pSiSEnt->MapCountIOPBase == 0) || (pSiSEnt->forceUnmapIOPBase)) {
7108		xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiSEnt->IOPBase, 2048);
7109		pSiSEnt->IOPBase = NULL;
7110		pSiSEnt->MapCountIOPBase = 0;
7111		pSiSEnt->forceUnmapIOPBase = FALSE;
7112	    }
7113	    pSiS->IOPBase = NULL;
7114	}
7115    } else {
7116#endif
7117	xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiS->IOPBase, 2048);
7118	pSiS->IOPBase = NULL;
7119#ifdef SISDUALHEAD
7120    }
7121#endif
7122    return TRUE;
7123}
7124#endif
7125
7126/*
7127 * Map the framebuffer and MMIO memory
7128 */
7129
7130static Bool
7131SISMapMem(ScrnInfoPtr pScrn)
7132{
7133    SISPtr pSiS = SISPTR(pScrn);
7134    int mmioFlags = VIDMEM_MMIO;
7135#ifdef SISDUALHEAD
7136    SISEntPtr pSiSEnt = pSiS->entityPrivate;
7137#endif
7138
7139    /*
7140     * Map IO registers to virtual address space
7141     * (For Alpha, we need to map SPARSE memory, since we need
7142     * byte/short access.)
7143     */
7144#if defined(__alpha__)
7145    mmioFlags |= VIDMEM_SPARSE;
7146#endif
7147
7148#ifdef SISDUALHEAD
7149    if(pSiS->DualHeadMode) {
7150        pSiSEnt->MapCountIOBase++;
7151        if(!(pSiSEnt->IOBase)) {
7152	     /* Only map if not mapped previously */
7153#ifndef XSERVER_LIBPCIACCESS
7154    	     pSiSEnt->IOBase = xf86MapPciMem(pScrn->scrnIndex, mmioFlags,
7155                         pSiS->PciTag, pSiS->IOAddress, (pSiS->mmioSize * 1024));
7156#else
7157	     void **result = (void **)&pSiSEnt->IOBase;
7158	     int err = pci_device_map_range(pSiS->PciInfo,
7159 	                                    pSiS->IOAddress,
7160	                                    (pSiS->mmioSize * 1024),
7161                                            PCI_DEV_MAP_FLAG_WRITABLE,
7162                                            result);
7163
7164             if (err) {
7165                 xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
7166                             "Unable to map IO aperture. %s (%d)\n",
7167                             strerror (err), err);
7168	     }
7169#endif
7170        }
7171        pSiS->IOBase = pSiSEnt->IOBase;
7172    } else
7173#endif
7174#ifndef XSERVER_LIBPCIACCESS
7175    	pSiS->IOBase = xf86MapPciMem(pScrn->scrnIndex, mmioFlags,
7176                        pSiS->PciTag, pSiS->IOAddress, (pSiS->mmioSize * 1024));
7177#else
7178       {
7179	     void **result = (void **)&pSiS->IOBase;
7180	     int err = pci_device_map_range(pSiS->PciInfo,
7181 	                                    pSiS->IOAddress,
7182	                                    (pSiS->mmioSize * 1024),
7183                                            PCI_DEV_MAP_FLAG_WRITABLE,
7184                                            result);
7185
7186             if (err) {
7187                 xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
7188                             "Unable to map IO aperture. %s (%d)\n",
7189                             strerror (err), err);
7190	     }
7191       }
7192#endif
7193
7194    if(pSiS->IOBase == NULL) {
7195    	SISErrorLog(pScrn, "Could not map MMIO area\n");
7196        return FALSE;
7197    }
7198
7199#ifdef __alpha__
7200    /*
7201     * for Alpha, we need to map DENSE memory as well, for
7202     * setting CPUToScreenColorExpandBase.
7203     */
7204#ifdef SISDUALHEAD
7205    if(pSiS->DualHeadMode) {
7206        pSiSEnt->MapCountIOBaseDense++;
7207        if(!(pSiSEnt->IOBaseDense)) {
7208	     /* Only map if not mapped previously */
7209#ifndef XSERVER_LIBPCIACCESS
7210	     pSiSEnt->IOBaseDense = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
7211                    pSiS->PciTag, pSiS->IOAddress, (pSiS->mmioSize * 1024));
7212#else
7213	     void **result = (void **)&pSiSEnt->IOBaseDense;
7214	     int err = pci_device_map_range(pSiS->PciInfo,
7215 	                                    pSiS->IOAddress,
7216	                                    (pSiS->mmioSize * 1024),
7217                                            PCI_DEV_MAP_FLAG_WRITABLE,
7218                                            result);
7219
7220             if (err) {
7221                 xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
7222                             "Unable to map IO dense aperture. %s (%d)\n",
7223                             strerror (err), err);
7224	     }
7225#endif /* XSERVER_LIBPCIACCESS */
7226	}
7227	pSiS->IOBaseDense = pSiSEnt->IOBaseDense;
7228    } else {
7229#endif /* SISDUALHEAD */
7230#ifndef XSERVER_LIBPCIACCESS
7231	     pSiS->IOBaseDense = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
7232                    pSiS->PciTag, pSiS->IOAddress, (pSiS->mmioSize * 1024));
7233#else
7234	     void **result = (void **)&pSiS->IOBaseDense;
7235	     int err = pci_device_map_range(pSiS->PciInfo,
7236 	                                    pSiS->IOAddress,
7237	                                    (pSiS->mmioSize * 1024),
7238                                            PCI_DEV_MAP_FLAG_WRITABLE,
7239                                            result);
7240
7241             if (err) {
7242                 xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
7243                             "Unable to map IO dense aperture. %s (%d)\n",
7244                             strerror (err), err);
7245	     }
7246#endif /* XSERVER_LIBPCIACCESS */
7247#ifdef SISDUALHEAD
7248    }
7249#endif
7250    if(pSiS->IOBaseDense == NULL) {
7251       SISErrorLog(pScrn, "Could not map MMIO dense area\n");
7252       return FALSE;
7253    }
7254#endif /* __alpha__ */
7255
7256#ifdef SISDUALHEAD
7257    if(pSiS->DualHeadMode) {
7258	pSiSEnt->MapCountFbBase++;
7259	if(!(pSiSEnt->FbBase)) {
7260	     /* Only map if not mapped previously */
7261#ifndef XSERVER_LIBPCIACCESS
7262	     pSiSEnt->FbBase = pSiSEnt->RealFbBase =
7263			xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
7264			 pSiS->PciTag, (ULong)pSiS->realFbAddress,
7265			 pSiS->FbMapSize);
7266#else
7267         int err = pci_device_map_range(pSiS->PciInfo,
7268                                   (ULong)pSiS->realFbAddress,
7269                                   pSiS->FbMapSize,
7270                                   PCI_DEV_MAP_FLAG_WRITABLE |
7271                                   PCI_DEV_MAP_FLAG_WRITE_COMBINE,
7272                                   (void *)&pSiSEnt->FbBase);
7273	if (err) {
7274            xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
7275                        "Unable to map FB aperture. %s (%d)\n",
7276                        strerror (err), err);
7277            return FALSE;
7278        }
7279	pSiSEnt->RealFbBase = pSiSEnt->FbBase;
7280#endif
7281	}
7282	pSiS->FbBase = pSiS->RealFbBase = pSiSEnt->FbBase;
7283	/* Adapt FbBase (for DHM and SiS76x UMA skipping; dhmOffset is 0 otherwise) */
7284	pSiS->FbBase += pSiS->dhmOffset;
7285    } else {
7286#endif
7287
7288#ifndef XSERVER_LIBPCIACCESS
7289      pSiS->FbBase = pSiS->RealFbBase =
7290			xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
7291			 pSiS->PciTag, (ULong)pSiS->realFbAddress,
7292			 pSiS->FbMapSize);
7293#else
7294         int err = pci_device_map_range(pSiS->PciInfo,
7295                                   (ULong)pSiS->realFbAddress,
7296                                   pSiS->FbMapSize,
7297                                   PCI_DEV_MAP_FLAG_WRITABLE |
7298                                   PCI_DEV_MAP_FLAG_WRITE_COMBINE,
7299                                   (void *)&pSiS->FbBase);
7300	if (err) {
7301            xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
7302                        "Unable to map FB aperture. %s (%d)\n",
7303                        strerror (err), err);
7304            return FALSE;
7305        }
7306	pSiS->RealFbBase = pSiS->FbBase;
7307#endif
7308	pSiS->FbBase += pSiS->dhmOffset;
7309
7310#ifdef SISDUALHEAD
7311    }
7312#endif
7313
7314    if(pSiS->FbBase == NULL) {
7315       SISErrorLog(pScrn, "Could not map framebuffer area\n");
7316       return FALSE;
7317    }
7318
7319#ifdef TWDEBUG
7320    xf86DrvMsg(0, 0, "Framebuffer mapped to %p\n", pSiS->FbBase);
7321#endif
7322
7323    return TRUE;
7324}
7325
7326
7327/*
7328 * Unmap the framebuffer and MMIO memory.
7329 */
7330
7331static Bool
7332SISUnmapMem(ScrnInfoPtr pScrn)
7333{
7334    SISPtr pSiS = SISPTR(pScrn);
7335#ifdef SISDUALHEAD
7336    SISEntPtr pSiSEnt = pSiS->entityPrivate;
7337#endif
7338
7339/* In dual head mode, we must not unmap if the other head still
7340 * assumes memory as mapped
7341 */
7342#ifdef SISDUALHEAD
7343    if(pSiS->DualHeadMode) {
7344        if(pSiSEnt->MapCountIOBase) {
7345	    pSiSEnt->MapCountIOBase--;
7346	    if((pSiSEnt->MapCountIOBase == 0) || (pSiSEnt->forceUnmapIOBase)) {
7347		xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiSEnt->IOBase, (pSiS->mmioSize * 1024));
7348		pSiSEnt->IOBase = NULL;
7349		pSiSEnt->MapCountIOBase = 0;
7350		pSiSEnt->forceUnmapIOBase = FALSE;
7351	    }
7352	    pSiS->IOBase = NULL;
7353	}
7354#ifdef __alpha__
7355	if(pSiSEnt->MapCountIOBaseDense) {
7356	    pSiSEnt->MapCountIOBaseDense--;
7357	    if((pSiSEnt->MapCountIOBaseDense == 0) || (pSiSEnt->forceUnmapIOBaseDense)) {
7358		xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiSEnt->IOBaseDense, (pSiS->mmioSize * 1024));
7359		pSiSEnt->IOBaseDense = NULL;
7360		pSiSEnt->MapCountIOBaseDense = 0;
7361		pSiSEnt->forceUnmapIOBaseDense = FALSE;
7362	    }
7363	    pSiS->IOBaseDense = NULL;
7364	}
7365#endif /* __alpha__ */
7366	if(pSiSEnt->MapCountFbBase) {
7367	    pSiSEnt->MapCountFbBase--;
7368	    if((pSiSEnt->MapCountFbBase == 0) || (pSiSEnt->forceUnmapFbBase)) {
7369		xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiSEnt->RealFbBase, pSiS->FbMapSize);
7370		pSiSEnt->FbBase = pSiSEnt->RealFbBase = NULL;
7371		pSiSEnt->MapCountFbBase = 0;
7372		pSiSEnt->forceUnmapFbBase = FALSE;
7373
7374	    }
7375	    pSiS->FbBase = pSiS->RealFbBase = NULL;
7376	}
7377    } else {
7378#endif
7379	xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiS->IOBase, (pSiS->mmioSize * 1024));
7380	pSiS->IOBase = NULL;
7381#ifdef __alpha__
7382	xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiS->IOBaseDense, (pSiS->mmioSize * 1024));
7383	pSiS->IOBaseDense = NULL;
7384#endif
7385	xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiS->RealFbBase, pSiS->FbMapSize);
7386	pSiS->FbBase = pSiS->RealFbBase = NULL;
7387#ifdef SISDUALHEAD
7388    }
7389#endif
7390    return TRUE;
7391}
7392
7393/*
7394 * This function saves the video state.
7395 */
7396static void
7397SISSave(ScrnInfoPtr pScrn)
7398{
7399    SISPtr pSiS = SISPTR(pScrn);
7400    SISRegPtr sisReg;
7401    int flags;
7402
7403#ifdef SISDUALHEAD
7404    /* We always save master & slave */
7405    if(pSiS->DualHeadMode && pSiS->SecondHead) return;
7406#endif
7407
7408    sisReg = &pSiS->SavedReg;
7409
7410    if( ((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) &&
7411        ((pSiS->VBFlags2 & VB2_VIDEOBRIDGE) && (SiSBridgeIsInSlaveMode(pScrn))) ) {
7412       SiSVGASave(pScrn, sisReg, SISVGA_SR_CMAP | SISVGA_SR_MODE);
7413#ifdef SIS_PC_PLATFORM
7414       if(pSiS->VGAMemBase) {
7415          SiSRegInit(pSiS->SiS_Pr, pSiS->RelIO+0x30);
7416          SiSSetLVDSetc(pSiS->SiS_Pr);
7417          SiS_GetVBType(pSiS->SiS_Pr);
7418          SiS_DisableBridge(pSiS->SiS_Pr);
7419          SiSVGASave(pScrn, sisReg, SISVGA_SR_FONTS);
7420          SiS_EnableBridge(pSiS->SiS_Pr);
7421       }
7422#endif
7423    } else {
7424       flags = SISVGA_SR_CMAP | SISVGA_SR_MODE;
7425#ifdef SIS_PC_PLATFORM
7426       if(pSiS->VGAMemBase) flags |= SISVGA_SR_FONTS;
7427#endif
7428       SiSVGASave(pScrn, sisReg, flags);
7429    }
7430
7431    sisSaveUnlockExtRegisterLock(pSiS, &sisReg->sisRegs3C4[0x05], &sisReg->sisRegs3D4[0x80]);
7432
7433    (*pSiS->SiSSave)(pScrn, sisReg);
7434
7435    if(pSiS->UseVESA) SISVESASaveRestore(pScrn, MODE_SAVE);
7436
7437    /* "Save" these again as they may have been changed prior to SISSave() call */
7438    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
7439       sisReg->sisRegs3C4[0x1f] = pSiS->oldSR1F;
7440       sisReg->sisRegs3D4[0x17] = pSiS->oldCR17;
7441       sisReg->sisRegs3D4[0x32] = pSiS->oldCR32;
7442       sisReg->sisRegs3D4[0x36] = pSiS->oldCR36;
7443       sisReg->sisRegs3D4[0x37] = pSiS->oldCR37;
7444       if(pSiS->VGAEngine == SIS_315_VGA) {
7445	  sisReg->sisRegs3D4[pSiS->myCR63] = pSiS->oldCR63;
7446       }
7447    }
7448}
7449
7450/* VESASaveRestore taken from vesa driver */
7451static void
7452SISVESASaveRestore(ScrnInfoPtr pScrn, vbeSaveRestoreFunction function)
7453{
7454    SISPtr pSiS = SISPTR(pScrn);
7455
7456    /* Query amount of memory to save state */
7457    if((function == MODE_QUERY) ||
7458       (function == MODE_SAVE && pSiS->state == NULL)) {
7459
7460       /* Make sure we save at least this information in case of failure */
7461       (void)VBEGetVBEMode(pSiS->pVbe, &pSiS->stateMode);
7462       SiSVGASaveFonts(pScrn);
7463
7464       if(pSiS->vesamajor > 1) {
7465	  if(!VBESaveRestore(pSiS->pVbe, function, (pointer)&pSiS->state,
7466				&pSiS->stateSize, &pSiS->statePage)) {
7467	     return;
7468	  }
7469       }
7470    }
7471
7472    /* Save/Restore Super VGA state */
7473    if(function != MODE_QUERY) {
7474
7475       if(pSiS->vesamajor > 1) {
7476	  if(function == MODE_RESTORE) {
7477	     memcpy(pSiS->state, pSiS->pstate, pSiS->stateSize);
7478	  }
7479
7480	  if(VBESaveRestore(pSiS->pVbe,function,(pointer)&pSiS->state,
7481			    &pSiS->stateSize,&pSiS->statePage) &&
7482	     (function == MODE_SAVE)) {
7483	     /* don't rely on the memory not being touched */
7484	     if(!pSiS->pstate) {
7485		pSiS->pstate = malloc(pSiS->stateSize);
7486	     }
7487	     memcpy(pSiS->pstate, pSiS->state, pSiS->stateSize);
7488	  }
7489       }
7490
7491       if(function == MODE_RESTORE) {
7492	  VBESetVBEMode(pSiS->pVbe, pSiS->stateMode, NULL);
7493	  SiSVGARestoreFonts(pScrn);
7494       }
7495
7496    }
7497}
7498
7499/*
7500 * Initialise a new mode.  This is currently done using the
7501 * "initialise struct, restore/write struct to HW" model for
7502 * the old chipsets (5597/530/6326). For newer chipsets,
7503 * we use our own mode switching code.
7504 */
7505
7506static Bool
7507SISModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
7508{
7509    SISPtr pSiS = SISPTR(pScrn);
7510    SISRegPtr sisReg;
7511#ifdef SISDUALHEAD
7512    SISEntPtr pSiSEnt = NULL;
7513#endif
7514
7515    andSISIDXREG(SISCR,0x11,0x7f);	/* Unlock CRTC registers */
7516
7517    SISModifyModeInfo(mode);		/* Quick check of the mode parameters */
7518
7519    if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
7520       SiSRegInit(pSiS->SiS_Pr, pSiS->RelIO+0x30);
7521    }
7522
7523    if(pSiS->UseVESA) {  /* With VESA: */
7524
7525#ifdef SISDUALHEAD
7526       /* No dual head mode when using VESA */
7527       if(pSiS->SecondHead) return TRUE;
7528#endif
7529
7530       pScrn->vtSema = TRUE;
7531
7532       /*
7533	* This order is required:
7534	* The video bridge needs to be adjusted before the
7535	* BIOS is run as the BIOS sets up CRT2 according to
7536	* these register settings.
7537	* After the BIOS is run, the bridges and turboqueue
7538	* registers need to be readjusted as the BIOS may
7539	* very probably have messed them up.
7540	*/
7541       if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
7542	  SiSPreSetMode(pScrn, mode, SIS_MODE_SIMU);
7543       }
7544       if(!SiSSetVESAMode(pScrn, mode)) {
7545	  SISErrorLog(pScrn, "SiSSetVESAMode() failed\n");
7546	  return FALSE;
7547       }
7548       sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
7549       if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
7550	  SiSPreSetMode(pScrn, mode, SIS_MODE_SIMU);
7551	  SiSPostSetMode(pScrn, &pSiS->ModeReg);
7552       }
7553#ifdef TWDEBUG
7554       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
7555		   "REAL REGISTER CONTENTS AFTER SETMODE:\n");
7556#endif
7557       if(!(*pSiS->ModeInit)(pScrn, mode)) {
7558	  SISErrorLog(pScrn, "ModeInit() failed\n");
7559	  return FALSE;
7560       }
7561
7562       SiSVGAProtect(pScrn, TRUE);
7563       (*pSiS->SiSRestore)(pScrn, &pSiS->ModeReg);
7564       SiSVGAProtect(pScrn, FALSE);
7565
7566    } else { /* Without VESA: */
7567
7568#ifdef SISDUALHEAD
7569       if(pSiS->DualHeadMode) {
7570
7571	  if(!(*pSiS->ModeInit)(pScrn, mode)) {
7572	     SISErrorLog(pScrn, "ModeInit() failed\n");
7573	     return FALSE;
7574	  }
7575
7576	  pScrn->vtSema = TRUE;
7577
7578	  pSiSEnt = pSiS->entityPrivate;
7579
7580	  if(!(pSiS->SecondHead)) {
7581	     /* Head 1 (master) is always CRT2 */
7582	     SiSPreSetMode(pScrn, mode, SIS_MODE_CRT2);
7583	     if(!SiSBIOSSetModeCRT2(pSiS->SiS_Pr, pScrn, mode, pSiS->IsCustom)) {
7584		SISErrorLog(pScrn, "SiSBIOSSetModeCRT2() failed\n");
7585		return FALSE;
7586	     }
7587	     SiSPostSetMode(pScrn, &pSiS->ModeReg);
7588	     if(pSiSEnt->pScrn_2) {
7589		SISAdjustFrame(ADJUST_FRAME_ARGS(pSiSEnt->pScrn_2,
7590			       pSiSEnt->pScrn_2->frameX0,
7591						 pSiSEnt->pScrn_2->frameY0));
7592	     }
7593	  } else {
7594	     /* Head 2 (slave) is always CRT1 */
7595	     SiSPreSetMode(pScrn, mode, SIS_MODE_CRT1);
7596	     if(!SiSBIOSSetModeCRT1(pSiS->SiS_Pr, pScrn, mode, pSiS->IsCustom)) {
7597		SISErrorLog(pScrn, "SiSBIOSSetModeCRT1() failed\n");
7598		return FALSE;
7599	     }
7600	     SiSPostSetMode(pScrn, &pSiS->ModeReg);
7601	     if(pSiSEnt->pScrn_1) {
7602		SISAdjustFrame(ADJUST_FRAME_ARGS(pSiSEnt->pScrn_1,
7603			       pSiSEnt->pScrn_1->frameX0,
7604			       pSiSEnt->pScrn_1->frameY0));
7605	     }
7606	  }
7607
7608       } else {
7609#endif
7610
7611	  if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
7612
7613	     if(!(*pSiS->ModeInit)(pScrn, mode)) {
7614		SISErrorLog(pScrn, "ModeInit() failed\n");
7615	        return FALSE;
7616	     }
7617
7618	     pScrn->vtSema = TRUE;
7619
7620#ifdef SISMERGED
7621	     if(pSiS->MergedFB) {
7622
7623		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Setting MergedFB mode %dx%d\n",
7624				mode->HDisplay, mode->VDisplay);
7625
7626		SiSPreSetMode(pScrn, mode, SIS_MODE_CRT1);
7627
7628		if(!SiSBIOSSetModeCRT1(pSiS->SiS_Pr, pScrn,
7629		                       ((SiSMergedDisplayModePtr)mode->Private)->CRT1,
7630				       pSiS->IsCustom)) {
7631		   SISErrorLog(pScrn, "SiSBIOSSetModeCRT1() failed\n");
7632		   return FALSE;
7633		}
7634
7635		SiSPreSetMode(pScrn, mode, SIS_MODE_CRT2);
7636
7637		if(!SiSBIOSSetModeCRT2(pSiS->SiS_Pr, pScrn,
7638		                       ((SiSMergedDisplayModePtr)mode->Private)->CRT2,
7639				       pSiS->IsCustom)) {
7640		   SISErrorLog(pScrn, "SiSBIOSSetModeCRT2() failed\n");
7641		   return FALSE;
7642		}
7643
7644	     } else {
7645#endif
7646
7647		if((pSiS->VBFlags & CRT1_LCDA) || (!(mode->type & M_T_DEFAULT))) {
7648
7649		   SiSPreSetMode(pScrn, mode, SIS_MODE_CRT1);
7650
7651		   if(!SiSBIOSSetModeCRT1(pSiS->SiS_Pr, pScrn,
7652				mode, pSiS->IsCustom)) {
7653		      SISErrorLog(pScrn, "SiSBIOSSetModeCRT1() failed\n");
7654		      return FALSE;
7655		   }
7656
7657		   SiSPreSetMode(pScrn, mode, SIS_MODE_CRT2);
7658
7659		   if(!SiSBIOSSetModeCRT2(pSiS->SiS_Pr, pScrn,
7660				mode, pSiS->IsCustom)) {
7661		      SISErrorLog(pScrn, "SiSBIOSSetModeCRT2() failed\n");
7662		      return FALSE;
7663		   }
7664
7665		} else {
7666
7667		   SiSPreSetMode(pScrn, mode, SIS_MODE_SIMU);
7668
7669		   if(!SiSBIOSSetMode(pSiS->SiS_Pr, pScrn,
7670				mode, pSiS->IsCustom)) {
7671		      SISErrorLog(pScrn, "SiSBIOSSetMode() failed\n");
7672		      return FALSE;
7673		   }
7674
7675		}
7676
7677#ifdef SISMERGED
7678	     }
7679#endif
7680
7681	     SiSPostSetMode(pScrn, &pSiS->ModeReg);
7682
7683#ifdef TWDEBUG
7684	     xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VBFlags %lx\n", pSiS->VBFlags);
7685	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
7686			"REAL REGISTER CONTENTS AFTER SETMODE:\n");
7687             (*pSiS->ModeInit)(pScrn, mode);
7688#endif
7689
7690	  } else {
7691
7692	     /* For other chipsets, use the old method */
7693
7694	     /* Prepare the register contents */
7695	     if(!(*pSiS->ModeInit)(pScrn, mode)) {
7696	        SISErrorLog(pScrn, "ModeInit() failed\n");
7697	        return FALSE;
7698	     }
7699
7700	     pScrn->vtSema = TRUE;
7701
7702	     /* Program the registers */
7703	     SiSVGAProtect(pScrn, TRUE);
7704	     sisReg = &pSiS->ModeReg;
7705
7706	     sisReg->sisRegsATTR[0x10] = 0x01;
7707	     if(pScrn->bitsPerPixel > 8) {
7708		sisReg->sisRegsGR[0x05] = 0x00;
7709	     }
7710
7711	     SiSVGARestore(pScrn, sisReg, SISVGA_SR_MODE);
7712
7713	     (*pSiS->SiSRestore)(pScrn, sisReg);
7714
7715	     if((pSiS->Chipset == PCI_CHIP_SIS6326) && (pSiS->SiS6326Flags & SIS6326_HASTV)) {
7716	        SiS6326PostSetMode(pScrn, &pSiS->ModeReg);
7717	     }
7718
7719#ifdef TWDEBUG
7720	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
7721			"REAL REGISTER CONTENTS AFTER SETMODE:\n");
7722	     (*pSiS->ModeInit)(pScrn, mode);
7723#endif
7724
7725	     SiSVGAProtect(pScrn, FALSE);
7726
7727	  }
7728
7729#ifdef SISDUALHEAD
7730       }
7731#endif
7732    }
7733
7734    /* Update Currentlayout */
7735    pSiS->CurrentLayout.mode = pSiS->currentModeLast = mode;
7736
7737    return TRUE;
7738}
7739
7740static Bool
7741SiSSetVESAMode(ScrnInfoPtr pScrn, DisplayModePtr pMode)
7742{
7743    SISPtr pSiS;
7744    int mode;
7745
7746    pSiS = SISPTR(pScrn);
7747
7748    if(!(mode = SiSCalcVESAModeIndex(pScrn, pMode))) return FALSE;
7749
7750    mode |= (1 << 15);	/* Don't clear framebuffer */
7751    mode |= (1 << 14); 	/* Use linear adressing */
7752
7753    if(VBESetVBEMode(pSiS->pVbe, mode, NULL) == FALSE) {
7754       SISErrorLog(pScrn, "Setting VESA mode 0x%x failed\n",
7755	             	mode & 0x0fff);
7756       return (FALSE);
7757    }
7758
7759    if(pMode->HDisplay != pScrn->virtualX) {
7760       VBESetLogicalScanline(pSiS->pVbe, pScrn->virtualX);
7761    }
7762
7763    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
7764    	"Setting VESA mode 0x%x succeeded\n",
7765	mode & 0x0fff);
7766
7767    return (TRUE);
7768}
7769
7770static void
7771SISSpecialRestore(ScrnInfoPtr pScrn)
7772{
7773    SISPtr    pSiS = SISPTR(pScrn);
7774    SISRegPtr sisReg = &pSiS->SavedReg;
7775    UChar temp;
7776    int i;
7777
7778    /* 1.11.04 and later for 651 and 301B(DH) do strange register
7779     * fiddling after the usual mode change. This happens
7780     * depending on the result of a call of int 2f (with
7781     * ax=0x1680) and if modeno <= 0x13. I have no idea if
7782     * that is specific for the 651 or that very machine.
7783     * So this perhaps requires some more checks in the beginning
7784     * (although it should not do any harm on other chipsets/bridges
7785     * etc.) However, even if I call the VBE to restore mode 0x03,
7786     * these registers don't get restored correctly, possibly
7787     * because that int-2f-call for some reason results non-zero. So
7788     * what I do here is to restore these few registers
7789     * manually.
7790     */
7791
7792    if(!(pSiS->ChipFlags & SiSCF_Is65x)) return;
7793    inSISIDXREG(SISCR, 0x34, temp);
7794    temp &= 0x7f;
7795    if(temp > 0x13) return;
7796
7797#ifdef UNLOCK_ALWAYS
7798    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
7799#endif
7800
7801    SiS_UnLockCRT2(pSiS->SiS_Pr);
7802
7803    outSISIDXREG(SISCAP, 0x3f, sisReg->sisCapt[0x3f]);
7804    outSISIDXREG(SISCAP, 0x00, sisReg->sisCapt[0x00]);
7805    for(i = 0; i < 0x4f; i++) {
7806       outSISIDXREG(SISCAP, i, sisReg->sisCapt[i]);
7807    }
7808    outSISIDXREG(SISVID, 0x32, (sisReg->sisVid[0x32] & ~0x05));
7809    outSISIDXREG(SISVID, 0x30, sisReg->sisVid[0x30]);
7810    outSISIDXREG(SISVID, 0x32, ((sisReg->sisVid[0x32] & ~0x04) | 0x01));
7811    outSISIDXREG(SISVID, 0x30, sisReg->sisVid[0x30]);
7812
7813    if(!(pSiS->ChipFlags & SiSCF_Is651)) return;
7814    if(!(pSiS->VBFlags2 & VB2_SISBRIDGE)) return;
7815
7816    inSISIDXREG(SISCR, 0x30, temp);
7817    if(temp & 0x40) {
7818       UChar myregs[] = {
7819       		0x2f, 0x08, 0x09, 0x03, 0x0a, 0x0c,
7820		0x0b, 0x0d, 0x0e, 0x12, 0x0f, 0x10,
7821		0x11, 0x04, 0x05, 0x06, 0x07, 0x00,
7822		0x2e
7823       };
7824       for(i = 0; i <= 18; i++) {
7825          outSISIDXREG(SISPART1, myregs[i], sisReg->VBPart1[myregs[i]]);
7826       }
7827    } else if((temp & 0x20) || (temp & 0x9c)) {
7828       UChar myregs[] = {
7829       		0x04, 0x05, 0x06, 0x07, 0x00, 0x2e
7830       };
7831       for(i = 0; i <= 5; i++) {
7832          outSISIDXREG(SISPART1, myregs[i], sisReg->VBPart1[myregs[i]]);
7833       }
7834    }
7835}
7836
7837/* Fix SR11 for 661 and later */
7838static void
7839SiSFixupSR11(ScrnInfoPtr pScrn)
7840{
7841    SISPtr pSiS = SISPTR(pScrn);
7842    CARD8  tmpreg;
7843
7844#ifdef UNLOCK_ALWAYS
7845    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
7846#endif
7847
7848    if(pSiS->ChipType >= SIS_661) {
7849       inSISIDXREG(SISSR,0x11,tmpreg);
7850       if(tmpreg & 0x20) {
7851          inSISIDXREG(SISSR,0x3e,tmpreg);
7852	  tmpreg = (tmpreg + 1) & 0xff;
7853	  outSISIDXREG(SISSR,0x3e,tmpreg);
7854       }
7855
7856       inSISIDXREG(SISSR,0x11,tmpreg);
7857       if(tmpreg & 0xf0) {
7858          andSISIDXREG(SISSR,0x11,0x0f);
7859       }
7860    }
7861}
7862
7863/* Subroutine for restoring sisfb's TV parameters (used by SiSRestore()) */
7864
7865static void
7866SiSRestore_SiSFB_TVParms(ScrnInfoPtr pScrn)
7867{
7868    SISPtr  pSiS = SISPTR(pScrn);
7869    int     fd;
7870    CARD32  parm;
7871
7872    if(!pSiS->sisfbfound) return;
7873    if(!pSiS->sisfb_tvposvalid) return;
7874    if(!(pSiS->sisfbdevname[0])) return;
7875
7876    if((fd = open(pSiS->sisfbdevname, O_RDONLY)) != -1) {
7877       parm = (CARD32)((pSiS->sisfb_tvxpos << 16) | (pSiS->sisfb_tvypos & 0xffff));
7878       ioctl(fd, SISFB_SET_TVPOSOFFSET, &parm);
7879       close(fd);
7880    }
7881}
7882
7883/*
7884 * Restore the initial mode. To be used internally only!
7885 */
7886static void
7887SISRestore(ScrnInfoPtr pScrn)
7888{
7889    SISPtr    pSiS = SISPTR(pScrn);
7890    SISRegPtr sisReg = &pSiS->SavedReg;
7891    Bool      doit = FALSE, doitlater = FALSE;
7892    Bool      vesasuccess = FALSE;
7893    int	      flags;
7894
7895    /* WARNING: Don't ever touch this. It now seems to work on
7896     * all chipset/bridge combinations - but finding out the
7897     * correct combination was pure hell.
7898     */
7899
7900    /* Wait for the accelerators */
7901    (*pSiS->SyncAccel)(pScrn);
7902
7903    /* Set up restore flags */
7904    flags = SISVGA_SR_MODE | SISVGA_SR_CMAP;
7905#ifdef SIS_PC_PLATFORM
7906    /* We now restore ALL to overcome the vga=extended problem */
7907    if(pSiS->VGAMemBase) flags |= SISVGA_SR_FONTS;
7908#endif
7909
7910    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
7911
7912#ifdef SISDUALHEAD
7913       /* We always restore master AND slave */
7914       if(pSiS->DualHeadMode && pSiS->SecondHead) return;
7915#endif
7916
7917#ifdef UNLOCK_ALWAYS
7918       sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
7919#endif
7920
7921       /* We must not disable the sequencer if the bridge is in SlaveMode! */
7922       if(!(SiSBridgeIsInSlaveMode(pScrn))) {
7923	  SiSVGAProtect(pScrn, TRUE);
7924       }
7925
7926       /* First, restore CRT1 on/off and VB connection registers */
7927       outSISIDXREG(SISCR, 0x32, pSiS->oldCR32);
7928       if(!(pSiS->oldCR17 & 0x80)) {			/* CRT1 was off */
7929	  if(!(SiSBridgeIsInSlaveMode(pScrn))) {        /* Bridge is NOT in SlaveMode now -> do it */
7930	     doit = TRUE;
7931	  } else {
7932	     doitlater = TRUE;
7933	  }
7934       } else {						/* CRT1 was on -> do it now */
7935	  doit = TRUE;
7936       }
7937
7938       if(doit) {
7939	  outSISIDXREG(SISCR, 0x17, pSiS->oldCR17);
7940       }
7941       if(pSiS->VGAEngine == SIS_315_VGA) {
7942	  outSISIDXREG(SISCR, pSiS->myCR63, pSiS->oldCR63);
7943       }
7944
7945       outSISIDXREG(SISSR, 0x1f, pSiS->oldSR1F);
7946
7947       /* For 30xB/LV, restoring the registers does not
7948	* work. We "manually" set the old mode, instead.
7949	* The same applies for SiS730 machines with LVDS.
7950	* Finally, this behavior can be forced by setting
7951	* the option RestoreBySetMode.
7952	*/
7953	if( ( (pSiS->restorebyset) ||
7954	      (pSiS->VBFlags2 & VB2_30xBLV) ||
7955	      ((pSiS->ChipType == SIS_730) && (pSiS->VBFlags2 & VB2_LVDS)) )     &&
7956	    (pSiS->OldMode) ) {
7957
7958	   Bool changedmode = FALSE;
7959
7960	   xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
7961	         "Restoring by setting old mode 0x%02x\n", pSiS->OldMode);
7962
7963	   if(((pSiS->OldMode <= 0x13) || (!pSiS->sisfbfound)) && (pSiS->pVbe)) {
7964	      int vmode = SiSTranslateToVESA(pScrn, pSiS->OldMode);
7965	      if(vmode > 0) {
7966		 if(vmode > 0x13) vmode |= ((1 << 15) | (1 << 14));
7967		 if(VBESetVBEMode(pSiS->pVbe, vmode, NULL) == TRUE) {
7968		    SISSpecialRestore(pScrn);
7969		    SiS_GetSetModeID(pScrn,pSiS->OldMode);
7970		    vesasuccess = TRUE;
7971		 } else {
7972		    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
7973			"VBE failed to restore mode 0x%x\n", pSiS->OldMode);
7974		 }
7975	      } else {
7976		 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
7977		 	"Can't identify VESA mode number for mode 0x%x\n", pSiS->OldMode);
7978	      }
7979	   }
7980
7981	   if(vesasuccess == FALSE) {
7982
7983	      int backupscaler = pSiS->SiS_Pr->UsePanelScaler;
7984	      int backupcenter = pSiS->SiS_Pr->CenterScreen;
7985	      ULong backupspecialtiming = pSiS->SiS_Pr->SiS_CustomT;
7986	      int mymode = pSiS->OldMode;
7987
7988	      if((pSiS->VGAEngine == SIS_315_VGA)			&&
7989	         ((pSiS->ROM661New) || (pSiS->ChipFlags & SiSCF_IsXGI)) &&
7990		 (!pSiS->sisfbfound)) {
7991	         /* New SiS BIOS or XGI BIOS has set mode, therefore eventually translate number */
7992	         mymode = SiSTranslateToOldMode(mymode);
7993	      }
7994
7995 	      if((pSiS->VBFlags2 & VB2_30xBLV)) {
7996	        /* !!! REQUIRED for 630+301B-DH, otherwise the text modes
7997	         *     will not be restored correctly !!!
7998	         * !!! Do this ONLY for LCD; VGA2 will not be restored
7999	         *     correctly otherwise.
8000	         */
8001	         UChar temp;
8002	         inSISIDXREG(SISCR, 0x30, temp);
8003	         if(temp & 0x20) {
8004	            if(mymode == 0x03) {
8005		       mymode = 0x13;
8006		       changedmode = TRUE;
8007	            }
8008	         }
8009	      }
8010
8011	      pSiS->SiS_Pr->UseCustomMode = FALSE;
8012	      pSiS->SiS_Pr->CRT1UsesCustomMode = FALSE;
8013	      pSiS->SiS_Pr->CenterScreen = 0;
8014	      if(pSiS->sisfbfound) {
8015		 pSiS->SiS_Pr->UsePanelScaler = pSiS->sisfbscalelcd;
8016		 pSiS->SiS_Pr->SiS_CustomT = pSiS->sisfbspecialtiming;
8017	      } else {
8018		 pSiS->SiS_Pr->UsePanelScaler = -1;
8019		 /* Leave CustomT as it is */
8020	      }
8021	      SiS_SetEnableDstn(pSiS->SiS_Pr, FALSE);
8022	      SiS_SetEnableFstn(pSiS->SiS_Pr, FALSE);
8023	      if((pSiS->ChipType == SIS_550) && (pSiS->sisfbfound)) {
8024		 if(pSiS->sisfbxSTN) {
8025		    SiS_SetEnableDstn(pSiS->SiS_Pr, pSiS->sisfbDSTN);
8026		    SiS_SetEnableFstn(pSiS->SiS_Pr, pSiS->sisfbFSTN);
8027		 } else if(mymode == 0x5a || mymode == 0x5b) {
8028		    SiS_SetEnableFstn(pSiS->SiS_Pr, TRUE);
8029		 }
8030	      }
8031	      SiSSetMode(pSiS->SiS_Pr, pScrn, mymode, FALSE);
8032	      if(changedmode) {
8033		 outSISIDXREG(SISCR,0x34,0x03);
8034	      }
8035	      SISSpecialRestore(pScrn);
8036	      SiS_GetSetModeID(pScrn, pSiS->OldMode); /* NOT mymode! */
8037	      pSiS->SiS_Pr->UsePanelScaler = backupscaler;
8038	      pSiS->SiS_Pr->CenterScreen = backupcenter;
8039	      pSiS->SiS_Pr->SiS_CustomT = backupspecialtiming;
8040	      SiS_SiSFB_Lock(pScrn, FALSE);
8041	      SiSRestore_SiSFB_TVParms(pScrn);
8042	      SiS_SiSFB_Lock(pScrn, TRUE);
8043
8044	   }
8045
8046	   /* Restore CRT1 status */
8047	   if(pSiS->VGAEngine == SIS_315_VGA) {
8048              outSISIDXREG(SISCR, pSiS->myCR63, pSiS->oldCR63);
8049           }
8050           outSISIDXREG(SISSR, 0x1f, pSiS->oldSR1F);
8051
8052#ifdef SISVRAMQ
8053	   /* Restore queue mode registers on 315/330/340 series */
8054	   /* (This became necessary due to the switch to VRAM queue) */
8055	   SiSRestoreQueueMode(pSiS, sisReg);
8056#endif
8057
8058        } else {
8059
8060	   if(pSiS->VBFlags2 & VB2_VIDEOBRIDGE) {
8061	      /* If a video bridge is present, we need to restore
8062	       * non-extended (=standard VGA) SR and CR registers
8063	       * before restoring the extended ones and the bridge
8064	       * registers.
8065	       */
8066	      if(!(SiSBridgeIsInSlaveMode(pScrn))) {
8067                 SiSVGAProtect(pScrn, TRUE);
8068	         SiSVGARestore(pScrn, sisReg, SISVGA_SR_MODE);
8069              }
8070	   }
8071
8072           (*pSiS->SiSRestore)(pScrn, sisReg);
8073
8074        }
8075
8076	if(doitlater) {
8077           outSISIDXREG(SISCR, 0x17, pSiS->oldCR17);
8078	}
8079
8080
8081
8082	if((pSiS->VBFlags2 & VB2_VIDEOBRIDGE) && (SiSBridgeIsInSlaveMode(pScrn))) {
8083
8084	   /* IMPORTANT: The 30xLV does not handle well being disabled if in
8085	    * LCDA mode! In LCDA mode, the bridge is NOT in slave mode,
8086	    * so this is the only safe way: Disable the bridge ONLY if
8087	    * in Slave Mode, and don't bother if not.
8088	    */
8089
8090	   if(flags & SISVGA_SR_FONTS) {
8091              SiSRegInit(pSiS->SiS_Pr, pSiS->RelIO+0x30);
8092	      SiSSetLVDSetc(pSiS->SiS_Pr);
8093	      SiS_GetVBType(pSiS->SiS_Pr);
8094	      SiS_DisableBridge(pSiS->SiS_Pr);
8095	      SiSVGAProtect(pScrn, TRUE);
8096	   }
8097
8098	   SiSVGARestore(pScrn, sisReg, flags);
8099
8100	   if(flags & SISVGA_SR_FONTS) {
8101	      SiSVGAProtect(pScrn, FALSE);
8102	      SiS_EnableBridge(pSiS->SiS_Pr);
8103	      andSISIDXREG(SISSR, 0x01, ~0x20);  /* Display on */
8104	   }
8105
8106	} else {
8107
8108	   SiSVGAProtect(pScrn, TRUE);
8109	   SiSVGARestore(pScrn, sisReg, flags);
8110           SiSVGAProtect(pScrn, FALSE);
8111
8112	}
8113
8114	SiSFixupSR11(pScrn);
8115
8116#ifdef TWDEBUG
8117	{
8118	  SISRegPtr pReg = &pSiS->ModeReg;
8119	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
8120		"REAL REGISTER CONTENTS AFTER RESTORE BY SETMODE:\n");
8121	  (*pSiS->SiSSave)(pScrn, pReg);
8122	}
8123#endif
8124
8125	sisRestoreExtRegisterLock(pSiS,sisReg->sisRegs3C4[0x05],sisReg->sisRegs3D4[0x80]);
8126
8127    } else {	/* All other chipsets */
8128
8129        SiSVGAProtect(pScrn, TRUE);
8130
8131#ifdef UNLOCK_ALWAYS
8132        sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
8133#endif
8134
8135        (*pSiS->SiSRestore)(pScrn, sisReg);
8136
8137        SiSVGAProtect(pScrn, TRUE);
8138
8139	SiSVGARestore(pScrn, sisReg, flags);
8140
8141	/* Restore TV. This is rather complicated, but if we don't do it,
8142	 * TV output will flicker terribly
8143	 */
8144        if((pSiS->Chipset == PCI_CHIP_SIS6326) && (pSiS->SiS6326Flags & SIS6326_HASTV)) {
8145	   if(sisReg->sis6326tv[0] & 0x04) {
8146	      UChar tmp;
8147	      int val;
8148
8149              orSISIDXREG(SISSR, 0x01, 0x20);
8150              tmp = SiS6326GetTVReg(pScrn,0x00);
8151              tmp &= ~0x04;
8152              while(!(inSISREG(SISINPSTAT) & 0x08));  /* Wait while NOT vb */
8153              SiS6326SetTVReg(pScrn,0x00,tmp);
8154              for(val=0; val < 2; val++) {
8155                 while(!(inSISREG(SISINPSTAT) & 0x08));  /* Wait while NOT vb */
8156                 while(inSISREG(SISINPSTAT) & 0x08);     /* wait while vb     */
8157              }
8158              SiS6326SetTVReg(pScrn, 0x00, sisReg->sis6326tv[0]);
8159              tmp = inSISREG(SISINPSTAT);
8160              outSISREG(SISAR, 0x20);
8161              tmp = inSISREG(SISINPSTAT);
8162              while(inSISREG(SISINPSTAT) & 0x01);
8163              while(!(inSISREG(SISINPSTAT) & 0x01));
8164              andSISIDXREG(SISSR, 0x01, ~0x20);
8165              for(val=0; val < 10; val++) {
8166                 while(!(inSISREG(SISINPSTAT) & 0x08));  /* Wait while NOT vb */
8167                 while(inSISREG(SISINPSTAT) & 0x08);     /* wait while vb     */
8168              }
8169              andSISIDXREG(SISSR, 0x01, ~0x20);
8170	   }
8171        }
8172
8173        sisRestoreExtRegisterLock(pSiS,sisReg->sisRegs3C4[5],sisReg->sisRegs3D4[0x80]);
8174
8175        SiSVGAProtect(pScrn, FALSE);
8176    }
8177}
8178
8179static void
8180SISVESARestore(ScrnInfoPtr pScrn)
8181{
8182   SISPtr pSiS = SISPTR(pScrn);
8183#ifdef SISVRAMQ
8184   SISRegPtr sisReg = &pSiS->SavedReg;
8185#endif
8186
8187   if(pSiS->UseVESA) {
8188      SISVESASaveRestore(pScrn, MODE_RESTORE);
8189#ifdef SISVRAMQ
8190      /* Restore queue mode registers on 315/330/340 series */
8191      /* (This became necessary due to the switch to VRAM queue) */
8192      SiSRestoreQueueMode(pSiS, sisReg);
8193#endif
8194   }
8195}
8196
8197/* Restore bridge config registers - to be called BEFORE VESARestore */
8198static void
8199SISBridgeRestore(ScrnInfoPtr pScrn)
8200{
8201    SISPtr pSiS = SISPTR(pScrn);
8202
8203#ifdef SISDUALHEAD
8204    /* We only restore for master head */
8205    if(pSiS->DualHeadMode && pSiS->SecondHead) return;
8206#endif
8207
8208    if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
8209	SiSRestoreBridge(pScrn, &pSiS->SavedReg);
8210    }
8211}
8212
8213/* Our BlockHandler */
8214static void
8215SISBlockHandler(BLOCKHANDLER_ARGS_DECL)
8216{
8217    SCREEN_PTR(arg);
8218    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
8219    SISPtr pSiS = SISPTR(pScrn);
8220
8221    pScreen->BlockHandler = pSiS->BlockHandler;
8222    (*pScreen->BlockHandler) (BLOCKHANDLER_ARGS);
8223    pScreen->BlockHandler = SISBlockHandler;
8224
8225#ifdef SISDUALHEAD
8226    if(pSiS->NeedCopyFastVidCpy) {
8227       SISEntPtr pSiSEnt = pSiS->entityPrivate;
8228       if(pSiSEnt->HaveFastVidCpy) {
8229	  pSiS->NeedCopyFastVidCpy = FALSE;
8230	  pSiS->SiSFastVidCopy = pSiSEnt->SiSFastVidCopy;
8231	  pSiS->SiSFastMemCopy = pSiSEnt->SiSFastMemCopy;
8232	  pSiS->SiSFastVidCopyFrom = pSiSEnt->SiSFastVidCopyFrom;
8233	  pSiS->SiSFastMemCopyFrom = pSiSEnt->SiSFastMemCopyFrom;
8234       }
8235    }
8236#endif
8237
8238    if(pSiS->VideoTimerCallback) {
8239       (*pSiS->VideoTimerCallback)(pScrn, currentTime.milliseconds);
8240    }
8241
8242#ifdef SIS_USE_XAA
8243    if(pSiS->RenderCallback) {
8244       (*pSiS->RenderCallback)(pScrn);
8245    }
8246#endif
8247#ifdef SIS_USE_EXA
8248    if(pSiS->ExaRenderCallback) {
8249       (*pSiS->ExaRenderCallback)(pScrn);
8250    }
8251#endif
8252}
8253
8254
8255
8256/* Do screen blanking; DPMS handling
8257 *
8258 * Mandatory; latter optional
8259 */
8260
8261static void
8262SiSHandleBackLight(SISPtr pSiS, Bool blon)
8263{
8264    UChar sr11mask = (pSiS->SiS_Pr->SiS_SensibleSR11) ? 0x03 : 0xf3;
8265
8266    if(pSiS->VBFlags2 & VB2_SISLVDSBRIDGE) {
8267
8268       if(!blon) {
8269	  SiS_SiS30xBLOff(pSiS->SiS_Pr);
8270       } else {
8271	  SiS_SiS30xBLOn(pSiS->SiS_Pr);
8272       }
8273
8274    } else if( ((pSiS->VGAEngine == SIS_300_VGA) &&
8275	        (pSiS->VBFlags2 & (VB2_LVDS | VB2_30xBDH))) ||
8276	       ((pSiS->VGAEngine == SIS_315_VGA) &&
8277	        ((pSiS->VBFlags2 & (VB2_LVDS | VB2_CHRONTEL)) == VB2_LVDS)) ) {
8278
8279       if(!blon) {
8280	  setSISIDXREG(SISSR, 0x11, sr11mask, 0x08);
8281       } else {
8282	  setSISIDXREG(SISSR, 0x11, sr11mask, 0x00);
8283       }
8284
8285    } else if((pSiS->VGAEngine == SIS_315_VGA) &&
8286	      (pSiS->VBFlags2 & VB2_CHRONTEL)) {
8287
8288       if(!blon) {
8289	  SiS_Chrontel701xBLOff(pSiS->SiS_Pr);
8290       } else {
8291	  SiS_Chrontel701xBLOn(pSiS->SiS_Pr);
8292       }
8293
8294    }
8295}
8296
8297static Bool
8298SISSaveScreen(ScreenPtr pScreen, int mode)
8299{
8300    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
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#ifdef UNLOCK_ALWAYS
8309    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
8310#endif
8311
8312    if(pSiS->VBFlags & (CRT2_LCD | CRT1_LCDA)) {
8313       SiSHandleBackLight(pSiS, IsUnblank);
8314    }
8315
8316    if(!SiSBridgeIsInSlaveMode(pScrn)) {
8317       return SiSVGASaveScreen(pScreen, mode);
8318    }
8319
8320    return TRUE;
8321}
8322
8323#ifdef SISDUALHEAD
8324/* SaveScreen for dual head mode */
8325static Bool
8326SISSaveScreenDH(ScreenPtr pScreen, int mode)
8327{
8328    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
8329    SISPtr pSiS;
8330    Bool IsUnblank = xf86IsUnblank(mode) ? TRUE : FALSE;
8331
8332    if((pScrn == NULL) || (!pScrn->vtSema)) return TRUE;
8333
8334    pSiS = SISPTR(pScrn);
8335
8336    if( (pSiS->SecondHead) &&
8337        ((!(pSiS->VBFlags & CRT1_LCDA)) || (pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE)) ) {
8338
8339       /* Slave head is always CRT1 */
8340       /* (No backlight handling on TMDS bridges) */
8341       return SiSVGASaveScreen(pScreen, mode);
8342
8343    } else {
8344
8345       /* Master head is always CRT2 */
8346       /* But we land here for LCDA, too (if bridge is SiS LVDS type) */
8347
8348       /* We can only blank LCD, not other CRT2 devices */
8349       if(pSiS->VBFlags & (CRT2_LCD|CRT1_LCDA)) {
8350
8351#ifdef UNLOCK_ALWAYS
8352	  sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
8353#endif
8354	  SiSHandleBackLight(pSiS, IsUnblank);
8355
8356       }
8357
8358    }
8359    return TRUE;
8360}
8361#endif
8362
8363static void
8364SISDisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode, int flags)
8365{
8366    SISPtr pSiS = SISPTR(pScrn);
8367    Bool   docrt1 = TRUE, docrt2 = TRUE, backlight = TRUE;
8368    UChar  sr1=0, cr17=0, cr63=0, pmreg=0, sr7=0;
8369    UChar  p1_13=0, p2_0=0, oldpmreg=0;
8370
8371    if(!pScrn->vtSema) return;
8372
8373    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 4,
8374          "SISDisplayPowerManagementSet(%d)\n", PowerManagementMode);
8375
8376#ifdef SISDUALHEAD
8377    if(pSiS->DualHeadMode) {
8378       if(pSiS->SecondHead) docrt2 = FALSE;
8379       else                 docrt1 = FALSE;
8380    }
8381#endif
8382
8383    /* FIXME: in old servers, DPMSSet was supposed to be called without open
8384     * the correct PCI bridges before access the hardware. Now we have this
8385     * hook wrapped by the vga arbiter which should do all the work, in
8386     * kernels that implement it. For this case we might not want this hack
8387     * bellow.
8388     */
8389    outSISIDXREG(SISSR,0x05,0x86);
8390    inSISIDXREG(SISSR,0x05,pmreg);
8391    if(pmreg != 0xa1) return;
8392
8393#ifdef UNLOCK_ALWAYS
8394    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
8395#endif
8396
8397    switch(PowerManagementMode) {
8398
8399       case DPMSModeOn:      /* HSync: On, VSync: On */
8400	  sr1   = 0x00;
8401	  cr17  = 0x80;
8402	  pmreg = 0x00;
8403	  cr63  = 0x00;
8404	  sr7   = 0x10;
8405	  p2_0  = 0x20;
8406	  p1_13 = 0x00;
8407	  backlight = TRUE;
8408	  break;
8409
8410       case DPMSModeSuspend: /* HSync: On, VSync: Off */
8411	  sr1   = 0x20;
8412	  cr17  = 0x80;
8413	  pmreg = 0x80;
8414	  cr63  = 0x40;
8415	  sr7   = 0x00;
8416	  p2_0  = 0x40;
8417	  p1_13 = 0x80;
8418	  backlight = FALSE;
8419	  break;
8420
8421       case DPMSModeStandby: /* HSync: Off, VSync: On */
8422	  sr1   = 0x20;
8423	  cr17  = 0x80;
8424	  pmreg = 0x40;
8425	  cr63  = 0x40;
8426	  sr7   = 0x00;
8427	  p2_0  = 0x80;
8428	  p1_13 = 0x40;
8429	  backlight = FALSE;
8430	  break;
8431
8432       case DPMSModeOff:     /* HSync: Off, VSync: Off */
8433	  sr1   = 0x20;
8434	  cr17  = 0x00;
8435	  pmreg = 0xc0;
8436	  cr63  = 0x40;
8437	  sr7   = 0x00;
8438	  p2_0  = 0xc0;
8439	  p1_13 = 0xc0;
8440	  backlight = FALSE;
8441	  break;
8442
8443       default:
8444	    return;
8445    }
8446
8447    oldpmreg = pmreg;
8448
8449    if((docrt2 && (pSiS->VBFlags & CRT2_LCD)) ||
8450       (docrt1 && (pSiS->VBFlags & CRT1_LCDA))) {
8451       SiSHandleBackLight(pSiS, backlight);
8452    }
8453
8454    if(docrt1) {
8455       switch(pSiS->VGAEngine) {
8456       case SIS_OLD_VGA:
8457       case SIS_530_VGA:
8458	    setSISIDXREG(SISSR, 0x01, ~0x20, sr1);    /* Set/Clear "Display On" bit */
8459	    inSISIDXREG(SISSR, 0x11, oldpmreg);
8460	    setSISIDXREG(SISCR, 0x17, 0x7f, cr17);
8461	    setSISIDXREG(SISSR, 0x11, 0x3f, pmreg);
8462	    break;
8463       case SIS_315_VGA:
8464	    if( (!pSiS->CRT1off) &&
8465	        ((!(pSiS->VBFlags & CRT1_LCDA)) || (pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE)) ) {
8466	       setSISIDXREG(SISCR, pSiS->myCR63, 0xbf, cr63);
8467	       setSISIDXREG(SISSR, 0x07, 0xef, sr7);
8468	    }
8469	    /* fall through */
8470       default:
8471	    if(!SiSBridgeIsInSlaveMode(pScrn)) {
8472	       setSISIDXREG(SISSR, 0x01, ~0x20, sr1);    /* Set/Clear "Display On" bit */
8473	    }
8474	    if((!(pSiS->VBFlags & CRT1_LCDA)) || (pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE)) {
8475	       inSISIDXREG(SISSR, 0x1f, oldpmreg);
8476	       if((!pSiS->CRT1off) && (!SiSBridgeIsInSlaveMode(pScrn))) {
8477		  setSISIDXREG(SISSR, 0x1f, 0x3f, pmreg);
8478	       }
8479	    }
8480       }
8481       oldpmreg &= 0xc0;
8482    }
8483
8484    if(docrt2) {
8485       if(pSiS->VBFlags & CRT2_LCD) {
8486          if((pSiS->VBFlags2 & VB2_SISBRIDGE) &&
8487	     (!(pSiS->VBFlags2 & VB2_30xBDH))) {
8488	     if(pSiS->VGAEngine == SIS_300_VGA) {
8489	        SiS_UnLockCRT2(pSiS->SiS_Pr);
8490	        setSISIDXREG(SISPART1, 0x13, 0x3f, p1_13);
8491	     }
8492	     if(pSiS->VBFlags2 & VB2_SISLVDSBRIDGE) p2_0 |= 0x20;
8493	     setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
8494	  }
8495       } else if(pSiS->VBFlags & (CRT2_VGA | CRT2_TV)) {
8496	  if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
8497	     setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
8498	  }
8499       }
8500    }
8501
8502    if( (docrt1) &&
8503        (pmreg != oldpmreg) &&
8504        ((!(pSiS->VBFlags & CRT1_LCDA)) || (pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE)) ) {
8505       outSISIDXREG(SISSR, 0x00, 0x01);    /* Synchronous Reset */
8506       usleep(10000);
8507       outSISIDXREG(SISSR, 0x00, 0x03);    /* End Reset */
8508    }
8509
8510}
8511
8512/* Mandatory
8513 * This gets called at the start of each server generation
8514 *
8515 * We use pScrn and not CurrentLayout here, because the
8516 * properties we use have not changed (displayWidth,
8517 * depth, bitsPerPixel)
8518 */
8519static Bool
8520SISScreenInit(SCREEN_INIT_ARGS_DECL)
8521{
8522    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
8523    SISPtr pSiS = SISPTR(pScrn);
8524    VisualPtr visual;
8525    ULong OnScreenSize;
8526    int ret, height, width, displayWidth;
8527    UChar *FBStart;
8528#ifdef SISDUALHEAD
8529    SISEntPtr pSiSEnt = NULL;
8530#endif
8531
8532#ifdef SISDUALHEAD
8533    if((!pSiS->DualHeadMode) || (!pSiS->SecondHead)) {
8534#endif
8535       SiS_LoadInitVBE(pScrn);
8536#ifdef SISDUALHEAD
8537    }
8538#endif
8539
8540#ifdef SISDUALHEAD
8541    if(pSiS->DualHeadMode) {
8542       pSiSEnt = pSiS->entityPrivate;
8543       pSiSEnt->refCount++;
8544    }
8545#endif
8546
8547#ifdef SIS_PC_PLATFORM
8548    /* Map 64k VGA window for saving/restoring CGA fonts */
8549    SiS_MapVGAMem(pScrn);
8550#endif
8551
8552    /* Map the SiS memory and MMIO areas */
8553    if(!SISMapMem(pScrn)) {
8554       SISErrorLog(pScrn, "SiSMapMem() failed\n");
8555       return FALSE;
8556    }
8557
8558    SiS_SiSFB_Lock(pScrn, TRUE);
8559
8560#ifdef UNLOCK_ALWAYS
8561    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
8562#endif
8563
8564    /* Enable TurboQueue so that SISSave() saves it in enabled
8565     * state. If we don't do this, X will hang after a restart!
8566     * (Happens for some unknown reason only when using VESA
8567     * for mode switching; assumingly a BIOS issue.)
8568     * This is done on 300 and 315 series only.
8569     */
8570    if(pSiS->UseVESA) {
8571#ifdef SISVRAMQ
8572       if(pSiS->VGAEngine != SIS_315_VGA)
8573#endif
8574          SiSEnableTurboQueue(pScrn);
8575    }
8576
8577    /* Save the current state */
8578    SISSave(pScrn);
8579
8580    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
8581
8582       if(!pSiS->OldMode) {
8583
8584          /* Try to find out current (=old) mode number
8585	   * (Do this only if not sisfb has told us its mode yet)
8586	   */
8587
8588	  /* Read 0:449 which the BIOS sets to the current mode number
8589	   * Unfortunately, this not reliable since the int10 emulation
8590	   * does not change this. So if we call the VBE later, this
8591	   * byte won't be touched (which is why we set this manually
8592	   * then).
8593	   */
8594          UChar myoldmode = SiS_GetSetModeID(pScrn, 0xFF);
8595	  UChar cr30, cr31;
8596
8597          /* Read CR34 which the BIOS sets to the current mode number for CRT2
8598	   * This is - of course - not reliable if the machine has no video
8599	   * bridge...
8600	   */
8601          inSISIDXREG(SISCR, 0x34, pSiS->OldMode);
8602	  inSISIDXREG(SISCR, 0x30, cr30);
8603	  inSISIDXREG(SISCR, 0x31, cr31);
8604
8605	  /* What if CR34 is different from the BIOS scratch byte? */
8606	  if(pSiS->OldMode != myoldmode) {
8607	     /* If no bridge output is active, trust the BIOS scratch byte */
8608	     if( (!(pSiS->VBFlags2 & VB2_VIDEOBRIDGE)) ||
8609	         (pSiS->OldMode == 0)                  ||
8610	         (!cr31 && !cr30)                      ||
8611		 (cr31 & 0x20) ) {
8612		pSiS->OldMode = myoldmode;
8613 	     }
8614	     /* ..else trust CR34 */
8615	  }
8616
8617	  /* Newer 650 BIOSes set CR34 to 0xff if the mode has been
8618	   * "patched", for instance for 80x50 text mode. (That mode
8619	   * has no number of its own, it's 0x03 like 80x25). In this
8620	   * case, we trust the BIOS scratch byte (provided that any
8621	   * of these two is valid).
8622	   */
8623	  if(pSiS->OldMode > 0x7f) {
8624	     pSiS->OldMode = myoldmode;
8625	  }
8626       }
8627#ifdef SISDUALHEAD
8628       if(pSiS->DualHeadMode) {
8629          if(!pSiS->SecondHead) pSiSEnt->OldMode = pSiS->OldMode;
8630          else                  pSiS->OldMode = pSiSEnt->OldMode;
8631       }
8632#endif
8633    }
8634
8635    /* RandR resets screen mode and size in CloseScreen(), hence
8636     * we need to adapt our VBFlags to the initial state if the
8637     * current mode has changed since closescreen() (or Screeninit()
8638     * for the first instance)
8639     */
8640    if(pScrn->currentMode != pSiS->currentModeLast) {
8641       pSiS->VBFlags = pSiS->VBFlags_backup = pSiS->VBFlagsInit;
8642    }
8643
8644    /* Copy our detected monitor gammas, part 2. Note that device redetection
8645     * is not supported in DHM, so there is no need to do that anytime later.
8646     */
8647#ifdef SISDUALHEAD
8648    if(pSiS->DualHeadMode) {
8649       if(!pSiS->SecondHead) {
8650          /* CRT2 */
8651	  pSiS->CRT1VGAMonitorGamma = pSiSEnt->CRT1VGAMonitorGamma;
8652       } else {
8653          /* CRT1 */
8654	  pSiS->CRT2VGAMonitorGamma = pSiSEnt->CRT2VGAMonitorGamma;
8655       }
8656       if(!pSiS->CRT2LCDMonitorGamma) pSiS->CRT2LCDMonitorGamma = pSiSEnt->CRT2LCDMonitorGamma;
8657    }
8658#endif
8659
8660    /* Initialize the first mode */
8661    if(!SISModeInit(pScrn, pScrn->currentMode)) {
8662       SISErrorLog(pScrn, "SiSModeInit() failed\n");
8663       return FALSE;
8664    }
8665
8666    /* Darken the screen for aesthetic reasons */
8667    /* Not using Dual Head variant on purpose; we darken
8668     * the screen for both displays, and un-darken
8669     * it when the second head is finished
8670     */
8671    SISSaveScreen(pScreen, SCREEN_SAVER_ON);
8672
8673    /* Set the viewport */
8674    SISAdjustFrame(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0));
8675
8676    /* Reset visual list. */
8677    miClearVisualTypes();
8678
8679    /* Setup the visuals we support. */
8680
8681    /*
8682     * For bpp > 8, the default visuals are not acceptable because we only
8683     * support TrueColor and not DirectColor.
8684     */
8685    if(!miSetVisualTypes(pScrn->depth,
8686			 (pScrn->bitsPerPixel > 8) ?
8687				TrueColorMask : miGetDefaultVisualMask(pScrn->depth),
8688			 pScrn->rgbBits, pScrn->defaultVisual)) {
8689       SISSaveScreen(pScreen, SCREEN_SAVER_OFF);
8690       SISErrorLog(pScrn, "miSetVisualTypes() failed (bpp %d)\n",
8691			pScrn->bitsPerPixel);
8692       return FALSE;
8693    }
8694
8695    width = pScrn->virtualX;
8696    height = pScrn->virtualY;
8697    displayWidth = pScrn->displayWidth;
8698
8699    if(pSiS->Rotate) {
8700       height = pScrn->virtualX;
8701       width = pScrn->virtualY;
8702    }
8703
8704    if(pSiS->ShadowFB) {
8705       pSiS->ShadowPitch = BitmapBytePad(pScrn->bitsPerPixel * width);
8706       pSiS->ShadowPtr = malloc(pSiS->ShadowPitch * height);
8707       displayWidth = pSiS->ShadowPitch / (pScrn->bitsPerPixel >> 3);
8708       FBStart = pSiS->ShadowPtr;
8709    } else {
8710       pSiS->ShadowPtr = NULL;
8711       FBStart = pSiS->FbBase;
8712    }
8713
8714    if(!miSetPixmapDepths()) {
8715       SISSaveScreen(pScreen, SCREEN_SAVER_OFF);
8716       SISErrorLog(pScrn, "miSetPixmapDepths() failed\n");
8717       return FALSE;
8718    }
8719
8720    /* Point cmdQueuePtr to pSiSEnt for shared usage
8721     * (same technique is then eventually used in DRIScreeninit)
8722     * For 315/330 series, this is done in EnableTurboQueue
8723     * which has already been called during ModeInit().
8724     */
8725#ifdef SISDUALHEAD
8726    if(pSiS->SecondHead)
8727       pSiS->cmdQueueLenPtr = &(SISPTR(pSiSEnt->pScrn_1)->cmdQueueLen);
8728    else
8729#endif
8730       pSiS->cmdQueueLenPtr = &(pSiS->cmdQueueLen);
8731
8732    pSiS->cmdQueueLen = 0; /* Force an EngineIdle() at start */
8733
8734#ifdef SISDRI
8735    if(pSiS->loadDRI) {
8736#ifdef SISDUALHEAD
8737       /* No DRI in dual head mode */
8738       if(pSiS->DualHeadMode) {
8739	  pSiS->directRenderingEnabled = FALSE;
8740	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
8741		"DRI not supported in Dual Head mode\n");
8742       } else
8743#endif
8744	      if(pSiS->VGAEngine != SIS_315_VGA) {
8745	  /* Force the initialization of the context */
8746	  pSiS->directRenderingEnabled = SISDRIScreenInit(pScreen);
8747       } else {
8748	  xf86DrvMsg(pScrn->scrnIndex, X_NOT_IMPLEMENTED,
8749		"DRI not supported on this chipset\n");
8750	  pSiS->directRenderingEnabled = FALSE;
8751       }
8752    }
8753#endif
8754
8755    /* Call the framebuffer layer's ScreenInit function and fill in other
8756     * pScreen fields.
8757     */
8758    switch(pScrn->bitsPerPixel) {
8759       case 24:
8760	  if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
8761	     ret = FALSE;
8762	     break;
8763	  }
8764	  /* fall through */
8765       case 8:
8766       case 16:
8767       case 32:
8768	  ret = fbScreenInit(pScreen, FBStart, width,
8769			height, pScrn->xDpi, pScrn->yDpi,
8770			displayWidth, pScrn->bitsPerPixel);
8771	  break;
8772       default:
8773	  ret = FALSE;
8774	  break;
8775    }
8776    if(!ret) {
8777       SISErrorLog(pScrn, "Unsupported bpp (%d) or fbScreenInit() failed\n",
8778			pScrn->bitsPerPixel);
8779       SISSaveScreen(pScreen, SCREEN_SAVER_OFF);
8780       return FALSE;
8781    }
8782
8783    /* Fixup RGB ordering */
8784    if(pScrn->bitsPerPixel > 8) {
8785       visual = pScreen->visuals + pScreen->numVisuals;
8786       while (--visual >= pScreen->visuals) {
8787          if((visual->class | DynamicClass) == DirectColor) {
8788             visual->offsetRed = pScrn->offset.red;
8789             visual->offsetGreen = pScrn->offset.green;
8790             visual->offsetBlue = pScrn->offset.blue;
8791             visual->redMask = pScrn->mask.red;
8792             visual->greenMask = pScrn->mask.green;
8793             visual->blueMask = pScrn->mask.blue;
8794          }
8795       }
8796    }
8797
8798    /* Initialize RENDER extension (must be after RGB ordering fixed) */
8799    fbPictureInit(pScreen, 0, 0);
8800
8801    /* Hardware cursor needs to wrap this layer */
8802    if(!pSiS->ShadowFB) SISDGAInit(pScreen);
8803
8804    xf86SetBlackWhitePixels(pScreen);
8805
8806    /* Initialize the accelerators */
8807    switch(pSiS->VGAEngine) {
8808    case SIS_530_VGA:
8809    case SIS_300_VGA:
8810       SiS300AccelInit(pScreen);
8811       break;
8812    case SIS_315_VGA:
8813       SiS315AccelInit(pScreen);
8814       break;
8815    default:
8816       SiSAccelInit(pScreen);
8817    }
8818
8819#ifdef TWDEBUG
8820    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CPUFlags %x\n", pSiS->CPUFlags);
8821#endif
8822
8823    /* Benchmark memcpy() methods (needs FB manager initialized) */
8824    /* Dual head: Do this AFTER the mode for CRT1 has been set */
8825    pSiS->NeedCopyFastVidCpy = FALSE;
8826    if(!pSiS->SiSFastVidCopyDone) {
8827#ifdef SISDUALHEAD
8828       if(pSiS->DualHeadMode) {
8829	  if(pSiS->SecondHead) {
8830	     pSiSEnt->SiSFastVidCopy = SiSVidCopyInit(pScreen, &pSiSEnt->SiSFastMemCopy, FALSE);
8831	     pSiSEnt->SiSFastVidCopyFrom = SiSVidCopyGetDefault();
8832	     pSiSEnt->SiSFastMemCopyFrom = SiSVidCopyGetDefault();
8833#ifdef SIS_USE_EXA
8834	     if(pSiS->useEXA) {
8835	        pSiSEnt->SiSFastVidCopyFrom = SiSVidCopyInit(pScreen, &pSiSEnt->SiSFastMemCopyFrom, TRUE);
8836	     }
8837#endif /* EXA */
8838	     pSiSEnt->HaveFastVidCpy = TRUE;
8839	     pSiS->SiSFastVidCopy = pSiSEnt->SiSFastVidCopy;
8840	     pSiS->SiSFastMemCopy = pSiSEnt->SiSFastMemCopy;
8841	     pSiS->SiSFastVidCopyFrom = pSiSEnt->SiSFastVidCopyFrom;
8842	     pSiS->SiSFastMemCopyFrom = pSiSEnt->SiSFastMemCopyFrom;
8843	  } else {
8844	     pSiS->NeedCopyFastVidCpy = TRUE;
8845	  }
8846       } else {
8847#endif
8848	  pSiS->SiSFastVidCopy = SiSVidCopyInit(pScreen, &pSiS->SiSFastMemCopy, FALSE);
8849	  pSiS->SiSFastVidCopyFrom = SiSVidCopyGetDefault();
8850	  pSiS->SiSFastMemCopyFrom = SiSVidCopyGetDefault();
8851#ifdef SIS_USE_EXA
8852	  if(pSiS->useEXA) {
8853	     pSiS->SiSFastVidCopyFrom = SiSVidCopyInit(pScreen, &pSiS->SiSFastMemCopyFrom, TRUE);
8854	  }
8855#endif /* EXA */
8856#ifdef SISDUALHEAD
8857       }
8858#endif
8859    }
8860    pSiS->SiSFastVidCopyDone = TRUE;
8861
8862    miInitializeBackingStore(pScreen);
8863    xf86SetBackingStore(pScreen);
8864    xf86SetSilkenMouse(pScreen);
8865
8866    /* Initialise cursor functions */
8867    miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
8868
8869    if(pSiS->HWCursor) {
8870       SiSHWCursorInit(pScreen);
8871    }
8872
8873#ifdef SISDUALHEAD
8874    if(!pSiS->DualHeadMode) {
8875#endif
8876       if((pSiS->VBFlags2 & VB2_SISBRIDGE) && (pScrn->depth > 8)) {
8877
8878	  pSiS->CRT2ColNum = 1 << pScrn->rgbBits;
8879
8880	  if((pSiS->crt2gcolortable = malloc(pSiS->CRT2ColNum * 2 * sizeof(LOCO)))) {
8881	     pSiS->crt2colors = &pSiS->crt2gcolortable[pSiS->CRT2ColNum];
8882	     if((pSiS->crt2cindices = malloc(256 * sizeof(int)))) {
8883		int i = pSiS->CRT2ColNum;
8884		SISCalculateGammaRampCRT2(pScrn);
8885		while(i--) pSiS->crt2cindices[i] = i;
8886	     } else {
8887		free(pSiS->crt2gcolortable);
8888		pSiS->crt2gcolortable = NULL;
8889		pSiS->CRT2SepGamma = FALSE;
8890	     }
8891	  } else {
8892	     pSiS->CRT2SepGamma = FALSE;
8893	  }
8894
8895	  if(!pSiS->crt2cindices) {
8896	     xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
8897	  	"Failed to allocate cmap for CRT2, separate gamma correction disabled\n");
8898	  }
8899
8900       }
8901#ifdef SISDUALHEAD
8902    } else pSiS->CRT2SepGamma = FALSE;
8903#endif
8904
8905    /* Initialise default colormap */
8906    if(!miCreateDefColormap(pScreen)) {
8907       SISSaveScreen(pScreen, SCREEN_SAVER_OFF);
8908       SISErrorLog(pScrn, "miCreateDefColormap() failed\n");
8909       return FALSE;
8910    }
8911
8912    if(!xf86HandleColormaps(pScreen, 256, (pScrn->depth == 8) ? 8 : pScrn->rgbBits,
8913                    SISLoadPalette, NULL,
8914                    CMAP_PALETTED_TRUECOLOR | CMAP_RELOAD_ON_MODE_SWITCH)) {
8915       SISSaveScreen(pScreen, SCREEN_SAVER_OFF);
8916       SISErrorLog(pScrn, "xf86HandleColormaps() failed\n");
8917       return FALSE;
8918    }
8919
8920    /* Recalculate our gamma ramp for brightness feature */
8921#ifdef SISGAMMARAMP
8922    if((pSiS->GammaBriR != 1000) ||
8923       (pSiS->GammaBriB != 1000) ||
8924       (pSiS->GammaBriG != 1000) ||
8925       (pSiS->NewGammaBriR != 0.0) ||
8926       (pSiS->NewGammaBriG != 0.0) ||
8927       (pSiS->NewGammaBriB != 0.0) ||
8928       (pSiS->NewGammaConR != 0.0) ||
8929       (pSiS->NewGammaConG != 0.0) ||
8930       (pSiS->NewGammaConB != 0.0)) {
8931       SISCalculateGammaRamp(pScreen, pScrn);
8932    }
8933#endif
8934
8935    /* Initialize Shadow framebuffer and screen rotation/reflection */
8936    if(pSiS->ShadowFB) {
8937       RefreshAreaFuncPtr refreshArea = SISRefreshArea;
8938
8939       if(pSiS->Rotate) {
8940	  if(!pSiS->PointerMoved) pSiS->PointerMoved = pScrn->PointerMoved;
8941	  pScrn->PointerMoved = SISPointerMoved;
8942	  switch(pScrn->bitsPerPixel) {
8943	     case 8:  refreshArea = SISRefreshArea8;  break;
8944	     case 16: refreshArea = SISRefreshArea16; break;
8945	     case 24: refreshArea = SISRefreshArea24; break;
8946	     case 32: refreshArea = SISRefreshArea32; break;
8947	  }
8948#if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4,3,0,0,0)
8949	  xf86DisableRandR();
8950	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
8951		"Driver rotation enabled, disabling RandR\n");
8952#endif
8953       } else if(pSiS->Reflect) {
8954          switch(pScrn->bitsPerPixel) {
8955	  case 8:
8956	  case 16:
8957	  case 32:
8958             if(!pSiS->PointerMoved) pSiS->PointerMoved = pScrn->PointerMoved;
8959	     pScrn->PointerMoved = SISPointerMovedReflect;
8960	     refreshArea = SISRefreshAreaReflect;
8961#if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4,3,0,0,0)
8962	     xf86DisableRandR();
8963	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
8964		  "Driver reflection enabled, disabling RandR\n");
8965#endif
8966	     break;
8967	  default:
8968	     xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
8969	     	  "Reflection not supported at this framebuffer depth\n");
8970	  }
8971       }
8972
8973       ShadowFBInit(pScreen, refreshArea);
8974    }
8975
8976    xf86DPMSInit(pScreen, (DPMSSetProcPtr)SISDisplayPowerManagementSet, 0);
8977
8978    /* Init memPhysBase and fbOffset in pScrn */
8979    pScrn->memPhysBase = pSiS->FbAddress;
8980    pScrn->fbOffset = 0;
8981
8982    /* Initialize Xv */
8983    pSiS->ResetXv = pSiS->ResetXvGamma = pSiS->ResetXvDisplay = NULL;
8984#if (XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4,3,99,0,0)) || (defined(XvExtension))
8985    if((!pSiS->NoXvideo) && (!(pSiS->SiS_SD2_Flags & SiS_SD2_NOOVERLAY))) {
8986
8987       if((pSiS->VGAEngine == SIS_300_VGA) ||
8988	  (pSiS->VGAEngine == SIS_315_VGA)) {
8989
8990	  const char *using = "Using SiS300/315/330/340 series HW Xv";
8991
8992#ifdef SISDUALHEAD
8993	  if(pSiS->DualHeadMode) {
8994	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
8995		    "%s on CRT%d\n", using, (pSiS->SecondHead ? 1 : 2));
8996	     if(!pSiS->hasTwoOverlays) {
8997		if( (pSiS->XvOnCRT2 && pSiS->SecondHead) ||
8998		    (!pSiS->XvOnCRT2 && !pSiS->SecondHead) ) {
8999		   xf86DrvMsg(pScrn->scrnIndex, X_INFO,
9000			   "However, video overlay will by default only be visible on CRT%d\n",
9001			   pSiS->XvOnCRT2 ? 2 : 1);
9002		}
9003	     }
9004	  } else {
9005#endif
9006	     if(pSiS->hasTwoOverlays) {
9007		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s\n", using);
9008	     } else {
9009		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s by default on CRT%d\n",
9010			using, (pSiS->XvOnCRT2 ? 2 : 1));
9011	     }
9012#ifdef SISDUALHEAD
9013	  }
9014#endif
9015
9016	  SISInitVideo(pScreen);
9017
9018	  if(pSiS->blitadaptor) {
9019	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
9020		     "Default Xv adaptor is Video %s\n",
9021		     pSiS->XvDefAdaptorBlit ? "Blitter" : "Overlay");
9022	  }
9023
9024       } else if(pSiS->Chipset == PCI_CHIP_SIS530  ||
9025		 pSiS->Chipset == PCI_CHIP_SIS6326 ||
9026		 pSiS->Chipset == PCI_CHIP_SIS5597) {
9027
9028	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
9029		        "Using SiS5597/5598/6326/530/620 HW Xv\n" );
9030
9031	  SIS6326InitVideo(pScreen);
9032
9033       } else { /* generic Xv */
9034
9035	  XF86VideoAdaptorPtr *ptr;
9036	  int n = xf86XVListGenericAdaptors(pScrn, &ptr);
9037
9038	  if(n) {
9039	     xf86XVScreenInit(pScreen, ptr, n);
9040	     xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using generic Xv\n" );
9041          }
9042
9043       }
9044    }
9045#endif
9046
9047#ifdef SISDRI
9048    if(pSiS->loadDRI) {
9049       if(pSiS->directRenderingEnabled) {
9050          /* Now that mi, drm and others have done their thing,
9051           * complete the DRI setup.
9052           */
9053          pSiS->directRenderingEnabled = SISDRIFinishScreenInit(pScreen);
9054       }
9055       xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Direct rendering %s\n",
9056		pSiS->directRenderingEnabled ? "enabled" : "disabled");
9057       /* TODO */
9058       /* if(pSiS->directRenderingEnabled) SISSetLFBConfig(pSiS); */
9059    }
9060#endif
9061
9062    /* Wrap some funcs, initialize pseudo-Xinerama and setup remaining SD flags */
9063
9064    pSiS->SiS_SD_Flags &= ~(SiS_SD_PSEUDOXINERAMA);
9065#ifdef SISMERGED
9066    if(pSiS->MergedFB) {
9067       pSiS->PointerMoved = pScrn->PointerMoved;
9068       pScrn->PointerMoved = SISMergedPointerMoved;
9069       pSiS->Rotate = 0;
9070       pSiS->Reflect = 0;
9071       pSiS->ShadowFB = FALSE;
9072#if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4,3,0,0,0)
9073       if(pSiS->CRT1XOffs || pSiS->CRT1YOffs || pSiS->CRT2XOffs || pSiS->CRT2YOffs) {
9074	  xf86DisableRandR();
9075	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
9076		"MergedFB: CRT2Position offset used, disabling RandR\n");
9077       }
9078#endif
9079#ifdef SISXINERAMA
9080       if(pSiS->UseSiSXinerama) {
9081	  SiSnoPanoramiXExtension = FALSE;
9082	  SiSXineramaExtensionInit(pScrn);
9083	  if(!SiSnoPanoramiXExtension) {
9084	     pSiS->SiS_SD_Flags |= SiS_SD_PSEUDOXINERAMA;
9085	     if(pSiS->HaveNonRect) {
9086		/* Reset the viewport (now eventually non-recangular) */
9087		SISAdjustFrame(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0));
9088	     }
9089	  }
9090       } else {
9091	  pSiS->MouseRestrictions = FALSE;
9092       }
9093#endif
9094    }
9095#endif
9096
9097    /* Wrap CloseScreen and set up SaveScreen */
9098    pSiS->CloseScreen = pScreen->CloseScreen;
9099    pScreen->CloseScreen = SISCloseScreen;
9100#ifdef SISDUALHEAD
9101    if(pSiS->DualHeadMode)
9102       pScreen->SaveScreen = SISSaveScreenDH;
9103    else
9104#endif
9105       pScreen->SaveScreen = SISSaveScreen;
9106
9107    /* Install BlockHandler */
9108    pSiS->BlockHandler = pScreen->BlockHandler;
9109    pScreen->BlockHandler = SISBlockHandler;
9110
9111    /* Report any unused options (only for the first generation) */
9112    if(serverGeneration == 1) {
9113       xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
9114    }
9115
9116    /* Clear frame buffer */
9117    /* For CRT2, we don't do that at this point in dual head
9118     * mode since the mode isn't switched at this time (it will
9119     * be reset when setting the CRT1 mode). Hence, we just
9120     * save the necessary data and clear the screen when
9121     * going through this for CRT1.
9122     */
9123
9124    OnScreenSize = pScrn->displayWidth * pScrn->currentMode->VDisplay
9125                               * (pScrn->bitsPerPixel >> 3);
9126
9127    /* Turn on the screen now */
9128    /* We do this in dual head mode after second head is finished */
9129#ifdef SISDUALHEAD
9130    if(pSiS->DualHeadMode) {
9131       if(pSiS->SecondHead) {
9132	  sisclearvram(pSiS->FbBase, OnScreenSize);
9133	  sisclearvram(pSiSEnt->FbBase1, pSiSEnt->OnScreenSize1);
9134	  SISSaveScreen(pScreen, SCREEN_SAVER_OFF);
9135       } else {
9136	  pSiSEnt->FbBase1 = pSiS->FbBase;
9137	  pSiSEnt->OnScreenSize1 = OnScreenSize;
9138       }
9139    } else {
9140#endif
9141       SISSaveScreen(pScreen, SCREEN_SAVER_OFF);
9142       sisclearvram(pSiS->FbBase, OnScreenSize);
9143#ifdef SISDUALHEAD
9144    }
9145#endif
9146
9147    pSiS->SiS_SD_Flags &= ~SiS_SD_SUPPORTSGRCRT2;
9148#ifdef SISDUALHEAD
9149    if(!pSiS->DualHeadMode) {
9150#endif
9151       if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
9152          if((pSiS->crt2cindices) && (pSiS->crt2gcolortable)) {
9153             pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTSGRCRT2;
9154	  }
9155       }
9156#ifdef SISDUALHEAD
9157    }
9158#endif
9159
9160    pSiS->SiS_SD_Flags &= ~SiS_SD_ISDEPTH8;
9161    if(pSiS->CurrentLayout.bitsPerPixel == 8) {
9162       pSiS->SiS_SD_Flags |= SiS_SD_ISDEPTH8;
9163       pSiS->SiS_SD_Flags &= ~SiS_SD_SUPPORTXVGAMMA1;
9164       pSiS->SiS_SD_Flags &= ~SiS_SD_SUPPORTSGRCRT2;
9165    }
9166
9167#ifdef SISGAMMARAMP
9168    pSiS->SiS_SD_Flags |= SiS_SD_CANSETGAMMA;
9169#else
9170    pSiS->SiS_SD_Flags &= ~SiS_SD_CANSETGAMMA;
9171#endif
9172
9173    SiSCtrlExtInit(pScrn);
9174
9175    return TRUE;
9176}
9177
9178/* Usually mandatory */
9179Bool
9180SISSwitchMode(SWITCH_MODE_ARGS_DECL)
9181{
9182    SCRN_INFO_PTR(arg);
9183    SISPtr pSiS = SISPTR(pScrn);
9184
9185    if(!pSiS->skipswitchcheck) {
9186       if(SISValidMode(arg, mode, TRUE, 0) != MODE_OK) {
9187          return FALSE;
9188       }
9189    }
9190
9191    (*pSiS->SyncAccel)(pScrn);
9192
9193    if(!(SISModeInit(pScrn, mode))) return FALSE;
9194
9195    /* Since RandR (indirectly) uses SwitchMode(), we need to
9196     * update our Xinerama info here, too, in case of resizing
9197     */
9198#ifdef SISMERGED
9199#ifdef SISXINERAMA
9200    if(pSiS->MergedFB) {
9201       SiSUpdateXineramaScreenInfo(pScrn);
9202    }
9203#endif
9204#endif
9205    return TRUE;
9206}
9207
9208static void
9209SISSetStartAddressCRT1(SISPtr pSiS, ULong base)
9210{
9211    UChar cr11backup;
9212
9213    inSISIDXREG(SISCR,  0x11, cr11backup);  /* Unlock CRTC registers */
9214    andSISIDXREG(SISCR, 0x11, 0x7F);
9215    outSISIDXREG(SISCR, 0x0D, base & 0xFF);
9216    outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF);
9217    outSISIDXREG(SISSR, 0x0D, (base >> 16) & 0xFF);
9218    if(pSiS->VGAEngine == SIS_315_VGA) {
9219       setSISIDXREG(SISSR, 0x37, 0xFE, (base >> 24) & 0x01);
9220    }
9221    /* Eventually lock CRTC registers */
9222    setSISIDXREG(SISCR, 0x11, 0x7F,(cr11backup & 0x80));
9223}
9224
9225static void
9226SISSetStartAddressCRT2(SISPtr pSiS, ULong base)
9227{
9228    SiS_UnLockCRT2(pSiS->SiS_Pr);
9229    outSISIDXREG(SISPART1, 0x06, GETVAR8(base));
9230    outSISIDXREG(SISPART1, 0x05, GETBITS(base, 15:8));
9231    outSISIDXREG(SISPART1, 0x04, GETBITS(base, 23:16));
9232    if(pSiS->VGAEngine == SIS_315_VGA) {
9233       setSISIDXREG(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7);
9234    }
9235    SiS_LockCRT2(pSiS->SiS_Pr);
9236}
9237
9238#ifdef SISMERGED
9239static Bool
9240InRegion(int x, int y, region r)
9241{
9242    return (r.x0 <= x) && (x <= r.x1) && (r.y0 <= y) && (y <= r.y1);
9243}
9244
9245static void
9246SISAdjustFrameHW_CRT1(ScrnInfoPtr pScrn, int x, int y)
9247{
9248    SISPtr pSiS = SISPTR(pScrn);
9249    ULong base;
9250
9251    base = y * pSiS->CurrentLayout.displayWidth + x;
9252    switch(pSiS->CurrentLayout.bitsPerPixel) {
9253       case 16:  base >>= 1; 	break;
9254       case 32:  		break;
9255       default:  base >>= 2;
9256    }
9257    base += (pSiS->dhmOffset/4);
9258    SISSetStartAddressCRT1(pSiS, base);
9259}
9260
9261static void
9262SISAdjustFrameHW_CRT2(ScrnInfoPtr pScrn, int x, int y)
9263{
9264    SISPtr pSiS = SISPTR(pScrn);
9265    ULong base;
9266
9267    base = y * pSiS->CurrentLayout.displayWidth + x;
9268    switch(pSiS->CurrentLayout.bitsPerPixel) {
9269       case 16:  base >>= 1; 	break;
9270       case 32:  		break;
9271       default:  base >>= 2;
9272    }
9273    base += (pSiS->dhmOffset/4);
9274    SISSetStartAddressCRT2(pSiS, base);
9275}
9276
9277static void
9278SISMergedPointerMoved(SCRN_ARG_TYPE arg, int x, int y)
9279{
9280  SCRN_INFO_PTR(arg);
9281  ScrnInfoPtr	pScrn1 = pScrn;
9282  SISPtr	pSiS = SISPTR(pScrn1);
9283  ScrnInfoPtr	pScrn2 = pSiS->CRT2pScrn;
9284  region	out, in1, in2, f2, f1;
9285  int		deltax, deltay;
9286  int		temp1, temp2;
9287  int		old1x0, old1y0, old2x0, old2y0;
9288  int		CRT1XOffs = 0, CRT1YOffs = 0, CRT2XOffs = 0, CRT2YOffs = 0;
9289  int		HVirt = pScrn1->virtualX;
9290  int		VVirt = pScrn1->virtualY;
9291  int		sigstate;
9292  Bool		doit = FALSE, HaveNonRect = FALSE, HaveOffsRegions = FALSE;
9293  SiSScrn2Rel   srel = ((SiSMergedDisplayModePtr)pSiS->CurrentLayout.mode->Private)->CRT2Position;
9294
9295  if(pSiS->DGAactive) {
9296     return;
9297     /* DGA: There is no cursor and no panning while DGA is active. */
9298     /* If it were, we would need to do: */
9299     /* HVirt = pSiS->CurrentLayout.displayWidth;
9300        VVirt = pSiS->CurrentLayout.displayHeight;
9301        BOUND(x, pSiS->CurrentLayout.DGAViewportX, HVirt);
9302        BOUND(y, pSiS->CurrentLayout.DGAViewportY, VVirt); */
9303  } else {
9304     CRT1XOffs = pSiS->CRT1XOffs;
9305     CRT1YOffs = pSiS->CRT1YOffs;
9306     CRT2XOffs = pSiS->CRT2XOffs;
9307     CRT2YOffs = pSiS->CRT2YOffs;
9308     HaveNonRect = pSiS->HaveNonRect;
9309     HaveOffsRegions = pSiS->HaveOffsRegions;
9310  }
9311
9312  /* Check if the pointer is inside our dead areas */
9313  if((pSiS->MouseRestrictions) && (srel != sisClone) && !SiSnoPanoramiXExtension) {
9314     if(HaveNonRect) {
9315	if(InRegion(x, y, pSiS->NonRectDead)) {
9316	   switch(srel) {
9317	   case sisLeftOf:
9318	   case sisRightOf: y = pSiS->NonRectDead.y0 - 1;
9319			    doit = TRUE;
9320			    break;
9321	   case sisAbove:
9322	   case sisBelow:   x = pSiS->NonRectDead.x0 - 1;
9323			    doit = TRUE;
9324	   default:	    break;
9325	   }
9326	}
9327     }
9328     if(HaveOffsRegions) {
9329	if(InRegion(x, y, pSiS->OffDead1)) {
9330	   switch(srel) {
9331	   case sisLeftOf:
9332	   case sisRightOf: y = pSiS->OffDead1.y1;
9333			    doit = TRUE;
9334			    break;
9335	   case sisAbove:
9336	   case sisBelow:   x = pSiS->OffDead1.x1;
9337			    doit = TRUE;
9338	   default:	    break;
9339	   }
9340	} else if(InRegion(x, y, pSiS->OffDead2)) {
9341	   switch(srel) {
9342	   case sisLeftOf:
9343	   case sisRightOf: y = pSiS->OffDead2.y0 - 1;
9344			    doit = TRUE;
9345			    break;
9346	   case sisAbove:
9347	   case sisBelow:   x = pSiS->OffDead2.x0 - 1;
9348			    doit = TRUE;
9349	   default:	    break;
9350	   }
9351	}
9352     }
9353     if(doit) {
9354	sigstate = xf86BlockSIGIO();
9355#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 15
9356        {
9357            double dx = x, dy = y;
9358            miPointerSetPosition(inputInfo.pointer, Absolute, &dx, &dy);
9359            x = (int)dx;
9360            y = (int)dy;
9361        }
9362#elif GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 13
9363	miPointerSetPosition(inputInfo.pointer, Absolute, x, y);
9364#elif GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 5
9365	miPointerSetPosition(inputInfo.pointer, x, y);
9366#else
9367	UpdateCurrentTime();
9368	miPointerAbsoluteCursor(x, y, currentTime.milliseconds);
9369#endif
9370	xf86UnblockSIGIO(sigstate);
9371	return;
9372     }
9373  }
9374
9375  f1.x0 = old1x0 = pSiS->CRT1frameX0;
9376  f1.x1 = pSiS->CRT1frameX1;
9377  f1.y0 = old1y0 = pSiS->CRT1frameY0;
9378  f1.y1 = pSiS->CRT1frameY1;
9379  f2.x0 = old2x0 = pScrn2->frameX0;
9380  f2.x1 = pScrn2->frameX1;
9381  f2.y0 = old2y0 = pScrn2->frameY0;
9382  f2.y1 = pScrn2->frameY1;
9383
9384  /* Define the outer region. Crossing this causes all frames to move */
9385  out.x0 = pScrn1->frameX0;
9386  out.x1 = pScrn1->frameX1;
9387  out.y0 = pScrn1->frameY0;
9388  out.y1 = pScrn1->frameY1;
9389
9390  /*
9391   * Define the inner sliding window. Being outsize both frames but
9392   * inside the outer clipping window will slide corresponding frame
9393   */
9394  in1 = out;
9395  in2 = out;
9396  switch(srel) {
9397     case sisLeftOf:
9398        in1.x0 = f1.x0;
9399        in2.x1 = f2.x1;
9400        break;
9401     case sisRightOf:
9402        in1.x1 = f1.x1;
9403        in2.x0 = f2.x0;
9404        break;
9405     case sisBelow:
9406        in1.y1 = f1.y1;
9407        in2.y0 = f2.y0;
9408        break;
9409     case sisAbove:
9410        in1.y0 = f1.y0;
9411        in2.y1 = f2.y1;
9412        break;
9413     case sisClone:
9414        break;
9415  }
9416
9417  deltay = 0;
9418  deltax = 0;
9419
9420  if(InRegion(x, y, out)) {	/* inside outer region */
9421
9422     if(InRegion(x, y, in1) && !InRegion(x, y, f1)) {
9423	REBOUND(f1.x0, f1.x1, x);
9424	REBOUND(f1.y0, f1.y1, y);
9425	deltax = 1;
9426     }
9427     if(InRegion(x, y, in2) && !InRegion(x, y, f2)) {
9428	REBOUND(f2.x0, f2.x1, x);
9429	REBOUND(f2.y0, f2.y1, y);
9430	deltax = 1;
9431     }
9432
9433  } else {			/* outside outer region */
9434
9435     if(out.x0 > x) {
9436	deltax = x - out.x0;
9437     }
9438     if(out.x1 < x) {
9439	deltax = x - out.x1;
9440     }
9441     if(deltax) {
9442	pScrn1->frameX0 += deltax;
9443	pScrn1->frameX1 += deltax;
9444	f1.x0 += deltax;
9445	f1.x1 += deltax;
9446	f2.x0 += deltax;
9447	f2.x1 += deltax;
9448     }
9449
9450     if(out.y0 > y) {
9451	deltay = y - out.y0;
9452     }
9453     if(out.y1 < y) {
9454	deltay = y - out.y1;
9455     }
9456     if(deltay) {
9457	pScrn1->frameY0 += deltay;
9458	pScrn1->frameY1 += deltay;
9459	f1.y0 += deltay;
9460	f1.y1 += deltay;
9461	f2.y0 += deltay;
9462	f2.y1 += deltay;
9463     }
9464
9465     switch(srel) {
9466	case sisLeftOf:
9467	   if(x >= f1.x0) { REBOUND(f1.y0, f1.y1, y); }
9468	   if(x <= f2.x1) { REBOUND(f2.y0, f2.y1, y); }
9469	   break;
9470	case sisRightOf:
9471	   if(x <= f1.x1) { REBOUND(f1.y0, f1.y1, y); }
9472	   if(x >= f2.x0) { REBOUND(f2.y0, f2.y1, y); }
9473	   break;
9474	case sisBelow:
9475	   if(y <= f1.y1) { REBOUND(f1.x0, f1.x1, x); }
9476	   if(y >= f2.y0) { REBOUND(f2.x0, f2.x1, x); }
9477	   break;
9478	case sisAbove:
9479	   if(y >= f1.y0) { REBOUND(f1.x0, f1.x1, x); }
9480	   if(y <= f2.y1) { REBOUND(f2.x0, f2.x1, x); }
9481	   break;
9482	case sisClone:
9483	   break;
9484     }
9485
9486  }
9487
9488  if(deltax || deltay) {
9489     pSiS->CRT1frameX0 = f1.x0;
9490     pSiS->CRT1frameY0 = f1.y0;
9491     pScrn2->frameX0 = f2.x0;
9492     pScrn2->frameY0 = f2.y0;
9493
9494     switch(srel) {
9495	case sisLeftOf:
9496	case sisRightOf:
9497	   if(CRT1YOffs || CRT2YOffs || HaveNonRect) {
9498	      if(pSiS->CRT1frameY0 != old1y0) {
9499	         if(pSiS->CRT1frameY0 < CRT1YOffs)
9500	            pSiS->CRT1frameY0 = CRT1YOffs;
9501
9502	         temp1 = pSiS->CRT1frameY0 + CDMPTR->CRT1->VDisplay;
9503	         temp2 = min((VVirt - CRT2YOffs), (CRT1YOffs + pSiS->MBXNR1YMAX));
9504	         if(temp1 > temp2)
9505	            pSiS->CRT1frameY0 -= (temp1 - temp2);
9506	      }
9507	      if(pScrn2->frameY0 != old2y0) {
9508	         if(pScrn2->frameY0 < CRT2YOffs)
9509	            pScrn2->frameY0 = CRT2YOffs;
9510
9511	         temp1 = pScrn2->frameY0 + CDMPTR->CRT2->VDisplay;
9512	         temp2 = min((VVirt - CRT1YOffs), (CRT2YOffs + pSiS->MBXNR2YMAX));
9513	         if(temp1 > temp2)
9514	            pScrn2->frameY0 -= (temp1 - temp2);
9515	      }
9516	   }
9517	   break;
9518	case sisBelow:
9519	case sisAbove:
9520	   if(CRT1XOffs || CRT2XOffs || HaveNonRect) {
9521	      if(pSiS->CRT1frameX0 != old1x0) {
9522	         if(pSiS->CRT1frameX0 < CRT1XOffs)
9523	            pSiS->CRT1frameX0 = CRT1XOffs;
9524
9525	         temp1 = pSiS->CRT1frameX0 + CDMPTR->CRT1->HDisplay;
9526	         temp2 = min((HVirt - CRT2XOffs), (CRT1XOffs + pSiS->MBXNR1XMAX));
9527	         if(temp1 > temp2)
9528	            pSiS->CRT1frameX0 -= (temp1 - temp2);
9529	      }
9530	      if(pScrn2->frameX0 != old2x0) {
9531	         if(pScrn2->frameX0 < CRT2XOffs)
9532	            pScrn2->frameX0 = CRT2XOffs;
9533
9534	         temp1 = pScrn2->frameX0 + CDMPTR->CRT2->HDisplay;
9535	         temp2 = min((HVirt - CRT1XOffs), (CRT2XOffs + pSiS->MBXNR2XMAX));
9536	         if(temp1 > temp2)
9537	            pScrn2->frameX0 -= (temp1 - temp2);
9538	      }
9539	   }
9540	   break;
9541	case sisClone:
9542	   break;
9543     }
9544
9545     pSiS->CRT1frameX1 = pSiS->CRT1frameX0 + CDMPTR->CRT1->HDisplay - 1;
9546     pSiS->CRT1frameY1 = pSiS->CRT1frameY0 + CDMPTR->CRT1->VDisplay - 1;
9547     pScrn2->frameX1   = pScrn2->frameX0   + CDMPTR->CRT2->HDisplay - 1;
9548     pScrn2->frameY1   = pScrn2->frameY0   + CDMPTR->CRT2->VDisplay - 1;
9549
9550     /* No need to update pScrn1->frame?1, done above */
9551
9552     SISAdjustFrameHW_CRT1(pScrn1, pSiS->CRT1frameX0, pSiS->CRT1frameY0);
9553     SISAdjustFrameHW_CRT2(pScrn1, pScrn2->frameX0, pScrn2->frameY0);
9554  }
9555}
9556
9557static void
9558SISAdjustFrameMerged(ADJUST_FRAME_ARGS_DECL)
9559{
9560    SCRN_INFO_PTR(arg);
9561    ScrnInfoPtr pScrn1 = pScrn;
9562    SISPtr pSiS = SISPTR(pScrn1);
9563    ScrnInfoPtr pScrn2 = pSiS->CRT2pScrn;
9564    int HTotal = pSiS->CurrentLayout.mode->HDisplay;
9565    int VTotal = pSiS->CurrentLayout.mode->VDisplay;
9566    int HMax = HTotal;
9567    int VMax = VTotal;
9568    int HVirt = pScrn1->virtualX;
9569    int VVirt = pScrn1->virtualY;
9570    int x1 = x, x2 = x;
9571    int y1 = y, y2 = y;
9572    int CRT1XOffs = 0, CRT1YOffs = 0, CRT2XOffs = 0, CRT2YOffs = 0;
9573    int MBXNR1XMAX = 65536, MBXNR1YMAX = 65536, MBXNR2XMAX = 65536, MBXNR2YMAX = 65536;
9574
9575    if(pSiS->DGAactive) {
9576       HVirt = pSiS->CurrentLayout.displayWidth;
9577       VVirt = pSiS->CurrentLayout.displayHeight;
9578    } else {
9579       CRT1XOffs = pSiS->CRT1XOffs;
9580       CRT1YOffs = pSiS->CRT1YOffs;
9581       CRT2XOffs = pSiS->CRT2XOffs;
9582       CRT2YOffs = pSiS->CRT2YOffs;
9583       MBXNR1XMAX = pSiS->MBXNR1XMAX;
9584       MBXNR1YMAX = pSiS->MBXNR1YMAX;
9585       MBXNR2XMAX = pSiS->MBXNR2XMAX;
9586       MBXNR2YMAX = pSiS->MBXNR2YMAX;
9587    }
9588
9589    BOUND(x, 0, HVirt - HTotal);
9590    BOUND(y, 0, VVirt - VTotal);
9591    if(SDMPTR(pScrn1)->CRT2Position != sisClone) {
9592       BOUND(x1, CRT1XOffs, min(HVirt, MBXNR1XMAX + CRT1XOffs) - min(HTotal, MBXNR1XMAX) - CRT2XOffs);
9593       BOUND(y1, CRT1YOffs, min(VVirt, MBXNR1YMAX + CRT1YOffs) - min(VTotal, MBXNR1YMAX) - CRT2YOffs);
9594       BOUND(x2, CRT2XOffs, min(HVirt, MBXNR2XMAX + CRT2XOffs) - min(HTotal, MBXNR2XMAX) - CRT1XOffs);
9595       BOUND(y2, CRT2YOffs, min(VVirt, MBXNR2YMAX + CRT2YOffs) - min(VTotal, MBXNR2YMAX) - CRT1YOffs);
9596    }
9597
9598    switch(SDMPTR(pScrn1)->CRT2Position) {
9599        case sisLeftOf:
9600            pScrn2->frameX0 = x2;
9601            BOUND(pScrn2->frameY0,   y2, y2 + min(VMax, MBXNR2YMAX) - CDMPTR->CRT2->VDisplay);
9602            pSiS->CRT1frameX0 = x1 + CDMPTR->CRT2->HDisplay;
9603            BOUND(pSiS->CRT1frameY0, y1, y1 + min(VMax, MBXNR1YMAX) - CDMPTR->CRT1->VDisplay);
9604            break;
9605        case sisRightOf:
9606            pSiS->CRT1frameX0 = x1;
9607            BOUND(pSiS->CRT1frameY0, y1, y1 + min(VMax, MBXNR1YMAX) - CDMPTR->CRT1->VDisplay);
9608            pScrn2->frameX0 = x2 + CDMPTR->CRT1->HDisplay;
9609            BOUND(pScrn2->frameY0,   y2, y2 + min(VMax, MBXNR2YMAX) - CDMPTR->CRT2->VDisplay);
9610            break;
9611        case sisAbove:
9612            BOUND(pScrn2->frameX0,   x2, x2 + min(HMax, MBXNR2XMAX) - CDMPTR->CRT2->HDisplay);
9613            pScrn2->frameY0 = y2;
9614            BOUND(pSiS->CRT1frameX0, x1, x1 + min(HMax, MBXNR1XMAX) - CDMPTR->CRT1->HDisplay);
9615            pSiS->CRT1frameY0 = y1 + CDMPTR->CRT2->VDisplay;
9616            break;
9617        case sisBelow:
9618            BOUND(pSiS->CRT1frameX0, x1, x1 + min(HMax, MBXNR1XMAX) - CDMPTR->CRT1->HDisplay);
9619            pSiS->CRT1frameY0 = y1;
9620            BOUND(pScrn2->frameX0,   x2, x2 + min(HMax, MBXNR2XMAX) - CDMPTR->CRT2->HDisplay);
9621            pScrn2->frameY0 = y2 + CDMPTR->CRT1->VDisplay;
9622            break;
9623        case sisClone:
9624            BOUND(pSiS->CRT1frameX0, x,  x + HMax - CDMPTR->CRT1->HDisplay);
9625            BOUND(pSiS->CRT1frameY0, y,  y + VMax - CDMPTR->CRT1->VDisplay);
9626            BOUND(pScrn2->frameX0,   x,  x + HMax - CDMPTR->CRT2->HDisplay);
9627            BOUND(pScrn2->frameY0,   y,  y + VMax - CDMPTR->CRT2->VDisplay);
9628            break;
9629    }
9630
9631    BOUND(pSiS->CRT1frameX0, 0, HVirt - CDMPTR->CRT1->HDisplay);
9632    BOUND(pSiS->CRT1frameY0, 0, VVirt - CDMPTR->CRT1->VDisplay);
9633    BOUND(pScrn2->frameX0,   0, HVirt - CDMPTR->CRT2->HDisplay);
9634    BOUND(pScrn2->frameY0,   0, VVirt - CDMPTR->CRT2->VDisplay);
9635
9636    pScrn1->frameX0 = x;
9637    pScrn1->frameY0 = y;
9638
9639    pSiS->CRT1frameX1 = pSiS->CRT1frameX0 + CDMPTR->CRT1->HDisplay - 1;
9640    pSiS->CRT1frameY1 = pSiS->CRT1frameY0 + CDMPTR->CRT1->VDisplay - 1;
9641    pScrn2->frameX1   = pScrn2->frameX0   + CDMPTR->CRT2->HDisplay - 1;
9642    pScrn2->frameY1   = pScrn2->frameY0   + CDMPTR->CRT2->VDisplay - 1;
9643
9644    pScrn1->frameX1   = pScrn1->frameX0   + pSiS->CurrentLayout.mode->HDisplay  - 1;
9645    pScrn1->frameY1   = pScrn1->frameY0   + pSiS->CurrentLayout.mode->VDisplay  - 1;
9646    if(SDMPTR(pScrn1)->CRT2Position != sisClone) {
9647       pScrn1->frameX1 += CRT1XOffs + CRT2XOffs;
9648       pScrn1->frameY1 += CRT1YOffs + CRT2YOffs;
9649    }
9650
9651    SISAdjustFrameHW_CRT1(pScrn1, pSiS->CRT1frameX0, pSiS->CRT1frameY0);
9652    SISAdjustFrameHW_CRT2(pScrn1, pScrn2->frameX0, pScrn2->frameY0);
9653}
9654#endif
9655
9656/*
9657 * This function is used to initialize the Start Address - the first
9658 * displayed location in the video memory.
9659 *
9660 * Usually mandatory
9661 */
9662void
9663SISAdjustFrame(ADJUST_FRAME_ARGS_DECL)
9664{
9665    SCRN_INFO_PTR(arg);
9666    SISPtr        pSiS = SISPTR(pScrn);
9667    ULong base;
9668    UChar temp, cr11backup;
9669
9670#ifdef SISMERGED
9671    if(pSiS->MergedFB) {
9672        SISAdjustFrameMerged(ADJUST_FRAME_ARGS(pScrn, x, y));
9673	return;
9674    }
9675#endif
9676
9677    if(pSiS->UseVESA) {
9678	VBESetDisplayStart(pSiS->pVbe, x, y, TRUE);
9679	return;
9680    }
9681
9682    if(pScrn->bitsPerPixel < 8) {
9683       base = (y * pSiS->CurrentLayout.displayWidth + x + 3) >> 3;
9684    } else {
9685       base  = y * pSiS->CurrentLayout.displayWidth + x;
9686
9687       /* calculate base bpp dep. */
9688       switch(pSiS->CurrentLayout.bitsPerPixel) {
9689          case 16:
9690     	     base >>= 1;
9691             break;
9692          case 24:
9693             base = ((base * 3)) >> 2;
9694             base -= base % 6;
9695             break;
9696          case 32:
9697             break;
9698          default:      /* 8bpp */
9699             base >>= 2;
9700             break;
9701       }
9702    }
9703
9704#ifdef UNLOCK_ALWAYS
9705    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
9706#endif
9707
9708    base += (pSiS->dhmOffset/4);
9709
9710#ifdef TWDEBUG
9711    xf86DrvMsg(0, 0, "AdjustFrame: x %d y %d bpp %d dw %d base %d, dhmOffset %d\n",
9712    			x, y, pSiS->CurrentLayout.bitsPerPixel, pSiS->CurrentLayout.displayWidth, base, pSiS->dhmOffset);
9713#endif
9714
9715#ifdef SISDUALHEAD
9716    if(pSiS->DualHeadMode) {
9717       if(!pSiS->SecondHead) {
9718	  /* Head 1 (master) is always CRT2 */
9719	  SISSetStartAddressCRT2(pSiS, base);
9720       } else {
9721	  /* Head 2 (slave) is always CRT1 */
9722	  SISSetStartAddressCRT1(pSiS, base);
9723       }
9724    } else {
9725#endif
9726       switch(pSiS->VGAEngine) {
9727	  case SIS_300_VGA:
9728	  case SIS_315_VGA:
9729	     SISSetStartAddressCRT1(pSiS, base);
9730	     if(pSiS->VBFlags & CRT2_ENABLE) {
9731		if(!SiSBridgeIsInSlaveMode(pScrn)) {
9732		   SISSetStartAddressCRT2(pSiS, base);
9733		}
9734	     }
9735	     break;
9736	  default:
9737	     /* Unlock CRTC registers */
9738	     inSISIDXREG(SISCR,  0x11, cr11backup);
9739	     andSISIDXREG(SISCR, 0x11, 0x7F);
9740	     outSISIDXREG(SISCR, 0x0D, base & 0xFF);
9741	     outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF);
9742	     inSISIDXREG(SISSR,  0x27, temp);
9743	     temp &= 0xF0;
9744	     temp |= (base & 0x0F0000) >> 16;
9745	     outSISIDXREG(SISSR, 0x27, temp);
9746	     /* Eventually lock CRTC registers */
9747	     setSISIDXREG(SISCR, 0x11, 0x7F, (cr11backup & 0x80));
9748       }
9749#ifdef SISDUALHEAD
9750    }
9751#endif
9752
9753}
9754
9755/*
9756 * This is called when VT switching back to the X server.  Its job is
9757 * to reinitialise the video mode.
9758 * Mandatory!
9759 */
9760static Bool
9761SISEnterVT(VT_FUNC_ARGS_DECL)
9762{
9763    SCRN_INFO_PTR(arg);
9764    SISPtr pSiS = SISPTR(pScrn);
9765
9766    SiS_SiSFB_Lock(pScrn, TRUE);
9767
9768    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
9769
9770    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
9771       outSISIDXREG(SISCR,0x32,pSiS->myCR32);
9772       outSISIDXREG(SISCR,0x36,pSiS->myCR36);
9773       outSISIDXREG(SISCR,0x37,pSiS->myCR37);
9774    }
9775
9776    if(!SISModeInit(pScrn, pScrn->currentMode)) {
9777       SISErrorLog(pScrn, "SiSEnterVT: SISModeInit() failed\n");
9778       return FALSE;
9779    }
9780
9781    SISAdjustFrame(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0));
9782
9783#ifdef SISDRI
9784    if(pSiS->directRenderingEnabled) {
9785       DRIUnlock(xf86ScrnToScreen(pScrn));
9786    }
9787#endif
9788
9789#ifdef SISDUALHEAD
9790    if((!pSiS->DualHeadMode) || (!pSiS->SecondHead))
9791#endif
9792       if(pSiS->ResetXv) {
9793          (pSiS->ResetXv)(pScrn);
9794       }
9795
9796    return TRUE;
9797}
9798
9799/*
9800 * This is called when VT switching away from the X server.  Its job is
9801 * to restore the previous (text) mode.
9802 * Mandatory!
9803 */
9804static void
9805SISLeaveVT(VT_FUNC_ARGS_DECL)
9806{
9807    SCRN_INFO_PTR(arg);
9808    SISPtr pSiS = SISPTR(pScrn);
9809#ifdef SISDRI
9810    ScreenPtr pScreen;
9811
9812    if(pSiS->directRenderingEnabled) {
9813       pScreen = xf86ScrnToScreen(pScrn);
9814       DRILock(pScreen, 0);
9815    }
9816#endif
9817
9818#ifdef SISDUALHEAD
9819    if(pSiS->DualHeadMode && pSiS->SecondHead) return;
9820#endif
9821
9822    if(pSiS->CursorInfoPtr) {
9823#ifdef SISDUALHEAD
9824       if(pSiS->DualHeadMode) {
9825          if(!pSiS->SecondHead) {
9826	     pSiS->ForceCursorOff = TRUE;
9827	     pSiS->CursorInfoPtr->HideCursor(pScrn);
9828	     SISWaitVBRetrace(pScrn);
9829	     pSiS->ForceCursorOff = FALSE;
9830	  }
9831       } else {
9832#endif
9833          pSiS->CursorInfoPtr->HideCursor(pScrn);
9834          SISWaitVBRetrace(pScrn);
9835#ifdef SISDUALHEAD
9836       }
9837#endif
9838    }
9839
9840    SISBridgeRestore(pScrn);
9841
9842    if(pSiS->UseVESA) {
9843
9844       /* This is a q&d work-around for a BIOS bug. In case we disabled CRT2,
9845    	* VBESaveRestore() does not restore CRT1. So we set any mode now,
9846	* because VBESetVBEMode correctly restores CRT1. Afterwards, we
9847	* can call VBESaveRestore to restore original mode.
9848	*/
9849       if((pSiS->VBFlags2 & VB2_VIDEOBRIDGE) && (!(pSiS->VBFlags & DISPTYPE_DISP2)))
9850	  VBESetVBEMode(pSiS->pVbe, (pSiS->SISVESAModeList->n) | 0xc000, NULL);
9851
9852       SISVESARestore(pScrn);
9853
9854    } else {
9855
9856       SISRestore(pScrn);
9857
9858    }
9859
9860    /* We use (otherwise unused) bit 7 to indicate that we are running
9861     * to keep sisfb to change the displaymode (this would result in
9862     * lethal display corruption upon quitting X or changing to a VT
9863     * until a reboot)
9864     */
9865    if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
9866       orSISIDXREG(SISCR,0x34,0x80);
9867    }
9868
9869    SISVGALock(pSiS);
9870
9871    SiS_SiSFB_Lock(pScrn, FALSE);
9872}
9873
9874
9875/*
9876 * This is called at the end of each server generation.  It restores the
9877 * original (text) mode.  It should really also unmap the video memory too.
9878 * Mandatory!
9879 */
9880static Bool
9881SISCloseScreen(CLOSE_SCREEN_ARGS_DECL)
9882{
9883    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
9884    SISPtr pSiS = SISPTR(pScrn);
9885#ifdef SISDUALHEAD
9886    SISEntPtr pSiSEnt = pSiS->entityPrivate;
9887#endif
9888
9889    if(pSiS->SiSCtrlExtEntry) {
9890       SiSCtrlExtUnregister(pSiS, pScrn->scrnIndex);
9891    }
9892
9893#ifdef SISDRI
9894    if(pSiS->directRenderingEnabled) {
9895       SISDRICloseScreen(pScreen);
9896       pSiS->directRenderingEnabled = FALSE;
9897    }
9898#endif
9899
9900    if(pScrn->vtSema) {
9901
9902        if(pSiS->CursorInfoPtr) {
9903#ifdef SISDUALHEAD
9904           if(pSiS->DualHeadMode) {
9905              if(!pSiS->SecondHead) {
9906	         pSiS->ForceCursorOff = TRUE;
9907	         pSiS->CursorInfoPtr->HideCursor(pScrn);
9908	         SISWaitVBRetrace(pScrn);
9909	         pSiS->ForceCursorOff = FALSE;
9910	      }
9911           } else {
9912#endif
9913             pSiS->CursorInfoPtr->HideCursor(pScrn);
9914             SISWaitVBRetrace(pScrn);
9915#ifdef SISDUALHEAD
9916           }
9917#endif
9918	}
9919
9920        SISBridgeRestore(pScrn);
9921
9922	if(pSiS->UseVESA) {
9923
9924	  /* This is a q&d work-around for a BIOS bug. In case we disabled CRT2,
9925    	   * VBESaveRestore() does not restore CRT1. So we set any mode now,
9926	   * because VBESetVBEMode correctly restores CRT1. Afterwards, we
9927	   * can call VBESaveRestore to restore original mode.
9928	   */
9929           if((pSiS->VBFlags2 & VB2_VIDEOBRIDGE) && (!(pSiS->VBFlags & DISPTYPE_DISP2)))
9930	      VBESetVBEMode(pSiS->pVbe, (pSiS->SISVESAModeList->n) | 0xc000, NULL);
9931
9932	   SISVESARestore(pScrn);
9933
9934	} else {
9935
9936	   SISRestore(pScrn);
9937
9938	}
9939
9940        SISVGALock(pSiS);
9941
9942    }
9943
9944    SiS_SiSFB_Lock(pScrn, FALSE);
9945
9946    /* We should restore the mode number in case vtsema = false as well,
9947     * but since we haven't register access then we can't do it. I think
9948     * I need to rework the save/restore stuff, like saving the video
9949     * status when returning to the X server and by that save me the
9950     * trouble if sisfb was started from a textmode VT while X was on.
9951     */
9952
9953    SISUnmapMem(pScrn);
9954#ifdef SIS_PC_PLATFORM
9955    SiSVGAUnmapMem(pScrn);
9956#endif
9957
9958#ifdef SISDUALHEAD
9959    if(pSiS->DualHeadMode) {
9960       pSiSEnt = pSiS->entityPrivate;
9961       pSiSEnt->refCount--;
9962    }
9963#endif
9964
9965    if(pSiS->pInt) {
9966       xf86FreeInt10(pSiS->pInt);
9967       pSiS->pInt = NULL;
9968    }
9969
9970#ifdef SIS_USE_XAA
9971    if(!pSiS->useEXA) {
9972       if(pSiS->AccelLinearScratch) {
9973          xf86FreeOffscreenLinear(pSiS->AccelLinearScratch);
9974          pSiS->AccelLinearScratch = NULL;
9975       }
9976       if(pSiS->AccelInfoPtr) {
9977          XAADestroyInfoRec(pSiS->AccelInfoPtr);
9978          pSiS->AccelInfoPtr = NULL;
9979       }
9980    }
9981#endif
9982
9983#ifdef SIS_USE_EXA
9984    if(pSiS->useEXA) {
9985       if(pSiS->EXADriverPtr) {
9986          exaDriverFini(pScreen);
9987          free(pSiS->EXADriverPtr);
9988          pSiS->EXADriverPtr = NULL;
9989          pSiS->exa_scratch = NULL;
9990       }
9991    }
9992#endif
9993
9994    if(pSiS->CursorInfoPtr) {
9995       xf86DestroyCursorInfoRec(pSiS->CursorInfoPtr);
9996       pSiS->CursorInfoPtr = NULL;
9997    }
9998
9999    if(pSiS->ShadowPtr) {
10000       free(pSiS->ShadowPtr);
10001       pSiS->ShadowPtr = NULL;
10002    }
10003
10004    if(pSiS->DGAModes) {
10005       free(pSiS->DGAModes);
10006       pSiS->DGAModes = NULL;
10007    }
10008
10009    if(pSiS->adaptor) {
10010       free(pSiS->adaptor);
10011       pSiS->adaptor = NULL;
10012       pSiS->ResetXv = pSiS->ResetXvGamma = pSiS->ResetXvDisplay = NULL;
10013    }
10014
10015    if(pSiS->blitadaptor) {
10016       free(pSiS->blitadaptor);
10017       pSiS->blitadaptor = NULL;
10018    }
10019
10020    if(pSiS->crt2gcolortable) {
10021       free(pSiS->crt2gcolortable);
10022       pSiS->crt2gcolortable = NULL;
10023    }
10024
10025    if(pSiS->crt2cindices) {
10026       free(pSiS->crt2cindices);
10027       pSiS->crt2cindices = NULL;
10028    }
10029
10030    pScrn->vtSema = FALSE;
10031
10032    /* Restore Blockhandler */
10033    pScreen->BlockHandler = pSiS->BlockHandler;
10034
10035    pScreen->CloseScreen = pSiS->CloseScreen;
10036
10037    return(*pScreen->CloseScreen)(CLOSE_SCREEN_ARGS);
10038}
10039
10040
10041/* Free up any per-generation data structures */
10042
10043/* Optional */
10044static void
10045SISFreeScreen(FREE_SCREEN_ARGS_DECL)
10046{
10047    SCRN_INFO_PTR(arg);
10048#ifdef SIS_NEED_MAP_IOP
10049    SISPtr pSiS = SISPTR(pScrn);
10050
10051    if(pSiS) {
10052#ifdef SISDUALHEAD
10053       SISEntPtr pSiSEnt = pSiS->entityPrivate;
10054       if(pSiSEnt) {
10055          pSiSEnt->forceUnmapIOPBase = TRUE;
10056       }
10057#endif
10058       SISUnmapIOPMem(pScrn);
10059    }
10060#endif
10061
10062    SISFreeRec(pScrn);
10063}
10064
10065
10066/* Checks if a mode is suitable for the selected chipset. */
10067
10068static ModeStatus
10069SISValidMode(SCRN_ARG_TYPE arg, DisplayModePtr mode, Bool verbose, int flags)
10070{
10071    SCRN_INFO_PTR(arg);
10072    SISPtr pSiS = SISPTR(pScrn);
10073
10074    if(pSiS->UseVESA) {
10075       if(SiSCalcVESAModeIndex(pScrn, mode))
10076	  return(MODE_OK);
10077       else
10078	  return(MODE_BAD);
10079    }
10080
10081    if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
10082#ifdef SISDUALHEAD
10083       if(pSiS->DualHeadMode) {
10084          if(pSiS->SecondHead) {
10085	     if(SiS_CheckModeCRT1(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
10086	        return(MODE_BAD);
10087	  } else {
10088	     if(SiS_CheckModeCRT2(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
10089	        return(MODE_BAD);
10090	  }
10091       } else
10092#endif
10093#ifdef SISMERGED
10094       if(pSiS->MergedFB) {
10095	  if(!mode->Private) {
10096	     if(!pSiS->CheckForCRT2) {
10097	        if(SiS_CheckModeCRT1(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
10098	           return(MODE_BAD);
10099	     } else {
10100	        if(SiS_CheckModeCRT2(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes2) < 0x14)
10101	           return(MODE_BAD);
10102	     }
10103	  } else {
10104	     if(SiS_CheckModeCRT1(pScrn, ((SiSMergedDisplayModePtr)mode->Private)->CRT1,
10105		                  pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
10106	        return(MODE_BAD);
10107
10108	     if(SiS_CheckModeCRT2(pScrn, ((SiSMergedDisplayModePtr)mode->Private)->CRT2,
10109		                  pSiS->VBFlags, pSiS->HaveCustomModes2) < 0x14)
10110	        return(MODE_BAD);
10111 	  }
10112       } else
10113#endif
10114       {
10115	  if(SiS_CheckModeCRT1(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
10116	     return(MODE_BAD);
10117
10118	  if(SiS_CheckModeCRT2(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
10119	     return(MODE_BAD);
10120       }
10121    }
10122
10123    return(MODE_OK);
10124}
10125
10126#ifdef DEBUG
10127static void
10128SiSDumpModeInfo(ScrnInfoPtr pScrn, DisplayModePtr mode)
10129{
10130    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Clock : %x\n", mode->Clock);
10131    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Display : %x\n", mode->CrtcHDisplay);
10132    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Blank Start : %x\n", mode->CrtcHBlankStart);
10133    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Sync Start : %x\n", mode->CrtcHSyncStart);
10134    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Sync End : %x\n", mode->CrtcHSyncEnd);
10135    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Blank End : %x\n", mode->CrtcHBlankEnd);
10136    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Total : %x\n", mode->CrtcHTotal);
10137    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Skew : %x\n", mode->CrtcHSkew);
10138    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz HAdjusted : %x\n", mode->CrtcHAdjusted);
10139    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Display : %x\n", mode->CrtcVDisplay);
10140    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Blank Start : %x\n", mode->CrtcVBlankStart);
10141    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Sync Start : %x\n", mode->CrtcVSyncStart);
10142    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Sync End : %x\n", mode->CrtcVSyncEnd);
10143    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Blank End : %x\n", mode->CrtcVBlankEnd);
10144    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Total : %x\n", mode->CrtcVTotal);
10145    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt VAdjusted : %x\n", mode->CrtcVAdjusted);
10146}
10147#endif
10148
10149static void
10150SISModifyModeInfo(DisplayModePtr mode)
10151{
10152    if(mode->CrtcHBlankStart == mode->CrtcHDisplay)
10153        mode->CrtcHBlankStart++;
10154    if(mode->CrtcHBlankEnd == mode->CrtcHTotal)
10155        mode->CrtcHBlankEnd--;
10156    if(mode->CrtcVBlankStart == mode->CrtcVDisplay)
10157        mode->CrtcVBlankStart++;
10158    if(mode->CrtcVBlankEnd == mode->CrtcVTotal)
10159        mode->CrtcVBlankEnd--;
10160}
10161
10162/* Enable the Turboqueue/Commandqueue (For 300 and 315/330/340 series only) */
10163static void
10164SiSEnableTurboQueue(ScrnInfoPtr pScrn)
10165{
10166    SISPtr pSiS = SISPTR(pScrn);
10167    UShort SR26, SR27;
10168    ULong  temp;
10169
10170    switch(pSiS->VGAEngine) {
10171	case SIS_300_VGA:
10172	   if((!pSiS->NoAccel) && (pSiS->TurboQueue)) {
10173		/* TQ size is always 512k */
10174		temp = (pScrn->videoRam/64) - 8;
10175		SR26 = temp & 0xFF;
10176		inSISIDXREG(SISSR, 0x27, SR27);
10177		SR27 &= 0xFC;
10178		SR27 |= (0xF0 | ((temp >> 8) & 3));
10179		outSISIDXREG(SISSR, 0x26, SR26);
10180		outSISIDXREG(SISSR, 0x27, SR27);
10181	   }
10182	   break;
10183
10184	case SIS_315_VGA:
10185	   if(!pSiS->NoAccel) {
10186	      /* On 315/330/340 series, there are three queue modes available
10187	       * which are chosen by setting bits 7:5 in SR26:
10188	       * 1. MMIO queue mode (bit 5, 0x20). The hardware will keep
10189	       *    track of the queue, the FIFO, command parsing and so
10190	       *    on. This is the one comparable to the 300 series.
10191	       * 2. VRAM queue mode (bit 6, 0x40). In this case, one will
10192	       *    have to do queue management himself.
10193	       * 3. AGP queue mode (bit 7, 0x80). Works as 2., but keeps the
10194	       *    queue in AGP memory space.
10195	       * We go VRAM or MMIO here.
10196	       * SR26 bit 4 is called "Bypass H/W queue".
10197	       * SR26 bit 1 is called "Enable Command Queue Auto Correction"
10198	       * SR26 bit 0 resets the queue
10199	       * Size of queue memory is encoded in bits 3:2 like this:
10200	       *    00  (0x00)  512K
10201	       *    01  (0x04)  1M
10202	       *    10  (0x08)  2M
10203	       *    11  (0x0C)  4M
10204	       * The queue location is to be written to 0x85C0.
10205	       */
10206#ifdef SISVRAMQ
10207	      /* We use VRAM Cmd Queue, not MMIO or AGP */
10208	      UChar tempCR55 = 0;
10209
10210	      /* Set Command Queue Threshold to max value 11111b (?) */
10211	      outSISIDXREG(SISSR, 0x27, 0x1F);
10212
10213	      /* Disable queue flipping */
10214	      inSISIDXREG(SISCR, 0x55, tempCR55);
10215	      andSISIDXREG(SISCR, 0x55, 0x33);
10216	      /* Synchronous reset for Command Queue */
10217	      outSISIDXREG(SISSR, 0x26, 0x01);
10218	      SIS_MMIO_OUT32(pSiS->IOBase, 0x85c4, 0);
10219	      /* Enable VRAM Command Queue mode */
10220	      if(pSiS->ChipType == XGI_20) {
10221		 /* On XGI_20, always 128K */
10222		 SR26 = 0x40 | 0x04 | 0x01;
10223	      } else {
10224	         switch(pSiS->cmdQueueSize) {
10225		    case 1*1024*1024: SR26 = (0x40 | 0x04 | 0x01); break;
10226		    case 2*1024*1024: SR26 = (0x40 | 0x08 | 0x01); break;
10227		    case 4*1024*1024: SR26 = (0x40 | 0x0C | 0x01); break;
10228		    default:
10229		                      pSiS->cmdQueueSize = 512 * 1024;
10230		    case    512*1024: SR26 = (0x40 | 0x00 | 0x01);
10231	         }
10232	      }
10233	      outSISIDXREG(SISSR, 0x26, SR26);
10234	      SR26 &= 0xfe;
10235	      outSISIDXREG(SISSR, 0x26, SR26);
10236	      *(pSiS->cmdQ_SharedWritePort) = (unsigned int)(SIS_MMIO_IN32(pSiS->IOBase, 0x85c8));
10237	      SIS_MMIO_OUT32(pSiS->IOBase, 0x85c4, (CARD32)(*(pSiS->cmdQ_SharedWritePort)));
10238	      SIS_MMIO_OUT32(pSiS->IOBase, 0x85C0, pSiS->cmdQueueOffset);
10239	      temp = (ULong)pSiS->RealFbBase;
10240#ifdef SISDUALHEAD
10241	      if(pSiS->DualHeadMode) {
10242	         SISEntPtr pSiSEnt = pSiS->entityPrivate;
10243	         temp = (ULong)pSiSEnt->RealFbBase;
10244	      }
10245#endif
10246	      temp += pSiS->cmdQueueOffset;
10247	      pSiS->cmdQueueBase = (unsigned int *)temp;
10248	      outSISIDXREG(SISCR, 0x55, tempCR55);
10249#ifdef TWDEBUG
10250	      xf86DrvMsg(0, 0, "CmdQueueOffs 0x%x, CmdQueueAdd %p, shwrp 0x%x, status %x, base %p\n",
10251		pSiS->cmdQueueOffset, pSiS->cmdQueueBase, *(pSiS->cmdQ_SharedWritePort),
10252		SIS_MMIO_IN32(pSiS->IOBase, 0x85cc), (ULong *)temp);
10253#endif
10254#else
10255	      /* For MMIO */
10256	      /* Syncronous reset for Command Queue */
10257	      orSISIDXREG(SISSR, 0x26, 0x01);
10258	      /* Set Command Queue Threshold to max value 11111b */
10259	      outSISIDXREG(SISSR, 0x27, 0x1F);
10260	      /* Do some magic (cp readport to writeport) */
10261	      temp = SIS_MMIO_IN32(pSiS->IOBase, 0x85C8);
10262	      SIS_MMIO_OUT32(pSiS->IOBase, 0x85C4, temp);
10263	      /* Enable MMIO Command Queue mode (0x20),
10264	       * Enable_command_queue_auto_correction (0x02)
10265	       *        (no idea, but sounds good, so use it)
10266	       * 512k (0x00) (does this apply to MMIO mode?) */
10267	      outSISIDXREG(SISSR, 0x26, 0x22);
10268	      /* Calc Command Queue position (Q is always 512k)*/
10269	      temp = (pScrn->videoRam - 512) * 1024;
10270	      /* Set Q position */
10271	      SIS_MMIO_OUT32(pSiS->IOBase, 0x85C0, temp);
10272#endif
10273	   }
10274	   break;
10275	default:
10276	   break;
10277    }
10278}
10279
10280#ifdef SISVRAMQ
10281static void
10282SiSRestoreQueueMode(SISPtr pSiS, SISRegPtr sisReg)
10283{
10284    UChar tempCR55=0;
10285
10286    if(pSiS->VGAEngine == SIS_315_VGA) {
10287       inSISIDXREG(SISCR,0x55,tempCR55);
10288       andSISIDXREG(SISCR,0x55,0x33);
10289       outSISIDXREG(SISSR,0x26,0x01);
10290       SIS_MMIO_OUT32(pSiS->IOBase, 0x85c4, 0);
10291       outSISIDXREG(SISSR,0x27,sisReg->sisRegs3C4[0x27]);
10292       outSISIDXREG(SISSR,0x26,sisReg->sisRegs3C4[0x26]);
10293       SIS_MMIO_OUT32(pSiS->IOBase, 0x85C0, sisReg->sisMMIO85C0);
10294       outSISIDXREG(SISCR,0x55,tempCR55);
10295    }
10296}
10297#endif
10298
10299/* Things to do before a ModeSwitch. We set up the
10300 * video bridge configuration and the TurboQueue.
10301 */
10302void SiSPreSetMode(ScrnInfoPtr pScrn, DisplayModePtr mode, int viewmode)
10303{
10304    SISPtr pSiS = SISPTR(pScrn);
10305    UChar  CR30, CR31, CR32, CR33;
10306    UChar  CR39 = 0, CR3B = 0;
10307    UChar  CR17, CR38 = 0;
10308    UChar  CR35 = 0, CR79 = 0;
10309    int    temp = 0, crt1rateindex = 0;
10310    ULong  vbflag = pSiS->VBFlags;
10311    Bool   hcm = pSiS->HaveCustomModes;
10312    DisplayModePtr mymode = mode;
10313
10314    pSiS->IsCustom = FALSE;
10315
10316    /* NEVER call this with viewmode = SIS_MODE_SIMU
10317     * if mode->type is not M_T_DEFAULT!
10318     */
10319
10320#ifdef SISMERGED
10321    if(pSiS->MergedFB) {
10322       switch(viewmode) {
10323       case SIS_MODE_CRT1:
10324	  mymode = ((SiSMergedDisplayModePtr)mode->Private)->CRT1;
10325	  break;
10326       case SIS_MODE_CRT2:
10327	  mymode = ((SiSMergedDisplayModePtr)mode->Private)->CRT2;
10328	  hcm = pSiS->HaveCustomModes2;
10329       }
10330    }
10331#endif
10332
10333    switch(viewmode) {
10334    case SIS_MODE_CRT1:
10335       if(SiS_CheckModeCRT1(pScrn, mymode, vbflag, hcm) == 0xfe) {
10336          pSiS->IsCustom = TRUE;
10337       }
10338       break;
10339    case SIS_MODE_CRT2:
10340       if(vbflag & CRT2_ENABLE) {
10341          if(SiS_CheckModeCRT2(pScrn, mymode, vbflag, hcm) == 0xfe) {
10342	     pSiS->IsCustom = TRUE;
10343          }
10344       } else {
10345          /* This can only happen in mirror mode */
10346          if(SiS_CheckModeCRT1(pScrn, mymode, vbflag, hcm) == 0xfe) {
10347             pSiS->IsCustom = TRUE;
10348          }
10349       }
10350    }
10351
10352#ifdef UNLOCK_ALWAYS
10353    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);    /* Unlock Registers */
10354#endif
10355
10356    inSISIDXREG(SISCR, 0x30, CR30);
10357    inSISIDXREG(SISCR, 0x31, CR31);
10358    CR32 = pSiS->newCR32;
10359    inSISIDXREG(SISCR, 0x33, CR33);
10360
10361    if(pSiS->NewCRLayout) {
10362
10363       inSISIDXREG(SISCR, 0x35, CR35);
10364       inSISIDXREG(SISCR, 0x38, CR38);
10365       inSISIDXREG(SISCR, 0x39, CR39);
10366
10367       xf86DrvMsgVerb(pScrn->scrnIndex, X_PROBED, SISVERBLEVEL,
10368	   "Before: CR30=0x%02x,CR31=0x%02x,CR32=0x%02x,CR33=0x%02x,CR35=0x%02x,CR38=0x%02x\n",
10369              CR30, CR31, CR32, CR33, CR35, CR38);
10370
10371       CR38 &= ~0x07;
10372
10373    } else {
10374
10375       if(pSiS->Chipset != PCI_CHIP_SIS300) {
10376          switch(pSiS->VGAEngine) {
10377             case SIS_300_VGA: temp = 0x35; break;
10378             case SIS_315_VGA: temp = 0x38; break;
10379          }
10380          if(temp) inSISIDXREG(SISCR, temp, CR38);
10381       }
10382       if(pSiS->VGAEngine == SIS_315_VGA) {
10383          inSISIDXREG(SISCR, 0x79, CR79);
10384          CR38 &= ~0x3b;   			/* Clear LCDA/DualEdge and YPbPr bits */
10385       }
10386       inSISIDXREG(SISCR, 0x3b, CR3B);
10387
10388       xf86DrvMsgVerb(pScrn->scrnIndex, X_PROBED, SISVERBLEVEL,
10389	   "Before: CR30=0x%02x, CR31=0x%02x, CR32=0x%02x, CR33=0x%02x, CR%02x=0x%02x\n",
10390              CR30, CR31, CR32, CR33, temp, CR38);
10391    }
10392
10393    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, SISVERBLEVEL, "VBFlags=0x%x\n", pSiS->VBFlags);
10394
10395    CR30 = 0x00;
10396    CR31 &= ~0x60;  /* Clear VB_Drivermode & VB_OutputDisable */
10397    CR31 |= 0x04;   /* Set VB_NotSimuMode (not for 30xB/1400x1050?) */
10398    CR35 = 0x00;
10399
10400    if(!pSiS->NewCRLayout) {
10401       if(!pSiS->AllowHotkey) {
10402          CR31 |= 0x80;   /* Disable hotkey-switch */
10403       }
10404       CR79 &= ~0x10;     /* Enable Backlight control on 315 series */
10405    }
10406
10407    SiS_SetEnableDstn(pSiS->SiS_Pr, FALSE);
10408    SiS_SetEnableFstn(pSiS->SiS_Pr, FALSE);
10409
10410    if((vbflag & CRT1_LCDA) && (viewmode == SIS_MODE_CRT1)) {
10411
10412       CR38 |= 0x02;
10413
10414    } else {
10415
10416       switch(vbflag & (CRT2_TV|CRT2_LCD|CRT2_VGA)) {
10417
10418       case CRT2_TV:
10419
10420          CR38 &= ~0xC0; 	/* Clear Pal M/N bits */
10421
10422          if((pSiS->VBFlags2 & VB2_CHRONTEL) && (vbflag & TV_CHSCART)) {		/* Chrontel */
10423	     CR30 |= 0x10;
10424	     CR38 |= 0x04;
10425	     CR38 &= ~0x08;
10426	     CR31 |= 0x01;
10427	  } else if((pSiS->VBFlags2 & VB2_CHRONTEL) && (vbflag & TV_CHYPBPR525I)) {	/* Chrontel */
10428	     CR38 |= 0x08;
10429	     CR38 &= ~0x04;
10430	     CR31 &= ~0x01;
10431          } else if(vbflag & TV_HIVISION) {	/* SiS bridge */
10432	     if(pSiS->NewCRLayout) {
10433	        CR38 |= 0x04;
10434	        CR35 |= 0x60;
10435	     } else {
10436	        CR30 |= 0x80;
10437		if(pSiS->VGAEngine == SIS_315_VGA) {
10438		   if(pSiS->VBFlags2 & VB2_SISYPBPRBRIDGE) {
10439		      CR38 |= (0x08 | 0x30);
10440		   }
10441		}
10442	     }
10443	     CR31 |= 0x01;
10444	     CR35 |= 0x01;
10445	  } else if(vbflag & TV_YPBPR) {					/* SiS bridge */
10446	     if(pSiS->NewCRLayout) {
10447		CR38 |= 0x04;
10448		CR31 &= ~0x01;
10449		CR35 &= ~0x01;
10450		if(vbflag & (TV_YPBPR525P | TV_YPBPR625P)) CR35 |= 0x20;
10451		else if(vbflag & TV_YPBPR750P)             CR35 |= 0x40;
10452		else if(vbflag & TV_YPBPR1080I)            CR35 |= 0x60;
10453
10454		if(vbflag & (TV_YPBPR625I | TV_YPBPR625P)) {
10455		   CR31 |= 0x01;
10456		   CR35 |= 0x01;
10457		}
10458
10459		CR39 &= ~0x03;
10460		if((vbflag & TV_YPBPRAR) == TV_YPBPR43LB)     CR39 |= 0x00;
10461		else if((vbflag & TV_YPBPRAR) == TV_YPBPR43)  CR39 |= 0x01;
10462		else if((vbflag & TV_YPBPRAR) == TV_YPBPR169) CR39 |= 0x02;
10463		else					      CR39 |= 0x03;
10464	     } else if(pSiS->SiS_SD_Flags & SiS_SD_SUPPORTYPBPR) {
10465		CR30 |= 0x80;
10466		CR38 |= 0x08;
10467		CR31 &= ~0x01;
10468		if(vbflag & (TV_YPBPR525P|TV_YPBPR625P)) CR38 |= 0x10;
10469		else if(vbflag & TV_YPBPR750P)  	 CR38 |= 0x20;
10470		else if(vbflag & TV_YPBPR1080I)		 CR38 |= 0x30;
10471
10472		if(vbflag & (TV_YPBPR625I | TV_YPBPR625P)) CR31 |= 0x01;
10473
10474		if(pSiS->SiS_SD_Flags & SiS_SD_SUPPORTYPBPRAR) {
10475		   CR3B &= ~0x03;
10476		   if((vbflag & TV_YPBPRAR) == TV_YPBPR43LB)     CR3B |= 0x00;
10477		   else if((vbflag & TV_YPBPRAR) == TV_YPBPR43)  CR3B |= 0x03;
10478		   else if((vbflag & TV_YPBPRAR) == TV_YPBPR169) CR3B |= 0x01;
10479		   else					         CR3B |= 0x03;
10480		}
10481	     }
10482          } else {								/* All */
10483	     if(vbflag & TV_SCART)  CR30 |= 0x10;
10484	     if(vbflag & TV_SVIDEO) CR30 |= 0x08;
10485	     if(vbflag & TV_AVIDEO) CR30 |= 0x04;
10486	     if(!(CR30 & 0x1C))	    CR30 |= 0x08;    /* default: SVIDEO */
10487
10488	     if(vbflag & TV_PAL) {
10489		CR31 |= 0x01;
10490		CR35 |= 0x01;
10491		if( (pSiS->VBFlags2 & VB2_SISBRIDGE) ||
10492		    ((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->ChrontelType == CHRONTEL_701x)) )  {
10493		   if(vbflag & TV_PALM) {
10494		      CR38 |= 0x40;
10495		      CR35 |= 0x04;
10496		   } else if(vbflag & TV_PALN) {
10497		      CR38 |= 0x80;
10498		      CR35 |= 0x08;
10499		   }
10500	        }
10501	     } else {
10502		CR31 &= ~0x01;
10503		CR35 &= ~0x01;
10504		if(vbflag & TV_NTSCJ) {
10505		   CR38 |= 0x40;  /* TW, not BIOS */
10506		   CR35 |= 0x02;
10507		}
10508	     }
10509	     if(vbflag & TV_SCART) {
10510		CR31 |= 0x01;
10511		CR35 |= 0x01;
10512	     }
10513	  }
10514
10515	  CR31 &= ~0x04;   /* Clear NotSimuMode */
10516	  pSiS->SiS_Pr->SiS_CHOverScan = pSiS->UseCHOverScan;
10517	  if((pSiS->OptTVSOver == 1) && (pSiS->ChrontelType == CHRONTEL_700x)) {
10518	     pSiS->SiS_Pr->SiS_CHSOverScan = TRUE;
10519	  } else {
10520	     pSiS->SiS_Pr->SiS_CHSOverScan = FALSE;
10521	  }
10522#ifdef SIS_CP
10523	  SIS_CP_DRIVER_CONFIG
10524#endif
10525	  break;
10526
10527       case CRT2_LCD:
10528	  CR30 |= 0x20;
10529	  SiS_SetEnableDstn(pSiS->SiS_Pr, pSiS->DSTN);
10530	  SiS_SetEnableFstn(pSiS->SiS_Pr, pSiS->FSTN);
10531	  break;
10532
10533       case CRT2_VGA:
10534	  CR30 |= 0x40;
10535	  break;
10536
10537       default:
10538	  CR30 |= 0x00;
10539	  CR31 |= 0x20;    /* VB_OUTPUT_DISABLE */
10540	  if(pSiS->UseVESA) {
10541	     crt1rateindex = SISSearchCRT1Rate(pScrn, mymode);
10542	  }
10543       }
10544
10545    }
10546
10547    if(vbflag & CRT1_LCDA) {
10548       switch(viewmode) {
10549       case SIS_MODE_CRT1:
10550	  CR38 |= 0x01;
10551	  break;
10552       case SIS_MODE_CRT2:
10553	  if(vbflag & (CRT2_TV|CRT2_VGA)) {
10554	     CR30 |= 0x02;
10555	     CR38 |= 0x01;
10556	  } else {
10557	     CR38 |= 0x03;
10558	  }
10559	  break;
10560       case SIS_MODE_SIMU:
10561       default:
10562	  if(vbflag & (CRT2_TV|CRT2_LCD|CRT2_VGA)) {
10563	     CR30 |= 0x01;
10564	  }
10565	  break;
10566       }
10567    } else {
10568       if(vbflag & (CRT2_TV|CRT2_LCD|CRT2_VGA)) {
10569          CR30 |= 0x01;
10570       }
10571    }
10572
10573    if(pSiS->UseVESA) {
10574       CR31 &= ~0x40;   /* Clear Drivermode */
10575       CR31 |= 0x06;    /* Set SlaveMode, Enable SimuMode in Slavemode */
10576#ifdef TWDEBUG
10577       CR31 |= 0x40;    /* DEBUG (for non-slave mode VESA) */
10578       crt1rateindex = SISSearchCRT1Rate(pScrn, mymode);
10579#endif
10580    } else {
10581       CR31 |=  0x40;  /* Set Drivermode */
10582       CR31 &=  ~0x06; /* Disable SlaveMode, disable SimuMode in SlaveMode */
10583       if(!pSiS->IsCustom) {
10584          crt1rateindex = SISSearchCRT1Rate(pScrn, mymode);
10585       }
10586    }
10587
10588    switch(viewmode) {
10589	case SIS_MODE_SIMU:
10590	   CR33 = 0;
10591	   if(!(vbflag & CRT1_LCDA)) {
10592	      CR33 |= (crt1rateindex & 0x0f);
10593	   }
10594	   if(vbflag & CRT2_VGA) {
10595	      CR33 |= ((crt1rateindex & 0x0f) << 4);
10596	   }
10597	   break;
10598	case SIS_MODE_CRT1:
10599	   CR33 &= 0xf0;
10600	   if(!(vbflag & CRT1_LCDA)) {
10601	      CR33 |= (crt1rateindex & 0x0f);
10602	   }
10603	   break;
10604	case SIS_MODE_CRT2:
10605	   CR33 &= 0x0f;
10606	   if(vbflag & CRT2_VGA) {
10607	      CR33 |= ((crt1rateindex & 0x0f) << 4);
10608	   }
10609	   break;
10610     }
10611
10612     if((!pSiS->UseVESA) && (vbflag & CRT2_ENABLE)) {
10613	if(pSiS->CRT1off) CR33 &= 0xf0;
10614     }
10615
10616     if(pSiS->NewCRLayout) {
10617
10618	CR31 &= 0xfe;   /* Clear PAL flag (now in CR35) */
10619	CR38 &= 0x07;   /* Use only LCDA and HiVision/YPbPr bits */
10620	outSISIDXREG(SISCR, 0x30, CR30);
10621	outSISIDXREG(SISCR, 0x31, CR31);
10622	outSISIDXREG(SISCR, 0x33, CR33);
10623	outSISIDXREG(SISCR, 0x35, CR35);
10624	setSISIDXREG(SISCR, 0x38, 0xf8, CR38);
10625	outSISIDXREG(SISCR, 0x39, CR39);
10626
10627	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, SISVERBLEVEL,
10628		"After:  CR30=0x%02x,CR31=0x%02x,CR33=0x%02x,CR35=0x%02x,CR38=%02x\n",
10629		    CR30, CR31, CR33, CR35, CR38);
10630
10631     } else {
10632
10633	outSISIDXREG(SISCR, 0x30, CR30);
10634	outSISIDXREG(SISCR, 0x31, CR31);
10635	outSISIDXREG(SISCR, 0x33, CR33);
10636	if(temp) {
10637	   outSISIDXREG(SISCR, temp, CR38);
10638	}
10639	if(pSiS->VGAEngine == SIS_315_VGA) {
10640	   outSISIDXREG(SISCR, 0x3b, CR3B);
10641	   outSISIDXREG(SISCR, 0x79, CR79);
10642	}
10643
10644	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, SISVERBLEVEL,
10645		"After:  CR30=0x%02x,CR31=0x%02x,CR33=0x%02x,CR%02x=%02x\n",
10646		    CR30, CR31, CR33, temp, CR38);
10647     }
10648
10649     pSiS->SiS_Pr->SiS_UseOEM = pSiS->OptUseOEM;
10650
10651     /* Enable TurboQueue */
10652#ifdef SISVRAMQ
10653     if(pSiS->VGAEngine != SIS_315_VGA)
10654#endif
10655	SiSEnableTurboQueue(pScrn);
10656
10657     if((!pSiS->UseVESA) && (pSiS->VBFlags & CRT2_ENABLE)) {
10658	/* Switch on CRT1 for modes that require the bridge in SlaveMode */
10659	andSISIDXREG(SISSR,0x1f,0x3f);
10660	inSISIDXREG(SISCR, 0x17, CR17);
10661	if(!(CR17 & 0x80)) {
10662	   orSISIDXREG(SISCR, 0x17, 0x80);
10663	   outSISIDXREG(SISSR, 0x00, 0x01);
10664	   usleep(10000);
10665	   outSISIDXREG(SISSR, 0x00, 0x03);
10666	}
10667     }
10668}
10669
10670/* Functions for adjusting various TV settings */
10671
10672/* These are used by the PostSetMode() functions as well as
10673 * the display properties tool SiSCtrl.
10674 *
10675 * There is each a Set and a Get routine. The Set functions
10676 * take a value of the same range as the corresponding option.
10677 * The Get routines return a value of the same range (although
10678 * not necessarily the same value as previously set because
10679 * of the lower resolution of the respective setting compared
10680 * to the valid range).
10681 * The Get routines return -2 on error (eg. hardware does not
10682 * support this setting).
10683 * Note: The x and y positioning routines accept a position
10684 * RELATIVE to the default position. All other routines
10685 * take ABSOLUTE values.
10686 *
10687 * The Set functions will store the property regardless if TV is
10688 * currently used or not and if the hardware supports the property
10689 * or not. The Get routines will return this stored
10690 * value if TV is not currently used (because the register does
10691 * not contain the correct value then) or if the hardware supports
10692 * the respective property. This should make it easier for the
10693 * display property tool because it does not have to know the
10694 * hardware features.
10695 *
10696 * All the routines are dual head aware. It does not matter
10697 * if the function is called from the CRT1 or CRT2 session.
10698 * The values will be in pSiSEnt anyway, and read from there
10699 * if we're running dual head.
10700 */
10701
10702void SiS_SetCHTVlumabandwidthcvbs(ScrnInfoPtr pScrn, int val)
10703{
10704   SISPtr pSiS = SISPTR(pScrn);
10705#ifdef SISDUALHEAD
10706   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10707#endif
10708
10709   pSiS->chtvlumabandwidthcvbs = val;
10710#ifdef SISDUALHEAD
10711   if(pSiSEnt) pSiSEnt->chtvlumabandwidthcvbs = val;
10712#endif
10713
10714   if(!(pSiS->VBFlags & CRT2_TV)) return;
10715   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
10716
10717#ifdef UNLOCK_ALWAYS
10718   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10719#endif
10720
10721   switch(pSiS->ChrontelType) {
10722       case CHRONTEL_700x:
10723           val /= 8;
10724           if((val == 0) || (val == 1)) {
10725	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, val, 0xFE);
10726           }
10727	   break;
10728       case CHRONTEL_701x:
10729           val /= 4;
10730	   if((val >= 0) && (val <= 3)) {
10731	       SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x02, val, 0xFC);
10732	   }
10733           break;
10734   }
10735}
10736
10737int SiS_GetCHTVlumabandwidthcvbs(ScrnInfoPtr pScrn)
10738{
10739   SISPtr pSiS = SISPTR(pScrn);
10740#ifdef SISDUALHEAD
10741   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10742#endif
10743
10744   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
10745#ifdef SISDUALHEAD
10746      if(pSiSEnt && pSiS->DualHeadMode)
10747           return (int)pSiSEnt->chtvlumabandwidthcvbs;
10748      else
10749#endif
10750           return (int)pSiS->chtvlumabandwidthcvbs;
10751   } else {
10752#ifdef UNLOCK_ALWAYS
10753      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10754#endif
10755      switch(pSiS->ChrontelType) {
10756      case CHRONTEL_700x:
10757           return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x03) & 0x01) * 8);
10758      case CHRONTEL_701x:
10759	   return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x02) & 0x03) * 4);
10760      default:
10761           return (int)pSiS->chtvlumabandwidthcvbs;
10762      }
10763   }
10764}
10765
10766void SiS_SetCHTVlumabandwidthsvideo(ScrnInfoPtr pScrn, int val)
10767{
10768   SISPtr pSiS = SISPTR(pScrn);
10769#ifdef SISDUALHEAD
10770   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10771#endif
10772
10773   pSiS->chtvlumabandwidthsvideo = val;
10774#ifdef SISDUALHEAD
10775   if(pSiSEnt) pSiSEnt->chtvlumabandwidthsvideo = val;
10776#endif
10777
10778   if(!(pSiS->VBFlags & CRT2_TV)) return;
10779   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
10780
10781#ifdef UNLOCK_ALWAYS
10782   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10783#endif
10784
10785   switch(pSiS->ChrontelType) {
10786       case CHRONTEL_700x:
10787           val /= 6;
10788           if((val >= 0) && (val <= 2)) {
10789	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, (val << 1), 0xF9);
10790           }
10791	   break;
10792       case CHRONTEL_701x:
10793           val /= 4;
10794	   if((val >= 0) && (val <= 3)) {
10795	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x02, (val << 2), 0xF3);
10796	   }
10797           break;
10798   }
10799}
10800
10801int SiS_GetCHTVlumabandwidthsvideo(ScrnInfoPtr pScrn)
10802{
10803   SISPtr pSiS = SISPTR(pScrn);
10804#ifdef SISDUALHEAD
10805   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10806#endif
10807
10808   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
10809#ifdef SISDUALHEAD
10810      if(pSiSEnt && pSiS->DualHeadMode)
10811           return (int)pSiSEnt->chtvlumabandwidthsvideo;
10812      else
10813#endif
10814           return (int)pSiS->chtvlumabandwidthsvideo;
10815   } else {
10816#ifdef UNLOCK_ALWAYS
10817      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10818#endif
10819      switch(pSiS->ChrontelType) {
10820      case CHRONTEL_700x:
10821           return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x03) & 0x06) >> 1) * 6);
10822      case CHRONTEL_701x:
10823	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x02) & 0x0c) >> 2) * 4);
10824      default:
10825           return (int)pSiS->chtvlumabandwidthsvideo;
10826      }
10827   }
10828}
10829
10830void SiS_SetCHTVlumaflickerfilter(ScrnInfoPtr pScrn, int val)
10831{
10832   SISPtr pSiS = SISPTR(pScrn);
10833#ifdef SISDUALHEAD
10834   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10835#endif
10836
10837   pSiS->chtvlumaflickerfilter = val;
10838#ifdef SISDUALHEAD
10839   if(pSiSEnt) pSiSEnt->chtvlumaflickerfilter = val;
10840#endif
10841
10842   if(!(pSiS->VBFlags & CRT2_TV)) return;
10843   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
10844
10845#ifdef UNLOCK_ALWAYS
10846   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10847#endif
10848
10849   switch(pSiS->ChrontelType) {
10850       case CHRONTEL_700x:
10851           val /= 6;
10852           if((val >= 0) && (val <= 2)) {
10853	      UShort reg = 0;
10854	      reg = SiS_GetCH70xx(pSiS->SiS_Pr, 0x01);
10855	      reg = (reg & 0xf0) | ((reg & 0x0c) >> 2) | (val << 2);
10856              SiS_SetCH70xx(pSiS->SiS_Pr, 0x01, reg);
10857           }
10858	   break;
10859       case CHRONTEL_701x:
10860           val /= 4;
10861	   if((val >= 0) && (val <= 3)) {
10862	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x01, (val << 2), 0xF3);
10863	   }
10864           break;
10865   }
10866}
10867
10868int SiS_GetCHTVlumaflickerfilter(ScrnInfoPtr pScrn)
10869{
10870   SISPtr pSiS = SISPTR(pScrn);
10871#ifdef SISDUALHEAD
10872   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10873#endif
10874
10875   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
10876#ifdef SISDUALHEAD
10877      if(pSiSEnt && pSiS->DualHeadMode)
10878          return (int)pSiSEnt->chtvlumaflickerfilter;
10879      else
10880#endif
10881          return (int)pSiS->chtvlumaflickerfilter;
10882   } else {
10883#ifdef UNLOCK_ALWAYS
10884      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10885#endif
10886      switch(pSiS->ChrontelType) {
10887      case CHRONTEL_700x:
10888           return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x01) & 0x03) * 6);
10889      case CHRONTEL_701x:
10890	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x01) & 0x0c) >> 2) * 4);
10891      default:
10892           return (int)pSiS->chtvlumaflickerfilter;
10893      }
10894   }
10895}
10896
10897void SiS_SetCHTVchromabandwidth(ScrnInfoPtr pScrn, int val)
10898{
10899   SISPtr pSiS = SISPTR(pScrn);
10900#ifdef SISDUALHEAD
10901   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10902#endif
10903
10904   pSiS->chtvchromabandwidth = val;
10905#ifdef SISDUALHEAD
10906   if(pSiSEnt) pSiSEnt->chtvchromabandwidth = val;
10907#endif
10908
10909   if(!(pSiS->VBFlags & CRT2_TV)) return;
10910   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
10911
10912#ifdef UNLOCK_ALWAYS
10913   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10914#endif
10915
10916   switch(pSiS->ChrontelType) {
10917       case CHRONTEL_700x:
10918           val /= 4;
10919           if((val >= 0) && (val <= 3)) {
10920              SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, (val << 4), 0xCF);
10921           }
10922	   break;
10923       case CHRONTEL_701x:
10924           val /= 8;
10925	   if((val >= 0) && (val <= 1)) {
10926	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x02, (val << 4), 0xEF);
10927	   }
10928           break;
10929   }
10930}
10931
10932int SiS_GetCHTVchromabandwidth(ScrnInfoPtr pScrn)
10933{
10934   SISPtr pSiS = SISPTR(pScrn);
10935#ifdef SISDUALHEAD
10936   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10937#endif
10938
10939   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
10940#ifdef SISDUALHEAD
10941      if(pSiSEnt && pSiS->DualHeadMode)
10942           return (int)pSiSEnt->chtvchromabandwidth;
10943      else
10944#endif
10945           return (int)pSiS->chtvchromabandwidth;
10946   } else {
10947#ifdef UNLOCK_ALWAYS
10948      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10949#endif
10950      switch(pSiS->ChrontelType) {
10951      case CHRONTEL_700x:
10952           return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x03) & 0x30) >> 4) * 4);
10953      case CHRONTEL_701x:
10954	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x02) & 0x10) >> 4) * 8);
10955      default:
10956           return (int)pSiS->chtvchromabandwidth;
10957      }
10958   }
10959}
10960
10961void SiS_SetCHTVchromaflickerfilter(ScrnInfoPtr pScrn, int val)
10962{
10963   SISPtr pSiS = SISPTR(pScrn);
10964#ifdef SISDUALHEAD
10965   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10966#endif
10967
10968   pSiS->chtvchromaflickerfilter = val;
10969#ifdef SISDUALHEAD
10970   if(pSiSEnt) pSiSEnt->chtvchromaflickerfilter = val;
10971#endif
10972
10973   if(!(pSiS->VBFlags & CRT2_TV)) return;
10974   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
10975
10976#ifdef UNLOCK_ALWAYS
10977   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10978#endif
10979
10980   switch(pSiS->ChrontelType) {
10981       case CHRONTEL_700x:
10982           val /= 6;
10983           if((val >= 0) && (val <= 2)) {
10984	      UShort reg = 0;
10985	      reg = SiS_GetCH70xx(pSiS->SiS_Pr, 0x01);
10986	      reg = (reg & 0xc0) | ((reg & 0x0c) >> 2) | ((reg & 0x03) << 2) | (val << 4);
10987              SiS_SetCH70xx(pSiS->SiS_Pr, 0x01, reg);
10988           }
10989	   break;
10990       case CHRONTEL_701x:
10991           val /= 4;
10992	   if((val >= 0) && (val <= 3)) {
10993	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x01, (val << 4), 0xCF);
10994	   }
10995           break;
10996   }
10997}
10998
10999int SiS_GetCHTVchromaflickerfilter(ScrnInfoPtr pScrn)
11000{
11001   SISPtr pSiS = SISPTR(pScrn);
11002#ifdef SISDUALHEAD
11003   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11004#endif
11005
11006   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
11007#ifdef SISDUALHEAD
11008      if(pSiSEnt && pSiS->DualHeadMode)
11009           return (int)pSiSEnt->chtvchromaflickerfilter;
11010      else
11011#endif
11012           return (int)pSiS->chtvchromaflickerfilter;
11013   } else {
11014#ifdef UNLOCK_ALWAYS
11015      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11016#endif
11017      switch(pSiS->ChrontelType) {
11018      case CHRONTEL_700x:
11019           return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x01) & 0x30) >> 4) * 6);
11020      case CHRONTEL_701x:
11021	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x01) & 0x30) >> 4) * 4);
11022      default:
11023           return (int)pSiS->chtvchromaflickerfilter;
11024      }
11025   }
11026}
11027
11028void SiS_SetCHTVcvbscolor(ScrnInfoPtr pScrn, int val)
11029{
11030   SISPtr pSiS = SISPTR(pScrn);
11031#ifdef SISDUALHEAD
11032   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11033#endif
11034
11035   pSiS->chtvcvbscolor = val ? 1 : 0;
11036#ifdef SISDUALHEAD
11037   if(pSiSEnt) pSiSEnt->chtvcvbscolor = pSiS->chtvcvbscolor;
11038#endif
11039
11040   if(!(pSiS->VBFlags & CRT2_TV)) return;
11041   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
11042
11043#ifdef UNLOCK_ALWAYS
11044   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11045#endif
11046
11047   switch(pSiS->ChrontelType) {
11048       case CHRONTEL_700x:
11049           if(!val)  SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, 0x40, 0x00);
11050           else      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, 0x00, ~0x40);
11051	   break;
11052       case CHRONTEL_701x:
11053           if(!val)  SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x02, 0x00, ~0x20);
11054	   else      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x02, 0x20, 0x00);
11055           break;
11056   }
11057}
11058
11059int SiS_GetCHTVcvbscolor(ScrnInfoPtr pScrn)
11060{
11061   SISPtr pSiS = SISPTR(pScrn);
11062#ifdef SISDUALHEAD
11063   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11064#endif
11065
11066   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
11067#ifdef SISDUALHEAD
11068      if(pSiSEnt && pSiS->DualHeadMode)
11069           return (int)pSiSEnt->chtvcvbscolor;
11070      else
11071#endif
11072           return (int)pSiS->chtvcvbscolor;
11073   } else {
11074#ifdef UNLOCK_ALWAYS
11075      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11076#endif
11077      switch(pSiS->ChrontelType) {
11078      case CHRONTEL_700x:
11079           return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x03) & 0x40) >> 6) ^ 0x01);
11080      case CHRONTEL_701x:
11081	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x02) & 0x20) >> 5) ^ 0x01);
11082      default:
11083           return (int)pSiS->chtvcvbscolor;
11084      }
11085   }
11086}
11087
11088void SiS_SetCHTVtextenhance(ScrnInfoPtr pScrn, int val)
11089{
11090   SISPtr pSiS = SISPTR(pScrn);
11091#ifdef SISDUALHEAD
11092   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11093#endif
11094
11095   pSiS->chtvtextenhance = val;
11096#ifdef SISDUALHEAD
11097   if(pSiSEnt) pSiSEnt->chtvtextenhance = val;
11098#endif
11099
11100   if(!(pSiS->VBFlags & CRT2_TV)) return;
11101   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
11102
11103#ifdef UNLOCK_ALWAYS
11104   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11105#endif
11106
11107   switch(pSiS->ChrontelType) {
11108       case CHRONTEL_700x:
11109           val /= 6;
11110           if((val >= 0) && (val <= 2)) {
11111	      UShort reg = 0;
11112	      reg = SiS_GetCH70xx(pSiS->SiS_Pr, 0x01);
11113	      reg = (reg & 0xf0) | ((reg & 0x03) << 2) | val;
11114              SiS_SetCH70xx(pSiS->SiS_Pr, 0x01, reg);
11115           }
11116	   break;
11117       case CHRONTEL_701x:
11118           val /= 2;
11119	   if((val >= 0) && (val <= 7)) {
11120	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, val, 0xF8);
11121	   }
11122           break;
11123   }
11124}
11125
11126int SiS_GetCHTVtextenhance(ScrnInfoPtr pScrn)
11127{
11128   SISPtr pSiS = SISPTR(pScrn);
11129#ifdef SISDUALHEAD
11130   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11131#endif
11132
11133   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
11134#ifdef SISDUALHEAD
11135      if(pSiSEnt && pSiS->DualHeadMode)
11136           return (int)pSiSEnt->chtvtextenhance;
11137      else
11138#endif
11139           return (int)pSiS->chtvtextenhance;
11140   } else {
11141#ifdef UNLOCK_ALWAYS
11142      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11143#endif
11144      switch(pSiS->ChrontelType) {
11145      case CHRONTEL_700x:
11146	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x01) & 0x0c) >> 2) * 6);
11147      case CHRONTEL_701x:
11148	   return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x03) & 0x07) * 2);
11149      default:
11150           return (int)pSiS->chtvtextenhance;
11151      }
11152   }
11153}
11154
11155void SiS_SetCHTVcontrast(ScrnInfoPtr pScrn, int val)
11156{
11157   SISPtr pSiS = SISPTR(pScrn);
11158#ifdef SISDUALHEAD
11159   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11160#endif
11161
11162   pSiS->chtvcontrast = val;
11163#ifdef SISDUALHEAD
11164   if(pSiSEnt) pSiSEnt->chtvcontrast = val;
11165#endif
11166
11167   if(!(pSiS->VBFlags & CRT2_TV)) return;
11168   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
11169
11170#ifdef UNLOCK_ALWAYS
11171   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11172#endif
11173
11174   val /= 2;
11175   if((val >= 0) && (val <= 7)) {
11176       switch(pSiS->ChrontelType) {
11177       case CHRONTEL_700x:
11178              SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x11, val, 0xF8);
11179	      break;
11180       case CHRONTEL_701x:
11181	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x08, val, 0xF8);
11182              break;
11183       }
11184       SiS_DDC2Delay(pSiS->SiS_Pr, 1000);
11185   }
11186}
11187
11188int SiS_GetCHTVcontrast(ScrnInfoPtr pScrn)
11189{
11190   SISPtr pSiS = SISPTR(pScrn);
11191#ifdef SISDUALHEAD
11192   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11193#endif
11194
11195   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
11196#ifdef SISDUALHEAD
11197      if(pSiSEnt && pSiS->DualHeadMode)
11198           return (int)pSiSEnt->chtvcontrast;
11199      else
11200#endif
11201           return (int)pSiS->chtvcontrast;
11202   } else {
11203#ifdef UNLOCK_ALWAYS
11204      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11205#endif
11206      switch(pSiS->ChrontelType) {
11207      case CHRONTEL_700x:
11208           return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x11) & 0x07) * 2);
11209      case CHRONTEL_701x:
11210	   return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x08) & 0x07) * 2);
11211      default:
11212           return (int)pSiS->chtvcontrast;
11213      }
11214   }
11215}
11216
11217void SiS_SetSISTVedgeenhance(ScrnInfoPtr pScrn, int val)
11218{
11219   SISPtr pSiS = SISPTR(pScrn);
11220#ifdef SISDUALHEAD
11221   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11222#endif
11223
11224   pSiS->sistvedgeenhance = val;
11225#ifdef SISDUALHEAD
11226   if(pSiSEnt) pSiSEnt->sistvedgeenhance = val;
11227#endif
11228
11229   if(!(pSiS->VBFlags2 & VB2_301))  return;
11230   if(!(pSiS->VBFlags & CRT2_TV))   return;
11231
11232#ifdef UNLOCK_ALWAYS
11233   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11234#endif
11235
11236   val /= 2;
11237   if((val >= 0) && (val <= 7)) {
11238      setSISIDXREG(SISPART2,0x3A, 0x1F, (val << 5));
11239   }
11240}
11241
11242int SiS_GetSISTVedgeenhance(ScrnInfoPtr pScrn)
11243{
11244   SISPtr pSiS = SISPTR(pScrn);
11245   int result = pSiS->sistvedgeenhance;
11246   UChar temp;
11247#ifdef SISDUALHEAD
11248   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11249
11250   if(pSiSEnt && pSiS->DualHeadMode) result = pSiSEnt->sistvedgeenhance;
11251#endif
11252
11253   if(!(pSiS->VBFlags2 & VB2_301))  return result;
11254   if(!(pSiS->VBFlags & CRT2_TV))   return result;
11255
11256#ifdef UNLOCK_ALWAYS
11257   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11258#endif
11259   inSISIDXREG(SISPART2, 0x3a, temp);
11260   return(int)(((temp & 0xe0) >> 5) * 2);
11261}
11262
11263void SiS_SetSISTVantiflicker(ScrnInfoPtr pScrn, int val)
11264{
11265   SISPtr pSiS = SISPTR(pScrn);
11266#ifdef SISDUALHEAD
11267   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11268#endif
11269
11270   pSiS->sistvantiflicker = val;
11271#ifdef SISDUALHEAD
11272   if(pSiSEnt) pSiSEnt->sistvantiflicker = val;
11273#endif
11274
11275   if(!(pSiS->VBFlags & CRT2_TV))      return;
11276   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE)) return;
11277   if(pSiS->VBFlags & TV_HIVISION)     return;
11278   if((pSiS->VBFlags & TV_YPBPR) &&
11279      (pSiS->VBFlags & (TV_YPBPR525P | TV_YPBPR625P | TV_YPBPR750P | TV_YPBPR1080I))) return;
11280
11281#ifdef UNLOCK_ALWAYS
11282   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11283#endif
11284
11285   /* Valid values: 0=off, 1=low, 2=med, 3=high, 4=adaptive */
11286   if((val >= 0) && (val <= 4)) {
11287      setSISIDXREG(SISPART2,0x0A,0x8F, (val << 4));
11288   }
11289}
11290
11291int SiS_GetSISTVantiflicker(ScrnInfoPtr pScrn)
11292{
11293   SISPtr pSiS = SISPTR(pScrn);
11294   int result = pSiS->sistvantiflicker;
11295   UChar temp;
11296#ifdef SISDUALHEAD
11297   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11298
11299   if(pSiSEnt && pSiS->DualHeadMode) result = pSiSEnt->sistvantiflicker;
11300#endif
11301
11302   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE)) return result;
11303   if(!(pSiS->VBFlags & CRT2_TV))        return result;
11304   if(pSiS->VBFlags & TV_HIVISION)       return result;
11305   if((pSiS->VBFlags & TV_YPBPR) &&
11306      (pSiS->VBFlags & (TV_YPBPR525P | TV_YPBPR625P | TV_YPBPR750P | TV_YPBPR1080I))) return result;
11307
11308#ifdef UNLOCK_ALWAYS
11309   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11310#endif
11311   inSISIDXREG(SISPART2, 0x0a, temp);
11312   return(int)((temp & 0x70) >> 4);
11313}
11314
11315void SiS_SetSISTVsaturation(ScrnInfoPtr pScrn, int val)
11316{
11317   SISPtr pSiS = SISPTR(pScrn);
11318#ifdef SISDUALHEAD
11319   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11320#endif
11321
11322   pSiS->sistvsaturation = val;
11323#ifdef SISDUALHEAD
11324   if(pSiSEnt) pSiSEnt->sistvsaturation = val;
11325#endif
11326
11327   if(!(pSiS->VBFlags & CRT2_TV)) return;
11328   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE)) return;
11329   if(pSiS->VBFlags2 & VB2_301) return;
11330
11331#ifdef UNLOCK_ALWAYS
11332   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11333#endif
11334
11335   val /= 2;
11336   if((val >= 0) && (val <= 7)) {
11337      setSISIDXREG(SISPART4,0x21,0xF8, val);
11338   }
11339}
11340
11341int SiS_GetSISTVsaturation(ScrnInfoPtr pScrn)
11342{
11343   SISPtr pSiS = SISPTR(pScrn);
11344   int result = pSiS->sistvsaturation;
11345   UChar temp;
11346#ifdef SISDUALHEAD
11347   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11348
11349   if(pSiSEnt && pSiS->DualHeadMode)  result = pSiSEnt->sistvsaturation;
11350#endif
11351
11352   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE)) return result;
11353   if(pSiS->VBFlags2 & VB2_301)          return result;
11354   if(!(pSiS->VBFlags & CRT2_TV))        return result;
11355
11356#ifdef UNLOCK_ALWAYS
11357   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11358#endif
11359   inSISIDXREG(SISPART4, 0x21, temp);
11360   return(int)((temp & 0x07) * 2);
11361}
11362
11363void SiS_SetSISTVcolcalib(ScrnInfoPtr pScrn, int val, Bool coarse)
11364{
11365   SISPtr pSiS = SISPTR(pScrn);
11366#ifdef SISDUALHEAD
11367   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11368#endif
11369   int ccoarse, cfine, cbase = pSiS->sistvccbase;
11370   /* UChar temp; */
11371
11372#ifdef SISDUALHEAD
11373   if(pSiSEnt && pSiS->DualHeadMode) cbase = pSiSEnt->sistvccbase;
11374#endif
11375
11376   if(coarse) {
11377      pSiS->sistvcolcalibc = ccoarse = val;
11378      cfine = pSiS->sistvcolcalibf;
11379#ifdef SISDUALHEAD
11380      if(pSiSEnt) {
11381         pSiSEnt->sistvcolcalibc = val;
11382	 if(pSiS->DualHeadMode) cfine = pSiSEnt->sistvcolcalibf;
11383      }
11384#endif
11385   } else {
11386      pSiS->sistvcolcalibf = cfine = val;
11387      ccoarse = pSiS->sistvcolcalibc;
11388#ifdef SISDUALHEAD
11389      if(pSiSEnt) {
11390         pSiSEnt->sistvcolcalibf = val;
11391         if(pSiS->DualHeadMode) ccoarse = pSiSEnt->sistvcolcalibc;
11392      }
11393#endif
11394   }
11395
11396   if(!(pSiS->VBFlags & CRT2_TV))               return;
11397   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE))        return;
11398   if(pSiS->VBFlags & (TV_HIVISION | TV_YPBPR)) return;
11399
11400#ifdef UNLOCK_ALWAYS
11401   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11402#endif
11403
11404   if((cfine >= -128) && (cfine <= 127) && (ccoarse >= -120) && (ccoarse <= 120)) {
11405      long finalcc = cbase + (((ccoarse * 256) + cfine) * 256);
11406
11407#if 0
11408      inSISIDXREG(SISPART4,0x1f,temp);
11409      if(!(temp & 0x01)) {
11410         if(pSiS->VBFlags & TV_NTSC) finalcc += 0x21ed8620;
11411	 else if(pSiS->VBFlags & TV_PALM) finalcc += ?;
11412	 else if(pSiS->VBFlags & TV_PALM) finalcc += ?;
11413	 else finalcc += 0x2a05d300;
11414      }
11415#endif
11416      setSISIDXREG(SISPART2,0x31,0x80,((finalcc >> 24) & 0x7f));
11417      outSISIDXREG(SISPART2,0x32,((finalcc >> 16) & 0xff));
11418      outSISIDXREG(SISPART2,0x33,((finalcc >> 8) & 0xff));
11419      outSISIDXREG(SISPART2,0x34,(finalcc & 0xff));
11420   }
11421}
11422
11423int SiS_GetSISTVcolcalib(ScrnInfoPtr pScrn, Bool coarse)
11424{
11425   SISPtr pSiS = SISPTR(pScrn);
11426#ifdef SISDUALHEAD
11427   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11428
11429   if(pSiSEnt && pSiS->DualHeadMode)
11430      if(coarse)  return (int)pSiSEnt->sistvcolcalibc;
11431      else        return (int)pSiSEnt->sistvcolcalibf;
11432   else
11433#endif
11434   if(coarse)     return (int)pSiS->sistvcolcalibc;
11435   else           return (int)pSiS->sistvcolcalibf;
11436}
11437
11438void SiS_SetSISTVcfilter(ScrnInfoPtr pScrn, int val)
11439{
11440   SISPtr pSiS = SISPTR(pScrn);
11441#ifdef SISDUALHEAD
11442   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11443#endif
11444
11445   pSiS->sistvcfilter = val ? 1 : 0;
11446#ifdef SISDUALHEAD
11447   if(pSiSEnt) pSiSEnt->sistvcfilter = pSiS->sistvcfilter;
11448#endif
11449
11450   if(!(pSiS->VBFlags & CRT2_TV))               return;
11451   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE))        return;
11452   if(pSiS->VBFlags & (TV_HIVISION | TV_YPBPR)) return;
11453
11454#ifdef UNLOCK_ALWAYS
11455   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11456#endif
11457
11458   setSISIDXREG(SISPART2,0x30,~0x10,((pSiS->sistvcfilter << 4) & 0x10));
11459}
11460
11461int SiS_GetSISTVcfilter(ScrnInfoPtr pScrn)
11462{
11463   SISPtr pSiS = SISPTR(pScrn);
11464   int result = pSiS->sistvcfilter;
11465   UChar temp;
11466#ifdef SISDUALHEAD
11467   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11468
11469   if(pSiSEnt && pSiS->DualHeadMode) result = pSiSEnt->sistvcfilter;
11470#endif
11471
11472   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE))        return result;
11473   if(!(pSiS->VBFlags & CRT2_TV))               return result;
11474   if(pSiS->VBFlags & (TV_HIVISION | TV_YPBPR)) return result;
11475
11476#ifdef UNLOCK_ALWAYS
11477   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11478#endif
11479   inSISIDXREG(SISPART2, 0x30, temp);
11480   return (int)((temp & 0x10) ? 1 : 0);
11481}
11482
11483void SiS_SetSISTVyfilter(ScrnInfoPtr pScrn, int val)
11484{
11485   SISPtr pSiS = SISPTR(pScrn);
11486#ifdef SISDUALHEAD
11487   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11488#endif
11489   UChar p35,p36,p37,p38,p48,p49,p4a,p30;
11490   int i,j;
11491
11492   pSiS->sistvyfilter = val;
11493#ifdef SISDUALHEAD
11494   if(pSiSEnt) pSiSEnt->sistvyfilter = pSiS->sistvyfilter;
11495#endif
11496
11497   if(!(pSiS->VBFlags & CRT2_TV))               return;
11498   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE))        return;
11499   if(pSiS->VBFlags & (TV_HIVISION | TV_YPBPR)) return;
11500
11501   p35 = pSiS->p2_35; p36 = pSiS->p2_36;
11502   p37 = pSiS->p2_37; p38 = pSiS->p2_38;
11503   p48 = pSiS->p2_48; p49 = pSiS->p2_49;
11504   p4a = pSiS->p2_4a; p30 = pSiS->p2_30;
11505#ifdef SISDUALHEAD
11506   if(pSiSEnt && pSiS->DualHeadMode) {
11507      p35 = pSiSEnt->p2_35; p36 = pSiSEnt->p2_36;
11508      p37 = pSiSEnt->p2_37; p38 = pSiSEnt->p2_38;
11509      p48 = pSiSEnt->p2_48; p49 = pSiSEnt->p2_49;
11510      p4a = pSiSEnt->p2_4a; p30 = pSiSEnt->p2_30;
11511   }
11512#endif
11513   p30 &= 0x20;
11514
11515#ifdef UNLOCK_ALWAYS
11516   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11517#endif
11518
11519   switch(pSiS->sistvyfilter) {
11520   case 0:
11521      andSISIDXREG(SISPART2,0x30,0xdf);
11522      break;
11523   case 1:
11524      outSISIDXREG(SISPART2,0x35,p35);
11525      outSISIDXREG(SISPART2,0x36,p36);
11526      outSISIDXREG(SISPART2,0x37,p37);
11527      outSISIDXREG(SISPART2,0x38,p38);
11528      if(!(pSiS->VBFlags2 & VB2_301)) {
11529         outSISIDXREG(SISPART2,0x48,p48);
11530         outSISIDXREG(SISPART2,0x49,p49);
11531         outSISIDXREG(SISPART2,0x4a,p4a);
11532      }
11533      setSISIDXREG(SISPART2,0x30,0xdf,p30);
11534      break;
11535   case 2:
11536   case 3:
11537   case 4:
11538   case 5:
11539   case 6:
11540   case 7:
11541   case 8:
11542      if(!(pSiS->VBFlags & (TV_PALM | TV_PALN | TV_NTSCJ))) {
11543         int yindex301 = -1, yindex301B = -1;
11544	 UChar p3d4_34;
11545
11546	 inSISIDXREG(SISCR,0x34,p3d4_34);
11547
11548	 switch((p3d4_34 & 0x7f)) {
11549	 case 0x59:  /* 320x200 */
11550	 case 0x41:
11551	 case 0x4f:
11552	 case 0x50:  /* 320x240 */
11553	 case 0x56:
11554	 case 0x53:
11555	    yindex301  = (pSiS->VBFlags & TV_NTSC) ? 0 : 4;
11556	    break;
11557	 case 0x2f:  /* 640x400 */
11558	 case 0x5d:
11559	 case 0x5e:
11560	 case 0x2e:  /* 640x480 */
11561	 case 0x44:
11562	 case 0x62:
11563	    yindex301  = (pSiS->VBFlags & TV_NTSC) ? 1 : 5;
11564	    yindex301B = (pSiS->VBFlags & TV_NTSC) ? 0 : 4;
11565	    break;
11566	 case 0x31:   /* 720x480 */
11567	 case 0x33:
11568	 case 0x35:
11569	 case 0x32:   /* 720x576 */
11570	 case 0x34:
11571	 case 0x36:
11572	 case 0x5f:   /* 768x576 */
11573	 case 0x60:
11574	 case 0x61:
11575	    yindex301  = (pSiS->VBFlags & TV_NTSC) ? 2 : 6;
11576	    yindex301B = (pSiS->VBFlags & TV_NTSC) ? 1 : 5;
11577	    break;
11578	 case 0x51:   /* 400x300 */
11579	 case 0x57:
11580	 case 0x54:
11581	 case 0x30:   /* 800x600 */
11582	 case 0x47:
11583	 case 0x63:
11584	    yindex301  = (pSiS->VBFlags & TV_NTSC) ? 3 : 7;
11585	    yindex301B = (pSiS->VBFlags & TV_NTSC) ? 2 : 6;
11586	    break;
11587	 case 0x52:   /* 512x384 */
11588	 case 0x58:
11589	 case 0x5c:
11590	 case 0x38:   /* 1024x768 */
11591	 case 0x4a:
11592	 case 0x64:
11593	    yindex301B = (pSiS->VBFlags & TV_NTSC) ? 3 : 7;
11594	    break;
11595	 }
11596         if(pSiS->VBFlags2 & VB2_301) {
11597            if(yindex301 >= 0) {
11598	       for(i=0, j=0x35; i<=3; i++, j++) {
11599	          outSISIDXREG(SISPART2,j,(SiSTVFilter301[yindex301].filter[pSiS->sistvyfilter-2][i]));
11600	       }
11601	    }
11602         } else {
11603            if(yindex301B >= 0) {
11604	       for(i=0, j=0x35; i<=3; i++, j++) {
11605	          outSISIDXREG(SISPART2,j,(SiSTVFilter301B[yindex301B].filter[pSiS->sistvyfilter-2][i]));
11606	       }
11607	       for(i=4, j=0x48; i<=6; i++, j++) {
11608	          outSISIDXREG(SISPART2,j,(SiSTVFilter301B[yindex301B].filter[pSiS->sistvyfilter-2][i]));
11609	       }
11610	    }
11611         }
11612         orSISIDXREG(SISPART2,0x30,0x20);
11613      }
11614   }
11615}
11616
11617int SiS_GetSISTVyfilter(ScrnInfoPtr pScrn)
11618{
11619   SISPtr pSiS = SISPTR(pScrn);
11620#ifdef SISDUALHEAD
11621   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11622
11623   if(pSiSEnt && pSiS->DualHeadMode)
11624      return (int)pSiSEnt->sistvyfilter;
11625   else
11626#endif
11627      return (int)pSiS->sistvyfilter;
11628}
11629
11630void SiS_SetSIS6326TVantiflicker(ScrnInfoPtr pScrn, int val)
11631{
11632   SISPtr pSiS = SISPTR(pScrn);
11633   UChar tmp;
11634
11635   pSiS->sistvantiflicker = val;
11636
11637   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) return;
11638
11639#ifdef UNLOCK_ALWAYS
11640   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11641#endif
11642
11643   tmp = SiS6326GetTVReg(pScrn,0x00);
11644   if(!(tmp & 0x04)) return;
11645
11646   /* Valid values: 0=off, 1=low, 2=med, 3=high, 4=adaptive */
11647   if(val >= 0 && val <= 4) {
11648      tmp &= 0x1f;
11649      tmp |= (val << 5);
11650      SiS6326SetTVReg(pScrn,0x00,tmp);
11651   }
11652}
11653
11654int SiS_GetSIS6326TVantiflicker(ScrnInfoPtr pScrn)
11655{
11656   SISPtr pSiS = SISPTR(pScrn);
11657   UChar tmp;
11658
11659   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) {
11660      return (int)pSiS->sistvantiflicker;
11661   }
11662
11663#ifdef UNLOCK_ALWAYS
11664   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11665#endif
11666
11667   tmp = SiS6326GetTVReg(pScrn,0x00);
11668   if(!(tmp & 0x04)) {
11669      return (int)pSiS->sistvantiflicker;
11670   } else {
11671      return (int)((tmp >> 5) & 0x07);
11672   }
11673}
11674
11675void SiS_SetSIS6326TVenableyfilter(ScrnInfoPtr pScrn, int val)
11676{
11677   SISPtr pSiS = SISPTR(pScrn);
11678   UChar tmp;
11679
11680   if(val) val = 1;
11681   pSiS->sis6326enableyfilter = val;
11682
11683   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) return;
11684
11685#ifdef UNLOCK_ALWAYS
11686   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11687#endif
11688
11689   tmp = SiS6326GetTVReg(pScrn,0x00);
11690   if(!(tmp & 0x04)) return;
11691
11692   tmp = SiS6326GetTVReg(pScrn,0x43);
11693   tmp &= ~0x10;
11694   tmp |= ((val & 0x01) << 4);
11695   SiS6326SetTVReg(pScrn,0x43,tmp);
11696}
11697
11698int SiS_GetSIS6326TVenableyfilter(ScrnInfoPtr pScrn)
11699{
11700   SISPtr pSiS = SISPTR(pScrn);
11701   UChar tmp;
11702
11703   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) {
11704      return (int)pSiS->sis6326enableyfilter;
11705   }
11706
11707#ifdef UNLOCK_ALWAYS
11708   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11709#endif
11710
11711   tmp = SiS6326GetTVReg(pScrn,0x00);
11712   if(!(tmp & 0x04)) {
11713      return (int)pSiS->sis6326enableyfilter;
11714   } else {
11715      tmp = SiS6326GetTVReg(pScrn,0x43);
11716      return (int)((tmp >> 4) & 0x01);
11717   }
11718}
11719
11720void SiS_SetSIS6326TVyfilterstrong(ScrnInfoPtr pScrn, int val)
11721{
11722   SISPtr pSiS = SISPTR(pScrn);
11723   UChar tmp;
11724
11725   if(val) val = 1;
11726   pSiS->sis6326yfilterstrong = val;
11727
11728   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) return;
11729
11730#ifdef UNLOCK_ALWAYS
11731   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11732#endif
11733
11734   tmp = SiS6326GetTVReg(pScrn,0x00);
11735   if(!(tmp & 0x04)) return;
11736
11737   tmp = SiS6326GetTVReg(pScrn,0x43);
11738   if(tmp & 0x10) {
11739      tmp &= ~0x40;
11740      tmp |= ((val & 0x01) << 6);
11741      SiS6326SetTVReg(pScrn,0x43,tmp);
11742   }
11743}
11744
11745int SiS_GetSIS6326TVyfilterstrong(ScrnInfoPtr pScrn)
11746{
11747   SISPtr pSiS = SISPTR(pScrn);
11748   UChar tmp;
11749
11750   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) {
11751      return (int)pSiS->sis6326yfilterstrong;
11752   }
11753
11754#ifdef UNLOCK_ALWAYS
11755   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11756#endif
11757
11758   tmp = SiS6326GetTVReg(pScrn,0x00);
11759   if(!(tmp & 0x04)) {
11760      return (int)pSiS->sis6326yfilterstrong;
11761   } else {
11762      tmp = SiS6326GetTVReg(pScrn,0x43);
11763      if(!(tmp & 0x10)) {
11764         return (int)pSiS->sis6326yfilterstrong;
11765      } else {
11766         return (int)((tmp >> 6) & 0x01);
11767      }
11768   }
11769}
11770
11771void SiS_SetTVxposoffset(ScrnInfoPtr pScrn, int val)
11772{
11773   SISPtr pSiS = SISPTR(pScrn);
11774#ifdef SISDUALHEAD
11775   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11776#endif
11777
11778#ifdef UNLOCK_ALWAYS
11779   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11780#endif
11781
11782   pSiS->tvxpos = val;
11783#ifdef SISDUALHEAD
11784   if(pSiSEnt) pSiSEnt->tvxpos = val;
11785#endif
11786
11787   if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
11788
11789      if(pSiS->VBFlags & CRT2_TV) {
11790
11791         if(pSiS->VBFlags2 & VB2_CHRONTEL) {
11792
11793	    int x = pSiS->tvx;
11794#ifdef SISDUALHEAD
11795	    if(pSiSEnt && pSiS->DualHeadMode) x = pSiSEnt->tvx;
11796#endif
11797	    switch(pSiS->ChrontelType) {
11798	    case CHRONTEL_700x:
11799	       if((val >= -32) && (val <= 32)) {
11800		   x += val;
11801		   if(x < 0) x = 0;
11802		   SiS_SetCH700x(pSiS->SiS_Pr, 0x0a, (x & 0xff));
11803		   SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x08, ((x & 0x0100) >> 7), 0xFD);
11804	       }
11805	       break;
11806	    case CHRONTEL_701x:
11807	       /* Not supported by hardware */
11808	       break;
11809	    }
11810
11811	 } else if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
11812
11813	    if((val >= -32) && (val <= 32)) {
11814
11815	        UChar p2_1f,p2_20,p2_2b,p2_42,p2_43;
11816		UShort temp;
11817		int mult;
11818
11819		p2_1f = pSiS->p2_1f;
11820		p2_20 = pSiS->p2_20;
11821		p2_2b = pSiS->p2_2b;
11822		p2_42 = pSiS->p2_42;
11823		p2_43 = pSiS->p2_43;
11824#ifdef SISDUALHEAD
11825	        if(pSiSEnt && pSiS->DualHeadMode) {
11826		   p2_1f = pSiSEnt->p2_1f;
11827		   p2_20 = pSiSEnt->p2_20;
11828		   p2_2b = pSiSEnt->p2_2b;
11829		   p2_42 = pSiSEnt->p2_42;
11830		   p2_43 = pSiSEnt->p2_43;
11831		}
11832#endif
11833		mult = 2;
11834		if(pSiS->VBFlags & TV_YPBPR) {
11835		   if(pSiS->VBFlags & (TV_YPBPR1080I | TV_YPBPR750P)) {
11836		      mult = 4;
11837		   }
11838		}
11839
11840		temp = p2_1f | ((p2_20 & 0xf0) << 4);
11841		temp += (val * mult);
11842		p2_1f = temp & 0xff;
11843		p2_20 = (temp & 0xf00) >> 4;
11844		p2_2b = ((p2_2b & 0x0f) + (val * mult)) & 0x0f;
11845		temp = p2_43 | ((p2_42 & 0xf0) << 4);
11846		temp += (val * mult);
11847		p2_43 = temp & 0xff;
11848		p2_42 = (temp & 0xf00) >> 4;
11849		SISWaitRetraceCRT2(pScrn);
11850	        outSISIDXREG(SISPART2,0x1f,p2_1f);
11851		setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
11852		setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
11853		setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
11854		outSISIDXREG(SISPART2,0x43,p2_43);
11855	     }
11856	 }
11857      }
11858
11859   } else if(pSiS->Chipset == PCI_CHIP_SIS6326) {
11860
11861      if(pSiS->SiS6326Flags & SIS6326_TVDETECTED) {
11862
11863         UChar tmp;
11864	 UShort temp1, temp2, temp3;
11865
11866         tmp = SiS6326GetTVReg(pScrn,0x00);
11867         if(tmp & 0x04) {
11868
11869	    temp1 = pSiS->tvx1;
11870            temp2 = pSiS->tvx2;
11871            temp3 = pSiS->tvx3;
11872            if((val >= -16) && (val <= 16)) {
11873	       if(val > 0) {
11874	          temp1 += (val * 4);
11875	          temp2 += (val * 4);
11876	          while((temp1 > 0x0fff) || (temp2 > 0x0fff)) {
11877	             temp1 -= 4;
11878		     temp2 -= 4;
11879	          }
11880	       } else {
11881	          val = -val;
11882	          temp3 += (val * 4);
11883	          while(temp3 > 0x03ff) {
11884	     	     temp3 -= 4;
11885	          }
11886	       }
11887            }
11888            SiS6326SetTVReg(pScrn,0x3a,(temp1 & 0xff));
11889            tmp = SiS6326GetTVReg(pScrn,0x3c);
11890            tmp &= 0xf0;
11891            tmp |= ((temp1 & 0x0f00) >> 8);
11892            SiS6326SetTVReg(pScrn,0x3c,tmp);
11893            SiS6326SetTVReg(pScrn,0x26,(temp2 & 0xff));
11894            tmp = SiS6326GetTVReg(pScrn,0x27);
11895            tmp &= 0x0f;
11896            tmp |= ((temp2 & 0x0f00) >> 4);
11897            SiS6326SetTVReg(pScrn,0x27,tmp);
11898            SiS6326SetTVReg(pScrn,0x12,(temp3 & 0xff));
11899            tmp = SiS6326GetTVReg(pScrn,0x13);
11900            tmp &= ~0xC0;
11901            tmp |= ((temp3 & 0x0300) >> 2);
11902            SiS6326SetTVReg(pScrn,0x13,tmp);
11903	 }
11904      }
11905   }
11906}
11907
11908int SiS_GetTVxposoffset(ScrnInfoPtr pScrn)
11909{
11910   SISPtr pSiS = SISPTR(pScrn);
11911#ifdef SISDUALHEAD
11912   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11913
11914   if(pSiSEnt && pSiS->DualHeadMode)
11915        return (int)pSiSEnt->tvxpos;
11916   else
11917#endif
11918        return (int)pSiS->tvxpos;
11919}
11920
11921void SiS_SetTVyposoffset(ScrnInfoPtr pScrn, int val)
11922{
11923   SISPtr pSiS = SISPTR(pScrn);
11924#ifdef SISDUALHEAD
11925   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11926#endif
11927
11928#ifdef UNLOCK_ALWAYS
11929   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11930#endif
11931
11932   pSiS->tvypos = val;
11933#ifdef SISDUALHEAD
11934   if(pSiSEnt) pSiSEnt->tvypos = val;
11935#endif
11936
11937   if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
11938
11939      if(pSiS->VBFlags & CRT2_TV) {
11940
11941         if(pSiS->VBFlags2 & VB2_CHRONTEL) {
11942
11943	    int y = pSiS->tvy;
11944#ifdef SISDUALHEAD
11945	    if(pSiSEnt && pSiS->DualHeadMode) y = pSiSEnt->tvy;
11946#endif
11947	    switch(pSiS->ChrontelType) {
11948	    case CHRONTEL_700x:
11949	       if((val >= -32) && (val <= 32)) {
11950		   y -= val;
11951		   if(y < 0) y = 0;
11952		   SiS_SetCH700x(pSiS->SiS_Pr, 0x0b, (y & 0xff));
11953		   SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x08, ((y & 0x0100) >> 8), 0xFE);
11954	       }
11955	       break;
11956	    case CHRONTEL_701x:
11957	       /* Not supported by hardware */
11958	       break;
11959	    }
11960
11961	 } else if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
11962
11963	    if((val >= -32) && (val <= 32)) {
11964		char p2_01, p2_02;
11965
11966		if( (pSiS->VBFlags & TV_HIVISION) ||
11967		    ((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & (TV_YPBPR1080I|TV_YPBPR750P))) ) {
11968		   val *= 2;
11969		} else {
11970		   val /= 2;  /* 4 */
11971		}
11972
11973		p2_01 = pSiS->p2_01;
11974		p2_02 = pSiS->p2_02;
11975#ifdef SISDUALHEAD
11976	        if(pSiSEnt && pSiS->DualHeadMode) {
11977		   p2_01 = pSiSEnt->p2_01;
11978		   p2_02 = pSiSEnt->p2_02;
11979		}
11980#endif
11981		p2_01 += val; /* val * 2 */
11982		p2_02 += val; /* val * 2 */
11983		if(!(pSiS->VBFlags & (TV_YPBPR | TV_HIVISION))) {
11984		   while((p2_01 <= 0) || (p2_02 <= 0)) {
11985		      p2_01 += 2;
11986		      p2_02 += 2;
11987		   }
11988		} else if((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR1080I)) {
11989		   while(p2_01 <= 8) {
11990		      p2_01 += 2;
11991		      p2_02 += 2;
11992		   }
11993		} else if((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR750P)) {
11994		   while(p2_01 <= 10) {
11995		      p2_01 += 2;
11996		      p2_02 += 2;
11997		   }
11998		}
11999
12000		SISWaitRetraceCRT2(pScrn);
12001		outSISIDXREG(SISPART2,0x01,p2_01);
12002		outSISIDXREG(SISPART2,0x02,p2_02);
12003	     }
12004	 }
12005
12006      }
12007
12008   } else if(pSiS->Chipset == PCI_CHIP_SIS6326) {
12009
12010      if(pSiS->SiS6326Flags & SIS6326_TVDETECTED) {
12011
12012         UChar tmp;
12013	 int temp1, limit;
12014
12015         tmp = SiS6326GetTVReg(pScrn,0x00);
12016         if(tmp & 0x04) {
12017
12018	    if((val >= -16) && (val <= 16)) {
12019	      temp1 = (UShort)pSiS->tvy1;
12020	      limit = (pSiS->SiS6326Flags & SIS6326_TVPAL) ? 625 : 525;
12021	      if(val > 0) {
12022                temp1 += (val * 4);
12023	        if(temp1 > limit) temp1 -= limit;
12024	      } else {
12025	        val = -val;
12026	        temp1 -= (val * 2);
12027	        if(temp1 <= 0) temp1 += (limit -1);
12028	      }
12029	      SiS6326SetTVReg(pScrn,0x11,(temp1 & 0xff));
12030	      tmp = SiS6326GetTVReg(pScrn,0x13);
12031	      tmp &= ~0x30;
12032	      tmp |= ((temp1 & 0x300) >> 4);
12033	      SiS6326SetTVReg(pScrn,0x13,tmp);
12034	      if(temp1 == 1)                                 tmp = 0x10;
12035	      else {
12036	       if(pSiS->SiS6326Flags & SIS6326_TVPAL) {
12037	         if((temp1 <= 3) || (temp1 >= (limit - 2)))  tmp = 0x08;
12038	         else if(temp1 < 22)		 	     tmp = 0x02;
12039	         else 					     tmp = 0x04;
12040	       } else {
12041	         if((temp1 <= 5) || (temp1 >= (limit - 4)))  tmp = 0x08;
12042	         else if(temp1 < 19)			     tmp = 0x02;
12043	         else 					     tmp = 0x04;
12044	       }
12045	     }
12046	     SiS6326SetTVReg(pScrn,0x21,tmp);
12047           }
12048	 }
12049      }
12050   }
12051}
12052
12053int SiS_GetTVyposoffset(ScrnInfoPtr pScrn)
12054{
12055   SISPtr pSiS = SISPTR(pScrn);
12056#ifdef SISDUALHEAD
12057   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12058
12059   if(pSiSEnt && pSiS->DualHeadMode)
12060        return (int)pSiSEnt->tvypos;
12061   else
12062#endif
12063        return (int)pSiS->tvypos;
12064}
12065
12066void SiS_SetTVxscale(ScrnInfoPtr pScrn, int val)
12067{
12068   SISPtr pSiS = SISPTR(pScrn);
12069#ifdef SISDUALHEAD
12070   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12071#endif
12072
12073#ifdef UNLOCK_ALWAYS
12074   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
12075#endif
12076
12077   pSiS->tvxscale = val;
12078#ifdef SISDUALHEAD
12079   if(pSiSEnt) pSiSEnt->tvxscale = val;
12080#endif
12081
12082   if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
12083
12084      if((pSiS->VBFlags & CRT2_TV) && (pSiS->VBFlags2 & VB2_SISBRIDGE)) {
12085
12086	 if((val >= -16) && (val <= 16)) {
12087
12088	    UChar p2_44,p2_45,p2_46;
12089	    int scalingfactor, mult;
12090
12091	    p2_44 = pSiS->p2_44;
12092	    p2_45 = pSiS->p2_45 & 0x3f;
12093	    p2_46 = pSiS->p2_46 & 0x07;
12094#ifdef SISDUALHEAD
12095	    if(pSiSEnt && pSiS->DualHeadMode) {
12096	       p2_44 = pSiSEnt->p2_44;
12097	       p2_45 = pSiSEnt->p2_45 & 0x3f;
12098	       p2_46 = pSiSEnt->p2_46 & 0x07;
12099	    }
12100#endif
12101	    scalingfactor = (p2_46 << 13) | ((p2_45 & 0x1f) << 8) | p2_44;
12102
12103	    mult = 64;
12104	    if(pSiS->VBFlags & TV_YPBPR) {
12105	       if(pSiS->VBFlags & TV_YPBPR1080I) {
12106	          mult = 190;
12107	       } else if(pSiS->VBFlags & TV_YPBPR750P) {
12108	          mult = 360;
12109	       }
12110	    } else if(pSiS->VBFlags & TV_HIVISION) {
12111	       mult = 190;
12112	    }
12113
12114	    if(val < 0) {
12115	       p2_45 &= 0xdf;
12116	       scalingfactor += ((-val) * mult);
12117	       if(scalingfactor > 0xffff) scalingfactor = 0xffff;
12118	    } else if(val > 0) {
12119	       p2_45 &= 0xdf;
12120	       scalingfactor -= (val * mult);
12121	       if(scalingfactor < 1) scalingfactor = 1;
12122	    }
12123
12124	    p2_44 = scalingfactor & 0xff;
12125	    p2_45 &= 0xe0;
12126	    p2_45 |= ((scalingfactor >> 8) & 0x1f);
12127	    p2_46 = ((scalingfactor >> 13) & 0x07);
12128
12129	    SISWaitRetraceCRT2(pScrn);
12130	    outSISIDXREG(SISPART2,0x44,p2_44);
12131	    setSISIDXREG(SISPART2,0x45,0xC0,p2_45);
12132	    if(!(pSiS->VBFlags2 & VB2_301)) {
12133	       setSISIDXREG(SISPART2,0x46,0xF8,p2_46);
12134	    }
12135
12136	 }
12137
12138      }
12139
12140   }
12141}
12142
12143int SiS_GetTVxscale(ScrnInfoPtr pScrn)
12144{
12145   SISPtr pSiS = SISPTR(pScrn);
12146#ifdef SISDUALHEAD
12147   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12148
12149   if(pSiSEnt && pSiS->DualHeadMode)
12150        return (int)pSiSEnt->tvxscale;
12151   else
12152#endif
12153        return (int)pSiS->tvxscale;
12154}
12155
12156void SiS_SetTVyscale(ScrnInfoPtr pScrn, int val)
12157{
12158   SISPtr pSiS = SISPTR(pScrn);
12159#ifdef SISDUALHEAD
12160   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12161#endif
12162
12163#ifdef UNLOCK_ALWAYS
12164   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
12165#endif
12166
12167   if(val < -4) val = -4;
12168   if(val > 3)  val = 3;
12169
12170   pSiS->tvyscale = val;
12171#ifdef SISDUALHEAD
12172   if(pSiSEnt) pSiSEnt->tvyscale = val;
12173#endif
12174
12175   if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
12176
12177      if((pSiS->VBFlags & CRT2_TV) && (pSiS->VBFlags2 & VB2_SISBRIDGE)) {
12178
12179	 int srindex = -1, newvde, i = 0, j, vlimit, temp, vdediv;
12180	 int hdclk = 0;
12181	 UChar p3d4_34;
12182	 Bool found = FALSE;
12183	 Bool usentsc = FALSE;
12184	 Bool is750p = FALSE;
12185	 Bool is1080i = FALSE;
12186	 Bool skipmoveup = FALSE;
12187
12188	 SiS_UnLockCRT2(pSiS->SiS_Pr);
12189
12190	 if((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR525P)) {
12191	    vlimit = 525 - 7;
12192	    vdediv = 1;
12193	    usentsc = TRUE;
12194	 } else if((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR625P)) {
12195	    vlimit = 625 - 7;
12196	    vdediv = 1;
12197	 } else if((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR750P)) {
12198	    vlimit = 750 - 7;
12199	    vdediv = 1;
12200	    is750p = TRUE;
12201	 } else if(((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR1080I)) ||
12202	           (pSiS->VBFlags & TV_HIVISION)) {
12203	    vlimit = (1125 - 7) / 2;
12204	    vdediv = 2;
12205	    is1080i = TRUE;
12206	 } else {
12207	    if( ((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR525I)) ||
12208	        ((!(pSiS->VBFlags & TV_YPBPR)) && (pSiS->VBFlags & (TV_NTSC | TV_PALM))) ) {
12209	       usentsc = TRUE;
12210	    }
12211	    vlimit = usentsc ? 259 : 309;
12212	    vdediv = 2;
12213	 }
12214
12215	 inSISIDXREG(SISCR,0x34,p3d4_34);
12216
12217	 switch((p3d4_34 & 0x7f)) {
12218	 case 0x50:   /* 320x240 */
12219	 case 0x56:
12220	 case 0x53:
12221	    hdclk = 1;
12222	    /* fall through */
12223	 case 0x2e:   /* 640x480 */
12224	 case 0x44:
12225	 case 0x62:
12226	    if(is1080i) {
12227	       srindex = 98;
12228	    } else if(is750p) {
12229	       srindex = 42;
12230	    } else {
12231	       srindex  = usentsc ? 0 : 21;
12232	    }
12233	    break;
12234	 case 0x31:   /* 720x480 */
12235	 case 0x33:
12236	 case 0x35:
12237	    if(is1080i) {
12238	       /* n/a */
12239	    } else if(is750p) {
12240	       srindex = 49;
12241	    } else {
12242	       srindex = usentsc ? 7 : 21;
12243	    }
12244	    break;
12245	 case 0x32:   /* 720x576 */
12246	 case 0x34:
12247	 case 0x36:
12248	 case 0x5f:   /* 768x576 */
12249	 case 0x60:
12250	 case 0x61:
12251	    if(is1080i) {
12252	       /* n/a */
12253	    } else if(is750p) {
12254	       srindex = 56;
12255	    } else {
12256	       srindex  = usentsc ? 147 : 28;
12257	    }
12258	    break;
12259	 case 0x70:   /* 800x480 */
12260	 case 0x7a:
12261	 case 0x76:
12262	    if(is1080i) {
12263	       srindex = 105;
12264	    } else if(is750p) {
12265	       srindex = 63;
12266	    } else {
12267	       srindex = usentsc ? 175 : 21;
12268	    }
12269	    break;
12270	 case 0x51:   /* 400x300 - hdclk mode */
12271	 case 0x57:
12272	 case 0x54:
12273	    hdclk = 1;
12274	    /* fall through */
12275	 case 0x30:   /* 800x600 */
12276	 case 0x47:
12277	 case 0x63:
12278	    if(is1080i) {
12279	       srindex = 112;
12280	    } else if(is750p) {
12281	       srindex = 70;
12282	    } else {
12283	       srindex = usentsc ? 14 : 35;
12284	    }
12285	    break;
12286	 case 0x1d:	/* 960x540 */
12287	 case 0x1e:
12288	 case 0x1f:
12289	    if(is1080i) {
12290	       srindex = 196;
12291	       skipmoveup = TRUE;
12292	    }
12293	    break;
12294	 case 0x20:	/* 960x600 */
12295	 case 0x21:
12296	 case 0x22:
12297	    if(pSiS->VGAEngine == SIS_315_VGA && is1080i) {
12298	       srindex = 203;
12299	    }
12300	    break;
12301	 case 0x71:	/* 1024x576 */
12302	 case 0x74:
12303	 case 0x77:
12304	    if(is1080i) {
12305	       srindex = 119;
12306	    } else if(is750p) {
12307	       srindex = 77;
12308	    } else {
12309	       srindex  = usentsc ? 182 : 189;
12310	    }
12311	    break;
12312	 case 0x52:	/* 512x384 */
12313	 case 0x58:
12314	 case 0x5c:
12315	    hdclk = 1;
12316	    /* fall through */
12317	 case 0x38:	/* 1024x768 */
12318	 case 0x4a:
12319	 case 0x64:
12320	    if(is1080i) {
12321	       srindex = 126;
12322	    } else if(is750p) {
12323	       srindex = 84;
12324	    } else if(!usentsc) {
12325	       srindex = 154;
12326	    } else if(vdediv == 1) {
12327	       if(!hdclk) srindex = 168;
12328	    } else {
12329	       if(!hdclk) srindex = 161;
12330	    }
12331	    break;
12332	 case 0x79:	/* 1280x720 */
12333	 case 0x75:
12334	 case 0x78:
12335	    if(is1080i) {
12336	       srindex = 133;
12337	    } else if(is750p) {
12338	       srindex = 91;
12339	    }
12340	    break;
12341	 case 0x3a:	/* 1280x1024 */
12342	 case 0x4d:
12343	 case 0x65:
12344	    if(is1080i) {
12345	       srindex = 140;
12346	    }
12347	    break;
12348	 }
12349
12350	 if(srindex < 0) return;
12351
12352	 if(pSiS->tvyscale != 0) {
12353	    for(j = 0; j <= 1; j++) {
12354	       for(i = 0; i <= 6; i++) {
12355		  if(SiSTVVScale[srindex+i].sindex == pSiS->tvyscale) {
12356		     found = TRUE;
12357		     break;
12358		  }
12359	       }
12360	       if(found) break;
12361	       if(pSiS->tvyscale > 0) pSiS->tvyscale--;
12362	       else pSiS->tvyscale++;
12363	    }
12364	 }
12365
12366#ifdef SISDUALHEAD
12367	 if(pSiSEnt) pSiSEnt->tvyscale = pSiS->tvyscale;
12368#endif
12369
12370	 if(pSiS->tvyscale == 0) {
12371	    UChar p2_0a = pSiS->p2_0a;
12372	    UChar p2_2f = pSiS->p2_2f;
12373	    UChar p2_30 = pSiS->p2_30;
12374	    UChar p2_46 = pSiS->p2_46;
12375	    UChar p2_47 = pSiS->p2_47;
12376	    UChar p1scaling[9], p4scaling[9];
12377	    UChar *p2scaling;
12378
12379	    for(i = 0; i < 9; i++) {
12380	        p1scaling[i] = pSiS->scalingp1[i];
12381		p4scaling[i] = pSiS->scalingp4[i];
12382	    }
12383	    p2scaling = &pSiS->scalingp2[0];
12384
12385#ifdef SISDUALHEAD
12386	    if(pSiSEnt && pSiS->DualHeadMode) {
12387	       p2_0a = pSiSEnt->p2_0a;
12388	       p2_2f = pSiSEnt->p2_2f;
12389	       p2_30 = pSiSEnt->p2_30;
12390	       p2_46 = pSiSEnt->p2_46;
12391	       p2_47 = pSiSEnt->p2_47;
12392	       for(i = 0; i < 9; i++) {
12393		  p1scaling[i] = pSiSEnt->scalingp1[i];
12394		  p4scaling[i] = pSiSEnt->scalingp4[i];
12395	       }
12396	       p2scaling = &pSiSEnt->scalingp2[0];
12397	    }
12398#endif
12399            SISWaitRetraceCRT2(pScrn);
12400	    if(pSiS->VBFlags2 & VB2_SISTAP4SCALER) {
12401	       for(i = 0; i < 64; i++) {
12402	          outSISIDXREG(SISPART2,(0xc0 + i),p2scaling[i]);
12403	       }
12404	    }
12405	    for(i = 0; i < 9; i++) {
12406	       outSISIDXREG(SISPART1,SiSScalingP1Regs[i],p1scaling[i]);
12407	    }
12408	    for(i = 0; i < 9; i++) {
12409	       outSISIDXREG(SISPART4,SiSScalingP4Regs[i],p4scaling[i]);
12410	    }
12411
12412	    setSISIDXREG(SISPART2,0x0a,0x7f,(p2_0a & 0x80));
12413	    outSISIDXREG(SISPART2,0x2f,p2_2f);
12414	    setSISIDXREG(SISPART2,0x30,0x3f,(p2_30 & 0xc0));
12415	    if(!(pSiS->VBFlags2 & VB2_301)) {
12416	       setSISIDXREG(SISPART2,0x46,0x9f,(p2_46 & 0x60));
12417	       outSISIDXREG(SISPART2,0x47,p2_47);
12418	    }
12419
12420	 } else {
12421
12422	    int realvde, myypos, watchdog = 32;
12423	    unsigned short temp1, temp2, vgahde, vgaht, vgavt;
12424	    int p1div = 1;
12425	    ULong calctemp;
12426
12427	    srindex += i;
12428	    newvde = SiSTVVScale[srindex].ScaleVDE;
12429	    realvde = SiSTVVScale[srindex].RealVDE;
12430
12431	    if(vdediv == 1) p1div = 2;
12432
12433	    if(!skipmoveup) {
12434	       do {
12435	          inSISIDXREG(SISPART2,0x01,temp);
12436	          temp = vlimit - ((temp & 0x7f) / p1div);
12437	          if((temp - (((newvde / vdediv) - 2) + 9)) > 0) break;
12438	          myypos = pSiS->tvypos - 1;
12439#ifdef SISDUALHEAD
12440	          if(pSiSEnt && pSiS->DualHeadMode) myypos = pSiSEnt->tvypos - 1;
12441#endif
12442	          SiS_SetTVyposoffset(pScrn, myypos);
12443	       } while(watchdog--);
12444	    }
12445
12446	    SISWaitRetraceCRT2(pScrn);
12447
12448	    if(pSiS->VBFlags2 & VB2_SISTAP4SCALER) {
12449	       SiS_CalcXTapScaler(pSiS->SiS_Pr, realvde, newvde, 4, FALSE);
12450	    }
12451
12452	    if(!(pSiS->VBFlags2 & VB2_301)) {
12453	       temp = (newvde / vdediv) - 3;
12454	       setSISIDXREG(SISPART2,0x46,0x9f,((temp & 0x0300) >> 3));
12455	       outSISIDXREG(SISPART2,0x47,(temp & 0xff));
12456	    }
12457
12458	    inSISIDXREG(SISPART1,0x0a,temp1);
12459	    inSISIDXREG(SISPART1,0x0c,temp2);
12460	    vgahde = ((temp2 & 0xf0) << 4) | temp1;
12461	    if(pSiS->VGAEngine == SIS_300_VGA) {
12462	       vgahde -= 12;
12463	    } else {
12464	       vgahde -= 16;
12465	       if(hdclk) vgahde <<= 1;
12466	    }
12467
12468	    vgaht = SiSTVVScale[srindex].reg[0];
12469	    temp1 = vgaht;
12470	    if((pSiS->VGAEngine == SIS_315_VGA) && hdclk) temp1 >>= 1;
12471	    temp1--;
12472	    outSISIDXREG(SISPART1,0x08,(temp1 & 0xff));
12473	    setSISIDXREG(SISPART1,0x09,0x0f,((temp1 >> 4) & 0xf0));
12474
12475	    temp2 = (vgaht - vgahde) >> 2;
12476	    if(pSiS->VGAEngine == SIS_300_VGA) {
12477	       temp1 = vgahde + 12 + temp2;
12478	       temp2 = temp1 + (temp2 << 1);
12479	    } else {
12480	       temp1 = vgahde;
12481	       if(hdclk) {
12482		  temp1 >>= 1;
12483		  temp2 >>= 1;
12484	       }
12485	       temp2 >>= 1;
12486	       temp1 = temp1 + 16 + temp2;
12487	       temp2 = temp1 + temp2;
12488	    }
12489	    outSISIDXREG(SISPART1,0x0b,(temp1 & 0xff));
12490	    setSISIDXREG(SISPART1,0x0c,0xf0,((temp1 >> 8) & 0x0f));
12491	    outSISIDXREG(SISPART1,0x0d,(temp2 & 0xff));
12492
12493	    vgavt = SiSTVVScale[srindex].reg[1];
12494	    temp1 = vgavt - 1;
12495	    if(pSiS->VGAEngine == SIS_315_VGA) temp1--;
12496	    outSISIDXREG(SISPART1,0x0e,(temp1 & 0xff));
12497	    setSISIDXREG(SISPART1,0x12,0xf8,((temp1 >> 8 ) & 0x07));
12498	    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->ChipType >= SIS_661)) {
12499	       temp1 = (vgavt + SiSTVVScale[srindex].RealVDE) >> 1;
12500	       temp2 = ((vgavt - SiSTVVScale[srindex].RealVDE) >> 4) + temp1 + 1;
12501	    } else {
12502	       temp1 = (vgavt - SiSTVVScale[srindex].RealVDE) >> 2;
12503	       temp2 = (temp1 < 4) ? 4 : temp1;
12504	       temp1 += SiSTVVScale[srindex].RealVDE;
12505	       temp2 = (temp2 >> 2) + temp1 + 1;
12506	    }
12507	    outSISIDXREG(SISPART1,0x10,(temp1 & 0xff));
12508	    setSISIDXREG(SISPART1,0x11,0x8f,((temp1 >> 4) & 0x70));
12509	    setSISIDXREG(SISPART1,0x11,0xf0,(temp2 & 0x0f));
12510
12511	    setSISIDXREG(SISPART2,0x0a,0x7f,((SiSTVVScale[srindex].reg[2] >> 8) & 0x80));
12512	    outSISIDXREG(SISPART2,0x2f,((newvde / vdediv) - 2));
12513	    setSISIDXREG(SISPART2,0x30,0x3f,((((newvde / vdediv) - 2) >> 2) & 0xc0));
12514
12515	    outSISIDXREG(SISPART4,0x13,(SiSTVVScale[srindex].reg[2] & 0xff));
12516	    outSISIDXREG(SISPART4,0x14,(SiSTVVScale[srindex].reg[3] & 0xff));
12517	    setSISIDXREG(SISPART4,0x15,0x7f,((SiSTVVScale[srindex].reg[3] >> 1) & 0x80));
12518
12519	    temp1 = vgaht - 1;
12520	    outSISIDXREG(SISPART4,0x16,(temp1 & 0xff));
12521	    setSISIDXREG(SISPART4,0x15,0x87,((temp1 >> 5) & 0x78));
12522
12523	    temp1 = vgavt - 1;
12524	    outSISIDXREG(SISPART4,0x17,(temp1 & 0xff));
12525	    setSISIDXREG(SISPART4,0x15,0xf8,((temp1 >> 8) & 0x07));
12526
12527	    outSISIDXREG(SISPART4,0x18,0x00);
12528	    setSISIDXREG(SISPART4,0x19,0xf0,0x00);
12529
12530	    inSISIDXREG(SISPART4,0x0e,temp1);
12531	    if(is1080i) {
12532	       if(!(temp1 & 0xe0)) newvde >>= 1;
12533	    }
12534
12535	    temp = 0x40;
12536	    if(realvde <= newvde) temp = 0;
12537	    else realvde -= newvde;
12538
12539	    calctemp = (realvde * 256 * 1024) / newvde;
12540	    if((realvde * 256 * 1024) % newvde) calctemp++;
12541	    outSISIDXREG(SISPART4,0x1b,(calctemp & 0xff));
12542	    outSISIDXREG(SISPART4,0x1a,((calctemp >> 8) & 0xff));
12543	    setSISIDXREG(SISPART4,0x19,0x8f,(((calctemp >> 12) & 0x70) | temp));
12544	 }
12545
12546      }
12547
12548   }
12549}
12550
12551int SiS_GetTVyscale(ScrnInfoPtr pScrn)
12552{
12553   SISPtr pSiS = SISPTR(pScrn);
12554#ifdef SISDUALHEAD
12555   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12556
12557   if(pSiSEnt && pSiS->DualHeadMode)
12558        return (int)pSiSEnt->tvyscale;
12559   else
12560#endif
12561        return (int)pSiS->tvyscale;
12562}
12563
12564void SiS_SetSISCRT1SaturationGain(ScrnInfoPtr pScrn, int val)
12565{
12566   SISPtr pSiS = SISPTR(pScrn);
12567#ifdef SISDUALHEAD
12568   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12569#endif
12570
12571   pSiS->siscrt1satgain = val;
12572#ifdef SISDUALHEAD
12573   if(pSiSEnt) pSiSEnt->siscrt1satgain = val;
12574#endif
12575
12576   if(!(pSiS->SiS_SD3_Flags & SiS_SD3_CRT1SATGAIN)) return;
12577
12578#ifdef UNLOCK_ALWAYS
12579   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
12580#endif
12581
12582   if((val >= 0) && (val <= 7)) {
12583      setSISIDXREG(SISCR,0x53,0xE3, (val << 2));
12584   }
12585}
12586
12587int SiS_GetSISCRT1SaturationGain(ScrnInfoPtr pScrn)
12588{
12589   SISPtr pSiS = SISPTR(pScrn);
12590   int result = pSiS->siscrt1satgain;
12591   UChar temp;
12592#ifdef SISDUALHEAD
12593   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12594
12595   if(pSiSEnt && pSiS->DualHeadMode)  result = pSiSEnt->siscrt1satgain;
12596#endif
12597
12598   if(!(pSiS->SiS_SD3_Flags & SiS_SD3_CRT1SATGAIN)) return result;
12599
12600#ifdef UNLOCK_ALWAYS
12601   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
12602#endif
12603   inSISIDXREG(SISCR, 0x53, temp);
12604   return (int)((temp >> 2) & 0x07);
12605}
12606
12607/* Calc dotclock from registers */
12608static int
12609SiSGetClockFromRegs(UChar sr2b, UChar sr2c)
12610{
12611   float num, denum, postscalar, divider;
12612   int   myclock;
12613
12614   divider = (sr2b & 0x80) ? 2.0 : 1.0;
12615   postscalar = (sr2c & 0x80) ?
12616              ( (((sr2c >> 5) & 0x03) == 0x02) ? 6.0 : 8.0 ) :
12617	      ( ((sr2c >> 5) & 0x03) + 1.0 );
12618   num = (sr2b & 0x7f) + 1.0;
12619   denum = (sr2c & 0x1f) + 1.0;
12620   myclock = (int)((14318 * (divider / postscalar) * (num / denum)) / 1000);
12621   return myclock;
12622}
12623
12624#ifdef SISDUALHEAD
12625static void
12626SiS_SetDHFlags(SISPtr pSiS, unsigned int misc, unsigned int sd2)
12627{
12628   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12629
12630   if(pSiS->DualHeadMode) {
12631      if(pSiSEnt->pScrn_1) {
12632	 SISPTR(pSiSEnt->pScrn_1)->MiscFlags |= misc;
12633	 SISPTR(pSiSEnt->pScrn_1)->SiS_SD2_Flags |= sd2;
12634      }
12635      if(pSiSEnt->pScrn_2) {
12636	 SISPTR(pSiSEnt->pScrn_2)->MiscFlags |= misc;
12637	 SISPTR(pSiSEnt->pScrn_2)->SiS_SD2_Flags |= sd2;
12638      }
12639   }
12640}
12641#endif
12642
12643/* PostSetMode:
12644 * -) Disable CRT1 for saving bandwidth. This doesn't work with VESA;
12645 *    VESA uses the bridge in SlaveMode and switching CRT1 off while
12646 *    the bridge is in SlaveMode not that clever...
12647 * -) Check if overlay can be used (depending on dotclock)
12648 * -) Check if Panel Scaler is active on LVDS for overlay re-scaling
12649 * -) Save TV registers for further processing
12650 * -) Apply TV settings
12651 */
12652static void
12653SiSPostSetMode(ScrnInfoPtr pScrn, SISRegPtr sisReg)
12654{
12655    SISPtr pSiS = SISPTR(pScrn);
12656#ifdef SISDUALHEAD
12657    SISEntPtr pSiSEnt = pSiS->entityPrivate;
12658#endif
12659    UChar usScratchCR17, sr2b, sr2c, tmpreg;
12660    int   myclock1, myclock2, mycoldepth1, mycoldepth2, temp;
12661    Bool  flag = FALSE;
12662    Bool  doit = TRUE;
12663    Bool  IsInSlaveMode;
12664
12665#ifdef TWDEBUG
12666    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
12667    	"CRT1off is %d\n", pSiS->CRT1off);
12668#endif
12669    pSiS->CRT1isoff = pSiS->CRT1off;
12670
12671#ifdef UNLOCK_ALWAYS
12672    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
12673#endif
12674
12675    SiSFixupSR11(pScrn);
12676
12677    IsInSlaveMode = SiSBridgeIsInSlaveMode(pScrn);
12678
12679    if((!pSiS->UseVESA) && (pSiS->VBFlags & CRT2_ENABLE)) {
12680
12681	if(pSiS->VBFlags != pSiS->VBFlags_backup) {
12682	   pSiS->VBFlags = pSiS->VBFlags_backup;
12683	   xf86DrvMsg(pScrn->scrnIndex, X_INFO,
12684			"VBFlags restored to %0x\n", pSiS->VBFlags);
12685	}
12686
12687	/* -) We can't switch off CRT1 if bridge is in SlaveMode.
12688	 * -) If we change to a SlaveMode-Mode (like 512x384), we
12689	 *    need to adapt VBFlags for eg. Xv.
12690	 */
12691#ifdef SISDUALHEAD
12692	if(!pSiS->DualHeadMode) {
12693#endif
12694	   if(IsInSlaveMode) {
12695	      doit = FALSE;
12696	      temp = pSiS->VBFlags;
12697	      pSiS->VBFlags &= (~VB_DISPMODE_SINGLE);
12698	      pSiS->VBFlags |= (VB_DISPMODE_MIRROR | DISPTYPE_DISP1);
12699              if(temp != pSiS->VBFlags) {
12700		 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
12701		 	"VBFlags changed to 0x%0x\n", pSiS->VBFlags);
12702	      }
12703	   }
12704#ifdef SISDUALHEAD
12705	}
12706#endif
12707
12708	if(pSiS->VGAEngine == SIS_315_VGA) {
12709
12710	   if((pSiS->CRT1off) && (doit)) {
12711	      orSISIDXREG(SISCR,pSiS->myCR63,0x40);
12712	      orSISIDXREG(SISSR,0x1f,0xc0);
12713	      andSISIDXREG(SISSR,0x07,~0x10);
12714	      andSISIDXREG(SISSR,0x06,0xe2);
12715	      andSISIDXREG(SISSR,0x31,0xcf);
12716	      outSISIDXREG(SISSR,0x2b,0x1b);
12717	      outSISIDXREG(SISSR,0x2c,0xe1);
12718	      outSISIDXREG(SISSR,0x2d,0x01);
12719	      outSISIDXREG(SISSR, 0x00, 0x01);    /* Synchronous Reset */
12720	      usleep(10000);
12721	      outSISIDXREG(SISSR, 0x00, 0x03);    /* End Reset */
12722	   } else {
12723	      andSISIDXREG(SISCR,pSiS->myCR63,0xBF);
12724	      andSISIDXREG(SISSR,0x1f,0x3f);
12725	      orSISIDXREG(SISSR,0x07,0x10);
12726	   }
12727
12728	} else {
12729
12730	   if(doit) {
12731	      inSISIDXREG(SISCR, 0x17, usScratchCR17);
12732	      if(pSiS->CRT1off) {
12733		 if(usScratchCR17 & 0x80) {
12734		    flag = TRUE;
12735		    usScratchCR17 &= ~0x80;
12736		 }
12737		 orSISIDXREG(SISSR,0x1f,0xc0);
12738	      } else {
12739		 if(!(usScratchCR17 & 0x80)) {
12740		    flag = TRUE;
12741		    usScratchCR17 |= 0x80;
12742		 }
12743		 andSISIDXREG(SISSR,0x1f,0x3f);
12744	      }
12745	      /* Reset only if status changed */
12746	      if(flag) {
12747		 outSISIDXREG(SISCR, 0x17, usScratchCR17);
12748		 outSISIDXREG(SISSR, 0x00, 0x01);    /* Synchronous Reset */
12749		 usleep(10000);
12750		 outSISIDXREG(SISSR, 0x00, 0x03);    /* End Reset */
12751	      }
12752	   }
12753	}
12754
12755    }
12756
12757    /* Set bridge to "disable CRT2" mode if CRT2 is disabled, LCD-A is enabled */
12758    /* (Not needed for CRT1=VGA since CRT2 will really be disabled then) */
12759#ifdef SISDUALHEAD
12760    if(!pSiS->DualHeadMode) {
12761#endif
12762       if((pSiS->VGAEngine == SIS_315_VGA)  && (pSiS->VBFlags2 & VB2_SISLCDABRIDGE)) {
12763	  if((!pSiS->UseVESA) && (!(pSiS->VBFlags & CRT2_ENABLE)) && (pSiS->VBFlags & CRT1_LCDA)) {
12764	     if(!IsInSlaveMode) {
12765	        andSISIDXREG(SISPART4,0x0d,~0x07);
12766	     }
12767	  }
12768       }
12769#ifdef SISDUALHEAD
12770    }
12771#endif
12772
12773    /* Reset flags */
12774    pSiS->MiscFlags &= ~( MISC_CRT1OVERLAY      |
12775			  MISC_CRT2OVERLAY      |
12776			  MISC_CRT1OVERLAYGAMMA |
12777			  MISC_SIS760ONEOVERLAY |
12778			  MISC_PANELLINKSCALER  |
12779			  MISC_STNMODE		|
12780			  MISC_TVNTSC1024);
12781
12782    pSiS->SiS_SD2_Flags &= ~SiS_SD2_SIS760ONEOVL;
12783
12784#ifdef SISDUALHEAD
12785    if(pSiS->DualHeadMode) {
12786       if(pSiSEnt->pScrn_1) {
12787	  SISPTR(pSiSEnt->pScrn_1)->MiscFlags &= ~(MISC_SIS760ONEOVERLAY	|
12788						   MISC_CRT1OVERLAY		|
12789						   MISC_CRT2OVERLAY		|
12790						   MISC_CRT1OVERLAYGAMMA	|
12791						   MISC_PANELLINKSCALER		|
12792						   MISC_STNMODE			|
12793						   MISC_TVNTSC1024);
12794	  SISPTR(pSiSEnt->pScrn_1)->SiS_SD2_Flags &= ~SiS_SD2_SIS760ONEOVL;
12795       }
12796       if(pSiSEnt->pScrn_2) {
12797	  SISPTR(pSiSEnt->pScrn_2)->MiscFlags &= ~(MISC_SIS760ONEOVERLAY	|
12798						   MISC_CRT1OVERLAY		|
12799						   MISC_CRT2OVERLAY		|
12800						   MISC_CRT1OVERLAYGAMMA	|
12801						   MISC_PANELLINKSCALER		|
12802						   MISC_STNMODE			|
12803						   MISC_TVNTSC1024);
12804	  SISPTR(pSiSEnt->pScrn_2)->SiS_SD2_Flags &= ~SiS_SD2_SIS760ONEOVL;
12805       }
12806    }
12807#endif
12808
12809    /* Determine if the video overlay can be used */
12810    if(!pSiS->NoXvideo) {
12811
12812       int clklimit1=0, clklimit2=0, clklimitg=0;
12813       Bool OverlayHandled = FALSE;
12814
12815       inSISIDXREG(SISSR,0x2b,sr2b);
12816       inSISIDXREG(SISSR,0x2c,sr2c);
12817       myclock1 = myclock2 = SiSGetClockFromRegs(sr2b, sr2c);
12818       inSISIDXREG(SISSR,0x06,tmpreg);
12819       switch((tmpreg & 0x1c) >> 2) {
12820       case 0:  mycoldepth1 = 1; break;
12821       case 1:
12822       case 2:  mycoldepth1 = 2; break;
12823       default: mycoldepth1 = 4;
12824       }
12825       mycoldepth2 = mycoldepth1;
12826
12827       if((!IsInSlaveMode) && (pSiS->VBFlags & CRT2_ENABLE)) {
12828	  if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
12829	     inSISIDXREG(SISPART4,0x0a,sr2b);
12830	     inSISIDXREG(SISPART4,0x0b,sr2c);
12831	  } else {
12832	     inSISIDXREG(SISSR,0x2e,sr2b);
12833	     inSISIDXREG(SISSR,0x2f,sr2c);
12834	  }
12835	  myclock2 = SiSGetClockFromRegs(sr2b, sr2c);
12836	  inSISIDXREG(SISPART1,0x00,tmpreg);
12837	  tmpreg &= 0x0f;
12838	  switch(tmpreg) {
12839	  case 8:  mycoldepth2 = 1; break;
12840	  case 4:
12841	  case 2:  mycoldepth2 = 2; break;
12842	  default: mycoldepth2 = 4;
12843	  }
12844       }
12845
12846       switch(pSiS->ChipType) {
12847
12848	 case SIS_300:
12849	 case SIS_540:
12850	 case SIS_630:
12851	 case SIS_730:
12852	    clklimit1 = clklimit2 = clklimitg = 150;
12853	    break;
12854
12855	 case SIS_550:
12856	 case SIS_650:
12857	 case SIS_740:
12858	    clklimit1 = clklimit2 = 175;  /* verified for 65x */
12859	    clklimitg = 166;		  /* ? */
12860	    break;
12861
12862	 case SIS_661:
12863	 case SIS_741:
12864	    clklimit1 = clklimit2 = 190;  /* ? */
12865	    clklimitg = 180;		  /* ? */
12866	    break;
12867
12868	 case SIS_760:
12869	 case SIS_761:
12870	    clklimit1 = clklimit2 = 190;    /* ? */
12871	    if(pSiS->ChipFlags & SiSCF_760LFB) {		/* LFB only or hybrid */
12872	       clklimit1 = clklimit2 = 220; /* ? */
12873	    }
12874	    clklimitg = 200;		    /* ? */
12875
12876	    if(pSiS->SiS_SD2_Flags & SiS_SD2_SUPPORT760OO) {	/* UMA only */
12877
12878	       Bool OnlyOne = FALSE, NoOverlay = FALSE;
12879	       int dotclocksum = 0;
12880
12881	       if(pSiS->VBFlags & DISPTYPE_CRT1)                     dotclocksum += myclock1;
12882	       if((!IsInSlaveMode) && (pSiS->VBFlags & CRT2_ENABLE)) dotclocksum += myclock2;
12883
12884	       /* TODO: Find out under what circumstances only one
12885		*	overlay is usable in UMA-only mode.
12886		*	This is not entirely accurate; the overlay
12887		*	scaler also requires some time, so even though
12888		*	the dotclocks are below these values, some
12889		*	distortions in the overlay may occure.
12890		*	Solution: Don't use a 760 with shared memory.
12891		*/
12892	       if( (pSiS->VBFlags & DISPTYPE_CRT1) &&
12893		   (pSiS->VBFlags & CRT2_ENABLE) &&
12894		   (mycoldepth1 != mycoldepth2) ) {
12895
12896		  /* 0. If coldepths are different (only possible in dual head mode),
12897		   *    I have no idea to calculate the limits; hence, allow only one
12898		   *    overlay in all cases.
12899		   */
12900		  OnlyOne = TRUE;
12901
12902	       } else if(pSiS->MemClock < 150000) {
12903
12904		  /* 1. MCLK <150: If someone seriously considers using such
12905		   *    slow RAM, so be it. Only one overlay in call cases.
12906		   */
12907		  OnlyOne = TRUE;
12908
12909	       } else if(pSiS->MemClock < 170000) {
12910
12911		  /* 2. MCLK 166 */
12912		  switch(pSiS->CurrentLayout.bitsPerPixel) {
12913		     case 32: if(dotclocksum > 133) OnlyOne = TRUE;		/* One overlay; verified */
12914			      if(dotclocksum > 180) NoOverlay = TRUE;		/* No overlay; verified */
12915			      break;
12916		     case 16: if(dotclocksum > 175) OnlyOne = TRUE;		/* One overlay; verified */
12917			      if(dotclocksum > 260) NoOverlay = TRUE;;		/* No overlay; FIXME */
12918			      break;
12919		  }
12920
12921	       } else if(pSiS->MemClock < 210000) {
12922
12923		  /* 3. MCLK 200 */
12924		  switch(pSiS->CurrentLayout.bitsPerPixel) {
12925		     case 32: if(dotclocksum > 160) OnlyOne = TRUE;		/* One overlay; FIXME */
12926			      if(dotclocksum > 216) NoOverlay = TRUE;;		/* No overlay; FIXME */
12927			      break;
12928		     case 16: if(dotclocksum > 210) OnlyOne = TRUE;		/* One overlay; FIXME */
12929			      if(dotclocksum > 312) NoOverlay = TRUE;;		/* No overlay; FIXME */
12930			      break;
12931		  }
12932
12933	       }
12934
12935	       if(OnlyOne || NoOverlay) {
12936
12937		  ULong tmpflags = 0;
12938
12939		  if(!NoOverlay) {
12940		     if(myclock1 <= clklimit1) tmpflags |= MISC_CRT1OVERLAY;
12941		     if(myclock2 <= clklimit2) tmpflags |= MISC_CRT2OVERLAY;
12942		     if(myclock1 <= clklimitg) tmpflags |= MISC_CRT1OVERLAYGAMMA;
12943		     pSiS->MiscFlags |= tmpflags;
12944		  }
12945		  pSiS->MiscFlags |= MISC_SIS760ONEOVERLAY;
12946		  pSiS->SiS_SD2_Flags |= SiS_SD2_SIS760ONEOVL;
12947#ifdef SISDUALHEAD
12948		  SiS_SetDHFlags(pSiS, (tmpflags | MISC_SIS760ONEOVERLAY), SiS_SD2_SIS760ONEOVL);
12949#endif
12950		  OverlayHandled = TRUE;
12951	       }
12952
12953	       xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
12954			"SiS76x/UMA: %s video overlay(s) available in current mode\n",
12955			NoOverlay ? "no" : ((pSiS->MiscFlags & MISC_SIS760ONEOVERLAY) ? "one" : "two"));
12956
12957#ifdef TWDEBUG
12958	       xf86DrvMsg(0, 0, "SiS760: Memclock %d, c1 %d/%d c2 %d/%d, sum %d / %x\n",
12959			pSiS->MemClock, myclock1, mycoldepth1,
12960			myclock2, mycoldepth2, dotclocksum, pSiS->SiS_SD2_Flags);
12961#endif
12962	    }
12963	    break;
12964
12965	 case SIS_660:
12966	    clklimit1 = clklimit2 = 200;  /* ? */
12967	    if(pSiS->ChipFlags & SiSCF_760LFB) {		/* LFB only */
12968	       clklimit1 = clklimit2 = 220;
12969	    }
12970	    clklimitg = 200;		  /* ? */
12971	    break;
12972
12973	 case SIS_315H:
12974	 case SIS_315:
12975	 case SIS_315PRO:
12976	 case SIS_330:
12977	    clklimit1 = clklimit2 = 180;  /* ? */
12978	    clklimitg = 166;		  /* ? */
12979	    break;
12980
12981	 case SIS_340: /* ? */
12982	 case XGI_20:
12983	 case XGI_40:
12984	    clklimit1 = clklimit2 = 240;  /* ? */
12985	    clklimitg = 200;		  /* ? */
12986	    break;
12987       }
12988
12989       if(!OverlayHandled) {
12990          ULong tmpflags = 0;
12991          if(myclock1 <= clklimit1) tmpflags |= MISC_CRT1OVERLAY;
12992          if(myclock2 <= clklimit2) tmpflags |= MISC_CRT2OVERLAY;
12993          if(myclock1 <= clklimitg) tmpflags |= MISC_CRT1OVERLAYGAMMA;
12994	  pSiS->MiscFlags |= tmpflags;
12995#ifdef SISDUALHEAD
12996	  SiS_SetDHFlags(pSiS, tmpflags, 0);
12997#endif
12998          if(!(pSiS->MiscFlags & MISC_CRT1OVERLAY)) {
12999#ifdef SISDUALHEAD
13000             if((!pSiS->DualHeadMode) || (pSiS->SecondHead))
13001#endif
13002		xf86DrvMsgVerb(pScrn->scrnIndex, X_WARNING, 3,
13003		   "Current dotclock (%dMhz) too high for video overlay on CRT1\n",
13004		   myclock1);
13005          }
13006          if((pSiS->VBFlags & CRT2_ENABLE) && (!(pSiS->MiscFlags & MISC_CRT2OVERLAY))) {
13007#ifdef SISDUALHEAD
13008	     if((!pSiS->DualHeadMode) || (!pSiS->SecondHead))
13009#endif
13010		xf86DrvMsgVerb(pScrn->scrnIndex, X_WARNING, 3,
13011		   "Current dotclock (%dMhz) too high for video overlay on CRT2\n",
13012		   myclock2);
13013	  }
13014       }
13015
13016    }
13017
13018    /* Determine if the Panel Link scaler is active */
13019
13020    if(pSiS->VBFlags & (CRT2_LCD | CRT1_LCDA)) {
13021       ULong tmpflags = 0;
13022       if(pSiS->VGAEngine == SIS_300_VGA) {
13023	  if(pSiS->VBFlags2 & (VB2_LVDS | VB2_30xBDH)) {
13024	     inSISIDXREG(SISPART1,0x1e,tmpreg);
13025	     tmpreg &= 0x3f;
13026	     if(tmpreg) tmpflags |= MISC_PANELLINKSCALER;
13027	  }
13028       } else {
13029	  if((pSiS->VBFlags2 & (VB2_LVDS | VB2_30xBDH)) || (pSiS->VBFlags & CRT1_LCDA)) {
13030	     inSISIDXREG(SISPART1,0x35,tmpreg);
13031	     tmpreg &= 0x04;
13032	     if(!tmpreg)  tmpflags |= MISC_PANELLINKSCALER;
13033	  }
13034       }
13035       pSiS->MiscFlags |= tmpflags;
13036#ifdef SISDUALHEAD
13037       SiS_SetDHFlags(pSiS, tmpflags, 0);
13038#endif
13039    }
13040
13041    /* Determine if STN is active */
13042    if(pSiS->ChipType == SIS_550) {
13043       if((pSiS->VBFlags & CRT2_LCD) && (pSiS->FSTN || pSiS->DSTN)) {
13044	  inSISIDXREG(SISCR,0x34,tmpreg);
13045	  tmpreg &= 0x7f;
13046	  if(tmpreg == 0x5a || tmpreg == 0x5b) {
13047	     pSiS->MiscFlags |= MISC_STNMODE;
13048#ifdef SISDUALHEAD
13049	     SiS_SetDHFlags(pSiS, MISC_STNMODE, 0);
13050#endif
13051	  }
13052       }
13053    }
13054
13055    /* Determine if our very special TV mode is active */
13056    if((pSiS->VBFlags2 & VB2_SISBRIDGE) && (pSiS->VBFlags & CRT2_TV) && (!(pSiS->VBFlags & TV_HIVISION))) {
13057       if( ((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR525I)) ||
13058	   ((!(pSiS->VBFlags & TV_YPBPR)) && (pSiS->VBFlags & (TV_NTSC | TV_PALM))) ) {
13059	  inSISIDXREG(SISCR,0x34,tmpreg);
13060	  tmpreg &= 0x7f;
13061	  if((tmpreg == 0x64) || (tmpreg == 0x4a) || (tmpreg == 0x38)) {
13062	     pSiS->MiscFlags |= MISC_TVNTSC1024;
13063#ifdef SISDUALHEAD
13064	     SiS_SetDHFlags(pSiS, MISC_TVNTSC1024, 0);
13065#endif
13066	  }
13067       }
13068    }
13069
13070    if(pSiS->VGAEngine == SIS_315_VGA) {
13071       int i;
13072#ifdef SISVRAMQ
13073       /* Re-Enable and reset command queue */
13074       SiSEnableTurboQueue(pScrn);
13075#endif
13076       /* Get HWCursor register contents for backup */
13077       for(i = 0; i < 16; i++) {
13078          pSiS->HWCursorBackup[i] = SIS_MMIO_IN32(pSiS->IOBase, 0x8500 + (i << 2));
13079       }
13080       if(pSiS->ChipType >= SIS_330) {
13081          /* Enable HWCursor protection (Y pos as trigger) */
13082          andSISIDXREG(SISCR, 0x5b, ~0x30);
13083       }
13084    }
13085
13086    /* Re-initialize accelerator engine */
13087    /* (We are sync'ed here) */
13088    if(!pSiS->NoAccel) {
13089       if(pSiS->InitAccel) {
13090          (pSiS->InitAccel)(pScrn);
13091       }
13092    }
13093
13094    /* Set display device gamma (for SISCTRL) */
13095    if(pSiS->VBFlags & CRT1_LCDA)
13096       pSiS->CRT1MonGamma = pSiS->CRT2LCDMonitorGamma;
13097    else
13098       pSiS->CRT1MonGamma = pSiS->CRT1VGAMonitorGamma;
13099
13100    if(pSiS->VBFlags & CRT2_LCD)
13101       pSiS->CRT2MonGamma = pSiS->CRT2LCDMonitorGamma;
13102    else if(pSiS->VBFlags & CRT2_TV) {
13103       if(pSiS->VBFlags & TV_YPBPR)
13104          pSiS->CRT2MonGamma = 2200; /* */
13105       else if(pSiS->VBFlags & TV_HIVISION)
13106          pSiS->CRT2MonGamma = 2200; /* ? */
13107       else if(pSiS->VBFlags & TV_NTSC)
13108          pSiS->CRT2MonGamma = 2200; /* NTSC */
13109       else
13110          pSiS->CRT2MonGamma = 2800; /* All PAL modes? */
13111    } else if(pSiS->VBFlags & CRT2_VGA)
13112       pSiS->CRT2MonGamma = pSiS->CRT2VGAMonitorGamma;
13113    else
13114       pSiS->CRT2MonGamma = 0; /* Unknown */
13115
13116    /* Reset XV display properties (such as number of overlays, etc) */
13117    /* (And copy monitor gamma) */
13118#ifdef SISDUALHEAD
13119    if(pSiS->DualHeadMode) {
13120       if(pSiSEnt->pScrn_1) {
13121	  if(SISPTR(pSiSEnt->pScrn_1)->ResetXvDisplay) {
13122	     (SISPTR(pSiSEnt->pScrn_1)->ResetXvDisplay)(pSiSEnt->pScrn_1);
13123	  }
13124	  SISPTR(pSiSEnt->pScrn_1)->CRT1MonGamma = pSiS->CRT1MonGamma;
13125	  SISPTR(pSiSEnt->pScrn_1)->CRT2MonGamma = pSiS->CRT2MonGamma;
13126       }
13127       if(pSiSEnt->pScrn_2) {
13128	  if(SISPTR(pSiSEnt->pScrn_2)->ResetXvDisplay) {
13129	     (SISPTR(pSiSEnt->pScrn_1)->ResetXvDisplay)(pSiSEnt->pScrn_2);
13130	  }
13131	  SISPTR(pSiSEnt->pScrn_2)->CRT1MonGamma = pSiS->CRT1MonGamma;
13132	  SISPTR(pSiSEnt->pScrn_2)->CRT2MonGamma = pSiS->CRT2MonGamma;
13133       }
13134    } else {
13135#endif
13136       if(pSiS->ResetXvDisplay) {
13137	  (pSiS->ResetXvDisplay)(pScrn);
13138       }
13139#ifdef SISDUALHEAD
13140    }
13141#endif
13142
13143    /* Reset XV gamma correction */
13144    if(pSiS->ResetXvGamma) {
13145       (pSiS->ResetXvGamma)(pScrn);
13146    }
13147
13148    /* Reset various display parameters */
13149    {
13150       int val = pSiS->siscrt1satgain;
13151#ifdef SISDUALHEAD
13152       if(pSiS->DualHeadMode && pSiSEnt) val = pSiSEnt->siscrt1satgain;
13153#endif
13154       SiS_SetSISCRT1SaturationGain(pScrn, val);
13155    }
13156
13157    /*  Apply TV settings given by options
13158           Do this even in DualHeadMode:
13159	   - if this is called by SetModeCRT1, CRT2 mode has been reset by SetModeCRT1
13160	   - if this is called by SetModeCRT2, CRT2 mode has changed (duh!)
13161	   -> Hence, in both cases, the settings must be re-applied.
13162     */
13163
13164    if(pSiS->VBFlags & CRT2_TV) {
13165       int val;
13166       if(pSiS->VBFlags2 & VB2_CHRONTEL) {
13167	  int mychtvlumabandwidthcvbs = pSiS->chtvlumabandwidthcvbs;
13168	  int mychtvlumabandwidthsvideo = pSiS->chtvlumabandwidthsvideo;
13169	  int mychtvlumaflickerfilter = pSiS->chtvlumaflickerfilter;
13170	  int mychtvchromabandwidth = pSiS->chtvchromabandwidth;
13171	  int mychtvchromaflickerfilter = pSiS->chtvchromaflickerfilter;
13172	  int mychtvcvbscolor = pSiS->chtvcvbscolor;
13173	  int mychtvtextenhance = pSiS->chtvtextenhance;
13174	  int mychtvcontrast = pSiS->chtvcontrast;
13175	  int mytvxpos = pSiS->tvxpos;
13176	  int mytvypos = pSiS->tvypos;
13177#ifdef SISDUALHEAD
13178	  if(pSiSEnt && pSiS->DualHeadMode) {
13179	     mychtvlumabandwidthcvbs = pSiSEnt->chtvlumabandwidthcvbs;
13180	     mychtvlumabandwidthsvideo = pSiSEnt->chtvlumabandwidthsvideo;
13181	     mychtvlumaflickerfilter = pSiSEnt->chtvlumaflickerfilter;
13182	     mychtvchromabandwidth = pSiSEnt->chtvchromabandwidth;
13183	     mychtvchromaflickerfilter = pSiSEnt->chtvchromaflickerfilter;
13184	     mychtvcvbscolor = pSiSEnt->chtvcvbscolor;
13185	     mychtvtextenhance = pSiSEnt->chtvtextenhance;
13186	     mychtvcontrast = pSiSEnt->chtvcontrast;
13187	     mytvxpos = pSiSEnt->tvxpos;
13188	     mytvypos = pSiSEnt->tvypos;
13189	  }
13190#endif
13191	  if((val = mychtvlumabandwidthcvbs) != -1) {
13192	     SiS_SetCHTVlumabandwidthcvbs(pScrn, val);
13193	  }
13194	  if((val = mychtvlumabandwidthsvideo) != -1) {
13195	     SiS_SetCHTVlumabandwidthsvideo(pScrn, val);
13196	  }
13197	  if((val = mychtvlumaflickerfilter) != -1) {
13198	     SiS_SetCHTVlumaflickerfilter(pScrn, val);
13199	  }
13200	  if((val = mychtvchromabandwidth) != -1) {
13201	     SiS_SetCHTVchromabandwidth(pScrn, val);
13202	  }
13203	  if((val = mychtvchromaflickerfilter) != -1) {
13204	     SiS_SetCHTVchromaflickerfilter(pScrn, val);
13205	  }
13206	  if((val = mychtvcvbscolor) != -1) {
13207	     SiS_SetCHTVcvbscolor(pScrn, val);
13208	  }
13209	  if((val = mychtvtextenhance) != -1) {
13210	     SiS_SetCHTVtextenhance(pScrn, val);
13211	  }
13212	  if((val = mychtvcontrast) != -1) {
13213	     SiS_SetCHTVcontrast(pScrn, val);
13214	  }
13215	  /* Backup default TV position registers */
13216	  switch(pSiS->ChrontelType) {
13217	  case CHRONTEL_700x:
13218	     pSiS->tvx = SiS_GetCH700x(pSiS->SiS_Pr, 0x0a);
13219	     pSiS->tvx |= (((SiS_GetCH700x(pSiS->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
13220	     pSiS->tvy = SiS_GetCH700x(pSiS->SiS_Pr, 0x0b);
13221	     pSiS->tvy |= ((SiS_GetCH700x(pSiS->SiS_Pr, 0x08) & 0x01) << 8);
13222#ifdef SISDUALHEAD
13223	     if(pSiSEnt) {
13224		pSiSEnt->tvx = pSiS->tvx;
13225		pSiSEnt->tvy = pSiS->tvy;
13226	     }
13227#endif
13228	     break;
13229	  case CHRONTEL_701x:
13230	     /* Not supported by hardware */
13231	     break;
13232	  }
13233	  if((val = mytvxpos) != 0) {
13234	     SiS_SetTVxposoffset(pScrn, val);
13235	  }
13236	  if((val = mytvypos) != 0) {
13237	     SiS_SetTVyposoffset(pScrn, val);
13238	  }
13239       }
13240       if(pSiS->VBFlags2 & VB2_301) {
13241          int mysistvedgeenhance = pSiS->sistvedgeenhance;
13242#ifdef SISDUALHEAD
13243          if(pSiSEnt && pSiS->DualHeadMode) {
13244	     mysistvedgeenhance = pSiSEnt->sistvedgeenhance;
13245	  }
13246#endif
13247          if((val = mysistvedgeenhance) != -1) {
13248	     SiS_SetSISTVedgeenhance(pScrn, val);
13249	  }
13250       }
13251       if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
13252          int mysistvantiflicker = pSiS->sistvantiflicker;
13253	  int mysistvsaturation = pSiS->sistvsaturation;
13254	  int mysistvcolcalibf = pSiS->sistvcolcalibf;
13255	  int mysistvcolcalibc = pSiS->sistvcolcalibc;
13256	  int mysistvcfilter = pSiS->sistvcfilter;
13257	  int mysistvyfilter = pSiS->sistvyfilter;
13258	  int mytvxpos = pSiS->tvxpos;
13259	  int mytvypos = pSiS->tvypos;
13260	  int mytvxscale = pSiS->tvxscale;
13261	  int mytvyscale = pSiS->tvyscale;
13262	  int i;
13263	  ULong cbase;
13264	  UChar ctemp;
13265#ifdef SISDUALHEAD
13266          if(pSiSEnt && pSiS->DualHeadMode) {
13267	     mysistvantiflicker = pSiSEnt->sistvantiflicker;
13268	     mysistvsaturation = pSiSEnt->sistvsaturation;
13269	     mysistvcolcalibf = pSiSEnt->sistvcolcalibf;
13270	     mysistvcolcalibc = pSiSEnt->sistvcolcalibc;
13271	     mysistvcfilter = pSiSEnt->sistvcfilter;
13272	     mysistvyfilter = pSiSEnt->sistvyfilter;
13273	     mytvxpos = pSiSEnt->tvxpos;
13274	     mytvypos = pSiSEnt->tvypos;
13275	     mytvxscale = pSiSEnt->tvxscale;
13276	     mytvyscale = pSiSEnt->tvyscale;
13277	  }
13278#endif
13279          /* Backup default TV position, scale and colcalib registers */
13280	  inSISIDXREG(SISPART2,0x1f,pSiS->p2_1f);
13281	  inSISIDXREG(SISPART2,0x20,pSiS->p2_20);
13282	  inSISIDXREG(SISPART2,0x2b,pSiS->p2_2b);
13283	  inSISIDXREG(SISPART2,0x42,pSiS->p2_42);
13284	  inSISIDXREG(SISPART2,0x43,pSiS->p2_43);
13285	  inSISIDXREG(SISPART2,0x01,pSiS->p2_01);
13286	  inSISIDXREG(SISPART2,0x02,pSiS->p2_02);
13287	  inSISIDXREG(SISPART2,0x44,pSiS->p2_44);
13288	  inSISIDXREG(SISPART2,0x45,pSiS->p2_45);
13289	  if(!(pSiS->VBFlags2 & VB2_301)) {
13290	     inSISIDXREG(SISPART2,0x46,pSiS->p2_46);
13291	  } else {
13292	     pSiS->p2_46 = 0;
13293	  }
13294	  inSISIDXREG(SISPART2,0x0a,pSiS->p2_0a);
13295	  inSISIDXREG(SISPART2,0x31,cbase);
13296	  cbase = (cbase & 0x7f) << 8;
13297	  inSISIDXREG(SISPART2,0x32,ctemp);
13298	  cbase = (cbase | ctemp) << 8;
13299	  inSISIDXREG(SISPART2,0x33,ctemp);
13300	  cbase = (cbase | ctemp) << 8;
13301	  inSISIDXREG(SISPART2,0x34,ctemp);
13302	  pSiS->sistvccbase = (cbase | ctemp);
13303	  inSISIDXREG(SISPART2,0x35,pSiS->p2_35);
13304	  inSISIDXREG(SISPART2,0x36,pSiS->p2_36);
13305	  inSISIDXREG(SISPART2,0x37,pSiS->p2_37);
13306	  inSISIDXREG(SISPART2,0x38,pSiS->p2_38);
13307	  if(!(pSiS->VBFlags2 & VB2_301)) {
13308	     inSISIDXREG(SISPART2,0x47,pSiS->p2_47);
13309	     inSISIDXREG(SISPART2,0x48,pSiS->p2_48);
13310	     inSISIDXREG(SISPART2,0x49,pSiS->p2_49);
13311	     inSISIDXREG(SISPART2,0x4a,pSiS->p2_4a);
13312	  }
13313	  inSISIDXREG(SISPART2,0x2f,pSiS->p2_2f);
13314	  inSISIDXREG(SISPART2,0x30,pSiS->p2_30);
13315	  for(i=0; i<9; i++) {
13316	     inSISIDXREG(SISPART1,SiSScalingP1Regs[i],pSiS->scalingp1[i]);
13317	  }
13318	  for(i=0; i<9; i++) {
13319	     inSISIDXREG(SISPART4,SiSScalingP4Regs[i],pSiS->scalingp4[i]);
13320	  }
13321	  if(pSiS->VBFlags2 & VB2_SISTAP4SCALER) {
13322	     for(i=0; i<64; i++) {
13323	        inSISIDXREG(SISPART2,(0xc0 + i),pSiS->scalingp2[i]);
13324  	     }
13325	  }
13326#ifdef SISDUALHEAD
13327	  if(pSiSEnt) {
13328	     pSiSEnt->p2_1f = pSiS->p2_1f; pSiSEnt->p2_20 = pSiS->p2_20;
13329	     pSiSEnt->p2_42 = pSiS->p2_42; pSiSEnt->p2_43 = pSiS->p2_43;
13330	     pSiSEnt->p2_2b = pSiS->p2_2b;
13331	     pSiSEnt->p2_01 = pSiS->p2_01; pSiSEnt->p2_02 = pSiS->p2_02;
13332	     pSiSEnt->p2_44 = pSiS->p2_44; pSiSEnt->p2_45 = pSiS->p2_45;
13333	     pSiSEnt->p2_46 = pSiS->p2_46; pSiSEnt->p2_0a = pSiS->p2_0a;
13334	     pSiSEnt->sistvccbase = pSiS->sistvccbase;
13335	     pSiSEnt->p2_35 = pSiS->p2_35; pSiSEnt->p2_36 = pSiS->p2_36;
13336	     pSiSEnt->p2_37 = pSiS->p2_37; pSiSEnt->p2_38 = pSiS->p2_38;
13337	     pSiSEnt->p2_48 = pSiS->p2_48; pSiSEnt->p2_49 = pSiS->p2_49;
13338	     pSiSEnt->p2_4a = pSiS->p2_4a; pSiSEnt->p2_2f = pSiS->p2_2f;
13339	     pSiSEnt->p2_30 = pSiS->p2_30; pSiSEnt->p2_47 = pSiS->p2_47;
13340	     for(i=0; i<9; i++) {
13341	        pSiSEnt->scalingp1[i] = pSiS->scalingp1[i];
13342	     }
13343	     for(i=0; i<9; i++) {
13344	        pSiSEnt->scalingp4[i] = pSiS->scalingp4[i];
13345	     }
13346	     if(pSiS->VBFlags2 & VB2_SISTAP4SCALER) {
13347	        for(i=0; i<64; i++) {
13348	           pSiSEnt->scalingp2[i] = pSiS->scalingp2[i];
13349  	        }
13350	     }
13351	  }
13352#endif
13353          if((val = mysistvantiflicker) != -1) {
13354	     SiS_SetSISTVantiflicker(pScrn, val);
13355	  }
13356	  if((val = mysistvsaturation) != -1) {
13357	     SiS_SetSISTVsaturation(pScrn, val);
13358	  }
13359	  if((val = mysistvcfilter) != -1) {
13360	     SiS_SetSISTVcfilter(pScrn, val);
13361	  }
13362	  if((val = mysistvyfilter) != 1) {
13363	     SiS_SetSISTVyfilter(pScrn, val);
13364	  }
13365	  if((val = mysistvcolcalibc) != 0) {
13366	     SiS_SetSISTVcolcalib(pScrn, val, TRUE);
13367	  }
13368	  if((val = mysistvcolcalibf) != 0) {
13369	     SiS_SetSISTVcolcalib(pScrn, val, FALSE);
13370	  }
13371	  if((val = mytvxpos) != 0) {
13372	     SiS_SetTVxposoffset(pScrn, val);
13373	  }
13374	  if((val = mytvypos) != 0) {
13375	     SiS_SetTVyposoffset(pScrn, val);
13376	  }
13377	  if((val = mytvxscale) != 0) {
13378	     SiS_SetTVxscale(pScrn, val);
13379	  }
13380	  if((val = mytvyscale) != 0) {
13381	     SiS_SetTVyscale(pScrn, val);
13382	  }
13383       }
13384    }
13385
13386}
13387
13388/* Post-set SiS6326 TV registers */
13389static void
13390SiS6326PostSetMode(ScrnInfoPtr pScrn, SISRegPtr sisReg)
13391{
13392    SISPtr pSiS = SISPTR(pScrn);
13393    UChar tmp;
13394    int val;
13395
13396    if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) return;
13397
13398#ifdef UNLOCK_ALWAYS
13399    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
13400#endif
13401
13402    /* Backup default TV position registers */
13403    pSiS->tvx1 = SiS6326GetTVReg(pScrn,0x3a);
13404    pSiS->tvx1 |= ((SiS6326GetTVReg(pScrn,0x3c) & 0x0f) << 8);
13405    pSiS->tvx2 = SiS6326GetTVReg(pScrn,0x26);
13406    pSiS->tvx2 |= ((SiS6326GetTVReg(pScrn,0x27) & 0xf0) << 4);
13407    pSiS->tvx3 = SiS6326GetTVReg(pScrn,0x12);
13408    pSiS->tvx3 |= ((SiS6326GetTVReg(pScrn,0x13) & 0xC0) << 2);
13409    pSiS->tvy1 = SiS6326GetTVReg(pScrn,0x11);
13410    pSiS->tvy1 |= ((SiS6326GetTVReg(pScrn,0x13) & 0x30) << 4);
13411
13412    /* Handle TVPosOffset options (BEFORE switching on TV) */
13413    if((val = pSiS->tvxpos) != 0) {
13414       SiS_SetTVxposoffset(pScrn, val);
13415    }
13416    if((val = pSiS->tvypos) != 0) {
13417       SiS_SetTVyposoffset(pScrn, val);
13418    }
13419
13420    /* Switch on TV output. This is rather complicated, but
13421     * if we don't do it, TV output will flicker terribly.
13422     */
13423    if(pSiS->SiS6326Flags & SIS6326_TVON) {
13424       orSISIDXREG(SISSR, 0x01, 0x20);
13425       tmp = SiS6326GetTVReg(pScrn,0x00);
13426       tmp &= ~0x04;
13427       while(!(inSISREG(SISINPSTAT) & 0x08));    /* Wait while NOT vb */
13428       SiS6326SetTVReg(pScrn,0x00,tmp);
13429       for(val=0; val < 2; val++) {
13430         while(!(inSISREG(SISINPSTAT) & 0x08));  /* Wait while NOT vb */
13431         while(inSISREG(SISINPSTAT) & 0x08);     /* wait while vb     */
13432       }
13433       SiS6326SetTVReg(pScrn, 0x00, sisReg->sis6326tv[0]);
13434       tmp = inSISREG(SISINPSTAT);
13435       outSISREG(SISAR, 0x20);
13436       tmp = inSISREG(SISINPSTAT);
13437       while(inSISREG(SISINPSTAT) & 0x01);
13438       while(!(inSISREG(SISINPSTAT) & 0x01));
13439       andSISIDXREG(SISSR, 0x01, ~0x20);
13440       for(val=0; val < 10; val++) {
13441         while(!(inSISREG(SISINPSTAT) & 0x08));  /* Wait while NOT vb */
13442         while(inSISREG(SISINPSTAT) & 0x08);     /* wait while vb     */
13443       }
13444       andSISIDXREG(SISSR, 0x01, ~0x20);
13445    }
13446
13447    tmp = SiS6326GetTVReg(pScrn,0x00);
13448    if(!(tmp & 0x04)) return;
13449
13450    /* Apply TV settings given by options */
13451    if((val = pSiS->sistvantiflicker) != -1) {
13452       SiS_SetSIS6326TVantiflicker(pScrn, val);
13453    }
13454    if((val = pSiS->sis6326enableyfilter) != -1) {
13455       SiS_SetSIS6326TVenableyfilter(pScrn, val);
13456    }
13457    if((val = pSiS->sis6326yfilterstrong) != -1) {
13458       SiS_SetSIS6326TVyfilterstrong(pScrn, val);
13459    }
13460
13461}
13462
13463/* Check if video bridge is in slave mode */
13464Bool
13465SiSBridgeIsInSlaveMode(ScrnInfoPtr pScrn)
13466{
13467    SISPtr pSiS = SISPTR(pScrn);
13468    UChar  usScrP1_00;
13469
13470    if(!(pSiS->VBFlags2 & VB2_VIDEOBRIDGE)) return FALSE;
13471
13472    inSISIDXREG(SISPART1,0x00,usScrP1_00);
13473    if( ((pSiS->VGAEngine == SIS_300_VGA) && (usScrP1_00 & 0xa0) == 0x20) ||
13474        ((pSiS->VGAEngine == SIS_315_VGA) && (usScrP1_00 & 0x50) == 0x10) ) {
13475       return TRUE;
13476    }
13477
13478    return FALSE;
13479}
13480
13481/* Build a list of the VESA modes the BIOS reports as valid */
13482static void
13483SiSBuildVesaModeList(ScrnInfoPtr pScrn, vbeInfoPtr pVbe, VbeInfoBlock *vbe)
13484{
13485    SISPtr pSiS = SISPTR(pScrn);
13486    int i = 0;
13487
13488    while(vbe->VideoModePtr[i] != 0xffff) {
13489       sisModeInfoPtr m;
13490       VbeModeInfoBlock *mode;
13491       int id = vbe->VideoModePtr[i++];
13492
13493       if((mode = VBEGetModeInfo(pVbe, id)) == NULL) {
13494	  continue;
13495       }
13496
13497       m = xnfcalloc(sizeof(sisModeInfoRec), 1);
13498       if(!m) {
13499	  VBEFreeModeInfo(mode);
13500	  continue;
13501       }
13502       m->width = mode->XResolution;
13503       m->height = mode->YResolution;
13504       m->bpp = mode->BitsPerPixel;
13505       m->n = id;
13506       m->next = pSiS->SISVESAModeList;
13507
13508       pSiS->SISVESAModeList = m;
13509
13510       VBEFreeModeInfo(mode);
13511
13512       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
13513	   "VESA BIOS supports mode number 0x%x: %ix%i (%i bpp)\n",
13514	   m->n, m->width, m->height, m->bpp);
13515    }
13516}
13517
13518/* Get VESA mode number from given resolution/depth */
13519static UShort
13520SiSCalcVESAModeIndex(ScrnInfoPtr pScrn, DisplayModePtr mode)
13521{
13522    SISPtr pSiS = SISPTR(pScrn);
13523    sisModeInfoPtr m = pSiS->SISVESAModeList;
13524    UShort i = (pScrn->bitsPerPixel+7)/8 - 1;
13525    UShort ModeNumber = 0;
13526    int j;
13527
13528    while(m) {
13529       if( (pScrn->bitsPerPixel == m->bpp) &&
13530	   (mode->HDisplay == m->width)    &&
13531	   (mode->VDisplay == m->height) )
13532	  return m->n;
13533       m = m->next;
13534    }
13535
13536    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
13537        "No valid VESA BIOS mode found for %dx%d (%d bpp)\n",
13538        mode->HDisplay, mode->VDisplay, pScrn->bitsPerPixel);
13539
13540    if(!pSiS->ROM661New) {  /* VESA numbers changed! */
13541       j = 0;
13542       while(VESAModeIndices[j] != 9999) {
13543          if( (mode->HDisplay == VESAModeIndices[j]) &&
13544	      (mode->VDisplay == VESAModeIndices[j+1]) ) {
13545	     ModeNumber = VESAModeIndices[j + 2 + i];
13546	     break;
13547          }
13548          j += 6;
13549       }
13550
13551       if(!ModeNumber) {
13552	  xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
13553	      "No valid mode found for %dx%dx%d in built-in table either.\n",
13554	      mode->HDisplay, mode->VDisplay, pScrn->bitsPerPixel);
13555       }
13556    }
13557
13558    return(ModeNumber);
13559}
13560
13561UShort
13562SiS_GetModeNumber(ScrnInfoPtr pScrn, DisplayModePtr mode, unsigned int VBFlags)
13563{
13564   SISPtr pSiS = SISPTR(pScrn);
13565   UShort i = (pSiS->CurrentLayout.bitsPerPixel+7)/8 - 1;
13566   BOOLEAN FSTN = pSiS->FSTN ? TRUE : FALSE;
13567
13568#ifdef SISDUALHEAD
13569   if(pSiS->DualHeadMode && pSiS->SecondHead) FSTN = FALSE;
13570#endif
13571
13572   return(SiS_GetModeID(pSiS->VGAEngine, VBFlags, mode->HDisplay, mode->VDisplay,
13573			i, FSTN, pSiS->LCDwidth, pSiS->LCDheight));
13574}
13575
13576static Bool
13577SiSValidLCDUserMode(SISPtr pSiS, unsigned int VBFlags, DisplayModePtr mode, Bool isforlcda)
13578{
13579   if(mode->Flags & V_INTERLACE) return FALSE;
13580
13581   if(mode->HDisplay > 2048) return FALSE;
13582   if(mode->VDisplay > 1536) return FALSE;
13583
13584   if(pSiS->VBFlags2 & VB2_LCD162MHZBRIDGE) {
13585      if(mode->Clock > 162500) return FALSE;
13586#ifdef VB_FORBID_CRT2LCD_OVER_1600
13587      if(!isforlcda) {
13588         if(mode->HDisplay > 1600) return FALSE;
13589      }
13590#endif
13591   } else { /* 301, 301B, 302B (no LCDA!) */
13592      if(mode->Clock > 130000)  return FALSE;
13593      if(mode->Clock > 111000) {
13594         xf86DrvMsg(pSiS->pScrn->scrnIndex, X_WARNING,
13595	 	"WARNING: Mode clock beyond video bridge specs (%dMHz). Hardware damage might occure.\n",
13596		mode->Clock / 1000);
13597      }
13598      if(mode->HDisplay > 1600) return FALSE;
13599      if(mode->VDisplay > 1024) return FALSE;
13600   }
13601
13602   return TRUE;
13603}
13604
13605static Bool
13606SiSValidVGA2UserMode(SISPtr pSiS, unsigned int VBFlags, DisplayModePtr mode)
13607{
13608   if(mode->Flags & V_INTERLACE) return FALSE;
13609
13610   if(mode->HDisplay > 2048) return FALSE;
13611   if(mode->VDisplay > 1536) return FALSE;
13612
13613   if(pSiS->VBFlags2 & VB2_RAMDAC202MHZBRIDGE) {
13614      if(mode->Clock > 203000) return FALSE;
13615   } else if(pSiS->VBFlags2 & VB2_30xBLV) {
13616      if(mode->Clock > 162500) return FALSE;
13617   } else {
13618      if(mode->Clock > 135500) return FALSE;
13619   }
13620
13621   return TRUE;
13622}
13623
13624UShort
13625SiS_CheckModeCRT1(ScrnInfoPtr pScrn, DisplayModePtr mode, unsigned int VBFlags, Bool havecustommodes)
13626{
13627   SISPtr pSiS = SISPTR(pScrn);
13628   UShort i = (pSiS->CurrentLayout.bitsPerPixel+7)/8 - 1;
13629   int j;
13630
13631   if(!(VBFlags & CRT1_LCDA)) {
13632
13633      if((havecustommodes) && (!(mode->type & M_T_DEFAULT))) {
13634         return 0xfe;
13635      }
13636
13637   } else if(pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE) {
13638
13639      if(pSiS->ChipType < SIS_661) {  /* < 661 only? */
13640         if(!(mode->type & M_T_DEFAULT)) {
13641            if(mode->HTotal > 2055) return 0;
13642	    /* (Default mode will be caught in mode switching code) */
13643	 }
13644      }
13645
13646      if(pSiS->SiS_Pr->CP_HaveCustomData) {
13647         for(j=0; j<7; j++) {
13648            if((pSiS->SiS_Pr->CP_DataValid[j]) &&
13649               (mode->HDisplay == pSiS->SiS_Pr->CP_HDisplay[j]) &&
13650               (mode->VDisplay == pSiS->SiS_Pr->CP_VDisplay[j]) &&
13651               (mode->type & M_T_BUILTIN))
13652               return 0xfe;
13653	 }
13654      }
13655
13656      if((pSiS->AddedPlasmaModes) && (mode->type & M_T_BUILTIN))
13657         return 0xfe;
13658
13659      if((havecustommodes) &&
13660         (pSiS->LCDwidth)  &&	/* = test if LCD present */
13661         (!(mode->type & M_T_DEFAULT)) &&
13662	 (SiSValidLCDUserMode(pSiS, VBFlags, mode, TRUE)))
13663         return 0xfe;
13664
13665      if((mode->HDisplay > pSiS->LCDwidth) ||
13666         (mode->VDisplay > pSiS->LCDheight)) {
13667	 return 0;
13668      }
13669
13670   } else {
13671
13672      if((mode->HDisplay > pSiS->LCDwidth) ||
13673         (mode->VDisplay > pSiS->LCDheight)) {
13674	 return 0;
13675      }
13676
13677   }
13678
13679   return(SiS_GetModeID(pSiS->VGAEngine, VBFlags, mode->HDisplay, mode->VDisplay,
13680   			i, pSiS->FSTN, pSiS->LCDwidth, pSiS->LCDheight));
13681}
13682
13683UShort
13684SiS_CheckModeCRT2(ScrnInfoPtr pScrn, DisplayModePtr mode, unsigned int VBFlags, Bool havecustommodes)
13685{
13686   SISPtr pSiS = SISPTR(pScrn);
13687   UShort i = (pSiS->CurrentLayout.bitsPerPixel+7)/8 - 1;
13688   UShort ModeIndex = 0;
13689   int    j;
13690
13691#ifdef TWDEBUG
13692   xf86DrvMsg(0, X_INFO, "Inside CheckCalcModeIndex (VBFlags %lx, mode %dx%d)\n",
13693	VBFlags,mode->HDisplay, mode->VDisplay);
13694#endif
13695
13696   if(VBFlags & CRT2_LCD) {			/* CRT2 is LCD */
13697
13698      if((pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) && (!(pSiS->VBFlags2 & VB2_30xBDH))) {
13699
13700         if(pSiS->SiS_Pr->CP_HaveCustomData) {
13701            for(j=0; j<7; j++) {
13702               if((pSiS->SiS_Pr->CP_DataValid[j]) &&
13703                  (mode->HDisplay == pSiS->SiS_Pr->CP_HDisplay[j]) &&
13704                  (mode->VDisplay == pSiS->SiS_Pr->CP_VDisplay[j]) &&
13705#ifdef VB_FORBID_CRT2LCD_OVER_1600
13706		  (mode->HDisplay <= 1600) 			   &&
13707#endif
13708                  (mode->type & M_T_BUILTIN))
13709                  return 0xfe;
13710	    }
13711         }
13712
13713	 /* All plasma modes have HDisplay <= 1600 */
13714         if((pSiS->AddedPlasmaModes) && (mode->type & M_T_BUILTIN))
13715            return 0xfe;
13716
13717         if((havecustommodes) &&
13718            (pSiS->LCDwidth)  &&	/* = test if LCD present */
13719	    (!(mode->type & M_T_DEFAULT)) &&
13720	    (SiSValidLCDUserMode(pSiS, VBFlags, mode, FALSE)))
13721            return 0xfe;
13722
13723      }
13724
13725      if( ((mode->HDisplay <= pSiS->LCDwidth) &&
13726           (mode->VDisplay <= pSiS->LCDheight)) ||
13727	  ((pSiS->SiS_Pr->SiS_CustomT == CUT_PANEL848) &&
13728	   (((mode->HDisplay == 1360) && (mode->HDisplay == 768)) ||
13729	    ((mode->HDisplay == 1024) && (mode->HDisplay == 768)) ||
13730	    ((mode->HDisplay ==  800) && (mode->HDisplay == 600)))) ||
13731	  ((pSiS->SiS_Pr->SiS_CustomT == CUT_PANEL856) &&
13732	   (((mode->HDisplay == 1024) && (mode->HDisplay == 768)) ||
13733	    ((mode->HDisplay ==  800) && (mode->HDisplay == 600)))) ) {
13734
13735	 ModeIndex = SiS_GetModeID_LCD(pSiS->VGAEngine, VBFlags, mode->HDisplay, mode->VDisplay, i,
13736				pSiS->FSTN, pSiS->SiS_Pr->SiS_CustomT, pSiS->LCDwidth, pSiS->LCDheight,
13737				pSiS->VBFlags2);
13738
13739      }
13740
13741   } else if(VBFlags & CRT2_TV) {		/* CRT2 is TV */
13742
13743      ModeIndex = SiS_GetModeID_TV(pSiS->VGAEngine, VBFlags, mode->HDisplay, mode->VDisplay, i,
13744					pSiS->VBFlags2);
13745
13746   } else if(VBFlags & CRT2_VGA) {		/* CRT2 is VGA2 */
13747
13748      if((pSiS->AddedPlasmaModes) && (mode->type & M_T_BUILTIN))
13749	 return 0xfe;
13750
13751      if((havecustommodes) &&
13752	 (!(mode->type & M_T_DEFAULT)) &&
13753	 (SiSValidVGA2UserMode(pSiS, VBFlags, mode)))
13754         return 0xfe;
13755
13756      ModeIndex = SiS_GetModeID_VGA2(pSiS->VGAEngine, VBFlags, mode->HDisplay, mode->VDisplay, i,
13757					pSiS->VBFlags2);
13758
13759   } else {					/* no CRT2 */
13760
13761      /* Return a valid mode number */
13762      ModeIndex = 0xfe;
13763
13764   }
13765
13766   return(ModeIndex);
13767}
13768
13769/* Calculate the vertical refresh rate from a mode */
13770float
13771SiSCalcVRate(DisplayModePtr mode)
13772{
13773   float hsync, refresh = 0;
13774
13775   if(mode->HSync > 0.0)
13776       	hsync = mode->HSync;
13777   else if(mode->HTotal > 0)
13778       	hsync = (float)mode->Clock / (float)mode->HTotal;
13779   else
13780       	hsync = 0.0;
13781
13782   if(mode->VTotal > 0)
13783       	refresh = hsync * 1000.0 / mode->VTotal;
13784
13785   if(mode->Flags & V_INTERLACE)
13786       	refresh *= 2.0;
13787
13788   if(mode->Flags & V_DBLSCAN)
13789       	refresh /= 2.0;
13790
13791   if(mode->VScan > 1)
13792        refresh /= mode->VScan;
13793
13794   if(mode->VRefresh > 0.0)
13795	refresh = mode->VRefresh;
13796
13797   if(hsync == 0.0 || refresh == 0.0) return 0.0;
13798
13799   return refresh;
13800}
13801
13802/* Calculate CR33 (rate index) for CRT1.
13803 * Calculation is done using currentmode, therefore it is
13804 * recommended to set VertRefresh and HorizSync to correct
13805 * values in config file.
13806 */
13807UChar
13808SISSearchCRT1Rate(ScrnInfoPtr pScrn, DisplayModePtr mode)
13809{
13810   SISPtr  pSiS = SISPTR(pScrn);
13811   int     i = 0, irefresh;
13812   UShort  xres = mode->HDisplay;
13813   UShort  yres = mode->VDisplay;
13814   UChar   index, defindex;
13815   Bool    checksis730 = FALSE;
13816
13817   defindex = (xres == 800 || xres == 1024 || xres == 1280) ? 0x02 : 0x01;
13818
13819   irefresh = (int)SiSCalcVRate(mode);
13820   if(!irefresh) return defindex;
13821
13822   /* SiS730 has troubles on CRT2 if CRT1 is at 32bpp */
13823   if( (pSiS->ChipType == SIS_730)        &&
13824       (pSiS->VBFlags2 & VB2_VIDEOBRIDGE) &&
13825       (pSiS->CurrentLayout.bitsPerPixel == 32) ) {
13826#ifdef SISDUALHEAD
13827      if(pSiS->DualHeadMode) {
13828         if(pSiS->SecondHead) {
13829	    checksis730 = TRUE;
13830	 }
13831      } else
13832#endif
13833      if((!pSiS->UseVESA) && (pSiS->VBFlags & CRT2_ENABLE) && (!pSiS->CRT1off)) {
13834         checksis730 = TRUE;
13835      }
13836   }
13837
13838#ifdef TWDEBUG
13839   xf86DrvMsg(0, X_INFO, "Debug: CalcVRate returned %d\n", irefresh);
13840#endif
13841
13842   /* We need the REAL refresh rate here */
13843   if(mode->Flags & V_INTERLACE) irefresh /= 2;
13844
13845   /* Do not multiply by 2 when DBLSCAN! */
13846
13847#ifdef TWDEBUG
13848   xf86DrvMsg(0, X_INFO, "Debug: Rate after correction = %d\n", irefresh);
13849#endif
13850
13851   index = 0;
13852   while((sisx_vrate[i].idx != 0) && (sisx_vrate[i].xres <= xres)) {
13853      if((sisx_vrate[i].xres == xres) && (sisx_vrate[i].yres == yres)) {
13854	 if((checksis730 == FALSE) || (sisx_vrate[i].SiS730valid32bpp == TRUE)) {
13855	    if(sisx_vrate[i].refresh == irefresh) {
13856	       index = sisx_vrate[i].idx;
13857	       break;
13858	    } else if(sisx_vrate[i].refresh > irefresh) {
13859	       if((sisx_vrate[i].refresh - irefresh) <= 3) {
13860		  index = sisx_vrate[i].idx;
13861	       } else if( ((checksis730 == FALSE) || (sisx_vrate[i - 1].SiS730valid32bpp == TRUE)) &&
13862		          ((irefresh - sisx_vrate[i - 1].refresh) <=  2) &&
13863			  (sisx_vrate[i].idx != 1) ) {
13864		  index = sisx_vrate[i - 1].idx;
13865	       }
13866	       break;
13867	    } else if((irefresh - sisx_vrate[i].refresh) <= 2) {
13868	       index = sisx_vrate[i].idx;
13869	       break;
13870	    }
13871	 }
13872      }
13873      i++;
13874   }
13875
13876   if(index > 0) return index;
13877   else          return defindex;
13878}
13879
13880void
13881SISWaitRetraceCRT1(ScrnInfoPtr pScrn)
13882{
13883   SISPtr pSiS = SISPTR(pScrn);
13884   int    watchdog;
13885   UChar  temp;
13886
13887   inSISIDXREG(SISCR,0x17,temp);
13888   if(!(temp & 0x80)) return;
13889
13890   inSISIDXREG(SISSR,0x1f,temp);
13891   if(temp & 0xc0) return;
13892
13893   watchdog = 65536;
13894   while((inSISREG(SISINPSTAT) & 0x08) && --watchdog);
13895   watchdog = 65536;
13896   while((!(inSISREG(SISINPSTAT) & 0x08)) && --watchdog);
13897}
13898
13899void
13900SISWaitRetraceCRT2(ScrnInfoPtr pScrn)
13901{
13902   SISPtr pSiS = SISPTR(pScrn);
13903   int    watchdog;
13904   UChar  temp, reg;
13905
13906   if(SiSBridgeIsInSlaveMode(pScrn)) {
13907      SISWaitRetraceCRT1(pScrn);
13908      return;
13909   }
13910
13911   switch(pSiS->VGAEngine) {
13912   case SIS_300_VGA:
13913   	reg = 0x25;
13914	break;
13915   case SIS_315_VGA:
13916   	reg = 0x30;
13917	break;
13918   default:
13919        return;
13920   }
13921
13922   watchdog = 65536;
13923   do {
13924   	inSISIDXREG(SISPART1, reg, temp);
13925	if(!(temp & 0x02)) break;
13926   } while(--watchdog);
13927   watchdog = 65536;
13928   do {
13929   	inSISIDXREG(SISPART1, reg, temp);
13930	if(temp & 0x02) break;
13931   } while(--watchdog);
13932}
13933
13934static void
13935SISWaitVBRetrace(ScrnInfoPtr pScrn)
13936{
13937   SISPtr  pSiS = SISPTR(pScrn);
13938
13939   if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
13940#ifdef SISDUALHEAD
13941      if(pSiS->DualHeadMode) {
13942   	 if(pSiS->SecondHead)
13943	    SISWaitRetraceCRT1(pScrn);
13944         else
13945	    SISWaitRetraceCRT2(pScrn);
13946      } else {
13947#endif
13948	 if(pSiS->VBFlags & DISPTYPE_DISP1) {
13949	    SISWaitRetraceCRT1(pScrn);
13950	 }
13951	 if(pSiS->VBFlags & DISPTYPE_DISP2) {
13952	    if(!(SiSBridgeIsInSlaveMode(pScrn))) {
13953	       SISWaitRetraceCRT2(pScrn);
13954	    }
13955	 }
13956#ifdef SISDUALHEAD
13957      }
13958#endif
13959   } else {
13960      SISWaitRetraceCRT1(pScrn);
13961   }
13962}
13963
13964#define MODEID_OFF 0x449
13965
13966UChar
13967SiS_GetSetBIOSScratch(ScrnInfoPtr pScrn, UShort offset, UChar value)
13968{
13969    UChar ret = 0;
13970#ifdef SIS_USE_BIOS_SCRATCH
13971    UChar *base;
13972#endif
13973
13974    /* For some reasons (like detecting the current display mode),
13975     * we need to read (or write-back) values from the BIOS
13976     * scratch area. This area is only valid for the primary
13977     * graphics card. For the secondary, we just return some
13978     * defaults and ignore requests to write data. As regards
13979     * the display mode: If sisfb is loaded for the secondary
13980     * card, it very probably has set a mode, but in any case
13981     * informed us via its info packet. So this here will not be
13982     * called for mode detection in this case.
13983     */
13984
13985    switch(offset) {
13986    case 0x489:
13987       ret = 0x11;  /* Default VGA Info */
13988       break;
13989    case MODEID_OFF:
13990       ret = 0x03;  /* Default current display mode */
13991       break;
13992    }
13993
13994#ifdef SIS_USE_BIOS_SCRATCH
13995    if(SISPTR(pScrn)->Primary) {
13996       base = xf86MapVidMem(pScrn->scrnIndex, VIDMEM_MMIO, 0, 0x2000);
13997       if(!base) {
13998          SISErrorLog(pScrn, "(Could not map BIOS scratch area)\n");
13999          return ret;
14000       }
14001
14002       ret = *(base + offset);
14003
14004       /* value != 0xff means: set register */
14005       if(value != 0xff) {
14006          *(base + offset) = value;
14007       }
14008
14009       xf86UnMapVidMem(pScrn->scrnIndex, base, 0x2000);
14010    }
14011#endif
14012    return ret;
14013}
14014
14015UChar
14016SiS_GetSetModeID(ScrnInfoPtr pScrn, UChar id)
14017{
14018    return(SiS_GetSetBIOSScratch(pScrn, MODEID_OFF, id));
14019}
14020
14021void
14022SiSMemCopyToVideoRam(SISPtr pSiS, UChar *to, UChar *from, int size)
14023{
14024   if((ULong)to & 15) (*pSiS->SiSFastMemCopy)(to, from, size);
14025   else       	      (*pSiS->SiSFastVidCopy)(to, from, size);
14026}
14027
14028void
14029SiSMemCopyFromVideoRam(SISPtr pSiS, UChar *to, UChar *from, int size)
14030{
14031   if((ULong)to & 15) (*pSiS->SiSFastMemCopyFrom)(to, from, size);
14032   else       	      (*pSiS->SiSFastVidCopyFrom)(to, from, size);
14033}
14034
14035void
14036sisSaveUnlockExtRegisterLock(SISPtr pSiS, UChar *reg1, UChar *reg2)
14037{
14038    register UChar val;
14039    ULong mylockcalls;
14040#ifdef TWDEBUG
14041    UChar val1, val2;
14042    int i;
14043#endif
14044
14045    pSiS->lockcalls++;
14046    mylockcalls = pSiS->lockcalls;
14047
14048    /* check if already unlocked */
14049    inSISIDXREG(SISSR, 0x05, val);
14050
14051    if(val != 0xa1) {
14052
14053       /* save State */
14054       if(reg1) *reg1 = val;
14055
14056       /* unlock */
14057       outSISIDXREG(SISSR, 0x05, 0x86);
14058
14059       /* Now check again */
14060       inSISIDXREG(SISSR, 0x05, val);
14061
14062       if(val != 0xA1) {
14063
14064          xf86DrvMsg(pSiS->pScrn->scrnIndex, X_WARNING,
14065               "Failed to unlock SR registers at relocated i/o ports\n");
14066
14067#ifdef TWDEBUG
14068          for(i = 0; i <= 0x3f; i++) {
14069		inSISIDXREG(SISSR, i, val1);
14070		inSISIDXREG(0x3c4, i, val2);
14071		xf86DrvMsg(pSiS->pScrn->scrnIndex, X_INFO,
14072			"SR%02d: RelIO=0x%02x 0x3c4=0x%02x (%ld)\n",
14073			i, val1, val2, mylockcalls);
14074	  }
14075#endif
14076
14077	  /* Emergency measure: unlock at 0x3c4, and try to enable relocated IO ports */
14078	  switch(pSiS->VGAEngine) {
14079          case SIS_OLD_VGA:
14080	  case SIS_530_VGA:
14081	     outSISIDXREG(0x3c4, 0x05, 0x86);
14082	     andSISIDXREG(0x3c4, 0x33, ~0x20);
14083	     break;
14084	  case SIS_300_VGA:
14085	  case SIS_315_VGA:
14086	     outSISIDXREG(0x3c4, 0x05, 0x86);
14087	     orSISIDXREG(0x3c4, 0x20, 0x20);
14088	     break;
14089          }
14090	  outSISIDXREG(SISSR, 0x05, 0x86);
14091	  inSISIDXREG(SISSR, 0x05, val);
14092	  if(val != 0xa1) {
14093	     SISErrorLog(pSiS->pScrn,
14094			"Failed to unlock SR registers (%p, %lx, 0x%02x; %ld)\n",
14095			(void *)pSiS, (ULong)pSiS->RelIO, val, mylockcalls);
14096	     /* Now await doom... */
14097	  }
14098       }
14099    }
14100    if((pSiS->VGAEngine == SIS_OLD_VGA) || (pSiS->VGAEngine == SIS_530_VGA)) {
14101       inSISIDXREG(SISCR, 0x80, val);
14102       if(val != 0xa1) {
14103          /* save State */
14104          if(reg2) *reg2 = val;
14105          outSISIDXREG(SISCR, 0x80, 0x86);
14106	  inSISIDXREG(SISCR, 0x80, val);
14107	  if(val != 0xA1) {
14108	     SISErrorLog(pSiS->pScrn,
14109	        "Failed to unlock cr registers (%p, %lx, 0x%02x)\n",
14110	       (void *)pSiS, (ULong)pSiS->RelIO, val);
14111	  }
14112       }
14113    }
14114}
14115
14116void
14117sisRestoreExtRegisterLock(SISPtr pSiS, UChar reg1, UChar reg2)
14118{
14119    /* restore lock */
14120#ifndef UNLOCK_ALWAYS
14121    outSISIDXREG(SISSR, 0x05, reg1 == 0xA1 ? 0x86 : 0x00);
14122    if((pSiS->VGAEngine == SIS_OLD_VGA) || (pSiS->VGAEngine == SIS_530_VGA)) {
14123       outSISIDXREG(SISCR, 0x80, reg2 == 0xA1 ? 0x86 : 0x00);
14124    }
14125#endif
14126}
14127
14128