sis_driver.c revision fe196524
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, X_INFO, "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#if 0
8984	  xf86DisableRandR();
8985#endif
8986	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
8987		"Driver rotation enabled, disabling RandR\n");
8988#endif
8989       } else if(pSiS->Reflect) {
8990          switch(pScrn->bitsPerPixel) {
8991	  case 8:
8992	  case 16:
8993	  case 32:
8994             if(!pSiS->PointerMoved) pSiS->PointerMoved = pScrn->PointerMoved;
8995	     pScrn->PointerMoved = SISPointerMovedReflect;
8996	     refreshArea = SISRefreshAreaReflect;
8997#if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4,3,0,0,0)
8998#if 0
8999	     xf86DisableRandR();
9000#endif
9001	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
9002		  "Driver reflection enabled, disabling RandR\n");
9003#endif
9004	     break;
9005	  default:
9006	     xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
9007	     	  "Reflection not supported at this framebuffer depth\n");
9008	  }
9009       }
9010
9011       ShadowFBInit(pScreen, refreshArea);
9012    }
9013
9014    xf86DPMSInit(pScreen, (DPMSSetProcPtr)SISDisplayPowerManagementSet, 0);
9015
9016    /* Init memPhysBase and fbOffset in pScrn */
9017    pScrn->memPhysBase = pSiS->FbAddress;
9018    pScrn->fbOffset = 0;
9019
9020    /* Initialize Xv */
9021    pSiS->ResetXv = pSiS->ResetXvGamma = pSiS->ResetXvDisplay = NULL;
9022#if (XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4,3,99,0,0)) || (defined(XvExtension))
9023    if((!pSiS->NoXvideo) && (!(pSiS->SiS_SD2_Flags & SiS_SD2_NOOVERLAY))) {
9024
9025       if((pSiS->VGAEngine == SIS_300_VGA) ||
9026	  (pSiS->VGAEngine == SIS_315_VGA)) {
9027
9028	  const char *using = "Using SiS300/315/330/340 series HW Xv";
9029
9030#ifdef SISDUALHEAD
9031	  if(pSiS->DualHeadMode) {
9032	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
9033		    "%s on CRT%d\n", using, (pSiS->SecondHead ? 1 : 2));
9034	     if(!pSiS->hasTwoOverlays) {
9035		if( (pSiS->XvOnCRT2 && pSiS->SecondHead) ||
9036		    (!pSiS->XvOnCRT2 && !pSiS->SecondHead) ) {
9037		   xf86DrvMsg(pScrn->scrnIndex, X_INFO,
9038			   "However, video overlay will by default only be visible on CRT%d\n",
9039			   pSiS->XvOnCRT2 ? 2 : 1);
9040		}
9041	     }
9042	  } else {
9043#endif
9044	     if(pSiS->hasTwoOverlays) {
9045		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s\n", using);
9046	     } else {
9047		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s by default on CRT%d\n",
9048			using, (pSiS->XvOnCRT2 ? 2 : 1));
9049	     }
9050#ifdef SISDUALHEAD
9051	  }
9052#endif
9053
9054	  SISInitVideo(pScreen);
9055
9056	  if(pSiS->blitadaptor) {
9057	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
9058		     "Default Xv adaptor is Video %s\n",
9059		     pSiS->XvDefAdaptorBlit ? "Blitter" : "Overlay");
9060	  }
9061
9062       } else if(pSiS->Chipset == PCI_CHIP_SIS530  ||
9063		 pSiS->Chipset == PCI_CHIP_SIS6326 ||
9064		 pSiS->Chipset == PCI_CHIP_SIS5597) {
9065
9066	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
9067		        "Using SiS5597/5598/6326/530/620 HW Xv\n" );
9068
9069	  SIS6326InitVideo(pScreen);
9070
9071       } else { /* generic Xv */
9072
9073	  XF86VideoAdaptorPtr *ptr;
9074	  int n = xf86XVListGenericAdaptors(pScrn, &ptr);
9075
9076	  if(n) {
9077	     xf86XVScreenInit(pScreen, ptr, n);
9078	     xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using generic Xv\n" );
9079          }
9080
9081       }
9082    }
9083#endif
9084
9085#ifdef SISDRI
9086    if(pSiS->loadDRI) {
9087       if(pSiS->directRenderingEnabled) {
9088          /* Now that mi, drm and others have done their thing,
9089           * complete the DRI setup.
9090           */
9091          pSiS->directRenderingEnabled = SISDRIFinishScreenInit(pScreen);
9092       }
9093       xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Direct rendering %s\n",
9094		pSiS->directRenderingEnabled ? "enabled" : "disabled");
9095       /* TODO */
9096       /* if(pSiS->directRenderingEnabled) SISSetLFBConfig(pSiS); */
9097    }
9098#endif
9099
9100    /* Wrap some funcs, initialize pseudo-Xinerama and setup remaining SD flags */
9101
9102    pSiS->SiS_SD_Flags &= ~(SiS_SD_PSEUDOXINERAMA);
9103#ifdef SISMERGED
9104    if(pSiS->MergedFB) {
9105       pSiS->PointerMoved = pScrn->PointerMoved;
9106       pScrn->PointerMoved = SISMergedPointerMoved;
9107       pSiS->Rotate = 0;
9108       pSiS->Reflect = 0;
9109       pSiS->ShadowFB = FALSE;
9110#if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4,3,0,0,0)
9111       if(pSiS->CRT1XOffs || pSiS->CRT1YOffs || pSiS->CRT2XOffs || pSiS->CRT2YOffs) {
9112#if 0
9113	  xf86DisableRandR();
9114#endif
9115	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
9116		"MergedFB: CRT2Position offset used, disabling RandR\n");
9117       }
9118#endif
9119#ifdef SISXINERAMA
9120       if(pSiS->UseSiSXinerama) {
9121	  SiSnoPanoramiXExtension = FALSE;
9122	  SiSXineramaExtensionInit(pScrn);
9123	  if(!SiSnoPanoramiXExtension) {
9124	     pSiS->SiS_SD_Flags |= SiS_SD_PSEUDOXINERAMA;
9125	     if(pSiS->HaveNonRect) {
9126		/* Reset the viewport (now eventually non-recangular) */
9127		SISAdjustFrame(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0));
9128	     }
9129	  }
9130       } else {
9131	  pSiS->MouseRestrictions = FALSE;
9132       }
9133#endif
9134    }
9135#endif
9136
9137    /* Wrap CloseScreen and set up SaveScreen */
9138    pSiS->CloseScreen = pScreen->CloseScreen;
9139    pScreen->CloseScreen = SISCloseScreen;
9140#ifdef SISDUALHEAD
9141    if(pSiS->DualHeadMode)
9142       pScreen->SaveScreen = SISSaveScreenDH;
9143    else
9144#endif
9145       pScreen->SaveScreen = SISSaveScreen;
9146
9147    /* Install BlockHandler */
9148    pSiS->BlockHandler = pScreen->BlockHandler;
9149    pScreen->BlockHandler = SISBlockHandler;
9150
9151    /* Report any unused options (only for the first generation) */
9152    if(serverGeneration == 1) {
9153       xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
9154    }
9155
9156    /* Clear frame buffer */
9157    /* For CRT2, we don't do that at this point in dual head
9158     * mode since the mode isn't switched at this time (it will
9159     * be reset when setting the CRT1 mode). Hence, we just
9160     * save the necessary data and clear the screen when
9161     * going through this for CRT1.
9162     */
9163
9164    OnScreenSize = pScrn->displayWidth * pScrn->currentMode->VDisplay
9165                               * (pScrn->bitsPerPixel >> 3);
9166
9167    /* Turn on the screen now */
9168    /* We do this in dual head mode after second head is finished */
9169#ifdef SISDUALHEAD
9170    if(pSiS->DualHeadMode) {
9171       if(pSiS->SecondHead) {
9172	  sisclearvram(pSiS->FbBase, OnScreenSize);
9173	  sisclearvram(pSiSEnt->FbBase1, pSiSEnt->OnScreenSize1);
9174	  SISSaveScreen(pScreen, SCREEN_SAVER_OFF);
9175       } else {
9176	  pSiSEnt->FbBase1 = pSiS->FbBase;
9177	  pSiSEnt->OnScreenSize1 = OnScreenSize;
9178       }
9179    } else {
9180#endif
9181       SISSaveScreen(pScreen, SCREEN_SAVER_OFF);
9182       sisclearvram(pSiS->FbBase, OnScreenSize);
9183#ifdef SISDUALHEAD
9184    }
9185#endif
9186
9187    pSiS->SiS_SD_Flags &= ~SiS_SD_SUPPORTSGRCRT2;
9188#ifdef SISDUALHEAD
9189    if(!pSiS->DualHeadMode) {
9190#endif
9191       if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
9192          if((pSiS->crt2cindices) && (pSiS->crt2gcolortable)) {
9193             pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTSGRCRT2;
9194	  }
9195       }
9196#ifdef SISDUALHEAD
9197    }
9198#endif
9199
9200    pSiS->SiS_SD_Flags &= ~SiS_SD_ISDEPTH8;
9201    if(pSiS->CurrentLayout.bitsPerPixel == 8) {
9202       pSiS->SiS_SD_Flags |= SiS_SD_ISDEPTH8;
9203       pSiS->SiS_SD_Flags &= ~SiS_SD_SUPPORTXVGAMMA1;
9204       pSiS->SiS_SD_Flags &= ~SiS_SD_SUPPORTSGRCRT2;
9205    }
9206
9207#ifdef SISGAMMARAMP
9208    pSiS->SiS_SD_Flags |= SiS_SD_CANSETGAMMA;
9209#else
9210    pSiS->SiS_SD_Flags &= ~SiS_SD_CANSETGAMMA;
9211#endif
9212
9213    SiSCtrlExtInit(pScrn);
9214
9215    return TRUE;
9216}
9217
9218/* Usually mandatory */
9219Bool
9220SISSwitchMode(SWITCH_MODE_ARGS_DECL)
9221{
9222    SCRN_INFO_PTR(arg);
9223    SISPtr pSiS = SISPTR(pScrn);
9224
9225    if(!pSiS->skipswitchcheck) {
9226       if(SISValidMode(arg, mode, TRUE, 0) != MODE_OK) {
9227          return FALSE;
9228       }
9229    }
9230
9231    (*pSiS->SyncAccel)(pScrn);
9232
9233    if(!(SISModeInit(pScrn, mode))) return FALSE;
9234
9235    /* Since RandR (indirectly) uses SwitchMode(), we need to
9236     * update our Xinerama info here, too, in case of resizing
9237     */
9238#ifdef SISMERGED
9239#ifdef SISXINERAMA
9240    if(pSiS->MergedFB) {
9241       SiSUpdateXineramaScreenInfo(pScrn);
9242    }
9243#endif
9244#endif
9245    return TRUE;
9246}
9247
9248static void
9249SISSetStartAddressCRT1(SISPtr pSiS, ULong base)
9250{
9251    UChar cr11backup;
9252
9253    inSISIDXREG(SISCR,  0x11, cr11backup);  /* Unlock CRTC registers */
9254    andSISIDXREG(SISCR, 0x11, 0x7F);
9255    outSISIDXREG(SISCR, 0x0D, base & 0xFF);
9256    outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF);
9257    outSISIDXREG(SISSR, 0x0D, (base >> 16) & 0xFF);
9258    if(pSiS->VGAEngine == SIS_315_VGA) {
9259       setSISIDXREG(SISSR, 0x37, 0xFE, (base >> 24) & 0x01);
9260    }
9261    /* Eventually lock CRTC registers */
9262    setSISIDXREG(SISCR, 0x11, 0x7F,(cr11backup & 0x80));
9263}
9264
9265static void
9266SISSetStartAddressCRT2(SISPtr pSiS, ULong base)
9267{
9268    SiS_UnLockCRT2(pSiS->SiS_Pr);
9269    outSISIDXREG(SISPART1, 0x06, GETVAR8(base));
9270    outSISIDXREG(SISPART1, 0x05, GETBITS(base, 15:8));
9271    outSISIDXREG(SISPART1, 0x04, GETBITS(base, 23:16));
9272    if(pSiS->VGAEngine == SIS_315_VGA) {
9273       setSISIDXREG(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7);
9274    }
9275    SiS_LockCRT2(pSiS->SiS_Pr);
9276}
9277
9278#ifdef SISMERGED
9279static Bool
9280InRegion(int x, int y, region r)
9281{
9282    return (r.x0 <= x) && (x <= r.x1) && (r.y0 <= y) && (y <= r.y1);
9283}
9284
9285static void
9286SISAdjustFrameHW_CRT1(ScrnInfoPtr pScrn, int x, int y)
9287{
9288    SISPtr pSiS = SISPTR(pScrn);
9289    ULong base;
9290
9291    base = y * pSiS->CurrentLayout.displayWidth + x;
9292    switch(pSiS->CurrentLayout.bitsPerPixel) {
9293       case 16:  base >>= 1; 	break;
9294       case 32:  		break;
9295       default:  base >>= 2;
9296    }
9297    base += (pSiS->dhmOffset/4);
9298    SISSetStartAddressCRT1(pSiS, base);
9299}
9300
9301static void
9302SISAdjustFrameHW_CRT2(ScrnInfoPtr pScrn, int x, int y)
9303{
9304    SISPtr pSiS = SISPTR(pScrn);
9305    ULong base;
9306
9307    base = y * pSiS->CurrentLayout.displayWidth + x;
9308    switch(pSiS->CurrentLayout.bitsPerPixel) {
9309       case 16:  base >>= 1; 	break;
9310       case 32:  		break;
9311       default:  base >>= 2;
9312    }
9313    base += (pSiS->dhmOffset/4);
9314    SISSetStartAddressCRT2(pSiS, base);
9315}
9316
9317static void
9318SISMergedPointerMoved(SCRN_ARG_TYPE arg, int x, int y)
9319{
9320  SCRN_INFO_PTR(arg);
9321  ScrnInfoPtr	pScrn1 = pScrn;
9322  SISPtr	pSiS = SISPTR(pScrn1);
9323  ScrnInfoPtr	pScrn2 = pSiS->CRT2pScrn;
9324  region	out, in1, in2, f2, f1;
9325  int		deltax, deltay;
9326  int		temp1, temp2;
9327  int		old1x0, old1y0, old2x0, old2y0;
9328  int		CRT1XOffs = 0, CRT1YOffs = 0, CRT2XOffs = 0, CRT2YOffs = 0;
9329  int		HVirt = pScrn1->virtualX;
9330  int		VVirt = pScrn1->virtualY;
9331  int		sigstate;
9332  Bool		doit = FALSE, HaveNonRect = FALSE, HaveOffsRegions = FALSE;
9333  SiSScrn2Rel   srel = ((SiSMergedDisplayModePtr)pSiS->CurrentLayout.mode->Private)->CRT2Position;
9334
9335  if(pSiS->DGAactive) {
9336     return;
9337     /* DGA: There is no cursor and no panning while DGA is active. */
9338     /* If it were, we would need to do: */
9339     /* HVirt = pSiS->CurrentLayout.displayWidth;
9340        VVirt = pSiS->CurrentLayout.displayHeight;
9341        BOUND(x, pSiS->CurrentLayout.DGAViewportX, HVirt);
9342        BOUND(y, pSiS->CurrentLayout.DGAViewportY, VVirt); */
9343  } else {
9344     CRT1XOffs = pSiS->CRT1XOffs;
9345     CRT1YOffs = pSiS->CRT1YOffs;
9346     CRT2XOffs = pSiS->CRT2XOffs;
9347     CRT2YOffs = pSiS->CRT2YOffs;
9348     HaveNonRect = pSiS->HaveNonRect;
9349     HaveOffsRegions = pSiS->HaveOffsRegions;
9350  }
9351
9352  /* Check if the pointer is inside our dead areas */
9353  if((pSiS->MouseRestrictions) && (srel != sisClone) && !SiSnoPanoramiXExtension) {
9354     if(HaveNonRect) {
9355	if(InRegion(x, y, pSiS->NonRectDead)) {
9356	   switch(srel) {
9357	   case sisLeftOf:
9358	   case sisRightOf: y = pSiS->NonRectDead.y0 - 1;
9359			    doit = TRUE;
9360			    break;
9361	   case sisAbove:
9362	   case sisBelow:   x = pSiS->NonRectDead.x0 - 1;
9363			    doit = TRUE;
9364	   default:	    break;
9365	   }
9366	}
9367     }
9368     if(HaveOffsRegions) {
9369	if(InRegion(x, y, pSiS->OffDead1)) {
9370	   switch(srel) {
9371	   case sisLeftOf:
9372	   case sisRightOf: y = pSiS->OffDead1.y1;
9373			    doit = TRUE;
9374			    break;
9375	   case sisAbove:
9376	   case sisBelow:   x = pSiS->OffDead1.x1;
9377			    doit = TRUE;
9378	   default:	    break;
9379	   }
9380	} else if(InRegion(x, y, pSiS->OffDead2)) {
9381	   switch(srel) {
9382	   case sisLeftOf:
9383	   case sisRightOf: y = pSiS->OffDead2.y0 - 1;
9384			    doit = TRUE;
9385			    break;
9386	   case sisAbove:
9387	   case sisBelow:   x = pSiS->OffDead2.x0 - 1;
9388			    doit = TRUE;
9389	   default:	    break;
9390	   }
9391	}
9392     }
9393     if(doit) {
9394#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 20 /* screw it */
9395	sigstate = xf86BlockSIGIO();
9396#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 15
9397        {
9398            double dx = x, dy = y;
9399            miPointerSetPosition(inputInfo.pointer, Absolute, &dx, &dy);
9400            x = (int)dx;
9401            y = (int)dy;
9402        }
9403#elif GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 13
9404	miPointerSetPosition(inputInfo.pointer, Absolute, &x, &y);
9405#elif GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 5
9406	miPointerSetPosition(inputInfo.pointer, &x, &y);
9407#else
9408	UpdateCurrentTime();
9409	miPointerAbsoluteCursor(x, y, currentTime.milliseconds);
9410#endif
9411	xf86UnblockSIGIO(sigstate);
9412#endif
9413	return;
9414     }
9415  }
9416
9417  f1.x0 = old1x0 = pSiS->CRT1frameX0;
9418  f1.x1 = pSiS->CRT1frameX1;
9419  f1.y0 = old1y0 = pSiS->CRT1frameY0;
9420  f1.y1 = pSiS->CRT1frameY1;
9421  f2.x0 = old2x0 = pScrn2->frameX0;
9422  f2.x1 = pScrn2->frameX1;
9423  f2.y0 = old2y0 = pScrn2->frameY0;
9424  f2.y1 = pScrn2->frameY1;
9425
9426  /* Define the outer region. Crossing this causes all frames to move */
9427  out.x0 = pScrn1->frameX0;
9428  out.x1 = pScrn1->frameX1;
9429  out.y0 = pScrn1->frameY0;
9430  out.y1 = pScrn1->frameY1;
9431
9432  /*
9433   * Define the inner sliding window. Being outsize both frames but
9434   * inside the outer clipping window will slide corresponding frame
9435   */
9436  in1 = out;
9437  in2 = out;
9438  switch(srel) {
9439     case sisLeftOf:
9440        in1.x0 = f1.x0;
9441        in2.x1 = f2.x1;
9442        break;
9443     case sisRightOf:
9444        in1.x1 = f1.x1;
9445        in2.x0 = f2.x0;
9446        break;
9447     case sisBelow:
9448        in1.y1 = f1.y1;
9449        in2.y0 = f2.y0;
9450        break;
9451     case sisAbove:
9452        in1.y0 = f1.y0;
9453        in2.y1 = f2.y1;
9454        break;
9455     case sisClone:
9456        break;
9457  }
9458
9459  deltay = 0;
9460  deltax = 0;
9461
9462  if(InRegion(x, y, out)) {	/* inside outer region */
9463
9464     if(InRegion(x, y, in1) && !InRegion(x, y, f1)) {
9465	REBOUND(f1.x0, f1.x1, x);
9466	REBOUND(f1.y0, f1.y1, y);
9467	deltax = 1;
9468     }
9469     if(InRegion(x, y, in2) && !InRegion(x, y, f2)) {
9470	REBOUND(f2.x0, f2.x1, x);
9471	REBOUND(f2.y0, f2.y1, y);
9472	deltax = 1;
9473     }
9474
9475  } else {			/* outside outer region */
9476
9477     if(out.x0 > x) {
9478	deltax = x - out.x0;
9479     }
9480     if(out.x1 < x) {
9481	deltax = x - out.x1;
9482     }
9483     if(deltax) {
9484	pScrn1->frameX0 += deltax;
9485	pScrn1->frameX1 += deltax;
9486	f1.x0 += deltax;
9487	f1.x1 += deltax;
9488	f2.x0 += deltax;
9489	f2.x1 += deltax;
9490     }
9491
9492     if(out.y0 > y) {
9493	deltay = y - out.y0;
9494     }
9495     if(out.y1 < y) {
9496	deltay = y - out.y1;
9497     }
9498     if(deltay) {
9499	pScrn1->frameY0 += deltay;
9500	pScrn1->frameY1 += deltay;
9501	f1.y0 += deltay;
9502	f1.y1 += deltay;
9503	f2.y0 += deltay;
9504	f2.y1 += deltay;
9505     }
9506
9507     switch(srel) {
9508	case sisLeftOf:
9509	   if(x >= f1.x0) { REBOUND(f1.y0, f1.y1, y); }
9510	   if(x <= f2.x1) { REBOUND(f2.y0, f2.y1, y); }
9511	   break;
9512	case sisRightOf:
9513	   if(x <= f1.x1) { REBOUND(f1.y0, f1.y1, y); }
9514	   if(x >= f2.x0) { REBOUND(f2.y0, f2.y1, y); }
9515	   break;
9516	case sisBelow:
9517	   if(y <= f1.y1) { REBOUND(f1.x0, f1.x1, x); }
9518	   if(y >= f2.y0) { REBOUND(f2.x0, f2.x1, x); }
9519	   break;
9520	case sisAbove:
9521	   if(y >= f1.y0) { REBOUND(f1.x0, f1.x1, x); }
9522	   if(y <= f2.y1) { REBOUND(f2.x0, f2.x1, x); }
9523	   break;
9524	case sisClone:
9525	   break;
9526     }
9527
9528  }
9529
9530  if(deltax || deltay) {
9531     pSiS->CRT1frameX0 = f1.x0;
9532     pSiS->CRT1frameY0 = f1.y0;
9533     pScrn2->frameX0 = f2.x0;
9534     pScrn2->frameY0 = f2.y0;
9535
9536     switch(srel) {
9537	case sisLeftOf:
9538	case sisRightOf:
9539	   if(CRT1YOffs || CRT2YOffs || HaveNonRect) {
9540	      if(pSiS->CRT1frameY0 != old1y0) {
9541	         if(pSiS->CRT1frameY0 < CRT1YOffs)
9542	            pSiS->CRT1frameY0 = CRT1YOffs;
9543
9544	         temp1 = pSiS->CRT1frameY0 + CDMPTR->CRT1->VDisplay;
9545	         temp2 = min((VVirt - CRT2YOffs), (CRT1YOffs + pSiS->MBXNR1YMAX));
9546	         if(temp1 > temp2)
9547	            pSiS->CRT1frameY0 -= (temp1 - temp2);
9548	      }
9549	      if(pScrn2->frameY0 != old2y0) {
9550	         if(pScrn2->frameY0 < CRT2YOffs)
9551	            pScrn2->frameY0 = CRT2YOffs;
9552
9553	         temp1 = pScrn2->frameY0 + CDMPTR->CRT2->VDisplay;
9554	         temp2 = min((VVirt - CRT1YOffs), (CRT2YOffs + pSiS->MBXNR2YMAX));
9555	         if(temp1 > temp2)
9556	            pScrn2->frameY0 -= (temp1 - temp2);
9557	      }
9558	   }
9559	   break;
9560	case sisBelow:
9561	case sisAbove:
9562	   if(CRT1XOffs || CRT2XOffs || HaveNonRect) {
9563	      if(pSiS->CRT1frameX0 != old1x0) {
9564	         if(pSiS->CRT1frameX0 < CRT1XOffs)
9565	            pSiS->CRT1frameX0 = CRT1XOffs;
9566
9567	         temp1 = pSiS->CRT1frameX0 + CDMPTR->CRT1->HDisplay;
9568	         temp2 = min((HVirt - CRT2XOffs), (CRT1XOffs + pSiS->MBXNR1XMAX));
9569	         if(temp1 > temp2)
9570	            pSiS->CRT1frameX0 -= (temp1 - temp2);
9571	      }
9572	      if(pScrn2->frameX0 != old2x0) {
9573	         if(pScrn2->frameX0 < CRT2XOffs)
9574	            pScrn2->frameX0 = CRT2XOffs;
9575
9576	         temp1 = pScrn2->frameX0 + CDMPTR->CRT2->HDisplay;
9577	         temp2 = min((HVirt - CRT1XOffs), (CRT2XOffs + pSiS->MBXNR2XMAX));
9578	         if(temp1 > temp2)
9579	            pScrn2->frameX0 -= (temp1 - temp2);
9580	      }
9581	   }
9582	   break;
9583	case sisClone:
9584	   break;
9585     }
9586
9587     pSiS->CRT1frameX1 = pSiS->CRT1frameX0 + CDMPTR->CRT1->HDisplay - 1;
9588     pSiS->CRT1frameY1 = pSiS->CRT1frameY0 + CDMPTR->CRT1->VDisplay - 1;
9589     pScrn2->frameX1   = pScrn2->frameX0   + CDMPTR->CRT2->HDisplay - 1;
9590     pScrn2->frameY1   = pScrn2->frameY0   + CDMPTR->CRT2->VDisplay - 1;
9591
9592     /* No need to update pScrn1->frame?1, done above */
9593
9594     SISAdjustFrameHW_CRT1(pScrn1, pSiS->CRT1frameX0, pSiS->CRT1frameY0);
9595     SISAdjustFrameHW_CRT2(pScrn1, pScrn2->frameX0, pScrn2->frameY0);
9596  }
9597}
9598
9599static void
9600SISAdjustFrameMerged(ADJUST_FRAME_ARGS_DECL)
9601{
9602    SCRN_INFO_PTR(arg);
9603    ScrnInfoPtr pScrn1 = pScrn;
9604    SISPtr pSiS = SISPTR(pScrn1);
9605    ScrnInfoPtr pScrn2 = pSiS->CRT2pScrn;
9606    int HTotal = pSiS->CurrentLayout.mode->HDisplay;
9607    int VTotal = pSiS->CurrentLayout.mode->VDisplay;
9608    int HMax = HTotal;
9609    int VMax = VTotal;
9610    int HVirt = pScrn1->virtualX;
9611    int VVirt = pScrn1->virtualY;
9612    int x1 = x, x2 = x;
9613    int y1 = y, y2 = y;
9614    int CRT1XOffs = 0, CRT1YOffs = 0, CRT2XOffs = 0, CRT2YOffs = 0;
9615    int MBXNR1XMAX = 65536, MBXNR1YMAX = 65536, MBXNR2XMAX = 65536, MBXNR2YMAX = 65536;
9616
9617    if(pSiS->DGAactive) {
9618       HVirt = pSiS->CurrentLayout.displayWidth;
9619       VVirt = pSiS->CurrentLayout.displayHeight;
9620    } else {
9621       CRT1XOffs = pSiS->CRT1XOffs;
9622       CRT1YOffs = pSiS->CRT1YOffs;
9623       CRT2XOffs = pSiS->CRT2XOffs;
9624       CRT2YOffs = pSiS->CRT2YOffs;
9625       MBXNR1XMAX = pSiS->MBXNR1XMAX;
9626       MBXNR1YMAX = pSiS->MBXNR1YMAX;
9627       MBXNR2XMAX = pSiS->MBXNR2XMAX;
9628       MBXNR2YMAX = pSiS->MBXNR2YMAX;
9629    }
9630
9631    BOUND(x, 0, HVirt - HTotal);
9632    BOUND(y, 0, VVirt - VTotal);
9633    if(SDMPTR(pScrn1)->CRT2Position != sisClone) {
9634       BOUND(x1, CRT1XOffs, min(HVirt, MBXNR1XMAX + CRT1XOffs) - min(HTotal, MBXNR1XMAX) - CRT2XOffs);
9635       BOUND(y1, CRT1YOffs, min(VVirt, MBXNR1YMAX + CRT1YOffs) - min(VTotal, MBXNR1YMAX) - CRT2YOffs);
9636       BOUND(x2, CRT2XOffs, min(HVirt, MBXNR2XMAX + CRT2XOffs) - min(HTotal, MBXNR2XMAX) - CRT1XOffs);
9637       BOUND(y2, CRT2YOffs, min(VVirt, MBXNR2YMAX + CRT2YOffs) - min(VTotal, MBXNR2YMAX) - CRT1YOffs);
9638    }
9639
9640    switch(SDMPTR(pScrn1)->CRT2Position) {
9641        case sisLeftOf:
9642            pScrn2->frameX0 = x2;
9643            BOUND(pScrn2->frameY0,   y2, y2 + min(VMax, MBXNR2YMAX) - CDMPTR->CRT2->VDisplay);
9644            pSiS->CRT1frameX0 = x1 + CDMPTR->CRT2->HDisplay;
9645            BOUND(pSiS->CRT1frameY0, y1, y1 + min(VMax, MBXNR1YMAX) - CDMPTR->CRT1->VDisplay);
9646            break;
9647        case sisRightOf:
9648            pSiS->CRT1frameX0 = x1;
9649            BOUND(pSiS->CRT1frameY0, y1, y1 + min(VMax, MBXNR1YMAX) - CDMPTR->CRT1->VDisplay);
9650            pScrn2->frameX0 = x2 + CDMPTR->CRT1->HDisplay;
9651            BOUND(pScrn2->frameY0,   y2, y2 + min(VMax, MBXNR2YMAX) - CDMPTR->CRT2->VDisplay);
9652            break;
9653        case sisAbove:
9654            BOUND(pScrn2->frameX0,   x2, x2 + min(HMax, MBXNR2XMAX) - CDMPTR->CRT2->HDisplay);
9655            pScrn2->frameY0 = y2;
9656            BOUND(pSiS->CRT1frameX0, x1, x1 + min(HMax, MBXNR1XMAX) - CDMPTR->CRT1->HDisplay);
9657            pSiS->CRT1frameY0 = y1 + CDMPTR->CRT2->VDisplay;
9658            break;
9659        case sisBelow:
9660            BOUND(pSiS->CRT1frameX0, x1, x1 + min(HMax, MBXNR1XMAX) - CDMPTR->CRT1->HDisplay);
9661            pSiS->CRT1frameY0 = y1;
9662            BOUND(pScrn2->frameX0,   x2, x2 + min(HMax, MBXNR2XMAX) - CDMPTR->CRT2->HDisplay);
9663            pScrn2->frameY0 = y2 + CDMPTR->CRT1->VDisplay;
9664            break;
9665        case sisClone:
9666            BOUND(pSiS->CRT1frameX0, x,  x + HMax - CDMPTR->CRT1->HDisplay);
9667            BOUND(pSiS->CRT1frameY0, y,  y + VMax - CDMPTR->CRT1->VDisplay);
9668            BOUND(pScrn2->frameX0,   x,  x + HMax - CDMPTR->CRT2->HDisplay);
9669            BOUND(pScrn2->frameY0,   y,  y + VMax - CDMPTR->CRT2->VDisplay);
9670            break;
9671    }
9672
9673    BOUND(pSiS->CRT1frameX0, 0, HVirt - CDMPTR->CRT1->HDisplay);
9674    BOUND(pSiS->CRT1frameY0, 0, VVirt - CDMPTR->CRT1->VDisplay);
9675    BOUND(pScrn2->frameX0,   0, HVirt - CDMPTR->CRT2->HDisplay);
9676    BOUND(pScrn2->frameY0,   0, VVirt - CDMPTR->CRT2->VDisplay);
9677
9678    pScrn1->frameX0 = x;
9679    pScrn1->frameY0 = y;
9680
9681    pSiS->CRT1frameX1 = pSiS->CRT1frameX0 + CDMPTR->CRT1->HDisplay - 1;
9682    pSiS->CRT1frameY1 = pSiS->CRT1frameY0 + CDMPTR->CRT1->VDisplay - 1;
9683    pScrn2->frameX1   = pScrn2->frameX0   + CDMPTR->CRT2->HDisplay - 1;
9684    pScrn2->frameY1   = pScrn2->frameY0   + CDMPTR->CRT2->VDisplay - 1;
9685
9686    pScrn1->frameX1   = pScrn1->frameX0   + pSiS->CurrentLayout.mode->HDisplay  - 1;
9687    pScrn1->frameY1   = pScrn1->frameY0   + pSiS->CurrentLayout.mode->VDisplay  - 1;
9688    if(SDMPTR(pScrn1)->CRT2Position != sisClone) {
9689       pScrn1->frameX1 += CRT1XOffs + CRT2XOffs;
9690       pScrn1->frameY1 += CRT1YOffs + CRT2YOffs;
9691    }
9692
9693    SISAdjustFrameHW_CRT1(pScrn1, pSiS->CRT1frameX0, pSiS->CRT1frameY0);
9694    SISAdjustFrameHW_CRT2(pScrn1, pScrn2->frameX0, pScrn2->frameY0);
9695}
9696#endif
9697
9698/*
9699 * This function is used to initialize the Start Address - the first
9700 * displayed location in the video memory.
9701 *
9702 * Usually mandatory
9703 */
9704void
9705SISAdjustFrame(ADJUST_FRAME_ARGS_DECL)
9706{
9707    SCRN_INFO_PTR(arg);
9708    SISPtr        pSiS = SISPTR(pScrn);
9709    ULong base;
9710    UChar temp, cr11backup;
9711
9712#ifdef SISMERGED
9713    if(pSiS->MergedFB) {
9714        SISAdjustFrameMerged(ADJUST_FRAME_ARGS(pScrn, x, y));
9715	return;
9716    }
9717#endif
9718
9719    if(pSiS->UseVESA) {
9720	VBESetDisplayStart(pSiS->pVbe, x, y, TRUE);
9721	return;
9722    }
9723
9724    if(pScrn->bitsPerPixel < 8) {
9725       base = (y * pSiS->CurrentLayout.displayWidth + x + 3) >> 3;
9726    } else {
9727       base  = y * pSiS->CurrentLayout.displayWidth + x;
9728
9729       /* calculate base bpp dep. */
9730       switch(pSiS->CurrentLayout.bitsPerPixel) {
9731          case 16:
9732     	     base >>= 1;
9733             break;
9734          case 24:
9735             base = ((base * 3)) >> 2;
9736             base -= base % 6;
9737             break;
9738          case 32:
9739             break;
9740          default:      /* 8bpp */
9741             base >>= 2;
9742             break;
9743       }
9744    }
9745
9746#ifdef UNLOCK_ALWAYS
9747    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
9748#endif
9749
9750    base += (pSiS->dhmOffset/4);
9751
9752#ifdef TWDEBUG
9753    xf86DrvMsg(0, 0, "AdjustFrame: x %d y %d bpp %d dw %d base %d, dhmOffset %d\n",
9754    			x, y, pSiS->CurrentLayout.bitsPerPixel, pSiS->CurrentLayout.displayWidth, base, pSiS->dhmOffset);
9755#endif
9756
9757#ifdef SISDUALHEAD
9758    if(pSiS->DualHeadMode) {
9759       if(!pSiS->SecondHead) {
9760	  /* Head 1 (master) is always CRT2 */
9761	  SISSetStartAddressCRT2(pSiS, base);
9762       } else {
9763	  /* Head 2 (slave) is always CRT1 */
9764	  SISSetStartAddressCRT1(pSiS, base);
9765       }
9766    } else {
9767#endif
9768       switch(pSiS->VGAEngine) {
9769	  case SIS_300_VGA:
9770	  case SIS_315_VGA:
9771	     SISSetStartAddressCRT1(pSiS, base);
9772	     if(pSiS->VBFlags & CRT2_ENABLE) {
9773		if(!SiSBridgeIsInSlaveMode(pScrn)) {
9774		   SISSetStartAddressCRT2(pSiS, base);
9775		}
9776	     }
9777	     break;
9778	  default:
9779	     /* Unlock CRTC registers */
9780	     inSISIDXREG(SISCR,  0x11, cr11backup);
9781	     andSISIDXREG(SISCR, 0x11, 0x7F);
9782	     outSISIDXREG(SISCR, 0x0D, base & 0xFF);
9783	     outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF);
9784	     inSISIDXREG(SISSR,  0x27, temp);
9785	     temp &= 0xF0;
9786	     temp |= (base & 0x0F0000) >> 16;
9787	     outSISIDXREG(SISSR, 0x27, temp);
9788	     /* Eventually lock CRTC registers */
9789	     setSISIDXREG(SISCR, 0x11, 0x7F, (cr11backup & 0x80));
9790       }
9791#ifdef SISDUALHEAD
9792    }
9793#endif
9794
9795}
9796
9797/*
9798 * This is called when VT switching back to the X server.  Its job is
9799 * to reinitialise the video mode.
9800 * Mandatory!
9801 */
9802static Bool
9803SISEnterVT(VT_FUNC_ARGS_DECL)
9804{
9805    SCRN_INFO_PTR(arg);
9806    SISPtr pSiS = SISPTR(pScrn);
9807
9808    SiS_SiSFB_Lock(pScrn, TRUE);
9809
9810    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
9811
9812    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
9813       outSISIDXREG(SISCR,0x32,pSiS->myCR32);
9814       outSISIDXREG(SISCR,0x36,pSiS->myCR36);
9815       outSISIDXREG(SISCR,0x37,pSiS->myCR37);
9816    }
9817
9818    if(!SISModeInit(pScrn, pScrn->currentMode)) {
9819       SISErrorLog(pScrn, "SiSEnterVT: SISModeInit() failed\n");
9820       return FALSE;
9821    }
9822
9823    SISAdjustFrame(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0));
9824
9825#ifdef SISDRI
9826    if(pSiS->directRenderingEnabled) {
9827       DRIUnlock(xf86ScrnToScreen(pScrn));
9828    }
9829#endif
9830
9831#ifdef SISDUALHEAD
9832    if((!pSiS->DualHeadMode) || (!pSiS->SecondHead))
9833#endif
9834       if(pSiS->ResetXv) {
9835          (pSiS->ResetXv)(pScrn);
9836       }
9837
9838    return TRUE;
9839}
9840
9841/*
9842 * This is called when VT switching away from the X server.  Its job is
9843 * to restore the previous (text) mode.
9844 * Mandatory!
9845 */
9846static void
9847SISLeaveVT(VT_FUNC_ARGS_DECL)
9848{
9849    SCRN_INFO_PTR(arg);
9850    SISPtr pSiS = SISPTR(pScrn);
9851#ifdef SISDRI
9852    ScreenPtr pScreen;
9853
9854    if(pSiS->directRenderingEnabled) {
9855       pScreen = xf86ScrnToScreen(pScrn);
9856       DRILock(pScreen, 0);
9857    }
9858#endif
9859
9860#ifdef SISDUALHEAD
9861    if(pSiS->DualHeadMode && pSiS->SecondHead) return;
9862#endif
9863
9864    if(pSiS->CursorInfoPtr) {
9865#ifdef SISDUALHEAD
9866       if(pSiS->DualHeadMode) {
9867          if(!pSiS->SecondHead) {
9868	     pSiS->ForceCursorOff = TRUE;
9869	     pSiS->CursorInfoPtr->HideCursor(pScrn);
9870	     SISWaitVBRetrace(pScrn);
9871	     pSiS->ForceCursorOff = FALSE;
9872	  }
9873       } else {
9874#endif
9875          pSiS->CursorInfoPtr->HideCursor(pScrn);
9876          SISWaitVBRetrace(pScrn);
9877#ifdef SISDUALHEAD
9878       }
9879#endif
9880    }
9881
9882    SISBridgeRestore(pScrn);
9883
9884    if(pSiS->UseVESA) {
9885
9886       /* This is a q&d work-around for a BIOS bug. In case we disabled CRT2,
9887    	* VBESaveRestore() does not restore CRT1. So we set any mode now,
9888	* because VBESetVBEMode correctly restores CRT1. Afterwards, we
9889	* can call VBESaveRestore to restore original mode.
9890	*/
9891       if((pSiS->VBFlags2 & VB2_VIDEOBRIDGE) && (!(pSiS->VBFlags & DISPTYPE_DISP2)))
9892	  VBESetVBEMode(pSiS->pVbe, (pSiS->SISVESAModeList->n) | 0xc000, NULL);
9893
9894       SISVESARestore(pScrn);
9895
9896    } else {
9897
9898       SISRestore(pScrn);
9899
9900    }
9901
9902    /* We use (otherwise unused) bit 7 to indicate that we are running
9903     * to keep sisfb to change the displaymode (this would result in
9904     * lethal display corruption upon quitting X or changing to a VT
9905     * until a reboot)
9906     */
9907    if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
9908       orSISIDXREG(SISCR,0x34,0x80);
9909    }
9910
9911    SISVGALock(pSiS);
9912
9913    SiS_SiSFB_Lock(pScrn, FALSE);
9914}
9915
9916
9917/*
9918 * This is called at the end of each server generation.  It restores the
9919 * original (text) mode.  It should really also unmap the video memory too.
9920 * Mandatory!
9921 */
9922static Bool
9923SISCloseScreen(CLOSE_SCREEN_ARGS_DECL)
9924{
9925    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
9926    SISPtr pSiS = SISPTR(pScrn);
9927#ifdef SISDUALHEAD
9928    SISEntPtr pSiSEnt = pSiS->entityPrivate;
9929#endif
9930
9931    if(pSiS->SiSCtrlExtEntry) {
9932       SiSCtrlExtUnregister(pSiS, pScrn->scrnIndex);
9933    }
9934
9935#ifdef SISDRI
9936    if(pSiS->directRenderingEnabled) {
9937       SISDRICloseScreen(pScreen);
9938       pSiS->directRenderingEnabled = FALSE;
9939    }
9940#endif
9941
9942    if(pScrn->vtSema) {
9943
9944        if(pSiS->CursorInfoPtr) {
9945#ifdef SISDUALHEAD
9946           if(pSiS->DualHeadMode) {
9947              if(!pSiS->SecondHead) {
9948	         pSiS->ForceCursorOff = TRUE;
9949	         pSiS->CursorInfoPtr->HideCursor(pScrn);
9950	         SISWaitVBRetrace(pScrn);
9951	         pSiS->ForceCursorOff = FALSE;
9952	      }
9953           } else {
9954#endif
9955             pSiS->CursorInfoPtr->HideCursor(pScrn);
9956             SISWaitVBRetrace(pScrn);
9957#ifdef SISDUALHEAD
9958           }
9959#endif
9960	}
9961
9962        SISBridgeRestore(pScrn);
9963
9964	if(pSiS->UseVESA) {
9965
9966	  /* This is a q&d work-around for a BIOS bug. In case we disabled CRT2,
9967    	   * VBESaveRestore() does not restore CRT1. So we set any mode now,
9968	   * because VBESetVBEMode correctly restores CRT1. Afterwards, we
9969	   * can call VBESaveRestore to restore original mode.
9970	   */
9971           if((pSiS->VBFlags2 & VB2_VIDEOBRIDGE) && (!(pSiS->VBFlags & DISPTYPE_DISP2)))
9972	      VBESetVBEMode(pSiS->pVbe, (pSiS->SISVESAModeList->n) | 0xc000, NULL);
9973
9974	   SISVESARestore(pScrn);
9975
9976	} else {
9977
9978	   SISRestore(pScrn);
9979
9980	}
9981
9982        SISVGALock(pSiS);
9983
9984    }
9985
9986    SiS_SiSFB_Lock(pScrn, FALSE);
9987
9988    /* We should restore the mode number in case vtsema = false as well,
9989     * but since we haven't register access then we can't do it. I think
9990     * I need to rework the save/restore stuff, like saving the video
9991     * status when returning to the X server and by that save me the
9992     * trouble if sisfb was started from a textmode VT while X was on.
9993     */
9994
9995    SISUnmapMem(pScrn);
9996#ifdef SIS_PC_PLATFORM
9997    SiSVGAUnmapMem(pScrn);
9998#endif
9999
10000#ifdef SISDUALHEAD
10001    if(pSiS->DualHeadMode) {
10002       pSiSEnt = pSiS->entityPrivate;
10003       pSiSEnt->refCount--;
10004    }
10005#endif
10006
10007    if(pSiS->pInt) {
10008       xf86FreeInt10(pSiS->pInt);
10009       pSiS->pInt = NULL;
10010    }
10011
10012#ifdef SIS_USE_XAA
10013    if(!pSiS->useEXA) {
10014       if(pSiS->AccelLinearScratch) {
10015          xf86FreeOffscreenLinear(pSiS->AccelLinearScratch);
10016          pSiS->AccelLinearScratch = NULL;
10017       }
10018       if(pSiS->AccelInfoPtr) {
10019          XAADestroyInfoRec(pSiS->AccelInfoPtr);
10020          pSiS->AccelInfoPtr = NULL;
10021       }
10022    }
10023#endif
10024
10025#ifdef SIS_USE_EXA
10026    if(pSiS->useEXA) {
10027       if(pSiS->EXADriverPtr) {
10028          exaDriverFini(pScreen);
10029          free(pSiS->EXADriverPtr);
10030          pSiS->EXADriverPtr = NULL;
10031          pSiS->exa_scratch = NULL;
10032       }
10033    }
10034#endif
10035
10036    if(pSiS->CursorInfoPtr) {
10037       xf86DestroyCursorInfoRec(pSiS->CursorInfoPtr);
10038       pSiS->CursorInfoPtr = NULL;
10039    }
10040
10041    if(pSiS->ShadowPtr) {
10042       free(pSiS->ShadowPtr);
10043       pSiS->ShadowPtr = NULL;
10044    }
10045
10046    if(pSiS->DGAModes) {
10047       free(pSiS->DGAModes);
10048       pSiS->DGAModes = NULL;
10049    }
10050
10051    if(pSiS->adaptor) {
10052       free(pSiS->adaptor);
10053       pSiS->adaptor = NULL;
10054       pSiS->ResetXv = pSiS->ResetXvGamma = pSiS->ResetXvDisplay = NULL;
10055    }
10056
10057    if(pSiS->blitadaptor) {
10058       free(pSiS->blitadaptor);
10059       pSiS->blitadaptor = NULL;
10060    }
10061
10062    if(pSiS->crt2gcolortable) {
10063       free(pSiS->crt2gcolortable);
10064       pSiS->crt2gcolortable = NULL;
10065    }
10066
10067    if(pSiS->crt2cindices) {
10068       free(pSiS->crt2cindices);
10069       pSiS->crt2cindices = NULL;
10070    }
10071
10072    pScrn->vtSema = FALSE;
10073
10074    /* Restore Blockhandler */
10075    pScreen->BlockHandler = pSiS->BlockHandler;
10076
10077    pScreen->CloseScreen = pSiS->CloseScreen;
10078
10079    return(*pScreen->CloseScreen)(CLOSE_SCREEN_ARGS);
10080}
10081
10082
10083/* Free up any per-generation data structures */
10084
10085/* Optional */
10086static void
10087SISFreeScreen(FREE_SCREEN_ARGS_DECL)
10088{
10089    SCRN_INFO_PTR(arg);
10090#ifdef SIS_NEED_MAP_IOP
10091    SISPtr pSiS = SISPTR(pScrn);
10092
10093    if(pSiS) {
10094#ifdef SISDUALHEAD
10095       SISEntPtr pSiSEnt = pSiS->entityPrivate;
10096       if(pSiSEnt) {
10097          pSiSEnt->forceUnmapIOPBase = TRUE;
10098       }
10099#endif
10100       SISUnmapIOPMem(pScrn);
10101    }
10102#endif
10103
10104    SISFreeRec(pScrn);
10105}
10106
10107
10108/* Checks if a mode is suitable for the selected chipset. */
10109
10110static ModeStatus
10111SISValidMode(SCRN_ARG_TYPE arg, DisplayModePtr mode, Bool verbose, int flags)
10112{
10113    SCRN_INFO_PTR(arg);
10114    SISPtr pSiS = SISPTR(pScrn);
10115
10116    if(pSiS->UseVESA) {
10117       if(SiSCalcVESAModeIndex(pScrn, mode))
10118	  return(MODE_OK);
10119       else
10120	  return(MODE_BAD);
10121    }
10122
10123    if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
10124#ifdef SISDUALHEAD
10125       if(pSiS->DualHeadMode) {
10126          if(pSiS->SecondHead) {
10127	     if(SiS_CheckModeCRT1(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
10128	        return(MODE_BAD);
10129	  } else {
10130	     if(SiS_CheckModeCRT2(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
10131	        return(MODE_BAD);
10132	  }
10133       } else
10134#endif
10135#ifdef SISMERGED
10136       if(pSiS->MergedFB) {
10137	  if(!mode->Private) {
10138	     if(!pSiS->CheckForCRT2) {
10139	        if(SiS_CheckModeCRT1(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
10140	           return(MODE_BAD);
10141	     } else {
10142	        if(SiS_CheckModeCRT2(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes2) < 0x14)
10143	           return(MODE_BAD);
10144	     }
10145	  } else {
10146	     if(SiS_CheckModeCRT1(pScrn, ((SiSMergedDisplayModePtr)mode->Private)->CRT1,
10147		                  pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
10148	        return(MODE_BAD);
10149
10150	     if(SiS_CheckModeCRT2(pScrn, ((SiSMergedDisplayModePtr)mode->Private)->CRT2,
10151		                  pSiS->VBFlags, pSiS->HaveCustomModes2) < 0x14)
10152	        return(MODE_BAD);
10153 	  }
10154       } else
10155#endif
10156       {
10157	  if(SiS_CheckModeCRT1(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
10158	     return(MODE_BAD);
10159
10160	  if(SiS_CheckModeCRT2(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
10161	     return(MODE_BAD);
10162       }
10163    }
10164
10165    return(MODE_OK);
10166}
10167
10168#ifdef DEBUG
10169static void
10170SiSDumpModeInfo(ScrnInfoPtr pScrn, DisplayModePtr mode)
10171{
10172    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Clock : %x\n", mode->Clock);
10173    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Display : %x\n", mode->CrtcHDisplay);
10174    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Blank Start : %x\n", mode->CrtcHBlankStart);
10175    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Sync Start : %x\n", mode->CrtcHSyncStart);
10176    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Sync End : %x\n", mode->CrtcHSyncEnd);
10177    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Blank End : %x\n", mode->CrtcHBlankEnd);
10178    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Total : %x\n", mode->CrtcHTotal);
10179    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Skew : %x\n", mode->CrtcHSkew);
10180    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz HAdjusted : %x\n", mode->CrtcHAdjusted);
10181    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Display : %x\n", mode->CrtcVDisplay);
10182    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Blank Start : %x\n", mode->CrtcVBlankStart);
10183    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Sync Start : %x\n", mode->CrtcVSyncStart);
10184    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Sync End : %x\n", mode->CrtcVSyncEnd);
10185    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Blank End : %x\n", mode->CrtcVBlankEnd);
10186    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Total : %x\n", mode->CrtcVTotal);
10187    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt VAdjusted : %x\n", mode->CrtcVAdjusted);
10188}
10189#endif
10190
10191static void
10192SISModifyModeInfo(DisplayModePtr mode)
10193{
10194    if(mode->CrtcHBlankStart == mode->CrtcHDisplay)
10195        mode->CrtcHBlankStart++;
10196    if(mode->CrtcHBlankEnd == mode->CrtcHTotal)
10197        mode->CrtcHBlankEnd--;
10198    if(mode->CrtcVBlankStart == mode->CrtcVDisplay)
10199        mode->CrtcVBlankStart++;
10200    if(mode->CrtcVBlankEnd == mode->CrtcVTotal)
10201        mode->CrtcVBlankEnd--;
10202}
10203
10204/* Enable the Turboqueue/Commandqueue (For 300 and 315/330/340 series only) */
10205static void
10206SiSEnableTurboQueue(ScrnInfoPtr pScrn)
10207{
10208    SISPtr pSiS = SISPTR(pScrn);
10209    UShort SR26, SR27;
10210    ULong  temp;
10211
10212    switch(pSiS->VGAEngine) {
10213	case SIS_300_VGA:
10214	   if((!pSiS->NoAccel) && (pSiS->TurboQueue)) {
10215		/* TQ size is always 512k */
10216		temp = (pScrn->videoRam/64) - 8;
10217		SR26 = temp & 0xFF;
10218		inSISIDXREG(SISSR, 0x27, SR27);
10219		SR27 &= 0xFC;
10220		SR27 |= (0xF0 | ((temp >> 8) & 3));
10221		outSISIDXREG(SISSR, 0x26, SR26);
10222		outSISIDXREG(SISSR, 0x27, SR27);
10223	   }
10224	   break;
10225
10226	case SIS_315_VGA:
10227	   if(!pSiS->NoAccel) {
10228	      /* On 315/330/340 series, there are three queue modes available
10229	       * which are chosen by setting bits 7:5 in SR26:
10230	       * 1. MMIO queue mode (bit 5, 0x20). The hardware will keep
10231	       *    track of the queue, the FIFO, command parsing and so
10232	       *    on. This is the one comparable to the 300 series.
10233	       * 2. VRAM queue mode (bit 6, 0x40). In this case, one will
10234	       *    have to do queue management himself.
10235	       * 3. AGP queue mode (bit 7, 0x80). Works as 2., but keeps the
10236	       *    queue in AGP memory space.
10237	       * We go VRAM or MMIO here.
10238	       * SR26 bit 4 is called "Bypass H/W queue".
10239	       * SR26 bit 1 is called "Enable Command Queue Auto Correction"
10240	       * SR26 bit 0 resets the queue
10241	       * Size of queue memory is encoded in bits 3:2 like this:
10242	       *    00  (0x00)  512K
10243	       *    01  (0x04)  1M
10244	       *    10  (0x08)  2M
10245	       *    11  (0x0C)  4M
10246	       * The queue location is to be written to 0x85C0.
10247	       */
10248#ifdef SISVRAMQ
10249	      /* We use VRAM Cmd Queue, not MMIO or AGP */
10250	      UChar tempCR55 = 0;
10251
10252	      /* Set Command Queue Threshold to max value 11111b (?) */
10253	      outSISIDXREG(SISSR, 0x27, 0x1F);
10254
10255	      /* Disable queue flipping */
10256	      inSISIDXREG(SISCR, 0x55, tempCR55);
10257	      andSISIDXREG(SISCR, 0x55, 0x33);
10258	      /* Synchronous reset for Command Queue */
10259	      outSISIDXREG(SISSR, 0x26, 0x01);
10260	      SIS_MMIO_OUT32(pSiS->IOBase, 0x85c4, 0);
10261	      /* Enable VRAM Command Queue mode */
10262	      if(pSiS->ChipType == XGI_20) {
10263		 /* On XGI_20, always 128K */
10264		 SR26 = 0x40 | 0x04 | 0x01;
10265	      } else {
10266	         switch(pSiS->cmdQueueSize) {
10267		    case 1*1024*1024: SR26 = (0x40 | 0x04 | 0x01); break;
10268		    case 2*1024*1024: SR26 = (0x40 | 0x08 | 0x01); break;
10269		    case 4*1024*1024: SR26 = (0x40 | 0x0C | 0x01); break;
10270		    default:
10271		                      pSiS->cmdQueueSize = 512 * 1024;
10272		    case    512*1024: SR26 = (0x40 | 0x00 | 0x01);
10273	         }
10274	      }
10275	      outSISIDXREG(SISSR, 0x26, SR26);
10276	      SR26 &= 0xfe;
10277	      outSISIDXREG(SISSR, 0x26, SR26);
10278	      *(pSiS->cmdQ_SharedWritePort) = (unsigned int)(SIS_MMIO_IN32(pSiS->IOBase, 0x85c8));
10279	      SIS_MMIO_OUT32(pSiS->IOBase, 0x85c4, (CARD32)(*(pSiS->cmdQ_SharedWritePort)));
10280	      SIS_MMIO_OUT32(pSiS->IOBase, 0x85C0, pSiS->cmdQueueOffset);
10281	      temp = (ULong)pSiS->RealFbBase;
10282#ifdef SISDUALHEAD
10283	      if(pSiS->DualHeadMode) {
10284	         SISEntPtr pSiSEnt = pSiS->entityPrivate;
10285	         temp = (ULong)pSiSEnt->RealFbBase;
10286	      }
10287#endif
10288	      temp += pSiS->cmdQueueOffset;
10289	      pSiS->cmdQueueBase = (unsigned int *)temp;
10290	      outSISIDXREG(SISCR, 0x55, tempCR55);
10291#ifdef TWDEBUG
10292	      xf86DrvMsg(0, 0, "CmdQueueOffs 0x%x, CmdQueueAdd %p, shwrp 0x%x, status %x, base %p\n",
10293		pSiS->cmdQueueOffset, pSiS->cmdQueueBase, *(pSiS->cmdQ_SharedWritePort),
10294		SIS_MMIO_IN32(pSiS->IOBase, 0x85cc), (ULong *)temp);
10295#endif
10296#else
10297	      /* For MMIO */
10298	      /* Syncronous reset for Command Queue */
10299	      orSISIDXREG(SISSR, 0x26, 0x01);
10300	      /* Set Command Queue Threshold to max value 11111b */
10301	      outSISIDXREG(SISSR, 0x27, 0x1F);
10302	      /* Do some magic (cp readport to writeport) */
10303	      temp = SIS_MMIO_IN32(pSiS->IOBase, 0x85C8);
10304	      SIS_MMIO_OUT32(pSiS->IOBase, 0x85C4, temp);
10305	      /* Enable MMIO Command Queue mode (0x20),
10306	       * Enable_command_queue_auto_correction (0x02)
10307	       *        (no idea, but sounds good, so use it)
10308	       * 512k (0x00) (does this apply to MMIO mode?) */
10309	      outSISIDXREG(SISSR, 0x26, 0x22);
10310	      /* Calc Command Queue position (Q is always 512k)*/
10311	      temp = (pScrn->videoRam - 512) * 1024;
10312	      /* Set Q position */
10313	      SIS_MMIO_OUT32(pSiS->IOBase, 0x85C0, temp);
10314#endif
10315	   }
10316	   break;
10317	default:
10318	   break;
10319    }
10320}
10321
10322#ifdef SISVRAMQ
10323static void
10324SiSRestoreQueueMode(SISPtr pSiS, SISRegPtr sisReg)
10325{
10326    UChar tempCR55=0;
10327
10328    if(pSiS->VGAEngine == SIS_315_VGA) {
10329       inSISIDXREG(SISCR,0x55,tempCR55);
10330       andSISIDXREG(SISCR,0x55,0x33);
10331       outSISIDXREG(SISSR,0x26,0x01);
10332       SIS_MMIO_OUT32(pSiS->IOBase, 0x85c4, 0);
10333       outSISIDXREG(SISSR,0x27,sisReg->sisRegs3C4[0x27]);
10334       outSISIDXREG(SISSR,0x26,sisReg->sisRegs3C4[0x26]);
10335       SIS_MMIO_OUT32(pSiS->IOBase, 0x85C0, sisReg->sisMMIO85C0);
10336       outSISIDXREG(SISCR,0x55,tempCR55);
10337    }
10338}
10339#endif
10340
10341/* Things to do before a ModeSwitch. We set up the
10342 * video bridge configuration and the TurboQueue.
10343 */
10344void SiSPreSetMode(ScrnInfoPtr pScrn, DisplayModePtr mode, int viewmode)
10345{
10346    SISPtr pSiS = SISPTR(pScrn);
10347    UChar  CR30, CR31, CR32, CR33;
10348    UChar  CR39 = 0, CR3B = 0;
10349    UChar  CR17, CR38 = 0;
10350    UChar  CR35 = 0, CR79 = 0;
10351    int    temp = 0, crt1rateindex = 0;
10352    ULong  vbflag = pSiS->VBFlags;
10353    Bool   hcm = pSiS->HaveCustomModes;
10354    DisplayModePtr mymode = mode;
10355
10356    pSiS->IsCustom = FALSE;
10357
10358    /* NEVER call this with viewmode = SIS_MODE_SIMU
10359     * if mode->type is not M_T_DEFAULT!
10360     */
10361
10362#ifdef SISMERGED
10363    if(pSiS->MergedFB) {
10364       switch(viewmode) {
10365       case SIS_MODE_CRT1:
10366	  mymode = ((SiSMergedDisplayModePtr)mode->Private)->CRT1;
10367	  break;
10368       case SIS_MODE_CRT2:
10369	  mymode = ((SiSMergedDisplayModePtr)mode->Private)->CRT2;
10370	  hcm = pSiS->HaveCustomModes2;
10371       }
10372    }
10373#endif
10374
10375    switch(viewmode) {
10376    case SIS_MODE_CRT1:
10377       if(SiS_CheckModeCRT1(pScrn, mymode, vbflag, hcm) == 0xfe) {
10378          pSiS->IsCustom = TRUE;
10379       }
10380       break;
10381    case SIS_MODE_CRT2:
10382       if(vbflag & CRT2_ENABLE) {
10383          if(SiS_CheckModeCRT2(pScrn, mymode, vbflag, hcm) == 0xfe) {
10384	     pSiS->IsCustom = TRUE;
10385          }
10386       } else {
10387          /* This can only happen in mirror mode */
10388          if(SiS_CheckModeCRT1(pScrn, mymode, vbflag, hcm) == 0xfe) {
10389             pSiS->IsCustom = TRUE;
10390          }
10391       }
10392    }
10393
10394#ifdef UNLOCK_ALWAYS
10395    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);    /* Unlock Registers */
10396#endif
10397
10398    inSISIDXREG(SISCR, 0x30, CR30);
10399    inSISIDXREG(SISCR, 0x31, CR31);
10400    CR32 = pSiS->newCR32;
10401    inSISIDXREG(SISCR, 0x33, CR33);
10402
10403    if(pSiS->NewCRLayout) {
10404
10405       inSISIDXREG(SISCR, 0x35, CR35);
10406       inSISIDXREG(SISCR, 0x38, CR38);
10407       inSISIDXREG(SISCR, 0x39, CR39);
10408
10409       xf86DrvMsgVerb(pScrn->scrnIndex, X_PROBED, SISVERBLEVEL,
10410	   "Before: CR30=0x%02x,CR31=0x%02x,CR32=0x%02x,CR33=0x%02x,CR35=0x%02x,CR38=0x%02x\n",
10411              CR30, CR31, CR32, CR33, CR35, CR38);
10412
10413       CR38 &= ~0x07;
10414
10415    } else {
10416
10417       if(pSiS->Chipset != PCI_CHIP_SIS300) {
10418          switch(pSiS->VGAEngine) {
10419             case SIS_300_VGA: temp = 0x35; break;
10420             case SIS_315_VGA: temp = 0x38; break;
10421          }
10422          if(temp) inSISIDXREG(SISCR, temp, CR38);
10423       }
10424       if(pSiS->VGAEngine == SIS_315_VGA) {
10425          inSISIDXREG(SISCR, 0x79, CR79);
10426          CR38 &= ~0x3b;   			/* Clear LCDA/DualEdge and YPbPr bits */
10427       }
10428       inSISIDXREG(SISCR, 0x3b, CR3B);
10429
10430       xf86DrvMsgVerb(pScrn->scrnIndex, X_PROBED, SISVERBLEVEL,
10431	   "Before: CR30=0x%02x, CR31=0x%02x, CR32=0x%02x, CR33=0x%02x, CR%02x=0x%02x\n",
10432              CR30, CR31, CR32, CR33, temp, CR38);
10433    }
10434
10435    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, SISVERBLEVEL, "VBFlags=0x%x\n", pSiS->VBFlags);
10436
10437    CR30 = 0x00;
10438    CR31 &= ~0x60;  /* Clear VB_Drivermode & VB_OutputDisable */
10439    CR31 |= 0x04;   /* Set VB_NotSimuMode (not for 30xB/1400x1050?) */
10440    CR35 = 0x00;
10441
10442    if(!pSiS->NewCRLayout) {
10443       if(!pSiS->AllowHotkey) {
10444          CR31 |= 0x80;   /* Disable hotkey-switch */
10445       }
10446       CR79 &= ~0x10;     /* Enable Backlight control on 315 series */
10447    }
10448
10449    SiS_SetEnableDstn(pSiS->SiS_Pr, FALSE);
10450    SiS_SetEnableFstn(pSiS->SiS_Pr, FALSE);
10451
10452    if((vbflag & CRT1_LCDA) && (viewmode == SIS_MODE_CRT1)) {
10453
10454       CR38 |= 0x02;
10455
10456    } else {
10457
10458       switch(vbflag & (CRT2_TV|CRT2_LCD|CRT2_VGA)) {
10459
10460       case CRT2_TV:
10461
10462          CR38 &= ~0xC0; 	/* Clear Pal M/N bits */
10463
10464          if((pSiS->VBFlags2 & VB2_CHRONTEL) && (vbflag & TV_CHSCART)) {		/* Chrontel */
10465	     CR30 |= 0x10;
10466	     CR38 |= 0x04;
10467	     CR38 &= ~0x08;
10468	     CR31 |= 0x01;
10469	  } else if((pSiS->VBFlags2 & VB2_CHRONTEL) && (vbflag & TV_CHYPBPR525I)) {	/* Chrontel */
10470	     CR38 |= 0x08;
10471	     CR38 &= ~0x04;
10472	     CR31 &= ~0x01;
10473          } else if(vbflag & TV_HIVISION) {	/* SiS bridge */
10474	     if(pSiS->NewCRLayout) {
10475	        CR38 |= 0x04;
10476	        CR35 |= 0x60;
10477	     } else {
10478	        CR30 |= 0x80;
10479		if(pSiS->VGAEngine == SIS_315_VGA) {
10480		   if(pSiS->VBFlags2 & VB2_SISYPBPRBRIDGE) {
10481		      CR38 |= (0x08 | 0x30);
10482		   }
10483		}
10484	     }
10485	     CR31 |= 0x01;
10486	     CR35 |= 0x01;
10487	  } else if(vbflag & TV_YPBPR) {					/* SiS bridge */
10488	     if(pSiS->NewCRLayout) {
10489		CR38 |= 0x04;
10490		CR31 &= ~0x01;
10491		CR35 &= ~0x01;
10492		if(vbflag & (TV_YPBPR525P | TV_YPBPR625P)) CR35 |= 0x20;
10493		else if(vbflag & TV_YPBPR750P)             CR35 |= 0x40;
10494		else if(vbflag & TV_YPBPR1080I)            CR35 |= 0x60;
10495
10496		if(vbflag & (TV_YPBPR625I | TV_YPBPR625P)) {
10497		   CR31 |= 0x01;
10498		   CR35 |= 0x01;
10499		}
10500
10501		CR39 &= ~0x03;
10502		if((vbflag & TV_YPBPRAR) == TV_YPBPR43LB)     CR39 |= 0x00;
10503		else if((vbflag & TV_YPBPRAR) == TV_YPBPR43)  CR39 |= 0x01;
10504		else if((vbflag & TV_YPBPRAR) == TV_YPBPR169) CR39 |= 0x02;
10505		else					      CR39 |= 0x03;
10506	     } else if(pSiS->SiS_SD_Flags & SiS_SD_SUPPORTYPBPR) {
10507		CR30 |= 0x80;
10508		CR38 |= 0x08;
10509		CR31 &= ~0x01;
10510		if(vbflag & (TV_YPBPR525P|TV_YPBPR625P)) CR38 |= 0x10;
10511		else if(vbflag & TV_YPBPR750P)  	 CR38 |= 0x20;
10512		else if(vbflag & TV_YPBPR1080I)		 CR38 |= 0x30;
10513
10514		if(vbflag & (TV_YPBPR625I | TV_YPBPR625P)) CR31 |= 0x01;
10515
10516		if(pSiS->SiS_SD_Flags & SiS_SD_SUPPORTYPBPRAR) {
10517		   CR3B &= ~0x03;
10518		   if((vbflag & TV_YPBPRAR) == TV_YPBPR43LB)     CR3B |= 0x00;
10519		   else if((vbflag & TV_YPBPRAR) == TV_YPBPR43)  CR3B |= 0x03;
10520		   else if((vbflag & TV_YPBPRAR) == TV_YPBPR169) CR3B |= 0x01;
10521		   else					         CR3B |= 0x03;
10522		}
10523	     }
10524          } else {								/* All */
10525	     if(vbflag & TV_SCART)  CR30 |= 0x10;
10526	     if(vbflag & TV_SVIDEO) CR30 |= 0x08;
10527	     if(vbflag & TV_AVIDEO) CR30 |= 0x04;
10528	     if(!(CR30 & 0x1C))	    CR30 |= 0x08;    /* default: SVIDEO */
10529
10530	     if(vbflag & TV_PAL) {
10531		CR31 |= 0x01;
10532		CR35 |= 0x01;
10533		if( (pSiS->VBFlags2 & VB2_SISBRIDGE) ||
10534		    ((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->ChrontelType == CHRONTEL_701x)) )  {
10535		   if(vbflag & TV_PALM) {
10536		      CR38 |= 0x40;
10537		      CR35 |= 0x04;
10538		   } else if(vbflag & TV_PALN) {
10539		      CR38 |= 0x80;
10540		      CR35 |= 0x08;
10541		   }
10542	        }
10543	     } else {
10544		CR31 &= ~0x01;
10545		CR35 &= ~0x01;
10546		if(vbflag & TV_NTSCJ) {
10547		   CR38 |= 0x40;  /* TW, not BIOS */
10548		   CR35 |= 0x02;
10549		}
10550	     }
10551	     if(vbflag & TV_SCART) {
10552		CR31 |= 0x01;
10553		CR35 |= 0x01;
10554	     }
10555	  }
10556
10557	  CR31 &= ~0x04;   /* Clear NotSimuMode */
10558	  pSiS->SiS_Pr->SiS_CHOverScan = pSiS->UseCHOverScan;
10559	  if((pSiS->OptTVSOver == 1) && (pSiS->ChrontelType == CHRONTEL_700x)) {
10560	     pSiS->SiS_Pr->SiS_CHSOverScan = TRUE;
10561	  } else {
10562	     pSiS->SiS_Pr->SiS_CHSOverScan = FALSE;
10563	  }
10564#ifdef SIS_CP
10565	  SIS_CP_DRIVER_CONFIG
10566#endif
10567	  break;
10568
10569       case CRT2_LCD:
10570	  CR30 |= 0x20;
10571	  SiS_SetEnableDstn(pSiS->SiS_Pr, pSiS->DSTN);
10572	  SiS_SetEnableFstn(pSiS->SiS_Pr, pSiS->FSTN);
10573	  break;
10574
10575       case CRT2_VGA:
10576	  CR30 |= 0x40;
10577	  break;
10578
10579       default:
10580	  CR30 |= 0x00;
10581	  CR31 |= 0x20;    /* VB_OUTPUT_DISABLE */
10582	  if(pSiS->UseVESA) {
10583	     crt1rateindex = SISSearchCRT1Rate(pScrn, mymode);
10584	  }
10585       }
10586
10587    }
10588
10589    if(vbflag & CRT1_LCDA) {
10590       switch(viewmode) {
10591       case SIS_MODE_CRT1:
10592	  CR38 |= 0x01;
10593	  break;
10594       case SIS_MODE_CRT2:
10595	  if(vbflag & (CRT2_TV|CRT2_VGA)) {
10596	     CR30 |= 0x02;
10597	     CR38 |= 0x01;
10598	  } else {
10599	     CR38 |= 0x03;
10600	  }
10601	  break;
10602       case SIS_MODE_SIMU:
10603       default:
10604	  if(vbflag & (CRT2_TV|CRT2_LCD|CRT2_VGA)) {
10605	     CR30 |= 0x01;
10606	  }
10607	  break;
10608       }
10609    } else {
10610       if(vbflag & (CRT2_TV|CRT2_LCD|CRT2_VGA)) {
10611          CR30 |= 0x01;
10612       }
10613    }
10614
10615    if(pSiS->UseVESA) {
10616       CR31 &= ~0x40;   /* Clear Drivermode */
10617       CR31 |= 0x06;    /* Set SlaveMode, Enable SimuMode in Slavemode */
10618#ifdef TWDEBUG
10619       CR31 |= 0x40;    /* DEBUG (for non-slave mode VESA) */
10620       crt1rateindex = SISSearchCRT1Rate(pScrn, mymode);
10621#endif
10622    } else {
10623       CR31 |=  0x40;  /* Set Drivermode */
10624       CR31 &=  ~0x06; /* Disable SlaveMode, disable SimuMode in SlaveMode */
10625       if(!pSiS->IsCustom) {
10626          crt1rateindex = SISSearchCRT1Rate(pScrn, mymode);
10627       }
10628    }
10629
10630    switch(viewmode) {
10631	case SIS_MODE_SIMU:
10632	   CR33 = 0;
10633	   if(!(vbflag & CRT1_LCDA)) {
10634	      CR33 |= (crt1rateindex & 0x0f);
10635	   }
10636	   if(vbflag & CRT2_VGA) {
10637	      CR33 |= ((crt1rateindex & 0x0f) << 4);
10638	   }
10639	   break;
10640	case SIS_MODE_CRT1:
10641	   CR33 &= 0xf0;
10642	   if(!(vbflag & CRT1_LCDA)) {
10643	      CR33 |= (crt1rateindex & 0x0f);
10644	   }
10645	   break;
10646	case SIS_MODE_CRT2:
10647	   CR33 &= 0x0f;
10648	   if(vbflag & CRT2_VGA) {
10649	      CR33 |= ((crt1rateindex & 0x0f) << 4);
10650	   }
10651	   break;
10652     }
10653
10654     if((!pSiS->UseVESA) && (vbflag & CRT2_ENABLE)) {
10655	if(pSiS->CRT1off) CR33 &= 0xf0;
10656     }
10657
10658     if(pSiS->NewCRLayout) {
10659
10660	CR31 &= 0xfe;   /* Clear PAL flag (now in CR35) */
10661	CR38 &= 0x07;   /* Use only LCDA and HiVision/YPbPr bits */
10662	outSISIDXREG(SISCR, 0x30, CR30);
10663	outSISIDXREG(SISCR, 0x31, CR31);
10664	outSISIDXREG(SISCR, 0x33, CR33);
10665	outSISIDXREG(SISCR, 0x35, CR35);
10666	setSISIDXREG(SISCR, 0x38, 0xf8, CR38);
10667	outSISIDXREG(SISCR, 0x39, CR39);
10668
10669	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, SISVERBLEVEL,
10670		"After:  CR30=0x%02x,CR31=0x%02x,CR33=0x%02x,CR35=0x%02x,CR38=%02x\n",
10671		    CR30, CR31, CR33, CR35, CR38);
10672
10673     } else {
10674
10675	outSISIDXREG(SISCR, 0x30, CR30);
10676	outSISIDXREG(SISCR, 0x31, CR31);
10677	outSISIDXREG(SISCR, 0x33, CR33);
10678	if(temp) {
10679	   outSISIDXREG(SISCR, temp, CR38);
10680	}
10681	if(pSiS->VGAEngine == SIS_315_VGA) {
10682	   outSISIDXREG(SISCR, 0x3b, CR3B);
10683	   outSISIDXREG(SISCR, 0x79, CR79);
10684	}
10685
10686	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, SISVERBLEVEL,
10687		"After:  CR30=0x%02x,CR31=0x%02x,CR33=0x%02x,CR%02x=%02x\n",
10688		    CR30, CR31, CR33, temp, CR38);
10689     }
10690
10691     pSiS->SiS_Pr->SiS_UseOEM = pSiS->OptUseOEM;
10692
10693     /* Enable TurboQueue */
10694#ifdef SISVRAMQ
10695     if(pSiS->VGAEngine != SIS_315_VGA)
10696#endif
10697	SiSEnableTurboQueue(pScrn);
10698
10699     if((!pSiS->UseVESA) && (pSiS->VBFlags & CRT2_ENABLE)) {
10700	/* Switch on CRT1 for modes that require the bridge in SlaveMode */
10701	andSISIDXREG(SISSR,0x1f,0x3f);
10702	inSISIDXREG(SISCR, 0x17, CR17);
10703	if(!(CR17 & 0x80)) {
10704	   orSISIDXREG(SISCR, 0x17, 0x80);
10705	   outSISIDXREG(SISSR, 0x00, 0x01);
10706	   usleep(10000);
10707	   outSISIDXREG(SISSR, 0x00, 0x03);
10708	}
10709     }
10710}
10711
10712/* Functions for adjusting various TV settings */
10713
10714/* These are used by the PostSetMode() functions as well as
10715 * the display properties tool SiSCtrl.
10716 *
10717 * There is each a Set and a Get routine. The Set functions
10718 * take a value of the same range as the corresponding option.
10719 * The Get routines return a value of the same range (although
10720 * not necessarily the same value as previously set because
10721 * of the lower resolution of the respective setting compared
10722 * to the valid range).
10723 * The Get routines return -2 on error (eg. hardware does not
10724 * support this setting).
10725 * Note: The x and y positioning routines accept a position
10726 * RELATIVE to the default position. All other routines
10727 * take ABSOLUTE values.
10728 *
10729 * The Set functions will store the property regardless if TV is
10730 * currently used or not and if the hardware supports the property
10731 * or not. The Get routines will return this stored
10732 * value if TV is not currently used (because the register does
10733 * not contain the correct value then) or if the hardware supports
10734 * the respective property. This should make it easier for the
10735 * display property tool because it does not have to know the
10736 * hardware features.
10737 *
10738 * All the routines are dual head aware. It does not matter
10739 * if the function is called from the CRT1 or CRT2 session.
10740 * The values will be in pSiSEnt anyway, and read from there
10741 * if we're running dual head.
10742 */
10743
10744void SiS_SetCHTVlumabandwidthcvbs(ScrnInfoPtr pScrn, int val)
10745{
10746   SISPtr pSiS = SISPTR(pScrn);
10747#ifdef SISDUALHEAD
10748   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10749#endif
10750
10751   pSiS->chtvlumabandwidthcvbs = val;
10752#ifdef SISDUALHEAD
10753   if(pSiSEnt) pSiSEnt->chtvlumabandwidthcvbs = val;
10754#endif
10755
10756   if(!(pSiS->VBFlags & CRT2_TV)) return;
10757   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
10758
10759#ifdef UNLOCK_ALWAYS
10760   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10761#endif
10762
10763   switch(pSiS->ChrontelType) {
10764       case CHRONTEL_700x:
10765           val /= 8;
10766           if((val == 0) || (val == 1)) {
10767	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, val, 0xFE);
10768           }
10769	   break;
10770       case CHRONTEL_701x:
10771           val /= 4;
10772	   if((val >= 0) && (val <= 3)) {
10773	       SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x02, val, 0xFC);
10774	   }
10775           break;
10776   }
10777}
10778
10779int SiS_GetCHTVlumabandwidthcvbs(ScrnInfoPtr pScrn)
10780{
10781   SISPtr pSiS = SISPTR(pScrn);
10782#ifdef SISDUALHEAD
10783   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10784#endif
10785
10786   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
10787#ifdef SISDUALHEAD
10788      if(pSiSEnt && pSiS->DualHeadMode)
10789           return (int)pSiSEnt->chtvlumabandwidthcvbs;
10790      else
10791#endif
10792           return (int)pSiS->chtvlumabandwidthcvbs;
10793   } else {
10794#ifdef UNLOCK_ALWAYS
10795      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10796#endif
10797      switch(pSiS->ChrontelType) {
10798      case CHRONTEL_700x:
10799           return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x03) & 0x01) * 8);
10800      case CHRONTEL_701x:
10801	   return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x02) & 0x03) * 4);
10802      default:
10803           return (int)pSiS->chtvlumabandwidthcvbs;
10804      }
10805   }
10806}
10807
10808void SiS_SetCHTVlumabandwidthsvideo(ScrnInfoPtr pScrn, int val)
10809{
10810   SISPtr pSiS = SISPTR(pScrn);
10811#ifdef SISDUALHEAD
10812   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10813#endif
10814
10815   pSiS->chtvlumabandwidthsvideo = val;
10816#ifdef SISDUALHEAD
10817   if(pSiSEnt) pSiSEnt->chtvlumabandwidthsvideo = val;
10818#endif
10819
10820   if(!(pSiS->VBFlags & CRT2_TV)) return;
10821   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
10822
10823#ifdef UNLOCK_ALWAYS
10824   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10825#endif
10826
10827   switch(pSiS->ChrontelType) {
10828       case CHRONTEL_700x:
10829           val /= 6;
10830           if((val >= 0) && (val <= 2)) {
10831	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, (val << 1), 0xF9);
10832           }
10833	   break;
10834       case CHRONTEL_701x:
10835           val /= 4;
10836	   if((val >= 0) && (val <= 3)) {
10837	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x02, (val << 2), 0xF3);
10838	   }
10839           break;
10840   }
10841}
10842
10843int SiS_GetCHTVlumabandwidthsvideo(ScrnInfoPtr pScrn)
10844{
10845   SISPtr pSiS = SISPTR(pScrn);
10846#ifdef SISDUALHEAD
10847   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10848#endif
10849
10850   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
10851#ifdef SISDUALHEAD
10852      if(pSiSEnt && pSiS->DualHeadMode)
10853           return (int)pSiSEnt->chtvlumabandwidthsvideo;
10854      else
10855#endif
10856           return (int)pSiS->chtvlumabandwidthsvideo;
10857   } else {
10858#ifdef UNLOCK_ALWAYS
10859      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10860#endif
10861      switch(pSiS->ChrontelType) {
10862      case CHRONTEL_700x:
10863           return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x03) & 0x06) >> 1) * 6);
10864      case CHRONTEL_701x:
10865	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x02) & 0x0c) >> 2) * 4);
10866      default:
10867           return (int)pSiS->chtvlumabandwidthsvideo;
10868      }
10869   }
10870}
10871
10872void SiS_SetCHTVlumaflickerfilter(ScrnInfoPtr pScrn, int val)
10873{
10874   SISPtr pSiS = SISPTR(pScrn);
10875#ifdef SISDUALHEAD
10876   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10877#endif
10878
10879   pSiS->chtvlumaflickerfilter = val;
10880#ifdef SISDUALHEAD
10881   if(pSiSEnt) pSiSEnt->chtvlumaflickerfilter = val;
10882#endif
10883
10884   if(!(pSiS->VBFlags & CRT2_TV)) return;
10885   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
10886
10887#ifdef UNLOCK_ALWAYS
10888   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10889#endif
10890
10891   switch(pSiS->ChrontelType) {
10892       case CHRONTEL_700x:
10893           val /= 6;
10894           if((val >= 0) && (val <= 2)) {
10895	      UShort reg = 0;
10896	      reg = SiS_GetCH70xx(pSiS->SiS_Pr, 0x01);
10897	      reg = (reg & 0xf0) | ((reg & 0x0c) >> 2) | (val << 2);
10898              SiS_SetCH70xx(pSiS->SiS_Pr, 0x01, reg);
10899           }
10900	   break;
10901       case CHRONTEL_701x:
10902           val /= 4;
10903	   if((val >= 0) && (val <= 3)) {
10904	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x01, (val << 2), 0xF3);
10905	   }
10906           break;
10907   }
10908}
10909
10910int SiS_GetCHTVlumaflickerfilter(ScrnInfoPtr pScrn)
10911{
10912   SISPtr pSiS = SISPTR(pScrn);
10913#ifdef SISDUALHEAD
10914   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10915#endif
10916
10917   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
10918#ifdef SISDUALHEAD
10919      if(pSiSEnt && pSiS->DualHeadMode)
10920          return (int)pSiSEnt->chtvlumaflickerfilter;
10921      else
10922#endif
10923          return (int)pSiS->chtvlumaflickerfilter;
10924   } else {
10925#ifdef UNLOCK_ALWAYS
10926      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10927#endif
10928      switch(pSiS->ChrontelType) {
10929      case CHRONTEL_700x:
10930           return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x01) & 0x03) * 6);
10931      case CHRONTEL_701x:
10932	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x01) & 0x0c) >> 2) * 4);
10933      default:
10934           return (int)pSiS->chtvlumaflickerfilter;
10935      }
10936   }
10937}
10938
10939void SiS_SetCHTVchromabandwidth(ScrnInfoPtr pScrn, int val)
10940{
10941   SISPtr pSiS = SISPTR(pScrn);
10942#ifdef SISDUALHEAD
10943   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10944#endif
10945
10946   pSiS->chtvchromabandwidth = val;
10947#ifdef SISDUALHEAD
10948   if(pSiSEnt) pSiSEnt->chtvchromabandwidth = val;
10949#endif
10950
10951   if(!(pSiS->VBFlags & CRT2_TV)) return;
10952   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
10953
10954#ifdef UNLOCK_ALWAYS
10955   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10956#endif
10957
10958   switch(pSiS->ChrontelType) {
10959       case CHRONTEL_700x:
10960           val /= 4;
10961           if((val >= 0) && (val <= 3)) {
10962              SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, (val << 4), 0xCF);
10963           }
10964	   break;
10965       case CHRONTEL_701x:
10966           val /= 8;
10967	   if((val >= 0) && (val <= 1)) {
10968	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x02, (val << 4), 0xEF);
10969	   }
10970           break;
10971   }
10972}
10973
10974int SiS_GetCHTVchromabandwidth(ScrnInfoPtr pScrn)
10975{
10976   SISPtr pSiS = SISPTR(pScrn);
10977#ifdef SISDUALHEAD
10978   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10979#endif
10980
10981   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
10982#ifdef SISDUALHEAD
10983      if(pSiSEnt && pSiS->DualHeadMode)
10984           return (int)pSiSEnt->chtvchromabandwidth;
10985      else
10986#endif
10987           return (int)pSiS->chtvchromabandwidth;
10988   } else {
10989#ifdef UNLOCK_ALWAYS
10990      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10991#endif
10992      switch(pSiS->ChrontelType) {
10993      case CHRONTEL_700x:
10994           return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x03) & 0x30) >> 4) * 4);
10995      case CHRONTEL_701x:
10996	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x02) & 0x10) >> 4) * 8);
10997      default:
10998           return (int)pSiS->chtvchromabandwidth;
10999      }
11000   }
11001}
11002
11003void SiS_SetCHTVchromaflickerfilter(ScrnInfoPtr pScrn, int val)
11004{
11005   SISPtr pSiS = SISPTR(pScrn);
11006#ifdef SISDUALHEAD
11007   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11008#endif
11009
11010   pSiS->chtvchromaflickerfilter = val;
11011#ifdef SISDUALHEAD
11012   if(pSiSEnt) pSiSEnt->chtvchromaflickerfilter = val;
11013#endif
11014
11015   if(!(pSiS->VBFlags & CRT2_TV)) return;
11016   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
11017
11018#ifdef UNLOCK_ALWAYS
11019   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11020#endif
11021
11022   switch(pSiS->ChrontelType) {
11023       case CHRONTEL_700x:
11024           val /= 6;
11025           if((val >= 0) && (val <= 2)) {
11026	      UShort reg = 0;
11027	      reg = SiS_GetCH70xx(pSiS->SiS_Pr, 0x01);
11028	      reg = (reg & 0xc0) | ((reg & 0x0c) >> 2) | ((reg & 0x03) << 2) | (val << 4);
11029              SiS_SetCH70xx(pSiS->SiS_Pr, 0x01, reg);
11030           }
11031	   break;
11032       case CHRONTEL_701x:
11033           val /= 4;
11034	   if((val >= 0) && (val <= 3)) {
11035	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x01, (val << 4), 0xCF);
11036	   }
11037           break;
11038   }
11039}
11040
11041int SiS_GetCHTVchromaflickerfilter(ScrnInfoPtr pScrn)
11042{
11043   SISPtr pSiS = SISPTR(pScrn);
11044#ifdef SISDUALHEAD
11045   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11046#endif
11047
11048   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
11049#ifdef SISDUALHEAD
11050      if(pSiSEnt && pSiS->DualHeadMode)
11051           return (int)pSiSEnt->chtvchromaflickerfilter;
11052      else
11053#endif
11054           return (int)pSiS->chtvchromaflickerfilter;
11055   } else {
11056#ifdef UNLOCK_ALWAYS
11057      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11058#endif
11059      switch(pSiS->ChrontelType) {
11060      case CHRONTEL_700x:
11061           return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x01) & 0x30) >> 4) * 6);
11062      case CHRONTEL_701x:
11063	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x01) & 0x30) >> 4) * 4);
11064      default:
11065           return (int)pSiS->chtvchromaflickerfilter;
11066      }
11067   }
11068}
11069
11070void SiS_SetCHTVcvbscolor(ScrnInfoPtr pScrn, int val)
11071{
11072   SISPtr pSiS = SISPTR(pScrn);
11073#ifdef SISDUALHEAD
11074   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11075#endif
11076
11077   pSiS->chtvcvbscolor = val ? 1 : 0;
11078#ifdef SISDUALHEAD
11079   if(pSiSEnt) pSiSEnt->chtvcvbscolor = pSiS->chtvcvbscolor;
11080#endif
11081
11082   if(!(pSiS->VBFlags & CRT2_TV)) return;
11083   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
11084
11085#ifdef UNLOCK_ALWAYS
11086   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11087#endif
11088
11089   switch(pSiS->ChrontelType) {
11090       case CHRONTEL_700x:
11091           if(!val)  SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, 0x40, 0x00);
11092           else      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, 0x00, ~0x40);
11093	   break;
11094       case CHRONTEL_701x:
11095           if(!val)  SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x02, 0x00, ~0x20);
11096	   else      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x02, 0x20, 0x00);
11097           break;
11098   }
11099}
11100
11101int SiS_GetCHTVcvbscolor(ScrnInfoPtr pScrn)
11102{
11103   SISPtr pSiS = SISPTR(pScrn);
11104#ifdef SISDUALHEAD
11105   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11106#endif
11107
11108   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
11109#ifdef SISDUALHEAD
11110      if(pSiSEnt && pSiS->DualHeadMode)
11111           return (int)pSiSEnt->chtvcvbscolor;
11112      else
11113#endif
11114           return (int)pSiS->chtvcvbscolor;
11115   } else {
11116#ifdef UNLOCK_ALWAYS
11117      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11118#endif
11119      switch(pSiS->ChrontelType) {
11120      case CHRONTEL_700x:
11121           return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x03) & 0x40) >> 6) ^ 0x01);
11122      case CHRONTEL_701x:
11123	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x02) & 0x20) >> 5) ^ 0x01);
11124      default:
11125           return (int)pSiS->chtvcvbscolor;
11126      }
11127   }
11128}
11129
11130void SiS_SetCHTVtextenhance(ScrnInfoPtr pScrn, int val)
11131{
11132   SISPtr pSiS = SISPTR(pScrn);
11133#ifdef SISDUALHEAD
11134   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11135#endif
11136
11137   pSiS->chtvtextenhance = val;
11138#ifdef SISDUALHEAD
11139   if(pSiSEnt) pSiSEnt->chtvtextenhance = val;
11140#endif
11141
11142   if(!(pSiS->VBFlags & CRT2_TV)) return;
11143   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
11144
11145#ifdef UNLOCK_ALWAYS
11146   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11147#endif
11148
11149   switch(pSiS->ChrontelType) {
11150       case CHRONTEL_700x:
11151           val /= 6;
11152           if((val >= 0) && (val <= 2)) {
11153	      UShort reg = 0;
11154	      reg = SiS_GetCH70xx(pSiS->SiS_Pr, 0x01);
11155	      reg = (reg & 0xf0) | ((reg & 0x03) << 2) | val;
11156              SiS_SetCH70xx(pSiS->SiS_Pr, 0x01, reg);
11157           }
11158	   break;
11159       case CHRONTEL_701x:
11160           val /= 2;
11161	   if((val >= 0) && (val <= 7)) {
11162	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, val, 0xF8);
11163	   }
11164           break;
11165   }
11166}
11167
11168int SiS_GetCHTVtextenhance(ScrnInfoPtr pScrn)
11169{
11170   SISPtr pSiS = SISPTR(pScrn);
11171#ifdef SISDUALHEAD
11172   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11173#endif
11174
11175   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
11176#ifdef SISDUALHEAD
11177      if(pSiSEnt && pSiS->DualHeadMode)
11178           return (int)pSiSEnt->chtvtextenhance;
11179      else
11180#endif
11181           return (int)pSiS->chtvtextenhance;
11182   } else {
11183#ifdef UNLOCK_ALWAYS
11184      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11185#endif
11186      switch(pSiS->ChrontelType) {
11187      case CHRONTEL_700x:
11188	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x01) & 0x0c) >> 2) * 6);
11189      case CHRONTEL_701x:
11190	   return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x03) & 0x07) * 2);
11191      default:
11192           return (int)pSiS->chtvtextenhance;
11193      }
11194   }
11195}
11196
11197void SiS_SetCHTVcontrast(ScrnInfoPtr pScrn, int val)
11198{
11199   SISPtr pSiS = SISPTR(pScrn);
11200#ifdef SISDUALHEAD
11201   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11202#endif
11203
11204   pSiS->chtvcontrast = val;
11205#ifdef SISDUALHEAD
11206   if(pSiSEnt) pSiSEnt->chtvcontrast = val;
11207#endif
11208
11209   if(!(pSiS->VBFlags & CRT2_TV)) return;
11210   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
11211
11212#ifdef UNLOCK_ALWAYS
11213   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11214#endif
11215
11216   val /= 2;
11217   if((val >= 0) && (val <= 7)) {
11218       switch(pSiS->ChrontelType) {
11219       case CHRONTEL_700x:
11220              SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x11, val, 0xF8);
11221	      break;
11222       case CHRONTEL_701x:
11223	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x08, val, 0xF8);
11224              break;
11225       }
11226       SiS_DDC2Delay(pSiS->SiS_Pr, 1000);
11227   }
11228}
11229
11230int SiS_GetCHTVcontrast(ScrnInfoPtr pScrn)
11231{
11232   SISPtr pSiS = SISPTR(pScrn);
11233#ifdef SISDUALHEAD
11234   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11235#endif
11236
11237   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
11238#ifdef SISDUALHEAD
11239      if(pSiSEnt && pSiS->DualHeadMode)
11240           return (int)pSiSEnt->chtvcontrast;
11241      else
11242#endif
11243           return (int)pSiS->chtvcontrast;
11244   } else {
11245#ifdef UNLOCK_ALWAYS
11246      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11247#endif
11248      switch(pSiS->ChrontelType) {
11249      case CHRONTEL_700x:
11250           return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x11) & 0x07) * 2);
11251      case CHRONTEL_701x:
11252	   return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x08) & 0x07) * 2);
11253      default:
11254           return (int)pSiS->chtvcontrast;
11255      }
11256   }
11257}
11258
11259void SiS_SetSISTVedgeenhance(ScrnInfoPtr pScrn, int val)
11260{
11261   SISPtr pSiS = SISPTR(pScrn);
11262#ifdef SISDUALHEAD
11263   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11264#endif
11265
11266   pSiS->sistvedgeenhance = val;
11267#ifdef SISDUALHEAD
11268   if(pSiSEnt) pSiSEnt->sistvedgeenhance = val;
11269#endif
11270
11271   if(!(pSiS->VBFlags2 & VB2_301))  return;
11272   if(!(pSiS->VBFlags & CRT2_TV))   return;
11273
11274#ifdef UNLOCK_ALWAYS
11275   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11276#endif
11277
11278   val /= 2;
11279   if((val >= 0) && (val <= 7)) {
11280      setSISIDXREG(SISPART2,0x3A, 0x1F, (val << 5));
11281   }
11282}
11283
11284int SiS_GetSISTVedgeenhance(ScrnInfoPtr pScrn)
11285{
11286   SISPtr pSiS = SISPTR(pScrn);
11287   int result = pSiS->sistvedgeenhance;
11288   UChar temp;
11289#ifdef SISDUALHEAD
11290   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11291
11292   if(pSiSEnt && pSiS->DualHeadMode) result = pSiSEnt->sistvedgeenhance;
11293#endif
11294
11295   if(!(pSiS->VBFlags2 & VB2_301))  return result;
11296   if(!(pSiS->VBFlags & CRT2_TV))   return result;
11297
11298#ifdef UNLOCK_ALWAYS
11299   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11300#endif
11301   inSISIDXREG(SISPART2, 0x3a, temp);
11302   return(int)(((temp & 0xe0) >> 5) * 2);
11303}
11304
11305void SiS_SetSISTVantiflicker(ScrnInfoPtr pScrn, int val)
11306{
11307   SISPtr pSiS = SISPTR(pScrn);
11308#ifdef SISDUALHEAD
11309   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11310#endif
11311
11312   pSiS->sistvantiflicker = val;
11313#ifdef SISDUALHEAD
11314   if(pSiSEnt) pSiSEnt->sistvantiflicker = val;
11315#endif
11316
11317   if(!(pSiS->VBFlags & CRT2_TV))      return;
11318   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE)) return;
11319   if(pSiS->VBFlags & TV_HIVISION)     return;
11320   if((pSiS->VBFlags & TV_YPBPR) &&
11321      (pSiS->VBFlags & (TV_YPBPR525P | TV_YPBPR625P | TV_YPBPR750P | TV_YPBPR1080I))) return;
11322
11323#ifdef UNLOCK_ALWAYS
11324   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11325#endif
11326
11327   /* Valid values: 0=off, 1=low, 2=med, 3=high, 4=adaptive */
11328   if((val >= 0) && (val <= 4)) {
11329      setSISIDXREG(SISPART2,0x0A,0x8F, (val << 4));
11330   }
11331}
11332
11333int SiS_GetSISTVantiflicker(ScrnInfoPtr pScrn)
11334{
11335   SISPtr pSiS = SISPTR(pScrn);
11336   int result = pSiS->sistvantiflicker;
11337   UChar temp;
11338#ifdef SISDUALHEAD
11339   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11340
11341   if(pSiSEnt && pSiS->DualHeadMode) result = pSiSEnt->sistvantiflicker;
11342#endif
11343
11344   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE)) return result;
11345   if(!(pSiS->VBFlags & CRT2_TV))        return result;
11346   if(pSiS->VBFlags & TV_HIVISION)       return result;
11347   if((pSiS->VBFlags & TV_YPBPR) &&
11348      (pSiS->VBFlags & (TV_YPBPR525P | TV_YPBPR625P | TV_YPBPR750P | TV_YPBPR1080I))) return result;
11349
11350#ifdef UNLOCK_ALWAYS
11351   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11352#endif
11353   inSISIDXREG(SISPART2, 0x0a, temp);
11354   return(int)((temp & 0x70) >> 4);
11355}
11356
11357void SiS_SetSISTVsaturation(ScrnInfoPtr pScrn, int val)
11358{
11359   SISPtr pSiS = SISPTR(pScrn);
11360#ifdef SISDUALHEAD
11361   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11362#endif
11363
11364   pSiS->sistvsaturation = val;
11365#ifdef SISDUALHEAD
11366   if(pSiSEnt) pSiSEnt->sistvsaturation = val;
11367#endif
11368
11369   if(!(pSiS->VBFlags & CRT2_TV)) return;
11370   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE)) return;
11371   if(pSiS->VBFlags2 & VB2_301) return;
11372
11373#ifdef UNLOCK_ALWAYS
11374   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11375#endif
11376
11377   val /= 2;
11378   if((val >= 0) && (val <= 7)) {
11379      setSISIDXREG(SISPART4,0x21,0xF8, val);
11380   }
11381}
11382
11383int SiS_GetSISTVsaturation(ScrnInfoPtr pScrn)
11384{
11385   SISPtr pSiS = SISPTR(pScrn);
11386   int result = pSiS->sistvsaturation;
11387   UChar temp;
11388#ifdef SISDUALHEAD
11389   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11390
11391   if(pSiSEnt && pSiS->DualHeadMode)  result = pSiSEnt->sistvsaturation;
11392#endif
11393
11394   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE)) return result;
11395   if(pSiS->VBFlags2 & VB2_301)          return result;
11396   if(!(pSiS->VBFlags & CRT2_TV))        return result;
11397
11398#ifdef UNLOCK_ALWAYS
11399   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11400#endif
11401   inSISIDXREG(SISPART4, 0x21, temp);
11402   return(int)((temp & 0x07) * 2);
11403}
11404
11405void SiS_SetSISTVcolcalib(ScrnInfoPtr pScrn, int val, Bool coarse)
11406{
11407   SISPtr pSiS = SISPTR(pScrn);
11408#ifdef SISDUALHEAD
11409   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11410#endif
11411   int ccoarse, cfine, cbase = pSiS->sistvccbase;
11412   /* UChar temp; */
11413
11414#ifdef SISDUALHEAD
11415   if(pSiSEnt && pSiS->DualHeadMode) cbase = pSiSEnt->sistvccbase;
11416#endif
11417
11418   if(coarse) {
11419      pSiS->sistvcolcalibc = ccoarse = val;
11420      cfine = pSiS->sistvcolcalibf;
11421#ifdef SISDUALHEAD
11422      if(pSiSEnt) {
11423         pSiSEnt->sistvcolcalibc = val;
11424	 if(pSiS->DualHeadMode) cfine = pSiSEnt->sistvcolcalibf;
11425      }
11426#endif
11427   } else {
11428      pSiS->sistvcolcalibf = cfine = val;
11429      ccoarse = pSiS->sistvcolcalibc;
11430#ifdef SISDUALHEAD
11431      if(pSiSEnt) {
11432         pSiSEnt->sistvcolcalibf = val;
11433         if(pSiS->DualHeadMode) ccoarse = pSiSEnt->sistvcolcalibc;
11434      }
11435#endif
11436   }
11437
11438   if(!(pSiS->VBFlags & CRT2_TV))               return;
11439   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE))        return;
11440   if(pSiS->VBFlags & (TV_HIVISION | TV_YPBPR)) return;
11441
11442#ifdef UNLOCK_ALWAYS
11443   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11444#endif
11445
11446   if((cfine >= -128) && (cfine <= 127) && (ccoarse >= -120) && (ccoarse <= 120)) {
11447      long finalcc = cbase + (((ccoarse * 256) + cfine) * 256);
11448
11449#if 0
11450      inSISIDXREG(SISPART4,0x1f,temp);
11451      if(!(temp & 0x01)) {
11452         if(pSiS->VBFlags & TV_NTSC) finalcc += 0x21ed8620;
11453	 else if(pSiS->VBFlags & TV_PALM) finalcc += ?;
11454	 else if(pSiS->VBFlags & TV_PALM) finalcc += ?;
11455	 else finalcc += 0x2a05d300;
11456      }
11457#endif
11458      setSISIDXREG(SISPART2,0x31,0x80,((finalcc >> 24) & 0x7f));
11459      outSISIDXREG(SISPART2,0x32,((finalcc >> 16) & 0xff));
11460      outSISIDXREG(SISPART2,0x33,((finalcc >> 8) & 0xff));
11461      outSISIDXREG(SISPART2,0x34,(finalcc & 0xff));
11462   }
11463}
11464
11465int SiS_GetSISTVcolcalib(ScrnInfoPtr pScrn, Bool coarse)
11466{
11467   SISPtr pSiS = SISPTR(pScrn);
11468#ifdef SISDUALHEAD
11469   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11470
11471   if(pSiSEnt && pSiS->DualHeadMode)
11472      if(coarse)  return (int)pSiSEnt->sistvcolcalibc;
11473      else        return (int)pSiSEnt->sistvcolcalibf;
11474   else
11475#endif
11476   if(coarse)     return (int)pSiS->sistvcolcalibc;
11477   else           return (int)pSiS->sistvcolcalibf;
11478}
11479
11480void SiS_SetSISTVcfilter(ScrnInfoPtr pScrn, int val)
11481{
11482   SISPtr pSiS = SISPTR(pScrn);
11483#ifdef SISDUALHEAD
11484   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11485#endif
11486
11487   pSiS->sistvcfilter = val ? 1 : 0;
11488#ifdef SISDUALHEAD
11489   if(pSiSEnt) pSiSEnt->sistvcfilter = pSiS->sistvcfilter;
11490#endif
11491
11492   if(!(pSiS->VBFlags & CRT2_TV))               return;
11493   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE))        return;
11494   if(pSiS->VBFlags & (TV_HIVISION | TV_YPBPR)) return;
11495
11496#ifdef UNLOCK_ALWAYS
11497   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11498#endif
11499
11500   setSISIDXREG(SISPART2,0x30,~0x10,((pSiS->sistvcfilter << 4) & 0x10));
11501}
11502
11503int SiS_GetSISTVcfilter(ScrnInfoPtr pScrn)
11504{
11505   SISPtr pSiS = SISPTR(pScrn);
11506   int result = pSiS->sistvcfilter;
11507   UChar temp;
11508#ifdef SISDUALHEAD
11509   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11510
11511   if(pSiSEnt && pSiS->DualHeadMode) result = pSiSEnt->sistvcfilter;
11512#endif
11513
11514   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE))        return result;
11515   if(!(pSiS->VBFlags & CRT2_TV))               return result;
11516   if(pSiS->VBFlags & (TV_HIVISION | TV_YPBPR)) return result;
11517
11518#ifdef UNLOCK_ALWAYS
11519   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11520#endif
11521   inSISIDXREG(SISPART2, 0x30, temp);
11522   return (int)((temp & 0x10) ? 1 : 0);
11523}
11524
11525void SiS_SetSISTVyfilter(ScrnInfoPtr pScrn, int val)
11526{
11527   SISPtr pSiS = SISPTR(pScrn);
11528#ifdef SISDUALHEAD
11529   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11530#endif
11531   UChar p35,p36,p37,p38,p48,p49,p4a,p30;
11532   int i,j;
11533
11534   pSiS->sistvyfilter = val;
11535#ifdef SISDUALHEAD
11536   if(pSiSEnt) pSiSEnt->sistvyfilter = pSiS->sistvyfilter;
11537#endif
11538
11539   if(!(pSiS->VBFlags & CRT2_TV))               return;
11540   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE))        return;
11541   if(pSiS->VBFlags & (TV_HIVISION | TV_YPBPR)) return;
11542
11543   p35 = pSiS->p2_35; p36 = pSiS->p2_36;
11544   p37 = pSiS->p2_37; p38 = pSiS->p2_38;
11545   p48 = pSiS->p2_48; p49 = pSiS->p2_49;
11546   p4a = pSiS->p2_4a; p30 = pSiS->p2_30;
11547#ifdef SISDUALHEAD
11548   if(pSiSEnt && pSiS->DualHeadMode) {
11549      p35 = pSiSEnt->p2_35; p36 = pSiSEnt->p2_36;
11550      p37 = pSiSEnt->p2_37; p38 = pSiSEnt->p2_38;
11551      p48 = pSiSEnt->p2_48; p49 = pSiSEnt->p2_49;
11552      p4a = pSiSEnt->p2_4a; p30 = pSiSEnt->p2_30;
11553   }
11554#endif
11555   p30 &= 0x20;
11556
11557#ifdef UNLOCK_ALWAYS
11558   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11559#endif
11560
11561   switch(pSiS->sistvyfilter) {
11562   case 0:
11563      andSISIDXREG(SISPART2,0x30,0xdf);
11564      break;
11565   case 1:
11566      outSISIDXREG(SISPART2,0x35,p35);
11567      outSISIDXREG(SISPART2,0x36,p36);
11568      outSISIDXREG(SISPART2,0x37,p37);
11569      outSISIDXREG(SISPART2,0x38,p38);
11570      if(!(pSiS->VBFlags2 & VB2_301)) {
11571         outSISIDXREG(SISPART2,0x48,p48);
11572         outSISIDXREG(SISPART2,0x49,p49);
11573         outSISIDXREG(SISPART2,0x4a,p4a);
11574      }
11575      setSISIDXREG(SISPART2,0x30,0xdf,p30);
11576      break;
11577   case 2:
11578   case 3:
11579   case 4:
11580   case 5:
11581   case 6:
11582   case 7:
11583   case 8:
11584      if(!(pSiS->VBFlags & (TV_PALM | TV_PALN | TV_NTSCJ))) {
11585         int yindex301 = -1, yindex301B = -1;
11586	 UChar p3d4_34;
11587
11588	 inSISIDXREG(SISCR,0x34,p3d4_34);
11589
11590	 switch((p3d4_34 & 0x7f)) {
11591	 case 0x59:  /* 320x200 */
11592	 case 0x41:
11593	 case 0x4f:
11594	 case 0x50:  /* 320x240 */
11595	 case 0x56:
11596	 case 0x53:
11597	    yindex301  = (pSiS->VBFlags & TV_NTSC) ? 0 : 4;
11598	    break;
11599	 case 0x2f:  /* 640x400 */
11600	 case 0x5d:
11601	 case 0x5e:
11602	 case 0x2e:  /* 640x480 */
11603	 case 0x44:
11604	 case 0x62:
11605	    yindex301  = (pSiS->VBFlags & TV_NTSC) ? 1 : 5;
11606	    yindex301B = (pSiS->VBFlags & TV_NTSC) ? 0 : 4;
11607	    break;
11608	 case 0x31:   /* 720x480 */
11609	 case 0x33:
11610	 case 0x35:
11611	 case 0x32:   /* 720x576 */
11612	 case 0x34:
11613	 case 0x36:
11614	 case 0x5f:   /* 768x576 */
11615	 case 0x60:
11616	 case 0x61:
11617	    yindex301  = (pSiS->VBFlags & TV_NTSC) ? 2 : 6;
11618	    yindex301B = (pSiS->VBFlags & TV_NTSC) ? 1 : 5;
11619	    break;
11620	 case 0x51:   /* 400x300 */
11621	 case 0x57:
11622	 case 0x54:
11623	 case 0x30:   /* 800x600 */
11624	 case 0x47:
11625	 case 0x63:
11626	    yindex301  = (pSiS->VBFlags & TV_NTSC) ? 3 : 7;
11627	    yindex301B = (pSiS->VBFlags & TV_NTSC) ? 2 : 6;
11628	    break;
11629	 case 0x52:   /* 512x384 */
11630	 case 0x58:
11631	 case 0x5c:
11632	 case 0x38:   /* 1024x768 */
11633	 case 0x4a:
11634	 case 0x64:
11635	    yindex301B = (pSiS->VBFlags & TV_NTSC) ? 3 : 7;
11636	    break;
11637	 }
11638         if(pSiS->VBFlags2 & VB2_301) {
11639            if(yindex301 >= 0) {
11640	       for(i=0, j=0x35; i<=3; i++, j++) {
11641	          outSISIDXREG(SISPART2,j,(SiSTVFilter301[yindex301].filter[pSiS->sistvyfilter-2][i]));
11642	       }
11643	    }
11644         } else {
11645            if(yindex301B >= 0) {
11646	       for(i=0, j=0x35; i<=3; i++, j++) {
11647	          outSISIDXREG(SISPART2,j,(SiSTVFilter301B[yindex301B].filter[pSiS->sistvyfilter-2][i]));
11648	       }
11649	       for(i=4, j=0x48; i<=6; i++, j++) {
11650	          outSISIDXREG(SISPART2,j,(SiSTVFilter301B[yindex301B].filter[pSiS->sistvyfilter-2][i]));
11651	       }
11652	    }
11653         }
11654         orSISIDXREG(SISPART2,0x30,0x20);
11655      }
11656   }
11657}
11658
11659int SiS_GetSISTVyfilter(ScrnInfoPtr pScrn)
11660{
11661   SISPtr pSiS = SISPTR(pScrn);
11662#ifdef SISDUALHEAD
11663   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11664
11665   if(pSiSEnt && pSiS->DualHeadMode)
11666      return (int)pSiSEnt->sistvyfilter;
11667   else
11668#endif
11669      return (int)pSiS->sistvyfilter;
11670}
11671
11672void SiS_SetSIS6326TVantiflicker(ScrnInfoPtr pScrn, int val)
11673{
11674   SISPtr pSiS = SISPTR(pScrn);
11675   UChar tmp;
11676
11677   pSiS->sistvantiflicker = val;
11678
11679   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) return;
11680
11681#ifdef UNLOCK_ALWAYS
11682   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11683#endif
11684
11685   tmp = SiS6326GetTVReg(pScrn,0x00);
11686   if(!(tmp & 0x04)) return;
11687
11688   /* Valid values: 0=off, 1=low, 2=med, 3=high, 4=adaptive */
11689   if(val >= 0 && val <= 4) {
11690      tmp &= 0x1f;
11691      tmp |= (val << 5);
11692      SiS6326SetTVReg(pScrn,0x00,tmp);
11693   }
11694}
11695
11696int SiS_GetSIS6326TVantiflicker(ScrnInfoPtr pScrn)
11697{
11698   SISPtr pSiS = SISPTR(pScrn);
11699   UChar tmp;
11700
11701   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) {
11702      return (int)pSiS->sistvantiflicker;
11703   }
11704
11705#ifdef UNLOCK_ALWAYS
11706   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11707#endif
11708
11709   tmp = SiS6326GetTVReg(pScrn,0x00);
11710   if(!(tmp & 0x04)) {
11711      return (int)pSiS->sistvantiflicker;
11712   } else {
11713      return (int)((tmp >> 5) & 0x07);
11714   }
11715}
11716
11717void SiS_SetSIS6326TVenableyfilter(ScrnInfoPtr pScrn, int val)
11718{
11719   SISPtr pSiS = SISPTR(pScrn);
11720   UChar tmp;
11721
11722   if(val) val = 1;
11723   pSiS->sis6326enableyfilter = val;
11724
11725   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) return;
11726
11727#ifdef UNLOCK_ALWAYS
11728   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11729#endif
11730
11731   tmp = SiS6326GetTVReg(pScrn,0x00);
11732   if(!(tmp & 0x04)) return;
11733
11734   tmp = SiS6326GetTVReg(pScrn,0x43);
11735   tmp &= ~0x10;
11736   tmp |= ((val & 0x01) << 4);
11737   SiS6326SetTVReg(pScrn,0x43,tmp);
11738}
11739
11740int SiS_GetSIS6326TVenableyfilter(ScrnInfoPtr pScrn)
11741{
11742   SISPtr pSiS = SISPTR(pScrn);
11743   UChar tmp;
11744
11745   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) {
11746      return (int)pSiS->sis6326enableyfilter;
11747   }
11748
11749#ifdef UNLOCK_ALWAYS
11750   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11751#endif
11752
11753   tmp = SiS6326GetTVReg(pScrn,0x00);
11754   if(!(tmp & 0x04)) {
11755      return (int)pSiS->sis6326enableyfilter;
11756   } else {
11757      tmp = SiS6326GetTVReg(pScrn,0x43);
11758      return (int)((tmp >> 4) & 0x01);
11759   }
11760}
11761
11762void SiS_SetSIS6326TVyfilterstrong(ScrnInfoPtr pScrn, int val)
11763{
11764   SISPtr pSiS = SISPTR(pScrn);
11765   UChar tmp;
11766
11767   if(val) val = 1;
11768   pSiS->sis6326yfilterstrong = val;
11769
11770   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) return;
11771
11772#ifdef UNLOCK_ALWAYS
11773   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11774#endif
11775
11776   tmp = SiS6326GetTVReg(pScrn,0x00);
11777   if(!(tmp & 0x04)) return;
11778
11779   tmp = SiS6326GetTVReg(pScrn,0x43);
11780   if(tmp & 0x10) {
11781      tmp &= ~0x40;
11782      tmp |= ((val & 0x01) << 6);
11783      SiS6326SetTVReg(pScrn,0x43,tmp);
11784   }
11785}
11786
11787int SiS_GetSIS6326TVyfilterstrong(ScrnInfoPtr pScrn)
11788{
11789   SISPtr pSiS = SISPTR(pScrn);
11790   UChar tmp;
11791
11792   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) {
11793      return (int)pSiS->sis6326yfilterstrong;
11794   }
11795
11796#ifdef UNLOCK_ALWAYS
11797   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11798#endif
11799
11800   tmp = SiS6326GetTVReg(pScrn,0x00);
11801   if(!(tmp & 0x04)) {
11802      return (int)pSiS->sis6326yfilterstrong;
11803   } else {
11804      tmp = SiS6326GetTVReg(pScrn,0x43);
11805      if(!(tmp & 0x10)) {
11806         return (int)pSiS->sis6326yfilterstrong;
11807      } else {
11808         return (int)((tmp >> 6) & 0x01);
11809      }
11810   }
11811}
11812
11813void SiS_SetTVxposoffset(ScrnInfoPtr pScrn, int val)
11814{
11815   SISPtr pSiS = SISPTR(pScrn);
11816#ifdef SISDUALHEAD
11817   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11818#endif
11819
11820#ifdef UNLOCK_ALWAYS
11821   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11822#endif
11823
11824   pSiS->tvxpos = val;
11825#ifdef SISDUALHEAD
11826   if(pSiSEnt) pSiSEnt->tvxpos = val;
11827#endif
11828
11829   if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
11830
11831      if(pSiS->VBFlags & CRT2_TV) {
11832
11833         if(pSiS->VBFlags2 & VB2_CHRONTEL) {
11834
11835	    int x = pSiS->tvx;
11836#ifdef SISDUALHEAD
11837	    if(pSiSEnt && pSiS->DualHeadMode) x = pSiSEnt->tvx;
11838#endif
11839	    switch(pSiS->ChrontelType) {
11840	    case CHRONTEL_700x:
11841	       if((val >= -32) && (val <= 32)) {
11842		   x += val;
11843		   if(x < 0) x = 0;
11844		   SiS_SetCH700x(pSiS->SiS_Pr, 0x0a, (x & 0xff));
11845		   SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x08, ((x & 0x0100) >> 7), 0xFD);
11846	       }
11847	       break;
11848	    case CHRONTEL_701x:
11849	       /* Not supported by hardware */
11850	       break;
11851	    }
11852
11853	 } else if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
11854
11855	    if((val >= -32) && (val <= 32)) {
11856
11857	        UChar p2_1f,p2_20,p2_2b,p2_42,p2_43;
11858		UShort temp;
11859		int mult;
11860
11861		p2_1f = pSiS->p2_1f;
11862		p2_20 = pSiS->p2_20;
11863		p2_2b = pSiS->p2_2b;
11864		p2_42 = pSiS->p2_42;
11865		p2_43 = pSiS->p2_43;
11866#ifdef SISDUALHEAD
11867	        if(pSiSEnt && pSiS->DualHeadMode) {
11868		   p2_1f = pSiSEnt->p2_1f;
11869		   p2_20 = pSiSEnt->p2_20;
11870		   p2_2b = pSiSEnt->p2_2b;
11871		   p2_42 = pSiSEnt->p2_42;
11872		   p2_43 = pSiSEnt->p2_43;
11873		}
11874#endif
11875		mult = 2;
11876		if(pSiS->VBFlags & TV_YPBPR) {
11877		   if(pSiS->VBFlags & (TV_YPBPR1080I | TV_YPBPR750P)) {
11878		      mult = 4;
11879		   }
11880		}
11881
11882		temp = p2_1f | ((p2_20 & 0xf0) << 4);
11883		temp += (val * mult);
11884		p2_1f = temp & 0xff;
11885		p2_20 = (temp & 0xf00) >> 4;
11886		p2_2b = ((p2_2b & 0x0f) + (val * mult)) & 0x0f;
11887		temp = p2_43 | ((p2_42 & 0xf0) << 4);
11888		temp += (val * mult);
11889		p2_43 = temp & 0xff;
11890		p2_42 = (temp & 0xf00) >> 4;
11891		SISWaitRetraceCRT2(pScrn);
11892	        outSISIDXREG(SISPART2,0x1f,p2_1f);
11893		setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
11894		setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
11895		setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
11896		outSISIDXREG(SISPART2,0x43,p2_43);
11897	     }
11898	 }
11899      }
11900
11901   } else if(pSiS->Chipset == PCI_CHIP_SIS6326) {
11902
11903      if(pSiS->SiS6326Flags & SIS6326_TVDETECTED) {
11904
11905         UChar tmp;
11906	 UShort temp1, temp2, temp3;
11907
11908         tmp = SiS6326GetTVReg(pScrn,0x00);
11909         if(tmp & 0x04) {
11910
11911	    temp1 = pSiS->tvx1;
11912            temp2 = pSiS->tvx2;
11913            temp3 = pSiS->tvx3;
11914            if((val >= -16) && (val <= 16)) {
11915	       if(val > 0) {
11916	          temp1 += (val * 4);
11917	          temp2 += (val * 4);
11918	          while((temp1 > 0x0fff) || (temp2 > 0x0fff)) {
11919	             temp1 -= 4;
11920		     temp2 -= 4;
11921	          }
11922	       } else {
11923	          val = -val;
11924	          temp3 += (val * 4);
11925	          while(temp3 > 0x03ff) {
11926	     	     temp3 -= 4;
11927	          }
11928	       }
11929            }
11930            SiS6326SetTVReg(pScrn,0x3a,(temp1 & 0xff));
11931            tmp = SiS6326GetTVReg(pScrn,0x3c);
11932            tmp &= 0xf0;
11933            tmp |= ((temp1 & 0x0f00) >> 8);
11934            SiS6326SetTVReg(pScrn,0x3c,tmp);
11935            SiS6326SetTVReg(pScrn,0x26,(temp2 & 0xff));
11936            tmp = SiS6326GetTVReg(pScrn,0x27);
11937            tmp &= 0x0f;
11938            tmp |= ((temp2 & 0x0f00) >> 4);
11939            SiS6326SetTVReg(pScrn,0x27,tmp);
11940            SiS6326SetTVReg(pScrn,0x12,(temp3 & 0xff));
11941            tmp = SiS6326GetTVReg(pScrn,0x13);
11942            tmp &= ~0xC0;
11943            tmp |= ((temp3 & 0x0300) >> 2);
11944            SiS6326SetTVReg(pScrn,0x13,tmp);
11945	 }
11946      }
11947   }
11948}
11949
11950int SiS_GetTVxposoffset(ScrnInfoPtr pScrn)
11951{
11952   SISPtr pSiS = SISPTR(pScrn);
11953#ifdef SISDUALHEAD
11954   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11955
11956   if(pSiSEnt && pSiS->DualHeadMode)
11957        return (int)pSiSEnt->tvxpos;
11958   else
11959#endif
11960        return (int)pSiS->tvxpos;
11961}
11962
11963void SiS_SetTVyposoffset(ScrnInfoPtr pScrn, int val)
11964{
11965   SISPtr pSiS = SISPTR(pScrn);
11966#ifdef SISDUALHEAD
11967   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11968#endif
11969
11970#ifdef UNLOCK_ALWAYS
11971   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11972#endif
11973
11974   pSiS->tvypos = val;
11975#ifdef SISDUALHEAD
11976   if(pSiSEnt) pSiSEnt->tvypos = val;
11977#endif
11978
11979   if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
11980
11981      if(pSiS->VBFlags & CRT2_TV) {
11982
11983         if(pSiS->VBFlags2 & VB2_CHRONTEL) {
11984
11985	    int y = pSiS->tvy;
11986#ifdef SISDUALHEAD
11987	    if(pSiSEnt && pSiS->DualHeadMode) y = pSiSEnt->tvy;
11988#endif
11989	    switch(pSiS->ChrontelType) {
11990	    case CHRONTEL_700x:
11991	       if((val >= -32) && (val <= 32)) {
11992		   y -= val;
11993		   if(y < 0) y = 0;
11994		   SiS_SetCH700x(pSiS->SiS_Pr, 0x0b, (y & 0xff));
11995		   SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x08, ((y & 0x0100) >> 8), 0xFE);
11996	       }
11997	       break;
11998	    case CHRONTEL_701x:
11999	       /* Not supported by hardware */
12000	       break;
12001	    }
12002
12003	 } else if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
12004
12005	    if((val >= -32) && (val <= 32)) {
12006		char p2_01, p2_02;
12007
12008		if( (pSiS->VBFlags & TV_HIVISION) ||
12009		    ((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & (TV_YPBPR1080I|TV_YPBPR750P))) ) {
12010		   val *= 2;
12011		} else {
12012		   val /= 2;  /* 4 */
12013		}
12014
12015		p2_01 = pSiS->p2_01;
12016		p2_02 = pSiS->p2_02;
12017#ifdef SISDUALHEAD
12018	        if(pSiSEnt && pSiS->DualHeadMode) {
12019		   p2_01 = pSiSEnt->p2_01;
12020		   p2_02 = pSiSEnt->p2_02;
12021		}
12022#endif
12023		p2_01 += val; /* val * 2 */
12024		p2_02 += val; /* val * 2 */
12025		if(!(pSiS->VBFlags & (TV_YPBPR | TV_HIVISION))) {
12026		   while((p2_01 <= 0) || (p2_02 <= 0)) {
12027		      p2_01 += 2;
12028		      p2_02 += 2;
12029		   }
12030		} else if((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR1080I)) {
12031		   while(p2_01 <= 8) {
12032		      p2_01 += 2;
12033		      p2_02 += 2;
12034		   }
12035		} else if((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR750P)) {
12036		   while(p2_01 <= 10) {
12037		      p2_01 += 2;
12038		      p2_02 += 2;
12039		   }
12040		}
12041
12042		SISWaitRetraceCRT2(pScrn);
12043		outSISIDXREG(SISPART2,0x01,p2_01);
12044		outSISIDXREG(SISPART2,0x02,p2_02);
12045	     }
12046	 }
12047
12048      }
12049
12050   } else if(pSiS->Chipset == PCI_CHIP_SIS6326) {
12051
12052      if(pSiS->SiS6326Flags & SIS6326_TVDETECTED) {
12053
12054         UChar tmp;
12055	 int temp1, limit;
12056
12057         tmp = SiS6326GetTVReg(pScrn,0x00);
12058         if(tmp & 0x04) {
12059
12060	    if((val >= -16) && (val <= 16)) {
12061	      temp1 = (UShort)pSiS->tvy1;
12062	      limit = (pSiS->SiS6326Flags & SIS6326_TVPAL) ? 625 : 525;
12063	      if(val > 0) {
12064                temp1 += (val * 4);
12065	        if(temp1 > limit) temp1 -= limit;
12066	      } else {
12067	        val = -val;
12068	        temp1 -= (val * 2);
12069	        if(temp1 <= 0) temp1 += (limit -1);
12070	      }
12071	      SiS6326SetTVReg(pScrn,0x11,(temp1 & 0xff));
12072	      tmp = SiS6326GetTVReg(pScrn,0x13);
12073	      tmp &= ~0x30;
12074	      tmp |= ((temp1 & 0x300) >> 4);
12075	      SiS6326SetTVReg(pScrn,0x13,tmp);
12076	      if(temp1 == 1)                                 tmp = 0x10;
12077	      else {
12078	       if(pSiS->SiS6326Flags & SIS6326_TVPAL) {
12079	         if((temp1 <= 3) || (temp1 >= (limit - 2)))  tmp = 0x08;
12080	         else if(temp1 < 22)		 	     tmp = 0x02;
12081	         else 					     tmp = 0x04;
12082	       } else {
12083	         if((temp1 <= 5) || (temp1 >= (limit - 4)))  tmp = 0x08;
12084	         else if(temp1 < 19)			     tmp = 0x02;
12085	         else 					     tmp = 0x04;
12086	       }
12087	     }
12088	     SiS6326SetTVReg(pScrn,0x21,tmp);
12089           }
12090	 }
12091      }
12092   }
12093}
12094
12095int SiS_GetTVyposoffset(ScrnInfoPtr pScrn)
12096{
12097   SISPtr pSiS = SISPTR(pScrn);
12098#ifdef SISDUALHEAD
12099   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12100
12101   if(pSiSEnt && pSiS->DualHeadMode)
12102        return (int)pSiSEnt->tvypos;
12103   else
12104#endif
12105        return (int)pSiS->tvypos;
12106}
12107
12108void SiS_SetTVxscale(ScrnInfoPtr pScrn, int val)
12109{
12110   SISPtr pSiS = SISPTR(pScrn);
12111#ifdef SISDUALHEAD
12112   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12113#endif
12114
12115#ifdef UNLOCK_ALWAYS
12116   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
12117#endif
12118
12119   pSiS->tvxscale = val;
12120#ifdef SISDUALHEAD
12121   if(pSiSEnt) pSiSEnt->tvxscale = val;
12122#endif
12123
12124   if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
12125
12126      if((pSiS->VBFlags & CRT2_TV) && (pSiS->VBFlags2 & VB2_SISBRIDGE)) {
12127
12128	 if((val >= -16) && (val <= 16)) {
12129
12130	    UChar p2_44,p2_45,p2_46;
12131	    int scalingfactor, mult;
12132
12133	    p2_44 = pSiS->p2_44;
12134	    p2_45 = pSiS->p2_45 & 0x3f;
12135	    p2_46 = pSiS->p2_46 & 0x07;
12136#ifdef SISDUALHEAD
12137	    if(pSiSEnt && pSiS->DualHeadMode) {
12138	       p2_44 = pSiSEnt->p2_44;
12139	       p2_45 = pSiSEnt->p2_45 & 0x3f;
12140	       p2_46 = pSiSEnt->p2_46 & 0x07;
12141	    }
12142#endif
12143	    scalingfactor = (p2_46 << 13) | ((p2_45 & 0x1f) << 8) | p2_44;
12144
12145	    mult = 64;
12146	    if(pSiS->VBFlags & TV_YPBPR) {
12147	       if(pSiS->VBFlags & TV_YPBPR1080I) {
12148	          mult = 190;
12149	       } else if(pSiS->VBFlags & TV_YPBPR750P) {
12150	          mult = 360;
12151	       }
12152	    } else if(pSiS->VBFlags & TV_HIVISION) {
12153	       mult = 190;
12154	    }
12155
12156	    if(val < 0) {
12157	       p2_45 &= 0xdf;
12158	       scalingfactor += ((-val) * mult);
12159	       if(scalingfactor > 0xffff) scalingfactor = 0xffff;
12160	    } else if(val > 0) {
12161	       p2_45 &= 0xdf;
12162	       scalingfactor -= (val * mult);
12163	       if(scalingfactor < 1) scalingfactor = 1;
12164	    }
12165
12166	    p2_44 = scalingfactor & 0xff;
12167	    p2_45 &= 0xe0;
12168	    p2_45 |= ((scalingfactor >> 8) & 0x1f);
12169	    p2_46 = ((scalingfactor >> 13) & 0x07);
12170
12171	    SISWaitRetraceCRT2(pScrn);
12172	    outSISIDXREG(SISPART2,0x44,p2_44);
12173	    setSISIDXREG(SISPART2,0x45,0xC0,p2_45);
12174	    if(!(pSiS->VBFlags2 & VB2_301)) {
12175	       setSISIDXREG(SISPART2,0x46,0xF8,p2_46);
12176	    }
12177
12178	 }
12179
12180      }
12181
12182   }
12183}
12184
12185int SiS_GetTVxscale(ScrnInfoPtr pScrn)
12186{
12187   SISPtr pSiS = SISPTR(pScrn);
12188#ifdef SISDUALHEAD
12189   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12190
12191   if(pSiSEnt && pSiS->DualHeadMode)
12192        return (int)pSiSEnt->tvxscale;
12193   else
12194#endif
12195        return (int)pSiS->tvxscale;
12196}
12197
12198void SiS_SetTVyscale(ScrnInfoPtr pScrn, int val)
12199{
12200   SISPtr pSiS = SISPTR(pScrn);
12201#ifdef SISDUALHEAD
12202   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12203#endif
12204
12205#ifdef UNLOCK_ALWAYS
12206   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
12207#endif
12208
12209   if(val < -4) val = -4;
12210   if(val > 3)  val = 3;
12211
12212   pSiS->tvyscale = val;
12213#ifdef SISDUALHEAD
12214   if(pSiSEnt) pSiSEnt->tvyscale = val;
12215#endif
12216
12217   if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
12218
12219      if((pSiS->VBFlags & CRT2_TV) && (pSiS->VBFlags2 & VB2_SISBRIDGE)) {
12220
12221	 int srindex = -1, newvde, i = 0, j, vlimit, temp, vdediv;
12222	 int hdclk = 0;
12223	 UChar p3d4_34;
12224	 Bool found = FALSE;
12225	 Bool usentsc = FALSE;
12226	 Bool is750p = FALSE;
12227	 Bool is1080i = FALSE;
12228	 Bool skipmoveup = FALSE;
12229
12230	 SiS_UnLockCRT2(pSiS->SiS_Pr);
12231
12232	 if((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR525P)) {
12233	    vlimit = 525 - 7;
12234	    vdediv = 1;
12235	    usentsc = TRUE;
12236	 } else if((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR625P)) {
12237	    vlimit = 625 - 7;
12238	    vdediv = 1;
12239	 } else if((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR750P)) {
12240	    vlimit = 750 - 7;
12241	    vdediv = 1;
12242	    is750p = TRUE;
12243	 } else if(((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR1080I)) ||
12244	           (pSiS->VBFlags & TV_HIVISION)) {
12245	    vlimit = (1125 - 7) / 2;
12246	    vdediv = 2;
12247	    is1080i = TRUE;
12248	 } else {
12249	    if( ((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR525I)) ||
12250	        ((!(pSiS->VBFlags & TV_YPBPR)) && (pSiS->VBFlags & (TV_NTSC | TV_PALM))) ) {
12251	       usentsc = TRUE;
12252	    }
12253	    vlimit = usentsc ? 259 : 309;
12254	    vdediv = 2;
12255	 }
12256
12257	 inSISIDXREG(SISCR,0x34,p3d4_34);
12258
12259	 switch((p3d4_34 & 0x7f)) {
12260	 case 0x50:   /* 320x240 */
12261	 case 0x56:
12262	 case 0x53:
12263	    hdclk = 1;
12264	    /* fall through */
12265	 case 0x2e:   /* 640x480 */
12266	 case 0x44:
12267	 case 0x62:
12268	    if(is1080i) {
12269	       srindex = 98;
12270	    } else if(is750p) {
12271	       srindex = 42;
12272	    } else {
12273	       srindex  = usentsc ? 0 : 21;
12274	    }
12275	    break;
12276	 case 0x31:   /* 720x480 */
12277	 case 0x33:
12278	 case 0x35:
12279	    if(is1080i) {
12280	       /* n/a */
12281	    } else if(is750p) {
12282	       srindex = 49;
12283	    } else {
12284	       srindex = usentsc ? 7 : 21;
12285	    }
12286	    break;
12287	 case 0x32:   /* 720x576 */
12288	 case 0x34:
12289	 case 0x36:
12290	 case 0x5f:   /* 768x576 */
12291	 case 0x60:
12292	 case 0x61:
12293	    if(is1080i) {
12294	       /* n/a */
12295	    } else if(is750p) {
12296	       srindex = 56;
12297	    } else {
12298	       srindex  = usentsc ? 147 : 28;
12299	    }
12300	    break;
12301	 case 0x70:   /* 800x480 */
12302	 case 0x7a:
12303	 case 0x76:
12304	    if(is1080i) {
12305	       srindex = 105;
12306	    } else if(is750p) {
12307	       srindex = 63;
12308	    } else {
12309	       srindex = usentsc ? 175 : 21;
12310	    }
12311	    break;
12312	 case 0x51:   /* 400x300 - hdclk mode */
12313	 case 0x57:
12314	 case 0x54:
12315	    hdclk = 1;
12316	    /* fall through */
12317	 case 0x30:   /* 800x600 */
12318	 case 0x47:
12319	 case 0x63:
12320	    if(is1080i) {
12321	       srindex = 112;
12322	    } else if(is750p) {
12323	       srindex = 70;
12324	    } else {
12325	       srindex = usentsc ? 14 : 35;
12326	    }
12327	    break;
12328	 case 0x1d:	/* 960x540 */
12329	 case 0x1e:
12330	 case 0x1f:
12331	    if(is1080i) {
12332	       srindex = 196;
12333	       skipmoveup = TRUE;
12334	    }
12335	    break;
12336	 case 0x20:	/* 960x600 */
12337	 case 0x21:
12338	 case 0x22:
12339	    if(pSiS->VGAEngine == SIS_315_VGA && is1080i) {
12340	       srindex = 203;
12341	    }
12342	    break;
12343	 case 0x71:	/* 1024x576 */
12344	 case 0x74:
12345	 case 0x77:
12346	    if(is1080i) {
12347	       srindex = 119;
12348	    } else if(is750p) {
12349	       srindex = 77;
12350	    } else {
12351	       srindex  = usentsc ? 182 : 189;
12352	    }
12353	    break;
12354	 case 0x52:	/* 512x384 */
12355	 case 0x58:
12356	 case 0x5c:
12357	    hdclk = 1;
12358	    /* fall through */
12359	 case 0x38:	/* 1024x768 */
12360	 case 0x4a:
12361	 case 0x64:
12362	    if(is1080i) {
12363	       srindex = 126;
12364	    } else if(is750p) {
12365	       srindex = 84;
12366	    } else if(!usentsc) {
12367	       srindex = 154;
12368	    } else if(vdediv == 1) {
12369	       if(!hdclk) srindex = 168;
12370	    } else {
12371	       if(!hdclk) srindex = 161;
12372	    }
12373	    break;
12374	 case 0x79:	/* 1280x720 */
12375	 case 0x75:
12376	 case 0x78:
12377	    if(is1080i) {
12378	       srindex = 133;
12379	    } else if(is750p) {
12380	       srindex = 91;
12381	    }
12382	    break;
12383	 case 0x3a:	/* 1280x1024 */
12384	 case 0x4d:
12385	 case 0x65:
12386	    if(is1080i) {
12387	       srindex = 140;
12388	    }
12389	    break;
12390	 }
12391
12392	 if(srindex < 0) return;
12393
12394	 if(pSiS->tvyscale != 0) {
12395	    for(j = 0; j <= 1; j++) {
12396	       for(i = 0; i <= 6; i++) {
12397		  if(SiSTVVScale[srindex+i].sindex == pSiS->tvyscale) {
12398		     found = TRUE;
12399		     break;
12400		  }
12401	       }
12402	       if(found) break;
12403	       if(pSiS->tvyscale > 0) pSiS->tvyscale--;
12404	       else pSiS->tvyscale++;
12405	    }
12406	 }
12407
12408#ifdef SISDUALHEAD
12409	 if(pSiSEnt) pSiSEnt->tvyscale = pSiS->tvyscale;
12410#endif
12411
12412	 if(pSiS->tvyscale == 0) {
12413	    UChar p2_0a = pSiS->p2_0a;
12414	    UChar p2_2f = pSiS->p2_2f;
12415	    UChar p2_30 = pSiS->p2_30;
12416	    UChar p2_46 = pSiS->p2_46;
12417	    UChar p2_47 = pSiS->p2_47;
12418	    UChar p1scaling[9], p4scaling[9];
12419	    UChar *p2scaling;
12420
12421	    for(i = 0; i < 9; i++) {
12422	        p1scaling[i] = pSiS->scalingp1[i];
12423		p4scaling[i] = pSiS->scalingp4[i];
12424	    }
12425	    p2scaling = &pSiS->scalingp2[0];
12426
12427#ifdef SISDUALHEAD
12428	    if(pSiSEnt && pSiS->DualHeadMode) {
12429	       p2_0a = pSiSEnt->p2_0a;
12430	       p2_2f = pSiSEnt->p2_2f;
12431	       p2_30 = pSiSEnt->p2_30;
12432	       p2_46 = pSiSEnt->p2_46;
12433	       p2_47 = pSiSEnt->p2_47;
12434	       for(i = 0; i < 9; i++) {
12435		  p1scaling[i] = pSiSEnt->scalingp1[i];
12436		  p4scaling[i] = pSiSEnt->scalingp4[i];
12437	       }
12438	       p2scaling = &pSiSEnt->scalingp2[0];
12439	    }
12440#endif
12441            SISWaitRetraceCRT2(pScrn);
12442	    if(pSiS->VBFlags2 & VB2_SISTAP4SCALER) {
12443	       for(i = 0; i < 64; i++) {
12444	          outSISIDXREG(SISPART2,(0xc0 + i),p2scaling[i]);
12445	       }
12446	    }
12447	    for(i = 0; i < 9; i++) {
12448	       outSISIDXREG(SISPART1,SiSScalingP1Regs[i],p1scaling[i]);
12449	    }
12450	    for(i = 0; i < 9; i++) {
12451	       outSISIDXREG(SISPART4,SiSScalingP4Regs[i],p4scaling[i]);
12452	    }
12453
12454	    setSISIDXREG(SISPART2,0x0a,0x7f,(p2_0a & 0x80));
12455	    outSISIDXREG(SISPART2,0x2f,p2_2f);
12456	    setSISIDXREG(SISPART2,0x30,0x3f,(p2_30 & 0xc0));
12457	    if(!(pSiS->VBFlags2 & VB2_301)) {
12458	       setSISIDXREG(SISPART2,0x46,0x9f,(p2_46 & 0x60));
12459	       outSISIDXREG(SISPART2,0x47,p2_47);
12460	    }
12461
12462	 } else {
12463
12464	    int realvde, myypos, watchdog = 32;
12465	    unsigned short temp1, temp2, vgahde, vgaht, vgavt;
12466	    int p1div = 1;
12467	    ULong calctemp;
12468
12469	    srindex += i;
12470	    newvde = SiSTVVScale[srindex].ScaleVDE;
12471	    realvde = SiSTVVScale[srindex].RealVDE;
12472
12473	    if(vdediv == 1) p1div = 2;
12474
12475	    if(!skipmoveup) {
12476	       do {
12477	          inSISIDXREG(SISPART2,0x01,temp);
12478	          temp = vlimit - ((temp & 0x7f) / p1div);
12479	          if((temp - (((newvde / vdediv) - 2) + 9)) > 0) break;
12480	          myypos = pSiS->tvypos - 1;
12481#ifdef SISDUALHEAD
12482	          if(pSiSEnt && pSiS->DualHeadMode) myypos = pSiSEnt->tvypos - 1;
12483#endif
12484	          SiS_SetTVyposoffset(pScrn, myypos);
12485	       } while(watchdog--);
12486	    }
12487
12488	    SISWaitRetraceCRT2(pScrn);
12489
12490	    if(pSiS->VBFlags2 & VB2_SISTAP4SCALER) {
12491	       SiS_CalcXTapScaler(pSiS->SiS_Pr, realvde, newvde, 4, FALSE);
12492	    }
12493
12494	    if(!(pSiS->VBFlags2 & VB2_301)) {
12495	       temp = (newvde / vdediv) - 3;
12496	       setSISIDXREG(SISPART2,0x46,0x9f,((temp & 0x0300) >> 3));
12497	       outSISIDXREG(SISPART2,0x47,(temp & 0xff));
12498	    }
12499
12500	    inSISIDXREG(SISPART1,0x0a,temp1);
12501	    inSISIDXREG(SISPART1,0x0c,temp2);
12502	    vgahde = ((temp2 & 0xf0) << 4) | temp1;
12503	    if(pSiS->VGAEngine == SIS_300_VGA) {
12504	       vgahde -= 12;
12505	    } else {
12506	       vgahde -= 16;
12507	       if(hdclk) vgahde <<= 1;
12508	    }
12509
12510	    vgaht = SiSTVVScale[srindex].reg[0];
12511	    temp1 = vgaht;
12512	    if((pSiS->VGAEngine == SIS_315_VGA) && hdclk) temp1 >>= 1;
12513	    temp1--;
12514	    outSISIDXREG(SISPART1,0x08,(temp1 & 0xff));
12515	    setSISIDXREG(SISPART1,0x09,0x0f,((temp1 >> 4) & 0xf0));
12516
12517	    temp2 = (vgaht - vgahde) >> 2;
12518	    if(pSiS->VGAEngine == SIS_300_VGA) {
12519	       temp1 = vgahde + 12 + temp2;
12520	       temp2 = temp1 + (temp2 << 1);
12521	    } else {
12522	       temp1 = vgahde;
12523	       if(hdclk) {
12524		  temp1 >>= 1;
12525		  temp2 >>= 1;
12526	       }
12527	       temp2 >>= 1;
12528	       temp1 = temp1 + 16 + temp2;
12529	       temp2 = temp1 + temp2;
12530	    }
12531	    outSISIDXREG(SISPART1,0x0b,(temp1 & 0xff));
12532	    setSISIDXREG(SISPART1,0x0c,0xf0,((temp1 >> 8) & 0x0f));
12533	    outSISIDXREG(SISPART1,0x0d,(temp2 & 0xff));
12534
12535	    vgavt = SiSTVVScale[srindex].reg[1];
12536	    temp1 = vgavt - 1;
12537	    if(pSiS->VGAEngine == SIS_315_VGA) temp1--;
12538	    outSISIDXREG(SISPART1,0x0e,(temp1 & 0xff));
12539	    setSISIDXREG(SISPART1,0x12,0xf8,((temp1 >> 8 ) & 0x07));
12540	    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->ChipType >= SIS_661)) {
12541	       temp1 = (vgavt + SiSTVVScale[srindex].RealVDE) >> 1;
12542	       temp2 = ((vgavt - SiSTVVScale[srindex].RealVDE) >> 4) + temp1 + 1;
12543	    } else {
12544	       temp1 = (vgavt - SiSTVVScale[srindex].RealVDE) >> 2;
12545	       temp2 = (temp1 < 4) ? 4 : temp1;
12546	       temp1 += SiSTVVScale[srindex].RealVDE;
12547	       temp2 = (temp2 >> 2) + temp1 + 1;
12548	    }
12549	    outSISIDXREG(SISPART1,0x10,(temp1 & 0xff));
12550	    setSISIDXREG(SISPART1,0x11,0x8f,((temp1 >> 4) & 0x70));
12551	    setSISIDXREG(SISPART1,0x11,0xf0,(temp2 & 0x0f));
12552
12553	    setSISIDXREG(SISPART2,0x0a,0x7f,((SiSTVVScale[srindex].reg[2] >> 8) & 0x80));
12554	    outSISIDXREG(SISPART2,0x2f,((newvde / vdediv) - 2));
12555	    setSISIDXREG(SISPART2,0x30,0x3f,((((newvde / vdediv) - 2) >> 2) & 0xc0));
12556
12557	    outSISIDXREG(SISPART4,0x13,(SiSTVVScale[srindex].reg[2] & 0xff));
12558	    outSISIDXREG(SISPART4,0x14,(SiSTVVScale[srindex].reg[3] & 0xff));
12559	    setSISIDXREG(SISPART4,0x15,0x7f,((SiSTVVScale[srindex].reg[3] >> 1) & 0x80));
12560
12561	    temp1 = vgaht - 1;
12562	    outSISIDXREG(SISPART4,0x16,(temp1 & 0xff));
12563	    setSISIDXREG(SISPART4,0x15,0x87,((temp1 >> 5) & 0x78));
12564
12565	    temp1 = vgavt - 1;
12566	    outSISIDXREG(SISPART4,0x17,(temp1 & 0xff));
12567	    setSISIDXREG(SISPART4,0x15,0xf8,((temp1 >> 8) & 0x07));
12568
12569	    outSISIDXREG(SISPART4,0x18,0x00);
12570	    setSISIDXREG(SISPART4,0x19,0xf0,0x00);
12571
12572	    inSISIDXREG(SISPART4,0x0e,temp1);
12573	    if(is1080i) {
12574	       if(!(temp1 & 0xe0)) newvde >>= 1;
12575	    }
12576
12577	    temp = 0x40;
12578	    if(realvde <= newvde) temp = 0;
12579	    else realvde -= newvde;
12580
12581	    calctemp = (realvde * 256 * 1024) / newvde;
12582	    if((realvde * 256 * 1024) % newvde) calctemp++;
12583	    outSISIDXREG(SISPART4,0x1b,(calctemp & 0xff));
12584	    outSISIDXREG(SISPART4,0x1a,((calctemp >> 8) & 0xff));
12585	    setSISIDXREG(SISPART4,0x19,0x8f,(((calctemp >> 12) & 0x70) | temp));
12586	 }
12587
12588      }
12589
12590   }
12591}
12592
12593int SiS_GetTVyscale(ScrnInfoPtr pScrn)
12594{
12595   SISPtr pSiS = SISPTR(pScrn);
12596#ifdef SISDUALHEAD
12597   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12598
12599   if(pSiSEnt && pSiS->DualHeadMode)
12600        return (int)pSiSEnt->tvyscale;
12601   else
12602#endif
12603        return (int)pSiS->tvyscale;
12604}
12605
12606void SiS_SetSISCRT1SaturationGain(ScrnInfoPtr pScrn, int val)
12607{
12608   SISPtr pSiS = SISPTR(pScrn);
12609#ifdef SISDUALHEAD
12610   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12611#endif
12612
12613   pSiS->siscrt1satgain = val;
12614#ifdef SISDUALHEAD
12615   if(pSiSEnt) pSiSEnt->siscrt1satgain = val;
12616#endif
12617
12618   if(!(pSiS->SiS_SD3_Flags & SiS_SD3_CRT1SATGAIN)) return;
12619
12620#ifdef UNLOCK_ALWAYS
12621   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
12622#endif
12623
12624   if((val >= 0) && (val <= 7)) {
12625      setSISIDXREG(SISCR,0x53,0xE3, (val << 2));
12626   }
12627}
12628
12629int SiS_GetSISCRT1SaturationGain(ScrnInfoPtr pScrn)
12630{
12631   SISPtr pSiS = SISPTR(pScrn);
12632   int result = pSiS->siscrt1satgain;
12633   UChar temp;
12634#ifdef SISDUALHEAD
12635   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12636
12637   if(pSiSEnt && pSiS->DualHeadMode)  result = pSiSEnt->siscrt1satgain;
12638#endif
12639
12640   if(!(pSiS->SiS_SD3_Flags & SiS_SD3_CRT1SATGAIN)) return result;
12641
12642#ifdef UNLOCK_ALWAYS
12643   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
12644#endif
12645   inSISIDXREG(SISCR, 0x53, temp);
12646   return (int)((temp >> 2) & 0x07);
12647}
12648
12649/* Calc dotclock from registers */
12650static int
12651SiSGetClockFromRegs(UChar sr2b, UChar sr2c)
12652{
12653   float num, denum, postscalar, divider;
12654   int   myclock;
12655
12656   divider = (sr2b & 0x80) ? 2.0 : 1.0;
12657   postscalar = (sr2c & 0x80) ?
12658              ( (((sr2c >> 5) & 0x03) == 0x02) ? 6.0 : 8.0 ) :
12659	      ( ((sr2c >> 5) & 0x03) + 1.0 );
12660   num = (sr2b & 0x7f) + 1.0;
12661   denum = (sr2c & 0x1f) + 1.0;
12662   myclock = (int)((14318 * (divider / postscalar) * (num / denum)) / 1000);
12663   return myclock;
12664}
12665
12666#ifdef SISDUALHEAD
12667static void
12668SiS_SetDHFlags(SISPtr pSiS, unsigned int misc, unsigned int sd2)
12669{
12670   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12671
12672   if(pSiS->DualHeadMode) {
12673      if(pSiSEnt->pScrn_1) {
12674	 SISPTR(pSiSEnt->pScrn_1)->MiscFlags |= misc;
12675	 SISPTR(pSiSEnt->pScrn_1)->SiS_SD2_Flags |= sd2;
12676      }
12677      if(pSiSEnt->pScrn_2) {
12678	 SISPTR(pSiSEnt->pScrn_2)->MiscFlags |= misc;
12679	 SISPTR(pSiSEnt->pScrn_2)->SiS_SD2_Flags |= sd2;
12680      }
12681   }
12682}
12683#endif
12684
12685/* PostSetMode:
12686 * -) Disable CRT1 for saving bandwidth. This doesn't work with VESA;
12687 *    VESA uses the bridge in SlaveMode and switching CRT1 off while
12688 *    the bridge is in SlaveMode not that clever...
12689 * -) Check if overlay can be used (depending on dotclock)
12690 * -) Check if Panel Scaler is active on LVDS for overlay re-scaling
12691 * -) Save TV registers for further processing
12692 * -) Apply TV settings
12693 */
12694static void
12695SiSPostSetMode(ScrnInfoPtr pScrn, SISRegPtr sisReg)
12696{
12697    SISPtr pSiS = SISPTR(pScrn);
12698#ifdef SISDUALHEAD
12699    SISEntPtr pSiSEnt = pSiS->entityPrivate;
12700#endif
12701    UChar usScratchCR17, sr2b, sr2c, tmpreg;
12702    int   myclock1, myclock2, mycoldepth1, mycoldepth2, temp;
12703    Bool  flag = FALSE;
12704    Bool  doit = TRUE;
12705    Bool  IsInSlaveMode;
12706
12707#ifdef TWDEBUG
12708    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
12709    	"CRT1off is %d\n", pSiS->CRT1off);
12710#endif
12711    pSiS->CRT1isoff = pSiS->CRT1off;
12712
12713#ifdef UNLOCK_ALWAYS
12714    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
12715#endif
12716
12717    SiSFixupSR11(pScrn);
12718
12719    IsInSlaveMode = SiSBridgeIsInSlaveMode(pScrn);
12720
12721    if((!pSiS->UseVESA) && (pSiS->VBFlags & CRT2_ENABLE)) {
12722
12723	if(pSiS->VBFlags != pSiS->VBFlags_backup) {
12724	   pSiS->VBFlags = pSiS->VBFlags_backup;
12725	   xf86DrvMsg(pScrn->scrnIndex, X_INFO,
12726			"VBFlags restored to %0x\n", pSiS->VBFlags);
12727	}
12728
12729	/* -) We can't switch off CRT1 if bridge is in SlaveMode.
12730	 * -) If we change to a SlaveMode-Mode (like 512x384), we
12731	 *    need to adapt VBFlags for eg. Xv.
12732	 */
12733#ifdef SISDUALHEAD
12734	if(!pSiS->DualHeadMode) {
12735#endif
12736	   if(IsInSlaveMode) {
12737	      doit = FALSE;
12738	      temp = pSiS->VBFlags;
12739	      pSiS->VBFlags &= (~VB_DISPMODE_SINGLE);
12740	      pSiS->VBFlags |= (VB_DISPMODE_MIRROR | DISPTYPE_DISP1);
12741              if(temp != pSiS->VBFlags) {
12742		 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
12743		 	"VBFlags changed to 0x%0x\n", pSiS->VBFlags);
12744	      }
12745	   }
12746#ifdef SISDUALHEAD
12747	}
12748#endif
12749
12750	if(pSiS->VGAEngine == SIS_315_VGA) {
12751
12752	   if((pSiS->CRT1off) && (doit)) {
12753	      orSISIDXREG(SISCR,pSiS->myCR63,0x40);
12754	      orSISIDXREG(SISSR,0x1f,0xc0);
12755	      andSISIDXREG(SISSR,0x07,~0x10);
12756	      andSISIDXREG(SISSR,0x06,0xe2);
12757	      andSISIDXREG(SISSR,0x31,0xcf);
12758	      outSISIDXREG(SISSR,0x2b,0x1b);
12759	      outSISIDXREG(SISSR,0x2c,0xe1);
12760	      outSISIDXREG(SISSR,0x2d,0x01);
12761	      outSISIDXREG(SISSR, 0x00, 0x01);    /* Synchronous Reset */
12762	      usleep(10000);
12763	      outSISIDXREG(SISSR, 0x00, 0x03);    /* End Reset */
12764	   } else {
12765	      andSISIDXREG(SISCR,pSiS->myCR63,0xBF);
12766	      andSISIDXREG(SISSR,0x1f,0x3f);
12767	      orSISIDXREG(SISSR,0x07,0x10);
12768	   }
12769
12770	} else {
12771
12772	   if(doit) {
12773	      inSISIDXREG(SISCR, 0x17, usScratchCR17);
12774	      if(pSiS->CRT1off) {
12775		 if(usScratchCR17 & 0x80) {
12776		    flag = TRUE;
12777		    usScratchCR17 &= ~0x80;
12778		 }
12779		 orSISIDXREG(SISSR,0x1f,0xc0);
12780	      } else {
12781		 if(!(usScratchCR17 & 0x80)) {
12782		    flag = TRUE;
12783		    usScratchCR17 |= 0x80;
12784		 }
12785		 andSISIDXREG(SISSR,0x1f,0x3f);
12786	      }
12787	      /* Reset only if status changed */
12788	      if(flag) {
12789		 outSISIDXREG(SISCR, 0x17, usScratchCR17);
12790		 outSISIDXREG(SISSR, 0x00, 0x01);    /* Synchronous Reset */
12791		 usleep(10000);
12792		 outSISIDXREG(SISSR, 0x00, 0x03);    /* End Reset */
12793	      }
12794	   }
12795	}
12796
12797    }
12798
12799    /* Set bridge to "disable CRT2" mode if CRT2 is disabled, LCD-A is enabled */
12800    /* (Not needed for CRT1=VGA since CRT2 will really be disabled then) */
12801#ifdef SISDUALHEAD
12802    if(!pSiS->DualHeadMode) {
12803#endif
12804       if((pSiS->VGAEngine == SIS_315_VGA)  && (pSiS->VBFlags2 & VB2_SISLCDABRIDGE)) {
12805	  if((!pSiS->UseVESA) && (!(pSiS->VBFlags & CRT2_ENABLE)) && (pSiS->VBFlags & CRT1_LCDA)) {
12806	     if(!IsInSlaveMode) {
12807	        andSISIDXREG(SISPART4,0x0d,~0x07);
12808	     }
12809	  }
12810       }
12811#ifdef SISDUALHEAD
12812    }
12813#endif
12814
12815    /* Reset flags */
12816    pSiS->MiscFlags &= ~( MISC_CRT1OVERLAY      |
12817			  MISC_CRT2OVERLAY      |
12818			  MISC_CRT1OVERLAYGAMMA |
12819			  MISC_SIS760ONEOVERLAY |
12820			  MISC_PANELLINKSCALER  |
12821			  MISC_STNMODE		|
12822			  MISC_TVNTSC1024);
12823
12824    pSiS->SiS_SD2_Flags &= ~SiS_SD2_SIS760ONEOVL;
12825
12826#ifdef SISDUALHEAD
12827    if(pSiS->DualHeadMode) {
12828       if(pSiSEnt->pScrn_1) {
12829	  SISPTR(pSiSEnt->pScrn_1)->MiscFlags &= ~(MISC_SIS760ONEOVERLAY	|
12830						   MISC_CRT1OVERLAY		|
12831						   MISC_CRT2OVERLAY		|
12832						   MISC_CRT1OVERLAYGAMMA	|
12833						   MISC_PANELLINKSCALER		|
12834						   MISC_STNMODE			|
12835						   MISC_TVNTSC1024);
12836	  SISPTR(pSiSEnt->pScrn_1)->SiS_SD2_Flags &= ~SiS_SD2_SIS760ONEOVL;
12837       }
12838       if(pSiSEnt->pScrn_2) {
12839	  SISPTR(pSiSEnt->pScrn_2)->MiscFlags &= ~(MISC_SIS760ONEOVERLAY	|
12840						   MISC_CRT1OVERLAY		|
12841						   MISC_CRT2OVERLAY		|
12842						   MISC_CRT1OVERLAYGAMMA	|
12843						   MISC_PANELLINKSCALER		|
12844						   MISC_STNMODE			|
12845						   MISC_TVNTSC1024);
12846	  SISPTR(pSiSEnt->pScrn_2)->SiS_SD2_Flags &= ~SiS_SD2_SIS760ONEOVL;
12847       }
12848    }
12849#endif
12850
12851    /* Determine if the video overlay can be used */
12852    if(!pSiS->NoXvideo) {
12853
12854       int clklimit1=0, clklimit2=0, clklimitg=0;
12855       Bool OverlayHandled = FALSE;
12856
12857       inSISIDXREG(SISSR,0x2b,sr2b);
12858       inSISIDXREG(SISSR,0x2c,sr2c);
12859       myclock1 = myclock2 = SiSGetClockFromRegs(sr2b, sr2c);
12860       inSISIDXREG(SISSR,0x06,tmpreg);
12861       switch((tmpreg & 0x1c) >> 2) {
12862       case 0:  mycoldepth1 = 1; break;
12863       case 1:
12864       case 2:  mycoldepth1 = 2; break;
12865       default: mycoldepth1 = 4;
12866       }
12867       mycoldepth2 = mycoldepth1;
12868
12869       if((!IsInSlaveMode) && (pSiS->VBFlags & CRT2_ENABLE)) {
12870	  if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
12871	     inSISIDXREG(SISPART4,0x0a,sr2b);
12872	     inSISIDXREG(SISPART4,0x0b,sr2c);
12873	  } else {
12874	     inSISIDXREG(SISSR,0x2e,sr2b);
12875	     inSISIDXREG(SISSR,0x2f,sr2c);
12876	  }
12877	  myclock2 = SiSGetClockFromRegs(sr2b, sr2c);
12878	  inSISIDXREG(SISPART1,0x00,tmpreg);
12879	  tmpreg &= 0x0f;
12880	  switch(tmpreg) {
12881	  case 8:  mycoldepth2 = 1; break;
12882	  case 4:
12883	  case 2:  mycoldepth2 = 2; break;
12884	  default: mycoldepth2 = 4;
12885	  }
12886       }
12887
12888       switch(pSiS->ChipType) {
12889
12890	 case SIS_300:
12891	 case SIS_540:
12892	 case SIS_630:
12893	 case SIS_730:
12894	    clklimit1 = clklimit2 = clklimitg = 150;
12895	    break;
12896
12897	 case SIS_550:
12898	 case SIS_650:
12899	 case SIS_740:
12900	    clklimit1 = clklimit2 = 175;  /* verified for 65x */
12901	    clklimitg = 166;		  /* ? */
12902	    break;
12903
12904	 case SIS_661:
12905	 case SIS_741:
12906	    clklimit1 = clklimit2 = 190;  /* ? */
12907	    clklimitg = 180;		  /* ? */
12908	    break;
12909
12910	 case SIS_760:
12911	 case SIS_761:
12912	    clklimit1 = clklimit2 = 190;    /* ? */
12913	    if(pSiS->ChipFlags & SiSCF_760LFB) {		/* LFB only or hybrid */
12914	       clklimit1 = clklimit2 = 220; /* ? */
12915	    }
12916	    clklimitg = 200;		    /* ? */
12917
12918	    if(pSiS->SiS_SD2_Flags & SiS_SD2_SUPPORT760OO) {	/* UMA only */
12919
12920	       Bool OnlyOne = FALSE, NoOverlay = FALSE;
12921	       int dotclocksum = 0;
12922
12923	       if(pSiS->VBFlags & DISPTYPE_CRT1)                     dotclocksum += myclock1;
12924	       if((!IsInSlaveMode) && (pSiS->VBFlags & CRT2_ENABLE)) dotclocksum += myclock2;
12925
12926	       /* TODO: Find out under what circumstances only one
12927		*	overlay is usable in UMA-only mode.
12928		*	This is not entirely accurate; the overlay
12929		*	scaler also requires some time, so even though
12930		*	the dotclocks are below these values, some
12931		*	distortions in the overlay may occure.
12932		*	Solution: Don't use a 760 with shared memory.
12933		*/
12934	       if( (pSiS->VBFlags & DISPTYPE_CRT1) &&
12935		   (pSiS->VBFlags & CRT2_ENABLE) &&
12936		   (mycoldepth1 != mycoldepth2) ) {
12937
12938		  /* 0. If coldepths are different (only possible in dual head mode),
12939		   *    I have no idea to calculate the limits; hence, allow only one
12940		   *    overlay in all cases.
12941		   */
12942		  OnlyOne = TRUE;
12943
12944	       } else if(pSiS->MemClock < 150000) {
12945
12946		  /* 1. MCLK <150: If someone seriously considers using such
12947		   *    slow RAM, so be it. Only one overlay in call cases.
12948		   */
12949		  OnlyOne = TRUE;
12950
12951	       } else if(pSiS->MemClock < 170000) {
12952
12953		  /* 2. MCLK 166 */
12954		  switch(pSiS->CurrentLayout.bitsPerPixel) {
12955		     case 32: if(dotclocksum > 133) OnlyOne = TRUE;		/* One overlay; verified */
12956			      if(dotclocksum > 180) NoOverlay = TRUE;		/* No overlay; verified */
12957			      break;
12958		     case 16: if(dotclocksum > 175) OnlyOne = TRUE;		/* One overlay; verified */
12959			      if(dotclocksum > 260) NoOverlay = TRUE;;		/* No overlay; FIXME */
12960			      break;
12961		  }
12962
12963	       } else if(pSiS->MemClock < 210000) {
12964
12965		  /* 3. MCLK 200 */
12966		  switch(pSiS->CurrentLayout.bitsPerPixel) {
12967		     case 32: if(dotclocksum > 160) OnlyOne = TRUE;		/* One overlay; FIXME */
12968			      if(dotclocksum > 216) NoOverlay = TRUE;;		/* No overlay; FIXME */
12969			      break;
12970		     case 16: if(dotclocksum > 210) OnlyOne = TRUE;		/* One overlay; FIXME */
12971			      if(dotclocksum > 312) NoOverlay = TRUE;;		/* No overlay; FIXME */
12972			      break;
12973		  }
12974
12975	       }
12976
12977	       if(OnlyOne || NoOverlay) {
12978
12979		  ULong tmpflags = 0;
12980
12981		  if(!NoOverlay) {
12982		     if(myclock1 <= clklimit1) tmpflags |= MISC_CRT1OVERLAY;
12983		     if(myclock2 <= clklimit2) tmpflags |= MISC_CRT2OVERLAY;
12984		     if(myclock1 <= clklimitg) tmpflags |= MISC_CRT1OVERLAYGAMMA;
12985		     pSiS->MiscFlags |= tmpflags;
12986		  }
12987		  pSiS->MiscFlags |= MISC_SIS760ONEOVERLAY;
12988		  pSiS->SiS_SD2_Flags |= SiS_SD2_SIS760ONEOVL;
12989#ifdef SISDUALHEAD
12990		  SiS_SetDHFlags(pSiS, (tmpflags | MISC_SIS760ONEOVERLAY), SiS_SD2_SIS760ONEOVL);
12991#endif
12992		  OverlayHandled = TRUE;
12993	       }
12994
12995	       xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
12996			"SiS76x/UMA: %s video overlay(s) available in current mode\n",
12997			NoOverlay ? "no" : ((pSiS->MiscFlags & MISC_SIS760ONEOVERLAY) ? "one" : "two"));
12998
12999#ifdef TWDEBUG
13000	       xf86DrvMsg(0, 0, "SiS760: Memclock %d, c1 %d/%d c2 %d/%d, sum %d / %x\n",
13001			pSiS->MemClock, myclock1, mycoldepth1,
13002			myclock2, mycoldepth2, dotclocksum, pSiS->SiS_SD2_Flags);
13003#endif
13004	    }
13005	    break;
13006
13007	 case SIS_660:
13008	    clklimit1 = clklimit2 = 200;  /* ? */
13009	    if(pSiS->ChipFlags & SiSCF_760LFB) {		/* LFB only */
13010	       clklimit1 = clklimit2 = 220;
13011	    }
13012	    clklimitg = 200;		  /* ? */
13013	    break;
13014
13015	 case SIS_315H:
13016	 case SIS_315:
13017	 case SIS_315PRO:
13018	 case SIS_330:
13019	    clklimit1 = clklimit2 = 180;  /* ? */
13020	    clklimitg = 166;		  /* ? */
13021	    break;
13022
13023	 case SIS_340: /* ? */
13024	 case XGI_20:
13025	 case XGI_40:
13026	    clklimit1 = clklimit2 = 240;  /* ? */
13027	    clklimitg = 200;		  /* ? */
13028	    break;
13029       }
13030
13031       if(!OverlayHandled) {
13032          ULong tmpflags = 0;
13033          if(myclock1 <= clklimit1) tmpflags |= MISC_CRT1OVERLAY;
13034          if(myclock2 <= clklimit2) tmpflags |= MISC_CRT2OVERLAY;
13035          if(myclock1 <= clklimitg) tmpflags |= MISC_CRT1OVERLAYGAMMA;
13036	  pSiS->MiscFlags |= tmpflags;
13037#ifdef SISDUALHEAD
13038	  SiS_SetDHFlags(pSiS, tmpflags, 0);
13039#endif
13040          if(!(pSiS->MiscFlags & MISC_CRT1OVERLAY)) {
13041#ifdef SISDUALHEAD
13042             if((!pSiS->DualHeadMode) || (pSiS->SecondHead))
13043#endif
13044		xf86DrvMsgVerb(pScrn->scrnIndex, X_WARNING, 3,
13045		   "Current dotclock (%dMhz) too high for video overlay on CRT1\n",
13046		   myclock1);
13047          }
13048          if((pSiS->VBFlags & CRT2_ENABLE) && (!(pSiS->MiscFlags & MISC_CRT2OVERLAY))) {
13049#ifdef SISDUALHEAD
13050	     if((!pSiS->DualHeadMode) || (!pSiS->SecondHead))
13051#endif
13052		xf86DrvMsgVerb(pScrn->scrnIndex, X_WARNING, 3,
13053		   "Current dotclock (%dMhz) too high for video overlay on CRT2\n",
13054		   myclock2);
13055	  }
13056       }
13057
13058    }
13059
13060    /* Determine if the Panel Link scaler is active */
13061
13062    if(pSiS->VBFlags & (CRT2_LCD | CRT1_LCDA)) {
13063       ULong tmpflags = 0;
13064       if(pSiS->VGAEngine == SIS_300_VGA) {
13065	  if(pSiS->VBFlags2 & (VB2_LVDS | VB2_30xBDH)) {
13066	     inSISIDXREG(SISPART1,0x1e,tmpreg);
13067	     tmpreg &= 0x3f;
13068	     if(tmpreg) tmpflags |= MISC_PANELLINKSCALER;
13069	  }
13070       } else {
13071	  if((pSiS->VBFlags2 & (VB2_LVDS | VB2_30xBDH)) || (pSiS->VBFlags & CRT1_LCDA)) {
13072	     inSISIDXREG(SISPART1,0x35,tmpreg);
13073	     tmpreg &= 0x04;
13074	     if(!tmpreg)  tmpflags |= MISC_PANELLINKSCALER;
13075	  }
13076       }
13077       pSiS->MiscFlags |= tmpflags;
13078#ifdef SISDUALHEAD
13079       SiS_SetDHFlags(pSiS, tmpflags, 0);
13080#endif
13081    }
13082
13083    /* Determine if STN is active */
13084    if(pSiS->ChipType == SIS_550) {
13085       if((pSiS->VBFlags & CRT2_LCD) && (pSiS->FSTN || pSiS->DSTN)) {
13086	  inSISIDXREG(SISCR,0x34,tmpreg);
13087	  tmpreg &= 0x7f;
13088	  if(tmpreg == 0x5a || tmpreg == 0x5b) {
13089	     pSiS->MiscFlags |= MISC_STNMODE;
13090#ifdef SISDUALHEAD
13091	     SiS_SetDHFlags(pSiS, MISC_STNMODE, 0);
13092#endif
13093	  }
13094       }
13095    }
13096
13097    /* Determine if our very special TV mode is active */
13098    if((pSiS->VBFlags2 & VB2_SISBRIDGE) && (pSiS->VBFlags & CRT2_TV) && (!(pSiS->VBFlags & TV_HIVISION))) {
13099       if( ((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR525I)) ||
13100	   ((!(pSiS->VBFlags & TV_YPBPR)) && (pSiS->VBFlags & (TV_NTSC | TV_PALM))) ) {
13101	  inSISIDXREG(SISCR,0x34,tmpreg);
13102	  tmpreg &= 0x7f;
13103	  if((tmpreg == 0x64) || (tmpreg == 0x4a) || (tmpreg == 0x38)) {
13104	     pSiS->MiscFlags |= MISC_TVNTSC1024;
13105#ifdef SISDUALHEAD
13106	     SiS_SetDHFlags(pSiS, MISC_TVNTSC1024, 0);
13107#endif
13108	  }
13109       }
13110    }
13111
13112    if(pSiS->VGAEngine == SIS_315_VGA) {
13113       int i;
13114#ifdef SISVRAMQ
13115       /* Re-Enable and reset command queue */
13116       SiSEnableTurboQueue(pScrn);
13117#endif
13118       /* Get HWCursor register contents for backup */
13119       for(i = 0; i < 16; i++) {
13120          pSiS->HWCursorBackup[i] = SIS_MMIO_IN32(pSiS->IOBase, 0x8500 + (i << 2));
13121       }
13122       if(pSiS->ChipType >= SIS_330) {
13123          /* Enable HWCursor protection (Y pos as trigger) */
13124          andSISIDXREG(SISCR, 0x5b, ~0x30);
13125       }
13126    }
13127
13128    /* Re-initialize accelerator engine */
13129    /* (We are sync'ed here) */
13130    if(!pSiS->NoAccel) {
13131       if(pSiS->InitAccel) {
13132          (pSiS->InitAccel)(pScrn);
13133       }
13134    }
13135
13136    /* Set display device gamma (for SISCTRL) */
13137    if(pSiS->VBFlags & CRT1_LCDA)
13138       pSiS->CRT1MonGamma = pSiS->CRT2LCDMonitorGamma;
13139    else
13140       pSiS->CRT1MonGamma = pSiS->CRT1VGAMonitorGamma;
13141
13142    if(pSiS->VBFlags & CRT2_LCD)
13143       pSiS->CRT2MonGamma = pSiS->CRT2LCDMonitorGamma;
13144    else if(pSiS->VBFlags & CRT2_TV) {
13145       if(pSiS->VBFlags & TV_YPBPR)
13146          pSiS->CRT2MonGamma = 2200; /* */
13147       else if(pSiS->VBFlags & TV_HIVISION)
13148          pSiS->CRT2MonGamma = 2200; /* ? */
13149       else if(pSiS->VBFlags & TV_NTSC)
13150          pSiS->CRT2MonGamma = 2200; /* NTSC */
13151       else
13152          pSiS->CRT2MonGamma = 2800; /* All PAL modes? */
13153    } else if(pSiS->VBFlags & CRT2_VGA)
13154       pSiS->CRT2MonGamma = pSiS->CRT2VGAMonitorGamma;
13155    else
13156       pSiS->CRT2MonGamma = 0; /* Unknown */
13157
13158    /* Reset XV display properties (such as number of overlays, etc) */
13159    /* (And copy monitor gamma) */
13160#ifdef SISDUALHEAD
13161    if(pSiS->DualHeadMode) {
13162       if(pSiSEnt->pScrn_1) {
13163	  if(SISPTR(pSiSEnt->pScrn_1)->ResetXvDisplay) {
13164	     (SISPTR(pSiSEnt->pScrn_1)->ResetXvDisplay)(pSiSEnt->pScrn_1);
13165	  }
13166	  SISPTR(pSiSEnt->pScrn_1)->CRT1MonGamma = pSiS->CRT1MonGamma;
13167	  SISPTR(pSiSEnt->pScrn_1)->CRT2MonGamma = pSiS->CRT2MonGamma;
13168       }
13169       if(pSiSEnt->pScrn_2) {
13170	  if(SISPTR(pSiSEnt->pScrn_2)->ResetXvDisplay) {
13171	     (SISPTR(pSiSEnt->pScrn_1)->ResetXvDisplay)(pSiSEnt->pScrn_2);
13172	  }
13173	  SISPTR(pSiSEnt->pScrn_2)->CRT1MonGamma = pSiS->CRT1MonGamma;
13174	  SISPTR(pSiSEnt->pScrn_2)->CRT2MonGamma = pSiS->CRT2MonGamma;
13175       }
13176    } else {
13177#endif
13178       if(pSiS->ResetXvDisplay) {
13179	  (pSiS->ResetXvDisplay)(pScrn);
13180       }
13181#ifdef SISDUALHEAD
13182    }
13183#endif
13184
13185    /* Reset XV gamma correction */
13186    if(pSiS->ResetXvGamma) {
13187       (pSiS->ResetXvGamma)(pScrn);
13188    }
13189
13190    /* Reset various display parameters */
13191    {
13192       int val = pSiS->siscrt1satgain;
13193#ifdef SISDUALHEAD
13194       if(pSiS->DualHeadMode && pSiSEnt) val = pSiSEnt->siscrt1satgain;
13195#endif
13196       SiS_SetSISCRT1SaturationGain(pScrn, val);
13197    }
13198
13199    /*  Apply TV settings given by options
13200           Do this even in DualHeadMode:
13201	   - if this is called by SetModeCRT1, CRT2 mode has been reset by SetModeCRT1
13202	   - if this is called by SetModeCRT2, CRT2 mode has changed (duh!)
13203	   -> Hence, in both cases, the settings must be re-applied.
13204     */
13205
13206    if(pSiS->VBFlags & CRT2_TV) {
13207       int val;
13208       if(pSiS->VBFlags2 & VB2_CHRONTEL) {
13209	  int mychtvlumabandwidthcvbs = pSiS->chtvlumabandwidthcvbs;
13210	  int mychtvlumabandwidthsvideo = pSiS->chtvlumabandwidthsvideo;
13211	  int mychtvlumaflickerfilter = pSiS->chtvlumaflickerfilter;
13212	  int mychtvchromabandwidth = pSiS->chtvchromabandwidth;
13213	  int mychtvchromaflickerfilter = pSiS->chtvchromaflickerfilter;
13214	  int mychtvcvbscolor = pSiS->chtvcvbscolor;
13215	  int mychtvtextenhance = pSiS->chtvtextenhance;
13216	  int mychtvcontrast = pSiS->chtvcontrast;
13217	  int mytvxpos = pSiS->tvxpos;
13218	  int mytvypos = pSiS->tvypos;
13219#ifdef SISDUALHEAD
13220	  if(pSiSEnt && pSiS->DualHeadMode) {
13221	     mychtvlumabandwidthcvbs = pSiSEnt->chtvlumabandwidthcvbs;
13222	     mychtvlumabandwidthsvideo = pSiSEnt->chtvlumabandwidthsvideo;
13223	     mychtvlumaflickerfilter = pSiSEnt->chtvlumaflickerfilter;
13224	     mychtvchromabandwidth = pSiSEnt->chtvchromabandwidth;
13225	     mychtvchromaflickerfilter = pSiSEnt->chtvchromaflickerfilter;
13226	     mychtvcvbscolor = pSiSEnt->chtvcvbscolor;
13227	     mychtvtextenhance = pSiSEnt->chtvtextenhance;
13228	     mychtvcontrast = pSiSEnt->chtvcontrast;
13229	     mytvxpos = pSiSEnt->tvxpos;
13230	     mytvypos = pSiSEnt->tvypos;
13231	  }
13232#endif
13233	  if((val = mychtvlumabandwidthcvbs) != -1) {
13234	     SiS_SetCHTVlumabandwidthcvbs(pScrn, val);
13235	  }
13236	  if((val = mychtvlumabandwidthsvideo) != -1) {
13237	     SiS_SetCHTVlumabandwidthsvideo(pScrn, val);
13238	  }
13239	  if((val = mychtvlumaflickerfilter) != -1) {
13240	     SiS_SetCHTVlumaflickerfilter(pScrn, val);
13241	  }
13242	  if((val = mychtvchromabandwidth) != -1) {
13243	     SiS_SetCHTVchromabandwidth(pScrn, val);
13244	  }
13245	  if((val = mychtvchromaflickerfilter) != -1) {
13246	     SiS_SetCHTVchromaflickerfilter(pScrn, val);
13247	  }
13248	  if((val = mychtvcvbscolor) != -1) {
13249	     SiS_SetCHTVcvbscolor(pScrn, val);
13250	  }
13251	  if((val = mychtvtextenhance) != -1) {
13252	     SiS_SetCHTVtextenhance(pScrn, val);
13253	  }
13254	  if((val = mychtvcontrast) != -1) {
13255	     SiS_SetCHTVcontrast(pScrn, val);
13256	  }
13257	  /* Backup default TV position registers */
13258	  switch(pSiS->ChrontelType) {
13259	  case CHRONTEL_700x:
13260	     pSiS->tvx = SiS_GetCH700x(pSiS->SiS_Pr, 0x0a);
13261	     pSiS->tvx |= (((SiS_GetCH700x(pSiS->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
13262	     pSiS->tvy = SiS_GetCH700x(pSiS->SiS_Pr, 0x0b);
13263	     pSiS->tvy |= ((SiS_GetCH700x(pSiS->SiS_Pr, 0x08) & 0x01) << 8);
13264#ifdef SISDUALHEAD
13265	     if(pSiSEnt) {
13266		pSiSEnt->tvx = pSiS->tvx;
13267		pSiSEnt->tvy = pSiS->tvy;
13268	     }
13269#endif
13270	     break;
13271	  case CHRONTEL_701x:
13272	     /* Not supported by hardware */
13273	     break;
13274	  }
13275	  if((val = mytvxpos) != 0) {
13276	     SiS_SetTVxposoffset(pScrn, val);
13277	  }
13278	  if((val = mytvypos) != 0) {
13279	     SiS_SetTVyposoffset(pScrn, val);
13280	  }
13281       }
13282       if(pSiS->VBFlags2 & VB2_301) {
13283          int mysistvedgeenhance = pSiS->sistvedgeenhance;
13284#ifdef SISDUALHEAD
13285          if(pSiSEnt && pSiS->DualHeadMode) {
13286	     mysistvedgeenhance = pSiSEnt->sistvedgeenhance;
13287	  }
13288#endif
13289          if((val = mysistvedgeenhance) != -1) {
13290	     SiS_SetSISTVedgeenhance(pScrn, val);
13291	  }
13292       }
13293       if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
13294          int mysistvantiflicker = pSiS->sistvantiflicker;
13295	  int mysistvsaturation = pSiS->sistvsaturation;
13296	  int mysistvcolcalibf = pSiS->sistvcolcalibf;
13297	  int mysistvcolcalibc = pSiS->sistvcolcalibc;
13298	  int mysistvcfilter = pSiS->sistvcfilter;
13299	  int mysistvyfilter = pSiS->sistvyfilter;
13300	  int mytvxpos = pSiS->tvxpos;
13301	  int mytvypos = pSiS->tvypos;
13302	  int mytvxscale = pSiS->tvxscale;
13303	  int mytvyscale = pSiS->tvyscale;
13304	  int i;
13305	  ULong cbase;
13306	  UChar ctemp;
13307#ifdef SISDUALHEAD
13308          if(pSiSEnt && pSiS->DualHeadMode) {
13309	     mysistvantiflicker = pSiSEnt->sistvantiflicker;
13310	     mysistvsaturation = pSiSEnt->sistvsaturation;
13311	     mysistvcolcalibf = pSiSEnt->sistvcolcalibf;
13312	     mysistvcolcalibc = pSiSEnt->sistvcolcalibc;
13313	     mysistvcfilter = pSiSEnt->sistvcfilter;
13314	     mysistvyfilter = pSiSEnt->sistvyfilter;
13315	     mytvxpos = pSiSEnt->tvxpos;
13316	     mytvypos = pSiSEnt->tvypos;
13317	     mytvxscale = pSiSEnt->tvxscale;
13318	     mytvyscale = pSiSEnt->tvyscale;
13319	  }
13320#endif
13321          /* Backup default TV position, scale and colcalib registers */
13322	  inSISIDXREG(SISPART2,0x1f,pSiS->p2_1f);
13323	  inSISIDXREG(SISPART2,0x20,pSiS->p2_20);
13324	  inSISIDXREG(SISPART2,0x2b,pSiS->p2_2b);
13325	  inSISIDXREG(SISPART2,0x42,pSiS->p2_42);
13326	  inSISIDXREG(SISPART2,0x43,pSiS->p2_43);
13327	  inSISIDXREG(SISPART2,0x01,pSiS->p2_01);
13328	  inSISIDXREG(SISPART2,0x02,pSiS->p2_02);
13329	  inSISIDXREG(SISPART2,0x44,pSiS->p2_44);
13330	  inSISIDXREG(SISPART2,0x45,pSiS->p2_45);
13331	  if(!(pSiS->VBFlags2 & VB2_301)) {
13332	     inSISIDXREG(SISPART2,0x46,pSiS->p2_46);
13333	  } else {
13334	     pSiS->p2_46 = 0;
13335	  }
13336	  inSISIDXREG(SISPART2,0x0a,pSiS->p2_0a);
13337	  inSISIDXREG(SISPART2,0x31,cbase);
13338	  cbase = (cbase & 0x7f) << 8;
13339	  inSISIDXREG(SISPART2,0x32,ctemp);
13340	  cbase = (cbase | ctemp) << 8;
13341	  inSISIDXREG(SISPART2,0x33,ctemp);
13342	  cbase = (cbase | ctemp) << 8;
13343	  inSISIDXREG(SISPART2,0x34,ctemp);
13344	  pSiS->sistvccbase = (cbase | ctemp);
13345	  inSISIDXREG(SISPART2,0x35,pSiS->p2_35);
13346	  inSISIDXREG(SISPART2,0x36,pSiS->p2_36);
13347	  inSISIDXREG(SISPART2,0x37,pSiS->p2_37);
13348	  inSISIDXREG(SISPART2,0x38,pSiS->p2_38);
13349	  if(!(pSiS->VBFlags2 & VB2_301)) {
13350	     inSISIDXREG(SISPART2,0x47,pSiS->p2_47);
13351	     inSISIDXREG(SISPART2,0x48,pSiS->p2_48);
13352	     inSISIDXREG(SISPART2,0x49,pSiS->p2_49);
13353	     inSISIDXREG(SISPART2,0x4a,pSiS->p2_4a);
13354	  }
13355	  inSISIDXREG(SISPART2,0x2f,pSiS->p2_2f);
13356	  inSISIDXREG(SISPART2,0x30,pSiS->p2_30);
13357	  for(i=0; i<9; i++) {
13358	     inSISIDXREG(SISPART1,SiSScalingP1Regs[i],pSiS->scalingp1[i]);
13359	  }
13360	  for(i=0; i<9; i++) {
13361	     inSISIDXREG(SISPART4,SiSScalingP4Regs[i],pSiS->scalingp4[i]);
13362	  }
13363	  if(pSiS->VBFlags2 & VB2_SISTAP4SCALER) {
13364	     for(i=0; i<64; i++) {
13365	        inSISIDXREG(SISPART2,(0xc0 + i),pSiS->scalingp2[i]);
13366  	     }
13367	  }
13368#ifdef SISDUALHEAD
13369	  if(pSiSEnt) {
13370	     pSiSEnt->p2_1f = pSiS->p2_1f; pSiSEnt->p2_20 = pSiS->p2_20;
13371	     pSiSEnt->p2_42 = pSiS->p2_42; pSiSEnt->p2_43 = pSiS->p2_43;
13372	     pSiSEnt->p2_2b = pSiS->p2_2b;
13373	     pSiSEnt->p2_01 = pSiS->p2_01; pSiSEnt->p2_02 = pSiS->p2_02;
13374	     pSiSEnt->p2_44 = pSiS->p2_44; pSiSEnt->p2_45 = pSiS->p2_45;
13375	     pSiSEnt->p2_46 = pSiS->p2_46; pSiSEnt->p2_0a = pSiS->p2_0a;
13376	     pSiSEnt->sistvccbase = pSiS->sistvccbase;
13377	     pSiSEnt->p2_35 = pSiS->p2_35; pSiSEnt->p2_36 = pSiS->p2_36;
13378	     pSiSEnt->p2_37 = pSiS->p2_37; pSiSEnt->p2_38 = pSiS->p2_38;
13379	     pSiSEnt->p2_48 = pSiS->p2_48; pSiSEnt->p2_49 = pSiS->p2_49;
13380	     pSiSEnt->p2_4a = pSiS->p2_4a; pSiSEnt->p2_2f = pSiS->p2_2f;
13381	     pSiSEnt->p2_30 = pSiS->p2_30; pSiSEnt->p2_47 = pSiS->p2_47;
13382	     for(i=0; i<9; i++) {
13383	        pSiSEnt->scalingp1[i] = pSiS->scalingp1[i];
13384	     }
13385	     for(i=0; i<9; i++) {
13386	        pSiSEnt->scalingp4[i] = pSiS->scalingp4[i];
13387	     }
13388	     if(pSiS->VBFlags2 & VB2_SISTAP4SCALER) {
13389	        for(i=0; i<64; i++) {
13390	           pSiSEnt->scalingp2[i] = pSiS->scalingp2[i];
13391  	        }
13392	     }
13393	  }
13394#endif
13395          if((val = mysistvantiflicker) != -1) {
13396	     SiS_SetSISTVantiflicker(pScrn, val);
13397	  }
13398	  if((val = mysistvsaturation) != -1) {
13399	     SiS_SetSISTVsaturation(pScrn, val);
13400	  }
13401	  if((val = mysistvcfilter) != -1) {
13402	     SiS_SetSISTVcfilter(pScrn, val);
13403	  }
13404	  if((val = mysistvyfilter) != 1) {
13405	     SiS_SetSISTVyfilter(pScrn, val);
13406	  }
13407	  if((val = mysistvcolcalibc) != 0) {
13408	     SiS_SetSISTVcolcalib(pScrn, val, TRUE);
13409	  }
13410	  if((val = mysistvcolcalibf) != 0) {
13411	     SiS_SetSISTVcolcalib(pScrn, val, FALSE);
13412	  }
13413	  if((val = mytvxpos) != 0) {
13414	     SiS_SetTVxposoffset(pScrn, val);
13415	  }
13416	  if((val = mytvypos) != 0) {
13417	     SiS_SetTVyposoffset(pScrn, val);
13418	  }
13419	  if((val = mytvxscale) != 0) {
13420	     SiS_SetTVxscale(pScrn, val);
13421	  }
13422	  if((val = mytvyscale) != 0) {
13423	     SiS_SetTVyscale(pScrn, val);
13424	  }
13425       }
13426    }
13427
13428}
13429
13430/* Post-set SiS6326 TV registers */
13431static void
13432SiS6326PostSetMode(ScrnInfoPtr pScrn, SISRegPtr sisReg)
13433{
13434    SISPtr pSiS = SISPTR(pScrn);
13435    UChar tmp;
13436    int val;
13437
13438    if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) return;
13439
13440#ifdef UNLOCK_ALWAYS
13441    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
13442#endif
13443
13444    /* Backup default TV position registers */
13445    pSiS->tvx1 = SiS6326GetTVReg(pScrn,0x3a);
13446    pSiS->tvx1 |= ((SiS6326GetTVReg(pScrn,0x3c) & 0x0f) << 8);
13447    pSiS->tvx2 = SiS6326GetTVReg(pScrn,0x26);
13448    pSiS->tvx2 |= ((SiS6326GetTVReg(pScrn,0x27) & 0xf0) << 4);
13449    pSiS->tvx3 = SiS6326GetTVReg(pScrn,0x12);
13450    pSiS->tvx3 |= ((SiS6326GetTVReg(pScrn,0x13) & 0xC0) << 2);
13451    pSiS->tvy1 = SiS6326GetTVReg(pScrn,0x11);
13452    pSiS->tvy1 |= ((SiS6326GetTVReg(pScrn,0x13) & 0x30) << 4);
13453
13454    /* Handle TVPosOffset options (BEFORE switching on TV) */
13455    if((val = pSiS->tvxpos) != 0) {
13456       SiS_SetTVxposoffset(pScrn, val);
13457    }
13458    if((val = pSiS->tvypos) != 0) {
13459       SiS_SetTVyposoffset(pScrn, val);
13460    }
13461
13462    /* Switch on TV output. This is rather complicated, but
13463     * if we don't do it, TV output will flicker terribly.
13464     */
13465    if(pSiS->SiS6326Flags & SIS6326_TVON) {
13466       orSISIDXREG(SISSR, 0x01, 0x20);
13467       tmp = SiS6326GetTVReg(pScrn,0x00);
13468       tmp &= ~0x04;
13469       while(!(inSISREG(SISINPSTAT) & 0x08));    /* Wait while NOT vb */
13470       SiS6326SetTVReg(pScrn,0x00,tmp);
13471       for(val=0; val < 2; val++) {
13472         while(!(inSISREG(SISINPSTAT) & 0x08));  /* Wait while NOT vb */
13473         while(inSISREG(SISINPSTAT) & 0x08);     /* wait while vb     */
13474       }
13475       SiS6326SetTVReg(pScrn, 0x00, sisReg->sis6326tv[0]);
13476       tmp = inSISREG(SISINPSTAT);
13477       outSISREG(SISAR, 0x20);
13478       tmp = inSISREG(SISINPSTAT);
13479       while(inSISREG(SISINPSTAT) & 0x01);
13480       while(!(inSISREG(SISINPSTAT) & 0x01));
13481       andSISIDXREG(SISSR, 0x01, ~0x20);
13482       for(val=0; val < 10; val++) {
13483         while(!(inSISREG(SISINPSTAT) & 0x08));  /* Wait while NOT vb */
13484         while(inSISREG(SISINPSTAT) & 0x08);     /* wait while vb     */
13485       }
13486       andSISIDXREG(SISSR, 0x01, ~0x20);
13487    }
13488
13489    tmp = SiS6326GetTVReg(pScrn,0x00);
13490    if(!(tmp & 0x04)) return;
13491
13492    /* Apply TV settings given by options */
13493    if((val = pSiS->sistvantiflicker) != -1) {
13494       SiS_SetSIS6326TVantiflicker(pScrn, val);
13495    }
13496    if((val = pSiS->sis6326enableyfilter) != -1) {
13497       SiS_SetSIS6326TVenableyfilter(pScrn, val);
13498    }
13499    if((val = pSiS->sis6326yfilterstrong) != -1) {
13500       SiS_SetSIS6326TVyfilterstrong(pScrn, val);
13501    }
13502
13503}
13504
13505/* Check if video bridge is in slave mode */
13506Bool
13507SiSBridgeIsInSlaveMode(ScrnInfoPtr pScrn)
13508{
13509    SISPtr pSiS = SISPTR(pScrn);
13510    UChar  usScrP1_00;
13511
13512    if(!(pSiS->VBFlags2 & VB2_VIDEOBRIDGE)) return FALSE;
13513
13514    inSISIDXREG(SISPART1,0x00,usScrP1_00);
13515    if( ((pSiS->VGAEngine == SIS_300_VGA) && (usScrP1_00 & 0xa0) == 0x20) ||
13516        ((pSiS->VGAEngine == SIS_315_VGA) && (usScrP1_00 & 0x50) == 0x10) ) {
13517       return TRUE;
13518    }
13519
13520    return FALSE;
13521}
13522
13523/* Build a list of the VESA modes the BIOS reports as valid */
13524static void
13525SiSBuildVesaModeList(ScrnInfoPtr pScrn, vbeInfoPtr pVbe, VbeInfoBlock *vbe)
13526{
13527    SISPtr pSiS = SISPTR(pScrn);
13528    int i = 0;
13529
13530    while(vbe->VideoModePtr[i] != 0xffff) {
13531       sisModeInfoPtr m;
13532       VbeModeInfoBlock *mode;
13533       int id = vbe->VideoModePtr[i++];
13534
13535       if((mode = VBEGetModeInfo(pVbe, id)) == NULL) {
13536	  continue;
13537       }
13538
13539       m = xnfcalloc(sizeof(sisModeInfoRec), 1);
13540       if(!m) {
13541	  VBEFreeModeInfo(mode);
13542	  continue;
13543       }
13544       m->width = mode->XResolution;
13545       m->height = mode->YResolution;
13546       m->bpp = mode->BitsPerPixel;
13547       m->n = id;
13548       m->next = pSiS->SISVESAModeList;
13549
13550       pSiS->SISVESAModeList = m;
13551
13552       VBEFreeModeInfo(mode);
13553
13554       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
13555	   "VESA BIOS supports mode number 0x%x: %ix%i (%i bpp)\n",
13556	   m->n, m->width, m->height, m->bpp);
13557    }
13558}
13559
13560/* Get VESA mode number from given resolution/depth */
13561static UShort
13562SiSCalcVESAModeIndex(ScrnInfoPtr pScrn, DisplayModePtr mode)
13563{
13564    SISPtr pSiS = SISPTR(pScrn);
13565    sisModeInfoPtr m = pSiS->SISVESAModeList;
13566    UShort i = (pScrn->bitsPerPixel+7)/8 - 1;
13567    UShort ModeNumber = 0;
13568    int j;
13569
13570    while(m) {
13571       if( (pScrn->bitsPerPixel == m->bpp) &&
13572	   (mode->HDisplay == m->width)    &&
13573	   (mode->VDisplay == m->height) )
13574	  return m->n;
13575       m = m->next;
13576    }
13577
13578    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
13579        "No valid VESA BIOS mode found for %dx%d (%d bpp)\n",
13580        mode->HDisplay, mode->VDisplay, pScrn->bitsPerPixel);
13581
13582    if(!pSiS->ROM661New) {  /* VESA numbers changed! */
13583       j = 0;
13584       while(VESAModeIndices[j] != 9999) {
13585          if( (mode->HDisplay == VESAModeIndices[j]) &&
13586	      (mode->VDisplay == VESAModeIndices[j+1]) ) {
13587	     ModeNumber = VESAModeIndices[j + 2 + i];
13588	     break;
13589          }
13590          j += 6;
13591       }
13592
13593       if(!ModeNumber) {
13594	  xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
13595	      "No valid mode found for %dx%dx%d in built-in table either.\n",
13596	      mode->HDisplay, mode->VDisplay, pScrn->bitsPerPixel);
13597       }
13598    }
13599
13600    return(ModeNumber);
13601}
13602
13603UShort
13604SiS_GetModeNumber(ScrnInfoPtr pScrn, DisplayModePtr mode, unsigned int VBFlags)
13605{
13606   SISPtr pSiS = SISPTR(pScrn);
13607   UShort i = (pSiS->CurrentLayout.bitsPerPixel+7)/8 - 1;
13608   BOOLEAN FSTN = pSiS->FSTN ? TRUE : FALSE;
13609
13610#ifdef SISDUALHEAD
13611   if(pSiS->DualHeadMode && pSiS->SecondHead) FSTN = FALSE;
13612#endif
13613
13614   return(SiS_GetModeID(pSiS->VGAEngine, VBFlags, mode->HDisplay, mode->VDisplay,
13615			i, FSTN, pSiS->LCDwidth, pSiS->LCDheight));
13616}
13617
13618static Bool
13619SiSValidLCDUserMode(SISPtr pSiS, unsigned int VBFlags, DisplayModePtr mode, Bool isforlcda)
13620{
13621   if(mode->Flags & V_INTERLACE) return FALSE;
13622
13623   if(mode->HDisplay > 2048) return FALSE;
13624   if(mode->VDisplay > 1536) return FALSE;
13625
13626   if(pSiS->VBFlags2 & VB2_LCD162MHZBRIDGE) {
13627      if(mode->Clock > 162500) return FALSE;
13628#ifdef VB_FORBID_CRT2LCD_OVER_1600
13629      if(!isforlcda) {
13630         if(mode->HDisplay > 1600) return FALSE;
13631      }
13632#endif
13633   } else { /* 301, 301B, 302B (no LCDA!) */
13634      if(mode->Clock > 130000)  return FALSE;
13635      if(mode->Clock > 111000) {
13636         xf86DrvMsg(pSiS->pScrn->scrnIndex, X_WARNING,
13637	 	"WARNING: Mode clock beyond video bridge specs (%dMHz). Hardware damage might occure.\n",
13638		mode->Clock / 1000);
13639      }
13640      if(mode->HDisplay > 1600) return FALSE;
13641      if(mode->VDisplay > 1024) return FALSE;
13642   }
13643
13644   return TRUE;
13645}
13646
13647static Bool
13648SiSValidVGA2UserMode(SISPtr pSiS, unsigned int VBFlags, DisplayModePtr mode)
13649{
13650   if(mode->Flags & V_INTERLACE) return FALSE;
13651
13652   if(mode->HDisplay > 2048) return FALSE;
13653   if(mode->VDisplay > 1536) return FALSE;
13654
13655   if(pSiS->VBFlags2 & VB2_RAMDAC202MHZBRIDGE) {
13656      if(mode->Clock > 203000) return FALSE;
13657   } else if(pSiS->VBFlags2 & VB2_30xBLV) {
13658      if(mode->Clock > 162500) return FALSE;
13659   } else {
13660      if(mode->Clock > 135500) return FALSE;
13661   }
13662
13663   return TRUE;
13664}
13665
13666UShort
13667SiS_CheckModeCRT1(ScrnInfoPtr pScrn, DisplayModePtr mode, unsigned int VBFlags, Bool havecustommodes)
13668{
13669   SISPtr pSiS = SISPTR(pScrn);
13670   UShort i = (pSiS->CurrentLayout.bitsPerPixel+7)/8 - 1;
13671   int j;
13672
13673   if(!(VBFlags & CRT1_LCDA)) {
13674
13675      if((havecustommodes) && (!(mode->type & M_T_DEFAULT))) {
13676         return 0xfe;
13677      }
13678
13679   } else if(pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE) {
13680
13681      if(pSiS->ChipType < SIS_661) {  /* < 661 only? */
13682         if(!(mode->type & M_T_DEFAULT)) {
13683            if(mode->HTotal > 2055) return 0;
13684	    /* (Default mode will be caught in mode switching code) */
13685	 }
13686      }
13687
13688      if(pSiS->SiS_Pr->CP_HaveCustomData) {
13689         for(j=0; j<7; j++) {
13690            if((pSiS->SiS_Pr->CP_DataValid[j]) &&
13691               (mode->HDisplay == pSiS->SiS_Pr->CP_HDisplay[j]) &&
13692               (mode->VDisplay == pSiS->SiS_Pr->CP_VDisplay[j]) &&
13693               (mode->type & M_T_BUILTIN))
13694               return 0xfe;
13695	 }
13696      }
13697
13698      if((pSiS->AddedPlasmaModes) && (mode->type & M_T_BUILTIN))
13699         return 0xfe;
13700
13701      if((havecustommodes) &&
13702         (pSiS->LCDwidth)  &&	/* = test if LCD present */
13703         (!(mode->type & M_T_DEFAULT)) &&
13704	 (SiSValidLCDUserMode(pSiS, VBFlags, mode, TRUE)))
13705         return 0xfe;
13706
13707      if((mode->HDisplay > pSiS->LCDwidth) ||
13708         (mode->VDisplay > pSiS->LCDheight)) {
13709	 return 0;
13710      }
13711
13712   } else {
13713
13714      if((mode->HDisplay > pSiS->LCDwidth) ||
13715         (mode->VDisplay > pSiS->LCDheight)) {
13716	 return 0;
13717      }
13718
13719   }
13720
13721   return(SiS_GetModeID(pSiS->VGAEngine, VBFlags, mode->HDisplay, mode->VDisplay,
13722   			i, pSiS->FSTN, pSiS->LCDwidth, pSiS->LCDheight));
13723}
13724
13725UShort
13726SiS_CheckModeCRT2(ScrnInfoPtr pScrn, DisplayModePtr mode, unsigned int VBFlags, Bool havecustommodes)
13727{
13728   SISPtr pSiS = SISPTR(pScrn);
13729   UShort i = (pSiS->CurrentLayout.bitsPerPixel+7)/8 - 1;
13730   UShort ModeIndex = 0;
13731   int    j;
13732
13733#ifdef TWDEBUG
13734   xf86DrvMsg(0, X_INFO, "Inside CheckCalcModeIndex (VBFlags %lx, mode %dx%d)\n",
13735	VBFlags,mode->HDisplay, mode->VDisplay);
13736#endif
13737
13738   if(VBFlags & CRT2_LCD) {			/* CRT2 is LCD */
13739
13740      if((pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) && (!(pSiS->VBFlags2 & VB2_30xBDH))) {
13741
13742         if(pSiS->SiS_Pr->CP_HaveCustomData) {
13743            for(j=0; j<7; j++) {
13744               if((pSiS->SiS_Pr->CP_DataValid[j]) &&
13745                  (mode->HDisplay == pSiS->SiS_Pr->CP_HDisplay[j]) &&
13746                  (mode->VDisplay == pSiS->SiS_Pr->CP_VDisplay[j]) &&
13747#ifdef VB_FORBID_CRT2LCD_OVER_1600
13748		  (mode->HDisplay <= 1600) 			   &&
13749#endif
13750                  (mode->type & M_T_BUILTIN))
13751                  return 0xfe;
13752	    }
13753         }
13754
13755	 /* All plasma modes have HDisplay <= 1600 */
13756         if((pSiS->AddedPlasmaModes) && (mode->type & M_T_BUILTIN))
13757            return 0xfe;
13758
13759         if((havecustommodes) &&
13760            (pSiS->LCDwidth)  &&	/* = test if LCD present */
13761	    (!(mode->type & M_T_DEFAULT)) &&
13762	    (SiSValidLCDUserMode(pSiS, VBFlags, mode, FALSE)))
13763            return 0xfe;
13764
13765      }
13766
13767      if( ((mode->HDisplay <= pSiS->LCDwidth) &&
13768           (mode->VDisplay <= pSiS->LCDheight)) ||
13769	  ((pSiS->SiS_Pr->SiS_CustomT == CUT_PANEL848) &&
13770	   (((mode->HDisplay == 1360) && (mode->VDisplay == 768)) ||
13771	    ((mode->HDisplay == 1024) && (mode->VDisplay == 768)) ||
13772	    ((mode->HDisplay ==  800) && (mode->VDisplay == 600)))) ||
13773	  ((pSiS->SiS_Pr->SiS_CustomT == CUT_PANEL856) &&
13774	   (((mode->HDisplay == 1024) && (mode->VDisplay == 768)) ||
13775	    ((mode->HDisplay ==  800) && (mode->VDisplay == 600)))) ) {
13776
13777	 ModeIndex = SiS_GetModeID_LCD(pSiS->VGAEngine, VBFlags, mode->HDisplay, mode->VDisplay, i,
13778				pSiS->FSTN, pSiS->SiS_Pr->SiS_CustomT, pSiS->LCDwidth, pSiS->LCDheight,
13779				pSiS->VBFlags2);
13780
13781      }
13782
13783   } else if(VBFlags & CRT2_TV) {		/* CRT2 is TV */
13784
13785      ModeIndex = SiS_GetModeID_TV(pSiS->VGAEngine, VBFlags, mode->HDisplay, mode->VDisplay, i,
13786					pSiS->VBFlags2);
13787
13788   } else if(VBFlags & CRT2_VGA) {		/* CRT2 is VGA2 */
13789
13790      if((pSiS->AddedPlasmaModes) && (mode->type & M_T_BUILTIN))
13791	 return 0xfe;
13792
13793      if((havecustommodes) &&
13794	 (!(mode->type & M_T_DEFAULT)) &&
13795	 (SiSValidVGA2UserMode(pSiS, VBFlags, mode)))
13796         return 0xfe;
13797
13798      ModeIndex = SiS_GetModeID_VGA2(pSiS->VGAEngine, VBFlags, mode->HDisplay, mode->VDisplay, i,
13799					pSiS->VBFlags2);
13800
13801   } else {					/* no CRT2 */
13802
13803      /* Return a valid mode number */
13804      ModeIndex = 0xfe;
13805
13806   }
13807
13808   return(ModeIndex);
13809}
13810
13811/* Calculate the vertical refresh rate from a mode */
13812float
13813SiSCalcVRate(DisplayModePtr mode)
13814{
13815   float hsync, refresh = 0;
13816
13817   if(mode->HSync > 0.0)
13818       	hsync = mode->HSync;
13819   else if(mode->HTotal > 0)
13820       	hsync = (float)mode->Clock / (float)mode->HTotal;
13821   else
13822       	hsync = 0.0;
13823
13824   if(mode->VTotal > 0)
13825       	refresh = hsync * 1000.0 / mode->VTotal;
13826
13827   if(mode->Flags & V_INTERLACE)
13828       	refresh *= 2.0;
13829
13830   if(mode->Flags & V_DBLSCAN)
13831       	refresh /= 2.0;
13832
13833   if(mode->VScan > 1)
13834        refresh /= mode->VScan;
13835
13836   if(mode->VRefresh > 0.0)
13837	refresh = mode->VRefresh;
13838
13839   if(hsync == 0.0 || refresh == 0.0) return 0.0;
13840
13841   return refresh;
13842}
13843
13844/* Calculate CR33 (rate index) for CRT1.
13845 * Calculation is done using currentmode, therefore it is
13846 * recommended to set VertRefresh and HorizSync to correct
13847 * values in config file.
13848 */
13849UChar
13850SISSearchCRT1Rate(ScrnInfoPtr pScrn, DisplayModePtr mode)
13851{
13852   SISPtr  pSiS = SISPTR(pScrn);
13853   int     i = 0, irefresh;
13854   UShort  xres = mode->HDisplay;
13855   UShort  yres = mode->VDisplay;
13856   UChar   index, defindex;
13857   Bool    checksis730 = FALSE;
13858
13859   defindex = (xres == 800 || xres == 1024 || xres == 1280) ? 0x02 : 0x01;
13860
13861   irefresh = (int)SiSCalcVRate(mode);
13862   if(!irefresh) return defindex;
13863
13864   /* SiS730 has troubles on CRT2 if CRT1 is at 32bpp */
13865   if( (pSiS->ChipType == SIS_730)        &&
13866       (pSiS->VBFlags2 & VB2_VIDEOBRIDGE) &&
13867       (pSiS->CurrentLayout.bitsPerPixel == 32) ) {
13868#ifdef SISDUALHEAD
13869      if(pSiS->DualHeadMode) {
13870         if(pSiS->SecondHead) {
13871	    checksis730 = TRUE;
13872	 }
13873      } else
13874#endif
13875      if((!pSiS->UseVESA) && (pSiS->VBFlags & CRT2_ENABLE) && (!pSiS->CRT1off)) {
13876         checksis730 = TRUE;
13877      }
13878   }
13879
13880#ifdef TWDEBUG
13881   xf86DrvMsg(0, X_INFO, "Debug: CalcVRate returned %d\n", irefresh);
13882#endif
13883
13884   /* We need the REAL refresh rate here */
13885   if(mode->Flags & V_INTERLACE) irefresh /= 2;
13886
13887   /* Do not multiply by 2 when DBLSCAN! */
13888
13889#ifdef TWDEBUG
13890   xf86DrvMsg(0, X_INFO, "Debug: Rate after correction = %d\n", irefresh);
13891#endif
13892
13893   index = 0;
13894   while((sisx_vrate[i].idx != 0) && (sisx_vrate[i].xres <= xres)) {
13895      if((sisx_vrate[i].xres == xres) && (sisx_vrate[i].yres == yres)) {
13896	 if((checksis730 == FALSE) || (sisx_vrate[i].SiS730valid32bpp == TRUE)) {
13897	    if(sisx_vrate[i].refresh == irefresh) {
13898	       index = sisx_vrate[i].idx;
13899	       break;
13900	    } else if(sisx_vrate[i].refresh > irefresh) {
13901	       if((sisx_vrate[i].refresh - irefresh) <= 3) {
13902		  index = sisx_vrate[i].idx;
13903	       } else if( ((checksis730 == FALSE) || (sisx_vrate[i - 1].SiS730valid32bpp == TRUE)) &&
13904		          ((irefresh - sisx_vrate[i - 1].refresh) <=  2) &&
13905			  (sisx_vrate[i].idx != 1) ) {
13906		  index = sisx_vrate[i - 1].idx;
13907	       }
13908	       break;
13909	    } else if((irefresh - sisx_vrate[i].refresh) <= 2) {
13910	       index = sisx_vrate[i].idx;
13911	       break;
13912	    }
13913	 }
13914      }
13915      i++;
13916   }
13917
13918   if(index > 0) return index;
13919   else          return defindex;
13920}
13921
13922void
13923SISWaitRetraceCRT1(ScrnInfoPtr pScrn)
13924{
13925   SISPtr pSiS = SISPTR(pScrn);
13926   int    watchdog;
13927   UChar  temp;
13928
13929   inSISIDXREG(SISCR,0x17,temp);
13930   if(!(temp & 0x80)) return;
13931
13932   inSISIDXREG(SISSR,0x1f,temp);
13933   if(temp & 0xc0) return;
13934
13935   watchdog = 65536;
13936   while((inSISREG(SISINPSTAT) & 0x08) && --watchdog);
13937   watchdog = 65536;
13938   while((!(inSISREG(SISINPSTAT) & 0x08)) && --watchdog);
13939}
13940
13941void
13942SISWaitRetraceCRT2(ScrnInfoPtr pScrn)
13943{
13944   SISPtr pSiS = SISPTR(pScrn);
13945   int    watchdog;
13946   UChar  temp, reg;
13947
13948   if(SiSBridgeIsInSlaveMode(pScrn)) {
13949      SISWaitRetraceCRT1(pScrn);
13950      return;
13951   }
13952
13953   switch(pSiS->VGAEngine) {
13954   case SIS_300_VGA:
13955   	reg = 0x25;
13956	break;
13957   case SIS_315_VGA:
13958   	reg = 0x30;
13959	break;
13960   default:
13961        return;
13962   }
13963
13964   watchdog = 65536;
13965   do {
13966   	inSISIDXREG(SISPART1, reg, temp);
13967	if(!(temp & 0x02)) break;
13968   } while(--watchdog);
13969   watchdog = 65536;
13970   do {
13971   	inSISIDXREG(SISPART1, reg, temp);
13972	if(temp & 0x02) break;
13973   } while(--watchdog);
13974}
13975
13976static void
13977SISWaitVBRetrace(ScrnInfoPtr pScrn)
13978{
13979   SISPtr  pSiS = SISPTR(pScrn);
13980
13981   if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
13982#ifdef SISDUALHEAD
13983      if(pSiS->DualHeadMode) {
13984   	 if(pSiS->SecondHead)
13985	    SISWaitRetraceCRT1(pScrn);
13986         else
13987	    SISWaitRetraceCRT2(pScrn);
13988      } else {
13989#endif
13990	 if(pSiS->VBFlags & DISPTYPE_DISP1) {
13991	    SISWaitRetraceCRT1(pScrn);
13992	 }
13993	 if(pSiS->VBFlags & DISPTYPE_DISP2) {
13994	    if(!(SiSBridgeIsInSlaveMode(pScrn))) {
13995	       SISWaitRetraceCRT2(pScrn);
13996	    }
13997	 }
13998#ifdef SISDUALHEAD
13999      }
14000#endif
14001   } else {
14002      SISWaitRetraceCRT1(pScrn);
14003   }
14004}
14005
14006#define MODEID_OFF 0x449
14007
14008UChar
14009SiS_GetSetBIOSScratch(ScrnInfoPtr pScrn, UShort offset, UChar value)
14010{
14011    UChar ret = 0;
14012#ifdef SIS_USE_BIOS_SCRATCH
14013    UChar *base;
14014#endif
14015
14016    /* For some reasons (like detecting the current display mode),
14017     * we need to read (or write-back) values from the BIOS
14018     * scratch area. This area is only valid for the primary
14019     * graphics card. For the secondary, we just return some
14020     * defaults and ignore requests to write data. As regards
14021     * the display mode: If sisfb is loaded for the secondary
14022     * card, it very probably has set a mode, but in any case
14023     * informed us via its info packet. So this here will not be
14024     * called for mode detection in this case.
14025     */
14026
14027    switch(offset) {
14028    case 0x489:
14029       ret = 0x11;  /* Default VGA Info */
14030       break;
14031    case MODEID_OFF:
14032       ret = 0x03;  /* Default current display mode */
14033       break;
14034    }
14035
14036#ifndef XSERVER_LIBPCIACCESS
14037#ifdef SIS_USE_BIOS_SCRATCH
14038    if(SISPTR(pScrn)->Primary) {
14039       base = xf86MapVidMem(pScrn->scrnIndex, VIDMEM_MMIO, 0, 0x2000);
14040       if(!base) {
14041          SISErrorLog(pScrn, "(Could not map BIOS scratch area)\n");
14042          return ret;
14043       }
14044
14045       ret = *(base + offset);
14046
14047       /* value != 0xff means: set register */
14048       if(value != 0xff) {
14049          *(base + offset) = value;
14050       }
14051
14052       xf86UnMapVidMem(pScrn->scrnIndex, base, 0x2000);
14053    }
14054#endif
14055#endif
14056    return ret;
14057}
14058
14059UChar
14060SiS_GetSetModeID(ScrnInfoPtr pScrn, UChar id)
14061{
14062    return(SiS_GetSetBIOSScratch(pScrn, MODEID_OFF, id));
14063}
14064
14065void
14066SiSMemCopyToVideoRam(SISPtr pSiS, UChar *to, UChar *from, int size)
14067{
14068   if((ULong)to & 15) (*pSiS->SiSFastMemCopy)(to, from, size);
14069   else       	      (*pSiS->SiSFastVidCopy)(to, from, size);
14070}
14071
14072void
14073SiSMemCopyFromVideoRam(SISPtr pSiS, UChar *to, UChar *from, int size)
14074{
14075   if((ULong)to & 15) (*pSiS->SiSFastMemCopyFrom)(to, from, size);
14076   else       	      (*pSiS->SiSFastVidCopyFrom)(to, from, size);
14077}
14078
14079void
14080sisSaveUnlockExtRegisterLock(SISPtr pSiS, UChar *reg1, UChar *reg2)
14081{
14082    register UChar val;
14083    ULong mylockcalls;
14084#ifdef TWDEBUG
14085    UChar val1, val2;
14086    int i;
14087#endif
14088
14089    pSiS->lockcalls++;
14090    mylockcalls = pSiS->lockcalls;
14091
14092    /* check if already unlocked */
14093    inSISIDXREG(SISSR, 0x05, val);
14094
14095    if(val != 0xa1) {
14096
14097       /* save State */
14098       if(reg1) *reg1 = val;
14099
14100       /* unlock */
14101       outSISIDXREG(SISSR, 0x05, 0x86);
14102
14103       /* Now check again */
14104       inSISIDXREG(SISSR, 0x05, val);
14105
14106       if(val != 0xA1) {
14107
14108          xf86DrvMsg(pSiS->pScrn->scrnIndex, X_WARNING,
14109               "Failed to unlock SR registers at relocated i/o ports\n");
14110
14111#ifdef TWDEBUG
14112          for(i = 0; i <= 0x3f; i++) {
14113		inSISIDXREG(SISSR, i, val1);
14114		inSISIDXREG(0x3c4, i, val2);
14115		xf86DrvMsg(pSiS->pScrn->scrnIndex, X_INFO,
14116			"SR%02d: RelIO=0x%02x 0x3c4=0x%02x (%ld)\n",
14117			i, val1, val2, mylockcalls);
14118	  }
14119#endif
14120
14121	  /* Emergency measure: unlock at 0x3c4, and try to enable relocated IO ports */
14122	  switch(pSiS->VGAEngine) {
14123          case SIS_OLD_VGA:
14124	  case SIS_530_VGA:
14125	     outSISIDXREG(0x3c4, 0x05, 0x86);
14126	     andSISIDXREG(0x3c4, 0x33, ~0x20);
14127	     break;
14128	  case SIS_300_VGA:
14129	  case SIS_315_VGA:
14130	     outSISIDXREG(0x3c4, 0x05, 0x86);
14131	     orSISIDXREG(0x3c4, 0x20, 0x20);
14132	     break;
14133          }
14134	  outSISIDXREG(SISSR, 0x05, 0x86);
14135	  inSISIDXREG(SISSR, 0x05, val);
14136	  if(val != 0xa1) {
14137	     SISErrorLog(pSiS->pScrn,
14138			"Failed to unlock SR registers (%p, %lx, 0x%02x; %ld)\n",
14139			(void *)pSiS, (ULong)pSiS->RelIO, val, mylockcalls);
14140	     /* Now await doom... */
14141	  }
14142       }
14143    }
14144    if((pSiS->VGAEngine == SIS_OLD_VGA) || (pSiS->VGAEngine == SIS_530_VGA)) {
14145       inSISIDXREG(SISCR, 0x80, val);
14146       if(val != 0xa1) {
14147          /* save State */
14148          if(reg2) *reg2 = val;
14149          outSISIDXREG(SISCR, 0x80, 0x86);
14150	  inSISIDXREG(SISCR, 0x80, val);
14151	  if(val != 0xA1) {
14152	     SISErrorLog(pSiS->pScrn,
14153	        "Failed to unlock cr registers (%p, %lx, 0x%02x)\n",
14154	       (void *)pSiS, (ULong)pSiS->RelIO, val);
14155	  }
14156       }
14157    }
14158}
14159
14160void
14161sisRestoreExtRegisterLock(SISPtr pSiS, UChar reg1, UChar reg2)
14162{
14163    /* restore lock */
14164#ifndef UNLOCK_ALWAYS
14165    outSISIDXREG(SISSR, 0x05, reg1 == 0xA1 ? 0x86 : 0x00);
14166    if((pSiS->VGAEngine == SIS_OLD_VGA) || (pSiS->VGAEngine == SIS_530_VGA)) {
14167       outSISIDXREG(SISCR, 0x80, reg2 == 0xA1 ? 0x86 : 0x00);
14168    }
14169#endif
14170}
14171
14172