vboxutils_68.c revision b72771e8c6ba3b3d9ebdd7977730325131ae0f98
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/** @file
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync *
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Linux Additions X11 graphics driver helper module
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/*
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Copyright (C) 2006-2007 Sun Microsystems, Inc.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync *
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * available from http://www.virtualbox.org. This file is free software;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * you can redistribute it and/or modify it under the terms of the GNU
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * General Public License (GPL) as published by the Free Software
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync *
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * additional information or have any questions.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#include <VBox/VBoxGuest.h>
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#include <xf86Pci.h>
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#include <Pci.h>
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#include "xf86.h"
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#define NEED_XF86_TYPES
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#include "xf86_ansic.h"
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#include "compiler.h"
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#include "cursorstr.h"
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#include "vboxvideo_68.h"
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#define VBOX_MAX_CURSOR_WIDTH 64
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#define VBOX_MAX_CURSOR_HEIGHT 64
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#if 0
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#define DEBUG_X
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#endif
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#ifdef DEBUG_X
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#define TRACE_ENTRY() do \
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync { \
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync ErrorF ("%s\n", __FUNCTION__); \
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync } while(0)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#define TRACE_LINE() do \
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync { \
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync ErrorF ("%s: line %d\n", __FUNCTION__, __LINE__); \
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync } while(0)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#define PUT_PIXEL(c) ErrorF ("%c", c)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#define dolog(...) ErrorF (__VA_ARGS__)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#else
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#define PUT_PIXEL(c) do { } while(0)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#define TRACE_ENTRY() do { } while(0)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#define TRACE_LINE() do { } while(0)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#define dolog(...) do { } while(0)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#endif
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/** Macro to printf an error message and return from a function */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#define RETERROR(scrnIndex, RetVal, ...) \
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncdo \
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync{ \
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync xf86DrvMsg(scrnIndex, X_ERROR, __VA_ARGS__); \
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return RetVal; \
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync} \
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncwhile (0)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#ifdef DEBUG_X
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncstatic void vbox_show_shape (unsigned short w, unsigned short h,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync CARD32 bg, unsigned char *image)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync{
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync size_t x, y;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync unsigned short pitch;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync CARD32 *color;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync unsigned char *mask;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync size_t size_mask;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync image += offsetof (VMMDevReqMousePointer, pointerData);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync mask = image;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pitch = (w + 7) / 8;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync size_mask = (pitch * h + 3) & ~3;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync color = (CARD32 *) (image + size_mask);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync TRACE_ENTRY ();
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync for (y = 0; y < h; ++y, mask += pitch, color += w)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync for (x = 0; x < w; ++x)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (mask[x / 8] & (1 << (7 - (x % 8))))
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync ErrorF (" ");
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync else
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync CARD32 c = color[x];
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (c == bg)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync ErrorF ("Y");
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync else
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync ErrorF ("X");
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync ErrorF ("\n");
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync}
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#endif
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncstatic Bool vbox_vmmcall (ScrnInfoPtr pScrn, VBOXPtr pVBox,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync VMMDevRequestHeader *hdrp)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync{
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync int err;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync TRACE_ENTRY ();
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#ifdef RT_OS_LINUX
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync err = ioctl (pVBox->vbox_fd, VBOXGUEST_IOCTL_VMMREQUEST(hdrp->size), hdrp);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#else
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/**
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @todo this should work fine on other platforms too, but it needs to be
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * checked for each one.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync# error port me!
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#endif
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (err < 0)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync RETERROR(pScrn->scrnIndex, FALSE,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync "Ioctl call failed during a request to the virtual machine: %s\n",
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync strerror (errno));
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync else
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (RT_FAILURE (hdrp->rc))
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync RETERROR(pScrn->scrnIndex, FALSE,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync "A request to the virtual machine returned %d\n",
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync hdrp->rc);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /* success */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return TRUE;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync}
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncstatic Bool
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncvbox_host_uses_hwcursor(ScrnInfoPtr pScrn)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync{
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync Bool rc = FALSE;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync VBOXPtr pVBox = pScrn->driverPrivate;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync VMMDevReqMouseStatus req;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync int vrc = vmmdevInitRequest ((VMMDevRequestHeader*)&req, VMMDevReq_GetMouseStatus);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (RT_FAILURE (vrc))
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync "Unable to determine whether the virtual machine supports mouse pointer integration - request initialization failed with return code %d\n", rc);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#ifdef RT_OS_LINUX
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if ( RT_SUCCESS(vrc)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync && (ioctl(pVBox->vbox_fd, VBOXGUEST_IOCTL_VMMREQUEST(sizeof(req)), (void*)&req) < 0))
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#else
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync# error port me!
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#endif
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync vrc = VERR_FILE_IO_ERROR;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync "Unable to determine whether the virtual machine supports mouse pointer integration - request system call failed: %s.\n",
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync strerror(errno));
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if ( RT_SUCCESS(rc)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync && !(req.mouseFeatures & VBOXGUEST_MOUSE_HOST_CANNOT_HWPOINTER)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync && (req.mouseFeatures & VBOXGUEST_MOUSE_GUEST_CAN_ABSOLUTE))
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync rc = TRUE;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return rc;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync}
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncvoid
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncvbox_close(ScrnInfoPtr pScrn, VBOXPtr pVBox)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync{
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync TRACE_ENTRY ();
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync xfree (pVBox->reqp);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pVBox->reqp = NULL;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#ifdef RT_OS_SOLARIS
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync VbglR3Term();
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#else
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (close (pVBox->vbox_fd))
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync "Unable to close the virtual machine device (file %d): %s\n",
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pVBox->vbox_fd, strerror (errno));
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pVBox->vbox_fd = -1;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#endif
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync}
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/**
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Macro to disable VBVA extensions and return, for use when an
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * unexplained error occurs.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#define DISABLE_VBVA_AND_RETURN(pScrn, ...) \
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncdo \
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync{ \
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync xf86DrvMsg(pScrn->scrnIndex, X_ERROR, __VA_ARGS__); \
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync vboxDisableVbva(pScrn); \
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pVBox->useVbva = FALSE; \
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return; \
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync} \
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncwhile (0)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/**
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Callback function called by the X server to tell us about dirty
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * rectangles in the video buffer.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync *
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param pScreen pointer to the information structure for the current
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * screen
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param iRects Number of dirty rectangles to update
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param aRects Array of structures containing the coordinates of the
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * rectangles
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncstatic void
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncvboxHandleDirtyRect(ScrnInfoPtr pScrn, int iRects, BoxPtr aRects)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync{
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync VBVACMDHDR cmdHdr;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync VBOXPtr pVBox;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync VBVARECORD *pRecord;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync VBVAMEMORY *pMem;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync CARD32 indexRecordNext;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync CARD32 off32Data;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync CARD32 off32Free;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync INT32 i32Diff;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync CARD32 cbHwBufferAvail;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync int scrnIndex;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync int i;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pVBox = pScrn->driverPrivate;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (pVBox->useVbva == FALSE)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pMem = pVBox->pVbvaMemory;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /* Just return quietly if VBVA is not currently active. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if ((pMem->fu32ModeFlags & VBVA_F_MODE_ENABLED) == 0)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync scrnIndex = pScrn->scrnIndex;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync for (i = 0; i < iRects; i++)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync cmdHdr.x = (int16_t)aRects[i].x1 - pVBox->viewportX;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync cmdHdr.y = (int16_t)aRects[i].y1 - pVBox->viewportY;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync cmdHdr.w = (uint16_t)(aRects[i].x2 - aRects[i].x1);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync cmdHdr.h = (uint16_t)(aRects[i].y2 - aRects[i].y1);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /* Get the active record and move the pointer along */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync indexRecordNext = (pMem->indexRecordFree + 1)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync % VBVA_MAX_RECORDS;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (indexRecordNext == pMem->indexRecordFirst)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /* All slots in the records queue are used. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (vbox_vmmcall(pScrn, pVBox,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync (VMMDevRequestHeader *) pVBox->reqf) != TRUE)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync DISABLE_VBVA_AND_RETURN(pScrn,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync "Unable to clear the VirtualBox graphics acceleration queue "
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync "- the request to the virtual machine failed. Switching to "
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync "unaccelerated mode.\n");
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (indexRecordNext == pMem->indexRecordFirst)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync DISABLE_VBVA_AND_RETURN(pScrn,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync "Failed to clear the VirtualBox graphics acceleration queue. "
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync "Switching to unaccelerated mode.\n");
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pRecord = &pMem->aRecords[pMem->indexRecordFree];
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /* Mark the record as being updated. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pRecord->cbRecord = VBVA_F_RECORD_PARTIAL;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pMem->indexRecordFree = indexRecordNext;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /* Compute how many bytes we have in the ring buffer. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync off32Free = pMem->off32Free;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync off32Data = pMem->off32Data;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /* Free is writing position. Data is reading position.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Data == Free means buffer is free.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * There must be always gap between free and data when data
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * are in the buffer.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Guest only changes free, host only changes data.
e5df77e70b59a10327e0d2bdd21af0a5c8a551e2vboxsync */
e5df77e70b59a10327e0d2bdd21af0a5c8a551e2vboxsync i32Diff = off32Data - off32Free;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync cbHwBufferAvail = i32Diff > 0? i32Diff: VBVA_RING_BUFFER_SIZE
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync + i32Diff;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (cbHwBufferAvail <= VBVA_RING_BUFFER_THRESHOLD)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (vbox_vmmcall(pScrn, pVBox,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync (VMMDevRequestHeader *) pVBox->reqf) != TRUE)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync DISABLE_VBVA_AND_RETURN(pScrn,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync "Unable to clear the VirtualBox graphics acceleration queue "
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync "- the request to the virtual machine failed. Switching to "
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync "unaccelerated mode.\n");
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /* Calculate the free space again. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync off32Free = pMem->off32Free;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync off32Data = pMem->off32Data;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync i32Diff = off32Data - off32Free;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync cbHwBufferAvail = i32Diff > 0? i32Diff:
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync VBVA_RING_BUFFER_SIZE + i32Diff;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (cbHwBufferAvail <= VBVA_RING_BUFFER_THRESHOLD)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync DISABLE_VBVA_AND_RETURN(pScrn,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync "No space left in the VirtualBox graphics acceleration command buffer, "
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync "despite clearing the queue. Switching to unaccelerated mode.\n");
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /* Now copy the data into the buffer */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (off32Free + sizeof(cmdHdr) < VBVA_RING_BUFFER_SIZE)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync memcpy(&pMem->au8RingBuffer[off32Free], &cmdHdr,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync sizeof(cmdHdr));
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pMem->off32Free = pMem->off32Free + sizeof(cmdHdr);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync else
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync CARD32 u32First = VBVA_RING_BUFFER_SIZE - off32Free;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /* The following is impressively ugly! */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync CARD8 *pu8Second = (CARD8 *)&cmdHdr + u32First;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync CARD32 u32Second = sizeof(cmdHdr) - u32First;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync memcpy(&pMem->au8RingBuffer[off32Free], &cmdHdr, u32First);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (u32Second)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync memcpy(&pMem->au8RingBuffer[0], (void *)pu8Second, u32Second);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pMem->off32Free = u32Second;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pRecord->cbRecord += sizeof(cmdHdr);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /* Mark the record completed. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pRecord->cbRecord &= ~VBVA_F_RECORD_PARTIAL;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync}
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/**
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Initialise VirtualBox's accelerated video extensions.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Note that we assume that the PCI memory is 32bit mapped,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * as X doesn't seem to support mapping 64bit memory.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync *
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @returns True on success, false on failure
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncstatic Bool
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncvboxInitVbva(int scrnIndex, ScreenPtr pScreen, VBOXPtr pVBox)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync{
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync PCITAG pciTag;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync ADDRESS pciAddress;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync int rc;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /* Locate the device. It should already have been enabled by
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync the kernel driver. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pciTag = pciFindFirst((unsigned) VMMDEV_DEVICEID << 16 | VMMDEV_VENDORID,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync (CARD32) ~0);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (pciTag == PCI_NOT_FOUND)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync xf86DrvMsg(scrnIndex, X_ERROR,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync "Could not find the VirtualBox base device on the PCI bus.\n");
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return FALSE;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /* Read the address and size of the second I/O region. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pciAddress = pciReadLong(pciTag, PCI_MAP_REG_START + 4);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (pciAddress == 0 || pciAddress == (CARD32) ~0)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync RETERROR(scrnIndex, FALSE,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync "The VirtualBox base device contains an invalid memory address.\n");
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (PCI_MAP_IS64BITMEM(pciAddress))
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync RETERROR(scrnIndex, FALSE,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync "The VirtualBox base device has a 64bit mapping address. "
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync "This is currently not supported.\n");
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /* Map it. We hardcode the size as X does not export the
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync function needed to determine it. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pVBox->pVMMDevMemory = xf86MapPciMem(scrnIndex, 0, pciTag, pciAddress,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync sizeof(VMMDevMemory));
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (pVBox->pVMMDevMemory == NULL)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync xf86DrvMsg(scrnIndex, X_ERROR,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync "Failed to map VirtualBox video extension memory.\n");
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return FALSE;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pVBox->pVbvaMemory = &pVBox->pVMMDevMemory->vbvaMemory;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /* Initialise requests */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pVBox->reqf = xcalloc(1, vmmdevGetRequestSize(VMMDevReq_VideoAccelFlush));
if (!pVBox->reqf)
{
xf86DrvMsg(scrnIndex, X_ERROR,
"Could not allocate memory for VBVA flush request.\n");
return FALSE;
}
rc = vmmdevInitRequest ((VMMDevRequestHeader *) pVBox->reqf,
VMMDevReq_VideoAccelFlush);
if (RT_FAILURE (rc))
{
xf86DrvMsg(scrnIndex, X_ERROR,
"Could not initialise VBVA flush request: return value %d\n", rc);
xfree(pVBox->reqf);
return FALSE;
}
pVBox->reqe = xcalloc(1, vmmdevGetRequestSize(VMMDevReq_VideoAccelEnable));
if (!pVBox->reqe)
{
xf86DrvMsg(scrnIndex, X_ERROR,
"Could not allocate memory for VBVA enable request.\n");
xfree(pVBox->reqf);
return FALSE;
}
rc = vmmdevInitRequest ((VMMDevRequestHeader *) pVBox->reqe,
VMMDevReq_VideoAccelEnable);
if (RT_FAILURE (rc))
{
xf86DrvMsg(scrnIndex, X_ERROR,
"Could not initialise VBVA enable request: return value = %d\n",
rc);
xfree(pVBox->reqf);
xfree(pVBox->reqe);
return FALSE;
}
/* Set up the dirty rectangle handler. Since this seems to be a
delicate operation, and removing it doubly so, this will
remain in place whether it is needed or not, and will simply
return if VBVA is not active. I assume that it will be active
most of the time. */
if (ShadowFBInit2(pScreen, NULL, vboxHandleDirtyRect) != TRUE)
{
xf86DrvMsg(scrnIndex, X_ERROR,
"Unable to install dirty rectangle handler for VirtualBox graphics acceleration.\n");
xfree(pVBox->reqf);
xfree(pVBox->reqe);
return FALSE;
}
return TRUE;
}
Bool
vbox_open (ScrnInfoPtr pScrn, ScreenPtr pScreen, VBOXPtr pVBox)
{
int fd, vrc;
void *p = NULL;
size_t size;
int scrnIndex = pScrn->scrnIndex;
Bool rc = TRUE;
TRACE_ENTRY ();
pVBox->useVbva = FALSE;
#ifdef RT_OS_SOLARIS
NOREF(fd);
if (pVBox->reqp)
{
/* still open, just re-enable VBVA after CloseScreen was called */
pVBox->useVbva = vboxInitVbva(scrnIndex, pScreen, pVBox);
return TRUE;
}
vrc = VbglR3Init();
if (RT_FAILURE(vrc))
{
xf86DrvMsg(scrnIndex, X_ERROR, "VbglR3Init failed vrc=%d.\n", vrc);
rc = FALSE;
}
#else
if (pVBox->vbox_fd != -1 && pVBox->reqp)
{
/* still open, just re-enable VBVA after CloseScreen was called */
pVBox->useVbva = vboxInitVbva(scrnIndex, pScreen, pVBox);
return TRUE;
}
fd = open (VBOXGUEST_DEVICE_NAME, O_RDWR, 0);
if (fd < 0)
{
xf86DrvMsg(scrnIndex, X_ERROR,
"Error opening kernel module: %s\n",
strerror (errno));
rc = FALSE;
}
#endif
if (rc) {
size = vmmdevGetRequestSize (VMMDevReq_SetPointerShape);
p = xcalloc (1, size);
if (NULL == p) {
xf86DrvMsg(scrnIndex, X_ERROR,
"Could not allocate %lu bytes for VMM request\n",
(unsigned long) size);
rc = FALSE;
}
}
if (rc) {
vrc = vmmdevInitRequest (p, VMMDevReq_SetPointerShape);
if (RT_FAILURE (vrc))
{
xf86DrvMsg(scrnIndex, X_ERROR,
"Could not init VMM request: vrc = %d\n", vrc);
rc = FALSE;
}
}
if (rc) {
#ifndef RT_OS_SOLARIS
pVBox->vbox_fd = fd;
#endif
pVBox->reqp = p;
pVBox->pCurs = NULL;
pVBox->pointerHeaderSize = size;
pVBox->useVbva = vboxInitVbva(scrnIndex, pScreen, pVBox);
} else {
if (NULL != p) {
xfree (p);
}
#ifdef RT_OS_SOLARIS
VbglR3Term();
#else
if (close (fd)) {
xf86DrvMsg(scrnIndex, X_ERROR,
"Error closing kernel module file descriptor(%d): %s\n",
fd, strerror (errno));
}
#endif
}
return rc;
}
static void vbox_vmm_hide_cursor (ScrnInfoPtr pScrn, VBOXPtr pVBox)
{
pVBox->reqp->fFlags = 0;
if (vbox_vmmcall (pScrn, pVBox, &pVBox->reqp->header) != TRUE)
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Could not hide the virtual mouse pointer.\n");
}
static void vbox_vmm_show_cursor (ScrnInfoPtr pScrn, VBOXPtr pVBox)
{
pVBox->reqp->fFlags = VBOX_MOUSE_POINTER_VISIBLE;
if (vbox_vmmcall (pScrn, pVBox, &pVBox->reqp->header) != TRUE)
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Could not unhide the virtual mouse pointer.\n");
}
static void vbox_vmm_load_cursor_image (ScrnInfoPtr pScrn, VBOXPtr pVBox,
unsigned char *image)
{
VMMDevReqMousePointer *reqp;
reqp = (VMMDevReqMousePointer *) image;
dolog ("w=%d h=%d size=%d\n",
reqp->width,
reqp->height,
reqp->header.size);
#ifdef DEBUG_X
vbox_show_shape (reqp->width, reqp->height, 0, image);
#endif
if (vbox_vmmcall (pScrn, pVBox, &reqp->header) != TRUE)
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Unable to set the virtual mouse pointer image.\n");
}
static void vbox_set_cursor_colors (ScrnInfoPtr pScrn, int bg, int fg)
{
TRACE_ENTRY ();
(void) pScrn;
(void) bg;
(void) fg;
/* ErrorF ("vbox_set_cursor_colors NOT IMPLEMENTED\n"); */
}
static void
vbox_set_cursor_position (ScrnInfoPtr pScrn, int x, int y)
{
(void) pScrn; (void) x; (void) y;
}
static void vbox_hide_cursor (ScrnInfoPtr pScrn)
{
VBOXPtr pVBox = pScrn->driverPrivate;
TRACE_ENTRY ();
vbox_vmm_hide_cursor (pScrn, pVBox);
}
static void vbox_show_cursor (ScrnInfoPtr pScrn)
{
VBOXPtr pVBox = pScrn->driverPrivate;
TRACE_ENTRY ();
vbox_vmm_show_cursor (pScrn, pVBox);
}
static void vbox_load_cursor_image (ScrnInfoPtr pScrn, unsigned char *image)
{
VBOXPtr pVBox = pScrn->driverPrivate;
TRACE_ENTRY ();
vbox_vmm_load_cursor_image (pScrn, pVBox, image);
}
static Bool
vbox_use_hw_cursor (ScreenPtr pScreen, CursorPtr pCurs)
{
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
return vbox_host_uses_hwcursor(pScrn);
}
static unsigned char color_to_byte (unsigned c)
{
return (c >> 8) & 0xff;
}
static unsigned char *
vbox_realize_cursor(xf86CursorInfoPtr infoPtr, CursorPtr pCurs)
{
VBOXPtr pVBox;
CursorBitsPtr bitsp;
unsigned short w, h, x, y;
unsigned char *c, *p, *pm, *ps, *m;
size_t size, size_rgba, size_mask, src_pitch, dst_pitch;
CARD32 fc, bc, *cp;
int rc, scrnIndex = infoPtr->pScrn->scrnIndex;
VMMDevReqMousePointer *reqp;
pVBox = infoPtr->pScrn->driverPrivate;
bitsp = pCurs->bits;
w = bitsp->width;
h = bitsp->height;
if (!w || !h || w > VBOX_MAX_CURSOR_WIDTH || h > VBOX_MAX_CURSOR_HEIGHT)
RETERROR(scrnIndex, NULL,
"Error invalid cursor dimensions %dx%d\n", w, h);
if ((bitsp->xhot > w) || (bitsp->yhot > h))
RETERROR(scrnIndex, NULL,
"Error invalid cursor hotspot location %dx%d (max %dx%d)\n",
bitsp->xhot, bitsp->yhot, w, h);
src_pitch = PixmapBytePad (bitsp->width, 1);
dst_pitch = (w + 7) / 8;
size_mask = ((dst_pitch * h) + 3) & (size_t) ~3;
size_rgba = w * h * 4;
size = size_mask + size_rgba + pVBox->pointerHeaderSize;
p = c = xcalloc (1, size);
if (!c)
RETERROR(scrnIndex, NULL,
"Error failed to alloc %lu bytes for cursor\n",
(unsigned long) size);
rc = vmmdevInitRequest ((VMMDevRequestHeader *) p,
VMMDevReq_SetPointerShape);
if (RT_FAILURE (rc)) {
xfree(p);
RETERROR(scrnIndex, NULL,
"Could not init VMM request: rc = %d\n", rc);
}
m = p + offsetof (VMMDevReqMousePointer, pointerData);
cp = (CARD32 *) (m + size_mask);
dolog ("w=%d h=%d sm=%d sr=%d p=%d\n",
w, h, (int) size_mask, (int) size_rgba, (int) dst_pitch);
dolog ("m=%p c=%p cp=%p\n", m, c, (void *) (void *)cp);
fc = color_to_byte (pCurs->foreBlue)
| (color_to_byte (pCurs->foreGreen) << 8)
| (color_to_byte (pCurs->foreRed) << 16);
bc = color_to_byte (pCurs->backBlue)
| (color_to_byte (pCurs->backGreen) << 8)
| (color_to_byte (pCurs->backRed) << 16);
/*
* Convert the Xorg source/mask bits to the and/xor bits VBox needs.
* Xorg:
* The mask is a bitmap indicating which parts of the cursor are
* transparent and which parts are drawn. The source is a bitmap
* indicating which parts of the non-transparent portion of the
* the cursor should be painted in the foreground color and which
* should be painted in the background color. By default, set bits
* indicate the opaque part of the mask bitmap and clear bits
* indicate the transparent part.
* VBox:
* The color data is the XOR mask. The AND mask bits determine
* which pixels of the color data (XOR mask) will replace (overwrite)
* the screen pixels (AND mask bit = 0) and which ones will be XORed
* with existing screen pixels (AND mask bit = 1).
* For example when you have the AND mask all 0, then you see the
* correct mouse pointer image surrounded by black square.
*/
for (pm = bitsp->mask, ps = bitsp->source, y = 0;
y < h;
++y, pm += src_pitch, ps += src_pitch, m += dst_pitch)
{
for (x = 0; x < w; ++x)
{
if (pm[x / 8] & (1 << (x % 8)))
{
/* opaque, leave AND mask bit at 0 */
if (ps[x / 8] & (1 << (x % 8)))
{
*cp++ = fc;
PUT_PIXEL ('X');
}
else
{
*cp++ = bc;
PUT_PIXEL ('*');
}
}
else
{
/* transparent, set AND mask bit */
m[x / 8] |= 1 << (7 - (x % 8));
/* don't change the screen pixel */
*cp++ = 0;
PUT_PIXEL (' ');
}
}
PUT_PIXEL ('\n');
}
reqp = (VMMDevReqMousePointer *) p;
reqp->width = w;
reqp->height = h;
reqp->xHot = bitsp->xhot;
reqp->yHot = bitsp->yhot;
reqp->fFlags = VBOX_MOUSE_POINTER_SHAPE;
reqp->header.size = size;
#ifdef DEBUG_X
ErrorF ("shape = %p\n", p);
vbox_show_shape (w, h, bc, c);
#endif
return p;
}
#ifdef ARGB_CURSOR
static Bool vbox_use_hw_cursor_argb (ScreenPtr pScreen, CursorPtr pCurs)
{
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
Bool rc = TRUE;
if (!vbox_host_uses_hwcursor(pScrn))
rc = FALSE;
if ( rc
&& ( (pCurs->bits->height > VBOX_MAX_CURSOR_HEIGHT)
|| (pCurs->bits->width > VBOX_MAX_CURSOR_WIDTH)
|| (pScrn->bitsPerPixel <= 8)
)
)
rc = FALSE;
return rc;
}
static void vbox_load_cursor_argb (ScrnInfoPtr pScrn, CursorPtr pCurs)
{
VBOXPtr pVBox;
VMMDevReqMousePointer *reqp;
CursorBitsPtr bitsp;
unsigned short w, h;
unsigned short cx, cy;
unsigned char *pm;
CARD32 *pc;
size_t size, mask_size;
CARD8 *p;
int scrnIndex;
pVBox = pScrn->driverPrivate;
bitsp = pCurs->bits;
w = bitsp->width;
h = bitsp->height;
scrnIndex = pScrn->scrnIndex;
/* Mask must be generated for alpha cursors, that is required by VBox. */
/* @note: (michael) the next struct must be 32bit aligned. */
mask_size = ((w + 7) / 8 * h + 3) & ~3;
if (!w || !h || w > VBOX_MAX_CURSOR_WIDTH || h > VBOX_MAX_CURSOR_HEIGHT)
RETERROR(scrnIndex, ,
"Error invalid cursor dimensions %dx%d\n", w, h);
if ((bitsp->xhot > w) || (bitsp->yhot > h))
RETERROR(scrnIndex, ,
"Error invalid cursor hotspot location %dx%d (max %dx%d)\n",
bitsp->xhot, bitsp->yhot, w, h);
size = w * h * 4 + pVBox->pointerHeaderSize + mask_size;
p = xcalloc (1, size);
if (!p)
RETERROR(scrnIndex, ,
"Error failed to alloc %lu bytes for cursor\n",
(unsigned long) size);
reqp = (VMMDevReqMousePointer *) p;
*reqp = *pVBox->reqp;
reqp->width = w;
reqp->height = h;
reqp->xHot = bitsp->xhot;
reqp->yHot = bitsp->yhot;
reqp->fFlags = VBOX_MOUSE_POINTER_SHAPE | VBOX_MOUSE_POINTER_ALPHA;
reqp->header.size = size;
memcpy (p + offsetof (VMMDevReqMousePointer, pointerData) + mask_size,
bitsp->argb, w * h * 4);
/** @ */
/* Emulate the AND mask. */
pm = p + offsetof (VMMDevReqMousePointer, pointerData);
pc = bitsp->argb;
/* Init AND mask to 1 */
memset (pm, 0xFF, mask_size);
/**
* The additions driver must provide the AND mask for alpha cursors. The host frontend
* which can handle alpha channel, will ignore the AND mask and draw an alpha cursor.
* But if the host does not support ARGB, then it simply uses the AND mask and the color
* data to draw a normal color cursor.
*/
for (cy = 0; cy < h; cy++)
{
unsigned char bitmask = 0x80;
for (cx = 0; cx < w; cx++, bitmask >>= 1)
{
if (bitmask == 0)
bitmask = 0x80;
if (pc[cx] >= 0xF0000000)
pm[cx / 8] &= ~bitmask;
}
/* Point to next source and dest scans */
pc += w;
pm += (w + 7) / 8;
}
if (vbox_vmmcall (pScrn, pVBox, &reqp->header) != TRUE)
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Request to virtual machine failed "
"- unable to set the virtual mouse pointer ARGB cursor image.\n");
xfree (p);
}
#endif
Bool vbox_cursor_init (ScreenPtr pScreen)
{
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
VBOXPtr pVBox = pScrn->driverPrivate;
xf86CursorInfoPtr pCurs;
Bool rc;
pVBox->pCurs = pCurs = xf86CreateCursorInfoRec ();
if (!pCurs)
RETERROR(pScrn->scrnIndex, FALSE,
"Failed to create X Window cursor information structures for virtual mouse.\n");
pCurs->MaxWidth = VBOX_MAX_CURSOR_WIDTH;
pCurs->MaxHeight = VBOX_MAX_CURSOR_HEIGHT;
pCurs->Flags = HARDWARE_CURSOR_TRUECOLOR_AT_8BPP
| HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1
| HARDWARE_CURSOR_BIT_ORDER_MSBFIRST;
pCurs->SetCursorColors = vbox_set_cursor_colors;
pCurs->SetCursorPosition = vbox_set_cursor_position;
pCurs->LoadCursorImage = vbox_load_cursor_image;
pCurs->HideCursor = vbox_hide_cursor;
pCurs->ShowCursor = vbox_show_cursor;
pCurs->UseHWCursor = vbox_use_hw_cursor;
pCurs->RealizeCursor = vbox_realize_cursor;
#ifdef ARGB_CURSOR
pCurs->UseHWCursorARGB = vbox_use_hw_cursor_argb;
pCurs->LoadCursorARGB = vbox_load_cursor_argb;
#endif
rc = xf86InitCursor (pScreen, pCurs);
if (rc == TRUE)
return TRUE;
RETERROR(pScrn->scrnIndex, FALSE, "Failed to enable mouse pointer integration.\n");
}
/**
* Inform VBox that we will supply it with dirty rectangle information
* and install the dirty rectangle handler.
*
* @returns TRUE for success, FALSE for failure
* @param pScreen Pointer to a structure describing the X screen in use
*/
Bool
vboxEnableVbva(ScrnInfoPtr pScrn)
{
int scrnIndex = pScrn->scrnIndex;
VBOXPtr pVBox = pScrn->driverPrivate;
if (pVBox->useVbva != TRUE)
return FALSE;
pVBox->reqe->u32Enable = 1;
pVBox->reqe->cbRingBuffer = VBVA_RING_BUFFER_SIZE;
pVBox->reqe->fu32Status = 0;
if (vbox_vmmcall(pScrn, pVBox, (VMMDevRequestHeader *) pVBox->reqe)
!= TRUE)
{
/* Request not accepted - disable for old hosts. */
xf86DrvMsg(scrnIndex, X_ERROR,
"Unable to activate VirtualBox graphics acceleration "
"- the request to the virtual machine failed. "
"You may be running an old version of VirtualBox.\n");
pVBox->useVbva = FALSE;
pVBox->reqe->u32Enable = 0;
pVBox->reqe->cbRingBuffer = VBVA_RING_BUFFER_SIZE;
pVBox->reqe->fu32Status = 0;
vbox_vmmcall(pScrn, pVBox, (VMMDevRequestHeader *) pVBox->reqe);
return FALSE;
}
return TRUE;
}
/**
* Inform VBox that we will stop supplying it with dirty rectangle
* information. This function is intended to be called when an X
* virtual terminal is disabled, or the X server is terminated.
*
* @returns TRUE for success, FALSE for failure
* @param pScreen Pointer to a structure describing the X screen in use
*/
Bool
vboxDisableVbva(ScrnInfoPtr pScrn)
{
int scrnIndex = pScrn->scrnIndex;
VBOXPtr pVBox = pScrn->driverPrivate;
if (pVBox->useVbva != TRUE) /* Ths function should not have been called */
return FALSE;
pVBox->reqe->u32Enable = 0;
pVBox->reqe->cbRingBuffer = VBVA_RING_BUFFER_SIZE;
pVBox->reqe->fu32Status = 0;
if (vbox_vmmcall(pScrn, pVBox, (VMMDevRequestHeader *) pVBox->reqe)
!= TRUE)
xf86DrvMsg(scrnIndex, X_ERROR,
"Unable to disable VirtualBox graphics acceleration "
"- the request to the virtual machine failed.\n");
else
memset(pVBox->pVbvaMemory, 0, sizeof(VBVAMEMORY));
return TRUE;
}
/**
* Query the last display change request.
*
* @returns iprt status value
* @param xres where to store the horizontal pixel resolution requested
* (0 = do not change)
* @param yres where to store the vertical pixel resolution requested
* (0 = do not change)
* @param bpp where to store the bits per pixel requeste
* (0 = do not change)
* @param display Where to store the display number the request was for -
* 0 for the primary display, 1 for the first secondary, etc.
*/
Bool
vboxGetDisplayChangeRequest(ScrnInfoPtr pScrn, uint32_t *px, uint32_t *py,
uint32_t *pbpp, uint32_t *display)
{
int rc, scrnIndex = pScrn->scrnIndex;
VBOXPtr pVBox = pScrn->driverPrivate;
VMMDevDisplayChangeRequest2 Req = { { 0 } };
vmmdevInitRequest(&Req.header, VMMDevReq_GetDisplayChangeRequest2);
rc = vbox_vmmcall(pScrn, pVBox, &Req.header);
if (RT_SUCCESS(rc))
{
*px = Req.xres;
*py = Req.yres;
*pbpp = Req.bpp;
*display = Req.display;
return TRUE;
}
xf86DrvMsg(scrnIndex, X_ERROR,
"Failed to request the last resolution requested from the guest, rc=%d.\n",
rc);
return FALSE;
}