VirtualBox

source: vbox/trunk/src/VBox/Additions/x11/xgraphics/vboxvideo_13.c@ 16701

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

Additions/x11/vboxvideo: dirty rectangles should be adjusted for the viewport position if the guest is using a virtual desktop larger than the current resolution

  • Property svn:eol-style set to native
File size: 49.4 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
1219 TRACE;
1220 /* Don't fiddle with the hardware if we are switched
1221 * to a virtual terminal. */
1222 if (!pVBox->vtSwitch) {
1223 pVBox->viewportX = x;
1224 pVBox->viewportY = y;
1225 VBESetDisplayStart(pVBox->pVbe, x, y, TRUE);
1226 }
1227 TRACE2;
1228}
1229
1230static void
1231VBOXFreeScreen(int scrnIndex, int flags)
1232{
1233 VBOXFreeRec(xf86Screens[scrnIndex]);
1234}
1235
1236static Bool
1237VBOXMapVidMem(ScrnInfoPtr pScrn)
1238{
1239 VBOXPtr pVBox = VBOXGetRec(pScrn);
1240 Bool rc = TRUE;
1241
1242 TRACE;
1243 if (NULL == pVBox->base)
1244 {
1245 pScrn->memPhysBase = pVBox->mapPhys;
1246 pScrn->fbOffset = pVBox->mapOff;
1247
1248 pVBox->base = xf86MapPciMem(pScrn->scrnIndex,
1249 VIDMEM_FRAMEBUFFER,
1250 pVBox->pciTag, pVBox->mapPhys,
1251 (unsigned) pVBox->mapSize);
1252
1253 if (pVBox->base) {
1254 pScrn->memPhysBase = pVBox->mapPhys;
1255 pVBox->VGAbase = xf86MapDomainMemory(pScrn->scrnIndex, 0,
1256 pVBox->pciTag,
1257 0xa0000, 0x10000);
1258 }
1259 /* We need this for saving/restoring textmode */
1260 pVBox->ioBase = pScrn->domainIOBase;
1261
1262 rc = pVBox->base != NULL;
1263 }
1264 TRACE3("returning %s\n", rc ? "TRUE" : "FALSE");
1265 return rc;
1266}
1267
1268static void
1269VBOXUnmapVidMem(ScrnInfoPtr pScrn)
1270{
1271 VBOXPtr pVBox = VBOXGetRec(pScrn);
1272
1273 TRACE;
1274 if (pVBox->base == NULL)
1275 return;
1276
1277 xf86UnMapVidMem(pScrn->scrnIndex, pVBox->base,
1278 (unsigned) pVBox->mapSize);
1279 xf86UnMapVidMem(pScrn->scrnIndex, pVBox->VGAbase, 0x10000);
1280 pVBox->base = NULL;
1281 TRACE2;
1282}
1283
1284static void
1285VBOXLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices,
1286 LOCO *colors, VisualPtr pVisual)
1287{
1288 VBOXPtr pVBox = VBOXGetRec(pScrn);
1289 int i, idx;
1290#define VBOXDACDelay() \
1291 do { \
1292 (void)inb(pVBox->ioBase + VGA_IOBASE_COLOR + VGA_IN_STAT_1_OFFSET); \
1293 (void)inb(pVBox->ioBase + VGA_IOBASE_COLOR + VGA_IN_STAT_1_OFFSET); \
1294 } while (0)
1295
1296 TRACE;
1297 for (i = 0; i < numColors; i++) {
1298 idx = indices[i];
1299 outb(pVBox->ioBase + VGA_DAC_WRITE_ADDR, idx);
1300 VBOXDACDelay();
1301 outb(pVBox->ioBase + VGA_DAC_DATA, colors[idx].red);
1302 VBOXDACDelay();
1303 outb(pVBox->ioBase + VGA_DAC_DATA, colors[idx].green);
1304 VBOXDACDelay();
1305 outb(pVBox->ioBase + VGA_DAC_DATA, colors[idx].blue);
1306 VBOXDACDelay();
1307 }
1308 TRACE2;
1309}
1310
1311/*
1312 * Just adapted from the std* functions in vgaHW.c
1313 */
1314static void
1315WriteAttr(VBOXPtr pVBox, int index, int value)
1316{
1317 (void) inb(pVBox->ioBase + VGA_IOBASE_COLOR + VGA_IN_STAT_1_OFFSET);
1318
1319 index |= 0x20;
1320 outb(pVBox->ioBase + VGA_ATTR_INDEX, index);
1321 outb(pVBox->ioBase + VGA_ATTR_DATA_W, value);
1322}
1323
1324static int
1325ReadAttr(VBOXPtr pVBox, int index)
1326{
1327 (void) inb(pVBox->ioBase + VGA_IOBASE_COLOR + VGA_IN_STAT_1_OFFSET);
1328
1329 index |= 0x20;
1330 outb(pVBox->ioBase + VGA_ATTR_INDEX, index);
1331 return (inb(pVBox->ioBase + VGA_ATTR_DATA_R));
1332}
1333
1334#define WriteMiscOut(value) outb(pVBox->ioBase + VGA_MISC_OUT_W, value)
1335#define ReadMiscOut() inb(pVBox->ioBase + VGA_MISC_OUT_R)
1336#define WriteSeq(index, value) \
1337 outb(pVBox->ioBase + VGA_SEQ_INDEX, (index));\
1338 outb(pVBox->ioBase + VGA_SEQ_DATA, value)
1339
1340static int
1341ReadSeq(VBOXPtr pVBox, int index)
1342{
1343 outb(pVBox->ioBase + VGA_SEQ_INDEX, index);
1344
1345 return (inb(pVBox->ioBase + VGA_SEQ_DATA));
1346}
1347
1348#define WriteGr(index, value) \
1349 outb(pVBox->ioBase + VGA_GRAPH_INDEX, index); \
1350 outb(pVBox->ioBase + VGA_GRAPH_DATA, value)
1351
1352static int
1353ReadGr(VBOXPtr pVBox, int index)
1354{
1355 outb(pVBox->ioBase + VGA_GRAPH_INDEX, index);
1356
1357 return (inb(pVBox->ioBase + VGA_GRAPH_DATA));
1358}
1359
1360#define WriteCrtc(index, value) \
1361 outb(pVBox->ioBase + (VGA_IOBASE_COLOR + VGA_CRTC_INDEX_OFFSET), index); \
1362 outb(pVBox->ioBase + (VGA_IOBASE_COLOR + VGA_CRTC_DATA_OFFSET), value)
1363
1364static void
1365SeqReset(VBOXPtr pVBox, Bool start)
1366{
1367 if (start) {
1368 WriteSeq(0x00, 0x01); /* Synchronous Reset */
1369 }
1370 else {
1371 WriteSeq(0x00, 0x03); /* End Reset */
1372 }
1373}
1374
1375static void
1376SaveFonts(ScrnInfoPtr pScrn)
1377{
1378 VBOXPtr pVBox = VBOXGetRec(pScrn);
1379 unsigned char miscOut, attr10, gr4, gr5, gr6, seq2, seq4, scrn;
1380 Bool cont = TRUE;
1381
1382 TRACE;
1383 if (pVBox->fonts != NULL)
1384 cont = FALSE;
1385
1386 if (cont)
1387 {
1388 /* If in graphics mode, don't save anything */
1389 attr10 = ReadAttr(pVBox, 0x10);
1390 if (attr10 & 0x01)
1391 cont = FALSE;
1392 }
1393
1394 if (cont)
1395 {
1396 pVBox->fonts = xalloc(16384);
1397
1398 /* save the registers that are needed here */
1399 miscOut = ReadMiscOut();
1400 gr4 = ReadGr(pVBox, 0x04);
1401 gr5 = ReadGr(pVBox, 0x05);
1402 gr6 = ReadGr(pVBox, 0x06);
1403 seq2 = ReadSeq(pVBox, 0x02);
1404 seq4 = ReadSeq(pVBox, 0x04);
1405
1406 /* Force into colour mode */
1407 WriteMiscOut(miscOut | 0x01);
1408
1409 scrn = ReadSeq(pVBox, 0x01) | 0x20;
1410 SeqReset(pVBox, TRUE);
1411 WriteSeq(0x01, scrn);
1412 SeqReset(pVBox, FALSE);
1413
1414 WriteAttr(pVBox, 0x10, 0x01); /* graphics mode */
1415
1416 /*font1 */
1417 WriteSeq(0x02, 0x04); /* write to plane 2 */
1418 WriteSeq(0x04, 0x06); /* enable plane graphics */
1419 WriteGr(0x04, 0x02); /* read plane 2 */
1420 WriteGr(0x05, 0x00); /* write mode 0, read mode 0 */
1421 WriteGr(0x06, 0x05); /* set graphics */
1422 slowbcopy_frombus(pVBox->VGAbase, pVBox->fonts, 8192);
1423
1424 /* font2 */
1425 WriteSeq(0x02, 0x08); /* write to plane 3 */
1426 WriteSeq(0x04, 0x06); /* enable plane graphics */
1427 WriteGr(0x04, 0x03); /* read plane 3 */
1428 WriteGr(0x05, 0x00); /* write mode 0, read mode 0 */
1429 WriteGr(0x06, 0x05); /* set graphics */
1430 slowbcopy_frombus(pVBox->VGAbase, pVBox->fonts + 8192, 8192);
1431
1432 scrn = ReadSeq(pVBox, 0x01) & ~0x20;
1433 SeqReset(pVBox, TRUE);
1434 WriteSeq(0x01, scrn);
1435 SeqReset(pVBox, FALSE);
1436
1437 /* Restore clobbered registers */
1438 WriteAttr(pVBox, 0x10, attr10);
1439 WriteSeq(0x02, seq2);
1440 WriteSeq(0x04, seq4);
1441 WriteGr(0x04, gr4);
1442 WriteGr(0x05, gr5);
1443 WriteGr(0x06, gr6);
1444 WriteMiscOut(miscOut);
1445 }
1446 TRACE2;
1447}
1448
1449static void
1450RestoreFonts(ScrnInfoPtr pScrn)
1451{
1452 VBOXPtr pVBox = VBOXGetRec(pScrn);
1453 unsigned char miscOut, attr10, gr1, gr3, gr4, gr5, gr6, gr8, seq2, seq4, scrn;
1454
1455 TRACE;
1456 if (pVBox->fonts != NULL)
1457 {
1458 /* save the registers that are needed here */
1459 miscOut = ReadMiscOut();
1460 attr10 = ReadAttr(pVBox, 0x10);
1461 gr1 = ReadGr(pVBox, 0x01);
1462 gr3 = ReadGr(pVBox, 0x03);
1463 gr4 = ReadGr(pVBox, 0x04);
1464 gr5 = ReadGr(pVBox, 0x05);
1465 gr6 = ReadGr(pVBox, 0x06);
1466 gr8 = ReadGr(pVBox, 0x08);
1467 seq2 = ReadSeq(pVBox, 0x02);
1468 seq4 = ReadSeq(pVBox, 0x04);
1469
1470 /* Force into colour mode */
1471 WriteMiscOut(miscOut | 0x01);
1472
1473 scrn = ReadSeq(pVBox, 0x01) & ~0x20;
1474 SeqReset(pVBox, TRUE);
1475 WriteSeq(0x01, scrn);
1476 SeqReset(pVBox, FALSE);
1477
1478 WriteAttr(pVBox, 0x10, 0x01); /* graphics mode */
1479 if (pScrn->depth == 4) {
1480 /* GJA */
1481 WriteGr(0x03, 0x00); /* don't rotate, write unmodified */
1482 WriteGr(0x08, 0xFF); /* write all bits in a byte */
1483 WriteGr(0x01, 0x00); /* all planes come from CPU */
1484 }
1485
1486 WriteSeq(0x02, 0x04); /* write to plane 2 */
1487 WriteSeq(0x04, 0x06); /* enable plane graphics */
1488 WriteGr(0x04, 0x02); /* read plane 2 */
1489 WriteGr(0x05, 0x00); /* write mode 0, read mode 0 */
1490 WriteGr(0x06, 0x05); /* set graphics */
1491 slowbcopy_tobus(pVBox->fonts, pVBox->VGAbase, 8192);
1492
1493 WriteSeq(0x02, 0x08); /* write to plane 3 */
1494 WriteSeq(0x04, 0x06); /* enable plane graphics */
1495 WriteGr(0x04, 0x03); /* read plane 3 */
1496 WriteGr(0x05, 0x00); /* write mode 0, read mode 0 */
1497 WriteGr(0x06, 0x05); /* set graphics */
1498 slowbcopy_tobus(pVBox->fonts + 8192, pVBox->VGAbase, 8192);
1499
1500 scrn = ReadSeq(pVBox, 0x01) & ~0x20;
1501 SeqReset(pVBox, TRUE);
1502 WriteSeq(0x01, scrn);
1503 SeqReset(pVBox, FALSE);
1504
1505 /* restore the registers that were changed */
1506 WriteMiscOut(miscOut);
1507 WriteAttr(pVBox, 0x10, attr10);
1508 WriteGr(0x01, gr1);
1509 WriteGr(0x03, gr3);
1510 WriteGr(0x04, gr4);
1511 WriteGr(0x05, gr5);
1512 WriteGr(0x06, gr6);
1513 WriteGr(0x08, gr8);
1514 WriteSeq(0x02, seq2);
1515 WriteSeq(0x04, seq4);
1516 }
1517 TRACE2;
1518}
1519
1520Bool
1521VBOXSaveRestore(ScrnInfoPtr pScrn, vbeSaveRestoreFunction function)
1522{
1523 VBOXPtr pVBox;
1524 Bool rc = TRUE;
1525
1526 TRACE;
1527 if (MODE_QUERY < 0 || function > MODE_RESTORE)
1528 rc = FALSE;
1529
1530 if (rc)
1531 {
1532 pVBox = VBOXGetRec(pScrn);
1533
1534 /* Query amount of memory to save state */
1535 if (function == MODE_QUERY ||
1536 (function == MODE_SAVE && pVBox->state == NULL))
1537 {
1538
1539 /* Make sure we save at least this information in case of failure */
1540 (void)VBEGetVBEMode(pVBox->pVbe, &pVBox->stateMode);
1541 SaveFonts(pScrn);
1542
1543 if (!VBESaveRestore(pVBox->pVbe,function,(pointer)&pVBox->state,
1544 &pVBox->stateSize,&pVBox->statePage)
1545 )
1546 rc = FALSE;
1547 }
1548 }
1549 if (rc)
1550 {
1551 /* Save/Restore Super VGA state */
1552 if (function != MODE_QUERY) {
1553
1554 if (function == MODE_RESTORE)
1555 memcpy(pVBox->state, pVBox->pstate,
1556 (unsigned) pVBox->stateSize);
1557
1558 if ( (rc = VBESaveRestore(pVBox->pVbe,function,
1559 (pointer)&pVBox->state,
1560 &pVBox->stateSize,&pVBox->statePage)
1561 )
1562 && (function == MODE_SAVE)
1563 )
1564 {
1565 /* don't rely on the memory not being touched */
1566 if (pVBox->pstate == NULL)
1567 pVBox->pstate = xalloc(pVBox->stateSize);
1568 memcpy(pVBox->pstate, pVBox->state,
1569 (unsigned) pVBox->stateSize);
1570 }
1571
1572 if (function == MODE_RESTORE)
1573 {
1574 VBESetVBEMode(pVBox->pVbe, pVBox->stateMode, NULL);
1575 RestoreFonts(pScrn);
1576 }
1577 }
1578 }
1579 TRACE3("returning %s\n", rc ? "TRUE" : "FALSE");
1580 return rc;
1581}
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