VirtualBox

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

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

backing out r30216

  • Property svn:eol-style set to native
File size: 43.3 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 unsigned maxSize, trySize = 512;
752
753 do {
754 maxSize = trySize;
755 trySize += 128;
756 } while (trySize * trySize * pScrn->bitsPerPixel / 8 < pScrn->videoRam * 1024);
757
758 xf86CrtcSetSizeRange(pScrn, 64, 64, maxSize, maxSize);
759
760 /* I don't know exactly what these are for (and they are only used in a couple
761 of places in the X server code), but due to a bug in RandR 1.2 they place
762 an upper limit on possible resolutions. To add to the fun, they get set
763 automatically if we don't do it ourselves. */
764 pScrn->display->virtualX = maxSize;
765 pScrn->display->virtualY = maxSize;
766 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
767 "The maximum supported resolution is currently %dx%d\n", maxSize, maxSize);
768 }
769
770 /* We are not interested in the monitor section in the configuration file. */
771 xf86OutputUseScreenMonitor(output, FALSE);
772 output->possible_crtcs = 1;
773 output->possible_clones = 0;
774
775 /* Now create our initial CRTC/output configuration. */
776 if (!xf86InitialConfiguration(pScrn, TRUE)) {
777 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Initial CRTC configuration failed!\n");
778 return (FALSE);
779 }
780
781 /* Colour weight - we always call this, since we are always in
782 truecolour. */
783 if (!xf86SetWeight(pScrn, rzeros, rzeros))
784 return (FALSE);
785
786 /* visual init */
787 if (!xf86SetDefaultVisual(pScrn, -1))
788 return (FALSE);
789
790 xf86SetGamma(pScrn, gzeros);
791
792 /* Set a default display resolution. */
793 xf86SetDpi(pScrn, 96, 96);
794
795 /* Framebuffer-related setup */
796 pScrn->bitmapBitOrder = BITMAP_BIT_ORDER;
797
798 return (TRUE);
799}
800
801/*
802 * QUOTE from the XFree86 DESIGN document:
803 *
804 * This is called at the start of each server generation.
805 *
806 * (...)
807 *
808 * Decide which operations need to be placed under resource access
809 * control. (...) Map any video memory or other memory regions. (...)
810 * Save the video card state. (...) Initialise the initial video
811 * mode.
812 *
813 * End QUOTE.Initialise the initial video mode.
814 */
815static Bool
816VBOXScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
817{
818 ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
819 VBOXPtr pVBox = VBOXGetRec(pScrn);
820 VisualPtr visual;
821 unsigned flags;
822
823 /* We make use of the X11 VBE code to save and restore text mode, in
824 order to keep our code simple. */
825 if ((pVBox->pVbe = VBEExtendedInit(NULL, pVBox->pEnt->index,
826 SET_BIOS_SCRATCH
827 | RESTORE_BIOS_SCRATCH)) == NULL)
828 return (FALSE);
829
830 if (pVBox->mapPhys == 0) {
831 pVBox->mapPhys = pVBox->pciInfo->memBase[0];
832/* pVBox->mapSize = 1 << pVBox->pciInfo->size[0]; */
833 /* Using the PCI information caused problems with
834 non-powers-of-two sized video RAM configurations */
835 pVBox->mapSize = inl(VBE_DISPI_IOPORT_DATA);
836 pVBox->mapOff = 0;
837 }
838
839 if (!VBOXMapVidMem(pScrn))
840 return (FALSE);
841
842 /* save current video state */
843 VBOXSaveRestore(pScrn, MODE_SAVE);
844 pVBox->savedPal = VBESetGetPaletteData(pVBox->pVbe, FALSE, 0, 256,
845 NULL, FALSE, FALSE);
846
847 /* mi layer - reset the visual list (?)*/
848 miClearVisualTypes();
849 if (!xf86SetDefaultVisual(pScrn, -1))
850 return (FALSE);
851 if (!miSetVisualTypes(pScrn->depth, TrueColorMask,
852 pScrn->rgbBits, TrueColor))
853 return (FALSE);
854 if (!miSetPixmapDepths())
855 return (FALSE);
856
857 /* I checked in the sources, and XFree86 4.2 does seem to support
858 this function for 32bpp. */
859 if (!fbScreenInit(pScreen, pVBox->base,
860 pScrn->virtualX, pScrn->virtualY,
861 pScrn->xDpi, pScrn->yDpi,
862 pScrn->virtualX, pScrn->bitsPerPixel))
863 return (FALSE);
864
865 /* Fixup RGB ordering */
866 visual = pScreen->visuals + pScreen->numVisuals;
867 while (--visual >= pScreen->visuals) {
868 if ((visual->class | DynamicClass) == DirectColor) {
869 visual->offsetRed = pScrn->offset.red;
870 visual->offsetGreen = pScrn->offset.green;
871 visual->offsetBlue = pScrn->offset.blue;
872 visual->redMask = pScrn->mask.red;
873 visual->greenMask = pScrn->mask.green;
874 visual->blueMask = pScrn->mask.blue;
875 }
876 }
877
878 /* must be after RGB ordering fixed */
879 fbPictureInit(pScreen, 0, 0);
880
881 xf86SetBlackWhitePixels(pScreen);
882 miInitializeBackingStore(pScreen);
883 xf86SetBackingStore(pScreen);
884
885 /* Initialise DGA. The cast is unfortunately correct - it gets cast back
886 to (unsigned char *) later. */
887 xf86DiDGAInit(pScreen, (unsigned long) pVBox->base);
888
889 /* Initialise randr 1.2 mode-setting functions and set first mode. */
890 if (!xf86CrtcScreenInit(pScreen)) {
891 return FALSE;
892 }
893
894 if (!xf86SetDesiredModes(pScrn)) {
895 return FALSE;
896 }
897
898 /* set the viewport */
899 VBOXAdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
900
901 /* software cursor */
902 miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
903
904 /* colourmap code - apparently, we need this even in Truecolour */
905 if (!miCreateDefColormap(pScreen))
906 return (FALSE);
907
908 flags = CMAP_RELOAD_ON_MODE_SWITCH;
909
910 if(!xf86HandleColormaps(pScreen, 256,
911 8 /* DAC is switchable to 8 bits per primary color */,
912 VBOXLoadPalette, NULL, flags))
913 return (FALSE);
914
915 pVBox->CloseScreen = pScreen->CloseScreen;
916 pScreen->CloseScreen = VBOXCloseScreen;
917 pScreen->SaveScreen = xf86SaveScreen;
918
919 /* We probably do want to support power management - even if we just use
920 a dummy function. */
921 xf86DPMSInit(pScreen, xf86DPMSSet, 0);
922
923 /* Report any unused options (only for the first generation) */
924 if (serverGeneration == 1)
925 xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
926
927 if (vbox_open (pScrn, pScreen, pVBox)) {
928 if (vbox_cursor_init(pScreen) != TRUE)
929 xf86DrvMsg(scrnIndex, X_ERROR,
930 "Unable to start the VirtualBox mouse pointer integration with the host system.\n");
931 if (vboxEnableVbva(pScrn) == TRUE)
932 xf86DrvMsg(scrnIndex, X_INFO,
933 "The VBox video extensions are now enabled.\n");
934 vboxEnableGraphicsCap(pVBox);
935 /* Report the largest resolution that we support */
936// vboxReportMaxGuestResolution(pScrn->display->virtualX,
937// pScrn->display->virtualY);
938 }
939 return (TRUE);
940}
941
942static Bool
943VBOXEnterVT(int scrnIndex, int flags)
944{
945 ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
946
947 return xf86SetDesiredModes(pScrn);
948}
949
950static void
951VBOXLeaveVT(int scrnIndex, int flags)
952{
953 ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
954 VBOXPtr pVBox = VBOXGetRec(pScrn);
955
956 VBOXSaveRestore(pScrn, MODE_RESTORE);
957 if (pVBox->useVbva == TRUE)
958 vboxDisableVbva(pScrn);
959 vboxDisableGraphicsCap(pVBox);
960}
961
962static Bool
963VBOXCloseScreen(int scrnIndex, ScreenPtr pScreen)
964{
965 ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
966 VBOXPtr pVBox = VBOXGetRec(pScrn);
967
968 if (pVBox->useVbva == TRUE)
969 vboxDisableVbva(pScrn);
970 vboxDisableGraphicsCap(pVBox);
971 if (pScrn->vtSema) {
972 VBOXSaveRestore(xf86Screens[scrnIndex], MODE_RESTORE);
973 if (pVBox->savedPal)
974 VBESetGetPaletteData(pVBox->pVbe, TRUE, 0, 256,
975 pVBox->savedPal, FALSE, TRUE);
976 VBOXUnmapVidMem(pScrn);
977 }
978 pScrn->vtSema = FALSE;
979
980 pScreen->CloseScreen = pVBox->CloseScreen;
981 return pScreen->CloseScreen(scrnIndex, pScreen);
982}
983
984/**
985 * Quoted from "How to add an (S)VGA driver to XFree86"
986 * (http://www.xfree86.org/3.3.6/VGADriver.html):
987 *
988 * The ValidMode() function is required. It is used to check for any
989 * chipset-dependent reasons why a graphics mode might not be valid. It gets
990 * called by higher levels of the code after the Probe() stage. In many cases
991 * no special checking will be required and this function will simply return
992 * TRUE always.
993 *
994 * Note: we check here that our generated video modes fulfil the X server's
995 * criteria for the monitor, since this can otherwise cause problems in
996 * randr 1.2.
997 */
998static ModeStatus
999VBOXValidMode(int scrn, DisplayModePtr p, Bool flag, int pass)
1000{
1001 static int warned = 0;
1002 ScrnInfoPtr pScrn = xf86Screens[scrn];
1003 MonPtr mon = pScrn->monitor;
1004 ModeStatus ret = MODE_BAD;
1005 DisplayModePtr mode;
1006 float v;
1007
1008 if (pass != MODECHECK_FINAL) {
1009 if (!warned) {
1010 xf86DrvMsg(scrn, X_WARNING, "VBOXValidMode called unexpectedly\n");
1011 warned = 1;
1012 }
1013 }
1014#if 0
1015 /*
1016 * First off, if this isn't a mode we handed to the server (ie,
1017 * M_T_BUILTIN), then we reject it out of hand.
1018 */
1019 if (!(p->type & M_T_BUILTIN))
1020 return MODE_NOMODE;
1021#endif
1022 /*
1023 * Finally, walk through the vsync rates 1Hz at a time looking for a mode
1024 * that will fit. This is assuredly a terrible way to do this, but
1025 * there's no obvious method for computing a mode of a given size that
1026 * will pass xf86CheckModeForMonitor.
1027 */
1028 for (v = mon->vrefresh[0].lo; v <= mon->vrefresh[0].hi; v++) {
1029 mode = xf86CVTMode(p->HDisplay, p->VDisplay, v, 0, 0);
1030 ret = xf86CheckModeForMonitor(mode, mon);
1031 xfree(mode);
1032 if (ret == MODE_OK)
1033 break;
1034 }
1035
1036 if (ret != MODE_OK)
1037 {
1038 xf86DrvMsg(scrn, X_WARNING, "Graphics mode %s rejected by the X server\n", p->name);
1039 }
1040 return ret;
1041}
1042
1043static Bool
1044VBOXSwitchMode(int scrnIndex, DisplayModePtr pMode, int flags)
1045{
1046 ScrnInfoPtr pScrn;
1047
1048 pScrn = xf86Screens[scrnIndex]; /* Why does X have three ways of refering to the screen? */
1049 return xf86SetSingleMode(pScrn, pMode, 0);
1050}
1051
1052/* Set a graphics mode */
1053static Bool
1054VBOXSetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode)
1055{
1056 VBOXPtr pVBox;
1057
1058 int bpp = pScrn->depth == 24 ? 32 : 16;
1059 pVBox = VBOXGetRec(pScrn);
1060 if (pVBox->useVbva == TRUE)
1061 if (vboxDisableVbva(pScrn) != TRUE) /* This would be bad. */
1062 return FALSE;
1063 pScrn->vtSema = TRUE;
1064 /* Disable linear framebuffer mode before making changes to the resolution. */
1065 outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
1066 outw(VBE_DISPI_IOPORT_DATA,
1067 VBE_DISPI_DISABLED);
1068 /* Unlike the resolution, the depth is fixed for a given screen
1069 for the lifetime of the X session. */
1070 outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_BPP);
1071 outw(VBE_DISPI_IOPORT_DATA, bpp);
1072 /* HDisplay and VDisplay are actually monitor information about
1073 the display part of the scanlines. */
1074 outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_XRES);
1075 outw(VBE_DISPI_IOPORT_DATA, pMode->HDisplay);
1076 outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_YRES);
1077 outw(VBE_DISPI_IOPORT_DATA, pMode->VDisplay);
1078 /* Set the virtual resolution. We are still using VESA to control
1079 the virtual offset. */
1080 outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_VIRT_WIDTH);
1081 outw(VBE_DISPI_IOPORT_DATA, pScrn->displayWidth);
1082 /* Enable linear framebuffer mode. */
1083 outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
1084 outw(VBE_DISPI_IOPORT_DATA,
1085 VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED);
1086 if (pVBox->useVbva == TRUE)
1087 if (vboxEnableVbva(pScrn) != TRUE) /* Bad but not fatal */
1088 pVBox->useVbva = FALSE;
1089 vboxEnableGraphicsCap(pVBox);
1090 return (TRUE);
1091}
1092
1093static void
1094VBOXAdjustFrame(int scrnIndex, int x, int y, int flags)
1095{
1096 VBOXPtr pVBox = VBOXGetRec(xf86Screens[scrnIndex]);
1097
1098 VBESetDisplayStart(pVBox->pVbe, x, y, TRUE);
1099}
1100
1101static void
1102VBOXFreeScreen(int scrnIndex, int flags)
1103{
1104 VBOXFreeRec(xf86Screens[scrnIndex]);
1105}
1106
1107static Bool
1108VBOXMapVidMem(ScrnInfoPtr pScrn)
1109{
1110 VBOXPtr pVBox = VBOXGetRec(pScrn);
1111
1112 if (pVBox->base != NULL)
1113 return (TRUE);
1114
1115 pScrn->memPhysBase = pVBox->mapPhys;
1116 pScrn->fbOffset = pVBox->mapOff;
1117
1118 pVBox->base = xf86MapPciMem(pScrn->scrnIndex,
1119 VIDMEM_FRAMEBUFFER,
1120 pVBox->pciTag, pVBox->mapPhys,
1121 (unsigned) pVBox->mapSize);
1122
1123 if (pVBox->base) {
1124 pScrn->memPhysBase = pVBox->mapPhys;
1125 pVBox->VGAbase = xf86MapDomainMemory(pScrn->scrnIndex, 0,
1126 pVBox->pciTag,
1127 0xa0000, 0x10000);
1128 }
1129 /* We need this for saving/restoring textmode */
1130 pVBox->ioBase = pScrn->domainIOBase;
1131
1132 return (pVBox->base != NULL);
1133}
1134
1135static void
1136VBOXUnmapVidMem(ScrnInfoPtr pScrn)
1137{
1138 VBOXPtr pVBox = VBOXGetRec(pScrn);
1139
1140 if (pVBox->base == NULL)
1141 return;
1142
1143 xf86UnMapVidMem(pScrn->scrnIndex, pVBox->base,
1144 (unsigned) pVBox->mapSize);
1145 xf86UnMapVidMem(pScrn->scrnIndex, pVBox->VGAbase, 0x10000);
1146 pVBox->base = NULL;
1147}
1148
1149static void
1150VBOXLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices,
1151 LOCO *colors, VisualPtr pVisual)
1152{
1153 VBOXPtr pVBox = VBOXGetRec(pScrn);
1154 int i, idx;
1155#define VBOXDACDelay() \
1156 do { \
1157 (void)inb(pVBox->ioBase + VGA_IOBASE_COLOR + VGA_IN_STAT_1_OFFSET); \
1158 (void)inb(pVBox->ioBase + VGA_IOBASE_COLOR + VGA_IN_STAT_1_OFFSET); \
1159 } while (0)
1160
1161 for (i = 0; i < numColors; i++) {
1162 idx = indices[i];
1163 outb(pVBox->ioBase + VGA_DAC_WRITE_ADDR, idx);
1164 VBOXDACDelay();
1165 outb(pVBox->ioBase + VGA_DAC_DATA, colors[idx].red);
1166 VBOXDACDelay();
1167 outb(pVBox->ioBase + VGA_DAC_DATA, colors[idx].green);
1168 VBOXDACDelay();
1169 outb(pVBox->ioBase + VGA_DAC_DATA, colors[idx].blue);
1170 VBOXDACDelay();
1171 }
1172}
1173
1174/*
1175 * Just adapted from the std* functions in vgaHW.c
1176 */
1177static void
1178WriteAttr(VBOXPtr pVBox, int index, int value)
1179{
1180 (void) inb(pVBox->ioBase + VGA_IOBASE_COLOR + VGA_IN_STAT_1_OFFSET);
1181
1182 index |= 0x20;
1183 outb(pVBox->ioBase + VGA_ATTR_INDEX, index);
1184 outb(pVBox->ioBase + VGA_ATTR_DATA_W, value);
1185}
1186
1187static int
1188ReadAttr(VBOXPtr pVBox, int index)
1189{
1190 (void) inb(pVBox->ioBase + VGA_IOBASE_COLOR + VGA_IN_STAT_1_OFFSET);
1191
1192 index |= 0x20;
1193 outb(pVBox->ioBase + VGA_ATTR_INDEX, index);
1194 return (inb(pVBox->ioBase + VGA_ATTR_DATA_R));
1195}
1196
1197#define WriteMiscOut(value) outb(pVBox->ioBase + VGA_MISC_OUT_W, value)
1198#define ReadMiscOut() inb(pVBox->ioBase + VGA_MISC_OUT_R)
1199#define WriteSeq(index, value) \
1200 outb(pVBox->ioBase + VGA_SEQ_INDEX, (index));\
1201 outb(pVBox->ioBase + VGA_SEQ_DATA, value)
1202
1203static int
1204ReadSeq(VBOXPtr pVBox, int index)
1205{
1206 outb(pVBox->ioBase + VGA_SEQ_INDEX, index);
1207
1208 return (inb(pVBox->ioBase + VGA_SEQ_DATA));
1209}
1210
1211#define WriteGr(index, value) \
1212 outb(pVBox->ioBase + VGA_GRAPH_INDEX, index); \
1213 outb(pVBox->ioBase + VGA_GRAPH_DATA, value)
1214
1215static int
1216ReadGr(VBOXPtr pVBox, int index)
1217{
1218 outb(pVBox->ioBase + VGA_GRAPH_INDEX, index);
1219
1220 return (inb(pVBox->ioBase + VGA_GRAPH_DATA));
1221}
1222
1223#define WriteCrtc(index, value) \
1224 outb(pVBox->ioBase + (VGA_IOBASE_COLOR + VGA_CRTC_INDEX_OFFSET), index); \
1225 outb(pVBox->ioBase + (VGA_IOBASE_COLOR + VGA_CRTC_DATA_OFFSET), value)
1226
1227static void
1228SeqReset(VBOXPtr pVBox, Bool start)
1229{
1230 if (start) {
1231 WriteSeq(0x00, 0x01); /* Synchronous Reset */
1232 }
1233 else {
1234 WriteSeq(0x00, 0x03); /* End Reset */
1235 }
1236}
1237
1238static void
1239SaveFonts(ScrnInfoPtr pScrn)
1240{
1241 VBOXPtr pVBox = VBOXGetRec(pScrn);
1242 unsigned char miscOut, attr10, gr4, gr5, gr6, seq2, seq4, scrn;
1243
1244 if (pVBox->fonts != NULL)
1245 return;
1246
1247 /* If in graphics mode, don't save anything */
1248 attr10 = ReadAttr(pVBox, 0x10);
1249 if (attr10 & 0x01)
1250 return;
1251
1252 pVBox->fonts = xalloc(16384);
1253
1254 /* save the registers that are needed here */
1255 miscOut = ReadMiscOut();
1256 gr4 = ReadGr(pVBox, 0x04);
1257 gr5 = ReadGr(pVBox, 0x05);
1258 gr6 = ReadGr(pVBox, 0x06);
1259 seq2 = ReadSeq(pVBox, 0x02);
1260 seq4 = ReadSeq(pVBox, 0x04);
1261
1262 /* Force into colour mode */
1263 WriteMiscOut(miscOut | 0x01);
1264
1265 scrn = ReadSeq(pVBox, 0x01) | 0x20;
1266 SeqReset(pVBox, TRUE);
1267 WriteSeq(0x01, scrn);
1268 SeqReset(pVBox, FALSE);
1269
1270 WriteAttr(pVBox, 0x10, 0x01); /* graphics mode */
1271
1272 /*font1 */
1273 WriteSeq(0x02, 0x04); /* write to plane 2 */
1274 WriteSeq(0x04, 0x06); /* enable plane graphics */
1275 WriteGr(0x04, 0x02); /* read plane 2 */
1276 WriteGr(0x05, 0x00); /* write mode 0, read mode 0 */
1277 WriteGr(0x06, 0x05); /* set graphics */
1278 slowbcopy_frombus(pVBox->VGAbase, pVBox->fonts, 8192);
1279
1280 /* font2 */
1281 WriteSeq(0x02, 0x08); /* write to plane 3 */
1282 WriteSeq(0x04, 0x06); /* enable plane graphics */
1283 WriteGr(0x04, 0x03); /* read plane 3 */
1284 WriteGr(0x05, 0x00); /* write mode 0, read mode 0 */
1285 WriteGr(0x06, 0x05); /* set graphics */
1286 slowbcopy_frombus(pVBox->VGAbase, pVBox->fonts + 8192, 8192);
1287
1288 scrn = ReadSeq(pVBox, 0x01) & ~0x20;
1289 SeqReset(pVBox, TRUE);
1290 WriteSeq(0x01, scrn);
1291 SeqReset(pVBox, FALSE);
1292
1293 /* Restore clobbered registers */
1294 WriteAttr(pVBox, 0x10, attr10);
1295 WriteSeq(0x02, seq2);
1296 WriteSeq(0x04, seq4);
1297 WriteGr(0x04, gr4);
1298 WriteGr(0x05, gr5);
1299 WriteGr(0x06, gr6);
1300 WriteMiscOut(miscOut);
1301}
1302
1303static void
1304RestoreFonts(ScrnInfoPtr pScrn)
1305{
1306 VBOXPtr pVBox = VBOXGetRec(pScrn);
1307 unsigned char miscOut, attr10, gr1, gr3, gr4, gr5, gr6, gr8, seq2, seq4, scrn;
1308
1309 if (pVBox->fonts == NULL)
1310 return;
1311
1312 /* save the registers that are needed here */
1313 miscOut = ReadMiscOut();
1314 attr10 = ReadAttr(pVBox, 0x10);
1315 gr1 = ReadGr(pVBox, 0x01);
1316 gr3 = ReadGr(pVBox, 0x03);
1317 gr4 = ReadGr(pVBox, 0x04);
1318 gr5 = ReadGr(pVBox, 0x05);
1319 gr6 = ReadGr(pVBox, 0x06);
1320 gr8 = ReadGr(pVBox, 0x08);
1321 seq2 = ReadSeq(pVBox, 0x02);
1322 seq4 = ReadSeq(pVBox, 0x04);
1323
1324 /* Force into colour mode */
1325 WriteMiscOut(miscOut | 0x01);
1326
1327 scrn = ReadSeq(pVBox, 0x01) & ~0x20;
1328 SeqReset(pVBox, TRUE);
1329 WriteSeq(0x01, scrn);
1330 SeqReset(pVBox, FALSE);
1331
1332 WriteAttr(pVBox, 0x10, 0x01); /* graphics mode */
1333 if (pScrn->depth == 4) {
1334 /* GJA */
1335 WriteGr(0x03, 0x00); /* don't rotate, write unmodified */
1336 WriteGr(0x08, 0xFF); /* write all bits in a byte */
1337 WriteGr(0x01, 0x00); /* all planes come from CPU */
1338 }
1339
1340 WriteSeq(0x02, 0x04); /* write to plane 2 */
1341 WriteSeq(0x04, 0x06); /* enable plane graphics */
1342 WriteGr(0x04, 0x02); /* read plane 2 */
1343 WriteGr(0x05, 0x00); /* write mode 0, read mode 0 */
1344 WriteGr(0x06, 0x05); /* set graphics */
1345 slowbcopy_tobus(pVBox->fonts, pVBox->VGAbase, 8192);
1346
1347 WriteSeq(0x02, 0x08); /* write to plane 3 */
1348 WriteSeq(0x04, 0x06); /* enable plane graphics */
1349 WriteGr(0x04, 0x03); /* read plane 3 */
1350 WriteGr(0x05, 0x00); /* write mode 0, read mode 0 */
1351 WriteGr(0x06, 0x05); /* set graphics */
1352 slowbcopy_tobus(pVBox->fonts + 8192, pVBox->VGAbase, 8192);
1353
1354 scrn = ReadSeq(pVBox, 0x01) & ~0x20;
1355 SeqReset(pVBox, TRUE);
1356 WriteSeq(0x01, scrn);
1357 SeqReset(pVBox, FALSE);
1358
1359 /* restore the registers that were changed */
1360 WriteMiscOut(miscOut);
1361 WriteAttr(pVBox, 0x10, attr10);
1362 WriteGr(0x01, gr1);
1363 WriteGr(0x03, gr3);
1364 WriteGr(0x04, gr4);
1365 WriteGr(0x05, gr5);
1366 WriteGr(0x06, gr6);
1367 WriteGr(0x08, gr8);
1368 WriteSeq(0x02, seq2);
1369 WriteSeq(0x04, seq4);
1370}
1371
1372Bool
1373VBOXSaveRestore(ScrnInfoPtr pScrn, vbeSaveRestoreFunction function)
1374{
1375 VBOXPtr pVBox;
1376
1377 if (MODE_QUERY < 0 || function > MODE_RESTORE)
1378 return (FALSE);
1379
1380 pVBox = VBOXGetRec(pScrn);
1381
1382
1383 /* Query amount of memory to save state */
1384 if (function == MODE_QUERY ||
1385 (function == MODE_SAVE && pVBox->state == NULL))
1386 {
1387
1388 /* Make sure we save at least this information in case of failure */
1389 (void)VBEGetVBEMode(pVBox->pVbe, &pVBox->stateMode);
1390 SaveFonts(pScrn);
1391
1392 if (!VBESaveRestore(pVBox->pVbe,function,(pointer)&pVBox->state,
1393 &pVBox->stateSize,&pVBox->statePage))
1394 return FALSE;
1395 }
1396
1397 /* Save/Restore Super VGA state */
1398 if (function != MODE_QUERY) {
1399 Bool retval = TRUE;
1400
1401 if (function == MODE_RESTORE)
1402 memcpy(pVBox->state, pVBox->pstate,
1403 (unsigned) pVBox->stateSize);
1404
1405 if ((retval = VBESaveRestore(pVBox->pVbe,function,
1406 (pointer)&pVBox->state,
1407 &pVBox->stateSize,&pVBox->statePage))
1408 && function == MODE_SAVE)
1409 {
1410 /* don't rely on the memory not being touched */
1411 if (pVBox->pstate == NULL)
1412 pVBox->pstate = xalloc(pVBox->stateSize);
1413 memcpy(pVBox->pstate, pVBox->state,
1414 (unsigned) pVBox->stateSize);
1415 }
1416
1417 if (function == MODE_RESTORE)
1418 {
1419 VBESetVBEMode(pVBox->pVbe, pVBox->stateMode, NULL);
1420 RestoreFonts(pScrn);
1421 }
1422
1423 if (!retval)
1424 return (FALSE);
1425
1426 }
1427
1428 return (TRUE);
1429}
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