VirtualBox

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

Last change on this file since 64670 was 64650, checked in by vboxsync, 8 years ago

bugref:8614: Additions/common/VBoxVideo: make the code more self-contained: my last attempt at removing all assertions from debug versions of the Linux video driver was not correct: I missed some places, and forgot that LINUX_VERSION_CODE is only defined when Linux headers are included. Hopefully fix that.

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