VirtualBox

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

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

Additions (x11): added randr 1.2 support to the graphics driver

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