VirtualBox

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

Last change on this file since 9663 was 9018, checked in by vboxsync, 17 years ago

Additions/x11: rename the graphics driver output to VBOX1 and only enable dynamic resizing if our graphics driver is running on the display the client is connected to

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