VirtualBox

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

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

Additions/x11/vboxvideo: blank the screen on server termination and VT switches too

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