VirtualBox

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

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

Additions/x11: round video mode hint width values down to a multiple of 8 to prevent X11 from rounding them up to a value potentially greater than the framebuffer likes

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