VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxVideo/Modesetting.cpp@ 62060

Last change on this file since 62060 was 60138, checked in by vboxsync, 9 years ago

bugref:8087: Additions/x11: support non-root X server: set up mouse multi-screen input mapping correctly in kernel video driver.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.1 KB
Line 
1/* $Id: Modesetting.cpp 60138 2016-03-22 18:50:35Z vboxsync $ */
2/** @file
3 * VirtualBox Video driver, common code - HGSMI initialisation and helper
4 * functions.
5 */
6
7/*
8 * Copyright (C) 2006-2015 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19#include <VBox/VBoxVideoGuest.h>
20#include <VBox/VBoxVideo.h>
21#include <VBox/VBoxGuest.h>
22#include <VBox/Hardware/VBoxVideoVBE.h>
23#include <VBox/VMMDev.h>
24
25#include <iprt/asm.h>
26#include <iprt/log.h>
27
28#ifndef VBOX_GUESTR3XF86MOD
29# include <iprt/string.h>
30#endif
31
32/**
33 * Gets the count of virtual monitors attached to the guest via an HGSMI
34 * command
35 *
36 * @returns the right count on success or 1 on failure.
37 * @param pCtx the context containing the heap to use
38 */
39RTDECL(uint32_t) VBoxHGSMIGetMonitorCount(PHGSMIGUESTCOMMANDCONTEXT pCtx)
40{
41 /* Query the configured number of displays. */
42 uint32_t cDisplays = 0;
43 VBoxQueryConfHGSMI(pCtx, VBOX_VBVA_CONF32_MONITOR_COUNT, &cDisplays);
44 LogFunc(("cDisplays = %d\n", cDisplays));
45 if (cDisplays == 0 || cDisplays > VBOX_VIDEO_MAX_SCREENS)
46 /* Host reported some bad value. Continue in the 1 screen mode. */
47 cDisplays = 1;
48 return cDisplays;
49}
50
51
52/**
53 * Returns the size of the video RAM in bytes.
54 *
55 * @returns the size
56 */
57RTDECL(uint32_t) VBoxVideoGetVRAMSize(void)
58{
59 /** @note A 32bit read on this port returns the VRAM size. */
60 return VBoxVideoCmnPortReadUlong(VBE_DISPI_IOPORT_DATA);
61}
62
63
64/**
65 * Check whether this hardware allows the display width to have non-multiple-
66 * of-eight values.
67 *
68 * @returns true if any width is allowed, false otherwise.
69 */
70RTDECL(bool) VBoxVideoAnyWidthAllowed(void)
71{
72 unsigned DispiId;
73 VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
74 VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_DATA, VBE_DISPI_ID_ANYX);
75 DispiId = VBoxVideoCmnPortReadUshort(VBE_DISPI_IOPORT_DATA);
76 return (DispiId == VBE_DISPI_ID_ANYX);
77}
78
79
80/**
81 * Tell the host about how VRAM is divided up between each screen via an HGSMI
82 * command. It is acceptable to specifiy identical data for each screen if
83 * they share a single framebuffer.
84 *
85 * @returns iprt status code, either VERR_NO_MEMORY or the status returned by
86 * @a pfnFill
87 * @todo What was I thinking of with that callback function? It
88 * would be much simpler to just pass in a structure in normal
89 * memory and copy it.
90 * @param pCtx the context containing the heap to use
91 * @param u32Count the number of screens we are activating
92 * @param pfnFill a callback which initialises the VBVAINFOVIEW structures
93 * for all screens
94 * @param pvData context data for @a pfnFill
95 */
96RTDECL(int) VBoxHGSMISendViewInfo(PHGSMIGUESTCOMMANDCONTEXT pCtx,
97 uint32_t u32Count,
98 PFNHGSMIFILLVIEWINFO pfnFill,
99 void *pvData)
100{
101 int rc;
102 /* Issue the screen info command. */
103 void *p = VBoxHGSMIBufferAlloc(pCtx, sizeof(VBVAINFOVIEW) * u32Count,
104 HGSMI_CH_VBVA, VBVA_INFO_VIEW);
105 if (p)
106 {
107 VBVAINFOVIEW *pInfo = (VBVAINFOVIEW *)p;
108 rc = pfnFill(pvData, pInfo, u32Count);
109 if (RT_SUCCESS(rc))
110 VBoxHGSMIBufferSubmit (pCtx, p);
111 VBoxHGSMIBufferFree(pCtx, p);
112 }
113 else
114 rc = VERR_NO_MEMORY;
115 return rc;
116}
117
118
119/**
120 * Set a video mode using port registers. This must be done for the first
121 * screen before every HGSMI modeset and also works when HGSM is not enabled.
122 * @param cWidth the mode width
123 * @param cHeight the mode height
124 * @param cVirtWidth the mode pitch
125 * @param cBPP the colour depth of the mode
126 * @param fFlags flags for the mode. These will be or-ed with the
127 * default _ENABLED flag, so unless you are restoring
128 * a saved mode or have special requirements you can pass
129 * zero here.
130 * @param cx the horizontal panning offset
131 * @param cy the vertical panning offset
132 */
133RTDECL(void) VBoxVideoSetModeRegisters(uint16_t cWidth, uint16_t cHeight,
134 uint16_t cVirtWidth, uint16_t cBPP,
135 uint16_t fFlags, uint16_t cx,
136 uint16_t cy)
137{
138 /* set the mode characteristics */
139 VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_XRES);
140 VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_DATA, cWidth);
141 VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_YRES);
142 VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_DATA, cHeight);
143 VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_INDEX,
144 VBE_DISPI_INDEX_VIRT_WIDTH);
145 VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_DATA, cVirtWidth);
146 VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_BPP);
147 VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_DATA, cBPP);
148 /* enable the mode */
149 VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_INDEX,
150 VBE_DISPI_INDEX_ENABLE);
151 VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_DATA,
152 fFlags | VBE_DISPI_ENABLED);
153 /* Panning registers */
154 VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_INDEX,
155 VBE_DISPI_INDEX_X_OFFSET);
156 VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_DATA, cx);
157 VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_INDEX,
158 VBE_DISPI_INDEX_Y_OFFSET);
159 VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_DATA, cy);
160 /** @todo read from the port to see if the mode switch was successful */
161}
162
163
164/**
165 * Get the video mode for the first screen using the port registers. All
166 * parameters are optional
167 * @returns true if the VBE mode returned is active, false if we are in VGA
168 * mode
169 * @note If anyone else needs additional register values just extend the
170 * function with additional parameters and fix any existing callers.
171 * @param pcWidth where to store the mode width
172 * @param pcHeight where to store the mode height
173 * @param pcVirtWidth where to store the mode pitch
174 * @param pcBPP where to store the colour depth of the mode
175 * @param pfFlags where to store the flags for the mode
176 */
177RTDECL(bool) VBoxVideoGetModeRegisters(uint16_t *pcWidth, uint16_t *pcHeight,
178 uint16_t *pcVirtWidth, uint16_t *pcBPP,
179 uint16_t *pfFlags)
180{
181 uint16_t fFlags;
182
183 VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_INDEX,
184 VBE_DISPI_INDEX_ENABLE);
185 fFlags = VBoxVideoCmnPortReadUshort(VBE_DISPI_IOPORT_DATA);
186 if (pcWidth)
187 {
188 VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_INDEX,
189 VBE_DISPI_INDEX_XRES);
190 *pcWidth = VBoxVideoCmnPortReadUshort(VBE_DISPI_IOPORT_DATA);
191 }
192 if (pcHeight)
193 {
194 VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_INDEX,
195 VBE_DISPI_INDEX_YRES);
196 *pcHeight = VBoxVideoCmnPortReadUshort(VBE_DISPI_IOPORT_DATA);
197 }
198 if (pcVirtWidth)
199 {
200 VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_INDEX,
201 VBE_DISPI_INDEX_VIRT_WIDTH);
202 *pcVirtWidth = VBoxVideoCmnPortReadUshort(VBE_DISPI_IOPORT_DATA);
203 }
204 if (pcBPP)
205 {
206 VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_INDEX,
207 VBE_DISPI_INDEX_BPP);
208 *pcBPP = VBoxVideoCmnPortReadUshort(VBE_DISPI_IOPORT_DATA);
209 }
210 if (pfFlags)
211 *pfFlags = fFlags;
212 return RT_BOOL(fFlags & VBE_DISPI_ENABLED);
213}
214
215
216/**
217 * Disable our extended graphics mode and go back to VGA mode.
218 */
219RTDECL(void) VBoxVideoDisableVBE(void)
220{
221 VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_INDEX,
222 VBE_DISPI_INDEX_ENABLE);
223 VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_DATA, 0);
224}
225
226
227/**
228 * Set a video mode via an HGSMI request. The views must have been
229 * initialised first using @a VBoxHGSMISendViewInfo and if the mode is being
230 * set on the first display then it must be set first using registers.
231 * @param cDisplay the screen number
232 * @param cOriginX the horizontal displacement relative to the first screen
233 * @param cOriginY the vertical displacement relative to the first screen
234 * @param offStart the offset of the visible area of the framebuffer
235 * relative to the framebuffer start
236 * @param cbPitch the offset in bytes between the starts of two adjecent
237 * scan lines in video RAM
238 * @param cWidth the mode width
239 * @param cHeight the mode height
240 * @param cBPP the colour depth of the mode
241 */
242RTDECL(void) VBoxHGSMIProcessDisplayInfo(PHGSMIGUESTCOMMANDCONTEXT pCtx,
243 uint32_t cDisplay,
244 int32_t cOriginX,
245 int32_t cOriginY,
246 uint32_t offStart,
247 uint32_t cbPitch,
248 uint32_t cWidth,
249 uint32_t cHeight,
250 uint16_t cBPP,
251 uint16_t fFlags)
252{
253 /* Issue the screen info command. */
254 void *p = VBoxHGSMIBufferAlloc(pCtx,
255 sizeof (VBVAINFOSCREEN),
256 HGSMI_CH_VBVA,
257 VBVA_INFO_SCREEN);
258 if (!p)
259 {
260 LogFunc(("HGSMIHeapAlloc failed\n"));
261 }
262 else
263 {
264 VBVAINFOSCREEN *pScreen = (VBVAINFOSCREEN *)p;
265
266 pScreen->u32ViewIndex = cDisplay;
267 pScreen->i32OriginX = cOriginX;
268 pScreen->i32OriginY = cOriginY;
269 pScreen->u32StartOffset = offStart;
270 pScreen->u32LineSize = cbPitch;
271 pScreen->u32Width = cWidth;
272 pScreen->u32Height = cHeight;
273 pScreen->u16BitsPerPixel = cBPP;
274 pScreen->u16Flags = fFlags;
275
276 VBoxHGSMIBufferSubmit(pCtx, p);
277
278 VBoxHGSMIBufferFree(pCtx, p);
279 }
280}
281
282
283/** Report the rectangle relative to which absolute pointer events should be
284 * expressed. This information remains valid until the next VBVA resize event
285 * for any screen, at which time it is reset to the bounding rectangle of all
286 * virtual screens.
287 * @param pCtx The context containing the heap to use.
288 * @param cOriginX Upper left X co-ordinate relative to the first screen.
289 * @param cOriginY Upper left Y co-ordinate relative to the first screen.
290 * @param cWidth Rectangle width.
291 * @param cHeight Rectangle height.
292 * @returns iprt status code.
293 * @returns VERR_NO_MEMORY HGSMI heap allocation failed.
294 */
295RTDECL(int) VBoxHGSMIUpdateInputMapping(PHGSMIGUESTCOMMANDCONTEXT pCtx, int32_t cOriginX, int32_t cOriginY,
296 uint32_t cWidth, uint32_t cHeight)
297{
298 int rc = VINF_SUCCESS;
299 VBVAREPORTINPUTMAPPING *p;
300 Log(("%s: cOriginX=%d, cOriginY=%d, cWidth=%u, cHeight=%u\n", __PRETTY_FUNCTION__, (int)cOriginX, (int)cOriginX,
301 (unsigned)cWidth, (unsigned)cHeight));
302
303 /* Allocate the IO buffer. */
304 p = (VBVAREPORTINPUTMAPPING *)VBoxHGSMIBufferAlloc(pCtx, sizeof(VBVAREPORTINPUTMAPPING), HGSMI_CH_VBVA,
305 VBVA_REPORT_INPUT_MAPPING);
306 if (p)
307 {
308 /* Prepare data to be sent to the host. */
309 p->x = cOriginX;
310 p->y = cOriginY;
311 p->cx = cWidth;
312 p->cy = cHeight;
313 rc = VBoxHGSMIBufferSubmit(pCtx, p);
314 /* Free the IO buffer. */
315 VBoxHGSMIBufferFree(pCtx, p);
316 }
317 else
318 rc = VERR_NO_MEMORY;
319 LogFunc(("rc = %d\n", rc));
320 return rc;
321}
322
323
324/**
325 * Get most recent video mode hints.
326 * @param pCtx the context containing the heap to use
327 * @param cScreens the number of screens to query hints for, starting at 0.
328 * @param pHints array of VBVAMODEHINT structures for receiving the hints.
329 * @returns iprt status code
330 * @returns VERR_NO_MEMORY HGSMI heap allocation failed.
331 * @returns VERR_NOT_SUPPORTED Host does not support this command.
332 */
333RTDECL(int) VBoxHGSMIGetModeHints(PHGSMIGUESTCOMMANDCONTEXT pCtx,
334 unsigned cScreens, VBVAMODEHINT *paHints)
335{
336 int rc;
337 AssertPtrReturn(paHints, VERR_INVALID_POINTER);
338 void *p = VBoxHGSMIBufferAlloc(pCtx, sizeof(VBVAQUERYMODEHINTS)
339 + cScreens * sizeof(VBVAMODEHINT),
340 HGSMI_CH_VBVA, VBVA_QUERY_MODE_HINTS);
341 if (!p)
342 {
343 LogFunc(("HGSMIHeapAlloc failed\n"));
344 return VERR_NO_MEMORY;
345 }
346 else
347 {
348 VBVAQUERYMODEHINTS *pQuery = (VBVAQUERYMODEHINTS *)p;
349
350 pQuery->cHintsQueried = cScreens;
351 pQuery->cbHintStructureGuest = sizeof(VBVAMODEHINT);
352 pQuery->rc = VERR_NOT_SUPPORTED;
353
354 VBoxHGSMIBufferSubmit(pCtx, p);
355 rc = pQuery->rc;
356 if (RT_SUCCESS(rc))
357 memcpy(paHints, ((uint8_t *)p) + sizeof(VBVAQUERYMODEHINTS),
358 cScreens * sizeof(VBVAMODEHINT));
359
360 VBoxHGSMIBufferFree(pCtx, p);
361 }
362 return rc;
363}
364
365
366/**
367 * Query the supported flags in VBVAINFOSCREEN::u16Flags.
368 *
369 * @returns The mask of VBVA_SCREEN_F_* flags or 0 if host does not support the request.
370 * @param pCtx the context containing the heap to use
371 */
372RTDECL(uint16_t) VBoxHGSMIGetScreenFlags(PHGSMIGUESTCOMMANDCONTEXT pCtx)
373{
374 uint32_t u32Flags = 0;
375 int rc = VBoxQueryConfHGSMIDef(pCtx, VBOX_VBVA_CONF32_SCREEN_FLAGS, 0, &u32Flags);
376 LogFunc(("u32Flags = 0x%x rc %Rrc\n", u32Flags, rc));
377 if (RT_FAILURE(rc))
378 u32Flags = 0;
379 return (uint16_t)u32Flags;
380}
Note: See TracBrowser for help on using the repository browser.

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