145bc899bSmrg#define DEBUG_VERB 2
245bc899bSmrg/*
345bc899bSmrg * Copyright (c) 2000 by Conectiva S.A. (http://www.conectiva.com)
450f2e948Smrg * Copyright 2008 Red Hat, Inc.
545bc899bSmrg *
645bc899bSmrg * Permission is hereby granted, free of charge, to any person obtaining a
745bc899bSmrg * copy of this software and associated documentation files (the "Software"),
845bc899bSmrg * to deal in the Software without restriction, including without limitation
945bc899bSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1045bc899bSmrg * and/or sell copies of the Software, and to permit persons to whom the
1145bc899bSmrg * Software is furnished to do so, subject to the following conditions:
1245bc899bSmrg *
1345bc899bSmrg * The above copyright notice and this permission notice shall be included in
1445bc899bSmrg * all copies or substantial portions of the Software.
1545bc899bSmrg *
1645bc899bSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1745bc899bSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1845bc899bSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1945bc899bSmrg * CONECTIVA LINUX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
2045bc899bSmrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
2145bc899bSmrg * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2245bc899bSmrg * SOFTWARE.
2345bc899bSmrg *
2445bc899bSmrg * Except as contained in this notice, the name of Conectiva Linux shall
2545bc899bSmrg * not be used in advertising or otherwise to promote the sale, use or other
2645bc899bSmrg * dealings in this Software without prior written authorization from
2745bc899bSmrg * Conectiva Linux.
2845bc899bSmrg *
2945bc899bSmrg * Authors: Paulo César Pereira de Andrade <pcpa@conectiva.com.br>
3045bc899bSmrg *          David Dawes <dawes@xfree86.org>
3150f2e948Smrg *          Adam Jackson <ajax@redhat.com>
3250f2e948Smrg */
3350f2e948Smrg
3450f2e948Smrg/*
3550f2e948Smrg * TODO:
3650f2e948Smrg * - Port to RANDR 1.2 setup to make mode selection slightly better
3750f2e948Smrg * - Port to RANDR 1.2 to drop the old-school DGA junk
3850f2e948Smrg * - VBE/SCI for secondary DDC method?
3945bc899bSmrg */
4045bc899bSmrg
4145bc899bSmrg#ifdef HAVE_CONFIG_H
4245bc899bSmrg#include "config.h"
4345bc899bSmrg#endif
4445bc899bSmrg
4545bc899bSmrg#include <string.h>
46a0c41156Smrg#include <unistd.h>
47e8b4ed9fSmrg#include <dirent.h>
4845bc899bSmrg#include "vesa.h"
4945bc899bSmrg
5045bc899bSmrg/* All drivers initialising the SW cursor need this */
5145bc899bSmrg#include "mipointer.h"
5245bc899bSmrg
5345bc899bSmrg/* Colormap handling */
5445bc899bSmrg#include "micmap.h"
5545bc899bSmrg#include "xf86cmap.h"
5650f2e948Smrg#include "xf86Modes.h"
5745bc899bSmrg
5845bc899bSmrg/* DPMS */
593a925b30Smrg#ifdef HAVE_XEXTPROTO_71
603a925b30Smrg#include <X11/extensions/dpmsconst.h>
613a925b30Smrg#else
6245bc899bSmrg#define DPMS_SERVER
6345bc899bSmrg#include <X11/extensions/dpms.h>
643a925b30Smrg#endif
65b40a6198Smrg#include "compat-api.h"
6645bc899bSmrg
6778f6f648Smrg#if defined(__NetBSD__)
6878f6f648Smrg#include <sys/sysctl.h>
6978f6f648Smrg#endif
7078f6f648Smrg
7145bc899bSmrg/* Mandatory functions */
7245bc899bSmrgstatic const OptionInfoRec * VESAAvailableOptions(int chipid, int busid);
7345bc899bSmrgstatic void VESAIdentify(int flags);
74f2408745Smrg#if defined(XSERVER_LIBPCIACCESS) && !defined(HAVE_ISA)
75f2408745Smrg#define VESAProbe NULL
76f2408745Smrg#else
7745bc899bSmrgstatic Bool VESAProbe(DriverPtr drv, int flags);
78f2408745Smrg#endif
7950f2e948Smrg#ifdef XSERVER_LIBPCIACCESS
8050f2e948Smrgstatic Bool VESAPciProbe(DriverPtr drv, int entity_num,
8150f2e948Smrg     struct pci_device *dev, intptr_t match_data);
8250f2e948Smrg#endif
8345bc899bSmrgstatic Bool VESAPreInit(ScrnInfoPtr pScrn, int flags);
84b40a6198Smrgstatic Bool VESAScreenInit(SCREEN_INIT_ARGS_DECL);
85b40a6198Smrgstatic Bool VESAEnterVT(VT_FUNC_ARGS_DECL);
86b40a6198Smrgstatic void VESALeaveVT(VT_FUNC_ARGS_DECL);
87b40a6198Smrgstatic Bool VESACloseScreen(CLOSE_SCREEN_ARGS_DECL);
8845bc899bSmrgstatic Bool VESASaveScreen(ScreenPtr pScreen, int mode);
8945bc899bSmrg
90b40a6198Smrgstatic Bool VESASwitchMode(SWITCH_MODE_ARGS_DECL);
9145bc899bSmrgstatic Bool VESASetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode);
92b40a6198Smrgstatic void VESAAdjustFrame(ADJUST_FRAME_ARGS_DECL);
93b40a6198Smrgstatic void VESAFreeScreen(FREE_SCREEN_ARGS_DECL);
9445bc899bSmrgstatic void VESAFreeRec(ScrnInfoPtr pScrn);
9550f2e948Smrgstatic VESAPtr VESAGetRec(ScrnInfoPtr pScrn);
9645bc899bSmrg
9745bc899bSmrgstatic void
9845bc899bSmrgVESADisplayPowerManagementSet(ScrnInfoPtr pScrn, int mode,
9945bc899bSmrg                int flags);
10045bc899bSmrg
10145bc899bSmrg/* locally used functions */
1025592a31fSmrg#ifdef HAVE_ISA
10345bc899bSmrgstatic int VESAFindIsaDevice(GDevPtr dev);
1045592a31fSmrg#endif
10545bc899bSmrgstatic Bool VESAMapVidMem(ScrnInfoPtr pScrn);
10645bc899bSmrgstatic void VESAUnmapVidMem(ScrnInfoPtr pScrn);
10745bc899bSmrgstatic int VESABankSwitch(ScreenPtr pScreen, unsigned int iBank);
10845bc899bSmrgstatic void VESALoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices,
10945bc899bSmrg			    LOCO *colors, VisualPtr pVisual);
11045bc899bSmrgstatic void SaveFonts(ScrnInfoPtr pScrn);
11145bc899bSmrgstatic void RestoreFonts(ScrnInfoPtr pScrn);
11245bc899bSmrgstatic Bool
11345bc899bSmrgVESASaveRestore(ScrnInfoPtr pScrn, vbeSaveRestoreFunction function);
11445bc899bSmrg
1155592a31fSmrgstatic void *
1165592a31fSmrgVESAWindowLinear(ScreenPtr pScreen, CARD32 row, CARD32 offset, int mode,
1175592a31fSmrg		 CARD32 *size, void *closure)
1185592a31fSmrg{
119b40a6198Smrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1205592a31fSmrg    VESAPtr pVesa = VESAGetRec(pScrn);
1215592a31fSmrg
1225592a31fSmrg    *size = pVesa->maxBytesPerScanline;
1235592a31fSmrg    return ((CARD8 *)pVesa->base + row * pVesa->maxBytesPerScanline + offset);
1245592a31fSmrg}
1255592a31fSmrg
1265592a31fSmrgstatic void *
1275592a31fSmrgVESAWindowWindowed(ScreenPtr pScreen, CARD32 row, CARD32 offset, int mode,
1285592a31fSmrg		   CARD32 *size, void *closure)
1295592a31fSmrg{
130b40a6198Smrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1315592a31fSmrg    VESAPtr pVesa = VESAGetRec(pScrn);
1325592a31fSmrg    VbeModeInfoBlock *data = ((VbeModeInfoData*)(pScrn->currentMode->Private))->data;
1335592a31fSmrg    int window;
1345592a31fSmrg
1355592a31fSmrg    offset += pVesa->maxBytesPerScanline * row;
1365592a31fSmrg    window = offset / (data->WinGranularity * 1024);
1375592a31fSmrg    pVesa->windowAoffset = window * data->WinGranularity * 1024;
1385592a31fSmrg    VESABankSwitch(pScreen, window);
1395592a31fSmrg    *size = data->WinSize * 1024 - (offset - pVesa->windowAoffset);
1405592a31fSmrg
1415592a31fSmrg    return (void *)((unsigned long)pVesa->base +
1425592a31fSmrg		    (offset - pVesa->windowAoffset));
1435592a31fSmrg}
1445592a31fSmrg
1455592a31fSmrgstatic void
1465592a31fSmrgvesaUpdatePacked(ScreenPtr pScreen, shadowBufPtr pBuf)
1475592a31fSmrg{
1485592a31fSmrg    shadowUpdatePacked(pScreen, pBuf);
1495592a31fSmrg}
15045bc899bSmrg
15145bc899bSmrgstatic Bool VESADGAInit(ScrnInfoPtr pScrn, ScreenPtr pScreen);
15245bc899bSmrg
15345bc899bSmrgenum GenericTypes
15445bc899bSmrg{
15545bc899bSmrg    CHIP_VESA_GENERIC
15645bc899bSmrg};
15745bc899bSmrg
15850f2e948Smrg#ifdef XSERVER_LIBPCIACCESS
15950f2e948Smrgstatic const struct pci_id_match vesa_device_match[] = {
16050f2e948Smrg    {
16150f2e948Smrg	PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY,
16250f2e948Smrg	0x00030000, 0x00ffffff, CHIP_VESA_GENERIC
16350f2e948Smrg    },
16450f2e948Smrg
16550f2e948Smrg    { 0, 0, 0 },
16650f2e948Smrg};
16750f2e948Smrg#endif
16850f2e948Smrg
16945bc899bSmrg/* Supported chipsets */
17045bc899bSmrgstatic SymTabRec VESAChipsets[] =
17145bc899bSmrg{
17245bc899bSmrg    {CHIP_VESA_GENERIC, "vesa"},
17345bc899bSmrg    {-1,		 NULL}
17445bc899bSmrg};
17545bc899bSmrg
17650f2e948Smrg#ifndef XSERVER_LIBPCIACCESS
17745bc899bSmrgstatic PciChipsets VESAPCIchipsets[] = {
17845bc899bSmrg  { CHIP_VESA_GENERIC, PCI_CHIP_VGA, RES_SHARED_VGA },
17945bc899bSmrg  { -1,		-1,	   RES_UNDEFINED },
18045bc899bSmrg};
18150f2e948Smrg#endif
18245bc899bSmrg
18350f2e948Smrg#ifdef HAVE_ISA
18445bc899bSmrgstatic IsaChipsets VESAISAchipsets[] = {
18545bc899bSmrg  {CHIP_VESA_GENERIC, RES_EXCLUSIVE_VGA},
18645bc899bSmrg  {-1,		0 }
18745bc899bSmrg};
18850f2e948Smrg#endif
18950f2e948Smrg
19050f2e948Smrg
19150f2e948Smrg/*
19250f2e948Smrg * This contains the functions needed by the server after loading the
19350f2e948Smrg * driver module.  It must be supplied, and gets added the driver list by
194e8b4ed9fSmrg * the Module Setup function in the dynamic case.  In the static case a
19550f2e948Smrg * reference to this is compiled in, and this requires that the name of
19650f2e948Smrg * this DriverRec be an upper-case version of the driver name.
19750f2e948Smrg */
19850f2e948Smrg_X_EXPORT DriverRec VESA = {
19950f2e948Smrg    VESA_VERSION,
20050f2e948Smrg    VESA_DRIVER_NAME,
20150f2e948Smrg    VESAIdentify,
20250f2e948Smrg    VESAProbe,
20350f2e948Smrg    VESAAvailableOptions,
20450f2e948Smrg    NULL,
20550f2e948Smrg    0,
20650f2e948Smrg    NULL,
20750f2e948Smrg
20850f2e948Smrg#ifdef XSERVER_LIBPCIACCESS
20950f2e948Smrg    vesa_device_match,
21050f2e948Smrg    VESAPciProbe
21150f2e948Smrg#endif
21250f2e948Smrg};
21350f2e948Smrg
21445bc899bSmrg
21545bc899bSmrgtypedef enum {
21645bc899bSmrg    OPTION_SHADOW_FB,
21745bc899bSmrg    OPTION_DFLT_REFRESH,
21845bc899bSmrg    OPTION_MODESET_CLEAR_SCREEN
21945bc899bSmrg} VESAOpts;
22045bc899bSmrg
22145bc899bSmrgstatic const OptionInfoRec VESAOptions[] = {
22245bc899bSmrg    { OPTION_SHADOW_FB,    "ShadowFB",		OPTV_BOOLEAN,	{0},	FALSE },
22345bc899bSmrg    { OPTION_DFLT_REFRESH, "DefaultRefresh",	OPTV_BOOLEAN,	{0},	FALSE },
22445bc899bSmrg    { OPTION_MODESET_CLEAR_SCREEN, "ModeSetClearScreen",
22545bc899bSmrg						OPTV_BOOLEAN,	{0},	FALSE },
22645bc899bSmrg    { -1,		   NULL,		OPTV_NONE,	{0},	FALSE }
22745bc899bSmrg};
22845bc899bSmrg
22945bc899bSmrg#ifdef XFree86LOADER
23045bc899bSmrg
23145bc899bSmrg/* Module loader interface */
23245bc899bSmrgstatic MODULESETUPPROTO(vesaSetup);
23345bc899bSmrg
23445bc899bSmrgstatic XF86ModuleVersionInfo vesaVersionRec =
23545bc899bSmrg{
23645bc899bSmrg    VESA_DRIVER_NAME,
23745bc899bSmrg    MODULEVENDORSTRING,
23845bc899bSmrg    MODINFOSTRING1,
23945bc899bSmrg    MODINFOSTRING2,
24045bc899bSmrg    XORG_VERSION_CURRENT,
24145bc899bSmrg    VESA_MAJOR_VERSION, VESA_MINOR_VERSION, VESA_PATCHLEVEL,
24245bc899bSmrg    ABI_CLASS_VIDEODRV,			/* This is a video driver */
24345bc899bSmrg    ABI_VIDEODRV_VERSION,
24445bc899bSmrg    MOD_CLASS_VIDEODRV,
24545bc899bSmrg    {0, 0, 0, 0}
24645bc899bSmrg};
24745bc899bSmrg
24845bc899bSmrg/*
24945bc899bSmrg * This data is accessed by the loader.  The name must be the module name
25045bc899bSmrg * followed by "ModuleData".
25145bc899bSmrg */
25245bc899bSmrg_X_EXPORT XF86ModuleData vesaModuleData = { &vesaVersionRec, vesaSetup, NULL };
25345bc899bSmrg
25445bc899bSmrgstatic pointer
25545bc899bSmrgvesaSetup(pointer Module, pointer Options, int *ErrorMajor, int *ErrorMinor)
25645bc899bSmrg{
25745bc899bSmrg    static Bool Initialised = FALSE;
25845bc899bSmrg
25945bc899bSmrg    if (!Initialised)
26045bc899bSmrg    {
26145bc899bSmrg	Initialised = TRUE;
26250f2e948Smrg	xf86AddDriver(&VESA, Module, 1);
26345bc899bSmrg	return (pointer)TRUE;
26445bc899bSmrg    }
26545bc899bSmrg
26645bc899bSmrg    if (ErrorMajor)
26745bc899bSmrg	*ErrorMajor = LDR_ONCEONLY;
26845bc899bSmrg    return (NULL);
26945bc899bSmrg}
27045bc899bSmrg
27145bc899bSmrg#endif
27245bc899bSmrg
27345bc899bSmrgstatic const OptionInfoRec *
27445bc899bSmrgVESAAvailableOptions(int chipid, int busid)
27545bc899bSmrg{
27645bc899bSmrg    return (VESAOptions);
27745bc899bSmrg}
27845bc899bSmrg
27945bc899bSmrgstatic void
28045bc899bSmrgVESAIdentify(int flags)
28145bc899bSmrg{
28245bc899bSmrg    xf86PrintChipsets(VESA_NAME, "driver for VESA chipsets", VESAChipsets);
28345bc899bSmrg}
28445bc899bSmrg
28550f2e948Smrgstatic VESAPtr
28650f2e948SmrgVESAGetRec(ScrnInfoPtr pScrn)
28750f2e948Smrg{
28850f2e948Smrg    if (!pScrn->driverPrivate)
289b40a6198Smrg	pScrn->driverPrivate = calloc(sizeof(VESARec), 1);
29050f2e948Smrg
29150f2e948Smrg    return ((VESAPtr)pScrn->driverPrivate);
29250f2e948Smrg}
29350f2e948Smrg
29450f2e948Smrg/* Only a little like VBESetModeParameters */
29550f2e948Smrgstatic void
29650f2e948SmrgVESASetModeParameters(vbeInfoPtr pVbe, DisplayModePtr vbemode,
29750f2e948Smrg		      DisplayModePtr ddcmode)
29850f2e948Smrg{
29950f2e948Smrg    VbeModeInfoData *data;
30050f2e948Smrg    int clock;
30150f2e948Smrg
30250f2e948Smrg    data = (VbeModeInfoData *)vbemode->Private;
30350f2e948Smrg
304b40a6198Smrg    data->block = calloc(sizeof(VbeCRTCInfoBlock), 1);
30550f2e948Smrg    data->block->HorizontalTotal = ddcmode->HTotal;
30650f2e948Smrg    data->block->HorizontalSyncStart = ddcmode->HSyncStart;
30750f2e948Smrg    data->block->HorizontalSyncEnd = ddcmode->HSyncEnd;
30850f2e948Smrg    data->block->VerticalTotal = ddcmode->VTotal;
30950f2e948Smrg    data->block->VerticalSyncStart = ddcmode->VSyncStart;
31050f2e948Smrg    data->block->VerticalSyncEnd = ddcmode->VSyncEnd;
31150f2e948Smrg    data->block->Flags = ((ddcmode->Flags & V_NHSYNC) ? CRTC_NHSYNC : 0) |
31250f2e948Smrg	                 ((ddcmode->Flags & V_NVSYNC) ? CRTC_NVSYNC : 0);
31350f2e948Smrg    data->block->PixelClock = ddcmode->Clock * 1000;
31450f2e948Smrg
31550f2e948Smrg    /* ask the BIOS to figure out the real clock */
31650f2e948Smrg    clock = VBEGetPixelClock(pVbe, data->mode, data->block->PixelClock);
31750f2e948Smrg    if (clock)
31850f2e948Smrg	data->block->PixelClock = clock;
31950f2e948Smrg
32050f2e948Smrg    data->mode |= (1 << 11);
32150f2e948Smrg    data->block->RefreshRate = 100 * ((double)(data->block->PixelClock) /
32250f2e948Smrg				(double)(ddcmode->HTotal * ddcmode->VTotal));
32350f2e948Smrg}
32450f2e948Smrg
325b40a6198Smrg/*
326b40a6198Smrg * Despite that VBE gives you pixel granularity for mode sizes, some BIOSes
327b40a6198Smrg * think they can only give sizes in multiples of character cells; and
328b40a6198Smrg * indeed, the reference CVT and GTF formulae only give results where
329b40a6198Smrg * (h % 8) == 0.  Whatever, let's just try to cope.  What we're looking for
330b40a6198Smrg * here is cases where the display says 1366x768 and the BIOS says 1360x768.
331b40a6198Smrg */
332b40a6198Smrgstatic Bool
333b40a6198SmrgvesaModesCloseEnough(DisplayModePtr edid, DisplayModePtr vbe)
334b40a6198Smrg{
335b40a6198Smrg    if (!(edid->type & M_T_DRIVER))
336b40a6198Smrg	return FALSE;
337b40a6198Smrg
338b40a6198Smrg    /* never seen a height granularity... */
339b40a6198Smrg    if (edid->VDisplay != vbe->VDisplay)
340b40a6198Smrg	return FALSE;
341b40a6198Smrg
342b40a6198Smrg    if (edid->HDisplay >= vbe->HDisplay &&
343b40a6198Smrg	(edid->HDisplay & ~7) == (vbe->HDisplay & ~7))
344b40a6198Smrg	return TRUE;
345b40a6198Smrg
346b40a6198Smrg    return FALSE;
347b40a6198Smrg}
348b40a6198Smrg
34950f2e948Smrgstatic ModeStatus
350b40a6198SmrgVESAValidMode(SCRN_ARG_TYPE arg, DisplayModePtr p, Bool flag, int pass)
35150f2e948Smrg{
352b40a6198Smrg    SCRN_INFO_PTR(arg);
35350f2e948Smrg    static int warned = 0;
35450f2e948Smrg    int found = 0;
35550f2e948Smrg    VESAPtr pVesa = VESAGetRec(pScrn);
35650f2e948Smrg    MonPtr mon = pScrn->monitor;
35750f2e948Smrg    ModeStatus ret = MODE_BAD;
35850f2e948Smrg    DisplayModePtr mode;
35950f2e948Smrg    float v;
36050f2e948Smrg
36150f2e948Smrg    if (pass != MODECHECK_FINAL) {
36250f2e948Smrg	if (!warned) {
363b40a6198Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "VESAValidMode called unexpectedly\n");
36450f2e948Smrg	    warned = 1;
36550f2e948Smrg	}
36650f2e948Smrg	return MODE_OK;
36750f2e948Smrg    }
36850f2e948Smrg
36950f2e948Smrg    /*
37050f2e948Smrg     * This is suboptimal.  We pass in just the barest description of a mode
37150f2e948Smrg     * we can get away with to VBEValidateModes, so it can't really throw
37250f2e948Smrg     * out anything we give it.  But we need to filter the list so that we
37350f2e948Smrg     * don't populate the mode list with things the monitor can't do.
37450f2e948Smrg     *
37550f2e948Smrg     * So first off, if this isn't a mode we handed to the server (ie,
37650f2e948Smrg     * M_T_BUILTIN), then we know we can't do it.
37750f2e948Smrg     */
37850f2e948Smrg    if (!(p->type & M_T_BUILTIN))
37950f2e948Smrg	return MODE_NOMODE;
38050f2e948Smrg
38150f2e948Smrg    if (pVesa->strict_validation) {
38250f2e948Smrg	/*
38350f2e948Smrg	 * If it's our first pass at mode validation, we'll try for a strict
38450f2e948Smrg	 * intersection between the VBE and DDC mode lists.
38550f2e948Smrg	 */
38650f2e948Smrg	if (pScrn->monitor->DDC) {
38750f2e948Smrg	    for (mode = pScrn->monitor->Modes; mode; mode = mode->next) {
388b40a6198Smrg		if (vesaModesCloseEnough(mode, p)) {
38950f2e948Smrg		    if (xf86CheckModeForMonitor(mode, mon) == MODE_OK) {
39050f2e948Smrg			found = 1;
39150f2e948Smrg			break;
39250f2e948Smrg		    }
39350f2e948Smrg		}
39450f2e948Smrg		if (mode == pScrn->monitor->Last)
39550f2e948Smrg		    break;
39650f2e948Smrg	    }
39750f2e948Smrg	    if (!found)
39850f2e948Smrg		return MODE_NOMODE;
39950f2e948Smrg
40050f2e948Smrg	    /* having found a matching mode, stash the CRTC values aside */
40150f2e948Smrg	    VESASetModeParameters(pVesa->pVbe, p, mode);
40250f2e948Smrg	    return MODE_OK;
40350f2e948Smrg	}
40450f2e948Smrg
40550f2e948Smrg	/* No DDC and no modes make Homer something something... */
40650f2e948Smrg	return MODE_NOMODE;
40750f2e948Smrg    }
40850f2e948Smrg
40950f2e948Smrg    /*
41050f2e948Smrg     * Finally, walk through the vsync rates 1Hz at a time looking for a mode
41150f2e948Smrg     * that will fit.  This is assuredly a terrible way to do this, but
41250f2e948Smrg     * there's no obvious method for computing a mode of a given size that
41350f2e948Smrg     * will pass xf86CheckModeForMonitor.  XXX this path is terrible, but
41450f2e948Smrg     * then, by this point, you're well into despair territory.
41550f2e948Smrg     */
41650f2e948Smrg    for (v = mon->vrefresh[0].lo; v <= mon->vrefresh[0].hi; v++) {
41750f2e948Smrg	mode = xf86GTFMode(p->HDisplay, p->VDisplay, v, 0, 0);
41850f2e948Smrg	ret = xf86CheckModeForMonitor(mode, mon);
419b40a6198Smrg	free(mode->name);
420b40a6198Smrg	free(mode);
42150f2e948Smrg	if (ret == MODE_OK)
42250f2e948Smrg	    break;
42350f2e948Smrg    }
42450f2e948Smrg
42550f2e948Smrg    return ret;
42650f2e948Smrg}
42750f2e948Smrg
42850f2e948Smrgstatic void
42950f2e948SmrgVESAInitScrn(ScrnInfoPtr pScrn)
43050f2e948Smrg{
43150f2e948Smrg    pScrn->driverVersion = VESA_VERSION;
43250f2e948Smrg    pScrn->driverName    = VESA_DRIVER_NAME;
43350f2e948Smrg    pScrn->name		 = VESA_NAME;
43450f2e948Smrg    pScrn->Probe	 = VESAProbe;
43550f2e948Smrg    pScrn->PreInit       = VESAPreInit;
43650f2e948Smrg    pScrn->ScreenInit    = VESAScreenInit;
43750f2e948Smrg    pScrn->SwitchMode    = VESASwitchMode;
43850f2e948Smrg    pScrn->ValidMode     = VESAValidMode;
43950f2e948Smrg    pScrn->AdjustFrame   = VESAAdjustFrame;
44050f2e948Smrg    pScrn->EnterVT       = VESAEnterVT;
44150f2e948Smrg    pScrn->LeaveVT       = VESALeaveVT;
44250f2e948Smrg    pScrn->FreeScreen    = VESAFreeScreen;
44350f2e948Smrg}
44450f2e948Smrg
445e8b4ed9fSmrg#ifdef XSERVER_LIBPCIACCESS
446e8b4ed9fSmrg#ifdef __linux__
447e8b4ed9fSmrg/*
448e8b4ed9fSmrg * check if a file exist in directory
449e8b4ed9fSmrg * should be equivalent to a glob ${directory}/${prefix}*
450e8b4ed9fSmrg */
451e8b4ed9fSmrg
452e8b4ed9fSmrgstatic Bool
453e8b4ed9fSmrgVESAFileExistsPrefix(const char *directory, const char *prefix) {
454e8b4ed9fSmrg    DIR *dir;
455e8b4ed9fSmrg    struct dirent *entry;
456e8b4ed9fSmrg    Bool found = FALSE;
457e8b4ed9fSmrg    int len = strlen(prefix);
458e8b4ed9fSmrg
459e8b4ed9fSmrg    dir = opendir(directory);
460e8b4ed9fSmrg    if (!dir)
461e8b4ed9fSmrg        return FALSE;
462e8b4ed9fSmrg
463e8b4ed9fSmrg    while ((entry = readdir(dir)) != NULL) {
464e8b4ed9fSmrg        if (strlen(entry->d_name) > len &&
465e8b4ed9fSmrg            !memcmp(entry->d_name, prefix, len)) {
466e8b4ed9fSmrg            found = TRUE;
467e8b4ed9fSmrg            break;
468e8b4ed9fSmrg        }
469e8b4ed9fSmrg    }
470e8b4ed9fSmrg    closedir(dir);
471e8b4ed9fSmrg    return found;
472e8b4ed9fSmrg}
473e8b4ed9fSmrg#endif
474e8b4ed9fSmrg
47545bc899bSmrg/*
47645bc899bSmrg * This function is called once, at the start of the first server generation to
47745bc899bSmrg * do a minimal probe for supported hardware.
47845bc899bSmrg */
47950f2e948Smrgstatic Bool
48050f2e948SmrgVESAPciProbe(DriverPtr drv, int entity_num, struct pci_device *dev,
48150f2e948Smrg	     intptr_t match_data)
48250f2e948Smrg{
48350f2e948Smrg    ScrnInfoPtr pScrn;
484a0c41156Smrg
485a0c41156Smrg#ifdef __linux__
486e8b4ed9fSmrg    if (VESAFileExistsPrefix("/dev", "fb") ||
487e8b4ed9fSmrg        VESAFileExistsPrefix("/dev/dri", "card")) {
488e8b4ed9fSmrg        ErrorF("vesa: Refusing to run, Framebuffer or dri device present\n");
489a0c41156Smrg        return FALSE;
490a0c41156Smrg    }
491a0c41156Smrg#endif
49278f6f648Smrg#if defined(__NetBSD__)
49378f6f648Smrg    {
49478f6f648Smrg	char method[10];
49578f6f648Smrg	size_t len = sizeof(method);
49678f6f648Smrg
49778f6f648Smrg        if (sysctlbyname("machdep.bootmethod", &method, &len, NULL, 0) == 0 &&
49878f6f648Smrg	    strcmp(method, "UEFI") == 0) {
49978f6f648Smrg            ErrorF("vesa: Refusing to run, UEFI booted\n");
50078f6f648Smrg            return FALSE;
50178f6f648Smrg        }
50278f6f648Smrg    }
50378f6f648Smrg#endif
504a0c41156Smrg
50550f2e948Smrg    pScrn = xf86ConfigPciEntity(NULL, 0, entity_num, NULL,
50650f2e948Smrg				NULL, NULL, NULL, NULL, NULL);
50750f2e948Smrg    if (pScrn != NULL) {
508b40a6198Smrg	VESAPtr pVesa;
509b40a6198Smrg
510b40a6198Smrg	if (pci_device_has_kernel_driver(dev)) {
511b40a6198Smrg	    ErrorF("vesa: Ignoring device with a bound kernel driver\n");
512b40a6198Smrg	    return FALSE;
513b40a6198Smrg	}
51450f2e948Smrg
515b40a6198Smrg	pVesa = VESAGetRec(pScrn);
51650f2e948Smrg	VESAInitScrn(pScrn);
51750f2e948Smrg	pVesa->pciInfo = dev;
51850f2e948Smrg    }
51950f2e948Smrg
52050f2e948Smrg    return (pScrn != NULL);
52150f2e948Smrg}
52250f2e948Smrg#endif
52350f2e948Smrg
524f2408745Smrg#ifndef VESAProbe
52545bc899bSmrgstatic Bool
52645bc899bSmrgVESAProbe(DriverPtr drv, int flags)
52745bc899bSmrg{
52845bc899bSmrg    Bool foundScreen = FALSE;
52945bc899bSmrg    int numDevSections, numUsed;
53045bc899bSmrg    GDevPtr *devSections;
53145bc899bSmrg    int *usedChips;
53245bc899bSmrg    int i;
53345bc899bSmrg
53445bc899bSmrg    /*
53545bc899bSmrg     * Find the config file Device sections that match this
53645bc899bSmrg     * driver, and return if there are none.
53745bc899bSmrg     */
53845bc899bSmrg    if ((numDevSections = xf86MatchDevice(VESA_NAME,
53945bc899bSmrg					  &devSections)) <= 0)
54045bc899bSmrg	return (FALSE);
54145bc899bSmrg
54250f2e948Smrg#ifndef XSERVER_LIBPCIACCESS
54345bc899bSmrg    /* PCI BUS */
54445bc899bSmrg    if (xf86GetPciVideoInfo()) {
54545bc899bSmrg	numUsed = xf86MatchPciInstances(VESA_NAME, PCI_VENDOR_GENERIC,
54645bc899bSmrg					VESAChipsets, VESAPCIchipsets,
54745bc899bSmrg					devSections, numDevSections,
54845bc899bSmrg					drv, &usedChips);
54945bc899bSmrg	if (numUsed > 0) {
55045bc899bSmrg	    if (flags & PROBE_DETECT)
55145bc899bSmrg		foundScreen = TRUE;
55245bc899bSmrg	    else {
55345bc899bSmrg		for (i = 0; i < numUsed; i++) {
55445bc899bSmrg		    ScrnInfoPtr pScrn = NULL;
55545bc899bSmrg		    /* Allocate a ScrnInfoRec  */
55645bc899bSmrg		    if ((pScrn = xf86ConfigPciEntity(pScrn,0,usedChips[i],
55745bc899bSmrg						     VESAPCIchipsets,NULL,
55845bc899bSmrg						     NULL,NULL,NULL,NULL))) {
55950f2e948Smrg			VESAInitScrn(pScrn);
56045bc899bSmrg			foundScreen = TRUE;
56145bc899bSmrg		    }
56245bc899bSmrg		}
56345bc899bSmrg	    }
564b40a6198Smrg	    free(usedChips);
56545bc899bSmrg	}
56645bc899bSmrg    }
56750f2e948Smrg#endif
56845bc899bSmrg
56950f2e948Smrg#ifdef HAVE_ISA
57045bc899bSmrg    /* Isa Bus */
57145bc899bSmrg    numUsed = xf86MatchIsaInstances(VESA_NAME,VESAChipsets,
57245bc899bSmrg				    VESAISAchipsets, drv,
57345bc899bSmrg				    VESAFindIsaDevice, devSections,
57445bc899bSmrg				    numDevSections, &usedChips);
57545bc899bSmrg    if(numUsed > 0) {
57645bc899bSmrg	if (flags & PROBE_DETECT)
57745bc899bSmrg	    foundScreen = TRUE;
57845bc899bSmrg	else for (i = 0; i < numUsed; i++) {
57945bc899bSmrg	    ScrnInfoPtr pScrn = NULL;
58045bc899bSmrg	    if ((pScrn = xf86ConfigIsaEntity(pScrn, 0,usedChips[i],
58145bc899bSmrg					     VESAISAchipsets, NULL,
58245bc899bSmrg					     NULL, NULL, NULL, NULL))) {
58350f2e948Smrg		VESAInitScrn(pScrn);
58445bc899bSmrg		foundScreen = TRUE;
58545bc899bSmrg	    }
58645bc899bSmrg	}
587b40a6198Smrg	free(usedChips);
58845bc899bSmrg    }
58950f2e948Smrg#endif
59045bc899bSmrg
591b40a6198Smrg    free(devSections);
59245bc899bSmrg
59345bc899bSmrg    return (foundScreen);
59445bc899bSmrg}
595f2408745Smrg#endif
59645bc899bSmrg
59750f2e948Smrg#ifdef HAVE_ISA
59845bc899bSmrgstatic int
59945bc899bSmrgVESAFindIsaDevice(GDevPtr dev)
60045bc899bSmrg{
60145bc899bSmrg#ifndef PC98_EGC
60245bc899bSmrg    CARD16 GenericIOBase = VGAHW_GET_IOBASE();
60345bc899bSmrg    CARD8 CurrentValue, TestValue;
60445bc899bSmrg
60545bc899bSmrg    /* There's no need to unlock VGA CRTC registers here */
60645bc899bSmrg
60745bc899bSmrg    /* VGA has one more read/write attribute register than EGA */
60845bc899bSmrg    (void) inb(GenericIOBase + VGA_IN_STAT_1_OFFSET);  /* Reset flip-flop */
60945bc899bSmrg    outb(VGA_ATTR_INDEX, 0x14 | 0x20);
61045bc899bSmrg    CurrentValue = inb(VGA_ATTR_DATA_R);
61145bc899bSmrg    outb(VGA_ATTR_DATA_W, CurrentValue ^ 0x0F);
61245bc899bSmrg    outb(VGA_ATTR_INDEX, 0x14 | 0x20);
61345bc899bSmrg    TestValue = inb(VGA_ATTR_DATA_R);
61445bc899bSmrg    outb(VGA_ATTR_DATA_R, CurrentValue);
61545bc899bSmrg
61645bc899bSmrg    /* Quit now if no VGA is present */
61745bc899bSmrg    if ((CurrentValue ^ 0x0F) != TestValue)
61845bc899bSmrg      return -1;
61945bc899bSmrg#endif
62045bc899bSmrg    return (int)CHIP_VESA_GENERIC;
62145bc899bSmrg}
62250f2e948Smrg#endif
62345bc899bSmrg
62445bc899bSmrgstatic void
62545bc899bSmrgVESAFreeRec(ScrnInfoPtr pScrn)
62645bc899bSmrg{
62745bc899bSmrg    VESAPtr pVesa = VESAGetRec(pScrn);
62845bc899bSmrg#if 0
62945bc899bSmrg    DisplayModePtr mode = pScrn->modes;
63045bc899bSmrg    /* I am not sure if the modes will ever get freed.
63145bc899bSmrg     * Anyway, the data unknown to other modules is being freed here.
63245bc899bSmrg     */
63345bc899bSmrg    if (mode) {
63445bc899bSmrg	do {
63545bc899bSmrg	    if (mode->Private) {
63645bc899bSmrg		VbeModeInfoData *data = (VbeModeInfoData*)mode->Private;
63745bc899bSmrg
63845bc899bSmrg		if (data->block)
639b40a6198Smrg		    free(data->block);
64045bc899bSmrg
641b40a6198Smrg		free(data);
64245bc899bSmrg
64345bc899bSmrg		mode->Private = NULL;
64445bc899bSmrg	    }
64545bc899bSmrg	    mode = mode->next;
64645bc899bSmrg	} while (mode && mode != pScrn->modes);
64745bc899bSmrg    }
64845bc899bSmrg#endif
649b40a6198Smrg    free(pVesa->monitor);
650f2408745Smrg    if (pVesa->vbeInfo)
651f2408745Smrg	VBEFreeVBEInfo(pVesa->vbeInfo);
652b40a6198Smrg    free(pVesa->pal);
653b40a6198Smrg    free(pVesa->savedPal);
654b40a6198Smrg    free(pVesa->fonts);
655b40a6198Smrg    free(pScrn->driverPrivate);
65645bc899bSmrg    pScrn->driverPrivate = NULL;
65745bc899bSmrg}
65845bc899bSmrg
65950f2e948Smrgstatic int
66050f2e948SmrgVESAValidateModes(ScrnInfoPtr pScrn)
66150f2e948Smrg{
66250f2e948Smrg    VESAPtr pVesa = VESAGetRec(pScrn);
66350f2e948Smrg    DisplayModePtr mode;
66450f2e948Smrg
66550f2e948Smrg    for (mode = pScrn->monitor->Modes; mode; mode = mode->next)
66650f2e948Smrg	mode->status = MODE_OK;
66750f2e948Smrg
66850f2e948Smrg    return VBEValidateModes(pScrn, NULL, pScrn->display->modes,
6695592a31fSmrg			    NULL, NULL, 0, 32767, 1, 0, 32767,
67050f2e948Smrg			    pScrn->display->virtualX,
67150f2e948Smrg			    pScrn->display->virtualY,
67250f2e948Smrg			    pVesa->mapSize, LOOKUP_BEST_REFRESH);
67350f2e948Smrg}
67450f2e948Smrg
67545bc899bSmrg/*
67645bc899bSmrg * This function is called once for each screen at the start of the first
67745bc899bSmrg * server generation to initialise the screen for all server generations.
67845bc899bSmrg */
67945bc899bSmrgstatic Bool
68045bc899bSmrgVESAPreInit(ScrnInfoPtr pScrn, int flags)
68145bc899bSmrg{
68245bc899bSmrg    VESAPtr pVesa;
68345bc899bSmrg    VbeInfoBlock *vbe;
68445bc899bSmrg    DisplayModePtr pMode;
68545bc899bSmrg    VbeModeInfoBlock *mode;
68645bc899bSmrg    Gamma gzeros = {0.0, 0.0, 0.0};
68745bc899bSmrg    rgb rzeros = {0, 0, 0};
68845bc899bSmrg    pointer pDDCModule;
68945bc899bSmrg    int i;
69045bc899bSmrg    int flags24 = 0;
69145bc899bSmrg    int defaultDepth = 0;
69250f2e948Smrg    int defaultBpp = 0;
69345bc899bSmrg    int depths = 0;
69445bc899bSmrg
69545bc899bSmrg    if (flags & PROBE_DETECT)
69645bc899bSmrg	return (FALSE);
69745bc899bSmrg
69845bc899bSmrg    pVesa = VESAGetRec(pScrn);
69945bc899bSmrg    pVesa->pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
70045bc899bSmrg
70145bc899bSmrg    /* Load vbe module */
70245bc899bSmrg    if (!xf86LoadSubModule(pScrn, "vbe"))
70345bc899bSmrg        return (FALSE);
70445bc899bSmrg
70545bc899bSmrg    if ((pVesa->pVbe = VBEExtendedInit(NULL, pVesa->pEnt->index,
70645bc899bSmrg				       SET_BIOS_SCRATCH
70745bc899bSmrg				       | RESTORE_BIOS_SCRATCH)) == NULL)
70845bc899bSmrg        return (FALSE);
70945bc899bSmrg
71050f2e948Smrg#ifndef XSERVER_LIBPCIACCESS
71145bc899bSmrg    if (pVesa->pEnt->location.type == BUS_PCI) {
71245bc899bSmrg	pVesa->pciInfo = xf86GetPciInfoForEntity(pVesa->pEnt->index);
71345bc899bSmrg	pVesa->pciTag = pciTag(pVesa->pciInfo->bus, pVesa->pciInfo->device,
71445bc899bSmrg			       pVesa->pciInfo->func);
71545bc899bSmrg    }
71650f2e948Smrg#endif
71745bc899bSmrg
71845bc899bSmrg    pScrn->chipset = "vesa";
71945bc899bSmrg    pScrn->monitor = pScrn->confScreen->monitor;
72045bc899bSmrg    pScrn->progClock = TRUE;
72145bc899bSmrg    pScrn->rgbBits = 8;
72245bc899bSmrg
72345bc899bSmrg    if ((vbe = VBEGetVBEInfo(pVesa->pVbe)) == NULL)
72445bc899bSmrg	return (FALSE);
72545bc899bSmrg    pVesa->major = (unsigned)(vbe->VESAVersion >> 8);
72645bc899bSmrg    pVesa->minor = vbe->VESAVersion & 0xff;
72745bc899bSmrg    pVesa->vbeInfo = vbe;
72845bc899bSmrg    pScrn->videoRam = vbe->TotalMemory * 64;
72945bc899bSmrg
73045bc899bSmrg    /*
73145bc899bSmrg     * Find what depths are available.
73245bc899bSmrg     */
73345bc899bSmrg    depths = VBEFindSupportedDepths(pVesa->pVbe, pVesa->vbeInfo, &flags24,
73445bc899bSmrg				    V_MODETYPE_VBE);
73545bc899bSmrg
73645bc899bSmrg    /* Preferred order for default depth selection. */
737a0c41156Smrg    if (depths & V_DEPTH_24 && (flags24 & Support32bppFb))
73850f2e948Smrg	defaultDepth = 24;
73950f2e948Smrg    else if (depths & V_DEPTH_16)
74045bc899bSmrg	defaultDepth = 16;
74145bc899bSmrg    else if (depths & V_DEPTH_15)
74245bc899bSmrg	defaultDepth = 15;
743a0c41156Smrg    else if (depths & V_DEPTH_24)
744a0c41156Smrg        defaultDepth = 24; /* ew though */
74545bc899bSmrg    else if (depths & V_DEPTH_8)
74645bc899bSmrg	defaultDepth = 8;
74745bc899bSmrg    else if (depths & V_DEPTH_4)
74845bc899bSmrg	defaultDepth = 4;
74945bc899bSmrg    else if (depths & V_DEPTH_1)
75045bc899bSmrg	defaultDepth = 1;
75145bc899bSmrg
75250f2e948Smrg    if (defaultDepth == 24 && !(flags24 & Support32bppFb))
75350f2e948Smrg	defaultBpp = 24;
75445bc899bSmrg
75550f2e948Smrg    /* Prefer 32bpp because 1999 called and wants its packed pixels back */
75650f2e948Smrg    if (flags24 & Support32bppFb)
75750f2e948Smrg	flags24 |= SupportConvert24to32 | PreferConvert24to32;
75845bc899bSmrg    if (flags24 & Support24bppFb)
75950f2e948Smrg	flags24 |= SupportConvert32to24;
76045bc899bSmrg
76150f2e948Smrg    if (!xf86SetDepthBpp(pScrn, defaultDepth, 0, defaultBpp, flags24)) {
76245bc899bSmrg        vbeFree(pVesa->pVbe);
76345bc899bSmrg	return (FALSE);
76445bc899bSmrg    }
76545bc899bSmrg    xf86PrintDepthBpp(pScrn);
76645bc899bSmrg
76745bc899bSmrg    /* color weight */
76845bc899bSmrg    if (pScrn->depth > 8 && !xf86SetWeight(pScrn, rzeros, rzeros)) {
76945bc899bSmrg        vbeFree(pVesa->pVbe);
77045bc899bSmrg	return (FALSE);
77145bc899bSmrg    }
77245bc899bSmrg    /* visual init */
77345bc899bSmrg    if (!xf86SetDefaultVisual(pScrn, -1)) {
77445bc899bSmrg        vbeFree(pVesa->pVbe);
77545bc899bSmrg	return (FALSE);
77645bc899bSmrg    }
77745bc899bSmrg
77845bc899bSmrg    xf86SetGamma(pScrn, gzeros);
77945bc899bSmrg
780f2408745Smrg    /* set up options before loading any modules that may look at them */
781f2408745Smrg    xf86CollectOptions(pScrn, NULL);
782f2408745Smrg
78345bc899bSmrg    if (pVesa->major >= 2) {
78445bc899bSmrg	/* Load ddc module */
78545bc899bSmrg	if ((pDDCModule = xf86LoadSubModule(pScrn, "ddc")) == NULL) {
78645bc899bSmrg	    vbeFree(pVesa->pVbe);
78745bc899bSmrg	    return (FALSE);
78845bc899bSmrg	}
78945bc899bSmrg
79045bc899bSmrg	if ((pVesa->monitor = vbeDoEDID(pVesa->pVbe, pDDCModule)) != NULL) {
79145bc899bSmrg	    xf86PrintEDID(pVesa->monitor);
79245bc899bSmrg	}
79345bc899bSmrg
79445bc899bSmrg	xf86UnloadSubModule(pDDCModule);
79545bc899bSmrg    }
79645bc899bSmrg
79745bc899bSmrg    if ((pScrn->monitor->DDC = pVesa->monitor) != NULL)
79845bc899bSmrg	xf86SetDDCproperties(pScrn, pVesa->monitor);
7993a925b30Smrg    else {
8003a925b30Smrg	void *panelid = VBEReadPanelID(pVesa->pVbe);
801b40a6198Smrg	VBEInterpretPanelID(SCRN_OR_INDEX_ARG(pScrn), panelid);
802b40a6198Smrg	free(panelid);
8033a925b30Smrg    }
80445bc899bSmrg
80545bc899bSmrg    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, DEBUG_VERB,
80645bc899bSmrg			"Searching for matching VESA mode(s):\n");
80745bc899bSmrg
80845bc899bSmrg    /*
80945bc899bSmrg     * Check the available BIOS modes, and extract those that match the
81045bc899bSmrg     * requirements into the modePool.  Note: modePool is a NULL-terminated
81145bc899bSmrg     * list.
81245bc899bSmrg     */
81345bc899bSmrg    pScrn->modePool = VBEGetModePool (pScrn, pVesa->pVbe, pVesa->vbeInfo,
81445bc899bSmrg				      V_MODETYPE_VBE);
81545bc899bSmrg
81645bc899bSmrg    xf86ErrorFVerb(DEBUG_VERB, "\n");
81745bc899bSmrg    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, DEBUG_VERB,
81845bc899bSmrg		   "Total Memory: %d 64KB banks (%dkB)\n", vbe->TotalMemory,
81945bc899bSmrg		   (vbe->TotalMemory * 65536) / 1024);
82045bc899bSmrg
82145bc899bSmrg    pVesa->mapSize = vbe->TotalMemory * 65536;
82245bc899bSmrg    if (pScrn->modePool == NULL) {
82345bc899bSmrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No matching modes\n");
82445bc899bSmrg        vbeFree(pVesa->pVbe);
82545bc899bSmrg	return (FALSE);
82645bc899bSmrg    }
82745bc899bSmrg
82845bc899bSmrg    VBESetModeNames(pScrn->modePool);
82945bc899bSmrg
83050f2e948Smrg    pVesa->strict_validation = TRUE;
83150f2e948Smrg    i = VESAValidateModes(pScrn);
83250f2e948Smrg
83350f2e948Smrg    if (i <= 0) {
83450f2e948Smrg	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
83550f2e948Smrg		"No valid modes left. Trying less strict filter...\n");
83650f2e948Smrg	pVesa->strict_validation = FALSE;
83750f2e948Smrg	i = VESAValidateModes(pScrn);
83850f2e948Smrg    }
83950f2e948Smrg
84050f2e948Smrg    if (i <= 0) do {
84150f2e948Smrg	Bool changed = FALSE;
84250f2e948Smrg	/* maybe there's more modes at the bottom... */
84350f2e948Smrg	if (pScrn->monitor->vrefresh[0].lo > 50) {
84450f2e948Smrg	    changed = TRUE;
84550f2e948Smrg	    pScrn->monitor->vrefresh[0].lo = 50;
84650f2e948Smrg	}
84750f2e948Smrg	if (pScrn->monitor->hsync[0].lo > 31.5) {
84850f2e948Smrg	    changed = TRUE;
84950f2e948Smrg	    pScrn->monitor->hsync[0].lo = 31.5;
85050f2e948Smrg	}
85150f2e948Smrg
85250f2e948Smrg	if (!changed)
85350f2e948Smrg	    break;
85450f2e948Smrg
85550f2e948Smrg	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
85650f2e948Smrg		   "No valid modes left. Trying aggressive sync range...\n");
85750f2e948Smrg	i = VESAValidateModes(pScrn);
85850f2e948Smrg    } while (0);
85945bc899bSmrg
86045bc899bSmrg    if (i <= 0) {
86150f2e948Smrg	/* alright, i'm out of ideas */
86245bc899bSmrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes\n");
86345bc899bSmrg        vbeFree(pVesa->pVbe);
86445bc899bSmrg	return (FALSE);
86545bc899bSmrg    }
86645bc899bSmrg
86745bc899bSmrg    xf86PruneDriverModes(pScrn);
86845bc899bSmrg
86945bc899bSmrg    pMode = pScrn->modes;
87045bc899bSmrg    do {
87145bc899bSmrg	mode = ((VbeModeInfoData*)pMode->Private)->data;
87245bc899bSmrg	if (mode->BytesPerScanline > pVesa->maxBytesPerScanline) {
87345bc899bSmrg	    pVesa->maxBytesPerScanline = mode->BytesPerScanline;
87445bc899bSmrg	}
87545bc899bSmrg	pMode = pMode->next;
87645bc899bSmrg    } while (pMode != pScrn->modes);
87745bc899bSmrg
87845bc899bSmrg    pScrn->currentMode = pScrn->modes;
87945bc899bSmrg    pScrn->displayWidth = pScrn->virtualX;
88045bc899bSmrg
88145bc899bSmrg    VBEPrintModes(pScrn);
88245bc899bSmrg
88345bc899bSmrg    /* Set display resolution */
88445bc899bSmrg    xf86SetDpi(pScrn, 0, 0);
88545bc899bSmrg
88645bc899bSmrg    if (pScrn->modes == NULL) {
88745bc899bSmrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No modes\n");
88845bc899bSmrg        vbeFree(pVesa->pVbe);
88945bc899bSmrg	return (FALSE);
89045bc899bSmrg    }
89145bc899bSmrg
89245bc899bSmrg    /* options */
893b40a6198Smrg    if (!(pVesa->Options = malloc(sizeof(VESAOptions)))) {
89445bc899bSmrg        vbeFree(pVesa->pVbe);
89545bc899bSmrg	return FALSE;
89645bc899bSmrg    }
89745bc899bSmrg    memcpy(pVesa->Options, VESAOptions, sizeof(VESAOptions));
89845bc899bSmrg    xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pVesa->Options);
89945bc899bSmrg
900a0c41156Smrg    /* Use shadow by default, for non-virt hardware */
901a0c41156Smrg    if (!xf86GetOptValBool(pVesa->Options, OPTION_SHADOW_FB, &pVesa->shadowFB))
902a0c41156Smrg    {
903a0c41156Smrg	switch (pVesa->pciInfo->vendor_id) {
904a0c41156Smrg	    case 0x1234: /* bochs vga (not in pci.ids) */
905a0c41156Smrg	    case 0x15ad: /* vmware */
906a0c41156Smrg	    case 0x1b36: /* qemu qxl */
907a0c41156Smrg	    case 0x80ee: /* virtualbox */
908a0c41156Smrg	    case 0xaaaa: /* parallels (not in pci.ids) */
909a0c41156Smrg		pVesa->shadowFB = FALSE;
910a0c41156Smrg		break;
911a0c41156Smrg
912a0c41156Smrg	    case 0x1013: /* qemu's cirrus emulation */
913a0c41156Smrg		if (pVesa->pciInfo->subvendor_id == 0x1af4)
914a0c41156Smrg		    pVesa->shadowFB = FALSE;
915a0c41156Smrg		else
916a0c41156Smrg		    pVesa->shadowFB = TRUE;
917a0c41156Smrg		break;
918a0c41156Smrg
919a0c41156Smrg	    case 0x1414: /* microsoft hyper-v */
920a0c41156Smrg		if (pVesa->pciInfo->device_id == 0x5353)
921a0c41156Smrg		    pVesa->shadowFB = FALSE;
922a0c41156Smrg		else
923a0c41156Smrg		    pVesa->shadowFB = TRUE;
924a0c41156Smrg		break;
925a0c41156Smrg
926a0c41156Smrg	    default:
927a0c41156Smrg		pVesa->shadowFB = TRUE;
928a0c41156Smrg		break;
929a0c41156Smrg	}
930a0c41156Smrg    }
931a0c41156Smrg
932f2408745Smrg    /*  Use default refresh by default. Too many VBE 3.0
933f2408745Smrg     *   BIOSes are incorrectly implemented.
934f2408745Smrg     */
935f2408745Smrg    pVesa->defaultRefresh = xf86ReturnOptValBool(pVesa->Options,
936f2408745Smrg                                                 OPTION_DFLT_REFRESH, TRUE);
93745bc899bSmrg
938c97b1c41Smrg    pVesa->ModeSetClearScreen =
939c97b1c41Smrg        xf86ReturnOptValBool(pVesa->Options,
940c97b1c41Smrg                             OPTION_MODESET_CLEAR_SCREEN, FALSE);
94145bc899bSmrg
94250f2e948Smrg    if (!pVesa->defaultRefresh && !pVesa->strict_validation)
94345bc899bSmrg	VBESetModeParameters(pScrn, pVesa->pVbe);
94445bc899bSmrg
94545bc899bSmrg    mode = ((VbeModeInfoData*)pScrn->modes->Private)->data;
94645bc899bSmrg    switch (mode->MemoryModel) {
94745bc899bSmrg	case 0x4:	/* Packed pixel */
94850f2e948Smrg	case 0x6:	/* Direct Color */
94945bc899bSmrg	    pScrn->bitmapBitOrder = BITMAP_BIT_ORDER;
95045bc899bSmrg
95145bc899bSmrg	    switch (pScrn->bitsPerPixel) {
95245bc899bSmrg		case 8:
95345bc899bSmrg		case 16:
95445bc899bSmrg		case 24:
95545bc899bSmrg		case 32:
95645bc899bSmrg		    break;
95745bc899bSmrg		default:
95845bc899bSmrg		    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
959a0c41156Smrg			       "Unsupported bpp: %d\n", pScrn->bitsPerPixel);
96045bc899bSmrg		    vbeFree(pVesa->pVbe);
96145bc899bSmrg		    return FALSE;
96245bc899bSmrg	    }
96345bc899bSmrg	    break;
96450f2e948Smrg	default:
96550f2e948Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
966a0c41156Smrg		       "Unsupported Memory Model: %d\n", mode->MemoryModel);
96750f2e948Smrg	    return FALSE;
96845bc899bSmrg    }
96945bc899bSmrg
97045bc899bSmrg    if (pVesa->shadowFB) {
97145bc899bSmrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Using \"Shadow Framebuffer\"\n");
97245bc899bSmrg	if (!xf86LoadSubModule(pScrn, "shadow")) {
97345bc899bSmrg	    vbeFree(pVesa->pVbe);
97445bc899bSmrg	    return (FALSE);
97545bc899bSmrg	}
97645bc899bSmrg    }
97745bc899bSmrg
97850f2e948Smrg    if (xf86LoadSubModule(pScrn, "fb") == NULL) {
97945bc899bSmrg	VESAFreeRec(pScrn);
98045bc899bSmrg        vbeFree(pVesa->pVbe);
98145bc899bSmrg	return (FALSE);
98245bc899bSmrg    }
98345bc899bSmrg
98445bc899bSmrg    vbeFree(pVesa->pVbe);
98545bc899bSmrg
98645bc899bSmrg    return (TRUE);
98745bc899bSmrg}
98845bc899bSmrg
98945bc899bSmrgstatic Bool
99045bc899bSmrgvesaCreateScreenResources(ScreenPtr pScreen)
99145bc899bSmrg{
992b40a6198Smrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
99345bc899bSmrg    VESAPtr pVesa = VESAGetRec(pScrn);
99445bc899bSmrg    Bool ret;
99545bc899bSmrg
99645bc899bSmrg    pScreen->CreateScreenResources = pVesa->CreateScreenResources;
99745bc899bSmrg    ret = pScreen->CreateScreenResources(pScreen);
99845bc899bSmrg    pScreen->CreateScreenResources = vesaCreateScreenResources;
99945bc899bSmrg
100045bc899bSmrg    shadowAdd(pScreen, pScreen->GetScreenPixmap(pScreen), pVesa->update,
100145bc899bSmrg	      pVesa->window, 0, 0);
100245bc899bSmrg
100345bc899bSmrg    return ret;
100445bc899bSmrg}
100545bc899bSmrg
100650f2e948Smrgstatic void
1007b40a6198SmrgvesaEnableDisableFBAccess(SCRN_ARG_TYPE arg, Bool enable)
100850f2e948Smrg{
1009b40a6198Smrg    SCRN_INFO_PTR(arg);
101050f2e948Smrg    VESAPtr pVesa = VESAGetRec(pScrn);
101150f2e948Smrg
101250f2e948Smrg    pVesa->accessEnabled = enable;
1013b40a6198Smrg    pVesa->EnableDisableFBAccess(arg, enable);
101450f2e948Smrg}
101550f2e948Smrg
101645bc899bSmrgstatic Bool
1017b40a6198SmrgVESAScreenInit(SCREEN_INIT_ARGS_DECL)
101845bc899bSmrg{
1019b40a6198Smrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
102045bc899bSmrg    VESAPtr pVesa = VESAGetRec(pScrn);
102145bc899bSmrg    VisualPtr visual;
102245bc899bSmrg    VbeModeInfoBlock *mode;
102345bc899bSmrg    int flags;
102445bc899bSmrg
102545bc899bSmrg    if ((pVesa->pVbe = VBEExtendedInit(NULL, pVesa->pEnt->index,
102645bc899bSmrg				       SET_BIOS_SCRATCH
102745bc899bSmrg				       | RESTORE_BIOS_SCRATCH)) == NULL)
102845bc899bSmrg        return (FALSE);
102945bc899bSmrg
103045bc899bSmrg    if (pVesa->mapPhys == 0) {
103145bc899bSmrg	mode = ((VbeModeInfoData*)(pScrn->currentMode->Private))->data;
103245bc899bSmrg	pScrn->videoRam = pVesa->mapSize;
103345bc899bSmrg	pVesa->mapPhys = mode->PhysBasePtr;
103445bc899bSmrg	pVesa->mapOff = 0;
103545bc899bSmrg    }
103645bc899bSmrg
103745bc899bSmrg    if (pVesa->mapPhys == 0) {
103845bc899bSmrg	pVesa->mapPhys = 0xa0000;
103945bc899bSmrg	pVesa->mapSize = 0x10000;
104045bc899bSmrg    }
104145bc899bSmrg
104245bc899bSmrg    if (!VESAMapVidMem(pScrn)) {
104345bc899bSmrg	if (pVesa->mapPhys != 0xa0000) {
104445bc899bSmrg	    pVesa->mapPhys = 0xa0000;
104545bc899bSmrg	    pVesa->mapSize = 0x10000;
104645bc899bSmrg	    if (!VESAMapVidMem(pScrn))
104745bc899bSmrg		return (FALSE);
104845bc899bSmrg	}
104945bc899bSmrg	else
105045bc899bSmrg	    return (FALSE);
105145bc899bSmrg    }
105245bc899bSmrg
105345bc899bSmrg    /* Set bpp to 8 for depth 4 when using shadowfb. */
105445bc899bSmrg    if (pVesa->shadowFB && pScrn->bitsPerPixel == 4)
105545bc899bSmrg	pScrn->bitsPerPixel = 8;
105645bc899bSmrg
105745bc899bSmrg    if (pVesa->shadowFB) {
1058b40a6198Smrg	pVesa->shadow = calloc(1, pScrn->displayWidth * pScrn->virtualY *
105945bc899bSmrg				   ((pScrn->bitsPerPixel + 7) / 8));
106045bc899bSmrg	if (!pVesa->shadow) {
106145bc899bSmrg	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
106245bc899bSmrg		       "Failed to allocate shadow buffer\n");
106345bc899bSmrg	    return FALSE;
106445bc899bSmrg	}
106545bc899bSmrg    }
106645bc899bSmrg
106745bc899bSmrg    /* save current video state */
106845bc899bSmrg    VESASaveRestore(pScrn, MODE_SAVE);
106945bc899bSmrg    pVesa->savedPal = VBESetGetPaletteData(pVesa->pVbe, FALSE, 0, 256,
107045bc899bSmrg					    NULL, FALSE, FALSE);
107145bc899bSmrg
107245bc899bSmrg    /* set first video mode */
107345bc899bSmrg    if (!VESASetMode(pScrn, pScrn->currentMode))
107445bc899bSmrg	return (FALSE);
107545bc899bSmrg
107645bc899bSmrg    /* set the viewport */
1077b40a6198Smrg    VESAAdjustFrame(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0));
107845bc899bSmrg
107945bc899bSmrg    /* Blank the screen for aesthetic reasons. */
108045bc899bSmrg    VESASaveScreen(pScreen, SCREEN_SAVER_ON);
108145bc899bSmrg
108245bc899bSmrg    /* mi layer */
108345bc899bSmrg    miClearVisualTypes();
108445bc899bSmrg    if (!xf86SetDefaultVisual(pScrn, -1))
108545bc899bSmrg	return (FALSE);
108645bc899bSmrg    if (pScrn->bitsPerPixel > 8) {
108745bc899bSmrg	if (!miSetVisualTypes(pScrn->depth, TrueColorMask,
108845bc899bSmrg			      pScrn->rgbBits, TrueColor))
108945bc899bSmrg	    return (FALSE);
109045bc899bSmrg    }
109145bc899bSmrg    else {
109245bc899bSmrg	if (!miSetVisualTypes(pScrn->depth,
109345bc899bSmrg			      miGetDefaultVisualMask(pScrn->depth),
109445bc899bSmrg			      pScrn->rgbBits, pScrn->defaultVisual))
109545bc899bSmrg	    return (FALSE);
109645bc899bSmrg    }
109745bc899bSmrg    if (!miSetPixmapDepths())
109845bc899bSmrg	return (FALSE);
109945bc899bSmrg
110045bc899bSmrg    mode = ((VbeModeInfoData*)pScrn->modes->Private)->data;
110145bc899bSmrg    switch (mode->MemoryModel) {
110245bc899bSmrg	case 0x4:	/* Packed pixel */
110350f2e948Smrg	case 0x6:	/* Direct Color */
110445bc899bSmrg	    switch (pScrn->bitsPerPixel) {
110545bc899bSmrg		case 8:
110645bc899bSmrg		case 16:
110745bc899bSmrg		case 24:
110845bc899bSmrg		case 32:
110945bc899bSmrg		    if (!fbScreenInit(pScreen,
111045bc899bSmrg				pVesa->shadowFB ? pVesa->shadow : pVesa->base,
111145bc899bSmrg				       pScrn->virtualX, pScrn->virtualY,
111245bc899bSmrg				       pScrn->xDpi, pScrn->yDpi,
111345bc899bSmrg				       pScrn->displayWidth, pScrn->bitsPerPixel))
111445bc899bSmrg			return (FALSE);
111545bc899bSmrg		    break;
111645bc899bSmrg		default:
111745bc899bSmrg		    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
111845bc899bSmrg			       "Unsupported bpp: %d", pScrn->bitsPerPixel);
111945bc899bSmrg		    return (FALSE);
112045bc899bSmrg	    }
112145bc899bSmrg	    break;
112250f2e948Smrg	default:
112350f2e948Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
112450f2e948Smrg		       "Unsupported Memory Model: %d", mode->MemoryModel);
112550f2e948Smrg	    return (FALSE);
112645bc899bSmrg    }
112745bc899bSmrg
112845bc899bSmrg
112945bc899bSmrg    if (pScrn->bitsPerPixel > 8) {
113045bc899bSmrg	/* Fixup RGB ordering */
113145bc899bSmrg	visual = pScreen->visuals + pScreen->numVisuals;
113245bc899bSmrg	while (--visual >= pScreen->visuals) {
113345bc899bSmrg	    if ((visual->class | DynamicClass) == DirectColor) {
113445bc899bSmrg		visual->offsetRed   = pScrn->offset.red;
113545bc899bSmrg		visual->offsetGreen = pScrn->offset.green;
113645bc899bSmrg		visual->offsetBlue  = pScrn->offset.blue;
113745bc899bSmrg		visual->redMask     = pScrn->mask.red;
113845bc899bSmrg		visual->greenMask   = pScrn->mask.green;
113945bc899bSmrg		visual->blueMask    = pScrn->mask.blue;
114045bc899bSmrg	    }
114145bc899bSmrg	}
114245bc899bSmrg    }
114345bc899bSmrg
114445bc899bSmrg    /* must be after RGB ordering fixed */
11455592a31fSmrg    fbPictureInit(pScreen, 0, 0);
114645bc899bSmrg
114745bc899bSmrg    if (pVesa->shadowFB) {
114850f2e948Smrg	if (pVesa->mapPhys == 0xa0000) {	/* Windowed */
11495592a31fSmrg	    pVesa->update = vesaUpdatePacked;
115045bc899bSmrg	    pVesa->window = VESAWindowWindowed;
115145bc899bSmrg	}
115245bc899bSmrg	else {	/* Linear */
11535592a31fSmrg	    pVesa->update = vesaUpdatePacked;
115445bc899bSmrg	    pVesa->window = VESAWindowLinear;
115545bc899bSmrg	}
115645bc899bSmrg
115745bc899bSmrg	if (!shadowSetup(pScreen))
115845bc899bSmrg	    return FALSE;
115945bc899bSmrg	pVesa->CreateScreenResources = pScreen->CreateScreenResources;
116045bc899bSmrg	pScreen->CreateScreenResources = vesaCreateScreenResources;
116145bc899bSmrg    }
116250f2e948Smrg    else if (pVesa->mapPhys == 0xa0000) {
11635592a31fSmrg        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
11645592a31fSmrg                   "Banked framebuffer requires ShadowFB\n");
11655592a31fSmrg        return FALSE;
116645bc899bSmrg    }
116745bc899bSmrg
116845bc899bSmrg    VESADGAInit(pScrn, pScreen);
116945bc899bSmrg
117045bc899bSmrg    xf86SetBlackWhitePixels(pScreen);
117145bc899bSmrg    xf86SetBackingStore(pScreen);
117245bc899bSmrg
117345bc899bSmrg    /* software cursor */
117445bc899bSmrg    miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
117545bc899bSmrg
117645bc899bSmrg    /* colormap */
117745bc899bSmrg    if (!miCreateDefColormap(pScreen))
117845bc899bSmrg	return (FALSE);
117945bc899bSmrg
118045bc899bSmrg    flags = CMAP_RELOAD_ON_MODE_SWITCH;
118145bc899bSmrg
118245bc899bSmrg    if(!xf86HandleColormaps(pScreen, 256,
118345bc899bSmrg	pVesa->vbeInfo->Capabilities[0] & 0x01 ? 8 : 6,
118445bc899bSmrg	VESALoadPalette, NULL, flags))
118545bc899bSmrg	return (FALSE);
118645bc899bSmrg
118750f2e948Smrg    pVesa->accessEnabled = TRUE;
118850f2e948Smrg    pVesa->EnableDisableFBAccess = pScrn->EnableDisableFBAccess;
118950f2e948Smrg    pScrn->EnableDisableFBAccess = vesaEnableDisableFBAccess;
119050f2e948Smrg
119145bc899bSmrg    pVesa->CloseScreen = pScreen->CloseScreen;
119245bc899bSmrg    pScreen->CloseScreen = VESACloseScreen;
119345bc899bSmrg    pScreen->SaveScreen = VESASaveScreen;
119445bc899bSmrg
119545bc899bSmrg    xf86DPMSInit(pScreen, VESADisplayPowerManagementSet, 0);
119645bc899bSmrg
119745bc899bSmrg    /* Report any unused options (only for the first generation) */
119845bc899bSmrg    if (serverGeneration == 1)
119945bc899bSmrg        xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
120045bc899bSmrg
120145bc899bSmrg    return (TRUE);
120245bc899bSmrg}
120345bc899bSmrg
120445bc899bSmrgstatic Bool
1205b40a6198SmrgVESAEnterVT(VT_FUNC_ARGS_DECL)
120645bc899bSmrg{
1207b40a6198Smrg    SCRN_INFO_PTR(arg);
120845bc899bSmrg
120945bc899bSmrg    if (!VESASetMode(pScrn, pScrn->currentMode))
121045bc899bSmrg	return FALSE;
1211b40a6198Smrg    VESAAdjustFrame(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0));
121245bc899bSmrg    return TRUE;
121345bc899bSmrg}
121445bc899bSmrg
121545bc899bSmrgstatic void
1216b40a6198SmrgVESALeaveVT(VT_FUNC_ARGS_DECL)
121745bc899bSmrg{
1218b40a6198Smrg    SCRN_INFO_PTR(arg);
1219b40a6198Smrg    VESASaveRestore(pScrn, MODE_RESTORE);
122045bc899bSmrg}
122145bc899bSmrg
122245bc899bSmrgstatic Bool
1223b40a6198SmrgVESACloseScreen(CLOSE_SCREEN_ARGS_DECL)
122445bc899bSmrg{
1225b40a6198Smrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
122645bc899bSmrg    VESAPtr pVesa = VESAGetRec(pScrn);
122745bc899bSmrg
122845bc899bSmrg    if (pScrn->vtSema) {
1229b40a6198Smrg	VESASaveRestore(pScrn, MODE_RESTORE);
123045bc899bSmrg	if (pVesa->savedPal)
123145bc899bSmrg	    VBESetGetPaletteData(pVesa->pVbe, TRUE, 0, 256,
123245bc899bSmrg				 pVesa->savedPal, FALSE, TRUE);
123345bc899bSmrg	VESAUnmapVidMem(pScrn);
123445bc899bSmrg    }
12355592a31fSmrg    if (pVesa->shadowFB && pVesa->shadow) {
12365592a31fSmrg	shadowRemove(pScreen, pScreen->GetScreenPixmap(pScreen));
1237b40a6198Smrg	free(pVesa->shadow);
12385592a31fSmrg    }
123945bc899bSmrg    if (pVesa->pDGAMode) {
1240b40a6198Smrg	free(pVesa->pDGAMode);
124145bc899bSmrg	pVesa->pDGAMode = NULL;
124245bc899bSmrg	pVesa->nDGAMode = 0;
124345bc899bSmrg    }
124445bc899bSmrg    pScrn->vtSema = FALSE;
124545bc899bSmrg
124650f2e948Smrg    pScrn->EnableDisableFBAccess = pVesa->EnableDisableFBAccess;
124745bc899bSmrg    pScreen->CreateScreenResources = pVesa->CreateScreenResources;
124845bc899bSmrg    pScreen->CloseScreen = pVesa->CloseScreen;
1249b40a6198Smrg    return pScreen->CloseScreen(CLOSE_SCREEN_ARGS);
125045bc899bSmrg}
125145bc899bSmrg
125245bc899bSmrgstatic Bool
1253b40a6198SmrgVESASwitchMode(SWITCH_MODE_ARGS_DECL)
125445bc899bSmrg{
1255b40a6198Smrg    SCRN_INFO_PTR(arg);
125645bc899bSmrg    VESAPtr pVesa = VESAGetRec(pScrn);
125750f2e948Smrg    Bool ret, disableAccess = pVesa->ModeSetClearScreen && pVesa->accessEnabled;
125845bc899bSmrg
125950f2e948Smrg    if (disableAccess)
1260b40a6198Smrg        pScrn->EnableDisableFBAccess(SCRN_OR_INDEX_ARG(pScrn),FALSE);
1261b40a6198Smrg    ret = VESASetMode(pScrn, mode);
126250f2e948Smrg    if (disableAccess)
1263b40a6198Smrg	pScrn->EnableDisableFBAccess(SCRN_OR_INDEX_ARG(pScrn),TRUE);
126445bc899bSmrg    return ret;
126545bc899bSmrg}
126645bc899bSmrg
126745bc899bSmrg/* Set a graphics mode */
126845bc899bSmrgstatic Bool
126945bc899bSmrgVESASetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode)
127045bc899bSmrg{
127145bc899bSmrg    VESAPtr pVesa;
127245bc899bSmrg    VbeModeInfoData *data;
127345bc899bSmrg    int mode;
127445bc899bSmrg
127545bc899bSmrg    pVesa = VESAGetRec(pScrn);
127645bc899bSmrg
127745bc899bSmrg    data = (VbeModeInfoData*)pMode->Private;
127850f2e948Smrg
127950f2e948Smrg    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
128050f2e948Smrg	       "Setting up VESA Mode 0x%X (%dx%d)\n",
128150f2e948Smrg	       data->mode & 0x7FF, pMode->HDisplay, pMode->VDisplay);
128250f2e948Smrg
128350f2e948Smrg    /* careful, setting the bit means don't clear the screen */
128450f2e948Smrg    mode = data->mode | (pVesa->ModeSetClearScreen ? 0 : (1U << 15));
128545bc899bSmrg
128645bc899bSmrg    /* enable linear addressing */
128745bc899bSmrg    if (pVesa->mapPhys != 0xa0000)
128845bc899bSmrg	mode |= 1 << 14;
128945bc899bSmrg
129045bc899bSmrg    if (VBESetVBEMode(pVesa->pVbe, mode, data->block) == FALSE) {
129145bc899bSmrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VBESetVBEMode failed");
129245bc899bSmrg	if ((data->block || (data->mode & (1 << 11))) &&
129345bc899bSmrg	    VBESetVBEMode(pVesa->pVbe, (mode & ~(1 << 11)), NULL) == TRUE) {
129445bc899bSmrg	    /* Some cards do not like setting the clock.
129545bc899bSmrg	     * Free it as it will not be any longer useful
129645bc899bSmrg	     */
12975592a31fSmrg	    xf86ErrorF(", mode set without customized refresh.\n");
1298b40a6198Smrg	    free(data->block);
129945bc899bSmrg	    data->block = NULL;
130045bc899bSmrg	    data->mode &= ~(1 << 11);
130145bc899bSmrg	}
130245bc899bSmrg	else {
130345bc899bSmrg	    ErrorF("\n");
130445bc899bSmrg	    return (FALSE);
130545bc899bSmrg	}
130645bc899bSmrg    }
130745bc899bSmrg
130845bc899bSmrg    pVesa->bankSwitchWindowB =
130945bc899bSmrg	!((data->data->WinBSegment == 0) && (data->data->WinBAttributes == 0));
131045bc899bSmrg
131145bc899bSmrg    if (data->data->XResolution != pScrn->displayWidth)
131245bc899bSmrg	VBESetLogicalScanline(pVesa->pVbe, pScrn->displayWidth);
131345bc899bSmrg
131445bc899bSmrg    if (pScrn->bitsPerPixel == 8 && pVesa->vbeInfo->Capabilities[0] & 0x01 &&
131550f2e948Smrg        !(data->data->MemoryModel == 0x6 || data->data->MemoryModel == 0x7))
131645bc899bSmrg	VBESetGetDACPaletteFormat(pVesa->pVbe, 8);
131745bc899bSmrg
131845bc899bSmrg    pScrn->vtSema = TRUE;
131945bc899bSmrg
132045bc899bSmrg    return (TRUE);
132145bc899bSmrg}
132245bc899bSmrg
132345bc899bSmrgstatic void
1324b40a6198SmrgVESAAdjustFrame(ADJUST_FRAME_ARGS_DECL)
132545bc899bSmrg{
1326b40a6198Smrg    SCRN_INFO_PTR(arg);
1327b40a6198Smrg    VESAPtr pVesa = VESAGetRec(pScrn);
132845bc899bSmrg
132945bc899bSmrg    VBESetDisplayStart(pVesa->pVbe, x, y, TRUE);
133045bc899bSmrg}
133145bc899bSmrg
133245bc899bSmrgstatic void
1333b40a6198SmrgVESAFreeScreen(FREE_SCREEN_ARGS_DECL)
133445bc899bSmrg{
1335b40a6198Smrg    SCRN_INFO_PTR(arg);
1336b40a6198Smrg    VESAFreeRec(pScrn);
133745bc899bSmrg}
133845bc899bSmrg
133945bc899bSmrgstatic Bool
134045bc899bSmrgVESAMapVidMem(ScrnInfoPtr pScrn)
134145bc899bSmrg{
134245bc899bSmrg    VESAPtr pVesa = VESAGetRec(pScrn);
134345bc899bSmrg
134445bc899bSmrg    if (pVesa->base != NULL)
134545bc899bSmrg	return (TRUE);
134645bc899bSmrg
134745bc899bSmrg    pScrn->memPhysBase = pVesa->mapPhys;
134845bc899bSmrg    pScrn->fbOffset = pVesa->mapOff;
134945bc899bSmrg
135050f2e948Smrg#ifdef XSERVER_LIBPCIACCESS
1351b40a6198Smrg    if (pVesa->pciInfo != NULL) {
1352b40a6198Smrg	if (pVesa->mapPhys != 0xa0000) {
1353b40a6198Smrg	    (void) pci_device_map_range(pVesa->pciInfo, pScrn->memPhysBase,
1354b40a6198Smrg	                                pVesa->mapSize,
1355b40a6198Smrg				        (PCI_DEV_MAP_FLAG_WRITABLE
1356b40a6198Smrg				         | PCI_DEV_MAP_FLAG_WRITE_COMBINE),
1357b40a6198Smrg				        & pVesa->base);
1358b40a6198Smrg
1359b40a6198Smrg	    if (pVesa->base)
1360b40a6198Smrg		(void) pci_device_map_legacy(pVesa->pciInfo, 0xa0000, 0x10000,
1361b40a6198Smrg		                             PCI_DEV_MAP_FLAG_WRITABLE,
1362b40a6198Smrg		                             & pVesa->VGAbase);
1363b40a6198Smrg	}
1364b40a6198Smrg	else {
1365b40a6198Smrg	    (void) pci_device_map_legacy(pVesa->pciInfo, pScrn->memPhysBase,
1366b40a6198Smrg	                                 pVesa->mapSize,
1367b40a6198Smrg	                                 PCI_DEV_MAP_FLAG_WRITABLE,
1368b40a6198Smrg	                                 & pVesa->base);
136950f2e948Smrg
1370b40a6198Smrg	    if (pVesa->base)
1371b40a6198Smrg		pVesa->VGAbase = pVesa->base;
1372b40a6198Smrg	}
137350f2e948Smrg    }
137450f2e948Smrg#else
137545bc899bSmrg    if (pVesa->mapPhys != 0xa0000 && pVesa->pEnt->location.type == BUS_PCI)
137645bc899bSmrg	pVesa->base = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
137745bc899bSmrg				    pVesa->pciTag, pScrn->memPhysBase,
137845bc899bSmrg				    pVesa->mapSize);
137945bc899bSmrg    else
138045bc899bSmrg	pVesa->base = xf86MapDomainMemory(pScrn->scrnIndex, 0, pVesa->pciTag,
138145bc899bSmrg					  pScrn->memPhysBase, pVesa->mapSize);
138245bc899bSmrg
138345bc899bSmrg    if (pVesa->base) {
138445bc899bSmrg	if (pVesa->mapPhys != 0xa0000)
138545bc899bSmrg	    pVesa->VGAbase = xf86MapDomainMemory(pScrn->scrnIndex, 0,
138645bc899bSmrg						 pVesa->pciTag,
138745bc899bSmrg						 0xa0000, 0x10000);
138845bc899bSmrg	else
138945bc899bSmrg	    pVesa->VGAbase = pVesa->base;
139045bc899bSmrg    }
139150f2e948Smrg#endif
139245bc899bSmrg
1393b40a6198Smrg#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 12
139445bc899bSmrg    pVesa->ioBase = pScrn->domainIOBase;
1395b40a6198Smrg#else
1396b40a6198Smrg    pVesa->ioBase = 0;
1397b40a6198Smrg#endif
139845bc899bSmrg
139945bc899bSmrg    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, DEBUG_VERB,
1400b1fb1a22Smrg		   "virtual address = %p, VGAbase = %p\n"
140145bc899bSmrg		   "\tphysical address = 0x%lx, size = %ld\n",
1402b1fb1a22Smrg		   pVesa->base, pVesa->VGAbase,
1403b1fb1a22Smrg		   pScrn->memPhysBase, pVesa->mapSize);
140445bc899bSmrg
140545bc899bSmrg    return (pVesa->base != NULL);
140645bc899bSmrg}
140745bc899bSmrg
140845bc899bSmrgstatic void
140945bc899bSmrgVESAUnmapVidMem(ScrnInfoPtr pScrn)
141045bc899bSmrg{
141145bc899bSmrg    VESAPtr pVesa = VESAGetRec(pScrn);
141245bc899bSmrg
141345bc899bSmrg    if (pVesa->base == NULL)
141445bc899bSmrg	return;
141545bc899bSmrg
141650f2e948Smrg#ifdef XSERVER_LIBPCIACCESS
141750f2e948Smrg    if (pVesa->mapPhys != 0xa0000) {
141850f2e948Smrg	(void) pci_device_unmap_range(pVesa->pciInfo, pVesa->base,
141950f2e948Smrg				      pVesa->mapSize);
1420b40a6198Smrg	(void) pci_device_unmap_legacy(pVesa->pciInfo, pVesa->VGAbase,
1421b40a6198Smrg	                               0x10000);
142250f2e948Smrg    }
142350f2e948Smrg    else {
1424b40a6198Smrg	(void) pci_device_unmap_legacy(pVesa->pciInfo, pVesa->base,
1425b40a6198Smrg	                               pVesa->mapSize);
142650f2e948Smrg    }
142750f2e948Smrg#else
142845bc899bSmrg    xf86UnMapVidMem(pScrn->scrnIndex, pVesa->base, pVesa->mapSize);
142945bc899bSmrg    if (pVesa->mapPhys != 0xa0000)
143045bc899bSmrg	xf86UnMapVidMem(pScrn->scrnIndex, pVesa->VGAbase, 0x10000);
143150f2e948Smrg#endif
143245bc899bSmrg    pVesa->base = NULL;
143345bc899bSmrg}
143445bc899bSmrg
14355592a31fSmrg/* This code works, but is very slow for programs that use it intensively */
143645bc899bSmrgstatic void
143745bc899bSmrgVESALoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices,
143845bc899bSmrg		LOCO *colors, VisualPtr pVisual)
143945bc899bSmrg{
144045bc899bSmrg    VESAPtr pVesa = VESAGetRec(pScrn);
144145bc899bSmrg    int i, idx;
144245bc899bSmrg    int base;
144345bc899bSmrg
1444f2408745Smrg    if (!pVesa->savedPal) {
1445f2408745Smrg#define VESADACDelay()							       \
1446f2408745Smrg	do {                                                                   \
1447f2408745Smrg	   (void)inb(pVesa->ioBase + VGA_IOBASE_COLOR + VGA_IN_STAT_1_OFFSET); \
1448f2408745Smrg	   (void)inb(pVesa->ioBase + VGA_IOBASE_COLOR + VGA_IN_STAT_1_OFFSET); \
1449f2408745Smrg	} while (0)
1450f2408745Smrg
1451f2408745Smrg	for (i = 0; i < numColors; i++) {
1452f2408745Smrg	   idx = indices[i];
1453f2408745Smrg	   outb(pVesa->ioBase + VGA_DAC_WRITE_ADDR, idx);
1454f2408745Smrg	   VESADACDelay();
1455f2408745Smrg	   outb(pVesa->ioBase + VGA_DAC_DATA, colors[idx].red);
1456f2408745Smrg	   VESADACDelay();
1457f2408745Smrg	   outb(pVesa->ioBase + VGA_DAC_DATA, colors[idx].green);
1458f2408745Smrg	   VESADACDelay();
1459f2408745Smrg	   outb(pVesa->ioBase + VGA_DAC_DATA, colors[idx].blue);
1460f2408745Smrg	   VESADACDelay();
1461f2408745Smrg	}
1462f2408745Smrg	return;
1463f2408745Smrg    }
1464f2408745Smrg
146545bc899bSmrg    if (pVesa->pal == NULL)
1466b40a6198Smrg	pVesa->pal = calloc(1, sizeof(CARD32) * 256);
146745bc899bSmrg
146845bc899bSmrg    for (i = 0, base = idx = indices[i]; i < numColors; i++, idx++) {
146945bc899bSmrg	int j = indices[i];
147045bc899bSmrg
147145bc899bSmrg	if (j < 0 || j >= 256)
147245bc899bSmrg	    continue;
147345bc899bSmrg	pVesa->pal[j] = colors[j].blue |
147445bc899bSmrg			(colors[j].green << 8) |
147545bc899bSmrg			(colors[j].red << 16);
147645bc899bSmrg	if (j != idx) {
147745bc899bSmrg	    VBESetGetPaletteData(pVesa->pVbe, TRUE, base, idx - base,
147845bc899bSmrg				  pVesa->pal + base, FALSE, TRUE);
147945bc899bSmrg	    idx = base = j;
148045bc899bSmrg	}
148145bc899bSmrg    }
148245bc899bSmrg
148345bc899bSmrg    if (idx - 1 == indices[i - 1])
148445bc899bSmrg	VBESetGetPaletteData(pVesa->pVbe, TRUE, base, idx - base,
148545bc899bSmrg			      pVesa->pal + base, FALSE, TRUE);
148645bc899bSmrg}
148745bc899bSmrg
148845bc899bSmrg/*
148945bc899bSmrg * Just adapted from the std* functions in vgaHW.c
149045bc899bSmrg */
149145bc899bSmrgstatic void
149245bc899bSmrgWriteAttr(VESAPtr pVesa, int index, int value)
149345bc899bSmrg{
149445bc899bSmrg    (void) inb(pVesa->ioBase + VGA_IOBASE_COLOR + VGA_IN_STAT_1_OFFSET);
149545bc899bSmrg
149645bc899bSmrg    index |= 0x20;
149745bc899bSmrg    outb(pVesa->ioBase + VGA_ATTR_INDEX, index);
149845bc899bSmrg    outb(pVesa->ioBase + VGA_ATTR_DATA_W, value);
149945bc899bSmrg}
150045bc899bSmrg
150145bc899bSmrgstatic int
150245bc899bSmrgReadAttr(VESAPtr pVesa, int index)
150345bc899bSmrg{
150445bc899bSmrg    (void) inb(pVesa->ioBase + VGA_IOBASE_COLOR + VGA_IN_STAT_1_OFFSET);
150545bc899bSmrg
150645bc899bSmrg    index |= 0x20;
150745bc899bSmrg    outb(pVesa->ioBase + VGA_ATTR_INDEX, index);
150845bc899bSmrg    return (inb(pVesa->ioBase + VGA_ATTR_DATA_R));
150945bc899bSmrg}
151045bc899bSmrg
151145bc899bSmrg#define WriteMiscOut(value)	outb(pVesa->ioBase + VGA_MISC_OUT_W, value)
151245bc899bSmrg#define ReadMiscOut()		inb(pVesa->ioBase + VGA_MISC_OUT_R)
151345bc899bSmrg#define WriteSeq(index, value)	outb(pVesa->ioBase + VGA_SEQ_INDEX, index);\
151445bc899bSmrg				outb(pVesa->ioBase + VGA_SEQ_DATA, value)
151545bc899bSmrg
151645bc899bSmrgstatic int
151745bc899bSmrgReadSeq(VESAPtr pVesa, int index)
151845bc899bSmrg{
151945bc899bSmrg    outb(pVesa->ioBase + VGA_SEQ_INDEX, index);
152045bc899bSmrg
152145bc899bSmrg    return (inb(pVesa->ioBase + VGA_SEQ_DATA));
152245bc899bSmrg}
152345bc899bSmrg
152445bc899bSmrg#define WriteGr(index, value)				\
152545bc899bSmrg    outb(pVesa->ioBase + VGA_GRAPH_INDEX, index);	\
152645bc899bSmrg    outb(pVesa->ioBase + VGA_GRAPH_DATA, value)
152745bc899bSmrg
152845bc899bSmrgstatic int
152945bc899bSmrgReadGr(VESAPtr pVesa, int index)
153045bc899bSmrg{
153145bc899bSmrg    outb(pVesa->ioBase + VGA_GRAPH_INDEX, index);
153245bc899bSmrg
153345bc899bSmrg    return (inb(pVesa->ioBase + VGA_GRAPH_DATA));
153445bc899bSmrg}
153545bc899bSmrg
153645bc899bSmrg#define WriteCrtc(index, value)						     \
153745bc899bSmrg    outb(pVesa->ioBase + (VGA_IOBASE_COLOR + VGA_CRTC_INDEX_OFFSET), index); \
153845bc899bSmrg    outb(pVesa->ioBase + (VGA_IOBASE_COLOR + VGA_CRTC_DATA_OFFSET), value)
153945bc899bSmrg
154045bc899bSmrgstatic void
154145bc899bSmrgSeqReset(VESAPtr pVesa, Bool start)
154245bc899bSmrg{
154345bc899bSmrg    if (start) {
154445bc899bSmrg	WriteSeq(0x00, 0x01);		/* Synchronous Reset */
154545bc899bSmrg    }
154645bc899bSmrg    else {
154745bc899bSmrg	WriteSeq(0x00, 0x03);		/* End Reset */
154845bc899bSmrg    }
154945bc899bSmrg}
155045bc899bSmrg
155145bc899bSmrgstatic void
155245bc899bSmrgSaveFonts(ScrnInfoPtr pScrn)
155345bc899bSmrg{
155445bc899bSmrg    VESAPtr pVesa = VESAGetRec(pScrn);
155545bc899bSmrg    unsigned char miscOut, attr10, gr4, gr5, gr6, seq2, seq4, scrn;
155645bc899bSmrg
155745bc899bSmrg    if (pVesa->fonts != NULL)
155845bc899bSmrg	return;
155945bc899bSmrg
156045bc899bSmrg    /* If in graphics mode, don't save anything */
156145bc899bSmrg    attr10 = ReadAttr(pVesa, 0x10);
156245bc899bSmrg    if (attr10 & 0x01)
156345bc899bSmrg	return;
156445bc899bSmrg
1565b40a6198Smrg    pVesa->fonts = malloc(16384);
156645bc899bSmrg
156745bc899bSmrg    /* save the registers that are needed here */
156845bc899bSmrg    miscOut = ReadMiscOut();
156945bc899bSmrg    gr4 = ReadGr(pVesa, 0x04);
157045bc899bSmrg    gr5 = ReadGr(pVesa, 0x05);
157145bc899bSmrg    gr6 = ReadGr(pVesa, 0x06);
157245bc899bSmrg    seq2 = ReadSeq(pVesa, 0x02);
157345bc899bSmrg    seq4 = ReadSeq(pVesa, 0x04);
157445bc899bSmrg
157545bc899bSmrg    /* Force into colour mode */
157645bc899bSmrg    WriteMiscOut(miscOut | 0x01);
157745bc899bSmrg
157845bc899bSmrg    scrn = ReadSeq(pVesa, 0x01) | 0x20;
157945bc899bSmrg    SeqReset(pVesa, TRUE);
158045bc899bSmrg    WriteSeq(0x01, scrn);
158145bc899bSmrg    SeqReset(pVesa, FALSE);
158245bc899bSmrg
158345bc899bSmrg    WriteAttr(pVesa, 0x10, 0x01);	/* graphics mode */
158445bc899bSmrg
158545bc899bSmrg    /*font1 */
158645bc899bSmrg    WriteSeq(0x02, 0x04);	/* write to plane 2 */
158745bc899bSmrg    WriteSeq(0x04, 0x06);	/* enable plane graphics */
158845bc899bSmrg    WriteGr(0x04, 0x02);	/* read plane 2 */
158945bc899bSmrg    WriteGr(0x05, 0x00);	/* write mode 0, read mode 0 */
159045bc899bSmrg    WriteGr(0x06, 0x05);	/* set graphics */
159145bc899bSmrg    slowbcopy_frombus(pVesa->VGAbase, pVesa->fonts, 8192);
159245bc899bSmrg
159345bc899bSmrg    /* font2 */
159445bc899bSmrg    WriteSeq(0x02, 0x08);	/* write to plane 3 */
159545bc899bSmrg    WriteSeq(0x04, 0x06);	/* enable plane graphics */
159645bc899bSmrg    WriteGr(0x04, 0x03);	/* read plane 3 */
159745bc899bSmrg    WriteGr(0x05, 0x00);	/* write mode 0, read mode 0 */
159845bc899bSmrg    WriteGr(0x06, 0x05);	/* set graphics */
159945bc899bSmrg    slowbcopy_frombus(pVesa->VGAbase, pVesa->fonts + 8192, 8192);
160045bc899bSmrg
160145bc899bSmrg    scrn = ReadSeq(pVesa, 0x01) & ~0x20;
160245bc899bSmrg    SeqReset(pVesa, TRUE);
160345bc899bSmrg    WriteSeq(0x01, scrn);
160445bc899bSmrg    SeqReset(pVesa, FALSE);
160545bc899bSmrg
160645bc899bSmrg    /* Restore clobbered registers */
160745bc899bSmrg    WriteAttr(pVesa, 0x10, attr10);
160845bc899bSmrg    WriteSeq(0x02, seq2);
160945bc899bSmrg    WriteSeq(0x04, seq4);
161045bc899bSmrg    WriteGr(0x04, gr4);
161145bc899bSmrg    WriteGr(0x05, gr5);
161245bc899bSmrg    WriteGr(0x06, gr6);
161345bc899bSmrg    WriteMiscOut(miscOut);
161445bc899bSmrg}
161545bc899bSmrg
161645bc899bSmrgstatic void
161745bc899bSmrgRestoreFonts(ScrnInfoPtr pScrn)
161845bc899bSmrg{
161945bc899bSmrg    VESAPtr pVesa = VESAGetRec(pScrn);
162045bc899bSmrg    unsigned char miscOut, attr10, gr1, gr3, gr4, gr5, gr6, gr8, seq2, seq4, scrn;
162145bc899bSmrg
162245bc899bSmrg    if (pVesa->fonts == NULL)
162345bc899bSmrg	return;
162445bc899bSmrg
162545bc899bSmrg    if (pVesa->mapPhys == 0xa0000 && pVesa->curBank != 0)
162645bc899bSmrg	VESABankSwitch(pScrn->pScreen, 0);
162745bc899bSmrg
162845bc899bSmrg    /* save the registers that are needed here */
162945bc899bSmrg    miscOut = ReadMiscOut();
163045bc899bSmrg    attr10 = ReadAttr(pVesa, 0x10);
163145bc899bSmrg    gr1 = ReadGr(pVesa, 0x01);
163245bc899bSmrg    gr3 = ReadGr(pVesa, 0x03);
163345bc899bSmrg    gr4 = ReadGr(pVesa, 0x04);
163445bc899bSmrg    gr5 = ReadGr(pVesa, 0x05);
163545bc899bSmrg    gr6 = ReadGr(pVesa, 0x06);
163645bc899bSmrg    gr8 = ReadGr(pVesa, 0x08);
163745bc899bSmrg    seq2 = ReadSeq(pVesa, 0x02);
163845bc899bSmrg    seq4 = ReadSeq(pVesa, 0x04);
163945bc899bSmrg
164045bc899bSmrg    /* Force into colour mode */
164145bc899bSmrg    WriteMiscOut(miscOut | 0x01);
164245bc899bSmrg
164345bc899bSmrg    scrn = ReadSeq(pVesa, 0x01) | 0x20;
164445bc899bSmrg    SeqReset(pVesa, TRUE);
164545bc899bSmrg    WriteSeq(0x01, scrn);
164645bc899bSmrg    SeqReset(pVesa, FALSE);
164745bc899bSmrg
164845bc899bSmrg    WriteAttr(pVesa, 0x10, 0x01);	/* graphics mode */
164945bc899bSmrg    if (pScrn->depth == 4) {
165045bc899bSmrg	/* GJA */
165145bc899bSmrg	WriteGr(0x03, 0x00);	/* don't rotate, write unmodified */
165245bc899bSmrg	WriteGr(0x08, 0xFF);	/* write all bits in a byte */
165345bc899bSmrg	WriteGr(0x01, 0x00);	/* all planes come from CPU */
165445bc899bSmrg    }
165545bc899bSmrg
165645bc899bSmrg    WriteSeq(0x02, 0x04);   /* write to plane 2 */
165745bc899bSmrg    WriteSeq(0x04, 0x06);   /* enable plane graphics */
165845bc899bSmrg    WriteGr(0x04, 0x02);    /* read plane 2 */
165945bc899bSmrg    WriteGr(0x05, 0x00);    /* write mode 0, read mode 0 */
166045bc899bSmrg    WriteGr(0x06, 0x05);    /* set graphics */
166145bc899bSmrg    slowbcopy_tobus(pVesa->fonts, pVesa->VGAbase, 8192);
166245bc899bSmrg
166345bc899bSmrg    WriteSeq(0x02, 0x08);   /* write to plane 3 */
166445bc899bSmrg    WriteSeq(0x04, 0x06);   /* enable plane graphics */
166545bc899bSmrg    WriteGr(0x04, 0x03);    /* read plane 3 */
166645bc899bSmrg    WriteGr(0x05, 0x00);    /* write mode 0, read mode 0 */
166745bc899bSmrg    WriteGr(0x06, 0x05);    /* set graphics */
166845bc899bSmrg    slowbcopy_tobus(pVesa->fonts + 8192, pVesa->VGAbase, 8192);
166945bc899bSmrg
167045bc899bSmrg    scrn = ReadSeq(pVesa, 0x01) & ~0x20;
167145bc899bSmrg    SeqReset(pVesa, TRUE);
167245bc899bSmrg    WriteSeq(0x01, scrn);
167345bc899bSmrg    SeqReset(pVesa, FALSE);
167445bc899bSmrg
167545bc899bSmrg    /* restore the registers that were changed */
167645bc899bSmrg    WriteMiscOut(miscOut);
167745bc899bSmrg    WriteAttr(pVesa, 0x10, attr10);
167845bc899bSmrg    WriteGr(0x01, gr1);
167945bc899bSmrg    WriteGr(0x03, gr3);
168045bc899bSmrg    WriteGr(0x04, gr4);
168145bc899bSmrg    WriteGr(0x05, gr5);
168245bc899bSmrg    WriteGr(0x06, gr6);
168345bc899bSmrg    WriteGr(0x08, gr8);
168445bc899bSmrg    WriteSeq(0x02, seq2);
168545bc899bSmrg    WriteSeq(0x04, seq4);
168645bc899bSmrg}
168745bc899bSmrg
168845bc899bSmrgstatic Bool
168945bc899bSmrgVESASaveScreen(ScreenPtr pScreen, int mode)
169045bc899bSmrg{
1691b40a6198Smrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
169245bc899bSmrg    VESAPtr pVesa = VESAGetRec(pScrn);
169345bc899bSmrg    Bool on = xf86IsUnblank(mode);
169445bc899bSmrg
169545bc899bSmrg    if (on)
169645bc899bSmrg	SetTimeSinceLastInputEvent();
169745bc899bSmrg
169845bc899bSmrg    if (pScrn->vtSema) {
169945bc899bSmrg	unsigned char scrn = ReadSeq(pVesa, 0x01);
170045bc899bSmrg
170145bc899bSmrg	if (on)
170245bc899bSmrg	    scrn &= ~0x20;
170345bc899bSmrg	else
170445bc899bSmrg	    scrn |= 0x20;
170545bc899bSmrg	SeqReset(pVesa, TRUE);
170645bc899bSmrg	WriteSeq(0x01, scrn);
170745bc899bSmrg	SeqReset(pVesa, FALSE);
170845bc899bSmrg    }
170945bc899bSmrg
171045bc899bSmrg    return (TRUE);
171145bc899bSmrg}
171245bc899bSmrg
171345bc899bSmrgstatic int
171445bc899bSmrgVESABankSwitch(ScreenPtr pScreen, unsigned int iBank)
171545bc899bSmrg{
1716b40a6198Smrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
171745bc899bSmrg    VESAPtr pVesa = VESAGetRec(pScrn);
171845bc899bSmrg
171945bc899bSmrg    if (pVesa->curBank == iBank)
172045bc899bSmrg	return (0);
172145bc899bSmrg    if (!VBEBankSwitch(pVesa->pVbe, iBank, 0))
172245bc899bSmrg        return (1);
172345bc899bSmrg    if (pVesa->bankSwitchWindowB) {
172445bc899bSmrg        if (!VBEBankSwitch(pVesa->pVbe, iBank, 1))
172545bc899bSmrg	   return (1);
172645bc899bSmrg    }
172745bc899bSmrg    pVesa->curBank = iBank;
172845bc899bSmrg
172945bc899bSmrg    return (0);
173045bc899bSmrg}
173145bc899bSmrg
173245bc899bSmrgBool
173345bc899bSmrgVESASaveRestore(ScrnInfoPtr pScrn, vbeSaveRestoreFunction function)
173445bc899bSmrg{
173545bc899bSmrg    VESAPtr pVesa;
173645bc899bSmrg
1737c97b1c41Smrg    if (function < MODE_QUERY || function > MODE_RESTORE)
173845bc899bSmrg	return (FALSE);
173945bc899bSmrg
174045bc899bSmrg    pVesa = VESAGetRec(pScrn);
174145bc899bSmrg
174245bc899bSmrg
174345bc899bSmrg    /* Query amount of memory to save state */
174445bc899bSmrg    if (function == MODE_QUERY ||
174545bc899bSmrg	(function == MODE_SAVE && pVesa->state == NULL)) {
174645bc899bSmrg
174745bc899bSmrg	/* Make sure we save at least this information in case of failure */
174845bc899bSmrg	(void)VBEGetVBEMode(pVesa->pVbe, &pVesa->stateMode);
174945bc899bSmrg	SaveFonts(pScrn);
175045bc899bSmrg
175145bc899bSmrg	if (pVesa->major > 1) {
175245bc899bSmrg	    if (!VBESaveRestore(pVesa->pVbe,function,(pointer)&pVesa->state,
175345bc899bSmrg				&pVesa->stateSize,&pVesa->statePage))
175445bc899bSmrg	        return FALSE;
175545bc899bSmrg
175645bc899bSmrg	}
175745bc899bSmrg    }
175845bc899bSmrg
175945bc899bSmrg    /* Save/Restore Super VGA state */
176045bc899bSmrg    if (function != MODE_QUERY) {
176145bc899bSmrg        Bool retval = TRUE;
176245bc899bSmrg
176345bc899bSmrg	if (pVesa->major > 1) {
176445bc899bSmrg	    if (function == MODE_RESTORE)
176545bc899bSmrg		memcpy(pVesa->state, pVesa->pstate, pVesa->stateSize);
176645bc899bSmrg
176745bc899bSmrg	    if ((retval = VBESaveRestore(pVesa->pVbe,function,
176845bc899bSmrg					 (pointer)&pVesa->state,
176945bc899bSmrg					 &pVesa->stateSize,&pVesa->statePage))
177045bc899bSmrg		&& function == MODE_SAVE) {
177145bc899bSmrg	        /* don't rely on the memory not being touched */
177245bc899bSmrg	        if (pVesa->pstate == NULL)
1773b40a6198Smrg		    pVesa->pstate = malloc(pVesa->stateSize);
177445bc899bSmrg		memcpy(pVesa->pstate, pVesa->state, pVesa->stateSize);
177545bc899bSmrg	    }
177645bc899bSmrg	}
177745bc899bSmrg
177845bc899bSmrg	if (function == MODE_RESTORE) {
177945bc899bSmrg	    VBESetVBEMode(pVesa->pVbe, pVesa->stateMode, NULL);
178045bc899bSmrg	    RestoreFonts(pScrn);
178145bc899bSmrg	}
178245bc899bSmrg
178345bc899bSmrg	if (!retval)
178445bc899bSmrg	    return (FALSE);
178545bc899bSmrg
178645bc899bSmrg    }
178745bc899bSmrg
178845bc899bSmrg    return (TRUE);
178945bc899bSmrg}
179045bc899bSmrg
179145bc899bSmrgstatic void
179245bc899bSmrgVESADisplayPowerManagementSet(ScrnInfoPtr pScrn, int mode,
179345bc899bSmrg                int flags)
179445bc899bSmrg{
179545bc899bSmrg    VESAPtr pVesa = VESAGetRec(pScrn);
179645bc899bSmrg
179745bc899bSmrg    if (!pScrn->vtSema)
179845bc899bSmrg	return;
179945bc899bSmrg
180050f2e948Smrg    VBEDPMSSet(pVesa->pVbe, mode);
180145bc899bSmrg}
180245bc899bSmrg
180345bc899bSmrg/***********************************************************************
180445bc899bSmrg * DGA stuff
180545bc899bSmrg ***********************************************************************/
180645bc899bSmrgstatic Bool VESADGAOpenFramebuffer(ScrnInfoPtr pScrn, char **DeviceName,
180745bc899bSmrg				   unsigned char **ApertureBase,
180845bc899bSmrg				   int *ApertureSize, int *ApertureOffset,
180945bc899bSmrg				   int *flags);
181045bc899bSmrgstatic Bool VESADGASetMode(ScrnInfoPtr pScrn, DGAModePtr pDGAMode);
181145bc899bSmrgstatic void VESADGASetViewport(ScrnInfoPtr pScrn, int x, int y, int flags);
181245bc899bSmrg
181345bc899bSmrgstatic Bool
181445bc899bSmrgVESADGAOpenFramebuffer(ScrnInfoPtr pScrn, char **DeviceName,
181545bc899bSmrg		       unsigned char **ApertureBase, int *ApertureSize,
181645bc899bSmrg		       int *ApertureOffset, int *flags)
181745bc899bSmrg{
181845bc899bSmrg    VESAPtr pVesa = VESAGetRec(pScrn);
181945bc899bSmrg
182045bc899bSmrg    *DeviceName = NULL;		/* No special device */
182145bc899bSmrg    *ApertureBase = (unsigned char *)(long)(pVesa->mapPhys);
182245bc899bSmrg    *ApertureSize = pVesa->mapSize;
182345bc899bSmrg    *ApertureOffset = pVesa->mapOff;
182445bc899bSmrg    *flags = DGA_NEED_ROOT;
182545bc899bSmrg
182645bc899bSmrg    return (TRUE);
182745bc899bSmrg}
182845bc899bSmrg
182945bc899bSmrgstatic Bool
183045bc899bSmrgVESADGASetMode(ScrnInfoPtr pScrn, DGAModePtr pDGAMode)
183145bc899bSmrg{
183245bc899bSmrg    DisplayModePtr pMode;
183345bc899bSmrg    int frameX0, frameY0;
183445bc899bSmrg
183545bc899bSmrg    if (pDGAMode) {
183645bc899bSmrg	pMode = pDGAMode->mode;
183745bc899bSmrg	frameX0 = frameY0 = 0;
183845bc899bSmrg    }
183945bc899bSmrg    else {
184045bc899bSmrg	if (!(pMode = pScrn->currentMode))
184145bc899bSmrg	    return (TRUE);
184245bc899bSmrg
184345bc899bSmrg	frameX0 = pScrn->frameX0;
184445bc899bSmrg	frameY0 = pScrn->frameY0;
184545bc899bSmrg    }
184645bc899bSmrg
1847b40a6198Smrg    if (!(*pScrn->SwitchMode)(SWITCH_MODE_ARGS(pScrn, pMode)))
184845bc899bSmrg	return (FALSE);
1849b40a6198Smrg    (*pScrn->AdjustFrame)(ADJUST_FRAME_ARGS(pScrn, frameX0, frameY0));
185045bc899bSmrg
185145bc899bSmrg    return (TRUE);
185245bc899bSmrg}
185345bc899bSmrg
185445bc899bSmrgstatic void
185545bc899bSmrgVESADGASetViewport(ScrnInfoPtr pScrn, int x, int y, int flags)
185645bc899bSmrg{
1857b40a6198Smrg    (*pScrn->AdjustFrame)(ADJUST_FRAME_ARGS(pScrn, x, y));
185845bc899bSmrg}
185945bc899bSmrg
186045bc899bSmrgstatic int
186145bc899bSmrgVESADGAGetViewport(ScrnInfoPtr pScrn)
186245bc899bSmrg{
186345bc899bSmrg    return (0);
186445bc899bSmrg}
186545bc899bSmrg
186645bc899bSmrgstatic DGAFunctionRec VESADGAFunctions =
186745bc899bSmrg{
186845bc899bSmrg    VESADGAOpenFramebuffer,
186945bc899bSmrg    NULL,       /* CloseFramebuffer */
187045bc899bSmrg    VESADGASetMode,
187145bc899bSmrg    VESADGASetViewport,
187245bc899bSmrg    VESADGAGetViewport,
187345bc899bSmrg    NULL,       /* Sync */
187445bc899bSmrg    NULL,       /* FillRect */
187545bc899bSmrg    NULL,       /* BlitRect */
187645bc899bSmrg    NULL,       /* BlitTransRect */
187745bc899bSmrg};
187845bc899bSmrg
187945bc899bSmrgstatic void
188045bc899bSmrgVESADGAAddModes(ScrnInfoPtr pScrn)
188145bc899bSmrg{
188245bc899bSmrg    VESAPtr pVesa = VESAGetRec(pScrn);
188345bc899bSmrg    DisplayModePtr pMode = pScrn->modes;
188445bc899bSmrg    DGAModePtr pDGAMode;
188545bc899bSmrg
188645bc899bSmrg    do {
1887b40a6198Smrg	pDGAMode = realloc(pVesa->pDGAMode,
188845bc899bSmrg			    (pVesa->nDGAMode + 1) * sizeof(DGAModeRec));
188945bc899bSmrg	if (!pDGAMode)
189045bc899bSmrg	    break;
189145bc899bSmrg
189245bc899bSmrg	pVesa->pDGAMode = pDGAMode;
189345bc899bSmrg	pDGAMode += pVesa->nDGAMode;
189445bc899bSmrg	(void)memset(pDGAMode, 0, sizeof(DGAModeRec));
189545bc899bSmrg
189645bc899bSmrg	++pVesa->nDGAMode;
189745bc899bSmrg	pDGAMode->mode = pMode;
189845bc899bSmrg	pDGAMode->flags = DGA_CONCURRENT_ACCESS | DGA_PIXMAP_AVAILABLE;
189945bc899bSmrg	pDGAMode->byteOrder = pScrn->imageByteOrder;
190045bc899bSmrg	pDGAMode->depth = pScrn->depth;
190145bc899bSmrg	pDGAMode->bitsPerPixel = pScrn->bitsPerPixel;
190245bc899bSmrg	pDGAMode->red_mask = pScrn->mask.red;
190345bc899bSmrg	pDGAMode->green_mask = pScrn->mask.green;
190445bc899bSmrg	pDGAMode->blue_mask = pScrn->mask.blue;
190545bc899bSmrg	pDGAMode->visualClass = pScrn->bitsPerPixel > 8 ?
190645bc899bSmrg	    TrueColor : PseudoColor;
190745bc899bSmrg	pDGAMode->xViewportStep = 1;
190845bc899bSmrg	pDGAMode->yViewportStep = 1;
190945bc899bSmrg	pDGAMode->viewportWidth = pMode->HDisplay;
191045bc899bSmrg	pDGAMode->viewportHeight = pMode->VDisplay;
191145bc899bSmrg
191245bc899bSmrg	pDGAMode->bytesPerScanline = pVesa->maxBytesPerScanline;
191345bc899bSmrg	pDGAMode->imageWidth = pMode->HDisplay;
191445bc899bSmrg	pDGAMode->imageHeight =  pMode->VDisplay;
191545bc899bSmrg	pDGAMode->pixmapWidth = pDGAMode->imageWidth;
191645bc899bSmrg	pDGAMode->pixmapHeight = pDGAMode->imageHeight;
191745bc899bSmrg	pDGAMode->maxViewportX = pScrn->virtualX -
191845bc899bSmrg				    pDGAMode->viewportWidth;
191945bc899bSmrg	pDGAMode->maxViewportY = pScrn->virtualY -
192045bc899bSmrg				    pDGAMode->viewportHeight;
192145bc899bSmrg
192245bc899bSmrg	pDGAMode->address = pVesa->base;
192345bc899bSmrg
192445bc899bSmrg	pMode = pMode->next;
192545bc899bSmrg    } while (pMode != pScrn->modes);
192645bc899bSmrg}
192745bc899bSmrg
192845bc899bSmrgstatic Bool
192945bc899bSmrgVESADGAInit(ScrnInfoPtr pScrn, ScreenPtr pScreen)
193045bc899bSmrg{
193145bc899bSmrg    VESAPtr pVesa = VESAGetRec(pScrn);
193245bc899bSmrg
193345bc899bSmrg    if (pScrn->depth < 8 || pVesa->mapPhys == 0xa0000L)
193445bc899bSmrg	return (FALSE);
193545bc899bSmrg
193645bc899bSmrg    if (!pVesa->nDGAMode)
193745bc899bSmrg	VESADGAAddModes(pScrn);
193845bc899bSmrg
193945bc899bSmrg    return (DGAInit(pScreen, &VESADGAFunctions,
194045bc899bSmrg	    pVesa->pDGAMode, pVesa->nDGAMode));
194145bc899bSmrg}
1942