VirtualBox

source: vbox/trunk/src/VBox/Additions/x11/vboxvideo/vboxvideo.c

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 48.8 KB
RevLine 
[32404]1/* $Id: vboxvideo.c 98103 2023-01-17 14:15:46Z vboxsync $ */
[6202]2/** @file
3 * Linux Additions X11 graphics driver
4 */
5
6/*
[98103]7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
[69346]8 * This file is based on the X.Org VESA driver:
[6202]9 *
10 * Copyright (c) 2000 by Conectiva S.A. (http://www.conectiva.com)
[43245]11 * Copyright 2008 Red Hat, Inc.
12 * Copyright 2012 Red Hat, Inc.
[6202]13 *
14 * Permission is hereby granted, free of charge, to any person obtaining a
15 * copy of this software and associated documentation files (the "Software"),
16 * to deal in the Software without restriction, including without limitation
17 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
18 * and/or sell copies of the Software, and to permit persons to whom the
19 * Software is furnished to do so, subject to the following conditions:
20 *
21 * The above copyright notice and this permission notice shall be included in
22 * all copies or substantial portions of the Software.
23 *
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
[69058]26 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
27 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
28 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
29 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
30 * USE OR OTHER DEALINGS IN THE SOFTWARE.
[6202]31 *
32 * Except as contained in this notice, the name of Conectiva Linux shall
33 * not be used in advertising or otherwise to promote the sale, use or other
34 * dealings in this Software without prior written authorization from
35 * Conectiva Linux.
36 *
37 * Authors: Paulo César Pereira de Andrade <pcpa@conectiva.com.br>
[43245]38 * David Dawes <dawes@xfree86.org>
39 * Adam Jackson <ajax@redhat.com>
40 * Dave Airlie <airlied@redhat.com>
[69058]41 * Michael Thayer <michael.thayer@oracle.com>
[6202]42 */
43
[55402]44#include "vboxvideo.h"
[65381]45#include <VBoxVideoVBE.h>
[43081]46
[55402]47/* Basic definitions and functions needed by all drivers. */
[43081]48#include "xf86.h"
[55402]49/* For video memory mapping. */
[43081]50#include "xf86_OSproc.h"
51#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 6
[55402]52/* PCI resources. */
[43081]53# include "xf86Resources.h"
54#endif
[55402]55/* Generic server linear frame-buffer APIs. */
[43081]56#include "fb.h"
[55402]57/* Colormap and visual handling. */
[6202]58#include "micmap.h"
59#include "xf86cmap.h"
[55358]60/* ShadowFB support */
61#include "shadowfb.h"
[22093]62/* VGA hardware functions for setting and restoring text mode */
63#include "vgaHW.h"
[34715]64#ifdef VBOXVIDEO_13
[6484]65/* X.org 1.3+ mode setting */
[34715]66# define _HAVE_STRING_ARCH_strsep /* bits/string2.h, __strsep_1c. */
67# include "xf86Crtc.h"
68# include "xf86Modes.h"
[55471]69/* For xf86RandR12GetOriginalVirtualSize(). */
70# include "xf86RandR12.h"
[34715]71#endif
[50981]72/* For setting the root window property. */
73#include "property.h"
[69075]74#include <X11/Xatom.h>
[50981]75
[55402]76#ifdef XORG_7X
77# include <stdlib.h>
78# include <string.h>
[63556]79# include <fcntl.h>
80# include <unistd.h>
[49628]81#endif
82
[6202]83/* Mandatory functions */
84
85static const OptionInfoRec * VBOXAvailableOptions(int chipid, int busid);
86static void VBOXIdentify(int flags);
[22085]87#ifndef PCIACCESS
[6202]88static Bool VBOXProbe(DriverPtr drv, int flags);
[22085]89#else
[22084]90static Bool VBOXPciProbe(DriverPtr drv, int entity_num,
91 struct pci_device *dev, intptr_t match_data);
92#endif
[6202]93static Bool VBOXPreInit(ScrnInfoPtr pScrn, int flags);
[43250]94static Bool VBOXScreenInit(ScreenPtr pScreen, int argc, char **argv);
95static Bool VBOXEnterVT(ScrnInfoPtr pScrn);
96static void VBOXLeaveVT(ScrnInfoPtr pScrn);
97static Bool VBOXCloseScreen(ScreenPtr pScreen);
[63221]98#ifndef VBOXVIDEO_13
[34715]99static Bool VBOXSaveScreen(ScreenPtr pScreen, int mode);
[63221]100#endif
[43250]101static Bool VBOXSwitchMode(ScrnInfoPtr pScrn, DisplayModePtr pMode);
102static void VBOXAdjustFrame(ScrnInfoPtr pScrn, int x, int y);
103static void VBOXFreeScreen(ScrnInfoPtr pScrn);
[63221]104#ifndef VBOXVIDEO_13
105static void VBOXDisplayPowerManagementSet(ScrnInfoPtr pScrn, int mode, int flags);
106#endif
[6202]107
108/* locally used functions */
109static Bool VBOXMapVidMem(ScrnInfoPtr pScrn);
110static void VBOXUnmapVidMem(ScrnInfoPtr pScrn);
[35949]111static void VBOXSaveMode(ScrnInfoPtr pScrn);
112static void VBOXRestoreMode(ScrnInfoPtr pScrn);
[69064]113static void setSizesAndCursorIntegration(ScrnInfoPtr pScrn, Bool fScreenInitTime);
[6202]114
[55283]115#ifndef XF86_SCRN_INTERFACE
116# define xf86ScreenToScrn(pScreen) xf86Screens[(pScreen)->myNum]
117# define xf86ScrnToScreen(pScrn) screenInfo.screens[(pScrn)->scrnIndex]
118#endif
119
[43081]120static inline void VBOXSetRec(ScrnInfoPtr pScrn)
121{
122 if (!pScrn->driverPrivate)
[53530]123 {
124 VBOXPtr pVBox = (VBOXPtr)xnfcalloc(sizeof(VBOXRec), 1);
125 pScrn->driverPrivate = pVBox;
[60190]126#if defined(VBOXVIDEO_13) && defined(RT_OS_LINUX)
127 pVBox->fdACPIDevices = -1;
128#endif
[53530]129 }
[43081]130}
131
[22084]132enum GenericTypes
133{
134 CHIP_VBOX_GENERIC
135};
136
137#ifdef PCIACCESS
138static const struct pci_id_match vbox_device_match[] = {
139 {
140 VBOX_VENDORID, VBOX_DEVICEID, PCI_MATCH_ANY, PCI_MATCH_ANY,
141 0, 0, 0
142 },
143
144 { 0, 0, 0 },
145};
146#endif
147
148/* Supported chipsets */
149static SymTabRec VBOXChipsets[] =
150{
151 {VBOX_DEVICEID, "vbox"},
[45356]152 {-1, NULL}
[22084]153};
154
155static PciChipsets VBOXPCIchipsets[] = {
156 { VBOX_DEVICEID, VBOX_DEVICEID, RES_SHARED_VGA },
[45356]157 { -1, -1, RES_UNDEFINED },
[22084]158};
159
[6202]160/*
161 * This contains the functions needed by the server after loading the
162 * driver module. It must be supplied, and gets added the driver list by
[33540]163 * the Module Setup function in the dynamic case. In the static case a
[6202]164 * reference to this is compiled in, and this requires that the name of
165 * this DriverRec be an upper-case version of the driver name.
166 */
167
[34715]168#ifdef XORG_7X
169_X_EXPORT
170#endif
171DriverRec VBOXVIDEO = {
[6202]172 VBOX_VERSION,
173 VBOX_DRIVER_NAME,
174 VBOXIdentify,
[22084]175#ifdef PCIACCESS
176 NULL,
177#else
[6202]178 VBOXProbe,
[22084]179#endif
[6202]180 VBOXAvailableOptions,
181 NULL,
182 0,
[34715]183#ifdef XORG_7X
[22084]184 NULL,
[34715]185#endif
[22084]186#ifdef PCIACCESS
187 vbox_device_match,
188 VBOXPciProbe
189#endif
[6202]190};
191
192/* No options for now */
193static const OptionInfoRec VBOXOptions[] = {
[45356]194 { -1, NULL, OPTV_NONE, {0}, FALSE }
[6202]195};
196
[34715]197#ifndef XORG_7X
198/*
199 * List of symbols from other modules that this module references. This
200 * list is used to tell the loader that it is OK for symbols here to be
201 * unresolved providing that it hasn't been told that they haven't been
202 * told that they are essential via a call to xf86LoaderReqSymbols() or
203 * xf86LoaderReqSymLists(). The purpose is this is to avoid warnings about
204 * unresolved symbols that are not required.
205 */
206static const char *fbSymbols[] = {
207 "fbPictureInit",
208 "fbScreenInit",
209 NULL
210};
211
212static const char *shadowfbSymbols[] = {
[35881]213 "ShadowFBInit2",
214 NULL
[34715]215};
216
217static const char *ramdacSymbols[] = {
[52224]218 "xf86DestroyCursorInfoRec",
[34715]219 "xf86InitCursor",
220 "xf86CreateCursorInfoRec",
221 NULL
222};
223
224static const char *vgahwSymbols[] = {
[35949]225 "vgaHWFreeHWRec",
[34715]226 "vgaHWGetHWRec",
[35949]227 "vgaHWGetIOBase",
228 "vgaHWGetIndex",
229 "vgaHWRestore",
230 "vgaHWSave",
[39695]231 "vgaHWSetStdFuncs",
[34715]232 NULL
233};
234#endif /* !XORG_7X */
235
[55283]236/** Resize the virtual framebuffer. */
237static Bool adjustScreenPixmap(ScrnInfoPtr pScrn, int width, int height)
238{
239 ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
240 VBOXPtr pVBox = VBOXGetRec(pScrn);
241 int adjustedWidth = pScrn->bitsPerPixel == 16 ? (width + 1) & ~1 : width;
242 int cbLine = adjustedWidth * pScrn->bitsPerPixel / 8;
243 PixmapPtr pPixmap;
244
245 TRACE_LOG("width=%d, height=%d\n", width, height);
[69080]246 AssertMsg(width >= 0 && height >= 0, ("Invalid negative width (%d) or height (%d)\n", width, height));
[55283]247 if (pScreen == NULL) /* Not yet initialised. */
248 return TRUE;
249 pPixmap = pScreen->GetScreenPixmap(pScreen);
[69080]250 AssertMsg(pPixmap != NULL, ("Failed to get the screen pixmap.\n"));
[55283]251 TRACE_LOG("pPixmap=%p adjustedWidth=%d height=%d pScrn->depth=%d pScrn->bitsPerPixel=%d cbLine=%d pVBox->base=%p pPixmap->drawable.width=%d pPixmap->drawable.height=%d\n",
[69079]252 (void *)pPixmap, adjustedWidth, height, pScrn->depth,
253 pScrn->bitsPerPixel, cbLine, pVBox->base,
254 pPixmap->drawable.width, pPixmap->drawable.height);
[55283]255 if ( adjustedWidth != pPixmap->drawable.width
256 || height != pPixmap->drawable.height)
257 {
258 if ( adjustedWidth > VBOX_VIDEO_MAX_VIRTUAL || height > VBOX_VIDEO_MAX_VIRTUAL
259 || (unsigned)cbLine * (unsigned)height >= pVBox->cbFBMax)
260 {
261 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
262 "Virtual framebuffer %dx%d too large. For information, video memory: %u Kb.\n",
263 adjustedWidth, height, (unsigned) pVBox->cbFBMax / 1024);
264 return FALSE;
265 }
[57092]266 if (pScrn->vtSema)
267 vbvxClearVRAM(pScrn, ((size_t)pScrn->virtualX) * pScrn->virtualY * (pScrn->bitsPerPixel / 8),
268 ((size_t)adjustedWidth) * height * (pScrn->bitsPerPixel / 8));
[55283]269 pScreen->ModifyPixmapHeader(pPixmap, adjustedWidth, height, pScrn->depth, pScrn->bitsPerPixel, cbLine, pVBox->base);
270 }
271 pScrn->displayWidth = pScrn->virtualX = adjustedWidth;
272 pScrn->virtualY = height;
273 return TRUE;
274}
275
[63221]276#ifndef VBOXVIDEO_13
277/** Set a video mode to the hardware, RandR 1.1 version.
278 *
279 * Since we no longer do virtual frame buffers, adjust the screen pixmap
280 * dimensions to match. The "override" parameters are for when we received a
281 * mode hint while switched to a virtual terminal. In this case VBoxClient will
282 * have told us about the mode, but not yet been able to do a mode switch using
283 * RandR. We solve this by setting the requested mode to the host but keeping
284 * the virtual frame-
[57356]285 * buffer matching what the X server expects. */
[69064]286static void setModeRandR11(ScrnInfoPtr pScrn, DisplayModePtr pMode, Bool fScreenInitTime, Bool fEnterVTTime,
[57356]287 int cXOverRide, int cYOverRide)
[55332]288{
289 VBOXPtr pVBox = VBOXGetRec(pScrn);
290 struct vbvxFrameBuffer frameBuffer = { 0, 0, pMode->HDisplay, pMode->VDisplay, pScrn->bitsPerPixel};
[57356]291 int cXPhysical = cXOverRide > 0 ? min(cXOverRide, pMode->HDisplay) : pMode->HDisplay;
292 int cYPhysical = cYOverRide > 0 ? min(cYOverRide, pMode->VDisplay) : pMode->VDisplay;
[55332]293
294 pVBox->pScreens[0].aScreenLocation.cx = pMode->HDisplay;
295 pVBox->pScreens[0].aScreenLocation.cy = pMode->VDisplay;
[55968]296 if (fScreenInitTime)
[55332]297 {
[55968]298 /* The screen structure is not fully set up yet, so do not touch it. */
[55332]299 pScrn->displayWidth = pScrn->virtualX = pMode->HDisplay;
300 pScrn->virtualY = pMode->VDisplay;
301 }
302 else
[55875]303 {
304 xf86ScrnToScreen(pScrn)->width = pMode->HDisplay;
305 xf86ScrnToScreen(pScrn)->height = pMode->VDisplay;
[57092]306 /* This prevents a crash in CentOS 3. I was unable to debug it to
307 * satisfaction, partly due to the lack of symbols. My guess is that
308 * pScrn->ModifyPixmapHeader() expects certain things to be set up when
309 * it sees pScrn->vtSema set to true which are not quite done at this
310 * point of the VT switch. */
311 if (fEnterVTTime)
312 pScrn->vtSema = FALSE;
[55332]313 adjustScreenPixmap(pScrn, pMode->HDisplay, pMode->VDisplay);
[57092]314 if (fEnterVTTime)
315 pScrn->vtSema = TRUE;
[55875]316 }
[57092]317 if (pMode->HDisplay != 0 && pMode->VDisplay != 0 && pScrn->vtSema)
[57356]318 vbvxSetMode(pScrn, 0, cXPhysical, cYPhysical, 0, 0, true, true, &frameBuffer);
[55332]319 pScrn->currentMode = pMode;
320}
[63221]321#endif
[55332]322
[34715]323#ifdef VBOXVIDEO_13
[6484]324/* X.org 1.3+ mode-setting support ******************************************/
325
[55332]326/** Set a video mode to the hardware, RandR 1.2 version. If this is the first
327 * screen, re-set the current mode for all others (the offset for the first
328 * screen is always treated as zero by the hardware, so all other screens need
329 * to be changed to compensate for any changes!). The mode to set is taken
330 * from the X.Org Crtc structure. */
331static void setModeRandR12(ScrnInfoPtr pScrn, unsigned cScreen)
332{
333 VBOXPtr pVBox = VBOXGetRec(pScrn);
334 unsigned i;
335 struct vbvxFrameBuffer frameBuffer = { pVBox->pScreens[0].paCrtcs->x, pVBox->pScreens[0].paCrtcs->y, pScrn->virtualX,
336 pScrn->virtualY, pScrn->bitsPerPixel };
337 unsigned cFirst = cScreen;
338 unsigned cLast = cScreen != 0 ? cScreen + 1 : pVBox->cScreens;
[55471]339 int originalX, originalY;
[55332]340
[55471]341 /* Check that this code cannot trigger the resizing bug in X.Org Server 1.3.
[57180]342 * See the work-around in ScreenInit. */
[55471]343 xf86RandR12GetOriginalVirtualSize(pScrn, &originalX, &originalY);
[69080]344 AssertMsg(originalX == VBOX_VIDEO_MAX_VIRTUAL && originalY == VBOX_VIDEO_MAX_VIRTUAL, ("OriginalSize=%dx%d",
[55559]345 originalX, originalY));
[55332]346 for (i = cFirst; i < cLast; ++i)
[57092]347 if (pVBox->pScreens[i].paCrtcs->mode.HDisplay != 0 && pVBox->pScreens[i].paCrtcs->mode.VDisplay != 0 && pScrn->vtSema)
[55332]348 vbvxSetMode(pScrn, i, pVBox->pScreens[i].paCrtcs->mode.HDisplay, pVBox->pScreens[i].paCrtcs->mode.VDisplay,
349 pVBox->pScreens[i].paCrtcs->x, pVBox->pScreens[i].paCrtcs->y, pVBox->pScreens[i].fPowerOn,
350 pVBox->pScreens[i].paOutputs->status == XF86OutputStatusConnected, &frameBuffer);
351}
352
353/** Wrapper around setModeRandR12() to avoid exposing non-obvious semantics.
354 */
355static void setAllModesRandR12(ScrnInfoPtr pScrn)
356{
357 setModeRandR12(pScrn, 0);
358}
359
[6484]360/* For descriptions of these functions and structures, see
361 hw/xfree86/modes/xf86Crtc.h and hw/xfree86/modes/xf86Modes.h in the
362 X.Org source tree. */
363
[43245]364static Bool vbox_config_resize(ScrnInfoPtr pScrn, int cw, int ch)
365{
366 VBOXPtr pVBox = VBOXGetRec(pScrn);
[55384]367 Bool rc;
368 unsigned i;
369
[43245]370 TRACE_LOG("width=%d, height=%d\n", cw, ch);
[55384]371 rc = adjustScreenPixmap(pScrn, cw, ch);
372 /* Power-on all screens (the server expects this) and set the new pitch to them. */
373 for (i = 0; i < pVBox->cScreens; ++i)
374 pVBox->pScreens[i].fPowerOn = true;
375 setAllModesRandR12(pScrn);
376 vbvxSetSolarisMouseRange(cw, ch);
377 return rc;
[43245]378}
379
[6484]380static const xf86CrtcConfigFuncsRec VBOXCrtcConfigFuncs = {
[43245]381 vbox_config_resize
[6484]382};
383
384static void
385vbox_crtc_dpms(xf86CrtcPtr crtc, int mode)
[35616]386{
[55384]387 ScrnInfoPtr pScrn = crtc->scrn;
388 VBOXPtr pVBox = VBOXGetRec(pScrn);
[35616]389 unsigned cDisplay = (uintptr_t)crtc->driver_private;
[53346]390
[55384]391 TRACE_LOG("mode=%d\n", mode);
392 pVBox->pScreens[cDisplay].fPowerOn = (mode != DPMSModeOff);
393 setModeRandR12(pScrn, cDisplay);
[35616]394}
[6484]395
396static Bool
397vbox_crtc_lock (xf86CrtcPtr crtc)
[69066]398{ RT_NOREF(crtc); return FALSE; }
[6484]399
[43245]400
401/* We use this function to check whether the X server owns the active virtual
402 * terminal before attempting a mode switch, since the RandR extension isn't
403 * very dilligent here, which can mean crashes if we are unlucky. This is
404 * not the way it the function is intended - it is meant for reporting modes
405 * which the hardware can't handle. I hope that this won't confuse any clients
406 * connecting to us. */
[6484]407static Bool
408vbox_crtc_mode_fixup (xf86CrtcPtr crtc, DisplayModePtr mode,
409 DisplayModePtr adjusted_mode)
[69066]410{ RT_NOREF(crtc, mode, adjusted_mode); return TRUE; }
[6484]411
412static void
413vbox_crtc_stub (xf86CrtcPtr crtc)
[69066]414{ RT_NOREF(crtc); }
[6484]415
416static void
417vbox_crtc_mode_set (xf86CrtcPtr crtc, DisplayModePtr mode,
418 DisplayModePtr adjusted_mode, int x, int y)
419{
[69066]420 RT_NOREF(mode);
[34715]421 VBOXPtr pVBox = VBOXGetRec(crtc->scrn);
[35616]422 unsigned cDisplay = (uintptr_t)crtc->driver_private;
[34715]423
[22087]424 TRACE_LOG("name=%s, HDisplay=%d, VDisplay=%d, x=%d, y=%d\n", adjusted_mode->name,
[6589]425 adjusted_mode->HDisplay, adjusted_mode->VDisplay, x, y);
[55384]426 pVBox->pScreens[cDisplay].fPowerOn = true;
[52199]427 pVBox->pScreens[cDisplay].aScreenLocation.cx = adjusted_mode->HDisplay;
428 pVBox->pScreens[cDisplay].aScreenLocation.cy = adjusted_mode->VDisplay;
429 pVBox->pScreens[cDisplay].aScreenLocation.x = x;
430 pVBox->pScreens[cDisplay].aScreenLocation.y = y;
[55384]431 setModeRandR12(crtc->scrn, cDisplay);
[6484]432}
433
434static void
435vbox_crtc_gamma_set (xf86CrtcPtr crtc, CARD16 *red,
436 CARD16 *green, CARD16 *blue, int size)
[69066]437{ RT_NOREF(crtc, red, green, blue, size); }
[6484]438
439static void *
440vbox_crtc_shadow_allocate (xf86CrtcPtr crtc, int width, int height)
[69066]441{ RT_NOREF(crtc, width, height); return NULL; }
[6484]442
443static const xf86CrtcFuncsRec VBOXCrtcFuncs = {
444 .dpms = vbox_crtc_dpms,
445 .save = NULL, /* These two are never called by the server. */
446 .restore = NULL,
447 .lock = vbox_crtc_lock,
448 .unlock = NULL, /* This will not be invoked if lock returns FALSE. */
449 .mode_fixup = vbox_crtc_mode_fixup,
450 .prepare = vbox_crtc_stub,
451 .mode_set = vbox_crtc_mode_set,
452 .commit = vbox_crtc_stub,
453 .gamma_set = vbox_crtc_gamma_set,
454 .shadow_allocate = vbox_crtc_shadow_allocate,
455 .shadow_create = NULL, /* These two should not be invoked if allocate
456 returns NULL. */
457 .shadow_destroy = NULL,
458 .set_cursor_colors = NULL, /* We are still using the old cursor API. */
459 .set_cursor_position = NULL,
460 .show_cursor = NULL,
461 .hide_cursor = NULL,
462 .load_cursor_argb = NULL,
463 .destroy = vbox_crtc_stub
464};
465
466static void
467vbox_output_stub (xf86OutputPtr output)
[69066]468{ RT_NOREF(output); }
[6484]469
470static void
471vbox_output_dpms (xf86OutputPtr output, int mode)
[53544]472{
[69066]473 RT_NOREF(output, mode);
[53544]474}
475
[6484]476static int
477vbox_output_mode_valid (xf86OutputPtr output, DisplayModePtr mode)
478{
[51242]479 return MODE_OK;
[6484]480}
481
482static Bool
483vbox_output_mode_fixup (xf86OutputPtr output, DisplayModePtr mode,
484 DisplayModePtr adjusted_mode)
[69066]485{ RT_NOREF(output, mode, adjusted_mode); return TRUE; }
[6484]486
487static void
488vbox_output_mode_set (xf86OutputPtr output, DisplayModePtr mode,
489 DisplayModePtr adjusted_mode)
[69066]490{ RT_NOREF(output, mode, adjusted_mode); }
[6484]491
492static xf86OutputStatus
493vbox_output_detect (xf86OutputPtr output)
494{
[53527]495 ScrnInfoPtr pScrn = output->scrn;
496 VBOXPtr pVBox = VBOXGetRec(pScrn);
497 uint32_t iScreen = (uintptr_t)output->driver_private;
498 return pVBox->pScreens[iScreen].afConnected
499 ? XF86OutputStatusConnected : XF86OutputStatusDisconnected;
[6484]500}
501
[53966]502static DisplayModePtr vbox_output_add_mode(VBOXPtr pVBox, DisplayModePtr *pModes, const char *pszName, int x, int y,
[54040]503 Bool isPreferred, Bool isUserDef)
[6484]504{
[50668]505 TRACE_LOG("pszName=%s, x=%d, y=%d\n", pszName ? pszName : "(null)", x, y);
[6484]506 DisplayModePtr pMode = xnfcalloc(1, sizeof(DisplayModeRec));
[54040]507 int cRefresh = 60;
[6484]508
509 pMode->status = MODE_OK;
[9826]510 /* We don't ask the host whether it likes user defined modes,
511 * as we assume that the user really wanted that mode. */
512 pMode->type = isUserDef ? M_T_USERDEF : M_T_BUILTIN;
513 if (isPreferred)
514 pMode->type |= M_T_PREFERRED;
[33460]515 /* Older versions of VBox only support screen widths which are a multiple
516 * of 8 */
517 if (pVBox->fAnyX)
518 pMode->HDisplay = x;
519 else
520 pMode->HDisplay = x & ~7;
[6484]521 pMode->HSyncStart = pMode->HDisplay + 2;
522 pMode->HSyncEnd = pMode->HDisplay + 4;
523 pMode->HTotal = pMode->HDisplay + 6;
524 pMode->VDisplay = y;
525 pMode->VSyncStart = pMode->VDisplay + 2;
526 pMode->VSyncEnd = pMode->VDisplay + 4;
527 pMode->VTotal = pMode->VDisplay + 6;
[53966]528 pMode->Clock = pMode->HTotal * pMode->VTotal * cRefresh / 1000; /* kHz */
[6484]529 if (NULL == pszName) {
530 xf86SetModeDefaultName(pMode);
531 } else {
532 pMode->name = xnfstrdup(pszName);
533 }
534 *pModes = xf86ModesAdd(*pModes, pMode);
[35775]535 return pMode;
[6484]536}
537
538static DisplayModePtr
539vbox_output_get_modes (xf86OutputPtr output)
540{
[56784]541 DisplayModePtr pModes = NULL;
[60180]542 DisplayModePtr pPreferred = NULL;
[6484]543 ScrnInfoPtr pScrn = output->scrn;
[7443]544 VBOXPtr pVBox = VBOXGetRec(pScrn);
[6484]545
[22087]546 TRACE_ENTRY();
[56211]547 uint32_t iScreen = (uintptr_t)output->driver_private;
[60180]548 pPreferred = vbox_output_add_mode(pVBox, &pModes, NULL,
[56784]549 RT_CLAMP(pVBox->pScreens[iScreen].aPreferredSize.cx, VBOX_VIDEO_MIN_SIZE, VBOX_VIDEO_MAX_VIRTUAL),
550 RT_CLAMP(pVBox->pScreens[iScreen].aPreferredSize.cy, VBOX_VIDEO_MIN_SIZE, VBOX_VIDEO_MAX_VIRTUAL),
551 TRUE, FALSE);
[56886]552 vbox_output_add_mode(pVBox, &pModes, NULL, 2560, 1600, FALSE, FALSE);
553 vbox_output_add_mode(pVBox, &pModes, NULL, 2560, 1440, FALSE, FALSE);
554 vbox_output_add_mode(pVBox, &pModes, NULL, 2048, 1536, FALSE, FALSE);
555 vbox_output_add_mode(pVBox, &pModes, NULL, 1920, 1600, FALSE, FALSE);
556 vbox_output_add_mode(pVBox, &pModes, NULL, 1920, 1080, FALSE, FALSE);
557 vbox_output_add_mode(pVBox, &pModes, NULL, 1680, 1050, FALSE, FALSE);
[56784]558 vbox_output_add_mode(pVBox, &pModes, NULL, 1600, 1200, FALSE, FALSE);
[56886]559 vbox_output_add_mode(pVBox, &pModes, NULL, 1400, 1050, FALSE, FALSE);
560 vbox_output_add_mode(pVBox, &pModes, NULL, 1280, 1024, FALSE, FALSE);
[56784]561 vbox_output_add_mode(pVBox, &pModes, NULL, 1024, 768, FALSE, FALSE);
562 vbox_output_add_mode(pVBox, &pModes, NULL, 800, 600, FALSE, FALSE);
563 vbox_output_add_mode(pVBox, &pModes, NULL, 640, 480, FALSE, FALSE);
[60180]564 VBOXEDIDSet(output, pPreferred);
[22087]565 TRACE_EXIT();
[6484]566 return pModes;
567}
568
569static const xf86OutputFuncsRec VBOXOutputFuncs = {
570 .create_resources = vbox_output_stub,
571 .dpms = vbox_output_dpms,
572 .save = NULL, /* These two are never called by the server. */
573 .restore = NULL,
574 .mode_valid = vbox_output_mode_valid,
575 .mode_fixup = vbox_output_mode_fixup,
576 .prepare = vbox_output_stub,
577 .commit = vbox_output_stub,
578 .mode_set = vbox_output_mode_set,
579 .detect = vbox_output_detect,
580 .get_modes = vbox_output_get_modes,
581#ifdef RANDR_12_INTERFACE
[52677]582 .set_property = NULL,
[6484]583#endif
584 .destroy = vbox_output_stub
585};
[34715]586#endif /* VBOXVIDEO_13 */
[6484]587
[6202]588/* Module loader interface */
589static MODULESETUPPROTO(vboxSetup);
590
591static XF86ModuleVersionInfo vboxVersionRec =
592{
593 VBOX_DRIVER_NAME,
[69065]594 "Oracle Corporation",
[6202]595 MODINFOSTRING1,
596 MODINFOSTRING2,
[34715]597#ifdef XORG_7X
[6202]598 XORG_VERSION_CURRENT,
[34715]599#else
600 XF86_VERSION_CURRENT,
601#endif
[6202]602 1, /* Module major version. Xorg-specific */
603 0, /* Module minor version. Xorg-specific */
604 1, /* Module patchlevel. Xorg-specific */
[45356]605 ABI_CLASS_VIDEODRV, /* This is a video driver */
[6202]606 ABI_VIDEODRV_VERSION,
607 MOD_CLASS_VIDEODRV,
608 {0, 0, 0, 0}
609};
610
611/*
612 * This data is accessed by the loader. The name must be the module name
613 * followed by "ModuleData".
614 */
[34715]615#ifdef XORG_7X
616_X_EXPORT
617#endif
618XF86ModuleData vboxvideoModuleData = { &vboxVersionRec, vboxSetup, NULL };
[6202]619
620static pointer
621vboxSetup(pointer Module, pointer Options, int *ErrorMajor, int *ErrorMinor)
622{
623 static Bool Initialised = FALSE;
[63221]624 RT_NOREF(Options, ErrorMinor);
[6202]625
626 if (!Initialised)
627 {
628 Initialised = TRUE;
[22084]629#ifdef PCIACCESS
[22090]630 xf86AddDriver(&VBOXVIDEO, Module, HaveDriverFuncs);
[22084]631#else
[22090]632 xf86AddDriver(&VBOXVIDEO, Module, 0);
[22084]633#endif
[34715]634#ifndef XORG_7X
635 LoaderRefSymLists(fbSymbols,
636 shadowfbSymbols,
637 ramdacSymbols,
638 vgahwSymbols,
639 NULL);
640#endif
[22090]641 xf86Msg(X_CONFIG, "Load address of symbol \"VBOXVIDEO\" is %p\n",
642 (void *)&VBOXVIDEO);
[6202]643 return (pointer)TRUE;
644 }
645
646 if (ErrorMajor)
647 *ErrorMajor = LDR_ONCEONLY;
648 return (NULL);
649}
650
651
652static const OptionInfoRec *
653VBOXAvailableOptions(int chipid, int busid)
654{
[63221]655 RT_NOREF(chipid, busid);
[6202]656 return (VBOXOptions);
657}
658
659static void
660VBOXIdentify(int flags)
661{
[63221]662 RT_NOREF(flags);
[6202]663 xf86PrintChipsets(VBOX_NAME, "guest driver for VirtualBox", VBOXChipsets);
664}
665
[43250]666#ifndef XF86_SCRN_INTERFACE
667# define SCRNINDEXAPI(pfn) pfn ## Index
[63221]668static Bool VBOXScreenInitIndex(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
669{
670 RT_NOREF(scrnIndex);
671 return VBOXScreenInit(pScreen, argc, argv);
672}
[43250]673
674static Bool VBOXEnterVTIndex(int scrnIndex, int flags)
[69066]675{ RT_NOREF(flags); return VBOXEnterVT(xf86Screens[scrnIndex]); }
[43250]676
677static void VBOXLeaveVTIndex(int scrnIndex, int flags)
[69066]678{ RT_NOREF(flags); VBOXLeaveVT(xf86Screens[scrnIndex]); }
[43250]679
680static Bool VBOXCloseScreenIndex(int scrnIndex, ScreenPtr pScreen)
[69066]681{ RT_NOREF(scrnIndex); return VBOXCloseScreen(pScreen); }
[43250]682
683static Bool VBOXSwitchModeIndex(int scrnIndex, DisplayModePtr pMode, int flags)
[69066]684{ RT_NOREF(flags); return VBOXSwitchMode(xf86Screens[scrnIndex], pMode); }
[43250]685
686static void VBOXAdjustFrameIndex(int scrnIndex, int x, int y, int flags)
[69066]687{ RT_NOREF(flags); VBOXAdjustFrame(xf86Screens[scrnIndex], x, y); }
[43250]688
689static void VBOXFreeScreenIndex(int scrnIndex, int flags)
[69066]690{ RT_NOREF(flags); VBOXFreeScreen(xf86Screens[scrnIndex]); }
[43250]691# else
692# define SCRNINDEXAPI(pfn) pfn
693#endif /* XF86_SCRN_INTERFACE */
694
695static void setScreenFunctions(ScrnInfoPtr pScrn, xf86ProbeProc pfnProbe)
696{
697 pScrn->driverVersion = VBOX_VERSION;
698 pScrn->driverName = VBOX_DRIVER_NAME;
699 pScrn->name = VBOX_NAME;
700 pScrn->Probe = pfnProbe;
701 pScrn->PreInit = VBOXPreInit;
702 pScrn->ScreenInit = SCRNINDEXAPI(VBOXScreenInit);
703 pScrn->SwitchMode = SCRNINDEXAPI(VBOXSwitchMode);
704 pScrn->AdjustFrame = SCRNINDEXAPI(VBOXAdjustFrame);
705 pScrn->EnterVT = SCRNINDEXAPI(VBOXEnterVT);
706 pScrn->LeaveVT = SCRNINDEXAPI(VBOXLeaveVT);
707 pScrn->FreeScreen = SCRNINDEXAPI(VBOXFreeScreen);
708}
709
[6202]710/*
[43250]711 * One of these functions is called once, at the start of the first server
712 * generation to do a minimal probe for supported hardware.
[6202]713 */
714
[22084]715#ifdef PCIACCESS
[6202]716static Bool
[22084]717VBOXPciProbe(DriverPtr drv, int entity_num, struct pci_device *dev,
718 intptr_t match_data)
719{
720 ScrnInfoPtr pScrn;
[63556]721 int drmFd;
[22084]722
[22087]723 TRACE_ENTRY();
[60317]724
[63556]725 drmFd = open("/dev/dri/card0", O_RDWR, 0);
726 if (drmFd >= 0)
[60317]727 {
728 xf86Msg(X_INFO, "vboxvideo: kernel driver found, not loading.\n");
[63556]729 close(drmFd);
[60317]730 return FALSE;
731 }
[63857]732 /* It is safe to call this, as the X server enables I/O access before
733 * calling the probe call-backs. */
734 if (!xf86EnableIO())
735 {
736 xf86Msg(X_INFO, "vboxvideo: this driver requires direct hardware access. You may wish to use the kernel driver instead.\n");
737 return FALSE;
738 }
[22084]739 pScrn = xf86ConfigPciEntity(NULL, 0, entity_num, VBOXPCIchipsets,
740 NULL, NULL, NULL, NULL, NULL);
741 if (pScrn != NULL) {
[43081]742 VBOXPtr pVBox;
[22084]743
[43081]744 VBOXSetRec(pScrn);
745 pVBox = VBOXGetRec(pScrn);
746 if (!pVBox)
747 return FALSE;
[43250]748 setScreenFunctions(pScrn, NULL);
[22084]749 pVBox->pciInfo = dev;
750 }
751
[69075]752 TRACE_LOG("returning %s\n", pScrn == NULL ? "false" : "true");
[22084]753 return (pScrn != NULL);
754}
755#endif
756
[22085]757#ifndef PCIACCESS
[22084]758static Bool
[6202]759VBOXProbe(DriverPtr drv, int flags)
760{
761 Bool foundScreen = FALSE;
[22084]762 int numDevSections;
[6202]763 GDevPtr *devSections;
764
765 /*
766 * Find the config file Device sections that match this
767 * driver, and return if there are none.
768 */
769 if ((numDevSections = xf86MatchDevice(VBOX_NAME,
[43250]770 &devSections)) <= 0)
771 return (FALSE);
[6202]772
773 /* PCI BUS */
[43250]774 if (xf86GetPciVideoInfo())
775 {
[22084]776 int numUsed;
777 int *usedChips;
778 int i;
[43250]779 numUsed = xf86MatchPciInstances(VBOX_NAME, VBOX_VENDORID,
780 VBOXChipsets, VBOXPCIchipsets,
781 devSections, numDevSections,
782 drv, &usedChips);
783 if (numUsed > 0)
784 {
785 if (flags & PROBE_DETECT)
786 foundScreen = TRUE;
787 else
788 for (i = 0; i < numUsed; i++)
789 {
790 ScrnInfoPtr pScrn = NULL;
791 /* Allocate a ScrnInfoRec */
792 if ((pScrn = xf86ConfigPciEntity(pScrn,0,usedChips[i],
793 VBOXPCIchipsets,NULL,
794 NULL,NULL,NULL,NULL)))
795 {
796 setScreenFunctions(pScrn, VBOXProbe);
797 foundScreen = TRUE;
798 }
799 }
800 free(usedChips);
801 }
[6202]802 }
[32164]803 free(devSections);
[6202]804 return (foundScreen);
805}
[22085]806#endif
[6202]807
[34715]808
[6202]809/*
810 * QUOTE from the XFree86 DESIGN document:
811 *
812 * The purpose of this function is to find out all the information
813 * required to determine if the configuration is usable, and to initialise
814 * those parts of the ScrnInfoRec that can be set once at the beginning of
815 * the first server generation.
816 *
817 * (...)
818 *
819 * This includes probing for video memory, clocks, ramdac, and all other
820 * HW info that is needed. It includes determining the depth/bpp/visual
821 * and related info. It includes validating and determining the set of
822 * video modes that will be used (and anything that is required to
823 * determine that).
824 *
825 * This information should be determined in the least intrusive way
826 * possible. The state of the HW must remain unchanged by this function.
827 * Although video memory (including MMIO) may be mapped within this
828 * function, it must be unmapped before returning.
829 *
830 * END QUOTE
831 */
832
833static Bool
834VBOXPreInit(ScrnInfoPtr pScrn, int flags)
835{
836 VBOXPtr pVBox;
837 Gamma gzeros = {0.0, 0.0, 0.0};
838 rgb rzeros = {0, 0, 0};
839
[34715]840 TRACE_ENTRY();
[6202]841 /* Are we really starting the server, or is this just a dummy run? */
842 if (flags & PROBE_DETECT)
843 return (FALSE);
844
[69065]845 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
846 "VirtualBox guest additions video driver version %d.%d\n",
847 VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR);
[6202]848
[34715]849 /* The ramdac module is needed for the hardware cursor. */
850 if (!xf86LoadSubModule(pScrn, "ramdac"))
851 return FALSE;
852
853 /* The framebuffer module. */
[35931]854 if (!xf86LoadSubModule(pScrn, "fb"))
[22084]855 return (FALSE);
856
[34715]857 if (!xf86LoadSubModule(pScrn, "shadowfb"))
858 return FALSE;
859
860 if (!xf86LoadSubModule(pScrn, "vgahw"))
861 return FALSE;
862
[59235]863 /* Get our private data from the ScrnInfoRec structure. */
864 VBOXSetRec(pScrn);
865 pVBox = VBOXGetRec(pScrn);
866 if (!pVBox)
867 return FALSE;
868
869 /* Entity information seems to mean bus information. */
870 pVBox->pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
871
[22084]872#ifndef PCIACCESS
[6202]873 if (pVBox->pEnt->location.type != BUS_PCI)
874 return FALSE;
875
[22084]876 pVBox->pciInfo = xf86GetPciInfoForEntity(pVBox->pEnt->index);
877 pVBox->pciTag = pciTag(pVBox->pciInfo->bus,
878 pVBox->pciInfo->device,
879 pVBox->pciInfo->func);
880#endif
881
[6202]882 /* Set up our ScrnInfoRec structure to describe our virtual
883 capabilities to X. */
884
[22084]885 pScrn->chipset = "vbox";
[35931]886 /** @note needed during colourmap initialisation */
[34715]887 pScrn->rgbBits = 8;
[6202]888
[35931]889 /* Let's create a nice, capable virtual monitor. */
[6202]890 pScrn->monitor = pScrn->confScreen->monitor;
[34715]891 pScrn->monitor->DDC = NULL;
892 pScrn->monitor->nHsync = 1;
893 pScrn->monitor->hsync[0].lo = 1;
894 pScrn->monitor->hsync[0].hi = 10000;
895 pScrn->monitor->nVrefresh = 1;
896 pScrn->monitor->vrefresh[0].lo = 1;
897 pScrn->monitor->vrefresh[0].hi = 100;
[6202]898
899 pScrn->progClock = TRUE;
900
901 /* Using the PCI information caused problems with non-powers-of-two
902 sized video RAM configurations */
[38207]903 pVBox->cbFBMax = VBoxVideoGetVRAMSize();
[35268]904 pScrn->videoRam = pVBox->cbFBMax / 1024;
[6202]905
[33460]906 /* Check if the chip restricts horizontal resolution or not. */
[38207]907 pVBox->fAnyX = VBoxVideoAnyWidthAllowed();
[33460]908
[34715]909 /* Set up clock information that will support all modes we need. */
910 pScrn->clockRanges = xnfcalloc(sizeof(ClockRange), 1);
911 pScrn->clockRanges->minClock = 1000;
912 pScrn->clockRanges->maxClock = 1000000000;
913 pScrn->clockRanges->clockIndex = -1;
914 pScrn->clockRanges->ClockMulFactor = 1;
915 pScrn->clockRanges->ClockDivFactor = 1;
916
[51242]917 if (!xf86SetDepthBpp(pScrn, 24, 0, 0, Support32bppFb))
918 return FALSE;
919 /* We only support 16 and 24 bits depth (i.e. 16 and 32bpp) */
[7168]920 if (pScrn->bitsPerPixel != 32 && pScrn->bitsPerPixel != 16)
921 {
[6202]922 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
923 "The VBox additions only support 16 and 32bpp graphics modes\n");
924 return FALSE;
925 }
926 xf86PrintDepthBpp(pScrn);
[51242]927 vboxAddModes(pScrn);
[6202]928
[34715]929#ifdef VBOXVIDEO_13
[55236]930 pScrn->virtualX = VBOX_VIDEO_MAX_VIRTUAL;
931 pScrn->virtualY = VBOX_VIDEO_MAX_VIRTUAL;
[34747]932#else
[34715]933 /* We don't validate with xf86ValidateModes and xf86PruneModes as we
934 * already know what we like and what we don't. */
[6202]935
[34715]936 pScrn->currentMode = pScrn->modes;
937
938 /* Set the right virtual resolution. */
[55392]939 pScrn->virtualX = pScrn->bitsPerPixel == 16 ? (pScrn->currentMode->HDisplay + 1) & ~1 : pScrn->currentMode->HDisplay;
[34715]940 pScrn->virtualY = pScrn->currentMode->VDisplay;
941
[34747]942#endif /* !VBOXVIDEO_13 */
943
[55392]944 pScrn->displayWidth = pScrn->virtualX;
[34715]945
946 xf86PrintModes(pScrn);
947
[35949]948 /* VGA hardware initialisation */
949 if (!vgaHWGetHWRec(pScrn))
950 return FALSE;
951 /* Must be called before any VGA registers are saved or restored */
[39695]952 vgaHWSetStdFuncs(VGAHWPTR(pScrn));
[35949]953 vgaHWGetIOBase(VGAHWPTR(pScrn));
954
[6484]955 /* Colour weight - we always call this, since we are always in
956 truecolour. */
957 if (!xf86SetWeight(pScrn, rzeros, rzeros))
958 return (FALSE);
[6202]959
[6484]960 /* visual init */
961 if (!xf86SetDefaultVisual(pScrn, -1))
962 return (FALSE);
[6202]963
[6484]964 xf86SetGamma(pScrn, gzeros);
[6202]965
[34715]966 /* Set the DPI. Perhaps we should read this from the host? */
[6484]967 xf86SetDpi(pScrn, 96, 96);
[6202]968
[35931]969 if (pScrn->memPhysBase == 0) {
970#ifdef PCIACCESS
971 pScrn->memPhysBase = pVBox->pciInfo->regions[0].base_addr;
972#else
973 pScrn->memPhysBase = pVBox->pciInfo->memBase[0];
974#endif
975 pScrn->fbOffset = 0;
976 }
[6484]977
[34715]978 TRACE_EXIT();
[6202]979 return (TRUE);
980}
981
[8531]982/**
[34715]983 * Dummy function for setting the colour palette, which we actually never
984 * touch. However, the server still requires us to provide this.
[8531]985 */
986static void
[34715]987vboxLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices,
988 LOCO *colors, VisualPtr pVisual)
[8531]989{
[69066]990 RT_NOREF(pScrn, numColors, indices, colors, pVisual);
[8531]991}
992
[57356]993/** Set the graphics and guest cursor support capabilities to the host if
994 * the user-space helper is running. */
995static void updateGraphicsCapability(ScrnInfoPtr pScrn, Bool hasVT)
[50981]996{
[57356]997 VBOXPtr pVBox = VBOXGetRec(pScrn);
[50981]998
[60083]999 if (!pVBox->fHaveHGSMIModeHints)
[55226]1000 return;
[60083]1001 VBoxHGSMISendCapsInfo(&pVBox->guestCtx, hasVT
1002 ? VBVACAPS_VIDEO_MODE_HINTS | VBVACAPS_DISABLE_CURSOR_INTEGRATION
1003 : VBVACAPS_DISABLE_CURSOR_INTEGRATION);
[50981]1004}
1005
[60115]1006#ifndef VBOXVIDEO_13
[55332]1007
[60083]1008#define PREFERRED_MODE_ATOM_NAME "VBOXVIDEO_PREFERRED_MODE"
1009
[55968]1010static void setSizesRandR11(ScrnInfoPtr pScrn)
[55332]1011{
1012 VBOXPtr pVBox = VBOXGetRec(pScrn);
1013 DisplayModePtr pNewMode;
[60083]1014 int32_t propertyValue;
[55332]1015
1016 pNewMode = pScrn->modes != pScrn->currentMode ? pScrn->modes : pScrn->modes->next;
1017 pNewMode->HDisplay = RT_CLAMP(pVBox->pScreens[0].aPreferredSize.cx, VBOX_VIDEO_MIN_SIZE, VBOX_VIDEO_MAX_VIRTUAL);
1018 pNewMode->VDisplay = RT_CLAMP(pVBox->pScreens[0].aPreferredSize.cy, VBOX_VIDEO_MIN_SIZE, VBOX_VIDEO_MAX_VIRTUAL);
[60083]1019 propertyValue = (pNewMode->HDisplay << 16) + pNewMode->VDisplay;
1020 ChangeWindowProperty(ROOT_WINDOW(pScrn), MakeAtom(PREFERRED_MODE_ATOM_NAME,
1021 sizeof(PREFERRED_MODE_ATOM_NAME) - 1, TRUE), XA_INTEGER, 32,
1022 PropModeReplace, 1, &propertyValue, TRUE);
[55332]1023}
1024
1025#endif
1026
[69078]1027static void reprobeCursor(ScrnInfoPtr pScrn)
1028{
1029 if (ROOT_WINDOW(pScrn) == NULL)
1030 return;
1031#ifdef XF86_SCRN_INTERFACE
1032 pScrn->EnableDisableFBAccess(pScrn, FALSE);
1033 pScrn->EnableDisableFBAccess(pScrn, TRUE);
1034#else
1035 pScrn->EnableDisableFBAccess(pScrn->scrnIndex, FALSE);
1036 pScrn->EnableDisableFBAccess(pScrn->scrnIndex, TRUE);
1037#endif
1038}
1039
[69064]1040static void setSizesAndCursorIntegration(ScrnInfoPtr pScrn, Bool fScreenInitTime)
[55332]1041{
[63369]1042 RT_NOREF(fScreenInitTime);
[55332]1043 TRACE_LOG("fScreenInitTime=%d\n", (int)fScreenInitTime);
1044#ifdef VBOXVIDEO_13
[60115]1045# if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 5
1046 RRGetInfo(xf86ScrnToScreen(pScrn), TRUE);
1047# else
1048 RRGetInfo(xf86ScrnToScreen(pScrn));
1049# endif
[55332]1050#else
[55968]1051 setSizesRandR11(pScrn);
[55332]1052#endif
[57092]1053 /* This calls EnableDisableFBAccess(), so only use when switched in. */
[55332]1054 if (pScrn->vtSema)
[69078]1055 reprobeCursor(pScrn);
[55332]1056}
1057
1058/* We update the size hints from the X11 property set by VBoxClient every time
1059 * that the X server goes to sleep (to catch the property change request).
1060 * Although this is far more often than necessary it should not have real-life
1061 * performance consequences and allows us to simplify the code quite a bit. */
[69082]1062static void vboxBlockHandler(pointer pData,
1063#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 23
1064 OSTimePtr pTimeout,
1065 pointer pReadmask
1066#else
1067 void *pTimeout
1068#endif
1069 )
[55332]1070{
1071 ScrnInfoPtr pScrn = (ScrnInfoPtr)pData;
[69064]1072 Bool fNeedUpdate = false;
[55332]1073
[69082]1074 RT_NOREF(pTimeout);
1075#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 23
1076 RT_NOREF(pReadmask);
1077#endif
[57356]1078 if (pScrn->vtSema)
1079 vbvxReadSizesAndCursorIntegrationFromHGSMI(pScrn, &fNeedUpdate);
[55332]1080 if (fNeedUpdate)
1081 setSizesAndCursorIntegration(pScrn, false);
1082}
1083
[6202]1084/*
1085 * QUOTE from the XFree86 DESIGN document:
1086 *
1087 * This is called at the start of each server generation.
1088 *
1089 * (...)
1090 *
1091 * Decide which operations need to be placed under resource access
1092 * control. (...) Map any video memory or other memory regions. (...)
1093 * Save the video card state. (...) Initialise the initial video
1094 * mode.
1095 *
[34715]1096 * End QUOTE.
[6202]1097 */
[43250]1098static Bool VBOXScreenInit(ScreenPtr pScreen, int argc, char **argv)
[6202]1099{
[43250]1100 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
[6202]1101 VBOXPtr pVBox = VBOXGetRec(pScrn);
1102 VisualPtr visual;
[63221]1103 RT_NOREF(argc, argv);
[6202]1104
[34715]1105 TRACE_ENTRY();
[35849]1106
[6202]1107 if (!VBOXMapVidMem(pScrn))
1108 return (FALSE);
1109
1110 /* save current video state */
[35949]1111 VBOXSaveMode(pScrn);
[6202]1112
1113 /* mi layer - reset the visual list (?)*/
1114 miClearVisualTypes();
1115 if (!miSetVisualTypes(pScrn->depth, TrueColorMask,
1116 pScrn->rgbBits, TrueColor))
1117 return (FALSE);
1118 if (!miSetPixmapDepths())
1119 return (FALSE);
1120
1121 if (!fbScreenInit(pScreen, pVBox->base,
1122 pScrn->virtualX, pScrn->virtualY,
1123 pScrn->xDpi, pScrn->yDpi,
[22091]1124 pScrn->displayWidth, pScrn->bitsPerPixel))
[6202]1125 return (FALSE);
1126
1127 /* Fixup RGB ordering */
[35931]1128 /** @note the X server uses this even in true colour. */
[6202]1129 visual = pScreen->visuals + pScreen->numVisuals;
1130 while (--visual >= pScreen->visuals) {
1131 if ((visual->class | DynamicClass) == DirectColor) {
1132 visual->offsetRed = pScrn->offset.red;
1133 visual->offsetGreen = pScrn->offset.green;
1134 visual->offsetBlue = pScrn->offset.blue;
1135 visual->redMask = pScrn->mask.red;
1136 visual->greenMask = pScrn->mask.green;
1137 visual->blueMask = pScrn->mask.blue;
1138 }
1139 }
1140
1141 /* must be after RGB ordering fixed */
1142 fbPictureInit(pScreen, 0, 0);
1143
1144 xf86SetBlackWhitePixels(pScreen);
[43245]1145 pScrn->vtSema = TRUE;
[6202]1146
[60190]1147#if defined(VBOXVIDEO_13) && defined(RT_OS_LINUX)
1148 vbvxSetUpLinuxACPI(pScreen);
1149#endif
1150
[55367]1151 if (!VBoxHGSMIIsSupported())
1152 {
1153 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Graphics device too old to support.\n");
1154 return FALSE;
1155 }
1156 vbvxSetUpHGSMIHeapInGuest(pVBox, pScrn->videoRam * 1024);
1157 pVBox->cScreens = VBoxHGSMIGetMonitorCount(&pVBox->guestCtx);
1158 pVBox->pScreens = xnfcalloc(pVBox->cScreens, sizeof(*pVBox->pScreens));
1159 pVBox->paVBVAModeHints = xnfcalloc(pVBox->cScreens, sizeof(*pVBox->paVBVAModeHints));
1160 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Requested monitor count: %u\n", pVBox->cScreens);
[51393]1161 vboxEnableVbva(pScrn);
[55358]1162 /* Set up the dirty rectangle handler. It will be added into a function
1163 * chain and gets removed when the screen is cleaned up. */
1164 if (ShadowFBInit2(pScreen, NULL, vbvxHandleDirtyRect) != TRUE)
1165 return FALSE;
[51242]1166 VBoxInitialiseSizeHints(pScrn);
[34715]1167
1168#ifdef VBOXVIDEO_13
[34747]1169 /* Initialise CRTC and output configuration for use with randr1.2. */
1170 xf86CrtcConfigInit(pScrn, &VBOXCrtcConfigFuncs);
1171
1172 {
1173 uint32_t i;
1174
1175 for (i = 0; i < pVBox->cScreens; ++i)
1176 {
1177 char szOutput[256];
1178
1179 /* Setup our virtual CRTCs. */
[52199]1180 pVBox->pScreens[i].paCrtcs = xf86CrtcCreate(pScrn, &VBOXCrtcFuncs);
1181 pVBox->pScreens[i].paCrtcs->driver_private = (void *)(uintptr_t)i;
[34747]1182
1183 /* Set up our virtual outputs. */
[49877]1184 snprintf(szOutput, sizeof(szOutput), "VGA-%u", i);
[52199]1185 pVBox->pScreens[i].paOutputs
1186 = xf86OutputCreate(pScrn, &VBOXOutputFuncs, szOutput);
[34747]1187
1188 /* We are not interested in the monitor section in the
1189 * configuration file. */
[52199]1190 xf86OutputUseScreenMonitor(pVBox->pScreens[i].paOutputs, FALSE);
1191 pVBox->pScreens[i].paOutputs->possible_crtcs = 1 << i;
1192 pVBox->pScreens[i].paOutputs->possible_clones = 0;
1193 pVBox->pScreens[i].paOutputs->driver_private = (void *)(uintptr_t)i;
[34747]1194 TRACE_LOG("Created crtc (%p) and output %s (%p)\n",
[52199]1195 (void *)pVBox->pScreens[i].paCrtcs, szOutput,
1196 (void *)pVBox->pScreens[i].paOutputs);
[34747]1197 }
1198 }
1199
[44998]1200 /* Set a sane minimum and maximum mode size to match what the hardware
1201 * supports. */
[55236]1202 xf86CrtcSetSizeRange(pScrn, VBOX_VIDEO_MIN_SIZE, VBOX_VIDEO_MIN_SIZE, VBOX_VIDEO_MAX_VIRTUAL, VBOX_VIDEO_MAX_VIRTUAL);
[34747]1203
1204 /* Now create our initial CRTC/output configuration. */
1205 if (!xf86InitialConfiguration(pScrn, TRUE)) {
1206 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Initial CRTC configuration failed!\n");
1207 return (FALSE);
1208 }
[35351]1209
[57180]1210 /* Work around a bug in the original X server modesetting code, which took
1211 * the first valid values set to these two as maxima over the server
1212 * lifetime. This bug was introduced on Feb 15 2007 and was fixed in commit
1213 * fa877d7f three months later, so it was present in X.Org Server 1.3. */
1214 pScrn->virtualX = VBOX_VIDEO_MAX_VIRTUAL;
1215 pScrn->virtualY = VBOX_VIDEO_MAX_VIRTUAL;
1216
[55384]1217 /* Initialise randr 1.2 mode-setting functions. */
[6484]1218 if (!xf86CrtcScreenInit(pScreen)) {
1219 return FALSE;
1220 }
1221
[34715]1222 /* set first video mode */
[60115]1223 if (!xf86SetDesiredModes(pScrn)) {
1224 return FALSE;
1225 }
[63221]1226#else /* !VBOXVIDEO_13 */
[55968]1227 /* set first video mode */
[57356]1228 setModeRandR11(pScrn, pScrn->currentMode, true, false, 0, 0);
[63221]1229#endif /* !VBOXVIDEO_13 */
[6484]1230
[60352]1231 /* Say that we support graphics. */
1232 updateGraphicsCapability(pScrn, TRUE);
1233
[69082]1234#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 23
1235# define WakeupHandlerProcPtr ServerWakeupHandlerProcPtr
1236#endif
1237
[55384]1238 /* Register block and wake-up handlers for getting new screen size hints. */
[57356]1239 RegisterBlockAndWakeupHandlers(vboxBlockHandler, (WakeupHandlerProcPtr)NoopDDA, (pointer)pScrn);
[55384]1240
[6202]1241 /* software cursor */
1242 miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
1243
[22091]1244 /* colourmap code */
[6202]1245 if (!miCreateDefColormap(pScreen))
[45356]1246 return (FALSE);
[6202]1247
[34715]1248 if(!xf86HandleColormaps(pScreen, 256, 8, vboxLoadPalette, NULL, 0))
[6202]1249 return (FALSE);
1250
1251 pVBox->CloseScreen = pScreen->CloseScreen;
[43250]1252 pScreen->CloseScreen = SCRNINDEXAPI(VBOXCloseScreen);
[35616]1253#ifdef VBOXVIDEO_13
1254 pScreen->SaveScreen = xf86SaveScreen;
1255#else
[34715]1256 pScreen->SaveScreen = VBOXSaveScreen;
[35616]1257#endif
[6202]1258
[35616]1259#ifdef VBOXVIDEO_13
1260 xf86DPMSInit(pScreen, xf86DPMSSet, 0);
1261#else
[6484]1262 /* We probably do want to support power management - even if we just use
1263 a dummy function. */
[34715]1264 xf86DPMSInit(pScreen, VBOXDisplayPowerManagementSet, 0);
[35616]1265#endif
[6202]1266
1267 /* Report any unused options (only for the first generation) */
1268 if (serverGeneration == 1)
1269 xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
1270
[55391]1271 if (vbvxCursorInit(pScreen) != TRUE)
[43250]1272 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
[34715]1273 "Unable to start the VirtualBox mouse pointer integration with the host system.\n");
[22087]1274
[6202]1275 return (TRUE);
1276}
1277
[57356]1278#define NO_VT_ATOM_NAME "VBOXVIDEO_NO_VT"
1279
[43250]1280static Bool VBOXEnterVT(ScrnInfoPtr pScrn)
[6202]1281{
[8531]1282 VBOXPtr pVBox = VBOXGetRec(pScrn);
[57356]1283#ifndef VBOXVIDEO_13
1284 /* If we got a mode request while we were switched out, temporarily override
1285 * the physical mode set to the device while keeping things consistent from
1286 * the server's point of view. */
1287 int cXOverRide = RT_CLAMP(pVBox->pScreens[0].aPreferredSize.cx, VBOX_VIDEO_MIN_SIZE, VBOX_VIDEO_MAX_VIRTUAL);
1288 int cYOverRide = RT_CLAMP(pVBox->pScreens[0].aPreferredSize.cy, VBOX_VIDEO_MIN_SIZE, VBOX_VIDEO_MAX_VIRTUAL);
1289#endif
[6202]1290
[22087]1291 TRACE_ENTRY();
[55369]1292 vbvxSetUpHGSMIHeapInGuest(pVBox, pScrn->videoRam * 1024);
[51393]1293 vboxEnableVbva(pScrn);
[55384]1294 /* Re-set video mode */
[55968]1295#ifdef VBOXVIDEO_13
[60115]1296 if (!xf86SetDesiredModes(pScrn)) {
1297 return FALSE;
1298 }
[55968]1299#else
[57356]1300 setModeRandR11(pScrn, pScrn->currentMode, false, true, cXOverRide, cYOverRide);
1301 DeleteProperty(ROOT_WINDOW(pScrn), MakeAtom(NO_VT_ATOM_NAME, sizeof(NO_VT_ATOM_NAME) - 1, TRUE));
[55968]1302#endif
[60352]1303 updateGraphicsCapability(pScrn, TRUE);
[34715]1304 return TRUE;
[6202]1305}
1306
[43250]1307static void VBOXLeaveVT(ScrnInfoPtr pScrn)
[6202]1308{
[63221]1309#ifdef VBOXVIDEO_13
[6202]1310 VBOXPtr pVBox = VBOXGetRec(pScrn);
[54187]1311 unsigned i;
[57356]1312#else
1313 int32_t propertyValue = 0;
[54187]1314#endif
[6202]1315
[22087]1316 TRACE_ENTRY();
[54187]1317#ifdef VBOXVIDEO_13
1318 for (i = 0; i < pVBox->cScreens; ++i)
[55334]1319 vbox_crtc_dpms(pVBox->pScreens[i].paCrtcs, DPMSModeOff);
[57356]1320#else
1321 ChangeWindowProperty(ROOT_WINDOW(pScrn), MakeAtom(NO_VT_ATOM_NAME, sizeof(NO_VT_ATOM_NAME) - 1, FALSE), XA_INTEGER, 32,
1322 PropModeReplace, 1, &propertyValue, TRUE);
[54187]1323#endif
[60352]1324 updateGraphicsCapability(pScrn, FALSE);
[51393]1325 vboxDisableVbva(pScrn);
[55450]1326 vbvxClearVRAM(pScrn, ((size_t)pScrn->virtualX) * pScrn->virtualY * (pScrn->bitsPerPixel / 8), 0);
[52865]1327 VBOXRestoreMode(pScrn);
[22087]1328 TRACE_EXIT();
[6202]1329}
1330
[43250]1331static Bool VBOXCloseScreen(ScreenPtr pScreen)
[6202]1332{
[43250]1333 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
[6202]1334 VBOXPtr pVBox = VBOXGetRec(pScrn);
[57356]1335 BOOL ret;
1336
[43245]1337 if (pScrn->vtSema)
1338 {
[54187]1339#ifdef VBOXVIDEO_13
[54197]1340 unsigned i;
[54187]1341
1342 for (i = 0; i < pVBox->cScreens; ++i)
[55334]1343 vbox_crtc_dpms(pVBox->pScreens[i].paCrtcs, DPMSModeOff);
[54187]1344#endif
[51393]1345 vboxDisableVbva(pScrn);
[55450]1346 vbvxClearVRAM(pScrn, ((size_t)pScrn->virtualX) * pScrn->virtualY * (pScrn->bitsPerPixel / 8), 0);
[43245]1347 }
[49639]1348 if (pScrn->vtSema)
[59194]1349 VBOXRestoreMode(pScrn);
1350 if (pScrn->vtSema)
[34715]1351 VBOXUnmapVidMem(pScrn);
[6202]1352 pScrn->vtSema = FALSE;
[26493]1353
[55391]1354 vbvxCursorTerm(pVBox);
[32692]1355
[6202]1356 pScreen->CloseScreen = pVBox->CloseScreen;
[60190]1357#if defined(VBOXVIDEO_13) && defined(RT_OS_LINUX)
1358 vbvxCleanUpLinuxACPI(pScreen);
1359#endif
[43250]1360#ifndef XF86_SCRN_INTERFACE
[57356]1361 ret = pScreen->CloseScreen(pScreen->myNum, pScreen);
[43250]1362#else
[57356]1363 ret = pScreen->CloseScreen(pScreen);
[43250]1364#endif
[57356]1365 return ret;
[6202]1366}
1367
[43250]1368static Bool VBOXSwitchMode(ScrnInfoPtr pScrn, DisplayModePtr pMode)
[6202]1369{
[55384]1370 Bool rc = TRUE;
[6202]1371
[22087]1372 TRACE_LOG("HDisplay=%d, VDisplay=%d\n", pMode->HDisplay, pMode->VDisplay);
[43245]1373#ifdef VBOXVIDEO_13
[52646]1374 rc = xf86SetSingleMode(pScrn, pMode, RR_Rotate_0);
[43245]1375#else
[57356]1376 setModeRandR11(pScrn, pMode, false, false, 0, 0);
[43245]1377#endif
[22087]1378 TRACE_LOG("returning %s\n", rc ? "TRUE" : "FALSE");
[8531]1379 return rc;
[6202]1380}
1381
[43250]1382static void VBOXAdjustFrame(ScrnInfoPtr pScrn, int x, int y)
[69066]1383{ RT_NOREF(pScrn, x, y); }
[6202]1384
[43250]1385static void VBOXFreeScreen(ScrnInfoPtr pScrn)
[6202]1386{
[35949]1387 /* Destroy the VGA hardware record */
1388 vgaHWFreeHWRec(pScrn);
1389 /* And our private record */
1390 free(pScrn->driverPrivate);
1391 pScrn->driverPrivate = NULL;
[6202]1392}
1393
1394static Bool
1395VBOXMapVidMem(ScrnInfoPtr pScrn)
1396{
1397 VBOXPtr pVBox = VBOXGetRec(pScrn);
[8949]1398 Bool rc = TRUE;
[6202]1399
[22087]1400 TRACE_ENTRY();
[22093]1401 if (!pVBox->base)
[8949]1402 {
[22084]1403#ifdef PCIACCESS
1404 (void) pci_device_map_range(pVBox->pciInfo,
1405 pScrn->memPhysBase,
[34715]1406 pScrn->videoRam * 1024,
[22084]1407 PCI_DEV_MAP_FLAG_WRITABLE,
1408 & pVBox->base);
1409#else
[8949]1410 pVBox->base = xf86MapPciMem(pScrn->scrnIndex,
1411 VIDMEM_FRAMEBUFFER,
[32495]1412 pVBox->pciTag, pScrn->memPhysBase,
[34715]1413 (unsigned) pScrn->videoRam * 1024);
[22093]1414#endif
[35882]1415 if (!pVBox->base)
[22093]1416 rc = FALSE;
[6202]1417 }
[22087]1418 TRACE_LOG("returning %s\n", rc ? "TRUE" : "FALSE");
[8949]1419 return rc;
[6202]1420}
1421
1422static void
1423VBOXUnmapVidMem(ScrnInfoPtr pScrn)
1424{
1425 VBOXPtr pVBox = VBOXGetRec(pScrn);
1426
[22087]1427 TRACE_ENTRY();
[6202]1428 if (pVBox->base == NULL)
1429 return;
1430
[22084]1431#ifdef PCIACCESS
1432 (void) pci_device_unmap_range(pVBox->pciInfo,
1433 pVBox->base,
[34715]1434 pScrn->videoRam * 1024);
[22084]1435#else
[6202]1436 xf86UnMapVidMem(pScrn->scrnIndex, pVBox->base,
[34715]1437 (unsigned) pScrn->videoRam * 1024);
[22084]1438#endif
[6202]1439 pVBox->base = NULL;
[22087]1440 TRACE_EXIT();
[6202]1441}
1442
[63221]1443#ifndef VBOXVIDEO_13
[34715]1444static Bool
1445VBOXSaveScreen(ScreenPtr pScreen, int mode)
1446{
[69066]1447 RT_NOREF(pScreen, mode);
[34715]1448 return TRUE;
1449}
[63221]1450#endif
[6202]1451
[35949]1452void
1453VBOXSaveMode(ScrnInfoPtr pScrn)
[6202]1454{
[35949]1455 VBOXPtr pVBox = VBOXGetRec(pScrn);
1456 vgaRegPtr vgaReg;
[6202]1457
[22087]1458 TRACE_ENTRY();
[35949]1459 vgaReg = &VGAHWPTR(pScrn)->SavedReg;
1460 vgaHWSave(pScrn, vgaReg, VGA_SR_ALL);
1461 pVBox->fSavedVBEMode = VBoxVideoGetModeRegisters(&pVBox->cSavedWidth,
1462 &pVBox->cSavedHeight,
1463 &pVBox->cSavedPitch,
1464 &pVBox->cSavedBPP,
1465 &pVBox->fSavedFlags);
1466}
[6202]1467
[35949]1468void
1469VBOXRestoreMode(ScrnInfoPtr pScrn)
1470{
1471 VBOXPtr pVBox = VBOXGetRec(pScrn);
1472 vgaRegPtr vgaReg;
[6202]1473
[35949]1474 TRACE_ENTRY();
1475 vgaReg = &VGAHWPTR(pScrn)->SavedReg;
1476 vgaHWRestore(pScrn, vgaReg, VGA_SR_ALL);
1477 if (pVBox->fSavedVBEMode)
1478 VBoxVideoSetModeRegisters(pVBox->cSavedWidth, pVBox->cSavedHeight,
1479 pVBox->cSavedPitch, pVBox->cSavedBPP,
1480 pVBox->fSavedFlags, 0, 0);
1481 else
1482 VBoxVideoDisableVBE();
[6202]1483}
[34715]1484
[63221]1485#ifndef VBOXVIDEO_13
[34715]1486static void
[63221]1487VBOXDisplayPowerManagementSet(ScrnInfoPtr pScrn, int mode, int flags)
[34715]1488{
[69066]1489 RT_NOREF(pScrn, mode, flags);
[34715]1490}
[63221]1491#endif
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use