VirtualBox

source: vbox/trunk/src/VBox/Additions/x11/vboxvideo/vboxvideo_15.c@ 21747

Last change on this file since 21747 was 21747, checked in by vboxsync, 16 years ago

Additions/x11: print the address of well know symbols to the Xorg log when our drivers are loaded to help with debugging crashes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 51.8 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 VBOXVIDEO = {
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.
209 * Round up if necessary. */
210 width = (width + 7) & ~7;
211 if (width * height * bpp / 8 >= scrn->videoRam * 1024)
212 {
213 xf86DrvMsg(scrn->scrnIndex, X_ERROR,
214 "Unable to set up a virtual screen size of %dx%d with %d Kb of video memory. Please increase the video memory size.\n",
215 width, height, scrn->videoRam);
216 rc = FALSE;
217 }
218 if (rc) {
219 pPixmap = pScreen->GetScreenPixmap(pScreen);
220 if (NULL == pPixmap) {
221 xf86DrvMsg(scrn->scrnIndex, X_ERROR,
222 "Failed to get the screen pixmap.\n");
223 rc = FALSE;
224 }
225 }
226 if (rc) {
227 if (
228 !pScreen->ModifyPixmapHeader(pPixmap, width, height,
229 scrn->depth, bpp, width * bpp / 8,
230 pVBox->base)
231 ) {
232 xf86DrvMsg(scrn->scrnIndex, X_ERROR,
233 "Failed to set up the screen pixmap.\n");
234 rc = FALSE;
235 }
236 }
237 if (rc) {
238 scrn->virtualX = width;
239 scrn->virtualY = height;
240 scrn->displayWidth = width;
241#ifdef VBOX_DRI
242 if (pVBox->useDRI)
243 VBOXDRIUpdateStride(scrn, pVBox);
244#endif
245 }
246 TRACE_LOG("returning %s\n", rc ? "TRUE" : "FALSE");
247 return rc;
248}
249
250static const xf86CrtcConfigFuncsRec VBOXCrtcConfigFuncs = {
251 VBOXCrtcResize
252};
253
254static void
255vbox_crtc_dpms(xf86CrtcPtr crtc, int mode)
256{ (void) crtc; (void) mode; }
257
258static Bool
259vbox_crtc_lock (xf86CrtcPtr crtc)
260{ (void) crtc; return FALSE; }
261
262static Bool
263vbox_crtc_mode_fixup (xf86CrtcPtr crtc, DisplayModePtr mode,
264 DisplayModePtr adjusted_mode)
265{
266 ScrnInfoPtr pScrn = crtc->scrn;
267 int xRes = adjusted_mode->HDisplay;
268
269 (void) mode;
270 TRACE_LOG("name=%s, HDisplay=%d, VDisplay=%d\n", adjusted_mode->name,
271 adjusted_mode->HDisplay, adjusted_mode->VDisplay);
272 /* We only support horizontal resolutions which are a multiple of 8. Round down if
273 necessary. */
274 if (xRes % 8 != 0)
275 {
276 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
277 "VirtualBox only supports screen widths which are a multiple of 8. Rounding down from %d to %d\n",
278 xRes, xRes - (xRes % 8));
279 adjusted_mode->HDisplay = xRes - (xRes % 8);
280 }
281 return TRUE;
282}
283
284static void
285vbox_crtc_stub (xf86CrtcPtr crtc)
286{ (void) crtc; }
287
288static void
289vbox_crtc_mode_set (xf86CrtcPtr crtc, DisplayModePtr mode,
290 DisplayModePtr adjusted_mode, int x, int y)
291{
292 (void) mode;
293 TRACE_LOG("name=%s, HDisplay=%d, VDisplay=%d, x=%d, y=%d\n", adjusted_mode->name,
294 adjusted_mode->HDisplay, adjusted_mode->VDisplay, x, y);
295 VBOXSetMode(crtc->scrn, adjusted_mode);
296 VBOXAdjustFrame(crtc->scrn->scrnIndex, x, y, 0);
297 vboxSaveVideoMode(crtc->scrn, adjusted_mode->HDisplay,
298 adjusted_mode->VDisplay, crtc->scrn->bitsPerPixel);
299}
300
301static void
302vbox_crtc_gamma_set (xf86CrtcPtr crtc, CARD16 *red,
303 CARD16 *green, CARD16 *blue, int size)
304{ (void) crtc; (void) red; (void) green; (void) blue; (void) size; }
305
306static void *
307vbox_crtc_shadow_allocate (xf86CrtcPtr crtc, int width, int height)
308{ (void) crtc; (void) width; (void) height; return NULL; }
309
310static const xf86CrtcFuncsRec VBOXCrtcFuncs = {
311 .dpms = vbox_crtc_dpms,
312 .save = NULL, /* These two are never called by the server. */
313 .restore = NULL,
314 .lock = vbox_crtc_lock,
315 .unlock = NULL, /* This will not be invoked if lock returns FALSE. */
316 .mode_fixup = vbox_crtc_mode_fixup,
317 .prepare = vbox_crtc_stub,
318 .mode_set = vbox_crtc_mode_set,
319 .commit = vbox_crtc_stub,
320 .gamma_set = vbox_crtc_gamma_set,
321 .shadow_allocate = vbox_crtc_shadow_allocate,
322 .shadow_create = NULL, /* These two should not be invoked if allocate
323 returns NULL. */
324 .shadow_destroy = NULL,
325 .set_cursor_colors = NULL, /* We are still using the old cursor API. */
326 .set_cursor_position = NULL,
327 .show_cursor = NULL,
328 .hide_cursor = NULL,
329 .load_cursor_argb = NULL,
330 .destroy = vbox_crtc_stub
331};
332
333static void
334vbox_output_stub (xf86OutputPtr output)
335{ (void) output; }
336
337static void
338vbox_output_dpms (xf86OutputPtr output, int mode)
339{ (void) output; (void) mode; }
340
341static int
342vbox_output_mode_valid (xf86OutputPtr output, DisplayModePtr mode)
343{
344 ScrnInfoPtr pScrn = output->scrn;
345 int rc = MODE_OK;
346 TRACE_LOG("HDisplay=%d, VDisplay=%d\n", mode->HDisplay, mode->VDisplay);
347 /* We always like modes specified by the user in the configuration
348 * file, as doing otherwise is likely to annoy people. */
349 if ( !(mode->type & M_T_USERDEF)
350 && vbox_device_available(VBOXGetRec(pScrn))
351 && !vboxHostLikesVideoMode(pScrn, mode->HDisplay, mode->VDisplay,
352 pScrn->bitsPerPixel)
353 )
354 rc = MODE_BAD;
355 TRACE_LOG("returning %s\n", MODE_OK == rc ? "MODE_OK" : "MODE_BAD");
356 return rc;
357}
358
359static Bool
360vbox_output_mode_fixup (xf86OutputPtr output, DisplayModePtr mode,
361 DisplayModePtr adjusted_mode)
362{ (void) output; (void) mode; (void) adjusted_mode; return TRUE; }
363
364static void
365vbox_output_mode_set (xf86OutputPtr output, DisplayModePtr mode,
366 DisplayModePtr adjusted_mode)
367{ (void) output; (void) mode; (void) adjusted_mode; }
368
369/* A virtual monitor is always connected. */
370static xf86OutputStatus
371vbox_output_detect (xf86OutputPtr output)
372{
373 (void) output;
374 return XF86OutputStatusConnected;
375}
376
377static void
378vbox_output_add_mode (DisplayModePtr *pModes, const char *pszName, int x, int y,
379 Bool isPreferred, Bool isUserDef)
380{
381 TRACE_LOG("pszName=%s, x=%d, y=%d\n", pszName, x, y);
382 DisplayModePtr pMode = xnfcalloc(1, sizeof(DisplayModeRec));
383
384 pMode->status = MODE_OK;
385 /* We don't ask the host whether it likes user defined modes,
386 * as we assume that the user really wanted that mode. */
387 pMode->type = isUserDef ? M_T_USERDEF : M_T_BUILTIN;
388 if (isPreferred)
389 pMode->type |= M_T_PREFERRED;
390 /* VBox only supports screen widths which are a multiple of 8 */
391 pMode->HDisplay = (x + 7) & ~7;
392 pMode->HSyncStart = pMode->HDisplay + 2;
393 pMode->HSyncEnd = pMode->HDisplay + 4;
394 pMode->HTotal = pMode->HDisplay + 6;
395 pMode->VDisplay = y;
396 pMode->VSyncStart = pMode->VDisplay + 2;
397 pMode->VSyncEnd = pMode->VDisplay + 4;
398 pMode->VTotal = pMode->VDisplay + 6;
399 pMode->Clock = pMode->HTotal * pMode->VTotal * 60 / 1000; /* kHz */
400 if (NULL == pszName) {
401 xf86SetModeDefaultName(pMode);
402 } else {
403 pMode->name = xnfstrdup(pszName);
404 }
405 *pModes = xf86ModesAdd(*pModes, pMode);
406}
407
408static DisplayModePtr
409vbox_output_get_modes (xf86OutputPtr output)
410{
411 bool rc;
412 unsigned i;
413 DisplayModePtr pModes = NULL;
414 ScrnInfoPtr pScrn = output->scrn;
415 VBOXPtr pVBox = VBOXGetRec(pScrn);
416
417 TRACE_ENTRY();
418 if (vbox_device_available(pVBox))
419 {
420 uint32_t x, y, bpp, display;
421 rc = vboxGetDisplayChangeRequest(pScrn, &x, &y, &bpp, &display);
422 /* @todo - check the display number once we support multiple displays. */
423 /* If we don't find a display request, see if we have a saved hint
424 * from a previous session. */
425 if (!rc || (0 == x) || (0 == y))
426 rc = vboxRetrieveVideoMode(pScrn, &x, &y, &bpp);
427 if (rc && (0 != x) && (0 != y)) {
428 /* We prefer a slightly smaller size to a slightly larger one */
429 x -= (x % 8);
430 vbox_output_add_mode(&pModes, NULL, x, y, TRUE, FALSE);
431 }
432 }
433 /* Also report any modes the user may have requested in the xorg.conf
434 * configuration file. */
435 for (i = 0; pScrn->display->modes[i] != NULL; i++)
436 {
437 int x, y;
438 if (2 == sscanf(pScrn->display->modes[i], "%dx%d", &x, &y))
439 vbox_output_add_mode(&pModes, pScrn->display->modes[i], x, y,
440 FALSE, TRUE);
441 }
442 TRACE_EXIT();
443 return pModes;
444}
445
446#ifdef RANDR_12_INTERFACE
447/* We don't yet have mutable properties, whatever they are. */
448static Bool
449vbox_output_set_property(xf86OutputPtr output, Atom property,
450 RRPropertyValuePtr value)
451{ (void) output; (void) property; (void) value; return FALSE; }
452#endif
453
454static const xf86OutputFuncsRec VBOXOutputFuncs = {
455 .create_resources = vbox_output_stub,
456 .dpms = vbox_output_dpms,
457 .save = NULL, /* These two are never called by the server. */
458 .restore = NULL,
459 .mode_valid = vbox_output_mode_valid,
460 .mode_fixup = vbox_output_mode_fixup,
461 .prepare = vbox_output_stub,
462 .commit = vbox_output_stub,
463 .mode_set = vbox_output_mode_set,
464 .detect = vbox_output_detect,
465 .get_modes = vbox_output_get_modes,
466#ifdef RANDR_12_INTERFACE
467 .set_property = vbox_output_set_property,
468#endif
469 .destroy = vbox_output_stub
470};
471
472/*
473 * List of symbols from other modules that this module references. This
474 * list is used to tell the loader that it is OK for symbols here to be
475 * unresolved providing that it hasn't been told that they are essential
476 * via a call to xf86LoaderReqSymbols() or xf86LoaderReqSymLists(). The
477 * purpose is this is to avoid warnings about unresolved symbols that are
478 * not required.
479 */
480static const char *fbSymbols[] = {
481 "fbPictureInit",
482 "fbScreenInit",
483 NULL
484};
485
486static const char *shadowfbSymbols[] = {
487 "ShadowFBInit2",
488 NULL
489};
490
491static const char *vbeSymbols[] = {
492 "VBEExtendedInit",
493 "VBEFindSupportedDepths",
494 "VBEGetModeInfo",
495 "VBEGetVBEInfo",
496 "VBEGetVBEMode",
497 "VBEPrintModes",
498 "VBESaveRestore",
499 "VBESetDisplayStart",
500 "VBESetGetDACPaletteFormat",
501 "VBESetGetLogicalScanlineLength",
502 "VBESetGetPaletteData",
503 "VBESetModeNames",
504 "VBESetModeParameters",
505 "VBESetVBEMode",
506 "VBEValidateModes",
507 "vbeDoEDID",
508 "vbeFree",
509 NULL
510};
511
512static const char *ramdacSymbols[] = {
513 "xf86InitCursor",
514 "xf86CreateCursorInfoRec",
515 NULL
516};
517
518#ifdef VBOX_DRI
519static const char *drmSymbols[] = {
520 "drmFreeVersion",
521 "drmGetVersion",
522 NULL
523};
524
525static const char *driSymbols[] = {
526 "DRICloseScreen",
527 "DRICreateInfoRec",
528 "DRIDestroyInfoRec",
529 "DRIFinishScreenInit",
530 "DRIGetSAREAPrivate",
531 "DRILock",
532 "DRIMoveBuffersHelper",
533 "DRIQueryVersion",
534 "DRIScreenInit",
535 "DRIUnlock",
536 "GlxSetVisualConfigs",
537 "DRICreatePCIBusID",
538 NULL
539};
540#endif
541
542#ifdef XFree86LOADER
543/* Module loader interface */
544static MODULESETUPPROTO(vboxSetup);
545
546static XF86ModuleVersionInfo vboxVersionRec =
547{
548 VBOX_DRIVER_NAME,
549 "Sun Microsystems, Inc.",
550 MODINFOSTRING1,
551 MODINFOSTRING2,
552 XORG_VERSION_CURRENT,
553 1, /* Module major version. Xorg-specific */
554 0, /* Module minor version. Xorg-specific */
555 1, /* Module patchlevel. Xorg-specific */
556 ABI_CLASS_VIDEODRV, /* This is a video driver */
557 ABI_VIDEODRV_VERSION,
558 MOD_CLASS_VIDEODRV,
559 {0, 0, 0, 0}
560};
561
562/*
563 * This data is accessed by the loader. The name must be the module name
564 * followed by "ModuleData".
565 */
566_X_EXPORT XF86ModuleData vboxvideoModuleData = { &vboxVersionRec, vboxSetup, NULL };
567
568static pointer
569vboxSetup(pointer Module, pointer Options, int *ErrorMajor, int *ErrorMinor)
570{
571 static Bool Initialised = FALSE;
572
573 if (!Initialised)
574 {
575 Initialised = TRUE;
576#ifdef PCIACCESS
577 xf86AddDriver(&VBOXVIDEO, Module, HaveDriverFuncs);
578#else
579 xf86AddDriver(&VBOXVIDEO, Module, 0);
580#endif
581 xf86Msg(X_CONFIG, "Load address of symbol \"VBOXVIDEO\" is %p\n",
582 (void *)&VBOXVIDEO);
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 and maximum mode size */
853 xf86CrtcSetSizeRange(pScrn, 64, 64, 32000, 32000);
854
855 /* We are not interested in the monitor section in the configuration file. */
856 xf86OutputUseScreenMonitor(output, FALSE);
857 output->possible_crtcs = 1;
858 output->possible_clones = 0;
859
860 /* Now create our initial CRTC/output configuration. */
861 if (!xf86InitialConfiguration(pScrn, TRUE)) {
862 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Initial CRTC configuration failed!\n");
863 return (FALSE);
864 }
865
866 /* Colour weight - we always call this, since we are always in
867 truecolour. */
868 if (!xf86SetWeight(pScrn, rzeros, rzeros))
869 return (FALSE);
870
871 /* visual init */
872 if (!xf86SetDefaultVisual(pScrn, -1))
873 return (FALSE);
874
875 xf86SetGamma(pScrn, gzeros);
876
877 /* Set a default display resolution. */
878 xf86SetDpi(pScrn, 96, 96);
879
880 /* Framebuffer-related setup */
881 pScrn->bitmapBitOrder = BITMAP_BIT_ORDER;
882
883#ifdef VBOX_DRI
884 /* Load the dri module. */
885 if (xf86LoadSubModule(pScrn, "dri")) {
886 xf86LoaderReqSymLists(driSymbols, drmSymbols, NULL);
887 }
888#endif
889 return (TRUE);
890}
891
892/**
893 * This function hooks into the chain that is called when framebuffer access
894 * is allowed or disallowed by a call to EnableDisableFBAccess in the server.
895 * In other words, it observes when the server wishes access to the
896 * framebuffer to be enabled and when it should be disabled. We need to know
897 * this because we disable access ourselves during mode switches (presumably
898 * the server should do this but it doesn't) and want to know whether to
899 * restore it or not afterwards.
900 */
901static void
902vboxEnableDisableFBAccess(int scrnIndex, Bool enable)
903{
904 ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
905 VBOXPtr pVBox = VBOXGetRec(pScrn);
906
907 TRACE_LOG("enable=%s\n", enable ? "TRUE" : "FALSE");
908 pVBox->accessEnabled = enable;
909 pVBox->EnableDisableFBAccess(scrnIndex, enable);
910 TRACE_EXIT();
911}
912
913/*
914 * QUOTE from the XFree86 DESIGN document:
915 *
916 * This is called at the start of each server generation.
917 *
918 * (...)
919 *
920 * Decide which operations need to be placed under resource access
921 * control. (...) Map any video memory or other memory regions. (...)
922 * Save the video card state. (...) Initialise the initial video
923 * mode.
924 *
925 * End QUOTE.Initialise the initial video mode.
926 */
927static Bool
928VBOXScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
929{
930 ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
931 VBOXPtr pVBox = VBOXGetRec(pScrn);
932 VisualPtr visual;
933 unsigned flags;
934
935 if (pVBox->mapPhys == 0) {
936#ifdef PCIACCESS
937 pVBox->mapPhys = pVBox->pciInfo->regions[0].base_addr;
938#else
939 pVBox->mapPhys = pVBox->pciInfo->memBase[0];
940#endif
941/* pVBox->mapSize = 1 << pVBox->pciInfo->size[0]; */
942 /* Using the PCI information caused problems with
943 non-powers-of-two sized video RAM configurations */
944 pVBox->mapSize = inl(VBE_DISPI_IOPORT_DATA);
945 pVBox->mapOff = 0;
946 }
947
948 if (!VBOXMapVidMem(pScrn))
949 return (FALSE);
950
951 /* save current video state */
952 VBOXSaveRestore(pScrn, MODE_SAVE);
953 pVBox->savedPal = VBESetGetPaletteData(pVBox->pVbe, FALSE, 0, 256,
954 NULL, FALSE, FALSE);
955
956 /* mi layer - reset the visual list (?)*/
957 miClearVisualTypes();
958 if (!xf86SetDefaultVisual(pScrn, -1))
959 return (FALSE);
960 if (!miSetVisualTypes(pScrn->depth, TrueColorMask,
961 pScrn->rgbBits, TrueColor))
962 return (FALSE);
963 if (!miSetPixmapDepths())
964 return (FALSE);
965
966 /* Needed before we initialise DRI. */
967 pScrn->virtualX = (pScrn->virtualX + 7) & ~7;
968 pScrn->displayWidth = pScrn->virtualX;
969
970#ifdef VBOX_DRI
971 pVBox->useDRI = VBOXDRIScreenInit(scrnIndex, pScreen, pVBox);
972#endif
973
974 /* I checked in the sources, and XFree86 4.2 does seem to support
975 this function for 32bpp. */
976 if (!fbScreenInit(pScreen, pVBox->base,
977 pScrn->virtualX, pScrn->virtualY,
978 pScrn->xDpi, pScrn->yDpi,
979 pScrn->virtualX, pScrn->bitsPerPixel))
980 return (FALSE);
981
982 /* Fixup RGB ordering */
983 visual = pScreen->visuals + pScreen->numVisuals;
984 while (--visual >= pScreen->visuals) {
985 if ((visual->class | DynamicClass) == DirectColor) {
986 visual->offsetRed = pScrn->offset.red;
987 visual->offsetGreen = pScrn->offset.green;
988 visual->offsetBlue = pScrn->offset.blue;
989 visual->redMask = pScrn->mask.red;
990 visual->greenMask = pScrn->mask.green;
991 visual->blueMask = pScrn->mask.blue;
992 }
993 }
994
995 /* must be after RGB ordering fixed */
996 fbPictureInit(pScreen, 0, 0);
997
998 xf86SetBlackWhitePixels(pScreen);
999 miInitializeBackingStore(pScreen);
1000 xf86SetBackingStore(pScreen);
1001
1002 /* We need to keep track of whether we are currently switched to a virtual
1003 * terminal to know whether a mode set operation is currently safe to do.
1004 */
1005 pVBox->vtSwitch = FALSE;
1006 /* Initialise DGA. The cast is unfortunately correct - it gets cast back
1007 to (unsigned char *) later. */
1008 xf86DiDGAInit(pScreen, (unsigned long) pVBox->base);
1009
1010 /* Initialise randr 1.2 mode-setting functions and set first mode. */
1011 if (!xf86CrtcScreenInit(pScreen)) {
1012 return FALSE;
1013 }
1014
1015 if (!xf86SetDesiredModes(pScrn)) {
1016 return FALSE;
1017 }
1018
1019 /* set the viewport */
1020 VBOXAdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
1021
1022 /* software cursor */
1023 miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
1024
1025 /* colourmap code - apparently, we need this even in Truecolour */
1026 if (!miCreateDefColormap(pScreen))
1027 return (FALSE);
1028
1029 flags = CMAP_RELOAD_ON_MODE_SWITCH;
1030
1031 if(!xf86HandleColormaps(pScreen, 256,
1032 8 /* DAC is switchable to 8 bits per primary color */,
1033 VBOXLoadPalette, NULL, flags))
1034 return (FALSE);
1035
1036 /* Hook our observer function ito the chain which is called when
1037 * framebuffer access is enabled or disabled in the server, and
1038 * assume an initial state of enabled. */
1039 pVBox->accessEnabled = TRUE;
1040 pVBox->EnableDisableFBAccess = pScrn->EnableDisableFBAccess;
1041 pScrn->EnableDisableFBAccess = vboxEnableDisableFBAccess;
1042
1043 pVBox->CloseScreen = pScreen->CloseScreen;
1044 pScreen->CloseScreen = VBOXCloseScreen;
1045 pScreen->SaveScreen = xf86SaveScreen;
1046
1047 /* We probably do want to support power management - even if we just use
1048 a dummy function. */
1049 xf86DPMSInit(pScreen, xf86DPMSSet, 0);
1050
1051 /* Report any unused options (only for the first generation) */
1052 if (serverGeneration == 1)
1053 xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
1054
1055 if (vbox_device_available(pVBox) && vbox_open (pScrn, pScreen, pVBox)) {
1056 if (vbox_cursor_init(pScreen) != TRUE)
1057 xf86DrvMsg(scrnIndex, X_ERROR,
1058 "Unable to start the VirtualBox mouse pointer integration with the host system.\n");
1059 if (vboxEnableVbva(pScrn) == TRUE)
1060 xf86DrvMsg(scrnIndex, X_INFO,
1061 "The VBox video extensions are now enabled.\n");
1062 vboxEnableGraphicsCap(pVBox);
1063 /* Report the largest resolution that we support */
1064 }
1065
1066#ifdef VBOX_DRI
1067 if (pVBox->useDRI)
1068 pVBox->useDRI = VBOXDRIFinishScreenInit(pScreen);
1069#endif
1070 return (TRUE);
1071}
1072
1073static Bool
1074VBOXEnterVT(int scrnIndex, int flags)
1075{
1076 ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1077 VBOXPtr pVBox = VBOXGetRec(pScrn);
1078 bool rc;
1079
1080 TRACE_ENTRY();
1081 pVBox->vtSwitch = FALSE;
1082#ifdef VBOX_DRI
1083 if (pVBox->useDRI)
1084 DRIUnlock(screenInfo.screens[scrnIndex]);
1085#endif
1086 rc = xf86SetDesiredModes(pScrn);
1087 TRACE_LOG("returning %s\n", rc ? "TRUE" : "FALSE");
1088 return rc;
1089}
1090
1091static void
1092VBOXLeaveVT(int scrnIndex, int flags)
1093{
1094 ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1095 VBOXPtr pVBox = VBOXGetRec(pScrn);
1096
1097 TRACE_ENTRY();
1098 pVBox->vtSwitch = TRUE;
1099 VBOXSaveRestore(pScrn, MODE_RESTORE);
1100 if (vbox_device_available(pVBox))
1101 {
1102 if (pVBox->useVbva == TRUE)
1103 vboxDisableVbva(pScrn);
1104 vboxDisableGraphicsCap(pVBox);
1105 }
1106#ifdef VBOX_DRI
1107 if (pVBox->useDRI)
1108 DRILock(screenInfo.screens[scrnIndex], 0);
1109#endif
1110 TRACE_EXIT();
1111}
1112
1113static Bool
1114VBOXCloseScreen(int scrnIndex, ScreenPtr pScreen)
1115{
1116 ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1117 VBOXPtr pVBox = VBOXGetRec(pScrn);
1118
1119#ifdef VBOX_DRI
1120 if (pVBox->useDRI)
1121 VBOXDRICloseScreen(pScreen, pVBox);
1122 pVBox->useDRI = false;
1123#endif
1124
1125 if (vbox_device_available(pVBox))
1126 {
1127 if (TRUE == pVBox->useVbva)
1128 vboxDisableVbva(pScrn);
1129 vboxDisableGraphicsCap(pVBox);
1130 }
1131 if (pScrn->vtSema) {
1132 VBOXSaveRestore(xf86Screens[scrnIndex], MODE_RESTORE);
1133 if (pVBox->savedPal)
1134 VBESetGetPaletteData(pVBox->pVbe, TRUE, 0, 256,
1135 pVBox->savedPal, FALSE, TRUE);
1136 VBOXUnmapVidMem(pScrn);
1137 }
1138 pScrn->vtSema = FALSE;
1139
1140 /* Remove our observer functions from the X server call chains. */
1141 pScrn->EnableDisableFBAccess = pVBox->EnableDisableFBAccess;
1142 pScreen->CloseScreen = pVBox->CloseScreen;
1143 return pScreen->CloseScreen(scrnIndex, pScreen);
1144}
1145
1146/**
1147 * Quoted from "How to add an (S)VGA driver to XFree86"
1148 * (http://www.xfree86.org/3.3.6/VGADriver.html):
1149 *
1150 * The ValidMode() function is required. It is used to check for any
1151 * chipset-dependent reasons why a graphics mode might not be valid. It gets
1152 * called by higher levels of the code after the Probe() stage. In many cases
1153 * no special checking will be required and this function will simply return
1154 * TRUE always.
1155 *
1156 * Note: we check here that our generated video modes fulfil the X server's
1157 * criteria for the monitor, since this can otherwise cause problems in
1158 * randr 1.2.
1159 */
1160static ModeStatus
1161VBOXValidMode(int scrn, DisplayModePtr p, Bool flag, int pass)
1162{
1163 static int warned = 0;
1164 ScrnInfoPtr pScrn = xf86Screens[scrn];
1165 MonPtr mon = pScrn->monitor;
1166 ModeStatus ret = MODE_BAD;
1167 DisplayModePtr mode;
1168 float v;
1169
1170 TRACE_LOG("HDisplay=%d, VDisplay=%d, flag=%s, pass=%d\n",
1171 p->HDisplay, p->VDisplay, flag ? "TRUE" : "FALSE", pass);
1172 if (pass != MODECHECK_FINAL) {
1173 if (!warned) {
1174 xf86DrvMsg(scrn, X_WARNING, "VBOXValidMode called unexpectedly\n");
1175 warned = 1;
1176 }
1177 }
1178#if 0
1179 /*
1180 * First off, if this isn't a mode we handed to the server (ie,
1181 * M_T_BUILTIN), then we reject it out of hand.
1182 */
1183 if (!(p->type & M_T_BUILTIN))
1184 return MODE_NOMODE;
1185#endif
1186 /*
1187 * Finally, walk through the vsync rates 1Hz at a time looking for a mode
1188 * that will fit. This is assuredly a terrible way to do this, but
1189 * there's no obvious method for computing a mode of a given size that
1190 * will pass xf86CheckModeForMonitor.
1191 */
1192 for (v = mon->vrefresh[0].lo; v <= mon->vrefresh[0].hi; v++) {
1193 mode = xf86CVTMode(p->HDisplay, p->VDisplay, v, 0, 0);
1194 ret = xf86CheckModeForMonitor(mode, mon);
1195 xfree(mode);
1196 if (ret == MODE_OK)
1197 break;
1198 }
1199
1200 if (ret != MODE_OK)
1201 {
1202 xf86DrvMsg(scrn, X_WARNING, "Graphics mode %s rejected by the X server\n", p->name);
1203 }
1204 TRACE_LOG("returning %d\n", ret);
1205 return ret;
1206}
1207
1208static Bool
1209VBOXSwitchMode(int scrnIndex, DisplayModePtr pMode, int flags)
1210{
1211 ScrnInfoPtr pScrn;
1212 VBOXPtr pVBox;
1213 Bool rc;
1214
1215 TRACE_LOG("HDisplay=%d, VDisplay=%d\n", pMode->HDisplay, pMode->VDisplay);
1216 pScrn = xf86Screens[scrnIndex]; /* Why does X have three ways of refering to the screen? */
1217 pVBox = VBOXGetRec(pScrn);
1218 /* We want to disable access to the framebuffer before switching mode.
1219 * After doing the switch, we allow access if it was allowed before. */
1220 if (pVBox->accessEnabled)
1221 pVBox->EnableDisableFBAccess(scrnIndex, FALSE);
1222 rc = xf86SetSingleMode(pScrn, pMode, 0);
1223 if (pVBox->accessEnabled)
1224 pVBox->EnableDisableFBAccess(scrnIndex, TRUE);
1225 TRACE_LOG("returning %s\n", rc ? "TRUE" : "FALSE");
1226 return rc;
1227}
1228
1229/* Set a graphics mode. Poke the required values into registers, enable
1230 guest-host acceleration functions and tell the host we support advanced
1231 graphics functions. */
1232static Bool
1233VBOXSetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode)
1234{
1235 VBOXPtr pVBox;
1236 Bool rc = TRUE;
1237
1238 int bpp = pScrn->depth == 24 ? 32 : 16;
1239 TRACE_LOG("HDisplay=%d, VDisplay=%d, displayWidth=%d\n",
1240 pMode->HDisplay, pMode->VDisplay, pScrn->displayWidth);
1241 pVBox = VBOXGetRec(pScrn);
1242 /* Don't fiddle with the hardware if we are switched
1243 * to a virtual terminal. */
1244 if (!pVBox->vtSwitch)
1245 {
1246 if ( vbox_device_available(pVBox)
1247 && (TRUE == pVBox->useVbva)
1248 && (vboxDisableVbva(pScrn) != TRUE)
1249 ) /* This would be bad. */
1250 rc = FALSE;
1251 if (rc)
1252 {
1253 /* Disable linear framebuffer mode before making changes to the resolution. */
1254 outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
1255 outw(VBE_DISPI_IOPORT_DATA, VBE_DISPI_DISABLED);
1256 /* Unlike the resolution, the depth is fixed for a given screen
1257 for the lifetime of the X session. */
1258 outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_BPP);
1259 outw(VBE_DISPI_IOPORT_DATA, bpp);
1260 /* HDisplay and VDisplay are actually monitor information about
1261 the display part of the scanlines. */
1262 outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_XRES);
1263 outw(VBE_DISPI_IOPORT_DATA, pMode->HDisplay);
1264 outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_YRES);
1265 outw(VBE_DISPI_IOPORT_DATA, pMode->VDisplay);
1266 /* Set the virtual resolution. We are still using VESA to control
1267 the virtual offset. */
1268 outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_VIRT_WIDTH);
1269 outw(VBE_DISPI_IOPORT_DATA, pScrn->displayWidth);
1270 /* Enable linear framebuffer mode. */
1271 outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
1272 outw(VBE_DISPI_IOPORT_DATA,
1273 VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED);
1274 /* Enable acceleration and tell the host we support graphics */
1275 if (vbox_device_available(pVBox))
1276 {
1277 if ((TRUE == pVBox->useVbva) && (vboxEnableVbva(pScrn) != TRUE))
1278 /* Bad but not fatal */
1279 pVBox->useVbva = FALSE;
1280 vboxEnableGraphicsCap(pVBox);
1281 }
1282 }
1283 }
1284 TRACE_LOG("returning %s\n", rc ? "TRUE" : "FALSE");
1285 return rc;
1286}
1287
1288static void
1289VBOXAdjustFrame(int scrnIndex, int x, int y, int flags)
1290{
1291 VBOXPtr pVBox = VBOXGetRec(xf86Screens[scrnIndex]);
1292 ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1293
1294 TRACE_ENTRY();
1295 /* Don't fiddle with the hardware if we are switched
1296 * to a virtual terminal. */
1297 if (!pVBox->vtSwitch) {
1298 pVBox->viewportX = x;
1299 pVBox->viewportY = y;
1300 /* If VBVA is enabled the graphics card will not notice the change. */
1301 if (pVBox->useVbva == TRUE)
1302 vboxDisableVbva(pScrn);
1303 VBESetDisplayStart(pVBox->pVbe, x, y, TRUE);
1304 if (pVBox->useVbva == TRUE)
1305 vboxEnableVbva(pScrn);
1306 }
1307 TRACE_EXIT();
1308}
1309
1310static void
1311VBOXFreeScreen(int scrnIndex, int flags)
1312{
1313 VBOXFreeRec(xf86Screens[scrnIndex]);
1314}
1315
1316static Bool
1317VBOXMapVidMem(ScrnInfoPtr pScrn)
1318{
1319 VBOXPtr pVBox = VBOXGetRec(pScrn);
1320 Bool rc = TRUE;
1321
1322 TRACE_ENTRY();
1323 if (NULL == pVBox->base)
1324 {
1325 pScrn->memPhysBase = pVBox->mapPhys;
1326 pScrn->fbOffset = pVBox->mapOff;
1327
1328#ifdef PCIACCESS
1329 (void) pci_device_map_range(pVBox->pciInfo,
1330 pScrn->memPhysBase,
1331 pVBox->mapSize,
1332 PCI_DEV_MAP_FLAG_WRITABLE,
1333 & pVBox->base);
1334
1335 if (pVBox->base) {
1336 pScrn->memPhysBase = pVBox->mapPhys;
1337 pVBox->VGAbase = xf86MapDomainMemory(pScrn->scrnIndex, 0,
1338 pVBox->pciInfo,
1339 0xa0000, 0x10000);
1340 }
1341#else
1342 pVBox->base = xf86MapPciMem(pScrn->scrnIndex,
1343 VIDMEM_FRAMEBUFFER,
1344 pVBox->pciTag, pVBox->mapPhys,
1345 (unsigned) pVBox->mapSize);
1346
1347 if (pVBox->base) {
1348 pScrn->memPhysBase = pVBox->mapPhys;
1349 pVBox->VGAbase = xf86MapDomainMemory(pScrn->scrnIndex, 0,
1350 pVBox->pciTag,
1351 0xa0000, 0x10000);
1352 }
1353#endif
1354 /* We need this for saving/restoring textmode */
1355 pVBox->ioBase = pScrn->domainIOBase;
1356
1357 rc = pVBox->base != NULL;
1358 }
1359 TRACE_LOG("returning %s\n", rc ? "TRUE" : "FALSE");
1360 return rc;
1361}
1362
1363static void
1364VBOXUnmapVidMem(ScrnInfoPtr pScrn)
1365{
1366 VBOXPtr pVBox = VBOXGetRec(pScrn);
1367
1368 TRACE_ENTRY();
1369 if (pVBox->base == NULL)
1370 return;
1371
1372#ifdef PCIACCESS
1373 (void) pci_device_unmap_range(pVBox->pciInfo,
1374 pVBox->base,
1375 pVBox->mapSize);
1376 xf86UnMapVidMem(pScrn->scrnIndex, pVBox->VGAbase, 0x10000);
1377#else
1378 xf86UnMapVidMem(pScrn->scrnIndex, pVBox->base,
1379 (unsigned) pVBox->mapSize);
1380 xf86UnMapVidMem(pScrn->scrnIndex, pVBox->VGAbase, 0x10000);
1381#endif
1382 pVBox->base = NULL;
1383 TRACE_EXIT();
1384}
1385
1386static void
1387VBOXLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices,
1388 LOCO *colors, VisualPtr pVisual)
1389{
1390 VBOXPtr pVBox = VBOXGetRec(pScrn);
1391 int i, idx;
1392#define VBOXDACDelay() \
1393 do { \
1394 (void)inb(pVBox->ioBase + VGA_IOBASE_COLOR + VGA_IN_STAT_1_OFFSET); \
1395 (void)inb(pVBox->ioBase + VGA_IOBASE_COLOR + VGA_IN_STAT_1_OFFSET); \
1396 } while (0)
1397
1398 TRACE_ENTRY();
1399 for (i = 0; i < numColors; i++) {
1400 idx = indices[i];
1401 outb(pVBox->ioBase + VGA_DAC_WRITE_ADDR, idx);
1402 VBOXDACDelay();
1403 outb(pVBox->ioBase + VGA_DAC_DATA, colors[idx].red);
1404 VBOXDACDelay();
1405 outb(pVBox->ioBase + VGA_DAC_DATA, colors[idx].green);
1406 VBOXDACDelay();
1407 outb(pVBox->ioBase + VGA_DAC_DATA, colors[idx].blue);
1408 VBOXDACDelay();
1409 }
1410 TRACE_EXIT();
1411}
1412
1413/*
1414 * Just adapted from the std* functions in vgaHW.c
1415 */
1416static void
1417WriteAttr(VBOXPtr pVBox, int index, int value)
1418{
1419 (void) inb(pVBox->ioBase + VGA_IOBASE_COLOR + VGA_IN_STAT_1_OFFSET);
1420
1421 index |= 0x20;
1422 outb(pVBox->ioBase + VGA_ATTR_INDEX, index);
1423 outb(pVBox->ioBase + VGA_ATTR_DATA_W, value);
1424}
1425
1426static int
1427ReadAttr(VBOXPtr pVBox, int index)
1428{
1429 (void) inb(pVBox->ioBase + VGA_IOBASE_COLOR + VGA_IN_STAT_1_OFFSET);
1430
1431 index |= 0x20;
1432 outb(pVBox->ioBase + VGA_ATTR_INDEX, index);
1433 return (inb(pVBox->ioBase + VGA_ATTR_DATA_R));
1434}
1435
1436#define WriteMiscOut(value) outb(pVBox->ioBase + VGA_MISC_OUT_W, value)
1437#define ReadMiscOut() inb(pVBox->ioBase + VGA_MISC_OUT_R)
1438#define WriteSeq(index, value) \
1439 outb(pVBox->ioBase + VGA_SEQ_INDEX, (index));\
1440 outb(pVBox->ioBase + VGA_SEQ_DATA, value)
1441
1442static int
1443ReadSeq(VBOXPtr pVBox, int index)
1444{
1445 outb(pVBox->ioBase + VGA_SEQ_INDEX, index);
1446
1447 return (inb(pVBox->ioBase + VGA_SEQ_DATA));
1448}
1449
1450#define WriteGr(index, value) \
1451 outb(pVBox->ioBase + VGA_GRAPH_INDEX, index); \
1452 outb(pVBox->ioBase + VGA_GRAPH_DATA, value)
1453
1454static int
1455ReadGr(VBOXPtr pVBox, int index)
1456{
1457 outb(pVBox->ioBase + VGA_GRAPH_INDEX, index);
1458
1459 return (inb(pVBox->ioBase + VGA_GRAPH_DATA));
1460}
1461
1462#define WriteCrtc(index, value) \
1463 outb(pVBox->ioBase + (VGA_IOBASE_COLOR + VGA_CRTC_INDEX_OFFSET), index); \
1464 outb(pVBox->ioBase + (VGA_IOBASE_COLOR + VGA_CRTC_DATA_OFFSET), value)
1465
1466static void
1467SeqReset(VBOXPtr pVBox, Bool start)
1468{
1469 if (start) {
1470 WriteSeq(0x00, 0x01); /* Synchronous Reset */
1471 }
1472 else {
1473 WriteSeq(0x00, 0x03); /* End Reset */
1474 }
1475}
1476
1477static void
1478SaveFonts(ScrnInfoPtr pScrn)
1479{
1480 VBOXPtr pVBox = VBOXGetRec(pScrn);
1481 unsigned char miscOut, attr10, gr4, gr5, gr6, seq2, seq4, scrn;
1482 Bool cont = TRUE;
1483
1484 TRACE_ENTRY();
1485 if (pVBox->fonts != NULL)
1486 cont = FALSE;
1487
1488 if (cont)
1489 {
1490 /* If in graphics mode, don't save anything */
1491 attr10 = ReadAttr(pVBox, 0x10);
1492 if (attr10 & 0x01)
1493 cont = FALSE;
1494 }
1495
1496 if (cont)
1497 {
1498 pVBox->fonts = xalloc(16384);
1499
1500 /* save the registers that are needed here */
1501 miscOut = ReadMiscOut();
1502 gr4 = ReadGr(pVBox, 0x04);
1503 gr5 = ReadGr(pVBox, 0x05);
1504 gr6 = ReadGr(pVBox, 0x06);
1505 seq2 = ReadSeq(pVBox, 0x02);
1506 seq4 = ReadSeq(pVBox, 0x04);
1507
1508 /* Force into colour mode */
1509 WriteMiscOut(miscOut | 0x01);
1510
1511 scrn = ReadSeq(pVBox, 0x01) | 0x20;
1512 SeqReset(pVBox, TRUE);
1513 WriteSeq(0x01, scrn);
1514 SeqReset(pVBox, FALSE);
1515
1516 WriteAttr(pVBox, 0x10, 0x01); /* graphics mode */
1517
1518 /*font1 */
1519 WriteSeq(0x02, 0x04); /* write to plane 2 */
1520 WriteSeq(0x04, 0x06); /* enable plane graphics */
1521 WriteGr(0x04, 0x02); /* read plane 2 */
1522 WriteGr(0x05, 0x00); /* write mode 0, read mode 0 */
1523 WriteGr(0x06, 0x05); /* set graphics */
1524 slowbcopy_frombus(pVBox->VGAbase, pVBox->fonts, 8192);
1525
1526 /* font2 */
1527 WriteSeq(0x02, 0x08); /* write to plane 3 */
1528 WriteSeq(0x04, 0x06); /* enable plane graphics */
1529 WriteGr(0x04, 0x03); /* read plane 3 */
1530 WriteGr(0x05, 0x00); /* write mode 0, read mode 0 */
1531 WriteGr(0x06, 0x05); /* set graphics */
1532 slowbcopy_frombus(pVBox->VGAbase, pVBox->fonts + 8192, 8192);
1533
1534 scrn = ReadSeq(pVBox, 0x01) & ~0x20;
1535 SeqReset(pVBox, TRUE);
1536 WriteSeq(0x01, scrn);
1537 SeqReset(pVBox, FALSE);
1538
1539 /* Restore clobbered registers */
1540 WriteAttr(pVBox, 0x10, attr10);
1541 WriteSeq(0x02, seq2);
1542 WriteSeq(0x04, seq4);
1543 WriteGr(0x04, gr4);
1544 WriteGr(0x05, gr5);
1545 WriteGr(0x06, gr6);
1546 WriteMiscOut(miscOut);
1547 }
1548 TRACE_EXIT();
1549}
1550
1551static void
1552RestoreFonts(ScrnInfoPtr pScrn)
1553{
1554 VBOXPtr pVBox = VBOXGetRec(pScrn);
1555 unsigned char miscOut, attr10, gr1, gr3, gr4, gr5, gr6, gr8, seq2, seq4, scrn;
1556
1557 TRACE_ENTRY();
1558 if (pVBox->fonts != NULL)
1559 {
1560 /* save the registers that are needed here */
1561 miscOut = ReadMiscOut();
1562 attr10 = ReadAttr(pVBox, 0x10);
1563 gr1 = ReadGr(pVBox, 0x01);
1564 gr3 = ReadGr(pVBox, 0x03);
1565 gr4 = ReadGr(pVBox, 0x04);
1566 gr5 = ReadGr(pVBox, 0x05);
1567 gr6 = ReadGr(pVBox, 0x06);
1568 gr8 = ReadGr(pVBox, 0x08);
1569 seq2 = ReadSeq(pVBox, 0x02);
1570 seq4 = ReadSeq(pVBox, 0x04);
1571
1572 /* Force into colour mode */
1573 WriteMiscOut(miscOut | 0x01);
1574
1575 scrn = ReadSeq(pVBox, 0x01) & ~0x20;
1576 SeqReset(pVBox, TRUE);
1577 WriteSeq(0x01, scrn);
1578 SeqReset(pVBox, FALSE);
1579
1580 WriteAttr(pVBox, 0x10, 0x01); /* graphics mode */
1581 if (pScrn->depth == 4) {
1582 /* GJA */
1583 WriteGr(0x03, 0x00); /* don't rotate, write unmodified */
1584 WriteGr(0x08, 0xFF); /* write all bits in a byte */
1585 WriteGr(0x01, 0x00); /* all planes come from CPU */
1586 }
1587
1588 WriteSeq(0x02, 0x04); /* write to plane 2 */
1589 WriteSeq(0x04, 0x06); /* enable plane graphics */
1590 WriteGr(0x04, 0x02); /* read plane 2 */
1591 WriteGr(0x05, 0x00); /* write mode 0, read mode 0 */
1592 WriteGr(0x06, 0x05); /* set graphics */
1593 slowbcopy_tobus(pVBox->fonts, pVBox->VGAbase, 8192);
1594
1595 WriteSeq(0x02, 0x08); /* write to plane 3 */
1596 WriteSeq(0x04, 0x06); /* enable plane graphics */
1597 WriteGr(0x04, 0x03); /* read plane 3 */
1598 WriteGr(0x05, 0x00); /* write mode 0, read mode 0 */
1599 WriteGr(0x06, 0x05); /* set graphics */
1600 slowbcopy_tobus(pVBox->fonts + 8192, pVBox->VGAbase, 8192);
1601
1602 scrn = ReadSeq(pVBox, 0x01) & ~0x20;
1603 SeqReset(pVBox, TRUE);
1604 WriteSeq(0x01, scrn);
1605 SeqReset(pVBox, FALSE);
1606
1607 /* restore the registers that were changed */
1608 WriteMiscOut(miscOut);
1609 WriteAttr(pVBox, 0x10, attr10);
1610 WriteGr(0x01, gr1);
1611 WriteGr(0x03, gr3);
1612 WriteGr(0x04, gr4);
1613 WriteGr(0x05, gr5);
1614 WriteGr(0x06, gr6);
1615 WriteGr(0x08, gr8);
1616 WriteSeq(0x02, seq2);
1617 WriteSeq(0x04, seq4);
1618 }
1619 TRACE_EXIT();
1620}
1621
1622Bool
1623VBOXSaveRestore(ScrnInfoPtr pScrn, vbeSaveRestoreFunction function)
1624{
1625 VBOXPtr pVBox;
1626 Bool rc = TRUE;
1627
1628 TRACE_ENTRY();
1629 if (MODE_QUERY < 0 || function > MODE_RESTORE)
1630 rc = FALSE;
1631
1632 if (rc)
1633 {
1634 pVBox = VBOXGetRec(pScrn);
1635
1636 /* Query amount of memory to save state */
1637 if (function == MODE_QUERY ||
1638 (function == MODE_SAVE && pVBox->state == NULL))
1639 {
1640
1641 /* Make sure we save at least this information in case of failure */
1642 (void)VBEGetVBEMode(pVBox->pVbe, &pVBox->stateMode);
1643 SaveFonts(pScrn);
1644
1645 if (!VBESaveRestore(pVBox->pVbe,function,(pointer)&pVBox->state,
1646 &pVBox->stateSize,&pVBox->statePage)
1647 )
1648 rc = FALSE;
1649 }
1650 }
1651 if (rc)
1652 {
1653 /* Save/Restore Super VGA state */
1654 if (function != MODE_QUERY) {
1655
1656 if (function == MODE_RESTORE)
1657 memcpy(pVBox->state, pVBox->pstate,
1658 (unsigned) pVBox->stateSize);
1659
1660 if ( (rc = VBESaveRestore(pVBox->pVbe,function,
1661 (pointer)&pVBox->state,
1662 &pVBox->stateSize,&pVBox->statePage)
1663 )
1664 && (function == MODE_SAVE)
1665 )
1666 {
1667 /* don't rely on the memory not being touched */
1668 if (pVBox->pstate == NULL)
1669 pVBox->pstate = xalloc(pVBox->stateSize);
1670 memcpy(pVBox->pstate, pVBox->state,
1671 (unsigned) pVBox->stateSize);
1672 }
1673
1674 if (function == MODE_RESTORE)
1675 {
1676 VBESetVBEMode(pVBox->pVbe, pVBox->stateMode, NULL);
1677 RestoreFonts(pScrn);
1678 }
1679 }
1680 }
1681 TRACE_LOG("returning %s\n", rc ? "TRUE" : "FALSE");
1682 return rc;
1683}
Note: See TracBrowser for help on using the repository browser.

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