vesa.c revision a0c41156
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>
4745bc899bSmrg#include "vesa.h"
4845bc899bSmrg
4945bc899bSmrg/* All drivers initialising the SW cursor need this */
5045bc899bSmrg#include "mipointer.h"
5145bc899bSmrg
5245bc899bSmrg/* Colormap handling */
5345bc899bSmrg#include "micmap.h"
5445bc899bSmrg#include "xf86cmap.h"
5550f2e948Smrg#include "xf86Modes.h"
5645bc899bSmrg
5745bc899bSmrg/* DPMS */
583a925b30Smrg#ifdef HAVE_XEXTPROTO_71
593a925b30Smrg#include <X11/extensions/dpmsconst.h>
603a925b30Smrg#else
6145bc899bSmrg#define DPMS_SERVER
6245bc899bSmrg#include <X11/extensions/dpms.h>
633a925b30Smrg#endif
64b40a6198Smrg#include "compat-api.h"
6545bc899bSmrg
6645bc899bSmrg/* Mandatory functions */
6745bc899bSmrgstatic const OptionInfoRec * VESAAvailableOptions(int chipid, int busid);
6845bc899bSmrgstatic void VESAIdentify(int flags);
69f2408745Smrg#if defined(XSERVER_LIBPCIACCESS) && !defined(HAVE_ISA)
70f2408745Smrg#define VESAProbe NULL
71f2408745Smrg#else
7245bc899bSmrgstatic Bool VESAProbe(DriverPtr drv, int flags);
73f2408745Smrg#endif
7450f2e948Smrg#ifdef XSERVER_LIBPCIACCESS
7550f2e948Smrgstatic Bool VESAPciProbe(DriverPtr drv, int entity_num,
7650f2e948Smrg     struct pci_device *dev, intptr_t match_data);
7750f2e948Smrg#endif
7845bc899bSmrgstatic Bool VESAPreInit(ScrnInfoPtr pScrn, int flags);
79b40a6198Smrgstatic Bool VESAScreenInit(SCREEN_INIT_ARGS_DECL);
80b40a6198Smrgstatic Bool VESAEnterVT(VT_FUNC_ARGS_DECL);
81b40a6198Smrgstatic void VESALeaveVT(VT_FUNC_ARGS_DECL);
82b40a6198Smrgstatic Bool VESACloseScreen(CLOSE_SCREEN_ARGS_DECL);
8345bc899bSmrgstatic Bool VESASaveScreen(ScreenPtr pScreen, int mode);
8445bc899bSmrg
85b40a6198Smrgstatic Bool VESASwitchMode(SWITCH_MODE_ARGS_DECL);
8645bc899bSmrgstatic Bool VESASetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode);
87b40a6198Smrgstatic void VESAAdjustFrame(ADJUST_FRAME_ARGS_DECL);
88b40a6198Smrgstatic void VESAFreeScreen(FREE_SCREEN_ARGS_DECL);
8945bc899bSmrgstatic void VESAFreeRec(ScrnInfoPtr pScrn);
9050f2e948Smrgstatic VESAPtr VESAGetRec(ScrnInfoPtr pScrn);
9145bc899bSmrg
9245bc899bSmrgstatic void
9345bc899bSmrgVESADisplayPowerManagementSet(ScrnInfoPtr pScrn, int mode,
9445bc899bSmrg                int flags);
9545bc899bSmrg
9645bc899bSmrg/* locally used functions */
975592a31fSmrg#ifdef HAVE_ISA
9845bc899bSmrgstatic int VESAFindIsaDevice(GDevPtr dev);
995592a31fSmrg#endif
10045bc899bSmrgstatic Bool VESAMapVidMem(ScrnInfoPtr pScrn);
10145bc899bSmrgstatic void VESAUnmapVidMem(ScrnInfoPtr pScrn);
10245bc899bSmrgstatic int VESABankSwitch(ScreenPtr pScreen, unsigned int iBank);
10345bc899bSmrgstatic void VESALoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices,
10445bc899bSmrg			    LOCO *colors, VisualPtr pVisual);
10545bc899bSmrgstatic void SaveFonts(ScrnInfoPtr pScrn);
10645bc899bSmrgstatic void RestoreFonts(ScrnInfoPtr pScrn);
10745bc899bSmrgstatic Bool
10845bc899bSmrgVESASaveRestore(ScrnInfoPtr pScrn, vbeSaveRestoreFunction function);
10945bc899bSmrg
1105592a31fSmrgstatic void *
1115592a31fSmrgVESAWindowLinear(ScreenPtr pScreen, CARD32 row, CARD32 offset, int mode,
1125592a31fSmrg		 CARD32 *size, void *closure)
1135592a31fSmrg{
114b40a6198Smrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1155592a31fSmrg    VESAPtr pVesa = VESAGetRec(pScrn);
1165592a31fSmrg
1175592a31fSmrg    *size = pVesa->maxBytesPerScanline;
1185592a31fSmrg    return ((CARD8 *)pVesa->base + row * pVesa->maxBytesPerScanline + offset);
1195592a31fSmrg}
1205592a31fSmrg
1215592a31fSmrgstatic void *
1225592a31fSmrgVESAWindowWindowed(ScreenPtr pScreen, CARD32 row, CARD32 offset, int mode,
1235592a31fSmrg		   CARD32 *size, void *closure)
1245592a31fSmrg{
125b40a6198Smrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1265592a31fSmrg    VESAPtr pVesa = VESAGetRec(pScrn);
1275592a31fSmrg    VbeModeInfoBlock *data = ((VbeModeInfoData*)(pScrn->currentMode->Private))->data;
1285592a31fSmrg    int window;
1295592a31fSmrg
1305592a31fSmrg    offset += pVesa->maxBytesPerScanline * row;
1315592a31fSmrg    window = offset / (data->WinGranularity * 1024);
1325592a31fSmrg    pVesa->windowAoffset = window * data->WinGranularity * 1024;
1335592a31fSmrg    VESABankSwitch(pScreen, window);
1345592a31fSmrg    *size = data->WinSize * 1024 - (offset - pVesa->windowAoffset);
1355592a31fSmrg
1365592a31fSmrg    return (void *)((unsigned long)pVesa->base +
1375592a31fSmrg		    (offset - pVesa->windowAoffset));
1385592a31fSmrg}
1395592a31fSmrg
1405592a31fSmrgstatic void
1415592a31fSmrgvesaUpdatePacked(ScreenPtr pScreen, shadowBufPtr pBuf)
1425592a31fSmrg{
1435592a31fSmrg    shadowUpdatePacked(pScreen, pBuf);
1445592a31fSmrg}
14545bc899bSmrg
14645bc899bSmrgstatic Bool VESADGAInit(ScrnInfoPtr pScrn, ScreenPtr pScreen);
14745bc899bSmrg
14845bc899bSmrgenum GenericTypes
14945bc899bSmrg{
15045bc899bSmrg    CHIP_VESA_GENERIC
15145bc899bSmrg};
15245bc899bSmrg
15350f2e948Smrg#ifdef XSERVER_LIBPCIACCESS
15450f2e948Smrgstatic const struct pci_id_match vesa_device_match[] = {
15550f2e948Smrg    {
15650f2e948Smrg	PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY,
15750f2e948Smrg	0x00030000, 0x00ffffff, CHIP_VESA_GENERIC
15850f2e948Smrg    },
15950f2e948Smrg
16050f2e948Smrg    { 0, 0, 0 },
16150f2e948Smrg};
16250f2e948Smrg#endif
16350f2e948Smrg
16445bc899bSmrg/* Supported chipsets */
16545bc899bSmrgstatic SymTabRec VESAChipsets[] =
16645bc899bSmrg{
16745bc899bSmrg    {CHIP_VESA_GENERIC, "vesa"},
16845bc899bSmrg    {-1,		 NULL}
16945bc899bSmrg};
17045bc899bSmrg
17150f2e948Smrg#ifndef XSERVER_LIBPCIACCESS
17245bc899bSmrgstatic PciChipsets VESAPCIchipsets[] = {
17345bc899bSmrg  { CHIP_VESA_GENERIC, PCI_CHIP_VGA, RES_SHARED_VGA },
17445bc899bSmrg  { -1,		-1,	   RES_UNDEFINED },
17545bc899bSmrg};
17650f2e948Smrg#endif
17745bc899bSmrg
17850f2e948Smrg#ifdef HAVE_ISA
17945bc899bSmrgstatic IsaChipsets VESAISAchipsets[] = {
18045bc899bSmrg  {CHIP_VESA_GENERIC, RES_EXCLUSIVE_VGA},
18145bc899bSmrg  {-1,		0 }
18245bc899bSmrg};
18350f2e948Smrg#endif
18450f2e948Smrg
18550f2e948Smrg
18650f2e948Smrg/*
18750f2e948Smrg * This contains the functions needed by the server after loading the
18850f2e948Smrg * driver module.  It must be supplied, and gets added the driver list by
18950f2e948Smrg * the Module Setup funtion in the dynamic case.  In the static case a
19050f2e948Smrg * reference to this is compiled in, and this requires that the name of
19150f2e948Smrg * this DriverRec be an upper-case version of the driver name.
19250f2e948Smrg */
19350f2e948Smrg_X_EXPORT DriverRec VESA = {
19450f2e948Smrg    VESA_VERSION,
19550f2e948Smrg    VESA_DRIVER_NAME,
19650f2e948Smrg    VESAIdentify,
19750f2e948Smrg    VESAProbe,
19850f2e948Smrg    VESAAvailableOptions,
19950f2e948Smrg    NULL,
20050f2e948Smrg    0,
20150f2e948Smrg    NULL,
20250f2e948Smrg
20350f2e948Smrg#ifdef XSERVER_LIBPCIACCESS
20450f2e948Smrg    vesa_device_match,
20550f2e948Smrg    VESAPciProbe
20650f2e948Smrg#endif
20750f2e948Smrg};
20850f2e948Smrg
20945bc899bSmrg
21045bc899bSmrgtypedef enum {
21145bc899bSmrg    OPTION_SHADOW_FB,
21245bc899bSmrg    OPTION_DFLT_REFRESH,
21345bc899bSmrg    OPTION_MODESET_CLEAR_SCREEN
21445bc899bSmrg} VESAOpts;
21545bc899bSmrg
21645bc899bSmrgstatic const OptionInfoRec VESAOptions[] = {
21745bc899bSmrg    { OPTION_SHADOW_FB,    "ShadowFB",		OPTV_BOOLEAN,	{0},	FALSE },
21845bc899bSmrg    { OPTION_DFLT_REFRESH, "DefaultRefresh",	OPTV_BOOLEAN,	{0},	FALSE },
21945bc899bSmrg    { OPTION_MODESET_CLEAR_SCREEN, "ModeSetClearScreen",
22045bc899bSmrg						OPTV_BOOLEAN,	{0},	FALSE },
22145bc899bSmrg    { -1,		   NULL,		OPTV_NONE,	{0},	FALSE }
22245bc899bSmrg};
22345bc899bSmrg
22445bc899bSmrg#ifdef XFree86LOADER
22545bc899bSmrg
22645bc899bSmrg/* Module loader interface */
22745bc899bSmrgstatic MODULESETUPPROTO(vesaSetup);
22845bc899bSmrg
22945bc899bSmrgstatic XF86ModuleVersionInfo vesaVersionRec =
23045bc899bSmrg{
23145bc899bSmrg    VESA_DRIVER_NAME,
23245bc899bSmrg    MODULEVENDORSTRING,
23345bc899bSmrg    MODINFOSTRING1,
23445bc899bSmrg    MODINFOSTRING2,
23545bc899bSmrg    XORG_VERSION_CURRENT,
23645bc899bSmrg    VESA_MAJOR_VERSION, VESA_MINOR_VERSION, VESA_PATCHLEVEL,
23745bc899bSmrg    ABI_CLASS_VIDEODRV,			/* This is a video driver */
23845bc899bSmrg    ABI_VIDEODRV_VERSION,
23945bc899bSmrg    MOD_CLASS_VIDEODRV,
24045bc899bSmrg    {0, 0, 0, 0}
24145bc899bSmrg};
24245bc899bSmrg
24345bc899bSmrg/*
24445bc899bSmrg * This data is accessed by the loader.  The name must be the module name
24545bc899bSmrg * followed by "ModuleData".
24645bc899bSmrg */
24745bc899bSmrg_X_EXPORT XF86ModuleData vesaModuleData = { &vesaVersionRec, vesaSetup, NULL };
24845bc899bSmrg
24945bc899bSmrgstatic pointer
25045bc899bSmrgvesaSetup(pointer Module, pointer Options, int *ErrorMajor, int *ErrorMinor)
25145bc899bSmrg{
25245bc899bSmrg    static Bool Initialised = FALSE;
25345bc899bSmrg
25445bc899bSmrg    if (!Initialised)
25545bc899bSmrg    {
25645bc899bSmrg	Initialised = TRUE;
25750f2e948Smrg	xf86AddDriver(&VESA, Module, 1);
25845bc899bSmrg	return (pointer)TRUE;
25945bc899bSmrg    }
26045bc899bSmrg
26145bc899bSmrg    if (ErrorMajor)
26245bc899bSmrg	*ErrorMajor = LDR_ONCEONLY;
26345bc899bSmrg    return (NULL);
26445bc899bSmrg}
26545bc899bSmrg
26645bc899bSmrg#endif
26745bc899bSmrg
26845bc899bSmrgstatic const OptionInfoRec *
26945bc899bSmrgVESAAvailableOptions(int chipid, int busid)
27045bc899bSmrg{
27145bc899bSmrg    return (VESAOptions);
27245bc899bSmrg}
27345bc899bSmrg
27445bc899bSmrgstatic void
27545bc899bSmrgVESAIdentify(int flags)
27645bc899bSmrg{
27745bc899bSmrg    xf86PrintChipsets(VESA_NAME, "driver for VESA chipsets", VESAChipsets);
27845bc899bSmrg}
27945bc899bSmrg
28050f2e948Smrgstatic VESAPtr
28150f2e948SmrgVESAGetRec(ScrnInfoPtr pScrn)
28250f2e948Smrg{
28350f2e948Smrg    if (!pScrn->driverPrivate)
284b40a6198Smrg	pScrn->driverPrivate = calloc(sizeof(VESARec), 1);
28550f2e948Smrg
28650f2e948Smrg    return ((VESAPtr)pScrn->driverPrivate);
28750f2e948Smrg}
28850f2e948Smrg
28950f2e948Smrg/* Only a little like VBESetModeParameters */
29050f2e948Smrgstatic void
29150f2e948SmrgVESASetModeParameters(vbeInfoPtr pVbe, DisplayModePtr vbemode,
29250f2e948Smrg		      DisplayModePtr ddcmode)
29350f2e948Smrg{
29450f2e948Smrg    VbeModeInfoData *data;
29550f2e948Smrg    int clock;
29650f2e948Smrg
29750f2e948Smrg    data = (VbeModeInfoData *)vbemode->Private;
29850f2e948Smrg
299b40a6198Smrg    data->block = calloc(sizeof(VbeCRTCInfoBlock), 1);
30050f2e948Smrg    data->block->HorizontalTotal = ddcmode->HTotal;
30150f2e948Smrg    data->block->HorizontalSyncStart = ddcmode->HSyncStart;
30250f2e948Smrg    data->block->HorizontalSyncEnd = ddcmode->HSyncEnd;
30350f2e948Smrg    data->block->VerticalTotal = ddcmode->VTotal;
30450f2e948Smrg    data->block->VerticalSyncStart = ddcmode->VSyncStart;
30550f2e948Smrg    data->block->VerticalSyncEnd = ddcmode->VSyncEnd;
30650f2e948Smrg    data->block->Flags = ((ddcmode->Flags & V_NHSYNC) ? CRTC_NHSYNC : 0) |
30750f2e948Smrg	                 ((ddcmode->Flags & V_NVSYNC) ? CRTC_NVSYNC : 0);
30850f2e948Smrg    data->block->PixelClock = ddcmode->Clock * 1000;
30950f2e948Smrg
31050f2e948Smrg    /* ask the BIOS to figure out the real clock */
31150f2e948Smrg    clock = VBEGetPixelClock(pVbe, data->mode, data->block->PixelClock);
31250f2e948Smrg    if (clock)
31350f2e948Smrg	data->block->PixelClock = clock;
31450f2e948Smrg
31550f2e948Smrg    data->mode |= (1 << 11);
31650f2e948Smrg    data->block->RefreshRate = 100 * ((double)(data->block->PixelClock) /
31750f2e948Smrg				(double)(ddcmode->HTotal * ddcmode->VTotal));
31850f2e948Smrg}
31950f2e948Smrg
320b40a6198Smrg/*
321b40a6198Smrg * Despite that VBE gives you pixel granularity for mode sizes, some BIOSes
322b40a6198Smrg * think they can only give sizes in multiples of character cells; and
323b40a6198Smrg * indeed, the reference CVT and GTF formulae only give results where
324b40a6198Smrg * (h % 8) == 0.  Whatever, let's just try to cope.  What we're looking for
325b40a6198Smrg * here is cases where the display says 1366x768 and the BIOS says 1360x768.
326b40a6198Smrg */
327b40a6198Smrgstatic Bool
328b40a6198SmrgvesaModesCloseEnough(DisplayModePtr edid, DisplayModePtr vbe)
329b40a6198Smrg{
330b40a6198Smrg    if (!(edid->type & M_T_DRIVER))
331b40a6198Smrg	return FALSE;
332b40a6198Smrg
333b40a6198Smrg    /* never seen a height granularity... */
334b40a6198Smrg    if (edid->VDisplay != vbe->VDisplay)
335b40a6198Smrg	return FALSE;
336b40a6198Smrg
337b40a6198Smrg    if (edid->HDisplay >= vbe->HDisplay &&
338b40a6198Smrg	(edid->HDisplay & ~7) == (vbe->HDisplay & ~7))
339b40a6198Smrg	return TRUE;
340b40a6198Smrg
341b40a6198Smrg    return FALSE;
342b40a6198Smrg}
343b40a6198Smrg
34450f2e948Smrgstatic ModeStatus
345b40a6198SmrgVESAValidMode(SCRN_ARG_TYPE arg, DisplayModePtr p, Bool flag, int pass)
34650f2e948Smrg{
347b40a6198Smrg    SCRN_INFO_PTR(arg);
34850f2e948Smrg    static int warned = 0;
34950f2e948Smrg    int found = 0;
35050f2e948Smrg    VESAPtr pVesa = VESAGetRec(pScrn);
35150f2e948Smrg    MonPtr mon = pScrn->monitor;
35250f2e948Smrg    ModeStatus ret = MODE_BAD;
35350f2e948Smrg    DisplayModePtr mode;
35450f2e948Smrg    float v;
35550f2e948Smrg
35650f2e948Smrg    pVesa = VESAGetRec(pScrn);
35750f2e948Smrg
35850f2e948Smrg    if (pass != MODECHECK_FINAL) {
35950f2e948Smrg	if (!warned) {
360b40a6198Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "VESAValidMode called unexpectedly\n");
36150f2e948Smrg	    warned = 1;
36250f2e948Smrg	}
36350f2e948Smrg	return MODE_OK;
36450f2e948Smrg    }
36550f2e948Smrg
36650f2e948Smrg    /*
36750f2e948Smrg     * This is suboptimal.  We pass in just the barest description of a mode
36850f2e948Smrg     * we can get away with to VBEValidateModes, so it can't really throw
36950f2e948Smrg     * out anything we give it.  But we need to filter the list so that we
37050f2e948Smrg     * don't populate the mode list with things the monitor can't do.
37150f2e948Smrg     *
37250f2e948Smrg     * So first off, if this isn't a mode we handed to the server (ie,
37350f2e948Smrg     * M_T_BUILTIN), then we know we can't do it.
37450f2e948Smrg     */
37550f2e948Smrg    if (!(p->type & M_T_BUILTIN))
37650f2e948Smrg	return MODE_NOMODE;
37750f2e948Smrg
37850f2e948Smrg    if (pVesa->strict_validation) {
37950f2e948Smrg	/*
38050f2e948Smrg	 * If it's our first pass at mode validation, we'll try for a strict
38150f2e948Smrg	 * intersection between the VBE and DDC mode lists.
38250f2e948Smrg	 */
38350f2e948Smrg	if (pScrn->monitor->DDC) {
38450f2e948Smrg	    for (mode = pScrn->monitor->Modes; mode; mode = mode->next) {
385b40a6198Smrg		if (vesaModesCloseEnough(mode, p)) {
38650f2e948Smrg		    if (xf86CheckModeForMonitor(mode, mon) == MODE_OK) {
38750f2e948Smrg			found = 1;
38850f2e948Smrg			break;
38950f2e948Smrg		    }
39050f2e948Smrg		}
39150f2e948Smrg		if (mode == pScrn->monitor->Last)
39250f2e948Smrg		    break;
39350f2e948Smrg	    }
39450f2e948Smrg	    if (!found)
39550f2e948Smrg		return MODE_NOMODE;
39650f2e948Smrg
39750f2e948Smrg	    /* having found a matching mode, stash the CRTC values aside */
39850f2e948Smrg	    VESASetModeParameters(pVesa->pVbe, p, mode);
39950f2e948Smrg	    return MODE_OK;
40050f2e948Smrg	}
40150f2e948Smrg
40250f2e948Smrg	/* No DDC and no modes make Homer something something... */
40350f2e948Smrg	return MODE_NOMODE;
40450f2e948Smrg    }
40550f2e948Smrg
40650f2e948Smrg    /*
40750f2e948Smrg     * Finally, walk through the vsync rates 1Hz at a time looking for a mode
40850f2e948Smrg     * that will fit.  This is assuredly a terrible way to do this, but
40950f2e948Smrg     * there's no obvious method for computing a mode of a given size that
41050f2e948Smrg     * will pass xf86CheckModeForMonitor.  XXX this path is terrible, but
41150f2e948Smrg     * then, by this point, you're well into despair territory.
41250f2e948Smrg     */
41350f2e948Smrg    for (v = mon->vrefresh[0].lo; v <= mon->vrefresh[0].hi; v++) {
41450f2e948Smrg	mode = xf86GTFMode(p->HDisplay, p->VDisplay, v, 0, 0);
41550f2e948Smrg	ret = xf86CheckModeForMonitor(mode, mon);
416b40a6198Smrg	free(mode->name);
417b40a6198Smrg	free(mode);
41850f2e948Smrg	if (ret == MODE_OK)
41950f2e948Smrg	    break;
42050f2e948Smrg    }
42150f2e948Smrg
42250f2e948Smrg    return ret;
42350f2e948Smrg}
42450f2e948Smrg
42550f2e948Smrgstatic void
42650f2e948SmrgVESAInitScrn(ScrnInfoPtr pScrn)
42750f2e948Smrg{
42850f2e948Smrg    pScrn->driverVersion = VESA_VERSION;
42950f2e948Smrg    pScrn->driverName    = VESA_DRIVER_NAME;
43050f2e948Smrg    pScrn->name		 = VESA_NAME;
43150f2e948Smrg    pScrn->Probe	 = VESAProbe;
43250f2e948Smrg    pScrn->PreInit       = VESAPreInit;
43350f2e948Smrg    pScrn->ScreenInit    = VESAScreenInit;
43450f2e948Smrg    pScrn->SwitchMode    = VESASwitchMode;
43550f2e948Smrg    pScrn->ValidMode     = VESAValidMode;
43650f2e948Smrg    pScrn->AdjustFrame   = VESAAdjustFrame;
43750f2e948Smrg    pScrn->EnterVT       = VESAEnterVT;
43850f2e948Smrg    pScrn->LeaveVT       = VESALeaveVT;
43950f2e948Smrg    pScrn->FreeScreen    = VESAFreeScreen;
44050f2e948Smrg}
44150f2e948Smrg
44245bc899bSmrg/*
44345bc899bSmrg * This function is called once, at the start of the first server generation to
44445bc899bSmrg * do a minimal probe for supported hardware.
44545bc899bSmrg */
44645bc899bSmrg
44750f2e948Smrg#ifdef XSERVER_LIBPCIACCESS
44850f2e948Smrgstatic Bool
44950f2e948SmrgVESAPciProbe(DriverPtr drv, int entity_num, struct pci_device *dev,
45050f2e948Smrg	     intptr_t match_data)
45150f2e948Smrg{
45250f2e948Smrg    ScrnInfoPtr pScrn;
453a0c41156Smrg
454a0c41156Smrg#ifdef __linux__
455a0c41156Smrg    if (access("/sys/devices/platform/efi-framebuffer.0", F_OK) == 0 ||
456a0c41156Smrg        access("/sys/devices/platform/efifb.0", F_OK) == 0) {
457a0c41156Smrg        ErrorF("vesa: Refusing to run on UEFI\n");
458a0c41156Smrg        return FALSE;
459a0c41156Smrg    }
460a0c41156Smrg#endif
461a0c41156Smrg
46250f2e948Smrg    pScrn = xf86ConfigPciEntity(NULL, 0, entity_num, NULL,
46350f2e948Smrg				NULL, NULL, NULL, NULL, NULL);
46450f2e948Smrg    if (pScrn != NULL) {
465b40a6198Smrg	VESAPtr pVesa;
466b40a6198Smrg
467b40a6198Smrg	if (pci_device_has_kernel_driver(dev)) {
468b40a6198Smrg	    ErrorF("vesa: Ignoring device with a bound kernel driver\n");
469b40a6198Smrg	    return FALSE;
470b40a6198Smrg	}
47150f2e948Smrg
472b40a6198Smrg	pVesa = VESAGetRec(pScrn);
47350f2e948Smrg	VESAInitScrn(pScrn);
47450f2e948Smrg	pVesa->pciInfo = dev;
47550f2e948Smrg    }
47650f2e948Smrg
47750f2e948Smrg    return (pScrn != NULL);
47850f2e948Smrg}
47950f2e948Smrg#endif
48050f2e948Smrg
481f2408745Smrg#ifndef VESAProbe
48245bc899bSmrgstatic Bool
48345bc899bSmrgVESAProbe(DriverPtr drv, int flags)
48445bc899bSmrg{
48545bc899bSmrg    Bool foundScreen = FALSE;
48645bc899bSmrg    int numDevSections, numUsed;
48745bc899bSmrg    GDevPtr *devSections;
48845bc899bSmrg    int *usedChips;
48945bc899bSmrg    int i;
49045bc899bSmrg
49145bc899bSmrg    /*
49245bc899bSmrg     * Find the config file Device sections that match this
49345bc899bSmrg     * driver, and return if there are none.
49445bc899bSmrg     */
49545bc899bSmrg    if ((numDevSections = xf86MatchDevice(VESA_NAME,
49645bc899bSmrg					  &devSections)) <= 0)
49745bc899bSmrg	return (FALSE);
49845bc899bSmrg
49950f2e948Smrg#ifndef XSERVER_LIBPCIACCESS
50045bc899bSmrg    /* PCI BUS */
50145bc899bSmrg    if (xf86GetPciVideoInfo()) {
50245bc899bSmrg	numUsed = xf86MatchPciInstances(VESA_NAME, PCI_VENDOR_GENERIC,
50345bc899bSmrg					VESAChipsets, VESAPCIchipsets,
50445bc899bSmrg					devSections, numDevSections,
50545bc899bSmrg					drv, &usedChips);
50645bc899bSmrg	if (numUsed > 0) {
50745bc899bSmrg	    if (flags & PROBE_DETECT)
50845bc899bSmrg		foundScreen = TRUE;
50945bc899bSmrg	    else {
51045bc899bSmrg		for (i = 0; i < numUsed; i++) {
51145bc899bSmrg		    ScrnInfoPtr pScrn = NULL;
51245bc899bSmrg		    /* Allocate a ScrnInfoRec  */
51345bc899bSmrg		    if ((pScrn = xf86ConfigPciEntity(pScrn,0,usedChips[i],
51445bc899bSmrg						     VESAPCIchipsets,NULL,
51545bc899bSmrg						     NULL,NULL,NULL,NULL))) {
51650f2e948Smrg			VESAInitScrn(pScrn);
51745bc899bSmrg			foundScreen = TRUE;
51845bc899bSmrg		    }
51945bc899bSmrg		}
52045bc899bSmrg	    }
521b40a6198Smrg	    free(usedChips);
52245bc899bSmrg	}
52345bc899bSmrg    }
52450f2e948Smrg#endif
52545bc899bSmrg
52650f2e948Smrg#ifdef HAVE_ISA
52745bc899bSmrg    /* Isa Bus */
52845bc899bSmrg    numUsed = xf86MatchIsaInstances(VESA_NAME,VESAChipsets,
52945bc899bSmrg				    VESAISAchipsets, drv,
53045bc899bSmrg				    VESAFindIsaDevice, devSections,
53145bc899bSmrg				    numDevSections, &usedChips);
53245bc899bSmrg    if(numUsed > 0) {
53345bc899bSmrg	if (flags & PROBE_DETECT)
53445bc899bSmrg	    foundScreen = TRUE;
53545bc899bSmrg	else for (i = 0; i < numUsed; i++) {
53645bc899bSmrg	    ScrnInfoPtr pScrn = NULL;
53745bc899bSmrg	    if ((pScrn = xf86ConfigIsaEntity(pScrn, 0,usedChips[i],
53845bc899bSmrg					     VESAISAchipsets, NULL,
53945bc899bSmrg					     NULL, NULL, NULL, NULL))) {
54050f2e948Smrg		VESAInitScrn(pScrn);
54145bc899bSmrg		foundScreen = TRUE;
54245bc899bSmrg	    }
54345bc899bSmrg	}
544b40a6198Smrg	free(usedChips);
54545bc899bSmrg    }
54650f2e948Smrg#endif
54745bc899bSmrg
548b40a6198Smrg    free(devSections);
54945bc899bSmrg
55045bc899bSmrg    return (foundScreen);
55145bc899bSmrg}
552f2408745Smrg#endif
55345bc899bSmrg
55450f2e948Smrg#ifdef HAVE_ISA
55545bc899bSmrgstatic int
55645bc899bSmrgVESAFindIsaDevice(GDevPtr dev)
55745bc899bSmrg{
55845bc899bSmrg#ifndef PC98_EGC
55945bc899bSmrg    CARD16 GenericIOBase = VGAHW_GET_IOBASE();
56045bc899bSmrg    CARD8 CurrentValue, TestValue;
56145bc899bSmrg
56245bc899bSmrg    /* There's no need to unlock VGA CRTC registers here */
56345bc899bSmrg
56445bc899bSmrg    /* VGA has one more read/write attribute register than EGA */
56545bc899bSmrg    (void) inb(GenericIOBase + VGA_IN_STAT_1_OFFSET);  /* Reset flip-flop */
56645bc899bSmrg    outb(VGA_ATTR_INDEX, 0x14 | 0x20);
56745bc899bSmrg    CurrentValue = inb(VGA_ATTR_DATA_R);
56845bc899bSmrg    outb(VGA_ATTR_DATA_W, CurrentValue ^ 0x0F);
56945bc899bSmrg    outb(VGA_ATTR_INDEX, 0x14 | 0x20);
57045bc899bSmrg    TestValue = inb(VGA_ATTR_DATA_R);
57145bc899bSmrg    outb(VGA_ATTR_DATA_R, CurrentValue);
57245bc899bSmrg
57345bc899bSmrg    /* Quit now if no VGA is present */
57445bc899bSmrg    if ((CurrentValue ^ 0x0F) != TestValue)
57545bc899bSmrg      return -1;
57645bc899bSmrg#endif
57745bc899bSmrg    return (int)CHIP_VESA_GENERIC;
57845bc899bSmrg}
57950f2e948Smrg#endif
58045bc899bSmrg
58145bc899bSmrgstatic void
58245bc899bSmrgVESAFreeRec(ScrnInfoPtr pScrn)
58345bc899bSmrg{
58445bc899bSmrg    VESAPtr pVesa = VESAGetRec(pScrn);
58545bc899bSmrg#if 0
58645bc899bSmrg    DisplayModePtr mode = pScrn->modes;
58745bc899bSmrg    /* I am not sure if the modes will ever get freed.
58845bc899bSmrg     * Anyway, the data unknown to other modules is being freed here.
58945bc899bSmrg     */
59045bc899bSmrg    if (mode) {
59145bc899bSmrg	do {
59245bc899bSmrg	    if (mode->Private) {
59345bc899bSmrg		VbeModeInfoData *data = (VbeModeInfoData*)mode->Private;
59445bc899bSmrg
59545bc899bSmrg		if (data->block)
596b40a6198Smrg		    free(data->block);
59745bc899bSmrg
598b40a6198Smrg		free(data);
59945bc899bSmrg
60045bc899bSmrg		mode->Private = NULL;
60145bc899bSmrg	    }
60245bc899bSmrg	    mode = mode->next;
60345bc899bSmrg	} while (mode && mode != pScrn->modes);
60445bc899bSmrg    }
60545bc899bSmrg#endif
606b40a6198Smrg    free(pVesa->monitor);
607f2408745Smrg    if (pVesa->vbeInfo)
608f2408745Smrg	VBEFreeVBEInfo(pVesa->vbeInfo);
609b40a6198Smrg    free(pVesa->pal);
610b40a6198Smrg    free(pVesa->savedPal);
611b40a6198Smrg    free(pVesa->fonts);
612b40a6198Smrg    free(pScrn->driverPrivate);
61345bc899bSmrg    pScrn->driverPrivate = NULL;
61445bc899bSmrg}
61545bc899bSmrg
61650f2e948Smrgstatic int
61750f2e948SmrgVESAValidateModes(ScrnInfoPtr pScrn)
61850f2e948Smrg{
61950f2e948Smrg    VESAPtr pVesa = VESAGetRec(pScrn);
62050f2e948Smrg    DisplayModePtr mode;
62150f2e948Smrg
62250f2e948Smrg    for (mode = pScrn->monitor->Modes; mode; mode = mode->next)
62350f2e948Smrg	mode->status = MODE_OK;
62450f2e948Smrg
62550f2e948Smrg    return VBEValidateModes(pScrn, NULL, pScrn->display->modes,
6265592a31fSmrg			    NULL, NULL, 0, 32767, 1, 0, 32767,
62750f2e948Smrg			    pScrn->display->virtualX,
62850f2e948Smrg			    pScrn->display->virtualY,
62950f2e948Smrg			    pVesa->mapSize, LOOKUP_BEST_REFRESH);
63050f2e948Smrg}
63150f2e948Smrg
63245bc899bSmrg/*
63345bc899bSmrg * This function is called once for each screen at the start of the first
63445bc899bSmrg * server generation to initialise the screen for all server generations.
63545bc899bSmrg */
63645bc899bSmrgstatic Bool
63745bc899bSmrgVESAPreInit(ScrnInfoPtr pScrn, int flags)
63845bc899bSmrg{
63945bc899bSmrg    VESAPtr pVesa;
64045bc899bSmrg    VbeInfoBlock *vbe;
64145bc899bSmrg    DisplayModePtr pMode;
64245bc899bSmrg    VbeModeInfoBlock *mode;
64345bc899bSmrg    Gamma gzeros = {0.0, 0.0, 0.0};
64445bc899bSmrg    rgb rzeros = {0, 0, 0};
64545bc899bSmrg    pointer pDDCModule;
64645bc899bSmrg    int i;
64745bc899bSmrg    int flags24 = 0;
64845bc899bSmrg    int defaultDepth = 0;
64950f2e948Smrg    int defaultBpp = 0;
65045bc899bSmrg    int depths = 0;
65145bc899bSmrg
65245bc899bSmrg    if (flags & PROBE_DETECT)
65345bc899bSmrg	return (FALSE);
65445bc899bSmrg
65545bc899bSmrg    pVesa = VESAGetRec(pScrn);
65645bc899bSmrg    pVesa->pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
65745bc899bSmrg
65845bc899bSmrg    /* Load vbe module */
65945bc899bSmrg    if (!xf86LoadSubModule(pScrn, "vbe"))
66045bc899bSmrg        return (FALSE);
66145bc899bSmrg
66245bc899bSmrg    if ((pVesa->pVbe = VBEExtendedInit(NULL, pVesa->pEnt->index,
66345bc899bSmrg				       SET_BIOS_SCRATCH
66445bc899bSmrg				       | RESTORE_BIOS_SCRATCH)) == NULL)
66545bc899bSmrg        return (FALSE);
66645bc899bSmrg
66750f2e948Smrg#ifndef XSERVER_LIBPCIACCESS
66845bc899bSmrg    if (pVesa->pEnt->location.type == BUS_PCI) {
66945bc899bSmrg	pVesa->pciInfo = xf86GetPciInfoForEntity(pVesa->pEnt->index);
67045bc899bSmrg	pVesa->pciTag = pciTag(pVesa->pciInfo->bus, pVesa->pciInfo->device,
67145bc899bSmrg			       pVesa->pciInfo->func);
67245bc899bSmrg    }
67350f2e948Smrg#endif
67445bc899bSmrg
67545bc899bSmrg    pScrn->chipset = "vesa";
67645bc899bSmrg    pScrn->monitor = pScrn->confScreen->monitor;
67745bc899bSmrg    pScrn->progClock = TRUE;
67845bc899bSmrg    pScrn->rgbBits = 8;
67945bc899bSmrg
68045bc899bSmrg    if ((vbe = VBEGetVBEInfo(pVesa->pVbe)) == NULL)
68145bc899bSmrg	return (FALSE);
68245bc899bSmrg    pVesa->major = (unsigned)(vbe->VESAVersion >> 8);
68345bc899bSmrg    pVesa->minor = vbe->VESAVersion & 0xff;
68445bc899bSmrg    pVesa->vbeInfo = vbe;
68545bc899bSmrg    pScrn->videoRam = vbe->TotalMemory * 64;
68645bc899bSmrg
68745bc899bSmrg    /*
68845bc899bSmrg     * Find what depths are available.
68945bc899bSmrg     */
69045bc899bSmrg    depths = VBEFindSupportedDepths(pVesa->pVbe, pVesa->vbeInfo, &flags24,
69145bc899bSmrg				    V_MODETYPE_VBE);
69245bc899bSmrg
69345bc899bSmrg    /* Preferred order for default depth selection. */
694a0c41156Smrg    if (depths & V_DEPTH_24 && (flags24 & Support32bppFb))
69550f2e948Smrg	defaultDepth = 24;
69650f2e948Smrg    else if (depths & V_DEPTH_16)
69745bc899bSmrg	defaultDepth = 16;
69845bc899bSmrg    else if (depths & V_DEPTH_15)
69945bc899bSmrg	defaultDepth = 15;
700a0c41156Smrg    else if (depths & V_DEPTH_24)
701a0c41156Smrg        defaultDepth = 24; /* ew though */
70245bc899bSmrg    else if (depths & V_DEPTH_8)
70345bc899bSmrg	defaultDepth = 8;
70445bc899bSmrg    else if (depths & V_DEPTH_4)
70545bc899bSmrg	defaultDepth = 4;
70645bc899bSmrg    else if (depths & V_DEPTH_1)
70745bc899bSmrg	defaultDepth = 1;
70845bc899bSmrg
70950f2e948Smrg    if (defaultDepth == 24 && !(flags24 & Support32bppFb))
71050f2e948Smrg	defaultBpp = 24;
71145bc899bSmrg
71250f2e948Smrg    /* Prefer 32bpp because 1999 called and wants its packed pixels back */
71350f2e948Smrg    if (flags24 & Support32bppFb)
71450f2e948Smrg	flags24 |= SupportConvert24to32 | PreferConvert24to32;
71545bc899bSmrg    if (flags24 & Support24bppFb)
71650f2e948Smrg	flags24 |= SupportConvert32to24;
71745bc899bSmrg
71850f2e948Smrg    if (!xf86SetDepthBpp(pScrn, defaultDepth, 0, defaultBpp, flags24)) {
71945bc899bSmrg        vbeFree(pVesa->pVbe);
72045bc899bSmrg	return (FALSE);
72145bc899bSmrg    }
72245bc899bSmrg    xf86PrintDepthBpp(pScrn);
72345bc899bSmrg
72445bc899bSmrg    /* color weight */
72545bc899bSmrg    if (pScrn->depth > 8 && !xf86SetWeight(pScrn, rzeros, rzeros)) {
72645bc899bSmrg        vbeFree(pVesa->pVbe);
72745bc899bSmrg	return (FALSE);
72845bc899bSmrg    }
72945bc899bSmrg    /* visual init */
73045bc899bSmrg    if (!xf86SetDefaultVisual(pScrn, -1)) {
73145bc899bSmrg        vbeFree(pVesa->pVbe);
73245bc899bSmrg	return (FALSE);
73345bc899bSmrg    }
73445bc899bSmrg
73545bc899bSmrg    xf86SetGamma(pScrn, gzeros);
73645bc899bSmrg
737f2408745Smrg    /* set up options before loading any modules that may look at them */
738f2408745Smrg    xf86CollectOptions(pScrn, NULL);
739f2408745Smrg
74045bc899bSmrg    if (pVesa->major >= 2) {
74145bc899bSmrg	/* Load ddc module */
74245bc899bSmrg	if ((pDDCModule = xf86LoadSubModule(pScrn, "ddc")) == NULL) {
74345bc899bSmrg	    vbeFree(pVesa->pVbe);
74445bc899bSmrg	    return (FALSE);
74545bc899bSmrg	}
74645bc899bSmrg
74745bc899bSmrg	if ((pVesa->monitor = vbeDoEDID(pVesa->pVbe, pDDCModule)) != NULL) {
74845bc899bSmrg	    xf86PrintEDID(pVesa->monitor);
74945bc899bSmrg	}
75045bc899bSmrg
75145bc899bSmrg	xf86UnloadSubModule(pDDCModule);
75245bc899bSmrg    }
75345bc899bSmrg
75445bc899bSmrg    if ((pScrn->monitor->DDC = pVesa->monitor) != NULL)
75545bc899bSmrg	xf86SetDDCproperties(pScrn, pVesa->monitor);
7563a925b30Smrg    else {
7573a925b30Smrg	void *panelid = VBEReadPanelID(pVesa->pVbe);
758b40a6198Smrg	VBEInterpretPanelID(SCRN_OR_INDEX_ARG(pScrn), panelid);
759b40a6198Smrg	free(panelid);
7603a925b30Smrg    }
76145bc899bSmrg
76245bc899bSmrg    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, DEBUG_VERB,
76345bc899bSmrg			"Searching for matching VESA mode(s):\n");
76445bc899bSmrg
76545bc899bSmrg    /*
76645bc899bSmrg     * Check the available BIOS modes, and extract those that match the
76745bc899bSmrg     * requirements into the modePool.  Note: modePool is a NULL-terminated
76845bc899bSmrg     * list.
76945bc899bSmrg     */
77045bc899bSmrg    pScrn->modePool = VBEGetModePool (pScrn, pVesa->pVbe, pVesa->vbeInfo,
77145bc899bSmrg				      V_MODETYPE_VBE);
77245bc899bSmrg
77345bc899bSmrg    xf86ErrorFVerb(DEBUG_VERB, "\n");
77445bc899bSmrg    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, DEBUG_VERB,
77545bc899bSmrg		   "Total Memory: %d 64KB banks (%dkB)\n", vbe->TotalMemory,
77645bc899bSmrg		   (vbe->TotalMemory * 65536) / 1024);
77745bc899bSmrg
77845bc899bSmrg    pVesa->mapSize = vbe->TotalMemory * 65536;
77945bc899bSmrg    if (pScrn->modePool == NULL) {
78045bc899bSmrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No matching modes\n");
78145bc899bSmrg        vbeFree(pVesa->pVbe);
78245bc899bSmrg	return (FALSE);
78345bc899bSmrg    }
78445bc899bSmrg
78545bc899bSmrg    VBESetModeNames(pScrn->modePool);
78645bc899bSmrg
78750f2e948Smrg    pVesa->strict_validation = TRUE;
78850f2e948Smrg    i = VESAValidateModes(pScrn);
78950f2e948Smrg
79050f2e948Smrg    if (i <= 0) {
79150f2e948Smrg	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
79250f2e948Smrg		"No valid modes left. Trying less strict filter...\n");
79350f2e948Smrg	pVesa->strict_validation = FALSE;
79450f2e948Smrg	i = VESAValidateModes(pScrn);
79550f2e948Smrg    }
79650f2e948Smrg
79750f2e948Smrg    if (i <= 0) do {
79850f2e948Smrg	Bool changed = FALSE;
79950f2e948Smrg	/* maybe there's more modes at the bottom... */
80050f2e948Smrg	if (pScrn->monitor->vrefresh[0].lo > 50) {
80150f2e948Smrg	    changed = TRUE;
80250f2e948Smrg	    pScrn->monitor->vrefresh[0].lo = 50;
80350f2e948Smrg	}
80450f2e948Smrg	if (pScrn->monitor->hsync[0].lo > 31.5) {
80550f2e948Smrg	    changed = TRUE;
80650f2e948Smrg	    pScrn->monitor->hsync[0].lo = 31.5;
80750f2e948Smrg	}
80850f2e948Smrg
80950f2e948Smrg	if (!changed)
81050f2e948Smrg	    break;
81150f2e948Smrg
81250f2e948Smrg	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
81350f2e948Smrg		   "No valid modes left. Trying aggressive sync range...\n");
81450f2e948Smrg	i = VESAValidateModes(pScrn);
81550f2e948Smrg    } while (0);
81645bc899bSmrg
81745bc899bSmrg    if (i <= 0) {
81850f2e948Smrg	/* alright, i'm out of ideas */
81945bc899bSmrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes\n");
82045bc899bSmrg        vbeFree(pVesa->pVbe);
82145bc899bSmrg	return (FALSE);
82245bc899bSmrg    }
82345bc899bSmrg
82445bc899bSmrg    xf86PruneDriverModes(pScrn);
82545bc899bSmrg
82645bc899bSmrg    pMode = pScrn->modes;
82745bc899bSmrg    do {
82845bc899bSmrg	mode = ((VbeModeInfoData*)pMode->Private)->data;
82945bc899bSmrg	if (mode->BytesPerScanline > pVesa->maxBytesPerScanline) {
83045bc899bSmrg	    pVesa->maxBytesPerScanline = mode->BytesPerScanline;
83145bc899bSmrg	}
83245bc899bSmrg	pMode = pMode->next;
83345bc899bSmrg    } while (pMode != pScrn->modes);
83445bc899bSmrg
83545bc899bSmrg    pScrn->currentMode = pScrn->modes;
83645bc899bSmrg    pScrn->displayWidth = pScrn->virtualX;
83745bc899bSmrg
83845bc899bSmrg    VBEPrintModes(pScrn);
83945bc899bSmrg
84045bc899bSmrg    /* Set display resolution */
84145bc899bSmrg    xf86SetDpi(pScrn, 0, 0);
84245bc899bSmrg
84345bc899bSmrg    if (pScrn->modes == NULL) {
84445bc899bSmrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No modes\n");
84545bc899bSmrg        vbeFree(pVesa->pVbe);
84645bc899bSmrg	return (FALSE);
84745bc899bSmrg    }
84845bc899bSmrg
84945bc899bSmrg    /* options */
850b40a6198Smrg    if (!(pVesa->Options = malloc(sizeof(VESAOptions)))) {
85145bc899bSmrg        vbeFree(pVesa->pVbe);
85245bc899bSmrg	return FALSE;
85345bc899bSmrg    }
85445bc899bSmrg    memcpy(pVesa->Options, VESAOptions, sizeof(VESAOptions));
85545bc899bSmrg    xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pVesa->Options);
85645bc899bSmrg
857a0c41156Smrg    /* Use shadow by default, for non-virt hardware */
858a0c41156Smrg    if (!xf86GetOptValBool(pVesa->Options, OPTION_SHADOW_FB, &pVesa->shadowFB))
859a0c41156Smrg    {
860a0c41156Smrg	switch (pVesa->pciInfo->vendor_id) {
861a0c41156Smrg	    case 0x1234: /* bochs vga (not in pci.ids) */
862a0c41156Smrg	    case 0x15ad: /* vmware */
863a0c41156Smrg	    case 0x1b36: /* qemu qxl */
864a0c41156Smrg	    case 0x80ee: /* virtualbox */
865a0c41156Smrg	    case 0xaaaa: /* parallels (not in pci.ids) */
866a0c41156Smrg		pVesa->shadowFB = FALSE;
867a0c41156Smrg		break;
868a0c41156Smrg
869a0c41156Smrg	    case 0x1013: /* qemu's cirrus emulation */
870a0c41156Smrg		if (pVesa->pciInfo->subvendor_id == 0x1af4)
871a0c41156Smrg		    pVesa->shadowFB = FALSE;
872a0c41156Smrg		else
873a0c41156Smrg		    pVesa->shadowFB = TRUE;
874a0c41156Smrg		break;
875a0c41156Smrg
876a0c41156Smrg	    case 0x1414: /* microsoft hyper-v */
877a0c41156Smrg		if (pVesa->pciInfo->device_id == 0x5353)
878a0c41156Smrg		    pVesa->shadowFB = FALSE;
879a0c41156Smrg		else
880a0c41156Smrg		    pVesa->shadowFB = TRUE;
881a0c41156Smrg		break;
882a0c41156Smrg
883a0c41156Smrg	    default:
884a0c41156Smrg		pVesa->shadowFB = TRUE;
885a0c41156Smrg		break;
886a0c41156Smrg	}
887a0c41156Smrg    }
888a0c41156Smrg
889f2408745Smrg    /*  Use default refresh by default. Too many VBE 3.0
890f2408745Smrg     *   BIOSes are incorrectly implemented.
891f2408745Smrg     */
892f2408745Smrg    pVesa->defaultRefresh = xf86ReturnOptValBool(pVesa->Options,
893f2408745Smrg                                                 OPTION_DFLT_REFRESH, TRUE);
89445bc899bSmrg
895c97b1c41Smrg    pVesa->ModeSetClearScreen =
896c97b1c41Smrg        xf86ReturnOptValBool(pVesa->Options,
897c97b1c41Smrg                             OPTION_MODESET_CLEAR_SCREEN, FALSE);
89845bc899bSmrg
89950f2e948Smrg    if (!pVesa->defaultRefresh && !pVesa->strict_validation)
90045bc899bSmrg	VBESetModeParameters(pScrn, pVesa->pVbe);
90145bc899bSmrg
90245bc899bSmrg    mode = ((VbeModeInfoData*)pScrn->modes->Private)->data;
90345bc899bSmrg    switch (mode->MemoryModel) {
90445bc899bSmrg	case 0x4:	/* Packed pixel */
90550f2e948Smrg	case 0x6:	/* Direct Color */
90645bc899bSmrg	    pScrn->bitmapBitOrder = BITMAP_BIT_ORDER;
90745bc899bSmrg
90845bc899bSmrg	    switch (pScrn->bitsPerPixel) {
90945bc899bSmrg		case 8:
91045bc899bSmrg		case 16:
91145bc899bSmrg		case 24:
91245bc899bSmrg		case 32:
91345bc899bSmrg		    break;
91445bc899bSmrg		default:
91545bc899bSmrg		    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
916a0c41156Smrg			       "Unsupported bpp: %d\n", pScrn->bitsPerPixel);
91745bc899bSmrg		    vbeFree(pVesa->pVbe);
91845bc899bSmrg		    return FALSE;
91945bc899bSmrg	    }
92045bc899bSmrg	    break;
92150f2e948Smrg	default:
92250f2e948Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
923a0c41156Smrg		       "Unsupported Memory Model: %d\n", mode->MemoryModel);
92450f2e948Smrg	    return FALSE;
92545bc899bSmrg    }
92645bc899bSmrg
92745bc899bSmrg    if (pVesa->shadowFB) {
92845bc899bSmrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Using \"Shadow Framebuffer\"\n");
92945bc899bSmrg	if (!xf86LoadSubModule(pScrn, "shadow")) {
93045bc899bSmrg	    vbeFree(pVesa->pVbe);
93145bc899bSmrg	    return (FALSE);
93245bc899bSmrg	}
93345bc899bSmrg    }
93445bc899bSmrg
93550f2e948Smrg    if (xf86LoadSubModule(pScrn, "fb") == NULL) {
93645bc899bSmrg	VESAFreeRec(pScrn);
93745bc899bSmrg        vbeFree(pVesa->pVbe);
93845bc899bSmrg	return (FALSE);
93945bc899bSmrg    }
94045bc899bSmrg
94145bc899bSmrg    vbeFree(pVesa->pVbe);
94245bc899bSmrg
94345bc899bSmrg    return (TRUE);
94445bc899bSmrg}
94545bc899bSmrg
94645bc899bSmrgstatic Bool
94745bc899bSmrgvesaCreateScreenResources(ScreenPtr pScreen)
94845bc899bSmrg{
949b40a6198Smrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
95045bc899bSmrg    VESAPtr pVesa = VESAGetRec(pScrn);
95145bc899bSmrg    Bool ret;
95245bc899bSmrg
95345bc899bSmrg    pScreen->CreateScreenResources = pVesa->CreateScreenResources;
95445bc899bSmrg    ret = pScreen->CreateScreenResources(pScreen);
95545bc899bSmrg    pScreen->CreateScreenResources = vesaCreateScreenResources;
95645bc899bSmrg
95745bc899bSmrg    shadowAdd(pScreen, pScreen->GetScreenPixmap(pScreen), pVesa->update,
95845bc899bSmrg	      pVesa->window, 0, 0);
95945bc899bSmrg
96045bc899bSmrg    return ret;
96145bc899bSmrg}
96245bc899bSmrg
96350f2e948Smrgstatic void
964b40a6198SmrgvesaEnableDisableFBAccess(SCRN_ARG_TYPE arg, Bool enable)
96550f2e948Smrg{
966b40a6198Smrg    SCRN_INFO_PTR(arg);
96750f2e948Smrg    VESAPtr pVesa = VESAGetRec(pScrn);
96850f2e948Smrg
96950f2e948Smrg    pVesa->accessEnabled = enable;
970b40a6198Smrg    pVesa->EnableDisableFBAccess(arg, enable);
97150f2e948Smrg}
97250f2e948Smrg
97345bc899bSmrgstatic Bool
974b40a6198SmrgVESAScreenInit(SCREEN_INIT_ARGS_DECL)
97545bc899bSmrg{
976b40a6198Smrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
97745bc899bSmrg    VESAPtr pVesa = VESAGetRec(pScrn);
97845bc899bSmrg    VisualPtr visual;
97945bc899bSmrg    VbeModeInfoBlock *mode;
98045bc899bSmrg    int flags;
98145bc899bSmrg
98245bc899bSmrg    if ((pVesa->pVbe = VBEExtendedInit(NULL, pVesa->pEnt->index,
98345bc899bSmrg				       SET_BIOS_SCRATCH
98445bc899bSmrg				       | RESTORE_BIOS_SCRATCH)) == NULL)
98545bc899bSmrg        return (FALSE);
98645bc899bSmrg
98745bc899bSmrg    if (pVesa->mapPhys == 0) {
98845bc899bSmrg	mode = ((VbeModeInfoData*)(pScrn->currentMode->Private))->data;
98945bc899bSmrg	pScrn->videoRam = pVesa->mapSize;
99045bc899bSmrg	pVesa->mapPhys = mode->PhysBasePtr;
99145bc899bSmrg	pVesa->mapOff = 0;
99245bc899bSmrg    }
99345bc899bSmrg
99445bc899bSmrg    if (pVesa->mapPhys == 0) {
99545bc899bSmrg	pVesa->mapPhys = 0xa0000;
99645bc899bSmrg	pVesa->mapSize = 0x10000;
99745bc899bSmrg    }
99845bc899bSmrg
99945bc899bSmrg    if (!VESAMapVidMem(pScrn)) {
100045bc899bSmrg	if (pVesa->mapPhys != 0xa0000) {
100145bc899bSmrg	    pVesa->mapPhys = 0xa0000;
100245bc899bSmrg	    pVesa->mapSize = 0x10000;
100345bc899bSmrg	    if (!VESAMapVidMem(pScrn))
100445bc899bSmrg		return (FALSE);
100545bc899bSmrg	}
100645bc899bSmrg	else
100745bc899bSmrg	    return (FALSE);
100845bc899bSmrg    }
100945bc899bSmrg
101045bc899bSmrg    /* Set bpp to 8 for depth 4 when using shadowfb. */
101145bc899bSmrg    if (pVesa->shadowFB && pScrn->bitsPerPixel == 4)
101245bc899bSmrg	pScrn->bitsPerPixel = 8;
101345bc899bSmrg
101445bc899bSmrg    if (pVesa->shadowFB) {
1015b40a6198Smrg	pVesa->shadow = calloc(1, pScrn->displayWidth * pScrn->virtualY *
101645bc899bSmrg				   ((pScrn->bitsPerPixel + 7) / 8));
101745bc899bSmrg	if (!pVesa->shadow) {
101845bc899bSmrg	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
101945bc899bSmrg		       "Failed to allocate shadow buffer\n");
102045bc899bSmrg	    return FALSE;
102145bc899bSmrg	}
102245bc899bSmrg    }
102345bc899bSmrg
102445bc899bSmrg    /* save current video state */
102545bc899bSmrg    VESASaveRestore(pScrn, MODE_SAVE);
102645bc899bSmrg    pVesa->savedPal = VBESetGetPaletteData(pVesa->pVbe, FALSE, 0, 256,
102745bc899bSmrg					    NULL, FALSE, FALSE);
102845bc899bSmrg
102945bc899bSmrg    /* set first video mode */
103045bc899bSmrg    if (!VESASetMode(pScrn, pScrn->currentMode))
103145bc899bSmrg	return (FALSE);
103245bc899bSmrg
103345bc899bSmrg    /* set the viewport */
1034b40a6198Smrg    VESAAdjustFrame(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0));
103545bc899bSmrg
103645bc899bSmrg    /* Blank the screen for aesthetic reasons. */
103745bc899bSmrg    VESASaveScreen(pScreen, SCREEN_SAVER_ON);
103845bc899bSmrg
103945bc899bSmrg    /* mi layer */
104045bc899bSmrg    miClearVisualTypes();
104145bc899bSmrg    if (!xf86SetDefaultVisual(pScrn, -1))
104245bc899bSmrg	return (FALSE);
104345bc899bSmrg    if (pScrn->bitsPerPixel > 8) {
104445bc899bSmrg	if (!miSetVisualTypes(pScrn->depth, TrueColorMask,
104545bc899bSmrg			      pScrn->rgbBits, TrueColor))
104645bc899bSmrg	    return (FALSE);
104745bc899bSmrg    }
104845bc899bSmrg    else {
104945bc899bSmrg	if (!miSetVisualTypes(pScrn->depth,
105045bc899bSmrg			      miGetDefaultVisualMask(pScrn->depth),
105145bc899bSmrg			      pScrn->rgbBits, pScrn->defaultVisual))
105245bc899bSmrg	    return (FALSE);
105345bc899bSmrg    }
105445bc899bSmrg    if (!miSetPixmapDepths())
105545bc899bSmrg	return (FALSE);
105645bc899bSmrg
105745bc899bSmrg    mode = ((VbeModeInfoData*)pScrn->modes->Private)->data;
105845bc899bSmrg    switch (mode->MemoryModel) {
105945bc899bSmrg	case 0x4:	/* Packed pixel */
106050f2e948Smrg	case 0x6:	/* Direct Color */
106145bc899bSmrg	    switch (pScrn->bitsPerPixel) {
106245bc899bSmrg		case 8:
106345bc899bSmrg		case 16:
106445bc899bSmrg		case 24:
106545bc899bSmrg		case 32:
106645bc899bSmrg		    if (!fbScreenInit(pScreen,
106745bc899bSmrg				pVesa->shadowFB ? pVesa->shadow : pVesa->base,
106845bc899bSmrg				       pScrn->virtualX, pScrn->virtualY,
106945bc899bSmrg				       pScrn->xDpi, pScrn->yDpi,
107045bc899bSmrg				       pScrn->displayWidth, pScrn->bitsPerPixel))
107145bc899bSmrg			return (FALSE);
107245bc899bSmrg		    break;
107345bc899bSmrg		default:
107445bc899bSmrg		    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
107545bc899bSmrg			       "Unsupported bpp: %d", pScrn->bitsPerPixel);
107645bc899bSmrg		    return (FALSE);
107745bc899bSmrg	    }
107845bc899bSmrg	    break;
107950f2e948Smrg	default:
108050f2e948Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
108150f2e948Smrg		       "Unsupported Memory Model: %d", mode->MemoryModel);
108250f2e948Smrg	    return (FALSE);
108345bc899bSmrg    }
108445bc899bSmrg
108545bc899bSmrg
108645bc899bSmrg    if (pScrn->bitsPerPixel > 8) {
108745bc899bSmrg	/* Fixup RGB ordering */
108845bc899bSmrg	visual = pScreen->visuals + pScreen->numVisuals;
108945bc899bSmrg	while (--visual >= pScreen->visuals) {
109045bc899bSmrg	    if ((visual->class | DynamicClass) == DirectColor) {
109145bc899bSmrg		visual->offsetRed   = pScrn->offset.red;
109245bc899bSmrg		visual->offsetGreen = pScrn->offset.green;
109345bc899bSmrg		visual->offsetBlue  = pScrn->offset.blue;
109445bc899bSmrg		visual->redMask     = pScrn->mask.red;
109545bc899bSmrg		visual->greenMask   = pScrn->mask.green;
109645bc899bSmrg		visual->blueMask    = pScrn->mask.blue;
109745bc899bSmrg	    }
109845bc899bSmrg	}
109945bc899bSmrg    }
110045bc899bSmrg
110145bc899bSmrg    /* must be after RGB ordering fixed */
11025592a31fSmrg    fbPictureInit(pScreen, 0, 0);
110345bc899bSmrg
110445bc899bSmrg    if (pVesa->shadowFB) {
110550f2e948Smrg	if (pVesa->mapPhys == 0xa0000) {	/* Windowed */
11065592a31fSmrg	    pVesa->update = vesaUpdatePacked;
110745bc899bSmrg	    pVesa->window = VESAWindowWindowed;
110845bc899bSmrg	}
110945bc899bSmrg	else {	/* Linear */
11105592a31fSmrg	    pVesa->update = vesaUpdatePacked;
111145bc899bSmrg	    pVesa->window = VESAWindowLinear;
111245bc899bSmrg	}
111345bc899bSmrg
111445bc899bSmrg	if (!shadowSetup(pScreen))
111545bc899bSmrg	    return FALSE;
111645bc899bSmrg	pVesa->CreateScreenResources = pScreen->CreateScreenResources;
111745bc899bSmrg	pScreen->CreateScreenResources = vesaCreateScreenResources;
111845bc899bSmrg    }
111950f2e948Smrg    else if (pVesa->mapPhys == 0xa0000) {
11205592a31fSmrg        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
11215592a31fSmrg                   "Banked framebuffer requires ShadowFB\n");
11225592a31fSmrg        return FALSE;
112345bc899bSmrg    }
112445bc899bSmrg
112545bc899bSmrg    VESADGAInit(pScrn, pScreen);
112645bc899bSmrg
112745bc899bSmrg    xf86SetBlackWhitePixels(pScreen);
112845bc899bSmrg    xf86SetBackingStore(pScreen);
112945bc899bSmrg
113045bc899bSmrg    /* software cursor */
113145bc899bSmrg    miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
113245bc899bSmrg
113345bc899bSmrg    /* colormap */
113445bc899bSmrg    if (!miCreateDefColormap(pScreen))
113545bc899bSmrg	return (FALSE);
113645bc899bSmrg
113745bc899bSmrg    flags = CMAP_RELOAD_ON_MODE_SWITCH;
113845bc899bSmrg
113945bc899bSmrg    if(!xf86HandleColormaps(pScreen, 256,
114045bc899bSmrg	pVesa->vbeInfo->Capabilities[0] & 0x01 ? 8 : 6,
114145bc899bSmrg	VESALoadPalette, NULL, flags))
114245bc899bSmrg	return (FALSE);
114345bc899bSmrg
114450f2e948Smrg    pVesa->accessEnabled = TRUE;
114550f2e948Smrg    pVesa->EnableDisableFBAccess = pScrn->EnableDisableFBAccess;
114650f2e948Smrg    pScrn->EnableDisableFBAccess = vesaEnableDisableFBAccess;
114750f2e948Smrg
114845bc899bSmrg    pVesa->CloseScreen = pScreen->CloseScreen;
114945bc899bSmrg    pScreen->CloseScreen = VESACloseScreen;
115045bc899bSmrg    pScreen->SaveScreen = VESASaveScreen;
115145bc899bSmrg
115245bc899bSmrg    xf86DPMSInit(pScreen, VESADisplayPowerManagementSet, 0);
115345bc899bSmrg
115445bc899bSmrg    /* Report any unused options (only for the first generation) */
115545bc899bSmrg    if (serverGeneration == 1)
115645bc899bSmrg        xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
115745bc899bSmrg
115845bc899bSmrg    return (TRUE);
115945bc899bSmrg}
116045bc899bSmrg
116145bc899bSmrgstatic Bool
1162b40a6198SmrgVESAEnterVT(VT_FUNC_ARGS_DECL)
116345bc899bSmrg{
1164b40a6198Smrg    SCRN_INFO_PTR(arg);
116545bc899bSmrg
116645bc899bSmrg    if (!VESASetMode(pScrn, pScrn->currentMode))
116745bc899bSmrg	return FALSE;
1168b40a6198Smrg    VESAAdjustFrame(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0));
116945bc899bSmrg    return TRUE;
117045bc899bSmrg}
117145bc899bSmrg
117245bc899bSmrgstatic void
1173b40a6198SmrgVESALeaveVT(VT_FUNC_ARGS_DECL)
117445bc899bSmrg{
1175b40a6198Smrg    SCRN_INFO_PTR(arg);
1176b40a6198Smrg    VESASaveRestore(pScrn, MODE_RESTORE);
117745bc899bSmrg}
117845bc899bSmrg
117945bc899bSmrgstatic Bool
1180b40a6198SmrgVESACloseScreen(CLOSE_SCREEN_ARGS_DECL)
118145bc899bSmrg{
1182b40a6198Smrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
118345bc899bSmrg    VESAPtr pVesa = VESAGetRec(pScrn);
118445bc899bSmrg
118545bc899bSmrg    if (pScrn->vtSema) {
1186b40a6198Smrg	VESASaveRestore(pScrn, MODE_RESTORE);
118745bc899bSmrg	if (pVesa->savedPal)
118845bc899bSmrg	    VBESetGetPaletteData(pVesa->pVbe, TRUE, 0, 256,
118945bc899bSmrg				 pVesa->savedPal, FALSE, TRUE);
119045bc899bSmrg	VESAUnmapVidMem(pScrn);
119145bc899bSmrg    }
11925592a31fSmrg    if (pVesa->shadowFB && pVesa->shadow) {
11935592a31fSmrg	shadowRemove(pScreen, pScreen->GetScreenPixmap(pScreen));
1194b40a6198Smrg	free(pVesa->shadow);
11955592a31fSmrg    }
119645bc899bSmrg    if (pVesa->pDGAMode) {
1197b40a6198Smrg	free(pVesa->pDGAMode);
119845bc899bSmrg	pVesa->pDGAMode = NULL;
119945bc899bSmrg	pVesa->nDGAMode = 0;
120045bc899bSmrg    }
120145bc899bSmrg    pScrn->vtSema = FALSE;
120245bc899bSmrg
120350f2e948Smrg    pScrn->EnableDisableFBAccess = pVesa->EnableDisableFBAccess;
120445bc899bSmrg    pScreen->CreateScreenResources = pVesa->CreateScreenResources;
120545bc899bSmrg    pScreen->CloseScreen = pVesa->CloseScreen;
1206b40a6198Smrg    return pScreen->CloseScreen(CLOSE_SCREEN_ARGS);
120745bc899bSmrg}
120845bc899bSmrg
120945bc899bSmrgstatic Bool
1210b40a6198SmrgVESASwitchMode(SWITCH_MODE_ARGS_DECL)
121145bc899bSmrg{
1212b40a6198Smrg    SCRN_INFO_PTR(arg);
121345bc899bSmrg    VESAPtr pVesa = VESAGetRec(pScrn);
121450f2e948Smrg    Bool ret, disableAccess = pVesa->ModeSetClearScreen && pVesa->accessEnabled;
121545bc899bSmrg
121650f2e948Smrg    if (disableAccess)
1217b40a6198Smrg        pScrn->EnableDisableFBAccess(SCRN_OR_INDEX_ARG(pScrn),FALSE);
1218b40a6198Smrg    ret = VESASetMode(pScrn, mode);
121950f2e948Smrg    if (disableAccess)
1220b40a6198Smrg	pScrn->EnableDisableFBAccess(SCRN_OR_INDEX_ARG(pScrn),TRUE);
122145bc899bSmrg    return ret;
122245bc899bSmrg}
122345bc899bSmrg
122445bc899bSmrg/* Set a graphics mode */
122545bc899bSmrgstatic Bool
122645bc899bSmrgVESASetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode)
122745bc899bSmrg{
122845bc899bSmrg    VESAPtr pVesa;
122945bc899bSmrg    VbeModeInfoData *data;
123045bc899bSmrg    int mode;
123145bc899bSmrg
123245bc899bSmrg    pVesa = VESAGetRec(pScrn);
123345bc899bSmrg
123445bc899bSmrg    data = (VbeModeInfoData*)pMode->Private;
123550f2e948Smrg
123650f2e948Smrg    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
123750f2e948Smrg	       "Setting up VESA Mode 0x%X (%dx%d)\n",
123850f2e948Smrg	       data->mode & 0x7FF, pMode->HDisplay, pMode->VDisplay);
123950f2e948Smrg
124050f2e948Smrg    /* careful, setting the bit means don't clear the screen */
124150f2e948Smrg    mode = data->mode | (pVesa->ModeSetClearScreen ? 0 : (1U << 15));
124245bc899bSmrg
124345bc899bSmrg    /* enable linear addressing */
124445bc899bSmrg    if (pVesa->mapPhys != 0xa0000)
124545bc899bSmrg	mode |= 1 << 14;
124645bc899bSmrg
124745bc899bSmrg    if (VBESetVBEMode(pVesa->pVbe, mode, data->block) == FALSE) {
124845bc899bSmrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VBESetVBEMode failed");
124945bc899bSmrg	if ((data->block || (data->mode & (1 << 11))) &&
125045bc899bSmrg	    VBESetVBEMode(pVesa->pVbe, (mode & ~(1 << 11)), NULL) == TRUE) {
125145bc899bSmrg	    /* Some cards do not like setting the clock.
125245bc899bSmrg	     * Free it as it will not be any longer useful
125345bc899bSmrg	     */
12545592a31fSmrg	    xf86ErrorF(", mode set without customized refresh.\n");
1255b40a6198Smrg	    free(data->block);
125645bc899bSmrg	    data->block = NULL;
125745bc899bSmrg	    data->mode &= ~(1 << 11);
125845bc899bSmrg	}
125945bc899bSmrg	else {
126045bc899bSmrg	    ErrorF("\n");
126145bc899bSmrg	    return (FALSE);
126245bc899bSmrg	}
126345bc899bSmrg    }
126445bc899bSmrg
126545bc899bSmrg    pVesa->bankSwitchWindowB =
126645bc899bSmrg	!((data->data->WinBSegment == 0) && (data->data->WinBAttributes == 0));
126745bc899bSmrg
126845bc899bSmrg    if (data->data->XResolution != pScrn->displayWidth)
126945bc899bSmrg	VBESetLogicalScanline(pVesa->pVbe, pScrn->displayWidth);
127045bc899bSmrg
127145bc899bSmrg    if (pScrn->bitsPerPixel == 8 && pVesa->vbeInfo->Capabilities[0] & 0x01 &&
127250f2e948Smrg        !(data->data->MemoryModel == 0x6 || data->data->MemoryModel == 0x7))
127345bc899bSmrg	VBESetGetDACPaletteFormat(pVesa->pVbe, 8);
127445bc899bSmrg
127545bc899bSmrg    pScrn->vtSema = TRUE;
127645bc899bSmrg
127745bc899bSmrg    return (TRUE);
127845bc899bSmrg}
127945bc899bSmrg
128045bc899bSmrgstatic void
1281b40a6198SmrgVESAAdjustFrame(ADJUST_FRAME_ARGS_DECL)
128245bc899bSmrg{
1283b40a6198Smrg    SCRN_INFO_PTR(arg);
1284b40a6198Smrg    VESAPtr pVesa = VESAGetRec(pScrn);
128545bc899bSmrg
128645bc899bSmrg    VBESetDisplayStart(pVesa->pVbe, x, y, TRUE);
128745bc899bSmrg}
128845bc899bSmrg
128945bc899bSmrgstatic void
1290b40a6198SmrgVESAFreeScreen(FREE_SCREEN_ARGS_DECL)
129145bc899bSmrg{
1292b40a6198Smrg    SCRN_INFO_PTR(arg);
1293b40a6198Smrg    VESAFreeRec(pScrn);
129445bc899bSmrg}
129545bc899bSmrg
129645bc899bSmrgstatic Bool
129745bc899bSmrgVESAMapVidMem(ScrnInfoPtr pScrn)
129845bc899bSmrg{
129945bc899bSmrg    VESAPtr pVesa = VESAGetRec(pScrn);
130045bc899bSmrg
130145bc899bSmrg    if (pVesa->base != NULL)
130245bc899bSmrg	return (TRUE);
130345bc899bSmrg
130445bc899bSmrg    pScrn->memPhysBase = pVesa->mapPhys;
130545bc899bSmrg    pScrn->fbOffset = pVesa->mapOff;
130645bc899bSmrg
130750f2e948Smrg#ifdef XSERVER_LIBPCIACCESS
1308b40a6198Smrg    if (pVesa->pciInfo != NULL) {
1309b40a6198Smrg	if (pVesa->mapPhys != 0xa0000) {
1310b40a6198Smrg	    (void) pci_device_map_range(pVesa->pciInfo, pScrn->memPhysBase,
1311b40a6198Smrg	                                pVesa->mapSize,
1312b40a6198Smrg				        (PCI_DEV_MAP_FLAG_WRITABLE
1313b40a6198Smrg				         | PCI_DEV_MAP_FLAG_WRITE_COMBINE),
1314b40a6198Smrg				        & pVesa->base);
1315b40a6198Smrg
1316b40a6198Smrg	    if (pVesa->base)
1317b40a6198Smrg		(void) pci_device_map_legacy(pVesa->pciInfo, 0xa0000, 0x10000,
1318b40a6198Smrg		                             PCI_DEV_MAP_FLAG_WRITABLE,
1319b40a6198Smrg		                             & pVesa->VGAbase);
1320b40a6198Smrg	}
1321b40a6198Smrg	else {
1322b40a6198Smrg	    (void) pci_device_map_legacy(pVesa->pciInfo, pScrn->memPhysBase,
1323b40a6198Smrg	                                 pVesa->mapSize,
1324b40a6198Smrg	                                 PCI_DEV_MAP_FLAG_WRITABLE,
1325b40a6198Smrg	                                 & pVesa->base);
132650f2e948Smrg
1327b40a6198Smrg	    if (pVesa->base)
1328b40a6198Smrg		pVesa->VGAbase = pVesa->base;
1329b40a6198Smrg	}
133050f2e948Smrg    }
133150f2e948Smrg#else
133245bc899bSmrg    if (pVesa->mapPhys != 0xa0000 && pVesa->pEnt->location.type == BUS_PCI)
133345bc899bSmrg	pVesa->base = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
133445bc899bSmrg				    pVesa->pciTag, pScrn->memPhysBase,
133545bc899bSmrg				    pVesa->mapSize);
133645bc899bSmrg    else
133745bc899bSmrg	pVesa->base = xf86MapDomainMemory(pScrn->scrnIndex, 0, pVesa->pciTag,
133845bc899bSmrg					  pScrn->memPhysBase, pVesa->mapSize);
133945bc899bSmrg
134045bc899bSmrg    if (pVesa->base) {
134145bc899bSmrg	if (pVesa->mapPhys != 0xa0000)
134245bc899bSmrg	    pVesa->VGAbase = xf86MapDomainMemory(pScrn->scrnIndex, 0,
134345bc899bSmrg						 pVesa->pciTag,
134445bc899bSmrg						 0xa0000, 0x10000);
134545bc899bSmrg	else
134645bc899bSmrg	    pVesa->VGAbase = pVesa->base;
134745bc899bSmrg    }
134850f2e948Smrg#endif
134945bc899bSmrg
1350b40a6198Smrg#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 12
135145bc899bSmrg    pVesa->ioBase = pScrn->domainIOBase;
1352b40a6198Smrg#else
1353b40a6198Smrg    pVesa->ioBase = 0;
1354b40a6198Smrg#endif
135545bc899bSmrg
135645bc899bSmrg    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, DEBUG_VERB,
1357b1fb1a22Smrg		   "virtual address = %p, VGAbase = %p\n"
135845bc899bSmrg		   "\tphysical address = 0x%lx, size = %ld\n",
1359b1fb1a22Smrg		   pVesa->base, pVesa->VGAbase,
1360b1fb1a22Smrg		   pScrn->memPhysBase, pVesa->mapSize);
136145bc899bSmrg
136245bc899bSmrg    return (pVesa->base != NULL);
136345bc899bSmrg}
136445bc899bSmrg
136545bc899bSmrgstatic void
136645bc899bSmrgVESAUnmapVidMem(ScrnInfoPtr pScrn)
136745bc899bSmrg{
136845bc899bSmrg    VESAPtr pVesa = VESAGetRec(pScrn);
136945bc899bSmrg
137045bc899bSmrg    if (pVesa->base == NULL)
137145bc899bSmrg	return;
137245bc899bSmrg
137350f2e948Smrg#ifdef XSERVER_LIBPCIACCESS
137450f2e948Smrg    if (pVesa->mapPhys != 0xa0000) {
137550f2e948Smrg	(void) pci_device_unmap_range(pVesa->pciInfo, pVesa->base,
137650f2e948Smrg				      pVesa->mapSize);
1377b40a6198Smrg	(void) pci_device_unmap_legacy(pVesa->pciInfo, pVesa->VGAbase,
1378b40a6198Smrg	                               0x10000);
137950f2e948Smrg    }
138050f2e948Smrg    else {
1381b40a6198Smrg	(void) pci_device_unmap_legacy(pVesa->pciInfo, pVesa->base,
1382b40a6198Smrg	                               pVesa->mapSize);
138350f2e948Smrg    }
138450f2e948Smrg#else
138545bc899bSmrg    xf86UnMapVidMem(pScrn->scrnIndex, pVesa->base, pVesa->mapSize);
138645bc899bSmrg    if (pVesa->mapPhys != 0xa0000)
138745bc899bSmrg	xf86UnMapVidMem(pScrn->scrnIndex, pVesa->VGAbase, 0x10000);
138850f2e948Smrg#endif
138945bc899bSmrg    pVesa->base = NULL;
139045bc899bSmrg}
139145bc899bSmrg
13925592a31fSmrg/* This code works, but is very slow for programs that use it intensively */
139345bc899bSmrgstatic void
139445bc899bSmrgVESALoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices,
139545bc899bSmrg		LOCO *colors, VisualPtr pVisual)
139645bc899bSmrg{
139745bc899bSmrg    VESAPtr pVesa = VESAGetRec(pScrn);
139845bc899bSmrg    int i, idx;
139945bc899bSmrg    int base;
140045bc899bSmrg
1401f2408745Smrg    if (!pVesa->savedPal) {
1402f2408745Smrg#define VESADACDelay()							       \
1403f2408745Smrg	do {                                                                   \
1404f2408745Smrg	   (void)inb(pVesa->ioBase + VGA_IOBASE_COLOR + VGA_IN_STAT_1_OFFSET); \
1405f2408745Smrg	   (void)inb(pVesa->ioBase + VGA_IOBASE_COLOR + VGA_IN_STAT_1_OFFSET); \
1406f2408745Smrg	} while (0)
1407f2408745Smrg
1408f2408745Smrg	for (i = 0; i < numColors; i++) {
1409f2408745Smrg	   idx = indices[i];
1410f2408745Smrg	   outb(pVesa->ioBase + VGA_DAC_WRITE_ADDR, idx);
1411f2408745Smrg	   VESADACDelay();
1412f2408745Smrg	   outb(pVesa->ioBase + VGA_DAC_DATA, colors[idx].red);
1413f2408745Smrg	   VESADACDelay();
1414f2408745Smrg	   outb(pVesa->ioBase + VGA_DAC_DATA, colors[idx].green);
1415f2408745Smrg	   VESADACDelay();
1416f2408745Smrg	   outb(pVesa->ioBase + VGA_DAC_DATA, colors[idx].blue);
1417f2408745Smrg	   VESADACDelay();
1418f2408745Smrg	}
1419f2408745Smrg	return;
1420f2408745Smrg    }
1421f2408745Smrg
142245bc899bSmrg    if (pVesa->pal == NULL)
1423b40a6198Smrg	pVesa->pal = calloc(1, sizeof(CARD32) * 256);
142445bc899bSmrg
142545bc899bSmrg    for (i = 0, base = idx = indices[i]; i < numColors; i++, idx++) {
142645bc899bSmrg	int j = indices[i];
142745bc899bSmrg
142845bc899bSmrg	if (j < 0 || j >= 256)
142945bc899bSmrg	    continue;
143045bc899bSmrg	pVesa->pal[j] = colors[j].blue |
143145bc899bSmrg			(colors[j].green << 8) |
143245bc899bSmrg			(colors[j].red << 16);
143345bc899bSmrg	if (j != idx) {
143445bc899bSmrg	    VBESetGetPaletteData(pVesa->pVbe, TRUE, base, idx - base,
143545bc899bSmrg				  pVesa->pal + base, FALSE, TRUE);
143645bc899bSmrg	    idx = base = j;
143745bc899bSmrg	}
143845bc899bSmrg    }
143945bc899bSmrg
144045bc899bSmrg    if (idx - 1 == indices[i - 1])
144145bc899bSmrg	VBESetGetPaletteData(pVesa->pVbe, TRUE, base, idx - base,
144245bc899bSmrg			      pVesa->pal + base, FALSE, TRUE);
144345bc899bSmrg}
144445bc899bSmrg
144545bc899bSmrg/*
144645bc899bSmrg * Just adapted from the std* functions in vgaHW.c
144745bc899bSmrg */
144845bc899bSmrgstatic void
144945bc899bSmrgWriteAttr(VESAPtr pVesa, int index, int value)
145045bc899bSmrg{
145145bc899bSmrg    (void) inb(pVesa->ioBase + VGA_IOBASE_COLOR + VGA_IN_STAT_1_OFFSET);
145245bc899bSmrg
145345bc899bSmrg    index |= 0x20;
145445bc899bSmrg    outb(pVesa->ioBase + VGA_ATTR_INDEX, index);
145545bc899bSmrg    outb(pVesa->ioBase + VGA_ATTR_DATA_W, value);
145645bc899bSmrg}
145745bc899bSmrg
145845bc899bSmrgstatic int
145945bc899bSmrgReadAttr(VESAPtr pVesa, int index)
146045bc899bSmrg{
146145bc899bSmrg    (void) inb(pVesa->ioBase + VGA_IOBASE_COLOR + VGA_IN_STAT_1_OFFSET);
146245bc899bSmrg
146345bc899bSmrg    index |= 0x20;
146445bc899bSmrg    outb(pVesa->ioBase + VGA_ATTR_INDEX, index);
146545bc899bSmrg    return (inb(pVesa->ioBase + VGA_ATTR_DATA_R));
146645bc899bSmrg}
146745bc899bSmrg
146845bc899bSmrg#define WriteMiscOut(value)	outb(pVesa->ioBase + VGA_MISC_OUT_W, value)
146945bc899bSmrg#define ReadMiscOut()		inb(pVesa->ioBase + VGA_MISC_OUT_R)
147045bc899bSmrg#define WriteSeq(index, value)	outb(pVesa->ioBase + VGA_SEQ_INDEX, index);\
147145bc899bSmrg				outb(pVesa->ioBase + VGA_SEQ_DATA, value)
147245bc899bSmrg
147345bc899bSmrgstatic int
147445bc899bSmrgReadSeq(VESAPtr pVesa, int index)
147545bc899bSmrg{
147645bc899bSmrg    outb(pVesa->ioBase + VGA_SEQ_INDEX, index);
147745bc899bSmrg
147845bc899bSmrg    return (inb(pVesa->ioBase + VGA_SEQ_DATA));
147945bc899bSmrg}
148045bc899bSmrg
148145bc899bSmrg#define WriteGr(index, value)				\
148245bc899bSmrg    outb(pVesa->ioBase + VGA_GRAPH_INDEX, index);	\
148345bc899bSmrg    outb(pVesa->ioBase + VGA_GRAPH_DATA, value)
148445bc899bSmrg
148545bc899bSmrgstatic int
148645bc899bSmrgReadGr(VESAPtr pVesa, int index)
148745bc899bSmrg{
148845bc899bSmrg    outb(pVesa->ioBase + VGA_GRAPH_INDEX, index);
148945bc899bSmrg
149045bc899bSmrg    return (inb(pVesa->ioBase + VGA_GRAPH_DATA));
149145bc899bSmrg}
149245bc899bSmrg
149345bc899bSmrg#define WriteCrtc(index, value)						     \
149445bc899bSmrg    outb(pVesa->ioBase + (VGA_IOBASE_COLOR + VGA_CRTC_INDEX_OFFSET), index); \
149545bc899bSmrg    outb(pVesa->ioBase + (VGA_IOBASE_COLOR + VGA_CRTC_DATA_OFFSET), value)
149645bc899bSmrg
149745bc899bSmrgstatic void
149845bc899bSmrgSeqReset(VESAPtr pVesa, Bool start)
149945bc899bSmrg{
150045bc899bSmrg    if (start) {
150145bc899bSmrg	WriteSeq(0x00, 0x01);		/* Synchronous Reset */
150245bc899bSmrg    }
150345bc899bSmrg    else {
150445bc899bSmrg	WriteSeq(0x00, 0x03);		/* End Reset */
150545bc899bSmrg    }
150645bc899bSmrg}
150745bc899bSmrg
150845bc899bSmrgstatic void
150945bc899bSmrgSaveFonts(ScrnInfoPtr pScrn)
151045bc899bSmrg{
151145bc899bSmrg    VESAPtr pVesa = VESAGetRec(pScrn);
151245bc899bSmrg    unsigned char miscOut, attr10, gr4, gr5, gr6, seq2, seq4, scrn;
151345bc899bSmrg
151445bc899bSmrg    if (pVesa->fonts != NULL)
151545bc899bSmrg	return;
151645bc899bSmrg
151745bc899bSmrg    /* If in graphics mode, don't save anything */
151845bc899bSmrg    attr10 = ReadAttr(pVesa, 0x10);
151945bc899bSmrg    if (attr10 & 0x01)
152045bc899bSmrg	return;
152145bc899bSmrg
1522b40a6198Smrg    pVesa->fonts = malloc(16384);
152345bc899bSmrg
152445bc899bSmrg    /* save the registers that are needed here */
152545bc899bSmrg    miscOut = ReadMiscOut();
152645bc899bSmrg    gr4 = ReadGr(pVesa, 0x04);
152745bc899bSmrg    gr5 = ReadGr(pVesa, 0x05);
152845bc899bSmrg    gr6 = ReadGr(pVesa, 0x06);
152945bc899bSmrg    seq2 = ReadSeq(pVesa, 0x02);
153045bc899bSmrg    seq4 = ReadSeq(pVesa, 0x04);
153145bc899bSmrg
153245bc899bSmrg    /* Force into colour mode */
153345bc899bSmrg    WriteMiscOut(miscOut | 0x01);
153445bc899bSmrg
153545bc899bSmrg    scrn = ReadSeq(pVesa, 0x01) | 0x20;
153645bc899bSmrg    SeqReset(pVesa, TRUE);
153745bc899bSmrg    WriteSeq(0x01, scrn);
153845bc899bSmrg    SeqReset(pVesa, FALSE);
153945bc899bSmrg
154045bc899bSmrg    WriteAttr(pVesa, 0x10, 0x01);	/* graphics mode */
154145bc899bSmrg
154245bc899bSmrg    /*font1 */
154345bc899bSmrg    WriteSeq(0x02, 0x04);	/* write to plane 2 */
154445bc899bSmrg    WriteSeq(0x04, 0x06);	/* enable plane graphics */
154545bc899bSmrg    WriteGr(0x04, 0x02);	/* read plane 2 */
154645bc899bSmrg    WriteGr(0x05, 0x00);	/* write mode 0, read mode 0 */
154745bc899bSmrg    WriteGr(0x06, 0x05);	/* set graphics */
154845bc899bSmrg    slowbcopy_frombus(pVesa->VGAbase, pVesa->fonts, 8192);
154945bc899bSmrg
155045bc899bSmrg    /* font2 */
155145bc899bSmrg    WriteSeq(0x02, 0x08);	/* write to plane 3 */
155245bc899bSmrg    WriteSeq(0x04, 0x06);	/* enable plane graphics */
155345bc899bSmrg    WriteGr(0x04, 0x03);	/* read plane 3 */
155445bc899bSmrg    WriteGr(0x05, 0x00);	/* write mode 0, read mode 0 */
155545bc899bSmrg    WriteGr(0x06, 0x05);	/* set graphics */
155645bc899bSmrg    slowbcopy_frombus(pVesa->VGAbase, pVesa->fonts + 8192, 8192);
155745bc899bSmrg
155845bc899bSmrg    scrn = ReadSeq(pVesa, 0x01) & ~0x20;
155945bc899bSmrg    SeqReset(pVesa, TRUE);
156045bc899bSmrg    WriteSeq(0x01, scrn);
156145bc899bSmrg    SeqReset(pVesa, FALSE);
156245bc899bSmrg
156345bc899bSmrg    /* Restore clobbered registers */
156445bc899bSmrg    WriteAttr(pVesa, 0x10, attr10);
156545bc899bSmrg    WriteSeq(0x02, seq2);
156645bc899bSmrg    WriteSeq(0x04, seq4);
156745bc899bSmrg    WriteGr(0x04, gr4);
156845bc899bSmrg    WriteGr(0x05, gr5);
156945bc899bSmrg    WriteGr(0x06, gr6);
157045bc899bSmrg    WriteMiscOut(miscOut);
157145bc899bSmrg}
157245bc899bSmrg
157345bc899bSmrgstatic void
157445bc899bSmrgRestoreFonts(ScrnInfoPtr pScrn)
157545bc899bSmrg{
157645bc899bSmrg    VESAPtr pVesa = VESAGetRec(pScrn);
157745bc899bSmrg    unsigned char miscOut, attr10, gr1, gr3, gr4, gr5, gr6, gr8, seq2, seq4, scrn;
157845bc899bSmrg
157945bc899bSmrg    if (pVesa->fonts == NULL)
158045bc899bSmrg	return;
158145bc899bSmrg
158245bc899bSmrg    if (pVesa->mapPhys == 0xa0000 && pVesa->curBank != 0)
158345bc899bSmrg	VESABankSwitch(pScrn->pScreen, 0);
158445bc899bSmrg
158545bc899bSmrg    /* save the registers that are needed here */
158645bc899bSmrg    miscOut = ReadMiscOut();
158745bc899bSmrg    attr10 = ReadAttr(pVesa, 0x10);
158845bc899bSmrg    gr1 = ReadGr(pVesa, 0x01);
158945bc899bSmrg    gr3 = ReadGr(pVesa, 0x03);
159045bc899bSmrg    gr4 = ReadGr(pVesa, 0x04);
159145bc899bSmrg    gr5 = ReadGr(pVesa, 0x05);
159245bc899bSmrg    gr6 = ReadGr(pVesa, 0x06);
159345bc899bSmrg    gr8 = ReadGr(pVesa, 0x08);
159445bc899bSmrg    seq2 = ReadSeq(pVesa, 0x02);
159545bc899bSmrg    seq4 = ReadSeq(pVesa, 0x04);
159645bc899bSmrg
159745bc899bSmrg    /* Force into colour mode */
159845bc899bSmrg    WriteMiscOut(miscOut | 0x01);
159945bc899bSmrg
160045bc899bSmrg    scrn = ReadSeq(pVesa, 0x01) | 0x20;
160145bc899bSmrg    SeqReset(pVesa, TRUE);
160245bc899bSmrg    WriteSeq(0x01, scrn);
160345bc899bSmrg    SeqReset(pVesa, FALSE);
160445bc899bSmrg
160545bc899bSmrg    WriteAttr(pVesa, 0x10, 0x01);	/* graphics mode */
160645bc899bSmrg    if (pScrn->depth == 4) {
160745bc899bSmrg	/* GJA */
160845bc899bSmrg	WriteGr(0x03, 0x00);	/* don't rotate, write unmodified */
160945bc899bSmrg	WriteGr(0x08, 0xFF);	/* write all bits in a byte */
161045bc899bSmrg	WriteGr(0x01, 0x00);	/* all planes come from CPU */
161145bc899bSmrg    }
161245bc899bSmrg
161345bc899bSmrg    WriteSeq(0x02, 0x04);   /* write to plane 2 */
161445bc899bSmrg    WriteSeq(0x04, 0x06);   /* enable plane graphics */
161545bc899bSmrg    WriteGr(0x04, 0x02);    /* read plane 2 */
161645bc899bSmrg    WriteGr(0x05, 0x00);    /* write mode 0, read mode 0 */
161745bc899bSmrg    WriteGr(0x06, 0x05);    /* set graphics */
161845bc899bSmrg    slowbcopy_tobus(pVesa->fonts, pVesa->VGAbase, 8192);
161945bc899bSmrg
162045bc899bSmrg    WriteSeq(0x02, 0x08);   /* write to plane 3 */
162145bc899bSmrg    WriteSeq(0x04, 0x06);   /* enable plane graphics */
162245bc899bSmrg    WriteGr(0x04, 0x03);    /* read plane 3 */
162345bc899bSmrg    WriteGr(0x05, 0x00);    /* write mode 0, read mode 0 */
162445bc899bSmrg    WriteGr(0x06, 0x05);    /* set graphics */
162545bc899bSmrg    slowbcopy_tobus(pVesa->fonts + 8192, pVesa->VGAbase, 8192);
162645bc899bSmrg
162745bc899bSmrg    scrn = ReadSeq(pVesa, 0x01) & ~0x20;
162845bc899bSmrg    SeqReset(pVesa, TRUE);
162945bc899bSmrg    WriteSeq(0x01, scrn);
163045bc899bSmrg    SeqReset(pVesa, FALSE);
163145bc899bSmrg
163245bc899bSmrg    /* restore the registers that were changed */
163345bc899bSmrg    WriteMiscOut(miscOut);
163445bc899bSmrg    WriteAttr(pVesa, 0x10, attr10);
163545bc899bSmrg    WriteGr(0x01, gr1);
163645bc899bSmrg    WriteGr(0x03, gr3);
163745bc899bSmrg    WriteGr(0x04, gr4);
163845bc899bSmrg    WriteGr(0x05, gr5);
163945bc899bSmrg    WriteGr(0x06, gr6);
164045bc899bSmrg    WriteGr(0x08, gr8);
164145bc899bSmrg    WriteSeq(0x02, seq2);
164245bc899bSmrg    WriteSeq(0x04, seq4);
164345bc899bSmrg}
164445bc899bSmrg
164545bc899bSmrgstatic Bool
164645bc899bSmrgVESASaveScreen(ScreenPtr pScreen, int mode)
164745bc899bSmrg{
1648b40a6198Smrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
164945bc899bSmrg    VESAPtr pVesa = VESAGetRec(pScrn);
165045bc899bSmrg    Bool on = xf86IsUnblank(mode);
165145bc899bSmrg
165245bc899bSmrg    if (on)
165345bc899bSmrg	SetTimeSinceLastInputEvent();
165445bc899bSmrg
165545bc899bSmrg    if (pScrn->vtSema) {
165645bc899bSmrg	unsigned char scrn = ReadSeq(pVesa, 0x01);
165745bc899bSmrg
165845bc899bSmrg	if (on)
165945bc899bSmrg	    scrn &= ~0x20;
166045bc899bSmrg	else
166145bc899bSmrg	    scrn |= 0x20;
166245bc899bSmrg	SeqReset(pVesa, TRUE);
166345bc899bSmrg	WriteSeq(0x01, scrn);
166445bc899bSmrg	SeqReset(pVesa, FALSE);
166545bc899bSmrg    }
166645bc899bSmrg
166745bc899bSmrg    return (TRUE);
166845bc899bSmrg}
166945bc899bSmrg
167045bc899bSmrgstatic int
167145bc899bSmrgVESABankSwitch(ScreenPtr pScreen, unsigned int iBank)
167245bc899bSmrg{
1673b40a6198Smrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
167445bc899bSmrg    VESAPtr pVesa = VESAGetRec(pScrn);
167545bc899bSmrg
167645bc899bSmrg    if (pVesa->curBank == iBank)
167745bc899bSmrg	return (0);
167845bc899bSmrg    if (!VBEBankSwitch(pVesa->pVbe, iBank, 0))
167945bc899bSmrg        return (1);
168045bc899bSmrg    if (pVesa->bankSwitchWindowB) {
168145bc899bSmrg        if (!VBEBankSwitch(pVesa->pVbe, iBank, 1))
168245bc899bSmrg	   return (1);
168345bc899bSmrg    }
168445bc899bSmrg    pVesa->curBank = iBank;
168545bc899bSmrg
168645bc899bSmrg    return (0);
168745bc899bSmrg}
168845bc899bSmrg
168945bc899bSmrgBool
169045bc899bSmrgVESASaveRestore(ScrnInfoPtr pScrn, vbeSaveRestoreFunction function)
169145bc899bSmrg{
169245bc899bSmrg    VESAPtr pVesa;
169345bc899bSmrg
1694c97b1c41Smrg    if (function < MODE_QUERY || function > MODE_RESTORE)
169545bc899bSmrg	return (FALSE);
169645bc899bSmrg
169745bc899bSmrg    pVesa = VESAGetRec(pScrn);
169845bc899bSmrg
169945bc899bSmrg
170045bc899bSmrg    /* Query amount of memory to save state */
170145bc899bSmrg    if (function == MODE_QUERY ||
170245bc899bSmrg	(function == MODE_SAVE && pVesa->state == NULL)) {
170345bc899bSmrg
170445bc899bSmrg	/* Make sure we save at least this information in case of failure */
170545bc899bSmrg	(void)VBEGetVBEMode(pVesa->pVbe, &pVesa->stateMode);
170645bc899bSmrg	SaveFonts(pScrn);
170745bc899bSmrg
170845bc899bSmrg	if (pVesa->major > 1) {
170945bc899bSmrg	    if (!VBESaveRestore(pVesa->pVbe,function,(pointer)&pVesa->state,
171045bc899bSmrg				&pVesa->stateSize,&pVesa->statePage))
171145bc899bSmrg	        return FALSE;
171245bc899bSmrg
171345bc899bSmrg	}
171445bc899bSmrg    }
171545bc899bSmrg
171645bc899bSmrg    /* Save/Restore Super VGA state */
171745bc899bSmrg    if (function != MODE_QUERY) {
171845bc899bSmrg        Bool retval = TRUE;
171945bc899bSmrg
172045bc899bSmrg	if (pVesa->major > 1) {
172145bc899bSmrg	    if (function == MODE_RESTORE)
172245bc899bSmrg		memcpy(pVesa->state, pVesa->pstate, pVesa->stateSize);
172345bc899bSmrg
172445bc899bSmrg	    if ((retval = VBESaveRestore(pVesa->pVbe,function,
172545bc899bSmrg					 (pointer)&pVesa->state,
172645bc899bSmrg					 &pVesa->stateSize,&pVesa->statePage))
172745bc899bSmrg		&& function == MODE_SAVE) {
172845bc899bSmrg	        /* don't rely on the memory not being touched */
172945bc899bSmrg	        if (pVesa->pstate == NULL)
1730b40a6198Smrg		    pVesa->pstate = malloc(pVesa->stateSize);
173145bc899bSmrg		memcpy(pVesa->pstate, pVesa->state, pVesa->stateSize);
173245bc899bSmrg	    }
173345bc899bSmrg	}
173445bc899bSmrg
173545bc899bSmrg	if (function == MODE_RESTORE) {
173645bc899bSmrg	    VBESetVBEMode(pVesa->pVbe, pVesa->stateMode, NULL);
173745bc899bSmrg	    RestoreFonts(pScrn);
173845bc899bSmrg	}
173945bc899bSmrg
174045bc899bSmrg	if (!retval)
174145bc899bSmrg	    return (FALSE);
174245bc899bSmrg
174345bc899bSmrg    }
174445bc899bSmrg
174545bc899bSmrg    return (TRUE);
174645bc899bSmrg}
174745bc899bSmrg
174845bc899bSmrgstatic void
174945bc899bSmrgVESADisplayPowerManagementSet(ScrnInfoPtr pScrn, int mode,
175045bc899bSmrg                int flags)
175145bc899bSmrg{
175245bc899bSmrg    VESAPtr pVesa = VESAGetRec(pScrn);
175345bc899bSmrg
175445bc899bSmrg    if (!pScrn->vtSema)
175545bc899bSmrg	return;
175645bc899bSmrg
175750f2e948Smrg    VBEDPMSSet(pVesa->pVbe, mode);
175845bc899bSmrg}
175945bc899bSmrg
176045bc899bSmrg/***********************************************************************
176145bc899bSmrg * DGA stuff
176245bc899bSmrg ***********************************************************************/
176345bc899bSmrgstatic Bool VESADGAOpenFramebuffer(ScrnInfoPtr pScrn, char **DeviceName,
176445bc899bSmrg				   unsigned char **ApertureBase,
176545bc899bSmrg				   int *ApertureSize, int *ApertureOffset,
176645bc899bSmrg				   int *flags);
176745bc899bSmrgstatic Bool VESADGASetMode(ScrnInfoPtr pScrn, DGAModePtr pDGAMode);
176845bc899bSmrgstatic void VESADGASetViewport(ScrnInfoPtr pScrn, int x, int y, int flags);
176945bc899bSmrg
177045bc899bSmrgstatic Bool
177145bc899bSmrgVESADGAOpenFramebuffer(ScrnInfoPtr pScrn, char **DeviceName,
177245bc899bSmrg		       unsigned char **ApertureBase, int *ApertureSize,
177345bc899bSmrg		       int *ApertureOffset, int *flags)
177445bc899bSmrg{
177545bc899bSmrg    VESAPtr pVesa = VESAGetRec(pScrn);
177645bc899bSmrg
177745bc899bSmrg    *DeviceName = NULL;		/* No special device */
177845bc899bSmrg    *ApertureBase = (unsigned char *)(long)(pVesa->mapPhys);
177945bc899bSmrg    *ApertureSize = pVesa->mapSize;
178045bc899bSmrg    *ApertureOffset = pVesa->mapOff;
178145bc899bSmrg    *flags = DGA_NEED_ROOT;
178245bc899bSmrg
178345bc899bSmrg    return (TRUE);
178445bc899bSmrg}
178545bc899bSmrg
178645bc899bSmrgstatic Bool
178745bc899bSmrgVESADGASetMode(ScrnInfoPtr pScrn, DGAModePtr pDGAMode)
178845bc899bSmrg{
178945bc899bSmrg    DisplayModePtr pMode;
179045bc899bSmrg    int scrnIdx = pScrn->pScreen->myNum;
179145bc899bSmrg    int frameX0, frameY0;
179245bc899bSmrg
179345bc899bSmrg    if (pDGAMode) {
179445bc899bSmrg	pMode = pDGAMode->mode;
179545bc899bSmrg	frameX0 = frameY0 = 0;
179645bc899bSmrg    }
179745bc899bSmrg    else {
179845bc899bSmrg	if (!(pMode = pScrn->currentMode))
179945bc899bSmrg	    return (TRUE);
180045bc899bSmrg
180145bc899bSmrg	frameX0 = pScrn->frameX0;
180245bc899bSmrg	frameY0 = pScrn->frameY0;
180345bc899bSmrg    }
180445bc899bSmrg
1805b40a6198Smrg    if (!(*pScrn->SwitchMode)(SWITCH_MODE_ARGS(pScrn, pMode)))
180645bc899bSmrg	return (FALSE);
1807b40a6198Smrg    (*pScrn->AdjustFrame)(ADJUST_FRAME_ARGS(pScrn, frameX0, frameY0));
180845bc899bSmrg
180945bc899bSmrg    return (TRUE);
181045bc899bSmrg}
181145bc899bSmrg
181245bc899bSmrgstatic void
181345bc899bSmrgVESADGASetViewport(ScrnInfoPtr pScrn, int x, int y, int flags)
181445bc899bSmrg{
1815b40a6198Smrg    (*pScrn->AdjustFrame)(ADJUST_FRAME_ARGS(pScrn, x, y));
181645bc899bSmrg}
181745bc899bSmrg
181845bc899bSmrgstatic int
181945bc899bSmrgVESADGAGetViewport(ScrnInfoPtr pScrn)
182045bc899bSmrg{
182145bc899bSmrg    return (0);
182245bc899bSmrg}
182345bc899bSmrg
182445bc899bSmrgstatic DGAFunctionRec VESADGAFunctions =
182545bc899bSmrg{
182645bc899bSmrg    VESADGAOpenFramebuffer,
182745bc899bSmrg    NULL,       /* CloseFramebuffer */
182845bc899bSmrg    VESADGASetMode,
182945bc899bSmrg    VESADGASetViewport,
183045bc899bSmrg    VESADGAGetViewport,
183145bc899bSmrg    NULL,       /* Sync */
183245bc899bSmrg    NULL,       /* FillRect */
183345bc899bSmrg    NULL,       /* BlitRect */
183445bc899bSmrg    NULL,       /* BlitTransRect */
183545bc899bSmrg};
183645bc899bSmrg
183745bc899bSmrgstatic void
183845bc899bSmrgVESADGAAddModes(ScrnInfoPtr pScrn)
183945bc899bSmrg{
184045bc899bSmrg    VESAPtr pVesa = VESAGetRec(pScrn);
184145bc899bSmrg    DisplayModePtr pMode = pScrn->modes;
184245bc899bSmrg    DGAModePtr pDGAMode;
184345bc899bSmrg
184445bc899bSmrg    do {
1845b40a6198Smrg	pDGAMode = realloc(pVesa->pDGAMode,
184645bc899bSmrg			    (pVesa->nDGAMode + 1) * sizeof(DGAModeRec));
184745bc899bSmrg	if (!pDGAMode)
184845bc899bSmrg	    break;
184945bc899bSmrg
185045bc899bSmrg	pVesa->pDGAMode = pDGAMode;
185145bc899bSmrg	pDGAMode += pVesa->nDGAMode;
185245bc899bSmrg	(void)memset(pDGAMode, 0, sizeof(DGAModeRec));
185345bc899bSmrg
185445bc899bSmrg	++pVesa->nDGAMode;
185545bc899bSmrg	pDGAMode->mode = pMode;
185645bc899bSmrg	pDGAMode->flags = DGA_CONCURRENT_ACCESS | DGA_PIXMAP_AVAILABLE;
185745bc899bSmrg	pDGAMode->byteOrder = pScrn->imageByteOrder;
185845bc899bSmrg	pDGAMode->depth = pScrn->depth;
185945bc899bSmrg	pDGAMode->bitsPerPixel = pScrn->bitsPerPixel;
186045bc899bSmrg	pDGAMode->red_mask = pScrn->mask.red;
186145bc899bSmrg	pDGAMode->green_mask = pScrn->mask.green;
186245bc899bSmrg	pDGAMode->blue_mask = pScrn->mask.blue;
186345bc899bSmrg	pDGAMode->visualClass = pScrn->bitsPerPixel > 8 ?
186445bc899bSmrg	    TrueColor : PseudoColor;
186545bc899bSmrg	pDGAMode->xViewportStep = 1;
186645bc899bSmrg	pDGAMode->yViewportStep = 1;
186745bc899bSmrg	pDGAMode->viewportWidth = pMode->HDisplay;
186845bc899bSmrg	pDGAMode->viewportHeight = pMode->VDisplay;
186945bc899bSmrg
187045bc899bSmrg	pDGAMode->bytesPerScanline = pVesa->maxBytesPerScanline;
187145bc899bSmrg	pDGAMode->imageWidth = pMode->HDisplay;
187245bc899bSmrg	pDGAMode->imageHeight =  pMode->VDisplay;
187345bc899bSmrg	pDGAMode->pixmapWidth = pDGAMode->imageWidth;
187445bc899bSmrg	pDGAMode->pixmapHeight = pDGAMode->imageHeight;
187545bc899bSmrg	pDGAMode->maxViewportX = pScrn->virtualX -
187645bc899bSmrg				    pDGAMode->viewportWidth;
187745bc899bSmrg	pDGAMode->maxViewportY = pScrn->virtualY -
187845bc899bSmrg				    pDGAMode->viewportHeight;
187945bc899bSmrg
188045bc899bSmrg	pDGAMode->address = pVesa->base;
188145bc899bSmrg
188245bc899bSmrg	pMode = pMode->next;
188345bc899bSmrg    } while (pMode != pScrn->modes);
188445bc899bSmrg}
188545bc899bSmrg
188645bc899bSmrgstatic Bool
188745bc899bSmrgVESADGAInit(ScrnInfoPtr pScrn, ScreenPtr pScreen)
188845bc899bSmrg{
188945bc899bSmrg    VESAPtr pVesa = VESAGetRec(pScrn);
189045bc899bSmrg
189145bc899bSmrg    if (pScrn->depth < 8 || pVesa->mapPhys == 0xa0000L)
189245bc899bSmrg	return (FALSE);
189345bc899bSmrg
189445bc899bSmrg    if (!pVesa->nDGAMode)
189545bc899bSmrg	VESADGAAddModes(pScrn);
189645bc899bSmrg
189745bc899bSmrg    return (DGAInit(pScreen, &VESADGAFunctions,
189845bc899bSmrg	    pVesa->pDGAMode, pVesa->nDGAMode));
189945bc899bSmrg}
1900