VirtualBox

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

Last change on this file since 22046 was 16753, checked in by vboxsync, 16 years ago

Additions/x11/vboxvideo: disable VBVA when the viewport is moved

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