VirtualBox

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

Last change on this file was 98103, checked in by vboxsync, 15 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
Line 
1/* $Id: vboxvideo.c 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * Linux Additions X11 graphics driver
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 * This file is based on the X.Org VESA driver:
9 *
10 * Copyright (c) 2000 by Conectiva S.A. (http://www.conectiva.com)
11 * Copyright 2008 Red Hat, Inc.
12 * Copyright 2012 Red Hat, Inc.
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,
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.
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>
38 * David Dawes <dawes@xfree86.org>
39 * Adam Jackson <ajax@redhat.com>
40 * Dave Airlie <airlied@redhat.com>
41 * Michael Thayer <michael.thayer@oracle.com>
42 */
43
44#include "vboxvideo.h"
45#include <VBoxVideoVBE.h>
46
47/* Basic definitions and functions needed by all drivers. */
48#include "xf86.h"
49/* For video memory mapping. */
50#include "xf86_OSproc.h"
51#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 6
52/* PCI resources. */
53# include "xf86Resources.h"
54#endif
55/* Generic server linear frame-buffer APIs. */
56#include "fb.h"
57/* Colormap and visual handling. */
58#include "micmap.h"
59#include "xf86cmap.h"
60/* ShadowFB support */
61#include "shadowfb.h"
62/* VGA hardware functions for setting and restoring text mode */
63#include "vgaHW.h"
64#ifdef VBOXVIDEO_13
65/* X.org 1.3+ mode setting */
66# define _HAVE_STRING_ARCH_strsep /* bits/string2.h, __strsep_1c. */
67# include "xf86Crtc.h"
68# include "xf86Modes.h"
69/* For xf86RandR12GetOriginalVirtualSize(). */
70# include "xf86RandR12.h"
71#endif
72/* For setting the root window property. */
73#include "property.h"
74#include <X11/Xatom.h>
75
76#ifdef XORG_7X
77# include <stdlib.h>
78# include <string.h>
79# include <fcntl.h>
80# include <unistd.h>
81#endif
82
83/* Mandatory functions */
84
85static const OptionInfoRec * VBOXAvailableOptions(int chipid, int busid);
86static void VBOXIdentify(int flags);
87#ifndef PCIACCESS
88static Bool VBOXProbe(DriverPtr drv, int flags);
89#else
90static Bool VBOXPciProbe(DriverPtr drv, int entity_num,
91 struct pci_device *dev, intptr_t match_data);
92#endif
93static Bool VBOXPreInit(ScrnInfoPtr pScrn, int flags);
94static Bool VBOXScreenInit(ScreenPtr pScreen, int argc, char **argv);
95static Bool VBOXEnterVT(ScrnInfoPtr pScrn);
96static void VBOXLeaveVT(ScrnInfoPtr pScrn);
97static Bool VBOXCloseScreen(ScreenPtr pScreen);
98#ifndef VBOXVIDEO_13
99static Bool VBOXSaveScreen(ScreenPtr pScreen, int mode);
100#endif
101static Bool VBOXSwitchMode(ScrnInfoPtr pScrn, DisplayModePtr pMode);
102static void VBOXAdjustFrame(ScrnInfoPtr pScrn, int x, int y);
103static void VBOXFreeScreen(ScrnInfoPtr pScrn);
104#ifndef VBOXVIDEO_13
105static void VBOXDisplayPowerManagementSet(ScrnInfoPtr pScrn, int mode, int flags);
106#endif
107
108/* locally used functions */
109static Bool VBOXMapVidMem(ScrnInfoPtr pScrn);
110static void VBOXUnmapVidMem(ScrnInfoPtr pScrn);
111static void VBOXSaveMode(ScrnInfoPtr pScrn);
112static void VBOXRestoreMode(ScrnInfoPtr pScrn);
113static void setSizesAndCursorIntegration(ScrnInfoPtr pScrn, Bool fScreenInitTime);
114
115#ifndef XF86_SCRN_INTERFACE
116# define xf86ScreenToScrn(pScreen) xf86Screens[(pScreen)->myNum]
117# define xf86ScrnToScreen(pScrn) screenInfo.screens[(pScrn)->scrnIndex]
118#endif
119
120static inline void VBOXSetRec(ScrnInfoPtr pScrn)
121{
122 if (!pScrn->driverPrivate)
123 {
124 VBOXPtr pVBox = (VBOXPtr)xnfcalloc(sizeof(VBOXRec), 1);
125 pScrn->driverPrivate = pVBox;
126#if defined(VBOXVIDEO_13) && defined(RT_OS_LINUX)
127 pVBox->fdACPIDevices = -1;
128#endif
129 }
130}
131
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"},
152 {-1, NULL}
153};
154
155static PciChipsets VBOXPCIchipsets[] = {
156 { VBOX_DEVICEID, VBOX_DEVICEID, RES_SHARED_VGA },
157 { -1, -1, RES_UNDEFINED },
158};
159
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
163 * the Module Setup function in the dynamic case. In the static case a
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
168#ifdef XORG_7X
169_X_EXPORT
170#endif
171DriverRec VBOXVIDEO = {
172 VBOX_VERSION,
173 VBOX_DRIVER_NAME,
174 VBOXIdentify,
175#ifdef PCIACCESS
176 NULL,
177#else
178 VBOXProbe,
179#endif
180 VBOXAvailableOptions,
181 NULL,
182 0,
183#ifdef XORG_7X
184 NULL,
185#endif
186#ifdef PCIACCESS
187 vbox_device_match,
188 VBOXPciProbe
189#endif
190};
191
192/* No options for now */
193static const OptionInfoRec VBOXOptions[] = {
194 { -1, NULL, OPTV_NONE, {0}, FALSE }
195};
196
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[] = {
213 "ShadowFBInit2",
214 NULL
215};
216
217static const char *ramdacSymbols[] = {
218 "xf86DestroyCursorInfoRec",
219 "xf86InitCursor",
220 "xf86CreateCursorInfoRec",
221 NULL
222};
223
224static const char *vgahwSymbols[] = {
225 "vgaHWFreeHWRec",
226 "vgaHWGetHWRec",
227 "vgaHWGetIOBase",
228 "vgaHWGetIndex",
229 "vgaHWRestore",
230 "vgaHWSave",
231 "vgaHWSetStdFuncs",
232 NULL
233};
234#endif /* !XORG_7X */
235
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);
246 AssertMsg(width >= 0 && height >= 0, ("Invalid negative width (%d) or height (%d)\n", width, height));
247 if (pScreen == NULL) /* Not yet initialised. */
248 return TRUE;
249 pPixmap = pScreen->GetScreenPixmap(pScreen);
250 AssertMsg(pPixmap != NULL, ("Failed to get the screen pixmap.\n"));
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",
252 (void *)pPixmap, adjustedWidth, height, pScrn->depth,
253 pScrn->bitsPerPixel, cbLine, pVBox->base,
254 pPixmap->drawable.width, pPixmap->drawable.height);
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 }
266 if (pScrn->vtSema)
267 vbvxClearVRAM(pScrn, ((size_t)pScrn->virtualX) * pScrn->virtualY * (pScrn->bitsPerPixel / 8),
268 ((size_t)adjustedWidth) * height * (pScrn->bitsPerPixel / 8));
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
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-
285 * buffer matching what the X server expects. */
286static void setModeRandR11(ScrnInfoPtr pScrn, DisplayModePtr pMode, Bool fScreenInitTime, Bool fEnterVTTime,
287 int cXOverRide, int cYOverRide)
288{
289 VBOXPtr pVBox = VBOXGetRec(pScrn);
290 struct vbvxFrameBuffer frameBuffer = { 0, 0, pMode->HDisplay, pMode->VDisplay, pScrn->bitsPerPixel};
291 int cXPhysical = cXOverRide > 0 ? min(cXOverRide, pMode->HDisplay) : pMode->HDisplay;
292 int cYPhysical = cYOverRide > 0 ? min(cYOverRide, pMode->VDisplay) : pMode->VDisplay;
293
294 pVBox->pScreens[0].aScreenLocation.cx = pMode->HDisplay;
295 pVBox->pScreens[0].aScreenLocation.cy = pMode->VDisplay;
296 if (fScreenInitTime)
297 {
298 /* The screen structure is not fully set up yet, so do not touch it. */
299 pScrn->displayWidth = pScrn->virtualX = pMode->HDisplay;
300 pScrn->virtualY = pMode->VDisplay;
301 }
302 else
303 {
304 xf86ScrnToScreen(pScrn)->width = pMode->HDisplay;
305 xf86ScrnToScreen(pScrn)->height = pMode->VDisplay;
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;
313 adjustScreenPixmap(pScrn, pMode->HDisplay, pMode->VDisplay);
314 if (fEnterVTTime)
315 pScrn->vtSema = TRUE;
316 }
317 if (pMode->HDisplay != 0 && pMode->VDisplay != 0 && pScrn->vtSema)
318 vbvxSetMode(pScrn, 0, cXPhysical, cYPhysical, 0, 0, true, true, &frameBuffer);
319 pScrn->currentMode = pMode;
320}
321#endif
322
323#ifdef VBOXVIDEO_13
324/* X.org 1.3+ mode-setting support ******************************************/
325
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;
339 int originalX, originalY;
340
341 /* Check that this code cannot trigger the resizing bug in X.Org Server 1.3.
342 * See the work-around in ScreenInit. */
343 xf86RandR12GetOriginalVirtualSize(pScrn, &originalX, &originalY);
344 AssertMsg(originalX == VBOX_VIDEO_MAX_VIRTUAL && originalY == VBOX_VIDEO_MAX_VIRTUAL, ("OriginalSize=%dx%d",
345 originalX, originalY));
346 for (i = cFirst; i < cLast; ++i)
347 if (pVBox->pScreens[i].paCrtcs->mode.HDisplay != 0 && pVBox->pScreens[i].paCrtcs->mode.VDisplay != 0 && pScrn->vtSema)
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
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
364static Bool vbox_config_resize(ScrnInfoPtr pScrn, int cw, int ch)
365{
366 VBOXPtr pVBox = VBOXGetRec(pScrn);
367 Bool rc;
368 unsigned i;
369
370 TRACE_LOG("width=%d, height=%d\n", cw, ch);
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;
378}
379
380static const xf86CrtcConfigFuncsRec VBOXCrtcConfigFuncs = {
381 vbox_config_resize
382};
383
384static void
385vbox_crtc_dpms(xf86CrtcPtr crtc, int mode)
386{
387 ScrnInfoPtr pScrn = crtc->scrn;
388 VBOXPtr pVBox = VBOXGetRec(pScrn);
389 unsigned cDisplay = (uintptr_t)crtc->driver_private;
390
391 TRACE_LOG("mode=%d\n", mode);
392 pVBox->pScreens[cDisplay].fPowerOn = (mode != DPMSModeOff);
393 setModeRandR12(pScrn, cDisplay);
394}
395
396static Bool
397vbox_crtc_lock (xf86CrtcPtr crtc)
398{ RT_NOREF(crtc); return FALSE; }
399
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. */
407static Bool
408vbox_crtc_mode_fixup (xf86CrtcPtr crtc, DisplayModePtr mode,
409 DisplayModePtr adjusted_mode)
410{ RT_NOREF(crtc, mode, adjusted_mode); return TRUE; }
411
412static void
413vbox_crtc_stub (xf86CrtcPtr crtc)
414{ RT_NOREF(crtc); }
415
416static void
417vbox_crtc_mode_set (xf86CrtcPtr crtc, DisplayModePtr mode,
418 DisplayModePtr adjusted_mode, int x, int y)
419{
420 RT_NOREF(mode);
421 VBOXPtr pVBox = VBOXGetRec(crtc->scrn);
422 unsigned cDisplay = (uintptr_t)crtc->driver_private;
423
424 TRACE_LOG("name=%s, HDisplay=%d, VDisplay=%d, x=%d, y=%d\n", adjusted_mode->name,
425 adjusted_mode->HDisplay, adjusted_mode->VDisplay, x, y);
426 pVBox->pScreens[cDisplay].fPowerOn = true;
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;
431 setModeRandR12(crtc->scrn, cDisplay);
432}
433
434static void
435vbox_crtc_gamma_set (xf86CrtcPtr crtc, CARD16 *red,
436 CARD16 *green, CARD16 *blue, int size)
437{ RT_NOREF(crtc, red, green, blue, size); }
438
439static void *
440vbox_crtc_shadow_allocate (xf86CrtcPtr crtc, int width, int height)
441{ RT_NOREF(crtc, width, height); return NULL; }
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)
468{ RT_NOREF(output); }
469
470static void
471vbox_output_dpms (xf86OutputPtr output, int mode)
472{
473 RT_NOREF(output, mode);
474}
475
476static int
477vbox_output_mode_valid (xf86OutputPtr output, DisplayModePtr mode)
478{
479 return MODE_OK;
480}
481
482static Bool
483vbox_output_mode_fixup (xf86OutputPtr output, DisplayModePtr mode,
484 DisplayModePtr adjusted_mode)
485{ RT_NOREF(output, mode, adjusted_mode); return TRUE; }
486
487static void
488vbox_output_mode_set (xf86OutputPtr output, DisplayModePtr mode,
489 DisplayModePtr adjusted_mode)
490{ RT_NOREF(output, mode, adjusted_mode); }
491
492static xf86OutputStatus
493vbox_output_detect (xf86OutputPtr output)
494{
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;
500}
501
502static DisplayModePtr vbox_output_add_mode(VBOXPtr pVBox, DisplayModePtr *pModes, const char *pszName, int x, int y,
503 Bool isPreferred, Bool isUserDef)
504{
505 TRACE_LOG("pszName=%s, x=%d, y=%d\n", pszName ? pszName : "(null)", x, y);
506 DisplayModePtr pMode = xnfcalloc(1, sizeof(DisplayModeRec));
507 int cRefresh = 60;
508
509 pMode->status = MODE_OK;
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;
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;
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;
528 pMode->Clock = pMode->HTotal * pMode->VTotal * cRefresh / 1000; /* kHz */
529 if (NULL == pszName) {
530 xf86SetModeDefaultName(pMode);
531 } else {
532 pMode->name = xnfstrdup(pszName);
533 }
534 *pModes = xf86ModesAdd(*pModes, pMode);
535 return pMode;
536}
537
538static DisplayModePtr
539vbox_output_get_modes (xf86OutputPtr output)
540{
541 DisplayModePtr pModes = NULL;
542 DisplayModePtr pPreferred = NULL;
543 ScrnInfoPtr pScrn = output->scrn;
544 VBOXPtr pVBox = VBOXGetRec(pScrn);
545
546 TRACE_ENTRY();
547 uint32_t iScreen = (uintptr_t)output->driver_private;
548 pPreferred = vbox_output_add_mode(pVBox, &pModes, NULL,
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);
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);
558 vbox_output_add_mode(pVBox, &pModes, NULL, 1600, 1200, FALSE, FALSE);
559 vbox_output_add_mode(pVBox, &pModes, NULL, 1400, 1050, FALSE, FALSE);
560 vbox_output_add_mode(pVBox, &pModes, NULL, 1280, 1024, FALSE, FALSE);
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);
564 VBOXEDIDSet(output, pPreferred);
565 TRACE_EXIT();
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
582 .set_property = NULL,
583#endif
584 .destroy = vbox_output_stub
585};
586#endif /* VBOXVIDEO_13 */
587
588/* Module loader interface */
589static MODULESETUPPROTO(vboxSetup);
590
591static XF86ModuleVersionInfo vboxVersionRec =
592{
593 VBOX_DRIVER_NAME,
594 "Oracle Corporation",
595 MODINFOSTRING1,
596 MODINFOSTRING2,
597#ifdef XORG_7X
598 XORG_VERSION_CURRENT,
599#else
600 XF86_VERSION_CURRENT,
601#endif
602 1, /* Module major version. Xorg-specific */
603 0, /* Module minor version. Xorg-specific */
604 1, /* Module patchlevel. Xorg-specific */
605 ABI_CLASS_VIDEODRV, /* This is a video driver */
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 */
615#ifdef XORG_7X
616_X_EXPORT
617#endif
618XF86ModuleData vboxvideoModuleData = { &vboxVersionRec, vboxSetup, NULL };
619
620static pointer
621vboxSetup(pointer Module, pointer Options, int *ErrorMajor, int *ErrorMinor)
622{
623 static Bool Initialised = FALSE;
624 RT_NOREF(Options, ErrorMinor);
625
626 if (!Initialised)
627 {
628 Initialised = TRUE;
629#ifdef PCIACCESS
630 xf86AddDriver(&VBOXVIDEO, Module, HaveDriverFuncs);
631#else
632 xf86AddDriver(&VBOXVIDEO, Module, 0);
633#endif
634#ifndef XORG_7X
635 LoaderRefSymLists(fbSymbols,
636 shadowfbSymbols,
637 ramdacSymbols,
638 vgahwSymbols,
639 NULL);
640#endif
641 xf86Msg(X_CONFIG, "Load address of symbol \"VBOXVIDEO\" is %p\n",
642 (void *)&VBOXVIDEO);
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{
655 RT_NOREF(chipid, busid);
656 return (VBOXOptions);
657}
658
659static void
660VBOXIdentify(int flags)
661{
662 RT_NOREF(flags);
663 xf86PrintChipsets(VBOX_NAME, "guest driver for VirtualBox", VBOXChipsets);
664}
665
666#ifndef XF86_SCRN_INTERFACE
667# define SCRNINDEXAPI(pfn) pfn ## Index
668static Bool VBOXScreenInitIndex(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
669{
670 RT_NOREF(scrnIndex);
671 return VBOXScreenInit(pScreen, argc, argv);
672}
673
674static Bool VBOXEnterVTIndex(int scrnIndex, int flags)
675{ RT_NOREF(flags); return VBOXEnterVT(xf86Screens[scrnIndex]); }
676
677static void VBOXLeaveVTIndex(int scrnIndex, int flags)
678{ RT_NOREF(flags); VBOXLeaveVT(xf86Screens[scrnIndex]); }
679
680static Bool VBOXCloseScreenIndex(int scrnIndex, ScreenPtr pScreen)
681{ RT_NOREF(scrnIndex); return VBOXCloseScreen(pScreen); }
682
683static Bool VBOXSwitchModeIndex(int scrnIndex, DisplayModePtr pMode, int flags)
684{ RT_NOREF(flags); return VBOXSwitchMode(xf86Screens[scrnIndex], pMode); }
685
686static void VBOXAdjustFrameIndex(int scrnIndex, int x, int y, int flags)
687{ RT_NOREF(flags); VBOXAdjustFrame(xf86Screens[scrnIndex], x, y); }
688
689static void VBOXFreeScreenIndex(int scrnIndex, int flags)
690{ RT_NOREF(flags); VBOXFreeScreen(xf86Screens[scrnIndex]); }
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
710/*
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.
713 */
714
715#ifdef PCIACCESS
716static Bool
717VBOXPciProbe(DriverPtr drv, int entity_num, struct pci_device *dev,
718 intptr_t match_data)
719{
720 ScrnInfoPtr pScrn;
721 int drmFd;
722
723 TRACE_ENTRY();
724
725 drmFd = open("/dev/dri/card0", O_RDWR, 0);
726 if (drmFd >= 0)
727 {
728 xf86Msg(X_INFO, "vboxvideo: kernel driver found, not loading.\n");
729 close(drmFd);
730 return FALSE;
731 }
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 }
739 pScrn = xf86ConfigPciEntity(NULL, 0, entity_num, VBOXPCIchipsets,
740 NULL, NULL, NULL, NULL, NULL);
741 if (pScrn != NULL) {
742 VBOXPtr pVBox;
743
744 VBOXSetRec(pScrn);
745 pVBox = VBOXGetRec(pScrn);
746 if (!pVBox)
747 return FALSE;
748 setScreenFunctions(pScrn, NULL);
749 pVBox->pciInfo = dev;
750 }
751
752 TRACE_LOG("returning %s\n", pScrn == NULL ? "false" : "true");
753 return (pScrn != NULL);
754}
755#endif
756
757#ifndef PCIACCESS
758static Bool
759VBOXProbe(DriverPtr drv, int flags)
760{
761 Bool foundScreen = FALSE;
762 int numDevSections;
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,
770 &devSections)) <= 0)
771 return (FALSE);
772
773 /* PCI BUS */
774 if (xf86GetPciVideoInfo())
775 {
776 int numUsed;
777 int *usedChips;
778 int i;
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 }
802 }
803 free(devSections);
804 return (foundScreen);
805}
806#endif
807
808
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
840 TRACE_ENTRY();
841 /* Are we really starting the server, or is this just a dummy run? */
842 if (flags & PROBE_DETECT)
843 return (FALSE);
844
845 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
846 "VirtualBox guest additions video driver version %d.%d\n",
847 VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR);
848
849 /* The ramdac module is needed for the hardware cursor. */
850 if (!xf86LoadSubModule(pScrn, "ramdac"))
851 return FALSE;
852
853 /* The framebuffer module. */
854 if (!xf86LoadSubModule(pScrn, "fb"))
855 return (FALSE);
856
857 if (!xf86LoadSubModule(pScrn, "shadowfb"))
858 return FALSE;
859
860 if (!xf86LoadSubModule(pScrn, "vgahw"))
861 return FALSE;
862
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
872#ifndef PCIACCESS
873 if (pVBox->pEnt->location.type != BUS_PCI)
874 return FALSE;
875
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
882 /* Set up our ScrnInfoRec structure to describe our virtual
883 capabilities to X. */
884
885 pScrn->chipset = "vbox";
886 /** @note needed during colourmap initialisation */
887 pScrn->rgbBits = 8;
888
889 /* Let's create a nice, capable virtual monitor. */
890 pScrn->monitor = pScrn->confScreen->monitor;
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;
898
899 pScrn->progClock = TRUE;
900
901 /* Using the PCI information caused problems with non-powers-of-two
902 sized video RAM configurations */
903 pVBox->cbFBMax = VBoxVideoGetVRAMSize();
904 pScrn->videoRam = pVBox->cbFBMax / 1024;
905
906 /* Check if the chip restricts horizontal resolution or not. */
907 pVBox->fAnyX = VBoxVideoAnyWidthAllowed();
908
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
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) */
920 if (pScrn->bitsPerPixel != 32 && pScrn->bitsPerPixel != 16)
921 {
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);
927 vboxAddModes(pScrn);
928
929#ifdef VBOXVIDEO_13
930 pScrn->virtualX = VBOX_VIDEO_MAX_VIRTUAL;
931 pScrn->virtualY = VBOX_VIDEO_MAX_VIRTUAL;
932#else
933 /* We don't validate with xf86ValidateModes and xf86PruneModes as we
934 * already know what we like and what we don't. */
935
936 pScrn->currentMode = pScrn->modes;
937
938 /* Set the right virtual resolution. */
939 pScrn->virtualX = pScrn->bitsPerPixel == 16 ? (pScrn->currentMode->HDisplay + 1) & ~1 : pScrn->currentMode->HDisplay;
940 pScrn->virtualY = pScrn->currentMode->VDisplay;
941
942#endif /* !VBOXVIDEO_13 */
943
944 pScrn->displayWidth = pScrn->virtualX;
945
946 xf86PrintModes(pScrn);
947
948 /* VGA hardware initialisation */
949 if (!vgaHWGetHWRec(pScrn))
950 return FALSE;
951 /* Must be called before any VGA registers are saved or restored */
952 vgaHWSetStdFuncs(VGAHWPTR(pScrn));
953 vgaHWGetIOBase(VGAHWPTR(pScrn));
954
955 /* Colour weight - we always call this, since we are always in
956 truecolour. */
957 if (!xf86SetWeight(pScrn, rzeros, rzeros))
958 return (FALSE);
959
960 /* visual init */
961 if (!xf86SetDefaultVisual(pScrn, -1))
962 return (FALSE);
963
964 xf86SetGamma(pScrn, gzeros);
965
966 /* Set the DPI. Perhaps we should read this from the host? */
967 xf86SetDpi(pScrn, 96, 96);
968
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 }
977
978 TRACE_EXIT();
979 return (TRUE);
980}
981
982/**
983 * Dummy function for setting the colour palette, which we actually never
984 * touch. However, the server still requires us to provide this.
985 */
986static void
987vboxLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices,
988 LOCO *colors, VisualPtr pVisual)
989{
990 RT_NOREF(pScrn, numColors, indices, colors, pVisual);
991}
992
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)
996{
997 VBOXPtr pVBox = VBOXGetRec(pScrn);
998
999 if (!pVBox->fHaveHGSMIModeHints)
1000 return;
1001 VBoxHGSMISendCapsInfo(&pVBox->guestCtx, hasVT
1002 ? VBVACAPS_VIDEO_MODE_HINTS | VBVACAPS_DISABLE_CURSOR_INTEGRATION
1003 : VBVACAPS_DISABLE_CURSOR_INTEGRATION);
1004}
1005
1006#ifndef VBOXVIDEO_13
1007
1008#define PREFERRED_MODE_ATOM_NAME "VBOXVIDEO_PREFERRED_MODE"
1009
1010static void setSizesRandR11(ScrnInfoPtr pScrn)
1011{
1012 VBOXPtr pVBox = VBOXGetRec(pScrn);
1013 DisplayModePtr pNewMode;
1014 int32_t propertyValue;
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);
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);
1023}
1024
1025#endif
1026
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
1040static void setSizesAndCursorIntegration(ScrnInfoPtr pScrn, Bool fScreenInitTime)
1041{
1042 RT_NOREF(fScreenInitTime);
1043 TRACE_LOG("fScreenInitTime=%d\n", (int)fScreenInitTime);
1044#ifdef VBOXVIDEO_13
1045# if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 5
1046 RRGetInfo(xf86ScrnToScreen(pScrn), TRUE);
1047# else
1048 RRGetInfo(xf86ScrnToScreen(pScrn));
1049# endif
1050#else
1051 setSizesRandR11(pScrn);
1052#endif
1053 /* This calls EnableDisableFBAccess(), so only use when switched in. */
1054 if (pScrn->vtSema)
1055 reprobeCursor(pScrn);
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. */
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 )
1070{
1071 ScrnInfoPtr pScrn = (ScrnInfoPtr)pData;
1072 Bool fNeedUpdate = false;
1073
1074 RT_NOREF(pTimeout);
1075#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 23
1076 RT_NOREF(pReadmask);
1077#endif
1078 if (pScrn->vtSema)
1079 vbvxReadSizesAndCursorIntegrationFromHGSMI(pScrn, &fNeedUpdate);
1080 if (fNeedUpdate)
1081 setSizesAndCursorIntegration(pScrn, false);
1082}
1083
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 *
1096 * End QUOTE.
1097 */
1098static Bool VBOXScreenInit(ScreenPtr pScreen, int argc, char **argv)
1099{
1100 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1101 VBOXPtr pVBox = VBOXGetRec(pScrn);
1102 VisualPtr visual;
1103 RT_NOREF(argc, argv);
1104
1105 TRACE_ENTRY();
1106
1107 if (!VBOXMapVidMem(pScrn))
1108 return (FALSE);
1109
1110 /* save current video state */
1111 VBOXSaveMode(pScrn);
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,
1124 pScrn->displayWidth, pScrn->bitsPerPixel))
1125 return (FALSE);
1126
1127 /* Fixup RGB ordering */
1128 /** @note the X server uses this even in true colour. */
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);
1145 pScrn->vtSema = TRUE;
1146
1147#if defined(VBOXVIDEO_13) && defined(RT_OS_LINUX)
1148 vbvxSetUpLinuxACPI(pScreen);
1149#endif
1150
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);
1161 vboxEnableVbva(pScrn);
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;
1166 VBoxInitialiseSizeHints(pScrn);
1167
1168#ifdef VBOXVIDEO_13
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. */
1180 pVBox->pScreens[i].paCrtcs = xf86CrtcCreate(pScrn, &VBOXCrtcFuncs);
1181 pVBox->pScreens[i].paCrtcs->driver_private = (void *)(uintptr_t)i;
1182
1183 /* Set up our virtual outputs. */
1184 snprintf(szOutput, sizeof(szOutput), "VGA-%u", i);
1185 pVBox->pScreens[i].paOutputs
1186 = xf86OutputCreate(pScrn, &VBOXOutputFuncs, szOutput);
1187
1188 /* We are not interested in the monitor section in the
1189 * configuration file. */
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;
1194 TRACE_LOG("Created crtc (%p) and output %s (%p)\n",
1195 (void *)pVBox->pScreens[i].paCrtcs, szOutput,
1196 (void *)pVBox->pScreens[i].paOutputs);
1197 }
1198 }
1199
1200 /* Set a sane minimum and maximum mode size to match what the hardware
1201 * supports. */
1202 xf86CrtcSetSizeRange(pScrn, VBOX_VIDEO_MIN_SIZE, VBOX_VIDEO_MIN_SIZE, VBOX_VIDEO_MAX_VIRTUAL, VBOX_VIDEO_MAX_VIRTUAL);
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 }
1209
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
1217 /* Initialise randr 1.2 mode-setting functions. */
1218 if (!xf86CrtcScreenInit(pScreen)) {
1219 return FALSE;
1220 }
1221
1222 /* set first video mode */
1223 if (!xf86SetDesiredModes(pScrn)) {
1224 return FALSE;
1225 }
1226#else /* !VBOXVIDEO_13 */
1227 /* set first video mode */
1228 setModeRandR11(pScrn, pScrn->currentMode, true, false, 0, 0);
1229#endif /* !VBOXVIDEO_13 */
1230
1231 /* Say that we support graphics. */
1232 updateGraphicsCapability(pScrn, TRUE);
1233
1234#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 23
1235# define WakeupHandlerProcPtr ServerWakeupHandlerProcPtr
1236#endif
1237
1238 /* Register block and wake-up handlers for getting new screen size hints. */
1239 RegisterBlockAndWakeupHandlers(vboxBlockHandler, (WakeupHandlerProcPtr)NoopDDA, (pointer)pScrn);
1240
1241 /* software cursor */
1242 miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
1243
1244 /* colourmap code */
1245 if (!miCreateDefColormap(pScreen))
1246 return (FALSE);
1247
1248 if(!xf86HandleColormaps(pScreen, 256, 8, vboxLoadPalette, NULL, 0))
1249 return (FALSE);
1250
1251 pVBox->CloseScreen = pScreen->CloseScreen;
1252 pScreen->CloseScreen = SCRNINDEXAPI(VBOXCloseScreen);
1253#ifdef VBOXVIDEO_13
1254 pScreen->SaveScreen = xf86SaveScreen;
1255#else
1256 pScreen->SaveScreen = VBOXSaveScreen;
1257#endif
1258
1259#ifdef VBOXVIDEO_13
1260 xf86DPMSInit(pScreen, xf86DPMSSet, 0);
1261#else
1262 /* We probably do want to support power management - even if we just use
1263 a dummy function. */
1264 xf86DPMSInit(pScreen, VBOXDisplayPowerManagementSet, 0);
1265#endif
1266
1267 /* Report any unused options (only for the first generation) */
1268 if (serverGeneration == 1)
1269 xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
1270
1271 if (vbvxCursorInit(pScreen) != TRUE)
1272 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1273 "Unable to start the VirtualBox mouse pointer integration with the host system.\n");
1274
1275 return (TRUE);
1276}
1277
1278#define NO_VT_ATOM_NAME "VBOXVIDEO_NO_VT"
1279
1280static Bool VBOXEnterVT(ScrnInfoPtr pScrn)
1281{
1282 VBOXPtr pVBox = VBOXGetRec(pScrn);
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
1290
1291 TRACE_ENTRY();
1292 vbvxSetUpHGSMIHeapInGuest(pVBox, pScrn->videoRam * 1024);
1293 vboxEnableVbva(pScrn);
1294 /* Re-set video mode */
1295#ifdef VBOXVIDEO_13
1296 if (!xf86SetDesiredModes(pScrn)) {
1297 return FALSE;
1298 }
1299#else
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));
1302#endif
1303 updateGraphicsCapability(pScrn, TRUE);
1304 return TRUE;
1305}
1306
1307static void VBOXLeaveVT(ScrnInfoPtr pScrn)
1308{
1309#ifdef VBOXVIDEO_13
1310 VBOXPtr pVBox = VBOXGetRec(pScrn);
1311 unsigned i;
1312#else
1313 int32_t propertyValue = 0;
1314#endif
1315
1316 TRACE_ENTRY();
1317#ifdef VBOXVIDEO_13
1318 for (i = 0; i < pVBox->cScreens; ++i)
1319 vbox_crtc_dpms(pVBox->pScreens[i].paCrtcs, DPMSModeOff);
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);
1323#endif
1324 updateGraphicsCapability(pScrn, FALSE);
1325 vboxDisableVbva(pScrn);
1326 vbvxClearVRAM(pScrn, ((size_t)pScrn->virtualX) * pScrn->virtualY * (pScrn->bitsPerPixel / 8), 0);
1327 VBOXRestoreMode(pScrn);
1328 TRACE_EXIT();
1329}
1330
1331static Bool VBOXCloseScreen(ScreenPtr pScreen)
1332{
1333 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1334 VBOXPtr pVBox = VBOXGetRec(pScrn);
1335 BOOL ret;
1336
1337 if (pScrn->vtSema)
1338 {
1339#ifdef VBOXVIDEO_13
1340 unsigned i;
1341
1342 for (i = 0; i < pVBox->cScreens; ++i)
1343 vbox_crtc_dpms(pVBox->pScreens[i].paCrtcs, DPMSModeOff);
1344#endif
1345 vboxDisableVbva(pScrn);
1346 vbvxClearVRAM(pScrn, ((size_t)pScrn->virtualX) * pScrn->virtualY * (pScrn->bitsPerPixel / 8), 0);
1347 }
1348 if (pScrn->vtSema)
1349 VBOXRestoreMode(pScrn);
1350 if (pScrn->vtSema)
1351 VBOXUnmapVidMem(pScrn);
1352 pScrn->vtSema = FALSE;
1353
1354 vbvxCursorTerm(pVBox);
1355
1356 pScreen->CloseScreen = pVBox->CloseScreen;
1357#if defined(VBOXVIDEO_13) && defined(RT_OS_LINUX)
1358 vbvxCleanUpLinuxACPI(pScreen);
1359#endif
1360#ifndef XF86_SCRN_INTERFACE
1361 ret = pScreen->CloseScreen(pScreen->myNum, pScreen);
1362#else
1363 ret = pScreen->CloseScreen(pScreen);
1364#endif
1365 return ret;
1366}
1367
1368static Bool VBOXSwitchMode(ScrnInfoPtr pScrn, DisplayModePtr pMode)
1369{
1370 Bool rc = TRUE;
1371
1372 TRACE_LOG("HDisplay=%d, VDisplay=%d\n", pMode->HDisplay, pMode->VDisplay);
1373#ifdef VBOXVIDEO_13
1374 rc = xf86SetSingleMode(pScrn, pMode, RR_Rotate_0);
1375#else
1376 setModeRandR11(pScrn, pMode, false, false, 0, 0);
1377#endif
1378 TRACE_LOG("returning %s\n", rc ? "TRUE" : "FALSE");
1379 return rc;
1380}
1381
1382static void VBOXAdjustFrame(ScrnInfoPtr pScrn, int x, int y)
1383{ RT_NOREF(pScrn, x, y); }
1384
1385static void VBOXFreeScreen(ScrnInfoPtr pScrn)
1386{
1387 /* Destroy the VGA hardware record */
1388 vgaHWFreeHWRec(pScrn);
1389 /* And our private record */
1390 free(pScrn->driverPrivate);
1391 pScrn->driverPrivate = NULL;
1392}
1393
1394static Bool
1395VBOXMapVidMem(ScrnInfoPtr pScrn)
1396{
1397 VBOXPtr pVBox = VBOXGetRec(pScrn);
1398 Bool rc = TRUE;
1399
1400 TRACE_ENTRY();
1401 if (!pVBox->base)
1402 {
1403#ifdef PCIACCESS
1404 (void) pci_device_map_range(pVBox->pciInfo,
1405 pScrn->memPhysBase,
1406 pScrn->videoRam * 1024,
1407 PCI_DEV_MAP_FLAG_WRITABLE,
1408 & pVBox->base);
1409#else
1410 pVBox->base = xf86MapPciMem(pScrn->scrnIndex,
1411 VIDMEM_FRAMEBUFFER,
1412 pVBox->pciTag, pScrn->memPhysBase,
1413 (unsigned) pScrn->videoRam * 1024);
1414#endif
1415 if (!pVBox->base)
1416 rc = FALSE;
1417 }
1418 TRACE_LOG("returning %s\n", rc ? "TRUE" : "FALSE");
1419 return rc;
1420}
1421
1422static void
1423VBOXUnmapVidMem(ScrnInfoPtr pScrn)
1424{
1425 VBOXPtr pVBox = VBOXGetRec(pScrn);
1426
1427 TRACE_ENTRY();
1428 if (pVBox->base == NULL)
1429 return;
1430
1431#ifdef PCIACCESS
1432 (void) pci_device_unmap_range(pVBox->pciInfo,
1433 pVBox->base,
1434 pScrn->videoRam * 1024);
1435#else
1436 xf86UnMapVidMem(pScrn->scrnIndex, pVBox->base,
1437 (unsigned) pScrn->videoRam * 1024);
1438#endif
1439 pVBox->base = NULL;
1440 TRACE_EXIT();
1441}
1442
1443#ifndef VBOXVIDEO_13
1444static Bool
1445VBOXSaveScreen(ScreenPtr pScreen, int mode)
1446{
1447 RT_NOREF(pScreen, mode);
1448 return TRUE;
1449}
1450#endif
1451
1452void
1453VBOXSaveMode(ScrnInfoPtr pScrn)
1454{
1455 VBOXPtr pVBox = VBOXGetRec(pScrn);
1456 vgaRegPtr vgaReg;
1457
1458 TRACE_ENTRY();
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}
1467
1468void
1469VBOXRestoreMode(ScrnInfoPtr pScrn)
1470{
1471 VBOXPtr pVBox = VBOXGetRec(pScrn);
1472 vgaRegPtr vgaReg;
1473
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();
1483}
1484
1485#ifndef VBOXVIDEO_13
1486static void
1487VBOXDisplayPowerManagementSet(ScrnInfoPtr pScrn, int mode, int flags)
1488{
1489 RT_NOREF(pScrn, mode, flags);
1490}
1491#endif
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use