VirtualBox

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

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

Additions/x11 and linux: make the Additions work with Fedora 9/X.org server 1.5

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