sis_driver.c revision 721a3bc8
172b676d7Smrg/*
272b676d7Smrg * SiS driver main code
372b676d7Smrg *
472b676d7Smrg * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria.
572b676d7Smrg *
672b676d7Smrg * Redistribution and use in source and binary forms, with or without
772b676d7Smrg * modification, are permitted provided that the following conditions
872b676d7Smrg * are met:
972b676d7Smrg * 1) Redistributions of source code must retain the above copyright
1072b676d7Smrg *    notice, this list of conditions and the following disclaimer.
1172b676d7Smrg * 2) Redistributions in binary form must reproduce the above copyright
1272b676d7Smrg *    notice, this list of conditions and the following disclaimer in the
1372b676d7Smrg *    documentation and/or other materials provided with the distribution.
1472b676d7Smrg * 3) The name of the author may not be used to endorse or promote products
1572b676d7Smrg *    derived from this software without specific prior written permission.
1672b676d7Smrg *
1772b676d7Smrg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1872b676d7Smrg * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1972b676d7Smrg * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2072b676d7Smrg * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2172b676d7Smrg * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2272b676d7Smrg * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2372b676d7Smrg * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2472b676d7Smrg * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2572b676d7Smrg * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2672b676d7Smrg * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2772b676d7Smrg *
2872b676d7Smrg * Author: Thomas Winischhofer <thomas@winischhofer.net>
2972b676d7Smrg *	- driver entirely rewritten since 2001, only basic structure taken from
3072b676d7Smrg *	  old code (except sis_dri.c, sis_shadow.c, sis_accel.c and parts of
3172b676d7Smrg *	  sis_dga.c; these were mostly taken over; sis_dri.c was changed for
3272b676d7Smrg *	  new versions of the DRI layer)
3372b676d7Smrg *
3472b676d7Smrg * This notice covers the entire driver code unless indicated otherwise.
3572b676d7Smrg *
3672b676d7Smrg * Formerly based on code which was
3772b676d7Smrg * 	     Copyright (C) 1998, 1999 by Alan Hourihane, Wigan, England.
3872b676d7Smrg * 	     Written by:
3972b676d7Smrg *           Alan Hourihane <alanh@fairlite.demon.co.uk>,
4072b676d7Smrg *           Mike Chapman <mike@paranoia.com>,
4172b676d7Smrg *           Juanjo Santamarta <santamarta@ctv.es>,
4272b676d7Smrg *           Mitani Hiroshi <hmitani@drl.mei.co.jp>,
4372b676d7Smrg *           David Thomas <davtom@dream.org.uk>.
4472b676d7Smrg */
4572b676d7Smrg
4672b676d7Smrg#ifdef HAVE_CONFIG_H
4772b676d7Smrg#include "config.h"
4872b676d7Smrg#endif
4972b676d7Smrg
5072b676d7Smrg#include "sis.h"
5172b676d7Smrg
52e47418d9Smrg#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 6
5372b676d7Smrg#include "xf86RAC.h"
54e47418d9Smrg#endif
5572b676d7Smrg#include "dixstruct.h"
5672b676d7Smrg#include "shadowfb.h"
5772b676d7Smrg#include "fb.h"
5872b676d7Smrg#include "micmap.h"
5972b676d7Smrg#include "mipointer.h"
6072b676d7Smrg#include "mibstore.h"
6172b676d7Smrg#include "edid.h"
6272b676d7Smrg
6372b676d7Smrg#define SIS_NEED_inSISREG
6472b676d7Smrg#define SIS_NEED_inSISIDXREG
6572b676d7Smrg#define SIS_NEED_outSISIDXREG
6672b676d7Smrg#define SIS_NEED_orSISIDXREG
6772b676d7Smrg#define SIS_NEED_andSISIDXREG
6872b676d7Smrg#define SIS_NEED_setSISIDXREG
6972b676d7Smrg#define SIS_NEED_outSISREG
7072b676d7Smrg#define SIS_NEED_MYMMIO
7172b676d7Smrg#define SIS_NEED_sisclearvram
7272b676d7Smrg#include "sis_regs.h"
7372b676d7Smrg#include "sis_dac.h"
7472b676d7Smrg
7572b676d7Smrg#include "sis_driver.h"
7672b676d7Smrg
775788ca14Smrg#include <X11/extensions/xf86dgaproto.h>
7872b676d7Smrg
7972b676d7Smrg#include "globals.h"
8072b676d7Smrg
81e47418d9Smrg#ifdef HAVE_XEXTPROTO_71
82e47418d9Smrg#include <X11/extensions/dpmsconst.h>
83e47418d9Smrg#else
8472b676d7Smrg#define DPMS_SERVER
8572b676d7Smrg#include <X11/extensions/dpms.h>
86e47418d9Smrg#endif
87e47418d9Smrg
885788ca14Smrg#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 5
895788ca14Smrg#include <inputstr.h> /* for inputInfo */
905788ca14Smrg#endif
915788ca14Smrg
9272b676d7Smrg
935788ca14Smrg#ifdef SISDRI
9472b676d7Smrg#include "dri.h"
9572b676d7Smrg#endif
9672b676d7Smrg
975788ca14Smrg/*
985788ca14Smrg * LookupWindow was removed with video abi 11.
995788ca14Smrg */
1005788ca14Smrg#if (GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 4)
1015788ca14Smrg#ifndef DixGetAttrAccess
1025788ca14Smrg#define DixGetAttrAccess   (1<<4)
1035788ca14Smrg#endif
1045788ca14Smrg#endif
1055788ca14Smrg
1065788ca14Smrg#if (GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 2)
1075788ca14Smrgstatic inline int
1085788ca14SmrgdixLookupWindow(WindowPtr *pWin, XID id, ClientPtr client, Mask access)
1095788ca14Smrg{
1105788ca14Smrg    *pWin = LookupWindow(id, client);
1115788ca14Smrg    if (!*pWin)
1125788ca14Smrg	return BadWindow;
1135788ca14Smrg    return Success;
1145788ca14Smrg}
1155788ca14Smrg#endif
1165788ca14Smrg
11772b676d7Smrg/* Globals (yes, these ARE really required to be global) */
11872b676d7Smrg
11972b676d7Smrg#ifdef SISUSEDEVPORT
12072b676d7Smrgint 		sisdevport = 0;
12172b676d7Smrg#endif
12272b676d7Smrg
12372b676d7Smrg#ifdef SISDUALHEAD
12472b676d7Smrgstatic int	SISEntityIndex = -1;
12572b676d7Smrg#endif
12672b676d7Smrg
12772b676d7Smrg#ifdef SISMERGED
12872b676d7Smrg#ifdef SISXINERAMA
12972b676d7Smrgstatic Bool 		SiSnoPanoramiXExtension = TRUE;
13072b676d7Smrgstatic int		SiSXineramaNumScreens = 0;
13172b676d7Smrgstatic SiSXineramaData	*SiSXineramadataPtr = NULL;
13272b676d7Smrgstatic int		SiSXineramaGeneration;
13372b676d7Smrg
13472b676d7Smrgstatic int SiSProcXineramaQueryVersion(ClientPtr client);
13572b676d7Smrgstatic int SiSProcXineramaGetState(ClientPtr client);
13672b676d7Smrgstatic int SiSProcXineramaGetScreenCount(ClientPtr client);
13772b676d7Smrgstatic int SiSProcXineramaGetScreenSize(ClientPtr client);
13872b676d7Smrgstatic int SiSProcXineramaIsActive(ClientPtr client);
13972b676d7Smrgstatic int SiSProcXineramaQueryScreens(ClientPtr client);
14072b676d7Smrgstatic int SiSSProcXineramaDispatch(ClientPtr client);
14172b676d7Smrg#endif
14272b676d7Smrg#endif
14372b676d7Smrg
14472b676d7Smrg/*
14572b676d7Smrg * This is intentionally screen-independent.  It indicates the binding
14672b676d7Smrg * choice made in the first PreInit.
14772b676d7Smrg */
14872b676d7Smrgstatic int pix24bpp = 0;
14972b676d7Smrg
15072b676d7Smrg/*
15172b676d7Smrg * This contains the functions needed by the server after loading the driver
15272b676d7Smrg * module.  It must be supplied, and gets passed back by the SetupProc
15372b676d7Smrg * function in the dynamic case.  In the static case, a reference to this
15472b676d7Smrg * is compiled in, and this requires that the name of this DriverRec be
15572b676d7Smrg * an upper-case version of the driver name.
15672b676d7Smrg */
15772b676d7Smrg
15872b676d7Smrg#ifdef _X_EXPORT
15972b676d7Smrg_X_EXPORT
16072b676d7Smrg#endif
16172b676d7SmrgDriverRec SIS = {
16272b676d7Smrg    SIS_CURRENT_VERSION,
16372b676d7Smrg    SIS_DRIVER_NAME,
16472b676d7Smrg    SISIdentify,
16572b676d7Smrg    SISProbe,
16672b676d7Smrg    SISAvailableOptions,
16772b676d7Smrg    NULL,
16872b676d7Smrg    0
16972b676d7Smrg#ifdef SIS_HAVE_DRIVER_FUNC
17072b676d7Smrg     ,
17172b676d7Smrg    SISDriverFunc
17272b676d7Smrg#endif
17372b676d7Smrg};
17472b676d7Smrg
17572b676d7Smrgstatic SymTabRec SISChipsets[] = {
17672b676d7Smrg    { PCI_CHIP_SIS5597,     "SIS5597/5598" },
17772b676d7Smrg    { PCI_CHIP_SIS530,      "SIS530/620" },
17872b676d7Smrg    { PCI_CHIP_SIS6326,     "SIS6326/AGP/DVD" },
17972b676d7Smrg    { PCI_CHIP_SIS300,      "SIS300/305" },
18072b676d7Smrg    { PCI_CHIP_SIS630,      "SIS630/730" },
18172b676d7Smrg    { PCI_CHIP_SIS540,      "SIS540" },
18272b676d7Smrg    { PCI_CHIP_SIS315,      "SIS315" },
18372b676d7Smrg    { PCI_CHIP_SIS315H,     "SIS315H" },
18472b676d7Smrg    { PCI_CHIP_SIS315PRO,   "SIS315PRO/E" },
18572b676d7Smrg    { PCI_CHIP_SIS550,	    "SIS550" },
18672b676d7Smrg    { PCI_CHIP_SIS650,      "SIS650/M650/651/740" },
18772b676d7Smrg    { PCI_CHIP_SIS330,      "SIS330(Xabre)" },
18872b676d7Smrg    { PCI_CHIP_SIS660,      "SIS660/[M]661[F|M]X/[M]670/[M]741[GX]/[M]760[GX]/[M]761[GX]/[M]770[GX]" },
18972b676d7Smrg    { PCI_CHIP_SIS340,      "SIS340" },
19072b676d7Smrg    { -1,                   NULL }
19172b676d7Smrg};
19272b676d7Smrg
19372b676d7Smrgstatic PciChipsets SISPciChipsets[] = {
19472b676d7Smrg    { PCI_CHIP_SIS5597,     PCI_CHIP_SIS5597,   RES_SHARED_VGA },
19572b676d7Smrg    { PCI_CHIP_SIS530,      PCI_CHIP_SIS530,    RES_SHARED_VGA },
19672b676d7Smrg    { PCI_CHIP_SIS6326,     PCI_CHIP_SIS6326,   RES_SHARED_VGA },
19772b676d7Smrg    { PCI_CHIP_SIS300,      PCI_CHIP_SIS300,    RES_SHARED_VGA },
19872b676d7Smrg    { PCI_CHIP_SIS630,      PCI_CHIP_SIS630,    RES_SHARED_VGA },
19972b676d7Smrg    { PCI_CHIP_SIS540,      PCI_CHIP_SIS540,    RES_SHARED_VGA },
20072b676d7Smrg    { PCI_CHIP_SIS550,      PCI_CHIP_SIS550,    RES_SHARED_VGA },
20172b676d7Smrg    { PCI_CHIP_SIS315,      PCI_CHIP_SIS315,    RES_SHARED_VGA },
20272b676d7Smrg    { PCI_CHIP_SIS315H,     PCI_CHIP_SIS315H,   RES_SHARED_VGA },
20372b676d7Smrg    { PCI_CHIP_SIS315PRO,   PCI_CHIP_SIS315PRO, RES_SHARED_VGA },
20472b676d7Smrg    { PCI_CHIP_SIS650,      PCI_CHIP_SIS650,    RES_SHARED_VGA },
20572b676d7Smrg    { PCI_CHIP_SIS330,      PCI_CHIP_SIS330,    RES_SHARED_VGA },
20672b676d7Smrg    { PCI_CHIP_SIS660,      PCI_CHIP_SIS660,    RES_SHARED_VGA },
20772b676d7Smrg    { PCI_CHIP_SIS340,      PCI_CHIP_SIS340,    RES_SHARED_VGA },
20872b676d7Smrg    { -1,                   -1,                 RES_UNDEFINED }
20972b676d7Smrg};
21072b676d7Smrg
21172b676d7Smrgstatic SymTabRec XGIChipsets[] = {
21272b676d7Smrg    { PCI_CHIP_XGIXG20,     "Volari Z7 (XG20)" },
21372b676d7Smrg    { PCI_CHIP_XGIXG40,     "Volari V3XT/V5/V8/Duo (XG40)" },
21472b676d7Smrg    { -1,                   NULL }
21572b676d7Smrg};
21672b676d7Smrg
21772b676d7Smrgstatic PciChipsets XGIPciChipsets[] = {
21872b676d7Smrg    { PCI_CHIP_XGIXG20,     PCI_CHIP_XGIXG20,   RES_SHARED_VGA },
21972b676d7Smrg    { PCI_CHIP_XGIXG40,     PCI_CHIP_XGIXG40,   RES_SHARED_VGA },
22072b676d7Smrg    { -1,                   -1,                 RES_UNDEFINED }
22172b676d7Smrg};
22272b676d7Smrg
22372b676d7Smrg#ifdef XFree86LOADER
22472b676d7Smrg
22572b676d7Smrgstatic MODULESETUPPROTO(sisSetup);
22672b676d7Smrg
22772b676d7Smrgstatic XF86ModuleVersionInfo sisVersRec =
22872b676d7Smrg{
22972b676d7Smrg    SIS_DRIVER_NAME,
23072b676d7Smrg    MODULEVENDORSTRING,
23172b676d7Smrg    MODINFOSTRING1,
23272b676d7Smrg    MODINFOSTRING2,
23372b676d7Smrg#ifdef XORG_VERSION_CURRENT
23472b676d7Smrg    XORG_VERSION_CURRENT,
23572b676d7Smrg#else
23672b676d7Smrg    XF86_VERSION_CURRENT,
23772b676d7Smrg#endif
23872b676d7Smrg    SIS_MAJOR_VERSION, SIS_MINOR_VERSION, SIS_PATCHLEVEL,
23972b676d7Smrg    ABI_CLASS_VIDEODRV,         /* This is a video driver */
24072b676d7Smrg    ABI_VIDEODRV_VERSION,
24172b676d7Smrg    MOD_CLASS_VIDEODRV,
24272b676d7Smrg    {0,0,0,0}
24372b676d7Smrg};
24472b676d7Smrg
24572b676d7Smrg#ifdef _X_EXPORT
24672b676d7Smrg_X_EXPORT
24772b676d7Smrg#endif
24872b676d7SmrgXF86ModuleData sisModuleData = { &sisVersRec, sisSetup, NULL };
24972b676d7Smrg
25072b676d7Smrgpointer
25172b676d7SmrgsisSetup(pointer module, pointer opts, int *errmaj, int *errmin)
25272b676d7Smrg{
25372b676d7Smrg    static Bool setupDone = FALSE;
25472b676d7Smrg
25572b676d7Smrg    if(!setupDone) {
25672b676d7Smrg       setupDone = TRUE;
25772b676d7Smrg       xf86AddDriver(&SIS, module, SIS_HaveDriverFuncs);
25872b676d7Smrg       return (pointer)TRUE;
25972b676d7Smrg    }
26072b676d7Smrg
26172b676d7Smrg    if(errmaj) *errmaj = LDR_ONCEONLY;
26272b676d7Smrg    return NULL;
26372b676d7Smrg}
26472b676d7Smrg
26572b676d7Smrg#endif /* XFree86LOADER */
26672b676d7Smrg
26772b676d7Smrg/* Mandatory */
26872b676d7Smrgstatic void
26972b676d7SmrgSISIdentify(int flags)
27072b676d7Smrg{
27172b676d7Smrg    xf86PrintChipsets(SIS_NAME, "driver for SiS chipsets", SISChipsets);
27272b676d7Smrg    xf86PrintChipsets(SIS_NAME, "driver for XGI chipsets", XGIChipsets);
27372b676d7Smrg}
27472b676d7Smrg
27572b676d7Smrg#ifdef SIS_HAVE_DRIVER_FUNC
27672b676d7Smrgstatic Bool
27772b676d7SmrgSISDriverFunc(ScrnInfoPtr pScrn, xorgDriverFuncOp op, pointer ptr)
27872b676d7Smrg{
27972b676d7Smrg    CARD32 *flag;
28072b676d7Smrg
28172b676d7Smrg    switch(op) {
28272b676d7Smrg    case RR_GET_INFO:
28372b676d7Smrg	break;
28472b676d7Smrg    case RR_SET_CONFIG:
28572b676d7Smrg	break;
28672b676d7Smrg    case GET_REQUIRED_HW_INTERFACES:
28772b676d7Smrg	break;
28872b676d7Smrg    }
28972b676d7Smrg    return TRUE;
29072b676d7Smrg}
29172b676d7Smrg#endif
29272b676d7Smrg
29372b676d7Smrgstatic Bool
29472b676d7SmrgSISGetRec(ScrnInfoPtr pScrn)
29572b676d7Smrg{
29672b676d7Smrg    /* Allocate an SISRec, and hook it into pScrn->driverPrivate.
29772b676d7Smrg     * pScrn->driverPrivate is initialised to NULL, so we can check if
29872b676d7Smrg     * the allocation has already been done.
29972b676d7Smrg     */
30072b676d7Smrg    if(pScrn->driverPrivate != NULL) return TRUE;
30172b676d7Smrg
30272b676d7Smrg    pScrn->driverPrivate = xnfcalloc(sizeof(SISRec), 1);
30372b676d7Smrg
30472b676d7Smrg    /* Initialise it to 0 */
30572b676d7Smrg    memset(pScrn->driverPrivate, 0, sizeof(SISRec));
30672b676d7Smrg
30772b676d7Smrg    return TRUE;
30872b676d7Smrg}
30972b676d7Smrg
31072b676d7Smrgstatic void
31172b676d7SmrgSISFreeRec(ScrnInfoPtr pScrn)
31272b676d7Smrg{
31372b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
31472b676d7Smrg#ifdef SISDUALHEAD
31572b676d7Smrg    SISEntPtr pSiSEnt = NULL;
31672b676d7Smrg#endif
31772b676d7Smrg
31872b676d7Smrg    /* Just to make sure... */
31972b676d7Smrg    if(!pSiS) return;
32072b676d7Smrg
32172b676d7Smrg#ifdef SISDUALHEAD
32272b676d7Smrg    pSiSEnt = pSiS->entityPrivate;
32372b676d7Smrg#endif
32472b676d7Smrg
3255788ca14Smrg    if(pSiS->pstate) free(pSiS->pstate);
32672b676d7Smrg    pSiS->pstate = NULL;
3275788ca14Smrg    if(pSiS->fonts) free(pSiS->fonts);
32872b676d7Smrg    pSiS->fonts = NULL;
32972b676d7Smrg
33072b676d7Smrg#ifdef SISDUALHEAD
33172b676d7Smrg    if(pSiSEnt) {
33272b676d7Smrg       if(!pSiS->SecondHead) {
33372b676d7Smrg	  /* Free memory only if we are first head; in case of an error
33472b676d7Smrg	   * during init of the second head, the server will continue -
33572b676d7Smrg	   * and we need the BIOS image and SiS_Private for the first
33672b676d7Smrg	   * head.
33772b676d7Smrg	   */
3385788ca14Smrg	  if(pSiSEnt->BIOS) free(pSiSEnt->BIOS);
33972b676d7Smrg	  pSiSEnt->BIOS = pSiS->BIOS = NULL;
3405788ca14Smrg	  if(pSiSEnt->SiS_Pr) free(pSiSEnt->SiS_Pr);
34172b676d7Smrg	  pSiSEnt->SiS_Pr = pSiS->SiS_Pr = NULL;
3425788ca14Smrg	  if(pSiSEnt->RenderAccelArray) free(pSiSEnt->RenderAccelArray);
34372b676d7Smrg	  pSiSEnt->RenderAccelArray = pSiS->RenderAccelArray = NULL;
34472b676d7Smrg	  pSiSEnt->pScrn_1 = NULL;
34572b676d7Smrg       } else {
34672b676d7Smrg	  pSiS->BIOS = NULL;
34772b676d7Smrg	  pSiS->SiS_Pr = NULL;
34872b676d7Smrg	  pSiS->RenderAccelArray = NULL;
34972b676d7Smrg	  pSiSEnt->pScrn_2 = NULL;
35072b676d7Smrg       }
35172b676d7Smrg    } else {
35272b676d7Smrg#endif
3535788ca14Smrg       if(pSiS->BIOS) free(pSiS->BIOS);
35472b676d7Smrg       pSiS->BIOS = NULL;
3555788ca14Smrg       if(pSiS->SiS_Pr) free(pSiS->SiS_Pr);
35672b676d7Smrg       pSiS->SiS_Pr = NULL;
3575788ca14Smrg       if(pSiS->RenderAccelArray) free(pSiS->RenderAccelArray);
35872b676d7Smrg       pSiS->RenderAccelArray = NULL;
35972b676d7Smrg#ifdef SISDUALHEAD
36072b676d7Smrg    }
36172b676d7Smrg#endif
36272b676d7Smrg#ifdef SISMERGED
3635788ca14Smrg    if(pSiS->CRT2HSync) free(pSiS->CRT2HSync);
36472b676d7Smrg    pSiS->CRT2HSync = NULL;
3655788ca14Smrg    if(pSiS->CRT2VRefresh) free(pSiS->CRT2VRefresh);
36672b676d7Smrg    pSiS->CRT2VRefresh = NULL;
3675788ca14Smrg    if(pSiS->MetaModes) free(pSiS->MetaModes);
36872b676d7Smrg    pSiS->MetaModes = NULL;
36972b676d7Smrg    if(pSiS->CRT2pScrn) {
37072b676d7Smrg       if(pSiS->CRT2pScrn->modes) {
37172b676d7Smrg	  while(pSiS->CRT2pScrn->modes)
37272b676d7Smrg	     xf86DeleteMode(&pSiS->CRT2pScrn->modes, pSiS->CRT2pScrn->modes);
37372b676d7Smrg       }
37472b676d7Smrg       if(pSiS->CRT2pScrn->monitor) {
37572b676d7Smrg	  if(pSiS->CRT2pScrn->monitor->Modes) {
37672b676d7Smrg	     while(pSiS->CRT2pScrn->monitor->Modes)
37772b676d7Smrg	        xf86DeleteMode(&pSiS->CRT2pScrn->monitor->Modes, pSiS->CRT2pScrn->monitor->Modes);
37872b676d7Smrg	  }
3795788ca14Smrg	  if(pSiS->CRT2pScrn->monitor->DDC) free(pSiS->CRT2pScrn->monitor->DDC);
3805788ca14Smrg	  free(pSiS->CRT2pScrn->monitor);
38172b676d7Smrg       }
3825788ca14Smrg       free(pSiS->CRT2pScrn);
38372b676d7Smrg       pSiS->CRT2pScrn = NULL;
38472b676d7Smrg    }
38572b676d7Smrg    if(pSiS->CRT1Modes) {
38672b676d7Smrg       if(pSiS->CRT1Modes != pScrn->modes) {
38772b676d7Smrg	  if(pScrn->modes) {
38872b676d7Smrg	     pScrn->currentMode = pScrn->modes;
38972b676d7Smrg	     do {
39072b676d7Smrg	        DisplayModePtr p = pScrn->currentMode->next;
39172b676d7Smrg	        if(pScrn->currentMode->Private)
3925788ca14Smrg	 	  free(pScrn->currentMode->Private);
3935788ca14Smrg	        free(pScrn->currentMode);
39472b676d7Smrg	        pScrn->currentMode = p;
39572b676d7Smrg	     } while(pScrn->currentMode != pScrn->modes);
39672b676d7Smrg	  }
39772b676d7Smrg	  pScrn->currentMode = pSiS->CRT1CurrentMode;
39872b676d7Smrg	  pScrn->modes = pSiS->CRT1Modes;
39972b676d7Smrg	  pSiS->CRT1CurrentMode = NULL;
40072b676d7Smrg	  pSiS->CRT1Modes = NULL;
40172b676d7Smrg       }
40272b676d7Smrg    }
40372b676d7Smrg#endif
40472b676d7Smrg    while(pSiS->SISVESAModeList) {
40572b676d7Smrg       sisModeInfoPtr mp = pSiS->SISVESAModeList->next;
4065788ca14Smrg       free(pSiS->SISVESAModeList);
40772b676d7Smrg       pSiS->SISVESAModeList = mp;
40872b676d7Smrg    }
40972b676d7Smrg    if(pSiS->pVbe) vbeFree(pSiS->pVbe);
41072b676d7Smrg    pSiS->pVbe = NULL;
41172b676d7Smrg
41272b676d7Smrg#ifdef SISUSEDEVPORT
41372b676d7Smrg    if(pSiS->sisdevportopen)   close(sisdevport);
41472b676d7Smrg#endif
41572b676d7Smrg
41672b676d7Smrg    if(pScrn->driverPrivate == NULL)
41772b676d7Smrg        return;
4185788ca14Smrg    free(pScrn->driverPrivate);
41972b676d7Smrg    pScrn->driverPrivate = NULL;
42072b676d7Smrg}
42172b676d7Smrg
42272b676d7Smrgstatic void
42372b676d7SmrgSISErrorLog(ScrnInfoPtr pScrn, const char *format, ...)
42472b676d7Smrg{
42572b676d7Smrg    va_list ap;
426721a3bc8Sjoerg    static const char str[] = "**************************************************\n";
42772b676d7Smrg
42872b676d7Smrg    va_start(ap, format);
42972b676d7Smrg    xf86DrvMsg(pScrn->scrnIndex, X_ERROR, str);
43072b676d7Smrg    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
43172b676d7Smrg	"                      ERROR:\n");
43272b676d7Smrg    xf86VDrvMsgVerb(pScrn->scrnIndex, X_ERROR, 1, format, ap);
43372b676d7Smrg    va_end(ap);
43472b676d7Smrg    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
43572b676d7Smrg	"                  END OF MESSAGE\n");
43672b676d7Smrg    xf86DrvMsg(pScrn->scrnIndex, X_ERROR, str);
43772b676d7Smrg}
43872b676d7Smrg
43972b676d7Smrgstatic void
44072b676d7SmrgSiS_SiSFB_Lock(ScrnInfoPtr pScrn, Bool lock)
44172b676d7Smrg{
44272b676d7Smrg    SISPtr  pSiS = SISPTR(pScrn);
44372b676d7Smrg    int     fd;
44472b676d7Smrg    CARD32  parm;
44572b676d7Smrg
44672b676d7Smrg    if(!pSiS->sisfbfound) return;
44772b676d7Smrg    if(!pSiS->sisfb_havelock) return;
44872b676d7Smrg
4491fd23544Smrg    if((fd = open(pSiS->sisfbdevname, O_RDONLY)) != -1) {
45072b676d7Smrg       parm = lock ? 1 : 0;
45172b676d7Smrg       ioctl(fd, SISFB_SET_LOCK, &parm);
45272b676d7Smrg       close(fd);
45372b676d7Smrg    }
45472b676d7Smrg}
45572b676d7Smrg
45672b676d7Smrg/* Probe()
45772b676d7Smrg *
45872b676d7Smrg * Mandatory
45972b676d7Smrg */
46072b676d7Smrgstatic Bool
46172b676d7SmrgSISProbe(DriverPtr drv, int flags)
46272b676d7Smrg{
46372b676d7Smrg    int     i;
46472b676d7Smrg    GDevPtr *devSections;
46572b676d7Smrg    int     *usedChipsSiS, *usedChipsXGI;
46672b676d7Smrg    int     numDevSections;
46772b676d7Smrg    int     numUsed, numUsedSiS, numUsedXGI;
46872b676d7Smrg    Bool    foundScreen = FALSE;
46972b676d7Smrg
47072b676d7Smrg    /*
47172b676d7Smrg     * The aim here is to find all cards that this driver can handle,
47272b676d7Smrg     * and for the ones not already claimed by another driver, claim the
47372b676d7Smrg     * slot, and allocate a ScrnInfoRec.
47472b676d7Smrg     *
47572b676d7Smrg     * This should be a minimal probe, and it should under no circumstances
47672b676d7Smrg     * change the state of the hardware.  Because a device is found, don't
47772b676d7Smrg     * assume that it will be used.  Don't do any initialisations other than
47872b676d7Smrg     * the required ScrnInfoRec initialisations.  Don't allocate any new
47972b676d7Smrg     * data structures.
48072b676d7Smrg     *
48172b676d7Smrg     */
48272b676d7Smrg
48372b676d7Smrg    /*
48472b676d7Smrg     * Next we check, if there has been a chipset override in the config file.
48572b676d7Smrg     * For this we must find out if there is an active device section which
48672b676d7Smrg     * is relevant, i.e., which has no driver specified or has THIS driver
48772b676d7Smrg     * specified.
48872b676d7Smrg     */
48972b676d7Smrg
49072b676d7Smrg    if((numDevSections = xf86MatchDevice(SIS_DRIVER_NAME, &devSections)) <= 0) {
49172b676d7Smrg       /*
49272b676d7Smrg        * There's no matching device section in the config file, so quit
49372b676d7Smrg        * now.
49472b676d7Smrg        */
49572b676d7Smrg       return FALSE;
49672b676d7Smrg    }
49772b676d7Smrg
49872b676d7Smrg    /*
49972b676d7Smrg     * We need to probe the hardware first.  We then need to see how this
50072b676d7Smrg     * fits in with what is given in the config file, and allow the config
50172b676d7Smrg     * file info to override any contradictions.
50272b676d7Smrg     */
50372b676d7Smrg
50472b676d7Smrg    /*
50572b676d7Smrg     * All of the cards this driver supports are PCI, so the "probing" just
50672b676d7Smrg     * amounts to checking the PCI data that the server has already collected.
50772b676d7Smrg     */
5081fd23544Smrg#ifndef XSERVER_LIBPCIACCESS
50972b676d7Smrg    if(xf86GetPciVideoInfo() == NULL) {
51072b676d7Smrg       /*
51172b676d7Smrg        * We won't let anything in the config file override finding no
51272b676d7Smrg        * PCI video cards at all.
51372b676d7Smrg        */
51472b676d7Smrg       return FALSE;
51572b676d7Smrg    }
5161fd23544Smrg#endif
51772b676d7Smrg
51872b676d7Smrg    numUsedSiS = xf86MatchPciInstances(SIS_NAME, PCI_VENDOR_SIS,
51972b676d7Smrg			SISChipsets, SISPciChipsets, devSections,
52072b676d7Smrg			numDevSections, drv, &usedChipsSiS);
52172b676d7Smrg
52272b676d7Smrg    numUsedXGI = xf86MatchPciInstances(SIS_NAME, PCI_VENDOR_XGI,
52372b676d7Smrg			XGIChipsets, XGIPciChipsets, devSections,
52472b676d7Smrg			numDevSections, drv, &usedChipsXGI);
52572b676d7Smrg
52672b676d7Smrg    /* Free it since we don't need that list after this */
5275788ca14Smrg    free(devSections);
52872b676d7Smrg
52972b676d7Smrg    numUsed = numUsedSiS + numUsedXGI;
53072b676d7Smrg
53172b676d7Smrg    if(numUsed <= 0)
53272b676d7Smrg       return FALSE;
53372b676d7Smrg
53472b676d7Smrg    if(flags & PROBE_DETECT) {
53572b676d7Smrg
53672b676d7Smrg	foundScreen = TRUE;
53772b676d7Smrg
53872b676d7Smrg    } else for(i = 0; i < numUsed; i++) {
53972b676d7Smrg
54072b676d7Smrg	ScrnInfoPtr pScrn;
54172b676d7Smrg#ifdef SISDUALHEAD
54272b676d7Smrg	EntityInfoPtr pEnt;
54372b676d7Smrg#endif
54472b676d7Smrg
54572b676d7Smrg	/* Allocate a ScrnInfoRec and claim the slot */
54672b676d7Smrg	pScrn = NULL;
54772b676d7Smrg
54872b676d7Smrg	if((pScrn = xf86ConfigPciEntity(pScrn, 0,
54972b676d7Smrg			(i < numUsedSiS) ? usedChipsSiS[i] : usedChipsXGI[i-numUsedSiS],
55072b676d7Smrg			(i < numUsedSiS) ? SISPciChipsets  : XGIPciChipsets,
55172b676d7Smrg			NULL, NULL, NULL, NULL, NULL))) {
55272b676d7Smrg	    /* Fill in what we can of the ScrnInfoRec */
55372b676d7Smrg	    pScrn->driverVersion    = SIS_CURRENT_VERSION;
55472b676d7Smrg	    pScrn->driverName       = SIS_DRIVER_NAME;
55572b676d7Smrg	    pScrn->name             = SIS_NAME;
55672b676d7Smrg	    pScrn->Probe            = SISProbe;
55772b676d7Smrg	    pScrn->PreInit          = SISPreInit;
55872b676d7Smrg	    pScrn->ScreenInit       = SISScreenInit;
55972b676d7Smrg	    pScrn->SwitchMode       = SISSwitchMode;
56072b676d7Smrg	    pScrn->AdjustFrame      = SISAdjustFrame;
56172b676d7Smrg	    pScrn->EnterVT          = SISEnterVT;
56272b676d7Smrg	    pScrn->LeaveVT          = SISLeaveVT;
56372b676d7Smrg	    pScrn->FreeScreen       = SISFreeScreen;
56472b676d7Smrg	    pScrn->ValidMode        = SISValidMode;
5651fd23544Smrg
56672b676d7Smrg	    foundScreen = TRUE;
56772b676d7Smrg	}
56872b676d7Smrg
56972b676d7Smrg#ifdef SISDUALHEAD
57072b676d7Smrg	pEnt = xf86GetEntityInfo((i < numUsedSiS) ? usedChipsSiS[i] : usedChipsXGI[i-numUsedSiS]);
57172b676d7Smrg
57272b676d7Smrg	if(pEnt->chipset == PCI_CHIP_SIS630 || pEnt->chipset == PCI_CHIP_SIS540 ||
57372b676d7Smrg	   pEnt->chipset == PCI_CHIP_SIS650 || pEnt->chipset == PCI_CHIP_SIS550 ||
57472b676d7Smrg	   pEnt->chipset == PCI_CHIP_SIS315 || pEnt->chipset == PCI_CHIP_SIS315H ||
57572b676d7Smrg	   pEnt->chipset == PCI_CHIP_SIS315PRO || pEnt->chipset == PCI_CHIP_SIS330 ||
57672b676d7Smrg	   pEnt->chipset == PCI_CHIP_SIS300 || pEnt->chipset == PCI_CHIP_SIS660 ||
57772b676d7Smrg	   pEnt->chipset == PCI_CHIP_SIS340 || pEnt->chipset == PCI_CHIP_XGIXG40) {
57872b676d7Smrg
57972b676d7Smrg	    SISEntPtr pSiSEnt = NULL;
58072b676d7Smrg	    DevUnion  *pPriv;
58172b676d7Smrg
58272b676d7Smrg	    xf86SetEntitySharable((i < numUsedSiS) ? usedChipsSiS[i] : usedChipsXGI[i-numUsedSiS]);
58372b676d7Smrg	    if(SISEntityIndex < 0) {
58472b676d7Smrg	       SISEntityIndex = xf86AllocateEntityPrivateIndex();
58572b676d7Smrg	    }
58672b676d7Smrg	    pPriv = xf86GetEntityPrivate(pScrn->entityList[0], SISEntityIndex);
58772b676d7Smrg	    if(!pPriv->ptr) {
58872b676d7Smrg	       pPriv->ptr = xnfcalloc(sizeof(SISEntRec), 1);
58972b676d7Smrg	       pSiSEnt = pPriv->ptr;
59072b676d7Smrg	       memset(pSiSEnt, 0, sizeof(SISEntRec));
59172b676d7Smrg	       pSiSEnt->lastInstance = -1;
59272b676d7Smrg	    } else {
59372b676d7Smrg	       pSiSEnt = pPriv->ptr;
59472b676d7Smrg	    }
59572b676d7Smrg	    pSiSEnt->lastInstance++;
59672b676d7Smrg	    xf86SetEntityInstanceForScreen(pScrn, pScrn->entityList[0],
59772b676d7Smrg	                                   pSiSEnt->lastInstance);
59872b676d7Smrg	}
59972b676d7Smrg#endif /* DUALHEAD */
60072b676d7Smrg
60172b676d7Smrg    }
60272b676d7Smrg
6035788ca14Smrg    if(usedChipsSiS) free(usedChipsSiS);
6045788ca14Smrg    if(usedChipsXGI) free(usedChipsXGI);
60572b676d7Smrg
60672b676d7Smrg    return foundScreen;
60772b676d7Smrg}
60872b676d7Smrg
60972b676d7Smrg/* Various helpers */
61072b676d7Smrg
61172b676d7Smrgstatic unsigned short
61272b676d7Smrgcalcgammaval(int j, int nramp, float invgamma, float bri, float c)
61372b676d7Smrg{
61472b676d7Smrg    float k = (float)j;
61572b676d7Smrg    float nrm1 = (float)(nramp - 1);
61672b676d7Smrg    float con = c * nrm1 / 3.0;
61772b676d7Smrg    float l, v;
61872b676d7Smrg
61972b676d7Smrg    if(con != 0.0) {
62072b676d7Smrg       l = nrm1 / 2.0;
62172b676d7Smrg       if(con <= 0.0) {
62272b676d7Smrg          k -= l;
62372b676d7Smrg          k *= (l + con) / l;
62472b676d7Smrg       } else {
62572b676d7Smrg          l -= 1.0;
62672b676d7Smrg          k -= l;
62772b676d7Smrg          k *= l / (l - con);
62872b676d7Smrg       }
62972b676d7Smrg       k += l;
63072b676d7Smrg       if(k < 0.0) k = 0.0;
63172b676d7Smrg    }
63272b676d7Smrg
63372b676d7Smrg    if(invgamma == 1.0) {
63472b676d7Smrg       v = k / nrm1 * 65535.0;
63572b676d7Smrg    } else {
63672b676d7Smrg       v = pow(k / nrm1, invgamma) * 65535.0 + 0.5;
63772b676d7Smrg    }
63872b676d7Smrg
63972b676d7Smrg    v += (bri * (65535.0 / 3.0)) ;
64072b676d7Smrg
64172b676d7Smrg    if(v < 0.0) v = 0.0;
64272b676d7Smrg    else if(v > 65535.0) v = 65535.0;
64372b676d7Smrg
64472b676d7Smrg    return (unsigned short)v;
64572b676d7Smrg}
64672b676d7Smrg
64772b676d7Smrg#ifdef SISGAMMARAMP
64872b676d7Smrgvoid
64972b676d7SmrgSISCalculateGammaRamp(ScreenPtr pScreen, ScrnInfoPtr pScrn)
65072b676d7Smrg{
65172b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
65272b676d7Smrg   int    i, j, nramp;
65372b676d7Smrg   UShort *ramp[3];
65472b676d7Smrg   float  gamma_max[3], framp;
65572b676d7Smrg   Bool   newmethod = FALSE;
65672b676d7Smrg
65772b676d7Smrg   if(!(pSiS->SiS_SD3_Flags & SiS_SD3_OLDGAMMAINUSE)) {
65872b676d7Smrg      newmethod = TRUE;
65972b676d7Smrg   } else {
66072b676d7Smrg      gamma_max[0] = (float)pSiS->GammaBriR / 1000;
66172b676d7Smrg      gamma_max[1] = (float)pSiS->GammaBriG / 1000;
66272b676d7Smrg      gamma_max[2] = (float)pSiS->GammaBriB / 1000;
66372b676d7Smrg   }
66472b676d7Smrg
66572b676d7Smrg   if(!(nramp = xf86GetGammaRampSize(pScreen))) return;
66672b676d7Smrg
66772b676d7Smrg   for(i=0; i<3; i++) {
6685788ca14Smrg      ramp[i] = (UShort *)malloc(nramp * sizeof(UShort));
66972b676d7Smrg      if(!ramp[i]) {
6705788ca14Smrg	 if(ramp[0]) { free(ramp[0]); ramp[0] = NULL; }
6715788ca14Smrg	 if(ramp[1]) { free(ramp[1]); ramp[1] = NULL; }
67272b676d7Smrg	 return;
67372b676d7Smrg      }
67472b676d7Smrg   }
67572b676d7Smrg
67672b676d7Smrg   if(newmethod) {
67772b676d7Smrg
67872b676d7Smrg      for(i = 0; i < 3; i++) {
67972b676d7Smrg
68072b676d7Smrg         float invgamma = 0.0, bri = 0.0, con = 0.0;
68172b676d7Smrg
68272b676d7Smrg         switch(i) {
68372b676d7Smrg         case 0: invgamma = 1. / pScrn->gamma.red;
68472b676d7Smrg		 bri = pSiS->NewGammaBriR;
68572b676d7Smrg		 con = pSiS->NewGammaConR;
68672b676d7Smrg		 break;
68772b676d7Smrg         case 1: invgamma = 1. / pScrn->gamma.green;
68872b676d7Smrg		 bri = pSiS->NewGammaBriG;
68972b676d7Smrg		 con = pSiS->NewGammaConG;
69072b676d7Smrg		 break;
69172b676d7Smrg         case 2: invgamma = 1. / pScrn->gamma.blue;
69272b676d7Smrg		 bri = pSiS->NewGammaBriB;
69372b676d7Smrg                 con = pSiS->NewGammaConB;
69472b676d7Smrg		 break;
69572b676d7Smrg         }
69672b676d7Smrg
69772b676d7Smrg	 for(j = 0; j < nramp; j++) {
69872b676d7Smrg	    ramp[i][j] = calcgammaval(j, nramp, invgamma, bri, con);
69972b676d7Smrg	 }
70072b676d7Smrg
70172b676d7Smrg      }
70272b676d7Smrg
70372b676d7Smrg   } else {
70472b676d7Smrg
70572b676d7Smrg      for(i = 0; i < 3; i++) {
70672b676d7Smrg         int fullscale = 65535 * gamma_max[i];
70772b676d7Smrg         float dramp = 1. / (nramp - 1);
70872b676d7Smrg         float invgamma = 0.0, v;
70972b676d7Smrg
71072b676d7Smrg         switch(i) {
71172b676d7Smrg         case 0: invgamma = 1. / pScrn->gamma.red; break;
71272b676d7Smrg         case 1: invgamma = 1. / pScrn->gamma.green; break;
71372b676d7Smrg         case 2: invgamma = 1. / pScrn->gamma.blue; break;
71472b676d7Smrg         }
71572b676d7Smrg
71672b676d7Smrg         for(j = 0; j < nramp; j++) {
71772b676d7Smrg	    framp = pow(j * dramp, invgamma);
71872b676d7Smrg
71972b676d7Smrg	    v = (fullscale < 0) ? (65535 + fullscale * framp) :
72072b676d7Smrg			       fullscale * framp;
72172b676d7Smrg	    if(v < 0) v = 0;
72272b676d7Smrg	    else if(v > 65535) v = 65535;
72372b676d7Smrg	    ramp[i][j] = (UShort)v;
72472b676d7Smrg         }
72572b676d7Smrg      }
72672b676d7Smrg
72772b676d7Smrg   }
72872b676d7Smrg
72972b676d7Smrg   xf86ChangeGammaRamp(pScreen, nramp, ramp[0], ramp[1], ramp[2]);
73072b676d7Smrg
7315788ca14Smrg   free(ramp[0]);
7325788ca14Smrg   free(ramp[1]);
7335788ca14Smrg   free(ramp[2]);
73472b676d7Smrg   ramp[0] = ramp[1] = ramp[2] = NULL;
73572b676d7Smrg}
73672b676d7Smrg#endif
73772b676d7Smrg
73872b676d7Smrgvoid
73972b676d7SmrgSISCalculateGammaRampCRT2(ScrnInfoPtr pScrn)
74072b676d7Smrg{
74172b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
74272b676d7Smrg   int    i;
74372b676d7Smrg   int    myshift = 16 - pScrn->rgbBits;
74472b676d7Smrg   int    maxvalue = (1 << pScrn->rgbBits) - 1;
74572b676d7Smrg   int    reds = pScrn->mask.red >> pScrn->offset.red;
74672b676d7Smrg   int    greens = pScrn->mask.green >> pScrn->offset.green;
74772b676d7Smrg   int    blues = pScrn->mask.blue >> pScrn->offset.blue;
74872b676d7Smrg   float  framp, invgamma1, invgamma2, invgamma3, v;
74972b676d7Smrg
75072b676d7Smrg   invgamma1  = 1. / pSiS->GammaR2;
75172b676d7Smrg   invgamma2  = 1. / pSiS->GammaG2;
75272b676d7Smrg   invgamma3  = 1. / pSiS->GammaB2;
75372b676d7Smrg
75472b676d7Smrg   if(!(pSiS->SiS_SD3_Flags & SiS_SD3_OLDGAMMAINUSE)) {
75572b676d7Smrg
75672b676d7Smrg      for(i = 0; i < pSiS->CRT2ColNum; i++) {
75772b676d7Smrg         pSiS->crt2gcolortable[i].red = calcgammaval(i, pSiS->CRT2ColNum, invgamma1,
75872b676d7Smrg			pSiS->NewGammaBriR2, pSiS->NewGammaConR2) >> myshift;
75972b676d7Smrg         pSiS->crt2gcolortable[i].green = calcgammaval(i, pSiS->CRT2ColNum, invgamma2,
76072b676d7Smrg			pSiS->NewGammaBriG2, pSiS->NewGammaConG2) >> myshift;
76172b676d7Smrg         pSiS->crt2gcolortable[i].blue = calcgammaval(i, pSiS->CRT2ColNum, invgamma3,
76272b676d7Smrg			pSiS->NewGammaBriB2, pSiS->NewGammaConB2) >> myshift;
76372b676d7Smrg      }
76472b676d7Smrg
76572b676d7Smrg   } else {
76672b676d7Smrg
76772b676d7Smrg      int fullscale1 = 65536 * (float)pSiS->GammaBriR2 / 1000;
76872b676d7Smrg      int fullscale2 = 65536 * (float)pSiS->GammaBriG2 / 1000;
76972b676d7Smrg      int fullscale3 = 65536 * (float)pSiS->GammaBriB2 / 1000;
77072b676d7Smrg
77172b676d7Smrg      float dramp = 1. / (pSiS->CRT2ColNum - 1);
77272b676d7Smrg
77372b676d7Smrg      for(i = 0; i < pSiS->CRT2ColNum; i++) {
77472b676d7Smrg         framp = pow(i * dramp, invgamma1);
77572b676d7Smrg         v = (fullscale1 < 0) ? (65535 + fullscale1 * framp) : fullscale1 * framp;
77672b676d7Smrg         if(v < 0) v = 0;
77772b676d7Smrg         else if(v > 65535) v = 65535;
77872b676d7Smrg         pSiS->crt2gcolortable[i].red = ((UShort)v) >> myshift;
77972b676d7Smrg         framp = pow(i * dramp, invgamma2);
78072b676d7Smrg         v = (fullscale2 < 0) ? (65535 + fullscale2 * framp) : fullscale2 * framp;
78172b676d7Smrg         if(v < 0) v = 0;
78272b676d7Smrg         else if(v > 65535) v = 65535;
78372b676d7Smrg         pSiS->crt2gcolortable[i].green = ((UShort)v) >> myshift;
78472b676d7Smrg         framp = pow(i * dramp, invgamma3);
78572b676d7Smrg         v = (fullscale3 < 0) ? (65535 + fullscale3 * framp) : fullscale3 * framp;
78672b676d7Smrg         if(v < 0) v = 0;
78772b676d7Smrg         else if(v > 65535) v = 65535;
78872b676d7Smrg         pSiS->crt2gcolortable[i].blue = ((UShort)v) >> myshift;
78972b676d7Smrg      }
79072b676d7Smrg
79172b676d7Smrg   }
79272b676d7Smrg
79372b676d7Smrg   for(i = 0; i < pSiS->CRT2ColNum; i++) {
79472b676d7Smrg      pSiS->crt2colors[i].red =
79572b676d7Smrg         pSiS->crt2gcolortable[i * maxvalue / reds].red;
79672b676d7Smrg      pSiS->crt2colors[i].green =
79772b676d7Smrg         pSiS->crt2gcolortable[i * maxvalue / greens].green;
79872b676d7Smrg      pSiS->crt2colors[i].blue  =
79972b676d7Smrg         pSiS->crt2gcolortable[i * maxvalue / blues].blue;
80072b676d7Smrg   }
80172b676d7Smrg}
80272b676d7Smrg
80372b676d7Smrg/* If monitor section has no HSync/VRefresh data,
80472b676d7Smrg * derive it from DDC data.
80572b676d7Smrg */
80672b676d7Smrgstatic void
80772b676d7SmrgSiSSetSyncRangeFromEdid(ScrnInfoPtr pScrn, int flag)
80872b676d7Smrg{
80972b676d7Smrg   MonPtr      mon = pScrn->monitor;
81072b676d7Smrg   xf86MonPtr  ddc = mon->DDC;
81172b676d7Smrg   float       myhhigh = 0.0, myhlow = 0.0, htest;
81272b676d7Smrg   int         myvhigh = 0, myvlow = 0, vtest, i;
81372b676d7Smrg   UChar temp;
81472b676d7Smrg   const myhddctiming myhtiming[12] = {
81572b676d7Smrg       { 1, 0x20, 31.6 }, /* rounded up by .1 */
81672b676d7Smrg       { 1, 0x80, 31.6 },
81772b676d7Smrg       { 1, 0x02, 35.3 },
81872b676d7Smrg       { 1, 0x04, 37.6 },
81972b676d7Smrg       { 1, 0x08, 38.0 },
82072b676d7Smrg       { 1, 0x01, 38.0 },
82172b676d7Smrg       { 2, 0x40, 47.0 },
82272b676d7Smrg       { 2, 0x80, 48.2 },
82372b676d7Smrg       { 2, 0x08, 48.5 },
82472b676d7Smrg       { 2, 0x04, 56.6 },
82572b676d7Smrg       { 2, 0x02, 60.1 },
82672b676d7Smrg       { 2, 0x01, 80.1 }
82772b676d7Smrg   };
82872b676d7Smrg   const myvddctiming myvtiming[11] = {
82972b676d7Smrg       { 1, 0x02, 56 },
83072b676d7Smrg       { 1, 0x01, 60 },
83172b676d7Smrg       { 2, 0x08, 60 },
83272b676d7Smrg       { 2, 0x04, 70 },
83372b676d7Smrg       { 1, 0x80, 71 },
83472b676d7Smrg       { 1, 0x08, 72 },
83572b676d7Smrg       { 2, 0x80, 72 },
83672b676d7Smrg       { 1, 0x04, 75 },
83772b676d7Smrg       { 2, 0x40, 75 },
83872b676d7Smrg       { 2, 0x02, 75 },
83972b676d7Smrg       { 2, 0x01, 75 }
84072b676d7Smrg   };
84172b676d7Smrg
84272b676d7Smrg   if(flag) { /* HSync */
84372b676d7Smrg
84472b676d7Smrg      for(i = 0; i < 4; i++) {
84572b676d7Smrg	 if(ddc->det_mon[i].type == DS_RANGES) {
84672b676d7Smrg	    mon->nHsync = 1;
84772b676d7Smrg	    mon->hsync[0].lo = ddc->det_mon[i].section.ranges.min_h;
84872b676d7Smrg	    mon->hsync[0].hi = ddc->det_mon[i].section.ranges.max_h;
84972b676d7Smrg	    if(mon->hsync[0].lo > 32.0 || mon->hsync[0].hi < 31.0) {
85072b676d7Smrg	       if(ddc->timings1.t1 & 0x80) {
85172b676d7Smrg		  mon->nHsync++;
85272b676d7Smrg		  mon->hsync[1].lo = 31.0;
85372b676d7Smrg		  mon->hsync[1].hi = 32.0;
85472b676d7Smrg	       }
85572b676d7Smrg	    }
85672b676d7Smrg	    return;
85772b676d7Smrg	 }
85872b676d7Smrg      }
85972b676d7Smrg
86072b676d7Smrg      /* If no sync ranges detected in detailed timing table, we
86172b676d7Smrg       * derive them from supported VESA modes.
86272b676d7Smrg       */
86372b676d7Smrg
86472b676d7Smrg      for(i = 0; i < 12; i++) {
86572b676d7Smrg	 if(myhtiming[i].whichone == 1) temp = ddc->timings1.t1;
86672b676d7Smrg	 else                           temp = ddc->timings1.t2;
86772b676d7Smrg	 if(temp & myhtiming[i].mask) {
86872b676d7Smrg	    if((i == 0) || (myhlow > myhtiming[i].rate))
86972b676d7Smrg	       myhlow = myhtiming[i].rate;
87072b676d7Smrg	 }
87172b676d7Smrg	 if(myhtiming[11-i].whichone == 1) temp = ddc->timings1.t1;
87272b676d7Smrg	 else                              temp = ddc->timings1.t2;
87372b676d7Smrg	 if(temp & myhtiming[11-i].mask) {
87472b676d7Smrg	    if((i == 0) || (myhhigh < myhtiming[11-i].rate))
87572b676d7Smrg	       myhhigh = myhtiming[11-i].rate;
87672b676d7Smrg	 }
87772b676d7Smrg      }
87872b676d7Smrg
87972b676d7Smrg      for(i = 0; i < STD_TIMINGS; i++) {
88072b676d7Smrg	 if(ddc->timings2[i].hsize > 256) {
88172b676d7Smrg	    htest = ddc->timings2[i].refresh * 1.05 * ddc->timings2[i].vsize / 1000.0;
88272b676d7Smrg	    if(htest < myhlow)  myhlow  = htest;
88372b676d7Smrg	    if(htest > myhhigh) myhhigh = htest;
88472b676d7Smrg	 }
88572b676d7Smrg      }
88672b676d7Smrg
88772b676d7Smrg      if((myhhigh > 0.0) && (myhlow > 0.0)) {
88872b676d7Smrg	 mon->nHsync = 1;
88972b676d7Smrg	 mon->hsync[0].lo = myhlow - 0.1;
89072b676d7Smrg	 mon->hsync[0].hi = myhhigh;
89172b676d7Smrg      }
89272b676d7Smrg
89372b676d7Smrg
89472b676d7Smrg   } else {  /* Vrefresh */
89572b676d7Smrg
89672b676d7Smrg      for(i = 0; i < 4; i++) {
89772b676d7Smrg         if(ddc->det_mon[i].type == DS_RANGES) {
89872b676d7Smrg	    mon->nVrefresh = 1;
89972b676d7Smrg	    mon->vrefresh[0].lo = ddc->det_mon[i].section.ranges.min_v;
90072b676d7Smrg	    mon->vrefresh[0].hi = ddc->det_mon[i].section.ranges.max_v;
90172b676d7Smrg	    if(mon->vrefresh[0].lo > 72 || mon->vrefresh[0].hi < 70) {
90272b676d7Smrg	       if(ddc->timings1.t1 & 0x80) {
90372b676d7Smrg		  mon->nVrefresh++;
90472b676d7Smrg		  mon->vrefresh[1].lo = 71;
90572b676d7Smrg		  mon->vrefresh[1].hi = 71;
90672b676d7Smrg	       }
90772b676d7Smrg	    }
90872b676d7Smrg	    return;
90972b676d7Smrg         }
91072b676d7Smrg      }
91172b676d7Smrg
91272b676d7Smrg      for(i = 0; i < 11; i++) {
91372b676d7Smrg	 if(myvtiming[i].whichone == 1) temp = ddc->timings1.t1;
91472b676d7Smrg	 else                           temp = ddc->timings1.t2;
91572b676d7Smrg	 if(temp & myvtiming[i].mask) {
91672b676d7Smrg	    if((i == 0) || (myvlow > myvtiming[i].rate))
91772b676d7Smrg	       myvlow = myvtiming[i].rate;
91872b676d7Smrg	 }
91972b676d7Smrg	 if(myvtiming[10-i].whichone == 1) temp = ddc->timings1.t1;
92072b676d7Smrg	 else                              temp = ddc->timings1.t2;
92172b676d7Smrg	 if(temp & myvtiming[10-i].mask) {
92272b676d7Smrg	    if((i == 0) || (myvhigh < myvtiming[10-i].rate))
92372b676d7Smrg	       myvhigh = myvtiming[10-i].rate;
92472b676d7Smrg	 }
92572b676d7Smrg      }
92672b676d7Smrg
92772b676d7Smrg      for(i = 0; i < STD_TIMINGS; i++) {
92872b676d7Smrg	 if(ddc->timings2[i].hsize > 256) {
92972b676d7Smrg	    vtest = ddc->timings2[i].refresh;
93072b676d7Smrg	    if(vtest < myvlow)  myvlow  = vtest;
93172b676d7Smrg	    if(vtest > myvhigh) myvhigh = vtest;
93272b676d7Smrg	 }
93372b676d7Smrg      }
93472b676d7Smrg
93572b676d7Smrg      if((myvhigh > 0) && (myvlow > 0)) {
93672b676d7Smrg	 mon->nVrefresh = 1;
93772b676d7Smrg	 mon->vrefresh[0].lo = myvlow;
93872b676d7Smrg	 mon->vrefresh[0].hi = myvhigh;
93972b676d7Smrg      }
94072b676d7Smrg
94172b676d7Smrg   }
94272b676d7Smrg}
94372b676d7Smrg
94472b676d7Smrgstatic Bool
94572b676d7SmrgSiSAllowSyncOverride(SISPtr pSiS, Bool fromDDC)
94672b676d7Smrg{
94772b676d7Smrg   if(!(pSiS->VBFlags2 & VB2_VIDEOBRIDGE)) return FALSE;
94872b676d7Smrg
94972b676d7Smrg#ifdef SISDUALHEAD
95072b676d7Smrg   if(pSiS->DualHeadMode) {
95172b676d7Smrg      if(pSiS->SecondHead) {
95272b676d7Smrg         if((pSiS->VBFlags & CRT1_LCDA) && (!fromDDC)) return TRUE;
95372b676d7Smrg      } else {
95472b676d7Smrg         if((pSiS->VBFlags & CRT2_TV) ||
95572b676d7Smrg	    ((pSiS->VBFlags & CRT2_LCD) && (!fromDDC))) return TRUE;
95672b676d7Smrg      }
95772b676d7Smrg      return FALSE;
95872b676d7Smrg   }
95972b676d7Smrg#endif
96072b676d7Smrg
96172b676d7Smrg#ifdef SISMERGED
96272b676d7Smrg   if(pSiS->MergedFB) {
96372b676d7Smrg      if((pSiS->VBFlags & CRT1_LCDA) && (!fromDDC)) return TRUE;
96472b676d7Smrg      return FALSE;
96572b676d7Smrg   }
96672b676d7Smrg#endif
96772b676d7Smrg
96872b676d7Smrg   if(!(pSiS->VBFlags & DISPTYPE_CRT1)) {
96972b676d7Smrg      if( (pSiS->VBFlags & CRT2_TV) ||
97072b676d7Smrg	  ((pSiS->VBFlags & CRT2_LCD) && (!fromDDC)) ) return TRUE;
97172b676d7Smrg   } else if((pSiS->VBFlags & CRT1_LCDA) && (!fromDDC)) return TRUE;
97272b676d7Smrg
97372b676d7Smrg   return FALSE;
97472b676d7Smrg}
97572b676d7Smrg
97672b676d7Smrgstatic Bool
97772b676d7SmrgSiSCheckForH(float hsync, MonPtr monitor)
97872b676d7Smrg{
97972b676d7Smrg   int i;
98072b676d7Smrg   for(i = 0; i < monitor->nHsync; i++) {
98172b676d7Smrg      if((hsync > monitor->hsync[i].lo * (1.0 - SYNC_TOLERANCE)) &&
98272b676d7Smrg	 (hsync < monitor->hsync[i].hi * (1.0 + SYNC_TOLERANCE)))
98372b676d7Smrg	 break;
98472b676d7Smrg   }
98572b676d7Smrg   if(i == monitor->nHsync) return FALSE;
98672b676d7Smrg   return TRUE;
98772b676d7Smrg}
98872b676d7Smrg
98972b676d7Smrgstatic Bool
99072b676d7SmrgSiSCheckForV(float vrefresh, MonPtr monitor)
99172b676d7Smrg{
99272b676d7Smrg   int i;
99372b676d7Smrg   for(i = 0; i < monitor->nVrefresh; i++) {
99472b676d7Smrg      if((vrefresh > monitor->vrefresh[i].lo * (1.0 - SYNC_TOLERANCE)) &&
99572b676d7Smrg	 (vrefresh < monitor->vrefresh[i].hi * (1.0 + SYNC_TOLERANCE)))
99672b676d7Smrg	 break;
99772b676d7Smrg   }
99872b676d7Smrg   if(i == monitor->nVrefresh) return FALSE;
99972b676d7Smrg   return TRUE;
100072b676d7Smrg}
100172b676d7Smrg
100272b676d7Smrgstatic Bool
100372b676d7SmrgCheckAndOverruleH(ScrnInfoPtr pScrn, MonPtr monitor)
100472b676d7Smrg{
100572b676d7Smrg   DisplayModePtr mode = monitor->Modes;
100672b676d7Smrg   float mymin = 30.0, mymax = 80.0, hsync;
100772b676d7Smrg   Bool doit = FALSE;
100872b676d7Smrg
100972b676d7Smrg   for(hsync = mymin; hsync <= mymax; hsync += .5) {
101072b676d7Smrg      if(!SiSCheckForH(hsync, monitor)) doit = TRUE;
101172b676d7Smrg   }
101272b676d7Smrg
101372b676d7Smrg   if(mode) {
101472b676d7Smrg      do {
101572b676d7Smrg         if(mode->type & M_T_BUILTIN) {
101672b676d7Smrg	    hsync = (float)mode->Clock / (float)mode->HTotal;
101772b676d7Smrg	    if(!SiSCheckForH(hsync, monitor)) {
101872b676d7Smrg	       doit = TRUE;
101972b676d7Smrg	       if(hsync < mymin) mymin = hsync;
102072b676d7Smrg	       if(hsync > mymax) mymax = hsync;
102172b676d7Smrg	    }
102272b676d7Smrg	 }
102372b676d7Smrg      } while((mode = mode->next));
102472b676d7Smrg   }
102572b676d7Smrg
102672b676d7Smrg   if(doit) {
102772b676d7Smrg      monitor->nHsync = 1;
102872b676d7Smrg      monitor->hsync[0].lo = mymin;
102972b676d7Smrg      monitor->hsync[0].hi = mymax;
103072b676d7Smrg      return TRUE;
103172b676d7Smrg   }
103272b676d7Smrg
103372b676d7Smrg   return FALSE;
103472b676d7Smrg}
103572b676d7Smrg
103672b676d7Smrgstatic Bool
103772b676d7SmrgCheckAndOverruleV(ScrnInfoPtr pScrn, MonPtr monitor)
103872b676d7Smrg{
103972b676d7Smrg   DisplayModePtr mode = monitor->Modes;
104072b676d7Smrg   float mymin = 59.0, mymax = 61.0, vrefresh;
104172b676d7Smrg   Bool doit = FALSE, ret = FALSE;
104272b676d7Smrg
104372b676d7Smrg   for(vrefresh = mymin; vrefresh <= mymax; vrefresh += 1.0) {
104472b676d7Smrg      if(!SiSCheckForV(vrefresh, monitor)) doit = TRUE;
104572b676d7Smrg   }
104672b676d7Smrg
104772b676d7Smrg   if(mode) {
104872b676d7Smrg      do {
104972b676d7Smrg         if(mode->type & M_T_BUILTIN) {
105072b676d7Smrg	    vrefresh = mode->Clock * 1000.0 / (mode->HTotal * mode->VTotal);
105172b676d7Smrg	    if(mode->Flags & V_INTERLACE) vrefresh *= 2.0;
105272b676d7Smrg	    if(mode->Flags & V_DBLSCAN) vrefresh /= 2.0;
105372b676d7Smrg	    if(!SiSCheckForH(vrefresh, monitor)) {
105472b676d7Smrg	       doit = TRUE;
105572b676d7Smrg	       if(vrefresh < mymin) mymin = vrefresh;
105672b676d7Smrg	       if(vrefresh > mymax) mymax = vrefresh;
105772b676d7Smrg	    }
105872b676d7Smrg	 }
105972b676d7Smrg      } while((mode = mode->next));
106072b676d7Smrg   }
106172b676d7Smrg
106272b676d7Smrg   if(doit) {
106372b676d7Smrg      monitor->nVrefresh = 1;
106472b676d7Smrg      monitor->vrefresh[0].lo = mymin;
106572b676d7Smrg      monitor->vrefresh[0].hi = mymax;
106672b676d7Smrg      ret = TRUE;
106772b676d7Smrg   }
106872b676d7Smrg
106972b676d7Smrg   /* special for 640x400/320x200/@70Hz (VGA/IBM 720x480) */
107072b676d7Smrg   if( (!SiSCheckForV(71, monitor)) &&
107172b676d7Smrg       (monitor->nVrefresh < MAX_VREFRESH) ) {
107272b676d7Smrg      monitor->vrefresh[monitor->nVrefresh].lo = 71;
107372b676d7Smrg      monitor->vrefresh[monitor->nVrefresh].hi = 71;
107472b676d7Smrg      monitor->nVrefresh++;
107572b676d7Smrg      ret = TRUE;
107672b676d7Smrg   }
107772b676d7Smrg   return ret;
107872b676d7Smrg}
107972b676d7Smrg
108072b676d7Smrg/* Some helper functions for MergedFB mode */
108172b676d7Smrg
108272b676d7Smrg#ifdef SISMERGED
108372b676d7Smrg
108472b676d7Smrg/* Helper function for CRT2 monitor vrefresh/hsync options
108572b676d7Smrg * (Code base from mga driver)
108672b676d7Smrg */
108772b676d7Smrgstatic int
108872b676d7SmrgSiSStrToRanges(range *r, char *s, int max)
108972b676d7Smrg{
109072b676d7Smrg   float num = 0.0;
109172b676d7Smrg   int rangenum = 0;
109272b676d7Smrg   Bool gotdash = FALSE;
109372b676d7Smrg   Bool nextdash = FALSE;
109472b676d7Smrg   char *strnum = NULL;
109572b676d7Smrg   do {
109672b676d7Smrg      switch(*s) {
109772b676d7Smrg      case '0':
109872b676d7Smrg      case '1':
109972b676d7Smrg      case '2':
110072b676d7Smrg      case '3':
110172b676d7Smrg      case '4':
110272b676d7Smrg      case '5':
110372b676d7Smrg      case '6':
110472b676d7Smrg      case '7':
110572b676d7Smrg      case '8':
110672b676d7Smrg      case '9':
110772b676d7Smrg      case '.':
110872b676d7Smrg         if(strnum == NULL) {
110972b676d7Smrg            strnum = s;
111072b676d7Smrg            gotdash = nextdash;
111172b676d7Smrg            nextdash = FALSE;
111272b676d7Smrg         }
111372b676d7Smrg         break;
111472b676d7Smrg      case '-':
111572b676d7Smrg      case ' ':
111672b676d7Smrg      case 0:
111772b676d7Smrg         if(strnum == NULL) break;
111872b676d7Smrg         sscanf(strnum, "%f", &num);
111972b676d7Smrg	 strnum = NULL;
112072b676d7Smrg         if(gotdash) {
112172b676d7Smrg            r[rangenum - 1].hi = num;
112272b676d7Smrg         } else {
112372b676d7Smrg            r[rangenum].lo = num;
112472b676d7Smrg            r[rangenum].hi = num;
112572b676d7Smrg            rangenum++;
112672b676d7Smrg         }
112772b676d7Smrg         if(*s == '-') nextdash = (rangenum != 0);
112872b676d7Smrg	 else if(rangenum >= max) return rangenum;
112972b676d7Smrg         break;
113072b676d7Smrg      default:
113172b676d7Smrg         return 0;
113272b676d7Smrg      }
113372b676d7Smrg
113472b676d7Smrg   } while(*(s++) != 0);
113572b676d7Smrg
113672b676d7Smrg   return rangenum;
113772b676d7Smrg}
113872b676d7Smrg
113972b676d7Smrg/* Copy and link two modes (i, j) for mergedfb mode
114072b676d7Smrg * (Code base taken from mga driver)
114172b676d7Smrg *
114272b676d7Smrg * - Copy mode i, merge j to copy of i, link the result to dest
114372b676d7Smrg * - Link i and j in private record.
114472b676d7Smrg * - If dest is NULL, return value is copy of i linked to itself.
114572b676d7Smrg * - For mergedfb auto-config, we only check the dimension
114672b676d7Smrg *   against virtualX/Y, if they were user-provided.
114772b676d7Smrg * - No special treatment required for CRTxxOffs.
114872b676d7Smrg * - Provide fake dotclock in order to distinguish between similar
114972b676d7Smrg *   looking MetaModes (for RandR and VidMode extensions)
115072b676d7Smrg * - Set unique VRefresh of dest mode for RandR
115172b676d7Smrg */
115272b676d7Smrgstatic DisplayModePtr
115372b676d7SmrgSiSCopyModeNLink(ScrnInfoPtr pScrn, DisplayModePtr dest,
115472b676d7Smrg                 DisplayModePtr i, DisplayModePtr j,
115572b676d7Smrg		 SiSScrn2Rel srel)
115672b676d7Smrg{
115772b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
115872b676d7Smrg    DisplayModePtr mode;
115972b676d7Smrg    int dx = 0,dy = 0;
116072b676d7Smrg
11615788ca14Smrg    if(!((mode = malloc(sizeof(DisplayModeRec))))) return dest;
116272b676d7Smrg    memcpy(mode, i, sizeof(DisplayModeRec));
11635788ca14Smrg    if(!((mode->Private = malloc(sizeof(SiSMergedDisplayModeRec))))) {
11645788ca14Smrg       free(mode);
116572b676d7Smrg       return dest;
116672b676d7Smrg    }
116772b676d7Smrg    ((SiSMergedDisplayModePtr)mode->Private)->CRT1 = i;
116872b676d7Smrg    ((SiSMergedDisplayModePtr)mode->Private)->CRT2 = j;
116972b676d7Smrg    ((SiSMergedDisplayModePtr)mode->Private)->CRT2Position = srel;
117072b676d7Smrg    mode->PrivSize = 0;
117172b676d7Smrg
117272b676d7Smrg    switch(srel) {
117372b676d7Smrg    case sisLeftOf:
117472b676d7Smrg    case sisRightOf:
117572b676d7Smrg       if(!(pScrn->display->virtualX)) {
117672b676d7Smrg          dx = i->HDisplay + j->HDisplay;
117772b676d7Smrg       } else {
117872b676d7Smrg          dx = min(pScrn->virtualX, i->HDisplay + j->HDisplay);
117972b676d7Smrg       }
118072b676d7Smrg       dx -= mode->HDisplay;
118172b676d7Smrg       if(!(pScrn->display->virtualY)) {
118272b676d7Smrg          dy = max(i->VDisplay, j->VDisplay);
118372b676d7Smrg       } else {
118472b676d7Smrg          dy = min(pScrn->virtualY, max(i->VDisplay, j->VDisplay));
118572b676d7Smrg       }
118672b676d7Smrg       dy -= mode->VDisplay;
118772b676d7Smrg       break;
118872b676d7Smrg    case sisAbove:
118972b676d7Smrg    case sisBelow:
119072b676d7Smrg       if(!(pScrn->display->virtualY)) {
119172b676d7Smrg          dy = i->VDisplay + j->VDisplay;
119272b676d7Smrg       } else {
119372b676d7Smrg          dy = min(pScrn->virtualY, i->VDisplay + j->VDisplay);
119472b676d7Smrg       }
119572b676d7Smrg       dy -= mode->VDisplay;
119672b676d7Smrg       if(!(pScrn->display->virtualX)) {
119772b676d7Smrg          dx = max(i->HDisplay, j->HDisplay);
119872b676d7Smrg       } else {
119972b676d7Smrg          dx = min(pScrn->virtualX, max(i->HDisplay, j->HDisplay));
120072b676d7Smrg       }
120172b676d7Smrg       dx -= mode->HDisplay;
120272b676d7Smrg       break;
120372b676d7Smrg    case sisClone:
120472b676d7Smrg       if(!(pScrn->display->virtualX)) {
120572b676d7Smrg          dx = max(i->HDisplay, j->HDisplay);
120672b676d7Smrg       } else {
120772b676d7Smrg          dx = min(pScrn->virtualX, max(i->HDisplay, j->HDisplay));
120872b676d7Smrg       }
120972b676d7Smrg       dx -= mode->HDisplay;
121072b676d7Smrg       if(!(pScrn->display->virtualY)) {
121172b676d7Smrg          dy = max(i->VDisplay, j->VDisplay);
121272b676d7Smrg       } else {
121372b676d7Smrg	  dy = min(pScrn->virtualY, max(i->VDisplay, j->VDisplay));
121472b676d7Smrg       }
121572b676d7Smrg       dy -= mode->VDisplay;
121672b676d7Smrg       break;
121772b676d7Smrg    }
121872b676d7Smrg    mode->HDisplay += dx;
121972b676d7Smrg    mode->HSyncStart += dx;
122072b676d7Smrg    mode->HSyncEnd += dx;
122172b676d7Smrg    mode->HTotal += dx;
122272b676d7Smrg    mode->VDisplay += dy;
122372b676d7Smrg    mode->VSyncStart += dy;
122472b676d7Smrg    mode->VSyncEnd += dy;
122572b676d7Smrg    mode->VTotal += dy;
122672b676d7Smrg
122772b676d7Smrg    mode->type = M_T_DEFAULT;
122872b676d7Smrg#if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4,2,99,2,0)
122972b676d7Smrg    /* Set up as user defined (ie fake that the mode has been named in the
123072b676d7Smrg     * Modes-list in the screen section; corrects cycling with CTRL-ALT-[-+]
123172b676d7Smrg     * when source mode has not been listed there.)
123272b676d7Smrg     */
123372b676d7Smrg    mode->type |= M_T_USERDEF;
123472b676d7Smrg#endif
123572b676d7Smrg
123672b676d7Smrg    /* Set the VRefresh field (in order to make RandR use it for the rates). We
123772b676d7Smrg     * simply set this to the refresh rate for the CRT1 mode (since CRT2 will
123872b676d7Smrg     * mostly be LCD or TV anyway).
123972b676d7Smrg     */
124072b676d7Smrg    mode->VRefresh = SiSCalcVRate(i);
124172b676d7Smrg
124272b676d7Smrg    if( ((mode->HDisplay * ((pScrn->bitsPerPixel + 7) / 8) * mode->VDisplay) > pSiS->maxxfbmem) ||
124372b676d7Smrg	(mode->HDisplay > 4088) ||
124472b676d7Smrg	(mode->VDisplay > 4096) ) {
124572b676d7Smrg
124672b676d7Smrg       xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
124772b676d7Smrg		"Skipped \"%s\" (%dx%d), not enough video RAM or beyond hardware specs\n",
124872b676d7Smrg		mode->name, mode->HDisplay, mode->VDisplay);
12495788ca14Smrg       free(mode->Private);
12505788ca14Smrg       free(mode);
125172b676d7Smrg
125272b676d7Smrg       return dest;
125372b676d7Smrg    }
125472b676d7Smrg
125572b676d7Smrg#ifdef SISXINERAMA
125672b676d7Smrg    if(srel != sisClone) {
125772b676d7Smrg       pSiS->AtLeastOneNonClone = TRUE;
125872b676d7Smrg    }
125972b676d7Smrg#endif
126072b676d7Smrg
126172b676d7Smrg    /* Now see if the resulting mode would be discarded as a "size" by the
126272b676d7Smrg     * RandR extension, and increase its clock by 1000 in case it does.
126372b676d7Smrg     */
126472b676d7Smrg    if(dest) {
126572b676d7Smrg       DisplayModePtr t = dest;
126672b676d7Smrg       do {
126772b676d7Smrg          if((t->HDisplay == mode->HDisplay) &&
126872b676d7Smrg	     (t->VDisplay == mode->VDisplay) &&
126972b676d7Smrg	     ((int)(t->VRefresh + .5) == (int)(mode->VRefresh + .5))) {
127072b676d7Smrg	     mode->VRefresh += 1000.0;
127172b676d7Smrg	  }
127272b676d7Smrg	  t = t->next;
127372b676d7Smrg       } while((t) && (t != dest));
127472b676d7Smrg    }
127572b676d7Smrg
127672b676d7Smrg    /* Provide a fake but unique DotClock in order to trick the vidmode
127772b676d7Smrg     * extension to allow selecting among a number of modes whose merged result
127872b676d7Smrg     * looks identical but consists of different modes for CRT1 and CRT2
127972b676d7Smrg     */
128072b676d7Smrg    mode->Clock = (int)(mode->VRefresh * 1000.0);
128172b676d7Smrg
128272b676d7Smrg    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
128372b676d7Smrg	"Merged \"%s\" (%dx%d) and \"%s\" (%dx%d) to %dx%d (%d)%s\n",
128472b676d7Smrg	i->name, i->HDisplay, i->VDisplay, j->name, j->HDisplay, j->VDisplay,
128572b676d7Smrg	mode->HDisplay, mode->VDisplay, (int)mode->VRefresh,
128672b676d7Smrg	(srel == sisClone) ? " (Clone)" : "");
128772b676d7Smrg
128872b676d7Smrg    mode->next = mode;
128972b676d7Smrg    mode->prev = mode;
129072b676d7Smrg
129172b676d7Smrg    if(dest) {
129272b676d7Smrg       mode->next = dest->next; 	/* Insert node after "dest" */
129372b676d7Smrg       dest->next->prev = mode;
129472b676d7Smrg       mode->prev = dest;
129572b676d7Smrg       dest->next = mode;
129672b676d7Smrg    }
129772b676d7Smrg
129872b676d7Smrg    return mode;
129972b676d7Smrg}
130072b676d7Smrg
130172b676d7Smrg/* Helper function to find a mode from a given name
130272b676d7Smrg * (Code base taken from mga driver)
130372b676d7Smrg */
130472b676d7Smrgstatic DisplayModePtr
130572b676d7SmrgSiSGetModeFromName(char* str, DisplayModePtr i)
130672b676d7Smrg{
130772b676d7Smrg    DisplayModePtr c = i;
130872b676d7Smrg    if(!i) return NULL;
130972b676d7Smrg    do {
131072b676d7Smrg       if(strcmp(str, c->name) == 0) return c;
131172b676d7Smrg       c = c->next;
131272b676d7Smrg    } while(c != i);
131372b676d7Smrg    return NULL;
131472b676d7Smrg}
131572b676d7Smrg
131672b676d7Smrgstatic DisplayModePtr
131772b676d7SmrgSiSFindWidestTallestMode(DisplayModePtr i, Bool tallest)
131872b676d7Smrg{
131972b676d7Smrg    DisplayModePtr c = i, d = NULL;
132072b676d7Smrg    int max = 0;
132172b676d7Smrg    if(!i) return NULL;
132272b676d7Smrg    do {
132372b676d7Smrg       if(tallest) {
132472b676d7Smrg          if(c->VDisplay > max) {
132572b676d7Smrg	     max = c->VDisplay;
132672b676d7Smrg	     d = c;
132772b676d7Smrg          }
132872b676d7Smrg       } else {
132972b676d7Smrg          if(c->HDisplay > max) {
133072b676d7Smrg	     max = c->HDisplay;
133172b676d7Smrg	     d = c;
133272b676d7Smrg          }
133372b676d7Smrg       }
133472b676d7Smrg       c = c->next;
133572b676d7Smrg    } while(c != i);
133672b676d7Smrg    return d;
133772b676d7Smrg}
133872b676d7Smrg
133972b676d7Smrgstatic void
134072b676d7SmrgSiSFindWidestTallestCommonMode(DisplayModePtr i, DisplayModePtr j, Bool tallest,
134172b676d7Smrg				DisplayModePtr *a, DisplayModePtr *b)
134272b676d7Smrg{
134372b676d7Smrg    DisplayModePtr c = i, d;
134472b676d7Smrg    int max = 0;
134572b676d7Smrg    Bool foundone;
134672b676d7Smrg
134772b676d7Smrg    (*a) = (*b) = NULL;
134872b676d7Smrg
134972b676d7Smrg    if(!i || !j) return;
135072b676d7Smrg
135172b676d7Smrg    do {
135272b676d7Smrg       d = j;
135372b676d7Smrg       foundone = FALSE;
135472b676d7Smrg       do {
135572b676d7Smrg	  if( (c->HDisplay == d->HDisplay) &&
135672b676d7Smrg	      (c->VDisplay == d->VDisplay) ) {
135772b676d7Smrg	     foundone = TRUE;
135872b676d7Smrg	     break;
135972b676d7Smrg	  }
136072b676d7Smrg	  d = d->next;
136172b676d7Smrg       } while(d != j);
136272b676d7Smrg       if(foundone) {
136372b676d7Smrg	  if(tallest) {
136472b676d7Smrg	     if(c->VDisplay > max) {
136572b676d7Smrg		max = c->VDisplay;
136672b676d7Smrg		(*a) = c;
136772b676d7Smrg		(*b) = d;
136872b676d7Smrg	     }
136972b676d7Smrg	  } else {
137072b676d7Smrg	     if(c->HDisplay > max) {
137172b676d7Smrg		max = c->HDisplay;
137272b676d7Smrg		(*a) = c;
137372b676d7Smrg		(*b) = d;
137472b676d7Smrg	     }
137572b676d7Smrg	  }
137672b676d7Smrg       }
137772b676d7Smrg       c = c->next;
137872b676d7Smrg    } while(c != i);
137972b676d7Smrg}
138072b676d7Smrg
138172b676d7Smrgstatic DisplayModePtr
138272b676d7SmrgSiSGenerateModeListFromLargestModes(ScrnInfoPtr pScrn,
138372b676d7Smrg		    DisplayModePtr i, DisplayModePtr j,
138472b676d7Smrg		    SiSScrn2Rel srel)
138572b676d7Smrg{
138672b676d7Smrg#ifdef SISXINERAMA
138772b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
138872b676d7Smrg#endif
138972b676d7Smrg    DisplayModePtr mode1 = NULL;
139072b676d7Smrg    DisplayModePtr mode2 = NULL;
139172b676d7Smrg    DisplayModePtr mode3 = NULL;
139272b676d7Smrg    DisplayModePtr mode4 = NULL;
139372b676d7Smrg    DisplayModePtr result = NULL;
139472b676d7Smrg
139572b676d7Smrg#ifdef SISXINERAMA
139672b676d7Smrg    pSiS->AtLeastOneNonClone = FALSE;
139772b676d7Smrg#endif
139872b676d7Smrg
139972b676d7Smrg    /* Now build a default list of MetaModes.
140072b676d7Smrg     * - Non-clone: If the user enabled NonRectangular, we use the
140172b676d7Smrg     * largest mode for each CRT1 and CRT2. If not, we use the largest
140272b676d7Smrg     * common mode for CRT1 and CRT2 (if available). Additionally, and
140372b676d7Smrg     * regardless if the above, we produce a clone mode consisting of
140472b676d7Smrg     * the largest common mode (if available) in order to use DGA.
140572b676d7Smrg     * - Clone: If the (global) CRT2Position is Clone, we use the
140672b676d7Smrg     * largest common mode if available, otherwise the first two modes
140772b676d7Smrg     * in each list.
140872b676d7Smrg     */
140972b676d7Smrg
141072b676d7Smrg    switch(srel) {
141172b676d7Smrg    case sisLeftOf:
141272b676d7Smrg    case sisRightOf:
141372b676d7Smrg       mode1 = SiSFindWidestTallestMode(i, FALSE);
141472b676d7Smrg       mode2 = SiSFindWidestTallestMode(j, FALSE);
141572b676d7Smrg       SiSFindWidestTallestCommonMode(i, j, FALSE, &mode3, &mode4);
141672b676d7Smrg       break;
141772b676d7Smrg    case sisAbove:
141872b676d7Smrg    case sisBelow:
141972b676d7Smrg       mode1 = SiSFindWidestTallestMode(i, TRUE);
142072b676d7Smrg       mode2 = SiSFindWidestTallestMode(j, TRUE);
142172b676d7Smrg       SiSFindWidestTallestCommonMode(i, j, TRUE, &mode3, &mode4);
142272b676d7Smrg       break;
142372b676d7Smrg    case sisClone:
142472b676d7Smrg       SiSFindWidestTallestCommonMode(i, j, FALSE, &mode3, &mode4);
142572b676d7Smrg       if(mode3 && mode4) {
142672b676d7Smrg	  mode1 = mode3;
142772b676d7Smrg	  mode2 = mode4;
142872b676d7Smrg       } else {
142972b676d7Smrg	  mode1 = i;
143072b676d7Smrg	  mode2 = j;
143172b676d7Smrg       }
143272b676d7Smrg    }
143372b676d7Smrg
143472b676d7Smrg    if(srel != sisClone) {
143572b676d7Smrg       if(mode3 && mode4 && !pSiS->NonRect) {
143672b676d7Smrg	  mode1 = mode3;
143772b676d7Smrg	  mode2 = mode2;
143872b676d7Smrg       }
143972b676d7Smrg    }
144072b676d7Smrg
144172b676d7Smrg    if(mode1 && mode2) {
144272b676d7Smrg       result = SiSCopyModeNLink(pScrn, result, mode1, mode2, srel);
144372b676d7Smrg    }
144472b676d7Smrg
144572b676d7Smrg    if(srel != sisClone) {
144672b676d7Smrg       if(mode3 && mode4) {
144772b676d7Smrg	  result = SiSCopyModeNLink(pScrn, result, mode3, mode4, sisClone);
144872b676d7Smrg       }
144972b676d7Smrg    }
145072b676d7Smrg
145172b676d7Smrg    return result;
145272b676d7Smrg}
145372b676d7Smrg
145472b676d7Smrg/* Generate the merged-fb mode modelist
145572b676d7Smrg * (Taken from mga driver)
145672b676d7Smrg */
145772b676d7Smrgstatic DisplayModePtr
145872b676d7SmrgSiSGenerateModeListFromMetaModes(ScrnInfoPtr pScrn, char* str,
145972b676d7Smrg		    DisplayModePtr i, DisplayModePtr j,
146072b676d7Smrg		    SiSScrn2Rel srel)
146172b676d7Smrg{
146272b676d7Smrg#ifdef SISXINERAMA
146372b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
146472b676d7Smrg#endif
146572b676d7Smrg    char* strmode = str;
146672b676d7Smrg    char modename[256];
146772b676d7Smrg    Bool gotdash = FALSE;
146872b676d7Smrg    char gotsep = 0;
146972b676d7Smrg    SiSScrn2Rel sr;
147072b676d7Smrg    DisplayModePtr mode1 = NULL;
147172b676d7Smrg    DisplayModePtr mode2 = NULL;
147272b676d7Smrg    DisplayModePtr result = NULL;
147372b676d7Smrg    int myslen;
147472b676d7Smrg
147572b676d7Smrg#ifdef SISXINERAMA
147672b676d7Smrg    pSiS->AtLeastOneNonClone = FALSE;
147772b676d7Smrg#endif
147872b676d7Smrg
147972b676d7Smrg    do {
148072b676d7Smrg        switch(*str) {
148172b676d7Smrg        case 0:
148272b676d7Smrg        case '-':
148372b676d7Smrg	case '+':
148472b676d7Smrg        case ' ':
148572b676d7Smrg	case ',':
148672b676d7Smrg	case ';':
148772b676d7Smrg           if(strmode != str) {
148872b676d7Smrg
148972b676d7Smrg              myslen = str - strmode;
149072b676d7Smrg              if(myslen > 255) myslen = 255;
149172b676d7Smrg  	      strncpy(modename, strmode, myslen);
149272b676d7Smrg  	      modename[myslen] = 0;
149372b676d7Smrg
149472b676d7Smrg              if(gotdash) {
149572b676d7Smrg                 if(mode1 == NULL) {
149672b676d7Smrg  	             xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
149772b676d7Smrg  	                        "Error parsing MetaModes parameter\n");
149872b676d7Smrg  	             return NULL;
149972b676d7Smrg  	         }
150072b676d7Smrg                 mode2 = SiSGetModeFromName(modename, j);
150172b676d7Smrg                 if(!mode2) {
150272b676d7Smrg                    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
150372b676d7Smrg                        "Mode \"%s\" is not a supported mode for CRT2\n", modename);
150472b676d7Smrg                    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
150572b676d7Smrg                        "\t(Skipping metamode \"%s%c%s\")\n", mode1->name, gotsep, modename);
150672b676d7Smrg                    mode1 = NULL;
150772b676d7Smrg		    gotsep = 0;
150872b676d7Smrg                 }
150972b676d7Smrg              } else {
151072b676d7Smrg                 mode1 = SiSGetModeFromName(modename, i);
151172b676d7Smrg                 if(!mode1) {
151272b676d7Smrg                    char* tmps = str;
151372b676d7Smrg                    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
151472b676d7Smrg                        "Mode \"%s\" is not a supported mode for CRT1\n", modename);
151572b676d7Smrg                    while(*tmps == ' ' || *tmps == ';') tmps++;
151672b676d7Smrg                    /* skip the next mode */
151772b676d7Smrg  	            if(*tmps == '-' || *tmps == '+' || *tmps == ',') {
151872b676d7Smrg                       tmps++;
151972b676d7Smrg		       /* skip spaces */
152072b676d7Smrg		       while(*tmps == ' ' || *tmps == ';') tmps++;
152172b676d7Smrg		       /* skip modename */
152272b676d7Smrg		       while(*tmps && *tmps != ' ' && *tmps != ';' && *tmps != '-' && *tmps != '+' && *tmps != ',') tmps++;
152372b676d7Smrg  	               myslen = tmps - strmode;
152472b676d7Smrg  	               if(myslen > 255) myslen = 255;
152572b676d7Smrg  	               strncpy(modename,strmode,myslen);
152672b676d7Smrg  	               modename[myslen] = 0;
152772b676d7Smrg                       str = tmps - 1;
152872b676d7Smrg                    }
152972b676d7Smrg                    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
153072b676d7Smrg                        "\t(Skipping metamode \"%s\")\n", modename);
153172b676d7Smrg                    mode1 = NULL;
153272b676d7Smrg		    gotsep = 0;
153372b676d7Smrg                 }
153472b676d7Smrg              }
153572b676d7Smrg              gotdash = FALSE;
153672b676d7Smrg           }
153772b676d7Smrg           strmode = str + 1;
153872b676d7Smrg           gotdash |= (*str == '-' || *str == '+' || *str == ',');
153972b676d7Smrg	   if (*str == '-' || *str == '+' || *str == ',')
154072b676d7Smrg  	      gotsep = *str;
154172b676d7Smrg
154272b676d7Smrg           if(*str != 0) break;
154372b676d7Smrg	   /* Fall through otherwise */
154472b676d7Smrg
154572b676d7Smrg        default:
154672b676d7Smrg           if(!gotdash && mode1) {
154772b676d7Smrg              sr = srel;
154872b676d7Smrg	      if(gotsep == '+') sr = sisClone;
154972b676d7Smrg              if(!mode2) {
155072b676d7Smrg                 mode2 = SiSGetModeFromName(mode1->name, j);
155172b676d7Smrg                 sr = sisClone;
155272b676d7Smrg              }
155372b676d7Smrg              if(!mode2) {
155472b676d7Smrg                 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
155572b676d7Smrg                     "Mode \"%s\" is not a supported mode for CRT2\n", mode1->name);
155672b676d7Smrg                 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
155772b676d7Smrg                     "\t(Skipping metamode \"%s\")\n", modename);
155872b676d7Smrg                 mode1 = NULL;
155972b676d7Smrg              } else {
156072b676d7Smrg                 result = SiSCopyModeNLink(pScrn, result, mode1, mode2, sr);
156172b676d7Smrg                 mode1 = NULL;
156272b676d7Smrg                 mode2 = NULL;
156372b676d7Smrg              }
156472b676d7Smrg	      gotsep = 0;
156572b676d7Smrg           }
156672b676d7Smrg           break;
156772b676d7Smrg
156872b676d7Smrg        }
156972b676d7Smrg
157072b676d7Smrg    } while(*(str++) != 0);
157172b676d7Smrg
157272b676d7Smrg    return result;
157372b676d7Smrg}
157472b676d7Smrg
157572b676d7Smrgstatic DisplayModePtr
157672b676d7SmrgSiSGenerateModeList(ScrnInfoPtr pScrn, char* str,
157772b676d7Smrg		    DisplayModePtr i, DisplayModePtr j,
157872b676d7Smrg		    SiSScrn2Rel srel)
157972b676d7Smrg{
158072b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
158172b676d7Smrg
158272b676d7Smrg   if(str != NULL) {
158372b676d7Smrg      return(SiSGenerateModeListFromMetaModes(pScrn, str, i, j, srel));
158472b676d7Smrg   } else {
158572b676d7Smrg      xf86DrvMsg(pScrn->scrnIndex, X_INFO,
158672b676d7Smrg	"No MetaModes given, linking %s modes by default\n",
158772b676d7Smrg	(srel == sisClone) ? "largest common" :
158872b676d7Smrg	   (pSiS->NonRect ?
158972b676d7Smrg		(((srel == sisLeftOf) || (srel == sisRightOf)) ? "widest" :  "tallest")
159072b676d7Smrg		:
159172b676d7Smrg		(((srel == sisLeftOf) || (srel == sisRightOf)) ? "widest common" :  "tallest common")) );
159272b676d7Smrg      return(SiSGenerateModeListFromLargestModes(pScrn, i, j, srel));
159372b676d7Smrg   }
159472b676d7Smrg}
159572b676d7Smrg
159672b676d7Smrgstatic void
159772b676d7SmrgSiSRecalcDefaultVirtualSize(ScrnInfoPtr pScrn)
159872b676d7Smrg{
159972b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
160072b676d7Smrg    DisplayModePtr mode, bmode;
160172b676d7Smrg    int maxh, maxv;
160272b676d7Smrg    static const char *str = "MergedFB: Virtual %s %d\n";
160372b676d7Smrg    static const char *errstr = "Virtual %s to small for given CRT2Position offset\n";
160472b676d7Smrg
160572b676d7Smrg    mode = bmode = pScrn->modes;
160672b676d7Smrg    maxh = maxv = 0;
160772b676d7Smrg    do {
160872b676d7Smrg       if(mode->HDisplay > maxh) maxh = mode->HDisplay;
160972b676d7Smrg       if(mode->VDisplay > maxv) maxv = mode->VDisplay;
161072b676d7Smrg       mode = mode->next;
161172b676d7Smrg    } while(mode != bmode);
161272b676d7Smrg
161372b676d7Smrg    maxh += pSiS->CRT1XOffs + pSiS->CRT2XOffs;
161472b676d7Smrg    maxv += pSiS->CRT1YOffs + pSiS->CRT2YOffs;
161572b676d7Smrg
161672b676d7Smrg    if(!(pScrn->display->virtualX)) {
161772b676d7Smrg       if(maxh > 4088) {
161872b676d7Smrg	  xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
161972b676d7Smrg		"Virtual width with CRT2Position offset beyond hardware specs\n");
162072b676d7Smrg	  pSiS->CRT1XOffs = pSiS->CRT2XOffs = 0;
162172b676d7Smrg	  maxh -= (pSiS->CRT1XOffs + pSiS->CRT2XOffs);
162272b676d7Smrg       }
162372b676d7Smrg       pScrn->virtualX = maxh;
162472b676d7Smrg       pScrn->displayWidth = maxh;
162572b676d7Smrg       xf86DrvMsg(pScrn->scrnIndex, X_PROBED, str, "width", maxh);
162672b676d7Smrg    } else {
162772b676d7Smrg       if(maxh < pScrn->display->virtualX) {
162872b676d7Smrg	  xf86DrvMsg(pScrn->scrnIndex, X_ERROR, errstr, "width");
162972b676d7Smrg	  pSiS->CRT1XOffs = pSiS->CRT2XOffs = 0;
163072b676d7Smrg       }
163172b676d7Smrg    }
163272b676d7Smrg
163372b676d7Smrg    if(!(pScrn->display->virtualY)) {
163472b676d7Smrg       pScrn->virtualY = maxv;
163572b676d7Smrg       xf86DrvMsg(pScrn->scrnIndex, X_PROBED, str, "height", maxv);
163672b676d7Smrg    } else {
163772b676d7Smrg       if(maxv < pScrn->display->virtualY) {
163872b676d7Smrg	  xf86DrvMsg(pScrn->scrnIndex, X_ERROR, errstr, "height");
163972b676d7Smrg	  pSiS->CRT1YOffs = pSiS->CRT2YOffs = 0;
164072b676d7Smrg       }
164172b676d7Smrg    }
164272b676d7Smrg}
164372b676d7Smrg
164472b676d7Smrgstatic void
164572b676d7SmrgSiSMergedFBSetDpi(ScrnInfoPtr pScrn1, ScrnInfoPtr pScrn2, SiSScrn2Rel srel)
164672b676d7Smrg{
164772b676d7Smrg   SISPtr pSiS = SISPTR(pScrn1);
164872b676d7Smrg   MessageType from = X_DEFAULT;
164972b676d7Smrg   xf86MonPtr DDC1 = (xf86MonPtr)(pScrn1->monitor->DDC);
165072b676d7Smrg   xf86MonPtr DDC2 = (xf86MonPtr)(pScrn2->monitor->DDC);
165172b676d7Smrg   int ddcWidthmm = 0, ddcHeightmm = 0;
165272b676d7Smrg   const char *dsstr = "MergedFB: Display dimensions: (%d, %d) mm\n";
165372b676d7Smrg
165472b676d7Smrg   /* This sets the DPI for MergedFB mode. The problem is that
165572b676d7Smrg    * this can never be exact, because the output devices may
165672b676d7Smrg    * have different dimensions. This function tries to compromise
165772b676d7Smrg    * through a few assumptions, and it just calculates an average DPI
165872b676d7Smrg    * value for both monitors.
165972b676d7Smrg    */
166072b676d7Smrg
166172b676d7Smrg   /* Given DisplaySize should regard BOTH monitors */
166272b676d7Smrg   pScrn1->widthmm = pScrn1->monitor->widthmm;
166372b676d7Smrg   pScrn1->heightmm = pScrn1->monitor->heightmm;
166472b676d7Smrg
166572b676d7Smrg   /* Get DDC display size; if only either CRT1 or CRT2 provided these,
166672b676d7Smrg    * assume equal dimensions for both, otherwise add dimensions
166772b676d7Smrg    */
166872b676d7Smrg   if( (DDC1 && (DDC1->features.hsize > 0 && DDC1->features.vsize > 0)) &&
166972b676d7Smrg       (DDC2 && (DDC2->features.hsize > 0 && DDC2->features.vsize > 0)) ) {
167072b676d7Smrg      ddcWidthmm = max(DDC1->features.hsize, DDC2->features.hsize) * 10;
167172b676d7Smrg      ddcHeightmm = max(DDC1->features.vsize, DDC2->features.vsize) * 10;
167272b676d7Smrg      switch(srel) {
167372b676d7Smrg      case sisLeftOf:
167472b676d7Smrg      case sisRightOf:
167572b676d7Smrg	 ddcWidthmm = (DDC1->features.hsize + DDC2->features.hsize) * 10;
167672b676d7Smrg	 break;
167772b676d7Smrg      case sisAbove:
167872b676d7Smrg      case sisBelow:
167972b676d7Smrg	 ddcHeightmm = (DDC1->features.vsize + DDC2->features.vsize) * 10;
168072b676d7Smrg      default:
168172b676d7Smrg	 break;
168272b676d7Smrg      }
168372b676d7Smrg   } else if(DDC1 && (DDC1->features.hsize > 0 && DDC1->features.vsize > 0)) {
168472b676d7Smrg      ddcWidthmm = DDC1->features.hsize * 10;
168572b676d7Smrg      ddcHeightmm = DDC1->features.vsize * 10;
168672b676d7Smrg      switch(srel) {
168772b676d7Smrg      case sisLeftOf:
168872b676d7Smrg      case sisRightOf:
168972b676d7Smrg	 ddcWidthmm *= 2;
169072b676d7Smrg	 break;
169172b676d7Smrg      case sisAbove:
169272b676d7Smrg      case sisBelow:
169372b676d7Smrg	 ddcHeightmm *= 2;
169472b676d7Smrg      default:
169572b676d7Smrg	 break;
169672b676d7Smrg      }
169772b676d7Smrg   } else if(DDC2 && (DDC2->features.hsize > 0 && DDC2->features.vsize > 0) ) {
169872b676d7Smrg      ddcWidthmm = DDC2->features.hsize * 10;
169972b676d7Smrg      ddcHeightmm = DDC2->features.vsize * 10;
170072b676d7Smrg      switch(srel) {
170172b676d7Smrg      case sisLeftOf:
170272b676d7Smrg      case sisRightOf:
170372b676d7Smrg	 ddcWidthmm *= 2;
170472b676d7Smrg	 break;
170572b676d7Smrg      case sisAbove:
170672b676d7Smrg      case sisBelow:
170772b676d7Smrg	 ddcHeightmm *= 2;
170872b676d7Smrg      default:
170972b676d7Smrg	 break;
171072b676d7Smrg      }
171172b676d7Smrg   }
171272b676d7Smrg
171372b676d7Smrg   if(monitorResolution > 0) {
171472b676d7Smrg
171572b676d7Smrg      /* Set command line given values (overrules given options) */
171672b676d7Smrg      pScrn1->xDpi = monitorResolution;
171772b676d7Smrg      pScrn1->yDpi = monitorResolution;
171872b676d7Smrg      from = X_CMDLINE;
171972b676d7Smrg
172072b676d7Smrg   } else if(pSiS->MergedFBXDPI) {
172172b676d7Smrg
172272b676d7Smrg      /* Set option-wise given values (overrule DisplaySize) */
172372b676d7Smrg      pScrn1->xDpi = pSiS->MergedFBXDPI;
172472b676d7Smrg      pScrn1->yDpi = pSiS->MergedFBYDPI;
172572b676d7Smrg      from = X_CONFIG;
172672b676d7Smrg
172772b676d7Smrg   } else if(pScrn1->widthmm > 0 || pScrn1->heightmm > 0) {
172872b676d7Smrg
172972b676d7Smrg      /* Set values calculated from given DisplaySize */
173072b676d7Smrg      from = X_CONFIG;
173172b676d7Smrg      if(pScrn1->widthmm > 0) {
173272b676d7Smrg	 pScrn1->xDpi = (int)((double)pScrn1->virtualX * 25.4 / pScrn1->widthmm);
173372b676d7Smrg      }
173472b676d7Smrg      if(pScrn1->heightmm > 0) {
173572b676d7Smrg	 pScrn1->yDpi = (int)((double)pScrn1->virtualY * 25.4 / pScrn1->heightmm);
173672b676d7Smrg      }
173772b676d7Smrg      xf86DrvMsg(pScrn1->scrnIndex, from, dsstr, pScrn1->widthmm, pScrn1->heightmm);
173872b676d7Smrg
173972b676d7Smrg    } else if(ddcWidthmm && ddcHeightmm) {
174072b676d7Smrg
174172b676d7Smrg      /* Set values from DDC-provided display size */
174272b676d7Smrg      from = X_PROBED;
174372b676d7Smrg      xf86DrvMsg(pScrn1->scrnIndex, from, dsstr, ddcWidthmm, ddcHeightmm );
174472b676d7Smrg      pScrn1->widthmm = ddcWidthmm;
174572b676d7Smrg      pScrn1->heightmm = ddcHeightmm;
174672b676d7Smrg      if(pScrn1->widthmm > 0) {
174772b676d7Smrg	 pScrn1->xDpi = (int)((double)pScrn1->virtualX * 25.4 / pScrn1->widthmm);
174872b676d7Smrg      }
174972b676d7Smrg      if(pScrn1->heightmm > 0) {
175072b676d7Smrg	 pScrn1->yDpi = (int)((double)pScrn1->virtualY * 25.4 / pScrn1->heightmm);
175172b676d7Smrg      }
175272b676d7Smrg
175372b676d7Smrg    } else {
175472b676d7Smrg
175572b676d7Smrg      pScrn1->xDpi = pScrn1->yDpi = DEFAULT_DPI;
175672b676d7Smrg
175772b676d7Smrg    }
175872b676d7Smrg
175972b676d7Smrg    /* Sanity check */
176072b676d7Smrg    if(pScrn1->xDpi > 0 && pScrn1->yDpi <= 0)
176172b676d7Smrg       pScrn1->yDpi = pScrn1->xDpi;
176272b676d7Smrg    if(pScrn1->yDpi > 0 && pScrn1->xDpi <= 0)
176372b676d7Smrg       pScrn1->xDpi = pScrn1->yDpi;
176472b676d7Smrg
176572b676d7Smrg    pScrn2->xDpi = pScrn1->xDpi;
176672b676d7Smrg    pScrn2->yDpi = pScrn1->yDpi;
176772b676d7Smrg
176872b676d7Smrg    xf86DrvMsg(pScrn1->scrnIndex, from, "MergedFB: DPI set to (%d, %d)\n",
176972b676d7Smrg		pScrn1->xDpi, pScrn1->yDpi);
177072b676d7Smrg}
177172b676d7Smrg
177272b676d7Smrg/* Pseudo-Xinerama extension for MergedFB mode */
177372b676d7Smrg#ifdef SISXINERAMA
177472b676d7Smrg
177572b676d7Smrgstatic void
177672b676d7SmrgSiSUpdateXineramaScreenInfo(ScrnInfoPtr pScrn1)
177772b676d7Smrg{
177872b676d7Smrg    SISPtr pSiS = SISPTR(pScrn1);
177972b676d7Smrg    int crt1scrnnum = 0, crt2scrnnum = 1;
178072b676d7Smrg    int x1=0, x2=0, y1=0, y2=0, h1=0, h2=0, w1=0, w2=0;
178172b676d7Smrg    int realvirtX, realvirtY;
178272b676d7Smrg    DisplayModePtr currentMode, firstMode;
178372b676d7Smrg    Bool infochanged = FALSE;
178472b676d7Smrg    Bool usenonrect = pSiS->NonRect;
1785721a3bc8Sjoerg    static const char rectxine[] = "\t... setting up rectangular Xinerama layout\n";
178672b676d7Smrg
178772b676d7Smrg    pSiS->MBXNR1XMAX = pSiS->MBXNR1YMAX = pSiS->MBXNR2XMAX = pSiS->MBXNR2YMAX = 65536;
178872b676d7Smrg    pSiS->HaveNonRect = pSiS->HaveOffsRegions = FALSE;
178972b676d7Smrg
179072b676d7Smrg    if(!pSiS->MergedFB) return;
179172b676d7Smrg
179272b676d7Smrg    if(SiSnoPanoramiXExtension) return;
179372b676d7Smrg
179472b676d7Smrg    if(!SiSXineramadataPtr) return;
179572b676d7Smrg
179672b676d7Smrg    if(pSiS->CRT2IsScrn0) {
179772b676d7Smrg       crt1scrnnum = 1;
179872b676d7Smrg       crt2scrnnum = 0;
179972b676d7Smrg    }
180072b676d7Smrg
180172b676d7Smrg    /* Attention: Usage of RandR may lead to virtual X and Y dimensions
180272b676d7Smrg     * actually smaller than our MetaModes. To avoid this, we calculate
180372b676d7Smrg     * the maxCRT fields here (and not somewhere else, like in CopyNLink)
180472b676d7Smrg     *
180572b676d7Smrg     * *** Note: RandR is disabled if one of CRTxxOffs is non-zero.
180672b676d7Smrg     */
180772b676d7Smrg
180872b676d7Smrg    /* "Real" virtual: Virtual without the Offset */
180972b676d7Smrg    realvirtX = pScrn1->virtualX - pSiS->CRT1XOffs - pSiS->CRT2XOffs;
181072b676d7Smrg    realvirtY = pScrn1->virtualY - pSiS->CRT1YOffs - pSiS->CRT2YOffs;
181172b676d7Smrg
181272b676d7Smrg    if((pSiS->SiSXineramaVX != pScrn1->virtualX) || (pSiS->SiSXineramaVY != pScrn1->virtualY)) {
181372b676d7Smrg
181472b676d7Smrg       if(!(pScrn1->modes)) return;
181572b676d7Smrg
181672b676d7Smrg       pSiS->maxCRT1_X1 = pSiS->maxCRT1_X2 = 0;
181772b676d7Smrg       pSiS->maxCRT1_Y1 = pSiS->maxCRT1_Y2 = 0;
181872b676d7Smrg       pSiS->maxCRT2_X1 = pSiS->maxCRT2_X2 = 0;
181972b676d7Smrg       pSiS->maxCRT2_Y1 = pSiS->maxCRT2_Y2 = 0;
182072b676d7Smrg       pSiS->maxClone_X1 = pSiS->maxClone_X2 = 0;
182172b676d7Smrg       pSiS->maxClone_Y1 = pSiS->maxClone_Y2 = 0;
182272b676d7Smrg
182372b676d7Smrg       currentMode = firstMode = pScrn1->modes;
182472b676d7Smrg
182572b676d7Smrg       do {
182672b676d7Smrg
182772b676d7Smrg          DisplayModePtr p = currentMode->next;
182872b676d7Smrg          DisplayModePtr i = ((SiSMergedDisplayModePtr)currentMode->Private)->CRT1;
182972b676d7Smrg          DisplayModePtr j = ((SiSMergedDisplayModePtr)currentMode->Private)->CRT2;
183072b676d7Smrg          SiSScrn2Rel srel = ((SiSMergedDisplayModePtr)currentMode->Private)->CRT2Position;
183172b676d7Smrg
183272b676d7Smrg          if((currentMode->HDisplay <= realvirtX) && (currentMode->VDisplay <= realvirtY) &&
183372b676d7Smrg	     (i->HDisplay <= realvirtX) && (j->HDisplay <= realvirtX) &&
183472b676d7Smrg	     (i->VDisplay <= realvirtY) && (j->VDisplay <= realvirtY)) {
183572b676d7Smrg
183672b676d7Smrg	     if(srel != sisClone) {
183772b676d7Smrg		if(pSiS->maxCRT1_X1 == i->HDisplay) {
183872b676d7Smrg		   if(pSiS->maxCRT1_X2 < j->HDisplay) {
183972b676d7Smrg		      pSiS->maxCRT1_X2 = j->HDisplay;   /* Widest CRT2 mode displayed with widest CRT1 mode */
184072b676d7Smrg		   }
184172b676d7Smrg		} else if(pSiS->maxCRT1_X1 < i->HDisplay) {
184272b676d7Smrg		   pSiS->maxCRT1_X1 = i->HDisplay;      /* Widest CRT1 mode */
184372b676d7Smrg		   pSiS->maxCRT1_X2 = j->HDisplay;
184472b676d7Smrg		}
184572b676d7Smrg		if(pSiS->maxCRT2_X2 == j->HDisplay) {
184672b676d7Smrg		   if(pSiS->maxCRT2_X1 < i->HDisplay) {
184772b676d7Smrg		      pSiS->maxCRT2_X1 = i->HDisplay;   /* Widest CRT1 mode displayed with widest CRT2 mode */
184872b676d7Smrg		   }
184972b676d7Smrg		} else if(pSiS->maxCRT2_X2 < j->HDisplay) {
185072b676d7Smrg		   pSiS->maxCRT2_X2 = j->HDisplay;      /* Widest CRT2 mode */
185172b676d7Smrg		   pSiS->maxCRT2_X1 = i->HDisplay;
185272b676d7Smrg		}
185372b676d7Smrg		if(pSiS->maxCRT1_Y1 == i->VDisplay) {   /* Same as above, but tallest instead of widest */
185472b676d7Smrg		   if(pSiS->maxCRT1_Y2 < j->VDisplay) {
185572b676d7Smrg		      pSiS->maxCRT1_Y2 = j->VDisplay;
185672b676d7Smrg		   }
185772b676d7Smrg		} else if(pSiS->maxCRT1_Y1 < i->VDisplay) {
185872b676d7Smrg		   pSiS->maxCRT1_Y1 = i->VDisplay;
185972b676d7Smrg		   pSiS->maxCRT1_Y2 = j->VDisplay;
186072b676d7Smrg		}
186172b676d7Smrg		if(pSiS->maxCRT2_Y2 == j->VDisplay) {
186272b676d7Smrg		   if(pSiS->maxCRT2_Y1 < i->VDisplay) {
186372b676d7Smrg		      pSiS->maxCRT2_Y1 = i->VDisplay;
186472b676d7Smrg		   }
186572b676d7Smrg		} else if(pSiS->maxCRT2_Y2 < j->VDisplay) {
186672b676d7Smrg		   pSiS->maxCRT2_Y2 = j->VDisplay;
186772b676d7Smrg		   pSiS->maxCRT2_Y1 = i->VDisplay;
186872b676d7Smrg		}
186972b676d7Smrg	     } else {
187072b676d7Smrg		if(pSiS->maxClone_X1 < i->HDisplay) {
187172b676d7Smrg		   pSiS->maxClone_X1 = i->HDisplay;
187272b676d7Smrg		}
187372b676d7Smrg		if(pSiS->maxClone_X2 < j->HDisplay) {
187472b676d7Smrg		   pSiS->maxClone_X2 = j->HDisplay;
187572b676d7Smrg		}
187672b676d7Smrg		if(pSiS->maxClone_Y1 < i->VDisplay) {
187772b676d7Smrg		   pSiS->maxClone_Y1 = i->VDisplay;
187872b676d7Smrg		}
187972b676d7Smrg		if(pSiS->maxClone_Y2 < j->VDisplay) {
188072b676d7Smrg		   pSiS->maxClone_Y2 = j->VDisplay;
188172b676d7Smrg		}
188272b676d7Smrg	     }
188372b676d7Smrg	  }
188472b676d7Smrg	  currentMode = p;
188572b676d7Smrg
188672b676d7Smrg       } while((currentMode) && (currentMode != firstMode));
188772b676d7Smrg
188872b676d7Smrg       pSiS->SiSXineramaVX = pScrn1->virtualX;
188972b676d7Smrg       pSiS->SiSXineramaVY = pScrn1->virtualY;
189072b676d7Smrg       infochanged = TRUE;
189172b676d7Smrg
189272b676d7Smrg    }
189372b676d7Smrg
189472b676d7Smrg    if((usenonrect) && (pSiS->CRT2Position != sisClone) && pSiS->maxCRT1_X1) {
189572b676d7Smrg       switch(pSiS->CRT2Position) {
189672b676d7Smrg       case sisLeftOf:
189772b676d7Smrg       case sisRightOf:
189872b676d7Smrg	  if((pSiS->maxCRT1_Y1 != realvirtY) && (pSiS->maxCRT2_Y2 != realvirtY)) {
189972b676d7Smrg	     usenonrect = FALSE;
190072b676d7Smrg	  }
190172b676d7Smrg	  break;
190272b676d7Smrg       case sisAbove:
190372b676d7Smrg       case sisBelow:
190472b676d7Smrg	  if((pSiS->maxCRT1_X1 != realvirtX) && (pSiS->maxCRT2_X2 != realvirtX)) {
190572b676d7Smrg	     usenonrect = FALSE;
190672b676d7Smrg	  }
190772b676d7Smrg	  break;
190872b676d7Smrg       case sisClone:
190972b676d7Smrg	  break;
191072b676d7Smrg       }
191172b676d7Smrg       if(infochanged && !usenonrect) {
191272b676d7Smrg	  xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
191372b676d7Smrg			"Virtual screen size does not match maximum display modes...\n");
191472b676d7Smrg	  xf86DrvMsg(pScrn1->scrnIndex, X_INFO, rectxine);
191572b676d7Smrg
191672b676d7Smrg       }
191772b676d7Smrg    } else if(infochanged && usenonrect) {
191872b676d7Smrg       usenonrect = FALSE;
191972b676d7Smrg       xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
192072b676d7Smrg		"Only clone modes available for this virtual screen size...\n");
192172b676d7Smrg       xf86DrvMsg(pScrn1->scrnIndex, X_INFO, rectxine);
192272b676d7Smrg    }
192372b676d7Smrg
192472b676d7Smrg    if(pSiS->maxCRT1_X1) {		/* Means we have at least one non-clone mode */
192572b676d7Smrg       switch(pSiS->CRT2Position) {
192672b676d7Smrg       case sisLeftOf:
192772b676d7Smrg	  x1 = min(pSiS->maxCRT1_X2, pScrn1->virtualX - pSiS->maxCRT1_X1);
192872b676d7Smrg	  if(x1 < 0) x1 = 0;
192972b676d7Smrg	  y1 = pSiS->CRT1YOffs;
193072b676d7Smrg	  w1 = pScrn1->virtualX - x1;
193172b676d7Smrg	  h1 = realvirtY;
193272b676d7Smrg	  if((usenonrect) && (pSiS->maxCRT1_Y1 != realvirtY)) {
193372b676d7Smrg	     h1 = pSiS->MBXNR1YMAX = pSiS->maxCRT1_Y1;
193472b676d7Smrg	     pSiS->NonRectDead.x0 = x1;
193572b676d7Smrg	     pSiS->NonRectDead.x1 = x1 + w1 - 1;
193672b676d7Smrg	     pSiS->NonRectDead.y0 = y1 + h1;
193772b676d7Smrg	     pSiS->NonRectDead.y1 = pScrn1->virtualY - 1;
193872b676d7Smrg	     pSiS->HaveNonRect = TRUE;
193972b676d7Smrg	  }
194072b676d7Smrg	  x2 = 0;
194172b676d7Smrg	  y2 = pSiS->CRT2YOffs;
194272b676d7Smrg	  w2 = max(pSiS->maxCRT2_X2, pScrn1->virtualX - pSiS->maxCRT2_X1);
194372b676d7Smrg	  if(w2 > pScrn1->virtualX) w2 = pScrn1->virtualX;
194472b676d7Smrg	  h2 = realvirtY;
194572b676d7Smrg	  if((usenonrect) && (pSiS->maxCRT2_Y2 != realvirtY)) {
194672b676d7Smrg	     h2 = pSiS->MBXNR2YMAX = pSiS->maxCRT2_Y2;
194772b676d7Smrg	     pSiS->NonRectDead.x0 = x2;
194872b676d7Smrg	     pSiS->NonRectDead.x1 = x2 + w2 - 1;
194972b676d7Smrg	     pSiS->NonRectDead.y0 = y2 + h2;
195072b676d7Smrg	     pSiS->NonRectDead.y1 = pScrn1->virtualY - 1;
195172b676d7Smrg	     pSiS->HaveNonRect = TRUE;
195272b676d7Smrg	  }
195372b676d7Smrg	  break;
195472b676d7Smrg       case sisRightOf:
195572b676d7Smrg	  x1 = 0;
195672b676d7Smrg	  y1 = pSiS->CRT1YOffs;
195772b676d7Smrg	  w1 = max(pSiS->maxCRT1_X1, pScrn1->virtualX - pSiS->maxCRT1_X2);
195872b676d7Smrg	  if(w1 > pScrn1->virtualX) w1 = pScrn1->virtualX;
195972b676d7Smrg	  h1 = realvirtY;
196072b676d7Smrg	  if((usenonrect) && (pSiS->maxCRT1_Y1 != realvirtY)) {
196172b676d7Smrg	     h1 = pSiS->MBXNR1YMAX = pSiS->maxCRT1_Y1;
196272b676d7Smrg	     pSiS->NonRectDead.x0 = x1;
196372b676d7Smrg	     pSiS->NonRectDead.x1 = x1 + w1 - 1;
196472b676d7Smrg	     pSiS->NonRectDead.y0 = y1 + h1;
196572b676d7Smrg	     pSiS->NonRectDead.y1 = pScrn1->virtualY - 1;
196672b676d7Smrg	     pSiS->HaveNonRect = TRUE;
196772b676d7Smrg	  }
196872b676d7Smrg	  x2 = min(pSiS->maxCRT2_X1, pScrn1->virtualX - pSiS->maxCRT2_X2);
196972b676d7Smrg	  if(x2 < 0) x2 = 0;
197072b676d7Smrg	  y2 = pSiS->CRT2YOffs;
197172b676d7Smrg	  w2 = pScrn1->virtualX - x2;
197272b676d7Smrg	  h2 = realvirtY;
197372b676d7Smrg	  if((usenonrect) && (pSiS->maxCRT2_Y2 != realvirtY)) {
197472b676d7Smrg	     h2 = pSiS->MBXNR2YMAX = pSiS->maxCRT2_Y2;
197572b676d7Smrg	     pSiS->NonRectDead.x0 = x2;
197672b676d7Smrg	     pSiS->NonRectDead.x1 = x2 + w2 - 1;
197772b676d7Smrg	     pSiS->NonRectDead.y0 = y2 + h2;
197872b676d7Smrg	     pSiS->NonRectDead.y1 = pScrn1->virtualY - 1;
197972b676d7Smrg	     pSiS->HaveNonRect = TRUE;
198072b676d7Smrg	  }
198172b676d7Smrg	  break;
198272b676d7Smrg       case sisAbove:
198372b676d7Smrg	  x1 = pSiS->CRT1XOffs;
198472b676d7Smrg	  y1 = min(pSiS->maxCRT1_Y2, pScrn1->virtualY - pSiS->maxCRT1_Y1);
198572b676d7Smrg	  if(y1 < 0) y1 = 0;
198672b676d7Smrg	  w1 = realvirtX;
198772b676d7Smrg	  h1 = pScrn1->virtualY - y1;
198872b676d7Smrg	  if((usenonrect) && (pSiS->maxCRT1_X1 != realvirtX)) {
198972b676d7Smrg	     w1 = pSiS->MBXNR1XMAX = pSiS->maxCRT1_X1;
199072b676d7Smrg	     pSiS->NonRectDead.x0 = x1 + w1;
199172b676d7Smrg	     pSiS->NonRectDead.x1 = pScrn1->virtualX - 1;
199272b676d7Smrg	     pSiS->NonRectDead.y0 = y1;
199372b676d7Smrg	     pSiS->NonRectDead.y1 = y1 + h1 - 1;
199472b676d7Smrg	     pSiS->HaveNonRect = TRUE;
199572b676d7Smrg	  }
199672b676d7Smrg	  x2 = pSiS->CRT2XOffs;
199772b676d7Smrg	  y2 = 0;
199872b676d7Smrg	  w2 = realvirtX;
199972b676d7Smrg	  h2 = max(pSiS->maxCRT2_Y2, pScrn1->virtualY - pSiS->maxCRT2_Y1);
200072b676d7Smrg	  if(h2 > pScrn1->virtualY) h2 = pScrn1->virtualY;
200172b676d7Smrg	  if((usenonrect) && (pSiS->maxCRT2_X2 != realvirtX)) {
200272b676d7Smrg	     w2 = pSiS->MBXNR2XMAX = pSiS->maxCRT2_X2;
200372b676d7Smrg	     pSiS->NonRectDead.x0 = x2 + w2;
200472b676d7Smrg	     pSiS->NonRectDead.x1 = pScrn1->virtualX - 1;
200572b676d7Smrg	     pSiS->NonRectDead.y0 = y2;
200672b676d7Smrg	     pSiS->NonRectDead.y1 = y2 + h2 - 1;
200772b676d7Smrg	     pSiS->HaveNonRect = TRUE;
200872b676d7Smrg	  }
200972b676d7Smrg	  break;
201072b676d7Smrg       case sisBelow:
201172b676d7Smrg	  x1 = pSiS->CRT1XOffs;
201272b676d7Smrg	  y1 = 0;
201372b676d7Smrg	  w1 = realvirtX;
201472b676d7Smrg	  h1 = max(pSiS->maxCRT1_Y1, pScrn1->virtualY - pSiS->maxCRT1_Y2);
201572b676d7Smrg	  if(h1 > pScrn1->virtualY) h1 = pScrn1->virtualY;
201672b676d7Smrg	  if((usenonrect) && (pSiS->maxCRT1_X1 != realvirtX)) {
201772b676d7Smrg	     w1 = pSiS->MBXNR1XMAX = pSiS->maxCRT1_X1;
201872b676d7Smrg	     pSiS->NonRectDead.x0 = x1 + w1;
201972b676d7Smrg	     pSiS->NonRectDead.x1 = pScrn1->virtualX - 1;
202072b676d7Smrg	     pSiS->NonRectDead.y0 = y1;
202172b676d7Smrg	     pSiS->NonRectDead.y1 = y1 + h1 - 1;
202272b676d7Smrg	     pSiS->HaveNonRect = TRUE;
202372b676d7Smrg	  }
202472b676d7Smrg	  x2 = pSiS->CRT2XOffs;
202572b676d7Smrg	  y2 = min(pSiS->maxCRT2_Y1, pScrn1->virtualY - pSiS->maxCRT2_Y2);
202672b676d7Smrg	  if(y2 < 0) y2 = 0;
202772b676d7Smrg	  w2 = realvirtX;
202872b676d7Smrg	  h2 = pScrn1->virtualY - y2;
202972b676d7Smrg	  if((usenonrect) && (pSiS->maxCRT2_X2 != realvirtX)) {
203072b676d7Smrg	     w2 = pSiS->MBXNR2XMAX = pSiS->maxCRT2_X2;
203172b676d7Smrg	     pSiS->NonRectDead.x0 = x2 + w2;
203272b676d7Smrg	     pSiS->NonRectDead.x1 = pScrn1->virtualX - 1;
203372b676d7Smrg	     pSiS->NonRectDead.y0 = y2;
203472b676d7Smrg	     pSiS->NonRectDead.y1 = y2 + h2 - 1;
203572b676d7Smrg	     pSiS->HaveNonRect = TRUE;
203672b676d7Smrg	  }
203772b676d7Smrg       default:
203872b676d7Smrg	  break;
203972b676d7Smrg       }
204072b676d7Smrg
204172b676d7Smrg       switch(pSiS->CRT2Position) {
204272b676d7Smrg       case sisLeftOf:
204372b676d7Smrg       case sisRightOf:
204472b676d7Smrg	  if(pSiS->CRT1YOffs) {
204572b676d7Smrg	     pSiS->OffDead1.x0 = x1;
204672b676d7Smrg	     pSiS->OffDead1.x1 = x1 + w1 - 1;
204772b676d7Smrg	     pSiS->OffDead1.y0 = 0;
204872b676d7Smrg	     pSiS->OffDead1.y1 = y1 - 1;
204972b676d7Smrg	     pSiS->OffDead2.x0 = x2;
205072b676d7Smrg	     pSiS->OffDead2.x1 = x2 + w2 - 1;
205172b676d7Smrg	     pSiS->OffDead2.y0 = y2 + h2;
205272b676d7Smrg	     pSiS->OffDead2.y1 = pScrn1->virtualY - 1;
205372b676d7Smrg	     pSiS->HaveOffsRegions = TRUE;
205472b676d7Smrg	  } else if(pSiS->CRT2YOffs) {
205572b676d7Smrg	     pSiS->OffDead1.x0 = x2;
205672b676d7Smrg	     pSiS->OffDead1.x1 = x2 + w2 - 1;
205772b676d7Smrg	     pSiS->OffDead1.y0 = 0;
205872b676d7Smrg	     pSiS->OffDead1.y1 = y2 - 1;
205972b676d7Smrg	     pSiS->OffDead2.x0 = x1;
206072b676d7Smrg	     pSiS->OffDead2.x1 = x1 + w1 - 1;
206172b676d7Smrg	     pSiS->OffDead2.y0 = y1 + h1;
206272b676d7Smrg	     pSiS->OffDead2.y1 = pScrn1->virtualY - 1;
206372b676d7Smrg	     pSiS->HaveOffsRegions = TRUE;
206472b676d7Smrg	  }
206572b676d7Smrg	  break;
206672b676d7Smrg       case sisAbove:
206772b676d7Smrg       case sisBelow:
206872b676d7Smrg	  if(pSiS->CRT1XOffs) {
206972b676d7Smrg	     pSiS->OffDead1.x0 = x2 + w2;
207072b676d7Smrg	     pSiS->OffDead1.x1 = pScrn1->virtualX - 1;
207172b676d7Smrg	     pSiS->OffDead1.y0 = y2;
207272b676d7Smrg	     pSiS->OffDead1.y1 = y2 + h2 - 1;
207372b676d7Smrg	     pSiS->OffDead2.x0 = 0;
207472b676d7Smrg	     pSiS->OffDead2.x1 = x1 - 1;
207572b676d7Smrg	     pSiS->OffDead2.y0 = y1;
207672b676d7Smrg	     pSiS->OffDead2.y1 = y1 + h1 - 1;
207772b676d7Smrg	     pSiS->HaveOffsRegions = TRUE;
207872b676d7Smrg	  } else if(pSiS->CRT2XOffs) {
207972b676d7Smrg	     pSiS->OffDead1.x0 = x1 + w1;
208072b676d7Smrg	     pSiS->OffDead1.x1 = pScrn1->virtualX - 1;
208172b676d7Smrg	     pSiS->OffDead1.y0 = y1;
208272b676d7Smrg	     pSiS->OffDead1.y1 = y1 + h1 - 1;
208372b676d7Smrg	     pSiS->OffDead2.x0 = 0;
208472b676d7Smrg	     pSiS->OffDead2.x1 = x2 - 1;
208572b676d7Smrg	     pSiS->OffDead2.y0 = y2;
208672b676d7Smrg	     pSiS->OffDead2.y1 = y2 + h2 - 1;
208772b676d7Smrg	     pSiS->HaveOffsRegions = TRUE;
208872b676d7Smrg	  }
208972b676d7Smrg       default:
209072b676d7Smrg	  break;
209172b676d7Smrg       }
209272b676d7Smrg
209372b676d7Smrg    } else {	/* Only clone-modes left */
209472b676d7Smrg
209572b676d7Smrg       x1 = x2 = 0;
209672b676d7Smrg       y1 = y2 = 0;
209772b676d7Smrg       w1 = w2 = max(pSiS->maxClone_X1, pSiS->maxClone_X2);
209872b676d7Smrg       h1 = h2 = max(pSiS->maxClone_Y1, pSiS->maxClone_Y2);
209972b676d7Smrg
210072b676d7Smrg    }
210172b676d7Smrg
210272b676d7Smrg    SiSXineramadataPtr[crt1scrnnum].x = x1;
210372b676d7Smrg    SiSXineramadataPtr[crt1scrnnum].y = y1;
210472b676d7Smrg    SiSXineramadataPtr[crt1scrnnum].width = w1;
210572b676d7Smrg    SiSXineramadataPtr[crt1scrnnum].height = h1;
210672b676d7Smrg    SiSXineramadataPtr[crt2scrnnum].x = x2;
210772b676d7Smrg    SiSXineramadataPtr[crt2scrnnum].y = y2;
210872b676d7Smrg    SiSXineramadataPtr[crt2scrnnum].width = w2;
210972b676d7Smrg    SiSXineramadataPtr[crt2scrnnum].height = h2;
211072b676d7Smrg
211172b676d7Smrg    if(infochanged) {
211272b676d7Smrg       xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
211372b676d7Smrg	  "Pseudo-Xinerama: CRT1 (Screen %d) (%d,%d)-(%d,%d)\n",
211472b676d7Smrg	  crt1scrnnum, x1, y1, w1+x1-1, h1+y1-1);
211572b676d7Smrg       xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
211672b676d7Smrg	  "Pseudo-Xinerama: CRT2 (Screen %d) (%d,%d)-(%d,%d)\n",
211772b676d7Smrg	  crt2scrnnum, x2, y2, w2+x2-1, h2+y2-1);
211872b676d7Smrg       if(pSiS->HaveNonRect) {
211972b676d7Smrg	  xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
212072b676d7Smrg		"Pseudo-Xinerama: Inaccessible area (%d,%d)-(%d,%d)\n",
212172b676d7Smrg		pSiS->NonRectDead.x0, pSiS->NonRectDead.y0,
212272b676d7Smrg		pSiS->NonRectDead.x1, pSiS->NonRectDead.y1);
212372b676d7Smrg       }
212472b676d7Smrg       if(pSiS->HaveOffsRegions) {
212572b676d7Smrg	  xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
212672b676d7Smrg		"Pseudo-Xinerama: Inaccessible offset area (%d,%d)-(%d,%d)\n",
212772b676d7Smrg		pSiS->OffDead1.x0, pSiS->OffDead1.y0,
212872b676d7Smrg		pSiS->OffDead1.x1, pSiS->OffDead1.y1);
212972b676d7Smrg	  xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
213072b676d7Smrg		"Pseudo-Xinerama: Inaccessible offset area (%d,%d)-(%d,%d)\n",
213172b676d7Smrg		pSiS->OffDead2.x0, pSiS->OffDead2.y0,
213272b676d7Smrg		pSiS->OffDead2.x1, pSiS->OffDead2.y1);
213372b676d7Smrg       }
213472b676d7Smrg       if(pSiS->HaveNonRect || pSiS->HaveOffsRegions) {
213572b676d7Smrg	  xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
213672b676d7Smrg		"Mouse restriction for inaccessible areas is %s\n",
213772b676d7Smrg		pSiS->MouseRestrictions ? "enabled" : "disabled");
213872b676d7Smrg       }
213972b676d7Smrg    }
214072b676d7Smrg}
214172b676d7Smrg
214272b676d7Smrg/* Proc */
214372b676d7Smrg
214472b676d7Smrgint
214572b676d7SmrgSiSProcXineramaQueryVersion(ClientPtr client)
214672b676d7Smrg{
214772b676d7Smrg    xPanoramiXQueryVersionReply	  rep;
214872b676d7Smrg    register int		  n;
214972b676d7Smrg
215072b676d7Smrg    REQUEST_SIZE_MATCH(xPanoramiXQueryVersionReq);
215172b676d7Smrg    rep.type = X_Reply;
215272b676d7Smrg    rep.length = 0;
215372b676d7Smrg    rep.sequenceNumber = client->sequence;
215472b676d7Smrg    rep.majorVersion = SIS_XINERAMA_MAJOR_VERSION;
215572b676d7Smrg    rep.minorVersion = SIS_XINERAMA_MINOR_VERSION;
215672b676d7Smrg    if(client->swapped) {
21575788ca14Smrg        _swaps(&rep.sequenceNumber, n);
21585788ca14Smrg        _swapl(&rep.length, n);
21595788ca14Smrg        _swaps(&rep.majorVersion, n);
21605788ca14Smrg        _swaps(&rep.minorVersion, n);
216172b676d7Smrg    }
216272b676d7Smrg    WriteToClient(client, sizeof(xPanoramiXQueryVersionReply), (char *)&rep);
216372b676d7Smrg    return (client->noClientException);
216472b676d7Smrg}
216572b676d7Smrg
216672b676d7Smrgint
216772b676d7SmrgSiSProcXineramaGetState(ClientPtr client)
216872b676d7Smrg{
216972b676d7Smrg    REQUEST(xPanoramiXGetStateReq);
217072b676d7Smrg    WindowPtr			pWin;
217172b676d7Smrg    xPanoramiXGetStateReply	rep;
217272b676d7Smrg    register int		n;
21735788ca14Smrg    int				rc;
217472b676d7Smrg
217572b676d7Smrg    REQUEST_SIZE_MATCH(xPanoramiXGetStateReq);
21765788ca14Smrg    rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
21775788ca14Smrg    if (rc != Success)
21785788ca14Smrg        return rc;
217972b676d7Smrg
218072b676d7Smrg    rep.type = X_Reply;
218172b676d7Smrg    rep.length = 0;
218272b676d7Smrg    rep.sequenceNumber = client->sequence;
218372b676d7Smrg    rep.state = !SiSnoPanoramiXExtension;
218472b676d7Smrg    if(client->swapped) {
21855788ca14Smrg       _swaps (&rep.sequenceNumber, n);
21865788ca14Smrg       _swapl (&rep.length, n);
218772b676d7Smrg    }
218872b676d7Smrg    WriteToClient(client, sizeof(xPanoramiXGetStateReply), (char *)&rep);
218972b676d7Smrg    return client->noClientException;
219072b676d7Smrg}
219172b676d7Smrg
219272b676d7Smrgint
219372b676d7SmrgSiSProcXineramaGetScreenCount(ClientPtr client)
219472b676d7Smrg{
219572b676d7Smrg    REQUEST(xPanoramiXGetScreenCountReq);
219672b676d7Smrg    WindowPtr				pWin;
219772b676d7Smrg    xPanoramiXGetScreenCountReply	rep;
219872b676d7Smrg    register int			n;
21995788ca14Smrg    int					rc;
220072b676d7Smrg
220172b676d7Smrg    REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq);
22025788ca14Smrg    rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
22035788ca14Smrg    if (rc != Success)
22045788ca14Smrg        return rc;
220572b676d7Smrg
220672b676d7Smrg    rep.type = X_Reply;
220772b676d7Smrg    rep.length = 0;
220872b676d7Smrg    rep.sequenceNumber = client->sequence;
220972b676d7Smrg    rep.ScreenCount = SiSXineramaNumScreens;
221072b676d7Smrg    if(client->swapped) {
22115788ca14Smrg       _swaps(&rep.sequenceNumber, n);
22125788ca14Smrg       _swapl(&rep.length, n);
221372b676d7Smrg    }
221472b676d7Smrg    WriteToClient(client, sizeof(xPanoramiXGetScreenCountReply), (char *)&rep);
221572b676d7Smrg    return client->noClientException;
221672b676d7Smrg}
221772b676d7Smrg
221872b676d7Smrgint
221972b676d7SmrgSiSProcXineramaGetScreenSize(ClientPtr client)
222072b676d7Smrg{
222172b676d7Smrg    REQUEST(xPanoramiXGetScreenSizeReq);
222272b676d7Smrg    WindowPtr				pWin;
222372b676d7Smrg    xPanoramiXGetScreenSizeReply	rep;
222472b676d7Smrg    register int			n;
22255788ca14Smrg    int					rc;
222672b676d7Smrg
222772b676d7Smrg    REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq);
22285788ca14Smrg    rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
22295788ca14Smrg    if (rc != Success)
22305788ca14Smrg        return rc;
223172b676d7Smrg
223272b676d7Smrg    rep.type = X_Reply;
223372b676d7Smrg    rep.length = 0;
223472b676d7Smrg    rep.sequenceNumber = client->sequence;
223572b676d7Smrg    rep.width  = SiSXineramadataPtr[stuff->screen].width;
223672b676d7Smrg    rep.height = SiSXineramadataPtr[stuff->screen].height;
223772b676d7Smrg    if(client->swapped) {
22385788ca14Smrg       _swaps(&rep.sequenceNumber, n);
22395788ca14Smrg       _swapl(&rep.length, n);
22405788ca14Smrg       _swapl(&rep.width, n);
22415788ca14Smrg       _swapl(&rep.height, n);
224272b676d7Smrg    }
224372b676d7Smrg    WriteToClient(client, sizeof(xPanoramiXGetScreenSizeReply), (char *)&rep);
224472b676d7Smrg    return client->noClientException;
224572b676d7Smrg}
224672b676d7Smrg
224772b676d7Smrgint
224872b676d7SmrgSiSProcXineramaIsActive(ClientPtr client)
224972b676d7Smrg{
225072b676d7Smrg    xXineramaIsActiveReply	rep;
225172b676d7Smrg
225272b676d7Smrg    REQUEST_SIZE_MATCH(xXineramaIsActiveReq);
225372b676d7Smrg
225472b676d7Smrg    rep.type = X_Reply;
225572b676d7Smrg    rep.length = 0;
225672b676d7Smrg    rep.sequenceNumber = client->sequence;
225772b676d7Smrg    rep.state = !SiSnoPanoramiXExtension;
225872b676d7Smrg    if(client->swapped) {
225972b676d7Smrg	register int n;
22605788ca14Smrg	_swaps(&rep.sequenceNumber, n);
22615788ca14Smrg	_swapl(&rep.length, n);
22625788ca14Smrg	_swapl(&rep.state, n);
226372b676d7Smrg    }
226472b676d7Smrg    WriteToClient(client, sizeof(xXineramaIsActiveReply), (char *) &rep);
226572b676d7Smrg    return client->noClientException;
226672b676d7Smrg}
226772b676d7Smrg
226872b676d7Smrgint
226972b676d7SmrgSiSProcXineramaQueryScreens(ClientPtr client)
227072b676d7Smrg{
227172b676d7Smrg    xXineramaQueryScreensReply	rep;
227272b676d7Smrg
227372b676d7Smrg    REQUEST_SIZE_MATCH(xXineramaQueryScreensReq);
227472b676d7Smrg
227572b676d7Smrg    rep.type = X_Reply;
227672b676d7Smrg    rep.sequenceNumber = client->sequence;
227772b676d7Smrg    rep.number = (SiSnoPanoramiXExtension) ? 0 : SiSXineramaNumScreens;
227872b676d7Smrg    rep.length = rep.number * sz_XineramaScreenInfo >> 2;
227972b676d7Smrg    if(client->swapped) {
228072b676d7Smrg       register int n;
22815788ca14Smrg       _swaps(&rep.sequenceNumber, n);
22825788ca14Smrg       _swapl(&rep.length, n);
22835788ca14Smrg       _swapl(&rep.number, n);
228472b676d7Smrg    }
228572b676d7Smrg    WriteToClient(client, sizeof(xXineramaQueryScreensReply), (char *)&rep);
228672b676d7Smrg
228772b676d7Smrg    if(!SiSnoPanoramiXExtension) {
228872b676d7Smrg       xXineramaScreenInfo scratch;
228972b676d7Smrg       int i;
229072b676d7Smrg
229172b676d7Smrg       for(i = 0; i < SiSXineramaNumScreens; i++) {
229272b676d7Smrg	  scratch.x_org  = SiSXineramadataPtr[i].x;
229372b676d7Smrg	  scratch.y_org  = SiSXineramadataPtr[i].y;
229472b676d7Smrg	  scratch.width  = SiSXineramadataPtr[i].width;
229572b676d7Smrg	  scratch.height = SiSXineramadataPtr[i].height;
229672b676d7Smrg	  if(client->swapped) {
229772b676d7Smrg	     register int n;
22985788ca14Smrg	     _swaps(&scratch.x_org, n);
22995788ca14Smrg	     _swaps(&scratch.y_org, n);
23005788ca14Smrg	     _swaps(&scratch.width, n);
23015788ca14Smrg	     _swaps(&scratch.height, n);
230272b676d7Smrg	  }
230372b676d7Smrg	  WriteToClient(client, sz_XineramaScreenInfo, (char *)&scratch);
230472b676d7Smrg       }
230572b676d7Smrg    }
230672b676d7Smrg
230772b676d7Smrg    return client->noClientException;
230872b676d7Smrg}
230972b676d7Smrg
231072b676d7Smrgstatic int
231172b676d7SmrgSiSProcXineramaDispatch(ClientPtr client)
231272b676d7Smrg{
231372b676d7Smrg    REQUEST(xReq);
231472b676d7Smrg    switch (stuff->data) {
231572b676d7Smrg	case X_PanoramiXQueryVersion:
231672b676d7Smrg	     return SiSProcXineramaQueryVersion(client);
231772b676d7Smrg	case X_PanoramiXGetState:
231872b676d7Smrg	     return SiSProcXineramaGetState(client);
231972b676d7Smrg	case X_PanoramiXGetScreenCount:
232072b676d7Smrg	     return SiSProcXineramaGetScreenCount(client);
232172b676d7Smrg	case X_PanoramiXGetScreenSize:
232272b676d7Smrg	     return SiSProcXineramaGetScreenSize(client);
232372b676d7Smrg	case X_XineramaIsActive:
232472b676d7Smrg	     return SiSProcXineramaIsActive(client);
232572b676d7Smrg	case X_XineramaQueryScreens:
232672b676d7Smrg	     return SiSProcXineramaQueryScreens(client);
232772b676d7Smrg    }
232872b676d7Smrg    return BadRequest;
232972b676d7Smrg}
233072b676d7Smrg
233172b676d7Smrg/* SProc */
233272b676d7Smrg
233372b676d7Smrgstatic int
233472b676d7SmrgSiSSProcXineramaQueryVersion (ClientPtr client)
233572b676d7Smrg{
233672b676d7Smrg    REQUEST(xPanoramiXQueryVersionReq);
233772b676d7Smrg    register int n;
23385788ca14Smrg    _swaps(&stuff->length,n);
233972b676d7Smrg    REQUEST_SIZE_MATCH (xPanoramiXQueryVersionReq);
234072b676d7Smrg    return SiSProcXineramaQueryVersion(client);
234172b676d7Smrg}
234272b676d7Smrg
234372b676d7Smrgstatic int
234472b676d7SmrgSiSSProcXineramaGetState(ClientPtr client)
234572b676d7Smrg{
234672b676d7Smrg    REQUEST(xPanoramiXGetStateReq);
234772b676d7Smrg    register int n;
23485788ca14Smrg    _swaps (&stuff->length, n);
234972b676d7Smrg    REQUEST_SIZE_MATCH(xPanoramiXGetStateReq);
235072b676d7Smrg    return SiSProcXineramaGetState(client);
235172b676d7Smrg}
235272b676d7Smrg
235372b676d7Smrgstatic int
235472b676d7SmrgSiSSProcXineramaGetScreenCount(ClientPtr client)
235572b676d7Smrg{
235672b676d7Smrg    REQUEST(xPanoramiXGetScreenCountReq);
235772b676d7Smrg    register int n;
23585788ca14Smrg    _swaps (&stuff->length, n);
235972b676d7Smrg    REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq);
236072b676d7Smrg    return SiSProcXineramaGetScreenCount(client);
236172b676d7Smrg}
236272b676d7Smrg
236372b676d7Smrgstatic int
236472b676d7SmrgSiSSProcXineramaGetScreenSize(ClientPtr client)
236572b676d7Smrg{
236672b676d7Smrg    REQUEST(xPanoramiXGetScreenSizeReq);
236772b676d7Smrg    register int n;
23685788ca14Smrg    _swaps (&stuff->length, n);
236972b676d7Smrg    REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq);
237072b676d7Smrg    return SiSProcXineramaGetScreenSize(client);
237172b676d7Smrg}
237272b676d7Smrg
237372b676d7Smrgstatic int
237472b676d7SmrgSiSSProcXineramaIsActive(ClientPtr client)
237572b676d7Smrg{
237672b676d7Smrg    REQUEST(xXineramaIsActiveReq);
237772b676d7Smrg    register int n;
23785788ca14Smrg    _swaps (&stuff->length, n);
237972b676d7Smrg    REQUEST_SIZE_MATCH(xXineramaIsActiveReq);
238072b676d7Smrg    return SiSProcXineramaIsActive(client);
238172b676d7Smrg}
238272b676d7Smrg
238372b676d7Smrgstatic int
238472b676d7SmrgSiSSProcXineramaQueryScreens(ClientPtr client)
238572b676d7Smrg{
238672b676d7Smrg    REQUEST(xXineramaQueryScreensReq);
238772b676d7Smrg    register int n;
23885788ca14Smrg    _swaps (&stuff->length, n);
238972b676d7Smrg    REQUEST_SIZE_MATCH(xXineramaQueryScreensReq);
239072b676d7Smrg    return SiSProcXineramaQueryScreens(client);
239172b676d7Smrg}
239272b676d7Smrg
239372b676d7Smrgint
239472b676d7SmrgSiSSProcXineramaDispatch(ClientPtr client)
239572b676d7Smrg{
239672b676d7Smrg    REQUEST(xReq);
239772b676d7Smrg    switch (stuff->data) {
239872b676d7Smrg	case X_PanoramiXQueryVersion:
239972b676d7Smrg	     return SiSSProcXineramaQueryVersion(client);
240072b676d7Smrg	case X_PanoramiXGetState:
240172b676d7Smrg	     return SiSSProcXineramaGetState(client);
240272b676d7Smrg	case X_PanoramiXGetScreenCount:
240372b676d7Smrg	     return SiSSProcXineramaGetScreenCount(client);
240472b676d7Smrg	case X_PanoramiXGetScreenSize:
240572b676d7Smrg	     return SiSSProcXineramaGetScreenSize(client);
240672b676d7Smrg	case X_XineramaIsActive:
240772b676d7Smrg	     return SiSSProcXineramaIsActive(client);
240872b676d7Smrg	case X_XineramaQueryScreens:
240972b676d7Smrg	     return SiSSProcXineramaQueryScreens(client);
241072b676d7Smrg    }
241172b676d7Smrg    return BadRequest;
241272b676d7Smrg}
241372b676d7Smrg
241472b676d7Smrgstatic void
241572b676d7SmrgSiSXineramaResetProc(ExtensionEntry* extEntry)
241672b676d7Smrg{
241772b676d7Smrg    /* Called by CloseDownExtensions() */
241872b676d7Smrg    if(SiSXineramadataPtr) {
24195788ca14Smrg       free(SiSXineramadataPtr);
242072b676d7Smrg       SiSXineramadataPtr = NULL;
242172b676d7Smrg    }
242272b676d7Smrg}
242372b676d7Smrg
242472b676d7Smrgstatic void
242572b676d7SmrgSiSXineramaExtensionInit(ScrnInfoPtr pScrn)
242672b676d7Smrg{
242772b676d7Smrg    SISPtr	pSiS = SISPTR(pScrn);
242872b676d7Smrg    Bool	success = FALSE;
242972b676d7Smrg
243072b676d7Smrg    if(!(SiSXineramadataPtr)) {
243172b676d7Smrg
243272b676d7Smrg       if(!pSiS->MergedFB) {
243372b676d7Smrg	  SiSnoPanoramiXExtension = TRUE;
243472b676d7Smrg	  pSiS->MouseRestrictions = FALSE;
243572b676d7Smrg	  return;
243672b676d7Smrg       }
243772b676d7Smrg
243872b676d7Smrg#ifdef PANORAMIX
243972b676d7Smrg       if(!noPanoramiXExtension) {
244072b676d7Smrg	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
244172b676d7Smrg	     "Xinerama active, not initializing SiS Pseudo-Xinerama\n");
244272b676d7Smrg	  SiSnoPanoramiXExtension = TRUE;
244372b676d7Smrg	  pSiS->MouseRestrictions = FALSE;
244472b676d7Smrg	  return;
244572b676d7Smrg       }
244672b676d7Smrg#endif
244772b676d7Smrg
244872b676d7Smrg       if(SiSnoPanoramiXExtension) {
244972b676d7Smrg	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
245072b676d7Smrg	      "SiS Pseudo-Xinerama disabled\n");
245172b676d7Smrg	  pSiS->MouseRestrictions = FALSE;
245272b676d7Smrg	  return;
245372b676d7Smrg       }
245472b676d7Smrg
245572b676d7Smrg       if(pSiS->CRT2Position == sisClone) {
245672b676d7Smrg	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
245772b676d7Smrg	     "Running MergedFB in Clone mode, SiS Pseudo-Xinerama disabled\n");
245872b676d7Smrg	  SiSnoPanoramiXExtension = TRUE;
245972b676d7Smrg	  pSiS->MouseRestrictions = FALSE;
246072b676d7Smrg	  return;
246172b676d7Smrg       }
246272b676d7Smrg
246372b676d7Smrg       if(!(pSiS->AtLeastOneNonClone)) {
246472b676d7Smrg	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
246572b676d7Smrg	     "Only Clone modes defined, SiS Pseudo-Xinerama disabled\n");
246672b676d7Smrg	  SiSnoPanoramiXExtension = TRUE;
246772b676d7Smrg	  pSiS->MouseRestrictions = FALSE;
246872b676d7Smrg	  return;
246972b676d7Smrg       }
247072b676d7Smrg
247172b676d7Smrg       SiSXineramaNumScreens = 2;
247272b676d7Smrg
247372b676d7Smrg       while(SiSXineramaGeneration != serverGeneration) {
247472b676d7Smrg
247572b676d7Smrg	  pSiS->XineramaExtEntry = AddExtension(PANORAMIX_PROTOCOL_NAME, 0,0,
247672b676d7Smrg					SiSProcXineramaDispatch,
247772b676d7Smrg					SiSSProcXineramaDispatch,
247872b676d7Smrg					SiSXineramaResetProc,
247972b676d7Smrg					StandardMinorOpcode);
248072b676d7Smrg
248172b676d7Smrg	  if(!pSiS->XineramaExtEntry) break;
248272b676d7Smrg
248372b676d7Smrg	  if(!(SiSXineramadataPtr = (SiSXineramaData *)
24845788ca14Smrg	        calloc(SiSXineramaNumScreens, sizeof(SiSXineramaData)))) break;
248572b676d7Smrg
248672b676d7Smrg	  SiSXineramaGeneration = serverGeneration;
248772b676d7Smrg	  success = TRUE;
248872b676d7Smrg       }
248972b676d7Smrg
249072b676d7Smrg       if(!success) {
249172b676d7Smrg	  SISErrorLog(pScrn, "Failed to initialize SiS Pseudo-Xinerama extension\n");
249272b676d7Smrg	  SiSnoPanoramiXExtension = TRUE;
249372b676d7Smrg	  pSiS->MouseRestrictions = FALSE;
249472b676d7Smrg	  return;
249572b676d7Smrg       }
249672b676d7Smrg
249772b676d7Smrg       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
249872b676d7Smrg	  "SiS Pseudo-Xinerama extension initialized\n");
249972b676d7Smrg
250072b676d7Smrg       pSiS->SiSXineramaVX = 0;
250172b676d7Smrg       pSiS->SiSXineramaVY = 0;
250272b676d7Smrg
250372b676d7Smrg    }
250472b676d7Smrg
250572b676d7Smrg    SiSUpdateXineramaScreenInfo(pScrn);
250672b676d7Smrg
250772b676d7Smrg}
250872b676d7Smrg#endif  /* End of PseudoXinerama */
250972b676d7Smrg
251072b676d7Smrgstatic void
251172b676d7SmrgSiSFreeCRT2Structs(SISPtr pSiS)
251272b676d7Smrg{
251372b676d7Smrg    if(pSiS->CRT2pScrn) {
251472b676d7Smrg       if(pSiS->CRT2pScrn->modes) {
251572b676d7Smrg	  while(pSiS->CRT2pScrn->modes)
251672b676d7Smrg	     xf86DeleteMode(&pSiS->CRT2pScrn->modes, pSiS->CRT2pScrn->modes);
251772b676d7Smrg       }
251872b676d7Smrg       if(pSiS->CRT2pScrn->monitor) {
251972b676d7Smrg	  if(pSiS->CRT2pScrn->monitor->Modes) {
252072b676d7Smrg	     while(pSiS->CRT2pScrn->monitor->Modes)
252172b676d7Smrg		xf86DeleteMode(&pSiS->CRT2pScrn->monitor->Modes, pSiS->CRT2pScrn->monitor->Modes);
252272b676d7Smrg	  }
25235788ca14Smrg	  if(pSiS->CRT2pScrn->monitor->DDC) free(pSiS->CRT2pScrn->monitor->DDC);
25245788ca14Smrg	  free(pSiS->CRT2pScrn->monitor);
252572b676d7Smrg       }
25265788ca14Smrg       free(pSiS->CRT2pScrn);
252772b676d7Smrg       pSiS->CRT2pScrn = NULL;
252872b676d7Smrg   }
252972b676d7Smrg}
253072b676d7Smrg
253172b676d7Smrg#endif	/* End of MergedFB helpers */
253272b676d7Smrg
253372b676d7Smrgstatic xf86MonPtr
253472b676d7SmrgSiSInternalDDC(ScrnInfoPtr pScrn, int crtno)
253572b676d7Smrg{
253672b676d7Smrg   SISPtr     pSiS = SISPTR(pScrn);
253772b676d7Smrg   xf86MonPtr pMonitor = NULL;
253872b676d7Smrg   UShort     temp = 0xffff, temp1, i, realcrtno = crtno;
253972b676d7Smrg   UChar      buffer[256];
254072b676d7Smrg
254172b676d7Smrg   /* If CRT1 is off, skip DDC */
254272b676d7Smrg   if((pSiS->CRT1off) && (!crtno)) return NULL;
254372b676d7Smrg
254472b676d7Smrg   if(crtno) {
254572b676d7Smrg      if(pSiS->VBFlags & CRT2_LCD)      realcrtno = 1;
254672b676d7Smrg      else if(pSiS->VBFlags & CRT2_VGA) realcrtno = 2;
254772b676d7Smrg      else				return NULL;
254872b676d7Smrg      if(pSiS->SiS_Pr->DDCPortMixup) realcrtno = 0;
254972b676d7Smrg   } else {
255072b676d7Smrg      /* If CRT1 is LCDA, skip DDC (except 301C: DDC allowed, but uses CRT2 port!) */
255172b676d7Smrg      if(pSiS->VBFlags & CRT1_LCDA) {
255272b676d7Smrg         if(pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE) realcrtno = 1;
255372b676d7Smrg         else return NULL;
255472b676d7Smrg      }
255572b676d7Smrg   }
255672b676d7Smrg
255772b676d7Smrg   i = 3; /* Number of retrys */
255872b676d7Smrg   do {
255972b676d7Smrg      temp1 = SiS_HandleDDC(pSiS->SiS_Pr, pSiS->VBFlags, pSiS->VGAEngine,
256072b676d7Smrg			realcrtno, 0, &buffer[0], pSiS->VBFlags2);
256172b676d7Smrg      if((temp1) && (temp1 != 0xffff)) temp = temp1;
256272b676d7Smrg   } while((temp == 0xffff) && i--);
256372b676d7Smrg   if(temp != 0xffff) {
256472b676d7Smrg      xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "CRT%d DDC supported\n", crtno + 1);
256572b676d7Smrg      xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "CRT%d DDC level: %s%s%s%s\n",
256672b676d7Smrg	     crtno + 1,
256772b676d7Smrg	     (temp & 0x1a) ? "" : "[none of the supported]",
256872b676d7Smrg	     (temp & 0x02) ? "2 " : "",
256972b676d7Smrg	     (temp & 0x08) ? "D&P" : "",
257072b676d7Smrg             (temp & 0x10) ? "FPDI-2" : "");
257172b676d7Smrg      if(temp & 0x02) {
257272b676d7Smrg	 i = 5;  /* Number of retrys */
257372b676d7Smrg	 do {
257472b676d7Smrg	    temp = SiS_HandleDDC(pSiS->SiS_Pr, pSiS->VBFlags, pSiS->VGAEngine,
257572b676d7Smrg				realcrtno, 1, &buffer[0], pSiS->VBFlags2);
257672b676d7Smrg	 } while((temp) && i--);
257772b676d7Smrg         if(!temp) {
257872b676d7Smrg	    if((pMonitor = xf86InterpretEDID(pScrn->scrnIndex, &buffer[0]))) {
257972b676d7Smrg	       int tempvgagamma = 0, templcdgamma = 0;
258072b676d7Smrg	       if(buffer[0x14] & 0x80) {
258172b676d7Smrg	          templcdgamma = (buffer[0x17] + 100) * 10;
258272b676d7Smrg	       } else {
258372b676d7Smrg	          tempvgagamma = (buffer[0x17] + 100) * 10;;
258472b676d7Smrg	       }
258572b676d7Smrg	       if(crtno == 0) {
258672b676d7Smrg		  if(tempvgagamma) pSiS->CRT1VGAMonitorGamma = tempvgagamma;
258772b676d7Smrg		  /* LCD never via (demanded) CRT1 DDC port */
258872b676d7Smrg	       } else {
258972b676d7Smrg	          if(tempvgagamma) pSiS->CRT2VGAMonitorGamma = tempvgagamma;
259072b676d7Smrg	          if(templcdgamma) pSiS->CRT2LCDMonitorGamma = templcdgamma;
259172b676d7Smrg	       }
259272b676d7Smrg	       return(pMonitor);
259372b676d7Smrg	    } else {
259472b676d7Smrg	       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
259572b676d7Smrg	           "CRT%d DDC EDID corrupt\n", crtno + 1);
259672b676d7Smrg	    }
259772b676d7Smrg	 } else if(temp == 0xFFFE) {
259872b676d7Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
259972b676d7Smrg	    	"CRT%d DDC data is from wrong device type (%s)\n",
260072b676d7Smrg			crtno + 1,
260172b676d7Smrg			(realcrtno == 1) ? "analog instead of digital" : "digital instead of analog");
260272b676d7Smrg	 } else {
260372b676d7Smrg            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
260472b676d7Smrg	    	"CRT%d DDC reading failed\n", crtno + 1);
260572b676d7Smrg	 }
260672b676d7Smrg      } else if(temp & 0x18) {
260772b676d7Smrg         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
260872b676d7Smrg	      "DDC for VESA D&P and FPDI-2 not supported yet.\n");
260972b676d7Smrg      }
261072b676d7Smrg   } else {
261172b676d7Smrg      xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
261272b676d7Smrg                "CRT%d DDC probing failed\n", crtno + 1);
261372b676d7Smrg   }
261472b676d7Smrg   return(NULL);
261572b676d7Smrg}
261672b676d7Smrg
261772b676d7Smrgstatic xf86MonPtr
261872b676d7SmrgSiSDoPrivateDDC(ScrnInfoPtr pScrn, int *crtnum)
261972b676d7Smrg{
262072b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
262172b676d7Smrg
262272b676d7Smrg#ifdef SISDUALHEAD
262372b676d7Smrg    if(pSiS->DualHeadMode) {
262472b676d7Smrg       if(pSiS->SecondHead) {
262572b676d7Smrg          *crtnum = 1;
262672b676d7Smrg	  return(SiSInternalDDC(pScrn, 0));
262772b676d7Smrg       } else {
262872b676d7Smrg          *crtnum = 2;
262972b676d7Smrg	  return(SiSInternalDDC(pScrn, 1));
263072b676d7Smrg       }
263172b676d7Smrg    } else
263272b676d7Smrg#endif
263372b676d7Smrg    if((pSiS->CRT1off) || (!pSiS->CRT1Detected)) {
263472b676d7Smrg       *crtnum = 2;
263572b676d7Smrg       return(SiSInternalDDC(pScrn, 1));
263672b676d7Smrg    } else {
263772b676d7Smrg       *crtnum = 1;
263872b676d7Smrg       return(SiSInternalDDC(pScrn, 0));
263972b676d7Smrg    }
264072b676d7Smrg}
264172b676d7Smrg
264272b676d7Smrgstatic void
264372b676d7SmrgSiSFindAspect(ScrnInfoPtr pScrn, xf86MonPtr pMonitor, int crtnum)
264472b676d7Smrg{
264572b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
264672b676d7Smrg    int UseWide = 0;
264772b676d7Smrg    int aspect = 0;
264872b676d7Smrg    Bool fromdim = FALSE;
264972b676d7Smrg
265072b676d7Smrg    if((pSiS->VGAEngine == SIS_315_VGA) && (!DIGITAL(pMonitor->features.input_type))) {
265172b676d7Smrg       if(pMonitor->features.hsize && pMonitor->features.vsize) {
265272b676d7Smrg	  aspect = (pMonitor->features.hsize * 1000) / pMonitor->features.vsize;
265372b676d7Smrg	  if(aspect >= 1400) UseWide = 1;
265472b676d7Smrg	  fromdim = TRUE;
265572b676d7Smrg       } else if((PREFERRED_TIMING_MODE(pMonitor->features.msc)) &&
265672b676d7Smrg		 (pMonitor->det_mon[0].type == DT)) {
265772b676d7Smrg	  aspect = (pMonitor->det_mon[0].section.d_timings.h_active * 1000) /
265872b676d7Smrg			pMonitor->det_mon[0].section.d_timings.v_active;
265972b676d7Smrg	  if(aspect >= 1400) UseWide = 1;
266072b676d7Smrg       }
266172b676d7Smrg       if(aspect) {
266272b676d7Smrg	  xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
266372b676d7Smrg		"According to %s, CRT%d aspect ratio is %.2f:1 (%s)\n",
266472b676d7Smrg		fromdim ? "DDC size" : "preferred mode",
266572b676d7Smrg		crtnum, (float)aspect / 1000.0, UseWide ? "wide" : "normal");
266672b676d7Smrg       } else {
266772b676d7Smrg	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
266872b676d7Smrg		"Unable to determine CRT%d aspect ratio, assuming \"normal\"\n",
266972b676d7Smrg		crtnum);
267072b676d7Smrg       }
267172b676d7Smrg    }
267272b676d7Smrg
267372b676d7Smrg    if((crtnum == 1) && (pSiS->SiS_Pr->SiS_UseWide == -1)) {
267472b676d7Smrg       pSiS->SiS_Pr->SiS_UseWide = UseWide;
267572b676d7Smrg    } else if((crtnum == 2) && (pSiS->SiS_Pr->SiS_UseWideCRT2 == -1)) {
267672b676d7Smrg       pSiS->SiS_Pr->SiS_UseWideCRT2 = UseWide;
267772b676d7Smrg    }
267872b676d7Smrg}
267972b676d7Smrg
268072b676d7Smrgstatic Bool
268172b676d7SmrgSiSMakeOwnModeList(ScrnInfoPtr pScrn, Bool acceptcustommodes, Bool includelcdmodes,
268272b676d7Smrg                   Bool isfordvi, Bool *havecustommodes, Bool fakecrt2modes, Bool IsForCRT2)
268372b676d7Smrg{
268472b676d7Smrg    DisplayModePtr tempmode, delmode, mymodes;
268572b676d7Smrg
268672b676d7Smrg    if((mymodes = SiSBuildBuiltInModeList(pScrn, includelcdmodes, isfordvi, fakecrt2modes, IsForCRT2))) {
268772b676d7Smrg       if(!acceptcustommodes) {
268872b676d7Smrg	  while(pScrn->monitor->Modes)
268972b676d7Smrg             xf86DeleteMode(&pScrn->monitor->Modes, pScrn->monitor->Modes);
269072b676d7Smrg	  pScrn->monitor->Modes = mymodes;
269172b676d7Smrg       } else {
269272b676d7Smrg	  delmode = pScrn->monitor->Modes;
269372b676d7Smrg	  while(delmode) {
269472b676d7Smrg	     if(delmode->type & M_T_DEFAULT) {
269572b676d7Smrg	        tempmode = delmode->next;
269672b676d7Smrg	        xf86DeleteMode(&pScrn->monitor->Modes, delmode);
269772b676d7Smrg	        delmode = tempmode;
269872b676d7Smrg	     } else {
269972b676d7Smrg	        delmode = delmode->next;
270072b676d7Smrg	     }
270172b676d7Smrg	  }
270272b676d7Smrg	  /* Link default modes AFTER user ones */
270372b676d7Smrg	  if((tempmode = pScrn->monitor->Modes)) {
270472b676d7Smrg	     *havecustommodes = TRUE;
270572b676d7Smrg	     while(tempmode) {
270672b676d7Smrg	        if(!tempmode->next) break;
270772b676d7Smrg	        else tempmode = tempmode->next;
270872b676d7Smrg	     }
270972b676d7Smrg	     tempmode->next = mymodes;
271072b676d7Smrg	     mymodes->prev = tempmode;
271172b676d7Smrg	  } else {
271272b676d7Smrg	     pScrn->monitor->Modes = mymodes;
271372b676d7Smrg	  }
271472b676d7Smrg#if 0
271572b676d7Smrg	  pScrn->monitor->Modes = mymodes;
271672b676d7Smrg	  while(mymodes) {
271772b676d7Smrg	     if(!mymodes->next) break;
271872b676d7Smrg	     else mymodes = mymodes->next;
271972b676d7Smrg	  }
272072b676d7Smrg	  mymodes->next = tempmode;
272172b676d7Smrg	  if(tempmode) {
272272b676d7Smrg	     tempmode->prev = mymodes;
272372b676d7Smrg	  }
272472b676d7Smrg#endif
272572b676d7Smrg       }
272672b676d7Smrg       return TRUE;
272772b676d7Smrg    } else
272872b676d7Smrg       return FALSE;
272972b676d7Smrg}
273072b676d7Smrg
273172b676d7Smrgstatic void
273272b676d7SmrgSiSPrintModes(ScrnInfoPtr pScrn)
273372b676d7Smrg{
273472b676d7Smrg    DisplayModePtr p;
273572b676d7Smrg    float hsync, refresh = 0.0;
273672b676d7Smrg    char *desc, *desc2, *prefix, *uprefix, *output;
273772b676d7Smrg
273872b676d7Smrg    xf86DrvMsg(pScrn->scrnIndex, pScrn->virtualFrom, "Virtual size is %dx%d "
273972b676d7Smrg	       "(pitch %d)\n", pScrn->virtualX, pScrn->virtualY,
274072b676d7Smrg	       pScrn->displayWidth);
274172b676d7Smrg
274272b676d7Smrg    if((p = pScrn->modes) == NULL) return;
274372b676d7Smrg
274472b676d7Smrg    do {
274572b676d7Smrg	desc = desc2 = "";
274672b676d7Smrg	uprefix = " ";
274772b676d7Smrg	prefix = "Mode";
274872b676d7Smrg	output = "For CRT device: ";
274972b676d7Smrg	if(p->HSync > 0.0)      hsync = p->HSync;
275072b676d7Smrg	else if (p->HTotal > 0) hsync = (float)p->Clock / (float)p->HTotal;
275172b676d7Smrg	else	                hsync = 0.0;
275272b676d7Smrg	refresh = 0.0;
275372b676d7Smrg        if(p->VRefresh > 0.0)   refresh = p->VRefresh;
275472b676d7Smrg        else if (p->HTotal > 0 && p->VTotal > 0) {
275572b676d7Smrg	   refresh = p->Clock * 1000.0 / p->HTotal / p->VTotal;
275672b676d7Smrg	   if(p->Flags & V_INTERLACE) refresh *= 2.0;
275772b676d7Smrg	   if(p->Flags & V_DBLSCAN)   refresh /= 2.0;
275872b676d7Smrg	   if(p->VScan > 1)  	      refresh /= p->VScan;
275972b676d7Smrg        }
276072b676d7Smrg	if(p->Flags & V_INTERLACE) desc = " (I)";
276172b676d7Smrg	if(p->Flags & V_DBLSCAN)   desc = " (D)";
276272b676d7Smrg	if(p->VScan > 1) 	   desc2 = " (VScan)";
276372b676d7Smrg#ifdef M_T_USERDEF
276472b676d7Smrg	if(p->type & M_T_USERDEF)  uprefix = "*";
276572b676d7Smrg#endif
276672b676d7Smrg	if(p->type & M_T_BUILTIN)       {
276772b676d7Smrg	   prefix = "Built-in mode";
276872b676d7Smrg	   output = "";
276972b676d7Smrg	} else if (p->type & M_T_DEFAULT) {
277072b676d7Smrg	   prefix = "Default mode";
277172b676d7Smrg	} else {
277272b676d7Smrg	   output = "";
277372b676d7Smrg	}
277472b676d7Smrg
277572b676d7Smrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
277672b676d7Smrg		"%s%s \"%s\" (%dx%d) (%s%.1f MHz, %.1f kHz, %.1f Hz%s%s)\n",
277772b676d7Smrg		uprefix, prefix, p->name, p->HDisplay, p->VDisplay, output,
277872b676d7Smrg		p->Clock / 1000.0, hsync, refresh, desc, desc2);
277972b676d7Smrg
278072b676d7Smrg	p = p->next;
278172b676d7Smrg    } while (p != NULL && p != pScrn->modes);
278272b676d7Smrg}
278372b676d7Smrg
278472b676d7SmrgBool SISDetermineLCDACap(ScrnInfoPtr pScrn)
278572b676d7Smrg{
278672b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
278772b676d7Smrg
278872b676d7Smrg    if( ((pSiS->ChipType == SIS_650)    ||
278972b676d7Smrg         (pSiS->ChipType == SIS_315PRO) ||
279072b676d7Smrg         (pSiS->ChipType >= SIS_661))		&&
279172b676d7Smrg	(pSiS->ChipType != XGI_20)		&&
279272b676d7Smrg        (pSiS->VBFlags2 & VB2_SISLCDABRIDGE)	&&
279372b676d7Smrg	(pSiS->VESA != 1) ) {
279472b676d7Smrg       return TRUE;
279572b676d7Smrg    }
279672b676d7Smrg    return FALSE;
279772b676d7Smrg}
279872b676d7Smrg
279972b676d7Smrgvoid SISSaveDetectedDevices(ScrnInfoPtr pScrn)
280072b676d7Smrg{
280172b676d7Smrg    SISPtr  pSiS = SISPTR(pScrn);
280272b676d7Smrg    /* Backup detected CRT2 devices */
280372b676d7Smrg    pSiS->detectedCRT2Devices = pSiS->VBFlags & (CRT2_LCD|CRT2_TV|CRT2_VGA|TV_AVIDEO|TV_SVIDEO|
280472b676d7Smrg                                                 TV_SCART|TV_HIVISION|TV_YPBPR);
280572b676d7Smrg}
280672b676d7Smrg
280772b676d7Smrgstatic Bool
280872b676d7SmrgSISCheckBIOS(SISPtr pSiS, UShort mypciid, UShort mypcivendor, int biossize)
280972b676d7Smrg{
281072b676d7Smrg    UShort romptr, pciid;
281172b676d7Smrg
281272b676d7Smrg    if(!pSiS->BIOS) return FALSE;
281372b676d7Smrg
281472b676d7Smrg    if((pSiS->BIOS[0] != 0x55) || (pSiS->BIOS[1] != 0xaa)) return FALSE;
281572b676d7Smrg
281672b676d7Smrg    romptr = pSiS->BIOS[0x18] | (pSiS->BIOS[0x19] << 8);
281772b676d7Smrg    if(romptr > (biossize - 8)) return FALSE;
281872b676d7Smrg    if((pSiS->BIOS[romptr]   != 'P') || (pSiS->BIOS[romptr+1] != 'C') ||
281972b676d7Smrg       (pSiS->BIOS[romptr+2] != 'I') || (pSiS->BIOS[romptr+3] != 'R')) return FALSE;
282072b676d7Smrg
282172b676d7Smrg    pciid = pSiS->BIOS[romptr+4] | (pSiS->BIOS[romptr+5] << 8);
282272b676d7Smrg    if(pciid != mypcivendor) return FALSE;
282372b676d7Smrg
282472b676d7Smrg    pciid = pSiS->BIOS[romptr+6] | (pSiS->BIOS[romptr+7] << 8);
282572b676d7Smrg    if(pciid != mypciid) return FALSE;
282672b676d7Smrg
282772b676d7Smrg    return TRUE;
282872b676d7Smrg}
282972b676d7Smrg
283072b676d7Smrgstatic void
283172b676d7SmrgSiS_LoadInitVBE(ScrnInfoPtr pScrn)
283272b676d7Smrg{
283372b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
283472b676d7Smrg
283572b676d7Smrg    /* Don't load the VBE module for secondary
283672b676d7Smrg     * cards which sisfb POSTed. We don't want
283772b676d7Smrg     * int10 to overwrite our set up (such as
283872b676d7Smrg     * disabled a0000 memory address decoding).
283972b676d7Smrg     * We don't need the VBE anyway because
284072b676d7Smrg     * the card will never be in text mode,
284172b676d7Smrg     * and we can restore graphics modes just
284272b676d7Smrg     * perfectly.
284372b676d7Smrg     */
284472b676d7Smrg    if( !pSiS->Primary &&
284572b676d7Smrg        pSiS->sisfbcardposted)
284672b676d7Smrg       return;
284772b676d7Smrg
284872b676d7Smrg    if(pSiS->pVbe) return;
284972b676d7Smrg
285072b676d7Smrg    if(xf86LoadSubModule(pScrn, "vbe")) {
285172b676d7Smrg#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,99,0,0)
285272b676d7Smrg       pSiS->pVbe = VBEInit(pSiS->pInt, pSiS->pEnt->index);
285372b676d7Smrg#else
285472b676d7Smrg       pSiS->pVbe = VBEExtendedInit(pSiS->pInt, pSiS->pEnt->index,
285572b676d7Smrg	                SET_BIOS_SCRATCH | RESTORE_BIOS_SCRATCH);
285672b676d7Smrg#endif
285772b676d7Smrg    }
285872b676d7Smrg
285972b676d7Smrg    if(!pSiS->pVbe) {
286072b676d7Smrg       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
286172b676d7Smrg	   "Failed to load/initialize vbe module\n");
286272b676d7Smrg    }
286372b676d7Smrg}
286472b676d7Smrg
286572b676d7Smrg#ifdef SIS_PC_PLATFORM
286672b676d7Smrgstatic void
286772b676d7SmrgSiS_MapVGAMem(ScrnInfoPtr pScrn)
286872b676d7Smrg{
286972b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
287072b676d7Smrg
287172b676d7Smrg    /* Map 64k VGA window for saving/restoring CGA fonts */
287272b676d7Smrg    pSiS->VGAMapSize = 0x10000;
287372b676d7Smrg    pSiS->VGAMapPhys = 0;	/* Default */
287472b676d7Smrg    if((!pSiS->Primary) || (!pSiS->VGADecodingEnabled)) {
287572b676d7Smrg       /* If card is secondary or if a0000-address decoding
287672b676d7Smrg        * is disabled, set Phys to beginning of our video RAM.
287772b676d7Smrg	*/
28781fd23544Smrg       pSiS->VGAMapPhys = PCI_REGION_BASE(pSiS->PciInfo, 0, REGION_MEM);
287972b676d7Smrg    }
288072b676d7Smrg    if(!SiSVGAMapMem(pScrn)) {
288172b676d7Smrg       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
288272b676d7Smrg	  "Failed to map VGA memory (0x%lx), can't save/restore console fonts\n",
288372b676d7Smrg	  pSiS->VGAMapPhys);
288472b676d7Smrg    }
288572b676d7Smrg}
288672b676d7Smrg#endif
288772b676d7Smrg
288872b676d7Smrgstatic void
288972b676d7SmrgSiS_CheckKernelFB(ScrnInfoPtr pScrn)
289072b676d7Smrg{
289172b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
289272b676d7Smrg    int        fd, i;
289372b676d7Smrg    CARD32     sisfbinfosize = 0, sisfbversion;
289472b676d7Smrg    sisfb_info *mysisfbinfo;
289572b676d7Smrg    char       name[16];
289672b676d7Smrg
289772b676d7Smrg    pSiS->donttrustpdc = FALSE;
289872b676d7Smrg    pSiS->sisfbpdc = 0xff;
289972b676d7Smrg    pSiS->sisfbpdca = 0xff;
290072b676d7Smrg    pSiS->sisfblcda = 0xff;
290172b676d7Smrg    pSiS->sisfbscalelcd = -1;
290272b676d7Smrg    pSiS->sisfbspecialtiming = CUT_NONE;
290372b676d7Smrg    pSiS->sisfb_haveemi = FALSE;
290472b676d7Smrg    pSiS->sisfbfound = FALSE;
290572b676d7Smrg    pSiS->sisfb_tvposvalid = FALSE;
290672b676d7Smrg    pSiS->sisfbdevname[0] = 0;
290772b676d7Smrg    pSiS->sisfb_havelock = FALSE;
290872b676d7Smrg    pSiS->sisfbHaveNewHeapDef = FALSE;
290972b676d7Smrg    pSiS->sisfbHeapSize = 0;
291072b676d7Smrg    pSiS->sisfbVideoOffset = 0;
291172b676d7Smrg    pSiS->sisfbxSTN = FALSE;
291272b676d7Smrg    pSiS->sisfbcanpost = FALSE;   /* (Old) sisfb can't POST card */
291372b676d7Smrg    pSiS->sisfbcardposted = TRUE; /* If (old) sisfb is running, card must have been POSTed */
291472b676d7Smrg    pSiS->sisfbprimary = FALSE;   /* (Old) sisfb doesn't know */
291572b676d7Smrg
291672b676d7Smrg    if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
291772b676d7Smrg
291872b676d7Smrg       i = 0;
291972b676d7Smrg       do {
292072b676d7Smrg
292172b676d7Smrg	  if(i <= 7) {
292272b676d7Smrg             sprintf(name, "/dev/fb%1d", i);
292372b676d7Smrg	  } else {
292472b676d7Smrg	     sprintf(name, "/dev/fb/%1d", (i - 8));
292572b676d7Smrg	  }
292672b676d7Smrg
29271fd23544Smrg          if((fd = open(name, O_RDONLY)) != -1) {
292872b676d7Smrg
292972b676d7Smrg	     Bool gotit = FALSE;
293072b676d7Smrg
293172b676d7Smrg 	     if(!ioctl(fd, SISFB_GET_INFO_SIZE, &sisfbinfosize)) {
29325788ca14Smrg 		if((mysisfbinfo = malloc(sisfbinfosize))) {
293372b676d7Smrg 		   if(!ioctl(fd, (SISFB_GET_INFO | (sisfbinfosize << 16)), mysisfbinfo)) {
293472b676d7Smrg 		      gotit = TRUE;
293572b676d7Smrg 		   } else {
29365788ca14Smrg 		      free(mysisfbinfo);
293772b676d7Smrg 		      mysisfbinfo = NULL;
293872b676d7Smrg 		   }
293972b676d7Smrg 		}
294072b676d7Smrg 	     } else {
29415788ca14Smrg 		if((mysisfbinfo = malloc(sizeof(*mysisfbinfo) + 16))) {
294272b676d7Smrg 		   if(!ioctl(fd, SISFB_GET_INFO_OLD, mysisfbinfo)) {
294372b676d7Smrg 		      gotit = TRUE;
294472b676d7Smrg		      xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
294572b676d7Smrg				"Possibly old version of sisfb detected. Please update.\n");
294672b676d7Smrg		   } else {
29475788ca14Smrg		      free(mysisfbinfo);
294872b676d7Smrg		      mysisfbinfo = NULL;
294972b676d7Smrg		   }
295072b676d7Smrg		}
295172b676d7Smrg	     }
295272b676d7Smrg
295372b676d7Smrg	     if(gotit) {
295472b676d7Smrg
295572b676d7Smrg		if(mysisfbinfo->sisfb_id == SISFB_ID) {
295672b676d7Smrg
295772b676d7Smrg		   sisfbversion = (mysisfbinfo->sisfb_version << 16) |
295872b676d7Smrg				  (mysisfbinfo->sisfb_revision << 8) |
295972b676d7Smrg				  (mysisfbinfo->sisfb_patchlevel);
296072b676d7Smrg
296172b676d7Smrg	           if(sisfbversion >= SISFB_VERSION(1, 5, 8)) {
296272b676d7Smrg		      /* Added PCI bus/slot/func into in sisfb Version 1.5.08.
296372b676d7Smrg		       * Check this to make sure we run on the same card as sisfb
296472b676d7Smrg		       */
296572b676d7Smrg		      if((mysisfbinfo->sisfb_pcibus  == pSiS->PciBus)    &&
296672b676d7Smrg			 (mysisfbinfo->sisfb_pcislot == pSiS->PciDevice) &&
296772b676d7Smrg			 (mysisfbinfo->sisfb_pcifunc == pSiS->PciFunc)) {
296872b676d7Smrg			 pSiS->sisfbfound = TRUE;
296972b676d7Smrg		      }
297072b676d7Smrg		   } else pSiS->sisfbfound = TRUE;
297172b676d7Smrg
297272b676d7Smrg		   if(pSiS->sisfbfound) {
297372b676d7Smrg		      xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
297472b676d7Smrg			     "%s: SiS kernel fb driver (sisfb) %d.%d.%d detected (PCI:%02d:%02d.%d)\n",
297572b676d7Smrg				&name[5],
297672b676d7Smrg				mysisfbinfo->sisfb_version,
297772b676d7Smrg				mysisfbinfo->sisfb_revision,
297872b676d7Smrg				mysisfbinfo->sisfb_patchlevel,
297972b676d7Smrg				pSiS->PciBus,
298072b676d7Smrg				pSiS->PciDevice,
298172b676d7Smrg				pSiS->PciFunc);
298272b676d7Smrg
298372b676d7Smrg		      /* Added version/rev/pl in sisfb 1.4.0 */
298472b676d7Smrg		      if(mysisfbinfo->sisfb_version == 0) {
298572b676d7Smrg			 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
298672b676d7Smrg				"Old version of sisfb found. Please update.\n");
298772b676d7Smrg		      }
298872b676d7Smrg		      /* Basically, we can't trust the pdc register if sisfb is loaded */
298972b676d7Smrg		      pSiS->donttrustpdc = TRUE;
299072b676d7Smrg		      pSiS->sisfbHeapStart = mysisfbinfo->heapstart;
299172b676d7Smrg
299272b676d7Smrg		      if(sisfbversion >= SISFB_VERSION(1, 7, 20)) {
299372b676d7Smrg			 pSiS->sisfbHeapSize = mysisfbinfo->sisfb_heapsize;
299472b676d7Smrg			 pSiS->sisfbVideoOffset = mysisfbinfo->sisfb_videooffset;
299572b676d7Smrg			 pSiS->sisfbHaveNewHeapDef = TRUE;
299672b676d7Smrg			 pSiS->sisfbFSTN = mysisfbinfo->sisfb_curfstn;
299772b676d7Smrg			 pSiS->sisfbDSTN = mysisfbinfo->sisfb_curdstn;
299872b676d7Smrg			 pSiS->sisfbxSTN = TRUE;
299972b676d7Smrg			 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
300072b676d7Smrg				"sisfb: memory heap at %dKB, size %dKB, viewport at %dKB\n",
300172b676d7Smrg				(int)pSiS->sisfbHeapStart, (int)pSiS->sisfbHeapSize,
300272b676d7Smrg				(int)pSiS->sisfbVideoOffset/1024);
300372b676d7Smrg		      } else {
300472b676d7Smrg			 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
300572b676d7Smrg				"sisfb: memory heap at %dKB\n", (int)pSiS->sisfbHeapStart);
300672b676d7Smrg		      }
300772b676d7Smrg		      xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
300872b676d7Smrg				"sisfb: using video mode 0x%02x\n", mysisfbinfo->fbvidmode);
300972b676d7Smrg		      pSiS->OldMode = mysisfbinfo->fbvidmode;
301072b676d7Smrg		      if(sisfbversion >= SISFB_VERSION(1, 5, 6)) {
301172b676d7Smrg			 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
301272b676d7Smrg				"sisfb: using %s, reserved %dK\n",
301372b676d7Smrg				(mysisfbinfo->sisfb_caps & 0x40) ? "SiS300 series Turboqueue" :
301472b676d7Smrg				   (mysisfbinfo->sisfb_caps & 0x20) ? "SiS315/330/340 series AGP command queue" :
301572b676d7Smrg				      (mysisfbinfo->sisfb_caps & 0x10) ? "SiS315/330/340 series VRAM command queue" :
301672b676d7Smrg					(mysisfbinfo->sisfb_caps & 0x08) ? "SiS315/330/340 series MMIO mode" :
301772b676d7Smrg					   "no command queue",
301872b676d7Smrg				(int)mysisfbinfo->sisfb_tqlen);
301972b676d7Smrg		      }
302072b676d7Smrg		      if(sisfbversion >= SISFB_VERSION(1, 5, 10)) {
302172b676d7Smrg			 /* We can trust the pdc value if sisfb is of recent version */
302272b676d7Smrg			 if(pSiS->VGAEngine == SIS_300_VGA) pSiS->donttrustpdc = FALSE;
302372b676d7Smrg		      }
302472b676d7Smrg		      if(sisfbversion >= SISFB_VERSION(1, 5, 11)) {
302572b676d7Smrg			 if(pSiS->VGAEngine == SIS_300_VGA) {
302672b676d7Smrg			    /* As of 1.5.11, sisfb saved the register for us (300 series) */
302772b676d7Smrg			    pSiS->sisfbpdc = mysisfbinfo->sisfb_lcdpdc;
302872b676d7Smrg			    if(!pSiS->sisfbpdc) pSiS->sisfbpdc = 0xff;
302972b676d7Smrg			 }
303072b676d7Smrg		      }
303172b676d7Smrg		      if(sisfbversion >= SISFB_VERSION(1, 5, 14)) {
303272b676d7Smrg			 if(pSiS->VGAEngine == SIS_315_VGA) {
303372b676d7Smrg			    pSiS->sisfblcda = mysisfbinfo->sisfb_lcda;
303472b676d7Smrg			 }
303572b676d7Smrg		      }
303672b676d7Smrg		      if(sisfbversion >= SISFB_VERSION(1, 6, 13)) {
303772b676d7Smrg			 pSiS->sisfbscalelcd = mysisfbinfo->sisfb_scalelcd;
303872b676d7Smrg			 pSiS->sisfbspecialtiming = mysisfbinfo->sisfb_specialtiming;
303972b676d7Smrg		      }
304072b676d7Smrg		      if(sisfbversion >= SISFB_VERSION(1, 6, 16)) {
304172b676d7Smrg			 if(pSiS->VGAEngine == SIS_315_VGA) {
304272b676d7Smrg			    pSiS->donttrustpdc = FALSE;
304372b676d7Smrg			    pSiS->sisfbpdc = mysisfbinfo->sisfb_lcdpdc;
304472b676d7Smrg			    if(sisfbversion >= SISFB_VERSION(1, 6, 24)) {
304572b676d7Smrg			       pSiS->sisfb_haveemi = mysisfbinfo->sisfb_haveemi ? TRUE : FALSE;
304672b676d7Smrg			       pSiS->sisfb_haveemilcd = TRUE;  /* will match most cases */
304772b676d7Smrg			       pSiS->sisfb_emi30 = mysisfbinfo->sisfb_emi30;
304872b676d7Smrg			       pSiS->sisfb_emi31 = mysisfbinfo->sisfb_emi31;
304972b676d7Smrg			       pSiS->sisfb_emi32 = mysisfbinfo->sisfb_emi32;
305072b676d7Smrg			       pSiS->sisfb_emi33 = mysisfbinfo->sisfb_emi33;
305172b676d7Smrg			    }
305272b676d7Smrg			    if(sisfbversion >= SISFB_VERSION(1, 6, 25)) {
305372b676d7Smrg			       pSiS->sisfb_haveemilcd = mysisfbinfo->sisfb_haveemilcd ? TRUE : FALSE;
305472b676d7Smrg			    }
305572b676d7Smrg			    if(sisfbversion >= SISFB_VERSION(1, 6, 31)) {
305672b676d7Smrg			       pSiS->sisfbpdca = mysisfbinfo->sisfb_lcdpdca;
305772b676d7Smrg			    } else {
305872b676d7Smrg			       if(pSiS->sisfbpdc) {
305972b676d7Smrg				  pSiS->sisfbpdca = (pSiS->sisfbpdc & 0xf0) >> 3;
306072b676d7Smrg				  pSiS->sisfbpdc  = (pSiS->sisfbpdc & 0x0f) << 1;
306172b676d7Smrg			       } else {
306272b676d7Smrg				  pSiS->sisfbpdca = pSiS->sisfbpdc = 0xff;
306372b676d7Smrg			       }
306472b676d7Smrg			    }
306572b676d7Smrg			 }
306672b676d7Smrg		      }
306772b676d7Smrg		      if(sisfbversion >= SISFB_VERSION(1, 7, 0)) {
306872b676d7Smrg		         pSiS->sisfb_havelock = TRUE;
306972b676d7Smrg			 if(sisfbversion >= SISFB_VERSION(1, 7, 1)) {
307072b676d7Smrg			    pSiS->sisfb_tvxpos = mysisfbinfo->sisfb_tvxpos;
307172b676d7Smrg			    pSiS->sisfb_tvypos = mysisfbinfo->sisfb_tvypos;
307272b676d7Smrg			    pSiS->sisfb_tvposvalid = TRUE;
307372b676d7Smrg			 }
307472b676d7Smrg		      }
307572b676d7Smrg		      if(sisfbversion >= SISFB_VERSION(1, 8, 7)) {
307672b676d7Smrg			 pSiS->sisfbcanpost = (mysisfbinfo->sisfb_can_post) ? TRUE : FALSE;
307772b676d7Smrg			 pSiS->sisfbcardposted = (mysisfbinfo->sisfb_card_posted) ? TRUE : FALSE;
307872b676d7Smrg			 pSiS->sisfbprimary = (mysisfbinfo->sisfb_was_boot_device) ? TRUE : FALSE;
307972b676d7Smrg			 /* Validity check */
308072b676d7Smrg			 if(!pSiS->sisfbcardposted) {
308172b676d7Smrg			    pSiS->sisfbprimary = FALSE;
308272b676d7Smrg			 }
308372b676d7Smrg		      }
308472b676d7Smrg		   }
308572b676d7Smrg	        }
30865788ca14Smrg		free(mysisfbinfo);
308772b676d7Smrg		mysisfbinfo = NULL;
308872b676d7Smrg	     }
308972b676d7Smrg	     close (fd);
309072b676d7Smrg          }
309172b676d7Smrg	  i++;
309272b676d7Smrg       } while((i <= 15) && (!pSiS->sisfbfound));
309372b676d7Smrg
309472b676d7Smrg       if(pSiS->sisfbfound) {
309572b676d7Smrg          strncpy(pSiS->sisfbdevname, name, 15);
309672b676d7Smrg       } else {
309772b676d7Smrg          xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "sisfb not found\n");
309872b676d7Smrg       }
309972b676d7Smrg    }
310072b676d7Smrg
310172b676d7Smrg    if(!pSiS->sisfbfound) {
310272b676d7Smrg       pSiS->sisfbcardposted = FALSE;
310372b676d7Smrg    }
310472b676d7Smrg}
310572b676d7Smrg
310672b676d7Smrgstatic void
310772b676d7SmrgSiSPseudo(ScrnInfoPtr pScrn)
310872b676d7Smrg{
310972b676d7Smrg}
311072b676d7Smrg
311172b676d7Smrg/* PreInit()
311272b676d7Smrg *
311372b676d7Smrg * Mandatory
311472b676d7Smrg */
311572b676d7Smrgstatic Bool
311672b676d7SmrgSISPreInit(ScrnInfoPtr pScrn, int flags)
311772b676d7Smrg{
311872b676d7Smrg    SISPtr pSiS;
311972b676d7Smrg#ifdef SISDUALHEAD
312072b676d7Smrg    SISEntPtr pSiSEnt = NULL;
312172b676d7Smrg#endif
312272b676d7Smrg    MessageType from;
312372b676d7Smrg    UChar usScratchCR17, usScratchCR32, usScratchCR63;
312472b676d7Smrg    UChar usScratchSR1F, srlockReg, crlockReg;
312572b676d7Smrg    unsigned int i;
312672b676d7Smrg    int pix24flags, temp;
312772b676d7Smrg    ClockRangePtr clockRanges;
312872b676d7Smrg    xf86MonPtr pMonitor = NULL;
312972b676d7Smrg    Bool didddc2, fromDDC, crt1freqoverruled = FALSE;
313072b676d7Smrg    UChar CR5F, tempreg;
313172b676d7Smrg#if defined(SISMERGED) || defined(SISDUALHEAD)
313272b676d7Smrg    DisplayModePtr first, p, n;
313372b676d7Smrg#endif
313472b676d7Smrg#ifdef SISMERGED
313572b676d7Smrg    Bool crt2freqoverruled = FALSE;
313672b676d7Smrg#endif
313772b676d7Smrg
313872b676d7Smrg    static const char *ddcsstr = "CRT%d DDC monitor info: *******************************************\n";
313972b676d7Smrg    static const char *ddcestr = "End of CRT%d DDC monitor info *************************************\n";
314072b676d7Smrg    static const char *subshstr = "Substituting missing CRT%d monitor HSync range by DDC data\n";
314172b676d7Smrg    static const char *subsvstr = "Substituting missing CRT%d monitor VRefresh range by DDC data\n";
314272b676d7Smrg    static const char *saneh = "Correcting %s CRT%d monitor HSync range\n";
314372b676d7Smrg    static const char *sanev = "Correcting %s CRT%d monitor VRefresh range\n";
314472b676d7Smrg#ifdef SISMERGED
314572b676d7Smrg    static const char *mergednocrt1 = "CRT1 not detected or forced off. %s.\n";
314672b676d7Smrg    static const char *mergednocrt2 = "No CRT2 output selected or no video bridge detected. %s.\n";
314772b676d7Smrg    static const char *mergeddisstr = "MergedFB mode disabled";
314872b676d7Smrg    static const char *modesforstr = "Modes for CRT%d: **************************************************\n";
314972b676d7Smrg    static const char *crtsetupstr = "*************************** CRT%d setup ***************************\n";
315072b676d7Smrg    static const char *crt2monname = "CRT2";
315172b676d7Smrg#endif
315272b676d7Smrg#if defined(SISDUALHEAD) || defined(SISMERGED)
315372b676d7Smrg    static const char *notsuitablestr = "Not using mode \"%s\" (not suitable for %s mode)\n";
315472b676d7Smrg#endif
315572b676d7Smrg
315672b676d7Smrg    if(flags & PROBE_DETECT) {
315772b676d7Smrg
315872b676d7Smrg       vbeInfoPtr   pVbe;
315972b676d7Smrg
316072b676d7Smrg       if(xf86LoadSubModule(pScrn, "vbe")) {
316172b676d7Smrg          int index = xf86GetEntityInfo(pScrn->entityList[0])->index;
316272b676d7Smrg#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,99,0,0)
316372b676d7Smrg	  if((pVbe = VBEInit(NULL, index)))
316472b676d7Smrg#else
316572b676d7Smrg          if((pVbe = VBEExtendedInit(NULL, index, 0)))
316672b676d7Smrg#endif
316772b676d7Smrg          {
316872b676d7Smrg             ConfiguredMonitor = vbeDoEDID(pVbe, NULL);
316972b676d7Smrg             vbeFree(pVbe);
317072b676d7Smrg          }
317172b676d7Smrg       }
317272b676d7Smrg       return TRUE;
317372b676d7Smrg    }
317472b676d7Smrg
317572b676d7Smrg    /*
317672b676d7Smrg     * Note: This function is only called once at server startup, and
317772b676d7Smrg     * not at the start of each server generation.  This means that
317872b676d7Smrg     * only things that are persistent across server generations can
317972b676d7Smrg     * be initialised here.  xf86Screens[] is the array of all screens,
318072b676d7Smrg     * (pScrn is a pointer to one of these).  Privates allocated using
318172b676d7Smrg     * xf86AllocateScrnInfoPrivateIndex() are too, and should be used
318272b676d7Smrg     * for data that must persist across server generations.
318372b676d7Smrg     *
318472b676d7Smrg     * Per-generation data should be allocated with
318572b676d7Smrg     * AllocateScreenPrivateIndex() from the ScreenInit() function.
318672b676d7Smrg     */
318772b676d7Smrg
318872b676d7Smrg    /* Check the number of entities, and fail if it isn't one. */
318972b676d7Smrg    if(pScrn->numEntities != 1) {
319072b676d7Smrg       SISErrorLog(pScrn, "Number of entities is not 1\n");
319172b676d7Smrg       return FALSE;
319272b676d7Smrg    }
319372b676d7Smrg
319472b676d7Smrg    /* Due to the liberal license terms this is needed for
319572b676d7Smrg     * keeping the copyright notice readable and intact in
319672b676d7Smrg     * binary distributions. Removing this is a copyright
319772b676d7Smrg     * infringement. Please read the license terms above.
319872b676d7Smrg     */
319972b676d7Smrg
320072b676d7Smrg    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
320172b676d7Smrg	"SiS driver (%d/%02d/%02d-%d, compiled for " SISMYSERVERNAME " %d.%d.%d.%d)\n",
320272b676d7Smrg	SISDRIVERVERSIONYEAR + 2000, SISDRIVERVERSIONMONTH,
320372b676d7Smrg	SISDRIVERVERSIONDAY, SISDRIVERREVISION,
320472b676d7Smrg#ifdef XORG_VERSION_CURRENT
320572b676d7Smrg	XORG_VERSION_MAJOR, XORG_VERSION_MINOR,
320672b676d7Smrg	XORG_VERSION_PATCH, XORG_VERSION_SNAP
320772b676d7Smrg#else
320872b676d7Smrg	XF86_VERSION_MAJOR, XF86_VERSION_MINOR,
320972b676d7Smrg	XF86_VERSION_PATCH, XF86_VERSION_SNAP
321072b676d7Smrg#endif
321172b676d7Smrg	);
321272b676d7Smrg    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
321372b676d7Smrg	"Copyright (C) 2001-2005 Thomas Winischhofer <thomas@winischhofer.net> and others\n");
321472b676d7Smrg    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3215e35772b2Smrg	"*** See http://www.winischhofer.eu/linuxsisvga.shtml\n");
321672b676d7Smrg    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
321772b676d7Smrg	"*** for documentation and updates.\n");
321872b676d7Smrg
321972b676d7Smrg#ifdef XORG_VERSION_CURRENT
322072b676d7Smrg#if 0  /* no prototype yet */
322172b676d7Smrg    if(xorgGetVersion() != XORG_VERSION_CURRENT) {
322272b676d7Smrg       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
322372b676d7Smrg         "This driver binary is not compiled for this version of " SISMYSERVERNAME "\n");
322472b676d7Smrg    }
322572b676d7Smrg#endif
322672b676d7Smrg#else
322772b676d7Smrg#if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4,2,99,0,0)
322872b676d7Smrg    if(xf86GetVersion() != XF86_VERSION_CURRENT) {
322972b676d7Smrg       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
323072b676d7Smrg         "This driver binary is not compiled for this version of " SISMYSERVERNAME "\n");
323172b676d7Smrg    }
323272b676d7Smrg#endif
323372b676d7Smrg#endif
323472b676d7Smrg
323572b676d7Smrg    /* Allocate the SISRec driverPrivate */
323672b676d7Smrg    if(!SISGetRec(pScrn)) {
323772b676d7Smrg       SISErrorLog(pScrn, "Could not allocate memory for pSiS private\n");
323872b676d7Smrg       return FALSE;
323972b676d7Smrg    }
324072b676d7Smrg    pSiS = SISPTR(pScrn);
324172b676d7Smrg    pSiS->pScrn = pScrn;
324272b676d7Smrg
324372b676d7Smrg    pSiS->pInt = NULL;
324472b676d7Smrg
324572b676d7Smrg    /* Save PCI Domain Base */
32465788ca14Smrg#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,99,0,0) || GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 12
324772b676d7Smrg    pSiS->IODBase = 0;
324872b676d7Smrg#else
324972b676d7Smrg    pSiS->IODBase = pScrn->domainIOBase;
325072b676d7Smrg#endif
325172b676d7Smrg
325272b676d7Smrg    /* Get the entity, and make sure it is PCI. */
325372b676d7Smrg    pSiS->pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
325472b676d7Smrg    if(pSiS->pEnt->location.type != BUS_PCI) {
325572b676d7Smrg       SISErrorLog(pScrn, "Entity's bus type is not PCI\n");
325672b676d7Smrg       goto my_error_0;
325772b676d7Smrg    }
325872b676d7Smrg
325972b676d7Smrg#ifdef SISDUALHEAD
326072b676d7Smrg    /* Allocate an entity private if necessary */
326172b676d7Smrg    if(xf86IsEntityShared(pScrn->entityList[0])) {
326272b676d7Smrg       pSiSEnt = xf86GetEntityPrivate(pScrn->entityList[0], SISEntityIndex)->ptr;
326372b676d7Smrg       pSiS->entityPrivate = pSiSEnt;
326472b676d7Smrg
326572b676d7Smrg       /* If something went wrong, quit here */
326672b676d7Smrg       if((pSiSEnt->DisableDual) || (pSiSEnt->ErrorAfterFirst)) {
326772b676d7Smrg	  SISErrorLog(pScrn, "First head encountered fatal error, aborting...\n");
326872b676d7Smrg	  goto my_error_0;
326972b676d7Smrg       }
327072b676d7Smrg    }
327172b676d7Smrg#endif
327272b676d7Smrg
327372b676d7Smrg    /* Find the PCI info for this screen */
327472b676d7Smrg    pSiS->PciInfo = xf86GetPciInfoForEntity(pSiS->pEnt->index);
32751fd23544Smrg    pSiS->PciBus = PCI_CFG_BUS(pSiS->PciInfo);    /*SIS_PCI_BUS(pSiS->PciInfo);*/
32761fd23544Smrg    pSiS->PciDevice = PCI_CFG_DEV(pSiS->PciInfo); /*SIS_PCI_DEVICE(pSiS->PciInfo);*/
32771fd23544Smrg    pSiS->PciFunc = PCI_CFG_FUNC(pSiS->PciInfo);  /*SIS_PCI_FUNC(pSiS->PciInfo);*/
32781fd23544Smrg
32791fd23544Smrg    pSiS->PciTag = pciTag(PCI_DEV_BUS(pSiS->PciInfo),
32801fd23544Smrg			  PCI_DEV_DEV(pSiS->PciInfo),
32811fd23544Smrg			  PCI_DEV_FUNC(pSiS->PciInfo));
328272b676d7Smrg
328372b676d7Smrg#ifdef SIS_NEED_MAP_IOP
328472b676d7Smrg    /********************************************/
328572b676d7Smrg    /*     THIS IS BROKEN AND WON'T WORK        */
328672b676d7Smrg    /* Reasons:                                 */
328772b676d7Smrg    /* 1) MIPS and ARM have no i/o ports but    */
328872b676d7Smrg    /* use memory mapped i/o only. The inX/outX */
328972b676d7Smrg    /* macros in compiler.h are smart enough to */
329072b676d7Smrg    /* add "IOPortBase" to the port number, but */
329172b676d7Smrg    /* "IOPortBase" is never initialized.       */
329272b676d7Smrg    /* 2) IOPortBase is declared in compiler.h  */
329372b676d7Smrg    /* itself. So until somebody fixes all      */
329472b676d7Smrg    /* modules that #include compiler.h to set  */
329572b676d7Smrg    /* IOPortBase, vga support for MIPS and ARM */
329672b676d7Smrg    /* is unusable.                             */
329772b676d7Smrg    /* (In this driver this is solvable because */
329872b676d7Smrg    /* we have our own vgaHW routines. However, */
329972b676d7Smrg    /* we use /dev/port for now instead.)       */
330072b676d7Smrg    /********************************************/
330172b676d7Smrg    pSiS->IOPAddress = pSiS->IODBase + pSiS->PciInfo->ioBase[2];
330272b676d7Smrg    if(!SISMapIOPMem(pScrn)) {
330372b676d7Smrg       SISErrorLog(pScrn, "Could not map I/O port area at 0x%x\n", pSiS->IOPAddress);
330472b676d7Smrg       goto my_error_0;
330572b676d7Smrg    } else {
330672b676d7Smrg       xf86DrvMsg(pScrn->scrnIndex, X_INFO, "I/O port area mapped to %p, size 128\n", pSiS->IOPBase);
330772b676d7Smrg#if defined(__mips__) || defined(__arm32__)
330872b676d7Smrg       /* inX/outX macros on these use IOPortBase as offset */
330972b676d7Smrg       /* This is entirely skrewed. */
331072b676d7Smrg       IOPortBase = (unsigned int)pSiS->IOPBase;
331172b676d7Smrg#endif
331272b676d7Smrg    }
331372b676d7Smrg#endif
331472b676d7Smrg
331572b676d7Smrg    /* Set up i/o port access (for non-x86) */
331672b676d7Smrg#ifdef SISUSEDEVPORT
331772b676d7Smrg    if((sisdevport = open("/dev/port", O_RDWR, 0)) == -1) {
331872b676d7Smrg       SISErrorLog(pScrn, "Failed to open /dev/port for read/write\n");
331972b676d7Smrg       goto my_error_0;
332072b676d7Smrg    }
332172b676d7Smrg    pSiS->sisdevportopen = TRUE;
332272b676d7Smrg#endif
332372b676d7Smrg
332472b676d7Smrg    /*
332572b676d7Smrg     * Set the Chipset and ChipRev, allowing config file entries to
332672b676d7Smrg     * override. DANGEROUS!
332772b676d7Smrg     */
332872b676d7Smrg    {
332972b676d7Smrg       SymTabRec *myChipsets = SISChipsets;
333072b676d7Smrg
33311fd23544Smrg       if(PCI_DEV_VENDOR_ID(pSiS->PciInfo) == PCI_VENDOR_XGI) {
333272b676d7Smrg          myChipsets = XGIChipsets;
333372b676d7Smrg       }
333472b676d7Smrg
333572b676d7Smrg       if(pSiS->pEnt->device->chipset && *pSiS->pEnt->device->chipset) {
333672b676d7Smrg
333772b676d7Smrg          pScrn->chipset = pSiS->pEnt->device->chipset;
333872b676d7Smrg          pSiS->Chipset = xf86StringToToken(myChipsets, pScrn->chipset);
333972b676d7Smrg
334072b676d7Smrg       } else if(pSiS->pEnt->device->chipID >= 0) {
334172b676d7Smrg
334272b676d7Smrg          pSiS->Chipset = pSiS->pEnt->device->chipID;
334372b676d7Smrg          pScrn->chipset = (char *)xf86TokenToString(myChipsets, pSiS->Chipset);
334472b676d7Smrg
334572b676d7Smrg          xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipID override: 0x%04X\n",
334672b676d7Smrg								pSiS->Chipset);
334772b676d7Smrg       } else {
334872b676d7Smrg
33491fd23544Smrg          pSiS->Chipset = PCI_DEV_DEVICE_ID(pSiS->PciInfo);
335072b676d7Smrg          pScrn->chipset = (char *)xf86TokenToString(myChipsets, pSiS->Chipset);
335172b676d7Smrg
335272b676d7Smrg       }
335372b676d7Smrg    }
335472b676d7Smrg
335572b676d7Smrg    if(pSiS->pEnt->device->chipRev >= 0) {
335672b676d7Smrg
335772b676d7Smrg       pSiS->ChipRev = pSiS->pEnt->device->chipRev;
335872b676d7Smrg       xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipRev override: %d\n",
335972b676d7Smrg								pSiS->ChipRev);
336072b676d7Smrg    } else {
336172b676d7Smrg
33621fd23544Smrg       pSiS->ChipRev = PCI_DEV_REVISION(pSiS->PciInfo);
336372b676d7Smrg
336472b676d7Smrg    }
336572b676d7Smrg
336672b676d7Smrg    /*
336772b676d7Smrg     * This shouldn't happen because such problems should be caught in
336872b676d7Smrg     * SISProbe(), but check it just in case the user has overridden them.
336972b676d7Smrg     */
337072b676d7Smrg    if(pScrn->chipset == NULL) {
337172b676d7Smrg       SISErrorLog(pScrn, "ChipID 0x%04X is not recognised\n", pSiS->Chipset);
337272b676d7Smrg       goto my_error_0;
337372b676d7Smrg    }
337472b676d7Smrg    if(pSiS->Chipset < 0) {
337572b676d7Smrg       SISErrorLog(pScrn, "Chipset \"%s\" is not recognised\n", pScrn->chipset);
337672b676d7Smrg       goto my_error_0;
337772b676d7Smrg    }
337872b676d7Smrg
337972b676d7Smrg    pSiS->SiS6326Flags = 0;
338072b676d7Smrg
338172b676d7Smrg    /* Determine VGA engine generation */
338272b676d7Smrg    switch(pSiS->Chipset) {
338372b676d7Smrg       case PCI_CHIP_SIS300:
338472b676d7Smrg       case PCI_CHIP_SIS540:
338572b676d7Smrg       case PCI_CHIP_SIS630: /* 630 + 730 */
338672b676d7Smrg          pSiS->VGAEngine = SIS_300_VGA;
338772b676d7Smrg	  break;
338872b676d7Smrg       case PCI_CHIP_SIS315H:
338972b676d7Smrg       case PCI_CHIP_SIS315:
339072b676d7Smrg       case PCI_CHIP_SIS315PRO:
339172b676d7Smrg       case PCI_CHIP_SIS550:
339272b676d7Smrg       case PCI_CHIP_SIS650: /* 650 + 740 */
339372b676d7Smrg       case PCI_CHIP_SIS330:
339472b676d7Smrg       case PCI_CHIP_SIS660: /* 660, 661, 741, 760, 761, 670(?), 770 */
339572b676d7Smrg       case PCI_CHIP_SIS340:
339672b676d7Smrg       case PCI_CHIP_XGIXG20:
339772b676d7Smrg       case PCI_CHIP_XGIXG40:
339872b676d7Smrg          pSiS->VGAEngine = SIS_315_VGA;
339972b676d7Smrg	  break;
340072b676d7Smrg       case PCI_CHIP_SIS530:
340172b676d7Smrg          pSiS->VGAEngine = SIS_530_VGA;
340272b676d7Smrg	  break;
340372b676d7Smrg       case PCI_CHIP_SIS6326:
340472b676d7Smrg          /* Determine SiS6326 revision. According to SiS the differences are:
340572b676d7Smrg	   * Chip name     Chip type      TV-Out       MPEG II decoder
340672b676d7Smrg	   * 6326 AGP      Rev. G0/H0     no           no
340772b676d7Smrg	   * 6326 DVD      Rev. D2        yes          yes
340872b676d7Smrg	   * 6326          Rev. Cx        yes          yes
340972b676d7Smrg	   */
341072b676d7Smrg	  xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
341172b676d7Smrg		"Chipset is SiS6326 %s (revision 0x%02x)\n",
341272b676d7Smrg		(pSiS->ChipRev == 0xaf) ? "(Ax)" :
341372b676d7Smrg		   ((pSiS->ChipRev == 0x0a) ? "AGP (G0)" :
341472b676d7Smrg		      ((pSiS->ChipRev == 0x0b) ? "AGP (H0)" :
341572b676d7Smrg			 (((pSiS->ChipRev & 0xf0) == 0xd0) ? "DVD (Dx/H0)" :
341672b676d7Smrg			    (((pSiS->ChipRev & 0xf0) == 0x90) ? "(9x)" :
341772b676d7Smrg			       (((pSiS->ChipRev & 0xf0) == 0xc0) ? "(Cx)" :
341872b676d7Smrg				  "(unknown)"))))),
341972b676d7Smrg		pSiS->ChipRev);
342072b676d7Smrg	  if((pSiS->ChipRev != 0x0a) && (pSiS->ChipRev != 0x0b)) {
342172b676d7Smrg	     pSiS->SiS6326Flags |= SIS6326_HASTV;
342272b676d7Smrg	  }
342372b676d7Smrg	  /* fall through */
342472b676d7Smrg       default:
342572b676d7Smrg	  pSiS->VGAEngine = SIS_OLD_VGA;
342672b676d7Smrg    }
342772b676d7Smrg
342872b676d7Smrg    /* We don't know about the current mode yet */
342972b676d7Smrg    pSiS->OldMode = 0;
343072b676d7Smrg
343172b676d7Smrg    /* Determine whether this is the primary or a secondary
343272b676d7Smrg     * display adapter. And right here the problem starts:
343372b676d7Smrg     * On machines with integrated SiS chipsets, the system BIOS
343472b676d7Smrg     * usually sets VGA_EN on all PCI-to-PCI bridges in the system
343572b676d7Smrg     * (of which there usually are two: PCI and AGP). This and
343672b676d7Smrg     * the fact that any PCI card POSTed by sisfb naturally has
343772b676d7Smrg     * its PCI resources enabled, leads to X assuming that
343872b676d7Smrg     * there are more than one "primary" cards in the system.
343972b676d7Smrg     * In this case, X treats ALL cards as "secondary" -
344072b676d7Smrg     * which by no means is desireable. If sisfb is running,
344172b676d7Smrg     * we can determine which card really is "primary" (in
344272b676d7Smrg     * terms of if it's the one that occupies the A0000 area
344372b676d7Smrg     * etc.) in a better way (Linux 2.6.12 or later). See below.
344472b676d7Smrg     */
344572b676d7Smrg    if(!(pSiS->Primary = xf86IsPrimaryPci(pSiS->PciInfo))) {
344672b676d7Smrg       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
344772b676d7Smrg	   SISMYSERVERNAME " assumes this adapter to be secondary\n");
344872b676d7Smrg    }
344972b676d7Smrg
345072b676d7Smrg    /* Now check if sisfb is running, and if so, retrieve
345172b676d7Smrg     * all possible info from it. This also resets all
345272b676d7Smrg     * sisfb_* entries in pSiS regardless of the chipset.
345372b676d7Smrg     */
345472b676d7Smrg    SiS_CheckKernelFB(pScrn);
345572b676d7Smrg
345672b676d7Smrg    /* Now for that primary/secondary mess: Linux kernel
345772b676d7Smrg     * 2.6.12 and later knows what card is primary, and so
345872b676d7Smrg     * does any recent version of sisfb. XFree86/X.org takes
345972b676d7Smrg     * all adapters as "secondary" if more than one card's
346072b676d7Smrg     * memory and i/o resources are enabled, and more than
346172b676d7Smrg     * one PCI bridge in the system has VGA_EN set at server
346272b676d7Smrg     * start. So, let's start thinking: What is this
346372b676d7Smrg     * primary/secondary classification needed for anyway?
346472b676d7Smrg     * (This list might be incomplete for the entire server
346572b676d7Smrg     * infrastructure, but it's complete as regards the driver's
346672b676d7Smrg     * purposes of primary/secondary classification.)
346772b676d7Smrg     *    1) VGA/console font restoring: Here it's irrelevant
346872b676d7Smrg     *       whether more than one card's resources are enabled
346972b676d7Smrg     *       at server start or not. Relevant is whether the card
347072b676d7Smrg     *       occupies the A0000 area at this time. Assuming (?)
347172b676d7Smrg     *       that this does not change during machine up-time,
347272b676d7Smrg     *       it suffices to know which device was the boot video
347372b676d7Smrg     *       device (as determined by Linux 2.6.12 and later).
347472b676d7Smrg     *       Also, this is only relevant if the card is in text
347572b676d7Smrg     *       mode; if it's in graphics mode, fonts aren't saved
347672b676d7Smrg     *       or restored anyway.
347772b676d7Smrg     *       sisfb tells us if that card is considered the boot
347872b676d7Smrg     *       video device. The hardware registers tell us if
347972b676d7Smrg     *       the card's A0000 address decoding is enabled, and if
348072b676d7Smrg     *       the card currently is in text mode. These three bits
348172b676d7Smrg     *       of information are enough to decide on whether or not
348272b676d7Smrg     *       to save/restore fonts.
348372b676d7Smrg     *    2) POSTing. Same here. Relevant is only whether or not
348472b676d7Smrg     *       the card has been POSTed once before. POSTing cards
348572b676d7Smrg     *       on every server start is pretty ugly, especially
348672b676d7Smrg     *       if a framebuffer driver is already handling it.
348772b676d7Smrg     * SiS/XGI cards POSTed by sisfb can coexist well with other
348872b676d7Smrg     * active adapters. So we trust sisfb's information more
348972b676d7Smrg     * than X's (especially as we only use this information for
349072b676d7Smrg     * console font restoring and eventual POSTing.)
349172b676d7Smrg     * What we still need is a way to find out about all this if
349272b676d7Smrg     * sisfb is not running....
349372b676d7Smrg     */
349472b676d7Smrg    if(!pSiS->Primary && pSiS->sisfbprimary) {
349572b676d7Smrg       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
349672b676d7Smrg		"sisfb reports this adapter to be primary. Seems more reliable.\n");
349772b676d7Smrg       pSiS->Primary = TRUE;
349872b676d7Smrg    }
349972b676d7Smrg
350072b676d7Smrg    /* If the card is "secondary" and has not been
350172b676d7Smrg     * POSTed by sisfb, POST it now through int10.
350272b676d7Smrg     * For cards POSTed by sisfb, we definitely don't
350372b676d7Smrg     * want that as it messes up our set up (eg. the
350472b676d7Smrg     * disabled A0000 area).
350572b676d7Smrg     * The int10 module decides on its own if the
350672b676d7Smrg     * card is primary or secondary. Since it uses
350772b676d7Smrg     * the generic technique described above, and since
350872b676d7Smrg     * for "secondary" cards it needs a real PCI BIOS
350972b676d7Smrg     * ROM, and since integrated chips don't have such
351072b676d7Smrg     * a PCI BIOS ROM, int10 will naturally fail to
351172b676d7Smrg     * find/read the BIOS on such machines. Great.
351272b676d7Smrg     * Using the integrated graphics as "secondary"
351372b676d7Smrg     * (which it will be as soon as X finds more than
351472b676d7Smrg     * one card's mem and i/o resources enabled, and more
351572b676d7Smrg     * than one PCI bridge's VGA_EN bit set during server
351672b676d7Smrg     * start) will therefore prevent us from restoring
351772b676d7Smrg     * the mode using the VBE. That means real fun if
351872b676d7Smrg     * the integrated chip is set up to use the video
351972b676d7Smrg     * bridge output for text mode (which is something
352072b676d7Smrg     * the driver doesn't really support since it's done
352172b676d7Smrg     * pretty much differently on every machine.)
352272b676d7Smrg     */
352372b676d7Smrg#if !defined(__alpha__)
352472b676d7Smrg    if(!pSiS->Primary) {
352572b676d7Smrg       if(!pSiS->sisfbcardposted) {
352672b676d7Smrg	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
352772b676d7Smrg		"Initializing adapter through int10\n");
352872b676d7Smrg	  if(xf86LoadSubModule(pScrn, "int10")) {
352972b676d7Smrg	     pSiS->pInt = xf86InitInt10(pSiS->pEnt->index);
353072b676d7Smrg	  } else {
353172b676d7Smrg	     SISErrorLog(pScrn, "Failed to load int10 module\n");
353272b676d7Smrg	  }
353372b676d7Smrg       } else {
353472b676d7Smrg	  xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
353572b676d7Smrg		"Adapter already initialized by sisfb\n");
353672b676d7Smrg       }
353772b676d7Smrg    }
353872b676d7Smrg#endif
353972b676d7Smrg
354072b676d7Smrg    /* Get the address of our relocated IO registers.
354172b676d7Smrg     * These are enabled by the hardware during cold boot, and
354272b676d7Smrg     * by the BIOS. So we can pretty much rely on that these
354372b676d7Smrg     * are enabled.
354472b676d7Smrg     */
35451fd23544Smrg    pSiS->RelIO = (SISIOADDRESS)(PCI_REGION_BASE(pSiS->PciInfo, 2, REGION_IO) + pSiS->IODBase);
354672b676d7Smrg    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Relocated I/O registers at 0x%lX\n",
354772b676d7Smrg           (ULong)pSiS->RelIO);
354872b676d7Smrg
354972b676d7Smrg    /* Unlock extended registers */
355072b676d7Smrg    sisSaveUnlockExtRegisterLock(pSiS, &srlockReg, &crlockReg);
355172b676d7Smrg
355272b676d7Smrg    /* Is a0000 memory address decoding enabled? */
355372b676d7Smrg    pSiS->VGADecodingEnabled = TRUE;
355472b676d7Smrg    switch(pSiS->VGAEngine) {
355572b676d7Smrg    case SIS_OLD_VGA:
355672b676d7Smrg       /* n/a */
355772b676d7Smrg       break;
355872b676d7Smrg    case SIS_530_VGA:
355972b676d7Smrg       inSISIDXREG(SISSR, 0x3d, tempreg);
356072b676d7Smrg       if(tempreg & 0x04) pSiS->VGADecodingEnabled = FALSE;
356172b676d7Smrg       break;
356272b676d7Smrg    case SIS_300_VGA:
356372b676d7Smrg    case SIS_315_VGA:
356472b676d7Smrg       inSISIDXREG(SISSR, 0x20, tempreg);
356572b676d7Smrg       if(tempreg & 0x04) pSiS->VGADecodingEnabled = FALSE;
356672b676d7Smrg       break;
356772b676d7Smrg    }
356872b676d7Smrg
356972b676d7Smrg    if(!pSiS->VGADecodingEnabled) {
357072b676d7Smrg       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
357172b676d7Smrg		"Standard VGA (0xA0000) memory address decoding is disabled\n");
357272b676d7Smrg    }
357372b676d7Smrg
357472b676d7Smrg#ifdef SIS_PC_PLATFORM
357572b676d7Smrg    /* Map 64k VGA window for saving/restoring CGA fonts.
357672b676d7Smrg     * For secondary cards or if A0000 address decoding
357772b676d7Smrg     * is disabled, this will map the beginning of the
357872b676d7Smrg     * linear (PCI) video RAM instead.
357972b676d7Smrg     */
358072b676d7Smrg    SiS_MapVGAMem(pScrn);
358172b676d7Smrg#endif
358272b676d7Smrg
3583e47418d9Smrg#ifndef XSERVER_LIBPCIACCESS
358472b676d7Smrg    /* Set operating state */
358572b676d7Smrg
358672b676d7Smrg    /* 1. memory */
358772b676d7Smrg    /* [ResUnusedOpr: Resource decoded by hw, but not used]
358872b676d7Smrg     * [ResDisableOpr: Resource is not decoded by hw]
358972b676d7Smrg     * So, if a0000 memory decoding is disabled, one could
359072b676d7Smrg     * argue that we may say so, too. Hm. Quite likely that
359172b676d7Smrg     * the VBE (via int10) will eventually enable it. So we
359272b676d7Smrg     * cowardly say unused instead.
359372b676d7Smrg     */
359472b676d7Smrg    xf86SetOperatingState(resVgaMem, pSiS->pEnt->index, ResUnusedOpr);
359572b676d7Smrg
359672b676d7Smrg    /* 2. i/o */
359772b676d7Smrg    /* Although we only use the relocated i/o ports, the hardware
359872b676d7Smrg     * also decodes the standard VGA port range. This could in
359972b676d7Smrg     * theory be disabled, but I don't dare to do this; in case of
360072b676d7Smrg     * a server crash, the card would be entirely dead. Also, this
360172b676d7Smrg     * would prevent int10 and the VBE from working at all. Generic
360272b676d7Smrg     * access control through the PCI configuration registers does
360372b676d7Smrg     * nicely anyway.
360472b676d7Smrg     */
360572b676d7Smrg    xf86SetOperatingState(resVgaIo, pSiS->pEnt->index, ResUnusedOpr);
360672b676d7Smrg
360772b676d7Smrg    /* Operations for which memory access is required */
360872b676d7Smrg    pScrn->racMemFlags = RAC_FB | RAC_COLORMAP | RAC_CURSOR | RAC_VIEWPORT;
360972b676d7Smrg
361072b676d7Smrg    /* Operations for which I/O access is required */
361172b676d7Smrg    pScrn->racIoFlags = RAC_COLORMAP | RAC_CURSOR | RAC_VIEWPORT;
361272b676d7Smrg
3613e47418d9Smrg#endif
3614e47418d9Smrg
361572b676d7Smrg    /* Load ramdac module */
361672b676d7Smrg    if(!xf86LoadSubModule(pScrn, "ramdac")) {
361772b676d7Smrg       SISErrorLog(pScrn, "Could not load ramdac module\n");
361872b676d7Smrg       goto my_error_1;
361972b676d7Smrg    }
362072b676d7Smrg
362172b676d7Smrg    /* Set pScrn->monitor */
362272b676d7Smrg    pScrn->monitor = pScrn->confScreen->monitor;
362372b676d7Smrg
362472b676d7Smrg    /* Reset some entries */
362572b676d7Smrg    pSiS->SiSFastVidCopy = SiSVidCopyGetDefault();
362672b676d7Smrg    pSiS->SiSFastMemCopy = SiSVidCopyGetDefault();
362772b676d7Smrg    pSiS->SiSFastVidCopyFrom = SiSVidCopyGetDefault();
362872b676d7Smrg    pSiS->SiSFastMemCopyFrom = SiSVidCopyGetDefault();
362972b676d7Smrg    pSiS->SiSFastVidCopyDone = FALSE;
363072b676d7Smrg#ifdef SIS_USE_XAA
363172b676d7Smrg    pSiS->RenderCallback = NULL;
363272b676d7Smrg#endif
363372b676d7Smrg#ifdef SIS_USE_EXA
363472b676d7Smrg    pSiS->ExaRenderCallback = NULL;
363572b676d7Smrg#endif
363672b676d7Smrg    pSiS->InitAccel = SiSPseudo;
363772b676d7Smrg    pSiS->SyncAccel = SiSPseudo;
363872b676d7Smrg    pSiS->FillRect  = NULL;
363972b676d7Smrg    pSiS->BlitRect  = NULL;
364072b676d7Smrg
364172b676d7Smrg    /* Always do a ValidMode() inside Switchmode() */
364272b676d7Smrg    pSiS->skipswitchcheck = FALSE;
364372b676d7Smrg
364472b676d7Smrg    /* Determine chipset and its capabilities in detail */
364572b676d7Smrg    pSiS->ChipFlags = 0;
364672b676d7Smrg    pSiS->SiS_SD_Flags = pSiS->SiS_SD2_Flags = 0;
364772b676d7Smrg    pSiS->SiS_SD3_Flags = pSiS->SiS_SD4_Flags = 0;
364872b676d7Smrg    pSiS->HWCursorMBufNum = pSiS->HWCursorCBufNum = 0;
364972b676d7Smrg    pSiS->NeedFlush = FALSE;
365072b676d7Smrg    pSiS->NewCRLayout = FALSE;
365172b676d7Smrg    pSiS->mmioSize = 64;
365272b676d7Smrg
365372b676d7Smrg    switch(pSiS->Chipset) {
365472b676d7Smrg       case PCI_CHIP_SIS530:
365572b676d7Smrg	  pSiS->ChipType = SIS_530;
365672b676d7Smrg	  break;
365772b676d7Smrg       case PCI_CHIP_SIS300:
365872b676d7Smrg	  pSiS->ChipType = SIS_300;
365972b676d7Smrg	  pSiS->SiS_SD_Flags |= SiS_SD_IS300SERIES;
366072b676d7Smrg	  break;
366172b676d7Smrg       case PCI_CHIP_SIS540:
366272b676d7Smrg	  pSiS->ChipType = SIS_540;
366372b676d7Smrg	  pSiS->SiS_SD_Flags |= SiS_SD_IS300SERIES;
366472b676d7Smrg	  break;
366572b676d7Smrg       case PCI_CHIP_SIS630: /* 630 + 730 */
366672b676d7Smrg	  pSiS->ChipType = SIS_630;
36671fd23544Smrg	  if(sis_pci_read_host_bridge_u32(0x00) == 0x07301039) {
366872b676d7Smrg	     pSiS->ChipType = SIS_730;
366972b676d7Smrg	  }
367072b676d7Smrg	  pSiS->SiS_SD_Flags |= SiS_SD_IS300SERIES;
367172b676d7Smrg	  break;
367272b676d7Smrg       case PCI_CHIP_SIS315H:
367372b676d7Smrg	  pSiS->ChipType = SIS_315H;
367472b676d7Smrg	  pSiS->ChipFlags |= (SiSCF_315Core | SiSCF_MMIOPalette);
367572b676d7Smrg	  pSiS->SiS_SD_Flags |= SiS_SD_IS315SERIES;
367672b676d7Smrg	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
367772b676d7Smrg	  pSiS->myCR63 = 0x63;
367872b676d7Smrg	  break;
367972b676d7Smrg       case PCI_CHIP_SIS315:
368072b676d7Smrg	  /* Override for simplicity */
368172b676d7Smrg	  pSiS->Chipset = PCI_CHIP_SIS315H;
368272b676d7Smrg	  pSiS->ChipType = SIS_315;
368372b676d7Smrg	  pSiS->ChipFlags |= (SiSCF_315Core | SiSCF_MMIOPalette);
368472b676d7Smrg	  pSiS->SiS_SD_Flags |= SiS_SD_IS315SERIES;
368572b676d7Smrg	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
368672b676d7Smrg	  pSiS->myCR63 = 0x63;
368772b676d7Smrg	  break;
368872b676d7Smrg       case PCI_CHIP_SIS315PRO:
368972b676d7Smrg	  /* Override for simplicity */
369072b676d7Smrg	  pSiS->Chipset = PCI_CHIP_SIS315H;
369172b676d7Smrg	  pSiS->ChipType = SIS_315PRO;
369272b676d7Smrg	  pSiS->ChipFlags |= (SiSCF_315Core | SiSCF_MMIOPalette);
369372b676d7Smrg	  pSiS->SiS_SD_Flags |= SiS_SD_IS315SERIES;
369472b676d7Smrg	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
369572b676d7Smrg	  pSiS->myCR63 = 0x63;
369672b676d7Smrg	  break;
369772b676d7Smrg       case PCI_CHIP_SIS550:
369872b676d7Smrg	  pSiS->ChipType = SIS_550;
369972b676d7Smrg	  pSiS->ChipFlags |= (SiSCF_Integrated | SiSCF_MMIOPalette);
370072b676d7Smrg	  pSiS->SiS_SD_Flags |= SiS_SD_IS315SERIES;
370172b676d7Smrg	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
370272b676d7Smrg	  pSiS->myCR63 = 0x63;
370372b676d7Smrg	  break;
370472b676d7Smrg       case PCI_CHIP_SIS650: /* 650 + 740 */
370572b676d7Smrg	  pSiS->ChipType = SIS_650;
37061fd23544Smrg	  if(sis_pci_read_host_bridge_u32(0x00) == 0x07401039) {
370772b676d7Smrg	     pSiS->ChipType = SIS_740;
370872b676d7Smrg	  }
370972b676d7Smrg	  pSiS->ChipFlags |= (SiSCF_Integrated | SiSCF_Real256ECore | SiSCF_MMIOPalette);
371072b676d7Smrg	  pSiS->SiS_SD_Flags |= SiS_SD_IS315SERIES;
371172b676d7Smrg	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
371272b676d7Smrg	  pSiS->myCR63 = 0x63;
371372b676d7Smrg	  break;
371472b676d7Smrg       case PCI_CHIP_SIS330:
371572b676d7Smrg	  pSiS->ChipType = SIS_330;
371672b676d7Smrg	  pSiS->ChipFlags |= (SiSCF_XabreCore | SiSCF_MMIOPalette);
371772b676d7Smrg	  pSiS->SiS_SD_Flags |= SiS_SD_IS330SERIES;
371872b676d7Smrg	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
371972b676d7Smrg	  pSiS->SiS_SD3_Flags |= SiS_SD3_CRT1SATGAIN; /* FIXME ? */
372072b676d7Smrg	  pSiS->myCR63 = 0x53; /* sic! */
372172b676d7Smrg	  break;
372272b676d7Smrg       case PCI_CHIP_SIS660: /* 660, 661, 741, 760, 761, 670(?) */
372372b676d7Smrg	  {
37241fd23544Smrg	     ULong hpciid = sis_pci_read_host_bridge_u32(0x00);
372572b676d7Smrg	     switch(hpciid) {
372672b676d7Smrg	     case 0x06601039:
372772b676d7Smrg		pSiS->ChipType = SIS_660;
372872b676d7Smrg		pSiS->ChipFlags |= SiSCF_Ultra256Core;
372972b676d7Smrg		pSiS->NeedFlush = TRUE;
373072b676d7Smrg		break;
373172b676d7Smrg	     case 0x07601039:
373272b676d7Smrg		pSiS->ChipType = SIS_760;
373372b676d7Smrg		pSiS->ChipFlags |= SiSCF_Ultra256Core;
373472b676d7Smrg		pSiS->NeedFlush = TRUE;
373572b676d7Smrg		break;
373672b676d7Smrg	     case 0x07611039:
373772b676d7Smrg		pSiS->ChipType = SIS_761;
373872b676d7Smrg		pSiS->ChipFlags |= SiSCF_Ultra256Core;
373972b676d7Smrg		pSiS->NeedFlush = TRUE;
374072b676d7Smrg		break;
374172b676d7Smrg	     case 0x07701039:
374272b676d7Smrg		pSiS->ChipType = SIS_770;
374372b676d7Smrg		pSiS->ChipFlags |= SiSCF_Ultra256Core;
374472b676d7Smrg		pSiS->NeedFlush = TRUE;
374572b676d7Smrg		break;
374672b676d7Smrg	     case 0x07411039:
374772b676d7Smrg		pSiS->ChipType = SIS_741;
374872b676d7Smrg		pSiS->ChipFlags |= SiSCF_Real256ECore;
374972b676d7Smrg		break;
375072b676d7Smrg	     case 0x06611039:
375172b676d7Smrg	     default:
375272b676d7Smrg		pSiS->ChipType = SIS_661;
375372b676d7Smrg		pSiS->ChipFlags |= SiSCF_Real256ECore;
375472b676d7Smrg		break;
375572b676d7Smrg	     case 0x06701039:
375672b676d7Smrg		pSiS->ChipType = SIS_670;
375772b676d7Smrg		pSiS->ChipFlags |= SiSCF_Real256ECore;
375872b676d7Smrg	     }
375972b676d7Smrg	     /* Detection could also be done by CR5C & 0xf8:
376072b676d7Smrg	      * 0x10 = 661 (CR5F & 0xc0: 0x00 both A0 and A1)
376172b676d7Smrg	      * 0x80 = 760 (CR5F & 0xc0: 0x00 A0, 0x40 A1)
376272b676d7Smrg	      * 0x90 = 741 (CR5F & 0xc0: 0x00 A0,A1 0x40 A2)
376372b676d7Smrg	      * other: 660 (CR5F & 0xc0: 0x00 A0 0x40 A1) (DOA?)
376472b676d7Smrg	      */
376572b676d7Smrg	     pSiS->ChipFlags |= (SiSCF_Integrated | SiSCF_MMIOPalette);
376672b676d7Smrg	     pSiS->SiS_SD_Flags |= SiS_SD_IS330SERIES;
376772b676d7Smrg	     pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
376872b676d7Smrg	     pSiS->SiS_SD3_Flags |= SiS_SD3_CRT1SATGAIN;
376972b676d7Smrg	     pSiS->myCR63 = 0x53; /* sic! */
377072b676d7Smrg	     pSiS->NewCRLayout = TRUE;
377172b676d7Smrg	  }
377272b676d7Smrg	  break;
377372b676d7Smrg       case PCI_CHIP_SIS340:
377472b676d7Smrg	  pSiS->ChipType = SIS_340;
377572b676d7Smrg	  pSiS->ChipFlags |= (SiSCF_XabreCore | SiSCF_MMIOPalette);
377672b676d7Smrg	  pSiS->SiS_SD_Flags |= SiS_SD_IS340SERIES;
377772b676d7Smrg	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
377872b676d7Smrg	  pSiS->SiS_SD3_Flags |= SiS_SD3_CRT1SATGAIN;
377972b676d7Smrg	  pSiS->myCR63 = 0x53;
378072b676d7Smrg	  pSiS->NewCRLayout = TRUE;
378172b676d7Smrg	  break;
378272b676d7Smrg       case PCI_CHIP_XGIXG20:
378372b676d7Smrg	  pSiS->ChipType = XGI_20;
378472b676d7Smrg	  pSiS->ChipFlags |= (SiSCF_XabreCore | SiSCF_MMIOPalette | SiSCF_IsXGI);
378572b676d7Smrg	  pSiS->SiS_SD2_Flags |= (SiS_SD2_NOOVERLAY | SiS_SD2_ISXGI);
378672b676d7Smrg	  pSiS->myCR63 = 0x53;
378772b676d7Smrg	  pSiS->NewCRLayout = TRUE;
378872b676d7Smrg	  break;
378972b676d7Smrg       case PCI_CHIP_XGIXG40:
379072b676d7Smrg	  pSiS->ChipType = XGI_40;
379172b676d7Smrg	  pSiS->ChipFlags |= (SiSCF_XabreCore | SiSCF_MMIOPalette | SiSCF_IsXGI);
379272b676d7Smrg	  pSiS->SiS_SD2_Flags |= (SiS_SD2_SUPPORTXVHUESAT | SiS_SD2_ISXGI);
379372b676d7Smrg	  pSiS->SiS_SD3_Flags |= SiS_SD3_CRT1SATGAIN;
379472b676d7Smrg	  pSiS->myCR63 = 0x53;
379572b676d7Smrg	  pSiS->NewCRLayout = TRUE;
379672b676d7Smrg	  if(pSiS->ChipRev == 2) pSiS->ChipFlags |= SiSCF_IsXGIV3;
379772b676d7Smrg	  break;
379872b676d7Smrg       default:
379972b676d7Smrg	  pSiS->ChipType = SIS_OLD;
380072b676d7Smrg	  break;
380172b676d7Smrg    }
380272b676d7Smrg
380372b676d7Smrg    /*
380472b676d7Smrg     * Now back to real business: Figure out the depth, bpp, etc.
380572b676d7Smrg     * Set SupportConvert... flags since we use the fb layer which
380672b676d7Smrg     * supports this conversion. (24to32 seems not implemented though)
380772b676d7Smrg     * Additionally, determine the size of the HWCursor memory area.
380872b676d7Smrg     */
380972b676d7Smrg    switch(pSiS->VGAEngine) {
381072b676d7Smrg       case SIS_300_VGA:
381172b676d7Smrg	  pSiS->CursorSize = 4096;
381272b676d7Smrg	  pix24flags = Support32bppFb;
381372b676d7Smrg	  break;
381472b676d7Smrg       case SIS_315_VGA:
381572b676d7Smrg	  pSiS->CursorSize = 16384;
381672b676d7Smrg	  pix24flags = Support32bppFb;
381772b676d7Smrg	  break;
381872b676d7Smrg       case SIS_530_VGA:
381972b676d7Smrg	  pSiS->CursorSize = 2048;
382072b676d7Smrg	  pix24flags = Support32bppFb	  |
382172b676d7Smrg		       Support24bppFb	  |
382272b676d7Smrg		       SupportConvert32to24;
382372b676d7Smrg          break;
382472b676d7Smrg       default:
382572b676d7Smrg	  pSiS->CursorSize = 2048;
382672b676d7Smrg	  pix24flags = Support24bppFb	    |
382772b676d7Smrg		       SupportConvert32to24 |
382872b676d7Smrg		       PreferConvert32to24;
382972b676d7Smrg	  break;
383072b676d7Smrg    }
383172b676d7Smrg
383272b676d7Smrg#ifdef SISDUALHEAD
383372b676d7Smrg    /* In case of Dual Head, we need to determine if we are the "master" head or
383472b676d7Smrg     * the "slave" head. In order to do that, we set PrimInit to DONE in the
383572b676d7Smrg     * shared entity at the end of the first initialization. The second
383672b676d7Smrg     * initialization then knows that some things have already been done. THIS
383772b676d7Smrg     * ALWAYS ASSUMES THAT THE FIRST DEVICE INITIALIZED IS THE MASTER!
383872b676d7Smrg     */
383972b676d7Smrg    if(xf86IsEntityShared(pScrn->entityList[0])) {
384072b676d7Smrg       if(pSiSEnt->lastInstance > 0) {
384172b676d7Smrg	  if(!xf86IsPrimInitDone(pScrn->entityList[0])) {
384272b676d7Smrg	     /* First Head (always CRT2) */
384372b676d7Smrg	     pSiS->SecondHead = FALSE;
384472b676d7Smrg	     pSiSEnt->pScrn_1 = pScrn;
384572b676d7Smrg	     pSiSEnt->CRT1ModeNo = pSiSEnt->CRT2ModeNo = -1;
384672b676d7Smrg	     pSiSEnt->CRT2ModeSet = FALSE;
384772b676d7Smrg	     pSiS->DualHeadMode = TRUE;
384872b676d7Smrg	     pSiSEnt->DisableDual = FALSE;
384972b676d7Smrg	     pSiSEnt->BIOS = NULL;
385072b676d7Smrg	     pSiSEnt->ROM661New = FALSE;
385172b676d7Smrg	     pSiSEnt->HaveXGIBIOS = FALSE;
385272b676d7Smrg	     pSiSEnt->SiS_Pr = NULL;
385372b676d7Smrg	     pSiSEnt->RenderAccelArray = NULL;
385472b676d7Smrg	     pSiSEnt->SiSFastVidCopy = pSiSEnt->SiSFastMemCopy = NULL;
385572b676d7Smrg	     pSiSEnt->SiSFastVidCopyFrom = pSiSEnt->SiSFastMemCopyFrom = NULL;
385672b676d7Smrg	  } else {
385772b676d7Smrg	     /* Second Head (always CRT1) */
385872b676d7Smrg	     pSiS->SecondHead = TRUE;
385972b676d7Smrg	     pSiSEnt->pScrn_2 = pScrn;
386072b676d7Smrg	     pSiS->DualHeadMode = TRUE;
386172b676d7Smrg	  }
386272b676d7Smrg       } else {
386372b676d7Smrg	  /* Only one screen in config file - disable dual head mode */
386472b676d7Smrg	  pSiS->SecondHead = FALSE;
386572b676d7Smrg	  pSiS->DualHeadMode = FALSE;
386672b676d7Smrg	  pSiSEnt->DisableDual = TRUE;
386772b676d7Smrg       }
386872b676d7Smrg    } else {
386972b676d7Smrg       /* Entity is not shared - disable dual head mode */
387072b676d7Smrg       pSiS->SecondHead = FALSE;
387172b676d7Smrg       pSiS->DualHeadMode = FALSE;
387272b676d7Smrg    }
387372b676d7Smrg#endif
387472b676d7Smrg
387572b676d7Smrg    /* Save the name of our Device section for SiSCtrl usage */
387672b676d7Smrg    {
387772b676d7Smrg       int ttt = 0;
387872b676d7Smrg       GDevPtr device = xf86GetDevFromEntity(pScrn->entityList[0],
387972b676d7Smrg						pScrn->entityInstanceList[0]);
388072b676d7Smrg       if(device && device->identifier) {
388172b676d7Smrg          if((ttt = strlen(device->identifier)) > 31) ttt = 31;
388272b676d7Smrg	  strncpy(&pSiS->devsectname[0], device->identifier, 31);
388372b676d7Smrg       }
388472b676d7Smrg       pSiS->devsectname[ttt] = 0;
388572b676d7Smrg    }
388672b676d7Smrg
388772b676d7Smrg    pSiS->ForceCursorOff = FALSE;
388872b676d7Smrg
388972b676d7Smrg    /* Allocate SiS_Private (for mode switching code) and initialize it */
389072b676d7Smrg    pSiS->SiS_Pr = NULL;
389172b676d7Smrg#ifdef SISDUALHEAD
389272b676d7Smrg    if(pSiSEnt) {
389372b676d7Smrg       if(pSiSEnt->SiS_Pr) pSiS->SiS_Pr = pSiSEnt->SiS_Pr;
389472b676d7Smrg    }
389572b676d7Smrg#endif
389672b676d7Smrg    if(!pSiS->SiS_Pr) {
389772b676d7Smrg       if(!(pSiS->SiS_Pr = xnfcalloc(sizeof(struct SiS_Private), 1))) {
389872b676d7Smrg	  SISErrorLog(pScrn, "Could not allocate memory for SiS_Pr structure\n");
389972b676d7Smrg	  goto my_error_1;
390072b676d7Smrg       }
390172b676d7Smrg#ifdef SISDUALHEAD
390272b676d7Smrg       if(pSiSEnt) pSiSEnt->SiS_Pr = pSiS->SiS_Pr;
390372b676d7Smrg#endif
390472b676d7Smrg       memset(pSiS->SiS_Pr, 0, sizeof(struct SiS_Private));
390572b676d7Smrg       pSiS->SiS_Pr->PciTag = pSiS->PciTag;
390672b676d7Smrg       pSiS->SiS_Pr->ChipType = pSiS->ChipType;
390772b676d7Smrg       pSiS->SiS_Pr->ChipRevision = pSiS->ChipRev;
390872b676d7Smrg       pSiS->SiS_Pr->SiS_Backup70xx = 0xff;
390972b676d7Smrg       pSiS->SiS_Pr->SiS_CHOverScan = -1;
391072b676d7Smrg       pSiS->SiS_Pr->SiS_ChSW = FALSE;
391172b676d7Smrg       pSiS->SiS_Pr->SiS_CustomT = CUT_NONE;
391272b676d7Smrg       pSiS->SiS_Pr->SiS_UseWide = -1;
391372b676d7Smrg       pSiS->SiS_Pr->SiS_UseWideCRT2 = -1;
391472b676d7Smrg       pSiS->SiS_Pr->SiS_TVBlue = -1;
391572b676d7Smrg       pSiS->SiS_Pr->PanelSelfDetected = FALSE;
391672b676d7Smrg       pSiS->SiS_Pr->UsePanelScaler = -1;
391772b676d7Smrg       pSiS->SiS_Pr->CenterScreen = -1;
391872b676d7Smrg       pSiS->SiS_Pr->CRT1UsesCustomMode = FALSE;
391972b676d7Smrg       pSiS->SiS_Pr->PDC = pSiS->SiS_Pr->PDCA = -1;
392072b676d7Smrg       pSiS->SiS_Pr->LVDSHL = -1;
392172b676d7Smrg       pSiS->SiS_Pr->HaveEMI = FALSE;
392272b676d7Smrg       pSiS->SiS_Pr->HaveEMILCD = FALSE;
392372b676d7Smrg       pSiS->SiS_Pr->OverruleEMI = FALSE;
392472b676d7Smrg       pSiS->SiS_Pr->SiS_SensibleSR11 = FALSE;
392572b676d7Smrg       if(pSiS->ChipType >= SIS_661) {
392672b676d7Smrg          pSiS->SiS_Pr->SiS_SensibleSR11 = TRUE;
392772b676d7Smrg       }
392872b676d7Smrg       pSiS->SiS_Pr->SiS_MyCR63 = pSiS->myCR63;
392972b676d7Smrg       pSiS->SiS_Pr->DDCPortMixup = FALSE;
393072b676d7Smrg    }
393172b676d7Smrg
393272b676d7Smrg    /* Copy IO address to SiS_Pr and init the structure for
393372b676d7Smrg     * routines inside init.c/init301.c
393472b676d7Smrg     */
393572b676d7Smrg    pSiS->SiS_Pr->IOAddress = (SISIOADDRESS)(pSiS->RelIO + 0x30);
393672b676d7Smrg    SiSRegInit(pSiS->SiS_Pr, pSiS->RelIO + 0x30);
393772b676d7Smrg
393872b676d7Smrg    /* The following identifies the old chipsets. This is only
393972b676d7Smrg     * partly used since the really old chips are not supported,
394072b676d7Smrg     * but I keep it here for future use.
394172b676d7Smrg     * 205, 215 and 225 are to be treated the same way, 201 and 202
394272b676d7Smrg     * are different.
394372b676d7Smrg     */
394472b676d7Smrg    if(pSiS->VGAEngine == SIS_OLD_VGA || pSiS->VGAEngine == SIS_530_VGA) {
394572b676d7Smrg       switch(pSiS->Chipset) {
394672b676d7Smrg       case PCI_CHIP_SG86C201:
394772b676d7Smrg	  pSiS->oldChipset = OC_SIS86201; break;
394872b676d7Smrg       case PCI_CHIP_SG86C202:
394972b676d7Smrg	  pSiS->oldChipset = OC_SIS86202; break;
395072b676d7Smrg       case PCI_CHIP_SG86C205:
395172b676d7Smrg	  inSISIDXREG(SISSR, 0x10, tempreg);
395272b676d7Smrg	  if(tempreg & 0x80) pSiS->oldChipset = OC_SIS6205B;
395372b676d7Smrg	  else pSiS->oldChipset = (pSiS->ChipRev == 0x11) ?
395472b676d7Smrg					OC_SIS6205C : OC_SIS6205A;
395572b676d7Smrg	  break;
395672b676d7Smrg       case PCI_CHIP_SIS82C204:
395772b676d7Smrg	  pSiS->oldChipset = OC_SIS82204; break;
395872b676d7Smrg       case 0x6225:
395972b676d7Smrg	  pSiS->oldChipset = OC_SIS6225; break;
396072b676d7Smrg       case PCI_CHIP_SIS5597:
396172b676d7Smrg	  pSiS->oldChipset = OC_SIS5597; break;
396272b676d7Smrg       case PCI_CHIP_SIS6326:
396372b676d7Smrg	  pSiS->oldChipset = OC_SIS6326; break;
396472b676d7Smrg       case PCI_CHIP_SIS530:
39651fd23544Smrg	  if(sis_pci_read_host_bridge_u32(0x00) == 0x06201039) {
396672b676d7Smrg	     pSiS->oldChipset = OC_SIS620;
396772b676d7Smrg	  } else {
396872b676d7Smrg	     if((pSiS->ChipRev & 0x0f) < 0x0a)
396972b676d7Smrg		   pSiS->oldChipset = OC_SIS530A;
397072b676d7Smrg	     else  pSiS->oldChipset = OC_SIS530B;
397172b676d7Smrg	  }
397272b676d7Smrg	  break;
397372b676d7Smrg       default:
397472b676d7Smrg	  pSiS->oldChipset = OC_UNKNOWN;
397572b676d7Smrg       }
397672b676d7Smrg    }
397772b676d7Smrg
397872b676d7Smrg    if(!xf86SetDepthBpp(pScrn, 0, 0, 0, pix24flags)) {
397972b676d7Smrg       SISErrorLog(pScrn, "xf86SetDepthBpp() error\n");
398072b676d7Smrg       goto my_error_1;
398172b676d7Smrg    }
398272b676d7Smrg
398372b676d7Smrg    /* Check that the returned depth is one we support */
398472b676d7Smrg    temp = 0;
398572b676d7Smrg    switch(pScrn->depth) {
398672b676d7Smrg       case 8:
398772b676d7Smrg       case 16:
398872b676d7Smrg       case 24:
398972b676d7Smrg          break;
399072b676d7Smrg       case 15:
399172b676d7Smrg	  if((pSiS->VGAEngine == SIS_300_VGA) ||
399272b676d7Smrg	     (pSiS->VGAEngine == SIS_315_VGA)) {
399372b676d7Smrg	     temp = 1;
399472b676d7Smrg	  }
399572b676d7Smrg	  break;
399672b676d7Smrg       default:
399772b676d7Smrg	  temp = 1;
399872b676d7Smrg    }
399972b676d7Smrg
400072b676d7Smrg    if(temp) {
400172b676d7Smrg       SISErrorLog(pScrn,
400272b676d7Smrg            "Given color depth (%d) is not supported by this driver/chipset\n",
400372b676d7Smrg            pScrn->depth);
400472b676d7Smrg       goto my_error_1;
400572b676d7Smrg    }
400672b676d7Smrg
400772b676d7Smrg    xf86PrintDepthBpp(pScrn);
400872b676d7Smrg
400972b676d7Smrg    if( (((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) &&
401072b676d7Smrg         (pScrn->bitsPerPixel == 24)) ||
401172b676d7Smrg	((pSiS->VGAEngine == SIS_OLD_VGA) && (pScrn->bitsPerPixel == 32)) ) {
401272b676d7Smrg       SISErrorLog(pScrn,
401372b676d7Smrg            "Framebuffer bpp %d not supported for this chipset\n", pScrn->bitsPerPixel);
401472b676d7Smrg       goto my_error_1;
401572b676d7Smrg    }
401672b676d7Smrg
401772b676d7Smrg    /* Get the depth24 pixmap format */
401872b676d7Smrg    if(pScrn->depth == 24 && pix24bpp == 0) {
401972b676d7Smrg       pix24bpp = xf86GetBppFromDepth(pScrn, 24);
402072b676d7Smrg    }
402172b676d7Smrg
402272b676d7Smrg    /*
402372b676d7Smrg     * This must happen after pScrn->display has been set because
402472b676d7Smrg     * xf86SetWeight references it.
402572b676d7Smrg     */
402672b676d7Smrg    if(pScrn->depth > 8) {
402772b676d7Smrg        /* The defaults are OK for us */
402872b676d7Smrg        rgb zeros = {0, 0, 0};
402972b676d7Smrg
403072b676d7Smrg        if(!xf86SetWeight(pScrn, zeros, zeros)) {
403172b676d7Smrg	    SISErrorLog(pScrn, "xf86SetWeight() error\n");
403272b676d7Smrg	    goto my_error_1;
403372b676d7Smrg        } else {
403472b676d7Smrg	   Bool ret = FALSE;
403572b676d7Smrg	   switch(pScrn->depth) {
403672b676d7Smrg	   case 15:
403772b676d7Smrg	      if((pScrn->weight.red != 5) ||
403872b676d7Smrg	         (pScrn->weight.green != 5) ||
403972b676d7Smrg		 (pScrn->weight.blue != 5)) ret = TRUE;
404072b676d7Smrg	      break;
404172b676d7Smrg	   case 16:
404272b676d7Smrg	      if((pScrn->weight.red != 5) ||
404372b676d7Smrg	         (pScrn->weight.green != 6) ||
404472b676d7Smrg		 (pScrn->weight.blue != 5)) ret = TRUE;
404572b676d7Smrg	      break;
404672b676d7Smrg	   case 24:
404772b676d7Smrg	      if((pScrn->weight.red != 8) ||
404872b676d7Smrg	         (pScrn->weight.green != 8) ||
404972b676d7Smrg		 (pScrn->weight.blue != 8)) ret = TRUE;
405072b676d7Smrg	      break;
405172b676d7Smrg	   }
405272b676d7Smrg	   if(ret) {
405372b676d7Smrg	      SISErrorLog(pScrn,
405472b676d7Smrg		   "RGB weight %d%d%d at depth %d not supported by hardware\n",
405572b676d7Smrg		   (int)pScrn->weight.red, (int)pScrn->weight.green,
405672b676d7Smrg		   (int)pScrn->weight.blue, pScrn->depth);
405772b676d7Smrg	      goto my_error_1;
405872b676d7Smrg	   }
405972b676d7Smrg        }
406072b676d7Smrg    }
406172b676d7Smrg
406272b676d7Smrg    /* Set the current layout parameters */
406372b676d7Smrg    pSiS->CurrentLayout.bitsPerPixel = pScrn->bitsPerPixel;
406472b676d7Smrg    pSiS->CurrentLayout.depth        = pScrn->depth;
406572b676d7Smrg    /* (Inside this function, we can use pScrn's contents anyway) */
406672b676d7Smrg
406772b676d7Smrg    if(!xf86SetDefaultVisual(pScrn, -1)) {
406872b676d7Smrg       SISErrorLog(pScrn, "xf86SetDefaultVisual() error\n");
406972b676d7Smrg       goto my_error_1;
407072b676d7Smrg    } else {
407172b676d7Smrg       /* We don't support DirectColor at > 8bpp */
407272b676d7Smrg       if(pScrn->depth > 8 && pScrn->defaultVisual != TrueColor) {
407372b676d7Smrg	  SISErrorLog(pScrn,
407472b676d7Smrg	       "Given default visual (%s) is not supported at depth %d\n",
407572b676d7Smrg	        xf86GetVisualName(pScrn->defaultVisual), pScrn->depth);
407672b676d7Smrg	  goto my_error_1;
407772b676d7Smrg       }
407872b676d7Smrg    }
407972b676d7Smrg
408072b676d7Smrg#ifdef SISDUALHEAD
408172b676d7Smrg    /* Due to palette & timing problems we don't support 8bpp in DHM */
408272b676d7Smrg    if((pSiS->DualHeadMode) && (pScrn->bitsPerPixel <= 8)) {
408372b676d7Smrg       SISErrorLog(pScrn, "Color depth %d not supported in Dual Head mode.\n",
408472b676d7Smrg			pScrn->bitsPerPixel);
408572b676d7Smrg       goto my_error_1;
408672b676d7Smrg    }
408772b676d7Smrg#endif
408872b676d7Smrg
408972b676d7Smrg    /* Read BIOS for 300/315/330/340 series customization */
409072b676d7Smrg    pSiS->SiS_Pr->VirtualRomBase = NULL;
409172b676d7Smrg    pSiS->BIOS = NULL;
409272b676d7Smrg    pSiS->SiS_Pr->UseROM = FALSE;
409372b676d7Smrg    pSiS->ROM661New = FALSE;
409472b676d7Smrg    pSiS->HaveXGIBIOS = FALSE;
409572b676d7Smrg
409672b676d7Smrg    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
409772b676d7Smrg#ifdef SISDUALHEAD
409872b676d7Smrg       if(pSiSEnt) {
409972b676d7Smrg	  if(pSiSEnt->BIOS) {
410072b676d7Smrg	     pSiS->BIOS = pSiSEnt->BIOS;
410172b676d7Smrg	     pSiS->SiS_Pr->VirtualRomBase = pSiS->BIOS;
410272b676d7Smrg	     pSiS->ROM661New = pSiSEnt->ROM661New;
410372b676d7Smrg	     pSiS->HaveXGIBIOS = pSiSEnt->HaveXGIBIOS;
410472b676d7Smrg	  }
410572b676d7Smrg       }
410672b676d7Smrg#endif
410772b676d7Smrg       if(!pSiS->BIOS) {
41085788ca14Smrg	  if(!(pSiS->BIOS = calloc(1, BIOS_SIZE))) {
410972b676d7Smrg	     xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
411072b676d7Smrg		"Could not allocate memory for video BIOS image\n");
411172b676d7Smrg	  } else {
411272b676d7Smrg	     UShort mypciid = pSiS->Chipset;
411372b676d7Smrg	     UShort mypcivendor = (pSiS->ChipFlags & SiSCF_IsXGI) ? PCI_VENDOR_XGI : PCI_VENDOR_SIS;
411472b676d7Smrg	     Bool   found = FALSE, readpci = FALSE;
411572b676d7Smrg	     int    biossize = BIOS_SIZE;
411672b676d7Smrg
411772b676d7Smrg	     switch(pSiS->ChipType) {
411872b676d7Smrg	     case SIS_315:    mypciid = PCI_CHIP_SIS315;
411972b676d7Smrg			      readpci = TRUE;
412072b676d7Smrg			      break;
412172b676d7Smrg	     case SIS_315PRO: mypciid = PCI_CHIP_SIS315PRO;
412272b676d7Smrg			      readpci = TRUE;
412372b676d7Smrg			      break;
412472b676d7Smrg	     case SIS_300:
412572b676d7Smrg	     case SIS_315H:
412672b676d7Smrg	     case SIS_330:
412772b676d7Smrg	     case SIS_340:
4128e35772b2Smrg	     case SIS_650:
4129e35772b2Smrg	     case SIS_760:
413072b676d7Smrg	     case XGI_40:     readpci = TRUE;
413172b676d7Smrg			      break;
413272b676d7Smrg	     case XGI_20:     readpci = TRUE;
413372b676d7Smrg			      biossize = 0x8000;
413472b676d7Smrg			      break;
413572b676d7Smrg	     }
41361fd23544Smrg#if XSERVER_LIBPCIACCESS
41371fd23544Smrg	     if(readpci) {
41381fd23544Smrg		pSiS->PciInfo->rom_size = biossize;
41391fd23544Smrg		pci_device_read_rom(pSiS->PciInfo, pSiS->BIOS);
41401fd23544Smrg		if(SISCheckBIOS(pSiS, mypciid, mypcivendor, biossize)) {
41411fd23544Smrg		   found = TRUE;
41421fd23544Smrg		}
41431fd23544Smrg	     }
41441fd23544Smrg#else
414572b676d7Smrg	     if(readpci) {
414672b676d7Smrg		xf86ReadPciBIOS(0, pSiS->PciTag, 0, pSiS->BIOS, biossize);
414772b676d7Smrg		if(SISCheckBIOS(pSiS, mypciid, mypcivendor, biossize)) {
414872b676d7Smrg		   found = TRUE;
414972b676d7Smrg		}
415072b676d7Smrg	     }
415172b676d7Smrg
415272b676d7Smrg	     if(!found) {
41531fd23544Smrg	        ULong  segstart;
415472b676d7Smrg		for(segstart = BIOS_BASE; segstart < 0x000f0000; segstart += 0x00001000) {
415572b676d7Smrg
415672b676d7Smrg#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,99,0,0)
415772b676d7Smrg		   if(xf86ReadBIOS(segstart, 0, pSiS->BIOS, biossize) != biossize) continue;
415872b676d7Smrg#else
415972b676d7Smrg		   if(xf86ReadDomainMemory(pSiS->PciTag, segstart, biossize, pSiS->BIOS) != biossize) continue;
416072b676d7Smrg#endif
416172b676d7Smrg
416272b676d7Smrg		   if(!SISCheckBIOS(pSiS, mypciid, mypcivendor, biossize)) continue;
416372b676d7Smrg
416472b676d7Smrg		   found = TRUE;
416572b676d7Smrg		   break;
416672b676d7Smrg		}
416772b676d7Smrg             }
41681fd23544Smrg#endif
416972b676d7Smrg	     if(found) {
417072b676d7Smrg		UShort romptr = pSiS->BIOS[0x16] | (pSiS->BIOS[0x17] << 8);
417172b676d7Smrg		pSiS->SiS_Pr->VirtualRomBase = pSiS->BIOS;
417272b676d7Smrg		if(pSiS->ChipFlags & SiSCF_IsXGI) {
417372b676d7Smrg		   pSiS->HaveXGIBIOS = pSiS->SiS_Pr->SiS_XGIROM = TRUE;
417472b676d7Smrg		   pSiS->SiS_Pr->UseROM = FALSE;
417572b676d7Smrg		   if(pSiS->ChipFlags & SiSCF_IsXGIV3) {
417672b676d7Smrg		      if(!(pSiS->BIOS[0x1d1] & 0x01)) {
417772b676d7Smrg			 pSiS->SiS_Pr->DDCPortMixup = TRUE;
417872b676d7Smrg		      }
417972b676d7Smrg	           }
418072b676d7Smrg	        } else {
418172b676d7Smrg		   pSiS->ROM661New = SiSDetermineROMLayout661(pSiS->SiS_Pr);
418272b676d7Smrg		}
418372b676d7Smrg		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
418472b676d7Smrg			"Video BIOS version \"%7s\" found (%s data layout)\n",
418572b676d7Smrg			&pSiS->BIOS[romptr], pSiS->ROM661New ? "new SiS" :
418672b676d7Smrg				(pSiS->HaveXGIBIOS ? "XGI" : "old SiS"));
418772b676d7Smrg		if(pSiS->SiS_Pr->DDCPortMixup) {
418872b676d7Smrg		   xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
418972b676d7Smrg			"*** Buggy XGI V3XT card detected: If VGA and DVI are connected at the\n");
419072b676d7Smrg		   xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
419172b676d7Smrg			"*** same time, BIOS and driver will be unable to detect DVI connection.\n");
419272b676d7Smrg		}
419372b676d7Smrg#ifdef SISDUALHEAD
419472b676d7Smrg		if(pSiSEnt) {
419572b676d7Smrg		   pSiSEnt->BIOS = pSiS->BIOS;
419672b676d7Smrg		   pSiSEnt->ROM661New = pSiS->ROM661New;
419772b676d7Smrg		   pSiSEnt->HaveXGIBIOS = pSiS->HaveXGIBIOS;
419872b676d7Smrg		}
419972b676d7Smrg#endif
420072b676d7Smrg	     } else {
420172b676d7Smrg	        xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
420272b676d7Smrg			 "Could not find/read video BIOS\n");
42035788ca14Smrg		free(pSiS->BIOS);
420472b676d7Smrg		pSiS->BIOS = NULL;
420572b676d7Smrg	     }
420672b676d7Smrg          }
420772b676d7Smrg       }
420872b676d7Smrg
420972b676d7Smrg       if(!(pSiS->ChipFlags & SiSCF_IsXGI)) {
421072b676d7Smrg          if(pSiS->BIOS) pSiS->SiS_Pr->UseROM = TRUE;
421172b676d7Smrg          else           pSiS->SiS_Pr->UseROM = FALSE;
421272b676d7Smrg       }
421372b676d7Smrg    }
421472b676d7Smrg
421572b676d7Smrg    /* Evaluate options */
421672b676d7Smrg    SiSOptions(pScrn);
421772b676d7Smrg
421872b676d7Smrg#ifdef SISMERGED
421972b676d7Smrg    /* Due to palette & timing problems we don't support 8bpp in MFBM */
422072b676d7Smrg    if((pSiS->MergedFB) && (pScrn->bitsPerPixel <= 8)) {
422172b676d7Smrg       SISErrorLog(pScrn, "MergedFB: Color depth %d not supported, %s\n",
422272b676d7Smrg			pScrn->bitsPerPixel, mergeddisstr);
422372b676d7Smrg       pSiS->MergedFB = pSiS->MergedFBAuto = FALSE;
422472b676d7Smrg    }
422572b676d7Smrg#endif
422672b676d7Smrg
422772b676d7Smrg    /* Probe CPU features */
422872b676d7Smrg#ifdef SISDUALHEAD
422972b676d7Smrg    if(pSiS->DualHeadMode) {
423072b676d7Smrg       pSiS->CPUFlags = pSiSEnt->CPUFlags;
423172b676d7Smrg    }
423272b676d7Smrg#endif
423372b676d7Smrg    if(!pSiS->CPUFlags) {
423472b676d7Smrg       pSiS->CPUFlags = SiSGetCPUFlags(pScrn);
423572b676d7Smrg       pSiS->CPUFlags |= SIS_CPUFL_FLAG;
423672b676d7Smrg#ifdef SISDUALHEAD
423772b676d7Smrg       if(pSiS->DualHeadMode) pSiSEnt->CPUFlags = pSiS->CPUFlags;
423872b676d7Smrg#endif
423972b676d7Smrg    }
424072b676d7Smrg
424172b676d7Smrg    /* We use a programamble clock */
424272b676d7Smrg    pScrn->progClock = TRUE;
424372b676d7Smrg
424472b676d7Smrg    /* Set the bits per RGB for 8bpp mode */
424572b676d7Smrg    if(pScrn->depth == 8) pScrn->rgbBits = 8;
424672b676d7Smrg
424772b676d7Smrg#ifdef SISDUALHEAD
424872b676d7Smrg    if(pSiS->DualHeadMode) {
424972b676d7Smrg       if(!pSiS->SecondHead) {
425072b676d7Smrg	  /* Copy some option settings to entity private */
425172b676d7Smrg	  pSiSEnt->HWCursor = pSiS->HWCursor;
425272b676d7Smrg	  pSiSEnt->NoAccel = pSiS->NoAccel;
425372b676d7Smrg	  pSiSEnt->useEXA = pSiS->useEXA;
425472b676d7Smrg	  pSiSEnt->restorebyset = pSiS->restorebyset;
425572b676d7Smrg	  pSiSEnt->OptROMUsage = pSiS->OptROMUsage;
425672b676d7Smrg	  pSiSEnt->OptUseOEM = pSiS->OptUseOEM;
425772b676d7Smrg	  pSiSEnt->TurboQueue = pSiS->TurboQueue;
425872b676d7Smrg	  pSiSEnt->forceCRT1 = pSiS->forceCRT1;
425972b676d7Smrg	  pSiSEnt->ForceCRT1Type = pSiS->ForceCRT1Type;
426072b676d7Smrg	  pSiSEnt->CRT1TypeForced = pSiS->CRT1TypeForced;
426172b676d7Smrg	  pSiSEnt->ForceCRT2Type = pSiS->ForceCRT2Type;
426272b676d7Smrg	  pSiSEnt->ForceTVType = pSiS->ForceTVType;
426372b676d7Smrg	  pSiSEnt->ForceYPbPrType = pSiS->ForceYPbPrType;
426472b676d7Smrg	  pSiSEnt->ForceYPbPrAR = pSiS->ForceYPbPrAR;
426572b676d7Smrg	  pSiSEnt->UsePanelScaler = pSiS->UsePanelScaler;
426672b676d7Smrg	  pSiSEnt->CenterLCD = pSiS->CenterLCD;
426772b676d7Smrg	  pSiSEnt->DSTN = pSiS->DSTN;
426872b676d7Smrg	  pSiSEnt->FSTN = pSiS->FSTN;
426972b676d7Smrg	  pSiSEnt->OptTVStand = pSiS->OptTVStand;
427072b676d7Smrg	  pSiSEnt->NonDefaultPAL = pSiS->NonDefaultPAL;
427172b676d7Smrg	  pSiSEnt->NonDefaultNTSC = pSiS->NonDefaultNTSC;
427272b676d7Smrg	  pSiSEnt->chtvtype = pSiS->chtvtype;
427372b676d7Smrg	  pSiSEnt->OptTVOver = pSiS->OptTVOver;
427472b676d7Smrg	  pSiSEnt->OptTVSOver = pSiS->OptTVSOver;
427572b676d7Smrg	  pSiSEnt->chtvlumabandwidthcvbs = pSiS->chtvlumabandwidthcvbs;
427672b676d7Smrg	  pSiSEnt->chtvlumabandwidthsvideo = pSiS->chtvlumabandwidthsvideo;
427772b676d7Smrg	  pSiSEnt->chtvlumaflickerfilter = pSiS->chtvlumaflickerfilter;
427872b676d7Smrg	  pSiSEnt->chtvchromabandwidth = pSiS->chtvchromabandwidth;
427972b676d7Smrg	  pSiSEnt->chtvchromaflickerfilter = pSiS->chtvchromaflickerfilter;
428072b676d7Smrg	  pSiSEnt->chtvtextenhance = pSiS->chtvtextenhance;
428172b676d7Smrg	  pSiSEnt->chtvcontrast = pSiS->chtvcontrast;
428272b676d7Smrg	  pSiSEnt->chtvcvbscolor = pSiS->chtvcvbscolor;
428372b676d7Smrg	  pSiSEnt->sistvedgeenhance = pSiS->sistvedgeenhance;
428472b676d7Smrg	  pSiSEnt->sistvantiflicker = pSiS->sistvantiflicker;
428572b676d7Smrg	  pSiSEnt->sistvsaturation = pSiS->sistvsaturation;
428672b676d7Smrg	  pSiSEnt->sistvcfilter = pSiS->sistvcfilter;
428772b676d7Smrg	  pSiSEnt->sistvyfilter = pSiS->sistvyfilter;
428872b676d7Smrg	  pSiSEnt->sistvcolcalibc = pSiS->sistvcolcalibc;
428972b676d7Smrg	  pSiSEnt->sistvcolcalibf = pSiS->sistvcolcalibf;
429072b676d7Smrg	  pSiSEnt->tvxpos = pSiS->tvxpos;
429172b676d7Smrg	  pSiSEnt->tvypos = pSiS->tvypos;
429272b676d7Smrg	  pSiSEnt->tvxscale = pSiS->tvxscale;
429372b676d7Smrg	  pSiSEnt->tvyscale = pSiS->tvyscale;
429472b676d7Smrg	  pSiSEnt->siscrt1satgain = pSiS->siscrt1satgain;
429572b676d7Smrg	  pSiSEnt->crt1satgaingiven = pSiS->crt1satgaingiven;
429672b676d7Smrg	  pSiSEnt->CRT1gamma = pSiS->CRT1gamma;
429772b676d7Smrg	  pSiSEnt->CRT1gammaGiven = pSiS->CRT1gammaGiven;
429872b676d7Smrg	  pSiSEnt->XvGammaRed = pSiS->XvGammaRed;
429972b676d7Smrg	  pSiSEnt->XvGammaGreen = pSiS->XvGammaGreen;
430072b676d7Smrg	  pSiSEnt->XvGammaBlue = pSiS->XvGammaBlue;
430172b676d7Smrg	  pSiSEnt->XvGamma = pSiS->XvGamma;
430272b676d7Smrg	  pSiSEnt->XvGammaGiven = pSiS->XvGammaGiven;
430372b676d7Smrg	  pSiSEnt->CRT2gamma = pSiS->CRT2gamma;
430472b676d7Smrg	  pSiSEnt->XvOnCRT2 = pSiS->XvOnCRT2;
430572b676d7Smrg	  pSiSEnt->AllowHotkey = pSiS->AllowHotkey;
430672b676d7Smrg	  pSiSEnt->enablesisctrl = pSiS->enablesisctrl;
430772b676d7Smrg	  pSiSEnt->SenseYPbPr = pSiS->SenseYPbPr;
430872b676d7Smrg	  pSiSEnt->XvUseMemcpy = pSiS->XvUseMemcpy;
430972b676d7Smrg	  pSiSEnt->BenchMemCpy = pSiS->BenchMemCpy;
431072b676d7Smrg#ifdef SIS_CP
431172b676d7Smrg	  SIS_CP_DRIVER_COPYOPTIONSENT
431272b676d7Smrg#endif
431372b676d7Smrg       } else {
431472b676d7Smrg	  /* We always use same cursor type on both screens */
431572b676d7Smrg	  pSiS->HWCursor = pSiSEnt->HWCursor;
431672b676d7Smrg	  /* We need identical NoAccel setting */
431772b676d7Smrg	  pSiS->NoAccel = pSiSEnt->NoAccel;
431872b676d7Smrg	  pSiS->useEXA = pSiSEnt->useEXA;
431972b676d7Smrg	  pSiS->TurboQueue = pSiSEnt->TurboQueue;
432072b676d7Smrg	  pSiS->restorebyset = pSiSEnt->restorebyset;
432172b676d7Smrg	  pSiS->AllowHotkey = pSiS->AllowHotkey;
432272b676d7Smrg	  pSiS->OptROMUsage = pSiSEnt->OptROMUsage;
432372b676d7Smrg	  pSiS->OptUseOEM = pSiSEnt->OptUseOEM;
432472b676d7Smrg	  pSiS->forceCRT1 = pSiSEnt->forceCRT1;
432572b676d7Smrg	  pSiS->nocrt2ddcdetection = FALSE;
432672b676d7Smrg	  pSiS->forcecrt2redetection = FALSE;
432772b676d7Smrg	  pSiS->ForceCRT1Type = pSiSEnt->ForceCRT1Type;
432872b676d7Smrg	  pSiS->ForceCRT2Type = pSiSEnt->ForceCRT2Type;
432972b676d7Smrg	  pSiS->CRT1TypeForced = pSiSEnt->CRT1TypeForced;
433072b676d7Smrg	  pSiS->UsePanelScaler = pSiSEnt->UsePanelScaler;
433172b676d7Smrg	  pSiS->CenterLCD = pSiSEnt->CenterLCD;
433272b676d7Smrg	  pSiS->DSTN = pSiSEnt->DSTN;
433372b676d7Smrg	  pSiS->FSTN = pSiSEnt->FSTN;
433472b676d7Smrg	  pSiS->OptTVStand = pSiSEnt->OptTVStand;
433572b676d7Smrg	  pSiS->NonDefaultPAL = pSiSEnt->NonDefaultPAL;
433672b676d7Smrg	  pSiS->NonDefaultNTSC = pSiSEnt->NonDefaultNTSC;
433772b676d7Smrg	  pSiS->chtvtype = pSiSEnt->chtvtype;
433872b676d7Smrg	  pSiS->ForceTVType = pSiSEnt->ForceTVType;
433972b676d7Smrg	  pSiS->ForceYPbPrType = pSiSEnt->ForceYPbPrType;
434072b676d7Smrg	  pSiS->ForceYPbPrAR = pSiSEnt->ForceYPbPrAR;
434172b676d7Smrg	  pSiS->OptTVOver = pSiSEnt->OptTVOver;
434272b676d7Smrg	  pSiS->OptTVSOver = pSiSEnt->OptTVSOver;
434372b676d7Smrg	  pSiS->chtvlumabandwidthcvbs = pSiSEnt->chtvlumabandwidthcvbs;
434472b676d7Smrg	  pSiS->chtvlumabandwidthsvideo = pSiSEnt->chtvlumabandwidthsvideo;
434572b676d7Smrg	  pSiS->chtvlumaflickerfilter = pSiSEnt->chtvlumaflickerfilter;
434672b676d7Smrg	  pSiS->chtvchromabandwidth = pSiSEnt->chtvchromabandwidth;
434772b676d7Smrg	  pSiS->chtvchromaflickerfilter = pSiSEnt->chtvchromaflickerfilter;
434872b676d7Smrg	  pSiS->chtvcvbscolor = pSiSEnt->chtvcvbscolor;
434972b676d7Smrg	  pSiS->chtvtextenhance = pSiSEnt->chtvtextenhance;
435072b676d7Smrg	  pSiS->chtvcontrast = pSiSEnt->chtvcontrast;
435172b676d7Smrg	  pSiS->sistvedgeenhance = pSiSEnt->sistvedgeenhance;
435272b676d7Smrg	  pSiS->sistvantiflicker = pSiSEnt->sistvantiflicker;
435372b676d7Smrg	  pSiS->sistvsaturation = pSiSEnt->sistvsaturation;
435472b676d7Smrg	  pSiS->sistvcfilter = pSiSEnt->sistvcfilter;
435572b676d7Smrg	  pSiS->sistvyfilter = pSiSEnt->sistvyfilter;
435672b676d7Smrg	  pSiS->sistvcolcalibc = pSiSEnt->sistvcolcalibc;
435772b676d7Smrg	  pSiS->sistvcolcalibf = pSiSEnt->sistvcolcalibf;
435872b676d7Smrg	  pSiS->tvxpos = pSiSEnt->tvxpos;
435972b676d7Smrg	  pSiS->tvypos = pSiSEnt->tvypos;
436072b676d7Smrg	  pSiS->tvxscale = pSiSEnt->tvxscale;
436172b676d7Smrg	  pSiS->tvyscale = pSiSEnt->tvyscale;
436272b676d7Smrg	  pSiS->SenseYPbPr = pSiSEnt->SenseYPbPr;
436372b676d7Smrg	  if(!pSiS->CRT1gammaGiven) {
436472b676d7Smrg	     if(pSiSEnt->CRT1gammaGiven)
436572b676d7Smrg	        pSiS->CRT1gamma = pSiSEnt->CRT1gamma;
436672b676d7Smrg	  }
436772b676d7Smrg	  pSiS->CRT2gamma = pSiSEnt->CRT2gamma;
436872b676d7Smrg	  if(!pSiS->XvGammaGiven) {
436972b676d7Smrg	     if(pSiSEnt->XvGammaGiven) {
437072b676d7Smrg		pSiS->XvGamma = pSiSEnt->XvGamma;
437172b676d7Smrg		pSiS->XvGammaRed = pSiS->XvGammaRedDef = pSiSEnt->XvGammaRed;
437272b676d7Smrg		pSiS->XvGammaGreen = pSiS->XvGammaGreenDef = pSiSEnt->XvGammaGreen;
437372b676d7Smrg		pSiS->XvGammaBlue = pSiS->XvGammaBlueDef = pSiSEnt->XvGammaBlue;
437472b676d7Smrg	     }
437572b676d7Smrg	  }
437672b676d7Smrg	  if(!pSiS->crt1satgaingiven) {
437772b676d7Smrg	     if(pSiSEnt->crt1satgaingiven)
437872b676d7Smrg	        pSiS->siscrt1satgain = pSiSEnt->siscrt1satgain;
437972b676d7Smrg	  }
438072b676d7Smrg	  pSiS->XvOnCRT2 = pSiSEnt->XvOnCRT2;
438172b676d7Smrg	  pSiS->enablesisctrl = pSiSEnt->enablesisctrl;
438272b676d7Smrg	  pSiS->XvUseMemcpy = pSiSEnt->XvUseMemcpy;
438372b676d7Smrg	  pSiS->BenchMemCpy = pSiSEnt->BenchMemCpy;
438472b676d7Smrg	  /* Copy gamma brightness to Ent (sic!) for Xinerama */
438572b676d7Smrg	  pSiSEnt->GammaBriR = pSiS->GammaBriR;
438672b676d7Smrg	  pSiSEnt->GammaBriG = pSiS->GammaBriG;
438772b676d7Smrg	  pSiSEnt->GammaBriB = pSiS->GammaBriB;
438872b676d7Smrg	  pSiSEnt->NewGammaBriR = pSiS->NewGammaBriR;
438972b676d7Smrg	  pSiSEnt->NewGammaBriG = pSiS->NewGammaBriG;
439072b676d7Smrg	  pSiSEnt->NewGammaBriB = pSiS->NewGammaBriB;
439172b676d7Smrg	  pSiSEnt->NewGammaConR = pSiS->NewGammaConR;
439272b676d7Smrg	  pSiSEnt->NewGammaConG = pSiS->NewGammaConG;
439372b676d7Smrg	  pSiSEnt->NewGammaConB = pSiS->NewGammaConB;
439472b676d7Smrg#ifdef SIS_CP
439572b676d7Smrg	  SIS_CP_DRIVER_COPYOPTIONS
439672b676d7Smrg#endif
439772b676d7Smrg       }
439872b676d7Smrg    }
439972b676d7Smrg#endif
440072b676d7Smrg
440172b676d7Smrg    /* Handle UseROMData, NoOEM and UsePanelScaler options */
440272b676d7Smrg    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
440372b676d7Smrg       from = X_PROBED;
440472b676d7Smrg       if(pSiS->OptROMUsage == 0) {
440572b676d7Smrg	  pSiS->SiS_Pr->UseROM = FALSE;
440672b676d7Smrg	  from = X_CONFIG;
440772b676d7Smrg	  xf86DrvMsg(pScrn->scrnIndex, from, "Video ROM data usage is disabled\n");
440872b676d7Smrg       }
440972b676d7Smrg
441072b676d7Smrg       if(!pSiS->OptUseOEM) {
441172b676d7Smrg	  xf86DrvMsg(pScrn->scrnIndex, from, "Internal OEM LCD/TV/VGA2 data usage is disabled\n");
441272b676d7Smrg       }
441372b676d7Smrg
441472b676d7Smrg       pSiS->SiS_Pr->UsePanelScaler = pSiS->UsePanelScaler;
441572b676d7Smrg       pSiS->SiS_Pr->CenterScreen = pSiS->CenterLCD;
441672b676d7Smrg    }
441772b676d7Smrg
441872b676d7Smrg    /* Do some HW configuration detection (memory amount & type, clock, etc) */
441972b676d7Smrg    SiSSetup(pScrn);
442072b676d7Smrg
442172b676d7Smrg    /* Get framebuffer address */
442272b676d7Smrg    if(pSiS->pEnt->device->MemBase != 0) {
442372b676d7Smrg       /*
442472b676d7Smrg	* XXX Should check that the config file value matches one of the
442572b676d7Smrg	* PCI base address values.
442672b676d7Smrg	*/
442772b676d7Smrg       pSiS->FbAddress = pSiS->pEnt->device->MemBase;
442872b676d7Smrg       from = X_CONFIG;
442972b676d7Smrg    } else {
44301fd23544Smrg       pSiS->FbAddress = PCI_REGION_BASE(pSiS->PciInfo, 0, REGION_MEM) & 0xFFFFFFF0;
443172b676d7Smrg       from = X_PROBED;
443272b676d7Smrg    }
443372b676d7Smrg
443472b676d7Smrg#ifdef SISDUALHEAD
443572b676d7Smrg    if(pSiS->DualHeadMode)
443672b676d7Smrg       xf86DrvMsg(pScrn->scrnIndex, from, "Global linear framebuffer at 0x%lX\n",
443772b676d7Smrg	   (ULong)pSiS->FbAddress);
443872b676d7Smrg    else
443972b676d7Smrg#endif
444072b676d7Smrg       xf86DrvMsg(pScrn->scrnIndex, from, "Linear framebuffer at 0x%lX\n",
444172b676d7Smrg	   (ULong)pSiS->FbAddress);
444272b676d7Smrg
444372b676d7Smrg    pSiS->realFbAddress = pSiS->FbAddress;
444472b676d7Smrg
444572b676d7Smrg    /* Get MMIO address */
444672b676d7Smrg    if(pSiS->pEnt->device->IOBase != 0) {
444772b676d7Smrg       /*
444872b676d7Smrg	* XXX Should check that the config file value matches one of the
444972b676d7Smrg	* PCI base address values.
445072b676d7Smrg	*/
445172b676d7Smrg       pSiS->IOAddress = pSiS->pEnt->device->IOBase;
445272b676d7Smrg       from = X_CONFIG;
445372b676d7Smrg    } else {
44541fd23544Smrg       pSiS->IOAddress = PCI_REGION_BASE(pSiS->PciInfo, 1, REGION_MEM) & 0xFFFFFFF0;
445572b676d7Smrg       from = X_PROBED;
445672b676d7Smrg    }
445772b676d7Smrg    xf86DrvMsg(pScrn->scrnIndex, from, "MMIO registers at 0x%lX (size %ldK)\n",
445872b676d7Smrg	   (ULong)pSiS->IOAddress, pSiS->mmioSize);
445972b676d7Smrg
4460e47418d9Smrg#ifndef XSERVER_LIBPCIACCESS
446172b676d7Smrg    /* Register the PCI-assigned resources */
446272b676d7Smrg    if(xf86RegisterResources(pSiS->pEnt->index, NULL, ResExclusive)) {
446372b676d7Smrg       SISErrorLog(pScrn, "PCI resource conflicts detected\n");
446472b676d7Smrg#ifdef SISDUALHEAD
446572b676d7Smrg       if(pSiSEnt) pSiSEnt->ErrorAfterFirst = TRUE;
446672b676d7Smrg#endif
446772b676d7Smrg       sisRestoreExtRegisterLock(pSiS,srlockReg,crlockReg);
446872b676d7Smrg       if(pSiS->pInt) xf86FreeInt10(pSiS->pInt);
446972b676d7Smrg       SISFreeRec(pScrn);
447072b676d7Smrg       return FALSE;
447172b676d7Smrg    }
4472e47418d9Smrg#endif
447372b676d7Smrg
447472b676d7Smrg    from = X_PROBED;
447572b676d7Smrg    if(pSiS->pEnt->device->videoRam != 0) {
447672b676d7Smrg       if(pSiS->Chipset == PCI_CHIP_SIS6326) {
447772b676d7Smrg	  pScrn->videoRam = pSiS->pEnt->device->videoRam;
447872b676d7Smrg	  from = X_CONFIG;
447972b676d7Smrg       } else {
448072b676d7Smrg	  xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
448172b676d7Smrg		"Option \"VideoRAM\" ignored\n");
448272b676d7Smrg       }
448372b676d7Smrg    }
448472b676d7Smrg
448572b676d7Smrg    pSiS->RealVideoRam = pScrn->videoRam;
448672b676d7Smrg
448772b676d7Smrg    if((pSiS->Chipset == PCI_CHIP_SIS6326) &&
448872b676d7Smrg       (pScrn->videoRam > 4096)            &&
448972b676d7Smrg       (from != X_CONFIG)) {
449072b676d7Smrg       pScrn->videoRam = 4096;
449172b676d7Smrg       xf86DrvMsg(pScrn->scrnIndex, from,
449272b676d7Smrg	   "SiS6326: Detected %d KB VideoRAM, limiting to %d KB\n",
449372b676d7Smrg	   pSiS->RealVideoRam, pScrn->videoRam);
449472b676d7Smrg    } else {
449572b676d7Smrg       xf86DrvMsg(pScrn->scrnIndex, from, "VideoRAM: %d KB\n", pScrn->videoRam);
449672b676d7Smrg    }
449772b676d7Smrg
449872b676d7Smrg    if((pSiS->Chipset == PCI_CHIP_SIS6326) &&
449972b676d7Smrg       (pScrn->videoRam > 4096)) {
450072b676d7Smrg       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
450172b676d7Smrg	   "SiS6326 engines do not support more than 4096KB RAM, therefore\n");
450272b676d7Smrg       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
450372b676d7Smrg	   "TurboQueue, HWCursor, 2D acceleration and XVideo are disabled.\n");
450472b676d7Smrg       pSiS->TurboQueue = FALSE;
450572b676d7Smrg       pSiS->HWCursor   = FALSE;
450672b676d7Smrg       pSiS->NoXvideo   = TRUE;
450772b676d7Smrg       pSiS->NoAccel    = TRUE;
450872b676d7Smrg    }
450972b676d7Smrg
451072b676d7Smrg    pSiS->FbMapSize = pSiS->availMem = pScrn->videoRam * 1024;
451172b676d7Smrg
451272b676d7Smrg    /* Calculate real availMem according to Accel/TurboQueue and
451372b676d7Smrg     * HWCursur setting. Also, initialize some variables used
451472b676d7Smrg     * in other modules.
451572b676d7Smrg     */
451672b676d7Smrg    pSiS->cursorOffset = 0;
451772b676d7Smrg    pSiS->CurARGBDest = NULL;
451872b676d7Smrg    pSiS->CurMonoSrc = NULL;
451972b676d7Smrg    pSiS->CurFGCol = pSiS->CurBGCol = 0;
452072b676d7Smrg    pSiS->FbBaseOffset = 0;
452172b676d7Smrg
452272b676d7Smrg    switch(pSiS->VGAEngine) {
452372b676d7Smrg
452472b676d7Smrg      case SIS_300_VGA:
452572b676d7Smrg	pSiS->TurboQueueLen = 512;
452672b676d7Smrg	if(pSiS->TurboQueue) {
452772b676d7Smrg	   pSiS->availMem -= (pSiS->TurboQueueLen*1024);
452872b676d7Smrg	   pSiS->cursorOffset = 512;
452972b676d7Smrg	}
453072b676d7Smrg	if(pSiS->HWCursor) {
453172b676d7Smrg	   pSiS->availMem -= pSiS->CursorSize;
453272b676d7Smrg	   if(pSiS->OptUseColorCursor) pSiS->availMem -= pSiS->CursorSize;
453372b676d7Smrg	}
453472b676d7Smrg	pSiS->CmdQueLenMask = 0xFFFF;
453572b676d7Smrg	pSiS->CmdQueLenFix  = 0;
453672b676d7Smrg	pSiS->cursorBufferNum = 0;
453772b676d7Smrg#ifdef SISDUALHEAD
453872b676d7Smrg	if(pSiSEnt) pSiSEnt->cursorBufferNum = 0;
453972b676d7Smrg#endif
454072b676d7Smrg	break;
454172b676d7Smrg
454272b676d7Smrg      case SIS_315_VGA:
454372b676d7Smrg#ifdef SISVRAMQ		/* VRAM queue */
454472b676d7Smrg	pSiS->cmdQueueSizeMask = pSiS->cmdQueueSize - 1;	/* VRAM Command Queue is variable (in therory) */
454572b676d7Smrg	pSiS->cmdQueueOffset = (pScrn->videoRam * 1024) - pSiS->cmdQueueSize;
454672b676d7Smrg	pSiS->cmdQueueLen = 0;
454772b676d7Smrg	pSiS->cmdQueueSize_div2 = pSiS->cmdQueueSize / 2;
454872b676d7Smrg	pSiS->cmdQueueSize_div4 = pSiS->cmdQueueSize / 4;
454972b676d7Smrg	pSiS->cmdQueueSize_4_3 = (pSiS->cmdQueueSize / 4) * 3;
455072b676d7Smrg	pSiS->availMem -= pSiS->cmdQueueSize;
455172b676d7Smrg	pSiS->cursorOffset = (pSiS->cmdQueueSize / 1024);
455272b676d7Smrg
455372b676d7Smrg	/* Set up shared pointer to current offset */
455472b676d7Smrg#ifdef SISDUALHEAD
455572b676d7Smrg	if(pSiS->DualHeadMode)
455672b676d7Smrg	   pSiS->cmdQ_SharedWritePort = &(pSiSEnt->cmdQ_SharedWritePort_2D);
455772b676d7Smrg	else
455872b676d7Smrg#endif
455972b676d7Smrg	   pSiS->cmdQ_SharedWritePort = &(pSiS->cmdQ_SharedWritePort_2D);
456072b676d7Smrg
456172b676d7Smrg
456272b676d7Smrg#else			/* MMIO */
456372b676d7Smrg	if(pSiS->TurboQueue) {
456472b676d7Smrg	   pSiS->availMem -= (512*1024);			/* MMIO Command Queue is 512k (variable in theory) */
456572b676d7Smrg	   pSiS->cursorOffset = 512;
456672b676d7Smrg	}
456772b676d7Smrg#endif
456872b676d7Smrg	if(pSiS->HWCursor) {
456972b676d7Smrg	   pSiS->availMem -= (pSiS->CursorSize * 2);
457072b676d7Smrg	   if(pSiS->OptUseColorCursor) pSiS->availMem -= (pSiS->CursorSize * 2);
457172b676d7Smrg	}
457272b676d7Smrg	pSiS->cursorBufferNum = 0;
457372b676d7Smrg#ifdef SISDUALHEAD
457472b676d7Smrg	if(pSiSEnt) pSiSEnt->cursorBufferNum = 0;
457572b676d7Smrg#endif
457672b676d7Smrg
457772b676d7Smrg	if((pSiS->SiS76xLFBSize) && (pSiS->SiS76xUMASize)) {
457872b676d7Smrg	   pSiS->availMem -= pSiS->SiS76xUMASize;
457972b676d7Smrg	   pSiS->FbBaseOffset = pSiS->SiS76xUMASize;
458072b676d7Smrg	}
458172b676d7Smrg
458272b676d7Smrg	break;
458372b676d7Smrg
458472b676d7Smrg      default:
458572b676d7Smrg	/* cursorOffset not used in cursor functions for 530 and
458672b676d7Smrg	 * older chips, because the cursor is *above* the TQ.
458772b676d7Smrg	 * On 5597 and older revisions of the 6326, the TQ is
458872b676d7Smrg	 * max 32K, on newer 6326 revisions and the 530 either 30
458972b676d7Smrg	 * (or 32?) or 62K (or 64?). However, to make sure, we
459072b676d7Smrg	 * use only 30K (or 32?), but reduce the available memory
459172b676d7Smrg	 * by 64, and locate the TQ at the beginning of this last
459272b676d7Smrg	 * 64K block. (We do this that way even when using the
459372b676d7Smrg	 * HWCursor, because the cursor only takes 2K and the
459472b676d7Smrg	 * queue does not seem to last that far anyway.)
459572b676d7Smrg	 * The TQ must be located at 32KB boundaries.
459672b676d7Smrg	 */
459772b676d7Smrg	if(pSiS->RealVideoRam < 3072) {
459872b676d7Smrg	   if(pSiS->TurboQueue) {
459972b676d7Smrg	      xf86DrvMsg(pScrn->scrnIndex, X_INFO,
460072b676d7Smrg		    "Not enough video RAM for TurboQueue. TurboQueue disabled\n");
460172b676d7Smrg	      pSiS->TurboQueue = FALSE;
460272b676d7Smrg	   }
460372b676d7Smrg	}
460472b676d7Smrg	pSiS->CmdQueMaxLen = 32;
460572b676d7Smrg	if(pSiS->TurboQueue) {
460672b676d7Smrg			      pSiS->availMem -= (64*1024);
460772b676d7Smrg			      pSiS->CmdQueMaxLen = 900;   /* To make sure; should be 992 */
460872b676d7Smrg	} else if(pSiS->HWCursor) {
460972b676d7Smrg			      pSiS->availMem -= pSiS->CursorSize;
461072b676d7Smrg	}
461172b676d7Smrg	if(pSiS->Chipset == PCI_CHIP_SIS530) {
461272b676d7Smrg		/* Check if Flat Panel is enabled */
461372b676d7Smrg		inSISIDXREG(SISSR, 0x0e, tempreg);
461472b676d7Smrg		if(!(tempreg & 0x04)) pSiS->availMem -= pSiS->CursorSize;
461572b676d7Smrg
461672b676d7Smrg		/* Set up mask for MMIO register */
461772b676d7Smrg		pSiS->CmdQueLenMask = (pSiS->TurboQueue) ? 0x1FFF : 0x00FF;
461872b676d7Smrg	} else {
461972b676d7Smrg	        /* TQ is never used on 6326/5597, because the accelerator
462072b676d7Smrg		 * always Syncs. So this is just cosmentic work. (And I
462172b676d7Smrg		 * am not even sure that 0x7fff is correct. MMIO 0x83a8
462272b676d7Smrg		 * holds 0xec0 if (30k) TQ is enabled, 0x20 if TQ disabled.
462372b676d7Smrg		 * The datasheet has no real explanation on the queue length
462472b676d7Smrg		 * if the TQ is enabled. Not syncing and waiting for a
462572b676d7Smrg		 * suitable queue length instead does not work.
462672b676d7Smrg		 */
462772b676d7Smrg	        pSiS->CmdQueLenMask = (pSiS->TurboQueue) ? 0x7FFF : 0x003F;
462872b676d7Smrg	}
462972b676d7Smrg
463072b676d7Smrg	/* This is to be subtracted from MMIO queue length register contents
463172b676d7Smrg	 * for getting the real Queue length.
463272b676d7Smrg	 */
463372b676d7Smrg	pSiS->CmdQueLenFix  = (pSiS->TurboQueue) ? 32 : 0;
463472b676d7Smrg    }
463572b676d7Smrg
463672b676d7Smrg
463772b676d7Smrg#ifdef SISDUALHEAD
463872b676d7Smrg    /* In dual head mode, we share availMem equally - so align it
463972b676d7Smrg     * to 8KB; this way, the address of the FB of the second
464072b676d7Smrg     * head is aligned to 4KB for mapping.
464172b676d7Smrg     */
464272b676d7Smrg   if(pSiS->DualHeadMode) pSiS->availMem &= 0xFFFFE000;
464372b676d7Smrg#endif
464472b676d7Smrg
464572b676d7Smrg    /* Check MaxXFBMem setting */
464672b676d7Smrg#ifdef SISDUALHEAD
464772b676d7Smrg    if(pSiS->DualHeadMode) {
464872b676d7Smrg        /* 1. Since DRI is not supported in dual head mode, we
464972b676d7Smrg	 *    don't need the MaxXFBMem setting - ignore it.
465072b676d7Smrg	 */
465172b676d7Smrg	if(pSiS->maxxfbmem) {
465272b676d7Smrg	   xf86DrvMsg(pScrn->scrnIndex, X_INFO,
465372b676d7Smrg		"MaxXFBMem ignored in Dual Head mode\n");
465472b676d7Smrg	}
465572b676d7Smrg	pSiS->maxxfbmem = pSiS->availMem;
465672b676d7Smrg    } else
465772b676d7Smrg#endif
465872b676d7Smrg	   if((pSiS->sisfbHeapStart) || (pSiS->sisfbHaveNewHeapDef)) {
465972b676d7Smrg
466072b676d7Smrg       /*
466172b676d7Smrg	* 2. We have memory layout info from sisfb - ignore MaxXFBMem
466272b676d7Smrg	*/
466372b676d7Smrg	if(pSiS->maxxfbmem) {
466472b676d7Smrg	   xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
466572b676d7Smrg		"Got memory layout info from sisfb, ignoring MaxXFBMem option\n");
466672b676d7Smrg	}
466772b676d7Smrg	if((pSiS->FbBaseOffset) && (!pSiS->sisfbHaveNewHeapDef)) {
466872b676d7Smrg	   xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
466972b676d7Smrg		"Incompatible sisfb version detected, DRI disabled\n");
467072b676d7Smrg	   pSiS->loadDRI = FALSE;
467172b676d7Smrg	   pSiS->maxxfbmem = pSiS->availMem;
467272b676d7Smrg	} else {
467372b676d7Smrg	   if(pSiS->FbBaseOffset) {
467472b676d7Smrg	      /* Revert our changes to FbBaseOffset and availMem; use sisfb's info */
467572b676d7Smrg	      pSiS->availMem += pSiS->FbBaseOffset;
467672b676d7Smrg	      pSiS->FbBaseOffset = 0;
467772b676d7Smrg	   }
467872b676d7Smrg	   if(pSiS->sisfbVideoOffset) {
467972b676d7Smrg	      /* a. DRI heap BELOW framebuffer */
468072b676d7Smrg	      pSiS->FbBaseOffset = pSiS->sisfbVideoOffset;
468172b676d7Smrg	      pSiS->availMem -= pSiS->FbBaseOffset;
468272b676d7Smrg	      pSiS->maxxfbmem = pSiS->availMem;
468372b676d7Smrg	   } else {
468472b676d7Smrg	      /* b. DRI heap ABOVE framebuffer (traditional layout) */
468572b676d7Smrg	      if(pSiS->availMem < (pSiS->sisfbHeapStart * 1024)) {
468672b676d7Smrg		 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
468772b676d7Smrg			"Internal error - sisfb memory layout corrupt\n");
468872b676d7Smrg		 pSiS->loadDRI = FALSE;
468972b676d7Smrg		 pSiS->maxxfbmem = pSiS->availMem;
469072b676d7Smrg	      } else {
469172b676d7Smrg	         pSiS->maxxfbmem = pSiS->sisfbHeapStart * 1024;
469272b676d7Smrg	      }
469372b676d7Smrg	   }
469472b676d7Smrg	}
469572b676d7Smrg
469672b676d7Smrg    } else if(pSiS->maxxfbmem) {
469772b676d7Smrg
469872b676d7Smrg       /*
469972b676d7Smrg	* 3. No sisfb, but user gave "MaxXFBMem"
470072b676d7Smrg	*/
470172b676d7Smrg	if(pSiS->FbBaseOffset) {
470272b676d7Smrg	   /* a. DRI heap BELOW framebuffer */
470372b676d7Smrg	   if(pSiS->maxxfbmem > (pSiS->availMem + pSiS->FbBaseOffset - pSiS->SiS76xUMASize)) {
470472b676d7Smrg	      xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
470572b676d7Smrg			"Invalid MaxXFBMem setting\n");
470672b676d7Smrg	      pSiS->maxxfbmem = pSiS->availMem;
470772b676d7Smrg	   } else {
470872b676d7Smrg	      /* Revert our changes */
470972b676d7Smrg	      pSiS->availMem += pSiS->FbBaseOffset;
471072b676d7Smrg	      /* Use user's MaxXFBMem setting */
471172b676d7Smrg	      pSiS->FbBaseOffset = pSiS->availMem - pSiS->maxxfbmem;
471272b676d7Smrg	      pSiS->availMem -= pSiS->FbBaseOffset;
471372b676d7Smrg	   }
471472b676d7Smrg	} else {
471572b676d7Smrg	   /* b. DRI heap ABOVE framebuffer (traditional layout) */
471672b676d7Smrg	   if(pSiS->maxxfbmem > pSiS->availMem) {
471772b676d7Smrg	      xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
471872b676d7Smrg			 "Invalid MaxXFBMem setting.\n");
471972b676d7Smrg	      pSiS->maxxfbmem = pSiS->availMem;
472072b676d7Smrg	   }
472172b676d7Smrg	}
472272b676d7Smrg
472372b676d7Smrg    } else {
472472b676d7Smrg
472572b676d7Smrg       /*
472672b676d7Smrg	* 4. No MaxXFBMem, no sisfb: Use all memory
472772b676d7Smrg	*/
472872b676d7Smrg	pSiS->maxxfbmem = pSiS->availMem;
472972b676d7Smrg
473072b676d7Smrg	/* ... except on chipsets, for which DRI is
473172b676d7Smrg	 * supported: If DRI is enabled, we now limit
473272b676d7Smrg	 * ourselves to a reasonable default:
473372b676d7Smrg	 */
473472b676d7Smrg
473572b676d7Smrg	if(pSiS->loadDRI) {
473672b676d7Smrg	   if(pSiS->FbBaseOffset) {
473772b676d7Smrg	      /* a. DRI heap BELOW framebuffer */
473872b676d7Smrg	      /* See how much UMA and LFB memory we have,
473972b676d7Smrg	       * and calculate a reasonable default. We
474072b676d7Smrg	       * use more vram for ourselves because these
474172b676d7Smrg	       * chips are eg. capable of larger Xv
474272b676d7Smrg	       * overlays, etc.
474372b676d7Smrg	       */
474472b676d7Smrg	      unsigned long total = (pSiS->SiS76xLFBSize + pSiS->SiS76xUMASize) / 1024;
474572b676d7Smrg	      unsigned long mymax;
474672b676d7Smrg	      if(total <= 16384)			/* <= 16MB: Use 8MB for X */
474772b676d7Smrg	         mymax = 8192 * 1024;
474872b676d7Smrg	      else if(total <= 32768)			/* <= 32MB: Use 16MB for X */
474972b676d7Smrg	         mymax = 16384 * 1024;
475072b676d7Smrg	      else					/* Otherwise: Use 20MB for X */
475172b676d7Smrg	         mymax = 20 * 1024 * 1024;
475272b676d7Smrg	      /* availMem is right now adjusted to not use the UMA
475372b676d7Smrg	       * area. Make sure that our default doesn't reach
475472b676d7Smrg	       * into the UMA area either.
475572b676d7Smrg	       */
475672b676d7Smrg	      if(pSiS->availMem > mymax) {
475772b676d7Smrg		 /* Write our default to maxxfbmem */
475872b676d7Smrg		 pSiS->maxxfbmem = mymax;
475972b676d7Smrg		 /* Revert our changes to availMem */
476072b676d7Smrg		 pSiS->availMem += pSiS->FbBaseOffset;
476172b676d7Smrg		 /* Use our default setting */
476272b676d7Smrg		 pSiS->FbBaseOffset = pSiS->availMem - pSiS->maxxfbmem;
476372b676d7Smrg		 pSiS->availMem -= pSiS->FbBaseOffset;
476472b676d7Smrg	      }
476572b676d7Smrg	   } else {
476672b676d7Smrg	      /* b. DRI heap ABOVE framebuffer (traditional layout) */
476772b676d7Smrg	      /* See how much video memory we have, and calculate
476872b676d7Smrg	       * a reasonable default.
476972b676d7Smrg	       * Since DRI is pointless with less than 4MB of total
477072b676d7Smrg	       * video RAM, we disable it in that case.
477172b676d7Smrg	       */
477272b676d7Smrg	      if(pScrn->videoRam <= 4096)
477372b676d7Smrg	         pSiS->loadDRI = FALSE;
477472b676d7Smrg	      else if(pScrn->videoRam <= 8192)		/* <= 8MB: Use 4MB for X */
477572b676d7Smrg	         pSiS->maxxfbmem = 4096 * 1024;
477672b676d7Smrg	      else if(pScrn->videoRam <= 16384)		/* <= 16MB: Use 8MB for X */
477772b676d7Smrg	         pSiS->maxxfbmem = 8192 * 1024;
477872b676d7Smrg#ifdef SISMERGED					/* Otherwise: --- */
477972b676d7Smrg	      else if(pSiS->MergedFB) {
478072b676d7Smrg	         if(pScrn->videoRam <= 65536)
478172b676d7Smrg	            pSiS->maxxfbmem = 16384 * 1024;	/* If MergedFB and <=64MB, use 16MB for X */
478272b676d7Smrg		 else
478372b676d7Smrg		    pSiS->maxxfbmem = 20 * 1024 * 1024;	/* If MergedFB and > 64MB, use 20MB for X */
478472b676d7Smrg	      }
478572b676d7Smrg#endif
478672b676d7Smrg	        else if(pSiS->VGAEngine == SIS_315_VGA) {
478772b676d7Smrg	         if(pScrn->videoRam <= 65536)
478872b676d7Smrg	            pSiS->maxxfbmem = 16384 * 1024;	/* On >=315 series and <=64MB, use 16MB */
478972b676d7Smrg		 else
479072b676d7Smrg		    pSiS->maxxfbmem = 20 * 1024 * 1024;	/* On >=315 series and > 64MB, use 20MB */
479172b676d7Smrg	      } else
479272b676d7Smrg	         pSiS->maxxfbmem = 12288 * 1024;	/* On <315 series, use 12MB */
479372b676d7Smrg
479472b676d7Smrg	      /* A final check */
479572b676d7Smrg	      if(pSiS->maxxfbmem > pSiS->availMem) {
479672b676d7Smrg		 pSiS->maxxfbmem = pSiS->availMem;
479772b676d7Smrg		 pSiS->loadDRI = FALSE;
479872b676d7Smrg	      }
479972b676d7Smrg	   }
480072b676d7Smrg
480172b676d7Smrg	}
480272b676d7Smrg    }
480372b676d7Smrg
480472b676d7Smrg    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using %dK of framebuffer memory at offset %dK\n",
480572b676d7Smrg				pSiS->maxxfbmem / 1024, pSiS->FbBaseOffset / 1024);
480672b676d7Smrg
480772b676d7Smrg    /* Find out about sub-classes of some chipsets and check
480872b676d7Smrg     * if the chipset supports two video overlays
480972b676d7Smrg     */
481072b676d7Smrg    if(pSiS->VGAEngine == SIS_300_VGA    ||
481172b676d7Smrg       pSiS->VGAEngine == SIS_315_VGA    ||
481272b676d7Smrg       pSiS->Chipset == PCI_CHIP_SIS530  ||
481372b676d7Smrg       pSiS->Chipset == PCI_CHIP_SIS6326 ||
481472b676d7Smrg       pSiS->Chipset == PCI_CHIP_SIS5597)  {
481572b676d7Smrg       pSiS->hasTwoOverlays = FALSE;
481672b676d7Smrg       switch(pSiS->Chipset) {
481772b676d7Smrg	 case PCI_CHIP_SIS300:
481872b676d7Smrg	 case PCI_CHIP_SIS540:  /* ? (If not, need to add the SwitchCRT Xv attribute!) */
481972b676d7Smrg	 case PCI_CHIP_SIS630:
482072b676d7Smrg	 case PCI_CHIP_SIS550:
482172b676d7Smrg	   pSiS->hasTwoOverlays = TRUE;
482272b676d7Smrg	   pSiS->SiS_SD_Flags |= SiS_SD_SUPPORT2OVL;
482372b676d7Smrg	   break;
482472b676d7Smrg	 case PCI_CHIP_SIS315PRO:
482572b676d7Smrg	   pSiS->ChipFlags |= SiSCF_LARGEOVERLAY;
482672b676d7Smrg	   break;
482772b676d7Smrg	 case PCI_CHIP_SIS330:
482872b676d7Smrg	   pSiS->ChipFlags |= (SiSCF_CRT2HWCKaputt | SiSCF_LARGEOVERLAY);
482972b676d7Smrg	   break;
483072b676d7Smrg	 case PCI_CHIP_SIS340:
483172b676d7Smrg	 case PCI_CHIP_XGIXG40: /* Verified: only 1 overlay */
483272b676d7Smrg	   pSiS->ChipFlags |= SiSCF_LARGEOVERLAY;
483372b676d7Smrg	   break;
483472b676d7Smrg	 case PCI_CHIP_SIS650:
483572b676d7Smrg	   {
483672b676d7Smrg	     UChar tempreg1, tempreg2;
483772b676d7Smrg	     static const char *id650str[] = {
483872b676d7Smrg		"650",       "650",       "650",       "650",
483972b676d7Smrg		"650 A0 AA", "650 A2 CA", "650",       "650",
484072b676d7Smrg		"M650 A0",   "M650 A1 AA","651 A0 AA", "651 A1 AA",
484172b676d7Smrg		"M650",      "65?",       "651",       "65?"
484272b676d7Smrg	     };
484372b676d7Smrg	     pSiS->ChipFlags |= SiSCF_LARGEOVERLAY;
484472b676d7Smrg	     if(pSiS->ChipType == SIS_650) {
484572b676d7Smrg		inSISIDXREG(SISCR, 0x5f, CR5F);
484672b676d7Smrg		CR5F &= 0xf0;
484772b676d7Smrg		andSISIDXREG(SISCR, 0x5c, 0x07);
484872b676d7Smrg		inSISIDXREG(SISCR, 0x5c, tempreg1);
484972b676d7Smrg		tempreg1 &= 0xf8;
485072b676d7Smrg		orSISIDXREG(SISCR, 0x5c, 0xf8);
485172b676d7Smrg		inSISIDXREG(SISCR, 0x5c, tempreg2);
485272b676d7Smrg		tempreg2 &= 0xf8;
485372b676d7Smrg		if((!tempreg1) || (tempreg2)) {
485472b676d7Smrg		   xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
485572b676d7Smrg		      "SiS650 revision ID %x (%s)\n", CR5F, id650str[CR5F >> 4]);
485672b676d7Smrg		   if(CR5F & 0x80) {
485772b676d7Smrg		      pSiS->hasTwoOverlays = TRUE;  /* M650 or 651 */
485872b676d7Smrg		      pSiS->SiS_SD_Flags |= SiS_SD_SUPPORT2OVL;
485972b676d7Smrg		   }
486072b676d7Smrg		   switch(CR5F) {
486172b676d7Smrg		      case 0xa0:
486272b676d7Smrg		      case 0xb0:
486372b676d7Smrg		      case 0xe0:
486472b676d7Smrg		         pSiS->ChipFlags |= SiSCF_Is651;
486572b676d7Smrg		         break;
486672b676d7Smrg		      case 0x80:
486772b676d7Smrg		      case 0x90:
486872b676d7Smrg		      case 0xc0:
486972b676d7Smrg		         pSiS->ChipFlags |= SiSCF_IsM650;
487072b676d7Smrg		         break;
487172b676d7Smrg		   }
487272b676d7Smrg		} else {
487372b676d7Smrg		   pSiS->hasTwoOverlays = TRUE;
487472b676d7Smrg		   pSiS->SiS_SD_Flags |= SiS_SD_SUPPORT2OVL;
487572b676d7Smrg		   switch(CR5F) {
487672b676d7Smrg		      case 0x90:
487772b676d7Smrg			 inSISIDXREG(SISCR, 0x5c, tempreg1);
487872b676d7Smrg			 tempreg1 &= 0xf8;
487972b676d7Smrg			 switch(tempreg1) {
488072b676d7Smrg			    case 0x00:
488172b676d7Smrg			       pSiS->ChipFlags |= SiSCF_IsM652;
488272b676d7Smrg			       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
488372b676d7Smrg			           "SiSM652 revision ID %x\n", CR5F);
488472b676d7Smrg			       break;
488572b676d7Smrg			    case 0x40:
488672b676d7Smrg			       pSiS->ChipFlags |= SiSCF_IsM653;
488772b676d7Smrg			       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
488872b676d7Smrg			           "SiSM653 revision ID %x\n", CR5F);
488972b676d7Smrg			       break;
489072b676d7Smrg			    default:
489172b676d7Smrg			       pSiS->ChipFlags |= SiSCF_IsM650;
489272b676d7Smrg			       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
489372b676d7Smrg			           "SiSM650 revision ID %x\n", CR5F);
489472b676d7Smrg			       break;
489572b676d7Smrg			 }
489672b676d7Smrg			 break;
489772b676d7Smrg		      case 0xb0:
489872b676d7Smrg			 pSiS->ChipFlags |= SiSCF_Is652;
489972b676d7Smrg			 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
490072b676d7Smrg			     "SiS652 revision ID %x\n", CR5F);
490172b676d7Smrg			 break;
490272b676d7Smrg		      default:
490372b676d7Smrg			 pSiS->ChipFlags |= SiSCF_IsM650;
490472b676d7Smrg			 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
490572b676d7Smrg			     "SiSM650 revision ID %x\n", CR5F);
490672b676d7Smrg			 break;
490772b676d7Smrg		   }
490872b676d7Smrg		}
490972b676d7Smrg	     }
491072b676d7Smrg	     break;
491172b676d7Smrg	   }
491272b676d7Smrg	 case PCI_CHIP_SIS660:
491372b676d7Smrg	   {
491472b676d7Smrg	     pSiS->ChipFlags |= SiSCF_LARGEOVERLAY;
491572b676d7Smrg	     pSiS->hasTwoOverlays = TRUE;
491672b676d7Smrg	     pSiS->SiS_SD_Flags |= SiS_SD_SUPPORT2OVL;
491772b676d7Smrg	     /* 760/761:  - UMA only: one/two overlays - dotclock dependent
491872b676d7Smrg			  - UMA+LFB:  two overlays if video data in LFB
491972b676d7Smrg			  - LFB only: two overlays
492072b676d7Smrg		If UMA only: Must switch between one/two overlays on the fly (done
492172b676d7Smrg			     in PostSetMode())
492272b676d7Smrg		If LFB+UMA:  We use LFB memory only and leave UMA to an eventually
492372b676d7Smrg			     written DRI driver.
492472b676d7Smrg	      */
492572b676d7Smrg	     break;
492672b676d7Smrg	   }
492772b676d7Smrg       }
492872b676d7Smrg
492972b676d7Smrg       if(!(pSiS->SiS_SD2_Flags & SiS_SD2_NOOVERLAY)) {
493072b676d7Smrg          xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
493172b676d7Smrg		"Hardware supports %s video overlay%s\n",
493272b676d7Smrg		pSiS->hasTwoOverlays ? "two" : "one",
493372b676d7Smrg		pSiS->hasTwoOverlays ? "s" : "");
493472b676d7Smrg       }
493572b676d7Smrg
493672b676d7Smrg       if(pSiS->SiS_SD2_Flags & SiS_SD2_SUPPORT760OO) {
493772b676d7Smrg	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
493872b676d7Smrg		"\n\tDear SiS76x user, your machine is using a shared memory framebuffer.\n"
493972b676d7Smrg		  "\tDue to hardware limitations of the SiS chip in combination with the\n"
494072b676d7Smrg		  "\tAMD CPU, video overlay support is very limited on this machine. If you\n"
494172b676d7Smrg		  "\texperience flashing lines in the video and/or the graphics display\n"
494272b676d7Smrg		  "\tduring video playback, reduce the color depth and/or the resolution\n"
494372b676d7Smrg		  "\tand/or the refresh rate. Alternatively, use the video blitter.\n");
494472b676d7Smrg       }
494572b676d7Smrg
494672b676d7Smrg    }
494772b676d7Smrg
494872b676d7Smrg    /* Backup VB connection and CRT1 on/off register */
494972b676d7Smrg    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
495072b676d7Smrg       inSISIDXREG(SISSR, 0x1f, pSiS->oldSR1F);
495172b676d7Smrg       inSISIDXREG(SISCR, 0x17, pSiS->oldCR17);
495272b676d7Smrg       inSISIDXREG(SISCR, 0x32, pSiS->oldCR32);
495372b676d7Smrg       inSISIDXREG(SISCR, 0x36, pSiS->oldCR36);
495472b676d7Smrg       inSISIDXREG(SISCR, 0x37, pSiS->oldCR37);
495572b676d7Smrg       if(pSiS->VGAEngine == SIS_315_VGA) {
495672b676d7Smrg          inSISIDXREG(SISCR, pSiS->myCR63, pSiS->oldCR63);
495772b676d7Smrg       }
495872b676d7Smrg
495972b676d7Smrg       pSiS->postVBCR32 = pSiS->oldCR32;
496072b676d7Smrg    }
496172b676d7Smrg
496272b676d7Smrg    /* There are some machines out there which require a special
496372b676d7Smrg     * setup of the GPIO registers in order to make the Chrontel
496472b676d7Smrg     * work. Try to find out if we're running on such a machine.
496572b676d7Smrg     * Furthermore, there is some highly customized hardware,
496672b676d7Smrg     * which requires some non-standard LVDS timing. Since the
496772b676d7Smrg     * vendors don't seem to care about PCI subsystem ID's we
496872b676d7Smrg     * need to find out using the BIOS version and date strings.
496972b676d7Smrg     */
497072b676d7Smrg    pSiS->SiS_Pr->SiS_ChSW = FALSE;
497172b676d7Smrg    if(pSiS->Chipset == PCI_CHIP_SIS630) {
497272b676d7Smrg       int i = 0;
497372b676d7Smrg       do {
49741fd23544Smrg	  if(mychswtable[i].subsysVendor == PCI_SUB_VENDOR_ID(pSiS->PciInfo) &&
49751fd23544Smrg	     mychswtable[i].subsysCard == PCI_SUB_DEVICE_ID(pSiS->PciInfo)) {
497672b676d7Smrg	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
497772b676d7Smrg	         "PCI subsystem ID found in list for Chrontel/GPIO setup:\n");
497872b676d7Smrg	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
497972b676d7Smrg		 "\tVendor/Card: %s %s (ID %04x)\n",
498072b676d7Smrg		  mychswtable[i].vendorName,
498172b676d7Smrg		  mychswtable[i].cardName,
49821fd23544Smrg		  PCI_SUB_DEVICE_ID(pSiS->PciInfo));
498372b676d7Smrg	     pSiS->SiS_Pr->SiS_ChSW = TRUE;
498472b676d7Smrg	     break;
498572b676d7Smrg          }
498672b676d7Smrg          i++;
498772b676d7Smrg       } while(mychswtable[i].subsysVendor != 0);
498872b676d7Smrg    }
498972b676d7Smrg
499072b676d7Smrg    if(pSiS->SiS_Pr->SiS_CustomT == CUT_NONE) {
499172b676d7Smrg       int    i = 0, j;
499272b676d7Smrg       UShort bversptr = 0;
499372b676d7Smrg       Bool   footprint;
499472b676d7Smrg       CARD32 chksum = 0;
499572b676d7Smrg
499672b676d7Smrg       if(pSiS->SiS_Pr->UseROM) {
499772b676d7Smrg          bversptr = pSiS->BIOS[0x16] | (pSiS->BIOS[0x17] << 8);
499872b676d7Smrg          for(i=0; i<32768; i++) chksum += pSiS->BIOS[i];
499972b676d7Smrg       }
500072b676d7Smrg
500172b676d7Smrg       i = 0;
500272b676d7Smrg       do {
500372b676d7Smrg	  if( (SiS_customttable[i].chipID == pSiS->ChipType)                            &&
500472b676d7Smrg	      ((!strlen(SiS_customttable[i].biosversion)) ||
500572b676d7Smrg	       (pSiS->SiS_Pr->UseROM &&
500672b676d7Smrg	       (!strncmp(SiS_customttable[i].biosversion, (char *)&pSiS->BIOS[bversptr],
500772b676d7Smrg	                strlen(SiS_customttable[i].biosversion)))))                     &&
500872b676d7Smrg	      ((!strlen(SiS_customttable[i].biosdate)) ||
500972b676d7Smrg	       (pSiS->SiS_Pr->UseROM &&
501072b676d7Smrg	       (!strncmp(SiS_customttable[i].biosdate, (char *)&pSiS->BIOS[0x2c],
501172b676d7Smrg	                strlen(SiS_customttable[i].biosdate)))))			      &&
501272b676d7Smrg	      ((!SiS_customttable[i].bioschksum) ||
501372b676d7Smrg	       (pSiS->SiS_Pr->UseROM &&
501472b676d7Smrg	       (SiS_customttable[i].bioschksum == chksum)))			      &&
50151fd23544Smrg	      (SiS_customttable[i].pcisubsysvendor == PCI_SUB_VENDOR_ID(pSiS->PciInfo))      &&
50161fd23544Smrg	      (SiS_customttable[i].pcisubsyscard == PCI_SUB_DEVICE_ID(pSiS->PciInfo)) ) {
501772b676d7Smrg	     footprint = TRUE;
501872b676d7Smrg	     for(j=0; j<5; j++) {
501972b676d7Smrg	        if(SiS_customttable[i].biosFootprintAddr[j]) {
502072b676d7Smrg		   if(pSiS->SiS_Pr->UseROM) {
502172b676d7Smrg		      if(pSiS->BIOS[SiS_customttable[i].biosFootprintAddr[j]] !=
502272b676d7Smrg						SiS_customttable[i].biosFootprintData[j])
502372b676d7Smrg		         footprint = FALSE;
502472b676d7Smrg		   } else footprint = FALSE;
502572b676d7Smrg	        }
502672b676d7Smrg	     }
502772b676d7Smrg	     if(footprint) {
502872b676d7Smrg	        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
502972b676d7Smrg	           "Identified %s %s, special timing applies\n",
503072b676d7Smrg		   SiS_customttable[i].vendorName, SiS_customttable[i].cardName);
503172b676d7Smrg	        pSiS->SiS_Pr->SiS_CustomT = SiS_customttable[i].SpecialID;
503272b676d7Smrg	        break;
503372b676d7Smrg	     }
503472b676d7Smrg          }
503572b676d7Smrg          i++;
503672b676d7Smrg       } while(SiS_customttable[i].chipID);
503772b676d7Smrg    }
503872b676d7Smrg
503972b676d7Smrg    /* Handle ForceCRT1 option */
504072b676d7Smrg    if(pSiS->forceCRT1 != -1) {
504172b676d7Smrg       if(pSiS->forceCRT1) pSiS->CRT1off = 0;
504272b676d7Smrg       else                pSiS->CRT1off = 1;
504372b676d7Smrg    } else                 pSiS->CRT1off = -1;
504472b676d7Smrg
504572b676d7Smrg    /* Detect video bridge and sense TV/VGA2 */
504672b676d7Smrg    SISVGAPreInit(pScrn);
504772b676d7Smrg
504872b676d7Smrg    /* Detect CRT1 (via DDC1 and DDC2, hence via VGA port; regardless of LCDA) */
504972b676d7Smrg    SISCRT1PreInit(pScrn);
505072b676d7Smrg
505172b676d7Smrg    /* Detect LCD (connected via CRT2, regardless of LCDA) and LCD resolution */
505272b676d7Smrg    SISLCDPreInit(pScrn, FALSE);
505372b676d7Smrg
505472b676d7Smrg    /* LCDA only supported under these conditions: */
505572b676d7Smrg    if(pSiS->ForceCRT1Type == CRT1_LCDA) {
505672b676d7Smrg       if(!SISDetermineLCDACap(pScrn)) {
505772b676d7Smrg	  xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
505872b676d7Smrg		"Chipset/Video bridge does not support LCD-via-CRT1\n");
505972b676d7Smrg	  pSiS->ForceCRT1Type = CRT1_VGA;
506072b676d7Smrg       } else if(!(pSiS->VBFlags & CRT2_LCD)) {
506172b676d7Smrg	  xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
506272b676d7Smrg		"No digital LCD panel found, LCD-via-CRT1 disabled\n");
506372b676d7Smrg	  pSiS->ForceCRT1Type = CRT1_VGA;
506472b676d7Smrg       }
506572b676d7Smrg    }
506672b676d7Smrg
506772b676d7Smrg    /* Setup SD flags */
506872b676d7Smrg    pSiS->SiS_SD_Flags |= SiS_SD_ADDLSUPFLAG;
506972b676d7Smrg
507072b676d7Smrg    pSiS->SiS_SD2_Flags |= SiS_SD2_MERGEDUCLOCK;
507172b676d7Smrg    pSiS->SiS_SD2_Flags |= SiS_SD2_USEVBFLAGS2;
507272b676d7Smrg    pSiS->SiS_SD2_Flags |= SiS_SD2_VBINVB2ONLY;
507372b676d7Smrg    pSiS->SiS_SD2_Flags |= SiS_SD2_HAVESD34;
507472b676d7Smrg    pSiS->SiS_SD2_Flags |= SiS_SD2_NEWGAMMABRICON;
507572b676d7Smrg
507672b676d7Smrg    pSiS->SiS_SD3_Flags |= SiS_SD3_MFBALLOWOFFCL;
507772b676d7Smrg
507872b676d7Smrg    if(pSiS->VBFlags2 & VB2_VIDEOBRIDGE) {
507972b676d7Smrg       pSiS->SiS_SD2_Flags |= SiS_SD2_VIDEOBRIDGE;
508072b676d7Smrg       if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
508172b676d7Smrg	  pSiS->SiS_SD2_Flags |= ( SiS_SD2_SISBRIDGE     |
508272b676d7Smrg				   SiS_SD2_SUPPORTGAMMA2 );
508372b676d7Smrg	  if(pSiS->VBFlags2 & VB2_SISLVDSBRIDGE) {
508472b676d7Smrg	     pSiS->SiS_SD2_Flags |= ( SiS_SD2_LCDLVDS    |
508572b676d7Smrg				      SiS_SD2_SUPPORTLCD );
508672b676d7Smrg	  } else if(pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) {
508772b676d7Smrg	     if(!(pSiS->VBFlags2 & VB2_30xBDH)) {
508872b676d7Smrg		pSiS->SiS_SD2_Flags |= ( SiS_SD2_LCDTMDS    |
508972b676d7Smrg					 SiS_SD2_SUPPORTLCD );
509072b676d7Smrg	     } else if(pSiS->VBFlags & CRT2_LCD) {
509172b676d7Smrg		pSiS->SiS_SD2_Flags |= ( SiS_SD2_THIRDPARTYLVDS |
509272b676d7Smrg				         SiS_SD2_SUPPORTLCD );
509372b676d7Smrg	     }
509472b676d7Smrg	  }
509572b676d7Smrg       } else if(pSiS->VBFlags2 & VB2_LVDS) {
509672b676d7Smrg	  pSiS->SiS_SD2_Flags |= ( SiS_SD2_THIRDPARTYLVDS |
509772b676d7Smrg				   SiS_SD2_SUPPORTLCD );
509872b676d7Smrg       }
509972b676d7Smrg
510072b676d7Smrg       if(pSiS->VBFlags2 & (VB2_SISTVBRIDGE | VB2_CHRONTEL)) {
510172b676d7Smrg	  pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTTV;
510272b676d7Smrg	  if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
510372b676d7Smrg	     pSiS->SiS_SD2_Flags |= ( SiS_SD2_SUPPORTTVTYPE |
510472b676d7Smrg				      SiS_SD2_SUPPORTTVSIZE );
510572b676d7Smrg	     if(!(pSiS->VBFlags2 & VB2_301)) {
510672b676d7Smrg		pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPTVSAT;
510772b676d7Smrg	     } else {
510872b676d7Smrg		pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPTVEDGE;
510972b676d7Smrg	     }
511072b676d7Smrg	  }
511172b676d7Smrg       }
511272b676d7Smrg    }
511372b676d7Smrg
511472b676d7Smrg#ifdef ENABLE_YPBPR
511572b676d7Smrg    if((pSiS->VGAEngine == SIS_315_VGA) &&
511672b676d7Smrg       (pSiS->VBFlags2 & VB2_SISYPBPRBRIDGE)) {
511772b676d7Smrg       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTYPBPR;
511872b676d7Smrg       pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORT625I;
511972b676d7Smrg       pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORT625P;
512072b676d7Smrg       if(pSiS->VBFlags2 & VB2_SISYPBPRARBRIDGE) {
512172b676d7Smrg          pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTYPBPRAR;
512272b676d7Smrg       }
512372b676d7Smrg    }
512472b676d7Smrg    if(pSiS->VBFlags2 & VB2_SISHIVISIONBRIDGE) {
512572b676d7Smrg       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTHIVISION;
512672b676d7Smrg    }
512772b676d7Smrg#endif
512872b676d7Smrg
512972b676d7Smrg    if((pSiS->VGAEngine != SIS_300_VGA) || (!(pSiS->VBFlags2 & VB2_TRUMPION))) {
513072b676d7Smrg       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTSCALE;
513172b676d7Smrg       if((pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) &&
513272b676d7Smrg          (!(pSiS->VBFlags2 & VB2_30xBDH))) {
513372b676d7Smrg          pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTCENTER;
513472b676d7Smrg       }
513572b676d7Smrg    }
513672b676d7Smrg
513772b676d7Smrg#ifdef SISDUALHEAD
513872b676d7Smrg    if(!pSiS->DualHeadMode) {
513972b676d7Smrg       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTREDETECT;
514072b676d7Smrg    }
514172b676d7Smrg#endif
514272b676d7Smrg
514372b676d7Smrg#ifndef SISCHECKOSSSE
514472b676d7Smrg    pSiS->SiS_SD2_Flags |= SiS_SD2_NEEDUSESSE;
514572b676d7Smrg#endif
514672b676d7Smrg
514772b676d7Smrg#ifdef TWDEBUG	/* FOR TESTING */
514872b676d7Smrg    pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTYPBPRAR;
514972b676d7Smrg    xf86DrvMsg(0, X_INFO, "TEST: Support Aspect Ratio\n");
515072b676d7Smrg#endif
515172b676d7Smrg
515272b676d7Smrg    /* Detect CRT2-TV and PAL/NTSC mode */
515372b676d7Smrg    SISTVPreInit(pScrn, FALSE);
515472b676d7Smrg
515572b676d7Smrg    /* Detect CRT2-VGA */
515672b676d7Smrg    SISCRT2PreInit(pScrn, FALSE);
515772b676d7Smrg
515872b676d7Smrg    /* Backup detected CRT2 devices */
515972b676d7Smrg    SISSaveDetectedDevices(pScrn);
516072b676d7Smrg
516172b676d7Smrg    if(!(pSiS->SiS_SD_Flags & SiS_SD_SUPPORTYPBPR)) {
516272b676d7Smrg       if((pSiS->ForceTVType != -1) && (pSiS->ForceTVType & TV_YPBPR)) {
516372b676d7Smrg	  pSiS->ForceTVType = -1;
516472b676d7Smrg	  xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "YPbPr TV output not supported\n");
516572b676d7Smrg       }
516672b676d7Smrg    }
516772b676d7Smrg
516872b676d7Smrg    if(!(pSiS->SiS_SD_Flags & SiS_SD_SUPPORTHIVISION)) {
516972b676d7Smrg       if((pSiS->ForceTVType != -1) && (pSiS->ForceTVType & TV_HIVISION)) {
517072b676d7Smrg	  pSiS->ForceTVType = -1;
517172b676d7Smrg	  xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "HiVision TV output not supported\n");
517272b676d7Smrg       }
517372b676d7Smrg    }
517472b676d7Smrg
517572b676d7Smrg    if((pSiS->VBFlags2 & VB2_SISTVBRIDGE) ||
517672b676d7Smrg       ((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->ChrontelType == CHRONTEL_701x))) {
517772b676d7Smrg       pSiS->SiS_SD_Flags |= (SiS_SD_SUPPORTPALMN | SiS_SD_SUPPORTNTSCJ);
517872b676d7Smrg    }
517972b676d7Smrg    if((pSiS->VBFlags2 & VB2_SISTVBRIDGE) ||
518072b676d7Smrg       ((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->ChrontelType == CHRONTEL_700x))) {
518172b676d7Smrg       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTTVPOS;
518272b676d7Smrg    }
518372b676d7Smrg    if(pSiS->VBFlags2 & VB2_SISVGA2BRIDGE) {
518472b676d7Smrg       pSiS->SiS_SD_Flags |= (SiS_SD_SUPPORTSCART | SiS_SD_SUPPORTVGA2);
518572b676d7Smrg    }
518672b676d7Smrg    if(pSiS->VBFlags2 & VB2_CHRONTEL) {
518772b676d7Smrg       pSiS->SiS_SD_Flags  |= SiS_SD_SUPPORTOVERSCAN;
518872b676d7Smrg       pSiS->SiS_SD2_Flags |= SiS_SD2_CHRONTEL;
518972b676d7Smrg       if(pSiS->ChrontelType == CHRONTEL_700x) {
519072b676d7Smrg	  pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTSOVER;
519172b676d7Smrg       }
519272b676d7Smrg    }
519372b676d7Smrg
519472b676d7Smrg    /* Determine if chipset LCDA-capable */
519572b676d7Smrg    pSiS->SiS_SD_Flags &= ~SiS_SD_SUPPORTLCDA;
519672b676d7Smrg    if(SISDetermineLCDACap(pScrn)) {
519772b676d7Smrg       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTLCDA;
519872b676d7Smrg    }
519972b676d7Smrg
520072b676d7Smrg    /* Default to LCDA if LCD detected and
520172b676d7Smrg     * - TV detected (hence default to LCDA+TV), or
520272b676d7Smrg     * - in single head mode, on LCD panels with xres > 1600
520372b676d7Smrg     *   (Don't do this in MergedFB or DHM; LCDA and CRT1/VGA
520472b676d7Smrg     *   are mutually exclusive; if no TV is detected, the
520572b676d7Smrg     *   code below will default to VGA+LCD, so LCD is driven
520672b676d7Smrg     *   via CRT2.)
520772b676d7Smrg     *   (TODO: This might need some modification for the
520872b676d7Smrg     *   307 bridges, if these are capable of driving
520972b676d7Smrg     *   LCDs > 1600 via channel B)
521072b676d7Smrg     */
521172b676d7Smrg    if((pSiS->SiS_SD_Flags & SiS_SD_SUPPORTLCDA) &&
521272b676d7Smrg       (pSiS->VBFlags & CRT2_LCD) &&
521372b676d7Smrg       (pSiS->SiS_Pr->SiS_CustomT != CUT_UNKNOWNLCD)) {
521472b676d7Smrg       if((!pSiS->CRT1TypeForced) && (pSiS->ForceCRT2Type == CRT2_DEFAULT)) {
521572b676d7Smrg	  if(pSiS->VBFlags & CRT2_TV) {
521672b676d7Smrg	     /* If both LCD and TV present, default to LCDA+TV */
521772b676d7Smrg	     pSiS->ForceCRT1Type = CRT1_LCDA;
521872b676d7Smrg	     pSiS->ForceCRT2Type = CRT2_TV;
521972b676d7Smrg	  } else if(pSiS->LCDwidth > 1600) {
522072b676d7Smrg	     /* If LCD is > 1600, default to LCDA if we don't need CRT1/VGA for other head */
522172b676d7Smrg	     Bool NeedCRT1VGA = FALSE;
522272b676d7Smrg#ifdef SISDUALHEAD
522372b676d7Smrg	     if(pSiS->DualHeadMode) NeedCRT1VGA = TRUE;
522472b676d7Smrg#endif
522572b676d7Smrg#ifdef SISMERGED
522672b676d7Smrg	     if(pSiS->MergedFB &&
522772b676d7Smrg		(!pSiS->MergedFBAuto || pSiS->CRT1Detected)) NeedCRT1VGA = TRUE;
522872b676d7Smrg#endif
522972b676d7Smrg	     if(!NeedCRT1VGA) {
523072b676d7Smrg		pSiS->ForceCRT1Type = CRT1_LCDA;
523172b676d7Smrg	     }
523272b676d7Smrg	  }
523372b676d7Smrg       }
523472b676d7Smrg    }
523572b676d7Smrg
523672b676d7Smrg    /* Set up pseudo-panel if LCDA forced on TMDS bridges */
523772b676d7Smrg    if(pSiS->SiS_SD_Flags & SiS_SD_SUPPORTLCDA) {
523872b676d7Smrg       if(pSiS->ForceCRT1Type == CRT1_LCDA) {
523972b676d7Smrg          if(pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE) {
524072b676d7Smrg	     if(!(pSiS->VBLCDFlags)) {
524172b676d7Smrg		SiSSetupPseudoPanel(pScrn);
524272b676d7Smrg		pSiS->detectedCRT2Devices |= CRT2_LCD;
524372b676d7Smrg	     }
524472b676d7Smrg	  } else if(!(pSiS->VBLCDFlags)) {
524572b676d7Smrg	     pSiS->ForceCRT1Type = CRT1_VGA;
524672b676d7Smrg	  }
524772b676d7Smrg       }
524872b676d7Smrg    } else {
524972b676d7Smrg       pSiS->ForceCRT1Type = CRT1_VGA;
525072b676d7Smrg    }
525172b676d7Smrg
525272b676d7Smrg    pSiS->VBFlags |= pSiS->ForceCRT1Type;
525372b676d7Smrg
525472b676d7Smrg#ifdef TWDEBUG
525572b676d7Smrg    xf86DrvMsg(0, X_INFO, "SDFlags %lx\n", pSiS->SiS_SD_Flags);
525672b676d7Smrg#endif
525772b676d7Smrg
525872b676d7Smrg    /* Eventually overrule detected CRT2 type
525972b676d7Smrg     * If no type forced, use the detected devices in the order TV->LCD->VGA2
526072b676d7Smrg     * Since the Chrontel 7005 sometimes delivers wrong detection results,
526172b676d7Smrg     * we use a different order on such machines (LCD->TV)
526272b676d7Smrg     */
526372b676d7Smrg    if(pSiS->ForceCRT2Type == CRT2_DEFAULT) {
526472b676d7Smrg       if((pSiS->VBFlags & CRT2_TV) && (!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VGAEngine == SIS_300_VGA))))
526572b676d7Smrg	  pSiS->ForceCRT2Type = CRT2_TV;
526672b676d7Smrg       else if((pSiS->VBFlags & CRT2_LCD) && (pSiS->ForceCRT1Type == CRT1_VGA))
526772b676d7Smrg	  pSiS->ForceCRT2Type = CRT2_LCD;
526872b676d7Smrg       else if(pSiS->VBFlags & CRT2_TV)
526972b676d7Smrg	  pSiS->ForceCRT2Type = CRT2_TV;
527072b676d7Smrg       else if((pSiS->VBFlags & CRT2_VGA) && (pSiS->ForceCRT1Type == CRT1_VGA))
527172b676d7Smrg	  pSiS->ForceCRT2Type = CRT2_VGA;
527272b676d7Smrg    }
527372b676d7Smrg
527472b676d7Smrg    switch(pSiS->ForceCRT2Type) {
527572b676d7Smrg       case CRT2_TV:
527672b676d7Smrg	  pSiS->VBFlags &= ~(CRT2_LCD | CRT2_VGA);
527772b676d7Smrg	  if(pSiS->VBFlags2 & (VB2_SISTVBRIDGE | VB2_CHRONTEL)) {
527872b676d7Smrg	     pSiS->VBFlags |= CRT2_TV;
527972b676d7Smrg	  } else {
528072b676d7Smrg	     pSiS->VBFlags &= ~(CRT2_TV);
528172b676d7Smrg	     xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
528272b676d7Smrg		"Hardware does not support TV output\n");
528372b676d7Smrg	  }
528472b676d7Smrg	  break;
528572b676d7Smrg       case CRT2_LCD:
528672b676d7Smrg	  pSiS->VBFlags &= ~(CRT2_TV | CRT2_VGA);
528772b676d7Smrg	  if((pSiS->VBFlags2 & VB2_VIDEOBRIDGE) && (pSiS->VBLCDFlags)) {
528872b676d7Smrg	     pSiS->VBFlags |= CRT2_LCD;
528972b676d7Smrg	  } else if((pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) && (!(pSiS->VBFlags2 & VB2_30xBDH))) {
529072b676d7Smrg	     SiSSetupPseudoPanel(pScrn);
529172b676d7Smrg	     pSiS->detectedCRT2Devices |= CRT2_LCD;
529272b676d7Smrg	  } else {
529372b676d7Smrg	     pSiS->VBFlags &= ~(CRT2_LCD);
529472b676d7Smrg	     xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
529572b676d7Smrg		"Can't force CRT2 to LCD, no LCD detected\n");
529672b676d7Smrg	  }
529772b676d7Smrg	  break;
529872b676d7Smrg       case CRT2_VGA:
529972b676d7Smrg	  pSiS->VBFlags &= ~(CRT2_TV | CRT2_LCD);
530072b676d7Smrg	  if(pSiS->VBFlags2 & VB2_SISVGA2BRIDGE) {
530172b676d7Smrg	     pSiS->VBFlags |= CRT2_VGA;
530272b676d7Smrg	  } else {
530372b676d7Smrg	     pSiS->VBFlags &= ~(CRT2_VGA);
530472b676d7Smrg	     xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
530572b676d7Smrg		 "Hardware does not support secondary VGA\n");
530672b676d7Smrg	  }
530772b676d7Smrg	  break;
530872b676d7Smrg       default:
530972b676d7Smrg	  pSiS->VBFlags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
531072b676d7Smrg    }
531172b676d7Smrg
531272b676d7Smrg    /* Setup gamma (the cmap layer needs this to be initialised) */
531372b676d7Smrg    /* (Do this after evaluating options) */
531472b676d7Smrg    {
531572b676d7Smrg       Gamma zeros = {0.0, 0.0, 0.0};
531672b676d7Smrg       xf86SetGamma(pScrn, zeros);
531772b676d7Smrg    }
531872b676d7Smrg
531972b676d7Smrg#ifdef SISDUALHEAD
532072b676d7Smrg    if((!pSiS->DualHeadMode) || (pSiS->SecondHead)) {
532172b676d7Smrg#endif
532272b676d7Smrg       xf86DrvMsg(pScrn->scrnIndex, pSiS->CRT1gammaGiven ? X_CONFIG : X_INFO,
532372b676d7Smrg	     "%samma correction is %s\n",
532472b676d7Smrg	     (pSiS->VBFlags2 & VB2_VIDEOBRIDGE) ? "CRT1 g" : "G",
532572b676d7Smrg	     pSiS->CRT1gamma ? "enabled" : "disabled");
532672b676d7Smrg
532772b676d7Smrg       if((pSiS->VGAEngine == SIS_315_VGA)	&&
532872b676d7Smrg          (!(pSiS->NoXvideo))			&&
532972b676d7Smrg	  (!(pSiS->SiS_SD2_Flags & SiS_SD2_NOOVERLAY))) {
533072b676d7Smrg	  xf86DrvMsg(pScrn->scrnIndex, pSiS->XvGammaGiven ? X_CONFIG : X_INFO,
533172b676d7Smrg		"Separate Xv gamma correction %sis %s\n",
533272b676d7Smrg		(pSiS->VBFlags2 & VB2_VIDEOBRIDGE) ? "for CRT1 " : "",
533372b676d7Smrg		pSiS->XvGamma ? "enabled" : "disabled");
533472b676d7Smrg	  if(pSiS->XvGamma) {
533572b676d7Smrg	     xf86DrvMsg(pScrn->scrnIndex, pSiS->XvGammaGiven ? X_CONFIG : X_INFO,
533672b676d7Smrg		"Xv gamma correction: %.3f %.3f %.3f\n",
533772b676d7Smrg		(float)((float)pSiS->XvGammaRed / 1000),
533872b676d7Smrg		(float)((float)pSiS->XvGammaGreen / 1000),
533972b676d7Smrg		(float)((float)pSiS->XvGammaBlue / 1000));
534072b676d7Smrg	     if(!pSiS->CRT1gamma) {
534172b676d7Smrg		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
534272b676d7Smrg		   "Xv gamma correction requires %samma correction enabled\n",
534372b676d7Smrg		   (pSiS->VBFlags2 & VB2_VIDEOBRIDGE) ? "CRT1 g" : "G");
534472b676d7Smrg	     }
534572b676d7Smrg	  }
534672b676d7Smrg       }
534772b676d7Smrg#ifdef SISDUALHEAD
534872b676d7Smrg    }
534972b676d7Smrg#endif
535072b676d7Smrg
535172b676d7Smrg#ifdef SISDUALHEAD
535272b676d7Smrg    if(pSiS->DualHeadMode) pSiS->CRT2SepGamma = FALSE;
535372b676d7Smrg#endif
535472b676d7Smrg
535572b676d7Smrg#ifdef SISDUALHEAD
535672b676d7Smrg    if((!pSiS->DualHeadMode) || (!pSiS->SecondHead))
535772b676d7Smrg#endif
535872b676d7Smrg    {
535972b676d7Smrg       Bool isDH = FALSE;
536072b676d7Smrg       if(pSiS->CRT2gamma) {
536172b676d7Smrg          if( ((pSiS->VGAEngine != SIS_300_VGA) && (pSiS->VGAEngine != SIS_315_VGA)) ||
536272b676d7Smrg              (!(pSiS->VBFlags2 & VB2_SISBRIDGE)) ) {
536372b676d7Smrg	     if(pSiS->VBFlags2 & VB2_VIDEOBRIDGE) {
536472b676d7Smrg	        xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
536572b676d7Smrg			"CRT2 gamma correction not supported by hardware\n");
536672b676d7Smrg	     }
536772b676d7Smrg	     pSiS->CRT2gamma = pSiS->CRT2SepGamma = FALSE;
536872b676d7Smrg          } else if((pSiS->VBFlags2 & VB2_30xBDH) && (pSiS->VBFlags & CRT2_LCD)) {
536972b676d7Smrg	     isDH = TRUE;
537072b676d7Smrg	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
537172b676d7Smrg			"CRT2 gamma correction not supported for LCD\n");
537272b676d7Smrg	     /* But leave it on, will be caught in LoadPalette */
537372b676d7Smrg          }
537472b676d7Smrg       }
537572b676d7Smrg       if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
537672b676d7Smrg	  xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CRT2 gamma correction is %s%s%s\n",
537772b676d7Smrg		pSiS->CRT2gamma ? "enabled" : "disabled",
537872b676d7Smrg		isDH ? " (for TV and VGA2) " : "",
537972b676d7Smrg		pSiS->CRT2SepGamma ? " (separate from CRT1)" : "");
538072b676d7Smrg       }
538172b676d7Smrg    }
538272b676d7Smrg
538372b676d7Smrg    /* Eventually overrule TV Type (SVIDEO, COMPOSITE, SCART, HIVISION, YPBPR) */
538472b676d7Smrg    if(pSiS->VBFlags2 & VB2_SISTVBRIDGE) {
538572b676d7Smrg       if(pSiS->ForceTVType != -1) {
538672b676d7Smrg	  pSiS->VBFlags &= ~(TV_INTERFACE);
538772b676d7Smrg	  if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) {
538872b676d7Smrg	     pSiS->VBFlags &= ~(TV_CHSCART | TV_CHYPBPR525I);
538972b676d7Smrg	  }
539072b676d7Smrg	  pSiS->VBFlags |= pSiS->ForceTVType;
539172b676d7Smrg	  if(pSiS->VBFlags & TV_YPBPR) {
539272b676d7Smrg	     pSiS->VBFlags &= ~(TV_STANDARD);
539372b676d7Smrg	     pSiS->VBFlags &= ~(TV_YPBPRAR);
539472b676d7Smrg	     pSiS->VBFlags |= pSiS->ForceYPbPrType;
539572b676d7Smrg	     pSiS->VBFlags |= pSiS->ForceYPbPrAR;
539672b676d7Smrg	  }
539772b676d7Smrg       }
539872b676d7Smrg    }
539972b676d7Smrg
540072b676d7Smrg    /* Handle ForceCRT1 option (part 2) */
540172b676d7Smrg    pSiS->CRT1changed = FALSE;
540272b676d7Smrg    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
540372b676d7Smrg       usScratchCR17 = pSiS->oldCR17;
540472b676d7Smrg       usScratchCR63 = pSiS->oldCR63;
540572b676d7Smrg       usScratchSR1F = pSiS->oldSR1F;
540672b676d7Smrg       usScratchCR32 = pSiS->postVBCR32;
540772b676d7Smrg       if(pSiS->VESA != 1) {
540872b676d7Smrg          /* Copy forceCRT1 option to CRT1off if option is given */
540972b676d7Smrg#ifdef SISDUALHEAD
541072b676d7Smrg          /* In DHM, handle this option only for master head, not the slave */
541172b676d7Smrg          if( (pSiS->forceCRT1 != -1) &&
541272b676d7Smrg	       (!(pSiS->DualHeadMode && pSiS->SecondHead)) ) {
541372b676d7Smrg#else
541472b676d7Smrg          if(pSiS->forceCRT1 != -1) {
541572b676d7Smrg#endif
541672b676d7Smrg	     xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
541772b676d7Smrg		 "CRT1 detection overruled by ForceCRT1 option\n");
541872b676d7Smrg	     if(pSiS->forceCRT1) {
541972b676d7Smrg		 pSiS->CRT1off = 0;
542072b676d7Smrg		 if(pSiS->VGAEngine == SIS_300_VGA) {
542172b676d7Smrg		    if(!(usScratchCR17 & 0x80)) pSiS->CRT1changed = TRUE;
542272b676d7Smrg		 } else {
542372b676d7Smrg		    if(usScratchCR63 & 0x40) pSiS->CRT1changed = TRUE;
542472b676d7Smrg		 }
542572b676d7Smrg		 usScratchCR17 |= 0x80;
542672b676d7Smrg		 usScratchCR32 |= 0x20;
542772b676d7Smrg		 usScratchCR63 &= ~0x40;
542872b676d7Smrg		 usScratchSR1F &= ~0xc0;
542972b676d7Smrg	     } else {
543072b676d7Smrg		 if( ! ( (pScrn->bitsPerPixel == 8) &&
543172b676d7Smrg		         ( (pSiS->VBFlags2 & (VB2_LVDS | VB2_CHRONTEL)) ||
543272b676d7Smrg		           ((pSiS->VBFlags2 & VB2_30xBDH) && (pSiS->VBFlags & CRT2_LCD)) ) ) ) {
543372b676d7Smrg		    pSiS->CRT1off = 1;
543472b676d7Smrg		    if(pSiS->VGAEngine == SIS_300_VGA) {
543572b676d7Smrg		       if(usScratchCR17 & 0x80) pSiS->CRT1changed = TRUE;
543672b676d7Smrg		    } else {
543772b676d7Smrg		       if(!(usScratchCR63 & 0x40)) pSiS->CRT1changed = TRUE;
543872b676d7Smrg		    }
543972b676d7Smrg		    usScratchCR32 &= ~0x20;
544072b676d7Smrg		    /* We must not actually switch off CRT1 before we changed the mode! */
544172b676d7Smrg		 }
544272b676d7Smrg	     }
544372b676d7Smrg	     /* Here we can write to CR17 even on 315 series as we only ENABLE
544472b676d7Smrg	      * the bit here
544572b676d7Smrg	      */
544672b676d7Smrg	     outSISIDXREG(SISCR, 0x17, usScratchCR17);
544772b676d7Smrg	     if(pSiS->VGAEngine == SIS_315_VGA) {
544872b676d7Smrg		outSISIDXREG(SISCR, pSiS->myCR63, usScratchCR63);
544972b676d7Smrg	     }
545072b676d7Smrg	     outSISIDXREG(SISCR, 0x32, usScratchCR32);
545172b676d7Smrg	     if(pSiS->CRT1changed) {
545272b676d7Smrg		outSISIDXREG(SISSR, 0x00, 0x01);    /* Synchronous Reset */
545372b676d7Smrg		usleep(10000);
545472b676d7Smrg		outSISIDXREG(SISSR, 0x00, 0x03);    /* End Reset */
545572b676d7Smrg		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
545672b676d7Smrg			"CRT1 status changed by ForceCRT1 option\n");
545772b676d7Smrg	     }
545872b676d7Smrg	     outSISIDXREG(SISSR, 0x1f, usScratchSR1F);
545972b676d7Smrg          }
546072b676d7Smrg       }
546172b676d7Smrg       /* Store the new VB connection register contents for later mode changes */
546272b676d7Smrg       pSiS->newCR32 = usScratchCR32;
546372b676d7Smrg    }
546472b676d7Smrg
546572b676d7Smrg    /* Check if CRT1 used (or needed; this eg. if no CRT2 detected) */
546672b676d7Smrg    if(pSiS->VBFlags2 & VB2_VIDEOBRIDGE) {
546772b676d7Smrg
546872b676d7Smrg        /* No CRT2 output? Then we NEED CRT1!
546972b676d7Smrg	 * We also need CRT1 if depth = 8 and bridge=LVDS|301B-DH
547072b676d7Smrg	 */
547172b676d7Smrg	if( (!(pSiS->VBFlags & (CRT2_VGA | CRT2_LCD | CRT2_TV))) ||
547272b676d7Smrg	    ( (pScrn->bitsPerPixel == 8) &&
547372b676d7Smrg	      ( (pSiS->VBFlags2 & (VB2_LVDS | VB2_CHRONTEL)) ||
547472b676d7Smrg	        ((pSiS->VBFlags2 & VB2_30xBDH) && (pSiS->VBFlags & CRT2_LCD)) ) ) ) {
547572b676d7Smrg	    pSiS->CRT1off = 0;
547672b676d7Smrg	}
547772b676d7Smrg	/* No CRT2 output? Then we can't use Xv on CRT2 */
547872b676d7Smrg	if(!(pSiS->VBFlags & (CRT2_VGA | CRT2_LCD | CRT2_TV))) {
547972b676d7Smrg	    pSiS->XvOnCRT2 = FALSE;
548072b676d7Smrg	}
548172b676d7Smrg
548272b676d7Smrg    } else { /* no video bridge? */
548372b676d7Smrg	/* Then we NEED CRT1... */
548472b676d7Smrg	pSiS->CRT1off = 0;
548572b676d7Smrg	/* ... and can't use CRT2 for Xv output */
548672b676d7Smrg	pSiS->XvOnCRT2 = FALSE;
548772b676d7Smrg    }
548872b676d7Smrg
548972b676d7Smrg    /* LCDA? Then we don't switch off CRT1 */
549072b676d7Smrg    if(pSiS->VBFlags & CRT1_LCDA) pSiS->CRT1off = 0;
549172b676d7Smrg
549272b676d7Smrg    /* Handle TVStandard option */
549372b676d7Smrg    if((pSiS->NonDefaultPAL != -1) || (pSiS->NonDefaultNTSC != -1)) {
549472b676d7Smrg       if( (!(pSiS->VBFlags2 & VB2_SISTVBRIDGE)) &&
549572b676d7Smrg	   (!((pSiS->VBFlags2 & VB2_CHRONTEL)) && (pSiS->ChrontelType == CHRONTEL_701x)) ) {
549672b676d7Smrg	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
549772b676d7Smrg	   	"PALM, PALN and NTSCJ not supported on this hardware\n");
549872b676d7Smrg	  pSiS->NonDefaultPAL = pSiS->NonDefaultNTSC = -1;
549972b676d7Smrg	  pSiS->VBFlags &= ~(TV_PALN | TV_PALM | TV_NTSCJ);
550072b676d7Smrg	  pSiS->SiS_SD_Flags &= ~(SiS_SD_SUPPORTPALMN | SiS_SD_SUPPORTNTSCJ);
550172b676d7Smrg       }
550272b676d7Smrg    }
550372b676d7Smrg    if(pSiS->OptTVStand != -1) {
550472b676d7Smrg       if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
550572b676d7Smrg	  if( (!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & (TV_CHSCART | TV_CHYPBPR525I)))) &&
550672b676d7Smrg	      (!(pSiS->VBFlags & (TV_HIVISION | TV_YPBPR))) ) {
550772b676d7Smrg	     pSiS->VBFlags &= ~(TV_PAL | TV_NTSC | TV_PALN | TV_PALM | TV_NTSCJ);
550872b676d7Smrg	     if(pSiS->OptTVStand) {
550972b676d7Smrg	        pSiS->VBFlags |= TV_PAL;
551072b676d7Smrg	        if(pSiS->NonDefaultPAL == 1)  pSiS->VBFlags |= TV_PALM;
551172b676d7Smrg	        else if(!pSiS->NonDefaultPAL) pSiS->VBFlags |= TV_PALN;
551272b676d7Smrg	     } else {
551372b676d7Smrg	        pSiS->VBFlags |= TV_NTSC;
551472b676d7Smrg		if(pSiS->NonDefaultNTSC == 1) pSiS->VBFlags |= TV_NTSCJ;
551572b676d7Smrg	     }
551672b676d7Smrg	  } else {
551772b676d7Smrg	     pSiS->OptTVStand = pSiS->NonDefaultPAL = -1;
551872b676d7Smrg	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
551972b676d7Smrg	    	 "Option TVStandard ignored for YPbPr, HiVision and Chrontel-SCART\n");
552072b676d7Smrg	  }
552172b676d7Smrg       } else if(pSiS->Chipset == PCI_CHIP_SIS6326) {
552272b676d7Smrg	  pSiS->SiS6326Flags &= ~SIS6326_TVPAL;
552372b676d7Smrg	  if(pSiS->OptTVStand) pSiS->SiS6326Flags |= SIS6326_TVPAL;
552472b676d7Smrg       }
552572b676d7Smrg    }
552672b676d7Smrg
552772b676d7Smrg    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
552872b676d7Smrg       /* Default to PAL */
552972b676d7Smrg       if(pSiS->VBFlags & (TV_SVIDEO | TV_AVIDEO)) {
553072b676d7Smrg          if(!(pSiS->VBFlags & (TV_PAL | TV_NTSC))) {
553172b676d7Smrg	     pSiS->VBFlags &= ~(TV_PAL | TV_NTSC | TV_PALN | TV_PALM | TV_NTSCJ);
553272b676d7Smrg	     pSiS->VBFlags |= TV_PAL;
553372b676d7Smrg	  }
553472b676d7Smrg       }
553572b676d7Smrg       /* SCART only supported for PAL */
553672b676d7Smrg       if((pSiS->VBFlags2 & VB2_SISBRIDGE) && (pSiS->VBFlags & TV_SCART)) {
553772b676d7Smrg	  pSiS->VBFlags &= ~(TV_NTSC | TV_PALN | TV_PALM | TV_NTSCJ);
553872b676d7Smrg	  pSiS->VBFlags |= TV_PAL;
553972b676d7Smrg	  pSiS->OptTVStand = 1;
554072b676d7Smrg	  pSiS->NonDefaultPAL = pSiS->NonDefaultNTSC = -1;
554172b676d7Smrg       }
554272b676d7Smrg    }
554372b676d7Smrg
554472b676d7Smrg#ifdef SIS_CP
554572b676d7Smrg    SIS_CP_DRIVER_RECONFIGOPT
554672b676d7Smrg#endif
554772b676d7Smrg
554872b676d7Smrg    if((pSiS->Chipset == PCI_CHIP_SIS6326) && (pSiS->SiS6326Flags & SIS6326_HASTV)) {
554972b676d7Smrg       if(pSiS->sis6326tvplug != -1) {
555072b676d7Smrg          pSiS->SiS6326Flags &= ~(SIS6326_TVSVIDEO | SIS6326_TVCVBS);
555172b676d7Smrg	  pSiS->SiS6326Flags |= SIS6326_TVDETECTED;
555272b676d7Smrg	  if(pSiS->sis6326tvplug == 1) 	pSiS->SiS6326Flags |= SIS6326_TVCVBS;
555372b676d7Smrg	  else 				pSiS->SiS6326Flags |= SIS6326_TVSVIDEO;
555472b676d7Smrg	  xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
555572b676d7Smrg	      "SiS6326 TV plug type detection overruled by %s\n",
555672b676d7Smrg	      (pSiS->SiS6326Flags & SIS6326_TVCVBS) ? "COMPOSITE" : "SVIDEO");
555772b676d7Smrg       }
555872b676d7Smrg    }
555972b676d7Smrg
556072b676d7Smrg    /* Do some checks */
556172b676d7Smrg    if(pSiS->OptTVOver != -1) {
556272b676d7Smrg       if(pSiS->VBFlags2 & VB2_CHRONTEL) {
556372b676d7Smrg	  pSiS->UseCHOverScan = pSiS->OptTVOver;
556472b676d7Smrg       } else {
556572b676d7Smrg	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
556672b676d7Smrg	      "CHTVOverscan only supported on CHRONTEL 70xx\n");
556772b676d7Smrg	  pSiS->UseCHOverScan = -1;
556872b676d7Smrg       }
556972b676d7Smrg    } else pSiS->UseCHOverScan = -1;
557072b676d7Smrg
557172b676d7Smrg    if(pSiS->sistvedgeenhance != -1) {
557272b676d7Smrg       if(!(pSiS->VBFlags2 & VB2_301)) {
557372b676d7Smrg	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
557472b676d7Smrg	      "SISTVEdgeEnhance only supported on SiS301\n");
557572b676d7Smrg	  pSiS->sistvedgeenhance = -1;
557672b676d7Smrg       }
557772b676d7Smrg    }
557872b676d7Smrg    if(pSiS->sistvsaturation != -1) {
557972b676d7Smrg       if(pSiS->VBFlags2 & VB2_301) {
558072b676d7Smrg	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
558172b676d7Smrg	      "SISTVSaturation not supported on SiS301\n");
558272b676d7Smrg	  pSiS->sistvsaturation = -1;
558372b676d7Smrg       }
558472b676d7Smrg    }
558572b676d7Smrg
558672b676d7Smrg    /* Do some MergedFB mode initialisation */
558772b676d7Smrg#ifdef SISMERGED
558872b676d7Smrg    if(pSiS->MergedFB) {
55895788ca14Smrg       pSiS->CRT2pScrn = malloc(sizeof(ScrnInfoRec));
559072b676d7Smrg       if(!pSiS->CRT2pScrn) {
559172b676d7Smrg          SISErrorLog(pScrn, "Failed to allocate memory for 2nd pScrn, %s\n", mergeddisstr);
559272b676d7Smrg	  pSiS->MergedFB = FALSE;
559372b676d7Smrg       } else {
559472b676d7Smrg          memcpy(pSiS->CRT2pScrn, pScrn, sizeof(ScrnInfoRec));
559572b676d7Smrg       }
559672b676d7Smrg    }
559772b676d7Smrg#endif
559872b676d7Smrg
559972b676d7Smrg    /* Determine CRT1<>CRT2 mode
560072b676d7Smrg     *     Note: When using VESA or if the bridge is in slavemode, display
560172b676d7Smrg     *           is ALWAYS in MIRROR_MODE!
560272b676d7Smrg     *           This requires extra checks in functions using this flag!
560372b676d7Smrg     *           (see sis_video.c for example)
560472b676d7Smrg     */
560572b676d7Smrg    if(pSiS->VBFlags & DISPTYPE_DISP2) {
560672b676d7Smrg        if(pSiS->CRT1off) {	/* CRT2 only ------------------------------- */
560772b676d7Smrg#ifdef SISDUALHEAD
560872b676d7Smrg	     if(pSiS->DualHeadMode) {
560972b676d7Smrg		SISErrorLog(pScrn,
561072b676d7Smrg		    "CRT1 not detected or forced off. Dual Head mode can't initialize.\n");
561172b676d7Smrg		if(pSiSEnt) pSiSEnt->DisableDual = TRUE;
561272b676d7Smrg		goto my_error_1;
561372b676d7Smrg	     }
561472b676d7Smrg#endif
561572b676d7Smrg#ifdef SISMERGED
561672b676d7Smrg	     if(pSiS->MergedFB) {
561772b676d7Smrg		if(pSiS->MergedFBAuto) {
561872b676d7Smrg		   xf86DrvMsg(pScrn->scrnIndex, X_INFO, mergednocrt1, mergeddisstr);
561972b676d7Smrg		} else {
562072b676d7Smrg		   SISErrorLog(pScrn, mergednocrt1, mergeddisstr);
562172b676d7Smrg		}
56225788ca14Smrg		if(pSiS->CRT2pScrn) free(pSiS->CRT2pScrn);
562372b676d7Smrg		pSiS->CRT2pScrn = NULL;
562472b676d7Smrg		pSiS->MergedFB = FALSE;
562572b676d7Smrg	     }
562672b676d7Smrg#endif
562772b676d7Smrg	     pSiS->VBFlags |= VB_DISPMODE_SINGLE;
562872b676d7Smrg	     /* No CRT1? Then we use the video overlay on CRT2 */
562972b676d7Smrg	     pSiS->XvOnCRT2 = TRUE;
563072b676d7Smrg	} else			/* CRT1 and CRT2 - mirror or dual head ----- */
563172b676d7Smrg#ifdef SISDUALHEAD
563272b676d7Smrg	     if(pSiS->DualHeadMode) {
563372b676d7Smrg		pSiS->VBFlags |= (VB_DISPMODE_DUAL | DISPTYPE_CRT1);
563472b676d7Smrg		if(pSiS->VESA != -1) {
563572b676d7Smrg		    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
563672b676d7Smrg			"VESA option not used in Dual Head mode. VESA disabled.\n");
563772b676d7Smrg		}
563872b676d7Smrg		if(pSiSEnt) pSiSEnt->DisableDual = FALSE;
563972b676d7Smrg		pSiS->VESA = 0;
564072b676d7Smrg	     } else
564172b676d7Smrg#endif
564272b676d7Smrg#ifdef SISMERGED
564372b676d7Smrg		    if(pSiS->MergedFB) {
564472b676d7Smrg		 pSiS->VBFlags |= (VB_DISPMODE_MIRROR | DISPTYPE_CRT1);
564572b676d7Smrg		 if(pSiS->VESA != -1) {
564672b676d7Smrg		    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
564772b676d7Smrg			"VESA option not used in MergedFB mode. VESA disabled.\n");
564872b676d7Smrg		 }
564972b676d7Smrg		 pSiS->VESA = 0;
565072b676d7Smrg	     } else
565172b676d7Smrg#endif
565272b676d7Smrg		 pSiS->VBFlags |= (VB_DISPMODE_MIRROR | DISPTYPE_CRT1);
565372b676d7Smrg    } else {			/* CRT1 only ------------------------------- */
565472b676d7Smrg#ifdef SISDUALHEAD
565572b676d7Smrg	     if(pSiS->DualHeadMode) {
565672b676d7Smrg		SISErrorLog(pScrn,
565772b676d7Smrg		   "No CRT2 output selected or no bridge detected. "
565872b676d7Smrg		   "Dual Head mode can't initialize.\n");
565972b676d7Smrg		goto my_error_1;
566072b676d7Smrg	     }
566172b676d7Smrg#endif
566272b676d7Smrg#ifdef SISMERGED
566372b676d7Smrg	     if(pSiS->MergedFB) {
566472b676d7Smrg		if(pSiS->MergedFBAuto) {
566572b676d7Smrg		   xf86DrvMsg(pScrn->scrnIndex, X_INFO, mergednocrt2, mergeddisstr);
566672b676d7Smrg		} else {
566772b676d7Smrg		   SISErrorLog(pScrn, mergednocrt2, mergeddisstr);
566872b676d7Smrg		}
56695788ca14Smrg		if(pSiS->CRT2pScrn) free(pSiS->CRT2pScrn);
567072b676d7Smrg		pSiS->CRT2pScrn = NULL;
567172b676d7Smrg		pSiS->MergedFB = FALSE;
567272b676d7Smrg	     }
567372b676d7Smrg#endif
567472b676d7Smrg             pSiS->VBFlags |= (VB_DISPMODE_SINGLE | DISPTYPE_CRT1);
567572b676d7Smrg    }
567672b676d7Smrg
567772b676d7Smrg    if((pSiS->VGAEngine == SIS_315_VGA) || (pSiS->VGAEngine == SIS_300_VGA)) {
567872b676d7Smrg       if((!pSiS->NoXvideo)		&&
567972b676d7Smrg          (!pSiS->hasTwoOverlays)	&&
568072b676d7Smrg	  (!(pSiS->SiS_SD2_Flags & SiS_SD2_NOOVERLAY))) {
568172b676d7Smrg	  xf86DrvMsg(pScrn->scrnIndex, from,
568272b676d7Smrg	      "Using Xv overlay by default on CRT%d\n",
568372b676d7Smrg	      pSiS->XvOnCRT2 ? 2 : 1);
568472b676d7Smrg       }
568572b676d7Smrg    }
568672b676d7Smrg
568772b676d7Smrg    /* Init ptrs for Save/Restore functions and calc MaxClock */
568872b676d7Smrg    SISDACPreInit(pScrn);
568972b676d7Smrg
569072b676d7Smrg    /* ********** end of VBFlags setup ********** */
569172b676d7Smrg
569272b676d7Smrg    /* VBFlags are initialized now. Back them up for SlaveMode modes. */
569372b676d7Smrg    pSiS->VBFlags_backup = pSiS->VBFlags;
569472b676d7Smrg
569572b676d7Smrg    /* Backup CR32,36,37 (in order to write them back after a VT switch) */
569672b676d7Smrg    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
569772b676d7Smrg       inSISIDXREG(SISCR,0x32,pSiS->myCR32);
569872b676d7Smrg       inSISIDXREG(SISCR,0x36,pSiS->myCR36);
569972b676d7Smrg       inSISIDXREG(SISCR,0x37,pSiS->myCR37);
570072b676d7Smrg    }
570172b676d7Smrg
570272b676d7Smrg    /* Find out about paneldelaycompensation and evaluate option */
570372b676d7Smrg#ifdef SISDUALHEAD
570472b676d7Smrg    if((!pSiS->DualHeadMode) || (!pSiS->SecondHead)) {
570572b676d7Smrg#endif
570672b676d7Smrg       if(pSiS->VGAEngine == SIS_300_VGA) {
570772b676d7Smrg
570872b676d7Smrg          if(pSiS->VBFlags2 & (VB2_LVDS | VB2_30xBDH)) {
570972b676d7Smrg
571072b676d7Smrg	     /* Save the current PDC if the panel is used at the moment.
571172b676d7Smrg	      * This seems by far the safest way to find out about it.
571272b676d7Smrg	      * If the system is using an old version of sisfb, we can't
571372b676d7Smrg	      * trust the pdc register value. If sisfb saved the pdc for
571472b676d7Smrg	      * us, use it.
571572b676d7Smrg	      */
571672b676d7Smrg	     if(pSiS->sisfbpdc != 0xff) {
571772b676d7Smrg	        pSiS->SiS_Pr->PDC = pSiS->sisfbpdc;
571872b676d7Smrg	     } else {
571972b676d7Smrg	        if(!(pSiS->donttrustpdc)) {
572072b676d7Smrg	           UChar tmp;
572172b676d7Smrg	           inSISIDXREG(SISCR, 0x30, tmp);
572272b676d7Smrg	           if(tmp & 0x20) {
572372b676d7Smrg	              inSISIDXREG(SISPART1, 0x13, pSiS->SiS_Pr->PDC);
572472b676d7Smrg                   } else {
572572b676d7Smrg	             xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
572672b676d7Smrg		          "Unable to detect LCD PanelDelayCompensation, LCD is not active\n");
572772b676d7Smrg	           }
572872b676d7Smrg	        } else {
572972b676d7Smrg	           xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
573072b676d7Smrg		        "Unable to detect LCD PanelDelayCompensation, please update sisfb\n");
573172b676d7Smrg	        }
573272b676d7Smrg	     }
573372b676d7Smrg	     if(pSiS->SiS_Pr->PDC != -1) {
573472b676d7Smrg	        pSiS->SiS_Pr->PDC &= 0x3c;
573572b676d7Smrg	        xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
573672b676d7Smrg		     "Detected LCD PanelDelayCompensation 0x%02x\n",
573772b676d7Smrg		     pSiS->SiS_Pr->PDC);
573872b676d7Smrg	     }
573972b676d7Smrg
574072b676d7Smrg	     /* If we haven't been able to find out, use our other methods */
574172b676d7Smrg	     if(pSiS->SiS_Pr->PDC == -1) {
574272b676d7Smrg		int i=0;
574372b676d7Smrg		do {
57441fd23544Smrg		   if(mypdctable[i].subsysVendor == PCI_SUB_VENDOR_ID(pSiS->PciInfo) &&
57451fd23544Smrg		      mypdctable[i].subsysCard == PCI_SUB_DEVICE_ID(pSiS->PciInfo)) {
574672b676d7Smrg			 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
574772b676d7Smrg			    "PCI card/vendor identified for non-default PanelDelayCompensation\n");
574872b676d7Smrg			 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
574972b676d7Smrg			     "Vendor: %s, card: %s (ID %04x), PanelDelayCompensation: 0x%02x\n",
575072b676d7Smrg			     mypdctable[i].vendorName, mypdctable[i].cardName,
57511fd23544Smrg			     PCI_SUB_DEVICE_ID(pSiS->PciInfo), mypdctable[i].pdc);
575272b676d7Smrg			 if(pSiS->PDC == -1) {
575372b676d7Smrg			    pSiS->PDC = mypdctable[i].pdc;
575472b676d7Smrg			 } else {
575572b676d7Smrg			    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
575672b676d7Smrg				"PanelDelayCompensation overruled by option\n");
575772b676d7Smrg			 }
575872b676d7Smrg			 break;
575972b676d7Smrg		   }
576072b676d7Smrg		   i++;
576172b676d7Smrg		} while(mypdctable[i].subsysVendor != 0);
576272b676d7Smrg	     }
576372b676d7Smrg
576472b676d7Smrg	     if(pSiS->PDC != -1) {
576572b676d7Smrg		if(pSiS->BIOS) {
576672b676d7Smrg		   if(pSiS->VBFlags2 & VB2_LVDS) {
576772b676d7Smrg		      if(pSiS->BIOS[0x220] & 0x80) {
576872b676d7Smrg			 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
576972b676d7Smrg			     "BIOS uses OEM LCD Panel Delay Compensation 0x%02x\n",
577072b676d7Smrg			     pSiS->BIOS[0x220] & 0x3c);
577172b676d7Smrg			 pSiS->BIOS[0x220] &= 0x7f;
577272b676d7Smrg		      }
577372b676d7Smrg		   }
577472b676d7Smrg		   if(pSiS->VBFlags2 & (VB2_301B | VB2_302B)) {
577572b676d7Smrg		      if(pSiS->BIOS[0x220] & 0x80) {
577672b676d7Smrg			 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
577772b676d7Smrg			     "BIOS uses OEM LCD Panel Delay Compensation 0x%02x\n",
577872b676d7Smrg			       (  (pSiS->VBLCDFlags & VB_LCD_1280x1024) ?
577972b676d7Smrg			                 pSiS->BIOS[0x223] : pSiS->BIOS[0x224]  ) & 0x3c);
578072b676d7Smrg			 pSiS->BIOS[0x220] &= 0x7f;
578172b676d7Smrg		      }
578272b676d7Smrg		   }
578372b676d7Smrg		}
578472b676d7Smrg		pSiS->SiS_Pr->PDC = (pSiS->PDC & 0x3c);
578572b676d7Smrg		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
578672b676d7Smrg		      "Using LCD Panel Delay Compensation 0x%02x\n", pSiS->SiS_Pr->PDC);
578772b676d7Smrg	     }
578872b676d7Smrg	  }
578972b676d7Smrg
579072b676d7Smrg       }  /* SIS_300_VGA */
579172b676d7Smrg
579272b676d7Smrg       if(pSiS->VGAEngine == SIS_315_VGA) {
579372b676d7Smrg
579472b676d7Smrg	  UChar tmp, tmp2;
579572b676d7Smrg	  inSISIDXREG(SISCR, 0x30, tmp);
579672b676d7Smrg
579772b676d7Smrg	  /* Save the current PDC if the panel is used at the moment. */
579872b676d7Smrg	  if(pSiS->VBFlags2 & VB2_SISLVDSBRIDGE) {
579972b676d7Smrg
580072b676d7Smrg	     if(pSiS->sisfbpdc != 0xff) {
580172b676d7Smrg	        pSiS->SiS_Pr->PDC = pSiS->sisfbpdc;
580272b676d7Smrg	     }
580372b676d7Smrg	     if(pSiS->sisfbpdca != 0xff) {
580472b676d7Smrg	        pSiS->SiS_Pr->PDCA = pSiS->sisfbpdca;
580572b676d7Smrg	     }
580672b676d7Smrg
580772b676d7Smrg	     if(!pSiS->donttrustpdc) {
580872b676d7Smrg	        if((pSiS->sisfbpdc == 0xff) && (pSiS->sisfbpdca == 0xff)) {
580972b676d7Smrg		   CARD16 tempa, tempb;
581072b676d7Smrg		   inSISIDXREG(SISPART1,0x2d,tmp2);
581172b676d7Smrg		   tempa = (tmp2 & 0xf0) >> 3;
581272b676d7Smrg		   tempb = (tmp2 & 0x0f) << 1;
581372b676d7Smrg		   inSISIDXREG(SISPART1,0x20,tmp2);
581472b676d7Smrg		   tempa |= ((tmp2 & 0x40) >> 6);
581572b676d7Smrg		   inSISIDXREG(SISPART1,0x35,tmp2);
581672b676d7Smrg		   tempb |= ((tmp2 & 0x80) >> 7);
581772b676d7Smrg		   inSISIDXREG(SISPART1,0x13,tmp2);
581872b676d7Smrg		   if(!pSiS->ROM661New) {
581972b676d7Smrg		      if((tmp2 & 0x04) || (tmp & 0x20)) {
582072b676d7Smrg		         pSiS->SiS_Pr->PDCA = tempa;
582172b676d7Smrg		         pSiS->SiS_Pr->PDC  = tempb;
582272b676d7Smrg		      } else {
582372b676d7Smrg			 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
582472b676d7Smrg			     "Unable to detect PanelDelayCompensation, LCD is not active\n");
582572b676d7Smrg		      }
582672b676d7Smrg		   } else {
582772b676d7Smrg		      if(tmp2 & 0x04) {
582872b676d7Smrg		         pSiS->SiS_Pr->PDCA = tempa;
582972b676d7Smrg		      } else if(tmp & 0x20) {
583072b676d7Smrg		         pSiS->SiS_Pr->PDC  = tempb;
583172b676d7Smrg		      } else {
583272b676d7Smrg			 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
583372b676d7Smrg			     "Unable to detect PanelDelayCompensation, LCD is not active\n");
583472b676d7Smrg		      }
583572b676d7Smrg		   }
583672b676d7Smrg		}
583772b676d7Smrg	     } else {
583872b676d7Smrg		xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
583972b676d7Smrg		    "Unable to detect PanelDelayCompensation, please update sisfb\n");
584072b676d7Smrg	     }
584172b676d7Smrg	     if(pSiS->SiS_Pr->PDC != -1) {
584272b676d7Smrg		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
584372b676d7Smrg		     "Detected LCD PanelDelayCompensation 0x%02x (for LCD=CRT2)\n",
584472b676d7Smrg		     pSiS->SiS_Pr->PDC);
584572b676d7Smrg	     }
584672b676d7Smrg	     if(pSiS->SiS_Pr->PDCA != -1) {
584772b676d7Smrg		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
584872b676d7Smrg		     "Detected LCD PanelDelayCompensation1 0x%02x (for LCD=CRT1)\n",
584972b676d7Smrg		     pSiS->SiS_Pr->PDCA);
585072b676d7Smrg	     }
585172b676d7Smrg	  }
585272b676d7Smrg
585372b676d7Smrg	  /* Let user override (for all bridges) */
585472b676d7Smrg	  if(pSiS->VBFlags2 & VB2_30xBLV) {
585572b676d7Smrg	     if(pSiS->PDC != -1) {
585672b676d7Smrg	        pSiS->SiS_Pr->PDC = pSiS->PDC & 0x1f;
585772b676d7Smrg		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
585872b676d7Smrg		     "Using LCD PanelDelayCompensation 0x%02x (for LCD=CRT2)\n",
585972b676d7Smrg		     pSiS->SiS_Pr->PDC);
586072b676d7Smrg	     }
586172b676d7Smrg	     if(pSiS->PDCA != -1) {
586272b676d7Smrg		pSiS->SiS_Pr->PDCA = pSiS->PDCA & 0x1f;
586372b676d7Smrg		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
586472b676d7Smrg		     "Using LCD PanelDelayCompensation1 0x%02x (for LCD=CRT1)\n",
586572b676d7Smrg		     pSiS->SiS_Pr->PDCA);
586672b676d7Smrg	     }
586772b676d7Smrg          }
586872b676d7Smrg
586972b676d7Smrg 	  /* Read the current EMI (if not overruled) */
587072b676d7Smrg	  if(pSiS->VBFlags2 & VB2_SISEMIBRIDGE) {
587172b676d7Smrg	     MessageType from = X_PROBED;
587272b676d7Smrg	     if(pSiS->EMI != -1) {
587372b676d7Smrg		pSiS->SiS_Pr->EMI_30 = (pSiS->EMI >> 24) & 0x60;
587472b676d7Smrg		pSiS->SiS_Pr->EMI_31 = (pSiS->EMI >> 16) & 0xff;
587572b676d7Smrg		pSiS->SiS_Pr->EMI_32 = (pSiS->EMI >> 8)  & 0xff;
587672b676d7Smrg		pSiS->SiS_Pr->EMI_33 = pSiS->EMI & 0xff;
587772b676d7Smrg		pSiS->SiS_Pr->HaveEMI = pSiS->SiS_Pr->HaveEMILCD = TRUE;
587872b676d7Smrg		pSiS->SiS_Pr->OverruleEMI = TRUE;
587972b676d7Smrg		from = X_CONFIG;
588072b676d7Smrg	     } else if((pSiS->sisfbfound) && (pSiS->sisfb_haveemi)) {
588172b676d7Smrg		pSiS->SiS_Pr->EMI_30 = pSiS->sisfb_emi30;
588272b676d7Smrg		pSiS->SiS_Pr->EMI_31 = pSiS->sisfb_emi31;
588372b676d7Smrg		pSiS->SiS_Pr->EMI_32 = pSiS->sisfb_emi32;
588472b676d7Smrg		pSiS->SiS_Pr->EMI_33 = pSiS->sisfb_emi33;
588572b676d7Smrg		pSiS->SiS_Pr->HaveEMI = TRUE;
588672b676d7Smrg		if(pSiS->sisfb_haveemilcd) pSiS->SiS_Pr->HaveEMILCD = TRUE;
588772b676d7Smrg		pSiS->SiS_Pr->OverruleEMI = FALSE;
588872b676d7Smrg	     } else {
588972b676d7Smrg		inSISIDXREG(SISPART4, 0x30, pSiS->SiS_Pr->EMI_30);
589072b676d7Smrg		inSISIDXREG(SISPART4, 0x31, pSiS->SiS_Pr->EMI_31);
589172b676d7Smrg		inSISIDXREG(SISPART4, 0x32, pSiS->SiS_Pr->EMI_32);
589272b676d7Smrg		inSISIDXREG(SISPART4, 0x33, pSiS->SiS_Pr->EMI_33);
589372b676d7Smrg		pSiS->SiS_Pr->HaveEMI = TRUE;
589472b676d7Smrg		if(tmp & 0x20) pSiS->SiS_Pr->HaveEMILCD = TRUE;
589572b676d7Smrg		pSiS->SiS_Pr->OverruleEMI = FALSE;
589672b676d7Smrg	     }
589772b676d7Smrg	     xf86DrvMsg(pScrn->scrnIndex, from,
589872b676d7Smrg		   "302LV/302ELV: Using EMI 0x%02x%02x%02x%02x%s\n",
589972b676d7Smrg		   pSiS->SiS_Pr->EMI_30,pSiS->SiS_Pr->EMI_31,
590072b676d7Smrg		   pSiS->SiS_Pr->EMI_32,pSiS->SiS_Pr->EMI_33,
590172b676d7Smrg		   pSiS->SiS_Pr->HaveEMILCD ? " (LCD)" : "");
590272b676d7Smrg	  }
590372b676d7Smrg
590472b676d7Smrg       } /* SIS_315_VGA */
590572b676d7Smrg#ifdef SISDUALHEAD
590672b676d7Smrg    }
590772b676d7Smrg#endif
590872b676d7Smrg
590972b676d7Smrg
591072b676d7Smrg    /* In dual head mode, both heads (currently) share the maxxfbmem equally.
591172b676d7Smrg     * If memory sharing is done differently, the following has to be changed;
591272b676d7Smrg     * the other modules (eg. accel and Xv) use dhmOffset for hardware
591372b676d7Smrg     * pointer settings relative to VideoRAM start and won't need to be changed.
591472b676d7Smrg     *
591572b676d7Smrg     * Addendum: dhmoffset is also used for skipping the UMA area on SiS76x.
591672b676d7Smrg     */
591772b676d7Smrg
591872b676d7Smrg    pSiS->dhmOffset = pSiS->FbBaseOffset;
591972b676d7Smrg    pSiS->FbAddress += pSiS->dhmOffset;
592072b676d7Smrg
592172b676d7Smrg#ifdef SISDUALHEAD
592272b676d7Smrg    if(pSiS->DualHeadMode) {
592372b676d7Smrg       pSiS->FbAddress = pSiS->realFbAddress;
592472b676d7Smrg       if(!pSiS->SecondHead) {
592572b676d7Smrg	  /* ===== First head (always CRT2) ===== */
592672b676d7Smrg	  /* We use only half of the memory available */
592772b676d7Smrg	  pSiS->maxxfbmem /= 2;
592872b676d7Smrg	  /* dhmOffset is 0 (or LFB-base for SiS76x UMA skipping) */
592972b676d7Smrg	  pSiS->FbAddress += pSiS->dhmOffset;
593072b676d7Smrg	  xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
593172b676d7Smrg	      "%dKB video RAM at 0x%lx available for master head (CRT2)\n",
593272b676d7Smrg	      pSiS->maxxfbmem/1024, pSiS->FbAddress);
593372b676d7Smrg       } else {
593472b676d7Smrg	  /* ===== Second head (always CRT1) ===== */
593572b676d7Smrg	  /* We use only half of the memory available */
593672b676d7Smrg	  pSiS->maxxfbmem /= 2;
593772b676d7Smrg	  /* Initialize dhmOffset */
593872b676d7Smrg	  pSiS->dhmOffset += pSiS->maxxfbmem;
593972b676d7Smrg	  /* Adapt FBAddress */
594072b676d7Smrg	  pSiS->FbAddress += pSiS->dhmOffset;
594172b676d7Smrg	  xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
594272b676d7Smrg	     "%dKB video RAM at 0x%lx available for slave head (CRT1)\n",
594372b676d7Smrg	     pSiS->maxxfbmem/1024,  pSiS->FbAddress);
594472b676d7Smrg       }
594572b676d7Smrg    }
594672b676d7Smrg#endif
594772b676d7Smrg
594872b676d7Smrg    /* Note: Do not use availMem for anything from now. Use
594972b676d7Smrg     * maxxfbmem instead. (availMem does not take dual head
595072b676d7Smrg     * mode into account.)
595172b676d7Smrg     */
595272b676d7Smrg
595372b676d7Smrg    if(pSiS->FbBaseOffset) {
595472b676d7Smrg       /* Doubt that the DRM memory manager can deal
595572b676d7Smrg        * with a heap start of 0...
595672b676d7Smrg	*/
595772b676d7Smrg       pSiS->DRIheapstart = 16;
595872b676d7Smrg       pSiS->DRIheapend = pSiS->FbBaseOffset;
595972b676d7Smrg    } else {
596072b676d7Smrg       pSiS->DRIheapstart = pSiS->maxxfbmem;
596172b676d7Smrg       pSiS->DRIheapend = pSiS->availMem;
596272b676d7Smrg    }
596372b676d7Smrg#ifdef SISDUALHEAD
596472b676d7Smrg    if(pSiS->DualHeadMode) {
596572b676d7Smrg       pSiS->DRIheapstart = pSiS->DRIheapend = 0;
596672b676d7Smrg    } else
596772b676d7Smrg#endif
596872b676d7Smrg           if(pSiS->DRIheapstart >= pSiS->DRIheapend) {
596972b676d7Smrg#if 0  /* For future use */
597072b676d7Smrg       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
597172b676d7Smrg	  "No memory for DRI heap. Please set the option \"MaxXFBMem\" to\n"
597272b676d7Smrg	  "\tlimit the memory X should use and leave the rest to DRI\n");
597372b676d7Smrg#endif
597472b676d7Smrg       pSiS->DRIheapstart = pSiS->DRIheapend = 0;
597572b676d7Smrg    }
597672b676d7Smrg
597772b676d7Smrg    /* Now for something completely different: DDC.
597872b676d7Smrg     * For 300 and 315/330/340 series, we provide our
597972b676d7Smrg     * own functions (in order to probe CRT2 as well)
598072b676d7Smrg     * If these fail, use the VBE.
598172b676d7Smrg     * All other chipsets will use VBE. No need to re-invent
598272b676d7Smrg     * the wheel there.
598372b676d7Smrg     */
598472b676d7Smrg
598572b676d7Smrg    pSiS->pVbe = NULL;
598672b676d7Smrg    didddc2 = FALSE;
598772b676d7Smrg
598872b676d7Smrg    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
598972b676d7Smrg       if(xf86LoadSubModule(pScrn, "ddc")) {
599072b676d7Smrg	  int crtnum = 0;
599172b676d7Smrg	  if((pMonitor = SiSDoPrivateDDC(pScrn, &crtnum))) {
599272b676d7Smrg	     didddc2 = TRUE;
599372b676d7Smrg	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED, ddcsstr, crtnum);
599472b676d7Smrg	     xf86PrintEDID(pMonitor);
599572b676d7Smrg	     xf86SetDDCproperties(pScrn, pMonitor);
599672b676d7Smrg	     pScrn->monitor->DDC = pMonitor;
599772b676d7Smrg	     /* Now try to find out aspect ratio */
599872b676d7Smrg	     SiSFindAspect(pScrn, pMonitor, crtnum);
599972b676d7Smrg	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED, ddcestr, crtnum);
600072b676d7Smrg	  }
600172b676d7Smrg       }
600272b676d7Smrg    }
600372b676d7Smrg
600472b676d7Smrg#ifdef SISDUALHEAD
600572b676d7Smrg    /* In dual head mode, probe DDC using VBE only for CRT1 (second head) */
600672b676d7Smrg    if((pSiS->DualHeadMode) && (!didddc2) && (!pSiS->SecondHead)) {
600772b676d7Smrg       didddc2 = TRUE;
600872b676d7Smrg    }
600972b676d7Smrg#endif
601072b676d7Smrg
601172b676d7Smrg    if(!didddc2) {
601272b676d7Smrg       /* If CRT1 is off or LCDA, skip DDC via VBE */
601372b676d7Smrg       if((pSiS->CRT1off) || (pSiS->VBFlags & CRT1_LCDA)) {
601472b676d7Smrg          didddc2 = TRUE;
601572b676d7Smrg       }
601672b676d7Smrg    }
601772b676d7Smrg
601872b676d7Smrg    /* Now (re-)load and initialize the DDC module */
601972b676d7Smrg    if(!didddc2) {
602072b676d7Smrg
602172b676d7Smrg       if(xf86LoadSubModule(pScrn, "ddc")) {
602272b676d7Smrg
602372b676d7Smrg	  /* Now load and initialize VBE module. */
602472b676d7Smrg	  SiS_LoadInitVBE(pScrn);
602572b676d7Smrg
602672b676d7Smrg	  if(pSiS->pVbe) {
602772b676d7Smrg	     if((pMonitor = vbeDoEDID(pSiS->pVbe,NULL))) {
602872b676d7Smrg		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
602972b676d7Smrg		      "VBE CRT1 DDC monitor info:\n");
603072b676d7Smrg		xf86SetDDCproperties(pScrn, xf86PrintEDID(pMonitor));
603172b676d7Smrg		pScrn->monitor->DDC = pMonitor;
603272b676d7Smrg		/* Now try to find out aspect ratio */
603372b676d7Smrg		SiSFindAspect(pScrn, pMonitor, 1);
603472b676d7Smrg		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
603572b676d7Smrg		      "End of VBE CRT1 DDC monitor info\n");
603672b676d7Smrg	     }
603772b676d7Smrg	  } else {
603872b676d7Smrg	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
603972b676d7Smrg		 "Failed to read DDC data\n");
604072b676d7Smrg	  }
604172b676d7Smrg       }
604272b676d7Smrg    }
604372b676d7Smrg
604472b676d7Smrg#ifdef SISMERGED
604572b676d7Smrg    if(pSiS->MergedFB) {
60465788ca14Smrg       pSiS->CRT2pScrn->monitor = malloc(sizeof(MonRec));
604772b676d7Smrg       if(pSiS->CRT2pScrn->monitor) {
604872b676d7Smrg	  DisplayModePtr tempm = NULL, currentm = NULL, newm = NULL;
604972b676d7Smrg	  memcpy(pSiS->CRT2pScrn->monitor, pScrn->monitor, sizeof(MonRec));
605072b676d7Smrg	  pSiS->CRT2pScrn->monitor->DDC = NULL;
605172b676d7Smrg	  pSiS->CRT2pScrn->monitor->Modes = NULL;
605272b676d7Smrg	  pSiS->CRT2pScrn->monitor->id = (char *)crt2monname;
605372b676d7Smrg	  tempm = pScrn->monitor->Modes;
605472b676d7Smrg	  while(tempm) {
60555788ca14Smrg	     if(!(newm = malloc(sizeof(DisplayModeRec)))) break;
605672b676d7Smrg	     memcpy(newm, tempm, sizeof(DisplayModeRec));
60575788ca14Smrg	     if(!(newm->name = malloc(strlen(tempm->name) + 1))) {
60585788ca14Smrg	        free(newm);
605972b676d7Smrg		break;
606072b676d7Smrg	     }
606172b676d7Smrg	     strcpy(newm->name, tempm->name);
606272b676d7Smrg	     if(!pSiS->CRT2pScrn->monitor->Modes) pSiS->CRT2pScrn->monitor->Modes = newm;
606372b676d7Smrg	     if(currentm) {
606472b676d7Smrg	        currentm->next = newm;
606572b676d7Smrg		newm->prev = currentm;
606672b676d7Smrg	     }
606772b676d7Smrg	     currentm = newm;
606872b676d7Smrg	     tempm = tempm->next;
606972b676d7Smrg	  }
607072b676d7Smrg	  if(pSiS->CRT2HSync) {
607172b676d7Smrg	     pSiS->CRT2pScrn->monitor->nHsync =
607272b676d7Smrg		SiSStrToRanges(pSiS->CRT2pScrn->monitor->hsync, pSiS->CRT2HSync, MAX_HSYNC);
607372b676d7Smrg	  }
607472b676d7Smrg	  if(pSiS->CRT2VRefresh) {
607572b676d7Smrg	     pSiS->CRT2pScrn->monitor->nVrefresh =
607672b676d7Smrg		SiSStrToRanges(pSiS->CRT2pScrn->monitor->vrefresh, pSiS->CRT2VRefresh, MAX_VREFRESH);
607772b676d7Smrg	  }
607872b676d7Smrg	  if((pMonitor = SiSInternalDDC(pSiS->CRT2pScrn, 1))) {
607972b676d7Smrg	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED, ddcsstr, 2);
608072b676d7Smrg	     xf86PrintEDID(pMonitor);
608172b676d7Smrg	     xf86SetDDCproperties(pSiS->CRT2pScrn, pMonitor);
608272b676d7Smrg	     pSiS->CRT2pScrn->monitor->DDC = pMonitor;
608372b676d7Smrg	     /* Now try to find out aspect ratio */
608472b676d7Smrg	     SiSFindAspect(pScrn, pMonitor, 2);
608572b676d7Smrg	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED, ddcestr, 2);
608672b676d7Smrg	     /* use DDC data if no ranges in config file */
608772b676d7Smrg	     if(!pSiS->CRT2HSync) {
608872b676d7Smrg	        pSiS->CRT2pScrn->monitor->nHsync = 0;
608972b676d7Smrg	     }
609072b676d7Smrg	     if(!pSiS->CRT2VRefresh) {
609172b676d7Smrg	        pSiS->CRT2pScrn->monitor->nVrefresh = 0;
609272b676d7Smrg	     }
609372b676d7Smrg	  } else {
609472b676d7Smrg	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
609572b676d7Smrg		"Failed to read DDC data for CRT2\n");
609672b676d7Smrg	  }
609772b676d7Smrg       } else {
609872b676d7Smrg	  SISErrorLog(pScrn, "Failed to allocate memory for CRT2 monitor, %s.\n",
609972b676d7Smrg	  		mergeddisstr);
61005788ca14Smrg	  if(pSiS->CRT2pScrn) free(pSiS->CRT2pScrn);
610172b676d7Smrg	  pSiS->CRT2pScrn = NULL;
610272b676d7Smrg	  pSiS->MergedFB = FALSE;
610372b676d7Smrg       }
610472b676d7Smrg    }
610572b676d7Smrg#endif
610672b676d7Smrg
610772b676d7Smrg    /* Copy our detected monitor gammas, part 1. Note that device redetection
610872b676d7Smrg     * is not supported in DHM, so there is no need to do that anytime later.
610972b676d7Smrg     */
611072b676d7Smrg#ifdef SISDUALHEAD
611172b676d7Smrg    if(pSiS->DualHeadMode) {
611272b676d7Smrg       if(!pSiS->SecondHead) {
611372b676d7Smrg          /* CRT2: Got gamma for LCD or VGA2 */
611472b676d7Smrg	  pSiSEnt->CRT2VGAMonitorGamma = pSiS->CRT2VGAMonitorGamma;
611572b676d7Smrg       } else {
611672b676d7Smrg          /* CRT1: Got gamma for LCD or VGA */
611772b676d7Smrg	  pSiSEnt->CRT1VGAMonitorGamma = pSiS->CRT1VGAMonitorGamma;
611872b676d7Smrg       }
611972b676d7Smrg       if(pSiS->CRT2LCDMonitorGamma) pSiSEnt->CRT2LCDMonitorGamma = pSiS->CRT2LCDMonitorGamma;
612072b676d7Smrg    }
612172b676d7Smrg#endif
612272b676d7Smrg
612372b676d7Smrg    /* end of DDC */
612472b676d7Smrg
612572b676d7Smrg    /* From here, we mainly deal with clocks and modes */
612672b676d7Smrg
612772b676d7Smrg#ifdef SISMERGED
612872b676d7Smrg    if(pSiS->MergedFB) xf86DrvMsg(pScrn->scrnIndex, X_INFO, crtsetupstr, 1);
612972b676d7Smrg#endif
613072b676d7Smrg
613172b676d7Smrg    /* Set the min pixel clock */
613272b676d7Smrg    pSiS->MinClock = 5000;
613372b676d7Smrg    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
613472b676d7Smrg       pSiS->MinClock = 10000;
613572b676d7Smrg    }
613672b676d7Smrg    xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "Min pixel clock is %d MHz\n",
613772b676d7Smrg                pSiS->MinClock / 1000);
613872b676d7Smrg
613972b676d7Smrg    /* If the user has specified ramdac speed in the config
614072b676d7Smrg     * file, we respect that setting.
614172b676d7Smrg     */
614272b676d7Smrg    from = X_PROBED;
614372b676d7Smrg    if(pSiS->pEnt->device->dacSpeeds[0]) {
614472b676d7Smrg       int speed = 0;
614572b676d7Smrg       switch(pScrn->bitsPerPixel) {
614672b676d7Smrg       case 8:  speed = pSiS->pEnt->device->dacSpeeds[DAC_BPP8];
614772b676d7Smrg                break;
614872b676d7Smrg       case 16: speed = pSiS->pEnt->device->dacSpeeds[DAC_BPP16];
614972b676d7Smrg                break;
615072b676d7Smrg       case 24: speed = pSiS->pEnt->device->dacSpeeds[DAC_BPP24];
615172b676d7Smrg                break;
615272b676d7Smrg       case 32: speed = pSiS->pEnt->device->dacSpeeds[DAC_BPP32];
615372b676d7Smrg                break;
615472b676d7Smrg       }
615572b676d7Smrg       if(speed == 0) pSiS->MaxClock = pSiS->pEnt->device->dacSpeeds[0];
615672b676d7Smrg       else           pSiS->MaxClock = speed;
615772b676d7Smrg       from = X_CONFIG;
615872b676d7Smrg    }
615972b676d7Smrg    xf86DrvMsg(pScrn->scrnIndex, from, "Max pixel clock is %d MHz\n",
616072b676d7Smrg                pSiS->MaxClock / 1000);
616172b676d7Smrg
616272b676d7Smrg    /*
616372b676d7Smrg     * Setup the ClockRanges, which describe what clock ranges are available,
616472b676d7Smrg     * and what sort of modes they can be used for.
616572b676d7Smrg     */
616672b676d7Smrg    clockRanges = xnfcalloc(sizeof(ClockRange), 1);
616772b676d7Smrg    clockRanges->next = NULL;
616872b676d7Smrg    clockRanges->minClock = pSiS->MinClock;
616972b676d7Smrg    clockRanges->maxClock = pSiS->MaxClock;
617072b676d7Smrg    clockRanges->clockIndex = -1;               /* programmable */
617172b676d7Smrg    clockRanges->interlaceAllowed = TRUE;
617272b676d7Smrg    clockRanges->doubleScanAllowed = TRUE;
617372b676d7Smrg
617472b676d7Smrg    /*
617572b676d7Smrg     * Since we have lots of built-in modes for 300/315/330/340 series
617672b676d7Smrg     * with vb support, we replace the given default mode list with our
617772b676d7Smrg     * own. In case the video bridge is to be used, we only allow other
617872b676d7Smrg     * modes if
617972b676d7Smrg     *   -) vbtype is 301, 301B, 301C or 302B, and
618072b676d7Smrg     *   -) crt2 device is not TV, and
618172b676d7Smrg     *   -) crt1 is not LCDA, unless bridge is TMDS/LCDA capable (301C)
618272b676d7Smrg     */
618372b676d7Smrg    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
618472b676d7Smrg       if(!(pSiS->noInternalModes)) {
618572b676d7Smrg          Bool acceptcustommodes = TRUE;  /* Accept user modelines */
618672b676d7Smrg	  Bool includelcdmodes   = TRUE;  /* Include modes reported by DDC */
618772b676d7Smrg	  Bool isfordvi          = FALSE; /* Is for digital DVI output */
618872b676d7Smrg	  Bool fakecrt2modes     = FALSE; /* Fake some modes for CRT2 */
618972b676d7Smrg	  Bool IsForCRT2	 = FALSE;
619072b676d7Smrg	  if(pSiS->UseVESA) {
619172b676d7Smrg	     acceptcustommodes = FALSE;
619272b676d7Smrg	     includelcdmodes   = FALSE;
619372b676d7Smrg	  }
619472b676d7Smrg#ifdef SISDUALHEAD  /* Dual head is static. Output devices will not change. */
619572b676d7Smrg	  if(pSiS->DualHeadMode) {
619672b676d7Smrg	     if(!pSiS->SecondHead) {  /* CRT2: */
619772b676d7Smrg	        if(pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) {
619872b676d7Smrg		   if(!(pSiS->VBFlags2 & VB2_30xBDH)) {
619972b676d7Smrg		      if(!(pSiS->VBFlags & (CRT2_LCD|CRT2_VGA))) includelcdmodes   = FALSE;
620072b676d7Smrg		      if(pSiS->VBFlags & CRT2_LCD)               isfordvi          = TRUE;
620172b676d7Smrg		      if(pSiS->VBFlags & CRT2_TV)                acceptcustommodes = FALSE;
620272b676d7Smrg		   } else {
620372b676d7Smrg		      if(pSiS->VBFlags & (CRT2_TV|CRT2_LCD)) {
620472b676d7Smrg		         acceptcustommodes = FALSE;
620572b676d7Smrg		         includelcdmodes   = FALSE;
620672b676d7Smrg			 fakecrt2modes = TRUE;
620772b676d7Smrg		      }
620872b676d7Smrg		   }
620972b676d7Smrg		} else {
621072b676d7Smrg		   acceptcustommodes = FALSE;
621172b676d7Smrg		   includelcdmodes   = FALSE;
621272b676d7Smrg		   if(pSiS->VBFlags & (CRT2_TV|CRT2_LCD)) {
621372b676d7Smrg		      fakecrt2modes = TRUE;
621472b676d7Smrg		   }
621572b676d7Smrg		}
621672b676d7Smrg		clockRanges->interlaceAllowed = FALSE;
621772b676d7Smrg		IsForCRT2 = TRUE;
621872b676d7Smrg	     } else {		/* CRT1: */
621972b676d7Smrg	        if(pSiS->VBFlags & CRT1_LCDA) {
622072b676d7Smrg		   if(!(pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE)) {
622172b676d7Smrg		      acceptcustommodes = FALSE;
622272b676d7Smrg		      includelcdmodes   = FALSE;
622372b676d7Smrg		      fakecrt2modes     = TRUE;
622472b676d7Smrg		      /* Will handle i-lace in mode-switching code */
622572b676d7Smrg		   } else {
622672b676d7Smrg		      isfordvi = TRUE;
622772b676d7Smrg		      /* Don't allow i-lace modes */
622872b676d7Smrg		      clockRanges->interlaceAllowed = FALSE;
622972b676d7Smrg		   }
623072b676d7Smrg		} else {
623172b676d7Smrg		   includelcdmodes = FALSE;
623272b676d7Smrg		}
623372b676d7Smrg	     }
623472b676d7Smrg	  } else
623572b676d7Smrg#endif
623672b676d7Smrg#ifdef SISMERGED  /* MergedFB mode is not static. Output devices may change. */
623772b676d7Smrg          if(pSiS->MergedFB) {
623872b676d7Smrg	     if(pSiS->VBFlags & CRT1_LCDA) {
623972b676d7Smrg	        if(!(pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE)) {
624072b676d7Smrg		   acceptcustommodes = FALSE;
624172b676d7Smrg		   includelcdmodes   = FALSE;
624272b676d7Smrg		   fakecrt2modes     = TRUE;
624372b676d7Smrg		   /* Will handle i-lace in mode-switching code */
624472b676d7Smrg		} else {
624572b676d7Smrg		   isfordvi = TRUE;
624672b676d7Smrg		   /* Don't allow i-lace custom modes */
624772b676d7Smrg		   clockRanges->interlaceAllowed = FALSE;
624872b676d7Smrg		}
624972b676d7Smrg	     } else {
625072b676d7Smrg	        includelcdmodes = FALSE;
625172b676d7Smrg	     }
625272b676d7Smrg          } else
625372b676d7Smrg#endif		 /* Mirror mode is not static. Output devices may change. */
625472b676d7Smrg          if(pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) {
625572b676d7Smrg	     if(!(pSiS->VBFlags2 & VB2_30xBDH)) {
625672b676d7Smrg		if(!(pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE)) {
625772b676d7Smrg		   if(!(pSiS->VBFlags & (CRT2_LCD|CRT2_VGA))) includelcdmodes = FALSE;
625872b676d7Smrg		   if(pSiS->VBFlags & CRT2_LCD)               isfordvi        = TRUE;
625972b676d7Smrg		} else {
626072b676d7Smrg		   if(!(pSiS->VBFlags & (CRT2_LCD|CRT2_VGA|CRT1_LCDA))) includelcdmodes = FALSE;
626172b676d7Smrg		   if(pSiS->VBFlags & (CRT2_LCD|CRT1_LCDA))             isfordvi        = TRUE;
626272b676d7Smrg		}
626372b676d7Smrg		if((!(pSiS->VBFlags & DISPTYPE_CRT1)) && (!(pSiS->VBFlags & CRT1_LCDA))) {
626472b676d7Smrg		   IsForCRT2 = TRUE;
626572b676d7Smrg		}
626672b676d7Smrg		/* Allow user modes, even if CRT2 is TV. Will be filtered through ValidMode();
626772b676d7Smrg		 * leaving the user modes here might have the advantage that such a mode, if
626872b676d7Smrg		 * it matches in resolution with a supported TV mode, allows us to drive eg.
626972b676d7Smrg		 * non standard panels, and still permits switching to TV. This mode will be
627072b676d7Smrg		 * "mapped" to a supported mode of identical resolution for TV. All this is
627172b676d7Smrg		 * taken care of by ValidMode() and ModeInit()/PresetMode().
627272b676d7Smrg		 */
627372b676d7Smrg	     } else {
627472b676d7Smrg		if(pSiS->VBFlags & (CRT2_TV|CRT2_LCD)) {
627572b676d7Smrg		   acceptcustommodes = FALSE;
627672b676d7Smrg		   includelcdmodes   = FALSE;
627772b676d7Smrg		   if(!(pSiS->VBFlags & DISPTYPE_CRT1)) {
627872b676d7Smrg		      fakecrt2modes = TRUE;
627972b676d7Smrg		      IsForCRT2 = TRUE;
628072b676d7Smrg		   }
628172b676d7Smrg		}
628272b676d7Smrg	     }
628372b676d7Smrg	  } else if(pSiS->VBFlags & (CRT2_ENABLE | CRT1_LCDA)) {
628472b676d7Smrg	     acceptcustommodes = FALSE;
628572b676d7Smrg	     includelcdmodes   = FALSE;
628672b676d7Smrg	     if((pSiS->VBFlags & CRT1_LCDA) || (!(pSiS->VBFlags & DISPTYPE_CRT1))) {
628772b676d7Smrg		fakecrt2modes = TRUE;
628872b676d7Smrg		IsForCRT2 = TRUE;
628972b676d7Smrg	     }
629072b676d7Smrg	  } else {
629172b676d7Smrg	     includelcdmodes   = FALSE;
629272b676d7Smrg	  }
629372b676d7Smrg	  /* Ignore interlace, mode switching code will handle this */
629472b676d7Smrg
629572b676d7Smrg	  pSiS->HaveCustomModes = FALSE;
629672b676d7Smrg	  if(SiSMakeOwnModeList(pScrn, acceptcustommodes, includelcdmodes,
629772b676d7Smrg			isfordvi, &pSiS->HaveCustomModes, FALSE /*fakecrt2modes*/, IsForCRT2)) {
629872b676d7Smrg	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
629972b676d7Smrg		 "Replaced %s mode list with built-in modes\n",
630072b676d7Smrg	     pSiS->HaveCustomModes ? "default" : "entire");
630172b676d7Smrg	     if(pSiS->VGAEngine == SIS_315_VGA) {
630272b676d7Smrg		int UseWide = pSiS->SiS_Pr->SiS_UseWide;
630372b676d7Smrg		if(IsForCRT2) UseWide = pSiS->SiS_Pr->SiS_UseWideCRT2;
630472b676d7Smrg		if((!IsForCRT2) || (pSiS->VBFlags2 & VB2_SISVGA2BRIDGE)) {
630572b676d7Smrg		   xf86DrvMsg(pScrn->scrnIndex, X_INFO,
630672b676d7Smrg			"Using %s widescreen modes for CRT%d VGA devices\n",
630772b676d7Smrg			UseWide ? "real" : "fake", IsForCRT2 ? 2 : 1);
630872b676d7Smrg		   xf86DrvMsg(pScrn->scrnIndex, X_INFO,
630972b676d7Smrg			"\tUse option \"ForceCRT%dVGAAspect\" to overrule\n",
631072b676d7Smrg			IsForCRT2 ? 2 : 1);
631172b676d7Smrg		}
631272b676d7Smrg	     }
631372b676d7Smrg#ifdef TWDEBUG
631472b676d7Smrg             pScrn->modes = pScrn->monitor->Modes;
631572b676d7Smrg	     xf86PrintModes(pScrn);
631672b676d7Smrg	     pScrn->modes = NULL;
631772b676d7Smrg#endif
631872b676d7Smrg          } else {
631972b676d7Smrg	     xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
632072b676d7Smrg		"Building list of built-in modes failed, using server defaults\n");
632172b676d7Smrg	  }
632272b676d7Smrg       } else {
632372b676d7Smrg          pSiS->HaveCustomModes = TRUE;
632472b676d7Smrg       }
632572b676d7Smrg    }
632672b676d7Smrg
632772b676d7Smrg    /* Add our built-in hi-res and TV modes on the 6326 */
632872b676d7Smrg    if(pSiS->Chipset == PCI_CHIP_SIS6326) {
632972b676d7Smrg       if(pScrn->bitsPerPixel == 8) {
633072b676d7Smrg	  SiS6326SIS1600x1200_60Mode.next = pScrn->monitor->Modes;
633172b676d7Smrg	  pScrn->monitor->Modes = &SiS6326SIS1600x1200_60Mode;
633272b676d7Smrg	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
633372b676d7Smrg	  	"Adding mode \"SIS1600x1200-60\" (depth 8 only)\n");
633472b676d7Smrg       }
633572b676d7Smrg       if(pScrn->bitsPerPixel <= 16) {
633672b676d7Smrg	  SiS6326SIS1280x1024_75Mode.next = pScrn->monitor->Modes;
633772b676d7Smrg	  pScrn->monitor->Modes = &SiS6326SIS1280x1024_75Mode;
633872b676d7Smrg	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
633972b676d7Smrg	  	"Adding mode \"SIS1280x1024-75\" (depths 8, 15 and 16 only)\n");
634072b676d7Smrg       }
634172b676d7Smrg       if((pSiS->SiS6326Flags & SIS6326_HASTV) &&
634272b676d7Smrg	  (pSiS->SiS6326Flags & SIS6326_TVDETECTED)) {
634372b676d7Smrg	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
634472b676d7Smrg		"Adding %s TV modes to mode list:\n",
634572b676d7Smrg		(pSiS->SiS6326Flags & SIS6326_TVPAL) ? "PAL" : "NTSC");
634672b676d7Smrg	  if(pSiS->SiS6326Flags & SIS6326_TVPAL) {
634772b676d7Smrg	     SiS6326PAL800x600Mode.next = pScrn->monitor->Modes;
634872b676d7Smrg	     pScrn->monitor->Modes = &SiS6326PAL640x480Mode;
634972b676d7Smrg	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
635072b676d7Smrg		"\t\"PAL800x600\" \"PAL800x600U\" \"PAL720x540\" \"PAL640x480\"\n");
635172b676d7Smrg	  } else {
635272b676d7Smrg	     SiS6326NTSC640x480Mode.next = pScrn->monitor->Modes;
635372b676d7Smrg	     pScrn->monitor->Modes = &SiS6326NTSC640x400Mode;
635472b676d7Smrg	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
635572b676d7Smrg		"\t\"NTSC640x480\" \"NTSC640x480U\" \"NTSC640x400\"\n");
635672b676d7Smrg	  }
635772b676d7Smrg       }
635872b676d7Smrg    }
635972b676d7Smrg
636072b676d7Smrg   /* If there is no HSync or VRefresh data for the monitor,
636172b676d7Smrg    * derive it from DDC data. Essentially done by common layer
636272b676d7Smrg    * since 4.3.99.14, but this is not usable since it is done
636372b676d7Smrg    * too late (in ValidateModes()).
636472b676d7Smrg    * Addendum: I overrule the ranges now in any case unless
636572b676d7Smrg    * it would affect a CRT output device or DDC data is available.
636672b676d7Smrg    * Hence, for LCD(A) and TV, we always get proper ranges. This
636772b676d7Smrg    * is entirely harmless. However, option "NoOverruleRanges" will
636872b676d7Smrg    * disable this behavior.
636972b676d7Smrg    * This should "fix" the - by far - most common configuration
637072b676d7Smrg    * mistakes.
637172b676d7Smrg    */
637272b676d7Smrg
637372b676d7Smrg    crt1freqoverruled = FALSE;
637472b676d7Smrg
637572b676d7Smrg    fromDDC = FALSE;
637672b676d7Smrg    if((pScrn->monitor->nHsync <= 0) || (pSiS->OverruleRanges)) {
637772b676d7Smrg       if((pScrn->monitor->nHsync <= 0) && (pScrn->monitor->DDC)) {
637872b676d7Smrg	  SiSSetSyncRangeFromEdid(pScrn, 1);
637972b676d7Smrg	  if(pScrn->monitor->nHsync > 0) {
638072b676d7Smrg	     xf86DrvMsg(pScrn->scrnIndex, X_INFO, subshstr,
638172b676d7Smrg#ifdef SISDUALHEAD
638272b676d7Smrg			pSiS->DualHeadMode ? (pSiS->SecondHead ? 1 : 2) :
638372b676d7Smrg#endif
638472b676d7Smrg				pSiS->CRT1off ? 2 : 1);
638572b676d7Smrg	     fromDDC = TRUE;
638672b676d7Smrg	  }
638772b676d7Smrg       }
638872b676d7Smrg       if((pScrn->monitor->nHsync <= 0) || (pSiS->OverruleRanges)) {
638972b676d7Smrg	  if(SiSAllowSyncOverride(pSiS, fromDDC)) {
639072b676d7Smrg	     Bool HaveNoRanges = (pScrn->monitor->nHsync <= 0);
639172b676d7Smrg	     /* Set sane ranges for LCD and TV
639272b676d7Smrg	      * (our strict checking will filter out invalid ones anyway)
639372b676d7Smrg	      */
639472b676d7Smrg	     if((crt1freqoverruled = CheckAndOverruleH(pScrn, pScrn->monitor))) {
639572b676d7Smrg		xf86DrvMsg(pScrn->scrnIndex, X_INFO, saneh,
639672b676d7Smrg			HaveNoRanges ? "missing" : "bogus",
639772b676d7Smrg#ifdef SISDUALHEAD
639872b676d7Smrg			pSiS->DualHeadMode ? (pSiS->SecondHead ? 1 : 2) :
639972b676d7Smrg#endif
640072b676d7Smrg				pSiS->CRT1off ? 2 : 1);
640172b676d7Smrg	     }
640272b676d7Smrg	  }
640372b676d7Smrg       }
640472b676d7Smrg    }
640572b676d7Smrg
640672b676d7Smrg    fromDDC = FALSE;
640772b676d7Smrg    if((pScrn->monitor->nVrefresh <= 0) || (pSiS->OverruleRanges)) {
640872b676d7Smrg       if((pScrn->monitor->nVrefresh <= 0) && (pScrn->monitor->DDC)) {
640972b676d7Smrg	  SiSSetSyncRangeFromEdid(pScrn, 0);
641072b676d7Smrg	  if(pScrn->monitor->nVrefresh > 0) {
641172b676d7Smrg	     xf86DrvMsg(pScrn->scrnIndex, X_INFO, subsvstr,
641272b676d7Smrg#ifdef SISDUALHEAD
641372b676d7Smrg			pSiS->DualHeadMode ? (pSiS->SecondHead ? 1 : 2) :
641472b676d7Smrg#endif
641572b676d7Smrg				pSiS->CRT1off ? 2 : 1);
641672b676d7Smrg	     fromDDC = TRUE;
641772b676d7Smrg          }
641872b676d7Smrg       }
641972b676d7Smrg       if((pScrn->monitor->nVrefresh <= 0) || (pSiS->OverruleRanges)) {
642072b676d7Smrg	  if(SiSAllowSyncOverride(pSiS, fromDDC)) {
642172b676d7Smrg	     Bool HaveNoRanges = (pScrn->monitor->nVrefresh <= 0);
642272b676d7Smrg	     /* Set sane ranges for LCD and TV */
642372b676d7Smrg	     if((crt1freqoverruled = CheckAndOverruleV(pScrn, pScrn->monitor))) {
642472b676d7Smrg		xf86DrvMsg(pScrn->scrnIndex, X_INFO, sanev,
642572b676d7Smrg			HaveNoRanges ? "missing" : "bogus",
642672b676d7Smrg#ifdef SISDUALHEAD
642772b676d7Smrg			pSiS->DualHeadMode ? (pSiS->SecondHead ? 1 : 2) :
642872b676d7Smrg#endif
642972b676d7Smrg				pSiS->CRT1off ? 2 : 1);
643072b676d7Smrg	     }
643172b676d7Smrg	  }
643272b676d7Smrg       }
643372b676d7Smrg    }
643472b676d7Smrg
643572b676d7Smrg    if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
643672b676d7Smrg       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
643772b676d7Smrg	  "\"Unknown reason\" in the following list means that the mode\n");
643872b676d7Smrg       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
643972b676d7Smrg	  "is not supported on the chipset/bridge/current output device.\n");
644072b676d7Smrg    }
644172b676d7Smrg
644272b676d7Smrg    /*
644372b676d7Smrg     * xf86ValidateModes will check that the mode HTotal and VTotal values
644472b676d7Smrg     * don't exceed the chipset's limit if pScrn->maxHValue and
644572b676d7Smrg     * pScrn->maxVValue are set.  Since our SISValidMode() already takes
644672b676d7Smrg     * care of this, we don't worry about setting them here.
644772b676d7Smrg     */
644872b676d7Smrg
644972b676d7Smrg    /* Select valid modes from those available */
645072b676d7Smrg    /*
645172b676d7Smrg     * Assuming min pitch 256, min height 128
645272b676d7Smrg     */
645372b676d7Smrg    {
645472b676d7Smrg       int minpitch, maxpitch, minheight, maxheight;
645572b676d7Smrg       pointer backupddc = pScrn->monitor->DDC;
645672b676d7Smrg
645772b676d7Smrg       minpitch = 256;
645872b676d7Smrg       minheight = 128;
645972b676d7Smrg       switch(pSiS->VGAEngine) {
646072b676d7Smrg       case SIS_OLD_VGA:
646172b676d7Smrg       case SIS_530_VGA:
646272b676d7Smrg          maxpitch = 2040;
646372b676d7Smrg          maxheight = 2048;
646472b676d7Smrg          break;
646572b676d7Smrg       case SIS_300_VGA:
646672b676d7Smrg       case SIS_315_VGA:
646772b676d7Smrg          maxpitch = 4088;
646872b676d7Smrg          maxheight = 4096;
646972b676d7Smrg          break;
647072b676d7Smrg       default:
647172b676d7Smrg          maxpitch = 2048;
647272b676d7Smrg          maxheight = 2048;
647372b676d7Smrg          break;
647472b676d7Smrg       }
647572b676d7Smrg
647672b676d7Smrg#ifdef SISMERGED
647772b676d7Smrg       pSiS->CheckForCRT2 = FALSE;
647872b676d7Smrg#endif
647972b676d7Smrg
648072b676d7Smrg       /* Suppress bogus DDC warning */
648172b676d7Smrg       if(crt1freqoverruled) pScrn->monitor->DDC = NULL;
648272b676d7Smrg
648372b676d7Smrg       i = xf86ValidateModes(pScrn, pScrn->monitor->Modes,
648472b676d7Smrg			pScrn->display->modes, clockRanges, NULL,
648572b676d7Smrg			minpitch, maxpitch,
648672b676d7Smrg			pScrn->bitsPerPixel * 8,
648772b676d7Smrg			minheight, maxheight,
648872b676d7Smrg			pScrn->display->virtualX,
648972b676d7Smrg			pScrn->display->virtualY,
649072b676d7Smrg			pSiS->maxxfbmem,
649172b676d7Smrg			LOOKUP_BEST_REFRESH);
649272b676d7Smrg
649372b676d7Smrg       pScrn->monitor->DDC = backupddc;
649472b676d7Smrg    }
649572b676d7Smrg
649672b676d7Smrg    if(i == -1) {
649772b676d7Smrg       SISErrorLog(pScrn, "xf86ValidateModes() error\n");
649872b676d7Smrg       goto my_error_1;
649972b676d7Smrg    }
650072b676d7Smrg
650172b676d7Smrg    /* Check the virtual screen against the available memory */
650272b676d7Smrg    {
650372b676d7Smrg       ULong memreq = (pScrn->virtualX * ((pScrn->bitsPerPixel + 7) / 8)) * pScrn->virtualY;
650472b676d7Smrg
650572b676d7Smrg       if(memreq > pSiS->maxxfbmem) {
650672b676d7Smrg	  SISErrorLog(pScrn,
650772b676d7Smrg	     "Virtual screen too big for memory; %ldK needed, %ldK available\n",
650872b676d7Smrg	     memreq/1024, pSiS->maxxfbmem/1024);
650972b676d7Smrg	  goto my_error_1;
651072b676d7Smrg       }
651172b676d7Smrg    }
651272b676d7Smrg
651372b676d7Smrg    /* Dual Head:
651472b676d7Smrg     * -) Go through mode list and mark all those modes as bad,
651572b676d7Smrg     *    which are unsuitable for dual head mode.
651672b676d7Smrg     * -) Find the highest used pixelclock on the master head.
651772b676d7Smrg     */
651872b676d7Smrg#ifdef SISDUALHEAD
651972b676d7Smrg    if((pSiS->DualHeadMode) && (!pSiS->SecondHead)) {
652072b676d7Smrg
652172b676d7Smrg       pSiSEnt->maxUsedClock = 0;
652272b676d7Smrg
652372b676d7Smrg       if((p = first = pScrn->modes)) {
652472b676d7Smrg
652572b676d7Smrg	  do {
652672b676d7Smrg
652772b676d7Smrg	     n = p->next;
652872b676d7Smrg
652972b676d7Smrg	     /* Modes that require the bridge to operate in SlaveMode
653072b676d7Smrg	      * are not suitable for Dual Head mode.
653172b676d7Smrg	      */
653272b676d7Smrg	     if( (pSiS->VGAEngine == SIS_300_VGA) &&
653372b676d7Smrg		 ( (strcmp(p->name, "320x200") == 0) ||
653472b676d7Smrg		   (strcmp(p->name, "320x240") == 0) ||
653572b676d7Smrg		   (strcmp(p->name, "400x300") == 0) ||
653672b676d7Smrg		   (strcmp(p->name, "512x384") == 0) ||
653772b676d7Smrg		   (strcmp(p->name, "640x400") == 0) ) )  {
653872b676d7Smrg		p->status = MODE_BAD;
653972b676d7Smrg		xf86DrvMsg(pScrn->scrnIndex, X_INFO, notsuitablestr, p->name, "dual head");
654072b676d7Smrg	     }
654172b676d7Smrg
654272b676d7Smrg	     /* Search for the highest clock on first head in order to calculate
654372b676d7Smrg	      * max clock for second head (CRT1)
654472b676d7Smrg	      */
654572b676d7Smrg	     if((p->status == MODE_OK) && (p->Clock > pSiSEnt->maxUsedClock)) {
654672b676d7Smrg		pSiSEnt->maxUsedClock = p->Clock;
654772b676d7Smrg	     }
654872b676d7Smrg
654972b676d7Smrg	     p = n;
655072b676d7Smrg
655172b676d7Smrg	  } while (p != NULL && p != first);
655272b676d7Smrg
655372b676d7Smrg       }
655472b676d7Smrg    }
655572b676d7Smrg#endif
655672b676d7Smrg
655772b676d7Smrg    /* Prune the modes marked as invalid */
655872b676d7Smrg    xf86PruneDriverModes(pScrn);
655972b676d7Smrg
656072b676d7Smrg    if(i == 0 || pScrn->modes == NULL) {
656172b676d7Smrg       SISErrorLog(pScrn, "No valid modes found - check VertRefresh/HorizSync\n");
656272b676d7Smrg       goto my_error_1;
656372b676d7Smrg    }
656472b676d7Smrg
656572b676d7Smrg    xf86SetCrtcForModes(pScrn, INTERLACE_HALVE_V);
656672b676d7Smrg
656772b676d7Smrg    /* Set the current mode to the first in the list */
656872b676d7Smrg    pScrn->currentMode = pScrn->modes;
656972b676d7Smrg
657072b676d7Smrg    /* Copy to CurrentLayout */
657172b676d7Smrg    pSiS->CurrentLayout.mode = pScrn->currentMode;
657272b676d7Smrg    pSiS->CurrentLayout.displayWidth = pScrn->displayWidth;
657372b676d7Smrg    pSiS->CurrentLayout.displayHeight = pScrn->virtualY;
657472b676d7Smrg
657572b676d7Smrg#ifdef SISMERGED
657672b676d7Smrg    if(pSiS->MergedFB) {
657772b676d7Smrg       xf86DrvMsg(pScrn->scrnIndex, X_INFO, modesforstr, 1);
657872b676d7Smrg    }
657972b676d7Smrg#endif
658072b676d7Smrg
658172b676d7Smrg    /* Print the list of modes being used */
658272b676d7Smrg    {
658372b676d7Smrg       Bool usemyprint = FALSE;
658472b676d7Smrg
658572b676d7Smrg#ifdef SISDUALHEAD
658672b676d7Smrg       if(pSiS->DualHeadMode) {
658772b676d7Smrg	  if(pSiS->SecondHead) {
658872b676d7Smrg	     if(pSiS->VBFlags & CRT1_LCDA) usemyprint = TRUE;
658972b676d7Smrg	  } else {
659072b676d7Smrg	     if(pSiS->VBFlags & (CRT2_LCD | CRT2_TV)) usemyprint = TRUE;
659172b676d7Smrg	  }
659272b676d7Smrg       } else
659372b676d7Smrg#endif
659472b676d7Smrg#ifdef SISMERGED
659572b676d7Smrg       if(pSiS->MergedFB) {
659672b676d7Smrg	  if(pSiS->VBFlags & CRT1_LCDA) usemyprint = TRUE;
659772b676d7Smrg       } else
659872b676d7Smrg#endif
659972b676d7Smrg       {
660072b676d7Smrg	  if( (pSiS->VBFlags & (CRT2_LCD | CRT2_TV)) &&
660172b676d7Smrg	      (!(pSiS->VBFlags & DISPTYPE_DISP1)) )
660272b676d7Smrg	     usemyprint = TRUE;
660372b676d7Smrg       }
660472b676d7Smrg
660572b676d7Smrg       if(usemyprint) {
660672b676d7Smrg	  SiSPrintModes(pScrn);
660772b676d7Smrg       } else {
660872b676d7Smrg	  xf86PrintModes(pScrn);
660972b676d7Smrg       }
661072b676d7Smrg    }
661172b676d7Smrg
661272b676d7Smrg#ifdef SISMERGED
661372b676d7Smrg    if(pSiS->MergedFB) {
661472b676d7Smrg       Bool acceptcustommodes = TRUE;
661572b676d7Smrg       Bool includelcdmodes   = TRUE;
661672b676d7Smrg       Bool isfordvi          = FALSE;
661772b676d7Smrg       Bool fakecrt2modes     = FALSE;
661872b676d7Smrg
661972b676d7Smrg       xf86DrvMsg(pScrn->scrnIndex, X_INFO, crtsetupstr, 2);
662072b676d7Smrg
662172b676d7Smrg       clockRanges->next = NULL;
662272b676d7Smrg       clockRanges->minClock = pSiS->MinClock;
662372b676d7Smrg       clockRanges->maxClock = SiSMemBandWidth(pSiS->CRT2pScrn, TRUE);
662472b676d7Smrg       clockRanges->clockIndex = -1;
662572b676d7Smrg       clockRanges->interlaceAllowed = FALSE;
662672b676d7Smrg       clockRanges->doubleScanAllowed = FALSE;
662772b676d7Smrg       if(pSiS->VGAEngine == SIS_315_VGA) {
662872b676d7Smrg          clockRanges->doubleScanAllowed = TRUE;
662972b676d7Smrg       }
663072b676d7Smrg
663172b676d7Smrg       xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "Min pixel clock for CRT2 is %d MHz\n",
663272b676d7Smrg                clockRanges->minClock / 1000);
663372b676d7Smrg       xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "Max pixel clock for CRT2 is %d MHz\n",
663472b676d7Smrg                clockRanges->maxClock / 1000);
663572b676d7Smrg
663672b676d7Smrg       if(pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) {
663772b676d7Smrg          if(!(pSiS->VBFlags2 & VB2_30xBDH)) {
663872b676d7Smrg             if(!(pSiS->VBFlags & (CRT2_LCD|CRT2_VGA))) includelcdmodes   = FALSE;
663972b676d7Smrg	     if(pSiS->VBFlags & CRT2_LCD)               isfordvi          = TRUE;
664072b676d7Smrg	     /* See above for a remark on handling CRT2 = TV */
664172b676d7Smrg	  } else {
664272b676d7Smrg	     if(pSiS->VBFlags & (CRT2_LCD|CRT2_TV)) {
664372b676d7Smrg		includelcdmodes   = FALSE;
664472b676d7Smrg		acceptcustommodes = FALSE;
664572b676d7Smrg		fakecrt2modes     = TRUE;
664672b676d7Smrg	     }
664772b676d7Smrg	  }
664872b676d7Smrg       } else {
664972b676d7Smrg	  includelcdmodes   = FALSE;
665072b676d7Smrg	  acceptcustommodes = FALSE;
665172b676d7Smrg	  if(pSiS->VBFlags & (CRT2_LCD|CRT2_TV)) {
665272b676d7Smrg	     fakecrt2modes = TRUE;
665372b676d7Smrg	  }
665472b676d7Smrg       }
665572b676d7Smrg
665672b676d7Smrg       pSiS->HaveCustomModes2 = FALSE;
665772b676d7Smrg       if(!SiSMakeOwnModeList(pSiS->CRT2pScrn, acceptcustommodes, includelcdmodes,
665872b676d7Smrg				isfordvi, &pSiS->HaveCustomModes2, FALSE /* fakecrt2modes */, TRUE )) {
665972b676d7Smrg
666072b676d7Smrg	  SISErrorLog(pScrn, "Building list of built-in modes for CRT2 failed, %s\n",
666172b676d7Smrg				mergeddisstr);
666272b676d7Smrg	  SiSFreeCRT2Structs(pSiS);
666372b676d7Smrg	  pSiS->MergedFB = FALSE;
666472b676d7Smrg
666572b676d7Smrg       } else {
666672b676d7Smrg	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
666772b676d7Smrg		 "Replaced %s mode list for CRT2 with built-in modes\n",
666872b676d7Smrg		 pSiS->HaveCustomModes2 ? "default" : "entire");
666972b676d7Smrg	  if((pSiS->VGAEngine == SIS_315_VGA) && (pSiS->VBFlags2 & VB2_SISVGA2BRIDGE)) {
667072b676d7Smrg	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
667172b676d7Smrg		 "Using %s widescreen modes for CRT2 VGA devices\n",
667272b676d7Smrg		 pSiS->SiS_Pr->SiS_UseWideCRT2 ? "real" : "fake");
667372b676d7Smrg	  } else pSiS->SiS_Pr->SiS_UseWideCRT2 = 0;
667472b676d7Smrg       }
667572b676d7Smrg
667672b676d7Smrg    }
667772b676d7Smrg
667872b676d7Smrg    if(pSiS->MergedFB) {
667972b676d7Smrg
668072b676d7Smrg       pointer backupddc;
668172b676d7Smrg
668272b676d7Smrg       crt2freqoverruled = FALSE;
668372b676d7Smrg
668472b676d7Smrg       fromDDC = FALSE;
668572b676d7Smrg       if((pSiS->CRT2pScrn->monitor->nHsync <= 0) || (pSiS->OverruleRanges)) {
668672b676d7Smrg          if((pSiS->CRT2pScrn->monitor->nHsync <= 0) && (pSiS->CRT2pScrn->monitor->DDC)) {
668772b676d7Smrg	     SiSSetSyncRangeFromEdid(pSiS->CRT2pScrn, 1);
668872b676d7Smrg	     if(pSiS->CRT2pScrn->monitor->nHsync > 0) {
668972b676d7Smrg		xf86DrvMsg(pScrn->scrnIndex, X_INFO, subshstr, 2);
669072b676d7Smrg		fromDDC = TRUE;
669172b676d7Smrg	     }
669272b676d7Smrg	  }
669372b676d7Smrg	  if((pSiS->CRT2pScrn->monitor->nHsync <= 0) || (pSiS->OverruleRanges)) {
669472b676d7Smrg	     if( (pSiS->VBFlags & CRT2_TV) ||
669572b676d7Smrg	         ((pSiS->VBFlags & CRT2_LCD) && (!fromDDC)) ) {
669672b676d7Smrg		Bool HaveNoRanges = (pSiS->CRT2pScrn->monitor->nHsync <= 0);
669772b676d7Smrg		/* Set sane ranges for LCD and TV */
669872b676d7Smrg		if((crt2freqoverruled = CheckAndOverruleH(pScrn, pSiS->CRT2pScrn->monitor))) {
669972b676d7Smrg		   xf86DrvMsg(pScrn->scrnIndex, X_INFO, saneh,
670072b676d7Smrg			HaveNoRanges ? "missing" : "bogus", 2);
670172b676d7Smrg		}
670272b676d7Smrg	     }
670372b676d7Smrg	  }
670472b676d7Smrg       }
670572b676d7Smrg
670672b676d7Smrg       fromDDC = FALSE;
670772b676d7Smrg       if((pSiS->CRT2pScrn->monitor->nVrefresh <= 0) || (pSiS->OverruleRanges)) {
670872b676d7Smrg	  if((pSiS->CRT2pScrn->monitor->nVrefresh <= 0) && (pSiS->CRT2pScrn->monitor->DDC)) {
670972b676d7Smrg	     SiSSetSyncRangeFromEdid(pSiS->CRT2pScrn, 0);
671072b676d7Smrg	     if(pSiS->CRT2pScrn->monitor->nVrefresh > 0) {
671172b676d7Smrg		xf86DrvMsg(pScrn->scrnIndex, X_INFO, subsvstr, 2);
671272b676d7Smrg		fromDDC = TRUE;
671372b676d7Smrg	     }
671472b676d7Smrg          }
671572b676d7Smrg	  if((pSiS->CRT2pScrn->monitor->nVrefresh <= 0) || (pSiS->OverruleRanges)) {
671672b676d7Smrg	     if( (pSiS->VBFlags & CRT2_TV) ||
671772b676d7Smrg	         ((pSiS->VBFlags & CRT2_LCD) && (!fromDDC)) ) {
671872b676d7Smrg		Bool HaveNoRanges = (pSiS->CRT2pScrn->monitor->nVrefresh <= 0);
671972b676d7Smrg		/* Set sane ranges for LCD and TV */
672072b676d7Smrg		if((crt2freqoverruled = CheckAndOverruleV(pScrn, pSiS->CRT2pScrn->monitor))) {
672172b676d7Smrg		   xf86DrvMsg(pScrn->scrnIndex, X_INFO, sanev,
672272b676d7Smrg			 HaveNoRanges ? "missing" : "bogus", 2);
672372b676d7Smrg	        }
672472b676d7Smrg	     }
672572b676d7Smrg	  }
672672b676d7Smrg       }
672772b676d7Smrg
672872b676d7Smrg       backupddc = pSiS->CRT2pScrn->monitor->DDC;
672972b676d7Smrg
673072b676d7Smrg       /* Suppress bogus DDC warning */
673172b676d7Smrg       if(crt2freqoverruled) pSiS->CRT2pScrn->monitor->DDC = NULL;
673272b676d7Smrg
673372b676d7Smrg       pSiS->CheckForCRT2 = TRUE;
673472b676d7Smrg
673572b676d7Smrg       i = xf86ValidateModes(pSiS->CRT2pScrn, pSiS->CRT2pScrn->monitor->Modes,
673672b676d7Smrg			pSiS->CRT2pScrn->display->modes, clockRanges,
673772b676d7Smrg			NULL, 256, 4088,
673872b676d7Smrg			pSiS->CRT2pScrn->bitsPerPixel * 8, 128, 4096,
673972b676d7Smrg			pScrn->display->virtualX ? pScrn->virtualX : 0,
674072b676d7Smrg			pScrn->display->virtualY ? pScrn->virtualY : 0,
674172b676d7Smrg			pSiS->maxxfbmem,
674272b676d7Smrg			LOOKUP_BEST_REFRESH);
674372b676d7Smrg
674472b676d7Smrg       pSiS->CheckForCRT2 = FALSE;
674572b676d7Smrg       pSiS->CRT2pScrn->monitor->DDC = backupddc;
674672b676d7Smrg
674772b676d7Smrg       if(i == -1) {
674872b676d7Smrg	  SISErrorLog(pScrn, "xf86ValidateModes() error, %s.\n", mergeddisstr);
674972b676d7Smrg	  SiSFreeCRT2Structs(pSiS);
675072b676d7Smrg	  pSiS->MergedFB = FALSE;
675172b676d7Smrg       }
675272b676d7Smrg
675372b676d7Smrg    }
675472b676d7Smrg
675572b676d7Smrg    if(pSiS->MergedFB) {
675672b676d7Smrg
675772b676d7Smrg       if((p = first = pSiS->CRT2pScrn->modes)) {
675872b676d7Smrg          do {
675972b676d7Smrg	     n = p->next;
676072b676d7Smrg	     if( (pSiS->VGAEngine == SIS_300_VGA) &&
676172b676d7Smrg		 ( (strcmp(p->name, "320x200") == 0) ||
676272b676d7Smrg		   (strcmp(p->name, "320x240") == 0) ||
676372b676d7Smrg		   (strcmp(p->name, "400x300") == 0) ||
676472b676d7Smrg		   (strcmp(p->name, "512x384") == 0) ||
676572b676d7Smrg		   (strcmp(p->name, "640x400") == 0) ) )  {
676672b676d7Smrg		p->status = MODE_BAD;
676772b676d7Smrg		xf86DrvMsg(pScrn->scrnIndex, X_INFO, notsuitablestr, p->name, "MergedFB");
676872b676d7Smrg	     }
676972b676d7Smrg	     p = n;
677072b676d7Smrg	  } while (p != NULL && p != first);
677172b676d7Smrg       }
677272b676d7Smrg
677372b676d7Smrg       xf86PruneDriverModes(pSiS->CRT2pScrn);
677472b676d7Smrg
677572b676d7Smrg       if(i == 0 || pSiS->CRT2pScrn->modes == NULL) {
677672b676d7Smrg	  SISErrorLog(pScrn, "No valid modes found for CRT2; %s\n", mergeddisstr);
677772b676d7Smrg	  SiSFreeCRT2Structs(pSiS);
677872b676d7Smrg	  pSiS->MergedFB = FALSE;
677972b676d7Smrg       }
678072b676d7Smrg
678172b676d7Smrg    }
678272b676d7Smrg
678372b676d7Smrg    if(pSiS->MergedFB) {
678472b676d7Smrg
678572b676d7Smrg       xf86SetCrtcForModes(pSiS->CRT2pScrn, INTERLACE_HALVE_V);
678672b676d7Smrg
678772b676d7Smrg       xf86DrvMsg(pScrn->scrnIndex, X_INFO, modesforstr, 2);
678872b676d7Smrg
678972b676d7Smrg       if(pSiS->VBFlags & (CRT2_LCD | CRT2_TV)) {
679072b676d7Smrg	  SiSPrintModes(pSiS->CRT2pScrn);
679172b676d7Smrg       } else {
679272b676d7Smrg	  xf86PrintModes(pSiS->CRT2pScrn);
679372b676d7Smrg       }
679472b676d7Smrg
679572b676d7Smrg       pSiS->CRT1Modes = pScrn->modes;
679672b676d7Smrg       pSiS->CRT1CurrentMode = pScrn->currentMode;
679772b676d7Smrg
679872b676d7Smrg       xf86DrvMsg(pScrn->scrnIndex, X_INFO, "MergedFB: Generating mode list\n");
679972b676d7Smrg
680072b676d7Smrg       pScrn->modes = SiSGenerateModeList(pScrn, pSiS->MetaModes,
680172b676d7Smrg					  pSiS->CRT1Modes, pSiS->CRT2pScrn->modes,
680272b676d7Smrg					  pSiS->CRT2Position);
680372b676d7Smrg
680472b676d7Smrg       if(!pScrn->modes) {
680572b676d7Smrg
680672b676d7Smrg	  SISErrorLog(pScrn, "Failed to parse MetaModes or no modes found. %s.\n",
680772b676d7Smrg			mergeddisstr);
680872b676d7Smrg	  SiSFreeCRT2Structs(pSiS);
680972b676d7Smrg	  pScrn->modes = pSiS->CRT1Modes;
681072b676d7Smrg	  pSiS->CRT1Modes = NULL;
681172b676d7Smrg	  pSiS->MergedFB = FALSE;
681272b676d7Smrg
681372b676d7Smrg       }
681472b676d7Smrg
681572b676d7Smrg    }
681672b676d7Smrg
681772b676d7Smrg    if(pSiS->MergedFB) {
681872b676d7Smrg
681972b676d7Smrg       /* If no virtual dimension was given by the user,
682072b676d7Smrg	* calculate a sane one now. Adapts pScrn->virtualX,
682172b676d7Smrg	* pScrn->virtualY and pScrn->displayWidth.
682272b676d7Smrg	*/
682372b676d7Smrg       SiSRecalcDefaultVirtualSize(pScrn);
682472b676d7Smrg
682572b676d7Smrg       pScrn->modes = pScrn->modes->next;  /* We get the last from GenerateModeList(), skip to first */
682672b676d7Smrg       pScrn->currentMode = pScrn->modes;
682772b676d7Smrg
682872b676d7Smrg       /* Update CurrentLayout */
682972b676d7Smrg       pSiS->CurrentLayout.mode = pScrn->currentMode;
683072b676d7Smrg       pSiS->CurrentLayout.displayWidth = pScrn->displayWidth;
683172b676d7Smrg       pSiS->CurrentLayout.displayHeight = pScrn->virtualY;
683272b676d7Smrg
683372b676d7Smrg    }
683472b676d7Smrg#endif
683572b676d7Smrg
683672b676d7Smrg    /* Set display resolution */
683772b676d7Smrg#ifdef SISMERGED
683872b676d7Smrg    if(pSiS->MergedFB) {
683972b676d7Smrg       SiSMergedFBSetDpi(pScrn, pSiS->CRT2pScrn, pSiS->CRT2Position);
684072b676d7Smrg    } else
684172b676d7Smrg#endif
684272b676d7Smrg       xf86SetDpi(pScrn, 0, 0);
684372b676d7Smrg
684472b676d7Smrg    /* Load fb module */
684572b676d7Smrg    switch(pScrn->bitsPerPixel) {
684672b676d7Smrg      case 8:
684772b676d7Smrg      case 16:
684872b676d7Smrg      case 24:
684972b676d7Smrg      case 32:
685072b676d7Smrg	if(!xf86LoadSubModule(pScrn, "fb")) {
685172b676d7Smrg           SISErrorLog(pScrn, "Failed to load fb module");
685272b676d7Smrg	   goto my_error_1;
685372b676d7Smrg	}
685472b676d7Smrg	break;
685572b676d7Smrg      default:
685672b676d7Smrg	SISErrorLog(pScrn, "Unsupported framebuffer bpp (%d)\n", pScrn->bitsPerPixel);
685772b676d7Smrg	goto my_error_1;
685872b676d7Smrg    }
685972b676d7Smrg
686072b676d7Smrg    /* Load XAA/EXA (if needed) */
686172b676d7Smrg    if(!pSiS->NoAccel) {
686272b676d7Smrg#ifdef SIS_USE_XAA
686372b676d7Smrg       if(!pSiS->useEXA) {
686472b676d7Smrg	  if (!xf86LoadSubModule(pScrn, "xaa")) {
68655788ca14Smrg	      xf86DrvMsg(pScrn->scrnIndex, X_INFO,
68665788ca14Smrg			 "Falling back to shadowfb\n");
68675788ca14Smrg	      pSiS->NoAccel = 1;
68685788ca14Smrg	      pSiS->ShadowFB = 1;
686972b676d7Smrg	  }
687072b676d7Smrg       }
687172b676d7Smrg#endif
687272b676d7Smrg#ifdef SIS_USE_EXA
687372b676d7Smrg       if(pSiS->useEXA) {
687472b676d7Smrg	  XF86ModReqInfo req;
687572b676d7Smrg	  int errmaj, errmin;
687672b676d7Smrg
687772b676d7Smrg	  memset(&req, 0, sizeof(req));
687872b676d7Smrg	  req.majorversion = 2;
687972b676d7Smrg	  req.minorversion = 0;
688072b676d7Smrg	  if (!LoadSubModule(pScrn->module, "exa", NULL, NULL, NULL, &req,
688172b676d7Smrg	    &errmaj, &errmin)) {
688272b676d7Smrg	    LoaderErrorMsg(NULL, "exa", errmaj, errmin);
688372b676d7Smrg	    goto my_error_1;
688472b676d7Smrg	  }
688572b676d7Smrg       }
688672b676d7Smrg#endif
688772b676d7Smrg    }
688872b676d7Smrg
688972b676d7Smrg    /* Load shadowfb (if needed) */
689072b676d7Smrg    if(pSiS->ShadowFB) {
689172b676d7Smrg       if(!xf86LoadSubModule(pScrn, "shadowfb")) {
689272b676d7Smrg	  SISErrorLog(pScrn, "Could not load shadowfb module\n");
689372b676d7Smrg	  goto my_error_1;
689472b676d7Smrg       }
689572b676d7Smrg    }
689672b676d7Smrg
689772b676d7Smrg    /* Load the dri and glx modules if requested. */
68985788ca14Smrg#ifdef SISDRI
689972b676d7Smrg    if(pSiS->loadDRI) {
690072b676d7Smrg       if(!xf86LoaderCheckSymbol("DRIScreenInit")) {
690172b676d7Smrg	  if(xf86LoadSubModule(pScrn, "dri")) {
690272b676d7Smrg	     if(!xf86LoaderCheckSymbol("GlxSetVisualConfigs")) {
6903e47418d9Smrg	        if(!xf86LoadSubModule(pScrn, "glx")) {
690472b676d7Smrg		   SISErrorLog(pScrn, "Failed to load glx module\n");
690572b676d7Smrg		}
690672b676d7Smrg	     }
690772b676d7Smrg	  } else {
690872b676d7Smrg	     SISErrorLog(pScrn, "Failed to load dri module\n");
690972b676d7Smrg	  }
691072b676d7Smrg       }
691172b676d7Smrg    }
691272b676d7Smrg#endif
691372b676d7Smrg
691472b676d7Smrg    /* Now load and initialize VBE module for VESA mode switching */
691572b676d7Smrg    pSiS->UseVESA = 0;
691672b676d7Smrg    if(pSiS->VESA == 1) {
691772b676d7Smrg       SiS_LoadInitVBE(pScrn);
691872b676d7Smrg       if(pSiS->pVbe) {
691972b676d7Smrg	  VbeInfoBlock *vbe;
692072b676d7Smrg	  if((vbe = VBEGetVBEInfo(pSiS->pVbe))) {
692172b676d7Smrg	     pSiS->vesamajor = (unsigned)(vbe->VESAVersion >> 8);
692272b676d7Smrg	     pSiS->vesaminor = vbe->VESAVersion & 0xff;
692372b676d7Smrg	     SiSBuildVesaModeList(pScrn, pSiS->pVbe, vbe);
692472b676d7Smrg	     VBEFreeVBEInfo(vbe);
692572b676d7Smrg	     pSiS->UseVESA = 1;
692672b676d7Smrg	  } else {
692772b676d7Smrg	     xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
692872b676d7Smrg	     	 "Failed to read VBE Info Block\n");
692972b676d7Smrg	  }
693072b676d7Smrg       }
693172b676d7Smrg       if(pSiS->UseVESA == 0) {
693272b676d7Smrg	  xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
693372b676d7Smrg	      "VESA mode switching disabled.\n");
693472b676d7Smrg       }
693572b676d7Smrg    }
693672b676d7Smrg
693772b676d7Smrg    if(pSiS->pVbe) {
693872b676d7Smrg       vbeFree(pSiS->pVbe);
693972b676d7Smrg       pSiS->pVbe = NULL;
694072b676d7Smrg    }
694172b676d7Smrg
694272b676d7Smrg#ifdef SISDUALHEAD
694372b676d7Smrg    xf86SetPrimInitDone(pScrn->entityList[0]);
694472b676d7Smrg#endif
694572b676d7Smrg
694672b676d7Smrg    sisRestoreExtRegisterLock(pSiS,srlockReg,crlockReg);
694772b676d7Smrg
694872b676d7Smrg    if(pSiS->pInt) xf86FreeInt10(pSiS->pInt);
694972b676d7Smrg    pSiS->pInt = NULL;
695072b676d7Smrg
695172b676d7Smrg    if(pSiS->VGAEngine == SIS_315_VGA) {
695272b676d7Smrg       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTXVGAMMA1;
695372b676d7Smrg    }
695472b676d7Smrg
695572b676d7Smrg#ifdef SISDUALHEAD
695672b676d7Smrg    if(pSiS->DualHeadMode) {
695772b676d7Smrg	pSiS->SiS_SD_Flags |= SiS_SD_ISDUALHEAD;
695872b676d7Smrg	if(pSiS->SecondHead) pSiS->SiS_SD_Flags |= SiS_SD_ISDHSECONDHEAD;
695972b676d7Smrg	else		     pSiS->SiS_SD_Flags &= ~(SiS_SD_SUPPORTXVGAMMA1);
696072b676d7Smrg#ifdef PANORAMIX
696172b676d7Smrg	if(!noPanoramiXExtension) {
696272b676d7Smrg	   pSiS->SiS_SD_Flags |= SiS_SD_ISDHXINERAMA;
696372b676d7Smrg	   /* pSiS->SiS_SD_Flags &= ~(SiS_SD_SUPPORTXVGAMMA1); */
696472b676d7Smrg	}
696572b676d7Smrg#endif
696672b676d7Smrg    }
696772b676d7Smrg#endif
696872b676d7Smrg
696972b676d7Smrg#ifdef SISMERGED
697072b676d7Smrg    if(pSiS->MergedFB) pSiS->SiS_SD_Flags |= SiS_SD_ISMERGEDFB;
697172b676d7Smrg#endif
697272b676d7Smrg
697372b676d7Smrg    /* Try to determine if this is a laptop   */
697472b676d7Smrg    /* (only used for SiSCtrl visualisations) */
697572b676d7Smrg    pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPLTFLAG;
697672b676d7Smrg    pSiS->SiS_SD2_Flags &= ~SiS_SD2_ISLAPTOP;
697772b676d7Smrg    if(pSiS->detectedCRT2Devices & CRT2_LCD) {
697872b676d7Smrg       if(pSiS->VBFlags2 & (VB2_SISLVDSBRIDGE | VB2_LVDS | VB2_30xBDH)) {
697972b676d7Smrg	  /* 1. By bridge type: LVDS in 99% of all cases;
698072b676d7Smrg	   * exclude unusual setups like Barco projectors
698172b676d7Smrg	   * and parallel flat panels. TODO: Exclude
698272b676d7Smrg	   * Sony W1, V1.
698372b676d7Smrg	   */
698472b676d7Smrg	  if((pSiS->SiS_Pr->SiS_CustomT != CUT_BARCO1366) &&
698572b676d7Smrg	     (pSiS->SiS_Pr->SiS_CustomT != CUT_BARCO1024) &&
698672b676d7Smrg	     (pSiS->SiS_Pr->SiS_CustomT != CUT_PANEL848)  &&
698772b676d7Smrg	     (pSiS->SiS_Pr->SiS_CustomT != CUT_PANEL856)  &&
698872b676d7Smrg	     (pSiS->SiS_Pr->SiS_CustomT != CUT_AOP8060)   &&
698972b676d7Smrg	     ( (pSiS->ChipType != SIS_550) ||
699072b676d7Smrg	       (!pSiS->DSTN && !pSiS->FSTN) ) ) {
699172b676d7Smrg	     pSiS->SiS_SD2_Flags |= SiS_SD2_ISLAPTOP;
699272b676d7Smrg	  }
699372b676d7Smrg       } else if((pSiS->VBFlags2 & (VB2_301 | VB2_301C)) &&
699472b676d7Smrg                 (pSiS->VBLCDFlags & (VB_LCD_1280x960  |
699572b676d7Smrg				      VB_LCD_1400x1050 |
699672b676d7Smrg				      VB_LCD_1024x600  |
699772b676d7Smrg				      VB_LCD_1280x800  |
699872b676d7Smrg				      VB_LCD_1280x854))) {
699972b676d7Smrg	  /* 2. By (odd) LCD resolutions on TMDS bridges
700072b676d7Smrg	   * (eg Averatec). TODO: Exclude IBM Netvista.
700172b676d7Smrg	   */
700272b676d7Smrg	  pSiS->SiS_SD2_Flags |= SiS_SD2_ISLAPTOP;
700372b676d7Smrg       }
700472b676d7Smrg    }
700572b676d7Smrg
700672b676d7Smrg    if(pSiS->enablesisctrl) pSiS->SiS_SD_Flags |= SiS_SD_ENABLED;
700772b676d7Smrg
700872b676d7Smrg    pSiS->currentModeLast = pScrn->currentMode;
700972b676d7Smrg    pSiS->VBFlagsInit = pSiS->VBFlags;
701072b676d7Smrg
701172b676d7Smrg    return TRUE;
701272b676d7Smrg
701372b676d7Smrg    /* ---- */
701472b676d7Smrg
701572b676d7Smrgmy_error_1:
701672b676d7Smrg    sisRestoreExtRegisterLock(pSiS, srlockReg, crlockReg);
701772b676d7Smrgmy_error_0:
701872b676d7Smrg#ifdef SISDUALHEAD
701972b676d7Smrg    if(pSiSEnt) pSiSEnt->ErrorAfterFirst = TRUE;
702072b676d7Smrg#endif
702172b676d7Smrg    if(pSiS->pInt) xf86FreeInt10(pSiS->pInt);
702272b676d7Smrg    pSiS->pInt = NULL;
702372b676d7Smrg    SISFreeRec(pScrn);
702472b676d7Smrg    return FALSE;
702572b676d7Smrg}
702672b676d7Smrg
702772b676d7Smrg/*
702872b676d7Smrg * Map I/O port area for non-PC platforms
702972b676d7Smrg */
703072b676d7Smrg#ifdef SIS_NEED_MAP_IOP
703172b676d7Smrgstatic Bool
703272b676d7SmrgSISMapIOPMem(ScrnInfoPtr pScrn)
703372b676d7Smrg{
703472b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
703572b676d7Smrg#ifdef SISDUALHEAD
703672b676d7Smrg    SISEntPtr pSiSEnt = pSiS->entityPrivate;
703772b676d7Smrg
703872b676d7Smrg    if(pSiS->DualHeadMode) {
703972b676d7Smrg        pSiSEnt->MapCountIOPBase++;
704072b676d7Smrg        if(!(pSiSEnt->IOPBase)) {
704172b676d7Smrg	     /* Only map if not mapped previously */
70421fd23544Smrg#ifndef XSERVER_LIBPCIACCESS
704372b676d7Smrg	     pSiSEnt->IOPBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
704472b676d7Smrg			pSiS->PciTag, pSiS->IOPAddress, 128);
70451fd23544Smrg#else
70461fd23544Smrg	     {
70471fd23544Smrg	       void **result = (void **)&pSiSEnt->IOPBase;
70481fd23544Smrg	       int err = pci_device_map_range(pSiS->PciInfo,
70491fd23544Smrg					      pSiS->IOPAddress,
70501fd23544Smrg					      128,
70511fd23544Smrg					      PCI_DEV_MAP_FLAG_WRITABLE,
70521fd23544Smrg					      result);
70531fd23544Smrg
70541fd23544Smrg	       if (err) {
70551fd23544Smrg                 xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
70561fd23544Smrg                             "Unable to map IO aperture. %s (%d)\n",
70571fd23544Smrg                             strerror (err), err);
70581fd23544Smrg	       }
70591fd23544Smrg	     }
70601fd23544Smrg#endif
706172b676d7Smrg        }
706272b676d7Smrg        pSiS->IOPBase = pSiSEnt->IOPBase;
706372b676d7Smrg    } else
706472b676d7Smrg#endif
70651fd23544Smrg#ifndef XSERVER_LIBPCIACCESS
70661fd23544Smrg	     pSiS->IOPBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
70671fd23544Smrg					   pSiS->PciTag, pSiS->IOPAddress, 128);
70681fd23544Smrg#else
70691fd23544Smrg	     {
70701fd23544Smrg	       void **result = (void **)&pSiS->IOPBase;
70711fd23544Smrg	       int err = pci_device_map_range(pSiS->PciInfo,
70721fd23544Smrg					      pSiS->IOPAddress,
70731fd23544Smrg					      128,
70741fd23544Smrg					      PCI_DEV_MAP_FLAG_WRITABLE,
70751fd23544Smrg					      result);
70761fd23544Smrg
70771fd23544Smrg	       if (err) {
70781fd23544Smrg                 xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
70791fd23544Smrg                             "Unable to map IO aperture. %s (%d)\n",
70801fd23544Smrg                             strerror (err), err);
70811fd23544Smrg	       }
70821fd23544Smrg	     }
70831fd23544Smrg#endif
708472b676d7Smrg    if(pSiS->IOPBase == NULL) {
708572b676d7Smrg	SISErrorLog(pScrn, "Could not map I/O port area\n");
708672b676d7Smrg	return FALSE;
708772b676d7Smrg    }
708872b676d7Smrg
708972b676d7Smrg    return TRUE;
709072b676d7Smrg}
709172b676d7Smrg
709272b676d7Smrgstatic Bool
709372b676d7SmrgSISUnmapIOPMem(ScrnInfoPtr pScrn)
709472b676d7Smrg{
709572b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
709672b676d7Smrg#ifdef SISDUALHEAD
709772b676d7Smrg    SISEntPtr pSiSEnt = pSiS->entityPrivate;;
709872b676d7Smrg#endif
709972b676d7Smrg
710072b676d7Smrg/* In dual head mode, we must not unmap if the other head still
710172b676d7Smrg * assumes memory as mapped
710272b676d7Smrg */
710372b676d7Smrg#ifdef SISDUALHEAD
710472b676d7Smrg    if(pSiS->DualHeadMode) {
710572b676d7Smrg        if(pSiSEnt->MapCountIOPBase) {
710672b676d7Smrg	    pSiSEnt->MapCountIOPBase--;
710772b676d7Smrg	    if((pSiSEnt->MapCountIOPBase == 0) || (pSiSEnt->forceUnmapIOPBase)) {
710872b676d7Smrg		xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiSEnt->IOPBase, 2048);
710972b676d7Smrg		pSiSEnt->IOPBase = NULL;
711072b676d7Smrg		pSiSEnt->MapCountIOPBase = 0;
711172b676d7Smrg		pSiSEnt->forceUnmapIOPBase = FALSE;
711272b676d7Smrg	    }
711372b676d7Smrg	    pSiS->IOPBase = NULL;
711472b676d7Smrg	}
711572b676d7Smrg    } else {
711672b676d7Smrg#endif
711772b676d7Smrg	xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiS->IOPBase, 2048);
711872b676d7Smrg	pSiS->IOPBase = NULL;
711972b676d7Smrg#ifdef SISDUALHEAD
712072b676d7Smrg    }
712172b676d7Smrg#endif
712272b676d7Smrg    return TRUE;
712372b676d7Smrg}
712472b676d7Smrg#endif
712572b676d7Smrg
712672b676d7Smrg/*
712772b676d7Smrg * Map the framebuffer and MMIO memory
712872b676d7Smrg */
712972b676d7Smrg
713072b676d7Smrgstatic Bool
713172b676d7SmrgSISMapMem(ScrnInfoPtr pScrn)
713272b676d7Smrg{
713372b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
713472b676d7Smrg    int mmioFlags = VIDMEM_MMIO;
713572b676d7Smrg#ifdef SISDUALHEAD
713672b676d7Smrg    SISEntPtr pSiSEnt = pSiS->entityPrivate;
713772b676d7Smrg#endif
713872b676d7Smrg
713972b676d7Smrg    /*
714072b676d7Smrg     * Map IO registers to virtual address space
714172b676d7Smrg     * (For Alpha, we need to map SPARSE memory, since we need
714272b676d7Smrg     * byte/short access.)
714372b676d7Smrg     */
714472b676d7Smrg#if defined(__alpha__)
714572b676d7Smrg    mmioFlags |= VIDMEM_SPARSE;
714672b676d7Smrg#endif
714772b676d7Smrg
714872b676d7Smrg#ifdef SISDUALHEAD
714972b676d7Smrg    if(pSiS->DualHeadMode) {
715072b676d7Smrg        pSiSEnt->MapCountIOBase++;
715172b676d7Smrg        if(!(pSiSEnt->IOBase)) {
715272b676d7Smrg	     /* Only map if not mapped previously */
71531fd23544Smrg#ifndef XSERVER_LIBPCIACCESS
715472b676d7Smrg    	     pSiSEnt->IOBase = xf86MapPciMem(pScrn->scrnIndex, mmioFlags,
715572b676d7Smrg                         pSiS->PciTag, pSiS->IOAddress, (pSiS->mmioSize * 1024));
71561fd23544Smrg#else
71571fd23544Smrg	     void **result = (void **)&pSiSEnt->IOBase;
71581fd23544Smrg	     int err = pci_device_map_range(pSiS->PciInfo,
71591fd23544Smrg 	                                    pSiS->IOAddress,
71601fd23544Smrg	                                    (pSiS->mmioSize * 1024),
71611fd23544Smrg                                            PCI_DEV_MAP_FLAG_WRITABLE,
71621fd23544Smrg                                            result);
71631fd23544Smrg
71641fd23544Smrg             if (err) {
71651fd23544Smrg                 xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
71661fd23544Smrg                             "Unable to map IO aperture. %s (%d)\n",
71671fd23544Smrg                             strerror (err), err);
71681fd23544Smrg	     }
71691fd23544Smrg#endif
717072b676d7Smrg        }
717172b676d7Smrg        pSiS->IOBase = pSiSEnt->IOBase;
717272b676d7Smrg    } else
717372b676d7Smrg#endif
71741fd23544Smrg#ifndef XSERVER_LIBPCIACCESS
717572b676d7Smrg    	pSiS->IOBase = xf86MapPciMem(pScrn->scrnIndex, mmioFlags,
717672b676d7Smrg                        pSiS->PciTag, pSiS->IOAddress, (pSiS->mmioSize * 1024));
71771fd23544Smrg#else
71781fd23544Smrg       {
71791fd23544Smrg	     void **result = (void **)&pSiS->IOBase;
71801fd23544Smrg	     int err = pci_device_map_range(pSiS->PciInfo,
71811fd23544Smrg 	                                    pSiS->IOAddress,
71821fd23544Smrg	                                    (pSiS->mmioSize * 1024),
71831fd23544Smrg                                            PCI_DEV_MAP_FLAG_WRITABLE,
71841fd23544Smrg                                            result);
71851fd23544Smrg
71861fd23544Smrg             if (err) {
71871fd23544Smrg                 xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
71881fd23544Smrg                             "Unable to map IO aperture. %s (%d)\n",
71891fd23544Smrg                             strerror (err), err);
71901fd23544Smrg	     }
71911fd23544Smrg       }
71921fd23544Smrg#endif
719372b676d7Smrg
719472b676d7Smrg    if(pSiS->IOBase == NULL) {
719572b676d7Smrg    	SISErrorLog(pScrn, "Could not map MMIO area\n");
719672b676d7Smrg        return FALSE;
719772b676d7Smrg    }
719872b676d7Smrg
719972b676d7Smrg#ifdef __alpha__
720072b676d7Smrg    /*
720172b676d7Smrg     * for Alpha, we need to map DENSE memory as well, for
720272b676d7Smrg     * setting CPUToScreenColorExpandBase.
720372b676d7Smrg     */
720472b676d7Smrg#ifdef SISDUALHEAD
720572b676d7Smrg    if(pSiS->DualHeadMode) {
720672b676d7Smrg        pSiSEnt->MapCountIOBaseDense++;
720772b676d7Smrg        if(!(pSiSEnt->IOBaseDense)) {
720872b676d7Smrg	     /* Only map if not mapped previously */
72091fd23544Smrg#ifndef XSERVER_LIBPCIACCESS
721072b676d7Smrg	     pSiSEnt->IOBaseDense = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
721172b676d7Smrg                    pSiS->PciTag, pSiS->IOAddress, (pSiS->mmioSize * 1024));
72121fd23544Smrg#else
72131fd23544Smrg	     void **result = (void **)&pSiSEnt->IOBaseDense;
72141fd23544Smrg	     int err = pci_device_map_range(pSiS->PciInfo,
72151fd23544Smrg 	                                    pSiS->IOAddress,
72161fd23544Smrg	                                    (pSiS->mmioSize * 1024),
72171fd23544Smrg                                            PCI_DEV_MAP_FLAG_WRITABLE,
72181fd23544Smrg                                            result);
72191fd23544Smrg
72201fd23544Smrg             if (err) {
72211fd23544Smrg                 xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
72221fd23544Smrg                             "Unable to map IO dense aperture. %s (%d)\n",
72231fd23544Smrg                             strerror (err), err);
72241fd23544Smrg	     }
72251fd23544Smrg#endif /* XSERVER_LIBPCIACCESS */
722672b676d7Smrg	}
722772b676d7Smrg	pSiS->IOBaseDense = pSiSEnt->IOBaseDense;
72281fd23544Smrg    } else {
72291fd23544Smrg#endif /* SISDUALHEAD */
72301fd23544Smrg#ifndef XSERVER_LIBPCIACCESS
72311fd23544Smrg	     pSiS->IOBaseDense = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
723272b676d7Smrg                    pSiS->PciTag, pSiS->IOAddress, (pSiS->mmioSize * 1024));
72331fd23544Smrg#else
72341fd23544Smrg	     void **result = (void **)&pSiS->IOBaseDense;
72351fd23544Smrg	     int err = pci_device_map_range(pSiS->PciInfo,
72361fd23544Smrg 	                                    pSiS->IOAddress,
72371fd23544Smrg	                                    (pSiS->mmioSize * 1024),
72381fd23544Smrg                                            PCI_DEV_MAP_FLAG_WRITABLE,
72391fd23544Smrg                                            result);
72401fd23544Smrg
72411fd23544Smrg             if (err) {
72421fd23544Smrg                 xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
72431fd23544Smrg                             "Unable to map IO dense aperture. %s (%d)\n",
72441fd23544Smrg                             strerror (err), err);
72451fd23544Smrg	     }
72461fd23544Smrg#endif /* XSERVER_LIBPCIACCESS */
72471fd23544Smrg#ifdef SISDUALHEAD
72481fd23544Smrg    }
72491fd23544Smrg#endif
725072b676d7Smrg    if(pSiS->IOBaseDense == NULL) {
725172b676d7Smrg       SISErrorLog(pScrn, "Could not map MMIO dense area\n");
725272b676d7Smrg       return FALSE;
725372b676d7Smrg    }
725472b676d7Smrg#endif /* __alpha__ */
725572b676d7Smrg
725672b676d7Smrg#ifdef SISDUALHEAD
725772b676d7Smrg    if(pSiS->DualHeadMode) {
725872b676d7Smrg	pSiSEnt->MapCountFbBase++;
725972b676d7Smrg	if(!(pSiSEnt->FbBase)) {
726072b676d7Smrg	     /* Only map if not mapped previously */
72611fd23544Smrg#ifndef XSERVER_LIBPCIACCESS
726272b676d7Smrg	     pSiSEnt->FbBase = pSiSEnt->RealFbBase =
726372b676d7Smrg			xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
726472b676d7Smrg			 pSiS->PciTag, (ULong)pSiS->realFbAddress,
726572b676d7Smrg			 pSiS->FbMapSize);
72661fd23544Smrg#else
72671fd23544Smrg         int err = pci_device_map_range(pSiS->PciInfo,
72681fd23544Smrg                                   (ULong)pSiS->realFbAddress,
72691fd23544Smrg                                   pSiS->FbMapSize,
72701fd23544Smrg                                   PCI_DEV_MAP_FLAG_WRITABLE |
72711fd23544Smrg                                   PCI_DEV_MAP_FLAG_WRITE_COMBINE,
72721fd23544Smrg                                   (void *)&pSiSEnt->FbBase);
72731fd23544Smrg	if (err) {
72741fd23544Smrg            xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
72751fd23544Smrg                        "Unable to map FB aperture. %s (%d)\n",
72761fd23544Smrg                        strerror (err), err);
72771fd23544Smrg            return FALSE;
72781fd23544Smrg        }
72791fd23544Smrg	pSiSEnt->RealFbBase = pSiSEnt->FbBase;
72801fd23544Smrg#endif
728172b676d7Smrg	}
728272b676d7Smrg	pSiS->FbBase = pSiS->RealFbBase = pSiSEnt->FbBase;
728372b676d7Smrg	/* Adapt FbBase (for DHM and SiS76x UMA skipping; dhmOffset is 0 otherwise) */
728472b676d7Smrg	pSiS->FbBase += pSiS->dhmOffset;
728572b676d7Smrg    } else {
728672b676d7Smrg#endif
72871fd23544Smrg
72881fd23544Smrg#ifndef XSERVER_LIBPCIACCESS
72891fd23544Smrg      pSiS->FbBase = pSiS->RealFbBase =
72901fd23544Smrg			xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
729172b676d7Smrg			 pSiS->PciTag, (ULong)pSiS->realFbAddress,
729272b676d7Smrg			 pSiS->FbMapSize);
72931fd23544Smrg#else
72941fd23544Smrg         int err = pci_device_map_range(pSiS->PciInfo,
72951fd23544Smrg                                   (ULong)pSiS->realFbAddress,
72961fd23544Smrg                                   pSiS->FbMapSize,
72971fd23544Smrg                                   PCI_DEV_MAP_FLAG_WRITABLE |
72981fd23544Smrg                                   PCI_DEV_MAP_FLAG_WRITE_COMBINE,
72991fd23544Smrg                                   (void *)&pSiS->FbBase);
73001fd23544Smrg	if (err) {
73011fd23544Smrg            xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
73021fd23544Smrg                        "Unable to map FB aperture. %s (%d)\n",
73031fd23544Smrg                        strerror (err), err);
73041fd23544Smrg            return FALSE;
73051fd23544Smrg        }
73061fd23544Smrg	pSiS->RealFbBase = pSiS->FbBase;
73071fd23544Smrg#endif
730872b676d7Smrg	pSiS->FbBase += pSiS->dhmOffset;
73091fd23544Smrg
731072b676d7Smrg#ifdef SISDUALHEAD
731172b676d7Smrg    }
731272b676d7Smrg#endif
731372b676d7Smrg
731472b676d7Smrg    if(pSiS->FbBase == NULL) {
731572b676d7Smrg       SISErrorLog(pScrn, "Could not map framebuffer area\n");
731672b676d7Smrg       return FALSE;
731772b676d7Smrg    }
731872b676d7Smrg
731972b676d7Smrg#ifdef TWDEBUG
732072b676d7Smrg    xf86DrvMsg(0, 0, "Framebuffer mapped to %p\n", pSiS->FbBase);
732172b676d7Smrg#endif
732272b676d7Smrg
732372b676d7Smrg    return TRUE;
732472b676d7Smrg}
732572b676d7Smrg
732672b676d7Smrg
732772b676d7Smrg/*
732872b676d7Smrg * Unmap the framebuffer and MMIO memory.
732972b676d7Smrg */
733072b676d7Smrg
733172b676d7Smrgstatic Bool
733272b676d7SmrgSISUnmapMem(ScrnInfoPtr pScrn)
733372b676d7Smrg{
733472b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
733572b676d7Smrg#ifdef SISDUALHEAD
733672b676d7Smrg    SISEntPtr pSiSEnt = pSiS->entityPrivate;
733772b676d7Smrg#endif
733872b676d7Smrg
733972b676d7Smrg/* In dual head mode, we must not unmap if the other head still
734072b676d7Smrg * assumes memory as mapped
734172b676d7Smrg */
734272b676d7Smrg#ifdef SISDUALHEAD
734372b676d7Smrg    if(pSiS->DualHeadMode) {
734472b676d7Smrg        if(pSiSEnt->MapCountIOBase) {
734572b676d7Smrg	    pSiSEnt->MapCountIOBase--;
734672b676d7Smrg	    if((pSiSEnt->MapCountIOBase == 0) || (pSiSEnt->forceUnmapIOBase)) {
734772b676d7Smrg		xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiSEnt->IOBase, (pSiS->mmioSize * 1024));
734872b676d7Smrg		pSiSEnt->IOBase = NULL;
734972b676d7Smrg		pSiSEnt->MapCountIOBase = 0;
735072b676d7Smrg		pSiSEnt->forceUnmapIOBase = FALSE;
735172b676d7Smrg	    }
735272b676d7Smrg	    pSiS->IOBase = NULL;
735372b676d7Smrg	}
735472b676d7Smrg#ifdef __alpha__
735572b676d7Smrg	if(pSiSEnt->MapCountIOBaseDense) {
735672b676d7Smrg	    pSiSEnt->MapCountIOBaseDense--;
735772b676d7Smrg	    if((pSiSEnt->MapCountIOBaseDense == 0) || (pSiSEnt->forceUnmapIOBaseDense)) {
735872b676d7Smrg		xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiSEnt->IOBaseDense, (pSiS->mmioSize * 1024));
735972b676d7Smrg		pSiSEnt->IOBaseDense = NULL;
736072b676d7Smrg		pSiSEnt->MapCountIOBaseDense = 0;
736172b676d7Smrg		pSiSEnt->forceUnmapIOBaseDense = FALSE;
736272b676d7Smrg	    }
736372b676d7Smrg	    pSiS->IOBaseDense = NULL;
736472b676d7Smrg	}
736572b676d7Smrg#endif /* __alpha__ */
736672b676d7Smrg	if(pSiSEnt->MapCountFbBase) {
736772b676d7Smrg	    pSiSEnt->MapCountFbBase--;
736872b676d7Smrg	    if((pSiSEnt->MapCountFbBase == 0) || (pSiSEnt->forceUnmapFbBase)) {
736972b676d7Smrg		xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiSEnt->RealFbBase, pSiS->FbMapSize);
737072b676d7Smrg		pSiSEnt->FbBase = pSiSEnt->RealFbBase = NULL;
737172b676d7Smrg		pSiSEnt->MapCountFbBase = 0;
737272b676d7Smrg		pSiSEnt->forceUnmapFbBase = FALSE;
737372b676d7Smrg
737472b676d7Smrg	    }
737572b676d7Smrg	    pSiS->FbBase = pSiS->RealFbBase = NULL;
737672b676d7Smrg	}
737772b676d7Smrg    } else {
737872b676d7Smrg#endif
737972b676d7Smrg	xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiS->IOBase, (pSiS->mmioSize * 1024));
738072b676d7Smrg	pSiS->IOBase = NULL;
738172b676d7Smrg#ifdef __alpha__
738272b676d7Smrg	xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiS->IOBaseDense, (pSiS->mmioSize * 1024));
738372b676d7Smrg	pSiS->IOBaseDense = NULL;
738472b676d7Smrg#endif
738572b676d7Smrg	xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiS->RealFbBase, pSiS->FbMapSize);
738672b676d7Smrg	pSiS->FbBase = pSiS->RealFbBase = NULL;
738772b676d7Smrg#ifdef SISDUALHEAD
738872b676d7Smrg    }
738972b676d7Smrg#endif
739072b676d7Smrg    return TRUE;
739172b676d7Smrg}
739272b676d7Smrg
739372b676d7Smrg/*
739472b676d7Smrg * This function saves the video state.
739572b676d7Smrg */
739672b676d7Smrgstatic void
739772b676d7SmrgSISSave(ScrnInfoPtr pScrn)
739872b676d7Smrg{
739972b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
740072b676d7Smrg    SISRegPtr sisReg;
740172b676d7Smrg    int flags;
740272b676d7Smrg
740372b676d7Smrg#ifdef SISDUALHEAD
740472b676d7Smrg    /* We always save master & slave */
740572b676d7Smrg    if(pSiS->DualHeadMode && pSiS->SecondHead) return;
740672b676d7Smrg#endif
740772b676d7Smrg
740872b676d7Smrg    sisReg = &pSiS->SavedReg;
740972b676d7Smrg
741072b676d7Smrg    if( ((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) &&
741172b676d7Smrg        ((pSiS->VBFlags2 & VB2_VIDEOBRIDGE) && (SiSBridgeIsInSlaveMode(pScrn))) ) {
741272b676d7Smrg       SiSVGASave(pScrn, sisReg, SISVGA_SR_CMAP | SISVGA_SR_MODE);
741372b676d7Smrg#ifdef SIS_PC_PLATFORM
741472b676d7Smrg       if(pSiS->VGAMemBase) {
741572b676d7Smrg          SiSRegInit(pSiS->SiS_Pr, pSiS->RelIO+0x30);
74165788ca14Smrg          SiSSetLVDSetc(pSiS->SiS_Pr);
741772b676d7Smrg          SiS_GetVBType(pSiS->SiS_Pr);
741872b676d7Smrg          SiS_DisableBridge(pSiS->SiS_Pr);
741972b676d7Smrg          SiSVGASave(pScrn, sisReg, SISVGA_SR_FONTS);
742072b676d7Smrg          SiS_EnableBridge(pSiS->SiS_Pr);
742172b676d7Smrg       }
742272b676d7Smrg#endif
742372b676d7Smrg    } else {
742472b676d7Smrg       flags = SISVGA_SR_CMAP | SISVGA_SR_MODE;
742572b676d7Smrg#ifdef SIS_PC_PLATFORM
742672b676d7Smrg       if(pSiS->VGAMemBase) flags |= SISVGA_SR_FONTS;
742772b676d7Smrg#endif
742872b676d7Smrg       SiSVGASave(pScrn, sisReg, flags);
742972b676d7Smrg    }
743072b676d7Smrg
743172b676d7Smrg    sisSaveUnlockExtRegisterLock(pSiS, &sisReg->sisRegs3C4[0x05], &sisReg->sisRegs3D4[0x80]);
743272b676d7Smrg
743372b676d7Smrg    (*pSiS->SiSSave)(pScrn, sisReg);
743472b676d7Smrg
743572b676d7Smrg    if(pSiS->UseVESA) SISVESASaveRestore(pScrn, MODE_SAVE);
743672b676d7Smrg
743772b676d7Smrg    /* "Save" these again as they may have been changed prior to SISSave() call */
743872b676d7Smrg    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
743972b676d7Smrg       sisReg->sisRegs3C4[0x1f] = pSiS->oldSR1F;
744072b676d7Smrg       sisReg->sisRegs3D4[0x17] = pSiS->oldCR17;
744172b676d7Smrg       sisReg->sisRegs3D4[0x32] = pSiS->oldCR32;
744272b676d7Smrg       sisReg->sisRegs3D4[0x36] = pSiS->oldCR36;
744372b676d7Smrg       sisReg->sisRegs3D4[0x37] = pSiS->oldCR37;
744472b676d7Smrg       if(pSiS->VGAEngine == SIS_315_VGA) {
744572b676d7Smrg	  sisReg->sisRegs3D4[pSiS->myCR63] = pSiS->oldCR63;
744672b676d7Smrg       }
744772b676d7Smrg    }
744872b676d7Smrg}
744972b676d7Smrg
745072b676d7Smrg/* VESASaveRestore taken from vesa driver */
745172b676d7Smrgstatic void
745272b676d7SmrgSISVESASaveRestore(ScrnInfoPtr pScrn, vbeSaveRestoreFunction function)
745372b676d7Smrg{
745472b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
745572b676d7Smrg
745672b676d7Smrg    /* Query amount of memory to save state */
745772b676d7Smrg    if((function == MODE_QUERY) ||
745872b676d7Smrg       (function == MODE_SAVE && pSiS->state == NULL)) {
745972b676d7Smrg
746072b676d7Smrg       /* Make sure we save at least this information in case of failure */
746172b676d7Smrg       (void)VBEGetVBEMode(pSiS->pVbe, &pSiS->stateMode);
746272b676d7Smrg       SiSVGASaveFonts(pScrn);
746372b676d7Smrg
746472b676d7Smrg       if(pSiS->vesamajor > 1) {
746572b676d7Smrg	  if(!VBESaveRestore(pSiS->pVbe, function, (pointer)&pSiS->state,
746672b676d7Smrg				&pSiS->stateSize, &pSiS->statePage)) {
746772b676d7Smrg	     return;
746872b676d7Smrg	  }
746972b676d7Smrg       }
747072b676d7Smrg    }
747172b676d7Smrg
747272b676d7Smrg    /* Save/Restore Super VGA state */
747372b676d7Smrg    if(function != MODE_QUERY) {
747472b676d7Smrg
747572b676d7Smrg       if(pSiS->vesamajor > 1) {
747672b676d7Smrg	  if(function == MODE_RESTORE) {
747772b676d7Smrg	     memcpy(pSiS->state, pSiS->pstate, pSiS->stateSize);
747872b676d7Smrg	  }
747972b676d7Smrg
748072b676d7Smrg	  if(VBESaveRestore(pSiS->pVbe,function,(pointer)&pSiS->state,
748172b676d7Smrg			    &pSiS->stateSize,&pSiS->statePage) &&
748272b676d7Smrg	     (function == MODE_SAVE)) {
748372b676d7Smrg	     /* don't rely on the memory not being touched */
748472b676d7Smrg	     if(!pSiS->pstate) {
74855788ca14Smrg		pSiS->pstate = malloc(pSiS->stateSize);
748672b676d7Smrg	     }
748772b676d7Smrg	     memcpy(pSiS->pstate, pSiS->state, pSiS->stateSize);
748872b676d7Smrg	  }
748972b676d7Smrg       }
749072b676d7Smrg
749172b676d7Smrg       if(function == MODE_RESTORE) {
749272b676d7Smrg	  VBESetVBEMode(pSiS->pVbe, pSiS->stateMode, NULL);
749372b676d7Smrg	  SiSVGARestoreFonts(pScrn);
749472b676d7Smrg       }
749572b676d7Smrg
749672b676d7Smrg    }
749772b676d7Smrg}
749872b676d7Smrg
749972b676d7Smrg/*
750072b676d7Smrg * Initialise a new mode.  This is currently done using the
750172b676d7Smrg * "initialise struct, restore/write struct to HW" model for
750272b676d7Smrg * the old chipsets (5597/530/6326). For newer chipsets,
750372b676d7Smrg * we use our own mode switching code.
750472b676d7Smrg */
750572b676d7Smrg
750672b676d7Smrgstatic Bool
750772b676d7SmrgSISModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
750872b676d7Smrg{
750972b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
751072b676d7Smrg    SISRegPtr sisReg;
751172b676d7Smrg#ifdef SISDUALHEAD
751272b676d7Smrg    SISEntPtr pSiSEnt = NULL;
751372b676d7Smrg#endif
751472b676d7Smrg
751572b676d7Smrg    andSISIDXREG(SISCR,0x11,0x7f);	/* Unlock CRTC registers */
751672b676d7Smrg
751772b676d7Smrg    SISModifyModeInfo(mode);		/* Quick check of the mode parameters */
751872b676d7Smrg
751972b676d7Smrg    if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
752072b676d7Smrg       SiSRegInit(pSiS->SiS_Pr, pSiS->RelIO+0x30);
752172b676d7Smrg    }
752272b676d7Smrg
752372b676d7Smrg    if(pSiS->UseVESA) {  /* With VESA: */
752472b676d7Smrg
752572b676d7Smrg#ifdef SISDUALHEAD
752672b676d7Smrg       /* No dual head mode when using VESA */
752772b676d7Smrg       if(pSiS->SecondHead) return TRUE;
752872b676d7Smrg#endif
752972b676d7Smrg
753072b676d7Smrg       pScrn->vtSema = TRUE;
753172b676d7Smrg
753272b676d7Smrg       /*
753372b676d7Smrg	* This order is required:
753472b676d7Smrg	* The video bridge needs to be adjusted before the
753572b676d7Smrg	* BIOS is run as the BIOS sets up CRT2 according to
753672b676d7Smrg	* these register settings.
753772b676d7Smrg	* After the BIOS is run, the bridges and turboqueue
753872b676d7Smrg	* registers need to be readjusted as the BIOS may
753972b676d7Smrg	* very probably have messed them up.
754072b676d7Smrg	*/
754172b676d7Smrg       if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
754272b676d7Smrg	  SiSPreSetMode(pScrn, mode, SIS_MODE_SIMU);
754372b676d7Smrg       }
754472b676d7Smrg       if(!SiSSetVESAMode(pScrn, mode)) {
754572b676d7Smrg	  SISErrorLog(pScrn, "SiSSetVESAMode() failed\n");
754672b676d7Smrg	  return FALSE;
754772b676d7Smrg       }
754872b676d7Smrg       sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
754972b676d7Smrg       if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
755072b676d7Smrg	  SiSPreSetMode(pScrn, mode, SIS_MODE_SIMU);
755172b676d7Smrg	  SiSPostSetMode(pScrn, &pSiS->ModeReg);
755272b676d7Smrg       }
755372b676d7Smrg#ifdef TWDEBUG
755472b676d7Smrg       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
755572b676d7Smrg		   "REAL REGISTER CONTENTS AFTER SETMODE:\n");
755672b676d7Smrg#endif
755772b676d7Smrg       if(!(*pSiS->ModeInit)(pScrn, mode)) {
755872b676d7Smrg	  SISErrorLog(pScrn, "ModeInit() failed\n");
755972b676d7Smrg	  return FALSE;
756072b676d7Smrg       }
756172b676d7Smrg
756272b676d7Smrg       SiSVGAProtect(pScrn, TRUE);
756372b676d7Smrg       (*pSiS->SiSRestore)(pScrn, &pSiS->ModeReg);
756472b676d7Smrg       SiSVGAProtect(pScrn, FALSE);
756572b676d7Smrg
756672b676d7Smrg    } else { /* Without VESA: */
756772b676d7Smrg
756872b676d7Smrg#ifdef SISDUALHEAD
756972b676d7Smrg       if(pSiS->DualHeadMode) {
757072b676d7Smrg
757172b676d7Smrg	  if(!(*pSiS->ModeInit)(pScrn, mode)) {
757272b676d7Smrg	     SISErrorLog(pScrn, "ModeInit() failed\n");
757372b676d7Smrg	     return FALSE;
757472b676d7Smrg	  }
757572b676d7Smrg
757672b676d7Smrg	  pScrn->vtSema = TRUE;
757772b676d7Smrg
757872b676d7Smrg	  pSiSEnt = pSiS->entityPrivate;
757972b676d7Smrg
758072b676d7Smrg	  if(!(pSiS->SecondHead)) {
758172b676d7Smrg	     /* Head 1 (master) is always CRT2 */
758272b676d7Smrg	     SiSPreSetMode(pScrn, mode, SIS_MODE_CRT2);
758372b676d7Smrg	     if(!SiSBIOSSetModeCRT2(pSiS->SiS_Pr, pScrn, mode, pSiS->IsCustom)) {
758472b676d7Smrg		SISErrorLog(pScrn, "SiSBIOSSetModeCRT2() failed\n");
758572b676d7Smrg		return FALSE;
758672b676d7Smrg	     }
758772b676d7Smrg	     SiSPostSetMode(pScrn, &pSiS->ModeReg);
758872b676d7Smrg	     if(pSiSEnt->pScrn_2) {
75895788ca14Smrg		SISAdjustFrame(ADJUST_FRAME_ARGS(pSiSEnt->pScrn_2,
759072b676d7Smrg			       pSiSEnt->pScrn_2->frameX0,
75915788ca14Smrg						 pSiSEnt->pScrn_2->frameY0));
759272b676d7Smrg	     }
759372b676d7Smrg	  } else {
759472b676d7Smrg	     /* Head 2 (slave) is always CRT1 */
759572b676d7Smrg	     SiSPreSetMode(pScrn, mode, SIS_MODE_CRT1);
759672b676d7Smrg	     if(!SiSBIOSSetModeCRT1(pSiS->SiS_Pr, pScrn, mode, pSiS->IsCustom)) {
759772b676d7Smrg		SISErrorLog(pScrn, "SiSBIOSSetModeCRT1() failed\n");
759872b676d7Smrg		return FALSE;
759972b676d7Smrg	     }
760072b676d7Smrg	     SiSPostSetMode(pScrn, &pSiS->ModeReg);
760172b676d7Smrg	     if(pSiSEnt->pScrn_1) {
76025788ca14Smrg		SISAdjustFrame(ADJUST_FRAME_ARGS(pSiSEnt->pScrn_1,
760372b676d7Smrg			       pSiSEnt->pScrn_1->frameX0,
76045788ca14Smrg			       pSiSEnt->pScrn_1->frameY0));
760572b676d7Smrg	     }
760672b676d7Smrg	  }
760772b676d7Smrg
760872b676d7Smrg       } else {
760972b676d7Smrg#endif
761072b676d7Smrg
761172b676d7Smrg	  if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
761272b676d7Smrg
761372b676d7Smrg	     if(!(*pSiS->ModeInit)(pScrn, mode)) {
761472b676d7Smrg		SISErrorLog(pScrn, "ModeInit() failed\n");
761572b676d7Smrg	        return FALSE;
761672b676d7Smrg	     }
761772b676d7Smrg
761872b676d7Smrg	     pScrn->vtSema = TRUE;
761972b676d7Smrg
762072b676d7Smrg#ifdef SISMERGED
762172b676d7Smrg	     if(pSiS->MergedFB) {
762272b676d7Smrg
762372b676d7Smrg		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Setting MergedFB mode %dx%d\n",
762472b676d7Smrg				mode->HDisplay, mode->VDisplay);
762572b676d7Smrg
762672b676d7Smrg		SiSPreSetMode(pScrn, mode, SIS_MODE_CRT1);
762772b676d7Smrg
762872b676d7Smrg		if(!SiSBIOSSetModeCRT1(pSiS->SiS_Pr, pScrn,
762972b676d7Smrg		                       ((SiSMergedDisplayModePtr)mode->Private)->CRT1,
763072b676d7Smrg				       pSiS->IsCustom)) {
763172b676d7Smrg		   SISErrorLog(pScrn, "SiSBIOSSetModeCRT1() failed\n");
763272b676d7Smrg		   return FALSE;
763372b676d7Smrg		}
763472b676d7Smrg
763572b676d7Smrg		SiSPreSetMode(pScrn, mode, SIS_MODE_CRT2);
763672b676d7Smrg
763772b676d7Smrg		if(!SiSBIOSSetModeCRT2(pSiS->SiS_Pr, pScrn,
763872b676d7Smrg		                       ((SiSMergedDisplayModePtr)mode->Private)->CRT2,
763972b676d7Smrg				       pSiS->IsCustom)) {
764072b676d7Smrg		   SISErrorLog(pScrn, "SiSBIOSSetModeCRT2() failed\n");
764172b676d7Smrg		   return FALSE;
764272b676d7Smrg		}
764372b676d7Smrg
764472b676d7Smrg	     } else {
764572b676d7Smrg#endif
764672b676d7Smrg
764772b676d7Smrg		if((pSiS->VBFlags & CRT1_LCDA) || (!(mode->type & M_T_DEFAULT))) {
764872b676d7Smrg
764972b676d7Smrg		   SiSPreSetMode(pScrn, mode, SIS_MODE_CRT1);
765072b676d7Smrg
765172b676d7Smrg		   if(!SiSBIOSSetModeCRT1(pSiS->SiS_Pr, pScrn,
765272b676d7Smrg				mode, pSiS->IsCustom)) {
765372b676d7Smrg		      SISErrorLog(pScrn, "SiSBIOSSetModeCRT1() failed\n");
765472b676d7Smrg		      return FALSE;
765572b676d7Smrg		   }
765672b676d7Smrg
765772b676d7Smrg		   SiSPreSetMode(pScrn, mode, SIS_MODE_CRT2);
765872b676d7Smrg
765972b676d7Smrg		   if(!SiSBIOSSetModeCRT2(pSiS->SiS_Pr, pScrn,
766072b676d7Smrg				mode, pSiS->IsCustom)) {
766172b676d7Smrg		      SISErrorLog(pScrn, "SiSBIOSSetModeCRT2() failed\n");
766272b676d7Smrg		      return FALSE;
766372b676d7Smrg		   }
766472b676d7Smrg
766572b676d7Smrg		} else {
766672b676d7Smrg
766772b676d7Smrg		   SiSPreSetMode(pScrn, mode, SIS_MODE_SIMU);
766872b676d7Smrg
766972b676d7Smrg		   if(!SiSBIOSSetMode(pSiS->SiS_Pr, pScrn,
767072b676d7Smrg				mode, pSiS->IsCustom)) {
767172b676d7Smrg		      SISErrorLog(pScrn, "SiSBIOSSetMode() failed\n");
767272b676d7Smrg		      return FALSE;
767372b676d7Smrg		   }
767472b676d7Smrg
767572b676d7Smrg		}
767672b676d7Smrg
767772b676d7Smrg#ifdef SISMERGED
767872b676d7Smrg	     }
767972b676d7Smrg#endif
768072b676d7Smrg
768172b676d7Smrg	     SiSPostSetMode(pScrn, &pSiS->ModeReg);
768272b676d7Smrg
768372b676d7Smrg#ifdef TWDEBUG
768472b676d7Smrg	     xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VBFlags %lx\n", pSiS->VBFlags);
768572b676d7Smrg	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
768672b676d7Smrg			"REAL REGISTER CONTENTS AFTER SETMODE:\n");
768772b676d7Smrg             (*pSiS->ModeInit)(pScrn, mode);
768872b676d7Smrg#endif
768972b676d7Smrg
769072b676d7Smrg	  } else {
769172b676d7Smrg
769272b676d7Smrg	     /* For other chipsets, use the old method */
769372b676d7Smrg
769472b676d7Smrg	     /* Prepare the register contents */
769572b676d7Smrg	     if(!(*pSiS->ModeInit)(pScrn, mode)) {
769672b676d7Smrg	        SISErrorLog(pScrn, "ModeInit() failed\n");
769772b676d7Smrg	        return FALSE;
769872b676d7Smrg	     }
769972b676d7Smrg
770072b676d7Smrg	     pScrn->vtSema = TRUE;
770172b676d7Smrg
770272b676d7Smrg	     /* Program the registers */
770372b676d7Smrg	     SiSVGAProtect(pScrn, TRUE);
770472b676d7Smrg	     sisReg = &pSiS->ModeReg;
770572b676d7Smrg
770672b676d7Smrg	     sisReg->sisRegsATTR[0x10] = 0x01;
770772b676d7Smrg	     if(pScrn->bitsPerPixel > 8) {
770872b676d7Smrg		sisReg->sisRegsGR[0x05] = 0x00;
770972b676d7Smrg	     }
771072b676d7Smrg
771172b676d7Smrg	     SiSVGARestore(pScrn, sisReg, SISVGA_SR_MODE);
771272b676d7Smrg
771372b676d7Smrg	     (*pSiS->SiSRestore)(pScrn, sisReg);
771472b676d7Smrg
771572b676d7Smrg	     if((pSiS->Chipset == PCI_CHIP_SIS6326) && (pSiS->SiS6326Flags & SIS6326_HASTV)) {
771672b676d7Smrg	        SiS6326PostSetMode(pScrn, &pSiS->ModeReg);
771772b676d7Smrg	     }
771872b676d7Smrg
771972b676d7Smrg#ifdef TWDEBUG
772072b676d7Smrg	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
772172b676d7Smrg			"REAL REGISTER CONTENTS AFTER SETMODE:\n");
772272b676d7Smrg	     (*pSiS->ModeInit)(pScrn, mode);
772372b676d7Smrg#endif
772472b676d7Smrg
772572b676d7Smrg	     SiSVGAProtect(pScrn, FALSE);
772672b676d7Smrg
772772b676d7Smrg	  }
772872b676d7Smrg
772972b676d7Smrg#ifdef SISDUALHEAD
773072b676d7Smrg       }
773172b676d7Smrg#endif
773272b676d7Smrg    }
773372b676d7Smrg
773472b676d7Smrg    /* Update Currentlayout */
773572b676d7Smrg    pSiS->CurrentLayout.mode = pSiS->currentModeLast = mode;
773672b676d7Smrg
773772b676d7Smrg    return TRUE;
773872b676d7Smrg}
773972b676d7Smrg
774072b676d7Smrgstatic Bool
774172b676d7SmrgSiSSetVESAMode(ScrnInfoPtr pScrn, DisplayModePtr pMode)
774272b676d7Smrg{
774372b676d7Smrg    SISPtr pSiS;
774472b676d7Smrg    int mode;
774572b676d7Smrg
774672b676d7Smrg    pSiS = SISPTR(pScrn);
774772b676d7Smrg
774872b676d7Smrg    if(!(mode = SiSCalcVESAModeIndex(pScrn, pMode))) return FALSE;
774972b676d7Smrg
775072b676d7Smrg    mode |= (1 << 15);	/* Don't clear framebuffer */
775172b676d7Smrg    mode |= (1 << 14); 	/* Use linear adressing */
775272b676d7Smrg
775372b676d7Smrg    if(VBESetVBEMode(pSiS->pVbe, mode, NULL) == FALSE) {
775472b676d7Smrg       SISErrorLog(pScrn, "Setting VESA mode 0x%x failed\n",
775572b676d7Smrg	             	mode & 0x0fff);
775672b676d7Smrg       return (FALSE);
775772b676d7Smrg    }
775872b676d7Smrg
775972b676d7Smrg    if(pMode->HDisplay != pScrn->virtualX) {
776072b676d7Smrg       VBESetLogicalScanline(pSiS->pVbe, pScrn->virtualX);
776172b676d7Smrg    }
776272b676d7Smrg
776372b676d7Smrg    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
776472b676d7Smrg    	"Setting VESA mode 0x%x succeeded\n",
776572b676d7Smrg	mode & 0x0fff);
776672b676d7Smrg
776772b676d7Smrg    return (TRUE);
776872b676d7Smrg}
776972b676d7Smrg
777072b676d7Smrgstatic void
777172b676d7SmrgSISSpecialRestore(ScrnInfoPtr pScrn)
777272b676d7Smrg{
777372b676d7Smrg    SISPtr    pSiS = SISPTR(pScrn);
777472b676d7Smrg    SISRegPtr sisReg = &pSiS->SavedReg;
777572b676d7Smrg    UChar temp;
777672b676d7Smrg    int i;
777772b676d7Smrg
777872b676d7Smrg    /* 1.11.04 and later for 651 and 301B(DH) do strange register
777972b676d7Smrg     * fiddling after the usual mode change. This happens
778072b676d7Smrg     * depending on the result of a call of int 2f (with
778172b676d7Smrg     * ax=0x1680) and if modeno <= 0x13. I have no idea if
778272b676d7Smrg     * that is specific for the 651 or that very machine.
778372b676d7Smrg     * So this perhaps requires some more checks in the beginning
778472b676d7Smrg     * (although it should not do any harm on other chipsets/bridges
778572b676d7Smrg     * etc.) However, even if I call the VBE to restore mode 0x03,
778672b676d7Smrg     * these registers don't get restored correctly, possibly
778772b676d7Smrg     * because that int-2f-call for some reason results non-zero. So
778872b676d7Smrg     * what I do here is to restore these few registers
778972b676d7Smrg     * manually.
779072b676d7Smrg     */
779172b676d7Smrg
779272b676d7Smrg    if(!(pSiS->ChipFlags & SiSCF_Is65x)) return;
779372b676d7Smrg    inSISIDXREG(SISCR, 0x34, temp);
779472b676d7Smrg    temp &= 0x7f;
779572b676d7Smrg    if(temp > 0x13) return;
779672b676d7Smrg
779772b676d7Smrg#ifdef UNLOCK_ALWAYS
779872b676d7Smrg    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
779972b676d7Smrg#endif
780072b676d7Smrg
780172b676d7Smrg    SiS_UnLockCRT2(pSiS->SiS_Pr);
780272b676d7Smrg
780372b676d7Smrg    outSISIDXREG(SISCAP, 0x3f, sisReg->sisCapt[0x3f]);
780472b676d7Smrg    outSISIDXREG(SISCAP, 0x00, sisReg->sisCapt[0x00]);
780572b676d7Smrg    for(i = 0; i < 0x4f; i++) {
780672b676d7Smrg       outSISIDXREG(SISCAP, i, sisReg->sisCapt[i]);
780772b676d7Smrg    }
780872b676d7Smrg    outSISIDXREG(SISVID, 0x32, (sisReg->sisVid[0x32] & ~0x05));
780972b676d7Smrg    outSISIDXREG(SISVID, 0x30, sisReg->sisVid[0x30]);
781072b676d7Smrg    outSISIDXREG(SISVID, 0x32, ((sisReg->sisVid[0x32] & ~0x04) | 0x01));
781172b676d7Smrg    outSISIDXREG(SISVID, 0x30, sisReg->sisVid[0x30]);
781272b676d7Smrg
781372b676d7Smrg    if(!(pSiS->ChipFlags & SiSCF_Is651)) return;
781472b676d7Smrg    if(!(pSiS->VBFlags2 & VB2_SISBRIDGE)) return;
781572b676d7Smrg
781672b676d7Smrg    inSISIDXREG(SISCR, 0x30, temp);
781772b676d7Smrg    if(temp & 0x40) {
781872b676d7Smrg       UChar myregs[] = {
781972b676d7Smrg       		0x2f, 0x08, 0x09, 0x03, 0x0a, 0x0c,
782072b676d7Smrg		0x0b, 0x0d, 0x0e, 0x12, 0x0f, 0x10,
782172b676d7Smrg		0x11, 0x04, 0x05, 0x06, 0x07, 0x00,
782272b676d7Smrg		0x2e
782372b676d7Smrg       };
782472b676d7Smrg       for(i = 0; i <= 18; i++) {
782572b676d7Smrg          outSISIDXREG(SISPART1, myregs[i], sisReg->VBPart1[myregs[i]]);
782672b676d7Smrg       }
782772b676d7Smrg    } else if((temp & 0x20) || (temp & 0x9c)) {
782872b676d7Smrg       UChar myregs[] = {
782972b676d7Smrg       		0x04, 0x05, 0x06, 0x07, 0x00, 0x2e
783072b676d7Smrg       };
783172b676d7Smrg       for(i = 0; i <= 5; i++) {
783272b676d7Smrg          outSISIDXREG(SISPART1, myregs[i], sisReg->VBPart1[myregs[i]]);
783372b676d7Smrg       }
783472b676d7Smrg    }
783572b676d7Smrg}
783672b676d7Smrg
783772b676d7Smrg/* Fix SR11 for 661 and later */
783872b676d7Smrgstatic void
783972b676d7SmrgSiSFixupSR11(ScrnInfoPtr pScrn)
784072b676d7Smrg{
784172b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
784272b676d7Smrg    CARD8  tmpreg;
784372b676d7Smrg
784472b676d7Smrg#ifdef UNLOCK_ALWAYS
784572b676d7Smrg    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
784672b676d7Smrg#endif
784772b676d7Smrg
784872b676d7Smrg    if(pSiS->ChipType >= SIS_661) {
784972b676d7Smrg       inSISIDXREG(SISSR,0x11,tmpreg);
785072b676d7Smrg       if(tmpreg & 0x20) {
785172b676d7Smrg          inSISIDXREG(SISSR,0x3e,tmpreg);
785272b676d7Smrg	  tmpreg = (tmpreg + 1) & 0xff;
785372b676d7Smrg	  outSISIDXREG(SISSR,0x3e,tmpreg);
785472b676d7Smrg       }
785572b676d7Smrg
785672b676d7Smrg       inSISIDXREG(SISSR,0x11,tmpreg);
785772b676d7Smrg       if(tmpreg & 0xf0) {
785872b676d7Smrg          andSISIDXREG(SISSR,0x11,0x0f);
785972b676d7Smrg       }
786072b676d7Smrg    }
786172b676d7Smrg}
786272b676d7Smrg
786372b676d7Smrg/* Subroutine for restoring sisfb's TV parameters (used by SiSRestore()) */
786472b676d7Smrg
786572b676d7Smrgstatic void
786672b676d7SmrgSiSRestore_SiSFB_TVParms(ScrnInfoPtr pScrn)
786772b676d7Smrg{
786872b676d7Smrg    SISPtr  pSiS = SISPTR(pScrn);
786972b676d7Smrg    int     fd;
787072b676d7Smrg    CARD32  parm;
787172b676d7Smrg
787272b676d7Smrg    if(!pSiS->sisfbfound) return;
787372b676d7Smrg    if(!pSiS->sisfb_tvposvalid) return;
787472b676d7Smrg    if(!(pSiS->sisfbdevname[0])) return;
787572b676d7Smrg
78761fd23544Smrg    if((fd = open(pSiS->sisfbdevname, O_RDONLY)) != -1) {
787772b676d7Smrg       parm = (CARD32)((pSiS->sisfb_tvxpos << 16) | (pSiS->sisfb_tvypos & 0xffff));
787872b676d7Smrg       ioctl(fd, SISFB_SET_TVPOSOFFSET, &parm);
787972b676d7Smrg       close(fd);
788072b676d7Smrg    }
788172b676d7Smrg}
788272b676d7Smrg
788372b676d7Smrg/*
788472b676d7Smrg * Restore the initial mode. To be used internally only!
788572b676d7Smrg */
788672b676d7Smrgstatic void
788772b676d7SmrgSISRestore(ScrnInfoPtr pScrn)
788872b676d7Smrg{
788972b676d7Smrg    SISPtr    pSiS = SISPTR(pScrn);
789072b676d7Smrg    SISRegPtr sisReg = &pSiS->SavedReg;
789172b676d7Smrg    Bool      doit = FALSE, doitlater = FALSE;
789272b676d7Smrg    Bool      vesasuccess = FALSE;
789372b676d7Smrg    int	      flags;
789472b676d7Smrg
789572b676d7Smrg    /* WARNING: Don't ever touch this. It now seems to work on
789672b676d7Smrg     * all chipset/bridge combinations - but finding out the
789772b676d7Smrg     * correct combination was pure hell.
789872b676d7Smrg     */
789972b676d7Smrg
790072b676d7Smrg    /* Wait for the accelerators */
790172b676d7Smrg    (*pSiS->SyncAccel)(pScrn);
790272b676d7Smrg
790372b676d7Smrg    /* Set up restore flags */
790472b676d7Smrg    flags = SISVGA_SR_MODE | SISVGA_SR_CMAP;
790572b676d7Smrg#ifdef SIS_PC_PLATFORM
790672b676d7Smrg    /* We now restore ALL to overcome the vga=extended problem */
790772b676d7Smrg    if(pSiS->VGAMemBase) flags |= SISVGA_SR_FONTS;
790872b676d7Smrg#endif
790972b676d7Smrg
791072b676d7Smrg    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
791172b676d7Smrg
791272b676d7Smrg#ifdef SISDUALHEAD
791372b676d7Smrg       /* We always restore master AND slave */
791472b676d7Smrg       if(pSiS->DualHeadMode && pSiS->SecondHead) return;
791572b676d7Smrg#endif
791672b676d7Smrg
791772b676d7Smrg#ifdef UNLOCK_ALWAYS
791872b676d7Smrg       sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
791972b676d7Smrg#endif
792072b676d7Smrg
792172b676d7Smrg       /* We must not disable the sequencer if the bridge is in SlaveMode! */
792272b676d7Smrg       if(!(SiSBridgeIsInSlaveMode(pScrn))) {
792372b676d7Smrg	  SiSVGAProtect(pScrn, TRUE);
792472b676d7Smrg       }
792572b676d7Smrg
792672b676d7Smrg       /* First, restore CRT1 on/off and VB connection registers */
792772b676d7Smrg       outSISIDXREG(SISCR, 0x32, pSiS->oldCR32);
792872b676d7Smrg       if(!(pSiS->oldCR17 & 0x80)) {			/* CRT1 was off */
792972b676d7Smrg	  if(!(SiSBridgeIsInSlaveMode(pScrn))) {        /* Bridge is NOT in SlaveMode now -> do it */
793072b676d7Smrg	     doit = TRUE;
793172b676d7Smrg	  } else {
793272b676d7Smrg	     doitlater = TRUE;
793372b676d7Smrg	  }
793472b676d7Smrg       } else {						/* CRT1 was on -> do it now */
793572b676d7Smrg	  doit = TRUE;
793672b676d7Smrg       }
793772b676d7Smrg
793872b676d7Smrg       if(doit) {
793972b676d7Smrg	  outSISIDXREG(SISCR, 0x17, pSiS->oldCR17);
794072b676d7Smrg       }
794172b676d7Smrg       if(pSiS->VGAEngine == SIS_315_VGA) {
794272b676d7Smrg	  outSISIDXREG(SISCR, pSiS->myCR63, pSiS->oldCR63);
794372b676d7Smrg       }
794472b676d7Smrg
794572b676d7Smrg       outSISIDXREG(SISSR, 0x1f, pSiS->oldSR1F);
794672b676d7Smrg
794772b676d7Smrg       /* For 30xB/LV, restoring the registers does not
794872b676d7Smrg	* work. We "manually" set the old mode, instead.
794972b676d7Smrg	* The same applies for SiS730 machines with LVDS.
795072b676d7Smrg	* Finally, this behavior can be forced by setting
795172b676d7Smrg	* the option RestoreBySetMode.
795272b676d7Smrg	*/
795372b676d7Smrg	if( ( (pSiS->restorebyset) ||
795472b676d7Smrg	      (pSiS->VBFlags2 & VB2_30xBLV) ||
795572b676d7Smrg	      ((pSiS->ChipType == SIS_730) && (pSiS->VBFlags2 & VB2_LVDS)) )     &&
795672b676d7Smrg	    (pSiS->OldMode) ) {
795772b676d7Smrg
795872b676d7Smrg	   Bool changedmode = FALSE;
795972b676d7Smrg
796072b676d7Smrg	   xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
796172b676d7Smrg	         "Restoring by setting old mode 0x%02x\n", pSiS->OldMode);
796272b676d7Smrg
796372b676d7Smrg	   if(((pSiS->OldMode <= 0x13) || (!pSiS->sisfbfound)) && (pSiS->pVbe)) {
796472b676d7Smrg	      int vmode = SiSTranslateToVESA(pScrn, pSiS->OldMode);
796572b676d7Smrg	      if(vmode > 0) {
796672b676d7Smrg		 if(vmode > 0x13) vmode |= ((1 << 15) | (1 << 14));
796772b676d7Smrg		 if(VBESetVBEMode(pSiS->pVbe, vmode, NULL) == TRUE) {
796872b676d7Smrg		    SISSpecialRestore(pScrn);
796972b676d7Smrg		    SiS_GetSetModeID(pScrn,pSiS->OldMode);
797072b676d7Smrg		    vesasuccess = TRUE;
797172b676d7Smrg		 } else {
797272b676d7Smrg		    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
797372b676d7Smrg			"VBE failed to restore mode 0x%x\n", pSiS->OldMode);
797472b676d7Smrg		 }
797572b676d7Smrg	      } else {
797672b676d7Smrg		 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
797772b676d7Smrg		 	"Can't identify VESA mode number for mode 0x%x\n", pSiS->OldMode);
797872b676d7Smrg	      }
797972b676d7Smrg	   }
798072b676d7Smrg
798172b676d7Smrg	   if(vesasuccess == FALSE) {
798272b676d7Smrg
798372b676d7Smrg	      int backupscaler = pSiS->SiS_Pr->UsePanelScaler;
798472b676d7Smrg	      int backupcenter = pSiS->SiS_Pr->CenterScreen;
798572b676d7Smrg	      ULong backupspecialtiming = pSiS->SiS_Pr->SiS_CustomT;
798672b676d7Smrg	      int mymode = pSiS->OldMode;
798772b676d7Smrg
798872b676d7Smrg	      if((pSiS->VGAEngine == SIS_315_VGA)			&&
798972b676d7Smrg	         ((pSiS->ROM661New) || (pSiS->ChipFlags & SiSCF_IsXGI)) &&
799072b676d7Smrg		 (!pSiS->sisfbfound)) {
799172b676d7Smrg	         /* New SiS BIOS or XGI BIOS has set mode, therefore eventually translate number */
799272b676d7Smrg	         mymode = SiSTranslateToOldMode(mymode);
799372b676d7Smrg	      }
799472b676d7Smrg
799572b676d7Smrg 	      if((pSiS->VBFlags2 & VB2_30xBLV)) {
799672b676d7Smrg	        /* !!! REQUIRED for 630+301B-DH, otherwise the text modes
799772b676d7Smrg	         *     will not be restored correctly !!!
799872b676d7Smrg	         * !!! Do this ONLY for LCD; VGA2 will not be restored
799972b676d7Smrg	         *     correctly otherwise.
800072b676d7Smrg	         */
800172b676d7Smrg	         UChar temp;
800272b676d7Smrg	         inSISIDXREG(SISCR, 0x30, temp);
800372b676d7Smrg	         if(temp & 0x20) {
800472b676d7Smrg	            if(mymode == 0x03) {
800572b676d7Smrg		       mymode = 0x13;
800672b676d7Smrg		       changedmode = TRUE;
800772b676d7Smrg	            }
800872b676d7Smrg	         }
800972b676d7Smrg	      }
801072b676d7Smrg
801172b676d7Smrg	      pSiS->SiS_Pr->UseCustomMode = FALSE;
801272b676d7Smrg	      pSiS->SiS_Pr->CRT1UsesCustomMode = FALSE;
801372b676d7Smrg	      pSiS->SiS_Pr->CenterScreen = 0;
801472b676d7Smrg	      if(pSiS->sisfbfound) {
801572b676d7Smrg		 pSiS->SiS_Pr->UsePanelScaler = pSiS->sisfbscalelcd;
801672b676d7Smrg		 pSiS->SiS_Pr->SiS_CustomT = pSiS->sisfbspecialtiming;
801772b676d7Smrg	      } else {
801872b676d7Smrg		 pSiS->SiS_Pr->UsePanelScaler = -1;
801972b676d7Smrg		 /* Leave CustomT as it is */
802072b676d7Smrg	      }
802172b676d7Smrg	      SiS_SetEnableDstn(pSiS->SiS_Pr, FALSE);
802272b676d7Smrg	      SiS_SetEnableFstn(pSiS->SiS_Pr, FALSE);
802372b676d7Smrg	      if((pSiS->ChipType == SIS_550) && (pSiS->sisfbfound)) {
802472b676d7Smrg		 if(pSiS->sisfbxSTN) {
802572b676d7Smrg		    SiS_SetEnableDstn(pSiS->SiS_Pr, pSiS->sisfbDSTN);
802672b676d7Smrg		    SiS_SetEnableFstn(pSiS->SiS_Pr, pSiS->sisfbFSTN);
802772b676d7Smrg		 } else if(mymode == 0x5a || mymode == 0x5b) {
802872b676d7Smrg		    SiS_SetEnableFstn(pSiS->SiS_Pr, TRUE);
802972b676d7Smrg		 }
803072b676d7Smrg	      }
803172b676d7Smrg	      SiSSetMode(pSiS->SiS_Pr, pScrn, mymode, FALSE);
803272b676d7Smrg	      if(changedmode) {
803372b676d7Smrg		 outSISIDXREG(SISCR,0x34,0x03);
803472b676d7Smrg	      }
803572b676d7Smrg	      SISSpecialRestore(pScrn);
803672b676d7Smrg	      SiS_GetSetModeID(pScrn, pSiS->OldMode); /* NOT mymode! */
803772b676d7Smrg	      pSiS->SiS_Pr->UsePanelScaler = backupscaler;
803872b676d7Smrg	      pSiS->SiS_Pr->CenterScreen = backupcenter;
803972b676d7Smrg	      pSiS->SiS_Pr->SiS_CustomT = backupspecialtiming;
804072b676d7Smrg	      SiS_SiSFB_Lock(pScrn, FALSE);
804172b676d7Smrg	      SiSRestore_SiSFB_TVParms(pScrn);
804272b676d7Smrg	      SiS_SiSFB_Lock(pScrn, TRUE);
804372b676d7Smrg
804472b676d7Smrg	   }
804572b676d7Smrg
804672b676d7Smrg	   /* Restore CRT1 status */
804772b676d7Smrg	   if(pSiS->VGAEngine == SIS_315_VGA) {
804872b676d7Smrg              outSISIDXREG(SISCR, pSiS->myCR63, pSiS->oldCR63);
804972b676d7Smrg           }
805072b676d7Smrg           outSISIDXREG(SISSR, 0x1f, pSiS->oldSR1F);
805172b676d7Smrg
805272b676d7Smrg#ifdef SISVRAMQ
805372b676d7Smrg	   /* Restore queue mode registers on 315/330/340 series */
805472b676d7Smrg	   /* (This became necessary due to the switch to VRAM queue) */
805572b676d7Smrg	   SiSRestoreQueueMode(pSiS, sisReg);
805672b676d7Smrg#endif
805772b676d7Smrg
805872b676d7Smrg        } else {
805972b676d7Smrg
806072b676d7Smrg	   if(pSiS->VBFlags2 & VB2_VIDEOBRIDGE) {
806172b676d7Smrg	      /* If a video bridge is present, we need to restore
806272b676d7Smrg	       * non-extended (=standard VGA) SR and CR registers
806372b676d7Smrg	       * before restoring the extended ones and the bridge
806472b676d7Smrg	       * registers.
806572b676d7Smrg	       */
806672b676d7Smrg	      if(!(SiSBridgeIsInSlaveMode(pScrn))) {
806772b676d7Smrg                 SiSVGAProtect(pScrn, TRUE);
806872b676d7Smrg	         SiSVGARestore(pScrn, sisReg, SISVGA_SR_MODE);
806972b676d7Smrg              }
807072b676d7Smrg	   }
807172b676d7Smrg
807272b676d7Smrg           (*pSiS->SiSRestore)(pScrn, sisReg);
807372b676d7Smrg
807472b676d7Smrg        }
807572b676d7Smrg
807672b676d7Smrg	if(doitlater) {
807772b676d7Smrg           outSISIDXREG(SISCR, 0x17, pSiS->oldCR17);
807872b676d7Smrg	}
807972b676d7Smrg
808072b676d7Smrg
808172b676d7Smrg
808272b676d7Smrg	if((pSiS->VBFlags2 & VB2_VIDEOBRIDGE) && (SiSBridgeIsInSlaveMode(pScrn))) {
808372b676d7Smrg
808472b676d7Smrg	   /* IMPORTANT: The 30xLV does not handle well being disabled if in
808572b676d7Smrg	    * LCDA mode! In LCDA mode, the bridge is NOT in slave mode,
808672b676d7Smrg	    * so this is the only safe way: Disable the bridge ONLY if
808772b676d7Smrg	    * in Slave Mode, and don't bother if not.
808872b676d7Smrg	    */
808972b676d7Smrg
809072b676d7Smrg	   if(flags & SISVGA_SR_FONTS) {
809172b676d7Smrg              SiSRegInit(pSiS->SiS_Pr, pSiS->RelIO+0x30);
80925788ca14Smrg	      SiSSetLVDSetc(pSiS->SiS_Pr);
809372b676d7Smrg	      SiS_GetVBType(pSiS->SiS_Pr);
809472b676d7Smrg	      SiS_DisableBridge(pSiS->SiS_Pr);
809572b676d7Smrg	      SiSVGAProtect(pScrn, TRUE);
809672b676d7Smrg	   }
809772b676d7Smrg
809872b676d7Smrg	   SiSVGARestore(pScrn, sisReg, flags);
809972b676d7Smrg
810072b676d7Smrg	   if(flags & SISVGA_SR_FONTS) {
810172b676d7Smrg	      SiSVGAProtect(pScrn, FALSE);
810272b676d7Smrg	      SiS_EnableBridge(pSiS->SiS_Pr);
810372b676d7Smrg	      andSISIDXREG(SISSR, 0x01, ~0x20);  /* Display on */
810472b676d7Smrg	   }
810572b676d7Smrg
810672b676d7Smrg	} else {
810772b676d7Smrg
810872b676d7Smrg	   SiSVGAProtect(pScrn, TRUE);
810972b676d7Smrg	   SiSVGARestore(pScrn, sisReg, flags);
811072b676d7Smrg           SiSVGAProtect(pScrn, FALSE);
811172b676d7Smrg
811272b676d7Smrg	}
811372b676d7Smrg
811472b676d7Smrg	SiSFixupSR11(pScrn);
811572b676d7Smrg
811672b676d7Smrg#ifdef TWDEBUG
811772b676d7Smrg	{
811872b676d7Smrg	  SISRegPtr pReg = &pSiS->ModeReg;
811972b676d7Smrg	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
812072b676d7Smrg		"REAL REGISTER CONTENTS AFTER RESTORE BY SETMODE:\n");
812172b676d7Smrg	  (*pSiS->SiSSave)(pScrn, pReg);
812272b676d7Smrg	}
812372b676d7Smrg#endif
812472b676d7Smrg
812572b676d7Smrg	sisRestoreExtRegisterLock(pSiS,sisReg->sisRegs3C4[0x05],sisReg->sisRegs3D4[0x80]);
812672b676d7Smrg
812772b676d7Smrg    } else {	/* All other chipsets */
812872b676d7Smrg
812972b676d7Smrg        SiSVGAProtect(pScrn, TRUE);
813072b676d7Smrg
813172b676d7Smrg#ifdef UNLOCK_ALWAYS
813272b676d7Smrg        sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
813372b676d7Smrg#endif
813472b676d7Smrg
813572b676d7Smrg        (*pSiS->SiSRestore)(pScrn, sisReg);
813672b676d7Smrg
813772b676d7Smrg        SiSVGAProtect(pScrn, TRUE);
813872b676d7Smrg
813972b676d7Smrg	SiSVGARestore(pScrn, sisReg, flags);
814072b676d7Smrg
814172b676d7Smrg	/* Restore TV. This is rather complicated, but if we don't do it,
814272b676d7Smrg	 * TV output will flicker terribly
814372b676d7Smrg	 */
814472b676d7Smrg        if((pSiS->Chipset == PCI_CHIP_SIS6326) && (pSiS->SiS6326Flags & SIS6326_HASTV)) {
814572b676d7Smrg	   if(sisReg->sis6326tv[0] & 0x04) {
814672b676d7Smrg	      UChar tmp;
814772b676d7Smrg	      int val;
814872b676d7Smrg
814972b676d7Smrg              orSISIDXREG(SISSR, 0x01, 0x20);
815072b676d7Smrg              tmp = SiS6326GetTVReg(pScrn,0x00);
815172b676d7Smrg              tmp &= ~0x04;
815272b676d7Smrg              while(!(inSISREG(SISINPSTAT) & 0x08));  /* Wait while NOT vb */
815372b676d7Smrg              SiS6326SetTVReg(pScrn,0x00,tmp);
815472b676d7Smrg              for(val=0; val < 2; val++) {
815572b676d7Smrg                 while(!(inSISREG(SISINPSTAT) & 0x08));  /* Wait while NOT vb */
815672b676d7Smrg                 while(inSISREG(SISINPSTAT) & 0x08);     /* wait while vb     */
815772b676d7Smrg              }
815872b676d7Smrg              SiS6326SetTVReg(pScrn, 0x00, sisReg->sis6326tv[0]);
815972b676d7Smrg              tmp = inSISREG(SISINPSTAT);
816072b676d7Smrg              outSISREG(SISAR, 0x20);
816172b676d7Smrg              tmp = inSISREG(SISINPSTAT);
816272b676d7Smrg              while(inSISREG(SISINPSTAT) & 0x01);
816372b676d7Smrg              while(!(inSISREG(SISINPSTAT) & 0x01));
816472b676d7Smrg              andSISIDXREG(SISSR, 0x01, ~0x20);
816572b676d7Smrg              for(val=0; val < 10; val++) {
816672b676d7Smrg                 while(!(inSISREG(SISINPSTAT) & 0x08));  /* Wait while NOT vb */
816772b676d7Smrg                 while(inSISREG(SISINPSTAT) & 0x08);     /* wait while vb     */
816872b676d7Smrg              }
816972b676d7Smrg              andSISIDXREG(SISSR, 0x01, ~0x20);
817072b676d7Smrg	   }
817172b676d7Smrg        }
817272b676d7Smrg
817372b676d7Smrg        sisRestoreExtRegisterLock(pSiS,sisReg->sisRegs3C4[5],sisReg->sisRegs3D4[0x80]);
817472b676d7Smrg
817572b676d7Smrg        SiSVGAProtect(pScrn, FALSE);
817672b676d7Smrg    }
817772b676d7Smrg}
817872b676d7Smrg
817972b676d7Smrgstatic void
818072b676d7SmrgSISVESARestore(ScrnInfoPtr pScrn)
818172b676d7Smrg{
818272b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
818372b676d7Smrg#ifdef SISVRAMQ
818472b676d7Smrg   SISRegPtr sisReg = &pSiS->SavedReg;
818572b676d7Smrg#endif
818672b676d7Smrg
818772b676d7Smrg   if(pSiS->UseVESA) {
818872b676d7Smrg      SISVESASaveRestore(pScrn, MODE_RESTORE);
818972b676d7Smrg#ifdef SISVRAMQ
819072b676d7Smrg      /* Restore queue mode registers on 315/330/340 series */
819172b676d7Smrg      /* (This became necessary due to the switch to VRAM queue) */
819272b676d7Smrg      SiSRestoreQueueMode(pSiS, sisReg);
819372b676d7Smrg#endif
819472b676d7Smrg   }
819572b676d7Smrg}
819672b676d7Smrg
819772b676d7Smrg/* Restore bridge config registers - to be called BEFORE VESARestore */
819872b676d7Smrgstatic void
819972b676d7SmrgSISBridgeRestore(ScrnInfoPtr pScrn)
820072b676d7Smrg{
820172b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
820272b676d7Smrg
820372b676d7Smrg#ifdef SISDUALHEAD
820472b676d7Smrg    /* We only restore for master head */
820572b676d7Smrg    if(pSiS->DualHeadMode && pSiS->SecondHead) return;
820672b676d7Smrg#endif
820772b676d7Smrg
820872b676d7Smrg    if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
820972b676d7Smrg	SiSRestoreBridge(pScrn, &pSiS->SavedReg);
821072b676d7Smrg    }
821172b676d7Smrg}
821272b676d7Smrg
821372b676d7Smrg/* Our BlockHandler */
821472b676d7Smrgstatic void
82155788ca14SmrgSISBlockHandler(BLOCKHANDLER_ARGS_DECL)
821672b676d7Smrg{
82175788ca14Smrg    SCREEN_PTR(arg);
82185788ca14Smrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
821972b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
822072b676d7Smrg
822172b676d7Smrg    pScreen->BlockHandler = pSiS->BlockHandler;
82225788ca14Smrg    (*pScreen->BlockHandler) (BLOCKHANDLER_ARGS);
822372b676d7Smrg    pScreen->BlockHandler = SISBlockHandler;
822472b676d7Smrg
822572b676d7Smrg#ifdef SISDUALHEAD
822672b676d7Smrg    if(pSiS->NeedCopyFastVidCpy) {
822772b676d7Smrg       SISEntPtr pSiSEnt = pSiS->entityPrivate;
822872b676d7Smrg       if(pSiSEnt->HaveFastVidCpy) {
822972b676d7Smrg	  pSiS->NeedCopyFastVidCpy = FALSE;
823072b676d7Smrg	  pSiS->SiSFastVidCopy = pSiSEnt->SiSFastVidCopy;
823172b676d7Smrg	  pSiS->SiSFastMemCopy = pSiSEnt->SiSFastMemCopy;
823272b676d7Smrg	  pSiS->SiSFastVidCopyFrom = pSiSEnt->SiSFastVidCopyFrom;
823372b676d7Smrg	  pSiS->SiSFastMemCopyFrom = pSiSEnt->SiSFastMemCopyFrom;
823472b676d7Smrg       }
823572b676d7Smrg    }
823672b676d7Smrg#endif
823772b676d7Smrg
823872b676d7Smrg    if(pSiS->VideoTimerCallback) {
823972b676d7Smrg       (*pSiS->VideoTimerCallback)(pScrn, currentTime.milliseconds);
824072b676d7Smrg    }
824172b676d7Smrg
824272b676d7Smrg#ifdef SIS_USE_XAA
824372b676d7Smrg    if(pSiS->RenderCallback) {
824472b676d7Smrg       (*pSiS->RenderCallback)(pScrn);
824572b676d7Smrg    }
824672b676d7Smrg#endif
824772b676d7Smrg#ifdef SIS_USE_EXA
824872b676d7Smrg    if(pSiS->ExaRenderCallback) {
824972b676d7Smrg       (*pSiS->ExaRenderCallback)(pScrn);
825072b676d7Smrg    }
825172b676d7Smrg#endif
825272b676d7Smrg}
825372b676d7Smrg
825472b676d7Smrg
825572b676d7Smrg
825672b676d7Smrg/* Do screen blanking; DPMS handling
825772b676d7Smrg *
825872b676d7Smrg * Mandatory; latter optional
825972b676d7Smrg */
826072b676d7Smrg
826172b676d7Smrgstatic void
826272b676d7SmrgSiSHandleBackLight(SISPtr pSiS, Bool blon)
826372b676d7Smrg{
826472b676d7Smrg    UChar sr11mask = (pSiS->SiS_Pr->SiS_SensibleSR11) ? 0x03 : 0xf3;
826572b676d7Smrg
826672b676d7Smrg    if(pSiS->VBFlags2 & VB2_SISLVDSBRIDGE) {
826772b676d7Smrg
826872b676d7Smrg       if(!blon) {
826972b676d7Smrg	  SiS_SiS30xBLOff(pSiS->SiS_Pr);
827072b676d7Smrg       } else {
827172b676d7Smrg	  SiS_SiS30xBLOn(pSiS->SiS_Pr);
827272b676d7Smrg       }
827372b676d7Smrg
827472b676d7Smrg    } else if( ((pSiS->VGAEngine == SIS_300_VGA) &&
827572b676d7Smrg	        (pSiS->VBFlags2 & (VB2_LVDS | VB2_30xBDH))) ||
827672b676d7Smrg	       ((pSiS->VGAEngine == SIS_315_VGA) &&
827772b676d7Smrg	        ((pSiS->VBFlags2 & (VB2_LVDS | VB2_CHRONTEL)) == VB2_LVDS)) ) {
827872b676d7Smrg
827972b676d7Smrg       if(!blon) {
828072b676d7Smrg	  setSISIDXREG(SISSR, 0x11, sr11mask, 0x08);
828172b676d7Smrg       } else {
828272b676d7Smrg	  setSISIDXREG(SISSR, 0x11, sr11mask, 0x00);
828372b676d7Smrg       }
828472b676d7Smrg
828572b676d7Smrg    } else if((pSiS->VGAEngine == SIS_315_VGA) &&
828672b676d7Smrg	      (pSiS->VBFlags2 & VB2_CHRONTEL)) {
828772b676d7Smrg
828872b676d7Smrg       if(!blon) {
828972b676d7Smrg	  SiS_Chrontel701xBLOff(pSiS->SiS_Pr);
829072b676d7Smrg       } else {
829172b676d7Smrg	  SiS_Chrontel701xBLOn(pSiS->SiS_Pr);
829272b676d7Smrg       }
829372b676d7Smrg
829472b676d7Smrg    }
829572b676d7Smrg}
829672b676d7Smrg
829772b676d7Smrgstatic Bool
829872b676d7SmrgSISSaveScreen(ScreenPtr pScreen, int mode)
829972b676d7Smrg{
83005788ca14Smrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
830172b676d7Smrg    SISPtr pSiS;
830272b676d7Smrg    Bool IsUnblank = xf86IsUnblank(mode) ? TRUE : FALSE;
830372b676d7Smrg
830472b676d7Smrg    if((pScrn == NULL) || (!pScrn->vtSema)) return TRUE;
830572b676d7Smrg
830672b676d7Smrg    pSiS = SISPTR(pScrn);
830772b676d7Smrg
830872b676d7Smrg#ifdef UNLOCK_ALWAYS
830972b676d7Smrg    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
831072b676d7Smrg#endif
831172b676d7Smrg
831272b676d7Smrg    if(pSiS->VBFlags & (CRT2_LCD | CRT1_LCDA)) {
831372b676d7Smrg       SiSHandleBackLight(pSiS, IsUnblank);
831472b676d7Smrg    }
831572b676d7Smrg
831672b676d7Smrg    if(!SiSBridgeIsInSlaveMode(pScrn)) {
831772b676d7Smrg       return SiSVGASaveScreen(pScreen, mode);
831872b676d7Smrg    }
831972b676d7Smrg
832072b676d7Smrg    return TRUE;
832172b676d7Smrg}
832272b676d7Smrg
832372b676d7Smrg#ifdef SISDUALHEAD
832472b676d7Smrg/* SaveScreen for dual head mode */
832572b676d7Smrgstatic Bool
832672b676d7SmrgSISSaveScreenDH(ScreenPtr pScreen, int mode)
832772b676d7Smrg{
83285788ca14Smrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
832972b676d7Smrg    SISPtr pSiS;
833072b676d7Smrg    Bool IsUnblank = xf86IsUnblank(mode) ? TRUE : FALSE;
833172b676d7Smrg
833272b676d7Smrg    if((pScrn == NULL) || (!pScrn->vtSema)) return TRUE;
833372b676d7Smrg
833472b676d7Smrg    pSiS = SISPTR(pScrn);
833572b676d7Smrg
833672b676d7Smrg    if( (pSiS->SecondHead) &&
833772b676d7Smrg        ((!(pSiS->VBFlags & CRT1_LCDA)) || (pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE)) ) {
833872b676d7Smrg
833972b676d7Smrg       /* Slave head is always CRT1 */
834072b676d7Smrg       /* (No backlight handling on TMDS bridges) */
834172b676d7Smrg       return SiSVGASaveScreen(pScreen, mode);
834272b676d7Smrg
834372b676d7Smrg    } else {
834472b676d7Smrg
834572b676d7Smrg       /* Master head is always CRT2 */
834672b676d7Smrg       /* But we land here for LCDA, too (if bridge is SiS LVDS type) */
834772b676d7Smrg
834872b676d7Smrg       /* We can only blank LCD, not other CRT2 devices */
834972b676d7Smrg       if(pSiS->VBFlags & (CRT2_LCD|CRT1_LCDA)) {
835072b676d7Smrg
835172b676d7Smrg#ifdef UNLOCK_ALWAYS
835272b676d7Smrg	  sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
835372b676d7Smrg#endif
835472b676d7Smrg	  SiSHandleBackLight(pSiS, IsUnblank);
835572b676d7Smrg
835672b676d7Smrg       }
835772b676d7Smrg
835872b676d7Smrg    }
835972b676d7Smrg    return TRUE;
836072b676d7Smrg}
836172b676d7Smrg#endif
836272b676d7Smrg
836372b676d7Smrgstatic void
836472b676d7SmrgSISDisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode, int flags)
836572b676d7Smrg{
836672b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
836772b676d7Smrg    Bool   docrt1 = TRUE, docrt2 = TRUE, backlight = TRUE;
836872b676d7Smrg    UChar  sr1=0, cr17=0, cr63=0, pmreg=0, sr7=0;
836972b676d7Smrg    UChar  p1_13=0, p2_0=0, oldpmreg=0;
837072b676d7Smrg
837172b676d7Smrg    if(!pScrn->vtSema) return;
837272b676d7Smrg
837372b676d7Smrg    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 4,
837472b676d7Smrg          "SISDisplayPowerManagementSet(%d)\n", PowerManagementMode);
837572b676d7Smrg
837672b676d7Smrg#ifdef SISDUALHEAD
837772b676d7Smrg    if(pSiS->DualHeadMode) {
837872b676d7Smrg       if(pSiS->SecondHead) docrt2 = FALSE;
837972b676d7Smrg       else                 docrt1 = FALSE;
838072b676d7Smrg    }
838172b676d7Smrg#endif
838272b676d7Smrg
8383e35772b2Smrg    /* FIXME: in old servers, DPMSSet was supposed to be called without open
8384e35772b2Smrg     * the correct PCI bridges before access the hardware. Now we have this
8385e35772b2Smrg     * hook wrapped by the vga arbiter which should do all the work, in
8386e35772b2Smrg     * kernels that implement it. For this case we might not want this hack
8387e35772b2Smrg     * bellow.
838872b676d7Smrg     */
838972b676d7Smrg    outSISIDXREG(SISSR,0x05,0x86);
839072b676d7Smrg    inSISIDXREG(SISSR,0x05,pmreg);
839172b676d7Smrg    if(pmreg != 0xa1) return;
839272b676d7Smrg
839372b676d7Smrg#ifdef UNLOCK_ALWAYS
839472b676d7Smrg    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
839572b676d7Smrg#endif
839672b676d7Smrg
839772b676d7Smrg    switch(PowerManagementMode) {
839872b676d7Smrg
839972b676d7Smrg       case DPMSModeOn:      /* HSync: On, VSync: On */
840072b676d7Smrg	  sr1   = 0x00;
840172b676d7Smrg	  cr17  = 0x80;
840272b676d7Smrg	  pmreg = 0x00;
840372b676d7Smrg	  cr63  = 0x00;
840472b676d7Smrg	  sr7   = 0x10;
840572b676d7Smrg	  p2_0  = 0x20;
840672b676d7Smrg	  p1_13 = 0x00;
840772b676d7Smrg	  backlight = TRUE;
840872b676d7Smrg	  break;
840972b676d7Smrg
841072b676d7Smrg       case DPMSModeSuspend: /* HSync: On, VSync: Off */
841172b676d7Smrg	  sr1   = 0x20;
841272b676d7Smrg	  cr17  = 0x80;
841372b676d7Smrg	  pmreg = 0x80;
841472b676d7Smrg	  cr63  = 0x40;
841572b676d7Smrg	  sr7   = 0x00;
841672b676d7Smrg	  p2_0  = 0x40;
841772b676d7Smrg	  p1_13 = 0x80;
841872b676d7Smrg	  backlight = FALSE;
841972b676d7Smrg	  break;
842072b676d7Smrg
842172b676d7Smrg       case DPMSModeStandby: /* HSync: Off, VSync: On */
842272b676d7Smrg	  sr1   = 0x20;
842372b676d7Smrg	  cr17  = 0x80;
842472b676d7Smrg	  pmreg = 0x40;
842572b676d7Smrg	  cr63  = 0x40;
842672b676d7Smrg	  sr7   = 0x00;
842772b676d7Smrg	  p2_0  = 0x80;
842872b676d7Smrg	  p1_13 = 0x40;
842972b676d7Smrg	  backlight = FALSE;
843072b676d7Smrg	  break;
843172b676d7Smrg
843272b676d7Smrg       case DPMSModeOff:     /* HSync: Off, VSync: Off */
843372b676d7Smrg	  sr1   = 0x20;
843472b676d7Smrg	  cr17  = 0x00;
843572b676d7Smrg	  pmreg = 0xc0;
843672b676d7Smrg	  cr63  = 0x40;
843772b676d7Smrg	  sr7   = 0x00;
843872b676d7Smrg	  p2_0  = 0xc0;
843972b676d7Smrg	  p1_13 = 0xc0;
844072b676d7Smrg	  backlight = FALSE;
844172b676d7Smrg	  break;
844272b676d7Smrg
844372b676d7Smrg       default:
844472b676d7Smrg	    return;
844572b676d7Smrg    }
844672b676d7Smrg
844772b676d7Smrg    oldpmreg = pmreg;
844872b676d7Smrg
844972b676d7Smrg    if((docrt2 && (pSiS->VBFlags & CRT2_LCD)) ||
845072b676d7Smrg       (docrt1 && (pSiS->VBFlags & CRT1_LCDA))) {
845172b676d7Smrg       SiSHandleBackLight(pSiS, backlight);
845272b676d7Smrg    }
845372b676d7Smrg
845472b676d7Smrg    if(docrt1) {
845572b676d7Smrg       switch(pSiS->VGAEngine) {
845672b676d7Smrg       case SIS_OLD_VGA:
845772b676d7Smrg       case SIS_530_VGA:
845872b676d7Smrg	    setSISIDXREG(SISSR, 0x01, ~0x20, sr1);    /* Set/Clear "Display On" bit */
845972b676d7Smrg	    inSISIDXREG(SISSR, 0x11, oldpmreg);
846072b676d7Smrg	    setSISIDXREG(SISCR, 0x17, 0x7f, cr17);
846172b676d7Smrg	    setSISIDXREG(SISSR, 0x11, 0x3f, pmreg);
846272b676d7Smrg	    break;
846372b676d7Smrg       case SIS_315_VGA:
846472b676d7Smrg	    if( (!pSiS->CRT1off) &&
846572b676d7Smrg	        ((!(pSiS->VBFlags & CRT1_LCDA)) || (pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE)) ) {
846672b676d7Smrg	       setSISIDXREG(SISCR, pSiS->myCR63, 0xbf, cr63);
846772b676d7Smrg	       setSISIDXREG(SISSR, 0x07, 0xef, sr7);
846872b676d7Smrg	    }
846972b676d7Smrg	    /* fall through */
847072b676d7Smrg       default:
847172b676d7Smrg	    if(!SiSBridgeIsInSlaveMode(pScrn)) {
847272b676d7Smrg	       setSISIDXREG(SISSR, 0x01, ~0x20, sr1);    /* Set/Clear "Display On" bit */
847372b676d7Smrg	    }
847472b676d7Smrg	    if((!(pSiS->VBFlags & CRT1_LCDA)) || (pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE)) {
847572b676d7Smrg	       inSISIDXREG(SISSR, 0x1f, oldpmreg);
847672b676d7Smrg	       if((!pSiS->CRT1off) && (!SiSBridgeIsInSlaveMode(pScrn))) {
847772b676d7Smrg		  setSISIDXREG(SISSR, 0x1f, 0x3f, pmreg);
847872b676d7Smrg	       }
847972b676d7Smrg	    }
848072b676d7Smrg       }
848172b676d7Smrg       oldpmreg &= 0xc0;
848272b676d7Smrg    }
848372b676d7Smrg
848472b676d7Smrg    if(docrt2) {
848572b676d7Smrg       if(pSiS->VBFlags & CRT2_LCD) {
848672b676d7Smrg          if((pSiS->VBFlags2 & VB2_SISBRIDGE) &&
848772b676d7Smrg	     (!(pSiS->VBFlags2 & VB2_30xBDH))) {
848872b676d7Smrg	     if(pSiS->VGAEngine == SIS_300_VGA) {
848972b676d7Smrg	        SiS_UnLockCRT2(pSiS->SiS_Pr);
849072b676d7Smrg	        setSISIDXREG(SISPART1, 0x13, 0x3f, p1_13);
849172b676d7Smrg	     }
849272b676d7Smrg	     if(pSiS->VBFlags2 & VB2_SISLVDSBRIDGE) p2_0 |= 0x20;
849372b676d7Smrg	     setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
849472b676d7Smrg	  }
849572b676d7Smrg       } else if(pSiS->VBFlags & (CRT2_VGA | CRT2_TV)) {
849672b676d7Smrg	  if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
849772b676d7Smrg	     setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
849872b676d7Smrg	  }
849972b676d7Smrg       }
850072b676d7Smrg    }
850172b676d7Smrg
850272b676d7Smrg    if( (docrt1) &&
850372b676d7Smrg        (pmreg != oldpmreg) &&
850472b676d7Smrg        ((!(pSiS->VBFlags & CRT1_LCDA)) || (pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE)) ) {
850572b676d7Smrg       outSISIDXREG(SISSR, 0x00, 0x01);    /* Synchronous Reset */
850672b676d7Smrg       usleep(10000);
850772b676d7Smrg       outSISIDXREG(SISSR, 0x00, 0x03);    /* End Reset */
850872b676d7Smrg    }
850972b676d7Smrg
851072b676d7Smrg}
851172b676d7Smrg
851272b676d7Smrg/* Mandatory
851372b676d7Smrg * This gets called at the start of each server generation
851472b676d7Smrg *
851572b676d7Smrg * We use pScrn and not CurrentLayout here, because the
851672b676d7Smrg * properties we use have not changed (displayWidth,
851772b676d7Smrg * depth, bitsPerPixel)
851872b676d7Smrg */
851972b676d7Smrgstatic Bool
85205788ca14SmrgSISScreenInit(SCREEN_INIT_ARGS_DECL)
852172b676d7Smrg{
85225788ca14Smrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
852372b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
852472b676d7Smrg    VisualPtr visual;
852572b676d7Smrg    ULong OnScreenSize;
852672b676d7Smrg    int ret, height, width, displayWidth;
852772b676d7Smrg    UChar *FBStart;
852872b676d7Smrg#ifdef SISDUALHEAD
852972b676d7Smrg    SISEntPtr pSiSEnt = NULL;
853072b676d7Smrg#endif
853172b676d7Smrg
853272b676d7Smrg#ifdef SISDUALHEAD
853372b676d7Smrg    if((!pSiS->DualHeadMode) || (!pSiS->SecondHead)) {
853472b676d7Smrg#endif
853572b676d7Smrg       SiS_LoadInitVBE(pScrn);
853672b676d7Smrg#ifdef SISDUALHEAD
853772b676d7Smrg    }
853872b676d7Smrg#endif
853972b676d7Smrg
854072b676d7Smrg#ifdef SISDUALHEAD
854172b676d7Smrg    if(pSiS->DualHeadMode) {
854272b676d7Smrg       pSiSEnt = pSiS->entityPrivate;
854372b676d7Smrg       pSiSEnt->refCount++;
854472b676d7Smrg    }
854572b676d7Smrg#endif
854672b676d7Smrg
854772b676d7Smrg#ifdef SIS_PC_PLATFORM
854872b676d7Smrg    /* Map 64k VGA window for saving/restoring CGA fonts */
854972b676d7Smrg    SiS_MapVGAMem(pScrn);
855072b676d7Smrg#endif
855172b676d7Smrg
855272b676d7Smrg    /* Map the SiS memory and MMIO areas */
855372b676d7Smrg    if(!SISMapMem(pScrn)) {
855472b676d7Smrg       SISErrorLog(pScrn, "SiSMapMem() failed\n");
855572b676d7Smrg       return FALSE;
855672b676d7Smrg    }
855772b676d7Smrg
855872b676d7Smrg    SiS_SiSFB_Lock(pScrn, TRUE);
855972b676d7Smrg
856072b676d7Smrg#ifdef UNLOCK_ALWAYS
856172b676d7Smrg    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
856272b676d7Smrg#endif
856372b676d7Smrg
856472b676d7Smrg    /* Enable TurboQueue so that SISSave() saves it in enabled
856572b676d7Smrg     * state. If we don't do this, X will hang after a restart!
856672b676d7Smrg     * (Happens for some unknown reason only when using VESA
856772b676d7Smrg     * for mode switching; assumingly a BIOS issue.)
856872b676d7Smrg     * This is done on 300 and 315 series only.
856972b676d7Smrg     */
857072b676d7Smrg    if(pSiS->UseVESA) {
857172b676d7Smrg#ifdef SISVRAMQ
857272b676d7Smrg       if(pSiS->VGAEngine != SIS_315_VGA)
857372b676d7Smrg#endif
857472b676d7Smrg          SiSEnableTurboQueue(pScrn);
857572b676d7Smrg    }
857672b676d7Smrg
857772b676d7Smrg    /* Save the current state */
857872b676d7Smrg    SISSave(pScrn);
857972b676d7Smrg
858072b676d7Smrg    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
858172b676d7Smrg
858272b676d7Smrg       if(!pSiS->OldMode) {
858372b676d7Smrg
858472b676d7Smrg          /* Try to find out current (=old) mode number
858572b676d7Smrg	   * (Do this only if not sisfb has told us its mode yet)
858672b676d7Smrg	   */
858772b676d7Smrg
858872b676d7Smrg	  /* Read 0:449 which the BIOS sets to the current mode number
858972b676d7Smrg	   * Unfortunately, this not reliable since the int10 emulation
859072b676d7Smrg	   * does not change this. So if we call the VBE later, this
859172b676d7Smrg	   * byte won't be touched (which is why we set this manually
859272b676d7Smrg	   * then).
859372b676d7Smrg	   */
859472b676d7Smrg          UChar myoldmode = SiS_GetSetModeID(pScrn, 0xFF);
859572b676d7Smrg	  UChar cr30, cr31;
859672b676d7Smrg
859772b676d7Smrg          /* Read CR34 which the BIOS sets to the current mode number for CRT2
859872b676d7Smrg	   * This is - of course - not reliable if the machine has no video
859972b676d7Smrg	   * bridge...
860072b676d7Smrg	   */
860172b676d7Smrg          inSISIDXREG(SISCR, 0x34, pSiS->OldMode);
860272b676d7Smrg	  inSISIDXREG(SISCR, 0x30, cr30);
860372b676d7Smrg	  inSISIDXREG(SISCR, 0x31, cr31);
860472b676d7Smrg
860572b676d7Smrg	  /* What if CR34 is different from the BIOS scratch byte? */
860672b676d7Smrg	  if(pSiS->OldMode != myoldmode) {
860772b676d7Smrg	     /* If no bridge output is active, trust the BIOS scratch byte */
860872b676d7Smrg	     if( (!(pSiS->VBFlags2 & VB2_VIDEOBRIDGE)) ||
860972b676d7Smrg	         (pSiS->OldMode == 0)                  ||
861072b676d7Smrg	         (!cr31 && !cr30)                      ||
861172b676d7Smrg		 (cr31 & 0x20) ) {
861272b676d7Smrg		pSiS->OldMode = myoldmode;
861372b676d7Smrg 	     }
861472b676d7Smrg	     /* ..else trust CR34 */
861572b676d7Smrg	  }
861672b676d7Smrg
861772b676d7Smrg	  /* Newer 650 BIOSes set CR34 to 0xff if the mode has been
861872b676d7Smrg	   * "patched", for instance for 80x50 text mode. (That mode
861972b676d7Smrg	   * has no number of its own, it's 0x03 like 80x25). In this
862072b676d7Smrg	   * case, we trust the BIOS scratch byte (provided that any
862172b676d7Smrg	   * of these two is valid).
862272b676d7Smrg	   */
862372b676d7Smrg	  if(pSiS->OldMode > 0x7f) {
862472b676d7Smrg	     pSiS->OldMode = myoldmode;
862572b676d7Smrg	  }
862672b676d7Smrg       }
862772b676d7Smrg#ifdef SISDUALHEAD
862872b676d7Smrg       if(pSiS->DualHeadMode) {
862972b676d7Smrg          if(!pSiS->SecondHead) pSiSEnt->OldMode = pSiS->OldMode;
863072b676d7Smrg          else                  pSiS->OldMode = pSiSEnt->OldMode;
863172b676d7Smrg       }
863272b676d7Smrg#endif
863372b676d7Smrg    }
863472b676d7Smrg
863572b676d7Smrg    /* RandR resets screen mode and size in CloseScreen(), hence
863672b676d7Smrg     * we need to adapt our VBFlags to the initial state if the
863772b676d7Smrg     * current mode has changed since closescreen() (or Screeninit()
863872b676d7Smrg     * for the first instance)
863972b676d7Smrg     */
864072b676d7Smrg    if(pScrn->currentMode != pSiS->currentModeLast) {
864172b676d7Smrg       pSiS->VBFlags = pSiS->VBFlags_backup = pSiS->VBFlagsInit;
864272b676d7Smrg    }
864372b676d7Smrg
864472b676d7Smrg    /* Copy our detected monitor gammas, part 2. Note that device redetection
864572b676d7Smrg     * is not supported in DHM, so there is no need to do that anytime later.
864672b676d7Smrg     */
864772b676d7Smrg#ifdef SISDUALHEAD
864872b676d7Smrg    if(pSiS->DualHeadMode) {
864972b676d7Smrg       if(!pSiS->SecondHead) {
865072b676d7Smrg          /* CRT2 */
865172b676d7Smrg	  pSiS->CRT1VGAMonitorGamma = pSiSEnt->CRT1VGAMonitorGamma;
865272b676d7Smrg       } else {
865372b676d7Smrg          /* CRT1 */
865472b676d7Smrg	  pSiS->CRT2VGAMonitorGamma = pSiSEnt->CRT2VGAMonitorGamma;
865572b676d7Smrg       }
865672b676d7Smrg       if(!pSiS->CRT2LCDMonitorGamma) pSiS->CRT2LCDMonitorGamma = pSiSEnt->CRT2LCDMonitorGamma;
865772b676d7Smrg    }
865872b676d7Smrg#endif
865972b676d7Smrg
866072b676d7Smrg    /* Initialize the first mode */
866172b676d7Smrg    if(!SISModeInit(pScrn, pScrn->currentMode)) {
866272b676d7Smrg       SISErrorLog(pScrn, "SiSModeInit() failed\n");
866372b676d7Smrg       return FALSE;
866472b676d7Smrg    }
866572b676d7Smrg
866672b676d7Smrg    /* Darken the screen for aesthetic reasons */
866772b676d7Smrg    /* Not using Dual Head variant on purpose; we darken
866872b676d7Smrg     * the screen for both displays, and un-darken
866972b676d7Smrg     * it when the second head is finished
867072b676d7Smrg     */
867172b676d7Smrg    SISSaveScreen(pScreen, SCREEN_SAVER_ON);
867272b676d7Smrg
867372b676d7Smrg    /* Set the viewport */
86745788ca14Smrg    SISAdjustFrame(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0));
867572b676d7Smrg
867672b676d7Smrg    /* Reset visual list. */
867772b676d7Smrg    miClearVisualTypes();
867872b676d7Smrg
867972b676d7Smrg    /* Setup the visuals we support. */
868072b676d7Smrg
868172b676d7Smrg    /*
868272b676d7Smrg     * For bpp > 8, the default visuals are not acceptable because we only
868372b676d7Smrg     * support TrueColor and not DirectColor.
868472b676d7Smrg     */
868572b676d7Smrg    if(!miSetVisualTypes(pScrn->depth,
868672b676d7Smrg			 (pScrn->bitsPerPixel > 8) ?
868772b676d7Smrg				TrueColorMask : miGetDefaultVisualMask(pScrn->depth),
868872b676d7Smrg			 pScrn->rgbBits, pScrn->defaultVisual)) {
868972b676d7Smrg       SISSaveScreen(pScreen, SCREEN_SAVER_OFF);
869072b676d7Smrg       SISErrorLog(pScrn, "miSetVisualTypes() failed (bpp %d)\n",
869172b676d7Smrg			pScrn->bitsPerPixel);
869272b676d7Smrg       return FALSE;
869372b676d7Smrg    }
869472b676d7Smrg
869572b676d7Smrg    width = pScrn->virtualX;
869672b676d7Smrg    height = pScrn->virtualY;
869772b676d7Smrg    displayWidth = pScrn->displayWidth;
869872b676d7Smrg
869972b676d7Smrg    if(pSiS->Rotate) {
870072b676d7Smrg       height = pScrn->virtualX;
870172b676d7Smrg       width = pScrn->virtualY;
870272b676d7Smrg    }
870372b676d7Smrg
870472b676d7Smrg    if(pSiS->ShadowFB) {
870572b676d7Smrg       pSiS->ShadowPitch = BitmapBytePad(pScrn->bitsPerPixel * width);
87065788ca14Smrg       pSiS->ShadowPtr = malloc(pSiS->ShadowPitch * height);
870772b676d7Smrg       displayWidth = pSiS->ShadowPitch / (pScrn->bitsPerPixel >> 3);
870872b676d7Smrg       FBStart = pSiS->ShadowPtr;
870972b676d7Smrg    } else {
871072b676d7Smrg       pSiS->ShadowPtr = NULL;
871172b676d7Smrg       FBStart = pSiS->FbBase;
871272b676d7Smrg    }
871372b676d7Smrg
871472b676d7Smrg    if(!miSetPixmapDepths()) {
871572b676d7Smrg       SISSaveScreen(pScreen, SCREEN_SAVER_OFF);
871672b676d7Smrg       SISErrorLog(pScrn, "miSetPixmapDepths() failed\n");
871772b676d7Smrg       return FALSE;
871872b676d7Smrg    }
871972b676d7Smrg
872072b676d7Smrg    /* Point cmdQueuePtr to pSiSEnt for shared usage
872172b676d7Smrg     * (same technique is then eventually used in DRIScreeninit)
872272b676d7Smrg     * For 315/330 series, this is done in EnableTurboQueue
872372b676d7Smrg     * which has already been called during ModeInit().
872472b676d7Smrg     */
872572b676d7Smrg#ifdef SISDUALHEAD
872672b676d7Smrg    if(pSiS->SecondHead)
872772b676d7Smrg       pSiS->cmdQueueLenPtr = &(SISPTR(pSiSEnt->pScrn_1)->cmdQueueLen);
872872b676d7Smrg    else
872972b676d7Smrg#endif
873072b676d7Smrg       pSiS->cmdQueueLenPtr = &(pSiS->cmdQueueLen);
873172b676d7Smrg
873272b676d7Smrg    pSiS->cmdQueueLen = 0; /* Force an EngineIdle() at start */
873372b676d7Smrg
87345788ca14Smrg#ifdef SISDRI
873572b676d7Smrg    if(pSiS->loadDRI) {
873672b676d7Smrg#ifdef SISDUALHEAD
873772b676d7Smrg       /* No DRI in dual head mode */
873872b676d7Smrg       if(pSiS->DualHeadMode) {
873972b676d7Smrg	  pSiS->directRenderingEnabled = FALSE;
874072b676d7Smrg	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
874172b676d7Smrg		"DRI not supported in Dual Head mode\n");
874272b676d7Smrg       } else
874372b676d7Smrg#endif
874472b676d7Smrg	      if(pSiS->VGAEngine != SIS_315_VGA) {
874572b676d7Smrg	  /* Force the initialization of the context */
874672b676d7Smrg	  pSiS->directRenderingEnabled = SISDRIScreenInit(pScreen);
874772b676d7Smrg       } else {
874872b676d7Smrg	  xf86DrvMsg(pScrn->scrnIndex, X_NOT_IMPLEMENTED,
874972b676d7Smrg		"DRI not supported on this chipset\n");
875072b676d7Smrg	  pSiS->directRenderingEnabled = FALSE;
875172b676d7Smrg       }
875272b676d7Smrg    }
875372b676d7Smrg#endif
875472b676d7Smrg
875572b676d7Smrg    /* Call the framebuffer layer's ScreenInit function and fill in other
875672b676d7Smrg     * pScreen fields.
875772b676d7Smrg     */
875872b676d7Smrg    switch(pScrn->bitsPerPixel) {
875972b676d7Smrg       case 24:
876072b676d7Smrg	  if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
876172b676d7Smrg	     ret = FALSE;
876272b676d7Smrg	     break;
876372b676d7Smrg	  }
876472b676d7Smrg	  /* fall through */
876572b676d7Smrg       case 8:
876672b676d7Smrg       case 16:
876772b676d7Smrg       case 32:
876872b676d7Smrg	  ret = fbScreenInit(pScreen, FBStart, width,
876972b676d7Smrg			height, pScrn->xDpi, pScrn->yDpi,
877072b676d7Smrg			displayWidth, pScrn->bitsPerPixel);
877172b676d7Smrg	  break;
877272b676d7Smrg       default:
877372b676d7Smrg	  ret = FALSE;
877472b676d7Smrg	  break;
877572b676d7Smrg    }
877672b676d7Smrg    if(!ret) {
877772b676d7Smrg       SISErrorLog(pScrn, "Unsupported bpp (%d) or fbScreenInit() failed\n",
877872b676d7Smrg			pScrn->bitsPerPixel);
877972b676d7Smrg       SISSaveScreen(pScreen, SCREEN_SAVER_OFF);
878072b676d7Smrg       return FALSE;
878172b676d7Smrg    }
878272b676d7Smrg
878372b676d7Smrg    /* Fixup RGB ordering */
878472b676d7Smrg    if(pScrn->bitsPerPixel > 8) {
878572b676d7Smrg       visual = pScreen->visuals + pScreen->numVisuals;
878672b676d7Smrg       while (--visual >= pScreen->visuals) {
878772b676d7Smrg          if((visual->class | DynamicClass) == DirectColor) {
878872b676d7Smrg             visual->offsetRed = pScrn->offset.red;
878972b676d7Smrg             visual->offsetGreen = pScrn->offset.green;
879072b676d7Smrg             visual->offsetBlue = pScrn->offset.blue;
879172b676d7Smrg             visual->redMask = pScrn->mask.red;
879272b676d7Smrg             visual->greenMask = pScrn->mask.green;
879372b676d7Smrg             visual->blueMask = pScrn->mask.blue;
879472b676d7Smrg          }
879572b676d7Smrg       }
879672b676d7Smrg    }
879772b676d7Smrg
879872b676d7Smrg    /* Initialize RENDER extension (must be after RGB ordering fixed) */
879972b676d7Smrg    fbPictureInit(pScreen, 0, 0);
880072b676d7Smrg
880172b676d7Smrg    /* Hardware cursor needs to wrap this layer */
880272b676d7Smrg    if(!pSiS->ShadowFB) SISDGAInit(pScreen);
880372b676d7Smrg
880472b676d7Smrg    xf86SetBlackWhitePixels(pScreen);
880572b676d7Smrg
880672b676d7Smrg    /* Initialize the accelerators */
880772b676d7Smrg    switch(pSiS->VGAEngine) {
880872b676d7Smrg    case SIS_530_VGA:
880972b676d7Smrg    case SIS_300_VGA:
881072b676d7Smrg       SiS300AccelInit(pScreen);
881172b676d7Smrg       break;
881272b676d7Smrg    case SIS_315_VGA:
881372b676d7Smrg       SiS315AccelInit(pScreen);
881472b676d7Smrg       break;
881572b676d7Smrg    default:
881672b676d7Smrg       SiSAccelInit(pScreen);
881772b676d7Smrg    }
881872b676d7Smrg
881972b676d7Smrg#ifdef TWDEBUG
882072b676d7Smrg    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CPUFlags %x\n", pSiS->CPUFlags);
882172b676d7Smrg#endif
882272b676d7Smrg
882372b676d7Smrg    /* Benchmark memcpy() methods (needs FB manager initialized) */
882472b676d7Smrg    /* Dual head: Do this AFTER the mode for CRT1 has been set */
882572b676d7Smrg    pSiS->NeedCopyFastVidCpy = FALSE;
882672b676d7Smrg    if(!pSiS->SiSFastVidCopyDone) {
882772b676d7Smrg#ifdef SISDUALHEAD
882872b676d7Smrg       if(pSiS->DualHeadMode) {
882972b676d7Smrg	  if(pSiS->SecondHead) {
883072b676d7Smrg	     pSiSEnt->SiSFastVidCopy = SiSVidCopyInit(pScreen, &pSiSEnt->SiSFastMemCopy, FALSE);
883172b676d7Smrg	     pSiSEnt->SiSFastVidCopyFrom = SiSVidCopyGetDefault();
883272b676d7Smrg	     pSiSEnt->SiSFastMemCopyFrom = SiSVidCopyGetDefault();
883372b676d7Smrg#ifdef SIS_USE_EXA
883472b676d7Smrg	     if(pSiS->useEXA) {
883572b676d7Smrg	        pSiSEnt->SiSFastVidCopyFrom = SiSVidCopyInit(pScreen, &pSiSEnt->SiSFastMemCopyFrom, TRUE);
883672b676d7Smrg	     }
883772b676d7Smrg#endif /* EXA */
883872b676d7Smrg	     pSiSEnt->HaveFastVidCpy = TRUE;
883972b676d7Smrg	     pSiS->SiSFastVidCopy = pSiSEnt->SiSFastVidCopy;
884072b676d7Smrg	     pSiS->SiSFastMemCopy = pSiSEnt->SiSFastMemCopy;
884172b676d7Smrg	     pSiS->SiSFastVidCopyFrom = pSiSEnt->SiSFastVidCopyFrom;
884272b676d7Smrg	     pSiS->SiSFastMemCopyFrom = pSiSEnt->SiSFastMemCopyFrom;
884372b676d7Smrg	  } else {
884472b676d7Smrg	     pSiS->NeedCopyFastVidCpy = TRUE;
884572b676d7Smrg	  }
884672b676d7Smrg       } else {
884772b676d7Smrg#endif
884872b676d7Smrg	  pSiS->SiSFastVidCopy = SiSVidCopyInit(pScreen, &pSiS->SiSFastMemCopy, FALSE);
884972b676d7Smrg	  pSiS->SiSFastVidCopyFrom = SiSVidCopyGetDefault();
885072b676d7Smrg	  pSiS->SiSFastMemCopyFrom = SiSVidCopyGetDefault();
885172b676d7Smrg#ifdef SIS_USE_EXA
885272b676d7Smrg	  if(pSiS->useEXA) {
885372b676d7Smrg	     pSiS->SiSFastVidCopyFrom = SiSVidCopyInit(pScreen, &pSiS->SiSFastMemCopyFrom, TRUE);
885472b676d7Smrg	  }
885572b676d7Smrg#endif /* EXA */
885672b676d7Smrg#ifdef SISDUALHEAD
885772b676d7Smrg       }
885872b676d7Smrg#endif
885972b676d7Smrg    }
886072b676d7Smrg    pSiS->SiSFastVidCopyDone = TRUE;
886172b676d7Smrg
886272b676d7Smrg    miInitializeBackingStore(pScreen);
886372b676d7Smrg    xf86SetBackingStore(pScreen);
886472b676d7Smrg    xf86SetSilkenMouse(pScreen);
886572b676d7Smrg
886672b676d7Smrg    /* Initialise cursor functions */
886772b676d7Smrg    miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
886872b676d7Smrg
886972b676d7Smrg    if(pSiS->HWCursor) {
887072b676d7Smrg       SiSHWCursorInit(pScreen);
887172b676d7Smrg    }
887272b676d7Smrg
887372b676d7Smrg#ifdef SISDUALHEAD
887472b676d7Smrg    if(!pSiS->DualHeadMode) {
887572b676d7Smrg#endif
887672b676d7Smrg       if((pSiS->VBFlags2 & VB2_SISBRIDGE) && (pScrn->depth > 8)) {
887772b676d7Smrg
887872b676d7Smrg	  pSiS->CRT2ColNum = 1 << pScrn->rgbBits;
887972b676d7Smrg
88805788ca14Smrg	  if((pSiS->crt2gcolortable = malloc(pSiS->CRT2ColNum * 2 * sizeof(LOCO)))) {
888172b676d7Smrg	     pSiS->crt2colors = &pSiS->crt2gcolortable[pSiS->CRT2ColNum];
88825788ca14Smrg	     if((pSiS->crt2cindices = malloc(256 * sizeof(int)))) {
888372b676d7Smrg		int i = pSiS->CRT2ColNum;
888472b676d7Smrg		SISCalculateGammaRampCRT2(pScrn);
888572b676d7Smrg		while(i--) pSiS->crt2cindices[i] = i;
888672b676d7Smrg	     } else {
88875788ca14Smrg		free(pSiS->crt2gcolortable);
888872b676d7Smrg		pSiS->crt2gcolortable = NULL;
888972b676d7Smrg		pSiS->CRT2SepGamma = FALSE;
889072b676d7Smrg	     }
889172b676d7Smrg	  } else {
889272b676d7Smrg	     pSiS->CRT2SepGamma = FALSE;
889372b676d7Smrg	  }
889472b676d7Smrg
889572b676d7Smrg	  if(!pSiS->crt2cindices) {
889672b676d7Smrg	     xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
889772b676d7Smrg	  	"Failed to allocate cmap for CRT2, separate gamma correction disabled\n");
889872b676d7Smrg	  }
889972b676d7Smrg
890072b676d7Smrg       }
890172b676d7Smrg#ifdef SISDUALHEAD
890272b676d7Smrg    } else pSiS->CRT2SepGamma = FALSE;
890372b676d7Smrg#endif
890472b676d7Smrg
890572b676d7Smrg    /* Initialise default colormap */
890672b676d7Smrg    if(!miCreateDefColormap(pScreen)) {
890772b676d7Smrg       SISSaveScreen(pScreen, SCREEN_SAVER_OFF);
890872b676d7Smrg       SISErrorLog(pScrn, "miCreateDefColormap() failed\n");
890972b676d7Smrg       return FALSE;
891072b676d7Smrg    }
891172b676d7Smrg
891272b676d7Smrg    if(!xf86HandleColormaps(pScreen, 256, (pScrn->depth == 8) ? 8 : pScrn->rgbBits,
891372b676d7Smrg                    SISLoadPalette, NULL,
891472b676d7Smrg                    CMAP_PALETTED_TRUECOLOR | CMAP_RELOAD_ON_MODE_SWITCH)) {
891572b676d7Smrg       SISSaveScreen(pScreen, SCREEN_SAVER_OFF);
891672b676d7Smrg       SISErrorLog(pScrn, "xf86HandleColormaps() failed\n");
891772b676d7Smrg       return FALSE;
891872b676d7Smrg    }
891972b676d7Smrg
892072b676d7Smrg    /* Recalculate our gamma ramp for brightness feature */
892172b676d7Smrg#ifdef SISGAMMARAMP
892272b676d7Smrg    if((pSiS->GammaBriR != 1000) ||
892372b676d7Smrg       (pSiS->GammaBriB != 1000) ||
892472b676d7Smrg       (pSiS->GammaBriG != 1000) ||
892572b676d7Smrg       (pSiS->NewGammaBriR != 0.0) ||
892672b676d7Smrg       (pSiS->NewGammaBriG != 0.0) ||
892772b676d7Smrg       (pSiS->NewGammaBriB != 0.0) ||
892872b676d7Smrg       (pSiS->NewGammaConR != 0.0) ||
892972b676d7Smrg       (pSiS->NewGammaConG != 0.0) ||
893072b676d7Smrg       (pSiS->NewGammaConB != 0.0)) {
893172b676d7Smrg       SISCalculateGammaRamp(pScreen, pScrn);
893272b676d7Smrg    }
893372b676d7Smrg#endif
893472b676d7Smrg
893572b676d7Smrg    /* Initialize Shadow framebuffer and screen rotation/reflection */
893672b676d7Smrg    if(pSiS->ShadowFB) {
893772b676d7Smrg       RefreshAreaFuncPtr refreshArea = SISRefreshArea;
893872b676d7Smrg
893972b676d7Smrg       if(pSiS->Rotate) {
894072b676d7Smrg	  if(!pSiS->PointerMoved) pSiS->PointerMoved = pScrn->PointerMoved;
894172b676d7Smrg	  pScrn->PointerMoved = SISPointerMoved;
894272b676d7Smrg	  switch(pScrn->bitsPerPixel) {
894372b676d7Smrg	     case 8:  refreshArea = SISRefreshArea8;  break;
894472b676d7Smrg	     case 16: refreshArea = SISRefreshArea16; break;
894572b676d7Smrg	     case 24: refreshArea = SISRefreshArea24; break;
894672b676d7Smrg	     case 32: refreshArea = SISRefreshArea32; break;
894772b676d7Smrg	  }
894872b676d7Smrg#if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4,3,0,0,0)
894972b676d7Smrg	  xf86DisableRandR();
895072b676d7Smrg	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
895172b676d7Smrg		"Driver rotation enabled, disabling RandR\n");
895272b676d7Smrg#endif
895372b676d7Smrg       } else if(pSiS->Reflect) {
895472b676d7Smrg          switch(pScrn->bitsPerPixel) {
895572b676d7Smrg	  case 8:
895672b676d7Smrg	  case 16:
895772b676d7Smrg	  case 32:
895872b676d7Smrg             if(!pSiS->PointerMoved) pSiS->PointerMoved = pScrn->PointerMoved;
895972b676d7Smrg	     pScrn->PointerMoved = SISPointerMovedReflect;
896072b676d7Smrg	     refreshArea = SISRefreshAreaReflect;
896172b676d7Smrg#if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4,3,0,0,0)
896272b676d7Smrg	     xf86DisableRandR();
896372b676d7Smrg	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
896472b676d7Smrg		  "Driver reflection enabled, disabling RandR\n");
896572b676d7Smrg#endif
896672b676d7Smrg	     break;
896772b676d7Smrg	  default:
896872b676d7Smrg	     xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
896972b676d7Smrg	     	  "Reflection not supported at this framebuffer depth\n");
897072b676d7Smrg	  }
897172b676d7Smrg       }
897272b676d7Smrg
897372b676d7Smrg       ShadowFBInit(pScreen, refreshArea);
897472b676d7Smrg    }
897572b676d7Smrg
897672b676d7Smrg    xf86DPMSInit(pScreen, (DPMSSetProcPtr)SISDisplayPowerManagementSet, 0);
897772b676d7Smrg
897872b676d7Smrg    /* Init memPhysBase and fbOffset in pScrn */
897972b676d7Smrg    pScrn->memPhysBase = pSiS->FbAddress;
898072b676d7Smrg    pScrn->fbOffset = 0;
898172b676d7Smrg
898272b676d7Smrg    /* Initialize Xv */
898372b676d7Smrg    pSiS->ResetXv = pSiS->ResetXvGamma = pSiS->ResetXvDisplay = NULL;
898472b676d7Smrg#if (XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4,3,99,0,0)) || (defined(XvExtension))
898572b676d7Smrg    if((!pSiS->NoXvideo) && (!(pSiS->SiS_SD2_Flags & SiS_SD2_NOOVERLAY))) {
898672b676d7Smrg
898772b676d7Smrg       if((pSiS->VGAEngine == SIS_300_VGA) ||
898872b676d7Smrg	  (pSiS->VGAEngine == SIS_315_VGA)) {
898972b676d7Smrg
899072b676d7Smrg	  const char *using = "Using SiS300/315/330/340 series HW Xv";
899172b676d7Smrg
899272b676d7Smrg#ifdef SISDUALHEAD
899372b676d7Smrg	  if(pSiS->DualHeadMode) {
899472b676d7Smrg	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
899572b676d7Smrg		    "%s on CRT%d\n", using, (pSiS->SecondHead ? 1 : 2));
899672b676d7Smrg	     if(!pSiS->hasTwoOverlays) {
899772b676d7Smrg		if( (pSiS->XvOnCRT2 && pSiS->SecondHead) ||
899872b676d7Smrg		    (!pSiS->XvOnCRT2 && !pSiS->SecondHead) ) {
899972b676d7Smrg		   xf86DrvMsg(pScrn->scrnIndex, X_INFO,
900072b676d7Smrg			   "However, video overlay will by default only be visible on CRT%d\n",
900172b676d7Smrg			   pSiS->XvOnCRT2 ? 2 : 1);
900272b676d7Smrg		}
900372b676d7Smrg	     }
900472b676d7Smrg	  } else {
900572b676d7Smrg#endif
900672b676d7Smrg	     if(pSiS->hasTwoOverlays) {
900772b676d7Smrg		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s\n", using);
900872b676d7Smrg	     } else {
900972b676d7Smrg		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s by default on CRT%d\n",
901072b676d7Smrg			using, (pSiS->XvOnCRT2 ? 2 : 1));
901172b676d7Smrg	     }
901272b676d7Smrg#ifdef SISDUALHEAD
901372b676d7Smrg	  }
901472b676d7Smrg#endif
901572b676d7Smrg
901672b676d7Smrg	  SISInitVideo(pScreen);
901772b676d7Smrg
901872b676d7Smrg	  if(pSiS->blitadaptor) {
901972b676d7Smrg	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
902072b676d7Smrg		     "Default Xv adaptor is Video %s\n",
902172b676d7Smrg		     pSiS->XvDefAdaptorBlit ? "Blitter" : "Overlay");
902272b676d7Smrg	  }
902372b676d7Smrg
902472b676d7Smrg       } else if(pSiS->Chipset == PCI_CHIP_SIS530  ||
902572b676d7Smrg		 pSiS->Chipset == PCI_CHIP_SIS6326 ||
902672b676d7Smrg		 pSiS->Chipset == PCI_CHIP_SIS5597) {
902772b676d7Smrg
902872b676d7Smrg	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
902972b676d7Smrg		        "Using SiS5597/5598/6326/530/620 HW Xv\n" );
903072b676d7Smrg
903172b676d7Smrg	  SIS6326InitVideo(pScreen);
903272b676d7Smrg
903372b676d7Smrg       } else { /* generic Xv */
903472b676d7Smrg
903572b676d7Smrg	  XF86VideoAdaptorPtr *ptr;
903672b676d7Smrg	  int n = xf86XVListGenericAdaptors(pScrn, &ptr);
903772b676d7Smrg
903872b676d7Smrg	  if(n) {
903972b676d7Smrg	     xf86XVScreenInit(pScreen, ptr, n);
904072b676d7Smrg	     xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using generic Xv\n" );
904172b676d7Smrg          }
904272b676d7Smrg
904372b676d7Smrg       }
904472b676d7Smrg    }
904572b676d7Smrg#endif
904672b676d7Smrg
90475788ca14Smrg#ifdef SISDRI
904872b676d7Smrg    if(pSiS->loadDRI) {
904972b676d7Smrg       if(pSiS->directRenderingEnabled) {
905072b676d7Smrg          /* Now that mi, drm and others have done their thing,
905172b676d7Smrg           * complete the DRI setup.
905272b676d7Smrg           */
905372b676d7Smrg          pSiS->directRenderingEnabled = SISDRIFinishScreenInit(pScreen);
905472b676d7Smrg       }
905572b676d7Smrg       xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Direct rendering %s\n",
905672b676d7Smrg		pSiS->directRenderingEnabled ? "enabled" : "disabled");
905772b676d7Smrg       /* TODO */
905872b676d7Smrg       /* if(pSiS->directRenderingEnabled) SISSetLFBConfig(pSiS); */
905972b676d7Smrg    }
906072b676d7Smrg#endif
906172b676d7Smrg
906272b676d7Smrg    /* Wrap some funcs, initialize pseudo-Xinerama and setup remaining SD flags */
906372b676d7Smrg
906472b676d7Smrg    pSiS->SiS_SD_Flags &= ~(SiS_SD_PSEUDOXINERAMA);
906572b676d7Smrg#ifdef SISMERGED
906672b676d7Smrg    if(pSiS->MergedFB) {
906772b676d7Smrg       pSiS->PointerMoved = pScrn->PointerMoved;
906872b676d7Smrg       pScrn->PointerMoved = SISMergedPointerMoved;
906972b676d7Smrg       pSiS->Rotate = 0;
907072b676d7Smrg       pSiS->Reflect = 0;
907172b676d7Smrg       pSiS->ShadowFB = FALSE;
907272b676d7Smrg#if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4,3,0,0,0)
907372b676d7Smrg       if(pSiS->CRT1XOffs || pSiS->CRT1YOffs || pSiS->CRT2XOffs || pSiS->CRT2YOffs) {
907472b676d7Smrg	  xf86DisableRandR();
907572b676d7Smrg	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
907672b676d7Smrg		"MergedFB: CRT2Position offset used, disabling RandR\n");
907772b676d7Smrg       }
907872b676d7Smrg#endif
907972b676d7Smrg#ifdef SISXINERAMA
908072b676d7Smrg       if(pSiS->UseSiSXinerama) {
908172b676d7Smrg	  SiSnoPanoramiXExtension = FALSE;
908272b676d7Smrg	  SiSXineramaExtensionInit(pScrn);
908372b676d7Smrg	  if(!SiSnoPanoramiXExtension) {
908472b676d7Smrg	     pSiS->SiS_SD_Flags |= SiS_SD_PSEUDOXINERAMA;
908572b676d7Smrg	     if(pSiS->HaveNonRect) {
908672b676d7Smrg		/* Reset the viewport (now eventually non-recangular) */
90875788ca14Smrg		SISAdjustFrame(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0));
908872b676d7Smrg	     }
908972b676d7Smrg	  }
909072b676d7Smrg       } else {
909172b676d7Smrg	  pSiS->MouseRestrictions = FALSE;
909272b676d7Smrg       }
909372b676d7Smrg#endif
909472b676d7Smrg    }
909572b676d7Smrg#endif
909672b676d7Smrg
909772b676d7Smrg    /* Wrap CloseScreen and set up SaveScreen */
909872b676d7Smrg    pSiS->CloseScreen = pScreen->CloseScreen;
909972b676d7Smrg    pScreen->CloseScreen = SISCloseScreen;
910072b676d7Smrg#ifdef SISDUALHEAD
910172b676d7Smrg    if(pSiS->DualHeadMode)
910272b676d7Smrg       pScreen->SaveScreen = SISSaveScreenDH;
910372b676d7Smrg    else
910472b676d7Smrg#endif
910572b676d7Smrg       pScreen->SaveScreen = SISSaveScreen;
910672b676d7Smrg
910772b676d7Smrg    /* Install BlockHandler */
910872b676d7Smrg    pSiS->BlockHandler = pScreen->BlockHandler;
910972b676d7Smrg    pScreen->BlockHandler = SISBlockHandler;
911072b676d7Smrg
911172b676d7Smrg    /* Report any unused options (only for the first generation) */
911272b676d7Smrg    if(serverGeneration == 1) {
911372b676d7Smrg       xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
911472b676d7Smrg    }
911572b676d7Smrg
911672b676d7Smrg    /* Clear frame buffer */
911772b676d7Smrg    /* For CRT2, we don't do that at this point in dual head
911872b676d7Smrg     * mode since the mode isn't switched at this time (it will
911972b676d7Smrg     * be reset when setting the CRT1 mode). Hence, we just
912072b676d7Smrg     * save the necessary data and clear the screen when
912172b676d7Smrg     * going through this for CRT1.
912272b676d7Smrg     */
912372b676d7Smrg
912472b676d7Smrg    OnScreenSize = pScrn->displayWidth * pScrn->currentMode->VDisplay
912572b676d7Smrg                               * (pScrn->bitsPerPixel >> 3);
912672b676d7Smrg
912772b676d7Smrg    /* Turn on the screen now */
912872b676d7Smrg    /* We do this in dual head mode after second head is finished */
912972b676d7Smrg#ifdef SISDUALHEAD
913072b676d7Smrg    if(pSiS->DualHeadMode) {
913172b676d7Smrg       if(pSiS->SecondHead) {
913272b676d7Smrg	  sisclearvram(pSiS->FbBase, OnScreenSize);
913372b676d7Smrg	  sisclearvram(pSiSEnt->FbBase1, pSiSEnt->OnScreenSize1);
913472b676d7Smrg	  SISSaveScreen(pScreen, SCREEN_SAVER_OFF);
913572b676d7Smrg       } else {
913672b676d7Smrg	  pSiSEnt->FbBase1 = pSiS->FbBase;
913772b676d7Smrg	  pSiSEnt->OnScreenSize1 = OnScreenSize;
913872b676d7Smrg       }
913972b676d7Smrg    } else {
914072b676d7Smrg#endif
914172b676d7Smrg       SISSaveScreen(pScreen, SCREEN_SAVER_OFF);
914272b676d7Smrg       sisclearvram(pSiS->FbBase, OnScreenSize);
914372b676d7Smrg#ifdef SISDUALHEAD
914472b676d7Smrg    }
914572b676d7Smrg#endif
914672b676d7Smrg
914772b676d7Smrg    pSiS->SiS_SD_Flags &= ~SiS_SD_SUPPORTSGRCRT2;
914872b676d7Smrg#ifdef SISDUALHEAD
914972b676d7Smrg    if(!pSiS->DualHeadMode) {
915072b676d7Smrg#endif
915172b676d7Smrg       if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
915272b676d7Smrg          if((pSiS->crt2cindices) && (pSiS->crt2gcolortable)) {
915372b676d7Smrg             pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTSGRCRT2;
915472b676d7Smrg	  }
915572b676d7Smrg       }
915672b676d7Smrg#ifdef SISDUALHEAD
915772b676d7Smrg    }
915872b676d7Smrg#endif
915972b676d7Smrg
916072b676d7Smrg    pSiS->SiS_SD_Flags &= ~SiS_SD_ISDEPTH8;
916172b676d7Smrg    if(pSiS->CurrentLayout.bitsPerPixel == 8) {
916272b676d7Smrg       pSiS->SiS_SD_Flags |= SiS_SD_ISDEPTH8;
916372b676d7Smrg       pSiS->SiS_SD_Flags &= ~SiS_SD_SUPPORTXVGAMMA1;
916472b676d7Smrg       pSiS->SiS_SD_Flags &= ~SiS_SD_SUPPORTSGRCRT2;
916572b676d7Smrg    }
916672b676d7Smrg
916772b676d7Smrg#ifdef SISGAMMARAMP
916872b676d7Smrg    pSiS->SiS_SD_Flags |= SiS_SD_CANSETGAMMA;
916972b676d7Smrg#else
917072b676d7Smrg    pSiS->SiS_SD_Flags &= ~SiS_SD_CANSETGAMMA;
917172b676d7Smrg#endif
917272b676d7Smrg
917372b676d7Smrg    SiSCtrlExtInit(pScrn);
917472b676d7Smrg
917572b676d7Smrg    return TRUE;
917672b676d7Smrg}
917772b676d7Smrg
917872b676d7Smrg/* Usually mandatory */
917972b676d7SmrgBool
91805788ca14SmrgSISSwitchMode(SWITCH_MODE_ARGS_DECL)
918172b676d7Smrg{
91825788ca14Smrg    SCRN_INFO_PTR(arg);
918372b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
918472b676d7Smrg
918572b676d7Smrg    if(!pSiS->skipswitchcheck) {
91865788ca14Smrg       if(SISValidMode(arg, mode, TRUE, 0) != MODE_OK) {
918772b676d7Smrg          return FALSE;
918872b676d7Smrg       }
918972b676d7Smrg    }
919072b676d7Smrg
919172b676d7Smrg    (*pSiS->SyncAccel)(pScrn);
919272b676d7Smrg
91935788ca14Smrg    if(!(SISModeInit(pScrn, mode))) return FALSE;
919472b676d7Smrg
919572b676d7Smrg    /* Since RandR (indirectly) uses SwitchMode(), we need to
919672b676d7Smrg     * update our Xinerama info here, too, in case of resizing
919772b676d7Smrg     */
919872b676d7Smrg#ifdef SISMERGED
919972b676d7Smrg#ifdef SISXINERAMA
920072b676d7Smrg    if(pSiS->MergedFB) {
920172b676d7Smrg       SiSUpdateXineramaScreenInfo(pScrn);
920272b676d7Smrg    }
920372b676d7Smrg#endif
920472b676d7Smrg#endif
920572b676d7Smrg    return TRUE;
920672b676d7Smrg}
920772b676d7Smrg
920872b676d7Smrgstatic void
920972b676d7SmrgSISSetStartAddressCRT1(SISPtr pSiS, ULong base)
921072b676d7Smrg{
921172b676d7Smrg    UChar cr11backup;
921272b676d7Smrg
921372b676d7Smrg    inSISIDXREG(SISCR,  0x11, cr11backup);  /* Unlock CRTC registers */
921472b676d7Smrg    andSISIDXREG(SISCR, 0x11, 0x7F);
921572b676d7Smrg    outSISIDXREG(SISCR, 0x0D, base & 0xFF);
921672b676d7Smrg    outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF);
921772b676d7Smrg    outSISIDXREG(SISSR, 0x0D, (base >> 16) & 0xFF);
921872b676d7Smrg    if(pSiS->VGAEngine == SIS_315_VGA) {
921972b676d7Smrg       setSISIDXREG(SISSR, 0x37, 0xFE, (base >> 24) & 0x01);
922072b676d7Smrg    }
922172b676d7Smrg    /* Eventually lock CRTC registers */
922272b676d7Smrg    setSISIDXREG(SISCR, 0x11, 0x7F,(cr11backup & 0x80));
922372b676d7Smrg}
922472b676d7Smrg
922572b676d7Smrgstatic void
922672b676d7SmrgSISSetStartAddressCRT2(SISPtr pSiS, ULong base)
922772b676d7Smrg{
922872b676d7Smrg    SiS_UnLockCRT2(pSiS->SiS_Pr);
922972b676d7Smrg    outSISIDXREG(SISPART1, 0x06, GETVAR8(base));
923072b676d7Smrg    outSISIDXREG(SISPART1, 0x05, GETBITS(base, 15:8));
923172b676d7Smrg    outSISIDXREG(SISPART1, 0x04, GETBITS(base, 23:16));
923272b676d7Smrg    if(pSiS->VGAEngine == SIS_315_VGA) {
923372b676d7Smrg       setSISIDXREG(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7);
923472b676d7Smrg    }
923572b676d7Smrg    SiS_LockCRT2(pSiS->SiS_Pr);
923672b676d7Smrg}
923772b676d7Smrg
923872b676d7Smrg#ifdef SISMERGED
923972b676d7Smrgstatic Bool
924072b676d7SmrgInRegion(int x, int y, region r)
924172b676d7Smrg{
924272b676d7Smrg    return (r.x0 <= x) && (x <= r.x1) && (r.y0 <= y) && (y <= r.y1);
924372b676d7Smrg}
924472b676d7Smrg
924572b676d7Smrgstatic void
924672b676d7SmrgSISAdjustFrameHW_CRT1(ScrnInfoPtr pScrn, int x, int y)
924772b676d7Smrg{
924872b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
924972b676d7Smrg    ULong base;
925072b676d7Smrg
925172b676d7Smrg    base = y * pSiS->CurrentLayout.displayWidth + x;
925272b676d7Smrg    switch(pSiS->CurrentLayout.bitsPerPixel) {
925372b676d7Smrg       case 16:  base >>= 1; 	break;
925472b676d7Smrg       case 32:  		break;
925572b676d7Smrg       default:  base >>= 2;
925672b676d7Smrg    }
925772b676d7Smrg    base += (pSiS->dhmOffset/4);
925872b676d7Smrg    SISSetStartAddressCRT1(pSiS, base);
925972b676d7Smrg}
926072b676d7Smrg
926172b676d7Smrgstatic void
926272b676d7SmrgSISAdjustFrameHW_CRT2(ScrnInfoPtr pScrn, int x, int y)
926372b676d7Smrg{
926472b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
926572b676d7Smrg    ULong base;
926672b676d7Smrg
926772b676d7Smrg    base = y * pSiS->CurrentLayout.displayWidth + x;
926872b676d7Smrg    switch(pSiS->CurrentLayout.bitsPerPixel) {
926972b676d7Smrg       case 16:  base >>= 1; 	break;
927072b676d7Smrg       case 32:  		break;
927172b676d7Smrg       default:  base >>= 2;
927272b676d7Smrg    }
927372b676d7Smrg    base += (pSiS->dhmOffset/4);
927472b676d7Smrg    SISSetStartAddressCRT2(pSiS, base);
927572b676d7Smrg}
927672b676d7Smrg
927772b676d7Smrgstatic void
92785788ca14SmrgSISMergedPointerMoved(SCRN_ARG_TYPE arg, int x, int y)
927972b676d7Smrg{
92805788ca14Smrg  SCRN_INFO_PTR(arg);
92815788ca14Smrg  ScrnInfoPtr	pScrn1 = pScrn;
928272b676d7Smrg  SISPtr	pSiS = SISPTR(pScrn1);
928372b676d7Smrg  ScrnInfoPtr	pScrn2 = pSiS->CRT2pScrn;
928472b676d7Smrg  region	out, in1, in2, f2, f1;
928572b676d7Smrg  int		deltax, deltay;
928672b676d7Smrg  int		temp1, temp2;
928772b676d7Smrg  int		old1x0, old1y0, old2x0, old2y0;
928872b676d7Smrg  int		CRT1XOffs = 0, CRT1YOffs = 0, CRT2XOffs = 0, CRT2YOffs = 0;
928972b676d7Smrg  int		HVirt = pScrn1->virtualX;
929072b676d7Smrg  int		VVirt = pScrn1->virtualY;
929172b676d7Smrg  int		sigstate;
929272b676d7Smrg  Bool		doit = FALSE, HaveNonRect = FALSE, HaveOffsRegions = FALSE;
929372b676d7Smrg  SiSScrn2Rel   srel = ((SiSMergedDisplayModePtr)pSiS->CurrentLayout.mode->Private)->CRT2Position;
929472b676d7Smrg
929572b676d7Smrg  if(pSiS->DGAactive) {
929672b676d7Smrg     return;
929772b676d7Smrg     /* DGA: There is no cursor and no panning while DGA is active. */
929872b676d7Smrg     /* If it were, we would need to do: */
929972b676d7Smrg     /* HVirt = pSiS->CurrentLayout.displayWidth;
930072b676d7Smrg        VVirt = pSiS->CurrentLayout.displayHeight;
930172b676d7Smrg        BOUND(x, pSiS->CurrentLayout.DGAViewportX, HVirt);
930272b676d7Smrg        BOUND(y, pSiS->CurrentLayout.DGAViewportY, VVirt); */
930372b676d7Smrg  } else {
930472b676d7Smrg     CRT1XOffs = pSiS->CRT1XOffs;
930572b676d7Smrg     CRT1YOffs = pSiS->CRT1YOffs;
930672b676d7Smrg     CRT2XOffs = pSiS->CRT2XOffs;
930772b676d7Smrg     CRT2YOffs = pSiS->CRT2YOffs;
930872b676d7Smrg     HaveNonRect = pSiS->HaveNonRect;
930972b676d7Smrg     HaveOffsRegions = pSiS->HaveOffsRegions;
931072b676d7Smrg  }
931172b676d7Smrg
931272b676d7Smrg  /* Check if the pointer is inside our dead areas */
931372b676d7Smrg  if((pSiS->MouseRestrictions) && (srel != sisClone) && !SiSnoPanoramiXExtension) {
931472b676d7Smrg     if(HaveNonRect) {
931572b676d7Smrg	if(InRegion(x, y, pSiS->NonRectDead)) {
931672b676d7Smrg	   switch(srel) {
931772b676d7Smrg	   case sisLeftOf:
931872b676d7Smrg	   case sisRightOf: y = pSiS->NonRectDead.y0 - 1;
931972b676d7Smrg			    doit = TRUE;
932072b676d7Smrg			    break;
932172b676d7Smrg	   case sisAbove:
932272b676d7Smrg	   case sisBelow:   x = pSiS->NonRectDead.x0 - 1;
932372b676d7Smrg			    doit = TRUE;
932472b676d7Smrg	   default:	    break;
932572b676d7Smrg	   }
932672b676d7Smrg	}
932772b676d7Smrg     }
932872b676d7Smrg     if(HaveOffsRegions) {
932972b676d7Smrg	if(InRegion(x, y, pSiS->OffDead1)) {
933072b676d7Smrg	   switch(srel) {
933172b676d7Smrg	   case sisLeftOf:
933272b676d7Smrg	   case sisRightOf: y = pSiS->OffDead1.y1;
933372b676d7Smrg			    doit = TRUE;
933472b676d7Smrg			    break;
933572b676d7Smrg	   case sisAbove:
933672b676d7Smrg	   case sisBelow:   x = pSiS->OffDead1.x1;
933772b676d7Smrg			    doit = TRUE;
933872b676d7Smrg	   default:	    break;
933972b676d7Smrg	   }
934072b676d7Smrg	} else if(InRegion(x, y, pSiS->OffDead2)) {
934172b676d7Smrg	   switch(srel) {
934272b676d7Smrg	   case sisLeftOf:
934372b676d7Smrg	   case sisRightOf: y = pSiS->OffDead2.y0 - 1;
934472b676d7Smrg			    doit = TRUE;
934572b676d7Smrg			    break;
934672b676d7Smrg	   case sisAbove:
934772b676d7Smrg	   case sisBelow:   x = pSiS->OffDead2.x0 - 1;
934872b676d7Smrg			    doit = TRUE;
934972b676d7Smrg	   default:	    break;
935072b676d7Smrg	   }
935172b676d7Smrg	}
935272b676d7Smrg     }
935372b676d7Smrg     if(doit) {
935472b676d7Smrg	sigstate = xf86BlockSIGIO();
93555788ca14Smrg#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 15
93565788ca14Smrg        {
93575788ca14Smrg            double dx = x, dy = y;
93585788ca14Smrg            miPointerSetPosition(inputInfo.pointer, Absolute, &dx, &dy);
93595788ca14Smrg            x = (int)dx;
93605788ca14Smrg            y = (int)dy;
93615788ca14Smrg        }
93625788ca14Smrg#elif GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 13
93635788ca14Smrg	miPointerSetPosition(inputInfo.pointer, Absolute, x, y);
93645788ca14Smrg#elif GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 5
9365256c1e2bSmrg	miPointerSetPosition(inputInfo.pointer, &x, &y);
93665788ca14Smrg#else
93675788ca14Smrg	UpdateCurrentTime();
93685788ca14Smrg	miPointerAbsoluteCursor(x, y, currentTime.milliseconds);
93695788ca14Smrg#endif
937072b676d7Smrg	xf86UnblockSIGIO(sigstate);
937172b676d7Smrg	return;
937272b676d7Smrg     }
937372b676d7Smrg  }
937472b676d7Smrg
937572b676d7Smrg  f1.x0 = old1x0 = pSiS->CRT1frameX0;
937672b676d7Smrg  f1.x1 = pSiS->CRT1frameX1;
937772b676d7Smrg  f1.y0 = old1y0 = pSiS->CRT1frameY0;
937872b676d7Smrg  f1.y1 = pSiS->CRT1frameY1;
937972b676d7Smrg  f2.x0 = old2x0 = pScrn2->frameX0;
938072b676d7Smrg  f2.x1 = pScrn2->frameX1;
938172b676d7Smrg  f2.y0 = old2y0 = pScrn2->frameY0;
938272b676d7Smrg  f2.y1 = pScrn2->frameY1;
938372b676d7Smrg
938472b676d7Smrg  /* Define the outer region. Crossing this causes all frames to move */
938572b676d7Smrg  out.x0 = pScrn1->frameX0;
938672b676d7Smrg  out.x1 = pScrn1->frameX1;
938772b676d7Smrg  out.y0 = pScrn1->frameY0;
938872b676d7Smrg  out.y1 = pScrn1->frameY1;
938972b676d7Smrg
939072b676d7Smrg  /*
939172b676d7Smrg   * Define the inner sliding window. Being outsize both frames but
939272b676d7Smrg   * inside the outer clipping window will slide corresponding frame
939372b676d7Smrg   */
939472b676d7Smrg  in1 = out;
939572b676d7Smrg  in2 = out;
939672b676d7Smrg  switch(srel) {
939772b676d7Smrg     case sisLeftOf:
939872b676d7Smrg        in1.x0 = f1.x0;
939972b676d7Smrg        in2.x1 = f2.x1;
940072b676d7Smrg        break;
940172b676d7Smrg     case sisRightOf:
940272b676d7Smrg        in1.x1 = f1.x1;
940372b676d7Smrg        in2.x0 = f2.x0;
940472b676d7Smrg        break;
940572b676d7Smrg     case sisBelow:
940672b676d7Smrg        in1.y1 = f1.y1;
940772b676d7Smrg        in2.y0 = f2.y0;
940872b676d7Smrg        break;
940972b676d7Smrg     case sisAbove:
941072b676d7Smrg        in1.y0 = f1.y0;
941172b676d7Smrg        in2.y1 = f2.y1;
941272b676d7Smrg        break;
941372b676d7Smrg     case sisClone:
941472b676d7Smrg        break;
941572b676d7Smrg  }
941672b676d7Smrg
941772b676d7Smrg  deltay = 0;
941872b676d7Smrg  deltax = 0;
941972b676d7Smrg
942072b676d7Smrg  if(InRegion(x, y, out)) {	/* inside outer region */
942172b676d7Smrg
942272b676d7Smrg     if(InRegion(x, y, in1) && !InRegion(x, y, f1)) {
942372b676d7Smrg	REBOUND(f1.x0, f1.x1, x);
942472b676d7Smrg	REBOUND(f1.y0, f1.y1, y);
942572b676d7Smrg	deltax = 1;
942672b676d7Smrg     }
942772b676d7Smrg     if(InRegion(x, y, in2) && !InRegion(x, y, f2)) {
942872b676d7Smrg	REBOUND(f2.x0, f2.x1, x);
942972b676d7Smrg	REBOUND(f2.y0, f2.y1, y);
943072b676d7Smrg	deltax = 1;
943172b676d7Smrg     }
943272b676d7Smrg
943372b676d7Smrg  } else {			/* outside outer region */
943472b676d7Smrg
943572b676d7Smrg     if(out.x0 > x) {
943672b676d7Smrg	deltax = x - out.x0;
943772b676d7Smrg     }
943872b676d7Smrg     if(out.x1 < x) {
943972b676d7Smrg	deltax = x - out.x1;
944072b676d7Smrg     }
944172b676d7Smrg     if(deltax) {
944272b676d7Smrg	pScrn1->frameX0 += deltax;
944372b676d7Smrg	pScrn1->frameX1 += deltax;
944472b676d7Smrg	f1.x0 += deltax;
944572b676d7Smrg	f1.x1 += deltax;
944672b676d7Smrg	f2.x0 += deltax;
944772b676d7Smrg	f2.x1 += deltax;
944872b676d7Smrg     }
944972b676d7Smrg
945072b676d7Smrg     if(out.y0 > y) {
945172b676d7Smrg	deltay = y - out.y0;
945272b676d7Smrg     }
945372b676d7Smrg     if(out.y1 < y) {
945472b676d7Smrg	deltay = y - out.y1;
945572b676d7Smrg     }
945672b676d7Smrg     if(deltay) {
945772b676d7Smrg	pScrn1->frameY0 += deltay;
945872b676d7Smrg	pScrn1->frameY1 += deltay;
945972b676d7Smrg	f1.y0 += deltay;
946072b676d7Smrg	f1.y1 += deltay;
946172b676d7Smrg	f2.y0 += deltay;
946272b676d7Smrg	f2.y1 += deltay;
946372b676d7Smrg     }
946472b676d7Smrg
946572b676d7Smrg     switch(srel) {
946672b676d7Smrg	case sisLeftOf:
946772b676d7Smrg	   if(x >= f1.x0) { REBOUND(f1.y0, f1.y1, y); }
946872b676d7Smrg	   if(x <= f2.x1) { REBOUND(f2.y0, f2.y1, y); }
946972b676d7Smrg	   break;
947072b676d7Smrg	case sisRightOf:
947172b676d7Smrg	   if(x <= f1.x1) { REBOUND(f1.y0, f1.y1, y); }
947272b676d7Smrg	   if(x >= f2.x0) { REBOUND(f2.y0, f2.y1, y); }
947372b676d7Smrg	   break;
947472b676d7Smrg	case sisBelow:
947572b676d7Smrg	   if(y <= f1.y1) { REBOUND(f1.x0, f1.x1, x); }
947672b676d7Smrg	   if(y >= f2.y0) { REBOUND(f2.x0, f2.x1, x); }
947772b676d7Smrg	   break;
947872b676d7Smrg	case sisAbove:
947972b676d7Smrg	   if(y >= f1.y0) { REBOUND(f1.x0, f1.x1, x); }
948072b676d7Smrg	   if(y <= f2.y1) { REBOUND(f2.x0, f2.x1, x); }
948172b676d7Smrg	   break;
948272b676d7Smrg	case sisClone:
948372b676d7Smrg	   break;
948472b676d7Smrg     }
948572b676d7Smrg
948672b676d7Smrg  }
948772b676d7Smrg
948872b676d7Smrg  if(deltax || deltay) {
948972b676d7Smrg     pSiS->CRT1frameX0 = f1.x0;
949072b676d7Smrg     pSiS->CRT1frameY0 = f1.y0;
949172b676d7Smrg     pScrn2->frameX0 = f2.x0;
949272b676d7Smrg     pScrn2->frameY0 = f2.y0;
949372b676d7Smrg
949472b676d7Smrg     switch(srel) {
949572b676d7Smrg	case sisLeftOf:
949672b676d7Smrg	case sisRightOf:
949772b676d7Smrg	   if(CRT1YOffs || CRT2YOffs || HaveNonRect) {
949872b676d7Smrg	      if(pSiS->CRT1frameY0 != old1y0) {
949972b676d7Smrg	         if(pSiS->CRT1frameY0 < CRT1YOffs)
950072b676d7Smrg	            pSiS->CRT1frameY0 = CRT1YOffs;
950172b676d7Smrg
950272b676d7Smrg	         temp1 = pSiS->CRT1frameY0 + CDMPTR->CRT1->VDisplay;
950372b676d7Smrg	         temp2 = min((VVirt - CRT2YOffs), (CRT1YOffs + pSiS->MBXNR1YMAX));
950472b676d7Smrg	         if(temp1 > temp2)
950572b676d7Smrg	            pSiS->CRT1frameY0 -= (temp1 - temp2);
950672b676d7Smrg	      }
950772b676d7Smrg	      if(pScrn2->frameY0 != old2y0) {
950872b676d7Smrg	         if(pScrn2->frameY0 < CRT2YOffs)
950972b676d7Smrg	            pScrn2->frameY0 = CRT2YOffs;
951072b676d7Smrg
951172b676d7Smrg	         temp1 = pScrn2->frameY0 + CDMPTR->CRT2->VDisplay;
951272b676d7Smrg	         temp2 = min((VVirt - CRT1YOffs), (CRT2YOffs + pSiS->MBXNR2YMAX));
951372b676d7Smrg	         if(temp1 > temp2)
951472b676d7Smrg	            pScrn2->frameY0 -= (temp1 - temp2);
951572b676d7Smrg	      }
951672b676d7Smrg	   }
951772b676d7Smrg	   break;
951872b676d7Smrg	case sisBelow:
951972b676d7Smrg	case sisAbove:
952072b676d7Smrg	   if(CRT1XOffs || CRT2XOffs || HaveNonRect) {
952172b676d7Smrg	      if(pSiS->CRT1frameX0 != old1x0) {
952272b676d7Smrg	         if(pSiS->CRT1frameX0 < CRT1XOffs)
952372b676d7Smrg	            pSiS->CRT1frameX0 = CRT1XOffs;
952472b676d7Smrg
952572b676d7Smrg	         temp1 = pSiS->CRT1frameX0 + CDMPTR->CRT1->HDisplay;
952672b676d7Smrg	         temp2 = min((HVirt - CRT2XOffs), (CRT1XOffs + pSiS->MBXNR1XMAX));
952772b676d7Smrg	         if(temp1 > temp2)
952872b676d7Smrg	            pSiS->CRT1frameX0 -= (temp1 - temp2);
952972b676d7Smrg	      }
953072b676d7Smrg	      if(pScrn2->frameX0 != old2x0) {
953172b676d7Smrg	         if(pScrn2->frameX0 < CRT2XOffs)
953272b676d7Smrg	            pScrn2->frameX0 = CRT2XOffs;
953372b676d7Smrg
953472b676d7Smrg	         temp1 = pScrn2->frameX0 + CDMPTR->CRT2->HDisplay;
953572b676d7Smrg	         temp2 = min((HVirt - CRT1XOffs), (CRT2XOffs + pSiS->MBXNR2XMAX));
953672b676d7Smrg	         if(temp1 > temp2)
953772b676d7Smrg	            pScrn2->frameX0 -= (temp1 - temp2);
953872b676d7Smrg	      }
953972b676d7Smrg	   }
954072b676d7Smrg	   break;
954172b676d7Smrg	case sisClone:
954272b676d7Smrg	   break;
954372b676d7Smrg     }
954472b676d7Smrg
954572b676d7Smrg     pSiS->CRT1frameX1 = pSiS->CRT1frameX0 + CDMPTR->CRT1->HDisplay - 1;
954672b676d7Smrg     pSiS->CRT1frameY1 = pSiS->CRT1frameY0 + CDMPTR->CRT1->VDisplay - 1;
954772b676d7Smrg     pScrn2->frameX1   = pScrn2->frameX0   + CDMPTR->CRT2->HDisplay - 1;
954872b676d7Smrg     pScrn2->frameY1   = pScrn2->frameY0   + CDMPTR->CRT2->VDisplay - 1;
954972b676d7Smrg
955072b676d7Smrg     /* No need to update pScrn1->frame?1, done above */
955172b676d7Smrg
955272b676d7Smrg     SISAdjustFrameHW_CRT1(pScrn1, pSiS->CRT1frameX0, pSiS->CRT1frameY0);
955372b676d7Smrg     SISAdjustFrameHW_CRT2(pScrn1, pScrn2->frameX0, pScrn2->frameY0);
955472b676d7Smrg  }
955572b676d7Smrg}
955672b676d7Smrg
955772b676d7Smrgstatic void
95585788ca14SmrgSISAdjustFrameMerged(ADJUST_FRAME_ARGS_DECL)
955972b676d7Smrg{
95605788ca14Smrg    SCRN_INFO_PTR(arg);
95615788ca14Smrg    ScrnInfoPtr pScrn1 = pScrn;
956272b676d7Smrg    SISPtr pSiS = SISPTR(pScrn1);
956372b676d7Smrg    ScrnInfoPtr pScrn2 = pSiS->CRT2pScrn;
956472b676d7Smrg    int HTotal = pSiS->CurrentLayout.mode->HDisplay;
956572b676d7Smrg    int VTotal = pSiS->CurrentLayout.mode->VDisplay;
956672b676d7Smrg    int HMax = HTotal;
956772b676d7Smrg    int VMax = VTotal;
956872b676d7Smrg    int HVirt = pScrn1->virtualX;
956972b676d7Smrg    int VVirt = pScrn1->virtualY;
957072b676d7Smrg    int x1 = x, x2 = x;
957172b676d7Smrg    int y1 = y, y2 = y;
957272b676d7Smrg    int CRT1XOffs = 0, CRT1YOffs = 0, CRT2XOffs = 0, CRT2YOffs = 0;
957372b676d7Smrg    int MBXNR1XMAX = 65536, MBXNR1YMAX = 65536, MBXNR2XMAX = 65536, MBXNR2YMAX = 65536;
957472b676d7Smrg
957572b676d7Smrg    if(pSiS->DGAactive) {
957672b676d7Smrg       HVirt = pSiS->CurrentLayout.displayWidth;
957772b676d7Smrg       VVirt = pSiS->CurrentLayout.displayHeight;
957872b676d7Smrg    } else {
957972b676d7Smrg       CRT1XOffs = pSiS->CRT1XOffs;
958072b676d7Smrg       CRT1YOffs = pSiS->CRT1YOffs;
958172b676d7Smrg       CRT2XOffs = pSiS->CRT2XOffs;
958272b676d7Smrg       CRT2YOffs = pSiS->CRT2YOffs;
958372b676d7Smrg       MBXNR1XMAX = pSiS->MBXNR1XMAX;
958472b676d7Smrg       MBXNR1YMAX = pSiS->MBXNR1YMAX;
958572b676d7Smrg       MBXNR2XMAX = pSiS->MBXNR2XMAX;
958672b676d7Smrg       MBXNR2YMAX = pSiS->MBXNR2YMAX;
958772b676d7Smrg    }
958872b676d7Smrg
958972b676d7Smrg    BOUND(x, 0, HVirt - HTotal);
959072b676d7Smrg    BOUND(y, 0, VVirt - VTotal);
959172b676d7Smrg    if(SDMPTR(pScrn1)->CRT2Position != sisClone) {
959272b676d7Smrg       BOUND(x1, CRT1XOffs, min(HVirt, MBXNR1XMAX + CRT1XOffs) - min(HTotal, MBXNR1XMAX) - CRT2XOffs);
959372b676d7Smrg       BOUND(y1, CRT1YOffs, min(VVirt, MBXNR1YMAX + CRT1YOffs) - min(VTotal, MBXNR1YMAX) - CRT2YOffs);
959472b676d7Smrg       BOUND(x2, CRT2XOffs, min(HVirt, MBXNR2XMAX + CRT2XOffs) - min(HTotal, MBXNR2XMAX) - CRT1XOffs);
959572b676d7Smrg       BOUND(y2, CRT2YOffs, min(VVirt, MBXNR2YMAX + CRT2YOffs) - min(VTotal, MBXNR2YMAX) - CRT1YOffs);
959672b676d7Smrg    }
959772b676d7Smrg
959872b676d7Smrg    switch(SDMPTR(pScrn1)->CRT2Position) {
959972b676d7Smrg        case sisLeftOf:
960072b676d7Smrg            pScrn2->frameX0 = x2;
960172b676d7Smrg            BOUND(pScrn2->frameY0,   y2, y2 + min(VMax, MBXNR2YMAX) - CDMPTR->CRT2->VDisplay);
960272b676d7Smrg            pSiS->CRT1frameX0 = x1 + CDMPTR->CRT2->HDisplay;
960372b676d7Smrg            BOUND(pSiS->CRT1frameY0, y1, y1 + min(VMax, MBXNR1YMAX) - CDMPTR->CRT1->VDisplay);
960472b676d7Smrg            break;
960572b676d7Smrg        case sisRightOf:
960672b676d7Smrg            pSiS->CRT1frameX0 = x1;
960772b676d7Smrg            BOUND(pSiS->CRT1frameY0, y1, y1 + min(VMax, MBXNR1YMAX) - CDMPTR->CRT1->VDisplay);
960872b676d7Smrg            pScrn2->frameX0 = x2 + CDMPTR->CRT1->HDisplay;
960972b676d7Smrg            BOUND(pScrn2->frameY0,   y2, y2 + min(VMax, MBXNR2YMAX) - CDMPTR->CRT2->VDisplay);
961072b676d7Smrg            break;
961172b676d7Smrg        case sisAbove:
961272b676d7Smrg            BOUND(pScrn2->frameX0,   x2, x2 + min(HMax, MBXNR2XMAX) - CDMPTR->CRT2->HDisplay);
961372b676d7Smrg            pScrn2->frameY0 = y2;
961472b676d7Smrg            BOUND(pSiS->CRT1frameX0, x1, x1 + min(HMax, MBXNR1XMAX) - CDMPTR->CRT1->HDisplay);
961572b676d7Smrg            pSiS->CRT1frameY0 = y1 + CDMPTR->CRT2->VDisplay;
961672b676d7Smrg            break;
961772b676d7Smrg        case sisBelow:
961872b676d7Smrg            BOUND(pSiS->CRT1frameX0, x1, x1 + min(HMax, MBXNR1XMAX) - CDMPTR->CRT1->HDisplay);
961972b676d7Smrg            pSiS->CRT1frameY0 = y1;
962072b676d7Smrg            BOUND(pScrn2->frameX0,   x2, x2 + min(HMax, MBXNR2XMAX) - CDMPTR->CRT2->HDisplay);
962172b676d7Smrg            pScrn2->frameY0 = y2 + CDMPTR->CRT1->VDisplay;
962272b676d7Smrg            break;
962372b676d7Smrg        case sisClone:
962472b676d7Smrg            BOUND(pSiS->CRT1frameX0, x,  x + HMax - CDMPTR->CRT1->HDisplay);
962572b676d7Smrg            BOUND(pSiS->CRT1frameY0, y,  y + VMax - CDMPTR->CRT1->VDisplay);
962672b676d7Smrg            BOUND(pScrn2->frameX0,   x,  x + HMax - CDMPTR->CRT2->HDisplay);
962772b676d7Smrg            BOUND(pScrn2->frameY0,   y,  y + VMax - CDMPTR->CRT2->VDisplay);
962872b676d7Smrg            break;
962972b676d7Smrg    }
963072b676d7Smrg
963172b676d7Smrg    BOUND(pSiS->CRT1frameX0, 0, HVirt - CDMPTR->CRT1->HDisplay);
963272b676d7Smrg    BOUND(pSiS->CRT1frameY0, 0, VVirt - CDMPTR->CRT1->VDisplay);
963372b676d7Smrg    BOUND(pScrn2->frameX0,   0, HVirt - CDMPTR->CRT2->HDisplay);
963472b676d7Smrg    BOUND(pScrn2->frameY0,   0, VVirt - CDMPTR->CRT2->VDisplay);
963572b676d7Smrg
963672b676d7Smrg    pScrn1->frameX0 = x;
963772b676d7Smrg    pScrn1->frameY0 = y;
963872b676d7Smrg
963972b676d7Smrg    pSiS->CRT1frameX1 = pSiS->CRT1frameX0 + CDMPTR->CRT1->HDisplay - 1;
964072b676d7Smrg    pSiS->CRT1frameY1 = pSiS->CRT1frameY0 + CDMPTR->CRT1->VDisplay - 1;
964172b676d7Smrg    pScrn2->frameX1   = pScrn2->frameX0   + CDMPTR->CRT2->HDisplay - 1;
964272b676d7Smrg    pScrn2->frameY1   = pScrn2->frameY0   + CDMPTR->CRT2->VDisplay - 1;
964372b676d7Smrg
964472b676d7Smrg    pScrn1->frameX1   = pScrn1->frameX0   + pSiS->CurrentLayout.mode->HDisplay  - 1;
964572b676d7Smrg    pScrn1->frameY1   = pScrn1->frameY0   + pSiS->CurrentLayout.mode->VDisplay  - 1;
964672b676d7Smrg    if(SDMPTR(pScrn1)->CRT2Position != sisClone) {
964772b676d7Smrg       pScrn1->frameX1 += CRT1XOffs + CRT2XOffs;
964872b676d7Smrg       pScrn1->frameY1 += CRT1YOffs + CRT2YOffs;
964972b676d7Smrg    }
965072b676d7Smrg
965172b676d7Smrg    SISAdjustFrameHW_CRT1(pScrn1, pSiS->CRT1frameX0, pSiS->CRT1frameY0);
965272b676d7Smrg    SISAdjustFrameHW_CRT2(pScrn1, pScrn2->frameX0, pScrn2->frameY0);
965372b676d7Smrg}
965472b676d7Smrg#endif
965572b676d7Smrg
965672b676d7Smrg/*
965772b676d7Smrg * This function is used to initialize the Start Address - the first
965872b676d7Smrg * displayed location in the video memory.
965972b676d7Smrg *
966072b676d7Smrg * Usually mandatory
966172b676d7Smrg */
966272b676d7Smrgvoid
96635788ca14SmrgSISAdjustFrame(ADJUST_FRAME_ARGS_DECL)
966472b676d7Smrg{
96655788ca14Smrg    SCRN_INFO_PTR(arg);
966672b676d7Smrg    SISPtr        pSiS = SISPTR(pScrn);
966772b676d7Smrg    ULong base;
966872b676d7Smrg    UChar temp, cr11backup;
966972b676d7Smrg
967072b676d7Smrg#ifdef SISMERGED
967172b676d7Smrg    if(pSiS->MergedFB) {
96725788ca14Smrg        SISAdjustFrameMerged(ADJUST_FRAME_ARGS(pScrn, x, y));
967372b676d7Smrg	return;
967472b676d7Smrg    }
967572b676d7Smrg#endif
967672b676d7Smrg
967772b676d7Smrg    if(pSiS->UseVESA) {
967872b676d7Smrg	VBESetDisplayStart(pSiS->pVbe, x, y, TRUE);
967972b676d7Smrg	return;
968072b676d7Smrg    }
968172b676d7Smrg
968272b676d7Smrg    if(pScrn->bitsPerPixel < 8) {
968372b676d7Smrg       base = (y * pSiS->CurrentLayout.displayWidth + x + 3) >> 3;
968472b676d7Smrg    } else {
968572b676d7Smrg       base  = y * pSiS->CurrentLayout.displayWidth + x;
968672b676d7Smrg
968772b676d7Smrg       /* calculate base bpp dep. */
968872b676d7Smrg       switch(pSiS->CurrentLayout.bitsPerPixel) {
968972b676d7Smrg          case 16:
969072b676d7Smrg     	     base >>= 1;
969172b676d7Smrg             break;
969272b676d7Smrg          case 24:
969372b676d7Smrg             base = ((base * 3)) >> 2;
969472b676d7Smrg             base -= base % 6;
969572b676d7Smrg             break;
969672b676d7Smrg          case 32:
969772b676d7Smrg             break;
969872b676d7Smrg          default:      /* 8bpp */
969972b676d7Smrg             base >>= 2;
970072b676d7Smrg             break;
970172b676d7Smrg       }
970272b676d7Smrg    }
970372b676d7Smrg
970472b676d7Smrg#ifdef UNLOCK_ALWAYS
970572b676d7Smrg    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
970672b676d7Smrg#endif
970772b676d7Smrg
970872b676d7Smrg    base += (pSiS->dhmOffset/4);
970972b676d7Smrg
971072b676d7Smrg#ifdef TWDEBUG
971172b676d7Smrg    xf86DrvMsg(0, 0, "AdjustFrame: x %d y %d bpp %d dw %d base %d, dhmOffset %d\n",
971272b676d7Smrg    			x, y, pSiS->CurrentLayout.bitsPerPixel, pSiS->CurrentLayout.displayWidth, base, pSiS->dhmOffset);
971372b676d7Smrg#endif
971472b676d7Smrg
971572b676d7Smrg#ifdef SISDUALHEAD
971672b676d7Smrg    if(pSiS->DualHeadMode) {
971772b676d7Smrg       if(!pSiS->SecondHead) {
971872b676d7Smrg	  /* Head 1 (master) is always CRT2 */
971972b676d7Smrg	  SISSetStartAddressCRT2(pSiS, base);
972072b676d7Smrg       } else {
972172b676d7Smrg	  /* Head 2 (slave) is always CRT1 */
972272b676d7Smrg	  SISSetStartAddressCRT1(pSiS, base);
972372b676d7Smrg       }
972472b676d7Smrg    } else {
972572b676d7Smrg#endif
972672b676d7Smrg       switch(pSiS->VGAEngine) {
972772b676d7Smrg	  case SIS_300_VGA:
972872b676d7Smrg	  case SIS_315_VGA:
972972b676d7Smrg	     SISSetStartAddressCRT1(pSiS, base);
973072b676d7Smrg	     if(pSiS->VBFlags & CRT2_ENABLE) {
973172b676d7Smrg		if(!SiSBridgeIsInSlaveMode(pScrn)) {
973272b676d7Smrg		   SISSetStartAddressCRT2(pSiS, base);
973372b676d7Smrg		}
973472b676d7Smrg	     }
973572b676d7Smrg	     break;
973672b676d7Smrg	  default:
973772b676d7Smrg	     /* Unlock CRTC registers */
973872b676d7Smrg	     inSISIDXREG(SISCR,  0x11, cr11backup);
973972b676d7Smrg	     andSISIDXREG(SISCR, 0x11, 0x7F);
974072b676d7Smrg	     outSISIDXREG(SISCR, 0x0D, base & 0xFF);
974172b676d7Smrg	     outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF);
974272b676d7Smrg	     inSISIDXREG(SISSR,  0x27, temp);
974372b676d7Smrg	     temp &= 0xF0;
974472b676d7Smrg	     temp |= (base & 0x0F0000) >> 16;
974572b676d7Smrg	     outSISIDXREG(SISSR, 0x27, temp);
974672b676d7Smrg	     /* Eventually lock CRTC registers */
974772b676d7Smrg	     setSISIDXREG(SISCR, 0x11, 0x7F, (cr11backup & 0x80));
974872b676d7Smrg       }
974972b676d7Smrg#ifdef SISDUALHEAD
975072b676d7Smrg    }
975172b676d7Smrg#endif
975272b676d7Smrg
975372b676d7Smrg}
975472b676d7Smrg
975572b676d7Smrg/*
975672b676d7Smrg * This is called when VT switching back to the X server.  Its job is
975772b676d7Smrg * to reinitialise the video mode.
975872b676d7Smrg * Mandatory!
975972b676d7Smrg */
976072b676d7Smrgstatic Bool
97615788ca14SmrgSISEnterVT(VT_FUNC_ARGS_DECL)
976272b676d7Smrg{
97635788ca14Smrg    SCRN_INFO_PTR(arg);
976472b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
976572b676d7Smrg
976672b676d7Smrg    SiS_SiSFB_Lock(pScrn, TRUE);
976772b676d7Smrg
976872b676d7Smrg    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
976972b676d7Smrg
977072b676d7Smrg    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
977172b676d7Smrg       outSISIDXREG(SISCR,0x32,pSiS->myCR32);
977272b676d7Smrg       outSISIDXREG(SISCR,0x36,pSiS->myCR36);
977372b676d7Smrg       outSISIDXREG(SISCR,0x37,pSiS->myCR37);
977472b676d7Smrg    }
977572b676d7Smrg
977672b676d7Smrg    if(!SISModeInit(pScrn, pScrn->currentMode)) {
977772b676d7Smrg       SISErrorLog(pScrn, "SiSEnterVT: SISModeInit() failed\n");
977872b676d7Smrg       return FALSE;
977972b676d7Smrg    }
978072b676d7Smrg
97815788ca14Smrg    SISAdjustFrame(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0));
978272b676d7Smrg
97835788ca14Smrg#ifdef SISDRI
978472b676d7Smrg    if(pSiS->directRenderingEnabled) {
97855788ca14Smrg       DRIUnlock(xf86ScrnToScreen(pScrn));
978672b676d7Smrg    }
978772b676d7Smrg#endif
978872b676d7Smrg
978972b676d7Smrg#ifdef SISDUALHEAD
979072b676d7Smrg    if((!pSiS->DualHeadMode) || (!pSiS->SecondHead))
979172b676d7Smrg#endif
979272b676d7Smrg       if(pSiS->ResetXv) {
979372b676d7Smrg          (pSiS->ResetXv)(pScrn);
979472b676d7Smrg       }
979572b676d7Smrg
979672b676d7Smrg    return TRUE;
979772b676d7Smrg}
979872b676d7Smrg
979972b676d7Smrg/*
980072b676d7Smrg * This is called when VT switching away from the X server.  Its job is
980172b676d7Smrg * to restore the previous (text) mode.
980272b676d7Smrg * Mandatory!
980372b676d7Smrg */
980472b676d7Smrgstatic void
98055788ca14SmrgSISLeaveVT(VT_FUNC_ARGS_DECL)
980672b676d7Smrg{
98075788ca14Smrg    SCRN_INFO_PTR(arg);
980872b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
98095788ca14Smrg#ifdef SISDRI
981072b676d7Smrg    ScreenPtr pScreen;
981172b676d7Smrg
981272b676d7Smrg    if(pSiS->directRenderingEnabled) {
98135788ca14Smrg       pScreen = xf86ScrnToScreen(pScrn);
981472b676d7Smrg       DRILock(pScreen, 0);
981572b676d7Smrg    }
981672b676d7Smrg#endif
981772b676d7Smrg
981872b676d7Smrg#ifdef SISDUALHEAD
981972b676d7Smrg    if(pSiS->DualHeadMode && pSiS->SecondHead) return;
982072b676d7Smrg#endif
982172b676d7Smrg
982272b676d7Smrg    if(pSiS->CursorInfoPtr) {
982372b676d7Smrg#ifdef SISDUALHEAD
982472b676d7Smrg       if(pSiS->DualHeadMode) {
982572b676d7Smrg          if(!pSiS->SecondHead) {
982672b676d7Smrg	     pSiS->ForceCursorOff = TRUE;
982772b676d7Smrg	     pSiS->CursorInfoPtr->HideCursor(pScrn);
982872b676d7Smrg	     SISWaitVBRetrace(pScrn);
982972b676d7Smrg	     pSiS->ForceCursorOff = FALSE;
983072b676d7Smrg	  }
983172b676d7Smrg       } else {
983272b676d7Smrg#endif
983372b676d7Smrg          pSiS->CursorInfoPtr->HideCursor(pScrn);
983472b676d7Smrg          SISWaitVBRetrace(pScrn);
983572b676d7Smrg#ifdef SISDUALHEAD
983672b676d7Smrg       }
983772b676d7Smrg#endif
983872b676d7Smrg    }
983972b676d7Smrg
984072b676d7Smrg    SISBridgeRestore(pScrn);
984172b676d7Smrg
984272b676d7Smrg    if(pSiS->UseVESA) {
984372b676d7Smrg
984472b676d7Smrg       /* This is a q&d work-around for a BIOS bug. In case we disabled CRT2,
984572b676d7Smrg    	* VBESaveRestore() does not restore CRT1. So we set any mode now,
984672b676d7Smrg	* because VBESetVBEMode correctly restores CRT1. Afterwards, we
984772b676d7Smrg	* can call VBESaveRestore to restore original mode.
984872b676d7Smrg	*/
984972b676d7Smrg       if((pSiS->VBFlags2 & VB2_VIDEOBRIDGE) && (!(pSiS->VBFlags & DISPTYPE_DISP2)))
985072b676d7Smrg	  VBESetVBEMode(pSiS->pVbe, (pSiS->SISVESAModeList->n) | 0xc000, NULL);
985172b676d7Smrg
985272b676d7Smrg       SISVESARestore(pScrn);
985372b676d7Smrg
985472b676d7Smrg    } else {
985572b676d7Smrg
985672b676d7Smrg       SISRestore(pScrn);
985772b676d7Smrg
985872b676d7Smrg    }
985972b676d7Smrg
986072b676d7Smrg    /* We use (otherwise unused) bit 7 to indicate that we are running
986172b676d7Smrg     * to keep sisfb to change the displaymode (this would result in
986272b676d7Smrg     * lethal display corruption upon quitting X or changing to a VT
986372b676d7Smrg     * until a reboot)
986472b676d7Smrg     */
986572b676d7Smrg    if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
986672b676d7Smrg       orSISIDXREG(SISCR,0x34,0x80);
986772b676d7Smrg    }
986872b676d7Smrg
986972b676d7Smrg    SISVGALock(pSiS);
987072b676d7Smrg
987172b676d7Smrg    SiS_SiSFB_Lock(pScrn, FALSE);
987272b676d7Smrg}
987372b676d7Smrg
987472b676d7Smrg
987572b676d7Smrg/*
987672b676d7Smrg * This is called at the end of each server generation.  It restores the
987772b676d7Smrg * original (text) mode.  It should really also unmap the video memory too.
987872b676d7Smrg * Mandatory!
987972b676d7Smrg */
988072b676d7Smrgstatic Bool
98815788ca14SmrgSISCloseScreen(CLOSE_SCREEN_ARGS_DECL)
988272b676d7Smrg{
98835788ca14Smrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
988472b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
988572b676d7Smrg#ifdef SISDUALHEAD
988672b676d7Smrg    SISEntPtr pSiSEnt = pSiS->entityPrivate;
988772b676d7Smrg#endif
988872b676d7Smrg
988972b676d7Smrg    if(pSiS->SiSCtrlExtEntry) {
989072b676d7Smrg       SiSCtrlExtUnregister(pSiS, pScrn->scrnIndex);
989172b676d7Smrg    }
989272b676d7Smrg
98935788ca14Smrg#ifdef SISDRI
989472b676d7Smrg    if(pSiS->directRenderingEnabled) {
989572b676d7Smrg       SISDRICloseScreen(pScreen);
989672b676d7Smrg       pSiS->directRenderingEnabled = FALSE;
989772b676d7Smrg    }
989872b676d7Smrg#endif
989972b676d7Smrg
990072b676d7Smrg    if(pScrn->vtSema) {
990172b676d7Smrg
990272b676d7Smrg        if(pSiS->CursorInfoPtr) {
990372b676d7Smrg#ifdef SISDUALHEAD
990472b676d7Smrg           if(pSiS->DualHeadMode) {
990572b676d7Smrg              if(!pSiS->SecondHead) {
990672b676d7Smrg	         pSiS->ForceCursorOff = TRUE;
990772b676d7Smrg	         pSiS->CursorInfoPtr->HideCursor(pScrn);
990872b676d7Smrg	         SISWaitVBRetrace(pScrn);
990972b676d7Smrg	         pSiS->ForceCursorOff = FALSE;
991072b676d7Smrg	      }
991172b676d7Smrg           } else {
991272b676d7Smrg#endif
991372b676d7Smrg             pSiS->CursorInfoPtr->HideCursor(pScrn);
991472b676d7Smrg             SISWaitVBRetrace(pScrn);
991572b676d7Smrg#ifdef SISDUALHEAD
991672b676d7Smrg           }
991772b676d7Smrg#endif
991872b676d7Smrg	}
991972b676d7Smrg
992072b676d7Smrg        SISBridgeRestore(pScrn);
992172b676d7Smrg
992272b676d7Smrg	if(pSiS->UseVESA) {
992372b676d7Smrg
992472b676d7Smrg	  /* This is a q&d work-around for a BIOS bug. In case we disabled CRT2,
992572b676d7Smrg    	   * VBESaveRestore() does not restore CRT1. So we set any mode now,
992672b676d7Smrg	   * because VBESetVBEMode correctly restores CRT1. Afterwards, we
992772b676d7Smrg	   * can call VBESaveRestore to restore original mode.
992872b676d7Smrg	   */
992972b676d7Smrg           if((pSiS->VBFlags2 & VB2_VIDEOBRIDGE) && (!(pSiS->VBFlags & DISPTYPE_DISP2)))
993072b676d7Smrg	      VBESetVBEMode(pSiS->pVbe, (pSiS->SISVESAModeList->n) | 0xc000, NULL);
993172b676d7Smrg
993272b676d7Smrg	   SISVESARestore(pScrn);
993372b676d7Smrg
993472b676d7Smrg	} else {
993572b676d7Smrg
993672b676d7Smrg	   SISRestore(pScrn);
993772b676d7Smrg
993872b676d7Smrg	}
993972b676d7Smrg
994072b676d7Smrg        SISVGALock(pSiS);
994172b676d7Smrg
994272b676d7Smrg    }
994372b676d7Smrg
994472b676d7Smrg    SiS_SiSFB_Lock(pScrn, FALSE);
994572b676d7Smrg
994672b676d7Smrg    /* We should restore the mode number in case vtsema = false as well,
994772b676d7Smrg     * but since we haven't register access then we can't do it. I think
994872b676d7Smrg     * I need to rework the save/restore stuff, like saving the video
994972b676d7Smrg     * status when returning to the X server and by that save me the
995072b676d7Smrg     * trouble if sisfb was started from a textmode VT while X was on.
995172b676d7Smrg     */
995272b676d7Smrg
995372b676d7Smrg    SISUnmapMem(pScrn);
995472b676d7Smrg#ifdef SIS_PC_PLATFORM
995572b676d7Smrg    SiSVGAUnmapMem(pScrn);
995672b676d7Smrg#endif
995772b676d7Smrg
995872b676d7Smrg#ifdef SISDUALHEAD
995972b676d7Smrg    if(pSiS->DualHeadMode) {
996072b676d7Smrg       pSiSEnt = pSiS->entityPrivate;
996172b676d7Smrg       pSiSEnt->refCount--;
996272b676d7Smrg    }
996372b676d7Smrg#endif
996472b676d7Smrg
996572b676d7Smrg    if(pSiS->pInt) {
996672b676d7Smrg       xf86FreeInt10(pSiS->pInt);
996772b676d7Smrg       pSiS->pInt = NULL;
996872b676d7Smrg    }
996972b676d7Smrg
997072b676d7Smrg#ifdef SIS_USE_XAA
997172b676d7Smrg    if(!pSiS->useEXA) {
997272b676d7Smrg       if(pSiS->AccelLinearScratch) {
997372b676d7Smrg          xf86FreeOffscreenLinear(pSiS->AccelLinearScratch);
997472b676d7Smrg          pSiS->AccelLinearScratch = NULL;
997572b676d7Smrg       }
997672b676d7Smrg       if(pSiS->AccelInfoPtr) {
997772b676d7Smrg          XAADestroyInfoRec(pSiS->AccelInfoPtr);
997872b676d7Smrg          pSiS->AccelInfoPtr = NULL;
997972b676d7Smrg       }
998072b676d7Smrg    }
998172b676d7Smrg#endif
998272b676d7Smrg
998372b676d7Smrg#ifdef SIS_USE_EXA
998472b676d7Smrg    if(pSiS->useEXA) {
998572b676d7Smrg       if(pSiS->EXADriverPtr) {
998672b676d7Smrg          exaDriverFini(pScreen);
99875788ca14Smrg          free(pSiS->EXADriverPtr);
998872b676d7Smrg          pSiS->EXADriverPtr = NULL;
998972b676d7Smrg          pSiS->exa_scratch = NULL;
999072b676d7Smrg       }
999172b676d7Smrg    }
999272b676d7Smrg#endif
999372b676d7Smrg
999472b676d7Smrg    if(pSiS->CursorInfoPtr) {
999572b676d7Smrg       xf86DestroyCursorInfoRec(pSiS->CursorInfoPtr);
999672b676d7Smrg       pSiS->CursorInfoPtr = NULL;
999772b676d7Smrg    }
999872b676d7Smrg
999972b676d7Smrg    if(pSiS->ShadowPtr) {
100005788ca14Smrg       free(pSiS->ShadowPtr);
1000172b676d7Smrg       pSiS->ShadowPtr = NULL;
1000272b676d7Smrg    }
1000372b676d7Smrg
1000472b676d7Smrg    if(pSiS->DGAModes) {
100055788ca14Smrg       free(pSiS->DGAModes);
1000672b676d7Smrg       pSiS->DGAModes = NULL;
1000772b676d7Smrg    }
1000872b676d7Smrg
1000972b676d7Smrg    if(pSiS->adaptor) {
100105788ca14Smrg       free(pSiS->adaptor);
1001172b676d7Smrg       pSiS->adaptor = NULL;
1001272b676d7Smrg       pSiS->ResetXv = pSiS->ResetXvGamma = pSiS->ResetXvDisplay = NULL;
1001372b676d7Smrg    }
1001472b676d7Smrg
1001572b676d7Smrg    if(pSiS->blitadaptor) {
100165788ca14Smrg       free(pSiS->blitadaptor);
1001772b676d7Smrg       pSiS->blitadaptor = NULL;
1001872b676d7Smrg    }
1001972b676d7Smrg
1002072b676d7Smrg    if(pSiS->crt2gcolortable) {
100215788ca14Smrg       free(pSiS->crt2gcolortable);
1002272b676d7Smrg       pSiS->crt2gcolortable = NULL;
1002372b676d7Smrg    }
1002472b676d7Smrg
1002572b676d7Smrg    if(pSiS->crt2cindices) {
100265788ca14Smrg       free(pSiS->crt2cindices);
1002772b676d7Smrg       pSiS->crt2cindices = NULL;
1002872b676d7Smrg    }
1002972b676d7Smrg
1003072b676d7Smrg    pScrn->vtSema = FALSE;
1003172b676d7Smrg
1003272b676d7Smrg    /* Restore Blockhandler */
1003372b676d7Smrg    pScreen->BlockHandler = pSiS->BlockHandler;
1003472b676d7Smrg
1003572b676d7Smrg    pScreen->CloseScreen = pSiS->CloseScreen;
1003672b676d7Smrg
100375788ca14Smrg    return(*pScreen->CloseScreen)(CLOSE_SCREEN_ARGS);
1003872b676d7Smrg}
1003972b676d7Smrg
1004072b676d7Smrg
1004172b676d7Smrg/* Free up any per-generation data structures */
1004272b676d7Smrg
1004372b676d7Smrg/* Optional */
1004472b676d7Smrgstatic void
100455788ca14SmrgSISFreeScreen(FREE_SCREEN_ARGS_DECL)
1004672b676d7Smrg{
100475788ca14Smrg    SCRN_INFO_PTR(arg);
1004872b676d7Smrg#ifdef SIS_NEED_MAP_IOP
1004972b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
1005072b676d7Smrg
1005172b676d7Smrg    if(pSiS) {
1005272b676d7Smrg#ifdef SISDUALHEAD
1005372b676d7Smrg       SISEntPtr pSiSEnt = pSiS->entityPrivate;
1005472b676d7Smrg       if(pSiSEnt) {
1005572b676d7Smrg          pSiSEnt->forceUnmapIOPBase = TRUE;
1005672b676d7Smrg       }
1005772b676d7Smrg#endif
1005872b676d7Smrg       SISUnmapIOPMem(pScrn);
1005972b676d7Smrg    }
1006072b676d7Smrg#endif
1006172b676d7Smrg
100625788ca14Smrg    SISFreeRec(pScrn);
1006372b676d7Smrg}
1006472b676d7Smrg
1006572b676d7Smrg
1006672b676d7Smrg/* Checks if a mode is suitable for the selected chipset. */
1006772b676d7Smrg
1006872b676d7Smrgstatic ModeStatus
100695788ca14SmrgSISValidMode(SCRN_ARG_TYPE arg, DisplayModePtr mode, Bool verbose, int flags)
1007072b676d7Smrg{
100715788ca14Smrg    SCRN_INFO_PTR(arg);
1007272b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
1007372b676d7Smrg
1007472b676d7Smrg    if(pSiS->UseVESA) {
1007572b676d7Smrg       if(SiSCalcVESAModeIndex(pScrn, mode))
1007672b676d7Smrg	  return(MODE_OK);
1007772b676d7Smrg       else
1007872b676d7Smrg	  return(MODE_BAD);
1007972b676d7Smrg    }
1008072b676d7Smrg
1008172b676d7Smrg    if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
1008272b676d7Smrg#ifdef SISDUALHEAD
1008372b676d7Smrg       if(pSiS->DualHeadMode) {
1008472b676d7Smrg          if(pSiS->SecondHead) {
1008572b676d7Smrg	     if(SiS_CheckModeCRT1(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
1008672b676d7Smrg	        return(MODE_BAD);
1008772b676d7Smrg	  } else {
1008872b676d7Smrg	     if(SiS_CheckModeCRT2(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
1008972b676d7Smrg	        return(MODE_BAD);
1009072b676d7Smrg	  }
1009172b676d7Smrg       } else
1009272b676d7Smrg#endif
1009372b676d7Smrg#ifdef SISMERGED
1009472b676d7Smrg       if(pSiS->MergedFB) {
1009572b676d7Smrg	  if(!mode->Private) {
1009672b676d7Smrg	     if(!pSiS->CheckForCRT2) {
1009772b676d7Smrg	        if(SiS_CheckModeCRT1(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
1009872b676d7Smrg	           return(MODE_BAD);
1009972b676d7Smrg	     } else {
1010072b676d7Smrg	        if(SiS_CheckModeCRT2(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes2) < 0x14)
1010172b676d7Smrg	           return(MODE_BAD);
1010272b676d7Smrg	     }
1010372b676d7Smrg	  } else {
1010472b676d7Smrg	     if(SiS_CheckModeCRT1(pScrn, ((SiSMergedDisplayModePtr)mode->Private)->CRT1,
1010572b676d7Smrg		                  pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
1010672b676d7Smrg	        return(MODE_BAD);
1010772b676d7Smrg
1010872b676d7Smrg	     if(SiS_CheckModeCRT2(pScrn, ((SiSMergedDisplayModePtr)mode->Private)->CRT2,
1010972b676d7Smrg		                  pSiS->VBFlags, pSiS->HaveCustomModes2) < 0x14)
1011072b676d7Smrg	        return(MODE_BAD);
1011172b676d7Smrg 	  }
1011272b676d7Smrg       } else
1011372b676d7Smrg#endif
1011472b676d7Smrg       {
1011572b676d7Smrg	  if(SiS_CheckModeCRT1(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
1011672b676d7Smrg	     return(MODE_BAD);
1011772b676d7Smrg
1011872b676d7Smrg	  if(SiS_CheckModeCRT2(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
1011972b676d7Smrg	     return(MODE_BAD);
1012072b676d7Smrg       }
1012172b676d7Smrg    }
1012272b676d7Smrg
1012372b676d7Smrg    return(MODE_OK);
1012472b676d7Smrg}
1012572b676d7Smrg
1012672b676d7Smrg#ifdef DEBUG
1012772b676d7Smrgstatic void
1012872b676d7SmrgSiSDumpModeInfo(ScrnInfoPtr pScrn, DisplayModePtr mode)
1012972b676d7Smrg{
1013072b676d7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Clock : %x\n", mode->Clock);
1013172b676d7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Display : %x\n", mode->CrtcHDisplay);
1013272b676d7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Blank Start : %x\n", mode->CrtcHBlankStart);
1013372b676d7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Sync Start : %x\n", mode->CrtcHSyncStart);
1013472b676d7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Sync End : %x\n", mode->CrtcHSyncEnd);
1013572b676d7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Blank End : %x\n", mode->CrtcHBlankEnd);
1013672b676d7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Total : %x\n", mode->CrtcHTotal);
1013772b676d7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Skew : %x\n", mode->CrtcHSkew);
1013872b676d7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz HAdjusted : %x\n", mode->CrtcHAdjusted);
1013972b676d7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Display : %x\n", mode->CrtcVDisplay);
1014072b676d7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Blank Start : %x\n", mode->CrtcVBlankStart);
1014172b676d7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Sync Start : %x\n", mode->CrtcVSyncStart);
1014272b676d7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Sync End : %x\n", mode->CrtcVSyncEnd);
1014372b676d7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Blank End : %x\n", mode->CrtcVBlankEnd);
1014472b676d7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Total : %x\n", mode->CrtcVTotal);
1014572b676d7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt VAdjusted : %x\n", mode->CrtcVAdjusted);
1014672b676d7Smrg}
1014772b676d7Smrg#endif
1014872b676d7Smrg
1014972b676d7Smrgstatic void
1015072b676d7SmrgSISModifyModeInfo(DisplayModePtr mode)
1015172b676d7Smrg{
1015272b676d7Smrg    if(mode->CrtcHBlankStart == mode->CrtcHDisplay)
1015372b676d7Smrg        mode->CrtcHBlankStart++;
1015472b676d7Smrg    if(mode->CrtcHBlankEnd == mode->CrtcHTotal)
1015572b676d7Smrg        mode->CrtcHBlankEnd--;
1015672b676d7Smrg    if(mode->CrtcVBlankStart == mode->CrtcVDisplay)
1015772b676d7Smrg        mode->CrtcVBlankStart++;
1015872b676d7Smrg    if(mode->CrtcVBlankEnd == mode->CrtcVTotal)
1015972b676d7Smrg        mode->CrtcVBlankEnd--;
1016072b676d7Smrg}
1016172b676d7Smrg
1016272b676d7Smrg/* Enable the Turboqueue/Commandqueue (For 300 and 315/330/340 series only) */
1016372b676d7Smrgstatic void
1016472b676d7SmrgSiSEnableTurboQueue(ScrnInfoPtr pScrn)
1016572b676d7Smrg{
1016672b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
1016772b676d7Smrg    UShort SR26, SR27;
1016872b676d7Smrg    ULong  temp;
1016972b676d7Smrg
1017072b676d7Smrg    switch(pSiS->VGAEngine) {
1017172b676d7Smrg	case SIS_300_VGA:
1017272b676d7Smrg	   if((!pSiS->NoAccel) && (pSiS->TurboQueue)) {
1017372b676d7Smrg		/* TQ size is always 512k */
1017472b676d7Smrg		temp = (pScrn->videoRam/64) - 8;
1017572b676d7Smrg		SR26 = temp & 0xFF;
1017672b676d7Smrg		inSISIDXREG(SISSR, 0x27, SR27);
1017772b676d7Smrg		SR27 &= 0xFC;
1017872b676d7Smrg		SR27 |= (0xF0 | ((temp >> 8) & 3));
1017972b676d7Smrg		outSISIDXREG(SISSR, 0x26, SR26);
1018072b676d7Smrg		outSISIDXREG(SISSR, 0x27, SR27);
1018172b676d7Smrg	   }
1018272b676d7Smrg	   break;
1018372b676d7Smrg
1018472b676d7Smrg	case SIS_315_VGA:
1018572b676d7Smrg	   if(!pSiS->NoAccel) {
1018672b676d7Smrg	      /* On 315/330/340 series, there are three queue modes available
1018772b676d7Smrg	       * which are chosen by setting bits 7:5 in SR26:
1018872b676d7Smrg	       * 1. MMIO queue mode (bit 5, 0x20). The hardware will keep
1018972b676d7Smrg	       *    track of the queue, the FIFO, command parsing and so
1019072b676d7Smrg	       *    on. This is the one comparable to the 300 series.
1019172b676d7Smrg	       * 2. VRAM queue mode (bit 6, 0x40). In this case, one will
1019272b676d7Smrg	       *    have to do queue management himself.
1019372b676d7Smrg	       * 3. AGP queue mode (bit 7, 0x80). Works as 2., but keeps the
1019472b676d7Smrg	       *    queue in AGP memory space.
1019572b676d7Smrg	       * We go VRAM or MMIO here.
1019672b676d7Smrg	       * SR26 bit 4 is called "Bypass H/W queue".
1019772b676d7Smrg	       * SR26 bit 1 is called "Enable Command Queue Auto Correction"
1019872b676d7Smrg	       * SR26 bit 0 resets the queue
1019972b676d7Smrg	       * Size of queue memory is encoded in bits 3:2 like this:
1020072b676d7Smrg	       *    00  (0x00)  512K
1020172b676d7Smrg	       *    01  (0x04)  1M
1020272b676d7Smrg	       *    10  (0x08)  2M
1020372b676d7Smrg	       *    11  (0x0C)  4M
1020472b676d7Smrg	       * The queue location is to be written to 0x85C0.
1020572b676d7Smrg	       */
1020672b676d7Smrg#ifdef SISVRAMQ
1020772b676d7Smrg	      /* We use VRAM Cmd Queue, not MMIO or AGP */
1020872b676d7Smrg	      UChar tempCR55 = 0;
1020972b676d7Smrg
1021072b676d7Smrg	      /* Set Command Queue Threshold to max value 11111b (?) */
1021172b676d7Smrg	      outSISIDXREG(SISSR, 0x27, 0x1F);
1021272b676d7Smrg
1021372b676d7Smrg	      /* Disable queue flipping */
1021472b676d7Smrg	      inSISIDXREG(SISCR, 0x55, tempCR55);
1021572b676d7Smrg	      andSISIDXREG(SISCR, 0x55, 0x33);
1021672b676d7Smrg	      /* Synchronous reset for Command Queue */
1021772b676d7Smrg	      outSISIDXREG(SISSR, 0x26, 0x01);
1021872b676d7Smrg	      SIS_MMIO_OUT32(pSiS->IOBase, 0x85c4, 0);
1021972b676d7Smrg	      /* Enable VRAM Command Queue mode */
1022072b676d7Smrg	      if(pSiS->ChipType == XGI_20) {
1022172b676d7Smrg		 /* On XGI_20, always 128K */
1022272b676d7Smrg		 SR26 = 0x40 | 0x04 | 0x01;
1022372b676d7Smrg	      } else {
1022472b676d7Smrg	         switch(pSiS->cmdQueueSize) {
1022572b676d7Smrg		    case 1*1024*1024: SR26 = (0x40 | 0x04 | 0x01); break;
1022672b676d7Smrg		    case 2*1024*1024: SR26 = (0x40 | 0x08 | 0x01); break;
1022772b676d7Smrg		    case 4*1024*1024: SR26 = (0x40 | 0x0C | 0x01); break;
1022872b676d7Smrg		    default:
1022972b676d7Smrg		                      pSiS->cmdQueueSize = 512 * 1024;
1023072b676d7Smrg		    case    512*1024: SR26 = (0x40 | 0x00 | 0x01);
1023172b676d7Smrg	         }
1023272b676d7Smrg	      }
1023372b676d7Smrg	      outSISIDXREG(SISSR, 0x26, SR26);
1023472b676d7Smrg	      SR26 &= 0xfe;
1023572b676d7Smrg	      outSISIDXREG(SISSR, 0x26, SR26);
1023672b676d7Smrg	      *(pSiS->cmdQ_SharedWritePort) = (unsigned int)(SIS_MMIO_IN32(pSiS->IOBase, 0x85c8));
1023772b676d7Smrg	      SIS_MMIO_OUT32(pSiS->IOBase, 0x85c4, (CARD32)(*(pSiS->cmdQ_SharedWritePort)));
1023872b676d7Smrg	      SIS_MMIO_OUT32(pSiS->IOBase, 0x85C0, pSiS->cmdQueueOffset);
1023972b676d7Smrg	      temp = (ULong)pSiS->RealFbBase;
1024072b676d7Smrg#ifdef SISDUALHEAD
1024172b676d7Smrg	      if(pSiS->DualHeadMode) {
1024272b676d7Smrg	         SISEntPtr pSiSEnt = pSiS->entityPrivate;
1024372b676d7Smrg	         temp = (ULong)pSiSEnt->RealFbBase;
1024472b676d7Smrg	      }
1024572b676d7Smrg#endif
1024672b676d7Smrg	      temp += pSiS->cmdQueueOffset;
1024772b676d7Smrg	      pSiS->cmdQueueBase = (unsigned int *)temp;
1024872b676d7Smrg	      outSISIDXREG(SISCR, 0x55, tempCR55);
1024972b676d7Smrg#ifdef TWDEBUG
1025072b676d7Smrg	      xf86DrvMsg(0, 0, "CmdQueueOffs 0x%x, CmdQueueAdd %p, shwrp 0x%x, status %x, base %p\n",
1025172b676d7Smrg		pSiS->cmdQueueOffset, pSiS->cmdQueueBase, *(pSiS->cmdQ_SharedWritePort),
1025272b676d7Smrg		SIS_MMIO_IN32(pSiS->IOBase, 0x85cc), (ULong *)temp);
1025372b676d7Smrg#endif
1025472b676d7Smrg#else
1025572b676d7Smrg	      /* For MMIO */
1025672b676d7Smrg	      /* Syncronous reset for Command Queue */
1025772b676d7Smrg	      orSISIDXREG(SISSR, 0x26, 0x01);
1025872b676d7Smrg	      /* Set Command Queue Threshold to max value 11111b */
1025972b676d7Smrg	      outSISIDXREG(SISSR, 0x27, 0x1F);
1026072b676d7Smrg	      /* Do some magic (cp readport to writeport) */
1026172b676d7Smrg	      temp = SIS_MMIO_IN32(pSiS->IOBase, 0x85C8);
1026272b676d7Smrg	      SIS_MMIO_OUT32(pSiS->IOBase, 0x85C4, temp);
1026372b676d7Smrg	      /* Enable MMIO Command Queue mode (0x20),
1026472b676d7Smrg	       * Enable_command_queue_auto_correction (0x02)
1026572b676d7Smrg	       *        (no idea, but sounds good, so use it)
1026672b676d7Smrg	       * 512k (0x00) (does this apply to MMIO mode?) */
1026772b676d7Smrg	      outSISIDXREG(SISSR, 0x26, 0x22);
1026872b676d7Smrg	      /* Calc Command Queue position (Q is always 512k)*/
1026972b676d7Smrg	      temp = (pScrn->videoRam - 512) * 1024;
1027072b676d7Smrg	      /* Set Q position */
1027172b676d7Smrg	      SIS_MMIO_OUT32(pSiS->IOBase, 0x85C0, temp);
1027272b676d7Smrg#endif
1027372b676d7Smrg	   }
1027472b676d7Smrg	   break;
1027572b676d7Smrg	default:
1027672b676d7Smrg	   break;
1027772b676d7Smrg    }
1027872b676d7Smrg}
1027972b676d7Smrg
1028072b676d7Smrg#ifdef SISVRAMQ
1028172b676d7Smrgstatic void
1028272b676d7SmrgSiSRestoreQueueMode(SISPtr pSiS, SISRegPtr sisReg)
1028372b676d7Smrg{
1028472b676d7Smrg    UChar tempCR55=0;
1028572b676d7Smrg
1028672b676d7Smrg    if(pSiS->VGAEngine == SIS_315_VGA) {
1028772b676d7Smrg       inSISIDXREG(SISCR,0x55,tempCR55);
1028872b676d7Smrg       andSISIDXREG(SISCR,0x55,0x33);
1028972b676d7Smrg       outSISIDXREG(SISSR,0x26,0x01);
1029072b676d7Smrg       SIS_MMIO_OUT32(pSiS->IOBase, 0x85c4, 0);
1029172b676d7Smrg       outSISIDXREG(SISSR,0x27,sisReg->sisRegs3C4[0x27]);
1029272b676d7Smrg       outSISIDXREG(SISSR,0x26,sisReg->sisRegs3C4[0x26]);
1029372b676d7Smrg       SIS_MMIO_OUT32(pSiS->IOBase, 0x85C0, sisReg->sisMMIO85C0);
1029472b676d7Smrg       outSISIDXREG(SISCR,0x55,tempCR55);
1029572b676d7Smrg    }
1029672b676d7Smrg}
1029772b676d7Smrg#endif
1029872b676d7Smrg
1029972b676d7Smrg/* Things to do before a ModeSwitch. We set up the
1030072b676d7Smrg * video bridge configuration and the TurboQueue.
1030172b676d7Smrg */
1030272b676d7Smrgvoid SiSPreSetMode(ScrnInfoPtr pScrn, DisplayModePtr mode, int viewmode)
1030372b676d7Smrg{
1030472b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
1030572b676d7Smrg    UChar  CR30, CR31, CR32, CR33;
1030672b676d7Smrg    UChar  CR39 = 0, CR3B = 0;
1030772b676d7Smrg    UChar  CR17, CR38 = 0;
1030872b676d7Smrg    UChar  CR35 = 0, CR79 = 0;
1030972b676d7Smrg    int    temp = 0, crt1rateindex = 0;
1031072b676d7Smrg    ULong  vbflag = pSiS->VBFlags;
1031172b676d7Smrg    Bool   hcm = pSiS->HaveCustomModes;
1031272b676d7Smrg    DisplayModePtr mymode = mode;
1031372b676d7Smrg
1031472b676d7Smrg    pSiS->IsCustom = FALSE;
1031572b676d7Smrg
1031672b676d7Smrg    /* NEVER call this with viewmode = SIS_MODE_SIMU
1031772b676d7Smrg     * if mode->type is not M_T_DEFAULT!
1031872b676d7Smrg     */
1031972b676d7Smrg
1032072b676d7Smrg#ifdef SISMERGED
1032172b676d7Smrg    if(pSiS->MergedFB) {
1032272b676d7Smrg       switch(viewmode) {
1032372b676d7Smrg       case SIS_MODE_CRT1:
1032472b676d7Smrg	  mymode = ((SiSMergedDisplayModePtr)mode->Private)->CRT1;
1032572b676d7Smrg	  break;
1032672b676d7Smrg       case SIS_MODE_CRT2:
1032772b676d7Smrg	  mymode = ((SiSMergedDisplayModePtr)mode->Private)->CRT2;
1032872b676d7Smrg	  hcm = pSiS->HaveCustomModes2;
1032972b676d7Smrg       }
1033072b676d7Smrg    }
1033172b676d7Smrg#endif
1033272b676d7Smrg
1033372b676d7Smrg    switch(viewmode) {
1033472b676d7Smrg    case SIS_MODE_CRT1:
1033572b676d7Smrg       if(SiS_CheckModeCRT1(pScrn, mymode, vbflag, hcm) == 0xfe) {
1033672b676d7Smrg          pSiS->IsCustom = TRUE;
1033772b676d7Smrg       }
1033872b676d7Smrg       break;
1033972b676d7Smrg    case SIS_MODE_CRT2:
1034072b676d7Smrg       if(vbflag & CRT2_ENABLE) {
1034172b676d7Smrg          if(SiS_CheckModeCRT2(pScrn, mymode, vbflag, hcm) == 0xfe) {
1034272b676d7Smrg	     pSiS->IsCustom = TRUE;
1034372b676d7Smrg          }
1034472b676d7Smrg       } else {
1034572b676d7Smrg          /* This can only happen in mirror mode */
1034672b676d7Smrg          if(SiS_CheckModeCRT1(pScrn, mymode, vbflag, hcm) == 0xfe) {
1034772b676d7Smrg             pSiS->IsCustom = TRUE;
1034872b676d7Smrg          }
1034972b676d7Smrg       }
1035072b676d7Smrg    }
1035172b676d7Smrg
1035272b676d7Smrg#ifdef UNLOCK_ALWAYS
1035372b676d7Smrg    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);    /* Unlock Registers */
1035472b676d7Smrg#endif
1035572b676d7Smrg
1035672b676d7Smrg    inSISIDXREG(SISCR, 0x30, CR30);
1035772b676d7Smrg    inSISIDXREG(SISCR, 0x31, CR31);
1035872b676d7Smrg    CR32 = pSiS->newCR32;
1035972b676d7Smrg    inSISIDXREG(SISCR, 0x33, CR33);
1036072b676d7Smrg
1036172b676d7Smrg    if(pSiS->NewCRLayout) {
1036272b676d7Smrg
1036372b676d7Smrg       inSISIDXREG(SISCR, 0x35, CR35);
1036472b676d7Smrg       inSISIDXREG(SISCR, 0x38, CR38);
1036572b676d7Smrg       inSISIDXREG(SISCR, 0x39, CR39);
1036672b676d7Smrg
1036772b676d7Smrg       xf86DrvMsgVerb(pScrn->scrnIndex, X_PROBED, SISVERBLEVEL,
1036872b676d7Smrg	   "Before: CR30=0x%02x,CR31=0x%02x,CR32=0x%02x,CR33=0x%02x,CR35=0x%02x,CR38=0x%02x\n",
1036972b676d7Smrg              CR30, CR31, CR32, CR33, CR35, CR38);
1037072b676d7Smrg
1037172b676d7Smrg       CR38 &= ~0x07;
1037272b676d7Smrg
1037372b676d7Smrg    } else {
1037472b676d7Smrg
1037572b676d7Smrg       if(pSiS->Chipset != PCI_CHIP_SIS300) {
1037672b676d7Smrg          switch(pSiS->VGAEngine) {
1037772b676d7Smrg             case SIS_300_VGA: temp = 0x35; break;
1037872b676d7Smrg             case SIS_315_VGA: temp = 0x38; break;
1037972b676d7Smrg          }
1038072b676d7Smrg          if(temp) inSISIDXREG(SISCR, temp, CR38);
1038172b676d7Smrg       }
1038272b676d7Smrg       if(pSiS->VGAEngine == SIS_315_VGA) {
1038372b676d7Smrg          inSISIDXREG(SISCR, 0x79, CR79);
1038472b676d7Smrg          CR38 &= ~0x3b;   			/* Clear LCDA/DualEdge and YPbPr bits */
1038572b676d7Smrg       }
1038672b676d7Smrg       inSISIDXREG(SISCR, 0x3b, CR3B);
1038772b676d7Smrg
1038872b676d7Smrg       xf86DrvMsgVerb(pScrn->scrnIndex, X_PROBED, SISVERBLEVEL,
1038972b676d7Smrg	   "Before: CR30=0x%02x, CR31=0x%02x, CR32=0x%02x, CR33=0x%02x, CR%02x=0x%02x\n",
1039072b676d7Smrg              CR30, CR31, CR32, CR33, temp, CR38);
1039172b676d7Smrg    }
1039272b676d7Smrg
1039372b676d7Smrg    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, SISVERBLEVEL, "VBFlags=0x%x\n", pSiS->VBFlags);
1039472b676d7Smrg
1039572b676d7Smrg    CR30 = 0x00;
1039672b676d7Smrg    CR31 &= ~0x60;  /* Clear VB_Drivermode & VB_OutputDisable */
1039772b676d7Smrg    CR31 |= 0x04;   /* Set VB_NotSimuMode (not for 30xB/1400x1050?) */
1039872b676d7Smrg    CR35 = 0x00;
1039972b676d7Smrg
1040072b676d7Smrg    if(!pSiS->NewCRLayout) {
1040172b676d7Smrg       if(!pSiS->AllowHotkey) {
1040272b676d7Smrg          CR31 |= 0x80;   /* Disable hotkey-switch */
1040372b676d7Smrg       }
1040472b676d7Smrg       CR79 &= ~0x10;     /* Enable Backlight control on 315 series */
1040572b676d7Smrg    }
1040672b676d7Smrg
1040772b676d7Smrg    SiS_SetEnableDstn(pSiS->SiS_Pr, FALSE);
1040872b676d7Smrg    SiS_SetEnableFstn(pSiS->SiS_Pr, FALSE);
1040972b676d7Smrg
1041072b676d7Smrg    if((vbflag & CRT1_LCDA) && (viewmode == SIS_MODE_CRT1)) {
1041172b676d7Smrg
1041272b676d7Smrg       CR38 |= 0x02;
1041372b676d7Smrg
1041472b676d7Smrg    } else {
1041572b676d7Smrg
1041672b676d7Smrg       switch(vbflag & (CRT2_TV|CRT2_LCD|CRT2_VGA)) {
1041772b676d7Smrg
1041872b676d7Smrg       case CRT2_TV:
1041972b676d7Smrg
1042072b676d7Smrg          CR38 &= ~0xC0; 	/* Clear Pal M/N bits */
1042172b676d7Smrg
1042272b676d7Smrg          if((pSiS->VBFlags2 & VB2_CHRONTEL) && (vbflag & TV_CHSCART)) {		/* Chrontel */
1042372b676d7Smrg	     CR30 |= 0x10;
1042472b676d7Smrg	     CR38 |= 0x04;
1042572b676d7Smrg	     CR38 &= ~0x08;
1042672b676d7Smrg	     CR31 |= 0x01;
1042772b676d7Smrg	  } else if((pSiS->VBFlags2 & VB2_CHRONTEL) && (vbflag & TV_CHYPBPR525I)) {	/* Chrontel */
1042872b676d7Smrg	     CR38 |= 0x08;
1042972b676d7Smrg	     CR38 &= ~0x04;
1043072b676d7Smrg	     CR31 &= ~0x01;
1043172b676d7Smrg          } else if(vbflag & TV_HIVISION) {	/* SiS bridge */
1043272b676d7Smrg	     if(pSiS->NewCRLayout) {
1043372b676d7Smrg	        CR38 |= 0x04;
1043472b676d7Smrg	        CR35 |= 0x60;
1043572b676d7Smrg	     } else {
1043672b676d7Smrg	        CR30 |= 0x80;
1043772b676d7Smrg		if(pSiS->VGAEngine == SIS_315_VGA) {
1043872b676d7Smrg		   if(pSiS->VBFlags2 & VB2_SISYPBPRBRIDGE) {
1043972b676d7Smrg		      CR38 |= (0x08 | 0x30);
1044072b676d7Smrg		   }
1044172b676d7Smrg		}
1044272b676d7Smrg	     }
1044372b676d7Smrg	     CR31 |= 0x01;
1044472b676d7Smrg	     CR35 |= 0x01;
1044572b676d7Smrg	  } else if(vbflag & TV_YPBPR) {					/* SiS bridge */
1044672b676d7Smrg	     if(pSiS->NewCRLayout) {
1044772b676d7Smrg		CR38 |= 0x04;
1044872b676d7Smrg		CR31 &= ~0x01;
1044972b676d7Smrg		CR35 &= ~0x01;
1045072b676d7Smrg		if(vbflag & (TV_YPBPR525P | TV_YPBPR625P)) CR35 |= 0x20;
1045172b676d7Smrg		else if(vbflag & TV_YPBPR750P)             CR35 |= 0x40;
1045272b676d7Smrg		else if(vbflag & TV_YPBPR1080I)            CR35 |= 0x60;
1045372b676d7Smrg
1045472b676d7Smrg		if(vbflag & (TV_YPBPR625I | TV_YPBPR625P)) {
1045572b676d7Smrg		   CR31 |= 0x01;
1045672b676d7Smrg		   CR35 |= 0x01;
1045772b676d7Smrg		}
1045872b676d7Smrg
1045972b676d7Smrg		CR39 &= ~0x03;
1046072b676d7Smrg		if((vbflag & TV_YPBPRAR) == TV_YPBPR43LB)     CR39 |= 0x00;
1046172b676d7Smrg		else if((vbflag & TV_YPBPRAR) == TV_YPBPR43)  CR39 |= 0x01;
1046272b676d7Smrg		else if((vbflag & TV_YPBPRAR) == TV_YPBPR169) CR39 |= 0x02;
1046372b676d7Smrg		else					      CR39 |= 0x03;
1046472b676d7Smrg	     } else if(pSiS->SiS_SD_Flags & SiS_SD_SUPPORTYPBPR) {
1046572b676d7Smrg		CR30 |= 0x80;
1046672b676d7Smrg		CR38 |= 0x08;
1046772b676d7Smrg		CR31 &= ~0x01;
1046872b676d7Smrg		if(vbflag & (TV_YPBPR525P|TV_YPBPR625P)) CR38 |= 0x10;
1046972b676d7Smrg		else if(vbflag & TV_YPBPR750P)  	 CR38 |= 0x20;
1047072b676d7Smrg		else if(vbflag & TV_YPBPR1080I)		 CR38 |= 0x30;
1047172b676d7Smrg
1047272b676d7Smrg		if(vbflag & (TV_YPBPR625I | TV_YPBPR625P)) CR31 |= 0x01;
1047372b676d7Smrg
1047472b676d7Smrg		if(pSiS->SiS_SD_Flags & SiS_SD_SUPPORTYPBPRAR) {
1047572b676d7Smrg		   CR3B &= ~0x03;
1047672b676d7Smrg		   if((vbflag & TV_YPBPRAR) == TV_YPBPR43LB)     CR3B |= 0x00;
1047772b676d7Smrg		   else if((vbflag & TV_YPBPRAR) == TV_YPBPR43)  CR3B |= 0x03;
1047872b676d7Smrg		   else if((vbflag & TV_YPBPRAR) == TV_YPBPR169) CR3B |= 0x01;
1047972b676d7Smrg		   else					         CR3B |= 0x03;
1048072b676d7Smrg		}
1048172b676d7Smrg	     }
1048272b676d7Smrg          } else {								/* All */
1048372b676d7Smrg	     if(vbflag & TV_SCART)  CR30 |= 0x10;
1048472b676d7Smrg	     if(vbflag & TV_SVIDEO) CR30 |= 0x08;
1048572b676d7Smrg	     if(vbflag & TV_AVIDEO) CR30 |= 0x04;
1048672b676d7Smrg	     if(!(CR30 & 0x1C))	    CR30 |= 0x08;    /* default: SVIDEO */
1048772b676d7Smrg
1048872b676d7Smrg	     if(vbflag & TV_PAL) {
1048972b676d7Smrg		CR31 |= 0x01;
1049072b676d7Smrg		CR35 |= 0x01;
1049172b676d7Smrg		if( (pSiS->VBFlags2 & VB2_SISBRIDGE) ||
1049272b676d7Smrg		    ((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->ChrontelType == CHRONTEL_701x)) )  {
1049372b676d7Smrg		   if(vbflag & TV_PALM) {
1049472b676d7Smrg		      CR38 |= 0x40;
1049572b676d7Smrg		      CR35 |= 0x04;
1049672b676d7Smrg		   } else if(vbflag & TV_PALN) {
1049772b676d7Smrg		      CR38 |= 0x80;
1049872b676d7Smrg		      CR35 |= 0x08;
1049972b676d7Smrg		   }
1050072b676d7Smrg	        }
1050172b676d7Smrg	     } else {
1050272b676d7Smrg		CR31 &= ~0x01;
1050372b676d7Smrg		CR35 &= ~0x01;
1050472b676d7Smrg		if(vbflag & TV_NTSCJ) {
1050572b676d7Smrg		   CR38 |= 0x40;  /* TW, not BIOS */
1050672b676d7Smrg		   CR35 |= 0x02;
1050772b676d7Smrg		}
1050872b676d7Smrg	     }
1050972b676d7Smrg	     if(vbflag & TV_SCART) {
1051072b676d7Smrg		CR31 |= 0x01;
1051172b676d7Smrg		CR35 |= 0x01;
1051272b676d7Smrg	     }
1051372b676d7Smrg	  }
1051472b676d7Smrg
1051572b676d7Smrg	  CR31 &= ~0x04;   /* Clear NotSimuMode */
1051672b676d7Smrg	  pSiS->SiS_Pr->SiS_CHOverScan = pSiS->UseCHOverScan;
1051772b676d7Smrg	  if((pSiS->OptTVSOver == 1) && (pSiS->ChrontelType == CHRONTEL_700x)) {
1051872b676d7Smrg	     pSiS->SiS_Pr->SiS_CHSOverScan = TRUE;
1051972b676d7Smrg	  } else {
1052072b676d7Smrg	     pSiS->SiS_Pr->SiS_CHSOverScan = FALSE;
1052172b676d7Smrg	  }
1052272b676d7Smrg#ifdef SIS_CP
1052372b676d7Smrg	  SIS_CP_DRIVER_CONFIG
1052472b676d7Smrg#endif
1052572b676d7Smrg	  break;
1052672b676d7Smrg
1052772b676d7Smrg       case CRT2_LCD:
1052872b676d7Smrg	  CR30 |= 0x20;
1052972b676d7Smrg	  SiS_SetEnableDstn(pSiS->SiS_Pr, pSiS->DSTN);
1053072b676d7Smrg	  SiS_SetEnableFstn(pSiS->SiS_Pr, pSiS->FSTN);
1053172b676d7Smrg	  break;
1053272b676d7Smrg
1053372b676d7Smrg       case CRT2_VGA:
1053472b676d7Smrg	  CR30 |= 0x40;
1053572b676d7Smrg	  break;
1053672b676d7Smrg
1053772b676d7Smrg       default:
1053872b676d7Smrg	  CR30 |= 0x00;
1053972b676d7Smrg	  CR31 |= 0x20;    /* VB_OUTPUT_DISABLE */
1054072b676d7Smrg	  if(pSiS->UseVESA) {
1054172b676d7Smrg	     crt1rateindex = SISSearchCRT1Rate(pScrn, mymode);
1054272b676d7Smrg	  }
1054372b676d7Smrg       }
1054472b676d7Smrg
1054572b676d7Smrg    }
1054672b676d7Smrg
1054772b676d7Smrg    if(vbflag & CRT1_LCDA) {
1054872b676d7Smrg       switch(viewmode) {
1054972b676d7Smrg       case SIS_MODE_CRT1:
1055072b676d7Smrg	  CR38 |= 0x01;
1055172b676d7Smrg	  break;
1055272b676d7Smrg       case SIS_MODE_CRT2:
1055372b676d7Smrg	  if(vbflag & (CRT2_TV|CRT2_VGA)) {
1055472b676d7Smrg	     CR30 |= 0x02;
1055572b676d7Smrg	     CR38 |= 0x01;
1055672b676d7Smrg	  } else {
1055772b676d7Smrg	     CR38 |= 0x03;
1055872b676d7Smrg	  }
1055972b676d7Smrg	  break;
1056072b676d7Smrg       case SIS_MODE_SIMU:
1056172b676d7Smrg       default:
1056272b676d7Smrg	  if(vbflag & (CRT2_TV|CRT2_LCD|CRT2_VGA)) {
1056372b676d7Smrg	     CR30 |= 0x01;
1056472b676d7Smrg	  }
1056572b676d7Smrg	  break;
1056672b676d7Smrg       }
1056772b676d7Smrg    } else {
1056872b676d7Smrg       if(vbflag & (CRT2_TV|CRT2_LCD|CRT2_VGA)) {
1056972b676d7Smrg          CR30 |= 0x01;
1057072b676d7Smrg       }
1057172b676d7Smrg    }
1057272b676d7Smrg
1057372b676d7Smrg    if(pSiS->UseVESA) {
1057472b676d7Smrg       CR31 &= ~0x40;   /* Clear Drivermode */
1057572b676d7Smrg       CR31 |= 0x06;    /* Set SlaveMode, Enable SimuMode in Slavemode */
1057672b676d7Smrg#ifdef TWDEBUG
1057772b676d7Smrg       CR31 |= 0x40;    /* DEBUG (for non-slave mode VESA) */
1057872b676d7Smrg       crt1rateindex = SISSearchCRT1Rate(pScrn, mymode);
1057972b676d7Smrg#endif
1058072b676d7Smrg    } else {
1058172b676d7Smrg       CR31 |=  0x40;  /* Set Drivermode */
1058272b676d7Smrg       CR31 &=  ~0x06; /* Disable SlaveMode, disable SimuMode in SlaveMode */
1058372b676d7Smrg       if(!pSiS->IsCustom) {
1058472b676d7Smrg          crt1rateindex = SISSearchCRT1Rate(pScrn, mymode);
1058572b676d7Smrg       }
1058672b676d7Smrg    }
1058772b676d7Smrg
1058872b676d7Smrg    switch(viewmode) {
1058972b676d7Smrg	case SIS_MODE_SIMU:
1059072b676d7Smrg	   CR33 = 0;
1059172b676d7Smrg	   if(!(vbflag & CRT1_LCDA)) {
1059272b676d7Smrg	      CR33 |= (crt1rateindex & 0x0f);
1059372b676d7Smrg	   }
1059472b676d7Smrg	   if(vbflag & CRT2_VGA) {
1059572b676d7Smrg	      CR33 |= ((crt1rateindex & 0x0f) << 4);
1059672b676d7Smrg	   }
1059772b676d7Smrg	   break;
1059872b676d7Smrg	case SIS_MODE_CRT1:
1059972b676d7Smrg	   CR33 &= 0xf0;
1060072b676d7Smrg	   if(!(vbflag & CRT1_LCDA)) {
1060172b676d7Smrg	      CR33 |= (crt1rateindex & 0x0f);
1060272b676d7Smrg	   }
1060372b676d7Smrg	   break;
1060472b676d7Smrg	case SIS_MODE_CRT2:
1060572b676d7Smrg	   CR33 &= 0x0f;
1060672b676d7Smrg	   if(vbflag & CRT2_VGA) {
1060772b676d7Smrg	      CR33 |= ((crt1rateindex & 0x0f) << 4);
1060872b676d7Smrg	   }
1060972b676d7Smrg	   break;
1061072b676d7Smrg     }
1061172b676d7Smrg
1061272b676d7Smrg     if((!pSiS->UseVESA) && (vbflag & CRT2_ENABLE)) {
1061372b676d7Smrg	if(pSiS->CRT1off) CR33 &= 0xf0;
1061472b676d7Smrg     }
1061572b676d7Smrg
1061672b676d7Smrg     if(pSiS->NewCRLayout) {
1061772b676d7Smrg
1061872b676d7Smrg	CR31 &= 0xfe;   /* Clear PAL flag (now in CR35) */
1061972b676d7Smrg	CR38 &= 0x07;   /* Use only LCDA and HiVision/YPbPr bits */
1062072b676d7Smrg	outSISIDXREG(SISCR, 0x30, CR30);
1062172b676d7Smrg	outSISIDXREG(SISCR, 0x31, CR31);
1062272b676d7Smrg	outSISIDXREG(SISCR, 0x33, CR33);
1062372b676d7Smrg	outSISIDXREG(SISCR, 0x35, CR35);
1062472b676d7Smrg	setSISIDXREG(SISCR, 0x38, 0xf8, CR38);
1062572b676d7Smrg	outSISIDXREG(SISCR, 0x39, CR39);
1062672b676d7Smrg
1062772b676d7Smrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, SISVERBLEVEL,
1062872b676d7Smrg		"After:  CR30=0x%02x,CR31=0x%02x,CR33=0x%02x,CR35=0x%02x,CR38=%02x\n",
1062972b676d7Smrg		    CR30, CR31, CR33, CR35, CR38);
1063072b676d7Smrg
1063172b676d7Smrg     } else {
1063272b676d7Smrg
1063372b676d7Smrg	outSISIDXREG(SISCR, 0x30, CR30);
1063472b676d7Smrg	outSISIDXREG(SISCR, 0x31, CR31);
1063572b676d7Smrg	outSISIDXREG(SISCR, 0x33, CR33);
1063672b676d7Smrg	if(temp) {
1063772b676d7Smrg	   outSISIDXREG(SISCR, temp, CR38);
1063872b676d7Smrg	}
1063972b676d7Smrg	if(pSiS->VGAEngine == SIS_315_VGA) {
1064072b676d7Smrg	   outSISIDXREG(SISCR, 0x3b, CR3B);
1064172b676d7Smrg	   outSISIDXREG(SISCR, 0x79, CR79);
1064272b676d7Smrg	}
1064372b676d7Smrg
1064472b676d7Smrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, SISVERBLEVEL,
1064572b676d7Smrg		"After:  CR30=0x%02x,CR31=0x%02x,CR33=0x%02x,CR%02x=%02x\n",
1064672b676d7Smrg		    CR30, CR31, CR33, temp, CR38);
1064772b676d7Smrg     }
1064872b676d7Smrg
1064972b676d7Smrg     pSiS->SiS_Pr->SiS_UseOEM = pSiS->OptUseOEM;
1065072b676d7Smrg
1065172b676d7Smrg     /* Enable TurboQueue */
1065272b676d7Smrg#ifdef SISVRAMQ
1065372b676d7Smrg     if(pSiS->VGAEngine != SIS_315_VGA)
1065472b676d7Smrg#endif
1065572b676d7Smrg	SiSEnableTurboQueue(pScrn);
1065672b676d7Smrg
1065772b676d7Smrg     if((!pSiS->UseVESA) && (pSiS->VBFlags & CRT2_ENABLE)) {
1065872b676d7Smrg	/* Switch on CRT1 for modes that require the bridge in SlaveMode */
1065972b676d7Smrg	andSISIDXREG(SISSR,0x1f,0x3f);
1066072b676d7Smrg	inSISIDXREG(SISCR, 0x17, CR17);
1066172b676d7Smrg	if(!(CR17 & 0x80)) {
1066272b676d7Smrg	   orSISIDXREG(SISCR, 0x17, 0x80);
1066372b676d7Smrg	   outSISIDXREG(SISSR, 0x00, 0x01);
1066472b676d7Smrg	   usleep(10000);
1066572b676d7Smrg	   outSISIDXREG(SISSR, 0x00, 0x03);
1066672b676d7Smrg	}
1066772b676d7Smrg     }
1066872b676d7Smrg}
1066972b676d7Smrg
1067072b676d7Smrg/* Functions for adjusting various TV settings */
1067172b676d7Smrg
1067272b676d7Smrg/* These are used by the PostSetMode() functions as well as
1067372b676d7Smrg * the display properties tool SiSCtrl.
1067472b676d7Smrg *
1067572b676d7Smrg * There is each a Set and a Get routine. The Set functions
1067672b676d7Smrg * take a value of the same range as the corresponding option.
1067772b676d7Smrg * The Get routines return a value of the same range (although
1067872b676d7Smrg * not necessarily the same value as previously set because
1067972b676d7Smrg * of the lower resolution of the respective setting compared
1068072b676d7Smrg * to the valid range).
1068172b676d7Smrg * The Get routines return -2 on error (eg. hardware does not
1068272b676d7Smrg * support this setting).
1068372b676d7Smrg * Note: The x and y positioning routines accept a position
1068472b676d7Smrg * RELATIVE to the default position. All other routines
1068572b676d7Smrg * take ABSOLUTE values.
1068672b676d7Smrg *
1068772b676d7Smrg * The Set functions will store the property regardless if TV is
1068872b676d7Smrg * currently used or not and if the hardware supports the property
1068972b676d7Smrg * or not. The Get routines will return this stored
1069072b676d7Smrg * value if TV is not currently used (because the register does
1069172b676d7Smrg * not contain the correct value then) or if the hardware supports
1069272b676d7Smrg * the respective property. This should make it easier for the
1069372b676d7Smrg * display property tool because it does not have to know the
1069472b676d7Smrg * hardware features.
1069572b676d7Smrg *
1069672b676d7Smrg * All the routines are dual head aware. It does not matter
1069772b676d7Smrg * if the function is called from the CRT1 or CRT2 session.
1069872b676d7Smrg * The values will be in pSiSEnt anyway, and read from there
1069972b676d7Smrg * if we're running dual head.
1070072b676d7Smrg */
1070172b676d7Smrg
1070272b676d7Smrgvoid SiS_SetCHTVlumabandwidthcvbs(ScrnInfoPtr pScrn, int val)
1070372b676d7Smrg{
1070472b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1070572b676d7Smrg#ifdef SISDUALHEAD
1070672b676d7Smrg   SISEntPtr pSiSEnt = pSiS->entityPrivate;
1070772b676d7Smrg#endif
1070872b676d7Smrg
1070972b676d7Smrg   pSiS->chtvlumabandwidthcvbs = val;
1071072b676d7Smrg#ifdef SISDUALHEAD
1071172b676d7Smrg   if(pSiSEnt) pSiSEnt->chtvlumabandwidthcvbs = val;
1071272b676d7Smrg#endif
1071372b676d7Smrg
1071472b676d7Smrg   if(!(pSiS->VBFlags & CRT2_TV)) return;
1071572b676d7Smrg   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
1071672b676d7Smrg
1071772b676d7Smrg#ifdef UNLOCK_ALWAYS
1071872b676d7Smrg   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
1071972b676d7Smrg#endif
1072072b676d7Smrg
1072172b676d7Smrg   switch(pSiS->ChrontelType) {
1072272b676d7Smrg       case CHRONTEL_700x:
1072372b676d7Smrg           val /= 8;
1072472b676d7Smrg           if((val == 0) || (val == 1)) {
1072572b676d7Smrg	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, val, 0xFE);
1072672b676d7Smrg           }
1072772b676d7Smrg	   break;
1072872b676d7Smrg       case CHRONTEL_701x:
1072972b676d7Smrg           val /= 4;
1073072b676d7Smrg	   if((val >= 0) && (val <= 3)) {
1073172b676d7Smrg	       SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x02, val, 0xFC);
1073272b676d7Smrg	   }
1073372b676d7Smrg           break;
1073472b676d7Smrg   }
1073572b676d7Smrg}
1073672b676d7Smrg
1073772b676d7Smrgint SiS_GetCHTVlumabandwidthcvbs(ScrnInfoPtr pScrn)
1073872b676d7Smrg{
1073972b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1074072b676d7Smrg#ifdef SISDUALHEAD
1074172b676d7Smrg   SISEntPtr pSiSEnt = pSiS->entityPrivate;
1074272b676d7Smrg#endif
1074372b676d7Smrg
1074472b676d7Smrg   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
1074572b676d7Smrg#ifdef SISDUALHEAD
1074672b676d7Smrg      if(pSiSEnt && pSiS->DualHeadMode)
1074772b676d7Smrg           return (int)pSiSEnt->chtvlumabandwidthcvbs;
1074872b676d7Smrg      else
1074972b676d7Smrg#endif
1075072b676d7Smrg           return (int)pSiS->chtvlumabandwidthcvbs;
1075172b676d7Smrg   } else {
1075272b676d7Smrg#ifdef UNLOCK_ALWAYS
1075372b676d7Smrg      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
1075472b676d7Smrg#endif
1075572b676d7Smrg      switch(pSiS->ChrontelType) {
1075672b676d7Smrg      case CHRONTEL_700x:
1075772b676d7Smrg           return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x03) & 0x01) * 8);
1075872b676d7Smrg      case CHRONTEL_701x:
1075972b676d7Smrg	   return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x02) & 0x03) * 4);
1076072b676d7Smrg      default:
1076172b676d7Smrg           return (int)pSiS->chtvlumabandwidthcvbs;
1076272b676d7Smrg      }
1076372b676d7Smrg   }
1076472b676d7Smrg}
1076572b676d7Smrg
1076672b676d7Smrgvoid SiS_SetCHTVlumabandwidthsvideo(ScrnInfoPtr pScrn, int val)
1076772b676d7Smrg{
1076872b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1076972b676d7Smrg#ifdef SISDUALHEAD
1077072b676d7Smrg   SISEntPtr pSiSEnt = pSiS->entityPrivate;
1077172b676d7Smrg#endif
1077272b676d7Smrg
1077372b676d7Smrg   pSiS->chtvlumabandwidthsvideo = val;
1077472b676d7Smrg#ifdef SISDUALHEAD
1077572b676d7Smrg   if(pSiSEnt) pSiSEnt->chtvlumabandwidthsvideo = val;
1077672b676d7Smrg#endif
1077772b676d7Smrg
1077872b676d7Smrg   if(!(pSiS->VBFlags & CRT2_TV)) return;
1077972b676d7Smrg   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
1078072b676d7Smrg
1078172b676d7Smrg#ifdef UNLOCK_ALWAYS
1078272b676d7Smrg   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
1078372b676d7Smrg#endif
1078472b676d7Smrg
1078572b676d7Smrg   switch(pSiS->ChrontelType) {
1078672b676d7Smrg       case CHRONTEL_700x:
1078772b676d7Smrg           val /= 6;
1078872b676d7Smrg           if((val >= 0) && (val <= 2)) {
1078972b676d7Smrg	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, (val << 1), 0xF9);
1079072b676d7Smrg           }
1079172b676d7Smrg	   break;
1079272b676d7Smrg       case CHRONTEL_701x:
1079372b676d7Smrg           val /= 4;
1079472b676d7Smrg	   if((val >= 0) && (val <= 3)) {
1079572b676d7Smrg	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x02, (val << 2), 0xF3);
1079672b676d7Smrg	   }
1079772b676d7Smrg           break;
1079872b676d7Smrg   }
1079972b676d7Smrg}
1080072b676d7Smrg
1080172b676d7Smrgint SiS_GetCHTVlumabandwidthsvideo(ScrnInfoPtr pScrn)
1080272b676d7Smrg{
1080372b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1080472b676d7Smrg#ifdef SISDUALHEAD
1080572b676d7Smrg   SISEntPtr pSiSEnt = pSiS->entityPrivate;
1080672b676d7Smrg#endif
1080772b676d7Smrg
1080872b676d7Smrg   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
1080972b676d7Smrg#ifdef SISDUALHEAD
1081072b676d7Smrg      if(pSiSEnt && pSiS->DualHeadMode)
1081172b676d7Smrg           return (int)pSiSEnt->chtvlumabandwidthsvideo;
1081272b676d7Smrg      else
1081372b676d7Smrg#endif
1081472b676d7Smrg           return (int)pSiS->chtvlumabandwidthsvideo;
1081572b676d7Smrg   } else {
1081672b676d7Smrg#ifdef UNLOCK_ALWAYS
1081772b676d7Smrg      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
1081872b676d7Smrg#endif
1081972b676d7Smrg      switch(pSiS->ChrontelType) {
1082072b676d7Smrg      case CHRONTEL_700x:
1082172b676d7Smrg           return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x03) & 0x06) >> 1) * 6);
1082272b676d7Smrg      case CHRONTEL_701x:
1082372b676d7Smrg	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x02) & 0x0c) >> 2) * 4);
1082472b676d7Smrg      default:
1082572b676d7Smrg           return (int)pSiS->chtvlumabandwidthsvideo;
1082672b676d7Smrg      }
1082772b676d7Smrg   }
1082872b676d7Smrg}
1082972b676d7Smrg
1083072b676d7Smrgvoid SiS_SetCHTVlumaflickerfilter(ScrnInfoPtr pScrn, int val)
1083172b676d7Smrg{
1083272b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1083372b676d7Smrg#ifdef SISDUALHEAD
1083472b676d7Smrg   SISEntPtr pSiSEnt = pSiS->entityPrivate;
1083572b676d7Smrg#endif
1083672b676d7Smrg
1083772b676d7Smrg   pSiS->chtvlumaflickerfilter = val;
1083872b676d7Smrg#ifdef SISDUALHEAD
1083972b676d7Smrg   if(pSiSEnt) pSiSEnt->chtvlumaflickerfilter = val;
1084072b676d7Smrg#endif
1084172b676d7Smrg
1084272b676d7Smrg   if(!(pSiS->VBFlags & CRT2_TV)) return;
1084372b676d7Smrg   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
1084472b676d7Smrg
1084572b676d7Smrg#ifdef UNLOCK_ALWAYS
1084672b676d7Smrg   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
1084772b676d7Smrg#endif
1084872b676d7Smrg
1084972b676d7Smrg   switch(pSiS->ChrontelType) {
1085072b676d7Smrg       case CHRONTEL_700x:
1085172b676d7Smrg           val /= 6;
1085272b676d7Smrg           if((val >= 0) && (val <= 2)) {
1085372b676d7Smrg	      UShort reg = 0;
1085472b676d7Smrg	      reg = SiS_GetCH70xx(pSiS->SiS_Pr, 0x01);
1085572b676d7Smrg	      reg = (reg & 0xf0) | ((reg & 0x0c) >> 2) | (val << 2);
1085672b676d7Smrg              SiS_SetCH70xx(pSiS->SiS_Pr, 0x01, reg);
1085772b676d7Smrg           }
1085872b676d7Smrg	   break;
1085972b676d7Smrg       case CHRONTEL_701x:
1086072b676d7Smrg           val /= 4;
1086172b676d7Smrg	   if((val >= 0) && (val <= 3)) {
1086272b676d7Smrg	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x01, (val << 2), 0xF3);
1086372b676d7Smrg	   }
1086472b676d7Smrg           break;
1086572b676d7Smrg   }
1086672b676d7Smrg}
1086772b676d7Smrg
1086872b676d7Smrgint SiS_GetCHTVlumaflickerfilter(ScrnInfoPtr pScrn)
1086972b676d7Smrg{
1087072b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1087172b676d7Smrg#ifdef SISDUALHEAD
1087272b676d7Smrg   SISEntPtr pSiSEnt = pSiS->entityPrivate;
1087372b676d7Smrg#endif
1087472b676d7Smrg
1087572b676d7Smrg   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
1087672b676d7Smrg#ifdef SISDUALHEAD
1087772b676d7Smrg      if(pSiSEnt && pSiS->DualHeadMode)
1087872b676d7Smrg          return (int)pSiSEnt->chtvlumaflickerfilter;
1087972b676d7Smrg      else
1088072b676d7Smrg#endif
1088172b676d7Smrg          return (int)pSiS->chtvlumaflickerfilter;
1088272b676d7Smrg   } else {
1088372b676d7Smrg#ifdef UNLOCK_ALWAYS
1088472b676d7Smrg      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
1088572b676d7Smrg#endif
1088672b676d7Smrg      switch(pSiS->ChrontelType) {
1088772b676d7Smrg      case CHRONTEL_700x:
1088872b676d7Smrg           return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x01) & 0x03) * 6);
1088972b676d7Smrg      case CHRONTEL_701x:
1089072b676d7Smrg	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x01) & 0x0c) >> 2) * 4);
1089172b676d7Smrg      default:
1089272b676d7Smrg           return (int)pSiS->chtvlumaflickerfilter;
1089372b676d7Smrg      }
1089472b676d7Smrg   }
1089572b676d7Smrg}
1089672b676d7Smrg
1089772b676d7Smrgvoid SiS_SetCHTVchromabandwidth(ScrnInfoPtr pScrn, int val)
1089872b676d7Smrg{
1089972b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1090072b676d7Smrg#ifdef SISDUALHEAD
1090172b676d7Smrg   SISEntPtr pSiSEnt = pSiS->entityPrivate;
1090272b676d7Smrg#endif
1090372b676d7Smrg
1090472b676d7Smrg   pSiS->chtvchromabandwidth = val;
1090572b676d7Smrg#ifdef SISDUALHEAD
1090672b676d7Smrg   if(pSiSEnt) pSiSEnt->chtvchromabandwidth = val;
1090772b676d7Smrg#endif
1090872b676d7Smrg
1090972b676d7Smrg   if(!(pSiS->VBFlags & CRT2_TV)) return;
1091072b676d7Smrg   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
1091172b676d7Smrg
1091272b676d7Smrg#ifdef UNLOCK_ALWAYS
1091372b676d7Smrg   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
1091472b676d7Smrg#endif
1091572b676d7Smrg
1091672b676d7Smrg   switch(pSiS->ChrontelType) {
1091772b676d7Smrg       case CHRONTEL_700x:
1091872b676d7Smrg           val /= 4;
1091972b676d7Smrg           if((val >= 0) && (val <= 3)) {
1092072b676d7Smrg              SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, (val << 4), 0xCF);
1092172b676d7Smrg           }
1092272b676d7Smrg	   break;
1092372b676d7Smrg       case CHRONTEL_701x:
1092472b676d7Smrg           val /= 8;
1092572b676d7Smrg	   if((val >= 0) && (val <= 1)) {
1092672b676d7Smrg	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x02, (val << 4), 0xEF);
1092772b676d7Smrg	   }
1092872b676d7Smrg           break;
1092972b676d7Smrg   }
1093072b676d7Smrg}
1093172b676d7Smrg
1093272b676d7Smrgint SiS_GetCHTVchromabandwidth(ScrnInfoPtr pScrn)
1093372b676d7Smrg{
1093472b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1093572b676d7Smrg#ifdef SISDUALHEAD
1093672b676d7Smrg   SISEntPtr pSiSEnt = pSiS->entityPrivate;
1093772b676d7Smrg#endif
1093872b676d7Smrg
1093972b676d7Smrg   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
1094072b676d7Smrg#ifdef SISDUALHEAD
1094172b676d7Smrg      if(pSiSEnt && pSiS->DualHeadMode)
1094272b676d7Smrg           return (int)pSiSEnt->chtvchromabandwidth;
1094372b676d7Smrg      else
1094472b676d7Smrg#endif
1094572b676d7Smrg           return (int)pSiS->chtvchromabandwidth;
1094672b676d7Smrg   } else {
1094772b676d7Smrg#ifdef UNLOCK_ALWAYS
1094872b676d7Smrg      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
1094972b676d7Smrg#endif
1095072b676d7Smrg      switch(pSiS->ChrontelType) {
1095172b676d7Smrg      case CHRONTEL_700x:
1095272b676d7Smrg           return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x03) & 0x30) >> 4) * 4);
1095372b676d7Smrg      case CHRONTEL_701x:
1095472b676d7Smrg	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x02) & 0x10) >> 4) * 8);
1095572b676d7Smrg      default:
1095672b676d7Smrg           return (int)pSiS->chtvchromabandwidth;
1095772b676d7Smrg      }
1095872b676d7Smrg   }
1095972b676d7Smrg}
1096072b676d7Smrg
1096172b676d7Smrgvoid SiS_SetCHTVchromaflickerfilter(ScrnInfoPtr pScrn, int val)
1096272b676d7Smrg{
1096372b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1096472b676d7Smrg#ifdef SISDUALHEAD
1096572b676d7Smrg   SISEntPtr pSiSEnt = pSiS->entityPrivate;
1096672b676d7Smrg#endif
1096772b676d7Smrg
1096872b676d7Smrg   pSiS->chtvchromaflickerfilter = val;
1096972b676d7Smrg#ifdef SISDUALHEAD
1097072b676d7Smrg   if(pSiSEnt) pSiSEnt->chtvchromaflickerfilter = val;
1097172b676d7Smrg#endif
1097272b676d7Smrg
1097372b676d7Smrg   if(!(pSiS->VBFlags & CRT2_TV)) return;
1097472b676d7Smrg   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
1097572b676d7Smrg
1097672b676d7Smrg#ifdef UNLOCK_ALWAYS
1097772b676d7Smrg   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
1097872b676d7Smrg#endif
1097972b676d7Smrg
1098072b676d7Smrg   switch(pSiS->ChrontelType) {
1098172b676d7Smrg       case CHRONTEL_700x:
1098272b676d7Smrg           val /= 6;
1098372b676d7Smrg           if((val >= 0) && (val <= 2)) {
1098472b676d7Smrg	      UShort reg = 0;
1098572b676d7Smrg	      reg = SiS_GetCH70xx(pSiS->SiS_Pr, 0x01);
1098672b676d7Smrg	      reg = (reg & 0xc0) | ((reg & 0x0c) >> 2) | ((reg & 0x03) << 2) | (val << 4);
1098772b676d7Smrg              SiS_SetCH70xx(pSiS->SiS_Pr, 0x01, reg);
1098872b676d7Smrg           }
1098972b676d7Smrg	   break;
1099072b676d7Smrg       case CHRONTEL_701x:
1099172b676d7Smrg           val /= 4;
1099272b676d7Smrg	   if((val >= 0) && (val <= 3)) {
1099372b676d7Smrg	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x01, (val << 4), 0xCF);
1099472b676d7Smrg	   }
1099572b676d7Smrg           break;
1099672b676d7Smrg   }
1099772b676d7Smrg}
1099872b676d7Smrg
1099972b676d7Smrgint SiS_GetCHTVchromaflickerfilter(ScrnInfoPtr pScrn)
1100072b676d7Smrg{
1100172b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1100272b676d7Smrg#ifdef SISDUALHEAD
1100372b676d7Smrg   SISEntPtr pSiSEnt = pSiS->entityPrivate;
1100472b676d7Smrg#endif
1100572b676d7Smrg
1100672b676d7Smrg   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
1100772b676d7Smrg#ifdef SISDUALHEAD
1100872b676d7Smrg      if(pSiSEnt && pSiS->DualHeadMode)
1100972b676d7Smrg           return (int)pSiSEnt->chtvchromaflickerfilter;
1101072b676d7Smrg      else
1101172b676d7Smrg#endif
1101272b676d7Smrg           return (int)pSiS->chtvchromaflickerfilter;
1101372b676d7Smrg   } else {
1101472b676d7Smrg#ifdef UNLOCK_ALWAYS
1101572b676d7Smrg      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
1101672b676d7Smrg#endif
1101772b676d7Smrg      switch(pSiS->ChrontelType) {
1101872b676d7Smrg      case CHRONTEL_700x:
1101972b676d7Smrg           return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x01) & 0x30) >> 4) * 6);
1102072b676d7Smrg      case CHRONTEL_701x:
1102172b676d7Smrg	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x01) & 0x30) >> 4) * 4);
1102272b676d7Smrg      default:
1102372b676d7Smrg           return (int)pSiS->chtvchromaflickerfilter;
1102472b676d7Smrg      }
1102572b676d7Smrg   }
1102672b676d7Smrg}
1102772b676d7Smrg
1102872b676d7Smrgvoid SiS_SetCHTVcvbscolor(ScrnInfoPtr pScrn, int val)
1102972b676d7Smrg{
1103072b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1103172b676d7Smrg#ifdef SISDUALHEAD
1103272b676d7Smrg   SISEntPtr pSiSEnt = pSiS->entityPrivate;
1103372b676d7Smrg#endif
1103472b676d7Smrg
1103572b676d7Smrg   pSiS->chtvcvbscolor = val ? 1 : 0;
1103672b676d7Smrg#ifdef SISDUALHEAD
1103772b676d7Smrg   if(pSiSEnt) pSiSEnt->chtvcvbscolor = pSiS->chtvcvbscolor;
1103872b676d7Smrg#endif
1103972b676d7Smrg
1104072b676d7Smrg   if(!(pSiS->VBFlags & CRT2_TV)) return;
1104172b676d7Smrg   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
1104272b676d7Smrg
1104372b676d7Smrg#ifdef UNLOCK_ALWAYS
1104472b676d7Smrg   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
1104572b676d7Smrg#endif
1104672b676d7Smrg
1104772b676d7Smrg   switch(pSiS->ChrontelType) {
1104872b676d7Smrg       case CHRONTEL_700x:
1104972b676d7Smrg           if(!val)  SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, 0x40, 0x00);
1105072b676d7Smrg           else      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, 0x00, ~0x40);
1105172b676d7Smrg	   break;
1105272b676d7Smrg       case CHRONTEL_701x:
1105372b676d7Smrg           if(!val)  SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x02, 0x00, ~0x20);
1105472b676d7Smrg	   else      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x02, 0x20, 0x00);
1105572b676d7Smrg           break;
1105672b676d7Smrg   }
1105772b676d7Smrg}
1105872b676d7Smrg
1105972b676d7Smrgint SiS_GetCHTVcvbscolor(ScrnInfoPtr pScrn)
1106072b676d7Smrg{
1106172b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1106272b676d7Smrg#ifdef SISDUALHEAD
1106372b676d7Smrg   SISEntPtr pSiSEnt = pSiS->entityPrivate;
1106472b676d7Smrg#endif
1106572b676d7Smrg
1106672b676d7Smrg   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
1106772b676d7Smrg#ifdef SISDUALHEAD
1106872b676d7Smrg      if(pSiSEnt && pSiS->DualHeadMode)
1106972b676d7Smrg           return (int)pSiSEnt->chtvcvbscolor;
1107072b676d7Smrg      else
1107172b676d7Smrg#endif
1107272b676d7Smrg           return (int)pSiS->chtvcvbscolor;
1107372b676d7Smrg   } else {
1107472b676d7Smrg#ifdef UNLOCK_ALWAYS
1107572b676d7Smrg      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
1107672b676d7Smrg#endif
1107772b676d7Smrg      switch(pSiS->ChrontelType) {
1107872b676d7Smrg      case CHRONTEL_700x:
1107972b676d7Smrg           return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x03) & 0x40) >> 6) ^ 0x01);
1108072b676d7Smrg      case CHRONTEL_701x:
1108172b676d7Smrg	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x02) & 0x20) >> 5) ^ 0x01);
1108272b676d7Smrg      default:
1108372b676d7Smrg           return (int)pSiS->chtvcvbscolor;
1108472b676d7Smrg      }
1108572b676d7Smrg   }
1108672b676d7Smrg}
1108772b676d7Smrg
1108872b676d7Smrgvoid SiS_SetCHTVtextenhance(ScrnInfoPtr pScrn, int val)
1108972b676d7Smrg{
1109072b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1109172b676d7Smrg#ifdef SISDUALHEAD
1109272b676d7Smrg   SISEntPtr pSiSEnt = pSiS->entityPrivate;
1109372b676d7Smrg#endif
1109472b676d7Smrg
1109572b676d7Smrg   pSiS->chtvtextenhance = val;
1109672b676d7Smrg#ifdef SISDUALHEAD
1109772b676d7Smrg   if(pSiSEnt) pSiSEnt->chtvtextenhance = val;
1109872b676d7Smrg#endif
1109972b676d7Smrg
1110072b676d7Smrg   if(!(pSiS->VBFlags & CRT2_TV)) return;
1110172b676d7Smrg   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
1110272b676d7Smrg
1110372b676d7Smrg#ifdef UNLOCK_ALWAYS
1110472b676d7Smrg   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
1110572b676d7Smrg#endif
1110672b676d7Smrg
1110772b676d7Smrg   switch(pSiS->ChrontelType) {
1110872b676d7Smrg       case CHRONTEL_700x:
1110972b676d7Smrg           val /= 6;
1111072b676d7Smrg           if((val >= 0) && (val <= 2)) {
1111172b676d7Smrg	      UShort reg = 0;
1111272b676d7Smrg	      reg = SiS_GetCH70xx(pSiS->SiS_Pr, 0x01);
1111372b676d7Smrg	      reg = (reg & 0xf0) | ((reg & 0x03) << 2) | val;
1111472b676d7Smrg              SiS_SetCH70xx(pSiS->SiS_Pr, 0x01, reg);
1111572b676d7Smrg           }
1111672b676d7Smrg	   break;
1111772b676d7Smrg       case CHRONTEL_701x:
1111872b676d7Smrg           val /= 2;
1111972b676d7Smrg	   if((val >= 0) && (val <= 7)) {
1112072b676d7Smrg	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, val, 0xF8);
1112172b676d7Smrg	   }
1112272b676d7Smrg           break;
1112372b676d7Smrg   }
1112472b676d7Smrg}
1112572b676d7Smrg
1112672b676d7Smrgint SiS_GetCHTVtextenhance(ScrnInfoPtr pScrn)
1112772b676d7Smrg{
1112872b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1112972b676d7Smrg#ifdef SISDUALHEAD
1113072b676d7Smrg   SISEntPtr pSiSEnt = pSiS->entityPrivate;
1113172b676d7Smrg#endif
1113272b676d7Smrg
1113372b676d7Smrg   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
1113472b676d7Smrg#ifdef SISDUALHEAD
1113572b676d7Smrg      if(pSiSEnt && pSiS->DualHeadMode)
1113672b676d7Smrg           return (int)pSiSEnt->chtvtextenhance;
1113772b676d7Smrg      else
1113872b676d7Smrg#endif
1113972b676d7Smrg           return (int)pSiS->chtvtextenhance;
1114072b676d7Smrg   } else {
1114172b676d7Smrg#ifdef UNLOCK_ALWAYS
1114272b676d7Smrg      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
1114372b676d7Smrg#endif
1114472b676d7Smrg      switch(pSiS->ChrontelType) {
1114572b676d7Smrg      case CHRONTEL_700x:
1114672b676d7Smrg	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x01) & 0x0c) >> 2) * 6);
1114772b676d7Smrg      case CHRONTEL_701x:
1114872b676d7Smrg	   return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x03) & 0x07) * 2);
1114972b676d7Smrg      default:
1115072b676d7Smrg           return (int)pSiS->chtvtextenhance;
1115172b676d7Smrg      }
1115272b676d7Smrg   }
1115372b676d7Smrg}
1115472b676d7Smrg
1115572b676d7Smrgvoid SiS_SetCHTVcontrast(ScrnInfoPtr pScrn, int val)
1115672b676d7Smrg{
1115772b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1115872b676d7Smrg#ifdef SISDUALHEAD
1115972b676d7Smrg   SISEntPtr pSiSEnt = pSiS->entityPrivate;
1116072b676d7Smrg#endif
1116172b676d7Smrg
1116272b676d7Smrg   pSiS->chtvcontrast = val;
1116372b676d7Smrg#ifdef SISDUALHEAD
1116472b676d7Smrg   if(pSiSEnt) pSiSEnt->chtvcontrast = val;
1116572b676d7Smrg#endif
1116672b676d7Smrg
1116772b676d7Smrg   if(!(pSiS->VBFlags & CRT2_TV)) return;
1116872b676d7Smrg   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
1116972b676d7Smrg
1117072b676d7Smrg#ifdef UNLOCK_ALWAYS
1117172b676d7Smrg   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
1117272b676d7Smrg#endif
1117372b676d7Smrg
1117472b676d7Smrg   val /= 2;
1117572b676d7Smrg   if((val >= 0) && (val <= 7)) {
1117672b676d7Smrg       switch(pSiS->ChrontelType) {
1117772b676d7Smrg       case CHRONTEL_700x:
1117872b676d7Smrg              SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x11, val, 0xF8);
1117972b676d7Smrg	      break;
1118072b676d7Smrg       case CHRONTEL_701x:
1118172b676d7Smrg	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x08, val, 0xF8);
1118272b676d7Smrg              break;
1118372b676d7Smrg       }
1118472b676d7Smrg       SiS_DDC2Delay(pSiS->SiS_Pr, 1000);
1118572b676d7Smrg   }
1118672b676d7Smrg}
1118772b676d7Smrg
1118872b676d7Smrgint SiS_GetCHTVcontrast(ScrnInfoPtr pScrn)
1118972b676d7Smrg{
1119072b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1119172b676d7Smrg#ifdef SISDUALHEAD
1119272b676d7Smrg   SISEntPtr pSiSEnt = pSiS->entityPrivate;
1119372b676d7Smrg#endif
1119472b676d7Smrg
1119572b676d7Smrg   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
1119672b676d7Smrg#ifdef SISDUALHEAD
1119772b676d7Smrg      if(pSiSEnt && pSiS->DualHeadMode)
1119872b676d7Smrg           return (int)pSiSEnt->chtvcontrast;
1119972b676d7Smrg      else
1120072b676d7Smrg#endif
1120172b676d7Smrg           return (int)pSiS->chtvcontrast;
1120272b676d7Smrg   } else {
1120372b676d7Smrg#ifdef UNLOCK_ALWAYS
1120472b676d7Smrg      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
1120572b676d7Smrg#endif
1120672b676d7Smrg      switch(pSiS->ChrontelType) {
1120772b676d7Smrg      case CHRONTEL_700x:
1120872b676d7Smrg           return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x11) & 0x07) * 2);
1120972b676d7Smrg      case CHRONTEL_701x:
1121072b676d7Smrg	   return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x08) & 0x07) * 2);
1121172b676d7Smrg      default:
1121272b676d7Smrg           return (int)pSiS->chtvcontrast;
1121372b676d7Smrg      }
1121472b676d7Smrg   }
1121572b676d7Smrg}
1121672b676d7Smrg
1121772b676d7Smrgvoid SiS_SetSISTVedgeenhance(ScrnInfoPtr pScrn, int val)
1121872b676d7Smrg{
1121972b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1122072b676d7Smrg#ifdef SISDUALHEAD
1122172b676d7Smrg   SISEntPtr pSiSEnt = pSiS->entityPrivate;
1122272b676d7Smrg#endif
1122372b676d7Smrg
1122472b676d7Smrg   pSiS->sistvedgeenhance = val;
1122572b676d7Smrg#ifdef SISDUALHEAD
1122672b676d7Smrg   if(pSiSEnt) pSiSEnt->sistvedgeenhance = val;
1122772b676d7Smrg#endif
1122872b676d7Smrg
1122972b676d7Smrg   if(!(pSiS->VBFlags2 & VB2_301))  return;
1123072b676d7Smrg   if(!(pSiS->VBFlags & CRT2_TV))   return;
1123172b676d7Smrg
1123272b676d7Smrg#ifdef UNLOCK_ALWAYS
1123372b676d7Smrg   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
1123472b676d7Smrg#endif
1123572b676d7Smrg
1123672b676d7Smrg   val /= 2;
1123772b676d7Smrg   if((val >= 0) && (val <= 7)) {
1123872b676d7Smrg      setSISIDXREG(SISPART2,0x3A, 0x1F, (val << 5));
1123972b676d7Smrg   }
1124072b676d7Smrg}
1124172b676d7Smrg
1124272b676d7Smrgint SiS_GetSISTVedgeenhance(ScrnInfoPtr pScrn)
1124372b676d7Smrg{
1124472b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1124572b676d7Smrg   int result = pSiS->sistvedgeenhance;
1124672b676d7Smrg   UChar temp;
1124772b676d7Smrg#ifdef SISDUALHEAD
1124872b676d7Smrg   SISEntPtr pSiSEnt = pSiS->entityPrivate;
1124972b676d7Smrg
1125072b676d7Smrg   if(pSiSEnt && pSiS->DualHeadMode) result = pSiSEnt->sistvedgeenhance;
1125172b676d7Smrg#endif
1125272b676d7Smrg
1125372b676d7Smrg   if(!(pSiS->VBFlags2 & VB2_301))  return result;
1125472b676d7Smrg   if(!(pSiS->VBFlags & CRT2_TV))   return result;
1125572b676d7Smrg
1125672b676d7Smrg#ifdef UNLOCK_ALWAYS
1125772b676d7Smrg   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
1125872b676d7Smrg#endif
1125972b676d7Smrg   inSISIDXREG(SISPART2, 0x3a, temp);
1126072b676d7Smrg   return(int)(((temp & 0xe0) >> 5) * 2);
1126172b676d7Smrg}
1126272b676d7Smrg
1126372b676d7Smrgvoid SiS_SetSISTVantiflicker(ScrnInfoPtr pScrn, int val)
1126472b676d7Smrg{
1126572b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1126672b676d7Smrg#ifdef SISDUALHEAD
1126772b676d7Smrg   SISEntPtr pSiSEnt = pSiS->entityPrivate;
1126872b676d7Smrg#endif
1126972b676d7Smrg
1127072b676d7Smrg   pSiS->sistvantiflicker = val;
1127172b676d7Smrg#ifdef SISDUALHEAD
1127272b676d7Smrg   if(pSiSEnt) pSiSEnt->sistvantiflicker = val;
1127372b676d7Smrg#endif
1127472b676d7Smrg
1127572b676d7Smrg   if(!(pSiS->VBFlags & CRT2_TV))      return;
1127672b676d7Smrg   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE)) return;
1127772b676d7Smrg   if(pSiS->VBFlags & TV_HIVISION)     return;
1127872b676d7Smrg   if((pSiS->VBFlags & TV_YPBPR) &&
1127972b676d7Smrg      (pSiS->VBFlags & (TV_YPBPR525P | TV_YPBPR625P | TV_YPBPR750P | TV_YPBPR1080I))) return;
1128072b676d7Smrg
1128172b676d7Smrg#ifdef UNLOCK_ALWAYS
1128272b676d7Smrg   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
1128372b676d7Smrg#endif
1128472b676d7Smrg
1128572b676d7Smrg   /* Valid values: 0=off, 1=low, 2=med, 3=high, 4=adaptive */
1128672b676d7Smrg   if((val >= 0) && (val <= 4)) {
1128772b676d7Smrg      setSISIDXREG(SISPART2,0x0A,0x8F, (val << 4));
1128872b676d7Smrg   }
1128972b676d7Smrg}
1129072b676d7Smrg
1129172b676d7Smrgint SiS_GetSISTVantiflicker(ScrnInfoPtr pScrn)
1129272b676d7Smrg{
1129372b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1129472b676d7Smrg   int result = pSiS->sistvantiflicker;
1129572b676d7Smrg   UChar temp;
1129672b676d7Smrg#ifdef SISDUALHEAD
1129772b676d7Smrg   SISEntPtr pSiSEnt = pSiS->entityPrivate;
1129872b676d7Smrg
1129972b676d7Smrg   if(pSiSEnt && pSiS->DualHeadMode) result = pSiSEnt->sistvantiflicker;
1130072b676d7Smrg#endif
1130172b676d7Smrg
1130272b676d7Smrg   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE)) return result;
1130372b676d7Smrg   if(!(pSiS->VBFlags & CRT2_TV))        return result;
1130472b676d7Smrg   if(pSiS->VBFlags & TV_HIVISION)       return result;
1130572b676d7Smrg   if((pSiS->VBFlags & TV_YPBPR) &&
1130672b676d7Smrg      (pSiS->VBFlags & (TV_YPBPR525P | TV_YPBPR625P | TV_YPBPR750P | TV_YPBPR1080I))) return result;
1130772b676d7Smrg
1130872b676d7Smrg#ifdef UNLOCK_ALWAYS
1130972b676d7Smrg   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
1131072b676d7Smrg#endif
1131172b676d7Smrg   inSISIDXREG(SISPART2, 0x0a, temp);
1131272b676d7Smrg   return(int)((temp & 0x70) >> 4);
1131372b676d7Smrg}
1131472b676d7Smrg
1131572b676d7Smrgvoid SiS_SetSISTVsaturation(ScrnInfoPtr pScrn, int val)
1131672b676d7Smrg{
1131772b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1131872b676d7Smrg#ifdef SISDUALHEAD
1131972b676d7Smrg   SISEntPtr pSiSEnt = pSiS->entityPrivate;
1132072b676d7Smrg#endif
1132172b676d7Smrg
1132272b676d7Smrg   pSiS->sistvsaturation = val;
1132372b676d7Smrg#ifdef SISDUALHEAD
1132472b676d7Smrg   if(pSiSEnt) pSiSEnt->sistvsaturation = val;
1132572b676d7Smrg#endif
1132672b676d7Smrg
1132772b676d7Smrg   if(!(pSiS->VBFlags & CRT2_TV)) return;
1132872b676d7Smrg   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE)) return;
1132972b676d7Smrg   if(pSiS->VBFlags2 & VB2_301) return;
1133072b676d7Smrg
1133172b676d7Smrg#ifdef UNLOCK_ALWAYS
1133272b676d7Smrg   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
1133372b676d7Smrg#endif
1133472b676d7Smrg
1133572b676d7Smrg   val /= 2;
1133672b676d7Smrg   if((val >= 0) && (val <= 7)) {
1133772b676d7Smrg      setSISIDXREG(SISPART4,0x21,0xF8, val);
1133872b676d7Smrg   }
1133972b676d7Smrg}
1134072b676d7Smrg
1134172b676d7Smrgint SiS_GetSISTVsaturation(ScrnInfoPtr pScrn)
1134272b676d7Smrg{
1134372b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1134472b676d7Smrg   int result = pSiS->sistvsaturation;
1134572b676d7Smrg   UChar temp;
1134672b676d7Smrg#ifdef SISDUALHEAD
1134772b676d7Smrg   SISEntPtr pSiSEnt = pSiS->entityPrivate;
1134872b676d7Smrg
1134972b676d7Smrg   if(pSiSEnt && pSiS->DualHeadMode)  result = pSiSEnt->sistvsaturation;
1135072b676d7Smrg#endif
1135172b676d7Smrg
1135272b676d7Smrg   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE)) return result;
1135372b676d7Smrg   if(pSiS->VBFlags2 & VB2_301)          return result;
1135472b676d7Smrg   if(!(pSiS->VBFlags & CRT2_TV))        return result;
1135572b676d7Smrg
1135672b676d7Smrg#ifdef UNLOCK_ALWAYS
1135772b676d7Smrg   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
1135872b676d7Smrg#endif
1135972b676d7Smrg   inSISIDXREG(SISPART4, 0x21, temp);
1136072b676d7Smrg   return(int)((temp & 0x07) * 2);
1136172b676d7Smrg}
1136272b676d7Smrg
1136372b676d7Smrgvoid SiS_SetSISTVcolcalib(ScrnInfoPtr pScrn, int val, Bool coarse)
1136472b676d7Smrg{
1136572b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1136672b676d7Smrg#ifdef SISDUALHEAD
1136772b676d7Smrg   SISEntPtr pSiSEnt = pSiS->entityPrivate;
1136872b676d7Smrg#endif
1136972b676d7Smrg   int ccoarse, cfine, cbase = pSiS->sistvccbase;
1137072b676d7Smrg   /* UChar temp; */
1137172b676d7Smrg
1137272b676d7Smrg#ifdef SISDUALHEAD
1137372b676d7Smrg   if(pSiSEnt && pSiS->DualHeadMode) cbase = pSiSEnt->sistvccbase;
1137472b676d7Smrg#endif
1137572b676d7Smrg
1137672b676d7Smrg   if(coarse) {
1137772b676d7Smrg      pSiS->sistvcolcalibc = ccoarse = val;
1137872b676d7Smrg      cfine = pSiS->sistvcolcalibf;
1137972b676d7Smrg#ifdef SISDUALHEAD
1138072b676d7Smrg      if(pSiSEnt) {
1138172b676d7Smrg         pSiSEnt->sistvcolcalibc = val;
1138272b676d7Smrg	 if(pSiS->DualHeadMode) cfine = pSiSEnt->sistvcolcalibf;
1138372b676d7Smrg      }
1138472b676d7Smrg#endif
1138572b676d7Smrg   } else {
1138672b676d7Smrg      pSiS->sistvcolcalibf = cfine = val;
1138772b676d7Smrg      ccoarse = pSiS->sistvcolcalibc;
1138872b676d7Smrg#ifdef SISDUALHEAD
1138972b676d7Smrg      if(pSiSEnt) {
1139072b676d7Smrg         pSiSEnt->sistvcolcalibf = val;
1139172b676d7Smrg         if(pSiS->DualHeadMode) ccoarse = pSiSEnt->sistvcolcalibc;
1139272b676d7Smrg      }
1139372b676d7Smrg#endif
1139472b676d7Smrg   }
1139572b676d7Smrg
1139672b676d7Smrg   if(!(pSiS->VBFlags & CRT2_TV))               return;
1139772b676d7Smrg   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE))        return;
1139872b676d7Smrg   if(pSiS->VBFlags & (TV_HIVISION | TV_YPBPR)) return;
1139972b676d7Smrg
1140072b676d7Smrg#ifdef UNLOCK_ALWAYS
1140172b676d7Smrg   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
1140272b676d7Smrg#endif
1140372b676d7Smrg
1140472b676d7Smrg   if((cfine >= -128) && (cfine <= 127) && (ccoarse >= -120) && (ccoarse <= 120)) {
1140572b676d7Smrg      long finalcc = cbase + (((ccoarse * 256) + cfine) * 256);
1140672b676d7Smrg
1140772b676d7Smrg#if 0
1140872b676d7Smrg      inSISIDXREG(SISPART4,0x1f,temp);
1140972b676d7Smrg      if(!(temp & 0x01)) {
1141072b676d7Smrg         if(pSiS->VBFlags & TV_NTSC) finalcc += 0x21ed8620;
1141172b676d7Smrg	 else if(pSiS->VBFlags & TV_PALM) finalcc += ?;
1141272b676d7Smrg	 else if(pSiS->VBFlags & TV_PALM) finalcc += ?;
1141372b676d7Smrg	 else finalcc += 0x2a05d300;
1141472b676d7Smrg      }
1141572b676d7Smrg#endif
1141672b676d7Smrg      setSISIDXREG(SISPART2,0x31,0x80,((finalcc >> 24) & 0x7f));
1141772b676d7Smrg      outSISIDXREG(SISPART2,0x32,((finalcc >> 16) & 0xff));
1141872b676d7Smrg      outSISIDXREG(SISPART2,0x33,((finalcc >> 8) & 0xff));
1141972b676d7Smrg      outSISIDXREG(SISPART2,0x34,(finalcc & 0xff));
1142072b676d7Smrg   }
1142172b676d7Smrg}
1142272b676d7Smrg
1142372b676d7Smrgint SiS_GetSISTVcolcalib(ScrnInfoPtr pScrn, Bool coarse)
1142472b676d7Smrg{
1142572b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1142672b676d7Smrg#ifdef SISDUALHEAD
1142772b676d7Smrg   SISEntPtr pSiSEnt = pSiS->entityPrivate;
1142872b676d7Smrg
1142972b676d7Smrg   if(pSiSEnt && pSiS->DualHeadMode)
1143072b676d7Smrg      if(coarse)  return (int)pSiSEnt->sistvcolcalibc;
1143172b676d7Smrg      else        return (int)pSiSEnt->sistvcolcalibf;
1143272b676d7Smrg   else
1143372b676d7Smrg#endif
1143472b676d7Smrg   if(coarse)     return (int)pSiS->sistvcolcalibc;
1143572b676d7Smrg   else           return (int)pSiS->sistvcolcalibf;
1143672b676d7Smrg}
1143772b676d7Smrg
1143872b676d7Smrgvoid SiS_SetSISTVcfilter(ScrnInfoPtr pScrn, int val)
1143972b676d7Smrg{
1144072b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1144172b676d7Smrg#ifdef SISDUALHEAD
1144272b676d7Smrg   SISEntPtr pSiSEnt = pSiS->entityPrivate;
1144372b676d7Smrg#endif
1144472b676d7Smrg
1144572b676d7Smrg   pSiS->sistvcfilter = val ? 1 : 0;
1144672b676d7Smrg#ifdef SISDUALHEAD
1144772b676d7Smrg   if(pSiSEnt) pSiSEnt->sistvcfilter = pSiS->sistvcfilter;
1144872b676d7Smrg#endif
1144972b676d7Smrg
1145072b676d7Smrg   if(!(pSiS->VBFlags & CRT2_TV))               return;
1145172b676d7Smrg   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE))        return;
1145272b676d7Smrg   if(pSiS->VBFlags & (TV_HIVISION | TV_YPBPR)) return;
1145372b676d7Smrg
1145472b676d7Smrg#ifdef UNLOCK_ALWAYS
1145572b676d7Smrg   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
1145672b676d7Smrg#endif
1145772b676d7Smrg
1145872b676d7Smrg   setSISIDXREG(SISPART2,0x30,~0x10,((pSiS->sistvcfilter << 4) & 0x10));
1145972b676d7Smrg}
1146072b676d7Smrg
1146172b676d7Smrgint SiS_GetSISTVcfilter(ScrnInfoPtr pScrn)
1146272b676d7Smrg{
1146372b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1146472b676d7Smrg   int result = pSiS->sistvcfilter;
1146572b676d7Smrg   UChar temp;
1146672b676d7Smrg#ifdef SISDUALHEAD
1146772b676d7Smrg   SISEntPtr pSiSEnt = pSiS->entityPrivate;
1146872b676d7Smrg
1146972b676d7Smrg   if(pSiSEnt && pSiS->DualHeadMode) result = pSiSEnt->sistvcfilter;
1147072b676d7Smrg#endif
1147172b676d7Smrg
1147272b676d7Smrg   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE))        return result;
1147372b676d7Smrg   if(!(pSiS->VBFlags & CRT2_TV))               return result;
1147472b676d7Smrg   if(pSiS->VBFlags & (TV_HIVISION | TV_YPBPR)) return result;
1147572b676d7Smrg
1147672b676d7Smrg#ifdef UNLOCK_ALWAYS
1147772b676d7Smrg   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
1147872b676d7Smrg#endif
1147972b676d7Smrg   inSISIDXREG(SISPART2, 0x30, temp);
1148072b676d7Smrg   return (int)((temp & 0x10) ? 1 : 0);
1148172b676d7Smrg}
1148272b676d7Smrg
1148372b676d7Smrgvoid SiS_SetSISTVyfilter(ScrnInfoPtr pScrn, int val)
1148472b676d7Smrg{
1148572b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1148672b676d7Smrg#ifdef SISDUALHEAD
1148772b676d7Smrg   SISEntPtr pSiSEnt = pSiS->entityPrivate;
1148872b676d7Smrg#endif
1148972b676d7Smrg   UChar p35,p36,p37,p38,p48,p49,p4a,p30;
1149072b676d7Smrg   int i,j;
1149172b676d7Smrg
1149272b676d7Smrg   pSiS->sistvyfilter = val;
1149372b676d7Smrg#ifdef SISDUALHEAD
1149472b676d7Smrg   if(pSiSEnt) pSiSEnt->sistvyfilter = pSiS->sistvyfilter;
1149572b676d7Smrg#endif
1149672b676d7Smrg
1149772b676d7Smrg   if(!(pSiS->VBFlags & CRT2_TV))               return;
1149872b676d7Smrg   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE))        return;
1149972b676d7Smrg   if(pSiS->VBFlags & (TV_HIVISION | TV_YPBPR)) return;
1150072b676d7Smrg
1150172b676d7Smrg   p35 = pSiS->p2_35; p36 = pSiS->p2_36;
1150272b676d7Smrg   p37 = pSiS->p2_37; p38 = pSiS->p2_38;
1150372b676d7Smrg   p48 = pSiS->p2_48; p49 = pSiS->p2_49;
1150472b676d7Smrg   p4a = pSiS->p2_4a; p30 = pSiS->p2_30;
1150572b676d7Smrg#ifdef SISDUALHEAD
1150672b676d7Smrg   if(pSiSEnt && pSiS->DualHeadMode) {
1150772b676d7Smrg      p35 = pSiSEnt->p2_35; p36 = pSiSEnt->p2_36;
1150872b676d7Smrg      p37 = pSiSEnt->p2_37; p38 = pSiSEnt->p2_38;
1150972b676d7Smrg      p48 = pSiSEnt->p2_48; p49 = pSiSEnt->p2_49;
1151072b676d7Smrg      p4a = pSiSEnt->p2_4a; p30 = pSiSEnt->p2_30;
1151172b676d7Smrg   }
1151272b676d7Smrg#endif
1151372b676d7Smrg   p30 &= 0x20;
1151472b676d7Smrg
1151572b676d7Smrg#ifdef UNLOCK_ALWAYS
1151672b676d7Smrg   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
1151772b676d7Smrg#endif
1151872b676d7Smrg
1151972b676d7Smrg   switch(pSiS->sistvyfilter) {
1152072b676d7Smrg   case 0:
1152172b676d7Smrg      andSISIDXREG(SISPART2,0x30,0xdf);
1152272b676d7Smrg      break;
1152372b676d7Smrg   case 1:
1152472b676d7Smrg      outSISIDXREG(SISPART2,0x35,p35);
1152572b676d7Smrg      outSISIDXREG(SISPART2,0x36,p36);
1152672b676d7Smrg      outSISIDXREG(SISPART2,0x37,p37);
1152772b676d7Smrg      outSISIDXREG(SISPART2,0x38,p38);
1152872b676d7Smrg      if(!(pSiS->VBFlags2 & VB2_301)) {
1152972b676d7Smrg         outSISIDXREG(SISPART2,0x48,p48);
1153072b676d7Smrg         outSISIDXREG(SISPART2,0x49,p49);
1153172b676d7Smrg         outSISIDXREG(SISPART2,0x4a,p4a);
1153272b676d7Smrg      }
1153372b676d7Smrg      setSISIDXREG(SISPART2,0x30,0xdf,p30);
1153472b676d7Smrg      break;
1153572b676d7Smrg   case 2:
1153672b676d7Smrg   case 3:
1153772b676d7Smrg   case 4:
1153872b676d7Smrg   case 5:
1153972b676d7Smrg   case 6:
1154072b676d7Smrg   case 7:
1154172b676d7Smrg   case 8:
1154272b676d7Smrg      if(!(pSiS->VBFlags & (TV_PALM | TV_PALN | TV_NTSCJ))) {
1154372b676d7Smrg         int yindex301 = -1, yindex301B = -1;
1154472b676d7Smrg	 UChar p3d4_34;
1154572b676d7Smrg
1154672b676d7Smrg	 inSISIDXREG(SISCR,0x34,p3d4_34);
1154772b676d7Smrg
1154872b676d7Smrg	 switch((p3d4_34 & 0x7f)) {
1154972b676d7Smrg	 case 0x59:  /* 320x200 */
1155072b676d7Smrg	 case 0x41:
1155172b676d7Smrg	 case 0x4f:
1155272b676d7Smrg	 case 0x50:  /* 320x240 */
1155372b676d7Smrg	 case 0x56:
1155472b676d7Smrg	 case 0x53:
1155572b676d7Smrg	    yindex301  = (pSiS->VBFlags & TV_NTSC) ? 0 : 4;
1155672b676d7Smrg	    break;
1155772b676d7Smrg	 case 0x2f:  /* 640x400 */
1155872b676d7Smrg	 case 0x5d:
1155972b676d7Smrg	 case 0x5e:
1156072b676d7Smrg	 case 0x2e:  /* 640x480 */
1156172b676d7Smrg	 case 0x44:
1156272b676d7Smrg	 case 0x62:
1156372b676d7Smrg	    yindex301  = (pSiS->VBFlags & TV_NTSC) ? 1 : 5;
1156472b676d7Smrg	    yindex301B = (pSiS->VBFlags & TV_NTSC) ? 0 : 4;
1156572b676d7Smrg	    break;
1156672b676d7Smrg	 case 0x31:   /* 720x480 */
1156772b676d7Smrg	 case 0x33:
1156872b676d7Smrg	 case 0x35:
1156972b676d7Smrg	 case 0x32:   /* 720x576 */
1157072b676d7Smrg	 case 0x34:
1157172b676d7Smrg	 case 0x36:
1157272b676d7Smrg	 case 0x5f:   /* 768x576 */
1157372b676d7Smrg	 case 0x60:
1157472b676d7Smrg	 case 0x61:
1157572b676d7Smrg	    yindex301  = (pSiS->VBFlags & TV_NTSC) ? 2 : 6;
1157672b676d7Smrg	    yindex301B = (pSiS->VBFlags & TV_NTSC) ? 1 : 5;
1157772b676d7Smrg	    break;
1157872b676d7Smrg	 case 0x51:   /* 400x300 */
1157972b676d7Smrg	 case 0x57:
1158072b676d7Smrg	 case 0x54:
1158172b676d7Smrg	 case 0x30:   /* 800x600 */
1158272b676d7Smrg	 case 0x47:
1158372b676d7Smrg	 case 0x63:
1158472b676d7Smrg	    yindex301  = (pSiS->VBFlags & TV_NTSC) ? 3 : 7;
1158572b676d7Smrg	    yindex301B = (pSiS->VBFlags & TV_NTSC) ? 2 : 6;
1158672b676d7Smrg	    break;
1158772b676d7Smrg	 case 0x52:   /* 512x384 */
1158872b676d7Smrg	 case 0x58:
1158972b676d7Smrg	 case 0x5c:
1159072b676d7Smrg	 case 0x38:   /* 1024x768 */
1159172b676d7Smrg	 case 0x4a:
1159272b676d7Smrg	 case 0x64:
1159372b676d7Smrg	    yindex301B = (pSiS->VBFlags & TV_NTSC) ? 3 : 7;
1159472b676d7Smrg	    break;
1159572b676d7Smrg	 }
1159672b676d7Smrg         if(pSiS->VBFlags2 & VB2_301) {
1159772b676d7Smrg            if(yindex301 >= 0) {
1159872b676d7Smrg	       for(i=0, j=0x35; i<=3; i++, j++) {
1159972b676d7Smrg	          outSISIDXREG(SISPART2,j,(SiSTVFilter301[yindex301].filter[pSiS->sistvyfilter-2][i]));
1160072b676d7Smrg	       }
1160172b676d7Smrg	    }
1160272b676d7Smrg         } else {
1160372b676d7Smrg            if(yindex301B >= 0) {
1160472b676d7Smrg	       for(i=0, j=0x35; i<=3; i++, j++) {
1160572b676d7Smrg	          outSISIDXREG(SISPART2,j,(SiSTVFilter301B[yindex301B].filter[pSiS->sistvyfilter-2][i]));
1160672b676d7Smrg	       }
1160772b676d7Smrg	       for(i=4, j=0x48; i<=6; i++, j++) {
1160872b676d7Smrg	          outSISIDXREG(SISPART2,j,(SiSTVFilter301B[yindex301B].filter[pSiS->sistvyfilter-2][i]));
1160972b676d7Smrg	       }
1161072b676d7Smrg	    }
1161172b676d7Smrg         }
1161272b676d7Smrg         orSISIDXREG(SISPART2,0x30,0x20);
1161372b676d7Smrg      }
1161472b676d7Smrg   }
1161572b676d7Smrg}
1161672b676d7Smrg
1161772b676d7Smrgint SiS_GetSISTVyfilter(ScrnInfoPtr pScrn)
1161872b676d7Smrg{
1161972b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1162072b676d7Smrg#ifdef SISDUALHEAD
1162172b676d7Smrg   SISEntPtr pSiSEnt = pSiS->entityPrivate;
1162272b676d7Smrg
1162372b676d7Smrg   if(pSiSEnt && pSiS->DualHeadMode)
1162472b676d7Smrg      return (int)pSiSEnt->sistvyfilter;
1162572b676d7Smrg   else
1162672b676d7Smrg#endif
1162772b676d7Smrg      return (int)pSiS->sistvyfilter;
1162872b676d7Smrg}
1162972b676d7Smrg
1163072b676d7Smrgvoid SiS_SetSIS6326TVantiflicker(ScrnInfoPtr pScrn, int val)
1163172b676d7Smrg{
1163272b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1163372b676d7Smrg   UChar tmp;
1163472b676d7Smrg
1163572b676d7Smrg   pSiS->sistvantiflicker = val;
1163672b676d7Smrg
1163772b676d7Smrg   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) return;
1163872b676d7Smrg
1163972b676d7Smrg#ifdef UNLOCK_ALWAYS
1164072b676d7Smrg   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
1164172b676d7Smrg#endif
1164272b676d7Smrg
1164372b676d7Smrg   tmp = SiS6326GetTVReg(pScrn,0x00);
1164472b676d7Smrg   if(!(tmp & 0x04)) return;
1164572b676d7Smrg
1164672b676d7Smrg   /* Valid values: 0=off, 1=low, 2=med, 3=high, 4=adaptive */
1164772b676d7Smrg   if(val >= 0 && val <= 4) {
1164872b676d7Smrg      tmp &= 0x1f;
1164972b676d7Smrg      tmp |= (val << 5);
1165072b676d7Smrg      SiS6326SetTVReg(pScrn,0x00,tmp);
1165172b676d7Smrg   }
1165272b676d7Smrg}
1165372b676d7Smrg
1165472b676d7Smrgint SiS_GetSIS6326TVantiflicker(ScrnInfoPtr pScrn)
1165572b676d7Smrg{
1165672b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1165772b676d7Smrg   UChar tmp;
1165872b676d7Smrg
1165972b676d7Smrg   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) {
1166072b676d7Smrg      return (int)pSiS->sistvantiflicker;
1166172b676d7Smrg   }
1166272b676d7Smrg
1166372b676d7Smrg#ifdef UNLOCK_ALWAYS
1166472b676d7Smrg   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
1166572b676d7Smrg#endif
1166672b676d7Smrg
1166772b676d7Smrg   tmp = SiS6326GetTVReg(pScrn,0x00);
1166872b676d7Smrg   if(!(tmp & 0x04)) {
1166972b676d7Smrg      return (int)pSiS->sistvantiflicker;
1167072b676d7Smrg   } else {
1167172b676d7Smrg      return (int)((tmp >> 5) & 0x07);
1167272b676d7Smrg   }
1167372b676d7Smrg}
1167472b676d7Smrg
1167572b676d7Smrgvoid SiS_SetSIS6326TVenableyfilter(ScrnInfoPtr pScrn, int val)
1167672b676d7Smrg{
1167772b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1167872b676d7Smrg   UChar tmp;
1167972b676d7Smrg
1168072b676d7Smrg   if(val) val = 1;
1168172b676d7Smrg   pSiS->sis6326enableyfilter = val;
1168272b676d7Smrg
1168372b676d7Smrg   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) return;
1168472b676d7Smrg
1168572b676d7Smrg#ifdef UNLOCK_ALWAYS
1168672b676d7Smrg   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
1168772b676d7Smrg#endif
1168872b676d7Smrg
1168972b676d7Smrg   tmp = SiS6326GetTVReg(pScrn,0x00);
1169072b676d7Smrg   if(!(tmp & 0x04)) return;
1169172b676d7Smrg
1169272b676d7Smrg   tmp = SiS6326GetTVReg(pScrn,0x43);
1169372b676d7Smrg   tmp &= ~0x10;
1169472b676d7Smrg   tmp |= ((val & 0x01) << 4);
1169572b676d7Smrg   SiS6326SetTVReg(pScrn,0x43,tmp);
1169672b676d7Smrg}
1169772b676d7Smrg
1169872b676d7Smrgint SiS_GetSIS6326TVenableyfilter(ScrnInfoPtr pScrn)
1169972b676d7Smrg{
1170072b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1170172b676d7Smrg   UChar tmp;
1170272b676d7Smrg
1170372b676d7Smrg   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) {
1170472b676d7Smrg      return (int)pSiS->sis6326enableyfilter;
1170572b676d7Smrg   }
1170672b676d7Smrg
1170772b676d7Smrg#ifdef UNLOCK_ALWAYS
1170872b676d7Smrg   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
1170972b676d7Smrg#endif
1171072b676d7Smrg
1171172b676d7Smrg   tmp = SiS6326GetTVReg(pScrn,0x00);
1171272b676d7Smrg   if(!(tmp & 0x04)) {
1171372b676d7Smrg      return (int)pSiS->sis6326enableyfilter;
1171472b676d7Smrg   } else {
1171572b676d7Smrg      tmp = SiS6326GetTVReg(pScrn,0x43);
1171672b676d7Smrg      return (int)((tmp >> 4) & 0x01);
1171772b676d7Smrg   }
1171872b676d7Smrg}
1171972b676d7Smrg
1172072b676d7Smrgvoid SiS_SetSIS6326TVyfilterstrong(ScrnInfoPtr pScrn, int val)
1172172b676d7Smrg{
1172272b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1172372b676d7Smrg   UChar tmp;
1172472b676d7Smrg
1172572b676d7Smrg   if(val) val = 1;
1172672b676d7Smrg   pSiS->sis6326yfilterstrong = val;
1172772b676d7Smrg
1172872b676d7Smrg   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) return;
1172972b676d7Smrg
1173072b676d7Smrg#ifdef UNLOCK_ALWAYS
1173172b676d7Smrg   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
1173272b676d7Smrg#endif
1173372b676d7Smrg
1173472b676d7Smrg   tmp = SiS6326GetTVReg(pScrn,0x00);
1173572b676d7Smrg   if(!(tmp & 0x04)) return;
1173672b676d7Smrg
1173772b676d7Smrg   tmp = SiS6326GetTVReg(pScrn,0x43);
1173872b676d7Smrg   if(tmp & 0x10) {
1173972b676d7Smrg      tmp &= ~0x40;
1174072b676d7Smrg      tmp |= ((val & 0x01) << 6);
1174172b676d7Smrg      SiS6326SetTVReg(pScrn,0x43,tmp);
1174272b676d7Smrg   }
1174372b676d7Smrg}
1174472b676d7Smrg
1174572b676d7Smrgint SiS_GetSIS6326TVyfilterstrong(ScrnInfoPtr pScrn)
1174672b676d7Smrg{
1174772b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1174872b676d7Smrg   UChar tmp;
1174972b676d7Smrg
1175072b676d7Smrg   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) {
1175172b676d7Smrg      return (int)pSiS->sis6326yfilterstrong;
1175272b676d7Smrg   }
1175372b676d7Smrg
1175472b676d7Smrg#ifdef UNLOCK_ALWAYS
1175572b676d7Smrg   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
1175672b676d7Smrg#endif
1175772b676d7Smrg
1175872b676d7Smrg   tmp = SiS6326GetTVReg(pScrn,0x00);
1175972b676d7Smrg   if(!(tmp & 0x04)) {
1176072b676d7Smrg      return (int)pSiS->sis6326yfilterstrong;
1176172b676d7Smrg   } else {
1176272b676d7Smrg      tmp = SiS6326GetTVReg(pScrn,0x43);
1176372b676d7Smrg      if(!(tmp & 0x10)) {
1176472b676d7Smrg         return (int)pSiS->sis6326yfilterstrong;
1176572b676d7Smrg      } else {
1176672b676d7Smrg         return (int)((tmp >> 6) & 0x01);
1176772b676d7Smrg      }
1176872b676d7Smrg   }
1176972b676d7Smrg}
1177072b676d7Smrg
1177172b676d7Smrgvoid SiS_SetTVxposoffset(ScrnInfoPtr pScrn, int val)
1177272b676d7Smrg{
1177372b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1177472b676d7Smrg#ifdef SISDUALHEAD
1177572b676d7Smrg   SISEntPtr pSiSEnt = pSiS->entityPrivate;
1177672b676d7Smrg#endif
1177772b676d7Smrg
1177872b676d7Smrg#ifdef UNLOCK_ALWAYS
1177972b676d7Smrg   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
1178072b676d7Smrg#endif
1178172b676d7Smrg
1178272b676d7Smrg   pSiS->tvxpos = val;
1178372b676d7Smrg#ifdef SISDUALHEAD
1178472b676d7Smrg   if(pSiSEnt) pSiSEnt->tvxpos = val;
1178572b676d7Smrg#endif
1178672b676d7Smrg
1178772b676d7Smrg   if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
1178872b676d7Smrg
1178972b676d7Smrg      if(pSiS->VBFlags & CRT2_TV) {
1179072b676d7Smrg
1179172b676d7Smrg         if(pSiS->VBFlags2 & VB2_CHRONTEL) {
1179272b676d7Smrg
1179372b676d7Smrg	    int x = pSiS->tvx;
1179472b676d7Smrg#ifdef SISDUALHEAD
1179572b676d7Smrg	    if(pSiSEnt && pSiS->DualHeadMode) x = pSiSEnt->tvx;
1179672b676d7Smrg#endif
1179772b676d7Smrg	    switch(pSiS->ChrontelType) {
1179872b676d7Smrg	    case CHRONTEL_700x:
1179972b676d7Smrg	       if((val >= -32) && (val <= 32)) {
1180072b676d7Smrg		   x += val;
1180172b676d7Smrg		   if(x < 0) x = 0;
1180272b676d7Smrg		   SiS_SetCH700x(pSiS->SiS_Pr, 0x0a, (x & 0xff));
1180372b676d7Smrg		   SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x08, ((x & 0x0100) >> 7), 0xFD);
1180472b676d7Smrg	       }
1180572b676d7Smrg	       break;
1180672b676d7Smrg	    case CHRONTEL_701x:
1180772b676d7Smrg	       /* Not supported by hardware */
1180872b676d7Smrg	       break;
1180972b676d7Smrg	    }
1181072b676d7Smrg
1181172b676d7Smrg	 } else if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
1181272b676d7Smrg
1181372b676d7Smrg	    if((val >= -32) && (val <= 32)) {
1181472b676d7Smrg
1181572b676d7Smrg	        UChar p2_1f,p2_20,p2_2b,p2_42,p2_43;
1181672b676d7Smrg		UShort temp;
1181772b676d7Smrg		int mult;
1181872b676d7Smrg
1181972b676d7Smrg		p2_1f = pSiS->p2_1f;
1182072b676d7Smrg		p2_20 = pSiS->p2_20;
1182172b676d7Smrg		p2_2b = pSiS->p2_2b;
1182272b676d7Smrg		p2_42 = pSiS->p2_42;
1182372b676d7Smrg		p2_43 = pSiS->p2_43;
1182472b676d7Smrg#ifdef SISDUALHEAD
1182572b676d7Smrg	        if(pSiSEnt && pSiS->DualHeadMode) {
1182672b676d7Smrg		   p2_1f = pSiSEnt->p2_1f;
1182772b676d7Smrg		   p2_20 = pSiSEnt->p2_20;
1182872b676d7Smrg		   p2_2b = pSiSEnt->p2_2b;
1182972b676d7Smrg		   p2_42 = pSiSEnt->p2_42;
1183072b676d7Smrg		   p2_43 = pSiSEnt->p2_43;
1183172b676d7Smrg		}
1183272b676d7Smrg#endif
1183372b676d7Smrg		mult = 2;
1183472b676d7Smrg		if(pSiS->VBFlags & TV_YPBPR) {
1183572b676d7Smrg		   if(pSiS->VBFlags & (TV_YPBPR1080I | TV_YPBPR750P)) {
1183672b676d7Smrg		      mult = 4;
1183772b676d7Smrg		   }
1183872b676d7Smrg		}
1183972b676d7Smrg
1184072b676d7Smrg		temp = p2_1f | ((p2_20 & 0xf0) << 4);
1184172b676d7Smrg		temp += (val * mult);
1184272b676d7Smrg		p2_1f = temp & 0xff;
1184372b676d7Smrg		p2_20 = (temp & 0xf00) >> 4;
1184472b676d7Smrg		p2_2b = ((p2_2b & 0x0f) + (val * mult)) & 0x0f;
1184572b676d7Smrg		temp = p2_43 | ((p2_42 & 0xf0) << 4);
1184672b676d7Smrg		temp += (val * mult);
1184772b676d7Smrg		p2_43 = temp & 0xff;
1184872b676d7Smrg		p2_42 = (temp & 0xf00) >> 4;
1184972b676d7Smrg		SISWaitRetraceCRT2(pScrn);
1185072b676d7Smrg	        outSISIDXREG(SISPART2,0x1f,p2_1f);
1185172b676d7Smrg		setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
1185272b676d7Smrg		setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
1185372b676d7Smrg		setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
1185472b676d7Smrg		outSISIDXREG(SISPART2,0x43,p2_43);
1185572b676d7Smrg	     }
1185672b676d7Smrg	 }
1185772b676d7Smrg      }
1185872b676d7Smrg
1185972b676d7Smrg   } else if(pSiS->Chipset == PCI_CHIP_SIS6326) {
1186072b676d7Smrg
1186172b676d7Smrg      if(pSiS->SiS6326Flags & SIS6326_TVDETECTED) {
1186272b676d7Smrg
1186372b676d7Smrg         UChar tmp;
1186472b676d7Smrg	 UShort temp1, temp2, temp3;
1186572b676d7Smrg
1186672b676d7Smrg         tmp = SiS6326GetTVReg(pScrn,0x00);
1186772b676d7Smrg         if(tmp & 0x04) {
1186872b676d7Smrg
1186972b676d7Smrg	    temp1 = pSiS->tvx1;
1187072b676d7Smrg            temp2 = pSiS->tvx2;
1187172b676d7Smrg            temp3 = pSiS->tvx3;
1187272b676d7Smrg            if((val >= -16) && (val <= 16)) {
1187372b676d7Smrg	       if(val > 0) {
1187472b676d7Smrg	          temp1 += (val * 4);
1187572b676d7Smrg	          temp2 += (val * 4);
1187672b676d7Smrg	          while((temp1 > 0x0fff) || (temp2 > 0x0fff)) {
1187772b676d7Smrg	             temp1 -= 4;
1187872b676d7Smrg		     temp2 -= 4;
1187972b676d7Smrg	          }
1188072b676d7Smrg	       } else {
1188172b676d7Smrg	          val = -val;
1188272b676d7Smrg	          temp3 += (val * 4);
1188372b676d7Smrg	          while(temp3 > 0x03ff) {
1188472b676d7Smrg	     	     temp3 -= 4;
1188572b676d7Smrg	          }
1188672b676d7Smrg	       }
1188772b676d7Smrg            }
1188872b676d7Smrg            SiS6326SetTVReg(pScrn,0x3a,(temp1 & 0xff));
1188972b676d7Smrg            tmp = SiS6326GetTVReg(pScrn,0x3c);
1189072b676d7Smrg            tmp &= 0xf0;
1189172b676d7Smrg            tmp |= ((temp1 & 0x0f00) >> 8);
1189272b676d7Smrg            SiS6326SetTVReg(pScrn,0x3c,tmp);
1189372b676d7Smrg            SiS6326SetTVReg(pScrn,0x26,(temp2 & 0xff));
1189472b676d7Smrg            tmp = SiS6326GetTVReg(pScrn,0x27);
1189572b676d7Smrg            tmp &= 0x0f;
1189672b676d7Smrg            tmp |= ((temp2 & 0x0f00) >> 4);
1189772b676d7Smrg            SiS6326SetTVReg(pScrn,0x27,tmp);
1189872b676d7Smrg            SiS6326SetTVReg(pScrn,0x12,(temp3 & 0xff));
1189972b676d7Smrg            tmp = SiS6326GetTVReg(pScrn,0x13);
1190072b676d7Smrg            tmp &= ~0xC0;
1190172b676d7Smrg            tmp |= ((temp3 & 0x0300) >> 2);
1190272b676d7Smrg            SiS6326SetTVReg(pScrn,0x13,tmp);
1190372b676d7Smrg	 }
1190472b676d7Smrg      }
1190572b676d7Smrg   }
1190672b676d7Smrg}
1190772b676d7Smrg
1190872b676d7Smrgint SiS_GetTVxposoffset(ScrnInfoPtr pScrn)
1190972b676d7Smrg{
1191072b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1191172b676d7Smrg#ifdef SISDUALHEAD
1191272b676d7Smrg   SISEntPtr pSiSEnt = pSiS->entityPrivate;
1191372b676d7Smrg
1191472b676d7Smrg   if(pSiSEnt && pSiS->DualHeadMode)
1191572b676d7Smrg        return (int)pSiSEnt->tvxpos;
1191672b676d7Smrg   else
1191772b676d7Smrg#endif
1191872b676d7Smrg        return (int)pSiS->tvxpos;
1191972b676d7Smrg}
1192072b676d7Smrg
1192172b676d7Smrgvoid SiS_SetTVyposoffset(ScrnInfoPtr pScrn, int val)
1192272b676d7Smrg{
1192372b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1192472b676d7Smrg#ifdef SISDUALHEAD
1192572b676d7Smrg   SISEntPtr pSiSEnt = pSiS->entityPrivate;
1192672b676d7Smrg#endif
1192772b676d7Smrg
1192872b676d7Smrg#ifdef UNLOCK_ALWAYS
1192972b676d7Smrg   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
1193072b676d7Smrg#endif
1193172b676d7Smrg
1193272b676d7Smrg   pSiS->tvypos = val;
1193372b676d7Smrg#ifdef SISDUALHEAD
1193472b676d7Smrg   if(pSiSEnt) pSiSEnt->tvypos = val;
1193572b676d7Smrg#endif
1193672b676d7Smrg
1193772b676d7Smrg   if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
1193872b676d7Smrg
1193972b676d7Smrg      if(pSiS->VBFlags & CRT2_TV) {
1194072b676d7Smrg
1194172b676d7Smrg         if(pSiS->VBFlags2 & VB2_CHRONTEL) {
1194272b676d7Smrg
1194372b676d7Smrg	    int y = pSiS->tvy;
1194472b676d7Smrg#ifdef SISDUALHEAD
1194572b676d7Smrg	    if(pSiSEnt && pSiS->DualHeadMode) y = pSiSEnt->tvy;
1194672b676d7Smrg#endif
1194772b676d7Smrg	    switch(pSiS->ChrontelType) {
1194872b676d7Smrg	    case CHRONTEL_700x:
1194972b676d7Smrg	       if((val >= -32) && (val <= 32)) {
1195072b676d7Smrg		   y -= val;
1195172b676d7Smrg		   if(y < 0) y = 0;
1195272b676d7Smrg		   SiS_SetCH700x(pSiS->SiS_Pr, 0x0b, (y & 0xff));
1195372b676d7Smrg		   SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x08, ((y & 0x0100) >> 8), 0xFE);
1195472b676d7Smrg	       }
1195572b676d7Smrg	       break;
1195672b676d7Smrg	    case CHRONTEL_701x:
1195772b676d7Smrg	       /* Not supported by hardware */
1195872b676d7Smrg	       break;
1195972b676d7Smrg	    }
1196072b676d7Smrg
1196172b676d7Smrg	 } else if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
1196272b676d7Smrg
1196372b676d7Smrg	    if((val >= -32) && (val <= 32)) {
1196472b676d7Smrg		char p2_01, p2_02;
1196572b676d7Smrg
1196672b676d7Smrg		if( (pSiS->VBFlags & TV_HIVISION) ||
1196772b676d7Smrg		    ((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & (TV_YPBPR1080I|TV_YPBPR750P))) ) {
1196872b676d7Smrg		   val *= 2;
1196972b676d7Smrg		} else {
1197072b676d7Smrg		   val /= 2;  /* 4 */
1197172b676d7Smrg		}
1197272b676d7Smrg
1197372b676d7Smrg		p2_01 = pSiS->p2_01;
1197472b676d7Smrg		p2_02 = pSiS->p2_02;
1197572b676d7Smrg#ifdef SISDUALHEAD
1197672b676d7Smrg	        if(pSiSEnt && pSiS->DualHeadMode) {
1197772b676d7Smrg		   p2_01 = pSiSEnt->p2_01;
1197872b676d7Smrg		   p2_02 = pSiSEnt->p2_02;
1197972b676d7Smrg		}
1198072b676d7Smrg#endif
1198172b676d7Smrg		p2_01 += val; /* val * 2 */
1198272b676d7Smrg		p2_02 += val; /* val * 2 */
1198372b676d7Smrg		if(!(pSiS->VBFlags & (TV_YPBPR | TV_HIVISION))) {
1198472b676d7Smrg		   while((p2_01 <= 0) || (p2_02 <= 0)) {
1198572b676d7Smrg		      p2_01 += 2;
1198672b676d7Smrg		      p2_02 += 2;
1198772b676d7Smrg		   }
1198872b676d7Smrg		} else if((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR1080I)) {
1198972b676d7Smrg		   while(p2_01 <= 8) {
1199072b676d7Smrg		      p2_01 += 2;
1199172b676d7Smrg		      p2_02 += 2;
1199272b676d7Smrg		   }
1199372b676d7Smrg		} else if((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR750P)) {
1199472b676d7Smrg		   while(p2_01 <= 10) {
1199572b676d7Smrg		      p2_01 += 2;
1199672b676d7Smrg		      p2_02 += 2;
1199772b676d7Smrg		   }
1199872b676d7Smrg		}
1199972b676d7Smrg
1200072b676d7Smrg		SISWaitRetraceCRT2(pScrn);
1200172b676d7Smrg		outSISIDXREG(SISPART2,0x01,p2_01);
1200272b676d7Smrg		outSISIDXREG(SISPART2,0x02,p2_02);
1200372b676d7Smrg	     }
1200472b676d7Smrg	 }
1200572b676d7Smrg
1200672b676d7Smrg      }
1200772b676d7Smrg
1200872b676d7Smrg   } else if(pSiS->Chipset == PCI_CHIP_SIS6326) {
1200972b676d7Smrg
1201072b676d7Smrg      if(pSiS->SiS6326Flags & SIS6326_TVDETECTED) {
1201172b676d7Smrg
1201272b676d7Smrg         UChar tmp;
1201372b676d7Smrg	 int temp1, limit;
1201472b676d7Smrg
1201572b676d7Smrg         tmp = SiS6326GetTVReg(pScrn,0x00);
1201672b676d7Smrg         if(tmp & 0x04) {
1201772b676d7Smrg
1201872b676d7Smrg	    if((val >= -16) && (val <= 16)) {
1201972b676d7Smrg	      temp1 = (UShort)pSiS->tvy1;
1202072b676d7Smrg	      limit = (pSiS->SiS6326Flags & SIS6326_TVPAL) ? 625 : 525;
1202172b676d7Smrg	      if(val > 0) {
1202272b676d7Smrg                temp1 += (val * 4);
1202372b676d7Smrg	        if(temp1 > limit) temp1 -= limit;
1202472b676d7Smrg	      } else {
1202572b676d7Smrg	        val = -val;
1202672b676d7Smrg	        temp1 -= (val * 2);
1202772b676d7Smrg	        if(temp1 <= 0) temp1 += (limit -1);
1202872b676d7Smrg	      }
1202972b676d7Smrg	      SiS6326SetTVReg(pScrn,0x11,(temp1 & 0xff));
1203072b676d7Smrg	      tmp = SiS6326GetTVReg(pScrn,0x13);
1203172b676d7Smrg	      tmp &= ~0x30;
1203272b676d7Smrg	      tmp |= ((temp1 & 0x300) >> 4);
1203372b676d7Smrg	      SiS6326SetTVReg(pScrn,0x13,tmp);
1203472b676d7Smrg	      if(temp1 == 1)                                 tmp = 0x10;
1203572b676d7Smrg	      else {
1203672b676d7Smrg	       if(pSiS->SiS6326Flags & SIS6326_TVPAL) {
1203772b676d7Smrg	         if((temp1 <= 3) || (temp1 >= (limit - 2)))  tmp = 0x08;
1203872b676d7Smrg	         else if(temp1 < 22)		 	     tmp = 0x02;
1203972b676d7Smrg	         else 					     tmp = 0x04;
1204072b676d7Smrg	       } else {
1204172b676d7Smrg	         if((temp1 <= 5) || (temp1 >= (limit - 4)))  tmp = 0x08;
1204272b676d7Smrg	         else if(temp1 < 19)			     tmp = 0x02;
1204372b676d7Smrg	         else 					     tmp = 0x04;
1204472b676d7Smrg	       }
1204572b676d7Smrg	     }
1204672b676d7Smrg	     SiS6326SetTVReg(pScrn,0x21,tmp);
1204772b676d7Smrg           }
1204872b676d7Smrg	 }
1204972b676d7Smrg      }
1205072b676d7Smrg   }
1205172b676d7Smrg}
1205272b676d7Smrg
1205372b676d7Smrgint SiS_GetTVyposoffset(ScrnInfoPtr pScrn)
1205472b676d7Smrg{
1205572b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1205672b676d7Smrg#ifdef SISDUALHEAD
1205772b676d7Smrg   SISEntPtr pSiSEnt = pSiS->entityPrivate;
1205872b676d7Smrg
1205972b676d7Smrg   if(pSiSEnt && pSiS->DualHeadMode)
1206072b676d7Smrg        return (int)pSiSEnt->tvypos;
1206172b676d7Smrg   else
1206272b676d7Smrg#endif
1206372b676d7Smrg        return (int)pSiS->tvypos;
1206472b676d7Smrg}
1206572b676d7Smrg
1206672b676d7Smrgvoid SiS_SetTVxscale(ScrnInfoPtr pScrn, int val)
1206772b676d7Smrg{
1206872b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1206972b676d7Smrg#ifdef SISDUALHEAD
1207072b676d7Smrg   SISEntPtr pSiSEnt = pSiS->entityPrivate;
1207172b676d7Smrg#endif
1207272b676d7Smrg
1207372b676d7Smrg#ifdef UNLOCK_ALWAYS
1207472b676d7Smrg   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
1207572b676d7Smrg#endif
1207672b676d7Smrg
1207772b676d7Smrg   pSiS->tvxscale = val;
1207872b676d7Smrg#ifdef SISDUALHEAD
1207972b676d7Smrg   if(pSiSEnt) pSiSEnt->tvxscale = val;
1208072b676d7Smrg#endif
1208172b676d7Smrg
1208272b676d7Smrg   if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
1208372b676d7Smrg
1208472b676d7Smrg      if((pSiS->VBFlags & CRT2_TV) && (pSiS->VBFlags2 & VB2_SISBRIDGE)) {
1208572b676d7Smrg
1208672b676d7Smrg	 if((val >= -16) && (val <= 16)) {
1208772b676d7Smrg
1208872b676d7Smrg	    UChar p2_44,p2_45,p2_46;
1208972b676d7Smrg	    int scalingfactor, mult;
1209072b676d7Smrg
1209172b676d7Smrg	    p2_44 = pSiS->p2_44;
1209272b676d7Smrg	    p2_45 = pSiS->p2_45 & 0x3f;
1209372b676d7Smrg	    p2_46 = pSiS->p2_46 & 0x07;
1209472b676d7Smrg#ifdef SISDUALHEAD
1209572b676d7Smrg	    if(pSiSEnt && pSiS->DualHeadMode) {
1209672b676d7Smrg	       p2_44 = pSiSEnt->p2_44;
1209772b676d7Smrg	       p2_45 = pSiSEnt->p2_45 & 0x3f;
1209872b676d7Smrg	       p2_46 = pSiSEnt->p2_46 & 0x07;
1209972b676d7Smrg	    }
1210072b676d7Smrg#endif
1210172b676d7Smrg	    scalingfactor = (p2_46 << 13) | ((p2_45 & 0x1f) << 8) | p2_44;
1210272b676d7Smrg
1210372b676d7Smrg	    mult = 64;
1210472b676d7Smrg	    if(pSiS->VBFlags & TV_YPBPR) {
1210572b676d7Smrg	       if(pSiS->VBFlags & TV_YPBPR1080I) {
1210672b676d7Smrg	          mult = 190;
1210772b676d7Smrg	       } else if(pSiS->VBFlags & TV_YPBPR750P) {
1210872b676d7Smrg	          mult = 360;
1210972b676d7Smrg	       }
1211072b676d7Smrg	    } else if(pSiS->VBFlags & TV_HIVISION) {
1211172b676d7Smrg	       mult = 190;
1211272b676d7Smrg	    }
1211372b676d7Smrg
1211472b676d7Smrg	    if(val < 0) {
1211572b676d7Smrg	       p2_45 &= 0xdf;
1211672b676d7Smrg	       scalingfactor += ((-val) * mult);
1211772b676d7Smrg	       if(scalingfactor > 0xffff) scalingfactor = 0xffff;
1211872b676d7Smrg	    } else if(val > 0) {
1211972b676d7Smrg	       p2_45 &= 0xdf;
1212072b676d7Smrg	       scalingfactor -= (val * mult);
1212172b676d7Smrg	       if(scalingfactor < 1) scalingfactor = 1;
1212272b676d7Smrg	    }
1212372b676d7Smrg
1212472b676d7Smrg	    p2_44 = scalingfactor & 0xff;
1212572b676d7Smrg	    p2_45 &= 0xe0;
1212672b676d7Smrg	    p2_45 |= ((scalingfactor >> 8) & 0x1f);
1212772b676d7Smrg	    p2_46 = ((scalingfactor >> 13) & 0x07);
1212872b676d7Smrg
1212972b676d7Smrg	    SISWaitRetraceCRT2(pScrn);
1213072b676d7Smrg	    outSISIDXREG(SISPART2,0x44,p2_44);
1213172b676d7Smrg	    setSISIDXREG(SISPART2,0x45,0xC0,p2_45);
1213272b676d7Smrg	    if(!(pSiS->VBFlags2 & VB2_301)) {
1213372b676d7Smrg	       setSISIDXREG(SISPART2,0x46,0xF8,p2_46);
1213472b676d7Smrg	    }
1213572b676d7Smrg
1213672b676d7Smrg	 }
1213772b676d7Smrg
1213872b676d7Smrg      }
1213972b676d7Smrg
1214072b676d7Smrg   }
1214172b676d7Smrg}
1214272b676d7Smrg
1214372b676d7Smrgint SiS_GetTVxscale(ScrnInfoPtr pScrn)
1214472b676d7Smrg{
1214572b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1214672b676d7Smrg#ifdef SISDUALHEAD
1214772b676d7Smrg   SISEntPtr pSiSEnt = pSiS->entityPrivate;
1214872b676d7Smrg
1214972b676d7Smrg   if(pSiSEnt && pSiS->DualHeadMode)
1215072b676d7Smrg        return (int)pSiSEnt->tvxscale;
1215172b676d7Smrg   else
1215272b676d7Smrg#endif
1215372b676d7Smrg        return (int)pSiS->tvxscale;
1215472b676d7Smrg}
1215572b676d7Smrg
1215672b676d7Smrgvoid SiS_SetTVyscale(ScrnInfoPtr pScrn, int val)
1215772b676d7Smrg{
1215872b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1215972b676d7Smrg#ifdef SISDUALHEAD
1216072b676d7Smrg   SISEntPtr pSiSEnt = pSiS->entityPrivate;
1216172b676d7Smrg#endif
1216272b676d7Smrg
1216372b676d7Smrg#ifdef UNLOCK_ALWAYS
1216472b676d7Smrg   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
1216572b676d7Smrg#endif
1216672b676d7Smrg
1216772b676d7Smrg   if(val < -4) val = -4;
1216872b676d7Smrg   if(val > 3)  val = 3;
1216972b676d7Smrg
1217072b676d7Smrg   pSiS->tvyscale = val;
1217172b676d7Smrg#ifdef SISDUALHEAD
1217272b676d7Smrg   if(pSiSEnt) pSiSEnt->tvyscale = val;
1217372b676d7Smrg#endif
1217472b676d7Smrg
1217572b676d7Smrg   if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
1217672b676d7Smrg
1217772b676d7Smrg      if((pSiS->VBFlags & CRT2_TV) && (pSiS->VBFlags2 & VB2_SISBRIDGE)) {
1217872b676d7Smrg
1217972b676d7Smrg	 int srindex = -1, newvde, i = 0, j, vlimit, temp, vdediv;
1218072b676d7Smrg	 int hdclk = 0;
1218172b676d7Smrg	 UChar p3d4_34;
1218272b676d7Smrg	 Bool found = FALSE;
1218372b676d7Smrg	 Bool usentsc = FALSE;
1218472b676d7Smrg	 Bool is750p = FALSE;
1218572b676d7Smrg	 Bool is1080i = FALSE;
1218672b676d7Smrg	 Bool skipmoveup = FALSE;
1218772b676d7Smrg
1218872b676d7Smrg	 SiS_UnLockCRT2(pSiS->SiS_Pr);
1218972b676d7Smrg
1219072b676d7Smrg	 if((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR525P)) {
1219172b676d7Smrg	    vlimit = 525 - 7;
1219272b676d7Smrg	    vdediv = 1;
1219372b676d7Smrg	    usentsc = TRUE;
1219472b676d7Smrg	 } else if((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR625P)) {
1219572b676d7Smrg	    vlimit = 625 - 7;
1219672b676d7Smrg	    vdediv = 1;
1219772b676d7Smrg	 } else if((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR750P)) {
1219872b676d7Smrg	    vlimit = 750 - 7;
1219972b676d7Smrg	    vdediv = 1;
1220072b676d7Smrg	    is750p = TRUE;
1220172b676d7Smrg	 } else if(((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR1080I)) ||
1220272b676d7Smrg	           (pSiS->VBFlags & TV_HIVISION)) {
1220372b676d7Smrg	    vlimit = (1125 - 7) / 2;
1220472b676d7Smrg	    vdediv = 2;
1220572b676d7Smrg	    is1080i = TRUE;
1220672b676d7Smrg	 } else {
1220772b676d7Smrg	    if( ((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR525I)) ||
1220872b676d7Smrg	        ((!(pSiS->VBFlags & TV_YPBPR)) && (pSiS->VBFlags & (TV_NTSC | TV_PALM))) ) {
1220972b676d7Smrg	       usentsc = TRUE;
1221072b676d7Smrg	    }
1221172b676d7Smrg	    vlimit = usentsc ? 259 : 309;
1221272b676d7Smrg	    vdediv = 2;
1221372b676d7Smrg	 }
1221472b676d7Smrg
1221572b676d7Smrg	 inSISIDXREG(SISCR,0x34,p3d4_34);
1221672b676d7Smrg
1221772b676d7Smrg	 switch((p3d4_34 & 0x7f)) {
1221872b676d7Smrg	 case 0x50:   /* 320x240 */
1221972b676d7Smrg	 case 0x56:
1222072b676d7Smrg	 case 0x53:
1222172b676d7Smrg	    hdclk = 1;
1222272b676d7Smrg	    /* fall through */
1222372b676d7Smrg	 case 0x2e:   /* 640x480 */
1222472b676d7Smrg	 case 0x44:
1222572b676d7Smrg	 case 0x62:
1222672b676d7Smrg	    if(is1080i) {
1222772b676d7Smrg	       srindex = 98;
1222872b676d7Smrg	    } else if(is750p) {
1222972b676d7Smrg	       srindex = 42;
1223072b676d7Smrg	    } else {
1223172b676d7Smrg	       srindex  = usentsc ? 0 : 21;
1223272b676d7Smrg	    }
1223372b676d7Smrg	    break;
1223472b676d7Smrg	 case 0x31:   /* 720x480 */
1223572b676d7Smrg	 case 0x33:
1223672b676d7Smrg	 case 0x35:
1223772b676d7Smrg	    if(is1080i) {
1223872b676d7Smrg	       /* n/a */
1223972b676d7Smrg	    } else if(is750p) {
1224072b676d7Smrg	       srindex = 49;
1224172b676d7Smrg	    } else {
1224272b676d7Smrg	       srindex = usentsc ? 7 : 21;
1224372b676d7Smrg	    }
1224472b676d7Smrg	    break;
1224572b676d7Smrg	 case 0x32:   /* 720x576 */
1224672b676d7Smrg	 case 0x34:
1224772b676d7Smrg	 case 0x36:
1224872b676d7Smrg	 case 0x5f:   /* 768x576 */
1224972b676d7Smrg	 case 0x60:
1225072b676d7Smrg	 case 0x61:
1225172b676d7Smrg	    if(is1080i) {
1225272b676d7Smrg	       /* n/a */
1225372b676d7Smrg	    } else if(is750p) {
1225472b676d7Smrg	       srindex = 56;
1225572b676d7Smrg	    } else {
1225672b676d7Smrg	       srindex  = usentsc ? 147 : 28;
1225772b676d7Smrg	    }
1225872b676d7Smrg	    break;
1225972b676d7Smrg	 case 0x70:   /* 800x480 */
1226072b676d7Smrg	 case 0x7a:
1226172b676d7Smrg	 case 0x76:
1226272b676d7Smrg	    if(is1080i) {
1226372b676d7Smrg	       srindex = 105;
1226472b676d7Smrg	    } else if(is750p) {
1226572b676d7Smrg	       srindex = 63;
1226672b676d7Smrg	    } else {
1226772b676d7Smrg	       srindex = usentsc ? 175 : 21;
1226872b676d7Smrg	    }
1226972b676d7Smrg	    break;
1227072b676d7Smrg	 case 0x51:   /* 400x300 - hdclk mode */
1227172b676d7Smrg	 case 0x57:
1227272b676d7Smrg	 case 0x54:
1227372b676d7Smrg	    hdclk = 1;
1227472b676d7Smrg	    /* fall through */
1227572b676d7Smrg	 case 0x30:   /* 800x600 */
1227672b676d7Smrg	 case 0x47:
1227772b676d7Smrg	 case 0x63:
1227872b676d7Smrg	    if(is1080i) {
1227972b676d7Smrg	       srindex = 112;
1228072b676d7Smrg	    } else if(is750p) {
1228172b676d7Smrg	       srindex = 70;
1228272b676d7Smrg	    } else {
1228372b676d7Smrg	       srindex = usentsc ? 14 : 35;
1228472b676d7Smrg	    }
1228572b676d7Smrg	    break;
1228672b676d7Smrg	 case 0x1d:	/* 960x540 */
1228772b676d7Smrg	 case 0x1e:
1228872b676d7Smrg	 case 0x1f:
1228972b676d7Smrg	    if(is1080i) {
1229072b676d7Smrg	       srindex = 196;
1229172b676d7Smrg	       skipmoveup = TRUE;
1229272b676d7Smrg	    }
1229372b676d7Smrg	    break;
1229472b676d7Smrg	 case 0x20:	/* 960x600 */
1229572b676d7Smrg	 case 0x21:
1229672b676d7Smrg	 case 0x22:
1229772b676d7Smrg	    if(pSiS->VGAEngine == SIS_315_VGA && is1080i) {
1229872b676d7Smrg	       srindex = 203;
1229972b676d7Smrg	    }
1230072b676d7Smrg	    break;
1230172b676d7Smrg	 case 0x71:	/* 1024x576 */
1230272b676d7Smrg	 case 0x74:
1230372b676d7Smrg	 case 0x77:
1230472b676d7Smrg	    if(is1080i) {
1230572b676d7Smrg	       srindex = 119;
1230672b676d7Smrg	    } else if(is750p) {
1230772b676d7Smrg	       srindex = 77;
1230872b676d7Smrg	    } else {
1230972b676d7Smrg	       srindex  = usentsc ? 182 : 189;
1231072b676d7Smrg	    }
1231172b676d7Smrg	    break;
1231272b676d7Smrg	 case 0x52:	/* 512x384 */
1231372b676d7Smrg	 case 0x58:
1231472b676d7Smrg	 case 0x5c:
1231572b676d7Smrg	    hdclk = 1;
1231672b676d7Smrg	    /* fall through */
1231772b676d7Smrg	 case 0x38:	/* 1024x768 */
1231872b676d7Smrg	 case 0x4a:
1231972b676d7Smrg	 case 0x64:
1232072b676d7Smrg	    if(is1080i) {
1232172b676d7Smrg	       srindex = 126;
1232272b676d7Smrg	    } else if(is750p) {
1232372b676d7Smrg	       srindex = 84;
1232472b676d7Smrg	    } else if(!usentsc) {
1232572b676d7Smrg	       srindex = 154;
1232672b676d7Smrg	    } else if(vdediv == 1) {
1232772b676d7Smrg	       if(!hdclk) srindex = 168;
1232872b676d7Smrg	    } else {
1232972b676d7Smrg	       if(!hdclk) srindex = 161;
1233072b676d7Smrg	    }
1233172b676d7Smrg	    break;
1233272b676d7Smrg	 case 0x79:	/* 1280x720 */
1233372b676d7Smrg	 case 0x75:
1233472b676d7Smrg	 case 0x78:
1233572b676d7Smrg	    if(is1080i) {
1233672b676d7Smrg	       srindex = 133;
1233772b676d7Smrg	    } else if(is750p) {
1233872b676d7Smrg	       srindex = 91;
1233972b676d7Smrg	    }
1234072b676d7Smrg	    break;
1234172b676d7Smrg	 case 0x3a:	/* 1280x1024 */
1234272b676d7Smrg	 case 0x4d:
1234372b676d7Smrg	 case 0x65:
1234472b676d7Smrg	    if(is1080i) {
1234572b676d7Smrg	       srindex = 140;
1234672b676d7Smrg	    }
1234772b676d7Smrg	    break;
1234872b676d7Smrg	 }
1234972b676d7Smrg
1235072b676d7Smrg	 if(srindex < 0) return;
1235172b676d7Smrg
1235272b676d7Smrg	 if(pSiS->tvyscale != 0) {
1235372b676d7Smrg	    for(j = 0; j <= 1; j++) {
1235472b676d7Smrg	       for(i = 0; i <= 6; i++) {
1235572b676d7Smrg		  if(SiSTVVScale[srindex+i].sindex == pSiS->tvyscale) {
1235672b676d7Smrg		     found = TRUE;
1235772b676d7Smrg		     break;
1235872b676d7Smrg		  }
1235972b676d7Smrg	       }
1236072b676d7Smrg	       if(found) break;
1236172b676d7Smrg	       if(pSiS->tvyscale > 0) pSiS->tvyscale--;
1236272b676d7Smrg	       else pSiS->tvyscale++;
1236372b676d7Smrg	    }
1236472b676d7Smrg	 }
1236572b676d7Smrg
1236672b676d7Smrg#ifdef SISDUALHEAD
1236772b676d7Smrg	 if(pSiSEnt) pSiSEnt->tvyscale = pSiS->tvyscale;
1236872b676d7Smrg#endif
1236972b676d7Smrg
1237072b676d7Smrg	 if(pSiS->tvyscale == 0) {
1237172b676d7Smrg	    UChar p2_0a = pSiS->p2_0a;
1237272b676d7Smrg	    UChar p2_2f = pSiS->p2_2f;
1237372b676d7Smrg	    UChar p2_30 = pSiS->p2_30;
1237472b676d7Smrg	    UChar p2_46 = pSiS->p2_46;
1237572b676d7Smrg	    UChar p2_47 = pSiS->p2_47;
1237672b676d7Smrg	    UChar p1scaling[9], p4scaling[9];
1237772b676d7Smrg	    UChar *p2scaling;
1237872b676d7Smrg
1237972b676d7Smrg	    for(i = 0; i < 9; i++) {
1238072b676d7Smrg	        p1scaling[i] = pSiS->scalingp1[i];
1238172b676d7Smrg		p4scaling[i] = pSiS->scalingp4[i];
1238272b676d7Smrg	    }
1238372b676d7Smrg	    p2scaling = &pSiS->scalingp2[0];
1238472b676d7Smrg
1238572b676d7Smrg#ifdef SISDUALHEAD
1238672b676d7Smrg	    if(pSiSEnt && pSiS->DualHeadMode) {
1238772b676d7Smrg	       p2_0a = pSiSEnt->p2_0a;
1238872b676d7Smrg	       p2_2f = pSiSEnt->p2_2f;
1238972b676d7Smrg	       p2_30 = pSiSEnt->p2_30;
1239072b676d7Smrg	       p2_46 = pSiSEnt->p2_46;
1239172b676d7Smrg	       p2_47 = pSiSEnt->p2_47;
1239272b676d7Smrg	       for(i = 0; i < 9; i++) {
1239372b676d7Smrg		  p1scaling[i] = pSiSEnt->scalingp1[i];
1239472b676d7Smrg		  p4scaling[i] = pSiSEnt->scalingp4[i];
1239572b676d7Smrg	       }
1239672b676d7Smrg	       p2scaling = &pSiSEnt->scalingp2[0];
1239772b676d7Smrg	    }
1239872b676d7Smrg#endif
1239972b676d7Smrg            SISWaitRetraceCRT2(pScrn);
1240072b676d7Smrg	    if(pSiS->VBFlags2 & VB2_SISTAP4SCALER) {
1240172b676d7Smrg	       for(i = 0; i < 64; i++) {
1240272b676d7Smrg	          outSISIDXREG(SISPART2,(0xc0 + i),p2scaling[i]);
1240372b676d7Smrg	       }
1240472b676d7Smrg	    }
1240572b676d7Smrg	    for(i = 0; i < 9; i++) {
1240672b676d7Smrg	       outSISIDXREG(SISPART1,SiSScalingP1Regs[i],p1scaling[i]);
1240772b676d7Smrg	    }
1240872b676d7Smrg	    for(i = 0; i < 9; i++) {
1240972b676d7Smrg	       outSISIDXREG(SISPART4,SiSScalingP4Regs[i],p4scaling[i]);
1241072b676d7Smrg	    }
1241172b676d7Smrg
1241272b676d7Smrg	    setSISIDXREG(SISPART2,0x0a,0x7f,(p2_0a & 0x80));
1241372b676d7Smrg	    outSISIDXREG(SISPART2,0x2f,p2_2f);
1241472b676d7Smrg	    setSISIDXREG(SISPART2,0x30,0x3f,(p2_30 & 0xc0));
1241572b676d7Smrg	    if(!(pSiS->VBFlags2 & VB2_301)) {
1241672b676d7Smrg	       setSISIDXREG(SISPART2,0x46,0x9f,(p2_46 & 0x60));
1241772b676d7Smrg	       outSISIDXREG(SISPART2,0x47,p2_47);
1241872b676d7Smrg	    }
1241972b676d7Smrg
1242072b676d7Smrg	 } else {
1242172b676d7Smrg
1242272b676d7Smrg	    int realvde, myypos, watchdog = 32;
1242372b676d7Smrg	    unsigned short temp1, temp2, vgahde, vgaht, vgavt;
1242472b676d7Smrg	    int p1div = 1;
1242572b676d7Smrg	    ULong calctemp;
1242672b676d7Smrg
1242772b676d7Smrg	    srindex += i;
1242872b676d7Smrg	    newvde = SiSTVVScale[srindex].ScaleVDE;
1242972b676d7Smrg	    realvde = SiSTVVScale[srindex].RealVDE;
1243072b676d7Smrg
1243172b676d7Smrg	    if(vdediv == 1) p1div = 2;
1243272b676d7Smrg
1243372b676d7Smrg	    if(!skipmoveup) {
1243472b676d7Smrg	       do {
1243572b676d7Smrg	          inSISIDXREG(SISPART2,0x01,temp);
1243672b676d7Smrg	          temp = vlimit - ((temp & 0x7f) / p1div);
1243772b676d7Smrg	          if((temp - (((newvde / vdediv) - 2) + 9)) > 0) break;
1243872b676d7Smrg	          myypos = pSiS->tvypos - 1;
1243972b676d7Smrg#ifdef SISDUALHEAD
1244072b676d7Smrg	          if(pSiSEnt && pSiS->DualHeadMode) myypos = pSiSEnt->tvypos - 1;
1244172b676d7Smrg#endif
1244272b676d7Smrg	          SiS_SetTVyposoffset(pScrn, myypos);
1244372b676d7Smrg	       } while(watchdog--);
1244472b676d7Smrg	    }
1244572b676d7Smrg
1244672b676d7Smrg	    SISWaitRetraceCRT2(pScrn);
1244772b676d7Smrg
1244872b676d7Smrg	    if(pSiS->VBFlags2 & VB2_SISTAP4SCALER) {
1244972b676d7Smrg	       SiS_CalcXTapScaler(pSiS->SiS_Pr, realvde, newvde, 4, FALSE);
1245072b676d7Smrg	    }
1245172b676d7Smrg
1245272b676d7Smrg	    if(!(pSiS->VBFlags2 & VB2_301)) {
1245372b676d7Smrg	       temp = (newvde / vdediv) - 3;
1245472b676d7Smrg	       setSISIDXREG(SISPART2,0x46,0x9f,((temp & 0x0300) >> 3));
1245572b676d7Smrg	       outSISIDXREG(SISPART2,0x47,(temp & 0xff));
1245672b676d7Smrg	    }
1245772b676d7Smrg
1245872b676d7Smrg	    inSISIDXREG(SISPART1,0x0a,temp1);
1245972b676d7Smrg	    inSISIDXREG(SISPART1,0x0c,temp2);
1246072b676d7Smrg	    vgahde = ((temp2 & 0xf0) << 4) | temp1;
1246172b676d7Smrg	    if(pSiS->VGAEngine == SIS_300_VGA) {
1246272b676d7Smrg	       vgahde -= 12;
1246372b676d7Smrg	    } else {
1246472b676d7Smrg	       vgahde -= 16;
1246572b676d7Smrg	       if(hdclk) vgahde <<= 1;
1246672b676d7Smrg	    }
1246772b676d7Smrg
1246872b676d7Smrg	    vgaht = SiSTVVScale[srindex].reg[0];
1246972b676d7Smrg	    temp1 = vgaht;
1247072b676d7Smrg	    if((pSiS->VGAEngine == SIS_315_VGA) && hdclk) temp1 >>= 1;
1247172b676d7Smrg	    temp1--;
1247272b676d7Smrg	    outSISIDXREG(SISPART1,0x08,(temp1 & 0xff));
1247372b676d7Smrg	    setSISIDXREG(SISPART1,0x09,0x0f,((temp1 >> 4) & 0xf0));
1247472b676d7Smrg
1247572b676d7Smrg	    temp2 = (vgaht - vgahde) >> 2;
1247672b676d7Smrg	    if(pSiS->VGAEngine == SIS_300_VGA) {
1247772b676d7Smrg	       temp1 = vgahde + 12 + temp2;
1247872b676d7Smrg	       temp2 = temp1 + (temp2 << 1);
1247972b676d7Smrg	    } else {
1248072b676d7Smrg	       temp1 = vgahde;
1248172b676d7Smrg	       if(hdclk) {
1248272b676d7Smrg		  temp1 >>= 1;
1248372b676d7Smrg		  temp2 >>= 1;
1248472b676d7Smrg	       }
1248572b676d7Smrg	       temp2 >>= 1;
1248672b676d7Smrg	       temp1 = temp1 + 16 + temp2;
1248772b676d7Smrg	       temp2 = temp1 + temp2;
1248872b676d7Smrg	    }
1248972b676d7Smrg	    outSISIDXREG(SISPART1,0x0b,(temp1 & 0xff));
1249072b676d7Smrg	    setSISIDXREG(SISPART1,0x0c,0xf0,((temp1 >> 8) & 0x0f));
1249172b676d7Smrg	    outSISIDXREG(SISPART1,0x0d,(temp2 & 0xff));
1249272b676d7Smrg
1249372b676d7Smrg	    vgavt = SiSTVVScale[srindex].reg[1];
1249472b676d7Smrg	    temp1 = vgavt - 1;
1249572b676d7Smrg	    if(pSiS->VGAEngine == SIS_315_VGA) temp1--;
1249672b676d7Smrg	    outSISIDXREG(SISPART1,0x0e,(temp1 & 0xff));
1249772b676d7Smrg	    setSISIDXREG(SISPART1,0x12,0xf8,((temp1 >> 8 ) & 0x07));
1249872b676d7Smrg	    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->ChipType >= SIS_661)) {
1249972b676d7Smrg	       temp1 = (vgavt + SiSTVVScale[srindex].RealVDE) >> 1;
1250072b676d7Smrg	       temp2 = ((vgavt - SiSTVVScale[srindex].RealVDE) >> 4) + temp1 + 1;
1250172b676d7Smrg	    } else {
1250272b676d7Smrg	       temp1 = (vgavt - SiSTVVScale[srindex].RealVDE) >> 2;
1250372b676d7Smrg	       temp2 = (temp1 < 4) ? 4 : temp1;
1250472b676d7Smrg	       temp1 += SiSTVVScale[srindex].RealVDE;
1250572b676d7Smrg	       temp2 = (temp2 >> 2) + temp1 + 1;
1250672b676d7Smrg	    }
1250772b676d7Smrg	    outSISIDXREG(SISPART1,0x10,(temp1 & 0xff));
1250872b676d7Smrg	    setSISIDXREG(SISPART1,0x11,0x8f,((temp1 >> 4) & 0x70));
1250972b676d7Smrg	    setSISIDXREG(SISPART1,0x11,0xf0,(temp2 & 0x0f));
1251072b676d7Smrg
1251172b676d7Smrg	    setSISIDXREG(SISPART2,0x0a,0x7f,((SiSTVVScale[srindex].reg[2] >> 8) & 0x80));
1251272b676d7Smrg	    outSISIDXREG(SISPART2,0x2f,((newvde / vdediv) - 2));
1251372b676d7Smrg	    setSISIDXREG(SISPART2,0x30,0x3f,((((newvde / vdediv) - 2) >> 2) & 0xc0));
1251472b676d7Smrg
1251572b676d7Smrg	    outSISIDXREG(SISPART4,0x13,(SiSTVVScale[srindex].reg[2] & 0xff));
1251672b676d7Smrg	    outSISIDXREG(SISPART4,0x14,(SiSTVVScale[srindex].reg[3] & 0xff));
1251772b676d7Smrg	    setSISIDXREG(SISPART4,0x15,0x7f,((SiSTVVScale[srindex].reg[3] >> 1) & 0x80));
1251872b676d7Smrg
1251972b676d7Smrg	    temp1 = vgaht - 1;
1252072b676d7Smrg	    outSISIDXREG(SISPART4,0x16,(temp1 & 0xff));
1252172b676d7Smrg	    setSISIDXREG(SISPART4,0x15,0x87,((temp1 >> 5) & 0x78));
1252272b676d7Smrg
1252372b676d7Smrg	    temp1 = vgavt - 1;
1252472b676d7Smrg	    outSISIDXREG(SISPART4,0x17,(temp1 & 0xff));
1252572b676d7Smrg	    setSISIDXREG(SISPART4,0x15,0xf8,((temp1 >> 8) & 0x07));
1252672b676d7Smrg
1252772b676d7Smrg	    outSISIDXREG(SISPART4,0x18,0x00);
1252872b676d7Smrg	    setSISIDXREG(SISPART4,0x19,0xf0,0x00);
1252972b676d7Smrg
1253072b676d7Smrg	    inSISIDXREG(SISPART4,0x0e,temp1);
1253172b676d7Smrg	    if(is1080i) {
1253272b676d7Smrg	       if(!(temp1 & 0xe0)) newvde >>= 1;
1253372b676d7Smrg	    }
1253472b676d7Smrg
1253572b676d7Smrg	    temp = 0x40;
1253672b676d7Smrg	    if(realvde <= newvde) temp = 0;
1253772b676d7Smrg	    else realvde -= newvde;
1253872b676d7Smrg
1253972b676d7Smrg	    calctemp = (realvde * 256 * 1024) / newvde;
1254072b676d7Smrg	    if((realvde * 256 * 1024) % newvde) calctemp++;
1254172b676d7Smrg	    outSISIDXREG(SISPART4,0x1b,(calctemp & 0xff));
1254272b676d7Smrg	    outSISIDXREG(SISPART4,0x1a,((calctemp >> 8) & 0xff));
1254372b676d7Smrg	    setSISIDXREG(SISPART4,0x19,0x8f,(((calctemp >> 12) & 0x70) | temp));
1254472b676d7Smrg	 }
1254572b676d7Smrg
1254672b676d7Smrg      }
1254772b676d7Smrg
1254872b676d7Smrg   }
1254972b676d7Smrg}
1255072b676d7Smrg
1255172b676d7Smrgint SiS_GetTVyscale(ScrnInfoPtr pScrn)
1255272b676d7Smrg{
1255372b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1255472b676d7Smrg#ifdef SISDUALHEAD
1255572b676d7Smrg   SISEntPtr pSiSEnt = pSiS->entityPrivate;
1255672b676d7Smrg
1255772b676d7Smrg   if(pSiSEnt && pSiS->DualHeadMode)
1255872b676d7Smrg        return (int)pSiSEnt->tvyscale;
1255972b676d7Smrg   else
1256072b676d7Smrg#endif
1256172b676d7Smrg        return (int)pSiS->tvyscale;
1256272b676d7Smrg}
1256372b676d7Smrg
1256472b676d7Smrgvoid SiS_SetSISCRT1SaturationGain(ScrnInfoPtr pScrn, int val)
1256572b676d7Smrg{
1256672b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1256772b676d7Smrg#ifdef SISDUALHEAD
1256872b676d7Smrg   SISEntPtr pSiSEnt = pSiS->entityPrivate;
1256972b676d7Smrg#endif
1257072b676d7Smrg
1257172b676d7Smrg   pSiS->siscrt1satgain = val;
1257272b676d7Smrg#ifdef SISDUALHEAD
1257372b676d7Smrg   if(pSiSEnt) pSiSEnt->siscrt1satgain = val;
1257472b676d7Smrg#endif
1257572b676d7Smrg
1257672b676d7Smrg   if(!(pSiS->SiS_SD3_Flags & SiS_SD3_CRT1SATGAIN)) return;
1257772b676d7Smrg
1257872b676d7Smrg#ifdef UNLOCK_ALWAYS
1257972b676d7Smrg   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
1258072b676d7Smrg#endif
1258172b676d7Smrg
1258272b676d7Smrg   if((val >= 0) && (val <= 7)) {
1258372b676d7Smrg      setSISIDXREG(SISCR,0x53,0xE3, (val << 2));
1258472b676d7Smrg   }
1258572b676d7Smrg}
1258672b676d7Smrg
1258772b676d7Smrgint SiS_GetSISCRT1SaturationGain(ScrnInfoPtr pScrn)
1258872b676d7Smrg{
1258972b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1259072b676d7Smrg   int result = pSiS->siscrt1satgain;
1259172b676d7Smrg   UChar temp;
1259272b676d7Smrg#ifdef SISDUALHEAD
1259372b676d7Smrg   SISEntPtr pSiSEnt = pSiS->entityPrivate;
1259472b676d7Smrg
1259572b676d7Smrg   if(pSiSEnt && pSiS->DualHeadMode)  result = pSiSEnt->siscrt1satgain;
1259672b676d7Smrg#endif
1259772b676d7Smrg
1259872b676d7Smrg   if(!(pSiS->SiS_SD3_Flags & SiS_SD3_CRT1SATGAIN)) return result;
1259972b676d7Smrg
1260072b676d7Smrg#ifdef UNLOCK_ALWAYS
1260172b676d7Smrg   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
1260272b676d7Smrg#endif
1260372b676d7Smrg   inSISIDXREG(SISCR, 0x53, temp);
1260472b676d7Smrg   return (int)((temp >> 2) & 0x07);
1260572b676d7Smrg}
1260672b676d7Smrg
1260772b676d7Smrg/* Calc dotclock from registers */
1260872b676d7Smrgstatic int
1260972b676d7SmrgSiSGetClockFromRegs(UChar sr2b, UChar sr2c)
1261072b676d7Smrg{
1261172b676d7Smrg   float num, denum, postscalar, divider;
1261272b676d7Smrg   int   myclock;
1261372b676d7Smrg
1261472b676d7Smrg   divider = (sr2b & 0x80) ? 2.0 : 1.0;
1261572b676d7Smrg   postscalar = (sr2c & 0x80) ?
1261672b676d7Smrg              ( (((sr2c >> 5) & 0x03) == 0x02) ? 6.0 : 8.0 ) :
1261772b676d7Smrg	      ( ((sr2c >> 5) & 0x03) + 1.0 );
1261872b676d7Smrg   num = (sr2b & 0x7f) + 1.0;
1261972b676d7Smrg   denum = (sr2c & 0x1f) + 1.0;
1262072b676d7Smrg   myclock = (int)((14318 * (divider / postscalar) * (num / denum)) / 1000);
1262172b676d7Smrg   return myclock;
1262272b676d7Smrg}
1262372b676d7Smrg
1262472b676d7Smrg#ifdef SISDUALHEAD
1262572b676d7Smrgstatic void
1262672b676d7SmrgSiS_SetDHFlags(SISPtr pSiS, unsigned int misc, unsigned int sd2)
1262772b676d7Smrg{
1262872b676d7Smrg   SISEntPtr pSiSEnt = pSiS->entityPrivate;
1262972b676d7Smrg
1263072b676d7Smrg   if(pSiS->DualHeadMode) {
1263172b676d7Smrg      if(pSiSEnt->pScrn_1) {
1263272b676d7Smrg	 SISPTR(pSiSEnt->pScrn_1)->MiscFlags |= misc;
1263372b676d7Smrg	 SISPTR(pSiSEnt->pScrn_1)->SiS_SD2_Flags |= sd2;
1263472b676d7Smrg      }
1263572b676d7Smrg      if(pSiSEnt->pScrn_2) {
1263672b676d7Smrg	 SISPTR(pSiSEnt->pScrn_2)->MiscFlags |= misc;
1263772b676d7Smrg	 SISPTR(pSiSEnt->pScrn_2)->SiS_SD2_Flags |= sd2;
1263872b676d7Smrg      }
1263972b676d7Smrg   }
1264072b676d7Smrg}
1264172b676d7Smrg#endif
1264272b676d7Smrg
1264372b676d7Smrg/* PostSetMode:
1264472b676d7Smrg * -) Disable CRT1 for saving bandwidth. This doesn't work with VESA;
1264572b676d7Smrg *    VESA uses the bridge in SlaveMode and switching CRT1 off while
1264672b676d7Smrg *    the bridge is in SlaveMode not that clever...
1264772b676d7Smrg * -) Check if overlay can be used (depending on dotclock)
1264872b676d7Smrg * -) Check if Panel Scaler is active on LVDS for overlay re-scaling
1264972b676d7Smrg * -) Save TV registers for further processing
1265072b676d7Smrg * -) Apply TV settings
1265172b676d7Smrg */
1265272b676d7Smrgstatic void
1265372b676d7SmrgSiSPostSetMode(ScrnInfoPtr pScrn, SISRegPtr sisReg)
1265472b676d7Smrg{
1265572b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
1265672b676d7Smrg#ifdef SISDUALHEAD
1265772b676d7Smrg    SISEntPtr pSiSEnt = pSiS->entityPrivate;
1265872b676d7Smrg#endif
1265972b676d7Smrg    UChar usScratchCR17, sr2b, sr2c, tmpreg;
1266072b676d7Smrg    int   myclock1, myclock2, mycoldepth1, mycoldepth2, temp;
1266172b676d7Smrg    Bool  flag = FALSE;
1266272b676d7Smrg    Bool  doit = TRUE;
1266372b676d7Smrg    Bool  IsInSlaveMode;
1266472b676d7Smrg
1266572b676d7Smrg#ifdef TWDEBUG
1266672b676d7Smrg    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1266772b676d7Smrg    	"CRT1off is %d\n", pSiS->CRT1off);
1266872b676d7Smrg#endif
1266972b676d7Smrg    pSiS->CRT1isoff = pSiS->CRT1off;
1267072b676d7Smrg
1267172b676d7Smrg#ifdef UNLOCK_ALWAYS
1267272b676d7Smrg    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
1267372b676d7Smrg#endif
1267472b676d7Smrg
1267572b676d7Smrg    SiSFixupSR11(pScrn);
1267672b676d7Smrg
1267772b676d7Smrg    IsInSlaveMode = SiSBridgeIsInSlaveMode(pScrn);
1267872b676d7Smrg
1267972b676d7Smrg    if((!pSiS->UseVESA) && (pSiS->VBFlags & CRT2_ENABLE)) {
1268072b676d7Smrg
1268172b676d7Smrg	if(pSiS->VBFlags != pSiS->VBFlags_backup) {
1268272b676d7Smrg	   pSiS->VBFlags = pSiS->VBFlags_backup;
1268372b676d7Smrg	   xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1268472b676d7Smrg			"VBFlags restored to %0x\n", pSiS->VBFlags);
1268572b676d7Smrg	}
1268672b676d7Smrg
1268772b676d7Smrg	/* -) We can't switch off CRT1 if bridge is in SlaveMode.
1268872b676d7Smrg	 * -) If we change to a SlaveMode-Mode (like 512x384), we
1268972b676d7Smrg	 *    need to adapt VBFlags for eg. Xv.
1269072b676d7Smrg	 */
1269172b676d7Smrg#ifdef SISDUALHEAD
1269272b676d7Smrg	if(!pSiS->DualHeadMode) {
1269372b676d7Smrg#endif
1269472b676d7Smrg	   if(IsInSlaveMode) {
1269572b676d7Smrg	      doit = FALSE;
1269672b676d7Smrg	      temp = pSiS->VBFlags;
1269772b676d7Smrg	      pSiS->VBFlags &= (~VB_DISPMODE_SINGLE);
1269872b676d7Smrg	      pSiS->VBFlags |= (VB_DISPMODE_MIRROR | DISPTYPE_DISP1);
1269972b676d7Smrg              if(temp != pSiS->VBFlags) {
1270072b676d7Smrg		 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1270172b676d7Smrg		 	"VBFlags changed to 0x%0x\n", pSiS->VBFlags);
1270272b676d7Smrg	      }
1270372b676d7Smrg	   }
1270472b676d7Smrg#ifdef SISDUALHEAD
1270572b676d7Smrg	}
1270672b676d7Smrg#endif
1270772b676d7Smrg
1270872b676d7Smrg	if(pSiS->VGAEngine == SIS_315_VGA) {
1270972b676d7Smrg
1271072b676d7Smrg	   if((pSiS->CRT1off) && (doit)) {
1271172b676d7Smrg	      orSISIDXREG(SISCR,pSiS->myCR63,0x40);
1271272b676d7Smrg	      orSISIDXREG(SISSR,0x1f,0xc0);
1271372b676d7Smrg	      andSISIDXREG(SISSR,0x07,~0x10);
1271472b676d7Smrg	      andSISIDXREG(SISSR,0x06,0xe2);
1271572b676d7Smrg	      andSISIDXREG(SISSR,0x31,0xcf);
1271672b676d7Smrg	      outSISIDXREG(SISSR,0x2b,0x1b);
1271772b676d7Smrg	      outSISIDXREG(SISSR,0x2c,0xe1);
1271872b676d7Smrg	      outSISIDXREG(SISSR,0x2d,0x01);
1271972b676d7Smrg	      outSISIDXREG(SISSR, 0x00, 0x01);    /* Synchronous Reset */
1272072b676d7Smrg	      usleep(10000);
1272172b676d7Smrg	      outSISIDXREG(SISSR, 0x00, 0x03);    /* End Reset */
1272272b676d7Smrg	   } else {
1272372b676d7Smrg	      andSISIDXREG(SISCR,pSiS->myCR63,0xBF);
1272472b676d7Smrg	      andSISIDXREG(SISSR,0x1f,0x3f);
1272572b676d7Smrg	      orSISIDXREG(SISSR,0x07,0x10);
1272672b676d7Smrg	   }
1272772b676d7Smrg
1272872b676d7Smrg	} else {
1272972b676d7Smrg
1273072b676d7Smrg	   if(doit) {
1273172b676d7Smrg	      inSISIDXREG(SISCR, 0x17, usScratchCR17);
1273272b676d7Smrg	      if(pSiS->CRT1off) {
1273372b676d7Smrg		 if(usScratchCR17 & 0x80) {
1273472b676d7Smrg		    flag = TRUE;
1273572b676d7Smrg		    usScratchCR17 &= ~0x80;
1273672b676d7Smrg		 }
1273772b676d7Smrg		 orSISIDXREG(SISSR,0x1f,0xc0);
1273872b676d7Smrg	      } else {
1273972b676d7Smrg		 if(!(usScratchCR17 & 0x80)) {
1274072b676d7Smrg		    flag = TRUE;
1274172b676d7Smrg		    usScratchCR17 |= 0x80;
1274272b676d7Smrg		 }
1274372b676d7Smrg		 andSISIDXREG(SISSR,0x1f,0x3f);
1274472b676d7Smrg	      }
1274572b676d7Smrg	      /* Reset only if status changed */
1274672b676d7Smrg	      if(flag) {
1274772b676d7Smrg		 outSISIDXREG(SISCR, 0x17, usScratchCR17);
1274872b676d7Smrg		 outSISIDXREG(SISSR, 0x00, 0x01);    /* Synchronous Reset */
1274972b676d7Smrg		 usleep(10000);
1275072b676d7Smrg		 outSISIDXREG(SISSR, 0x00, 0x03);    /* End Reset */
1275172b676d7Smrg	      }
1275272b676d7Smrg	   }
1275372b676d7Smrg	}
1275472b676d7Smrg
1275572b676d7Smrg    }
1275672b676d7Smrg
1275772b676d7Smrg    /* Set bridge to "disable CRT2" mode if CRT2 is disabled, LCD-A is enabled */
1275872b676d7Smrg    /* (Not needed for CRT1=VGA since CRT2 will really be disabled then) */
1275972b676d7Smrg#ifdef SISDUALHEAD
1276072b676d7Smrg    if(!pSiS->DualHeadMode) {
1276172b676d7Smrg#endif
1276272b676d7Smrg       if((pSiS->VGAEngine == SIS_315_VGA)  && (pSiS->VBFlags2 & VB2_SISLCDABRIDGE)) {
1276372b676d7Smrg	  if((!pSiS->UseVESA) && (!(pSiS->VBFlags & CRT2_ENABLE)) && (pSiS->VBFlags & CRT1_LCDA)) {
1276472b676d7Smrg	     if(!IsInSlaveMode) {
1276572b676d7Smrg	        andSISIDXREG(SISPART4,0x0d,~0x07);
1276672b676d7Smrg	     }
1276772b676d7Smrg	  }
1276872b676d7Smrg       }
1276972b676d7Smrg#ifdef SISDUALHEAD
1277072b676d7Smrg    }
1277172b676d7Smrg#endif
1277272b676d7Smrg
1277372b676d7Smrg    /* Reset flags */
1277472b676d7Smrg    pSiS->MiscFlags &= ~( MISC_CRT1OVERLAY      |
1277572b676d7Smrg			  MISC_CRT2OVERLAY      |
1277672b676d7Smrg			  MISC_CRT1OVERLAYGAMMA |
1277772b676d7Smrg			  MISC_SIS760ONEOVERLAY |
1277872b676d7Smrg			  MISC_PANELLINKSCALER  |
1277972b676d7Smrg			  MISC_STNMODE		|
1278072b676d7Smrg			  MISC_TVNTSC1024);
1278172b676d7Smrg
1278272b676d7Smrg    pSiS->SiS_SD2_Flags &= ~SiS_SD2_SIS760ONEOVL;
1278372b676d7Smrg
1278472b676d7Smrg#ifdef SISDUALHEAD
1278572b676d7Smrg    if(pSiS->DualHeadMode) {
1278672b676d7Smrg       if(pSiSEnt->pScrn_1) {
1278772b676d7Smrg	  SISPTR(pSiSEnt->pScrn_1)->MiscFlags &= ~(MISC_SIS760ONEOVERLAY	|
1278872b676d7Smrg						   MISC_CRT1OVERLAY		|
1278972b676d7Smrg						   MISC_CRT2OVERLAY		|
1279072b676d7Smrg						   MISC_CRT1OVERLAYGAMMA	|
1279172b676d7Smrg						   MISC_PANELLINKSCALER		|
1279272b676d7Smrg						   MISC_STNMODE			|
1279372b676d7Smrg						   MISC_TVNTSC1024);
1279472b676d7Smrg	  SISPTR(pSiSEnt->pScrn_1)->SiS_SD2_Flags &= ~SiS_SD2_SIS760ONEOVL;
1279572b676d7Smrg       }
1279672b676d7Smrg       if(pSiSEnt->pScrn_2) {
1279772b676d7Smrg	  SISPTR(pSiSEnt->pScrn_2)->MiscFlags &= ~(MISC_SIS760ONEOVERLAY	|
1279872b676d7Smrg						   MISC_CRT1OVERLAY		|
1279972b676d7Smrg						   MISC_CRT2OVERLAY		|
1280072b676d7Smrg						   MISC_CRT1OVERLAYGAMMA	|
1280172b676d7Smrg						   MISC_PANELLINKSCALER		|
1280272b676d7Smrg						   MISC_STNMODE			|
1280372b676d7Smrg						   MISC_TVNTSC1024);
1280472b676d7Smrg	  SISPTR(pSiSEnt->pScrn_2)->SiS_SD2_Flags &= ~SiS_SD2_SIS760ONEOVL;
1280572b676d7Smrg       }
1280672b676d7Smrg    }
1280772b676d7Smrg#endif
1280872b676d7Smrg
1280972b676d7Smrg    /* Determine if the video overlay can be used */
1281072b676d7Smrg    if(!pSiS->NoXvideo) {
1281172b676d7Smrg
1281272b676d7Smrg       int clklimit1=0, clklimit2=0, clklimitg=0;
1281372b676d7Smrg       Bool OverlayHandled = FALSE;
1281472b676d7Smrg
1281572b676d7Smrg       inSISIDXREG(SISSR,0x2b,sr2b);
1281672b676d7Smrg       inSISIDXREG(SISSR,0x2c,sr2c);
1281772b676d7Smrg       myclock1 = myclock2 = SiSGetClockFromRegs(sr2b, sr2c);
1281872b676d7Smrg       inSISIDXREG(SISSR,0x06,tmpreg);
1281972b676d7Smrg       switch((tmpreg & 0x1c) >> 2) {
1282072b676d7Smrg       case 0:  mycoldepth1 = 1; break;
1282172b676d7Smrg       case 1:
1282272b676d7Smrg       case 2:  mycoldepth1 = 2; break;
1282372b676d7Smrg       default: mycoldepth1 = 4;
1282472b676d7Smrg       }
1282572b676d7Smrg       mycoldepth2 = mycoldepth1;
1282672b676d7Smrg
1282772b676d7Smrg       if((!IsInSlaveMode) && (pSiS->VBFlags & CRT2_ENABLE)) {
1282872b676d7Smrg	  if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
1282972b676d7Smrg	     inSISIDXREG(SISPART4,0x0a,sr2b);
1283072b676d7Smrg	     inSISIDXREG(SISPART4,0x0b,sr2c);
1283172b676d7Smrg	  } else {
1283272b676d7Smrg	     inSISIDXREG(SISSR,0x2e,sr2b);
1283372b676d7Smrg	     inSISIDXREG(SISSR,0x2f,sr2c);
1283472b676d7Smrg	  }
1283572b676d7Smrg	  myclock2 = SiSGetClockFromRegs(sr2b, sr2c);
1283672b676d7Smrg	  inSISIDXREG(SISPART1,0x00,tmpreg);
1283772b676d7Smrg	  tmpreg &= 0x0f;
1283872b676d7Smrg	  switch(tmpreg) {
1283972b676d7Smrg	  case 8:  mycoldepth2 = 1; break;
1284072b676d7Smrg	  case 4:
1284172b676d7Smrg	  case 2:  mycoldepth2 = 2; break;
1284272b676d7Smrg	  default: mycoldepth2 = 4;
1284372b676d7Smrg	  }
1284472b676d7Smrg       }
1284572b676d7Smrg
1284672b676d7Smrg       switch(pSiS->ChipType) {
1284772b676d7Smrg
1284872b676d7Smrg	 case SIS_300:
1284972b676d7Smrg	 case SIS_540:
1285072b676d7Smrg	 case SIS_630:
1285172b676d7Smrg	 case SIS_730:
1285272b676d7Smrg	    clklimit1 = clklimit2 = clklimitg = 150;
1285372b676d7Smrg	    break;
1285472b676d7Smrg
1285572b676d7Smrg	 case SIS_550:
1285672b676d7Smrg	 case SIS_650:
1285772b676d7Smrg	 case SIS_740:
1285872b676d7Smrg	    clklimit1 = clklimit2 = 175;  /* verified for 65x */
1285972b676d7Smrg	    clklimitg = 166;		  /* ? */
1286072b676d7Smrg	    break;
1286172b676d7Smrg
1286272b676d7Smrg	 case SIS_661:
1286372b676d7Smrg	 case SIS_741:
1286472b676d7Smrg	    clklimit1 = clklimit2 = 190;  /* ? */
1286572b676d7Smrg	    clklimitg = 180;		  /* ? */
1286672b676d7Smrg	    break;
1286772b676d7Smrg
1286872b676d7Smrg	 case SIS_760:
1286972b676d7Smrg	 case SIS_761:
1287072b676d7Smrg	    clklimit1 = clklimit2 = 190;    /* ? */
1287172b676d7Smrg	    if(pSiS->ChipFlags & SiSCF_760LFB) {		/* LFB only or hybrid */
1287272b676d7Smrg	       clklimit1 = clklimit2 = 220; /* ? */
1287372b676d7Smrg	    }
1287472b676d7Smrg	    clklimitg = 200;		    /* ? */
1287572b676d7Smrg
1287672b676d7Smrg	    if(pSiS->SiS_SD2_Flags & SiS_SD2_SUPPORT760OO) {	/* UMA only */
1287772b676d7Smrg
1287872b676d7Smrg	       Bool OnlyOne = FALSE, NoOverlay = FALSE;
1287972b676d7Smrg	       int dotclocksum = 0;
1288072b676d7Smrg
1288172b676d7Smrg	       if(pSiS->VBFlags & DISPTYPE_CRT1)                     dotclocksum += myclock1;
1288272b676d7Smrg	       if((!IsInSlaveMode) && (pSiS->VBFlags & CRT2_ENABLE)) dotclocksum += myclock2;
1288372b676d7Smrg
1288472b676d7Smrg	       /* TODO: Find out under what circumstances only one
1288572b676d7Smrg		*	overlay is usable in UMA-only mode.
1288672b676d7Smrg		*	This is not entirely accurate; the overlay
1288772b676d7Smrg		*	scaler also requires some time, so even though
1288872b676d7Smrg		*	the dotclocks are below these values, some
1288972b676d7Smrg		*	distortions in the overlay may occure.
1289072b676d7Smrg		*	Solution: Don't use a 760 with shared memory.
1289172b676d7Smrg		*/
1289272b676d7Smrg	       if( (pSiS->VBFlags & DISPTYPE_CRT1) &&
1289372b676d7Smrg		   (pSiS->VBFlags & CRT2_ENABLE) &&
1289472b676d7Smrg		   (mycoldepth1 != mycoldepth2) ) {
1289572b676d7Smrg
1289672b676d7Smrg		  /* 0. If coldepths are different (only possible in dual head mode),
1289772b676d7Smrg		   *    I have no idea to calculate the limits; hence, allow only one
1289872b676d7Smrg		   *    overlay in all cases.
1289972b676d7Smrg		   */
1290072b676d7Smrg		  OnlyOne = TRUE;
1290172b676d7Smrg
1290272b676d7Smrg	       } else if(pSiS->MemClock < 150000) {
1290372b676d7Smrg
1290472b676d7Smrg		  /* 1. MCLK <150: If someone seriously considers using such
1290572b676d7Smrg		   *    slow RAM, so be it. Only one overlay in call cases.
1290672b676d7Smrg		   */
1290772b676d7Smrg		  OnlyOne = TRUE;
1290872b676d7Smrg
1290972b676d7Smrg	       } else if(pSiS->MemClock < 170000) {
1291072b676d7Smrg
1291172b676d7Smrg		  /* 2. MCLK 166 */
1291272b676d7Smrg		  switch(pSiS->CurrentLayout.bitsPerPixel) {
1291372b676d7Smrg		     case 32: if(dotclocksum > 133) OnlyOne = TRUE;		/* One overlay; verified */
1291472b676d7Smrg			      if(dotclocksum > 180) NoOverlay = TRUE;		/* No overlay; verified */
1291572b676d7Smrg			      break;
1291672b676d7Smrg		     case 16: if(dotclocksum > 175) OnlyOne = TRUE;		/* One overlay; verified */
1291772b676d7Smrg			      if(dotclocksum > 260) NoOverlay = TRUE;;		/* No overlay; FIXME */
1291872b676d7Smrg			      break;
1291972b676d7Smrg		  }
1292072b676d7Smrg
1292172b676d7Smrg	       } else if(pSiS->MemClock < 210000) {
1292272b676d7Smrg
1292372b676d7Smrg		  /* 3. MCLK 200 */
1292472b676d7Smrg		  switch(pSiS->CurrentLayout.bitsPerPixel) {
1292572b676d7Smrg		     case 32: if(dotclocksum > 160) OnlyOne = TRUE;		/* One overlay; FIXME */
1292672b676d7Smrg			      if(dotclocksum > 216) NoOverlay = TRUE;;		/* No overlay; FIXME */
1292772b676d7Smrg			      break;
1292872b676d7Smrg		     case 16: if(dotclocksum > 210) OnlyOne = TRUE;		/* One overlay; FIXME */
1292972b676d7Smrg			      if(dotclocksum > 312) NoOverlay = TRUE;;		/* No overlay; FIXME */
1293072b676d7Smrg			      break;
1293172b676d7Smrg		  }
1293272b676d7Smrg
1293372b676d7Smrg	       }
1293472b676d7Smrg
1293572b676d7Smrg	       if(OnlyOne || NoOverlay) {
1293672b676d7Smrg
1293772b676d7Smrg		  ULong tmpflags = 0;
1293872b676d7Smrg
1293972b676d7Smrg		  if(!NoOverlay) {
1294072b676d7Smrg		     if(myclock1 <= clklimit1) tmpflags |= MISC_CRT1OVERLAY;
1294172b676d7Smrg		     if(myclock2 <= clklimit2) tmpflags |= MISC_CRT2OVERLAY;
1294272b676d7Smrg		     if(myclock1 <= clklimitg) tmpflags |= MISC_CRT1OVERLAYGAMMA;
1294372b676d7Smrg		     pSiS->MiscFlags |= tmpflags;
1294472b676d7Smrg		  }
1294572b676d7Smrg		  pSiS->MiscFlags |= MISC_SIS760ONEOVERLAY;
1294672b676d7Smrg		  pSiS->SiS_SD2_Flags |= SiS_SD2_SIS760ONEOVL;
1294772b676d7Smrg#ifdef SISDUALHEAD
1294872b676d7Smrg		  SiS_SetDHFlags(pSiS, (tmpflags | MISC_SIS760ONEOVERLAY), SiS_SD2_SIS760ONEOVL);
1294972b676d7Smrg#endif
1295072b676d7Smrg		  OverlayHandled = TRUE;
1295172b676d7Smrg	       }
1295272b676d7Smrg
1295372b676d7Smrg	       xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
1295472b676d7Smrg			"SiS76x/UMA: %s video overlay(s) available in current mode\n",
1295572b676d7Smrg			NoOverlay ? "no" : ((pSiS->MiscFlags & MISC_SIS760ONEOVERLAY) ? "one" : "two"));
1295672b676d7Smrg
1295772b676d7Smrg#ifdef TWDEBUG
1295872b676d7Smrg	       xf86DrvMsg(0, 0, "SiS760: Memclock %d, c1 %d/%d c2 %d/%d, sum %d / %x\n",
1295972b676d7Smrg			pSiS->MemClock, myclock1, mycoldepth1,
1296072b676d7Smrg			myclock2, mycoldepth2, dotclocksum, pSiS->SiS_SD2_Flags);
1296172b676d7Smrg#endif
1296272b676d7Smrg	    }
1296372b676d7Smrg	    break;
1296472b676d7Smrg
1296572b676d7Smrg	 case SIS_660:
1296672b676d7Smrg	    clklimit1 = clklimit2 = 200;  /* ? */
1296772b676d7Smrg	    if(pSiS->ChipFlags & SiSCF_760LFB) {		/* LFB only */
1296872b676d7Smrg	       clklimit1 = clklimit2 = 220;
1296972b676d7Smrg	    }
1297072b676d7Smrg	    clklimitg = 200;		  /* ? */
1297172b676d7Smrg	    break;
1297272b676d7Smrg
1297372b676d7Smrg	 case SIS_315H:
1297472b676d7Smrg	 case SIS_315:
1297572b676d7Smrg	 case SIS_315PRO:
1297672b676d7Smrg	 case SIS_330:
1297772b676d7Smrg	    clklimit1 = clklimit2 = 180;  /* ? */
1297872b676d7Smrg	    clklimitg = 166;		  /* ? */
1297972b676d7Smrg	    break;
1298072b676d7Smrg
1298172b676d7Smrg	 case SIS_340: /* ? */
1298272b676d7Smrg	 case XGI_20:
1298372b676d7Smrg	 case XGI_40:
1298472b676d7Smrg	    clklimit1 = clklimit2 = 240;  /* ? */
1298572b676d7Smrg	    clklimitg = 200;		  /* ? */
1298672b676d7Smrg	    break;
1298772b676d7Smrg       }
1298872b676d7Smrg
1298972b676d7Smrg       if(!OverlayHandled) {
1299072b676d7Smrg          ULong tmpflags = 0;
1299172b676d7Smrg          if(myclock1 <= clklimit1) tmpflags |= MISC_CRT1OVERLAY;
1299272b676d7Smrg          if(myclock2 <= clklimit2) tmpflags |= MISC_CRT2OVERLAY;
1299372b676d7Smrg          if(myclock1 <= clklimitg) tmpflags |= MISC_CRT1OVERLAYGAMMA;
1299472b676d7Smrg	  pSiS->MiscFlags |= tmpflags;
1299572b676d7Smrg#ifdef SISDUALHEAD
1299672b676d7Smrg	  SiS_SetDHFlags(pSiS, tmpflags, 0);
1299772b676d7Smrg#endif
1299872b676d7Smrg          if(!(pSiS->MiscFlags & MISC_CRT1OVERLAY)) {
1299972b676d7Smrg#ifdef SISDUALHEAD
1300072b676d7Smrg             if((!pSiS->DualHeadMode) || (pSiS->SecondHead))
1300172b676d7Smrg#endif
1300272b676d7Smrg		xf86DrvMsgVerb(pScrn->scrnIndex, X_WARNING, 3,
1300372b676d7Smrg		   "Current dotclock (%dMhz) too high for video overlay on CRT1\n",
1300472b676d7Smrg		   myclock1);
1300572b676d7Smrg          }
1300672b676d7Smrg          if((pSiS->VBFlags & CRT2_ENABLE) && (!(pSiS->MiscFlags & MISC_CRT2OVERLAY))) {
1300772b676d7Smrg#ifdef SISDUALHEAD
1300872b676d7Smrg	     if((!pSiS->DualHeadMode) || (!pSiS->SecondHead))
1300972b676d7Smrg#endif
1301072b676d7Smrg		xf86DrvMsgVerb(pScrn->scrnIndex, X_WARNING, 3,
1301172b676d7Smrg		   "Current dotclock (%dMhz) too high for video overlay on CRT2\n",
1301272b676d7Smrg		   myclock2);
1301372b676d7Smrg	  }
1301472b676d7Smrg       }
1301572b676d7Smrg
1301672b676d7Smrg    }
1301772b676d7Smrg
1301872b676d7Smrg    /* Determine if the Panel Link scaler is active */
1301972b676d7Smrg
1302072b676d7Smrg    if(pSiS->VBFlags & (CRT2_LCD | CRT1_LCDA)) {
1302172b676d7Smrg       ULong tmpflags = 0;
1302272b676d7Smrg       if(pSiS->VGAEngine == SIS_300_VGA) {
1302372b676d7Smrg	  if(pSiS->VBFlags2 & (VB2_LVDS | VB2_30xBDH)) {
1302472b676d7Smrg	     inSISIDXREG(SISPART1,0x1e,tmpreg);
1302572b676d7Smrg	     tmpreg &= 0x3f;
1302672b676d7Smrg	     if(tmpreg) tmpflags |= MISC_PANELLINKSCALER;
1302772b676d7Smrg	  }
1302872b676d7Smrg       } else {
1302972b676d7Smrg	  if((pSiS->VBFlags2 & (VB2_LVDS | VB2_30xBDH)) || (pSiS->VBFlags & CRT1_LCDA)) {
1303072b676d7Smrg	     inSISIDXREG(SISPART1,0x35,tmpreg);
1303172b676d7Smrg	     tmpreg &= 0x04;
1303272b676d7Smrg	     if(!tmpreg)  tmpflags |= MISC_PANELLINKSCALER;
1303372b676d7Smrg	  }
1303472b676d7Smrg       }
1303572b676d7Smrg       pSiS->MiscFlags |= tmpflags;
1303672b676d7Smrg#ifdef SISDUALHEAD
1303772b676d7Smrg       SiS_SetDHFlags(pSiS, tmpflags, 0);
1303872b676d7Smrg#endif
1303972b676d7Smrg    }
1304072b676d7Smrg
1304172b676d7Smrg    /* Determine if STN is active */
1304272b676d7Smrg    if(pSiS->ChipType == SIS_550) {
1304372b676d7Smrg       if((pSiS->VBFlags & CRT2_LCD) && (pSiS->FSTN || pSiS->DSTN)) {
1304472b676d7Smrg	  inSISIDXREG(SISCR,0x34,tmpreg);
1304572b676d7Smrg	  tmpreg &= 0x7f;
1304672b676d7Smrg	  if(tmpreg == 0x5a || tmpreg == 0x5b) {
1304772b676d7Smrg	     pSiS->MiscFlags |= MISC_STNMODE;
1304872b676d7Smrg#ifdef SISDUALHEAD
1304972b676d7Smrg	     SiS_SetDHFlags(pSiS, MISC_STNMODE, 0);
1305072b676d7Smrg#endif
1305172b676d7Smrg	  }
1305272b676d7Smrg       }
1305372b676d7Smrg    }
1305472b676d7Smrg
1305572b676d7Smrg    /* Determine if our very special TV mode is active */
1305672b676d7Smrg    if((pSiS->VBFlags2 & VB2_SISBRIDGE) && (pSiS->VBFlags & CRT2_TV) && (!(pSiS->VBFlags & TV_HIVISION))) {
1305772b676d7Smrg       if( ((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR525I)) ||
1305872b676d7Smrg	   ((!(pSiS->VBFlags & TV_YPBPR)) && (pSiS->VBFlags & (TV_NTSC | TV_PALM))) ) {
1305972b676d7Smrg	  inSISIDXREG(SISCR,0x34,tmpreg);
1306072b676d7Smrg	  tmpreg &= 0x7f;
1306172b676d7Smrg	  if((tmpreg == 0x64) || (tmpreg == 0x4a) || (tmpreg == 0x38)) {
1306272b676d7Smrg	     pSiS->MiscFlags |= MISC_TVNTSC1024;
1306372b676d7Smrg#ifdef SISDUALHEAD
1306472b676d7Smrg	     SiS_SetDHFlags(pSiS, MISC_TVNTSC1024, 0);
1306572b676d7Smrg#endif
1306672b676d7Smrg	  }
1306772b676d7Smrg       }
1306872b676d7Smrg    }
1306972b676d7Smrg
1307072b676d7Smrg    if(pSiS->VGAEngine == SIS_315_VGA) {
1307172b676d7Smrg       int i;
1307272b676d7Smrg#ifdef SISVRAMQ
1307372b676d7Smrg       /* Re-Enable and reset command queue */
1307472b676d7Smrg       SiSEnableTurboQueue(pScrn);
1307572b676d7Smrg#endif
1307672b676d7Smrg       /* Get HWCursor register contents for backup */
1307772b676d7Smrg       for(i = 0; i < 16; i++) {
1307872b676d7Smrg          pSiS->HWCursorBackup[i] = SIS_MMIO_IN32(pSiS->IOBase, 0x8500 + (i << 2));
1307972b676d7Smrg       }
1308072b676d7Smrg       if(pSiS->ChipType >= SIS_330) {
1308172b676d7Smrg          /* Enable HWCursor protection (Y pos as trigger) */
1308272b676d7Smrg          andSISIDXREG(SISCR, 0x5b, ~0x30);
1308372b676d7Smrg       }
1308472b676d7Smrg    }
1308572b676d7Smrg
1308672b676d7Smrg    /* Re-initialize accelerator engine */
1308772b676d7Smrg    /* (We are sync'ed here) */
1308872b676d7Smrg    if(!pSiS->NoAccel) {
1308972b676d7Smrg       if(pSiS->InitAccel) {
1309072b676d7Smrg          (pSiS->InitAccel)(pScrn);
1309172b676d7Smrg       }
1309272b676d7Smrg    }
1309372b676d7Smrg
1309472b676d7Smrg    /* Set display device gamma (for SISCTRL) */
1309572b676d7Smrg    if(pSiS->VBFlags & CRT1_LCDA)
1309672b676d7Smrg       pSiS->CRT1MonGamma = pSiS->CRT2LCDMonitorGamma;
1309772b676d7Smrg    else
1309872b676d7Smrg       pSiS->CRT1MonGamma = pSiS->CRT1VGAMonitorGamma;
1309972b676d7Smrg
1310072b676d7Smrg    if(pSiS->VBFlags & CRT2_LCD)
1310172b676d7Smrg       pSiS->CRT2MonGamma = pSiS->CRT2LCDMonitorGamma;
1310272b676d7Smrg    else if(pSiS->VBFlags & CRT2_TV) {
1310372b676d7Smrg       if(pSiS->VBFlags & TV_YPBPR)
1310472b676d7Smrg          pSiS->CRT2MonGamma = 2200; /* */
1310572b676d7Smrg       else if(pSiS->VBFlags & TV_HIVISION)
1310672b676d7Smrg          pSiS->CRT2MonGamma = 2200; /* ? */
1310772b676d7Smrg       else if(pSiS->VBFlags & TV_NTSC)
1310872b676d7Smrg          pSiS->CRT2MonGamma = 2200; /* NTSC */
1310972b676d7Smrg       else
1311072b676d7Smrg          pSiS->CRT2MonGamma = 2800; /* All PAL modes? */
1311172b676d7Smrg    } else if(pSiS->VBFlags & CRT2_VGA)
1311272b676d7Smrg       pSiS->CRT2MonGamma = pSiS->CRT2VGAMonitorGamma;
1311372b676d7Smrg    else
1311472b676d7Smrg       pSiS->CRT2MonGamma = 0; /* Unknown */
1311572b676d7Smrg
1311672b676d7Smrg    /* Reset XV display properties (such as number of overlays, etc) */
1311772b676d7Smrg    /* (And copy monitor gamma) */
1311872b676d7Smrg#ifdef SISDUALHEAD
1311972b676d7Smrg    if(pSiS->DualHeadMode) {
1312072b676d7Smrg       if(pSiSEnt->pScrn_1) {
1312172b676d7Smrg	  if(SISPTR(pSiSEnt->pScrn_1)->ResetXvDisplay) {
1312272b676d7Smrg	     (SISPTR(pSiSEnt->pScrn_1)->ResetXvDisplay)(pSiSEnt->pScrn_1);
1312372b676d7Smrg	  }
1312472b676d7Smrg	  SISPTR(pSiSEnt->pScrn_1)->CRT1MonGamma = pSiS->CRT1MonGamma;
1312572b676d7Smrg	  SISPTR(pSiSEnt->pScrn_1)->CRT2MonGamma = pSiS->CRT2MonGamma;
1312672b676d7Smrg       }
1312772b676d7Smrg       if(pSiSEnt->pScrn_2) {
1312872b676d7Smrg	  if(SISPTR(pSiSEnt->pScrn_2)->ResetXvDisplay) {
1312972b676d7Smrg	     (SISPTR(pSiSEnt->pScrn_1)->ResetXvDisplay)(pSiSEnt->pScrn_2);
1313072b676d7Smrg	  }
1313172b676d7Smrg	  SISPTR(pSiSEnt->pScrn_2)->CRT1MonGamma = pSiS->CRT1MonGamma;
1313272b676d7Smrg	  SISPTR(pSiSEnt->pScrn_2)->CRT2MonGamma = pSiS->CRT2MonGamma;
1313372b676d7Smrg       }
1313472b676d7Smrg    } else {
1313572b676d7Smrg#endif
1313672b676d7Smrg       if(pSiS->ResetXvDisplay) {
1313772b676d7Smrg	  (pSiS->ResetXvDisplay)(pScrn);
1313872b676d7Smrg       }
1313972b676d7Smrg#ifdef SISDUALHEAD
1314072b676d7Smrg    }
1314172b676d7Smrg#endif
1314272b676d7Smrg
1314372b676d7Smrg    /* Reset XV gamma correction */
1314472b676d7Smrg    if(pSiS->ResetXvGamma) {
1314572b676d7Smrg       (pSiS->ResetXvGamma)(pScrn);
1314672b676d7Smrg    }
1314772b676d7Smrg
1314872b676d7Smrg    /* Reset various display parameters */
1314972b676d7Smrg    {
1315072b676d7Smrg       int val = pSiS->siscrt1satgain;
1315172b676d7Smrg#ifdef SISDUALHEAD
1315272b676d7Smrg       if(pSiS->DualHeadMode && pSiSEnt) val = pSiSEnt->siscrt1satgain;
1315372b676d7Smrg#endif
1315472b676d7Smrg       SiS_SetSISCRT1SaturationGain(pScrn, val);
1315572b676d7Smrg    }
1315672b676d7Smrg
1315772b676d7Smrg    /*  Apply TV settings given by options
1315872b676d7Smrg           Do this even in DualHeadMode:
1315972b676d7Smrg	   - if this is called by SetModeCRT1, CRT2 mode has been reset by SetModeCRT1
1316072b676d7Smrg	   - if this is called by SetModeCRT2, CRT2 mode has changed (duh!)
1316172b676d7Smrg	   -> Hence, in both cases, the settings must be re-applied.
1316272b676d7Smrg     */
1316372b676d7Smrg
1316472b676d7Smrg    if(pSiS->VBFlags & CRT2_TV) {
1316572b676d7Smrg       int val;
1316672b676d7Smrg       if(pSiS->VBFlags2 & VB2_CHRONTEL) {
1316772b676d7Smrg	  int mychtvlumabandwidthcvbs = pSiS->chtvlumabandwidthcvbs;
1316872b676d7Smrg	  int mychtvlumabandwidthsvideo = pSiS->chtvlumabandwidthsvideo;
1316972b676d7Smrg	  int mychtvlumaflickerfilter = pSiS->chtvlumaflickerfilter;
1317072b676d7Smrg	  int mychtvchromabandwidth = pSiS->chtvchromabandwidth;
1317172b676d7Smrg	  int mychtvchromaflickerfilter = pSiS->chtvchromaflickerfilter;
1317272b676d7Smrg	  int mychtvcvbscolor = pSiS->chtvcvbscolor;
1317372b676d7Smrg	  int mychtvtextenhance = pSiS->chtvtextenhance;
1317472b676d7Smrg	  int mychtvcontrast = pSiS->chtvcontrast;
1317572b676d7Smrg	  int mytvxpos = pSiS->tvxpos;
1317672b676d7Smrg	  int mytvypos = pSiS->tvypos;
1317772b676d7Smrg#ifdef SISDUALHEAD
1317872b676d7Smrg	  if(pSiSEnt && pSiS->DualHeadMode) {
1317972b676d7Smrg	     mychtvlumabandwidthcvbs = pSiSEnt->chtvlumabandwidthcvbs;
1318072b676d7Smrg	     mychtvlumabandwidthsvideo = pSiSEnt->chtvlumabandwidthsvideo;
1318172b676d7Smrg	     mychtvlumaflickerfilter = pSiSEnt->chtvlumaflickerfilter;
1318272b676d7Smrg	     mychtvchromabandwidth = pSiSEnt->chtvchromabandwidth;
1318372b676d7Smrg	     mychtvchromaflickerfilter = pSiSEnt->chtvchromaflickerfilter;
1318472b676d7Smrg	     mychtvcvbscolor = pSiSEnt->chtvcvbscolor;
1318572b676d7Smrg	     mychtvtextenhance = pSiSEnt->chtvtextenhance;
1318672b676d7Smrg	     mychtvcontrast = pSiSEnt->chtvcontrast;
1318772b676d7Smrg	     mytvxpos = pSiSEnt->tvxpos;
1318872b676d7Smrg	     mytvypos = pSiSEnt->tvypos;
1318972b676d7Smrg	  }
1319072b676d7Smrg#endif
1319172b676d7Smrg	  if((val = mychtvlumabandwidthcvbs) != -1) {
1319272b676d7Smrg	     SiS_SetCHTVlumabandwidthcvbs(pScrn, val);
1319372b676d7Smrg	  }
1319472b676d7Smrg	  if((val = mychtvlumabandwidthsvideo) != -1) {
1319572b676d7Smrg	     SiS_SetCHTVlumabandwidthsvideo(pScrn, val);
1319672b676d7Smrg	  }
1319772b676d7Smrg	  if((val = mychtvlumaflickerfilter) != -1) {
1319872b676d7Smrg	     SiS_SetCHTVlumaflickerfilter(pScrn, val);
1319972b676d7Smrg	  }
1320072b676d7Smrg	  if((val = mychtvchromabandwidth) != -1) {
1320172b676d7Smrg	     SiS_SetCHTVchromabandwidth(pScrn, val);
1320272b676d7Smrg	  }
1320372b676d7Smrg	  if((val = mychtvchromaflickerfilter) != -1) {
1320472b676d7Smrg	     SiS_SetCHTVchromaflickerfilter(pScrn, val);
1320572b676d7Smrg	  }
1320672b676d7Smrg	  if((val = mychtvcvbscolor) != -1) {
1320772b676d7Smrg	     SiS_SetCHTVcvbscolor(pScrn, val);
1320872b676d7Smrg	  }
1320972b676d7Smrg	  if((val = mychtvtextenhance) != -1) {
1321072b676d7Smrg	     SiS_SetCHTVtextenhance(pScrn, val);
1321172b676d7Smrg	  }
1321272b676d7Smrg	  if((val = mychtvcontrast) != -1) {
1321372b676d7Smrg	     SiS_SetCHTVcontrast(pScrn, val);
1321472b676d7Smrg	  }
1321572b676d7Smrg	  /* Backup default TV position registers */
1321672b676d7Smrg	  switch(pSiS->ChrontelType) {
1321772b676d7Smrg	  case CHRONTEL_700x:
1321872b676d7Smrg	     pSiS->tvx = SiS_GetCH700x(pSiS->SiS_Pr, 0x0a);
1321972b676d7Smrg	     pSiS->tvx |= (((SiS_GetCH700x(pSiS->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
1322072b676d7Smrg	     pSiS->tvy = SiS_GetCH700x(pSiS->SiS_Pr, 0x0b);
1322172b676d7Smrg	     pSiS->tvy |= ((SiS_GetCH700x(pSiS->SiS_Pr, 0x08) & 0x01) << 8);
1322272b676d7Smrg#ifdef SISDUALHEAD
1322372b676d7Smrg	     if(pSiSEnt) {
1322472b676d7Smrg		pSiSEnt->tvx = pSiS->tvx;
1322572b676d7Smrg		pSiSEnt->tvy = pSiS->tvy;
1322672b676d7Smrg	     }
1322772b676d7Smrg#endif
1322872b676d7Smrg	     break;
1322972b676d7Smrg	  case CHRONTEL_701x:
1323072b676d7Smrg	     /* Not supported by hardware */
1323172b676d7Smrg	     break;
1323272b676d7Smrg	  }
1323372b676d7Smrg	  if((val = mytvxpos) != 0) {
1323472b676d7Smrg	     SiS_SetTVxposoffset(pScrn, val);
1323572b676d7Smrg	  }
1323672b676d7Smrg	  if((val = mytvypos) != 0) {
1323772b676d7Smrg	     SiS_SetTVyposoffset(pScrn, val);
1323872b676d7Smrg	  }
1323972b676d7Smrg       }
1324072b676d7Smrg       if(pSiS->VBFlags2 & VB2_301) {
1324172b676d7Smrg          int mysistvedgeenhance = pSiS->sistvedgeenhance;
1324272b676d7Smrg#ifdef SISDUALHEAD
1324372b676d7Smrg          if(pSiSEnt && pSiS->DualHeadMode) {
1324472b676d7Smrg	     mysistvedgeenhance = pSiSEnt->sistvedgeenhance;
1324572b676d7Smrg	  }
1324672b676d7Smrg#endif
1324772b676d7Smrg          if((val = mysistvedgeenhance) != -1) {
1324872b676d7Smrg	     SiS_SetSISTVedgeenhance(pScrn, val);
1324972b676d7Smrg	  }
1325072b676d7Smrg       }
1325172b676d7Smrg       if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
1325272b676d7Smrg          int mysistvantiflicker = pSiS->sistvantiflicker;
1325372b676d7Smrg	  int mysistvsaturation = pSiS->sistvsaturation;
1325472b676d7Smrg	  int mysistvcolcalibf = pSiS->sistvcolcalibf;
1325572b676d7Smrg	  int mysistvcolcalibc = pSiS->sistvcolcalibc;
1325672b676d7Smrg	  int mysistvcfilter = pSiS->sistvcfilter;
1325772b676d7Smrg	  int mysistvyfilter = pSiS->sistvyfilter;
1325872b676d7Smrg	  int mytvxpos = pSiS->tvxpos;
1325972b676d7Smrg	  int mytvypos = pSiS->tvypos;
1326072b676d7Smrg	  int mytvxscale = pSiS->tvxscale;
1326172b676d7Smrg	  int mytvyscale = pSiS->tvyscale;
1326272b676d7Smrg	  int i;
1326372b676d7Smrg	  ULong cbase;
1326472b676d7Smrg	  UChar ctemp;
1326572b676d7Smrg#ifdef SISDUALHEAD
1326672b676d7Smrg          if(pSiSEnt && pSiS->DualHeadMode) {
1326772b676d7Smrg	     mysistvantiflicker = pSiSEnt->sistvantiflicker;
1326872b676d7Smrg	     mysistvsaturation = pSiSEnt->sistvsaturation;
1326972b676d7Smrg	     mysistvcolcalibf = pSiSEnt->sistvcolcalibf;
1327072b676d7Smrg	     mysistvcolcalibc = pSiSEnt->sistvcolcalibc;
1327172b676d7Smrg	     mysistvcfilter = pSiSEnt->sistvcfilter;
1327272b676d7Smrg	     mysistvyfilter = pSiSEnt->sistvyfilter;
1327372b676d7Smrg	     mytvxpos = pSiSEnt->tvxpos;
1327472b676d7Smrg	     mytvypos = pSiSEnt->tvypos;
1327572b676d7Smrg	     mytvxscale = pSiSEnt->tvxscale;
1327672b676d7Smrg	     mytvyscale = pSiSEnt->tvyscale;
1327772b676d7Smrg	  }
1327872b676d7Smrg#endif
1327972b676d7Smrg          /* Backup default TV position, scale and colcalib registers */
1328072b676d7Smrg	  inSISIDXREG(SISPART2,0x1f,pSiS->p2_1f);
1328172b676d7Smrg	  inSISIDXREG(SISPART2,0x20,pSiS->p2_20);
1328272b676d7Smrg	  inSISIDXREG(SISPART2,0x2b,pSiS->p2_2b);
1328372b676d7Smrg	  inSISIDXREG(SISPART2,0x42,pSiS->p2_42);
1328472b676d7Smrg	  inSISIDXREG(SISPART2,0x43,pSiS->p2_43);
1328572b676d7Smrg	  inSISIDXREG(SISPART2,0x01,pSiS->p2_01);
1328672b676d7Smrg	  inSISIDXREG(SISPART2,0x02,pSiS->p2_02);
1328772b676d7Smrg	  inSISIDXREG(SISPART2,0x44,pSiS->p2_44);
1328872b676d7Smrg	  inSISIDXREG(SISPART2,0x45,pSiS->p2_45);
1328972b676d7Smrg	  if(!(pSiS->VBFlags2 & VB2_301)) {
1329072b676d7Smrg	     inSISIDXREG(SISPART2,0x46,pSiS->p2_46);
1329172b676d7Smrg	  } else {
1329272b676d7Smrg	     pSiS->p2_46 = 0;
1329372b676d7Smrg	  }
1329472b676d7Smrg	  inSISIDXREG(SISPART2,0x0a,pSiS->p2_0a);
1329572b676d7Smrg	  inSISIDXREG(SISPART2,0x31,cbase);
1329672b676d7Smrg	  cbase = (cbase & 0x7f) << 8;
1329772b676d7Smrg	  inSISIDXREG(SISPART2,0x32,ctemp);
1329872b676d7Smrg	  cbase = (cbase | ctemp) << 8;
1329972b676d7Smrg	  inSISIDXREG(SISPART2,0x33,ctemp);
1330072b676d7Smrg	  cbase = (cbase | ctemp) << 8;
1330172b676d7Smrg	  inSISIDXREG(SISPART2,0x34,ctemp);
1330272b676d7Smrg	  pSiS->sistvccbase = (cbase | ctemp);
1330372b676d7Smrg	  inSISIDXREG(SISPART2,0x35,pSiS->p2_35);
1330472b676d7Smrg	  inSISIDXREG(SISPART2,0x36,pSiS->p2_36);
1330572b676d7Smrg	  inSISIDXREG(SISPART2,0x37,pSiS->p2_37);
1330672b676d7Smrg	  inSISIDXREG(SISPART2,0x38,pSiS->p2_38);
1330772b676d7Smrg	  if(!(pSiS->VBFlags2 & VB2_301)) {
1330872b676d7Smrg	     inSISIDXREG(SISPART2,0x47,pSiS->p2_47);
1330972b676d7Smrg	     inSISIDXREG(SISPART2,0x48,pSiS->p2_48);
1331072b676d7Smrg	     inSISIDXREG(SISPART2,0x49,pSiS->p2_49);
1331172b676d7Smrg	     inSISIDXREG(SISPART2,0x4a,pSiS->p2_4a);
1331272b676d7Smrg	  }
1331372b676d7Smrg	  inSISIDXREG(SISPART2,0x2f,pSiS->p2_2f);
1331472b676d7Smrg	  inSISIDXREG(SISPART2,0x30,pSiS->p2_30);
1331572b676d7Smrg	  for(i=0; i<9; i++) {
1331672b676d7Smrg	     inSISIDXREG(SISPART1,SiSScalingP1Regs[i],pSiS->scalingp1[i]);
1331772b676d7Smrg	  }
1331872b676d7Smrg	  for(i=0; i<9; i++) {
1331972b676d7Smrg	     inSISIDXREG(SISPART4,SiSScalingP4Regs[i],pSiS->scalingp4[i]);
1332072b676d7Smrg	  }
1332172b676d7Smrg	  if(pSiS->VBFlags2 & VB2_SISTAP4SCALER) {
1332272b676d7Smrg	     for(i=0; i<64; i++) {
1332372b676d7Smrg	        inSISIDXREG(SISPART2,(0xc0 + i),pSiS->scalingp2[i]);
1332472b676d7Smrg  	     }
1332572b676d7Smrg	  }
1332672b676d7Smrg#ifdef SISDUALHEAD
1332772b676d7Smrg	  if(pSiSEnt) {
1332872b676d7Smrg	     pSiSEnt->p2_1f = pSiS->p2_1f; pSiSEnt->p2_20 = pSiS->p2_20;
1332972b676d7Smrg	     pSiSEnt->p2_42 = pSiS->p2_42; pSiSEnt->p2_43 = pSiS->p2_43;
1333072b676d7Smrg	     pSiSEnt->p2_2b = pSiS->p2_2b;
1333172b676d7Smrg	     pSiSEnt->p2_01 = pSiS->p2_01; pSiSEnt->p2_02 = pSiS->p2_02;
1333272b676d7Smrg	     pSiSEnt->p2_44 = pSiS->p2_44; pSiSEnt->p2_45 = pSiS->p2_45;
1333372b676d7Smrg	     pSiSEnt->p2_46 = pSiS->p2_46; pSiSEnt->p2_0a = pSiS->p2_0a;
1333472b676d7Smrg	     pSiSEnt->sistvccbase = pSiS->sistvccbase;
1333572b676d7Smrg	     pSiSEnt->p2_35 = pSiS->p2_35; pSiSEnt->p2_36 = pSiS->p2_36;
1333672b676d7Smrg	     pSiSEnt->p2_37 = pSiS->p2_37; pSiSEnt->p2_38 = pSiS->p2_38;
1333772b676d7Smrg	     pSiSEnt->p2_48 = pSiS->p2_48; pSiSEnt->p2_49 = pSiS->p2_49;
1333872b676d7Smrg	     pSiSEnt->p2_4a = pSiS->p2_4a; pSiSEnt->p2_2f = pSiS->p2_2f;
1333972b676d7Smrg	     pSiSEnt->p2_30 = pSiS->p2_30; pSiSEnt->p2_47 = pSiS->p2_47;
1334072b676d7Smrg	     for(i=0; i<9; i++) {
1334172b676d7Smrg	        pSiSEnt->scalingp1[i] = pSiS->scalingp1[i];
1334272b676d7Smrg	     }
1334372b676d7Smrg	     for(i=0; i<9; i++) {
1334472b676d7Smrg	        pSiSEnt->scalingp4[i] = pSiS->scalingp4[i];
1334572b676d7Smrg	     }
1334672b676d7Smrg	     if(pSiS->VBFlags2 & VB2_SISTAP4SCALER) {
1334772b676d7Smrg	        for(i=0; i<64; i++) {
1334872b676d7Smrg	           pSiSEnt->scalingp2[i] = pSiS->scalingp2[i];
1334972b676d7Smrg  	        }
1335072b676d7Smrg	     }
1335172b676d7Smrg	  }
1335272b676d7Smrg#endif
1335372b676d7Smrg          if((val = mysistvantiflicker) != -1) {
1335472b676d7Smrg	     SiS_SetSISTVantiflicker(pScrn, val);
1335572b676d7Smrg	  }
1335672b676d7Smrg	  if((val = mysistvsaturation) != -1) {
1335772b676d7Smrg	     SiS_SetSISTVsaturation(pScrn, val);
1335872b676d7Smrg	  }
1335972b676d7Smrg	  if((val = mysistvcfilter) != -1) {
1336072b676d7Smrg	     SiS_SetSISTVcfilter(pScrn, val);
1336172b676d7Smrg	  }
1336272b676d7Smrg	  if((val = mysistvyfilter) != 1) {
1336372b676d7Smrg	     SiS_SetSISTVyfilter(pScrn, val);
1336472b676d7Smrg	  }
1336572b676d7Smrg	  if((val = mysistvcolcalibc) != 0) {
1336672b676d7Smrg	     SiS_SetSISTVcolcalib(pScrn, val, TRUE);
1336772b676d7Smrg	  }
1336872b676d7Smrg	  if((val = mysistvcolcalibf) != 0) {
1336972b676d7Smrg	     SiS_SetSISTVcolcalib(pScrn, val, FALSE);
1337072b676d7Smrg	  }
1337172b676d7Smrg	  if((val = mytvxpos) != 0) {
1337272b676d7Smrg	     SiS_SetTVxposoffset(pScrn, val);
1337372b676d7Smrg	  }
1337472b676d7Smrg	  if((val = mytvypos) != 0) {
1337572b676d7Smrg	     SiS_SetTVyposoffset(pScrn, val);
1337672b676d7Smrg	  }
1337772b676d7Smrg	  if((val = mytvxscale) != 0) {
1337872b676d7Smrg	     SiS_SetTVxscale(pScrn, val);
1337972b676d7Smrg	  }
1338072b676d7Smrg	  if((val = mytvyscale) != 0) {
1338172b676d7Smrg	     SiS_SetTVyscale(pScrn, val);
1338272b676d7Smrg	  }
1338372b676d7Smrg       }
1338472b676d7Smrg    }
1338572b676d7Smrg
1338672b676d7Smrg}
1338772b676d7Smrg
1338872b676d7Smrg/* Post-set SiS6326 TV registers */
1338972b676d7Smrgstatic void
1339072b676d7SmrgSiS6326PostSetMode(ScrnInfoPtr pScrn, SISRegPtr sisReg)
1339172b676d7Smrg{
1339272b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
1339372b676d7Smrg    UChar tmp;
1339472b676d7Smrg    int val;
1339572b676d7Smrg
1339672b676d7Smrg    if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) return;
1339772b676d7Smrg
1339872b676d7Smrg#ifdef UNLOCK_ALWAYS
1339972b676d7Smrg    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
1340072b676d7Smrg#endif
1340172b676d7Smrg
1340272b676d7Smrg    /* Backup default TV position registers */
1340372b676d7Smrg    pSiS->tvx1 = SiS6326GetTVReg(pScrn,0x3a);
1340472b676d7Smrg    pSiS->tvx1 |= ((SiS6326GetTVReg(pScrn,0x3c) & 0x0f) << 8);
1340572b676d7Smrg    pSiS->tvx2 = SiS6326GetTVReg(pScrn,0x26);
1340672b676d7Smrg    pSiS->tvx2 |= ((SiS6326GetTVReg(pScrn,0x27) & 0xf0) << 4);
1340772b676d7Smrg    pSiS->tvx3 = SiS6326GetTVReg(pScrn,0x12);
1340872b676d7Smrg    pSiS->tvx3 |= ((SiS6326GetTVReg(pScrn,0x13) & 0xC0) << 2);
1340972b676d7Smrg    pSiS->tvy1 = SiS6326GetTVReg(pScrn,0x11);
1341072b676d7Smrg    pSiS->tvy1 |= ((SiS6326GetTVReg(pScrn,0x13) & 0x30) << 4);
1341172b676d7Smrg
1341272b676d7Smrg    /* Handle TVPosOffset options (BEFORE switching on TV) */
1341372b676d7Smrg    if((val = pSiS->tvxpos) != 0) {
1341472b676d7Smrg       SiS_SetTVxposoffset(pScrn, val);
1341572b676d7Smrg    }
1341672b676d7Smrg    if((val = pSiS->tvypos) != 0) {
1341772b676d7Smrg       SiS_SetTVyposoffset(pScrn, val);
1341872b676d7Smrg    }
1341972b676d7Smrg
1342072b676d7Smrg    /* Switch on TV output. This is rather complicated, but
1342172b676d7Smrg     * if we don't do it, TV output will flicker terribly.
1342272b676d7Smrg     */
1342372b676d7Smrg    if(pSiS->SiS6326Flags & SIS6326_TVON) {
1342472b676d7Smrg       orSISIDXREG(SISSR, 0x01, 0x20);
1342572b676d7Smrg       tmp = SiS6326GetTVReg(pScrn,0x00);
1342672b676d7Smrg       tmp &= ~0x04;
1342772b676d7Smrg       while(!(inSISREG(SISINPSTAT) & 0x08));    /* Wait while NOT vb */
1342872b676d7Smrg       SiS6326SetTVReg(pScrn,0x00,tmp);
1342972b676d7Smrg       for(val=0; val < 2; val++) {
1343072b676d7Smrg         while(!(inSISREG(SISINPSTAT) & 0x08));  /* Wait while NOT vb */
1343172b676d7Smrg         while(inSISREG(SISINPSTAT) & 0x08);     /* wait while vb     */
1343272b676d7Smrg       }
1343372b676d7Smrg       SiS6326SetTVReg(pScrn, 0x00, sisReg->sis6326tv[0]);
1343472b676d7Smrg       tmp = inSISREG(SISINPSTAT);
1343572b676d7Smrg       outSISREG(SISAR, 0x20);
1343672b676d7Smrg       tmp = inSISREG(SISINPSTAT);
1343772b676d7Smrg       while(inSISREG(SISINPSTAT) & 0x01);
1343872b676d7Smrg       while(!(inSISREG(SISINPSTAT) & 0x01));
1343972b676d7Smrg       andSISIDXREG(SISSR, 0x01, ~0x20);
1344072b676d7Smrg       for(val=0; val < 10; val++) {
1344172b676d7Smrg         while(!(inSISREG(SISINPSTAT) & 0x08));  /* Wait while NOT vb */
1344272b676d7Smrg         while(inSISREG(SISINPSTAT) & 0x08);     /* wait while vb     */
1344372b676d7Smrg       }
1344472b676d7Smrg       andSISIDXREG(SISSR, 0x01, ~0x20);
1344572b676d7Smrg    }
1344672b676d7Smrg
1344772b676d7Smrg    tmp = SiS6326GetTVReg(pScrn,0x00);
1344872b676d7Smrg    if(!(tmp & 0x04)) return;
1344972b676d7Smrg
1345072b676d7Smrg    /* Apply TV settings given by options */
1345172b676d7Smrg    if((val = pSiS->sistvantiflicker) != -1) {
1345272b676d7Smrg       SiS_SetSIS6326TVantiflicker(pScrn, val);
1345372b676d7Smrg    }
1345472b676d7Smrg    if((val = pSiS->sis6326enableyfilter) != -1) {
1345572b676d7Smrg       SiS_SetSIS6326TVenableyfilter(pScrn, val);
1345672b676d7Smrg    }
1345772b676d7Smrg    if((val = pSiS->sis6326yfilterstrong) != -1) {
1345872b676d7Smrg       SiS_SetSIS6326TVyfilterstrong(pScrn, val);
1345972b676d7Smrg    }
1346072b676d7Smrg
1346172b676d7Smrg}
1346272b676d7Smrg
1346372b676d7Smrg/* Check if video bridge is in slave mode */
1346472b676d7SmrgBool
1346572b676d7SmrgSiSBridgeIsInSlaveMode(ScrnInfoPtr pScrn)
1346672b676d7Smrg{
1346772b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
1346872b676d7Smrg    UChar  usScrP1_00;
1346972b676d7Smrg
1347072b676d7Smrg    if(!(pSiS->VBFlags2 & VB2_VIDEOBRIDGE)) return FALSE;
1347172b676d7Smrg
1347272b676d7Smrg    inSISIDXREG(SISPART1,0x00,usScrP1_00);
1347372b676d7Smrg    if( ((pSiS->VGAEngine == SIS_300_VGA) && (usScrP1_00 & 0xa0) == 0x20) ||
1347472b676d7Smrg        ((pSiS->VGAEngine == SIS_315_VGA) && (usScrP1_00 & 0x50) == 0x10) ) {
1347572b676d7Smrg       return TRUE;
1347672b676d7Smrg    }
1347772b676d7Smrg
1347872b676d7Smrg    return FALSE;
1347972b676d7Smrg}
1348072b676d7Smrg
1348172b676d7Smrg/* Build a list of the VESA modes the BIOS reports as valid */
1348272b676d7Smrgstatic void
1348372b676d7SmrgSiSBuildVesaModeList(ScrnInfoPtr pScrn, vbeInfoPtr pVbe, VbeInfoBlock *vbe)
1348472b676d7Smrg{
1348572b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
1348672b676d7Smrg    int i = 0;
1348772b676d7Smrg
1348872b676d7Smrg    while(vbe->VideoModePtr[i] != 0xffff) {
1348972b676d7Smrg       sisModeInfoPtr m;
1349072b676d7Smrg       VbeModeInfoBlock *mode;
1349172b676d7Smrg       int id = vbe->VideoModePtr[i++];
1349272b676d7Smrg
1349372b676d7Smrg       if((mode = VBEGetModeInfo(pVbe, id)) == NULL) {
1349472b676d7Smrg	  continue;
1349572b676d7Smrg       }
1349672b676d7Smrg
1349772b676d7Smrg       m = xnfcalloc(sizeof(sisModeInfoRec), 1);
1349872b676d7Smrg       if(!m) {
1349972b676d7Smrg	  VBEFreeModeInfo(mode);
1350072b676d7Smrg	  continue;
1350172b676d7Smrg       }
1350272b676d7Smrg       m->width = mode->XResolution;
1350372b676d7Smrg       m->height = mode->YResolution;
1350472b676d7Smrg       m->bpp = mode->BitsPerPixel;
1350572b676d7Smrg       m->n = id;
1350672b676d7Smrg       m->next = pSiS->SISVESAModeList;
1350772b676d7Smrg
1350872b676d7Smrg       pSiS->SISVESAModeList = m;
1350972b676d7Smrg
1351072b676d7Smrg       VBEFreeModeInfo(mode);
1351172b676d7Smrg
1351272b676d7Smrg       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1351372b676d7Smrg	   "VESA BIOS supports mode number 0x%x: %ix%i (%i bpp)\n",
1351472b676d7Smrg	   m->n, m->width, m->height, m->bpp);
1351572b676d7Smrg    }
1351672b676d7Smrg}
1351772b676d7Smrg
1351872b676d7Smrg/* Get VESA mode number from given resolution/depth */
1351972b676d7Smrgstatic UShort
1352072b676d7SmrgSiSCalcVESAModeIndex(ScrnInfoPtr pScrn, DisplayModePtr mode)
1352172b676d7Smrg{
1352272b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
1352372b676d7Smrg    sisModeInfoPtr m = pSiS->SISVESAModeList;
1352472b676d7Smrg    UShort i = (pScrn->bitsPerPixel+7)/8 - 1;
1352572b676d7Smrg    UShort ModeNumber = 0;
1352672b676d7Smrg    int j;
1352772b676d7Smrg
1352872b676d7Smrg    while(m) {
1352972b676d7Smrg       if( (pScrn->bitsPerPixel == m->bpp) &&
1353072b676d7Smrg	   (mode->HDisplay == m->width)    &&
1353172b676d7Smrg	   (mode->VDisplay == m->height) )
1353272b676d7Smrg	  return m->n;
1353372b676d7Smrg       m = m->next;
1353472b676d7Smrg    }
1353572b676d7Smrg
1353672b676d7Smrg    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1353772b676d7Smrg        "No valid VESA BIOS mode found for %dx%d (%d bpp)\n",
1353872b676d7Smrg        mode->HDisplay, mode->VDisplay, pScrn->bitsPerPixel);
1353972b676d7Smrg
1354072b676d7Smrg    if(!pSiS->ROM661New) {  /* VESA numbers changed! */
1354172b676d7Smrg       j = 0;
1354272b676d7Smrg       while(VESAModeIndices[j] != 9999) {
1354372b676d7Smrg          if( (mode->HDisplay == VESAModeIndices[j]) &&
1354472b676d7Smrg	      (mode->VDisplay == VESAModeIndices[j+1]) ) {
1354572b676d7Smrg	     ModeNumber = VESAModeIndices[j + 2 + i];
1354672b676d7Smrg	     break;
1354772b676d7Smrg          }
1354872b676d7Smrg          j += 6;
1354972b676d7Smrg       }
1355072b676d7Smrg
1355172b676d7Smrg       if(!ModeNumber) {
1355272b676d7Smrg	  xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1355372b676d7Smrg	      "No valid mode found for %dx%dx%d in built-in table either.\n",
1355472b676d7Smrg	      mode->HDisplay, mode->VDisplay, pScrn->bitsPerPixel);
1355572b676d7Smrg       }
1355672b676d7Smrg    }
1355772b676d7Smrg
1355872b676d7Smrg    return(ModeNumber);
1355972b676d7Smrg}
1356072b676d7Smrg
1356172b676d7SmrgUShort
1356272b676d7SmrgSiS_GetModeNumber(ScrnInfoPtr pScrn, DisplayModePtr mode, unsigned int VBFlags)
1356372b676d7Smrg{
1356472b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1356572b676d7Smrg   UShort i = (pSiS->CurrentLayout.bitsPerPixel+7)/8 - 1;
1356672b676d7Smrg   BOOLEAN FSTN = pSiS->FSTN ? TRUE : FALSE;
1356772b676d7Smrg
1356872b676d7Smrg#ifdef SISDUALHEAD
1356972b676d7Smrg   if(pSiS->DualHeadMode && pSiS->SecondHead) FSTN = FALSE;
1357072b676d7Smrg#endif
1357172b676d7Smrg
1357272b676d7Smrg   return(SiS_GetModeID(pSiS->VGAEngine, VBFlags, mode->HDisplay, mode->VDisplay,
1357372b676d7Smrg			i, FSTN, pSiS->LCDwidth, pSiS->LCDheight));
1357472b676d7Smrg}
1357572b676d7Smrg
1357672b676d7Smrgstatic Bool
1357772b676d7SmrgSiSValidLCDUserMode(SISPtr pSiS, unsigned int VBFlags, DisplayModePtr mode, Bool isforlcda)
1357872b676d7Smrg{
1357972b676d7Smrg   if(mode->Flags & V_INTERLACE) return FALSE;
1358072b676d7Smrg
1358172b676d7Smrg   if(mode->HDisplay > 2048) return FALSE;
1358272b676d7Smrg   if(mode->VDisplay > 1536) return FALSE;
1358372b676d7Smrg
1358472b676d7Smrg   if(pSiS->VBFlags2 & VB2_LCD162MHZBRIDGE) {
1358572b676d7Smrg      if(mode->Clock > 162500) return FALSE;
1358672b676d7Smrg#ifdef VB_FORBID_CRT2LCD_OVER_1600
1358772b676d7Smrg      if(!isforlcda) {
1358872b676d7Smrg         if(mode->HDisplay > 1600) return FALSE;
1358972b676d7Smrg      }
1359072b676d7Smrg#endif
1359172b676d7Smrg   } else { /* 301, 301B, 302B (no LCDA!) */
1359272b676d7Smrg      if(mode->Clock > 130000)  return FALSE;
1359372b676d7Smrg      if(mode->Clock > 111000) {
1359472b676d7Smrg         xf86DrvMsg(pSiS->pScrn->scrnIndex, X_WARNING,
1359572b676d7Smrg	 	"WARNING: Mode clock beyond video bridge specs (%dMHz). Hardware damage might occure.\n",
1359672b676d7Smrg		mode->Clock / 1000);
1359772b676d7Smrg      }
1359872b676d7Smrg      if(mode->HDisplay > 1600) return FALSE;
1359972b676d7Smrg      if(mode->VDisplay > 1024) return FALSE;
1360072b676d7Smrg   }
1360172b676d7Smrg
1360272b676d7Smrg   return TRUE;
1360372b676d7Smrg}
1360472b676d7Smrg
1360572b676d7Smrgstatic Bool
1360672b676d7SmrgSiSValidVGA2UserMode(SISPtr pSiS, unsigned int VBFlags, DisplayModePtr mode)
1360772b676d7Smrg{
1360872b676d7Smrg   if(mode->Flags & V_INTERLACE) return FALSE;
1360972b676d7Smrg
1361072b676d7Smrg   if(mode->HDisplay > 2048) return FALSE;
1361172b676d7Smrg   if(mode->VDisplay > 1536) return FALSE;
1361272b676d7Smrg
1361372b676d7Smrg   if(pSiS->VBFlags2 & VB2_RAMDAC202MHZBRIDGE) {
1361472b676d7Smrg      if(mode->Clock > 203000) return FALSE;
1361572b676d7Smrg   } else if(pSiS->VBFlags2 & VB2_30xBLV) {
1361672b676d7Smrg      if(mode->Clock > 162500) return FALSE;
1361772b676d7Smrg   } else {
1361872b676d7Smrg      if(mode->Clock > 135500) return FALSE;
1361972b676d7Smrg   }
1362072b676d7Smrg
1362172b676d7Smrg   return TRUE;
1362272b676d7Smrg}
1362372b676d7Smrg
1362472b676d7SmrgUShort
1362572b676d7SmrgSiS_CheckModeCRT1(ScrnInfoPtr pScrn, DisplayModePtr mode, unsigned int VBFlags, Bool havecustommodes)
1362672b676d7Smrg{
1362772b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1362872b676d7Smrg   UShort i = (pSiS->CurrentLayout.bitsPerPixel+7)/8 - 1;
1362972b676d7Smrg   int j;
1363072b676d7Smrg
1363172b676d7Smrg   if(!(VBFlags & CRT1_LCDA)) {
1363272b676d7Smrg
1363372b676d7Smrg      if((havecustommodes) && (!(mode->type & M_T_DEFAULT))) {
1363472b676d7Smrg         return 0xfe;
1363572b676d7Smrg      }
1363672b676d7Smrg
1363772b676d7Smrg   } else if(pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE) {
1363872b676d7Smrg
1363972b676d7Smrg      if(pSiS->ChipType < SIS_661) {  /* < 661 only? */
1364072b676d7Smrg         if(!(mode->type & M_T_DEFAULT)) {
1364172b676d7Smrg            if(mode->HTotal > 2055) return 0;
1364272b676d7Smrg	    /* (Default mode will be caught in mode switching code) */
1364372b676d7Smrg	 }
1364472b676d7Smrg      }
1364572b676d7Smrg
1364672b676d7Smrg      if(pSiS->SiS_Pr->CP_HaveCustomData) {
1364772b676d7Smrg         for(j=0; j<7; j++) {
1364872b676d7Smrg            if((pSiS->SiS_Pr->CP_DataValid[j]) &&
1364972b676d7Smrg               (mode->HDisplay == pSiS->SiS_Pr->CP_HDisplay[j]) &&
1365072b676d7Smrg               (mode->VDisplay == pSiS->SiS_Pr->CP_VDisplay[j]) &&
1365172b676d7Smrg               (mode->type & M_T_BUILTIN))
1365272b676d7Smrg               return 0xfe;
1365372b676d7Smrg	 }
1365472b676d7Smrg      }
1365572b676d7Smrg
1365672b676d7Smrg      if((pSiS->AddedPlasmaModes) && (mode->type & M_T_BUILTIN))
1365772b676d7Smrg         return 0xfe;
1365872b676d7Smrg
1365972b676d7Smrg      if((havecustommodes) &&
1366072b676d7Smrg         (pSiS->LCDwidth)  &&	/* = test if LCD present */
1366172b676d7Smrg         (!(mode->type & M_T_DEFAULT)) &&
1366272b676d7Smrg	 (SiSValidLCDUserMode(pSiS, VBFlags, mode, TRUE)))
1366372b676d7Smrg         return 0xfe;
1366472b676d7Smrg
1366572b676d7Smrg      if((mode->HDisplay > pSiS->LCDwidth) ||
1366672b676d7Smrg         (mode->VDisplay > pSiS->LCDheight)) {
1366772b676d7Smrg	 return 0;
1366872b676d7Smrg      }
1366972b676d7Smrg
1367072b676d7Smrg   } else {
1367172b676d7Smrg
1367272b676d7Smrg      if((mode->HDisplay > pSiS->LCDwidth) ||
1367372b676d7Smrg         (mode->VDisplay > pSiS->LCDheight)) {
1367472b676d7Smrg	 return 0;
1367572b676d7Smrg      }
1367672b676d7Smrg
1367772b676d7Smrg   }
1367872b676d7Smrg
1367972b676d7Smrg   return(SiS_GetModeID(pSiS->VGAEngine, VBFlags, mode->HDisplay, mode->VDisplay,
1368072b676d7Smrg   			i, pSiS->FSTN, pSiS->LCDwidth, pSiS->LCDheight));
1368172b676d7Smrg}
1368272b676d7Smrg
1368372b676d7SmrgUShort
1368472b676d7SmrgSiS_CheckModeCRT2(ScrnInfoPtr pScrn, DisplayModePtr mode, unsigned int VBFlags, Bool havecustommodes)
1368572b676d7Smrg{
1368672b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1368772b676d7Smrg   UShort i = (pSiS->CurrentLayout.bitsPerPixel+7)/8 - 1;
1368872b676d7Smrg   UShort ModeIndex = 0;
1368972b676d7Smrg   int    j;
1369072b676d7Smrg
1369172b676d7Smrg#ifdef TWDEBUG
1369272b676d7Smrg   xf86DrvMsg(0, X_INFO, "Inside CheckCalcModeIndex (VBFlags %lx, mode %dx%d)\n",
1369372b676d7Smrg	VBFlags,mode->HDisplay, mode->VDisplay);
1369472b676d7Smrg#endif
1369572b676d7Smrg
1369672b676d7Smrg   if(VBFlags & CRT2_LCD) {			/* CRT2 is LCD */
1369772b676d7Smrg
1369872b676d7Smrg      if((pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) && (!(pSiS->VBFlags2 & VB2_30xBDH))) {
1369972b676d7Smrg
1370072b676d7Smrg         if(pSiS->SiS_Pr->CP_HaveCustomData) {
1370172b676d7Smrg            for(j=0; j<7; j++) {
1370272b676d7Smrg               if((pSiS->SiS_Pr->CP_DataValid[j]) &&
1370372b676d7Smrg                  (mode->HDisplay == pSiS->SiS_Pr->CP_HDisplay[j]) &&
1370472b676d7Smrg                  (mode->VDisplay == pSiS->SiS_Pr->CP_VDisplay[j]) &&
1370572b676d7Smrg#ifdef VB_FORBID_CRT2LCD_OVER_1600
1370672b676d7Smrg		  (mode->HDisplay <= 1600) 			   &&
1370772b676d7Smrg#endif
1370872b676d7Smrg                  (mode->type & M_T_BUILTIN))
1370972b676d7Smrg                  return 0xfe;
1371072b676d7Smrg	    }
1371172b676d7Smrg         }
1371272b676d7Smrg
1371372b676d7Smrg	 /* All plasma modes have HDisplay <= 1600 */
1371472b676d7Smrg         if((pSiS->AddedPlasmaModes) && (mode->type & M_T_BUILTIN))
1371572b676d7Smrg            return 0xfe;
1371672b676d7Smrg
1371772b676d7Smrg         if((havecustommodes) &&
1371872b676d7Smrg            (pSiS->LCDwidth)  &&	/* = test if LCD present */
1371972b676d7Smrg	    (!(mode->type & M_T_DEFAULT)) &&
1372072b676d7Smrg	    (SiSValidLCDUserMode(pSiS, VBFlags, mode, FALSE)))
1372172b676d7Smrg            return 0xfe;
1372272b676d7Smrg
1372372b676d7Smrg      }
1372472b676d7Smrg
1372572b676d7Smrg      if( ((mode->HDisplay <= pSiS->LCDwidth) &&
1372672b676d7Smrg           (mode->VDisplay <= pSiS->LCDheight)) ||
1372772b676d7Smrg	  ((pSiS->SiS_Pr->SiS_CustomT == CUT_PANEL848) &&
1372872b676d7Smrg	   (((mode->HDisplay == 1360) && (mode->HDisplay == 768)) ||
1372972b676d7Smrg	    ((mode->HDisplay == 1024) && (mode->HDisplay == 768)) ||
1373072b676d7Smrg	    ((mode->HDisplay ==  800) && (mode->HDisplay == 600)))) ||
1373172b676d7Smrg	  ((pSiS->SiS_Pr->SiS_CustomT == CUT_PANEL856) &&
1373272b676d7Smrg	   (((mode->HDisplay == 1024) && (mode->HDisplay == 768)) ||
1373372b676d7Smrg	    ((mode->HDisplay ==  800) && (mode->HDisplay == 600)))) ) {
1373472b676d7Smrg
1373572b676d7Smrg	 ModeIndex = SiS_GetModeID_LCD(pSiS->VGAEngine, VBFlags, mode->HDisplay, mode->VDisplay, i,
1373672b676d7Smrg				pSiS->FSTN, pSiS->SiS_Pr->SiS_CustomT, pSiS->LCDwidth, pSiS->LCDheight,
1373772b676d7Smrg				pSiS->VBFlags2);
1373872b676d7Smrg
1373972b676d7Smrg      }
1374072b676d7Smrg
1374172b676d7Smrg   } else if(VBFlags & CRT2_TV) {		/* CRT2 is TV */
1374272b676d7Smrg
1374372b676d7Smrg      ModeIndex = SiS_GetModeID_TV(pSiS->VGAEngine, VBFlags, mode->HDisplay, mode->VDisplay, i,
1374472b676d7Smrg					pSiS->VBFlags2);
1374572b676d7Smrg
1374672b676d7Smrg   } else if(VBFlags & CRT2_VGA) {		/* CRT2 is VGA2 */
1374772b676d7Smrg
1374872b676d7Smrg      if((pSiS->AddedPlasmaModes) && (mode->type & M_T_BUILTIN))
1374972b676d7Smrg	 return 0xfe;
1375072b676d7Smrg
1375172b676d7Smrg      if((havecustommodes) &&
1375272b676d7Smrg	 (!(mode->type & M_T_DEFAULT)) &&
1375372b676d7Smrg	 (SiSValidVGA2UserMode(pSiS, VBFlags, mode)))
1375472b676d7Smrg         return 0xfe;
1375572b676d7Smrg
1375672b676d7Smrg      ModeIndex = SiS_GetModeID_VGA2(pSiS->VGAEngine, VBFlags, mode->HDisplay, mode->VDisplay, i,
1375772b676d7Smrg					pSiS->VBFlags2);
1375872b676d7Smrg
1375972b676d7Smrg   } else {					/* no CRT2 */
1376072b676d7Smrg
1376172b676d7Smrg      /* Return a valid mode number */
1376272b676d7Smrg      ModeIndex = 0xfe;
1376372b676d7Smrg
1376472b676d7Smrg   }
1376572b676d7Smrg
1376672b676d7Smrg   return(ModeIndex);
1376772b676d7Smrg}
1376872b676d7Smrg
1376972b676d7Smrg/* Calculate the vertical refresh rate from a mode */
1377072b676d7Smrgfloat
1377172b676d7SmrgSiSCalcVRate(DisplayModePtr mode)
1377272b676d7Smrg{
1377372b676d7Smrg   float hsync, refresh = 0;
1377472b676d7Smrg
1377572b676d7Smrg   if(mode->HSync > 0.0)
1377672b676d7Smrg       	hsync = mode->HSync;
1377772b676d7Smrg   else if(mode->HTotal > 0)
1377872b676d7Smrg       	hsync = (float)mode->Clock / (float)mode->HTotal;
1377972b676d7Smrg   else
1378072b676d7Smrg       	hsync = 0.0;
1378172b676d7Smrg
1378272b676d7Smrg   if(mode->VTotal > 0)
1378372b676d7Smrg       	refresh = hsync * 1000.0 / mode->VTotal;
1378472b676d7Smrg
1378572b676d7Smrg   if(mode->Flags & V_INTERLACE)
1378672b676d7Smrg       	refresh *= 2.0;
1378772b676d7Smrg
1378872b676d7Smrg   if(mode->Flags & V_DBLSCAN)
1378972b676d7Smrg       	refresh /= 2.0;
1379072b676d7Smrg
1379172b676d7Smrg   if(mode->VScan > 1)
1379272b676d7Smrg        refresh /= mode->VScan;
1379372b676d7Smrg
1379472b676d7Smrg   if(mode->VRefresh > 0.0)
1379572b676d7Smrg	refresh = mode->VRefresh;
1379672b676d7Smrg
1379772b676d7Smrg   if(hsync == 0.0 || refresh == 0.0) return 0.0;
1379872b676d7Smrg
1379972b676d7Smrg   return refresh;
1380072b676d7Smrg}
1380172b676d7Smrg
1380272b676d7Smrg/* Calculate CR33 (rate index) for CRT1.
1380372b676d7Smrg * Calculation is done using currentmode, therefore it is
1380472b676d7Smrg * recommended to set VertRefresh and HorizSync to correct
1380572b676d7Smrg * values in config file.
1380672b676d7Smrg */
1380772b676d7SmrgUChar
1380872b676d7SmrgSISSearchCRT1Rate(ScrnInfoPtr pScrn, DisplayModePtr mode)
1380972b676d7Smrg{
1381072b676d7Smrg   SISPtr  pSiS = SISPTR(pScrn);
1381172b676d7Smrg   int     i = 0, irefresh;
1381272b676d7Smrg   UShort  xres = mode->HDisplay;
1381372b676d7Smrg   UShort  yres = mode->VDisplay;
1381472b676d7Smrg   UChar   index, defindex;
1381572b676d7Smrg   Bool    checksis730 = FALSE;
1381672b676d7Smrg
1381772b676d7Smrg   defindex = (xres == 800 || xres == 1024 || xres == 1280) ? 0x02 : 0x01;
1381872b676d7Smrg
1381972b676d7Smrg   irefresh = (int)SiSCalcVRate(mode);
1382072b676d7Smrg   if(!irefresh) return defindex;
1382172b676d7Smrg
1382272b676d7Smrg   /* SiS730 has troubles on CRT2 if CRT1 is at 32bpp */
1382372b676d7Smrg   if( (pSiS->ChipType == SIS_730)        &&
1382472b676d7Smrg       (pSiS->VBFlags2 & VB2_VIDEOBRIDGE) &&
1382572b676d7Smrg       (pSiS->CurrentLayout.bitsPerPixel == 32) ) {
1382672b676d7Smrg#ifdef SISDUALHEAD
1382772b676d7Smrg      if(pSiS->DualHeadMode) {
1382872b676d7Smrg         if(pSiS->SecondHead) {
1382972b676d7Smrg	    checksis730 = TRUE;
1383072b676d7Smrg	 }
1383172b676d7Smrg      } else
1383272b676d7Smrg#endif
1383372b676d7Smrg      if((!pSiS->UseVESA) && (pSiS->VBFlags & CRT2_ENABLE) && (!pSiS->CRT1off)) {
1383472b676d7Smrg         checksis730 = TRUE;
1383572b676d7Smrg      }
1383672b676d7Smrg   }
1383772b676d7Smrg
1383872b676d7Smrg#ifdef TWDEBUG
1383972b676d7Smrg   xf86DrvMsg(0, X_INFO, "Debug: CalcVRate returned %d\n", irefresh);
1384072b676d7Smrg#endif
1384172b676d7Smrg
1384272b676d7Smrg   /* We need the REAL refresh rate here */
1384372b676d7Smrg   if(mode->Flags & V_INTERLACE) irefresh /= 2;
1384472b676d7Smrg
1384572b676d7Smrg   /* Do not multiply by 2 when DBLSCAN! */
1384672b676d7Smrg
1384772b676d7Smrg#ifdef TWDEBUG
1384872b676d7Smrg   xf86DrvMsg(0, X_INFO, "Debug: Rate after correction = %d\n", irefresh);
1384972b676d7Smrg#endif
1385072b676d7Smrg
1385172b676d7Smrg   index = 0;
1385272b676d7Smrg   while((sisx_vrate[i].idx != 0) && (sisx_vrate[i].xres <= xres)) {
1385372b676d7Smrg      if((sisx_vrate[i].xres == xres) && (sisx_vrate[i].yres == yres)) {
1385472b676d7Smrg	 if((checksis730 == FALSE) || (sisx_vrate[i].SiS730valid32bpp == TRUE)) {
1385572b676d7Smrg	    if(sisx_vrate[i].refresh == irefresh) {
1385672b676d7Smrg	       index = sisx_vrate[i].idx;
1385772b676d7Smrg	       break;
1385872b676d7Smrg	    } else if(sisx_vrate[i].refresh > irefresh) {
1385972b676d7Smrg	       if((sisx_vrate[i].refresh - irefresh) <= 3) {
1386072b676d7Smrg		  index = sisx_vrate[i].idx;
1386172b676d7Smrg	       } else if( ((checksis730 == FALSE) || (sisx_vrate[i - 1].SiS730valid32bpp == TRUE)) &&
1386272b676d7Smrg		          ((irefresh - sisx_vrate[i - 1].refresh) <=  2) &&
1386372b676d7Smrg			  (sisx_vrate[i].idx != 1) ) {
1386472b676d7Smrg		  index = sisx_vrate[i - 1].idx;
1386572b676d7Smrg	       }
1386672b676d7Smrg	       break;
1386772b676d7Smrg	    } else if((irefresh - sisx_vrate[i].refresh) <= 2) {
1386872b676d7Smrg	       index = sisx_vrate[i].idx;
1386972b676d7Smrg	       break;
1387072b676d7Smrg	    }
1387172b676d7Smrg	 }
1387272b676d7Smrg      }
1387372b676d7Smrg      i++;
1387472b676d7Smrg   }
1387572b676d7Smrg
1387672b676d7Smrg   if(index > 0) return index;
1387772b676d7Smrg   else          return defindex;
1387872b676d7Smrg}
1387972b676d7Smrg
1388072b676d7Smrgvoid
1388172b676d7SmrgSISWaitRetraceCRT1(ScrnInfoPtr pScrn)
1388272b676d7Smrg{
1388372b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1388472b676d7Smrg   int    watchdog;
1388572b676d7Smrg   UChar  temp;
1388672b676d7Smrg
1388772b676d7Smrg   inSISIDXREG(SISCR,0x17,temp);
1388872b676d7Smrg   if(!(temp & 0x80)) return;
1388972b676d7Smrg
1389072b676d7Smrg   inSISIDXREG(SISSR,0x1f,temp);
1389172b676d7Smrg   if(temp & 0xc0) return;
1389272b676d7Smrg
1389372b676d7Smrg   watchdog = 65536;
1389472b676d7Smrg   while((inSISREG(SISINPSTAT) & 0x08) && --watchdog);
1389572b676d7Smrg   watchdog = 65536;
1389672b676d7Smrg   while((!(inSISREG(SISINPSTAT) & 0x08)) && --watchdog);
1389772b676d7Smrg}
1389872b676d7Smrg
1389972b676d7Smrgvoid
1390072b676d7SmrgSISWaitRetraceCRT2(ScrnInfoPtr pScrn)
1390172b676d7Smrg{
1390272b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
1390372b676d7Smrg   int    watchdog;
1390472b676d7Smrg   UChar  temp, reg;
1390572b676d7Smrg
1390672b676d7Smrg   if(SiSBridgeIsInSlaveMode(pScrn)) {
1390772b676d7Smrg      SISWaitRetraceCRT1(pScrn);
1390872b676d7Smrg      return;
1390972b676d7Smrg   }
1391072b676d7Smrg
1391172b676d7Smrg   switch(pSiS->VGAEngine) {
1391272b676d7Smrg   case SIS_300_VGA:
1391372b676d7Smrg   	reg = 0x25;
1391472b676d7Smrg	break;
1391572b676d7Smrg   case SIS_315_VGA:
1391672b676d7Smrg   	reg = 0x30;
1391772b676d7Smrg	break;
1391872b676d7Smrg   default:
1391972b676d7Smrg        return;
1392072b676d7Smrg   }
1392172b676d7Smrg
1392272b676d7Smrg   watchdog = 65536;
1392372b676d7Smrg   do {
1392472b676d7Smrg   	inSISIDXREG(SISPART1, reg, temp);
1392572b676d7Smrg	if(!(temp & 0x02)) break;
1392672b676d7Smrg   } while(--watchdog);
1392772b676d7Smrg   watchdog = 65536;
1392872b676d7Smrg   do {
1392972b676d7Smrg   	inSISIDXREG(SISPART1, reg, temp);
1393072b676d7Smrg	if(temp & 0x02) break;
1393172b676d7Smrg   } while(--watchdog);
1393272b676d7Smrg}
1393372b676d7Smrg
1393472b676d7Smrgstatic void
1393572b676d7SmrgSISWaitVBRetrace(ScrnInfoPtr pScrn)
1393672b676d7Smrg{
1393772b676d7Smrg   SISPtr  pSiS = SISPTR(pScrn);
1393872b676d7Smrg
1393972b676d7Smrg   if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
1394072b676d7Smrg#ifdef SISDUALHEAD
1394172b676d7Smrg      if(pSiS->DualHeadMode) {
1394272b676d7Smrg   	 if(pSiS->SecondHead)
1394372b676d7Smrg	    SISWaitRetraceCRT1(pScrn);
1394472b676d7Smrg         else
1394572b676d7Smrg	    SISWaitRetraceCRT2(pScrn);
1394672b676d7Smrg      } else {
1394772b676d7Smrg#endif
1394872b676d7Smrg	 if(pSiS->VBFlags & DISPTYPE_DISP1) {
1394972b676d7Smrg	    SISWaitRetraceCRT1(pScrn);
1395072b676d7Smrg	 }
1395172b676d7Smrg	 if(pSiS->VBFlags & DISPTYPE_DISP2) {
1395272b676d7Smrg	    if(!(SiSBridgeIsInSlaveMode(pScrn))) {
1395372b676d7Smrg	       SISWaitRetraceCRT2(pScrn);
1395472b676d7Smrg	    }
1395572b676d7Smrg	 }
1395672b676d7Smrg#ifdef SISDUALHEAD
1395772b676d7Smrg      }
1395872b676d7Smrg#endif
1395972b676d7Smrg   } else {
1396072b676d7Smrg      SISWaitRetraceCRT1(pScrn);
1396172b676d7Smrg   }
1396272b676d7Smrg}
1396372b676d7Smrg
1396472b676d7Smrg#define MODEID_OFF 0x449
1396572b676d7Smrg
1396672b676d7SmrgUChar
1396772b676d7SmrgSiS_GetSetBIOSScratch(ScrnInfoPtr pScrn, UShort offset, UChar value)
1396872b676d7Smrg{
1396972b676d7Smrg    UChar ret = 0;
1397072b676d7Smrg#ifdef SIS_USE_BIOS_SCRATCH
1397172b676d7Smrg    UChar *base;
1397272b676d7Smrg#endif
1397372b676d7Smrg
1397472b676d7Smrg    /* For some reasons (like detecting the current display mode),
1397572b676d7Smrg     * we need to read (or write-back) values from the BIOS
1397672b676d7Smrg     * scratch area. This area is only valid for the primary
1397772b676d7Smrg     * graphics card. For the secondary, we just return some
1397872b676d7Smrg     * defaults and ignore requests to write data. As regards
1397972b676d7Smrg     * the display mode: If sisfb is loaded for the secondary
1398072b676d7Smrg     * card, it very probably has set a mode, but in any case
1398172b676d7Smrg     * informed us via its info packet. So this here will not be
1398272b676d7Smrg     * called for mode detection in this case.
1398372b676d7Smrg     */
1398472b676d7Smrg
1398572b676d7Smrg    switch(offset) {
1398672b676d7Smrg    case 0x489:
1398772b676d7Smrg       ret = 0x11;  /* Default VGA Info */
1398872b676d7Smrg       break;
1398972b676d7Smrg    case MODEID_OFF:
1399072b676d7Smrg       ret = 0x03;  /* Default current display mode */
1399172b676d7Smrg       break;
1399272b676d7Smrg    }
1399372b676d7Smrg
1399472b676d7Smrg#ifdef SIS_USE_BIOS_SCRATCH
1399572b676d7Smrg    if(SISPTR(pScrn)->Primary) {
1399672b676d7Smrg       base = xf86MapVidMem(pScrn->scrnIndex, VIDMEM_MMIO, 0, 0x2000);
1399772b676d7Smrg       if(!base) {
1399872b676d7Smrg          SISErrorLog(pScrn, "(Could not map BIOS scratch area)\n");
1399972b676d7Smrg          return ret;
1400072b676d7Smrg       }
1400172b676d7Smrg
1400272b676d7Smrg       ret = *(base + offset);
1400372b676d7Smrg
1400472b676d7Smrg       /* value != 0xff means: set register */
1400572b676d7Smrg       if(value != 0xff) {
1400672b676d7Smrg          *(base + offset) = value;
1400772b676d7Smrg       }
1400872b676d7Smrg
1400972b676d7Smrg       xf86UnMapVidMem(pScrn->scrnIndex, base, 0x2000);
1401072b676d7Smrg    }
1401172b676d7Smrg#endif
1401272b676d7Smrg    return ret;
1401372b676d7Smrg}
1401472b676d7Smrg
1401572b676d7SmrgUChar
1401672b676d7SmrgSiS_GetSetModeID(ScrnInfoPtr pScrn, UChar id)
1401772b676d7Smrg{
1401872b676d7Smrg    return(SiS_GetSetBIOSScratch(pScrn, MODEID_OFF, id));
1401972b676d7Smrg}
1402072b676d7Smrg
1402172b676d7Smrgvoid
1402272b676d7SmrgSiSMemCopyToVideoRam(SISPtr pSiS, UChar *to, UChar *from, int size)
1402372b676d7Smrg{
1402472b676d7Smrg   if((ULong)to & 15) (*pSiS->SiSFastMemCopy)(to, from, size);
1402572b676d7Smrg   else       	      (*pSiS->SiSFastVidCopy)(to, from, size);
1402672b676d7Smrg}
1402772b676d7Smrg
1402872b676d7Smrgvoid
1402972b676d7SmrgSiSMemCopyFromVideoRam(SISPtr pSiS, UChar *to, UChar *from, int size)
1403072b676d7Smrg{
1403172b676d7Smrg   if((ULong)to & 15) (*pSiS->SiSFastMemCopyFrom)(to, from, size);
1403272b676d7Smrg   else       	      (*pSiS->SiSFastVidCopyFrom)(to, from, size);
1403372b676d7Smrg}
1403472b676d7Smrg
1403572b676d7Smrgvoid
1403672b676d7SmrgsisSaveUnlockExtRegisterLock(SISPtr pSiS, UChar *reg1, UChar *reg2)
1403772b676d7Smrg{
1403872b676d7Smrg    register UChar val;
1403972b676d7Smrg    ULong mylockcalls;
1404072b676d7Smrg#ifdef TWDEBUG
1404172b676d7Smrg    UChar val1, val2;
1404272b676d7Smrg    int i;
1404372b676d7Smrg#endif
1404472b676d7Smrg
1404572b676d7Smrg    pSiS->lockcalls++;
1404672b676d7Smrg    mylockcalls = pSiS->lockcalls;
1404772b676d7Smrg
1404872b676d7Smrg    /* check if already unlocked */
1404972b676d7Smrg    inSISIDXREG(SISSR, 0x05, val);
1405072b676d7Smrg
1405172b676d7Smrg    if(val != 0xa1) {
1405272b676d7Smrg
1405372b676d7Smrg       /* save State */
1405472b676d7Smrg       if(reg1) *reg1 = val;
1405572b676d7Smrg
1405672b676d7Smrg       /* unlock */
1405772b676d7Smrg       outSISIDXREG(SISSR, 0x05, 0x86);
1405872b676d7Smrg
1405972b676d7Smrg       /* Now check again */
1406072b676d7Smrg       inSISIDXREG(SISSR, 0x05, val);
1406172b676d7Smrg
1406272b676d7Smrg       if(val != 0xA1) {
1406372b676d7Smrg
1406472b676d7Smrg          xf86DrvMsg(pSiS->pScrn->scrnIndex, X_WARNING,
1406572b676d7Smrg               "Failed to unlock SR registers at relocated i/o ports\n");
1406672b676d7Smrg
1406772b676d7Smrg#ifdef TWDEBUG
1406872b676d7Smrg          for(i = 0; i <= 0x3f; i++) {
1406972b676d7Smrg		inSISIDXREG(SISSR, i, val1);
1407072b676d7Smrg		inSISIDXREG(0x3c4, i, val2);
1407172b676d7Smrg		xf86DrvMsg(pSiS->pScrn->scrnIndex, X_INFO,
1407272b676d7Smrg			"SR%02d: RelIO=0x%02x 0x3c4=0x%02x (%ld)\n",
1407372b676d7Smrg			i, val1, val2, mylockcalls);
1407472b676d7Smrg	  }
1407572b676d7Smrg#endif
1407672b676d7Smrg
1407772b676d7Smrg	  /* Emergency measure: unlock at 0x3c4, and try to enable relocated IO ports */
1407872b676d7Smrg	  switch(pSiS->VGAEngine) {
1407972b676d7Smrg          case SIS_OLD_VGA:
1408072b676d7Smrg	  case SIS_530_VGA:
1408172b676d7Smrg	     outSISIDXREG(0x3c4, 0x05, 0x86);
1408272b676d7Smrg	     andSISIDXREG(0x3c4, 0x33, ~0x20);
1408372b676d7Smrg	     break;
1408472b676d7Smrg	  case SIS_300_VGA:
1408572b676d7Smrg	  case SIS_315_VGA:
1408672b676d7Smrg	     outSISIDXREG(0x3c4, 0x05, 0x86);
1408772b676d7Smrg	     orSISIDXREG(0x3c4, 0x20, 0x20);
1408872b676d7Smrg	     break;
1408972b676d7Smrg          }
1409072b676d7Smrg	  outSISIDXREG(SISSR, 0x05, 0x86);
1409172b676d7Smrg	  inSISIDXREG(SISSR, 0x05, val);
1409272b676d7Smrg	  if(val != 0xa1) {
1409372b676d7Smrg	     SISErrorLog(pSiS->pScrn,
1409472b676d7Smrg			"Failed to unlock SR registers (%p, %lx, 0x%02x; %ld)\n",
1409572b676d7Smrg			(void *)pSiS, (ULong)pSiS->RelIO, val, mylockcalls);
1409672b676d7Smrg	     /* Now await doom... */
1409772b676d7Smrg	  }
1409872b676d7Smrg       }
1409972b676d7Smrg    }
1410072b676d7Smrg    if((pSiS->VGAEngine == SIS_OLD_VGA) || (pSiS->VGAEngine == SIS_530_VGA)) {
1410172b676d7Smrg       inSISIDXREG(SISCR, 0x80, val);
1410272b676d7Smrg       if(val != 0xa1) {
1410372b676d7Smrg          /* save State */
1410472b676d7Smrg          if(reg2) *reg2 = val;
1410572b676d7Smrg          outSISIDXREG(SISCR, 0x80, 0x86);
1410672b676d7Smrg	  inSISIDXREG(SISCR, 0x80, val);
1410772b676d7Smrg	  if(val != 0xA1) {
1410872b676d7Smrg	     SISErrorLog(pSiS->pScrn,
1410972b676d7Smrg	        "Failed to unlock cr registers (%p, %lx, 0x%02x)\n",
1411072b676d7Smrg	       (void *)pSiS, (ULong)pSiS->RelIO, val);
1411172b676d7Smrg	  }
1411272b676d7Smrg       }
1411372b676d7Smrg    }
1411472b676d7Smrg}
1411572b676d7Smrg
1411672b676d7Smrgvoid
1411772b676d7SmrgsisRestoreExtRegisterLock(SISPtr pSiS, UChar reg1, UChar reg2)
1411872b676d7Smrg{
1411972b676d7Smrg    /* restore lock */
1412072b676d7Smrg#ifndef UNLOCK_ALWAYS
1412172b676d7Smrg    outSISIDXREG(SISSR, 0x05, reg1 == 0xA1 ? 0x86 : 0x00);
1412272b676d7Smrg    if((pSiS->VGAEngine == SIS_OLD_VGA) || (pSiS->VGAEngine == SIS_530_VGA)) {
1412372b676d7Smrg       outSISIDXREG(SISCR, 0x80, reg2 == 0xA1 ? 0x86 : 0x00);
1412472b676d7Smrg    }
1412572b676d7Smrg#endif
1412672b676d7Smrg}
1412772b676d7Smrg
14128