VirtualBox

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

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

Additions/x11: * fix for the case in which the video driver is loaded but the mouse driver not - in this case the mouse pointer will be drawn in software. * More logging clean-ups

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