vesa.c revision 3a925b30
16abeab63Snia#define DEBUG_VERB 2
26abeab63Snia/*
36abeab63Snia * Copyright (c) 2000 by Conectiva S.A. (http://www.conectiva.com)
4XS�)�*�+�+�+�+�+�+�+�+�+�+�+�+�+�+�+�+�+�+��&�&�&�&�&�&�&�&�&�&�&�&�&�&�&��������@��@��@��@���#�$�%�&�'�'�'�'�'�'�'�'�'�&�%�$�#��#�$�%�&�'�'�'�'�'�'�'�'�'�&�%�$�#��#�$�%�&�'�'�'�'�'�'�'�'�'�&�%�$�#��%�&�'�(�)�*�+�+�+�+�+�+�+�+�+�+�+�+�+�*�)�(�'�&�%��!�"�#�#��.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.��.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.��.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.����������������������������������������������������������������������������������������������������������������������������������"�!� � �!�"�#�$�%�&�'�(��������������������� * Copyright 2008 Red Hat, Inc.
56abeab63Snia *
66abeab63Snia * Permission is hereby granted, free of charge, to any person obtaining a
76abeab63Snia * copy of this software and associated documentation files (the "Software"),
86abeab63Snia * to deal in the Software without restriction, including without limitation
96abeab63Snia * the rights to use, copy, modify, merge, publish, distribute, sublicense,
106abeab63Snia * and/or sell copies of the Software, and to permit persons to whom the
116abeab63Snia * Software is furnished to do so, subject to the following conditions:
126abeab63Snia *
131S�'������������������	 ��=�=�<�;�:� * The above copyright notice and this permission notice shall be included in
146abeab63Snia * all copies or substantial portions of the Software.
156abeab63Snia *
166abeab63Snia * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
176abeab63Snia * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
186abeab63Snia * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
196abeab63Snia * CONECTIVA LINUX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
206abeab63Snia * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
211S�'�'�'�'�'�'�'�'�'�'�)�+�-�/� * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
226abeab63Snia * SOFTWARE.
231S�'�'�'�'�'�'�'�'�'�'�)�+�-�/� *
246abeab63Snia * Except as contained in this notice, the name of Conectiva Linux shall
251S�'�'�'�'�'�'�'�'�'�'�)�+�-�/� * not be used in advertising or otherwise to promote the sale, use or other
266abeab63Snia * dealings in this Software without prior written authorization from
276abeab63Snia * Conectiva Linux.
286abeab63Snia *
296abeab63Snia * Authors: Paulo César Pereira de Andrade <pcpa@conectiva.com.br>
306abeab63Snia *          David Dawes <dawes@xfree86.org>
316abeab63Snia *          Adam Jackson <ajax@redhat.com>
326abeab63Snia */
336abeab63Snia
346abeab63Snia/*
356abeab63Snia * TODO:
366abeab63Snia * - PanelID might give us useful size hints.
376abeab63Snia * - Port to RANDR 1.2 setup to make mode selection slightly better
386abeab63Snia * - Port to RANDR 1.2 to drop the old-school DGA junk
396abeab63Snia * - VBE/SCI for secondary DDC method?
406abeab63Snia */
416abeab63Snia
426abeab63Snia#ifdef HAVE_CONFIG_H
436abeab63Snia#include "config.h"
446abeab63Snia#endif
450S&#
466abeab63Snia#include <string.h>
476abeab63Snia
486abeab63Snia#include "vesa.h"
496abeab63Snia
506abeab63Snia/* All drivers initialising the SW cursor need this */
516abeab63Snia#include "mipointer.h"
52xeSCS����������������{hVE
536abeab63Snia/* All drivers implementing backing store need this */
546abeab63Snia#include "mibstore.h"
556abeab63Snia
566abeab63Snia/* Colormap handling */
576abeab63Snia#include "micmap.h"
586abeab63Snia#include "xf86cmap.h"
596abeab63Snia#include "xf86Modes.h"
606abeab63Snia
616abeab63Snia/* DPMS */
626abeab63Snia#ifdef HAVE_XEXTPROTO_71
636abeab63Snia#include <X11/extensions/dpmsconst.h>
646abeab63Snia#else
656abeab63Snia#define DPMS_SERVER
666abeab63Snia#include <X11/extensions/dpms.h>
676abeab63Snia#endif
686abeab63Snia
696abeab63Snia
706abeab63Snia/* Mandatory functions */
716abeab63Sniastatic const OptionInfoRec * VESAAvailableOptions(int chipid, int busid);
726abeab63Sniastatic void VESAIdentify(int flags);
736abeab63Sniastatic Bool VESAProbe(DriverPtr drv, int flags);
746abeab63Snia#ifdef XSERVER_LIBPCIACCESS
756abeab63Sniastatic Bool VESAPciProbe(DriverPtr drv, int entity_num,
766abeab63Snia     struct pci_device *dev, intptr_t match_data);
776abeab63Snia#endif
786abeab63Sniastatic Bool VESAPreInit(ScrnInfoPtr pScrn, int flags);
796abeab63Sniastatic Bool VESAScreenInit(int Index, ScreenPtr pScreen, int argc,
806abeab63Snia			   char **argv);
816abeab63Sniastatic Bool VESAEnterVT(int scrnIndex, int flags);
826abeab63Sniastatic void VESALeaveVT(int scrnIndex, int flags);
836abeab63Sniastatic Bool VESACloseScreen(int scrnIndex, ScreenPtr pScreen);
84tgZLSstatic Bool VESASaveScreen(ScreenPtr pScreen, int mode);
85rgS
866abeab63Sniastatic Bool VESASwitchMode(int scrnIndex, DisplayModePtr pMode, int flags);
876abeab63Sniastatic Bool VESASetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode);
886abeab63Sniastatic void VESAAdjustFrame(int scrnIndex, int x, int y, int flags);
896abeab63Sniastatic void VESAFreeScreen(int scrnIndex, int flags);
906abeab63Sniastatic void VESAFreeRec(ScrnInfoPtr pScrn);
916abeab63Sniastatic VESAPtr VESAGetRec(ScrnInfoPtr pScrn);
926abeab63Snia
936abeab63Sniastatic void
946abeab63SniaVESADisplayPowerManagementSet(ScrnInfoPtr pScrn, int mode,
956abeab63Snia                int flags);
966abeab63Snia
976abeab63Snia/* locally used functions */
986abeab63Sniastatic int VESAFindIsaDevice(GDevPtr dev);
996abeab63Sniastatic Bool VESAMapVidMem(ScrnInfoPtr pScrn);
1006abeab63Sniastatic void VESAUnmapVidMem(ScrnInfoPtr pScrn);
1016abeab63Sniastatic int VESABankSwitch(ScreenPtr pScreen, unsigned int iBank);
1026abeab63Sniastatic void VESALoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices,
1036abeab63Snia			    LOCO *colors, VisualPtr pVisual);
1046abeab63Sniastatic void SaveFonts(ScrnInfoPtr pScrn);
1056abeab63Sniastatic void RestoreFonts(ScrnInfoPtr pScrn);
1066abeab63Sniastatic Bool
1076abeab63SniaVESASaveRestore(ScrnInfoPtr pScrn, vbeSaveRestoreFunction function);
1086abeab63Snia
1096abeab63Sniastatic void *VESAWindowLinear(ScreenPtr pScrn, CARD32 row, CARD32 offset,
1106abeab63Snia			      int mode, CARD32 *size, void *closure);
1116abeab63Sniastatic void *VESAWindowWindowed(ScreenPtr pScrn, CARD32 row, CARD32 offset,
1126abeab63Snia				int mode, CARD32 *size, void *closure);
1136abeab63Snia
1146abeab63Sniastatic Bool VESADGAInit(ScrnInfoPtr pScrn, ScreenPtr pScreen);
1156abeab63Snia
1166abeab63Sniaenum GenericTypes
1176abeab63Snia{
1186abeab63Snia    CHIP_VESA_GENERIC
1196abeab63Snia};
1206abeab63Snia
1216abeab63Snia#ifdef XSERVER_LIBPCIACCESS
1226abeab63Sniastatic const struct pci_id_match vesa_device_match[] = {
1232S    {
1246abeab63Snia	PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY,
1256abeab63Snia	0x00030000, 0x00ffffff, CHIP_VESA_GENERIC
1266abeab63Snia    },
1276abeab63Snia
1286abeab63Snia    { 0, 0, 0 },
1296abeab63Snia};
1306abeab63Snia#endif
1316abeab63Snia
1326abeab63Snia/* Supported chipsets */
1336abeab63Sniastatic SymTabRec VESAChipsets[] =
1346abeab63Snia{
1356abeab63Snia    {CHIP_VESA_GENERIC, "vesa"},
1366abeab63Snia    {-1,		 NULL}
1376abeab63Snia};
1386abeab63Snia
1396abeab63Snia#ifndef XSERVER_LIBPCIACCESS
1406abeab63Sniastatic PciChipsets VESAPCIchipsets[] = {
1416abeab63Snia  { CHIP_VESA_GENERIC, PCI_CHIP_VGA, RES_SHARED_VGA },
1426abeab63Snia  { -1,		-1,	   RES_UNDEFINED },
1436abeab63Snia};
1446abeab63Snia#endif
1456abeab63Snia
1466abeab63Snia#ifdef HAVE_ISA
1476abeab63Sniastatic IsaChipsets VESAISAchipsets[] = {
1486abeab63Snia  {CHIP_VESA_GENERIC, RES_EXCLUSIVE_VGA},
1496abeab63Snia  {-1,		0 }
1506abeab63Snia};
1516abeab63Snia#endif
1526abeab63Snia
1536abeab63Snia
1546abeab63Snia/*
1556abeab63Snia * This contains the functions needed by the server after loading the
1566abeab63Snia * driver module.  It must be supplied, and gets added the driver list by
1576abeab63Snia * the Module Setup funtion in the dynamic case.  In the static case a
1586abeab63Snia * reference to this is compiled in, and this requires that the name of
1596abeab63Snia * this DriverRec be an upper-case version of the driver name.
1606abeab63Snia */
1616abeab63Snia_X_EXPORT DriverRec VESA = {
1626abeab63Snia    VESA_VERSION,
1636abeab63Snia    VESA_DRIVER_NAME,
1646abeab63Snia    VESAIdentify,
1656abeab63Snia    VESAProbe,
1666abeab63Snia    VESAAvailableOptions,
1676abeab63Snia    NULL,
1686abeab63Snia    0,
1696abeab63Snia    NULL,
1706abeab63Snia
1716abeab63Snia#ifdef XSERVER_LIBPCIACCESS
172rcTF8S�{��������������{rg\PC    vesa_device_match,
1736abeab63Snia    VESAPciProbe
1746abeab63Snia#endif
1756abeab63Snia};
1766abeab63Snia
1776abeab63Snia
1786abeab63Sniatypedef enum {
1796abeab63Snia    OPTION_SHADOW_FB,
1806abeab63Snia    OPTION_DFLT_REFRESH,
1816abeab63Snia    OPTION_MODESET_CLEAR_SCREEN
1826abeab63Snia} VESAOpts;
1836abeab63Snia
1846abeab63Sniastatic const OptionInfoRec VESAOptions[] = {
1856abeab63Snia    { OPTION_SHADOW_FB,    "ShadowFB",		OPTV_BOOLEAN,	{0},	FALSE },
1866abeab63Snia    { OPTION_DFLT_REFRESH, "DefaultRefresh",	OPTV_BOOLEAN,	{0},	FALSE },
1876abeab63Snia    { OPTION_MODESET_CLEAR_SCREEN, "ModeSetClearScreen",
1886abeab63Snia						OPTV_BOOLEAN,	{0},	FALSE },
1896abeab63Snia    { -1,		   NULL,		OPTV_NONE,	{0},	FALSE }
1908COS�%.};
1916abeab63Snia
1926abeab63Snia#ifdef XFree86LOADER
1936abeab63Snia
1946abeab63Snia/* Module loader interface */
1956abeab63Sniastatic MODULESETUPPROTO(vesaSetup);
1966abeab63Snia
1976abeab63Sniastatic XF86ModuleVersionInfo vesaVersionRec =
1986abeab63Snia{
1996abeab63Snia    VESA_DRIVER_NAME,
2006S!    MODULEVENDORSTRING,
2016abeab63Snia    MODINFOSTRING1,
2026abeab63Snia    MODINFOSTRING2,
2036abeab63Snia    XORG_VERSION_CURRENT,
2046abeab63Snia    VESA_MAJOR_VERSION, VESA_MINOR_VERSION, VESA_PATCHLEVEL,
2056abeab63Snia    ABI_CLASS_VIDEODRV,			/* This is a video driver */
2066abeab63Snia    ABI_VIDEODRV_VERSION,
207    MOD_CLASS_VIDEODRV,
208    {0, 0, 0, 0}
209};
210
211/*
212 * This data is accessed by the loader.  The name must be the module name
213 * followed by "ModuleData".
214 */
215_X_EXPORT XF86ModuleData vesaModuleData = { &vesaVersionRec, vesaSetup, NULL };
216
217static pointer
218vesaSetup(pointer Module, pointer Options, int *ErrorMajor, int *ErrorMinor)
219{
220    static Bool Initialised = FALSE;
221
222    if (!Initialised)
223    {
224	Initialised = TRUE;
225	xf86AddDriver(&VESA, Module, 1);
226	return (pointer)TRUE;
227    }
228
229    if (ErrorMajor)
230	*ErrorMajor = LDR_ONCEONLY;
231    return (NULL);
232}
233
234#endif
235
236static const OptionInfoRec *
237VESAAvailableOptions(int chipid, int busid)
238{
239    return (VESAOptions);
240}
241
242static void
243VESAIdentify(int flags)
244{
245    xf86PrintChipsets(VESA_NAME, "driver for VESA chipsets", VESAChipsets);
246}
247
248static VESAPtr
249VESAGetRec(ScrnInfoPtr pScrn)
250{
251    if (!pScrn->driverPrivate)
252	pScrn->driverPrivate = xcalloc(sizeof(VESARec), 1);
253
254    return ((VESAPtr)pScrn->driverPrivate);
255}
256
257/* Only a little like VBESetModeParameters */
258static void
259VESASetModeParameters(vbeInfoPtr pVbe, DisplayModePtr vbemode,
260		      DisplayModePtr ddcmode)
261{
262    VbeModeInfoData *data;
263    int clock;
264
265    data = (VbeModeInfoData *)vbemode->Private;
266
267    data->block = xcalloc(sizeof(VbeCRTCInfoBlock), 1);
268    data->block->HorizontalTotal = ddcmode->HTotal;
269    data->block->HorizontalSyncStart = ddcmode->HSyncStart;
270    data->block->HorizontalSyncEnd = ddcmode->HSyncEnd;
271    data->block->VerticalTotal = ddcmode->VTotal;
272    data->block->VerticalSyncStart = ddcmode->VSyncStart;
273    data->block->VerticalSyncEnd = ddcmode->VSyncEnd;
274    data->block->Flags = ((ddcmode->Flags & V_NHSYNC) ? CRTC_NHSYNC : 0) |
275	                 ((ddcmode->Flags & V_NVSYNC) ? CRTC_NVSYNC : 0);
276    data->block->PixelClock = ddcmode->Clock * 1000;
277
278    /* ask the BIOS to figure out the real clock */
279    clock = VBEGetPixelClock(pVbe, data->mode, data->block->PixelClock);
280    if (clock)
281	data->block->PixelClock = clock;
282
283    data->mode |= (1 << 11);
284    data->block->RefreshRate = 100 * ((double)(data->block->PixelClock) /
285				(double)(ddcmode->HTotal * ddcmode->VTotal));
286}
287
288static ModeStatus
289VESAValidMode(int scrn, DisplayModePtr p, Bool flag, int pass)
290{
291    static int warned = 0;
292    int found = 0;
293    ScrnInfoPtr pScrn = xf86Screens[scrn];
294    VESAPtr pVesa = VESAGetRec(pScrn);
295    MonPtr mon = pScrn->monitor;
296    ModeStatus ret = MODE_BAD;
297    DisplayModePtr mode;
298    float v;
299
300    pVesa = VESAGetRec(pScrn);
301
302    if (pass != MODECHECK_FINAL) {
303	if (!warned) {
304	    xf86DrvMsg(scrn, X_WARNING, "VESAValidMode called unexpectedly\n");
305	    warned = 1;
306	}
307	return MODE_OK;
308    }
309
310    /*
311     * This is suboptimal.  We pass in just the barest description of a mode
312     * we can get away with to VBEValidateModes, so it can't really throw
313     * out anything we give it.  But we need to filter the list so that we
314     * don't populate the mode list with things the monitor can't do.
315     *
316     * So first off, if this isn't a mode we handed to the server (ie,
317     * M_T_BUILTIN), then we know we can't do it.
318     */
319    if (!(p->type & M_T_BUILTIN))
320	return MODE_NOMODE;
321
322    if (pVesa->strict_validation) {
323	/*
324	 * If it's our first pass at mode validation, we'll try for a strict
325	 * intersection between the VBE and DDC mode lists.
326	 */
327	if (pScrn->monitor->DDC) {
328	    for (mode = pScrn->monitor->Modes; mode; mode = mode->next) {
329		if (mode->type & M_T_DRIVER &&
330			mode->HDisplay == p->HDisplay &&
331			mode->VDisplay == p->VDisplay) {
332		    if (xf86CheckModeForMonitor(mode, mon) == MODE_OK) {
333			found = 1;
334			break;
335		    }
336		}
337		if (mode == pScrn->monitor->Last)
338		    break;
339	    }
340	    if (!found)
341		return MODE_NOMODE;
342
343	    /* having found a matching mode, stash the CRTC values aside */
344	    VESASetModeParameters(pVesa->pVbe, p, mode);
345	    return MODE_OK;
346	}
347
348	/* No DDC and no modes make Homer something something... */
349	return MODE_NOMODE;
350    }
351
352    /*
353     * Finally, walk through the vsync rates 1Hz at a time looking for a mode
354     * that will fit.  This is assuredly a terrible way to do this, but
355     * there's no obvious method for computing a mode of a given size that
356     * will pass xf86CheckModeForMonitor.  XXX this path is terrible, but
357     * then, by this point, you're well into despair territory.
358     */
359    for (v = mon->vrefresh[0].lo; v <= mon->vrefresh[0].hi; v++) {
360	mode = xf86GTFMode(p->HDisplay, p->VDisplay, v, 0, 0);
361	ret = xf86CheckModeForMonitor(mode, mon);
362	xfree(mode);
363	if (ret == MODE_OK)
364	    break;
365    }
366
367    return ret;
368}
369
370static void
371VESAInitScrn(ScrnInfoPtr pScrn)
372{
373    pScrn->driverVersion = VESA_VERSION;
374    pScrn->driverName    = VESA_DRIVER_NAME;
375    pScrn->name		 = VESA_NAME;
376    pScrn->Probe	 = VESAProbe;
377    pScrn->PreInit       = VESAPreInit;
378    pScrn->ScreenInit    = VESAScreenInit;
379    pScrn->SwitchMode    = VESASwitchMode;
380    pScrn->ValidMode     = VESAValidMode;
381    pScrn->AdjustFrame   = VESAAdjustFrame;
382    pScrn->EnterVT       = VESAEnterVT;
383    pScrn->LeaveVT       = VESALeaveVT;
384    pScrn->FreeScreen    = VESAFreeScreen;
385}
386
387/*
388 * This function is called once, at the start of the first server generation to
389 * do a minimal probe for supported hardware.
390 */
391
392#ifdef XSERVER_LIBPCIACCESS
393static Bool
394VESAPciProbe(DriverPtr drv, int entity_num, struct pci_device *dev,
395	     intptr_t match_data)
396{
397    ScrnInfoPtr pScrn;
398
399    pScrn = xf86ConfigPciEntity(NULL, 0, entity_num, NULL,
400				NULL, NULL, NULL, NULL, NULL);
401    if (pScrn != NULL) {
402	VESAPtr pVesa = VESAGetRec(pScrn);
403
404	VESAInitScrn(pScrn);
405	pVesa->pciInfo = dev;
406    }
407
408    return (pScrn != NULL);
409}
410#endif
411
412static Bool
413VESAProbe(DriverPtr drv, int flags)
414{
415    Bool foundScreen = FALSE;
416    int numDevSections, numUsed;
417    GDevPtr *devSections;
418    int *usedChips;
419    int i;
420
421    /*
422     * Find the config file Device sections that match this
423     * driver, and return if there are none.
424     */
425    if ((numDevSections = xf86MatchDevice(VESA_NAME,
426					  &devSections)) <= 0)
427	return (FALSE);
428
429#ifndef XSERVER_LIBPCIACCESS
430    /* PCI BUS */
431    if (xf86GetPciVideoInfo()) {
432	numUsed = xf86MatchPciInstances(VESA_NAME, PCI_VENDOR_GENERIC,
433					VESAChipsets, VESAPCIchipsets,
434					devSections, numDevSections,
435					drv, &usedChips);
436	if (numUsed > 0) {
437	    if (flags & PROBE_DETECT)
438		foundScreen = TRUE;
439	    else {
440		for (i = 0; i < numUsed; i++) {
441		    ScrnInfoPtr pScrn = NULL;
442		    /* Allocate a ScrnInfoRec  */
443		    if ((pScrn = xf86ConfigPciEntity(pScrn,0,usedChips[i],
444						     VESAPCIchipsets,NULL,
445						     NULL,NULL,NULL,NULL))) {
446			VESAInitScrn(pScrn);
447			foundScreen = TRUE;
448		    }
449		}
450	    }
451	    xfree(usedChips);
452	}
453    }
454#endif
455
456#ifdef HAVE_ISA
457    /* Isa Bus */
458    numUsed = xf86MatchIsaInstances(VESA_NAME,VESAChipsets,
459				    VESAISAchipsets, drv,
460				    VESAFindIsaDevice, devSections,
461				    numDevSections, &usedChips);
462    if(numUsed > 0) {
463	if (flags & PROBE_DETECT)
464	    foundScreen = TRUE;
465	else for (i = 0; i < numUsed; i++) {
466	    ScrnInfoPtr pScrn = NULL;
467	    if ((pScrn = xf86ConfigIsaEntity(pScrn, 0,usedChips[i],
468					     VESAISAchipsets, NULL,
469					     NULL, NULL, NULL, NULL))) {
470		VESAInitScrn(pScrn);
471		foundScreen = TRUE;
472	    }
473	}
474	xfree(usedChips);
475    }
476#endif
477
478    xfree(devSections);
479
480    return (foundScreen);
481}
482
483#ifdef HAVE_ISA
484static int
485VESAFindIsaDevice(GDevPtr dev)
486{
487#ifndef PC98_EGC
488    CARD16 GenericIOBase = VGAHW_GET_IOBASE();
489    CARD8 CurrentValue, TestValue;
490
491    /* There's no need to unlock VGA CRTC registers here */
492
493    /* VGA has one more read/write attribute register than EGA */
494    (void) inb(GenericIOBase + VGA_IN_STAT_1_OFFSET);  /* Reset flip-flop */
495    outb(VGA_ATTR_INDEX, 0x14 | 0x20);
496    CurrentValue = inb(VGA_ATTR_DATA_R);
497    outb(VGA_ATTR_DATA_W, CurrentValue ^ 0x0F);
498    outb(VGA_ATTR_INDEX, 0x14 | 0x20);
499    TestValue = inb(VGA_ATTR_DATA_R);
500    outb(VGA_ATTR_DATA_R, CurrentValue);
501
502    /* Quit now if no VGA is present */
503    if ((CurrentValue ^ 0x0F) != TestValue)
504      return -1;
505#endif
506    return (int)CHIP_VESA_GENERIC;
507}
508#endif
509
510static void
511VESAFreeRec(ScrnInfoPtr pScrn)
512{
513    VESAPtr pVesa = VESAGetRec(pScrn);
514#if 0
515    DisplayModePtr mode = pScrn->modes;
516    /* I am not sure if the modes will ever get freed.
517     * Anyway, the data unknown to other modules is being freed here.
518     */
519    if (mode) {
520	do {
521	    if (mode->Private) {
522		VbeModeInfoData *data = (VbeModeInfoData*)mode->Private;
523
524		if (data->block)
525		    xfree(data->block);
526
527		xfree(data);
528
529		mode->Private = NULL;
530	    }
531	    mode = mode->next;
532	} while (mode && mode != pScrn->modes);
533    }
534#endif
535    xfree(pVesa->monitor);
536    xfree(pVesa->vbeInfo);
537    xfree(pVesa->pal);
538    xfree(pVesa->savedPal);
539    xfree(pVesa->fonts);
540    xfree(pScrn->driverPrivate);
541    pScrn->driverPrivate = NULL;
542}
543
544static int
545VESAValidateModes(ScrnInfoPtr pScrn)
546{
547    VESAPtr pVesa = VESAGetRec(pScrn);
548    DisplayModePtr mode;
549
550    for (mode = pScrn->monitor->Modes; mode; mode = mode->next)
551	mode->status = MODE_OK;
552
553    return VBEValidateModes(pScrn, NULL, pScrn->display->modes,
554			    NULL, NULL, 0, 2048, 1, 0, 2048,
555			    pScrn->display->virtualX,
556			    pScrn->display->virtualY,
557			    pVesa->mapSize, LOOKUP_BEST_REFRESH);
558}
559
560/*
561 * This function is called once for each screen at the start of the first
562 * server generation to initialise the screen for all server generations.
563 */
564static Bool
565VESAPreInit(ScrnInfoPtr pScrn, int flags)
566{
567    VESAPtr pVesa;
568    VbeInfoBlock *vbe;
569    DisplayModePtr pMode;
570    VbeModeInfoBlock *mode;
571    Gamma gzeros = {0.0, 0.0, 0.0};
572    rgb rzeros = {0, 0, 0};
573    pointer pDDCModule;
574    int i;
575    int flags24 = 0;
576    int defaultDepth = 0;
577    int defaultBpp = 0;
578    int depths = 0;
579
580    if (flags & PROBE_DETECT)
581	return (FALSE);
582
583    pVesa = VESAGetRec(pScrn);
584    pVesa->pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
585
586    /* Load vbe module */
587    if (!xf86LoadSubModule(pScrn, "vbe"))
588        return (FALSE);
589
590    if ((pVesa->pVbe = VBEExtendedInit(NULL, pVesa->pEnt->index,
591				       SET_BIOS_SCRATCH
592				       | RESTORE_BIOS_SCRATCH)) == NULL)
593        return (FALSE);
594
595#ifndef XSERVER_LIBPCIACCESS
596    if (pVesa->pEnt->location.type == BUS_PCI) {
597	pVesa->pciInfo = xf86GetPciInfoForEntity(pVesa->pEnt->index);
598	pVesa->pciTag = pciTag(pVesa->pciInfo->bus, pVesa->pciInfo->device,
599			       pVesa->pciInfo->func);
600    }
601#endif
602
603    pScrn->chipset = "vesa";
604    pScrn->monitor = pScrn->confScreen->monitor;
605    pScrn->progClock = TRUE;
606    pScrn->rgbBits = 8;
607
608    if ((vbe = VBEGetVBEInfo(pVesa->pVbe)) == NULL)
609	return (FALSE);
610    pVesa->major = (unsigned)(vbe->VESAVersion >> 8);
611    pVesa->minor = vbe->VESAVersion & 0xff;
612    pVesa->vbeInfo = vbe;
613    pScrn->videoRam = vbe->TotalMemory * 64;
614
615    /*
616     * Find what depths are available.
617     */
618    depths = VBEFindSupportedDepths(pVesa->pVbe, pVesa->vbeInfo, &flags24,
619				    V_MODETYPE_VBE);
620
621    /* Preferred order for default depth selection. */
622    if (depths & V_DEPTH_24)
623	defaultDepth = 24;
624    else if (depths & V_DEPTH_16)
625	defaultDepth = 16;
626    else if (depths & V_DEPTH_15)
627	defaultDepth = 15;
628    else if (depths & V_DEPTH_8)
629	defaultDepth = 8;
630    else if (depths & V_DEPTH_4)
631	defaultDepth = 4;
632    else if (depths & V_DEPTH_1)
633	defaultDepth = 1;
634
635    if (defaultDepth == 24 && !(flags24 & Support32bppFb))
636	defaultBpp = 24;
637
638    /* Prefer 32bpp because 1999 called and wants its packed pixels back */
639    if (flags24 & Support32bppFb)
640	flags24 |= SupportConvert24to32 | PreferConvert24to32;
641    if (flags24 & Support24bppFb)
642	flags24 |= SupportConvert32to24;
643
644    if (!xf86SetDepthBpp(pScrn, defaultDepth, 0, defaultBpp, flags24)) {
645        vbeFree(pVesa->pVbe);
646	return (FALSE);
647    }
648    xf86PrintDepthBpp(pScrn);
649
650    /* color weight */
651    if (pScrn->depth > 8 && !xf86SetWeight(pScrn, rzeros, rzeros)) {
652        vbeFree(pVesa->pVbe);
653	return (FALSE);
654    }
655    /* visual init */
656    if (!xf86SetDefaultVisual(pScrn, -1)) {
657        vbeFree(pVesa->pVbe);
658	return (FALSE);
659    }
660
661    xf86SetGamma(pScrn, gzeros);
662
663    if (pVesa->major >= 2) {
664	/* Load ddc module */
665	if ((pDDCModule = xf86LoadSubModule(pScrn, "ddc")) == NULL) {
666	    vbeFree(pVesa->pVbe);
667	    return (FALSE);
668	}
669
670	if ((pVesa->monitor = vbeDoEDID(pVesa->pVbe, pDDCModule)) != NULL) {
671	    xf86PrintEDID(pVesa->monitor);
672	}
673
674	xf86UnloadSubModule(pDDCModule);
675    }
676
677    if ((pScrn->monitor->DDC = pVesa->monitor) != NULL)
678	xf86SetDDCproperties(pScrn, pVesa->monitor);
679#ifdef HAVE_PANELID
680    else {
681	void *panelid = VBEReadPanelID(pVesa->pVbe);
682	VBEInterpretPanelID(pScrn->scrnIndex, panelid);
683	xfree(panelid);
684    }
685#endif
686
687    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, DEBUG_VERB,
688			"Searching for matching VESA mode(s):\n");
689
690    /*
691     * Check the available BIOS modes, and extract those that match the
692     * requirements into the modePool.  Note: modePool is a NULL-terminated
693     * list.
694     */
695    pScrn->modePool = VBEGetModePool (pScrn, pVesa->pVbe, pVesa->vbeInfo,
696				      V_MODETYPE_VBE);
697
698    xf86ErrorFVerb(DEBUG_VERB, "\n");
699    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, DEBUG_VERB,
700		   "Total Memory: %d 64KB banks (%dkB)\n", vbe->TotalMemory,
701		   (vbe->TotalMemory * 65536) / 1024);
702
703    pVesa->mapSize = vbe->TotalMemory * 65536;
704    if (pScrn->modePool == NULL) {
705	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No matching modes\n");
706        vbeFree(pVesa->pVbe);
707	return (FALSE);
708    }
709
710    VBESetModeNames(pScrn->modePool);
711
712    pVesa->strict_validation = TRUE;
713    i = VESAValidateModes(pScrn);
714
715    if (i <= 0) {
716	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
717		"No valid modes left. Trying less strict filter...\n");
718	pVesa->strict_validation = FALSE;
719	i = VESAValidateModes(pScrn);
720    }
721
722    if (i <= 0) do {
723	Bool changed = FALSE;
724	/* maybe there's more modes at the bottom... */
725	if (pScrn->monitor->vrefresh[0].lo > 50) {
726	    changed = TRUE;
727	    pScrn->monitor->vrefresh[0].lo = 50;
728	}
729	if (pScrn->monitor->hsync[0].lo > 31.5) {
730	    changed = TRUE;
731	    pScrn->monitor->hsync[0].lo = 31.5;
732	}
733
734	if (!changed)
735	    break;
736
737	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
738		   "No valid modes left. Trying aggressive sync range...\n");
739	i = VESAValidateModes(pScrn);
740    } while (0);
741
742    if (i <= 0) {
743	/* alright, i'm out of ideas */
744	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes\n");
745        vbeFree(pVesa->pVbe);
746	return (FALSE);
747    }
748
749    xf86PruneDriverModes(pScrn);
750
751    pMode = pScrn->modes;
752    do {
753	mode = ((VbeModeInfoData*)pMode->Private)->data;
754	if (mode->BytesPerScanline > pVesa->maxBytesPerScanline) {
755	    pVesa->maxBytesPerScanline = mode->BytesPerScanline;
756	}
757	pMode = pMode->next;
758    } while (pMode != pScrn->modes);
759
760    pScrn->currentMode = pScrn->modes;
761    pScrn->displayWidth = pScrn->virtualX;
762
763    VBEPrintModes(pScrn);
764
765    /* Set display resolution */
766    xf86SetDpi(pScrn, 0, 0);
767
768    if (pScrn->modes == NULL) {
769	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No modes\n");
770        vbeFree(pVesa->pVbe);
771	return (FALSE);
772    }
773
774    /* options */
775    xf86CollectOptions(pScrn, NULL);
776    if (!(pVesa->Options = xalloc(sizeof(VESAOptions)))) {
777        vbeFree(pVesa->pVbe);
778	return FALSE;
779    }
780    memcpy(pVesa->Options, VESAOptions, sizeof(VESAOptions));
781    xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pVesa->Options);
782
783    /* Use shadow by default */
784    if (xf86ReturnOptValBool(pVesa->Options, OPTION_SHADOW_FB, TRUE))
785	pVesa->shadowFB = TRUE;
786
787    if (xf86ReturnOptValBool(pVesa->Options, OPTION_DFLT_REFRESH, FALSE))
788	pVesa->defaultRefresh = TRUE;
789
790    pVesa->ModeSetClearScreen = FALSE;
791    if (xf86ReturnOptValBool(pVesa->Options, OPTION_MODESET_CLEAR_SCREEN,
792			     FALSE))
793	pVesa->ModeSetClearScreen = TRUE;
794
795    if (!pVesa->defaultRefresh && !pVesa->strict_validation)
796	VBESetModeParameters(pScrn, pVesa->pVbe);
797
798    mode = ((VbeModeInfoData*)pScrn->modes->Private)->data;
799    switch (mode->MemoryModel) {
800	case 0x4:	/* Packed pixel */
801	case 0x6:	/* Direct Color */
802	    pScrn->bitmapBitOrder = BITMAP_BIT_ORDER;
803
804	    switch (pScrn->bitsPerPixel) {
805		case 8:
806		case 16:
807		case 24:
808		case 32:
809		    break;
810		default:
811		    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
812			       "Unsupported bpp: %d", pScrn->bitsPerPixel);
813		    vbeFree(pVesa->pVbe);
814		    return FALSE;
815	    }
816	    break;
817	default:
818	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
819		       "Unsupported Memory Model: %d", mode->MemoryModel);
820	    return FALSE;
821    }
822
823    if (pVesa->shadowFB) {
824	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Using \"Shadow Framebuffer\"\n");
825	if (!xf86LoadSubModule(pScrn, "shadow")) {
826	    vbeFree(pVesa->pVbe);
827	    return (FALSE);
828	}
829    }
830
831    if (xf86LoadSubModule(pScrn, "fb") == NULL) {
832	VESAFreeRec(pScrn);
833        vbeFree(pVesa->pVbe);
834	return (FALSE);
835    }
836
837    vbeFree(pVesa->pVbe);
838
839    return (TRUE);
840}
841
842static Bool
843vesaCreateScreenResources(ScreenPtr pScreen)
844{
845    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
846    VESAPtr pVesa = VESAGetRec(pScrn);
847    Bool ret;
848
849    pScreen->CreateScreenResources = pVesa->CreateScreenResources;
850    ret = pScreen->CreateScreenResources(pScreen);
851    pScreen->CreateScreenResources = vesaCreateScreenResources;
852
853    shadowAdd(pScreen, pScreen->GetScreenPixmap(pScreen), pVesa->update,
854	      pVesa->window, 0, 0);
855
856    return ret;
857}
858
859static void
860vesaEnableDisableFBAccess(int scrnIndex, Bool enable)
861{
862    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
863    VESAPtr pVesa = VESAGetRec(pScrn);
864
865    pVesa->accessEnabled = enable;
866    pVesa->EnableDisableFBAccess(scrnIndex, enable);
867}
868
869static Bool
870VESAScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
871{
872    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
873    VESAPtr pVesa = VESAGetRec(pScrn);
874    VisualPtr visual;
875    VbeModeInfoBlock *mode;
876    int flags;
877    int init_picture = 0;
878
879    if ((pVesa->pVbe = VBEExtendedInit(NULL, pVesa->pEnt->index,
880				       SET_BIOS_SCRATCH
881				       | RESTORE_BIOS_SCRATCH)) == NULL)
882        return (FALSE);
883
884    if (pVesa->mapPhys == 0) {
885	mode = ((VbeModeInfoData*)(pScrn->currentMode->Private))->data;
886	pScrn->videoRam = pVesa->mapSize;
887	pVesa->mapPhys = mode->PhysBasePtr;
888	pVesa->mapOff = 0;
889    }
890
891    if (pVesa->mapPhys == 0) {
892	pVesa->mapPhys = 0xa0000;
893	pVesa->mapSize = 0x10000;
894    }
895
896    if (!VESAMapVidMem(pScrn)) {
897	if (pVesa->mapPhys != 0xa0000) {
898	    pVesa->mapPhys = 0xa0000;
899	    pVesa->mapSize = 0x10000;
900	    if (!VESAMapVidMem(pScrn))
901		return (FALSE);
902	}
903	else
904	    return (FALSE);
905    }
906
907    /* Set bpp to 8 for depth 4 when using shadowfb. */
908    if (pVesa->shadowFB && pScrn->bitsPerPixel == 4)
909	pScrn->bitsPerPixel = 8;
910
911    if (pVesa->shadowFB) {
912	pVesa->shadow = xcalloc(1, pScrn->displayWidth * pScrn->virtualY *
913				   ((pScrn->bitsPerPixel + 7) / 8));
914	if (!pVesa->shadow) {
915	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
916		       "Failed to allocate shadow buffer\n");
917	    return FALSE;
918	}
919    }
920
921    /* save current video state */
922    VESASaveRestore(pScrn, MODE_SAVE);
923    pVesa->savedPal = VBESetGetPaletteData(pVesa->pVbe, FALSE, 0, 256,
924					    NULL, FALSE, FALSE);
925
926    /* set first video mode */
927    if (!VESASetMode(pScrn, pScrn->currentMode))
928	return (FALSE);
929
930    /* set the viewport */
931    VESAAdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
932
933    /* Blank the screen for aesthetic reasons. */
934    VESASaveScreen(pScreen, SCREEN_SAVER_ON);
935
936    /* mi layer */
937    miClearVisualTypes();
938    if (!xf86SetDefaultVisual(pScrn, -1))
939	return (FALSE);
940    if (pScrn->bitsPerPixel > 8) {
941	if (!miSetVisualTypes(pScrn->depth, TrueColorMask,
942			      pScrn->rgbBits, TrueColor))
943	    return (FALSE);
944    }
945    else {
946	if (!miSetVisualTypes(pScrn->depth,
947			      miGetDefaultVisualMask(pScrn->depth),
948			      pScrn->rgbBits, pScrn->defaultVisual))
949	    return (FALSE);
950    }
951    if (!miSetPixmapDepths())
952	return (FALSE);
953
954    mode = ((VbeModeInfoData*)pScrn->modes->Private)->data;
955    switch (mode->MemoryModel) {
956	case 0x4:	/* Packed pixel */
957	case 0x6:	/* Direct Color */
958	    switch (pScrn->bitsPerPixel) {
959		case 8:
960		case 16:
961		case 24:
962		case 32:
963		    if (!fbScreenInit(pScreen,
964				pVesa->shadowFB ? pVesa->shadow : pVesa->base,
965				       pScrn->virtualX, pScrn->virtualY,
966				       pScrn->xDpi, pScrn->yDpi,
967				       pScrn->displayWidth, pScrn->bitsPerPixel))
968			return (FALSE);
969		    init_picture = 1;
970		    break;
971		default:
972		    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
973			       "Unsupported bpp: %d", pScrn->bitsPerPixel);
974		    return (FALSE);
975	    }
976	    break;
977	default:
978	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
979		       "Unsupported Memory Model: %d", mode->MemoryModel);
980	    return (FALSE);
981    }
982
983
984    if (pScrn->bitsPerPixel > 8) {
985	/* Fixup RGB ordering */
986	visual = pScreen->visuals + pScreen->numVisuals;
987	while (--visual >= pScreen->visuals) {
988	    if ((visual->class | DynamicClass) == DirectColor) {
989		visual->offsetRed   = pScrn->offset.red;
990		visual->offsetGreen = pScrn->offset.green;
991		visual->offsetBlue  = pScrn->offset.blue;
992		visual->redMask     = pScrn->mask.red;
993		visual->greenMask   = pScrn->mask.green;
994		visual->blueMask    = pScrn->mask.blue;
995	    }
996	}
997    }
998
999    /* must be after RGB ordering fixed */
1000    if (init_picture)
1001	fbPictureInit(pScreen, 0, 0);
1002
1003    if (pVesa->shadowFB) {
1004	if (pVesa->mapPhys == 0xa0000) {	/* Windowed */
1005	    pVesa->update = shadowUpdatePackedWeak();
1006	    pVesa->window = VESAWindowWindowed;
1007	}
1008	else {	/* Linear */
1009	    pVesa->update = shadowUpdatePackedWeak();
1010	    pVesa->window = VESAWindowLinear;
1011	}
1012
1013	if (!shadowSetup(pScreen))
1014	    return FALSE;
1015	pVesa->CreateScreenResources = pScreen->CreateScreenResources;
1016	pScreen->CreateScreenResources = vesaCreateScreenResources;
1017    }
1018    else if (pVesa->mapPhys == 0xa0000) {
1019	unsigned int bankShift = 0;
1020	while ((unsigned)(64 >> bankShift) != mode->WinGranularity)
1021	    bankShift++;
1022	pVesa->curBank = -1;
1023	pVesa->bank.SetSourceBank =
1024	pVesa->bank.SetDestinationBank =
1025	pVesa->bank.SetSourceAndDestinationBanks = VESABankSwitch;
1026	pVesa->bank.pBankA = pVesa->bank.pBankB = pVesa->base;
1027	pVesa->bank.BankSize = (mode->WinSize * 1024) >> bankShift;
1028	pVesa->bank.nBankDepth = pScrn->depth;
1029	if (!miInitializeBanking(pScreen, pScrn->virtualX, pScrn->virtualY,
1030				 pScrn->virtualX, &pVesa->bank)) {
1031	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1032		       "Bank switch initialization failed!\n");
1033	    return (FALSE);
1034	}
1035    }
1036
1037    VESADGAInit(pScrn, pScreen);
1038
1039    xf86SetBlackWhitePixels(pScreen);
1040    miInitializeBackingStore(pScreen);
1041    xf86SetBackingStore(pScreen);
1042
1043    /* software cursor */
1044    miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
1045
1046    /* colormap */
1047    if (!miCreateDefColormap(pScreen))
1048	return (FALSE);
1049
1050    flags = CMAP_RELOAD_ON_MODE_SWITCH;
1051
1052    if(!xf86HandleColormaps(pScreen, 256,
1053	pVesa->vbeInfo->Capabilities[0] & 0x01 ? 8 : 6,
1054	VESALoadPalette, NULL, flags))
1055	return (FALSE);
1056
1057    pVesa->accessEnabled = TRUE;
1058    pVesa->EnableDisableFBAccess = pScrn->EnableDisableFBAccess;
1059    pScrn->EnableDisableFBAccess = vesaEnableDisableFBAccess;
1060
1061    pVesa->CloseScreen = pScreen->CloseScreen;
1062    pScreen->CloseScreen = VESACloseScreen;
1063    pScreen->SaveScreen = VESASaveScreen;
1064
1065    xf86DPMSInit(pScreen, VESADisplayPowerManagementSet, 0);
1066
1067    /* Report any unused options (only for the first generation) */
1068    if (serverGeneration == 1)
1069        xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
1070
1071    return (TRUE);
1072}
1073
1074static Bool
1075VESAEnterVT(int scrnIndex, int flags)
1076{
1077    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1078
1079    if (!VESASetMode(pScrn, pScrn->currentMode))
1080	return FALSE;
1081    VESAAdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
1082    return TRUE;
1083}
1084
1085static void
1086VESALeaveVT(int scrnIndex, int flags)
1087{
1088    VESASaveRestore(xf86Screens[scrnIndex], MODE_RESTORE);
1089}
1090
1091static Bool
1092VESACloseScreen(int scrnIndex, ScreenPtr pScreen)
1093{
1094    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1095    VESAPtr pVesa = VESAGetRec(pScrn);
1096
1097    if (pScrn->vtSema) {
1098	VESASaveRestore(xf86Screens[scrnIndex], MODE_RESTORE);
1099	if (pVesa->savedPal)
1100	    VBESetGetPaletteData(pVesa->pVbe, TRUE, 0, 256,
1101				 pVesa->savedPal, FALSE, TRUE);
1102	VESAUnmapVidMem(pScrn);
1103    }
1104    if (pVesa->shadowFB && pVesa->shadow)
1105	xfree(pVesa->shadow);
1106    if (pVesa->pDGAMode) {
1107	xfree(pVesa->pDGAMode);
1108	pVesa->pDGAMode = NULL;
1109	pVesa->nDGAMode = 0;
1110    }
1111    pScrn->vtSema = FALSE;
1112
1113    pScrn->EnableDisableFBAccess = pVesa->EnableDisableFBAccess;
1114    pScreen->CreateScreenResources = pVesa->CreateScreenResources;
1115    pScreen->CloseScreen = pVesa->CloseScreen;
1116    return pScreen->CloseScreen(scrnIndex, pScreen);
1117}
1118
1119static Bool
1120VESASwitchMode(int scrnIndex, DisplayModePtr pMode, int flags)
1121{
1122    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1123    VESAPtr pVesa = VESAGetRec(pScrn);
1124    Bool ret, disableAccess = pVesa->ModeSetClearScreen && pVesa->accessEnabled;
1125
1126    if (disableAccess)
1127	pScrn->EnableDisableFBAccess(scrnIndex,FALSE);
1128    ret = VESASetMode(xf86Screens[scrnIndex], pMode);
1129    if (disableAccess)
1130	pScrn->EnableDisableFBAccess(scrnIndex,TRUE);
1131    return ret;
1132}
1133
1134/* Set a graphics mode */
1135static Bool
1136VESASetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode)
1137{
1138    VESAPtr pVesa;
1139    VbeModeInfoData *data;
1140    int mode;
1141
1142    pVesa = VESAGetRec(pScrn);
1143
1144    data = (VbeModeInfoData*)pMode->Private;
1145
1146    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1147	       "Setting up VESA Mode 0x%X (%dx%d)\n",
1148	       data->mode & 0x7FF, pMode->HDisplay, pMode->VDisplay);
1149
1150    /* careful, setting the bit means don't clear the screen */
1151    mode = data->mode | (pVesa->ModeSetClearScreen ? 0 : (1U << 15));
1152
1153    /* enable linear addressing */
1154    if (pVesa->mapPhys != 0xa0000)
1155	mode |= 1 << 14;
1156
1157    if (VBESetVBEMode(pVesa->pVbe, mode, data->block) == FALSE) {
1158	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VBESetVBEMode failed");
1159	if ((data->block || (data->mode & (1 << 11))) &&
1160	    VBESetVBEMode(pVesa->pVbe, (mode & ~(1 << 11)), NULL) == TRUE) {
1161	    /* Some cards do not like setting the clock.
1162	     * Free it as it will not be any longer useful
1163	     */
1164	    xf86ErrorF("...Tried again without customized values.\n");
1165	    xfree(data->block);
1166	    data->block = NULL;
1167	    data->mode &= ~(1 << 11);
1168	}
1169	else {
1170	    ErrorF("\n");
1171	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Set VBE Mode failed!\n");
1172	    return (FALSE);
1173	}
1174    }
1175
1176    pVesa->bankSwitchWindowB =
1177	!((data->data->WinBSegment == 0) && (data->data->WinBAttributes == 0));
1178
1179    if (data->data->XResolution != pScrn->displayWidth)
1180	VBESetLogicalScanline(pVesa->pVbe, pScrn->displayWidth);
1181
1182    if (pScrn->bitsPerPixel == 8 && pVesa->vbeInfo->Capabilities[0] & 0x01 &&
1183        !(data->data->MemoryModel == 0x6 || data->data->MemoryModel == 0x7))
1184	VBESetGetDACPaletteFormat(pVesa->pVbe, 8);
1185
1186    pScrn->vtSema = TRUE;
1187
1188    return (TRUE);
1189}
1190
1191static void
1192VESAAdjustFrame(int scrnIndex, int x, int y, int flags)
1193{
1194    VESAPtr pVesa = VESAGetRec(xf86Screens[scrnIndex]);
1195
1196    VBESetDisplayStart(pVesa->pVbe, x, y, TRUE);
1197}
1198
1199static void
1200VESAFreeScreen(int scrnIndex, int flags)
1201{
1202    VESAFreeRec(xf86Screens[scrnIndex]);
1203}
1204
1205static Bool
1206VESAMapVidMem(ScrnInfoPtr pScrn)
1207{
1208    VESAPtr pVesa = VESAGetRec(pScrn);
1209
1210    if (pVesa->base != NULL)
1211	return (TRUE);
1212
1213    pScrn->memPhysBase = pVesa->mapPhys;
1214    pScrn->fbOffset = pVesa->mapOff;
1215
1216#ifdef XSERVER_LIBPCIACCESS
1217    if ((pVesa->mapPhys != 0xa0000) && (pVesa->pciInfo != NULL)) {
1218	(void) pci_device_map_range(pVesa->pciInfo, pScrn->memPhysBase,
1219				    pVesa->mapSize,
1220				    (PCI_DEV_MAP_FLAG_WRITABLE
1221				     | PCI_DEV_MAP_FLAG_WRITE_COMBINE),
1222				    & pVesa->base);
1223    }
1224    else
1225	pVesa->base = xf86MapDomainMemory(pScrn->scrnIndex, 0, pVesa->pciInfo,
1226					  pScrn->memPhysBase, pVesa->mapSize);
1227
1228    if (pVesa->base) {
1229	if (pVesa->mapPhys != 0xa0000)
1230	    pVesa->VGAbase = xf86MapDomainMemory(pScrn->scrnIndex, 0,
1231						 pVesa->pciInfo,
1232						 0xa0000, 0x10000);
1233	else
1234	    pVesa->VGAbase = pVesa->base;
1235
1236    }
1237#else
1238    if (pVesa->mapPhys != 0xa0000 && pVesa->pEnt->location.type == BUS_PCI)
1239	pVesa->base = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
1240				    pVesa->pciTag, pScrn->memPhysBase,
1241				    pVesa->mapSize);
1242    else
1243	pVesa->base = xf86MapDomainMemory(pScrn->scrnIndex, 0, pVesa->pciTag,
1244					  pScrn->memPhysBase, pVesa->mapSize);
1245
1246    if (pVesa->base) {
1247	if (pVesa->mapPhys != 0xa0000)
1248	    pVesa->VGAbase = xf86MapDomainMemory(pScrn->scrnIndex, 0,
1249						 pVesa->pciTag,
1250						 0xa0000, 0x10000);
1251	else
1252	    pVesa->VGAbase = pVesa->base;
1253    }
1254#endif
1255
1256    pVesa->ioBase = pScrn->domainIOBase;
1257
1258    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, DEBUG_VERB,
1259		   "virtual address = %p,\n"
1260		   "\tphysical address = 0x%lx, size = %ld\n",
1261		   pVesa->base, pScrn->memPhysBase, pVesa->mapSize);
1262
1263    return (pVesa->base != NULL);
1264}
1265
1266static void
1267VESAUnmapVidMem(ScrnInfoPtr pScrn)
1268{
1269    VESAPtr pVesa = VESAGetRec(pScrn);
1270
1271    if (pVesa->base == NULL)
1272	return;
1273
1274#ifdef XSERVER_LIBPCIACCESS
1275    if (pVesa->mapPhys != 0xa0000) {
1276	(void) pci_device_unmap_range(pVesa->pciInfo, pVesa->base,
1277				      pVesa->mapSize);
1278	xf86UnMapVidMem(pScrn->scrnIndex, pVesa->VGAbase, 0x10000);
1279    }
1280    else {
1281	xf86UnMapVidMem(pScrn->scrnIndex, pVesa->base, pVesa->mapSize);
1282    }
1283#else
1284    xf86UnMapVidMem(pScrn->scrnIndex, pVesa->base, pVesa->mapSize);
1285    if (pVesa->mapPhys != 0xa0000)
1286	xf86UnMapVidMem(pScrn->scrnIndex, pVesa->VGAbase, 0x10000);
1287#endif
1288    pVesa->base = NULL;
1289}
1290
1291static void *
1292VESAWindowLinear(ScreenPtr pScreen, CARD32 row, CARD32 offset, int mode,
1293		 CARD32 *size, void *closure)
1294{
1295    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
1296    VESAPtr pVesa = VESAGetRec(pScrn);
1297
1298    *size = pVesa->maxBytesPerScanline;
1299    return ((CARD8 *)pVesa->base + row * pVesa->maxBytesPerScanline + offset);
1300}
1301
1302static void *
1303VESAWindowWindowed(ScreenPtr pScreen, CARD32 row, CARD32 offset, int mode,
1304		   CARD32 *size, void *closure)
1305{
1306    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
1307    VESAPtr pVesa = VESAGetRec(pScrn);
1308    VbeModeInfoBlock *data = ((VbeModeInfoData*)(pScrn->currentMode->Private))->data;
1309    int window;
1310
1311    offset += pVesa->maxBytesPerScanline * row;
1312    window = offset / (data->WinGranularity * 1024);
1313    pVesa->windowAoffset = window * data->WinGranularity * 1024;
1314    VESABankSwitch(pScreen, window);
1315    *size = data->WinSize * 1024 - (offset - pVesa->windowAoffset);
1316
1317    return (void *)((unsigned long)pVesa->base +
1318		    (offset - pVesa->windowAoffset));
1319}
1320
1321static void
1322VESALoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices,
1323		LOCO *colors, VisualPtr pVisual)
1324{
1325    VESAPtr pVesa = VESAGetRec(pScrn);
1326    int i, idx;
1327
1328#if 0
1329
1330    /* This code works, but is very slow for programs that use it intensively */
1331    int base;
1332
1333    if (pVesa->pal == NULL)
1334	pVesa->pal = xcalloc(1, sizeof(CARD32) * 256);
1335
1336    for (i = 0, base = idx = indices[i]; i < numColors; i++, idx++) {
1337	int j = indices[i];
1338
1339	if (j < 0 || j >= 256)
1340	    continue;
1341	pVesa->pal[j] = colors[j].blue |
1342			(colors[j].green << 8) |
1343			(colors[j].red << 16);
1344	if (j != idx) {
1345	    VBESetGetPaletteData(pVesa->pVbe, TRUE, base, idx - base,
1346				  pVesa->pal + base, FALSE, TRUE);
1347	    idx = base = j;
1348	}
1349    }
1350
1351    if (idx - 1 == indices[i - 1])
1352	VBESetGetPaletteData(pVesa->pVbe, TRUE, base, idx - base,
1353			      pVesa->pal + base, FALSE, TRUE);
1354
1355#else
1356
1357#define VESADACDelay()							    \
1358    do {								    \
1359	(void)inb(pVesa->ioBase + VGA_IOBASE_COLOR + VGA_IN_STAT_1_OFFSET); \
1360	(void)inb(pVesa->ioBase + VGA_IOBASE_COLOR + VGA_IN_STAT_1_OFFSET); \
1361    } while (0)
1362
1363    for (i = 0; i < numColors; i++) {
1364	idx = indices[i];
1365	outb(pVesa->ioBase + VGA_DAC_WRITE_ADDR, idx);
1366	VESADACDelay();
1367	outb(pVesa->ioBase + VGA_DAC_DATA, colors[idx].red);
1368	VESADACDelay();
1369	outb(pVesa->ioBase + VGA_DAC_DATA, colors[idx].green);
1370	VESADACDelay();
1371	outb(pVesa->ioBase + VGA_DAC_DATA, colors[idx].blue);
1372	VESADACDelay();
1373    }
1374
1375#endif
1376}
1377
1378/*
1379 * Just adapted from the std* functions in vgaHW.c
1380 */
1381static void
1382WriteAttr(VESAPtr pVesa, int index, int value)
1383{
1384    (void) inb(pVesa->ioBase + VGA_IOBASE_COLOR + VGA_IN_STAT_1_OFFSET);
1385
1386    index |= 0x20;
1387    outb(pVesa->ioBase + VGA_ATTR_INDEX, index);
1388    outb(pVesa->ioBase + VGA_ATTR_DATA_W, value);
1389}
1390
1391static int
1392ReadAttr(VESAPtr pVesa, int index)
1393{
1394    (void) inb(pVesa->ioBase + VGA_IOBASE_COLOR + VGA_IN_STAT_1_OFFSET);
1395
1396    index |= 0x20;
1397    outb(pVesa->ioBase + VGA_ATTR_INDEX, index);
1398    return (inb(pVesa->ioBase + VGA_ATTR_DATA_R));
1399}
1400
1401#define WriteMiscOut(value)	outb(pVesa->ioBase + VGA_MISC_OUT_W, value)
1402#define ReadMiscOut()		inb(pVesa->ioBase + VGA_MISC_OUT_R)
1403#define WriteSeq(index, value)	outb(pVesa->ioBase + VGA_SEQ_INDEX, index);\
1404				outb(pVesa->ioBase + VGA_SEQ_DATA, value)
1405
1406static int
1407ReadSeq(VESAPtr pVesa, int index)
1408{
1409    outb(pVesa->ioBase + VGA_SEQ_INDEX, index);
1410
1411    return (inb(pVesa->ioBase + VGA_SEQ_DATA));
1412}
1413
1414#define WriteGr(index, value)				\
1415    outb(pVesa->ioBase + VGA_GRAPH_INDEX, index);	\
1416    outb(pVesa->ioBase + VGA_GRAPH_DATA, value)
1417
1418static int
1419ReadGr(VESAPtr pVesa, int index)
1420{
1421    outb(pVesa->ioBase + VGA_GRAPH_INDEX, index);
1422
1423    return (inb(pVesa->ioBase + VGA_GRAPH_DATA));
1424}
1425
1426#define WriteCrtc(index, value)						     \
1427    outb(pVesa->ioBase + (VGA_IOBASE_COLOR + VGA_CRTC_INDEX_OFFSET), index); \
1428    outb(pVesa->ioBase + (VGA_IOBASE_COLOR + VGA_CRTC_DATA_OFFSET), value)
1429
1430static void
1431SeqReset(VESAPtr pVesa, Bool start)
1432{
1433    if (start) {
1434	WriteSeq(0x00, 0x01);		/* Synchronous Reset */
1435    }
1436    else {
1437	WriteSeq(0x00, 0x03);		/* End Reset */
1438    }
1439}
1440
1441static void
1442SaveFonts(ScrnInfoPtr pScrn)
1443{
1444    VESAPtr pVesa = VESAGetRec(pScrn);
1445    unsigned char miscOut, attr10, gr4, gr5, gr6, seq2, seq4, scrn;
1446
1447    if (pVesa->fonts != NULL)
1448	return;
1449
1450    /* If in graphics mode, don't save anything */
1451    attr10 = ReadAttr(pVesa, 0x10);
1452    if (attr10 & 0x01)
1453	return;
1454
1455    pVesa->fonts = xalloc(16384);
1456
1457    /* save the registers that are needed here */
1458    miscOut = ReadMiscOut();
1459    gr4 = ReadGr(pVesa, 0x04);
1460    gr5 = ReadGr(pVesa, 0x05);
1461    gr6 = ReadGr(pVesa, 0x06);
1462    seq2 = ReadSeq(pVesa, 0x02);
1463    seq4 = ReadSeq(pVesa, 0x04);
1464
1465    /* Force into colour mode */
1466    WriteMiscOut(miscOut | 0x01);
1467
1468    scrn = ReadSeq(pVesa, 0x01) | 0x20;
1469    SeqReset(pVesa, TRUE);
1470    WriteSeq(0x01, scrn);
1471    SeqReset(pVesa, FALSE);
1472
1473    WriteAttr(pVesa, 0x10, 0x01);	/* graphics mode */
1474
1475    /*font1 */
1476    WriteSeq(0x02, 0x04);	/* write to plane 2 */
1477    WriteSeq(0x04, 0x06);	/* enable plane graphics */
1478    WriteGr(0x04, 0x02);	/* read plane 2 */
1479    WriteGr(0x05, 0x00);	/* write mode 0, read mode 0 */
1480    WriteGr(0x06, 0x05);	/* set graphics */
1481    slowbcopy_frombus(pVesa->VGAbase, pVesa->fonts, 8192);
1482
1483    /* font2 */
1484    WriteSeq(0x02, 0x08);	/* write to plane 3 */
1485    WriteSeq(0x04, 0x06);	/* enable plane graphics */
1486    WriteGr(0x04, 0x03);	/* read plane 3 */
1487    WriteGr(0x05, 0x00);	/* write mode 0, read mode 0 */
1488    WriteGr(0x06, 0x05);	/* set graphics */
1489    slowbcopy_frombus(pVesa->VGAbase, pVesa->fonts + 8192, 8192);
1490
1491    scrn = ReadSeq(pVesa, 0x01) & ~0x20;
1492    SeqReset(pVesa, TRUE);
1493    WriteSeq(0x01, scrn);
1494    SeqReset(pVesa, FALSE);
1495
1496    /* Restore clobbered registers */
1497    WriteAttr(pVesa, 0x10, attr10);
1498    WriteSeq(0x02, seq2);
1499    WriteSeq(0x04, seq4);
1500    WriteGr(0x04, gr4);
1501    WriteGr(0x05, gr5);
1502    WriteGr(0x06, gr6);
1503    WriteMiscOut(miscOut);
1504}
1505
1506static void
1507RestoreFonts(ScrnInfoPtr pScrn)
1508{
1509    VESAPtr pVesa = VESAGetRec(pScrn);
1510    unsigned char miscOut, attr10, gr1, gr3, gr4, gr5, gr6, gr8, seq2, seq4, scrn;
1511
1512    if (pVesa->fonts == NULL)
1513	return;
1514
1515    if (pVesa->mapPhys == 0xa0000 && pVesa->curBank != 0)
1516	VESABankSwitch(pScrn->pScreen, 0);
1517
1518    /* save the registers that are needed here */
1519    miscOut = ReadMiscOut();
1520    attr10 = ReadAttr(pVesa, 0x10);
1521    gr1 = ReadGr(pVesa, 0x01);
1522    gr3 = ReadGr(pVesa, 0x03);
1523    gr4 = ReadGr(pVesa, 0x04);
1524    gr5 = ReadGr(pVesa, 0x05);
1525    gr6 = ReadGr(pVesa, 0x06);
1526    gr8 = ReadGr(pVesa, 0x08);
1527    seq2 = ReadSeq(pVesa, 0x02);
1528    seq4 = ReadSeq(pVesa, 0x04);
1529
1530    /* Force into colour mode */
1531    WriteMiscOut(miscOut | 0x01);
1532
1533    scrn = ReadSeq(pVesa, 0x01) | 0x20;
1534    SeqReset(pVesa, TRUE);
1535    WriteSeq(0x01, scrn);
1536    SeqReset(pVesa, FALSE);
1537
1538    WriteAttr(pVesa, 0x10, 0x01);	/* graphics mode */
1539    if (pScrn->depth == 4) {
1540	/* GJA */
1541	WriteGr(0x03, 0x00);	/* don't rotate, write unmodified */
1542	WriteGr(0x08, 0xFF);	/* write all bits in a byte */
1543	WriteGr(0x01, 0x00);	/* all planes come from CPU */
1544    }
1545
1546    WriteSeq(0x02, 0x04);   /* write to plane 2 */
1547    WriteSeq(0x04, 0x06);   /* enable plane graphics */
1548    WriteGr(0x04, 0x02);    /* read plane 2 */
1549    WriteGr(0x05, 0x00);    /* write mode 0, read mode 0 */
1550    WriteGr(0x06, 0x05);    /* set graphics */
1551    slowbcopy_tobus(pVesa->fonts, pVesa->VGAbase, 8192);
1552
1553    WriteSeq(0x02, 0x08);   /* write to plane 3 */
1554    WriteSeq(0x04, 0x06);   /* enable plane graphics */
1555    WriteGr(0x04, 0x03);    /* read plane 3 */
1556    WriteGr(0x05, 0x00);    /* write mode 0, read mode 0 */
1557    WriteGr(0x06, 0x05);    /* set graphics */
1558    slowbcopy_tobus(pVesa->fonts + 8192, pVesa->VGAbase, 8192);
1559
1560    scrn = ReadSeq(pVesa, 0x01) & ~0x20;
1561    SeqReset(pVesa, TRUE);
1562    WriteSeq(0x01, scrn);
1563    SeqReset(pVesa, FALSE);
1564
1565    /* restore the registers that were changed */
1566    WriteMiscOut(miscOut);
1567    WriteAttr(pVesa, 0x10, attr10);
1568    WriteGr(0x01, gr1);
1569    WriteGr(0x03, gr3);
1570    WriteGr(0x04, gr4);
1571    WriteGr(0x05, gr5);
1572    WriteGr(0x06, gr6);
1573    WriteGr(0x08, gr8);
1574    WriteSeq(0x02, seq2);
1575    WriteSeq(0x04, seq4);
1576}
1577
1578static Bool
1579VESASaveScreen(ScreenPtr pScreen, int mode)
1580{
1581    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
1582    VESAPtr pVesa = VESAGetRec(pScrn);
1583    Bool on = xf86IsUnblank(mode);
1584
1585    if (on)
1586	SetTimeSinceLastInputEvent();
1587
1588    if (pScrn->vtSema) {
1589	unsigned char scrn = ReadSeq(pVesa, 0x01);
1590
1591	if (on)
1592	    scrn &= ~0x20;
1593	else
1594	    scrn |= 0x20;
1595	SeqReset(pVesa, TRUE);
1596	WriteSeq(0x01, scrn);
1597	SeqReset(pVesa, FALSE);
1598    }
1599
1600    return (TRUE);
1601}
1602
1603static int
1604VESABankSwitch(ScreenPtr pScreen, unsigned int iBank)
1605{
1606    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
1607    VESAPtr pVesa = VESAGetRec(pScrn);
1608
1609    if (pVesa->curBank == iBank)
1610	return (0);
1611    if (!VBEBankSwitch(pVesa->pVbe, iBank, 0))
1612        return (1);
1613    if (pVesa->bankSwitchWindowB) {
1614        if (!VBEBankSwitch(pVesa->pVbe, iBank, 1))
1615	   return (1);
1616    }
1617    pVesa->curBank = iBank;
1618
1619    return (0);
1620}
1621
1622Bool
1623VESASaveRestore(ScrnInfoPtr pScrn, vbeSaveRestoreFunction function)
1624{
1625    VESAPtr pVesa;
1626
1627    if (MODE_QUERY < 0 || function > MODE_RESTORE)
1628	return (FALSE);
1629
1630    pVesa = VESAGetRec(pScrn);
1631
1632
1633    /* Query amount of memory to save state */
1634    if (function == MODE_QUERY ||
1635	(function == MODE_SAVE && pVesa->state == NULL)) {
1636
1637	/* Make sure we save at least this information in case of failure */
1638	(void)VBEGetVBEMode(pVesa->pVbe, &pVesa->stateMode);
1639	SaveFonts(pScrn);
1640
1641	if (pVesa->major > 1) {
1642	    if (!VBESaveRestore(pVesa->pVbe,function,(pointer)&pVesa->state,
1643				&pVesa->stateSize,&pVesa->statePage))
1644	        return FALSE;
1645
1646	}
1647    }
1648
1649    /* Save/Restore Super VGA state */
1650    if (function != MODE_QUERY) {
1651        Bool retval = TRUE;
1652
1653	if (pVesa->major > 1) {
1654	    if (function == MODE_RESTORE)
1655		memcpy(pVesa->state, pVesa->pstate, pVesa->stateSize);
1656
1657	    if ((retval = VBESaveRestore(pVesa->pVbe,function,
1658					 (pointer)&pVesa->state,
1659					 &pVesa->stateSize,&pVesa->statePage))
1660		&& function == MODE_SAVE) {
1661	        /* don't rely on the memory not being touched */
1662	        if (pVesa->pstate == NULL)
1663		    pVesa->pstate = xalloc(pVesa->stateSize);
1664		memcpy(pVesa->pstate, pVesa->state, pVesa->stateSize);
1665	    }
1666	}
1667
1668	if (function == MODE_RESTORE) {
1669	    VBESetVBEMode(pVesa->pVbe, pVesa->stateMode, NULL);
1670	    RestoreFonts(pScrn);
1671	}
1672
1673	if (!retval)
1674	    return (FALSE);
1675
1676    }
1677
1678    return (TRUE);
1679}
1680
1681static void
1682VESADisplayPowerManagementSet(ScrnInfoPtr pScrn, int mode,
1683                int flags)
1684{
1685    VESAPtr pVesa = VESAGetRec(pScrn);
1686
1687    if (!pScrn->vtSema)
1688	return;
1689
1690    VBEDPMSSet(pVesa->pVbe, mode);
1691}
1692
1693/***********************************************************************
1694 * DGA stuff
1695 ***********************************************************************/
1696static Bool VESADGAOpenFramebuffer(ScrnInfoPtr pScrn, char **DeviceName,
1697				   unsigned char **ApertureBase,
1698				   int *ApertureSize, int *ApertureOffset,
1699				   int *flags);
1700static Bool VESADGASetMode(ScrnInfoPtr pScrn, DGAModePtr pDGAMode);
1701static void VESADGASetViewport(ScrnInfoPtr pScrn, int x, int y, int flags);
1702
1703static Bool
1704VESADGAOpenFramebuffer(ScrnInfoPtr pScrn, char **DeviceName,
1705		       unsigned char **ApertureBase, int *ApertureSize,
1706		       int *ApertureOffset, int *flags)
1707{
1708    VESAPtr pVesa = VESAGetRec(pScrn);
1709
1710    *DeviceName = NULL;		/* No special device */
1711    *ApertureBase = (unsigned char *)(long)(pVesa->mapPhys);
1712    *ApertureSize = pVesa->mapSize;
1713    *ApertureOffset = pVesa->mapOff;
1714    *flags = DGA_NEED_ROOT;
1715
1716    return (TRUE);
1717}
1718
1719static Bool
1720VESADGASetMode(ScrnInfoPtr pScrn, DGAModePtr pDGAMode)
1721{
1722    DisplayModePtr pMode;
1723    int scrnIdx = pScrn->pScreen->myNum;
1724    int frameX0, frameY0;
1725
1726    if (pDGAMode) {
1727	pMode = pDGAMode->mode;
1728	frameX0 = frameY0 = 0;
1729    }
1730    else {
1731	if (!(pMode = pScrn->currentMode))
1732	    return (TRUE);
1733
1734	frameX0 = pScrn->frameX0;
1735	frameY0 = pScrn->frameY0;
1736    }
1737
1738    if (!(*pScrn->SwitchMode)(scrnIdx, pMode, 0))
1739	return (FALSE);
1740    (*pScrn->AdjustFrame)(scrnIdx, frameX0, frameY0, 0);
1741
1742    return (TRUE);
1743}
1744
1745static void
1746VESADGASetViewport(ScrnInfoPtr pScrn, int x, int y, int flags)
1747{
1748    (*pScrn->AdjustFrame)(pScrn->pScreen->myNum, x, y, flags);
1749}
1750
1751static int
1752VESADGAGetViewport(ScrnInfoPtr pScrn)
1753{
1754    return (0);
1755}
1756
1757static DGAFunctionRec VESADGAFunctions =
1758{
1759    VESADGAOpenFramebuffer,
1760    NULL,       /* CloseFramebuffer */
1761    VESADGASetMode,
1762    VESADGASetViewport,
1763    VESADGAGetViewport,
1764    NULL,       /* Sync */
1765    NULL,       /* FillRect */
1766    NULL,       /* BlitRect */
1767    NULL,       /* BlitTransRect */
1768};
1769
1770static void
1771VESADGAAddModes(ScrnInfoPtr pScrn)
1772{
1773    VESAPtr pVesa = VESAGetRec(pScrn);
1774    DisplayModePtr pMode = pScrn->modes;
1775    DGAModePtr pDGAMode;
1776
1777    do {
1778	pDGAMode = xrealloc(pVesa->pDGAMode,
1779			    (pVesa->nDGAMode + 1) * sizeof(DGAModeRec));
1780	if (!pDGAMode)
1781	    break;
1782
1783	pVesa->pDGAMode = pDGAMode;
1784	pDGAMode += pVesa->nDGAMode;
1785	(void)memset(pDGAMode, 0, sizeof(DGAModeRec));
1786
1787	++pVesa->nDGAMode;
1788	pDGAMode->mode = pMode;
1789	pDGAMode->flags = DGA_CONCURRENT_ACCESS | DGA_PIXMAP_AVAILABLE;
1790	pDGAMode->byteOrder = pScrn->imageByteOrder;
1791	pDGAMode->depth = pScrn->depth;
1792	pDGAMode->bitsPerPixel = pScrn->bitsPerPixel;
1793	pDGAMode->red_mask = pScrn->mask.red;
1794	pDGAMode->green_mask = pScrn->mask.green;
1795	pDGAMode->blue_mask = pScrn->mask.blue;
1796	pDGAMode->visualClass = pScrn->bitsPerPixel > 8 ?
1797	    TrueColor : PseudoColor;
1798	pDGAMode->xViewportStep = 1;
1799	pDGAMode->yViewportStep = 1;
1800	pDGAMode->viewportWidth = pMode->HDisplay;
1801	pDGAMode->viewportHeight = pMode->VDisplay;
1802
1803	pDGAMode->bytesPerScanline = pVesa->maxBytesPerScanline;
1804	pDGAMode->imageWidth = pMode->HDisplay;
1805	pDGAMode->imageHeight =  pMode->VDisplay;
1806	pDGAMode->pixmapWidth = pDGAMode->imageWidth;
1807	pDGAMode->pixmapHeight = pDGAMode->imageHeight;
1808	pDGAMode->maxViewportX = pScrn->virtualX -
1809				    pDGAMode->viewportWidth;
1810	pDGAMode->maxViewportY = pScrn->virtualY -
1811				    pDGAMode->viewportHeight;
1812
1813	pDGAMode->address = pVesa->base;
1814
1815	pMode = pMode->next;
1816    } while (pMode != pScrn->modes);
1817}
1818
1819static Bool
1820VESADGAInit(ScrnInfoPtr pScrn, ScreenPtr pScreen)
1821{
1822    VESAPtr pVesa = VESAGetRec(pScrn);
1823
1824    if (pScrn->depth < 8 || pVesa->mapPhys == 0xa0000L)
1825	return (FALSE);
1826
1827    if (!pVesa->nDGAMode)
1828	VESADGAAddModes(pScrn);
1829
1830    return (DGAInit(pScreen, &VESADGAFunctions,
1831	    pVesa->pDGAMode, pVesa->nDGAMode));
1832}
1833