VirtualBox

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

Last change on this file since 34997 was 34922, checked in by vboxsync, 14 years ago

Additions/x11/vboxvideo: another screen layout/mouse location issue

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 50.2 KB
Line 
1/* $Id: vboxvideo.c 34922 2010-12-09 19:59:27Z vboxsync $ */
2/** @file
3 *
4 * Linux Additions X11 graphics driver
5 */
6
7/*
8 * Copyright (C) 2006-2010 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 * --------------------------------------------------------------------
18 *
19 * This code is based on:
20 *
21 * X11 VESA driver
22 *
23 * Copyright (c) 2000 by Conectiva S.A. (http://www.conectiva.com)
24 *
25 * Permission is hereby granted, free of charge, to any person obtaining a
26 * copy of this software and associated documentation files (the "Software"),
27 * to deal in the Software without restriction, including without limitation
28 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
29 * and/or sell copies of the Software, and to permit persons to whom the
30 * Software is furnished to do so, subject to the following conditions:
31 *
32 * The above copyright notice and this permission notice shall be included in
33 * all copies or substantial portions of the Software.
34 *
35 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
36 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
37 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
38 * CONECTIVA LINUX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
39 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
40 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
41 * SOFTWARE.
42 *
43 * Except as contained in this notice, the name of Conectiva Linux shall
44 * not be used in advertising or otherwise to promote the sale, use or other
45 * dealings in this Software without prior written authorization from
46 * Conectiva Linux.
47 *
48 * Authors: Paulo César Pereira de Andrade <[email protected]>
49 */
50
51#ifdef XORG_7X
52# include "xorg-server.h"
53# include <string.h>
54#endif
55#include "vboxvideo.h"
56#include <iprt/asm-math.h>
57#include "version-generated.h"
58#include "product-generated.h"
59#include <xf86.h>
60
61/* All drivers initialising the SW cursor need this */
62#include "mipointer.h"
63
64/* All drivers implementing backing store need this */
65#include "mibstore.h"
66
67/* Colormap handling */
68#include "micmap.h"
69#include "xf86cmap.h"
70
71/* DPMS */
72/* #define DPMS_SERVER
73#include "extensions/dpms.h" */
74
75/* VGA hardware functions for setting and restoring text mode */
76#include "vgaHW.h"
77
78#ifdef VBOXVIDEO_13
79/* X.org 1.3+ mode setting */
80# define _HAVE_STRING_ARCH_strsep /* bits/string2.h, __strsep_1c. */
81# include "xf86Crtc.h"
82# include "xf86Modes.h"
83# include <X11/Xatom.h>
84#endif
85
86/* Mandatory functions */
87
88static const OptionInfoRec * VBOXAvailableOptions(int chipid, int busid);
89static void VBOXIdentify(int flags);
90#ifndef PCIACCESS
91static Bool VBOXProbe(DriverPtr drv, int flags);
92#else
93static Bool VBOXPciProbe(DriverPtr drv, int entity_num,
94 struct pci_device *dev, intptr_t match_data);
95#endif
96static Bool VBOXPreInit(ScrnInfoPtr pScrn, int flags);
97static Bool VBOXScreenInit(int Index, ScreenPtr pScreen, int argc,
98 char **argv);
99static Bool VBOXEnterVT(int scrnIndex, int flags);
100static void VBOXLeaveVT(int scrnIndex, int flags);
101static Bool VBOXCloseScreen(int scrnIndex, ScreenPtr pScreen);
102static Bool VBOXSaveScreen(ScreenPtr pScreen, int mode);
103static Bool VBOXSwitchMode(int scrnIndex, DisplayModePtr pMode, int flags);
104static Bool VBOXSetMode(ScrnInfoPtr pScrn, unsigned cDisplay, unsigned cWidth,
105 unsigned cHeight, int x, int y);
106static void VBOXAdjustFrame(int scrnIndex, int x, int y, int flags);
107static void VBOXFreeScreen(int scrnIndex, int flags);
108static void VBOXFreeRec(ScrnInfoPtr pScrn);
109static void VBOXDisplayPowerManagementSet(ScrnInfoPtr pScrn, int mode,
110 int flags);
111
112/* locally used functions */
113static Bool VBOXMapVidMem(ScrnInfoPtr pScrn);
114static void VBOXUnmapVidMem(ScrnInfoPtr pScrn);
115static Bool VBOXSaveRestore(ScrnInfoPtr pScrn,
116 vbeSaveRestoreFunction function);
117static Bool VBOXAdjustScreenPixmap(ScrnInfoPtr pScrn, int width, int height);
118
119enum GenericTypes
120{
121 CHIP_VBOX_GENERIC
122};
123
124#ifdef PCIACCESS
125static const struct pci_id_match vbox_device_match[] = {
126 {
127 VBOX_VENDORID, VBOX_DEVICEID, PCI_MATCH_ANY, PCI_MATCH_ANY,
128 0, 0, 0
129 },
130
131 { 0, 0, 0 },
132};
133#endif
134
135/* Supported chipsets */
136static SymTabRec VBOXChipsets[] =
137{
138 {VBOX_DEVICEID, "vbox"},
139 {-1, NULL}
140};
141
142static PciChipsets VBOXPCIchipsets[] = {
143 { VBOX_DEVICEID, VBOX_DEVICEID, RES_SHARED_VGA },
144 { -1, -1, RES_UNDEFINED },
145};
146
147/*
148 * This contains the functions needed by the server after loading the
149 * driver module. It must be supplied, and gets added the driver list by
150 * the Module Setup function in the dynamic case. In the static case a
151 * reference to this is compiled in, and this requires that the name of
152 * this DriverRec be an upper-case version of the driver name.
153 */
154
155#ifdef XORG_7X
156_X_EXPORT
157#endif
158DriverRec VBOXVIDEO = {
159 VBOX_VERSION,
160 VBOX_DRIVER_NAME,
161 VBOXIdentify,
162#ifdef PCIACCESS
163 NULL,
164#else
165 VBOXProbe,
166#endif
167 VBOXAvailableOptions,
168 NULL,
169 0,
170#ifdef XORG_7X
171 NULL,
172#endif
173#ifdef PCIACCESS
174 vbox_device_match,
175 VBOXPciProbe
176#endif
177};
178
179/* No options for now */
180static const OptionInfoRec VBOXOptions[] = {
181 { -1, NULL, OPTV_NONE, {0}, FALSE }
182};
183
184#ifndef XORG_7X
185/*
186 * List of symbols from other modules that this module references. This
187 * list is used to tell the loader that it is OK for symbols here to be
188 * unresolved providing that it hasn't been told that they haven't been
189 * told that they are essential via a call to xf86LoaderReqSymbols() or
190 * xf86LoaderReqSymLists(). The purpose is this is to avoid warnings about
191 * unresolved symbols that are not required.
192 */
193static const char *fbSymbols[] = {
194 "fbPictureInit",
195 "fbScreenInit",
196 NULL
197};
198
199static const char *shadowfbSymbols[] = {
200 "ShadowFBInit2",
201 NULL
202};
203
204static const char *vbeSymbols[] = {
205 "VBEExtendedInit",
206 "VBEFindSupportedDepths",
207 "VBEGetModeInfo",
208 "VBEGetVBEInfo",
209 "VBEGetVBEMode",
210 "VBEPrintModes",
211 "VBESaveRestore",
212 "VBESetDisplayStart",
213 "VBESetGetDACPaletteFormat",
214 "VBESetGetLogicalScanlineLength",
215 "VBESetGetPaletteData",
216 "VBESetModeNames",
217 "VBESetModeParameters",
218 "VBESetVBEMode",
219 "VBEValidateModes",
220 "vbeDoEDID",
221 "vbeFree",
222 NULL
223};
224
225static const char *ramdacSymbols[] = {
226 "xf86InitCursor",
227 "xf86CreateCursorInfoRec",
228 NULL
229};
230
231static const char *vgahwSymbols[] = {
232 "vgaHWGetHWRec",
233 "vgaHWHandleColormaps",
234 "vgaHWFreeHWRec",
235 "vgaHWMapMem",
236 "vgaHWUnmapMem",
237 "vgaHWSaveFonts",
238 "vgaHWRestoreFonts",
239 "vgaHWGetIndex",
240 "vgaHWSaveScreen",
241 "vgaHWDPMSSet",
242 NULL
243};
244#endif /* !XORG_7X */
245
246static VBOXPtr
247VBOXGetRec(ScrnInfoPtr pScrn)
248{
249 if (!pScrn->driverPrivate)
250 {
251 pScrn->driverPrivate = calloc(sizeof(VBOXRec), 1);
252 }
253
254 return ((VBOXPtr)pScrn->driverPrivate);
255}
256
257static void
258VBOXFreeRec(ScrnInfoPtr pScrn)
259{
260 VBOXPtr pVBox = VBOXGetRec(pScrn);
261 free(pVBox->savedPal);
262 free(pVBox->fonts);
263 free(pScrn->driverPrivate);
264 pScrn->driverPrivate = NULL;
265}
266
267#ifdef VBOXVIDEO_13
268/* X.org 1.3+ mode-setting support ******************************************/
269
270/* For descriptions of these functions and structures, see
271 hw/xfree86/modes/xf86Crtc.h and hw/xfree86/modes/xf86Modes.h in the
272 X.Org source tree. */
273
274static const xf86CrtcConfigFuncsRec VBOXCrtcConfigFuncs = {
275 VBOXAdjustScreenPixmap
276};
277
278static void
279vbox_crtc_dpms(xf86CrtcPtr crtc, int mode)
280{ (void) crtc; (void) mode; }
281
282static Bool
283vbox_crtc_lock (xf86CrtcPtr crtc)
284{ (void) crtc; return FALSE; }
285
286static Bool
287vbox_crtc_mode_fixup (xf86CrtcPtr crtc, DisplayModePtr mode,
288 DisplayModePtr adjusted_mode)
289{ (void) crtc; (void) mode; (void) adjusted_mode; return TRUE; }
290
291static void
292vbox_crtc_stub (xf86CrtcPtr crtc)
293{ (void) crtc; }
294
295static void
296vbox_crtc_mode_set (xf86CrtcPtr crtc, DisplayModePtr mode,
297 DisplayModePtr adjusted_mode, int x, int y)
298{
299 (void) mode;
300 VBOXPtr pVBox = VBOXGetRec(crtc->scrn);
301
302 TRACE_LOG("name=%s, HDisplay=%d, VDisplay=%d, x=%d, y=%d\n", adjusted_mode->name,
303 adjusted_mode->HDisplay, adjusted_mode->VDisplay, x, y);
304 VBOXSetMode(crtc->scrn, (uintptr_t)crtc->driver_private,
305 adjusted_mode->HDisplay, adjusted_mode->VDisplay, x, y);
306 /* Don't remember any modes set while we are seamless, as they are
307 * just temporary. */
308 if (!vboxGuestIsSeamless(crtc->scrn))
309 vboxSaveVideoMode(crtc->scrn, adjusted_mode->HDisplay,
310 adjusted_mode->VDisplay, crtc->scrn->bitsPerPixel);
311}
312
313static void
314vbox_crtc_gamma_set (xf86CrtcPtr crtc, CARD16 *red,
315 CARD16 *green, CARD16 *blue, int size)
316{ (void) crtc; (void) red; (void) green; (void) blue; (void) size; }
317
318static void *
319vbox_crtc_shadow_allocate (xf86CrtcPtr crtc, int width, int height)
320{ (void) crtc; (void) width; (void) height; return NULL; }
321
322static const xf86CrtcFuncsRec VBOXCrtcFuncs = {
323 .dpms = vbox_crtc_dpms,
324 .save = NULL, /* These two are never called by the server. */
325 .restore = NULL,
326 .lock = vbox_crtc_lock,
327 .unlock = NULL, /* This will not be invoked if lock returns FALSE. */
328 .mode_fixup = vbox_crtc_mode_fixup,
329 .prepare = vbox_crtc_stub,
330 .mode_set = vbox_crtc_mode_set,
331 .commit = vbox_crtc_stub,
332 .gamma_set = vbox_crtc_gamma_set,
333 .shadow_allocate = vbox_crtc_shadow_allocate,
334 .shadow_create = NULL, /* These two should not be invoked if allocate
335 returns NULL. */
336 .shadow_destroy = NULL,
337 .set_cursor_colors = NULL, /* We are still using the old cursor API. */
338 .set_cursor_position = NULL,
339 .show_cursor = NULL,
340 .hide_cursor = NULL,
341 .load_cursor_argb = NULL,
342 .destroy = vbox_crtc_stub
343};
344
345static void
346vbox_output_stub (xf86OutputPtr output)
347{ (void) output; }
348
349static void
350vbox_output_dpms (xf86OutputPtr output, int mode)
351{ (void) output; (void) mode; }
352
353static int
354vbox_output_mode_valid (xf86OutputPtr output, DisplayModePtr mode)
355{
356 ScrnInfoPtr pScrn = output->scrn;
357 int rc = MODE_OK;
358 TRACE_LOG("HDisplay=%d, VDisplay=%d\n", mode->HDisplay, mode->VDisplay);
359 /* We always like modes specified by the user in the configuration
360 * file and modes requested by the host, as doing otherwise is likely to
361 * annoy people. */
362 if ( !(mode->type & M_T_USERDEF)
363 && !(mode->type & M_T_PREFERRED)
364 && vbox_device_available(VBOXGetRec(pScrn))
365 && !vboxHostLikesVideoMode(pScrn, mode->HDisplay, mode->VDisplay,
366 pScrn->bitsPerPixel)
367 )
368 rc = MODE_BAD;
369 TRACE_LOG("returning %s\n", MODE_OK == rc ? "MODE_OK" : "MODE_BAD");
370 return rc;
371}
372
373static Bool
374vbox_output_mode_fixup (xf86OutputPtr output, DisplayModePtr mode,
375 DisplayModePtr adjusted_mode)
376{ (void) output; (void) mode; (void) adjusted_mode; return TRUE; }
377
378static void
379vbox_output_mode_set (xf86OutputPtr output, DisplayModePtr mode,
380 DisplayModePtr adjusted_mode)
381{ (void) output; (void) mode; (void) adjusted_mode; }
382
383/* A virtual monitor is always connected. */
384static xf86OutputStatus
385vbox_output_detect (xf86OutputPtr output)
386{
387 (void) output;
388 return XF86OutputStatusConnected;
389}
390
391static void
392vbox_output_add_mode (VBOXPtr pVBox, DisplayModePtr *pModes,
393 const char *pszName, int x, int y,
394 Bool isPreferred, Bool isUserDef)
395{
396 TRACE_LOG("pszName=%s, x=%d, y=%d\n", pszName, x, y);
397 DisplayModePtr pMode = xnfcalloc(1, sizeof(DisplayModeRec));
398
399 pMode->status = MODE_OK;
400 /* We don't ask the host whether it likes user defined modes,
401 * as we assume that the user really wanted that mode. */
402 pMode->type = isUserDef ? M_T_USERDEF : M_T_BUILTIN;
403 if (isPreferred)
404 pMode->type |= M_T_PREFERRED;
405 /* Older versions of VBox only support screen widths which are a multiple
406 * of 8 */
407 if (pVBox->fAnyX)
408 pMode->HDisplay = x;
409 else
410 pMode->HDisplay = x & ~7;
411 pMode->HSyncStart = pMode->HDisplay + 2;
412 pMode->HSyncEnd = pMode->HDisplay + 4;
413 pMode->HTotal = pMode->HDisplay + 6;
414 pMode->VDisplay = y;
415 pMode->VSyncStart = pMode->VDisplay + 2;
416 pMode->VSyncEnd = pMode->VDisplay + 4;
417 pMode->VTotal = pMode->VDisplay + 6;
418 pMode->Clock = pMode->HTotal * pMode->VTotal * 60 / 1000; /* kHz */
419 if (NULL == pszName) {
420 xf86SetModeDefaultName(pMode);
421 } else {
422 pMode->name = xnfstrdup(pszName);
423 }
424 *pModes = xf86ModesAdd(*pModes, pMode);
425}
426
427static DisplayModePtr
428vbox_output_get_modes (xf86OutputPtr output)
429{
430 unsigned i;
431 DisplayModePtr pModes = NULL;
432 ScrnInfoPtr pScrn = output->scrn;
433 VBOXPtr pVBox = VBOXGetRec(pScrn);
434
435 TRACE_ENTRY();
436 if (vbox_device_available(pVBox))
437 {
438 Bool rc = FALSE;
439 uint32_t x, y, bpp, iScreen;
440 iScreen = (uintptr_t)output->driver_private;
441 if ( pVBox->aPreferredSize[iScreen].cx
442 && pVBox->aPreferredSize[iScreen].cy)
443 {
444 x = pVBox->aPreferredSize[iScreen].cx;
445 y = pVBox->aPreferredSize[iScreen].cy;
446 rc = TRUE;
447 }
448 else
449 rc = vboxGetDisplayChangeRequest(pScrn, &x, &y, &bpp, &iScreen);
450 /* If we don't find a display request, see if we have a saved hint
451 * from a previous session. */
452 if (!rc || (0 == x) || (0 == y))
453 rc = vboxRetrieveVideoMode(pScrn, &x, &y, &bpp);
454 if (rc && (0 != x) && (0 != y))
455 vbox_output_add_mode(pVBox, &pModes, NULL, x, y, TRUE, FALSE);
456 }
457 /* Also report any modes the user may have requested in the xorg.conf
458 * configuration file. */
459 for (i = 0; pScrn->display->modes[i] != NULL; i++)
460 {
461 int x, y;
462 if (2 == sscanf(pScrn->display->modes[i], "%dx%d", &x, &y))
463 vbox_output_add_mode(pVBox, &pModes, pScrn->display->modes[i], x, y,
464 FALSE, TRUE);
465 }
466 TRACE_EXIT();
467 return pModes;
468}
469
470#ifdef RANDR_12_INTERFACE
471static Atom
472vboxAtomVBoxMode(void)
473{
474 static Atom rc = 0;
475 if (!rc)
476 rc = MakeAtom("VBOX_MODE", sizeof("VBOX_MODE") - 1, TRUE);
477 return rc;
478}
479
480/** We use this for receiving information from clients for the purpose of
481 * dynamic resizing, and later possibly other things too.
482 */
483static Bool
484vbox_output_set_property(xf86OutputPtr output, Atom property,
485 RRPropertyValuePtr value)
486{
487 ScrnInfoPtr pScrn = output->scrn;
488 VBOXPtr pVBox = VBOXGetRec(pScrn);
489 TRACE_LOG("property=%d, value->type=%d, value->format=%d, value->size=%ld\n",
490 (int)property, (int)value->type, value->format, value->size);
491 if (property == vboxAtomVBoxMode())
492 {
493 uint32_t cDisplay = (uintptr_t)output->driver_private;
494 char sz[256] = { 0 };
495 int w, h;
496
497 if ( value->type != XA_STRING
498 || (unsigned) value->size > (sizeof(sz) - 1))
499 return FALSE;
500 strncpy(sz, value->data, value->size);
501 if (sscanf(sz, "%dx%d", &w, &h) != 2)
502 return FALSE;
503 pVBox->aPreferredSize[cDisplay].cx = w;
504 pVBox->aPreferredSize[cDisplay].cy = h;
505 return TRUE;
506 }
507 return FALSE;
508}
509#endif
510
511static const xf86OutputFuncsRec VBOXOutputFuncs = {
512 .create_resources = vbox_output_stub,
513 .dpms = vbox_output_dpms,
514 .save = NULL, /* These two are never called by the server. */
515 .restore = NULL,
516 .mode_valid = vbox_output_mode_valid,
517 .mode_fixup = vbox_output_mode_fixup,
518 .prepare = vbox_output_stub,
519 .commit = vbox_output_stub,
520 .mode_set = vbox_output_mode_set,
521 .detect = vbox_output_detect,
522 .get_modes = vbox_output_get_modes,
523#ifdef RANDR_12_INTERFACE
524 .set_property = vbox_output_set_property,
525#endif
526 .destroy = vbox_output_stub
527};
528#endif /* VBOXVIDEO_13 */
529
530#ifdef XFree86LOADER
531/* Module loader interface */
532static MODULESETUPPROTO(vboxSetup);
533
534static XF86ModuleVersionInfo vboxVersionRec =
535{
536 VBOX_DRIVER_NAME,
537 VBOX_VENDOR,
538 MODINFOSTRING1,
539 MODINFOSTRING2,
540#ifdef XORG_7X
541 XORG_VERSION_CURRENT,
542#else
543 XF86_VERSION_CURRENT,
544#endif
545 1, /* Module major version. Xorg-specific */
546 0, /* Module minor version. Xorg-specific */
547 1, /* Module patchlevel. Xorg-specific */
548 ABI_CLASS_VIDEODRV, /* This is a video driver */
549 ABI_VIDEODRV_VERSION,
550 MOD_CLASS_VIDEODRV,
551 {0, 0, 0, 0}
552};
553
554/*
555 * This data is accessed by the loader. The name must be the module name
556 * followed by "ModuleData".
557 */
558#ifdef XORG_7X
559_X_EXPORT
560#endif
561XF86ModuleData vboxvideoModuleData = { &vboxVersionRec, vboxSetup, NULL };
562
563static pointer
564vboxSetup(pointer Module, pointer Options, int *ErrorMajor, int *ErrorMinor)
565{
566 static Bool Initialised = FALSE;
567
568 if (!Initialised)
569 {
570 Initialised = TRUE;
571#ifdef PCIACCESS
572 xf86AddDriver(&VBOXVIDEO, Module, HaveDriverFuncs);
573#else
574 xf86AddDriver(&VBOXVIDEO, Module, 0);
575#endif
576#ifndef XORG_7X
577 LoaderRefSymLists(fbSymbols,
578 shadowfbSymbols,
579 vbeSymbols,
580 ramdacSymbols,
581 vgahwSymbols,
582 NULL);
583#endif
584 xf86Msg(X_CONFIG, "Load address of symbol \"VBOXVIDEO\" is %p\n",
585 (void *)&VBOXVIDEO);
586 return (pointer)TRUE;
587 }
588
589 if (ErrorMajor)
590 *ErrorMajor = LDR_ONCEONLY;
591 return (NULL);
592}
593
594#endif /* XFree86Loader defined */
595
596static const OptionInfoRec *
597VBOXAvailableOptions(int chipid, int busid)
598{
599 return (VBOXOptions);
600}
601
602static void
603VBOXIdentify(int flags)
604{
605 xf86PrintChipsets(VBOX_NAME, "guest driver for VirtualBox", VBOXChipsets);
606}
607
608/*
609 * This function is called once, at the start of the first server generation to
610 * do a minimal probe for supported hardware.
611 */
612
613#ifdef PCIACCESS
614static Bool
615VBOXPciProbe(DriverPtr drv, int entity_num, struct pci_device *dev,
616 intptr_t match_data)
617{
618 ScrnInfoPtr pScrn;
619
620 TRACE_ENTRY();
621 pScrn = xf86ConfigPciEntity(NULL, 0, entity_num, VBOXPCIchipsets,
622 NULL, NULL, NULL, NULL, NULL);
623 if (pScrn != NULL) {
624 VBOXPtr pVBox = VBOXGetRec(pScrn);
625
626 pScrn->driverVersion = VBOX_VERSION;
627 pScrn->driverName = VBOX_DRIVER_NAME;
628 pScrn->name = VBOX_NAME;
629 pScrn->Probe = NULL;
630 pScrn->PreInit = VBOXPreInit;
631 pScrn->ScreenInit = VBOXScreenInit;
632 pScrn->SwitchMode = VBOXSwitchMode;
633 pScrn->AdjustFrame = VBOXAdjustFrame;
634 pScrn->EnterVT = VBOXEnterVT;
635 pScrn->LeaveVT = VBOXLeaveVT;
636 pScrn->FreeScreen = VBOXFreeScreen;
637
638 pVBox->pciInfo = dev;
639 }
640
641 TRACE_LOG("returning %s\n", BOOL_STR(pScrn != NULL));
642 return (pScrn != NULL);
643}
644#endif
645
646#ifndef PCIACCESS
647static Bool
648VBOXProbe(DriverPtr drv, int flags)
649{
650 Bool foundScreen = FALSE;
651 int numDevSections;
652 GDevPtr *devSections;
653
654 /*
655 * Find the config file Device sections that match this
656 * driver, and return if there are none.
657 */
658 if ((numDevSections = xf86MatchDevice(VBOX_NAME,
659 &devSections)) <= 0)
660 return (FALSE);
661
662 /* PCI BUS */
663 if (xf86GetPciVideoInfo()) {
664 int numUsed;
665 int *usedChips;
666 int i;
667 numUsed = xf86MatchPciInstances(VBOX_NAME, VBOX_VENDORID,
668 VBOXChipsets, VBOXPCIchipsets,
669 devSections, numDevSections,
670 drv, &usedChips);
671 if (numUsed > 0) {
672 if (flags & PROBE_DETECT)
673 foundScreen = TRUE;
674 else {
675 for (i = 0; i < numUsed; i++) {
676 ScrnInfoPtr pScrn = NULL;
677 /* Allocate a ScrnInfoRec */
678 if ((pScrn = xf86ConfigPciEntity(pScrn,0,usedChips[i],
679 VBOXPCIchipsets,NULL,
680 NULL,NULL,NULL,NULL))) {
681 pScrn->driverVersion = VBOX_VERSION;
682 pScrn->driverName = VBOX_DRIVER_NAME;
683 pScrn->name = VBOX_NAME;
684 pScrn->Probe = VBOXProbe;
685 pScrn->PreInit = VBOXPreInit;
686 pScrn->ScreenInit = VBOXScreenInit;
687 pScrn->SwitchMode = VBOXSwitchMode;
688 pScrn->AdjustFrame = VBOXAdjustFrame;
689 pScrn->EnterVT = VBOXEnterVT;
690 pScrn->LeaveVT = VBOXLeaveVT;
691 pScrn->FreeScreen = VBOXFreeScreen;
692 foundScreen = TRUE;
693 }
694 }
695 }
696 free(usedChips);
697 }
698 }
699
700 free(devSections);
701
702 return (foundScreen);
703}
704#endif
705
706/**
707 * This function hooks into the chain that is called when framebuffer access
708 * is allowed or disallowed by a call to EnableDisableFBAccess in the server.
709 * In other words, it observes when the server wishes access to the
710 * framebuffer to be enabled and when it should be disabled. We need to know
711 * this because we disable access ourselves during mode switches (presumably
712 * the server should do this but it doesn't) and want to know whether to
713 * restore it or not afterwards.
714 */
715static void
716vboxEnableDisableFBAccess(int scrnIndex, Bool enable)
717{
718 ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
719 VBOXPtr pVBox = VBOXGetRec(pScrn);
720
721 TRACE_LOG("enable=%s\n", enable ? "TRUE" : "FALSE");
722 pVBox->accessEnabled = enable;
723 pVBox->EnableDisableFBAccess(scrnIndex, enable);
724 TRACE_EXIT();
725}
726
727/** Calculate the BPP from the screen depth */
728static uint16_t
729vboxBPP(ScrnInfoPtr pScrn)
730{
731 return pScrn->depth == 24 ? 32 : 16;
732}
733
734/** Calculate the scan line length for a display width */
735static int32_t
736vboxLineLength(ScrnInfoPtr pScrn, int32_t cDisplayWidth)
737{
738 uint64_t cbLine = ((uint64_t)cDisplayWidth * vboxBPP(pScrn) / 8 + 3) & ~3;
739 return cbLine < INT32_MAX ? cbLine : INT32_MAX;
740}
741
742/** Calculate the display pitch from the scan line length */
743static int32_t
744vboxDisplayPitch(ScrnInfoPtr pScrn, int32_t cbLine)
745{
746 return ASMDivU64ByU32RetU32((uint64_t)cbLine * 8, vboxBPP(pScrn));
747}
748
749/*
750 * QUOTE from the XFree86 DESIGN document:
751 *
752 * The purpose of this function is to find out all the information
753 * required to determine if the configuration is usable, and to initialise
754 * those parts of the ScrnInfoRec that can be set once at the beginning of
755 * the first server generation.
756 *
757 * (...)
758 *
759 * This includes probing for video memory, clocks, ramdac, and all other
760 * HW info that is needed. It includes determining the depth/bpp/visual
761 * and related info. It includes validating and determining the set of
762 * video modes that will be used (and anything that is required to
763 * determine that).
764 *
765 * This information should be determined in the least intrusive way
766 * possible. The state of the HW must remain unchanged by this function.
767 * Although video memory (including MMIO) may be mapped within this
768 * function, it must be unmapped before returning.
769 *
770 * END QUOTE
771 */
772
773static Bool
774VBOXPreInit(ScrnInfoPtr pScrn, int flags)
775{
776 VBOXPtr pVBox;
777 Gamma gzeros = {0.0, 0.0, 0.0};
778 rgb rzeros = {0, 0, 0};
779 unsigned DispiId;
780
781 TRACE_ENTRY();
782 /* Are we really starting the server, or is this just a dummy run? */
783 if (flags & PROBE_DETECT)
784 return (FALSE);
785
786 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
787 "VirtualBox guest additions video driver version "
788 VBOX_VERSION_STRING "\n");
789
790 /* Get our private data from the ScrnInfoRec structure. */
791 pVBox = VBOXGetRec(pScrn);
792
793 /* Initialise the guest library */
794 vbox_init(pScrn->scrnIndex, pVBox);
795
796 /* Entity information seems to mean bus information. */
797 pVBox->pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
798
799 /* The ramdac module is needed for the hardware cursor. */
800 if (!xf86LoadSubModule(pScrn, "ramdac"))
801 return FALSE;
802
803 /* We need the vbe module because we use VBE code to save and restore
804 text mode, in order to keep our code simple. */
805 if (!xf86LoadSubModule(pScrn, "vbe"))
806 return (FALSE);
807
808 /* The framebuffer module. */
809 if (xf86LoadSubModule(pScrn, "fb") == NULL)
810 return (FALSE);
811
812 if (!xf86LoadSubModule(pScrn, "shadowfb"))
813 return FALSE;
814
815 if (!xf86LoadSubModule(pScrn, "vgahw"))
816 return FALSE;
817
818#ifdef VBOX_DRI
819 /* Load the dri module. */
820 if (!xf86LoadSubModule(pScrn, "dri"))
821 return FALSE;
822#endif
823
824#ifndef PCIACCESS
825 if (pVBox->pEnt->location.type != BUS_PCI)
826 return FALSE;
827
828 pVBox->pciInfo = xf86GetPciInfoForEntity(pVBox->pEnt->index);
829 pVBox->pciTag = pciTag(pVBox->pciInfo->bus,
830 pVBox->pciInfo->device,
831 pVBox->pciInfo->func);
832#endif
833
834 /* Set up our ScrnInfoRec structure to describe our virtual
835 capabilities to X. */
836
837 pScrn->chipset = "vbox";
838 pScrn->rgbBits = 8;
839
840 /* Let's create a nice, capable virtual monitor.
841 * This *is* still needed, at least for server version 1.3 */
842 pScrn->monitor = pScrn->confScreen->monitor;
843 pScrn->monitor->DDC = NULL;
844 pScrn->monitor->nHsync = 1;
845 pScrn->monitor->hsync[0].lo = 1;
846 pScrn->monitor->hsync[0].hi = 10000;
847 pScrn->monitor->nVrefresh = 1;
848 pScrn->monitor->vrefresh[0].lo = 1;
849 pScrn->monitor->vrefresh[0].hi = 100;
850
851 pScrn->progClock = TRUE;
852
853 /* Using the PCI information caused problems with non-powers-of-two
854 sized video RAM configurations */
855 pVBox->cbFramebuffer = inl(VBE_DISPI_IOPORT_DATA);
856 pScrn->videoRam = pVBox->cbFramebuffer / 1024;
857
858 /* Check if the chip restricts horizontal resolution or not. */
859 outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
860 outw(VBE_DISPI_IOPORT_DATA, VBE_DISPI_ID_ANYX);
861 DispiId = inw(VBE_DISPI_IOPORT_DATA);
862 if (DispiId == VBE_DISPI_ID_ANYX)
863 pVBox->fAnyX = TRUE;
864 else
865 pVBox->fAnyX = FALSE;
866
867 /* Set up clock information that will support all modes we need. */
868 pScrn->clockRanges = xnfcalloc(sizeof(ClockRange), 1);
869 pScrn->clockRanges->minClock = 1000;
870 pScrn->clockRanges->maxClock = 1000000000;
871 pScrn->clockRanges->clockIndex = -1;
872 pScrn->clockRanges->ClockMulFactor = 1;
873 pScrn->clockRanges->ClockDivFactor = 1;
874
875 /* Query the host for the preferred colour depth */
876 {
877 uint32_t cx = 0, cy = 0, cBits = 0;
878
879 vboxGetPreferredMode(pScrn, &cx, &cy, &cBits);
880 /* We only support 16 and 24 bits depth (i.e. 16 and 32bpp) */
881 if (cBits != 16)
882 cBits = 24;
883 if (!xf86SetDepthBpp(pScrn, cBits, 0, 0, Support32bppFb))
884 return FALSE;
885 vboxAddModes(pScrn, cx, cy);
886 }
887 if (pScrn->bitsPerPixel != 32 && pScrn->bitsPerPixel != 16)
888 {
889 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
890 "The VBox additions only support 16 and 32bpp graphics modes\n");
891 return FALSE;
892 }
893 xf86PrintDepthBpp(pScrn);
894
895#ifdef VBOXVIDEO_13
896 /* Work around a bug in the original X server modesetting code, which
897 * took the first valid values set to these two as maxima over the
898 * server lifetime. */
899 pScrn->virtualX = 32000;
900 pScrn->virtualY = 32000;
901#else
902 /* We don't validate with xf86ValidateModes and xf86PruneModes as we
903 * already know what we like and what we don't. */
904
905 pScrn->currentMode = pScrn->modes;
906
907 /* Set the right virtual resolution. */
908 pScrn->virtualX = pScrn->currentMode->HDisplay;
909 pScrn->virtualY = pScrn->currentMode->VDisplay;
910
911#endif /* !VBOXVIDEO_13 */
912
913 /* Needed before we initialise DRI. */
914 pVBox->cbLine = vboxLineLength(pScrn, pScrn->virtualX);
915 pScrn->displayWidth = vboxDisplayPitch(pScrn, pVBox->cbLine);
916
917 xf86PrintModes(pScrn);
918
919 /* Colour weight - we always call this, since we are always in
920 truecolour. */
921 if (!xf86SetWeight(pScrn, rzeros, rzeros))
922 return (FALSE);
923
924 /* visual init */
925 if (!xf86SetDefaultVisual(pScrn, -1))
926 return (FALSE);
927
928 xf86SetGamma(pScrn, gzeros);
929
930 /* Set the DPI. Perhaps we should read this from the host? */
931 xf86SetDpi(pScrn, 96, 96);
932
933 /* Framebuffer-related setup */
934 pScrn->bitmapBitOrder = BITMAP_BIT_ORDER;
935
936 /* VGA hardware initialisation */
937 if (!vgaHWGetHWRec(pScrn))
938 return FALSE;
939
940 TRACE_EXIT();
941 return (TRUE);
942}
943
944/**
945 * Dummy function for setting the colour palette, which we actually never
946 * touch. However, the server still requires us to provide this.
947 */
948static void
949vboxLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices,
950 LOCO *colors, VisualPtr pVisual)
951{
952 (void)pScrn; (void) numColors; (void) indices; (void) colors;
953 (void)pVisual;
954}
955
956/*
957 * QUOTE from the XFree86 DESIGN document:
958 *
959 * This is called at the start of each server generation.
960 *
961 * (...)
962 *
963 * Decide which operations need to be placed under resource access
964 * control. (...) Map any video memory or other memory regions. (...)
965 * Save the video card state. (...) Initialise the initial video
966 * mode.
967 *
968 * End QUOTE.
969 */
970static Bool
971VBOXScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
972{
973 ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
974 VBOXPtr pVBox = VBOXGetRec(pScrn);
975 VisualPtr visual;
976 unsigned flags;
977
978 TRACE_ENTRY();
979 /* We make use of the X11 VBE code to save and restore text mode, in
980 order to keep our code simple. */
981 if ((pVBox->pVbe = VBEExtendedInit(NULL, pVBox->pEnt->index,
982 SET_BIOS_SCRATCH
983 | RESTORE_BIOS_SCRATCH)) == NULL)
984 return (FALSE);
985
986 if (pScrn->memPhysBase == 0) {
987#ifdef PCIACCESS
988 pScrn->memPhysBase = pVBox->pciInfo->regions[0].base_addr;
989#else
990 pScrn->memPhysBase = pVBox->pciInfo->memBase[0];
991#endif
992 pScrn->fbOffset = 0;
993 }
994
995 if (!VBOXMapVidMem(pScrn))
996 return (FALSE);
997
998 /* save current video state */
999 VBOXSaveRestore(pScrn, MODE_SAVE);
1000
1001 /* mi layer - reset the visual list (?)*/
1002 miClearVisualTypes();
1003 if (!xf86SetDefaultVisual(pScrn, -1))
1004 return (FALSE);
1005 if (!miSetVisualTypes(pScrn->depth, TrueColorMask,
1006 pScrn->rgbBits, TrueColor))
1007 return (FALSE);
1008 if (!miSetPixmapDepths())
1009 return (FALSE);
1010
1011#ifdef VBOX_DRI
1012 pVBox->useDRI = VBOXDRIScreenInit(scrnIndex, pScreen, pVBox);
1013#endif
1014
1015 /* I checked in the sources, and XFree86 4.2 does seem to support
1016 this function for 32bpp. */
1017 if (!fbScreenInit(pScreen, pVBox->base,
1018 pScrn->virtualX, pScrn->virtualY,
1019 pScrn->xDpi, pScrn->yDpi,
1020 pScrn->displayWidth, pScrn->bitsPerPixel))
1021 return (FALSE);
1022
1023 /* Fixup RGB ordering */
1024 visual = pScreen->visuals + pScreen->numVisuals;
1025 while (--visual >= pScreen->visuals) {
1026 if ((visual->class | DynamicClass) == DirectColor) {
1027 visual->offsetRed = pScrn->offset.red;
1028 visual->offsetGreen = pScrn->offset.green;
1029 visual->offsetBlue = pScrn->offset.blue;
1030 visual->redMask = pScrn->mask.red;
1031 visual->greenMask = pScrn->mask.green;
1032 visual->blueMask = pScrn->mask.blue;
1033 }
1034 }
1035
1036 /* must be after RGB ordering fixed */
1037 fbPictureInit(pScreen, 0, 0);
1038
1039 xf86SetBlackWhitePixels(pScreen);
1040 miInitializeBackingStore(pScreen);
1041 xf86SetBackingStore(pScreen);
1042
1043 /* We need to keep track of whether we are currently switched to a virtual
1044 * terminal to know whether a mode set operation is currently safe to do.
1045 */
1046 pVBox->vtSwitch = FALSE;
1047
1048 if (vbox_device_available(pVBox) && vbox_open (pScrn, pScreen, pVBox)) {
1049 vboxEnableVbva(pScrn);
1050 vboxEnableGraphicsCap(pVBox);
1051 }
1052
1053#ifdef VBOXVIDEO_13
1054 /* Initialise CRTC and output configuration for use with randr1.2. */
1055 xf86CrtcConfigInit(pScrn, &VBOXCrtcConfigFuncs);
1056
1057 {
1058 uint32_t i;
1059
1060 for (i = 0; i < pVBox->cScreens; ++i)
1061 {
1062 char szOutput[256];
1063
1064 /* Setup our virtual CRTCs. */
1065 pVBox->paCrtcs[i] = xf86CrtcCreate(pScrn, &VBOXCrtcFuncs);
1066 pVBox->paCrtcs[i]->driver_private = (void *)(uintptr_t)i;
1067
1068 /* Set up our virtual outputs. */
1069 snprintf(szOutput, sizeof(szOutput), "VBOX%u", i);
1070 pVBox->paOutputs[i] = xf86OutputCreate(pScrn, &VBOXOutputFuncs,
1071 szOutput);
1072
1073 /* We are not interested in the monitor section in the
1074 * configuration file. */
1075 xf86OutputUseScreenMonitor(pVBox->paOutputs[i], FALSE);
1076 pVBox->paOutputs[i]->possible_crtcs = 1 << i;
1077 pVBox->paOutputs[i]->possible_clones = 0;
1078 pVBox->paOutputs[i]->driver_private = (void *)(uintptr_t)i;
1079 TRACE_LOG("Created crtc (%p) and output %s (%p)\n",
1080 (void *)pVBox->paCrtcs[i], szOutput,
1081 (void *)pVBox->paOutputs[i]);
1082 }
1083 }
1084
1085 /* Set a sane minimum and maximum mode size */
1086 xf86CrtcSetSizeRange(pScrn, 64, 64, 32000, 32000);
1087
1088 /* Now create our initial CRTC/output configuration. */
1089 if (!xf86InitialConfiguration(pScrn, TRUE)) {
1090 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Initial CRTC configuration failed!\n");
1091 return (FALSE);
1092 }
1093
1094 /* Initialise randr 1.2 mode-setting functions and set first mode.
1095 * Note that the mode won't be usable until the server has resized the
1096 * framebuffer to something reasonable. */
1097 if (!xf86CrtcScreenInit(pScreen)) {
1098 return FALSE;
1099 }
1100
1101 /* Create our VBOX_MODE display properties. */
1102 {
1103 uint32_t i;
1104
1105 for (i = 0; i < pVBox->cScreens; ++i)
1106 {
1107 char csz[] = "0x0";
1108 RRChangeOutputProperty(pVBox->paOutputs[i]->randr_output,
1109 vboxAtomVBoxMode(), XA_STRING, 8,
1110 PropModeReplace, sizeof(csz), csz, TRUE,
1111 FALSE);
1112
1113 }
1114 }
1115
1116 if (!xf86SetDesiredModes(pScrn)) {
1117 return FALSE;
1118 }
1119#else /* !VBOXVIDEO_13 */
1120 /* set first video mode */
1121 if (!VBOXSetMode(pScrn, 0, pScrn->currentMode->HDisplay,
1122 pScrn->currentMode->VDisplay, pScrn->frameX0,
1123 pScrn->frameY0))
1124 return FALSE;
1125 /* And make sure that a non-current dynamic mode is at the front of the
1126 * list */
1127 vboxWriteHostModes(pScrn, pScrn->currentMode);
1128#endif /* !VBOXVIDEO_13 */
1129
1130 /* software cursor */
1131 miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
1132
1133 /* colourmap code */
1134 if (!miCreateDefColormap(pScreen))
1135 return (FALSE);
1136
1137 if(!xf86HandleColormaps(pScreen, 256, 8, vboxLoadPalette, NULL, 0))
1138 return (FALSE);
1139
1140 /* Hook our observer function ito the chain which is called when
1141 * framebuffer access is enabled or disabled in the server, and
1142 * assume an initial state of enabled. */
1143 pVBox->accessEnabled = TRUE;
1144 pVBox->EnableDisableFBAccess = pScrn->EnableDisableFBAccess;
1145 pScrn->EnableDisableFBAccess = vboxEnableDisableFBAccess;
1146
1147 pVBox->CloseScreen = pScreen->CloseScreen;
1148 pScreen->CloseScreen = VBOXCloseScreen;
1149 pScreen->SaveScreen = VBOXSaveScreen;
1150
1151 /* We probably do want to support power management - even if we just use
1152 a dummy function. */
1153 xf86DPMSInit(pScreen, VBOXDisplayPowerManagementSet, 0);
1154
1155 /* Report any unused options (only for the first generation) */
1156 if (serverGeneration == 1)
1157 xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
1158
1159 if (vbox_cursor_init(pScreen) != TRUE)
1160 xf86DrvMsg(scrnIndex, X_ERROR,
1161 "Unable to start the VirtualBox mouse pointer integration with the host system.\n");
1162
1163#ifdef VBOX_DRI
1164 if (pVBox->useDRI)
1165 pVBox->useDRI = VBOXDRIFinishScreenInit(pScreen);
1166#endif
1167 return (TRUE);
1168}
1169
1170static Bool
1171VBOXEnterVT(int scrnIndex, int flags)
1172{
1173 ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1174 VBOXPtr pVBox = VBOXGetRec(pScrn);
1175
1176 TRACE_ENTRY();
1177 pVBox->vtSwitch = FALSE;
1178#ifdef VBOX_DRI
1179 if (pVBox->useDRI)
1180 DRIUnlock(screenInfo.screens[scrnIndex]);
1181#endif
1182#ifdef VBOXVIDEO_13
1183 if (!xf86SetDesiredModes(pScrn))
1184 return FALSE;
1185#else
1186 if (!VBOXSetMode(pScrn, 0, pScrn->currentMode->HDisplay,
1187 pScrn->currentMode->VDisplay, pScrn->frameX0,
1188 pScrn->frameY0))
1189 return FALSE;
1190#endif
1191 if (pVBox->fHaveHGSMI)
1192 vboxEnableVbva(pScrn);
1193 return TRUE;
1194}
1195
1196static void
1197VBOXLeaveVT(int scrnIndex, int flags)
1198{
1199 ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1200 VBOXPtr pVBox = VBOXGetRec(pScrn);
1201
1202 TRACE_ENTRY();
1203 pVBox->vtSwitch = TRUE;
1204 VBOXSaveRestore(pScrn, MODE_RESTORE);
1205 if (pVBox->fHaveHGSMI)
1206 vboxDisableVbva(pScrn);
1207 vboxDisableGraphicsCap(pVBox);
1208#ifdef VBOX_DRI
1209 if (pVBox->useDRI)
1210 DRILock(screenInfo.screens[scrnIndex], 0);
1211#endif
1212 TRACE_EXIT();
1213}
1214
1215static Bool
1216VBOXCloseScreen(int scrnIndex, ScreenPtr pScreen)
1217{
1218 ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1219 VBOXPtr pVBox = VBOXGetRec(pScrn);
1220
1221#ifdef VBOX_DRI
1222 if (pVBox->useDRI)
1223 VBOXDRICloseScreen(pScreen, pVBox);
1224 pVBox->useDRI = false;
1225#endif
1226
1227 if (pVBox->fHaveHGSMI)
1228 vboxDisableVbva(pScrn);
1229 vboxDisableGraphicsCap(pVBox);
1230 if (pScrn->vtSema) {
1231 VBOXSaveRestore(xf86Screens[scrnIndex], MODE_RESTORE);
1232 VBOXUnmapVidMem(pScrn);
1233 }
1234 pScrn->vtSema = FALSE;
1235
1236 /* Destroy the VGA hardware record */
1237 vgaHWFreeHWRec(pScrn);
1238
1239 /* And do additional bits which are separate for historical reasons */
1240 vbox_close(pScrn, pVBox);
1241
1242 /* Remove our observer functions from the X server call chains. */
1243 pScrn->EnableDisableFBAccess = pVBox->EnableDisableFBAccess;
1244 pScreen->CloseScreen = pVBox->CloseScreen;
1245 return pScreen->CloseScreen(scrnIndex, pScreen);
1246}
1247
1248static Bool
1249VBOXSwitchMode(int scrnIndex, DisplayModePtr pMode, int flags)
1250{
1251 ScrnInfoPtr pScrn;
1252 VBOXPtr pVBox;
1253 Bool rc;
1254
1255 TRACE_LOG("HDisplay=%d, VDisplay=%d\n", pMode->HDisplay, pMode->VDisplay);
1256 pScrn = xf86Screens[scrnIndex]; /* Why does X have three ways of referring to the screen? */
1257 pVBox = VBOXGetRec(pScrn);
1258 /* We want to disable access to the framebuffer before switching mode.
1259 * After doing the switch, we allow access if it was allowed before. */
1260 if (pVBox->accessEnabled)
1261 pVBox->EnableDisableFBAccess(scrnIndex, FALSE);
1262#ifdef VBOXVIDEO_13
1263 rc = xf86SetSingleMode(pScrn, pMode, 0);
1264#else
1265 VBOXAdjustScreenPixmap(pScrn, pMode->HDisplay, pMode->VDisplay);
1266 rc = VBOXSetMode(pScrn, 0, pMode->HDisplay, pMode->VDisplay,
1267 pScrn->frameX0, pScrn->frameY0);
1268 if (rc)
1269 {
1270 vboxWriteHostModes(pScrn, pMode);
1271 xf86PrintModes(pScrn);
1272 }
1273 if (rc && !vboxGuestIsSeamless(pScrn))
1274 vboxSaveVideoMode(pScrn, pMode->HDisplay, pMode->VDisplay,
1275 pScrn->bitsPerPixel);
1276#endif
1277 if (pVBox->accessEnabled)
1278 pVBox->EnableDisableFBAccess(scrnIndex, TRUE);
1279 TRACE_LOG("returning %s\n", rc ? "TRUE" : "FALSE");
1280 return rc;
1281}
1282
1283/** Get the index of the screen we will use as the primary one. This is in
1284 * fact the first screen located fully inside the virtual desktop, or zero
1285 * if none are. Screens which are not fully inside will be set up to be
1286 * identical to the primary one, so from the host's point of view the first
1287 * screen can always be treated as the primary. */
1288static uint32_t
1289vboxGetPrimaryIndex(ScrnInfoPtr pScrn)
1290{
1291 VBOXPtr pVBox = VBOXGetRec(pScrn);
1292 unsigned i;
1293 for (i = 0; i < pVBox->cScreens; ++i)
1294 if ( pVBox->aScreenLocation[i].x + pVBox->aScreenLocation[i].cx
1295 <= pScrn->virtualX
1296 && pVBox->aScreenLocation[i].y + pVBox->aScreenLocation[i].cy
1297 <= pScrn->virtualY)
1298 return i;
1299 return 0; /* This will probably look bad if it can happen. */
1300}
1301
1302/**
1303 * This is a rather un-transparent workaround for the fact that HGSMI doesn't
1304 * let us disable screens. If a guest screen is not enabled we set it to
1305 * match the display on the primary screen.
1306 */
1307static uint32_t
1308vboxGetRealLocationIndex(ScrnInfoPtr pScrn, unsigned i)
1309{
1310 VBOXPtr pVBox = VBOXGetRec(pScrn);
1311 if ( pVBox->aScreenLocation[i].x + pVBox->aScreenLocation[i].cx
1312 <= pScrn->virtualX
1313 && pVBox->aScreenLocation[i].y + pVBox->aScreenLocation[i].cy
1314 <= pScrn->virtualY)
1315 return i;
1316 return vboxGetPrimaryIndex(pScrn);
1317
1318}
1319
1320/** Set a graphics mode. Poke any required values into registers, do an HGSMI
1321 * mode set and tell the host we support advanced graphics functions. This
1322 * procedure is complicated by three things.
1323 * - The first is that X.Org can implicitly disable a screen by resizing the
1324 * virtual framebuffer so that the screen is no longer inside it. We have
1325 * to spot and handle this.
1326 * - The second is that HGSMI doesn't actually let us disable a monitor. We
1327 * should add this at some point, but for now I want to implement the
1328 * protocol and not extend it, so I "disable" monitors by setting them to
1329 * show the same thing as the first enabled monitor (see @a
1330 * vboxGetPrimaryIndex).
1331 * - The third is that the code has to work around HGSMI's special handling of
1332 * the primary screen. X.Org doesn't have the same concept, and can move
1333 * the primary about the virtual desktop (not such an issue) and can also
1334 * disable the first screen.
1335 */
1336static Bool
1337VBOXSetMode(ScrnInfoPtr pScrn, unsigned cDisplay, unsigned cWidth,
1338 unsigned cHeight, int x, int y)
1339{
1340 VBOXPtr pVBox = VBOXGetRec(pScrn);
1341 Bool rc = TRUE;
1342 Bool fPrimaryMoved = FALSE;
1343 uint32_t cPrimary, cIndex;
1344 uint32_t cwReal, chReal;
1345 int32_t cxRel, cyRel, cxReal, cyReal, cxOld, cyOld;
1346
1347 TRACE_LOG("cDisplay=%u, cWidth=%u, cHeight=%u, x=%d, y=%d, displayWidth=%d\n",
1348 cDisplay, cWidth, cHeight, x, y, pScrn->displayWidth);
1349 cxOld = pVBox->aScreenLocation[cDisplay].cx;
1350 cyOld = pVBox->aScreenLocation[cDisplay].cy;
1351 pVBox->aScreenLocation[cDisplay].cx = cWidth;
1352 pVBox->aScreenLocation[cDisplay].cy = cHeight;
1353 pVBox->aScreenLocation[cDisplay].x = x;
1354 pVBox->aScreenLocation[cDisplay].y = y;
1355 cPrimary = vboxGetPrimaryIndex(pScrn);
1356 cIndex = vboxGetRealLocationIndex(pScrn, cDisplay);
1357 if (cDisplay == cPrimary && (x != cxOld || y != cyOld))
1358 fPrimaryMoved = TRUE;
1359 cwReal = pVBox->aScreenLocation[cIndex].cx;
1360 chReal = pVBox->aScreenLocation[cIndex].cy;
1361 cxReal = pVBox->aScreenLocation[cIndex].x;
1362 cyReal = pVBox->aScreenLocation[cIndex].y;
1363 cxRel = cxReal - pVBox->aScreenLocation[cPrimary].x;
1364 cyRel = cyReal - pVBox->aScreenLocation[cPrimary].y;
1365 /* Don't fiddle with the hardware if we are switched
1366 * to a virtual terminal. */
1367 if (!pVBox->vtSwitch)
1368 {
1369 TRACE_LOG("setting mode. cWidth=%u, cHeight=%u, cwReal=%u, chReal=%u, pScrn->virtualX=%d, pScrn->virtualY=%d, vboxBPP(pScrn)=%d, x=%d, y=%d, cDisplay=%u, cPrimary=%u, cIndex=%u, cxRel=%d, cyRel=%d, cxReal=%d, cyReal=%d, pVBox->cbLine=%d\n",
1370 cWidth, cHeight, cwReal, chReal, pScrn->virtualX,
1371 pScrn->virtualY, vboxBPP(pScrn), x, y, cDisplay, cPrimary,
1372 cIndex, cxRel, cyRel, cxReal, cyReal, pVBox->cbLine);
1373 if (cDisplay == 0)
1374 VBoxVideoSetModeRegisters(cwReal, chReal, pScrn->displayWidth,
1375 vboxBPP(pScrn), cxReal, cyReal);
1376 /* Tell the host we support graphics */
1377 if (vbox_device_available(pVBox))
1378 vboxEnableGraphicsCap(pVBox);
1379 }
1380 if ( vbox_device_available(pVBox)
1381 && (pVBox->fHaveHGSMI)
1382 && !pVBox->vtSwitch)
1383 VBoxHGSMIProcessDisplayInfo(&pVBox->guestCtx, cDisplay, cxRel, cyRel,
1384 cyReal * pVBox->cbLine
1385 + cxReal * vboxBPP(pScrn) / 8,
1386 pVBox->cbLine,
1387 cwReal, chReal, vboxBPP(pScrn));
1388 /* The guest-host protocol says that first screen is always at offset
1389 * (0,0). Ergo, if the guest changes that offset we need to move all
1390 * other screens in the host to keep the relative positions right. */
1391 if (fPrimaryMoved)
1392 {
1393 unsigned i;
1394 for (i = 1; i < pVBox->cScreens; ++i)
1395 if (i != cPrimary)
1396 VBOXSetMode(pScrn, i, pVBox->aScreenLocation[i].cx,
1397 pVBox->aScreenLocation[i].cy,
1398 pVBox->aScreenLocation[i].x,
1399 pVBox->aScreenLocation[i].y);
1400 }
1401 TRACE_LOG("returning %s\n", rc ? "TRUE" : "FALSE");
1402 return rc;
1403}
1404
1405/** Resize the virtual framebuffer. After resizing we reset all modes
1406 * (X.Org 1.3+) to adjust them to the new framebuffer.
1407 */
1408static Bool VBOXAdjustScreenPixmap(ScrnInfoPtr pScrn, int width, int height)
1409{
1410 ScreenPtr pScreen = pScrn->pScreen;
1411 PixmapPtr pPixmap = pScreen->GetScreenPixmap(pScreen);
1412 VBOXPtr pVBox = VBOXGetRec(pScrn);
1413 uint64_t cbLine = vboxLineLength(pScrn, width);
1414
1415 TRACE_LOG("width=%d, height=%d\n", width, height);
1416 if (!pPixmap) {
1417 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1418 "Failed to get the screen pixmap.\n");
1419 return FALSE;
1420 }
1421 if (cbLine > UINT32_MAX || cbLine * height >= pVBox->cbFramebuffer)
1422 {
1423 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1424 "Unable to set up a virtual screen size of %dx%d with %lu of %d Kb of video memory available. Please increase the video memory size.\n",
1425 width, height, pVBox->cbFramebuffer / 1024, pScrn->videoRam);
1426 return FALSE;
1427 }
1428 pScreen->ModifyPixmapHeader(pPixmap, width, height,
1429 pScrn->depth, vboxBPP(pScrn), cbLine,
1430 pVBox->base);
1431 pScrn->virtualX = width;
1432 pScrn->virtualY = height;
1433 pScrn->displayWidth = vboxDisplayPitch(pScrn, cbLine);
1434 pVBox->cbLine = cbLine;
1435#ifdef VBOX_DRI
1436 if (pVBox->useDRI)
1437 VBOXDRIUpdateStride(pScrn, pVBox);
1438#endif
1439#ifdef VBOXVIDEO_13
1440 /* Write the new values to the hardware */
1441 {
1442 unsigned i;
1443 for (i = 0; i < pVBox->cScreens; ++i)
1444 VBOXSetMode(pScrn, i, pVBox->aScreenLocation[i].cx,
1445 pVBox->aScreenLocation[i].cy,
1446 pVBox->aScreenLocation[i].x,
1447 pVBox->aScreenLocation[i].y);
1448 }
1449#endif
1450 return TRUE;
1451}
1452
1453static void
1454VBOXAdjustFrame(int scrnIndex, int x, int y, int flags)
1455{
1456 VBOXPtr pVBox = VBOXGetRec(xf86Screens[scrnIndex]);
1457 ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1458
1459 TRACE_ENTRY();
1460 /* Don't fiddle with the hardware if we are switched
1461 * to a virtual terminal. */
1462 VBOXSetMode(pScrn, 0, pVBox->aScreenLocation[0].cx,
1463 pVBox->aScreenLocation[0].cy, x, y);
1464 TRACE_EXIT();
1465}
1466
1467static void
1468VBOXFreeScreen(int scrnIndex, int flags)
1469{
1470 VBOXFreeRec(xf86Screens[scrnIndex]);
1471}
1472
1473static Bool
1474VBOXMapVidMem(ScrnInfoPtr pScrn)
1475{
1476 VBOXPtr pVBox = VBOXGetRec(pScrn);
1477 Bool rc = TRUE;
1478
1479 TRACE_ENTRY();
1480 if (!pVBox->base)
1481 {
1482#ifdef PCIACCESS
1483 (void) pci_device_map_range(pVBox->pciInfo,
1484 pScrn->memPhysBase,
1485 pScrn->videoRam * 1024,
1486 PCI_DEV_MAP_FLAG_WRITABLE,
1487 & pVBox->base);
1488#else
1489 pVBox->base = xf86MapPciMem(pScrn->scrnIndex,
1490 VIDMEM_FRAMEBUFFER,
1491 pVBox->pciTag, pScrn->memPhysBase,
1492 (unsigned) pScrn->videoRam * 1024);
1493#endif
1494 if (pVBox->base)
1495 {
1496 /* We need this for saving/restoring textmode */
1497 VGAHWPTR(pScrn)->IOBase = pScrn->domainIOBase;
1498 rc = vgaHWMapMem(pScrn);
1499 }
1500 else
1501 rc = FALSE;
1502 }
1503 TRACE_LOG("returning %s\n", rc ? "TRUE" : "FALSE");
1504 return rc;
1505}
1506
1507static void
1508VBOXUnmapVidMem(ScrnInfoPtr pScrn)
1509{
1510 VBOXPtr pVBox = VBOXGetRec(pScrn);
1511
1512 TRACE_ENTRY();
1513 if (pVBox->base == NULL)
1514 return;
1515
1516#ifdef PCIACCESS
1517 (void) pci_device_unmap_range(pVBox->pciInfo,
1518 pVBox->base,
1519 pScrn->videoRam * 1024);
1520#else
1521 xf86UnMapVidMem(pScrn->scrnIndex, pVBox->base,
1522 (unsigned) pScrn->videoRam * 1024);
1523#endif
1524 vgaHWUnmapMem(pScrn);
1525 pVBox->base = NULL;
1526 TRACE_EXIT();
1527}
1528
1529static Bool
1530VBOXSaveScreen(ScreenPtr pScreen, int mode)
1531{
1532 (void)pScreen; (void)mode;
1533 return TRUE;
1534}
1535
1536Bool
1537VBOXSaveRestore(ScrnInfoPtr pScrn, vbeSaveRestoreFunction function)
1538{
1539 VBOXPtr pVBox;
1540 Bool rc = TRUE;
1541
1542 TRACE_ENTRY();
1543 if (MODE_QUERY < 0 || function > MODE_RESTORE)
1544 rc = FALSE;
1545
1546 if (rc)
1547 {
1548 pVBox = VBOXGetRec(pScrn);
1549
1550 /* Query amount of memory to save state */
1551 if (function == MODE_QUERY ||
1552 (function == MODE_SAVE && pVBox->state == NULL))
1553 {
1554
1555 /* Make sure we save at least this information in case of failure */
1556 (void)VBEGetVBEMode(pVBox->pVbe, &pVBox->stateMode);
1557 vgaHWSaveFonts(pScrn, &pVBox->vgaRegs);
1558
1559 if (!VBESaveRestore(pVBox->pVbe,function,(pointer)&pVBox->state,
1560 &pVBox->stateSize,&pVBox->statePage)
1561 )
1562 rc = FALSE;
1563 }
1564 }
1565 if (rc)
1566 {
1567 /* Save/Restore Super VGA state */
1568 if (function != MODE_QUERY) {
1569
1570 if (function == MODE_RESTORE)
1571 memcpy(pVBox->state, pVBox->pstate,
1572 (unsigned) pVBox->stateSize);
1573
1574 if ( (rc = VBESaveRestore(pVBox->pVbe,function,
1575 (pointer)&pVBox->state,
1576 &pVBox->stateSize,&pVBox->statePage)
1577 )
1578 && (function == MODE_SAVE)
1579 )
1580 {
1581 /* don't rely on the memory not being touched */
1582 if (pVBox->pstate == NULL)
1583 pVBox->pstate = malloc(pVBox->stateSize);
1584 memcpy(pVBox->pstate, pVBox->state,
1585 (unsigned) pVBox->stateSize);
1586 }
1587
1588 if (function == MODE_RESTORE)
1589 {
1590 VBESetVBEMode(pVBox->pVbe, pVBox->stateMode, NULL);
1591 vgaHWRestoreFonts(pScrn, &pVBox->vgaRegs);
1592 }
1593 }
1594 }
1595 TRACE_LOG("returning %s\n", rc ? "TRUE" : "FALSE");
1596 return rc;
1597}
1598
1599static void
1600VBOXDisplayPowerManagementSet(ScrnInfoPtr pScrn, int mode,
1601 int flags)
1602{
1603 (void)pScrn; (void)mode; (void) flags;
1604}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette