VirtualBox

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

Last change on this file since 22086 was 22086, checked in by vboxsync, 15 years ago

Additions/x11/vboxvideo_13: merged back vboxvideo_15 parts of r41801: Additions/x11 and Linux: added support for X.Org server 1.6

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