VirtualBox

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

Last change on this file since 21219 was 20618, checked in by vboxsync, 16 years ago

Additions/x11/vboxvideo: fix for systems without DRI

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 52.7 KB
Line 
1/** @file
2 *
3 * Linux Additions X11 graphics driver
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 * --------------------------------------------------------------------
21 *
22 * This code is based on:
23 *
24 * X11 VESA driver
25 *
26 * Copyright (c) 2000 by Conectiva S.A. (http://www.conectiva.com)
27 *
28 * Permission is hereby granted, free of charge, to any person obtaining a
29 * copy of this software and associated documentation files (the "Software"),
30 * to deal in the Software without restriction, including without limitation
31 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
32 * and/or sell copies of the Software, and to permit persons to whom the
33 * Software is furnished to do so, subject to the following conditions:
34 *
35 * The above copyright notice and this permission notice shall be included in
36 * all copies or substantial portions of the Software.
37 *
38 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
39 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
40 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
41 * CONECTIVA LINUX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
42 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
43 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
44 * SOFTWARE.
45 *
46 * Except as contained in this notice, the name of Conectiva Linux shall
47 * not be used in advertising or otherwise to promote the sale, use or other
48 * dealings in this Software without prior written authorization from
49 * Conectiva Linux.
50 *
51 * Authors: Paulo César Pereira de Andrade <[email protected]>
52 */
53
54#include "xorg-server.h"
55#include "vboxvideo.h"
56#include "version-generated.h"
57#include <xf86.h>
58
59/* All drivers initialising the SW cursor need this */
60#include "mipointer.h"
61
62/* All drivers implementing backing store need this */
63#include "mibstore.h"
64
65/* Colormap handling */
66#include "micmap.h"
67#include "xf86cmap.h"
68
69/* DPMS */
70/* #define DPMS_SERVER
71#include "extensions/dpms.h" */
72
73/* X.org 1.3+ mode setting */
74#include "xf86Crtc.h"
75#include "xf86Modes.h"
76
77/* Mandatory functions */
78
79static const OptionInfoRec * VBOXAvailableOptions(int chipid, int busid);
80static void VBOXIdentify(int flags);
81#ifndef PCIACCESS
82static Bool VBOXProbe(DriverPtr drv, int flags);
83#else
84static Bool VBOXPciProbe(DriverPtr drv, int entity_num,
85 struct pci_device *dev, intptr_t match_data);
86#endif
87static Bool VBOXPreInit(ScrnInfoPtr pScrn, int flags);
88static Bool VBOXScreenInit(int Index, ScreenPtr pScreen, int argc,
89 char **argv);
90static Bool VBOXEnterVT(int scrnIndex, int flags);
91static void VBOXLeaveVT(int scrnIndex, int flags);
92static Bool VBOXCloseScreen(int scrnIndex, ScreenPtr pScreen);
93static Bool VBOXSwitchMode(int scrnIndex, DisplayModePtr pMode, int flags);
94static ModeStatus VBOXValidMode(int scrn, DisplayModePtr p, Bool flag, int pass);
95static Bool VBOXSetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode);
96static void VBOXAdjustFrame(int scrnIndex, int x, int y, int flags);
97static void VBOXFreeScreen(int scrnIndex, int flags);
98static void VBOXFreeRec(ScrnInfoPtr pScrn);
99
100/* locally used functions */
101static Bool VBOXMapVidMem(ScrnInfoPtr pScrn);
102static void VBOXUnmapVidMem(ScrnInfoPtr pScrn);
103static void VBOXLoadPalette(ScrnInfoPtr pScrn, int numColors,
104 int *indices,
105 LOCO *colors, VisualPtr pVisual);
106static void SaveFonts(ScrnInfoPtr pScrn);
107static void RestoreFonts(ScrnInfoPtr pScrn);
108static Bool VBOXSaveRestore(ScrnInfoPtr pScrn,
109 vbeSaveRestoreFunction function);
110
111enum GenericTypes
112{
113 CHIP_VBOX_GENERIC
114};
115
116#ifdef PCIACCESS
117static const struct pci_id_match vbox_device_match[] = {
118 {
119 VBOX_VENDORID, VBOX_DEVICEID, PCI_MATCH_ANY, PCI_MATCH_ANY,
120 0, 0, 0
121 },
122
123 { 0, 0, 0 },
124};
125#endif
126
127/* Supported chipsets */
128static SymTabRec VBOXChipsets[] =
129{
130 {VBOX_DEVICEID, "vbox"},
131 {-1, NULL}
132};
133
134static PciChipsets VBOXPCIchipsets[] = {
135 { VBOX_DEVICEID, VBOX_DEVICEID, RES_SHARED_VGA },
136 { -1, -1, RES_UNDEFINED },
137};
138
139/*
140 * This contains the functions needed by the server after loading the
141 * driver module. It must be supplied, and gets added the driver list by
142 * the Module Setup funtion in the dynamic case. In the static case a
143 * reference to this is compiled in, and this requires that the name of
144 * this DriverRec be an upper-case version of the driver name.
145 */
146
147_X_EXPORT DriverRec VBOXDRV = {
148 VBOX_VERSION,
149 VBOX_DRIVER_NAME,
150 VBOXIdentify,
151#ifdef PCIACCESS
152 NULL,
153#else
154 VBOXProbe,
155#endif
156 VBOXAvailableOptions,
157 NULL,
158 0,
159 NULL,
160
161#ifdef PCIACCESS
162 vbox_device_match,
163 VBOXPciProbe
164#endif
165};
166
167/* No options for now */
168static const OptionInfoRec VBOXOptions[] = {
169 { -1, NULL, OPTV_NONE, {0}, FALSE }
170};
171
172static VBOXPtr
173VBOXGetRec(ScrnInfoPtr pScrn)
174{
175 if (!pScrn->driverPrivate) {
176 pScrn->driverPrivate = xcalloc(sizeof(VBOXRec), 1);
177 }
178
179 return ((VBOXPtr)pScrn->driverPrivate);
180}
181
182static void
183VBOXFreeRec(ScrnInfoPtr pScrn)
184{
185 VBOXPtr pVBox = VBOXGetRec(pScrn);
186 xfree(pVBox->savedPal);
187 xfree(pVBox->fonts);
188 xfree(pScrn->driverPrivate);
189 pScrn->driverPrivate = NULL;
190}
191
192/* X.org 1.3+ mode-setting support ******************************************/
193
194/* For descriptions of these functions and structures, see
195 hw/xfree86/modes/xf86Crtc.h and hw/xfree86/modes/xf86Modes.h in the
196 X.Org source tree. */
197
198static Bool
199VBOXCrtcResize(ScrnInfoPtr scrn, int width, int height)
200{
201 int bpp = scrn->bitsPerPixel;
202 ScreenPtr pScreen = scrn->pScreen;
203 PixmapPtr pPixmap = NULL;
204 VBOXPtr pVBox = VBOXGetRec(scrn);
205 Bool rc = TRUE;
206
207 TRACE_LOG("width=%d, height=%d\n", width, height);
208 /* We only support horizontal resolutions which are a multiple of 8. Round down if
209 necessary. */
210 if (width % 8 != 0)
211 {
212 xf86DrvMsg(scrn->scrnIndex, X_WARNING,
213 "VirtualBox only supports virtual screen widths which are a multiple of 8. Rounding down from %d to %d\n",
214 width, width - (width % 8));
215 width = width - (width % 8);
216 }
217 if (width * height * bpp / 8 >= scrn->videoRam * 1024)
218 {
219 xf86DrvMsg(scrn->scrnIndex, X_ERROR,
220 "Unable to set up a virtual screen size of %dx%d with %d Kb of video memory. Please increase the video memory size.\n",
221 width, height, scrn->videoRam);
222 rc = FALSE;
223 }
224 if (rc) {
225 pPixmap = pScreen->GetScreenPixmap(pScreen);
226 if (NULL == pPixmap) {
227 xf86DrvMsg(scrn->scrnIndex, X_ERROR,
228 "Failed to get the screen pixmap.\n");
229 rc = FALSE;
230 }
231 }
232 if (rc) {
233 if (
234 !pScreen->ModifyPixmapHeader(pPixmap, width, height,
235 scrn->depth, bpp, width * bpp / 8,
236 pVBox->base)
237 ) {
238 xf86DrvMsg(scrn->scrnIndex, X_ERROR,
239 "Failed to set up the screen pixmap.\n");
240 rc = FALSE;
241 }
242 }
243 if (rc) {
244 scrn->virtualX = width;
245 scrn->virtualY = height;
246 scrn->displayWidth = width;
247#ifdef VBOX_DRI
248 if (pVBox->useDRI)
249 VBOXDRIUpdateStride(scrn, pVBox);
250#endif
251 }
252 TRACE_LOG("returning %s\n", rc ? "TRUE" : "FALSE");
253 return rc;
254}
255
256static const xf86CrtcConfigFuncsRec VBOXCrtcConfigFuncs = {
257 VBOXCrtcResize
258};
259
260static void
261vbox_crtc_dpms(xf86CrtcPtr crtc, int mode)
262{ (void) crtc; (void) mode; }
263
264static Bool
265vbox_crtc_lock (xf86CrtcPtr crtc)
266{ (void) crtc; return FALSE; }
267
268static Bool
269vbox_crtc_mode_fixup (xf86CrtcPtr crtc, DisplayModePtr mode,
270 DisplayModePtr adjusted_mode)
271{
272 ScrnInfoPtr pScrn = crtc->scrn;
273 int xRes = adjusted_mode->HDisplay;
274
275 (void) mode;
276 TRACE_LOG("name=%s, HDisplay=%d, VDisplay=%d\n", adjusted_mode->name,
277 adjusted_mode->HDisplay, adjusted_mode->VDisplay);
278 /* We only support horizontal resolutions which are a multiple of 8. Round down if
279 necessary. */
280 if (xRes % 8 != 0)
281 {
282 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
283 "VirtualBox only supports screen widths which are a multiple of 8. Rounding down from %d to %d\n",
284 xRes, xRes - (xRes % 8));
285 adjusted_mode->HDisplay = xRes - (xRes % 8);
286 }
287 return TRUE;
288}
289
290static void
291vbox_crtc_stub (xf86CrtcPtr crtc)
292{ (void) crtc; }
293
294static void
295vbox_crtc_mode_set (xf86CrtcPtr crtc, DisplayModePtr mode,
296 DisplayModePtr adjusted_mode, int x, int y)
297{
298 (void) mode;
299 TRACE_LOG("name=%s, HDisplay=%d, VDisplay=%d, x=%d, y=%d\n", adjusted_mode->name,
300 adjusted_mode->HDisplay, adjusted_mode->VDisplay, x, y);
301 VBOXSetMode(crtc->scrn, adjusted_mode);
302 VBOXAdjustFrame(crtc->scrn->scrnIndex, x, y, 0);
303 vboxSaveVideoMode(crtc->scrn, adjusted_mode->HDisplay,
304 adjusted_mode->VDisplay, crtc->scrn->bitsPerPixel);
305}
306
307static void
308vbox_crtc_gamma_set (xf86CrtcPtr crtc, CARD16 *red,
309 CARD16 *green, CARD16 *blue, int size)
310{ (void) crtc; (void) red; (void) green; (void) blue; (void) size; }
311
312static void *
313vbox_crtc_shadow_allocate (xf86CrtcPtr crtc, int width, int height)
314{ (void) crtc; (void) width; (void) height; return NULL; }
315
316static const xf86CrtcFuncsRec VBOXCrtcFuncs = {
317 .dpms = vbox_crtc_dpms,
318 .save = NULL, /* These two are never called by the server. */
319 .restore = NULL,
320 .lock = vbox_crtc_lock,
321 .unlock = NULL, /* This will not be invoked if lock returns FALSE. */
322 .mode_fixup = vbox_crtc_mode_fixup,
323 .prepare = vbox_crtc_stub,
324 .mode_set = vbox_crtc_mode_set,
325 .commit = vbox_crtc_stub,
326 .gamma_set = vbox_crtc_gamma_set,
327 .shadow_allocate = vbox_crtc_shadow_allocate,
328 .shadow_create = NULL, /* These two should not be invoked if allocate
329 returns NULL. */
330 .shadow_destroy = NULL,
331 .set_cursor_colors = NULL, /* We are still using the old cursor API. */
332 .set_cursor_position = NULL,
333 .show_cursor = NULL,
334 .hide_cursor = NULL,
335 .load_cursor_argb = NULL,
336 .destroy = vbox_crtc_stub
337};
338
339static void
340vbox_output_stub (xf86OutputPtr output)
341{ (void) output; }
342
343static void
344vbox_output_dpms (xf86OutputPtr output, int mode)
345{ (void) output; (void) mode; }
346
347static int
348vbox_output_mode_valid (xf86OutputPtr output, DisplayModePtr mode)
349{
350 ScrnInfoPtr pScrn = output->scrn;
351 int rc = MODE_OK;
352 TRACE_LOG("HDisplay=%d, VDisplay=%d\n", mode->HDisplay, mode->VDisplay);
353 /* We always like modes specified by the user in the configuration
354 * file, as doing otherwise is likely to annoy people. */
355 if ( !(mode->type & M_T_USERDEF)
356 && vbox_device_available(VBOXGetRec(pScrn))
357 && !vboxHostLikesVideoMode(pScrn, mode->HDisplay, mode->VDisplay,
358 pScrn->bitsPerPixel)
359 )
360 rc = MODE_BAD;
361 TRACE_LOG("returning %s\n", MODE_OK == rc ? "MODE_OK" : "MODE_BAD");
362 return rc;
363}
364
365static Bool
366vbox_output_mode_fixup (xf86OutputPtr output, DisplayModePtr mode,
367 DisplayModePtr adjusted_mode)
368{ (void) output; (void) mode; (void) adjusted_mode; return TRUE; }
369
370static void
371vbox_output_mode_set (xf86OutputPtr output, DisplayModePtr mode,
372 DisplayModePtr adjusted_mode)
373{ (void) output; (void) mode; (void) adjusted_mode; }
374
375/* A virtual monitor is always connected. */
376static xf86OutputStatus
377vbox_output_detect (xf86OutputPtr output)
378{
379 (void) output;
380 return XF86OutputStatusConnected;
381}
382
383static void
384vbox_output_add_mode (DisplayModePtr *pModes, const char *pszName, int x, int y,
385 Bool isPreferred, Bool isUserDef)
386{
387 TRACE_LOG("pszName=%s, x=%d, y=%d\n", pszName, x, y);
388 DisplayModePtr pMode = xnfcalloc(1, sizeof(DisplayModeRec));
389
390 pMode->status = MODE_OK;
391 /* We don't ask the host whether it likes user defined modes,
392 * as we assume that the user really wanted that mode. */
393 pMode->type = isUserDef ? M_T_USERDEF : M_T_BUILTIN;
394 if (isPreferred)
395 pMode->type |= M_T_PREFERRED;
396 /* VBox only supports screen widths which are a multiple of 8 */
397 pMode->HDisplay = (x + 7) & ~7;
398 pMode->HSyncStart = pMode->HDisplay + 2;
399 pMode->HSyncEnd = pMode->HDisplay + 4;
400 pMode->HTotal = pMode->HDisplay + 6;
401 pMode->VDisplay = y;
402 pMode->VSyncStart = pMode->VDisplay + 2;
403 pMode->VSyncEnd = pMode->VDisplay + 4;
404 pMode->VTotal = pMode->VDisplay + 6;
405 pMode->Clock = pMode->HTotal * pMode->VTotal * 60 / 1000; /* kHz */
406 if (NULL == pszName) {
407 xf86SetModeDefaultName(pMode);
408 } else {
409 pMode->name = xnfstrdup(pszName);
410 }
411 *pModes = xf86ModesAdd(*pModes, pMode);
412}
413
414static DisplayModePtr
415vbox_output_get_modes (xf86OutputPtr output)
416{
417 bool rc;
418 unsigned i;
419 DisplayModePtr pModes = NULL;
420 ScrnInfoPtr pScrn = output->scrn;
421 VBOXPtr pVBox = VBOXGetRec(pScrn);
422
423 TRACE_ENTRY();
424 if (vbox_device_available(pVBox))
425 {
426 uint32_t x, y, bpp, display;
427 rc = vboxGetDisplayChangeRequest(pScrn, &x, &y, &bpp, &display);
428 /* @todo - check the display number once we support multiple displays. */
429 /* If we don't find a display request, see if we have a saved hint
430 * from a previous session. */
431 if (!rc || (0 == x) || (0 == y))
432 rc = vboxRetrieveVideoMode(pScrn, &x, &y, &bpp);
433 if (rc && (0 != x) && (0 != y)) {
434 /* We prefer a slightly smaller size to a slightly larger one */
435 x -= (x % 8);
436 vbox_output_add_mode(&pModes, NULL, x, y, TRUE, FALSE);
437 }
438 }
439 /* Also report any modes the user may have requested in the xorg.conf
440 * configuration file. */
441 for (i = 0; pScrn->display->modes[i] != NULL; i++)
442 {
443 int x, y;
444 if (2 == sscanf(pScrn->display->modes[i], "%dx%d", &x, &y))
445 vbox_output_add_mode(&pModes, pScrn->display->modes[i], x, y,
446 FALSE, TRUE);
447 }
448 TRACE_EXIT();
449 return pModes;
450}
451
452#ifdef RANDR_12_INTERFACE
453/* We don't yet have mutable properties, whatever they are. */
454static Bool
455vbox_output_set_property(xf86OutputPtr output, Atom property,
456 RRPropertyValuePtr value)
457{ (void) output; (void) property; (void) value; return FALSE; }
458#endif
459
460static const xf86OutputFuncsRec VBOXOutputFuncs = {
461 .create_resources = vbox_output_stub,
462 .dpms = vbox_output_dpms,
463 .save = NULL, /* These two are never called by the server. */
464 .restore = NULL,
465 .mode_valid = vbox_output_mode_valid,
466 .mode_fixup = vbox_output_mode_fixup,
467 .prepare = vbox_output_stub,
468 .commit = vbox_output_stub,
469 .mode_set = vbox_output_mode_set,
470 .detect = vbox_output_detect,
471 .get_modes = vbox_output_get_modes,
472#ifdef RANDR_12_INTERFACE
473 .set_property = vbox_output_set_property,
474#endif
475 .destroy = vbox_output_stub
476};
477
478/*
479 * List of symbols from other modules that this module references. This
480 * list is used to tell the loader that it is OK for symbols here to be
481 * unresolved providing that it hasn't been told that they are essential
482 * via a call to xf86LoaderReqSymbols() or xf86LoaderReqSymLists(). The
483 * purpose is this is to avoid warnings about unresolved symbols that are
484 * not required.
485 */
486static const char *fbSymbols[] = {
487 "fbPictureInit",
488 "fbScreenInit",
489 NULL
490};
491
492static const char *shadowfbSymbols[] = {
493 "ShadowFBInit2",
494 NULL
495};
496
497static const char *vbeSymbols[] = {
498 "VBEExtendedInit",
499 "VBEFindSupportedDepths",
500 "VBEGetModeInfo",
501 "VBEGetVBEInfo",
502 "VBEGetVBEMode",
503 "VBEPrintModes",
504 "VBESaveRestore",
505 "VBESetDisplayStart",
506 "VBESetGetDACPaletteFormat",
507 "VBESetGetLogicalScanlineLength",
508 "VBESetGetPaletteData",
509 "VBESetModeNames",
510 "VBESetModeParameters",
511 "VBESetVBEMode",
512 "VBEValidateModes",
513 "vbeDoEDID",
514 "vbeFree",
515 NULL
516};
517
518static const char *ramdacSymbols[] = {
519 "xf86InitCursor",
520 "xf86CreateCursorInfoRec",
521 NULL
522};
523
524#ifdef VBOX_DRI
525static const char *drmSymbols[] = {
526 "drmFreeVersion",
527 "drmGetVersion",
528 NULL
529};
530
531static const char *driSymbols[] = {
532 "DRICloseScreen",
533 "DRICreateInfoRec",
534 "DRIDestroyInfoRec",
535 "DRIFinishScreenInit",
536 "DRIGetSAREAPrivate",
537 "DRILock",
538 "DRIMoveBuffersHelper",
539 "DRIQueryVersion",
540 "DRIScreenInit",
541 "DRIUnlock",
542 "GlxSetVisualConfigs",
543 "DRICreatePCIBusID",
544 NULL
545};
546#endif
547
548#ifdef XFree86LOADER
549/* Module loader interface */
550static MODULESETUPPROTO(vboxSetup);
551
552static XF86ModuleVersionInfo vboxVersionRec =
553{
554 VBOX_DRIVER_NAME,
555 "Sun Microsystems, Inc.",
556 MODINFOSTRING1,
557 MODINFOSTRING2,
558 XORG_VERSION_CURRENT,
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_X_EXPORT XF86ModuleData vboxvideoModuleData = { &vboxVersionRec, vboxSetup, NULL };
573
574static pointer
575vboxSetup(pointer Module, pointer Options, int *ErrorMajor, int *ErrorMinor)
576{
577 static Bool Initialised = FALSE;
578
579 if (!Initialised)
580 {
581 Initialised = TRUE;
582#ifdef PCIACCESS
583 xf86AddDriver(&VBOXDRV, Module, HaveDriverFuncs);
584#else
585 xf86AddDriver(&VBOXDRV, Module, 0);
586#endif
587 LoaderRefSymLists(fbSymbols,
588 shadowfbSymbols,
589 vbeSymbols,
590 ramdacSymbols,
591#ifdef VBOX_DRI
592 drmSymbols, driSymbols,
593#endif
594 NULL);
595 return (pointer)TRUE;
596 }
597
598 if (ErrorMajor)
599 *ErrorMajor = LDR_ONCEONLY;
600 return (NULL);
601}
602
603#endif /* XFree86Loader defined */
604
605static const OptionInfoRec *
606VBOXAvailableOptions(int chipid, int busid)
607{
608 return (VBOXOptions);
609}
610
611static void
612VBOXIdentify(int flags)
613{
614 xf86PrintChipsets(VBOX_NAME, "guest driver for VirtualBox", VBOXChipsets);
615}
616
617/*
618 * This function is called once, at the start of the first server generation to
619 * do a minimal probe for supported hardware.
620 */
621
622#ifdef PCIACCESS
623static Bool
624VBOXPciProbe(DriverPtr drv, int entity_num, struct pci_device *dev,
625 intptr_t match_data)
626{
627 ScrnInfoPtr pScrn;
628
629 TRACE_ENTRY();
630 pScrn = xf86ConfigPciEntity(NULL, 0, entity_num, VBOXPCIchipsets,
631 NULL, NULL, NULL, NULL, NULL);
632 if (pScrn != NULL) {
633 VBOXPtr pVBox = VBOXGetRec(pScrn);
634
635 pScrn->driverVersion = VBOX_VERSION;
636 pScrn->driverName = VBOX_DRIVER_NAME;
637 pScrn->name = VBOX_NAME;
638 pScrn->Probe = NULL;
639 pScrn->PreInit = VBOXPreInit;
640 pScrn->ScreenInit = VBOXScreenInit;
641 pScrn->SwitchMode = VBOXSwitchMode;
642 pScrn->ValidMode = VBOXValidMode;
643 pScrn->AdjustFrame = VBOXAdjustFrame;
644 pScrn->EnterVT = VBOXEnterVT;
645 pScrn->LeaveVT = VBOXLeaveVT;
646 pScrn->FreeScreen = VBOXFreeScreen;
647
648 pVBox->pciInfo = dev;
649 }
650
651 TRACE_LOG("returning %s\n", BOOL_STR(pScrn != NULL));
652 return (pScrn != NULL);
653}
654#endif
655
656#ifndef PCIACCESS
657static Bool
658VBOXProbe(DriverPtr drv, int flags)
659{
660 Bool foundScreen = FALSE;
661 int numDevSections;
662 GDevPtr *devSections;
663
664 /*
665 * Find the config file Device sections that match this
666 * driver, and return if there are none.
667 */
668 if ((numDevSections = xf86MatchDevice(VBOX_NAME,
669 &devSections)) <= 0)
670 return (FALSE);
671
672 /* PCI BUS */
673 if (xf86GetPciVideoInfo()) {
674 int numUsed;
675 int *usedChips;
676 int i;
677 numUsed = xf86MatchPciInstances(VBOX_NAME, VBOX_VENDORID,
678 VBOXChipsets, VBOXPCIchipsets,
679 devSections, numDevSections,
680 drv, &usedChips);
681 if (numUsed > 0) {
682 if (flags & PROBE_DETECT)
683 foundScreen = TRUE;
684 else {
685 for (i = 0; i < numUsed; i++) {
686 ScrnInfoPtr pScrn = NULL;
687 /* Allocate a ScrnInfoRec */
688 if ((pScrn = xf86ConfigPciEntity(pScrn,0,usedChips[i],
689 VBOXPCIchipsets,NULL,
690 NULL,NULL,NULL,NULL))) {
691 pScrn->driverVersion = VBOX_VERSION;
692 pScrn->driverName = VBOX_DRIVER_NAME;
693 pScrn->name = VBOX_NAME;
694 pScrn->Probe = VBOXProbe;
695 pScrn->PreInit = VBOXPreInit;
696 pScrn->ScreenInit = VBOXScreenInit;
697 pScrn->SwitchMode = VBOXSwitchMode;
698 pScrn->ValidMode = VBOXValidMode;
699 pScrn->AdjustFrame = VBOXAdjustFrame;
700 pScrn->EnterVT = VBOXEnterVT;
701 pScrn->LeaveVT = VBOXLeaveVT;
702 pScrn->FreeScreen = VBOXFreeScreen;
703 foundScreen = TRUE;
704 }
705 }
706 }
707 xfree(usedChips);
708 }
709 }
710
711 xfree(devSections);
712
713 return (foundScreen);
714}
715#endif
716
717/*
718 * QUOTE from the XFree86 DESIGN document:
719 *
720 * The purpose of this function is to find out all the information
721 * required to determine if the configuration is usable, and to initialise
722 * those parts of the ScrnInfoRec that can be set once at the beginning of
723 * the first server generation.
724 *
725 * (...)
726 *
727 * This includes probing for video memory, clocks, ramdac, and all other
728 * HW info that is needed. It includes determining the depth/bpp/visual
729 * and related info. It includes validating and determining the set of
730 * video modes that will be used (and anything that is required to
731 * determine that).
732 *
733 * This information should be determined in the least intrusive way
734 * possible. The state of the HW must remain unchanged by this function.
735 * Although video memory (including MMIO) may be mapped within this
736 * function, it must be unmapped before returning.
737 *
738 * END QUOTE
739 */
740
741static Bool
742VBOXPreInit(ScrnInfoPtr pScrn, int flags)
743{
744 VBOXPtr pVBox;
745 Gamma gzeros = {0.0, 0.0, 0.0};
746 rgb rzeros = {0, 0, 0};
747 xf86OutputPtr output;
748
749 /* Are we really starting the server, or is this just a dummy run? */
750 if (flags & PROBE_DETECT)
751 return (FALSE);
752
753 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
754 "VirtualBox guest additions video driver version "
755 VBOX_VERSION_STRING "\n");
756
757 /* Get our private data from the ScrnInfoRec structure. */
758 pVBox = VBOXGetRec(pScrn);
759
760 /* Initialise the guest library */
761 vbox_init(pScrn->scrnIndex, pVBox);
762
763 /* Entity information seems to mean bus information. */
764 pVBox->pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
765
766 /* We need the vbe module because we use VBE code to save and restore
767 text mode, in order to keep our code simple. */
768 if (!xf86LoadSubModule(pScrn, "vbe"))
769 return (FALSE);
770 xf86LoaderReqSymLists(vbeSymbols, NULL);
771
772 if ((pVBox->pVbe = VBEExtendedInit(NULL, pVBox->pEnt->index,
773 SET_BIOS_SCRATCH
774 | RESTORE_BIOS_SCRATCH)) == NULL)
775 return (FALSE);
776
777#ifndef PCIACCESS
778 if (pVBox->pEnt->location.type != BUS_PCI)
779 return FALSE;
780
781 pVBox->pciInfo = xf86GetPciInfoForEntity(pVBox->pEnt->index);
782 pVBox->pciTag = pciTag(pVBox->pciInfo->bus,
783 pVBox->pciInfo->device,
784 pVBox->pciInfo->func);
785#endif
786
787 /* The ramdac module is needed for the hardware cursor. */
788 if (!xf86LoadSubModule(pScrn, "ramdac"))
789 return FALSE;
790 xf86LoaderReqSymLists(ramdacSymbols, NULL);
791
792 /* The framebuffer module. */
793 if (xf86LoadSubModule(pScrn, "fb") == NULL)
794 return (FALSE);
795 xf86LoaderReqSymLists(fbSymbols, NULL);
796
797 if (!xf86LoadSubModule(pScrn, "shadowfb"))
798 return FALSE;
799 xf86LoaderReqSymLists(shadowfbSymbols, NULL);
800
801 /* Set up our ScrnInfoRec structure to describe our virtual
802 capabilities to X. */
803
804 pScrn->chipset = "vbox";
805
806 /* I assume that this is no longer a requirement in the config file. */
807 pScrn->monitor = pScrn->confScreen->monitor;
808
809 pScrn->progClock = TRUE;
810 pScrn->rgbBits = 8;
811
812 /* Using the PCI information caused problems with non-powers-of-two
813 sized video RAM configurations */
814 pScrn->videoRam = inl(VBE_DISPI_IOPORT_DATA) / 1024;
815
816 /* Query the host for the preferred colour depth */
817 {
818 uint32_t cx, cy, iDisplay, cBits = 24;
819
820 if (vbox_device_available(pVBox))
821 {
822 /* We only support 16 and 24 bits depth (i.e. 16 and 32bpp) */
823 if ( vboxGetDisplayChangeRequest(pScrn, &cx, &cy, &cBits,
824 &iDisplay)
825 && (cBits != 16)
826 )
827 cBits = 24;
828 }
829 if (!xf86SetDepthBpp(pScrn, cBits, 0, 0, Support32bppFb))
830 return FALSE;
831 }
832 if (pScrn->bitsPerPixel != 32 && pScrn->bitsPerPixel != 16)
833 {
834 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
835 "The VBox additions only support 16 and 32bpp graphics modes\n");
836 return FALSE;
837 }
838 xf86PrintDepthBpp(pScrn);
839
840 /* options */
841 xf86CollectOptions(pScrn, NULL);
842 if (!(pVBox->Options = xalloc(sizeof(VBOXOptions))))
843 return FALSE;
844 memcpy(pVBox->Options, VBOXOptions, sizeof(VBOXOptions));
845 xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pVBox->Options);
846
847 /* Initialise CRTC and output configuration for use with randr1.2. */
848 xf86CrtcConfigInit(pScrn, &VBOXCrtcConfigFuncs);
849
850 /* Setup our single virtual CRTC. */
851 xf86CrtcCreate(pScrn, &VBOXCrtcFuncs);
852
853 /* Set up our single virtual output. */
854 output = xf86OutputCreate(pScrn, &VBOXOutputFuncs, "VBOX1");
855
856 /* Set a sane minimum mode size and the maximum allowed by the available VRAM */
857 {
858#if 0
859 unsigned maxSize, trySize = 512;
860
861 do {
862 maxSize = trySize;
863 trySize += 128;
864 } while (trySize * trySize * pScrn->bitsPerPixel / 8 < pScrn->videoRam * 1024);
865#else
866 unsigned maxSize = 32000;
867#endif
868
869 xf86CrtcSetSizeRange(pScrn, 64, 64, maxSize, maxSize);
870
871 /* I don't know exactly what these are for (and they are only used in a couple
872 of places in the X server code), but due to a bug in RandR 1.2 they place
873 an upper limit on possible resolutions. To add to the fun, they get set
874 automatically if we don't do it ourselves. */
875 pScrn->display->virtualX = maxSize;
876 pScrn->display->virtualY = maxSize;
877 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
878 "The maximum supported resolution is currently %dx%d\n", maxSize, maxSize);
879 }
880
881 /* We are not interested in the monitor section in the configuration file. */
882 xf86OutputUseScreenMonitor(output, FALSE);
883 output->possible_crtcs = 1;
884 output->possible_clones = 0;
885
886 /* Now create our initial CRTC/output configuration. */
887 if (!xf86InitialConfiguration(pScrn, TRUE)) {
888 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Initial CRTC configuration failed!\n");
889 return (FALSE);
890 }
891
892 /* Colour weight - we always call this, since we are always in
893 truecolour. */
894 if (!xf86SetWeight(pScrn, rzeros, rzeros))
895 return (FALSE);
896
897 /* visual init */
898 if (!xf86SetDefaultVisual(pScrn, -1))
899 return (FALSE);
900
901 xf86SetGamma(pScrn, gzeros);
902
903 /* Set a default display resolution. */
904 xf86SetDpi(pScrn, 96, 96);
905
906 /* Framebuffer-related setup */
907 pScrn->bitmapBitOrder = BITMAP_BIT_ORDER;
908
909#ifdef VBOX_DRI
910 /* Load the dri module. */
911 if (xf86LoadSubModule(pScrn, "dri")) {
912 xf86LoaderReqSymLists(driSymbols, drmSymbols, NULL);
913 }
914#endif
915 return (TRUE);
916}
917
918/**
919 * This function hooks into the chain that is called when framebuffer access
920 * is allowed or disallowed by a call to EnableDisableFBAccess in the server.
921 * In other words, it observes when the server wishes access to the
922 * framebuffer to be enabled and when it should be disabled. We need to know
923 * this because we disable access ourselves during mode switches (presumably
924 * the server should do this but it doesn't) and want to know whether to
925 * restore it or not afterwards.
926 */
927static void
928vboxEnableDisableFBAccess(int scrnIndex, Bool enable)
929{
930 ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
931 VBOXPtr pVBox = VBOXGetRec(pScrn);
932
933 TRACE_LOG("enable=%s\n", enable ? "TRUE" : "FALSE");
934 pVBox->accessEnabled = enable;
935 pVBox->EnableDisableFBAccess(scrnIndex, enable);
936 TRACE_EXIT();
937}
938
939/*
940 * QUOTE from the XFree86 DESIGN document:
941 *
942 * This is called at the start of each server generation.
943 *
944 * (...)
945 *
946 * Decide which operations need to be placed under resource access
947 * control. (...) Map any video memory or other memory regions. (...)
948 * Save the video card state. (...) Initialise the initial video
949 * mode.
950 *
951 * End QUOTE.Initialise the initial video mode.
952 */
953static Bool
954VBOXScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
955{
956 ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
957 VBOXPtr pVBox = VBOXGetRec(pScrn);
958 VisualPtr visual;
959 unsigned flags;
960
961 if (pVBox->mapPhys == 0) {
962#ifdef PCIACCESS
963 pVBox->mapPhys = pVBox->pciInfo->regions[0].base_addr;
964#else
965 pVBox->mapPhys = pVBox->pciInfo->memBase[0];
966#endif
967/* pVBox->mapSize = 1 << pVBox->pciInfo->size[0]; */
968 /* Using the PCI information caused problems with
969 non-powers-of-two sized video RAM configurations */
970 pVBox->mapSize = inl(VBE_DISPI_IOPORT_DATA);
971 pVBox->mapOff = 0;
972 }
973
974 if (!VBOXMapVidMem(pScrn))
975 return (FALSE);
976
977 /* save current video state */
978 VBOXSaveRestore(pScrn, MODE_SAVE);
979 pVBox->savedPal = VBESetGetPaletteData(pVBox->pVbe, FALSE, 0, 256,
980 NULL, FALSE, FALSE);
981
982 /* mi layer - reset the visual list (?)*/
983 miClearVisualTypes();
984 if (!xf86SetDefaultVisual(pScrn, -1))
985 return (FALSE);
986 if (!miSetVisualTypes(pScrn->depth, TrueColorMask,
987 pScrn->rgbBits, TrueColor))
988 return (FALSE);
989 if (!miSetPixmapDepths())
990 return (FALSE);
991
992 /* Needed before we initialise DRI. */
993 pScrn->displayWidth = pScrn->virtualX;
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->virtualX, 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 /* Initialise DGA. The cast is unfortunately correct - it gets cast back
1032 to (unsigned char *) later. */
1033 xf86DiDGAInit(pScreen, (unsigned long) pVBox->base);
1034
1035 /* Initialise randr 1.2 mode-setting functions and set first mode. */
1036 if (!xf86CrtcScreenInit(pScreen)) {
1037 return FALSE;
1038 }
1039
1040 if (!xf86SetDesiredModes(pScrn)) {
1041 return FALSE;
1042 }
1043
1044 /* set the viewport */
1045 VBOXAdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
1046
1047 /* software cursor */
1048 miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
1049
1050 /* colourmap code - apparently, we need this even in Truecolour */
1051 if (!miCreateDefColormap(pScreen))
1052 return (FALSE);
1053
1054 flags = CMAP_RELOAD_ON_MODE_SWITCH;
1055
1056 if(!xf86HandleColormaps(pScreen, 256,
1057 8 /* DAC is switchable to 8 bits per primary color */,
1058 VBOXLoadPalette, NULL, flags))
1059 return (FALSE);
1060
1061 /* Hook our observer function ito the chain which is called when
1062 * framebuffer access is enabled or disabled in the server, and
1063 * assume an initial state of enabled. */
1064 pVBox->accessEnabled = TRUE;
1065 pVBox->EnableDisableFBAccess = pScrn->EnableDisableFBAccess;
1066 pScrn->EnableDisableFBAccess = vboxEnableDisableFBAccess;
1067
1068 pVBox->CloseScreen = pScreen->CloseScreen;
1069 pScreen->CloseScreen = VBOXCloseScreen;
1070 pScreen->SaveScreen = xf86SaveScreen;
1071
1072 /* We probably do want to support power management - even if we just use
1073 a dummy function. */
1074 xf86DPMSInit(pScreen, xf86DPMSSet, 0);
1075
1076 /* Report any unused options (only for the first generation) */
1077 if (serverGeneration == 1)
1078 xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
1079
1080 if (vbox_device_available(pVBox) && vbox_open (pScrn, pScreen, pVBox)) {
1081 if (vbox_cursor_init(pScreen) != TRUE)
1082 xf86DrvMsg(scrnIndex, X_ERROR,
1083 "Unable to start the VirtualBox mouse pointer integration with the host system.\n");
1084 if (vboxEnableVbva(pScrn) == TRUE)
1085 xf86DrvMsg(scrnIndex, X_INFO,
1086 "The VBox video extensions are now enabled.\n");
1087 vboxEnableGraphicsCap(pVBox);
1088 /* Report the largest resolution that we support */
1089 }
1090
1091#ifdef VBOX_DRI
1092 if (pVBox->useDRI)
1093 pVBox->useDRI = VBOXDRIFinishScreenInit(pScreen);
1094#endif
1095 return (TRUE);
1096}
1097
1098static Bool
1099VBOXEnterVT(int scrnIndex, int flags)
1100{
1101 ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1102 VBOXPtr pVBox = VBOXGetRec(pScrn);
1103 bool rc;
1104
1105 TRACE_ENTRY();
1106 pVBox->vtSwitch = FALSE;
1107#ifdef VBOX_DRI
1108 if (pVBox->useDRI)
1109 DRIUnlock(screenInfo.screens[scrnIndex]);
1110#endif
1111 rc = xf86SetDesiredModes(pScrn);
1112 TRACE_LOG("returning %s\n", rc ? "TRUE" : "FALSE");
1113 return rc;
1114}
1115
1116static void
1117VBOXLeaveVT(int scrnIndex, int flags)
1118{
1119 ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1120 VBOXPtr pVBox = VBOXGetRec(pScrn);
1121
1122 TRACE_ENTRY();
1123 pVBox->vtSwitch = TRUE;
1124 VBOXSaveRestore(pScrn, MODE_RESTORE);
1125 if (vbox_device_available(pVBox))
1126 {
1127 if (pVBox->useVbva == TRUE)
1128 vboxDisableVbva(pScrn);
1129 vboxDisableGraphicsCap(pVBox);
1130 }
1131#ifdef VBOX_DRI
1132 if (pVBox->useDRI)
1133 DRILock(screenInfo.screens[scrnIndex], 0);
1134#endif
1135 TRACE_EXIT();
1136}
1137
1138static Bool
1139VBOXCloseScreen(int scrnIndex, ScreenPtr pScreen)
1140{
1141 ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1142 VBOXPtr pVBox = VBOXGetRec(pScrn);
1143
1144#ifdef VBOX_DRI
1145 if (pVBox->useDRI)
1146 VBOXDRICloseScreen(pScreen, pVBox);
1147 pVBox->useDRI = false;
1148#endif
1149
1150 if (vbox_device_available(pVBox))
1151 {
1152 if (TRUE == pVBox->useVbva)
1153 vboxDisableVbva(pScrn);
1154 vboxDisableGraphicsCap(pVBox);
1155 }
1156 if (pScrn->vtSema) {
1157 VBOXSaveRestore(xf86Screens[scrnIndex], MODE_RESTORE);
1158 if (pVBox->savedPal)
1159 VBESetGetPaletteData(pVBox->pVbe, TRUE, 0, 256,
1160 pVBox->savedPal, FALSE, TRUE);
1161 VBOXUnmapVidMem(pScrn);
1162 }
1163 pScrn->vtSema = FALSE;
1164
1165 /* Remove our observer functions from the X server call chains. */
1166 pScrn->EnableDisableFBAccess = pVBox->EnableDisableFBAccess;
1167 pScreen->CloseScreen = pVBox->CloseScreen;
1168 return pScreen->CloseScreen(scrnIndex, pScreen);
1169}
1170
1171/**
1172 * Quoted from "How to add an (S)VGA driver to XFree86"
1173 * (http://www.xfree86.org/3.3.6/VGADriver.html):
1174 *
1175 * The ValidMode() function is required. It is used to check for any
1176 * chipset-dependent reasons why a graphics mode might not be valid. It gets
1177 * called by higher levels of the code after the Probe() stage. In many cases
1178 * no special checking will be required and this function will simply return
1179 * TRUE always.
1180 *
1181 * Note: we check here that our generated video modes fulfil the X server's
1182 * criteria for the monitor, since this can otherwise cause problems in
1183 * randr 1.2.
1184 */
1185static ModeStatus
1186VBOXValidMode(int scrn, DisplayModePtr p, Bool flag, int pass)
1187{
1188 static int warned = 0;
1189 ScrnInfoPtr pScrn = xf86Screens[scrn];
1190 MonPtr mon = pScrn->monitor;
1191 ModeStatus ret = MODE_BAD;
1192 DisplayModePtr mode;
1193 float v;
1194
1195 TRACE_LOG("HDisplay=%d, VDisplay=%d, flag=%s, pass=%d\n",
1196 p->HDisplay, p->VDisplay, flag ? "TRUE" : "FALSE", pass);
1197 if (pass != MODECHECK_FINAL) {
1198 if (!warned) {
1199 xf86DrvMsg(scrn, X_WARNING, "VBOXValidMode called unexpectedly\n");
1200 warned = 1;
1201 }
1202 }
1203#if 0
1204 /*
1205 * First off, if this isn't a mode we handed to the server (ie,
1206 * M_T_BUILTIN), then we reject it out of hand.
1207 */
1208 if (!(p->type & M_T_BUILTIN))
1209 return MODE_NOMODE;
1210#endif
1211 /*
1212 * Finally, walk through the vsync rates 1Hz at a time looking for a mode
1213 * that will fit. This is assuredly a terrible way to do this, but
1214 * there's no obvious method for computing a mode of a given size that
1215 * will pass xf86CheckModeForMonitor.
1216 */
1217 for (v = mon->vrefresh[0].lo; v <= mon->vrefresh[0].hi; v++) {
1218 mode = xf86CVTMode(p->HDisplay, p->VDisplay, v, 0, 0);
1219 ret = xf86CheckModeForMonitor(mode, mon);
1220 xfree(mode);
1221 if (ret == MODE_OK)
1222 break;
1223 }
1224
1225 if (ret != MODE_OK)
1226 {
1227 xf86DrvMsg(scrn, X_WARNING, "Graphics mode %s rejected by the X server\n", p->name);
1228 }
1229 TRACE_LOG("returning %d\n", ret);
1230 return ret;
1231}
1232
1233static Bool
1234VBOXSwitchMode(int scrnIndex, DisplayModePtr pMode, int flags)
1235{
1236 ScrnInfoPtr pScrn;
1237 VBOXPtr pVBox;
1238 Bool rc;
1239
1240 TRACE_LOG("HDisplay=%d, VDisplay=%d\n", pMode->HDisplay, pMode->VDisplay);
1241 pScrn = xf86Screens[scrnIndex]; /* Why does X have three ways of refering to the screen? */
1242 pVBox = VBOXGetRec(pScrn);
1243 /* We want to disable access to the framebuffer before switching mode.
1244 * After doing the switch, we allow access if it was allowed before. */
1245 if (pVBox->accessEnabled)
1246 pVBox->EnableDisableFBAccess(scrnIndex, FALSE);
1247 rc = xf86SetSingleMode(pScrn, pMode, 0);
1248 if (pVBox->accessEnabled)
1249 pVBox->EnableDisableFBAccess(scrnIndex, TRUE);
1250 TRACE_LOG("returning %s\n", rc ? "TRUE" : "FALSE");
1251 return rc;
1252}
1253
1254/* Set a graphics mode. Poke the required values into registers, enable
1255 guest-host acceleration functions and tell the host we support advanced
1256 graphics functions. */
1257static Bool
1258VBOXSetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode)
1259{
1260 VBOXPtr pVBox;
1261 Bool rc = TRUE;
1262
1263 int bpp = pScrn->depth == 24 ? 32 : 16;
1264 TRACE_LOG("HDisplay=%d, VDisplay=%d\n", pMode->HDisplay, pMode->VDisplay);
1265 pVBox = VBOXGetRec(pScrn);
1266 /* Don't fiddle with the hardware if we are switched
1267 * to a virtual terminal. */
1268 if (!pVBox->vtSwitch)
1269 {
1270 if ( vbox_device_available(pVBox)
1271 && (TRUE == pVBox->useVbva)
1272 && (vboxDisableVbva(pScrn) != TRUE)
1273 ) /* This would be bad. */
1274 rc = FALSE;
1275 if (rc)
1276 {
1277 /* Disable linear framebuffer mode before making changes to the resolution. */
1278 outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
1279 outw(VBE_DISPI_IOPORT_DATA, VBE_DISPI_DISABLED);
1280 /* Unlike the resolution, the depth is fixed for a given screen
1281 for the lifetime of the X session. */
1282 outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_BPP);
1283 outw(VBE_DISPI_IOPORT_DATA, bpp);
1284 /* HDisplay and VDisplay are actually monitor information about
1285 the display part of the scanlines. */
1286 outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_XRES);
1287 outw(VBE_DISPI_IOPORT_DATA, pMode->HDisplay);
1288 outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_YRES);
1289 outw(VBE_DISPI_IOPORT_DATA, pMode->VDisplay);
1290 /* Set the virtual resolution. We are still using VESA to control
1291 the virtual offset. */
1292 outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_VIRT_WIDTH);
1293 outw(VBE_DISPI_IOPORT_DATA, pScrn->displayWidth);
1294 /* Enable linear framebuffer mode. */
1295 outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
1296 outw(VBE_DISPI_IOPORT_DATA,
1297 VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED);
1298 /* Enable acceleration and tell the host we support graphics */
1299 if (vbox_device_available(pVBox))
1300 {
1301 if ((TRUE == pVBox->useVbva) && (vboxEnableVbva(pScrn) != TRUE))
1302 /* Bad but not fatal */
1303 pVBox->useVbva = FALSE;
1304 vboxEnableGraphicsCap(pVBox);
1305 }
1306 }
1307 }
1308 TRACE_LOG("returning %s\n", rc ? "TRUE" : "FALSE");
1309 return rc;
1310}
1311
1312static void
1313VBOXAdjustFrame(int scrnIndex, int x, int y, int flags)
1314{
1315 VBOXPtr pVBox = VBOXGetRec(xf86Screens[scrnIndex]);
1316 ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1317
1318 TRACE_ENTRY();
1319 /* Don't fiddle with the hardware if we are switched
1320 * to a virtual terminal. */
1321 if (!pVBox->vtSwitch) {
1322 pVBox->viewportX = x;
1323 pVBox->viewportY = y;
1324 /* If VBVA is enabled the graphics card will not notice the change. */
1325 if (pVBox->useVbva == TRUE)
1326 vboxDisableVbva(pScrn);
1327 VBESetDisplayStart(pVBox->pVbe, x, y, TRUE);
1328 if (pVBox->useVbva == TRUE)
1329 vboxEnableVbva(pScrn);
1330 }
1331 TRACE_EXIT();
1332}
1333
1334static void
1335VBOXFreeScreen(int scrnIndex, int flags)
1336{
1337 VBOXFreeRec(xf86Screens[scrnIndex]);
1338}
1339
1340static Bool
1341VBOXMapVidMem(ScrnInfoPtr pScrn)
1342{
1343 VBOXPtr pVBox = VBOXGetRec(pScrn);
1344 Bool rc = TRUE;
1345
1346 TRACE_ENTRY();
1347 if (NULL == pVBox->base)
1348 {
1349 pScrn->memPhysBase = pVBox->mapPhys;
1350 pScrn->fbOffset = pVBox->mapOff;
1351
1352#ifdef PCIACCESS
1353 (void) pci_device_map_range(pVBox->pciInfo,
1354 pScrn->memPhysBase,
1355 pVBox->mapSize,
1356 PCI_DEV_MAP_FLAG_WRITABLE,
1357 & pVBox->base);
1358
1359 if (pVBox->base) {
1360 pScrn->memPhysBase = pVBox->mapPhys;
1361 pVBox->VGAbase = xf86MapDomainMemory(pScrn->scrnIndex, 0,
1362 pVBox->pciInfo,
1363 0xa0000, 0x10000);
1364 }
1365#else
1366 pVBox->base = xf86MapPciMem(pScrn->scrnIndex,
1367 VIDMEM_FRAMEBUFFER,
1368 pVBox->pciTag, pVBox->mapPhys,
1369 (unsigned) pVBox->mapSize);
1370
1371 if (pVBox->base) {
1372 pScrn->memPhysBase = pVBox->mapPhys;
1373 pVBox->VGAbase = xf86MapDomainMemory(pScrn->scrnIndex, 0,
1374 pVBox->pciTag,
1375 0xa0000, 0x10000);
1376 }
1377#endif
1378 /* We need this for saving/restoring textmode */
1379 pVBox->ioBase = pScrn->domainIOBase;
1380
1381 rc = pVBox->base != NULL;
1382 }
1383 TRACE_LOG("returning %s\n", rc ? "TRUE" : "FALSE");
1384 return rc;
1385}
1386
1387static void
1388VBOXUnmapVidMem(ScrnInfoPtr pScrn)
1389{
1390 VBOXPtr pVBox = VBOXGetRec(pScrn);
1391
1392 TRACE_ENTRY();
1393 if (pVBox->base == NULL)
1394 return;
1395
1396#ifdef PCIACCESS
1397 (void) pci_device_unmap_range(pVBox->pciInfo,
1398 pVBox->base,
1399 pVBox->mapSize);
1400 xf86UnMapVidMem(pScrn->scrnIndex, pVBox->VGAbase, 0x10000);
1401#else
1402 xf86UnMapVidMem(pScrn->scrnIndex, pVBox->base,
1403 (unsigned) pVBox->mapSize);
1404 xf86UnMapVidMem(pScrn->scrnIndex, pVBox->VGAbase, 0x10000);
1405#endif
1406 pVBox->base = NULL;
1407 TRACE_EXIT();
1408}
1409
1410static void
1411VBOXLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices,
1412 LOCO *colors, VisualPtr pVisual)
1413{
1414 VBOXPtr pVBox = VBOXGetRec(pScrn);
1415 int i, idx;
1416#define VBOXDACDelay() \
1417 do { \
1418 (void)inb(pVBox->ioBase + VGA_IOBASE_COLOR + VGA_IN_STAT_1_OFFSET); \
1419 (void)inb(pVBox->ioBase + VGA_IOBASE_COLOR + VGA_IN_STAT_1_OFFSET); \
1420 } while (0)
1421
1422 TRACE_ENTRY();
1423 for (i = 0; i < numColors; i++) {
1424 idx = indices[i];
1425 outb(pVBox->ioBase + VGA_DAC_WRITE_ADDR, idx);
1426 VBOXDACDelay();
1427 outb(pVBox->ioBase + VGA_DAC_DATA, colors[idx].red);
1428 VBOXDACDelay();
1429 outb(pVBox->ioBase + VGA_DAC_DATA, colors[idx].green);
1430 VBOXDACDelay();
1431 outb(pVBox->ioBase + VGA_DAC_DATA, colors[idx].blue);
1432 VBOXDACDelay();
1433 }
1434 TRACE_EXIT();
1435}
1436
1437/*
1438 * Just adapted from the std* functions in vgaHW.c
1439 */
1440static void
1441WriteAttr(VBOXPtr pVBox, int index, int value)
1442{
1443 (void) inb(pVBox->ioBase + VGA_IOBASE_COLOR + VGA_IN_STAT_1_OFFSET);
1444
1445 index |= 0x20;
1446 outb(pVBox->ioBase + VGA_ATTR_INDEX, index);
1447 outb(pVBox->ioBase + VGA_ATTR_DATA_W, value);
1448}
1449
1450static int
1451ReadAttr(VBOXPtr pVBox, int index)
1452{
1453 (void) inb(pVBox->ioBase + VGA_IOBASE_COLOR + VGA_IN_STAT_1_OFFSET);
1454
1455 index |= 0x20;
1456 outb(pVBox->ioBase + VGA_ATTR_INDEX, index);
1457 return (inb(pVBox->ioBase + VGA_ATTR_DATA_R));
1458}
1459
1460#define WriteMiscOut(value) outb(pVBox->ioBase + VGA_MISC_OUT_W, value)
1461#define ReadMiscOut() inb(pVBox->ioBase + VGA_MISC_OUT_R)
1462#define WriteSeq(index, value) \
1463 outb(pVBox->ioBase + VGA_SEQ_INDEX, (index));\
1464 outb(pVBox->ioBase + VGA_SEQ_DATA, value)
1465
1466static int
1467ReadSeq(VBOXPtr pVBox, int index)
1468{
1469 outb(pVBox->ioBase + VGA_SEQ_INDEX, index);
1470
1471 return (inb(pVBox->ioBase + VGA_SEQ_DATA));
1472}
1473
1474#define WriteGr(index, value) \
1475 outb(pVBox->ioBase + VGA_GRAPH_INDEX, index); \
1476 outb(pVBox->ioBase + VGA_GRAPH_DATA, value)
1477
1478static int
1479ReadGr(VBOXPtr pVBox, int index)
1480{
1481 outb(pVBox->ioBase + VGA_GRAPH_INDEX, index);
1482
1483 return (inb(pVBox->ioBase + VGA_GRAPH_DATA));
1484}
1485
1486#define WriteCrtc(index, value) \
1487 outb(pVBox->ioBase + (VGA_IOBASE_COLOR + VGA_CRTC_INDEX_OFFSET), index); \
1488 outb(pVBox->ioBase + (VGA_IOBASE_COLOR + VGA_CRTC_DATA_OFFSET), value)
1489
1490static void
1491SeqReset(VBOXPtr pVBox, Bool start)
1492{
1493 if (start) {
1494 WriteSeq(0x00, 0x01); /* Synchronous Reset */
1495 }
1496 else {
1497 WriteSeq(0x00, 0x03); /* End Reset */
1498 }
1499}
1500
1501static void
1502SaveFonts(ScrnInfoPtr pScrn)
1503{
1504 VBOXPtr pVBox = VBOXGetRec(pScrn);
1505 unsigned char miscOut, attr10, gr4, gr5, gr6, seq2, seq4, scrn;
1506 Bool cont = TRUE;
1507
1508 TRACE_ENTRY();
1509 if (pVBox->fonts != NULL)
1510 cont = FALSE;
1511
1512 if (cont)
1513 {
1514 /* If in graphics mode, don't save anything */
1515 attr10 = ReadAttr(pVBox, 0x10);
1516 if (attr10 & 0x01)
1517 cont = FALSE;
1518 }
1519
1520 if (cont)
1521 {
1522 pVBox->fonts = xalloc(16384);
1523
1524 /* save the registers that are needed here */
1525 miscOut = ReadMiscOut();
1526 gr4 = ReadGr(pVBox, 0x04);
1527 gr5 = ReadGr(pVBox, 0x05);
1528 gr6 = ReadGr(pVBox, 0x06);
1529 seq2 = ReadSeq(pVBox, 0x02);
1530 seq4 = ReadSeq(pVBox, 0x04);
1531
1532 /* Force into colour mode */
1533 WriteMiscOut(miscOut | 0x01);
1534
1535 scrn = ReadSeq(pVBox, 0x01) | 0x20;
1536 SeqReset(pVBox, TRUE);
1537 WriteSeq(0x01, scrn);
1538 SeqReset(pVBox, FALSE);
1539
1540 WriteAttr(pVBox, 0x10, 0x01); /* graphics mode */
1541
1542 /*font1 */
1543 WriteSeq(0x02, 0x04); /* write to plane 2 */
1544 WriteSeq(0x04, 0x06); /* enable plane graphics */
1545 WriteGr(0x04, 0x02); /* read plane 2 */
1546 WriteGr(0x05, 0x00); /* write mode 0, read mode 0 */
1547 WriteGr(0x06, 0x05); /* set graphics */
1548 slowbcopy_frombus(pVBox->VGAbase, pVBox->fonts, 8192);
1549
1550 /* font2 */
1551 WriteSeq(0x02, 0x08); /* write to plane 3 */
1552 WriteSeq(0x04, 0x06); /* enable plane graphics */
1553 WriteGr(0x04, 0x03); /* read plane 3 */
1554 WriteGr(0x05, 0x00); /* write mode 0, read mode 0 */
1555 WriteGr(0x06, 0x05); /* set graphics */
1556 slowbcopy_frombus(pVBox->VGAbase, pVBox->fonts + 8192, 8192);
1557
1558 scrn = ReadSeq(pVBox, 0x01) & ~0x20;
1559 SeqReset(pVBox, TRUE);
1560 WriteSeq(0x01, scrn);
1561 SeqReset(pVBox, FALSE);
1562
1563 /* Restore clobbered registers */
1564 WriteAttr(pVBox, 0x10, attr10);
1565 WriteSeq(0x02, seq2);
1566 WriteSeq(0x04, seq4);
1567 WriteGr(0x04, gr4);
1568 WriteGr(0x05, gr5);
1569 WriteGr(0x06, gr6);
1570 WriteMiscOut(miscOut);
1571 }
1572 TRACE_EXIT();
1573}
1574
1575static void
1576RestoreFonts(ScrnInfoPtr pScrn)
1577{
1578 VBOXPtr pVBox = VBOXGetRec(pScrn);
1579 unsigned char miscOut, attr10, gr1, gr3, gr4, gr5, gr6, gr8, seq2, seq4, scrn;
1580
1581 TRACE_ENTRY();
1582 if (pVBox->fonts != NULL)
1583 {
1584 /* save the registers that are needed here */
1585 miscOut = ReadMiscOut();
1586 attr10 = ReadAttr(pVBox, 0x10);
1587 gr1 = ReadGr(pVBox, 0x01);
1588 gr3 = ReadGr(pVBox, 0x03);
1589 gr4 = ReadGr(pVBox, 0x04);
1590 gr5 = ReadGr(pVBox, 0x05);
1591 gr6 = ReadGr(pVBox, 0x06);
1592 gr8 = ReadGr(pVBox, 0x08);
1593 seq2 = ReadSeq(pVBox, 0x02);
1594 seq4 = ReadSeq(pVBox, 0x04);
1595
1596 /* Force into colour mode */
1597 WriteMiscOut(miscOut | 0x01);
1598
1599 scrn = ReadSeq(pVBox, 0x01) & ~0x20;
1600 SeqReset(pVBox, TRUE);
1601 WriteSeq(0x01, scrn);
1602 SeqReset(pVBox, FALSE);
1603
1604 WriteAttr(pVBox, 0x10, 0x01); /* graphics mode */
1605 if (pScrn->depth == 4) {
1606 /* GJA */
1607 WriteGr(0x03, 0x00); /* don't rotate, write unmodified */
1608 WriteGr(0x08, 0xFF); /* write all bits in a byte */
1609 WriteGr(0x01, 0x00); /* all planes come from CPU */
1610 }
1611
1612 WriteSeq(0x02, 0x04); /* write to plane 2 */
1613 WriteSeq(0x04, 0x06); /* enable plane graphics */
1614 WriteGr(0x04, 0x02); /* read plane 2 */
1615 WriteGr(0x05, 0x00); /* write mode 0, read mode 0 */
1616 WriteGr(0x06, 0x05); /* set graphics */
1617 slowbcopy_tobus(pVBox->fonts, pVBox->VGAbase, 8192);
1618
1619 WriteSeq(0x02, 0x08); /* write to plane 3 */
1620 WriteSeq(0x04, 0x06); /* enable plane graphics */
1621 WriteGr(0x04, 0x03); /* read plane 3 */
1622 WriteGr(0x05, 0x00); /* write mode 0, read mode 0 */
1623 WriteGr(0x06, 0x05); /* set graphics */
1624 slowbcopy_tobus(pVBox->fonts + 8192, pVBox->VGAbase, 8192);
1625
1626 scrn = ReadSeq(pVBox, 0x01) & ~0x20;
1627 SeqReset(pVBox, TRUE);
1628 WriteSeq(0x01, scrn);
1629 SeqReset(pVBox, FALSE);
1630
1631 /* restore the registers that were changed */
1632 WriteMiscOut(miscOut);
1633 WriteAttr(pVBox, 0x10, attr10);
1634 WriteGr(0x01, gr1);
1635 WriteGr(0x03, gr3);
1636 WriteGr(0x04, gr4);
1637 WriteGr(0x05, gr5);
1638 WriteGr(0x06, gr6);
1639 WriteGr(0x08, gr8);
1640 WriteSeq(0x02, seq2);
1641 WriteSeq(0x04, seq4);
1642 }
1643 TRACE_EXIT();
1644}
1645
1646Bool
1647VBOXSaveRestore(ScrnInfoPtr pScrn, vbeSaveRestoreFunction function)
1648{
1649 VBOXPtr pVBox;
1650 Bool rc = TRUE;
1651
1652 TRACE_ENTRY();
1653 if (MODE_QUERY < 0 || function > MODE_RESTORE)
1654 rc = FALSE;
1655
1656 if (rc)
1657 {
1658 pVBox = VBOXGetRec(pScrn);
1659
1660 /* Query amount of memory to save state */
1661 if (function == MODE_QUERY ||
1662 (function == MODE_SAVE && pVBox->state == NULL))
1663 {
1664
1665 /* Make sure we save at least this information in case of failure */
1666 (void)VBEGetVBEMode(pVBox->pVbe, &pVBox->stateMode);
1667 SaveFonts(pScrn);
1668
1669 if (!VBESaveRestore(pVBox->pVbe,function,(pointer)&pVBox->state,
1670 &pVBox->stateSize,&pVBox->statePage)
1671 )
1672 rc = FALSE;
1673 }
1674 }
1675 if (rc)
1676 {
1677 /* Save/Restore Super VGA state */
1678 if (function != MODE_QUERY) {
1679
1680 if (function == MODE_RESTORE)
1681 memcpy(pVBox->state, pVBox->pstate,
1682 (unsigned) pVBox->stateSize);
1683
1684 if ( (rc = VBESaveRestore(pVBox->pVbe,function,
1685 (pointer)&pVBox->state,
1686 &pVBox->stateSize,&pVBox->statePage)
1687 )
1688 && (function == MODE_SAVE)
1689 )
1690 {
1691 /* don't rely on the memory not being touched */
1692 if (pVBox->pstate == NULL)
1693 pVBox->pstate = xalloc(pVBox->stateSize);
1694 memcpy(pVBox->pstate, pVBox->state,
1695 (unsigned) pVBox->stateSize);
1696 }
1697
1698 if (function == MODE_RESTORE)
1699 {
1700 VBESetVBEMode(pVBox->pVbe, pVBox->stateMode, NULL);
1701 RestoreFonts(pScrn);
1702 }
1703 }
1704 }
1705 TRACE_LOG("returning %s\n", rc ? "TRUE" : "FALSE");
1706 return rc;
1707}
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