Exemple #1
0
/**
 * Get most recent video mode hints.
 * @param  pCtx      the context containing the heap to use
 * @param  cScreens  the number of screens to query hints for, starting at 0.
 * @param  pHints    array of VBVAMODEHINT structures for receiving the hints.
 * @returns  iprt status code
 * @returns  VERR_NO_MEMORY      HGSMI heap allocation failed.
 * @returns  VERR_NOT_SUPPORTED  Host does not support this command.
 */
RTDECL(int) VBoxHGSMIGetModeHints(PHGSMIGUESTCOMMANDCONTEXT pCtx,
                                  unsigned cScreens, VBVAMODEHINT *paHints)
{
    int rc;
    AssertPtrReturn(paHints, VERR_INVALID_POINTER);
    void *p = VBoxHGSMIBufferAlloc(pCtx,   sizeof(VBVAQUERYMODEHINTS)
                                         + cScreens * sizeof(VBVAMODEHINT),
                                   HGSMI_CH_VBVA, VBVA_QUERY_MODE_HINTS);
    if (!p)
    {
        LogFunc(("HGSMIHeapAlloc failed\n"));
        return VERR_NO_MEMORY;
    }
    else
    {
        VBVAQUERYMODEHINTS *pQuery   = (VBVAQUERYMODEHINTS *)p;

        pQuery->cHintsQueried        = cScreens;
        pQuery->cbHintStructureGuest = sizeof(VBVAMODEHINT);
        pQuery->rc                   = VERR_NOT_SUPPORTED;

        VBoxHGSMIBufferSubmit(pCtx, p);
        rc = pQuery->rc;
        if (RT_SUCCESS(rc))
            memcpy(paHints, ((uint8_t *)p) + sizeof(VBVAQUERYMODEHINTS),
                   cScreens * sizeof(VBVAMODEHINT));

        VBoxHGSMIBufferFree(pCtx, p);
    }
    return rc;
}
/**
 * Query the host for an HGSMI configuration parameter via an HGSMI command.
 * @returns iprt status value
 * @param  pCtx      the context containing the heap used
 * @param  u32Index  the index of the parameter to query,
 *                   @see VBVACONF32::u32Index
 * @param  pulValue  where to store the value of the parameter on success
 */
RTDECL(int) VBoxQueryConfHGSMI(PHGSMIGUESTCOMMANDCONTEXT pCtx,
                               uint32_t u32Index, uint32_t *pulValue)
{
    int rc = VINF_SUCCESS;
    VBVACONF32 *p;
    LogFunc(("u32Index = %d\n", u32Index));

    /* Allocate the IO buffer. */
    p = (VBVACONF32 *)VBoxHGSMIBufferAlloc(pCtx,
                                     sizeof(VBVACONF32), HGSMI_CH_VBVA,
                                     VBVA_QUERY_CONF32);
    if (p)
    {
        /* Prepare data to be sent to the host. */
        p->u32Index = u32Index;
        p->u32Value = 0;
        rc = VBoxHGSMIBufferSubmit(pCtx, p);
        if (RT_SUCCESS(rc))
        {
            *pulValue = p->u32Value;
            LogFunc(("u32Value = %d\n", p->u32Value));
        }
        /* Free the IO buffer. */
        VBoxHGSMIBufferFree(pCtx, p);
    }
    else
        rc = VERR_NO_MEMORY;
    LogFunc(("rc = %d\n", rc));
    return rc;
}
Exemple #3
0
void VBoxCmdVbvaSubmitUnlock(PVBOXMP_DEVEXT pDevExt, VBOXCMDVBVA *pVbva, VBOXCMDVBVA_HDR* pCmd, uint32_t u32FenceID)
{
    if (u32FenceID)
        pVbva->u32FenceSubmitted = u32FenceID;
    else
        WARN(("no cmd fence specified"));

    pCmd->u8State = VBOXCMDVBVA_STATE_SUBMITTED;

    pCmd->u2.u32FenceID = u32FenceID;

    VBoxVBVAExBufferEndUpdate(&pVbva->Vbva);

    if (!VBoxVBVAExIsProcessing(&pVbva->Vbva))
    {
        /* Issue the submit command. */
        HGSMIGUESTCOMMANDCONTEXT *pCtx = &VBoxCommonFromDeviceExt(pDevExt)->guestCtx;
        VBVACMDVBVASUBMIT *pSubmit = (VBVACMDVBVASUBMIT*)VBoxHGSMIBufferAlloc(pCtx,
                                       sizeof (VBVACMDVBVASUBMIT),
                                       HGSMI_CH_VBVA,
                                       VBVA_CMDVBVA_SUBMIT);
        if (!pSubmit)
        {
            WARN(("VBoxHGSMIBufferAlloc failed\n"));
            return;
        }

        pSubmit->u32Reserved = 0;

        VBoxHGSMIBufferSubmit(pCtx, pSubmit);

        VBoxHGSMIBufferFree(pCtx, pSubmit);
    }
}
/** Notify the host of HGSMI-related guest capabilities via an HGSMI command.
 */
static int vboxHGSMISendCapsInfo(PHGSMIGUESTCOMMANDCONTEXT pCtx,
                                 uint32_t fCaps)
{
    VBVACAPS *pCaps;
    int rc = VINF_SUCCESS;

    /* Allocate the IO buffer. */
    pCaps = (VBVACAPS *)VBoxHGSMIBufferAlloc(pCtx,
                                       sizeof(VBVACAPS), HGSMI_CH_VBVA,
                                       VBVA_INFO_CAPS);

    if (pCaps)
    {
        /* Prepare data to be sent to the host. */
        pCaps->rc    = VERR_NOT_IMPLEMENTED;
        pCaps->fCaps = fCaps;
        rc = VBoxHGSMIBufferSubmit(pCtx, pCaps);
        if (RT_SUCCESS(rc))
        {
            AssertRC(pCaps->rc);
            rc = pCaps->rc;
        }
        /* Free the IO buffer. */
        VBoxHGSMIBufferFree(pCtx, pCaps);
    }
    else
        rc = VERR_NO_MEMORY;
    return rc;
}
Exemple #5
0
/**
 * Report the guest cursor position.  The host may wish to use this information
 * to re-position its own cursor (though this is currently unlikely).  The
 * current host cursor position is returned.
 * @param  pCtx             The context containing the heap used.
 * @param  fReportPosition  Are we reporting a position?
 * @param  x                Guest cursor X position.
 * @param  y                Guest cursor Y position.
 * @param  pxHost           Host cursor X position is stored here.  Optional.
 * @param  pyHost           Host cursor Y position is stored here.  Optional.
 * @returns  iprt status code.
 * @returns  VERR_NO_MEMORY      HGSMI heap allocation failed.
 */
RTDECL(int) VBoxHGSMICursorPosition(PHGSMIGUESTCOMMANDCONTEXT pCtx, bool fReportPosition, uint32_t x, uint32_t y,
                                    uint32_t *pxHost, uint32_t *pyHost)
{
    int rc = VINF_SUCCESS;
    VBVACURSORPOSITION *p;
    Log(("%s: x=%u, y=%u\n", __PRETTY_FUNCTION__, (unsigned)x, (unsigned)y));

    /* Allocate the IO buffer. */
    p = (VBVACURSORPOSITION *)VBoxHGSMIBufferAlloc(pCtx, sizeof(VBVACURSORPOSITION), HGSMI_CH_VBVA, VBVA_CURSOR_POSITION);
    if (p)
    {
        /* Prepare data to be sent to the host. */
        p->fReportPosition = fReportPosition ? 1 : 0;
        p->x = x;
        p->y = y;
        rc = VBoxHGSMIBufferSubmit(pCtx, p);
        if (RT_SUCCESS(rc))
        {
            if (pxHost)
                *pxHost = p->x;
            if (pyHost)
                *pyHost = p->y;
            Log(("%s: return: x=%u, y=%u\n", __PRETTY_FUNCTION__, (unsigned)x, (unsigned)y));
        }
        /* Free the IO buffer. */
        VBoxHGSMIBufferFree(pCtx, p);
    }
    else
        rc = VERR_NO_MEMORY;
    LogFunc(("rc = %d\n", rc));
    return rc;
}
static void vboxHwBufferFlush (PVBOXMP_DEVEXT pDevExt, VBOXVBVAINFO *pVbva)
{
    /* Issue the flush command. */
    void *p = VBoxHGSMIBufferAlloc (&VBoxCommonFromDeviceExt(pDevExt)->guestCtx,
                              sizeof (VBVAFLUSH),
                              HGSMI_CH_VBVA,
                              VBVA_FLUSH);
    Assert(p);
    if (!p)
    {
        LOGREL(("HGSMIHeapAlloc failed"));
    }
    else
    {
        VBVAFLUSH *pFlush = (VBVAFLUSH *)p;

        pFlush->u32Reserved = 0;

        VBoxHGSMIBufferSubmit (&VBoxCommonFromDeviceExt(pDevExt)->guestCtx, p);

        VBoxHGSMIBufferFree (&VBoxCommonFromDeviceExt(pDevExt)->guestCtx, p);
    }

    return;
}
Exemple #7
0
static int vbox_set_view(struct drm_crtc *crtc)
{
    struct vbox_crtc   *vbox_crtc = to_vbox_crtc(crtc);
    struct vbox_private *vbox = crtc->dev->dev_private;
    void *p;

    LogFunc(("vboxvideo: %d: vbox_crtc=%p\n", __LINE__, vbox_crtc));
    /* Tell the host about the view.  This design originally targeted the
     * Windows XP driver architecture and assumed that each screen would have
     * a dedicated frame buffer with the command buffer following it, the whole
     * being a "view".  The host works out which screen a command buffer belongs
     * to by checking whether it is in the first view, then whether it is in the
     * second and so on.  The first match wins.  We cheat around this by making
     * the first view be the managed memory plus the first command buffer, the
     * second the same plus the second buffer and so on. */
    p = VBoxHGSMIBufferAlloc(&vbox->Ctx, sizeof(VBVAINFOVIEW), HGSMI_CH_VBVA,
                             VBVA_INFO_VIEW);
    if (p)
    {
        VBVAINFOVIEW *pInfo = (VBVAINFOVIEW *)p;
        pInfo->u32ViewIndex = vbox_crtc->crtc_id;
        pInfo->u32ViewOffset = vbox_crtc->offFB;
        pInfo->u32ViewSize =   vbox->vram_size - vbox_crtc->offFB
                             + vbox_crtc->crtc_id * VBVA_MIN_BUFFER_SIZE;
        pInfo->u32MaxScreenSize = vbox->vram_size - vbox_crtc->offFB;
        VBoxHGSMIBufferSubmit(&vbox->Ctx, p);
        VBoxHGSMIBufferFree(&vbox->Ctx, p);
    }
    else
        return -ENOMEM;
    LogFunc(("vboxvideo: %d: p=%p\n", __LINE__, p));
    return 0;
}
Exemple #8
0
/** Report the rectangle relative to which absolute pointer events should be
 *  expressed.  This information remains valid until the next VBVA resize event
 *  for any screen, at which time it is reset to the bounding rectangle of all
 *  virtual screens.
 * @param  pCtx      The context containing the heap to use.
 * @param  cOriginX  Upper left X co-ordinate relative to the first screen.
 * @param  cOriginY  Upper left Y co-ordinate relative to the first screen.
 * @param  cWidth    Rectangle width.
 * @param  cHeight   Rectangle height.
 * @returns  iprt status code.
 * @returns  VERR_NO_MEMORY      HGSMI heap allocation failed.
 */
RTDECL(int)      VBoxHGSMIUpdateInputMapping(PHGSMIGUESTCOMMANDCONTEXT pCtx, int32_t  cOriginX, int32_t  cOriginY,
                                             uint32_t cWidth, uint32_t cHeight)
{
    int rc = VINF_SUCCESS;
    VBVAREPORTINPUTMAPPING *p;
    Log(("%s: cOriginX=%d, cOriginY=%d, cWidth=%u, cHeight=%u\n", __PRETTY_FUNCTION__, (int)cOriginX, (int)cOriginX,
         (unsigned)cWidth, (unsigned)cHeight));

    /* Allocate the IO buffer. */
    p = (VBVAREPORTINPUTMAPPING *)VBoxHGSMIBufferAlloc(pCtx, sizeof(VBVAREPORTINPUTMAPPING), HGSMI_CH_VBVA,
                                                       VBVA_REPORT_INPUT_MAPPING);
    if (p)
    {
        /* Prepare data to be sent to the host. */
        p->x  = cOriginX;
        p->y  = cOriginY;
        p->cx = cWidth;
        p->cy = cHeight;
        rc = VBoxHGSMIBufferSubmit(pCtx, p);
        /* Free the IO buffer. */
        VBoxHGSMIBufferFree(pCtx, p);
    }
    else
        rc = VERR_NO_MEMORY;
    LogFunc(("rc = %d\n", rc));
    return rc;
}
Exemple #9
0
DECLINLINE(void) vbvaVhwaCommandRelease(PVBOXMP_DEVEXT pDevExt, VBOXVHWACMD* pCmd)
{
    uint32_t cRefs = ASMAtomicDecU32(&pCmd->cRefs);
    Assert(cRefs < UINT32_MAX / 2);
    if(!cRefs)
    {
        VBoxHGSMIBufferFree(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx, pCmd);
    }
}
static bool vboxVBVAInformHost(PVBVABUFFERCONTEXT pCtx,
                               PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx,
                               int32_t cScreen, bool bEnable)
{
    bool bRc = false;

#if 0  /* All callers check this */
    if (ppdev->bHGSMISupported)
#endif
    {
        void *p = VBoxHGSMIBufferAlloc(pHGSMICtx,
                                       sizeof (VBVAENABLE_EX),
                                       HGSMI_CH_VBVA,
                                       VBVA_ENABLE);
        if (!p)
        {
            LogFunc(("HGSMIHeapAlloc failed\n"));
        }
        else
        {
            VBVAENABLE_EX *pEnable = (VBVAENABLE_EX *)p;

            pEnable->Base.u32Flags  = bEnable? VBVA_F_ENABLE: VBVA_F_DISABLE;
            pEnable->Base.u32Offset = pCtx->offVRAMBuffer;
            pEnable->Base.i32Result = VERR_NOT_SUPPORTED;
            if (cScreen >= 0)
            {
                pEnable->Base.u32Flags |= VBVA_F_EXTENDED | VBVA_F_ABSOFFSET;
                pEnable->u32ScreenId    = cScreen;
            }

            VBoxHGSMIBufferSubmit(pHGSMICtx, p);

            if (bEnable)
            {
                bRc = RT_SUCCESS(pEnable->Base.i32Result);
            }
            else
            {
                bRc = true;
            }

            VBoxHGSMIBufferFree(pHGSMICtx, p);
        }
    }

    return bRc;
}
/**
 * Tell the host about how VRAM is divided up between each screen via an HGSMI
 * command.  It is acceptable to specifiy identical data for each screen if
 * they share a single framebuffer.
 *
 * @returns iprt status code, either VERR_NO_MEMORY or the status returned by
 *          @a pfnFill
 * @todo  What was I thinking of with that callback function?  It
 *        would be much simpler to just pass in a structure in normal
 *        memory and copy it.
 * @param  pCtx      the context containing the heap to use
 * @param  u32Count  the number of screens we are activating
 * @param  pfnFill   a callback which initialises the VBVAINFOVIEW structures
 *                   for all screens
 * @param  pvData    context data for @a pfnFill
 */
RTDECL(int) VBoxHGSMISendViewInfo(PHGSMIGUESTCOMMANDCONTEXT pCtx,
                                  uint32_t u32Count,
                                  PFNHGSMIFILLVIEWINFO pfnFill,
                                  void *pvData)
{
    int rc;
    /* Issue the screen info command. */
    void *p = VBoxHGSMIBufferAlloc(pCtx, sizeof(VBVAINFOVIEW) * u32Count,
                                   HGSMI_CH_VBVA, VBVA_INFO_VIEW);
    if (p)
    {
        VBVAINFOVIEW *pInfo = (VBVAINFOVIEW *)p;
        rc = pfnFill(pvData, pInfo, u32Count);
        if (RT_SUCCESS(rc))
            VBoxHGSMIBufferSubmit (pCtx, p);
        VBoxHGSMIBufferFree(pCtx, p);
    }
    else
        rc = VERR_NO_MEMORY;
    return rc;
}
Exemple #12
0
static int vboxCmdVbvaFlush(PVBOXMP_DEVEXT pDevExt, HGSMIGUESTCOMMANDCONTEXT *pCtx, bool fBufferOverflow)
{
    /* Issue the flush command. */
    VBVACMDVBVAFLUSH *pFlush = (VBVACMDVBVAFLUSH*)VBoxHGSMIBufferAlloc(pCtx,
                                   sizeof (VBVACMDVBVAFLUSH),
                                   HGSMI_CH_VBVA,
                                   VBVA_CMDVBVA_FLUSH);
    if (!pFlush)
    {
        WARN(("VBoxHGSMIBufferAlloc failed\n"));
        return VERR_OUT_OF_RESOURCES;
    }

    pFlush->u32Flags = fBufferOverflow ?  VBVACMDVBVAFLUSH_F_GUEST_BUFFER_OVERFLOW : 0;

    VBoxHGSMIBufferSubmit(pCtx, pFlush);

    VBoxHGSMIBufferFree(pCtx, pFlush);

    return VINF_SUCCESS;
}
/**
 * Set a video mode via an HGSMI request.  The views must have been
 * initialised first using @a VBoxHGSMISendViewInfo and if the mode is being
 * set on the first display then it must be set first using registers.
 * @param  cDisplay  the screen number
 * @param  cOriginX  the horizontal displacement relative to the first screen
 * @param  cOriginY  the vertical displacement relative to the first screen
 * @param  offStart  the offset of the visible area of the framebuffer
 *                   relative to the framebuffer start
 * @param  cbPitch   the offset in bytes between the starts of two adjecent
 *                   scan lines in video RAM
 * @param  cWidth    the mode width
 * @param  cHeight   the mode height
 * @param  cBPP      the colour depth of the mode
 */
RTDECL(void) VBoxHGSMIProcessDisplayInfo(PHGSMIGUESTCOMMANDCONTEXT pCtx,
                                         uint32_t cDisplay,
                                         int32_t  cOriginX,
                                         int32_t  cOriginY,
                                         uint32_t offStart,
                                         uint32_t cbPitch,
                                         uint32_t cWidth,
                                         uint32_t cHeight,
                                         uint16_t cBPP,
                                         uint16_t fFlags)
{
    /* Issue the screen info command. */
    void *p = VBoxHGSMIBufferAlloc(pCtx,
                                   sizeof (VBVAINFOSCREEN),
                                   HGSMI_CH_VBVA,
                                   VBVA_INFO_SCREEN);
    if (!p)
    {
        LogFunc(("HGSMIHeapAlloc failed\n"));
    }
    else
    {
        VBVAINFOSCREEN *pScreen = (VBVAINFOSCREEN *)p;

        pScreen->u32ViewIndex    = cDisplay;
        pScreen->i32OriginX      = cOriginX;
        pScreen->i32OriginY      = cOriginY;
        pScreen->u32StartOffset  = offStart;
        pScreen->u32LineSize     = cbPitch;
        pScreen->u32Width        = cWidth;
        pScreen->u32Height       = cHeight;
        pScreen->u16BitsPerPixel = cBPP;
        pScreen->u16Flags        = fFlags;

        VBoxHGSMIBufferSubmit(pCtx, p);

        VBoxHGSMIBufferFree(pCtx, p);
    }
}
static int vboxVBVAInformHost (PVBOXMP_DEVEXT pDevExt, VBOXVBVAINFO * pVbva, BOOL bEnable)
{
    int rc = VERR_NO_MEMORY;
    void *p = VBoxHGSMIBufferAlloc (&VBoxCommonFromDeviceExt(pDevExt)->guestCtx,
                                  sizeof (VBVAENABLE_EX),
                                  HGSMI_CH_VBVA,
                                  VBVA_ENABLE);
    Assert(p);
    if (!p)
    {
        LOGREL(("HGSMIHeapAlloc failed"));
        rc = VERR_NO_MEMORY;
    }
    else
    {
        VBVAENABLE_EX *pEnableEx = (VBVAENABLE_EX *)p;
        pEnableEx->u32ScreenId = pVbva->srcId;

        VBVAENABLE *pEnable = &pEnableEx->Base;
        pEnable->u32Flags  = bEnable? VBVA_F_ENABLE: VBVA_F_DISABLE;
        pEnable->u32Flags |= VBVA_F_EXTENDED | VBVA_F_ABSOFFSET;
        pEnable->u32Offset = (uint32_t)pVbva->offVBVA;
        pEnable->i32Result = VERR_NOT_SUPPORTED;

        VBoxHGSMIBufferSubmit (&VBoxCommonFromDeviceExt(pDevExt)->guestCtx, p);

        if (bEnable)
        {
            rc = pEnable->i32Result;
            AssertRC(rc);
        }
        else
            rc = VINF_SUCCESS;

        VBoxHGSMIBufferFree (&VBoxCommonFromDeviceExt(pDevExt)->guestCtx, p);
    }
    return rc;
}
/** Tell the host about the location of the area of VRAM set aside for the host
 * heap. */
static int vboxHGSMIReportHostArea(PHGSMIGUESTCOMMANDCONTEXT pCtx,
                                   uint32_t u32AreaOffset, uint32_t u32AreaSize)
{
    VBVAINFOHEAP *p;
    int rc = VINF_SUCCESS;

    /* Allocate the IO buffer. */
    p = (VBVAINFOHEAP *)VBoxHGSMIBufferAlloc(pCtx,
                                       sizeof (VBVAINFOHEAP), HGSMI_CH_VBVA,
                                       VBVA_INFO_HEAP);
    if (p)
    {
        /* Prepare data to be sent to the host. */
        p->u32HeapOffset = u32AreaOffset;
        p->u32HeapSize   = u32AreaSize;
        rc = VBoxHGSMIBufferSubmit(pCtx, p);
        /* Free the IO buffer. */
        VBoxHGSMIBufferFree(pCtx, p);
    }
    else
        rc = VERR_NO_MEMORY;
    return rc;
}
/** Inform the host of the location of the host flags in VRAM via an HGSMI
 * command. */
static int vboxHGSMIReportFlagsLocation(PHGSMIGUESTCOMMANDCONTEXT pCtx,
                                        HGSMIOFFSET offLocation)
{
    HGSMIBUFFERLOCATION *p;
    int rc = VINF_SUCCESS;

    /* Allocate the IO buffer. */
    p = (HGSMIBUFFERLOCATION *)VBoxHGSMIBufferAlloc(pCtx,
                                              sizeof(HGSMIBUFFERLOCATION),
                                              HGSMI_CH_HGSMI,
                                              HGSMI_CC_HOST_FLAGS_LOCATION);
    if (p)
    {
        /* Prepare data to be sent to the host. */
        p->offLocation = offLocation;
        p->cbLocation  = sizeof(HGSMIHOSTFLAGS);
        rc = VBoxHGSMIBufferSubmit(pCtx, p);
        /* Free the IO buffer. */
        VBoxHGSMIBufferFree(pCtx, p);
    }
    else
        rc = VERR_NO_MEMORY;
    return rc;
}
static void vboxHwBufferFlush(PHGSMIGUESTCOMMANDCONTEXT pCtx)
{
    /* Issue the flush command. */
    void *p = VBoxHGSMIBufferAlloc(pCtx,
                                   sizeof (VBVAFLUSH),
                                   HGSMI_CH_VBVA,
                                   VBVA_FLUSH);
    if (!p)
    {
        LogFunc(("HGSMIHeapAlloc failed\n"));
    }
    else
    {
        VBVAFLUSH *pFlush = (VBVAFLUSH *)p;

        pFlush->u32Reserved = 0;

        VBoxHGSMIBufferSubmit(pCtx, p);

        VBoxHGSMIBufferFree(pCtx, p);
    }

    return;
}
Exemple #18
0
static void VBoxDispVHWACommandFree(PVBOXDISPDEV pDev, VBOXVHWACMD* pCmd)
{
    VBoxHGSMIBufferFree(&pDev->hgsmi.ctx, pCmd);
}
/**
 * Pass the host a new mouse pointer shape via an HGSMI command.
 *
 * @returns  success or failure
 * @param  fFlags    cursor flags, @see VMMDevReqMousePointer::fFlags
 * @param  cHotX     horizontal position of the hot spot
 * @param  cHotY     vertical position of the hot spot
 * @param  cWidth    width in pixels of the cursor
 * @param  cHeight   height in pixels of the cursor
 * @param  pPixels   pixel data, @see VMMDevReqMousePointer for the format
 * @param  cbLength  size in bytes of the pixel data
 */
RTDECL(int)  VBoxHGSMIUpdatePointerShape(PHGSMIGUESTCOMMANDCONTEXT pCtx,
                                         uint32_t fFlags,
                                         uint32_t cHotX,
                                         uint32_t cHotY,
                                         uint32_t cWidth,
                                         uint32_t cHeight,
                                         uint8_t *pPixels,
                                         uint32_t cbLength)
{
    VBVAMOUSEPOINTERSHAPE *p;
    uint32_t cbData = 0;
    int rc = VINF_SUCCESS;

    if (fFlags & VBOX_MOUSE_POINTER_SHAPE)
    {
        /* Size of the pointer data: sizeof (AND mask) + sizeof (XOR_MASK) */
        cbData = ((((cWidth + 7) / 8) * cHeight + 3) & ~3)
                 + cWidth * 4 * cHeight;
        /* If shape is supplied, then always create the pointer visible.
         * See comments in 'vboxUpdatePointerShape'
         */
        fFlags |= VBOX_MOUSE_POINTER_VISIBLE;
    }
    LogFlowFunc(("cbData %d, %dx%d\n", cbData, cWidth, cHeight));
    if (cbData > cbLength)
    {
        LogFunc(("calculated pointer data size is too big (%d bytes, limit %d)\n",
                 cbData, cbLength));
        return VERR_INVALID_PARAMETER;
    }
    /* Allocate the IO buffer. */
    p = (VBVAMOUSEPOINTERSHAPE *)VBoxHGSMIBufferAlloc(pCtx,
                                                  sizeof(VBVAMOUSEPOINTERSHAPE)
                                                + cbData,
                                                HGSMI_CH_VBVA,
                                                VBVA_MOUSE_POINTER_SHAPE);
    if (p)
    {
        /* Prepare data to be sent to the host. */
        /* Will be updated by the host. */
        p->i32Result = VINF_SUCCESS;
        /* We have our custom flags in the field */
        p->fu32Flags = fFlags;
        p->u32HotX   = cHotX;
        p->u32HotY   = cHotY;
        p->u32Width  = cWidth;
        p->u32Height = cHeight;
        if (p->fu32Flags & VBOX_MOUSE_POINTER_SHAPE)
            /* Copy the actual pointer data. */
            memcpy (p->au8Data, pPixels, cbData);
        rc = VBoxHGSMIBufferSubmit(pCtx, p);
        if (RT_SUCCESS(rc))
            rc = p->i32Result;
        /* Free the IO buffer. */
        VBoxHGSMIBufferFree(pCtx, p);
    }
    else
        rc = VERR_NO_MEMORY;
    LogFlowFunc(("rc %d\n", rc));
    return rc;
}