VirtualBox

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

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

Additions/X11: make the X11 drivers work again when the kernel module fails to load

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