VirtualBox

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

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

Additions/x11/vboxvideo_13: Backported r31434 from vboxvideo_15: Additions/x11 and linux: make the Additions work with Fedora 9/X.org server 1.5

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