sis_driver.c revision eee1ded1
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 "edid.h"
61
62#define SIS_NEED_inSISREG
63#define SIS_NEED_inSISIDXREG
64#define SIS_NEED_outSISIDXREG
65#define SIS_NEED_orSISIDXREG
66#define SIS_NEED_andSISIDXREG
67#define SIS_NEED_setSISIDXREG
68#define SIS_NEED_outSISREG
69#define SIS_NEED_MYMMIO
70#define SIS_NEED_sisclearvram
71#include "sis_regs.h"
72#include "sis_dac.h"
73
74#include "sis_driver.h"
75
76#include <X11/extensions/xf86dgaproto.h>
77
78#include "globals.h"
79
80#ifdef HAVE_XEXTPROTO_71
81#include <X11/extensions/dpmsconst.h>
82#else
83#define DPMS_SERVER
84#include <X11/extensions/dpms.h>
85#endif
86
87#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 5
88#include <inputstr.h> /* for inputInfo */
89#endif
90
91
92#ifdef SISDRI
93#include "dri.h"
94#endif
95
96#ifndef DEFAULT_DPI
97#define DEFAULT_DPI 96
98#endif
99
100/*
101 * LookupWindow was removed with video abi 11.
102 */
103#if (GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 4)
104#ifndef DixGetAttrAccess
105#define DixGetAttrAccess   (1<<4)
106#endif
107#endif
108
109#if (GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 2)
110static inline int
111dixLookupWindow(WindowPtr *pWin, XID id, ClientPtr client, Mask access)
112{
113    *pWin = LookupWindow(id, client);
114    if (!*pWin)
115	return BadWindow;
116    return Success;
117}
118#endif
119
120/* Globals (yes, these ARE really required to be global) */
121
122#ifdef SISUSEDEVPORT
123int 		sisdevport = 0;
124#endif
125
126#ifdef SISDUALHEAD
127static int	SISEntityIndex = -1;
128#endif
129
130#ifdef SISMERGED
131#ifdef SISXINERAMA
132static Bool 		SiSnoPanoramiXExtension = TRUE;
133static int		SiSXineramaNumScreens = 0;
134static SiSXineramaData	*SiSXineramadataPtr = NULL;
135static int		SiSXineramaGeneration;
136
137static int SiSProcXineramaQueryVersion(ClientPtr client);
138static int SiSProcXineramaGetState(ClientPtr client);
139static int SiSProcXineramaGetScreenCount(ClientPtr client);
140static int SiSProcXineramaGetScreenSize(ClientPtr client);
141static int SiSProcXineramaIsActive(ClientPtr client);
142static int SiSProcXineramaQueryScreens(ClientPtr client);
143static int SiSSProcXineramaDispatch(ClientPtr client);
144#endif
145#endif
146
147/*
148 * This is intentionally screen-independent.  It indicates the binding
149 * choice made in the first PreInit.
150 */
151static int pix24bpp = 0;
152
153/*
154 * This contains the functions needed by the server after loading the driver
155 * module.  It must be supplied, and gets passed back by the SetupProc
156 * function in the dynamic case.  In the static case, a reference to this
157 * is compiled in, and this requires that the name of this DriverRec be
158 * an upper-case version of the driver name.
159 */
160
161#ifdef _X_EXPORT
162_X_EXPORT
163#endif
164DriverRec SIS = {
165    SIS_CURRENT_VERSION,
166    SIS_DRIVER_NAME,
167    SISIdentify,
168    SISProbe,
169    SISAvailableOptions,
170    NULL,
171    0
172#ifdef SIS_HAVE_DRIVER_FUNC
173     ,
174    SISDriverFunc
175#endif
176};
177
178static SymTabRec SISChipsets[] = {
179    { PCI_CHIP_SIS5597,     "SIS5597/5598" },
180    { PCI_CHIP_SIS530,      "SIS530/620" },
181    { PCI_CHIP_SIS6326,     "SIS6326/AGP/DVD" },
182    { PCI_CHIP_SIS300,      "SIS300/305" },
183    { PCI_CHIP_SIS630,      "SIS630/730" },
184    { PCI_CHIP_SIS540,      "SIS540" },
185    { PCI_CHIP_SIS315,      "SIS315" },
186    { PCI_CHIP_SIS315H,     "SIS315H" },
187    { PCI_CHIP_SIS315PRO,   "SIS315PRO/E" },
188    { PCI_CHIP_SIS550,	    "SIS550" },
189    { PCI_CHIP_SIS650,      "SIS650/M650/651/740" },
190    { PCI_CHIP_SIS330,      "SIS330(Xabre)" },
191    { PCI_CHIP_SIS660,      "SIS660/[M]661[F|M]X/[M]670/[M]741[GX]/[M]760[GX]/[M]761[GX]/[M]770[GX]" },
192    { PCI_CHIP_SIS340,      "SIS340" },
193    { -1,                   NULL }
194};
195
196static PciChipsets SISPciChipsets[] = {
197    { PCI_CHIP_SIS5597,     PCI_CHIP_SIS5597,   RES_SHARED_VGA },
198    { PCI_CHIP_SIS530,      PCI_CHIP_SIS530,    RES_SHARED_VGA },
199    { PCI_CHIP_SIS6326,     PCI_CHIP_SIS6326,   RES_SHARED_VGA },
200    { PCI_CHIP_SIS300,      PCI_CHIP_SIS300,    RES_SHARED_VGA },
201    { PCI_CHIP_SIS630,      PCI_CHIP_SIS630,    RES_SHARED_VGA },
202    { PCI_CHIP_SIS540,      PCI_CHIP_SIS540,    RES_SHARED_VGA },
203    { PCI_CHIP_SIS550,      PCI_CHIP_SIS550,    RES_SHARED_VGA },
204    { PCI_CHIP_SIS315,      PCI_CHIP_SIS315,    RES_SHARED_VGA },
205    { PCI_CHIP_SIS315H,     PCI_CHIP_SIS315H,   RES_SHARED_VGA },
206    { PCI_CHIP_SIS315PRO,   PCI_CHIP_SIS315PRO, RES_SHARED_VGA },
207    { PCI_CHIP_SIS650,      PCI_CHIP_SIS650,    RES_SHARED_VGA },
208    { PCI_CHIP_SIS330,      PCI_CHIP_SIS330,    RES_SHARED_VGA },
209    { PCI_CHIP_SIS660,      PCI_CHIP_SIS660,    RES_SHARED_VGA },
210    { PCI_CHIP_SIS340,      PCI_CHIP_SIS340,    RES_SHARED_VGA },
211    { -1,                   -1,                 RES_UNDEFINED }
212};
213
214static SymTabRec XGIChipsets[] = {
215    { PCI_CHIP_XGIXG20,     "Volari Z7 (XG20)" },
216    { PCI_CHIP_XGIXG40,     "Volari V3XT/V5/V8/Duo (XG40)" },
217    { -1,                   NULL }
218};
219
220static PciChipsets XGIPciChipsets[] = {
221    { PCI_CHIP_XGIXG20,     PCI_CHIP_XGIXG20,   RES_SHARED_VGA },
222    { PCI_CHIP_XGIXG40,     PCI_CHIP_XGIXG40,   RES_SHARED_VGA },
223    { -1,                   -1,                 RES_UNDEFINED }
224};
225
226#ifdef XFree86LOADER
227
228static MODULESETUPPROTO(sisSetup);
229
230static XF86ModuleVersionInfo sisVersRec =
231{
232    SIS_DRIVER_NAME,
233    MODULEVENDORSTRING,
234    MODINFOSTRING1,
235    MODINFOSTRING2,
236#ifdef XORG_VERSION_CURRENT
237    XORG_VERSION_CURRENT,
238#else
239    XF86_VERSION_CURRENT,
240#endif
241    SIS_MAJOR_VERSION, SIS_MINOR_VERSION, SIS_PATCHLEVEL,
242    ABI_CLASS_VIDEODRV,         /* This is a video driver */
243    ABI_VIDEODRV_VERSION,
244    MOD_CLASS_VIDEODRV,
245    {0,0,0,0}
246};
247
248#ifdef _X_EXPORT
249_X_EXPORT
250#endif
251XF86ModuleData sisModuleData = { &sisVersRec, sisSetup, NULL };
252
253pointer
254sisSetup(pointer module, pointer opts, int *errmaj, int *errmin)
255{
256    static Bool setupDone = FALSE;
257
258    if(!setupDone) {
259       setupDone = TRUE;
260       xf86AddDriver(&SIS, module, SIS_HaveDriverFuncs);
261       return (pointer)TRUE;
262    }
263
264    if(errmaj) *errmaj = LDR_ONCEONLY;
265    return NULL;
266}
267
268#endif /* XFree86LOADER */
269
270/* Mandatory */
271static void
272SISIdentify(int flags)
273{
274    xf86PrintChipsets(SIS_NAME, "driver for SiS chipsets", SISChipsets);
275    xf86PrintChipsets(SIS_NAME, "driver for XGI chipsets", XGIChipsets);
276}
277
278#ifdef SIS_HAVE_DRIVER_FUNC
279static Bool
280SISDriverFunc(ScrnInfoPtr pScrn, xorgDriverFuncOp op, pointer ptr)
281{
282    CARD32 *flag;
283
284    switch(op) {
285    case RR_GET_INFO:
286	break;
287    case RR_SET_CONFIG:
288	break;
289    case GET_REQUIRED_HW_INTERFACES:
290	break;
291    }
292    return TRUE;
293}
294#endif
295
296static Bool
297SISGetRec(ScrnInfoPtr pScrn)
298{
299    /* Allocate an SISRec, and hook it into pScrn->driverPrivate.
300     * pScrn->driverPrivate is initialised to NULL, so we can check if
301     * the allocation has already been done.
302     */
303    if(pScrn->driverPrivate != NULL) return TRUE;
304
305    pScrn->driverPrivate = xnfcalloc(sizeof(SISRec), 1);
306
307    /* Initialise it to 0 */
308    memset(pScrn->driverPrivate, 0, sizeof(SISRec));
309
310    return TRUE;
311}
312
313static void
314SISFreeRec(ScrnInfoPtr pScrn)
315{
316    SISPtr pSiS = SISPTR(pScrn);
317#ifdef SISDUALHEAD
318    SISEntPtr pSiSEnt = NULL;
319#endif
320
321    /* Just to make sure... */
322    if(!pSiS) return;
323
324#ifdef SISDUALHEAD
325    pSiSEnt = pSiS->entityPrivate;
326#endif
327
328    if(pSiS->pstate) free(pSiS->pstate);
329    pSiS->pstate = NULL;
330    if(pSiS->fonts) free(pSiS->fonts);
331    pSiS->fonts = NULL;
332
333#ifdef SISDUALHEAD
334    if(pSiSEnt) {
335       if(!pSiS->SecondHead) {
336	  /* Free memory only if we are first head; in case of an error
337	   * during init of the second head, the server will continue -
338	   * and we need the BIOS image and SiS_Private for the first
339	   * head.
340	   */
341	  if(pSiSEnt->BIOS) free(pSiSEnt->BIOS);
342	  pSiSEnt->BIOS = pSiS->BIOS = NULL;
343	  if(pSiSEnt->SiS_Pr) free(pSiSEnt->SiS_Pr);
344	  pSiSEnt->SiS_Pr = pSiS->SiS_Pr = NULL;
345	  if(pSiSEnt->RenderAccelArray) free(pSiSEnt->RenderAccelArray);
346	  pSiSEnt->RenderAccelArray = pSiS->RenderAccelArray = NULL;
347	  pSiSEnt->pScrn_1 = NULL;
348       } else {
349	  pSiS->BIOS = NULL;
350	  pSiS->SiS_Pr = NULL;
351	  pSiS->RenderAccelArray = NULL;
352	  pSiSEnt->pScrn_2 = NULL;
353       }
354    } else {
355#endif
356       if(pSiS->BIOS) free(pSiS->BIOS);
357       pSiS->BIOS = NULL;
358       if(pSiS->SiS_Pr) free(pSiS->SiS_Pr);
359       pSiS->SiS_Pr = NULL;
360       if(pSiS->RenderAccelArray) free(pSiS->RenderAccelArray);
361       pSiS->RenderAccelArray = NULL;
362#ifdef SISDUALHEAD
363    }
364#endif
365#ifdef SISMERGED
366    if(pSiS->CRT2HSync) free(pSiS->CRT2HSync);
367    pSiS->CRT2HSync = NULL;
368    if(pSiS->CRT2VRefresh) free(pSiS->CRT2VRefresh);
369    pSiS->CRT2VRefresh = NULL;
370    if(pSiS->MetaModes) free(pSiS->MetaModes);
371    pSiS->MetaModes = NULL;
372    if(pSiS->CRT2pScrn) {
373       if(pSiS->CRT2pScrn->modes) {
374	  while(pSiS->CRT2pScrn->modes)
375	     xf86DeleteMode(&pSiS->CRT2pScrn->modes, pSiS->CRT2pScrn->modes);
376       }
377       if(pSiS->CRT2pScrn->monitor) {
378	  if(pSiS->CRT2pScrn->monitor->Modes) {
379	     while(pSiS->CRT2pScrn->monitor->Modes)
380	        xf86DeleteMode(&pSiS->CRT2pScrn->monitor->Modes, pSiS->CRT2pScrn->monitor->Modes);
381	  }
382	  if(pSiS->CRT2pScrn->monitor->DDC) free(pSiS->CRT2pScrn->monitor->DDC);
383	  free(pSiS->CRT2pScrn->monitor);
384       }
385       free(pSiS->CRT2pScrn);
386       pSiS->CRT2pScrn = NULL;
387    }
388    if(pSiS->CRT1Modes) {
389       if(pSiS->CRT1Modes != pScrn->modes) {
390	  if(pScrn->modes) {
391	     pScrn->currentMode = pScrn->modes;
392	     do {
393	        DisplayModePtr p = pScrn->currentMode->next;
394	        if(pScrn->currentMode->Private)
395	 	  free(pScrn->currentMode->Private);
396	        free(pScrn->currentMode);
397	        pScrn->currentMode = p;
398	     } while(pScrn->currentMode != pScrn->modes);
399	  }
400	  pScrn->currentMode = pSiS->CRT1CurrentMode;
401	  pScrn->modes = pSiS->CRT1Modes;
402	  pSiS->CRT1CurrentMode = NULL;
403	  pSiS->CRT1Modes = NULL;
404       }
405    }
406#endif
407    while(pSiS->SISVESAModeList) {
408       sisModeInfoPtr mp = pSiS->SISVESAModeList->next;
409       free(pSiS->SISVESAModeList);
410       pSiS->SISVESAModeList = mp;
411    }
412    if(pSiS->pVbe) vbeFree(pSiS->pVbe);
413    pSiS->pVbe = NULL;
414
415#ifdef SISUSEDEVPORT
416    if(pSiS->sisdevportopen)   close(sisdevport);
417#endif
418
419    if(pScrn->driverPrivate == NULL)
420        return;
421    free(pScrn->driverPrivate);
422    pScrn->driverPrivate = NULL;
423}
424
425static void
426SISErrorLog(ScrnInfoPtr pScrn, const char *format, ...)
427{
428    va_list ap;
429    static const char str[] = "**************************************************\n";
430
431    va_start(ap, format);
432    xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "%s", str);
433    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
434	"                      ERROR:\n");
435    xf86VDrvMsgVerb(pScrn->scrnIndex, X_ERROR, 1, format, ap);
436    va_end(ap);
437    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
438	"                  END OF MESSAGE\n");
439    xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "%s", str);
440}
441
442static void
443SiS_SiSFB_Lock(ScrnInfoPtr pScrn, Bool lock)
444{
445    SISPtr  pSiS = SISPTR(pScrn);
446    int     fd;
447    CARD32  parm;
448
449    if(!pSiS->sisfbfound) return;
450    if(!pSiS->sisfb_havelock) return;
451
452    if((fd = open(pSiS->sisfbdevname, O_RDONLY)) != -1) {
453       parm = lock ? 1 : 0;
454       ioctl(fd, SISFB_SET_LOCK, &parm);
455       close(fd);
456    }
457}
458
459/* Probe()
460 *
461 * Mandatory
462 */
463static Bool
464SISProbe(DriverPtr drv, int flags)
465{
466    int     i;
467    GDevPtr *devSections;
468    int     *usedChipsSiS, *usedChipsXGI;
469    int     numDevSections;
470    int     numUsed, numUsedSiS, numUsedXGI;
471    Bool    foundScreen = FALSE;
472
473    /*
474     * The aim here is to find all cards that this driver can handle,
475     * and for the ones not already claimed by another driver, claim the
476     * slot, and allocate a ScrnInfoRec.
477     *
478     * This should be a minimal probe, and it should under no circumstances
479     * change the state of the hardware.  Because a device is found, don't
480     * assume that it will be used.  Don't do any initialisations other than
481     * the required ScrnInfoRec initialisations.  Don't allocate any new
482     * data structures.
483     *
484     */
485
486    /*
487     * Next we check, if there has been a chipset override in the config file.
488     * For this we must find out if there is an active device section which
489     * is relevant, i.e., which has no driver specified or has THIS driver
490     * specified.
491     */
492
493    if((numDevSections = xf86MatchDevice(SIS_DRIVER_NAME, &devSections)) <= 0) {
494       /*
495        * There's no matching device section in the config file, so quit
496        * now.
497        */
498       return FALSE;
499    }
500
501    /*
502     * We need to probe the hardware first.  We then need to see how this
503     * fits in with what is given in the config file, and allow the config
504     * file info to override any contradictions.
505     */
506
507    /*
508     * All of the cards this driver supports are PCI, so the "probing" just
509     * amounts to checking the PCI data that the server has already collected.
510     */
511#ifndef XSERVER_LIBPCIACCESS
512    if(xf86GetPciVideoInfo() == NULL) {
513       /*
514        * We won't let anything in the config file override finding no
515        * PCI video cards at all.
516        */
517       return FALSE;
518    }
519#endif
520
521    numUsedSiS = xf86MatchPciInstances(SIS_NAME, PCI_VENDOR_SIS,
522			SISChipsets, SISPciChipsets, devSections,
523			numDevSections, drv, &usedChipsSiS);
524
525    numUsedXGI = xf86MatchPciInstances(SIS_NAME, PCI_VENDOR_XGI,
526			XGIChipsets, XGIPciChipsets, devSections,
527			numDevSections, drv, &usedChipsXGI);
528
529    /* Free it since we don't need that list after this */
530    free(devSections);
531
532    numUsed = numUsedSiS + numUsedXGI;
533
534    if(numUsed <= 0)
535       return FALSE;
536
537    if(flags & PROBE_DETECT) {
538
539	foundScreen = TRUE;
540
541    } else for(i = 0; i < numUsed; i++) {
542
543	ScrnInfoPtr pScrn;
544#ifdef SISDUALHEAD
545	EntityInfoPtr pEnt;
546#endif
547
548	/* Allocate a ScrnInfoRec and claim the slot */
549	pScrn = NULL;
550
551	if((pScrn = xf86ConfigPciEntity(pScrn, 0,
552			(i < numUsedSiS) ? usedChipsSiS[i] : usedChipsXGI[i-numUsedSiS],
553			(i < numUsedSiS) ? SISPciChipsets  : XGIPciChipsets,
554			NULL, NULL, NULL, NULL, NULL))) {
555	    /* Fill in what we can of the ScrnInfoRec */
556	    pScrn->driverVersion    = SIS_CURRENT_VERSION;
557	    pScrn->driverName       = SIS_DRIVER_NAME;
558	    pScrn->name             = SIS_NAME;
559	    pScrn->Probe            = SISProbe;
560	    pScrn->PreInit          = SISPreInit;
561	    pScrn->ScreenInit       = SISScreenInit;
562	    pScrn->SwitchMode       = SISSwitchMode;
563	    pScrn->AdjustFrame      = SISAdjustFrame;
564	    pScrn->EnterVT          = SISEnterVT;
565	    pScrn->LeaveVT          = SISLeaveVT;
566	    pScrn->FreeScreen       = SISFreeScreen;
567	    pScrn->ValidMode        = SISValidMode;
568
569	    foundScreen = TRUE;
570	}
571
572#ifdef SISDUALHEAD
573	pEnt = xf86GetEntityInfo((i < numUsedSiS) ? usedChipsSiS[i] : usedChipsXGI[i-numUsedSiS]);
574
575	if(pEnt->chipset == PCI_CHIP_SIS630 || pEnt->chipset == PCI_CHIP_SIS540 ||
576	   pEnt->chipset == PCI_CHIP_SIS650 || pEnt->chipset == PCI_CHIP_SIS550 ||
577	   pEnt->chipset == PCI_CHIP_SIS315 || pEnt->chipset == PCI_CHIP_SIS315H ||
578	   pEnt->chipset == PCI_CHIP_SIS315PRO || pEnt->chipset == PCI_CHIP_SIS330 ||
579	   pEnt->chipset == PCI_CHIP_SIS300 || pEnt->chipset == PCI_CHIP_SIS660 ||
580	   pEnt->chipset == PCI_CHIP_SIS340 || pEnt->chipset == PCI_CHIP_XGIXG40) {
581
582	    SISEntPtr pSiSEnt = NULL;
583	    DevUnion  *pPriv;
584
585	    xf86SetEntitySharable((i < numUsedSiS) ? usedChipsSiS[i] : usedChipsXGI[i-numUsedSiS]);
586	    if(SISEntityIndex < 0) {
587	       SISEntityIndex = xf86AllocateEntityPrivateIndex();
588	    }
589	    pPriv = xf86GetEntityPrivate(pScrn->entityList[0], SISEntityIndex);
590	    if(!pPriv->ptr) {
591	       pPriv->ptr = xnfcalloc(sizeof(SISEntRec), 1);
592	       pSiSEnt = pPriv->ptr;
593	       memset(pSiSEnt, 0, sizeof(SISEntRec));
594	       pSiSEnt->lastInstance = -1;
595	    } else {
596	       pSiSEnt = pPriv->ptr;
597	    }
598	    pSiSEnt->lastInstance++;
599	    xf86SetEntityInstanceForScreen(pScrn, pScrn->entityList[0],
600	                                   pSiSEnt->lastInstance);
601	}
602#endif /* DUALHEAD */
603
604    }
605
606    if(usedChipsSiS) free(usedChipsSiS);
607    if(usedChipsXGI) free(usedChipsXGI);
608
609    return foundScreen;
610}
611
612/* Various helpers */
613
614static unsigned short
615calcgammaval(int j, int nramp, float invgamma, float bri, float c)
616{
617    float k = (float)j;
618    float nrm1 = (float)(nramp - 1);
619    float con = c * nrm1 / 3.0;
620    float l, v;
621
622    if(con != 0.0) {
623       l = nrm1 / 2.0;
624       if(con <= 0.0) {
625          k -= l;
626          k *= (l + con) / l;
627       } else {
628          l -= 1.0;
629          k -= l;
630          k *= l / (l - con);
631       }
632       k += l;
633       if(k < 0.0) k = 0.0;
634    }
635
636    if(invgamma == 1.0) {
637       v = k / nrm1 * 65535.0;
638    } else {
639       v = pow(k / nrm1, invgamma) * 65535.0 + 0.5;
640    }
641
642    v += (bri * (65535.0 / 3.0)) ;
643
644    if(v < 0.0) v = 0.0;
645    else if(v > 65535.0) v = 65535.0;
646
647    return (unsigned short)v;
648}
649
650#ifdef SISGAMMARAMP
651void
652SISCalculateGammaRamp(ScreenPtr pScreen, ScrnInfoPtr pScrn)
653{
654   SISPtr pSiS = SISPTR(pScrn);
655   int    i, j, nramp;
656   UShort *ramp[3];
657   float  gamma_max[3], framp;
658   Bool   newmethod = FALSE;
659
660   if(!(pSiS->SiS_SD3_Flags & SiS_SD3_OLDGAMMAINUSE)) {
661      newmethod = TRUE;
662   } else {
663      gamma_max[0] = (float)pSiS->GammaBriR / 1000;
664      gamma_max[1] = (float)pSiS->GammaBriG / 1000;
665      gamma_max[2] = (float)pSiS->GammaBriB / 1000;
666   }
667
668   if(!(nramp = xf86GetGammaRampSize(pScreen))) return;
669
670   for(i=0; i<3; i++) {
671      ramp[i] = (UShort *)malloc(nramp * sizeof(UShort));
672      if(!ramp[i]) {
673	 if(ramp[0]) { free(ramp[0]); ramp[0] = NULL; }
674	 if(ramp[1]) { free(ramp[1]); ramp[1] = NULL; }
675	 return;
676      }
677   }
678
679   if(newmethod) {
680
681      for(i = 0; i < 3; i++) {
682
683         float invgamma = 0.0, bri = 0.0, con = 0.0;
684
685         switch(i) {
686         case 0: invgamma = 1. / pScrn->gamma.red;
687		 bri = pSiS->NewGammaBriR;
688		 con = pSiS->NewGammaConR;
689		 break;
690         case 1: invgamma = 1. / pScrn->gamma.green;
691		 bri = pSiS->NewGammaBriG;
692		 con = pSiS->NewGammaConG;
693		 break;
694         case 2: invgamma = 1. / pScrn->gamma.blue;
695		 bri = pSiS->NewGammaBriB;
696                 con = pSiS->NewGammaConB;
697		 break;
698         }
699
700	 for(j = 0; j < nramp; j++) {
701	    ramp[i][j] = calcgammaval(j, nramp, invgamma, bri, con);
702	 }
703
704      }
705
706   } else {
707
708      for(i = 0; i < 3; i++) {
709         int fullscale = 65535 * gamma_max[i];
710         float dramp = 1. / (nramp - 1);
711         float invgamma = 0.0, v;
712
713         switch(i) {
714         case 0: invgamma = 1. / pScrn->gamma.red; break;
715         case 1: invgamma = 1. / pScrn->gamma.green; break;
716         case 2: invgamma = 1. / pScrn->gamma.blue; break;
717         }
718
719         for(j = 0; j < nramp; j++) {
720	    framp = pow(j * dramp, invgamma);
721
722	    v = (fullscale < 0) ? (65535 + fullscale * framp) :
723			       fullscale * framp;
724	    if(v < 0) v = 0;
725	    else if(v > 65535) v = 65535;
726	    ramp[i][j] = (UShort)v;
727         }
728      }
729
730   }
731
732   xf86ChangeGammaRamp(pScreen, nramp, ramp[0], ramp[1], ramp[2]);
733
734   free(ramp[0]);
735   free(ramp[1]);
736   free(ramp[2]);
737   ramp[0] = ramp[1] = ramp[2] = NULL;
738}
739#endif
740
741void
742SISCalculateGammaRampCRT2(ScrnInfoPtr pScrn)
743{
744   SISPtr pSiS = SISPTR(pScrn);
745   int    i;
746   int    myshift = 16 - pScrn->rgbBits;
747   int    maxvalue = (1 << pScrn->rgbBits) - 1;
748   int    reds = pScrn->mask.red >> pScrn->offset.red;
749   int    greens = pScrn->mask.green >> pScrn->offset.green;
750   int    blues = pScrn->mask.blue >> pScrn->offset.blue;
751   float  framp, invgamma1, invgamma2, invgamma3, v;
752
753   invgamma1  = 1. / pSiS->GammaR2;
754   invgamma2  = 1. / pSiS->GammaG2;
755   invgamma3  = 1. / pSiS->GammaB2;
756
757   if(!(pSiS->SiS_SD3_Flags & SiS_SD3_OLDGAMMAINUSE)) {
758
759      for(i = 0; i < pSiS->CRT2ColNum; i++) {
760         pSiS->crt2gcolortable[i].red = calcgammaval(i, pSiS->CRT2ColNum, invgamma1,
761			pSiS->NewGammaBriR2, pSiS->NewGammaConR2) >> myshift;
762         pSiS->crt2gcolortable[i].green = calcgammaval(i, pSiS->CRT2ColNum, invgamma2,
763			pSiS->NewGammaBriG2, pSiS->NewGammaConG2) >> myshift;
764         pSiS->crt2gcolortable[i].blue = calcgammaval(i, pSiS->CRT2ColNum, invgamma3,
765			pSiS->NewGammaBriB2, pSiS->NewGammaConB2) >> myshift;
766      }
767
768   } else {
769
770      int fullscale1 = 65536 * (float)pSiS->GammaBriR2 / 1000;
771      int fullscale2 = 65536 * (float)pSiS->GammaBriG2 / 1000;
772      int fullscale3 = 65536 * (float)pSiS->GammaBriB2 / 1000;
773
774      float dramp = 1. / (pSiS->CRT2ColNum - 1);
775
776      for(i = 0; i < pSiS->CRT2ColNum; i++) {
777         framp = pow(i * dramp, invgamma1);
778         v = (fullscale1 < 0) ? (65535 + fullscale1 * framp) : fullscale1 * framp;
779         if(v < 0) v = 0;
780         else if(v > 65535) v = 65535;
781         pSiS->crt2gcolortable[i].red = ((UShort)v) >> myshift;
782         framp = pow(i * dramp, invgamma2);
783         v = (fullscale2 < 0) ? (65535 + fullscale2 * framp) : fullscale2 * framp;
784         if(v < 0) v = 0;
785         else if(v > 65535) v = 65535;
786         pSiS->crt2gcolortable[i].green = ((UShort)v) >> myshift;
787         framp = pow(i * dramp, invgamma3);
788         v = (fullscale3 < 0) ? (65535 + fullscale3 * framp) : fullscale3 * framp;
789         if(v < 0) v = 0;
790         else if(v > 65535) v = 65535;
791         pSiS->crt2gcolortable[i].blue = ((UShort)v) >> myshift;
792      }
793
794   }
795
796   for(i = 0; i < pSiS->CRT2ColNum; i++) {
797      pSiS->crt2colors[i].red =
798         pSiS->crt2gcolortable[i * maxvalue / reds].red;
799      pSiS->crt2colors[i].green =
800         pSiS->crt2gcolortable[i * maxvalue / greens].green;
801      pSiS->crt2colors[i].blue  =
802         pSiS->crt2gcolortable[i * maxvalue / blues].blue;
803   }
804}
805
806/* If monitor section has no HSync/VRefresh data,
807 * derive it from DDC data.
808 */
809static void
810SiSSetSyncRangeFromEdid(ScrnInfoPtr pScrn, int flag)
811{
812   MonPtr      mon = pScrn->monitor;
813   xf86MonPtr  ddc = mon->DDC;
814   float       myhhigh = 0.0, myhlow = 0.0, htest;
815   int         myvhigh = 0, myvlow = 0, vtest, i;
816   UChar temp;
817   const myhddctiming myhtiming[12] = {
818       { 1, 0x20, 31.6 }, /* rounded up by .1 */
819       { 1, 0x80, 31.6 },
820       { 1, 0x02, 35.3 },
821       { 1, 0x04, 37.6 },
822       { 1, 0x08, 38.0 },
823       { 1, 0x01, 38.0 },
824       { 2, 0x40, 47.0 },
825       { 2, 0x80, 48.2 },
826       { 2, 0x08, 48.5 },
827       { 2, 0x04, 56.6 },
828       { 2, 0x02, 60.1 },
829       { 2, 0x01, 80.1 }
830   };
831   const myvddctiming myvtiming[11] = {
832       { 1, 0x02, 56 },
833       { 1, 0x01, 60 },
834       { 2, 0x08, 60 },
835       { 2, 0x04, 70 },
836       { 1, 0x80, 71 },
837       { 1, 0x08, 72 },
838       { 2, 0x80, 72 },
839       { 1, 0x04, 75 },
840       { 2, 0x40, 75 },
841       { 2, 0x02, 75 },
842       { 2, 0x01, 75 }
843   };
844
845   if(flag) { /* HSync */
846
847      for(i = 0; i < 4; i++) {
848	 if(ddc->det_mon[i].type == DS_RANGES) {
849	    mon->nHsync = 1;
850	    mon->hsync[0].lo = ddc->det_mon[i].section.ranges.min_h;
851	    mon->hsync[0].hi = ddc->det_mon[i].section.ranges.max_h;
852	    if(mon->hsync[0].lo > 32.0 || mon->hsync[0].hi < 31.0) {
853	       if(ddc->timings1.t1 & 0x80) {
854		  mon->nHsync++;
855		  mon->hsync[1].lo = 31.0;
856		  mon->hsync[1].hi = 32.0;
857	       }
858	    }
859	    return;
860	 }
861      }
862
863      /* If no sync ranges detected in detailed timing table, we
864       * derive them from supported VESA modes.
865       */
866
867      for(i = 0; i < 12; i++) {
868	 if(myhtiming[i].whichone == 1) temp = ddc->timings1.t1;
869	 else                           temp = ddc->timings1.t2;
870	 if(temp & myhtiming[i].mask) {
871	    if((i == 0) || (myhlow > myhtiming[i].rate))
872	       myhlow = myhtiming[i].rate;
873	 }
874	 if(myhtiming[11-i].whichone == 1) temp = ddc->timings1.t1;
875	 else                              temp = ddc->timings1.t2;
876	 if(temp & myhtiming[11-i].mask) {
877	    if((i == 0) || (myhhigh < myhtiming[11-i].rate))
878	       myhhigh = myhtiming[11-i].rate;
879	 }
880      }
881
882      for(i = 0; i < STD_TIMINGS; i++) {
883	 if(ddc->timings2[i].hsize > 256) {
884	    htest = ddc->timings2[i].refresh * 1.05 * ddc->timings2[i].vsize / 1000.0;
885	    if(htest < myhlow)  myhlow  = htest;
886	    if(htest > myhhigh) myhhigh = htest;
887	 }
888      }
889
890      if((myhhigh > 0.0) && (myhlow > 0.0)) {
891	 mon->nHsync = 1;
892	 mon->hsync[0].lo = myhlow - 0.1;
893	 mon->hsync[0].hi = myhhigh;
894      }
895
896
897   } else {  /* Vrefresh */
898
899      for(i = 0; i < 4; i++) {
900         if(ddc->det_mon[i].type == DS_RANGES) {
901	    mon->nVrefresh = 1;
902	    mon->vrefresh[0].lo = ddc->det_mon[i].section.ranges.min_v;
903	    mon->vrefresh[0].hi = ddc->det_mon[i].section.ranges.max_v;
904	    if(mon->vrefresh[0].lo > 72 || mon->vrefresh[0].hi < 70) {
905	       if(ddc->timings1.t1 & 0x80) {
906		  mon->nVrefresh++;
907		  mon->vrefresh[1].lo = 71;
908		  mon->vrefresh[1].hi = 71;
909	       }
910	    }
911	    return;
912         }
913      }
914
915      for(i = 0; i < 11; i++) {
916	 if(myvtiming[i].whichone == 1) temp = ddc->timings1.t1;
917	 else                           temp = ddc->timings1.t2;
918	 if(temp & myvtiming[i].mask) {
919	    if((i == 0) || (myvlow > myvtiming[i].rate))
920	       myvlow = myvtiming[i].rate;
921	 }
922	 if(myvtiming[10-i].whichone == 1) temp = ddc->timings1.t1;
923	 else                              temp = ddc->timings1.t2;
924	 if(temp & myvtiming[10-i].mask) {
925	    if((i == 0) || (myvhigh < myvtiming[10-i].rate))
926	       myvhigh = myvtiming[10-i].rate;
927	 }
928      }
929
930      for(i = 0; i < STD_TIMINGS; i++) {
931	 if(ddc->timings2[i].hsize > 256) {
932	    vtest = ddc->timings2[i].refresh;
933	    if(vtest < myvlow)  myvlow  = vtest;
934	    if(vtest > myvhigh) myvhigh = vtest;
935	 }
936      }
937
938      if((myvhigh > 0) && (myvlow > 0)) {
939	 mon->nVrefresh = 1;
940	 mon->vrefresh[0].lo = myvlow;
941	 mon->vrefresh[0].hi = myvhigh;
942      }
943
944   }
945}
946
947static Bool
948SiSAllowSyncOverride(SISPtr pSiS, Bool fromDDC)
949{
950   if(!(pSiS->VBFlags2 & VB2_VIDEOBRIDGE)) return FALSE;
951
952#ifdef SISDUALHEAD
953   if(pSiS->DualHeadMode) {
954      if(pSiS->SecondHead) {
955         if((pSiS->VBFlags & CRT1_LCDA) && (!fromDDC)) return TRUE;
956      } else {
957         if((pSiS->VBFlags & CRT2_TV) ||
958	    ((pSiS->VBFlags & CRT2_LCD) && (!fromDDC))) return TRUE;
959      }
960      return FALSE;
961   }
962#endif
963
964#ifdef SISMERGED
965   if(pSiS->MergedFB) {
966      if((pSiS->VBFlags & CRT1_LCDA) && (!fromDDC)) return TRUE;
967      return FALSE;
968   }
969#endif
970
971   if(!(pSiS->VBFlags & DISPTYPE_CRT1)) {
972      if( (pSiS->VBFlags & CRT2_TV) ||
973	  ((pSiS->VBFlags & CRT2_LCD) && (!fromDDC)) ) return TRUE;
974   } else if((pSiS->VBFlags & CRT1_LCDA) && (!fromDDC)) return TRUE;
975
976   return FALSE;
977}
978
979static Bool
980SiSCheckForH(float hsync, MonPtr monitor)
981{
982   int i;
983   for(i = 0; i < monitor->nHsync; i++) {
984      if((hsync > monitor->hsync[i].lo * (1.0 - SYNC_TOLERANCE)) &&
985	 (hsync < monitor->hsync[i].hi * (1.0 + SYNC_TOLERANCE)))
986	 break;
987   }
988   if(i == monitor->nHsync) return FALSE;
989   return TRUE;
990}
991
992static Bool
993SiSCheckForV(float vrefresh, MonPtr monitor)
994{
995   int i;
996   for(i = 0; i < monitor->nVrefresh; i++) {
997      if((vrefresh > monitor->vrefresh[i].lo * (1.0 - SYNC_TOLERANCE)) &&
998	 (vrefresh < monitor->vrefresh[i].hi * (1.0 + SYNC_TOLERANCE)))
999	 break;
1000   }
1001   if(i == monitor->nVrefresh) return FALSE;
1002   return TRUE;
1003}
1004
1005static Bool
1006CheckAndOverruleH(ScrnInfoPtr pScrn, MonPtr monitor)
1007{
1008   DisplayModePtr mode = monitor->Modes;
1009   float mymin = 30.0, mymax = 80.0, hsync;
1010   Bool doit = FALSE;
1011
1012   for(hsync = mymin; hsync <= mymax; hsync += .5) {
1013      if(!SiSCheckForH(hsync, monitor)) doit = TRUE;
1014   }
1015
1016   if(mode) {
1017      do {
1018         if(mode->type & M_T_BUILTIN) {
1019	    hsync = (float)mode->Clock / (float)mode->HTotal;
1020	    if(!SiSCheckForH(hsync, monitor)) {
1021	       doit = TRUE;
1022	       if(hsync < mymin) mymin = hsync;
1023	       if(hsync > mymax) mymax = hsync;
1024	    }
1025	 }
1026      } while((mode = mode->next));
1027   }
1028
1029   if(doit) {
1030      monitor->nHsync = 1;
1031      monitor->hsync[0].lo = mymin;
1032      monitor->hsync[0].hi = mymax;
1033      return TRUE;
1034   }
1035
1036   return FALSE;
1037}
1038
1039static Bool
1040CheckAndOverruleV(ScrnInfoPtr pScrn, MonPtr monitor)
1041{
1042   DisplayModePtr mode = monitor->Modes;
1043   float mymin = 59.0, mymax = 61.0, vrefresh;
1044   Bool doit = FALSE, ret = FALSE;
1045
1046   for(vrefresh = mymin; vrefresh <= mymax; vrefresh += 1.0) {
1047      if(!SiSCheckForV(vrefresh, monitor)) doit = TRUE;
1048   }
1049
1050   if(mode) {
1051      do {
1052         if(mode->type & M_T_BUILTIN) {
1053	    vrefresh = mode->Clock * 1000.0 / (mode->HTotal * mode->VTotal);
1054	    if(mode->Flags & V_INTERLACE) vrefresh *= 2.0;
1055	    if(mode->Flags & V_DBLSCAN) vrefresh /= 2.0;
1056	    if(!SiSCheckForH(vrefresh, monitor)) {
1057	       doit = TRUE;
1058	       if(vrefresh < mymin) mymin = vrefresh;
1059	       if(vrefresh > mymax) mymax = vrefresh;
1060	    }
1061	 }
1062      } while((mode = mode->next));
1063   }
1064
1065   if(doit) {
1066      monitor->nVrefresh = 1;
1067      monitor->vrefresh[0].lo = mymin;
1068      monitor->vrefresh[0].hi = mymax;
1069      ret = TRUE;
1070   }
1071
1072   /* special for 640x400/320x200/@70Hz (VGA/IBM 720x480) */
1073   if( (!SiSCheckForV(71, monitor)) &&
1074       (monitor->nVrefresh < MAX_VREFRESH) ) {
1075      monitor->vrefresh[monitor->nVrefresh].lo = 71;
1076      monitor->vrefresh[monitor->nVrefresh].hi = 71;
1077      monitor->nVrefresh++;
1078      ret = TRUE;
1079   }
1080   return ret;
1081}
1082
1083/* Some helper functions for MergedFB mode */
1084
1085#ifdef SISMERGED
1086
1087/* Helper function for CRT2 monitor vrefresh/hsync options
1088 * (Code base from mga driver)
1089 */
1090static int
1091SiSStrToRanges(range *r, char *s, int max)
1092{
1093   float num = 0.0;
1094   int rangenum = 0;
1095   Bool gotdash = FALSE;
1096   Bool nextdash = FALSE;
1097   char *strnum = NULL;
1098   do {
1099      switch(*s) {
1100      case '0':
1101      case '1':
1102      case '2':
1103      case '3':
1104      case '4':
1105      case '5':
1106      case '6':
1107      case '7':
1108      case '8':
1109      case '9':
1110      case '.':
1111         if(strnum == NULL) {
1112            strnum = s;
1113            gotdash = nextdash;
1114            nextdash = FALSE;
1115         }
1116         break;
1117      case '-':
1118      case ' ':
1119      case 0:
1120         if(strnum == NULL) break;
1121         sscanf(strnum, "%f", &num);
1122	 strnum = NULL;
1123         if(gotdash) {
1124            r[rangenum - 1].hi = num;
1125         } else {
1126            r[rangenum].lo = num;
1127            r[rangenum].hi = num;
1128            rangenum++;
1129         }
1130         if(*s == '-') nextdash = (rangenum != 0);
1131	 else if(rangenum >= max) return rangenum;
1132         break;
1133      default:
1134         return 0;
1135      }
1136
1137   } while(*(s++) != 0);
1138
1139   return rangenum;
1140}
1141
1142/* Copy and link two modes (i, j) for mergedfb mode
1143 * (Code base taken from mga driver)
1144 *
1145 * - Copy mode i, merge j to copy of i, link the result to dest
1146 * - Link i and j in private record.
1147 * - If dest is NULL, return value is copy of i linked to itself.
1148 * - For mergedfb auto-config, we only check the dimension
1149 *   against virtualX/Y, if they were user-provided.
1150 * - No special treatment required for CRTxxOffs.
1151 * - Provide fake dotclock in order to distinguish between similar
1152 *   looking MetaModes (for RandR and VidMode extensions)
1153 * - Set unique VRefresh of dest mode for RandR
1154 */
1155static DisplayModePtr
1156SiSCopyModeNLink(ScrnInfoPtr pScrn, DisplayModePtr dest,
1157                 DisplayModePtr i, DisplayModePtr j,
1158		 SiSScrn2Rel srel)
1159{
1160    SISPtr pSiS = SISPTR(pScrn);
1161    DisplayModePtr mode;
1162    int dx = 0,dy = 0;
1163
1164    if(!((mode = malloc(sizeof(DisplayModeRec))))) return dest;
1165    memcpy(mode, i, sizeof(DisplayModeRec));
1166    if(!((mode->Private = malloc(sizeof(SiSMergedDisplayModeRec))))) {
1167       free(mode);
1168       return dest;
1169    }
1170    ((SiSMergedDisplayModePtr)mode->Private)->CRT1 = i;
1171    ((SiSMergedDisplayModePtr)mode->Private)->CRT2 = j;
1172    ((SiSMergedDisplayModePtr)mode->Private)->CRT2Position = srel;
1173    mode->PrivSize = 0;
1174
1175    switch(srel) {
1176    case sisLeftOf:
1177    case sisRightOf:
1178       if(!(pScrn->display->virtualX)) {
1179          dx = i->HDisplay + j->HDisplay;
1180       } else {
1181          dx = min(pScrn->virtualX, i->HDisplay + j->HDisplay);
1182       }
1183       dx -= mode->HDisplay;
1184       if(!(pScrn->display->virtualY)) {
1185          dy = max(i->VDisplay, j->VDisplay);
1186       } else {
1187          dy = min(pScrn->virtualY, max(i->VDisplay, j->VDisplay));
1188       }
1189       dy -= mode->VDisplay;
1190       break;
1191    case sisAbove:
1192    case sisBelow:
1193       if(!(pScrn->display->virtualY)) {
1194          dy = i->VDisplay + j->VDisplay;
1195       } else {
1196          dy = min(pScrn->virtualY, i->VDisplay + j->VDisplay);
1197       }
1198       dy -= mode->VDisplay;
1199       if(!(pScrn->display->virtualX)) {
1200          dx = max(i->HDisplay, j->HDisplay);
1201       } else {
1202          dx = min(pScrn->virtualX, max(i->HDisplay, j->HDisplay));
1203       }
1204       dx -= mode->HDisplay;
1205       break;
1206    case sisClone:
1207       if(!(pScrn->display->virtualX)) {
1208          dx = max(i->HDisplay, j->HDisplay);
1209       } else {
1210          dx = min(pScrn->virtualX, max(i->HDisplay, j->HDisplay));
1211       }
1212       dx -= mode->HDisplay;
1213       if(!(pScrn->display->virtualY)) {
1214          dy = max(i->VDisplay, j->VDisplay);
1215       } else {
1216	  dy = min(pScrn->virtualY, max(i->VDisplay, j->VDisplay));
1217       }
1218       dy -= mode->VDisplay;
1219       break;
1220    }
1221    mode->HDisplay += dx;
1222    mode->HSyncStart += dx;
1223    mode->HSyncEnd += dx;
1224    mode->HTotal += dx;
1225    mode->VDisplay += dy;
1226    mode->VSyncStart += dy;
1227    mode->VSyncEnd += dy;
1228    mode->VTotal += dy;
1229
1230    mode->type = M_T_DEFAULT;
1231#if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4,2,99,2,0)
1232    /* Set up as user defined (ie fake that the mode has been named in the
1233     * Modes-list in the screen section; corrects cycling with CTRL-ALT-[-+]
1234     * when source mode has not been listed there.)
1235     */
1236    mode->type |= M_T_USERDEF;
1237#endif
1238
1239    /* Set the VRefresh field (in order to make RandR use it for the rates). We
1240     * simply set this to the refresh rate for the CRT1 mode (since CRT2 will
1241     * mostly be LCD or TV anyway).
1242     */
1243    mode->VRefresh = SiSCalcVRate(i);
1244
1245    if( ((mode->HDisplay * ((pScrn->bitsPerPixel + 7) / 8) * mode->VDisplay) > pSiS->maxxfbmem) ||
1246	(mode->HDisplay > 4088) ||
1247	(mode->VDisplay > 4096) ) {
1248
1249       xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1250		"Skipped \"%s\" (%dx%d), not enough video RAM or beyond hardware specs\n",
1251		mode->name, mode->HDisplay, mode->VDisplay);
1252       free(mode->Private);
1253       free(mode);
1254
1255       return dest;
1256    }
1257
1258#ifdef SISXINERAMA
1259    if(srel != sisClone) {
1260       pSiS->AtLeastOneNonClone = TRUE;
1261    }
1262#endif
1263
1264    /* Now see if the resulting mode would be discarded as a "size" by the
1265     * RandR extension, and increase its clock by 1000 in case it does.
1266     */
1267    if(dest) {
1268       DisplayModePtr t = dest;
1269       do {
1270          if((t->HDisplay == mode->HDisplay) &&
1271	     (t->VDisplay == mode->VDisplay) &&
1272	     ((int)(t->VRefresh + .5) == (int)(mode->VRefresh + .5))) {
1273	     mode->VRefresh += 1000.0;
1274	  }
1275	  t = t->next;
1276       } while((t) && (t != dest));
1277    }
1278
1279    /* Provide a fake but unique DotClock in order to trick the vidmode
1280     * extension to allow selecting among a number of modes whose merged result
1281     * looks identical but consists of different modes for CRT1 and CRT2
1282     */
1283    mode->Clock = (int)(mode->VRefresh * 1000.0);
1284
1285    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1286	"Merged \"%s\" (%dx%d) and \"%s\" (%dx%d) to %dx%d (%d)%s\n",
1287	i->name, i->HDisplay, i->VDisplay, j->name, j->HDisplay, j->VDisplay,
1288	mode->HDisplay, mode->VDisplay, (int)mode->VRefresh,
1289	(srel == sisClone) ? " (Clone)" : "");
1290
1291    mode->next = mode;
1292    mode->prev = mode;
1293
1294    if(dest) {
1295       mode->next = dest->next; 	/* Insert node after "dest" */
1296       dest->next->prev = mode;
1297       mode->prev = dest;
1298       dest->next = mode;
1299    }
1300
1301    return mode;
1302}
1303
1304/* Helper function to find a mode from a given name
1305 * (Code base taken from mga driver)
1306 */
1307static DisplayModePtr
1308SiSGetModeFromName(char* str, DisplayModePtr i)
1309{
1310    DisplayModePtr c = i;
1311    if(!i) return NULL;
1312    do {
1313       if(strcmp(str, c->name) == 0) return c;
1314       c = c->next;
1315    } while(c != i);
1316    return NULL;
1317}
1318
1319static DisplayModePtr
1320SiSFindWidestTallestMode(DisplayModePtr i, Bool tallest)
1321{
1322    DisplayModePtr c = i, d = NULL;
1323    int max = 0;
1324    if(!i) return NULL;
1325    do {
1326       if(tallest) {
1327          if(c->VDisplay > max) {
1328	     max = c->VDisplay;
1329	     d = c;
1330          }
1331       } else {
1332          if(c->HDisplay > max) {
1333	     max = c->HDisplay;
1334	     d = c;
1335          }
1336       }
1337       c = c->next;
1338    } while(c != i);
1339    return d;
1340}
1341
1342static void
1343SiSFindWidestTallestCommonMode(DisplayModePtr i, DisplayModePtr j, Bool tallest,
1344				DisplayModePtr *a, DisplayModePtr *b)
1345{
1346    DisplayModePtr c = i, d;
1347    int max = 0;
1348    Bool foundone;
1349
1350    (*a) = (*b) = NULL;
1351
1352    if(!i || !j) return;
1353
1354    do {
1355       d = j;
1356       foundone = FALSE;
1357       do {
1358	  if( (c->HDisplay == d->HDisplay) &&
1359	      (c->VDisplay == d->VDisplay) ) {
1360	     foundone = TRUE;
1361	     break;
1362	  }
1363	  d = d->next;
1364       } while(d != j);
1365       if(foundone) {
1366	  if(tallest) {
1367	     if(c->VDisplay > max) {
1368		max = c->VDisplay;
1369		(*a) = c;
1370		(*b) = d;
1371	     }
1372	  } else {
1373	     if(c->HDisplay > max) {
1374		max = c->HDisplay;
1375		(*a) = c;
1376		(*b) = d;
1377	     }
1378	  }
1379       }
1380       c = c->next;
1381    } while(c != i);
1382}
1383
1384static DisplayModePtr
1385SiSGenerateModeListFromLargestModes(ScrnInfoPtr pScrn,
1386		    DisplayModePtr i, DisplayModePtr j,
1387		    SiSScrn2Rel srel)
1388{
1389#ifdef SISXINERAMA
1390    SISPtr pSiS = SISPTR(pScrn);
1391#endif
1392    DisplayModePtr mode1 = NULL;
1393    DisplayModePtr mode2 = NULL;
1394    DisplayModePtr mode3 = NULL;
1395    DisplayModePtr mode4 = NULL;
1396    DisplayModePtr result = NULL;
1397
1398#ifdef SISXINERAMA
1399    pSiS->AtLeastOneNonClone = FALSE;
1400#endif
1401
1402    /* Now build a default list of MetaModes.
1403     * - Non-clone: If the user enabled NonRectangular, we use the
1404     * largest mode for each CRT1 and CRT2. If not, we use the largest
1405     * common mode for CRT1 and CRT2 (if available). Additionally, and
1406     * regardless if the above, we produce a clone mode consisting of
1407     * the largest common mode (if available) in order to use DGA.
1408     * - Clone: If the (global) CRT2Position is Clone, we use the
1409     * largest common mode if available, otherwise the first two modes
1410     * in each list.
1411     */
1412
1413    switch(srel) {
1414    case sisLeftOf:
1415    case sisRightOf:
1416       mode1 = SiSFindWidestTallestMode(i, FALSE);
1417       mode2 = SiSFindWidestTallestMode(j, FALSE);
1418       SiSFindWidestTallestCommonMode(i, j, FALSE, &mode3, &mode4);
1419       break;
1420    case sisAbove:
1421    case sisBelow:
1422       mode1 = SiSFindWidestTallestMode(i, TRUE);
1423       mode2 = SiSFindWidestTallestMode(j, TRUE);
1424       SiSFindWidestTallestCommonMode(i, j, TRUE, &mode3, &mode4);
1425       break;
1426    case sisClone:
1427       SiSFindWidestTallestCommonMode(i, j, FALSE, &mode3, &mode4);
1428       if(mode3 && mode4) {
1429	  mode1 = mode3;
1430	  mode2 = mode4;
1431       } else {
1432	  mode1 = i;
1433	  mode2 = j;
1434       }
1435    }
1436
1437    if(srel != sisClone) {
1438       if(mode3 && mode4 && !pSiS->NonRect) {
1439	  mode1 = mode3;
1440	  mode2 = mode2;
1441       }
1442    }
1443
1444    if(mode1 && mode2) {
1445       result = SiSCopyModeNLink(pScrn, result, mode1, mode2, srel);
1446    }
1447
1448    if(srel != sisClone) {
1449       if(mode3 && mode4) {
1450	  result = SiSCopyModeNLink(pScrn, result, mode3, mode4, sisClone);
1451       }
1452    }
1453
1454    return result;
1455}
1456
1457/* Generate the merged-fb mode modelist
1458 * (Taken from mga driver)
1459 */
1460static DisplayModePtr
1461SiSGenerateModeListFromMetaModes(ScrnInfoPtr pScrn, char* str,
1462		    DisplayModePtr i, DisplayModePtr j,
1463		    SiSScrn2Rel srel)
1464{
1465#ifdef SISXINERAMA
1466    SISPtr pSiS = SISPTR(pScrn);
1467#endif
1468    char* strmode = str;
1469    char modename[256];
1470    Bool gotdash = FALSE;
1471    char gotsep = 0;
1472    SiSScrn2Rel sr;
1473    DisplayModePtr mode1 = NULL;
1474    DisplayModePtr mode2 = NULL;
1475    DisplayModePtr result = NULL;
1476    int myslen;
1477
1478#ifdef SISXINERAMA
1479    pSiS->AtLeastOneNonClone = FALSE;
1480#endif
1481
1482    do {
1483        switch(*str) {
1484        case 0:
1485        case '-':
1486	case '+':
1487        case ' ':
1488	case ',':
1489	case ';':
1490           if(strmode != str) {
1491
1492              myslen = str - strmode;
1493              if(myslen > 255) myslen = 255;
1494  	      strncpy(modename, strmode, myslen);
1495  	      modename[myslen] = 0;
1496
1497              if(gotdash) {
1498                 if(mode1 == NULL) {
1499  	             xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1500  	                        "Error parsing MetaModes parameter\n");
1501  	             return NULL;
1502  	         }
1503                 mode2 = SiSGetModeFromName(modename, j);
1504                 if(!mode2) {
1505                    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1506                        "Mode \"%s\" is not a supported mode for CRT2\n", modename);
1507                    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1508                        "\t(Skipping metamode \"%s%c%s\")\n", mode1->name, gotsep, modename);
1509                    mode1 = NULL;
1510		    gotsep = 0;
1511                 }
1512              } else {
1513                 mode1 = SiSGetModeFromName(modename, i);
1514                 if(!mode1) {
1515                    char* tmps = str;
1516                    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1517                        "Mode \"%s\" is not a supported mode for CRT1\n", modename);
1518                    while(*tmps == ' ' || *tmps == ';') tmps++;
1519                    /* skip the next mode */
1520  	            if(*tmps == '-' || *tmps == '+' || *tmps == ',') {
1521                       tmps++;
1522		       /* skip spaces */
1523		       while(*tmps == ' ' || *tmps == ';') tmps++;
1524		       /* skip modename */
1525		       while(*tmps && *tmps != ' ' && *tmps != ';' && *tmps != '-' && *tmps != '+' && *tmps != ',') tmps++;
1526  	               myslen = tmps - strmode;
1527  	               if(myslen > 255) myslen = 255;
1528  	               strncpy(modename,strmode,myslen);
1529  	               modename[myslen] = 0;
1530                       str = tmps - 1;
1531                    }
1532                    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1533                        "\t(Skipping metamode \"%s\")\n", modename);
1534                    mode1 = NULL;
1535		    gotsep = 0;
1536                 }
1537              }
1538              gotdash = FALSE;
1539           }
1540           strmode = str + 1;
1541           gotdash |= (*str == '-' || *str == '+' || *str == ',');
1542	   if (*str == '-' || *str == '+' || *str == ',')
1543  	      gotsep = *str;
1544
1545           if(*str != 0) break;
1546	   /* Fall through otherwise */
1547
1548        default:
1549           if(!gotdash && mode1) {
1550              sr = srel;
1551	      if(gotsep == '+') sr = sisClone;
1552              if(!mode2) {
1553                 mode2 = SiSGetModeFromName(mode1->name, j);
1554                 sr = sisClone;
1555              }
1556              if(!mode2) {
1557                 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1558                     "Mode \"%s\" is not a supported mode for CRT2\n", mode1->name);
1559                 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1560                     "\t(Skipping metamode \"%s\")\n", modename);
1561                 mode1 = NULL;
1562              } else {
1563                 result = SiSCopyModeNLink(pScrn, result, mode1, mode2, sr);
1564                 mode1 = NULL;
1565                 mode2 = NULL;
1566              }
1567	      gotsep = 0;
1568           }
1569           break;
1570
1571        }
1572
1573    } while(*(str++) != 0);
1574
1575    return result;
1576}
1577
1578static DisplayModePtr
1579SiSGenerateModeList(ScrnInfoPtr pScrn, char* str,
1580		    DisplayModePtr i, DisplayModePtr j,
1581		    SiSScrn2Rel srel)
1582{
1583   SISPtr pSiS = SISPTR(pScrn);
1584
1585   if(str != NULL) {
1586      return(SiSGenerateModeListFromMetaModes(pScrn, str, i, j, srel));
1587   } else {
1588      xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1589	"No MetaModes given, linking %s modes by default\n",
1590	(srel == sisClone) ? "largest common" :
1591	   (pSiS->NonRect ?
1592		(((srel == sisLeftOf) || (srel == sisRightOf)) ? "widest" :  "tallest")
1593		:
1594		(((srel == sisLeftOf) || (srel == sisRightOf)) ? "widest common" :  "tallest common")) );
1595      return(SiSGenerateModeListFromLargestModes(pScrn, i, j, srel));
1596   }
1597}
1598
1599static void
1600SiSRecalcDefaultVirtualSize(ScrnInfoPtr pScrn)
1601{
1602    SISPtr pSiS = SISPTR(pScrn);
1603    DisplayModePtr mode, bmode;
1604    int maxh, maxv;
1605    static const char *str = "MergedFB: Virtual %s %d\n";
1606    static const char *errstr = "Virtual %s to small for given CRT2Position offset\n";
1607
1608    mode = bmode = pScrn->modes;
1609    maxh = maxv = 0;
1610    do {
1611       if(mode->HDisplay > maxh) maxh = mode->HDisplay;
1612       if(mode->VDisplay > maxv) maxv = mode->VDisplay;
1613       mode = mode->next;
1614    } while(mode != bmode);
1615
1616    maxh += pSiS->CRT1XOffs + pSiS->CRT2XOffs;
1617    maxv += pSiS->CRT1YOffs + pSiS->CRT2YOffs;
1618
1619    if(!(pScrn->display->virtualX)) {
1620       if(maxh > 4088) {
1621	  xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1622		"Virtual width with CRT2Position offset beyond hardware specs\n");
1623	  pSiS->CRT1XOffs = pSiS->CRT2XOffs = 0;
1624	  maxh -= (pSiS->CRT1XOffs + pSiS->CRT2XOffs);
1625       }
1626       pScrn->virtualX = maxh;
1627       pScrn->displayWidth = maxh;
1628       xf86DrvMsg(pScrn->scrnIndex, X_PROBED, str, "width", maxh);
1629    } else {
1630       if(maxh < pScrn->display->virtualX) {
1631	  xf86DrvMsg(pScrn->scrnIndex, X_ERROR, errstr, "width");
1632	  pSiS->CRT1XOffs = pSiS->CRT2XOffs = 0;
1633       }
1634    }
1635
1636    if(!(pScrn->display->virtualY)) {
1637       pScrn->virtualY = maxv;
1638       xf86DrvMsg(pScrn->scrnIndex, X_PROBED, str, "height", maxv);
1639    } else {
1640       if(maxv < pScrn->display->virtualY) {
1641	  xf86DrvMsg(pScrn->scrnIndex, X_ERROR, errstr, "height");
1642	  pSiS->CRT1YOffs = pSiS->CRT2YOffs = 0;
1643       }
1644    }
1645}
1646
1647static void
1648SiSMergedFBSetDpi(ScrnInfoPtr pScrn1, ScrnInfoPtr pScrn2, SiSScrn2Rel srel)
1649{
1650   SISPtr pSiS = SISPTR(pScrn1);
1651   MessageType from = X_DEFAULT;
1652   xf86MonPtr DDC1 = (xf86MonPtr)(pScrn1->monitor->DDC);
1653   xf86MonPtr DDC2 = (xf86MonPtr)(pScrn2->monitor->DDC);
1654   int ddcWidthmm = 0, ddcHeightmm = 0;
1655   const char *dsstr = "MergedFB: Display dimensions: (%d, %d) mm\n";
1656
1657   /* This sets the DPI for MergedFB mode. The problem is that
1658    * this can never be exact, because the output devices may
1659    * have different dimensions. This function tries to compromise
1660    * through a few assumptions, and it just calculates an average DPI
1661    * value for both monitors.
1662    */
1663
1664   /* Given DisplaySize should regard BOTH monitors */
1665   pScrn1->widthmm = pScrn1->monitor->widthmm;
1666   pScrn1->heightmm = pScrn1->monitor->heightmm;
1667
1668   /* Get DDC display size; if only either CRT1 or CRT2 provided these,
1669    * assume equal dimensions for both, otherwise add dimensions
1670    */
1671   if( (DDC1 && (DDC1->features.hsize > 0 && DDC1->features.vsize > 0)) &&
1672       (DDC2 && (DDC2->features.hsize > 0 && DDC2->features.vsize > 0)) ) {
1673      ddcWidthmm = max(DDC1->features.hsize, DDC2->features.hsize) * 10;
1674      ddcHeightmm = max(DDC1->features.vsize, DDC2->features.vsize) * 10;
1675      switch(srel) {
1676      case sisLeftOf:
1677      case sisRightOf:
1678	 ddcWidthmm = (DDC1->features.hsize + DDC2->features.hsize) * 10;
1679	 break;
1680      case sisAbove:
1681      case sisBelow:
1682	 ddcHeightmm = (DDC1->features.vsize + DDC2->features.vsize) * 10;
1683      default:
1684	 break;
1685      }
1686   } else if(DDC1 && (DDC1->features.hsize > 0 && DDC1->features.vsize > 0)) {
1687      ddcWidthmm = DDC1->features.hsize * 10;
1688      ddcHeightmm = DDC1->features.vsize * 10;
1689      switch(srel) {
1690      case sisLeftOf:
1691      case sisRightOf:
1692	 ddcWidthmm *= 2;
1693	 break;
1694      case sisAbove:
1695      case sisBelow:
1696	 ddcHeightmm *= 2;
1697      default:
1698	 break;
1699      }
1700   } else if(DDC2 && (DDC2->features.hsize > 0 && DDC2->features.vsize > 0) ) {
1701      ddcWidthmm = DDC2->features.hsize * 10;
1702      ddcHeightmm = DDC2->features.vsize * 10;
1703      switch(srel) {
1704      case sisLeftOf:
1705      case sisRightOf:
1706	 ddcWidthmm *= 2;
1707	 break;
1708      case sisAbove:
1709      case sisBelow:
1710	 ddcHeightmm *= 2;
1711      default:
1712	 break;
1713      }
1714   }
1715
1716   if(monitorResolution > 0) {
1717
1718      /* Set command line given values (overrules given options) */
1719      pScrn1->xDpi = monitorResolution;
1720      pScrn1->yDpi = monitorResolution;
1721      from = X_CMDLINE;
1722
1723   } else if(pSiS->MergedFBXDPI) {
1724
1725      /* Set option-wise given values (overrule DisplaySize) */
1726      pScrn1->xDpi = pSiS->MergedFBXDPI;
1727      pScrn1->yDpi = pSiS->MergedFBYDPI;
1728      from = X_CONFIG;
1729
1730   } else if(pScrn1->widthmm > 0 || pScrn1->heightmm > 0) {
1731
1732      /* Set values calculated from given DisplaySize */
1733      from = X_CONFIG;
1734      if(pScrn1->widthmm > 0) {
1735	 pScrn1->xDpi = (int)((double)pScrn1->virtualX * 25.4 / pScrn1->widthmm);
1736      }
1737      if(pScrn1->heightmm > 0) {
1738	 pScrn1->yDpi = (int)((double)pScrn1->virtualY * 25.4 / pScrn1->heightmm);
1739      }
1740      xf86DrvMsg(pScrn1->scrnIndex, from, dsstr, pScrn1->widthmm, pScrn1->heightmm);
1741
1742    } else if(ddcWidthmm && ddcHeightmm) {
1743
1744      /* Set values from DDC-provided display size */
1745      from = X_PROBED;
1746      xf86DrvMsg(pScrn1->scrnIndex, from, dsstr, ddcWidthmm, ddcHeightmm );
1747      pScrn1->widthmm = ddcWidthmm;
1748      pScrn1->heightmm = ddcHeightmm;
1749      if(pScrn1->widthmm > 0) {
1750	 pScrn1->xDpi = (int)((double)pScrn1->virtualX * 25.4 / pScrn1->widthmm);
1751      }
1752      if(pScrn1->heightmm > 0) {
1753	 pScrn1->yDpi = (int)((double)pScrn1->virtualY * 25.4 / pScrn1->heightmm);
1754      }
1755
1756    } else {
1757
1758      pScrn1->xDpi = pScrn1->yDpi = DEFAULT_DPI;
1759
1760    }
1761
1762    /* Sanity check */
1763    if(pScrn1->xDpi > 0 && pScrn1->yDpi <= 0)
1764       pScrn1->yDpi = pScrn1->xDpi;
1765    if(pScrn1->yDpi > 0 && pScrn1->xDpi <= 0)
1766       pScrn1->xDpi = pScrn1->yDpi;
1767
1768    pScrn2->xDpi = pScrn1->xDpi;
1769    pScrn2->yDpi = pScrn1->yDpi;
1770
1771    xf86DrvMsg(pScrn1->scrnIndex, from, "MergedFB: DPI set to (%d, %d)\n",
1772		pScrn1->xDpi, pScrn1->yDpi);
1773}
1774
1775/* Pseudo-Xinerama extension for MergedFB mode */
1776#ifdef SISXINERAMA
1777
1778static void
1779SiSUpdateXineramaScreenInfo(ScrnInfoPtr pScrn1)
1780{
1781    SISPtr pSiS = SISPTR(pScrn1);
1782    int crt1scrnnum = 0, crt2scrnnum = 1;
1783    int x1=0, x2=0, y1=0, y2=0, h1=0, h2=0, w1=0, w2=0;
1784    int realvirtX, realvirtY;
1785    DisplayModePtr currentMode, firstMode;
1786    Bool infochanged = FALSE;
1787    Bool usenonrect = pSiS->NonRect;
1788    static const char rectxine[] = "\t... setting up rectangular Xinerama layout\n";
1789
1790    pSiS->MBXNR1XMAX = pSiS->MBXNR1YMAX = pSiS->MBXNR2XMAX = pSiS->MBXNR2YMAX = 65536;
1791    pSiS->HaveNonRect = pSiS->HaveOffsRegions = FALSE;
1792
1793    if(!pSiS->MergedFB) return;
1794
1795    if(SiSnoPanoramiXExtension) return;
1796
1797    if(!SiSXineramadataPtr) return;
1798
1799    if(pSiS->CRT2IsScrn0) {
1800       crt1scrnnum = 1;
1801       crt2scrnnum = 0;
1802    }
1803
1804    /* Attention: Usage of RandR may lead to virtual X and Y dimensions
1805     * actually smaller than our MetaModes. To avoid this, we calculate
1806     * the maxCRT fields here (and not somewhere else, like in CopyNLink)
1807     *
1808     * *** Note: RandR is disabled if one of CRTxxOffs is non-zero.
1809     */
1810
1811    /* "Real" virtual: Virtual without the Offset */
1812    realvirtX = pScrn1->virtualX - pSiS->CRT1XOffs - pSiS->CRT2XOffs;
1813    realvirtY = pScrn1->virtualY - pSiS->CRT1YOffs - pSiS->CRT2YOffs;
1814
1815    if((pSiS->SiSXineramaVX != pScrn1->virtualX) || (pSiS->SiSXineramaVY != pScrn1->virtualY)) {
1816
1817       if(!(pScrn1->modes)) return;
1818
1819       pSiS->maxCRT1_X1 = pSiS->maxCRT1_X2 = 0;
1820       pSiS->maxCRT1_Y1 = pSiS->maxCRT1_Y2 = 0;
1821       pSiS->maxCRT2_X1 = pSiS->maxCRT2_X2 = 0;
1822       pSiS->maxCRT2_Y1 = pSiS->maxCRT2_Y2 = 0;
1823       pSiS->maxClone_X1 = pSiS->maxClone_X2 = 0;
1824       pSiS->maxClone_Y1 = pSiS->maxClone_Y2 = 0;
1825
1826       currentMode = firstMode = pScrn1->modes;
1827
1828       do {
1829
1830          DisplayModePtr p = currentMode->next;
1831          DisplayModePtr i = ((SiSMergedDisplayModePtr)currentMode->Private)->CRT1;
1832          DisplayModePtr j = ((SiSMergedDisplayModePtr)currentMode->Private)->CRT2;
1833          SiSScrn2Rel srel = ((SiSMergedDisplayModePtr)currentMode->Private)->CRT2Position;
1834
1835          if((currentMode->HDisplay <= realvirtX) && (currentMode->VDisplay <= realvirtY) &&
1836	     (i->HDisplay <= realvirtX) && (j->HDisplay <= realvirtX) &&
1837	     (i->VDisplay <= realvirtY) && (j->VDisplay <= realvirtY)) {
1838
1839	     if(srel != sisClone) {
1840		if(pSiS->maxCRT1_X1 == i->HDisplay) {
1841		   if(pSiS->maxCRT1_X2 < j->HDisplay) {
1842		      pSiS->maxCRT1_X2 = j->HDisplay;   /* Widest CRT2 mode displayed with widest CRT1 mode */
1843		   }
1844		} else if(pSiS->maxCRT1_X1 < i->HDisplay) {
1845		   pSiS->maxCRT1_X1 = i->HDisplay;      /* Widest CRT1 mode */
1846		   pSiS->maxCRT1_X2 = j->HDisplay;
1847		}
1848		if(pSiS->maxCRT2_X2 == j->HDisplay) {
1849		   if(pSiS->maxCRT2_X1 < i->HDisplay) {
1850		      pSiS->maxCRT2_X1 = i->HDisplay;   /* Widest CRT1 mode displayed with widest CRT2 mode */
1851		   }
1852		} else if(pSiS->maxCRT2_X2 < j->HDisplay) {
1853		   pSiS->maxCRT2_X2 = j->HDisplay;      /* Widest CRT2 mode */
1854		   pSiS->maxCRT2_X1 = i->HDisplay;
1855		}
1856		if(pSiS->maxCRT1_Y1 == i->VDisplay) {   /* Same as above, but tallest instead of widest */
1857		   if(pSiS->maxCRT1_Y2 < j->VDisplay) {
1858		      pSiS->maxCRT1_Y2 = j->VDisplay;
1859		   }
1860		} else if(pSiS->maxCRT1_Y1 < i->VDisplay) {
1861		   pSiS->maxCRT1_Y1 = i->VDisplay;
1862		   pSiS->maxCRT1_Y2 = j->VDisplay;
1863		}
1864		if(pSiS->maxCRT2_Y2 == j->VDisplay) {
1865		   if(pSiS->maxCRT2_Y1 < i->VDisplay) {
1866		      pSiS->maxCRT2_Y1 = i->VDisplay;
1867		   }
1868		} else if(pSiS->maxCRT2_Y2 < j->VDisplay) {
1869		   pSiS->maxCRT2_Y2 = j->VDisplay;
1870		   pSiS->maxCRT2_Y1 = i->VDisplay;
1871		}
1872	     } else {
1873		if(pSiS->maxClone_X1 < i->HDisplay) {
1874		   pSiS->maxClone_X1 = i->HDisplay;
1875		}
1876		if(pSiS->maxClone_X2 < j->HDisplay) {
1877		   pSiS->maxClone_X2 = j->HDisplay;
1878		}
1879		if(pSiS->maxClone_Y1 < i->VDisplay) {
1880		   pSiS->maxClone_Y1 = i->VDisplay;
1881		}
1882		if(pSiS->maxClone_Y2 < j->VDisplay) {
1883		   pSiS->maxClone_Y2 = j->VDisplay;
1884		}
1885	     }
1886	  }
1887	  currentMode = p;
1888
1889       } while((currentMode) && (currentMode != firstMode));
1890
1891       pSiS->SiSXineramaVX = pScrn1->virtualX;
1892       pSiS->SiSXineramaVY = pScrn1->virtualY;
1893       infochanged = TRUE;
1894
1895    }
1896
1897    if((usenonrect) && (pSiS->CRT2Position != sisClone) && pSiS->maxCRT1_X1) {
1898       switch(pSiS->CRT2Position) {
1899       case sisLeftOf:
1900       case sisRightOf:
1901	  if((pSiS->maxCRT1_Y1 != realvirtY) && (pSiS->maxCRT2_Y2 != realvirtY)) {
1902	     usenonrect = FALSE;
1903	  }
1904	  break;
1905       case sisAbove:
1906       case sisBelow:
1907	  if((pSiS->maxCRT1_X1 != realvirtX) && (pSiS->maxCRT2_X2 != realvirtX)) {
1908	     usenonrect = FALSE;
1909	  }
1910	  break;
1911       case sisClone:
1912	  break;
1913       }
1914       if(infochanged && !usenonrect) {
1915	  xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
1916			"Virtual screen size does not match maximum display modes...\n");
1917	  xf86DrvMsg(pScrn1->scrnIndex, X_INFO, "%s", rectxine);
1918
1919       }
1920    } else if(infochanged && usenonrect) {
1921       usenonrect = FALSE;
1922       xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
1923		"Only clone modes available for this virtual screen size...\n");
1924       xf86DrvMsg(pScrn1->scrnIndex, X_INFO, "%s", rectxine);
1925    }
1926
1927    if(pSiS->maxCRT1_X1) {		/* Means we have at least one non-clone mode */
1928       switch(pSiS->CRT2Position) {
1929       case sisLeftOf:
1930	  x1 = min(pSiS->maxCRT1_X2, pScrn1->virtualX - pSiS->maxCRT1_X1);
1931	  if(x1 < 0) x1 = 0;
1932	  y1 = pSiS->CRT1YOffs;
1933	  w1 = pScrn1->virtualX - x1;
1934	  h1 = realvirtY;
1935	  if((usenonrect) && (pSiS->maxCRT1_Y1 != realvirtY)) {
1936	     h1 = pSiS->MBXNR1YMAX = pSiS->maxCRT1_Y1;
1937	     pSiS->NonRectDead.x0 = x1;
1938	     pSiS->NonRectDead.x1 = x1 + w1 - 1;
1939	     pSiS->NonRectDead.y0 = y1 + h1;
1940	     pSiS->NonRectDead.y1 = pScrn1->virtualY - 1;
1941	     pSiS->HaveNonRect = TRUE;
1942	  }
1943	  x2 = 0;
1944	  y2 = pSiS->CRT2YOffs;
1945	  w2 = max(pSiS->maxCRT2_X2, pScrn1->virtualX - pSiS->maxCRT2_X1);
1946	  if(w2 > pScrn1->virtualX) w2 = pScrn1->virtualX;
1947	  h2 = realvirtY;
1948	  if((usenonrect) && (pSiS->maxCRT2_Y2 != realvirtY)) {
1949	     h2 = pSiS->MBXNR2YMAX = pSiS->maxCRT2_Y2;
1950	     pSiS->NonRectDead.x0 = x2;
1951	     pSiS->NonRectDead.x1 = x2 + w2 - 1;
1952	     pSiS->NonRectDead.y0 = y2 + h2;
1953	     pSiS->NonRectDead.y1 = pScrn1->virtualY - 1;
1954	     pSiS->HaveNonRect = TRUE;
1955	  }
1956	  break;
1957       case sisRightOf:
1958	  x1 = 0;
1959	  y1 = pSiS->CRT1YOffs;
1960	  w1 = max(pSiS->maxCRT1_X1, pScrn1->virtualX - pSiS->maxCRT1_X2);
1961	  if(w1 > pScrn1->virtualX) w1 = pScrn1->virtualX;
1962	  h1 = realvirtY;
1963	  if((usenonrect) && (pSiS->maxCRT1_Y1 != realvirtY)) {
1964	     h1 = pSiS->MBXNR1YMAX = pSiS->maxCRT1_Y1;
1965	     pSiS->NonRectDead.x0 = x1;
1966	     pSiS->NonRectDead.x1 = x1 + w1 - 1;
1967	     pSiS->NonRectDead.y0 = y1 + h1;
1968	     pSiS->NonRectDead.y1 = pScrn1->virtualY - 1;
1969	     pSiS->HaveNonRect = TRUE;
1970	  }
1971	  x2 = min(pSiS->maxCRT2_X1, pScrn1->virtualX - pSiS->maxCRT2_X2);
1972	  if(x2 < 0) x2 = 0;
1973	  y2 = pSiS->CRT2YOffs;
1974	  w2 = pScrn1->virtualX - x2;
1975	  h2 = realvirtY;
1976	  if((usenonrect) && (pSiS->maxCRT2_Y2 != realvirtY)) {
1977	     h2 = pSiS->MBXNR2YMAX = pSiS->maxCRT2_Y2;
1978	     pSiS->NonRectDead.x0 = x2;
1979	     pSiS->NonRectDead.x1 = x2 + w2 - 1;
1980	     pSiS->NonRectDead.y0 = y2 + h2;
1981	     pSiS->NonRectDead.y1 = pScrn1->virtualY - 1;
1982	     pSiS->HaveNonRect = TRUE;
1983	  }
1984	  break;
1985       case sisAbove:
1986	  x1 = pSiS->CRT1XOffs;
1987	  y1 = min(pSiS->maxCRT1_Y2, pScrn1->virtualY - pSiS->maxCRT1_Y1);
1988	  if(y1 < 0) y1 = 0;
1989	  w1 = realvirtX;
1990	  h1 = pScrn1->virtualY - y1;
1991	  if((usenonrect) && (pSiS->maxCRT1_X1 != realvirtX)) {
1992	     w1 = pSiS->MBXNR1XMAX = pSiS->maxCRT1_X1;
1993	     pSiS->NonRectDead.x0 = x1 + w1;
1994	     pSiS->NonRectDead.x1 = pScrn1->virtualX - 1;
1995	     pSiS->NonRectDead.y0 = y1;
1996	     pSiS->NonRectDead.y1 = y1 + h1 - 1;
1997	     pSiS->HaveNonRect = TRUE;
1998	  }
1999	  x2 = pSiS->CRT2XOffs;
2000	  y2 = 0;
2001	  w2 = realvirtX;
2002	  h2 = max(pSiS->maxCRT2_Y2, pScrn1->virtualY - pSiS->maxCRT2_Y1);
2003	  if(h2 > pScrn1->virtualY) h2 = pScrn1->virtualY;
2004	  if((usenonrect) && (pSiS->maxCRT2_X2 != realvirtX)) {
2005	     w2 = pSiS->MBXNR2XMAX = pSiS->maxCRT2_X2;
2006	     pSiS->NonRectDead.x0 = x2 + w2;
2007	     pSiS->NonRectDead.x1 = pScrn1->virtualX - 1;
2008	     pSiS->NonRectDead.y0 = y2;
2009	     pSiS->NonRectDead.y1 = y2 + h2 - 1;
2010	     pSiS->HaveNonRect = TRUE;
2011	  }
2012	  break;
2013       case sisBelow:
2014	  x1 = pSiS->CRT1XOffs;
2015	  y1 = 0;
2016	  w1 = realvirtX;
2017	  h1 = max(pSiS->maxCRT1_Y1, pScrn1->virtualY - pSiS->maxCRT1_Y2);
2018	  if(h1 > pScrn1->virtualY) h1 = pScrn1->virtualY;
2019	  if((usenonrect) && (pSiS->maxCRT1_X1 != realvirtX)) {
2020	     w1 = pSiS->MBXNR1XMAX = pSiS->maxCRT1_X1;
2021	     pSiS->NonRectDead.x0 = x1 + w1;
2022	     pSiS->NonRectDead.x1 = pScrn1->virtualX - 1;
2023	     pSiS->NonRectDead.y0 = y1;
2024	     pSiS->NonRectDead.y1 = y1 + h1 - 1;
2025	     pSiS->HaveNonRect = TRUE;
2026	  }
2027	  x2 = pSiS->CRT2XOffs;
2028	  y2 = min(pSiS->maxCRT2_Y1, pScrn1->virtualY - pSiS->maxCRT2_Y2);
2029	  if(y2 < 0) y2 = 0;
2030	  w2 = realvirtX;
2031	  h2 = pScrn1->virtualY - y2;
2032	  if((usenonrect) && (pSiS->maxCRT2_X2 != realvirtX)) {
2033	     w2 = pSiS->MBXNR2XMAX = pSiS->maxCRT2_X2;
2034	     pSiS->NonRectDead.x0 = x2 + w2;
2035	     pSiS->NonRectDead.x1 = pScrn1->virtualX - 1;
2036	     pSiS->NonRectDead.y0 = y2;
2037	     pSiS->NonRectDead.y1 = y2 + h2 - 1;
2038	     pSiS->HaveNonRect = TRUE;
2039	  }
2040       default:
2041	  break;
2042       }
2043
2044       switch(pSiS->CRT2Position) {
2045       case sisLeftOf:
2046       case sisRightOf:
2047	  if(pSiS->CRT1YOffs) {
2048	     pSiS->OffDead1.x0 = x1;
2049	     pSiS->OffDead1.x1 = x1 + w1 - 1;
2050	     pSiS->OffDead1.y0 = 0;
2051	     pSiS->OffDead1.y1 = y1 - 1;
2052	     pSiS->OffDead2.x0 = x2;
2053	     pSiS->OffDead2.x1 = x2 + w2 - 1;
2054	     pSiS->OffDead2.y0 = y2 + h2;
2055	     pSiS->OffDead2.y1 = pScrn1->virtualY - 1;
2056	     pSiS->HaveOffsRegions = TRUE;
2057	  } else if(pSiS->CRT2YOffs) {
2058	     pSiS->OffDead1.x0 = x2;
2059	     pSiS->OffDead1.x1 = x2 + w2 - 1;
2060	     pSiS->OffDead1.y0 = 0;
2061	     pSiS->OffDead1.y1 = y2 - 1;
2062	     pSiS->OffDead2.x0 = x1;
2063	     pSiS->OffDead2.x1 = x1 + w1 - 1;
2064	     pSiS->OffDead2.y0 = y1 + h1;
2065	     pSiS->OffDead2.y1 = pScrn1->virtualY - 1;
2066	     pSiS->HaveOffsRegions = TRUE;
2067	  }
2068	  break;
2069       case sisAbove:
2070       case sisBelow:
2071	  if(pSiS->CRT1XOffs) {
2072	     pSiS->OffDead1.x0 = x2 + w2;
2073	     pSiS->OffDead1.x1 = pScrn1->virtualX - 1;
2074	     pSiS->OffDead1.y0 = y2;
2075	     pSiS->OffDead1.y1 = y2 + h2 - 1;
2076	     pSiS->OffDead2.x0 = 0;
2077	     pSiS->OffDead2.x1 = x1 - 1;
2078	     pSiS->OffDead2.y0 = y1;
2079	     pSiS->OffDead2.y1 = y1 + h1 - 1;
2080	     pSiS->HaveOffsRegions = TRUE;
2081	  } else if(pSiS->CRT2XOffs) {
2082	     pSiS->OffDead1.x0 = x1 + w1;
2083	     pSiS->OffDead1.x1 = pScrn1->virtualX - 1;
2084	     pSiS->OffDead1.y0 = y1;
2085	     pSiS->OffDead1.y1 = y1 + h1 - 1;
2086	     pSiS->OffDead2.x0 = 0;
2087	     pSiS->OffDead2.x1 = x2 - 1;
2088	     pSiS->OffDead2.y0 = y2;
2089	     pSiS->OffDead2.y1 = y2 + h2 - 1;
2090	     pSiS->HaveOffsRegions = TRUE;
2091	  }
2092       default:
2093	  break;
2094       }
2095
2096    } else {	/* Only clone-modes left */
2097
2098       x1 = x2 = 0;
2099       y1 = y2 = 0;
2100       w1 = w2 = max(pSiS->maxClone_X1, pSiS->maxClone_X2);
2101       h1 = h2 = max(pSiS->maxClone_Y1, pSiS->maxClone_Y2);
2102
2103    }
2104
2105    SiSXineramadataPtr[crt1scrnnum].x = x1;
2106    SiSXineramadataPtr[crt1scrnnum].y = y1;
2107    SiSXineramadataPtr[crt1scrnnum].width = w1;
2108    SiSXineramadataPtr[crt1scrnnum].height = h1;
2109    SiSXineramadataPtr[crt2scrnnum].x = x2;
2110    SiSXineramadataPtr[crt2scrnnum].y = y2;
2111    SiSXineramadataPtr[crt2scrnnum].width = w2;
2112    SiSXineramadataPtr[crt2scrnnum].height = h2;
2113
2114    if(infochanged) {
2115       xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
2116	  "Pseudo-Xinerama: CRT1 (Screen %d) (%d,%d)-(%d,%d)\n",
2117	  crt1scrnnum, x1, y1, w1+x1-1, h1+y1-1);
2118       xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
2119	  "Pseudo-Xinerama: CRT2 (Screen %d) (%d,%d)-(%d,%d)\n",
2120	  crt2scrnnum, x2, y2, w2+x2-1, h2+y2-1);
2121       if(pSiS->HaveNonRect) {
2122	  xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
2123		"Pseudo-Xinerama: Inaccessible area (%d,%d)-(%d,%d)\n",
2124		pSiS->NonRectDead.x0, pSiS->NonRectDead.y0,
2125		pSiS->NonRectDead.x1, pSiS->NonRectDead.y1);
2126       }
2127       if(pSiS->HaveOffsRegions) {
2128	  xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
2129		"Pseudo-Xinerama: Inaccessible offset area (%d,%d)-(%d,%d)\n",
2130		pSiS->OffDead1.x0, pSiS->OffDead1.y0,
2131		pSiS->OffDead1.x1, pSiS->OffDead1.y1);
2132	  xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
2133		"Pseudo-Xinerama: Inaccessible offset area (%d,%d)-(%d,%d)\n",
2134		pSiS->OffDead2.x0, pSiS->OffDead2.y0,
2135		pSiS->OffDead2.x1, pSiS->OffDead2.y1);
2136       }
2137       if(pSiS->HaveNonRect || pSiS->HaveOffsRegions) {
2138	  xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
2139		"Mouse restriction for inaccessible areas is %s\n",
2140		pSiS->MouseRestrictions ? "enabled" : "disabled");
2141       }
2142    }
2143}
2144
2145/* Proc */
2146
2147int
2148SiSProcXineramaQueryVersion(ClientPtr client)
2149{
2150    xPanoramiXQueryVersionReply	  rep;
2151    register int		  n;
2152
2153    REQUEST_SIZE_MATCH(xPanoramiXQueryVersionReq);
2154    rep.type = X_Reply;
2155    rep.length = 0;
2156    rep.sequenceNumber = client->sequence;
2157    rep.majorVersion = SIS_XINERAMA_MAJOR_VERSION;
2158    rep.minorVersion = SIS_XINERAMA_MINOR_VERSION;
2159    if(client->swapped) {
2160        _swaps(&rep.sequenceNumber, n);
2161        _swapl(&rep.length, n);
2162        _swaps(&rep.majorVersion, n);
2163        _swaps(&rep.minorVersion, n);
2164    }
2165    WriteToClient(client, sizeof(xPanoramiXQueryVersionReply), (char *)&rep);
2166    return (client->noClientException);
2167}
2168
2169int
2170SiSProcXineramaGetState(ClientPtr client)
2171{
2172    REQUEST(xPanoramiXGetStateReq);
2173    WindowPtr			pWin;
2174    xPanoramiXGetStateReply	rep;
2175    register int		n;
2176    int				rc;
2177
2178    REQUEST_SIZE_MATCH(xPanoramiXGetStateReq);
2179    rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
2180    if (rc != Success)
2181        return rc;
2182
2183    rep.type = X_Reply;
2184    rep.length = 0;
2185    rep.sequenceNumber = client->sequence;
2186    rep.state = !SiSnoPanoramiXExtension;
2187    if(client->swapped) {
2188       _swaps (&rep.sequenceNumber, n);
2189       _swapl (&rep.length, n);
2190    }
2191    WriteToClient(client, sizeof(xPanoramiXGetStateReply), (char *)&rep);
2192    return client->noClientException;
2193}
2194
2195int
2196SiSProcXineramaGetScreenCount(ClientPtr client)
2197{
2198    REQUEST(xPanoramiXGetScreenCountReq);
2199    WindowPtr				pWin;
2200    xPanoramiXGetScreenCountReply	rep;
2201    register int			n;
2202    int					rc;
2203
2204    REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq);
2205    rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
2206    if (rc != Success)
2207        return rc;
2208
2209    rep.type = X_Reply;
2210    rep.length = 0;
2211    rep.sequenceNumber = client->sequence;
2212    rep.ScreenCount = SiSXineramaNumScreens;
2213    if(client->swapped) {
2214       _swaps(&rep.sequenceNumber, n);
2215       _swapl(&rep.length, n);
2216    }
2217    WriteToClient(client, sizeof(xPanoramiXGetScreenCountReply), (char *)&rep);
2218    return client->noClientException;
2219}
2220
2221int
2222SiSProcXineramaGetScreenSize(ClientPtr client)
2223{
2224    REQUEST(xPanoramiXGetScreenSizeReq);
2225    WindowPtr				pWin;
2226    xPanoramiXGetScreenSizeReply	rep;
2227    register int			n;
2228    int					rc;
2229
2230    REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq);
2231    rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
2232    if (rc != Success)
2233        return rc;
2234
2235    rep.type = X_Reply;
2236    rep.length = 0;
2237    rep.sequenceNumber = client->sequence;
2238    rep.width  = SiSXineramadataPtr[stuff->screen].width;
2239    rep.height = SiSXineramadataPtr[stuff->screen].height;
2240    if(client->swapped) {
2241       _swaps(&rep.sequenceNumber, n);
2242       _swapl(&rep.length, n);
2243       _swapl(&rep.width, n);
2244       _swapl(&rep.height, n);
2245    }
2246    WriteToClient(client, sizeof(xPanoramiXGetScreenSizeReply), (char *)&rep);
2247    return client->noClientException;
2248}
2249
2250int
2251SiSProcXineramaIsActive(ClientPtr client)
2252{
2253    xXineramaIsActiveReply	rep;
2254
2255    REQUEST_SIZE_MATCH(xXineramaIsActiveReq);
2256
2257    rep.type = X_Reply;
2258    rep.length = 0;
2259    rep.sequenceNumber = client->sequence;
2260    rep.state = !SiSnoPanoramiXExtension;
2261    if(client->swapped) {
2262	register int n;
2263	_swaps(&rep.sequenceNumber, n);
2264	_swapl(&rep.length, n);
2265	_swapl(&rep.state, n);
2266    }
2267    WriteToClient(client, sizeof(xXineramaIsActiveReply), (char *) &rep);
2268    return client->noClientException;
2269}
2270
2271int
2272SiSProcXineramaQueryScreens(ClientPtr client)
2273{
2274    xXineramaQueryScreensReply	rep;
2275
2276    REQUEST_SIZE_MATCH(xXineramaQueryScreensReq);
2277
2278    rep.type = X_Reply;
2279    rep.sequenceNumber = client->sequence;
2280    rep.number = (SiSnoPanoramiXExtension) ? 0 : SiSXineramaNumScreens;
2281    rep.length = rep.number * sz_XineramaScreenInfo >> 2;
2282    if(client->swapped) {
2283       register int n;
2284       _swaps(&rep.sequenceNumber, n);
2285       _swapl(&rep.length, n);
2286       _swapl(&rep.number, n);
2287    }
2288    WriteToClient(client, sizeof(xXineramaQueryScreensReply), (char *)&rep);
2289
2290    if(!SiSnoPanoramiXExtension) {
2291       xXineramaScreenInfo scratch;
2292       int i;
2293
2294       for(i = 0; i < SiSXineramaNumScreens; i++) {
2295	  scratch.x_org  = SiSXineramadataPtr[i].x;
2296	  scratch.y_org  = SiSXineramadataPtr[i].y;
2297	  scratch.width  = SiSXineramadataPtr[i].width;
2298	  scratch.height = SiSXineramadataPtr[i].height;
2299	  if(client->swapped) {
2300	     register int n;
2301	     _swaps(&scratch.x_org, n);
2302	     _swaps(&scratch.y_org, n);
2303	     _swaps(&scratch.width, n);
2304	     _swaps(&scratch.height, n);
2305	  }
2306	  WriteToClient(client, sz_XineramaScreenInfo, (char *)&scratch);
2307       }
2308    }
2309
2310    return client->noClientException;
2311}
2312
2313static int
2314SiSProcXineramaDispatch(ClientPtr client)
2315{
2316    REQUEST(xReq);
2317    switch (stuff->data) {
2318	case X_PanoramiXQueryVersion:
2319	     return SiSProcXineramaQueryVersion(client);
2320	case X_PanoramiXGetState:
2321	     return SiSProcXineramaGetState(client);
2322	case X_PanoramiXGetScreenCount:
2323	     return SiSProcXineramaGetScreenCount(client);
2324	case X_PanoramiXGetScreenSize:
2325	     return SiSProcXineramaGetScreenSize(client);
2326	case X_XineramaIsActive:
2327	     return SiSProcXineramaIsActive(client);
2328	case X_XineramaQueryScreens:
2329	     return SiSProcXineramaQueryScreens(client);
2330    }
2331    return BadRequest;
2332}
2333
2334/* SProc */
2335
2336static int
2337SiSSProcXineramaQueryVersion (ClientPtr client)
2338{
2339    REQUEST(xPanoramiXQueryVersionReq);
2340    register int n;
2341    _swaps(&stuff->length,n);
2342    REQUEST_SIZE_MATCH (xPanoramiXQueryVersionReq);
2343    return SiSProcXineramaQueryVersion(client);
2344}
2345
2346static int
2347SiSSProcXineramaGetState(ClientPtr client)
2348{
2349    REQUEST(xPanoramiXGetStateReq);
2350    register int n;
2351    _swaps (&stuff->length, n);
2352    REQUEST_SIZE_MATCH(xPanoramiXGetStateReq);
2353    return SiSProcXineramaGetState(client);
2354}
2355
2356static int
2357SiSSProcXineramaGetScreenCount(ClientPtr client)
2358{
2359    REQUEST(xPanoramiXGetScreenCountReq);
2360    register int n;
2361    _swaps (&stuff->length, n);
2362    REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq);
2363    return SiSProcXineramaGetScreenCount(client);
2364}
2365
2366static int
2367SiSSProcXineramaGetScreenSize(ClientPtr client)
2368{
2369    REQUEST(xPanoramiXGetScreenSizeReq);
2370    register int n;
2371    _swaps (&stuff->length, n);
2372    REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq);
2373    return SiSProcXineramaGetScreenSize(client);
2374}
2375
2376static int
2377SiSSProcXineramaIsActive(ClientPtr client)
2378{
2379    REQUEST(xXineramaIsActiveReq);
2380    register int n;
2381    _swaps (&stuff->length, n);
2382    REQUEST_SIZE_MATCH(xXineramaIsActiveReq);
2383    return SiSProcXineramaIsActive(client);
2384}
2385
2386static int
2387SiSSProcXineramaQueryScreens(ClientPtr client)
2388{
2389    REQUEST(xXineramaQueryScreensReq);
2390    register int n;
2391    _swaps (&stuff->length, n);
2392    REQUEST_SIZE_MATCH(xXineramaQueryScreensReq);
2393    return SiSProcXineramaQueryScreens(client);
2394}
2395
2396int
2397SiSSProcXineramaDispatch(ClientPtr client)
2398{
2399    REQUEST(xReq);
2400    switch (stuff->data) {
2401	case X_PanoramiXQueryVersion:
2402	     return SiSSProcXineramaQueryVersion(client);
2403	case X_PanoramiXGetState:
2404	     return SiSSProcXineramaGetState(client);
2405	case X_PanoramiXGetScreenCount:
2406	     return SiSSProcXineramaGetScreenCount(client);
2407	case X_PanoramiXGetScreenSize:
2408	     return SiSSProcXineramaGetScreenSize(client);
2409	case X_XineramaIsActive:
2410	     return SiSSProcXineramaIsActive(client);
2411	case X_XineramaQueryScreens:
2412	     return SiSSProcXineramaQueryScreens(client);
2413    }
2414    return BadRequest;
2415}
2416
2417static void
2418SiSXineramaResetProc(ExtensionEntry* extEntry)
2419{
2420    /* Called by CloseDownExtensions() */
2421    if(SiSXineramadataPtr) {
2422       free(SiSXineramadataPtr);
2423       SiSXineramadataPtr = NULL;
2424    }
2425}
2426
2427static void
2428SiSXineramaExtensionInit(ScrnInfoPtr pScrn)
2429{
2430    SISPtr	pSiS = SISPTR(pScrn);
2431    Bool	success = FALSE;
2432
2433    if(!(SiSXineramadataPtr)) {
2434
2435       if(!pSiS->MergedFB) {
2436	  SiSnoPanoramiXExtension = TRUE;
2437	  pSiS->MouseRestrictions = FALSE;
2438	  return;
2439       }
2440
2441#ifdef PANORAMIX
2442       if(!noPanoramiXExtension) {
2443	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2444	     "Xinerama active, not initializing SiS Pseudo-Xinerama\n");
2445	  SiSnoPanoramiXExtension = TRUE;
2446	  pSiS->MouseRestrictions = FALSE;
2447	  return;
2448       }
2449#endif
2450
2451       if(SiSnoPanoramiXExtension) {
2452	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2453	      "SiS Pseudo-Xinerama disabled\n");
2454	  pSiS->MouseRestrictions = FALSE;
2455	  return;
2456       }
2457
2458       if(pSiS->CRT2Position == sisClone) {
2459	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2460	     "Running MergedFB in Clone mode, SiS Pseudo-Xinerama disabled\n");
2461	  SiSnoPanoramiXExtension = TRUE;
2462	  pSiS->MouseRestrictions = FALSE;
2463	  return;
2464       }
2465
2466       if(!(pSiS->AtLeastOneNonClone)) {
2467	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2468	     "Only Clone modes defined, SiS Pseudo-Xinerama disabled\n");
2469	  SiSnoPanoramiXExtension = TRUE;
2470	  pSiS->MouseRestrictions = FALSE;
2471	  return;
2472       }
2473
2474       SiSXineramaNumScreens = 2;
2475
2476       while(SiSXineramaGeneration != serverGeneration) {
2477
2478	  pSiS->XineramaExtEntry = AddExtension(PANORAMIX_PROTOCOL_NAME, 0,0,
2479					SiSProcXineramaDispatch,
2480					SiSSProcXineramaDispatch,
2481					SiSXineramaResetProc,
2482					StandardMinorOpcode);
2483
2484	  if(!pSiS->XineramaExtEntry) break;
2485
2486	  if(!(SiSXineramadataPtr = (SiSXineramaData *)
2487	        calloc(SiSXineramaNumScreens, sizeof(SiSXineramaData)))) break;
2488
2489	  SiSXineramaGeneration = serverGeneration;
2490	  success = TRUE;
2491       }
2492
2493       if(!success) {
2494	  SISErrorLog(pScrn, "Failed to initialize SiS Pseudo-Xinerama extension\n");
2495	  SiSnoPanoramiXExtension = TRUE;
2496	  pSiS->MouseRestrictions = FALSE;
2497	  return;
2498       }
2499
2500       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2501	  "SiS Pseudo-Xinerama extension initialized\n");
2502
2503       pSiS->SiSXineramaVX = 0;
2504       pSiS->SiSXineramaVY = 0;
2505
2506    }
2507
2508    SiSUpdateXineramaScreenInfo(pScrn);
2509
2510}
2511#endif  /* End of PseudoXinerama */
2512
2513static void
2514SiSFreeCRT2Structs(SISPtr pSiS)
2515{
2516    if(pSiS->CRT2pScrn) {
2517       if(pSiS->CRT2pScrn->modes) {
2518	  while(pSiS->CRT2pScrn->modes)
2519	     xf86DeleteMode(&pSiS->CRT2pScrn->modes, pSiS->CRT2pScrn->modes);
2520       }
2521       if(pSiS->CRT2pScrn->monitor) {
2522	  if(pSiS->CRT2pScrn->monitor->Modes) {
2523	     while(pSiS->CRT2pScrn->monitor->Modes)
2524		xf86DeleteMode(&pSiS->CRT2pScrn->monitor->Modes, pSiS->CRT2pScrn->monitor->Modes);
2525	  }
2526	  if(pSiS->CRT2pScrn->monitor->DDC) free(pSiS->CRT2pScrn->monitor->DDC);
2527	  free(pSiS->CRT2pScrn->monitor);
2528       }
2529       free(pSiS->CRT2pScrn);
2530       pSiS->CRT2pScrn = NULL;
2531   }
2532}
2533
2534#endif	/* End of MergedFB helpers */
2535
2536static xf86MonPtr
2537SiSInternalDDC(ScrnInfoPtr pScrn, int crtno)
2538{
2539   SISPtr     pSiS = SISPTR(pScrn);
2540   xf86MonPtr pMonitor = NULL;
2541   UShort     temp = 0xffff, temp1, i, realcrtno = crtno;
2542   UChar      buffer[256];
2543
2544   /* If CRT1 is off, skip DDC */
2545   if((pSiS->CRT1off) && (!crtno)) return NULL;
2546
2547   if(crtno) {
2548      if(pSiS->VBFlags & CRT2_LCD)      realcrtno = 1;
2549      else if(pSiS->VBFlags & CRT2_VGA) realcrtno = 2;
2550      else				return NULL;
2551      if(pSiS->SiS_Pr->DDCPortMixup) realcrtno = 0;
2552   } else {
2553      /* If CRT1 is LCDA, skip DDC (except 301C: DDC allowed, but uses CRT2 port!) */
2554      if(pSiS->VBFlags & CRT1_LCDA) {
2555         if(pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE) realcrtno = 1;
2556         else return NULL;
2557      }
2558   }
2559
2560   i = 3; /* Number of retrys */
2561   do {
2562      temp1 = SiS_HandleDDC(pSiS->SiS_Pr, pSiS->VBFlags, pSiS->VGAEngine,
2563			realcrtno, 0, &buffer[0], pSiS->VBFlags2);
2564      if((temp1) && (temp1 != 0xffff)) temp = temp1;
2565   } while((temp == 0xffff) && i--);
2566   if(temp != 0xffff) {
2567      xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "CRT%d DDC supported\n", crtno + 1);
2568      xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "CRT%d DDC level: %s%s%s%s\n",
2569	     crtno + 1,
2570	     (temp & 0x1a) ? "" : "[none of the supported]",
2571	     (temp & 0x02) ? "2 " : "",
2572	     (temp & 0x08) ? "D&P" : "",
2573             (temp & 0x10) ? "FPDI-2" : "");
2574      if(temp & 0x02) {
2575	 i = 5;  /* Number of retrys */
2576	 do {
2577	    temp = SiS_HandleDDC(pSiS->SiS_Pr, pSiS->VBFlags, pSiS->VGAEngine,
2578				realcrtno, 1, &buffer[0], pSiS->VBFlags2);
2579	 } while((temp) && i--);
2580         if(!temp) {
2581	    if((pMonitor = xf86InterpretEDID(pScrn->scrnIndex, &buffer[0]))) {
2582	       int tempvgagamma = 0, templcdgamma = 0;
2583	       if(buffer[0x14] & 0x80) {
2584	          templcdgamma = (buffer[0x17] + 100) * 10;
2585	       } else {
2586	          tempvgagamma = (buffer[0x17] + 100) * 10;;
2587	       }
2588	       if(crtno == 0) {
2589		  if(tempvgagamma) pSiS->CRT1VGAMonitorGamma = tempvgagamma;
2590		  /* LCD never via (demanded) CRT1 DDC port */
2591	       } else {
2592	          if(tempvgagamma) pSiS->CRT2VGAMonitorGamma = tempvgagamma;
2593	          if(templcdgamma) pSiS->CRT2LCDMonitorGamma = templcdgamma;
2594	       }
2595	       return(pMonitor);
2596	    } else {
2597	       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2598	           "CRT%d DDC EDID corrupt\n", crtno + 1);
2599	    }
2600	 } else if(temp == 0xFFFE) {
2601	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2602	    	"CRT%d DDC data is from wrong device type (%s)\n",
2603			crtno + 1,
2604			(realcrtno == 1) ? "analog instead of digital" : "digital instead of analog");
2605	 } else {
2606            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
2607	    	"CRT%d DDC reading failed\n", crtno + 1);
2608	 }
2609      } else if(temp & 0x18) {
2610         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2611	      "DDC for VESA D&P and FPDI-2 not supported yet.\n");
2612      }
2613   } else {
2614      xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
2615                "CRT%d DDC probing failed\n", crtno + 1);
2616   }
2617   return(NULL);
2618}
2619
2620static xf86MonPtr
2621SiSDoPrivateDDC(ScrnInfoPtr pScrn, int *crtnum)
2622{
2623    SISPtr pSiS = SISPTR(pScrn);
2624
2625#ifdef SISDUALHEAD
2626    if(pSiS->DualHeadMode) {
2627       if(pSiS->SecondHead) {
2628          *crtnum = 1;
2629	  return(SiSInternalDDC(pScrn, 0));
2630       } else {
2631          *crtnum = 2;
2632	  return(SiSInternalDDC(pScrn, 1));
2633       }
2634    } else
2635#endif
2636    if((pSiS->CRT1off) || (!pSiS->CRT1Detected)) {
2637       *crtnum = 2;
2638       return(SiSInternalDDC(pScrn, 1));
2639    } else {
2640       *crtnum = 1;
2641       return(SiSInternalDDC(pScrn, 0));
2642    }
2643}
2644
2645static void
2646SiSFindAspect(ScrnInfoPtr pScrn, xf86MonPtr pMonitor, int crtnum)
2647{
2648    SISPtr pSiS = SISPTR(pScrn);
2649    int UseWide = 0;
2650    int aspect = 0;
2651    Bool fromdim = FALSE;
2652
2653    if((pSiS->VGAEngine == SIS_315_VGA) && (!DIGITAL(pMonitor->features.input_type))) {
2654       if(pMonitor->features.hsize && pMonitor->features.vsize) {
2655	  aspect = (pMonitor->features.hsize * 1000) / pMonitor->features.vsize;
2656	  if(aspect >= 1400) UseWide = 1;
2657	  fromdim = TRUE;
2658       } else if((PREFERRED_TIMING_MODE(pMonitor->features.msc)) &&
2659		 (pMonitor->det_mon[0].type == DT)) {
2660	  aspect = (pMonitor->det_mon[0].section.d_timings.h_active * 1000) /
2661			pMonitor->det_mon[0].section.d_timings.v_active;
2662	  if(aspect >= 1400) UseWide = 1;
2663       }
2664       if(aspect) {
2665	  xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
2666		"According to %s, CRT%d aspect ratio is %.2f:1 (%s)\n",
2667		fromdim ? "DDC size" : "preferred mode",
2668		crtnum, (float)aspect / 1000.0, UseWide ? "wide" : "normal");
2669       } else {
2670	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2671		"Unable to determine CRT%d aspect ratio, assuming \"normal\"\n",
2672		crtnum);
2673       }
2674    }
2675
2676    if((crtnum == 1) && (pSiS->SiS_Pr->SiS_UseWide == -1)) {
2677       pSiS->SiS_Pr->SiS_UseWide = UseWide;
2678    } else if((crtnum == 2) && (pSiS->SiS_Pr->SiS_UseWideCRT2 == -1)) {
2679       pSiS->SiS_Pr->SiS_UseWideCRT2 = UseWide;
2680    }
2681}
2682
2683static Bool
2684SiSMakeOwnModeList(ScrnInfoPtr pScrn, Bool acceptcustommodes, Bool includelcdmodes,
2685                   Bool isfordvi, Bool *havecustommodes, Bool fakecrt2modes, Bool IsForCRT2)
2686{
2687    DisplayModePtr tempmode, delmode, mymodes;
2688
2689    if((mymodes = SiSBuildBuiltInModeList(pScrn, includelcdmodes, isfordvi, fakecrt2modes, IsForCRT2))) {
2690       if(!acceptcustommodes) {
2691	  while(pScrn->monitor->Modes)
2692             xf86DeleteMode(&pScrn->monitor->Modes, pScrn->monitor->Modes);
2693	  pScrn->monitor->Modes = mymodes;
2694       } else {
2695	  delmode = pScrn->monitor->Modes;
2696	  while(delmode) {
2697	     if(delmode->type & M_T_DEFAULT) {
2698	        tempmode = delmode->next;
2699	        xf86DeleteMode(&pScrn->monitor->Modes, delmode);
2700	        delmode = tempmode;
2701	     } else {
2702	        delmode = delmode->next;
2703	     }
2704	  }
2705	  /* Link default modes AFTER user ones */
2706	  if((tempmode = pScrn->monitor->Modes)) {
2707	     *havecustommodes = TRUE;
2708	     while(tempmode) {
2709	        if(!tempmode->next) break;
2710	        else tempmode = tempmode->next;
2711	     }
2712	     tempmode->next = mymodes;
2713	     mymodes->prev = tempmode;
2714	  } else {
2715	     pScrn->monitor->Modes = mymodes;
2716	  }
2717#if 0
2718	  pScrn->monitor->Modes = mymodes;
2719	  while(mymodes) {
2720	     if(!mymodes->next) break;
2721	     else mymodes = mymodes->next;
2722	  }
2723	  mymodes->next = tempmode;
2724	  if(tempmode) {
2725	     tempmode->prev = mymodes;
2726	  }
2727#endif
2728       }
2729       return TRUE;
2730    } else
2731       return FALSE;
2732}
2733
2734static void
2735SiSPrintModes(ScrnInfoPtr pScrn)
2736{
2737    DisplayModePtr p;
2738    float hsync, refresh = 0.0;
2739    char *desc, *desc2, *prefix, *uprefix, *output;
2740
2741    xf86DrvMsg(pScrn->scrnIndex, pScrn->virtualFrom, "Virtual size is %dx%d "
2742	       "(pitch %d)\n", pScrn->virtualX, pScrn->virtualY,
2743	       pScrn->displayWidth);
2744
2745    if((p = pScrn->modes) == NULL) return;
2746
2747    do {
2748	desc = desc2 = "";
2749	uprefix = " ";
2750	prefix = "Mode";
2751	output = "For CRT device: ";
2752	if(p->HSync > 0.0)      hsync = p->HSync;
2753	else if (p->HTotal > 0) hsync = (float)p->Clock / (float)p->HTotal;
2754	else	                hsync = 0.0;
2755	refresh = 0.0;
2756        if(p->VRefresh > 0.0)   refresh = p->VRefresh;
2757        else if (p->HTotal > 0 && p->VTotal > 0) {
2758	   refresh = p->Clock * 1000.0 / p->HTotal / p->VTotal;
2759	   if(p->Flags & V_INTERLACE) refresh *= 2.0;
2760	   if(p->Flags & V_DBLSCAN)   refresh /= 2.0;
2761	   if(p->VScan > 1)  	      refresh /= p->VScan;
2762        }
2763	if(p->Flags & V_INTERLACE) desc = " (I)";
2764	if(p->Flags & V_DBLSCAN)   desc = " (D)";
2765	if(p->VScan > 1) 	   desc2 = " (VScan)";
2766#ifdef M_T_USERDEF
2767	if(p->type & M_T_USERDEF)  uprefix = "*";
2768#endif
2769	if(p->type & M_T_BUILTIN)       {
2770	   prefix = "Built-in mode";
2771	   output = "";
2772	} else if (p->type & M_T_DEFAULT) {
2773	   prefix = "Default mode";
2774	} else {
2775	   output = "";
2776	}
2777
2778	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
2779		"%s%s \"%s\" (%dx%d) (%s%.1f MHz, %.1f kHz, %.1f Hz%s%s)\n",
2780		uprefix, prefix, p->name, p->HDisplay, p->VDisplay, output,
2781		p->Clock / 1000.0, hsync, refresh, desc, desc2);
2782
2783	p = p->next;
2784    } while (p != NULL && p != pScrn->modes);
2785}
2786
2787Bool SISDetermineLCDACap(ScrnInfoPtr pScrn)
2788{
2789    SISPtr pSiS = SISPTR(pScrn);
2790
2791    if( ((pSiS->ChipType == SIS_650)    ||
2792         (pSiS->ChipType == SIS_315PRO) ||
2793         (pSiS->ChipType >= SIS_661))		&&
2794	(pSiS->ChipType != XGI_20)		&&
2795        (pSiS->VBFlags2 & VB2_SISLCDABRIDGE)	&&
2796	(pSiS->VESA != 1) ) {
2797       return TRUE;
2798    }
2799    return FALSE;
2800}
2801
2802void SISSaveDetectedDevices(ScrnInfoPtr pScrn)
2803{
2804    SISPtr  pSiS = SISPTR(pScrn);
2805    /* Backup detected CRT2 devices */
2806    pSiS->detectedCRT2Devices = pSiS->VBFlags & (CRT2_LCD|CRT2_TV|CRT2_VGA|TV_AVIDEO|TV_SVIDEO|
2807                                                 TV_SCART|TV_HIVISION|TV_YPBPR);
2808}
2809
2810static Bool
2811SISCheckBIOS(SISPtr pSiS, UShort mypciid, UShort mypcivendor, int biossize)
2812{
2813    UShort romptr, pciid;
2814
2815    if(!pSiS->BIOS) return FALSE;
2816
2817    if((pSiS->BIOS[0] != 0x55) || (pSiS->BIOS[1] != 0xaa)) return FALSE;
2818
2819    romptr = pSiS->BIOS[0x18] | (pSiS->BIOS[0x19] << 8);
2820    if(romptr > (biossize - 8)) return FALSE;
2821    if((pSiS->BIOS[romptr]   != 'P') || (pSiS->BIOS[romptr+1] != 'C') ||
2822       (pSiS->BIOS[romptr+2] != 'I') || (pSiS->BIOS[romptr+3] != 'R')) return FALSE;
2823
2824    pciid = pSiS->BIOS[romptr+4] | (pSiS->BIOS[romptr+5] << 8);
2825    if(pciid != mypcivendor) return FALSE;
2826
2827    pciid = pSiS->BIOS[romptr+6] | (pSiS->BIOS[romptr+7] << 8);
2828    if(pciid != mypciid) return FALSE;
2829
2830    return TRUE;
2831}
2832
2833static void
2834SiS_LoadInitVBE(ScrnInfoPtr pScrn)
2835{
2836    SISPtr pSiS = SISPTR(pScrn);
2837
2838    /* Don't load the VBE module for secondary
2839     * cards which sisfb POSTed. We don't want
2840     * int10 to overwrite our set up (such as
2841     * disabled a0000 memory address decoding).
2842     * We don't need the VBE anyway because
2843     * the card will never be in text mode,
2844     * and we can restore graphics modes just
2845     * perfectly.
2846     */
2847    if( !pSiS->Primary &&
2848        pSiS->sisfbcardposted)
2849       return;
2850
2851    if(pSiS->pVbe) return;
2852
2853    if(xf86LoadSubModule(pScrn, "vbe")) {
2854#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,99,0,0)
2855       pSiS->pVbe = VBEInit(pSiS->pInt, pSiS->pEnt->index);
2856#else
2857       pSiS->pVbe = VBEExtendedInit(pSiS->pInt, pSiS->pEnt->index,
2858	                SET_BIOS_SCRATCH | RESTORE_BIOS_SCRATCH);
2859#endif
2860    }
2861
2862    if(!pSiS->pVbe) {
2863       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2864	   "Failed to load/initialize vbe module\n");
2865    }
2866}
2867
2868#ifdef SIS_PC_PLATFORM
2869static void
2870SiS_MapVGAMem(ScrnInfoPtr pScrn)
2871{
2872    SISPtr pSiS = SISPTR(pScrn);
2873
2874    /* Map 64k VGA window for saving/restoring CGA fonts */
2875    pSiS->VGAMapSize = 0x10000;
2876    pSiS->VGAMapPhys = 0;	/* Default */
2877    if((!pSiS->Primary) || (!pSiS->VGADecodingEnabled)) {
2878       /* If card is secondary or if a0000-address decoding
2879        * is disabled, set Phys to beginning of our video RAM.
2880	*/
2881       pSiS->VGAMapPhys = PCI_REGION_BASE(pSiS->PciInfo, 0, REGION_MEM);
2882    }
2883    if(!SiSVGAMapMem(pScrn)) {
2884       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2885	  "Failed to map VGA memory (0x%lx), can't save/restore console fonts\n",
2886	  pSiS->VGAMapPhys);
2887    }
2888}
2889#endif
2890
2891static void
2892SiS_CheckKernelFB(ScrnInfoPtr pScrn)
2893{
2894    SISPtr pSiS = SISPTR(pScrn);
2895    int        fd, i;
2896    CARD32     sisfbinfosize = 0, sisfbversion;
2897    sisfb_info *mysisfbinfo;
2898    char       name[16];
2899
2900    pSiS->donttrustpdc = FALSE;
2901    pSiS->sisfbpdc = 0xff;
2902    pSiS->sisfbpdca = 0xff;
2903    pSiS->sisfblcda = 0xff;
2904    pSiS->sisfbscalelcd = -1;
2905    pSiS->sisfbspecialtiming = CUT_NONE;
2906    pSiS->sisfb_haveemi = FALSE;
2907    pSiS->sisfbfound = FALSE;
2908    pSiS->sisfb_tvposvalid = FALSE;
2909    pSiS->sisfbdevname[0] = 0;
2910    pSiS->sisfb_havelock = FALSE;
2911    pSiS->sisfbHaveNewHeapDef = FALSE;
2912    pSiS->sisfbHeapSize = 0;
2913    pSiS->sisfbVideoOffset = 0;
2914    pSiS->sisfbxSTN = FALSE;
2915    pSiS->sisfbcanpost = FALSE;   /* (Old) sisfb can't POST card */
2916    pSiS->sisfbcardposted = TRUE; /* If (old) sisfb is running, card must have been POSTed */
2917    pSiS->sisfbprimary = FALSE;   /* (Old) sisfb doesn't know */
2918
2919    if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
2920
2921       i = 0;
2922       do {
2923
2924	  if(i <= 7) {
2925             sprintf(name, "/dev/fb%1d", i);
2926	  } else {
2927	     sprintf(name, "/dev/fb/%1d", (i - 8));
2928	  }
2929
2930          if((fd = open(name, O_RDONLY)) != -1) {
2931
2932	     Bool gotit = FALSE;
2933
2934 	     if(!ioctl(fd, SISFB_GET_INFO_SIZE, &sisfbinfosize)) {
2935 		if((mysisfbinfo = malloc(sisfbinfosize))) {
2936 		   if(!ioctl(fd, (SISFB_GET_INFO | (sisfbinfosize << 16)), mysisfbinfo)) {
2937 		      gotit = TRUE;
2938 		   } else {
2939 		      free(mysisfbinfo);
2940 		      mysisfbinfo = NULL;
2941 		   }
2942 		}
2943 	     } else {
2944 		if((mysisfbinfo = malloc(sizeof(*mysisfbinfo) + 16))) {
2945 		   if(!ioctl(fd, SISFB_GET_INFO_OLD, mysisfbinfo)) {
2946 		      gotit = TRUE;
2947		      xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2948				"Possibly old version of sisfb detected. Please update.\n");
2949		   } else {
2950		      free(mysisfbinfo);
2951		      mysisfbinfo = NULL;
2952		   }
2953		}
2954	     }
2955
2956	     if(gotit) {
2957
2958		if(mysisfbinfo->sisfb_id == SISFB_ID) {
2959
2960		   sisfbversion = (mysisfbinfo->sisfb_version << 16) |
2961				  (mysisfbinfo->sisfb_revision << 8) |
2962				  (mysisfbinfo->sisfb_patchlevel);
2963
2964	           if(sisfbversion >= SISFB_VERSION(1, 5, 8)) {
2965		      /* Added PCI bus/slot/func into in sisfb Version 1.5.08.
2966		       * Check this to make sure we run on the same card as sisfb
2967		       */
2968		      if((mysisfbinfo->sisfb_pcibus  == pSiS->PciBus)    &&
2969			 (mysisfbinfo->sisfb_pcislot == pSiS->PciDevice) &&
2970			 (mysisfbinfo->sisfb_pcifunc == pSiS->PciFunc)) {
2971			 pSiS->sisfbfound = TRUE;
2972		      }
2973		   } else pSiS->sisfbfound = TRUE;
2974
2975		   if(pSiS->sisfbfound) {
2976		      xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
2977			     "%s: SiS kernel fb driver (sisfb) %d.%d.%d detected (PCI:%02d:%02d.%d)\n",
2978				&name[5],
2979				mysisfbinfo->sisfb_version,
2980				mysisfbinfo->sisfb_revision,
2981				mysisfbinfo->sisfb_patchlevel,
2982				pSiS->PciBus,
2983				pSiS->PciDevice,
2984				pSiS->PciFunc);
2985
2986		      /* Added version/rev/pl in sisfb 1.4.0 */
2987		      if(mysisfbinfo->sisfb_version == 0) {
2988			 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2989				"Old version of sisfb found. Please update.\n");
2990		      }
2991		      /* Basically, we can't trust the pdc register if sisfb is loaded */
2992		      pSiS->donttrustpdc = TRUE;
2993		      pSiS->sisfbHeapStart = mysisfbinfo->heapstart;
2994
2995		      if(sisfbversion >= SISFB_VERSION(1, 7, 20)) {
2996			 pSiS->sisfbHeapSize = mysisfbinfo->sisfb_heapsize;
2997			 pSiS->sisfbVideoOffset = mysisfbinfo->sisfb_videooffset;
2998			 pSiS->sisfbHaveNewHeapDef = TRUE;
2999			 pSiS->sisfbFSTN = mysisfbinfo->sisfb_curfstn;
3000			 pSiS->sisfbDSTN = mysisfbinfo->sisfb_curdstn;
3001			 pSiS->sisfbxSTN = TRUE;
3002			 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3003				"sisfb: memory heap at %dKB, size %dKB, viewport at %dKB\n",
3004				(int)pSiS->sisfbHeapStart, (int)pSiS->sisfbHeapSize,
3005				(int)pSiS->sisfbVideoOffset/1024);
3006		      } else {
3007			 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3008				"sisfb: memory heap at %dKB\n", (int)pSiS->sisfbHeapStart);
3009		      }
3010		      xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3011				"sisfb: using video mode 0x%02x\n", mysisfbinfo->fbvidmode);
3012		      pSiS->OldMode = mysisfbinfo->fbvidmode;
3013		      if(sisfbversion >= SISFB_VERSION(1, 5, 6)) {
3014			 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3015				"sisfb: using %s, reserved %dK\n",
3016				(mysisfbinfo->sisfb_caps & 0x40) ? "SiS300 series Turboqueue" :
3017				   (mysisfbinfo->sisfb_caps & 0x20) ? "SiS315/330/340 series AGP command queue" :
3018				      (mysisfbinfo->sisfb_caps & 0x10) ? "SiS315/330/340 series VRAM command queue" :
3019					(mysisfbinfo->sisfb_caps & 0x08) ? "SiS315/330/340 series MMIO mode" :
3020					   "no command queue",
3021				(int)mysisfbinfo->sisfb_tqlen);
3022		      }
3023		      if(sisfbversion >= SISFB_VERSION(1, 5, 10)) {
3024			 /* We can trust the pdc value if sisfb is of recent version */
3025			 if(pSiS->VGAEngine == SIS_300_VGA) pSiS->donttrustpdc = FALSE;
3026		      }
3027		      if(sisfbversion >= SISFB_VERSION(1, 5, 11)) {
3028			 if(pSiS->VGAEngine == SIS_300_VGA) {
3029			    /* As of 1.5.11, sisfb saved the register for us (300 series) */
3030			    pSiS->sisfbpdc = mysisfbinfo->sisfb_lcdpdc;
3031			    if(!pSiS->sisfbpdc) pSiS->sisfbpdc = 0xff;
3032			 }
3033		      }
3034		      if(sisfbversion >= SISFB_VERSION(1, 5, 14)) {
3035			 if(pSiS->VGAEngine == SIS_315_VGA) {
3036			    pSiS->sisfblcda = mysisfbinfo->sisfb_lcda;
3037			 }
3038		      }
3039		      if(sisfbversion >= SISFB_VERSION(1, 6, 13)) {
3040			 pSiS->sisfbscalelcd = mysisfbinfo->sisfb_scalelcd;
3041			 pSiS->sisfbspecialtiming = mysisfbinfo->sisfb_specialtiming;
3042		      }
3043		      if(sisfbversion >= SISFB_VERSION(1, 6, 16)) {
3044			 if(pSiS->VGAEngine == SIS_315_VGA) {
3045			    pSiS->donttrustpdc = FALSE;
3046			    pSiS->sisfbpdc = mysisfbinfo->sisfb_lcdpdc;
3047			    if(sisfbversion >= SISFB_VERSION(1, 6, 24)) {
3048			       pSiS->sisfb_haveemi = mysisfbinfo->sisfb_haveemi ? TRUE : FALSE;
3049			       pSiS->sisfb_haveemilcd = TRUE;  /* will match most cases */
3050			       pSiS->sisfb_emi30 = mysisfbinfo->sisfb_emi30;
3051			       pSiS->sisfb_emi31 = mysisfbinfo->sisfb_emi31;
3052			       pSiS->sisfb_emi32 = mysisfbinfo->sisfb_emi32;
3053			       pSiS->sisfb_emi33 = mysisfbinfo->sisfb_emi33;
3054			    }
3055			    if(sisfbversion >= SISFB_VERSION(1, 6, 25)) {
3056			       pSiS->sisfb_haveemilcd = mysisfbinfo->sisfb_haveemilcd ? TRUE : FALSE;
3057			    }
3058			    if(sisfbversion >= SISFB_VERSION(1, 6, 31)) {
3059			       pSiS->sisfbpdca = mysisfbinfo->sisfb_lcdpdca;
3060			    } else {
3061			       if(pSiS->sisfbpdc) {
3062				  pSiS->sisfbpdca = (pSiS->sisfbpdc & 0xf0) >> 3;
3063				  pSiS->sisfbpdc  = (pSiS->sisfbpdc & 0x0f) << 1;
3064			       } else {
3065				  pSiS->sisfbpdca = pSiS->sisfbpdc = 0xff;
3066			       }
3067			    }
3068			 }
3069		      }
3070		      if(sisfbversion >= SISFB_VERSION(1, 7, 0)) {
3071		         pSiS->sisfb_havelock = TRUE;
3072			 if(sisfbversion >= SISFB_VERSION(1, 7, 1)) {
3073			    pSiS->sisfb_tvxpos = mysisfbinfo->sisfb_tvxpos;
3074			    pSiS->sisfb_tvypos = mysisfbinfo->sisfb_tvypos;
3075			    pSiS->sisfb_tvposvalid = TRUE;
3076			 }
3077		      }
3078		      if(sisfbversion >= SISFB_VERSION(1, 8, 7)) {
3079			 pSiS->sisfbcanpost = (mysisfbinfo->sisfb_can_post) ? TRUE : FALSE;
3080			 pSiS->sisfbcardposted = (mysisfbinfo->sisfb_card_posted) ? TRUE : FALSE;
3081			 pSiS->sisfbprimary = (mysisfbinfo->sisfb_was_boot_device) ? TRUE : FALSE;
3082			 /* Validity check */
3083			 if(!pSiS->sisfbcardposted) {
3084			    pSiS->sisfbprimary = FALSE;
3085			 }
3086		      }
3087		   }
3088	        }
3089		free(mysisfbinfo);
3090		mysisfbinfo = NULL;
3091	     }
3092	     close (fd);
3093          }
3094	  i++;
3095       } while((i <= 15) && (!pSiS->sisfbfound));
3096
3097       if(pSiS->sisfbfound) {
3098          strncpy(pSiS->sisfbdevname, name, 15);
3099       } else {
3100          xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "sisfb not found\n");
3101       }
3102    }
3103
3104    if(!pSiS->sisfbfound) {
3105       pSiS->sisfbcardposted = FALSE;
3106    }
3107}
3108
3109static void
3110SiSPseudo(ScrnInfoPtr pScrn)
3111{
3112}
3113
3114/* PreInit()
3115 *
3116 * Mandatory
3117 */
3118static Bool
3119SISPreInit(ScrnInfoPtr pScrn, int flags)
3120{
3121    SISPtr pSiS;
3122#ifdef SISDUALHEAD
3123    SISEntPtr pSiSEnt = NULL;
3124#endif
3125    MessageType from;
3126    UChar usScratchCR17, usScratchCR32, usScratchCR63;
3127    UChar usScratchSR1F, srlockReg, crlockReg;
3128    unsigned int i;
3129    int pix24flags, temp;
3130    ClockRangePtr clockRanges;
3131    xf86MonPtr pMonitor = NULL;
3132    Bool didddc2, fromDDC, crt1freqoverruled = FALSE;
3133    UChar CR5F, tempreg;
3134#if defined(SISMERGED) || defined(SISDUALHEAD)
3135    DisplayModePtr first, p, n;
3136#endif
3137#ifdef SISMERGED
3138    Bool crt2freqoverruled = FALSE;
3139#endif
3140
3141    static const char *ddcsstr = "CRT%d DDC monitor info: *******************************************\n";
3142    static const char *ddcestr = "End of CRT%d DDC monitor info *************************************\n";
3143    static const char *subshstr = "Substituting missing CRT%d monitor HSync range by DDC data\n";
3144    static const char *subsvstr = "Substituting missing CRT%d monitor VRefresh range by DDC data\n";
3145    static const char *saneh = "Correcting %s CRT%d monitor HSync range\n";
3146    static const char *sanev = "Correcting %s CRT%d monitor VRefresh range\n";
3147#ifdef SISMERGED
3148    static const char *mergednocrt1 = "CRT1 not detected or forced off. %s.\n";
3149    static const char *mergednocrt2 = "No CRT2 output selected or no video bridge detected. %s.\n";
3150    static const char *mergeddisstr = "MergedFB mode disabled";
3151    static const char *modesforstr = "Modes for CRT%d: **************************************************\n";
3152    static const char *crtsetupstr = "*************************** CRT%d setup ***************************\n";
3153    static const char *crt2monname = "CRT2";
3154#endif
3155#if defined(SISDUALHEAD) || defined(SISMERGED)
3156    static const char *notsuitablestr = "Not using mode \"%s\" (not suitable for %s mode)\n";
3157#endif
3158
3159    if(flags & PROBE_DETECT) {
3160
3161       vbeInfoPtr   pVbe;
3162
3163       if(xf86LoadSubModule(pScrn, "vbe")) {
3164          int index = xf86GetEntityInfo(pScrn->entityList[0])->index;
3165#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,99,0,0)
3166	  if((pVbe = VBEInit(NULL, index)))
3167#else
3168          if((pVbe = VBEExtendedInit(NULL, index, 0)))
3169#endif
3170          {
3171             ConfiguredMonitor = vbeDoEDID(pVbe, NULL);
3172             vbeFree(pVbe);
3173          }
3174       }
3175       return TRUE;
3176    }
3177
3178    /*
3179     * Note: This function is only called once at server startup, and
3180     * not at the start of each server generation.  This means that
3181     * only things that are persistent across server generations can
3182     * be initialised here.  xf86Screens[] is the array of all screens,
3183     * (pScrn is a pointer to one of these).  Privates allocated using
3184     * xf86AllocateScrnInfoPrivateIndex() are too, and should be used
3185     * for data that must persist across server generations.
3186     *
3187     * Per-generation data should be allocated with
3188     * AllocateScreenPrivateIndex() from the ScreenInit() function.
3189     */
3190
3191    /* Check the number of entities, and fail if it isn't one. */
3192    if(pScrn->numEntities != 1) {
3193       SISErrorLog(pScrn, "Number of entities is not 1\n");
3194       return FALSE;
3195    }
3196
3197    /* Due to the liberal license terms this is needed for
3198     * keeping the copyright notice readable and intact in
3199     * binary distributions. Removing this is a copyright
3200     * infringement. Please read the license terms above.
3201     */
3202
3203    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3204	"SiS driver (%d/%02d/%02d-%d, compiled for " SISMYSERVERNAME " %d.%d.%d.%d)\n",
3205	SISDRIVERVERSIONYEAR + 2000, SISDRIVERVERSIONMONTH,
3206	SISDRIVERVERSIONDAY, SISDRIVERREVISION,
3207#ifdef XORG_VERSION_CURRENT
3208	XORG_VERSION_MAJOR, XORG_VERSION_MINOR,
3209	XORG_VERSION_PATCH, XORG_VERSION_SNAP
3210#else
3211	XF86_VERSION_MAJOR, XF86_VERSION_MINOR,
3212	XF86_VERSION_PATCH, XF86_VERSION_SNAP
3213#endif
3214	);
3215    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3216	"Copyright (C) 2001-2005 Thomas Winischhofer <thomas@winischhofer.net> and others\n");
3217    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3218	"*** See http://www.winischhofer.eu/linuxsisvga.shtml\n");
3219    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3220	"*** for documentation and updates.\n");
3221
3222#ifdef XORG_VERSION_CURRENT
3223#if 0  /* no prototype yet */
3224    if(xorgGetVersion() != XORG_VERSION_CURRENT) {
3225       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
3226         "This driver binary is not compiled for this version of " SISMYSERVERNAME "\n");
3227    }
3228#endif
3229#else
3230#if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4,2,99,0,0)
3231    if(xf86GetVersion() != XF86_VERSION_CURRENT) {
3232       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
3233         "This driver binary is not compiled for this version of " SISMYSERVERNAME "\n");
3234    }
3235#endif
3236#endif
3237
3238    /* Allocate the SISRec driverPrivate */
3239    if(!SISGetRec(pScrn)) {
3240       SISErrorLog(pScrn, "Could not allocate memory for pSiS private\n");
3241       return FALSE;
3242    }
3243    pSiS = SISPTR(pScrn);
3244    pSiS->pScrn = pScrn;
3245
3246    pSiS->pInt = NULL;
3247
3248    /* Save PCI Domain Base */
3249#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,99,0,0) || GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 12
3250    pSiS->IODBase = 0;
3251#else
3252    pSiS->IODBase = pScrn->domainIOBase;
3253#endif
3254
3255    /* Get the entity, and make sure it is PCI. */
3256    pSiS->pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
3257    if(pSiS->pEnt->location.type != BUS_PCI) {
3258       SISErrorLog(pScrn, "Entity's bus type is not PCI\n");
3259       goto my_error_0;
3260    }
3261
3262#ifdef SISDUALHEAD
3263    /* Allocate an entity private if necessary */
3264    if(xf86IsEntityShared(pScrn->entityList[0])) {
3265       pSiSEnt = xf86GetEntityPrivate(pScrn->entityList[0], SISEntityIndex)->ptr;
3266       pSiS->entityPrivate = pSiSEnt;
3267
3268       /* If something went wrong, quit here */
3269       if((pSiSEnt->DisableDual) || (pSiSEnt->ErrorAfterFirst)) {
3270	  SISErrorLog(pScrn, "First head encountered fatal error, aborting...\n");
3271	  goto my_error_0;
3272       }
3273    }
3274#endif
3275
3276    /* Find the PCI info for this screen */
3277    pSiS->PciInfo = xf86GetPciInfoForEntity(pSiS->pEnt->index);
3278    pSiS->PciBus = PCI_CFG_BUS(pSiS->PciInfo);    /*SIS_PCI_BUS(pSiS->PciInfo);*/
3279    pSiS->PciDevice = PCI_CFG_DEV(pSiS->PciInfo); /*SIS_PCI_DEVICE(pSiS->PciInfo);*/
3280    pSiS->PciFunc = PCI_CFG_FUNC(pSiS->PciInfo);  /*SIS_PCI_FUNC(pSiS->PciInfo);*/
3281
3282#ifndef XSERVER_LIBPCIACCESS
3283    pSiS->PciTag = pciTag(PCI_DEV_BUS(pSiS->PciInfo),
3284			  PCI_DEV_DEV(pSiS->PciInfo),
3285			  PCI_DEV_FUNC(pSiS->PciInfo));
3286#endif
3287
3288#ifdef SIS_NEED_MAP_IOP
3289    /********************************************/
3290    /*     THIS IS BROKEN AND WON'T WORK        */
3291    /* Reasons:                                 */
3292    /* 1) MIPS and ARM have no i/o ports but    */
3293    /* use memory mapped i/o only. The inX/outX */
3294    /* macros in compiler.h are smart enough to */
3295    /* add "IOPortBase" to the port number, but */
3296    /* "IOPortBase" is never initialized.       */
3297    /* 2) IOPortBase is declared in compiler.h  */
3298    /* itself. So until somebody fixes all      */
3299    /* modules that #include compiler.h to set  */
3300    /* IOPortBase, vga support for MIPS and ARM */
3301    /* is unusable.                             */
3302    /* (In this driver this is solvable because */
3303    /* we have our own vgaHW routines. However, */
3304    /* we use /dev/port for now instead.)       */
3305    /********************************************/
3306    pSiS->IOPAddress = pSiS->IODBase + pSiS->PciInfo->ioBase[2];
3307    if(!SISMapIOPMem(pScrn)) {
3308       SISErrorLog(pScrn, "Could not map I/O port area at 0x%x\n", pSiS->IOPAddress);
3309       goto my_error_0;
3310    } else {
3311       xf86DrvMsg(pScrn->scrnIndex, X_INFO, "I/O port area mapped to %p, size 128\n", pSiS->IOPBase);
3312#if defined(__mips__) || defined(__arm32__)
3313       /* inX/outX macros on these use IOPortBase as offset */
3314       /* This is entirely skrewed. */
3315       IOPortBase = (unsigned int)pSiS->IOPBase;
3316#endif
3317    }
3318#endif
3319
3320    /* Set up i/o port access (for non-x86) */
3321#ifdef SISUSEDEVPORT
3322    if((sisdevport = open("/dev/port", O_RDWR, 0)) == -1) {
3323       SISErrorLog(pScrn, "Failed to open /dev/port for read/write\n");
3324       goto my_error_0;
3325    }
3326    pSiS->sisdevportopen = TRUE;
3327#endif
3328
3329    /*
3330     * Set the Chipset and ChipRev, allowing config file entries to
3331     * override. DANGEROUS!
3332     */
3333    {
3334       SymTabRec *myChipsets = SISChipsets;
3335
3336       if(PCI_DEV_VENDOR_ID(pSiS->PciInfo) == PCI_VENDOR_XGI) {
3337          myChipsets = XGIChipsets;
3338       }
3339
3340       if(pSiS->pEnt->device->chipset && *pSiS->pEnt->device->chipset) {
3341
3342          pScrn->chipset = pSiS->pEnt->device->chipset;
3343          pSiS->Chipset = xf86StringToToken(myChipsets, pScrn->chipset);
3344
3345       } else if(pSiS->pEnt->device->chipID >= 0) {
3346
3347          pSiS->Chipset = pSiS->pEnt->device->chipID;
3348          pScrn->chipset = (char *)xf86TokenToString(myChipsets, pSiS->Chipset);
3349
3350          xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipID override: 0x%04X\n",
3351								pSiS->Chipset);
3352       } else {
3353
3354          pSiS->Chipset = PCI_DEV_DEVICE_ID(pSiS->PciInfo);
3355          pScrn->chipset = (char *)xf86TokenToString(myChipsets, pSiS->Chipset);
3356
3357       }
3358    }
3359
3360    if(pSiS->pEnt->device->chipRev >= 0) {
3361
3362       pSiS->ChipRev = pSiS->pEnt->device->chipRev;
3363       xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipRev override: %d\n",
3364								pSiS->ChipRev);
3365    } else {
3366
3367       pSiS->ChipRev = PCI_DEV_REVISION(pSiS->PciInfo);
3368
3369    }
3370
3371    /*
3372     * This shouldn't happen because such problems should be caught in
3373     * SISProbe(), but check it just in case the user has overridden them.
3374     */
3375    if(pScrn->chipset == NULL) {
3376       SISErrorLog(pScrn, "ChipID 0x%04X is not recognised\n", pSiS->Chipset);
3377       goto my_error_0;
3378    }
3379    if(pSiS->Chipset < 0) {
3380       SISErrorLog(pScrn, "Chipset \"%s\" is not recognised\n", pScrn->chipset);
3381       goto my_error_0;
3382    }
3383
3384    pSiS->SiS6326Flags = 0;
3385
3386    /* Determine VGA engine generation */
3387    switch(pSiS->Chipset) {
3388       case PCI_CHIP_SIS300:
3389       case PCI_CHIP_SIS540:
3390       case PCI_CHIP_SIS630: /* 630 + 730 */
3391          pSiS->VGAEngine = SIS_300_VGA;
3392	  break;
3393       case PCI_CHIP_SIS315H:
3394       case PCI_CHIP_SIS315:
3395       case PCI_CHIP_SIS315PRO:
3396       case PCI_CHIP_SIS550:
3397       case PCI_CHIP_SIS650: /* 650 + 740 */
3398       case PCI_CHIP_SIS330:
3399       case PCI_CHIP_SIS660: /* 660, 661, 741, 760, 761, 670(?), 770 */
3400       case PCI_CHIP_SIS340:
3401       case PCI_CHIP_XGIXG20:
3402       case PCI_CHIP_XGIXG40:
3403          pSiS->VGAEngine = SIS_315_VGA;
3404	  break;
3405       case PCI_CHIP_SIS530:
3406          pSiS->VGAEngine = SIS_530_VGA;
3407	  break;
3408       case PCI_CHIP_SIS6326:
3409          /* Determine SiS6326 revision. According to SiS the differences are:
3410	   * Chip name     Chip type      TV-Out       MPEG II decoder
3411	   * 6326 AGP      Rev. G0/H0     no           no
3412	   * 6326 DVD      Rev. D2        yes          yes
3413	   * 6326          Rev. Cx        yes          yes
3414	   */
3415	  xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3416		"Chipset is SiS6326 %s (revision 0x%02x)\n",
3417		(pSiS->ChipRev == 0xaf) ? "(Ax)" :
3418		   ((pSiS->ChipRev == 0x0a) ? "AGP (G0)" :
3419		      ((pSiS->ChipRev == 0x0b) ? "AGP (H0)" :
3420			 (((pSiS->ChipRev & 0xf0) == 0xd0) ? "DVD (Dx/H0)" :
3421			    (((pSiS->ChipRev & 0xf0) == 0x90) ? "(9x)" :
3422			       (((pSiS->ChipRev & 0xf0) == 0xc0) ? "(Cx)" :
3423				  "(unknown)"))))),
3424		pSiS->ChipRev);
3425	  if((pSiS->ChipRev != 0x0a) && (pSiS->ChipRev != 0x0b)) {
3426	     pSiS->SiS6326Flags |= SIS6326_HASTV;
3427	  }
3428	  /* fall through */
3429       default:
3430	  pSiS->VGAEngine = SIS_OLD_VGA;
3431    }
3432
3433    /* We don't know about the current mode yet */
3434    pSiS->OldMode = 0;
3435
3436    /* Determine whether this is the primary or a secondary
3437     * display adapter. And right here the problem starts:
3438     * On machines with integrated SiS chipsets, the system BIOS
3439     * usually sets VGA_EN on all PCI-to-PCI bridges in the system
3440     * (of which there usually are two: PCI and AGP). This and
3441     * the fact that any PCI card POSTed by sisfb naturally has
3442     * its PCI resources enabled, leads to X assuming that
3443     * there are more than one "primary" cards in the system.
3444     * In this case, X treats ALL cards as "secondary" -
3445     * which by no means is desireable. If sisfb is running,
3446     * we can determine which card really is "primary" (in
3447     * terms of if it's the one that occupies the A0000 area
3448     * etc.) in a better way (Linux 2.6.12 or later). See below.
3449     */
3450    if(!(pSiS->Primary = xf86IsPrimaryPci(pSiS->PciInfo))) {
3451       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3452	   SISMYSERVERNAME " assumes this adapter to be secondary\n");
3453    }
3454
3455    /* Now check if sisfb is running, and if so, retrieve
3456     * all possible info from it. This also resets all
3457     * sisfb_* entries in pSiS regardless of the chipset.
3458     */
3459    SiS_CheckKernelFB(pScrn);
3460
3461    /* Now for that primary/secondary mess: Linux kernel
3462     * 2.6.12 and later knows what card is primary, and so
3463     * does any recent version of sisfb. XFree86/X.org takes
3464     * all adapters as "secondary" if more than one card's
3465     * memory and i/o resources are enabled, and more than
3466     * one PCI bridge in the system has VGA_EN set at server
3467     * start. So, let's start thinking: What is this
3468     * primary/secondary classification needed for anyway?
3469     * (This list might be incomplete for the entire server
3470     * infrastructure, but it's complete as regards the driver's
3471     * purposes of primary/secondary classification.)
3472     *    1) VGA/console font restoring: Here it's irrelevant
3473     *       whether more than one card's resources are enabled
3474     *       at server start or not. Relevant is whether the card
3475     *       occupies the A0000 area at this time. Assuming (?)
3476     *       that this does not change during machine up-time,
3477     *       it suffices to know which device was the boot video
3478     *       device (as determined by Linux 2.6.12 and later).
3479     *       Also, this is only relevant if the card is in text
3480     *       mode; if it's in graphics mode, fonts aren't saved
3481     *       or restored anyway.
3482     *       sisfb tells us if that card is considered the boot
3483     *       video device. The hardware registers tell us if
3484     *       the card's A0000 address decoding is enabled, and if
3485     *       the card currently is in text mode. These three bits
3486     *       of information are enough to decide on whether or not
3487     *       to save/restore fonts.
3488     *    2) POSTing. Same here. Relevant is only whether or not
3489     *       the card has been POSTed once before. POSTing cards
3490     *       on every server start is pretty ugly, especially
3491     *       if a framebuffer driver is already handling it.
3492     * SiS/XGI cards POSTed by sisfb can coexist well with other
3493     * active adapters. So we trust sisfb's information more
3494     * than X's (especially as we only use this information for
3495     * console font restoring and eventual POSTing.)
3496     * What we still need is a way to find out about all this if
3497     * sisfb is not running....
3498     */
3499    if(!pSiS->Primary && pSiS->sisfbprimary) {
3500       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3501		"sisfb reports this adapter to be primary. Seems more reliable.\n");
3502       pSiS->Primary = TRUE;
3503    }
3504
3505    /* If the card is "secondary" and has not been
3506     * POSTed by sisfb, POST it now through int10.
3507     * For cards POSTed by sisfb, we definitely don't
3508     * want that as it messes up our set up (eg. the
3509     * disabled A0000 area).
3510     * The int10 module decides on its own if the
3511     * card is primary or secondary. Since it uses
3512     * the generic technique described above, and since
3513     * for "secondary" cards it needs a real PCI BIOS
3514     * ROM, and since integrated chips don't have such
3515     * a PCI BIOS ROM, int10 will naturally fail to
3516     * find/read the BIOS on such machines. Great.
3517     * Using the integrated graphics as "secondary"
3518     * (which it will be as soon as X finds more than
3519     * one card's mem and i/o resources enabled, and more
3520     * than one PCI bridge's VGA_EN bit set during server
3521     * start) will therefore prevent us from restoring
3522     * the mode using the VBE. That means real fun if
3523     * the integrated chip is set up to use the video
3524     * bridge output for text mode (which is something
3525     * the driver doesn't really support since it's done
3526     * pretty much differently on every machine.)
3527     */
3528#if !defined(__alpha__)
3529    if(!pSiS->Primary) {
3530       if(!pSiS->sisfbcardposted) {
3531	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3532		"Initializing adapter through int10\n");
3533	  if(xf86LoadSubModule(pScrn, "int10")) {
3534	     pSiS->pInt = xf86InitInt10(pSiS->pEnt->index);
3535	  } else {
3536	     SISErrorLog(pScrn, "Failed to load int10 module\n");
3537	  }
3538       } else {
3539	  xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3540		"Adapter already initialized by sisfb\n");
3541       }
3542    }
3543#endif
3544
3545    /* Get the address of our relocated IO registers.
3546     * These are enabled by the hardware during cold boot, and
3547     * by the BIOS. So we can pretty much rely on that these
3548     * are enabled.
3549     */
3550    pSiS->RelIO = (SISIOADDRESS)(PCI_REGION_BASE(pSiS->PciInfo, 2, REGION_IO) + pSiS->IODBase);
3551    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Relocated I/O registers at 0x%lX\n",
3552           (ULong)pSiS->RelIO);
3553
3554    /* Unlock extended registers */
3555    sisSaveUnlockExtRegisterLock(pSiS, &srlockReg, &crlockReg);
3556
3557    /* Is a0000 memory address decoding enabled? */
3558    pSiS->VGADecodingEnabled = TRUE;
3559    switch(pSiS->VGAEngine) {
3560    case SIS_OLD_VGA:
3561       /* n/a */
3562       break;
3563    case SIS_530_VGA:
3564       inSISIDXREG(SISSR, 0x3d, tempreg);
3565       if(tempreg & 0x04) pSiS->VGADecodingEnabled = FALSE;
3566       break;
3567    case SIS_300_VGA:
3568    case SIS_315_VGA:
3569       inSISIDXREG(SISSR, 0x20, tempreg);
3570       if(tempreg & 0x04) pSiS->VGADecodingEnabled = FALSE;
3571       break;
3572    }
3573
3574    if(!pSiS->VGADecodingEnabled) {
3575       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3576		"Standard VGA (0xA0000) memory address decoding is disabled\n");
3577    }
3578
3579#ifdef SIS_PC_PLATFORM
3580    /* Map 64k VGA window for saving/restoring CGA fonts.
3581     * For secondary cards or if A0000 address decoding
3582     * is disabled, this will map the beginning of the
3583     * linear (PCI) video RAM instead.
3584     */
3585    SiS_MapVGAMem(pScrn);
3586#endif
3587
3588#ifndef XSERVER_LIBPCIACCESS
3589    /* Set operating state */
3590
3591    /* 1. memory */
3592    /* [ResUnusedOpr: Resource decoded by hw, but not used]
3593     * [ResDisableOpr: Resource is not decoded by hw]
3594     * So, if a0000 memory decoding is disabled, one could
3595     * argue that we may say so, too. Hm. Quite likely that
3596     * the VBE (via int10) will eventually enable it. So we
3597     * cowardly say unused instead.
3598     */
3599    xf86SetOperatingState(resVgaMem, pSiS->pEnt->index, ResUnusedOpr);
3600
3601    /* 2. i/o */
3602    /* Although we only use the relocated i/o ports, the hardware
3603     * also decodes the standard VGA port range. This could in
3604     * theory be disabled, but I don't dare to do this; in case of
3605     * a server crash, the card would be entirely dead. Also, this
3606     * would prevent int10 and the VBE from working at all. Generic
3607     * access control through the PCI configuration registers does
3608     * nicely anyway.
3609     */
3610    xf86SetOperatingState(resVgaIo, pSiS->pEnt->index, ResUnusedOpr);
3611
3612    /* Operations for which memory access is required */
3613    pScrn->racMemFlags = RAC_FB | RAC_COLORMAP | RAC_CURSOR | RAC_VIEWPORT;
3614
3615    /* Operations for which I/O access is required */
3616    pScrn->racIoFlags = RAC_COLORMAP | RAC_CURSOR | RAC_VIEWPORT;
3617
3618#endif
3619
3620    /* Load ramdac module */
3621    if(!xf86LoadSubModule(pScrn, "ramdac")) {
3622       SISErrorLog(pScrn, "Could not load ramdac module\n");
3623       goto my_error_1;
3624    }
3625
3626    /* Set pScrn->monitor */
3627    pScrn->monitor = pScrn->confScreen->monitor;
3628
3629    /* Reset some entries */
3630    pSiS->SiSFastVidCopy = SiSVidCopyGetDefault();
3631    pSiS->SiSFastMemCopy = SiSVidCopyGetDefault();
3632    pSiS->SiSFastVidCopyFrom = SiSVidCopyGetDefault();
3633    pSiS->SiSFastMemCopyFrom = SiSVidCopyGetDefault();
3634    pSiS->SiSFastVidCopyDone = FALSE;
3635#ifdef SIS_USE_XAA
3636    pSiS->RenderCallback = NULL;
3637#endif
3638#ifdef SIS_USE_EXA
3639    pSiS->ExaRenderCallback = NULL;
3640#endif
3641    pSiS->InitAccel = SiSPseudo;
3642    pSiS->SyncAccel = SiSPseudo;
3643    pSiS->FillRect  = NULL;
3644    pSiS->BlitRect  = NULL;
3645
3646    /* Always do a ValidMode() inside Switchmode() */
3647    pSiS->skipswitchcheck = FALSE;
3648
3649    /* Determine chipset and its capabilities in detail */
3650    pSiS->ChipFlags = 0;
3651    pSiS->SiS_SD_Flags = pSiS->SiS_SD2_Flags = 0;
3652    pSiS->SiS_SD3_Flags = pSiS->SiS_SD4_Flags = 0;
3653    pSiS->HWCursorMBufNum = pSiS->HWCursorCBufNum = 0;
3654    pSiS->NeedFlush = FALSE;
3655    pSiS->NewCRLayout = FALSE;
3656    pSiS->mmioSize = 64;
3657
3658    switch(pSiS->Chipset) {
3659       case PCI_CHIP_SIS530:
3660	  pSiS->ChipType = SIS_530;
3661	  break;
3662       case PCI_CHIP_SIS300:
3663	  pSiS->ChipType = SIS_300;
3664	  pSiS->SiS_SD_Flags |= SiS_SD_IS300SERIES;
3665	  break;
3666       case PCI_CHIP_SIS540:
3667	  pSiS->ChipType = SIS_540;
3668	  pSiS->SiS_SD_Flags |= SiS_SD_IS300SERIES;
3669	  break;
3670       case PCI_CHIP_SIS630: /* 630 + 730 */
3671	  pSiS->ChipType = SIS_630;
3672	  if(sis_pci_read_host_bridge_u32(0x00) == 0x07301039) {
3673	     pSiS->ChipType = SIS_730;
3674	  }
3675	  pSiS->SiS_SD_Flags |= SiS_SD_IS300SERIES;
3676	  break;
3677       case PCI_CHIP_SIS315H:
3678	  pSiS->ChipType = SIS_315H;
3679	  pSiS->ChipFlags |= (SiSCF_315Core | SiSCF_MMIOPalette);
3680	  pSiS->SiS_SD_Flags |= SiS_SD_IS315SERIES;
3681	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3682	  pSiS->myCR63 = 0x63;
3683	  break;
3684       case PCI_CHIP_SIS315:
3685	  /* Override for simplicity */
3686	  pSiS->Chipset = PCI_CHIP_SIS315H;
3687	  pSiS->ChipType = SIS_315;
3688	  pSiS->ChipFlags |= (SiSCF_315Core | SiSCF_MMIOPalette);
3689	  pSiS->SiS_SD_Flags |= SiS_SD_IS315SERIES;
3690	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3691	  pSiS->myCR63 = 0x63;
3692	  break;
3693       case PCI_CHIP_SIS315PRO:
3694	  /* Override for simplicity */
3695	  pSiS->Chipset = PCI_CHIP_SIS315H;
3696	  pSiS->ChipType = SIS_315PRO;
3697	  pSiS->ChipFlags |= (SiSCF_315Core | SiSCF_MMIOPalette);
3698	  pSiS->SiS_SD_Flags |= SiS_SD_IS315SERIES;
3699	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3700	  pSiS->myCR63 = 0x63;
3701	  break;
3702       case PCI_CHIP_SIS550:
3703	  pSiS->ChipType = SIS_550;
3704	  pSiS->ChipFlags |= (SiSCF_Integrated | SiSCF_MMIOPalette);
3705	  pSiS->SiS_SD_Flags |= SiS_SD_IS315SERIES;
3706	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3707	  pSiS->myCR63 = 0x63;
3708	  break;
3709       case PCI_CHIP_SIS650: /* 650 + 740 */
3710	  pSiS->ChipType = SIS_650;
3711	  if(sis_pci_read_host_bridge_u32(0x00) == 0x07401039) {
3712	     pSiS->ChipType = SIS_740;
3713	  }
3714	  pSiS->ChipFlags |= (SiSCF_Integrated | SiSCF_Real256ECore | SiSCF_MMIOPalette);
3715	  pSiS->SiS_SD_Flags |= SiS_SD_IS315SERIES;
3716	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3717	  pSiS->myCR63 = 0x63;
3718	  break;
3719       case PCI_CHIP_SIS330:
3720	  pSiS->ChipType = SIS_330;
3721	  pSiS->ChipFlags |= (SiSCF_XabreCore | SiSCF_MMIOPalette);
3722	  pSiS->SiS_SD_Flags |= SiS_SD_IS330SERIES;
3723	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3724	  pSiS->SiS_SD3_Flags |= SiS_SD3_CRT1SATGAIN; /* FIXME ? */
3725	  pSiS->myCR63 = 0x53; /* sic! */
3726	  break;
3727       case PCI_CHIP_SIS660: /* 660, 661, 741, 760, 761, 670(?) */
3728	  {
3729	     ULong hpciid = sis_pci_read_host_bridge_u32(0x00);
3730	     switch(hpciid) {
3731	     case 0x06601039:
3732		pSiS->ChipType = SIS_660;
3733		pSiS->ChipFlags |= SiSCF_Ultra256Core;
3734		pSiS->NeedFlush = TRUE;
3735		break;
3736	     case 0x07601039:
3737		pSiS->ChipType = SIS_760;
3738		pSiS->ChipFlags |= SiSCF_Ultra256Core;
3739		pSiS->NeedFlush = TRUE;
3740		break;
3741	     case 0x07611039:
3742		pSiS->ChipType = SIS_761;
3743		pSiS->ChipFlags |= SiSCF_Ultra256Core;
3744		pSiS->NeedFlush = TRUE;
3745		break;
3746	     case 0x07701039:
3747		pSiS->ChipType = SIS_770;
3748		pSiS->ChipFlags |= SiSCF_Ultra256Core;
3749		pSiS->NeedFlush = TRUE;
3750		break;
3751	     case 0x07411039:
3752		pSiS->ChipType = SIS_741;
3753		pSiS->ChipFlags |= SiSCF_Real256ECore;
3754		break;
3755	     case 0x06611039:
3756	     default:
3757		pSiS->ChipType = SIS_661;
3758		pSiS->ChipFlags |= SiSCF_Real256ECore;
3759		break;
3760	     case 0x06701039:
3761		pSiS->ChipType = SIS_670;
3762		pSiS->ChipFlags |= SiSCF_Real256ECore;
3763	     }
3764	     /* Detection could also be done by CR5C & 0xf8:
3765	      * 0x10 = 661 (CR5F & 0xc0: 0x00 both A0 and A1)
3766	      * 0x80 = 760 (CR5F & 0xc0: 0x00 A0, 0x40 A1)
3767	      * 0x90 = 741 (CR5F & 0xc0: 0x00 A0,A1 0x40 A2)
3768	      * other: 660 (CR5F & 0xc0: 0x00 A0 0x40 A1) (DOA?)
3769	      */
3770	     pSiS->ChipFlags |= (SiSCF_Integrated | SiSCF_MMIOPalette);
3771	     pSiS->SiS_SD_Flags |= SiS_SD_IS330SERIES;
3772	     pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3773	     pSiS->SiS_SD3_Flags |= SiS_SD3_CRT1SATGAIN;
3774	     pSiS->myCR63 = 0x53; /* sic! */
3775	     pSiS->NewCRLayout = TRUE;
3776	  }
3777	  break;
3778       case PCI_CHIP_SIS340:
3779	  pSiS->ChipType = SIS_340;
3780	  pSiS->ChipFlags |= (SiSCF_XabreCore | SiSCF_MMIOPalette);
3781	  pSiS->SiS_SD_Flags |= SiS_SD_IS340SERIES;
3782	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3783	  pSiS->SiS_SD3_Flags |= SiS_SD3_CRT1SATGAIN;
3784	  pSiS->myCR63 = 0x53;
3785	  pSiS->NewCRLayout = TRUE;
3786	  break;
3787       case PCI_CHIP_XGIXG20:
3788	  pSiS->ChipType = XGI_20;
3789	  pSiS->ChipFlags |= (SiSCF_XabreCore | SiSCF_MMIOPalette | SiSCF_IsXGI);
3790	  pSiS->SiS_SD2_Flags |= (SiS_SD2_NOOVERLAY | SiS_SD2_ISXGI);
3791	  pSiS->myCR63 = 0x53;
3792	  pSiS->NewCRLayout = TRUE;
3793	  break;
3794       case PCI_CHIP_XGIXG40:
3795	  pSiS->ChipType = XGI_40;
3796	  pSiS->ChipFlags |= (SiSCF_XabreCore | SiSCF_MMIOPalette | SiSCF_IsXGI);
3797	  pSiS->SiS_SD2_Flags |= (SiS_SD2_SUPPORTXVHUESAT | SiS_SD2_ISXGI);
3798	  pSiS->SiS_SD3_Flags |= SiS_SD3_CRT1SATGAIN;
3799	  pSiS->myCR63 = 0x53;
3800	  pSiS->NewCRLayout = TRUE;
3801	  if(pSiS->ChipRev == 2) pSiS->ChipFlags |= SiSCF_IsXGIV3;
3802	  break;
3803       default:
3804	  pSiS->ChipType = SIS_OLD;
3805	  break;
3806    }
3807
3808    /*
3809     * Now back to real business: Figure out the depth, bpp, etc.
3810     * Set SupportConvert... flags since we use the fb layer which
3811     * supports this conversion. (24to32 seems not implemented though)
3812     * Additionally, determine the size of the HWCursor memory area.
3813     */
3814    switch(pSiS->VGAEngine) {
3815       case SIS_300_VGA:
3816	  pSiS->CursorSize = 4096;
3817	  pix24flags = Support32bppFb;
3818	  break;
3819       case SIS_315_VGA:
3820	  pSiS->CursorSize = 16384;
3821	  pix24flags = Support32bppFb;
3822	  break;
3823       case SIS_530_VGA:
3824	  pSiS->CursorSize = 2048;
3825	  pix24flags = Support32bppFb	  |
3826		       Support24bppFb	  |
3827		       SupportConvert32to24;
3828          break;
3829       default:
3830	  pSiS->CursorSize = 2048;
3831	  pix24flags = Support24bppFb	    |
3832		       SupportConvert32to24 |
3833		       PreferConvert32to24;
3834	  break;
3835    }
3836
3837#ifdef SISDUALHEAD
3838    /* In case of Dual Head, we need to determine if we are the "master" head or
3839     * the "slave" head. In order to do that, we set PrimInit to DONE in the
3840     * shared entity at the end of the first initialization. The second
3841     * initialization then knows that some things have already been done. THIS
3842     * ALWAYS ASSUMES THAT THE FIRST DEVICE INITIALIZED IS THE MASTER!
3843     */
3844    if(xf86IsEntityShared(pScrn->entityList[0])) {
3845       if(pSiSEnt->lastInstance > 0) {
3846	  if(!xf86IsPrimInitDone(pScrn->entityList[0])) {
3847	     /* First Head (always CRT2) */
3848	     pSiS->SecondHead = FALSE;
3849	     pSiSEnt->pScrn_1 = pScrn;
3850	     pSiSEnt->CRT1ModeNo = pSiSEnt->CRT2ModeNo = -1;
3851	     pSiSEnt->CRT2ModeSet = FALSE;
3852	     pSiS->DualHeadMode = TRUE;
3853	     pSiSEnt->DisableDual = FALSE;
3854	     pSiSEnt->BIOS = NULL;
3855	     pSiSEnt->ROM661New = FALSE;
3856	     pSiSEnt->HaveXGIBIOS = FALSE;
3857	     pSiSEnt->SiS_Pr = NULL;
3858	     pSiSEnt->RenderAccelArray = NULL;
3859	     pSiSEnt->SiSFastVidCopy = pSiSEnt->SiSFastMemCopy = NULL;
3860	     pSiSEnt->SiSFastVidCopyFrom = pSiSEnt->SiSFastMemCopyFrom = NULL;
3861	  } else {
3862	     /* Second Head (always CRT1) */
3863	     pSiS->SecondHead = TRUE;
3864	     pSiSEnt->pScrn_2 = pScrn;
3865	     pSiS->DualHeadMode = TRUE;
3866	  }
3867       } else {
3868	  /* Only one screen in config file - disable dual head mode */
3869	  pSiS->SecondHead = FALSE;
3870	  pSiS->DualHeadMode = FALSE;
3871	  pSiSEnt->DisableDual = TRUE;
3872       }
3873    } else {
3874       /* Entity is not shared - disable dual head mode */
3875       pSiS->SecondHead = FALSE;
3876       pSiS->DualHeadMode = FALSE;
3877    }
3878#endif
3879
3880    /* Save the name of our Device section for SiSCtrl usage */
3881    {
3882       int ttt = 0;
3883       GDevPtr device = xf86GetDevFromEntity(pScrn->entityList[0],
3884						pScrn->entityInstanceList[0]);
3885       if(device && device->identifier) {
3886          if((ttt = strlen(device->identifier)) > 31) ttt = 31;
3887	  strncpy(&pSiS->devsectname[0], device->identifier, 31);
3888       }
3889       pSiS->devsectname[ttt] = 0;
3890    }
3891
3892    pSiS->ForceCursorOff = FALSE;
3893
3894    /* Allocate SiS_Private (for mode switching code) and initialize it */
3895    pSiS->SiS_Pr = NULL;
3896#ifdef SISDUALHEAD
3897    if(pSiSEnt) {
3898       if(pSiSEnt->SiS_Pr) pSiS->SiS_Pr = pSiSEnt->SiS_Pr;
3899    }
3900#endif
3901    if(!pSiS->SiS_Pr) {
3902       if(!(pSiS->SiS_Pr = xnfcalloc(sizeof(struct SiS_Private), 1))) {
3903	  SISErrorLog(pScrn, "Could not allocate memory for SiS_Pr structure\n");
3904	  goto my_error_1;
3905       }
3906#ifdef SISDUALHEAD
3907       if(pSiSEnt) pSiSEnt->SiS_Pr = pSiS->SiS_Pr;
3908#endif
3909       memset(pSiS->SiS_Pr, 0, sizeof(struct SiS_Private));
3910#ifndef XSERVER_LIBPCIACCESS
3911       pSiS->SiS_Pr->PciTag = pSiS->PciTag;
3912#endif
3913       pSiS->SiS_Pr->ChipType = pSiS->ChipType;
3914       pSiS->SiS_Pr->ChipRevision = pSiS->ChipRev;
3915       pSiS->SiS_Pr->SiS_Backup70xx = 0xff;
3916       pSiS->SiS_Pr->SiS_CHOverScan = -1;
3917       pSiS->SiS_Pr->SiS_ChSW = FALSE;
3918       pSiS->SiS_Pr->SiS_CustomT = CUT_NONE;
3919       pSiS->SiS_Pr->SiS_UseWide = -1;
3920       pSiS->SiS_Pr->SiS_UseWideCRT2 = -1;
3921       pSiS->SiS_Pr->SiS_TVBlue = -1;
3922       pSiS->SiS_Pr->PanelSelfDetected = FALSE;
3923       pSiS->SiS_Pr->UsePanelScaler = -1;
3924       pSiS->SiS_Pr->CenterScreen = -1;
3925       pSiS->SiS_Pr->CRT1UsesCustomMode = FALSE;
3926       pSiS->SiS_Pr->PDC = pSiS->SiS_Pr->PDCA = -1;
3927       pSiS->SiS_Pr->LVDSHL = -1;
3928       pSiS->SiS_Pr->HaveEMI = FALSE;
3929       pSiS->SiS_Pr->HaveEMILCD = FALSE;
3930       pSiS->SiS_Pr->OverruleEMI = FALSE;
3931       pSiS->SiS_Pr->SiS_SensibleSR11 = FALSE;
3932       if(pSiS->ChipType >= SIS_661) {
3933          pSiS->SiS_Pr->SiS_SensibleSR11 = TRUE;
3934       }
3935       pSiS->SiS_Pr->SiS_MyCR63 = pSiS->myCR63;
3936       pSiS->SiS_Pr->DDCPortMixup = FALSE;
3937    }
3938
3939    /* Copy IO address to SiS_Pr and init the structure for
3940     * routines inside init.c/init301.c
3941     */
3942    pSiS->SiS_Pr->IOAddress = (SISIOADDRESS)(pSiS->RelIO + 0x30);
3943    SiSRegInit(pSiS->SiS_Pr, pSiS->RelIO + 0x30);
3944
3945    /* The following identifies the old chipsets. This is only
3946     * partly used since the really old chips are not supported,
3947     * but I keep it here for future use.
3948     * 205, 215 and 225 are to be treated the same way, 201 and 202
3949     * are different.
3950     */
3951    if(pSiS->VGAEngine == SIS_OLD_VGA || pSiS->VGAEngine == SIS_530_VGA) {
3952       switch(pSiS->Chipset) {
3953       case PCI_CHIP_SG86C201:
3954	  pSiS->oldChipset = OC_SIS86201; break;
3955       case PCI_CHIP_SG86C202:
3956	  pSiS->oldChipset = OC_SIS86202; break;
3957       case PCI_CHIP_SG86C205:
3958	  inSISIDXREG(SISSR, 0x10, tempreg);
3959	  if(tempreg & 0x80) pSiS->oldChipset = OC_SIS6205B;
3960	  else pSiS->oldChipset = (pSiS->ChipRev == 0x11) ?
3961					OC_SIS6205C : OC_SIS6205A;
3962	  break;
3963       case PCI_CHIP_SIS82C204:
3964	  pSiS->oldChipset = OC_SIS82204; break;
3965       case 0x6225:
3966	  pSiS->oldChipset = OC_SIS6225; break;
3967       case PCI_CHIP_SIS5597:
3968	  pSiS->oldChipset = OC_SIS5597; break;
3969       case PCI_CHIP_SIS6326:
3970	  pSiS->oldChipset = OC_SIS6326; break;
3971       case PCI_CHIP_SIS530:
3972	  if(sis_pci_read_host_bridge_u32(0x00) == 0x06201039) {
3973	     pSiS->oldChipset = OC_SIS620;
3974	  } else {
3975	     if((pSiS->ChipRev & 0x0f) < 0x0a)
3976		   pSiS->oldChipset = OC_SIS530A;
3977	     else  pSiS->oldChipset = OC_SIS530B;
3978	  }
3979	  break;
3980       default:
3981	  pSiS->oldChipset = OC_UNKNOWN;
3982       }
3983    }
3984
3985    if(!xf86SetDepthBpp(pScrn, 0, 0, 0, pix24flags)) {
3986       SISErrorLog(pScrn, "xf86SetDepthBpp() error\n");
3987       goto my_error_1;
3988    }
3989
3990    /* Check that the returned depth is one we support */
3991    temp = 0;
3992    switch(pScrn->depth) {
3993       case 8:
3994       case 16:
3995       case 24:
3996          break;
3997       case 15:
3998	  if((pSiS->VGAEngine == SIS_300_VGA) ||
3999	     (pSiS->VGAEngine == SIS_315_VGA)) {
4000	     temp = 1;
4001	  }
4002	  break;
4003       default:
4004	  temp = 1;
4005    }
4006
4007    if(temp) {
4008       SISErrorLog(pScrn,
4009            "Given color depth (%d) is not supported by this driver/chipset\n",
4010            pScrn->depth);
4011       goto my_error_1;
4012    }
4013
4014    xf86PrintDepthBpp(pScrn);
4015
4016    if( (((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) &&
4017         (pScrn->bitsPerPixel == 24)) ||
4018	((pSiS->VGAEngine == SIS_OLD_VGA) && (pScrn->bitsPerPixel == 32)) ) {
4019       SISErrorLog(pScrn,
4020            "Framebuffer bpp %d not supported for this chipset\n", pScrn->bitsPerPixel);
4021       goto my_error_1;
4022    }
4023
4024    /* Get the depth24 pixmap format */
4025    if(pScrn->depth == 24 && pix24bpp == 0) {
4026       pix24bpp = xf86GetBppFromDepth(pScrn, 24);
4027    }
4028
4029    /*
4030     * This must happen after pScrn->display has been set because
4031     * xf86SetWeight references it.
4032     */
4033    if(pScrn->depth > 8) {
4034        /* The defaults are OK for us */
4035        rgb zeros = {0, 0, 0};
4036
4037        if(!xf86SetWeight(pScrn, zeros, zeros)) {
4038	    SISErrorLog(pScrn, "xf86SetWeight() error\n");
4039	    goto my_error_1;
4040        } else {
4041	   Bool ret = FALSE;
4042	   switch(pScrn->depth) {
4043	   case 15:
4044	      if((pScrn->weight.red != 5) ||
4045	         (pScrn->weight.green != 5) ||
4046		 (pScrn->weight.blue != 5)) ret = TRUE;
4047	      break;
4048	   case 16:
4049	      if((pScrn->weight.red != 5) ||
4050	         (pScrn->weight.green != 6) ||
4051		 (pScrn->weight.blue != 5)) ret = TRUE;
4052	      break;
4053	   case 24:
4054	      if((pScrn->weight.red != 8) ||
4055	         (pScrn->weight.green != 8) ||
4056		 (pScrn->weight.blue != 8)) ret = TRUE;
4057	      break;
4058	   }
4059	   if(ret) {
4060	      SISErrorLog(pScrn,
4061		   "RGB weight %d%d%d at depth %d not supported by hardware\n",
4062		   (int)pScrn->weight.red, (int)pScrn->weight.green,
4063		   (int)pScrn->weight.blue, pScrn->depth);
4064	      goto my_error_1;
4065	   }
4066        }
4067    }
4068
4069    /* Set the current layout parameters */
4070    pSiS->CurrentLayout.bitsPerPixel = pScrn->bitsPerPixel;
4071    pSiS->CurrentLayout.depth        = pScrn->depth;
4072    /* (Inside this function, we can use pScrn's contents anyway) */
4073
4074    if(!xf86SetDefaultVisual(pScrn, -1)) {
4075       SISErrorLog(pScrn, "xf86SetDefaultVisual() error\n");
4076       goto my_error_1;
4077    } else {
4078       /* We don't support DirectColor at > 8bpp */
4079       if(pScrn->depth > 8 && pScrn->defaultVisual != TrueColor) {
4080	  SISErrorLog(pScrn,
4081	       "Given default visual (%s) is not supported at depth %d\n",
4082	        xf86GetVisualName(pScrn->defaultVisual), pScrn->depth);
4083	  goto my_error_1;
4084       }
4085    }
4086
4087#ifdef SISDUALHEAD
4088    /* Due to palette & timing problems we don't support 8bpp in DHM */
4089    if((pSiS->DualHeadMode) && (pScrn->bitsPerPixel <= 8)) {
4090       SISErrorLog(pScrn, "Color depth %d not supported in Dual Head mode.\n",
4091			pScrn->bitsPerPixel);
4092       goto my_error_1;
4093    }
4094#endif
4095
4096    /* Read BIOS for 300/315/330/340 series customization */
4097    pSiS->SiS_Pr->VirtualRomBase = NULL;
4098    pSiS->BIOS = NULL;
4099    pSiS->SiS_Pr->UseROM = FALSE;
4100    pSiS->ROM661New = FALSE;
4101    pSiS->HaveXGIBIOS = FALSE;
4102
4103    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
4104#ifdef SISDUALHEAD
4105       if(pSiSEnt) {
4106	  if(pSiSEnt->BIOS) {
4107	     pSiS->BIOS = pSiSEnt->BIOS;
4108	     pSiS->SiS_Pr->VirtualRomBase = pSiS->BIOS;
4109	     pSiS->ROM661New = pSiSEnt->ROM661New;
4110	     pSiS->HaveXGIBIOS = pSiSEnt->HaveXGIBIOS;
4111	  }
4112       }
4113#endif
4114       if(!pSiS->BIOS) {
4115	  if(!(pSiS->BIOS = calloc(1, BIOS_SIZE))) {
4116	     xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
4117		"Could not allocate memory for video BIOS image\n");
4118	  } else {
4119	     UShort mypciid = pSiS->Chipset;
4120	     UShort mypcivendor = (pSiS->ChipFlags & SiSCF_IsXGI) ? PCI_VENDOR_XGI : PCI_VENDOR_SIS;
4121	     Bool   found = FALSE, readpci = FALSE;
4122	     int    biossize = BIOS_SIZE;
4123
4124	     switch(pSiS->ChipType) {
4125	     case SIS_315:    mypciid = PCI_CHIP_SIS315;
4126			      readpci = TRUE;
4127			      break;
4128	     case SIS_315PRO: mypciid = PCI_CHIP_SIS315PRO;
4129			      readpci = TRUE;
4130			      break;
4131	     case SIS_300:
4132	     case SIS_315H:
4133	     case SIS_330:
4134	     case SIS_340:
4135	     case SIS_650:
4136	     case SIS_760:
4137	     case XGI_40:     readpci = TRUE;
4138			      break;
4139	     case XGI_20:     readpci = TRUE;
4140			      biossize = 0x8000;
4141			      break;
4142	     }
4143#if XSERVER_LIBPCIACCESS
4144	     if(readpci) {
4145		pSiS->PciInfo->rom_size = biossize;
4146		pci_device_read_rom(pSiS->PciInfo, pSiS->BIOS);
4147		if(SISCheckBIOS(pSiS, mypciid, mypcivendor, biossize)) {
4148		   found = TRUE;
4149		}
4150	     }
4151#else
4152	     if(readpci) {
4153		xf86ReadPciBIOS(0, pSiS->PciTag, 0, pSiS->BIOS, biossize);
4154		if(SISCheckBIOS(pSiS, mypciid, mypcivendor, biossize)) {
4155		   found = TRUE;
4156		}
4157	     }
4158
4159	     if(!found) {
4160	        ULong  segstart;
4161		for(segstart = BIOS_BASE; segstart < 0x000f0000; segstart += 0x00001000) {
4162
4163#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,99,0,0)
4164		   if(xf86ReadBIOS(segstart, 0, pSiS->BIOS, biossize) != biossize) continue;
4165#else
4166		   if(xf86ReadDomainMemory(pSiS->PciTag, segstart, biossize, pSiS->BIOS) != biossize) continue;
4167#endif
4168
4169		   if(!SISCheckBIOS(pSiS, mypciid, mypcivendor, biossize)) continue;
4170
4171		   found = TRUE;
4172		   break;
4173		}
4174             }
4175#endif
4176	     if(found) {
4177		UShort romptr = pSiS->BIOS[0x16] | (pSiS->BIOS[0x17] << 8);
4178		pSiS->SiS_Pr->VirtualRomBase = pSiS->BIOS;
4179		if(pSiS->ChipFlags & SiSCF_IsXGI) {
4180		   pSiS->HaveXGIBIOS = pSiS->SiS_Pr->SiS_XGIROM = TRUE;
4181		   pSiS->SiS_Pr->UseROM = FALSE;
4182		   if(pSiS->ChipFlags & SiSCF_IsXGIV3) {
4183		      if(!(pSiS->BIOS[0x1d1] & 0x01)) {
4184			 pSiS->SiS_Pr->DDCPortMixup = TRUE;
4185		      }
4186	           }
4187	        } else {
4188		   pSiS->ROM661New = SiSDetermineROMLayout661(pSiS->SiS_Pr);
4189		}
4190		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4191			"Video BIOS version \"%7s\" found (%s data layout)\n",
4192			&pSiS->BIOS[romptr], pSiS->ROM661New ? "new SiS" :
4193				(pSiS->HaveXGIBIOS ? "XGI" : "old SiS"));
4194		if(pSiS->SiS_Pr->DDCPortMixup) {
4195		   xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
4196			"*** Buggy XGI V3XT card detected: If VGA and DVI are connected at the\n");
4197		   xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
4198			"*** same time, BIOS and driver will be unable to detect DVI connection.\n");
4199		}
4200#ifdef SISDUALHEAD
4201		if(pSiSEnt) {
4202		   pSiSEnt->BIOS = pSiS->BIOS;
4203		   pSiSEnt->ROM661New = pSiS->ROM661New;
4204		   pSiSEnt->HaveXGIBIOS = pSiS->HaveXGIBIOS;
4205		}
4206#endif
4207	     } else {
4208	        xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
4209			 "Could not find/read video BIOS\n");
4210		free(pSiS->BIOS);
4211		pSiS->BIOS = NULL;
4212	     }
4213          }
4214       }
4215
4216       if(!(pSiS->ChipFlags & SiSCF_IsXGI)) {
4217          if(pSiS->BIOS) pSiS->SiS_Pr->UseROM = TRUE;
4218          else           pSiS->SiS_Pr->UseROM = FALSE;
4219       }
4220    }
4221
4222    /* Evaluate options */
4223    SiSOptions(pScrn);
4224
4225#ifdef SISMERGED
4226    /* Due to palette & timing problems we don't support 8bpp in MFBM */
4227    if((pSiS->MergedFB) && (pScrn->bitsPerPixel <= 8)) {
4228       SISErrorLog(pScrn, "MergedFB: Color depth %d not supported, %s\n",
4229			pScrn->bitsPerPixel, mergeddisstr);
4230       pSiS->MergedFB = pSiS->MergedFBAuto = FALSE;
4231    }
4232#endif
4233
4234    /* Probe CPU features */
4235#ifdef SISDUALHEAD
4236    if(pSiS->DualHeadMode) {
4237       pSiS->CPUFlags = pSiSEnt->CPUFlags;
4238    }
4239#endif
4240    if(!pSiS->CPUFlags) {
4241       pSiS->CPUFlags = SiSGetCPUFlags(pScrn);
4242       pSiS->CPUFlags |= SIS_CPUFL_FLAG;
4243#ifdef SISDUALHEAD
4244       if(pSiS->DualHeadMode) pSiSEnt->CPUFlags = pSiS->CPUFlags;
4245#endif
4246    }
4247
4248    /* We use a programamble clock */
4249    pScrn->progClock = TRUE;
4250
4251    /* Set the bits per RGB for 8bpp mode */
4252    if(pScrn->depth == 8) pScrn->rgbBits = 8;
4253
4254#ifdef SISDUALHEAD
4255    if(pSiS->DualHeadMode) {
4256       if(!pSiS->SecondHead) {
4257	  /* Copy some option settings to entity private */
4258	  pSiSEnt->HWCursor = pSiS->HWCursor;
4259	  pSiSEnt->NoAccel = pSiS->NoAccel;
4260	  pSiSEnt->useEXA = pSiS->useEXA;
4261	  pSiSEnt->restorebyset = pSiS->restorebyset;
4262	  pSiSEnt->OptROMUsage = pSiS->OptROMUsage;
4263	  pSiSEnt->OptUseOEM = pSiS->OptUseOEM;
4264	  pSiSEnt->TurboQueue = pSiS->TurboQueue;
4265	  pSiSEnt->forceCRT1 = pSiS->forceCRT1;
4266	  pSiSEnt->ForceCRT1Type = pSiS->ForceCRT1Type;
4267	  pSiSEnt->CRT1TypeForced = pSiS->CRT1TypeForced;
4268	  pSiSEnt->ForceCRT2Type = pSiS->ForceCRT2Type;
4269	  pSiSEnt->ForceTVType = pSiS->ForceTVType;
4270	  pSiSEnt->ForceYPbPrType = pSiS->ForceYPbPrType;
4271	  pSiSEnt->ForceYPbPrAR = pSiS->ForceYPbPrAR;
4272	  pSiSEnt->UsePanelScaler = pSiS->UsePanelScaler;
4273	  pSiSEnt->CenterLCD = pSiS->CenterLCD;
4274	  pSiSEnt->DSTN = pSiS->DSTN;
4275	  pSiSEnt->FSTN = pSiS->FSTN;
4276	  pSiSEnt->OptTVStand = pSiS->OptTVStand;
4277	  pSiSEnt->NonDefaultPAL = pSiS->NonDefaultPAL;
4278	  pSiSEnt->NonDefaultNTSC = pSiS->NonDefaultNTSC;
4279	  pSiSEnt->chtvtype = pSiS->chtvtype;
4280	  pSiSEnt->OptTVOver = pSiS->OptTVOver;
4281	  pSiSEnt->OptTVSOver = pSiS->OptTVSOver;
4282	  pSiSEnt->chtvlumabandwidthcvbs = pSiS->chtvlumabandwidthcvbs;
4283	  pSiSEnt->chtvlumabandwidthsvideo = pSiS->chtvlumabandwidthsvideo;
4284	  pSiSEnt->chtvlumaflickerfilter = pSiS->chtvlumaflickerfilter;
4285	  pSiSEnt->chtvchromabandwidth = pSiS->chtvchromabandwidth;
4286	  pSiSEnt->chtvchromaflickerfilter = pSiS->chtvchromaflickerfilter;
4287	  pSiSEnt->chtvtextenhance = pSiS->chtvtextenhance;
4288	  pSiSEnt->chtvcontrast = pSiS->chtvcontrast;
4289	  pSiSEnt->chtvcvbscolor = pSiS->chtvcvbscolor;
4290	  pSiSEnt->sistvedgeenhance = pSiS->sistvedgeenhance;
4291	  pSiSEnt->sistvantiflicker = pSiS->sistvantiflicker;
4292	  pSiSEnt->sistvsaturation = pSiS->sistvsaturation;
4293	  pSiSEnt->sistvcfilter = pSiS->sistvcfilter;
4294	  pSiSEnt->sistvyfilter = pSiS->sistvyfilter;
4295	  pSiSEnt->sistvcolcalibc = pSiS->sistvcolcalibc;
4296	  pSiSEnt->sistvcolcalibf = pSiS->sistvcolcalibf;
4297	  pSiSEnt->tvxpos = pSiS->tvxpos;
4298	  pSiSEnt->tvypos = pSiS->tvypos;
4299	  pSiSEnt->tvxscale = pSiS->tvxscale;
4300	  pSiSEnt->tvyscale = pSiS->tvyscale;
4301	  pSiSEnt->siscrt1satgain = pSiS->siscrt1satgain;
4302	  pSiSEnt->crt1satgaingiven = pSiS->crt1satgaingiven;
4303	  pSiSEnt->CRT1gamma = pSiS->CRT1gamma;
4304	  pSiSEnt->CRT1gammaGiven = pSiS->CRT1gammaGiven;
4305	  pSiSEnt->XvGammaRed = pSiS->XvGammaRed;
4306	  pSiSEnt->XvGammaGreen = pSiS->XvGammaGreen;
4307	  pSiSEnt->XvGammaBlue = pSiS->XvGammaBlue;
4308	  pSiSEnt->XvGamma = pSiS->XvGamma;
4309	  pSiSEnt->XvGammaGiven = pSiS->XvGammaGiven;
4310	  pSiSEnt->CRT2gamma = pSiS->CRT2gamma;
4311	  pSiSEnt->XvOnCRT2 = pSiS->XvOnCRT2;
4312	  pSiSEnt->AllowHotkey = pSiS->AllowHotkey;
4313	  pSiSEnt->enablesisctrl = pSiS->enablesisctrl;
4314	  pSiSEnt->SenseYPbPr = pSiS->SenseYPbPr;
4315	  pSiSEnt->XvUseMemcpy = pSiS->XvUseMemcpy;
4316	  pSiSEnt->BenchMemCpy = pSiS->BenchMemCpy;
4317#ifdef SIS_CP
4318	  SIS_CP_DRIVER_COPYOPTIONSENT
4319#endif
4320       } else {
4321	  /* We always use same cursor type on both screens */
4322	  pSiS->HWCursor = pSiSEnt->HWCursor;
4323	  /* We need identical NoAccel setting */
4324	  pSiS->NoAccel = pSiSEnt->NoAccel;
4325	  pSiS->useEXA = pSiSEnt->useEXA;
4326	  pSiS->TurboQueue = pSiSEnt->TurboQueue;
4327	  pSiS->restorebyset = pSiSEnt->restorebyset;
4328	  pSiS->AllowHotkey = pSiS->AllowHotkey;
4329	  pSiS->OptROMUsage = pSiSEnt->OptROMUsage;
4330	  pSiS->OptUseOEM = pSiSEnt->OptUseOEM;
4331	  pSiS->forceCRT1 = pSiSEnt->forceCRT1;
4332	  pSiS->nocrt2ddcdetection = FALSE;
4333	  pSiS->forcecrt2redetection = FALSE;
4334	  pSiS->ForceCRT1Type = pSiSEnt->ForceCRT1Type;
4335	  pSiS->ForceCRT2Type = pSiSEnt->ForceCRT2Type;
4336	  pSiS->CRT1TypeForced = pSiSEnt->CRT1TypeForced;
4337	  pSiS->UsePanelScaler = pSiSEnt->UsePanelScaler;
4338	  pSiS->CenterLCD = pSiSEnt->CenterLCD;
4339	  pSiS->DSTN = pSiSEnt->DSTN;
4340	  pSiS->FSTN = pSiSEnt->FSTN;
4341	  pSiS->OptTVStand = pSiSEnt->OptTVStand;
4342	  pSiS->NonDefaultPAL = pSiSEnt->NonDefaultPAL;
4343	  pSiS->NonDefaultNTSC = pSiSEnt->NonDefaultNTSC;
4344	  pSiS->chtvtype = pSiSEnt->chtvtype;
4345	  pSiS->ForceTVType = pSiSEnt->ForceTVType;
4346	  pSiS->ForceYPbPrType = pSiSEnt->ForceYPbPrType;
4347	  pSiS->ForceYPbPrAR = pSiSEnt->ForceYPbPrAR;
4348	  pSiS->OptTVOver = pSiSEnt->OptTVOver;
4349	  pSiS->OptTVSOver = pSiSEnt->OptTVSOver;
4350	  pSiS->chtvlumabandwidthcvbs = pSiSEnt->chtvlumabandwidthcvbs;
4351	  pSiS->chtvlumabandwidthsvideo = pSiSEnt->chtvlumabandwidthsvideo;
4352	  pSiS->chtvlumaflickerfilter = pSiSEnt->chtvlumaflickerfilter;
4353	  pSiS->chtvchromabandwidth = pSiSEnt->chtvchromabandwidth;
4354	  pSiS->chtvchromaflickerfilter = pSiSEnt->chtvchromaflickerfilter;
4355	  pSiS->chtvcvbscolor = pSiSEnt->chtvcvbscolor;
4356	  pSiS->chtvtextenhance = pSiSEnt->chtvtextenhance;
4357	  pSiS->chtvcontrast = pSiSEnt->chtvcontrast;
4358	  pSiS->sistvedgeenhance = pSiSEnt->sistvedgeenhance;
4359	  pSiS->sistvantiflicker = pSiSEnt->sistvantiflicker;
4360	  pSiS->sistvsaturation = pSiSEnt->sistvsaturation;
4361	  pSiS->sistvcfilter = pSiSEnt->sistvcfilter;
4362	  pSiS->sistvyfilter = pSiSEnt->sistvyfilter;
4363	  pSiS->sistvcolcalibc = pSiSEnt->sistvcolcalibc;
4364	  pSiS->sistvcolcalibf = pSiSEnt->sistvcolcalibf;
4365	  pSiS->tvxpos = pSiSEnt->tvxpos;
4366	  pSiS->tvypos = pSiSEnt->tvypos;
4367	  pSiS->tvxscale = pSiSEnt->tvxscale;
4368	  pSiS->tvyscale = pSiSEnt->tvyscale;
4369	  pSiS->SenseYPbPr = pSiSEnt->SenseYPbPr;
4370	  if(!pSiS->CRT1gammaGiven) {
4371	     if(pSiSEnt->CRT1gammaGiven)
4372	        pSiS->CRT1gamma = pSiSEnt->CRT1gamma;
4373	  }
4374	  pSiS->CRT2gamma = pSiSEnt->CRT2gamma;
4375	  if(!pSiS->XvGammaGiven) {
4376	     if(pSiSEnt->XvGammaGiven) {
4377		pSiS->XvGamma = pSiSEnt->XvGamma;
4378		pSiS->XvGammaRed = pSiS->XvGammaRedDef = pSiSEnt->XvGammaRed;
4379		pSiS->XvGammaGreen = pSiS->XvGammaGreenDef = pSiSEnt->XvGammaGreen;
4380		pSiS->XvGammaBlue = pSiS->XvGammaBlueDef = pSiSEnt->XvGammaBlue;
4381	     }
4382	  }
4383	  if(!pSiS->crt1satgaingiven) {
4384	     if(pSiSEnt->crt1satgaingiven)
4385	        pSiS->siscrt1satgain = pSiSEnt->siscrt1satgain;
4386	  }
4387	  pSiS->XvOnCRT2 = pSiSEnt->XvOnCRT2;
4388	  pSiS->enablesisctrl = pSiSEnt->enablesisctrl;
4389	  pSiS->XvUseMemcpy = pSiSEnt->XvUseMemcpy;
4390	  pSiS->BenchMemCpy = pSiSEnt->BenchMemCpy;
4391	  /* Copy gamma brightness to Ent (sic!) for Xinerama */
4392	  pSiSEnt->GammaBriR = pSiS->GammaBriR;
4393	  pSiSEnt->GammaBriG = pSiS->GammaBriG;
4394	  pSiSEnt->GammaBriB = pSiS->GammaBriB;
4395	  pSiSEnt->NewGammaBriR = pSiS->NewGammaBriR;
4396	  pSiSEnt->NewGammaBriG = pSiS->NewGammaBriG;
4397	  pSiSEnt->NewGammaBriB = pSiS->NewGammaBriB;
4398	  pSiSEnt->NewGammaConR = pSiS->NewGammaConR;
4399	  pSiSEnt->NewGammaConG = pSiS->NewGammaConG;
4400	  pSiSEnt->NewGammaConB = pSiS->NewGammaConB;
4401#ifdef SIS_CP
4402	  SIS_CP_DRIVER_COPYOPTIONS
4403#endif
4404       }
4405    }
4406#endif
4407
4408    /* Handle UseROMData, NoOEM and UsePanelScaler options */
4409    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
4410       from = X_PROBED;
4411       if(pSiS->OptROMUsage == 0) {
4412	  pSiS->SiS_Pr->UseROM = FALSE;
4413	  from = X_CONFIG;
4414	  xf86DrvMsg(pScrn->scrnIndex, from, "Video ROM data usage is disabled\n");
4415       }
4416
4417       if(!pSiS->OptUseOEM) {
4418	  xf86DrvMsg(pScrn->scrnIndex, from, "Internal OEM LCD/TV/VGA2 data usage is disabled\n");
4419       }
4420
4421       pSiS->SiS_Pr->UsePanelScaler = pSiS->UsePanelScaler;
4422       pSiS->SiS_Pr->CenterScreen = pSiS->CenterLCD;
4423    }
4424
4425    /* Do some HW configuration detection (memory amount & type, clock, etc) */
4426    SiSSetup(pScrn);
4427
4428    /* Get framebuffer address */
4429    if(pSiS->pEnt->device->MemBase != 0) {
4430       /*
4431	* XXX Should check that the config file value matches one of the
4432	* PCI base address values.
4433	*/
4434       pSiS->FbAddress = pSiS->pEnt->device->MemBase;
4435       from = X_CONFIG;
4436    } else {
4437       pSiS->FbAddress = PCI_REGION_BASE(pSiS->PciInfo, 0, REGION_MEM) & 0xFFFFFFF0;
4438       from = X_PROBED;
4439    }
4440
4441#ifdef SISDUALHEAD
4442    if(pSiS->DualHeadMode)
4443       xf86DrvMsg(pScrn->scrnIndex, from, "Global linear framebuffer at 0x%lX\n",
4444	   (ULong)pSiS->FbAddress);
4445    else
4446#endif
4447       xf86DrvMsg(pScrn->scrnIndex, from, "Linear framebuffer at 0x%lX\n",
4448	   (ULong)pSiS->FbAddress);
4449
4450    pSiS->realFbAddress = pSiS->FbAddress;
4451
4452    /* Get MMIO address */
4453    if(pSiS->pEnt->device->IOBase != 0) {
4454       /*
4455	* XXX Should check that the config file value matches one of the
4456	* PCI base address values.
4457	*/
4458       pSiS->IOAddress = pSiS->pEnt->device->IOBase;
4459       from = X_CONFIG;
4460    } else {
4461       pSiS->IOAddress = PCI_REGION_BASE(pSiS->PciInfo, 1, REGION_MEM) & 0xFFFFFFF0;
4462       from = X_PROBED;
4463    }
4464    xf86DrvMsg(pScrn->scrnIndex, from, "MMIO registers at 0x%lX (size %ldK)\n",
4465	   (ULong)pSiS->IOAddress, pSiS->mmioSize);
4466
4467#ifndef XSERVER_LIBPCIACCESS
4468    /* Register the PCI-assigned resources */
4469    if(xf86RegisterResources(pSiS->pEnt->index, NULL, ResExclusive)) {
4470       SISErrorLog(pScrn, "PCI resource conflicts detected\n");
4471#ifdef SISDUALHEAD
4472       if(pSiSEnt) pSiSEnt->ErrorAfterFirst = TRUE;
4473#endif
4474       sisRestoreExtRegisterLock(pSiS,srlockReg,crlockReg);
4475       if(pSiS->pInt) xf86FreeInt10(pSiS->pInt);
4476       SISFreeRec(pScrn);
4477       return FALSE;
4478    }
4479#endif
4480
4481    from = X_PROBED;
4482    if(pSiS->pEnt->device->videoRam != 0) {
4483       if(pSiS->Chipset == PCI_CHIP_SIS6326) {
4484	  pScrn->videoRam = pSiS->pEnt->device->videoRam;
4485	  from = X_CONFIG;
4486       } else {
4487	  xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
4488		"Option \"VideoRAM\" ignored\n");
4489       }
4490    }
4491
4492    pSiS->RealVideoRam = pScrn->videoRam;
4493
4494    if((pSiS->Chipset == PCI_CHIP_SIS6326) &&
4495       (pScrn->videoRam > 4096)            &&
4496       (from != X_CONFIG)) {
4497       pScrn->videoRam = 4096;
4498       xf86DrvMsg(pScrn->scrnIndex, from,
4499	   "SiS6326: Detected %d KB VideoRAM, limiting to %d KB\n",
4500	   pSiS->RealVideoRam, pScrn->videoRam);
4501    } else {
4502       xf86DrvMsg(pScrn->scrnIndex, from, "VideoRAM: %d KB\n", pScrn->videoRam);
4503    }
4504
4505    if((pSiS->Chipset == PCI_CHIP_SIS6326) &&
4506       (pScrn->videoRam > 4096)) {
4507       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
4508	   "SiS6326 engines do not support more than 4096KB RAM, therefore\n");
4509       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
4510	   "TurboQueue, HWCursor, 2D acceleration and XVideo are disabled.\n");
4511       pSiS->TurboQueue = FALSE;
4512       pSiS->HWCursor   = FALSE;
4513       pSiS->NoXvideo   = TRUE;
4514       pSiS->NoAccel    = TRUE;
4515    }
4516
4517    pSiS->FbMapSize = pSiS->availMem = pScrn->videoRam * 1024;
4518
4519    /* Calculate real availMem according to Accel/TurboQueue and
4520     * HWCursur setting. Also, initialize some variables used
4521     * in other modules.
4522     */
4523    pSiS->cursorOffset = 0;
4524    pSiS->CurARGBDest = NULL;
4525    pSiS->CurMonoSrc = NULL;
4526    pSiS->CurFGCol = pSiS->CurBGCol = 0;
4527    pSiS->FbBaseOffset = 0;
4528
4529    switch(pSiS->VGAEngine) {
4530
4531      case SIS_300_VGA:
4532	pSiS->TurboQueueLen = 512;
4533	if(pSiS->TurboQueue) {
4534	   pSiS->availMem -= (pSiS->TurboQueueLen*1024);
4535	   pSiS->cursorOffset = 512;
4536	}
4537	if(pSiS->HWCursor) {
4538	   pSiS->availMem -= pSiS->CursorSize;
4539	   if(pSiS->OptUseColorCursor) pSiS->availMem -= pSiS->CursorSize;
4540	}
4541	pSiS->CmdQueLenMask = 0xFFFF;
4542	pSiS->CmdQueLenFix  = 0;
4543	pSiS->cursorBufferNum = 0;
4544#ifdef SISDUALHEAD
4545	if(pSiSEnt) pSiSEnt->cursorBufferNum = 0;
4546#endif
4547	break;
4548
4549      case SIS_315_VGA:
4550#ifdef SISVRAMQ		/* VRAM queue */
4551	pSiS->cmdQueueSizeMask = pSiS->cmdQueueSize - 1;	/* VRAM Command Queue is variable (in therory) */
4552	pSiS->cmdQueueOffset = (pScrn->videoRam * 1024) - pSiS->cmdQueueSize;
4553	pSiS->cmdQueueLen = 0;
4554	pSiS->cmdQueueSize_div2 = pSiS->cmdQueueSize / 2;
4555	pSiS->cmdQueueSize_div4 = pSiS->cmdQueueSize / 4;
4556	pSiS->cmdQueueSize_4_3 = (pSiS->cmdQueueSize / 4) * 3;
4557	pSiS->availMem -= pSiS->cmdQueueSize;
4558	pSiS->cursorOffset = (pSiS->cmdQueueSize / 1024);
4559
4560	/* Set up shared pointer to current offset */
4561#ifdef SISDUALHEAD
4562	if(pSiS->DualHeadMode)
4563	   pSiS->cmdQ_SharedWritePort = &(pSiSEnt->cmdQ_SharedWritePort_2D);
4564	else
4565#endif
4566	   pSiS->cmdQ_SharedWritePort = &(pSiS->cmdQ_SharedWritePort_2D);
4567
4568
4569#else			/* MMIO */
4570	if(pSiS->TurboQueue) {
4571	   pSiS->availMem -= (512*1024);			/* MMIO Command Queue is 512k (variable in theory) */
4572	   pSiS->cursorOffset = 512;
4573	}
4574#endif
4575	if(pSiS->HWCursor) {
4576	   pSiS->availMem -= (pSiS->CursorSize * 2);
4577	   if(pSiS->OptUseColorCursor) pSiS->availMem -= (pSiS->CursorSize * 2);
4578	}
4579	pSiS->cursorBufferNum = 0;
4580#ifdef SISDUALHEAD
4581	if(pSiSEnt) pSiSEnt->cursorBufferNum = 0;
4582#endif
4583
4584	if((pSiS->SiS76xLFBSize) && (pSiS->SiS76xUMASize)) {
4585	   pSiS->availMem -= pSiS->SiS76xUMASize;
4586	   pSiS->FbBaseOffset = pSiS->SiS76xUMASize;
4587	}
4588
4589	break;
4590
4591      default:
4592	/* cursorOffset not used in cursor functions for 530 and
4593	 * older chips, because the cursor is *above* the TQ.
4594	 * On 5597 and older revisions of the 6326, the TQ is
4595	 * max 32K, on newer 6326 revisions and the 530 either 30
4596	 * (or 32?) or 62K (or 64?). However, to make sure, we
4597	 * use only 30K (or 32?), but reduce the available memory
4598	 * by 64, and locate the TQ at the beginning of this last
4599	 * 64K block. (We do this that way even when using the
4600	 * HWCursor, because the cursor only takes 2K and the
4601	 * queue does not seem to last that far anyway.)
4602	 * The TQ must be located at 32KB boundaries.
4603	 */
4604	if(pSiS->RealVideoRam < 3072) {
4605	   if(pSiS->TurboQueue) {
4606	      xf86DrvMsg(pScrn->scrnIndex, X_INFO,
4607		    "Not enough video RAM for TurboQueue. TurboQueue disabled\n");
4608	      pSiS->TurboQueue = FALSE;
4609	   }
4610	}
4611	pSiS->CmdQueMaxLen = 32;
4612	if(pSiS->TurboQueue) {
4613			      pSiS->availMem -= (64*1024);
4614			      pSiS->CmdQueMaxLen = 900;   /* To make sure; should be 992 */
4615	} else if(pSiS->HWCursor) {
4616			      pSiS->availMem -= pSiS->CursorSize;
4617	}
4618	if(pSiS->Chipset == PCI_CHIP_SIS530) {
4619		/* Check if Flat Panel is enabled */
4620		inSISIDXREG(SISSR, 0x0e, tempreg);
4621		if(!(tempreg & 0x04)) pSiS->availMem -= pSiS->CursorSize;
4622
4623		/* Set up mask for MMIO register */
4624		pSiS->CmdQueLenMask = (pSiS->TurboQueue) ? 0x1FFF : 0x00FF;
4625	} else {
4626	        /* TQ is never used on 6326/5597, because the accelerator
4627		 * always Syncs. So this is just cosmentic work. (And I
4628		 * am not even sure that 0x7fff is correct. MMIO 0x83a8
4629		 * holds 0xec0 if (30k) TQ is enabled, 0x20 if TQ disabled.
4630		 * The datasheet has no real explanation on the queue length
4631		 * if the TQ is enabled. Not syncing and waiting for a
4632		 * suitable queue length instead does not work.
4633		 */
4634	        pSiS->CmdQueLenMask = (pSiS->TurboQueue) ? 0x7FFF : 0x003F;
4635	}
4636
4637	/* This is to be subtracted from MMIO queue length register contents
4638	 * for getting the real Queue length.
4639	 */
4640	pSiS->CmdQueLenFix  = (pSiS->TurboQueue) ? 32 : 0;
4641    }
4642
4643
4644#ifdef SISDUALHEAD
4645    /* In dual head mode, we share availMem equally - so align it
4646     * to 8KB; this way, the address of the FB of the second
4647     * head is aligned to 4KB for mapping.
4648     */
4649   if(pSiS->DualHeadMode) pSiS->availMem &= 0xFFFFE000;
4650#endif
4651
4652    /* Check MaxXFBMem setting */
4653#ifdef SISDUALHEAD
4654    if(pSiS->DualHeadMode) {
4655        /* 1. Since DRI is not supported in dual head mode, we
4656	 *    don't need the MaxXFBMem setting - ignore it.
4657	 */
4658	if(pSiS->maxxfbmem) {
4659	   xf86DrvMsg(pScrn->scrnIndex, X_INFO,
4660		"MaxXFBMem ignored in Dual Head mode\n");
4661	}
4662	pSiS->maxxfbmem = pSiS->availMem;
4663    } else
4664#endif
4665	   if((pSiS->sisfbHeapStart) || (pSiS->sisfbHaveNewHeapDef)) {
4666
4667       /*
4668	* 2. We have memory layout info from sisfb - ignore MaxXFBMem
4669	*/
4670	if(pSiS->maxxfbmem) {
4671	   xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
4672		"Got memory layout info from sisfb, ignoring MaxXFBMem option\n");
4673	}
4674	if((pSiS->FbBaseOffset) && (!pSiS->sisfbHaveNewHeapDef)) {
4675	   xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
4676		"Incompatible sisfb version detected, DRI disabled\n");
4677	   pSiS->loadDRI = FALSE;
4678	   pSiS->maxxfbmem = pSiS->availMem;
4679	} else {
4680	   if(pSiS->FbBaseOffset) {
4681	      /* Revert our changes to FbBaseOffset and availMem; use sisfb's info */
4682	      pSiS->availMem += pSiS->FbBaseOffset;
4683	      pSiS->FbBaseOffset = 0;
4684	   }
4685	   if(pSiS->sisfbVideoOffset) {
4686	      /* a. DRI heap BELOW framebuffer */
4687	      pSiS->FbBaseOffset = pSiS->sisfbVideoOffset;
4688	      pSiS->availMem -= pSiS->FbBaseOffset;
4689	      pSiS->maxxfbmem = pSiS->availMem;
4690	   } else {
4691	      /* b. DRI heap ABOVE framebuffer (traditional layout) */
4692	      if(pSiS->availMem < (pSiS->sisfbHeapStart * 1024)) {
4693		 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
4694			"Internal error - sisfb memory layout corrupt\n");
4695		 pSiS->loadDRI = FALSE;
4696		 pSiS->maxxfbmem = pSiS->availMem;
4697	      } else {
4698	         pSiS->maxxfbmem = pSiS->sisfbHeapStart * 1024;
4699	      }
4700	   }
4701	}
4702
4703    } else if(pSiS->maxxfbmem) {
4704
4705       /*
4706	* 3. No sisfb, but user gave "MaxXFBMem"
4707	*/
4708	if(pSiS->FbBaseOffset) {
4709	   /* a. DRI heap BELOW framebuffer */
4710	   if(pSiS->maxxfbmem > (pSiS->availMem + pSiS->FbBaseOffset - pSiS->SiS76xUMASize)) {
4711	      xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
4712			"Invalid MaxXFBMem setting\n");
4713	      pSiS->maxxfbmem = pSiS->availMem;
4714	   } else {
4715	      /* Revert our changes */
4716	      pSiS->availMem += pSiS->FbBaseOffset;
4717	      /* Use user's MaxXFBMem setting */
4718	      pSiS->FbBaseOffset = pSiS->availMem - pSiS->maxxfbmem;
4719	      pSiS->availMem -= pSiS->FbBaseOffset;
4720	   }
4721	} else {
4722	   /* b. DRI heap ABOVE framebuffer (traditional layout) */
4723	   if(pSiS->maxxfbmem > pSiS->availMem) {
4724	      xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
4725			 "Invalid MaxXFBMem setting.\n");
4726	      pSiS->maxxfbmem = pSiS->availMem;
4727	   }
4728	}
4729
4730    } else {
4731
4732       /*
4733	* 4. No MaxXFBMem, no sisfb: Use all memory
4734	*/
4735	pSiS->maxxfbmem = pSiS->availMem;
4736
4737	/* ... except on chipsets, for which DRI is
4738	 * supported: If DRI is enabled, we now limit
4739	 * ourselves to a reasonable default:
4740	 */
4741
4742	if(pSiS->loadDRI) {
4743	   if(pSiS->FbBaseOffset) {
4744	      /* a. DRI heap BELOW framebuffer */
4745	      /* See how much UMA and LFB memory we have,
4746	       * and calculate a reasonable default. We
4747	       * use more vram for ourselves because these
4748	       * chips are eg. capable of larger Xv
4749	       * overlays, etc.
4750	       */
4751	      unsigned long total = (pSiS->SiS76xLFBSize + pSiS->SiS76xUMASize) / 1024;
4752	      unsigned long mymax;
4753	      if(total <= 16384)			/* <= 16MB: Use 8MB for X */
4754	         mymax = 8192 * 1024;
4755	      else if(total <= 32768)			/* <= 32MB: Use 16MB for X */
4756	         mymax = 16384 * 1024;
4757	      else					/* Otherwise: Use 20MB for X */
4758	         mymax = 20 * 1024 * 1024;
4759	      /* availMem is right now adjusted to not use the UMA
4760	       * area. Make sure that our default doesn't reach
4761	       * into the UMA area either.
4762	       */
4763	      if(pSiS->availMem > mymax) {
4764		 /* Write our default to maxxfbmem */
4765		 pSiS->maxxfbmem = mymax;
4766		 /* Revert our changes to availMem */
4767		 pSiS->availMem += pSiS->FbBaseOffset;
4768		 /* Use our default setting */
4769		 pSiS->FbBaseOffset = pSiS->availMem - pSiS->maxxfbmem;
4770		 pSiS->availMem -= pSiS->FbBaseOffset;
4771	      }
4772	   } else {
4773	      /* b. DRI heap ABOVE framebuffer (traditional layout) */
4774	      /* See how much video memory we have, and calculate
4775	       * a reasonable default.
4776	       * Since DRI is pointless with less than 4MB of total
4777	       * video RAM, we disable it in that case.
4778	       */
4779	      if(pScrn->videoRam <= 4096)
4780	         pSiS->loadDRI = FALSE;
4781	      else if(pScrn->videoRam <= 8192)		/* <= 8MB: Use 4MB for X */
4782	         pSiS->maxxfbmem = 4096 * 1024;
4783	      else if(pScrn->videoRam <= 16384)		/* <= 16MB: Use 8MB for X */
4784	         pSiS->maxxfbmem = 8192 * 1024;
4785#ifdef SISMERGED					/* Otherwise: --- */
4786	      else if(pSiS->MergedFB) {
4787	         if(pScrn->videoRam <= 65536)
4788	            pSiS->maxxfbmem = 16384 * 1024;	/* If MergedFB and <=64MB, use 16MB for X */
4789		 else
4790		    pSiS->maxxfbmem = 20 * 1024 * 1024;	/* If MergedFB and > 64MB, use 20MB for X */
4791	      }
4792#endif
4793	        else if(pSiS->VGAEngine == SIS_315_VGA) {
4794	         if(pScrn->videoRam <= 65536)
4795	            pSiS->maxxfbmem = 16384 * 1024;	/* On >=315 series and <=64MB, use 16MB */
4796		 else
4797		    pSiS->maxxfbmem = 20 * 1024 * 1024;	/* On >=315 series and > 64MB, use 20MB */
4798	      } else
4799	         pSiS->maxxfbmem = 12288 * 1024;	/* On <315 series, use 12MB */
4800
4801	      /* A final check */
4802	      if(pSiS->maxxfbmem > pSiS->availMem) {
4803		 pSiS->maxxfbmem = pSiS->availMem;
4804		 pSiS->loadDRI = FALSE;
4805	      }
4806	   }
4807
4808	}
4809    }
4810
4811    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using %dK of framebuffer memory at offset %dK\n",
4812				pSiS->maxxfbmem / 1024, pSiS->FbBaseOffset / 1024);
4813
4814    /* Find out about sub-classes of some chipsets and check
4815     * if the chipset supports two video overlays
4816     */
4817    if(pSiS->VGAEngine == SIS_300_VGA    ||
4818       pSiS->VGAEngine == SIS_315_VGA    ||
4819       pSiS->Chipset == PCI_CHIP_SIS530  ||
4820       pSiS->Chipset == PCI_CHIP_SIS6326 ||
4821       pSiS->Chipset == PCI_CHIP_SIS5597)  {
4822       pSiS->hasTwoOverlays = FALSE;
4823       switch(pSiS->Chipset) {
4824	 case PCI_CHIP_SIS300:
4825	 case PCI_CHIP_SIS540:  /* ? (If not, need to add the SwitchCRT Xv attribute!) */
4826	 case PCI_CHIP_SIS630:
4827	 case PCI_CHIP_SIS550:
4828	   pSiS->hasTwoOverlays = TRUE;
4829	   pSiS->SiS_SD_Flags |= SiS_SD_SUPPORT2OVL;
4830	   break;
4831	 case PCI_CHIP_SIS315PRO:
4832	   pSiS->ChipFlags |= SiSCF_LARGEOVERLAY;
4833	   break;
4834	 case PCI_CHIP_SIS330:
4835	   pSiS->ChipFlags |= (SiSCF_CRT2HWCKaputt | SiSCF_LARGEOVERLAY);
4836	   break;
4837	 case PCI_CHIP_SIS340:
4838	 case PCI_CHIP_XGIXG40: /* Verified: only 1 overlay */
4839	   pSiS->ChipFlags |= SiSCF_LARGEOVERLAY;
4840	   break;
4841	 case PCI_CHIP_SIS650:
4842	   {
4843	     UChar tempreg1, tempreg2;
4844	     static const char *id650str[] = {
4845		"650",       "650",       "650",       "650",
4846		"650 A0 AA", "650 A2 CA", "650",       "650",
4847		"M650 A0",   "M650 A1 AA","651 A0 AA", "651 A1 AA",
4848		"M650",      "65?",       "651",       "65?"
4849	     };
4850	     pSiS->ChipFlags |= SiSCF_LARGEOVERLAY;
4851	     if(pSiS->ChipType == SIS_650) {
4852		inSISIDXREG(SISCR, 0x5f, CR5F);
4853		CR5F &= 0xf0;
4854		andSISIDXREG(SISCR, 0x5c, 0x07);
4855		inSISIDXREG(SISCR, 0x5c, tempreg1);
4856		tempreg1 &= 0xf8;
4857		orSISIDXREG(SISCR, 0x5c, 0xf8);
4858		inSISIDXREG(SISCR, 0x5c, tempreg2);
4859		tempreg2 &= 0xf8;
4860		if((!tempreg1) || (tempreg2)) {
4861		   xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4862		      "SiS650 revision ID %x (%s)\n", CR5F, id650str[CR5F >> 4]);
4863		   if(CR5F & 0x80) {
4864		      pSiS->hasTwoOverlays = TRUE;  /* M650 or 651 */
4865		      pSiS->SiS_SD_Flags |= SiS_SD_SUPPORT2OVL;
4866		   }
4867		   switch(CR5F) {
4868		      case 0xa0:
4869		      case 0xb0:
4870		      case 0xe0:
4871		         pSiS->ChipFlags |= SiSCF_Is651;
4872		         break;
4873		      case 0x80:
4874		      case 0x90:
4875		      case 0xc0:
4876		         pSiS->ChipFlags |= SiSCF_IsM650;
4877		         break;
4878		   }
4879		} else {
4880		   pSiS->hasTwoOverlays = TRUE;
4881		   pSiS->SiS_SD_Flags |= SiS_SD_SUPPORT2OVL;
4882		   switch(CR5F) {
4883		      case 0x90:
4884			 inSISIDXREG(SISCR, 0x5c, tempreg1);
4885			 tempreg1 &= 0xf8;
4886			 switch(tempreg1) {
4887			    case 0x00:
4888			       pSiS->ChipFlags |= SiSCF_IsM652;
4889			       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4890			           "SiSM652 revision ID %x\n", CR5F);
4891			       break;
4892			    case 0x40:
4893			       pSiS->ChipFlags |= SiSCF_IsM653;
4894			       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4895			           "SiSM653 revision ID %x\n", CR5F);
4896			       break;
4897			    default:
4898			       pSiS->ChipFlags |= SiSCF_IsM650;
4899			       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4900			           "SiSM650 revision ID %x\n", CR5F);
4901			       break;
4902			 }
4903			 break;
4904		      case 0xb0:
4905			 pSiS->ChipFlags |= SiSCF_Is652;
4906			 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4907			     "SiS652 revision ID %x\n", CR5F);
4908			 break;
4909		      default:
4910			 pSiS->ChipFlags |= SiSCF_IsM650;
4911			 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4912			     "SiSM650 revision ID %x\n", CR5F);
4913			 break;
4914		   }
4915		}
4916	     }
4917	     break;
4918	   }
4919	 case PCI_CHIP_SIS660:
4920	   {
4921	     pSiS->ChipFlags |= SiSCF_LARGEOVERLAY;
4922	     pSiS->hasTwoOverlays = TRUE;
4923	     pSiS->SiS_SD_Flags |= SiS_SD_SUPPORT2OVL;
4924	     /* 760/761:  - UMA only: one/two overlays - dotclock dependent
4925			  - UMA+LFB:  two overlays if video data in LFB
4926			  - LFB only: two overlays
4927		If UMA only: Must switch between one/two overlays on the fly (done
4928			     in PostSetMode())
4929		If LFB+UMA:  We use LFB memory only and leave UMA to an eventually
4930			     written DRI driver.
4931	      */
4932	     break;
4933	   }
4934       }
4935
4936       if(!(pSiS->SiS_SD2_Flags & SiS_SD2_NOOVERLAY)) {
4937          xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4938		"Hardware supports %s video overlay%s\n",
4939		pSiS->hasTwoOverlays ? "two" : "one",
4940		pSiS->hasTwoOverlays ? "s" : "");
4941       }
4942
4943       if(pSiS->SiS_SD2_Flags & SiS_SD2_SUPPORT760OO) {
4944	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
4945		"\n\tDear SiS76x user, your machine is using a shared memory framebuffer.\n"
4946		  "\tDue to hardware limitations of the SiS chip in combination with the\n"
4947		  "\tAMD CPU, video overlay support is very limited on this machine. If you\n"
4948		  "\texperience flashing lines in the video and/or the graphics display\n"
4949		  "\tduring video playback, reduce the color depth and/or the resolution\n"
4950		  "\tand/or the refresh rate. Alternatively, use the video blitter.\n");
4951       }
4952
4953    }
4954
4955    /* Backup VB connection and CRT1 on/off register */
4956    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
4957       inSISIDXREG(SISSR, 0x1f, pSiS->oldSR1F);
4958       inSISIDXREG(SISCR, 0x17, pSiS->oldCR17);
4959       inSISIDXREG(SISCR, 0x32, pSiS->oldCR32);
4960       inSISIDXREG(SISCR, 0x36, pSiS->oldCR36);
4961       inSISIDXREG(SISCR, 0x37, pSiS->oldCR37);
4962       if(pSiS->VGAEngine == SIS_315_VGA) {
4963          inSISIDXREG(SISCR, pSiS->myCR63, pSiS->oldCR63);
4964       }
4965
4966       pSiS->postVBCR32 = pSiS->oldCR32;
4967    }
4968
4969    /* There are some machines out there which require a special
4970     * setup of the GPIO registers in order to make the Chrontel
4971     * work. Try to find out if we're running on such a machine.
4972     * Furthermore, there is some highly customized hardware,
4973     * which requires some non-standard LVDS timing. Since the
4974     * vendors don't seem to care about PCI subsystem ID's we
4975     * need to find out using the BIOS version and date strings.
4976     */
4977    pSiS->SiS_Pr->SiS_ChSW = FALSE;
4978    if(pSiS->Chipset == PCI_CHIP_SIS630) {
4979       int i = 0;
4980       do {
4981	  if(mychswtable[i].subsysVendor == PCI_SUB_VENDOR_ID(pSiS->PciInfo) &&
4982	     mychswtable[i].subsysCard == PCI_SUB_DEVICE_ID(pSiS->PciInfo)) {
4983	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
4984	         "PCI subsystem ID found in list for Chrontel/GPIO setup:\n");
4985	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4986		 "\tVendor/Card: %s %s (ID %04x)\n",
4987		  mychswtable[i].vendorName,
4988		  mychswtable[i].cardName,
4989		  PCI_SUB_DEVICE_ID(pSiS->PciInfo));
4990	     pSiS->SiS_Pr->SiS_ChSW = TRUE;
4991	     break;
4992          }
4993          i++;
4994       } while(mychswtable[i].subsysVendor != 0);
4995    }
4996
4997    if(pSiS->SiS_Pr->SiS_CustomT == CUT_NONE) {
4998       int    i = 0, j;
4999       UShort bversptr = 0;
5000       Bool   footprint;
5001       CARD32 chksum = 0;
5002
5003       if(pSiS->SiS_Pr->UseROM) {
5004          bversptr = pSiS->BIOS[0x16] | (pSiS->BIOS[0x17] << 8);
5005          for(i=0; i<32768; i++) chksum += pSiS->BIOS[i];
5006       }
5007
5008       i = 0;
5009       do {
5010	  if( (SiS_customttable[i].chipID == pSiS->ChipType)                            &&
5011	      ((!strlen(SiS_customttable[i].biosversion)) ||
5012	       (pSiS->SiS_Pr->UseROM &&
5013	       (!strncmp(SiS_customttable[i].biosversion, (char *)&pSiS->BIOS[bversptr],
5014	                strlen(SiS_customttable[i].biosversion)))))                     &&
5015	      ((!strlen(SiS_customttable[i].biosdate)) ||
5016	       (pSiS->SiS_Pr->UseROM &&
5017	       (!strncmp(SiS_customttable[i].biosdate, (char *)&pSiS->BIOS[0x2c],
5018	                strlen(SiS_customttable[i].biosdate)))))			      &&
5019	      ((!SiS_customttable[i].bioschksum) ||
5020	       (pSiS->SiS_Pr->UseROM &&
5021	       (SiS_customttable[i].bioschksum == chksum)))			      &&
5022	      (SiS_customttable[i].pcisubsysvendor == PCI_SUB_VENDOR_ID(pSiS->PciInfo))      &&
5023	      (SiS_customttable[i].pcisubsyscard == PCI_SUB_DEVICE_ID(pSiS->PciInfo)) ) {
5024	     footprint = TRUE;
5025	     for(j=0; j<5; j++) {
5026	        if(SiS_customttable[i].biosFootprintAddr[j]) {
5027		   if(pSiS->SiS_Pr->UseROM) {
5028		      if(pSiS->BIOS[SiS_customttable[i].biosFootprintAddr[j]] !=
5029						SiS_customttable[i].biosFootprintData[j])
5030		         footprint = FALSE;
5031		   } else footprint = FALSE;
5032	        }
5033	     }
5034	     if(footprint) {
5035	        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5036	           "Identified %s %s, special timing applies\n",
5037		   SiS_customttable[i].vendorName, SiS_customttable[i].cardName);
5038	        pSiS->SiS_Pr->SiS_CustomT = SiS_customttable[i].SpecialID;
5039	        break;
5040	     }
5041          }
5042          i++;
5043       } while(SiS_customttable[i].chipID);
5044    }
5045
5046    /* Handle ForceCRT1 option */
5047    if(pSiS->forceCRT1 != -1) {
5048       if(pSiS->forceCRT1) pSiS->CRT1off = 0;
5049       else                pSiS->CRT1off = 1;
5050    } else                 pSiS->CRT1off = -1;
5051
5052    /* Detect video bridge and sense TV/VGA2 */
5053    SISVGAPreInit(pScrn);
5054
5055    /* Detect CRT1 (via DDC1 and DDC2, hence via VGA port; regardless of LCDA) */
5056    SISCRT1PreInit(pScrn);
5057
5058    /* Detect LCD (connected via CRT2, regardless of LCDA) and LCD resolution */
5059    SISLCDPreInit(pScrn, FALSE);
5060
5061    /* LCDA only supported under these conditions: */
5062    if(pSiS->ForceCRT1Type == CRT1_LCDA) {
5063       if(!SISDetermineLCDACap(pScrn)) {
5064	  xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5065		"Chipset/Video bridge does not support LCD-via-CRT1\n");
5066	  pSiS->ForceCRT1Type = CRT1_VGA;
5067       } else if(!(pSiS->VBFlags & CRT2_LCD)) {
5068	  xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5069		"No digital LCD panel found, LCD-via-CRT1 disabled\n");
5070	  pSiS->ForceCRT1Type = CRT1_VGA;
5071       }
5072    }
5073
5074    /* Setup SD flags */
5075    pSiS->SiS_SD_Flags |= SiS_SD_ADDLSUPFLAG;
5076
5077    pSiS->SiS_SD2_Flags |= SiS_SD2_MERGEDUCLOCK;
5078    pSiS->SiS_SD2_Flags |= SiS_SD2_USEVBFLAGS2;
5079    pSiS->SiS_SD2_Flags |= SiS_SD2_VBINVB2ONLY;
5080    pSiS->SiS_SD2_Flags |= SiS_SD2_HAVESD34;
5081    pSiS->SiS_SD2_Flags |= SiS_SD2_NEWGAMMABRICON;
5082
5083    pSiS->SiS_SD3_Flags |= SiS_SD3_MFBALLOWOFFCL;
5084
5085    if(pSiS->VBFlags2 & VB2_VIDEOBRIDGE) {
5086       pSiS->SiS_SD2_Flags |= SiS_SD2_VIDEOBRIDGE;
5087       if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
5088	  pSiS->SiS_SD2_Flags |= ( SiS_SD2_SISBRIDGE     |
5089				   SiS_SD2_SUPPORTGAMMA2 );
5090	  if(pSiS->VBFlags2 & VB2_SISLVDSBRIDGE) {
5091	     pSiS->SiS_SD2_Flags |= ( SiS_SD2_LCDLVDS    |
5092				      SiS_SD2_SUPPORTLCD );
5093	  } else if(pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) {
5094	     if(!(pSiS->VBFlags2 & VB2_30xBDH)) {
5095		pSiS->SiS_SD2_Flags |= ( SiS_SD2_LCDTMDS    |
5096					 SiS_SD2_SUPPORTLCD );
5097	     } else if(pSiS->VBFlags & CRT2_LCD) {
5098		pSiS->SiS_SD2_Flags |= ( SiS_SD2_THIRDPARTYLVDS |
5099				         SiS_SD2_SUPPORTLCD );
5100	     }
5101	  }
5102       } else if(pSiS->VBFlags2 & VB2_LVDS) {
5103	  pSiS->SiS_SD2_Flags |= ( SiS_SD2_THIRDPARTYLVDS |
5104				   SiS_SD2_SUPPORTLCD );
5105       }
5106
5107       if(pSiS->VBFlags2 & (VB2_SISTVBRIDGE | VB2_CHRONTEL)) {
5108	  pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTTV;
5109	  if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
5110	     pSiS->SiS_SD2_Flags |= ( SiS_SD2_SUPPORTTVTYPE |
5111				      SiS_SD2_SUPPORTTVSIZE );
5112	     if(!(pSiS->VBFlags2 & VB2_301)) {
5113		pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPTVSAT;
5114	     } else {
5115		pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPTVEDGE;
5116	     }
5117	  }
5118       }
5119    }
5120
5121#ifdef ENABLE_YPBPR
5122    if((pSiS->VGAEngine == SIS_315_VGA) &&
5123       (pSiS->VBFlags2 & VB2_SISYPBPRBRIDGE)) {
5124       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTYPBPR;
5125       pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORT625I;
5126       pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORT625P;
5127       if(pSiS->VBFlags2 & VB2_SISYPBPRARBRIDGE) {
5128          pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTYPBPRAR;
5129       }
5130    }
5131    if(pSiS->VBFlags2 & VB2_SISHIVISIONBRIDGE) {
5132       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTHIVISION;
5133    }
5134#endif
5135
5136    if((pSiS->VGAEngine != SIS_300_VGA) || (!(pSiS->VBFlags2 & VB2_TRUMPION))) {
5137       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTSCALE;
5138       if((pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) &&
5139          (!(pSiS->VBFlags2 & VB2_30xBDH))) {
5140          pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTCENTER;
5141       }
5142    }
5143
5144#ifdef SISDUALHEAD
5145    if(!pSiS->DualHeadMode) {
5146       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTREDETECT;
5147    }
5148#endif
5149
5150#ifndef SISCHECKOSSSE
5151    pSiS->SiS_SD2_Flags |= SiS_SD2_NEEDUSESSE;
5152#endif
5153
5154#ifdef TWDEBUG	/* FOR TESTING */
5155    pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTYPBPRAR;
5156    xf86DrvMsg(0, X_INFO, "TEST: Support Aspect Ratio\n");
5157#endif
5158
5159    /* Detect CRT2-TV and PAL/NTSC mode */
5160    SISTVPreInit(pScrn, FALSE);
5161
5162    /* Detect CRT2-VGA */
5163    SISCRT2PreInit(pScrn, FALSE);
5164
5165    /* Backup detected CRT2 devices */
5166    SISSaveDetectedDevices(pScrn);
5167
5168    if(!(pSiS->SiS_SD_Flags & SiS_SD_SUPPORTYPBPR)) {
5169       if((pSiS->ForceTVType != -1) && (pSiS->ForceTVType & TV_YPBPR)) {
5170	  pSiS->ForceTVType = -1;
5171	  xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "YPbPr TV output not supported\n");
5172       }
5173    }
5174
5175    if(!(pSiS->SiS_SD_Flags & SiS_SD_SUPPORTHIVISION)) {
5176       if((pSiS->ForceTVType != -1) && (pSiS->ForceTVType & TV_HIVISION)) {
5177	  pSiS->ForceTVType = -1;
5178	  xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "HiVision TV output not supported\n");
5179       }
5180    }
5181
5182    if((pSiS->VBFlags2 & VB2_SISTVBRIDGE) ||
5183       ((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->ChrontelType == CHRONTEL_701x))) {
5184       pSiS->SiS_SD_Flags |= (SiS_SD_SUPPORTPALMN | SiS_SD_SUPPORTNTSCJ);
5185    }
5186    if((pSiS->VBFlags2 & VB2_SISTVBRIDGE) ||
5187       ((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->ChrontelType == CHRONTEL_700x))) {
5188       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTTVPOS;
5189    }
5190    if(pSiS->VBFlags2 & VB2_SISVGA2BRIDGE) {
5191       pSiS->SiS_SD_Flags |= (SiS_SD_SUPPORTSCART | SiS_SD_SUPPORTVGA2);
5192    }
5193    if(pSiS->VBFlags2 & VB2_CHRONTEL) {
5194       pSiS->SiS_SD_Flags  |= SiS_SD_SUPPORTOVERSCAN;
5195       pSiS->SiS_SD2_Flags |= SiS_SD2_CHRONTEL;
5196       if(pSiS->ChrontelType == CHRONTEL_700x) {
5197	  pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTSOVER;
5198       }
5199    }
5200
5201    /* Determine if chipset LCDA-capable */
5202    pSiS->SiS_SD_Flags &= ~SiS_SD_SUPPORTLCDA;
5203    if(SISDetermineLCDACap(pScrn)) {
5204       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTLCDA;
5205    }
5206
5207    /* Default to LCDA if LCD detected and
5208     * - TV detected (hence default to LCDA+TV), or
5209     * - in single head mode, on LCD panels with xres > 1600
5210     *   (Don't do this in MergedFB or DHM; LCDA and CRT1/VGA
5211     *   are mutually exclusive; if no TV is detected, the
5212     *   code below will default to VGA+LCD, so LCD is driven
5213     *   via CRT2.)
5214     *   (TODO: This might need some modification for the
5215     *   307 bridges, if these are capable of driving
5216     *   LCDs > 1600 via channel B)
5217     */
5218    if((pSiS->SiS_SD_Flags & SiS_SD_SUPPORTLCDA) &&
5219       (pSiS->VBFlags & CRT2_LCD) &&
5220       (pSiS->SiS_Pr->SiS_CustomT != CUT_UNKNOWNLCD)) {
5221       if((!pSiS->CRT1TypeForced) && (pSiS->ForceCRT2Type == CRT2_DEFAULT)) {
5222	  if(pSiS->VBFlags & CRT2_TV) {
5223	     /* If both LCD and TV present, default to LCDA+TV */
5224	     pSiS->ForceCRT1Type = CRT1_LCDA;
5225	     pSiS->ForceCRT2Type = CRT2_TV;
5226	  } else if(pSiS->LCDwidth > 1600) {
5227	     /* If LCD is > 1600, default to LCDA if we don't need CRT1/VGA for other head */
5228	     Bool NeedCRT1VGA = FALSE;
5229#ifdef SISDUALHEAD
5230	     if(pSiS->DualHeadMode) NeedCRT1VGA = TRUE;
5231#endif
5232#ifdef SISMERGED
5233	     if(pSiS->MergedFB &&
5234		(!pSiS->MergedFBAuto || pSiS->CRT1Detected)) NeedCRT1VGA = TRUE;
5235#endif
5236	     if(!NeedCRT1VGA) {
5237		pSiS->ForceCRT1Type = CRT1_LCDA;
5238	     }
5239	  }
5240       }
5241    }
5242
5243    /* Set up pseudo-panel if LCDA forced on TMDS bridges */
5244    if(pSiS->SiS_SD_Flags & SiS_SD_SUPPORTLCDA) {
5245       if(pSiS->ForceCRT1Type == CRT1_LCDA) {
5246          if(pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE) {
5247	     if(!(pSiS->VBLCDFlags)) {
5248		SiSSetupPseudoPanel(pScrn);
5249		pSiS->detectedCRT2Devices |= CRT2_LCD;
5250	     }
5251	  } else if(!(pSiS->VBLCDFlags)) {
5252	     pSiS->ForceCRT1Type = CRT1_VGA;
5253	  }
5254       }
5255    } else {
5256       pSiS->ForceCRT1Type = CRT1_VGA;
5257    }
5258
5259    pSiS->VBFlags |= pSiS->ForceCRT1Type;
5260
5261#ifdef TWDEBUG
5262    xf86DrvMsg(0, X_INFO, "SDFlags %lx\n", pSiS->SiS_SD_Flags);
5263#endif
5264
5265    /* Eventually overrule detected CRT2 type
5266     * If no type forced, use the detected devices in the order TV->LCD->VGA2
5267     * Since the Chrontel 7005 sometimes delivers wrong detection results,
5268     * we use a different order on such machines (LCD->TV)
5269     */
5270    if(pSiS->ForceCRT2Type == CRT2_DEFAULT) {
5271       if((pSiS->VBFlags & CRT2_TV) && (!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VGAEngine == SIS_300_VGA))))
5272	  pSiS->ForceCRT2Type = CRT2_TV;
5273       else if((pSiS->VBFlags & CRT2_LCD) && (pSiS->ForceCRT1Type == CRT1_VGA))
5274	  pSiS->ForceCRT2Type = CRT2_LCD;
5275       else if(pSiS->VBFlags & CRT2_TV)
5276	  pSiS->ForceCRT2Type = CRT2_TV;
5277       else if((pSiS->VBFlags & CRT2_VGA) && (pSiS->ForceCRT1Type == CRT1_VGA))
5278	  pSiS->ForceCRT2Type = CRT2_VGA;
5279    }
5280
5281    switch(pSiS->ForceCRT2Type) {
5282       case CRT2_TV:
5283	  pSiS->VBFlags &= ~(CRT2_LCD | CRT2_VGA);
5284	  if(pSiS->VBFlags2 & (VB2_SISTVBRIDGE | VB2_CHRONTEL)) {
5285	     pSiS->VBFlags |= CRT2_TV;
5286	  } else {
5287	     pSiS->VBFlags &= ~(CRT2_TV);
5288	     xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
5289		"Hardware does not support TV output\n");
5290	  }
5291	  break;
5292       case CRT2_LCD:
5293	  pSiS->VBFlags &= ~(CRT2_TV | CRT2_VGA);
5294	  if((pSiS->VBFlags2 & VB2_VIDEOBRIDGE) && (pSiS->VBLCDFlags)) {
5295	     pSiS->VBFlags |= CRT2_LCD;
5296	  } else if((pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) && (!(pSiS->VBFlags2 & VB2_30xBDH))) {
5297	     SiSSetupPseudoPanel(pScrn);
5298	     pSiS->detectedCRT2Devices |= CRT2_LCD;
5299	  } else {
5300	     pSiS->VBFlags &= ~(CRT2_LCD);
5301	     xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
5302		"Can't force CRT2 to LCD, no LCD detected\n");
5303	  }
5304	  break;
5305       case CRT2_VGA:
5306	  pSiS->VBFlags &= ~(CRT2_TV | CRT2_LCD);
5307	  if(pSiS->VBFlags2 & VB2_SISVGA2BRIDGE) {
5308	     pSiS->VBFlags |= CRT2_VGA;
5309	  } else {
5310	     pSiS->VBFlags &= ~(CRT2_VGA);
5311	     xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
5312		 "Hardware does not support secondary VGA\n");
5313	  }
5314	  break;
5315       default:
5316	  pSiS->VBFlags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
5317    }
5318
5319    /* Setup gamma (the cmap layer needs this to be initialised) */
5320    /* (Do this after evaluating options) */
5321    {
5322       Gamma zeros = {0.0, 0.0, 0.0};
5323       xf86SetGamma(pScrn, zeros);
5324    }
5325
5326#ifdef SISDUALHEAD
5327    if((!pSiS->DualHeadMode) || (pSiS->SecondHead)) {
5328#endif
5329       xf86DrvMsg(pScrn->scrnIndex, pSiS->CRT1gammaGiven ? X_CONFIG : X_INFO,
5330	     "%samma correction is %s\n",
5331	     (pSiS->VBFlags2 & VB2_VIDEOBRIDGE) ? "CRT1 g" : "G",
5332	     pSiS->CRT1gamma ? "enabled" : "disabled");
5333
5334       if((pSiS->VGAEngine == SIS_315_VGA)	&&
5335          (!(pSiS->NoXvideo))			&&
5336	  (!(pSiS->SiS_SD2_Flags & SiS_SD2_NOOVERLAY))) {
5337	  xf86DrvMsg(pScrn->scrnIndex, pSiS->XvGammaGiven ? X_CONFIG : X_INFO,
5338		"Separate Xv gamma correction %sis %s\n",
5339		(pSiS->VBFlags2 & VB2_VIDEOBRIDGE) ? "for CRT1 " : "",
5340		pSiS->XvGamma ? "enabled" : "disabled");
5341	  if(pSiS->XvGamma) {
5342	     xf86DrvMsg(pScrn->scrnIndex, pSiS->XvGammaGiven ? X_CONFIG : X_INFO,
5343		"Xv gamma correction: %.3f %.3f %.3f\n",
5344		(float)((float)pSiS->XvGammaRed / 1000),
5345		(float)((float)pSiS->XvGammaGreen / 1000),
5346		(float)((float)pSiS->XvGammaBlue / 1000));
5347	     if(!pSiS->CRT1gamma) {
5348		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5349		   "Xv gamma correction requires %samma correction enabled\n",
5350		   (pSiS->VBFlags2 & VB2_VIDEOBRIDGE) ? "CRT1 g" : "G");
5351	     }
5352	  }
5353       }
5354#ifdef SISDUALHEAD
5355    }
5356#endif
5357
5358#ifdef SISDUALHEAD
5359    if(pSiS->DualHeadMode) pSiS->CRT2SepGamma = FALSE;
5360#endif
5361
5362#ifdef SISDUALHEAD
5363    if((!pSiS->DualHeadMode) || (!pSiS->SecondHead))
5364#endif
5365    {
5366       Bool isDH = FALSE;
5367       if(pSiS->CRT2gamma) {
5368          if( ((pSiS->VGAEngine != SIS_300_VGA) && (pSiS->VGAEngine != SIS_315_VGA)) ||
5369              (!(pSiS->VBFlags2 & VB2_SISBRIDGE)) ) {
5370	     if(pSiS->VBFlags2 & VB2_VIDEOBRIDGE) {
5371	        xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5372			"CRT2 gamma correction not supported by hardware\n");
5373	     }
5374	     pSiS->CRT2gamma = pSiS->CRT2SepGamma = FALSE;
5375          } else if((pSiS->VBFlags2 & VB2_30xBDH) && (pSiS->VBFlags & CRT2_LCD)) {
5376	     isDH = TRUE;
5377	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5378			"CRT2 gamma correction not supported for LCD\n");
5379	     /* But leave it on, will be caught in LoadPalette */
5380          }
5381       }
5382       if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
5383	  xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CRT2 gamma correction is %s%s%s\n",
5384		pSiS->CRT2gamma ? "enabled" : "disabled",
5385		isDH ? " (for TV and VGA2) " : "",
5386		pSiS->CRT2SepGamma ? " (separate from CRT1)" : "");
5387       }
5388    }
5389
5390    /* Eventually overrule TV Type (SVIDEO, COMPOSITE, SCART, HIVISION, YPBPR) */
5391    if(pSiS->VBFlags2 & VB2_SISTVBRIDGE) {
5392       if(pSiS->ForceTVType != -1) {
5393	  pSiS->VBFlags &= ~(TV_INTERFACE);
5394	  if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) {
5395	     pSiS->VBFlags &= ~(TV_CHSCART | TV_CHYPBPR525I);
5396	  }
5397	  pSiS->VBFlags |= pSiS->ForceTVType;
5398	  if(pSiS->VBFlags & TV_YPBPR) {
5399	     pSiS->VBFlags &= ~(TV_STANDARD);
5400	     pSiS->VBFlags &= ~(TV_YPBPRAR);
5401	     pSiS->VBFlags |= pSiS->ForceYPbPrType;
5402	     pSiS->VBFlags |= pSiS->ForceYPbPrAR;
5403	  }
5404       }
5405    }
5406
5407    /* Handle ForceCRT1 option (part 2) */
5408    pSiS->CRT1changed = FALSE;
5409    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
5410       usScratchCR17 = pSiS->oldCR17;
5411       usScratchCR63 = pSiS->oldCR63;
5412       usScratchSR1F = pSiS->oldSR1F;
5413       usScratchCR32 = pSiS->postVBCR32;
5414       if(pSiS->VESA != 1) {
5415          /* Copy forceCRT1 option to CRT1off if option is given */
5416#ifdef SISDUALHEAD
5417          /* In DHM, handle this option only for master head, not the slave */
5418          if( (pSiS->forceCRT1 != -1) &&
5419	       (!(pSiS->DualHeadMode && pSiS->SecondHead)) ) {
5420#else
5421          if(pSiS->forceCRT1 != -1) {
5422#endif
5423	     xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
5424		 "CRT1 detection overruled by ForceCRT1 option\n");
5425	     if(pSiS->forceCRT1) {
5426		 pSiS->CRT1off = 0;
5427		 if(pSiS->VGAEngine == SIS_300_VGA) {
5428		    if(!(usScratchCR17 & 0x80)) pSiS->CRT1changed = TRUE;
5429		 } else {
5430		    if(usScratchCR63 & 0x40) pSiS->CRT1changed = TRUE;
5431		 }
5432		 usScratchCR17 |= 0x80;
5433		 usScratchCR32 |= 0x20;
5434		 usScratchCR63 &= ~0x40;
5435		 usScratchSR1F &= ~0xc0;
5436	     } else {
5437		 if( ! ( (pScrn->bitsPerPixel == 8) &&
5438		         ( (pSiS->VBFlags2 & (VB2_LVDS | VB2_CHRONTEL)) ||
5439		           ((pSiS->VBFlags2 & VB2_30xBDH) && (pSiS->VBFlags & CRT2_LCD)) ) ) ) {
5440		    pSiS->CRT1off = 1;
5441		    if(pSiS->VGAEngine == SIS_300_VGA) {
5442		       if(usScratchCR17 & 0x80) pSiS->CRT1changed = TRUE;
5443		    } else {
5444		       if(!(usScratchCR63 & 0x40)) pSiS->CRT1changed = TRUE;
5445		    }
5446		    usScratchCR32 &= ~0x20;
5447		    /* We must not actually switch off CRT1 before we changed the mode! */
5448		 }
5449	     }
5450	     /* Here we can write to CR17 even on 315 series as we only ENABLE
5451	      * the bit here
5452	      */
5453	     outSISIDXREG(SISCR, 0x17, usScratchCR17);
5454	     if(pSiS->VGAEngine == SIS_315_VGA) {
5455		outSISIDXREG(SISCR, pSiS->myCR63, usScratchCR63);
5456	     }
5457	     outSISIDXREG(SISCR, 0x32, usScratchCR32);
5458	     if(pSiS->CRT1changed) {
5459		outSISIDXREG(SISSR, 0x00, 0x01);    /* Synchronous Reset */
5460		usleep(10000);
5461		outSISIDXREG(SISSR, 0x00, 0x03);    /* End Reset */
5462		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5463			"CRT1 status changed by ForceCRT1 option\n");
5464	     }
5465	     outSISIDXREG(SISSR, 0x1f, usScratchSR1F);
5466          }
5467       }
5468       /* Store the new VB connection register contents for later mode changes */
5469       pSiS->newCR32 = usScratchCR32;
5470    }
5471
5472    /* Check if CRT1 used (or needed; this eg. if no CRT2 detected) */
5473    if(pSiS->VBFlags2 & VB2_VIDEOBRIDGE) {
5474
5475        /* No CRT2 output? Then we NEED CRT1!
5476	 * We also need CRT1 if depth = 8 and bridge=LVDS|301B-DH
5477	 */
5478	if( (!(pSiS->VBFlags & (CRT2_VGA | CRT2_LCD | CRT2_TV))) ||
5479	    ( (pScrn->bitsPerPixel == 8) &&
5480	      ( (pSiS->VBFlags2 & (VB2_LVDS | VB2_CHRONTEL)) ||
5481	        ((pSiS->VBFlags2 & VB2_30xBDH) && (pSiS->VBFlags & CRT2_LCD)) ) ) ) {
5482	    pSiS->CRT1off = 0;
5483	}
5484	/* No CRT2 output? Then we can't use Xv on CRT2 */
5485	if(!(pSiS->VBFlags & (CRT2_VGA | CRT2_LCD | CRT2_TV))) {
5486	    pSiS->XvOnCRT2 = FALSE;
5487	}
5488
5489    } else { /* no video bridge? */
5490	/* Then we NEED CRT1... */
5491	pSiS->CRT1off = 0;
5492	/* ... and can't use CRT2 for Xv output */
5493	pSiS->XvOnCRT2 = FALSE;
5494    }
5495
5496    /* LCDA? Then we don't switch off CRT1 */
5497    if(pSiS->VBFlags & CRT1_LCDA) pSiS->CRT1off = 0;
5498
5499    /* Handle TVStandard option */
5500    if((pSiS->NonDefaultPAL != -1) || (pSiS->NonDefaultNTSC != -1)) {
5501       if( (!(pSiS->VBFlags2 & VB2_SISTVBRIDGE)) &&
5502	   (!((pSiS->VBFlags2 & VB2_CHRONTEL)) && (pSiS->ChrontelType == CHRONTEL_701x)) ) {
5503	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5504	   	"PALM, PALN and NTSCJ not supported on this hardware\n");
5505	  pSiS->NonDefaultPAL = pSiS->NonDefaultNTSC = -1;
5506	  pSiS->VBFlags &= ~(TV_PALN | TV_PALM | TV_NTSCJ);
5507	  pSiS->SiS_SD_Flags &= ~(SiS_SD_SUPPORTPALMN | SiS_SD_SUPPORTNTSCJ);
5508       }
5509    }
5510    if(pSiS->OptTVStand != -1) {
5511       if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
5512	  if( (!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & (TV_CHSCART | TV_CHYPBPR525I)))) &&
5513	      (!(pSiS->VBFlags & (TV_HIVISION | TV_YPBPR))) ) {
5514	     pSiS->VBFlags &= ~(TV_PAL | TV_NTSC | TV_PALN | TV_PALM | TV_NTSCJ);
5515	     if(pSiS->OptTVStand) {
5516	        pSiS->VBFlags |= TV_PAL;
5517	        if(pSiS->NonDefaultPAL == 1)  pSiS->VBFlags |= TV_PALM;
5518	        else if(!pSiS->NonDefaultPAL) pSiS->VBFlags |= TV_PALN;
5519	     } else {
5520	        pSiS->VBFlags |= TV_NTSC;
5521		if(pSiS->NonDefaultNTSC == 1) pSiS->VBFlags |= TV_NTSCJ;
5522	     }
5523	  } else {
5524	     pSiS->OptTVStand = pSiS->NonDefaultPAL = -1;
5525	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5526	    	 "Option TVStandard ignored for YPbPr, HiVision and Chrontel-SCART\n");
5527	  }
5528       } else if(pSiS->Chipset == PCI_CHIP_SIS6326) {
5529	  pSiS->SiS6326Flags &= ~SIS6326_TVPAL;
5530	  if(pSiS->OptTVStand) pSiS->SiS6326Flags |= SIS6326_TVPAL;
5531       }
5532    }
5533
5534    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
5535       /* Default to PAL */
5536       if(pSiS->VBFlags & (TV_SVIDEO | TV_AVIDEO)) {
5537          if(!(pSiS->VBFlags & (TV_PAL | TV_NTSC))) {
5538	     pSiS->VBFlags &= ~(TV_PAL | TV_NTSC | TV_PALN | TV_PALM | TV_NTSCJ);
5539	     pSiS->VBFlags |= TV_PAL;
5540	  }
5541       }
5542       /* SCART only supported for PAL */
5543       if((pSiS->VBFlags2 & VB2_SISBRIDGE) && (pSiS->VBFlags & TV_SCART)) {
5544	  pSiS->VBFlags &= ~(TV_NTSC | TV_PALN | TV_PALM | TV_NTSCJ);
5545	  pSiS->VBFlags |= TV_PAL;
5546	  pSiS->OptTVStand = 1;
5547	  pSiS->NonDefaultPAL = pSiS->NonDefaultNTSC = -1;
5548       }
5549    }
5550
5551#ifdef SIS_CP
5552    SIS_CP_DRIVER_RECONFIGOPT
5553#endif
5554
5555    if((pSiS->Chipset == PCI_CHIP_SIS6326) && (pSiS->SiS6326Flags & SIS6326_HASTV)) {
5556       if(pSiS->sis6326tvplug != -1) {
5557          pSiS->SiS6326Flags &= ~(SIS6326_TVSVIDEO | SIS6326_TVCVBS);
5558	  pSiS->SiS6326Flags |= SIS6326_TVDETECTED;
5559	  if(pSiS->sis6326tvplug == 1) 	pSiS->SiS6326Flags |= SIS6326_TVCVBS;
5560	  else 				pSiS->SiS6326Flags |= SIS6326_TVSVIDEO;
5561	  xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
5562	      "SiS6326 TV plug type detection overruled by %s\n",
5563	      (pSiS->SiS6326Flags & SIS6326_TVCVBS) ? "COMPOSITE" : "SVIDEO");
5564       }
5565    }
5566
5567    /* Do some checks */
5568    if(pSiS->OptTVOver != -1) {
5569       if(pSiS->VBFlags2 & VB2_CHRONTEL) {
5570	  pSiS->UseCHOverScan = pSiS->OptTVOver;
5571       } else {
5572	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5573	      "CHTVOverscan only supported on CHRONTEL 70xx\n");
5574	  pSiS->UseCHOverScan = -1;
5575       }
5576    } else pSiS->UseCHOverScan = -1;
5577
5578    if(pSiS->sistvedgeenhance != -1) {
5579       if(!(pSiS->VBFlags2 & VB2_301)) {
5580	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5581	      "SISTVEdgeEnhance only supported on SiS301\n");
5582	  pSiS->sistvedgeenhance = -1;
5583       }
5584    }
5585    if(pSiS->sistvsaturation != -1) {
5586       if(pSiS->VBFlags2 & VB2_301) {
5587	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5588	      "SISTVSaturation not supported on SiS301\n");
5589	  pSiS->sistvsaturation = -1;
5590       }
5591    }
5592
5593    /* Do some MergedFB mode initialisation */
5594#ifdef SISMERGED
5595    if(pSiS->MergedFB) {
5596       pSiS->CRT2pScrn = malloc(sizeof(ScrnInfoRec));
5597       if(!pSiS->CRT2pScrn) {
5598          SISErrorLog(pScrn, "Failed to allocate memory for 2nd pScrn, %s\n", mergeddisstr);
5599	  pSiS->MergedFB = FALSE;
5600       } else {
5601          memcpy(pSiS->CRT2pScrn, pScrn, sizeof(ScrnInfoRec));
5602       }
5603    }
5604#endif
5605
5606    /* Determine CRT1<>CRT2 mode
5607     *     Note: When using VESA or if the bridge is in slavemode, display
5608     *           is ALWAYS in MIRROR_MODE!
5609     *           This requires extra checks in functions using this flag!
5610     *           (see sis_video.c for example)
5611     */
5612    if(pSiS->VBFlags & DISPTYPE_DISP2) {
5613        if(pSiS->CRT1off) {	/* CRT2 only ------------------------------- */
5614#ifdef SISDUALHEAD
5615	     if(pSiS->DualHeadMode) {
5616		SISErrorLog(pScrn,
5617		    "CRT1 not detected or forced off. Dual Head mode can't initialize.\n");
5618		if(pSiSEnt) pSiSEnt->DisableDual = TRUE;
5619		goto my_error_1;
5620	     }
5621#endif
5622#ifdef SISMERGED
5623	     if(pSiS->MergedFB) {
5624		if(pSiS->MergedFBAuto) {
5625		   xf86DrvMsg(pScrn->scrnIndex, X_INFO, mergednocrt1, mergeddisstr);
5626		} else {
5627		   SISErrorLog(pScrn, mergednocrt1, mergeddisstr);
5628		}
5629		if(pSiS->CRT2pScrn) free(pSiS->CRT2pScrn);
5630		pSiS->CRT2pScrn = NULL;
5631		pSiS->MergedFB = FALSE;
5632	     }
5633#endif
5634	     pSiS->VBFlags |= VB_DISPMODE_SINGLE;
5635	     /* No CRT1? Then we use the video overlay on CRT2 */
5636	     pSiS->XvOnCRT2 = TRUE;
5637	} else			/* CRT1 and CRT2 - mirror or dual head ----- */
5638#ifdef SISDUALHEAD
5639	     if(pSiS->DualHeadMode) {
5640		pSiS->VBFlags |= (VB_DISPMODE_DUAL | DISPTYPE_CRT1);
5641		if(pSiS->VESA != -1) {
5642		    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5643			"VESA option not used in Dual Head mode. VESA disabled.\n");
5644		}
5645		if(pSiSEnt) pSiSEnt->DisableDual = FALSE;
5646		pSiS->VESA = 0;
5647	     } else
5648#endif
5649#ifdef SISMERGED
5650		    if(pSiS->MergedFB) {
5651		 pSiS->VBFlags |= (VB_DISPMODE_MIRROR | DISPTYPE_CRT1);
5652		 if(pSiS->VESA != -1) {
5653		    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5654			"VESA option not used in MergedFB mode. VESA disabled.\n");
5655		 }
5656		 pSiS->VESA = 0;
5657	     } else
5658#endif
5659		 pSiS->VBFlags |= (VB_DISPMODE_MIRROR | DISPTYPE_CRT1);
5660    } else {			/* CRT1 only ------------------------------- */
5661#ifdef SISDUALHEAD
5662	     if(pSiS->DualHeadMode) {
5663		SISErrorLog(pScrn,
5664		   "No CRT2 output selected or no bridge detected. "
5665		   "Dual Head mode can't initialize.\n");
5666		goto my_error_1;
5667	     }
5668#endif
5669#ifdef SISMERGED
5670	     if(pSiS->MergedFB) {
5671		if(pSiS->MergedFBAuto) {
5672		   xf86DrvMsg(pScrn->scrnIndex, X_INFO, mergednocrt2, mergeddisstr);
5673		} else {
5674		   SISErrorLog(pScrn, mergednocrt2, mergeddisstr);
5675		}
5676		if(pSiS->CRT2pScrn) free(pSiS->CRT2pScrn);
5677		pSiS->CRT2pScrn = NULL;
5678		pSiS->MergedFB = FALSE;
5679	     }
5680#endif
5681             pSiS->VBFlags |= (VB_DISPMODE_SINGLE | DISPTYPE_CRT1);
5682    }
5683
5684    if((pSiS->VGAEngine == SIS_315_VGA) || (pSiS->VGAEngine == SIS_300_VGA)) {
5685       if((!pSiS->NoXvideo)		&&
5686          (!pSiS->hasTwoOverlays)	&&
5687	  (!(pSiS->SiS_SD2_Flags & SiS_SD2_NOOVERLAY))) {
5688	  xf86DrvMsg(pScrn->scrnIndex, from,
5689	      "Using Xv overlay by default on CRT%d\n",
5690	      pSiS->XvOnCRT2 ? 2 : 1);
5691       }
5692    }
5693
5694    /* Init ptrs for Save/Restore functions and calc MaxClock */
5695    SISDACPreInit(pScrn);
5696
5697    /* ********** end of VBFlags setup ********** */
5698
5699    /* VBFlags are initialized now. Back them up for SlaveMode modes. */
5700    pSiS->VBFlags_backup = pSiS->VBFlags;
5701
5702    /* Backup CR32,36,37 (in order to write them back after a VT switch) */
5703    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
5704       inSISIDXREG(SISCR,0x32,pSiS->myCR32);
5705       inSISIDXREG(SISCR,0x36,pSiS->myCR36);
5706       inSISIDXREG(SISCR,0x37,pSiS->myCR37);
5707    }
5708
5709    /* Find out about paneldelaycompensation and evaluate option */
5710#ifdef SISDUALHEAD
5711    if((!pSiS->DualHeadMode) || (!pSiS->SecondHead)) {
5712#endif
5713       if(pSiS->VGAEngine == SIS_300_VGA) {
5714
5715          if(pSiS->VBFlags2 & (VB2_LVDS | VB2_30xBDH)) {
5716
5717	     /* Save the current PDC if the panel is used at the moment.
5718	      * This seems by far the safest way to find out about it.
5719	      * If the system is using an old version of sisfb, we can't
5720	      * trust the pdc register value. If sisfb saved the pdc for
5721	      * us, use it.
5722	      */
5723	     if(pSiS->sisfbpdc != 0xff) {
5724	        pSiS->SiS_Pr->PDC = pSiS->sisfbpdc;
5725	     } else {
5726	        if(!(pSiS->donttrustpdc)) {
5727	           UChar tmp;
5728	           inSISIDXREG(SISCR, 0x30, tmp);
5729	           if(tmp & 0x20) {
5730	              inSISIDXREG(SISPART1, 0x13, pSiS->SiS_Pr->PDC);
5731                   } else {
5732	             xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5733		          "Unable to detect LCD PanelDelayCompensation, LCD is not active\n");
5734	           }
5735	        } else {
5736	           xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5737		        "Unable to detect LCD PanelDelayCompensation, please update sisfb\n");
5738	        }
5739	     }
5740	     if(pSiS->SiS_Pr->PDC != -1) {
5741	        pSiS->SiS_Pr->PDC &= 0x3c;
5742	        xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5743		     "Detected LCD PanelDelayCompensation 0x%02x\n",
5744		     pSiS->SiS_Pr->PDC);
5745	     }
5746
5747	     /* If we haven't been able to find out, use our other methods */
5748	     if(pSiS->SiS_Pr->PDC == -1) {
5749		int i=0;
5750		do {
5751		   if(mypdctable[i].subsysVendor == PCI_SUB_VENDOR_ID(pSiS->PciInfo) &&
5752		      mypdctable[i].subsysCard == PCI_SUB_DEVICE_ID(pSiS->PciInfo)) {
5753			 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5754			    "PCI card/vendor identified for non-default PanelDelayCompensation\n");
5755			 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5756			     "Vendor: %s, card: %s (ID %04x), PanelDelayCompensation: 0x%02x\n",
5757			     mypdctable[i].vendorName, mypdctable[i].cardName,
5758			     PCI_SUB_DEVICE_ID(pSiS->PciInfo), mypdctable[i].pdc);
5759			 if(pSiS->PDC == -1) {
5760			    pSiS->PDC = mypdctable[i].pdc;
5761			 } else {
5762			    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
5763				"PanelDelayCompensation overruled by option\n");
5764			 }
5765			 break;
5766		   }
5767		   i++;
5768		} while(mypdctable[i].subsysVendor != 0);
5769	     }
5770
5771	     if(pSiS->PDC != -1) {
5772		if(pSiS->BIOS) {
5773		   if(pSiS->VBFlags2 & VB2_LVDS) {
5774		      if(pSiS->BIOS[0x220] & 0x80) {
5775			 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5776			     "BIOS uses OEM LCD Panel Delay Compensation 0x%02x\n",
5777			     pSiS->BIOS[0x220] & 0x3c);
5778			 pSiS->BIOS[0x220] &= 0x7f;
5779		      }
5780		   }
5781		   if(pSiS->VBFlags2 & (VB2_301B | VB2_302B)) {
5782		      if(pSiS->BIOS[0x220] & 0x80) {
5783			 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5784			     "BIOS uses OEM LCD Panel Delay Compensation 0x%02x\n",
5785			       (  (pSiS->VBLCDFlags & VB_LCD_1280x1024) ?
5786			                 pSiS->BIOS[0x223] : pSiS->BIOS[0x224]  ) & 0x3c);
5787			 pSiS->BIOS[0x220] &= 0x7f;
5788		      }
5789		   }
5790		}
5791		pSiS->SiS_Pr->PDC = (pSiS->PDC & 0x3c);
5792		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
5793		      "Using LCD Panel Delay Compensation 0x%02x\n", pSiS->SiS_Pr->PDC);
5794	     }
5795	  }
5796
5797       }  /* SIS_300_VGA */
5798
5799       if(pSiS->VGAEngine == SIS_315_VGA) {
5800
5801	  UChar tmp, tmp2;
5802	  inSISIDXREG(SISCR, 0x30, tmp);
5803
5804	  /* Save the current PDC if the panel is used at the moment. */
5805	  if(pSiS->VBFlags2 & VB2_SISLVDSBRIDGE) {
5806
5807	     if(pSiS->sisfbpdc != 0xff) {
5808	        pSiS->SiS_Pr->PDC = pSiS->sisfbpdc;
5809	     }
5810	     if(pSiS->sisfbpdca != 0xff) {
5811	        pSiS->SiS_Pr->PDCA = pSiS->sisfbpdca;
5812	     }
5813
5814	     if(!pSiS->donttrustpdc) {
5815	        if((pSiS->sisfbpdc == 0xff) && (pSiS->sisfbpdca == 0xff)) {
5816		   CARD16 tempa, tempb;
5817		   inSISIDXREG(SISPART1,0x2d,tmp2);
5818		   tempa = (tmp2 & 0xf0) >> 3;
5819		   tempb = (tmp2 & 0x0f) << 1;
5820		   inSISIDXREG(SISPART1,0x20,tmp2);
5821		   tempa |= ((tmp2 & 0x40) >> 6);
5822		   inSISIDXREG(SISPART1,0x35,tmp2);
5823		   tempb |= ((tmp2 & 0x80) >> 7);
5824		   inSISIDXREG(SISPART1,0x13,tmp2);
5825		   if(!pSiS->ROM661New) {
5826		      if((tmp2 & 0x04) || (tmp & 0x20)) {
5827		         pSiS->SiS_Pr->PDCA = tempa;
5828		         pSiS->SiS_Pr->PDC  = tempb;
5829		      } else {
5830			 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5831			     "Unable to detect PanelDelayCompensation, LCD is not active\n");
5832		      }
5833		   } else {
5834		      if(tmp2 & 0x04) {
5835		         pSiS->SiS_Pr->PDCA = tempa;
5836		      } else if(tmp & 0x20) {
5837		         pSiS->SiS_Pr->PDC  = tempb;
5838		      } else {
5839			 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5840			     "Unable to detect PanelDelayCompensation, LCD is not active\n");
5841		      }
5842		   }
5843		}
5844	     } else {
5845		xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5846		    "Unable to detect PanelDelayCompensation, please update sisfb\n");
5847	     }
5848	     if(pSiS->SiS_Pr->PDC != -1) {
5849		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5850		     "Detected LCD PanelDelayCompensation 0x%02x (for LCD=CRT2)\n",
5851		     pSiS->SiS_Pr->PDC);
5852	     }
5853	     if(pSiS->SiS_Pr->PDCA != -1) {
5854		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5855		     "Detected LCD PanelDelayCompensation1 0x%02x (for LCD=CRT1)\n",
5856		     pSiS->SiS_Pr->PDCA);
5857	     }
5858	  }
5859
5860	  /* Let user override (for all bridges) */
5861	  if(pSiS->VBFlags2 & VB2_30xBLV) {
5862	     if(pSiS->PDC != -1) {
5863	        pSiS->SiS_Pr->PDC = pSiS->PDC & 0x1f;
5864		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
5865		     "Using LCD PanelDelayCompensation 0x%02x (for LCD=CRT2)\n",
5866		     pSiS->SiS_Pr->PDC);
5867	     }
5868	     if(pSiS->PDCA != -1) {
5869		pSiS->SiS_Pr->PDCA = pSiS->PDCA & 0x1f;
5870		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
5871		     "Using LCD PanelDelayCompensation1 0x%02x (for LCD=CRT1)\n",
5872		     pSiS->SiS_Pr->PDCA);
5873	     }
5874          }
5875
5876 	  /* Read the current EMI (if not overruled) */
5877	  if(pSiS->VBFlags2 & VB2_SISEMIBRIDGE) {
5878	     MessageType from = X_PROBED;
5879	     if(pSiS->EMI != -1) {
5880		pSiS->SiS_Pr->EMI_30 = (pSiS->EMI >> 24) & 0x60;
5881		pSiS->SiS_Pr->EMI_31 = (pSiS->EMI >> 16) & 0xff;
5882		pSiS->SiS_Pr->EMI_32 = (pSiS->EMI >> 8)  & 0xff;
5883		pSiS->SiS_Pr->EMI_33 = pSiS->EMI & 0xff;
5884		pSiS->SiS_Pr->HaveEMI = pSiS->SiS_Pr->HaveEMILCD = TRUE;
5885		pSiS->SiS_Pr->OverruleEMI = TRUE;
5886		from = X_CONFIG;
5887	     } else if((pSiS->sisfbfound) && (pSiS->sisfb_haveemi)) {
5888		pSiS->SiS_Pr->EMI_30 = pSiS->sisfb_emi30;
5889		pSiS->SiS_Pr->EMI_31 = pSiS->sisfb_emi31;
5890		pSiS->SiS_Pr->EMI_32 = pSiS->sisfb_emi32;
5891		pSiS->SiS_Pr->EMI_33 = pSiS->sisfb_emi33;
5892		pSiS->SiS_Pr->HaveEMI = TRUE;
5893		if(pSiS->sisfb_haveemilcd) pSiS->SiS_Pr->HaveEMILCD = TRUE;
5894		pSiS->SiS_Pr->OverruleEMI = FALSE;
5895	     } else {
5896		inSISIDXREG(SISPART4, 0x30, pSiS->SiS_Pr->EMI_30);
5897		inSISIDXREG(SISPART4, 0x31, pSiS->SiS_Pr->EMI_31);
5898		inSISIDXREG(SISPART4, 0x32, pSiS->SiS_Pr->EMI_32);
5899		inSISIDXREG(SISPART4, 0x33, pSiS->SiS_Pr->EMI_33);
5900		pSiS->SiS_Pr->HaveEMI = TRUE;
5901		if(tmp & 0x20) pSiS->SiS_Pr->HaveEMILCD = TRUE;
5902		pSiS->SiS_Pr->OverruleEMI = FALSE;
5903	     }
5904	     xf86DrvMsg(pScrn->scrnIndex, from,
5905		   "302LV/302ELV: Using EMI 0x%02x%02x%02x%02x%s\n",
5906		   pSiS->SiS_Pr->EMI_30,pSiS->SiS_Pr->EMI_31,
5907		   pSiS->SiS_Pr->EMI_32,pSiS->SiS_Pr->EMI_33,
5908		   pSiS->SiS_Pr->HaveEMILCD ? " (LCD)" : "");
5909	  }
5910
5911       } /* SIS_315_VGA */
5912#ifdef SISDUALHEAD
5913    }
5914#endif
5915
5916
5917    /* In dual head mode, both heads (currently) share the maxxfbmem equally.
5918     * If memory sharing is done differently, the following has to be changed;
5919     * the other modules (eg. accel and Xv) use dhmOffset for hardware
5920     * pointer settings relative to VideoRAM start and won't need to be changed.
5921     *
5922     * Addendum: dhmoffset is also used for skipping the UMA area on SiS76x.
5923     */
5924
5925    pSiS->dhmOffset = pSiS->FbBaseOffset;
5926    pSiS->FbAddress += pSiS->dhmOffset;
5927
5928#ifdef SISDUALHEAD
5929    if(pSiS->DualHeadMode) {
5930       pSiS->FbAddress = pSiS->realFbAddress;
5931       if(!pSiS->SecondHead) {
5932	  /* ===== First head (always CRT2) ===== */
5933	  /* We use only half of the memory available */
5934	  pSiS->maxxfbmem /= 2;
5935	  /* dhmOffset is 0 (or LFB-base for SiS76x UMA skipping) */
5936	  pSiS->FbAddress += pSiS->dhmOffset;
5937	  xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5938	      "%dKB video RAM at 0x%lx available for master head (CRT2)\n",
5939	      pSiS->maxxfbmem/1024, pSiS->FbAddress);
5940       } else {
5941	  /* ===== Second head (always CRT1) ===== */
5942	  /* We use only half of the memory available */
5943	  pSiS->maxxfbmem /= 2;
5944	  /* Initialize dhmOffset */
5945	  pSiS->dhmOffset += pSiS->maxxfbmem;
5946	  /* Adapt FBAddress */
5947	  pSiS->FbAddress += pSiS->dhmOffset;
5948	  xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5949	     "%dKB video RAM at 0x%lx available for slave head (CRT1)\n",
5950	     pSiS->maxxfbmem/1024,  pSiS->FbAddress);
5951       }
5952    }
5953#endif
5954
5955    /* Note: Do not use availMem for anything from now. Use
5956     * maxxfbmem instead. (availMem does not take dual head
5957     * mode into account.)
5958     */
5959
5960    if(pSiS->FbBaseOffset) {
5961       /* Doubt that the DRM memory manager can deal
5962        * with a heap start of 0...
5963	*/
5964       pSiS->DRIheapstart = 16;
5965       pSiS->DRIheapend = pSiS->FbBaseOffset;
5966    } else {
5967       pSiS->DRIheapstart = pSiS->maxxfbmem;
5968       pSiS->DRIheapend = pSiS->availMem;
5969    }
5970#ifdef SISDUALHEAD
5971    if(pSiS->DualHeadMode) {
5972       pSiS->DRIheapstart = pSiS->DRIheapend = 0;
5973    } else
5974#endif
5975           if(pSiS->DRIheapstart >= pSiS->DRIheapend) {
5976#if 0  /* For future use */
5977       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5978	  "No memory for DRI heap. Please set the option \"MaxXFBMem\" to\n"
5979	  "\tlimit the memory X should use and leave the rest to DRI\n");
5980#endif
5981       pSiS->DRIheapstart = pSiS->DRIheapend = 0;
5982    }
5983
5984    /* Now for something completely different: DDC.
5985     * For 300 and 315/330/340 series, we provide our
5986     * own functions (in order to probe CRT2 as well)
5987     * If these fail, use the VBE.
5988     * All other chipsets will use VBE. No need to re-invent
5989     * the wheel there.
5990     */
5991
5992    pSiS->pVbe = NULL;
5993    didddc2 = FALSE;
5994
5995    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
5996       if(xf86LoadSubModule(pScrn, "ddc")) {
5997	  int crtnum = 0;
5998	  if((pMonitor = SiSDoPrivateDDC(pScrn, &crtnum))) {
5999	     didddc2 = TRUE;
6000	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED, ddcsstr, crtnum);
6001	     xf86PrintEDID(pMonitor);
6002	     xf86SetDDCproperties(pScrn, pMonitor);
6003	     pScrn->monitor->DDC = pMonitor;
6004	     /* Now try to find out aspect ratio */
6005	     SiSFindAspect(pScrn, pMonitor, crtnum);
6006	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED, ddcestr, crtnum);
6007	  }
6008       }
6009    }
6010
6011#ifdef SISDUALHEAD
6012    /* In dual head mode, probe DDC using VBE only for CRT1 (second head) */
6013    if((pSiS->DualHeadMode) && (!didddc2) && (!pSiS->SecondHead)) {
6014       didddc2 = TRUE;
6015    }
6016#endif
6017
6018    if(!didddc2) {
6019       /* If CRT1 is off or LCDA, skip DDC via VBE */
6020       if((pSiS->CRT1off) || (pSiS->VBFlags & CRT1_LCDA)) {
6021          didddc2 = TRUE;
6022       }
6023    }
6024
6025    /* Now (re-)load and initialize the DDC module */
6026    if(!didddc2) {
6027
6028       if(xf86LoadSubModule(pScrn, "ddc")) {
6029
6030	  /* Now load and initialize VBE module. */
6031	  SiS_LoadInitVBE(pScrn);
6032
6033	  if(pSiS->pVbe) {
6034	     if((pMonitor = vbeDoEDID(pSiS->pVbe,NULL))) {
6035		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
6036		      "VBE CRT1 DDC monitor info:\n");
6037		xf86SetDDCproperties(pScrn, xf86PrintEDID(pMonitor));
6038		pScrn->monitor->DDC = pMonitor;
6039		/* Now try to find out aspect ratio */
6040		SiSFindAspect(pScrn, pMonitor, 1);
6041		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
6042		      "End of VBE CRT1 DDC monitor info\n");
6043	     }
6044	  } else {
6045	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6046		 "Failed to read DDC data\n");
6047	  }
6048       }
6049    }
6050
6051#ifdef SISMERGED
6052    if(pSiS->MergedFB) {
6053       pSiS->CRT2pScrn->monitor = malloc(sizeof(MonRec));
6054       if(pSiS->CRT2pScrn->monitor) {
6055	  DisplayModePtr tempm = NULL, currentm = NULL, newm = NULL;
6056	  memcpy(pSiS->CRT2pScrn->monitor, pScrn->monitor, sizeof(MonRec));
6057	  pSiS->CRT2pScrn->monitor->DDC = NULL;
6058	  pSiS->CRT2pScrn->monitor->Modes = NULL;
6059	  pSiS->CRT2pScrn->monitor->id = (char *)crt2monname;
6060	  tempm = pScrn->monitor->Modes;
6061	  while(tempm) {
6062	     if(!(newm = malloc(sizeof(DisplayModeRec)))) break;
6063	     memcpy(newm, tempm, sizeof(DisplayModeRec));
6064	     if(!(newm->name = malloc(strlen(tempm->name) + 1))) {
6065	        free(newm);
6066		break;
6067	     }
6068	     strcpy(newm->name, tempm->name);
6069	     if(!pSiS->CRT2pScrn->monitor->Modes) pSiS->CRT2pScrn->monitor->Modes = newm;
6070	     if(currentm) {
6071	        currentm->next = newm;
6072		newm->prev = currentm;
6073	     }
6074	     currentm = newm;
6075	     tempm = tempm->next;
6076	  }
6077	  if(pSiS->CRT2HSync) {
6078	     pSiS->CRT2pScrn->monitor->nHsync =
6079		SiSStrToRanges(pSiS->CRT2pScrn->monitor->hsync, pSiS->CRT2HSync, MAX_HSYNC);
6080	  }
6081	  if(pSiS->CRT2VRefresh) {
6082	     pSiS->CRT2pScrn->monitor->nVrefresh =
6083		SiSStrToRanges(pSiS->CRT2pScrn->monitor->vrefresh, pSiS->CRT2VRefresh, MAX_VREFRESH);
6084	  }
6085	  if((pMonitor = SiSInternalDDC(pSiS->CRT2pScrn, 1))) {
6086	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED, ddcsstr, 2);
6087	     xf86PrintEDID(pMonitor);
6088	     xf86SetDDCproperties(pSiS->CRT2pScrn, pMonitor);
6089	     pSiS->CRT2pScrn->monitor->DDC = pMonitor;
6090	     /* Now try to find out aspect ratio */
6091	     SiSFindAspect(pScrn, pMonitor, 2);
6092	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED, ddcestr, 2);
6093	     /* use DDC data if no ranges in config file */
6094	     if(!pSiS->CRT2HSync) {
6095	        pSiS->CRT2pScrn->monitor->nHsync = 0;
6096	     }
6097	     if(!pSiS->CRT2VRefresh) {
6098	        pSiS->CRT2pScrn->monitor->nVrefresh = 0;
6099	     }
6100	  } else {
6101	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
6102		"Failed to read DDC data for CRT2\n");
6103	  }
6104       } else {
6105	  SISErrorLog(pScrn, "Failed to allocate memory for CRT2 monitor, %s.\n",
6106	  		mergeddisstr);
6107	  if(pSiS->CRT2pScrn) free(pSiS->CRT2pScrn);
6108	  pSiS->CRT2pScrn = NULL;
6109	  pSiS->MergedFB = FALSE;
6110       }
6111    }
6112#endif
6113
6114    /* Copy our detected monitor gammas, part 1. Note that device redetection
6115     * is not supported in DHM, so there is no need to do that anytime later.
6116     */
6117#ifdef SISDUALHEAD
6118    if(pSiS->DualHeadMode) {
6119       if(!pSiS->SecondHead) {
6120          /* CRT2: Got gamma for LCD or VGA2 */
6121	  pSiSEnt->CRT2VGAMonitorGamma = pSiS->CRT2VGAMonitorGamma;
6122       } else {
6123          /* CRT1: Got gamma for LCD or VGA */
6124	  pSiSEnt->CRT1VGAMonitorGamma = pSiS->CRT1VGAMonitorGamma;
6125       }
6126       if(pSiS->CRT2LCDMonitorGamma) pSiSEnt->CRT2LCDMonitorGamma = pSiS->CRT2LCDMonitorGamma;
6127    }
6128#endif
6129
6130    /* end of DDC */
6131
6132    /* From here, we mainly deal with clocks and modes */
6133
6134#ifdef SISMERGED
6135    if(pSiS->MergedFB) xf86DrvMsg(pScrn->scrnIndex, X_INFO, crtsetupstr, 1);
6136#endif
6137
6138    /* Set the min pixel clock */
6139    pSiS->MinClock = 5000;
6140    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
6141       pSiS->MinClock = 10000;
6142    }
6143    xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "Min pixel clock is %d MHz\n",
6144                pSiS->MinClock / 1000);
6145
6146    /* If the user has specified ramdac speed in the config
6147     * file, we respect that setting.
6148     */
6149    from = X_PROBED;
6150    if(pSiS->pEnt->device->dacSpeeds[0]) {
6151       int speed = 0;
6152       switch(pScrn->bitsPerPixel) {
6153       case 8:  speed = pSiS->pEnt->device->dacSpeeds[DAC_BPP8];
6154                break;
6155       case 16: speed = pSiS->pEnt->device->dacSpeeds[DAC_BPP16];
6156                break;
6157       case 24: speed = pSiS->pEnt->device->dacSpeeds[DAC_BPP24];
6158                break;
6159       case 32: speed = pSiS->pEnt->device->dacSpeeds[DAC_BPP32];
6160                break;
6161       }
6162       if(speed == 0) pSiS->MaxClock = pSiS->pEnt->device->dacSpeeds[0];
6163       else           pSiS->MaxClock = speed;
6164       from = X_CONFIG;
6165    }
6166    xf86DrvMsg(pScrn->scrnIndex, from, "Max pixel clock is %d MHz\n",
6167                pSiS->MaxClock / 1000);
6168
6169    /*
6170     * Setup the ClockRanges, which describe what clock ranges are available,
6171     * and what sort of modes they can be used for.
6172     */
6173    clockRanges = xnfcalloc(sizeof(ClockRange), 1);
6174    clockRanges->next = NULL;
6175    clockRanges->minClock = pSiS->MinClock;
6176    clockRanges->maxClock = pSiS->MaxClock;
6177    clockRanges->clockIndex = -1;               /* programmable */
6178    clockRanges->interlaceAllowed = TRUE;
6179    clockRanges->doubleScanAllowed = TRUE;
6180
6181    /*
6182     * Since we have lots of built-in modes for 300/315/330/340 series
6183     * with vb support, we replace the given default mode list with our
6184     * own. In case the video bridge is to be used, we only allow other
6185     * modes if
6186     *   -) vbtype is 301, 301B, 301C or 302B, and
6187     *   -) crt2 device is not TV, and
6188     *   -) crt1 is not LCDA, unless bridge is TMDS/LCDA capable (301C)
6189     */
6190    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
6191       if(!(pSiS->noInternalModes)) {
6192          Bool acceptcustommodes = TRUE;  /* Accept user modelines */
6193	  Bool includelcdmodes   = TRUE;  /* Include modes reported by DDC */
6194	  Bool isfordvi          = FALSE; /* Is for digital DVI output */
6195	  Bool fakecrt2modes     = FALSE; /* Fake some modes for CRT2 */
6196	  Bool IsForCRT2	 = FALSE;
6197	  if(pSiS->UseVESA) {
6198	     acceptcustommodes = FALSE;
6199	     includelcdmodes   = FALSE;
6200	  }
6201#ifdef SISDUALHEAD  /* Dual head is static. Output devices will not change. */
6202	  if(pSiS->DualHeadMode) {
6203	     if(!pSiS->SecondHead) {  /* CRT2: */
6204	        if(pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) {
6205		   if(!(pSiS->VBFlags2 & VB2_30xBDH)) {
6206		      if(!(pSiS->VBFlags & (CRT2_LCD|CRT2_VGA))) includelcdmodes   = FALSE;
6207		      if(pSiS->VBFlags & CRT2_LCD)               isfordvi          = TRUE;
6208		      if(pSiS->VBFlags & CRT2_TV)                acceptcustommodes = FALSE;
6209		   } else {
6210		      if(pSiS->VBFlags & (CRT2_TV|CRT2_LCD)) {
6211		         acceptcustommodes = FALSE;
6212		         includelcdmodes   = FALSE;
6213			 fakecrt2modes = TRUE;
6214		      }
6215		   }
6216		} else {
6217		   acceptcustommodes = FALSE;
6218		   includelcdmodes   = FALSE;
6219		   if(pSiS->VBFlags & (CRT2_TV|CRT2_LCD)) {
6220		      fakecrt2modes = TRUE;
6221		   }
6222		}
6223		clockRanges->interlaceAllowed = FALSE;
6224		IsForCRT2 = TRUE;
6225	     } else {		/* CRT1: */
6226	        if(pSiS->VBFlags & CRT1_LCDA) {
6227		   if(!(pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE)) {
6228		      acceptcustommodes = FALSE;
6229		      includelcdmodes   = FALSE;
6230		      fakecrt2modes     = TRUE;
6231		      /* Will handle i-lace in mode-switching code */
6232		   } else {
6233		      isfordvi = TRUE;
6234		      /* Don't allow i-lace modes */
6235		      clockRanges->interlaceAllowed = FALSE;
6236		   }
6237		} else {
6238		   includelcdmodes = FALSE;
6239		}
6240	     }
6241	  } else
6242#endif
6243#ifdef SISMERGED  /* MergedFB mode is not static. Output devices may change. */
6244          if(pSiS->MergedFB) {
6245	     if(pSiS->VBFlags & CRT1_LCDA) {
6246	        if(!(pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE)) {
6247		   acceptcustommodes = FALSE;
6248		   includelcdmodes   = FALSE;
6249		   fakecrt2modes     = TRUE;
6250		   /* Will handle i-lace in mode-switching code */
6251		} else {
6252		   isfordvi = TRUE;
6253		   /* Don't allow i-lace custom modes */
6254		   clockRanges->interlaceAllowed = FALSE;
6255		}
6256	     } else {
6257	        includelcdmodes = FALSE;
6258	     }
6259          } else
6260#endif		 /* Mirror mode is not static. Output devices may change. */
6261          if(pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) {
6262	     if(!(pSiS->VBFlags2 & VB2_30xBDH)) {
6263		if(!(pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE)) {
6264		   if(!(pSiS->VBFlags & (CRT2_LCD|CRT2_VGA))) includelcdmodes = FALSE;
6265		   if(pSiS->VBFlags & CRT2_LCD)               isfordvi        = TRUE;
6266		} else {
6267		   if(!(pSiS->VBFlags & (CRT2_LCD|CRT2_VGA|CRT1_LCDA))) includelcdmodes = FALSE;
6268		   if(pSiS->VBFlags & (CRT2_LCD|CRT1_LCDA))             isfordvi        = TRUE;
6269		}
6270		if((!(pSiS->VBFlags & DISPTYPE_CRT1)) && (!(pSiS->VBFlags & CRT1_LCDA))) {
6271		   IsForCRT2 = TRUE;
6272		}
6273		/* Allow user modes, even if CRT2 is TV. Will be filtered through ValidMode();
6274		 * leaving the user modes here might have the advantage that such a mode, if
6275		 * it matches in resolution with a supported TV mode, allows us to drive eg.
6276		 * non standard panels, and still permits switching to TV. This mode will be
6277		 * "mapped" to a supported mode of identical resolution for TV. All this is
6278		 * taken care of by ValidMode() and ModeInit()/PresetMode().
6279		 */
6280	     } else {
6281		if(pSiS->VBFlags & (CRT2_TV|CRT2_LCD)) {
6282		   acceptcustommodes = FALSE;
6283		   includelcdmodes   = FALSE;
6284		   if(!(pSiS->VBFlags & DISPTYPE_CRT1)) {
6285		      fakecrt2modes = TRUE;
6286		      IsForCRT2 = TRUE;
6287		   }
6288		}
6289	     }
6290	  } else if(pSiS->VBFlags & (CRT2_ENABLE | CRT1_LCDA)) {
6291	     acceptcustommodes = FALSE;
6292	     includelcdmodes   = FALSE;
6293	     if((pSiS->VBFlags & CRT1_LCDA) || (!(pSiS->VBFlags & DISPTYPE_CRT1))) {
6294		fakecrt2modes = TRUE;
6295		IsForCRT2 = TRUE;
6296	     }
6297	  } else {
6298	     includelcdmodes   = FALSE;
6299	  }
6300	  /* Ignore interlace, mode switching code will handle this */
6301
6302	  pSiS->HaveCustomModes = FALSE;
6303	  if(SiSMakeOwnModeList(pScrn, acceptcustommodes, includelcdmodes,
6304			isfordvi, &pSiS->HaveCustomModes, FALSE /*fakecrt2modes*/, IsForCRT2)) {
6305	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6306		 "Replaced %s mode list with built-in modes\n",
6307	     pSiS->HaveCustomModes ? "default" : "entire");
6308	     if(pSiS->VGAEngine == SIS_315_VGA) {
6309		int UseWide = pSiS->SiS_Pr->SiS_UseWide;
6310		if(IsForCRT2) UseWide = pSiS->SiS_Pr->SiS_UseWideCRT2;
6311		if((!IsForCRT2) || (pSiS->VBFlags2 & VB2_SISVGA2BRIDGE)) {
6312		   xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6313			"Using %s widescreen modes for CRT%d VGA devices\n",
6314			UseWide ? "real" : "fake", IsForCRT2 ? 2 : 1);
6315		   xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6316			"\tUse option \"ForceCRT%dVGAAspect\" to overrule\n",
6317			IsForCRT2 ? 2 : 1);
6318		}
6319	     }
6320#ifdef TWDEBUG
6321             pScrn->modes = pScrn->monitor->Modes;
6322	     xf86PrintModes(pScrn);
6323	     pScrn->modes = NULL;
6324#endif
6325          } else {
6326	     xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
6327		"Building list of built-in modes failed, using server defaults\n");
6328	  }
6329       } else {
6330          pSiS->HaveCustomModes = TRUE;
6331       }
6332    }
6333
6334    /* Add our built-in hi-res and TV modes on the 6326 */
6335    if(pSiS->Chipset == PCI_CHIP_SIS6326) {
6336       if(pScrn->bitsPerPixel == 8) {
6337	  SiS6326SIS1600x1200_60Mode.next = pScrn->monitor->Modes;
6338	  pScrn->monitor->Modes = &SiS6326SIS1600x1200_60Mode;
6339	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6340	  	"Adding mode \"SIS1600x1200-60\" (depth 8 only)\n");
6341       }
6342       if(pScrn->bitsPerPixel <= 16) {
6343	  SiS6326SIS1280x1024_75Mode.next = pScrn->monitor->Modes;
6344	  pScrn->monitor->Modes = &SiS6326SIS1280x1024_75Mode;
6345	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6346	  	"Adding mode \"SIS1280x1024-75\" (depths 8, 15 and 16 only)\n");
6347       }
6348       if((pSiS->SiS6326Flags & SIS6326_HASTV) &&
6349	  (pSiS->SiS6326Flags & SIS6326_TVDETECTED)) {
6350	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6351		"Adding %s TV modes to mode list:\n",
6352		(pSiS->SiS6326Flags & SIS6326_TVPAL) ? "PAL" : "NTSC");
6353	  if(pSiS->SiS6326Flags & SIS6326_TVPAL) {
6354	     SiS6326PAL800x600Mode.next = pScrn->monitor->Modes;
6355	     pScrn->monitor->Modes = &SiS6326PAL640x480Mode;
6356	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6357		"\t\"PAL800x600\" \"PAL800x600U\" \"PAL720x540\" \"PAL640x480\"\n");
6358	  } else {
6359	     SiS6326NTSC640x480Mode.next = pScrn->monitor->Modes;
6360	     pScrn->monitor->Modes = &SiS6326NTSC640x400Mode;
6361	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6362		"\t\"NTSC640x480\" \"NTSC640x480U\" \"NTSC640x400\"\n");
6363	  }
6364       }
6365    }
6366
6367   /* If there is no HSync or VRefresh data for the monitor,
6368    * derive it from DDC data. Essentially done by common layer
6369    * since 4.3.99.14, but this is not usable since it is done
6370    * too late (in ValidateModes()).
6371    * Addendum: I overrule the ranges now in any case unless
6372    * it would affect a CRT output device or DDC data is available.
6373    * Hence, for LCD(A) and TV, we always get proper ranges. This
6374    * is entirely harmless. However, option "NoOverruleRanges" will
6375    * disable this behavior.
6376    * This should "fix" the - by far - most common configuration
6377    * mistakes.
6378    */
6379
6380    crt1freqoverruled = FALSE;
6381
6382    fromDDC = FALSE;
6383    if((pScrn->monitor->nHsync <= 0) || (pSiS->OverruleRanges)) {
6384       if((pScrn->monitor->nHsync <= 0) && (pScrn->monitor->DDC)) {
6385	  SiSSetSyncRangeFromEdid(pScrn, 1);
6386	  if(pScrn->monitor->nHsync > 0) {
6387	     xf86DrvMsg(pScrn->scrnIndex, X_INFO, subshstr,
6388#ifdef SISDUALHEAD
6389			pSiS->DualHeadMode ? (pSiS->SecondHead ? 1 : 2) :
6390#endif
6391				pSiS->CRT1off ? 2 : 1);
6392	     fromDDC = TRUE;
6393	  }
6394       }
6395       if((pScrn->monitor->nHsync <= 0) || (pSiS->OverruleRanges)) {
6396	  if(SiSAllowSyncOverride(pSiS, fromDDC)) {
6397	     Bool HaveNoRanges = (pScrn->monitor->nHsync <= 0);
6398	     /* Set sane ranges for LCD and TV
6399	      * (our strict checking will filter out invalid ones anyway)
6400	      */
6401	     if((crt1freqoverruled = CheckAndOverruleH(pScrn, pScrn->monitor))) {
6402		xf86DrvMsg(pScrn->scrnIndex, X_INFO, saneh,
6403			HaveNoRanges ? "missing" : "bogus",
6404#ifdef SISDUALHEAD
6405			pSiS->DualHeadMode ? (pSiS->SecondHead ? 1 : 2) :
6406#endif
6407				pSiS->CRT1off ? 2 : 1);
6408	     }
6409	  }
6410       }
6411    }
6412
6413    fromDDC = FALSE;
6414    if((pScrn->monitor->nVrefresh <= 0) || (pSiS->OverruleRanges)) {
6415       if((pScrn->monitor->nVrefresh <= 0) && (pScrn->monitor->DDC)) {
6416	  SiSSetSyncRangeFromEdid(pScrn, 0);
6417	  if(pScrn->monitor->nVrefresh > 0) {
6418	     xf86DrvMsg(pScrn->scrnIndex, X_INFO, subsvstr,
6419#ifdef SISDUALHEAD
6420			pSiS->DualHeadMode ? (pSiS->SecondHead ? 1 : 2) :
6421#endif
6422				pSiS->CRT1off ? 2 : 1);
6423	     fromDDC = TRUE;
6424          }
6425       }
6426       if((pScrn->monitor->nVrefresh <= 0) || (pSiS->OverruleRanges)) {
6427	  if(SiSAllowSyncOverride(pSiS, fromDDC)) {
6428	     Bool HaveNoRanges = (pScrn->monitor->nVrefresh <= 0);
6429	     /* Set sane ranges for LCD and TV */
6430	     if((crt1freqoverruled = CheckAndOverruleV(pScrn, pScrn->monitor))) {
6431		xf86DrvMsg(pScrn->scrnIndex, X_INFO, sanev,
6432			HaveNoRanges ? "missing" : "bogus",
6433#ifdef SISDUALHEAD
6434			pSiS->DualHeadMode ? (pSiS->SecondHead ? 1 : 2) :
6435#endif
6436				pSiS->CRT1off ? 2 : 1);
6437	     }
6438	  }
6439       }
6440    }
6441
6442    if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
6443       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6444	  "\"Unknown reason\" in the following list means that the mode\n");
6445       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6446	  "is not supported on the chipset/bridge/current output device.\n");
6447    }
6448
6449    /*
6450     * xf86ValidateModes will check that the mode HTotal and VTotal values
6451     * don't exceed the chipset's limit if pScrn->maxHValue and
6452     * pScrn->maxVValue are set.  Since our SISValidMode() already takes
6453     * care of this, we don't worry about setting them here.
6454     */
6455
6456    /* Select valid modes from those available */
6457    /*
6458     * Assuming min pitch 256, min height 128
6459     */
6460    {
6461       int minpitch, maxpitch, minheight, maxheight;
6462       pointer backupddc = pScrn->monitor->DDC;
6463
6464       minpitch = 256;
6465       minheight = 128;
6466       switch(pSiS->VGAEngine) {
6467       case SIS_OLD_VGA:
6468       case SIS_530_VGA:
6469          maxpitch = 2040;
6470          maxheight = 2048;
6471          break;
6472       case SIS_300_VGA:
6473       case SIS_315_VGA:
6474          maxpitch = 4088;
6475          maxheight = 4096;
6476          break;
6477       default:
6478          maxpitch = 2048;
6479          maxheight = 2048;
6480          break;
6481       }
6482
6483#ifdef SISMERGED
6484       pSiS->CheckForCRT2 = FALSE;
6485#endif
6486
6487       /* Suppress bogus DDC warning */
6488       if(crt1freqoverruled) pScrn->monitor->DDC = NULL;
6489
6490       i = xf86ValidateModes(pScrn, pScrn->monitor->Modes,
6491			pScrn->display->modes, clockRanges, NULL,
6492			minpitch, maxpitch,
6493			pScrn->bitsPerPixel * 8,
6494			minheight, maxheight,
6495			pScrn->display->virtualX,
6496			pScrn->display->virtualY,
6497			pSiS->maxxfbmem,
6498			LOOKUP_BEST_REFRESH);
6499
6500       pScrn->monitor->DDC = backupddc;
6501    }
6502
6503    if(i == -1) {
6504       SISErrorLog(pScrn, "xf86ValidateModes() error\n");
6505       goto my_error_1;
6506    }
6507
6508    /* Check the virtual screen against the available memory */
6509    {
6510       ULong memreq = (pScrn->virtualX * ((pScrn->bitsPerPixel + 7) / 8)) * pScrn->virtualY;
6511
6512       if(memreq > pSiS->maxxfbmem) {
6513	  SISErrorLog(pScrn,
6514	     "Virtual screen too big for memory; %ldK needed, %ldK available\n",
6515	     memreq/1024, pSiS->maxxfbmem/1024);
6516	  goto my_error_1;
6517       }
6518    }
6519
6520    /* Dual Head:
6521     * -) Go through mode list and mark all those modes as bad,
6522     *    which are unsuitable for dual head mode.
6523     * -) Find the highest used pixelclock on the master head.
6524     */
6525#ifdef SISDUALHEAD
6526    if((pSiS->DualHeadMode) && (!pSiS->SecondHead)) {
6527
6528       pSiSEnt->maxUsedClock = 0;
6529
6530       if((p = first = pScrn->modes)) {
6531
6532	  do {
6533
6534	     n = p->next;
6535
6536	     /* Modes that require the bridge to operate in SlaveMode
6537	      * are not suitable for Dual Head mode.
6538	      */
6539	     if( (pSiS->VGAEngine == SIS_300_VGA) &&
6540		 ( (strcmp(p->name, "320x200") == 0) ||
6541		   (strcmp(p->name, "320x240") == 0) ||
6542		   (strcmp(p->name, "400x300") == 0) ||
6543		   (strcmp(p->name, "512x384") == 0) ||
6544		   (strcmp(p->name, "640x400") == 0) ) )  {
6545		p->status = MODE_BAD;
6546		xf86DrvMsg(pScrn->scrnIndex, X_INFO, notsuitablestr, p->name, "dual head");
6547	     }
6548
6549	     /* Search for the highest clock on first head in order to calculate
6550	      * max clock for second head (CRT1)
6551	      */
6552	     if((p->status == MODE_OK) && (p->Clock > pSiSEnt->maxUsedClock)) {
6553		pSiSEnt->maxUsedClock = p->Clock;
6554	     }
6555
6556	     p = n;
6557
6558	  } while (p != NULL && p != first);
6559
6560       }
6561    }
6562#endif
6563
6564    /* Prune the modes marked as invalid */
6565    xf86PruneDriverModes(pScrn);
6566
6567    if(i == 0 || pScrn->modes == NULL) {
6568       SISErrorLog(pScrn, "No valid modes found - check VertRefresh/HorizSync\n");
6569       goto my_error_1;
6570    }
6571
6572    xf86SetCrtcForModes(pScrn, INTERLACE_HALVE_V);
6573
6574    /* Set the current mode to the first in the list */
6575    pScrn->currentMode = pScrn->modes;
6576
6577    /* Copy to CurrentLayout */
6578    pSiS->CurrentLayout.mode = pScrn->currentMode;
6579    pSiS->CurrentLayout.displayWidth = pScrn->displayWidth;
6580    pSiS->CurrentLayout.displayHeight = pScrn->virtualY;
6581
6582#ifdef SISMERGED
6583    if(pSiS->MergedFB) {
6584       xf86DrvMsg(pScrn->scrnIndex, X_INFO, modesforstr, 1);
6585    }
6586#endif
6587
6588    /* Print the list of modes being used */
6589    {
6590       Bool usemyprint = FALSE;
6591
6592#ifdef SISDUALHEAD
6593       if(pSiS->DualHeadMode) {
6594	  if(pSiS->SecondHead) {
6595	     if(pSiS->VBFlags & CRT1_LCDA) usemyprint = TRUE;
6596	  } else {
6597	     if(pSiS->VBFlags & (CRT2_LCD | CRT2_TV)) usemyprint = TRUE;
6598	  }
6599       } else
6600#endif
6601#ifdef SISMERGED
6602       if(pSiS->MergedFB) {
6603	  if(pSiS->VBFlags & CRT1_LCDA) usemyprint = TRUE;
6604       } else
6605#endif
6606       {
6607	  if( (pSiS->VBFlags & (CRT2_LCD | CRT2_TV)) &&
6608	      (!(pSiS->VBFlags & DISPTYPE_DISP1)) )
6609	     usemyprint = TRUE;
6610       }
6611
6612       if(usemyprint) {
6613	  SiSPrintModes(pScrn);
6614       } else {
6615	  xf86PrintModes(pScrn);
6616       }
6617    }
6618
6619#ifdef SISMERGED
6620    if(pSiS->MergedFB) {
6621       Bool acceptcustommodes = TRUE;
6622       Bool includelcdmodes   = TRUE;
6623       Bool isfordvi          = FALSE;
6624       Bool fakecrt2modes     = FALSE;
6625
6626       xf86DrvMsg(pScrn->scrnIndex, X_INFO, crtsetupstr, 2);
6627
6628       clockRanges->next = NULL;
6629       clockRanges->minClock = pSiS->MinClock;
6630       clockRanges->maxClock = SiSMemBandWidth(pSiS->CRT2pScrn, TRUE);
6631       clockRanges->clockIndex = -1;
6632       clockRanges->interlaceAllowed = FALSE;
6633       clockRanges->doubleScanAllowed = FALSE;
6634       if(pSiS->VGAEngine == SIS_315_VGA) {
6635          clockRanges->doubleScanAllowed = TRUE;
6636       }
6637
6638       xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "Min pixel clock for CRT2 is %d MHz\n",
6639                clockRanges->minClock / 1000);
6640       xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "Max pixel clock for CRT2 is %d MHz\n",
6641                clockRanges->maxClock / 1000);
6642
6643       if(pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) {
6644          if(!(pSiS->VBFlags2 & VB2_30xBDH)) {
6645             if(!(pSiS->VBFlags & (CRT2_LCD|CRT2_VGA))) includelcdmodes   = FALSE;
6646	     if(pSiS->VBFlags & CRT2_LCD)               isfordvi          = TRUE;
6647	     /* See above for a remark on handling CRT2 = TV */
6648	  } else {
6649	     if(pSiS->VBFlags & (CRT2_LCD|CRT2_TV)) {
6650		includelcdmodes   = FALSE;
6651		acceptcustommodes = FALSE;
6652		fakecrt2modes     = TRUE;
6653	     }
6654	  }
6655       } else {
6656	  includelcdmodes   = FALSE;
6657	  acceptcustommodes = FALSE;
6658	  if(pSiS->VBFlags & (CRT2_LCD|CRT2_TV)) {
6659	     fakecrt2modes = TRUE;
6660	  }
6661       }
6662
6663       pSiS->HaveCustomModes2 = FALSE;
6664       if(!SiSMakeOwnModeList(pSiS->CRT2pScrn, acceptcustommodes, includelcdmodes,
6665				isfordvi, &pSiS->HaveCustomModes2, FALSE /* fakecrt2modes */, TRUE )) {
6666
6667	  SISErrorLog(pScrn, "Building list of built-in modes for CRT2 failed, %s\n",
6668				mergeddisstr);
6669	  SiSFreeCRT2Structs(pSiS);
6670	  pSiS->MergedFB = FALSE;
6671
6672       } else {
6673	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6674		 "Replaced %s mode list for CRT2 with built-in modes\n",
6675		 pSiS->HaveCustomModes2 ? "default" : "entire");
6676	  if((pSiS->VGAEngine == SIS_315_VGA) && (pSiS->VBFlags2 & VB2_SISVGA2BRIDGE)) {
6677	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6678		 "Using %s widescreen modes for CRT2 VGA devices\n",
6679		 pSiS->SiS_Pr->SiS_UseWideCRT2 ? "real" : "fake");
6680	  } else pSiS->SiS_Pr->SiS_UseWideCRT2 = 0;
6681       }
6682
6683    }
6684
6685    if(pSiS->MergedFB) {
6686
6687       pointer backupddc;
6688
6689       crt2freqoverruled = FALSE;
6690
6691       fromDDC = FALSE;
6692       if((pSiS->CRT2pScrn->monitor->nHsync <= 0) || (pSiS->OverruleRanges)) {
6693          if((pSiS->CRT2pScrn->monitor->nHsync <= 0) && (pSiS->CRT2pScrn->monitor->DDC)) {
6694	     SiSSetSyncRangeFromEdid(pSiS->CRT2pScrn, 1);
6695	     if(pSiS->CRT2pScrn->monitor->nHsync > 0) {
6696		xf86DrvMsg(pScrn->scrnIndex, X_INFO, subshstr, 2);
6697		fromDDC = TRUE;
6698	     }
6699	  }
6700	  if((pSiS->CRT2pScrn->monitor->nHsync <= 0) || (pSiS->OverruleRanges)) {
6701	     if( (pSiS->VBFlags & CRT2_TV) ||
6702	         ((pSiS->VBFlags & CRT2_LCD) && (!fromDDC)) ) {
6703		Bool HaveNoRanges = (pSiS->CRT2pScrn->monitor->nHsync <= 0);
6704		/* Set sane ranges for LCD and TV */
6705		if((crt2freqoverruled = CheckAndOverruleH(pScrn, pSiS->CRT2pScrn->monitor))) {
6706		   xf86DrvMsg(pScrn->scrnIndex, X_INFO, saneh,
6707			HaveNoRanges ? "missing" : "bogus", 2);
6708		}
6709	     }
6710	  }
6711       }
6712
6713       fromDDC = FALSE;
6714       if((pSiS->CRT2pScrn->monitor->nVrefresh <= 0) || (pSiS->OverruleRanges)) {
6715	  if((pSiS->CRT2pScrn->monitor->nVrefresh <= 0) && (pSiS->CRT2pScrn->monitor->DDC)) {
6716	     SiSSetSyncRangeFromEdid(pSiS->CRT2pScrn, 0);
6717	     if(pSiS->CRT2pScrn->monitor->nVrefresh > 0) {
6718		xf86DrvMsg(pScrn->scrnIndex, X_INFO, subsvstr, 2);
6719		fromDDC = TRUE;
6720	     }
6721          }
6722	  if((pSiS->CRT2pScrn->monitor->nVrefresh <= 0) || (pSiS->OverruleRanges)) {
6723	     if( (pSiS->VBFlags & CRT2_TV) ||
6724	         ((pSiS->VBFlags & CRT2_LCD) && (!fromDDC)) ) {
6725		Bool HaveNoRanges = (pSiS->CRT2pScrn->monitor->nVrefresh <= 0);
6726		/* Set sane ranges for LCD and TV */
6727		if((crt2freqoverruled = CheckAndOverruleV(pScrn, pSiS->CRT2pScrn->monitor))) {
6728		   xf86DrvMsg(pScrn->scrnIndex, X_INFO, sanev,
6729			 HaveNoRanges ? "missing" : "bogus", 2);
6730	        }
6731	     }
6732	  }
6733       }
6734
6735       backupddc = pSiS->CRT2pScrn->monitor->DDC;
6736
6737       /* Suppress bogus DDC warning */
6738       if(crt2freqoverruled) pSiS->CRT2pScrn->monitor->DDC = NULL;
6739
6740       pSiS->CheckForCRT2 = TRUE;
6741
6742       i = xf86ValidateModes(pSiS->CRT2pScrn, pSiS->CRT2pScrn->monitor->Modes,
6743			pSiS->CRT2pScrn->display->modes, clockRanges,
6744			NULL, 256, 4088,
6745			pSiS->CRT2pScrn->bitsPerPixel * 8, 128, 4096,
6746			pScrn->display->virtualX ? pScrn->virtualX : 0,
6747			pScrn->display->virtualY ? pScrn->virtualY : 0,
6748			pSiS->maxxfbmem,
6749			LOOKUP_BEST_REFRESH);
6750
6751       pSiS->CheckForCRT2 = FALSE;
6752       pSiS->CRT2pScrn->monitor->DDC = backupddc;
6753
6754       if(i == -1) {
6755	  SISErrorLog(pScrn, "xf86ValidateModes() error, %s.\n", mergeddisstr);
6756	  SiSFreeCRT2Structs(pSiS);
6757	  pSiS->MergedFB = FALSE;
6758       }
6759
6760    }
6761
6762    if(pSiS->MergedFB) {
6763
6764       if((p = first = pSiS->CRT2pScrn->modes)) {
6765          do {
6766	     n = p->next;
6767	     if( (pSiS->VGAEngine == SIS_300_VGA) &&
6768		 ( (strcmp(p->name, "320x200") == 0) ||
6769		   (strcmp(p->name, "320x240") == 0) ||
6770		   (strcmp(p->name, "400x300") == 0) ||
6771		   (strcmp(p->name, "512x384") == 0) ||
6772		   (strcmp(p->name, "640x400") == 0) ) )  {
6773		p->status = MODE_BAD;
6774		xf86DrvMsg(pScrn->scrnIndex, X_INFO, notsuitablestr, p->name, "MergedFB");
6775	     }
6776	     p = n;
6777	  } while (p != NULL && p != first);
6778       }
6779
6780       xf86PruneDriverModes(pSiS->CRT2pScrn);
6781
6782       if(i == 0 || pSiS->CRT2pScrn->modes == NULL) {
6783	  SISErrorLog(pScrn, "No valid modes found for CRT2; %s\n", mergeddisstr);
6784	  SiSFreeCRT2Structs(pSiS);
6785	  pSiS->MergedFB = FALSE;
6786       }
6787
6788    }
6789
6790    if(pSiS->MergedFB) {
6791
6792       xf86SetCrtcForModes(pSiS->CRT2pScrn, INTERLACE_HALVE_V);
6793
6794       xf86DrvMsg(pScrn->scrnIndex, X_INFO, modesforstr, 2);
6795
6796       if(pSiS->VBFlags & (CRT2_LCD | CRT2_TV)) {
6797	  SiSPrintModes(pSiS->CRT2pScrn);
6798       } else {
6799	  xf86PrintModes(pSiS->CRT2pScrn);
6800       }
6801
6802       pSiS->CRT1Modes = pScrn->modes;
6803       pSiS->CRT1CurrentMode = pScrn->currentMode;
6804
6805       xf86DrvMsg(pScrn->scrnIndex, X_INFO, "MergedFB: Generating mode list\n");
6806
6807       pScrn->modes = SiSGenerateModeList(pScrn, pSiS->MetaModes,
6808					  pSiS->CRT1Modes, pSiS->CRT2pScrn->modes,
6809					  pSiS->CRT2Position);
6810
6811       if(!pScrn->modes) {
6812
6813	  SISErrorLog(pScrn, "Failed to parse MetaModes or no modes found. %s.\n",
6814			mergeddisstr);
6815	  SiSFreeCRT2Structs(pSiS);
6816	  pScrn->modes = pSiS->CRT1Modes;
6817	  pSiS->CRT1Modes = NULL;
6818	  pSiS->MergedFB = FALSE;
6819
6820       }
6821
6822    }
6823
6824    if(pSiS->MergedFB) {
6825
6826       /* If no virtual dimension was given by the user,
6827	* calculate a sane one now. Adapts pScrn->virtualX,
6828	* pScrn->virtualY and pScrn->displayWidth.
6829	*/
6830       SiSRecalcDefaultVirtualSize(pScrn);
6831
6832       pScrn->modes = pScrn->modes->next;  /* We get the last from GenerateModeList(), skip to first */
6833       pScrn->currentMode = pScrn->modes;
6834
6835       /* Update CurrentLayout */
6836       pSiS->CurrentLayout.mode = pScrn->currentMode;
6837       pSiS->CurrentLayout.displayWidth = pScrn->displayWidth;
6838       pSiS->CurrentLayout.displayHeight = pScrn->virtualY;
6839
6840    }
6841#endif
6842
6843    /* Set display resolution */
6844#ifdef SISMERGED
6845    if(pSiS->MergedFB) {
6846       SiSMergedFBSetDpi(pScrn, pSiS->CRT2pScrn, pSiS->CRT2Position);
6847    } else
6848#endif
6849       xf86SetDpi(pScrn, 0, 0);
6850
6851    /* Load fb module */
6852    switch(pScrn->bitsPerPixel) {
6853      case 8:
6854      case 16:
6855      case 24:
6856      case 32:
6857	if(!xf86LoadSubModule(pScrn, "fb")) {
6858           SISErrorLog(pScrn, "Failed to load fb module");
6859	   goto my_error_1;
6860	}
6861	break;
6862      default:
6863	SISErrorLog(pScrn, "Unsupported framebuffer bpp (%d)\n", pScrn->bitsPerPixel);
6864	goto my_error_1;
6865    }
6866
6867    /* Load XAA/EXA (if needed) */
6868    if(!pSiS->NoAccel) {
6869#ifdef SIS_USE_XAA
6870       if(!pSiS->useEXA) {
6871	  if (!xf86LoadSubModule(pScrn, "xaa")) {
6872	      xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6873			 "Falling back to shadowfb\n");
6874	      pSiS->NoAccel = 1;
6875	      pSiS->ShadowFB = 1;
6876	  }
6877       }
6878#endif
6879#ifdef SIS_USE_EXA
6880       if(pSiS->useEXA) {
6881	  XF86ModReqInfo req;
6882	  int errmaj, errmin;
6883
6884	  memset(&req, 0, sizeof(req));
6885	  req.majorversion = 2;
6886	  req.minorversion = 0;
6887	  if (!LoadSubModule(pScrn->module, "exa", NULL, NULL, NULL, &req,
6888	    &errmaj, &errmin)) {
6889	    LoaderErrorMsg(NULL, "exa", errmaj, errmin);
6890	    goto my_error_1;
6891	  }
6892       }
6893#endif
6894    }
6895
6896    /* Load shadowfb (if needed) */
6897    if(pSiS->ShadowFB) {
6898       if(!xf86LoadSubModule(pScrn, "shadowfb")) {
6899	  SISErrorLog(pScrn, "Could not load shadowfb module\n");
6900	  goto my_error_1;
6901       }
6902    }
6903
6904    /* Load the dri and glx modules if requested. */
6905#ifdef SISDRI
6906    if(pSiS->loadDRI) {
6907       if(!xf86LoaderCheckSymbol("DRIScreenInit")) {
6908	  if(xf86LoadSubModule(pScrn, "dri")) {
6909	     if(!xf86LoaderCheckSymbol("GlxSetVisualConfigs")) {
6910	        if(!xf86LoadSubModule(pScrn, "glx")) {
6911		   SISErrorLog(pScrn, "Failed to load glx module\n");
6912		}
6913	     }
6914	  } else {
6915	     SISErrorLog(pScrn, "Failed to load dri module\n");
6916	  }
6917       }
6918    }
6919#endif
6920
6921    /* Now load and initialize VBE module for VESA mode switching */
6922    pSiS->UseVESA = 0;
6923    if(pSiS->VESA == 1) {
6924       SiS_LoadInitVBE(pScrn);
6925       if(pSiS->pVbe) {
6926	  VbeInfoBlock *vbe;
6927	  if((vbe = VBEGetVBEInfo(pSiS->pVbe))) {
6928	     pSiS->vesamajor = (unsigned)(vbe->VESAVersion >> 8);
6929	     pSiS->vesaminor = vbe->VESAVersion & 0xff;
6930	     SiSBuildVesaModeList(pScrn, pSiS->pVbe, vbe);
6931	     VBEFreeVBEInfo(vbe);
6932	     pSiS->UseVESA = 1;
6933	  } else {
6934	     xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
6935	     	 "Failed to read VBE Info Block\n");
6936	  }
6937       }
6938       if(pSiS->UseVESA == 0) {
6939	  xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
6940	      "VESA mode switching disabled.\n");
6941       }
6942    }
6943
6944    if(pSiS->pVbe) {
6945       vbeFree(pSiS->pVbe);
6946       pSiS->pVbe = NULL;
6947    }
6948
6949#ifdef SISDUALHEAD
6950    xf86SetPrimInitDone(pScrn->entityList[0]);
6951#endif
6952
6953    sisRestoreExtRegisterLock(pSiS,srlockReg,crlockReg);
6954
6955    if(pSiS->pInt) xf86FreeInt10(pSiS->pInt);
6956    pSiS->pInt = NULL;
6957
6958    if(pSiS->VGAEngine == SIS_315_VGA) {
6959       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTXVGAMMA1;
6960    }
6961
6962#ifdef SISDUALHEAD
6963    if(pSiS->DualHeadMode) {
6964	pSiS->SiS_SD_Flags |= SiS_SD_ISDUALHEAD;
6965	if(pSiS->SecondHead) pSiS->SiS_SD_Flags |= SiS_SD_ISDHSECONDHEAD;
6966	else		     pSiS->SiS_SD_Flags &= ~(SiS_SD_SUPPORTXVGAMMA1);
6967#ifdef PANORAMIX
6968	if(!noPanoramiXExtension) {
6969	   pSiS->SiS_SD_Flags |= SiS_SD_ISDHXINERAMA;
6970	   /* pSiS->SiS_SD_Flags &= ~(SiS_SD_SUPPORTXVGAMMA1); */
6971	}
6972#endif
6973    }
6974#endif
6975
6976#ifdef SISMERGED
6977    if(pSiS->MergedFB) pSiS->SiS_SD_Flags |= SiS_SD_ISMERGEDFB;
6978#endif
6979
6980    /* Try to determine if this is a laptop   */
6981    /* (only used for SiSCtrl visualisations) */
6982    pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPLTFLAG;
6983    pSiS->SiS_SD2_Flags &= ~SiS_SD2_ISLAPTOP;
6984    if(pSiS->detectedCRT2Devices & CRT2_LCD) {
6985       if(pSiS->VBFlags2 & (VB2_SISLVDSBRIDGE | VB2_LVDS | VB2_30xBDH)) {
6986	  /* 1. By bridge type: LVDS in 99% of all cases;
6987	   * exclude unusual setups like Barco projectors
6988	   * and parallel flat panels. TODO: Exclude
6989	   * Sony W1, V1.
6990	   */
6991	  if((pSiS->SiS_Pr->SiS_CustomT != CUT_BARCO1366) &&
6992	     (pSiS->SiS_Pr->SiS_CustomT != CUT_BARCO1024) &&
6993	     (pSiS->SiS_Pr->SiS_CustomT != CUT_PANEL848)  &&
6994	     (pSiS->SiS_Pr->SiS_CustomT != CUT_PANEL856)  &&
6995	     (pSiS->SiS_Pr->SiS_CustomT != CUT_AOP8060)   &&
6996	     ( (pSiS->ChipType != SIS_550) ||
6997	       (!pSiS->DSTN && !pSiS->FSTN) ) ) {
6998	     pSiS->SiS_SD2_Flags |= SiS_SD2_ISLAPTOP;
6999	  }
7000       } else if((pSiS->VBFlags2 & (VB2_301 | VB2_301C)) &&
7001                 (pSiS->VBLCDFlags & (VB_LCD_1280x960  |
7002				      VB_LCD_1400x1050 |
7003				      VB_LCD_1024x600  |
7004				      VB_LCD_1280x800  |
7005				      VB_LCD_1280x854))) {
7006	  /* 2. By (odd) LCD resolutions on TMDS bridges
7007	   * (eg Averatec). TODO: Exclude IBM Netvista.
7008	   */
7009	  pSiS->SiS_SD2_Flags |= SiS_SD2_ISLAPTOP;
7010       }
7011    }
7012
7013    if(pSiS->enablesisctrl) pSiS->SiS_SD_Flags |= SiS_SD_ENABLED;
7014
7015    pSiS->currentModeLast = pScrn->currentMode;
7016    pSiS->VBFlagsInit = pSiS->VBFlags;
7017
7018    return TRUE;
7019
7020    /* ---- */
7021
7022my_error_1:
7023    sisRestoreExtRegisterLock(pSiS, srlockReg, crlockReg);
7024my_error_0:
7025#ifdef SISDUALHEAD
7026    if(pSiSEnt) pSiSEnt->ErrorAfterFirst = TRUE;
7027#endif
7028    if(pSiS->pInt) xf86FreeInt10(pSiS->pInt);
7029    pSiS->pInt = NULL;
7030    SISFreeRec(pScrn);
7031    return FALSE;
7032}
7033
7034/*
7035 * Map I/O port area for non-PC platforms
7036 */
7037#ifdef SIS_NEED_MAP_IOP
7038static Bool
7039SISMapIOPMem(ScrnInfoPtr pScrn)
7040{
7041    SISPtr pSiS = SISPTR(pScrn);
7042#ifdef SISDUALHEAD
7043    SISEntPtr pSiSEnt = pSiS->entityPrivate;
7044
7045    if(pSiS->DualHeadMode) {
7046        pSiSEnt->MapCountIOPBase++;
7047        if(!(pSiSEnt->IOPBase)) {
7048	     /* Only map if not mapped previously */
7049#ifndef XSERVER_LIBPCIACCESS
7050	     pSiSEnt->IOPBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
7051			pSiS->PciTag, pSiS->IOPAddress, 128);
7052#else
7053	     {
7054	       void **result = (void **)&pSiSEnt->IOPBase;
7055	       int err = pci_device_map_range(pSiS->PciInfo,
7056					      pSiS->IOPAddress,
7057					      128,
7058					      PCI_DEV_MAP_FLAG_WRITABLE,
7059					      result);
7060
7061	       if (err) {
7062                 xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
7063                             "Unable to map IO aperture. %s (%d)\n",
7064                             strerror (err), err);
7065	       }
7066	     }
7067#endif
7068        }
7069        pSiS->IOPBase = pSiSEnt->IOPBase;
7070    } else
7071#endif
7072#ifndef XSERVER_LIBPCIACCESS
7073	     pSiS->IOPBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
7074					   pSiS->PciTag, pSiS->IOPAddress, 128);
7075#else
7076	     {
7077	       void **result = (void **)&pSiS->IOPBase;
7078	       int err = pci_device_map_range(pSiS->PciInfo,
7079					      pSiS->IOPAddress,
7080					      128,
7081					      PCI_DEV_MAP_FLAG_WRITABLE,
7082					      result);
7083
7084	       if (err) {
7085                 xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
7086                             "Unable to map IO aperture. %s (%d)\n",
7087                             strerror (err), err);
7088	       }
7089	     }
7090#endif
7091    if(pSiS->IOPBase == NULL) {
7092	SISErrorLog(pScrn, "Could not map I/O port area\n");
7093	return FALSE;
7094    }
7095
7096    return TRUE;
7097}
7098
7099static Bool
7100SISUnmapIOPMem(ScrnInfoPtr pScrn)
7101{
7102    SISPtr pSiS = SISPTR(pScrn);
7103#ifdef SISDUALHEAD
7104    SISEntPtr pSiSEnt = pSiS->entityPrivate;;
7105#endif
7106
7107/* In dual head mode, we must not unmap if the other head still
7108 * assumes memory as mapped
7109 */
7110#ifdef SISDUALHEAD
7111    if(pSiS->DualHeadMode) {
7112        if(pSiSEnt->MapCountIOPBase) {
7113	    pSiSEnt->MapCountIOPBase--;
7114	    if((pSiSEnt->MapCountIOPBase == 0) || (pSiSEnt->forceUnmapIOPBase)) {
7115		xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiSEnt->IOPBase, 2048);
7116		pSiSEnt->IOPBase = NULL;
7117		pSiSEnt->MapCountIOPBase = 0;
7118		pSiSEnt->forceUnmapIOPBase = FALSE;
7119	    }
7120	    pSiS->IOPBase = NULL;
7121	}
7122    } else {
7123#endif
7124	xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiS->IOPBase, 2048);
7125	pSiS->IOPBase = NULL;
7126#ifdef SISDUALHEAD
7127    }
7128#endif
7129    return TRUE;
7130}
7131#endif
7132
7133/*
7134 * Map the framebuffer and MMIO memory
7135 */
7136
7137static Bool
7138SISMapMem(ScrnInfoPtr pScrn)
7139{
7140    SISPtr pSiS = SISPTR(pScrn);
7141#ifndef XSERVER_LIBPCIACCESS
7142    int mmioFlags = VIDMEM_MMIO;
7143#endif
7144#ifdef SISDUALHEAD
7145    SISEntPtr pSiSEnt = pSiS->entityPrivate;
7146#endif
7147
7148    /*
7149     * Map IO registers to virtual address space
7150     * (For Alpha, we need to map SPARSE memory, since we need
7151     * byte/short access.)
7152     */
7153#ifndef XSERVER_LIBPCIACCESS
7154#if defined(__alpha__)
7155    mmioFlags |= VIDMEM_SPARSE;
7156#endif
7157#endif
7158
7159#ifdef SISDUALHEAD
7160    if(pSiS->DualHeadMode) {
7161        pSiSEnt->MapCountIOBase++;
7162        if(!(pSiSEnt->IOBase)) {
7163	     /* Only map if not mapped previously */
7164#ifndef XSERVER_LIBPCIACCESS
7165    	     pSiSEnt->IOBase = xf86MapPciMem(pScrn->scrnIndex, mmioFlags,
7166                         pSiS->PciTag, pSiS->IOAddress, (pSiS->mmioSize * 1024));
7167#else
7168	     void **result = (void **)&pSiSEnt->IOBase;
7169	     int err = pci_device_map_range(pSiS->PciInfo,
7170 	                                    pSiS->IOAddress,
7171	                                    (pSiS->mmioSize * 1024),
7172                                            PCI_DEV_MAP_FLAG_WRITABLE,
7173                                            result);
7174
7175             if (err) {
7176                 xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
7177                             "Unable to map IO aperture. %s (%d)\n",
7178                             strerror (err), err);
7179	     }
7180#endif
7181        }
7182        pSiS->IOBase = pSiSEnt->IOBase;
7183    } else
7184#endif
7185#ifndef XSERVER_LIBPCIACCESS
7186    	pSiS->IOBase = xf86MapPciMem(pScrn->scrnIndex, mmioFlags,
7187                        pSiS->PciTag, pSiS->IOAddress, (pSiS->mmioSize * 1024));
7188#else
7189       {
7190	     void **result = (void **)&pSiS->IOBase;
7191	     int err = pci_device_map_range(pSiS->PciInfo,
7192 	                                    pSiS->IOAddress,
7193	                                    (pSiS->mmioSize * 1024),
7194                                            PCI_DEV_MAP_FLAG_WRITABLE,
7195                                            result);
7196
7197             if (err) {
7198                 xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
7199                             "Unable to map IO aperture. %s (%d)\n",
7200                             strerror (err), err);
7201	     }
7202       }
7203#endif
7204
7205    if(pSiS->IOBase == NULL) {
7206    	SISErrorLog(pScrn, "Could not map MMIO area\n");
7207        return FALSE;
7208    }
7209
7210#ifdef __alpha__
7211    /*
7212     * for Alpha, we need to map DENSE memory as well, for
7213     * setting CPUToScreenColorExpandBase.
7214     */
7215#ifdef SISDUALHEAD
7216    if(pSiS->DualHeadMode) {
7217        pSiSEnt->MapCountIOBaseDense++;
7218        if(!(pSiSEnt->IOBaseDense)) {
7219	     /* Only map if not mapped previously */
7220#ifndef XSERVER_LIBPCIACCESS
7221	     pSiSEnt->IOBaseDense = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
7222                    pSiS->PciTag, pSiS->IOAddress, (pSiS->mmioSize * 1024));
7223#else
7224	     void **result = (void **)&pSiSEnt->IOBaseDense;
7225	     int err = pci_device_map_range(pSiS->PciInfo,
7226 	                                    pSiS->IOAddress,
7227	                                    (pSiS->mmioSize * 1024),
7228                                            PCI_DEV_MAP_FLAG_WRITABLE,
7229                                            result);
7230
7231             if (err) {
7232                 xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
7233                             "Unable to map IO dense aperture. %s (%d)\n",
7234                             strerror (err), err);
7235	     }
7236#endif /* XSERVER_LIBPCIACCESS */
7237	}
7238	pSiS->IOBaseDense = pSiSEnt->IOBaseDense;
7239    } else {
7240#endif /* SISDUALHEAD */
7241#ifndef XSERVER_LIBPCIACCESS
7242	     pSiS->IOBaseDense = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
7243                    pSiS->PciTag, pSiS->IOAddress, (pSiS->mmioSize * 1024));
7244#else
7245	     void **result = (void **)&pSiS->IOBaseDense;
7246	     int err = pci_device_map_range(pSiS->PciInfo,
7247 	                                    pSiS->IOAddress,
7248	                                    (pSiS->mmioSize * 1024),
7249                                            PCI_DEV_MAP_FLAG_WRITABLE,
7250                                            result);
7251
7252             if (err) {
7253                 xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
7254                             "Unable to map IO dense aperture. %s (%d)\n",
7255                             strerror (err), err);
7256	     }
7257#endif /* XSERVER_LIBPCIACCESS */
7258#ifdef SISDUALHEAD
7259    }
7260#endif
7261    if(pSiS->IOBaseDense == NULL) {
7262       SISErrorLog(pScrn, "Could not map MMIO dense area\n");
7263       return FALSE;
7264    }
7265#endif /* __alpha__ */
7266
7267#ifdef SISDUALHEAD
7268    if(pSiS->DualHeadMode) {
7269	pSiSEnt->MapCountFbBase++;
7270	if(!(pSiSEnt->FbBase)) {
7271	     /* Only map if not mapped previously */
7272#ifndef XSERVER_LIBPCIACCESS
7273	     pSiSEnt->FbBase = pSiSEnt->RealFbBase =
7274			xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
7275			 pSiS->PciTag, (ULong)pSiS->realFbAddress,
7276			 pSiS->FbMapSize);
7277#else
7278         int err = pci_device_map_range(pSiS->PciInfo,
7279                                   (ULong)pSiS->realFbAddress,
7280                                   pSiS->FbMapSize,
7281                                   PCI_DEV_MAP_FLAG_WRITABLE |
7282                                   PCI_DEV_MAP_FLAG_WRITE_COMBINE,
7283                                   (void *)&pSiSEnt->FbBase);
7284	if (err) {
7285            xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
7286                        "Unable to map FB aperture. %s (%d)\n",
7287                        strerror (err), err);
7288            return FALSE;
7289        }
7290	pSiSEnt->RealFbBase = pSiSEnt->FbBase;
7291#endif
7292	}
7293	pSiS->FbBase = pSiS->RealFbBase = pSiSEnt->FbBase;
7294	/* Adapt FbBase (for DHM and SiS76x UMA skipping; dhmOffset is 0 otherwise) */
7295	pSiS->FbBase += pSiS->dhmOffset;
7296    } else {
7297#endif
7298
7299#ifndef XSERVER_LIBPCIACCESS
7300      pSiS->FbBase = pSiS->RealFbBase =
7301			xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
7302			 pSiS->PciTag, (ULong)pSiS->realFbAddress,
7303			 pSiS->FbMapSize);
7304#else
7305         int err = pci_device_map_range(pSiS->PciInfo,
7306                                   (ULong)pSiS->realFbAddress,
7307                                   pSiS->FbMapSize,
7308                                   PCI_DEV_MAP_FLAG_WRITABLE |
7309                                   PCI_DEV_MAP_FLAG_WRITE_COMBINE,
7310                                   (void *)&pSiS->FbBase);
7311	if (err) {
7312            xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
7313                        "Unable to map FB aperture. %s (%d)\n",
7314                        strerror (err), err);
7315            return FALSE;
7316        }
7317	pSiS->RealFbBase = pSiS->FbBase;
7318#endif
7319	pSiS->FbBase += pSiS->dhmOffset;
7320
7321#ifdef SISDUALHEAD
7322    }
7323#endif
7324
7325    if(pSiS->FbBase == NULL) {
7326       SISErrorLog(pScrn, "Could not map framebuffer area\n");
7327       return FALSE;
7328    }
7329
7330#ifdef TWDEBUG
7331    xf86DrvMsg(0, 0, "Framebuffer mapped to %p\n", pSiS->FbBase);
7332#endif
7333
7334    return TRUE;
7335}
7336
7337
7338/*
7339 * Unmap the framebuffer and MMIO memory.
7340 */
7341
7342static Bool
7343SISUnmapMem(ScrnInfoPtr pScrn)
7344{
7345    SISPtr pSiS = SISPTR(pScrn);
7346#ifdef SISDUALHEAD
7347    SISEntPtr pSiSEnt = pSiS->entityPrivate;
7348#endif
7349
7350/* In dual head mode, we must not unmap if the other head still
7351 * assumes memory as mapped
7352 */
7353#ifdef SISDUALHEAD
7354    if(pSiS->DualHeadMode) {
7355        if(pSiSEnt->MapCountIOBase) {
7356	    pSiSEnt->MapCountIOBase--;
7357	    if((pSiSEnt->MapCountIOBase == 0) || (pSiSEnt->forceUnmapIOBase)) {
7358#ifndef XSERVER_LIBPCIACCESS
7359		xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiSEnt->IOBase, (pSiS->mmioSize * 1024));
7360#else
7361	        pci_device_unmap_range(pSiS->PciInfo, pSiSEnt->IOBase, (pSiS->mmioSize * 1024));
7362#endif
7363		pSiSEnt->IOBase = NULL;
7364		pSiSEnt->MapCountIOBase = 0;
7365		pSiSEnt->forceUnmapIOBase = FALSE;
7366	    }
7367	    pSiS->IOBase = NULL;
7368	}
7369#ifdef __alpha__
7370	if(pSiSEnt->MapCountIOBaseDense) {
7371	    pSiSEnt->MapCountIOBaseDense--;
7372	    if((pSiSEnt->MapCountIOBaseDense == 0) || (pSiSEnt->forceUnmapIOBaseDense)) {
7373#ifndef XSERVER_LIBPCIACCESS
7374		xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiSEnt->IOBaseDense, (pSiS->mmioSize * 1024));
7375#else
7376		pci_device_unmap_range(pSiS->PciInfo, (pointer)pSiSEnt->IOBaseDense, (pSiS->mmioSize * 1024));
7377#endif
7378		pSiSEnt->IOBaseDense = NULL;
7379		pSiSEnt->MapCountIOBaseDense = 0;
7380		pSiSEnt->forceUnmapIOBaseDense = FALSE;
7381	    }
7382	    pSiS->IOBaseDense = NULL;
7383	}
7384#endif /* __alpha__ */
7385	if(pSiSEnt->MapCountFbBase) {
7386	    pSiSEnt->MapCountFbBase--;
7387	    if((pSiSEnt->MapCountFbBase == 0) || (pSiSEnt->forceUnmapFbBase)) {
7388#ifndef XSERVER_LIBPCIACCESS
7389		xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiSEnt->RealFbBase, pSiS->FbMapSize);
7390#else
7391		pci_device_unmap_range(pSiS->PciInfo, (pointer)pSiSEnt->RealFbBase, pSiS->FbMapSize);
7392#endif
7393		pSiSEnt->FbBase = pSiSEnt->RealFbBase = NULL;
7394		pSiSEnt->MapCountFbBase = 0;
7395		pSiSEnt->forceUnmapFbBase = FALSE;
7396
7397	    }
7398	    pSiS->FbBase = pSiS->RealFbBase = NULL;
7399	}
7400    } else {
7401#endif
7402#ifndef XSERVER_LIBPCIACCESS
7403	xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiS->IOBase, (pSiS->mmioSize * 1024));
7404#else
7405	pci_device_unmap_range(pSiS->PciInfo, (pointer)pSiS->IOBase, (pSiS->mmioSize * 1024));
7406#endif
7407	pSiS->IOBase = NULL;
7408#ifdef __alpha__
7409#ifndef XSERVER_LIBPCIACCESS
7410	xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiS->IOBaseDense, (pSiS->mmioSize * 1024));
7411#else
7412	pci_device_unmap_range(pSiS->PciInfo, (pointer)pSiS->IOBaseDense, (pSiS->mmioSize * 1024));
7413#endif
7414	pSiS->IOBaseDense = NULL;
7415#endif
7416#ifndef XSERVER_LIBPCIACCESS
7417	xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiS->RealFbBase, pSiS->FbMapSize);
7418#else
7419	pci_device_unmap_range(pSiS->PciInfo, (pointer)pSiS->RealFbBase, pSiS->FbMapSize);
7420#endif
7421	pSiS->FbBase = pSiS->RealFbBase = NULL;
7422#ifdef SISDUALHEAD
7423    }
7424#endif
7425    return TRUE;
7426}
7427
7428/*
7429 * This function saves the video state.
7430 */
7431static void
7432SISSave(ScrnInfoPtr pScrn)
7433{
7434    SISPtr pSiS = SISPTR(pScrn);
7435    SISRegPtr sisReg;
7436    int flags;
7437
7438#ifdef SISDUALHEAD
7439    /* We always save master & slave */
7440    if(pSiS->DualHeadMode && pSiS->SecondHead) return;
7441#endif
7442
7443    sisReg = &pSiS->SavedReg;
7444
7445    if( ((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) &&
7446        ((pSiS->VBFlags2 & VB2_VIDEOBRIDGE) && (SiSBridgeIsInSlaveMode(pScrn))) ) {
7447       SiSVGASave(pScrn, sisReg, SISVGA_SR_CMAP | SISVGA_SR_MODE);
7448#ifdef SIS_PC_PLATFORM
7449       if(pSiS->VGAMemBase) {
7450          SiSRegInit(pSiS->SiS_Pr, pSiS->RelIO+0x30);
7451          SiSSetLVDSetc(pSiS->SiS_Pr);
7452          SiS_GetVBType(pSiS->SiS_Pr);
7453          SiS_DisableBridge(pSiS->SiS_Pr);
7454          SiSVGASave(pScrn, sisReg, SISVGA_SR_FONTS);
7455          SiS_EnableBridge(pSiS->SiS_Pr);
7456       }
7457#endif
7458    } else {
7459       flags = SISVGA_SR_CMAP | SISVGA_SR_MODE;
7460#ifdef SIS_PC_PLATFORM
7461       if(pSiS->VGAMemBase) flags |= SISVGA_SR_FONTS;
7462#endif
7463       SiSVGASave(pScrn, sisReg, flags);
7464    }
7465
7466    sisSaveUnlockExtRegisterLock(pSiS, &sisReg->sisRegs3C4[0x05], &sisReg->sisRegs3D4[0x80]);
7467
7468    (*pSiS->SiSSave)(pScrn, sisReg);
7469
7470    if(pSiS->UseVESA) SISVESASaveRestore(pScrn, MODE_SAVE);
7471
7472    /* "Save" these again as they may have been changed prior to SISSave() call */
7473    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
7474       sisReg->sisRegs3C4[0x1f] = pSiS->oldSR1F;
7475       sisReg->sisRegs3D4[0x17] = pSiS->oldCR17;
7476       sisReg->sisRegs3D4[0x32] = pSiS->oldCR32;
7477       sisReg->sisRegs3D4[0x36] = pSiS->oldCR36;
7478       sisReg->sisRegs3D4[0x37] = pSiS->oldCR37;
7479       if(pSiS->VGAEngine == SIS_315_VGA) {
7480	  sisReg->sisRegs3D4[pSiS->myCR63] = pSiS->oldCR63;
7481       }
7482    }
7483}
7484
7485/* VESASaveRestore taken from vesa driver */
7486static void
7487SISVESASaveRestore(ScrnInfoPtr pScrn, vbeSaveRestoreFunction function)
7488{
7489    SISPtr pSiS = SISPTR(pScrn);
7490
7491    /* Query amount of memory to save state */
7492    if((function == MODE_QUERY) ||
7493       (function == MODE_SAVE && pSiS->state == NULL)) {
7494
7495       /* Make sure we save at least this information in case of failure */
7496       (void)VBEGetVBEMode(pSiS->pVbe, &pSiS->stateMode);
7497       SiSVGASaveFonts(pScrn);
7498
7499       if(pSiS->vesamajor > 1) {
7500	  if(!VBESaveRestore(pSiS->pVbe, function, (pointer)&pSiS->state,
7501				&pSiS->stateSize, &pSiS->statePage)) {
7502	     return;
7503	  }
7504       }
7505    }
7506
7507    /* Save/Restore Super VGA state */
7508    if(function != MODE_QUERY) {
7509
7510       if(pSiS->vesamajor > 1) {
7511	  if(function == MODE_RESTORE) {
7512	     memcpy(pSiS->state, pSiS->pstate, pSiS->stateSize);
7513	  }
7514
7515	  if(VBESaveRestore(pSiS->pVbe,function,(pointer)&pSiS->state,
7516			    &pSiS->stateSize,&pSiS->statePage) &&
7517	     (function == MODE_SAVE)) {
7518	     /* don't rely on the memory not being touched */
7519	     if(!pSiS->pstate) {
7520		pSiS->pstate = malloc(pSiS->stateSize);
7521	     }
7522	     memcpy(pSiS->pstate, pSiS->state, pSiS->stateSize);
7523	  }
7524       }
7525
7526       if(function == MODE_RESTORE) {
7527	  VBESetVBEMode(pSiS->pVbe, pSiS->stateMode, NULL);
7528	  SiSVGARestoreFonts(pScrn);
7529       }
7530
7531    }
7532}
7533
7534/*
7535 * Initialise a new mode.  This is currently done using the
7536 * "initialise struct, restore/write struct to HW" model for
7537 * the old chipsets (5597/530/6326). For newer chipsets,
7538 * we use our own mode switching code.
7539 */
7540
7541static Bool
7542SISModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
7543{
7544    SISPtr pSiS = SISPTR(pScrn);
7545    SISRegPtr sisReg;
7546#ifdef SISDUALHEAD
7547    SISEntPtr pSiSEnt = NULL;
7548#endif
7549
7550    andSISIDXREG(SISCR,0x11,0x7f);	/* Unlock CRTC registers */
7551
7552    SISModifyModeInfo(mode);		/* Quick check of the mode parameters */
7553
7554    if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
7555       SiSRegInit(pSiS->SiS_Pr, pSiS->RelIO+0x30);
7556    }
7557
7558    if(pSiS->UseVESA) {  /* With VESA: */
7559
7560#ifdef SISDUALHEAD
7561       /* No dual head mode when using VESA */
7562       if(pSiS->SecondHead) return TRUE;
7563#endif
7564
7565       pScrn->vtSema = TRUE;
7566
7567       /*
7568	* This order is required:
7569	* The video bridge needs to be adjusted before the
7570	* BIOS is run as the BIOS sets up CRT2 according to
7571	* these register settings.
7572	* After the BIOS is run, the bridges and turboqueue
7573	* registers need to be readjusted as the BIOS may
7574	* very probably have messed them up.
7575	*/
7576       if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
7577	  SiSPreSetMode(pScrn, mode, SIS_MODE_SIMU);
7578       }
7579       if(!SiSSetVESAMode(pScrn, mode)) {
7580	  SISErrorLog(pScrn, "SiSSetVESAMode() failed\n");
7581	  return FALSE;
7582       }
7583       sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
7584       if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
7585	  SiSPreSetMode(pScrn, mode, SIS_MODE_SIMU);
7586	  SiSPostSetMode(pScrn, &pSiS->ModeReg);
7587       }
7588#ifdef TWDEBUG
7589       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
7590		   "REAL REGISTER CONTENTS AFTER SETMODE:\n");
7591#endif
7592       if(!(*pSiS->ModeInit)(pScrn, mode)) {
7593	  SISErrorLog(pScrn, "ModeInit() failed\n");
7594	  return FALSE;
7595       }
7596
7597       SiSVGAProtect(pScrn, TRUE);
7598       (*pSiS->SiSRestore)(pScrn, &pSiS->ModeReg);
7599       SiSVGAProtect(pScrn, FALSE);
7600
7601    } else { /* Without VESA: */
7602
7603#ifdef SISDUALHEAD
7604       if(pSiS->DualHeadMode) {
7605
7606	  if(!(*pSiS->ModeInit)(pScrn, mode)) {
7607	     SISErrorLog(pScrn, "ModeInit() failed\n");
7608	     return FALSE;
7609	  }
7610
7611	  pScrn->vtSema = TRUE;
7612
7613	  pSiSEnt = pSiS->entityPrivate;
7614
7615	  if(!(pSiS->SecondHead)) {
7616	     /* Head 1 (master) is always CRT2 */
7617	     SiSPreSetMode(pScrn, mode, SIS_MODE_CRT2);
7618	     if(!SiSBIOSSetModeCRT2(pSiS->SiS_Pr, pScrn, mode, pSiS->IsCustom)) {
7619		SISErrorLog(pScrn, "SiSBIOSSetModeCRT2() failed\n");
7620		return FALSE;
7621	     }
7622	     SiSPostSetMode(pScrn, &pSiS->ModeReg);
7623	     if(pSiSEnt->pScrn_2) {
7624		SISAdjustFrame(ADJUST_FRAME_ARGS(pSiSEnt->pScrn_2,
7625			       pSiSEnt->pScrn_2->frameX0,
7626						 pSiSEnt->pScrn_2->frameY0));
7627	     }
7628	  } else {
7629	     /* Head 2 (slave) is always CRT1 */
7630	     SiSPreSetMode(pScrn, mode, SIS_MODE_CRT1);
7631	     if(!SiSBIOSSetModeCRT1(pSiS->SiS_Pr, pScrn, mode, pSiS->IsCustom)) {
7632		SISErrorLog(pScrn, "SiSBIOSSetModeCRT1() failed\n");
7633		return FALSE;
7634	     }
7635	     SiSPostSetMode(pScrn, &pSiS->ModeReg);
7636	     if(pSiSEnt->pScrn_1) {
7637		SISAdjustFrame(ADJUST_FRAME_ARGS(pSiSEnt->pScrn_1,
7638			       pSiSEnt->pScrn_1->frameX0,
7639			       pSiSEnt->pScrn_1->frameY0));
7640	     }
7641	  }
7642
7643       } else {
7644#endif
7645
7646	  if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
7647
7648	     if(!(*pSiS->ModeInit)(pScrn, mode)) {
7649		SISErrorLog(pScrn, "ModeInit() failed\n");
7650	        return FALSE;
7651	     }
7652
7653	     pScrn->vtSema = TRUE;
7654
7655#ifdef SISMERGED
7656	     if(pSiS->MergedFB) {
7657
7658		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Setting MergedFB mode %dx%d\n",
7659				mode->HDisplay, mode->VDisplay);
7660
7661		SiSPreSetMode(pScrn, mode, SIS_MODE_CRT1);
7662
7663		if(!SiSBIOSSetModeCRT1(pSiS->SiS_Pr, pScrn,
7664		                       ((SiSMergedDisplayModePtr)mode->Private)->CRT1,
7665				       pSiS->IsCustom)) {
7666		   SISErrorLog(pScrn, "SiSBIOSSetModeCRT1() failed\n");
7667		   return FALSE;
7668		}
7669
7670		SiSPreSetMode(pScrn, mode, SIS_MODE_CRT2);
7671
7672		if(!SiSBIOSSetModeCRT2(pSiS->SiS_Pr, pScrn,
7673		                       ((SiSMergedDisplayModePtr)mode->Private)->CRT2,
7674				       pSiS->IsCustom)) {
7675		   SISErrorLog(pScrn, "SiSBIOSSetModeCRT2() failed\n");
7676		   return FALSE;
7677		}
7678
7679	     } else {
7680#endif
7681
7682		if((pSiS->VBFlags & CRT1_LCDA) || (!(mode->type & M_T_DEFAULT))) {
7683
7684		   SiSPreSetMode(pScrn, mode, SIS_MODE_CRT1);
7685
7686		   if(!SiSBIOSSetModeCRT1(pSiS->SiS_Pr, pScrn,
7687				mode, pSiS->IsCustom)) {
7688		      SISErrorLog(pScrn, "SiSBIOSSetModeCRT1() failed\n");
7689		      return FALSE;
7690		   }
7691
7692		   SiSPreSetMode(pScrn, mode, SIS_MODE_CRT2);
7693
7694		   if(!SiSBIOSSetModeCRT2(pSiS->SiS_Pr, pScrn,
7695				mode, pSiS->IsCustom)) {
7696		      SISErrorLog(pScrn, "SiSBIOSSetModeCRT2() failed\n");
7697		      return FALSE;
7698		   }
7699
7700		} else {
7701
7702		   SiSPreSetMode(pScrn, mode, SIS_MODE_SIMU);
7703
7704		   if(!SiSBIOSSetMode(pSiS->SiS_Pr, pScrn,
7705				mode, pSiS->IsCustom)) {
7706		      SISErrorLog(pScrn, "SiSBIOSSetMode() failed\n");
7707		      return FALSE;
7708		   }
7709
7710		}
7711
7712#ifdef SISMERGED
7713	     }
7714#endif
7715
7716	     SiSPostSetMode(pScrn, &pSiS->ModeReg);
7717
7718#ifdef TWDEBUG
7719	     xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VBFlags %lx\n", pSiS->VBFlags);
7720	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
7721			"REAL REGISTER CONTENTS AFTER SETMODE:\n");
7722             (*pSiS->ModeInit)(pScrn, mode);
7723#endif
7724
7725	  } else {
7726
7727	     /* For other chipsets, use the old method */
7728
7729	     /* Prepare the register contents */
7730	     if(!(*pSiS->ModeInit)(pScrn, mode)) {
7731	        SISErrorLog(pScrn, "ModeInit() failed\n");
7732	        return FALSE;
7733	     }
7734
7735	     pScrn->vtSema = TRUE;
7736
7737	     /* Program the registers */
7738	     SiSVGAProtect(pScrn, TRUE);
7739	     sisReg = &pSiS->ModeReg;
7740
7741	     sisReg->sisRegsATTR[0x10] = 0x01;
7742	     if(pScrn->bitsPerPixel > 8) {
7743		sisReg->sisRegsGR[0x05] = 0x00;
7744	     }
7745
7746	     SiSVGARestore(pScrn, sisReg, SISVGA_SR_MODE);
7747
7748	     (*pSiS->SiSRestore)(pScrn, sisReg);
7749
7750	     if((pSiS->Chipset == PCI_CHIP_SIS6326) && (pSiS->SiS6326Flags & SIS6326_HASTV)) {
7751	        SiS6326PostSetMode(pScrn, &pSiS->ModeReg);
7752	     }
7753
7754#ifdef TWDEBUG
7755	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
7756			"REAL REGISTER CONTENTS AFTER SETMODE:\n");
7757	     (*pSiS->ModeInit)(pScrn, mode);
7758#endif
7759
7760	     SiSVGAProtect(pScrn, FALSE);
7761
7762	  }
7763
7764#ifdef SISDUALHEAD
7765       }
7766#endif
7767    }
7768
7769    /* Update Currentlayout */
7770    pSiS->CurrentLayout.mode = pSiS->currentModeLast = mode;
7771
7772    return TRUE;
7773}
7774
7775static Bool
7776SiSSetVESAMode(ScrnInfoPtr pScrn, DisplayModePtr pMode)
7777{
7778    SISPtr pSiS;
7779    int mode;
7780
7781    pSiS = SISPTR(pScrn);
7782
7783    if(!(mode = SiSCalcVESAModeIndex(pScrn, pMode))) return FALSE;
7784
7785    mode |= (1 << 15);	/* Don't clear framebuffer */
7786    mode |= (1 << 14); 	/* Use linear adressing */
7787
7788    if(VBESetVBEMode(pSiS->pVbe, mode, NULL) == FALSE) {
7789       SISErrorLog(pScrn, "Setting VESA mode 0x%x failed\n",
7790	             	mode & 0x0fff);
7791       return (FALSE);
7792    }
7793
7794    if(pMode->HDisplay != pScrn->virtualX) {
7795       VBESetLogicalScanline(pSiS->pVbe, pScrn->virtualX);
7796    }
7797
7798    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
7799    	"Setting VESA mode 0x%x succeeded\n",
7800	mode & 0x0fff);
7801
7802    return (TRUE);
7803}
7804
7805static void
7806SISSpecialRestore(ScrnInfoPtr pScrn)
7807{
7808    SISPtr    pSiS = SISPTR(pScrn);
7809    SISRegPtr sisReg = &pSiS->SavedReg;
7810    UChar temp;
7811    int i;
7812
7813    /* 1.11.04 and later for 651 and 301B(DH) do strange register
7814     * fiddling after the usual mode change. This happens
7815     * depending on the result of a call of int 2f (with
7816     * ax=0x1680) and if modeno <= 0x13. I have no idea if
7817     * that is specific for the 651 or that very machine.
7818     * So this perhaps requires some more checks in the beginning
7819     * (although it should not do any harm on other chipsets/bridges
7820     * etc.) However, even if I call the VBE to restore mode 0x03,
7821     * these registers don't get restored correctly, possibly
7822     * because that int-2f-call for some reason results non-zero. So
7823     * what I do here is to restore these few registers
7824     * manually.
7825     */
7826
7827    if(!(pSiS->ChipFlags & SiSCF_Is65x)) return;
7828    inSISIDXREG(SISCR, 0x34, temp);
7829    temp &= 0x7f;
7830    if(temp > 0x13) return;
7831
7832#ifdef UNLOCK_ALWAYS
7833    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
7834#endif
7835
7836    SiS_UnLockCRT2(pSiS->SiS_Pr);
7837
7838    outSISIDXREG(SISCAP, 0x3f, sisReg->sisCapt[0x3f]);
7839    outSISIDXREG(SISCAP, 0x00, sisReg->sisCapt[0x00]);
7840    for(i = 0; i < 0x4f; i++) {
7841       outSISIDXREG(SISCAP, i, sisReg->sisCapt[i]);
7842    }
7843    outSISIDXREG(SISVID, 0x32, (sisReg->sisVid[0x32] & ~0x05));
7844    outSISIDXREG(SISVID, 0x30, sisReg->sisVid[0x30]);
7845    outSISIDXREG(SISVID, 0x32, ((sisReg->sisVid[0x32] & ~0x04) | 0x01));
7846    outSISIDXREG(SISVID, 0x30, sisReg->sisVid[0x30]);
7847
7848    if(!(pSiS->ChipFlags & SiSCF_Is651)) return;
7849    if(!(pSiS->VBFlags2 & VB2_SISBRIDGE)) return;
7850
7851    inSISIDXREG(SISCR, 0x30, temp);
7852    if(temp & 0x40) {
7853       UChar myregs[] = {
7854       		0x2f, 0x08, 0x09, 0x03, 0x0a, 0x0c,
7855		0x0b, 0x0d, 0x0e, 0x12, 0x0f, 0x10,
7856		0x11, 0x04, 0x05, 0x06, 0x07, 0x00,
7857		0x2e
7858       };
7859       for(i = 0; i <= 18; i++) {
7860          outSISIDXREG(SISPART1, myregs[i], sisReg->VBPart1[myregs[i]]);
7861       }
7862    } else if((temp & 0x20) || (temp & 0x9c)) {
7863       UChar myregs[] = {
7864       		0x04, 0x05, 0x06, 0x07, 0x00, 0x2e
7865       };
7866       for(i = 0; i <= 5; i++) {
7867          outSISIDXREG(SISPART1, myregs[i], sisReg->VBPart1[myregs[i]]);
7868       }
7869    }
7870}
7871
7872/* Fix SR11 for 661 and later */
7873static void
7874SiSFixupSR11(ScrnInfoPtr pScrn)
7875{
7876    SISPtr pSiS = SISPTR(pScrn);
7877    CARD8  tmpreg;
7878
7879#ifdef UNLOCK_ALWAYS
7880    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
7881#endif
7882
7883    if(pSiS->ChipType >= SIS_661) {
7884       inSISIDXREG(SISSR,0x11,tmpreg);
7885       if(tmpreg & 0x20) {
7886          inSISIDXREG(SISSR,0x3e,tmpreg);
7887	  tmpreg = (tmpreg + 1) & 0xff;
7888	  outSISIDXREG(SISSR,0x3e,tmpreg);
7889       }
7890
7891       inSISIDXREG(SISSR,0x11,tmpreg);
7892       if(tmpreg & 0xf0) {
7893          andSISIDXREG(SISSR,0x11,0x0f);
7894       }
7895    }
7896}
7897
7898/* Subroutine for restoring sisfb's TV parameters (used by SiSRestore()) */
7899
7900static void
7901SiSRestore_SiSFB_TVParms(ScrnInfoPtr pScrn)
7902{
7903    SISPtr  pSiS = SISPTR(pScrn);
7904    int     fd;
7905    CARD32  parm;
7906
7907    if(!pSiS->sisfbfound) return;
7908    if(!pSiS->sisfb_tvposvalid) return;
7909    if(!(pSiS->sisfbdevname[0])) return;
7910
7911    if((fd = open(pSiS->sisfbdevname, O_RDONLY)) != -1) {
7912       parm = (CARD32)((pSiS->sisfb_tvxpos << 16) | (pSiS->sisfb_tvypos & 0xffff));
7913       ioctl(fd, SISFB_SET_TVPOSOFFSET, &parm);
7914       close(fd);
7915    }
7916}
7917
7918/*
7919 * Restore the initial mode. To be used internally only!
7920 */
7921static void
7922SISRestore(ScrnInfoPtr pScrn)
7923{
7924    SISPtr    pSiS = SISPTR(pScrn);
7925    SISRegPtr sisReg = &pSiS->SavedReg;
7926    Bool      doit = FALSE, doitlater = FALSE;
7927    Bool      vesasuccess = FALSE;
7928    int	      flags;
7929
7930    /* WARNING: Don't ever touch this. It now seems to work on
7931     * all chipset/bridge combinations - but finding out the
7932     * correct combination was pure hell.
7933     */
7934
7935    /* Wait for the accelerators */
7936    (*pSiS->SyncAccel)(pScrn);
7937
7938    /* Set up restore flags */
7939    flags = SISVGA_SR_MODE | SISVGA_SR_CMAP;
7940#ifdef SIS_PC_PLATFORM
7941    /* We now restore ALL to overcome the vga=extended problem */
7942    if(pSiS->VGAMemBase) flags |= SISVGA_SR_FONTS;
7943#endif
7944
7945    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
7946
7947#ifdef SISDUALHEAD
7948       /* We always restore master AND slave */
7949       if(pSiS->DualHeadMode && pSiS->SecondHead) return;
7950#endif
7951
7952#ifdef UNLOCK_ALWAYS
7953       sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
7954#endif
7955
7956       /* We must not disable the sequencer if the bridge is in SlaveMode! */
7957       if(!(SiSBridgeIsInSlaveMode(pScrn))) {
7958	  SiSVGAProtect(pScrn, TRUE);
7959       }
7960
7961       /* First, restore CRT1 on/off and VB connection registers */
7962       outSISIDXREG(SISCR, 0x32, pSiS->oldCR32);
7963       if(!(pSiS->oldCR17 & 0x80)) {			/* CRT1 was off */
7964	  if(!(SiSBridgeIsInSlaveMode(pScrn))) {        /* Bridge is NOT in SlaveMode now -> do it */
7965	     doit = TRUE;
7966	  } else {
7967	     doitlater = TRUE;
7968	  }
7969       } else {						/* CRT1 was on -> do it now */
7970	  doit = TRUE;
7971       }
7972
7973       if(doit) {
7974	  outSISIDXREG(SISCR, 0x17, pSiS->oldCR17);
7975       }
7976       if(pSiS->VGAEngine == SIS_315_VGA) {
7977	  outSISIDXREG(SISCR, pSiS->myCR63, pSiS->oldCR63);
7978       }
7979
7980       outSISIDXREG(SISSR, 0x1f, pSiS->oldSR1F);
7981
7982       /* For 30xB/LV, restoring the registers does not
7983	* work. We "manually" set the old mode, instead.
7984	* The same applies for SiS730 machines with LVDS.
7985	* Finally, this behavior can be forced by setting
7986	* the option RestoreBySetMode.
7987	*/
7988	if( ( (pSiS->restorebyset) ||
7989	      (pSiS->VBFlags2 & VB2_30xBLV) ||
7990	      ((pSiS->ChipType == SIS_730) && (pSiS->VBFlags2 & VB2_LVDS)) )     &&
7991	    (pSiS->OldMode) ) {
7992
7993	   Bool changedmode = FALSE;
7994
7995	   xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
7996	         "Restoring by setting old mode 0x%02x\n", pSiS->OldMode);
7997
7998	   if(((pSiS->OldMode <= 0x13) || (!pSiS->sisfbfound)) && (pSiS->pVbe)) {
7999	      int vmode = SiSTranslateToVESA(pScrn, pSiS->OldMode);
8000	      if(vmode > 0) {
8001		 if(vmode > 0x13) vmode |= ((1 << 15) | (1 << 14));
8002		 if(VBESetVBEMode(pSiS->pVbe, vmode, NULL) == TRUE) {
8003		    SISSpecialRestore(pScrn);
8004		    SiS_GetSetModeID(pScrn,pSiS->OldMode);
8005		    vesasuccess = TRUE;
8006		 } else {
8007		    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
8008			"VBE failed to restore mode 0x%x\n", pSiS->OldMode);
8009		 }
8010	      } else {
8011		 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
8012		 	"Can't identify VESA mode number for mode 0x%x\n", pSiS->OldMode);
8013	      }
8014	   }
8015
8016	   if(vesasuccess == FALSE) {
8017
8018	      int backupscaler = pSiS->SiS_Pr->UsePanelScaler;
8019	      int backupcenter = pSiS->SiS_Pr->CenterScreen;
8020	      ULong backupspecialtiming = pSiS->SiS_Pr->SiS_CustomT;
8021	      int mymode = pSiS->OldMode;
8022
8023	      if((pSiS->VGAEngine == SIS_315_VGA)			&&
8024	         ((pSiS->ROM661New) || (pSiS->ChipFlags & SiSCF_IsXGI)) &&
8025		 (!pSiS->sisfbfound)) {
8026	         /* New SiS BIOS or XGI BIOS has set mode, therefore eventually translate number */
8027	         mymode = SiSTranslateToOldMode(mymode);
8028	      }
8029
8030 	      if((pSiS->VBFlags2 & VB2_30xBLV)) {
8031	        /* !!! REQUIRED for 630+301B-DH, otherwise the text modes
8032	         *     will not be restored correctly !!!
8033	         * !!! Do this ONLY for LCD; VGA2 will not be restored
8034	         *     correctly otherwise.
8035	         */
8036	         UChar temp;
8037	         inSISIDXREG(SISCR, 0x30, temp);
8038	         if(temp & 0x20) {
8039	            if(mymode == 0x03) {
8040		       mymode = 0x13;
8041		       changedmode = TRUE;
8042	            }
8043	         }
8044	      }
8045
8046	      pSiS->SiS_Pr->UseCustomMode = FALSE;
8047	      pSiS->SiS_Pr->CRT1UsesCustomMode = FALSE;
8048	      pSiS->SiS_Pr->CenterScreen = 0;
8049	      if(pSiS->sisfbfound) {
8050		 pSiS->SiS_Pr->UsePanelScaler = pSiS->sisfbscalelcd;
8051		 pSiS->SiS_Pr->SiS_CustomT = pSiS->sisfbspecialtiming;
8052	      } else {
8053		 pSiS->SiS_Pr->UsePanelScaler = -1;
8054		 /* Leave CustomT as it is */
8055	      }
8056	      SiS_SetEnableDstn(pSiS->SiS_Pr, FALSE);
8057	      SiS_SetEnableFstn(pSiS->SiS_Pr, FALSE);
8058	      if((pSiS->ChipType == SIS_550) && (pSiS->sisfbfound)) {
8059		 if(pSiS->sisfbxSTN) {
8060		    SiS_SetEnableDstn(pSiS->SiS_Pr, pSiS->sisfbDSTN);
8061		    SiS_SetEnableFstn(pSiS->SiS_Pr, pSiS->sisfbFSTN);
8062		 } else if(mymode == 0x5a || mymode == 0x5b) {
8063		    SiS_SetEnableFstn(pSiS->SiS_Pr, TRUE);
8064		 }
8065	      }
8066	      SiSSetMode(pSiS->SiS_Pr, pScrn, mymode, FALSE);
8067	      if(changedmode) {
8068		 outSISIDXREG(SISCR,0x34,0x03);
8069	      }
8070	      SISSpecialRestore(pScrn);
8071	      SiS_GetSetModeID(pScrn, pSiS->OldMode); /* NOT mymode! */
8072	      pSiS->SiS_Pr->UsePanelScaler = backupscaler;
8073	      pSiS->SiS_Pr->CenterScreen = backupcenter;
8074	      pSiS->SiS_Pr->SiS_CustomT = backupspecialtiming;
8075	      SiS_SiSFB_Lock(pScrn, FALSE);
8076	      SiSRestore_SiSFB_TVParms(pScrn);
8077	      SiS_SiSFB_Lock(pScrn, TRUE);
8078
8079	   }
8080
8081	   /* Restore CRT1 status */
8082	   if(pSiS->VGAEngine == SIS_315_VGA) {
8083              outSISIDXREG(SISCR, pSiS->myCR63, pSiS->oldCR63);
8084           }
8085           outSISIDXREG(SISSR, 0x1f, pSiS->oldSR1F);
8086
8087#ifdef SISVRAMQ
8088	   /* Restore queue mode registers on 315/330/340 series */
8089	   /* (This became necessary due to the switch to VRAM queue) */
8090	   SiSRestoreQueueMode(pSiS, sisReg);
8091#endif
8092
8093        } else {
8094
8095	   if(pSiS->VBFlags2 & VB2_VIDEOBRIDGE) {
8096	      /* If a video bridge is present, we need to restore
8097	       * non-extended (=standard VGA) SR and CR registers
8098	       * before restoring the extended ones and the bridge
8099	       * registers.
8100	       */
8101	      if(!(SiSBridgeIsInSlaveMode(pScrn))) {
8102                 SiSVGAProtect(pScrn, TRUE);
8103	         SiSVGARestore(pScrn, sisReg, SISVGA_SR_MODE);
8104              }
8105	   }
8106
8107           (*pSiS->SiSRestore)(pScrn, sisReg);
8108
8109        }
8110
8111	if(doitlater) {
8112           outSISIDXREG(SISCR, 0x17, pSiS->oldCR17);
8113	}
8114
8115
8116
8117	if((pSiS->VBFlags2 & VB2_VIDEOBRIDGE) && (SiSBridgeIsInSlaveMode(pScrn))) {
8118
8119	   /* IMPORTANT: The 30xLV does not handle well being disabled if in
8120	    * LCDA mode! In LCDA mode, the bridge is NOT in slave mode,
8121	    * so this is the only safe way: Disable the bridge ONLY if
8122	    * in Slave Mode, and don't bother if not.
8123	    */
8124
8125	   if(flags & SISVGA_SR_FONTS) {
8126              SiSRegInit(pSiS->SiS_Pr, pSiS->RelIO+0x30);
8127	      SiSSetLVDSetc(pSiS->SiS_Pr);
8128	      SiS_GetVBType(pSiS->SiS_Pr);
8129	      SiS_DisableBridge(pSiS->SiS_Pr);
8130	      SiSVGAProtect(pScrn, TRUE);
8131	   }
8132
8133	   SiSVGARestore(pScrn, sisReg, flags);
8134
8135	   if(flags & SISVGA_SR_FONTS) {
8136	      SiSVGAProtect(pScrn, FALSE);
8137	      SiS_EnableBridge(pSiS->SiS_Pr);
8138	      andSISIDXREG(SISSR, 0x01, ~0x20);  /* Display on */
8139	   }
8140
8141	} else {
8142
8143	   SiSVGAProtect(pScrn, TRUE);
8144	   SiSVGARestore(pScrn, sisReg, flags);
8145           SiSVGAProtect(pScrn, FALSE);
8146
8147	}
8148
8149	SiSFixupSR11(pScrn);
8150
8151#ifdef TWDEBUG
8152	{
8153	  SISRegPtr pReg = &pSiS->ModeReg;
8154	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
8155		"REAL REGISTER CONTENTS AFTER RESTORE BY SETMODE:\n");
8156	  (*pSiS->SiSSave)(pScrn, pReg);
8157	}
8158#endif
8159
8160	sisRestoreExtRegisterLock(pSiS,sisReg->sisRegs3C4[0x05],sisReg->sisRegs3D4[0x80]);
8161
8162    } else {	/* All other chipsets */
8163
8164        SiSVGAProtect(pScrn, TRUE);
8165
8166#ifdef UNLOCK_ALWAYS
8167        sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
8168#endif
8169
8170        (*pSiS->SiSRestore)(pScrn, sisReg);
8171
8172        SiSVGAProtect(pScrn, TRUE);
8173
8174	SiSVGARestore(pScrn, sisReg, flags);
8175
8176	/* Restore TV. This is rather complicated, but if we don't do it,
8177	 * TV output will flicker terribly
8178	 */
8179        if((pSiS->Chipset == PCI_CHIP_SIS6326) && (pSiS->SiS6326Flags & SIS6326_HASTV)) {
8180	   if(sisReg->sis6326tv[0] & 0x04) {
8181	      UChar tmp;
8182	      int val;
8183
8184              orSISIDXREG(SISSR, 0x01, 0x20);
8185              tmp = SiS6326GetTVReg(pScrn,0x00);
8186              tmp &= ~0x04;
8187              while(!(inSISREG(SISINPSTAT) & 0x08));  /* Wait while NOT vb */
8188              SiS6326SetTVReg(pScrn,0x00,tmp);
8189              for(val=0; val < 2; val++) {
8190                 while(!(inSISREG(SISINPSTAT) & 0x08));  /* Wait while NOT vb */
8191                 while(inSISREG(SISINPSTAT) & 0x08);     /* wait while vb     */
8192              }
8193              SiS6326SetTVReg(pScrn, 0x00, sisReg->sis6326tv[0]);
8194              tmp = inSISREG(SISINPSTAT);
8195              outSISREG(SISAR, 0x20);
8196              tmp = inSISREG(SISINPSTAT);
8197              while(inSISREG(SISINPSTAT) & 0x01);
8198              while(!(inSISREG(SISINPSTAT) & 0x01));
8199              andSISIDXREG(SISSR, 0x01, ~0x20);
8200              for(val=0; val < 10; val++) {
8201                 while(!(inSISREG(SISINPSTAT) & 0x08));  /* Wait while NOT vb */
8202                 while(inSISREG(SISINPSTAT) & 0x08);     /* wait while vb     */
8203              }
8204              andSISIDXREG(SISSR, 0x01, ~0x20);
8205	   }
8206        }
8207
8208        sisRestoreExtRegisterLock(pSiS,sisReg->sisRegs3C4[5],sisReg->sisRegs3D4[0x80]);
8209
8210        SiSVGAProtect(pScrn, FALSE);
8211    }
8212}
8213
8214static void
8215SISVESARestore(ScrnInfoPtr pScrn)
8216{
8217   SISPtr pSiS = SISPTR(pScrn);
8218#ifdef SISVRAMQ
8219   SISRegPtr sisReg = &pSiS->SavedReg;
8220#endif
8221
8222   if(pSiS->UseVESA) {
8223      SISVESASaveRestore(pScrn, MODE_RESTORE);
8224#ifdef SISVRAMQ
8225      /* Restore queue mode registers on 315/330/340 series */
8226      /* (This became necessary due to the switch to VRAM queue) */
8227      SiSRestoreQueueMode(pSiS, sisReg);
8228#endif
8229   }
8230}
8231
8232/* Restore bridge config registers - to be called BEFORE VESARestore */
8233static void
8234SISBridgeRestore(ScrnInfoPtr pScrn)
8235{
8236    SISPtr pSiS = SISPTR(pScrn);
8237
8238#ifdef SISDUALHEAD
8239    /* We only restore for master head */
8240    if(pSiS->DualHeadMode && pSiS->SecondHead) return;
8241#endif
8242
8243    if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
8244	SiSRestoreBridge(pScrn, &pSiS->SavedReg);
8245    }
8246}
8247
8248/* Our BlockHandler */
8249static void
8250SISBlockHandler(BLOCKHANDLER_ARGS_DECL)
8251{
8252    SCREEN_PTR(arg);
8253    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
8254    SISPtr pSiS = SISPTR(pScrn);
8255
8256    pScreen->BlockHandler = pSiS->BlockHandler;
8257    (*pScreen->BlockHandler) (BLOCKHANDLER_ARGS);
8258    pScreen->BlockHandler = SISBlockHandler;
8259
8260#ifdef SISDUALHEAD
8261    if(pSiS->NeedCopyFastVidCpy) {
8262       SISEntPtr pSiSEnt = pSiS->entityPrivate;
8263       if(pSiSEnt->HaveFastVidCpy) {
8264	  pSiS->NeedCopyFastVidCpy = FALSE;
8265	  pSiS->SiSFastVidCopy = pSiSEnt->SiSFastVidCopy;
8266	  pSiS->SiSFastMemCopy = pSiSEnt->SiSFastMemCopy;
8267	  pSiS->SiSFastVidCopyFrom = pSiSEnt->SiSFastVidCopyFrom;
8268	  pSiS->SiSFastMemCopyFrom = pSiSEnt->SiSFastMemCopyFrom;
8269       }
8270    }
8271#endif
8272
8273    if(pSiS->VideoTimerCallback) {
8274       (*pSiS->VideoTimerCallback)(pScrn, currentTime.milliseconds);
8275    }
8276
8277#ifdef SIS_USE_XAA
8278    if(pSiS->RenderCallback) {
8279       (*pSiS->RenderCallback)(pScrn);
8280    }
8281#endif
8282#ifdef SIS_USE_EXA
8283    if(pSiS->ExaRenderCallback) {
8284       (*pSiS->ExaRenderCallback)(pScrn);
8285    }
8286#endif
8287}
8288
8289
8290
8291/* Do screen blanking; DPMS handling
8292 *
8293 * Mandatory; latter optional
8294 */
8295
8296static void
8297SiSHandleBackLight(SISPtr pSiS, Bool blon)
8298{
8299    UChar sr11mask = (pSiS->SiS_Pr->SiS_SensibleSR11) ? 0x03 : 0xf3;
8300
8301    if(pSiS->VBFlags2 & VB2_SISLVDSBRIDGE) {
8302
8303       if(!blon) {
8304	  SiS_SiS30xBLOff(pSiS->SiS_Pr);
8305       } else {
8306	  SiS_SiS30xBLOn(pSiS->SiS_Pr);
8307       }
8308
8309    } else if( ((pSiS->VGAEngine == SIS_300_VGA) &&
8310	        (pSiS->VBFlags2 & (VB2_LVDS | VB2_30xBDH))) ||
8311	       ((pSiS->VGAEngine == SIS_315_VGA) &&
8312	        ((pSiS->VBFlags2 & (VB2_LVDS | VB2_CHRONTEL)) == VB2_LVDS)) ) {
8313
8314       if(!blon) {
8315	  setSISIDXREG(SISSR, 0x11, sr11mask, 0x08);
8316       } else {
8317	  setSISIDXREG(SISSR, 0x11, sr11mask, 0x00);
8318       }
8319
8320    } else if((pSiS->VGAEngine == SIS_315_VGA) &&
8321	      (pSiS->VBFlags2 & VB2_CHRONTEL)) {
8322
8323       if(!blon) {
8324	  SiS_Chrontel701xBLOff(pSiS->SiS_Pr);
8325       } else {
8326	  SiS_Chrontel701xBLOn(pSiS->SiS_Pr);
8327       }
8328
8329    }
8330}
8331
8332static Bool
8333SISSaveScreen(ScreenPtr pScreen, int mode)
8334{
8335    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
8336    SISPtr pSiS;
8337    Bool IsUnblank = xf86IsUnblank(mode) ? TRUE : FALSE;
8338
8339    if((pScrn == NULL) || (!pScrn->vtSema)) return TRUE;
8340
8341    pSiS = SISPTR(pScrn);
8342
8343#ifdef UNLOCK_ALWAYS
8344    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
8345#endif
8346
8347    if(pSiS->VBFlags & (CRT2_LCD | CRT1_LCDA)) {
8348       SiSHandleBackLight(pSiS, IsUnblank);
8349    }
8350
8351    if(!SiSBridgeIsInSlaveMode(pScrn)) {
8352       return SiSVGASaveScreen(pScreen, mode);
8353    }
8354
8355    return TRUE;
8356}
8357
8358#ifdef SISDUALHEAD
8359/* SaveScreen for dual head mode */
8360static Bool
8361SISSaveScreenDH(ScreenPtr pScreen, int mode)
8362{
8363    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
8364    SISPtr pSiS;
8365    Bool IsUnblank = xf86IsUnblank(mode) ? TRUE : FALSE;
8366
8367    if((pScrn == NULL) || (!pScrn->vtSema)) return TRUE;
8368
8369    pSiS = SISPTR(pScrn);
8370
8371    if( (pSiS->SecondHead) &&
8372        ((!(pSiS->VBFlags & CRT1_LCDA)) || (pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE)) ) {
8373
8374       /* Slave head is always CRT1 */
8375       /* (No backlight handling on TMDS bridges) */
8376       return SiSVGASaveScreen(pScreen, mode);
8377
8378    } else {
8379
8380       /* Master head is always CRT2 */
8381       /* But we land here for LCDA, too (if bridge is SiS LVDS type) */
8382
8383       /* We can only blank LCD, not other CRT2 devices */
8384       if(pSiS->VBFlags & (CRT2_LCD|CRT1_LCDA)) {
8385
8386#ifdef UNLOCK_ALWAYS
8387	  sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
8388#endif
8389	  SiSHandleBackLight(pSiS, IsUnblank);
8390
8391       }
8392
8393    }
8394    return TRUE;
8395}
8396#endif
8397
8398static void
8399SISDisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode, int flags)
8400{
8401    SISPtr pSiS = SISPTR(pScrn);
8402    Bool   docrt1 = TRUE, docrt2 = TRUE, backlight = TRUE;
8403    UChar  sr1=0, cr17=0, cr63=0, pmreg=0, sr7=0;
8404    UChar  p1_13=0, p2_0=0, oldpmreg=0;
8405
8406    if(!pScrn->vtSema) return;
8407
8408    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 4,
8409          "SISDisplayPowerManagementSet(%d)\n", PowerManagementMode);
8410
8411#ifdef SISDUALHEAD
8412    if(pSiS->DualHeadMode) {
8413       if(pSiS->SecondHead) docrt2 = FALSE;
8414       else                 docrt1 = FALSE;
8415    }
8416#endif
8417
8418    /* FIXME: in old servers, DPMSSet was supposed to be called without open
8419     * the correct PCI bridges before access the hardware. Now we have this
8420     * hook wrapped by the vga arbiter which should do all the work, in
8421     * kernels that implement it. For this case we might not want this hack
8422     * bellow.
8423     */
8424    outSISIDXREG(SISSR,0x05,0x86);
8425    inSISIDXREG(SISSR,0x05,pmreg);
8426    if(pmreg != 0xa1) return;
8427
8428#ifdef UNLOCK_ALWAYS
8429    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
8430#endif
8431
8432    switch(PowerManagementMode) {
8433
8434       case DPMSModeOn:      /* HSync: On, VSync: On */
8435	  sr1   = 0x00;
8436	  cr17  = 0x80;
8437	  pmreg = 0x00;
8438	  cr63  = 0x00;
8439	  sr7   = 0x10;
8440	  p2_0  = 0x20;
8441	  p1_13 = 0x00;
8442	  backlight = TRUE;
8443	  break;
8444
8445       case DPMSModeSuspend: /* HSync: On, VSync: Off */
8446	  sr1   = 0x20;
8447	  cr17  = 0x80;
8448	  pmreg = 0x80;
8449	  cr63  = 0x40;
8450	  sr7   = 0x00;
8451	  p2_0  = 0x40;
8452	  p1_13 = 0x80;
8453	  backlight = FALSE;
8454	  break;
8455
8456       case DPMSModeStandby: /* HSync: Off, VSync: On */
8457	  sr1   = 0x20;
8458	  cr17  = 0x80;
8459	  pmreg = 0x40;
8460	  cr63  = 0x40;
8461	  sr7   = 0x00;
8462	  p2_0  = 0x80;
8463	  p1_13 = 0x40;
8464	  backlight = FALSE;
8465	  break;
8466
8467       case DPMSModeOff:     /* HSync: Off, VSync: Off */
8468	  sr1   = 0x20;
8469	  cr17  = 0x00;
8470	  pmreg = 0xc0;
8471	  cr63  = 0x40;
8472	  sr7   = 0x00;
8473	  p2_0  = 0xc0;
8474	  p1_13 = 0xc0;
8475	  backlight = FALSE;
8476	  break;
8477
8478       default:
8479	    return;
8480    }
8481
8482    oldpmreg = pmreg;
8483
8484    if((docrt2 && (pSiS->VBFlags & CRT2_LCD)) ||
8485       (docrt1 && (pSiS->VBFlags & CRT1_LCDA))) {
8486       SiSHandleBackLight(pSiS, backlight);
8487    }
8488
8489    if(docrt1) {
8490       switch(pSiS->VGAEngine) {
8491       case SIS_OLD_VGA:
8492       case SIS_530_VGA:
8493	    setSISIDXREG(SISSR, 0x01, ~0x20, sr1);    /* Set/Clear "Display On" bit */
8494	    inSISIDXREG(SISSR, 0x11, oldpmreg);
8495	    setSISIDXREG(SISCR, 0x17, 0x7f, cr17);
8496	    setSISIDXREG(SISSR, 0x11, 0x3f, pmreg);
8497	    break;
8498       case SIS_315_VGA:
8499	    if( (!pSiS->CRT1off) &&
8500	        ((!(pSiS->VBFlags & CRT1_LCDA)) || (pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE)) ) {
8501	       setSISIDXREG(SISCR, pSiS->myCR63, 0xbf, cr63);
8502	       setSISIDXREG(SISSR, 0x07, 0xef, sr7);
8503	    }
8504	    /* fall through */
8505       default:
8506	    if(!SiSBridgeIsInSlaveMode(pScrn)) {
8507	       setSISIDXREG(SISSR, 0x01, ~0x20, sr1);    /* Set/Clear "Display On" bit */
8508	    }
8509	    if((!(pSiS->VBFlags & CRT1_LCDA)) || (pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE)) {
8510	       inSISIDXREG(SISSR, 0x1f, oldpmreg);
8511	       if((!pSiS->CRT1off) && (!SiSBridgeIsInSlaveMode(pScrn))) {
8512		  setSISIDXREG(SISSR, 0x1f, 0x3f, pmreg);
8513	       }
8514	    }
8515       }
8516       oldpmreg &= 0xc0;
8517    }
8518
8519    if(docrt2) {
8520       if(pSiS->VBFlags & CRT2_LCD) {
8521          if((pSiS->VBFlags2 & VB2_SISBRIDGE) &&
8522	     (!(pSiS->VBFlags2 & VB2_30xBDH))) {
8523	     if(pSiS->VGAEngine == SIS_300_VGA) {
8524	        SiS_UnLockCRT2(pSiS->SiS_Pr);
8525	        setSISIDXREG(SISPART1, 0x13, 0x3f, p1_13);
8526	     }
8527	     if(pSiS->VBFlags2 & VB2_SISLVDSBRIDGE) p2_0 |= 0x20;
8528	     setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
8529	  }
8530       } else if(pSiS->VBFlags & (CRT2_VGA | CRT2_TV)) {
8531	  if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
8532	     setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
8533	  }
8534       }
8535    }
8536
8537    if( (docrt1) &&
8538        (pmreg != oldpmreg) &&
8539        ((!(pSiS->VBFlags & CRT1_LCDA)) || (pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE)) ) {
8540       outSISIDXREG(SISSR, 0x00, 0x01);    /* Synchronous Reset */
8541       usleep(10000);
8542       outSISIDXREG(SISSR, 0x00, 0x03);    /* End Reset */
8543    }
8544
8545}
8546
8547/* Mandatory
8548 * This gets called at the start of each server generation
8549 *
8550 * We use pScrn and not CurrentLayout here, because the
8551 * properties we use have not changed (displayWidth,
8552 * depth, bitsPerPixel)
8553 */
8554static Bool
8555SISScreenInit(SCREEN_INIT_ARGS_DECL)
8556{
8557    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
8558    SISPtr pSiS = SISPTR(pScrn);
8559    VisualPtr visual;
8560    ULong OnScreenSize;
8561    int ret, height, width, displayWidth;
8562    UChar *FBStart;
8563#ifdef SISDUALHEAD
8564    SISEntPtr pSiSEnt = NULL;
8565#endif
8566
8567#ifdef SISDUALHEAD
8568    if((!pSiS->DualHeadMode) || (!pSiS->SecondHead)) {
8569#endif
8570       SiS_LoadInitVBE(pScrn);
8571#ifdef SISDUALHEAD
8572    }
8573#endif
8574
8575#ifdef SISDUALHEAD
8576    if(pSiS->DualHeadMode) {
8577       pSiSEnt = pSiS->entityPrivate;
8578       pSiSEnt->refCount++;
8579    }
8580#endif
8581
8582#ifdef SIS_PC_PLATFORM
8583    /* Map 64k VGA window for saving/restoring CGA fonts */
8584    SiS_MapVGAMem(pScrn);
8585#endif
8586
8587    /* Map the SiS memory and MMIO areas */
8588    if(!SISMapMem(pScrn)) {
8589       SISErrorLog(pScrn, "SiSMapMem() failed\n");
8590       return FALSE;
8591    }
8592
8593    SiS_SiSFB_Lock(pScrn, TRUE);
8594
8595#ifdef UNLOCK_ALWAYS
8596    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
8597#endif
8598
8599    /* Enable TurboQueue so that SISSave() saves it in enabled
8600     * state. If we don't do this, X will hang after a restart!
8601     * (Happens for some unknown reason only when using VESA
8602     * for mode switching; assumingly a BIOS issue.)
8603     * This is done on 300 and 315 series only.
8604     */
8605    if(pSiS->UseVESA) {
8606#ifdef SISVRAMQ
8607       if(pSiS->VGAEngine != SIS_315_VGA)
8608#endif
8609          SiSEnableTurboQueue(pScrn);
8610    }
8611
8612    /* Save the current state */
8613    SISSave(pScrn);
8614
8615    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
8616
8617       if(!pSiS->OldMode) {
8618
8619          /* Try to find out current (=old) mode number
8620	   * (Do this only if not sisfb has told us its mode yet)
8621	   */
8622
8623	  /* Read 0:449 which the BIOS sets to the current mode number
8624	   * Unfortunately, this not reliable since the int10 emulation
8625	   * does not change this. So if we call the VBE later, this
8626	   * byte won't be touched (which is why we set this manually
8627	   * then).
8628	   */
8629          UChar myoldmode = SiS_GetSetModeID(pScrn, 0xFF);
8630	  UChar cr30, cr31;
8631
8632          /* Read CR34 which the BIOS sets to the current mode number for CRT2
8633	   * This is - of course - not reliable if the machine has no video
8634	   * bridge...
8635	   */
8636          inSISIDXREG(SISCR, 0x34, pSiS->OldMode);
8637	  inSISIDXREG(SISCR, 0x30, cr30);
8638	  inSISIDXREG(SISCR, 0x31, cr31);
8639
8640	  /* What if CR34 is different from the BIOS scratch byte? */
8641	  if(pSiS->OldMode != myoldmode) {
8642	     /* If no bridge output is active, trust the BIOS scratch byte */
8643	     if( (!(pSiS->VBFlags2 & VB2_VIDEOBRIDGE)) ||
8644	         (pSiS->OldMode == 0)                  ||
8645	         (!cr31 && !cr30)                      ||
8646		 (cr31 & 0x20) ) {
8647		pSiS->OldMode = myoldmode;
8648 	     }
8649	     /* ..else trust CR34 */
8650	  }
8651
8652	  /* Newer 650 BIOSes set CR34 to 0xff if the mode has been
8653	   * "patched", for instance for 80x50 text mode. (That mode
8654	   * has no number of its own, it's 0x03 like 80x25). In this
8655	   * case, we trust the BIOS scratch byte (provided that any
8656	   * of these two is valid).
8657	   */
8658	  if(pSiS->OldMode > 0x7f) {
8659	     pSiS->OldMode = myoldmode;
8660	  }
8661       }
8662#ifdef SISDUALHEAD
8663       if(pSiS->DualHeadMode) {
8664          if(!pSiS->SecondHead) pSiSEnt->OldMode = pSiS->OldMode;
8665          else                  pSiS->OldMode = pSiSEnt->OldMode;
8666       }
8667#endif
8668    }
8669
8670    /* RandR resets screen mode and size in CloseScreen(), hence
8671     * we need to adapt our VBFlags to the initial state if the
8672     * current mode has changed since closescreen() (or Screeninit()
8673     * for the first instance)
8674     */
8675    if(pScrn->currentMode != pSiS->currentModeLast) {
8676       pSiS->VBFlags = pSiS->VBFlags_backup = pSiS->VBFlagsInit;
8677    }
8678
8679    /* Copy our detected monitor gammas, part 2. Note that device redetection
8680     * is not supported in DHM, so there is no need to do that anytime later.
8681     */
8682#ifdef SISDUALHEAD
8683    if(pSiS->DualHeadMode) {
8684       if(!pSiS->SecondHead) {
8685          /* CRT2 */
8686	  pSiS->CRT1VGAMonitorGamma = pSiSEnt->CRT1VGAMonitorGamma;
8687       } else {
8688          /* CRT1 */
8689	  pSiS->CRT2VGAMonitorGamma = pSiSEnt->CRT2VGAMonitorGamma;
8690       }
8691       if(!pSiS->CRT2LCDMonitorGamma) pSiS->CRT2LCDMonitorGamma = pSiSEnt->CRT2LCDMonitorGamma;
8692    }
8693#endif
8694
8695    /* Initialize the first mode */
8696    if(!SISModeInit(pScrn, pScrn->currentMode)) {
8697       SISErrorLog(pScrn, "SiSModeInit() failed\n");
8698       return FALSE;
8699    }
8700
8701    /* Darken the screen for aesthetic reasons */
8702    /* Not using Dual Head variant on purpose; we darken
8703     * the screen for both displays, and un-darken
8704     * it when the second head is finished
8705     */
8706    SISSaveScreen(pScreen, SCREEN_SAVER_ON);
8707
8708    /* Set the viewport */
8709    SISAdjustFrame(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0));
8710
8711    /* Reset visual list. */
8712    miClearVisualTypes();
8713
8714    /* Setup the visuals we support. */
8715
8716    /*
8717     * For bpp > 8, the default visuals are not acceptable because we only
8718     * support TrueColor and not DirectColor.
8719     */
8720    if(!miSetVisualTypes(pScrn->depth,
8721			 (pScrn->bitsPerPixel > 8) ?
8722				TrueColorMask : miGetDefaultVisualMask(pScrn->depth),
8723			 pScrn->rgbBits, pScrn->defaultVisual)) {
8724       SISSaveScreen(pScreen, SCREEN_SAVER_OFF);
8725       SISErrorLog(pScrn, "miSetVisualTypes() failed (bpp %d)\n",
8726			pScrn->bitsPerPixel);
8727       return FALSE;
8728    }
8729
8730    width = pScrn->virtualX;
8731    height = pScrn->virtualY;
8732    displayWidth = pScrn->displayWidth;
8733
8734    if(pSiS->Rotate) {
8735       height = pScrn->virtualX;
8736       width = pScrn->virtualY;
8737    }
8738
8739    if(pSiS->ShadowFB) {
8740       pSiS->ShadowPitch = BitmapBytePad(pScrn->bitsPerPixel * width);
8741       pSiS->ShadowPtr = malloc(pSiS->ShadowPitch * height);
8742       displayWidth = pSiS->ShadowPitch / (pScrn->bitsPerPixel >> 3);
8743       FBStart = pSiS->ShadowPtr;
8744    } else {
8745       pSiS->ShadowPtr = NULL;
8746       FBStart = pSiS->FbBase;
8747    }
8748
8749    if(!miSetPixmapDepths()) {
8750       SISSaveScreen(pScreen, SCREEN_SAVER_OFF);
8751       SISErrorLog(pScrn, "miSetPixmapDepths() failed\n");
8752       return FALSE;
8753    }
8754
8755    /* Point cmdQueuePtr to pSiSEnt for shared usage
8756     * (same technique is then eventually used in DRIScreeninit)
8757     * For 315/330 series, this is done in EnableTurboQueue
8758     * which has already been called during ModeInit().
8759     */
8760#ifdef SISDUALHEAD
8761    if(pSiS->SecondHead)
8762       pSiS->cmdQueueLenPtr = &(SISPTR(pSiSEnt->pScrn_1)->cmdQueueLen);
8763    else
8764#endif
8765       pSiS->cmdQueueLenPtr = &(pSiS->cmdQueueLen);
8766
8767    pSiS->cmdQueueLen = 0; /* Force an EngineIdle() at start */
8768
8769#ifdef SISDRI
8770    if(pSiS->loadDRI) {
8771#ifdef SISDUALHEAD
8772       /* No DRI in dual head mode */
8773       if(pSiS->DualHeadMode) {
8774	  pSiS->directRenderingEnabled = FALSE;
8775	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
8776		"DRI not supported in Dual Head mode\n");
8777       } else
8778#endif
8779	      if(pSiS->VGAEngine != SIS_315_VGA) {
8780	  /* Force the initialization of the context */
8781	  pSiS->directRenderingEnabled = SISDRIScreenInit(pScreen);
8782       } else {
8783	  xf86DrvMsg(pScrn->scrnIndex, X_NOT_IMPLEMENTED,
8784		"DRI not supported on this chipset\n");
8785	  pSiS->directRenderingEnabled = FALSE;
8786       }
8787    }
8788#endif
8789
8790    /* Call the framebuffer layer's ScreenInit function and fill in other
8791     * pScreen fields.
8792     */
8793    switch(pScrn->bitsPerPixel) {
8794       case 24:
8795	  if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
8796	     ret = FALSE;
8797	     break;
8798	  }
8799	  /* fall through */
8800       case 8:
8801       case 16:
8802       case 32:
8803	  ret = fbScreenInit(pScreen, FBStart, width,
8804			height, pScrn->xDpi, pScrn->yDpi,
8805			displayWidth, pScrn->bitsPerPixel);
8806	  break;
8807       default:
8808	  ret = FALSE;
8809	  break;
8810    }
8811    if(!ret) {
8812       SISErrorLog(pScrn, "Unsupported bpp (%d) or fbScreenInit() failed\n",
8813			pScrn->bitsPerPixel);
8814       SISSaveScreen(pScreen, SCREEN_SAVER_OFF);
8815       return FALSE;
8816    }
8817
8818    /* Fixup RGB ordering */
8819    if(pScrn->bitsPerPixel > 8) {
8820       visual = pScreen->visuals + pScreen->numVisuals;
8821       while (--visual >= pScreen->visuals) {
8822          if((visual->class | DynamicClass) == DirectColor) {
8823             visual->offsetRed = pScrn->offset.red;
8824             visual->offsetGreen = pScrn->offset.green;
8825             visual->offsetBlue = pScrn->offset.blue;
8826             visual->redMask = pScrn->mask.red;
8827             visual->greenMask = pScrn->mask.green;
8828             visual->blueMask = pScrn->mask.blue;
8829          }
8830       }
8831    }
8832
8833    /* Initialize RENDER extension (must be after RGB ordering fixed) */
8834    fbPictureInit(pScreen, 0, 0);
8835
8836    /* Hardware cursor needs to wrap this layer */
8837    if(!pSiS->ShadowFB) SISDGAInit(pScreen);
8838
8839    xf86SetBlackWhitePixels(pScreen);
8840
8841    /* Initialize the accelerators */
8842    switch(pSiS->VGAEngine) {
8843    case SIS_530_VGA:
8844    case SIS_300_VGA:
8845       SiS300AccelInit(pScreen);
8846       break;
8847    case SIS_315_VGA:
8848       SiS315AccelInit(pScreen);
8849       break;
8850    default:
8851       SiSAccelInit(pScreen);
8852    }
8853
8854#ifdef TWDEBUG
8855    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CPUFlags %x\n", pSiS->CPUFlags);
8856#endif
8857
8858    /* Benchmark memcpy() methods (needs FB manager initialized) */
8859    /* Dual head: Do this AFTER the mode for CRT1 has been set */
8860    pSiS->NeedCopyFastVidCpy = FALSE;
8861    if(!pSiS->SiSFastVidCopyDone) {
8862#ifdef SISDUALHEAD
8863       if(pSiS->DualHeadMode) {
8864	  if(pSiS->SecondHead) {
8865	     pSiSEnt->SiSFastVidCopy = SiSVidCopyInit(pScreen, &pSiSEnt->SiSFastMemCopy, FALSE);
8866	     pSiSEnt->SiSFastVidCopyFrom = SiSVidCopyGetDefault();
8867	     pSiSEnt->SiSFastMemCopyFrom = SiSVidCopyGetDefault();
8868#ifdef SIS_USE_EXA
8869	     if(pSiS->useEXA) {
8870	        pSiSEnt->SiSFastVidCopyFrom = SiSVidCopyInit(pScreen, &pSiSEnt->SiSFastMemCopyFrom, TRUE);
8871	     }
8872#endif /* EXA */
8873	     pSiSEnt->HaveFastVidCpy = TRUE;
8874	     pSiS->SiSFastVidCopy = pSiSEnt->SiSFastVidCopy;
8875	     pSiS->SiSFastMemCopy = pSiSEnt->SiSFastMemCopy;
8876	     pSiS->SiSFastVidCopyFrom = pSiSEnt->SiSFastVidCopyFrom;
8877	     pSiS->SiSFastMemCopyFrom = pSiSEnt->SiSFastMemCopyFrom;
8878	  } else {
8879	     pSiS->NeedCopyFastVidCpy = TRUE;
8880	  }
8881       } else {
8882#endif
8883	  pSiS->SiSFastVidCopy = SiSVidCopyInit(pScreen, &pSiS->SiSFastMemCopy, FALSE);
8884	  pSiS->SiSFastVidCopyFrom = SiSVidCopyGetDefault();
8885	  pSiS->SiSFastMemCopyFrom = SiSVidCopyGetDefault();
8886#ifdef SIS_USE_EXA
8887	  if(pSiS->useEXA) {
8888	     pSiS->SiSFastVidCopyFrom = SiSVidCopyInit(pScreen, &pSiS->SiSFastMemCopyFrom, TRUE);
8889	  }
8890#endif /* EXA */
8891#ifdef SISDUALHEAD
8892       }
8893#endif
8894    }
8895    pSiS->SiSFastVidCopyDone = TRUE;
8896
8897    xf86SetBackingStore(pScreen);
8898    xf86SetSilkenMouse(pScreen);
8899
8900    /* Initialise cursor functions */
8901    miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
8902
8903    if(pSiS->HWCursor) {
8904       SiSHWCursorInit(pScreen);
8905    }
8906
8907#ifdef SISDUALHEAD
8908    if(!pSiS->DualHeadMode) {
8909#endif
8910       if((pSiS->VBFlags2 & VB2_SISBRIDGE) && (pScrn->depth > 8)) {
8911
8912	  pSiS->CRT2ColNum = 1 << pScrn->rgbBits;
8913
8914	  if((pSiS->crt2gcolortable = malloc(pSiS->CRT2ColNum * 2 * sizeof(LOCO)))) {
8915	     pSiS->crt2colors = &pSiS->crt2gcolortable[pSiS->CRT2ColNum];
8916	     if((pSiS->crt2cindices = malloc(256 * sizeof(int)))) {
8917		int i = pSiS->CRT2ColNum;
8918		SISCalculateGammaRampCRT2(pScrn);
8919		while(i--) pSiS->crt2cindices[i] = i;
8920	     } else {
8921		free(pSiS->crt2gcolortable);
8922		pSiS->crt2gcolortable = NULL;
8923		pSiS->CRT2SepGamma = FALSE;
8924	     }
8925	  } else {
8926	     pSiS->CRT2SepGamma = FALSE;
8927	  }
8928
8929	  if(!pSiS->crt2cindices) {
8930	     xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
8931	  	"Failed to allocate cmap for CRT2, separate gamma correction disabled\n");
8932	  }
8933
8934       }
8935#ifdef SISDUALHEAD
8936    } else pSiS->CRT2SepGamma = FALSE;
8937#endif
8938
8939    /* Initialise default colormap */
8940    if(!miCreateDefColormap(pScreen)) {
8941       SISSaveScreen(pScreen, SCREEN_SAVER_OFF);
8942       SISErrorLog(pScrn, "miCreateDefColormap() failed\n");
8943       return FALSE;
8944    }
8945
8946    if(!xf86HandleColormaps(pScreen, 256, (pScrn->depth == 8) ? 8 : pScrn->rgbBits,
8947                    SISLoadPalette, NULL,
8948                    CMAP_PALETTED_TRUECOLOR | CMAP_RELOAD_ON_MODE_SWITCH)) {
8949       SISSaveScreen(pScreen, SCREEN_SAVER_OFF);
8950       SISErrorLog(pScrn, "xf86HandleColormaps() failed\n");
8951       return FALSE;
8952    }
8953
8954    /* Recalculate our gamma ramp for brightness feature */
8955#ifdef SISGAMMARAMP
8956    if((pSiS->GammaBriR != 1000) ||
8957       (pSiS->GammaBriB != 1000) ||
8958       (pSiS->GammaBriG != 1000) ||
8959       (pSiS->NewGammaBriR != 0.0) ||
8960       (pSiS->NewGammaBriG != 0.0) ||
8961       (pSiS->NewGammaBriB != 0.0) ||
8962       (pSiS->NewGammaConR != 0.0) ||
8963       (pSiS->NewGammaConG != 0.0) ||
8964       (pSiS->NewGammaConB != 0.0)) {
8965       SISCalculateGammaRamp(pScreen, pScrn);
8966    }
8967#endif
8968
8969    /* Initialize Shadow framebuffer and screen rotation/reflection */
8970    if(pSiS->ShadowFB) {
8971       RefreshAreaFuncPtr refreshArea = SISRefreshArea;
8972
8973       if(pSiS->Rotate) {
8974	  if(!pSiS->PointerMoved) pSiS->PointerMoved = pScrn->PointerMoved;
8975	  pScrn->PointerMoved = SISPointerMoved;
8976	  switch(pScrn->bitsPerPixel) {
8977	     case 8:  refreshArea = SISRefreshArea8;  break;
8978	     case 16: refreshArea = SISRefreshArea16; break;
8979	     case 24: refreshArea = SISRefreshArea24; break;
8980	     case 32: refreshArea = SISRefreshArea32; break;
8981	  }
8982#if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4,3,0,0,0)
8983	  xf86DisableRandR();
8984	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
8985		"Driver rotation enabled, disabling RandR\n");
8986#endif
8987       } else if(pSiS->Reflect) {
8988          switch(pScrn->bitsPerPixel) {
8989	  case 8:
8990	  case 16:
8991	  case 32:
8992             if(!pSiS->PointerMoved) pSiS->PointerMoved = pScrn->PointerMoved;
8993	     pScrn->PointerMoved = SISPointerMovedReflect;
8994	     refreshArea = SISRefreshAreaReflect;
8995#if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4,3,0,0,0)
8996	     xf86DisableRandR();
8997	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
8998		  "Driver reflection enabled, disabling RandR\n");
8999#endif
9000	     break;
9001	  default:
9002	     xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
9003	     	  "Reflection not supported at this framebuffer depth\n");
9004	  }
9005       }
9006
9007       ShadowFBInit(pScreen, refreshArea);
9008    }
9009
9010    xf86DPMSInit(pScreen, (DPMSSetProcPtr)SISDisplayPowerManagementSet, 0);
9011
9012    /* Init memPhysBase and fbOffset in pScrn */
9013    pScrn->memPhysBase = pSiS->FbAddress;
9014    pScrn->fbOffset = 0;
9015
9016    /* Initialize Xv */
9017    pSiS->ResetXv = pSiS->ResetXvGamma = pSiS->ResetXvDisplay = NULL;
9018#if (XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4,3,99,0,0)) || (defined(XvExtension))
9019    if((!pSiS->NoXvideo) && (!(pSiS->SiS_SD2_Flags & SiS_SD2_NOOVERLAY))) {
9020
9021       if((pSiS->VGAEngine == SIS_300_VGA) ||
9022	  (pSiS->VGAEngine == SIS_315_VGA)) {
9023
9024	  const char *using = "Using SiS300/315/330/340 series HW Xv";
9025
9026#ifdef SISDUALHEAD
9027	  if(pSiS->DualHeadMode) {
9028	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
9029		    "%s on CRT%d\n", using, (pSiS->SecondHead ? 1 : 2));
9030	     if(!pSiS->hasTwoOverlays) {
9031		if( (pSiS->XvOnCRT2 && pSiS->SecondHead) ||
9032		    (!pSiS->XvOnCRT2 && !pSiS->SecondHead) ) {
9033		   xf86DrvMsg(pScrn->scrnIndex, X_INFO,
9034			   "However, video overlay will by default only be visible on CRT%d\n",
9035			   pSiS->XvOnCRT2 ? 2 : 1);
9036		}
9037	     }
9038	  } else {
9039#endif
9040	     if(pSiS->hasTwoOverlays) {
9041		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s\n", using);
9042	     } else {
9043		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s by default on CRT%d\n",
9044			using, (pSiS->XvOnCRT2 ? 2 : 1));
9045	     }
9046#ifdef SISDUALHEAD
9047	  }
9048#endif
9049
9050	  SISInitVideo(pScreen);
9051
9052	  if(pSiS->blitadaptor) {
9053	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
9054		     "Default Xv adaptor is Video %s\n",
9055		     pSiS->XvDefAdaptorBlit ? "Blitter" : "Overlay");
9056	  }
9057
9058       } else if(pSiS->Chipset == PCI_CHIP_SIS530  ||
9059		 pSiS->Chipset == PCI_CHIP_SIS6326 ||
9060		 pSiS->Chipset == PCI_CHIP_SIS5597) {
9061
9062	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
9063		        "Using SiS5597/5598/6326/530/620 HW Xv\n" );
9064
9065	  SIS6326InitVideo(pScreen);
9066
9067       } else { /* generic Xv */
9068
9069	  XF86VideoAdaptorPtr *ptr;
9070	  int n = xf86XVListGenericAdaptors(pScrn, &ptr);
9071
9072	  if(n) {
9073	     xf86XVScreenInit(pScreen, ptr, n);
9074	     xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using generic Xv\n" );
9075          }
9076
9077       }
9078    }
9079#endif
9080
9081#ifdef SISDRI
9082    if(pSiS->loadDRI) {
9083       if(pSiS->directRenderingEnabled) {
9084          /* Now that mi, drm and others have done their thing,
9085           * complete the DRI setup.
9086           */
9087          pSiS->directRenderingEnabled = SISDRIFinishScreenInit(pScreen);
9088       }
9089       xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Direct rendering %s\n",
9090		pSiS->directRenderingEnabled ? "enabled" : "disabled");
9091       /* TODO */
9092       /* if(pSiS->directRenderingEnabled) SISSetLFBConfig(pSiS); */
9093    }
9094#endif
9095
9096    /* Wrap some funcs, initialize pseudo-Xinerama and setup remaining SD flags */
9097
9098    pSiS->SiS_SD_Flags &= ~(SiS_SD_PSEUDOXINERAMA);
9099#ifdef SISMERGED
9100    if(pSiS->MergedFB) {
9101       pSiS->PointerMoved = pScrn->PointerMoved;
9102       pScrn->PointerMoved = SISMergedPointerMoved;
9103       pSiS->Rotate = 0;
9104       pSiS->Reflect = 0;
9105       pSiS->ShadowFB = FALSE;
9106#if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4,3,0,0,0)
9107       if(pSiS->CRT1XOffs || pSiS->CRT1YOffs || pSiS->CRT2XOffs || pSiS->CRT2YOffs) {
9108	  xf86DisableRandR();
9109	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
9110		"MergedFB: CRT2Position offset used, disabling RandR\n");
9111       }
9112#endif
9113#ifdef SISXINERAMA
9114       if(pSiS->UseSiSXinerama) {
9115	  SiSnoPanoramiXExtension = FALSE;
9116	  SiSXineramaExtensionInit(pScrn);
9117	  if(!SiSnoPanoramiXExtension) {
9118	     pSiS->SiS_SD_Flags |= SiS_SD_PSEUDOXINERAMA;
9119	     if(pSiS->HaveNonRect) {
9120		/* Reset the viewport (now eventually non-recangular) */
9121		SISAdjustFrame(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0));
9122	     }
9123	  }
9124       } else {
9125	  pSiS->MouseRestrictions = FALSE;
9126       }
9127#endif
9128    }
9129#endif
9130
9131    /* Wrap CloseScreen and set up SaveScreen */
9132    pSiS->CloseScreen = pScreen->CloseScreen;
9133    pScreen->CloseScreen = SISCloseScreen;
9134#ifdef SISDUALHEAD
9135    if(pSiS->DualHeadMode)
9136       pScreen->SaveScreen = SISSaveScreenDH;
9137    else
9138#endif
9139       pScreen->SaveScreen = SISSaveScreen;
9140
9141    /* Install BlockHandler */
9142    pSiS->BlockHandler = pScreen->BlockHandler;
9143    pScreen->BlockHandler = SISBlockHandler;
9144
9145    /* Report any unused options (only for the first generation) */
9146    if(serverGeneration == 1) {
9147       xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
9148    }
9149
9150    /* Clear frame buffer */
9151    /* For CRT2, we don't do that at this point in dual head
9152     * mode since the mode isn't switched at this time (it will
9153     * be reset when setting the CRT1 mode). Hence, we just
9154     * save the necessary data and clear the screen when
9155     * going through this for CRT1.
9156     */
9157
9158    OnScreenSize = pScrn->displayWidth * pScrn->currentMode->VDisplay
9159                               * (pScrn->bitsPerPixel >> 3);
9160
9161    /* Turn on the screen now */
9162    /* We do this in dual head mode after second head is finished */
9163#ifdef SISDUALHEAD
9164    if(pSiS->DualHeadMode) {
9165       if(pSiS->SecondHead) {
9166	  sisclearvram(pSiS->FbBase, OnScreenSize);
9167	  sisclearvram(pSiSEnt->FbBase1, pSiSEnt->OnScreenSize1);
9168	  SISSaveScreen(pScreen, SCREEN_SAVER_OFF);
9169       } else {
9170	  pSiSEnt->FbBase1 = pSiS->FbBase;
9171	  pSiSEnt->OnScreenSize1 = OnScreenSize;
9172       }
9173    } else {
9174#endif
9175       SISSaveScreen(pScreen, SCREEN_SAVER_OFF);
9176       sisclearvram(pSiS->FbBase, OnScreenSize);
9177#ifdef SISDUALHEAD
9178    }
9179#endif
9180
9181    pSiS->SiS_SD_Flags &= ~SiS_SD_SUPPORTSGRCRT2;
9182#ifdef SISDUALHEAD
9183    if(!pSiS->DualHeadMode) {
9184#endif
9185       if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
9186          if((pSiS->crt2cindices) && (pSiS->crt2gcolortable)) {
9187             pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTSGRCRT2;
9188	  }
9189       }
9190#ifdef SISDUALHEAD
9191    }
9192#endif
9193
9194    pSiS->SiS_SD_Flags &= ~SiS_SD_ISDEPTH8;
9195    if(pSiS->CurrentLayout.bitsPerPixel == 8) {
9196       pSiS->SiS_SD_Flags |= SiS_SD_ISDEPTH8;
9197       pSiS->SiS_SD_Flags &= ~SiS_SD_SUPPORTXVGAMMA1;
9198       pSiS->SiS_SD_Flags &= ~SiS_SD_SUPPORTSGRCRT2;
9199    }
9200
9201#ifdef SISGAMMARAMP
9202    pSiS->SiS_SD_Flags |= SiS_SD_CANSETGAMMA;
9203#else
9204    pSiS->SiS_SD_Flags &= ~SiS_SD_CANSETGAMMA;
9205#endif
9206
9207    SiSCtrlExtInit(pScrn);
9208
9209    return TRUE;
9210}
9211
9212/* Usually mandatory */
9213Bool
9214SISSwitchMode(SWITCH_MODE_ARGS_DECL)
9215{
9216    SCRN_INFO_PTR(arg);
9217    SISPtr pSiS = SISPTR(pScrn);
9218
9219    if(!pSiS->skipswitchcheck) {
9220       if(SISValidMode(arg, mode, TRUE, 0) != MODE_OK) {
9221          return FALSE;
9222       }
9223    }
9224
9225    (*pSiS->SyncAccel)(pScrn);
9226
9227    if(!(SISModeInit(pScrn, mode))) return FALSE;
9228
9229    /* Since RandR (indirectly) uses SwitchMode(), we need to
9230     * update our Xinerama info here, too, in case of resizing
9231     */
9232#ifdef SISMERGED
9233#ifdef SISXINERAMA
9234    if(pSiS->MergedFB) {
9235       SiSUpdateXineramaScreenInfo(pScrn);
9236    }
9237#endif
9238#endif
9239    return TRUE;
9240}
9241
9242static void
9243SISSetStartAddressCRT1(SISPtr pSiS, ULong base)
9244{
9245    UChar cr11backup;
9246
9247    inSISIDXREG(SISCR,  0x11, cr11backup);  /* Unlock CRTC registers */
9248    andSISIDXREG(SISCR, 0x11, 0x7F);
9249    outSISIDXREG(SISCR, 0x0D, base & 0xFF);
9250    outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF);
9251    outSISIDXREG(SISSR, 0x0D, (base >> 16) & 0xFF);
9252    if(pSiS->VGAEngine == SIS_315_VGA) {
9253       setSISIDXREG(SISSR, 0x37, 0xFE, (base >> 24) & 0x01);
9254    }
9255    /* Eventually lock CRTC registers */
9256    setSISIDXREG(SISCR, 0x11, 0x7F,(cr11backup & 0x80));
9257}
9258
9259static void
9260SISSetStartAddressCRT2(SISPtr pSiS, ULong base)
9261{
9262    SiS_UnLockCRT2(pSiS->SiS_Pr);
9263    outSISIDXREG(SISPART1, 0x06, GETVAR8(base));
9264    outSISIDXREG(SISPART1, 0x05, GETBITS(base, 15:8));
9265    outSISIDXREG(SISPART1, 0x04, GETBITS(base, 23:16));
9266    if(pSiS->VGAEngine == SIS_315_VGA) {
9267       setSISIDXREG(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7);
9268    }
9269    SiS_LockCRT2(pSiS->SiS_Pr);
9270}
9271
9272#ifdef SISMERGED
9273static Bool
9274InRegion(int x, int y, region r)
9275{
9276    return (r.x0 <= x) && (x <= r.x1) && (r.y0 <= y) && (y <= r.y1);
9277}
9278
9279static void
9280SISAdjustFrameHW_CRT1(ScrnInfoPtr pScrn, int x, int y)
9281{
9282    SISPtr pSiS = SISPTR(pScrn);
9283    ULong base;
9284
9285    base = y * pSiS->CurrentLayout.displayWidth + x;
9286    switch(pSiS->CurrentLayout.bitsPerPixel) {
9287       case 16:  base >>= 1; 	break;
9288       case 32:  		break;
9289       default:  base >>= 2;
9290    }
9291    base += (pSiS->dhmOffset/4);
9292    SISSetStartAddressCRT1(pSiS, base);
9293}
9294
9295static void
9296SISAdjustFrameHW_CRT2(ScrnInfoPtr pScrn, int x, int y)
9297{
9298    SISPtr pSiS = SISPTR(pScrn);
9299    ULong base;
9300
9301    base = y * pSiS->CurrentLayout.displayWidth + x;
9302    switch(pSiS->CurrentLayout.bitsPerPixel) {
9303       case 16:  base >>= 1; 	break;
9304       case 32:  		break;
9305       default:  base >>= 2;
9306    }
9307    base += (pSiS->dhmOffset/4);
9308    SISSetStartAddressCRT2(pSiS, base);
9309}
9310
9311static void
9312SISMergedPointerMoved(SCRN_ARG_TYPE arg, int x, int y)
9313{
9314  SCRN_INFO_PTR(arg);
9315  ScrnInfoPtr	pScrn1 = pScrn;
9316  SISPtr	pSiS = SISPTR(pScrn1);
9317  ScrnInfoPtr	pScrn2 = pSiS->CRT2pScrn;
9318  region	out, in1, in2, f2, f1;
9319  int		deltax, deltay;
9320  int		temp1, temp2;
9321  int		old1x0, old1y0, old2x0, old2y0;
9322  int		CRT1XOffs = 0, CRT1YOffs = 0, CRT2XOffs = 0, CRT2YOffs = 0;
9323  int		HVirt = pScrn1->virtualX;
9324  int		VVirt = pScrn1->virtualY;
9325  int		sigstate;
9326  Bool		doit = FALSE, HaveNonRect = FALSE, HaveOffsRegions = FALSE;
9327  SiSScrn2Rel   srel = ((SiSMergedDisplayModePtr)pSiS->CurrentLayout.mode->Private)->CRT2Position;
9328
9329  if(pSiS->DGAactive) {
9330     return;
9331     /* DGA: There is no cursor and no panning while DGA is active. */
9332     /* If it were, we would need to do: */
9333     /* HVirt = pSiS->CurrentLayout.displayWidth;
9334        VVirt = pSiS->CurrentLayout.displayHeight;
9335        BOUND(x, pSiS->CurrentLayout.DGAViewportX, HVirt);
9336        BOUND(y, pSiS->CurrentLayout.DGAViewportY, VVirt); */
9337  } else {
9338     CRT1XOffs = pSiS->CRT1XOffs;
9339     CRT1YOffs = pSiS->CRT1YOffs;
9340     CRT2XOffs = pSiS->CRT2XOffs;
9341     CRT2YOffs = pSiS->CRT2YOffs;
9342     HaveNonRect = pSiS->HaveNonRect;
9343     HaveOffsRegions = pSiS->HaveOffsRegions;
9344  }
9345
9346  /* Check if the pointer is inside our dead areas */
9347  if((pSiS->MouseRestrictions) && (srel != sisClone) && !SiSnoPanoramiXExtension) {
9348     if(HaveNonRect) {
9349	if(InRegion(x, y, pSiS->NonRectDead)) {
9350	   switch(srel) {
9351	   case sisLeftOf:
9352	   case sisRightOf: y = pSiS->NonRectDead.y0 - 1;
9353			    doit = TRUE;
9354			    break;
9355	   case sisAbove:
9356	   case sisBelow:   x = pSiS->NonRectDead.x0 - 1;
9357			    doit = TRUE;
9358	   default:	    break;
9359	   }
9360	}
9361     }
9362     if(HaveOffsRegions) {
9363	if(InRegion(x, y, pSiS->OffDead1)) {
9364	   switch(srel) {
9365	   case sisLeftOf:
9366	   case sisRightOf: y = pSiS->OffDead1.y1;
9367			    doit = TRUE;
9368			    break;
9369	   case sisAbove:
9370	   case sisBelow:   x = pSiS->OffDead1.x1;
9371			    doit = TRUE;
9372	   default:	    break;
9373	   }
9374	} else if(InRegion(x, y, pSiS->OffDead2)) {
9375	   switch(srel) {
9376	   case sisLeftOf:
9377	   case sisRightOf: y = pSiS->OffDead2.y0 - 1;
9378			    doit = TRUE;
9379			    break;
9380	   case sisAbove:
9381	   case sisBelow:   x = pSiS->OffDead2.x0 - 1;
9382			    doit = TRUE;
9383	   default:	    break;
9384	   }
9385	}
9386     }
9387     if(doit) {
9388#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 20 /* screw it */
9389	sigstate = xf86BlockSIGIO();
9390#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 15
9391        {
9392            double dx = x, dy = y;
9393            miPointerSetPosition(inputInfo.pointer, Absolute, &dx, &dy);
9394            x = (int)dx;
9395            y = (int)dy;
9396        }
9397#elif GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 13
9398	miPointerSetPosition(inputInfo.pointer, Absolute, &x, &y);
9399#elif GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 5
9400	miPointerSetPosition(inputInfo.pointer, &x, &y);
9401#else
9402	UpdateCurrentTime();
9403	miPointerAbsoluteCursor(x, y, currentTime.milliseconds);
9404#endif
9405	xf86UnblockSIGIO(sigstate);
9406#endif
9407	return;
9408     }
9409  }
9410
9411  f1.x0 = old1x0 = pSiS->CRT1frameX0;
9412  f1.x1 = pSiS->CRT1frameX1;
9413  f1.y0 = old1y0 = pSiS->CRT1frameY0;
9414  f1.y1 = pSiS->CRT1frameY1;
9415  f2.x0 = old2x0 = pScrn2->frameX0;
9416  f2.x1 = pScrn2->frameX1;
9417  f2.y0 = old2y0 = pScrn2->frameY0;
9418  f2.y1 = pScrn2->frameY1;
9419
9420  /* Define the outer region. Crossing this causes all frames to move */
9421  out.x0 = pScrn1->frameX0;
9422  out.x1 = pScrn1->frameX1;
9423  out.y0 = pScrn1->frameY0;
9424  out.y1 = pScrn1->frameY1;
9425
9426  /*
9427   * Define the inner sliding window. Being outsize both frames but
9428   * inside the outer clipping window will slide corresponding frame
9429   */
9430  in1 = out;
9431  in2 = out;
9432  switch(srel) {
9433     case sisLeftOf:
9434        in1.x0 = f1.x0;
9435        in2.x1 = f2.x1;
9436        break;
9437     case sisRightOf:
9438        in1.x1 = f1.x1;
9439        in2.x0 = f2.x0;
9440        break;
9441     case sisBelow:
9442        in1.y1 = f1.y1;
9443        in2.y0 = f2.y0;
9444        break;
9445     case sisAbove:
9446        in1.y0 = f1.y0;
9447        in2.y1 = f2.y1;
9448        break;
9449     case sisClone:
9450        break;
9451  }
9452
9453  deltay = 0;
9454  deltax = 0;
9455
9456  if(InRegion(x, y, out)) {	/* inside outer region */
9457
9458     if(InRegion(x, y, in1) && !InRegion(x, y, f1)) {
9459	REBOUND(f1.x0, f1.x1, x);
9460	REBOUND(f1.y0, f1.y1, y);
9461	deltax = 1;
9462     }
9463     if(InRegion(x, y, in2) && !InRegion(x, y, f2)) {
9464	REBOUND(f2.x0, f2.x1, x);
9465	REBOUND(f2.y0, f2.y1, y);
9466	deltax = 1;
9467     }
9468
9469  } else {			/* outside outer region */
9470
9471     if(out.x0 > x) {
9472	deltax = x - out.x0;
9473     }
9474     if(out.x1 < x) {
9475	deltax = x - out.x1;
9476     }
9477     if(deltax) {
9478	pScrn1->frameX0 += deltax;
9479	pScrn1->frameX1 += deltax;
9480	f1.x0 += deltax;
9481	f1.x1 += deltax;
9482	f2.x0 += deltax;
9483	f2.x1 += deltax;
9484     }
9485
9486     if(out.y0 > y) {
9487	deltay = y - out.y0;
9488     }
9489     if(out.y1 < y) {
9490	deltay = y - out.y1;
9491     }
9492     if(deltay) {
9493	pScrn1->frameY0 += deltay;
9494	pScrn1->frameY1 += deltay;
9495	f1.y0 += deltay;
9496	f1.y1 += deltay;
9497	f2.y0 += deltay;
9498	f2.y1 += deltay;
9499     }
9500
9501     switch(srel) {
9502	case sisLeftOf:
9503	   if(x >= f1.x0) { REBOUND(f1.y0, f1.y1, y); }
9504	   if(x <= f2.x1) { REBOUND(f2.y0, f2.y1, y); }
9505	   break;
9506	case sisRightOf:
9507	   if(x <= f1.x1) { REBOUND(f1.y0, f1.y1, y); }
9508	   if(x >= f2.x0) { REBOUND(f2.y0, f2.y1, y); }
9509	   break;
9510	case sisBelow:
9511	   if(y <= f1.y1) { REBOUND(f1.x0, f1.x1, x); }
9512	   if(y >= f2.y0) { REBOUND(f2.x0, f2.x1, x); }
9513	   break;
9514	case sisAbove:
9515	   if(y >= f1.y0) { REBOUND(f1.x0, f1.x1, x); }
9516	   if(y <= f2.y1) { REBOUND(f2.x0, f2.x1, x); }
9517	   break;
9518	case sisClone:
9519	   break;
9520     }
9521
9522  }
9523
9524  if(deltax || deltay) {
9525     pSiS->CRT1frameX0 = f1.x0;
9526     pSiS->CRT1frameY0 = f1.y0;
9527     pScrn2->frameX0 = f2.x0;
9528     pScrn2->frameY0 = f2.y0;
9529
9530     switch(srel) {
9531	case sisLeftOf:
9532	case sisRightOf:
9533	   if(CRT1YOffs || CRT2YOffs || HaveNonRect) {
9534	      if(pSiS->CRT1frameY0 != old1y0) {
9535	         if(pSiS->CRT1frameY0 < CRT1YOffs)
9536	            pSiS->CRT1frameY0 = CRT1YOffs;
9537
9538	         temp1 = pSiS->CRT1frameY0 + CDMPTR->CRT1->VDisplay;
9539	         temp2 = min((VVirt - CRT2YOffs), (CRT1YOffs + pSiS->MBXNR1YMAX));
9540	         if(temp1 > temp2)
9541	            pSiS->CRT1frameY0 -= (temp1 - temp2);
9542	      }
9543	      if(pScrn2->frameY0 != old2y0) {
9544	         if(pScrn2->frameY0 < CRT2YOffs)
9545	            pScrn2->frameY0 = CRT2YOffs;
9546
9547	         temp1 = pScrn2->frameY0 + CDMPTR->CRT2->VDisplay;
9548	         temp2 = min((VVirt - CRT1YOffs), (CRT2YOffs + pSiS->MBXNR2YMAX));
9549	         if(temp1 > temp2)
9550	            pScrn2->frameY0 -= (temp1 - temp2);
9551	      }
9552	   }
9553	   break;
9554	case sisBelow:
9555	case sisAbove:
9556	   if(CRT1XOffs || CRT2XOffs || HaveNonRect) {
9557	      if(pSiS->CRT1frameX0 != old1x0) {
9558	         if(pSiS->CRT1frameX0 < CRT1XOffs)
9559	            pSiS->CRT1frameX0 = CRT1XOffs;
9560
9561	         temp1 = pSiS->CRT1frameX0 + CDMPTR->CRT1->HDisplay;
9562	         temp2 = min((HVirt - CRT2XOffs), (CRT1XOffs + pSiS->MBXNR1XMAX));
9563	         if(temp1 > temp2)
9564	            pSiS->CRT1frameX0 -= (temp1 - temp2);
9565	      }
9566	      if(pScrn2->frameX0 != old2x0) {
9567	         if(pScrn2->frameX0 < CRT2XOffs)
9568	            pScrn2->frameX0 = CRT2XOffs;
9569
9570	         temp1 = pScrn2->frameX0 + CDMPTR->CRT2->HDisplay;
9571	         temp2 = min((HVirt - CRT1XOffs), (CRT2XOffs + pSiS->MBXNR2XMAX));
9572	         if(temp1 > temp2)
9573	            pScrn2->frameX0 -= (temp1 - temp2);
9574	      }
9575	   }
9576	   break;
9577	case sisClone:
9578	   break;
9579     }
9580
9581     pSiS->CRT1frameX1 = pSiS->CRT1frameX0 + CDMPTR->CRT1->HDisplay - 1;
9582     pSiS->CRT1frameY1 = pSiS->CRT1frameY0 + CDMPTR->CRT1->VDisplay - 1;
9583     pScrn2->frameX1   = pScrn2->frameX0   + CDMPTR->CRT2->HDisplay - 1;
9584     pScrn2->frameY1   = pScrn2->frameY0   + CDMPTR->CRT2->VDisplay - 1;
9585
9586     /* No need to update pScrn1->frame?1, done above */
9587
9588     SISAdjustFrameHW_CRT1(pScrn1, pSiS->CRT1frameX0, pSiS->CRT1frameY0);
9589     SISAdjustFrameHW_CRT2(pScrn1, pScrn2->frameX0, pScrn2->frameY0);
9590  }
9591}
9592
9593static void
9594SISAdjustFrameMerged(ADJUST_FRAME_ARGS_DECL)
9595{
9596    SCRN_INFO_PTR(arg);
9597    ScrnInfoPtr pScrn1 = pScrn;
9598    SISPtr pSiS = SISPTR(pScrn1);
9599    ScrnInfoPtr pScrn2 = pSiS->CRT2pScrn;
9600    int HTotal = pSiS->CurrentLayout.mode->HDisplay;
9601    int VTotal = pSiS->CurrentLayout.mode->VDisplay;
9602    int HMax = HTotal;
9603    int VMax = VTotal;
9604    int HVirt = pScrn1->virtualX;
9605    int VVirt = pScrn1->virtualY;
9606    int x1 = x, x2 = x;
9607    int y1 = y, y2 = y;
9608    int CRT1XOffs = 0, CRT1YOffs = 0, CRT2XOffs = 0, CRT2YOffs = 0;
9609    int MBXNR1XMAX = 65536, MBXNR1YMAX = 65536, MBXNR2XMAX = 65536, MBXNR2YMAX = 65536;
9610
9611    if(pSiS->DGAactive) {
9612       HVirt = pSiS->CurrentLayout.displayWidth;
9613       VVirt = pSiS->CurrentLayout.displayHeight;
9614    } else {
9615       CRT1XOffs = pSiS->CRT1XOffs;
9616       CRT1YOffs = pSiS->CRT1YOffs;
9617       CRT2XOffs = pSiS->CRT2XOffs;
9618       CRT2YOffs = pSiS->CRT2YOffs;
9619       MBXNR1XMAX = pSiS->MBXNR1XMAX;
9620       MBXNR1YMAX = pSiS->MBXNR1YMAX;
9621       MBXNR2XMAX = pSiS->MBXNR2XMAX;
9622       MBXNR2YMAX = pSiS->MBXNR2YMAX;
9623    }
9624
9625    BOUND(x, 0, HVirt - HTotal);
9626    BOUND(y, 0, VVirt - VTotal);
9627    if(SDMPTR(pScrn1)->CRT2Position != sisClone) {
9628       BOUND(x1, CRT1XOffs, min(HVirt, MBXNR1XMAX + CRT1XOffs) - min(HTotal, MBXNR1XMAX) - CRT2XOffs);
9629       BOUND(y1, CRT1YOffs, min(VVirt, MBXNR1YMAX + CRT1YOffs) - min(VTotal, MBXNR1YMAX) - CRT2YOffs);
9630       BOUND(x2, CRT2XOffs, min(HVirt, MBXNR2XMAX + CRT2XOffs) - min(HTotal, MBXNR2XMAX) - CRT1XOffs);
9631       BOUND(y2, CRT2YOffs, min(VVirt, MBXNR2YMAX + CRT2YOffs) - min(VTotal, MBXNR2YMAX) - CRT1YOffs);
9632    }
9633
9634    switch(SDMPTR(pScrn1)->CRT2Position) {
9635        case sisLeftOf:
9636            pScrn2->frameX0 = x2;
9637            BOUND(pScrn2->frameY0,   y2, y2 + min(VMax, MBXNR2YMAX) - CDMPTR->CRT2->VDisplay);
9638            pSiS->CRT1frameX0 = x1 + CDMPTR->CRT2->HDisplay;
9639            BOUND(pSiS->CRT1frameY0, y1, y1 + min(VMax, MBXNR1YMAX) - CDMPTR->CRT1->VDisplay);
9640            break;
9641        case sisRightOf:
9642            pSiS->CRT1frameX0 = x1;
9643            BOUND(pSiS->CRT1frameY0, y1, y1 + min(VMax, MBXNR1YMAX) - CDMPTR->CRT1->VDisplay);
9644            pScrn2->frameX0 = x2 + CDMPTR->CRT1->HDisplay;
9645            BOUND(pScrn2->frameY0,   y2, y2 + min(VMax, MBXNR2YMAX) - CDMPTR->CRT2->VDisplay);
9646            break;
9647        case sisAbove:
9648            BOUND(pScrn2->frameX0,   x2, x2 + min(HMax, MBXNR2XMAX) - CDMPTR->CRT2->HDisplay);
9649            pScrn2->frameY0 = y2;
9650            BOUND(pSiS->CRT1frameX0, x1, x1 + min(HMax, MBXNR1XMAX) - CDMPTR->CRT1->HDisplay);
9651            pSiS->CRT1frameY0 = y1 + CDMPTR->CRT2->VDisplay;
9652            break;
9653        case sisBelow:
9654            BOUND(pSiS->CRT1frameX0, x1, x1 + min(HMax, MBXNR1XMAX) - CDMPTR->CRT1->HDisplay);
9655            pSiS->CRT1frameY0 = y1;
9656            BOUND(pScrn2->frameX0,   x2, x2 + min(HMax, MBXNR2XMAX) - CDMPTR->CRT2->HDisplay);
9657            pScrn2->frameY0 = y2 + CDMPTR->CRT1->VDisplay;
9658            break;
9659        case sisClone:
9660            BOUND(pSiS->CRT1frameX0, x,  x + HMax - CDMPTR->CRT1->HDisplay);
9661            BOUND(pSiS->CRT1frameY0, y,  y + VMax - CDMPTR->CRT1->VDisplay);
9662            BOUND(pScrn2->frameX0,   x,  x + HMax - CDMPTR->CRT2->HDisplay);
9663            BOUND(pScrn2->frameY0,   y,  y + VMax - CDMPTR->CRT2->VDisplay);
9664            break;
9665    }
9666
9667    BOUND(pSiS->CRT1frameX0, 0, HVirt - CDMPTR->CRT1->HDisplay);
9668    BOUND(pSiS->CRT1frameY0, 0, VVirt - CDMPTR->CRT1->VDisplay);
9669    BOUND(pScrn2->frameX0,   0, HVirt - CDMPTR->CRT2->HDisplay);
9670    BOUND(pScrn2->frameY0,   0, VVirt - CDMPTR->CRT2->VDisplay);
9671
9672    pScrn1->frameX0 = x;
9673    pScrn1->frameY0 = y;
9674
9675    pSiS->CRT1frameX1 = pSiS->CRT1frameX0 + CDMPTR->CRT1->HDisplay - 1;
9676    pSiS->CRT1frameY1 = pSiS->CRT1frameY0 + CDMPTR->CRT1->VDisplay - 1;
9677    pScrn2->frameX1   = pScrn2->frameX0   + CDMPTR->CRT2->HDisplay - 1;
9678    pScrn2->frameY1   = pScrn2->frameY0   + CDMPTR->CRT2->VDisplay - 1;
9679
9680    pScrn1->frameX1   = pScrn1->frameX0   + pSiS->CurrentLayout.mode->HDisplay  - 1;
9681    pScrn1->frameY1   = pScrn1->frameY0   + pSiS->CurrentLayout.mode->VDisplay  - 1;
9682    if(SDMPTR(pScrn1)->CRT2Position != sisClone) {
9683       pScrn1->frameX1 += CRT1XOffs + CRT2XOffs;
9684       pScrn1->frameY1 += CRT1YOffs + CRT2YOffs;
9685    }
9686
9687    SISAdjustFrameHW_CRT1(pScrn1, pSiS->CRT1frameX0, pSiS->CRT1frameY0);
9688    SISAdjustFrameHW_CRT2(pScrn1, pScrn2->frameX0, pScrn2->frameY0);
9689}
9690#endif
9691
9692/*
9693 * This function is used to initialize the Start Address - the first
9694 * displayed location in the video memory.
9695 *
9696 * Usually mandatory
9697 */
9698void
9699SISAdjustFrame(ADJUST_FRAME_ARGS_DECL)
9700{
9701    SCRN_INFO_PTR(arg);
9702    SISPtr        pSiS = SISPTR(pScrn);
9703    ULong base;
9704    UChar temp, cr11backup;
9705
9706#ifdef SISMERGED
9707    if(pSiS->MergedFB) {
9708        SISAdjustFrameMerged(ADJUST_FRAME_ARGS(pScrn, x, y));
9709	return;
9710    }
9711#endif
9712
9713    if(pSiS->UseVESA) {
9714	VBESetDisplayStart(pSiS->pVbe, x, y, TRUE);
9715	return;
9716    }
9717
9718    if(pScrn->bitsPerPixel < 8) {
9719       base = (y * pSiS->CurrentLayout.displayWidth + x + 3) >> 3;
9720    } else {
9721       base  = y * pSiS->CurrentLayout.displayWidth + x;
9722
9723       /* calculate base bpp dep. */
9724       switch(pSiS->CurrentLayout.bitsPerPixel) {
9725          case 16:
9726     	     base >>= 1;
9727             break;
9728          case 24:
9729             base = ((base * 3)) >> 2;
9730             base -= base % 6;
9731             break;
9732          case 32:
9733             break;
9734          default:      /* 8bpp */
9735             base >>= 2;
9736             break;
9737       }
9738    }
9739
9740#ifdef UNLOCK_ALWAYS
9741    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
9742#endif
9743
9744    base += (pSiS->dhmOffset/4);
9745
9746#ifdef TWDEBUG
9747    xf86DrvMsg(0, 0, "AdjustFrame: x %d y %d bpp %d dw %d base %d, dhmOffset %d\n",
9748    			x, y, pSiS->CurrentLayout.bitsPerPixel, pSiS->CurrentLayout.displayWidth, base, pSiS->dhmOffset);
9749#endif
9750
9751#ifdef SISDUALHEAD
9752    if(pSiS->DualHeadMode) {
9753       if(!pSiS->SecondHead) {
9754	  /* Head 1 (master) is always CRT2 */
9755	  SISSetStartAddressCRT2(pSiS, base);
9756       } else {
9757	  /* Head 2 (slave) is always CRT1 */
9758	  SISSetStartAddressCRT1(pSiS, base);
9759       }
9760    } else {
9761#endif
9762       switch(pSiS->VGAEngine) {
9763	  case SIS_300_VGA:
9764	  case SIS_315_VGA:
9765	     SISSetStartAddressCRT1(pSiS, base);
9766	     if(pSiS->VBFlags & CRT2_ENABLE) {
9767		if(!SiSBridgeIsInSlaveMode(pScrn)) {
9768		   SISSetStartAddressCRT2(pSiS, base);
9769		}
9770	     }
9771	     break;
9772	  default:
9773	     /* Unlock CRTC registers */
9774	     inSISIDXREG(SISCR,  0x11, cr11backup);
9775	     andSISIDXREG(SISCR, 0x11, 0x7F);
9776	     outSISIDXREG(SISCR, 0x0D, base & 0xFF);
9777	     outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF);
9778	     inSISIDXREG(SISSR,  0x27, temp);
9779	     temp &= 0xF0;
9780	     temp |= (base & 0x0F0000) >> 16;
9781	     outSISIDXREG(SISSR, 0x27, temp);
9782	     /* Eventually lock CRTC registers */
9783	     setSISIDXREG(SISCR, 0x11, 0x7F, (cr11backup & 0x80));
9784       }
9785#ifdef SISDUALHEAD
9786    }
9787#endif
9788
9789}
9790
9791/*
9792 * This is called when VT switching back to the X server.  Its job is
9793 * to reinitialise the video mode.
9794 * Mandatory!
9795 */
9796static Bool
9797SISEnterVT(VT_FUNC_ARGS_DECL)
9798{
9799    SCRN_INFO_PTR(arg);
9800    SISPtr pSiS = SISPTR(pScrn);
9801
9802    SiS_SiSFB_Lock(pScrn, TRUE);
9803
9804    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
9805
9806    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
9807       outSISIDXREG(SISCR,0x32,pSiS->myCR32);
9808       outSISIDXREG(SISCR,0x36,pSiS->myCR36);
9809       outSISIDXREG(SISCR,0x37,pSiS->myCR37);
9810    }
9811
9812    if(!SISModeInit(pScrn, pScrn->currentMode)) {
9813       SISErrorLog(pScrn, "SiSEnterVT: SISModeInit() failed\n");
9814       return FALSE;
9815    }
9816
9817    SISAdjustFrame(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0));
9818
9819#ifdef SISDRI
9820    if(pSiS->directRenderingEnabled) {
9821       DRIUnlock(xf86ScrnToScreen(pScrn));
9822    }
9823#endif
9824
9825#ifdef SISDUALHEAD
9826    if((!pSiS->DualHeadMode) || (!pSiS->SecondHead))
9827#endif
9828       if(pSiS->ResetXv) {
9829          (pSiS->ResetXv)(pScrn);
9830       }
9831
9832    return TRUE;
9833}
9834
9835/*
9836 * This is called when VT switching away from the X server.  Its job is
9837 * to restore the previous (text) mode.
9838 * Mandatory!
9839 */
9840static void
9841SISLeaveVT(VT_FUNC_ARGS_DECL)
9842{
9843    SCRN_INFO_PTR(arg);
9844    SISPtr pSiS = SISPTR(pScrn);
9845#ifdef SISDRI
9846    ScreenPtr pScreen;
9847
9848    if(pSiS->directRenderingEnabled) {
9849       pScreen = xf86ScrnToScreen(pScrn);
9850       DRILock(pScreen, 0);
9851    }
9852#endif
9853
9854#ifdef SISDUALHEAD
9855    if(pSiS->DualHeadMode && pSiS->SecondHead) return;
9856#endif
9857
9858    if(pSiS->CursorInfoPtr) {
9859#ifdef SISDUALHEAD
9860       if(pSiS->DualHeadMode) {
9861          if(!pSiS->SecondHead) {
9862	     pSiS->ForceCursorOff = TRUE;
9863	     pSiS->CursorInfoPtr->HideCursor(pScrn);
9864	     SISWaitVBRetrace(pScrn);
9865	     pSiS->ForceCursorOff = FALSE;
9866	  }
9867       } else {
9868#endif
9869          pSiS->CursorInfoPtr->HideCursor(pScrn);
9870          SISWaitVBRetrace(pScrn);
9871#ifdef SISDUALHEAD
9872       }
9873#endif
9874    }
9875
9876    SISBridgeRestore(pScrn);
9877
9878    if(pSiS->UseVESA) {
9879
9880       /* This is a q&d work-around for a BIOS bug. In case we disabled CRT2,
9881    	* VBESaveRestore() does not restore CRT1. So we set any mode now,
9882	* because VBESetVBEMode correctly restores CRT1. Afterwards, we
9883	* can call VBESaveRestore to restore original mode.
9884	*/
9885       if((pSiS->VBFlags2 & VB2_VIDEOBRIDGE) && (!(pSiS->VBFlags & DISPTYPE_DISP2)))
9886	  VBESetVBEMode(pSiS->pVbe, (pSiS->SISVESAModeList->n) | 0xc000, NULL);
9887
9888       SISVESARestore(pScrn);
9889
9890    } else {
9891
9892       SISRestore(pScrn);
9893
9894    }
9895
9896    /* We use (otherwise unused) bit 7 to indicate that we are running
9897     * to keep sisfb to change the displaymode (this would result in
9898     * lethal display corruption upon quitting X or changing to a VT
9899     * until a reboot)
9900     */
9901    if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
9902       orSISIDXREG(SISCR,0x34,0x80);
9903    }
9904
9905    SISVGALock(pSiS);
9906
9907    SiS_SiSFB_Lock(pScrn, FALSE);
9908}
9909
9910
9911/*
9912 * This is called at the end of each server generation.  It restores the
9913 * original (text) mode.  It should really also unmap the video memory too.
9914 * Mandatory!
9915 */
9916static Bool
9917SISCloseScreen(CLOSE_SCREEN_ARGS_DECL)
9918{
9919    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
9920    SISPtr pSiS = SISPTR(pScrn);
9921#ifdef SISDUALHEAD
9922    SISEntPtr pSiSEnt = pSiS->entityPrivate;
9923#endif
9924
9925    if(pSiS->SiSCtrlExtEntry) {
9926       SiSCtrlExtUnregister(pSiS, pScrn->scrnIndex);
9927    }
9928
9929#ifdef SISDRI
9930    if(pSiS->directRenderingEnabled) {
9931       SISDRICloseScreen(pScreen);
9932       pSiS->directRenderingEnabled = FALSE;
9933    }
9934#endif
9935
9936    if(pScrn->vtSema) {
9937
9938        if(pSiS->CursorInfoPtr) {
9939#ifdef SISDUALHEAD
9940           if(pSiS->DualHeadMode) {
9941              if(!pSiS->SecondHead) {
9942	         pSiS->ForceCursorOff = TRUE;
9943	         pSiS->CursorInfoPtr->HideCursor(pScrn);
9944	         SISWaitVBRetrace(pScrn);
9945	         pSiS->ForceCursorOff = FALSE;
9946	      }
9947           } else {
9948#endif
9949             pSiS->CursorInfoPtr->HideCursor(pScrn);
9950             SISWaitVBRetrace(pScrn);
9951#ifdef SISDUALHEAD
9952           }
9953#endif
9954	}
9955
9956        SISBridgeRestore(pScrn);
9957
9958	if(pSiS->UseVESA) {
9959
9960	  /* This is a q&d work-around for a BIOS bug. In case we disabled CRT2,
9961    	   * VBESaveRestore() does not restore CRT1. So we set any mode now,
9962	   * because VBESetVBEMode correctly restores CRT1. Afterwards, we
9963	   * can call VBESaveRestore to restore original mode.
9964	   */
9965           if((pSiS->VBFlags2 & VB2_VIDEOBRIDGE) && (!(pSiS->VBFlags & DISPTYPE_DISP2)))
9966	      VBESetVBEMode(pSiS->pVbe, (pSiS->SISVESAModeList->n) | 0xc000, NULL);
9967
9968	   SISVESARestore(pScrn);
9969
9970	} else {
9971
9972	   SISRestore(pScrn);
9973
9974	}
9975
9976        SISVGALock(pSiS);
9977
9978    }
9979
9980    SiS_SiSFB_Lock(pScrn, FALSE);
9981
9982    /* We should restore the mode number in case vtsema = false as well,
9983     * but since we haven't register access then we can't do it. I think
9984     * I need to rework the save/restore stuff, like saving the video
9985     * status when returning to the X server and by that save me the
9986     * trouble if sisfb was started from a textmode VT while X was on.
9987     */
9988
9989    SISUnmapMem(pScrn);
9990#ifdef SIS_PC_PLATFORM
9991    SiSVGAUnmapMem(pScrn);
9992#endif
9993
9994#ifdef SISDUALHEAD
9995    if(pSiS->DualHeadMode) {
9996       pSiSEnt = pSiS->entityPrivate;
9997       pSiSEnt->refCount--;
9998    }
9999#endif
10000
10001    if(pSiS->pInt) {
10002       xf86FreeInt10(pSiS->pInt);
10003       pSiS->pInt = NULL;
10004    }
10005
10006#ifdef SIS_USE_XAA
10007    if(!pSiS->useEXA) {
10008       if(pSiS->AccelLinearScratch) {
10009          xf86FreeOffscreenLinear(pSiS->AccelLinearScratch);
10010          pSiS->AccelLinearScratch = NULL;
10011       }
10012       if(pSiS->AccelInfoPtr) {
10013          XAADestroyInfoRec(pSiS->AccelInfoPtr);
10014          pSiS->AccelInfoPtr = NULL;
10015       }
10016    }
10017#endif
10018
10019#ifdef SIS_USE_EXA
10020    if(pSiS->useEXA) {
10021       if(pSiS->EXADriverPtr) {
10022          exaDriverFini(pScreen);
10023          free(pSiS->EXADriverPtr);
10024          pSiS->EXADriverPtr = NULL;
10025          pSiS->exa_scratch = NULL;
10026       }
10027    }
10028#endif
10029
10030    if(pSiS->CursorInfoPtr) {
10031       xf86DestroyCursorInfoRec(pSiS->CursorInfoPtr);
10032       pSiS->CursorInfoPtr = NULL;
10033    }
10034
10035    if(pSiS->ShadowPtr) {
10036       free(pSiS->ShadowPtr);
10037       pSiS->ShadowPtr = NULL;
10038    }
10039
10040    if(pSiS->DGAModes) {
10041       free(pSiS->DGAModes);
10042       pSiS->DGAModes = NULL;
10043    }
10044
10045    if(pSiS->adaptor) {
10046       free(pSiS->adaptor);
10047       pSiS->adaptor = NULL;
10048       pSiS->ResetXv = pSiS->ResetXvGamma = pSiS->ResetXvDisplay = NULL;
10049    }
10050
10051    if(pSiS->blitadaptor) {
10052       free(pSiS->blitadaptor);
10053       pSiS->blitadaptor = NULL;
10054    }
10055
10056    if(pSiS->crt2gcolortable) {
10057       free(pSiS->crt2gcolortable);
10058       pSiS->crt2gcolortable = NULL;
10059    }
10060
10061    if(pSiS->crt2cindices) {
10062       free(pSiS->crt2cindices);
10063       pSiS->crt2cindices = NULL;
10064    }
10065
10066    pScrn->vtSema = FALSE;
10067
10068    /* Restore Blockhandler */
10069    pScreen->BlockHandler = pSiS->BlockHandler;
10070
10071    pScreen->CloseScreen = pSiS->CloseScreen;
10072
10073    return(*pScreen->CloseScreen)(CLOSE_SCREEN_ARGS);
10074}
10075
10076
10077/* Free up any per-generation data structures */
10078
10079/* Optional */
10080static void
10081SISFreeScreen(FREE_SCREEN_ARGS_DECL)
10082{
10083    SCRN_INFO_PTR(arg);
10084#ifdef SIS_NEED_MAP_IOP
10085    SISPtr pSiS = SISPTR(pScrn);
10086
10087    if(pSiS) {
10088#ifdef SISDUALHEAD
10089       SISEntPtr pSiSEnt = pSiS->entityPrivate;
10090       if(pSiSEnt) {
10091          pSiSEnt->forceUnmapIOPBase = TRUE;
10092       }
10093#endif
10094       SISUnmapIOPMem(pScrn);
10095    }
10096#endif
10097
10098    SISFreeRec(pScrn);
10099}
10100
10101
10102/* Checks if a mode is suitable for the selected chipset. */
10103
10104static ModeStatus
10105SISValidMode(SCRN_ARG_TYPE arg, DisplayModePtr mode, Bool verbose, int flags)
10106{
10107    SCRN_INFO_PTR(arg);
10108    SISPtr pSiS = SISPTR(pScrn);
10109
10110    if(pSiS->UseVESA) {
10111       if(SiSCalcVESAModeIndex(pScrn, mode))
10112	  return(MODE_OK);
10113       else
10114	  return(MODE_BAD);
10115    }
10116
10117    if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
10118#ifdef SISDUALHEAD
10119       if(pSiS->DualHeadMode) {
10120          if(pSiS->SecondHead) {
10121	     if(SiS_CheckModeCRT1(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
10122	        return(MODE_BAD);
10123	  } else {
10124	     if(SiS_CheckModeCRT2(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
10125	        return(MODE_BAD);
10126	  }
10127       } else
10128#endif
10129#ifdef SISMERGED
10130       if(pSiS->MergedFB) {
10131	  if(!mode->Private) {
10132	     if(!pSiS->CheckForCRT2) {
10133	        if(SiS_CheckModeCRT1(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
10134	           return(MODE_BAD);
10135	     } else {
10136	        if(SiS_CheckModeCRT2(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes2) < 0x14)
10137	           return(MODE_BAD);
10138	     }
10139	  } else {
10140	     if(SiS_CheckModeCRT1(pScrn, ((SiSMergedDisplayModePtr)mode->Private)->CRT1,
10141		                  pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
10142	        return(MODE_BAD);
10143
10144	     if(SiS_CheckModeCRT2(pScrn, ((SiSMergedDisplayModePtr)mode->Private)->CRT2,
10145		                  pSiS->VBFlags, pSiS->HaveCustomModes2) < 0x14)
10146	        return(MODE_BAD);
10147 	  }
10148       } else
10149#endif
10150       {
10151	  if(SiS_CheckModeCRT1(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
10152	     return(MODE_BAD);
10153
10154	  if(SiS_CheckModeCRT2(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
10155	     return(MODE_BAD);
10156       }
10157    }
10158
10159    return(MODE_OK);
10160}
10161
10162#ifdef DEBUG
10163static void
10164SiSDumpModeInfo(ScrnInfoPtr pScrn, DisplayModePtr mode)
10165{
10166    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Clock : %x\n", mode->Clock);
10167    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Display : %x\n", mode->CrtcHDisplay);
10168    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Blank Start : %x\n", mode->CrtcHBlankStart);
10169    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Sync Start : %x\n", mode->CrtcHSyncStart);
10170    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Sync End : %x\n", mode->CrtcHSyncEnd);
10171    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Blank End : %x\n", mode->CrtcHBlankEnd);
10172    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Total : %x\n", mode->CrtcHTotal);
10173    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Skew : %x\n", mode->CrtcHSkew);
10174    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz HAdjusted : %x\n", mode->CrtcHAdjusted);
10175    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Display : %x\n", mode->CrtcVDisplay);
10176    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Blank Start : %x\n", mode->CrtcVBlankStart);
10177    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Sync Start : %x\n", mode->CrtcVSyncStart);
10178    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Sync End : %x\n", mode->CrtcVSyncEnd);
10179    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Blank End : %x\n", mode->CrtcVBlankEnd);
10180    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Total : %x\n", mode->CrtcVTotal);
10181    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt VAdjusted : %x\n", mode->CrtcVAdjusted);
10182}
10183#endif
10184
10185static void
10186SISModifyModeInfo(DisplayModePtr mode)
10187{
10188    if(mode->CrtcHBlankStart == mode->CrtcHDisplay)
10189        mode->CrtcHBlankStart++;
10190    if(mode->CrtcHBlankEnd == mode->CrtcHTotal)
10191        mode->CrtcHBlankEnd--;
10192    if(mode->CrtcVBlankStart == mode->CrtcVDisplay)
10193        mode->CrtcVBlankStart++;
10194    if(mode->CrtcVBlankEnd == mode->CrtcVTotal)
10195        mode->CrtcVBlankEnd--;
10196}
10197
10198/* Enable the Turboqueue/Commandqueue (For 300 and 315/330/340 series only) */
10199static void
10200SiSEnableTurboQueue(ScrnInfoPtr pScrn)
10201{
10202    SISPtr pSiS = SISPTR(pScrn);
10203    UShort SR26, SR27;
10204    ULong  temp;
10205
10206    switch(pSiS->VGAEngine) {
10207	case SIS_300_VGA:
10208	   if((!pSiS->NoAccel) && (pSiS->TurboQueue)) {
10209		/* TQ size is always 512k */
10210		temp = (pScrn->videoRam/64) - 8;
10211		SR26 = temp & 0xFF;
10212		inSISIDXREG(SISSR, 0x27, SR27);
10213		SR27 &= 0xFC;
10214		SR27 |= (0xF0 | ((temp >> 8) & 3));
10215		outSISIDXREG(SISSR, 0x26, SR26);
10216		outSISIDXREG(SISSR, 0x27, SR27);
10217	   }
10218	   break;
10219
10220	case SIS_315_VGA:
10221	   if(!pSiS->NoAccel) {
10222	      /* On 315/330/340 series, there are three queue modes available
10223	       * which are chosen by setting bits 7:5 in SR26:
10224	       * 1. MMIO queue mode (bit 5, 0x20). The hardware will keep
10225	       *    track of the queue, the FIFO, command parsing and so
10226	       *    on. This is the one comparable to the 300 series.
10227	       * 2. VRAM queue mode (bit 6, 0x40). In this case, one will
10228	       *    have to do queue management himself.
10229	       * 3. AGP queue mode (bit 7, 0x80). Works as 2., but keeps the
10230	       *    queue in AGP memory space.
10231	       * We go VRAM or MMIO here.
10232	       * SR26 bit 4 is called "Bypass H/W queue".
10233	       * SR26 bit 1 is called "Enable Command Queue Auto Correction"
10234	       * SR26 bit 0 resets the queue
10235	       * Size of queue memory is encoded in bits 3:2 like this:
10236	       *    00  (0x00)  512K
10237	       *    01  (0x04)  1M
10238	       *    10  (0x08)  2M
10239	       *    11  (0x0C)  4M
10240	       * The queue location is to be written to 0x85C0.
10241	       */
10242#ifdef SISVRAMQ
10243	      /* We use VRAM Cmd Queue, not MMIO or AGP */
10244	      UChar tempCR55 = 0;
10245
10246	      /* Set Command Queue Threshold to max value 11111b (?) */
10247	      outSISIDXREG(SISSR, 0x27, 0x1F);
10248
10249	      /* Disable queue flipping */
10250	      inSISIDXREG(SISCR, 0x55, tempCR55);
10251	      andSISIDXREG(SISCR, 0x55, 0x33);
10252	      /* Synchronous reset for Command Queue */
10253	      outSISIDXREG(SISSR, 0x26, 0x01);
10254	      SIS_MMIO_OUT32(pSiS->IOBase, 0x85c4, 0);
10255	      /* Enable VRAM Command Queue mode */
10256	      if(pSiS->ChipType == XGI_20) {
10257		 /* On XGI_20, always 128K */
10258		 SR26 = 0x40 | 0x04 | 0x01;
10259	      } else {
10260	         switch(pSiS->cmdQueueSize) {
10261		    case 1*1024*1024: SR26 = (0x40 | 0x04 | 0x01); break;
10262		    case 2*1024*1024: SR26 = (0x40 | 0x08 | 0x01); break;
10263		    case 4*1024*1024: SR26 = (0x40 | 0x0C | 0x01); break;
10264		    default:
10265		                      pSiS->cmdQueueSize = 512 * 1024;
10266		    case    512*1024: SR26 = (0x40 | 0x00 | 0x01);
10267	         }
10268	      }
10269	      outSISIDXREG(SISSR, 0x26, SR26);
10270	      SR26 &= 0xfe;
10271	      outSISIDXREG(SISSR, 0x26, SR26);
10272	      *(pSiS->cmdQ_SharedWritePort) = (unsigned int)(SIS_MMIO_IN32(pSiS->IOBase, 0x85c8));
10273	      SIS_MMIO_OUT32(pSiS->IOBase, 0x85c4, (CARD32)(*(pSiS->cmdQ_SharedWritePort)));
10274	      SIS_MMIO_OUT32(pSiS->IOBase, 0x85C0, pSiS->cmdQueueOffset);
10275	      temp = (ULong)pSiS->RealFbBase;
10276#ifdef SISDUALHEAD
10277	      if(pSiS->DualHeadMode) {
10278	         SISEntPtr pSiSEnt = pSiS->entityPrivate;
10279	         temp = (ULong)pSiSEnt->RealFbBase;
10280	      }
10281#endif
10282	      temp += pSiS->cmdQueueOffset;
10283	      pSiS->cmdQueueBase = (unsigned int *)temp;
10284	      outSISIDXREG(SISCR, 0x55, tempCR55);
10285#ifdef TWDEBUG
10286	      xf86DrvMsg(0, 0, "CmdQueueOffs 0x%x, CmdQueueAdd %p, shwrp 0x%x, status %x, base %p\n",
10287		pSiS->cmdQueueOffset, pSiS->cmdQueueBase, *(pSiS->cmdQ_SharedWritePort),
10288		SIS_MMIO_IN32(pSiS->IOBase, 0x85cc), (ULong *)temp);
10289#endif
10290#else
10291	      /* For MMIO */
10292	      /* Syncronous reset for Command Queue */
10293	      orSISIDXREG(SISSR, 0x26, 0x01);
10294	      /* Set Command Queue Threshold to max value 11111b */
10295	      outSISIDXREG(SISSR, 0x27, 0x1F);
10296	      /* Do some magic (cp readport to writeport) */
10297	      temp = SIS_MMIO_IN32(pSiS->IOBase, 0x85C8);
10298	      SIS_MMIO_OUT32(pSiS->IOBase, 0x85C4, temp);
10299	      /* Enable MMIO Command Queue mode (0x20),
10300	       * Enable_command_queue_auto_correction (0x02)
10301	       *        (no idea, but sounds good, so use it)
10302	       * 512k (0x00) (does this apply to MMIO mode?) */
10303	      outSISIDXREG(SISSR, 0x26, 0x22);
10304	      /* Calc Command Queue position (Q is always 512k)*/
10305	      temp = (pScrn->videoRam - 512) * 1024;
10306	      /* Set Q position */
10307	      SIS_MMIO_OUT32(pSiS->IOBase, 0x85C0, temp);
10308#endif
10309	   }
10310	   break;
10311	default:
10312	   break;
10313    }
10314}
10315
10316#ifdef SISVRAMQ
10317static void
10318SiSRestoreQueueMode(SISPtr pSiS, SISRegPtr sisReg)
10319{
10320    UChar tempCR55=0;
10321
10322    if(pSiS->VGAEngine == SIS_315_VGA) {
10323       inSISIDXREG(SISCR,0x55,tempCR55);
10324       andSISIDXREG(SISCR,0x55,0x33);
10325       outSISIDXREG(SISSR,0x26,0x01);
10326       SIS_MMIO_OUT32(pSiS->IOBase, 0x85c4, 0);
10327       outSISIDXREG(SISSR,0x27,sisReg->sisRegs3C4[0x27]);
10328       outSISIDXREG(SISSR,0x26,sisReg->sisRegs3C4[0x26]);
10329       SIS_MMIO_OUT32(pSiS->IOBase, 0x85C0, sisReg->sisMMIO85C0);
10330       outSISIDXREG(SISCR,0x55,tempCR55);
10331    }
10332}
10333#endif
10334
10335/* Things to do before a ModeSwitch. We set up the
10336 * video bridge configuration and the TurboQueue.
10337 */
10338void SiSPreSetMode(ScrnInfoPtr pScrn, DisplayModePtr mode, int viewmode)
10339{
10340    SISPtr pSiS = SISPTR(pScrn);
10341    UChar  CR30, CR31, CR32, CR33;
10342    UChar  CR39 = 0, CR3B = 0;
10343    UChar  CR17, CR38 = 0;
10344    UChar  CR35 = 0, CR79 = 0;
10345    int    temp = 0, crt1rateindex = 0;
10346    ULong  vbflag = pSiS->VBFlags;
10347    Bool   hcm = pSiS->HaveCustomModes;
10348    DisplayModePtr mymode = mode;
10349
10350    pSiS->IsCustom = FALSE;
10351
10352    /* NEVER call this with viewmode = SIS_MODE_SIMU
10353     * if mode->type is not M_T_DEFAULT!
10354     */
10355
10356#ifdef SISMERGED
10357    if(pSiS->MergedFB) {
10358       switch(viewmode) {
10359       case SIS_MODE_CRT1:
10360	  mymode = ((SiSMergedDisplayModePtr)mode->Private)->CRT1;
10361	  break;
10362       case SIS_MODE_CRT2:
10363	  mymode = ((SiSMergedDisplayModePtr)mode->Private)->CRT2;
10364	  hcm = pSiS->HaveCustomModes2;
10365       }
10366    }
10367#endif
10368
10369    switch(viewmode) {
10370    case SIS_MODE_CRT1:
10371       if(SiS_CheckModeCRT1(pScrn, mymode, vbflag, hcm) == 0xfe) {
10372          pSiS->IsCustom = TRUE;
10373       }
10374       break;
10375    case SIS_MODE_CRT2:
10376       if(vbflag & CRT2_ENABLE) {
10377          if(SiS_CheckModeCRT2(pScrn, mymode, vbflag, hcm) == 0xfe) {
10378	     pSiS->IsCustom = TRUE;
10379          }
10380       } else {
10381          /* This can only happen in mirror mode */
10382          if(SiS_CheckModeCRT1(pScrn, mymode, vbflag, hcm) == 0xfe) {
10383             pSiS->IsCustom = TRUE;
10384          }
10385       }
10386    }
10387
10388#ifdef UNLOCK_ALWAYS
10389    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);    /* Unlock Registers */
10390#endif
10391
10392    inSISIDXREG(SISCR, 0x30, CR30);
10393    inSISIDXREG(SISCR, 0x31, CR31);
10394    CR32 = pSiS->newCR32;
10395    inSISIDXREG(SISCR, 0x33, CR33);
10396
10397    if(pSiS->NewCRLayout) {
10398
10399       inSISIDXREG(SISCR, 0x35, CR35);
10400       inSISIDXREG(SISCR, 0x38, CR38);
10401       inSISIDXREG(SISCR, 0x39, CR39);
10402
10403       xf86DrvMsgVerb(pScrn->scrnIndex, X_PROBED, SISVERBLEVEL,
10404	   "Before: CR30=0x%02x,CR31=0x%02x,CR32=0x%02x,CR33=0x%02x,CR35=0x%02x,CR38=0x%02x\n",
10405              CR30, CR31, CR32, CR33, CR35, CR38);
10406
10407       CR38 &= ~0x07;
10408
10409    } else {
10410
10411       if(pSiS->Chipset != PCI_CHIP_SIS300) {
10412          switch(pSiS->VGAEngine) {
10413             case SIS_300_VGA: temp = 0x35; break;
10414             case SIS_315_VGA: temp = 0x38; break;
10415          }
10416          if(temp) inSISIDXREG(SISCR, temp, CR38);
10417       }
10418       if(pSiS->VGAEngine == SIS_315_VGA) {
10419          inSISIDXREG(SISCR, 0x79, CR79);
10420          CR38 &= ~0x3b;   			/* Clear LCDA/DualEdge and YPbPr bits */
10421       }
10422       inSISIDXREG(SISCR, 0x3b, CR3B);
10423
10424       xf86DrvMsgVerb(pScrn->scrnIndex, X_PROBED, SISVERBLEVEL,
10425	   "Before: CR30=0x%02x, CR31=0x%02x, CR32=0x%02x, CR33=0x%02x, CR%02x=0x%02x\n",
10426              CR30, CR31, CR32, CR33, temp, CR38);
10427    }
10428
10429    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, SISVERBLEVEL, "VBFlags=0x%x\n", pSiS->VBFlags);
10430
10431    CR30 = 0x00;
10432    CR31 &= ~0x60;  /* Clear VB_Drivermode & VB_OutputDisable */
10433    CR31 |= 0x04;   /* Set VB_NotSimuMode (not for 30xB/1400x1050?) */
10434    CR35 = 0x00;
10435
10436    if(!pSiS->NewCRLayout) {
10437       if(!pSiS->AllowHotkey) {
10438          CR31 |= 0x80;   /* Disable hotkey-switch */
10439       }
10440       CR79 &= ~0x10;     /* Enable Backlight control on 315 series */
10441    }
10442
10443    SiS_SetEnableDstn(pSiS->SiS_Pr, FALSE);
10444    SiS_SetEnableFstn(pSiS->SiS_Pr, FALSE);
10445
10446    if((vbflag & CRT1_LCDA) && (viewmode == SIS_MODE_CRT1)) {
10447
10448       CR38 |= 0x02;
10449
10450    } else {
10451
10452       switch(vbflag & (CRT2_TV|CRT2_LCD|CRT2_VGA)) {
10453
10454       case CRT2_TV:
10455
10456          CR38 &= ~0xC0; 	/* Clear Pal M/N bits */
10457
10458          if((pSiS->VBFlags2 & VB2_CHRONTEL) && (vbflag & TV_CHSCART)) {		/* Chrontel */
10459	     CR30 |= 0x10;
10460	     CR38 |= 0x04;
10461	     CR38 &= ~0x08;
10462	     CR31 |= 0x01;
10463	  } else if((pSiS->VBFlags2 & VB2_CHRONTEL) && (vbflag & TV_CHYPBPR525I)) {	/* Chrontel */
10464	     CR38 |= 0x08;
10465	     CR38 &= ~0x04;
10466	     CR31 &= ~0x01;
10467          } else if(vbflag & TV_HIVISION) {	/* SiS bridge */
10468	     if(pSiS->NewCRLayout) {
10469	        CR38 |= 0x04;
10470	        CR35 |= 0x60;
10471	     } else {
10472	        CR30 |= 0x80;
10473		if(pSiS->VGAEngine == SIS_315_VGA) {
10474		   if(pSiS->VBFlags2 & VB2_SISYPBPRBRIDGE) {
10475		      CR38 |= (0x08 | 0x30);
10476		   }
10477		}
10478	     }
10479	     CR31 |= 0x01;
10480	     CR35 |= 0x01;
10481	  } else if(vbflag & TV_YPBPR) {					/* SiS bridge */
10482	     if(pSiS->NewCRLayout) {
10483		CR38 |= 0x04;
10484		CR31 &= ~0x01;
10485		CR35 &= ~0x01;
10486		if(vbflag & (TV_YPBPR525P | TV_YPBPR625P)) CR35 |= 0x20;
10487		else if(vbflag & TV_YPBPR750P)             CR35 |= 0x40;
10488		else if(vbflag & TV_YPBPR1080I)            CR35 |= 0x60;
10489
10490		if(vbflag & (TV_YPBPR625I | TV_YPBPR625P)) {
10491		   CR31 |= 0x01;
10492		   CR35 |= 0x01;
10493		}
10494
10495		CR39 &= ~0x03;
10496		if((vbflag & TV_YPBPRAR) == TV_YPBPR43LB)     CR39 |= 0x00;
10497		else if((vbflag & TV_YPBPRAR) == TV_YPBPR43)  CR39 |= 0x01;
10498		else if((vbflag & TV_YPBPRAR) == TV_YPBPR169) CR39 |= 0x02;
10499		else					      CR39 |= 0x03;
10500	     } else if(pSiS->SiS_SD_Flags & SiS_SD_SUPPORTYPBPR) {
10501		CR30 |= 0x80;
10502		CR38 |= 0x08;
10503		CR31 &= ~0x01;
10504		if(vbflag & (TV_YPBPR525P|TV_YPBPR625P)) CR38 |= 0x10;
10505		else if(vbflag & TV_YPBPR750P)  	 CR38 |= 0x20;
10506		else if(vbflag & TV_YPBPR1080I)		 CR38 |= 0x30;
10507
10508		if(vbflag & (TV_YPBPR625I | TV_YPBPR625P)) CR31 |= 0x01;
10509
10510		if(pSiS->SiS_SD_Flags & SiS_SD_SUPPORTYPBPRAR) {
10511		   CR3B &= ~0x03;
10512		   if((vbflag & TV_YPBPRAR) == TV_YPBPR43LB)     CR3B |= 0x00;
10513		   else if((vbflag & TV_YPBPRAR) == TV_YPBPR43)  CR3B |= 0x03;
10514		   else if((vbflag & TV_YPBPRAR) == TV_YPBPR169) CR3B |= 0x01;
10515		   else					         CR3B |= 0x03;
10516		}
10517	     }
10518          } else {								/* All */
10519	     if(vbflag & TV_SCART)  CR30 |= 0x10;
10520	     if(vbflag & TV_SVIDEO) CR30 |= 0x08;
10521	     if(vbflag & TV_AVIDEO) CR30 |= 0x04;
10522	     if(!(CR30 & 0x1C))	    CR30 |= 0x08;    /* default: SVIDEO */
10523
10524	     if(vbflag & TV_PAL) {
10525		CR31 |= 0x01;
10526		CR35 |= 0x01;
10527		if( (pSiS->VBFlags2 & VB2_SISBRIDGE) ||
10528		    ((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->ChrontelType == CHRONTEL_701x)) )  {
10529		   if(vbflag & TV_PALM) {
10530		      CR38 |= 0x40;
10531		      CR35 |= 0x04;
10532		   } else if(vbflag & TV_PALN) {
10533		      CR38 |= 0x80;
10534		      CR35 |= 0x08;
10535		   }
10536	        }
10537	     } else {
10538		CR31 &= ~0x01;
10539		CR35 &= ~0x01;
10540		if(vbflag & TV_NTSCJ) {
10541		   CR38 |= 0x40;  /* TW, not BIOS */
10542		   CR35 |= 0x02;
10543		}
10544	     }
10545	     if(vbflag & TV_SCART) {
10546		CR31 |= 0x01;
10547		CR35 |= 0x01;
10548	     }
10549	  }
10550
10551	  CR31 &= ~0x04;   /* Clear NotSimuMode */
10552	  pSiS->SiS_Pr->SiS_CHOverScan = pSiS->UseCHOverScan;
10553	  if((pSiS->OptTVSOver == 1) && (pSiS->ChrontelType == CHRONTEL_700x)) {
10554	     pSiS->SiS_Pr->SiS_CHSOverScan = TRUE;
10555	  } else {
10556	     pSiS->SiS_Pr->SiS_CHSOverScan = FALSE;
10557	  }
10558#ifdef SIS_CP
10559	  SIS_CP_DRIVER_CONFIG
10560#endif
10561	  break;
10562
10563       case CRT2_LCD:
10564	  CR30 |= 0x20;
10565	  SiS_SetEnableDstn(pSiS->SiS_Pr, pSiS->DSTN);
10566	  SiS_SetEnableFstn(pSiS->SiS_Pr, pSiS->FSTN);
10567	  break;
10568
10569       case CRT2_VGA:
10570	  CR30 |= 0x40;
10571	  break;
10572
10573       default:
10574	  CR30 |= 0x00;
10575	  CR31 |= 0x20;    /* VB_OUTPUT_DISABLE */
10576	  if(pSiS->UseVESA) {
10577	     crt1rateindex = SISSearchCRT1Rate(pScrn, mymode);
10578	  }
10579       }
10580
10581    }
10582
10583    if(vbflag & CRT1_LCDA) {
10584       switch(viewmode) {
10585       case SIS_MODE_CRT1:
10586	  CR38 |= 0x01;
10587	  break;
10588       case SIS_MODE_CRT2:
10589	  if(vbflag & (CRT2_TV|CRT2_VGA)) {
10590	     CR30 |= 0x02;
10591	     CR38 |= 0x01;
10592	  } else {
10593	     CR38 |= 0x03;
10594	  }
10595	  break;
10596       case SIS_MODE_SIMU:
10597       default:
10598	  if(vbflag & (CRT2_TV|CRT2_LCD|CRT2_VGA)) {
10599	     CR30 |= 0x01;
10600	  }
10601	  break;
10602       }
10603    } else {
10604       if(vbflag & (CRT2_TV|CRT2_LCD|CRT2_VGA)) {
10605          CR30 |= 0x01;
10606       }
10607    }
10608
10609    if(pSiS->UseVESA) {
10610       CR31 &= ~0x40;   /* Clear Drivermode */
10611       CR31 |= 0x06;    /* Set SlaveMode, Enable SimuMode in Slavemode */
10612#ifdef TWDEBUG
10613       CR31 |= 0x40;    /* DEBUG (for non-slave mode VESA) */
10614       crt1rateindex = SISSearchCRT1Rate(pScrn, mymode);
10615#endif
10616    } else {
10617       CR31 |=  0x40;  /* Set Drivermode */
10618       CR31 &=  ~0x06; /* Disable SlaveMode, disable SimuMode in SlaveMode */
10619       if(!pSiS->IsCustom) {
10620          crt1rateindex = SISSearchCRT1Rate(pScrn, mymode);
10621       }
10622    }
10623
10624    switch(viewmode) {
10625	case SIS_MODE_SIMU:
10626	   CR33 = 0;
10627	   if(!(vbflag & CRT1_LCDA)) {
10628	      CR33 |= (crt1rateindex & 0x0f);
10629	   }
10630	   if(vbflag & CRT2_VGA) {
10631	      CR33 |= ((crt1rateindex & 0x0f) << 4);
10632	   }
10633	   break;
10634	case SIS_MODE_CRT1:
10635	   CR33 &= 0xf0;
10636	   if(!(vbflag & CRT1_LCDA)) {
10637	      CR33 |= (crt1rateindex & 0x0f);
10638	   }
10639	   break;
10640	case SIS_MODE_CRT2:
10641	   CR33 &= 0x0f;
10642	   if(vbflag & CRT2_VGA) {
10643	      CR33 |= ((crt1rateindex & 0x0f) << 4);
10644	   }
10645	   break;
10646     }
10647
10648     if((!pSiS->UseVESA) && (vbflag & CRT2_ENABLE)) {
10649	if(pSiS->CRT1off) CR33 &= 0xf0;
10650     }
10651
10652     if(pSiS->NewCRLayout) {
10653
10654	CR31 &= 0xfe;   /* Clear PAL flag (now in CR35) */
10655	CR38 &= 0x07;   /* Use only LCDA and HiVision/YPbPr bits */
10656	outSISIDXREG(SISCR, 0x30, CR30);
10657	outSISIDXREG(SISCR, 0x31, CR31);
10658	outSISIDXREG(SISCR, 0x33, CR33);
10659	outSISIDXREG(SISCR, 0x35, CR35);
10660	setSISIDXREG(SISCR, 0x38, 0xf8, CR38);
10661	outSISIDXREG(SISCR, 0x39, CR39);
10662
10663	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, SISVERBLEVEL,
10664		"After:  CR30=0x%02x,CR31=0x%02x,CR33=0x%02x,CR35=0x%02x,CR38=%02x\n",
10665		    CR30, CR31, CR33, CR35, CR38);
10666
10667     } else {
10668
10669	outSISIDXREG(SISCR, 0x30, CR30);
10670	outSISIDXREG(SISCR, 0x31, CR31);
10671	outSISIDXREG(SISCR, 0x33, CR33);
10672	if(temp) {
10673	   outSISIDXREG(SISCR, temp, CR38);
10674	}
10675	if(pSiS->VGAEngine == SIS_315_VGA) {
10676	   outSISIDXREG(SISCR, 0x3b, CR3B);
10677	   outSISIDXREG(SISCR, 0x79, CR79);
10678	}
10679
10680	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, SISVERBLEVEL,
10681		"After:  CR30=0x%02x,CR31=0x%02x,CR33=0x%02x,CR%02x=%02x\n",
10682		    CR30, CR31, CR33, temp, CR38);
10683     }
10684
10685     pSiS->SiS_Pr->SiS_UseOEM = pSiS->OptUseOEM;
10686
10687     /* Enable TurboQueue */
10688#ifdef SISVRAMQ
10689     if(pSiS->VGAEngine != SIS_315_VGA)
10690#endif
10691	SiSEnableTurboQueue(pScrn);
10692
10693     if((!pSiS->UseVESA) && (pSiS->VBFlags & CRT2_ENABLE)) {
10694	/* Switch on CRT1 for modes that require the bridge in SlaveMode */
10695	andSISIDXREG(SISSR,0x1f,0x3f);
10696	inSISIDXREG(SISCR, 0x17, CR17);
10697	if(!(CR17 & 0x80)) {
10698	   orSISIDXREG(SISCR, 0x17, 0x80);
10699	   outSISIDXREG(SISSR, 0x00, 0x01);
10700	   usleep(10000);
10701	   outSISIDXREG(SISSR, 0x00, 0x03);
10702	}
10703     }
10704}
10705
10706/* Functions for adjusting various TV settings */
10707
10708/* These are used by the PostSetMode() functions as well as
10709 * the display properties tool SiSCtrl.
10710 *
10711 * There is each a Set and a Get routine. The Set functions
10712 * take a value of the same range as the corresponding option.
10713 * The Get routines return a value of the same range (although
10714 * not necessarily the same value as previously set because
10715 * of the lower resolution of the respective setting compared
10716 * to the valid range).
10717 * The Get routines return -2 on error (eg. hardware does not
10718 * support this setting).
10719 * Note: The x and y positioning routines accept a position
10720 * RELATIVE to the default position. All other routines
10721 * take ABSOLUTE values.
10722 *
10723 * The Set functions will store the property regardless if TV is
10724 * currently used or not and if the hardware supports the property
10725 * or not. The Get routines will return this stored
10726 * value if TV is not currently used (because the register does
10727 * not contain the correct value then) or if the hardware supports
10728 * the respective property. This should make it easier for the
10729 * display property tool because it does not have to know the
10730 * hardware features.
10731 *
10732 * All the routines are dual head aware. It does not matter
10733 * if the function is called from the CRT1 or CRT2 session.
10734 * The values will be in pSiSEnt anyway, and read from there
10735 * if we're running dual head.
10736 */
10737
10738void SiS_SetCHTVlumabandwidthcvbs(ScrnInfoPtr pScrn, int val)
10739{
10740   SISPtr pSiS = SISPTR(pScrn);
10741#ifdef SISDUALHEAD
10742   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10743#endif
10744
10745   pSiS->chtvlumabandwidthcvbs = val;
10746#ifdef SISDUALHEAD
10747   if(pSiSEnt) pSiSEnt->chtvlumabandwidthcvbs = val;
10748#endif
10749
10750   if(!(pSiS->VBFlags & CRT2_TV)) return;
10751   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
10752
10753#ifdef UNLOCK_ALWAYS
10754   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10755#endif
10756
10757   switch(pSiS->ChrontelType) {
10758       case CHRONTEL_700x:
10759           val /= 8;
10760           if((val == 0) || (val == 1)) {
10761	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, val, 0xFE);
10762           }
10763	   break;
10764       case CHRONTEL_701x:
10765           val /= 4;
10766	   if((val >= 0) && (val <= 3)) {
10767	       SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x02, val, 0xFC);
10768	   }
10769           break;
10770   }
10771}
10772
10773int SiS_GetCHTVlumabandwidthcvbs(ScrnInfoPtr pScrn)
10774{
10775   SISPtr pSiS = SISPTR(pScrn);
10776#ifdef SISDUALHEAD
10777   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10778#endif
10779
10780   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
10781#ifdef SISDUALHEAD
10782      if(pSiSEnt && pSiS->DualHeadMode)
10783           return (int)pSiSEnt->chtvlumabandwidthcvbs;
10784      else
10785#endif
10786           return (int)pSiS->chtvlumabandwidthcvbs;
10787   } else {
10788#ifdef UNLOCK_ALWAYS
10789      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10790#endif
10791      switch(pSiS->ChrontelType) {
10792      case CHRONTEL_700x:
10793           return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x03) & 0x01) * 8);
10794      case CHRONTEL_701x:
10795	   return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x02) & 0x03) * 4);
10796      default:
10797           return (int)pSiS->chtvlumabandwidthcvbs;
10798      }
10799   }
10800}
10801
10802void SiS_SetCHTVlumabandwidthsvideo(ScrnInfoPtr pScrn, int val)
10803{
10804   SISPtr pSiS = SISPTR(pScrn);
10805#ifdef SISDUALHEAD
10806   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10807#endif
10808
10809   pSiS->chtvlumabandwidthsvideo = val;
10810#ifdef SISDUALHEAD
10811   if(pSiSEnt) pSiSEnt->chtvlumabandwidthsvideo = val;
10812#endif
10813
10814   if(!(pSiS->VBFlags & CRT2_TV)) return;
10815   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
10816
10817#ifdef UNLOCK_ALWAYS
10818   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10819#endif
10820
10821   switch(pSiS->ChrontelType) {
10822       case CHRONTEL_700x:
10823           val /= 6;
10824           if((val >= 0) && (val <= 2)) {
10825	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, (val << 1), 0xF9);
10826           }
10827	   break;
10828       case CHRONTEL_701x:
10829           val /= 4;
10830	   if((val >= 0) && (val <= 3)) {
10831	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x02, (val << 2), 0xF3);
10832	   }
10833           break;
10834   }
10835}
10836
10837int SiS_GetCHTVlumabandwidthsvideo(ScrnInfoPtr pScrn)
10838{
10839   SISPtr pSiS = SISPTR(pScrn);
10840#ifdef SISDUALHEAD
10841   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10842#endif
10843
10844   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
10845#ifdef SISDUALHEAD
10846      if(pSiSEnt && pSiS->DualHeadMode)
10847           return (int)pSiSEnt->chtvlumabandwidthsvideo;
10848      else
10849#endif
10850           return (int)pSiS->chtvlumabandwidthsvideo;
10851   } else {
10852#ifdef UNLOCK_ALWAYS
10853      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10854#endif
10855      switch(pSiS->ChrontelType) {
10856      case CHRONTEL_700x:
10857           return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x03) & 0x06) >> 1) * 6);
10858      case CHRONTEL_701x:
10859	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x02) & 0x0c) >> 2) * 4);
10860      default:
10861           return (int)pSiS->chtvlumabandwidthsvideo;
10862      }
10863   }
10864}
10865
10866void SiS_SetCHTVlumaflickerfilter(ScrnInfoPtr pScrn, int val)
10867{
10868   SISPtr pSiS = SISPTR(pScrn);
10869#ifdef SISDUALHEAD
10870   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10871#endif
10872
10873   pSiS->chtvlumaflickerfilter = val;
10874#ifdef SISDUALHEAD
10875   if(pSiSEnt) pSiSEnt->chtvlumaflickerfilter = val;
10876#endif
10877
10878   if(!(pSiS->VBFlags & CRT2_TV)) return;
10879   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
10880
10881#ifdef UNLOCK_ALWAYS
10882   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10883#endif
10884
10885   switch(pSiS->ChrontelType) {
10886       case CHRONTEL_700x:
10887           val /= 6;
10888           if((val >= 0) && (val <= 2)) {
10889	      UShort reg = 0;
10890	      reg = SiS_GetCH70xx(pSiS->SiS_Pr, 0x01);
10891	      reg = (reg & 0xf0) | ((reg & 0x0c) >> 2) | (val << 2);
10892              SiS_SetCH70xx(pSiS->SiS_Pr, 0x01, reg);
10893           }
10894	   break;
10895       case CHRONTEL_701x:
10896           val /= 4;
10897	   if((val >= 0) && (val <= 3)) {
10898	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x01, (val << 2), 0xF3);
10899	   }
10900           break;
10901   }
10902}
10903
10904int SiS_GetCHTVlumaflickerfilter(ScrnInfoPtr pScrn)
10905{
10906   SISPtr pSiS = SISPTR(pScrn);
10907#ifdef SISDUALHEAD
10908   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10909#endif
10910
10911   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
10912#ifdef SISDUALHEAD
10913      if(pSiSEnt && pSiS->DualHeadMode)
10914          return (int)pSiSEnt->chtvlumaflickerfilter;
10915      else
10916#endif
10917          return (int)pSiS->chtvlumaflickerfilter;
10918   } else {
10919#ifdef UNLOCK_ALWAYS
10920      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10921#endif
10922      switch(pSiS->ChrontelType) {
10923      case CHRONTEL_700x:
10924           return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x01) & 0x03) * 6);
10925      case CHRONTEL_701x:
10926	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x01) & 0x0c) >> 2) * 4);
10927      default:
10928           return (int)pSiS->chtvlumaflickerfilter;
10929      }
10930   }
10931}
10932
10933void SiS_SetCHTVchromabandwidth(ScrnInfoPtr pScrn, int val)
10934{
10935   SISPtr pSiS = SISPTR(pScrn);
10936#ifdef SISDUALHEAD
10937   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10938#endif
10939
10940   pSiS->chtvchromabandwidth = val;
10941#ifdef SISDUALHEAD
10942   if(pSiSEnt) pSiSEnt->chtvchromabandwidth = val;
10943#endif
10944
10945   if(!(pSiS->VBFlags & CRT2_TV)) return;
10946   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
10947
10948#ifdef UNLOCK_ALWAYS
10949   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10950#endif
10951
10952   switch(pSiS->ChrontelType) {
10953       case CHRONTEL_700x:
10954           val /= 4;
10955           if((val >= 0) && (val <= 3)) {
10956              SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, (val << 4), 0xCF);
10957           }
10958	   break;
10959       case CHRONTEL_701x:
10960           val /= 8;
10961	   if((val >= 0) && (val <= 1)) {
10962	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x02, (val << 4), 0xEF);
10963	   }
10964           break;
10965   }
10966}
10967
10968int SiS_GetCHTVchromabandwidth(ScrnInfoPtr pScrn)
10969{
10970   SISPtr pSiS = SISPTR(pScrn);
10971#ifdef SISDUALHEAD
10972   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10973#endif
10974
10975   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
10976#ifdef SISDUALHEAD
10977      if(pSiSEnt && pSiS->DualHeadMode)
10978           return (int)pSiSEnt->chtvchromabandwidth;
10979      else
10980#endif
10981           return (int)pSiS->chtvchromabandwidth;
10982   } else {
10983#ifdef UNLOCK_ALWAYS
10984      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10985#endif
10986      switch(pSiS->ChrontelType) {
10987      case CHRONTEL_700x:
10988           return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x03) & 0x30) >> 4) * 4);
10989      case CHRONTEL_701x:
10990	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x02) & 0x10) >> 4) * 8);
10991      default:
10992           return (int)pSiS->chtvchromabandwidth;
10993      }
10994   }
10995}
10996
10997void SiS_SetCHTVchromaflickerfilter(ScrnInfoPtr pScrn, int val)
10998{
10999   SISPtr pSiS = SISPTR(pScrn);
11000#ifdef SISDUALHEAD
11001   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11002#endif
11003
11004   pSiS->chtvchromaflickerfilter = val;
11005#ifdef SISDUALHEAD
11006   if(pSiSEnt) pSiSEnt->chtvchromaflickerfilter = val;
11007#endif
11008
11009   if(!(pSiS->VBFlags & CRT2_TV)) return;
11010   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
11011
11012#ifdef UNLOCK_ALWAYS
11013   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11014#endif
11015
11016   switch(pSiS->ChrontelType) {
11017       case CHRONTEL_700x:
11018           val /= 6;
11019           if((val >= 0) && (val <= 2)) {
11020	      UShort reg = 0;
11021	      reg = SiS_GetCH70xx(pSiS->SiS_Pr, 0x01);
11022	      reg = (reg & 0xc0) | ((reg & 0x0c) >> 2) | ((reg & 0x03) << 2) | (val << 4);
11023              SiS_SetCH70xx(pSiS->SiS_Pr, 0x01, reg);
11024           }
11025	   break;
11026       case CHRONTEL_701x:
11027           val /= 4;
11028	   if((val >= 0) && (val <= 3)) {
11029	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x01, (val << 4), 0xCF);
11030	   }
11031           break;
11032   }
11033}
11034
11035int SiS_GetCHTVchromaflickerfilter(ScrnInfoPtr pScrn)
11036{
11037   SISPtr pSiS = SISPTR(pScrn);
11038#ifdef SISDUALHEAD
11039   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11040#endif
11041
11042   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
11043#ifdef SISDUALHEAD
11044      if(pSiSEnt && pSiS->DualHeadMode)
11045           return (int)pSiSEnt->chtvchromaflickerfilter;
11046      else
11047#endif
11048           return (int)pSiS->chtvchromaflickerfilter;
11049   } else {
11050#ifdef UNLOCK_ALWAYS
11051      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11052#endif
11053      switch(pSiS->ChrontelType) {
11054      case CHRONTEL_700x:
11055           return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x01) & 0x30) >> 4) * 6);
11056      case CHRONTEL_701x:
11057	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x01) & 0x30) >> 4) * 4);
11058      default:
11059           return (int)pSiS->chtvchromaflickerfilter;
11060      }
11061   }
11062}
11063
11064void SiS_SetCHTVcvbscolor(ScrnInfoPtr pScrn, int val)
11065{
11066   SISPtr pSiS = SISPTR(pScrn);
11067#ifdef SISDUALHEAD
11068   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11069#endif
11070
11071   pSiS->chtvcvbscolor = val ? 1 : 0;
11072#ifdef SISDUALHEAD
11073   if(pSiSEnt) pSiSEnt->chtvcvbscolor = pSiS->chtvcvbscolor;
11074#endif
11075
11076   if(!(pSiS->VBFlags & CRT2_TV)) return;
11077   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
11078
11079#ifdef UNLOCK_ALWAYS
11080   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11081#endif
11082
11083   switch(pSiS->ChrontelType) {
11084       case CHRONTEL_700x:
11085           if(!val)  SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, 0x40, 0x00);
11086           else      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, 0x00, ~0x40);
11087	   break;
11088       case CHRONTEL_701x:
11089           if(!val)  SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x02, 0x00, ~0x20);
11090	   else      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x02, 0x20, 0x00);
11091           break;
11092   }
11093}
11094
11095int SiS_GetCHTVcvbscolor(ScrnInfoPtr pScrn)
11096{
11097   SISPtr pSiS = SISPTR(pScrn);
11098#ifdef SISDUALHEAD
11099   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11100#endif
11101
11102   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
11103#ifdef SISDUALHEAD
11104      if(pSiSEnt && pSiS->DualHeadMode)
11105           return (int)pSiSEnt->chtvcvbscolor;
11106      else
11107#endif
11108           return (int)pSiS->chtvcvbscolor;
11109   } else {
11110#ifdef UNLOCK_ALWAYS
11111      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11112#endif
11113      switch(pSiS->ChrontelType) {
11114      case CHRONTEL_700x:
11115           return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x03) & 0x40) >> 6) ^ 0x01);
11116      case CHRONTEL_701x:
11117	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x02) & 0x20) >> 5) ^ 0x01);
11118      default:
11119           return (int)pSiS->chtvcvbscolor;
11120      }
11121   }
11122}
11123
11124void SiS_SetCHTVtextenhance(ScrnInfoPtr pScrn, int val)
11125{
11126   SISPtr pSiS = SISPTR(pScrn);
11127#ifdef SISDUALHEAD
11128   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11129#endif
11130
11131   pSiS->chtvtextenhance = val;
11132#ifdef SISDUALHEAD
11133   if(pSiSEnt) pSiSEnt->chtvtextenhance = val;
11134#endif
11135
11136   if(!(pSiS->VBFlags & CRT2_TV)) return;
11137   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
11138
11139#ifdef UNLOCK_ALWAYS
11140   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11141#endif
11142
11143   switch(pSiS->ChrontelType) {
11144       case CHRONTEL_700x:
11145           val /= 6;
11146           if((val >= 0) && (val <= 2)) {
11147	      UShort reg = 0;
11148	      reg = SiS_GetCH70xx(pSiS->SiS_Pr, 0x01);
11149	      reg = (reg & 0xf0) | ((reg & 0x03) << 2) | val;
11150              SiS_SetCH70xx(pSiS->SiS_Pr, 0x01, reg);
11151           }
11152	   break;
11153       case CHRONTEL_701x:
11154           val /= 2;
11155	   if((val >= 0) && (val <= 7)) {
11156	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, val, 0xF8);
11157	   }
11158           break;
11159   }
11160}
11161
11162int SiS_GetCHTVtextenhance(ScrnInfoPtr pScrn)
11163{
11164   SISPtr pSiS = SISPTR(pScrn);
11165#ifdef SISDUALHEAD
11166   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11167#endif
11168
11169   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
11170#ifdef SISDUALHEAD
11171      if(pSiSEnt && pSiS->DualHeadMode)
11172           return (int)pSiSEnt->chtvtextenhance;
11173      else
11174#endif
11175           return (int)pSiS->chtvtextenhance;
11176   } else {
11177#ifdef UNLOCK_ALWAYS
11178      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11179#endif
11180      switch(pSiS->ChrontelType) {
11181      case CHRONTEL_700x:
11182	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x01) & 0x0c) >> 2) * 6);
11183      case CHRONTEL_701x:
11184	   return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x03) & 0x07) * 2);
11185      default:
11186           return (int)pSiS->chtvtextenhance;
11187      }
11188   }
11189}
11190
11191void SiS_SetCHTVcontrast(ScrnInfoPtr pScrn, int val)
11192{
11193   SISPtr pSiS = SISPTR(pScrn);
11194#ifdef SISDUALHEAD
11195   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11196#endif
11197
11198   pSiS->chtvcontrast = val;
11199#ifdef SISDUALHEAD
11200   if(pSiSEnt) pSiSEnt->chtvcontrast = val;
11201#endif
11202
11203   if(!(pSiS->VBFlags & CRT2_TV)) return;
11204   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
11205
11206#ifdef UNLOCK_ALWAYS
11207   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11208#endif
11209
11210   val /= 2;
11211   if((val >= 0) && (val <= 7)) {
11212       switch(pSiS->ChrontelType) {
11213       case CHRONTEL_700x:
11214              SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x11, val, 0xF8);
11215	      break;
11216       case CHRONTEL_701x:
11217	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x08, val, 0xF8);
11218              break;
11219       }
11220       SiS_DDC2Delay(pSiS->SiS_Pr, 1000);
11221   }
11222}
11223
11224int SiS_GetCHTVcontrast(ScrnInfoPtr pScrn)
11225{
11226   SISPtr pSiS = SISPTR(pScrn);
11227#ifdef SISDUALHEAD
11228   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11229#endif
11230
11231   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
11232#ifdef SISDUALHEAD
11233      if(pSiSEnt && pSiS->DualHeadMode)
11234           return (int)pSiSEnt->chtvcontrast;
11235      else
11236#endif
11237           return (int)pSiS->chtvcontrast;
11238   } else {
11239#ifdef UNLOCK_ALWAYS
11240      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11241#endif
11242      switch(pSiS->ChrontelType) {
11243      case CHRONTEL_700x:
11244           return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x11) & 0x07) * 2);
11245      case CHRONTEL_701x:
11246	   return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x08) & 0x07) * 2);
11247      default:
11248           return (int)pSiS->chtvcontrast;
11249      }
11250   }
11251}
11252
11253void SiS_SetSISTVedgeenhance(ScrnInfoPtr pScrn, int val)
11254{
11255   SISPtr pSiS = SISPTR(pScrn);
11256#ifdef SISDUALHEAD
11257   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11258#endif
11259
11260   pSiS->sistvedgeenhance = val;
11261#ifdef SISDUALHEAD
11262   if(pSiSEnt) pSiSEnt->sistvedgeenhance = val;
11263#endif
11264
11265   if(!(pSiS->VBFlags2 & VB2_301))  return;
11266   if(!(pSiS->VBFlags & CRT2_TV))   return;
11267
11268#ifdef UNLOCK_ALWAYS
11269   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11270#endif
11271
11272   val /= 2;
11273   if((val >= 0) && (val <= 7)) {
11274      setSISIDXREG(SISPART2,0x3A, 0x1F, (val << 5));
11275   }
11276}
11277
11278int SiS_GetSISTVedgeenhance(ScrnInfoPtr pScrn)
11279{
11280   SISPtr pSiS = SISPTR(pScrn);
11281   int result = pSiS->sistvedgeenhance;
11282   UChar temp;
11283#ifdef SISDUALHEAD
11284   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11285
11286   if(pSiSEnt && pSiS->DualHeadMode) result = pSiSEnt->sistvedgeenhance;
11287#endif
11288
11289   if(!(pSiS->VBFlags2 & VB2_301))  return result;
11290   if(!(pSiS->VBFlags & CRT2_TV))   return result;
11291
11292#ifdef UNLOCK_ALWAYS
11293   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11294#endif
11295   inSISIDXREG(SISPART2, 0x3a, temp);
11296   return(int)(((temp & 0xe0) >> 5) * 2);
11297}
11298
11299void SiS_SetSISTVantiflicker(ScrnInfoPtr pScrn, int val)
11300{
11301   SISPtr pSiS = SISPTR(pScrn);
11302#ifdef SISDUALHEAD
11303   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11304#endif
11305
11306   pSiS->sistvantiflicker = val;
11307#ifdef SISDUALHEAD
11308   if(pSiSEnt) pSiSEnt->sistvantiflicker = val;
11309#endif
11310
11311   if(!(pSiS->VBFlags & CRT2_TV))      return;
11312   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE)) return;
11313   if(pSiS->VBFlags & TV_HIVISION)     return;
11314   if((pSiS->VBFlags & TV_YPBPR) &&
11315      (pSiS->VBFlags & (TV_YPBPR525P | TV_YPBPR625P | TV_YPBPR750P | TV_YPBPR1080I))) return;
11316
11317#ifdef UNLOCK_ALWAYS
11318   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11319#endif
11320
11321   /* Valid values: 0=off, 1=low, 2=med, 3=high, 4=adaptive */
11322   if((val >= 0) && (val <= 4)) {
11323      setSISIDXREG(SISPART2,0x0A,0x8F, (val << 4));
11324   }
11325}
11326
11327int SiS_GetSISTVantiflicker(ScrnInfoPtr pScrn)
11328{
11329   SISPtr pSiS = SISPTR(pScrn);
11330   int result = pSiS->sistvantiflicker;
11331   UChar temp;
11332#ifdef SISDUALHEAD
11333   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11334
11335   if(pSiSEnt && pSiS->DualHeadMode) result = pSiSEnt->sistvantiflicker;
11336#endif
11337
11338   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE)) return result;
11339   if(!(pSiS->VBFlags & CRT2_TV))        return result;
11340   if(pSiS->VBFlags & TV_HIVISION)       return result;
11341   if((pSiS->VBFlags & TV_YPBPR) &&
11342      (pSiS->VBFlags & (TV_YPBPR525P | TV_YPBPR625P | TV_YPBPR750P | TV_YPBPR1080I))) return result;
11343
11344#ifdef UNLOCK_ALWAYS
11345   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11346#endif
11347   inSISIDXREG(SISPART2, 0x0a, temp);
11348   return(int)((temp & 0x70) >> 4);
11349}
11350
11351void SiS_SetSISTVsaturation(ScrnInfoPtr pScrn, int val)
11352{
11353   SISPtr pSiS = SISPTR(pScrn);
11354#ifdef SISDUALHEAD
11355   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11356#endif
11357
11358   pSiS->sistvsaturation = val;
11359#ifdef SISDUALHEAD
11360   if(pSiSEnt) pSiSEnt->sistvsaturation = val;
11361#endif
11362
11363   if(!(pSiS->VBFlags & CRT2_TV)) return;
11364   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE)) return;
11365   if(pSiS->VBFlags2 & VB2_301) return;
11366
11367#ifdef UNLOCK_ALWAYS
11368   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11369#endif
11370
11371   val /= 2;
11372   if((val >= 0) && (val <= 7)) {
11373      setSISIDXREG(SISPART4,0x21,0xF8, val);
11374   }
11375}
11376
11377int SiS_GetSISTVsaturation(ScrnInfoPtr pScrn)
11378{
11379   SISPtr pSiS = SISPTR(pScrn);
11380   int result = pSiS->sistvsaturation;
11381   UChar temp;
11382#ifdef SISDUALHEAD
11383   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11384
11385   if(pSiSEnt && pSiS->DualHeadMode)  result = pSiSEnt->sistvsaturation;
11386#endif
11387
11388   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE)) return result;
11389   if(pSiS->VBFlags2 & VB2_301)          return result;
11390   if(!(pSiS->VBFlags & CRT2_TV))        return result;
11391
11392#ifdef UNLOCK_ALWAYS
11393   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11394#endif
11395   inSISIDXREG(SISPART4, 0x21, temp);
11396   return(int)((temp & 0x07) * 2);
11397}
11398
11399void SiS_SetSISTVcolcalib(ScrnInfoPtr pScrn, int val, Bool coarse)
11400{
11401   SISPtr pSiS = SISPTR(pScrn);
11402#ifdef SISDUALHEAD
11403   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11404#endif
11405   int ccoarse, cfine, cbase = pSiS->sistvccbase;
11406   /* UChar temp; */
11407
11408#ifdef SISDUALHEAD
11409   if(pSiSEnt && pSiS->DualHeadMode) cbase = pSiSEnt->sistvccbase;
11410#endif
11411
11412   if(coarse) {
11413      pSiS->sistvcolcalibc = ccoarse = val;
11414      cfine = pSiS->sistvcolcalibf;
11415#ifdef SISDUALHEAD
11416      if(pSiSEnt) {
11417         pSiSEnt->sistvcolcalibc = val;
11418	 if(pSiS->DualHeadMode) cfine = pSiSEnt->sistvcolcalibf;
11419      }
11420#endif
11421   } else {
11422      pSiS->sistvcolcalibf = cfine = val;
11423      ccoarse = pSiS->sistvcolcalibc;
11424#ifdef SISDUALHEAD
11425      if(pSiSEnt) {
11426         pSiSEnt->sistvcolcalibf = val;
11427         if(pSiS->DualHeadMode) ccoarse = pSiSEnt->sistvcolcalibc;
11428      }
11429#endif
11430   }
11431
11432   if(!(pSiS->VBFlags & CRT2_TV))               return;
11433   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE))        return;
11434   if(pSiS->VBFlags & (TV_HIVISION | TV_YPBPR)) return;
11435
11436#ifdef UNLOCK_ALWAYS
11437   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11438#endif
11439
11440   if((cfine >= -128) && (cfine <= 127) && (ccoarse >= -120) && (ccoarse <= 120)) {
11441      long finalcc = cbase + (((ccoarse * 256) + cfine) * 256);
11442
11443#if 0
11444      inSISIDXREG(SISPART4,0x1f,temp);
11445      if(!(temp & 0x01)) {
11446         if(pSiS->VBFlags & TV_NTSC) finalcc += 0x21ed8620;
11447	 else if(pSiS->VBFlags & TV_PALM) finalcc += ?;
11448	 else if(pSiS->VBFlags & TV_PALM) finalcc += ?;
11449	 else finalcc += 0x2a05d300;
11450      }
11451#endif
11452      setSISIDXREG(SISPART2,0x31,0x80,((finalcc >> 24) & 0x7f));
11453      outSISIDXREG(SISPART2,0x32,((finalcc >> 16) & 0xff));
11454      outSISIDXREG(SISPART2,0x33,((finalcc >> 8) & 0xff));
11455      outSISIDXREG(SISPART2,0x34,(finalcc & 0xff));
11456   }
11457}
11458
11459int SiS_GetSISTVcolcalib(ScrnInfoPtr pScrn, Bool coarse)
11460{
11461   SISPtr pSiS = SISPTR(pScrn);
11462#ifdef SISDUALHEAD
11463   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11464
11465   if(pSiSEnt && pSiS->DualHeadMode)
11466      if(coarse)  return (int)pSiSEnt->sistvcolcalibc;
11467      else        return (int)pSiSEnt->sistvcolcalibf;
11468   else
11469#endif
11470   if(coarse)     return (int)pSiS->sistvcolcalibc;
11471   else           return (int)pSiS->sistvcolcalibf;
11472}
11473
11474void SiS_SetSISTVcfilter(ScrnInfoPtr pScrn, int val)
11475{
11476   SISPtr pSiS = SISPTR(pScrn);
11477#ifdef SISDUALHEAD
11478   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11479#endif
11480
11481   pSiS->sistvcfilter = val ? 1 : 0;
11482#ifdef SISDUALHEAD
11483   if(pSiSEnt) pSiSEnt->sistvcfilter = pSiS->sistvcfilter;
11484#endif
11485
11486   if(!(pSiS->VBFlags & CRT2_TV))               return;
11487   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE))        return;
11488   if(pSiS->VBFlags & (TV_HIVISION | TV_YPBPR)) return;
11489
11490#ifdef UNLOCK_ALWAYS
11491   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11492#endif
11493
11494   setSISIDXREG(SISPART2,0x30,~0x10,((pSiS->sistvcfilter << 4) & 0x10));
11495}
11496
11497int SiS_GetSISTVcfilter(ScrnInfoPtr pScrn)
11498{
11499   SISPtr pSiS = SISPTR(pScrn);
11500   int result = pSiS->sistvcfilter;
11501   UChar temp;
11502#ifdef SISDUALHEAD
11503   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11504
11505   if(pSiSEnt && pSiS->DualHeadMode) result = pSiSEnt->sistvcfilter;
11506#endif
11507
11508   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE))        return result;
11509   if(!(pSiS->VBFlags & CRT2_TV))               return result;
11510   if(pSiS->VBFlags & (TV_HIVISION | TV_YPBPR)) return result;
11511
11512#ifdef UNLOCK_ALWAYS
11513   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11514#endif
11515   inSISIDXREG(SISPART2, 0x30, temp);
11516   return (int)((temp & 0x10) ? 1 : 0);
11517}
11518
11519void SiS_SetSISTVyfilter(ScrnInfoPtr pScrn, int val)
11520{
11521   SISPtr pSiS = SISPTR(pScrn);
11522#ifdef SISDUALHEAD
11523   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11524#endif
11525   UChar p35,p36,p37,p38,p48,p49,p4a,p30;
11526   int i,j;
11527
11528   pSiS->sistvyfilter = val;
11529#ifdef SISDUALHEAD
11530   if(pSiSEnt) pSiSEnt->sistvyfilter = pSiS->sistvyfilter;
11531#endif
11532
11533   if(!(pSiS->VBFlags & CRT2_TV))               return;
11534   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE))        return;
11535   if(pSiS->VBFlags & (TV_HIVISION | TV_YPBPR)) return;
11536
11537   p35 = pSiS->p2_35; p36 = pSiS->p2_36;
11538   p37 = pSiS->p2_37; p38 = pSiS->p2_38;
11539   p48 = pSiS->p2_48; p49 = pSiS->p2_49;
11540   p4a = pSiS->p2_4a; p30 = pSiS->p2_30;
11541#ifdef SISDUALHEAD
11542   if(pSiSEnt && pSiS->DualHeadMode) {
11543      p35 = pSiSEnt->p2_35; p36 = pSiSEnt->p2_36;
11544      p37 = pSiSEnt->p2_37; p38 = pSiSEnt->p2_38;
11545      p48 = pSiSEnt->p2_48; p49 = pSiSEnt->p2_49;
11546      p4a = pSiSEnt->p2_4a; p30 = pSiSEnt->p2_30;
11547   }
11548#endif
11549   p30 &= 0x20;
11550
11551#ifdef UNLOCK_ALWAYS
11552   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11553#endif
11554
11555   switch(pSiS->sistvyfilter) {
11556   case 0:
11557      andSISIDXREG(SISPART2,0x30,0xdf);
11558      break;
11559   case 1:
11560      outSISIDXREG(SISPART2,0x35,p35);
11561      outSISIDXREG(SISPART2,0x36,p36);
11562      outSISIDXREG(SISPART2,0x37,p37);
11563      outSISIDXREG(SISPART2,0x38,p38);
11564      if(!(pSiS->VBFlags2 & VB2_301)) {
11565         outSISIDXREG(SISPART2,0x48,p48);
11566         outSISIDXREG(SISPART2,0x49,p49);
11567         outSISIDXREG(SISPART2,0x4a,p4a);
11568      }
11569      setSISIDXREG(SISPART2,0x30,0xdf,p30);
11570      break;
11571   case 2:
11572   case 3:
11573   case 4:
11574   case 5:
11575   case 6:
11576   case 7:
11577   case 8:
11578      if(!(pSiS->VBFlags & (TV_PALM | TV_PALN | TV_NTSCJ))) {
11579         int yindex301 = -1, yindex301B = -1;
11580	 UChar p3d4_34;
11581
11582	 inSISIDXREG(SISCR,0x34,p3d4_34);
11583
11584	 switch((p3d4_34 & 0x7f)) {
11585	 case 0x59:  /* 320x200 */
11586	 case 0x41:
11587	 case 0x4f:
11588	 case 0x50:  /* 320x240 */
11589	 case 0x56:
11590	 case 0x53:
11591	    yindex301  = (pSiS->VBFlags & TV_NTSC) ? 0 : 4;
11592	    break;
11593	 case 0x2f:  /* 640x400 */
11594	 case 0x5d:
11595	 case 0x5e:
11596	 case 0x2e:  /* 640x480 */
11597	 case 0x44:
11598	 case 0x62:
11599	    yindex301  = (pSiS->VBFlags & TV_NTSC) ? 1 : 5;
11600	    yindex301B = (pSiS->VBFlags & TV_NTSC) ? 0 : 4;
11601	    break;
11602	 case 0x31:   /* 720x480 */
11603	 case 0x33:
11604	 case 0x35:
11605	 case 0x32:   /* 720x576 */
11606	 case 0x34:
11607	 case 0x36:
11608	 case 0x5f:   /* 768x576 */
11609	 case 0x60:
11610	 case 0x61:
11611	    yindex301  = (pSiS->VBFlags & TV_NTSC) ? 2 : 6;
11612	    yindex301B = (pSiS->VBFlags & TV_NTSC) ? 1 : 5;
11613	    break;
11614	 case 0x51:   /* 400x300 */
11615	 case 0x57:
11616	 case 0x54:
11617	 case 0x30:   /* 800x600 */
11618	 case 0x47:
11619	 case 0x63:
11620	    yindex301  = (pSiS->VBFlags & TV_NTSC) ? 3 : 7;
11621	    yindex301B = (pSiS->VBFlags & TV_NTSC) ? 2 : 6;
11622	    break;
11623	 case 0x52:   /* 512x384 */
11624	 case 0x58:
11625	 case 0x5c:
11626	 case 0x38:   /* 1024x768 */
11627	 case 0x4a:
11628	 case 0x64:
11629	    yindex301B = (pSiS->VBFlags & TV_NTSC) ? 3 : 7;
11630	    break;
11631	 }
11632         if(pSiS->VBFlags2 & VB2_301) {
11633            if(yindex301 >= 0) {
11634	       for(i=0, j=0x35; i<=3; i++, j++) {
11635	          outSISIDXREG(SISPART2,j,(SiSTVFilter301[yindex301].filter[pSiS->sistvyfilter-2][i]));
11636	       }
11637	    }
11638         } else {
11639            if(yindex301B >= 0) {
11640	       for(i=0, j=0x35; i<=3; i++, j++) {
11641	          outSISIDXREG(SISPART2,j,(SiSTVFilter301B[yindex301B].filter[pSiS->sistvyfilter-2][i]));
11642	       }
11643	       for(i=4, j=0x48; i<=6; i++, j++) {
11644	          outSISIDXREG(SISPART2,j,(SiSTVFilter301B[yindex301B].filter[pSiS->sistvyfilter-2][i]));
11645	       }
11646	    }
11647         }
11648         orSISIDXREG(SISPART2,0x30,0x20);
11649      }
11650   }
11651}
11652
11653int SiS_GetSISTVyfilter(ScrnInfoPtr pScrn)
11654{
11655   SISPtr pSiS = SISPTR(pScrn);
11656#ifdef SISDUALHEAD
11657   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11658
11659   if(pSiSEnt && pSiS->DualHeadMode)
11660      return (int)pSiSEnt->sistvyfilter;
11661   else
11662#endif
11663      return (int)pSiS->sistvyfilter;
11664}
11665
11666void SiS_SetSIS6326TVantiflicker(ScrnInfoPtr pScrn, int val)
11667{
11668   SISPtr pSiS = SISPTR(pScrn);
11669   UChar tmp;
11670
11671   pSiS->sistvantiflicker = val;
11672
11673   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) return;
11674
11675#ifdef UNLOCK_ALWAYS
11676   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11677#endif
11678
11679   tmp = SiS6326GetTVReg(pScrn,0x00);
11680   if(!(tmp & 0x04)) return;
11681
11682   /* Valid values: 0=off, 1=low, 2=med, 3=high, 4=adaptive */
11683   if(val >= 0 && val <= 4) {
11684      tmp &= 0x1f;
11685      tmp |= (val << 5);
11686      SiS6326SetTVReg(pScrn,0x00,tmp);
11687   }
11688}
11689
11690int SiS_GetSIS6326TVantiflicker(ScrnInfoPtr pScrn)
11691{
11692   SISPtr pSiS = SISPTR(pScrn);
11693   UChar tmp;
11694
11695   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) {
11696      return (int)pSiS->sistvantiflicker;
11697   }
11698
11699#ifdef UNLOCK_ALWAYS
11700   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11701#endif
11702
11703   tmp = SiS6326GetTVReg(pScrn,0x00);
11704   if(!(tmp & 0x04)) {
11705      return (int)pSiS->sistvantiflicker;
11706   } else {
11707      return (int)((tmp >> 5) & 0x07);
11708   }
11709}
11710
11711void SiS_SetSIS6326TVenableyfilter(ScrnInfoPtr pScrn, int val)
11712{
11713   SISPtr pSiS = SISPTR(pScrn);
11714   UChar tmp;
11715
11716   if(val) val = 1;
11717   pSiS->sis6326enableyfilter = val;
11718
11719   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) return;
11720
11721#ifdef UNLOCK_ALWAYS
11722   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11723#endif
11724
11725   tmp = SiS6326GetTVReg(pScrn,0x00);
11726   if(!(tmp & 0x04)) return;
11727
11728   tmp = SiS6326GetTVReg(pScrn,0x43);
11729   tmp &= ~0x10;
11730   tmp |= ((val & 0x01) << 4);
11731   SiS6326SetTVReg(pScrn,0x43,tmp);
11732}
11733
11734int SiS_GetSIS6326TVenableyfilter(ScrnInfoPtr pScrn)
11735{
11736   SISPtr pSiS = SISPTR(pScrn);
11737   UChar tmp;
11738
11739   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) {
11740      return (int)pSiS->sis6326enableyfilter;
11741   }
11742
11743#ifdef UNLOCK_ALWAYS
11744   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11745#endif
11746
11747   tmp = SiS6326GetTVReg(pScrn,0x00);
11748   if(!(tmp & 0x04)) {
11749      return (int)pSiS->sis6326enableyfilter;
11750   } else {
11751      tmp = SiS6326GetTVReg(pScrn,0x43);
11752      return (int)((tmp >> 4) & 0x01);
11753   }
11754}
11755
11756void SiS_SetSIS6326TVyfilterstrong(ScrnInfoPtr pScrn, int val)
11757{
11758   SISPtr pSiS = SISPTR(pScrn);
11759   UChar tmp;
11760
11761   if(val) val = 1;
11762   pSiS->sis6326yfilterstrong = val;
11763
11764   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) return;
11765
11766#ifdef UNLOCK_ALWAYS
11767   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11768#endif
11769
11770   tmp = SiS6326GetTVReg(pScrn,0x00);
11771   if(!(tmp & 0x04)) return;
11772
11773   tmp = SiS6326GetTVReg(pScrn,0x43);
11774   if(tmp & 0x10) {
11775      tmp &= ~0x40;
11776      tmp |= ((val & 0x01) << 6);
11777      SiS6326SetTVReg(pScrn,0x43,tmp);
11778   }
11779}
11780
11781int SiS_GetSIS6326TVyfilterstrong(ScrnInfoPtr pScrn)
11782{
11783   SISPtr pSiS = SISPTR(pScrn);
11784   UChar tmp;
11785
11786   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) {
11787      return (int)pSiS->sis6326yfilterstrong;
11788   }
11789
11790#ifdef UNLOCK_ALWAYS
11791   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11792#endif
11793
11794   tmp = SiS6326GetTVReg(pScrn,0x00);
11795   if(!(tmp & 0x04)) {
11796      return (int)pSiS->sis6326yfilterstrong;
11797   } else {
11798      tmp = SiS6326GetTVReg(pScrn,0x43);
11799      if(!(tmp & 0x10)) {
11800         return (int)pSiS->sis6326yfilterstrong;
11801      } else {
11802         return (int)((tmp >> 6) & 0x01);
11803      }
11804   }
11805}
11806
11807void SiS_SetTVxposoffset(ScrnInfoPtr pScrn, int val)
11808{
11809   SISPtr pSiS = SISPTR(pScrn);
11810#ifdef SISDUALHEAD
11811   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11812#endif
11813
11814#ifdef UNLOCK_ALWAYS
11815   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11816#endif
11817
11818   pSiS->tvxpos = val;
11819#ifdef SISDUALHEAD
11820   if(pSiSEnt) pSiSEnt->tvxpos = val;
11821#endif
11822
11823   if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
11824
11825      if(pSiS->VBFlags & CRT2_TV) {
11826
11827         if(pSiS->VBFlags2 & VB2_CHRONTEL) {
11828
11829	    int x = pSiS->tvx;
11830#ifdef SISDUALHEAD
11831	    if(pSiSEnt && pSiS->DualHeadMode) x = pSiSEnt->tvx;
11832#endif
11833	    switch(pSiS->ChrontelType) {
11834	    case CHRONTEL_700x:
11835	       if((val >= -32) && (val <= 32)) {
11836		   x += val;
11837		   if(x < 0) x = 0;
11838		   SiS_SetCH700x(pSiS->SiS_Pr, 0x0a, (x & 0xff));
11839		   SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x08, ((x & 0x0100) >> 7), 0xFD);
11840	       }
11841	       break;
11842	    case CHRONTEL_701x:
11843	       /* Not supported by hardware */
11844	       break;
11845	    }
11846
11847	 } else if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
11848
11849	    if((val >= -32) && (val <= 32)) {
11850
11851	        UChar p2_1f,p2_20,p2_2b,p2_42,p2_43;
11852		UShort temp;
11853		int mult;
11854
11855		p2_1f = pSiS->p2_1f;
11856		p2_20 = pSiS->p2_20;
11857		p2_2b = pSiS->p2_2b;
11858		p2_42 = pSiS->p2_42;
11859		p2_43 = pSiS->p2_43;
11860#ifdef SISDUALHEAD
11861	        if(pSiSEnt && pSiS->DualHeadMode) {
11862		   p2_1f = pSiSEnt->p2_1f;
11863		   p2_20 = pSiSEnt->p2_20;
11864		   p2_2b = pSiSEnt->p2_2b;
11865		   p2_42 = pSiSEnt->p2_42;
11866		   p2_43 = pSiSEnt->p2_43;
11867		}
11868#endif
11869		mult = 2;
11870		if(pSiS->VBFlags & TV_YPBPR) {
11871		   if(pSiS->VBFlags & (TV_YPBPR1080I | TV_YPBPR750P)) {
11872		      mult = 4;
11873		   }
11874		}
11875
11876		temp = p2_1f | ((p2_20 & 0xf0) << 4);
11877		temp += (val * mult);
11878		p2_1f = temp & 0xff;
11879		p2_20 = (temp & 0xf00) >> 4;
11880		p2_2b = ((p2_2b & 0x0f) + (val * mult)) & 0x0f;
11881		temp = p2_43 | ((p2_42 & 0xf0) << 4);
11882		temp += (val * mult);
11883		p2_43 = temp & 0xff;
11884		p2_42 = (temp & 0xf00) >> 4;
11885		SISWaitRetraceCRT2(pScrn);
11886	        outSISIDXREG(SISPART2,0x1f,p2_1f);
11887		setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
11888		setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
11889		setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
11890		outSISIDXREG(SISPART2,0x43,p2_43);
11891	     }
11892	 }
11893      }
11894
11895   } else if(pSiS->Chipset == PCI_CHIP_SIS6326) {
11896
11897      if(pSiS->SiS6326Flags & SIS6326_TVDETECTED) {
11898
11899         UChar tmp;
11900	 UShort temp1, temp2, temp3;
11901
11902         tmp = SiS6326GetTVReg(pScrn,0x00);
11903         if(tmp & 0x04) {
11904
11905	    temp1 = pSiS->tvx1;
11906            temp2 = pSiS->tvx2;
11907            temp3 = pSiS->tvx3;
11908            if((val >= -16) && (val <= 16)) {
11909	       if(val > 0) {
11910	          temp1 += (val * 4);
11911	          temp2 += (val * 4);
11912	          while((temp1 > 0x0fff) || (temp2 > 0x0fff)) {
11913	             temp1 -= 4;
11914		     temp2 -= 4;
11915	          }
11916	       } else {
11917	          val = -val;
11918	          temp3 += (val * 4);
11919	          while(temp3 > 0x03ff) {
11920	     	     temp3 -= 4;
11921	          }
11922	       }
11923            }
11924            SiS6326SetTVReg(pScrn,0x3a,(temp1 & 0xff));
11925            tmp = SiS6326GetTVReg(pScrn,0x3c);
11926            tmp &= 0xf0;
11927            tmp |= ((temp1 & 0x0f00) >> 8);
11928            SiS6326SetTVReg(pScrn,0x3c,tmp);
11929            SiS6326SetTVReg(pScrn,0x26,(temp2 & 0xff));
11930            tmp = SiS6326GetTVReg(pScrn,0x27);
11931            tmp &= 0x0f;
11932            tmp |= ((temp2 & 0x0f00) >> 4);
11933            SiS6326SetTVReg(pScrn,0x27,tmp);
11934            SiS6326SetTVReg(pScrn,0x12,(temp3 & 0xff));
11935            tmp = SiS6326GetTVReg(pScrn,0x13);
11936            tmp &= ~0xC0;
11937            tmp |= ((temp3 & 0x0300) >> 2);
11938            SiS6326SetTVReg(pScrn,0x13,tmp);
11939	 }
11940      }
11941   }
11942}
11943
11944int SiS_GetTVxposoffset(ScrnInfoPtr pScrn)
11945{
11946   SISPtr pSiS = SISPTR(pScrn);
11947#ifdef SISDUALHEAD
11948   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11949
11950   if(pSiSEnt && pSiS->DualHeadMode)
11951        return (int)pSiSEnt->tvxpos;
11952   else
11953#endif
11954        return (int)pSiS->tvxpos;
11955}
11956
11957void SiS_SetTVyposoffset(ScrnInfoPtr pScrn, int val)
11958{
11959   SISPtr pSiS = SISPTR(pScrn);
11960#ifdef SISDUALHEAD
11961   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11962#endif
11963
11964#ifdef UNLOCK_ALWAYS
11965   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11966#endif
11967
11968   pSiS->tvypos = val;
11969#ifdef SISDUALHEAD
11970   if(pSiSEnt) pSiSEnt->tvypos = val;
11971#endif
11972
11973   if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
11974
11975      if(pSiS->VBFlags & CRT2_TV) {
11976
11977         if(pSiS->VBFlags2 & VB2_CHRONTEL) {
11978
11979	    int y = pSiS->tvy;
11980#ifdef SISDUALHEAD
11981	    if(pSiSEnt && pSiS->DualHeadMode) y = pSiSEnt->tvy;
11982#endif
11983	    switch(pSiS->ChrontelType) {
11984	    case CHRONTEL_700x:
11985	       if((val >= -32) && (val <= 32)) {
11986		   y -= val;
11987		   if(y < 0) y = 0;
11988		   SiS_SetCH700x(pSiS->SiS_Pr, 0x0b, (y & 0xff));
11989		   SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x08, ((y & 0x0100) >> 8), 0xFE);
11990	       }
11991	       break;
11992	    case CHRONTEL_701x:
11993	       /* Not supported by hardware */
11994	       break;
11995	    }
11996
11997	 } else if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
11998
11999	    if((val >= -32) && (val <= 32)) {
12000		char p2_01, p2_02;
12001
12002		if( (pSiS->VBFlags & TV_HIVISION) ||
12003		    ((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & (TV_YPBPR1080I|TV_YPBPR750P))) ) {
12004		   val *= 2;
12005		} else {
12006		   val /= 2;  /* 4 */
12007		}
12008
12009		p2_01 = pSiS->p2_01;
12010		p2_02 = pSiS->p2_02;
12011#ifdef SISDUALHEAD
12012	        if(pSiSEnt && pSiS->DualHeadMode) {
12013		   p2_01 = pSiSEnt->p2_01;
12014		   p2_02 = pSiSEnt->p2_02;
12015		}
12016#endif
12017		p2_01 += val; /* val * 2 */
12018		p2_02 += val; /* val * 2 */
12019		if(!(pSiS->VBFlags & (TV_YPBPR | TV_HIVISION))) {
12020		   while((p2_01 <= 0) || (p2_02 <= 0)) {
12021		      p2_01 += 2;
12022		      p2_02 += 2;
12023		   }
12024		} else if((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR1080I)) {
12025		   while(p2_01 <= 8) {
12026		      p2_01 += 2;
12027		      p2_02 += 2;
12028		   }
12029		} else if((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR750P)) {
12030		   while(p2_01 <= 10) {
12031		      p2_01 += 2;
12032		      p2_02 += 2;
12033		   }
12034		}
12035
12036		SISWaitRetraceCRT2(pScrn);
12037		outSISIDXREG(SISPART2,0x01,p2_01);
12038		outSISIDXREG(SISPART2,0x02,p2_02);
12039	     }
12040	 }
12041
12042      }
12043
12044   } else if(pSiS->Chipset == PCI_CHIP_SIS6326) {
12045
12046      if(pSiS->SiS6326Flags & SIS6326_TVDETECTED) {
12047
12048         UChar tmp;
12049	 int temp1, limit;
12050
12051         tmp = SiS6326GetTVReg(pScrn,0x00);
12052         if(tmp & 0x04) {
12053
12054	    if((val >= -16) && (val <= 16)) {
12055	      temp1 = (UShort)pSiS->tvy1;
12056	      limit = (pSiS->SiS6326Flags & SIS6326_TVPAL) ? 625 : 525;
12057	      if(val > 0) {
12058                temp1 += (val * 4);
12059	        if(temp1 > limit) temp1 -= limit;
12060	      } else {
12061	        val = -val;
12062	        temp1 -= (val * 2);
12063	        if(temp1 <= 0) temp1 += (limit -1);
12064	      }
12065	      SiS6326SetTVReg(pScrn,0x11,(temp1 & 0xff));
12066	      tmp = SiS6326GetTVReg(pScrn,0x13);
12067	      tmp &= ~0x30;
12068	      tmp |= ((temp1 & 0x300) >> 4);
12069	      SiS6326SetTVReg(pScrn,0x13,tmp);
12070	      if(temp1 == 1)                                 tmp = 0x10;
12071	      else {
12072	       if(pSiS->SiS6326Flags & SIS6326_TVPAL) {
12073	         if((temp1 <= 3) || (temp1 >= (limit - 2)))  tmp = 0x08;
12074	         else if(temp1 < 22)		 	     tmp = 0x02;
12075	         else 					     tmp = 0x04;
12076	       } else {
12077	         if((temp1 <= 5) || (temp1 >= (limit - 4)))  tmp = 0x08;
12078	         else if(temp1 < 19)			     tmp = 0x02;
12079	         else 					     tmp = 0x04;
12080	       }
12081	     }
12082	     SiS6326SetTVReg(pScrn,0x21,tmp);
12083           }
12084	 }
12085      }
12086   }
12087}
12088
12089int SiS_GetTVyposoffset(ScrnInfoPtr pScrn)
12090{
12091   SISPtr pSiS = SISPTR(pScrn);
12092#ifdef SISDUALHEAD
12093   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12094
12095   if(pSiSEnt && pSiS->DualHeadMode)
12096        return (int)pSiSEnt->tvypos;
12097   else
12098#endif
12099        return (int)pSiS->tvypos;
12100}
12101
12102void SiS_SetTVxscale(ScrnInfoPtr pScrn, int val)
12103{
12104   SISPtr pSiS = SISPTR(pScrn);
12105#ifdef SISDUALHEAD
12106   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12107#endif
12108
12109#ifdef UNLOCK_ALWAYS
12110   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
12111#endif
12112
12113   pSiS->tvxscale = val;
12114#ifdef SISDUALHEAD
12115   if(pSiSEnt) pSiSEnt->tvxscale = val;
12116#endif
12117
12118   if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
12119
12120      if((pSiS->VBFlags & CRT2_TV) && (pSiS->VBFlags2 & VB2_SISBRIDGE)) {
12121
12122	 if((val >= -16) && (val <= 16)) {
12123
12124	    UChar p2_44,p2_45,p2_46;
12125	    int scalingfactor, mult;
12126
12127	    p2_44 = pSiS->p2_44;
12128	    p2_45 = pSiS->p2_45 & 0x3f;
12129	    p2_46 = pSiS->p2_46 & 0x07;
12130#ifdef SISDUALHEAD
12131	    if(pSiSEnt && pSiS->DualHeadMode) {
12132	       p2_44 = pSiSEnt->p2_44;
12133	       p2_45 = pSiSEnt->p2_45 & 0x3f;
12134	       p2_46 = pSiSEnt->p2_46 & 0x07;
12135	    }
12136#endif
12137	    scalingfactor = (p2_46 << 13) | ((p2_45 & 0x1f) << 8) | p2_44;
12138
12139	    mult = 64;
12140	    if(pSiS->VBFlags & TV_YPBPR) {
12141	       if(pSiS->VBFlags & TV_YPBPR1080I) {
12142	          mult = 190;
12143	       } else if(pSiS->VBFlags & TV_YPBPR750P) {
12144	          mult = 360;
12145	       }
12146	    } else if(pSiS->VBFlags & TV_HIVISION) {
12147	       mult = 190;
12148	    }
12149
12150	    if(val < 0) {
12151	       p2_45 &= 0xdf;
12152	       scalingfactor += ((-val) * mult);
12153	       if(scalingfactor > 0xffff) scalingfactor = 0xffff;
12154	    } else if(val > 0) {
12155	       p2_45 &= 0xdf;
12156	       scalingfactor -= (val * mult);
12157	       if(scalingfactor < 1) scalingfactor = 1;
12158	    }
12159
12160	    p2_44 = scalingfactor & 0xff;
12161	    p2_45 &= 0xe0;
12162	    p2_45 |= ((scalingfactor >> 8) & 0x1f);
12163	    p2_46 = ((scalingfactor >> 13) & 0x07);
12164
12165	    SISWaitRetraceCRT2(pScrn);
12166	    outSISIDXREG(SISPART2,0x44,p2_44);
12167	    setSISIDXREG(SISPART2,0x45,0xC0,p2_45);
12168	    if(!(pSiS->VBFlags2 & VB2_301)) {
12169	       setSISIDXREG(SISPART2,0x46,0xF8,p2_46);
12170	    }
12171
12172	 }
12173
12174      }
12175
12176   }
12177}
12178
12179int SiS_GetTVxscale(ScrnInfoPtr pScrn)
12180{
12181   SISPtr pSiS = SISPTR(pScrn);
12182#ifdef SISDUALHEAD
12183   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12184
12185   if(pSiSEnt && pSiS->DualHeadMode)
12186        return (int)pSiSEnt->tvxscale;
12187   else
12188#endif
12189        return (int)pSiS->tvxscale;
12190}
12191
12192void SiS_SetTVyscale(ScrnInfoPtr pScrn, int val)
12193{
12194   SISPtr pSiS = SISPTR(pScrn);
12195#ifdef SISDUALHEAD
12196   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12197#endif
12198
12199#ifdef UNLOCK_ALWAYS
12200   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
12201#endif
12202
12203   if(val < -4) val = -4;
12204   if(val > 3)  val = 3;
12205
12206   pSiS->tvyscale = val;
12207#ifdef SISDUALHEAD
12208   if(pSiSEnt) pSiSEnt->tvyscale = val;
12209#endif
12210
12211   if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
12212
12213      if((pSiS->VBFlags & CRT2_TV) && (pSiS->VBFlags2 & VB2_SISBRIDGE)) {
12214
12215	 int srindex = -1, newvde, i = 0, j, vlimit, temp, vdediv;
12216	 int hdclk = 0;
12217	 UChar p3d4_34;
12218	 Bool found = FALSE;
12219	 Bool usentsc = FALSE;
12220	 Bool is750p = FALSE;
12221	 Bool is1080i = FALSE;
12222	 Bool skipmoveup = FALSE;
12223
12224	 SiS_UnLockCRT2(pSiS->SiS_Pr);
12225
12226	 if((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR525P)) {
12227	    vlimit = 525 - 7;
12228	    vdediv = 1;
12229	    usentsc = TRUE;
12230	 } else if((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR625P)) {
12231	    vlimit = 625 - 7;
12232	    vdediv = 1;
12233	 } else if((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR750P)) {
12234	    vlimit = 750 - 7;
12235	    vdediv = 1;
12236	    is750p = TRUE;
12237	 } else if(((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR1080I)) ||
12238	           (pSiS->VBFlags & TV_HIVISION)) {
12239	    vlimit = (1125 - 7) / 2;
12240	    vdediv = 2;
12241	    is1080i = TRUE;
12242	 } else {
12243	    if( ((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR525I)) ||
12244	        ((!(pSiS->VBFlags & TV_YPBPR)) && (pSiS->VBFlags & (TV_NTSC | TV_PALM))) ) {
12245	       usentsc = TRUE;
12246	    }
12247	    vlimit = usentsc ? 259 : 309;
12248	    vdediv = 2;
12249	 }
12250
12251	 inSISIDXREG(SISCR,0x34,p3d4_34);
12252
12253	 switch((p3d4_34 & 0x7f)) {
12254	 case 0x50:   /* 320x240 */
12255	 case 0x56:
12256	 case 0x53:
12257	    hdclk = 1;
12258	    /* fall through */
12259	 case 0x2e:   /* 640x480 */
12260	 case 0x44:
12261	 case 0x62:
12262	    if(is1080i) {
12263	       srindex = 98;
12264	    } else if(is750p) {
12265	       srindex = 42;
12266	    } else {
12267	       srindex  = usentsc ? 0 : 21;
12268	    }
12269	    break;
12270	 case 0x31:   /* 720x480 */
12271	 case 0x33:
12272	 case 0x35:
12273	    if(is1080i) {
12274	       /* n/a */
12275	    } else if(is750p) {
12276	       srindex = 49;
12277	    } else {
12278	       srindex = usentsc ? 7 : 21;
12279	    }
12280	    break;
12281	 case 0x32:   /* 720x576 */
12282	 case 0x34:
12283	 case 0x36:
12284	 case 0x5f:   /* 768x576 */
12285	 case 0x60:
12286	 case 0x61:
12287	    if(is1080i) {
12288	       /* n/a */
12289	    } else if(is750p) {
12290	       srindex = 56;
12291	    } else {
12292	       srindex  = usentsc ? 147 : 28;
12293	    }
12294	    break;
12295	 case 0x70:   /* 800x480 */
12296	 case 0x7a:
12297	 case 0x76:
12298	    if(is1080i) {
12299	       srindex = 105;
12300	    } else if(is750p) {
12301	       srindex = 63;
12302	    } else {
12303	       srindex = usentsc ? 175 : 21;
12304	    }
12305	    break;
12306	 case 0x51:   /* 400x300 - hdclk mode */
12307	 case 0x57:
12308	 case 0x54:
12309	    hdclk = 1;
12310	    /* fall through */
12311	 case 0x30:   /* 800x600 */
12312	 case 0x47:
12313	 case 0x63:
12314	    if(is1080i) {
12315	       srindex = 112;
12316	    } else if(is750p) {
12317	       srindex = 70;
12318	    } else {
12319	       srindex = usentsc ? 14 : 35;
12320	    }
12321	    break;
12322	 case 0x1d:	/* 960x540 */
12323	 case 0x1e:
12324	 case 0x1f:
12325	    if(is1080i) {
12326	       srindex = 196;
12327	       skipmoveup = TRUE;
12328	    }
12329	    break;
12330	 case 0x20:	/* 960x600 */
12331	 case 0x21:
12332	 case 0x22:
12333	    if(pSiS->VGAEngine == SIS_315_VGA && is1080i) {
12334	       srindex = 203;
12335	    }
12336	    break;
12337	 case 0x71:	/* 1024x576 */
12338	 case 0x74:
12339	 case 0x77:
12340	    if(is1080i) {
12341	       srindex = 119;
12342	    } else if(is750p) {
12343	       srindex = 77;
12344	    } else {
12345	       srindex  = usentsc ? 182 : 189;
12346	    }
12347	    break;
12348	 case 0x52:	/* 512x384 */
12349	 case 0x58:
12350	 case 0x5c:
12351	    hdclk = 1;
12352	    /* fall through */
12353	 case 0x38:	/* 1024x768 */
12354	 case 0x4a:
12355	 case 0x64:
12356	    if(is1080i) {
12357	       srindex = 126;
12358	    } else if(is750p) {
12359	       srindex = 84;
12360	    } else if(!usentsc) {
12361	       srindex = 154;
12362	    } else if(vdediv == 1) {
12363	       if(!hdclk) srindex = 168;
12364	    } else {
12365	       if(!hdclk) srindex = 161;
12366	    }
12367	    break;
12368	 case 0x79:	/* 1280x720 */
12369	 case 0x75:
12370	 case 0x78:
12371	    if(is1080i) {
12372	       srindex = 133;
12373	    } else if(is750p) {
12374	       srindex = 91;
12375	    }
12376	    break;
12377	 case 0x3a:	/* 1280x1024 */
12378	 case 0x4d:
12379	 case 0x65:
12380	    if(is1080i) {
12381	       srindex = 140;
12382	    }
12383	    break;
12384	 }
12385
12386	 if(srindex < 0) return;
12387
12388	 if(pSiS->tvyscale != 0) {
12389	    for(j = 0; j <= 1; j++) {
12390	       for(i = 0; i <= 6; i++) {
12391		  if(SiSTVVScale[srindex+i].sindex == pSiS->tvyscale) {
12392		     found = TRUE;
12393		     break;
12394		  }
12395	       }
12396	       if(found) break;
12397	       if(pSiS->tvyscale > 0) pSiS->tvyscale--;
12398	       else pSiS->tvyscale++;
12399	    }
12400	 }
12401
12402#ifdef SISDUALHEAD
12403	 if(pSiSEnt) pSiSEnt->tvyscale = pSiS->tvyscale;
12404#endif
12405
12406	 if(pSiS->tvyscale == 0) {
12407	    UChar p2_0a = pSiS->p2_0a;
12408	    UChar p2_2f = pSiS->p2_2f;
12409	    UChar p2_30 = pSiS->p2_30;
12410	    UChar p2_46 = pSiS->p2_46;
12411	    UChar p2_47 = pSiS->p2_47;
12412	    UChar p1scaling[9], p4scaling[9];
12413	    UChar *p2scaling;
12414
12415	    for(i = 0; i < 9; i++) {
12416	        p1scaling[i] = pSiS->scalingp1[i];
12417		p4scaling[i] = pSiS->scalingp4[i];
12418	    }
12419	    p2scaling = &pSiS->scalingp2[0];
12420
12421#ifdef SISDUALHEAD
12422	    if(pSiSEnt && pSiS->DualHeadMode) {
12423	       p2_0a = pSiSEnt->p2_0a;
12424	       p2_2f = pSiSEnt->p2_2f;
12425	       p2_30 = pSiSEnt->p2_30;
12426	       p2_46 = pSiSEnt->p2_46;
12427	       p2_47 = pSiSEnt->p2_47;
12428	       for(i = 0; i < 9; i++) {
12429		  p1scaling[i] = pSiSEnt->scalingp1[i];
12430		  p4scaling[i] = pSiSEnt->scalingp4[i];
12431	       }
12432	       p2scaling = &pSiSEnt->scalingp2[0];
12433	    }
12434#endif
12435            SISWaitRetraceCRT2(pScrn);
12436	    if(pSiS->VBFlags2 & VB2_SISTAP4SCALER) {
12437	       for(i = 0; i < 64; i++) {
12438	          outSISIDXREG(SISPART2,(0xc0 + i),p2scaling[i]);
12439	       }
12440	    }
12441	    for(i = 0; i < 9; i++) {
12442	       outSISIDXREG(SISPART1,SiSScalingP1Regs[i],p1scaling[i]);
12443	    }
12444	    for(i = 0; i < 9; i++) {
12445	       outSISIDXREG(SISPART4,SiSScalingP4Regs[i],p4scaling[i]);
12446	    }
12447
12448	    setSISIDXREG(SISPART2,0x0a,0x7f,(p2_0a & 0x80));
12449	    outSISIDXREG(SISPART2,0x2f,p2_2f);
12450	    setSISIDXREG(SISPART2,0x30,0x3f,(p2_30 & 0xc0));
12451	    if(!(pSiS->VBFlags2 & VB2_301)) {
12452	       setSISIDXREG(SISPART2,0x46,0x9f,(p2_46 & 0x60));
12453	       outSISIDXREG(SISPART2,0x47,p2_47);
12454	    }
12455
12456	 } else {
12457
12458	    int realvde, myypos, watchdog = 32;
12459	    unsigned short temp1, temp2, vgahde, vgaht, vgavt;
12460	    int p1div = 1;
12461	    ULong calctemp;
12462
12463	    srindex += i;
12464	    newvde = SiSTVVScale[srindex].ScaleVDE;
12465	    realvde = SiSTVVScale[srindex].RealVDE;
12466
12467	    if(vdediv == 1) p1div = 2;
12468
12469	    if(!skipmoveup) {
12470	       do {
12471	          inSISIDXREG(SISPART2,0x01,temp);
12472	          temp = vlimit - ((temp & 0x7f) / p1div);
12473	          if((temp - (((newvde / vdediv) - 2) + 9)) > 0) break;
12474	          myypos = pSiS->tvypos - 1;
12475#ifdef SISDUALHEAD
12476	          if(pSiSEnt && pSiS->DualHeadMode) myypos = pSiSEnt->tvypos - 1;
12477#endif
12478	          SiS_SetTVyposoffset(pScrn, myypos);
12479	       } while(watchdog--);
12480	    }
12481
12482	    SISWaitRetraceCRT2(pScrn);
12483
12484	    if(pSiS->VBFlags2 & VB2_SISTAP4SCALER) {
12485	       SiS_CalcXTapScaler(pSiS->SiS_Pr, realvde, newvde, 4, FALSE);
12486	    }
12487
12488	    if(!(pSiS->VBFlags2 & VB2_301)) {
12489	       temp = (newvde / vdediv) - 3;
12490	       setSISIDXREG(SISPART2,0x46,0x9f,((temp & 0x0300) >> 3));
12491	       outSISIDXREG(SISPART2,0x47,(temp & 0xff));
12492	    }
12493
12494	    inSISIDXREG(SISPART1,0x0a,temp1);
12495	    inSISIDXREG(SISPART1,0x0c,temp2);
12496	    vgahde = ((temp2 & 0xf0) << 4) | temp1;
12497	    if(pSiS->VGAEngine == SIS_300_VGA) {
12498	       vgahde -= 12;
12499	    } else {
12500	       vgahde -= 16;
12501	       if(hdclk) vgahde <<= 1;
12502	    }
12503
12504	    vgaht = SiSTVVScale[srindex].reg[0];
12505	    temp1 = vgaht;
12506	    if((pSiS->VGAEngine == SIS_315_VGA) && hdclk) temp1 >>= 1;
12507	    temp1--;
12508	    outSISIDXREG(SISPART1,0x08,(temp1 & 0xff));
12509	    setSISIDXREG(SISPART1,0x09,0x0f,((temp1 >> 4) & 0xf0));
12510
12511	    temp2 = (vgaht - vgahde) >> 2;
12512	    if(pSiS->VGAEngine == SIS_300_VGA) {
12513	       temp1 = vgahde + 12 + temp2;
12514	       temp2 = temp1 + (temp2 << 1);
12515	    } else {
12516	       temp1 = vgahde;
12517	       if(hdclk) {
12518		  temp1 >>= 1;
12519		  temp2 >>= 1;
12520	       }
12521	       temp2 >>= 1;
12522	       temp1 = temp1 + 16 + temp2;
12523	       temp2 = temp1 + temp2;
12524	    }
12525	    outSISIDXREG(SISPART1,0x0b,(temp1 & 0xff));
12526	    setSISIDXREG(SISPART1,0x0c,0xf0,((temp1 >> 8) & 0x0f));
12527	    outSISIDXREG(SISPART1,0x0d,(temp2 & 0xff));
12528
12529	    vgavt = SiSTVVScale[srindex].reg[1];
12530	    temp1 = vgavt - 1;
12531	    if(pSiS->VGAEngine == SIS_315_VGA) temp1--;
12532	    outSISIDXREG(SISPART1,0x0e,(temp1 & 0xff));
12533	    setSISIDXREG(SISPART1,0x12,0xf8,((temp1 >> 8 ) & 0x07));
12534	    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->ChipType >= SIS_661)) {
12535	       temp1 = (vgavt + SiSTVVScale[srindex].RealVDE) >> 1;
12536	       temp2 = ((vgavt - SiSTVVScale[srindex].RealVDE) >> 4) + temp1 + 1;
12537	    } else {
12538	       temp1 = (vgavt - SiSTVVScale[srindex].RealVDE) >> 2;
12539	       temp2 = (temp1 < 4) ? 4 : temp1;
12540	       temp1 += SiSTVVScale[srindex].RealVDE;
12541	       temp2 = (temp2 >> 2) + temp1 + 1;
12542	    }
12543	    outSISIDXREG(SISPART1,0x10,(temp1 & 0xff));
12544	    setSISIDXREG(SISPART1,0x11,0x8f,((temp1 >> 4) & 0x70));
12545	    setSISIDXREG(SISPART1,0x11,0xf0,(temp2 & 0x0f));
12546
12547	    setSISIDXREG(SISPART2,0x0a,0x7f,((SiSTVVScale[srindex].reg[2] >> 8) & 0x80));
12548	    outSISIDXREG(SISPART2,0x2f,((newvde / vdediv) - 2));
12549	    setSISIDXREG(SISPART2,0x30,0x3f,((((newvde / vdediv) - 2) >> 2) & 0xc0));
12550
12551	    outSISIDXREG(SISPART4,0x13,(SiSTVVScale[srindex].reg[2] & 0xff));
12552	    outSISIDXREG(SISPART4,0x14,(SiSTVVScale[srindex].reg[3] & 0xff));
12553	    setSISIDXREG(SISPART4,0x15,0x7f,((SiSTVVScale[srindex].reg[3] >> 1) & 0x80));
12554
12555	    temp1 = vgaht - 1;
12556	    outSISIDXREG(SISPART4,0x16,(temp1 & 0xff));
12557	    setSISIDXREG(SISPART4,0x15,0x87,((temp1 >> 5) & 0x78));
12558
12559	    temp1 = vgavt - 1;
12560	    outSISIDXREG(SISPART4,0x17,(temp1 & 0xff));
12561	    setSISIDXREG(SISPART4,0x15,0xf8,((temp1 >> 8) & 0x07));
12562
12563	    outSISIDXREG(SISPART4,0x18,0x00);
12564	    setSISIDXREG(SISPART4,0x19,0xf0,0x00);
12565
12566	    inSISIDXREG(SISPART4,0x0e,temp1);
12567	    if(is1080i) {
12568	       if(!(temp1 & 0xe0)) newvde >>= 1;
12569	    }
12570
12571	    temp = 0x40;
12572	    if(realvde <= newvde) temp = 0;
12573	    else realvde -= newvde;
12574
12575	    calctemp = (realvde * 256 * 1024) / newvde;
12576	    if((realvde * 256 * 1024) % newvde) calctemp++;
12577	    outSISIDXREG(SISPART4,0x1b,(calctemp & 0xff));
12578	    outSISIDXREG(SISPART4,0x1a,((calctemp >> 8) & 0xff));
12579	    setSISIDXREG(SISPART4,0x19,0x8f,(((calctemp >> 12) & 0x70) | temp));
12580	 }
12581
12582      }
12583
12584   }
12585}
12586
12587int SiS_GetTVyscale(ScrnInfoPtr pScrn)
12588{
12589   SISPtr pSiS = SISPTR(pScrn);
12590#ifdef SISDUALHEAD
12591   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12592
12593   if(pSiSEnt && pSiS->DualHeadMode)
12594        return (int)pSiSEnt->tvyscale;
12595   else
12596#endif
12597        return (int)pSiS->tvyscale;
12598}
12599
12600void SiS_SetSISCRT1SaturationGain(ScrnInfoPtr pScrn, int val)
12601{
12602   SISPtr pSiS = SISPTR(pScrn);
12603#ifdef SISDUALHEAD
12604   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12605#endif
12606
12607   pSiS->siscrt1satgain = val;
12608#ifdef SISDUALHEAD
12609   if(pSiSEnt) pSiSEnt->siscrt1satgain = val;
12610#endif
12611
12612   if(!(pSiS->SiS_SD3_Flags & SiS_SD3_CRT1SATGAIN)) return;
12613
12614#ifdef UNLOCK_ALWAYS
12615   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
12616#endif
12617
12618   if((val >= 0) && (val <= 7)) {
12619      setSISIDXREG(SISCR,0x53,0xE3, (val << 2));
12620   }
12621}
12622
12623int SiS_GetSISCRT1SaturationGain(ScrnInfoPtr pScrn)
12624{
12625   SISPtr pSiS = SISPTR(pScrn);
12626   int result = pSiS->siscrt1satgain;
12627   UChar temp;
12628#ifdef SISDUALHEAD
12629   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12630
12631   if(pSiSEnt && pSiS->DualHeadMode)  result = pSiSEnt->siscrt1satgain;
12632#endif
12633
12634   if(!(pSiS->SiS_SD3_Flags & SiS_SD3_CRT1SATGAIN)) return result;
12635
12636#ifdef UNLOCK_ALWAYS
12637   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
12638#endif
12639   inSISIDXREG(SISCR, 0x53, temp);
12640   return (int)((temp >> 2) & 0x07);
12641}
12642
12643/* Calc dotclock from registers */
12644static int
12645SiSGetClockFromRegs(UChar sr2b, UChar sr2c)
12646{
12647   float num, denum, postscalar, divider;
12648   int   myclock;
12649
12650   divider = (sr2b & 0x80) ? 2.0 : 1.0;
12651   postscalar = (sr2c & 0x80) ?
12652              ( (((sr2c >> 5) & 0x03) == 0x02) ? 6.0 : 8.0 ) :
12653	      ( ((sr2c >> 5) & 0x03) + 1.0 );
12654   num = (sr2b & 0x7f) + 1.0;
12655   denum = (sr2c & 0x1f) + 1.0;
12656   myclock = (int)((14318 * (divider / postscalar) * (num / denum)) / 1000);
12657   return myclock;
12658}
12659
12660#ifdef SISDUALHEAD
12661static void
12662SiS_SetDHFlags(SISPtr pSiS, unsigned int misc, unsigned int sd2)
12663{
12664   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12665
12666   if(pSiS->DualHeadMode) {
12667      if(pSiSEnt->pScrn_1) {
12668	 SISPTR(pSiSEnt->pScrn_1)->MiscFlags |= misc;
12669	 SISPTR(pSiSEnt->pScrn_1)->SiS_SD2_Flags |= sd2;
12670      }
12671      if(pSiSEnt->pScrn_2) {
12672	 SISPTR(pSiSEnt->pScrn_2)->MiscFlags |= misc;
12673	 SISPTR(pSiSEnt->pScrn_2)->SiS_SD2_Flags |= sd2;
12674      }
12675   }
12676}
12677#endif
12678
12679/* PostSetMode:
12680 * -) Disable CRT1 for saving bandwidth. This doesn't work with VESA;
12681 *    VESA uses the bridge in SlaveMode and switching CRT1 off while
12682 *    the bridge is in SlaveMode not that clever...
12683 * -) Check if overlay can be used (depending on dotclock)
12684 * -) Check if Panel Scaler is active on LVDS for overlay re-scaling
12685 * -) Save TV registers for further processing
12686 * -) Apply TV settings
12687 */
12688static void
12689SiSPostSetMode(ScrnInfoPtr pScrn, SISRegPtr sisReg)
12690{
12691    SISPtr pSiS = SISPTR(pScrn);
12692#ifdef SISDUALHEAD
12693    SISEntPtr pSiSEnt = pSiS->entityPrivate;
12694#endif
12695    UChar usScratchCR17, sr2b, sr2c, tmpreg;
12696    int   myclock1, myclock2, mycoldepth1, mycoldepth2, temp;
12697    Bool  flag = FALSE;
12698    Bool  doit = TRUE;
12699    Bool  IsInSlaveMode;
12700
12701#ifdef TWDEBUG
12702    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
12703    	"CRT1off is %d\n", pSiS->CRT1off);
12704#endif
12705    pSiS->CRT1isoff = pSiS->CRT1off;
12706
12707#ifdef UNLOCK_ALWAYS
12708    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
12709#endif
12710
12711    SiSFixupSR11(pScrn);
12712
12713    IsInSlaveMode = SiSBridgeIsInSlaveMode(pScrn);
12714
12715    if((!pSiS->UseVESA) && (pSiS->VBFlags & CRT2_ENABLE)) {
12716
12717	if(pSiS->VBFlags != pSiS->VBFlags_backup) {
12718	   pSiS->VBFlags = pSiS->VBFlags_backup;
12719	   xf86DrvMsg(pScrn->scrnIndex, X_INFO,
12720			"VBFlags restored to %0x\n", pSiS->VBFlags);
12721	}
12722
12723	/* -) We can't switch off CRT1 if bridge is in SlaveMode.
12724	 * -) If we change to a SlaveMode-Mode (like 512x384), we
12725	 *    need to adapt VBFlags for eg. Xv.
12726	 */
12727#ifdef SISDUALHEAD
12728	if(!pSiS->DualHeadMode) {
12729#endif
12730	   if(IsInSlaveMode) {
12731	      doit = FALSE;
12732	      temp = pSiS->VBFlags;
12733	      pSiS->VBFlags &= (~VB_DISPMODE_SINGLE);
12734	      pSiS->VBFlags |= (VB_DISPMODE_MIRROR | DISPTYPE_DISP1);
12735              if(temp != pSiS->VBFlags) {
12736		 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
12737		 	"VBFlags changed to 0x%0x\n", pSiS->VBFlags);
12738	      }
12739	   }
12740#ifdef SISDUALHEAD
12741	}
12742#endif
12743
12744	if(pSiS->VGAEngine == SIS_315_VGA) {
12745
12746	   if((pSiS->CRT1off) && (doit)) {
12747	      orSISIDXREG(SISCR,pSiS->myCR63,0x40);
12748	      orSISIDXREG(SISSR,0x1f,0xc0);
12749	      andSISIDXREG(SISSR,0x07,~0x10);
12750	      andSISIDXREG(SISSR,0x06,0xe2);
12751	      andSISIDXREG(SISSR,0x31,0xcf);
12752	      outSISIDXREG(SISSR,0x2b,0x1b);
12753	      outSISIDXREG(SISSR,0x2c,0xe1);
12754	      outSISIDXREG(SISSR,0x2d,0x01);
12755	      outSISIDXREG(SISSR, 0x00, 0x01);    /* Synchronous Reset */
12756	      usleep(10000);
12757	      outSISIDXREG(SISSR, 0x00, 0x03);    /* End Reset */
12758	   } else {
12759	      andSISIDXREG(SISCR,pSiS->myCR63,0xBF);
12760	      andSISIDXREG(SISSR,0x1f,0x3f);
12761	      orSISIDXREG(SISSR,0x07,0x10);
12762	   }
12763
12764	} else {
12765
12766	   if(doit) {
12767	      inSISIDXREG(SISCR, 0x17, usScratchCR17);
12768	      if(pSiS->CRT1off) {
12769		 if(usScratchCR17 & 0x80) {
12770		    flag = TRUE;
12771		    usScratchCR17 &= ~0x80;
12772		 }
12773		 orSISIDXREG(SISSR,0x1f,0xc0);
12774	      } else {
12775		 if(!(usScratchCR17 & 0x80)) {
12776		    flag = TRUE;
12777		    usScratchCR17 |= 0x80;
12778		 }
12779		 andSISIDXREG(SISSR,0x1f,0x3f);
12780	      }
12781	      /* Reset only if status changed */
12782	      if(flag) {
12783		 outSISIDXREG(SISCR, 0x17, usScratchCR17);
12784		 outSISIDXREG(SISSR, 0x00, 0x01);    /* Synchronous Reset */
12785		 usleep(10000);
12786		 outSISIDXREG(SISSR, 0x00, 0x03);    /* End Reset */
12787	      }
12788	   }
12789	}
12790
12791    }
12792
12793    /* Set bridge to "disable CRT2" mode if CRT2 is disabled, LCD-A is enabled */
12794    /* (Not needed for CRT1=VGA since CRT2 will really be disabled then) */
12795#ifdef SISDUALHEAD
12796    if(!pSiS->DualHeadMode) {
12797#endif
12798       if((pSiS->VGAEngine == SIS_315_VGA)  && (pSiS->VBFlags2 & VB2_SISLCDABRIDGE)) {
12799	  if((!pSiS->UseVESA) && (!(pSiS->VBFlags & CRT2_ENABLE)) && (pSiS->VBFlags & CRT1_LCDA)) {
12800	     if(!IsInSlaveMode) {
12801	        andSISIDXREG(SISPART4,0x0d,~0x07);
12802	     }
12803	  }
12804       }
12805#ifdef SISDUALHEAD
12806    }
12807#endif
12808
12809    /* Reset flags */
12810    pSiS->MiscFlags &= ~( MISC_CRT1OVERLAY      |
12811			  MISC_CRT2OVERLAY      |
12812			  MISC_CRT1OVERLAYGAMMA |
12813			  MISC_SIS760ONEOVERLAY |
12814			  MISC_PANELLINKSCALER  |
12815			  MISC_STNMODE		|
12816			  MISC_TVNTSC1024);
12817
12818    pSiS->SiS_SD2_Flags &= ~SiS_SD2_SIS760ONEOVL;
12819
12820#ifdef SISDUALHEAD
12821    if(pSiS->DualHeadMode) {
12822       if(pSiSEnt->pScrn_1) {
12823	  SISPTR(pSiSEnt->pScrn_1)->MiscFlags &= ~(MISC_SIS760ONEOVERLAY	|
12824						   MISC_CRT1OVERLAY		|
12825						   MISC_CRT2OVERLAY		|
12826						   MISC_CRT1OVERLAYGAMMA	|
12827						   MISC_PANELLINKSCALER		|
12828						   MISC_STNMODE			|
12829						   MISC_TVNTSC1024);
12830	  SISPTR(pSiSEnt->pScrn_1)->SiS_SD2_Flags &= ~SiS_SD2_SIS760ONEOVL;
12831       }
12832       if(pSiSEnt->pScrn_2) {
12833	  SISPTR(pSiSEnt->pScrn_2)->MiscFlags &= ~(MISC_SIS760ONEOVERLAY	|
12834						   MISC_CRT1OVERLAY		|
12835						   MISC_CRT2OVERLAY		|
12836						   MISC_CRT1OVERLAYGAMMA	|
12837						   MISC_PANELLINKSCALER		|
12838						   MISC_STNMODE			|
12839						   MISC_TVNTSC1024);
12840	  SISPTR(pSiSEnt->pScrn_2)->SiS_SD2_Flags &= ~SiS_SD2_SIS760ONEOVL;
12841       }
12842    }
12843#endif
12844
12845    /* Determine if the video overlay can be used */
12846    if(!pSiS->NoXvideo) {
12847
12848       int clklimit1=0, clklimit2=0, clklimitg=0;
12849       Bool OverlayHandled = FALSE;
12850
12851       inSISIDXREG(SISSR,0x2b,sr2b);
12852       inSISIDXREG(SISSR,0x2c,sr2c);
12853       myclock1 = myclock2 = SiSGetClockFromRegs(sr2b, sr2c);
12854       inSISIDXREG(SISSR,0x06,tmpreg);
12855       switch((tmpreg & 0x1c) >> 2) {
12856       case 0:  mycoldepth1 = 1; break;
12857       case 1:
12858       case 2:  mycoldepth1 = 2; break;
12859       default: mycoldepth1 = 4;
12860       }
12861       mycoldepth2 = mycoldepth1;
12862
12863       if((!IsInSlaveMode) && (pSiS->VBFlags & CRT2_ENABLE)) {
12864	  if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
12865	     inSISIDXREG(SISPART4,0x0a,sr2b);
12866	     inSISIDXREG(SISPART4,0x0b,sr2c);
12867	  } else {
12868	     inSISIDXREG(SISSR,0x2e,sr2b);
12869	     inSISIDXREG(SISSR,0x2f,sr2c);
12870	  }
12871	  myclock2 = SiSGetClockFromRegs(sr2b, sr2c);
12872	  inSISIDXREG(SISPART1,0x00,tmpreg);
12873	  tmpreg &= 0x0f;
12874	  switch(tmpreg) {
12875	  case 8:  mycoldepth2 = 1; break;
12876	  case 4:
12877	  case 2:  mycoldepth2 = 2; break;
12878	  default: mycoldepth2 = 4;
12879	  }
12880       }
12881
12882       switch(pSiS->ChipType) {
12883
12884	 case SIS_300:
12885	 case SIS_540:
12886	 case SIS_630:
12887	 case SIS_730:
12888	    clklimit1 = clklimit2 = clklimitg = 150;
12889	    break;
12890
12891	 case SIS_550:
12892	 case SIS_650:
12893	 case SIS_740:
12894	    clklimit1 = clklimit2 = 175;  /* verified for 65x */
12895	    clklimitg = 166;		  /* ? */
12896	    break;
12897
12898	 case SIS_661:
12899	 case SIS_741:
12900	    clklimit1 = clklimit2 = 190;  /* ? */
12901	    clklimitg = 180;		  /* ? */
12902	    break;
12903
12904	 case SIS_760:
12905	 case SIS_761:
12906	    clklimit1 = clklimit2 = 190;    /* ? */
12907	    if(pSiS->ChipFlags & SiSCF_760LFB) {		/* LFB only or hybrid */
12908	       clklimit1 = clklimit2 = 220; /* ? */
12909	    }
12910	    clklimitg = 200;		    /* ? */
12911
12912	    if(pSiS->SiS_SD2_Flags & SiS_SD2_SUPPORT760OO) {	/* UMA only */
12913
12914	       Bool OnlyOne = FALSE, NoOverlay = FALSE;
12915	       int dotclocksum = 0;
12916
12917	       if(pSiS->VBFlags & DISPTYPE_CRT1)                     dotclocksum += myclock1;
12918	       if((!IsInSlaveMode) && (pSiS->VBFlags & CRT2_ENABLE)) dotclocksum += myclock2;
12919
12920	       /* TODO: Find out under what circumstances only one
12921		*	overlay is usable in UMA-only mode.
12922		*	This is not entirely accurate; the overlay
12923		*	scaler also requires some time, so even though
12924		*	the dotclocks are below these values, some
12925		*	distortions in the overlay may occure.
12926		*	Solution: Don't use a 760 with shared memory.
12927		*/
12928	       if( (pSiS->VBFlags & DISPTYPE_CRT1) &&
12929		   (pSiS->VBFlags & CRT2_ENABLE) &&
12930		   (mycoldepth1 != mycoldepth2) ) {
12931
12932		  /* 0. If coldepths are different (only possible in dual head mode),
12933		   *    I have no idea to calculate the limits; hence, allow only one
12934		   *    overlay in all cases.
12935		   */
12936		  OnlyOne = TRUE;
12937
12938	       } else if(pSiS->MemClock < 150000) {
12939
12940		  /* 1. MCLK <150: If someone seriously considers using such
12941		   *    slow RAM, so be it. Only one overlay in call cases.
12942		   */
12943		  OnlyOne = TRUE;
12944
12945	       } else if(pSiS->MemClock < 170000) {
12946
12947		  /* 2. MCLK 166 */
12948		  switch(pSiS->CurrentLayout.bitsPerPixel) {
12949		     case 32: if(dotclocksum > 133) OnlyOne = TRUE;		/* One overlay; verified */
12950			      if(dotclocksum > 180) NoOverlay = TRUE;		/* No overlay; verified */
12951			      break;
12952		     case 16: if(dotclocksum > 175) OnlyOne = TRUE;		/* One overlay; verified */
12953			      if(dotclocksum > 260) NoOverlay = TRUE;;		/* No overlay; FIXME */
12954			      break;
12955		  }
12956
12957	       } else if(pSiS->MemClock < 210000) {
12958
12959		  /* 3. MCLK 200 */
12960		  switch(pSiS->CurrentLayout.bitsPerPixel) {
12961		     case 32: if(dotclocksum > 160) OnlyOne = TRUE;		/* One overlay; FIXME */
12962			      if(dotclocksum > 216) NoOverlay = TRUE;;		/* No overlay; FIXME */
12963			      break;
12964		     case 16: if(dotclocksum > 210) OnlyOne = TRUE;		/* One overlay; FIXME */
12965			      if(dotclocksum > 312) NoOverlay = TRUE;;		/* No overlay; FIXME */
12966			      break;
12967		  }
12968
12969	       }
12970
12971	       if(OnlyOne || NoOverlay) {
12972
12973		  ULong tmpflags = 0;
12974
12975		  if(!NoOverlay) {
12976		     if(myclock1 <= clklimit1) tmpflags |= MISC_CRT1OVERLAY;
12977		     if(myclock2 <= clklimit2) tmpflags |= MISC_CRT2OVERLAY;
12978		     if(myclock1 <= clklimitg) tmpflags |= MISC_CRT1OVERLAYGAMMA;
12979		     pSiS->MiscFlags |= tmpflags;
12980		  }
12981		  pSiS->MiscFlags |= MISC_SIS760ONEOVERLAY;
12982		  pSiS->SiS_SD2_Flags |= SiS_SD2_SIS760ONEOVL;
12983#ifdef SISDUALHEAD
12984		  SiS_SetDHFlags(pSiS, (tmpflags | MISC_SIS760ONEOVERLAY), SiS_SD2_SIS760ONEOVL);
12985#endif
12986		  OverlayHandled = TRUE;
12987	       }
12988
12989	       xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
12990			"SiS76x/UMA: %s video overlay(s) available in current mode\n",
12991			NoOverlay ? "no" : ((pSiS->MiscFlags & MISC_SIS760ONEOVERLAY) ? "one" : "two"));
12992
12993#ifdef TWDEBUG
12994	       xf86DrvMsg(0, 0, "SiS760: Memclock %d, c1 %d/%d c2 %d/%d, sum %d / %x\n",
12995			pSiS->MemClock, myclock1, mycoldepth1,
12996			myclock2, mycoldepth2, dotclocksum, pSiS->SiS_SD2_Flags);
12997#endif
12998	    }
12999	    break;
13000
13001	 case SIS_660:
13002	    clklimit1 = clklimit2 = 200;  /* ? */
13003	    if(pSiS->ChipFlags & SiSCF_760LFB) {		/* LFB only */
13004	       clklimit1 = clklimit2 = 220;
13005	    }
13006	    clklimitg = 200;		  /* ? */
13007	    break;
13008
13009	 case SIS_315H:
13010	 case SIS_315:
13011	 case SIS_315PRO:
13012	 case SIS_330:
13013	    clklimit1 = clklimit2 = 180;  /* ? */
13014	    clklimitg = 166;		  /* ? */
13015	    break;
13016
13017	 case SIS_340: /* ? */
13018	 case XGI_20:
13019	 case XGI_40:
13020	    clklimit1 = clklimit2 = 240;  /* ? */
13021	    clklimitg = 200;		  /* ? */
13022	    break;
13023       }
13024
13025       if(!OverlayHandled) {
13026          ULong tmpflags = 0;
13027          if(myclock1 <= clklimit1) tmpflags |= MISC_CRT1OVERLAY;
13028          if(myclock2 <= clklimit2) tmpflags |= MISC_CRT2OVERLAY;
13029          if(myclock1 <= clklimitg) tmpflags |= MISC_CRT1OVERLAYGAMMA;
13030	  pSiS->MiscFlags |= tmpflags;
13031#ifdef SISDUALHEAD
13032	  SiS_SetDHFlags(pSiS, tmpflags, 0);
13033#endif
13034          if(!(pSiS->MiscFlags & MISC_CRT1OVERLAY)) {
13035#ifdef SISDUALHEAD
13036             if((!pSiS->DualHeadMode) || (pSiS->SecondHead))
13037#endif
13038		xf86DrvMsgVerb(pScrn->scrnIndex, X_WARNING, 3,
13039		   "Current dotclock (%dMhz) too high for video overlay on CRT1\n",
13040		   myclock1);
13041          }
13042          if((pSiS->VBFlags & CRT2_ENABLE) && (!(pSiS->MiscFlags & MISC_CRT2OVERLAY))) {
13043#ifdef SISDUALHEAD
13044	     if((!pSiS->DualHeadMode) || (!pSiS->SecondHead))
13045#endif
13046		xf86DrvMsgVerb(pScrn->scrnIndex, X_WARNING, 3,
13047		   "Current dotclock (%dMhz) too high for video overlay on CRT2\n",
13048		   myclock2);
13049	  }
13050       }
13051
13052    }
13053
13054    /* Determine if the Panel Link scaler is active */
13055
13056    if(pSiS->VBFlags & (CRT2_LCD | CRT1_LCDA)) {
13057       ULong tmpflags = 0;
13058       if(pSiS->VGAEngine == SIS_300_VGA) {
13059	  if(pSiS->VBFlags2 & (VB2_LVDS | VB2_30xBDH)) {
13060	     inSISIDXREG(SISPART1,0x1e,tmpreg);
13061	     tmpreg &= 0x3f;
13062	     if(tmpreg) tmpflags |= MISC_PANELLINKSCALER;
13063	  }
13064       } else {
13065	  if((pSiS->VBFlags2 & (VB2_LVDS | VB2_30xBDH)) || (pSiS->VBFlags & CRT1_LCDA)) {
13066	     inSISIDXREG(SISPART1,0x35,tmpreg);
13067	     tmpreg &= 0x04;
13068	     if(!tmpreg)  tmpflags |= MISC_PANELLINKSCALER;
13069	  }
13070       }
13071       pSiS->MiscFlags |= tmpflags;
13072#ifdef SISDUALHEAD
13073       SiS_SetDHFlags(pSiS, tmpflags, 0);
13074#endif
13075    }
13076
13077    /* Determine if STN is active */
13078    if(pSiS->ChipType == SIS_550) {
13079       if((pSiS->VBFlags & CRT2_LCD) && (pSiS->FSTN || pSiS->DSTN)) {
13080	  inSISIDXREG(SISCR,0x34,tmpreg);
13081	  tmpreg &= 0x7f;
13082	  if(tmpreg == 0x5a || tmpreg == 0x5b) {
13083	     pSiS->MiscFlags |= MISC_STNMODE;
13084#ifdef SISDUALHEAD
13085	     SiS_SetDHFlags(pSiS, MISC_STNMODE, 0);
13086#endif
13087	  }
13088       }
13089    }
13090
13091    /* Determine if our very special TV mode is active */
13092    if((pSiS->VBFlags2 & VB2_SISBRIDGE) && (pSiS->VBFlags & CRT2_TV) && (!(pSiS->VBFlags & TV_HIVISION))) {
13093       if( ((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR525I)) ||
13094	   ((!(pSiS->VBFlags & TV_YPBPR)) && (pSiS->VBFlags & (TV_NTSC | TV_PALM))) ) {
13095	  inSISIDXREG(SISCR,0x34,tmpreg);
13096	  tmpreg &= 0x7f;
13097	  if((tmpreg == 0x64) || (tmpreg == 0x4a) || (tmpreg == 0x38)) {
13098	     pSiS->MiscFlags |= MISC_TVNTSC1024;
13099#ifdef SISDUALHEAD
13100	     SiS_SetDHFlags(pSiS, MISC_TVNTSC1024, 0);
13101#endif
13102	  }
13103       }
13104    }
13105
13106    if(pSiS->VGAEngine == SIS_315_VGA) {
13107       int i;
13108#ifdef SISVRAMQ
13109       /* Re-Enable and reset command queue */
13110       SiSEnableTurboQueue(pScrn);
13111#endif
13112       /* Get HWCursor register contents for backup */
13113       for(i = 0; i < 16; i++) {
13114          pSiS->HWCursorBackup[i] = SIS_MMIO_IN32(pSiS->IOBase, 0x8500 + (i << 2));
13115       }
13116       if(pSiS->ChipType >= SIS_330) {
13117          /* Enable HWCursor protection (Y pos as trigger) */
13118          andSISIDXREG(SISCR, 0x5b, ~0x30);
13119       }
13120    }
13121
13122    /* Re-initialize accelerator engine */
13123    /* (We are sync'ed here) */
13124    if(!pSiS->NoAccel) {
13125       if(pSiS->InitAccel) {
13126          (pSiS->InitAccel)(pScrn);
13127       }
13128    }
13129
13130    /* Set display device gamma (for SISCTRL) */
13131    if(pSiS->VBFlags & CRT1_LCDA)
13132       pSiS->CRT1MonGamma = pSiS->CRT2LCDMonitorGamma;
13133    else
13134       pSiS->CRT1MonGamma = pSiS->CRT1VGAMonitorGamma;
13135
13136    if(pSiS->VBFlags & CRT2_LCD)
13137       pSiS->CRT2MonGamma = pSiS->CRT2LCDMonitorGamma;
13138    else if(pSiS->VBFlags & CRT2_TV) {
13139       if(pSiS->VBFlags & TV_YPBPR)
13140          pSiS->CRT2MonGamma = 2200; /* */
13141       else if(pSiS->VBFlags & TV_HIVISION)
13142          pSiS->CRT2MonGamma = 2200; /* ? */
13143       else if(pSiS->VBFlags & TV_NTSC)
13144          pSiS->CRT2MonGamma = 2200; /* NTSC */
13145       else
13146          pSiS->CRT2MonGamma = 2800; /* All PAL modes? */
13147    } else if(pSiS->VBFlags & CRT2_VGA)
13148       pSiS->CRT2MonGamma = pSiS->CRT2VGAMonitorGamma;
13149    else
13150       pSiS->CRT2MonGamma = 0; /* Unknown */
13151
13152    /* Reset XV display properties (such as number of overlays, etc) */
13153    /* (And copy monitor gamma) */
13154#ifdef SISDUALHEAD
13155    if(pSiS->DualHeadMode) {
13156       if(pSiSEnt->pScrn_1) {
13157	  if(SISPTR(pSiSEnt->pScrn_1)->ResetXvDisplay) {
13158	     (SISPTR(pSiSEnt->pScrn_1)->ResetXvDisplay)(pSiSEnt->pScrn_1);
13159	  }
13160	  SISPTR(pSiSEnt->pScrn_1)->CRT1MonGamma = pSiS->CRT1MonGamma;
13161	  SISPTR(pSiSEnt->pScrn_1)->CRT2MonGamma = pSiS->CRT2MonGamma;
13162       }
13163       if(pSiSEnt->pScrn_2) {
13164	  if(SISPTR(pSiSEnt->pScrn_2)->ResetXvDisplay) {
13165	     (SISPTR(pSiSEnt->pScrn_1)->ResetXvDisplay)(pSiSEnt->pScrn_2);
13166	  }
13167	  SISPTR(pSiSEnt->pScrn_2)->CRT1MonGamma = pSiS->CRT1MonGamma;
13168	  SISPTR(pSiSEnt->pScrn_2)->CRT2MonGamma = pSiS->CRT2MonGamma;
13169       }
13170    } else {
13171#endif
13172       if(pSiS->ResetXvDisplay) {
13173	  (pSiS->ResetXvDisplay)(pScrn);
13174       }
13175#ifdef SISDUALHEAD
13176    }
13177#endif
13178
13179    /* Reset XV gamma correction */
13180    if(pSiS->ResetXvGamma) {
13181       (pSiS->ResetXvGamma)(pScrn);
13182    }
13183
13184    /* Reset various display parameters */
13185    {
13186       int val = pSiS->siscrt1satgain;
13187#ifdef SISDUALHEAD
13188       if(pSiS->DualHeadMode && pSiSEnt) val = pSiSEnt->siscrt1satgain;
13189#endif
13190       SiS_SetSISCRT1SaturationGain(pScrn, val);
13191    }
13192
13193    /*  Apply TV settings given by options
13194           Do this even in DualHeadMode:
13195	   - if this is called by SetModeCRT1, CRT2 mode has been reset by SetModeCRT1
13196	   - if this is called by SetModeCRT2, CRT2 mode has changed (duh!)
13197	   -> Hence, in both cases, the settings must be re-applied.
13198     */
13199
13200    if(pSiS->VBFlags & CRT2_TV) {
13201       int val;
13202       if(pSiS->VBFlags2 & VB2_CHRONTEL) {
13203	  int mychtvlumabandwidthcvbs = pSiS->chtvlumabandwidthcvbs;
13204	  int mychtvlumabandwidthsvideo = pSiS->chtvlumabandwidthsvideo;
13205	  int mychtvlumaflickerfilter = pSiS->chtvlumaflickerfilter;
13206	  int mychtvchromabandwidth = pSiS->chtvchromabandwidth;
13207	  int mychtvchromaflickerfilter = pSiS->chtvchromaflickerfilter;
13208	  int mychtvcvbscolor = pSiS->chtvcvbscolor;
13209	  int mychtvtextenhance = pSiS->chtvtextenhance;
13210	  int mychtvcontrast = pSiS->chtvcontrast;
13211	  int mytvxpos = pSiS->tvxpos;
13212	  int mytvypos = pSiS->tvypos;
13213#ifdef SISDUALHEAD
13214	  if(pSiSEnt && pSiS->DualHeadMode) {
13215	     mychtvlumabandwidthcvbs = pSiSEnt->chtvlumabandwidthcvbs;
13216	     mychtvlumabandwidthsvideo = pSiSEnt->chtvlumabandwidthsvideo;
13217	     mychtvlumaflickerfilter = pSiSEnt->chtvlumaflickerfilter;
13218	     mychtvchromabandwidth = pSiSEnt->chtvchromabandwidth;
13219	     mychtvchromaflickerfilter = pSiSEnt->chtvchromaflickerfilter;
13220	     mychtvcvbscolor = pSiSEnt->chtvcvbscolor;
13221	     mychtvtextenhance = pSiSEnt->chtvtextenhance;
13222	     mychtvcontrast = pSiSEnt->chtvcontrast;
13223	     mytvxpos = pSiSEnt->tvxpos;
13224	     mytvypos = pSiSEnt->tvypos;
13225	  }
13226#endif
13227	  if((val = mychtvlumabandwidthcvbs) != -1) {
13228	     SiS_SetCHTVlumabandwidthcvbs(pScrn, val);
13229	  }
13230	  if((val = mychtvlumabandwidthsvideo) != -1) {
13231	     SiS_SetCHTVlumabandwidthsvideo(pScrn, val);
13232	  }
13233	  if((val = mychtvlumaflickerfilter) != -1) {
13234	     SiS_SetCHTVlumaflickerfilter(pScrn, val);
13235	  }
13236	  if((val = mychtvchromabandwidth) != -1) {
13237	     SiS_SetCHTVchromabandwidth(pScrn, val);
13238	  }
13239	  if((val = mychtvchromaflickerfilter) != -1) {
13240	     SiS_SetCHTVchromaflickerfilter(pScrn, val);
13241	  }
13242	  if((val = mychtvcvbscolor) != -1) {
13243	     SiS_SetCHTVcvbscolor(pScrn, val);
13244	  }
13245	  if((val = mychtvtextenhance) != -1) {
13246	     SiS_SetCHTVtextenhance(pScrn, val);
13247	  }
13248	  if((val = mychtvcontrast) != -1) {
13249	     SiS_SetCHTVcontrast(pScrn, val);
13250	  }
13251	  /* Backup default TV position registers */
13252	  switch(pSiS->ChrontelType) {
13253	  case CHRONTEL_700x:
13254	     pSiS->tvx = SiS_GetCH700x(pSiS->SiS_Pr, 0x0a);
13255	     pSiS->tvx |= (((SiS_GetCH700x(pSiS->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
13256	     pSiS->tvy = SiS_GetCH700x(pSiS->SiS_Pr, 0x0b);
13257	     pSiS->tvy |= ((SiS_GetCH700x(pSiS->SiS_Pr, 0x08) & 0x01) << 8);
13258#ifdef SISDUALHEAD
13259	     if(pSiSEnt) {
13260		pSiSEnt->tvx = pSiS->tvx;
13261		pSiSEnt->tvy = pSiS->tvy;
13262	     }
13263#endif
13264	     break;
13265	  case CHRONTEL_701x:
13266	     /* Not supported by hardware */
13267	     break;
13268	  }
13269	  if((val = mytvxpos) != 0) {
13270	     SiS_SetTVxposoffset(pScrn, val);
13271	  }
13272	  if((val = mytvypos) != 0) {
13273	     SiS_SetTVyposoffset(pScrn, val);
13274	  }
13275       }
13276       if(pSiS->VBFlags2 & VB2_301) {
13277          int mysistvedgeenhance = pSiS->sistvedgeenhance;
13278#ifdef SISDUALHEAD
13279          if(pSiSEnt && pSiS->DualHeadMode) {
13280	     mysistvedgeenhance = pSiSEnt->sistvedgeenhance;
13281	  }
13282#endif
13283          if((val = mysistvedgeenhance) != -1) {
13284	     SiS_SetSISTVedgeenhance(pScrn, val);
13285	  }
13286       }
13287       if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
13288          int mysistvantiflicker = pSiS->sistvantiflicker;
13289	  int mysistvsaturation = pSiS->sistvsaturation;
13290	  int mysistvcolcalibf = pSiS->sistvcolcalibf;
13291	  int mysistvcolcalibc = pSiS->sistvcolcalibc;
13292	  int mysistvcfilter = pSiS->sistvcfilter;
13293	  int mysistvyfilter = pSiS->sistvyfilter;
13294	  int mytvxpos = pSiS->tvxpos;
13295	  int mytvypos = pSiS->tvypos;
13296	  int mytvxscale = pSiS->tvxscale;
13297	  int mytvyscale = pSiS->tvyscale;
13298	  int i;
13299	  ULong cbase;
13300	  UChar ctemp;
13301#ifdef SISDUALHEAD
13302          if(pSiSEnt && pSiS->DualHeadMode) {
13303	     mysistvantiflicker = pSiSEnt->sistvantiflicker;
13304	     mysistvsaturation = pSiSEnt->sistvsaturation;
13305	     mysistvcolcalibf = pSiSEnt->sistvcolcalibf;
13306	     mysistvcolcalibc = pSiSEnt->sistvcolcalibc;
13307	     mysistvcfilter = pSiSEnt->sistvcfilter;
13308	     mysistvyfilter = pSiSEnt->sistvyfilter;
13309	     mytvxpos = pSiSEnt->tvxpos;
13310	     mytvypos = pSiSEnt->tvypos;
13311	     mytvxscale = pSiSEnt->tvxscale;
13312	     mytvyscale = pSiSEnt->tvyscale;
13313	  }
13314#endif
13315          /* Backup default TV position, scale and colcalib registers */
13316	  inSISIDXREG(SISPART2,0x1f,pSiS->p2_1f);
13317	  inSISIDXREG(SISPART2,0x20,pSiS->p2_20);
13318	  inSISIDXREG(SISPART2,0x2b,pSiS->p2_2b);
13319	  inSISIDXREG(SISPART2,0x42,pSiS->p2_42);
13320	  inSISIDXREG(SISPART2,0x43,pSiS->p2_43);
13321	  inSISIDXREG(SISPART2,0x01,pSiS->p2_01);
13322	  inSISIDXREG(SISPART2,0x02,pSiS->p2_02);
13323	  inSISIDXREG(SISPART2,0x44,pSiS->p2_44);
13324	  inSISIDXREG(SISPART2,0x45,pSiS->p2_45);
13325	  if(!(pSiS->VBFlags2 & VB2_301)) {
13326	     inSISIDXREG(SISPART2,0x46,pSiS->p2_46);
13327	  } else {
13328	     pSiS->p2_46 = 0;
13329	  }
13330	  inSISIDXREG(SISPART2,0x0a,pSiS->p2_0a);
13331	  inSISIDXREG(SISPART2,0x31,cbase);
13332	  cbase = (cbase & 0x7f) << 8;
13333	  inSISIDXREG(SISPART2,0x32,ctemp);
13334	  cbase = (cbase | ctemp) << 8;
13335	  inSISIDXREG(SISPART2,0x33,ctemp);
13336	  cbase = (cbase | ctemp) << 8;
13337	  inSISIDXREG(SISPART2,0x34,ctemp);
13338	  pSiS->sistvccbase = (cbase | ctemp);
13339	  inSISIDXREG(SISPART2,0x35,pSiS->p2_35);
13340	  inSISIDXREG(SISPART2,0x36,pSiS->p2_36);
13341	  inSISIDXREG(SISPART2,0x37,pSiS->p2_37);
13342	  inSISIDXREG(SISPART2,0x38,pSiS->p2_38);
13343	  if(!(pSiS->VBFlags2 & VB2_301)) {
13344	     inSISIDXREG(SISPART2,0x47,pSiS->p2_47);
13345	     inSISIDXREG(SISPART2,0x48,pSiS->p2_48);
13346	     inSISIDXREG(SISPART2,0x49,pSiS->p2_49);
13347	     inSISIDXREG(SISPART2,0x4a,pSiS->p2_4a);
13348	  }
13349	  inSISIDXREG(SISPART2,0x2f,pSiS->p2_2f);
13350	  inSISIDXREG(SISPART2,0x30,pSiS->p2_30);
13351	  for(i=0; i<9; i++) {
13352	     inSISIDXREG(SISPART1,SiSScalingP1Regs[i],pSiS->scalingp1[i]);
13353	  }
13354	  for(i=0; i<9; i++) {
13355	     inSISIDXREG(SISPART4,SiSScalingP4Regs[i],pSiS->scalingp4[i]);
13356	  }
13357	  if(pSiS->VBFlags2 & VB2_SISTAP4SCALER) {
13358	     for(i=0; i<64; i++) {
13359	        inSISIDXREG(SISPART2,(0xc0 + i),pSiS->scalingp2[i]);
13360  	     }
13361	  }
13362#ifdef SISDUALHEAD
13363	  if(pSiSEnt) {
13364	     pSiSEnt->p2_1f = pSiS->p2_1f; pSiSEnt->p2_20 = pSiS->p2_20;
13365	     pSiSEnt->p2_42 = pSiS->p2_42; pSiSEnt->p2_43 = pSiS->p2_43;
13366	     pSiSEnt->p2_2b = pSiS->p2_2b;
13367	     pSiSEnt->p2_01 = pSiS->p2_01; pSiSEnt->p2_02 = pSiS->p2_02;
13368	     pSiSEnt->p2_44 = pSiS->p2_44; pSiSEnt->p2_45 = pSiS->p2_45;
13369	     pSiSEnt->p2_46 = pSiS->p2_46; pSiSEnt->p2_0a = pSiS->p2_0a;
13370	     pSiSEnt->sistvccbase = pSiS->sistvccbase;
13371	     pSiSEnt->p2_35 = pSiS->p2_35; pSiSEnt->p2_36 = pSiS->p2_36;
13372	     pSiSEnt->p2_37 = pSiS->p2_37; pSiSEnt->p2_38 = pSiS->p2_38;
13373	     pSiSEnt->p2_48 = pSiS->p2_48; pSiSEnt->p2_49 = pSiS->p2_49;
13374	     pSiSEnt->p2_4a = pSiS->p2_4a; pSiSEnt->p2_2f = pSiS->p2_2f;
13375	     pSiSEnt->p2_30 = pSiS->p2_30; pSiSEnt->p2_47 = pSiS->p2_47;
13376	     for(i=0; i<9; i++) {
13377	        pSiSEnt->scalingp1[i] = pSiS->scalingp1[i];
13378	     }
13379	     for(i=0; i<9; i++) {
13380	        pSiSEnt->scalingp4[i] = pSiS->scalingp4[i];
13381	     }
13382	     if(pSiS->VBFlags2 & VB2_SISTAP4SCALER) {
13383	        for(i=0; i<64; i++) {
13384	           pSiSEnt->scalingp2[i] = pSiS->scalingp2[i];
13385  	        }
13386	     }
13387	  }
13388#endif
13389          if((val = mysistvantiflicker) != -1) {
13390	     SiS_SetSISTVantiflicker(pScrn, val);
13391	  }
13392	  if((val = mysistvsaturation) != -1) {
13393	     SiS_SetSISTVsaturation(pScrn, val);
13394	  }
13395	  if((val = mysistvcfilter) != -1) {
13396	     SiS_SetSISTVcfilter(pScrn, val);
13397	  }
13398	  if((val = mysistvyfilter) != 1) {
13399	     SiS_SetSISTVyfilter(pScrn, val);
13400	  }
13401	  if((val = mysistvcolcalibc) != 0) {
13402	     SiS_SetSISTVcolcalib(pScrn, val, TRUE);
13403	  }
13404	  if((val = mysistvcolcalibf) != 0) {
13405	     SiS_SetSISTVcolcalib(pScrn, val, FALSE);
13406	  }
13407	  if((val = mytvxpos) != 0) {
13408	     SiS_SetTVxposoffset(pScrn, val);
13409	  }
13410	  if((val = mytvypos) != 0) {
13411	     SiS_SetTVyposoffset(pScrn, val);
13412	  }
13413	  if((val = mytvxscale) != 0) {
13414	     SiS_SetTVxscale(pScrn, val);
13415	  }
13416	  if((val = mytvyscale) != 0) {
13417	     SiS_SetTVyscale(pScrn, val);
13418	  }
13419       }
13420    }
13421
13422}
13423
13424/* Post-set SiS6326 TV registers */
13425static void
13426SiS6326PostSetMode(ScrnInfoPtr pScrn, SISRegPtr sisReg)
13427{
13428    SISPtr pSiS = SISPTR(pScrn);
13429    UChar tmp;
13430    int val;
13431
13432    if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) return;
13433
13434#ifdef UNLOCK_ALWAYS
13435    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
13436#endif
13437
13438    /* Backup default TV position registers */
13439    pSiS->tvx1 = SiS6326GetTVReg(pScrn,0x3a);
13440    pSiS->tvx1 |= ((SiS6326GetTVReg(pScrn,0x3c) & 0x0f) << 8);
13441    pSiS->tvx2 = SiS6326GetTVReg(pScrn,0x26);
13442    pSiS->tvx2 |= ((SiS6326GetTVReg(pScrn,0x27) & 0xf0) << 4);
13443    pSiS->tvx3 = SiS6326GetTVReg(pScrn,0x12);
13444    pSiS->tvx3 |= ((SiS6326GetTVReg(pScrn,0x13) & 0xC0) << 2);
13445    pSiS->tvy1 = SiS6326GetTVReg(pScrn,0x11);
13446    pSiS->tvy1 |= ((SiS6326GetTVReg(pScrn,0x13) & 0x30) << 4);
13447
13448    /* Handle TVPosOffset options (BEFORE switching on TV) */
13449    if((val = pSiS->tvxpos) != 0) {
13450       SiS_SetTVxposoffset(pScrn, val);
13451    }
13452    if((val = pSiS->tvypos) != 0) {
13453       SiS_SetTVyposoffset(pScrn, val);
13454    }
13455
13456    /* Switch on TV output. This is rather complicated, but
13457     * if we don't do it, TV output will flicker terribly.
13458     */
13459    if(pSiS->SiS6326Flags & SIS6326_TVON) {
13460       orSISIDXREG(SISSR, 0x01, 0x20);
13461       tmp = SiS6326GetTVReg(pScrn,0x00);
13462       tmp &= ~0x04;
13463       while(!(inSISREG(SISINPSTAT) & 0x08));    /* Wait while NOT vb */
13464       SiS6326SetTVReg(pScrn,0x00,tmp);
13465       for(val=0; val < 2; val++) {
13466         while(!(inSISREG(SISINPSTAT) & 0x08));  /* Wait while NOT vb */
13467         while(inSISREG(SISINPSTAT) & 0x08);     /* wait while vb     */
13468       }
13469       SiS6326SetTVReg(pScrn, 0x00, sisReg->sis6326tv[0]);
13470       tmp = inSISREG(SISINPSTAT);
13471       outSISREG(SISAR, 0x20);
13472       tmp = inSISREG(SISINPSTAT);
13473       while(inSISREG(SISINPSTAT) & 0x01);
13474       while(!(inSISREG(SISINPSTAT) & 0x01));
13475       andSISIDXREG(SISSR, 0x01, ~0x20);
13476       for(val=0; val < 10; val++) {
13477         while(!(inSISREG(SISINPSTAT) & 0x08));  /* Wait while NOT vb */
13478         while(inSISREG(SISINPSTAT) & 0x08);     /* wait while vb     */
13479       }
13480       andSISIDXREG(SISSR, 0x01, ~0x20);
13481    }
13482
13483    tmp = SiS6326GetTVReg(pScrn,0x00);
13484    if(!(tmp & 0x04)) return;
13485
13486    /* Apply TV settings given by options */
13487    if((val = pSiS->sistvantiflicker) != -1) {
13488       SiS_SetSIS6326TVantiflicker(pScrn, val);
13489    }
13490    if((val = pSiS->sis6326enableyfilter) != -1) {
13491       SiS_SetSIS6326TVenableyfilter(pScrn, val);
13492    }
13493    if((val = pSiS->sis6326yfilterstrong) != -1) {
13494       SiS_SetSIS6326TVyfilterstrong(pScrn, val);
13495    }
13496
13497}
13498
13499/* Check if video bridge is in slave mode */
13500Bool
13501SiSBridgeIsInSlaveMode(ScrnInfoPtr pScrn)
13502{
13503    SISPtr pSiS = SISPTR(pScrn);
13504    UChar  usScrP1_00;
13505
13506    if(!(pSiS->VBFlags2 & VB2_VIDEOBRIDGE)) return FALSE;
13507
13508    inSISIDXREG(SISPART1,0x00,usScrP1_00);
13509    if( ((pSiS->VGAEngine == SIS_300_VGA) && (usScrP1_00 & 0xa0) == 0x20) ||
13510        ((pSiS->VGAEngine == SIS_315_VGA) && (usScrP1_00 & 0x50) == 0x10) ) {
13511       return TRUE;
13512    }
13513
13514    return FALSE;
13515}
13516
13517/* Build a list of the VESA modes the BIOS reports as valid */
13518static void
13519SiSBuildVesaModeList(ScrnInfoPtr pScrn, vbeInfoPtr pVbe, VbeInfoBlock *vbe)
13520{
13521    SISPtr pSiS = SISPTR(pScrn);
13522    int i = 0;
13523
13524    while(vbe->VideoModePtr[i] != 0xffff) {
13525       sisModeInfoPtr m;
13526       VbeModeInfoBlock *mode;
13527       int id = vbe->VideoModePtr[i++];
13528
13529       if((mode = VBEGetModeInfo(pVbe, id)) == NULL) {
13530	  continue;
13531       }
13532
13533       m = xnfcalloc(sizeof(sisModeInfoRec), 1);
13534       if(!m) {
13535	  VBEFreeModeInfo(mode);
13536	  continue;
13537       }
13538       m->width = mode->XResolution;
13539       m->height = mode->YResolution;
13540       m->bpp = mode->BitsPerPixel;
13541       m->n = id;
13542       m->next = pSiS->SISVESAModeList;
13543
13544       pSiS->SISVESAModeList = m;
13545
13546       VBEFreeModeInfo(mode);
13547
13548       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
13549	   "VESA BIOS supports mode number 0x%x: %ix%i (%i bpp)\n",
13550	   m->n, m->width, m->height, m->bpp);
13551    }
13552}
13553
13554/* Get VESA mode number from given resolution/depth */
13555static UShort
13556SiSCalcVESAModeIndex(ScrnInfoPtr pScrn, DisplayModePtr mode)
13557{
13558    SISPtr pSiS = SISPTR(pScrn);
13559    sisModeInfoPtr m = pSiS->SISVESAModeList;
13560    UShort i = (pScrn->bitsPerPixel+7)/8 - 1;
13561    UShort ModeNumber = 0;
13562    int j;
13563
13564    while(m) {
13565       if( (pScrn->bitsPerPixel == m->bpp) &&
13566	   (mode->HDisplay == m->width)    &&
13567	   (mode->VDisplay == m->height) )
13568	  return m->n;
13569       m = m->next;
13570    }
13571
13572    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
13573        "No valid VESA BIOS mode found for %dx%d (%d bpp)\n",
13574        mode->HDisplay, mode->VDisplay, pScrn->bitsPerPixel);
13575
13576    if(!pSiS->ROM661New) {  /* VESA numbers changed! */
13577       j = 0;
13578       while(VESAModeIndices[j] != 9999) {
13579          if( (mode->HDisplay == VESAModeIndices[j]) &&
13580	      (mode->VDisplay == VESAModeIndices[j+1]) ) {
13581	     ModeNumber = VESAModeIndices[j + 2 + i];
13582	     break;
13583          }
13584          j += 6;
13585       }
13586
13587       if(!ModeNumber) {
13588	  xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
13589	      "No valid mode found for %dx%dx%d in built-in table either.\n",
13590	      mode->HDisplay, mode->VDisplay, pScrn->bitsPerPixel);
13591       }
13592    }
13593
13594    return(ModeNumber);
13595}
13596
13597UShort
13598SiS_GetModeNumber(ScrnInfoPtr pScrn, DisplayModePtr mode, unsigned int VBFlags)
13599{
13600   SISPtr pSiS = SISPTR(pScrn);
13601   UShort i = (pSiS->CurrentLayout.bitsPerPixel+7)/8 - 1;
13602   BOOLEAN FSTN = pSiS->FSTN ? TRUE : FALSE;
13603
13604#ifdef SISDUALHEAD
13605   if(pSiS->DualHeadMode && pSiS->SecondHead) FSTN = FALSE;
13606#endif
13607
13608   return(SiS_GetModeID(pSiS->VGAEngine, VBFlags, mode->HDisplay, mode->VDisplay,
13609			i, FSTN, pSiS->LCDwidth, pSiS->LCDheight));
13610}
13611
13612static Bool
13613SiSValidLCDUserMode(SISPtr pSiS, unsigned int VBFlags, DisplayModePtr mode, Bool isforlcda)
13614{
13615   if(mode->Flags & V_INTERLACE) return FALSE;
13616
13617   if(mode->HDisplay > 2048) return FALSE;
13618   if(mode->VDisplay > 1536) return FALSE;
13619
13620   if(pSiS->VBFlags2 & VB2_LCD162MHZBRIDGE) {
13621      if(mode->Clock > 162500) return FALSE;
13622#ifdef VB_FORBID_CRT2LCD_OVER_1600
13623      if(!isforlcda) {
13624         if(mode->HDisplay > 1600) return FALSE;
13625      }
13626#endif
13627   } else { /* 301, 301B, 302B (no LCDA!) */
13628      if(mode->Clock > 130000)  return FALSE;
13629      if(mode->Clock > 111000) {
13630         xf86DrvMsg(pSiS->pScrn->scrnIndex, X_WARNING,
13631	 	"WARNING: Mode clock beyond video bridge specs (%dMHz). Hardware damage might occure.\n",
13632		mode->Clock / 1000);
13633      }
13634      if(mode->HDisplay > 1600) return FALSE;
13635      if(mode->VDisplay > 1024) return FALSE;
13636   }
13637
13638   return TRUE;
13639}
13640
13641static Bool
13642SiSValidVGA2UserMode(SISPtr pSiS, unsigned int VBFlags, DisplayModePtr mode)
13643{
13644   if(mode->Flags & V_INTERLACE) return FALSE;
13645
13646   if(mode->HDisplay > 2048) return FALSE;
13647   if(mode->VDisplay > 1536) return FALSE;
13648
13649   if(pSiS->VBFlags2 & VB2_RAMDAC202MHZBRIDGE) {
13650      if(mode->Clock > 203000) return FALSE;
13651   } else if(pSiS->VBFlags2 & VB2_30xBLV) {
13652      if(mode->Clock > 162500) return FALSE;
13653   } else {
13654      if(mode->Clock > 135500) return FALSE;
13655   }
13656
13657   return TRUE;
13658}
13659
13660UShort
13661SiS_CheckModeCRT1(ScrnInfoPtr pScrn, DisplayModePtr mode, unsigned int VBFlags, Bool havecustommodes)
13662{
13663   SISPtr pSiS = SISPTR(pScrn);
13664   UShort i = (pSiS->CurrentLayout.bitsPerPixel+7)/8 - 1;
13665   int j;
13666
13667   if(!(VBFlags & CRT1_LCDA)) {
13668
13669      if((havecustommodes) && (!(mode->type & M_T_DEFAULT))) {
13670         return 0xfe;
13671      }
13672
13673   } else if(pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE) {
13674
13675      if(pSiS->ChipType < SIS_661) {  /* < 661 only? */
13676         if(!(mode->type & M_T_DEFAULT)) {
13677            if(mode->HTotal > 2055) return 0;
13678	    /* (Default mode will be caught in mode switching code) */
13679	 }
13680      }
13681
13682      if(pSiS->SiS_Pr->CP_HaveCustomData) {
13683         for(j=0; j<7; j++) {
13684            if((pSiS->SiS_Pr->CP_DataValid[j]) &&
13685               (mode->HDisplay == pSiS->SiS_Pr->CP_HDisplay[j]) &&
13686               (mode->VDisplay == pSiS->SiS_Pr->CP_VDisplay[j]) &&
13687               (mode->type & M_T_BUILTIN))
13688               return 0xfe;
13689	 }
13690      }
13691
13692      if((pSiS->AddedPlasmaModes) && (mode->type & M_T_BUILTIN))
13693         return 0xfe;
13694
13695      if((havecustommodes) &&
13696         (pSiS->LCDwidth)  &&	/* = test if LCD present */
13697         (!(mode->type & M_T_DEFAULT)) &&
13698	 (SiSValidLCDUserMode(pSiS, VBFlags, mode, TRUE)))
13699         return 0xfe;
13700
13701      if((mode->HDisplay > pSiS->LCDwidth) ||
13702         (mode->VDisplay > pSiS->LCDheight)) {
13703	 return 0;
13704      }
13705
13706   } else {
13707
13708      if((mode->HDisplay > pSiS->LCDwidth) ||
13709         (mode->VDisplay > pSiS->LCDheight)) {
13710	 return 0;
13711      }
13712
13713   }
13714
13715   return(SiS_GetModeID(pSiS->VGAEngine, VBFlags, mode->HDisplay, mode->VDisplay,
13716   			i, pSiS->FSTN, pSiS->LCDwidth, pSiS->LCDheight));
13717}
13718
13719UShort
13720SiS_CheckModeCRT2(ScrnInfoPtr pScrn, DisplayModePtr mode, unsigned int VBFlags, Bool havecustommodes)
13721{
13722   SISPtr pSiS = SISPTR(pScrn);
13723   UShort i = (pSiS->CurrentLayout.bitsPerPixel+7)/8 - 1;
13724   UShort ModeIndex = 0;
13725   int    j;
13726
13727#ifdef TWDEBUG
13728   xf86DrvMsg(0, X_INFO, "Inside CheckCalcModeIndex (VBFlags %lx, mode %dx%d)\n",
13729	VBFlags,mode->HDisplay, mode->VDisplay);
13730#endif
13731
13732   if(VBFlags & CRT2_LCD) {			/* CRT2 is LCD */
13733
13734      if((pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) && (!(pSiS->VBFlags2 & VB2_30xBDH))) {
13735
13736         if(pSiS->SiS_Pr->CP_HaveCustomData) {
13737            for(j=0; j<7; j++) {
13738               if((pSiS->SiS_Pr->CP_DataValid[j]) &&
13739                  (mode->HDisplay == pSiS->SiS_Pr->CP_HDisplay[j]) &&
13740                  (mode->VDisplay == pSiS->SiS_Pr->CP_VDisplay[j]) &&
13741#ifdef VB_FORBID_CRT2LCD_OVER_1600
13742		  (mode->HDisplay <= 1600) 			   &&
13743#endif
13744                  (mode->type & M_T_BUILTIN))
13745                  return 0xfe;
13746	    }
13747         }
13748
13749	 /* All plasma modes have HDisplay <= 1600 */
13750         if((pSiS->AddedPlasmaModes) && (mode->type & M_T_BUILTIN))
13751            return 0xfe;
13752
13753         if((havecustommodes) &&
13754            (pSiS->LCDwidth)  &&	/* = test if LCD present */
13755	    (!(mode->type & M_T_DEFAULT)) &&
13756	    (SiSValidLCDUserMode(pSiS, VBFlags, mode, FALSE)))
13757            return 0xfe;
13758
13759      }
13760
13761      if( ((mode->HDisplay <= pSiS->LCDwidth) &&
13762           (mode->VDisplay <= pSiS->LCDheight)) ||
13763	  ((pSiS->SiS_Pr->SiS_CustomT == CUT_PANEL848) &&
13764	   (((mode->HDisplay == 1360) && (mode->VDisplay == 768)) ||
13765	    ((mode->HDisplay == 1024) && (mode->VDisplay == 768)) ||
13766	    ((mode->HDisplay ==  800) && (mode->VDisplay == 600)))) ||
13767	  ((pSiS->SiS_Pr->SiS_CustomT == CUT_PANEL856) &&
13768	   (((mode->HDisplay == 1024) && (mode->VDisplay == 768)) ||
13769	    ((mode->HDisplay ==  800) && (mode->VDisplay == 600)))) ) {
13770
13771	 ModeIndex = SiS_GetModeID_LCD(pSiS->VGAEngine, VBFlags, mode->HDisplay, mode->VDisplay, i,
13772				pSiS->FSTN, pSiS->SiS_Pr->SiS_CustomT, pSiS->LCDwidth, pSiS->LCDheight,
13773				pSiS->VBFlags2);
13774
13775      }
13776
13777   } else if(VBFlags & CRT2_TV) {		/* CRT2 is TV */
13778
13779      ModeIndex = SiS_GetModeID_TV(pSiS->VGAEngine, VBFlags, mode->HDisplay, mode->VDisplay, i,
13780					pSiS->VBFlags2);
13781
13782   } else if(VBFlags & CRT2_VGA) {		/* CRT2 is VGA2 */
13783
13784      if((pSiS->AddedPlasmaModes) && (mode->type & M_T_BUILTIN))
13785	 return 0xfe;
13786
13787      if((havecustommodes) &&
13788	 (!(mode->type & M_T_DEFAULT)) &&
13789	 (SiSValidVGA2UserMode(pSiS, VBFlags, mode)))
13790         return 0xfe;
13791
13792      ModeIndex = SiS_GetModeID_VGA2(pSiS->VGAEngine, VBFlags, mode->HDisplay, mode->VDisplay, i,
13793					pSiS->VBFlags2);
13794
13795   } else {					/* no CRT2 */
13796
13797      /* Return a valid mode number */
13798      ModeIndex = 0xfe;
13799
13800   }
13801
13802   return(ModeIndex);
13803}
13804
13805/* Calculate the vertical refresh rate from a mode */
13806float
13807SiSCalcVRate(DisplayModePtr mode)
13808{
13809   float hsync, refresh = 0;
13810
13811   if(mode->HSync > 0.0)
13812       	hsync = mode->HSync;
13813   else if(mode->HTotal > 0)
13814       	hsync = (float)mode->Clock / (float)mode->HTotal;
13815   else
13816       	hsync = 0.0;
13817
13818   if(mode->VTotal > 0)
13819       	refresh = hsync * 1000.0 / mode->VTotal;
13820
13821   if(mode->Flags & V_INTERLACE)
13822       	refresh *= 2.0;
13823
13824   if(mode->Flags & V_DBLSCAN)
13825       	refresh /= 2.0;
13826
13827   if(mode->VScan > 1)
13828        refresh /= mode->VScan;
13829
13830   if(mode->VRefresh > 0.0)
13831	refresh = mode->VRefresh;
13832
13833   if(hsync == 0.0 || refresh == 0.0) return 0.0;
13834
13835   return refresh;
13836}
13837
13838/* Calculate CR33 (rate index) for CRT1.
13839 * Calculation is done using currentmode, therefore it is
13840 * recommended to set VertRefresh and HorizSync to correct
13841 * values in config file.
13842 */
13843UChar
13844SISSearchCRT1Rate(ScrnInfoPtr pScrn, DisplayModePtr mode)
13845{
13846   SISPtr  pSiS = SISPTR(pScrn);
13847   int     i = 0, irefresh;
13848   UShort  xres = mode->HDisplay;
13849   UShort  yres = mode->VDisplay;
13850   UChar   index, defindex;
13851   Bool    checksis730 = FALSE;
13852
13853   defindex = (xres == 800 || xres == 1024 || xres == 1280) ? 0x02 : 0x01;
13854
13855   irefresh = (int)SiSCalcVRate(mode);
13856   if(!irefresh) return defindex;
13857
13858   /* SiS730 has troubles on CRT2 if CRT1 is at 32bpp */
13859   if( (pSiS->ChipType == SIS_730)        &&
13860       (pSiS->VBFlags2 & VB2_VIDEOBRIDGE) &&
13861       (pSiS->CurrentLayout.bitsPerPixel == 32) ) {
13862#ifdef SISDUALHEAD
13863      if(pSiS->DualHeadMode) {
13864         if(pSiS->SecondHead) {
13865	    checksis730 = TRUE;
13866	 }
13867      } else
13868#endif
13869      if((!pSiS->UseVESA) && (pSiS->VBFlags & CRT2_ENABLE) && (!pSiS->CRT1off)) {
13870         checksis730 = TRUE;
13871      }
13872   }
13873
13874#ifdef TWDEBUG
13875   xf86DrvMsg(0, X_INFO, "Debug: CalcVRate returned %d\n", irefresh);
13876#endif
13877
13878   /* We need the REAL refresh rate here */
13879   if(mode->Flags & V_INTERLACE) irefresh /= 2;
13880
13881   /* Do not multiply by 2 when DBLSCAN! */
13882
13883#ifdef TWDEBUG
13884   xf86DrvMsg(0, X_INFO, "Debug: Rate after correction = %d\n", irefresh);
13885#endif
13886
13887   index = 0;
13888   while((sisx_vrate[i].idx != 0) && (sisx_vrate[i].xres <= xres)) {
13889      if((sisx_vrate[i].xres == xres) && (sisx_vrate[i].yres == yres)) {
13890	 if((checksis730 == FALSE) || (sisx_vrate[i].SiS730valid32bpp == TRUE)) {
13891	    if(sisx_vrate[i].refresh == irefresh) {
13892	       index = sisx_vrate[i].idx;
13893	       break;
13894	    } else if(sisx_vrate[i].refresh > irefresh) {
13895	       if((sisx_vrate[i].refresh - irefresh) <= 3) {
13896		  index = sisx_vrate[i].idx;
13897	       } else if( ((checksis730 == FALSE) || (sisx_vrate[i - 1].SiS730valid32bpp == TRUE)) &&
13898		          ((irefresh - sisx_vrate[i - 1].refresh) <=  2) &&
13899			  (sisx_vrate[i].idx != 1) ) {
13900		  index = sisx_vrate[i - 1].idx;
13901	       }
13902	       break;
13903	    } else if((irefresh - sisx_vrate[i].refresh) <= 2) {
13904	       index = sisx_vrate[i].idx;
13905	       break;
13906	    }
13907	 }
13908      }
13909      i++;
13910   }
13911
13912   if(index > 0) return index;
13913   else          return defindex;
13914}
13915
13916void
13917SISWaitRetraceCRT1(ScrnInfoPtr pScrn)
13918{
13919   SISPtr pSiS = SISPTR(pScrn);
13920   int    watchdog;
13921   UChar  temp;
13922
13923   inSISIDXREG(SISCR,0x17,temp);
13924   if(!(temp & 0x80)) return;
13925
13926   inSISIDXREG(SISSR,0x1f,temp);
13927   if(temp & 0xc0) return;
13928
13929   watchdog = 65536;
13930   while((inSISREG(SISINPSTAT) & 0x08) && --watchdog);
13931   watchdog = 65536;
13932   while((!(inSISREG(SISINPSTAT) & 0x08)) && --watchdog);
13933}
13934
13935void
13936SISWaitRetraceCRT2(ScrnInfoPtr pScrn)
13937{
13938   SISPtr pSiS = SISPTR(pScrn);
13939   int    watchdog;
13940   UChar  temp, reg;
13941
13942   if(SiSBridgeIsInSlaveMode(pScrn)) {
13943      SISWaitRetraceCRT1(pScrn);
13944      return;
13945   }
13946
13947   switch(pSiS->VGAEngine) {
13948   case SIS_300_VGA:
13949   	reg = 0x25;
13950	break;
13951   case SIS_315_VGA:
13952   	reg = 0x30;
13953	break;
13954   default:
13955        return;
13956   }
13957
13958   watchdog = 65536;
13959   do {
13960   	inSISIDXREG(SISPART1, reg, temp);
13961	if(!(temp & 0x02)) break;
13962   } while(--watchdog);
13963   watchdog = 65536;
13964   do {
13965   	inSISIDXREG(SISPART1, reg, temp);
13966	if(temp & 0x02) break;
13967   } while(--watchdog);
13968}
13969
13970static void
13971SISWaitVBRetrace(ScrnInfoPtr pScrn)
13972{
13973   SISPtr  pSiS = SISPTR(pScrn);
13974
13975   if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
13976#ifdef SISDUALHEAD
13977      if(pSiS->DualHeadMode) {
13978   	 if(pSiS->SecondHead)
13979	    SISWaitRetraceCRT1(pScrn);
13980         else
13981	    SISWaitRetraceCRT2(pScrn);
13982      } else {
13983#endif
13984	 if(pSiS->VBFlags & DISPTYPE_DISP1) {
13985	    SISWaitRetraceCRT1(pScrn);
13986	 }
13987	 if(pSiS->VBFlags & DISPTYPE_DISP2) {
13988	    if(!(SiSBridgeIsInSlaveMode(pScrn))) {
13989	       SISWaitRetraceCRT2(pScrn);
13990	    }
13991	 }
13992#ifdef SISDUALHEAD
13993      }
13994#endif
13995   } else {
13996      SISWaitRetraceCRT1(pScrn);
13997   }
13998}
13999
14000#define MODEID_OFF 0x449
14001
14002UChar
14003SiS_GetSetBIOSScratch(ScrnInfoPtr pScrn, UShort offset, UChar value)
14004{
14005    UChar ret = 0;
14006#ifdef SIS_USE_BIOS_SCRATCH
14007    UChar *base;
14008#endif
14009
14010    /* For some reasons (like detecting the current display mode),
14011     * we need to read (or write-back) values from the BIOS
14012     * scratch area. This area is only valid for the primary
14013     * graphics card. For the secondary, we just return some
14014     * defaults and ignore requests to write data. As regards
14015     * the display mode: If sisfb is loaded for the secondary
14016     * card, it very probably has set a mode, but in any case
14017     * informed us via its info packet. So this here will not be
14018     * called for mode detection in this case.
14019     */
14020
14021    switch(offset) {
14022    case 0x489:
14023       ret = 0x11;  /* Default VGA Info */
14024       break;
14025    case MODEID_OFF:
14026       ret = 0x03;  /* Default current display mode */
14027       break;
14028    }
14029
14030#ifndef XSERVER_LIBPCIACCESS
14031#ifdef SIS_USE_BIOS_SCRATCH
14032    if(SISPTR(pScrn)->Primary) {
14033       base = xf86MapVidMem(pScrn->scrnIndex, VIDMEM_MMIO, 0, 0x2000);
14034       if(!base) {
14035          SISErrorLog(pScrn, "(Could not map BIOS scratch area)\n");
14036          return ret;
14037       }
14038
14039       ret = *(base + offset);
14040
14041       /* value != 0xff means: set register */
14042       if(value != 0xff) {
14043          *(base + offset) = value;
14044       }
14045
14046       xf86UnMapVidMem(pScrn->scrnIndex, base, 0x2000);
14047    }
14048#endif
14049#endif
14050    return ret;
14051}
14052
14053UChar
14054SiS_GetSetModeID(ScrnInfoPtr pScrn, UChar id)
14055{
14056    return(SiS_GetSetBIOSScratch(pScrn, MODEID_OFF, id));
14057}
14058
14059void
14060SiSMemCopyToVideoRam(SISPtr pSiS, UChar *to, UChar *from, int size)
14061{
14062   if((ULong)to & 15) (*pSiS->SiSFastMemCopy)(to, from, size);
14063   else       	      (*pSiS->SiSFastVidCopy)(to, from, size);
14064}
14065
14066void
14067SiSMemCopyFromVideoRam(SISPtr pSiS, UChar *to, UChar *from, int size)
14068{
14069   if((ULong)to & 15) (*pSiS->SiSFastMemCopyFrom)(to, from, size);
14070   else       	      (*pSiS->SiSFastVidCopyFrom)(to, from, size);
14071}
14072
14073void
14074sisSaveUnlockExtRegisterLock(SISPtr pSiS, UChar *reg1, UChar *reg2)
14075{
14076    register UChar val;
14077    ULong mylockcalls;
14078#ifdef TWDEBUG
14079    UChar val1, val2;
14080    int i;
14081#endif
14082
14083    pSiS->lockcalls++;
14084    mylockcalls = pSiS->lockcalls;
14085
14086    /* check if already unlocked */
14087    inSISIDXREG(SISSR, 0x05, val);
14088
14089    if(val != 0xa1) {
14090
14091       /* save State */
14092       if(reg1) *reg1 = val;
14093
14094       /* unlock */
14095       outSISIDXREG(SISSR, 0x05, 0x86);
14096
14097       /* Now check again */
14098       inSISIDXREG(SISSR, 0x05, val);
14099
14100       if(val != 0xA1) {
14101
14102          xf86DrvMsg(pSiS->pScrn->scrnIndex, X_WARNING,
14103               "Failed to unlock SR registers at relocated i/o ports\n");
14104
14105#ifdef TWDEBUG
14106          for(i = 0; i <= 0x3f; i++) {
14107		inSISIDXREG(SISSR, i, val1);
14108		inSISIDXREG(0x3c4, i, val2);
14109		xf86DrvMsg(pSiS->pScrn->scrnIndex, X_INFO,
14110			"SR%02d: RelIO=0x%02x 0x3c4=0x%02x (%ld)\n",
14111			i, val1, val2, mylockcalls);
14112	  }
14113#endif
14114
14115	  /* Emergency measure: unlock at 0x3c4, and try to enable relocated IO ports */
14116	  switch(pSiS->VGAEngine) {
14117          case SIS_OLD_VGA:
14118	  case SIS_530_VGA:
14119	     outSISIDXREG(0x3c4, 0x05, 0x86);
14120	     andSISIDXREG(0x3c4, 0x33, ~0x20);
14121	     break;
14122	  case SIS_300_VGA:
14123	  case SIS_315_VGA:
14124	     outSISIDXREG(0x3c4, 0x05, 0x86);
14125	     orSISIDXREG(0x3c4, 0x20, 0x20);
14126	     break;
14127          }
14128	  outSISIDXREG(SISSR, 0x05, 0x86);
14129	  inSISIDXREG(SISSR, 0x05, val);
14130	  if(val != 0xa1) {
14131	     SISErrorLog(pSiS->pScrn,
14132			"Failed to unlock SR registers (%p, %lx, 0x%02x; %ld)\n",
14133			(void *)pSiS, (ULong)pSiS->RelIO, val, mylockcalls);
14134	     /* Now await doom... */
14135	  }
14136       }
14137    }
14138    if((pSiS->VGAEngine == SIS_OLD_VGA) || (pSiS->VGAEngine == SIS_530_VGA)) {
14139       inSISIDXREG(SISCR, 0x80, val);
14140       if(val != 0xa1) {
14141          /* save State */
14142          if(reg2) *reg2 = val;
14143          outSISIDXREG(SISCR, 0x80, 0x86);
14144	  inSISIDXREG(SISCR, 0x80, val);
14145	  if(val != 0xA1) {
14146	     SISErrorLog(pSiS->pScrn,
14147	        "Failed to unlock cr registers (%p, %lx, 0x%02x)\n",
14148	       (void *)pSiS, (ULong)pSiS->RelIO, val);
14149	  }
14150       }
14151    }
14152}
14153
14154void
14155sisRestoreExtRegisterLock(SISPtr pSiS, UChar reg1, UChar reg2)
14156{
14157    /* restore lock */
14158#ifndef UNLOCK_ALWAYS
14159    outSISIDXREG(SISSR, 0x05, reg1 == 0xA1 ? 0x86 : 0x00);
14160    if((pSiS->VGAEngine == SIS_OLD_VGA) || (pSiS->VGAEngine == SIS_530_VGA)) {
14161       outSISIDXREG(SISCR, 0x80, reg2 == 0xA1 ? 0x86 : 0x00);
14162    }
14163#endif
14164}
14165
14166