VirtualBox

source: vbox/trunk/src/VBox/Additions/x11/vboxvideo/getmode.c@ 69078

Last change on this file since 69078 was 69064, checked in by vboxsync, 7 years ago

Additions/x11/vboxvideo: use X.Org Bool rather than C++ bool.
bugref:9017: Additions/x11: put vboxvideo into upstream X.Org

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 11.3 KB
Line 
1/* $Id: getmode.c 69064 2017-10-12 18:18:01Z vboxsync $ */
2/** @file
3 * VirtualBox X11 Additions graphics driver dynamic video mode functions.
4 */
5
6/*
7 * Copyright (C) 2006-2017 Oracle Corporation
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
22 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
23 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
25 * USE OR OTHER DEALINGS IN THE SOFTWARE.
26 */
27
28#include "vboxvideo.h"
29
30#define NEED_XF86_TYPES
31#include <iprt/string.h>
32
33#include "xf86.h"
34
35#ifdef XORG_7X
36# include <stdio.h>
37# include <stdlib.h>
38#endif
39
40#ifdef VBOXVIDEO_13
41# ifdef RT_OS_LINUX
42# include <linux/input.h>
43# ifndef EVIOCGRAB
44# define EVIOCGRAB _IOW('E', 0x90, int)
45# endif
46# ifndef KEY_SWITCHVIDEOMODE
47# define KEY_SWITCHVIDEOMODE 227
48# endif
49# include <dirent.h>
50# include <errno.h>
51# include <fcntl.h>
52# include <unistd.h>
53# endif /* RT_OS_LINUX */
54#endif /* VBOXVIDEO_13 */
55
56/**************************************************************************
57* Main functions *
58**************************************************************************/
59
60/**
61 * Fills a display mode M with a built-in mode of name pszName and dimensions
62 * cx and cy.
63 */
64static void vboxFillDisplayMode(ScrnInfoPtr pScrn, DisplayModePtr m,
65 const char *pszName, unsigned cx, unsigned cy)
66{
67 VBOXPtr pVBox = pScrn->driverPrivate;
68 char szName[256];
69 DisplayModePtr pPrev = m->prev;
70 DisplayModePtr pNext = m->next;
71
72 if (!pszName)
73 {
74 sprintf(szName, "%ux%u", cx, cy);
75 pszName = szName;
76 }
77 TRACE_LOG("pszName=%s, cx=%u, cy=%u\n", pszName, cx, cy);
78 if (m->name)
79 free((void*)m->name);
80 memset(m, '\0', sizeof(*m));
81 m->prev = pPrev;
82 m->next = pNext;
83 m->status = MODE_OK;
84 m->type = M_T_BUILTIN;
85 /* Older versions of VBox only support screen widths which are a multiple
86 * of 8 */
87 if (pVBox->fAnyX)
88 m->HDisplay = cx;
89 else
90 m->HDisplay = cx & ~7;
91 m->HSyncStart = m->HDisplay + 2;
92 m->HSyncEnd = m->HDisplay + 4;
93 m->HTotal = m->HDisplay + 6;
94 m->VDisplay = cy;
95 m->VSyncStart = m->VDisplay + 2;
96 m->VSyncEnd = m->VDisplay + 4;
97 m->VTotal = m->VDisplay + 6;
98 m->Clock = m->HTotal * m->VTotal * 60 / 1000; /* kHz */
99 m->name = xnfstrdup(pszName);
100}
101
102/**
103 * Allocates an empty display mode and links it into the doubly linked list of
104 * modes pointed to by pScrn->modes. Returns a pointer to the newly allocated
105 * memory.
106 */
107static DisplayModePtr vboxAddEmptyScreenMode(ScrnInfoPtr pScrn)
108{
109 DisplayModePtr pMode = xnfcalloc(sizeof(DisplayModeRec), 1);
110
111 TRACE_ENTRY();
112 if (!pScrn->modes)
113 {
114 pScrn->modes = pMode;
115 pMode->next = pMode;
116 pMode->prev = pMode;
117 }
118 else
119 {
120 pMode->next = pScrn->modes;
121 pMode->prev = pScrn->modes->prev;
122 pMode->next->prev = pMode;
123 pMode->prev->next = pMode;
124 }
125 return pMode;
126}
127
128/**
129 * Create display mode entries in the screen information structure for each
130 * of the graphics modes that we wish to support, that is:
131 * - A dynamic mode in first place which will be updated by the RandR code.
132 * - Any modes that the user requested in xorg.conf/XFree86Config.
133 */
134void vboxAddModes(ScrnInfoPtr pScrn)
135{
136 unsigned cx = 0;
137 unsigned cy = 0;
138 unsigned i;
139 DisplayModePtr pMode;
140
141 /* Add two dynamic mode entries. When we receive a new size hint we will
142 * update whichever of these is not current. */
143 pMode = vboxAddEmptyScreenMode(pScrn);
144 vboxFillDisplayMode(pScrn, pMode, NULL, 800, 600);
145 pMode = vboxAddEmptyScreenMode(pScrn);
146 vboxFillDisplayMode(pScrn, pMode, NULL, 800, 600);
147 /* Add any modes specified by the user. We assume here that the mode names
148 * reflect the mode sizes. */
149 for (i = 0; pScrn->display->modes && pScrn->display->modes[i]; i++)
150 {
151 if (sscanf(pScrn->display->modes[i], "%ux%u", &cx, &cy) == 2)
152 {
153 pMode = vboxAddEmptyScreenMode(pScrn);
154 vboxFillDisplayMode(pScrn, pMode, pScrn->display->modes[i], cx, cy);
155 }
156 }
157}
158
159/** Set the initial values for the guest screen size hints to standard values
160 * in case nothing else is available. */
161void VBoxInitialiseSizeHints(ScrnInfoPtr pScrn)
162{
163 VBOXPtr pVBox = VBOXGetRec(pScrn);
164 unsigned i;
165
166 for (i = 0; i < pVBox->cScreens; ++i)
167 {
168 pVBox->pScreens[i].aPreferredSize.cx = 800;
169 pVBox->pScreens[i].aPreferredSize.cy = 600;
170 pVBox->pScreens[i].afConnected = true;
171 }
172 /* Set up the first mode correctly to match the requested initial mode. */
173 pScrn->modes->HDisplay = pVBox->pScreens[0].aPreferredSize.cx;
174 pScrn->modes->VDisplay = pVBox->pScreens[0].aPreferredSize.cy;
175}
176
177static Bool useHardwareCursor(uint32_t fCursorCapabilities)
178{
179 if (fCursorCapabilities & VBOX_VBVA_CURSOR_CAPABILITY_HARDWARE)
180 return true;
181 return false;
182}
183
184static void compareAndMaybeSetUseHardwareCursor(VBOXPtr pVBox, uint32_t fCursorCapabilities, Bool *pfChanged, Bool fSet)
185{
186 if (pVBox->fUseHardwareCursor != useHardwareCursor(fCursorCapabilities))
187 *pfChanged = true;
188 if (fSet)
189 pVBox->fUseHardwareCursor = useHardwareCursor(fCursorCapabilities);
190}
191
192#define COMPARE_AND_MAYBE_SET(pDest, src, pfChanged, fSet) \
193do { \
194 if (*(pDest) != (src)) \
195 { \
196 if (fSet) \
197 *(pDest) = (src); \
198 *(pfChanged) = true; \
199 } \
200} while(0)
201
202/** Read in information about the most recent size hints and cursor
203 * capabilities requested for the guest screens from HGSMI. */
204void vbvxReadSizesAndCursorIntegrationFromHGSMI(ScrnInfoPtr pScrn, Bool *pfNeedUpdate)
205{
206 VBOXPtr pVBox = VBOXGetRec(pScrn);
207 int rc;
208 unsigned i;
209 Bool fChanged = false;
210 uint32_t fCursorCapabilities;
211
212 if (!pVBox->fHaveHGSMIModeHints)
213 return;
214 rc = VBoxHGSMIGetModeHints(&pVBox->guestCtx, pVBox->cScreens, pVBox->paVBVAModeHints);
215 VBVXASSERT(rc == VINF_SUCCESS, ("VBoxHGSMIGetModeHints failed, rc=%d.\n", rc));
216 for (i = 0; i < pVBox->cScreens; ++i)
217 if (pVBox->paVBVAModeHints[i].magic == VBVAMODEHINT_MAGIC)
218 {
219 COMPARE_AND_MAYBE_SET(&pVBox->pScreens[i].aPreferredSize.cx, pVBox->paVBVAModeHints[i].cx & 0x8fff, &fChanged, true);
220 COMPARE_AND_MAYBE_SET(&pVBox->pScreens[i].aPreferredSize.cy, pVBox->paVBVAModeHints[i].cy & 0x8fff, &fChanged, true);
221 COMPARE_AND_MAYBE_SET(&pVBox->pScreens[i].afConnected, RT_BOOL(pVBox->paVBVAModeHints[i].fEnabled), &fChanged, true);
222 COMPARE_AND_MAYBE_SET(&pVBox->pScreens[i].aPreferredLocation.x, (int32_t)pVBox->paVBVAModeHints[i].dx & 0x8fff, &fChanged,
223 true);
224 COMPARE_AND_MAYBE_SET(&pVBox->pScreens[i].aPreferredLocation.y, (int32_t)pVBox->paVBVAModeHints[i].dy & 0x8fff, &fChanged,
225 true);
226 if (pVBox->paVBVAModeHints[i].dx != ~(uint32_t)0 && pVBox->paVBVAModeHints[i].dy != ~(uint32_t)0)
227 COMPARE_AND_MAYBE_SET(&pVBox->pScreens[i].afHaveLocation, true, &fChanged, true);
228 else
229 COMPARE_AND_MAYBE_SET(&pVBox->pScreens[i].afHaveLocation, false, &fChanged, true);
230 }
231 rc = VBoxQueryConfHGSMI(&pVBox->guestCtx, VBOX_VBVA_CONF32_CURSOR_CAPABILITIES, &fCursorCapabilities);
232 VBVXASSERT(rc == VINF_SUCCESS, ("Getting VBOX_VBVA_CONF32_CURSOR_CAPABILITIES failed, rc=%d.\n", rc));
233 compareAndMaybeSetUseHardwareCursor(pVBox, fCursorCapabilities, &fChanged, true);
234 if (pfNeedUpdate != NULL && fChanged)
235 *pfNeedUpdate = true;
236}
237
238#undef COMPARE_AND_MAYBE_SET
239
240#ifdef VBOXVIDEO_13
241# ifdef RT_OS_LINUX
242/** We have this for two purposes: one is to ensure that the X server is woken
243 * up when we get a video ACPI event. Two is to grab ACPI video events to
244 * prevent gnome-settings-daemon from seeing them, as older versions ignored
245 * the time stamp and handled them at the wrong time. */
246static void acpiEventHandler(int fd, void *pvData)
247{
248 struct input_event event;
249 ssize_t rc;
250 RT_NOREF(pvData);
251
252 do
253 rc = read(fd, &event, sizeof(event));
254 while (rc > 0 || (rc == -1 && errno == EINTR));
255 /* Why do they return EAGAIN instead of zero bytes read like everyone else does? */
256 VBVXASSERT(rc != -1 || errno == EAGAIN, ("Reading ACPI input event failed.\n"));
257}
258
259void vbvxSetUpLinuxACPI(ScreenPtr pScreen)
260{
261 VBOXPtr pVBox = VBOXGetRec(xf86Screens[pScreen->myNum]);
262 struct dirent *pDirent;
263 DIR *pDir;
264 int fd = -1;
265
266 if (pVBox->fdACPIDevices != -1 || pVBox->hACPIEventHandler != NULL)
267 FatalError("ACPI input file descriptor not initialised correctly.\n");
268 pDir = opendir("/dev/input");
269 if (pDir == NULL)
270 return;
271 for (pDirent = readdir(pDir); pDirent != NULL; pDirent = readdir(pDir))
272 {
273 if (strncmp(pDirent->d_name, "event", sizeof("event") - 1) == 0)
274 {
275#define BITS_PER_BLOCK (sizeof(unsigned long) * 8)
276 char szFile[64] = "/dev/input/";
277 char szDevice[64] = "";
278 unsigned long afKeys[KEY_MAX / BITS_PER_BLOCK];
279
280 strncat(szFile, pDirent->d_name, sizeof(szFile) - sizeof("/dev/input/"));
281 if (fd != -1)
282 close(fd);
283 fd = open(szFile, O_RDONLY | O_NONBLOCK);
284 if ( fd == -1
285 || ioctl(fd, EVIOCGNAME(sizeof(szDevice)), szDevice) == -1
286 || strcmp(szDevice, "Video Bus") != 0)
287 continue;
288 if ( ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(afKeys)), afKeys) == -1
289 || (( afKeys[KEY_SWITCHVIDEOMODE / BITS_PER_BLOCK]
290 >> KEY_SWITCHVIDEOMODE % BITS_PER_BLOCK) & 1) == 0)
291 break;
292 if (ioctl(fd, EVIOCGRAB, (void *)1) != 0)
293 break;
294 pVBox->hACPIEventHandler
295 = xf86AddGeneralHandler(fd, acpiEventHandler, pScreen);
296 if (pVBox->hACPIEventHandler == NULL)
297 break;
298 pVBox->fdACPIDevices = fd;
299 fd = -1;
300 break;
301#undef BITS_PER_BLOCK
302 }
303 }
304 if (fd != -1)
305 close(fd);
306 closedir(pDir);
307}
308
309void vbvxCleanUpLinuxACPI(ScreenPtr pScreen)
310{
311 VBOXPtr pVBox = VBOXGetRec(xf86Screens[pScreen->myNum]);
312 if (pVBox->fdACPIDevices != -1)
313 close(pVBox->fdACPIDevices);
314 pVBox->fdACPIDevices = -1;
315 xf86RemoveGeneralHandler(pVBox->hACPIEventHandler);
316 pVBox->hACPIEventHandler = NULL;
317}
318# endif /* RT_OS_LINUX */
319#endif /* VBOXVIDEO_13 */
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