VirtualBox

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

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

cosmetics

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