VirtualBox

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

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

Additions/VBoxVideo: support disabling the screen via VBVA_SCREEN_F_DISABLE

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 47.1 KB
Line 
1/* $Id: vboxvideo.c 35150 2010-12-15 16:33:59Z 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/** Set a graphics mode. Poke any required values into registers, do an HGSMI
1284 * mode set and tell the host we support advanced graphics functions. This
1285 * procedure is complicated by the fact that X.Org can implicitly disable a
1286 * screen by resizing the virtual framebuffer so that the screen is no longer
1287 * inside it. We have to spot and handle this.
1288 */
1289static Bool
1290VBOXSetMode(ScrnInfoPtr pScrn, unsigned cDisplay, unsigned cWidth,
1291 unsigned cHeight, int x, int y)
1292{
1293 VBOXPtr pVBox = VBOXGetRec(pScrn);
1294 Bool rc = TRUE, fActive = TRUE;
1295 uint32_t offStart, cwReal;
1296
1297 TRACE_LOG("cDisplay=%u, cWidth=%u, cHeight=%u, x=%d, y=%d, displayWidth=%d\n",
1298 cDisplay, cWidth, cHeight, x, y, pScrn->displayWidth);
1299 pVBox->aScreenLocation[cDisplay].cx = cWidth;
1300 pVBox->aScreenLocation[cDisplay].cy = cHeight;
1301 pVBox->aScreenLocation[cDisplay].x = x;
1302 pVBox->aScreenLocation[cDisplay].y = y;
1303 offStart = y * pVBox->cbLine + x * vboxBPP(pScrn) / 8;
1304 /* Deactivate the screen if the mode - specifically the virtual width - is
1305 * too large for VRAM as we sometimes have to do this - see comments in
1306 * VBOXPreInit. */
1307 if (offStart + pVBox->cbLine * cHeight > pVBox->cbFramebuffer)
1308 fActive = FALSE;
1309 /* Deactivate the screen if it is outside of the virtual framebuffer and
1310 * clamp it to lie inside if it is partly outside. */
1311 if (x >= pScrn->displayWidth || x + (int) cWidth <= 0)
1312 fActive = FALSE;
1313 else
1314 cwReal = RT_MIN((int) cWidth, pScrn->displayWidth - x);
1315 /* Don't fiddle with the hardware if we are switched
1316 * to a virtual terminal. */
1317 if (!pVBox->vtSwitch && fActive)
1318 {
1319 if (cDisplay == 0)
1320 VBoxVideoSetModeRegisters(cwReal, cHeight, pScrn->displayWidth,
1321 vboxBPP(pScrn), x, y);
1322 /* Tell the host we support graphics */
1323 if (vbox_device_available(pVBox))
1324 vboxEnableGraphicsCap(pVBox);
1325 }
1326 if ( vbox_device_available(pVBox)
1327 && (pVBox->fHaveHGSMI)
1328 && !pVBox->vtSwitch)
1329 VBoxHGSMIProcessDisplayInfo(&pVBox->guestCtx, cDisplay, x, y,
1330 offStart, pVBox->cbLine, cwReal, cHeight,
1331 vboxBPP(pScrn),
1332 VBVA_SCREEN_F_ACTIVE
1333 | (fActive ? 0: VBVA_SCREEN_F_DISABLED));
1334 TRACE_LOG("returning %s\n", rc ? "TRUE" : "FALSE");
1335 return rc;
1336}
1337
1338/** Resize the virtual framebuffer. After resizing we reset all modes
1339 * (X.Org 1.3+) to adjust them to the new framebuffer.
1340 */
1341static Bool VBOXAdjustScreenPixmap(ScrnInfoPtr pScrn, int width, int height)
1342{
1343 ScreenPtr pScreen = pScrn->pScreen;
1344 PixmapPtr pPixmap = pScreen->GetScreenPixmap(pScreen);
1345 VBOXPtr pVBox = VBOXGetRec(pScrn);
1346 uint64_t cbLine = vboxLineLength(pScrn, width);
1347
1348 TRACE_LOG("width=%d, height=%d\n", width, height);
1349 if (!pPixmap) {
1350 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1351 "Failed to get the screen pixmap.\n");
1352 return FALSE;
1353 }
1354 if (cbLine > UINT32_MAX || cbLine * height >= pVBox->cbFramebuffer)
1355 {
1356 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1357 "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",
1358 width, height, pVBox->cbFramebuffer / 1024, pScrn->videoRam);
1359 return FALSE;
1360 }
1361 pScreen->ModifyPixmapHeader(pPixmap, width, height,
1362 pScrn->depth, vboxBPP(pScrn), cbLine,
1363 pVBox->base);
1364 pScrn->virtualX = width;
1365 pScrn->virtualY = height;
1366 pScrn->displayWidth = vboxDisplayPitch(pScrn, cbLine);
1367 pVBox->cbLine = cbLine;
1368#ifdef VBOX_DRI
1369 if (pVBox->useDRI)
1370 VBOXDRIUpdateStride(pScrn, pVBox);
1371#endif
1372#ifdef VBOXVIDEO_13
1373 /* Write the new values to the hardware */
1374 {
1375 unsigned i;
1376 for (i = 0; i < pVBox->cScreens; ++i)
1377 VBOXSetMode(pScrn, i, pVBox->aScreenLocation[i].cx,
1378 pVBox->aScreenLocation[i].cy,
1379 pVBox->aScreenLocation[i].x,
1380 pVBox->aScreenLocation[i].y);
1381 }
1382#endif
1383 return TRUE;
1384}
1385
1386static void
1387VBOXAdjustFrame(int scrnIndex, int x, int y, int flags)
1388{
1389 VBOXPtr pVBox = VBOXGetRec(xf86Screens[scrnIndex]);
1390 ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1391
1392 TRACE_ENTRY();
1393 /* Don't fiddle with the hardware if we are switched
1394 * to a virtual terminal. */
1395 VBOXSetMode(pScrn, 0, pVBox->aScreenLocation[0].cx,
1396 pVBox->aScreenLocation[0].cy, x, y);
1397 TRACE_EXIT();
1398}
1399
1400static void
1401VBOXFreeScreen(int scrnIndex, int flags)
1402{
1403 VBOXFreeRec(xf86Screens[scrnIndex]);
1404}
1405
1406static Bool
1407VBOXMapVidMem(ScrnInfoPtr pScrn)
1408{
1409 VBOXPtr pVBox = VBOXGetRec(pScrn);
1410 Bool rc = TRUE;
1411
1412 TRACE_ENTRY();
1413 if (!pVBox->base)
1414 {
1415#ifdef PCIACCESS
1416 (void) pci_device_map_range(pVBox->pciInfo,
1417 pScrn->memPhysBase,
1418 pScrn->videoRam * 1024,
1419 PCI_DEV_MAP_FLAG_WRITABLE,
1420 & pVBox->base);
1421#else
1422 pVBox->base = xf86MapPciMem(pScrn->scrnIndex,
1423 VIDMEM_FRAMEBUFFER,
1424 pVBox->pciTag, pScrn->memPhysBase,
1425 (unsigned) pScrn->videoRam * 1024);
1426#endif
1427 if (pVBox->base)
1428 {
1429 /* We need this for saving/restoring textmode */
1430 VGAHWPTR(pScrn)->IOBase = pScrn->domainIOBase;
1431 rc = vgaHWMapMem(pScrn);
1432 }
1433 else
1434 rc = FALSE;
1435 }
1436 TRACE_LOG("returning %s\n", rc ? "TRUE" : "FALSE");
1437 return rc;
1438}
1439
1440static void
1441VBOXUnmapVidMem(ScrnInfoPtr pScrn)
1442{
1443 VBOXPtr pVBox = VBOXGetRec(pScrn);
1444
1445 TRACE_ENTRY();
1446 if (pVBox->base == NULL)
1447 return;
1448
1449#ifdef PCIACCESS
1450 (void) pci_device_unmap_range(pVBox->pciInfo,
1451 pVBox->base,
1452 pScrn->videoRam * 1024);
1453#else
1454 xf86UnMapVidMem(pScrn->scrnIndex, pVBox->base,
1455 (unsigned) pScrn->videoRam * 1024);
1456#endif
1457 vgaHWUnmapMem(pScrn);
1458 pVBox->base = NULL;
1459 TRACE_EXIT();
1460}
1461
1462static Bool
1463VBOXSaveScreen(ScreenPtr pScreen, int mode)
1464{
1465 (void)pScreen; (void)mode;
1466 return TRUE;
1467}
1468
1469Bool
1470VBOXSaveRestore(ScrnInfoPtr pScrn, vbeSaveRestoreFunction function)
1471{
1472 VBOXPtr pVBox;
1473 Bool rc = TRUE;
1474
1475 TRACE_ENTRY();
1476 if (MODE_QUERY < 0 || function > MODE_RESTORE)
1477 rc = FALSE;
1478
1479 if (rc)
1480 {
1481 pVBox = VBOXGetRec(pScrn);
1482
1483 /* Query amount of memory to save state */
1484 if (function == MODE_QUERY ||
1485 (function == MODE_SAVE && pVBox->state == NULL))
1486 {
1487
1488 /* Make sure we save at least this information in case of failure */
1489 (void)VBEGetVBEMode(pVBox->pVbe, &pVBox->stateMode);
1490 vgaHWSaveFonts(pScrn, &pVBox->vgaRegs);
1491
1492 if (!VBESaveRestore(pVBox->pVbe,function,(pointer)&pVBox->state,
1493 &pVBox->stateSize,&pVBox->statePage)
1494 )
1495 rc = FALSE;
1496 }
1497 }
1498 if (rc)
1499 {
1500 /* Save/Restore Super VGA state */
1501 if (function != MODE_QUERY) {
1502
1503 if (function == MODE_RESTORE)
1504 memcpy(pVBox->state, pVBox->pstate,
1505 (unsigned) pVBox->stateSize);
1506
1507 if ( (rc = VBESaveRestore(pVBox->pVbe,function,
1508 (pointer)&pVBox->state,
1509 &pVBox->stateSize,&pVBox->statePage)
1510 )
1511 && (function == MODE_SAVE)
1512 )
1513 {
1514 /* don't rely on the memory not being touched */
1515 if (pVBox->pstate == NULL)
1516 pVBox->pstate = malloc(pVBox->stateSize);
1517 memcpy(pVBox->pstate, pVBox->state,
1518 (unsigned) pVBox->stateSize);
1519 }
1520
1521 if (function == MODE_RESTORE)
1522 {
1523 VBESetVBEMode(pVBox->pVbe, pVBox->stateMode, NULL);
1524 vgaHWRestoreFonts(pScrn, &pVBox->vgaRegs);
1525 }
1526 }
1527 }
1528 TRACE_LOG("returning %s\n", rc ? "TRUE" : "FALSE");
1529 return rc;
1530}
1531
1532static void
1533VBOXDisplayPowerManagementSet(ScrnInfoPtr pScrn, int mode,
1534 int flags)
1535{
1536 (void)pScrn; (void)mode; (void) flags;
1537}
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