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(const 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#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 12
2152    register int		  n;
2153#endif
2154
2155    REQUEST_SIZE_MATCH(xPanoramiXQueryVersionReq);
2156    rep.type = X_Reply;
2157    rep.length = 0;
2158    rep.sequenceNumber = client->sequence;
2159    rep.majorVersion = SIS_XINERAMA_MAJOR_VERSION;
2160    rep.minorVersion = SIS_XINERAMA_MINOR_VERSION;
2161    if(client->swapped) {
2162        _swaps(&rep.sequenceNumber, n);
2163        _swapl(&rep.length, n);
2164        _swaps(&rep.majorVersion, n);
2165        _swaps(&rep.minorVersion, n);
2166    }
2167    WriteToClient(client, sizeof(xPanoramiXQueryVersionReply), (char *)&rep);
2168    return (client->noClientException);
2169}
2170
2171int
2172SiSProcXineramaGetState(ClientPtr client)
2173{
2174    REQUEST(xPanoramiXGetStateReq);
2175    WindowPtr			pWin;
2176    xPanoramiXGetStateReply	rep;
2177#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 12
2178    register int		n;
2179#endif
2180    int				rc;
2181
2182    REQUEST_SIZE_MATCH(xPanoramiXGetStateReq);
2183    rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
2184    if (rc != Success)
2185        return rc;
2186
2187    rep.type = X_Reply;
2188    rep.length = 0;
2189    rep.sequenceNumber = client->sequence;
2190    rep.state = !SiSnoPanoramiXExtension;
2191    if(client->swapped) {
2192       _swaps (&rep.sequenceNumber, n);
2193       _swapl (&rep.length, n);
2194    }
2195    WriteToClient(client, sizeof(xPanoramiXGetStateReply), (char *)&rep);
2196    return client->noClientException;
2197}
2198
2199int
2200SiSProcXineramaGetScreenCount(ClientPtr client)
2201{
2202    REQUEST(xPanoramiXGetScreenCountReq);
2203    WindowPtr				pWin;
2204    xPanoramiXGetScreenCountReply	rep;
2205#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 12
2206    register int			n;
2207#endif
2208    int					rc;
2209
2210    REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq);
2211    rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
2212    if (rc != Success)
2213        return rc;
2214
2215    rep.type = X_Reply;
2216    rep.length = 0;
2217    rep.sequenceNumber = client->sequence;
2218    rep.ScreenCount = SiSXineramaNumScreens;
2219    if(client->swapped) {
2220       _swaps(&rep.sequenceNumber, n);
2221       _swapl(&rep.length, n);
2222    }
2223    WriteToClient(client, sizeof(xPanoramiXGetScreenCountReply), (char *)&rep);
2224    return client->noClientException;
2225}
2226
2227int
2228SiSProcXineramaGetScreenSize(ClientPtr client)
2229{
2230    REQUEST(xPanoramiXGetScreenSizeReq);
2231    WindowPtr				pWin;
2232    xPanoramiXGetScreenSizeReply	rep;
2233#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 12
2234    register int			n;
2235#endif
2236    int					rc;
2237
2238    REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq);
2239    rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
2240    if (rc != Success)
2241        return rc;
2242
2243    rep.type = X_Reply;
2244    rep.length = 0;
2245    rep.sequenceNumber = client->sequence;
2246    rep.width  = SiSXineramadataPtr[stuff->screen].width;
2247    rep.height = SiSXineramadataPtr[stuff->screen].height;
2248    if(client->swapped) {
2249       _swaps(&rep.sequenceNumber, n);
2250       _swapl(&rep.length, n);
2251       _swapl(&rep.width, n);
2252       _swapl(&rep.height, n);
2253    }
2254    WriteToClient(client, sizeof(xPanoramiXGetScreenSizeReply), (char *)&rep);
2255    return client->noClientException;
2256}
2257
2258int
2259SiSProcXineramaIsActive(ClientPtr client)
2260{
2261    xXineramaIsActiveReply	rep;
2262
2263    REQUEST_SIZE_MATCH(xXineramaIsActiveReq);
2264
2265    rep.type = X_Reply;
2266    rep.length = 0;
2267    rep.sequenceNumber = client->sequence;
2268    rep.state = !SiSnoPanoramiXExtension;
2269    if(client->swapped) {
2270#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 12
2271	register int n;
2272#endif
2273	_swaps(&rep.sequenceNumber, n);
2274	_swapl(&rep.length, n);
2275	_swapl(&rep.state, n);
2276    }
2277    WriteToClient(client, sizeof(xXineramaIsActiveReply), (char *) &rep);
2278    return client->noClientException;
2279}
2280
2281int
2282SiSProcXineramaQueryScreens(ClientPtr client)
2283{
2284    xXineramaQueryScreensReply	rep;
2285
2286    REQUEST_SIZE_MATCH(xXineramaQueryScreensReq);
2287
2288    rep.type = X_Reply;
2289    rep.sequenceNumber = client->sequence;
2290    rep.number = (SiSnoPanoramiXExtension) ? 0 : SiSXineramaNumScreens;
2291    rep.length = rep.number * sz_XineramaScreenInfo >> 2;
2292    if(client->swapped) {
2293#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 12
2294       register int n;
2295#endif
2296       _swaps(&rep.sequenceNumber, n);
2297       _swapl(&rep.length, n);
2298       _swapl(&rep.number, n);
2299    }
2300    WriteToClient(client, sizeof(xXineramaQueryScreensReply), (char *)&rep);
2301
2302    if(!SiSnoPanoramiXExtension) {
2303       xXineramaScreenInfo scratch;
2304       int i;
2305
2306       for(i = 0; i < SiSXineramaNumScreens; i++) {
2307	  scratch.x_org  = SiSXineramadataPtr[i].x;
2308	  scratch.y_org  = SiSXineramadataPtr[i].y;
2309	  scratch.width  = SiSXineramadataPtr[i].width;
2310	  scratch.height = SiSXineramadataPtr[i].height;
2311	  if(client->swapped) {
2312#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 12
2313	     register int n;
2314#endif
2315	     _swaps(&scratch.x_org, n);
2316	     _swaps(&scratch.y_org, n);
2317	     _swaps(&scratch.width, n);
2318	     _swaps(&scratch.height, n);
2319	  }
2320	  WriteToClient(client, sz_XineramaScreenInfo, (char *)&scratch);
2321       }
2322    }
2323
2324    return client->noClientException;
2325}
2326
2327static int
2328SiSProcXineramaDispatch(ClientPtr client)
2329{
2330    REQUEST(xReq);
2331    switch (stuff->data) {
2332	case X_PanoramiXQueryVersion:
2333	     return SiSProcXineramaQueryVersion(client);
2334	case X_PanoramiXGetState:
2335	     return SiSProcXineramaGetState(client);
2336	case X_PanoramiXGetScreenCount:
2337	     return SiSProcXineramaGetScreenCount(client);
2338	case X_PanoramiXGetScreenSize:
2339	     return SiSProcXineramaGetScreenSize(client);
2340	case X_XineramaIsActive:
2341	     return SiSProcXineramaIsActive(client);
2342	case X_XineramaQueryScreens:
2343	     return SiSProcXineramaQueryScreens(client);
2344    }
2345    return BadRequest;
2346}
2347
2348/* SProc */
2349
2350static int
2351SiSSProcXineramaQueryVersion (ClientPtr client)
2352{
2353    REQUEST(xPanoramiXQueryVersionReq);
2354#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 12
2355    register int n;
2356#endif
2357    _swaps(&stuff->length,n);
2358    REQUEST_SIZE_MATCH (xPanoramiXQueryVersionReq);
2359    return SiSProcXineramaQueryVersion(client);
2360}
2361
2362static int
2363SiSSProcXineramaGetState(ClientPtr client)
2364{
2365    REQUEST(xPanoramiXGetStateReq);
2366#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 12
2367    register int n;
2368#endif
2369    _swaps (&stuff->length, n);
2370    REQUEST_SIZE_MATCH(xPanoramiXGetStateReq);
2371    return SiSProcXineramaGetState(client);
2372}
2373
2374static int
2375SiSSProcXineramaGetScreenCount(ClientPtr client)
2376{
2377    REQUEST(xPanoramiXGetScreenCountReq);
2378#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 12
2379    register int n;
2380#endif
2381    _swaps (&stuff->length, n);
2382    REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq);
2383    return SiSProcXineramaGetScreenCount(client);
2384}
2385
2386static int
2387SiSSProcXineramaGetScreenSize(ClientPtr client)
2388{
2389    REQUEST(xPanoramiXGetScreenSizeReq);
2390#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 12
2391    register int n;
2392#endif
2393    _swaps (&stuff->length, n);
2394    REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq);
2395    return SiSProcXineramaGetScreenSize(client);
2396}
2397
2398static int
2399SiSSProcXineramaIsActive(ClientPtr client)
2400{
2401    REQUEST(xXineramaIsActiveReq);
2402#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 12
2403    register int n;
2404#endif
2405    _swaps (&stuff->length, n);
2406    REQUEST_SIZE_MATCH(xXineramaIsActiveReq);
2407    return SiSProcXineramaIsActive(client);
2408}
2409
2410static int
2411SiSSProcXineramaQueryScreens(ClientPtr client)
2412{
2413    REQUEST(xXineramaQueryScreensReq);
2414#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 12
2415    register int n;
2416#endif
2417    _swaps (&stuff->length, n);
2418    REQUEST_SIZE_MATCH(xXineramaQueryScreensReq);
2419    return SiSProcXineramaQueryScreens(client);
2420}
2421
2422int
2423SiSSProcXineramaDispatch(ClientPtr client)
2424{
2425    REQUEST(xReq);
2426    switch (stuff->data) {
2427	case X_PanoramiXQueryVersion:
2428	     return SiSSProcXineramaQueryVersion(client);
2429	case X_PanoramiXGetState:
2430	     return SiSSProcXineramaGetState(client);
2431	case X_PanoramiXGetScreenCount:
2432	     return SiSSProcXineramaGetScreenCount(client);
2433	case X_PanoramiXGetScreenSize:
2434	     return SiSSProcXineramaGetScreenSize(client);
2435	case X_XineramaIsActive:
2436	     return SiSSProcXineramaIsActive(client);
2437	case X_XineramaQueryScreens:
2438	     return SiSSProcXineramaQueryScreens(client);
2439    }
2440    return BadRequest;
2441}
2442
2443static void
2444SiSXineramaResetProc(ExtensionEntry* extEntry)
2445{
2446    /* Called by CloseDownExtensions() */
2447    if(SiSXineramadataPtr) {
2448       free(SiSXineramadataPtr);
2449       SiSXineramadataPtr = NULL;
2450    }
2451}
2452
2453static void
2454SiSXineramaExtensionInit(ScrnInfoPtr pScrn)
2455{
2456    SISPtr	pSiS = SISPTR(pScrn);
2457    Bool	success = FALSE;
2458
2459    if(!(SiSXineramadataPtr)) {
2460
2461       if(!pSiS->MergedFB) {
2462	  SiSnoPanoramiXExtension = TRUE;
2463	  pSiS->MouseRestrictions = FALSE;
2464	  return;
2465       }
2466
2467#ifdef PANORAMIX
2468       if(!noPanoramiXExtension) {
2469	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2470	     "Xinerama active, not initializing SiS Pseudo-Xinerama\n");
2471	  SiSnoPanoramiXExtension = TRUE;
2472	  pSiS->MouseRestrictions = FALSE;
2473	  return;
2474       }
2475#endif
2476
2477       if(SiSnoPanoramiXExtension) {
2478	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2479	      "SiS Pseudo-Xinerama disabled\n");
2480	  pSiS->MouseRestrictions = FALSE;
2481	  return;
2482       }
2483
2484       if(pSiS->CRT2Position == sisClone) {
2485	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2486	     "Running MergedFB in Clone mode, SiS Pseudo-Xinerama disabled\n");
2487	  SiSnoPanoramiXExtension = TRUE;
2488	  pSiS->MouseRestrictions = FALSE;
2489	  return;
2490       }
2491
2492       if(!(pSiS->AtLeastOneNonClone)) {
2493	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2494	     "Only Clone modes defined, SiS Pseudo-Xinerama disabled\n");
2495	  SiSnoPanoramiXExtension = TRUE;
2496	  pSiS->MouseRestrictions = FALSE;
2497	  return;
2498       }
2499
2500       SiSXineramaNumScreens = 2;
2501
2502       while(SiSXineramaGeneration != serverGeneration) {
2503
2504	  pSiS->XineramaExtEntry = AddExtension(PANORAMIX_PROTOCOL_NAME, 0,0,
2505					SiSProcXineramaDispatch,
2506					SiSSProcXineramaDispatch,
2507					SiSXineramaResetProc,
2508					StandardMinorOpcode);
2509
2510	  if(!pSiS->XineramaExtEntry) break;
2511
2512	  if(!(SiSXineramadataPtr = (SiSXineramaData *)
2513	        calloc(SiSXineramaNumScreens, sizeof(SiSXineramaData)))) break;
2514
2515	  SiSXineramaGeneration = serverGeneration;
2516	  success = TRUE;
2517       }
2518
2519       if(!success) {
2520	  SISErrorLog(pScrn, "Failed to initialize SiS Pseudo-Xinerama extension\n");
2521	  SiSnoPanoramiXExtension = TRUE;
2522	  pSiS->MouseRestrictions = FALSE;
2523	  return;
2524       }
2525
2526       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2527	  "SiS Pseudo-Xinerama extension initialized\n");
2528
2529       pSiS->SiSXineramaVX = 0;
2530       pSiS->SiSXineramaVY = 0;
2531
2532    }
2533
2534    SiSUpdateXineramaScreenInfo(pScrn);
2535
2536}
2537#endif  /* End of PseudoXinerama */
2538
2539static void
2540SiSFreeCRT2Structs(SISPtr pSiS)
2541{
2542    if(pSiS->CRT2pScrn) {
2543       if(pSiS->CRT2pScrn->modes) {
2544	  while(pSiS->CRT2pScrn->modes)
2545	     xf86DeleteMode(&pSiS->CRT2pScrn->modes, pSiS->CRT2pScrn->modes);
2546       }
2547       if(pSiS->CRT2pScrn->monitor) {
2548	  if(pSiS->CRT2pScrn->monitor->Modes) {
2549	     while(pSiS->CRT2pScrn->monitor->Modes)
2550		xf86DeleteMode(&pSiS->CRT2pScrn->monitor->Modes, pSiS->CRT2pScrn->monitor->Modes);
2551	  }
2552	  if(pSiS->CRT2pScrn->monitor->DDC) free(pSiS->CRT2pScrn->monitor->DDC);
2553	  free(pSiS->CRT2pScrn->monitor);
2554       }
2555       free(pSiS->CRT2pScrn);
2556       pSiS->CRT2pScrn = NULL;
2557   }
2558}
2559
2560#endif	/* End of MergedFB helpers */
2561
2562static xf86MonPtr
2563SiSInternalDDC(ScrnInfoPtr pScrn, int crtno)
2564{
2565   SISPtr     pSiS = SISPTR(pScrn);
2566   xf86MonPtr pMonitor = NULL;
2567   UShort     temp = 0xffff, temp1, i, realcrtno = crtno;
2568   UChar      buffer[256];
2569
2570   /* If CRT1 is off, skip DDC */
2571   if((pSiS->CRT1off) && (!crtno)) return NULL;
2572
2573   if(crtno) {
2574      if(pSiS->VBFlags & CRT2_LCD)      realcrtno = 1;
2575      else if(pSiS->VBFlags & CRT2_VGA) realcrtno = 2;
2576      else				return NULL;
2577      if(pSiS->SiS_Pr->DDCPortMixup) realcrtno = 0;
2578   } else {
2579      /* If CRT1 is LCDA, skip DDC (except 301C: DDC allowed, but uses CRT2 port!) */
2580      if(pSiS->VBFlags & CRT1_LCDA) {
2581         if(pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE) realcrtno = 1;
2582         else return NULL;
2583      }
2584   }
2585
2586   i = 3; /* Number of retrys */
2587   do {
2588      temp1 = SiS_HandleDDC(pSiS->SiS_Pr, pSiS->VBFlags, pSiS->VGAEngine,
2589			realcrtno, 0, &buffer[0], pSiS->VBFlags2);
2590      if((temp1) && (temp1 != 0xffff)) temp = temp1;
2591   } while((temp == 0xffff) && i--);
2592   if(temp != 0xffff) {
2593      xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "CRT%d DDC supported\n", crtno + 1);
2594      xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "CRT%d DDC level: %s%s%s%s\n",
2595	     crtno + 1,
2596	     (temp & 0x1a) ? "" : "[none of the supported]",
2597	     (temp & 0x02) ? "2 " : "",
2598	     (temp & 0x08) ? "D&P" : "",
2599             (temp & 0x10) ? "FPDI-2" : "");
2600      if(temp & 0x02) {
2601	 i = 5;  /* Number of retrys */
2602	 do {
2603	    temp = SiS_HandleDDC(pSiS->SiS_Pr, pSiS->VBFlags, pSiS->VGAEngine,
2604				realcrtno, 1, &buffer[0], pSiS->VBFlags2);
2605	 } while((temp) && i--);
2606         if(!temp) {
2607	    if((pMonitor = xf86InterpretEDID(pScrn->scrnIndex, &buffer[0]))) {
2608	       int tempvgagamma = 0, templcdgamma = 0;
2609	       if(buffer[0x14] & 0x80) {
2610	          templcdgamma = (buffer[0x17] + 100) * 10;
2611	       } else {
2612	          tempvgagamma = (buffer[0x17] + 100) * 10;;
2613	       }
2614	       if(crtno == 0) {
2615		  if(tempvgagamma) pSiS->CRT1VGAMonitorGamma = tempvgagamma;
2616		  /* LCD never via (demanded) CRT1 DDC port */
2617	       } else {
2618	          if(tempvgagamma) pSiS->CRT2VGAMonitorGamma = tempvgagamma;
2619	          if(templcdgamma) pSiS->CRT2LCDMonitorGamma = templcdgamma;
2620	       }
2621	       return(pMonitor);
2622	    } else {
2623	       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2624	           "CRT%d DDC EDID corrupt\n", crtno + 1);
2625	    }
2626	 } else if(temp == 0xFFFE) {
2627	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2628	    	"CRT%d DDC data is from wrong device type (%s)\n",
2629			crtno + 1,
2630			(realcrtno == 1) ? "analog instead of digital" : "digital instead of analog");
2631	 } else {
2632            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
2633	    	"CRT%d DDC reading failed\n", crtno + 1);
2634	 }
2635      } else if(temp & 0x18) {
2636         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2637	      "DDC for VESA D&P and FPDI-2 not supported yet.\n");
2638      }
2639   } else {
2640      xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
2641                "CRT%d DDC probing failed\n", crtno + 1);
2642   }
2643   return(NULL);
2644}
2645
2646static xf86MonPtr
2647SiSDoPrivateDDC(ScrnInfoPtr pScrn, int *crtnum)
2648{
2649    SISPtr pSiS = SISPTR(pScrn);
2650
2651#ifdef SISDUALHEAD
2652    if(pSiS->DualHeadMode) {
2653       if(pSiS->SecondHead) {
2654          *crtnum = 1;
2655	  return(SiSInternalDDC(pScrn, 0));
2656       } else {
2657          *crtnum = 2;
2658	  return(SiSInternalDDC(pScrn, 1));
2659       }
2660    } else
2661#endif
2662    if((pSiS->CRT1off) || (!pSiS->CRT1Detected)) {
2663       *crtnum = 2;
2664       return(SiSInternalDDC(pScrn, 1));
2665    } else {
2666       *crtnum = 1;
2667       return(SiSInternalDDC(pScrn, 0));
2668    }
2669}
2670
2671static void
2672SiSFindAspect(ScrnInfoPtr pScrn, xf86MonPtr pMonitor, int crtnum)
2673{
2674    SISPtr pSiS = SISPTR(pScrn);
2675    int UseWide = 0;
2676    int aspect = 0;
2677    Bool fromdim = FALSE;
2678
2679    if((pSiS->VGAEngine == SIS_315_VGA) && (!DIGITAL(pMonitor->features.input_type))) {
2680       if(pMonitor->features.hsize && pMonitor->features.vsize) {
2681	  aspect = (pMonitor->features.hsize * 1000) / pMonitor->features.vsize;
2682	  if(aspect >= 1400) UseWide = 1;
2683	  fromdim = TRUE;
2684       } else if((PREFERRED_TIMING_MODE(pMonitor->features.msc)) &&
2685		 (pMonitor->det_mon[0].type == DT)) {
2686	  aspect = (pMonitor->det_mon[0].section.d_timings.h_active * 1000) /
2687			pMonitor->det_mon[0].section.d_timings.v_active;
2688	  if(aspect >= 1400) UseWide = 1;
2689       }
2690       if(aspect) {
2691	  xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
2692		"According to %s, CRT%d aspect ratio is %.2f:1 (%s)\n",
2693		fromdim ? "DDC size" : "preferred mode",
2694		crtnum, (float)aspect / 1000.0, UseWide ? "wide" : "normal");
2695       } else {
2696	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2697		"Unable to determine CRT%d aspect ratio, assuming \"normal\"\n",
2698		crtnum);
2699       }
2700    }
2701
2702    if((crtnum == 1) && (pSiS->SiS_Pr->SiS_UseWide == -1)) {
2703       pSiS->SiS_Pr->SiS_UseWide = UseWide;
2704    } else if((crtnum == 2) && (pSiS->SiS_Pr->SiS_UseWideCRT2 == -1)) {
2705       pSiS->SiS_Pr->SiS_UseWideCRT2 = UseWide;
2706    }
2707}
2708
2709static Bool
2710SiSMakeOwnModeList(ScrnInfoPtr pScrn, Bool acceptcustommodes, Bool includelcdmodes,
2711                   Bool isfordvi, Bool *havecustommodes, Bool fakecrt2modes, Bool IsForCRT2)
2712{
2713    DisplayModePtr tempmode, delmode, mymodes;
2714
2715    if((mymodes = SiSBuildBuiltInModeList(pScrn, includelcdmodes, isfordvi, fakecrt2modes, IsForCRT2))) {
2716       if(!acceptcustommodes) {
2717	  while(pScrn->monitor->Modes)
2718             xf86DeleteMode(&pScrn->monitor->Modes, pScrn->monitor->Modes);
2719	  pScrn->monitor->Modes = mymodes;
2720       } else {
2721	  delmode = pScrn->monitor->Modes;
2722	  while(delmode) {
2723	     if(delmode->type & M_T_DEFAULT) {
2724	        tempmode = delmode->next;
2725	        xf86DeleteMode(&pScrn->monitor->Modes, delmode);
2726	        delmode = tempmode;
2727	     } else {
2728	        delmode = delmode->next;
2729	     }
2730	  }
2731	  /* Link default modes AFTER user ones */
2732	  if((tempmode = pScrn->monitor->Modes)) {
2733	     *havecustommodes = TRUE;
2734	     while(tempmode) {
2735	        if(!tempmode->next) break;
2736	        else tempmode = tempmode->next;
2737	     }
2738	     tempmode->next = mymodes;
2739	     mymodes->prev = tempmode;
2740	  } else {
2741	     pScrn->monitor->Modes = mymodes;
2742	  }
2743#if 0
2744	  pScrn->monitor->Modes = mymodes;
2745	  while(mymodes) {
2746	     if(!mymodes->next) break;
2747	     else mymodes = mymodes->next;
2748	  }
2749	  mymodes->next = tempmode;
2750	  if(tempmode) {
2751	     tempmode->prev = mymodes;
2752	  }
2753#endif
2754       }
2755       return TRUE;
2756    } else
2757       return FALSE;
2758}
2759
2760static void
2761SiSPrintModes(ScrnInfoPtr pScrn)
2762{
2763    DisplayModePtr p;
2764    float hsync, refresh = 0.0;
2765    char *desc, *desc2, *prefix, *uprefix, *output;
2766
2767    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Virtual size is %dx%d "
2768	       "(pitch %d)\n", pScrn->virtualX, pScrn->virtualY,
2769	       pScrn->displayWidth);
2770
2771    if((p = pScrn->modes) == NULL) return;
2772
2773    do {
2774	desc = desc2 = "";
2775	uprefix = " ";
2776	prefix = "Mode";
2777	output = "For CRT device: ";
2778	if(p->HSync > 0.0)      hsync = p->HSync;
2779	else if (p->HTotal > 0) hsync = (float)p->Clock / (float)p->HTotal;
2780	else	                hsync = 0.0;
2781	refresh = 0.0;
2782        if(p->VRefresh > 0.0)   refresh = p->VRefresh;
2783        else if (p->HTotal > 0 && p->VTotal > 0) {
2784	   refresh = p->Clock * 1000.0 / p->HTotal / p->VTotal;
2785	   if(p->Flags & V_INTERLACE) refresh *= 2.0;
2786	   if(p->Flags & V_DBLSCAN)   refresh /= 2.0;
2787	   if(p->VScan > 1)  	      refresh /= p->VScan;
2788        }
2789	if(p->Flags & V_INTERLACE) desc = " (I)";
2790	if(p->Flags & V_DBLSCAN)   desc = " (D)";
2791	if(p->VScan > 1) 	   desc2 = " (VScan)";
2792#ifdef M_T_USERDEF
2793	if(p->type & M_T_USERDEF)  uprefix = "*";
2794#endif
2795	if(p->type & M_T_BUILTIN)       {
2796	   prefix = "Built-in mode";
2797	   output = "";
2798	} else if (p->type & M_T_DEFAULT) {
2799	   prefix = "Default mode";
2800	} else {
2801	   output = "";
2802	}
2803
2804	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
2805		"%s%s \"%s\" (%dx%d) (%s%.1f MHz, %.1f kHz, %.1f Hz%s%s)\n",
2806		uprefix, prefix, p->name, p->HDisplay, p->VDisplay, output,
2807		p->Clock / 1000.0, hsync, refresh, desc, desc2);
2808
2809	p = p->next;
2810    } while (p != NULL && p != pScrn->modes);
2811}
2812
2813Bool SISDetermineLCDACap(ScrnInfoPtr pScrn)
2814{
2815    SISPtr pSiS = SISPTR(pScrn);
2816
2817    if( ((pSiS->ChipType == SIS_650)    ||
2818         (pSiS->ChipType == SIS_315PRO) ||
2819         (pSiS->ChipType >= SIS_661))		&&
2820	(pSiS->ChipType != XGI_20)		&&
2821        (pSiS->VBFlags2 & VB2_SISLCDABRIDGE)	&&
2822	(pSiS->VESA != 1) ) {
2823       return TRUE;
2824    }
2825    return FALSE;
2826}
2827
2828void SISSaveDetectedDevices(ScrnInfoPtr pScrn)
2829{
2830    SISPtr  pSiS = SISPTR(pScrn);
2831    /* Backup detected CRT2 devices */
2832    pSiS->detectedCRT2Devices = pSiS->VBFlags & (CRT2_LCD|CRT2_TV|CRT2_VGA|TV_AVIDEO|TV_SVIDEO|
2833                                                 TV_SCART|TV_HIVISION|TV_YPBPR);
2834}
2835
2836static Bool
2837SISCheckBIOS(SISPtr pSiS, UShort mypciid, UShort mypcivendor, int biossize)
2838{
2839    UShort romptr, pciid;
2840
2841    if(!pSiS->BIOS) return FALSE;
2842
2843    if((pSiS->BIOS[0] != 0x55) || (pSiS->BIOS[1] != 0xaa)) return FALSE;
2844
2845    romptr = pSiS->BIOS[0x18] | (pSiS->BIOS[0x19] << 8);
2846    if(romptr > (biossize - 8)) return FALSE;
2847    if((pSiS->BIOS[romptr]   != 'P') || (pSiS->BIOS[romptr+1] != 'C') ||
2848       (pSiS->BIOS[romptr+2] != 'I') || (pSiS->BIOS[romptr+3] != 'R')) return FALSE;
2849
2850    pciid = pSiS->BIOS[romptr+4] | (pSiS->BIOS[romptr+5] << 8);
2851    if(pciid != mypcivendor) return FALSE;
2852
2853    pciid = pSiS->BIOS[romptr+6] | (pSiS->BIOS[romptr+7] << 8);
2854    if(pciid != mypciid) return FALSE;
2855
2856    return TRUE;
2857}
2858
2859static void
2860SiS_LoadInitVBE(ScrnInfoPtr pScrn)
2861{
2862    SISPtr pSiS = SISPTR(pScrn);
2863
2864    /* Don't load the VBE module for secondary
2865     * cards which sisfb POSTed. We don't want
2866     * int10 to overwrite our set up (such as
2867     * disabled a0000 memory address decoding).
2868     * We don't need the VBE anyway because
2869     * the card will never be in text mode,
2870     * and we can restore graphics modes just
2871     * perfectly.
2872     */
2873    if( !pSiS->Primary &&
2874        pSiS->sisfbcardposted)
2875       return;
2876
2877    if(pSiS->pVbe) return;
2878
2879    if(xf86LoadSubModule(pScrn, "vbe")) {
2880#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,99,0,0)
2881       pSiS->pVbe = VBEInit(pSiS->pInt, pSiS->pEnt->index);
2882#else
2883       pSiS->pVbe = VBEExtendedInit(pSiS->pInt, pSiS->pEnt->index,
2884	                SET_BIOS_SCRATCH | RESTORE_BIOS_SCRATCH);
2885#endif
2886    }
2887
2888    if(!pSiS->pVbe) {
2889       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2890	   "Failed to load/initialize vbe module\n");
2891    }
2892}
2893
2894#ifdef SIS_PC_PLATFORM
2895static void
2896SiS_MapVGAMem(ScrnInfoPtr pScrn)
2897{
2898    SISPtr pSiS = SISPTR(pScrn);
2899
2900    /* Map 64k VGA window for saving/restoring CGA fonts */
2901    pSiS->VGAMapSize = 0x10000;
2902    pSiS->VGAMapPhys = 0;	/* Default */
2903    if((!pSiS->Primary) || (!pSiS->VGADecodingEnabled)) {
2904       /* If card is secondary or if a0000-address decoding
2905        * is disabled, set Phys to beginning of our video RAM.
2906	*/
2907       pSiS->VGAMapPhys = PCI_REGION_BASE(pSiS->PciInfo, 0, REGION_MEM);
2908    }
2909    if(!SiSVGAMapMem(pScrn)) {
2910       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2911	  "Failed to map VGA memory (0x%lx), can't save/restore console fonts\n",
2912	  pSiS->VGAMapPhys);
2913    }
2914}
2915#endif
2916
2917static void
2918SiS_CheckKernelFB(ScrnInfoPtr pScrn)
2919{
2920    SISPtr pSiS = SISPTR(pScrn);
2921    int        fd, i;
2922    CARD32     sisfbinfosize = 0, sisfbversion;
2923    sisfb_info *mysisfbinfo;
2924    char       name[16];
2925
2926    pSiS->donttrustpdc = FALSE;
2927    pSiS->sisfbpdc = 0xff;
2928    pSiS->sisfbpdca = 0xff;
2929    pSiS->sisfblcda = 0xff;
2930    pSiS->sisfbscalelcd = -1;
2931    pSiS->sisfbspecialtiming = CUT_NONE;
2932    pSiS->sisfb_haveemi = FALSE;
2933    pSiS->sisfbfound = FALSE;
2934    pSiS->sisfb_tvposvalid = FALSE;
2935    pSiS->sisfbdevname[0] = 0;
2936    pSiS->sisfb_havelock = FALSE;
2937    pSiS->sisfbHaveNewHeapDef = FALSE;
2938    pSiS->sisfbHeapSize = 0;
2939    pSiS->sisfbVideoOffset = 0;
2940    pSiS->sisfbxSTN = FALSE;
2941    pSiS->sisfbcanpost = FALSE;   /* (Old) sisfb can't POST card */
2942    pSiS->sisfbcardposted = TRUE; /* If (old) sisfb is running, card must have been POSTed */
2943    pSiS->sisfbprimary = FALSE;   /* (Old) sisfb doesn't know */
2944
2945    if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
2946
2947       i = 0;
2948       do {
2949
2950	  if(i <= 7) {
2951             sprintf(name, "/dev/fb%1d", i);
2952	  } else {
2953	     sprintf(name, "/dev/fb/%1d", (i - 8));
2954	  }
2955
2956          if((fd = open(name, O_RDONLY)) != -1) {
2957
2958	     Bool gotit = FALSE;
2959
2960 	     if(!ioctl(fd, SISFB_GET_INFO_SIZE, &sisfbinfosize)) {
2961 		if((mysisfbinfo = malloc(sisfbinfosize))) {
2962 		   if(!ioctl(fd, (SISFB_GET_INFO | (sisfbinfosize << 16)), mysisfbinfo)) {
2963 		      gotit = TRUE;
2964 		   } else {
2965 		      free(mysisfbinfo);
2966 		      mysisfbinfo = NULL;
2967 		   }
2968 		}
2969 	     } else {
2970 		if((mysisfbinfo = malloc(sizeof(*mysisfbinfo) + 16))) {
2971 		   if(!ioctl(fd, SISFB_GET_INFO_OLD, mysisfbinfo)) {
2972 		      gotit = TRUE;
2973		      xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2974				"Possibly old version of sisfb detected. Please update.\n");
2975		   } else {
2976		      free(mysisfbinfo);
2977		      mysisfbinfo = NULL;
2978		   }
2979		}
2980	     }
2981
2982	     if(gotit) {
2983
2984		if(mysisfbinfo->sisfb_id == SISFB_ID) {
2985
2986		   sisfbversion = (mysisfbinfo->sisfb_version << 16) |
2987				  (mysisfbinfo->sisfb_revision << 8) |
2988				  (mysisfbinfo->sisfb_patchlevel);
2989
2990	           if(sisfbversion >= SISFB_VERSION(1, 5, 8)) {
2991		      /* Added PCI bus/slot/func into in sisfb Version 1.5.08.
2992		       * Check this to make sure we run on the same card as sisfb
2993		       */
2994		      if((mysisfbinfo->sisfb_pcibus  == pSiS->PciBus)    &&
2995			 (mysisfbinfo->sisfb_pcislot == pSiS->PciDevice) &&
2996			 (mysisfbinfo->sisfb_pcifunc == pSiS->PciFunc)) {
2997			 pSiS->sisfbfound = TRUE;
2998		      }
2999		   } else pSiS->sisfbfound = TRUE;
3000
3001		   if(pSiS->sisfbfound) {
3002		      xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3003			     "%s: SiS kernel fb driver (sisfb) %d.%d.%d detected (PCI:%02d:%02d.%d)\n",
3004				&name[5],
3005				mysisfbinfo->sisfb_version,
3006				mysisfbinfo->sisfb_revision,
3007				mysisfbinfo->sisfb_patchlevel,
3008				pSiS->PciBus,
3009				pSiS->PciDevice,
3010				pSiS->PciFunc);
3011
3012		      /* Added version/rev/pl in sisfb 1.4.0 */
3013		      if(mysisfbinfo->sisfb_version == 0) {
3014			 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3015				"Old version of sisfb found. Please update.\n");
3016		      }
3017		      /* Basically, we can't trust the pdc register if sisfb is loaded */
3018		      pSiS->donttrustpdc = TRUE;
3019		      pSiS->sisfbHeapStart = mysisfbinfo->heapstart;
3020
3021		      if(sisfbversion >= SISFB_VERSION(1, 7, 20)) {
3022			 pSiS->sisfbHeapSize = mysisfbinfo->sisfb_heapsize;
3023			 pSiS->sisfbVideoOffset = mysisfbinfo->sisfb_videooffset;
3024			 pSiS->sisfbHaveNewHeapDef = TRUE;
3025			 pSiS->sisfbFSTN = mysisfbinfo->sisfb_curfstn;
3026			 pSiS->sisfbDSTN = mysisfbinfo->sisfb_curdstn;
3027			 pSiS->sisfbxSTN = TRUE;
3028			 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3029				"sisfb: memory heap at %dKB, size %dKB, viewport at %dKB\n",
3030				(int)pSiS->sisfbHeapStart, (int)pSiS->sisfbHeapSize,
3031				(int)pSiS->sisfbVideoOffset/1024);
3032		      } else {
3033			 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3034				"sisfb: memory heap at %dKB\n", (int)pSiS->sisfbHeapStart);
3035		      }
3036		      xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3037				"sisfb: using video mode 0x%02x\n", mysisfbinfo->fbvidmode);
3038		      pSiS->OldMode = mysisfbinfo->fbvidmode;
3039		      if(sisfbversion >= SISFB_VERSION(1, 5, 6)) {
3040			 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3041				"sisfb: using %s, reserved %dK\n",
3042				(mysisfbinfo->sisfb_caps & 0x40) ? "SiS300 series Turboqueue" :
3043				   (mysisfbinfo->sisfb_caps & 0x20) ? "SiS315/330/340 series AGP command queue" :
3044				      (mysisfbinfo->sisfb_caps & 0x10) ? "SiS315/330/340 series VRAM command queue" :
3045					(mysisfbinfo->sisfb_caps & 0x08) ? "SiS315/330/340 series MMIO mode" :
3046					   "no command queue",
3047				(int)mysisfbinfo->sisfb_tqlen);
3048		      }
3049		      if(sisfbversion >= SISFB_VERSION(1, 5, 10)) {
3050			 /* We can trust the pdc value if sisfb is of recent version */
3051			 if(pSiS->VGAEngine == SIS_300_VGA) pSiS->donttrustpdc = FALSE;
3052		      }
3053		      if(sisfbversion >= SISFB_VERSION(1, 5, 11)) {
3054			 if(pSiS->VGAEngine == SIS_300_VGA) {
3055			    /* As of 1.5.11, sisfb saved the register for us (300 series) */
3056			    pSiS->sisfbpdc = mysisfbinfo->sisfb_lcdpdc;
3057			    if(!pSiS->sisfbpdc) pSiS->sisfbpdc = 0xff;
3058			 }
3059		      }
3060		      if(sisfbversion >= SISFB_VERSION(1, 5, 14)) {
3061			 if(pSiS->VGAEngine == SIS_315_VGA) {
3062			    pSiS->sisfblcda = mysisfbinfo->sisfb_lcda;
3063			 }
3064		      }
3065		      if(sisfbversion >= SISFB_VERSION(1, 6, 13)) {
3066			 pSiS->sisfbscalelcd = mysisfbinfo->sisfb_scalelcd;
3067			 pSiS->sisfbspecialtiming = mysisfbinfo->sisfb_specialtiming;
3068		      }
3069		      if(sisfbversion >= SISFB_VERSION(1, 6, 16)) {
3070			 if(pSiS->VGAEngine == SIS_315_VGA) {
3071			    pSiS->donttrustpdc = FALSE;
3072			    pSiS->sisfbpdc = mysisfbinfo->sisfb_lcdpdc;
3073			    if(sisfbversion >= SISFB_VERSION(1, 6, 24)) {
3074			       pSiS->sisfb_haveemi = mysisfbinfo->sisfb_haveemi ? TRUE : FALSE;
3075			       pSiS->sisfb_haveemilcd = TRUE;  /* will match most cases */
3076			       pSiS->sisfb_emi30 = mysisfbinfo->sisfb_emi30;
3077			       pSiS->sisfb_emi31 = mysisfbinfo->sisfb_emi31;
3078			       pSiS->sisfb_emi32 = mysisfbinfo->sisfb_emi32;
3079			       pSiS->sisfb_emi33 = mysisfbinfo->sisfb_emi33;
3080			    }
3081			    if(sisfbversion >= SISFB_VERSION(1, 6, 25)) {
3082			       pSiS->sisfb_haveemilcd = mysisfbinfo->sisfb_haveemilcd ? TRUE : FALSE;
3083			    }
3084			    if(sisfbversion >= SISFB_VERSION(1, 6, 31)) {
3085			       pSiS->sisfbpdca = mysisfbinfo->sisfb_lcdpdca;
3086			    } else {
3087			       if(pSiS->sisfbpdc) {
3088				  pSiS->sisfbpdca = (pSiS->sisfbpdc & 0xf0) >> 3;
3089				  pSiS->sisfbpdc  = (pSiS->sisfbpdc & 0x0f) << 1;
3090			       } else {
3091				  pSiS->sisfbpdca = pSiS->sisfbpdc = 0xff;
3092			       }
3093			    }
3094			 }
3095		      }
3096		      if(sisfbversion >= SISFB_VERSION(1, 7, 0)) {
3097		         pSiS->sisfb_havelock = TRUE;
3098			 if(sisfbversion >= SISFB_VERSION(1, 7, 1)) {
3099			    pSiS->sisfb_tvxpos = mysisfbinfo->sisfb_tvxpos;
3100			    pSiS->sisfb_tvypos = mysisfbinfo->sisfb_tvypos;
3101			    pSiS->sisfb_tvposvalid = TRUE;
3102			 }
3103		      }
3104		      if(sisfbversion >= SISFB_VERSION(1, 8, 7)) {
3105			 pSiS->sisfbcanpost = (mysisfbinfo->sisfb_can_post) ? TRUE : FALSE;
3106			 pSiS->sisfbcardposted = (mysisfbinfo->sisfb_card_posted) ? TRUE : FALSE;
3107			 pSiS->sisfbprimary = (mysisfbinfo->sisfb_was_boot_device) ? TRUE : FALSE;
3108			 /* Validity check */
3109			 if(!pSiS->sisfbcardposted) {
3110			    pSiS->sisfbprimary = FALSE;
3111			 }
3112		      }
3113		   }
3114	        }
3115		free(mysisfbinfo);
3116		mysisfbinfo = NULL;
3117	     }
3118	     close (fd);
3119          }
3120	  i++;
3121       } while((i <= 15) && (!pSiS->sisfbfound));
3122
3123       if(pSiS->sisfbfound) {
3124          strncpy(pSiS->sisfbdevname, name, 15);
3125       } else {
3126          xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "sisfb not found\n");
3127       }
3128    }
3129
3130    if(!pSiS->sisfbfound) {
3131       pSiS->sisfbcardposted = FALSE;
3132    }
3133}
3134
3135static void
3136SiSPseudo(ScrnInfoPtr pScrn)
3137{
3138}
3139
3140/* PreInit()
3141 *
3142 * Mandatory
3143 */
3144static Bool
3145SISPreInit(ScrnInfoPtr pScrn, int flags)
3146{
3147    SISPtr pSiS;
3148#ifdef SISDUALHEAD
3149    SISEntPtr pSiSEnt = NULL;
3150#endif
3151    MessageType from;
3152    UChar usScratchCR17, usScratchCR32, usScratchCR63;
3153    UChar usScratchSR1F, srlockReg, crlockReg;
3154    unsigned int i;
3155    int pix24flags, temp;
3156    ClockRangePtr clockRanges;
3157    xf86MonPtr pMonitor = NULL;
3158    Bool didddc2, fromDDC, crt1freqoverruled = FALSE;
3159    UChar CR5F, tempreg;
3160#if defined(SISMERGED) || defined(SISDUALHEAD)
3161    DisplayModePtr first, p, n;
3162#endif
3163#ifdef SISMERGED
3164    Bool crt2freqoverruled = FALSE;
3165#endif
3166
3167    static const char *ddcsstr = "CRT%d DDC monitor info: *******************************************\n";
3168    static const char *ddcestr = "End of CRT%d DDC monitor info *************************************\n";
3169    static const char *subshstr = "Substituting missing CRT%d monitor HSync range by DDC data\n";
3170    static const char *subsvstr = "Substituting missing CRT%d monitor VRefresh range by DDC data\n";
3171    static const char *saneh = "Correcting %s CRT%d monitor HSync range\n";
3172    static const char *sanev = "Correcting %s CRT%d monitor VRefresh range\n";
3173#ifdef SISMERGED
3174    static const char *mergednocrt1 = "CRT1 not detected or forced off. %s.\n";
3175    static const char *mergednocrt2 = "No CRT2 output selected or no video bridge detected. %s.\n";
3176    static const char *mergeddisstr = "MergedFB mode disabled";
3177    static const char *modesforstr = "Modes for CRT%d: **************************************************\n";
3178    static const char *crtsetupstr = "*************************** CRT%d setup ***************************\n";
3179    static const char *crt2monname = "CRT2";
3180#endif
3181#if defined(SISDUALHEAD) || defined(SISMERGED)
3182    static const char *notsuitablestr = "Not using mode \"%s\" (not suitable for %s mode)\n";
3183#endif
3184
3185    if(flags & PROBE_DETECT) {
3186
3187       vbeInfoPtr   pVbe;
3188
3189       if(xf86LoadSubModule(pScrn, "vbe")) {
3190          int index = xf86GetEntityInfo(pScrn->entityList[0])->index;
3191#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,99,0,0)
3192	  if((pVbe = VBEInit(NULL, index)))
3193#else
3194          if((pVbe = VBEExtendedInit(NULL, index, 0)))
3195#endif
3196          {
3197             ConfiguredMonitor = vbeDoEDID(pVbe, NULL);
3198             vbeFree(pVbe);
3199          }
3200       }
3201       return TRUE;
3202    }
3203
3204    /*
3205     * Note: This function is only called once at server startup, and
3206     * not at the start of each server generation.  This means that
3207     * only things that are persistent across server generations can
3208     * be initialised here.  xf86Screens[] is the array of all screens,
3209     * (pScrn is a pointer to one of these).  Privates allocated using
3210     * xf86AllocateScrnInfoPrivateIndex() are too, and should be used
3211     * for data that must persist across server generations.
3212     *
3213     * Per-generation data should be allocated with
3214     * AllocateScreenPrivateIndex() from the ScreenInit() function.
3215     */
3216
3217    /* Check the number of entities, and fail if it isn't one. */
3218    if(pScrn->numEntities != 1) {
3219       SISErrorLog(pScrn, "Number of entities is not 1\n");
3220       return FALSE;
3221    }
3222
3223    /* Due to the liberal license terms this is needed for
3224     * keeping the copyright notice readable and intact in
3225     * binary distributions. Removing this is a copyright
3226     * infringement. Please read the license terms above.
3227     */
3228
3229    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3230	"SiS driver (%d/%02d/%02d-%d, compiled for " SISMYSERVERNAME " %d.%d.%d.%d)\n",
3231	SISDRIVERVERSIONYEAR + 2000, SISDRIVERVERSIONMONTH,
3232	SISDRIVERVERSIONDAY, SISDRIVERREVISION,
3233#ifdef XORG_VERSION_CURRENT
3234	XORG_VERSION_MAJOR, XORG_VERSION_MINOR,
3235	XORG_VERSION_PATCH, XORG_VERSION_SNAP
3236#else
3237	XF86_VERSION_MAJOR, XF86_VERSION_MINOR,
3238	XF86_VERSION_PATCH, XF86_VERSION_SNAP
3239#endif
3240	);
3241    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3242	"Copyright (C) 2001-2005 Thomas Winischhofer <thomas@winischhofer.net> and others\n");
3243    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3244	"*** See http://www.winischhofer.eu/linuxsisvga.shtml\n");
3245    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3246	"*** for documentation and updates.\n");
3247
3248#ifdef XORG_VERSION_CURRENT
3249#if 0  /* no prototype yet */
3250    if(xorgGetVersion() != XORG_VERSION_CURRENT) {
3251       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
3252         "This driver binary is not compiled for this version of " SISMYSERVERNAME "\n");
3253    }
3254#endif
3255#else
3256#if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4,2,99,0,0)
3257    if(xf86GetVersion() != XF86_VERSION_CURRENT) {
3258       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
3259         "This driver binary is not compiled for this version of " SISMYSERVERNAME "\n");
3260    }
3261#endif
3262#endif
3263
3264    /* Allocate the SISRec driverPrivate */
3265    if(!SISGetRec(pScrn)) {
3266       SISErrorLog(pScrn, "Could not allocate memory for pSiS private\n");
3267       return FALSE;
3268    }
3269    pSiS = SISPTR(pScrn);
3270    pSiS->pScrn = pScrn;
3271
3272    pSiS->pInt = NULL;
3273
3274    /* Save PCI Domain Base */
3275#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,99,0,0) || GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 12
3276    pSiS->IODBase = 0;
3277#else
3278    pSiS->IODBase = pScrn->domainIOBase;
3279#endif
3280
3281    /* Get the entity, and make sure it is PCI. */
3282    pSiS->pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
3283    if(pSiS->pEnt->location.type != BUS_PCI) {
3284       SISErrorLog(pScrn, "Entity's bus type is not PCI\n");
3285       goto my_error_0;
3286    }
3287
3288#ifdef SISDUALHEAD
3289    /* Allocate an entity private if necessary */
3290    if(xf86IsEntityShared(pScrn->entityList[0])) {
3291       pSiSEnt = xf86GetEntityPrivate(pScrn->entityList[0], SISEntityIndex)->ptr;
3292       pSiS->entityPrivate = pSiSEnt;
3293
3294       /* If something went wrong, quit here */
3295       if((pSiSEnt->DisableDual) || (pSiSEnt->ErrorAfterFirst)) {
3296	  SISErrorLog(pScrn, "First head encountered fatal error, aborting...\n");
3297	  goto my_error_0;
3298       }
3299    }
3300#endif
3301
3302    /* Find the PCI info for this screen */
3303    pSiS->PciInfo = xf86GetPciInfoForEntity(pSiS->pEnt->index);
3304    pSiS->PciBus = PCI_CFG_BUS(pSiS->PciInfo);    /*SIS_PCI_BUS(pSiS->PciInfo);*/
3305    pSiS->PciDevice = PCI_CFG_DEV(pSiS->PciInfo); /*SIS_PCI_DEVICE(pSiS->PciInfo);*/
3306    pSiS->PciFunc = PCI_CFG_FUNC(pSiS->PciInfo);  /*SIS_PCI_FUNC(pSiS->PciInfo);*/
3307
3308#ifndef XSERVER_LIBPCIACCESS
3309    pSiS->PciTag = pciTag(PCI_DEV_BUS(pSiS->PciInfo),
3310			  PCI_DEV_DEV(pSiS->PciInfo),
3311			  PCI_DEV_FUNC(pSiS->PciInfo));
3312#endif
3313
3314#ifdef SIS_NEED_MAP_IOP
3315    /********************************************/
3316    /*     THIS IS BROKEN AND WON'T WORK        */
3317    /* Reasons:                                 */
3318    /* 1) MIPS and ARM have no i/o ports but    */
3319    /* use memory mapped i/o only. The inX/outX */
3320    /* macros in compiler.h are smart enough to */
3321    /* add "IOPortBase" to the port number, but */
3322    /* "IOPortBase" is never initialized.       */
3323    /* 2) IOPortBase is declared in compiler.h  */
3324    /* itself. So until somebody fixes all      */
3325    /* modules that #include compiler.h to set  */
3326    /* IOPortBase, vga support for MIPS and ARM */
3327    /* is unusable.                             */
3328    /* (In this driver this is solvable because */
3329    /* we have our own vgaHW routines. However, */
3330    /* we use /dev/port for now instead.)       */
3331    /********************************************/
3332    pSiS->IOPAddress = pSiS->IODBase + pSiS->PciInfo->ioBase[2];
3333    if(!SISMapIOPMem(pScrn)) {
3334       SISErrorLog(pScrn, "Could not map I/O port area at 0x%x\n", pSiS->IOPAddress);
3335       goto my_error_0;
3336    } else {
3337       xf86DrvMsg(pScrn->scrnIndex, X_INFO, "I/O port area mapped to %p, size 128\n", pSiS->IOPBase);
3338#if defined(__mips__) || defined(__arm32__)
3339       /* inX/outX macros on these use IOPortBase as offset */
3340       /* This is entirely skrewed. */
3341       IOPortBase = (unsigned int)pSiS->IOPBase;
3342#endif
3343    }
3344#endif
3345
3346    /* Set up i/o port access (for non-x86) */
3347#ifdef SISUSEDEVPORT
3348    if((sisdevport = open("/dev/port", O_RDWR, 0)) == -1) {
3349       SISErrorLog(pScrn, "Failed to open /dev/port for read/write\n");
3350       goto my_error_0;
3351    }
3352    pSiS->sisdevportopen = TRUE;
3353#endif
3354
3355    /*
3356     * Set the Chipset and ChipRev, allowing config file entries to
3357     * override. DANGEROUS!
3358     */
3359    {
3360       SymTabRec *myChipsets = SISChipsets;
3361
3362       if(PCI_DEV_VENDOR_ID(pSiS->PciInfo) == PCI_VENDOR_XGI) {
3363          myChipsets = XGIChipsets;
3364       }
3365
3366       if(pSiS->pEnt->device->chipset && *pSiS->pEnt->device->chipset) {
3367
3368          pScrn->chipset = pSiS->pEnt->device->chipset;
3369          pSiS->Chipset = xf86StringToToken(myChipsets, pScrn->chipset);
3370
3371       } else if(pSiS->pEnt->device->chipID >= 0) {
3372
3373          pSiS->Chipset = pSiS->pEnt->device->chipID;
3374          pScrn->chipset = (char *)xf86TokenToString(myChipsets, pSiS->Chipset);
3375
3376          xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipID override: 0x%04X\n",
3377								pSiS->Chipset);
3378       } else {
3379
3380          pSiS->Chipset = PCI_DEV_DEVICE_ID(pSiS->PciInfo);
3381          pScrn->chipset = (char *)xf86TokenToString(myChipsets, pSiS->Chipset);
3382
3383       }
3384    }
3385
3386    if(pSiS->pEnt->device->chipRev >= 0) {
3387
3388       pSiS->ChipRev = pSiS->pEnt->device->chipRev;
3389       xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipRev override: %d\n",
3390								pSiS->ChipRev);
3391    } else {
3392
3393       pSiS->ChipRev = PCI_DEV_REVISION(pSiS->PciInfo);
3394
3395    }
3396
3397    /*
3398     * This shouldn't happen because such problems should be caught in
3399     * SISProbe(), but check it just in case the user has overridden them.
3400     */
3401    if(pScrn->chipset == NULL) {
3402       SISErrorLog(pScrn, "ChipID 0x%04X is not recognised\n", pSiS->Chipset);
3403       goto my_error_0;
3404    }
3405    if(pSiS->Chipset < 0) {
3406       SISErrorLog(pScrn, "Chipset \"%s\" is not recognised\n", pScrn->chipset);
3407       goto my_error_0;
3408    }
3409
3410    pSiS->SiS6326Flags = 0;
3411
3412    /* Determine VGA engine generation */
3413    switch(pSiS->Chipset) {
3414       case PCI_CHIP_SIS300:
3415       case PCI_CHIP_SIS540:
3416       case PCI_CHIP_SIS630: /* 630 + 730 */
3417          pSiS->VGAEngine = SIS_300_VGA;
3418	  break;
3419       case PCI_CHIP_SIS315H:
3420       case PCI_CHIP_SIS315:
3421       case PCI_CHIP_SIS315PRO:
3422       case PCI_CHIP_SIS550:
3423       case PCI_CHIP_SIS650: /* 650 + 740 */
3424       case PCI_CHIP_SIS330:
3425       case PCI_CHIP_SIS660: /* 660, 661, 741, 760, 761, 670(?), 770 */
3426       case PCI_CHIP_SIS340:
3427       case PCI_CHIP_XGIXG20:
3428       case PCI_CHIP_XGIXG40:
3429          pSiS->VGAEngine = SIS_315_VGA;
3430	  break;
3431       case PCI_CHIP_SIS530:
3432          pSiS->VGAEngine = SIS_530_VGA;
3433	  break;
3434       case PCI_CHIP_SIS6326:
3435          /* Determine SiS6326 revision. According to SiS the differences are:
3436	   * Chip name     Chip type      TV-Out       MPEG II decoder
3437	   * 6326 AGP      Rev. G0/H0     no           no
3438	   * 6326 DVD      Rev. D2        yes          yes
3439	   * 6326          Rev. Cx        yes          yes
3440	   */
3441	  xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3442		"Chipset is SiS6326 %s (revision 0x%02x)\n",
3443		(pSiS->ChipRev == 0xaf) ? "(Ax)" :
3444		   ((pSiS->ChipRev == 0x0a) ? "AGP (G0)" :
3445		      ((pSiS->ChipRev == 0x0b) ? "AGP (H0)" :
3446			 (((pSiS->ChipRev & 0xf0) == 0xd0) ? "DVD (Dx/H0)" :
3447			    (((pSiS->ChipRev & 0xf0) == 0x90) ? "(9x)" :
3448			       (((pSiS->ChipRev & 0xf0) == 0xc0) ? "(Cx)" :
3449				  "(unknown)"))))),
3450		pSiS->ChipRev);
3451	  if((pSiS->ChipRev != 0x0a) && (pSiS->ChipRev != 0x0b)) {
3452	     pSiS->SiS6326Flags |= SIS6326_HASTV;
3453	  }
3454	  /* fall through */
3455       default:
3456	  pSiS->VGAEngine = SIS_OLD_VGA;
3457    }
3458
3459    /* We don't know about the current mode yet */
3460    pSiS->OldMode = 0;
3461
3462    /* Determine whether this is the primary or a secondary
3463     * display adapter. And right here the problem starts:
3464     * On machines with integrated SiS chipsets, the system BIOS
3465     * usually sets VGA_EN on all PCI-to-PCI bridges in the system
3466     * (of which there usually are two: PCI and AGP). This and
3467     * the fact that any PCI card POSTed by sisfb naturally has
3468     * its PCI resources enabled, leads to X assuming that
3469     * there are more than one "primary" cards in the system.
3470     * In this case, X treats ALL cards as "secondary" -
3471     * which by no means is desireable. If sisfb is running,
3472     * we can determine which card really is "primary" (in
3473     * terms of if it's the one that occupies the A0000 area
3474     * etc.) in a better way (Linux 2.6.12 or later). See below.
3475     */
3476    if(!(pSiS->Primary = xf86IsPrimaryPci(pSiS->PciInfo))) {
3477       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3478	   SISMYSERVERNAME " assumes this adapter to be secondary\n");
3479    }
3480
3481    /* Now check if sisfb is running, and if so, retrieve
3482     * all possible info from it. This also resets all
3483     * sisfb_* entries in pSiS regardless of the chipset.
3484     */
3485    SiS_CheckKernelFB(pScrn);
3486
3487    /* Now for that primary/secondary mess: Linux kernel
3488     * 2.6.12 and later knows what card is primary, and so
3489     * does any recent version of sisfb. XFree86/X.org takes
3490     * all adapters as "secondary" if more than one card's
3491     * memory and i/o resources are enabled, and more than
3492     * one PCI bridge in the system has VGA_EN set at server
3493     * start. So, let's start thinking: What is this
3494     * primary/secondary classification needed for anyway?
3495     * (This list might be incomplete for the entire server
3496     * infrastructure, but it's complete as regards the driver's
3497     * purposes of primary/secondary classification.)
3498     *    1) VGA/console font restoring: Here it's irrelevant
3499     *       whether more than one card's resources are enabled
3500     *       at server start or not. Relevant is whether the card
3501     *       occupies the A0000 area at this time. Assuming (?)
3502     *       that this does not change during machine up-time,
3503     *       it suffices to know which device was the boot video
3504     *       device (as determined by Linux 2.6.12 and later).
3505     *       Also, this is only relevant if the card is in text
3506     *       mode; if it's in graphics mode, fonts aren't saved
3507     *       or restored anyway.
3508     *       sisfb tells us if that card is considered the boot
3509     *       video device. The hardware registers tell us if
3510     *       the card's A0000 address decoding is enabled, and if
3511     *       the card currently is in text mode. These three bits
3512     *       of information are enough to decide on whether or not
3513     *       to save/restore fonts.
3514     *    2) POSTing. Same here. Relevant is only whether or not
3515     *       the card has been POSTed once before. POSTing cards
3516     *       on every server start is pretty ugly, especially
3517     *       if a framebuffer driver is already handling it.
3518     * SiS/XGI cards POSTed by sisfb can coexist well with other
3519     * active adapters. So we trust sisfb's information more
3520     * than X's (especially as we only use this information for
3521     * console font restoring and eventual POSTing.)
3522     * What we still need is a way to find out about all this if
3523     * sisfb is not running....
3524     */
3525    if(!pSiS->Primary && pSiS->sisfbprimary) {
3526       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3527		"sisfb reports this adapter to be primary. Seems more reliable.\n");
3528       pSiS->Primary = TRUE;
3529    }
3530
3531    /* If the card is "secondary" and has not been
3532     * POSTed by sisfb, POST it now through int10.
3533     * For cards POSTed by sisfb, we definitely don't
3534     * want that as it messes up our set up (eg. the
3535     * disabled A0000 area).
3536     * The int10 module decides on its own if the
3537     * card is primary or secondary. Since it uses
3538     * the generic technique described above, and since
3539     * for "secondary" cards it needs a real PCI BIOS
3540     * ROM, and since integrated chips don't have such
3541     * a PCI BIOS ROM, int10 will naturally fail to
3542     * find/read the BIOS on such machines. Great.
3543     * Using the integrated graphics as "secondary"
3544     * (which it will be as soon as X finds more than
3545     * one card's mem and i/o resources enabled, and more
3546     * than one PCI bridge's VGA_EN bit set during server
3547     * start) will therefore prevent us from restoring
3548     * the mode using the VBE. That means real fun if
3549     * the integrated chip is set up to use the video
3550     * bridge output for text mode (which is something
3551     * the driver doesn't really support since it's done
3552     * pretty much differently on every machine.)
3553     */
3554#if !defined(__alpha__)
3555    if(!pSiS->Primary) {
3556       if(!pSiS->sisfbcardposted) {
3557	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3558		"Initializing adapter through int10\n");
3559	  if(xf86LoadSubModule(pScrn, "int10")) {
3560	     pSiS->pInt = xf86InitInt10(pSiS->pEnt->index);
3561	  } else {
3562	     SISErrorLog(pScrn, "Failed to load int10 module\n");
3563	  }
3564       } else {
3565	  xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3566		"Adapter already initialized by sisfb\n");
3567       }
3568    }
3569#endif
3570
3571    /* Get the address of our relocated IO registers.
3572     * These are enabled by the hardware during cold boot, and
3573     * by the BIOS. So we can pretty much rely on that these
3574     * are enabled.
3575     */
3576    pSiS->RelIO = (SISIOADDRESS)(PCI_REGION_BASE(pSiS->PciInfo, 2, REGION_IO) + pSiS->IODBase);
3577    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Relocated I/O registers at 0x%lX\n",
3578           (ULong)pSiS->RelIO);
3579
3580    /* Unlock extended registers */
3581    sisSaveUnlockExtRegisterLock(pSiS, &srlockReg, &crlockReg);
3582
3583    /* Is a0000 memory address decoding enabled? */
3584    pSiS->VGADecodingEnabled = TRUE;
3585    switch(pSiS->VGAEngine) {
3586    case SIS_OLD_VGA:
3587       /* n/a */
3588       break;
3589    case SIS_530_VGA:
3590       inSISIDXREG(SISSR, 0x3d, tempreg);
3591       if(tempreg & 0x04) pSiS->VGADecodingEnabled = FALSE;
3592       break;
3593    case SIS_300_VGA:
3594    case SIS_315_VGA:
3595       inSISIDXREG(SISSR, 0x20, tempreg);
3596       if(tempreg & 0x04) pSiS->VGADecodingEnabled = FALSE;
3597       break;
3598    }
3599
3600    if(!pSiS->VGADecodingEnabled) {
3601       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3602		"Standard VGA (0xA0000) memory address decoding is disabled\n");
3603    }
3604
3605#ifdef SIS_PC_PLATFORM
3606    /* Map 64k VGA window for saving/restoring CGA fonts.
3607     * For secondary cards or if A0000 address decoding
3608     * is disabled, this will map the beginning of the
3609     * linear (PCI) video RAM instead.
3610     */
3611    SiS_MapVGAMem(pScrn);
3612#endif
3613
3614#ifndef XSERVER_LIBPCIACCESS
3615    /* Set operating state */
3616
3617    /* 1. memory */
3618    /* [ResUnusedOpr: Resource decoded by hw, but not used]
3619     * [ResDisableOpr: Resource is not decoded by hw]
3620     * So, if a0000 memory decoding is disabled, one could
3621     * argue that we may say so, too. Hm. Quite likely that
3622     * the VBE (via int10) will eventually enable it. So we
3623     * cowardly say unused instead.
3624     */
3625    xf86SetOperatingState(resVgaMem, pSiS->pEnt->index, ResUnusedOpr);
3626
3627    /* 2. i/o */
3628    /* Although we only use the relocated i/o ports, the hardware
3629     * also decodes the standard VGA port range. This could in
3630     * theory be disabled, but I don't dare to do this; in case of
3631     * a server crash, the card would be entirely dead. Also, this
3632     * would prevent int10 and the VBE from working at all. Generic
3633     * access control through the PCI configuration registers does
3634     * nicely anyway.
3635     */
3636    xf86SetOperatingState(resVgaIo, pSiS->pEnt->index, ResUnusedOpr);
3637
3638    /* Operations for which memory access is required */
3639    pScrn->racMemFlags = RAC_FB | RAC_COLORMAP | RAC_CURSOR | RAC_VIEWPORT;
3640
3641    /* Operations for which I/O access is required */
3642    pScrn->racIoFlags = RAC_COLORMAP | RAC_CURSOR | RAC_VIEWPORT;
3643
3644#endif
3645
3646    /* Load ramdac module */
3647    if(!xf86LoadSubModule(pScrn, "ramdac")) {
3648       SISErrorLog(pScrn, "Could not load ramdac module\n");
3649       goto my_error_1;
3650    }
3651
3652    /* Set pScrn->monitor */
3653    pScrn->monitor = pScrn->confScreen->monitor;
3654
3655    /* Reset some entries */
3656    pSiS->SiSFastVidCopy = SiSVidCopyGetDefault();
3657    pSiS->SiSFastMemCopy = SiSVidCopyGetDefault();
3658    pSiS->SiSFastVidCopyFrom = SiSVidCopyGetDefault();
3659    pSiS->SiSFastMemCopyFrom = SiSVidCopyGetDefault();
3660    pSiS->SiSFastVidCopyDone = FALSE;
3661#ifdef SIS_USE_XAA
3662    pSiS->RenderCallback = NULL;
3663#endif
3664#ifdef SIS_USE_EXA
3665    pSiS->ExaRenderCallback = NULL;
3666#endif
3667    pSiS->InitAccel = SiSPseudo;
3668    pSiS->SyncAccel = SiSPseudo;
3669    pSiS->FillRect  = NULL;
3670    pSiS->BlitRect  = NULL;
3671
3672    /* Always do a ValidMode() inside Switchmode() */
3673    pSiS->skipswitchcheck = FALSE;
3674
3675    /* Determine chipset and its capabilities in detail */
3676    pSiS->ChipFlags = 0;
3677    pSiS->SiS_SD_Flags = pSiS->SiS_SD2_Flags = 0;
3678    pSiS->SiS_SD3_Flags = pSiS->SiS_SD4_Flags = 0;
3679    pSiS->HWCursorMBufNum = pSiS->HWCursorCBufNum = 0;
3680    pSiS->NeedFlush = FALSE;
3681    pSiS->NewCRLayout = FALSE;
3682    pSiS->mmioSize = 64;
3683
3684    switch(pSiS->Chipset) {
3685       case PCI_CHIP_SIS530:
3686	  pSiS->ChipType = SIS_530;
3687	  break;
3688       case PCI_CHIP_SIS300:
3689	  pSiS->ChipType = SIS_300;
3690	  pSiS->SiS_SD_Flags |= SiS_SD_IS300SERIES;
3691	  break;
3692       case PCI_CHIP_SIS540:
3693	  pSiS->ChipType = SIS_540;
3694	  pSiS->SiS_SD_Flags |= SiS_SD_IS300SERIES;
3695	  break;
3696       case PCI_CHIP_SIS630: /* 630 + 730 */
3697	  pSiS->ChipType = SIS_630;
3698	  if(sis_pci_read_host_bridge_u32(0x00) == 0x07301039) {
3699	     pSiS->ChipType = SIS_730;
3700	  }
3701	  pSiS->SiS_SD_Flags |= SiS_SD_IS300SERIES;
3702	  break;
3703       case PCI_CHIP_SIS315H:
3704	  pSiS->ChipType = SIS_315H;
3705	  pSiS->ChipFlags |= (SiSCF_315Core | SiSCF_MMIOPalette);
3706	  pSiS->SiS_SD_Flags |= SiS_SD_IS315SERIES;
3707	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3708	  pSiS->myCR63 = 0x63;
3709	  break;
3710       case PCI_CHIP_SIS315:
3711	  /* Override for simplicity */
3712	  pSiS->Chipset = PCI_CHIP_SIS315H;
3713	  pSiS->ChipType = SIS_315;
3714	  pSiS->ChipFlags |= (SiSCF_315Core | 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_SIS315PRO:
3720	  /* Override for simplicity */
3721	  pSiS->Chipset = PCI_CHIP_SIS315H;
3722	  pSiS->ChipType = SIS_315PRO;
3723	  pSiS->ChipFlags |= (SiSCF_315Core | SiSCF_MMIOPalette);
3724	  pSiS->SiS_SD_Flags |= SiS_SD_IS315SERIES;
3725	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3726	  pSiS->myCR63 = 0x63;
3727	  break;
3728       case PCI_CHIP_SIS550:
3729	  pSiS->ChipType = SIS_550;
3730	  pSiS->ChipFlags |= (SiSCF_Integrated | SiSCF_MMIOPalette);
3731	  pSiS->SiS_SD_Flags |= SiS_SD_IS315SERIES;
3732	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3733	  pSiS->myCR63 = 0x63;
3734	  break;
3735       case PCI_CHIP_SIS650: /* 650 + 740 */
3736	  pSiS->ChipType = SIS_650;
3737	  if(sis_pci_read_host_bridge_u32(0x00) == 0x07401039) {
3738	     pSiS->ChipType = SIS_740;
3739	  }
3740	  pSiS->ChipFlags |= (SiSCF_Integrated | SiSCF_Real256ECore | SiSCF_MMIOPalette);
3741	  pSiS->SiS_SD_Flags |= SiS_SD_IS315SERIES;
3742	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3743	  pSiS->myCR63 = 0x63;
3744	  break;
3745       case PCI_CHIP_SIS330:
3746	  pSiS->ChipType = SIS_330;
3747	  pSiS->ChipFlags |= (SiSCF_XabreCore | SiSCF_MMIOPalette);
3748	  pSiS->SiS_SD_Flags |= SiS_SD_IS330SERIES;
3749	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3750	  pSiS->SiS_SD3_Flags |= SiS_SD3_CRT1SATGAIN; /* FIXME ? */
3751	  pSiS->myCR63 = 0x53; /* sic! */
3752	  break;
3753       case PCI_CHIP_SIS660: /* 660, 661, 741, 760, 761, 670(?) */
3754	  {
3755	     ULong hpciid = sis_pci_read_host_bridge_u32(0x00);
3756	     switch(hpciid) {
3757	     case 0x06601039:
3758		pSiS->ChipType = SIS_660;
3759		pSiS->ChipFlags |= SiSCF_Ultra256Core;
3760		pSiS->NeedFlush = TRUE;
3761		break;
3762	     case 0x07601039:
3763		pSiS->ChipType = SIS_760;
3764		pSiS->ChipFlags |= SiSCF_Ultra256Core;
3765		pSiS->NeedFlush = TRUE;
3766		break;
3767	     case 0x07611039:
3768		pSiS->ChipType = SIS_761;
3769		pSiS->ChipFlags |= SiSCF_Ultra256Core;
3770		pSiS->NeedFlush = TRUE;
3771		break;
3772	     case 0x07701039:
3773		pSiS->ChipType = SIS_770;
3774		pSiS->ChipFlags |= SiSCF_Ultra256Core;
3775		pSiS->NeedFlush = TRUE;
3776		break;
3777	     case 0x07411039:
3778		pSiS->ChipType = SIS_741;
3779		pSiS->ChipFlags |= SiSCF_Real256ECore;
3780		break;
3781	     case 0x06611039:
3782	     default:
3783		pSiS->ChipType = SIS_661;
3784		pSiS->ChipFlags |= SiSCF_Real256ECore;
3785		break;
3786	     case 0x06701039:
3787		pSiS->ChipType = SIS_670;
3788		pSiS->ChipFlags |= SiSCF_Real256ECore;
3789	     }
3790	     /* Detection could also be done by CR5C & 0xf8:
3791	      * 0x10 = 661 (CR5F & 0xc0: 0x00 both A0 and A1)
3792	      * 0x80 = 760 (CR5F & 0xc0: 0x00 A0, 0x40 A1)
3793	      * 0x90 = 741 (CR5F & 0xc0: 0x00 A0,A1 0x40 A2)
3794	      * other: 660 (CR5F & 0xc0: 0x00 A0 0x40 A1) (DOA?)
3795	      */
3796	     pSiS->ChipFlags |= (SiSCF_Integrated | SiSCF_MMIOPalette);
3797	     pSiS->SiS_SD_Flags |= SiS_SD_IS330SERIES;
3798	     pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3799	     pSiS->SiS_SD3_Flags |= SiS_SD3_CRT1SATGAIN;
3800	     pSiS->myCR63 = 0x53; /* sic! */
3801	     pSiS->NewCRLayout = TRUE;
3802	  }
3803	  break;
3804       case PCI_CHIP_SIS340:
3805	  pSiS->ChipType = SIS_340;
3806	  pSiS->ChipFlags |= (SiSCF_XabreCore | SiSCF_MMIOPalette);
3807	  pSiS->SiS_SD_Flags |= SiS_SD_IS340SERIES;
3808	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3809	  pSiS->SiS_SD3_Flags |= SiS_SD3_CRT1SATGAIN;
3810	  pSiS->myCR63 = 0x53;
3811	  pSiS->NewCRLayout = TRUE;
3812	  break;
3813       case PCI_CHIP_XGIXG20:
3814	  pSiS->ChipType = XGI_20;
3815	  pSiS->ChipFlags |= (SiSCF_XabreCore | SiSCF_MMIOPalette | SiSCF_IsXGI);
3816	  pSiS->SiS_SD2_Flags |= (SiS_SD2_NOOVERLAY | SiS_SD2_ISXGI);
3817	  pSiS->myCR63 = 0x53;
3818	  pSiS->NewCRLayout = TRUE;
3819	  break;
3820       case PCI_CHIP_XGIXG40:
3821	  pSiS->ChipType = XGI_40;
3822	  pSiS->ChipFlags |= (SiSCF_XabreCore | SiSCF_MMIOPalette | SiSCF_IsXGI);
3823	  pSiS->SiS_SD2_Flags |= (SiS_SD2_SUPPORTXVHUESAT | SiS_SD2_ISXGI);
3824	  pSiS->SiS_SD3_Flags |= SiS_SD3_CRT1SATGAIN;
3825	  pSiS->myCR63 = 0x53;
3826	  pSiS->NewCRLayout = TRUE;
3827	  if(pSiS->ChipRev == 2) pSiS->ChipFlags |= SiSCF_IsXGIV3;
3828	  break;
3829       default:
3830	  pSiS->ChipType = SIS_OLD;
3831	  break;
3832    }
3833
3834    /*
3835     * Now back to real business: Figure out the depth, bpp, etc.
3836     * Set SupportConvert... flags since we use the fb layer which
3837     * supports this conversion. (24to32 seems not implemented though)
3838     * Additionally, determine the size of the HWCursor memory area.
3839     */
3840    switch(pSiS->VGAEngine) {
3841       case SIS_300_VGA:
3842	  pSiS->CursorSize = 4096;
3843	  pix24flags = Support32bppFb;
3844	  break;
3845       case SIS_315_VGA:
3846	  pSiS->CursorSize = 16384;
3847	  pix24flags = Support32bppFb;
3848	  break;
3849       case SIS_530_VGA:
3850	  pSiS->CursorSize = 2048;
3851	  pix24flags = Support32bppFb	  |
3852		       Support24bppFb	  |
3853		       SupportConvert32to24;
3854          break;
3855       default:
3856	  pSiS->CursorSize = 2048;
3857	  pix24flags = Support24bppFb	    |
3858		       SupportConvert32to24 |
3859		       PreferConvert32to24;
3860	  break;
3861    }
3862
3863#ifdef SISDUALHEAD
3864    /* In case of Dual Head, we need to determine if we are the "master" head or
3865     * the "slave" head. In order to do that, we set PrimInit to DONE in the
3866     * shared entity at the end of the first initialization. The second
3867     * initialization then knows that some things have already been done. THIS
3868     * ALWAYS ASSUMES THAT THE FIRST DEVICE INITIALIZED IS THE MASTER!
3869     */
3870    if(xf86IsEntityShared(pScrn->entityList[0])) {
3871       if(pSiSEnt->lastInstance > 0) {
3872	  if(!xf86IsPrimInitDone(pScrn->entityList[0])) {
3873	     /* First Head (always CRT2) */
3874	     pSiS->SecondHead = FALSE;
3875	     pSiSEnt->pScrn_1 = pScrn;
3876	     pSiSEnt->CRT1ModeNo = pSiSEnt->CRT2ModeNo = -1;
3877	     pSiSEnt->CRT2ModeSet = FALSE;
3878	     pSiS->DualHeadMode = TRUE;
3879	     pSiSEnt->DisableDual = FALSE;
3880	     pSiSEnt->BIOS = NULL;
3881	     pSiSEnt->ROM661New = FALSE;
3882	     pSiSEnt->HaveXGIBIOS = FALSE;
3883	     pSiSEnt->SiS_Pr = NULL;
3884	     pSiSEnt->RenderAccelArray = NULL;
3885	     pSiSEnt->SiSFastVidCopy = pSiSEnt->SiSFastMemCopy = NULL;
3886	     pSiSEnt->SiSFastVidCopyFrom = pSiSEnt->SiSFastMemCopyFrom = NULL;
3887	  } else {
3888	     /* Second Head (always CRT1) */
3889	     pSiS->SecondHead = TRUE;
3890	     pSiSEnt->pScrn_2 = pScrn;
3891	     pSiS->DualHeadMode = TRUE;
3892	  }
3893       } else {
3894	  /* Only one screen in config file - disable dual head mode */
3895	  pSiS->SecondHead = FALSE;
3896	  pSiS->DualHeadMode = FALSE;
3897	  pSiSEnt->DisableDual = TRUE;
3898       }
3899    } else {
3900       /* Entity is not shared - disable dual head mode */
3901       pSiS->SecondHead = FALSE;
3902       pSiS->DualHeadMode = FALSE;
3903    }
3904#endif
3905
3906    /* Save the name of our Device section for SiSCtrl usage */
3907    {
3908       int ttt = 0;
3909       GDevPtr device = xf86GetDevFromEntity(pScrn->entityList[0],
3910						pScrn->entityInstanceList[0]);
3911       if(device && device->identifier) {
3912          if((ttt = strlen(device->identifier)) > 31) ttt = 31;
3913	  strncpy(&pSiS->devsectname[0], device->identifier, 31);
3914       }
3915       pSiS->devsectname[ttt] = 0;
3916    }
3917
3918    pSiS->ForceCursorOff = FALSE;
3919
3920    /* Allocate SiS_Private (for mode switching code) and initialize it */
3921    pSiS->SiS_Pr = NULL;
3922#ifdef SISDUALHEAD
3923    if(pSiSEnt) {
3924       if(pSiSEnt->SiS_Pr) pSiS->SiS_Pr = pSiSEnt->SiS_Pr;
3925    }
3926#endif
3927    if(!pSiS->SiS_Pr) {
3928       if(!(pSiS->SiS_Pr = xnfcalloc(sizeof(struct SiS_Private), 1))) {
3929	  SISErrorLog(pScrn, "Could not allocate memory for SiS_Pr structure\n");
3930	  goto my_error_1;
3931       }
3932#ifdef SISDUALHEAD
3933       if(pSiSEnt) pSiSEnt->SiS_Pr = pSiS->SiS_Pr;
3934#endif
3935       memset(pSiS->SiS_Pr, 0, sizeof(struct SiS_Private));
3936#ifndef XSERVER_LIBPCIACCESS
3937       pSiS->SiS_Pr->PciTag = pSiS->PciTag;
3938#endif
3939       pSiS->SiS_Pr->ChipType = pSiS->ChipType;
3940       pSiS->SiS_Pr->ChipRevision = pSiS->ChipRev;
3941       pSiS->SiS_Pr->SiS_Backup70xx = 0xff;
3942       pSiS->SiS_Pr->SiS_CHOverScan = -1;
3943       pSiS->SiS_Pr->SiS_ChSW = FALSE;
3944       pSiS->SiS_Pr->SiS_CustomT = CUT_NONE;
3945       pSiS->SiS_Pr->SiS_UseWide = -1;
3946       pSiS->SiS_Pr->SiS_UseWideCRT2 = -1;
3947       pSiS->SiS_Pr->SiS_TVBlue = -1;
3948       pSiS->SiS_Pr->PanelSelfDetected = FALSE;
3949       pSiS->SiS_Pr->UsePanelScaler = -1;
3950       pSiS->SiS_Pr->CenterScreen = -1;
3951       pSiS->SiS_Pr->CRT1UsesCustomMode = FALSE;
3952       pSiS->SiS_Pr->PDC = pSiS->SiS_Pr->PDCA = -1;
3953       pSiS->SiS_Pr->LVDSHL = -1;
3954       pSiS->SiS_Pr->HaveEMI = FALSE;
3955       pSiS->SiS_Pr->HaveEMILCD = FALSE;
3956       pSiS->SiS_Pr->OverruleEMI = FALSE;
3957       pSiS->SiS_Pr->SiS_SensibleSR11 = FALSE;
3958       if(pSiS->ChipType >= SIS_661) {
3959          pSiS->SiS_Pr->SiS_SensibleSR11 = TRUE;
3960       }
3961       pSiS->SiS_Pr->SiS_MyCR63 = pSiS->myCR63;
3962       pSiS->SiS_Pr->DDCPortMixup = FALSE;
3963    }
3964
3965    /* Copy IO address to SiS_Pr and init the structure for
3966     * routines inside init.c/init301.c
3967     */
3968    pSiS->SiS_Pr->IOAddress = (SISIOADDRESS)(pSiS->RelIO + 0x30);
3969    SiSRegInit(pSiS->SiS_Pr, pSiS->RelIO + 0x30);
3970
3971    /* The following identifies the old chipsets. This is only
3972     * partly used since the really old chips are not supported,
3973     * but I keep it here for future use.
3974     * 205, 215 and 225 are to be treated the same way, 201 and 202
3975     * are different.
3976     */
3977    if(pSiS->VGAEngine == SIS_OLD_VGA || pSiS->VGAEngine == SIS_530_VGA) {
3978       switch(pSiS->Chipset) {
3979       case PCI_CHIP_SG86C201:
3980	  pSiS->oldChipset = OC_SIS86201; break;
3981       case PCI_CHIP_SG86C202:
3982	  pSiS->oldChipset = OC_SIS86202; break;
3983       case PCI_CHIP_SG86C205:
3984	  inSISIDXREG(SISSR, 0x10, tempreg);
3985	  if(tempreg & 0x80) pSiS->oldChipset = OC_SIS6205B;
3986	  else pSiS->oldChipset = (pSiS->ChipRev == 0x11) ?
3987					OC_SIS6205C : OC_SIS6205A;
3988	  break;
3989       case PCI_CHIP_SIS82C204:
3990	  pSiS->oldChipset = OC_SIS82204; break;
3991       case 0x6225:
3992	  pSiS->oldChipset = OC_SIS6225; break;
3993       case PCI_CHIP_SIS5597:
3994	  pSiS->oldChipset = OC_SIS5597; break;
3995       case PCI_CHIP_SIS6326:
3996	  pSiS->oldChipset = OC_SIS6326; break;
3997       case PCI_CHIP_SIS530:
3998	  if(sis_pci_read_host_bridge_u32(0x00) == 0x06201039) {
3999	     pSiS->oldChipset = OC_SIS620;
4000	  } else {
4001	     if((pSiS->ChipRev & 0x0f) < 0x0a)
4002		   pSiS->oldChipset = OC_SIS530A;
4003	     else  pSiS->oldChipset = OC_SIS530B;
4004	  }
4005	  break;
4006       default:
4007	  pSiS->oldChipset = OC_UNKNOWN;
4008       }
4009    }
4010
4011    if(!xf86SetDepthBpp(pScrn, 0, 0, 0, pix24flags)) {
4012       SISErrorLog(pScrn, "xf86SetDepthBpp() error\n");
4013       goto my_error_1;
4014    }
4015
4016    /* Check that the returned depth is one we support */
4017    temp = 0;
4018    switch(pScrn->depth) {
4019       case 8:
4020       case 16:
4021       case 24:
4022          break;
4023       case 15:
4024	  if((pSiS->VGAEngine == SIS_300_VGA) ||
4025	     (pSiS->VGAEngine == SIS_315_VGA)) {
4026	     temp = 1;
4027	  }
4028	  break;
4029       default:
4030	  temp = 1;
4031    }
4032
4033    if(temp) {
4034       SISErrorLog(pScrn,
4035            "Given color depth (%d) is not supported by this driver/chipset\n",
4036            pScrn->depth);
4037       goto my_error_1;
4038    }
4039
4040    xf86PrintDepthBpp(pScrn);
4041
4042    if( (((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) &&
4043         (pScrn->bitsPerPixel == 24)) ||
4044	((pSiS->VGAEngine == SIS_OLD_VGA) && (pScrn->bitsPerPixel == 32)) ) {
4045       SISErrorLog(pScrn,
4046            "Framebuffer bpp %d not supported for this chipset\n", pScrn->bitsPerPixel);
4047       goto my_error_1;
4048    }
4049
4050    /* Get the depth24 pixmap format */
4051    if(pScrn->depth == 24 && pix24bpp == 0) {
4052       pix24bpp = xf86GetBppFromDepth(pScrn, 24);
4053    }
4054
4055    /*
4056     * This must happen after pScrn->display has been set because
4057     * xf86SetWeight references it.
4058     */
4059    if(pScrn->depth > 8) {
4060        /* The defaults are OK for us */
4061        rgb zeros = {0, 0, 0};
4062
4063        if(!xf86SetWeight(pScrn, zeros, zeros)) {
4064	    SISErrorLog(pScrn, "xf86SetWeight() error\n");
4065	    goto my_error_1;
4066        } else {
4067	   Bool ret = FALSE;
4068	   switch(pScrn->depth) {
4069	   case 15:
4070	      if((pScrn->weight.red != 5) ||
4071	         (pScrn->weight.green != 5) ||
4072		 (pScrn->weight.blue != 5)) ret = TRUE;
4073	      break;
4074	   case 16:
4075	      if((pScrn->weight.red != 5) ||
4076	         (pScrn->weight.green != 6) ||
4077		 (pScrn->weight.blue != 5)) ret = TRUE;
4078	      break;
4079	   case 24:
4080	      if((pScrn->weight.red != 8) ||
4081	         (pScrn->weight.green != 8) ||
4082		 (pScrn->weight.blue != 8)) ret = TRUE;
4083	      break;
4084	   }
4085	   if(ret) {
4086	      SISErrorLog(pScrn,
4087		   "RGB weight %d%d%d at depth %d not supported by hardware\n",
4088		   (int)pScrn->weight.red, (int)pScrn->weight.green,
4089		   (int)pScrn->weight.blue, pScrn->depth);
4090	      goto my_error_1;
4091	   }
4092        }
4093    }
4094
4095    /* Set the current layout parameters */
4096    pSiS->CurrentLayout.bitsPerPixel = pScrn->bitsPerPixel;
4097    pSiS->CurrentLayout.depth        = pScrn->depth;
4098    /* (Inside this function, we can use pScrn's contents anyway) */
4099
4100    if(!xf86SetDefaultVisual(pScrn, -1)) {
4101       SISErrorLog(pScrn, "xf86SetDefaultVisual() error\n");
4102       goto my_error_1;
4103    } else {
4104       /* We don't support DirectColor at > 8bpp */
4105       if(pScrn->depth > 8 && pScrn->defaultVisual != TrueColor) {
4106	  SISErrorLog(pScrn,
4107	       "Given default visual (%s) is not supported at depth %d\n",
4108	        xf86GetVisualName(pScrn->defaultVisual), pScrn->depth);
4109	  goto my_error_1;
4110       }
4111    }
4112
4113#ifdef SISDUALHEAD
4114    /* Due to palette & timing problems we don't support 8bpp in DHM */
4115    if((pSiS->DualHeadMode) && (pScrn->bitsPerPixel <= 8)) {
4116       SISErrorLog(pScrn, "Color depth %d not supported in Dual Head mode.\n",
4117			pScrn->bitsPerPixel);
4118       goto my_error_1;
4119    }
4120#endif
4121
4122    /* Read BIOS for 300/315/330/340 series customization */
4123    pSiS->SiS_Pr->VirtualRomBase = NULL;
4124    pSiS->BIOS = NULL;
4125    pSiS->SiS_Pr->UseROM = FALSE;
4126    pSiS->ROM661New = FALSE;
4127    pSiS->HaveXGIBIOS = FALSE;
4128
4129    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
4130#ifdef SISDUALHEAD
4131       if(pSiSEnt) {
4132	  if(pSiSEnt->BIOS) {
4133	     pSiS->BIOS = pSiSEnt->BIOS;
4134	     pSiS->SiS_Pr->VirtualRomBase = pSiS->BIOS;
4135	     pSiS->ROM661New = pSiSEnt->ROM661New;
4136	     pSiS->HaveXGIBIOS = pSiSEnt->HaveXGIBIOS;
4137	  }
4138       }
4139#endif
4140       if(!pSiS->BIOS) {
4141	  if(!(pSiS->BIOS = calloc(1, BIOS_SIZE))) {
4142	     xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
4143		"Could not allocate memory for video BIOS image\n");
4144	  } else {
4145	     UShort mypciid = pSiS->Chipset;
4146	     UShort mypcivendor = (pSiS->ChipFlags & SiSCF_IsXGI) ? PCI_VENDOR_XGI : PCI_VENDOR_SIS;
4147	     Bool   found = FALSE, readpci = FALSE;
4148	     int    biossize = BIOS_SIZE;
4149
4150	     switch(pSiS->ChipType) {
4151	     case SIS_315:    mypciid = PCI_CHIP_SIS315;
4152			      readpci = TRUE;
4153			      break;
4154	     case SIS_315PRO: mypciid = PCI_CHIP_SIS315PRO;
4155			      readpci = TRUE;
4156			      break;
4157	     case SIS_300:
4158	     case SIS_315H:
4159	     case SIS_330:
4160	     case SIS_340:
4161	     case SIS_650:
4162	     case SIS_760:
4163	     case XGI_40:     readpci = TRUE;
4164			      break;
4165	     case XGI_20:     readpci = TRUE;
4166			      biossize = 0x8000;
4167			      break;
4168	     }
4169#if XSERVER_LIBPCIACCESS
4170	     if(readpci) {
4171		pSiS->PciInfo->rom_size = biossize;
4172		pci_device_read_rom(pSiS->PciInfo, pSiS->BIOS);
4173		if(SISCheckBIOS(pSiS, mypciid, mypcivendor, biossize)) {
4174		   found = TRUE;
4175		}
4176	     }
4177#else
4178	     if(readpci) {
4179		xf86ReadPciBIOS(0, pSiS->PciTag, 0, pSiS->BIOS, biossize);
4180		if(SISCheckBIOS(pSiS, mypciid, mypcivendor, biossize)) {
4181		   found = TRUE;
4182		}
4183	     }
4184
4185	     if(!found) {
4186	        ULong  segstart;
4187		for(segstart = BIOS_BASE; segstart < 0x000f0000; segstart += 0x00001000) {
4188
4189#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,99,0,0)
4190		   if(xf86ReadBIOS(segstart, 0, pSiS->BIOS, biossize) != biossize) continue;
4191#else
4192		   if(xf86ReadDomainMemory(pSiS->PciTag, segstart, biossize, pSiS->BIOS) != biossize) continue;
4193#endif
4194
4195		   if(!SISCheckBIOS(pSiS, mypciid, mypcivendor, biossize)) continue;
4196
4197		   found = TRUE;
4198		   break;
4199		}
4200             }
4201#endif
4202	     if(found) {
4203		UShort romptr = pSiS->BIOS[0x16] | (pSiS->BIOS[0x17] << 8);
4204		pSiS->SiS_Pr->VirtualRomBase = pSiS->BIOS;
4205		if(pSiS->ChipFlags & SiSCF_IsXGI) {
4206		   pSiS->HaveXGIBIOS = pSiS->SiS_Pr->SiS_XGIROM = TRUE;
4207		   pSiS->SiS_Pr->UseROM = FALSE;
4208		   if(pSiS->ChipFlags & SiSCF_IsXGIV3) {
4209		      if(!(pSiS->BIOS[0x1d1] & 0x01)) {
4210			 pSiS->SiS_Pr->DDCPortMixup = TRUE;
4211		      }
4212	           }
4213	        } else {
4214		   pSiS->ROM661New = SiSDetermineROMLayout661(pSiS->SiS_Pr);
4215		}
4216		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4217			"Video BIOS version \"%7s\" found (%s data layout)\n",
4218			&pSiS->BIOS[romptr], pSiS->ROM661New ? "new SiS" :
4219				(pSiS->HaveXGIBIOS ? "XGI" : "old SiS"));
4220		if(pSiS->SiS_Pr->DDCPortMixup) {
4221		   xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
4222			"*** Buggy XGI V3XT card detected: If VGA and DVI are connected at the\n");
4223		   xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
4224			"*** same time, BIOS and driver will be unable to detect DVI connection.\n");
4225		}
4226#ifdef SISDUALHEAD
4227		if(pSiSEnt) {
4228		   pSiSEnt->BIOS = pSiS->BIOS;
4229		   pSiSEnt->ROM661New = pSiS->ROM661New;
4230		   pSiSEnt->HaveXGIBIOS = pSiS->HaveXGIBIOS;
4231		}
4232#endif
4233	     } else {
4234	        xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
4235			 "Could not find/read video BIOS\n");
4236		free(pSiS->BIOS);
4237		pSiS->BIOS = NULL;
4238	     }
4239          }
4240       }
4241
4242       if(!(pSiS->ChipFlags & SiSCF_IsXGI)) {
4243          if(pSiS->BIOS) pSiS->SiS_Pr->UseROM = TRUE;
4244          else           pSiS->SiS_Pr->UseROM = FALSE;
4245       }
4246    }
4247
4248    /* Evaluate options */
4249    SiSOptions(pScrn);
4250
4251#ifdef SISMERGED
4252    /* Due to palette & timing problems we don't support 8bpp in MFBM */
4253    if((pSiS->MergedFB) && (pScrn->bitsPerPixel <= 8)) {
4254       SISErrorLog(pScrn, "MergedFB: Color depth %d not supported, %s\n",
4255			pScrn->bitsPerPixel, mergeddisstr);
4256       pSiS->MergedFB = pSiS->MergedFBAuto = FALSE;
4257    }
4258#endif
4259
4260    /* Probe CPU features */
4261#ifdef SISDUALHEAD
4262    if(pSiS->DualHeadMode) {
4263       pSiS->CPUFlags = pSiSEnt->CPUFlags;
4264    }
4265#endif
4266    if(!pSiS->CPUFlags) {
4267       pSiS->CPUFlags = SiSGetCPUFlags(pScrn);
4268       pSiS->CPUFlags |= SIS_CPUFL_FLAG;
4269#ifdef SISDUALHEAD
4270       if(pSiS->DualHeadMode) pSiSEnt->CPUFlags = pSiS->CPUFlags;
4271#endif
4272    }
4273
4274    /* We use a programamble clock */
4275    pScrn->progClock = TRUE;
4276
4277    /* Set the bits per RGB for 8bpp mode */
4278    if(pScrn->depth == 8) pScrn->rgbBits = 8;
4279
4280#ifdef SISDUALHEAD
4281    if(pSiS->DualHeadMode) {
4282       if(!pSiS->SecondHead) {
4283	  /* Copy some option settings to entity private */
4284	  pSiSEnt->HWCursor = pSiS->HWCursor;
4285	  pSiSEnt->NoAccel = pSiS->NoAccel;
4286	  pSiSEnt->useEXA = pSiS->useEXA;
4287	  pSiSEnt->restorebyset = pSiS->restorebyset;
4288	  pSiSEnt->OptROMUsage = pSiS->OptROMUsage;
4289	  pSiSEnt->OptUseOEM = pSiS->OptUseOEM;
4290	  pSiSEnt->TurboQueue = pSiS->TurboQueue;
4291	  pSiSEnt->forceCRT1 = pSiS->forceCRT1;
4292	  pSiSEnt->ForceCRT1Type = pSiS->ForceCRT1Type;
4293	  pSiSEnt->CRT1TypeForced = pSiS->CRT1TypeForced;
4294	  pSiSEnt->ForceCRT2Type = pSiS->ForceCRT2Type;
4295	  pSiSEnt->ForceTVType = pSiS->ForceTVType;
4296	  pSiSEnt->ForceYPbPrType = pSiS->ForceYPbPrType;
4297	  pSiSEnt->ForceYPbPrAR = pSiS->ForceYPbPrAR;
4298	  pSiSEnt->UsePanelScaler = pSiS->UsePanelScaler;
4299	  pSiSEnt->CenterLCD = pSiS->CenterLCD;
4300	  pSiSEnt->DSTN = pSiS->DSTN;
4301	  pSiSEnt->FSTN = pSiS->FSTN;
4302	  pSiSEnt->OptTVStand = pSiS->OptTVStand;
4303	  pSiSEnt->NonDefaultPAL = pSiS->NonDefaultPAL;
4304	  pSiSEnt->NonDefaultNTSC = pSiS->NonDefaultNTSC;
4305	  pSiSEnt->chtvtype = pSiS->chtvtype;
4306	  pSiSEnt->OptTVOver = pSiS->OptTVOver;
4307	  pSiSEnt->OptTVSOver = pSiS->OptTVSOver;
4308	  pSiSEnt->chtvlumabandwidthcvbs = pSiS->chtvlumabandwidthcvbs;
4309	  pSiSEnt->chtvlumabandwidthsvideo = pSiS->chtvlumabandwidthsvideo;
4310	  pSiSEnt->chtvlumaflickerfilter = pSiS->chtvlumaflickerfilter;
4311	  pSiSEnt->chtvchromabandwidth = pSiS->chtvchromabandwidth;
4312	  pSiSEnt->chtvchromaflickerfilter = pSiS->chtvchromaflickerfilter;
4313	  pSiSEnt->chtvtextenhance = pSiS->chtvtextenhance;
4314	  pSiSEnt->chtvcontrast = pSiS->chtvcontrast;
4315	  pSiSEnt->chtvcvbscolor = pSiS->chtvcvbscolor;
4316	  pSiSEnt->sistvedgeenhance = pSiS->sistvedgeenhance;
4317	  pSiSEnt->sistvantiflicker = pSiS->sistvantiflicker;
4318	  pSiSEnt->sistvsaturation = pSiS->sistvsaturation;
4319	  pSiSEnt->sistvcfilter = pSiS->sistvcfilter;
4320	  pSiSEnt->sistvyfilter = pSiS->sistvyfilter;
4321	  pSiSEnt->sistvcolcalibc = pSiS->sistvcolcalibc;
4322	  pSiSEnt->sistvcolcalibf = pSiS->sistvcolcalibf;
4323	  pSiSEnt->tvxpos = pSiS->tvxpos;
4324	  pSiSEnt->tvypos = pSiS->tvypos;
4325	  pSiSEnt->tvxscale = pSiS->tvxscale;
4326	  pSiSEnt->tvyscale = pSiS->tvyscale;
4327	  pSiSEnt->siscrt1satgain = pSiS->siscrt1satgain;
4328	  pSiSEnt->crt1satgaingiven = pSiS->crt1satgaingiven;
4329	  pSiSEnt->CRT1gamma = pSiS->CRT1gamma;
4330	  pSiSEnt->CRT1gammaGiven = pSiS->CRT1gammaGiven;
4331	  pSiSEnt->XvGammaRed = pSiS->XvGammaRed;
4332	  pSiSEnt->XvGammaGreen = pSiS->XvGammaGreen;
4333	  pSiSEnt->XvGammaBlue = pSiS->XvGammaBlue;
4334	  pSiSEnt->XvGamma = pSiS->XvGamma;
4335	  pSiSEnt->XvGammaGiven = pSiS->XvGammaGiven;
4336	  pSiSEnt->CRT2gamma = pSiS->CRT2gamma;
4337	  pSiSEnt->XvOnCRT2 = pSiS->XvOnCRT2;
4338	  pSiSEnt->AllowHotkey = pSiS->AllowHotkey;
4339	  pSiSEnt->enablesisctrl = pSiS->enablesisctrl;
4340	  pSiSEnt->SenseYPbPr = pSiS->SenseYPbPr;
4341	  pSiSEnt->XvUseMemcpy = pSiS->XvUseMemcpy;
4342	  pSiSEnt->BenchMemCpy = pSiS->BenchMemCpy;
4343#ifdef SIS_CP
4344	  SIS_CP_DRIVER_COPYOPTIONSENT
4345#endif
4346       } else {
4347	  /* We always use same cursor type on both screens */
4348	  pSiS->HWCursor = pSiSEnt->HWCursor;
4349	  /* We need identical NoAccel setting */
4350	  pSiS->NoAccel = pSiSEnt->NoAccel;
4351	  pSiS->useEXA = pSiSEnt->useEXA;
4352	  pSiS->TurboQueue = pSiSEnt->TurboQueue;
4353	  pSiS->restorebyset = pSiSEnt->restorebyset;
4354	  pSiS->AllowHotkey = pSiS->AllowHotkey;
4355	  pSiS->OptROMUsage = pSiSEnt->OptROMUsage;
4356	  pSiS->OptUseOEM = pSiSEnt->OptUseOEM;
4357	  pSiS->forceCRT1 = pSiSEnt->forceCRT1;
4358	  pSiS->nocrt2ddcdetection = FALSE;
4359	  pSiS->forcecrt2redetection = FALSE;
4360	  pSiS->ForceCRT1Type = pSiSEnt->ForceCRT1Type;
4361	  pSiS->ForceCRT2Type = pSiSEnt->ForceCRT2Type;
4362	  pSiS->CRT1TypeForced = pSiSEnt->CRT1TypeForced;
4363	  pSiS->UsePanelScaler = pSiSEnt->UsePanelScaler;
4364	  pSiS->CenterLCD = pSiSEnt->CenterLCD;
4365	  pSiS->DSTN = pSiSEnt->DSTN;
4366	  pSiS->FSTN = pSiSEnt->FSTN;
4367	  pSiS->OptTVStand = pSiSEnt->OptTVStand;
4368	  pSiS->NonDefaultPAL = pSiSEnt->NonDefaultPAL;
4369	  pSiS->NonDefaultNTSC = pSiSEnt->NonDefaultNTSC;
4370	  pSiS->chtvtype = pSiSEnt->chtvtype;
4371	  pSiS->ForceTVType = pSiSEnt->ForceTVType;
4372	  pSiS->ForceYPbPrType = pSiSEnt->ForceYPbPrType;
4373	  pSiS->ForceYPbPrAR = pSiSEnt->ForceYPbPrAR;
4374	  pSiS->OptTVOver = pSiSEnt->OptTVOver;
4375	  pSiS->OptTVSOver = pSiSEnt->OptTVSOver;
4376	  pSiS->chtvlumabandwidthcvbs = pSiSEnt->chtvlumabandwidthcvbs;
4377	  pSiS->chtvlumabandwidthsvideo = pSiSEnt->chtvlumabandwidthsvideo;
4378	  pSiS->chtvlumaflickerfilter = pSiSEnt->chtvlumaflickerfilter;
4379	  pSiS->chtvchromabandwidth = pSiSEnt->chtvchromabandwidth;
4380	  pSiS->chtvchromaflickerfilter = pSiSEnt->chtvchromaflickerfilter;
4381	  pSiS->chtvcvbscolor = pSiSEnt->chtvcvbscolor;
4382	  pSiS->chtvtextenhance = pSiSEnt->chtvtextenhance;
4383	  pSiS->chtvcontrast = pSiSEnt->chtvcontrast;
4384	  pSiS->sistvedgeenhance = pSiSEnt->sistvedgeenhance;
4385	  pSiS->sistvantiflicker = pSiSEnt->sistvantiflicker;
4386	  pSiS->sistvsaturation = pSiSEnt->sistvsaturation;
4387	  pSiS->sistvcfilter = pSiSEnt->sistvcfilter;
4388	  pSiS->sistvyfilter = pSiSEnt->sistvyfilter;
4389	  pSiS->sistvcolcalibc = pSiSEnt->sistvcolcalibc;
4390	  pSiS->sistvcolcalibf = pSiSEnt->sistvcolcalibf;
4391	  pSiS->tvxpos = pSiSEnt->tvxpos;
4392	  pSiS->tvypos = pSiSEnt->tvypos;
4393	  pSiS->tvxscale = pSiSEnt->tvxscale;
4394	  pSiS->tvyscale = pSiSEnt->tvyscale;
4395	  pSiS->SenseYPbPr = pSiSEnt->SenseYPbPr;
4396	  if(!pSiS->CRT1gammaGiven) {
4397	     if(pSiSEnt->CRT1gammaGiven)
4398	        pSiS->CRT1gamma = pSiSEnt->CRT1gamma;
4399	  }
4400	  pSiS->CRT2gamma = pSiSEnt->CRT2gamma;
4401	  if(!pSiS->XvGammaGiven) {
4402	     if(pSiSEnt->XvGammaGiven) {
4403		pSiS->XvGamma = pSiSEnt->XvGamma;
4404		pSiS->XvGammaRed = pSiS->XvGammaRedDef = pSiSEnt->XvGammaRed;
4405		pSiS->XvGammaGreen = pSiS->XvGammaGreenDef = pSiSEnt->XvGammaGreen;
4406		pSiS->XvGammaBlue = pSiS->XvGammaBlueDef = pSiSEnt->XvGammaBlue;
4407	     }
4408	  }
4409	  if(!pSiS->crt1satgaingiven) {
4410	     if(pSiSEnt->crt1satgaingiven)
4411	        pSiS->siscrt1satgain = pSiSEnt->siscrt1satgain;
4412	  }
4413	  pSiS->XvOnCRT2 = pSiSEnt->XvOnCRT2;
4414	  pSiS->enablesisctrl = pSiSEnt->enablesisctrl;
4415	  pSiS->XvUseMemcpy = pSiSEnt->XvUseMemcpy;
4416	  pSiS->BenchMemCpy = pSiSEnt->BenchMemCpy;
4417	  /* Copy gamma brightness to Ent (sic!) for Xinerama */
4418	  pSiSEnt->GammaBriR = pSiS->GammaBriR;
4419	  pSiSEnt->GammaBriG = pSiS->GammaBriG;
4420	  pSiSEnt->GammaBriB = pSiS->GammaBriB;
4421	  pSiSEnt->NewGammaBriR = pSiS->NewGammaBriR;
4422	  pSiSEnt->NewGammaBriG = pSiS->NewGammaBriG;
4423	  pSiSEnt->NewGammaBriB = pSiS->NewGammaBriB;
4424	  pSiSEnt->NewGammaConR = pSiS->NewGammaConR;
4425	  pSiSEnt->NewGammaConG = pSiS->NewGammaConG;
4426	  pSiSEnt->NewGammaConB = pSiS->NewGammaConB;
4427#ifdef SIS_CP
4428	  SIS_CP_DRIVER_COPYOPTIONS
4429#endif
4430       }
4431    }
4432#endif
4433
4434    /* Handle UseROMData, NoOEM and UsePanelScaler options */
4435    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
4436       from = X_PROBED;
4437       if(pSiS->OptROMUsage == 0) {
4438	  pSiS->SiS_Pr->UseROM = FALSE;
4439	  from = X_CONFIG;
4440	  xf86DrvMsg(pScrn->scrnIndex, from, "Video ROM data usage is disabled\n");
4441       }
4442
4443       if(!pSiS->OptUseOEM) {
4444	  xf86DrvMsg(pScrn->scrnIndex, from, "Internal OEM LCD/TV/VGA2 data usage is disabled\n");
4445       }
4446
4447       pSiS->SiS_Pr->UsePanelScaler = pSiS->UsePanelScaler;
4448       pSiS->SiS_Pr->CenterScreen = pSiS->CenterLCD;
4449    }
4450
4451    /* Do some HW configuration detection (memory amount & type, clock, etc) */
4452    SiSSetup(pScrn);
4453
4454    /* Get framebuffer address */
4455    if(pSiS->pEnt->device->MemBase != 0) {
4456       /*
4457	* XXX Should check that the config file value matches one of the
4458	* PCI base address values.
4459	*/
4460       pSiS->FbAddress = pSiS->pEnt->device->MemBase;
4461       from = X_CONFIG;
4462    } else {
4463       pSiS->FbAddress = PCI_REGION_BASE(pSiS->PciInfo, 0, REGION_MEM) & 0xFFFFFFF0;
4464       from = X_PROBED;
4465    }
4466
4467#ifdef SISDUALHEAD
4468    if(pSiS->DualHeadMode)
4469       xf86DrvMsg(pScrn->scrnIndex, from, "Global linear framebuffer at 0x%lX\n",
4470	   (ULong)pSiS->FbAddress);
4471    else
4472#endif
4473       xf86DrvMsg(pScrn->scrnIndex, from, "Linear framebuffer at 0x%lX\n",
4474	   (ULong)pSiS->FbAddress);
4475
4476    pSiS->realFbAddress = pSiS->FbAddress;
4477
4478    /* Get MMIO address */
4479    if(pSiS->pEnt->device->IOBase != 0) {
4480       /*
4481	* XXX Should check that the config file value matches one of the
4482	* PCI base address values.
4483	*/
4484       pSiS->IOAddress = pSiS->pEnt->device->IOBase;
4485       from = X_CONFIG;
4486    } else {
4487       pSiS->IOAddress = PCI_REGION_BASE(pSiS->PciInfo, 1, REGION_MEM) & 0xFFFFFFF0;
4488       from = X_PROBED;
4489    }
4490    xf86DrvMsg(pScrn->scrnIndex, from, "MMIO registers at 0x%lX (size %ldK)\n",
4491	   (ULong)pSiS->IOAddress, pSiS->mmioSize);
4492
4493#ifndef XSERVER_LIBPCIACCESS
4494    /* Register the PCI-assigned resources */
4495    if(xf86RegisterResources(pSiS->pEnt->index, NULL, ResExclusive)) {
4496       SISErrorLog(pScrn, "PCI resource conflicts detected\n");
4497#ifdef SISDUALHEAD
4498       if(pSiSEnt) pSiSEnt->ErrorAfterFirst = TRUE;
4499#endif
4500       sisRestoreExtRegisterLock(pSiS,srlockReg,crlockReg);
4501       if(pSiS->pInt) xf86FreeInt10(pSiS->pInt);
4502       SISFreeRec(pScrn);
4503       return FALSE;
4504    }
4505#endif
4506
4507    from = X_PROBED;
4508    if(pSiS->pEnt->device->videoRam != 0) {
4509       if(pSiS->Chipset == PCI_CHIP_SIS6326) {
4510	  pScrn->videoRam = pSiS->pEnt->device->videoRam;
4511	  from = X_CONFIG;
4512       } else {
4513	  xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
4514		"Option \"VideoRAM\" ignored\n");
4515       }
4516    }
4517
4518    pSiS->RealVideoRam = pScrn->videoRam;
4519
4520    if((pSiS->Chipset == PCI_CHIP_SIS6326) &&
4521       (pScrn->videoRam > 4096)            &&
4522       (from != X_CONFIG)) {
4523       pScrn->videoRam = 4096;
4524       xf86DrvMsg(pScrn->scrnIndex, from,
4525	   "SiS6326: Detected %d KB VideoRAM, limiting to %d KB\n",
4526	   pSiS->RealVideoRam, pScrn->videoRam);
4527    } else {
4528       xf86DrvMsg(pScrn->scrnIndex, from, "VideoRAM: %d KB\n", pScrn->videoRam);
4529    }
4530
4531    if((pSiS->Chipset == PCI_CHIP_SIS6326) &&
4532       (pScrn->videoRam > 4096)) {
4533       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
4534	   "SiS6326 engines do not support more than 4096KB RAM, therefore\n");
4535       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
4536	   "TurboQueue, HWCursor, 2D acceleration and XVideo are disabled.\n");
4537       pSiS->TurboQueue = FALSE;
4538       pSiS->HWCursor   = FALSE;
4539       pSiS->NoXvideo   = TRUE;
4540       pSiS->NoAccel    = TRUE;
4541    }
4542
4543    pSiS->FbMapSize = pSiS->availMem = pScrn->videoRam * 1024;
4544
4545    /* Calculate real availMem according to Accel/TurboQueue and
4546     * HWCursur setting. Also, initialize some variables used
4547     * in other modules.
4548     */
4549    pSiS->cursorOffset = 0;
4550    pSiS->CurARGBDest = NULL;
4551    pSiS->CurMonoSrc = NULL;
4552    pSiS->CurFGCol = pSiS->CurBGCol = 0;
4553    pSiS->FbBaseOffset = 0;
4554
4555    switch(pSiS->VGAEngine) {
4556
4557      case SIS_300_VGA:
4558	pSiS->TurboQueueLen = 512;
4559	if(pSiS->TurboQueue) {
4560	   pSiS->availMem -= (pSiS->TurboQueueLen*1024);
4561	   pSiS->cursorOffset = 512;
4562	}
4563	if(pSiS->HWCursor) {
4564	   pSiS->availMem -= pSiS->CursorSize;
4565	   if(pSiS->OptUseColorCursor) pSiS->availMem -= pSiS->CursorSize;
4566	}
4567	pSiS->CmdQueLenMask = 0xFFFF;
4568	pSiS->CmdQueLenFix  = 0;
4569	pSiS->cursorBufferNum = 0;
4570#ifdef SISDUALHEAD
4571	if(pSiSEnt) pSiSEnt->cursorBufferNum = 0;
4572#endif
4573	break;
4574
4575      case SIS_315_VGA:
4576#ifdef SISVRAMQ		/* VRAM queue */
4577	pSiS->cmdQueueSizeMask = pSiS->cmdQueueSize - 1;	/* VRAM Command Queue is variable (in therory) */
4578	pSiS->cmdQueueOffset = (pScrn->videoRam * 1024) - pSiS->cmdQueueSize;
4579	pSiS->cmdQueueLen = 0;
4580	pSiS->cmdQueueSize_div2 = pSiS->cmdQueueSize / 2;
4581	pSiS->cmdQueueSize_div4 = pSiS->cmdQueueSize / 4;
4582	pSiS->cmdQueueSize_4_3 = (pSiS->cmdQueueSize / 4) * 3;
4583	pSiS->availMem -= pSiS->cmdQueueSize;
4584	pSiS->cursorOffset = (pSiS->cmdQueueSize / 1024);
4585
4586	/* Set up shared pointer to current offset */
4587#ifdef SISDUALHEAD
4588	if(pSiS->DualHeadMode)
4589	   pSiS->cmdQ_SharedWritePort = &(pSiSEnt->cmdQ_SharedWritePort_2D);
4590	else
4591#endif
4592	   pSiS->cmdQ_SharedWritePort = &(pSiS->cmdQ_SharedWritePort_2D);
4593
4594
4595#else			/* MMIO */
4596	if(pSiS->TurboQueue) {
4597	   pSiS->availMem -= (512*1024);			/* MMIO Command Queue is 512k (variable in theory) */
4598	   pSiS->cursorOffset = 512;
4599	}
4600#endif
4601	if(pSiS->HWCursor) {
4602	   pSiS->availMem -= (pSiS->CursorSize * 2);
4603	   if(pSiS->OptUseColorCursor) pSiS->availMem -= (pSiS->CursorSize * 2);
4604	}
4605	pSiS->cursorBufferNum = 0;
4606#ifdef SISDUALHEAD
4607	if(pSiSEnt) pSiSEnt->cursorBufferNum = 0;
4608#endif
4609
4610	if((pSiS->SiS76xLFBSize) && (pSiS->SiS76xUMASize)) {
4611	   pSiS->availMem -= pSiS->SiS76xUMASize;
4612	   pSiS->FbBaseOffset = pSiS->SiS76xUMASize;
4613	}
4614
4615	break;
4616
4617      default:
4618	/* cursorOffset not used in cursor functions for 530 and
4619	 * older chips, because the cursor is *above* the TQ.
4620	 * On 5597 and older revisions of the 6326, the TQ is
4621	 * max 32K, on newer 6326 revisions and the 530 either 30
4622	 * (or 32?) or 62K (or 64?). However, to make sure, we
4623	 * use only 30K (or 32?), but reduce the available memory
4624	 * by 64, and locate the TQ at the beginning of this last
4625	 * 64K block. (We do this that way even when using the
4626	 * HWCursor, because the cursor only takes 2K and the
4627	 * queue does not seem to last that far anyway.)
4628	 * The TQ must be located at 32KB boundaries.
4629	 */
4630	if(pSiS->RealVideoRam < 3072) {
4631	   if(pSiS->TurboQueue) {
4632	      xf86DrvMsg(pScrn->scrnIndex, X_INFO,
4633		    "Not enough video RAM for TurboQueue. TurboQueue disabled\n");
4634	      pSiS->TurboQueue = FALSE;
4635	   }
4636	}
4637	pSiS->CmdQueMaxLen = 32;
4638	if(pSiS->TurboQueue) {
4639			      pSiS->availMem -= (64*1024);
4640			      pSiS->CmdQueMaxLen = 900;   /* To make sure; should be 992 */
4641	} else if(pSiS->HWCursor) {
4642			      pSiS->availMem -= pSiS->CursorSize;
4643	}
4644	if(pSiS->Chipset == PCI_CHIP_SIS530) {
4645		/* Check if Flat Panel is enabled */
4646		inSISIDXREG(SISSR, 0x0e, tempreg);
4647		if(!(tempreg & 0x04)) pSiS->availMem -= pSiS->CursorSize;
4648
4649		/* Set up mask for MMIO register */
4650		pSiS->CmdQueLenMask = (pSiS->TurboQueue) ? 0x1FFF : 0x00FF;
4651	} else {
4652	        /* TQ is never used on 6326/5597, because the accelerator
4653		 * always Syncs. So this is just cosmentic work. (And I
4654		 * am not even sure that 0x7fff is correct. MMIO 0x83a8
4655		 * holds 0xec0 if (30k) TQ is enabled, 0x20 if TQ disabled.
4656		 * The datasheet has no real explanation on the queue length
4657		 * if the TQ is enabled. Not syncing and waiting for a
4658		 * suitable queue length instead does not work.
4659		 */
4660	        pSiS->CmdQueLenMask = (pSiS->TurboQueue) ? 0x7FFF : 0x003F;
4661	}
4662
4663	/* This is to be subtracted from MMIO queue length register contents
4664	 * for getting the real Queue length.
4665	 */
4666	pSiS->CmdQueLenFix  = (pSiS->TurboQueue) ? 32 : 0;
4667    }
4668
4669
4670#ifdef SISDUALHEAD
4671    /* In dual head mode, we share availMem equally - so align it
4672     * to 8KB; this way, the address of the FB of the second
4673     * head is aligned to 4KB for mapping.
4674     */
4675   if(pSiS->DualHeadMode) pSiS->availMem &= 0xFFFFE000;
4676#endif
4677
4678    /* Check MaxXFBMem setting */
4679#ifdef SISDUALHEAD
4680    if(pSiS->DualHeadMode) {
4681        /* 1. Since DRI is not supported in dual head mode, we
4682	 *    don't need the MaxXFBMem setting - ignore it.
4683	 */
4684	if(pSiS->maxxfbmem) {
4685	   xf86DrvMsg(pScrn->scrnIndex, X_INFO,
4686		"MaxXFBMem ignored in Dual Head mode\n");
4687	}
4688	pSiS->maxxfbmem = pSiS->availMem;
4689    } else
4690#endif
4691	   if((pSiS->sisfbHeapStart) || (pSiS->sisfbHaveNewHeapDef)) {
4692
4693       /*
4694	* 2. We have memory layout info from sisfb - ignore MaxXFBMem
4695	*/
4696	if(pSiS->maxxfbmem) {
4697	   xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
4698		"Got memory layout info from sisfb, ignoring MaxXFBMem option\n");
4699	}
4700	if((pSiS->FbBaseOffset) && (!pSiS->sisfbHaveNewHeapDef)) {
4701	   xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
4702		"Incompatible sisfb version detected, DRI disabled\n");
4703	   pSiS->loadDRI = FALSE;
4704	   pSiS->maxxfbmem = pSiS->availMem;
4705	} else {
4706	   if(pSiS->FbBaseOffset) {
4707	      /* Revert our changes to FbBaseOffset and availMem; use sisfb's info */
4708	      pSiS->availMem += pSiS->FbBaseOffset;
4709	      pSiS->FbBaseOffset = 0;
4710	   }
4711	   if(pSiS->sisfbVideoOffset) {
4712	      /* a. DRI heap BELOW framebuffer */
4713	      pSiS->FbBaseOffset = pSiS->sisfbVideoOffset;
4714	      pSiS->availMem -= pSiS->FbBaseOffset;
4715	      pSiS->maxxfbmem = pSiS->availMem;
4716	   } else {
4717	      /* b. DRI heap ABOVE framebuffer (traditional layout) */
4718	      if(pSiS->availMem < (pSiS->sisfbHeapStart * 1024)) {
4719		 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
4720			"Internal error - sisfb memory layout corrupt\n");
4721		 pSiS->loadDRI = FALSE;
4722		 pSiS->maxxfbmem = pSiS->availMem;
4723	      } else {
4724	         pSiS->maxxfbmem = pSiS->sisfbHeapStart * 1024;
4725	      }
4726	   }
4727	}
4728
4729    } else if(pSiS->maxxfbmem) {
4730
4731       /*
4732	* 3. No sisfb, but user gave "MaxXFBMem"
4733	*/
4734	if(pSiS->FbBaseOffset) {
4735	   /* a. DRI heap BELOW framebuffer */
4736	   if(pSiS->maxxfbmem > (pSiS->availMem + pSiS->FbBaseOffset - pSiS->SiS76xUMASize)) {
4737	      xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
4738			"Invalid MaxXFBMem setting\n");
4739	      pSiS->maxxfbmem = pSiS->availMem;
4740	   } else {
4741	      /* Revert our changes */
4742	      pSiS->availMem += pSiS->FbBaseOffset;
4743	      /* Use user's MaxXFBMem setting */
4744	      pSiS->FbBaseOffset = pSiS->availMem - pSiS->maxxfbmem;
4745	      pSiS->availMem -= pSiS->FbBaseOffset;
4746	   }
4747	} else {
4748	   /* b. DRI heap ABOVE framebuffer (traditional layout) */
4749	   if(pSiS->maxxfbmem > pSiS->availMem) {
4750	      xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
4751			 "Invalid MaxXFBMem setting.\n");
4752	      pSiS->maxxfbmem = pSiS->availMem;
4753	   }
4754	}
4755
4756    } else {
4757
4758       /*
4759	* 4. No MaxXFBMem, no sisfb: Use all memory
4760	*/
4761	pSiS->maxxfbmem = pSiS->availMem;
4762
4763	/* ... except on chipsets, for which DRI is
4764	 * supported: If DRI is enabled, we now limit
4765	 * ourselves to a reasonable default:
4766	 */
4767
4768	if(pSiS->loadDRI) {
4769	   if(pSiS->FbBaseOffset) {
4770	      /* a. DRI heap BELOW framebuffer */
4771	      /* See how much UMA and LFB memory we have,
4772	       * and calculate a reasonable default. We
4773	       * use more vram for ourselves because these
4774	       * chips are eg. capable of larger Xv
4775	       * overlays, etc.
4776	       */
4777	      unsigned long total = (pSiS->SiS76xLFBSize + pSiS->SiS76xUMASize) / 1024;
4778	      unsigned long mymax;
4779	      if(total <= 16384)			/* <= 16MB: Use 8MB for X */
4780	         mymax = 8192 * 1024;
4781	      else if(total <= 32768)			/* <= 32MB: Use 16MB for X */
4782	         mymax = 16384 * 1024;
4783	      else					/* Otherwise: Use 20MB for X */
4784	         mymax = 20 * 1024 * 1024;
4785	      /* availMem is right now adjusted to not use the UMA
4786	       * area. Make sure that our default doesn't reach
4787	       * into the UMA area either.
4788	       */
4789	      if(pSiS->availMem > mymax) {
4790		 /* Write our default to maxxfbmem */
4791		 pSiS->maxxfbmem = mymax;
4792		 /* Revert our changes to availMem */
4793		 pSiS->availMem += pSiS->FbBaseOffset;
4794		 /* Use our default setting */
4795		 pSiS->FbBaseOffset = pSiS->availMem - pSiS->maxxfbmem;
4796		 pSiS->availMem -= pSiS->FbBaseOffset;
4797	      }
4798	   } else {
4799	      /* b. DRI heap ABOVE framebuffer (traditional layout) */
4800	      /* See how much video memory we have, and calculate
4801	       * a reasonable default.
4802	       * Since DRI is pointless with less than 4MB of total
4803	       * video RAM, we disable it in that case.
4804	       */
4805	      if(pScrn->videoRam <= 4096)
4806	         pSiS->loadDRI = FALSE;
4807	      else if(pScrn->videoRam <= 8192)		/* <= 8MB: Use 4MB for X */
4808	         pSiS->maxxfbmem = 4096 * 1024;
4809	      else if(pScrn->videoRam <= 16384)		/* <= 16MB: Use 8MB for X */
4810	         pSiS->maxxfbmem = 8192 * 1024;
4811#ifdef SISMERGED					/* Otherwise: --- */
4812	      else if(pSiS->MergedFB) {
4813	         if(pScrn->videoRam <= 65536)
4814	            pSiS->maxxfbmem = 16384 * 1024;	/* If MergedFB and <=64MB, use 16MB for X */
4815		 else
4816		    pSiS->maxxfbmem = 20 * 1024 * 1024;	/* If MergedFB and > 64MB, use 20MB for X */
4817	      }
4818#endif
4819	        else if(pSiS->VGAEngine == SIS_315_VGA) {
4820	         if(pScrn->videoRam <= 65536)
4821	            pSiS->maxxfbmem = 16384 * 1024;	/* On >=315 series and <=64MB, use 16MB */
4822		 else
4823		    pSiS->maxxfbmem = 20 * 1024 * 1024;	/* On >=315 series and > 64MB, use 20MB */
4824	      } else
4825	         pSiS->maxxfbmem = 12288 * 1024;	/* On <315 series, use 12MB */
4826
4827	      /* A final check */
4828	      if(pSiS->maxxfbmem > pSiS->availMem) {
4829		 pSiS->maxxfbmem = pSiS->availMem;
4830		 pSiS->loadDRI = FALSE;
4831	      }
4832	   }
4833
4834	}
4835    }
4836
4837    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using %dK of framebuffer memory at offset %dK\n",
4838				pSiS->maxxfbmem / 1024, pSiS->FbBaseOffset / 1024);
4839
4840    /* Find out about sub-classes of some chipsets and check
4841     * if the chipset supports two video overlays
4842     */
4843    if(pSiS->VGAEngine == SIS_300_VGA    ||
4844       pSiS->VGAEngine == SIS_315_VGA    ||
4845       pSiS->Chipset == PCI_CHIP_SIS530  ||
4846       pSiS->Chipset == PCI_CHIP_SIS6326 ||
4847       pSiS->Chipset == PCI_CHIP_SIS5597)  {
4848       pSiS->hasTwoOverlays = FALSE;
4849       switch(pSiS->Chipset) {
4850	 case PCI_CHIP_SIS300:
4851	 case PCI_CHIP_SIS540:  /* ? (If not, need to add the SwitchCRT Xv attribute!) */
4852	 case PCI_CHIP_SIS630:
4853	 case PCI_CHIP_SIS550:
4854	   pSiS->hasTwoOverlays = TRUE;
4855	   pSiS->SiS_SD_Flags |= SiS_SD_SUPPORT2OVL;
4856	   break;
4857	 case PCI_CHIP_SIS315PRO:
4858	   pSiS->ChipFlags |= SiSCF_LARGEOVERLAY;
4859	   break;
4860	 case PCI_CHIP_SIS330:
4861	   pSiS->ChipFlags |= (SiSCF_CRT2HWCKaputt | SiSCF_LARGEOVERLAY);
4862	   break;
4863	 case PCI_CHIP_SIS340:
4864	 case PCI_CHIP_XGIXG40: /* Verified: only 1 overlay */
4865	   pSiS->ChipFlags |= SiSCF_LARGEOVERLAY;
4866	   break;
4867	 case PCI_CHIP_SIS650:
4868	   {
4869	     UChar tempreg1, tempreg2;
4870	     static const char *id650str[] = {
4871		"650",       "650",       "650",       "650",
4872		"650 A0 AA", "650 A2 CA", "650",       "650",
4873		"M650 A0",   "M650 A1 AA","651 A0 AA", "651 A1 AA",
4874		"M650",      "65?",       "651",       "65?"
4875	     };
4876	     pSiS->ChipFlags |= SiSCF_LARGEOVERLAY;
4877	     if(pSiS->ChipType == SIS_650) {
4878		inSISIDXREG(SISCR, 0x5f, CR5F);
4879		CR5F &= 0xf0;
4880		andSISIDXREG(SISCR, 0x5c, 0x07);
4881		inSISIDXREG(SISCR, 0x5c, tempreg1);
4882		tempreg1 &= 0xf8;
4883		orSISIDXREG(SISCR, 0x5c, 0xf8);
4884		inSISIDXREG(SISCR, 0x5c, tempreg2);
4885		tempreg2 &= 0xf8;
4886		if((!tempreg1) || (tempreg2)) {
4887		   xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4888		      "SiS650 revision ID %x (%s)\n", CR5F, id650str[CR5F >> 4]);
4889		   if(CR5F & 0x80) {
4890		      pSiS->hasTwoOverlays = TRUE;  /* M650 or 651 */
4891		      pSiS->SiS_SD_Flags |= SiS_SD_SUPPORT2OVL;
4892		   }
4893		   switch(CR5F) {
4894		      case 0xa0:
4895		      case 0xb0:
4896		      case 0xe0:
4897		         pSiS->ChipFlags |= SiSCF_Is651;
4898		         break;
4899		      case 0x80:
4900		      case 0x90:
4901		      case 0xc0:
4902		         pSiS->ChipFlags |= SiSCF_IsM650;
4903		         break;
4904		   }
4905		} else {
4906		   pSiS->hasTwoOverlays = TRUE;
4907		   pSiS->SiS_SD_Flags |= SiS_SD_SUPPORT2OVL;
4908		   switch(CR5F) {
4909		      case 0x90:
4910			 inSISIDXREG(SISCR, 0x5c, tempreg1);
4911			 tempreg1 &= 0xf8;
4912			 switch(tempreg1) {
4913			    case 0x00:
4914			       pSiS->ChipFlags |= SiSCF_IsM652;
4915			       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4916			           "SiSM652 revision ID %x\n", CR5F);
4917			       break;
4918			    case 0x40:
4919			       pSiS->ChipFlags |= SiSCF_IsM653;
4920			       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4921			           "SiSM653 revision ID %x\n", CR5F);
4922			       break;
4923			    default:
4924			       pSiS->ChipFlags |= SiSCF_IsM650;
4925			       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4926			           "SiSM650 revision ID %x\n", CR5F);
4927			       break;
4928			 }
4929			 break;
4930		      case 0xb0:
4931			 pSiS->ChipFlags |= SiSCF_Is652;
4932			 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4933			     "SiS652 revision ID %x\n", CR5F);
4934			 break;
4935		      default:
4936			 pSiS->ChipFlags |= SiSCF_IsM650;
4937			 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4938			     "SiSM650 revision ID %x\n", CR5F);
4939			 break;
4940		   }
4941		}
4942	     }
4943	     break;
4944	   }
4945	 case PCI_CHIP_SIS660:
4946	   {
4947	     pSiS->ChipFlags |= SiSCF_LARGEOVERLAY;
4948	     pSiS->hasTwoOverlays = TRUE;
4949	     pSiS->SiS_SD_Flags |= SiS_SD_SUPPORT2OVL;
4950	     /* 760/761:  - UMA only: one/two overlays - dotclock dependent
4951			  - UMA+LFB:  two overlays if video data in LFB
4952			  - LFB only: two overlays
4953		If UMA only: Must switch between one/two overlays on the fly (done
4954			     in PostSetMode())
4955		If LFB+UMA:  We use LFB memory only and leave UMA to an eventually
4956			     written DRI driver.
4957	      */
4958	     break;
4959	   }
4960       }
4961
4962       if(!(pSiS->SiS_SD2_Flags & SiS_SD2_NOOVERLAY)) {
4963          xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4964		"Hardware supports %s video overlay%s\n",
4965		pSiS->hasTwoOverlays ? "two" : "one",
4966		pSiS->hasTwoOverlays ? "s" : "");
4967       }
4968
4969       if(pSiS->SiS_SD2_Flags & SiS_SD2_SUPPORT760OO) {
4970	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
4971		"\n\tDear SiS76x user, your machine is using a shared memory framebuffer.\n"
4972		  "\tDue to hardware limitations of the SiS chip in combination with the\n"
4973		  "\tAMD CPU, video overlay support is very limited on this machine. If you\n"
4974		  "\texperience flashing lines in the video and/or the graphics display\n"
4975		  "\tduring video playback, reduce the color depth and/or the resolution\n"
4976		  "\tand/or the refresh rate. Alternatively, use the video blitter.\n");
4977       }
4978
4979    }
4980
4981    /* Backup VB connection and CRT1 on/off register */
4982    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
4983       inSISIDXREG(SISSR, 0x1f, pSiS->oldSR1F);
4984       inSISIDXREG(SISCR, 0x17, pSiS->oldCR17);
4985       inSISIDXREG(SISCR, 0x32, pSiS->oldCR32);
4986       inSISIDXREG(SISCR, 0x36, pSiS->oldCR36);
4987       inSISIDXREG(SISCR, 0x37, pSiS->oldCR37);
4988       if(pSiS->VGAEngine == SIS_315_VGA) {
4989          inSISIDXREG(SISCR, pSiS->myCR63, pSiS->oldCR63);
4990       }
4991
4992       pSiS->postVBCR32 = pSiS->oldCR32;
4993    }
4994
4995    /* There are some machines out there which require a special
4996     * setup of the GPIO registers in order to make the Chrontel
4997     * work. Try to find out if we're running on such a machine.
4998     * Furthermore, there is some highly customized hardware,
4999     * which requires some non-standard LVDS timing. Since the
5000     * vendors don't seem to care about PCI subsystem ID's we
5001     * need to find out using the BIOS version and date strings.
5002     */
5003    pSiS->SiS_Pr->SiS_ChSW = FALSE;
5004    if(pSiS->Chipset == PCI_CHIP_SIS630) {
5005       int i = 0;
5006       do {
5007	  if(mychswtable[i].subsysVendor == PCI_SUB_VENDOR_ID(pSiS->PciInfo) &&
5008	     mychswtable[i].subsysCard == PCI_SUB_DEVICE_ID(pSiS->PciInfo)) {
5009	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5010	         "PCI subsystem ID found in list for Chrontel/GPIO setup:\n");
5011	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5012		 "\tVendor/Card: %s %s (ID %04x)\n",
5013		  mychswtable[i].vendorName,
5014		  mychswtable[i].cardName,
5015		  PCI_SUB_DEVICE_ID(pSiS->PciInfo));
5016	     pSiS->SiS_Pr->SiS_ChSW = TRUE;
5017	     break;
5018          }
5019          i++;
5020       } while(mychswtable[i].subsysVendor != 0);
5021    }
5022
5023    if(pSiS->SiS_Pr->SiS_CustomT == CUT_NONE) {
5024       int    i = 0, j;
5025       UShort bversptr = 0;
5026       Bool   footprint;
5027       CARD32 chksum = 0;
5028
5029       if(pSiS->SiS_Pr->UseROM) {
5030          bversptr = pSiS->BIOS[0x16] | (pSiS->BIOS[0x17] << 8);
5031          for(i=0; i<32768; i++) chksum += pSiS->BIOS[i];
5032       }
5033
5034       i = 0;
5035       do {
5036	  if( (SiS_customttable[i].chipID == pSiS->ChipType)                            &&
5037	      ((!strlen(SiS_customttable[i].biosversion)) ||
5038	       (pSiS->SiS_Pr->UseROM &&
5039	       (!strncmp(SiS_customttable[i].biosversion, (char *)&pSiS->BIOS[bversptr],
5040	                strlen(SiS_customttable[i].biosversion)))))                     &&
5041	      ((!strlen(SiS_customttable[i].biosdate)) ||
5042	       (pSiS->SiS_Pr->UseROM &&
5043	       (!strncmp(SiS_customttable[i].biosdate, (char *)&pSiS->BIOS[0x2c],
5044	                strlen(SiS_customttable[i].biosdate)))))			      &&
5045	      ((!SiS_customttable[i].bioschksum) ||
5046	       (pSiS->SiS_Pr->UseROM &&
5047	       (SiS_customttable[i].bioschksum == chksum)))			      &&
5048	      (SiS_customttable[i].pcisubsysvendor == PCI_SUB_VENDOR_ID(pSiS->PciInfo))      &&
5049	      (SiS_customttable[i].pcisubsyscard == PCI_SUB_DEVICE_ID(pSiS->PciInfo)) ) {
5050	     footprint = TRUE;
5051	     for(j=0; j<5; j++) {
5052	        if(SiS_customttable[i].biosFootprintAddr[j]) {
5053		   if(pSiS->SiS_Pr->UseROM) {
5054		      if(pSiS->BIOS[SiS_customttable[i].biosFootprintAddr[j]] !=
5055						SiS_customttable[i].biosFootprintData[j])
5056		         footprint = FALSE;
5057		   } else footprint = FALSE;
5058	        }
5059	     }
5060	     if(footprint) {
5061	        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5062	           "Identified %s %s, special timing applies\n",
5063		   SiS_customttable[i].vendorName, SiS_customttable[i].cardName);
5064	        pSiS->SiS_Pr->SiS_CustomT = SiS_customttable[i].SpecialID;
5065	        break;
5066	     }
5067          }
5068          i++;
5069       } while(SiS_customttable[i].chipID);
5070    }
5071
5072    /* Handle ForceCRT1 option */
5073    if(pSiS->forceCRT1 != -1) {
5074       if(pSiS->forceCRT1) pSiS->CRT1off = 0;
5075       else                pSiS->CRT1off = 1;
5076    } else                 pSiS->CRT1off = -1;
5077
5078    /* Detect video bridge and sense TV/VGA2 */
5079    SISVGAPreInit(pScrn);
5080
5081    /* Detect CRT1 (via DDC1 and DDC2, hence via VGA port; regardless of LCDA) */
5082    SISCRT1PreInit(pScrn);
5083
5084    /* Detect LCD (connected via CRT2, regardless of LCDA) and LCD resolution */
5085    SISLCDPreInit(pScrn, FALSE);
5086
5087    /* LCDA only supported under these conditions: */
5088    if(pSiS->ForceCRT1Type == CRT1_LCDA) {
5089       if(!SISDetermineLCDACap(pScrn)) {
5090	  xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5091		"Chipset/Video bridge does not support LCD-via-CRT1\n");
5092	  pSiS->ForceCRT1Type = CRT1_VGA;
5093       } else if(!(pSiS->VBFlags & CRT2_LCD)) {
5094	  xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5095		"No digital LCD panel found, LCD-via-CRT1 disabled\n");
5096	  pSiS->ForceCRT1Type = CRT1_VGA;
5097       }
5098    }
5099
5100    /* Setup SD flags */
5101    pSiS->SiS_SD_Flags |= SiS_SD_ADDLSUPFLAG;
5102
5103    pSiS->SiS_SD2_Flags |= SiS_SD2_MERGEDUCLOCK;
5104    pSiS->SiS_SD2_Flags |= SiS_SD2_USEVBFLAGS2;
5105    pSiS->SiS_SD2_Flags |= SiS_SD2_VBINVB2ONLY;
5106    pSiS->SiS_SD2_Flags |= SiS_SD2_HAVESD34;
5107    pSiS->SiS_SD2_Flags |= SiS_SD2_NEWGAMMABRICON;
5108
5109    pSiS->SiS_SD3_Flags |= SiS_SD3_MFBALLOWOFFCL;
5110
5111    if(pSiS->VBFlags2 & VB2_VIDEOBRIDGE) {
5112       pSiS->SiS_SD2_Flags |= SiS_SD2_VIDEOBRIDGE;
5113       if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
5114	  pSiS->SiS_SD2_Flags |= ( SiS_SD2_SISBRIDGE     |
5115				   SiS_SD2_SUPPORTGAMMA2 );
5116	  if(pSiS->VBFlags2 & VB2_SISLVDSBRIDGE) {
5117	     pSiS->SiS_SD2_Flags |= ( SiS_SD2_LCDLVDS    |
5118				      SiS_SD2_SUPPORTLCD );
5119	  } else if(pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) {
5120	     if(!(pSiS->VBFlags2 & VB2_30xBDH)) {
5121		pSiS->SiS_SD2_Flags |= ( SiS_SD2_LCDTMDS    |
5122					 SiS_SD2_SUPPORTLCD );
5123	     } else if(pSiS->VBFlags & CRT2_LCD) {
5124		pSiS->SiS_SD2_Flags |= ( SiS_SD2_THIRDPARTYLVDS |
5125				         SiS_SD2_SUPPORTLCD );
5126	     }
5127	  }
5128       } else if(pSiS->VBFlags2 & VB2_LVDS) {
5129	  pSiS->SiS_SD2_Flags |= ( SiS_SD2_THIRDPARTYLVDS |
5130				   SiS_SD2_SUPPORTLCD );
5131       }
5132
5133       if(pSiS->VBFlags2 & (VB2_SISTVBRIDGE | VB2_CHRONTEL)) {
5134	  pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTTV;
5135	  if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
5136	     pSiS->SiS_SD2_Flags |= ( SiS_SD2_SUPPORTTVTYPE |
5137				      SiS_SD2_SUPPORTTVSIZE );
5138	     if(!(pSiS->VBFlags2 & VB2_301)) {
5139		pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPTVSAT;
5140	     } else {
5141		pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPTVEDGE;
5142	     }
5143	  }
5144       }
5145    }
5146
5147#ifdef ENABLE_YPBPR
5148    if((pSiS->VGAEngine == SIS_315_VGA) &&
5149       (pSiS->VBFlags2 & VB2_SISYPBPRBRIDGE)) {
5150       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTYPBPR;
5151       pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORT625I;
5152       pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORT625P;
5153       if(pSiS->VBFlags2 & VB2_SISYPBPRARBRIDGE) {
5154          pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTYPBPRAR;
5155       }
5156    }
5157    if(pSiS->VBFlags2 & VB2_SISHIVISIONBRIDGE) {
5158       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTHIVISION;
5159    }
5160#endif
5161
5162    if((pSiS->VGAEngine != SIS_300_VGA) || (!(pSiS->VBFlags2 & VB2_TRUMPION))) {
5163       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTSCALE;
5164       if((pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) &&
5165          (!(pSiS->VBFlags2 & VB2_30xBDH))) {
5166          pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTCENTER;
5167       }
5168    }
5169
5170#ifdef SISDUALHEAD
5171    if(!pSiS->DualHeadMode) {
5172       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTREDETECT;
5173    }
5174#endif
5175
5176#ifndef SISCHECKOSSSE
5177    pSiS->SiS_SD2_Flags |= SiS_SD2_NEEDUSESSE;
5178#endif
5179
5180#ifdef TWDEBUG	/* FOR TESTING */
5181    pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTYPBPRAR;
5182    xf86DrvMsg(0, X_INFO, "TEST: Support Aspect Ratio\n");
5183#endif
5184
5185    /* Detect CRT2-TV and PAL/NTSC mode */
5186    SISTVPreInit(pScrn, FALSE);
5187
5188    /* Detect CRT2-VGA */
5189    SISCRT2PreInit(pScrn, FALSE);
5190
5191    /* Backup detected CRT2 devices */
5192    SISSaveDetectedDevices(pScrn);
5193
5194    if(!(pSiS->SiS_SD_Flags & SiS_SD_SUPPORTYPBPR)) {
5195       if((pSiS->ForceTVType != -1) && (pSiS->ForceTVType & TV_YPBPR)) {
5196	  pSiS->ForceTVType = -1;
5197	  xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "YPbPr TV output not supported\n");
5198       }
5199    }
5200
5201    if(!(pSiS->SiS_SD_Flags & SiS_SD_SUPPORTHIVISION)) {
5202       if((pSiS->ForceTVType != -1) && (pSiS->ForceTVType & TV_HIVISION)) {
5203	  pSiS->ForceTVType = -1;
5204	  xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "HiVision TV output not supported\n");
5205       }
5206    }
5207
5208    if((pSiS->VBFlags2 & VB2_SISTVBRIDGE) ||
5209       ((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->ChrontelType == CHRONTEL_701x))) {
5210       pSiS->SiS_SD_Flags |= (SiS_SD_SUPPORTPALMN | SiS_SD_SUPPORTNTSCJ);
5211    }
5212    if((pSiS->VBFlags2 & VB2_SISTVBRIDGE) ||
5213       ((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->ChrontelType == CHRONTEL_700x))) {
5214       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTTVPOS;
5215    }
5216    if(pSiS->VBFlags2 & VB2_SISVGA2BRIDGE) {
5217       pSiS->SiS_SD_Flags |= (SiS_SD_SUPPORTSCART | SiS_SD_SUPPORTVGA2);
5218    }
5219    if(pSiS->VBFlags2 & VB2_CHRONTEL) {
5220       pSiS->SiS_SD_Flags  |= SiS_SD_SUPPORTOVERSCAN;
5221       pSiS->SiS_SD2_Flags |= SiS_SD2_CHRONTEL;
5222       if(pSiS->ChrontelType == CHRONTEL_700x) {
5223	  pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTSOVER;
5224       }
5225    }
5226
5227    /* Determine if chipset LCDA-capable */
5228    pSiS->SiS_SD_Flags &= ~SiS_SD_SUPPORTLCDA;
5229    if(SISDetermineLCDACap(pScrn)) {
5230       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTLCDA;
5231    }
5232
5233    /* Default to LCDA if LCD detected and
5234     * - TV detected (hence default to LCDA+TV), or
5235     * - in single head mode, on LCD panels with xres > 1600
5236     *   (Don't do this in MergedFB or DHM; LCDA and CRT1/VGA
5237     *   are mutually exclusive; if no TV is detected, the
5238     *   code below will default to VGA+LCD, so LCD is driven
5239     *   via CRT2.)
5240     *   (TODO: This might need some modification for the
5241     *   307 bridges, if these are capable of driving
5242     *   LCDs > 1600 via channel B)
5243     */
5244    if((pSiS->SiS_SD_Flags & SiS_SD_SUPPORTLCDA) &&
5245       (pSiS->VBFlags & CRT2_LCD) &&
5246       (pSiS->SiS_Pr->SiS_CustomT != CUT_UNKNOWNLCD)) {
5247       if((!pSiS->CRT1TypeForced) && (pSiS->ForceCRT2Type == CRT2_DEFAULT)) {
5248	  if(pSiS->VBFlags & CRT2_TV) {
5249	     /* If both LCD and TV present, default to LCDA+TV */
5250	     pSiS->ForceCRT1Type = CRT1_LCDA;
5251	     pSiS->ForceCRT2Type = CRT2_TV;
5252	  } else if(pSiS->LCDwidth > 1600) {
5253	     /* If LCD is > 1600, default to LCDA if we don't need CRT1/VGA for other head */
5254	     Bool NeedCRT1VGA = FALSE;
5255#ifdef SISDUALHEAD
5256	     if(pSiS->DualHeadMode) NeedCRT1VGA = TRUE;
5257#endif
5258#ifdef SISMERGED
5259	     if(pSiS->MergedFB &&
5260		(!pSiS->MergedFBAuto || pSiS->CRT1Detected)) NeedCRT1VGA = TRUE;
5261#endif
5262	     if(!NeedCRT1VGA) {
5263		pSiS->ForceCRT1Type = CRT1_LCDA;
5264	     }
5265	  }
5266       }
5267    }
5268
5269    /* Set up pseudo-panel if LCDA forced on TMDS bridges */
5270    if(pSiS->SiS_SD_Flags & SiS_SD_SUPPORTLCDA) {
5271       if(pSiS->ForceCRT1Type == CRT1_LCDA) {
5272          if(pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE) {
5273	     if(!(pSiS->VBLCDFlags)) {
5274		SiSSetupPseudoPanel(pScrn);
5275		pSiS->detectedCRT2Devices |= CRT2_LCD;
5276	     }
5277	  } else if(!(pSiS->VBLCDFlags)) {
5278	     pSiS->ForceCRT1Type = CRT1_VGA;
5279	  }
5280       }
5281    } else {
5282       pSiS->ForceCRT1Type = CRT1_VGA;
5283    }
5284
5285    pSiS->VBFlags |= pSiS->ForceCRT1Type;
5286
5287#ifdef TWDEBUG
5288    xf86DrvMsg(0, X_INFO, "SDFlags %lx\n", pSiS->SiS_SD_Flags);
5289#endif
5290
5291    /* Eventually overrule detected CRT2 type
5292     * If no type forced, use the detected devices in the order TV->LCD->VGA2
5293     * Since the Chrontel 7005 sometimes delivers wrong detection results,
5294     * we use a different order on such machines (LCD->TV)
5295     */
5296    if(pSiS->ForceCRT2Type == CRT2_DEFAULT) {
5297       if((pSiS->VBFlags & CRT2_TV) && (!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VGAEngine == SIS_300_VGA))))
5298	  pSiS->ForceCRT2Type = CRT2_TV;
5299       else if((pSiS->VBFlags & CRT2_LCD) && (pSiS->ForceCRT1Type == CRT1_VGA))
5300	  pSiS->ForceCRT2Type = CRT2_LCD;
5301       else if(pSiS->VBFlags & CRT2_TV)
5302	  pSiS->ForceCRT2Type = CRT2_TV;
5303       else if((pSiS->VBFlags & CRT2_VGA) && (pSiS->ForceCRT1Type == CRT1_VGA))
5304	  pSiS->ForceCRT2Type = CRT2_VGA;
5305    }
5306
5307    switch(pSiS->ForceCRT2Type) {
5308       case CRT2_TV:
5309	  pSiS->VBFlags &= ~(CRT2_LCD | CRT2_VGA);
5310	  if(pSiS->VBFlags2 & (VB2_SISTVBRIDGE | VB2_CHRONTEL)) {
5311	     pSiS->VBFlags |= CRT2_TV;
5312	  } else {
5313	     pSiS->VBFlags &= ~(CRT2_TV);
5314	     xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
5315		"Hardware does not support TV output\n");
5316	  }
5317	  break;
5318       case CRT2_LCD:
5319	  pSiS->VBFlags &= ~(CRT2_TV | CRT2_VGA);
5320	  if((pSiS->VBFlags2 & VB2_VIDEOBRIDGE) && (pSiS->VBLCDFlags)) {
5321	     pSiS->VBFlags |= CRT2_LCD;
5322	  } else if((pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) && (!(pSiS->VBFlags2 & VB2_30xBDH))) {
5323	     SiSSetupPseudoPanel(pScrn);
5324	     pSiS->detectedCRT2Devices |= CRT2_LCD;
5325	  } else {
5326	     pSiS->VBFlags &= ~(CRT2_LCD);
5327	     xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
5328		"Can't force CRT2 to LCD, no LCD detected\n");
5329	  }
5330	  break;
5331       case CRT2_VGA:
5332	  pSiS->VBFlags &= ~(CRT2_TV | CRT2_LCD);
5333	  if(pSiS->VBFlags2 & VB2_SISVGA2BRIDGE) {
5334	     pSiS->VBFlags |= CRT2_VGA;
5335	  } else {
5336	     pSiS->VBFlags &= ~(CRT2_VGA);
5337	     xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
5338		 "Hardware does not support secondary VGA\n");
5339	  }
5340	  break;
5341       default:
5342	  pSiS->VBFlags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
5343    }
5344
5345    /* Setup gamma (the cmap layer needs this to be initialised) */
5346    /* (Do this after evaluating options) */
5347    {
5348       Gamma zeros = {0.0, 0.0, 0.0};
5349       xf86SetGamma(pScrn, zeros);
5350    }
5351
5352#ifdef SISDUALHEAD
5353    if((!pSiS->DualHeadMode) || (pSiS->SecondHead)) {
5354#endif
5355       xf86DrvMsg(pScrn->scrnIndex, pSiS->CRT1gammaGiven ? X_CONFIG : X_INFO,
5356	     "%samma correction is %s\n",
5357	     (pSiS->VBFlags2 & VB2_VIDEOBRIDGE) ? "CRT1 g" : "G",
5358	     pSiS->CRT1gamma ? "enabled" : "disabled");
5359
5360       if((pSiS->VGAEngine == SIS_315_VGA)	&&
5361          (!(pSiS->NoXvideo))			&&
5362	  (!(pSiS->SiS_SD2_Flags & SiS_SD2_NOOVERLAY))) {
5363	  xf86DrvMsg(pScrn->scrnIndex, pSiS->XvGammaGiven ? X_CONFIG : X_INFO,
5364		"Separate Xv gamma correction %sis %s\n",
5365		(pSiS->VBFlags2 & VB2_VIDEOBRIDGE) ? "for CRT1 " : "",
5366		pSiS->XvGamma ? "enabled" : "disabled");
5367	  if(pSiS->XvGamma) {
5368	     xf86DrvMsg(pScrn->scrnIndex, pSiS->XvGammaGiven ? X_CONFIG : X_INFO,
5369		"Xv gamma correction: %.3f %.3f %.3f\n",
5370		(float)((float)pSiS->XvGammaRed / 1000),
5371		(float)((float)pSiS->XvGammaGreen / 1000),
5372		(float)((float)pSiS->XvGammaBlue / 1000));
5373	     if(!pSiS->CRT1gamma) {
5374		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5375		   "Xv gamma correction requires %samma correction enabled\n",
5376		   (pSiS->VBFlags2 & VB2_VIDEOBRIDGE) ? "CRT1 g" : "G");
5377	     }
5378	  }
5379       }
5380#ifdef SISDUALHEAD
5381    }
5382#endif
5383
5384#ifdef SISDUALHEAD
5385    if(pSiS->DualHeadMode) pSiS->CRT2SepGamma = FALSE;
5386#endif
5387
5388#ifdef SISDUALHEAD
5389    if((!pSiS->DualHeadMode) || (!pSiS->SecondHead))
5390#endif
5391    {
5392       Bool isDH = FALSE;
5393       if(pSiS->CRT2gamma) {
5394          if( ((pSiS->VGAEngine != SIS_300_VGA) && (pSiS->VGAEngine != SIS_315_VGA)) ||
5395              (!(pSiS->VBFlags2 & VB2_SISBRIDGE)) ) {
5396	     if(pSiS->VBFlags2 & VB2_VIDEOBRIDGE) {
5397	        xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5398			"CRT2 gamma correction not supported by hardware\n");
5399	     }
5400	     pSiS->CRT2gamma = pSiS->CRT2SepGamma = FALSE;
5401          } else if((pSiS->VBFlags2 & VB2_30xBDH) && (pSiS->VBFlags & CRT2_LCD)) {
5402	     isDH = TRUE;
5403	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5404			"CRT2 gamma correction not supported for LCD\n");
5405	     /* But leave it on, will be caught in LoadPalette */
5406          }
5407       }
5408       if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
5409	  xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CRT2 gamma correction is %s%s%s\n",
5410		pSiS->CRT2gamma ? "enabled" : "disabled",
5411		isDH ? " (for TV and VGA2) " : "",
5412		pSiS->CRT2SepGamma ? " (separate from CRT1)" : "");
5413       }
5414    }
5415
5416    /* Eventually overrule TV Type (SVIDEO, COMPOSITE, SCART, HIVISION, YPBPR) */
5417    if(pSiS->VBFlags2 & VB2_SISTVBRIDGE) {
5418       if(pSiS->ForceTVType != -1) {
5419	  pSiS->VBFlags &= ~(TV_INTERFACE);
5420	  if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) {
5421	     pSiS->VBFlags &= ~(TV_CHSCART | TV_CHYPBPR525I);
5422	  }
5423	  pSiS->VBFlags |= pSiS->ForceTVType;
5424	  if(pSiS->VBFlags & TV_YPBPR) {
5425	     pSiS->VBFlags &= ~(TV_STANDARD);
5426	     pSiS->VBFlags &= ~(TV_YPBPRAR);
5427	     pSiS->VBFlags |= pSiS->ForceYPbPrType;
5428	     pSiS->VBFlags |= pSiS->ForceYPbPrAR;
5429	  }
5430       }
5431    }
5432
5433    /* Handle ForceCRT1 option (part 2) */
5434    pSiS->CRT1changed = FALSE;
5435    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
5436       usScratchCR17 = pSiS->oldCR17;
5437       usScratchCR63 = pSiS->oldCR63;
5438       usScratchSR1F = pSiS->oldSR1F;
5439       usScratchCR32 = pSiS->postVBCR32;
5440       if(pSiS->VESA != 1) {
5441          /* Copy forceCRT1 option to CRT1off if option is given */
5442#ifdef SISDUALHEAD
5443          /* In DHM, handle this option only for master head, not the slave */
5444          if( (pSiS->forceCRT1 != -1) &&
5445	       (!(pSiS->DualHeadMode && pSiS->SecondHead)) ) {
5446#else
5447          if(pSiS->forceCRT1 != -1) {
5448#endif
5449	     xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
5450		 "CRT1 detection overruled by ForceCRT1 option\n");
5451	     if(pSiS->forceCRT1) {
5452		 pSiS->CRT1off = 0;
5453		 if(pSiS->VGAEngine == SIS_300_VGA) {
5454		    if(!(usScratchCR17 & 0x80)) pSiS->CRT1changed = TRUE;
5455		 } else {
5456		    if(usScratchCR63 & 0x40) pSiS->CRT1changed = TRUE;
5457		 }
5458		 usScratchCR17 |= 0x80;
5459		 usScratchCR32 |= 0x20;
5460		 usScratchCR63 &= ~0x40;
5461		 usScratchSR1F &= ~0xc0;
5462	     } else {
5463		 if( ! ( (pScrn->bitsPerPixel == 8) &&
5464		         ( (pSiS->VBFlags2 & (VB2_LVDS | VB2_CHRONTEL)) ||
5465		           ((pSiS->VBFlags2 & VB2_30xBDH) && (pSiS->VBFlags & CRT2_LCD)) ) ) ) {
5466		    pSiS->CRT1off = 1;
5467		    if(pSiS->VGAEngine == SIS_300_VGA) {
5468		       if(usScratchCR17 & 0x80) pSiS->CRT1changed = TRUE;
5469		    } else {
5470		       if(!(usScratchCR63 & 0x40)) pSiS->CRT1changed = TRUE;
5471		    }
5472		    usScratchCR32 &= ~0x20;
5473		    /* We must not actually switch off CRT1 before we changed the mode! */
5474		 }
5475	     }
5476	     /* Here we can write to CR17 even on 315 series as we only ENABLE
5477	      * the bit here
5478	      */
5479	     outSISIDXREG(SISCR, 0x17, usScratchCR17);
5480	     if(pSiS->VGAEngine == SIS_315_VGA) {
5481		outSISIDXREG(SISCR, pSiS->myCR63, usScratchCR63);
5482	     }
5483	     outSISIDXREG(SISCR, 0x32, usScratchCR32);
5484	     if(pSiS->CRT1changed) {
5485		outSISIDXREG(SISSR, 0x00, 0x01);    /* Synchronous Reset */
5486		usleep(10000);
5487		outSISIDXREG(SISSR, 0x00, 0x03);    /* End Reset */
5488		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5489			"CRT1 status changed by ForceCRT1 option\n");
5490	     }
5491	     outSISIDXREG(SISSR, 0x1f, usScratchSR1F);
5492          }
5493       }
5494       /* Store the new VB connection register contents for later mode changes */
5495       pSiS->newCR32 = usScratchCR32;
5496    }
5497
5498    /* Check if CRT1 used (or needed; this eg. if no CRT2 detected) */
5499    if(pSiS->VBFlags2 & VB2_VIDEOBRIDGE) {
5500
5501        /* No CRT2 output? Then we NEED CRT1!
5502	 * We also need CRT1 if depth = 8 and bridge=LVDS|301B-DH
5503	 */
5504	if( (!(pSiS->VBFlags & (CRT2_VGA | CRT2_LCD | CRT2_TV))) ||
5505	    ( (pScrn->bitsPerPixel == 8) &&
5506	      ( (pSiS->VBFlags2 & (VB2_LVDS | VB2_CHRONTEL)) ||
5507	        ((pSiS->VBFlags2 & VB2_30xBDH) && (pSiS->VBFlags & CRT2_LCD)) ) ) ) {
5508	    pSiS->CRT1off = 0;
5509	}
5510	/* No CRT2 output? Then we can't use Xv on CRT2 */
5511	if(!(pSiS->VBFlags & (CRT2_VGA | CRT2_LCD | CRT2_TV))) {
5512	    pSiS->XvOnCRT2 = FALSE;
5513	}
5514
5515    } else { /* no video bridge? */
5516	/* Then we NEED CRT1... */
5517	pSiS->CRT1off = 0;
5518	/* ... and can't use CRT2 for Xv output */
5519	pSiS->XvOnCRT2 = FALSE;
5520    }
5521
5522    /* LCDA? Then we don't switch off CRT1 */
5523    if(pSiS->VBFlags & CRT1_LCDA) pSiS->CRT1off = 0;
5524
5525    /* Handle TVStandard option */
5526    if((pSiS->NonDefaultPAL != -1) || (pSiS->NonDefaultNTSC != -1)) {
5527       if( (!(pSiS->VBFlags2 & VB2_SISTVBRIDGE)) &&
5528	   (!((pSiS->VBFlags2 & VB2_CHRONTEL)) && (pSiS->ChrontelType == CHRONTEL_701x)) ) {
5529	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5530	   	"PALM, PALN and NTSCJ not supported on this hardware\n");
5531	  pSiS->NonDefaultPAL = pSiS->NonDefaultNTSC = -1;
5532	  pSiS->VBFlags &= ~(TV_PALN | TV_PALM | TV_NTSCJ);
5533	  pSiS->SiS_SD_Flags &= ~(SiS_SD_SUPPORTPALMN | SiS_SD_SUPPORTNTSCJ);
5534       }
5535    }
5536    if(pSiS->OptTVStand != -1) {
5537       if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
5538	  if( (!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & (TV_CHSCART | TV_CHYPBPR525I)))) &&
5539	      (!(pSiS->VBFlags & (TV_HIVISION | TV_YPBPR))) ) {
5540	     pSiS->VBFlags &= ~(TV_PAL | TV_NTSC | TV_PALN | TV_PALM | TV_NTSCJ);
5541	     if(pSiS->OptTVStand) {
5542	        pSiS->VBFlags |= TV_PAL;
5543	        if(pSiS->NonDefaultPAL == 1)  pSiS->VBFlags |= TV_PALM;
5544	        else if(!pSiS->NonDefaultPAL) pSiS->VBFlags |= TV_PALN;
5545	     } else {
5546	        pSiS->VBFlags |= TV_NTSC;
5547		if(pSiS->NonDefaultNTSC == 1) pSiS->VBFlags |= TV_NTSCJ;
5548	     }
5549	  } else {
5550	     pSiS->OptTVStand = pSiS->NonDefaultPAL = -1;
5551	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5552	    	 "Option TVStandard ignored for YPbPr, HiVision and Chrontel-SCART\n");
5553	  }
5554       } else if(pSiS->Chipset == PCI_CHIP_SIS6326) {
5555	  pSiS->SiS6326Flags &= ~SIS6326_TVPAL;
5556	  if(pSiS->OptTVStand) pSiS->SiS6326Flags |= SIS6326_TVPAL;
5557       }
5558    }
5559
5560    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
5561       /* Default to PAL */
5562       if(pSiS->VBFlags & (TV_SVIDEO | TV_AVIDEO)) {
5563          if(!(pSiS->VBFlags & (TV_PAL | TV_NTSC))) {
5564	     pSiS->VBFlags &= ~(TV_PAL | TV_NTSC | TV_PALN | TV_PALM | TV_NTSCJ);
5565	     pSiS->VBFlags |= TV_PAL;
5566	  }
5567       }
5568       /* SCART only supported for PAL */
5569       if((pSiS->VBFlags2 & VB2_SISBRIDGE) && (pSiS->VBFlags & TV_SCART)) {
5570	  pSiS->VBFlags &= ~(TV_NTSC | TV_PALN | TV_PALM | TV_NTSCJ);
5571	  pSiS->VBFlags |= TV_PAL;
5572	  pSiS->OptTVStand = 1;
5573	  pSiS->NonDefaultPAL = pSiS->NonDefaultNTSC = -1;
5574       }
5575    }
5576
5577#ifdef SIS_CP
5578    SIS_CP_DRIVER_RECONFIGOPT
5579#endif
5580
5581    if((pSiS->Chipset == PCI_CHIP_SIS6326) && (pSiS->SiS6326Flags & SIS6326_HASTV)) {
5582       if(pSiS->sis6326tvplug != -1) {
5583          pSiS->SiS6326Flags &= ~(SIS6326_TVSVIDEO | SIS6326_TVCVBS);
5584	  pSiS->SiS6326Flags |= SIS6326_TVDETECTED;
5585	  if(pSiS->sis6326tvplug == 1) 	pSiS->SiS6326Flags |= SIS6326_TVCVBS;
5586	  else 				pSiS->SiS6326Flags |= SIS6326_TVSVIDEO;
5587	  xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
5588	      "SiS6326 TV plug type detection overruled by %s\n",
5589	      (pSiS->SiS6326Flags & SIS6326_TVCVBS) ? "COMPOSITE" : "SVIDEO");
5590       }
5591    }
5592
5593    /* Do some checks */
5594    if(pSiS->OptTVOver != -1) {
5595       if(pSiS->VBFlags2 & VB2_CHRONTEL) {
5596	  pSiS->UseCHOverScan = pSiS->OptTVOver;
5597       } else {
5598	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5599	      "CHTVOverscan only supported on CHRONTEL 70xx\n");
5600	  pSiS->UseCHOverScan = -1;
5601       }
5602    } else pSiS->UseCHOverScan = -1;
5603
5604    if(pSiS->sistvedgeenhance != -1) {
5605       if(!(pSiS->VBFlags2 & VB2_301)) {
5606	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5607	      "SISTVEdgeEnhance only supported on SiS301\n");
5608	  pSiS->sistvedgeenhance = -1;
5609       }
5610    }
5611    if(pSiS->sistvsaturation != -1) {
5612       if(pSiS->VBFlags2 & VB2_301) {
5613	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5614	      "SISTVSaturation not supported on SiS301\n");
5615	  pSiS->sistvsaturation = -1;
5616       }
5617    }
5618
5619    /* Do some MergedFB mode initialisation */
5620#ifdef SISMERGED
5621    if(pSiS->MergedFB) {
5622       pSiS->CRT2pScrn = malloc(sizeof(ScrnInfoRec));
5623       if(!pSiS->CRT2pScrn) {
5624          SISErrorLog(pScrn, "Failed to allocate memory for 2nd pScrn, %s\n", mergeddisstr);
5625	  pSiS->MergedFB = FALSE;
5626       } else {
5627          memcpy(pSiS->CRT2pScrn, pScrn, sizeof(ScrnInfoRec));
5628       }
5629    }
5630#endif
5631
5632    /* Determine CRT1<>CRT2 mode
5633     *     Note: When using VESA or if the bridge is in slavemode, display
5634     *           is ALWAYS in MIRROR_MODE!
5635     *           This requires extra checks in functions using this flag!
5636     *           (see sis_video.c for example)
5637     */
5638    if(pSiS->VBFlags & DISPTYPE_DISP2) {
5639        if(pSiS->CRT1off) {	/* CRT2 only ------------------------------- */
5640#ifdef SISDUALHEAD
5641	     if(pSiS->DualHeadMode) {
5642		SISErrorLog(pScrn,
5643		    "CRT1 not detected or forced off. Dual Head mode can't initialize.\n");
5644		if(pSiSEnt) pSiSEnt->DisableDual = TRUE;
5645		goto my_error_1;
5646	     }
5647#endif
5648#ifdef SISMERGED
5649	     if(pSiS->MergedFB) {
5650		if(pSiS->MergedFBAuto) {
5651		   xf86DrvMsg(pScrn->scrnIndex, X_INFO, mergednocrt1, mergeddisstr);
5652		} else {
5653		   SISErrorLog(pScrn, mergednocrt1, mergeddisstr);
5654		}
5655		if(pSiS->CRT2pScrn) free(pSiS->CRT2pScrn);
5656		pSiS->CRT2pScrn = NULL;
5657		pSiS->MergedFB = FALSE;
5658	     }
5659#endif
5660	     pSiS->VBFlags |= VB_DISPMODE_SINGLE;
5661	     /* No CRT1? Then we use the video overlay on CRT2 */
5662	     pSiS->XvOnCRT2 = TRUE;
5663	} else			/* CRT1 and CRT2 - mirror or dual head ----- */
5664#ifdef SISDUALHEAD
5665	     if(pSiS->DualHeadMode) {
5666		pSiS->VBFlags |= (VB_DISPMODE_DUAL | DISPTYPE_CRT1);
5667		if(pSiS->VESA != -1) {
5668		    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5669			"VESA option not used in Dual Head mode. VESA disabled.\n");
5670		}
5671		if(pSiSEnt) pSiSEnt->DisableDual = FALSE;
5672		pSiS->VESA = 0;
5673	     } else
5674#endif
5675#ifdef SISMERGED
5676		    if(pSiS->MergedFB) {
5677		 pSiS->VBFlags |= (VB_DISPMODE_MIRROR | DISPTYPE_CRT1);
5678		 if(pSiS->VESA != -1) {
5679		    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5680			"VESA option not used in MergedFB mode. VESA disabled.\n");
5681		 }
5682		 pSiS->VESA = 0;
5683	     } else
5684#endif
5685		 pSiS->VBFlags |= (VB_DISPMODE_MIRROR | DISPTYPE_CRT1);
5686    } else {			/* CRT1 only ------------------------------- */
5687#ifdef SISDUALHEAD
5688	     if(pSiS->DualHeadMode) {
5689		SISErrorLog(pScrn,
5690		   "No CRT2 output selected or no bridge detected. "
5691		   "Dual Head mode can't initialize.\n");
5692		goto my_error_1;
5693	     }
5694#endif
5695#ifdef SISMERGED
5696	     if(pSiS->MergedFB) {
5697		if(pSiS->MergedFBAuto) {
5698		   xf86DrvMsg(pScrn->scrnIndex, X_INFO, mergednocrt2, mergeddisstr);
5699		} else {
5700		   SISErrorLog(pScrn, mergednocrt2, mergeddisstr);
5701		}
5702		if(pSiS->CRT2pScrn) free(pSiS->CRT2pScrn);
5703		pSiS->CRT2pScrn = NULL;
5704		pSiS->MergedFB = FALSE;
5705	     }
5706#endif
5707             pSiS->VBFlags |= (VB_DISPMODE_SINGLE | DISPTYPE_CRT1);
5708    }
5709
5710    if((pSiS->VGAEngine == SIS_315_VGA) || (pSiS->VGAEngine == SIS_300_VGA)) {
5711       if((!pSiS->NoXvideo)		&&
5712          (!pSiS->hasTwoOverlays)	&&
5713	  (!(pSiS->SiS_SD2_Flags & SiS_SD2_NOOVERLAY))) {
5714	  xf86DrvMsg(pScrn->scrnIndex, from,
5715	      "Using Xv overlay by default on CRT%d\n",
5716	      pSiS->XvOnCRT2 ? 2 : 1);
5717       }
5718    }
5719
5720    /* Init ptrs for Save/Restore functions and calc MaxClock */
5721    SISDACPreInit(pScrn);
5722
5723    /* ********** end of VBFlags setup ********** */
5724
5725    /* VBFlags are initialized now. Back them up for SlaveMode modes. */
5726    pSiS->VBFlags_backup = pSiS->VBFlags;
5727
5728    /* Backup CR32,36,37 (in order to write them back after a VT switch) */
5729    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
5730       inSISIDXREG(SISCR,0x32,pSiS->myCR32);
5731       inSISIDXREG(SISCR,0x36,pSiS->myCR36);
5732       inSISIDXREG(SISCR,0x37,pSiS->myCR37);
5733    }
5734
5735    /* Find out about paneldelaycompensation and evaluate option */
5736#ifdef SISDUALHEAD
5737    if((!pSiS->DualHeadMode) || (!pSiS->SecondHead)) {
5738#endif
5739       if(pSiS->VGAEngine == SIS_300_VGA) {
5740
5741          if(pSiS->VBFlags2 & (VB2_LVDS | VB2_30xBDH)) {
5742
5743	     /* Save the current PDC if the panel is used at the moment.
5744	      * This seems by far the safest way to find out about it.
5745	      * If the system is using an old version of sisfb, we can't
5746	      * trust the pdc register value. If sisfb saved the pdc for
5747	      * us, use it.
5748	      */
5749	     if(pSiS->sisfbpdc != 0xff) {
5750	        pSiS->SiS_Pr->PDC = pSiS->sisfbpdc;
5751	     } else {
5752	        if(!(pSiS->donttrustpdc)) {
5753	           UChar tmp;
5754	           inSISIDXREG(SISCR, 0x30, tmp);
5755	           if(tmp & 0x20) {
5756	              inSISIDXREG(SISPART1, 0x13, pSiS->SiS_Pr->PDC);
5757                   } else {
5758	             xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5759		          "Unable to detect LCD PanelDelayCompensation, LCD is not active\n");
5760	           }
5761	        } else {
5762	           xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5763		        "Unable to detect LCD PanelDelayCompensation, please update sisfb\n");
5764	        }
5765	     }
5766	     if(pSiS->SiS_Pr->PDC != -1) {
5767	        pSiS->SiS_Pr->PDC &= 0x3c;
5768	        xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5769		     "Detected LCD PanelDelayCompensation 0x%02x\n",
5770		     pSiS->SiS_Pr->PDC);
5771	     }
5772
5773	     /* If we haven't been able to find out, use our other methods */
5774	     if(pSiS->SiS_Pr->PDC == -1) {
5775		int i=0;
5776		do {
5777		   if(mypdctable[i].subsysVendor == PCI_SUB_VENDOR_ID(pSiS->PciInfo) &&
5778		      mypdctable[i].subsysCard == PCI_SUB_DEVICE_ID(pSiS->PciInfo)) {
5779			 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5780			    "PCI card/vendor identified for non-default PanelDelayCompensation\n");
5781			 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5782			     "Vendor: %s, card: %s (ID %04x), PanelDelayCompensation: 0x%02x\n",
5783			     mypdctable[i].vendorName, mypdctable[i].cardName,
5784			     PCI_SUB_DEVICE_ID(pSiS->PciInfo), mypdctable[i].pdc);
5785			 if(pSiS->PDC == -1) {
5786			    pSiS->PDC = mypdctable[i].pdc;
5787			 } else {
5788			    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
5789				"PanelDelayCompensation overruled by option\n");
5790			 }
5791			 break;
5792		   }
5793		   i++;
5794		} while(mypdctable[i].subsysVendor != 0);
5795	     }
5796
5797	     if(pSiS->PDC != -1) {
5798		if(pSiS->BIOS) {
5799		   if(pSiS->VBFlags2 & VB2_LVDS) {
5800		      if(pSiS->BIOS[0x220] & 0x80) {
5801			 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5802			     "BIOS uses OEM LCD Panel Delay Compensation 0x%02x\n",
5803			     pSiS->BIOS[0x220] & 0x3c);
5804			 pSiS->BIOS[0x220] &= 0x7f;
5805		      }
5806		   }
5807		   if(pSiS->VBFlags2 & (VB2_301B | VB2_302B)) {
5808		      if(pSiS->BIOS[0x220] & 0x80) {
5809			 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5810			     "BIOS uses OEM LCD Panel Delay Compensation 0x%02x\n",
5811			       (  (pSiS->VBLCDFlags & VB_LCD_1280x1024) ?
5812			                 pSiS->BIOS[0x223] : pSiS->BIOS[0x224]  ) & 0x3c);
5813			 pSiS->BIOS[0x220] &= 0x7f;
5814		      }
5815		   }
5816		}
5817		pSiS->SiS_Pr->PDC = (pSiS->PDC & 0x3c);
5818		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
5819		      "Using LCD Panel Delay Compensation 0x%02x\n", pSiS->SiS_Pr->PDC);
5820	     }
5821	  }
5822
5823       }  /* SIS_300_VGA */
5824
5825       if(pSiS->VGAEngine == SIS_315_VGA) {
5826
5827	  UChar tmp, tmp2;
5828	  inSISIDXREG(SISCR, 0x30, tmp);
5829
5830	  /* Save the current PDC if the panel is used at the moment. */
5831	  if(pSiS->VBFlags2 & VB2_SISLVDSBRIDGE) {
5832
5833	     if(pSiS->sisfbpdc != 0xff) {
5834	        pSiS->SiS_Pr->PDC = pSiS->sisfbpdc;
5835	     }
5836	     if(pSiS->sisfbpdca != 0xff) {
5837	        pSiS->SiS_Pr->PDCA = pSiS->sisfbpdca;
5838	     }
5839
5840	     if(!pSiS->donttrustpdc) {
5841	        if((pSiS->sisfbpdc == 0xff) && (pSiS->sisfbpdca == 0xff)) {
5842		   CARD16 tempa, tempb;
5843		   inSISIDXREG(SISPART1,0x2d,tmp2);
5844		   tempa = (tmp2 & 0xf0) >> 3;
5845		   tempb = (tmp2 & 0x0f) << 1;
5846		   inSISIDXREG(SISPART1,0x20,tmp2);
5847		   tempa |= ((tmp2 & 0x40) >> 6);
5848		   inSISIDXREG(SISPART1,0x35,tmp2);
5849		   tempb |= ((tmp2 & 0x80) >> 7);
5850		   inSISIDXREG(SISPART1,0x13,tmp2);
5851		   if(!pSiS->ROM661New) {
5852		      if((tmp2 & 0x04) || (tmp & 0x20)) {
5853		         pSiS->SiS_Pr->PDCA = tempa;
5854		         pSiS->SiS_Pr->PDC  = tempb;
5855		      } else {
5856			 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5857			     "Unable to detect PanelDelayCompensation, LCD is not active\n");
5858		      }
5859		   } else {
5860		      if(tmp2 & 0x04) {
5861		         pSiS->SiS_Pr->PDCA = tempa;
5862		      } else if(tmp & 0x20) {
5863		         pSiS->SiS_Pr->PDC  = tempb;
5864		      } else {
5865			 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5866			     "Unable to detect PanelDelayCompensation, LCD is not active\n");
5867		      }
5868		   }
5869		}
5870	     } else {
5871		xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5872		    "Unable to detect PanelDelayCompensation, please update sisfb\n");
5873	     }
5874	     if(pSiS->SiS_Pr->PDC != -1) {
5875		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5876		     "Detected LCD PanelDelayCompensation 0x%02x (for LCD=CRT2)\n",
5877		     pSiS->SiS_Pr->PDC);
5878	     }
5879	     if(pSiS->SiS_Pr->PDCA != -1) {
5880		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5881		     "Detected LCD PanelDelayCompensation1 0x%02x (for LCD=CRT1)\n",
5882		     pSiS->SiS_Pr->PDCA);
5883	     }
5884	  }
5885
5886	  /* Let user override (for all bridges) */
5887	  if(pSiS->VBFlags2 & VB2_30xBLV) {
5888	     if(pSiS->PDC != -1) {
5889	        pSiS->SiS_Pr->PDC = pSiS->PDC & 0x1f;
5890		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
5891		     "Using LCD PanelDelayCompensation 0x%02x (for LCD=CRT2)\n",
5892		     pSiS->SiS_Pr->PDC);
5893	     }
5894	     if(pSiS->PDCA != -1) {
5895		pSiS->SiS_Pr->PDCA = pSiS->PDCA & 0x1f;
5896		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
5897		     "Using LCD PanelDelayCompensation1 0x%02x (for LCD=CRT1)\n",
5898		     pSiS->SiS_Pr->PDCA);
5899	     }
5900          }
5901
5902 	  /* Read the current EMI (if not overruled) */
5903	  if(pSiS->VBFlags2 & VB2_SISEMIBRIDGE) {
5904	     MessageType from = X_PROBED;
5905	     if(pSiS->EMI != -1) {
5906		pSiS->SiS_Pr->EMI_30 = (pSiS->EMI >> 24) & 0x60;
5907		pSiS->SiS_Pr->EMI_31 = (pSiS->EMI >> 16) & 0xff;
5908		pSiS->SiS_Pr->EMI_32 = (pSiS->EMI >> 8)  & 0xff;
5909		pSiS->SiS_Pr->EMI_33 = pSiS->EMI & 0xff;
5910		pSiS->SiS_Pr->HaveEMI = pSiS->SiS_Pr->HaveEMILCD = TRUE;
5911		pSiS->SiS_Pr->OverruleEMI = TRUE;
5912		from = X_CONFIG;
5913	     } else if((pSiS->sisfbfound) && (pSiS->sisfb_haveemi)) {
5914		pSiS->SiS_Pr->EMI_30 = pSiS->sisfb_emi30;
5915		pSiS->SiS_Pr->EMI_31 = pSiS->sisfb_emi31;
5916		pSiS->SiS_Pr->EMI_32 = pSiS->sisfb_emi32;
5917		pSiS->SiS_Pr->EMI_33 = pSiS->sisfb_emi33;
5918		pSiS->SiS_Pr->HaveEMI = TRUE;
5919		if(pSiS->sisfb_haveemilcd) pSiS->SiS_Pr->HaveEMILCD = TRUE;
5920		pSiS->SiS_Pr->OverruleEMI = FALSE;
5921	     } else {
5922		inSISIDXREG(SISPART4, 0x30, pSiS->SiS_Pr->EMI_30);
5923		inSISIDXREG(SISPART4, 0x31, pSiS->SiS_Pr->EMI_31);
5924		inSISIDXREG(SISPART4, 0x32, pSiS->SiS_Pr->EMI_32);
5925		inSISIDXREG(SISPART4, 0x33, pSiS->SiS_Pr->EMI_33);
5926		pSiS->SiS_Pr->HaveEMI = TRUE;
5927		if(tmp & 0x20) pSiS->SiS_Pr->HaveEMILCD = TRUE;
5928		pSiS->SiS_Pr->OverruleEMI = FALSE;
5929	     }
5930	     xf86DrvMsg(pScrn->scrnIndex, from,
5931		   "302LV/302ELV: Using EMI 0x%02x%02x%02x%02x%s\n",
5932		   pSiS->SiS_Pr->EMI_30,pSiS->SiS_Pr->EMI_31,
5933		   pSiS->SiS_Pr->EMI_32,pSiS->SiS_Pr->EMI_33,
5934		   pSiS->SiS_Pr->HaveEMILCD ? " (LCD)" : "");
5935	  }
5936
5937       } /* SIS_315_VGA */
5938#ifdef SISDUALHEAD
5939    }
5940#endif
5941
5942
5943    /* In dual head mode, both heads (currently) share the maxxfbmem equally.
5944     * If memory sharing is done differently, the following has to be changed;
5945     * the other modules (eg. accel and Xv) use dhmOffset for hardware
5946     * pointer settings relative to VideoRAM start and won't need to be changed.
5947     *
5948     * Addendum: dhmoffset is also used for skipping the UMA area on SiS76x.
5949     */
5950
5951    pSiS->dhmOffset = pSiS->FbBaseOffset;
5952    pSiS->FbAddress += pSiS->dhmOffset;
5953
5954#ifdef SISDUALHEAD
5955    if(pSiS->DualHeadMode) {
5956       pSiS->FbAddress = pSiS->realFbAddress;
5957       if(!pSiS->SecondHead) {
5958	  /* ===== First head (always CRT2) ===== */
5959	  /* We use only half of the memory available */
5960	  pSiS->maxxfbmem /= 2;
5961	  /* dhmOffset is 0 (or LFB-base for SiS76x UMA skipping) */
5962	  pSiS->FbAddress += pSiS->dhmOffset;
5963	  xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5964	      "%dKB video RAM at 0x%lx available for master head (CRT2)\n",
5965	      pSiS->maxxfbmem/1024, pSiS->FbAddress);
5966       } else {
5967	  /* ===== Second head (always CRT1) ===== */
5968	  /* We use only half of the memory available */
5969	  pSiS->maxxfbmem /= 2;
5970	  /* Initialize dhmOffset */
5971	  pSiS->dhmOffset += pSiS->maxxfbmem;
5972	  /* Adapt FBAddress */
5973	  pSiS->FbAddress += pSiS->dhmOffset;
5974	  xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5975	     "%dKB video RAM at 0x%lx available for slave head (CRT1)\n",
5976	     pSiS->maxxfbmem/1024,  pSiS->FbAddress);
5977       }
5978    }
5979#endif
5980
5981    /* Note: Do not use availMem for anything from now. Use
5982     * maxxfbmem instead. (availMem does not take dual head
5983     * mode into account.)
5984     */
5985
5986    if(pSiS->FbBaseOffset) {
5987       /* Doubt that the DRM memory manager can deal
5988        * with a heap start of 0...
5989	*/
5990       pSiS->DRIheapstart = 16;
5991       pSiS->DRIheapend = pSiS->FbBaseOffset;
5992    } else {
5993       pSiS->DRIheapstart = pSiS->maxxfbmem;
5994       pSiS->DRIheapend = pSiS->availMem;
5995    }
5996#ifdef SISDUALHEAD
5997    if(pSiS->DualHeadMode) {
5998       pSiS->DRIheapstart = pSiS->DRIheapend = 0;
5999    } else
6000#endif
6001           if(pSiS->DRIheapstart >= pSiS->DRIheapend) {
6002#if 0  /* For future use */
6003       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6004	  "No memory for DRI heap. Please set the option \"MaxXFBMem\" to\n"
6005	  "\tlimit the memory X should use and leave the rest to DRI\n");
6006#endif
6007       pSiS->DRIheapstart = pSiS->DRIheapend = 0;
6008    }
6009
6010    /* Now for something completely different: DDC.
6011     * For 300 and 315/330/340 series, we provide our
6012     * own functions (in order to probe CRT2 as well)
6013     * If these fail, use the VBE.
6014     * All other chipsets will use VBE. No need to re-invent
6015     * the wheel there.
6016     */
6017
6018    pSiS->pVbe = NULL;
6019    didddc2 = FALSE;
6020
6021    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
6022       if(xf86LoadSubModule(pScrn, "ddc")) {
6023	  int crtnum = 0;
6024	  if((pMonitor = SiSDoPrivateDDC(pScrn, &crtnum))) {
6025	     didddc2 = TRUE;
6026	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED, ddcsstr, crtnum);
6027	     xf86PrintEDID(pMonitor);
6028	     xf86SetDDCproperties(pScrn, pMonitor);
6029	     pScrn->monitor->DDC = pMonitor;
6030	     /* Now try to find out aspect ratio */
6031	     SiSFindAspect(pScrn, pMonitor, crtnum);
6032	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED, ddcestr, crtnum);
6033	  }
6034       }
6035    }
6036
6037#ifdef SISDUALHEAD
6038    /* In dual head mode, probe DDC using VBE only for CRT1 (second head) */
6039    if((pSiS->DualHeadMode) && (!didddc2) && (!pSiS->SecondHead)) {
6040       didddc2 = TRUE;
6041    }
6042#endif
6043
6044    if(!didddc2) {
6045       /* If CRT1 is off or LCDA, skip DDC via VBE */
6046       if((pSiS->CRT1off) || (pSiS->VBFlags & CRT1_LCDA)) {
6047          didddc2 = TRUE;
6048       }
6049    }
6050
6051    /* Now (re-)load and initialize the DDC module */
6052    if(!didddc2) {
6053
6054       if(xf86LoadSubModule(pScrn, "ddc")) {
6055
6056	  /* Now load and initialize VBE module. */
6057	  SiS_LoadInitVBE(pScrn);
6058
6059	  if(pSiS->pVbe) {
6060	     if((pMonitor = vbeDoEDID(pSiS->pVbe,NULL))) {
6061		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
6062		      "VBE CRT1 DDC monitor info:\n");
6063		xf86SetDDCproperties(pScrn, xf86PrintEDID(pMonitor));
6064		pScrn->monitor->DDC = pMonitor;
6065		/* Now try to find out aspect ratio */
6066		SiSFindAspect(pScrn, pMonitor, 1);
6067		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
6068		      "End of VBE CRT1 DDC monitor info\n");
6069	     }
6070	  } else {
6071	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6072		 "Failed to read DDC data\n");
6073	  }
6074       }
6075    }
6076
6077#ifdef SISMERGED
6078    if(pSiS->MergedFB) {
6079       pSiS->CRT2pScrn->monitor = malloc(sizeof(MonRec));
6080       if(pSiS->CRT2pScrn->monitor) {
6081	  DisplayModePtr tempm = NULL, currentm = NULL, newm = NULL;
6082	  memcpy(pSiS->CRT2pScrn->monitor, pScrn->monitor, sizeof(MonRec));
6083	  pSiS->CRT2pScrn->monitor->DDC = NULL;
6084	  pSiS->CRT2pScrn->monitor->Modes = NULL;
6085	  pSiS->CRT2pScrn->monitor->id = (char *)crt2monname;
6086	  tempm = pScrn->monitor->Modes;
6087	  while(tempm) {
6088	     if(!(newm = malloc(sizeof(DisplayModeRec)))) break;
6089	     memcpy(newm, tempm, sizeof(DisplayModeRec));
6090	     if(!(newm->name = malloc(strlen(tempm->name) + 1))) {
6091	        free(newm);
6092		break;
6093	     }
6094	     strcpy(newm->name, tempm->name);
6095	     if(!pSiS->CRT2pScrn->monitor->Modes) pSiS->CRT2pScrn->monitor->Modes = newm;
6096	     if(currentm) {
6097	        currentm->next = newm;
6098		newm->prev = currentm;
6099	     }
6100	     currentm = newm;
6101	     tempm = tempm->next;
6102	  }
6103	  if(pSiS->CRT2HSync) {
6104	     pSiS->CRT2pScrn->monitor->nHsync =
6105		SiSStrToRanges(pSiS->CRT2pScrn->monitor->hsync, pSiS->CRT2HSync, MAX_HSYNC);
6106	  }
6107	  if(pSiS->CRT2VRefresh) {
6108	     pSiS->CRT2pScrn->monitor->nVrefresh =
6109		SiSStrToRanges(pSiS->CRT2pScrn->monitor->vrefresh, pSiS->CRT2VRefresh, MAX_VREFRESH);
6110	  }
6111	  if((pMonitor = SiSInternalDDC(pSiS->CRT2pScrn, 1))) {
6112	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED, ddcsstr, 2);
6113	     xf86PrintEDID(pMonitor);
6114	     xf86SetDDCproperties(pSiS->CRT2pScrn, pMonitor);
6115	     pSiS->CRT2pScrn->monitor->DDC = pMonitor;
6116	     /* Now try to find out aspect ratio */
6117	     SiSFindAspect(pScrn, pMonitor, 2);
6118	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED, ddcestr, 2);
6119	     /* use DDC data if no ranges in config file */
6120	     if(!pSiS->CRT2HSync) {
6121	        pSiS->CRT2pScrn->monitor->nHsync = 0;
6122	     }
6123	     if(!pSiS->CRT2VRefresh) {
6124	        pSiS->CRT2pScrn->monitor->nVrefresh = 0;
6125	     }
6126	  } else {
6127	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
6128		"Failed to read DDC data for CRT2\n");
6129	  }
6130       } else {
6131	  SISErrorLog(pScrn, "Failed to allocate memory for CRT2 monitor, %s.\n",
6132	  		mergeddisstr);
6133	  if(pSiS->CRT2pScrn) free(pSiS->CRT2pScrn);
6134	  pSiS->CRT2pScrn = NULL;
6135	  pSiS->MergedFB = FALSE;
6136       }
6137    }
6138#endif
6139
6140    /* Copy our detected monitor gammas, part 1. Note that device redetection
6141     * is not supported in DHM, so there is no need to do that anytime later.
6142     */
6143#ifdef SISDUALHEAD
6144    if(pSiS->DualHeadMode) {
6145       if(!pSiS->SecondHead) {
6146          /* CRT2: Got gamma for LCD or VGA2 */
6147	  pSiSEnt->CRT2VGAMonitorGamma = pSiS->CRT2VGAMonitorGamma;
6148       } else {
6149          /* CRT1: Got gamma for LCD or VGA */
6150	  pSiSEnt->CRT1VGAMonitorGamma = pSiS->CRT1VGAMonitorGamma;
6151       }
6152       if(pSiS->CRT2LCDMonitorGamma) pSiSEnt->CRT2LCDMonitorGamma = pSiS->CRT2LCDMonitorGamma;
6153    }
6154#endif
6155
6156    /* end of DDC */
6157
6158    /* From here, we mainly deal with clocks and modes */
6159
6160#ifdef SISMERGED
6161    if(pSiS->MergedFB) xf86DrvMsg(pScrn->scrnIndex, X_INFO, crtsetupstr, 1);
6162#endif
6163
6164    /* Set the min pixel clock */
6165    pSiS->MinClock = 5000;
6166    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
6167       pSiS->MinClock = 10000;
6168    }
6169    xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "Min pixel clock is %d MHz\n",
6170                pSiS->MinClock / 1000);
6171
6172    /* If the user has specified ramdac speed in the config
6173     * file, we respect that setting.
6174     */
6175    from = X_PROBED;
6176    if(pSiS->pEnt->device->dacSpeeds[0]) {
6177       int speed = 0;
6178       switch(pScrn->bitsPerPixel) {
6179       case 8:  speed = pSiS->pEnt->device->dacSpeeds[DAC_BPP8];
6180                break;
6181       case 16: speed = pSiS->pEnt->device->dacSpeeds[DAC_BPP16];
6182                break;
6183       case 24: speed = pSiS->pEnt->device->dacSpeeds[DAC_BPP24];
6184                break;
6185       case 32: speed = pSiS->pEnt->device->dacSpeeds[DAC_BPP32];
6186                break;
6187       }
6188       if(speed == 0) pSiS->MaxClock = pSiS->pEnt->device->dacSpeeds[0];
6189       else           pSiS->MaxClock = speed;
6190       from = X_CONFIG;
6191    }
6192    xf86DrvMsg(pScrn->scrnIndex, from, "Max pixel clock is %d MHz\n",
6193                pSiS->MaxClock / 1000);
6194
6195    /*
6196     * Setup the ClockRanges, which describe what clock ranges are available,
6197     * and what sort of modes they can be used for.
6198     */
6199    clockRanges = xnfcalloc(sizeof(ClockRange), 1);
6200    clockRanges->next = NULL;
6201    clockRanges->minClock = pSiS->MinClock;
6202    clockRanges->maxClock = pSiS->MaxClock;
6203    clockRanges->clockIndex = -1;               /* programmable */
6204    clockRanges->interlaceAllowed = TRUE;
6205    clockRanges->doubleScanAllowed = TRUE;
6206
6207    /*
6208     * Since we have lots of built-in modes for 300/315/330/340 series
6209     * with vb support, we replace the given default mode list with our
6210     * own. In case the video bridge is to be used, we only allow other
6211     * modes if
6212     *   -) vbtype is 301, 301B, 301C or 302B, and
6213     *   -) crt2 device is not TV, and
6214     *   -) crt1 is not LCDA, unless bridge is TMDS/LCDA capable (301C)
6215     */
6216    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
6217       if(!(pSiS->noInternalModes)) {
6218          Bool acceptcustommodes = TRUE;  /* Accept user modelines */
6219	  Bool includelcdmodes   = TRUE;  /* Include modes reported by DDC */
6220	  Bool isfordvi          = FALSE; /* Is for digital DVI output */
6221	  Bool IsForCRT2	 = FALSE;
6222	  if(pSiS->UseVESA) {
6223	     acceptcustommodes = FALSE;
6224	     includelcdmodes   = FALSE;
6225	  }
6226#ifdef SISDUALHEAD  /* Dual head is static. Output devices will not change. */
6227	  if(pSiS->DualHeadMode) {
6228	     if(!pSiS->SecondHead) {  /* CRT2: */
6229	        if(pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) {
6230		   if(!(pSiS->VBFlags2 & VB2_30xBDH)) {
6231		      if(!(pSiS->VBFlags & (CRT2_LCD|CRT2_VGA))) includelcdmodes   = FALSE;
6232		      if(pSiS->VBFlags & CRT2_LCD)               isfordvi          = TRUE;
6233		      if(pSiS->VBFlags & CRT2_TV)                acceptcustommodes = FALSE;
6234		   } else {
6235		      if(pSiS->VBFlags & (CRT2_TV|CRT2_LCD)) {
6236		         acceptcustommodes = FALSE;
6237		         includelcdmodes   = FALSE;
6238		      }
6239		   }
6240		} else {
6241		   acceptcustommodes = FALSE;
6242		   includelcdmodes   = FALSE;
6243		}
6244		clockRanges->interlaceAllowed = FALSE;
6245		IsForCRT2 = TRUE;
6246	     } else {		/* CRT1: */
6247	        if(pSiS->VBFlags & CRT1_LCDA) {
6248		   if(!(pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE)) {
6249		      acceptcustommodes = FALSE;
6250		      includelcdmodes   = FALSE;
6251		      /* Will handle i-lace in mode-switching code */
6252		   } else {
6253		      isfordvi = TRUE;
6254		      /* Don't allow i-lace modes */
6255		      clockRanges->interlaceAllowed = FALSE;
6256		   }
6257		} else {
6258		   includelcdmodes = FALSE;
6259		}
6260	     }
6261	  } else
6262#endif
6263#ifdef SISMERGED  /* MergedFB mode is not static. Output devices may change. */
6264          if(pSiS->MergedFB) {
6265	     if(pSiS->VBFlags & CRT1_LCDA) {
6266	        if(!(pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE)) {
6267		   acceptcustommodes = FALSE;
6268		   includelcdmodes   = FALSE;
6269		   /* Will handle i-lace in mode-switching code */
6270		} else {
6271		   isfordvi = TRUE;
6272		   /* Don't allow i-lace custom modes */
6273		   clockRanges->interlaceAllowed = FALSE;
6274		}
6275	     } else {
6276	        includelcdmodes = FALSE;
6277	     }
6278          } else
6279#endif		 /* Mirror mode is not static. Output devices may change. */
6280          if(pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) {
6281	     if(!(pSiS->VBFlags2 & VB2_30xBDH)) {
6282		if(!(pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE)) {
6283		   if(!(pSiS->VBFlags & (CRT2_LCD|CRT2_VGA))) includelcdmodes = FALSE;
6284		   if(pSiS->VBFlags & CRT2_LCD)               isfordvi        = TRUE;
6285		} else {
6286		   if(!(pSiS->VBFlags & (CRT2_LCD|CRT2_VGA|CRT1_LCDA))) includelcdmodes = FALSE;
6287		   if(pSiS->VBFlags & (CRT2_LCD|CRT1_LCDA))             isfordvi        = TRUE;
6288		}
6289		if((!(pSiS->VBFlags & DISPTYPE_CRT1)) && (!(pSiS->VBFlags & CRT1_LCDA))) {
6290		   IsForCRT2 = TRUE;
6291		}
6292		/* Allow user modes, even if CRT2 is TV. Will be filtered through ValidMode();
6293		 * leaving the user modes here might have the advantage that such a mode, if
6294		 * it matches in resolution with a supported TV mode, allows us to drive eg.
6295		 * non standard panels, and still permits switching to TV. This mode will be
6296		 * "mapped" to a supported mode of identical resolution for TV. All this is
6297		 * taken care of by ValidMode() and ModeInit()/PresetMode().
6298		 */
6299	     } else {
6300		if(pSiS->VBFlags & (CRT2_TV|CRT2_LCD)) {
6301		   acceptcustommodes = FALSE;
6302		   includelcdmodes   = FALSE;
6303		   if(!(pSiS->VBFlags & DISPTYPE_CRT1)) {
6304		      IsForCRT2 = TRUE;
6305		   }
6306		}
6307	     }
6308	  } else if(pSiS->VBFlags & (CRT2_ENABLE | CRT1_LCDA)) {
6309	     acceptcustommodes = FALSE;
6310	     includelcdmodes   = FALSE;
6311	     if((pSiS->VBFlags & CRT1_LCDA) || (!(pSiS->VBFlags & DISPTYPE_CRT1))) {
6312		IsForCRT2 = TRUE;
6313	     }
6314	  } else {
6315	     includelcdmodes   = FALSE;
6316	  }
6317	  /* Ignore interlace, mode switching code will handle this */
6318
6319	  pSiS->HaveCustomModes = FALSE;
6320	  if(SiSMakeOwnModeList(pScrn, acceptcustommodes, includelcdmodes,
6321			isfordvi, &pSiS->HaveCustomModes, FALSE, IsForCRT2)) {
6322	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6323		 "Replaced %s mode list with built-in modes\n",
6324	     pSiS->HaveCustomModes ? "default" : "entire");
6325	     if(pSiS->VGAEngine == SIS_315_VGA) {
6326		int UseWide = pSiS->SiS_Pr->SiS_UseWide;
6327		if(IsForCRT2) UseWide = pSiS->SiS_Pr->SiS_UseWideCRT2;
6328		if((!IsForCRT2) || (pSiS->VBFlags2 & VB2_SISVGA2BRIDGE)) {
6329		   xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6330			"Using %s widescreen modes for CRT%d VGA devices\n",
6331			UseWide ? "real" : "fake", IsForCRT2 ? 2 : 1);
6332		   xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6333			"\tUse option \"ForceCRT%dVGAAspect\" to overrule\n",
6334			IsForCRT2 ? 2 : 1);
6335		}
6336	     }
6337#ifdef TWDEBUG
6338             pScrn->modes = pScrn->monitor->Modes;
6339	     xf86PrintModes(pScrn);
6340	     pScrn->modes = NULL;
6341#endif
6342          } else {
6343	     xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
6344		"Building list of built-in modes failed, using server defaults\n");
6345	  }
6346       } else {
6347          pSiS->HaveCustomModes = TRUE;
6348       }
6349    }
6350
6351    /* Add our built-in hi-res and TV modes on the 6326 */
6352    if(pSiS->Chipset == PCI_CHIP_SIS6326) {
6353       if(pScrn->bitsPerPixel == 8) {
6354	  SiS6326SIS1600x1200_60Mode.next = pScrn->monitor->Modes;
6355	  pScrn->monitor->Modes = &SiS6326SIS1600x1200_60Mode;
6356	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6357	  	"Adding mode \"SIS1600x1200-60\" (depth 8 only)\n");
6358       }
6359       if(pScrn->bitsPerPixel <= 16) {
6360	  SiS6326SIS1280x1024_75Mode.next = pScrn->monitor->Modes;
6361	  pScrn->monitor->Modes = &SiS6326SIS1280x1024_75Mode;
6362	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6363	  	"Adding mode \"SIS1280x1024-75\" (depths 8, 15 and 16 only)\n");
6364       }
6365       if((pSiS->SiS6326Flags & SIS6326_HASTV) &&
6366	  (pSiS->SiS6326Flags & SIS6326_TVDETECTED)) {
6367	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6368		"Adding %s TV modes to mode list:\n",
6369		(pSiS->SiS6326Flags & SIS6326_TVPAL) ? "PAL" : "NTSC");
6370	  if(pSiS->SiS6326Flags & SIS6326_TVPAL) {
6371	     SiS6326PAL800x600Mode.next = pScrn->monitor->Modes;
6372	     pScrn->monitor->Modes = &SiS6326PAL640x480Mode;
6373	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6374		"\t\"PAL800x600\" \"PAL800x600U\" \"PAL720x540\" \"PAL640x480\"\n");
6375	  } else {
6376	     SiS6326NTSC640x480Mode.next = pScrn->monitor->Modes;
6377	     pScrn->monitor->Modes = &SiS6326NTSC640x400Mode;
6378	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6379		"\t\"NTSC640x480\" \"NTSC640x480U\" \"NTSC640x400\"\n");
6380	  }
6381       }
6382    }
6383
6384   /* If there is no HSync or VRefresh data for the monitor,
6385    * derive it from DDC data. Essentially done by common layer
6386    * since 4.3.99.14, but this is not usable since it is done
6387    * too late (in ValidateModes()).
6388    * Addendum: I overrule the ranges now in any case unless
6389    * it would affect a CRT output device or DDC data is available.
6390    * Hence, for LCD(A) and TV, we always get proper ranges. This
6391    * is entirely harmless. However, option "NoOverruleRanges" will
6392    * disable this behavior.
6393    * This should "fix" the - by far - most common configuration
6394    * mistakes.
6395    */
6396
6397    crt1freqoverruled = FALSE;
6398
6399    fromDDC = FALSE;
6400    if((pScrn->monitor->nHsync <= 0) || (pSiS->OverruleRanges)) {
6401       if((pScrn->monitor->nHsync <= 0) && (pScrn->monitor->DDC)) {
6402	  SiSSetSyncRangeFromEdid(pScrn, 1);
6403	  if(pScrn->monitor->nHsync > 0) {
6404	     xf86DrvMsg(pScrn->scrnIndex, X_INFO, subshstr,
6405#ifdef SISDUALHEAD
6406			pSiS->DualHeadMode ? (pSiS->SecondHead ? 1 : 2) :
6407#endif
6408				pSiS->CRT1off ? 2 : 1);
6409	     fromDDC = TRUE;
6410	  }
6411       }
6412       if((pScrn->monitor->nHsync <= 0) || (pSiS->OverruleRanges)) {
6413	  if(SiSAllowSyncOverride(pSiS, fromDDC)) {
6414	     Bool HaveNoRanges = (pScrn->monitor->nHsync <= 0);
6415	     /* Set sane ranges for LCD and TV
6416	      * (our strict checking will filter out invalid ones anyway)
6417	      */
6418	     if((crt1freqoverruled = CheckAndOverruleH(pScrn, pScrn->monitor))) {
6419		xf86DrvMsg(pScrn->scrnIndex, X_INFO, saneh,
6420			HaveNoRanges ? "missing" : "bogus",
6421#ifdef SISDUALHEAD
6422			pSiS->DualHeadMode ? (pSiS->SecondHead ? 1 : 2) :
6423#endif
6424				pSiS->CRT1off ? 2 : 1);
6425	     }
6426	  }
6427       }
6428    }
6429
6430    fromDDC = FALSE;
6431    if((pScrn->monitor->nVrefresh <= 0) || (pSiS->OverruleRanges)) {
6432       if((pScrn->monitor->nVrefresh <= 0) && (pScrn->monitor->DDC)) {
6433	  SiSSetSyncRangeFromEdid(pScrn, 0);
6434	  if(pScrn->monitor->nVrefresh > 0) {
6435	     xf86DrvMsg(pScrn->scrnIndex, X_INFO, subsvstr,
6436#ifdef SISDUALHEAD
6437			pSiS->DualHeadMode ? (pSiS->SecondHead ? 1 : 2) :
6438#endif
6439				pSiS->CRT1off ? 2 : 1);
6440	     fromDDC = TRUE;
6441          }
6442       }
6443       if((pScrn->monitor->nVrefresh <= 0) || (pSiS->OverruleRanges)) {
6444	  if(SiSAllowSyncOverride(pSiS, fromDDC)) {
6445	     Bool HaveNoRanges = (pScrn->monitor->nVrefresh <= 0);
6446	     /* Set sane ranges for LCD and TV */
6447	     if((crt1freqoverruled = CheckAndOverruleV(pScrn, pScrn->monitor))) {
6448		xf86DrvMsg(pScrn->scrnIndex, X_INFO, sanev,
6449			HaveNoRanges ? "missing" : "bogus",
6450#ifdef SISDUALHEAD
6451			pSiS->DualHeadMode ? (pSiS->SecondHead ? 1 : 2) :
6452#endif
6453				pSiS->CRT1off ? 2 : 1);
6454	     }
6455	  }
6456       }
6457    }
6458
6459    if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
6460       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6461	  "\"Unknown reason\" in the following list means that the mode\n");
6462       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6463	  "is not supported on the chipset/bridge/current output device.\n");
6464    }
6465
6466    /*
6467     * xf86ValidateModes will check that the mode HTotal and VTotal values
6468     * don't exceed the chipset's limit if pScrn->maxHValue and
6469     * pScrn->maxVValue are set.  Since our SISValidMode() already takes
6470     * care of this, we don't worry about setting them here.
6471     */
6472
6473    /* Select valid modes from those available */
6474    /*
6475     * Assuming min pitch 256, min height 128
6476     */
6477    {
6478       int minpitch, maxpitch, minheight, maxheight;
6479       pointer backupddc = pScrn->monitor->DDC;
6480
6481       minpitch = 256;
6482       minheight = 128;
6483       switch(pSiS->VGAEngine) {
6484       case SIS_OLD_VGA:
6485       case SIS_530_VGA:
6486          maxpitch = 2040;
6487          maxheight = 2048;
6488          break;
6489       case SIS_300_VGA:
6490       case SIS_315_VGA:
6491          maxpitch = 4088;
6492          maxheight = 4096;
6493          break;
6494       default:
6495          maxpitch = 2048;
6496          maxheight = 2048;
6497          break;
6498       }
6499
6500#ifdef SISMERGED
6501       pSiS->CheckForCRT2 = FALSE;
6502#endif
6503
6504       /* Suppress bogus DDC warning */
6505       if(crt1freqoverruled) pScrn->monitor->DDC = NULL;
6506
6507       i = xf86ValidateModes(pScrn, pScrn->monitor->Modes,
6508			pScrn->display->modes, clockRanges, NULL,
6509			minpitch, maxpitch,
6510			pScrn->bitsPerPixel * 8,
6511			minheight, maxheight,
6512			pScrn->display->virtualX,
6513			pScrn->display->virtualY,
6514			pSiS->maxxfbmem,
6515			LOOKUP_BEST_REFRESH);
6516
6517       pScrn->monitor->DDC = backupddc;
6518    }
6519
6520    if(i == -1) {
6521       SISErrorLog(pScrn, "xf86ValidateModes() error\n");
6522       goto my_error_1;
6523    }
6524
6525    /* Check the virtual screen against the available memory */
6526    {
6527       ULong memreq = (pScrn->virtualX * ((pScrn->bitsPerPixel + 7) / 8)) * pScrn->virtualY;
6528
6529       if(memreq > pSiS->maxxfbmem) {
6530	  SISErrorLog(pScrn,
6531	     "Virtual screen too big for memory; %ldK needed, %ldK available\n",
6532	     memreq/1024, pSiS->maxxfbmem/1024);
6533	  goto my_error_1;
6534       }
6535    }
6536
6537    /* Dual Head:
6538     * -) Go through mode list and mark all those modes as bad,
6539     *    which are unsuitable for dual head mode.
6540     * -) Find the highest used pixelclock on the master head.
6541     */
6542#ifdef SISDUALHEAD
6543    if((pSiS->DualHeadMode) && (!pSiS->SecondHead)) {
6544
6545       pSiSEnt->maxUsedClock = 0;
6546
6547       if((p = first = pScrn->modes)) {
6548
6549	  do {
6550
6551	     n = p->next;
6552
6553	     /* Modes that require the bridge to operate in SlaveMode
6554	      * are not suitable for Dual Head mode.
6555	      */
6556	     if( (pSiS->VGAEngine == SIS_300_VGA) &&
6557		 ( (strcmp(p->name, "320x200") == 0) ||
6558		   (strcmp(p->name, "320x240") == 0) ||
6559		   (strcmp(p->name, "400x300") == 0) ||
6560		   (strcmp(p->name, "512x384") == 0) ||
6561		   (strcmp(p->name, "640x400") == 0) ) )  {
6562		p->status = MODE_BAD;
6563		xf86DrvMsg(pScrn->scrnIndex, X_INFO, notsuitablestr, p->name, "dual head");
6564	     }
6565
6566	     /* Search for the highest clock on first head in order to calculate
6567	      * max clock for second head (CRT1)
6568	      */
6569	     if((p->status == MODE_OK) && (p->Clock > pSiSEnt->maxUsedClock)) {
6570		pSiSEnt->maxUsedClock = p->Clock;
6571	     }
6572
6573	     p = n;
6574
6575	  } while (p != NULL && p != first);
6576
6577       }
6578    }
6579#endif
6580
6581    /* Prune the modes marked as invalid */
6582    xf86PruneDriverModes(pScrn);
6583
6584    if(i == 0 || pScrn->modes == NULL) {
6585       SISErrorLog(pScrn, "No valid modes found - check VertRefresh/HorizSync\n");
6586       goto my_error_1;
6587    }
6588
6589    xf86SetCrtcForModes(pScrn, INTERLACE_HALVE_V);
6590
6591    /* Set the current mode to the first in the list */
6592    pScrn->currentMode = pScrn->modes;
6593
6594    /* Copy to CurrentLayout */
6595    pSiS->CurrentLayout.mode = pScrn->currentMode;
6596    pSiS->CurrentLayout.displayWidth = pScrn->displayWidth;
6597    pSiS->CurrentLayout.displayHeight = pScrn->virtualY;
6598
6599#ifdef SISMERGED
6600    if(pSiS->MergedFB) {
6601       xf86DrvMsg(pScrn->scrnIndex, X_INFO, modesforstr, 1);
6602    }
6603#endif
6604
6605    /* Print the list of modes being used */
6606    {
6607       Bool usemyprint = FALSE;
6608
6609#ifdef SISDUALHEAD
6610       if(pSiS->DualHeadMode) {
6611	  if(pSiS->SecondHead) {
6612	     if(pSiS->VBFlags & CRT1_LCDA) usemyprint = TRUE;
6613	  } else {
6614	     if(pSiS->VBFlags & (CRT2_LCD | CRT2_TV)) usemyprint = TRUE;
6615	  }
6616       } else
6617#endif
6618#ifdef SISMERGED
6619       if(pSiS->MergedFB) {
6620	  if(pSiS->VBFlags & CRT1_LCDA) usemyprint = TRUE;
6621       } else
6622#endif
6623       {
6624	  if( (pSiS->VBFlags & (CRT2_LCD | CRT2_TV)) &&
6625	      (!(pSiS->VBFlags & DISPTYPE_DISP1)) )
6626	     usemyprint = TRUE;
6627       }
6628
6629       if(usemyprint) {
6630	  SiSPrintModes(pScrn);
6631       } else {
6632	  xf86PrintModes(pScrn);
6633       }
6634    }
6635
6636#ifdef SISMERGED
6637    if(pSiS->MergedFB) {
6638       Bool acceptcustommodes = TRUE;
6639       Bool includelcdmodes   = TRUE;
6640       Bool isfordvi          = FALSE;
6641
6642       xf86DrvMsg(pScrn->scrnIndex, X_INFO, crtsetupstr, 2);
6643
6644       clockRanges->next = NULL;
6645       clockRanges->minClock = pSiS->MinClock;
6646       clockRanges->maxClock = SiSMemBandWidth(pSiS->CRT2pScrn, TRUE);
6647       clockRanges->clockIndex = -1;
6648       clockRanges->interlaceAllowed = FALSE;
6649       clockRanges->doubleScanAllowed = FALSE;
6650       if(pSiS->VGAEngine == SIS_315_VGA) {
6651          clockRanges->doubleScanAllowed = TRUE;
6652       }
6653
6654       xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "Min pixel clock for CRT2 is %d MHz\n",
6655                clockRanges->minClock / 1000);
6656       xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "Max pixel clock for CRT2 is %d MHz\n",
6657                clockRanges->maxClock / 1000);
6658
6659       if(pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) {
6660          if(!(pSiS->VBFlags2 & VB2_30xBDH)) {
6661             if(!(pSiS->VBFlags & (CRT2_LCD|CRT2_VGA))) includelcdmodes   = FALSE;
6662	     if(pSiS->VBFlags & CRT2_LCD)               isfordvi          = TRUE;
6663	     /* See above for a remark on handling CRT2 = TV */
6664	  } else {
6665	     if(pSiS->VBFlags & (CRT2_LCD|CRT2_TV)) {
6666		includelcdmodes   = FALSE;
6667		acceptcustommodes = FALSE;
6668	     }
6669	  }
6670       } else {
6671	  includelcdmodes   = FALSE;
6672	  acceptcustommodes = FALSE;
6673       }
6674
6675       pSiS->HaveCustomModes2 = FALSE;
6676       if(!SiSMakeOwnModeList(pSiS->CRT2pScrn, acceptcustommodes, includelcdmodes,
6677				isfordvi, &pSiS->HaveCustomModes2, FALSE, TRUE )) {
6678
6679	  SISErrorLog(pScrn, "Building list of built-in modes for CRT2 failed, %s\n",
6680				mergeddisstr);
6681	  SiSFreeCRT2Structs(pSiS);
6682	  pSiS->MergedFB = FALSE;
6683
6684       } else {
6685	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6686		 "Replaced %s mode list for CRT2 with built-in modes\n",
6687		 pSiS->HaveCustomModes2 ? "default" : "entire");
6688	  if((pSiS->VGAEngine == SIS_315_VGA) && (pSiS->VBFlags2 & VB2_SISVGA2BRIDGE)) {
6689	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6690		 "Using %s widescreen modes for CRT2 VGA devices\n",
6691		 pSiS->SiS_Pr->SiS_UseWideCRT2 ? "real" : "fake");
6692	  } else pSiS->SiS_Pr->SiS_UseWideCRT2 = 0;
6693       }
6694
6695    }
6696
6697    if(pSiS->MergedFB) {
6698
6699       pointer backupddc;
6700
6701       crt2freqoverruled = FALSE;
6702
6703       fromDDC = FALSE;
6704       if((pSiS->CRT2pScrn->monitor->nHsync <= 0) || (pSiS->OverruleRanges)) {
6705          if((pSiS->CRT2pScrn->monitor->nHsync <= 0) && (pSiS->CRT2pScrn->monitor->DDC)) {
6706	     SiSSetSyncRangeFromEdid(pSiS->CRT2pScrn, 1);
6707	     if(pSiS->CRT2pScrn->monitor->nHsync > 0) {
6708		xf86DrvMsg(pScrn->scrnIndex, X_INFO, subshstr, 2);
6709		fromDDC = TRUE;
6710	     }
6711	  }
6712	  if((pSiS->CRT2pScrn->monitor->nHsync <= 0) || (pSiS->OverruleRanges)) {
6713	     if( (pSiS->VBFlags & CRT2_TV) ||
6714	         ((pSiS->VBFlags & CRT2_LCD) && (!fromDDC)) ) {
6715		Bool HaveNoRanges = (pSiS->CRT2pScrn->monitor->nHsync <= 0);
6716		/* Set sane ranges for LCD and TV */
6717		if((crt2freqoverruled = CheckAndOverruleH(pScrn, pSiS->CRT2pScrn->monitor))) {
6718		   xf86DrvMsg(pScrn->scrnIndex, X_INFO, saneh,
6719			HaveNoRanges ? "missing" : "bogus", 2);
6720		}
6721	     }
6722	  }
6723       }
6724
6725       fromDDC = FALSE;
6726       if((pSiS->CRT2pScrn->monitor->nVrefresh <= 0) || (pSiS->OverruleRanges)) {
6727	  if((pSiS->CRT2pScrn->monitor->nVrefresh <= 0) && (pSiS->CRT2pScrn->monitor->DDC)) {
6728	     SiSSetSyncRangeFromEdid(pSiS->CRT2pScrn, 0);
6729	     if(pSiS->CRT2pScrn->monitor->nVrefresh > 0) {
6730		xf86DrvMsg(pScrn->scrnIndex, X_INFO, subsvstr, 2);
6731		fromDDC = TRUE;
6732	     }
6733          }
6734	  if((pSiS->CRT2pScrn->monitor->nVrefresh <= 0) || (pSiS->OverruleRanges)) {
6735	     if( (pSiS->VBFlags & CRT2_TV) ||
6736	         ((pSiS->VBFlags & CRT2_LCD) && (!fromDDC)) ) {
6737		Bool HaveNoRanges = (pSiS->CRT2pScrn->monitor->nVrefresh <= 0);
6738		/* Set sane ranges for LCD and TV */
6739		if((crt2freqoverruled = CheckAndOverruleV(pScrn, pSiS->CRT2pScrn->monitor))) {
6740		   xf86DrvMsg(pScrn->scrnIndex, X_INFO, sanev,
6741			 HaveNoRanges ? "missing" : "bogus", 2);
6742	        }
6743	     }
6744	  }
6745       }
6746
6747       backupddc = pSiS->CRT2pScrn->monitor->DDC;
6748
6749       /* Suppress bogus DDC warning */
6750       if(crt2freqoverruled) pSiS->CRT2pScrn->monitor->DDC = NULL;
6751
6752       pSiS->CheckForCRT2 = TRUE;
6753
6754       i = xf86ValidateModes(pSiS->CRT2pScrn, pSiS->CRT2pScrn->monitor->Modes,
6755			pSiS->CRT2pScrn->display->modes, clockRanges,
6756			NULL, 256, 4088,
6757			pSiS->CRT2pScrn->bitsPerPixel * 8, 128, 4096,
6758			pScrn->display->virtualX ? pScrn->virtualX : 0,
6759			pScrn->display->virtualY ? pScrn->virtualY : 0,
6760			pSiS->maxxfbmem,
6761			LOOKUP_BEST_REFRESH);
6762
6763       pSiS->CheckForCRT2 = FALSE;
6764       pSiS->CRT2pScrn->monitor->DDC = backupddc;
6765
6766       if(i == -1) {
6767	  SISErrorLog(pScrn, "xf86ValidateModes() error, %s.\n", mergeddisstr);
6768	  SiSFreeCRT2Structs(pSiS);
6769	  pSiS->MergedFB = FALSE;
6770       }
6771
6772    }
6773
6774    if(pSiS->MergedFB) {
6775
6776       if((p = first = pSiS->CRT2pScrn->modes)) {
6777          do {
6778	     n = p->next;
6779	     if( (pSiS->VGAEngine == SIS_300_VGA) &&
6780		 ( (strcmp(p->name, "320x200") == 0) ||
6781		   (strcmp(p->name, "320x240") == 0) ||
6782		   (strcmp(p->name, "400x300") == 0) ||
6783		   (strcmp(p->name, "512x384") == 0) ||
6784		   (strcmp(p->name, "640x400") == 0) ) )  {
6785		p->status = MODE_BAD;
6786		xf86DrvMsg(pScrn->scrnIndex, X_INFO, notsuitablestr, p->name, "MergedFB");
6787	     }
6788	     p = n;
6789	  } while (p != NULL && p != first);
6790       }
6791
6792       xf86PruneDriverModes(pSiS->CRT2pScrn);
6793
6794       if(i == 0 || pSiS->CRT2pScrn->modes == NULL) {
6795	  SISErrorLog(pScrn, "No valid modes found for CRT2; %s\n", mergeddisstr);
6796	  SiSFreeCRT2Structs(pSiS);
6797	  pSiS->MergedFB = FALSE;
6798       }
6799
6800    }
6801
6802    if(pSiS->MergedFB) {
6803
6804       xf86SetCrtcForModes(pSiS->CRT2pScrn, INTERLACE_HALVE_V);
6805
6806       xf86DrvMsg(pScrn->scrnIndex, X_INFO, modesforstr, 2);
6807
6808       if(pSiS->VBFlags & (CRT2_LCD | CRT2_TV)) {
6809	  SiSPrintModes(pSiS->CRT2pScrn);
6810       } else {
6811	  xf86PrintModes(pSiS->CRT2pScrn);
6812       }
6813
6814       pSiS->CRT1Modes = pScrn->modes;
6815       pSiS->CRT1CurrentMode = pScrn->currentMode;
6816
6817       xf86DrvMsg(pScrn->scrnIndex, X_INFO, "MergedFB: Generating mode list\n");
6818
6819       pScrn->modes = SiSGenerateModeList(pScrn, pSiS->MetaModes,
6820					  pSiS->CRT1Modes, pSiS->CRT2pScrn->modes,
6821					  pSiS->CRT2Position);
6822
6823       if(!pScrn->modes) {
6824
6825	  SISErrorLog(pScrn, "Failed to parse MetaModes or no modes found. %s.\n",
6826			mergeddisstr);
6827	  SiSFreeCRT2Structs(pSiS);
6828	  pScrn->modes = pSiS->CRT1Modes;
6829	  pSiS->CRT1Modes = NULL;
6830	  pSiS->MergedFB = FALSE;
6831
6832       }
6833
6834    }
6835
6836    if(pSiS->MergedFB) {
6837
6838       /* If no virtual dimension was given by the user,
6839	* calculate a sane one now. Adapts pScrn->virtualX,
6840	* pScrn->virtualY and pScrn->displayWidth.
6841	*/
6842       SiSRecalcDefaultVirtualSize(pScrn);
6843
6844       pScrn->modes = pScrn->modes->next;  /* We get the last from GenerateModeList(), skip to first */
6845       pScrn->currentMode = pScrn->modes;
6846
6847       /* Update CurrentLayout */
6848       pSiS->CurrentLayout.mode = pScrn->currentMode;
6849       pSiS->CurrentLayout.displayWidth = pScrn->displayWidth;
6850       pSiS->CurrentLayout.displayHeight = pScrn->virtualY;
6851
6852    }
6853#endif
6854
6855    /* Set display resolution */
6856#ifdef SISMERGED
6857    if(pSiS->MergedFB) {
6858       SiSMergedFBSetDpi(pScrn, pSiS->CRT2pScrn, pSiS->CRT2Position);
6859    } else
6860#endif
6861       xf86SetDpi(pScrn, 0, 0);
6862
6863    /* Load fb module */
6864    switch(pScrn->bitsPerPixel) {
6865      case 8:
6866      case 16:
6867      case 24:
6868      case 32:
6869	if(!xf86LoadSubModule(pScrn, "fb")) {
6870           SISErrorLog(pScrn, "Failed to load fb module");
6871	   goto my_error_1;
6872	}
6873	break;
6874      default:
6875	SISErrorLog(pScrn, "Unsupported framebuffer bpp (%d)\n", pScrn->bitsPerPixel);
6876	goto my_error_1;
6877    }
6878
6879    /* Load XAA/EXA (if needed) */
6880    if(!pSiS->NoAccel) {
6881#ifdef SIS_USE_XAA
6882       if(!pSiS->useEXA) {
6883	  if (!xf86LoadSubModule(pScrn, "xaa")) {
6884	      xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6885			 "Falling back to shadowfb\n");
6886	      pSiS->NoAccel = 1;
6887	      pSiS->ShadowFB = 1;
6888	  }
6889       }
6890#endif
6891#ifdef SIS_USE_EXA
6892       if(pSiS->useEXA) {
6893	  XF86ModReqInfo req;
6894	  int errmaj, errmin;
6895
6896	  memset(&req, 0, sizeof(req));
6897	  req.majorversion = 2;
6898	  req.minorversion = 0;
6899	  if (!LoadSubModule(pScrn->module, "exa", NULL, NULL, NULL, &req,
6900	    &errmaj, &errmin)) {
6901	    LoaderErrorMsg(NULL, "exa", errmaj, errmin);
6902	    goto my_error_1;
6903	  }
6904       }
6905#endif
6906    }
6907
6908    /* Load shadowfb (if needed) */
6909    if(pSiS->ShadowFB) {
6910       if(!xf86LoadSubModule(pScrn, "shadowfb")) {
6911	  SISErrorLog(pScrn, "Could not load shadowfb module\n");
6912	  goto my_error_1;
6913       }
6914    }
6915
6916    /* Load the dri modules if requested. */
6917#ifdef SISDRI
6918    if(pSiS->loadDRI) {
6919       if(!xf86LoaderCheckSymbol("DRIScreenInit")) {
6920	  if(!xf86LoadSubModule(pScrn, "dri")) {
6921	     SISErrorLog(pScrn, "Failed to load dri module\n");
6922	  }
6923       }
6924    }
6925#endif
6926
6927    /* Now load and initialize VBE module for VESA mode switching */
6928    pSiS->UseVESA = 0;
6929    if(pSiS->VESA == 1) {
6930       SiS_LoadInitVBE(pScrn);
6931       if(pSiS->pVbe) {
6932	  VbeInfoBlock *vbe;
6933	  if((vbe = VBEGetVBEInfo(pSiS->pVbe))) {
6934	     pSiS->vesamajor = (unsigned)(vbe->VESAVersion >> 8);
6935	     pSiS->vesaminor = vbe->VESAVersion & 0xff;
6936	     SiSBuildVesaModeList(pScrn, pSiS->pVbe, vbe);
6937	     VBEFreeVBEInfo(vbe);
6938	     pSiS->UseVESA = 1;
6939	  } else {
6940	     xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
6941	     	 "Failed to read VBE Info Block\n");
6942	  }
6943       }
6944       if(pSiS->UseVESA == 0) {
6945	  xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
6946	      "VESA mode switching disabled.\n");
6947       }
6948    }
6949
6950    if(pSiS->pVbe) {
6951       vbeFree(pSiS->pVbe);
6952       pSiS->pVbe = NULL;
6953    }
6954
6955#ifdef SISDUALHEAD
6956    xf86SetPrimInitDone(pScrn->entityList[0]);
6957#endif
6958
6959    sisRestoreExtRegisterLock(pSiS,srlockReg,crlockReg);
6960
6961    if(pSiS->pInt) xf86FreeInt10(pSiS->pInt);
6962    pSiS->pInt = NULL;
6963
6964    if(pSiS->VGAEngine == SIS_315_VGA) {
6965       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTXVGAMMA1;
6966    }
6967
6968#ifdef SISDUALHEAD
6969    if(pSiS->DualHeadMode) {
6970	pSiS->SiS_SD_Flags |= SiS_SD_ISDUALHEAD;
6971	if(pSiS->SecondHead) pSiS->SiS_SD_Flags |= SiS_SD_ISDHSECONDHEAD;
6972	else		     pSiS->SiS_SD_Flags &= ~(SiS_SD_SUPPORTXVGAMMA1);
6973#ifdef PANORAMIX
6974	if(!noPanoramiXExtension) {
6975	   pSiS->SiS_SD_Flags |= SiS_SD_ISDHXINERAMA;
6976	   /* pSiS->SiS_SD_Flags &= ~(SiS_SD_SUPPORTXVGAMMA1); */
6977	}
6978#endif
6979    }
6980#endif
6981
6982#ifdef SISMERGED
6983    if(pSiS->MergedFB) pSiS->SiS_SD_Flags |= SiS_SD_ISMERGEDFB;
6984#endif
6985
6986    /* Try to determine if this is a laptop   */
6987    /* (only used for SiSCtrl visualisations) */
6988    pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPLTFLAG;
6989    pSiS->SiS_SD2_Flags &= ~SiS_SD2_ISLAPTOP;
6990    if(pSiS->detectedCRT2Devices & CRT2_LCD) {
6991       if(pSiS->VBFlags2 & (VB2_SISLVDSBRIDGE | VB2_LVDS | VB2_30xBDH)) {
6992	  /* 1. By bridge type: LVDS in 99% of all cases;
6993	   * exclude unusual setups like Barco projectors
6994	   * and parallel flat panels. TODO: Exclude
6995	   * Sony W1, V1.
6996	   */
6997	  if((pSiS->SiS_Pr->SiS_CustomT != CUT_BARCO1366) &&
6998	     (pSiS->SiS_Pr->SiS_CustomT != CUT_BARCO1024) &&
6999	     (pSiS->SiS_Pr->SiS_CustomT != CUT_PANEL848)  &&
7000	     (pSiS->SiS_Pr->SiS_CustomT != CUT_PANEL856)  &&
7001	     (pSiS->SiS_Pr->SiS_CustomT != CUT_AOP8060)   &&
7002	     ( (pSiS->ChipType != SIS_550) ||
7003	       (!pSiS->DSTN && !pSiS->FSTN) ) ) {
7004	     pSiS->SiS_SD2_Flags |= SiS_SD2_ISLAPTOP;
7005	  }
7006       } else if((pSiS->VBFlags2 & (VB2_301 | VB2_301C)) &&
7007                 (pSiS->VBLCDFlags & (VB_LCD_1280x960  |
7008				      VB_LCD_1400x1050 |
7009				      VB_LCD_1024x600  |
7010				      VB_LCD_1280x800  |
7011				      VB_LCD_1280x854))) {
7012	  /* 2. By (odd) LCD resolutions on TMDS bridges
7013	   * (eg Averatec). TODO: Exclude IBM Netvista.
7014	   */
7015	  pSiS->SiS_SD2_Flags |= SiS_SD2_ISLAPTOP;
7016       }
7017    }
7018
7019    if(pSiS->enablesisctrl) pSiS->SiS_SD_Flags |= SiS_SD_ENABLED;
7020
7021    pSiS->currentModeLast = pScrn->currentMode;
7022    pSiS->VBFlagsInit = pSiS->VBFlags;
7023
7024    return TRUE;
7025
7026    /* ---- */
7027
7028my_error_1:
7029    sisRestoreExtRegisterLock(pSiS, srlockReg, crlockReg);
7030my_error_0:
7031#ifdef SISDUALHEAD
7032    if(pSiSEnt) pSiSEnt->ErrorAfterFirst = TRUE;
7033#endif
7034    if(pSiS->pInt) xf86FreeInt10(pSiS->pInt);
7035    pSiS->pInt = NULL;
7036    SISFreeRec(pScrn);
7037    return FALSE;
7038}
7039
7040/*
7041 * Map I/O port area for non-PC platforms
7042 */
7043#ifdef SIS_NEED_MAP_IOP
7044static Bool
7045SISMapIOPMem(ScrnInfoPtr pScrn)
7046{
7047    SISPtr pSiS = SISPTR(pScrn);
7048#ifdef SISDUALHEAD
7049    SISEntPtr pSiSEnt = pSiS->entityPrivate;
7050
7051    if(pSiS->DualHeadMode) {
7052        pSiSEnt->MapCountIOPBase++;
7053        if(!(pSiSEnt->IOPBase)) {
7054	     /* Only map if not mapped previously */
7055#ifndef XSERVER_LIBPCIACCESS
7056	     pSiSEnt->IOPBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
7057			pSiS->PciTag, pSiS->IOPAddress, 128);
7058#else
7059	     {
7060	       void **result = (void **)&pSiSEnt->IOPBase;
7061	       int err = pci_device_map_range(pSiS->PciInfo,
7062					      pSiS->IOPAddress,
7063					      128,
7064					      PCI_DEV_MAP_FLAG_WRITABLE,
7065					      result);
7066
7067	       if (err) {
7068                 xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
7069                             "Unable to map IO aperture. %s (%d)\n",
7070                             strerror (err), err);
7071	       }
7072	     }
7073#endif
7074        }
7075        pSiS->IOPBase = pSiSEnt->IOPBase;
7076    } else
7077#endif
7078#ifndef XSERVER_LIBPCIACCESS
7079	     pSiS->IOPBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
7080					   pSiS->PciTag, pSiS->IOPAddress, 128);
7081#else
7082	     {
7083	       void **result = (void **)&pSiS->IOPBase;
7084	       int err = pci_device_map_range(pSiS->PciInfo,
7085					      pSiS->IOPAddress,
7086					      128,
7087					      PCI_DEV_MAP_FLAG_WRITABLE,
7088					      result);
7089
7090	       if (err) {
7091                 xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
7092                             "Unable to map IO aperture. %s (%d)\n",
7093                             strerror (err), err);
7094	       }
7095	     }
7096#endif
7097    if(pSiS->IOPBase == NULL) {
7098	SISErrorLog(pScrn, "Could not map I/O port area\n");
7099	return FALSE;
7100    }
7101
7102    return TRUE;
7103}
7104
7105static Bool
7106SISUnmapIOPMem(ScrnInfoPtr pScrn)
7107{
7108    SISPtr pSiS = SISPTR(pScrn);
7109#ifdef SISDUALHEAD
7110    SISEntPtr pSiSEnt = pSiS->entityPrivate;;
7111#endif
7112
7113/* In dual head mode, we must not unmap if the other head still
7114 * assumes memory as mapped
7115 */
7116#ifdef SISDUALHEAD
7117    if(pSiS->DualHeadMode) {
7118        if(pSiSEnt->MapCountIOPBase) {
7119	    pSiSEnt->MapCountIOPBase--;
7120	    if((pSiSEnt->MapCountIOPBase == 0) || (pSiSEnt->forceUnmapIOPBase)) {
7121		xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiSEnt->IOPBase, 2048);
7122		pSiSEnt->IOPBase = NULL;
7123		pSiSEnt->MapCountIOPBase = 0;
7124		pSiSEnt->forceUnmapIOPBase = FALSE;
7125	    }
7126	    pSiS->IOPBase = NULL;
7127	}
7128    } else {
7129#endif
7130	xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiS->IOPBase, 2048);
7131	pSiS->IOPBase = NULL;
7132#ifdef SISDUALHEAD
7133    }
7134#endif
7135    return TRUE;
7136}
7137#endif
7138
7139/*
7140 * Map the framebuffer and MMIO memory
7141 */
7142
7143static Bool
7144SISMapMem(ScrnInfoPtr pScrn)
7145{
7146    SISPtr pSiS = SISPTR(pScrn);
7147#ifndef XSERVER_LIBPCIACCESS
7148    int mmioFlags = VIDMEM_MMIO;
7149#endif
7150#ifdef SISDUALHEAD
7151    SISEntPtr pSiSEnt = pSiS->entityPrivate;
7152#endif
7153
7154    /*
7155     * Map IO registers to virtual address space
7156     * (For Alpha, we need to map SPARSE memory, since we need
7157     * byte/short access.)
7158     */
7159#ifndef XSERVER_LIBPCIACCESS
7160#if defined(__alpha__)
7161    mmioFlags |= VIDMEM_SPARSE;
7162#endif
7163#endif
7164
7165#ifdef SISDUALHEAD
7166    if(pSiS->DualHeadMode) {
7167        pSiSEnt->MapCountIOBase++;
7168        if(!(pSiSEnt->IOBase)) {
7169	     /* Only map if not mapped previously */
7170#ifndef XSERVER_LIBPCIACCESS
7171    	     pSiSEnt->IOBase = xf86MapPciMem(pScrn->scrnIndex, mmioFlags,
7172                         pSiS->PciTag, pSiS->IOAddress, (pSiS->mmioSize * 1024));
7173#else
7174	     void **result = (void **)&pSiSEnt->IOBase;
7175	     int err = pci_device_map_range(pSiS->PciInfo,
7176 	                                    pSiS->IOAddress,
7177	                                    (pSiS->mmioSize * 1024),
7178                                            PCI_DEV_MAP_FLAG_WRITABLE,
7179                                            result);
7180
7181             if (err) {
7182                 xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
7183                             "Unable to map IO aperture. %s (%d)\n",
7184                             strerror (err), err);
7185	     }
7186#endif
7187        }
7188        pSiS->IOBase = pSiSEnt->IOBase;
7189    } else
7190#endif
7191#ifndef XSERVER_LIBPCIACCESS
7192    	pSiS->IOBase = xf86MapPciMem(pScrn->scrnIndex, mmioFlags,
7193                        pSiS->PciTag, pSiS->IOAddress, (pSiS->mmioSize * 1024));
7194#else
7195       {
7196	     void **result = (void **)&pSiS->IOBase;
7197	     int err = pci_device_map_range(pSiS->PciInfo,
7198 	                                    pSiS->IOAddress,
7199	                                    (pSiS->mmioSize * 1024),
7200                                            PCI_DEV_MAP_FLAG_WRITABLE,
7201                                            result);
7202
7203             if (err) {
7204                 xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
7205                             "Unable to map IO aperture. %s (%d)\n",
7206                             strerror (err), err);
7207	     }
7208       }
7209#endif
7210
7211    if(pSiS->IOBase == NULL) {
7212    	SISErrorLog(pScrn, "Could not map MMIO area\n");
7213        return FALSE;
7214    }
7215
7216#ifdef __alpha__
7217    /*
7218     * for Alpha, we need to map DENSE memory as well, for
7219     * setting CPUToScreenColorExpandBase.
7220     */
7221#ifdef SISDUALHEAD
7222    if(pSiS->DualHeadMode) {
7223        pSiSEnt->MapCountIOBaseDense++;
7224        if(!(pSiSEnt->IOBaseDense)) {
7225	     /* Only map if not mapped previously */
7226#ifndef XSERVER_LIBPCIACCESS
7227	     pSiSEnt->IOBaseDense = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
7228                    pSiS->PciTag, pSiS->IOAddress, (pSiS->mmioSize * 1024));
7229#else
7230	     void **result = (void **)&pSiSEnt->IOBaseDense;
7231	     int err = pci_device_map_range(pSiS->PciInfo,
7232 	                                    pSiS->IOAddress,
7233	                                    (pSiS->mmioSize * 1024),
7234                                            PCI_DEV_MAP_FLAG_WRITABLE,
7235                                            result);
7236
7237             if (err) {
7238                 xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
7239                             "Unable to map IO dense aperture. %s (%d)\n",
7240                             strerror (err), err);
7241	     }
7242#endif /* XSERVER_LIBPCIACCESS */
7243	}
7244	pSiS->IOBaseDense = pSiSEnt->IOBaseDense;
7245    } else {
7246#endif /* SISDUALHEAD */
7247#ifndef XSERVER_LIBPCIACCESS
7248	     pSiS->IOBaseDense = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
7249                    pSiS->PciTag, pSiS->IOAddress, (pSiS->mmioSize * 1024));
7250#else
7251	     void **result = (void **)&pSiS->IOBaseDense;
7252	     int err = pci_device_map_range(pSiS->PciInfo,
7253 	                                    pSiS->IOAddress,
7254	                                    (pSiS->mmioSize * 1024),
7255                                            PCI_DEV_MAP_FLAG_WRITABLE,
7256                                            result);
7257
7258             if (err) {
7259                 xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
7260                             "Unable to map IO dense aperture. %s (%d)\n",
7261                             strerror (err), err);
7262	     }
7263#endif /* XSERVER_LIBPCIACCESS */
7264#ifdef SISDUALHEAD
7265    }
7266#endif
7267    if(pSiS->IOBaseDense == NULL) {
7268       SISErrorLog(pScrn, "Could not map MMIO dense area\n");
7269       return FALSE;
7270    }
7271#endif /* __alpha__ */
7272
7273#ifdef SISDUALHEAD
7274    if(pSiS->DualHeadMode) {
7275	pSiSEnt->MapCountFbBase++;
7276	if(!(pSiSEnt->FbBase)) {
7277	     /* Only map if not mapped previously */
7278#ifndef XSERVER_LIBPCIACCESS
7279	     pSiSEnt->FbBase = pSiSEnt->RealFbBase =
7280			xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
7281			 pSiS->PciTag, (ULong)pSiS->realFbAddress,
7282			 pSiS->FbMapSize);
7283#else
7284         int err = pci_device_map_range(pSiS->PciInfo,
7285                                   (ULong)pSiS->realFbAddress,
7286                                   pSiS->FbMapSize,
7287                                   PCI_DEV_MAP_FLAG_WRITABLE |
7288                                   PCI_DEV_MAP_FLAG_WRITE_COMBINE,
7289                                   (void *)&pSiSEnt->FbBase);
7290	if (err) {
7291            xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
7292                        "Unable to map FB aperture. %s (%d)\n",
7293                        strerror (err), err);
7294            return FALSE;
7295        }
7296	pSiSEnt->RealFbBase = pSiSEnt->FbBase;
7297#endif
7298	}
7299	pSiS->FbBase = pSiS->RealFbBase = pSiSEnt->FbBase;
7300	/* Adapt FbBase (for DHM and SiS76x UMA skipping; dhmOffset is 0 otherwise) */
7301	pSiS->FbBase += pSiS->dhmOffset;
7302    } else {
7303#endif
7304
7305#ifndef XSERVER_LIBPCIACCESS
7306      pSiS->FbBase = pSiS->RealFbBase =
7307			xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
7308			 pSiS->PciTag, (ULong)pSiS->realFbAddress,
7309			 pSiS->FbMapSize);
7310#else
7311         int err = pci_device_map_range(pSiS->PciInfo,
7312                                   (ULong)pSiS->realFbAddress,
7313                                   pSiS->FbMapSize,
7314                                   PCI_DEV_MAP_FLAG_WRITABLE |
7315                                   PCI_DEV_MAP_FLAG_WRITE_COMBINE,
7316                                   (void *)&pSiS->FbBase);
7317	if (err) {
7318            xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
7319                        "Unable to map FB aperture. %s (%d)\n",
7320                        strerror (err), err);
7321            return FALSE;
7322        }
7323	pSiS->RealFbBase = pSiS->FbBase;
7324#endif
7325	pSiS->FbBase += pSiS->dhmOffset;
7326
7327#ifdef SISDUALHEAD
7328    }
7329#endif
7330
7331    if(pSiS->FbBase == NULL) {
7332       SISErrorLog(pScrn, "Could not map framebuffer area\n");
7333       return FALSE;
7334    }
7335
7336#ifdef TWDEBUG
7337    xf86DrvMsg(0, 0, "Framebuffer mapped to %p\n", pSiS->FbBase);
7338#endif
7339
7340    return TRUE;
7341}
7342
7343
7344/*
7345 * Unmap the framebuffer and MMIO memory.
7346 */
7347
7348static Bool
7349SISUnmapMem(ScrnInfoPtr pScrn)
7350{
7351    SISPtr pSiS = SISPTR(pScrn);
7352#ifdef SISDUALHEAD
7353    SISEntPtr pSiSEnt = pSiS->entityPrivate;
7354#endif
7355
7356/* In dual head mode, we must not unmap if the other head still
7357 * assumes memory as mapped
7358 */
7359#ifdef SISDUALHEAD
7360    if(pSiS->DualHeadMode) {
7361        if(pSiSEnt->MapCountIOBase) {
7362	    pSiSEnt->MapCountIOBase--;
7363	    if((pSiSEnt->MapCountIOBase == 0) || (pSiSEnt->forceUnmapIOBase)) {
7364#ifndef XSERVER_LIBPCIACCESS
7365		xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiSEnt->IOBase, (pSiS->mmioSize * 1024));
7366#else
7367	        pci_device_unmap_range(pSiS->PciInfo, pSiSEnt->IOBase, (pSiS->mmioSize * 1024));
7368#endif
7369		pSiSEnt->IOBase = NULL;
7370		pSiSEnt->MapCountIOBase = 0;
7371		pSiSEnt->forceUnmapIOBase = FALSE;
7372	    }
7373	    pSiS->IOBase = NULL;
7374	}
7375#ifdef __alpha__
7376	if(pSiSEnt->MapCountIOBaseDense) {
7377	    pSiSEnt->MapCountIOBaseDense--;
7378	    if((pSiSEnt->MapCountIOBaseDense == 0) || (pSiSEnt->forceUnmapIOBaseDense)) {
7379#ifndef XSERVER_LIBPCIACCESS
7380		xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiSEnt->IOBaseDense, (pSiS->mmioSize * 1024));
7381#else
7382		pci_device_unmap_range(pSiS->PciInfo, (pointer)pSiSEnt->IOBaseDense, (pSiS->mmioSize * 1024));
7383#endif
7384		pSiSEnt->IOBaseDense = NULL;
7385		pSiSEnt->MapCountIOBaseDense = 0;
7386		pSiSEnt->forceUnmapIOBaseDense = FALSE;
7387	    }
7388	    pSiS->IOBaseDense = NULL;
7389	}
7390#endif /* __alpha__ */
7391	if(pSiSEnt->MapCountFbBase) {
7392	    pSiSEnt->MapCountFbBase--;
7393	    if((pSiSEnt->MapCountFbBase == 0) || (pSiSEnt->forceUnmapFbBase)) {
7394#ifndef XSERVER_LIBPCIACCESS
7395		xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiSEnt->RealFbBase, pSiS->FbMapSize);
7396#else
7397		pci_device_unmap_range(pSiS->PciInfo, (pointer)pSiSEnt->RealFbBase, pSiS->FbMapSize);
7398#endif
7399		pSiSEnt->FbBase = pSiSEnt->RealFbBase = NULL;
7400		pSiSEnt->MapCountFbBase = 0;
7401		pSiSEnt->forceUnmapFbBase = FALSE;
7402
7403	    }
7404	    pSiS->FbBase = pSiS->RealFbBase = NULL;
7405	}
7406    } else {
7407#endif
7408#ifndef XSERVER_LIBPCIACCESS
7409	xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiS->IOBase, (pSiS->mmioSize * 1024));
7410#else
7411	pci_device_unmap_range(pSiS->PciInfo, (pointer)pSiS->IOBase, (pSiS->mmioSize * 1024));
7412#endif
7413	pSiS->IOBase = NULL;
7414#ifdef __alpha__
7415#ifndef XSERVER_LIBPCIACCESS
7416	xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiS->IOBaseDense, (pSiS->mmioSize * 1024));
7417#else
7418	pci_device_unmap_range(pSiS->PciInfo, (pointer)pSiS->IOBaseDense, (pSiS->mmioSize * 1024));
7419#endif
7420	pSiS->IOBaseDense = NULL;
7421#endif
7422#ifndef XSERVER_LIBPCIACCESS
7423	xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiS->RealFbBase, pSiS->FbMapSize);
7424#else
7425	pci_device_unmap_range(pSiS->PciInfo, (pointer)pSiS->RealFbBase, pSiS->FbMapSize);
7426#endif
7427	pSiS->FbBase = pSiS->RealFbBase = NULL;
7428#ifdef SISDUALHEAD
7429    }
7430#endif
7431    return TRUE;
7432}
7433
7434/*
7435 * This function saves the video state.
7436 */
7437static void
7438SISSave(ScrnInfoPtr pScrn)
7439{
7440    SISPtr pSiS = SISPTR(pScrn);
7441    SISRegPtr sisReg;
7442    int flags;
7443
7444#ifdef SISDUALHEAD
7445    /* We always save master & slave */
7446    if(pSiS->DualHeadMode && pSiS->SecondHead) return;
7447#endif
7448
7449    sisReg = &pSiS->SavedReg;
7450
7451    if( ((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) &&
7452        ((pSiS->VBFlags2 & VB2_VIDEOBRIDGE) && (SiSBridgeIsInSlaveMode(pScrn))) ) {
7453       SiSVGASave(pScrn, sisReg, SISVGA_SR_CMAP | SISVGA_SR_MODE);
7454#ifdef SIS_PC_PLATFORM
7455       if(pSiS->VGAMemBase) {
7456          SiSRegInit(pSiS->SiS_Pr, pSiS->RelIO+0x30);
7457          SiSSetLVDSetc(pSiS->SiS_Pr);
7458          SiS_GetVBType(pSiS->SiS_Pr);
7459          SiS_DisableBridge(pSiS->SiS_Pr);
7460          SiSVGASave(pScrn, sisReg, SISVGA_SR_FONTS);
7461          SiS_EnableBridge(pSiS->SiS_Pr);
7462       }
7463#endif
7464    } else {
7465       flags = SISVGA_SR_CMAP | SISVGA_SR_MODE;
7466#ifdef SIS_PC_PLATFORM
7467       if(pSiS->VGAMemBase) flags |= SISVGA_SR_FONTS;
7468#endif
7469       SiSVGASave(pScrn, sisReg, flags);
7470    }
7471
7472    sisSaveUnlockExtRegisterLock(pSiS, &sisReg->sisRegs3C4[0x05], &sisReg->sisRegs3D4[0x80]);
7473
7474    (*pSiS->SiSSave)(pScrn, sisReg);
7475
7476    if(pSiS->UseVESA) SISVESASaveRestore(pScrn, MODE_SAVE);
7477
7478    /* "Save" these again as they may have been changed prior to SISSave() call */
7479    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
7480       sisReg->sisRegs3C4[0x1f] = pSiS->oldSR1F;
7481       sisReg->sisRegs3D4[0x17] = pSiS->oldCR17;
7482       sisReg->sisRegs3D4[0x32] = pSiS->oldCR32;
7483       sisReg->sisRegs3D4[0x36] = pSiS->oldCR36;
7484       sisReg->sisRegs3D4[0x37] = pSiS->oldCR37;
7485       if(pSiS->VGAEngine == SIS_315_VGA) {
7486	  sisReg->sisRegs3D4[pSiS->myCR63] = pSiS->oldCR63;
7487       }
7488    }
7489}
7490
7491/* VESASaveRestore taken from vesa driver */
7492static void
7493SISVESASaveRestore(ScrnInfoPtr pScrn, vbeSaveRestoreFunction function)
7494{
7495    SISPtr pSiS = SISPTR(pScrn);
7496
7497    /* Query amount of memory to save state */
7498    if((function == MODE_QUERY) ||
7499       (function == MODE_SAVE && pSiS->state == NULL)) {
7500
7501       /* Make sure we save at least this information in case of failure */
7502       (void)VBEGetVBEMode(pSiS->pVbe, &pSiS->stateMode);
7503       SiSVGASaveFonts(pScrn);
7504
7505       if(pSiS->vesamajor > 1) {
7506	  if(!VBESaveRestore(pSiS->pVbe, function, (pointer)&pSiS->state,
7507				&pSiS->stateSize, &pSiS->statePage)) {
7508	     return;
7509	  }
7510       }
7511    }
7512
7513    /* Save/Restore Super VGA state */
7514    if(function != MODE_QUERY) {
7515
7516       if(pSiS->vesamajor > 1) {
7517	  if(function == MODE_RESTORE) {
7518	     memcpy(pSiS->state, pSiS->pstate, pSiS->stateSize);
7519	  }
7520
7521	  if(VBESaveRestore(pSiS->pVbe,function,(pointer)&pSiS->state,
7522			    &pSiS->stateSize,&pSiS->statePage) &&
7523	     (function == MODE_SAVE)) {
7524	     /* don't rely on the memory not being touched */
7525	     if(!pSiS->pstate) {
7526		pSiS->pstate = malloc(pSiS->stateSize);
7527	     }
7528	     memcpy(pSiS->pstate, pSiS->state, pSiS->stateSize);
7529	  }
7530       }
7531
7532       if(function == MODE_RESTORE) {
7533	  VBESetVBEMode(pSiS->pVbe, pSiS->stateMode, NULL);
7534	  SiSVGARestoreFonts(pScrn);
7535       }
7536
7537    }
7538}
7539
7540/*
7541 * Initialise a new mode.  This is currently done using the
7542 * "initialise struct, restore/write struct to HW" model for
7543 * the old chipsets (5597/530/6326). For newer chipsets,
7544 * we use our own mode switching code.
7545 */
7546
7547static Bool
7548SISModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
7549{
7550    SISPtr pSiS = SISPTR(pScrn);
7551    SISRegPtr sisReg;
7552#ifdef SISDUALHEAD
7553    SISEntPtr pSiSEnt = NULL;
7554#endif
7555
7556    andSISIDXREG(SISCR,0x11,0x7f);	/* Unlock CRTC registers */
7557
7558    SISModifyModeInfo(mode);		/* Quick check of the mode parameters */
7559
7560    if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
7561       SiSRegInit(pSiS->SiS_Pr, pSiS->RelIO+0x30);
7562    }
7563
7564    if(pSiS->UseVESA) {  /* With VESA: */
7565
7566#ifdef SISDUALHEAD
7567       /* No dual head mode when using VESA */
7568       if(pSiS->SecondHead) return TRUE;
7569#endif
7570
7571       pScrn->vtSema = TRUE;
7572
7573       /*
7574	* This order is required:
7575	* The video bridge needs to be adjusted before the
7576	* BIOS is run as the BIOS sets up CRT2 according to
7577	* these register settings.
7578	* After the BIOS is run, the bridges and turboqueue
7579	* registers need to be readjusted as the BIOS may
7580	* very probably have messed them up.
7581	*/
7582       if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
7583	  SiSPreSetMode(pScrn, mode, SIS_MODE_SIMU);
7584       }
7585       if(!SiSSetVESAMode(pScrn, mode)) {
7586	  SISErrorLog(pScrn, "SiSSetVESAMode() failed\n");
7587	  return FALSE;
7588       }
7589       sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
7590       if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
7591	  SiSPreSetMode(pScrn, mode, SIS_MODE_SIMU);
7592	  SiSPostSetMode(pScrn, &pSiS->ModeReg);
7593       }
7594#ifdef TWDEBUG
7595       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
7596		   "REAL REGISTER CONTENTS AFTER SETMODE:\n");
7597#endif
7598       if(!(*pSiS->ModeInit)(pScrn, mode)) {
7599	  SISErrorLog(pScrn, "ModeInit() failed\n");
7600	  return FALSE;
7601       }
7602
7603       SiSVGAProtect(pScrn, TRUE);
7604       (*pSiS->SiSRestore)(pScrn, &pSiS->ModeReg);
7605       SiSVGAProtect(pScrn, FALSE);
7606
7607    } else { /* Without VESA: */
7608
7609#ifdef SISDUALHEAD
7610       if(pSiS->DualHeadMode) {
7611
7612	  if(!(*pSiS->ModeInit)(pScrn, mode)) {
7613	     SISErrorLog(pScrn, "ModeInit() failed\n");
7614	     return FALSE;
7615	  }
7616
7617	  pScrn->vtSema = TRUE;
7618
7619	  pSiSEnt = pSiS->entityPrivate;
7620
7621	  if(!(pSiS->SecondHead)) {
7622	     /* Head 1 (master) is always CRT2 */
7623	     SiSPreSetMode(pScrn, mode, SIS_MODE_CRT2);
7624	     if(!SiSBIOSSetModeCRT2(pSiS->SiS_Pr, pScrn, mode, pSiS->IsCustom)) {
7625		SISErrorLog(pScrn, "SiSBIOSSetModeCRT2() failed\n");
7626		return FALSE;
7627	     }
7628	     SiSPostSetMode(pScrn, &pSiS->ModeReg);
7629	     if(pSiSEnt->pScrn_2) {
7630		SISAdjustFrame(ADJUST_FRAME_ARGS(pSiSEnt->pScrn_2,
7631			       pSiSEnt->pScrn_2->frameX0,
7632						 pSiSEnt->pScrn_2->frameY0));
7633	     }
7634	  } else {
7635	     /* Head 2 (slave) is always CRT1 */
7636	     SiSPreSetMode(pScrn, mode, SIS_MODE_CRT1);
7637	     if(!SiSBIOSSetModeCRT1(pSiS->SiS_Pr, pScrn, mode, pSiS->IsCustom)) {
7638		SISErrorLog(pScrn, "SiSBIOSSetModeCRT1() failed\n");
7639		return FALSE;
7640	     }
7641	     SiSPostSetMode(pScrn, &pSiS->ModeReg);
7642	     if(pSiSEnt->pScrn_1) {
7643		SISAdjustFrame(ADJUST_FRAME_ARGS(pSiSEnt->pScrn_1,
7644			       pSiSEnt->pScrn_1->frameX0,
7645			       pSiSEnt->pScrn_1->frameY0));
7646	     }
7647	  }
7648
7649       } else {
7650#endif
7651
7652	  if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
7653
7654	     if(!(*pSiS->ModeInit)(pScrn, mode)) {
7655		SISErrorLog(pScrn, "ModeInit() failed\n");
7656	        return FALSE;
7657	     }
7658
7659	     pScrn->vtSema = TRUE;
7660
7661#ifdef SISMERGED
7662	     if(pSiS->MergedFB) {
7663
7664		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Setting MergedFB mode %dx%d\n",
7665				mode->HDisplay, mode->VDisplay);
7666
7667		SiSPreSetMode(pScrn, mode, SIS_MODE_CRT1);
7668
7669		if(!SiSBIOSSetModeCRT1(pSiS->SiS_Pr, pScrn,
7670		                       ((SiSMergedDisplayModePtr)mode->Private)->CRT1,
7671				       pSiS->IsCustom)) {
7672		   SISErrorLog(pScrn, "SiSBIOSSetModeCRT1() failed\n");
7673		   return FALSE;
7674		}
7675
7676		SiSPreSetMode(pScrn, mode, SIS_MODE_CRT2);
7677
7678		if(!SiSBIOSSetModeCRT2(pSiS->SiS_Pr, pScrn,
7679		                       ((SiSMergedDisplayModePtr)mode->Private)->CRT2,
7680				       pSiS->IsCustom)) {
7681		   SISErrorLog(pScrn, "SiSBIOSSetModeCRT2() failed\n");
7682		   return FALSE;
7683		}
7684
7685	     } else {
7686#endif
7687
7688		if((pSiS->VBFlags & CRT1_LCDA) || (!(mode->type & M_T_DEFAULT))) {
7689
7690		   SiSPreSetMode(pScrn, mode, SIS_MODE_CRT1);
7691
7692		   if(!SiSBIOSSetModeCRT1(pSiS->SiS_Pr, pScrn,
7693				mode, pSiS->IsCustom)) {
7694		      SISErrorLog(pScrn, "SiSBIOSSetModeCRT1() failed\n");
7695		      return FALSE;
7696		   }
7697
7698		   SiSPreSetMode(pScrn, mode, SIS_MODE_CRT2);
7699
7700		   if(!SiSBIOSSetModeCRT2(pSiS->SiS_Pr, pScrn,
7701				mode, pSiS->IsCustom)) {
7702		      SISErrorLog(pScrn, "SiSBIOSSetModeCRT2() failed\n");
7703		      return FALSE;
7704		   }
7705
7706		} else {
7707
7708		   SiSPreSetMode(pScrn, mode, SIS_MODE_SIMU);
7709
7710		   if(!SiSBIOSSetMode(pSiS->SiS_Pr, pScrn,
7711				mode, pSiS->IsCustom)) {
7712		      SISErrorLog(pScrn, "SiSBIOSSetMode() failed\n");
7713		      return FALSE;
7714		   }
7715
7716		}
7717
7718#ifdef SISMERGED
7719	     }
7720#endif
7721
7722	     SiSPostSetMode(pScrn, &pSiS->ModeReg);
7723
7724#ifdef TWDEBUG
7725	     xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VBFlags %lx\n", pSiS->VBFlags);
7726	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
7727			"REAL REGISTER CONTENTS AFTER SETMODE:\n");
7728             (*pSiS->ModeInit)(pScrn, mode);
7729#endif
7730
7731	  } else {
7732
7733	     /* For other chipsets, use the old method */
7734
7735	     /* Prepare the register contents */
7736	     if(!(*pSiS->ModeInit)(pScrn, mode)) {
7737	        SISErrorLog(pScrn, "ModeInit() failed\n");
7738	        return FALSE;
7739	     }
7740
7741	     pScrn->vtSema = TRUE;
7742
7743	     /* Program the registers */
7744	     SiSVGAProtect(pScrn, TRUE);
7745	     sisReg = &pSiS->ModeReg;
7746
7747	     sisReg->sisRegsATTR[0x10] = 0x01;
7748	     if(pScrn->bitsPerPixel > 8) {
7749		sisReg->sisRegsGR[0x05] = 0x00;
7750	     }
7751
7752	     SiSVGARestore(pScrn, sisReg, SISVGA_SR_MODE);
7753
7754	     (*pSiS->SiSRestore)(pScrn, sisReg);
7755
7756	     if((pSiS->Chipset == PCI_CHIP_SIS6326) && (pSiS->SiS6326Flags & SIS6326_HASTV)) {
7757	        SiS6326PostSetMode(pScrn, &pSiS->ModeReg);
7758	     }
7759
7760#ifdef TWDEBUG
7761	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
7762			"REAL REGISTER CONTENTS AFTER SETMODE:\n");
7763	     (*pSiS->ModeInit)(pScrn, mode);
7764#endif
7765
7766	     SiSVGAProtect(pScrn, FALSE);
7767
7768	  }
7769
7770#ifdef SISDUALHEAD
7771       }
7772#endif
7773    }
7774
7775    /* Update Currentlayout */
7776    pSiS->CurrentLayout.mode = pSiS->currentModeLast = mode;
7777
7778    return TRUE;
7779}
7780
7781static Bool
7782SiSSetVESAMode(ScrnInfoPtr pScrn, DisplayModePtr pMode)
7783{
7784    SISPtr pSiS;
7785    int mode;
7786
7787    pSiS = SISPTR(pScrn);
7788
7789    if(!(mode = SiSCalcVESAModeIndex(pScrn, pMode))) return FALSE;
7790
7791    mode |= (1 << 15);	/* Don't clear framebuffer */
7792    mode |= (1 << 14); 	/* Use linear adressing */
7793
7794    if(VBESetVBEMode(pSiS->pVbe, mode, NULL) == FALSE) {
7795       SISErrorLog(pScrn, "Setting VESA mode 0x%x failed\n",
7796	             	mode & 0x0fff);
7797       return (FALSE);
7798    }
7799
7800    if(pMode->HDisplay != pScrn->virtualX) {
7801       VBESetLogicalScanline(pSiS->pVbe, pScrn->virtualX);
7802    }
7803
7804    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
7805    	"Setting VESA mode 0x%x succeeded\n",
7806	mode & 0x0fff);
7807
7808    return (TRUE);
7809}
7810
7811static void
7812SISSpecialRestore(ScrnInfoPtr pScrn)
7813{
7814    SISPtr    pSiS = SISPTR(pScrn);
7815    SISRegPtr sisReg = &pSiS->SavedReg;
7816    UChar temp;
7817    int i;
7818
7819    /* 1.11.04 and later for 651 and 301B(DH) do strange register
7820     * fiddling after the usual mode change. This happens
7821     * depending on the result of a call of int 2f (with
7822     * ax=0x1680) and if modeno <= 0x13. I have no idea if
7823     * that is specific for the 651 or that very machine.
7824     * So this perhaps requires some more checks in the beginning
7825     * (although it should not do any harm on other chipsets/bridges
7826     * etc.) However, even if I call the VBE to restore mode 0x03,
7827     * these registers don't get restored correctly, possibly
7828     * because that int-2f-call for some reason results non-zero. So
7829     * what I do here is to restore these few registers
7830     * manually.
7831     */
7832
7833    if(!(pSiS->ChipFlags & SiSCF_Is65x)) return;
7834    inSISIDXREG(SISCR, 0x34, temp);
7835    temp &= 0x7f;
7836    if(temp > 0x13) return;
7837
7838#ifdef UNLOCK_ALWAYS
7839    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
7840#endif
7841
7842    SiS_UnLockCRT2(pSiS->SiS_Pr);
7843
7844    outSISIDXREG(SISCAP, 0x3f, sisReg->sisCapt[0x3f]);
7845    outSISIDXREG(SISCAP, 0x00, sisReg->sisCapt[0x00]);
7846    for(i = 0; i < 0x4f; i++) {
7847       outSISIDXREG(SISCAP, i, sisReg->sisCapt[i]);
7848    }
7849    outSISIDXREG(SISVID, 0x32, (sisReg->sisVid[0x32] & ~0x05));
7850    outSISIDXREG(SISVID, 0x30, sisReg->sisVid[0x30]);
7851    outSISIDXREG(SISVID, 0x32, ((sisReg->sisVid[0x32] & ~0x04) | 0x01));
7852    outSISIDXREG(SISVID, 0x30, sisReg->sisVid[0x30]);
7853
7854    if(!(pSiS->ChipFlags & SiSCF_Is651)) return;
7855    if(!(pSiS->VBFlags2 & VB2_SISBRIDGE)) return;
7856
7857    inSISIDXREG(SISCR, 0x30, temp);
7858    if(temp & 0x40) {
7859       UChar myregs[] = {
7860       		0x2f, 0x08, 0x09, 0x03, 0x0a, 0x0c,
7861		0x0b, 0x0d, 0x0e, 0x12, 0x0f, 0x10,
7862		0x11, 0x04, 0x05, 0x06, 0x07, 0x00,
7863		0x2e
7864       };
7865       for(i = 0; i <= 18; i++) {
7866          outSISIDXREG(SISPART1, myregs[i], sisReg->VBPart1[myregs[i]]);
7867       }
7868    } else if((temp & 0x20) || (temp & 0x9c)) {
7869       UChar myregs[] = {
7870       		0x04, 0x05, 0x06, 0x07, 0x00, 0x2e
7871       };
7872       for(i = 0; i <= 5; i++) {
7873          outSISIDXREG(SISPART1, myregs[i], sisReg->VBPart1[myregs[i]]);
7874       }
7875    }
7876}
7877
7878/* Fix SR11 for 661 and later */
7879static void
7880SiSFixupSR11(ScrnInfoPtr pScrn)
7881{
7882    SISPtr pSiS = SISPTR(pScrn);
7883    CARD8  tmpreg;
7884
7885#ifdef UNLOCK_ALWAYS
7886    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
7887#endif
7888
7889    if(pSiS->ChipType >= SIS_661) {
7890       inSISIDXREG(SISSR,0x11,tmpreg);
7891       if(tmpreg & 0x20) {
7892          inSISIDXREG(SISSR,0x3e,tmpreg);
7893	  tmpreg = (tmpreg + 1) & 0xff;
7894	  outSISIDXREG(SISSR,0x3e,tmpreg);
7895       }
7896
7897       inSISIDXREG(SISSR,0x11,tmpreg);
7898       if(tmpreg & 0xf0) {
7899          andSISIDXREG(SISSR,0x11,0x0f);
7900       }
7901    }
7902}
7903
7904/* Subroutine for restoring sisfb's TV parameters (used by SiSRestore()) */
7905
7906static void
7907SiSRestore_SiSFB_TVParms(ScrnInfoPtr pScrn)
7908{
7909    SISPtr  pSiS = SISPTR(pScrn);
7910    int     fd;
7911    CARD32  parm;
7912
7913    if(!pSiS->sisfbfound) return;
7914    if(!pSiS->sisfb_tvposvalid) return;
7915    if(!(pSiS->sisfbdevname[0])) return;
7916
7917    if((fd = open(pSiS->sisfbdevname, O_RDONLY)) != -1) {
7918       parm = (CARD32)((pSiS->sisfb_tvxpos << 16) | (pSiS->sisfb_tvypos & 0xffff));
7919       ioctl(fd, SISFB_SET_TVPOSOFFSET, &parm);
7920       close(fd);
7921    }
7922}
7923
7924/*
7925 * Restore the initial mode. To be used internally only!
7926 */
7927static void
7928SISRestore(ScrnInfoPtr pScrn)
7929{
7930    SISPtr    pSiS = SISPTR(pScrn);
7931    SISRegPtr sisReg = &pSiS->SavedReg;
7932    Bool      doit = FALSE, doitlater = FALSE;
7933    Bool      vesasuccess = FALSE;
7934    int	      flags;
7935
7936    /* WARNING: Don't ever touch this. It now seems to work on
7937     * all chipset/bridge combinations - but finding out the
7938     * correct combination was pure hell.
7939     */
7940
7941    /* Wait for the accelerators */
7942    (*pSiS->SyncAccel)(pScrn);
7943
7944    /* Set up restore flags */
7945    flags = SISVGA_SR_MODE | SISVGA_SR_CMAP;
7946#ifdef SIS_PC_PLATFORM
7947    /* We now restore ALL to overcome the vga=extended problem */
7948    if(pSiS->VGAMemBase) flags |= SISVGA_SR_FONTS;
7949#endif
7950
7951    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
7952
7953#ifdef SISDUALHEAD
7954       /* We always restore master AND slave */
7955       if(pSiS->DualHeadMode && pSiS->SecondHead) return;
7956#endif
7957
7958#ifdef UNLOCK_ALWAYS
7959       sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
7960#endif
7961
7962       /* We must not disable the sequencer if the bridge is in SlaveMode! */
7963       if(!(SiSBridgeIsInSlaveMode(pScrn))) {
7964	  SiSVGAProtect(pScrn, TRUE);
7965       }
7966
7967       /* First, restore CRT1 on/off and VB connection registers */
7968       outSISIDXREG(SISCR, 0x32, pSiS->oldCR32);
7969       if(!(pSiS->oldCR17 & 0x80)) {			/* CRT1 was off */
7970	  if(!(SiSBridgeIsInSlaveMode(pScrn))) {        /* Bridge is NOT in SlaveMode now -> do it */
7971	     doit = TRUE;
7972	  } else {
7973	     doitlater = TRUE;
7974	  }
7975       } else {						/* CRT1 was on -> do it now */
7976	  doit = TRUE;
7977       }
7978
7979       if(doit) {
7980	  outSISIDXREG(SISCR, 0x17, pSiS->oldCR17);
7981       }
7982       if(pSiS->VGAEngine == SIS_315_VGA) {
7983	  outSISIDXREG(SISCR, pSiS->myCR63, pSiS->oldCR63);
7984       }
7985
7986       outSISIDXREG(SISSR, 0x1f, pSiS->oldSR1F);
7987
7988       /* For 30xB/LV, restoring the registers does not
7989	* work. We "manually" set the old mode, instead.
7990	* The same applies for SiS730 machines with LVDS.
7991	* Finally, this behavior can be forced by setting
7992	* the option RestoreBySetMode.
7993	*/
7994	if( ( (pSiS->restorebyset) ||
7995	      (pSiS->VBFlags2 & VB2_30xBLV) ||
7996	      ((pSiS->ChipType == SIS_730) && (pSiS->VBFlags2 & VB2_LVDS)) )     &&
7997	    (pSiS->OldMode) ) {
7998
7999	   Bool changedmode = FALSE;
8000
8001	   xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
8002	         "Restoring by setting old mode 0x%02x\n", pSiS->OldMode);
8003
8004	   if(((pSiS->OldMode <= 0x13) || (!pSiS->sisfbfound)) && (pSiS->pVbe)) {
8005	      int vmode = SiSTranslateToVESA(pScrn, pSiS->OldMode);
8006	      if(vmode > 0) {
8007		 if(vmode > 0x13) vmode |= ((1 << 15) | (1 << 14));
8008		 if(VBESetVBEMode(pSiS->pVbe, vmode, NULL) == TRUE) {
8009		    SISSpecialRestore(pScrn);
8010		    SiS_GetSetModeID(pScrn,pSiS->OldMode);
8011		    vesasuccess = TRUE;
8012		 } else {
8013		    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
8014			"VBE failed to restore mode 0x%x\n", pSiS->OldMode);
8015		 }
8016	      } else {
8017		 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
8018		 	"Can't identify VESA mode number for mode 0x%x\n", pSiS->OldMode);
8019	      }
8020	   }
8021
8022	   if(vesasuccess == FALSE) {
8023
8024	      int backupscaler = pSiS->SiS_Pr->UsePanelScaler;
8025	      int backupcenter = pSiS->SiS_Pr->CenterScreen;
8026	      ULong backupspecialtiming = pSiS->SiS_Pr->SiS_CustomT;
8027	      int mymode = pSiS->OldMode;
8028
8029	      if((pSiS->VGAEngine == SIS_315_VGA)			&&
8030	         ((pSiS->ROM661New) || (pSiS->ChipFlags & SiSCF_IsXGI)) &&
8031		 (!pSiS->sisfbfound)) {
8032	         /* New SiS BIOS or XGI BIOS has set mode, therefore eventually translate number */
8033	         mymode = SiSTranslateToOldMode(mymode);
8034	      }
8035
8036 	      if((pSiS->VBFlags2 & VB2_30xBLV)) {
8037	        /* !!! REQUIRED for 630+301B-DH, otherwise the text modes
8038	         *     will not be restored correctly !!!
8039	         * !!! Do this ONLY for LCD; VGA2 will not be restored
8040	         *     correctly otherwise.
8041	         */
8042	         UChar temp;
8043	         inSISIDXREG(SISCR, 0x30, temp);
8044	         if(temp & 0x20) {
8045	            if(mymode == 0x03) {
8046		       mymode = 0x13;
8047		       changedmode = TRUE;
8048	            }
8049	         }
8050	      }
8051
8052	      pSiS->SiS_Pr->UseCustomMode = FALSE;
8053	      pSiS->SiS_Pr->CRT1UsesCustomMode = FALSE;
8054	      pSiS->SiS_Pr->CenterScreen = 0;
8055	      if(pSiS->sisfbfound) {
8056		 pSiS->SiS_Pr->UsePanelScaler = pSiS->sisfbscalelcd;
8057		 pSiS->SiS_Pr->SiS_CustomT = pSiS->sisfbspecialtiming;
8058	      } else {
8059		 pSiS->SiS_Pr->UsePanelScaler = -1;
8060		 /* Leave CustomT as it is */
8061	      }
8062	      SiS_SetEnableDstn(pSiS->SiS_Pr, FALSE);
8063	      SiS_SetEnableFstn(pSiS->SiS_Pr, FALSE);
8064	      if((pSiS->ChipType == SIS_550) && (pSiS->sisfbfound)) {
8065		 if(pSiS->sisfbxSTN) {
8066		    SiS_SetEnableDstn(pSiS->SiS_Pr, pSiS->sisfbDSTN);
8067		    SiS_SetEnableFstn(pSiS->SiS_Pr, pSiS->sisfbFSTN);
8068		 } else if(mymode == 0x5a || mymode == 0x5b) {
8069		    SiS_SetEnableFstn(pSiS->SiS_Pr, TRUE);
8070		 }
8071	      }
8072	      SiSSetMode(pSiS->SiS_Pr, pScrn, mymode, FALSE);
8073	      if(changedmode) {
8074		 outSISIDXREG(SISCR,0x34,0x03);
8075	      }
8076	      SISSpecialRestore(pScrn);
8077	      SiS_GetSetModeID(pScrn, pSiS->OldMode); /* NOT mymode! */
8078	      pSiS->SiS_Pr->UsePanelScaler = backupscaler;
8079	      pSiS->SiS_Pr->CenterScreen = backupcenter;
8080	      pSiS->SiS_Pr->SiS_CustomT = backupspecialtiming;
8081	      SiS_SiSFB_Lock(pScrn, FALSE);
8082	      SiSRestore_SiSFB_TVParms(pScrn);
8083	      SiS_SiSFB_Lock(pScrn, TRUE);
8084
8085	   }
8086
8087	   /* Restore CRT1 status */
8088	   if(pSiS->VGAEngine == SIS_315_VGA) {
8089              outSISIDXREG(SISCR, pSiS->myCR63, pSiS->oldCR63);
8090           }
8091           outSISIDXREG(SISSR, 0x1f, pSiS->oldSR1F);
8092
8093#ifdef SISVRAMQ
8094	   /* Restore queue mode registers on 315/330/340 series */
8095	   /* (This became necessary due to the switch to VRAM queue) */
8096	   SiSRestoreQueueMode(pSiS, sisReg);
8097#endif
8098
8099        } else {
8100
8101	   if(pSiS->VBFlags2 & VB2_VIDEOBRIDGE) {
8102	      /* If a video bridge is present, we need to restore
8103	       * non-extended (=standard VGA) SR and CR registers
8104	       * before restoring the extended ones and the bridge
8105	       * registers.
8106	       */
8107	      if(!(SiSBridgeIsInSlaveMode(pScrn))) {
8108                 SiSVGAProtect(pScrn, TRUE);
8109	         SiSVGARestore(pScrn, sisReg, SISVGA_SR_MODE);
8110              }
8111	   }
8112
8113           (*pSiS->SiSRestore)(pScrn, sisReg);
8114
8115        }
8116
8117	if(doitlater) {
8118           outSISIDXREG(SISCR, 0x17, pSiS->oldCR17);
8119	}
8120
8121
8122
8123	if((pSiS->VBFlags2 & VB2_VIDEOBRIDGE) && (SiSBridgeIsInSlaveMode(pScrn))) {
8124
8125	   /* IMPORTANT: The 30xLV does not handle well being disabled if in
8126	    * LCDA mode! In LCDA mode, the bridge is NOT in slave mode,
8127	    * so this is the only safe way: Disable the bridge ONLY if
8128	    * in Slave Mode, and don't bother if not.
8129	    */
8130
8131	   if(flags & SISVGA_SR_FONTS) {
8132              SiSRegInit(pSiS->SiS_Pr, pSiS->RelIO+0x30);
8133	      SiSSetLVDSetc(pSiS->SiS_Pr);
8134	      SiS_GetVBType(pSiS->SiS_Pr);
8135	      SiS_DisableBridge(pSiS->SiS_Pr);
8136	      SiSVGAProtect(pScrn, TRUE);
8137	   }
8138
8139	   SiSVGARestore(pScrn, sisReg, flags);
8140
8141	   if(flags & SISVGA_SR_FONTS) {
8142	      SiSVGAProtect(pScrn, FALSE);
8143	      SiS_EnableBridge(pSiS->SiS_Pr);
8144	      andSISIDXREG(SISSR, 0x01, ~0x20);  /* Display on */
8145	   }
8146
8147	} else {
8148
8149	   SiSVGAProtect(pScrn, TRUE);
8150	   SiSVGARestore(pScrn, sisReg, flags);
8151           SiSVGAProtect(pScrn, FALSE);
8152
8153	}
8154
8155	SiSFixupSR11(pScrn);
8156
8157#ifdef TWDEBUG
8158	{
8159	  SISRegPtr pReg = &pSiS->ModeReg;
8160	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
8161		"REAL REGISTER CONTENTS AFTER RESTORE BY SETMODE:\n");
8162	  (*pSiS->SiSSave)(pScrn, pReg);
8163	}
8164#endif
8165
8166	sisRestoreExtRegisterLock(pSiS,sisReg->sisRegs3C4[0x05],sisReg->sisRegs3D4[0x80]);
8167
8168    } else {	/* All other chipsets */
8169
8170        SiSVGAProtect(pScrn, TRUE);
8171
8172#ifdef UNLOCK_ALWAYS
8173        sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
8174#endif
8175
8176        (*pSiS->SiSRestore)(pScrn, sisReg);
8177
8178        SiSVGAProtect(pScrn, TRUE);
8179
8180	SiSVGARestore(pScrn, sisReg, flags);
8181
8182	/* Restore TV. This is rather complicated, but if we don't do it,
8183	 * TV output will flicker terribly
8184	 */
8185        if((pSiS->Chipset == PCI_CHIP_SIS6326) && (pSiS->SiS6326Flags & SIS6326_HASTV)) {
8186	   if(sisReg->sis6326tv[0] & 0x04) {
8187	      UChar tmp;
8188	      int val;
8189
8190              orSISIDXREG(SISSR, 0x01, 0x20);
8191              tmp = SiS6326GetTVReg(pScrn,0x00);
8192              tmp &= ~0x04;
8193              while(!(inSISREG(SISINPSTAT) & 0x08));  /* Wait while NOT vb */
8194              SiS6326SetTVReg(pScrn,0x00,tmp);
8195              for(val=0; val < 2; val++) {
8196                 while(!(inSISREG(SISINPSTAT) & 0x08));  /* Wait while NOT vb */
8197                 while(inSISREG(SISINPSTAT) & 0x08);     /* wait while vb     */
8198              }
8199              SiS6326SetTVReg(pScrn, 0x00, sisReg->sis6326tv[0]);
8200              tmp = inSISREG(SISINPSTAT);
8201              outSISREG(SISAR, 0x20);
8202              tmp = inSISREG(SISINPSTAT);
8203              while(inSISREG(SISINPSTAT) & 0x01);
8204              while(!(inSISREG(SISINPSTAT) & 0x01));
8205              andSISIDXREG(SISSR, 0x01, ~0x20);
8206              for(val=0; val < 10; val++) {
8207                 while(!(inSISREG(SISINPSTAT) & 0x08));  /* Wait while NOT vb */
8208                 while(inSISREG(SISINPSTAT) & 0x08);     /* wait while vb     */
8209              }
8210              andSISIDXREG(SISSR, 0x01, ~0x20);
8211	   }
8212        }
8213
8214        sisRestoreExtRegisterLock(pSiS,sisReg->sisRegs3C4[5],sisReg->sisRegs3D4[0x80]);
8215
8216        SiSVGAProtect(pScrn, FALSE);
8217    }
8218}
8219
8220static void
8221SISVESARestore(ScrnInfoPtr pScrn)
8222{
8223   SISPtr pSiS = SISPTR(pScrn);
8224#ifdef SISVRAMQ
8225   SISRegPtr sisReg = &pSiS->SavedReg;
8226#endif
8227
8228   if(pSiS->UseVESA) {
8229      SISVESASaveRestore(pScrn, MODE_RESTORE);
8230#ifdef SISVRAMQ
8231      /* Restore queue mode registers on 315/330/340 series */
8232      /* (This became necessary due to the switch to VRAM queue) */
8233      SiSRestoreQueueMode(pSiS, sisReg);
8234#endif
8235   }
8236}
8237
8238/* Restore bridge config registers - to be called BEFORE VESARestore */
8239static void
8240SISBridgeRestore(ScrnInfoPtr pScrn)
8241{
8242    SISPtr pSiS = SISPTR(pScrn);
8243
8244#ifdef SISDUALHEAD
8245    /* We only restore for master head */
8246    if(pSiS->DualHeadMode && pSiS->SecondHead) return;
8247#endif
8248
8249    if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
8250	SiSRestoreBridge(pScrn, &pSiS->SavedReg);
8251    }
8252}
8253
8254/* Our BlockHandler */
8255static void
8256SISBlockHandler(BLOCKHANDLER_ARGS_DECL)
8257{
8258    SCREEN_PTR(arg);
8259    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
8260    SISPtr pSiS = SISPTR(pScrn);
8261
8262    pScreen->BlockHandler = pSiS->BlockHandler;
8263    (*pScreen->BlockHandler) (BLOCKHANDLER_ARGS);
8264    pScreen->BlockHandler = SISBlockHandler;
8265
8266#ifdef SISDUALHEAD
8267    if(pSiS->NeedCopyFastVidCpy) {
8268       SISEntPtr pSiSEnt = pSiS->entityPrivate;
8269       if(pSiSEnt->HaveFastVidCpy) {
8270	  pSiS->NeedCopyFastVidCpy = FALSE;
8271	  pSiS->SiSFastVidCopy = pSiSEnt->SiSFastVidCopy;
8272	  pSiS->SiSFastMemCopy = pSiSEnt->SiSFastMemCopy;
8273	  pSiS->SiSFastVidCopyFrom = pSiSEnt->SiSFastVidCopyFrom;
8274	  pSiS->SiSFastMemCopyFrom = pSiSEnt->SiSFastMemCopyFrom;
8275       }
8276    }
8277#endif
8278
8279    if(pSiS->VideoTimerCallback) {
8280       (*pSiS->VideoTimerCallback)(pScrn, currentTime.milliseconds);
8281    }
8282
8283#ifdef SIS_USE_XAA
8284    if(pSiS->RenderCallback) {
8285       (*pSiS->RenderCallback)(pScrn);
8286    }
8287#endif
8288#ifdef SIS_USE_EXA
8289    if(pSiS->ExaRenderCallback) {
8290       (*pSiS->ExaRenderCallback)(pScrn);
8291    }
8292#endif
8293}
8294
8295
8296
8297/* Do screen blanking; DPMS handling
8298 *
8299 * Mandatory; latter optional
8300 */
8301
8302static void
8303SiSHandleBackLight(SISPtr pSiS, Bool blon)
8304{
8305    UChar sr11mask = (pSiS->SiS_Pr->SiS_SensibleSR11) ? 0x03 : 0xf3;
8306
8307    if(pSiS->VBFlags2 & VB2_SISLVDSBRIDGE) {
8308
8309       if(!blon) {
8310	  SiS_SiS30xBLOff(pSiS->SiS_Pr);
8311       } else {
8312	  SiS_SiS30xBLOn(pSiS->SiS_Pr);
8313       }
8314
8315    } else if( ((pSiS->VGAEngine == SIS_300_VGA) &&
8316	        (pSiS->VBFlags2 & (VB2_LVDS | VB2_30xBDH))) ||
8317	       ((pSiS->VGAEngine == SIS_315_VGA) &&
8318	        ((pSiS->VBFlags2 & (VB2_LVDS | VB2_CHRONTEL)) == VB2_LVDS)) ) {
8319
8320       if(!blon) {
8321	  setSISIDXREG(SISSR, 0x11, sr11mask, 0x08);
8322       } else {
8323	  setSISIDXREG(SISSR, 0x11, sr11mask, 0x00);
8324       }
8325
8326    } else if((pSiS->VGAEngine == SIS_315_VGA) &&
8327	      (pSiS->VBFlags2 & VB2_CHRONTEL)) {
8328
8329       if(!blon) {
8330	  SiS_Chrontel701xBLOff(pSiS->SiS_Pr);
8331       } else {
8332	  SiS_Chrontel701xBLOn(pSiS->SiS_Pr);
8333       }
8334
8335    }
8336}
8337
8338static Bool
8339SISSaveScreen(ScreenPtr pScreen, int mode)
8340{
8341    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
8342    SISPtr pSiS;
8343    Bool IsUnblank = xf86IsUnblank(mode) ? TRUE : FALSE;
8344
8345    if((pScrn == NULL) || (!pScrn->vtSema)) return TRUE;
8346
8347    pSiS = SISPTR(pScrn);
8348
8349#ifdef UNLOCK_ALWAYS
8350    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
8351#endif
8352
8353    if(pSiS->VBFlags & (CRT2_LCD | CRT1_LCDA)) {
8354       SiSHandleBackLight(pSiS, IsUnblank);
8355    }
8356
8357    if(!SiSBridgeIsInSlaveMode(pScrn)) {
8358       return SiSVGASaveScreen(pScreen, mode);
8359    }
8360
8361    return TRUE;
8362}
8363
8364#ifdef SISDUALHEAD
8365/* SaveScreen for dual head mode */
8366static Bool
8367SISSaveScreenDH(ScreenPtr pScreen, int mode)
8368{
8369    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
8370    SISPtr pSiS;
8371    Bool IsUnblank = xf86IsUnblank(mode) ? TRUE : FALSE;
8372
8373    if((pScrn == NULL) || (!pScrn->vtSema)) return TRUE;
8374
8375    pSiS = SISPTR(pScrn);
8376
8377    if( (pSiS->SecondHead) &&
8378        ((!(pSiS->VBFlags & CRT1_LCDA)) || (pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE)) ) {
8379
8380       /* Slave head is always CRT1 */
8381       /* (No backlight handling on TMDS bridges) */
8382       return SiSVGASaveScreen(pScreen, mode);
8383
8384    } else {
8385
8386       /* Master head is always CRT2 */
8387       /* But we land here for LCDA, too (if bridge is SiS LVDS type) */
8388
8389       /* We can only blank LCD, not other CRT2 devices */
8390       if(pSiS->VBFlags & (CRT2_LCD|CRT1_LCDA)) {
8391
8392#ifdef UNLOCK_ALWAYS
8393	  sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
8394#endif
8395	  SiSHandleBackLight(pSiS, IsUnblank);
8396
8397       }
8398
8399    }
8400    return TRUE;
8401}
8402#endif
8403
8404static void
8405SISDisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode, int flags)
8406{
8407    SISPtr pSiS = SISPTR(pScrn);
8408    Bool   docrt1 = TRUE, docrt2 = TRUE, backlight = TRUE;
8409    UChar  sr1=0, cr17=0, cr63=0, pmreg=0, sr7=0;
8410    UChar  p1_13=0, p2_0=0, oldpmreg=0;
8411
8412    if(!pScrn->vtSema) return;
8413
8414    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 4,
8415          "SISDisplayPowerManagementSet(%d)\n", PowerManagementMode);
8416
8417#ifdef SISDUALHEAD
8418    if(pSiS->DualHeadMode) {
8419       if(pSiS->SecondHead) docrt2 = FALSE;
8420       else                 docrt1 = FALSE;
8421    }
8422#endif
8423
8424    /* FIXME: in old servers, DPMSSet was supposed to be called without open
8425     * the correct PCI bridges before access the hardware. Now we have this
8426     * hook wrapped by the vga arbiter which should do all the work, in
8427     * kernels that implement it. For this case we might not want this hack
8428     * bellow.
8429     */
8430    outSISIDXREG(SISSR,0x05,0x86);
8431    inSISIDXREG(SISSR,0x05,pmreg);
8432    if(pmreg != 0xa1) return;
8433
8434#ifdef UNLOCK_ALWAYS
8435    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
8436#endif
8437
8438    switch(PowerManagementMode) {
8439
8440       case DPMSModeOn:      /* HSync: On, VSync: On */
8441	  sr1   = 0x00;
8442	  cr17  = 0x80;
8443	  pmreg = 0x00;
8444	  cr63  = 0x00;
8445	  sr7   = 0x10;
8446	  p2_0  = 0x20;
8447	  p1_13 = 0x00;
8448	  backlight = TRUE;
8449	  break;
8450
8451       case DPMSModeSuspend: /* HSync: On, VSync: Off */
8452	  sr1   = 0x20;
8453	  cr17  = 0x80;
8454	  pmreg = 0x80;
8455	  cr63  = 0x40;
8456	  sr7   = 0x00;
8457	  p2_0  = 0x40;
8458	  p1_13 = 0x80;
8459	  backlight = FALSE;
8460	  break;
8461
8462       case DPMSModeStandby: /* HSync: Off, VSync: On */
8463	  sr1   = 0x20;
8464	  cr17  = 0x80;
8465	  pmreg = 0x40;
8466	  cr63  = 0x40;
8467	  sr7   = 0x00;
8468	  p2_0  = 0x80;
8469	  p1_13 = 0x40;
8470	  backlight = FALSE;
8471	  break;
8472
8473       case DPMSModeOff:     /* HSync: Off, VSync: Off */
8474	  sr1   = 0x20;
8475	  cr17  = 0x00;
8476	  pmreg = 0xc0;
8477	  cr63  = 0x40;
8478	  sr7   = 0x00;
8479	  p2_0  = 0xc0;
8480	  p1_13 = 0xc0;
8481	  backlight = FALSE;
8482	  break;
8483
8484       default:
8485	    return;
8486    }
8487
8488    oldpmreg = pmreg;
8489
8490    if((docrt2 && (pSiS->VBFlags & CRT2_LCD)) ||
8491       (docrt1 && (pSiS->VBFlags & CRT1_LCDA))) {
8492       SiSHandleBackLight(pSiS, backlight);
8493    }
8494
8495    if(docrt1) {
8496       switch(pSiS->VGAEngine) {
8497       case SIS_OLD_VGA:
8498       case SIS_530_VGA:
8499	    setSISIDXREG(SISSR, 0x01, ~0x20, sr1);    /* Set/Clear "Display On" bit */
8500	    inSISIDXREG(SISSR, 0x11, oldpmreg);
8501	    setSISIDXREG(SISCR, 0x17, 0x7f, cr17);
8502	    setSISIDXREG(SISSR, 0x11, 0x3f, pmreg);
8503	    break;
8504       case SIS_315_VGA:
8505	    if( (!pSiS->CRT1off) &&
8506	        ((!(pSiS->VBFlags & CRT1_LCDA)) || (pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE)) ) {
8507	       setSISIDXREG(SISCR, pSiS->myCR63, 0xbf, cr63);
8508	       setSISIDXREG(SISSR, 0x07, 0xef, sr7);
8509	    }
8510	    /* fall through */
8511       default:
8512	    if(!SiSBridgeIsInSlaveMode(pScrn)) {
8513	       setSISIDXREG(SISSR, 0x01, ~0x20, sr1);    /* Set/Clear "Display On" bit */
8514	    }
8515	    if((!(pSiS->VBFlags & CRT1_LCDA)) || (pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE)) {
8516	       inSISIDXREG(SISSR, 0x1f, oldpmreg);
8517	       if((!pSiS->CRT1off) && (!SiSBridgeIsInSlaveMode(pScrn))) {
8518		  setSISIDXREG(SISSR, 0x1f, 0x3f, pmreg);
8519	       }
8520	    }
8521       }
8522       oldpmreg &= 0xc0;
8523    }
8524
8525    if(docrt2) {
8526       if(pSiS->VBFlags & CRT2_LCD) {
8527          if((pSiS->VBFlags2 & VB2_SISBRIDGE) &&
8528	     (!(pSiS->VBFlags2 & VB2_30xBDH))) {
8529	     if(pSiS->VGAEngine == SIS_300_VGA) {
8530	        SiS_UnLockCRT2(pSiS->SiS_Pr);
8531	        setSISIDXREG(SISPART1, 0x13, 0x3f, p1_13);
8532	     }
8533	     if(pSiS->VBFlags2 & VB2_SISLVDSBRIDGE) p2_0 |= 0x20;
8534	     setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
8535	  }
8536       } else if(pSiS->VBFlags & (CRT2_VGA | CRT2_TV)) {
8537	  if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
8538	     setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
8539	  }
8540       }
8541    }
8542
8543    if( (docrt1) &&
8544        (pmreg != oldpmreg) &&
8545        ((!(pSiS->VBFlags & CRT1_LCDA)) || (pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE)) ) {
8546       outSISIDXREG(SISSR, 0x00, 0x01);    /* Synchronous Reset */
8547       usleep(10000);
8548       outSISIDXREG(SISSR, 0x00, 0x03);    /* End Reset */
8549    }
8550
8551}
8552
8553/* Mandatory
8554 * This gets called at the start of each server generation
8555 *
8556 * We use pScrn and not CurrentLayout here, because the
8557 * properties we use have not changed (displayWidth,
8558 * depth, bitsPerPixel)
8559 */
8560static Bool
8561SISScreenInit(SCREEN_INIT_ARGS_DECL)
8562{
8563    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
8564    SISPtr pSiS = SISPTR(pScrn);
8565    VisualPtr visual;
8566    ULong OnScreenSize;
8567    int ret, height, width, displayWidth;
8568    UChar *FBStart;
8569#ifdef SISDUALHEAD
8570    SISEntPtr pSiSEnt = NULL;
8571#endif
8572
8573#ifdef SISDUALHEAD
8574    if((!pSiS->DualHeadMode) || (!pSiS->SecondHead)) {
8575#endif
8576       SiS_LoadInitVBE(pScrn);
8577#ifdef SISDUALHEAD
8578    }
8579#endif
8580
8581#ifdef SISDUALHEAD
8582    if(pSiS->DualHeadMode) {
8583       pSiSEnt = pSiS->entityPrivate;
8584       pSiSEnt->refCount++;
8585    }
8586#endif
8587
8588#ifdef SIS_PC_PLATFORM
8589    /* Map 64k VGA window for saving/restoring CGA fonts */
8590    SiS_MapVGAMem(pScrn);
8591#endif
8592
8593    /* Map the SiS memory and MMIO areas */
8594    if(!SISMapMem(pScrn)) {
8595       SISErrorLog(pScrn, "SiSMapMem() failed\n");
8596       return FALSE;
8597    }
8598
8599    SiS_SiSFB_Lock(pScrn, TRUE);
8600
8601#ifdef UNLOCK_ALWAYS
8602    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
8603#endif
8604
8605    /* Enable TurboQueue so that SISSave() saves it in enabled
8606     * state. If we don't do this, X will hang after a restart!
8607     * (Happens for some unknown reason only when using VESA
8608     * for mode switching; assumingly a BIOS issue.)
8609     * This is done on 300 and 315 series only.
8610     */
8611    if(pSiS->UseVESA) {
8612#ifdef SISVRAMQ
8613       if(pSiS->VGAEngine != SIS_315_VGA)
8614#endif
8615          SiSEnableTurboQueue(pScrn);
8616    }
8617
8618    /* Save the current state */
8619    SISSave(pScrn);
8620
8621    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
8622
8623       if(!pSiS->OldMode) {
8624
8625          /* Try to find out current (=old) mode number
8626	   * (Do this only if not sisfb has told us its mode yet)
8627	   */
8628
8629	  /* Read 0:449 which the BIOS sets to the current mode number
8630	   * Unfortunately, this not reliable since the int10 emulation
8631	   * does not change this. So if we call the VBE later, this
8632	   * byte won't be touched (which is why we set this manually
8633	   * then).
8634	   */
8635          UChar myoldmode = SiS_GetSetModeID(pScrn, 0xFF);
8636	  UChar cr30, cr31;
8637
8638          /* Read CR34 which the BIOS sets to the current mode number for CRT2
8639	   * This is - of course - not reliable if the machine has no video
8640	   * bridge...
8641	   */
8642          inSISIDXREG(SISCR, 0x34, pSiS->OldMode);
8643	  inSISIDXREG(SISCR, 0x30, cr30);
8644	  inSISIDXREG(SISCR, 0x31, cr31);
8645
8646	  /* What if CR34 is different from the BIOS scratch byte? */
8647	  if(pSiS->OldMode != myoldmode) {
8648	     /* If no bridge output is active, trust the BIOS scratch byte */
8649	     if( (!(pSiS->VBFlags2 & VB2_VIDEOBRIDGE)) ||
8650	         (pSiS->OldMode == 0)                  ||
8651	         (!cr31 && !cr30)                      ||
8652		 (cr31 & 0x20) ) {
8653		pSiS->OldMode = myoldmode;
8654 	     }
8655	     /* ..else trust CR34 */
8656	  }
8657
8658	  /* Newer 650 BIOSes set CR34 to 0xff if the mode has been
8659	   * "patched", for instance for 80x50 text mode. (That mode
8660	   * has no number of its own, it's 0x03 like 80x25). In this
8661	   * case, we trust the BIOS scratch byte (provided that any
8662	   * of these two is valid).
8663	   */
8664	  if(pSiS->OldMode > 0x7f) {
8665	     pSiS->OldMode = myoldmode;
8666	  }
8667       }
8668#ifdef SISDUALHEAD
8669       if(pSiS->DualHeadMode) {
8670          if(!pSiS->SecondHead) pSiSEnt->OldMode = pSiS->OldMode;
8671          else                  pSiS->OldMode = pSiSEnt->OldMode;
8672       }
8673#endif
8674    }
8675
8676    /* RandR resets screen mode and size in CloseScreen(), hence
8677     * we need to adapt our VBFlags to the initial state if the
8678     * current mode has changed since closescreen() (or Screeninit()
8679     * for the first instance)
8680     */
8681    if(pScrn->currentMode != pSiS->currentModeLast) {
8682       pSiS->VBFlags = pSiS->VBFlags_backup = pSiS->VBFlagsInit;
8683    }
8684
8685    /* Copy our detected monitor gammas, part 2. Note that device redetection
8686     * is not supported in DHM, so there is no need to do that anytime later.
8687     */
8688#ifdef SISDUALHEAD
8689    if(pSiS->DualHeadMode) {
8690       if(!pSiS->SecondHead) {
8691          /* CRT2 */
8692	  pSiS->CRT1VGAMonitorGamma = pSiSEnt->CRT1VGAMonitorGamma;
8693       } else {
8694          /* CRT1 */
8695	  pSiS->CRT2VGAMonitorGamma = pSiSEnt->CRT2VGAMonitorGamma;
8696       }
8697       if(!pSiS->CRT2LCDMonitorGamma) pSiS->CRT2LCDMonitorGamma = pSiSEnt->CRT2LCDMonitorGamma;
8698    }
8699#endif
8700
8701    /* Initialize the first mode */
8702    if(!SISModeInit(pScrn, pScrn->currentMode)) {
8703       SISErrorLog(pScrn, "SiSModeInit() failed\n");
8704       return FALSE;
8705    }
8706
8707    /* Darken the screen for aesthetic reasons */
8708    /* Not using Dual Head variant on purpose; we darken
8709     * the screen for both displays, and un-darken
8710     * it when the second head is finished
8711     */
8712    SISSaveScreen(pScreen, SCREEN_SAVER_ON);
8713
8714    /* Set the viewport */
8715    SISAdjustFrame(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0));
8716
8717    /* Reset visual list. */
8718    miClearVisualTypes();
8719
8720    /* Setup the visuals we support. */
8721
8722    /*
8723     * For bpp > 8, the default visuals are not acceptable because we only
8724     * support TrueColor and not DirectColor.
8725     */
8726    if(!miSetVisualTypes(pScrn->depth,
8727			 (pScrn->bitsPerPixel > 8) ?
8728				TrueColorMask : miGetDefaultVisualMask(pScrn->depth),
8729			 pScrn->rgbBits, pScrn->defaultVisual)) {
8730       SISSaveScreen(pScreen, SCREEN_SAVER_OFF);
8731       SISErrorLog(pScrn, "miSetVisualTypes() failed (bpp %d)\n",
8732			pScrn->bitsPerPixel);
8733       return FALSE;
8734    }
8735
8736    width = pScrn->virtualX;
8737    height = pScrn->virtualY;
8738    displayWidth = pScrn->displayWidth;
8739
8740    if(pSiS->Rotate) {
8741       height = pScrn->virtualX;
8742       width = pScrn->virtualY;
8743    }
8744
8745    if(pSiS->ShadowFB) {
8746       pSiS->ShadowPitch = BitmapBytePad(pScrn->bitsPerPixel * width);
8747       pSiS->ShadowPtr = malloc(pSiS->ShadowPitch * height);
8748       displayWidth = pSiS->ShadowPitch / (pScrn->bitsPerPixel >> 3);
8749       FBStart = pSiS->ShadowPtr;
8750    } else {
8751       pSiS->ShadowPtr = NULL;
8752       FBStart = pSiS->FbBase;
8753    }
8754
8755    if(!miSetPixmapDepths()) {
8756       SISSaveScreen(pScreen, SCREEN_SAVER_OFF);
8757       SISErrorLog(pScrn, "miSetPixmapDepths() failed\n");
8758       return FALSE;
8759    }
8760
8761    /* Point cmdQueuePtr to pSiSEnt for shared usage
8762     * (same technique is then eventually used in DRIScreeninit)
8763     * For 315/330 series, this is done in EnableTurboQueue
8764     * which has already been called during ModeInit().
8765     */
8766#ifdef SISDUALHEAD
8767    if(pSiS->SecondHead)
8768       pSiS->cmdQueueLenPtr = &(SISPTR(pSiSEnt->pScrn_1)->cmdQueueLen);
8769    else
8770#endif
8771       pSiS->cmdQueueLenPtr = &(pSiS->cmdQueueLen);
8772
8773    pSiS->cmdQueueLen = 0; /* Force an EngineIdle() at start */
8774
8775#ifdef SISDRI
8776    if(pSiS->loadDRI) {
8777#ifdef SISDUALHEAD
8778       /* No DRI in dual head mode */
8779       if(pSiS->DualHeadMode) {
8780	  pSiS->directRenderingEnabled = FALSE;
8781	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
8782		"DRI not supported in Dual Head mode\n");
8783       } else
8784#endif
8785	      if(pSiS->VGAEngine != SIS_315_VGA) {
8786	  /* Force the initialization of the context */
8787	  pSiS->directRenderingEnabled = SISDRIScreenInit(pScreen);
8788       } else {
8789	  xf86DrvMsg(pScrn->scrnIndex, X_NOT_IMPLEMENTED,
8790		"DRI not supported on this chipset\n");
8791	  pSiS->directRenderingEnabled = FALSE;
8792       }
8793    }
8794#endif
8795
8796    /* Call the framebuffer layer's ScreenInit function and fill in other
8797     * pScreen fields.
8798     */
8799    switch(pScrn->bitsPerPixel) {
8800       case 24:
8801	  if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
8802	     ret = FALSE;
8803	     break;
8804	  }
8805	  /* fall through */
8806       case 8:
8807       case 16:
8808       case 32:
8809	  ret = fbScreenInit(pScreen, FBStart, width,
8810			height, pScrn->xDpi, pScrn->yDpi,
8811			displayWidth, pScrn->bitsPerPixel);
8812	  break;
8813       default:
8814	  ret = FALSE;
8815	  break;
8816    }
8817    if(!ret) {
8818       SISErrorLog(pScrn, "Unsupported bpp (%d) or fbScreenInit() failed\n",
8819			pScrn->bitsPerPixel);
8820       SISSaveScreen(pScreen, SCREEN_SAVER_OFF);
8821       return FALSE;
8822    }
8823
8824    /* Fixup RGB ordering */
8825    if(pScrn->bitsPerPixel > 8) {
8826       visual = pScreen->visuals + pScreen->numVisuals;
8827       while (--visual >= pScreen->visuals) {
8828          if((visual->class | DynamicClass) == DirectColor) {
8829             visual->offsetRed = pScrn->offset.red;
8830             visual->offsetGreen = pScrn->offset.green;
8831             visual->offsetBlue = pScrn->offset.blue;
8832             visual->redMask = pScrn->mask.red;
8833             visual->greenMask = pScrn->mask.green;
8834             visual->blueMask = pScrn->mask.blue;
8835          }
8836       }
8837    }
8838
8839    /* Initialize RENDER extension (must be after RGB ordering fixed) */
8840    fbPictureInit(pScreen, 0, 0);
8841
8842    /* Hardware cursor needs to wrap this layer */
8843    if(!pSiS->ShadowFB) SISDGAInit(pScreen);
8844
8845    xf86SetBlackWhitePixels(pScreen);
8846
8847    /* Initialize the accelerators */
8848    switch(pSiS->VGAEngine) {
8849    case SIS_530_VGA:
8850    case SIS_300_VGA:
8851       SiS300AccelInit(pScreen);
8852       break;
8853    case SIS_315_VGA:
8854       SiS315AccelInit(pScreen);
8855       break;
8856    default:
8857       SiSAccelInit(pScreen);
8858    }
8859
8860#ifdef TWDEBUG
8861    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CPUFlags %x\n", pSiS->CPUFlags);
8862#endif
8863
8864    /* Benchmark memcpy() methods (needs FB manager initialized) */
8865    /* Dual head: Do this AFTER the mode for CRT1 has been set */
8866    pSiS->NeedCopyFastVidCpy = FALSE;
8867    if(!pSiS->SiSFastVidCopyDone) {
8868#ifdef SISDUALHEAD
8869       if(pSiS->DualHeadMode) {
8870	  if(pSiS->SecondHead) {
8871	     pSiSEnt->SiSFastVidCopy = SiSVidCopyInit(pScreen, &pSiSEnt->SiSFastMemCopy, FALSE);
8872	     pSiSEnt->SiSFastVidCopyFrom = SiSVidCopyGetDefault();
8873	     pSiSEnt->SiSFastMemCopyFrom = SiSVidCopyGetDefault();
8874#ifdef SIS_USE_EXA
8875	     if(pSiS->useEXA) {
8876	        pSiSEnt->SiSFastVidCopyFrom = SiSVidCopyInit(pScreen, &pSiSEnt->SiSFastMemCopyFrom, TRUE);
8877	     }
8878#endif /* EXA */
8879	     pSiSEnt->HaveFastVidCpy = TRUE;
8880	     pSiS->SiSFastVidCopy = pSiSEnt->SiSFastVidCopy;
8881	     pSiS->SiSFastMemCopy = pSiSEnt->SiSFastMemCopy;
8882	     pSiS->SiSFastVidCopyFrom = pSiSEnt->SiSFastVidCopyFrom;
8883	     pSiS->SiSFastMemCopyFrom = pSiSEnt->SiSFastMemCopyFrom;
8884	  } else {
8885	     pSiS->NeedCopyFastVidCpy = TRUE;
8886	  }
8887       } else {
8888#endif
8889	  pSiS->SiSFastVidCopy = SiSVidCopyInit(pScreen, &pSiS->SiSFastMemCopy, FALSE);
8890	  pSiS->SiSFastVidCopyFrom = SiSVidCopyGetDefault();
8891	  pSiS->SiSFastMemCopyFrom = SiSVidCopyGetDefault();
8892#ifdef SIS_USE_EXA
8893	  if(pSiS->useEXA) {
8894	     pSiS->SiSFastVidCopyFrom = SiSVidCopyInit(pScreen, &pSiS->SiSFastMemCopyFrom, TRUE);
8895	  }
8896#endif /* EXA */
8897#ifdef SISDUALHEAD
8898       }
8899#endif
8900    }
8901    pSiS->SiSFastVidCopyDone = TRUE;
8902
8903    xf86SetBackingStore(pScreen);
8904    xf86SetSilkenMouse(pScreen);
8905
8906    /* Initialise cursor functions */
8907    miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
8908
8909    if(pSiS->HWCursor) {
8910       SiSHWCursorInit(pScreen);
8911    }
8912
8913#ifdef SISDUALHEAD
8914    if(!pSiS->DualHeadMode) {
8915#endif
8916       if((pSiS->VBFlags2 & VB2_SISBRIDGE) && (pScrn->depth > 8)) {
8917
8918	  pSiS->CRT2ColNum = 1 << pScrn->rgbBits;
8919
8920	  if((pSiS->crt2gcolortable = malloc(pSiS->CRT2ColNum * 2 * sizeof(LOCO)))) {
8921	     pSiS->crt2colors = &pSiS->crt2gcolortable[pSiS->CRT2ColNum];
8922	     if((pSiS->crt2cindices = malloc(256 * sizeof(int)))) {
8923		int i = pSiS->CRT2ColNum;
8924		SISCalculateGammaRampCRT2(pScrn);
8925		while(i--) pSiS->crt2cindices[i] = i;
8926	     } else {
8927		free(pSiS->crt2gcolortable);
8928		pSiS->crt2gcolortable = NULL;
8929		pSiS->CRT2SepGamma = FALSE;
8930	     }
8931	  } else {
8932	     pSiS->CRT2SepGamma = FALSE;
8933	  }
8934
8935	  if(!pSiS->crt2cindices) {
8936	     xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
8937	  	"Failed to allocate cmap for CRT2, separate gamma correction disabled\n");
8938	  }
8939
8940       }
8941#ifdef SISDUALHEAD
8942    } else pSiS->CRT2SepGamma = FALSE;
8943#endif
8944
8945    /* Initialise default colormap */
8946    if(!miCreateDefColormap(pScreen)) {
8947       SISSaveScreen(pScreen, SCREEN_SAVER_OFF);
8948       SISErrorLog(pScrn, "miCreateDefColormap() failed\n");
8949       return FALSE;
8950    }
8951
8952    if(!xf86HandleColormaps(pScreen, 256, (pScrn->depth == 8) ? 8 : pScrn->rgbBits,
8953                    SISLoadPalette, NULL,
8954                    CMAP_PALETTED_TRUECOLOR | CMAP_RELOAD_ON_MODE_SWITCH)) {
8955       SISSaveScreen(pScreen, SCREEN_SAVER_OFF);
8956       SISErrorLog(pScrn, "xf86HandleColormaps() failed\n");
8957       return FALSE;
8958    }
8959
8960    /* Recalculate our gamma ramp for brightness feature */
8961#ifdef SISGAMMARAMP
8962    if((pSiS->GammaBriR != 1000) ||
8963       (pSiS->GammaBriB != 1000) ||
8964       (pSiS->GammaBriG != 1000) ||
8965       (pSiS->NewGammaBriR != 0.0) ||
8966       (pSiS->NewGammaBriG != 0.0) ||
8967       (pSiS->NewGammaBriB != 0.0) ||
8968       (pSiS->NewGammaConR != 0.0) ||
8969       (pSiS->NewGammaConG != 0.0) ||
8970       (pSiS->NewGammaConB != 0.0)) {
8971       SISCalculateGammaRamp(pScreen, pScrn);
8972    }
8973#endif
8974
8975    /* Initialize Shadow framebuffer and screen rotation/reflection */
8976    if(pSiS->ShadowFB) {
8977       RefreshAreaFuncPtr refreshArea = SISRefreshArea;
8978
8979       if(pSiS->Rotate) {
8980	  if(!pSiS->PointerMoved) pSiS->PointerMoved = pScrn->PointerMoved;
8981	  pScrn->PointerMoved = SISPointerMoved;
8982	  switch(pScrn->bitsPerPixel) {
8983	     case 8:  refreshArea = SISRefreshArea8;  break;
8984	     case 16: refreshArea = SISRefreshArea16; break;
8985	     case 24: refreshArea = SISRefreshArea24; break;
8986	     case 32: refreshArea = SISRefreshArea32; break;
8987	  }
8988#if (XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4,3,0,0,0)) && (GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 24)
8989	  xf86DisableRandR();
8990	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
8991		"Driver rotation enabled, disabling RandR\n");
8992#endif
8993       } else if(pSiS->Reflect) {
8994          switch(pScrn->bitsPerPixel) {
8995	  case 8:
8996	  case 16:
8997	  case 32:
8998             if(!pSiS->PointerMoved) pSiS->PointerMoved = pScrn->PointerMoved;
8999	     pScrn->PointerMoved = SISPointerMovedReflect;
9000	     refreshArea = SISRefreshAreaReflect;
9001#if (XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4,3,0,0,0)) && (GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 24)
9002	     xf86DisableRandR();
9003	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
9004		  "Driver reflection enabled, disabling RandR\n");
9005#endif
9006	     break;
9007	  default:
9008	     xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
9009	     	  "Reflection not supported at this framebuffer depth\n");
9010	  }
9011       }
9012
9013       ShadowFBInit(pScreen, refreshArea);
9014    }
9015
9016    xf86DPMSInit(pScreen, (DPMSSetProcPtr)SISDisplayPowerManagementSet, 0);
9017
9018    /* Init memPhysBase and fbOffset in pScrn */
9019    pScrn->memPhysBase = pSiS->FbAddress;
9020    pScrn->fbOffset = 0;
9021
9022    /* Initialize Xv */
9023    pSiS->ResetXv = pSiS->ResetXvGamma = pSiS->ResetXvDisplay = NULL;
9024#if (XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4,3,99,0,0)) || (defined(XvExtension))
9025    if((!pSiS->NoXvideo) && (!(pSiS->SiS_SD2_Flags & SiS_SD2_NOOVERLAY))) {
9026
9027       if((pSiS->VGAEngine == SIS_300_VGA) ||
9028	  (pSiS->VGAEngine == SIS_315_VGA)) {
9029
9030	  const char *using = "Using SiS300/315/330/340 series HW Xv";
9031
9032#ifdef SISDUALHEAD
9033	  if(pSiS->DualHeadMode) {
9034	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
9035		    "%s on CRT%d\n", using, (pSiS->SecondHead ? 1 : 2));
9036	     if(!pSiS->hasTwoOverlays) {
9037		if( (pSiS->XvOnCRT2 && pSiS->SecondHead) ||
9038		    (!pSiS->XvOnCRT2 && !pSiS->SecondHead) ) {
9039		   xf86DrvMsg(pScrn->scrnIndex, X_INFO,
9040			   "However, video overlay will by default only be visible on CRT%d\n",
9041			   pSiS->XvOnCRT2 ? 2 : 1);
9042		}
9043	     }
9044	  } else {
9045#endif
9046	     if(pSiS->hasTwoOverlays) {
9047		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s\n", using);
9048	     } else {
9049		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s by default on CRT%d\n",
9050			using, (pSiS->XvOnCRT2 ? 2 : 1));
9051	     }
9052#ifdef SISDUALHEAD
9053	  }
9054#endif
9055
9056	  SISInitVideo(pScreen);
9057
9058	  if(pSiS->blitadaptor) {
9059	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
9060		     "Default Xv adaptor is Video %s\n",
9061		     pSiS->XvDefAdaptorBlit ? "Blitter" : "Overlay");
9062	  }
9063
9064       } else if(pSiS->Chipset == PCI_CHIP_SIS530  ||
9065		 pSiS->Chipset == PCI_CHIP_SIS6326 ||
9066		 pSiS->Chipset == PCI_CHIP_SIS5597) {
9067
9068	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
9069		        "Using SiS5597/5598/6326/530/620 HW Xv\n" );
9070
9071	  SIS6326InitVideo(pScreen);
9072
9073       } else { /* generic Xv */
9074
9075	  XF86VideoAdaptorPtr *ptr;
9076	  int n = xf86XVListGenericAdaptors(pScrn, &ptr);
9077
9078	  if(n) {
9079	     xf86XVScreenInit(pScreen, ptr, n);
9080	     xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using generic Xv\n" );
9081          }
9082
9083       }
9084    }
9085#endif
9086
9087#ifdef SISDRI
9088    if(pSiS->loadDRI) {
9089       if(pSiS->directRenderingEnabled) {
9090          /* Now that mi, drm and others have done their thing,
9091           * complete the DRI setup.
9092           */
9093          pSiS->directRenderingEnabled = SISDRIFinishScreenInit(pScreen);
9094       }
9095       xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Direct rendering %s\n",
9096		pSiS->directRenderingEnabled ? "enabled" : "disabled");
9097       /* TODO */
9098       /* if(pSiS->directRenderingEnabled) SISSetLFBConfig(pSiS); */
9099    }
9100#endif
9101
9102    /* Wrap some funcs, initialize pseudo-Xinerama and setup remaining SD flags */
9103
9104    pSiS->SiS_SD_Flags &= ~(SiS_SD_PSEUDOXINERAMA);
9105#ifdef SISMERGED
9106    if(pSiS->MergedFB) {
9107       pSiS->PointerMoved = pScrn->PointerMoved;
9108       pScrn->PointerMoved = SISMergedPointerMoved;
9109       pSiS->Rotate = 0;
9110       pSiS->Reflect = 0;
9111       pSiS->ShadowFB = FALSE;
9112#if (XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4,3,0,0,0)) && (GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 24)
9113       if(pSiS->CRT1XOffs || pSiS->CRT1YOffs || pSiS->CRT2XOffs || pSiS->CRT2YOffs) {
9114	  xf86DisableRandR();
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#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 20
9332  int		sigstate;
9333#endif
9334  Bool		doit = FALSE, HaveNonRect = FALSE, HaveOffsRegions = FALSE;
9335  SiSScrn2Rel   srel = ((SiSMergedDisplayModePtr)pSiS->CurrentLayout.mode->Private)->CRT2Position;
9336
9337  if(pSiS->DGAactive) {
9338     return;
9339     /* DGA: There is no cursor and no panning while DGA is active. */
9340     /* If it were, we would need to do: */
9341     /* HVirt = pSiS->CurrentLayout.displayWidth;
9342        VVirt = pSiS->CurrentLayout.displayHeight;
9343        BOUND(x, pSiS->CurrentLayout.DGAViewportX, HVirt);
9344        BOUND(y, pSiS->CurrentLayout.DGAViewportY, VVirt); */
9345  } else {
9346     CRT1XOffs = pSiS->CRT1XOffs;
9347     CRT1YOffs = pSiS->CRT1YOffs;
9348     CRT2XOffs = pSiS->CRT2XOffs;
9349     CRT2YOffs = pSiS->CRT2YOffs;
9350     HaveNonRect = pSiS->HaveNonRect;
9351     HaveOffsRegions = pSiS->HaveOffsRegions;
9352  }
9353
9354  /* Check if the pointer is inside our dead areas */
9355  if((pSiS->MouseRestrictions) && (srel != sisClone) && !SiSnoPanoramiXExtension) {
9356     if(HaveNonRect) {
9357	if(InRegion(x, y, pSiS->NonRectDead)) {
9358	   switch(srel) {
9359	   case sisLeftOf:
9360	   case sisRightOf: y = pSiS->NonRectDead.y0 - 1;
9361			    doit = TRUE;
9362			    break;
9363	   case sisAbove:
9364	   case sisBelow:   x = pSiS->NonRectDead.x0 - 1;
9365			    doit = TRUE;
9366	   default:	    break;
9367	   }
9368	}
9369     }
9370     if(HaveOffsRegions) {
9371	if(InRegion(x, y, pSiS->OffDead1)) {
9372	   switch(srel) {
9373	   case sisLeftOf:
9374	   case sisRightOf: y = pSiS->OffDead1.y1;
9375			    doit = TRUE;
9376			    break;
9377	   case sisAbove:
9378	   case sisBelow:   x = pSiS->OffDead1.x1;
9379			    doit = TRUE;
9380	   default:	    break;
9381	   }
9382	} else if(InRegion(x, y, pSiS->OffDead2)) {
9383	   switch(srel) {
9384	   case sisLeftOf:
9385	   case sisRightOf: y = pSiS->OffDead2.y0 - 1;
9386			    doit = TRUE;
9387			    break;
9388	   case sisAbove:
9389	   case sisBelow:   x = pSiS->OffDead2.x0 - 1;
9390			    doit = TRUE;
9391	   default:	    break;
9392	   }
9393	}
9394     }
9395     if(doit) {
9396#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 20 /* screw it */
9397	sigstate = xf86BlockSIGIO();
9398#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 15
9399        {
9400            double dx = x, dy = y;
9401            miPointerSetPosition(inputInfo.pointer, Absolute, &dx, &dy);
9402            x = (int)dx;
9403            y = (int)dy;
9404        }
9405#elif GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 13
9406	miPointerSetPosition(inputInfo.pointer, Absolute, &x, &y);
9407#elif GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 5
9408	miPointerSetPosition(inputInfo.pointer, &x, &y);
9409#else
9410	UpdateCurrentTime();
9411	miPointerAbsoluteCursor(x, y, currentTime.milliseconds);
9412#endif
9413	xf86UnblockSIGIO(sigstate);
9414#endif
9415	return;
9416     }
9417  }
9418
9419  f1.x0 = old1x0 = pSiS->CRT1frameX0;
9420  f1.x1 = pSiS->CRT1frameX1;
9421  f1.y0 = old1y0 = pSiS->CRT1frameY0;
9422  f1.y1 = pSiS->CRT1frameY1;
9423  f2.x0 = old2x0 = pScrn2->frameX0;
9424  f2.x1 = pScrn2->frameX1;
9425  f2.y0 = old2y0 = pScrn2->frameY0;
9426  f2.y1 = pScrn2->frameY1;
9427
9428  /* Define the outer region. Crossing this causes all frames to move */
9429  out.x0 = pScrn1->frameX0;
9430  out.x1 = pScrn1->frameX1;
9431  out.y0 = pScrn1->frameY0;
9432  out.y1 = pScrn1->frameY1;
9433
9434  /*
9435   * Define the inner sliding window. Being outsize both frames but
9436   * inside the outer clipping window will slide corresponding frame
9437   */
9438  in1 = out;
9439  in2 = out;
9440  switch(srel) {
9441     case sisLeftOf:
9442        in1.x0 = f1.x0;
9443        in2.x1 = f2.x1;
9444        break;
9445     case sisRightOf:
9446        in1.x1 = f1.x1;
9447        in2.x0 = f2.x0;
9448        break;
9449     case sisBelow:
9450        in1.y1 = f1.y1;
9451        in2.y0 = f2.y0;
9452        break;
9453     case sisAbove:
9454        in1.y0 = f1.y0;
9455        in2.y1 = f2.y1;
9456        break;
9457     case sisClone:
9458        break;
9459  }
9460
9461  deltay = 0;
9462  deltax = 0;
9463
9464  if(InRegion(x, y, out)) {	/* inside outer region */
9465
9466     if(InRegion(x, y, in1) && !InRegion(x, y, f1)) {
9467	REBOUND(f1.x0, f1.x1, x);
9468	REBOUND(f1.y0, f1.y1, y);
9469	deltax = 1;
9470     }
9471     if(InRegion(x, y, in2) && !InRegion(x, y, f2)) {
9472	REBOUND(f2.x0, f2.x1, x);
9473	REBOUND(f2.y0, f2.y1, y);
9474	deltax = 1;
9475     }
9476
9477  } else {			/* outside outer region */
9478
9479     if(out.x0 > x) {
9480	deltax = x - out.x0;
9481     }
9482     if(out.x1 < x) {
9483	deltax = x - out.x1;
9484     }
9485     if(deltax) {
9486	pScrn1->frameX0 += deltax;
9487	pScrn1->frameX1 += deltax;
9488	f1.x0 += deltax;
9489	f1.x1 += deltax;
9490	f2.x0 += deltax;
9491	f2.x1 += deltax;
9492     }
9493
9494     if(out.y0 > y) {
9495	deltay = y - out.y0;
9496     }
9497     if(out.y1 < y) {
9498	deltay = y - out.y1;
9499     }
9500     if(deltay) {
9501	pScrn1->frameY0 += deltay;
9502	pScrn1->frameY1 += deltay;
9503	f1.y0 += deltay;
9504	f1.y1 += deltay;
9505	f2.y0 += deltay;
9506	f2.y1 += deltay;
9507     }
9508
9509     switch(srel) {
9510	case sisLeftOf:
9511	   if(x >= f1.x0) { REBOUND(f1.y0, f1.y1, y); }
9512	   if(x <= f2.x1) { REBOUND(f2.y0, f2.y1, y); }
9513	   break;
9514	case sisRightOf:
9515	   if(x <= f1.x1) { REBOUND(f1.y0, f1.y1, y); }
9516	   if(x >= f2.x0) { REBOUND(f2.y0, f2.y1, y); }
9517	   break;
9518	case sisBelow:
9519	   if(y <= f1.y1) { REBOUND(f1.x0, f1.x1, x); }
9520	   if(y >= f2.y0) { REBOUND(f2.x0, f2.x1, x); }
9521	   break;
9522	case sisAbove:
9523	   if(y >= f1.y0) { REBOUND(f1.x0, f1.x1, x); }
9524	   if(y <= f2.y1) { REBOUND(f2.x0, f2.x1, x); }
9525	   break;
9526	case sisClone:
9527	   break;
9528     }
9529
9530  }
9531
9532  if(deltax || deltay) {
9533     pSiS->CRT1frameX0 = f1.x0;
9534     pSiS->CRT1frameY0 = f1.y0;
9535     pScrn2->frameX0 = f2.x0;
9536     pScrn2->frameY0 = f2.y0;
9537
9538     switch(srel) {
9539	case sisLeftOf:
9540	case sisRightOf:
9541	   if(CRT1YOffs || CRT2YOffs || HaveNonRect) {
9542	      if(pSiS->CRT1frameY0 != old1y0) {
9543	         if(pSiS->CRT1frameY0 < CRT1YOffs)
9544	            pSiS->CRT1frameY0 = CRT1YOffs;
9545
9546	         temp1 = pSiS->CRT1frameY0 + CDMPTR->CRT1->VDisplay;
9547	         temp2 = min((VVirt - CRT2YOffs), (CRT1YOffs + pSiS->MBXNR1YMAX));
9548	         if(temp1 > temp2)
9549	            pSiS->CRT1frameY0 -= (temp1 - temp2);
9550	      }
9551	      if(pScrn2->frameY0 != old2y0) {
9552	         if(pScrn2->frameY0 < CRT2YOffs)
9553	            pScrn2->frameY0 = CRT2YOffs;
9554
9555	         temp1 = pScrn2->frameY0 + CDMPTR->CRT2->VDisplay;
9556	         temp2 = min((VVirt - CRT1YOffs), (CRT2YOffs + pSiS->MBXNR2YMAX));
9557	         if(temp1 > temp2)
9558	            pScrn2->frameY0 -= (temp1 - temp2);
9559	      }
9560	   }
9561	   break;
9562	case sisBelow:
9563	case sisAbove:
9564	   if(CRT1XOffs || CRT2XOffs || HaveNonRect) {
9565	      if(pSiS->CRT1frameX0 != old1x0) {
9566	         if(pSiS->CRT1frameX0 < CRT1XOffs)
9567	            pSiS->CRT1frameX0 = CRT1XOffs;
9568
9569	         temp1 = pSiS->CRT1frameX0 + CDMPTR->CRT1->HDisplay;
9570	         temp2 = min((HVirt - CRT2XOffs), (CRT1XOffs + pSiS->MBXNR1XMAX));
9571	         if(temp1 > temp2)
9572	            pSiS->CRT1frameX0 -= (temp1 - temp2);
9573	      }
9574	      if(pScrn2->frameX0 != old2x0) {
9575	         if(pScrn2->frameX0 < CRT2XOffs)
9576	            pScrn2->frameX0 = CRT2XOffs;
9577
9578	         temp1 = pScrn2->frameX0 + CDMPTR->CRT2->HDisplay;
9579	         temp2 = min((HVirt - CRT1XOffs), (CRT2XOffs + pSiS->MBXNR2XMAX));
9580	         if(temp1 > temp2)
9581	            pScrn2->frameX0 -= (temp1 - temp2);
9582	      }
9583	   }
9584	   break;
9585	case sisClone:
9586	   break;
9587     }
9588
9589     pSiS->CRT1frameX1 = pSiS->CRT1frameX0 + CDMPTR->CRT1->HDisplay - 1;
9590     pSiS->CRT1frameY1 = pSiS->CRT1frameY0 + CDMPTR->CRT1->VDisplay - 1;
9591     pScrn2->frameX1   = pScrn2->frameX0   + CDMPTR->CRT2->HDisplay - 1;
9592     pScrn2->frameY1   = pScrn2->frameY0   + CDMPTR->CRT2->VDisplay - 1;
9593
9594     /* No need to update pScrn1->frame?1, done above */
9595
9596     SISAdjustFrameHW_CRT1(pScrn1, pSiS->CRT1frameX0, pSiS->CRT1frameY0);
9597     SISAdjustFrameHW_CRT2(pScrn1, pScrn2->frameX0, pScrn2->frameY0);
9598  }
9599}
9600
9601static void
9602SISAdjustFrameMerged(ADJUST_FRAME_ARGS_DECL)
9603{
9604    SCRN_INFO_PTR(arg);
9605    ScrnInfoPtr pScrn1 = pScrn;
9606    SISPtr pSiS = SISPTR(pScrn1);
9607    ScrnInfoPtr pScrn2 = pSiS->CRT2pScrn;
9608    int HTotal = pSiS->CurrentLayout.mode->HDisplay;
9609    int VTotal = pSiS->CurrentLayout.mode->VDisplay;
9610    int HMax = HTotal;
9611    int VMax = VTotal;
9612    int HVirt = pScrn1->virtualX;
9613    int VVirt = pScrn1->virtualY;
9614    int x1 = x, x2 = x;
9615    int y1 = y, y2 = y;
9616    int CRT1XOffs = 0, CRT1YOffs = 0, CRT2XOffs = 0, CRT2YOffs = 0;
9617    int MBXNR1XMAX = 65536, MBXNR1YMAX = 65536, MBXNR2XMAX = 65536, MBXNR2YMAX = 65536;
9618
9619    if(pSiS->DGAactive) {
9620       HVirt = pSiS->CurrentLayout.displayWidth;
9621       VVirt = pSiS->CurrentLayout.displayHeight;
9622    } else {
9623       CRT1XOffs = pSiS->CRT1XOffs;
9624       CRT1YOffs = pSiS->CRT1YOffs;
9625       CRT2XOffs = pSiS->CRT2XOffs;
9626       CRT2YOffs = pSiS->CRT2YOffs;
9627       MBXNR1XMAX = pSiS->MBXNR1XMAX;
9628       MBXNR1YMAX = pSiS->MBXNR1YMAX;
9629       MBXNR2XMAX = pSiS->MBXNR2XMAX;
9630       MBXNR2YMAX = pSiS->MBXNR2YMAX;
9631    }
9632
9633    BOUND(x, 0, HVirt - HTotal);
9634    BOUND(y, 0, VVirt - VTotal);
9635    if(SDMPTR(pScrn1)->CRT2Position != sisClone) {
9636       BOUND(x1, CRT1XOffs, min(HVirt, MBXNR1XMAX + CRT1XOffs) - min(HTotal, MBXNR1XMAX) - CRT2XOffs);
9637       BOUND(y1, CRT1YOffs, min(VVirt, MBXNR1YMAX + CRT1YOffs) - min(VTotal, MBXNR1YMAX) - CRT2YOffs);
9638       BOUND(x2, CRT2XOffs, min(HVirt, MBXNR2XMAX + CRT2XOffs) - min(HTotal, MBXNR2XMAX) - CRT1XOffs);
9639       BOUND(y2, CRT2YOffs, min(VVirt, MBXNR2YMAX + CRT2YOffs) - min(VTotal, MBXNR2YMAX) - CRT1YOffs);
9640    }
9641
9642    switch(SDMPTR(pScrn1)->CRT2Position) {
9643        case sisLeftOf:
9644            pScrn2->frameX0 = x2;
9645            BOUND(pScrn2->frameY0,   y2, y2 + min(VMax, MBXNR2YMAX) - CDMPTR->CRT2->VDisplay);
9646            pSiS->CRT1frameX0 = x1 + CDMPTR->CRT2->HDisplay;
9647            BOUND(pSiS->CRT1frameY0, y1, y1 + min(VMax, MBXNR1YMAX) - CDMPTR->CRT1->VDisplay);
9648            break;
9649        case sisRightOf:
9650            pSiS->CRT1frameX0 = x1;
9651            BOUND(pSiS->CRT1frameY0, y1, y1 + min(VMax, MBXNR1YMAX) - CDMPTR->CRT1->VDisplay);
9652            pScrn2->frameX0 = x2 + CDMPTR->CRT1->HDisplay;
9653            BOUND(pScrn2->frameY0,   y2, y2 + min(VMax, MBXNR2YMAX) - CDMPTR->CRT2->VDisplay);
9654            break;
9655        case sisAbove:
9656            BOUND(pScrn2->frameX0,   x2, x2 + min(HMax, MBXNR2XMAX) - CDMPTR->CRT2->HDisplay);
9657            pScrn2->frameY0 = y2;
9658            BOUND(pSiS->CRT1frameX0, x1, x1 + min(HMax, MBXNR1XMAX) - CDMPTR->CRT1->HDisplay);
9659            pSiS->CRT1frameY0 = y1 + CDMPTR->CRT2->VDisplay;
9660            break;
9661        case sisBelow:
9662            BOUND(pSiS->CRT1frameX0, x1, x1 + min(HMax, MBXNR1XMAX) - CDMPTR->CRT1->HDisplay);
9663            pSiS->CRT1frameY0 = y1;
9664            BOUND(pScrn2->frameX0,   x2, x2 + min(HMax, MBXNR2XMAX) - CDMPTR->CRT2->HDisplay);
9665            pScrn2->frameY0 = y2 + CDMPTR->CRT1->VDisplay;
9666            break;
9667        case sisClone:
9668            BOUND(pSiS->CRT1frameX0, x,  x + HMax - CDMPTR->CRT1->HDisplay);
9669            BOUND(pSiS->CRT1frameY0, y,  y + VMax - CDMPTR->CRT1->VDisplay);
9670            BOUND(pScrn2->frameX0,   x,  x + HMax - CDMPTR->CRT2->HDisplay);
9671            BOUND(pScrn2->frameY0,   y,  y + VMax - CDMPTR->CRT2->VDisplay);
9672            break;
9673    }
9674
9675    BOUND(pSiS->CRT1frameX0, 0, HVirt - CDMPTR->CRT1->HDisplay);
9676    BOUND(pSiS->CRT1frameY0, 0, VVirt - CDMPTR->CRT1->VDisplay);
9677    BOUND(pScrn2->frameX0,   0, HVirt - CDMPTR->CRT2->HDisplay);
9678    BOUND(pScrn2->frameY0,   0, VVirt - CDMPTR->CRT2->VDisplay);
9679
9680    pScrn1->frameX0 = x;
9681    pScrn1->frameY0 = y;
9682
9683    pSiS->CRT1frameX1 = pSiS->CRT1frameX0 + CDMPTR->CRT1->HDisplay - 1;
9684    pSiS->CRT1frameY1 = pSiS->CRT1frameY0 + CDMPTR->CRT1->VDisplay - 1;
9685    pScrn2->frameX1   = pScrn2->frameX0   + CDMPTR->CRT2->HDisplay - 1;
9686    pScrn2->frameY1   = pScrn2->frameY0   + CDMPTR->CRT2->VDisplay - 1;
9687
9688    pScrn1->frameX1   = pScrn1->frameX0   + pSiS->CurrentLayout.mode->HDisplay  - 1;
9689    pScrn1->frameY1   = pScrn1->frameY0   + pSiS->CurrentLayout.mode->VDisplay  - 1;
9690    if(SDMPTR(pScrn1)->CRT2Position != sisClone) {
9691       pScrn1->frameX1 += CRT1XOffs + CRT2XOffs;
9692       pScrn1->frameY1 += CRT1YOffs + CRT2YOffs;
9693    }
9694
9695    SISAdjustFrameHW_CRT1(pScrn1, pSiS->CRT1frameX0, pSiS->CRT1frameY0);
9696    SISAdjustFrameHW_CRT2(pScrn1, pScrn2->frameX0, pScrn2->frameY0);
9697}
9698#endif
9699
9700/*
9701 * This function is used to initialize the Start Address - the first
9702 * displayed location in the video memory.
9703 *
9704 * Usually mandatory
9705 */
9706void
9707SISAdjustFrame(ADJUST_FRAME_ARGS_DECL)
9708{
9709    SCRN_INFO_PTR(arg);
9710    SISPtr        pSiS = SISPTR(pScrn);
9711    ULong base;
9712    UChar temp, cr11backup;
9713
9714#ifdef SISMERGED
9715    if(pSiS->MergedFB) {
9716        SISAdjustFrameMerged(ADJUST_FRAME_ARGS(pScrn, x, y));
9717	return;
9718    }
9719#endif
9720
9721    if(pSiS->UseVESA) {
9722	VBESetDisplayStart(pSiS->pVbe, x, y, TRUE);
9723	return;
9724    }
9725
9726    if(pScrn->bitsPerPixel < 8) {
9727       base = (y * pSiS->CurrentLayout.displayWidth + x + 3) >> 3;
9728    } else {
9729       base  = y * pSiS->CurrentLayout.displayWidth + x;
9730
9731       /* calculate base bpp dep. */
9732       switch(pSiS->CurrentLayout.bitsPerPixel) {
9733          case 16:
9734     	     base >>= 1;
9735             break;
9736          case 24:
9737             base = ((base * 3)) >> 2;
9738             base -= base % 6;
9739             break;
9740          case 32:
9741             break;
9742          default:      /* 8bpp */
9743             base >>= 2;
9744             break;
9745       }
9746    }
9747
9748#ifdef UNLOCK_ALWAYS
9749    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
9750#endif
9751
9752    base += (pSiS->dhmOffset/4);
9753
9754#ifdef TWDEBUG
9755    xf86DrvMsg(0, 0, "AdjustFrame: x %d y %d bpp %d dw %d base %d, dhmOffset %d\n",
9756    			x, y, pSiS->CurrentLayout.bitsPerPixel, pSiS->CurrentLayout.displayWidth, base, pSiS->dhmOffset);
9757#endif
9758
9759#ifdef SISDUALHEAD
9760    if(pSiS->DualHeadMode) {
9761       if(!pSiS->SecondHead) {
9762	  /* Head 1 (master) is always CRT2 */
9763	  SISSetStartAddressCRT2(pSiS, base);
9764       } else {
9765	  /* Head 2 (slave) is always CRT1 */
9766	  SISSetStartAddressCRT1(pSiS, base);
9767       }
9768    } else {
9769#endif
9770       switch(pSiS->VGAEngine) {
9771	  case SIS_300_VGA:
9772	  case SIS_315_VGA:
9773	     SISSetStartAddressCRT1(pSiS, base);
9774	     if(pSiS->VBFlags & CRT2_ENABLE) {
9775		if(!SiSBridgeIsInSlaveMode(pScrn)) {
9776		   SISSetStartAddressCRT2(pSiS, base);
9777		}
9778	     }
9779	     break;
9780	  default:
9781	     /* Unlock CRTC registers */
9782	     inSISIDXREG(SISCR,  0x11, cr11backup);
9783	     andSISIDXREG(SISCR, 0x11, 0x7F);
9784	     outSISIDXREG(SISCR, 0x0D, base & 0xFF);
9785	     outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF);
9786	     inSISIDXREG(SISSR,  0x27, temp);
9787	     temp &= 0xF0;
9788	     temp |= (base & 0x0F0000) >> 16;
9789	     outSISIDXREG(SISSR, 0x27, temp);
9790	     /* Eventually lock CRTC registers */
9791	     setSISIDXREG(SISCR, 0x11, 0x7F, (cr11backup & 0x80));
9792       }
9793#ifdef SISDUALHEAD
9794    }
9795#endif
9796
9797}
9798
9799/*
9800 * This is called when VT switching back to the X server.  Its job is
9801 * to reinitialise the video mode.
9802 * Mandatory!
9803 */
9804static Bool
9805SISEnterVT(VT_FUNC_ARGS_DECL)
9806{
9807    SCRN_INFO_PTR(arg);
9808    SISPtr pSiS = SISPTR(pScrn);
9809
9810    SiS_SiSFB_Lock(pScrn, TRUE);
9811
9812    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
9813
9814    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
9815       outSISIDXREG(SISCR,0x32,pSiS->myCR32);
9816       outSISIDXREG(SISCR,0x36,pSiS->myCR36);
9817       outSISIDXREG(SISCR,0x37,pSiS->myCR37);
9818    }
9819
9820    if(!SISModeInit(pScrn, pScrn->currentMode)) {
9821       SISErrorLog(pScrn, "SiSEnterVT: SISModeInit() failed\n");
9822       return FALSE;
9823    }
9824
9825    SISAdjustFrame(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0));
9826
9827#ifdef SISDRI
9828    if(pSiS->directRenderingEnabled) {
9829       DRIUnlock(xf86ScrnToScreen(pScrn));
9830    }
9831#endif
9832
9833#ifdef SISDUALHEAD
9834    if((!pSiS->DualHeadMode) || (!pSiS->SecondHead))
9835#endif
9836       if(pSiS->ResetXv) {
9837          (pSiS->ResetXv)(pScrn);
9838       }
9839
9840    return TRUE;
9841}
9842
9843/*
9844 * This is called when VT switching away from the X server.  Its job is
9845 * to restore the previous (text) mode.
9846 * Mandatory!
9847 */
9848static void
9849SISLeaveVT(VT_FUNC_ARGS_DECL)
9850{
9851    SCRN_INFO_PTR(arg);
9852    SISPtr pSiS = SISPTR(pScrn);
9853#ifdef SISDRI
9854    ScreenPtr pScreen;
9855
9856    if(pSiS->directRenderingEnabled) {
9857       pScreen = xf86ScrnToScreen(pScrn);
9858       DRILock(pScreen, 0);
9859    }
9860#endif
9861
9862#ifdef SISDUALHEAD
9863    if(pSiS->DualHeadMode && pSiS->SecondHead) return;
9864#endif
9865
9866    if(pSiS->CursorInfoPtr) {
9867#ifdef SISDUALHEAD
9868       if(pSiS->DualHeadMode) {
9869          if(!pSiS->SecondHead) {
9870	     pSiS->ForceCursorOff = TRUE;
9871	     pSiS->CursorInfoPtr->HideCursor(pScrn);
9872	     SISWaitVBRetrace(pScrn);
9873	     pSiS->ForceCursorOff = FALSE;
9874	  }
9875       } else {
9876#endif
9877          pSiS->CursorInfoPtr->HideCursor(pScrn);
9878          SISWaitVBRetrace(pScrn);
9879#ifdef SISDUALHEAD
9880       }
9881#endif
9882    }
9883
9884    SISBridgeRestore(pScrn);
9885
9886    if(pSiS->UseVESA) {
9887
9888       /* This is a q&d work-around for a BIOS bug. In case we disabled CRT2,
9889    	* VBESaveRestore() does not restore CRT1. So we set any mode now,
9890	* because VBESetVBEMode correctly restores CRT1. Afterwards, we
9891	* can call VBESaveRestore to restore original mode.
9892	*/
9893       if((pSiS->VBFlags2 & VB2_VIDEOBRIDGE) && (!(pSiS->VBFlags & DISPTYPE_DISP2)))
9894	  VBESetVBEMode(pSiS->pVbe, (pSiS->SISVESAModeList->n) | 0xc000, NULL);
9895
9896       SISVESARestore(pScrn);
9897
9898    } else {
9899
9900       SISRestore(pScrn);
9901
9902    }
9903
9904    /* We use (otherwise unused) bit 7 to indicate that we are running
9905     * to keep sisfb to change the displaymode (this would result in
9906     * lethal display corruption upon quitting X or changing to a VT
9907     * until a reboot)
9908     */
9909    if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
9910       orSISIDXREG(SISCR,0x34,0x80);
9911    }
9912
9913    SISVGALock(pSiS);
9914
9915    SiS_SiSFB_Lock(pScrn, FALSE);
9916}
9917
9918
9919/*
9920 * This is called at the end of each server generation.  It restores the
9921 * original (text) mode.  It should really also unmap the video memory too.
9922 * Mandatory!
9923 */
9924static Bool
9925SISCloseScreen(CLOSE_SCREEN_ARGS_DECL)
9926{
9927    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
9928    SISPtr pSiS = SISPTR(pScrn);
9929#ifdef SISDUALHEAD
9930    SISEntPtr pSiSEnt = pSiS->entityPrivate;
9931#endif
9932
9933    if(pSiS->SiSCtrlExtEntry) {
9934       SiSCtrlExtUnregister(pSiS, pScrn->scrnIndex);
9935    }
9936
9937#ifdef SISDRI
9938    if(pSiS->directRenderingEnabled) {
9939       SISDRICloseScreen(pScreen);
9940       pSiS->directRenderingEnabled = FALSE;
9941    }
9942#endif
9943
9944    if(pScrn->vtSema) {
9945
9946        if(pSiS->CursorInfoPtr) {
9947#ifdef SISDUALHEAD
9948           if(pSiS->DualHeadMode) {
9949              if(!pSiS->SecondHead) {
9950	         pSiS->ForceCursorOff = TRUE;
9951	         pSiS->CursorInfoPtr->HideCursor(pScrn);
9952	         SISWaitVBRetrace(pScrn);
9953	         pSiS->ForceCursorOff = FALSE;
9954	      }
9955           } else {
9956#endif
9957             pSiS->CursorInfoPtr->HideCursor(pScrn);
9958             SISWaitVBRetrace(pScrn);
9959#ifdef SISDUALHEAD
9960           }
9961#endif
9962	}
9963
9964        SISBridgeRestore(pScrn);
9965
9966	if(pSiS->UseVESA) {
9967
9968	  /* This is a q&d work-around for a BIOS bug. In case we disabled CRT2,
9969    	   * VBESaveRestore() does not restore CRT1. So we set any mode now,
9970	   * because VBESetVBEMode correctly restores CRT1. Afterwards, we
9971	   * can call VBESaveRestore to restore original mode.
9972	   */
9973           if((pSiS->VBFlags2 & VB2_VIDEOBRIDGE) && (!(pSiS->VBFlags & DISPTYPE_DISP2)))
9974	      VBESetVBEMode(pSiS->pVbe, (pSiS->SISVESAModeList->n) | 0xc000, NULL);
9975
9976	   SISVESARestore(pScrn);
9977
9978	} else {
9979
9980	   SISRestore(pScrn);
9981
9982	}
9983
9984        SISVGALock(pSiS);
9985
9986    }
9987
9988    SiS_SiSFB_Lock(pScrn, FALSE);
9989
9990    /* We should restore the mode number in case vtsema = false as well,
9991     * but since we haven't register access then we can't do it. I think
9992     * I need to rework the save/restore stuff, like saving the video
9993     * status when returning to the X server and by that save me the
9994     * trouble if sisfb was started from a textmode VT while X was on.
9995     */
9996
9997    SISUnmapMem(pScrn);
9998#ifdef SIS_PC_PLATFORM
9999    SiSVGAUnmapMem(pScrn);
10000#endif
10001
10002#ifdef SISDUALHEAD
10003    if(pSiS->DualHeadMode) {
10004       pSiSEnt = pSiS->entityPrivate;
10005       pSiSEnt->refCount--;
10006    }
10007#endif
10008
10009    if(pSiS->pInt) {
10010       xf86FreeInt10(pSiS->pInt);
10011       pSiS->pInt = NULL;
10012    }
10013
10014#ifdef SIS_USE_XAA
10015    if(!pSiS->useEXA) {
10016       if(pSiS->AccelLinearScratch) {
10017          xf86FreeOffscreenLinear(pSiS->AccelLinearScratch);
10018          pSiS->AccelLinearScratch = NULL;
10019       }
10020       if(pSiS->AccelInfoPtr) {
10021          XAADestroyInfoRec(pSiS->AccelInfoPtr);
10022          pSiS->AccelInfoPtr = NULL;
10023       }
10024    }
10025#endif
10026
10027#ifdef SIS_USE_EXA
10028    if(pSiS->useEXA) {
10029       if(pSiS->EXADriverPtr) {
10030          exaDriverFini(pScreen);
10031          free(pSiS->EXADriverPtr);
10032          pSiS->EXADriverPtr = NULL;
10033          pSiS->exa_scratch = NULL;
10034       }
10035    }
10036#endif
10037
10038    if(pSiS->CursorInfoPtr) {
10039       xf86DestroyCursorInfoRec(pSiS->CursorInfoPtr);
10040       pSiS->CursorInfoPtr = NULL;
10041    }
10042
10043    if(pSiS->ShadowPtr) {
10044       free(pSiS->ShadowPtr);
10045       pSiS->ShadowPtr = NULL;
10046    }
10047
10048    if(pSiS->DGAModes) {
10049       free(pSiS->DGAModes);
10050       pSiS->DGAModes = NULL;
10051    }
10052
10053    if(pSiS->adaptor) {
10054       free(pSiS->adaptor);
10055       pSiS->adaptor = NULL;
10056       pSiS->ResetXv = pSiS->ResetXvGamma = pSiS->ResetXvDisplay = NULL;
10057    }
10058
10059    if(pSiS->blitadaptor) {
10060       free(pSiS->blitadaptor);
10061       pSiS->blitadaptor = NULL;
10062    }
10063
10064    if(pSiS->crt2gcolortable) {
10065       free(pSiS->crt2gcolortable);
10066       pSiS->crt2gcolortable = NULL;
10067    }
10068
10069    if(pSiS->crt2cindices) {
10070       free(pSiS->crt2cindices);
10071       pSiS->crt2cindices = NULL;
10072    }
10073
10074    pScrn->vtSema = FALSE;
10075
10076    /* Restore Blockhandler */
10077    pScreen->BlockHandler = pSiS->BlockHandler;
10078
10079    pScreen->CloseScreen = pSiS->CloseScreen;
10080
10081    return(*pScreen->CloseScreen)(CLOSE_SCREEN_ARGS);
10082}
10083
10084
10085/* Free up any per-generation data structures */
10086
10087/* Optional */
10088static void
10089SISFreeScreen(FREE_SCREEN_ARGS_DECL)
10090{
10091    SCRN_INFO_PTR(arg);
10092#ifdef SIS_NEED_MAP_IOP
10093    SISPtr pSiS = SISPTR(pScrn);
10094
10095    if(pSiS) {
10096#ifdef SISDUALHEAD
10097       SISEntPtr pSiSEnt = pSiS->entityPrivate;
10098       if(pSiSEnt) {
10099          pSiSEnt->forceUnmapIOPBase = TRUE;
10100       }
10101#endif
10102       SISUnmapIOPMem(pScrn);
10103    }
10104#endif
10105
10106    SISFreeRec(pScrn);
10107}
10108
10109
10110/* Checks if a mode is suitable for the selected chipset. */
10111
10112static ModeStatus
10113SISValidMode(SCRN_ARG_TYPE arg, DisplayModePtr mode, Bool verbose, int flags)
10114{
10115    SCRN_INFO_PTR(arg);
10116    SISPtr pSiS = SISPTR(pScrn);
10117
10118    if(pSiS->UseVESA) {
10119       if(SiSCalcVESAModeIndex(pScrn, mode))
10120	  return(MODE_OK);
10121       else
10122	  return(MODE_BAD);
10123    }
10124
10125    if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
10126#ifdef SISDUALHEAD
10127       if(pSiS->DualHeadMode) {
10128          if(pSiS->SecondHead) {
10129	     if(SiS_CheckModeCRT1(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
10130	        return(MODE_BAD);
10131	  } else {
10132	     if(SiS_CheckModeCRT2(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
10133	        return(MODE_BAD);
10134	  }
10135       } else
10136#endif
10137#ifdef SISMERGED
10138       if(pSiS->MergedFB) {
10139	  if(!mode->Private) {
10140	     if(!pSiS->CheckForCRT2) {
10141	        if(SiS_CheckModeCRT1(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
10142	           return(MODE_BAD);
10143	     } else {
10144	        if(SiS_CheckModeCRT2(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes2) < 0x14)
10145	           return(MODE_BAD);
10146	     }
10147	  } else {
10148	     if(SiS_CheckModeCRT1(pScrn, ((SiSMergedDisplayModePtr)mode->Private)->CRT1,
10149		                  pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
10150	        return(MODE_BAD);
10151
10152	     if(SiS_CheckModeCRT2(pScrn, ((SiSMergedDisplayModePtr)mode->Private)->CRT2,
10153		                  pSiS->VBFlags, pSiS->HaveCustomModes2) < 0x14)
10154	        return(MODE_BAD);
10155 	  }
10156       } else
10157#endif
10158       {
10159	  if(SiS_CheckModeCRT1(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
10160	     return(MODE_BAD);
10161
10162	  if(SiS_CheckModeCRT2(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
10163	     return(MODE_BAD);
10164       }
10165    }
10166
10167    return(MODE_OK);
10168}
10169
10170#ifdef DEBUG
10171static void
10172SiSDumpModeInfo(ScrnInfoPtr pScrn, DisplayModePtr mode)
10173{
10174    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Clock : %x\n", mode->Clock);
10175    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Display : %x\n", mode->CrtcHDisplay);
10176    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Blank Start : %x\n", mode->CrtcHBlankStart);
10177    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Sync Start : %x\n", mode->CrtcHSyncStart);
10178    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Sync End : %x\n", mode->CrtcHSyncEnd);
10179    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Blank End : %x\n", mode->CrtcHBlankEnd);
10180    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Total : %x\n", mode->CrtcHTotal);
10181    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Skew : %x\n", mode->CrtcHSkew);
10182    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz HAdjusted : %x\n", mode->CrtcHAdjusted);
10183    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Display : %x\n", mode->CrtcVDisplay);
10184    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Blank Start : %x\n", mode->CrtcVBlankStart);
10185    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Sync Start : %x\n", mode->CrtcVSyncStart);
10186    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Sync End : %x\n", mode->CrtcVSyncEnd);
10187    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Blank End : %x\n", mode->CrtcVBlankEnd);
10188    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Total : %x\n", mode->CrtcVTotal);
10189    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt VAdjusted : %x\n", mode->CrtcVAdjusted);
10190}
10191#endif
10192
10193static void
10194SISModifyModeInfo(DisplayModePtr mode)
10195{
10196    if(mode->CrtcHBlankStart == mode->CrtcHDisplay)
10197        mode->CrtcHBlankStart++;
10198    if(mode->CrtcHBlankEnd == mode->CrtcHTotal)
10199        mode->CrtcHBlankEnd--;
10200    if(mode->CrtcVBlankStart == mode->CrtcVDisplay)
10201        mode->CrtcVBlankStart++;
10202    if(mode->CrtcVBlankEnd == mode->CrtcVTotal)
10203        mode->CrtcVBlankEnd--;
10204}
10205
10206/* Enable the Turboqueue/Commandqueue (For 300 and 315/330/340 series only) */
10207static void
10208SiSEnableTurboQueue(ScrnInfoPtr pScrn)
10209{
10210    SISPtr pSiS = SISPTR(pScrn);
10211    UShort SR26, SR27;
10212    ULong  temp;
10213
10214    switch(pSiS->VGAEngine) {
10215	case SIS_300_VGA:
10216	   if((!pSiS->NoAccel) && (pSiS->TurboQueue)) {
10217		/* TQ size is always 512k */
10218		temp = (pScrn->videoRam/64) - 8;
10219		SR26 = temp & 0xFF;
10220		inSISIDXREG(SISSR, 0x27, SR27);
10221		SR27 &= 0xFC;
10222		SR27 |= (0xF0 | ((temp >> 8) & 3));
10223		outSISIDXREG(SISSR, 0x26, SR26);
10224		outSISIDXREG(SISSR, 0x27, SR27);
10225	   }
10226	   break;
10227
10228	case SIS_315_VGA:
10229	   if(!pSiS->NoAccel) {
10230	      /* On 315/330/340 series, there are three queue modes available
10231	       * which are chosen by setting bits 7:5 in SR26:
10232	       * 1. MMIO queue mode (bit 5, 0x20). The hardware will keep
10233	       *    track of the queue, the FIFO, command parsing and so
10234	       *    on. This is the one comparable to the 300 series.
10235	       * 2. VRAM queue mode (bit 6, 0x40). In this case, one will
10236	       *    have to do queue management himself.
10237	       * 3. AGP queue mode (bit 7, 0x80). Works as 2., but keeps the
10238	       *    queue in AGP memory space.
10239	       * We go VRAM or MMIO here.
10240	       * SR26 bit 4 is called "Bypass H/W queue".
10241	       * SR26 bit 1 is called "Enable Command Queue Auto Correction"
10242	       * SR26 bit 0 resets the queue
10243	       * Size of queue memory is encoded in bits 3:2 like this:
10244	       *    00  (0x00)  512K
10245	       *    01  (0x04)  1M
10246	       *    10  (0x08)  2M
10247	       *    11  (0x0C)  4M
10248	       * The queue location is to be written to 0x85C0.
10249	       */
10250#ifdef SISVRAMQ
10251	      /* We use VRAM Cmd Queue, not MMIO or AGP */
10252	      UChar tempCR55 = 0;
10253
10254	      /* Set Command Queue Threshold to max value 11111b (?) */
10255	      outSISIDXREG(SISSR, 0x27, 0x1F);
10256
10257	      /* Disable queue flipping */
10258	      inSISIDXREG(SISCR, 0x55, tempCR55);
10259	      andSISIDXREG(SISCR, 0x55, 0x33);
10260	      /* Synchronous reset for Command Queue */
10261	      outSISIDXREG(SISSR, 0x26, 0x01);
10262	      SIS_MMIO_OUT32(pSiS->IOBase, 0x85c4, 0);
10263	      /* Enable VRAM Command Queue mode */
10264	      if(pSiS->ChipType == XGI_20) {
10265		 /* On XGI_20, always 128K */
10266		 SR26 = 0x40 | 0x04 | 0x01;
10267	      } else {
10268	         switch(pSiS->cmdQueueSize) {
10269		    case 1*1024*1024: SR26 = (0x40 | 0x04 | 0x01); break;
10270		    case 2*1024*1024: SR26 = (0x40 | 0x08 | 0x01); break;
10271		    case 4*1024*1024: SR26 = (0x40 | 0x0C | 0x01); break;
10272		    default:
10273		                      pSiS->cmdQueueSize = 512 * 1024;
10274		    case    512*1024: SR26 = (0x40 | 0x00 | 0x01);
10275	         }
10276	      }
10277	      outSISIDXREG(SISSR, 0x26, SR26);
10278	      SR26 &= 0xfe;
10279	      outSISIDXREG(SISSR, 0x26, SR26);
10280	      *(pSiS->cmdQ_SharedWritePort) = (unsigned int)(SIS_MMIO_IN32(pSiS->IOBase, 0x85c8));
10281	      SIS_MMIO_OUT32(pSiS->IOBase, 0x85c4, (CARD32)(*(pSiS->cmdQ_SharedWritePort)));
10282	      SIS_MMIO_OUT32(pSiS->IOBase, 0x85C0, pSiS->cmdQueueOffset);
10283	      temp = (ULong)pSiS->RealFbBase;
10284#ifdef SISDUALHEAD
10285	      if(pSiS->DualHeadMode) {
10286	         SISEntPtr pSiSEnt = pSiS->entityPrivate;
10287	         temp = (ULong)pSiSEnt->RealFbBase;
10288	      }
10289#endif
10290	      temp += pSiS->cmdQueueOffset;
10291	      pSiS->cmdQueueBase = (unsigned int *)temp;
10292	      outSISIDXREG(SISCR, 0x55, tempCR55);
10293#ifdef TWDEBUG
10294	      xf86DrvMsg(0, 0, "CmdQueueOffs 0x%x, CmdQueueAdd %p, shwrp 0x%x, status %x, base %p\n",
10295		pSiS->cmdQueueOffset, pSiS->cmdQueueBase, *(pSiS->cmdQ_SharedWritePort),
10296		SIS_MMIO_IN32(pSiS->IOBase, 0x85cc), (ULong *)temp);
10297#endif
10298#else
10299	      /* For MMIO */
10300	      /* Syncronous reset for Command Queue */
10301	      orSISIDXREG(SISSR, 0x26, 0x01);
10302	      /* Set Command Queue Threshold to max value 11111b */
10303	      outSISIDXREG(SISSR, 0x27, 0x1F);
10304	      /* Do some magic (cp readport to writeport) */
10305	      temp = SIS_MMIO_IN32(pSiS->IOBase, 0x85C8);
10306	      SIS_MMIO_OUT32(pSiS->IOBase, 0x85C4, temp);
10307	      /* Enable MMIO Command Queue mode (0x20),
10308	       * Enable_command_queue_auto_correction (0x02)
10309	       *        (no idea, but sounds good, so use it)
10310	       * 512k (0x00) (does this apply to MMIO mode?) */
10311	      outSISIDXREG(SISSR, 0x26, 0x22);
10312	      /* Calc Command Queue position (Q is always 512k)*/
10313	      temp = (pScrn->videoRam - 512) * 1024;
10314	      /* Set Q position */
10315	      SIS_MMIO_OUT32(pSiS->IOBase, 0x85C0, temp);
10316#endif
10317	   }
10318	   break;
10319	default:
10320	   break;
10321    }
10322}
10323
10324#ifdef SISVRAMQ
10325static void
10326SiSRestoreQueueMode(SISPtr pSiS, SISRegPtr sisReg)
10327{
10328    UChar tempCR55=0;
10329
10330    if(pSiS->VGAEngine == SIS_315_VGA) {
10331       inSISIDXREG(SISCR,0x55,tempCR55);
10332       andSISIDXREG(SISCR,0x55,0x33);
10333       outSISIDXREG(SISSR,0x26,0x01);
10334       SIS_MMIO_OUT32(pSiS->IOBase, 0x85c4, 0);
10335       outSISIDXREG(SISSR,0x27,sisReg->sisRegs3C4[0x27]);
10336       outSISIDXREG(SISSR,0x26,sisReg->sisRegs3C4[0x26]);
10337       SIS_MMIO_OUT32(pSiS->IOBase, 0x85C0, sisReg->sisMMIO85C0);
10338       outSISIDXREG(SISCR,0x55,tempCR55);
10339    }
10340}
10341#endif
10342
10343/* Things to do before a ModeSwitch. We set up the
10344 * video bridge configuration and the TurboQueue.
10345 */
10346void SiSPreSetMode(ScrnInfoPtr pScrn, DisplayModePtr mode, int viewmode)
10347{
10348    SISPtr pSiS = SISPTR(pScrn);
10349    UChar  CR30, CR31, CR32, CR33;
10350    UChar  CR39 = 0, CR3B = 0;
10351    UChar  CR17, CR38 = 0;
10352    UChar  CR35 = 0, CR79 = 0;
10353    int    temp = 0, crt1rateindex = 0;
10354    ULong  vbflag = pSiS->VBFlags;
10355    Bool   hcm = pSiS->HaveCustomModes;
10356    DisplayModePtr mymode = mode;
10357
10358    pSiS->IsCustom = FALSE;
10359
10360    /* NEVER call this with viewmode = SIS_MODE_SIMU
10361     * if mode->type is not M_T_DEFAULT!
10362     */
10363
10364#ifdef SISMERGED
10365    if(pSiS->MergedFB) {
10366       switch(viewmode) {
10367       case SIS_MODE_CRT1:
10368	  mymode = ((SiSMergedDisplayModePtr)mode->Private)->CRT1;
10369	  break;
10370       case SIS_MODE_CRT2:
10371	  mymode = ((SiSMergedDisplayModePtr)mode->Private)->CRT2;
10372	  hcm = pSiS->HaveCustomModes2;
10373       }
10374    }
10375#endif
10376
10377    switch(viewmode) {
10378    case SIS_MODE_CRT1:
10379       if(SiS_CheckModeCRT1(pScrn, mymode, vbflag, hcm) == 0xfe) {
10380          pSiS->IsCustom = TRUE;
10381       }
10382       break;
10383    case SIS_MODE_CRT2:
10384       if(vbflag & CRT2_ENABLE) {
10385          if(SiS_CheckModeCRT2(pScrn, mymode, vbflag, hcm) == 0xfe) {
10386	     pSiS->IsCustom = TRUE;
10387          }
10388       } else {
10389          /* This can only happen in mirror mode */
10390          if(SiS_CheckModeCRT1(pScrn, mymode, vbflag, hcm) == 0xfe) {
10391             pSiS->IsCustom = TRUE;
10392          }
10393       }
10394    }
10395
10396#ifdef UNLOCK_ALWAYS
10397    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);    /* Unlock Registers */
10398#endif
10399
10400    inSISIDXREG(SISCR, 0x30, CR30);
10401    inSISIDXREG(SISCR, 0x31, CR31);
10402    CR32 = pSiS->newCR32;
10403    inSISIDXREG(SISCR, 0x33, CR33);
10404
10405    if(pSiS->NewCRLayout) {
10406
10407       inSISIDXREG(SISCR, 0x35, CR35);
10408       inSISIDXREG(SISCR, 0x38, CR38);
10409       inSISIDXREG(SISCR, 0x39, CR39);
10410
10411       xf86DrvMsgVerb(pScrn->scrnIndex, X_PROBED, SISVERBLEVEL,
10412	   "Before: CR30=0x%02x,CR31=0x%02x,CR32=0x%02x,CR33=0x%02x,CR35=0x%02x,CR38=0x%02x\n",
10413              CR30, CR31, CR32, CR33, CR35, CR38);
10414
10415       CR38 &= ~0x07;
10416
10417    } else {
10418
10419       if(pSiS->Chipset != PCI_CHIP_SIS300) {
10420          switch(pSiS->VGAEngine) {
10421             case SIS_300_VGA: temp = 0x35; break;
10422             case SIS_315_VGA: temp = 0x38; break;
10423          }
10424          if(temp) inSISIDXREG(SISCR, temp, CR38);
10425       }
10426       if(pSiS->VGAEngine == SIS_315_VGA) {
10427          inSISIDXREG(SISCR, 0x79, CR79);
10428          CR38 &= ~0x3b;   			/* Clear LCDA/DualEdge and YPbPr bits */
10429       }
10430       inSISIDXREG(SISCR, 0x3b, CR3B);
10431
10432       xf86DrvMsgVerb(pScrn->scrnIndex, X_PROBED, SISVERBLEVEL,
10433	   "Before: CR30=0x%02x, CR31=0x%02x, CR32=0x%02x, CR33=0x%02x, CR%02x=0x%02x\n",
10434              CR30, CR31, CR32, CR33, temp, CR38);
10435    }
10436
10437    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, SISVERBLEVEL, "VBFlags=0x%x\n", pSiS->VBFlags);
10438
10439    CR30 = 0x00;
10440    CR31 &= ~0x60;  /* Clear VB_Drivermode & VB_OutputDisable */
10441    CR31 |= 0x04;   /* Set VB_NotSimuMode (not for 30xB/1400x1050?) */
10442    CR35 = 0x00;
10443
10444    if(!pSiS->NewCRLayout) {
10445       if(!pSiS->AllowHotkey) {
10446          CR31 |= 0x80;   /* Disable hotkey-switch */
10447       }
10448       CR79 &= ~0x10;     /* Enable Backlight control on 315 series */
10449    }
10450
10451    SiS_SetEnableDstn(pSiS->SiS_Pr, FALSE);
10452    SiS_SetEnableFstn(pSiS->SiS_Pr, FALSE);
10453
10454    if((vbflag & CRT1_LCDA) && (viewmode == SIS_MODE_CRT1)) {
10455
10456       CR38 |= 0x02;
10457
10458    } else {
10459
10460       switch(vbflag & (CRT2_TV|CRT2_LCD|CRT2_VGA)) {
10461
10462       case CRT2_TV:
10463
10464          CR38 &= ~0xC0; 	/* Clear Pal M/N bits */
10465
10466          if((pSiS->VBFlags2 & VB2_CHRONTEL) && (vbflag & TV_CHSCART)) {		/* Chrontel */
10467	     CR30 |= 0x10;
10468	     CR38 |= 0x04;
10469	     CR38 &= ~0x08;
10470	     CR31 |= 0x01;
10471	  } else if((pSiS->VBFlags2 & VB2_CHRONTEL) && (vbflag & TV_CHYPBPR525I)) {	/* Chrontel */
10472	     CR38 |= 0x08;
10473	     CR38 &= ~0x04;
10474	     CR31 &= ~0x01;
10475          } else if(vbflag & TV_HIVISION) {	/* SiS bridge */
10476	     if(pSiS->NewCRLayout) {
10477	        CR38 |= 0x04;
10478	        CR35 |= 0x60;
10479	     } else {
10480	        CR30 |= 0x80;
10481		if(pSiS->VGAEngine == SIS_315_VGA) {
10482		   if(pSiS->VBFlags2 & VB2_SISYPBPRBRIDGE) {
10483		      CR38 |= (0x08 | 0x30);
10484		   }
10485		}
10486	     }
10487	     CR31 |= 0x01;
10488	     CR35 |= 0x01;
10489	  } else if(vbflag & TV_YPBPR) {					/* SiS bridge */
10490	     if(pSiS->NewCRLayout) {
10491		CR38 |= 0x04;
10492		CR31 &= ~0x01;
10493		CR35 &= ~0x01;
10494		if(vbflag & (TV_YPBPR525P | TV_YPBPR625P)) CR35 |= 0x20;
10495		else if(vbflag & TV_YPBPR750P)             CR35 |= 0x40;
10496		else if(vbflag & TV_YPBPR1080I)            CR35 |= 0x60;
10497
10498		if(vbflag & (TV_YPBPR625I | TV_YPBPR625P)) {
10499		   CR31 |= 0x01;
10500		   CR35 |= 0x01;
10501		}
10502
10503		CR39 &= ~0x03;
10504		if((vbflag & TV_YPBPRAR) == TV_YPBPR43LB)     CR39 |= 0x00;
10505		else if((vbflag & TV_YPBPRAR) == TV_YPBPR43)  CR39 |= 0x01;
10506		else if((vbflag & TV_YPBPRAR) == TV_YPBPR169) CR39 |= 0x02;
10507		else					      CR39 |= 0x03;
10508	     } else if(pSiS->SiS_SD_Flags & SiS_SD_SUPPORTYPBPR) {
10509		CR30 |= 0x80;
10510		CR38 |= 0x08;
10511		CR31 &= ~0x01;
10512		if(vbflag & (TV_YPBPR525P|TV_YPBPR625P)) CR38 |= 0x10;
10513		else if(vbflag & TV_YPBPR750P)  	 CR38 |= 0x20;
10514		else if(vbflag & TV_YPBPR1080I)		 CR38 |= 0x30;
10515
10516		if(vbflag & (TV_YPBPR625I | TV_YPBPR625P)) CR31 |= 0x01;
10517
10518		if(pSiS->SiS_SD_Flags & SiS_SD_SUPPORTYPBPRAR) {
10519		   CR3B &= ~0x03;
10520		   if((vbflag & TV_YPBPRAR) == TV_YPBPR43LB)     CR3B |= 0x00;
10521		   else if((vbflag & TV_YPBPRAR) == TV_YPBPR43)  CR3B |= 0x03;
10522		   else if((vbflag & TV_YPBPRAR) == TV_YPBPR169) CR3B |= 0x01;
10523		   else					         CR3B |= 0x03;
10524		}
10525	     }
10526          } else {								/* All */
10527	     if(vbflag & TV_SCART)  CR30 |= 0x10;
10528	     if(vbflag & TV_SVIDEO) CR30 |= 0x08;
10529	     if(vbflag & TV_AVIDEO) CR30 |= 0x04;
10530	     if(!(CR30 & 0x1C))	    CR30 |= 0x08;    /* default: SVIDEO */
10531
10532	     if(vbflag & TV_PAL) {
10533		CR31 |= 0x01;
10534		CR35 |= 0x01;
10535		if( (pSiS->VBFlags2 & VB2_SISBRIDGE) ||
10536		    ((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->ChrontelType == CHRONTEL_701x)) )  {
10537		   if(vbflag & TV_PALM) {
10538		      CR38 |= 0x40;
10539		      CR35 |= 0x04;
10540		   } else if(vbflag & TV_PALN) {
10541		      CR38 |= 0x80;
10542		      CR35 |= 0x08;
10543		   }
10544	        }
10545	     } else {
10546		CR31 &= ~0x01;
10547		CR35 &= ~0x01;
10548		if(vbflag & TV_NTSCJ) {
10549		   CR38 |= 0x40;  /* TW, not BIOS */
10550		   CR35 |= 0x02;
10551		}
10552	     }
10553	     if(vbflag & TV_SCART) {
10554		CR31 |= 0x01;
10555		CR35 |= 0x01;
10556	     }
10557	  }
10558
10559	  CR31 &= ~0x04;   /* Clear NotSimuMode */
10560	  pSiS->SiS_Pr->SiS_CHOverScan = pSiS->UseCHOverScan;
10561	  if((pSiS->OptTVSOver == 1) && (pSiS->ChrontelType == CHRONTEL_700x)) {
10562	     pSiS->SiS_Pr->SiS_CHSOverScan = TRUE;
10563	  } else {
10564	     pSiS->SiS_Pr->SiS_CHSOverScan = FALSE;
10565	  }
10566#ifdef SIS_CP
10567	  SIS_CP_DRIVER_CONFIG
10568#endif
10569	  break;
10570
10571       case CRT2_LCD:
10572	  CR30 |= 0x20;
10573	  SiS_SetEnableDstn(pSiS->SiS_Pr, pSiS->DSTN);
10574	  SiS_SetEnableFstn(pSiS->SiS_Pr, pSiS->FSTN);
10575	  break;
10576
10577       case CRT2_VGA:
10578	  CR30 |= 0x40;
10579	  break;
10580
10581       default:
10582	  CR30 |= 0x00;
10583	  CR31 |= 0x20;    /* VB_OUTPUT_DISABLE */
10584	  if(pSiS->UseVESA) {
10585	     crt1rateindex = SISSearchCRT1Rate(pScrn, mymode);
10586	  }
10587       }
10588
10589    }
10590
10591    if(vbflag & CRT1_LCDA) {
10592       switch(viewmode) {
10593       case SIS_MODE_CRT1:
10594	  CR38 |= 0x01;
10595	  break;
10596       case SIS_MODE_CRT2:
10597	  if(vbflag & (CRT2_TV|CRT2_VGA)) {
10598	     CR30 |= 0x02;
10599	     CR38 |= 0x01;
10600	  } else {
10601	     CR38 |= 0x03;
10602	  }
10603	  break;
10604       case SIS_MODE_SIMU:
10605       default:
10606	  if(vbflag & (CRT2_TV|CRT2_LCD|CRT2_VGA)) {
10607	     CR30 |= 0x01;
10608	  }
10609	  break;
10610       }
10611    } else {
10612       if(vbflag & (CRT2_TV|CRT2_LCD|CRT2_VGA)) {
10613          CR30 |= 0x01;
10614       }
10615    }
10616
10617    if(pSiS->UseVESA) {
10618       CR31 &= ~0x40;   /* Clear Drivermode */
10619       CR31 |= 0x06;    /* Set SlaveMode, Enable SimuMode in Slavemode */
10620#ifdef TWDEBUG
10621       CR31 |= 0x40;    /* DEBUG (for non-slave mode VESA) */
10622       crt1rateindex = SISSearchCRT1Rate(pScrn, mymode);
10623#endif
10624    } else {
10625       CR31 |=  0x40;  /* Set Drivermode */
10626       CR31 &=  ~0x06; /* Disable SlaveMode, disable SimuMode in SlaveMode */
10627       if(!pSiS->IsCustom) {
10628          crt1rateindex = SISSearchCRT1Rate(pScrn, mymode);
10629       }
10630    }
10631
10632    switch(viewmode) {
10633	case SIS_MODE_SIMU:
10634	   CR33 = 0;
10635	   if(!(vbflag & CRT1_LCDA)) {
10636	      CR33 |= (crt1rateindex & 0x0f);
10637	   }
10638	   if(vbflag & CRT2_VGA) {
10639	      CR33 |= ((crt1rateindex & 0x0f) << 4);
10640	   }
10641	   break;
10642	case SIS_MODE_CRT1:
10643	   CR33 &= 0xf0;
10644	   if(!(vbflag & CRT1_LCDA)) {
10645	      CR33 |= (crt1rateindex & 0x0f);
10646	   }
10647	   break;
10648	case SIS_MODE_CRT2:
10649	   CR33 &= 0x0f;
10650	   if(vbflag & CRT2_VGA) {
10651	      CR33 |= ((crt1rateindex & 0x0f) << 4);
10652	   }
10653	   break;
10654     }
10655
10656     if((!pSiS->UseVESA) && (vbflag & CRT2_ENABLE)) {
10657	if(pSiS->CRT1off) CR33 &= 0xf0;
10658     }
10659
10660     if(pSiS->NewCRLayout) {
10661
10662	CR31 &= 0xfe;   /* Clear PAL flag (now in CR35) */
10663	CR38 &= 0x07;   /* Use only LCDA and HiVision/YPbPr bits */
10664	outSISIDXREG(SISCR, 0x30, CR30);
10665	outSISIDXREG(SISCR, 0x31, CR31);
10666	outSISIDXREG(SISCR, 0x33, CR33);
10667	outSISIDXREG(SISCR, 0x35, CR35);
10668	setSISIDXREG(SISCR, 0x38, 0xf8, CR38);
10669	outSISIDXREG(SISCR, 0x39, CR39);
10670
10671	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, SISVERBLEVEL,
10672		"After:  CR30=0x%02x,CR31=0x%02x,CR33=0x%02x,CR35=0x%02x,CR38=%02x\n",
10673		    CR30, CR31, CR33, CR35, CR38);
10674
10675     } else {
10676
10677	outSISIDXREG(SISCR, 0x30, CR30);
10678	outSISIDXREG(SISCR, 0x31, CR31);
10679	outSISIDXREG(SISCR, 0x33, CR33);
10680	if(temp) {
10681	   outSISIDXREG(SISCR, temp, CR38);
10682	}
10683	if(pSiS->VGAEngine == SIS_315_VGA) {
10684	   outSISIDXREG(SISCR, 0x3b, CR3B);
10685	   outSISIDXREG(SISCR, 0x79, CR79);
10686	}
10687
10688	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, SISVERBLEVEL,
10689		"After:  CR30=0x%02x,CR31=0x%02x,CR33=0x%02x,CR%02x=%02x\n",
10690		    CR30, CR31, CR33, temp, CR38);
10691     }
10692
10693     pSiS->SiS_Pr->SiS_UseOEM = pSiS->OptUseOEM;
10694
10695     /* Enable TurboQueue */
10696#ifdef SISVRAMQ
10697     if(pSiS->VGAEngine != SIS_315_VGA)
10698#endif
10699	SiSEnableTurboQueue(pScrn);
10700
10701     if((!pSiS->UseVESA) && (pSiS->VBFlags & CRT2_ENABLE)) {
10702	/* Switch on CRT1 for modes that require the bridge in SlaveMode */
10703	andSISIDXREG(SISSR,0x1f,0x3f);
10704	inSISIDXREG(SISCR, 0x17, CR17);
10705	if(!(CR17 & 0x80)) {
10706	   orSISIDXREG(SISCR, 0x17, 0x80);
10707	   outSISIDXREG(SISSR, 0x00, 0x01);
10708	   usleep(10000);
10709	   outSISIDXREG(SISSR, 0x00, 0x03);
10710	}
10711     }
10712}
10713
10714/* Functions for adjusting various TV settings */
10715
10716/* These are used by the PostSetMode() functions as well as
10717 * the display properties tool SiSCtrl.
10718 *
10719 * There is each a Set and a Get routine. The Set functions
10720 * take a value of the same range as the corresponding option.
10721 * The Get routines return a value of the same range (although
10722 * not necessarily the same value as previously set because
10723 * of the lower resolution of the respective setting compared
10724 * to the valid range).
10725 * The Get routines return -2 on error (eg. hardware does not
10726 * support this setting).
10727 * Note: The x and y positioning routines accept a position
10728 * RELATIVE to the default position. All other routines
10729 * take ABSOLUTE values.
10730 *
10731 * The Set functions will store the property regardless if TV is
10732 * currently used or not and if the hardware supports the property
10733 * or not. The Get routines will return this stored
10734 * value if TV is not currently used (because the register does
10735 * not contain the correct value then) or if the hardware supports
10736 * the respective property. This should make it easier for the
10737 * display property tool because it does not have to know the
10738 * hardware features.
10739 *
10740 * All the routines are dual head aware. It does not matter
10741 * if the function is called from the CRT1 or CRT2 session.
10742 * The values will be in pSiSEnt anyway, and read from there
10743 * if we're running dual head.
10744 */
10745
10746void SiS_SetCHTVlumabandwidthcvbs(ScrnInfoPtr pScrn, int val)
10747{
10748   SISPtr pSiS = SISPTR(pScrn);
10749#ifdef SISDUALHEAD
10750   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10751#endif
10752
10753   pSiS->chtvlumabandwidthcvbs = val;
10754#ifdef SISDUALHEAD
10755   if(pSiSEnt) pSiSEnt->chtvlumabandwidthcvbs = val;
10756#endif
10757
10758   if(!(pSiS->VBFlags & CRT2_TV)) return;
10759   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
10760
10761#ifdef UNLOCK_ALWAYS
10762   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10763#endif
10764
10765   switch(pSiS->ChrontelType) {
10766       case CHRONTEL_700x:
10767           val /= 8;
10768           if((val == 0) || (val == 1)) {
10769	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, val, 0xFE);
10770           }
10771	   break;
10772       case CHRONTEL_701x:
10773           val /= 4;
10774	   if((val >= 0) && (val <= 3)) {
10775	       SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x02, val, 0xFC);
10776	   }
10777           break;
10778   }
10779}
10780
10781int SiS_GetCHTVlumabandwidthcvbs(ScrnInfoPtr pScrn)
10782{
10783   SISPtr pSiS = SISPTR(pScrn);
10784#ifdef SISDUALHEAD
10785   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10786#endif
10787
10788   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
10789#ifdef SISDUALHEAD
10790      if(pSiSEnt && pSiS->DualHeadMode)
10791           return (int)pSiSEnt->chtvlumabandwidthcvbs;
10792      else
10793#endif
10794           return (int)pSiS->chtvlumabandwidthcvbs;
10795   } else {
10796#ifdef UNLOCK_ALWAYS
10797      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10798#endif
10799      switch(pSiS->ChrontelType) {
10800      case CHRONTEL_700x:
10801           return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x03) & 0x01) * 8);
10802      case CHRONTEL_701x:
10803	   return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x02) & 0x03) * 4);
10804      default:
10805           return (int)pSiS->chtvlumabandwidthcvbs;
10806      }
10807   }
10808}
10809
10810void SiS_SetCHTVlumabandwidthsvideo(ScrnInfoPtr pScrn, int val)
10811{
10812   SISPtr pSiS = SISPTR(pScrn);
10813#ifdef SISDUALHEAD
10814   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10815#endif
10816
10817   pSiS->chtvlumabandwidthsvideo = val;
10818#ifdef SISDUALHEAD
10819   if(pSiSEnt) pSiSEnt->chtvlumabandwidthsvideo = val;
10820#endif
10821
10822   if(!(pSiS->VBFlags & CRT2_TV)) return;
10823   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
10824
10825#ifdef UNLOCK_ALWAYS
10826   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10827#endif
10828
10829   switch(pSiS->ChrontelType) {
10830       case CHRONTEL_700x:
10831           val /= 6;
10832           if((val >= 0) && (val <= 2)) {
10833	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, (val << 1), 0xF9);
10834           }
10835	   break;
10836       case CHRONTEL_701x:
10837           val /= 4;
10838	   if((val >= 0) && (val <= 3)) {
10839	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x02, (val << 2), 0xF3);
10840	   }
10841           break;
10842   }
10843}
10844
10845int SiS_GetCHTVlumabandwidthsvideo(ScrnInfoPtr pScrn)
10846{
10847   SISPtr pSiS = SISPTR(pScrn);
10848#ifdef SISDUALHEAD
10849   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10850#endif
10851
10852   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
10853#ifdef SISDUALHEAD
10854      if(pSiSEnt && pSiS->DualHeadMode)
10855           return (int)pSiSEnt->chtvlumabandwidthsvideo;
10856      else
10857#endif
10858           return (int)pSiS->chtvlumabandwidthsvideo;
10859   } else {
10860#ifdef UNLOCK_ALWAYS
10861      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10862#endif
10863      switch(pSiS->ChrontelType) {
10864      case CHRONTEL_700x:
10865           return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x03) & 0x06) >> 1) * 6);
10866      case CHRONTEL_701x:
10867	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x02) & 0x0c) >> 2) * 4);
10868      default:
10869           return (int)pSiS->chtvlumabandwidthsvideo;
10870      }
10871   }
10872}
10873
10874void SiS_SetCHTVlumaflickerfilter(ScrnInfoPtr pScrn, int val)
10875{
10876   SISPtr pSiS = SISPTR(pScrn);
10877#ifdef SISDUALHEAD
10878   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10879#endif
10880
10881   pSiS->chtvlumaflickerfilter = val;
10882#ifdef SISDUALHEAD
10883   if(pSiSEnt) pSiSEnt->chtvlumaflickerfilter = val;
10884#endif
10885
10886   if(!(pSiS->VBFlags & CRT2_TV)) return;
10887   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
10888
10889#ifdef UNLOCK_ALWAYS
10890   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10891#endif
10892
10893   switch(pSiS->ChrontelType) {
10894       case CHRONTEL_700x:
10895           val /= 6;
10896           if((val >= 0) && (val <= 2)) {
10897	      UShort reg = 0;
10898	      reg = SiS_GetCH70xx(pSiS->SiS_Pr, 0x01);
10899	      reg = (reg & 0xf0) | ((reg & 0x0c) >> 2) | (val << 2);
10900              SiS_SetCH70xx(pSiS->SiS_Pr, 0x01, reg);
10901           }
10902	   break;
10903       case CHRONTEL_701x:
10904           val /= 4;
10905	   if((val >= 0) && (val <= 3)) {
10906	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x01, (val << 2), 0xF3);
10907	   }
10908           break;
10909   }
10910}
10911
10912int SiS_GetCHTVlumaflickerfilter(ScrnInfoPtr pScrn)
10913{
10914   SISPtr pSiS = SISPTR(pScrn);
10915#ifdef SISDUALHEAD
10916   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10917#endif
10918
10919   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
10920#ifdef SISDUALHEAD
10921      if(pSiSEnt && pSiS->DualHeadMode)
10922          return (int)pSiSEnt->chtvlumaflickerfilter;
10923      else
10924#endif
10925          return (int)pSiS->chtvlumaflickerfilter;
10926   } else {
10927#ifdef UNLOCK_ALWAYS
10928      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10929#endif
10930      switch(pSiS->ChrontelType) {
10931      case CHRONTEL_700x:
10932           return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x01) & 0x03) * 6);
10933      case CHRONTEL_701x:
10934	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x01) & 0x0c) >> 2) * 4);
10935      default:
10936           return (int)pSiS->chtvlumaflickerfilter;
10937      }
10938   }
10939}
10940
10941void SiS_SetCHTVchromabandwidth(ScrnInfoPtr pScrn, int val)
10942{
10943   SISPtr pSiS = SISPTR(pScrn);
10944#ifdef SISDUALHEAD
10945   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10946#endif
10947
10948   pSiS->chtvchromabandwidth = val;
10949#ifdef SISDUALHEAD
10950   if(pSiSEnt) pSiSEnt->chtvchromabandwidth = val;
10951#endif
10952
10953   if(!(pSiS->VBFlags & CRT2_TV)) return;
10954   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
10955
10956#ifdef UNLOCK_ALWAYS
10957   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10958#endif
10959
10960   switch(pSiS->ChrontelType) {
10961       case CHRONTEL_700x:
10962           val /= 4;
10963           if((val >= 0) && (val <= 3)) {
10964              SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, (val << 4), 0xCF);
10965           }
10966	   break;
10967       case CHRONTEL_701x:
10968           val /= 8;
10969	   if((val >= 0) && (val <= 1)) {
10970	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x02, (val << 4), 0xEF);
10971	   }
10972           break;
10973   }
10974}
10975
10976int SiS_GetCHTVchromabandwidth(ScrnInfoPtr pScrn)
10977{
10978   SISPtr pSiS = SISPTR(pScrn);
10979#ifdef SISDUALHEAD
10980   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10981#endif
10982
10983   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
10984#ifdef SISDUALHEAD
10985      if(pSiSEnt && pSiS->DualHeadMode)
10986           return (int)pSiSEnt->chtvchromabandwidth;
10987      else
10988#endif
10989           return (int)pSiS->chtvchromabandwidth;
10990   } else {
10991#ifdef UNLOCK_ALWAYS
10992      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10993#endif
10994      switch(pSiS->ChrontelType) {
10995      case CHRONTEL_700x:
10996           return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x03) & 0x30) >> 4) * 4);
10997      case CHRONTEL_701x:
10998	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x02) & 0x10) >> 4) * 8);
10999      default:
11000           return (int)pSiS->chtvchromabandwidth;
11001      }
11002   }
11003}
11004
11005void SiS_SetCHTVchromaflickerfilter(ScrnInfoPtr pScrn, int val)
11006{
11007   SISPtr pSiS = SISPTR(pScrn);
11008#ifdef SISDUALHEAD
11009   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11010#endif
11011
11012   pSiS->chtvchromaflickerfilter = val;
11013#ifdef SISDUALHEAD
11014   if(pSiSEnt) pSiSEnt->chtvchromaflickerfilter = val;
11015#endif
11016
11017   if(!(pSiS->VBFlags & CRT2_TV)) return;
11018   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
11019
11020#ifdef UNLOCK_ALWAYS
11021   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11022#endif
11023
11024   switch(pSiS->ChrontelType) {
11025       case CHRONTEL_700x:
11026           val /= 6;
11027           if((val >= 0) && (val <= 2)) {
11028	      UShort reg = 0;
11029	      reg = SiS_GetCH70xx(pSiS->SiS_Pr, 0x01);
11030	      reg = (reg & 0xc0) | ((reg & 0x0c) >> 2) | ((reg & 0x03) << 2) | (val << 4);
11031              SiS_SetCH70xx(pSiS->SiS_Pr, 0x01, reg);
11032           }
11033	   break;
11034       case CHRONTEL_701x:
11035           val /= 4;
11036	   if((val >= 0) && (val <= 3)) {
11037	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x01, (val << 4), 0xCF);
11038	   }
11039           break;
11040   }
11041}
11042
11043int SiS_GetCHTVchromaflickerfilter(ScrnInfoPtr pScrn)
11044{
11045   SISPtr pSiS = SISPTR(pScrn);
11046#ifdef SISDUALHEAD
11047   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11048#endif
11049
11050   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
11051#ifdef SISDUALHEAD
11052      if(pSiSEnt && pSiS->DualHeadMode)
11053           return (int)pSiSEnt->chtvchromaflickerfilter;
11054      else
11055#endif
11056           return (int)pSiS->chtvchromaflickerfilter;
11057   } else {
11058#ifdef UNLOCK_ALWAYS
11059      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11060#endif
11061      switch(pSiS->ChrontelType) {
11062      case CHRONTEL_700x:
11063           return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x01) & 0x30) >> 4) * 6);
11064      case CHRONTEL_701x:
11065	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x01) & 0x30) >> 4) * 4);
11066      default:
11067           return (int)pSiS->chtvchromaflickerfilter;
11068      }
11069   }
11070}
11071
11072void SiS_SetCHTVcvbscolor(ScrnInfoPtr pScrn, int val)
11073{
11074   SISPtr pSiS = SISPTR(pScrn);
11075#ifdef SISDUALHEAD
11076   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11077#endif
11078
11079   pSiS->chtvcvbscolor = val ? 1 : 0;
11080#ifdef SISDUALHEAD
11081   if(pSiSEnt) pSiSEnt->chtvcvbscolor = pSiS->chtvcvbscolor;
11082#endif
11083
11084   if(!(pSiS->VBFlags & CRT2_TV)) return;
11085   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
11086
11087#ifdef UNLOCK_ALWAYS
11088   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11089#endif
11090
11091   switch(pSiS->ChrontelType) {
11092       case CHRONTEL_700x:
11093           if(!val)  SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, 0x40, 0x00);
11094           else      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, 0x00, ~0x40);
11095	   break;
11096       case CHRONTEL_701x:
11097           if(!val)  SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x02, 0x00, ~0x20);
11098	   else      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x02, 0x20, 0x00);
11099           break;
11100   }
11101}
11102
11103int SiS_GetCHTVcvbscolor(ScrnInfoPtr pScrn)
11104{
11105   SISPtr pSiS = SISPTR(pScrn);
11106#ifdef SISDUALHEAD
11107   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11108#endif
11109
11110   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
11111#ifdef SISDUALHEAD
11112      if(pSiSEnt && pSiS->DualHeadMode)
11113           return (int)pSiSEnt->chtvcvbscolor;
11114      else
11115#endif
11116           return (int)pSiS->chtvcvbscolor;
11117   } else {
11118#ifdef UNLOCK_ALWAYS
11119      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11120#endif
11121      switch(pSiS->ChrontelType) {
11122      case CHRONTEL_700x:
11123           return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x03) & 0x40) >> 6) ^ 0x01);
11124      case CHRONTEL_701x:
11125	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x02) & 0x20) >> 5) ^ 0x01);
11126      default:
11127           return (int)pSiS->chtvcvbscolor;
11128      }
11129   }
11130}
11131
11132void SiS_SetCHTVtextenhance(ScrnInfoPtr pScrn, int val)
11133{
11134   SISPtr pSiS = SISPTR(pScrn);
11135#ifdef SISDUALHEAD
11136   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11137#endif
11138
11139   pSiS->chtvtextenhance = val;
11140#ifdef SISDUALHEAD
11141   if(pSiSEnt) pSiSEnt->chtvtextenhance = val;
11142#endif
11143
11144   if(!(pSiS->VBFlags & CRT2_TV)) return;
11145   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
11146
11147#ifdef UNLOCK_ALWAYS
11148   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11149#endif
11150
11151   switch(pSiS->ChrontelType) {
11152       case CHRONTEL_700x:
11153           val /= 6;
11154           if((val >= 0) && (val <= 2)) {
11155	      UShort reg = 0;
11156	      reg = SiS_GetCH70xx(pSiS->SiS_Pr, 0x01);
11157	      reg = (reg & 0xf0) | ((reg & 0x03) << 2) | val;
11158              SiS_SetCH70xx(pSiS->SiS_Pr, 0x01, reg);
11159           }
11160	   break;
11161       case CHRONTEL_701x:
11162           val /= 2;
11163	   if((val >= 0) && (val <= 7)) {
11164	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, val, 0xF8);
11165	   }
11166           break;
11167   }
11168}
11169
11170int SiS_GetCHTVtextenhance(ScrnInfoPtr pScrn)
11171{
11172   SISPtr pSiS = SISPTR(pScrn);
11173#ifdef SISDUALHEAD
11174   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11175#endif
11176
11177   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
11178#ifdef SISDUALHEAD
11179      if(pSiSEnt && pSiS->DualHeadMode)
11180           return (int)pSiSEnt->chtvtextenhance;
11181      else
11182#endif
11183           return (int)pSiS->chtvtextenhance;
11184   } else {
11185#ifdef UNLOCK_ALWAYS
11186      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11187#endif
11188      switch(pSiS->ChrontelType) {
11189      case CHRONTEL_700x:
11190	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x01) & 0x0c) >> 2) * 6);
11191      case CHRONTEL_701x:
11192	   return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x03) & 0x07) * 2);
11193      default:
11194           return (int)pSiS->chtvtextenhance;
11195      }
11196   }
11197}
11198
11199void SiS_SetCHTVcontrast(ScrnInfoPtr pScrn, int val)
11200{
11201   SISPtr pSiS = SISPTR(pScrn);
11202#ifdef SISDUALHEAD
11203   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11204#endif
11205
11206   pSiS->chtvcontrast = val;
11207#ifdef SISDUALHEAD
11208   if(pSiSEnt) pSiSEnt->chtvcontrast = val;
11209#endif
11210
11211   if(!(pSiS->VBFlags & CRT2_TV)) return;
11212   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
11213
11214#ifdef UNLOCK_ALWAYS
11215   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11216#endif
11217
11218   val /= 2;
11219   if((val >= 0) && (val <= 7)) {
11220       switch(pSiS->ChrontelType) {
11221       case CHRONTEL_700x:
11222              SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x11, val, 0xF8);
11223	      break;
11224       case CHRONTEL_701x:
11225	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x08, val, 0xF8);
11226              break;
11227       }
11228       SiS_DDC2Delay(pSiS->SiS_Pr, 1000);
11229   }
11230}
11231
11232int SiS_GetCHTVcontrast(ScrnInfoPtr pScrn)
11233{
11234   SISPtr pSiS = SISPTR(pScrn);
11235#ifdef SISDUALHEAD
11236   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11237#endif
11238
11239   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
11240#ifdef SISDUALHEAD
11241      if(pSiSEnt && pSiS->DualHeadMode)
11242           return (int)pSiSEnt->chtvcontrast;
11243      else
11244#endif
11245           return (int)pSiS->chtvcontrast;
11246   } else {
11247#ifdef UNLOCK_ALWAYS
11248      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11249#endif
11250      switch(pSiS->ChrontelType) {
11251      case CHRONTEL_700x:
11252           return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x11) & 0x07) * 2);
11253      case CHRONTEL_701x:
11254	   return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x08) & 0x07) * 2);
11255      default:
11256           return (int)pSiS->chtvcontrast;
11257      }
11258   }
11259}
11260
11261void SiS_SetSISTVedgeenhance(ScrnInfoPtr pScrn, int val)
11262{
11263   SISPtr pSiS = SISPTR(pScrn);
11264#ifdef SISDUALHEAD
11265   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11266#endif
11267
11268   pSiS->sistvedgeenhance = val;
11269#ifdef SISDUALHEAD
11270   if(pSiSEnt) pSiSEnt->sistvedgeenhance = val;
11271#endif
11272
11273   if(!(pSiS->VBFlags2 & VB2_301))  return;
11274   if(!(pSiS->VBFlags & CRT2_TV))   return;
11275
11276#ifdef UNLOCK_ALWAYS
11277   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11278#endif
11279
11280   val /= 2;
11281   if((val >= 0) && (val <= 7)) {
11282      setSISIDXREG(SISPART2,0x3A, 0x1F, (val << 5));
11283   }
11284}
11285
11286int SiS_GetSISTVedgeenhance(ScrnInfoPtr pScrn)
11287{
11288   SISPtr pSiS = SISPTR(pScrn);
11289   int result = pSiS->sistvedgeenhance;
11290   UChar temp;
11291#ifdef SISDUALHEAD
11292   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11293
11294   if(pSiSEnt && pSiS->DualHeadMode) result = pSiSEnt->sistvedgeenhance;
11295#endif
11296
11297   if(!(pSiS->VBFlags2 & VB2_301))  return result;
11298   if(!(pSiS->VBFlags & CRT2_TV))   return result;
11299
11300#ifdef UNLOCK_ALWAYS
11301   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11302#endif
11303   inSISIDXREG(SISPART2, 0x3a, temp);
11304   return(int)(((temp & 0xe0) >> 5) * 2);
11305}
11306
11307void SiS_SetSISTVantiflicker(ScrnInfoPtr pScrn, int val)
11308{
11309   SISPtr pSiS = SISPTR(pScrn);
11310#ifdef SISDUALHEAD
11311   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11312#endif
11313
11314   pSiS->sistvantiflicker = val;
11315#ifdef SISDUALHEAD
11316   if(pSiSEnt) pSiSEnt->sistvantiflicker = val;
11317#endif
11318
11319   if(!(pSiS->VBFlags & CRT2_TV))      return;
11320   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE)) return;
11321   if(pSiS->VBFlags & TV_HIVISION)     return;
11322   if((pSiS->VBFlags & TV_YPBPR) &&
11323      (pSiS->VBFlags & (TV_YPBPR525P | TV_YPBPR625P | TV_YPBPR750P | TV_YPBPR1080I))) return;
11324
11325#ifdef UNLOCK_ALWAYS
11326   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11327#endif
11328
11329   /* Valid values: 0=off, 1=low, 2=med, 3=high, 4=adaptive */
11330   if((val >= 0) && (val <= 4)) {
11331      setSISIDXREG(SISPART2,0x0A,0x8F, (val << 4));
11332   }
11333}
11334
11335int SiS_GetSISTVantiflicker(ScrnInfoPtr pScrn)
11336{
11337   SISPtr pSiS = SISPTR(pScrn);
11338   int result = pSiS->sistvantiflicker;
11339   UChar temp;
11340#ifdef SISDUALHEAD
11341   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11342
11343   if(pSiSEnt && pSiS->DualHeadMode) result = pSiSEnt->sistvantiflicker;
11344#endif
11345
11346   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE)) return result;
11347   if(!(pSiS->VBFlags & CRT2_TV))        return result;
11348   if(pSiS->VBFlags & TV_HIVISION)       return result;
11349   if((pSiS->VBFlags & TV_YPBPR) &&
11350      (pSiS->VBFlags & (TV_YPBPR525P | TV_YPBPR625P | TV_YPBPR750P | TV_YPBPR1080I))) return result;
11351
11352#ifdef UNLOCK_ALWAYS
11353   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11354#endif
11355   inSISIDXREG(SISPART2, 0x0a, temp);
11356   return(int)((temp & 0x70) >> 4);
11357}
11358
11359void SiS_SetSISTVsaturation(ScrnInfoPtr pScrn, int val)
11360{
11361   SISPtr pSiS = SISPTR(pScrn);
11362#ifdef SISDUALHEAD
11363   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11364#endif
11365
11366   pSiS->sistvsaturation = val;
11367#ifdef SISDUALHEAD
11368   if(pSiSEnt) pSiSEnt->sistvsaturation = val;
11369#endif
11370
11371   if(!(pSiS->VBFlags & CRT2_TV)) return;
11372   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE)) return;
11373   if(pSiS->VBFlags2 & VB2_301) return;
11374
11375#ifdef UNLOCK_ALWAYS
11376   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11377#endif
11378
11379   val /= 2;
11380   if((val >= 0) && (val <= 7)) {
11381      setSISIDXREG(SISPART4,0x21,0xF8, val);
11382   }
11383}
11384
11385int SiS_GetSISTVsaturation(ScrnInfoPtr pScrn)
11386{
11387   SISPtr pSiS = SISPTR(pScrn);
11388   int result = pSiS->sistvsaturation;
11389   UChar temp;
11390#ifdef SISDUALHEAD
11391   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11392
11393   if(pSiSEnt && pSiS->DualHeadMode)  result = pSiSEnt->sistvsaturation;
11394#endif
11395
11396   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE)) return result;
11397   if(pSiS->VBFlags2 & VB2_301)          return result;
11398   if(!(pSiS->VBFlags & CRT2_TV))        return result;
11399
11400#ifdef UNLOCK_ALWAYS
11401   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11402#endif
11403   inSISIDXREG(SISPART4, 0x21, temp);
11404   return(int)((temp & 0x07) * 2);
11405}
11406
11407void SiS_SetSISTVcolcalib(ScrnInfoPtr pScrn, int val, Bool coarse)
11408{
11409   SISPtr pSiS = SISPTR(pScrn);
11410#ifdef SISDUALHEAD
11411   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11412#endif
11413   int ccoarse, cfine, cbase = pSiS->sistvccbase;
11414   /* UChar temp; */
11415
11416#ifdef SISDUALHEAD
11417   if(pSiSEnt && pSiS->DualHeadMode) cbase = pSiSEnt->sistvccbase;
11418#endif
11419
11420   if(coarse) {
11421      pSiS->sistvcolcalibc = ccoarse = val;
11422      cfine = pSiS->sistvcolcalibf;
11423#ifdef SISDUALHEAD
11424      if(pSiSEnt) {
11425         pSiSEnt->sistvcolcalibc = val;
11426	 if(pSiS->DualHeadMode) cfine = pSiSEnt->sistvcolcalibf;
11427      }
11428#endif
11429   } else {
11430      pSiS->sistvcolcalibf = cfine = val;
11431      ccoarse = pSiS->sistvcolcalibc;
11432#ifdef SISDUALHEAD
11433      if(pSiSEnt) {
11434         pSiSEnt->sistvcolcalibf = val;
11435         if(pSiS->DualHeadMode) ccoarse = pSiSEnt->sistvcolcalibc;
11436      }
11437#endif
11438   }
11439
11440   if(!(pSiS->VBFlags & CRT2_TV))               return;
11441   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE))        return;
11442   if(pSiS->VBFlags & (TV_HIVISION | TV_YPBPR)) return;
11443
11444#ifdef UNLOCK_ALWAYS
11445   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11446#endif
11447
11448   if((cfine >= -128) && (cfine <= 127) && (ccoarse >= -120) && (ccoarse <= 120)) {
11449      long finalcc = cbase + (((ccoarse * 256) + cfine) * 256);
11450
11451#if 0
11452      inSISIDXREG(SISPART4,0x1f,temp);
11453      if(!(temp & 0x01)) {
11454         if(pSiS->VBFlags & TV_NTSC) finalcc += 0x21ed8620;
11455	 else if(pSiS->VBFlags & TV_PALM) finalcc += ?;
11456	 else if(pSiS->VBFlags & TV_PALM) finalcc += ?;
11457	 else finalcc += 0x2a05d300;
11458      }
11459#endif
11460      setSISIDXREG(SISPART2,0x31,0x80,((finalcc >> 24) & 0x7f));
11461      outSISIDXREG(SISPART2,0x32,((finalcc >> 16) & 0xff));
11462      outSISIDXREG(SISPART2,0x33,((finalcc >> 8) & 0xff));
11463      outSISIDXREG(SISPART2,0x34,(finalcc & 0xff));
11464   }
11465}
11466
11467int SiS_GetSISTVcolcalib(ScrnInfoPtr pScrn, Bool coarse)
11468{
11469   SISPtr pSiS = SISPTR(pScrn);
11470#ifdef SISDUALHEAD
11471   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11472
11473   if(pSiSEnt && pSiS->DualHeadMode)
11474      if(coarse)  return (int)pSiSEnt->sistvcolcalibc;
11475      else        return (int)pSiSEnt->sistvcolcalibf;
11476   else
11477#endif
11478   if(coarse)     return (int)pSiS->sistvcolcalibc;
11479   else           return (int)pSiS->sistvcolcalibf;
11480}
11481
11482void SiS_SetSISTVcfilter(ScrnInfoPtr pScrn, int val)
11483{
11484   SISPtr pSiS = SISPTR(pScrn);
11485#ifdef SISDUALHEAD
11486   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11487#endif
11488
11489   pSiS->sistvcfilter = val ? 1 : 0;
11490#ifdef SISDUALHEAD
11491   if(pSiSEnt) pSiSEnt->sistvcfilter = pSiS->sistvcfilter;
11492#endif
11493
11494   if(!(pSiS->VBFlags & CRT2_TV))               return;
11495   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE))        return;
11496   if(pSiS->VBFlags & (TV_HIVISION | TV_YPBPR)) return;
11497
11498#ifdef UNLOCK_ALWAYS
11499   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11500#endif
11501
11502   setSISIDXREG(SISPART2,0x30,~0x10,((pSiS->sistvcfilter << 4) & 0x10));
11503}
11504
11505int SiS_GetSISTVcfilter(ScrnInfoPtr pScrn)
11506{
11507   SISPtr pSiS = SISPTR(pScrn);
11508   int result = pSiS->sistvcfilter;
11509   UChar temp;
11510#ifdef SISDUALHEAD
11511   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11512
11513   if(pSiSEnt && pSiS->DualHeadMode) result = pSiSEnt->sistvcfilter;
11514#endif
11515
11516   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE))        return result;
11517   if(!(pSiS->VBFlags & CRT2_TV))               return result;
11518   if(pSiS->VBFlags & (TV_HIVISION | TV_YPBPR)) return result;
11519
11520#ifdef UNLOCK_ALWAYS
11521   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11522#endif
11523   inSISIDXREG(SISPART2, 0x30, temp);
11524   return (int)((temp & 0x10) ? 1 : 0);
11525}
11526
11527void SiS_SetSISTVyfilter(ScrnInfoPtr pScrn, int val)
11528{
11529   SISPtr pSiS = SISPTR(pScrn);
11530#ifdef SISDUALHEAD
11531   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11532#endif
11533   UChar p35,p36,p37,p38,p48,p49,p4a,p30;
11534   int i,j;
11535
11536   pSiS->sistvyfilter = val;
11537#ifdef SISDUALHEAD
11538   if(pSiSEnt) pSiSEnt->sistvyfilter = pSiS->sistvyfilter;
11539#endif
11540
11541   if(!(pSiS->VBFlags & CRT2_TV))               return;
11542   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE))        return;
11543   if(pSiS->VBFlags & (TV_HIVISION | TV_YPBPR)) return;
11544
11545   p35 = pSiS->p2_35; p36 = pSiS->p2_36;
11546   p37 = pSiS->p2_37; p38 = pSiS->p2_38;
11547   p48 = pSiS->p2_48; p49 = pSiS->p2_49;
11548   p4a = pSiS->p2_4a; p30 = pSiS->p2_30;
11549#ifdef SISDUALHEAD
11550   if(pSiSEnt && pSiS->DualHeadMode) {
11551      p35 = pSiSEnt->p2_35; p36 = pSiSEnt->p2_36;
11552      p37 = pSiSEnt->p2_37; p38 = pSiSEnt->p2_38;
11553      p48 = pSiSEnt->p2_48; p49 = pSiSEnt->p2_49;
11554      p4a = pSiSEnt->p2_4a; p30 = pSiSEnt->p2_30;
11555   }
11556#endif
11557   p30 &= 0x20;
11558
11559#ifdef UNLOCK_ALWAYS
11560   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11561#endif
11562
11563   switch(pSiS->sistvyfilter) {
11564   case 0:
11565      andSISIDXREG(SISPART2,0x30,0xdf);
11566      break;
11567   case 1:
11568      outSISIDXREG(SISPART2,0x35,p35);
11569      outSISIDXREG(SISPART2,0x36,p36);
11570      outSISIDXREG(SISPART2,0x37,p37);
11571      outSISIDXREG(SISPART2,0x38,p38);
11572      if(!(pSiS->VBFlags2 & VB2_301)) {
11573         outSISIDXREG(SISPART2,0x48,p48);
11574         outSISIDXREG(SISPART2,0x49,p49);
11575         outSISIDXREG(SISPART2,0x4a,p4a);
11576      }
11577      setSISIDXREG(SISPART2,0x30,0xdf,p30);
11578      break;
11579   case 2:
11580   case 3:
11581   case 4:
11582   case 5:
11583   case 6:
11584   case 7:
11585   case 8:
11586      if(!(pSiS->VBFlags & (TV_PALM | TV_PALN | TV_NTSCJ))) {
11587         int yindex301 = -1, yindex301B = -1;
11588	 UChar p3d4_34;
11589
11590	 inSISIDXREG(SISCR,0x34,p3d4_34);
11591
11592	 switch((p3d4_34 & 0x7f)) {
11593	 case 0x59:  /* 320x200 */
11594	 case 0x41:
11595	 case 0x4f:
11596	 case 0x50:  /* 320x240 */
11597	 case 0x56:
11598	 case 0x53:
11599	    yindex301  = (pSiS->VBFlags & TV_NTSC) ? 0 : 4;
11600	    break;
11601	 case 0x2f:  /* 640x400 */
11602	 case 0x5d:
11603	 case 0x5e:
11604	 case 0x2e:  /* 640x480 */
11605	 case 0x44:
11606	 case 0x62:
11607	    yindex301  = (pSiS->VBFlags & TV_NTSC) ? 1 : 5;
11608	    yindex301B = (pSiS->VBFlags & TV_NTSC) ? 0 : 4;
11609	    break;
11610	 case 0x31:   /* 720x480 */
11611	 case 0x33:
11612	 case 0x35:
11613	 case 0x32:   /* 720x576 */
11614	 case 0x34:
11615	 case 0x36:
11616	 case 0x5f:   /* 768x576 */
11617	 case 0x60:
11618	 case 0x61:
11619	    yindex301  = (pSiS->VBFlags & TV_NTSC) ? 2 : 6;
11620	    yindex301B = (pSiS->VBFlags & TV_NTSC) ? 1 : 5;
11621	    break;
11622	 case 0x51:   /* 400x300 */
11623	 case 0x57:
11624	 case 0x54:
11625	 case 0x30:   /* 800x600 */
11626	 case 0x47:
11627	 case 0x63:
11628	    yindex301  = (pSiS->VBFlags & TV_NTSC) ? 3 : 7;
11629	    yindex301B = (pSiS->VBFlags & TV_NTSC) ? 2 : 6;
11630	    break;
11631	 case 0x52:   /* 512x384 */
11632	 case 0x58:
11633	 case 0x5c:
11634	 case 0x38:   /* 1024x768 */
11635	 case 0x4a:
11636	 case 0x64:
11637	    yindex301B = (pSiS->VBFlags & TV_NTSC) ? 3 : 7;
11638	    break;
11639	 }
11640         if(pSiS->VBFlags2 & VB2_301) {
11641            if(yindex301 >= 0) {
11642	       for(i=0, j=0x35; i<=3; i++, j++) {
11643	          outSISIDXREG(SISPART2,j,(SiSTVFilter301[yindex301].filter[pSiS->sistvyfilter-2][i]));
11644	       }
11645	    }
11646         } else {
11647            if(yindex301B >= 0) {
11648	       for(i=0, j=0x35; i<=3; i++, j++) {
11649	          outSISIDXREG(SISPART2,j,(SiSTVFilter301B[yindex301B].filter[pSiS->sistvyfilter-2][i]));
11650	       }
11651	       for(i=4, j=0x48; i<=6; i++, j++) {
11652	          outSISIDXREG(SISPART2,j,(SiSTVFilter301B[yindex301B].filter[pSiS->sistvyfilter-2][i]));
11653	       }
11654	    }
11655         }
11656         orSISIDXREG(SISPART2,0x30,0x20);
11657      }
11658   }
11659}
11660
11661int SiS_GetSISTVyfilter(ScrnInfoPtr pScrn)
11662{
11663   SISPtr pSiS = SISPTR(pScrn);
11664#ifdef SISDUALHEAD
11665   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11666
11667   if(pSiSEnt && pSiS->DualHeadMode)
11668      return (int)pSiSEnt->sistvyfilter;
11669   else
11670#endif
11671      return (int)pSiS->sistvyfilter;
11672}
11673
11674void SiS_SetSIS6326TVantiflicker(ScrnInfoPtr pScrn, int val)
11675{
11676   SISPtr pSiS = SISPTR(pScrn);
11677   UChar tmp;
11678
11679   pSiS->sistvantiflicker = val;
11680
11681   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) return;
11682
11683#ifdef UNLOCK_ALWAYS
11684   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11685#endif
11686
11687   tmp = SiS6326GetTVReg(pScrn,0x00);
11688   if(!(tmp & 0x04)) return;
11689
11690   /* Valid values: 0=off, 1=low, 2=med, 3=high, 4=adaptive */
11691   if(val >= 0 && val <= 4) {
11692      tmp &= 0x1f;
11693      tmp |= (val << 5);
11694      SiS6326SetTVReg(pScrn,0x00,tmp);
11695   }
11696}
11697
11698int SiS_GetSIS6326TVantiflicker(ScrnInfoPtr pScrn)
11699{
11700   SISPtr pSiS = SISPTR(pScrn);
11701   UChar tmp;
11702
11703   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) {
11704      return (int)pSiS->sistvantiflicker;
11705   }
11706
11707#ifdef UNLOCK_ALWAYS
11708   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11709#endif
11710
11711   tmp = SiS6326GetTVReg(pScrn,0x00);
11712   if(!(tmp & 0x04)) {
11713      return (int)pSiS->sistvantiflicker;
11714   } else {
11715      return (int)((tmp >> 5) & 0x07);
11716   }
11717}
11718
11719void SiS_SetSIS6326TVenableyfilter(ScrnInfoPtr pScrn, int val)
11720{
11721   SISPtr pSiS = SISPTR(pScrn);
11722   UChar tmp;
11723
11724   if(val) val = 1;
11725   pSiS->sis6326enableyfilter = val;
11726
11727   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) return;
11728
11729#ifdef UNLOCK_ALWAYS
11730   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11731#endif
11732
11733   tmp = SiS6326GetTVReg(pScrn,0x00);
11734   if(!(tmp & 0x04)) return;
11735
11736   tmp = SiS6326GetTVReg(pScrn,0x43);
11737   tmp &= ~0x10;
11738   tmp |= ((val & 0x01) << 4);
11739   SiS6326SetTVReg(pScrn,0x43,tmp);
11740}
11741
11742int SiS_GetSIS6326TVenableyfilter(ScrnInfoPtr pScrn)
11743{
11744   SISPtr pSiS = SISPTR(pScrn);
11745   UChar tmp;
11746
11747   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) {
11748      return (int)pSiS->sis6326enableyfilter;
11749   }
11750
11751#ifdef UNLOCK_ALWAYS
11752   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11753#endif
11754
11755   tmp = SiS6326GetTVReg(pScrn,0x00);
11756   if(!(tmp & 0x04)) {
11757      return (int)pSiS->sis6326enableyfilter;
11758   } else {
11759      tmp = SiS6326GetTVReg(pScrn,0x43);
11760      return (int)((tmp >> 4) & 0x01);
11761   }
11762}
11763
11764void SiS_SetSIS6326TVyfilterstrong(ScrnInfoPtr pScrn, int val)
11765{
11766   SISPtr pSiS = SISPTR(pScrn);
11767   UChar tmp;
11768
11769   if(val) val = 1;
11770   pSiS->sis6326yfilterstrong = val;
11771
11772   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) return;
11773
11774#ifdef UNLOCK_ALWAYS
11775   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11776#endif
11777
11778   tmp = SiS6326GetTVReg(pScrn,0x00);
11779   if(!(tmp & 0x04)) return;
11780
11781   tmp = SiS6326GetTVReg(pScrn,0x43);
11782   if(tmp & 0x10) {
11783      tmp &= ~0x40;
11784      tmp |= ((val & 0x01) << 6);
11785      SiS6326SetTVReg(pScrn,0x43,tmp);
11786   }
11787}
11788
11789int SiS_GetSIS6326TVyfilterstrong(ScrnInfoPtr pScrn)
11790{
11791   SISPtr pSiS = SISPTR(pScrn);
11792   UChar tmp;
11793
11794   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) {
11795      return (int)pSiS->sis6326yfilterstrong;
11796   }
11797
11798#ifdef UNLOCK_ALWAYS
11799   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11800#endif
11801
11802   tmp = SiS6326GetTVReg(pScrn,0x00);
11803   if(!(tmp & 0x04)) {
11804      return (int)pSiS->sis6326yfilterstrong;
11805   } else {
11806      tmp = SiS6326GetTVReg(pScrn,0x43);
11807      if(!(tmp & 0x10)) {
11808         return (int)pSiS->sis6326yfilterstrong;
11809      } else {
11810         return (int)((tmp >> 6) & 0x01);
11811      }
11812   }
11813}
11814
11815void SiS_SetTVxposoffset(ScrnInfoPtr pScrn, int val)
11816{
11817   SISPtr pSiS = SISPTR(pScrn);
11818#ifdef SISDUALHEAD
11819   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11820#endif
11821
11822#ifdef UNLOCK_ALWAYS
11823   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11824#endif
11825
11826   pSiS->tvxpos = val;
11827#ifdef SISDUALHEAD
11828   if(pSiSEnt) pSiSEnt->tvxpos = val;
11829#endif
11830
11831   if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
11832
11833      if(pSiS->VBFlags & CRT2_TV) {
11834
11835         if(pSiS->VBFlags2 & VB2_CHRONTEL) {
11836
11837	    int x = pSiS->tvx;
11838#ifdef SISDUALHEAD
11839	    if(pSiSEnt && pSiS->DualHeadMode) x = pSiSEnt->tvx;
11840#endif
11841	    switch(pSiS->ChrontelType) {
11842	    case CHRONTEL_700x:
11843	       if((val >= -32) && (val <= 32)) {
11844		   x += val;
11845		   if(x < 0) x = 0;
11846		   SiS_SetCH700x(pSiS->SiS_Pr, 0x0a, (x & 0xff));
11847		   SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x08, ((x & 0x0100) >> 7), 0xFD);
11848	       }
11849	       break;
11850	    case CHRONTEL_701x:
11851	       /* Not supported by hardware */
11852	       break;
11853	    }
11854
11855	 } else if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
11856
11857	    if((val >= -32) && (val <= 32)) {
11858
11859	        UChar p2_1f,p2_20,p2_2b,p2_42,p2_43;
11860		UShort temp;
11861		int mult;
11862
11863		p2_1f = pSiS->p2_1f;
11864		p2_20 = pSiS->p2_20;
11865		p2_2b = pSiS->p2_2b;
11866		p2_42 = pSiS->p2_42;
11867		p2_43 = pSiS->p2_43;
11868#ifdef SISDUALHEAD
11869	        if(pSiSEnt && pSiS->DualHeadMode) {
11870		   p2_1f = pSiSEnt->p2_1f;
11871		   p2_20 = pSiSEnt->p2_20;
11872		   p2_2b = pSiSEnt->p2_2b;
11873		   p2_42 = pSiSEnt->p2_42;
11874		   p2_43 = pSiSEnt->p2_43;
11875		}
11876#endif
11877		mult = 2;
11878		if(pSiS->VBFlags & TV_YPBPR) {
11879		   if(pSiS->VBFlags & (TV_YPBPR1080I | TV_YPBPR750P)) {
11880		      mult = 4;
11881		   }
11882		}
11883
11884		temp = p2_1f | ((p2_20 & 0xf0) << 4);
11885		temp += (val * mult);
11886		p2_1f = temp & 0xff;
11887		p2_20 = (temp & 0xf00) >> 4;
11888		p2_2b = ((p2_2b & 0x0f) + (val * mult)) & 0x0f;
11889		temp = p2_43 | ((p2_42 & 0xf0) << 4);
11890		temp += (val * mult);
11891		p2_43 = temp & 0xff;
11892		p2_42 = (temp & 0xf00) >> 4;
11893		SISWaitRetraceCRT2(pScrn);
11894	        outSISIDXREG(SISPART2,0x1f,p2_1f);
11895		setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
11896		setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
11897		setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
11898		outSISIDXREG(SISPART2,0x43,p2_43);
11899	     }
11900	 }
11901      }
11902
11903   } else if(pSiS->Chipset == PCI_CHIP_SIS6326) {
11904
11905      if(pSiS->SiS6326Flags & SIS6326_TVDETECTED) {
11906
11907         UChar tmp;
11908	 UShort temp1, temp2, temp3;
11909
11910         tmp = SiS6326GetTVReg(pScrn,0x00);
11911         if(tmp & 0x04) {
11912
11913	    temp1 = pSiS->tvx1;
11914            temp2 = pSiS->tvx2;
11915            temp3 = pSiS->tvx3;
11916            if((val >= -16) && (val <= 16)) {
11917	       if(val > 0) {
11918	          temp1 += (val * 4);
11919	          temp2 += (val * 4);
11920	          while((temp1 > 0x0fff) || (temp2 > 0x0fff)) {
11921	             temp1 -= 4;
11922		     temp2 -= 4;
11923	          }
11924	       } else {
11925	          val = -val;
11926	          temp3 += (val * 4);
11927	          while(temp3 > 0x03ff) {
11928	     	     temp3 -= 4;
11929	          }
11930	       }
11931            }
11932            SiS6326SetTVReg(pScrn,0x3a,(temp1 & 0xff));
11933            tmp = SiS6326GetTVReg(pScrn,0x3c);
11934            tmp &= 0xf0;
11935            tmp |= ((temp1 & 0x0f00) >> 8);
11936            SiS6326SetTVReg(pScrn,0x3c,tmp);
11937            SiS6326SetTVReg(pScrn,0x26,(temp2 & 0xff));
11938            tmp = SiS6326GetTVReg(pScrn,0x27);
11939            tmp &= 0x0f;
11940            tmp |= ((temp2 & 0x0f00) >> 4);
11941            SiS6326SetTVReg(pScrn,0x27,tmp);
11942            SiS6326SetTVReg(pScrn,0x12,(temp3 & 0xff));
11943            tmp = SiS6326GetTVReg(pScrn,0x13);
11944            tmp &= ~0xC0;
11945            tmp |= ((temp3 & 0x0300) >> 2);
11946            SiS6326SetTVReg(pScrn,0x13,tmp);
11947	 }
11948      }
11949   }
11950}
11951
11952int SiS_GetTVxposoffset(ScrnInfoPtr pScrn)
11953{
11954   SISPtr pSiS = SISPTR(pScrn);
11955#ifdef SISDUALHEAD
11956   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11957
11958   if(pSiSEnt && pSiS->DualHeadMode)
11959        return (int)pSiSEnt->tvxpos;
11960   else
11961#endif
11962        return (int)pSiS->tvxpos;
11963}
11964
11965void SiS_SetTVyposoffset(ScrnInfoPtr pScrn, int val)
11966{
11967   SISPtr pSiS = SISPTR(pScrn);
11968#ifdef SISDUALHEAD
11969   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11970#endif
11971
11972#ifdef UNLOCK_ALWAYS
11973   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11974#endif
11975
11976   pSiS->tvypos = val;
11977#ifdef SISDUALHEAD
11978   if(pSiSEnt) pSiSEnt->tvypos = val;
11979#endif
11980
11981   if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
11982
11983      if(pSiS->VBFlags & CRT2_TV) {
11984
11985         if(pSiS->VBFlags2 & VB2_CHRONTEL) {
11986
11987	    int y = pSiS->tvy;
11988#ifdef SISDUALHEAD
11989	    if(pSiSEnt && pSiS->DualHeadMode) y = pSiSEnt->tvy;
11990#endif
11991	    switch(pSiS->ChrontelType) {
11992	    case CHRONTEL_700x:
11993	       if((val >= -32) && (val <= 32)) {
11994		   y -= val;
11995		   if(y < 0) y = 0;
11996		   SiS_SetCH700x(pSiS->SiS_Pr, 0x0b, (y & 0xff));
11997		   SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x08, ((y & 0x0100) >> 8), 0xFE);
11998	       }
11999	       break;
12000	    case CHRONTEL_701x:
12001	       /* Not supported by hardware */
12002	       break;
12003	    }
12004
12005	 } else if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
12006
12007	    if((val >= -32) && (val <= 32)) {
12008		char p2_01, p2_02;
12009
12010		if( (pSiS->VBFlags & TV_HIVISION) ||
12011		    ((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & (TV_YPBPR1080I|TV_YPBPR750P))) ) {
12012		   val *= 2;
12013		} else {
12014		   val /= 2;  /* 4 */
12015		}
12016
12017		p2_01 = pSiS->p2_01;
12018		p2_02 = pSiS->p2_02;
12019#ifdef SISDUALHEAD
12020	        if(pSiSEnt && pSiS->DualHeadMode) {
12021		   p2_01 = pSiSEnt->p2_01;
12022		   p2_02 = pSiSEnt->p2_02;
12023		}
12024#endif
12025		p2_01 += val; /* val * 2 */
12026		p2_02 += val; /* val * 2 */
12027		if(!(pSiS->VBFlags & (TV_YPBPR | TV_HIVISION))) {
12028		   while((p2_01 <= 0) || (p2_02 <= 0)) {
12029		      p2_01 += 2;
12030		      p2_02 += 2;
12031		   }
12032		} else if((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR1080I)) {
12033		   while(p2_01 <= 8) {
12034		      p2_01 += 2;
12035		      p2_02 += 2;
12036		   }
12037		} else if((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR750P)) {
12038		   while(p2_01 <= 10) {
12039		      p2_01 += 2;
12040		      p2_02 += 2;
12041		   }
12042		}
12043
12044		SISWaitRetraceCRT2(pScrn);
12045		outSISIDXREG(SISPART2,0x01,p2_01);
12046		outSISIDXREG(SISPART2,0x02,p2_02);
12047	     }
12048	 }
12049
12050      }
12051
12052   } else if(pSiS->Chipset == PCI_CHIP_SIS6326) {
12053
12054      if(pSiS->SiS6326Flags & SIS6326_TVDETECTED) {
12055
12056         UChar tmp;
12057	 int temp1, limit;
12058
12059         tmp = SiS6326GetTVReg(pScrn,0x00);
12060         if(tmp & 0x04) {
12061
12062	    if((val >= -16) && (val <= 16)) {
12063	      temp1 = (UShort)pSiS->tvy1;
12064	      limit = (pSiS->SiS6326Flags & SIS6326_TVPAL) ? 625 : 525;
12065	      if(val > 0) {
12066                temp1 += (val * 4);
12067	        if(temp1 > limit) temp1 -= limit;
12068	      } else {
12069	        val = -val;
12070	        temp1 -= (val * 2);
12071	        if(temp1 <= 0) temp1 += (limit -1);
12072	      }
12073	      SiS6326SetTVReg(pScrn,0x11,(temp1 & 0xff));
12074	      tmp = SiS6326GetTVReg(pScrn,0x13);
12075	      tmp &= ~0x30;
12076	      tmp |= ((temp1 & 0x300) >> 4);
12077	      SiS6326SetTVReg(pScrn,0x13,tmp);
12078	      if(temp1 == 1)                                 tmp = 0x10;
12079	      else {
12080	       if(pSiS->SiS6326Flags & SIS6326_TVPAL) {
12081	         if((temp1 <= 3) || (temp1 >= (limit - 2)))  tmp = 0x08;
12082	         else if(temp1 < 22)		 	     tmp = 0x02;
12083	         else 					     tmp = 0x04;
12084	       } else {
12085	         if((temp1 <= 5) || (temp1 >= (limit - 4)))  tmp = 0x08;
12086	         else if(temp1 < 19)			     tmp = 0x02;
12087	         else 					     tmp = 0x04;
12088	       }
12089	     }
12090	     SiS6326SetTVReg(pScrn,0x21,tmp);
12091           }
12092	 }
12093      }
12094   }
12095}
12096
12097int SiS_GetTVyposoffset(ScrnInfoPtr pScrn)
12098{
12099   SISPtr pSiS = SISPTR(pScrn);
12100#ifdef SISDUALHEAD
12101   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12102
12103   if(pSiSEnt && pSiS->DualHeadMode)
12104        return (int)pSiSEnt->tvypos;
12105   else
12106#endif
12107        return (int)pSiS->tvypos;
12108}
12109
12110void SiS_SetTVxscale(ScrnInfoPtr pScrn, int val)
12111{
12112   SISPtr pSiS = SISPTR(pScrn);
12113#ifdef SISDUALHEAD
12114   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12115#endif
12116
12117#ifdef UNLOCK_ALWAYS
12118   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
12119#endif
12120
12121   pSiS->tvxscale = val;
12122#ifdef SISDUALHEAD
12123   if(pSiSEnt) pSiSEnt->tvxscale = val;
12124#endif
12125
12126   if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
12127
12128      if((pSiS->VBFlags & CRT2_TV) && (pSiS->VBFlags2 & VB2_SISBRIDGE)) {
12129
12130	 if((val >= -16) && (val <= 16)) {
12131
12132	    UChar p2_44,p2_45,p2_46;
12133	    int scalingfactor, mult;
12134
12135	    p2_44 = pSiS->p2_44;
12136	    p2_45 = pSiS->p2_45 & 0x3f;
12137	    p2_46 = pSiS->p2_46 & 0x07;
12138#ifdef SISDUALHEAD
12139	    if(pSiSEnt && pSiS->DualHeadMode) {
12140	       p2_44 = pSiSEnt->p2_44;
12141	       p2_45 = pSiSEnt->p2_45 & 0x3f;
12142	       p2_46 = pSiSEnt->p2_46 & 0x07;
12143	    }
12144#endif
12145	    scalingfactor = (p2_46 << 13) | ((p2_45 & 0x1f) << 8) | p2_44;
12146
12147	    mult = 64;
12148	    if(pSiS->VBFlags & TV_YPBPR) {
12149	       if(pSiS->VBFlags & TV_YPBPR1080I) {
12150	          mult = 190;
12151	       } else if(pSiS->VBFlags & TV_YPBPR750P) {
12152	          mult = 360;
12153	       }
12154	    } else if(pSiS->VBFlags & TV_HIVISION) {
12155	       mult = 190;
12156	    }
12157
12158	    if(val < 0) {
12159	       p2_45 &= 0xdf;
12160	       scalingfactor += ((-val) * mult);
12161	       if(scalingfactor > 0xffff) scalingfactor = 0xffff;
12162	    } else if(val > 0) {
12163	       p2_45 &= 0xdf;
12164	       scalingfactor -= (val * mult);
12165	       if(scalingfactor < 1) scalingfactor = 1;
12166	    }
12167
12168	    p2_44 = scalingfactor & 0xff;
12169	    p2_45 &= 0xe0;
12170	    p2_45 |= ((scalingfactor >> 8) & 0x1f);
12171	    p2_46 = ((scalingfactor >> 13) & 0x07);
12172
12173	    SISWaitRetraceCRT2(pScrn);
12174	    outSISIDXREG(SISPART2,0x44,p2_44);
12175	    setSISIDXREG(SISPART2,0x45,0xC0,p2_45);
12176	    if(!(pSiS->VBFlags2 & VB2_301)) {
12177	       setSISIDXREG(SISPART2,0x46,0xF8,p2_46);
12178	    }
12179
12180	 }
12181
12182      }
12183
12184   }
12185}
12186
12187int SiS_GetTVxscale(ScrnInfoPtr pScrn)
12188{
12189   SISPtr pSiS = SISPTR(pScrn);
12190#ifdef SISDUALHEAD
12191   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12192
12193   if(pSiSEnt && pSiS->DualHeadMode)
12194        return (int)pSiSEnt->tvxscale;
12195   else
12196#endif
12197        return (int)pSiS->tvxscale;
12198}
12199
12200void SiS_SetTVyscale(ScrnInfoPtr pScrn, int val)
12201{
12202   SISPtr pSiS = SISPTR(pScrn);
12203#ifdef SISDUALHEAD
12204   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12205#endif
12206
12207#ifdef UNLOCK_ALWAYS
12208   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
12209#endif
12210
12211   if(val < -4) val = -4;
12212   if(val > 3)  val = 3;
12213
12214   pSiS->tvyscale = val;
12215#ifdef SISDUALHEAD
12216   if(pSiSEnt) pSiSEnt->tvyscale = val;
12217#endif
12218
12219   if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
12220
12221      if((pSiS->VBFlags & CRT2_TV) && (pSiS->VBFlags2 & VB2_SISBRIDGE)) {
12222
12223	 int srindex = -1, newvde, i = 0, j, vlimit, temp, vdediv;
12224	 int hdclk = 0;
12225	 UChar p3d4_34;
12226	 Bool found = FALSE;
12227	 Bool usentsc = FALSE;
12228	 Bool is750p = FALSE;
12229	 Bool is1080i = FALSE;
12230	 Bool skipmoveup = FALSE;
12231
12232	 SiS_UnLockCRT2(pSiS->SiS_Pr);
12233
12234	 if((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR525P)) {
12235	    vlimit = 525 - 7;
12236	    vdediv = 1;
12237	    usentsc = TRUE;
12238	 } else if((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR625P)) {
12239	    vlimit = 625 - 7;
12240	    vdediv = 1;
12241	 } else if((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR750P)) {
12242	    vlimit = 750 - 7;
12243	    vdediv = 1;
12244	    is750p = TRUE;
12245	 } else if(((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR1080I)) ||
12246	           (pSiS->VBFlags & TV_HIVISION)) {
12247	    vlimit = (1125 - 7) / 2;
12248	    vdediv = 2;
12249	    is1080i = TRUE;
12250	 } else {
12251	    if( ((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR525I)) ||
12252	        ((!(pSiS->VBFlags & TV_YPBPR)) && (pSiS->VBFlags & (TV_NTSC | TV_PALM))) ) {
12253	       usentsc = TRUE;
12254	    }
12255	    vlimit = usentsc ? 259 : 309;
12256	    vdediv = 2;
12257	 }
12258
12259	 inSISIDXREG(SISCR,0x34,p3d4_34);
12260
12261	 switch((p3d4_34 & 0x7f)) {
12262	 case 0x50:   /* 320x240 */
12263	 case 0x56:
12264	 case 0x53:
12265	    hdclk = 1;
12266	    /* fall through */
12267	 case 0x2e:   /* 640x480 */
12268	 case 0x44:
12269	 case 0x62:
12270	    if(is1080i) {
12271	       srindex = 98;
12272	    } else if(is750p) {
12273	       srindex = 42;
12274	    } else {
12275	       srindex  = usentsc ? 0 : 21;
12276	    }
12277	    break;
12278	 case 0x31:   /* 720x480 */
12279	 case 0x33:
12280	 case 0x35:
12281	    if(is1080i) {
12282	       /* n/a */
12283	    } else if(is750p) {
12284	       srindex = 49;
12285	    } else {
12286	       srindex = usentsc ? 7 : 21;
12287	    }
12288	    break;
12289	 case 0x32:   /* 720x576 */
12290	 case 0x34:
12291	 case 0x36:
12292	 case 0x5f:   /* 768x576 */
12293	 case 0x60:
12294	 case 0x61:
12295	    if(is1080i) {
12296	       /* n/a */
12297	    } else if(is750p) {
12298	       srindex = 56;
12299	    } else {
12300	       srindex  = usentsc ? 147 : 28;
12301	    }
12302	    break;
12303	 case 0x70:   /* 800x480 */
12304	 case 0x7a:
12305	 case 0x76:
12306	    if(is1080i) {
12307	       srindex = 105;
12308	    } else if(is750p) {
12309	       srindex = 63;
12310	    } else {
12311	       srindex = usentsc ? 175 : 21;
12312	    }
12313	    break;
12314	 case 0x51:   /* 400x300 - hdclk mode */
12315	 case 0x57:
12316	 case 0x54:
12317	    hdclk = 1;
12318	    /* fall through */
12319	 case 0x30:   /* 800x600 */
12320	 case 0x47:
12321	 case 0x63:
12322	    if(is1080i) {
12323	       srindex = 112;
12324	    } else if(is750p) {
12325	       srindex = 70;
12326	    } else {
12327	       srindex = usentsc ? 14 : 35;
12328	    }
12329	    break;
12330	 case 0x1d:	/* 960x540 */
12331	 case 0x1e:
12332	 case 0x1f:
12333	    if(is1080i) {
12334	       srindex = 196;
12335	       skipmoveup = TRUE;
12336	    }
12337	    break;
12338	 case 0x20:	/* 960x600 */
12339	 case 0x21:
12340	 case 0x22:
12341	    if(pSiS->VGAEngine == SIS_315_VGA && is1080i) {
12342	       srindex = 203;
12343	    }
12344	    break;
12345	 case 0x71:	/* 1024x576 */
12346	 case 0x74:
12347	 case 0x77:
12348	    if(is1080i) {
12349	       srindex = 119;
12350	    } else if(is750p) {
12351	       srindex = 77;
12352	    } else {
12353	       srindex  = usentsc ? 182 : 189;
12354	    }
12355	    break;
12356	 case 0x52:	/* 512x384 */
12357	 case 0x58:
12358	 case 0x5c:
12359	    hdclk = 1;
12360	    /* fall through */
12361	 case 0x38:	/* 1024x768 */
12362	 case 0x4a:
12363	 case 0x64:
12364	    if(is1080i) {
12365	       srindex = 126;
12366	    } else if(is750p) {
12367	       srindex = 84;
12368	    } else if(!usentsc) {
12369	       srindex = 154;
12370	    } else if(vdediv == 1) {
12371	       if(!hdclk) srindex = 168;
12372	    } else {
12373	       if(!hdclk) srindex = 161;
12374	    }
12375	    break;
12376	 case 0x79:	/* 1280x720 */
12377	 case 0x75:
12378	 case 0x78:
12379	    if(is1080i) {
12380	       srindex = 133;
12381	    } else if(is750p) {
12382	       srindex = 91;
12383	    }
12384	    break;
12385	 case 0x3a:	/* 1280x1024 */
12386	 case 0x4d:
12387	 case 0x65:
12388	    if(is1080i) {
12389	       srindex = 140;
12390	    }
12391	    break;
12392	 }
12393
12394	 if(srindex < 0) return;
12395
12396	 if(pSiS->tvyscale != 0) {
12397	    for(j = 0; j <= 1; j++) {
12398	       for(i = 0; i <= 6; i++) {
12399		  if(SiSTVVScale[srindex+i].sindex == pSiS->tvyscale) {
12400		     found = TRUE;
12401		     break;
12402		  }
12403	       }
12404	       if(found) break;
12405	       if(pSiS->tvyscale > 0) pSiS->tvyscale--;
12406	       else pSiS->tvyscale++;
12407	    }
12408	 }
12409
12410#ifdef SISDUALHEAD
12411	 if(pSiSEnt) pSiSEnt->tvyscale = pSiS->tvyscale;
12412#endif
12413
12414	 if(pSiS->tvyscale == 0) {
12415	    UChar p2_0a = pSiS->p2_0a;
12416	    UChar p2_2f = pSiS->p2_2f;
12417	    UChar p2_30 = pSiS->p2_30;
12418	    UChar p2_46 = pSiS->p2_46;
12419	    UChar p2_47 = pSiS->p2_47;
12420	    UChar p1scaling[9], p4scaling[9];
12421	    UChar *p2scaling;
12422
12423	    for(i = 0; i < 9; i++) {
12424	        p1scaling[i] = pSiS->scalingp1[i];
12425		p4scaling[i] = pSiS->scalingp4[i];
12426	    }
12427	    p2scaling = &pSiS->scalingp2[0];
12428
12429#ifdef SISDUALHEAD
12430	    if(pSiSEnt && pSiS->DualHeadMode) {
12431	       p2_0a = pSiSEnt->p2_0a;
12432	       p2_2f = pSiSEnt->p2_2f;
12433	       p2_30 = pSiSEnt->p2_30;
12434	       p2_46 = pSiSEnt->p2_46;
12435	       p2_47 = pSiSEnt->p2_47;
12436	       for(i = 0; i < 9; i++) {
12437		  p1scaling[i] = pSiSEnt->scalingp1[i];
12438		  p4scaling[i] = pSiSEnt->scalingp4[i];
12439	       }
12440	       p2scaling = &pSiSEnt->scalingp2[0];
12441	    }
12442#endif
12443            SISWaitRetraceCRT2(pScrn);
12444	    if(pSiS->VBFlags2 & VB2_SISTAP4SCALER) {
12445	       for(i = 0; i < 64; i++) {
12446	          outSISIDXREG(SISPART2,(0xc0 + i),p2scaling[i]);
12447	       }
12448	    }
12449	    for(i = 0; i < 9; i++) {
12450	       outSISIDXREG(SISPART1,SiSScalingP1Regs[i],p1scaling[i]);
12451	    }
12452	    for(i = 0; i < 9; i++) {
12453	       outSISIDXREG(SISPART4,SiSScalingP4Regs[i],p4scaling[i]);
12454	    }
12455
12456	    setSISIDXREG(SISPART2,0x0a,0x7f,(p2_0a & 0x80));
12457	    outSISIDXREG(SISPART2,0x2f,p2_2f);
12458	    setSISIDXREG(SISPART2,0x30,0x3f,(p2_30 & 0xc0));
12459	    if(!(pSiS->VBFlags2 & VB2_301)) {
12460	       setSISIDXREG(SISPART2,0x46,0x9f,(p2_46 & 0x60));
12461	       outSISIDXREG(SISPART2,0x47,p2_47);
12462	    }
12463
12464	 } else {
12465
12466	    int realvde, myypos, watchdog = 32;
12467	    unsigned short temp1, temp2, vgahde, vgaht, vgavt;
12468	    int p1div = 1;
12469	    ULong calctemp;
12470
12471	    srindex += i;
12472	    newvde = SiSTVVScale[srindex].ScaleVDE;
12473	    realvde = SiSTVVScale[srindex].RealVDE;
12474
12475	    if(vdediv == 1) p1div = 2;
12476
12477	    if(!skipmoveup) {
12478	       do {
12479	          inSISIDXREG(SISPART2,0x01,temp);
12480	          temp = vlimit - ((temp & 0x7f) / p1div);
12481	          if((temp - (((newvde / vdediv) - 2) + 9)) > 0) break;
12482	          myypos = pSiS->tvypos - 1;
12483#ifdef SISDUALHEAD
12484	          if(pSiSEnt && pSiS->DualHeadMode) myypos = pSiSEnt->tvypos - 1;
12485#endif
12486	          SiS_SetTVyposoffset(pScrn, myypos);
12487	       } while(watchdog--);
12488	    }
12489
12490	    SISWaitRetraceCRT2(pScrn);
12491
12492	    if(pSiS->VBFlags2 & VB2_SISTAP4SCALER) {
12493	       SiS_CalcXTapScaler(pSiS->SiS_Pr, realvde, newvde, 4, FALSE);
12494	    }
12495
12496	    if(!(pSiS->VBFlags2 & VB2_301)) {
12497	       temp = (newvde / vdediv) - 3;
12498	       setSISIDXREG(SISPART2,0x46,0x9f,((temp & 0x0300) >> 3));
12499	       outSISIDXREG(SISPART2,0x47,(temp & 0xff));
12500	    }
12501
12502	    inSISIDXREG(SISPART1,0x0a,temp1);
12503	    inSISIDXREG(SISPART1,0x0c,temp2);
12504	    vgahde = ((temp2 & 0xf0) << 4) | temp1;
12505	    if(pSiS->VGAEngine == SIS_300_VGA) {
12506	       vgahde -= 12;
12507	    } else {
12508	       vgahde -= 16;
12509	       if(hdclk) vgahde <<= 1;
12510	    }
12511
12512	    vgaht = SiSTVVScale[srindex].reg[0];
12513	    temp1 = vgaht;
12514	    if((pSiS->VGAEngine == SIS_315_VGA) && hdclk) temp1 >>= 1;
12515	    temp1--;
12516	    outSISIDXREG(SISPART1,0x08,(temp1 & 0xff));
12517	    setSISIDXREG(SISPART1,0x09,0x0f,((temp1 >> 4) & 0xf0));
12518
12519	    temp2 = (vgaht - vgahde) >> 2;
12520	    if(pSiS->VGAEngine == SIS_300_VGA) {
12521	       temp1 = vgahde + 12 + temp2;
12522	       temp2 = temp1 + (temp2 << 1);
12523	    } else {
12524	       temp1 = vgahde;
12525	       if(hdclk) {
12526		  temp1 >>= 1;
12527		  temp2 >>= 1;
12528	       }
12529	       temp2 >>= 1;
12530	       temp1 = temp1 + 16 + temp2;
12531	       temp2 = temp1 + temp2;
12532	    }
12533	    outSISIDXREG(SISPART1,0x0b,(temp1 & 0xff));
12534	    setSISIDXREG(SISPART1,0x0c,0xf0,((temp1 >> 8) & 0x0f));
12535	    outSISIDXREG(SISPART1,0x0d,(temp2 & 0xff));
12536
12537	    vgavt = SiSTVVScale[srindex].reg[1];
12538	    temp1 = vgavt - 1;
12539	    if(pSiS->VGAEngine == SIS_315_VGA) temp1--;
12540	    outSISIDXREG(SISPART1,0x0e,(temp1 & 0xff));
12541	    setSISIDXREG(SISPART1,0x12,0xf8,((temp1 >> 8 ) & 0x07));
12542	    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->ChipType >= SIS_661)) {
12543	       temp1 = (vgavt + SiSTVVScale[srindex].RealVDE) >> 1;
12544	       temp2 = ((vgavt - SiSTVVScale[srindex].RealVDE) >> 4) + temp1 + 1;
12545	    } else {
12546	       temp1 = (vgavt - SiSTVVScale[srindex].RealVDE) >> 2;
12547	       temp2 = (temp1 < 4) ? 4 : temp1;
12548	       temp1 += SiSTVVScale[srindex].RealVDE;
12549	       temp2 = (temp2 >> 2) + temp1 + 1;
12550	    }
12551	    outSISIDXREG(SISPART1,0x10,(temp1 & 0xff));
12552	    setSISIDXREG(SISPART1,0x11,0x8f,((temp1 >> 4) & 0x70));
12553	    setSISIDXREG(SISPART1,0x11,0xf0,(temp2 & 0x0f));
12554
12555	    setSISIDXREG(SISPART2,0x0a,0x7f,((SiSTVVScale[srindex].reg[2] >> 8) & 0x80));
12556	    outSISIDXREG(SISPART2,0x2f,((newvde / vdediv) - 2));
12557	    setSISIDXREG(SISPART2,0x30,0x3f,((((newvde / vdediv) - 2) >> 2) & 0xc0));
12558
12559	    outSISIDXREG(SISPART4,0x13,(SiSTVVScale[srindex].reg[2] & 0xff));
12560	    outSISIDXREG(SISPART4,0x14,(SiSTVVScale[srindex].reg[3] & 0xff));
12561	    setSISIDXREG(SISPART4,0x15,0x7f,((SiSTVVScale[srindex].reg[3] >> 1) & 0x80));
12562
12563	    temp1 = vgaht - 1;
12564	    outSISIDXREG(SISPART4,0x16,(temp1 & 0xff));
12565	    setSISIDXREG(SISPART4,0x15,0x87,((temp1 >> 5) & 0x78));
12566
12567	    temp1 = vgavt - 1;
12568	    outSISIDXREG(SISPART4,0x17,(temp1 & 0xff));
12569	    setSISIDXREG(SISPART4,0x15,0xf8,((temp1 >> 8) & 0x07));
12570
12571	    outSISIDXREG(SISPART4,0x18,0x00);
12572	    setSISIDXREG(SISPART4,0x19,0xf0,0x00);
12573
12574	    inSISIDXREG(SISPART4,0x0e,temp1);
12575	    if(is1080i) {
12576	       if(!(temp1 & 0xe0)) newvde >>= 1;
12577	    }
12578
12579	    temp = 0x40;
12580	    if(realvde <= newvde) temp = 0;
12581	    else realvde -= newvde;
12582
12583	    calctemp = (realvde * 256 * 1024) / newvde;
12584	    if((realvde * 256 * 1024) % newvde) calctemp++;
12585	    outSISIDXREG(SISPART4,0x1b,(calctemp & 0xff));
12586	    outSISIDXREG(SISPART4,0x1a,((calctemp >> 8) & 0xff));
12587	    setSISIDXREG(SISPART4,0x19,0x8f,(((calctemp >> 12) & 0x70) | temp));
12588	 }
12589
12590      }
12591
12592   }
12593}
12594
12595int SiS_GetTVyscale(ScrnInfoPtr pScrn)
12596{
12597   SISPtr pSiS = SISPTR(pScrn);
12598#ifdef SISDUALHEAD
12599   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12600
12601   if(pSiSEnt && pSiS->DualHeadMode)
12602        return (int)pSiSEnt->tvyscale;
12603   else
12604#endif
12605        return (int)pSiS->tvyscale;
12606}
12607
12608void SiS_SetSISCRT1SaturationGain(ScrnInfoPtr pScrn, int val)
12609{
12610   SISPtr pSiS = SISPTR(pScrn);
12611#ifdef SISDUALHEAD
12612   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12613#endif
12614
12615   pSiS->siscrt1satgain = val;
12616#ifdef SISDUALHEAD
12617   if(pSiSEnt) pSiSEnt->siscrt1satgain = val;
12618#endif
12619
12620   if(!(pSiS->SiS_SD3_Flags & SiS_SD3_CRT1SATGAIN)) return;
12621
12622#ifdef UNLOCK_ALWAYS
12623   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
12624#endif
12625
12626   if((val >= 0) && (val <= 7)) {
12627      setSISIDXREG(SISCR,0x53,0xE3, (val << 2));
12628   }
12629}
12630
12631int SiS_GetSISCRT1SaturationGain(ScrnInfoPtr pScrn)
12632{
12633   SISPtr pSiS = SISPTR(pScrn);
12634   int result = pSiS->siscrt1satgain;
12635   UChar temp;
12636#ifdef SISDUALHEAD
12637   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12638
12639   if(pSiSEnt && pSiS->DualHeadMode)  result = pSiSEnt->siscrt1satgain;
12640#endif
12641
12642   if(!(pSiS->SiS_SD3_Flags & SiS_SD3_CRT1SATGAIN)) return result;
12643
12644#ifdef UNLOCK_ALWAYS
12645   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
12646#endif
12647   inSISIDXREG(SISCR, 0x53, temp);
12648   return (int)((temp >> 2) & 0x07);
12649}
12650
12651/* Calc dotclock from registers */
12652static int
12653SiSGetClockFromRegs(UChar sr2b, UChar sr2c)
12654{
12655   float num, denum, postscalar, divider;
12656   int   myclock;
12657
12658   divider = (sr2b & 0x80) ? 2.0 : 1.0;
12659   postscalar = (sr2c & 0x80) ?
12660              ( (((sr2c >> 5) & 0x03) == 0x02) ? 6.0 : 8.0 ) :
12661	      ( ((sr2c >> 5) & 0x03) + 1.0 );
12662   num = (sr2b & 0x7f) + 1.0;
12663   denum = (sr2c & 0x1f) + 1.0;
12664   myclock = (int)((14318 * (divider / postscalar) * (num / denum)) / 1000);
12665   return myclock;
12666}
12667
12668#ifdef SISDUALHEAD
12669static void
12670SiS_SetDHFlags(SISPtr pSiS, unsigned int misc, unsigned int sd2)
12671{
12672   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12673
12674   if(pSiS->DualHeadMode) {
12675      if(pSiSEnt->pScrn_1) {
12676	 SISPTR(pSiSEnt->pScrn_1)->MiscFlags |= misc;
12677	 SISPTR(pSiSEnt->pScrn_1)->SiS_SD2_Flags |= sd2;
12678      }
12679      if(pSiSEnt->pScrn_2) {
12680	 SISPTR(pSiSEnt->pScrn_2)->MiscFlags |= misc;
12681	 SISPTR(pSiSEnt->pScrn_2)->SiS_SD2_Flags |= sd2;
12682      }
12683   }
12684}
12685#endif
12686
12687/* PostSetMode:
12688 * -) Disable CRT1 for saving bandwidth. This doesn't work with VESA;
12689 *    VESA uses the bridge in SlaveMode and switching CRT1 off while
12690 *    the bridge is in SlaveMode not that clever...
12691 * -) Check if overlay can be used (depending on dotclock)
12692 * -) Check if Panel Scaler is active on LVDS for overlay re-scaling
12693 * -) Save TV registers for further processing
12694 * -) Apply TV settings
12695 */
12696static void
12697SiSPostSetMode(ScrnInfoPtr pScrn, SISRegPtr sisReg)
12698{
12699    SISPtr pSiS = SISPTR(pScrn);
12700#ifdef SISDUALHEAD
12701    SISEntPtr pSiSEnt = pSiS->entityPrivate;
12702#endif
12703    UChar usScratchCR17, sr2b, sr2c, tmpreg;
12704    int   myclock1, myclock2, mycoldepth1, mycoldepth2, temp;
12705    Bool  flag = FALSE;
12706    Bool  doit = TRUE;
12707    Bool  IsInSlaveMode;
12708
12709#ifdef TWDEBUG
12710    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
12711    	"CRT1off is %d\n", pSiS->CRT1off);
12712#endif
12713    pSiS->CRT1isoff = pSiS->CRT1off;
12714
12715#ifdef UNLOCK_ALWAYS
12716    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
12717#endif
12718
12719    SiSFixupSR11(pScrn);
12720
12721    IsInSlaveMode = SiSBridgeIsInSlaveMode(pScrn);
12722
12723    if((!pSiS->UseVESA) && (pSiS->VBFlags & CRT2_ENABLE)) {
12724
12725	if(pSiS->VBFlags != pSiS->VBFlags_backup) {
12726	   pSiS->VBFlags = pSiS->VBFlags_backup;
12727	   xf86DrvMsg(pScrn->scrnIndex, X_INFO,
12728			"VBFlags restored to %0x\n", pSiS->VBFlags);
12729	}
12730
12731	/* -) We can't switch off CRT1 if bridge is in SlaveMode.
12732	 * -) If we change to a SlaveMode-Mode (like 512x384), we
12733	 *    need to adapt VBFlags for eg. Xv.
12734	 */
12735#ifdef SISDUALHEAD
12736	if(!pSiS->DualHeadMode) {
12737#endif
12738	   if(IsInSlaveMode) {
12739	      doit = FALSE;
12740	      temp = pSiS->VBFlags;
12741	      pSiS->VBFlags &= (~VB_DISPMODE_SINGLE);
12742	      pSiS->VBFlags |= (VB_DISPMODE_MIRROR | DISPTYPE_DISP1);
12743              if(temp != pSiS->VBFlags) {
12744		 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
12745		 	"VBFlags changed to 0x%0x\n", pSiS->VBFlags);
12746	      }
12747	   }
12748#ifdef SISDUALHEAD
12749	}
12750#endif
12751
12752	if(pSiS->VGAEngine == SIS_315_VGA) {
12753
12754	   if((pSiS->CRT1off) && (doit)) {
12755	      orSISIDXREG(SISCR,pSiS->myCR63,0x40);
12756	      orSISIDXREG(SISSR,0x1f,0xc0);
12757	      andSISIDXREG(SISSR,0x07,~0x10);
12758	      andSISIDXREG(SISSR,0x06,0xe2);
12759	      andSISIDXREG(SISSR,0x31,0xcf);
12760	      outSISIDXREG(SISSR,0x2b,0x1b);
12761	      outSISIDXREG(SISSR,0x2c,0xe1);
12762	      outSISIDXREG(SISSR,0x2d,0x01);
12763	      outSISIDXREG(SISSR, 0x00, 0x01);    /* Synchronous Reset */
12764	      usleep(10000);
12765	      outSISIDXREG(SISSR, 0x00, 0x03);    /* End Reset */
12766	   } else {
12767	      andSISIDXREG(SISCR,pSiS->myCR63,0xBF);
12768	      andSISIDXREG(SISSR,0x1f,0x3f);
12769	      orSISIDXREG(SISSR,0x07,0x10);
12770	   }
12771
12772	} else {
12773
12774	   if(doit) {
12775	      inSISIDXREG(SISCR, 0x17, usScratchCR17);
12776	      if(pSiS->CRT1off) {
12777		 if(usScratchCR17 & 0x80) {
12778		    flag = TRUE;
12779		    usScratchCR17 &= ~0x80;
12780		 }
12781		 orSISIDXREG(SISSR,0x1f,0xc0);
12782	      } else {
12783		 if(!(usScratchCR17 & 0x80)) {
12784		    flag = TRUE;
12785		    usScratchCR17 |= 0x80;
12786		 }
12787		 andSISIDXREG(SISSR,0x1f,0x3f);
12788	      }
12789	      /* Reset only if status changed */
12790	      if(flag) {
12791		 outSISIDXREG(SISCR, 0x17, usScratchCR17);
12792		 outSISIDXREG(SISSR, 0x00, 0x01);    /* Synchronous Reset */
12793		 usleep(10000);
12794		 outSISIDXREG(SISSR, 0x00, 0x03);    /* End Reset */
12795	      }
12796	   }
12797	}
12798
12799    }
12800
12801    /* Set bridge to "disable CRT2" mode if CRT2 is disabled, LCD-A is enabled */
12802    /* (Not needed for CRT1=VGA since CRT2 will really be disabled then) */
12803#ifdef SISDUALHEAD
12804    if(!pSiS->DualHeadMode) {
12805#endif
12806       if((pSiS->VGAEngine == SIS_315_VGA)  && (pSiS->VBFlags2 & VB2_SISLCDABRIDGE)) {
12807	  if((!pSiS->UseVESA) && (!(pSiS->VBFlags & CRT2_ENABLE)) && (pSiS->VBFlags & CRT1_LCDA)) {
12808	     if(!IsInSlaveMode) {
12809	        andSISIDXREG(SISPART4,0x0d,~0x07);
12810	     }
12811	  }
12812       }
12813#ifdef SISDUALHEAD
12814    }
12815#endif
12816
12817    /* Reset flags */
12818    pSiS->MiscFlags &= ~( MISC_CRT1OVERLAY      |
12819			  MISC_CRT2OVERLAY      |
12820			  MISC_CRT1OVERLAYGAMMA |
12821			  MISC_SIS760ONEOVERLAY |
12822			  MISC_PANELLINKSCALER  |
12823			  MISC_STNMODE		|
12824			  MISC_TVNTSC1024);
12825
12826    pSiS->SiS_SD2_Flags &= ~SiS_SD2_SIS760ONEOVL;
12827
12828#ifdef SISDUALHEAD
12829    if(pSiS->DualHeadMode) {
12830       if(pSiSEnt->pScrn_1) {
12831	  SISPTR(pSiSEnt->pScrn_1)->MiscFlags &= ~(MISC_SIS760ONEOVERLAY	|
12832						   MISC_CRT1OVERLAY		|
12833						   MISC_CRT2OVERLAY		|
12834						   MISC_CRT1OVERLAYGAMMA	|
12835						   MISC_PANELLINKSCALER		|
12836						   MISC_STNMODE			|
12837						   MISC_TVNTSC1024);
12838	  SISPTR(pSiSEnt->pScrn_1)->SiS_SD2_Flags &= ~SiS_SD2_SIS760ONEOVL;
12839       }
12840       if(pSiSEnt->pScrn_2) {
12841	  SISPTR(pSiSEnt->pScrn_2)->MiscFlags &= ~(MISC_SIS760ONEOVERLAY	|
12842						   MISC_CRT1OVERLAY		|
12843						   MISC_CRT2OVERLAY		|
12844						   MISC_CRT1OVERLAYGAMMA	|
12845						   MISC_PANELLINKSCALER		|
12846						   MISC_STNMODE			|
12847						   MISC_TVNTSC1024);
12848	  SISPTR(pSiSEnt->pScrn_2)->SiS_SD2_Flags &= ~SiS_SD2_SIS760ONEOVL;
12849       }
12850    }
12851#endif
12852
12853    /* Determine if the video overlay can be used */
12854    if(!pSiS->NoXvideo) {
12855
12856       int clklimit1=0, clklimit2=0, clklimitg=0;
12857       Bool OverlayHandled = FALSE;
12858
12859       inSISIDXREG(SISSR,0x2b,sr2b);
12860       inSISIDXREG(SISSR,0x2c,sr2c);
12861       myclock1 = myclock2 = SiSGetClockFromRegs(sr2b, sr2c);
12862       inSISIDXREG(SISSR,0x06,tmpreg);
12863       switch((tmpreg & 0x1c) >> 2) {
12864       case 0:  mycoldepth1 = 1; break;
12865       case 1:
12866       case 2:  mycoldepth1 = 2; break;
12867       default: mycoldepth1 = 4;
12868       }
12869       mycoldepth2 = mycoldepth1;
12870
12871       if((!IsInSlaveMode) && (pSiS->VBFlags & CRT2_ENABLE)) {
12872	  if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
12873	     inSISIDXREG(SISPART4,0x0a,sr2b);
12874	     inSISIDXREG(SISPART4,0x0b,sr2c);
12875	  } else {
12876	     inSISIDXREG(SISSR,0x2e,sr2b);
12877	     inSISIDXREG(SISSR,0x2f,sr2c);
12878	  }
12879	  myclock2 = SiSGetClockFromRegs(sr2b, sr2c);
12880	  inSISIDXREG(SISPART1,0x00,tmpreg);
12881	  tmpreg &= 0x0f;
12882	  switch(tmpreg) {
12883	  case 8:  mycoldepth2 = 1; break;
12884	  case 4:
12885	  case 2:  mycoldepth2 = 2; break;
12886	  default: mycoldepth2 = 4;
12887	  }
12888       }
12889
12890       switch(pSiS->ChipType) {
12891
12892	 case SIS_300:
12893	 case SIS_540:
12894	 case SIS_630:
12895	 case SIS_730:
12896	    clklimit1 = clklimit2 = clklimitg = 150;
12897	    break;
12898
12899	 case SIS_550:
12900	 case SIS_650:
12901	 case SIS_740:
12902	    clklimit1 = clklimit2 = 175;  /* verified for 65x */
12903	    clklimitg = 166;		  /* ? */
12904	    break;
12905
12906	 case SIS_661:
12907	 case SIS_741:
12908	    clklimit1 = clklimit2 = 190;  /* ? */
12909	    clklimitg = 180;		  /* ? */
12910	    break;
12911
12912	 case SIS_760:
12913	 case SIS_761:
12914	    clklimit1 = clklimit2 = 190;    /* ? */
12915	    if(pSiS->ChipFlags & SiSCF_760LFB) {		/* LFB only or hybrid */
12916	       clklimit1 = clklimit2 = 220; /* ? */
12917	    }
12918	    clklimitg = 200;		    /* ? */
12919
12920	    if(pSiS->SiS_SD2_Flags & SiS_SD2_SUPPORT760OO) {	/* UMA only */
12921
12922	       Bool OnlyOne = FALSE, NoOverlay = FALSE;
12923	       int dotclocksum = 0;
12924
12925	       if(pSiS->VBFlags & DISPTYPE_CRT1)                     dotclocksum += myclock1;
12926	       if((!IsInSlaveMode) && (pSiS->VBFlags & CRT2_ENABLE)) dotclocksum += myclock2;
12927
12928	       /* TODO: Find out under what circumstances only one
12929		*	overlay is usable in UMA-only mode.
12930		*	This is not entirely accurate; the overlay
12931		*	scaler also requires some time, so even though
12932		*	the dotclocks are below these values, some
12933		*	distortions in the overlay may occure.
12934		*	Solution: Don't use a 760 with shared memory.
12935		*/
12936	       if( (pSiS->VBFlags & DISPTYPE_CRT1) &&
12937		   (pSiS->VBFlags & CRT2_ENABLE) &&
12938		   (mycoldepth1 != mycoldepth2) ) {
12939
12940		  /* 0. If coldepths are different (only possible in dual head mode),
12941		   *    I have no idea to calculate the limits; hence, allow only one
12942		   *    overlay in all cases.
12943		   */
12944		  OnlyOne = TRUE;
12945
12946	       } else if(pSiS->MemClock < 150000) {
12947
12948		  /* 1. MCLK <150: If someone seriously considers using such
12949		   *    slow RAM, so be it. Only one overlay in call cases.
12950		   */
12951		  OnlyOne = TRUE;
12952
12953	       } else if(pSiS->MemClock < 170000) {
12954
12955		  /* 2. MCLK 166 */
12956		  switch(pSiS->CurrentLayout.bitsPerPixel) {
12957		     case 32: if(dotclocksum > 133) OnlyOne = TRUE;		/* One overlay; verified */
12958			      if(dotclocksum > 180) NoOverlay = TRUE;		/* No overlay; verified */
12959			      break;
12960		     case 16: if(dotclocksum > 175) OnlyOne = TRUE;		/* One overlay; verified */
12961			      if(dotclocksum > 260) NoOverlay = TRUE;;		/* No overlay; FIXME */
12962			      break;
12963		  }
12964
12965	       } else if(pSiS->MemClock < 210000) {
12966
12967		  /* 3. MCLK 200 */
12968		  switch(pSiS->CurrentLayout.bitsPerPixel) {
12969		     case 32: if(dotclocksum > 160) OnlyOne = TRUE;		/* One overlay; FIXME */
12970			      if(dotclocksum > 216) NoOverlay = TRUE;;		/* No overlay; FIXME */
12971			      break;
12972		     case 16: if(dotclocksum > 210) OnlyOne = TRUE;		/* One overlay; FIXME */
12973			      if(dotclocksum > 312) NoOverlay = TRUE;;		/* No overlay; FIXME */
12974			      break;
12975		  }
12976
12977	       }
12978
12979	       if(OnlyOne || NoOverlay) {
12980
12981		  ULong tmpflags = 0;
12982
12983		  if(!NoOverlay) {
12984		     if(myclock1 <= clklimit1) tmpflags |= MISC_CRT1OVERLAY;
12985		     if(myclock2 <= clklimit2) tmpflags |= MISC_CRT2OVERLAY;
12986		     if(myclock1 <= clklimitg) tmpflags |= MISC_CRT1OVERLAYGAMMA;
12987		     pSiS->MiscFlags |= tmpflags;
12988		  }
12989		  pSiS->MiscFlags |= MISC_SIS760ONEOVERLAY;
12990		  pSiS->SiS_SD2_Flags |= SiS_SD2_SIS760ONEOVL;
12991#ifdef SISDUALHEAD
12992		  SiS_SetDHFlags(pSiS, (tmpflags | MISC_SIS760ONEOVERLAY), SiS_SD2_SIS760ONEOVL);
12993#endif
12994		  OverlayHandled = TRUE;
12995	       }
12996
12997	       xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
12998			"SiS76x/UMA: %s video overlay(s) available in current mode\n",
12999			NoOverlay ? "no" : ((pSiS->MiscFlags & MISC_SIS760ONEOVERLAY) ? "one" : "two"));
13000
13001#ifdef TWDEBUG
13002	       xf86DrvMsg(0, 0, "SiS760: Memclock %d, c1 %d/%d c2 %d/%d, sum %d / %x\n",
13003			pSiS->MemClock, myclock1, mycoldepth1,
13004			myclock2, mycoldepth2, dotclocksum, pSiS->SiS_SD2_Flags);
13005#endif
13006	    }
13007	    break;
13008
13009	 case SIS_660:
13010	    clklimit1 = clklimit2 = 200;  /* ? */
13011	    if(pSiS->ChipFlags & SiSCF_760LFB) {		/* LFB only */
13012	       clklimit1 = clklimit2 = 220;
13013	    }
13014	    clklimitg = 200;		  /* ? */
13015	    break;
13016
13017	 case SIS_315H:
13018	 case SIS_315:
13019	 case SIS_315PRO:
13020	 case SIS_330:
13021	    clklimit1 = clklimit2 = 180;  /* ? */
13022	    clklimitg = 166;		  /* ? */
13023	    break;
13024
13025	 case SIS_340: /* ? */
13026	 case XGI_20:
13027	 case XGI_40:
13028	    clklimit1 = clklimit2 = 240;  /* ? */
13029	    clklimitg = 200;		  /* ? */
13030	    break;
13031       }
13032
13033       if(!OverlayHandled) {
13034          ULong tmpflags = 0;
13035          if(myclock1 <= clklimit1) tmpflags |= MISC_CRT1OVERLAY;
13036          if(myclock2 <= clklimit2) tmpflags |= MISC_CRT2OVERLAY;
13037          if(myclock1 <= clklimitg) tmpflags |= MISC_CRT1OVERLAYGAMMA;
13038	  pSiS->MiscFlags |= tmpflags;
13039#ifdef SISDUALHEAD
13040	  SiS_SetDHFlags(pSiS, tmpflags, 0);
13041#endif
13042          if(!(pSiS->MiscFlags & MISC_CRT1OVERLAY)) {
13043#ifdef SISDUALHEAD
13044             if((!pSiS->DualHeadMode) || (pSiS->SecondHead))
13045#endif
13046		xf86DrvMsgVerb(pScrn->scrnIndex, X_WARNING, 3,
13047		   "Current dotclock (%dMhz) too high for video overlay on CRT1\n",
13048		   myclock1);
13049          }
13050          if((pSiS->VBFlags & CRT2_ENABLE) && (!(pSiS->MiscFlags & MISC_CRT2OVERLAY))) {
13051#ifdef SISDUALHEAD
13052	     if((!pSiS->DualHeadMode) || (!pSiS->SecondHead))
13053#endif
13054		xf86DrvMsgVerb(pScrn->scrnIndex, X_WARNING, 3,
13055		   "Current dotclock (%dMhz) too high for video overlay on CRT2\n",
13056		   myclock2);
13057	  }
13058       }
13059
13060    }
13061
13062    /* Determine if the Panel Link scaler is active */
13063
13064    if(pSiS->VBFlags & (CRT2_LCD | CRT1_LCDA)) {
13065       ULong tmpflags = 0;
13066       if(pSiS->VGAEngine == SIS_300_VGA) {
13067	  if(pSiS->VBFlags2 & (VB2_LVDS | VB2_30xBDH)) {
13068	     inSISIDXREG(SISPART1,0x1e,tmpreg);
13069	     tmpreg &= 0x3f;
13070	     if(tmpreg) tmpflags |= MISC_PANELLINKSCALER;
13071	  }
13072       } else {
13073	  if((pSiS->VBFlags2 & (VB2_LVDS | VB2_30xBDH)) || (pSiS->VBFlags & CRT1_LCDA)) {
13074	     inSISIDXREG(SISPART1,0x35,tmpreg);
13075	     tmpreg &= 0x04;
13076	     if(!tmpreg)  tmpflags |= MISC_PANELLINKSCALER;
13077	  }
13078       }
13079       pSiS->MiscFlags |= tmpflags;
13080#ifdef SISDUALHEAD
13081       SiS_SetDHFlags(pSiS, tmpflags, 0);
13082#endif
13083    }
13084
13085    /* Determine if STN is active */
13086    if(pSiS->ChipType == SIS_550) {
13087       if((pSiS->VBFlags & CRT2_LCD) && (pSiS->FSTN || pSiS->DSTN)) {
13088	  inSISIDXREG(SISCR,0x34,tmpreg);
13089	  tmpreg &= 0x7f;
13090	  if(tmpreg == 0x5a || tmpreg == 0x5b) {
13091	     pSiS->MiscFlags |= MISC_STNMODE;
13092#ifdef SISDUALHEAD
13093	     SiS_SetDHFlags(pSiS, MISC_STNMODE, 0);
13094#endif
13095	  }
13096       }
13097    }
13098
13099    /* Determine if our very special TV mode is active */
13100    if((pSiS->VBFlags2 & VB2_SISBRIDGE) && (pSiS->VBFlags & CRT2_TV) && (!(pSiS->VBFlags & TV_HIVISION))) {
13101       if( ((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR525I)) ||
13102	   ((!(pSiS->VBFlags & TV_YPBPR)) && (pSiS->VBFlags & (TV_NTSC | TV_PALM))) ) {
13103	  inSISIDXREG(SISCR,0x34,tmpreg);
13104	  tmpreg &= 0x7f;
13105	  if((tmpreg == 0x64) || (tmpreg == 0x4a) || (tmpreg == 0x38)) {
13106	     pSiS->MiscFlags |= MISC_TVNTSC1024;
13107#ifdef SISDUALHEAD
13108	     SiS_SetDHFlags(pSiS, MISC_TVNTSC1024, 0);
13109#endif
13110	  }
13111       }
13112    }
13113
13114    if(pSiS->VGAEngine == SIS_315_VGA) {
13115       int i;
13116#ifdef SISVRAMQ
13117       /* Re-Enable and reset command queue */
13118       SiSEnableTurboQueue(pScrn);
13119#endif
13120       /* Get HWCursor register contents for backup */
13121       for(i = 0; i < 16; i++) {
13122          pSiS->HWCursorBackup[i] = SIS_MMIO_IN32(pSiS->IOBase, 0x8500 + (i << 2));
13123       }
13124       if(pSiS->ChipType >= SIS_330) {
13125          /* Enable HWCursor protection (Y pos as trigger) */
13126          andSISIDXREG(SISCR, 0x5b, ~0x30);
13127       }
13128    }
13129
13130    /* Re-initialize accelerator engine */
13131    /* (We are sync'ed here) */
13132    if(!pSiS->NoAccel) {
13133       if(pSiS->InitAccel) {
13134          (pSiS->InitAccel)(pScrn);
13135       }
13136    }
13137
13138    /* Set display device gamma (for SISCTRL) */
13139    if(pSiS->VBFlags & CRT1_LCDA)
13140       pSiS->CRT1MonGamma = pSiS->CRT2LCDMonitorGamma;
13141    else
13142       pSiS->CRT1MonGamma = pSiS->CRT1VGAMonitorGamma;
13143
13144    if(pSiS->VBFlags & CRT2_LCD)
13145       pSiS->CRT2MonGamma = pSiS->CRT2LCDMonitorGamma;
13146    else if(pSiS->VBFlags & CRT2_TV) {
13147       if(pSiS->VBFlags & TV_YPBPR)
13148          pSiS->CRT2MonGamma = 2200; /* */
13149       else if(pSiS->VBFlags & TV_HIVISION)
13150          pSiS->CRT2MonGamma = 2200; /* ? */
13151       else if(pSiS->VBFlags & TV_NTSC)
13152          pSiS->CRT2MonGamma = 2200; /* NTSC */
13153       else
13154          pSiS->CRT2MonGamma = 2800; /* All PAL modes? */
13155    } else if(pSiS->VBFlags & CRT2_VGA)
13156       pSiS->CRT2MonGamma = pSiS->CRT2VGAMonitorGamma;
13157    else
13158       pSiS->CRT2MonGamma = 0; /* Unknown */
13159
13160    /* Reset XV display properties (such as number of overlays, etc) */
13161    /* (And copy monitor gamma) */
13162#ifdef SISDUALHEAD
13163    if(pSiS->DualHeadMode) {
13164       if(pSiSEnt->pScrn_1) {
13165	  if(SISPTR(pSiSEnt->pScrn_1)->ResetXvDisplay) {
13166	     (SISPTR(pSiSEnt->pScrn_1)->ResetXvDisplay)(pSiSEnt->pScrn_1);
13167	  }
13168	  SISPTR(pSiSEnt->pScrn_1)->CRT1MonGamma = pSiS->CRT1MonGamma;
13169	  SISPTR(pSiSEnt->pScrn_1)->CRT2MonGamma = pSiS->CRT2MonGamma;
13170       }
13171       if(pSiSEnt->pScrn_2) {
13172	  if(SISPTR(pSiSEnt->pScrn_2)->ResetXvDisplay) {
13173	     (SISPTR(pSiSEnt->pScrn_1)->ResetXvDisplay)(pSiSEnt->pScrn_2);
13174	  }
13175	  SISPTR(pSiSEnt->pScrn_2)->CRT1MonGamma = pSiS->CRT1MonGamma;
13176	  SISPTR(pSiSEnt->pScrn_2)->CRT2MonGamma = pSiS->CRT2MonGamma;
13177       }
13178    } else {
13179#endif
13180       if(pSiS->ResetXvDisplay) {
13181	  (pSiS->ResetXvDisplay)(pScrn);
13182       }
13183#ifdef SISDUALHEAD
13184    }
13185#endif
13186
13187    /* Reset XV gamma correction */
13188    if(pSiS->ResetXvGamma) {
13189       (pSiS->ResetXvGamma)(pScrn);
13190    }
13191
13192    /* Reset various display parameters */
13193    {
13194       int val = pSiS->siscrt1satgain;
13195#ifdef SISDUALHEAD
13196       if(pSiS->DualHeadMode && pSiSEnt) val = pSiSEnt->siscrt1satgain;
13197#endif
13198       SiS_SetSISCRT1SaturationGain(pScrn, val);
13199    }
13200
13201    /*  Apply TV settings given by options
13202           Do this even in DualHeadMode:
13203	   - if this is called by SetModeCRT1, CRT2 mode has been reset by SetModeCRT1
13204	   - if this is called by SetModeCRT2, CRT2 mode has changed (duh!)
13205	   -> Hence, in both cases, the settings must be re-applied.
13206     */
13207
13208    if(pSiS->VBFlags & CRT2_TV) {
13209       int val;
13210       if(pSiS->VBFlags2 & VB2_CHRONTEL) {
13211	  int mychtvlumabandwidthcvbs = pSiS->chtvlumabandwidthcvbs;
13212	  int mychtvlumabandwidthsvideo = pSiS->chtvlumabandwidthsvideo;
13213	  int mychtvlumaflickerfilter = pSiS->chtvlumaflickerfilter;
13214	  int mychtvchromabandwidth = pSiS->chtvchromabandwidth;
13215	  int mychtvchromaflickerfilter = pSiS->chtvchromaflickerfilter;
13216	  int mychtvcvbscolor = pSiS->chtvcvbscolor;
13217	  int mychtvtextenhance = pSiS->chtvtextenhance;
13218	  int mychtvcontrast = pSiS->chtvcontrast;
13219	  int mytvxpos = pSiS->tvxpos;
13220	  int mytvypos = pSiS->tvypos;
13221#ifdef SISDUALHEAD
13222	  if(pSiSEnt && pSiS->DualHeadMode) {
13223	     mychtvlumabandwidthcvbs = pSiSEnt->chtvlumabandwidthcvbs;
13224	     mychtvlumabandwidthsvideo = pSiSEnt->chtvlumabandwidthsvideo;
13225	     mychtvlumaflickerfilter = pSiSEnt->chtvlumaflickerfilter;
13226	     mychtvchromabandwidth = pSiSEnt->chtvchromabandwidth;
13227	     mychtvchromaflickerfilter = pSiSEnt->chtvchromaflickerfilter;
13228	     mychtvcvbscolor = pSiSEnt->chtvcvbscolor;
13229	     mychtvtextenhance = pSiSEnt->chtvtextenhance;
13230	     mychtvcontrast = pSiSEnt->chtvcontrast;
13231	     mytvxpos = pSiSEnt->tvxpos;
13232	     mytvypos = pSiSEnt->tvypos;
13233	  }
13234#endif
13235	  if((val = mychtvlumabandwidthcvbs) != -1) {
13236	     SiS_SetCHTVlumabandwidthcvbs(pScrn, val);
13237	  }
13238	  if((val = mychtvlumabandwidthsvideo) != -1) {
13239	     SiS_SetCHTVlumabandwidthsvideo(pScrn, val);
13240	  }
13241	  if((val = mychtvlumaflickerfilter) != -1) {
13242	     SiS_SetCHTVlumaflickerfilter(pScrn, val);
13243	  }
13244	  if((val = mychtvchromabandwidth) != -1) {
13245	     SiS_SetCHTVchromabandwidth(pScrn, val);
13246	  }
13247	  if((val = mychtvchromaflickerfilter) != -1) {
13248	     SiS_SetCHTVchromaflickerfilter(pScrn, val);
13249	  }
13250	  if((val = mychtvcvbscolor) != -1) {
13251	     SiS_SetCHTVcvbscolor(pScrn, val);
13252	  }
13253	  if((val = mychtvtextenhance) != -1) {
13254	     SiS_SetCHTVtextenhance(pScrn, val);
13255	  }
13256	  if((val = mychtvcontrast) != -1) {
13257	     SiS_SetCHTVcontrast(pScrn, val);
13258	  }
13259	  /* Backup default TV position registers */
13260	  switch(pSiS->ChrontelType) {
13261	  case CHRONTEL_700x:
13262	     pSiS->tvx = SiS_GetCH700x(pSiS->SiS_Pr, 0x0a);
13263	     pSiS->tvx |= (((SiS_GetCH700x(pSiS->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
13264	     pSiS->tvy = SiS_GetCH700x(pSiS->SiS_Pr, 0x0b);
13265	     pSiS->tvy |= ((SiS_GetCH700x(pSiS->SiS_Pr, 0x08) & 0x01) << 8);
13266#ifdef SISDUALHEAD
13267	     if(pSiSEnt) {
13268		pSiSEnt->tvx = pSiS->tvx;
13269		pSiSEnt->tvy = pSiS->tvy;
13270	     }
13271#endif
13272	     break;
13273	  case CHRONTEL_701x:
13274	     /* Not supported by hardware */
13275	     break;
13276	  }
13277	  if((val = mytvxpos) != 0) {
13278	     SiS_SetTVxposoffset(pScrn, val);
13279	  }
13280	  if((val = mytvypos) != 0) {
13281	     SiS_SetTVyposoffset(pScrn, val);
13282	  }
13283       }
13284       if(pSiS->VBFlags2 & VB2_301) {
13285          int mysistvedgeenhance = pSiS->sistvedgeenhance;
13286#ifdef SISDUALHEAD
13287          if(pSiSEnt && pSiS->DualHeadMode) {
13288	     mysistvedgeenhance = pSiSEnt->sistvedgeenhance;
13289	  }
13290#endif
13291          if((val = mysistvedgeenhance) != -1) {
13292	     SiS_SetSISTVedgeenhance(pScrn, val);
13293	  }
13294       }
13295       if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
13296          int mysistvantiflicker = pSiS->sistvantiflicker;
13297	  int mysistvsaturation = pSiS->sistvsaturation;
13298	  int mysistvcolcalibf = pSiS->sistvcolcalibf;
13299	  int mysistvcolcalibc = pSiS->sistvcolcalibc;
13300	  int mysistvcfilter = pSiS->sistvcfilter;
13301	  int mysistvyfilter = pSiS->sistvyfilter;
13302	  int mytvxpos = pSiS->tvxpos;
13303	  int mytvypos = pSiS->tvypos;
13304	  int mytvxscale = pSiS->tvxscale;
13305	  int mytvyscale = pSiS->tvyscale;
13306	  int i;
13307	  ULong cbase;
13308	  UChar ctemp;
13309#ifdef SISDUALHEAD
13310          if(pSiSEnt && pSiS->DualHeadMode) {
13311	     mysistvantiflicker = pSiSEnt->sistvantiflicker;
13312	     mysistvsaturation = pSiSEnt->sistvsaturation;
13313	     mysistvcolcalibf = pSiSEnt->sistvcolcalibf;
13314	     mysistvcolcalibc = pSiSEnt->sistvcolcalibc;
13315	     mysistvcfilter = pSiSEnt->sistvcfilter;
13316	     mysistvyfilter = pSiSEnt->sistvyfilter;
13317	     mytvxpos = pSiSEnt->tvxpos;
13318	     mytvypos = pSiSEnt->tvypos;
13319	     mytvxscale = pSiSEnt->tvxscale;
13320	     mytvyscale = pSiSEnt->tvyscale;
13321	  }
13322#endif
13323          /* Backup default TV position, scale and colcalib registers */
13324	  inSISIDXREG(SISPART2,0x1f,pSiS->p2_1f);
13325	  inSISIDXREG(SISPART2,0x20,pSiS->p2_20);
13326	  inSISIDXREG(SISPART2,0x2b,pSiS->p2_2b);
13327	  inSISIDXREG(SISPART2,0x42,pSiS->p2_42);
13328	  inSISIDXREG(SISPART2,0x43,pSiS->p2_43);
13329	  inSISIDXREG(SISPART2,0x01,pSiS->p2_01);
13330	  inSISIDXREG(SISPART2,0x02,pSiS->p2_02);
13331	  inSISIDXREG(SISPART2,0x44,pSiS->p2_44);
13332	  inSISIDXREG(SISPART2,0x45,pSiS->p2_45);
13333	  if(!(pSiS->VBFlags2 & VB2_301)) {
13334	     inSISIDXREG(SISPART2,0x46,pSiS->p2_46);
13335	  } else {
13336	     pSiS->p2_46 = 0;
13337	  }
13338	  inSISIDXREG(SISPART2,0x0a,pSiS->p2_0a);
13339	  inSISIDXREG(SISPART2,0x31,cbase);
13340	  cbase = (cbase & 0x7f) << 8;
13341	  inSISIDXREG(SISPART2,0x32,ctemp);
13342	  cbase = (cbase | ctemp) << 8;
13343	  inSISIDXREG(SISPART2,0x33,ctemp);
13344	  cbase = (cbase | ctemp) << 8;
13345	  inSISIDXREG(SISPART2,0x34,ctemp);
13346	  pSiS->sistvccbase = (cbase | ctemp);
13347	  inSISIDXREG(SISPART2,0x35,pSiS->p2_35);
13348	  inSISIDXREG(SISPART2,0x36,pSiS->p2_36);
13349	  inSISIDXREG(SISPART2,0x37,pSiS->p2_37);
13350	  inSISIDXREG(SISPART2,0x38,pSiS->p2_38);
13351	  if(!(pSiS->VBFlags2 & VB2_301)) {
13352	     inSISIDXREG(SISPART2,0x47,pSiS->p2_47);
13353	     inSISIDXREG(SISPART2,0x48,pSiS->p2_48);
13354	     inSISIDXREG(SISPART2,0x49,pSiS->p2_49);
13355	     inSISIDXREG(SISPART2,0x4a,pSiS->p2_4a);
13356	  }
13357	  inSISIDXREG(SISPART2,0x2f,pSiS->p2_2f);
13358	  inSISIDXREG(SISPART2,0x30,pSiS->p2_30);
13359	  for(i=0; i<9; i++) {
13360	     inSISIDXREG(SISPART1,SiSScalingP1Regs[i],pSiS->scalingp1[i]);
13361	  }
13362	  for(i=0; i<9; i++) {
13363	     inSISIDXREG(SISPART4,SiSScalingP4Regs[i],pSiS->scalingp4[i]);
13364	  }
13365	  if(pSiS->VBFlags2 & VB2_SISTAP4SCALER) {
13366	     for(i=0; i<64; i++) {
13367	        inSISIDXREG(SISPART2,(0xc0 + i),pSiS->scalingp2[i]);
13368  	     }
13369	  }
13370#ifdef SISDUALHEAD
13371	  if(pSiSEnt) {
13372	     pSiSEnt->p2_1f = pSiS->p2_1f; pSiSEnt->p2_20 = pSiS->p2_20;
13373	     pSiSEnt->p2_42 = pSiS->p2_42; pSiSEnt->p2_43 = pSiS->p2_43;
13374	     pSiSEnt->p2_2b = pSiS->p2_2b;
13375	     pSiSEnt->p2_01 = pSiS->p2_01; pSiSEnt->p2_02 = pSiS->p2_02;
13376	     pSiSEnt->p2_44 = pSiS->p2_44; pSiSEnt->p2_45 = pSiS->p2_45;
13377	     pSiSEnt->p2_46 = pSiS->p2_46; pSiSEnt->p2_0a = pSiS->p2_0a;
13378	     pSiSEnt->sistvccbase = pSiS->sistvccbase;
13379	     pSiSEnt->p2_35 = pSiS->p2_35; pSiSEnt->p2_36 = pSiS->p2_36;
13380	     pSiSEnt->p2_37 = pSiS->p2_37; pSiSEnt->p2_38 = pSiS->p2_38;
13381	     pSiSEnt->p2_48 = pSiS->p2_48; pSiSEnt->p2_49 = pSiS->p2_49;
13382	     pSiSEnt->p2_4a = pSiS->p2_4a; pSiSEnt->p2_2f = pSiS->p2_2f;
13383	     pSiSEnt->p2_30 = pSiS->p2_30; pSiSEnt->p2_47 = pSiS->p2_47;
13384	     for(i=0; i<9; i++) {
13385	        pSiSEnt->scalingp1[i] = pSiS->scalingp1[i];
13386	     }
13387	     for(i=0; i<9; i++) {
13388	        pSiSEnt->scalingp4[i] = pSiS->scalingp4[i];
13389	     }
13390	     if(pSiS->VBFlags2 & VB2_SISTAP4SCALER) {
13391	        for(i=0; i<64; i++) {
13392	           pSiSEnt->scalingp2[i] = pSiS->scalingp2[i];
13393  	        }
13394	     }
13395	  }
13396#endif
13397          if((val = mysistvantiflicker) != -1) {
13398	     SiS_SetSISTVantiflicker(pScrn, val);
13399	  }
13400	  if((val = mysistvsaturation) != -1) {
13401	     SiS_SetSISTVsaturation(pScrn, val);
13402	  }
13403	  if((val = mysistvcfilter) != -1) {
13404	     SiS_SetSISTVcfilter(pScrn, val);
13405	  }
13406	  if((val = mysistvyfilter) != 1) {
13407	     SiS_SetSISTVyfilter(pScrn, val);
13408	  }
13409	  if((val = mysistvcolcalibc) != 0) {
13410	     SiS_SetSISTVcolcalib(pScrn, val, TRUE);
13411	  }
13412	  if((val = mysistvcolcalibf) != 0) {
13413	     SiS_SetSISTVcolcalib(pScrn, val, FALSE);
13414	  }
13415	  if((val = mytvxpos) != 0) {
13416	     SiS_SetTVxposoffset(pScrn, val);
13417	  }
13418	  if((val = mytvypos) != 0) {
13419	     SiS_SetTVyposoffset(pScrn, val);
13420	  }
13421	  if((val = mytvxscale) != 0) {
13422	     SiS_SetTVxscale(pScrn, val);
13423	  }
13424	  if((val = mytvyscale) != 0) {
13425	     SiS_SetTVyscale(pScrn, val);
13426	  }
13427       }
13428    }
13429
13430}
13431
13432/* Post-set SiS6326 TV registers */
13433static void
13434SiS6326PostSetMode(ScrnInfoPtr pScrn, SISRegPtr sisReg)
13435{
13436    SISPtr pSiS = SISPTR(pScrn);
13437    UChar tmp;
13438    int val;
13439
13440    if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) return;
13441
13442#ifdef UNLOCK_ALWAYS
13443    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
13444#endif
13445
13446    /* Backup default TV position registers */
13447    pSiS->tvx1 = SiS6326GetTVReg(pScrn,0x3a);
13448    pSiS->tvx1 |= ((SiS6326GetTVReg(pScrn,0x3c) & 0x0f) << 8);
13449    pSiS->tvx2 = SiS6326GetTVReg(pScrn,0x26);
13450    pSiS->tvx2 |= ((SiS6326GetTVReg(pScrn,0x27) & 0xf0) << 4);
13451    pSiS->tvx3 = SiS6326GetTVReg(pScrn,0x12);
13452    pSiS->tvx3 |= ((SiS6326GetTVReg(pScrn,0x13) & 0xC0) << 2);
13453    pSiS->tvy1 = SiS6326GetTVReg(pScrn,0x11);
13454    pSiS->tvy1 |= ((SiS6326GetTVReg(pScrn,0x13) & 0x30) << 4);
13455
13456    /* Handle TVPosOffset options (BEFORE switching on TV) */
13457    if((val = pSiS->tvxpos) != 0) {
13458       SiS_SetTVxposoffset(pScrn, val);
13459    }
13460    if((val = pSiS->tvypos) != 0) {
13461       SiS_SetTVyposoffset(pScrn, val);
13462    }
13463
13464    /* Switch on TV output. This is rather complicated, but
13465     * if we don't do it, TV output will flicker terribly.
13466     */
13467    if(pSiS->SiS6326Flags & SIS6326_TVON) {
13468       orSISIDXREG(SISSR, 0x01, 0x20);
13469       tmp = SiS6326GetTVReg(pScrn,0x00);
13470       tmp &= ~0x04;
13471       while(!(inSISREG(SISINPSTAT) & 0x08));    /* Wait while NOT vb */
13472       SiS6326SetTVReg(pScrn,0x00,tmp);
13473       for(val=0; val < 2; val++) {
13474         while(!(inSISREG(SISINPSTAT) & 0x08));  /* Wait while NOT vb */
13475         while(inSISREG(SISINPSTAT) & 0x08);     /* wait while vb     */
13476       }
13477       SiS6326SetTVReg(pScrn, 0x00, sisReg->sis6326tv[0]);
13478       tmp = inSISREG(SISINPSTAT);
13479       outSISREG(SISAR, 0x20);
13480       tmp = inSISREG(SISINPSTAT);
13481       while(inSISREG(SISINPSTAT) & 0x01);
13482       while(!(inSISREG(SISINPSTAT) & 0x01));
13483       andSISIDXREG(SISSR, 0x01, ~0x20);
13484       for(val=0; val < 10; val++) {
13485         while(!(inSISREG(SISINPSTAT) & 0x08));  /* Wait while NOT vb */
13486         while(inSISREG(SISINPSTAT) & 0x08);     /* wait while vb     */
13487       }
13488       andSISIDXREG(SISSR, 0x01, ~0x20);
13489    }
13490
13491    tmp = SiS6326GetTVReg(pScrn,0x00);
13492    if(!(tmp & 0x04)) return;
13493
13494    /* Apply TV settings given by options */
13495    if((val = pSiS->sistvantiflicker) != -1) {
13496       SiS_SetSIS6326TVantiflicker(pScrn, val);
13497    }
13498    if((val = pSiS->sis6326enableyfilter) != -1) {
13499       SiS_SetSIS6326TVenableyfilter(pScrn, val);
13500    }
13501    if((val = pSiS->sis6326yfilterstrong) != -1) {
13502       SiS_SetSIS6326TVyfilterstrong(pScrn, val);
13503    }
13504
13505}
13506
13507/* Check if video bridge is in slave mode */
13508Bool
13509SiSBridgeIsInSlaveMode(ScrnInfoPtr pScrn)
13510{
13511    SISPtr pSiS = SISPTR(pScrn);
13512    UChar  usScrP1_00;
13513
13514    if(!(pSiS->VBFlags2 & VB2_VIDEOBRIDGE)) return FALSE;
13515
13516    inSISIDXREG(SISPART1,0x00,usScrP1_00);
13517    if( ((pSiS->VGAEngine == SIS_300_VGA) && (usScrP1_00 & 0xa0) == 0x20) ||
13518        ((pSiS->VGAEngine == SIS_315_VGA) && (usScrP1_00 & 0x50) == 0x10) ) {
13519       return TRUE;
13520    }
13521
13522    return FALSE;
13523}
13524
13525/* Build a list of the VESA modes the BIOS reports as valid */
13526static void
13527SiSBuildVesaModeList(ScrnInfoPtr pScrn, vbeInfoPtr pVbe, VbeInfoBlock *vbe)
13528{
13529    SISPtr pSiS = SISPTR(pScrn);
13530    int i = 0;
13531
13532    while(vbe->VideoModePtr[i] != 0xffff) {
13533       sisModeInfoPtr m;
13534       VbeModeInfoBlock *mode;
13535       int id = vbe->VideoModePtr[i++];
13536
13537       if((mode = VBEGetModeInfo(pVbe, id)) == NULL) {
13538	  continue;
13539       }
13540
13541       m = xnfcalloc(sizeof(sisModeInfoRec), 1);
13542       if(!m) {
13543	  VBEFreeModeInfo(mode);
13544	  continue;
13545       }
13546       m->width = mode->XResolution;
13547       m->height = mode->YResolution;
13548       m->bpp = mode->BitsPerPixel;
13549       m->n = id;
13550       m->next = pSiS->SISVESAModeList;
13551
13552       pSiS->SISVESAModeList = m;
13553
13554       VBEFreeModeInfo(mode);
13555
13556       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
13557	   "VESA BIOS supports mode number 0x%x: %ix%i (%i bpp)\n",
13558	   m->n, m->width, m->height, m->bpp);
13559    }
13560}
13561
13562/* Get VESA mode number from given resolution/depth */
13563static UShort
13564SiSCalcVESAModeIndex(ScrnInfoPtr pScrn, DisplayModePtr mode)
13565{
13566    SISPtr pSiS = SISPTR(pScrn);
13567    sisModeInfoPtr m = pSiS->SISVESAModeList;
13568    UShort i = (pScrn->bitsPerPixel+7)/8 - 1;
13569    UShort ModeNumber = 0;
13570    int j;
13571
13572    while(m) {
13573       if( (pScrn->bitsPerPixel == m->bpp) &&
13574	   (mode->HDisplay == m->width)    &&
13575	   (mode->VDisplay == m->height) )
13576	  return m->n;
13577       m = m->next;
13578    }
13579
13580    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
13581        "No valid VESA BIOS mode found for %dx%d (%d bpp)\n",
13582        mode->HDisplay, mode->VDisplay, pScrn->bitsPerPixel);
13583
13584    if(!pSiS->ROM661New) {  /* VESA numbers changed! */
13585       j = 0;
13586       while(VESAModeIndices[j] != 9999) {
13587          if( (mode->HDisplay == VESAModeIndices[j]) &&
13588	      (mode->VDisplay == VESAModeIndices[j+1]) ) {
13589	     ModeNumber = VESAModeIndices[j + 2 + i];
13590	     break;
13591          }
13592          j += 6;
13593       }
13594
13595       if(!ModeNumber) {
13596	  xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
13597	      "No valid mode found for %dx%dx%d in built-in table either.\n",
13598	      mode->HDisplay, mode->VDisplay, pScrn->bitsPerPixel);
13599       }
13600    }
13601
13602    return(ModeNumber);
13603}
13604
13605UShort
13606SiS_GetModeNumber(ScrnInfoPtr pScrn, DisplayModePtr mode, unsigned int VBFlags)
13607{
13608   SISPtr pSiS = SISPTR(pScrn);
13609   UShort i = (pSiS->CurrentLayout.bitsPerPixel+7)/8 - 1;
13610   BOOLEAN FSTN = pSiS->FSTN ? TRUE : FALSE;
13611
13612#ifdef SISDUALHEAD
13613   if(pSiS->DualHeadMode && pSiS->SecondHead) FSTN = FALSE;
13614#endif
13615
13616   return(SiS_GetModeID(pSiS->VGAEngine, VBFlags, mode->HDisplay, mode->VDisplay,
13617			i, FSTN, pSiS->LCDwidth, pSiS->LCDheight));
13618}
13619
13620static Bool
13621SiSValidLCDUserMode(SISPtr pSiS, unsigned int VBFlags, DisplayModePtr mode, Bool isforlcda)
13622{
13623   if(mode->Flags & V_INTERLACE) return FALSE;
13624
13625   if(mode->HDisplay > 2048) return FALSE;
13626   if(mode->VDisplay > 1536) return FALSE;
13627
13628   if(pSiS->VBFlags2 & VB2_LCD162MHZBRIDGE) {
13629      if(mode->Clock > 162500) return FALSE;
13630#ifdef VB_FORBID_CRT2LCD_OVER_1600
13631      if(!isforlcda) {
13632         if(mode->HDisplay > 1600) return FALSE;
13633      }
13634#endif
13635   } else { /* 301, 301B, 302B (no LCDA!) */
13636      if(mode->Clock > 130000)  return FALSE;
13637      if(mode->Clock > 111000) {
13638         xf86DrvMsg(pSiS->pScrn->scrnIndex, X_WARNING,
13639	 	"WARNING: Mode clock beyond video bridge specs (%dMHz). Hardware damage might occure.\n",
13640		mode->Clock / 1000);
13641      }
13642      if(mode->HDisplay > 1600) return FALSE;
13643      if(mode->VDisplay > 1024) return FALSE;
13644   }
13645
13646   return TRUE;
13647}
13648
13649static Bool
13650SiSValidVGA2UserMode(SISPtr pSiS, unsigned int VBFlags, DisplayModePtr mode)
13651{
13652   if(mode->Flags & V_INTERLACE) return FALSE;
13653
13654   if(mode->HDisplay > 2048) return FALSE;
13655   if(mode->VDisplay > 1536) return FALSE;
13656
13657   if(pSiS->VBFlags2 & VB2_RAMDAC202MHZBRIDGE) {
13658      if(mode->Clock > 203000) return FALSE;
13659   } else if(pSiS->VBFlags2 & VB2_30xBLV) {
13660      if(mode->Clock > 162500) return FALSE;
13661   } else {
13662      if(mode->Clock > 135500) return FALSE;
13663   }
13664
13665   return TRUE;
13666}
13667
13668UShort
13669SiS_CheckModeCRT1(ScrnInfoPtr pScrn, DisplayModePtr mode, unsigned int VBFlags, Bool havecustommodes)
13670{
13671   SISPtr pSiS = SISPTR(pScrn);
13672   UShort i = (pSiS->CurrentLayout.bitsPerPixel+7)/8 - 1;
13673   int j;
13674
13675   if(!(VBFlags & CRT1_LCDA)) {
13676
13677      if((havecustommodes) && (!(mode->type & M_T_DEFAULT))) {
13678         return 0xfe;
13679      }
13680
13681   } else if(pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE) {
13682
13683      if(pSiS->ChipType < SIS_661) {  /* < 661 only? */
13684         if(!(mode->type & M_T_DEFAULT)) {
13685            if(mode->HTotal > 2055) return 0;
13686	    /* (Default mode will be caught in mode switching code) */
13687	 }
13688      }
13689
13690      if(pSiS->SiS_Pr->CP_HaveCustomData) {
13691         for(j=0; j<7; j++) {
13692            if((pSiS->SiS_Pr->CP_DataValid[j]) &&
13693               (mode->HDisplay == pSiS->SiS_Pr->CP_HDisplay[j]) &&
13694               (mode->VDisplay == pSiS->SiS_Pr->CP_VDisplay[j]) &&
13695               (mode->type & M_T_BUILTIN))
13696               return 0xfe;
13697	 }
13698      }
13699
13700      if((pSiS->AddedPlasmaModes) && (mode->type & M_T_BUILTIN))
13701         return 0xfe;
13702
13703      if((havecustommodes) &&
13704         (pSiS->LCDwidth)  &&	/* = test if LCD present */
13705         (!(mode->type & M_T_DEFAULT)) &&
13706	 (SiSValidLCDUserMode(pSiS, VBFlags, mode, TRUE)))
13707         return 0xfe;
13708
13709      if((mode->HDisplay > pSiS->LCDwidth) ||
13710         (mode->VDisplay > pSiS->LCDheight)) {
13711	 return 0;
13712      }
13713
13714   } else {
13715
13716      if((mode->HDisplay > pSiS->LCDwidth) ||
13717         (mode->VDisplay > pSiS->LCDheight)) {
13718	 return 0;
13719      }
13720
13721   }
13722
13723   return(SiS_GetModeID(pSiS->VGAEngine, VBFlags, mode->HDisplay, mode->VDisplay,
13724   			i, pSiS->FSTN, pSiS->LCDwidth, pSiS->LCDheight));
13725}
13726
13727UShort
13728SiS_CheckModeCRT2(ScrnInfoPtr pScrn, DisplayModePtr mode, unsigned int VBFlags, Bool havecustommodes)
13729{
13730   SISPtr pSiS = SISPTR(pScrn);
13731   UShort i = (pSiS->CurrentLayout.bitsPerPixel+7)/8 - 1;
13732   UShort ModeIndex = 0;
13733   int    j;
13734
13735#ifdef TWDEBUG
13736   xf86DrvMsg(0, X_INFO, "Inside CheckCalcModeIndex (VBFlags %lx, mode %dx%d)\n",
13737	VBFlags,mode->HDisplay, mode->VDisplay);
13738#endif
13739
13740   if(VBFlags & CRT2_LCD) {			/* CRT2 is LCD */
13741
13742      if((pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) && (!(pSiS->VBFlags2 & VB2_30xBDH))) {
13743
13744         if(pSiS->SiS_Pr->CP_HaveCustomData) {
13745            for(j=0; j<7; j++) {
13746               if((pSiS->SiS_Pr->CP_DataValid[j]) &&
13747                  (mode->HDisplay == pSiS->SiS_Pr->CP_HDisplay[j]) &&
13748                  (mode->VDisplay == pSiS->SiS_Pr->CP_VDisplay[j]) &&
13749#ifdef VB_FORBID_CRT2LCD_OVER_1600
13750		  (mode->HDisplay <= 1600) 			   &&
13751#endif
13752                  (mode->type & M_T_BUILTIN))
13753                  return 0xfe;
13754	    }
13755         }
13756
13757	 /* All plasma modes have HDisplay <= 1600 */
13758         if((pSiS->AddedPlasmaModes) && (mode->type & M_T_BUILTIN))
13759            return 0xfe;
13760
13761         if((havecustommodes) &&
13762            (pSiS->LCDwidth)  &&	/* = test if LCD present */
13763	    (!(mode->type & M_T_DEFAULT)) &&
13764	    (SiSValidLCDUserMode(pSiS, VBFlags, mode, FALSE)))
13765            return 0xfe;
13766
13767      }
13768
13769      if( ((mode->HDisplay <= pSiS->LCDwidth) &&
13770           (mode->VDisplay <= pSiS->LCDheight)) ||
13771	  ((pSiS->SiS_Pr->SiS_CustomT == CUT_PANEL848) &&
13772	   (((mode->HDisplay == 1360) && (mode->VDisplay == 768)) ||
13773	    ((mode->HDisplay == 1024) && (mode->VDisplay == 768)) ||
13774	    ((mode->HDisplay ==  800) && (mode->VDisplay == 600)))) ||
13775	  ((pSiS->SiS_Pr->SiS_CustomT == CUT_PANEL856) &&
13776	   (((mode->HDisplay == 1024) && (mode->VDisplay == 768)) ||
13777	    ((mode->HDisplay ==  800) && (mode->VDisplay == 600)))) ) {
13778
13779	 ModeIndex = SiS_GetModeID_LCD(pSiS->VGAEngine, VBFlags, mode->HDisplay, mode->VDisplay, i,
13780				pSiS->FSTN, pSiS->SiS_Pr->SiS_CustomT, pSiS->LCDwidth, pSiS->LCDheight,
13781				pSiS->VBFlags2);
13782
13783      }
13784
13785   } else if(VBFlags & CRT2_TV) {		/* CRT2 is TV */
13786
13787      ModeIndex = SiS_GetModeID_TV(pSiS->VGAEngine, VBFlags, mode->HDisplay, mode->VDisplay, i,
13788					pSiS->VBFlags2);
13789
13790   } else if(VBFlags & CRT2_VGA) {		/* CRT2 is VGA2 */
13791
13792      if((pSiS->AddedPlasmaModes) && (mode->type & M_T_BUILTIN))
13793	 return 0xfe;
13794
13795      if((havecustommodes) &&
13796	 (!(mode->type & M_T_DEFAULT)) &&
13797	 (SiSValidVGA2UserMode(pSiS, VBFlags, mode)))
13798         return 0xfe;
13799
13800      ModeIndex = SiS_GetModeID_VGA2(pSiS->VGAEngine, VBFlags, mode->HDisplay, mode->VDisplay, i,
13801					pSiS->VBFlags2);
13802
13803   } else {					/* no CRT2 */
13804
13805      /* Return a valid mode number */
13806      ModeIndex = 0xfe;
13807
13808   }
13809
13810   return(ModeIndex);
13811}
13812
13813/* Calculate the vertical refresh rate from a mode */
13814float
13815SiSCalcVRate(DisplayModePtr mode)
13816{
13817   float hsync, refresh = 0;
13818
13819   if(mode->HSync > 0.0)
13820       	hsync = mode->HSync;
13821   else if(mode->HTotal > 0)
13822       	hsync = (float)mode->Clock / (float)mode->HTotal;
13823   else
13824       	hsync = 0.0;
13825
13826   if(mode->VTotal > 0)
13827       	refresh = hsync * 1000.0 / mode->VTotal;
13828
13829   if(mode->Flags & V_INTERLACE)
13830       	refresh *= 2.0;
13831
13832   if(mode->Flags & V_DBLSCAN)
13833       	refresh /= 2.0;
13834
13835   if(mode->VScan > 1)
13836        refresh /= mode->VScan;
13837
13838   if(mode->VRefresh > 0.0)
13839	refresh = mode->VRefresh;
13840
13841   if(hsync == 0.0 || refresh == 0.0) return 0.0;
13842
13843   return refresh;
13844}
13845
13846/* Calculate CR33 (rate index) for CRT1.
13847 * Calculation is done using currentmode, therefore it is
13848 * recommended to set VertRefresh and HorizSync to correct
13849 * values in config file.
13850 */
13851UChar
13852SISSearchCRT1Rate(ScrnInfoPtr pScrn, DisplayModePtr mode)
13853{
13854   SISPtr  pSiS = SISPTR(pScrn);
13855   int     i = 0, irefresh;
13856   UShort  xres = mode->HDisplay;
13857   UShort  yres = mode->VDisplay;
13858   UChar   index, defindex;
13859   Bool    checksis730 = FALSE;
13860
13861   defindex = (xres == 800 || xres == 1024 || xres == 1280) ? 0x02 : 0x01;
13862
13863   irefresh = (int)SiSCalcVRate(mode);
13864   if(!irefresh) return defindex;
13865
13866   /* SiS730 has troubles on CRT2 if CRT1 is at 32bpp */
13867   if( (pSiS->ChipType == SIS_730)        &&
13868       (pSiS->VBFlags2 & VB2_VIDEOBRIDGE) &&
13869       (pSiS->CurrentLayout.bitsPerPixel == 32) ) {
13870#ifdef SISDUALHEAD
13871      if(pSiS->DualHeadMode) {
13872         if(pSiS->SecondHead) {
13873	    checksis730 = TRUE;
13874	 }
13875      } else
13876#endif
13877      if((!pSiS->UseVESA) && (pSiS->VBFlags & CRT2_ENABLE) && (!pSiS->CRT1off)) {
13878         checksis730 = TRUE;
13879      }
13880   }
13881
13882#ifdef TWDEBUG
13883   xf86DrvMsg(0, X_INFO, "Debug: CalcVRate returned %d\n", irefresh);
13884#endif
13885
13886   /* We need the REAL refresh rate here */
13887   if(mode->Flags & V_INTERLACE) irefresh /= 2;
13888
13889   /* Do not multiply by 2 when DBLSCAN! */
13890
13891#ifdef TWDEBUG
13892   xf86DrvMsg(0, X_INFO, "Debug: Rate after correction = %d\n", irefresh);
13893#endif
13894
13895   index = 0;
13896   while((sisx_vrate[i].idx != 0) && (sisx_vrate[i].xres <= xres)) {
13897      if((sisx_vrate[i].xres == xres) && (sisx_vrate[i].yres == yres)) {
13898	 if((checksis730 == FALSE) || (sisx_vrate[i].SiS730valid32bpp == TRUE)) {
13899	    if(sisx_vrate[i].refresh == irefresh) {
13900	       index = sisx_vrate[i].idx;
13901	       break;
13902	    } else if(sisx_vrate[i].refresh > irefresh) {
13903	       if((sisx_vrate[i].refresh - irefresh) <= 3) {
13904		  index = sisx_vrate[i].idx;
13905	       } else if( ((checksis730 == FALSE) || (sisx_vrate[i - 1].SiS730valid32bpp == TRUE)) &&
13906		          ((irefresh - sisx_vrate[i - 1].refresh) <=  2) &&
13907			  (sisx_vrate[i].idx != 1) ) {
13908		  index = sisx_vrate[i - 1].idx;
13909	       }
13910	       break;
13911	    } else if((irefresh - sisx_vrate[i].refresh) <= 2) {
13912	       index = sisx_vrate[i].idx;
13913	       break;
13914	    }
13915	 }
13916      }
13917      i++;
13918   }
13919
13920   if(index > 0) return index;
13921   else          return defindex;
13922}
13923
13924void
13925SISWaitRetraceCRT1(ScrnInfoPtr pScrn)
13926{
13927   SISPtr pSiS = SISPTR(pScrn);
13928   int    watchdog;
13929   UChar  temp;
13930
13931   inSISIDXREG(SISCR,0x17,temp);
13932   if(!(temp & 0x80)) return;
13933
13934   inSISIDXREG(SISSR,0x1f,temp);
13935   if(temp & 0xc0) return;
13936
13937   watchdog = 65536;
13938   while((inSISREG(SISINPSTAT) & 0x08) && --watchdog);
13939   watchdog = 65536;
13940   while((!(inSISREG(SISINPSTAT) & 0x08)) && --watchdog);
13941}
13942
13943void
13944SISWaitRetraceCRT2(ScrnInfoPtr pScrn)
13945{
13946   SISPtr pSiS = SISPTR(pScrn);
13947   int    watchdog;
13948   UChar  temp, reg;
13949
13950   if(SiSBridgeIsInSlaveMode(pScrn)) {
13951      SISWaitRetraceCRT1(pScrn);
13952      return;
13953   }
13954
13955   switch(pSiS->VGAEngine) {
13956   case SIS_300_VGA:
13957   	reg = 0x25;
13958	break;
13959   case SIS_315_VGA:
13960   	reg = 0x30;
13961	break;
13962   default:
13963        return;
13964   }
13965
13966   watchdog = 65536;
13967   do {
13968   	inSISIDXREG(SISPART1, reg, temp);
13969	if(!(temp & 0x02)) break;
13970   } while(--watchdog);
13971   watchdog = 65536;
13972   do {
13973   	inSISIDXREG(SISPART1, reg, temp);
13974	if(temp & 0x02) break;
13975   } while(--watchdog);
13976}
13977
13978static void
13979SISWaitVBRetrace(ScrnInfoPtr pScrn)
13980{
13981   SISPtr  pSiS = SISPTR(pScrn);
13982
13983   if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
13984#ifdef SISDUALHEAD
13985      if(pSiS->DualHeadMode) {
13986   	 if(pSiS->SecondHead)
13987	    SISWaitRetraceCRT1(pScrn);
13988         else
13989	    SISWaitRetraceCRT2(pScrn);
13990      } else {
13991#endif
13992	 if(pSiS->VBFlags & DISPTYPE_DISP1) {
13993	    SISWaitRetraceCRT1(pScrn);
13994	 }
13995	 if(pSiS->VBFlags & DISPTYPE_DISP2) {
13996	    if(!(SiSBridgeIsInSlaveMode(pScrn))) {
13997	       SISWaitRetraceCRT2(pScrn);
13998	    }
13999	 }
14000#ifdef SISDUALHEAD
14001      }
14002#endif
14003   } else {
14004      SISWaitRetraceCRT1(pScrn);
14005   }
14006}
14007
14008#define MODEID_OFF 0x449
14009
14010UChar
14011SiS_GetSetBIOSScratch(ScrnInfoPtr pScrn, UShort offset, UChar value)
14012{
14013    UChar ret = 0;
14014#ifndef XSERVER_LIBPCIACCESS
14015#ifdef SIS_USE_BIOS_SCRATCH
14016    UChar *base;
14017#endif
14018#endif
14019
14020    /* For some reasons (like detecting the current display mode),
14021     * we need to read (or write-back) values from the BIOS
14022     * scratch area. This area is only valid for the primary
14023     * graphics card. For the secondary, we just return some
14024     * defaults and ignore requests to write data. As regards
14025     * the display mode: If sisfb is loaded for the secondary
14026     * card, it very probably has set a mode, but in any case
14027     * informed us via its info packet. So this here will not be
14028     * called for mode detection in this case.
14029     */
14030
14031    switch(offset) {
14032    case 0x489:
14033       ret = 0x11;  /* Default VGA Info */
14034       break;
14035    case MODEID_OFF:
14036       ret = 0x03;  /* Default current display mode */
14037       break;
14038    }
14039
14040#ifndef XSERVER_LIBPCIACCESS
14041#ifdef SIS_USE_BIOS_SCRATCH
14042    if(SISPTR(pScrn)->Primary) {
14043       base = xf86MapVidMem(pScrn->scrnIndex, VIDMEM_MMIO, 0, 0x2000);
14044       if(!base) {
14045          SISErrorLog(pScrn, "(Could not map BIOS scratch area)\n");
14046          return ret;
14047       }
14048
14049       ret = *(base + offset);
14050
14051       /* value != 0xff means: set register */
14052       if(value != 0xff) {
14053          *(base + offset) = value;
14054       }
14055
14056       xf86UnMapVidMem(pScrn->scrnIndex, base, 0x2000);
14057    }
14058#endif
14059#endif
14060    return ret;
14061}
14062
14063UChar
14064SiS_GetSetModeID(ScrnInfoPtr pScrn, UChar id)
14065{
14066    return(SiS_GetSetBIOSScratch(pScrn, MODEID_OFF, id));
14067}
14068
14069void
14070SiSMemCopyToVideoRam(SISPtr pSiS, UChar *to, UChar *from, int size)
14071{
14072   if((ULong)to & 15) (*pSiS->SiSFastMemCopy)(to, from, size);
14073   else       	      (*pSiS->SiSFastVidCopy)(to, from, size);
14074}
14075
14076void
14077SiSMemCopyFromVideoRam(SISPtr pSiS, UChar *to, UChar *from, int size)
14078{
14079   if((ULong)to & 15) (*pSiS->SiSFastMemCopyFrom)(to, from, size);
14080   else       	      (*pSiS->SiSFastVidCopyFrom)(to, from, size);
14081}
14082
14083void
14084sisSaveUnlockExtRegisterLock(SISPtr pSiS, UChar *reg1, UChar *reg2)
14085{
14086    register UChar val;
14087    ULong mylockcalls;
14088#ifdef TWDEBUG
14089    UChar val1, val2;
14090    int i;
14091#endif
14092
14093    pSiS->lockcalls++;
14094    mylockcalls = pSiS->lockcalls;
14095
14096    /* check if already unlocked */
14097    inSISIDXREG(SISSR, 0x05, val);
14098
14099    if(val != 0xa1) {
14100
14101       /* save State */
14102       if(reg1) *reg1 = val;
14103
14104       /* unlock */
14105       outSISIDXREG(SISSR, 0x05, 0x86);
14106
14107       /* Now check again */
14108       inSISIDXREG(SISSR, 0x05, val);
14109
14110       if(val != 0xA1) {
14111
14112          xf86DrvMsg(pSiS->pScrn->scrnIndex, X_WARNING,
14113               "Failed to unlock SR registers at relocated i/o ports\n");
14114
14115#ifdef TWDEBUG
14116          for(i = 0; i <= 0x3f; i++) {
14117		inSISIDXREG(SISSR, i, val1);
14118		inSISIDXREG(0x3c4, i, val2);
14119		xf86DrvMsg(pSiS->pScrn->scrnIndex, X_INFO,
14120			"SR%02d: RelIO=0x%02x 0x3c4=0x%02x (%ld)\n",
14121			i, val1, val2, mylockcalls);
14122	  }
14123#endif
14124
14125	  /* Emergency measure: unlock at 0x3c4, and try to enable relocated IO ports */
14126	  switch(pSiS->VGAEngine) {
14127          case SIS_OLD_VGA:
14128	  case SIS_530_VGA:
14129	     outSISIDXREG(0x3c4, 0x05, 0x86);
14130	     andSISIDXREG(0x3c4, 0x33, ~0x20);
14131	     break;
14132	  case SIS_300_VGA:
14133	  case SIS_315_VGA:
14134	     outSISIDXREG(0x3c4, 0x05, 0x86);
14135	     orSISIDXREG(0x3c4, 0x20, 0x20);
14136	     break;
14137          }
14138	  outSISIDXREG(SISSR, 0x05, 0x86);
14139	  inSISIDXREG(SISSR, 0x05, val);
14140	  if(val != 0xa1) {
14141	     SISErrorLog(pSiS->pScrn,
14142			"Failed to unlock SR registers (%p, %lx, 0x%02x; %ld)\n",
14143			(void *)pSiS, (ULong)pSiS->RelIO, val, mylockcalls);
14144	     /* Now await doom... */
14145	  }
14146       }
14147    }
14148    if((pSiS->VGAEngine == SIS_OLD_VGA) || (pSiS->VGAEngine == SIS_530_VGA)) {
14149       inSISIDXREG(SISCR, 0x80, val);
14150       if(val != 0xa1) {
14151          /* save State */
14152          if(reg2) *reg2 = val;
14153          outSISIDXREG(SISCR, 0x80, 0x86);
14154	  inSISIDXREG(SISCR, 0x80, val);
14155	  if(val != 0xA1) {
14156	     SISErrorLog(pSiS->pScrn,
14157	        "Failed to unlock cr registers (%p, %lx, 0x%02x)\n",
14158	       (void *)pSiS, (ULong)pSiS->RelIO, val);
14159	  }
14160       }
14161    }
14162}
14163
14164void
14165sisRestoreExtRegisterLock(SISPtr pSiS, UChar reg1, UChar reg2)
14166{
14167    /* restore lock */
14168#ifndef UNLOCK_ALWAYS
14169    outSISIDXREG(SISSR, 0x05, reg1 == 0xA1 ? 0x86 : 0x00);
14170    if((pSiS->VGAEngine == SIS_OLD_VGA) || (pSiS->VGAEngine == SIS_530_VGA)) {
14171       outSISIDXREG(SISCR, 0x80, reg2 == 0xA1 ? 0x86 : 0x00);
14172    }
14173#endif
14174}
14175
14176