VirtualBox

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

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

Additions/x11/vboxvideo: add EDID

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