VirtualBox

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

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

Additions/x11: hopefully got rid of the resolution limit in the X11 graphics driver

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