VirtualBox

source: vbox/trunk/src/VBox/Additions/x11/xgraphics/vboxvideo_15.c@ 9860

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

Additions/x11: make the Xorg 1.3+ Additions handle modes specified by the user in xorg.conf

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette