VirtualBox

source: vbox/trunk/src/VBox/Additions/x11/vboxvideo/vboxvideo_13.c@ 22087

Last change on this file since 22087 was 22087, checked in by vboxsync, 15 years ago

Additions/x11/vboxvideo_13: merged back vboxvideo_15 parts of r43690: Additions/x11/vboxvideo: more DRI updates

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