vboxvideo_70.c revision efca78798c39c5c7e32c7cc3843d1982c5a5b271
/** @file
*
* Linux Additions X11 graphics driver
*/
/*
* Copyright (C) 2006-2007 Sun Microsystems, Inc.
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 USA or visit http://www.sun.com if you need
* additional information or have any questions.
* --------------------------------------------------------------------
*
* This code is based on:
*
* X11 VESA driver
*
* Copyright (c) 2000 by Conectiva S.A. (http://www.conectiva.com)
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* CONECTIVA LINUX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of Conectiva Linux shall
* not be used in advertising or otherwise to promote the sale, use or other
* dealings in this Software without prior written authorization from
* Conectiva Linux.
*
* Authors: Paulo César Pereira de Andrade <pcpa@conectiva.com.br>
*/
#ifdef XORG_7X
# include "xorg-server.h"
#endif
#include "vboxvideo.h"
#include "version-generated.h"
#include <xf86.h>
/* All drivers initialising the SW cursor need this */
#include "mipointer.h"
/* All drivers implementing backing store need this */
#include "mibstore.h"
/* Colormap handling */
#include "micmap.h"
#include "xf86cmap.h"
/* DPMS */
/* #define DPMS_SERVER
#include "extensions/dpms.h" */
/* Mandatory functions */
static void VBOXIdentify(int flags);
char **argv);
int flags);
/* locally used functions */
int *indices,
/*
* This contains the functions needed by the server after loading the
* driver module. It must be supplied, and gets added the driver list by
* the Module Setup funtion in the dynamic case. In the static case a
* reference to this is compiled in, and this requires that the name of
* this DriverRec be an upper-case version of the driver name.
*/
#ifdef XORG_7X
#endif
NULL,
0,
#ifdef XORG_7X
#endif
};
/* Supported chipsets */
static SymTabRec VBOXChipsets[] =
{
{VBOX_VESA_DEVICEID, "vbox"},
{-1, NULL}
};
static PciChipsets VBOXPCIchipsets[] = {
};
typedef enum {
} VBOXOpts;
/* No options for now */
static const OptionInfoRec VBOXOptions[] = {
};
/*
* List of symbols from other modules that this module references. This
* list is used to tell the loader that it is OK for symbols here to be
* unresolved providing that it hasn't been told that they haven't been
* told that they are essential via a call to xf86LoaderReqSymbols() or
* xf86LoaderReqSymLists(). The purpose is this is to avoid warnings about
* unresolved symbols that are not required.
*/
static const char *fbSymbols[] = {
"fbPictureInit",
"fbScreenInit",
};
static const char *shadowfbSymbols[] = {
"ShadowFBInit2",
};
static const char *vbeSymbols[] = {
"VBEExtendedInit",
"VBEFindSupportedDepths",
"VBEGetModeInfo",
"VBEGetVBEInfo",
"VBEGetVBEMode",
"VBEPrintModes",
"VBESaveRestore",
"VBESetDisplayStart",
"VBESetGetDACPaletteFormat",
"VBESetGetLogicalScanlineLength",
"VBESetGetPaletteData",
"VBESetModeNames",
"VBESetModeParameters",
"VBESetVBEMode",
"VBEValidateModes",
"vbeDoEDID",
"vbeFree",
};
static const char *ramdacSymbols[] = {
"xf86InitCursor",
"xf86CreateCursorInfoRec",
};
#ifdef XFree86LOADER
/* Module loader interface */
static MODULESETUPPROTO(vboxSetup);
static XF86ModuleVersionInfo vboxVersionRec =
{
"Sun Microsystems, Inc.",
#ifdef XORG_7X
#else
#endif
1, /* Module major version. Xorg-specific */
0, /* Module minor version. Xorg-specific */
1, /* Module patchlevel. Xorg-specific */
ABI_CLASS_VIDEODRV, /* This is a video driver */
{0, 0, 0, 0}
};
/*
* This data is accessed by the loader. The name must be the module name
* followed by "ModuleData".
*/
#ifdef XORG_7X
#endif
static pointer
{
if (!Initialised)
{
Initialised = TRUE;
NULL);
}
if (ErrorMajor)
return (NULL);
}
#endif /* XFree86Loader defined */
static const OptionInfoRec *
{
return (VBOXOptions);
}
static void
VBOXIdentify(int flags)
{
}
/*
* This function is called once, at the start of the first server generation to
* do a minimal probe for supported hardware.
*/
static Bool
{
int numDevSections, numUsed;
int *usedChips;
int i;
/*
* Find the config file Device sections that match this
* driver, and return if there are none.
*/
&devSections)) <= 0)
return (FALSE);
/* PCI BUS */
if (xf86GetPciVideoInfo()) {
if (numUsed > 0) {
if (flags & PROBE_DETECT)
foundScreen = TRUE;
else {
for (i = 0; i < numUsed; i++) {
/* Allocate a ScrnInfoRec */
foundScreen = TRUE;
}
}
}
}
}
return (foundScreen);
}
static VBOXPtr
{
if (!pScrn->driverPrivate)
{
#if 0
#endif
}
}
static void
{
#if 0
#endif
}
/**
* Fills a display mode M with a built-in mode of name pszName and dimensions
* cx and cy.
*/
{
m->type = M_T_BUILTIN;
/* VBox only supports screen widths which are a multiple of 8 */
if (pszName)
{
if (m->name)
}
}
/** vboxvideo's list of standard video modes */
struct
{
/** mode width */
/** mode height */
} vboxStandardModes[] =
{
{ 1600, 1200 },
{ 1440, 1050 },
{ 1280, 960 },
{ 1024, 768 },
{ 800, 600 },
{ 640, 480 },
{ 0, 0 }
};
enum
{
};
/**
* Returns a standard mode which the host likes. Can be called multiple
* times with the index returned by the previous call to get a list of modes.
* @returns the index of the mode in the list, or 0 if no more modes are
* available
* @param pScrn the screen information structure
* @param pScrn->bitsPerPixel
* if this is non-null, only modes with this BPP will be
* returned
* @param cIndex the index of the last mode queried, or 0 to query the
* first mode available. Note: the first index is 1
* @param pcx where to store the mode's width
* @param pcy where to store the mode's height
* @param pcBits where to store the mode's BPP
*/
{
("cIndex = %d, vboxNumStdModes = %d\n", cIndex,
{
continue;
cBits = 32;
cBits = 16;
else
continue;
if (pcx)
if (pcy)
if (pcBits)
return i + 1;
}
return 0;
}
/**
* Returns the preferred video mode. The current order of preference is
* (from highest to least preferred):
* - The mode corresponding to the last size hint from the host
* - The video mode saved from the last session
* - The largest standard mode which the host likes, falling back to
* 640x480x32 as a worst case
* - If the host can't be contacted at all, we return 1024x768x32
*
* The return type is void as we guarantee we will return some mode.
*/
{
/* Query the host for the preferred resolution and colour depth */
TRACE_ENTRY();
{
found = false;
if (!found)
found = false;
if (found)
/* Adjust to a multiple of eight */
if (!found)
if (!found)
{
/* Last resort */
cx = 640;
cy = 480;
cBits = 32;
}
}
else
{
cx = 1024;
cy = 768;
}
if (pcx)
if (pcy)
if (pcx)
}
/* Move a screen mode found to the end of the list, so that RandR will give
* it the highest priority when a mode switch is requested. Returns the mode
* that was previously before the mode in the list in order to allow the
* caller to continue walking the list. */
{
{
}
return pPrev;
}
/**
* Rewrites the first dynamic mode found which is not the current screen mode
* to contain the host's currently preferred screen size, then moves that
* mode to the front of the screen information structure's mode list.
* Additionally, if the current mode is not dynamic, the second dynamic mode
* will be set to match the current mode and also added to the front. This
* ensures that the user can always reset the current size to kick the driver
* to update its mode list.
*/
{
bool found = false;
TRACE_ENTRY();
#ifdef DEBUG
/* Count the number of modes for sanity */
break;
#endif
{
#ifdef DEBUG
#endif
{
if (!found)
else if (pCurrent)
found = true;
}
break;
}
("vboxvideo: no free dynamic mode found. Exiting.\n"));
("pScrn->modes->HDisplay=%u, pScrn->modes->next->HDisplay=%u\n",
("pScrn->modes->VDisplay=%u, pScrn->modes->next->VDisplay=%u\n",
}
/**
* Allocates an empty display mode and links it into the doubly linked list of
* modes pointed to by pScrn->modes. Returns a pointer to the newly allocated
* memory.
*/
{
TRACE_ENTRY();
{
}
else
{
}
return pMode;
}
/**
* Create display mode entries in the screen information structure for each
* of the initial graphics modes that we wish to support. This includes:
* - An initial mode, of the size requested by the caller
* - Two dynamic modes, one of which will be updated to match the last size
* hint from the host on each mode switch, but initially also of the
* requested size
* - Several standard modes, if possible ones that the host likes
* - Any modes that the user requested in xorg.conf/XFree86Config
*/
static void
{
/* For reasons related to the way RandR 1.1 is implemented, we need to
* make sure that the initial mode (more precisely, a mode equal to the
* initial virtual resolution) is always present in the mode list. RandR
* has the assumption build in that there will either be a mode of that
* size present at all times, or that the first mode in the list will
* always be smaller than the initial virtual resolution. Since our
* approach to dynamic resizing isn't quite the way RandR was intended to
* be, and breaks the second assumption, we guarantee the first. */
/* Create our two dynamic modes. */
/* Add standard modes supported by the host */
for ( ; ; )
{
char szName[256];
if (cIndex == 0)
break;
}
/* And finally any modes specified by the user. We assume here that
* the mode names reflect the mode sizes. */
{
{
}
}
}
/*
* QUOTE from the XFree86 DESIGN document:
*
* The purpose of this function is to find out all the information
* required to determine if the configuration is usable, and to initialise
* those parts of the ScrnInfoRec that can be set once at the beginning of
* the first server generation.
*
* (...)
*
* This includes probing for video memory, clocks, ramdac, and all other
* and related info. It includes validating and determining the set of
* video modes that will be used (and anything that is required to
* determine that).
*
* This information should be determined in the least intrusive way
* possible. The state of the HW must remain unchanged by this function.
* Although video memory (including MMIO) may be mapped within this
* function, it must be unmapped before returning.
*
* END QUOTE
*/
static Bool
{
int i;
enum { MODE_MIN_SIZE = 64 };
TRACE_ENTRY();
/* Are we really starting the server, or is this just a dummy run? */
if (flags & PROBE_DETECT)
return (FALSE);
"VirtualBox guest additions video driver version "
VBOX_VERSION_STRING "\n");
/* Get our private data from the ScrnInfoRec structure. */
/* Initialise the guest library */
/* Entity information seems to mean bus information. */
return FALSE;
/* The ramdac module is needed for the hardware cursor. */
return FALSE;
/* We need the vbe module because we use VBE code to save and restore
text mode, in order to keep our code simple. */
return (FALSE);
/* The framebuffer module. */
return (FALSE);
return FALSE;
/* Set up our ScrnInfoRec structure to describe our virtual
capabilities to X. */
/* Let's create a nice, capable virtual monitor. */
/* Determine the size of the VBox video RAM from PCI data*/
#if 0
#endif
/* Using the PCI information caused problems with non-powers-of-two
sized video RAM configurations */
/* Set up clock information that will support all modes we need. */
/* Determine the preferred size and colour depth and setup video modes */
{
/* We only support 16 and 24 bits depth (i.e. 16 and 32bpp) */
if (cBits != 16)
cBits = 24;
return FALSE;
}
{
"The VBox additions only support 16 and 32bpp graphics modes\n");
return FALSE;
}
/* Colour weight - we always call this, since we are always in
truecolour. */
return (FALSE);
/* visual init */
return (FALSE);
/* We don't validate with xf86ValidateModes and xf86PruneModes as we
* already know what we like and what we don't. */
/* Set the right virtual resolution. */
/* Set the DPI. Perhaps we should read this from the host? */
/* options */
return FALSE;
/* Framebuffer-related setup */
TRACE_EXIT();
return (TRUE);
}
/*
* QUOTE from the XFree86 DESIGN document:
*
* This is called at the start of each server generation.
*
* (...)
*
* Decide which operations need to be placed under resource access
* control. (...) Map any video memory or other memory regions. (...)
* Save the video card state. (...) Initialise the initial video
* mode.
*
* End QUOTE.
*/
static Bool
{
unsigned flags;
TRACE_ENTRY();
/* We make use of the X11 VBE code to save and restore text mode, in
order to keep our code simple. */
| RESTORE_BIOS_SCRATCH)) == NULL)
return (FALSE);
/* pVBox->mapSize = 1 << pVBox->pciInfo->size[0]; */
/* Using the PCI information caused problems with
non-powers-of-two sized video RAM configurations */
}
if (!VBOXMapVidMem(pScrn))
return (FALSE);
/* save current video state */
/* set the viewport */
/* Blank the screen for aesthetic reasons. */
/* mi layer - reset the visual list (?)*/
return (FALSE);
return (FALSE);
if (!miSetPixmapDepths())
return (FALSE);
/* I checked in the sources, and XFree86 4.2 does seem to support
this function for 32bpp. */
return (FALSE);
/* Fixup RGB ordering */
}
}
/* must be after RGB ordering fixed */
fbPictureInit(pScreen, 0, 0);
/* software cursor */
/* colourmap code - apparently, we need this even in Truecolour */
if (!miCreateDefColormap(pScreen))
return (FALSE);
8 /* DAC is switchable to 8 bits per primary color */,
return (FALSE);
/* However, we probably do want to support power management -
even if we just use a dummy function. */
/* Report any unused options (only for the first generation) */
if (serverGeneration == 1)
/* set first video mode */
return FALSE;
/* And make sure that a non-current dynamic mode is at the front of the
* list */
"Unable to start the VirtualBox mouse pointer integration with the host system.\n");
"The VBox video extensions are now enabled.\n");
}
TRACE_EXIT();
return (TRUE);
}
static Bool
{
return FALSE;
return TRUE;
}
static void
{
}
static Bool
{
}
}
static Bool
{
return FALSE;
return FALSE;
return FALSE;
return TRUE;
}
/* Set a graphics mode */
static Bool
{
TRACE_ENTRY();
{
"Unable to set up a virtual screen size of %dx%d with %d Kb of video memory. Please increase the video memory size.\n",
return FALSE;
}
/* Do not reset the current mode - we use this as a way of kicking
* the driver */
return TRUE;
/* Disable linear framebuffer mode before making changes to the resolution. */
/* Unlike the resolution, the depth is fixed for a given screen
for the lifetime of the X session. */
/* HDisplay and VDisplay are actually monitor information about
the display part of the scanlines. */
/* Enable linear framebuffer mode. */
/* Set the virtual resolution. We are still using VESA to control
the virtual offset. */
TRACE_EXIT();
return (TRUE);
}
{
if (!pPixmap) {
"Failed to get the screen pixmap.\n");
return FALSE;
}
return TRUE;
}
static void
{
/* If VBVA is enabled the graphics card will not notice the change. */
}
static void
{
}
static Bool
{
return (TRUE);
0xa0000, 0x10000);
}
}
static void
{
return;
}
static void
{
int i, idx;
#define VBOXDACDelay() \
do { \
} while (0)
for (i = 0; i < numColors; i++) {
VBOXDACDelay();
VBOXDACDelay();
VBOXDACDelay();
VBOXDACDelay();
}
}
/*
* Just adapted from the std* functions in vgaHW.c
*/
static void
{
index |= 0x20;
}
static int
{
index |= 0x20;
}
static int
{
}
static int
{
}
static void
{
if (start) {
}
else {
}
}
static void
{
return;
/* If in graphics mode, don't save anything */
if (attr10 & 0x01)
return;
/* save the registers that are needed here */
miscOut = ReadMiscOut();
/* Force into colour mode */
/*font1 */
/* font2 */
/* Restore clobbered registers */
}
static void
{
return;
/* save the registers that are needed here */
miscOut = ReadMiscOut();
/* Force into colour mode */
/* GJA */
}
/* restore the registers that were changed */
}
static Bool
{
if (on)
if (on)
scrn &= ~0x20;
else
scrn |= 0x20;
}
return (TRUE);
}
{
return (FALSE);
/* Query amount of memory to save state */
if (function == MODE_QUERY ||
{
/* Make sure we save at least this information in case of failure */
return FALSE;
}
if (function != MODE_QUERY) {
if (function == MODE_RESTORE)
{
/* don't rely on the memory not being touched */
}
if (function == MODE_RESTORE)
{
}
if (!retval)
return (FALSE);
}
return (TRUE);
}
static void
int flags)
{
/* VBox is always power efficient... */
}