~ubuntu-branches/ubuntu/raring/virtualbox-ose/raring

« back to all changes in this revision

Viewing changes to src/VBox/Additions/x11/vboxvideo/vboxutils_68.c

  • Committer: Bazaar Package Importer
  • Author(s): Felix Geyer
  • Date: 2011-01-30 23:27:25 UTC
  • mfrom: (0.3.12 upstream)
  • Revision ID: james.westby@ubuntu.com-20110130232725-2ouajjd2ggdet0zd
Tags: 4.0.2-dfsg-1ubuntu1
* Merge from Debian unstable, remaining changes:
  - Add Apport hook.
    - debian/virtualbox-ose.files/source_virtualbox-ose.py
    - debian/virtualbox-ose.install
  - Drop *-source packages.
* Drop ubuntu-01-fix-build-gcc45.patch, fixed upstream.
* Drop ubuntu-02-as-needed.patch, added to the Debian package.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/** @file
2
 
 * Linux Additions X11 graphics driver helper module
3
 
 */
4
 
 
5
 
/*
6
 
 * Copyright (C) 2006-2007 Oracle Corporation
7
 
 *
8
 
 * This file is part of VirtualBox Open Source Edition (OSE), as
9
 
 * available from http://www.virtualbox.org. This file is free software;
10
 
 * you can redistribute it and/or modify it under the terms of the GNU
11
 
 * General Public License (GPL) as published by the Free Software
12
 
 * Foundation, in version 2 as it comes in the "COPYING" file of the
13
 
 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14
 
 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15
 
 */
16
 
 
17
 
#include <VBox/VBoxGuest.h>
18
 
#include <VBox/VBoxGuestLib.h>
19
 
 
20
 
#include <xf86Pci.h>
21
 
#include <Pci.h>
22
 
 
23
 
#include "xf86.h"
24
 
#define NEED_XF86_TYPES
25
 
#include "xf86_ansic.h"
26
 
#include "compiler.h"
27
 
#include "cursorstr.h"
28
 
 
29
 
#include "vboxvideo_68.h"
30
 
 
31
 
#define VBOX_MAX_CURSOR_WIDTH 64
32
 
#define VBOX_MAX_CURSOR_HEIGHT 64
33
 
 
34
 
#if 0
35
 
#define DEBUG_X
36
 
#endif
37
 
#ifdef DEBUG_X
38
 
#define TRACE_ENTRY() do \
39
 
    { \
40
 
        ErrorF ("%s\n", __FUNCTION__); \
41
 
    } while(0)
42
 
#define TRACE_LINE() do \
43
 
    { \
44
 
        ErrorF ("%s: line %d\n", __FUNCTION__, __LINE__); \
45
 
    } while(0)
46
 
#define PUT_PIXEL(c) ErrorF ("%c", c)
47
 
#define dolog(...) ErrorF  (__VA_ARGS__)
48
 
#else
49
 
#define PUT_PIXEL(c) do { } while(0)
50
 
#define TRACE_ENTRY() do { } while(0)
51
 
#define TRACE_LINE() do { } while(0)
52
 
#define dolog(...) do { } while(0)
53
 
#endif
54
 
 
55
 
/** Macro to printf an error message and return from a function */
56
 
#define RETERROR(scrnIndex, RetVal, ...) \
57
 
do \
58
 
{ \
59
 
    xf86DrvMsg(scrnIndex, X_ERROR, __VA_ARGS__); \
60
 
    return RetVal; \
61
 
} \
62
 
while (0)
63
 
 
64
 
#ifdef DEBUG_X
65
 
static void vbox_show_shape (unsigned short w, unsigned short h,
66
 
                             CARD32 bg, unsigned char *image)
67
 
{
68
 
    size_t x, y;
69
 
    unsigned short pitch;
70
 
    CARD32 *color;
71
 
    unsigned char *mask;
72
 
    size_t size_mask;
73
 
 
74
 
    image    += offsetof (VMMDevReqMousePointer, pointerData);
75
 
    mask      = image;
76
 
    pitch     = (w + 7) / 8;
77
 
    size_mask = (pitch * h + 3) & ~3;
78
 
    color     = (CARD32 *) (image + size_mask);
79
 
 
80
 
    TRACE_ENTRY ();
81
 
    for (y = 0; y < h; ++y, mask += pitch, color += w)
82
 
    {
83
 
        for (x = 0; x < w; ++x)
84
 
        {
85
 
            if (mask[x / 8] & (1 << (7 - (x % 8))))
86
 
                ErrorF (" ");
87
 
 
88
 
            else
89
 
            {
90
 
                CARD32 c = color[x];
91
 
                if (c == bg)
92
 
                    ErrorF ("Y");
93
 
                else
94
 
                    ErrorF ("X");
95
 
            }
96
 
        }
97
 
        ErrorF ("\n");
98
 
    }
99
 
}
100
 
#endif
101
 
 
102
 
static Bool vbox_vmmcall (ScrnInfoPtr pScrn, VBOXPtr pVBox,
103
 
                          VMMDevRequestHeader *hdrp)
104
 
{
105
 
    int err;
106
 
 
107
 
    TRACE_ENTRY ();
108
 
#ifdef RT_OS_LINUX
109
 
    err = ioctl (pVBox->vbox_fd, VBOXGUEST_IOCTL_VMMREQUEST(hdrp->size), hdrp);
110
 
#else
111
 
/**
112
 
 * @todo this should work fine on other platforms too, but it needs to be
113
 
 *       checked for each one.
114
 
 */
115
 
# error port me!
116
 
#endif
117
 
    if (err < 0)
118
 
        RETERROR(pScrn->scrnIndex, FALSE,
119
 
                 "Ioctl call failed during a request to the virtual machine: %s\n",
120
 
                 strerror (errno));
121
 
    else
122
 
        if (RT_FAILURE (hdrp->rc))
123
 
            RETERROR(pScrn->scrnIndex, FALSE,
124
 
                     "A request to the virtual machine returned %d\n",
125
 
                     hdrp->rc);
126
 
 
127
 
    /* success */
128
 
    return TRUE;
129
 
}
130
 
 
131
 
static Bool
132
 
vbox_host_uses_hwcursor(ScrnInfoPtr pScrn)
133
 
{
134
 
    Bool rc = FALSE;
135
 
    VBOXPtr pVBox = pScrn->driverPrivate;
136
 
    VMMDevReqMouseStatus req;
137
 
 
138
 
    /* We may want to force the use of a software cursor.  Currently this is
139
 
     * needed if the guest uses a large virtual resolution, as in this case
140
 
     * the host and guest tend to disagree about the pointer location. */
141
 
    if (pVBox->forceSWCursor)
142
 
        rc = FALSE;
143
 
    else
144
 
    {
145
 
        int vrc = vmmdevInitRequest ((VMMDevRequestHeader*)&req, VMMDevReq_GetMouseStatus);
146
 
        if (RT_FAILURE (vrc))
147
 
            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
148
 
                "Unable to determine whether the virtual machine supports mouse pointer integration - request initialization failed with return code %d\n", rc);
149
 
    #ifdef RT_OS_LINUX
150
 
        if (   RT_SUCCESS(vrc)
151
 
            && (ioctl(pVBox->vbox_fd, VBOXGUEST_IOCTL_VMMREQUEST(sizeof(req)), (void*)&req) < 0))
152
 
    #else
153
 
    # error port me!
154
 
    #endif
155
 
        {
156
 
            vrc = VERR_FILE_IO_ERROR;
157
 
            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
158
 
                "Unable to determine whether the virtual machine supports mouse pointer integration - request system call failed: %s.\n",
159
 
                strerror(errno));
160
 
        }
161
 
        if (   RT_SUCCESS(rc)
162
 
            && !(req.mouseFeatures & VMMDEV_MOUSE_HOST_CANNOT_HWPOINTER)
163
 
            && (req.mouseFeatures & VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE))
164
 
                rc = TRUE;
165
 
    }
166
 
    return rc;
167
 
}
168
 
 
169
 
 
170
 
void
171
 
vbox_close(ScrnInfoPtr pScrn, VBOXPtr pVBox)
172
 
{
173
 
    TRACE_ENTRY ();
174
 
 
175
 
    xfree (pVBox->reqp);
176
 
    pVBox->reqp = NULL;
177
 
 
178
 
#ifdef RT_OS_SOLARIS
179
 
    VbglR3Term();
180
 
#else
181
 
    if (close (pVBox->vbox_fd))
182
 
        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
183
 
            "Unable to close the virtual machine device (file %d): %s\n",
184
 
            pVBox->vbox_fd, strerror (errno));
185
 
    pVBox->vbox_fd = -1;
186
 
#endif
187
 
}
188
 
 
189
 
/**
190
 
 * Macro to disable VBVA extensions and return, for use when an
191
 
 * unexplained error occurs.
192
 
 */
193
 
#define DISABLE_VBVA_AND_RETURN(pScrn, ...) \
194
 
do \
195
 
{ \
196
 
    xf86DrvMsg(pScrn->scrnIndex, X_ERROR, __VA_ARGS__); \
197
 
    vboxDisableVbva(pScrn); \
198
 
    pVBox->useVbva = FALSE; \
199
 
    return; \
200
 
} \
201
 
while (0)
202
 
 
203
 
/**
204
 
 * Callback function called by the X server to tell us about dirty
205
 
 * rectangles in the video buffer.
206
 
 *
207
 
 * @param pScreen pointer to the information structure for the current
208
 
 *                screen
209
 
 * @param iRects  Number of dirty rectangles to update
210
 
 * @param aRects  Array of structures containing the coordinates of the
211
 
 *                rectangles
212
 
 */
213
 
static void
214
 
vboxHandleDirtyRect(ScrnInfoPtr pScrn, int iRects, BoxPtr aRects)
215
 
{
216
 
    VBVACMDHDR cmdHdr;
217
 
    VBOXPtr pVBox;
218
 
    VBVARECORD *pRecord;
219
 
    VBVAMEMORY *pMem;
220
 
    CARD32 indexRecordNext;
221
 
    CARD32 off32Data;
222
 
    CARD32 off32Free;
223
 
    INT32 i32Diff;
224
 
    CARD32 cbHwBufferAvail;
225
 
    int scrnIndex;
226
 
    int i;
227
 
 
228
 
    pVBox = pScrn->driverPrivate;
229
 
    if (pVBox->useVbva == FALSE)
230
 
        return;
231
 
    pMem = pVBox->pVbvaMemory;
232
 
    /* Just return quietly if VBVA is not currently active. */
233
 
    if ((pMem->fu32ModeFlags & VBVA_F_MODE_ENABLED) == 0)
234
 
        return;
235
 
    scrnIndex = pScrn->scrnIndex;
236
 
 
237
 
    for (i = 0; i < iRects; i++)
238
 
    {
239
 
        cmdHdr.x = (int16_t)aRects[i].x1 - pVBox->viewportX;
240
 
        cmdHdr.y = (int16_t)aRects[i].y1 - pVBox->viewportY;
241
 
        cmdHdr.w = (uint16_t)(aRects[i].x2 - aRects[i].x1);
242
 
        cmdHdr.h = (uint16_t)(aRects[i].y2 - aRects[i].y1);
243
 
 
244
 
        /* Get the active record and move the pointer along */
245
 
        indexRecordNext = (pMem->indexRecordFree + 1)
246
 
                           % VBVA_MAX_RECORDS;
247
 
        if (indexRecordNext == pMem->indexRecordFirst)
248
 
        {
249
 
            /* All slots in the records queue are used. */
250
 
            if (vbox_vmmcall(pScrn, pVBox,
251
 
                             (VMMDevRequestHeader *) pVBox->reqf) != TRUE)
252
 
                DISABLE_VBVA_AND_RETURN(pScrn,
253
 
                    "Unable to clear the VirtualBox graphics acceleration queue "
254
 
                    "- the request to the virtual machine failed.  Switching to "
255
 
                    "unaccelerated mode.\n");
256
 
        }
257
 
        if (indexRecordNext == pMem->indexRecordFirst)
258
 
            DISABLE_VBVA_AND_RETURN(pScrn,
259
 
                "Failed to clear the VirtualBox graphics acceleration queue.  "
260
 
                "Switching to unaccelerated mode.\n");
261
 
        pRecord = &pMem->aRecords[pMem->indexRecordFree];
262
 
        /* Mark the record as being updated. */
263
 
        pRecord->cbRecord = VBVA_F_RECORD_PARTIAL;
264
 
        pMem->indexRecordFree = indexRecordNext;
265
 
        /* Compute how many bytes we have in the ring buffer. */
266
 
        off32Free = pMem->off32Free;
267
 
        off32Data = pMem->off32Data;
268
 
        /* Free is writing position. Data is reading position.
269
 
         * Data == Free means buffer is free.
270
 
         * There must be always gap between free and data when data
271
 
         * are in the buffer.
272
 
         * Guest only changes free, host only changes data.
273
 
         */
274
 
        i32Diff = off32Data - off32Free;
275
 
        cbHwBufferAvail = i32Diff > 0? i32Diff: VBVA_RING_BUFFER_SIZE
276
 
                                              + i32Diff;
277
 
        if (cbHwBufferAvail <= VBVA_RING_BUFFER_THRESHOLD)
278
 
        {
279
 
            if (vbox_vmmcall(pScrn, pVBox,
280
 
                            (VMMDevRequestHeader *) pVBox->reqf) != TRUE)
281
 
                DISABLE_VBVA_AND_RETURN(pScrn,
282
 
                    "Unable to clear the VirtualBox graphics acceleration queue "
283
 
                    "- the request to the virtual machine failed.  Switching to "
284
 
                    "unaccelerated mode.\n");
285
 
            /* Calculate the free space again. */
286
 
            off32Free = pMem->off32Free;
287
 
            off32Data = pMem->off32Data;
288
 
            i32Diff = off32Data - off32Free;
289
 
            cbHwBufferAvail = i32Diff > 0? i32Diff:
290
 
                                  VBVA_RING_BUFFER_SIZE + i32Diff;
291
 
            if (cbHwBufferAvail <= VBVA_RING_BUFFER_THRESHOLD)
292
 
                DISABLE_VBVA_AND_RETURN(pScrn,
293
 
                    "No space left in the VirtualBox graphics acceleration command buffer, "
294
 
                    "despite clearing the queue.  Switching to unaccelerated mode.\n");
295
 
        }
296
 
        /* Now copy the data into the buffer */
297
 
        if (off32Free + sizeof(cmdHdr) < VBVA_RING_BUFFER_SIZE)
298
 
        {
299
 
            memcpy(&pMem->au8RingBuffer[off32Free], &cmdHdr,
300
 
                   sizeof(cmdHdr));
301
 
            pMem->off32Free = pMem->off32Free + sizeof(cmdHdr);
302
 
        }
303
 
        else
304
 
        {
305
 
            CARD32 u32First = VBVA_RING_BUFFER_SIZE - off32Free;
306
 
            /* The following is impressively ugly! */
307
 
            CARD8 *pu8Second = (CARD8 *)&cmdHdr + u32First;
308
 
            CARD32 u32Second = sizeof(cmdHdr) - u32First;
309
 
            memcpy(&pMem->au8RingBuffer[off32Free], &cmdHdr, u32First);
310
 
            if (u32Second)
311
 
                memcpy(&pMem->au8RingBuffer[0], (void *)pu8Second, u32Second);
312
 
            pMem->off32Free = u32Second;
313
 
        }
314
 
        pRecord->cbRecord += sizeof(cmdHdr);
315
 
        /* Mark the record completed. */
316
 
        pRecord->cbRecord &= ~VBVA_F_RECORD_PARTIAL;
317
 
    }
318
 
}
319
 
 
320
 
 
321
 
/**
322
 
 * Initialise VirtualBox's accelerated video extensions.
323
 
 * Note that we assume that the PCI memory is 32bit mapped,
324
 
 * as X doesn't seem to support mapping 64bit memory.
325
 
 *
326
 
 * @returns True on success, false on failure
327
 
 */
328
 
static Bool
329
 
vboxInitVbva(int scrnIndex, ScreenPtr pScreen, VBOXPtr pVBox)
330
 
{
331
 
    PCITAG pciTagDev;
332
 
    ADDRESS pciAddrDev;
333
 
    int rc;
334
 
 
335
 
    /* Locate the device.  It should already have been enabled by
336
 
       the kernel driver. */
337
 
    pciTagDev = pciFindFirst((unsigned) VMMDEV_DEVICEID << 16 | VMMDEV_VENDORID,
338
 
                             (CARD32) ~0);
339
 
    if (pciTagDev == PCI_NOT_FOUND)
340
 
    {
341
 
        xf86DrvMsg(scrnIndex, X_ERROR,
342
 
                   "Could not find the VirtualBox base device on the PCI bus.\n");
343
 
        return FALSE;
344
 
    }
345
 
    /* Read the address and size of the second I/O region. */
346
 
    pciAddrDev = pciReadLong(pciTagDev, PCI_MAP_REG_START + 4);
347
 
    if (pciAddrDev == 0 || pciAddrDev == (CARD32) ~0)
348
 
        RETERROR(scrnIndex, FALSE,
349
 
                 "The VirtualBox base device contains an invalid memory address.\n");
350
 
    if (PCI_MAP_IS64BITMEM(pciAddrDev))
351
 
        RETERROR(scrnIndex, FALSE,
352
 
                 "The VirtualBox base device has a 64bit mapping address.  "
353
 
                 "This is currently not supported.\n");
354
 
    /* Map it.  We hardcode the size as X does not export the
355
 
       function needed to determine it. */
356
 
    pVBox->pVMMDevMemory = xf86MapPciMem(scrnIndex, 0, pciTagDev, pciAddrDev,
357
 
                                         sizeof(VMMDevMemory));
358
 
    if (pVBox->pVMMDevMemory == NULL)
359
 
    {
360
 
        xf86DrvMsg(scrnIndex, X_ERROR,
361
 
                   "Failed to map VirtualBox video extension memory.\n");
362
 
        return FALSE;
363
 
    }
364
 
    pVBox->pVbvaMemory = &pVBox->pVMMDevMemory->vbvaMemory;
365
 
    /* Initialise requests */
366
 
    pVBox->reqf = xcalloc(1, vmmdevGetRequestSize(VMMDevReq_VideoAccelFlush));
367
 
    if (!pVBox->reqf)
368
 
    {
369
 
        xf86DrvMsg(scrnIndex, X_ERROR,
370
 
                   "Could not allocate memory for VBVA flush request.\n");
371
 
        return FALSE;
372
 
    }
373
 
    rc = vmmdevInitRequest ((VMMDevRequestHeader *) pVBox->reqf,
374
 
                            VMMDevReq_VideoAccelFlush);
375
 
    if (RT_FAILURE (rc))
376
 
    {
377
 
        xf86DrvMsg(scrnIndex, X_ERROR,
378
 
                   "Could not initialise VBVA flush request: return value %d\n", rc);
379
 
        xfree(pVBox->reqf);
380
 
        return FALSE;
381
 
    }
382
 
    pVBox->reqe = xcalloc(1, vmmdevGetRequestSize(VMMDevReq_VideoAccelEnable));
383
 
    if (!pVBox->reqe)
384
 
    {
385
 
        xf86DrvMsg(scrnIndex, X_ERROR,
386
 
                   "Could not allocate memory for VBVA enable request.\n");
387
 
        xfree(pVBox->reqf);
388
 
        return FALSE;
389
 
    }
390
 
    rc = vmmdevInitRequest ((VMMDevRequestHeader *) pVBox->reqe,
391
 
                            VMMDevReq_VideoAccelEnable);
392
 
    if (RT_FAILURE (rc))
393
 
    {
394
 
        xf86DrvMsg(scrnIndex, X_ERROR,
395
 
                   "Could not initialise VBVA enable request: return value = %d\n",
396
 
                   rc);
397
 
        xfree(pVBox->reqf);
398
 
        xfree(pVBox->reqe);
399
 
        return FALSE;
400
 
    }
401
 
    /* Set up the dirty rectangle handler.  Since this seems to be a
402
 
       delicate operation, and removing it doubly so, this will
403
 
       remain in place whether it is needed or not, and will simply
404
 
       return if VBVA is not active.  I assume that it will be active
405
 
       most of the time. */
406
 
    if (ShadowFBInit2(pScreen, NULL, vboxHandleDirtyRect) != TRUE)
407
 
    {
408
 
        xf86DrvMsg(scrnIndex, X_ERROR,
409
 
                   "Unable to install dirty rectangle handler for VirtualBox graphics acceleration.\n");
410
 
        xfree(pVBox->reqf);
411
 
        xfree(pVBox->reqe);
412
 
        return FALSE;
413
 
    }
414
 
    return TRUE;
415
 
}
416
 
 
417
 
Bool
418
 
vbox_open (ScrnInfoPtr pScrn, ScreenPtr pScreen, VBOXPtr pVBox)
419
 
{
420
 
    int fd, vrc;
421
 
    void *p = NULL;
422
 
    size_t size;
423
 
    int scrnIndex = pScrn->scrnIndex;
424
 
    Bool rc = TRUE;
425
 
 
426
 
    TRACE_ENTRY ();
427
 
 
428
 
    pVBox->useVbva = FALSE;
429
 
 
430
 
#ifdef RT_OS_SOLARIS
431
 
    NOREF(fd);
432
 
    if (pVBox->reqp)
433
 
    {
434
 
        /* still open, just re-enable VBVA after CloseScreen was called */
435
 
        pVBox->useVbva = vboxInitVbva(scrnIndex, pScreen, pVBox);
436
 
        return TRUE;
437
 
    }
438
 
 
439
 
    vrc = VbglR3Init();
440
 
    if (RT_FAILURE(vrc))
441
 
    {
442
 
        xf86DrvMsg(scrnIndex, X_ERROR, "VbglR3Init failed vrc=%d.\n", vrc);
443
 
        rc = FALSE;
444
 
    }
445
 
#else
446
 
    if (pVBox->vbox_fd != -1 && pVBox->reqp)
447
 
    {
448
 
        /* still open, just re-enable VBVA after CloseScreen was called */
449
 
        pVBox->useVbva = vboxInitVbva(scrnIndex, pScreen, pVBox);
450
 
        return TRUE;
451
 
    }
452
 
 
453
 
    fd = open (VBOXGUEST_DEVICE_NAME, O_RDWR, 0);
454
 
    if (fd < 0)
455
 
    {
456
 
        xf86DrvMsg(scrnIndex, X_ERROR,
457
 
                   "Error opening kernel module: %s\n",
458
 
                   strerror (errno));
459
 
        rc = FALSE;
460
 
    }
461
 
#endif
462
 
 
463
 
    if (rc) {
464
 
        size = vmmdevGetRequestSize (VMMDevReq_SetPointerShape);
465
 
 
466
 
        p = xcalloc (1, size);
467
 
        if (NULL == p) {
468
 
            xf86DrvMsg(scrnIndex, X_ERROR,
469
 
                       "Could not allocate %lu bytes for VMM request\n",
470
 
                       (unsigned long) size);
471
 
            rc = FALSE;
472
 
        }
473
 
    }
474
 
    if (rc) {
475
 
        vrc = vmmdevInitRequest (p, VMMDevReq_SetPointerShape);
476
 
        if (RT_FAILURE (vrc))
477
 
        {
478
 
            xf86DrvMsg(scrnIndex, X_ERROR,
479
 
                       "Could not init VMM request: vrc = %d\n", vrc);
480
 
            rc = FALSE;
481
 
        }
482
 
    }
483
 
    if (rc) {
484
 
#ifndef RT_OS_SOLARIS
485
 
        pVBox->vbox_fd = fd;
486
 
#endif
487
 
        pVBox->reqp = p;
488
 
        pVBox->pCurs = NULL;
489
 
        pVBox->pointerHeaderSize = size;
490
 
        pVBox->useVbva = vboxInitVbva(scrnIndex, pScreen, pVBox);
491
 
    } else {
492
 
        if (NULL != p) {
493
 
            xfree (p);
494
 
        }
495
 
#ifdef RT_OS_SOLARIS
496
 
        VbglR3Term();
497
 
#else
498
 
        if (close (fd)) {
499
 
            xf86DrvMsg(scrnIndex, X_ERROR,
500
 
                       "Error closing kernel module file descriptor(%d): %s\n",
501
 
                       fd, strerror (errno));
502
 
        }
503
 
#endif
504
 
    }
505
 
    return rc;
506
 
}
507
 
 
508
 
static void vbox_vmm_hide_cursor (ScrnInfoPtr pScrn, VBOXPtr pVBox)
509
 
{
510
 
    pVBox->reqp->fFlags = 0;
511
 
    if (vbox_vmmcall (pScrn, pVBox, &pVBox->reqp->header) != TRUE)
512
 
        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
513
 
                   "Could not hide the virtual mouse pointer.\n");
514
 
}
515
 
 
516
 
static void vbox_vmm_show_cursor (ScrnInfoPtr pScrn, VBOXPtr pVBox)
517
 
{
518
 
    pVBox->reqp->fFlags = VBOX_MOUSE_POINTER_VISIBLE;
519
 
    if (vbox_vmmcall (pScrn, pVBox, &pVBox->reqp->header) != TRUE)
520
 
        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
521
 
                   "Could not unhide the virtual mouse pointer.\n");
522
 
}
523
 
 
524
 
static void vbox_vmm_load_cursor_image (ScrnInfoPtr pScrn, VBOXPtr pVBox,
525
 
                                        unsigned char *image)
526
 
{
527
 
    VMMDevReqMousePointer *reqp;
528
 
    reqp = (VMMDevReqMousePointer *) image;
529
 
 
530
 
    dolog ("w=%d h=%d size=%d\n",
531
 
           reqp->width,
532
 
           reqp->height,
533
 
           reqp->header.size);
534
 
 
535
 
#ifdef DEBUG_X
536
 
    vbox_show_shape (reqp->width, reqp->height, 0, image);
537
 
#endif
538
 
 
539
 
    if (vbox_vmmcall (pScrn, pVBox, &reqp->header) != TRUE)
540
 
        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
541
 
                   "Unable to set the virtual mouse pointer image.\n");
542
 
}
543
 
 
544
 
static void vbox_set_cursor_colors (ScrnInfoPtr pScrn, int bg, int fg)
545
 
{
546
 
    TRACE_ENTRY ();
547
 
 
548
 
    (void) pScrn;
549
 
    (void) bg;
550
 
    (void) fg;
551
 
    /* ErrorF ("vbox_set_cursor_colors NOT IMPLEMENTED\n"); */
552
 
}
553
 
 
554
 
static void
555
 
vbox_set_cursor_position (ScrnInfoPtr pScrn, int x, int y)
556
 
{
557
 
    (void) pScrn; (void) x; (void) y;
558
 
}
559
 
 
560
 
static void vbox_hide_cursor (ScrnInfoPtr pScrn)
561
 
{
562
 
    VBOXPtr pVBox = pScrn->driverPrivate;
563
 
 
564
 
    TRACE_ENTRY ();
565
 
 
566
 
    vbox_vmm_hide_cursor (pScrn, pVBox);
567
 
}
568
 
 
569
 
static void vbox_show_cursor (ScrnInfoPtr pScrn)
570
 
{
571
 
    VBOXPtr pVBox = pScrn->driverPrivate;
572
 
 
573
 
    TRACE_ENTRY ();
574
 
 
575
 
    vbox_vmm_show_cursor (pScrn, pVBox);
576
 
}
577
 
 
578
 
static void vbox_load_cursor_image (ScrnInfoPtr pScrn, unsigned char *image)
579
 
{
580
 
    VBOXPtr pVBox = pScrn->driverPrivate;
581
 
 
582
 
    TRACE_ENTRY ();
583
 
 
584
 
    vbox_vmm_load_cursor_image (pScrn, pVBox, image);
585
 
}
586
 
 
587
 
static Bool
588
 
vbox_use_hw_cursor (ScreenPtr pScreen, CursorPtr pCurs)
589
 
{
590
 
    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
591
 
    return vbox_host_uses_hwcursor(pScrn);
592
 
}
593
 
 
594
 
static unsigned char color_to_byte (unsigned c)
595
 
{
596
 
    return (c >> 8) & 0xff;
597
 
}
598
 
 
599
 
static unsigned char *
600
 
vbox_realize_cursor(xf86CursorInfoPtr infoPtr, CursorPtr pCurs)
601
 
{
602
 
    VBOXPtr pVBox;
603
 
    CursorBitsPtr bitsp;
604
 
    unsigned short w, h, x, y;
605
 
    unsigned char *c, *p, *pm, *ps, *m;
606
 
    size_t size, size_rgba, size_mask, src_pitch, dst_pitch;
607
 
    CARD32 fc, bc, *cp;
608
 
    int rc, scrnIndex = infoPtr->pScrn->scrnIndex;
609
 
    VMMDevReqMousePointer *reqp;
610
 
 
611
 
    pVBox = infoPtr->pScrn->driverPrivate;
612
 
    bitsp = pCurs->bits;
613
 
    w = bitsp->width;
614
 
    h = bitsp->height;
615
 
 
616
 
    if (!w || !h || w > VBOX_MAX_CURSOR_WIDTH || h > VBOX_MAX_CURSOR_HEIGHT)
617
 
        RETERROR(scrnIndex, NULL,
618
 
            "Error invalid cursor dimensions %dx%d\n", w, h);
619
 
 
620
 
    if ((bitsp->xhot > w) || (bitsp->yhot > h))
621
 
        RETERROR(scrnIndex, NULL,
622
 
            "Error invalid cursor hotspot location %dx%d (max %dx%d)\n",
623
 
            bitsp->xhot, bitsp->yhot, w, h);
624
 
 
625
 
    src_pitch = PixmapBytePad (bitsp->width, 1);
626
 
    dst_pitch = (w + 7) / 8;
627
 
    size_mask = ((dst_pitch * h) + 3) & (size_t) ~3;
628
 
    size_rgba = w * h * 4;
629
 
    size      = size_mask + size_rgba + pVBox->pointerHeaderSize;
630
 
 
631
 
    p = c = xcalloc (1, size);
632
 
    if (!c)
633
 
        RETERROR(scrnIndex, NULL,
634
 
                 "Error failed to alloc %lu bytes for cursor\n",
635
 
                 (unsigned long) size);
636
 
 
637
 
    rc = vmmdevInitRequest ((VMMDevRequestHeader *) p,
638
 
                            VMMDevReq_SetPointerShape);
639
 
    if (RT_FAILURE (rc)) {
640
 
        xfree(p);
641
 
        RETERROR(scrnIndex, NULL,
642
 
                 "Could not init VMM request: rc = %d\n", rc);
643
 
    }
644
 
 
645
 
    m = p + offsetof (VMMDevReqMousePointer, pointerData);
646
 
    cp = (CARD32 *) (m + size_mask);
647
 
 
648
 
    dolog ("w=%d h=%d sm=%d sr=%d p=%d\n",
649
 
           w, h, (int) size_mask, (int) size_rgba, (int) dst_pitch);
650
 
    dolog ("m=%p c=%p cp=%p\n", m, c, (void *) (void *)cp);
651
 
 
652
 
    fc = color_to_byte (pCurs->foreBlue)
653
 
      | (color_to_byte (pCurs->foreGreen) << 8)
654
 
      | (color_to_byte (pCurs->foreRed)   << 16);
655
 
 
656
 
    bc = color_to_byte (pCurs->backBlue)
657
 
      | (color_to_byte (pCurs->backGreen) << 8)
658
 
      | (color_to_byte (pCurs->backRed)   << 16);
659
 
 
660
 
    /*
661
 
     * Convert the Xorg source/mask bits to the and/xor bits VBox needs.
662
 
     * Xorg:
663
 
     *   The mask is a bitmap indicating which parts of the cursor are
664
 
     *   transparent and which parts are drawn. The source is a bitmap
665
 
     *   indicating which parts of the non-transparent portion of the
666
 
     *   the cursor should be painted in the foreground color and which
667
 
     *   should be painted in the background color. By default, set bits
668
 
     *   indicate the opaque part of the mask bitmap and clear bits
669
 
     *   indicate the transparent part.
670
 
     * VBox:
671
 
     *   The color data is the XOR mask. The AND mask bits determine
672
 
     *   which pixels of the color data (XOR mask) will replace (overwrite)
673
 
     *   the screen pixels (AND mask bit = 0) and which ones will be XORed
674
 
     *   with existing screen pixels (AND mask bit = 1).
675
 
     *   For example when you have the AND mask all 0, then you see the
676
 
     *   correct mouse pointer image surrounded by black square.
677
 
     */
678
 
    for (pm = bitsp->mask, ps = bitsp->source, y = 0;
679
 
         y < h;
680
 
         ++y, pm += src_pitch, ps += src_pitch, m += dst_pitch)
681
 
    {
682
 
        for (x = 0; x < w; ++x)
683
 
        {
684
 
            if (pm[x / 8] & (1 << (x % 8)))
685
 
            {
686
 
                /* opaque, leave AND mask bit at 0 */
687
 
                if (ps[x / 8] & (1 << (x % 8)))
688
 
                {
689
 
                    *cp++ = fc;
690
 
                    PUT_PIXEL ('X');
691
 
                }
692
 
                else
693
 
                {
694
 
                    *cp++ = bc;
695
 
                    PUT_PIXEL ('*');
696
 
                }
697
 
            }
698
 
            else
699
 
            {
700
 
                /* transparent, set AND mask bit */
701
 
                m[x / 8] |= 1 << (7 - (x % 8));
702
 
                /* don't change the screen pixel */
703
 
                *cp++ = 0;
704
 
                PUT_PIXEL (' ');
705
 
            }
706
 
        }
707
 
        PUT_PIXEL ('\n');
708
 
    }
709
 
 
710
 
    reqp = (VMMDevReqMousePointer *) p;
711
 
    reqp->width  = w;
712
 
    reqp->height = h;
713
 
    reqp->xHot   = bitsp->xhot;
714
 
    reqp->yHot   = bitsp->yhot;
715
 
    reqp->fFlags = VBOX_MOUSE_POINTER_SHAPE;
716
 
    reqp->header.size = size;
717
 
 
718
 
#ifdef DEBUG_X
719
 
    ErrorF ("shape = %p\n", p);
720
 
    vbox_show_shape (w, h, bc, c);
721
 
#endif
722
 
 
723
 
    return p;
724
 
}
725
 
 
726
 
#ifdef ARGB_CURSOR
727
 
static Bool vbox_use_hw_cursor_argb (ScreenPtr pScreen, CursorPtr pCurs)
728
 
{
729
 
    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
730
 
    Bool rc = TRUE;
731
 
 
732
 
    if (!vbox_host_uses_hwcursor(pScrn))
733
 
        rc = FALSE;
734
 
    if (   rc
735
 
        && (   (pCurs->bits->height > VBOX_MAX_CURSOR_HEIGHT)
736
 
            || (pCurs->bits->width > VBOX_MAX_CURSOR_WIDTH)
737
 
            || (pScrn->bitsPerPixel <= 8)
738
 
           )
739
 
       )
740
 
        rc = FALSE;
741
 
    return rc;
742
 
}
743
 
 
744
 
static void vbox_load_cursor_argb (ScrnInfoPtr pScrn, CursorPtr pCurs)
745
 
{
746
 
    VBOXPtr pVBox;
747
 
    VMMDevReqMousePointer *reqp;
748
 
    CursorBitsPtr bitsp;
749
 
    unsigned short w, h;
750
 
    unsigned short cx, cy;
751
 
    unsigned char *pm;
752
 
    CARD32 *pc;
753
 
    size_t size, mask_size;
754
 
    CARD8 *p;
755
 
    int scrnIndex;
756
 
 
757
 
    pVBox = pScrn->driverPrivate;
758
 
    bitsp = pCurs->bits;
759
 
    w     = bitsp->width;
760
 
    h     = bitsp->height;
761
 
    scrnIndex = pScrn->scrnIndex;
762
 
 
763
 
    /* Mask must be generated for alpha cursors, that is required by VBox. */
764
 
    /* @note: (michael) the next struct must be 32bit aligned. */
765
 
    mask_size  = ((w + 7) / 8 * h + 3) & ~3;
766
 
 
767
 
    if (!w || !h || w > VBOX_MAX_CURSOR_WIDTH || h > VBOX_MAX_CURSOR_HEIGHT)
768
 
        RETERROR(scrnIndex, ,
769
 
                 "Error invalid cursor dimensions %dx%d\n", w, h);
770
 
 
771
 
    if ((bitsp->xhot > w) || (bitsp->yhot > h))
772
 
        RETERROR(scrnIndex, ,
773
 
            "Error invalid cursor hotspot location %dx%d (max %dx%d)\n",
774
 
            bitsp->xhot, bitsp->yhot, w, h);
775
 
 
776
 
    size = w * h * 4 + pVBox->pointerHeaderSize + mask_size;
777
 
    p = xcalloc (1, size);
778
 
    if (!p)
779
 
        RETERROR(scrnIndex, ,
780
 
            "Error failed to alloc %lu bytes for cursor\n",
781
 
            (unsigned long) size);
782
 
 
783
 
    reqp = (VMMDevReqMousePointer *) p;
784
 
    *reqp = *pVBox->reqp;
785
 
    reqp->width  = w;
786
 
    reqp->height = h;
787
 
    reqp->xHot   = bitsp->xhot;
788
 
    reqp->yHot   = bitsp->yhot;
789
 
    reqp->fFlags = VBOX_MOUSE_POINTER_SHAPE | VBOX_MOUSE_POINTER_ALPHA;
790
 
    reqp->header.size = size;
791
 
 
792
 
    memcpy (p + offsetof (VMMDevReqMousePointer, pointerData) + mask_size,
793
 
            bitsp->argb, w * h * 4);
794
 
 
795
 
    /** @ */
796
 
    /* Emulate the AND mask. */
797
 
    pm = p + offsetof (VMMDevReqMousePointer, pointerData);
798
 
    pc = bitsp->argb;
799
 
 
800
 
    /* Init AND mask to 1 */
801
 
    memset (pm, 0xFF, mask_size);
802
 
 
803
 
    /**
804
 
     * The additions driver must provide the AND mask for alpha cursors. The host frontend
805
 
     * which can handle alpha channel, will ignore the AND mask and draw an alpha cursor.
806
 
     * But if the host does not support ARGB, then it simply uses the AND mask and the color
807
 
     * data to draw a normal color cursor.
808
 
     */
809
 
    for (cy = 0; cy < h; cy++)
810
 
    {
811
 
        unsigned char bitmask = 0x80;
812
 
 
813
 
        for (cx = 0; cx < w; cx++, bitmask >>= 1)
814
 
        {
815
 
            if (bitmask == 0)
816
 
                bitmask = 0x80;
817
 
 
818
 
            if (pc[cx] >= 0xF0000000)
819
 
                pm[cx / 8] &= ~bitmask;
820
 
        }
821
 
 
822
 
        /* Point to next source and dest scans */
823
 
        pc += w;
824
 
        pm += (w + 7) / 8;
825
 
    }
826
 
 
827
 
    if (vbox_vmmcall (pScrn, pVBox, &reqp->header) != TRUE)
828
 
        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
829
 
                   "Request to virtual machine failed "
830
 
                   "- unable to set the virtual mouse pointer ARGB cursor image.\n");
831
 
 
832
 
    xfree (p);
833
 
}
834
 
#endif
835
 
 
836
 
Bool vbox_cursor_init (ScreenPtr pScreen)
837
 
{
838
 
    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
839
 
    VBOXPtr pVBox = pScrn->driverPrivate;
840
 
    xf86CursorInfoPtr pCurs;
841
 
    Bool rc;
842
 
 
843
 
    pVBox->pCurs = pCurs = xf86CreateCursorInfoRec ();
844
 
    if (!pCurs)
845
 
        RETERROR(pScrn->scrnIndex, FALSE,
846
 
                 "Failed to create X Window cursor information structures for virtual mouse.\n");
847
 
 
848
 
    pCurs->MaxWidth = VBOX_MAX_CURSOR_WIDTH;
849
 
    pCurs->MaxHeight = VBOX_MAX_CURSOR_HEIGHT;
850
 
    pCurs->Flags = HARDWARE_CURSOR_TRUECOLOR_AT_8BPP
851
 
                 | HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1
852
 
                 | HARDWARE_CURSOR_BIT_ORDER_MSBFIRST;
853
 
 
854
 
    pCurs->SetCursorColors   = vbox_set_cursor_colors;
855
 
    pCurs->SetCursorPosition = vbox_set_cursor_position;
856
 
    pCurs->LoadCursorImage   = vbox_load_cursor_image;
857
 
    pCurs->HideCursor        = vbox_hide_cursor;
858
 
    pCurs->ShowCursor        = vbox_show_cursor;
859
 
    pCurs->UseHWCursor       = vbox_use_hw_cursor;
860
 
    pCurs->RealizeCursor     = vbox_realize_cursor;
861
 
 
862
 
#ifdef ARGB_CURSOR
863
 
    pCurs->UseHWCursorARGB   = vbox_use_hw_cursor_argb;
864
 
    pCurs->LoadCursorARGB    = vbox_load_cursor_argb;
865
 
#endif
866
 
 
867
 
    /* Hide the host cursor before we initialise if we wish to use a
868
 
     * software cursor. */
869
 
    if (pVBox->forceSWCursor)
870
 
        vbox_vmm_hide_cursor(pScrn, pVBox);
871
 
    rc = xf86InitCursor (pScreen, pCurs);
872
 
    if (rc == TRUE)
873
 
        return TRUE;
874
 
    RETERROR(pScrn->scrnIndex, FALSE, "Failed to enable mouse pointer integration.\n");
875
 
}
876
 
 
877
 
/**
878
 
 * Inform VBox that we will supply it with dirty rectangle information
879
 
 * and install the dirty rectangle handler.
880
 
 *
881
 
 * @returns TRUE for success, FALSE for failure
882
 
 * @param   pScreen Pointer to a structure describing the X screen in use
883
 
 */
884
 
Bool
885
 
vboxEnableVbva(ScrnInfoPtr pScrn)
886
 
{
887
 
    int scrnIndex = pScrn->scrnIndex;
888
 
    VBOXPtr pVBox = pScrn->driverPrivate;
889
 
 
890
 
    if (pVBox->useVbva != TRUE)
891
 
        return FALSE;
892
 
    pVBox->reqe->u32Enable = 1;
893
 
    pVBox->reqe->cbRingBuffer = VBVA_RING_BUFFER_SIZE;
894
 
    pVBox->reqe->fu32Status = 0;
895
 
    if (vbox_vmmcall(pScrn, pVBox, (VMMDevRequestHeader *) pVBox->reqe)
896
 
        != TRUE)
897
 
    {
898
 
        /* Request not accepted - disable for old hosts. */
899
 
        xf86DrvMsg(scrnIndex, X_ERROR,
900
 
                   "Unable to activate VirtualBox graphics acceleration "
901
 
                   "- the request to the virtual machine failed.  "
902
 
                   "You may be running an old version of VirtualBox.\n");
903
 
        pVBox->useVbva = FALSE;
904
 
        pVBox->reqe->u32Enable = 0;
905
 
        pVBox->reqe->cbRingBuffer = VBVA_RING_BUFFER_SIZE;
906
 
        pVBox->reqe->fu32Status = 0;
907
 
        vbox_vmmcall(pScrn, pVBox, (VMMDevRequestHeader *) pVBox->reqe);
908
 
        return FALSE;
909
 
    }
910
 
    return TRUE;
911
 
}
912
 
 
913
 
 
914
 
/**
915
 
 * Inform VBox that we will stop supplying it with dirty rectangle
916
 
 * information. This function is intended to be called when an X
917
 
 * virtual terminal is disabled, or the X server is terminated.
918
 
 *
919
 
 * @returns TRUE for success, FALSE for failure
920
 
 * @param   pScreen Pointer to a structure describing the X screen in use
921
 
 */
922
 
Bool
923
 
vboxDisableVbva(ScrnInfoPtr pScrn)
924
 
{
925
 
    int scrnIndex = pScrn->scrnIndex;
926
 
    VBOXPtr pVBox = pScrn->driverPrivate;
927
 
 
928
 
    if (pVBox->useVbva != TRUE)  /* Ths function should not have been called */
929
 
        return FALSE;
930
 
    pVBox->reqe->u32Enable = 0;
931
 
    pVBox->reqe->cbRingBuffer = VBVA_RING_BUFFER_SIZE;
932
 
    pVBox->reqe->fu32Status = 0;
933
 
    if (vbox_vmmcall(pScrn, pVBox, (VMMDevRequestHeader *) pVBox->reqe)
934
 
        != TRUE)
935
 
        xf86DrvMsg(scrnIndex, X_ERROR,
936
 
            "Unable to disable VirtualBox graphics acceleration "
937
 
            "- the request to the virtual machine failed.\n");
938
 
    else
939
 
        memset(pVBox->pVbvaMemory, 0, sizeof(VBVAMEMORY));
940
 
    return TRUE;
941
 
}
942
 
 
943
 
 
944
 
/**
945
 
 * Query the last display change request.
946
 
 *
947
 
 * @returns iprt status value
948
 
 * @param xres     where to store the horizontal pixel resolution requested
949
 
 *                 (0 = do not change)
950
 
 * @param yres     where to store the vertical pixel resolution requested
951
 
 *                 (0 = do not change)
952
 
 * @param bpp      where to store the bits per pixel requeste
953
 
 *                 (0 = do not change)
954
 
 * @param  display Where to store the display number the request was for -
955
 
 *                 0 for the primary display, 1 for the first secondary, etc.
956
 
 */
957
 
Bool
958
 
vboxGetDisplayChangeRequest(ScrnInfoPtr pScrn, uint32_t *pX, uint32_t *pY,
959
 
                            uint32_t *pBpp, uint32_t *pDisplay)
960
 
{
961
 
    int rc, scrnIndex = pScrn->scrnIndex;
962
 
    VBOXPtr pVBox = pScrn->driverPrivate;
963
 
 
964
 
    VMMDevDisplayChangeRequest2 Req = { { 0 } };
965
 
    vmmdevInitRequest(&Req.header, VMMDevReq_GetDisplayChangeRequest2);
966
 
    rc = vbox_vmmcall(pScrn, pVBox, &Req.header);
967
 
    if (RT_SUCCESS(rc))
968
 
    {
969
 
        *pX = Req.xres;
970
 
        *pY = Req.yres;
971
 
        *pBpp = Req.bpp;
972
 
        *pDisplay = Req.display;
973
 
        return TRUE;
974
 
    }
975
 
    xf86DrvMsg(scrnIndex, X_ERROR,
976
 
               "Failed to request the last resolution requested from the guest, rc=%d.\n",
977
 
               rc);
978
 
    return FALSE;
979
 
}