1e07dc26bSmrg/*
2e07dc26bSmrg * Copyright (C) 2006-2017 Oracle Corporation
3e07dc26bSmrg *
4e07dc26bSmrg * Permission is hereby granted, free of charge, to any person obtaining a
5e07dc26bSmrg * copy of this software and associated documentation files (the "Software"),
6e07dc26bSmrg * to deal in the Software without restriction, including without limitation
7e07dc26bSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8e07dc26bSmrg * and/or sell copies of the Software, and to permit persons to whom the
9e07dc26bSmrg * Software is furnished to do so, subject to the following conditions:
10e07dc26bSmrg *
11e07dc26bSmrg * The above copyright notice and this permission notice shall be included in
12e07dc26bSmrg * all copies or substantial portions of the Software.
13e07dc26bSmrg *
14e07dc26bSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15e07dc26bSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16e07dc26bSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17e07dc26bSmrg * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18e07dc26bSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19e07dc26bSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20e07dc26bSmrg * OTHER DEALINGS IN THE SOFTWARE.
21e07dc26bSmrg */
22e07dc26bSmrg
23e07dc26bSmrg#include <VBoxVideoGuest.h>
24e07dc26bSmrg#include <VBoxVideoVBE.h>
25e07dc26bSmrg#include <HGSMIChannels.h>
26e07dc26bSmrg
27e07dc26bSmrg#ifndef VBOX_GUESTR3XF86MOD
28e07dc26bSmrg# include <VBoxVideoIPRT.h>
29e07dc26bSmrg#endif
30e07dc26bSmrg
31e07dc26bSmrg/**
32e07dc26bSmrg * Gets the count of virtual monitors attached to the guest via an HGSMI
33e07dc26bSmrg * command
34e07dc26bSmrg *
35e07dc26bSmrg * @returns the right count on success or 1 on failure.
36e07dc26bSmrg * @param  pCtx  the context containing the heap to use
37e07dc26bSmrg */
38e07dc26bSmrgDECLHIDDEN(uint32_t) VBoxHGSMIGetMonitorCount(PHGSMIGUESTCOMMANDCONTEXT pCtx)
39e07dc26bSmrg{
40e07dc26bSmrg    /* Query the configured number of displays. */
41e07dc26bSmrg    uint32_t cDisplays = 0;
42e07dc26bSmrg    VBoxQueryConfHGSMI(pCtx, VBOX_VBVA_CONF32_MONITOR_COUNT, &cDisplays);
43e07dc26bSmrg    // LogFunc(("cDisplays = %d\n", cDisplays));
44e07dc26bSmrg    if (cDisplays == 0 || cDisplays > VBOX_VIDEO_MAX_SCREENS)
45e07dc26bSmrg        /* Host reported some bad value. Continue in the 1 screen mode. */
46e07dc26bSmrg        cDisplays = 1;
47e07dc26bSmrg    return cDisplays;
48e07dc26bSmrg}
49e07dc26bSmrg
50e07dc26bSmrg
51e07dc26bSmrg/**
52e07dc26bSmrg * Returns the size of the video RAM in bytes.
53e07dc26bSmrg *
54e07dc26bSmrg * @returns the size
55e07dc26bSmrg */
56e07dc26bSmrgDECLHIDDEN(uint32_t) VBoxVideoGetVRAMSize(void)
57e07dc26bSmrg{
58e07dc26bSmrg    /** @note A 32bit read on this port returns the VRAM size. */
59e07dc26bSmrg    return VBVO_PORT_READ_U32(VBE_DISPI_IOPORT_DATA);
60e07dc26bSmrg}
61e07dc26bSmrg
62e07dc26bSmrg
63e07dc26bSmrg/**
64e07dc26bSmrg * Check whether this hardware allows the display width to have non-multiple-
65e07dc26bSmrg * of-eight values.
66e07dc26bSmrg *
67e07dc26bSmrg * @returns true if any width is allowed, false otherwise.
68e07dc26bSmrg */
69e07dc26bSmrgDECLHIDDEN(bool) VBoxVideoAnyWidthAllowed(void)
70e07dc26bSmrg{
71e07dc26bSmrg    unsigned DispiId;
72e07dc26bSmrg    VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
73e07dc26bSmrg    VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_DATA, VBE_DISPI_ID_ANYX);
74e07dc26bSmrg    DispiId = VBVO_PORT_READ_U16(VBE_DISPI_IOPORT_DATA);
75e07dc26bSmrg    return (DispiId == VBE_DISPI_ID_ANYX);
76e07dc26bSmrg}
77e07dc26bSmrg
78e07dc26bSmrg
79e07dc26bSmrg/**
80e07dc26bSmrg * Tell the host about how VRAM is divided up between each screen via an HGSMI
81636c353eSmrg * command.  It is acceptable to specify identical data for each screen if
82e07dc26bSmrg * they share a single framebuffer.
83e07dc26bSmrg *
84e07dc26bSmrg * @returns iprt status code, either VERR_NO_MEMORY or the status returned by
85e07dc26bSmrg *          @a pfnFill
86e07dc26bSmrg * @todo  What was I thinking of with that callback function?  It
87e07dc26bSmrg *        would be much simpler to just pass in a structure in normal
88e07dc26bSmrg *        memory and copy it.
89e07dc26bSmrg * @param  pCtx      the context containing the heap to use
90e07dc26bSmrg * @param  u32Count  the number of screens we are activating
91e07dc26bSmrg * @param  pfnFill   a callback which initialises the VBVAINFOVIEW structures
92e07dc26bSmrg *                   for all screens
93e07dc26bSmrg * @param  pvData    context data for @a pfnFill
94e07dc26bSmrg */
95e07dc26bSmrgDECLHIDDEN(int) VBoxHGSMISendViewInfo(PHGSMIGUESTCOMMANDCONTEXT pCtx,
96e07dc26bSmrg                                      uint32_t u32Count,
97e07dc26bSmrg                                      PFNHGSMIFILLVIEWINFO pfnFill,
98e07dc26bSmrg                                      void *pvData)
99e07dc26bSmrg{
100e07dc26bSmrg    int rc;
101e07dc26bSmrg    /* Issue the screen info command. */
102e07dc26bSmrg    void *p = VBoxHGSMIBufferAlloc(pCtx, sizeof(VBVAINFOVIEW) * u32Count,
103e07dc26bSmrg                                   HGSMI_CH_VBVA, VBVA_INFO_VIEW);
104e07dc26bSmrg    if (p)
105e07dc26bSmrg    {
106e07dc26bSmrg        VBVAINFOVIEW *pInfo = (VBVAINFOVIEW *)p;
107e07dc26bSmrg        rc = pfnFill(pvData, pInfo, u32Count);
108e07dc26bSmrg        if (RT_SUCCESS(rc))
109e07dc26bSmrg            VBoxHGSMIBufferSubmit (pCtx, p);
110e07dc26bSmrg        VBoxHGSMIBufferFree(pCtx, p);
111e07dc26bSmrg    }
112e07dc26bSmrg    else
113e07dc26bSmrg        rc = VERR_NO_MEMORY;
114e07dc26bSmrg    return rc;
115e07dc26bSmrg}
116e07dc26bSmrg
117e07dc26bSmrg
118e07dc26bSmrg/**
119e07dc26bSmrg * Set a video mode using port registers.  This must be done for the first
120e07dc26bSmrg * screen before every HGSMI modeset and also works when HGSM is not enabled.
121e07dc26bSmrg * @param  cWidth      the mode width
122e07dc26bSmrg * @param  cHeight     the mode height
123e07dc26bSmrg * @param  cVirtWidth  the mode pitch
124e07dc26bSmrg * @param  cBPP        the colour depth of the mode
125e07dc26bSmrg * @param  fFlags      flags for the mode.  These will be or-ed with the
126e07dc26bSmrg *                     default _ENABLED flag, so unless you are restoring
127e07dc26bSmrg *                     a saved mode or have special requirements you can pass
128e07dc26bSmrg *                     zero here.
129e07dc26bSmrg * @param  cx          the horizontal panning offset
130e07dc26bSmrg * @param  cy          the vertical panning offset
131e07dc26bSmrg */
132e07dc26bSmrgDECLHIDDEN(void) VBoxVideoSetModeRegisters(uint16_t cWidth, uint16_t cHeight,
133e07dc26bSmrg                                           uint16_t cVirtWidth, uint16_t cBPP,
134e07dc26bSmrg                                           uint16_t fFlags, uint16_t cx,
135e07dc26bSmrg                                           uint16_t cy)
136e07dc26bSmrg{
137e07dc26bSmrg    /* set the mode characteristics */
138e07dc26bSmrg    VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_XRES);
139e07dc26bSmrg    VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_DATA, cWidth);
140e07dc26bSmrg    VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_YRES);
141e07dc26bSmrg    VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_DATA, cHeight);
142e07dc26bSmrg    VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX,
143e07dc26bSmrg                                VBE_DISPI_INDEX_VIRT_WIDTH);
144e07dc26bSmrg    VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_DATA, cVirtWidth);
145e07dc26bSmrg    VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_BPP);
146e07dc26bSmrg    VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_DATA, cBPP);
147e07dc26bSmrg    /* enable the mode */
148e07dc26bSmrg    VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX,
149e07dc26bSmrg                                VBE_DISPI_INDEX_ENABLE);
150e07dc26bSmrg    VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_DATA,
151e07dc26bSmrg                                fFlags | VBE_DISPI_ENABLED);
152e07dc26bSmrg    /* Panning registers */
153e07dc26bSmrg    VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX,
154e07dc26bSmrg                                VBE_DISPI_INDEX_X_OFFSET);
155e07dc26bSmrg    VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_DATA, cx);
156e07dc26bSmrg    VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX,
157e07dc26bSmrg                                VBE_DISPI_INDEX_Y_OFFSET);
158e07dc26bSmrg    VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_DATA, cy);
159e07dc26bSmrg    /** @todo read from the port to see if the mode switch was successful */
160e07dc26bSmrg}
161e07dc26bSmrg
162e07dc26bSmrg
163e07dc26bSmrg/**
164e07dc26bSmrg * Get the video mode for the first screen using the port registers.  All
165e07dc26bSmrg * parameters are optional
166e07dc26bSmrg * @returns  true if the VBE mode returned is active, false if we are in VGA
167e07dc26bSmrg *           mode
168e07dc26bSmrg * @note  If anyone else needs additional register values just extend the
169e07dc26bSmrg *        function with additional parameters and fix any existing callers.
170e07dc26bSmrg * @param  pcWidth      where to store the mode width
171e07dc26bSmrg * @param  pcHeight     where to store the mode height
172e07dc26bSmrg * @param  pcVirtWidth  where to store the mode pitch
173e07dc26bSmrg * @param  pcBPP        where to store the colour depth of the mode
174e07dc26bSmrg * @param  pfFlags      where to store the flags for the mode
175e07dc26bSmrg */
176e07dc26bSmrgDECLHIDDEN(bool) VBoxVideoGetModeRegisters(uint16_t *pcWidth, uint16_t *pcHeight,
177e07dc26bSmrg                                           uint16_t *pcVirtWidth, uint16_t *pcBPP,
178e07dc26bSmrg                                           uint16_t *pfFlags)
179e07dc26bSmrg{
180e07dc26bSmrg    uint16_t fFlags;
181e07dc26bSmrg
182e07dc26bSmrg    VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX,
183e07dc26bSmrg                                VBE_DISPI_INDEX_ENABLE);
184e07dc26bSmrg    fFlags = VBVO_PORT_READ_U16(VBE_DISPI_IOPORT_DATA);
185e07dc26bSmrg    if (pcWidth)
186e07dc26bSmrg    {
187e07dc26bSmrg        VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX,
188e07dc26bSmrg                                    VBE_DISPI_INDEX_XRES);
189e07dc26bSmrg        *pcWidth = VBVO_PORT_READ_U16(VBE_DISPI_IOPORT_DATA);
190e07dc26bSmrg    }
191e07dc26bSmrg    if (pcHeight)
192e07dc26bSmrg    {
193e07dc26bSmrg        VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX,
194e07dc26bSmrg                                    VBE_DISPI_INDEX_YRES);
195e07dc26bSmrg        *pcHeight = VBVO_PORT_READ_U16(VBE_DISPI_IOPORT_DATA);
196e07dc26bSmrg    }
197e07dc26bSmrg    if (pcVirtWidth)
198e07dc26bSmrg    {
199e07dc26bSmrg        VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX,
200e07dc26bSmrg                                    VBE_DISPI_INDEX_VIRT_WIDTH);
201e07dc26bSmrg        *pcVirtWidth = VBVO_PORT_READ_U16(VBE_DISPI_IOPORT_DATA);
202e07dc26bSmrg    }
203e07dc26bSmrg    if (pcBPP)
204e07dc26bSmrg    {
205e07dc26bSmrg        VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX,
206e07dc26bSmrg                                    VBE_DISPI_INDEX_BPP);
207e07dc26bSmrg        *pcBPP = VBVO_PORT_READ_U16(VBE_DISPI_IOPORT_DATA);
208e07dc26bSmrg    }
209e07dc26bSmrg    if (pfFlags)
210e07dc26bSmrg        *pfFlags = fFlags;
211e07dc26bSmrg    return !!(fFlags & VBE_DISPI_ENABLED);
212e07dc26bSmrg}
213e07dc26bSmrg
214e07dc26bSmrg
215e07dc26bSmrg/**
216e07dc26bSmrg * Disable our extended graphics mode and go back to VGA mode.
217e07dc26bSmrg */
218e07dc26bSmrgDECLHIDDEN(void) VBoxVideoDisableVBE(void)
219e07dc26bSmrg{
220e07dc26bSmrg    VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX,
221e07dc26bSmrg                                VBE_DISPI_INDEX_ENABLE);
222e07dc26bSmrg    VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_DATA, 0);
223e07dc26bSmrg}
224e07dc26bSmrg
225e07dc26bSmrg
226e07dc26bSmrg/**
227e07dc26bSmrg * Set a video mode via an HGSMI request.  The views must have been
228e07dc26bSmrg * initialised first using @a VBoxHGSMISendViewInfo and if the mode is being
229e07dc26bSmrg * set on the first display then it must be set first using registers.
230e07dc26bSmrg * @param  pCtx      The context containing the heap to use.
231e07dc26bSmrg * @param  cDisplay  the screen number
232e07dc26bSmrg * @param  cOriginX  the horizontal displacement relative to the first screen
233e07dc26bSmrg * @param  cOriginY  the vertical displacement relative to the first screen
234e07dc26bSmrg * @param  offStart  the offset of the visible area of the framebuffer
235e07dc26bSmrg *                   relative to the framebuffer start
236e07dc26bSmrg * @param  cbPitch   the offset in bytes between the starts of two adjecent
237e07dc26bSmrg *                   scan lines in video RAM
238e07dc26bSmrg * @param  cWidth    the mode width
239e07dc26bSmrg * @param  cHeight   the mode height
240e07dc26bSmrg * @param  cBPP      the colour depth of the mode
241e07dc26bSmrg * @param  fFlags    flags
242e07dc26bSmrg */
243e07dc26bSmrgDECLHIDDEN(void) VBoxHGSMIProcessDisplayInfo(PHGSMIGUESTCOMMANDCONTEXT pCtx,
244e07dc26bSmrg                                             uint32_t cDisplay,
245e07dc26bSmrg                                             int32_t  cOriginX,
246e07dc26bSmrg                                             int32_t  cOriginY,
247e07dc26bSmrg                                             uint32_t offStart,
248e07dc26bSmrg                                             uint32_t cbPitch,
249e07dc26bSmrg                                             uint32_t cWidth,
250e07dc26bSmrg                                             uint32_t cHeight,
251e07dc26bSmrg                                             uint16_t cBPP,
252e07dc26bSmrg                                             uint16_t fFlags)
253e07dc26bSmrg{
254e07dc26bSmrg    /* Issue the screen info command. */
255e07dc26bSmrg    void *p = VBoxHGSMIBufferAlloc(pCtx,
256e07dc26bSmrg                                   sizeof (VBVAINFOSCREEN),
257e07dc26bSmrg                                   HGSMI_CH_VBVA,
258e07dc26bSmrg                                   VBVA_INFO_SCREEN);
259e07dc26bSmrg    if (!p)
260e07dc26bSmrg    {
261e07dc26bSmrg        // LogFunc(("HGSMIHeapAlloc failed\n"));
262e07dc26bSmrg    }
263e07dc26bSmrg    else
264e07dc26bSmrg    {
265e07dc26bSmrg        VBVAINFOSCREEN *pScreen = (VBVAINFOSCREEN *)p;
266e07dc26bSmrg
267e07dc26bSmrg        pScreen->u32ViewIndex    = cDisplay;
268e07dc26bSmrg        pScreen->i32OriginX      = cOriginX;
269e07dc26bSmrg        pScreen->i32OriginY      = cOriginY;
270e07dc26bSmrg        pScreen->u32StartOffset  = offStart;
271e07dc26bSmrg        pScreen->u32LineSize     = cbPitch;
272e07dc26bSmrg        pScreen->u32Width        = cWidth;
273e07dc26bSmrg        pScreen->u32Height       = cHeight;
274e07dc26bSmrg        pScreen->u16BitsPerPixel = cBPP;
275e07dc26bSmrg        pScreen->u16Flags        = fFlags;
276e07dc26bSmrg
277e07dc26bSmrg        VBoxHGSMIBufferSubmit(pCtx, p);
278e07dc26bSmrg
279e07dc26bSmrg        VBoxHGSMIBufferFree(pCtx, p);
280e07dc26bSmrg    }
281e07dc26bSmrg}
282e07dc26bSmrg
283e07dc26bSmrg
284e07dc26bSmrg/** Report the rectangle relative to which absolute pointer events should be
285e07dc26bSmrg *  expressed.  This information remains valid until the next VBVA resize event
286e07dc26bSmrg *  for any screen, at which time it is reset to the bounding rectangle of all
287e07dc26bSmrg *  virtual screens.
288e07dc26bSmrg * @param  pCtx      The context containing the heap to use.
289636c353eSmrg * @param  cOriginX  Upper left X coordinate relative to the first screen.
290636c353eSmrg * @param  cOriginY  Upper left Y coordinate relative to the first screen.
291e07dc26bSmrg * @param  cWidth    Rectangle width.
292e07dc26bSmrg * @param  cHeight   Rectangle height.
293e07dc26bSmrg * @returns  iprt status code.
294e07dc26bSmrg * @returns  VERR_NO_MEMORY      HGSMI heap allocation failed.
295e07dc26bSmrg */
296e07dc26bSmrgDECLHIDDEN(int)      VBoxHGSMIUpdateInputMapping(PHGSMIGUESTCOMMANDCONTEXT pCtx, int32_t  cOriginX, int32_t  cOriginY,
297e07dc26bSmrg                                                 uint32_t cWidth, uint32_t cHeight)
298e07dc26bSmrg{
299e07dc26bSmrg    int rc = VINF_SUCCESS;
300e07dc26bSmrg    VBVAREPORTINPUTMAPPING *p;
301e07dc26bSmrg    // Log(("%s: cOriginX=%d, cOriginY=%d, cWidth=%u, cHeight=%u\n", __PRETTY_FUNCTION__, (int)cOriginX, (int)cOriginX,
302e07dc26bSmrg    //      (unsigned)cWidth, (unsigned)cHeight));
303e07dc26bSmrg
304e07dc26bSmrg    /* Allocate the IO buffer. */
305e07dc26bSmrg    p = (VBVAREPORTINPUTMAPPING *)VBoxHGSMIBufferAlloc(pCtx, sizeof(VBVAREPORTINPUTMAPPING), HGSMI_CH_VBVA,
306e07dc26bSmrg                                                       VBVA_REPORT_INPUT_MAPPING);
307e07dc26bSmrg    if (p)
308e07dc26bSmrg    {
309e07dc26bSmrg        /* Prepare data to be sent to the host. */
310e07dc26bSmrg        p->x  = cOriginX;
311e07dc26bSmrg        p->y  = cOriginY;
312e07dc26bSmrg        p->cx = cWidth;
313e07dc26bSmrg        p->cy = cHeight;
314e07dc26bSmrg        rc = VBoxHGSMIBufferSubmit(pCtx, p);
315e07dc26bSmrg        /* Free the IO buffer. */
316e07dc26bSmrg        VBoxHGSMIBufferFree(pCtx, p);
317e07dc26bSmrg    }
318e07dc26bSmrg    else
319e07dc26bSmrg        rc = VERR_NO_MEMORY;
320e07dc26bSmrg    // LogFunc(("rc = %d\n", rc));
321e07dc26bSmrg    return rc;
322e07dc26bSmrg}
323e07dc26bSmrg
324e07dc26bSmrg
325e07dc26bSmrg/**
326e07dc26bSmrg * Get most recent video mode hints.
327e07dc26bSmrg * @param  pCtx      the context containing the heap to use
328e07dc26bSmrg * @param  cScreens  the number of screens to query hints for, starting at 0.
329e07dc26bSmrg * @param  paHints   array of VBVAMODEHINT structures for receiving the hints.
330e07dc26bSmrg * @returns  iprt status code
331e07dc26bSmrg * @returns  VERR_NO_MEMORY      HGSMI heap allocation failed.
332e07dc26bSmrg * @returns  VERR_NOT_SUPPORTED  Host does not support this command.
333e07dc26bSmrg */
334e07dc26bSmrgDECLHIDDEN(int) VBoxHGSMIGetModeHints(PHGSMIGUESTCOMMANDCONTEXT pCtx,
335e07dc26bSmrg                                      unsigned cScreens, VBVAMODEHINT *paHints)
336e07dc26bSmrg{
337e07dc26bSmrg    int rc;
338e07dc26bSmrg    void *p;
339e07dc26bSmrg
340e07dc26bSmrg    AssertPtr(paHints);
341e07dc26bSmrg    if (!paHints)
342e07dc26bSmrg        return VERR_INVALID_POINTER;
343e07dc26bSmrg
344e07dc26bSmrg    p = VBoxHGSMIBufferAlloc(pCtx, sizeof(VBVAQUERYMODEHINTS)
345e07dc26bSmrg                                       + cScreens * sizeof(VBVAMODEHINT),
346e07dc26bSmrg                             HGSMI_CH_VBVA, VBVA_QUERY_MODE_HINTS);
347e07dc26bSmrg    if (!p)
348e07dc26bSmrg    {
349e07dc26bSmrg        // LogFunc(("HGSMIHeapAlloc failed\n"));
350e07dc26bSmrg        return VERR_NO_MEMORY;
351e07dc26bSmrg    }
352e07dc26bSmrg    else
353e07dc26bSmrg    {
354e07dc26bSmrg        VBVAQUERYMODEHINTS *pQuery   = (VBVAQUERYMODEHINTS *)p;
355e07dc26bSmrg
356e07dc26bSmrg        pQuery->cHintsQueried        = cScreens;
357e07dc26bSmrg        pQuery->cbHintStructureGuest = sizeof(VBVAMODEHINT);
358e07dc26bSmrg        pQuery->rc                   = VERR_NOT_SUPPORTED;
359e07dc26bSmrg
360e07dc26bSmrg        VBoxHGSMIBufferSubmit(pCtx, p);
361e07dc26bSmrg        rc = pQuery->rc;
362e07dc26bSmrg        if (RT_SUCCESS(rc))
363e07dc26bSmrg            memcpy(paHints, ((uint8_t *)p) + sizeof(VBVAQUERYMODEHINTS),
364e07dc26bSmrg                   cScreens * sizeof(VBVAMODEHINT));
365e07dc26bSmrg
366e07dc26bSmrg        VBoxHGSMIBufferFree(pCtx, p);
367e07dc26bSmrg    }
368e07dc26bSmrg    return rc;
369e07dc26bSmrg}
370e07dc26bSmrg
371e07dc26bSmrg
372e07dc26bSmrg/**
373e07dc26bSmrg * Query the supported flags in VBVAINFOSCREEN::u16Flags.
374e07dc26bSmrg *
375e07dc26bSmrg * @returns The mask of VBVA_SCREEN_F_* flags or 0 if host does not support the request.
376e07dc26bSmrg * @param  pCtx  the context containing the heap to use
377e07dc26bSmrg */
378e07dc26bSmrgDECLHIDDEN(uint16_t) VBoxHGSMIGetScreenFlags(PHGSMIGUESTCOMMANDCONTEXT pCtx)
379e07dc26bSmrg{
380e07dc26bSmrg    uint32_t u32Flags = 0;
381e07dc26bSmrg    int rc = VBoxQueryConfHGSMI(pCtx, VBOX_VBVA_CONF32_SCREEN_FLAGS, &u32Flags);
382e07dc26bSmrg    // LogFunc(("u32Flags = 0x%x rc %Rrc\n", u32Flags, rc));
383e07dc26bSmrg    if (RT_FAILURE(rc) || u32Flags > UINT16_MAX)
384e07dc26bSmrg        u32Flags = 0;
385e07dc26bSmrg    return (uint16_t)u32Flags;
386e07dc26bSmrg}
387