VirtualBox

source: vbox/trunk/src/VBox/Additions/linux/drm/vbox_mode.c@ 74581

Last change on this file since 74581 was 74581, checked in by vboxsync, 6 years ago

Additions/linux/vboxvideo: better work-around for missing dirty rectangles.
bugref:9235: No screenshot for Linux VM
Background: a long time ago, Linux user-space applications using the DRM
graphics interface did not need to provide the graphics driver with dirty
rectangle information. This was changed to make life easier for virtual
devices like ours, but the version of Plymouth (the splash screen at system
boot) in recent Ubuntu 14.04 versions does not do it. We did some nasty
tricks to make the hardware notice screen updates anyway, and they caused
screenshots in Linux virtual machines not to work (and might have other side
effects).
This changes removes the tricks mentioned above, and instead introduces a
twice-a-second refresh timer in the driver. As this is only intended for that
version of Plymouth, we disable the timer as soon as we either receive dirty
rectangle information, or the user-space client shows that it can handle
screen resizes (which Plymouth cannot, at least that version). Once page flip
support is integrated we could use that as a test instead of the second, but
only if there is actually a need. Twice a second refresh is quite a high
overhead, but it is only incurred in that rare case, and usually only for a
few seconds at that.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 26.6 KB
Line 
1/* $Id: vbox_mode.c 74581 2018-10-02 14:01:09Z vboxsync $ */
2/** @file
3 * VirtualBox Additions Linux kernel video driver
4 */
5
6/*
7 * Copyright (C) 2013-2017 Oracle Corporation
8 * This file is based on ast_mode.c
9 * Copyright 2012 Red Hat Inc.
10 * Parts based on xf86-video-ast
11 * Copyright (c) 2005 ASPEED Technology Inc.
12 *
13 * Permission is hereby granted, free of charge, to any person obtaining a
14 * copy of this software and associated documentation files (the
15 * "Software"), to deal in the Software without restriction, including
16 * without limitation the rights to use, copy, modify, merge, publish,
17 * distribute, sub license, and/or sell copies of the Software, and to
18 * permit persons to whom the Software is furnished to do so, subject to
19 * the following conditions:
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
24 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
25 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
26 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
27 * USE OR OTHER DEALINGS IN THE SOFTWARE.
28 *
29 * The above copyright notice and this permission notice (including the
30 * next paragraph) shall be included in all copies or substantial portions
31 * of the Software.
32 *
33 */
34/*
35 * Authors: Dave Airlie <[email protected]>
36 * Michael Thayer <[email protected],
37 * Hans de Goede <[email protected]>
38 */
39#include "vbox_drv.h"
40#include <linux/export.h>
41#include <drm/drm_crtc_helper.h>
42#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0) || defined(RHEL_73)
43#include <drm/drm_plane_helper.h>
44#endif
45
46#include "VBoxVideo.h"
47#include "hgsmi_channels.h"
48
49static int vbox_cursor_set2(struct drm_crtc *crtc, struct drm_file *file_priv,
50 u32 handle, u32 width, u32 height,
51 s32 hot_x, s32 hot_y);
52static int vbox_cursor_move(struct drm_crtc *crtc, int x, int y);
53
54/**
55 * Set a graphics mode. Poke any required values into registers, do an HGSMI
56 * mode set and tell the host we support advanced graphics functions.
57 */
58static void vbox_do_modeset(struct drm_crtc *crtc,
59 const struct drm_display_mode *mode)
60{
61 struct vbox_crtc *vbox_crtc = to_vbox_crtc(crtc);
62 struct vbox_private *vbox;
63 int width, height, bpp, pitch;
64 unsigned int crtc_id;
65 u16 flags;
66 s32 x_offset, y_offset;
67
68 vbox = crtc->dev->dev_private;
69 width = mode->hdisplay ? mode->hdisplay : 640;
70 height = mode->vdisplay ? mode->vdisplay : 480;
71 crtc_id = vbox_crtc->crtc_id;
72#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) || defined(RHEL_75)
73 bpp = crtc->enabled ? CRTC_FB(crtc)->format->cpp[0] * 8 : 32;
74 pitch = crtc->enabled ? CRTC_FB(crtc)->pitches[0] : width * bpp / 8;
75#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)
76 bpp = crtc->enabled ? CRTC_FB(crtc)->bits_per_pixel : 32;
77 pitch = crtc->enabled ? CRTC_FB(crtc)->pitches[0] : width * bpp / 8;
78#else
79 bpp = crtc->enabled ? CRTC_FB(crtc)->bits_per_pixel : 32;
80 pitch = crtc->enabled ? CRTC_FB(crtc)->pitch : width * bpp / 8;
81#endif
82 x_offset = vbox->single_framebuffer ? crtc->x : vbox_crtc->x_hint;
83 y_offset = vbox->single_framebuffer ? crtc->y : vbox_crtc->y_hint;
84
85 /*
86 * This is the old way of setting graphics modes. It assumed one screen
87 * and a frame-buffer at the start of video RAM. On older versions of
88 * VirtualBox, certain parts of the code still assume that the first
89 * screen is programmed this way, so try to fake it.
90 */
91 if (vbox_crtc->crtc_id == 0 && crtc->enabled &&
92 vbox_crtc->fb_offset / pitch < 0xffff - crtc->y &&
93 vbox_crtc->fb_offset % (bpp / 8) == 0)
94 VBoxVideoSetModeRegisters(
95 width, height, pitch * 8 / bpp,
96#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) || defined(RHEL_75)
97 CRTC_FB(crtc)->format->cpp[0] * 8,
98#else
99 CRTC_FB(crtc)->bits_per_pixel,
100#endif
101 0,
102 vbox_crtc->fb_offset % pitch / bpp * 8 + crtc->x,
103 vbox_crtc->fb_offset / pitch + crtc->y);
104
105 flags = VBVA_SCREEN_F_ACTIVE;
106 flags |= (crtc->enabled && !vbox_crtc->blanked) ?
107 0 : VBVA_SCREEN_F_BLANK;
108 flags |= vbox_crtc->disconnected ? VBVA_SCREEN_F_DISABLED : 0;
109 VBoxHGSMIProcessDisplayInfo(vbox->guest_pool, vbox_crtc->crtc_id,
110 x_offset, y_offset,
111 crtc->x * bpp / 8 + crtc->y * pitch,
112 pitch, width, height,
113 vbox_crtc->blanked ? 0 : bpp, flags);
114}
115
116static int vbox_set_view(struct drm_crtc *crtc)
117{
118 struct vbox_crtc *vbox_crtc = to_vbox_crtc(crtc);
119 struct vbox_private *vbox = crtc->dev->dev_private;
120 void *p;
121
122 /*
123 * Tell the host about the view. This design originally targeted the
124 * Windows XP driver architecture and assumed that each screen would
125 * have a dedicated frame buffer with the command buffer following it,
126 * the whole being a "view". The host works out which screen a command
127 * buffer belongs to by checking whether it is in the first view, then
128 * whether it is in the second and so on. The first match wins. We
129 * cheat around this by making the first view be the managed memory
130 * plus the first command buffer, the second the same plus the second
131 * buffer and so on.
132 */
133 p = VBoxHGSMIBufferAlloc(vbox->guest_pool, sizeof(VBVAINFOVIEW),
134 HGSMI_CH_VBVA, VBVA_INFO_VIEW);
135 if (p) {
136 VBVAINFOVIEW *pInfo = (VBVAINFOVIEW *) p;
137
138 pInfo->u32ViewIndex = vbox_crtc->crtc_id;
139 pInfo->u32ViewOffset = vbox_crtc->fb_offset;
140 pInfo->u32ViewSize =
141 vbox->available_vram_size - vbox_crtc->fb_offset +
142 vbox_crtc->crtc_id * VBVA_MIN_BUFFER_SIZE;
143 pInfo->u32MaxScreenSize =
144 vbox->available_vram_size - vbox_crtc->fb_offset;
145 VBoxHGSMIBufferSubmit(vbox->guest_pool, p);
146 VBoxHGSMIBufferFree(vbox->guest_pool, p);
147 } else {
148 return -ENOMEM;
149 }
150
151 return 0;
152}
153
154static void vbox_crtc_dpms(struct drm_crtc *crtc, int mode)
155{
156 struct vbox_crtc *vbox_crtc = to_vbox_crtc(crtc);
157 struct vbox_private *vbox = crtc->dev->dev_private;
158
159 switch (mode) {
160 case DRM_MODE_DPMS_ON:
161 vbox_crtc->blanked = false;
162 /* Restart the refresh timer if necessary. */
163 schedule_delayed_work(&vbox->refresh_work, VBOX_REFRESH_PERIOD);
164 break;
165 case DRM_MODE_DPMS_STANDBY:
166 case DRM_MODE_DPMS_SUSPEND:
167 case DRM_MODE_DPMS_OFF:
168 vbox_crtc->blanked = true;
169 break;
170 }
171
172 mutex_lock(&vbox->hw_mutex);
173 vbox_do_modeset(crtc, &crtc->hwmode);
174 mutex_unlock(&vbox->hw_mutex);
175}
176
177static bool vbox_crtc_mode_fixup(struct drm_crtc *crtc,
178 const struct drm_display_mode *mode,
179 struct drm_display_mode *adjusted_mode)
180{
181 return true;
182}
183
184/*
185 * Try to map the layout of virtual screens to the range of the input device.
186 * Return true if we need to re-set the crtc modes due to screen offset
187 * changes.
188 */
189static bool vbox_set_up_input_mapping(struct vbox_private *vbox)
190{
191 struct drm_crtc *crtci;
192 struct drm_connector *connectori;
193 struct drm_framebuffer *fb1 = NULL;
194 bool single_framebuffer = true;
195 bool old_single_framebuffer = vbox->single_framebuffer;
196 u16 width = 0, height = 0;
197
198 /*
199 * Are we using an X.Org-style single large frame-buffer for all crtcs?
200 * If so then screen layout can be deduced from the crtc offsets.
201 * Same fall-back if this is the fbdev frame-buffer.
202 */
203 list_for_each_entry(crtci, &vbox->dev->mode_config.crtc_list, head) {
204 if (!fb1) {
205 fb1 = CRTC_FB(crtci);
206 if (to_vbox_framebuffer(fb1) == &vbox->fbdev->afb)
207 break;
208 } else if (CRTC_FB(crtci) && fb1 != CRTC_FB(crtci)) {
209 single_framebuffer = false;
210 }
211 }
212 if (single_framebuffer) {
213 list_for_each_entry(crtci, &vbox->dev->mode_config.crtc_list,
214 head) {
215 if (to_vbox_crtc(crtci)->crtc_id == 0) {
216 vbox->single_framebuffer = true;
217 vbox->input_mapping_width =
218 CRTC_FB(crtci)->width;
219 vbox->input_mapping_height =
220 CRTC_FB(crtci)->height;
221 return old_single_framebuffer !=
222 vbox->single_framebuffer;
223 }
224 }
225 }
226 /* Otherwise calculate the total span of all screens. */
227 list_for_each_entry(connectori, &vbox->dev->mode_config.connector_list,
228 head) {
229 struct vbox_connector *vbox_connector =
230 to_vbox_connector(connectori);
231 struct vbox_crtc *vbox_crtc = vbox_connector->vbox_crtc;
232
233 width = max_t(u16, width, vbox_crtc->x_hint +
234 vbox_connector->mode_hint.width);
235 height = max_t(u16, height, vbox_crtc->y_hint +
236 vbox_connector->mode_hint.height);
237 }
238
239 vbox->single_framebuffer = false;
240 vbox->input_mapping_width = width;
241 vbox->input_mapping_height = height;
242
243 return old_single_framebuffer != vbox->single_framebuffer;
244}
245
246static int vbox_crtc_set_base(struct drm_crtc *crtc,
247 struct drm_framebuffer *old_fb, int x, int y)
248{
249 struct vbox_private *vbox = crtc->dev->dev_private;
250 struct vbox_crtc *vbox_crtc = to_vbox_crtc(crtc);
251 struct drm_gem_object *obj;
252 struct vbox_framebuffer *vbox_fb;
253 struct vbox_bo *bo;
254 int ret;
255 u64 gpu_addr;
256
257 vbox_fb = to_vbox_framebuffer(CRTC_FB(crtc));
258 obj = vbox_fb->obj;
259 bo = gem_to_vbox_bo(obj);
260
261 ret = vbox_bo_reserve(bo, false);
262 if (ret)
263 return ret;
264
265 ret = vbox_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr);
266 vbox_bo_unreserve(bo);
267 if (ret)
268 return ret;
269
270 /* Unpin the previous fb. Do this after the new one has been pinned rather
271 * than before and re-pinning it on failure in case that fails too. */
272 if (old_fb) {
273 vbox_fb = to_vbox_framebuffer(old_fb);
274 obj = vbox_fb->obj;
275 bo = gem_to_vbox_bo(obj);
276 ret = vbox_bo_reserve(bo, false);
277 /* This should never fail, as no one else should be accessing it and we
278 * should be running under the modeset locks. */
279 if (!ret) {
280 vbox_bo_unpin(bo);
281 vbox_bo_unreserve(bo);
282 }
283 }
284
285 vbox_crtc->fb_offset = gpu_addr;
286 if (vbox_set_up_input_mapping(vbox)) {
287 struct drm_crtc *crtci;
288
289 list_for_each_entry(crtci, &vbox->dev->mode_config.crtc_list,
290 head) {
291 vbox_set_view(crtc);
292 vbox_do_modeset(crtci, &crtci->mode);
293 }
294 }
295
296 return 0;
297}
298
299static int vbox_crtc_mode_set(struct drm_crtc *crtc,
300 struct drm_display_mode *mode,
301 struct drm_display_mode *adjusted_mode,
302 int x, int y, struct drm_framebuffer *old_fb)
303{
304 struct vbox_private *vbox = crtc->dev->dev_private;
305 int rc = vbox_crtc_set_base(crtc, old_fb, x, y);
306 if (rc)
307 return rc;
308 mutex_lock(&vbox->hw_mutex);
309 rc = vbox_set_view(crtc);
310 if (!rc)
311 vbox_do_modeset(crtc, mode);
312 VBoxHGSMIUpdateInputMapping(vbox->guest_pool, 0, 0,
313 vbox->input_mapping_width,
314 vbox->input_mapping_height);
315 mutex_unlock(&vbox->hw_mutex);
316
317 return rc;
318}
319
320static void vbox_crtc_disable(struct drm_crtc *crtc)
321{
322}
323
324static void vbox_crtc_prepare(struct drm_crtc *crtc)
325{
326}
327
328static void vbox_crtc_commit(struct drm_crtc *crtc)
329{
330}
331
332static const struct drm_crtc_helper_funcs vbox_crtc_helper_funcs = {
333 .dpms = vbox_crtc_dpms,
334 .mode_fixup = vbox_crtc_mode_fixup,
335 .mode_set = vbox_crtc_mode_set,
336 .disable = vbox_crtc_disable,
337 .prepare = vbox_crtc_prepare,
338 .commit = vbox_crtc_commit,
339};
340
341static void vbox_crtc_reset(struct drm_crtc *crtc)
342{
343}
344
345static void vbox_crtc_destroy(struct drm_crtc *crtc)
346{
347 drm_crtc_cleanup(crtc);
348 kfree(crtc);
349}
350
351static const struct drm_crtc_funcs vbox_crtc_funcs = {
352 .cursor_move = vbox_cursor_move,
353 .cursor_set2 = vbox_cursor_set2,
354 .reset = vbox_crtc_reset,
355 .set_config = drm_crtc_helper_set_config,
356 /* .gamma_set = vbox_crtc_gamma_set, */
357 .destroy = vbox_crtc_destroy,
358};
359
360static struct vbox_crtc *vbox_crtc_init(struct drm_device *dev, unsigned int i)
361{
362 struct vbox_crtc *vbox_crtc;
363
364 vbox_crtc = kzalloc(sizeof(*vbox_crtc), GFP_KERNEL);
365 if (!vbox_crtc)
366 return NULL;
367
368 vbox_crtc->crtc_id = i;
369
370 drm_crtc_init(dev, &vbox_crtc->base, &vbox_crtc_funcs);
371 drm_mode_crtc_set_gamma_size(&vbox_crtc->base, 256);
372 drm_crtc_helper_add(&vbox_crtc->base, &vbox_crtc_helper_funcs);
373
374 return vbox_crtc;
375}
376
377static void vbox_encoder_destroy(struct drm_encoder *encoder)
378{
379 drm_encoder_cleanup(encoder);
380 kfree(encoder);
381}
382
383#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) && !defined(RHEL_73)
384static struct drm_encoder *drm_encoder_find(struct drm_device *dev, u32 id)
385{
386 struct drm_mode_object *mo;
387
388 mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_ENCODER);
389 return mo ? obj_to_encoder(mo) : NULL;
390}
391#endif
392
393static struct drm_encoder *vbox_best_single_encoder(struct drm_connector
394 *connector)
395{
396 int enc_id = connector->encoder_ids[0];
397
398 /* pick the encoder ids */
399 if (enc_id)
400#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) || \
401 (defined(CONFIG_SUSE_VERSION) && CONFIG_SUSE_VERSION == 15)
402 return drm_encoder_find(connector->dev, NULL, enc_id);
403#else
404 return drm_encoder_find(connector->dev, enc_id);
405#endif
406
407 return NULL;
408}
409
410static const struct drm_encoder_funcs vbox_enc_funcs = {
411 .destroy = vbox_encoder_destroy,
412};
413
414static void vbox_encoder_dpms(struct drm_encoder *encoder, int mode)
415{
416}
417
418static bool vbox_mode_fixup(struct drm_encoder *encoder,
419 const struct drm_display_mode *mode,
420 struct drm_display_mode *adjusted_mode)
421{
422 return true;
423}
424
425static void vbox_encoder_mode_set(struct drm_encoder *encoder,
426 struct drm_display_mode *mode,
427 struct drm_display_mode *adjusted_mode)
428{
429}
430
431static void vbox_encoder_prepare(struct drm_encoder *encoder)
432{
433}
434
435static void vbox_encoder_commit(struct drm_encoder *encoder)
436{
437}
438
439static const struct drm_encoder_helper_funcs vbox_enc_helper_funcs = {
440 .dpms = vbox_encoder_dpms,
441 .mode_fixup = vbox_mode_fixup,
442 .prepare = vbox_encoder_prepare,
443 .commit = vbox_encoder_commit,
444 .mode_set = vbox_encoder_mode_set,
445};
446
447static struct drm_encoder *vbox_encoder_init(struct drm_device *dev,
448 unsigned int i)
449{
450 struct vbox_encoder *vbox_encoder;
451
452 vbox_encoder = kzalloc(sizeof(*vbox_encoder), GFP_KERNEL);
453 if (!vbox_encoder)
454 return NULL;
455
456 drm_encoder_init(dev, &vbox_encoder->base, &vbox_enc_funcs,
457 DRM_MODE_ENCODER_DAC
458#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0) || defined(RHEL_73)
459 , NULL
460#endif
461 );
462 drm_encoder_helper_add(&vbox_encoder->base, &vbox_enc_helper_funcs);
463
464 vbox_encoder->base.possible_crtcs = 1 << i;
465 return &vbox_encoder->base;
466}
467
468/**
469 * Generate EDID data with a mode-unique serial number for the virtual
470 * monitor to try to persuade Unity that different modes correspond to
471 * different monitors and it should not try to force the same resolution on
472 * them.
473 */
474static void vbox_set_edid(struct drm_connector *connector, int width,
475 int height)
476{
477 enum { EDID_SIZE = 128 };
478 unsigned char edid[EDID_SIZE] = {
479 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, /* header */
480 0x58, 0x58, /* manufacturer (VBX) */
481 0x00, 0x00, /* product code */
482 0x00, 0x00, 0x00, 0x00, /* serial number goes here */
483 0x01, /* week of manufacture */
484 0x00, /* year of manufacture */
485 0x01, 0x03, /* EDID version */
486 0x80, /* capabilities - digital */
487 0x00, /* horiz. res in cm, zero for projectors */
488 0x00, /* vert. res in cm */
489 0x78, /* display gamma (120 == 2.2). */
490 0xEE, /* features (standby, suspend, off, RGB, std */
491 /* colour space, preferred timing mode) */
492 0xEE, 0x91, 0xA3, 0x54, 0x4C, 0x99, 0x26, 0x0F, 0x50, 0x54,
493 /* chromaticity for standard colour space. */
494 0x00, 0x00, 0x00, /* no default timings */
495 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
496 0x01, 0x01,
497 0x01, 0x01, 0x01, 0x01, /* no standard timings */
498 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x06, 0x00, 0x02, 0x02,
499 0x02, 0x02,
500 /* descriptor block 1 goes below */
501 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
502 /* descriptor block 2, monitor ranges */
503 0x00, 0x00, 0x00, 0xFD, 0x00,
504 0x00, 0xC8, 0x00, 0xC8, 0x64, 0x00, 0x0A, 0x20, 0x20, 0x20,
505 0x20, 0x20,
506 /* 0-200Hz vertical, 0-200KHz horizontal, 1000MHz pixel clock */
507 0x20,
508 /* descriptor block 3, monitor name */
509 0x00, 0x00, 0x00, 0xFC, 0x00,
510 'V', 'B', 'O', 'X', ' ', 'm', 'o', 'n', 'i', 't', 'o', 'r',
511 '\n',
512 /* descriptor block 4: dummy data */
513 0x00, 0x00, 0x00, 0x10, 0x00,
514 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20,
515 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
516 0x20,
517 0x00, /* number of extensions */
518 0x00 /* checksum goes here */
519 };
520 int clock = (width + 6) * (height + 6) * 60 / 10000;
521 unsigned int i, sum = 0;
522
523 edid[12] = width & 0xff;
524 edid[13] = width >> 8;
525 edid[14] = height & 0xff;
526 edid[15] = height >> 8;
527 edid[54] = clock & 0xff;
528 edid[55] = clock >> 8;
529 edid[56] = width & 0xff;
530 edid[58] = (width >> 4) & 0xf0;
531 edid[59] = height & 0xff;
532 edid[61] = (height >> 4) & 0xf0;
533 for (i = 0; i < EDID_SIZE - 1; ++i)
534 sum += edid[i];
535 edid[EDID_SIZE - 1] = (0x100 - (sum & 0xFF)) & 0xFF;
536 drm_mode_connector_update_edid_property(connector, (struct edid *)edid);
537}
538
539static int vbox_get_modes(struct drm_connector *connector)
540{
541 struct vbox_connector *vbox_connector = NULL;
542 struct drm_display_mode *mode = NULL;
543 struct vbox_private *vbox = NULL;
544 unsigned int num_modes = 0;
545 int preferred_width, preferred_height;
546
547 vbox_connector = to_vbox_connector(connector);
548 vbox = connector->dev->dev_private;
549 /*
550 * Heuristic: we do not want to tell the host that we support dynamic
551 * resizing unless we feel confident that the user space client using
552 * the video driver can handle hot-plug events. So the first time modes
553 * are queried after a "master" switch we tell the host that we do not,
554 * and immediately after we send the client a hot-plug notification as
555 * a test to see if they will respond and query again.
556 * That is also the reason why capabilities are reported to the host at
557 * this place in the code rather than elsewhere.
558 * We need to report the flags location before reporting the IRQ
559 * capability.
560 */
561 VBoxHGSMIReportFlagsLocation(vbox->guest_pool, GUEST_HEAP_OFFSET(vbox) +
562 HOST_FLAGS_OFFSET);
563 if (vbox_connector->vbox_crtc->crtc_id == 0)
564 vbox_report_caps(vbox);
565 if (!vbox->initial_mode_queried) {
566 if (vbox_connector->vbox_crtc->crtc_id == 0) {
567 vbox->initial_mode_queried = true;
568 vbox_report_hotplug(vbox);
569 }
570 return drm_add_modes_noedid(connector, 800, 600);
571 }
572 /* Also assume that a client which supports hot-plugging also knows
573 * how to update the screen in a way we can use, the only known
574 * relevent client which cannot is Plymouth in Ubuntu 14.04. */
575 vbox->need_refresh_timer = false;
576 num_modes = drm_add_modes_noedid(connector, 2560, 1600);
577 preferred_width = vbox_connector->mode_hint.width ?
578 vbox_connector->mode_hint.width : 1024;
579 preferred_height = vbox_connector->mode_hint.height ?
580 vbox_connector->mode_hint.height : 768;
581 mode = drm_cvt_mode(connector->dev, preferred_width, preferred_height,
582 60, false, false, false);
583 if (mode) {
584 mode->type |= DRM_MODE_TYPE_PREFERRED;
585 drm_mode_probed_add(connector, mode);
586 ++num_modes;
587 }
588 vbox_set_edid(connector, preferred_width, preferred_height);
589
590#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) || defined(RHEL_73)
591 if (vbox_connector->vbox_crtc->x_hint != -1)
592 drm_object_property_set_value(&connector->base,
593 vbox->dev->mode_config.suggested_x_property,
594 vbox_connector->vbox_crtc->x_hint);
595 else
596 drm_object_property_set_value(&connector->base,
597 vbox->dev->mode_config.suggested_x_property, 0);
598
599 if (vbox_connector->vbox_crtc->y_hint != -1)
600 drm_object_property_set_value(&connector->base,
601 vbox->dev->mode_config.suggested_y_property,
602 vbox_connector->vbox_crtc->y_hint);
603 else
604 drm_object_property_set_value(&connector->base,
605 vbox->dev->mode_config.suggested_y_property, 0);
606#endif
607
608 return num_modes;
609}
610
611static int vbox_mode_valid(struct drm_connector *connector,
612 struct drm_display_mode *mode)
613{
614 return MODE_OK;
615}
616
617static void vbox_connector_destroy(struct drm_connector *connector)
618{
619 struct vbox_connector *vbox_connector = NULL;
620
621 vbox_connector = to_vbox_connector(connector);
622#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0) && !defined(RHEL_73)
623 drm_sysfs_connector_remove(connector);
624#else
625 drm_connector_unregister(connector);
626#endif
627 drm_connector_cleanup(connector);
628 kfree(connector);
629}
630
631static enum drm_connector_status
632vbox_connector_detect(struct drm_connector *connector, bool force)
633{
634 struct vbox_connector *vbox_connector = NULL;
635
636 (void)force;
637 vbox_connector = to_vbox_connector(connector);
638
639 return vbox_connector->mode_hint.disconnected ?
640 connector_status_disconnected : connector_status_connected;
641}
642
643static int vbox_fill_modes(struct drm_connector *connector, u32 max_x,
644 u32 max_y)
645{
646 struct vbox_connector *vbox_connector;
647 struct drm_device *dev;
648 struct drm_display_mode *mode, *iterator;
649
650 vbox_connector = to_vbox_connector(connector);
651 dev = vbox_connector->base.dev;
652 list_for_each_entry_safe(mode, iterator, &connector->modes, head) {
653 list_del(&mode->head);
654 drm_mode_destroy(dev, mode);
655 }
656
657 return drm_helper_probe_single_connector_modes(connector, max_x, max_y);
658}
659
660static const struct drm_connector_helper_funcs vbox_connector_helper_funcs = {
661 .mode_valid = vbox_mode_valid,
662 .get_modes = vbox_get_modes,
663 .best_encoder = vbox_best_single_encoder,
664};
665
666static const struct drm_connector_funcs vbox_connector_funcs = {
667 .dpms = drm_helper_connector_dpms,
668 .detect = vbox_connector_detect,
669 .fill_modes = vbox_fill_modes,
670 .destroy = vbox_connector_destroy,
671};
672
673static int vbox_connector_init(struct drm_device *dev,
674 struct vbox_crtc *vbox_crtc,
675 struct drm_encoder *encoder)
676{
677 struct vbox_connector *vbox_connector;
678 struct drm_connector *connector;
679
680 vbox_connector = kzalloc(sizeof(*vbox_connector), GFP_KERNEL);
681 if (!vbox_connector)
682 return -ENOMEM;
683
684 connector = &vbox_connector->base;
685 vbox_connector->vbox_crtc = vbox_crtc;
686
687 drm_connector_init(dev, connector, &vbox_connector_funcs,
688 DRM_MODE_CONNECTOR_VGA);
689 drm_connector_helper_add(connector, &vbox_connector_helper_funcs);
690
691 connector->interlace_allowed = 0;
692 connector->doublescan_allowed = 0;
693
694#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) || defined(RHEL_73)
695 drm_mode_create_suggested_offset_properties(dev);
696 drm_object_attach_property(&connector->base,
697 dev->mode_config.suggested_x_property, 0);
698 drm_object_attach_property(&connector->base,
699 dev->mode_config.suggested_y_property, 0);
700#endif
701#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0) && !defined(RHEL_73)
702 drm_sysfs_connector_add(connector);
703#else
704 drm_connector_register(connector);
705#endif
706
707 drm_mode_connector_attach_encoder(connector, encoder);
708
709 return 0;
710}
711
712int vbox_mode_init(struct drm_device *dev)
713{
714 struct vbox_private *vbox = dev->dev_private;
715 struct drm_encoder *encoder;
716 struct vbox_crtc *vbox_crtc;
717 unsigned int i;
718
719 /* vbox_cursor_init(dev); */
720 for (i = 0; i < vbox->num_crtcs; ++i) {
721 vbox_crtc = vbox_crtc_init(dev, i);
722 if (!vbox_crtc)
723 return -ENOMEM;
724 encoder = vbox_encoder_init(dev, i);
725 if (!encoder)
726 return -ENOMEM;
727 vbox_connector_init(dev, vbox_crtc, encoder);
728 }
729
730 return 0;
731}
732
733void vbox_mode_fini(struct drm_device *dev)
734{
735 /* vbox_cursor_fini(dev); */
736}
737
738/**
739 * Copy the ARGB image and generate the mask, which is needed in case the host
740 * does not support ARGB cursors. The mask is a 1BPP bitmap with the bit set
741 * if the corresponding alpha value in the ARGB image is greater than 0xF0.
742 */
743static void copy_cursor_image(u8 *src, u8 *dst, u32 width, u32 height,
744 size_t mask_size)
745{
746 size_t line_size = (width + 7) / 8;
747 u32 i, j;
748
749 memcpy(dst + mask_size, src, width * height * 4);
750 for (i = 0; i < height; ++i)
751 for (j = 0; j < width; ++j)
752 if (((u32 *)src)[i * width + j] > 0xf0000000)
753 dst[i * line_size + j / 8] |= (0x80 >> (j % 8));
754}
755
756static int vbox_cursor_set2(struct drm_crtc *crtc, struct drm_file *file_priv,
757 u32 handle, u32 width, u32 height,
758 s32 hot_x, s32 hot_y)
759{
760 struct vbox_private *vbox = crtc->dev->dev_private;
761 struct vbox_crtc *vbox_crtc = to_vbox_crtc(crtc);
762 struct drm_gem_object *obj;
763 struct vbox_bo *bo;
764 int ret, rc;
765 struct ttm_bo_kmap_obj uobj_map;
766 u8 *src;
767 u8 *dst = NULL;
768 u32 caps = 0;
769 size_t data_size, mask_size;
770 bool src_isiomem;
771
772 if (!handle) {
773 bool cursor_enabled = false;
774 struct drm_crtc *crtci;
775
776 /* Hide cursor. */
777 vbox_crtc->cursor_enabled = false;
778 list_for_each_entry(crtci, &vbox->dev->mode_config.crtc_list,
779 head)
780 if (to_vbox_crtc(crtci)->cursor_enabled)
781 cursor_enabled = true;
782
783 if (!cursor_enabled)
784 VBoxHGSMIUpdatePointerShape(vbox->guest_pool, 0, 0, 0,
785 0, 0, NULL, 0);
786 return 0;
787 }
788 vbox_crtc->cursor_enabled = true;
789 if (width > VBOX_MAX_CURSOR_WIDTH || height > VBOX_MAX_CURSOR_HEIGHT ||
790 width == 0 || height == 0)
791 return -EINVAL;
792 rc = VBoxQueryConfHGSMI(vbox->guest_pool,
793 VBOX_VBVA_CONF32_CURSOR_CAPABILITIES, &caps);
794 ret = rc == VINF_SUCCESS ? 0 : rc == VERR_NO_MEMORY ? -ENOMEM : -EINVAL;
795 if (ret)
796 return ret;
797
798 if (!(caps & VBOX_VBVA_CURSOR_CAPABILITY_HARDWARE))
799 /*
800 * -EINVAL means cursor_set2() not supported, -EAGAIN means
801 * retry at once.
802 */
803 return -EBUSY;
804
805#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0) || defined(RHEL_74)
806 obj = drm_gem_object_lookup(file_priv, handle);
807#else
808 obj = drm_gem_object_lookup(crtc->dev, file_priv, handle);
809#endif
810 if (obj) {
811 bo = gem_to_vbox_bo(obj);
812 ret = vbox_bo_reserve(bo, false);
813 if (!ret) {
814 /*
815 * The mask must be calculated based on the alpha
816 * channel, one bit per ARGB word, and must be 32-bit
817 * padded.
818 */
819 mask_size = ((width + 7) / 8 * height + 3) & ~3;
820 data_size = width * height * 4 + mask_size;
821 vbox->cursor_hot_x = hot_x;
822 vbox->cursor_hot_y = hot_y;
823 vbox->cursor_width = width;
824 vbox->cursor_height = height;
825 vbox->cursor_data_size = data_size;
826 dst = vbox->cursor_data;
827 ret =
828 ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages,
829 &uobj_map);
830 if (!ret) {
831 src =
832 ttm_kmap_obj_virtual(&uobj_map,
833 &src_isiomem);
834 if (!src_isiomem) {
835 u32 flags =
836 VBOX_MOUSE_POINTER_VISIBLE |
837 VBOX_MOUSE_POINTER_SHAPE |
838 VBOX_MOUSE_POINTER_ALPHA;
839 copy_cursor_image(src, dst, width,
840 height, mask_size);
841 rc = VBoxHGSMIUpdatePointerShape(
842 vbox->guest_pool, flags,
843 vbox->cursor_hot_x,
844 vbox->cursor_hot_y,
845 width, height, dst, data_size);
846 ret =
847 rc == VINF_SUCCESS ? 0 : rc ==
848 VERR_NO_MEMORY ? -ENOMEM : rc ==
849 VERR_NOT_SUPPORTED ? -EBUSY :
850 -EINVAL;
851 } else {
852 DRM_ERROR("src cursor bo should be in main memory\n");
853 }
854 ttm_bo_kunmap(&uobj_map);
855 } else {
856 vbox->cursor_data_size = 0;
857 }
858 vbox_bo_unreserve(bo);
859 }
860 drm_gem_object_unreference_unlocked(obj);
861 } else {
862 DRM_ERROR("Cannot find cursor object %x for crtc\n", handle);
863 ret = -ENOENT;
864 }
865
866 return ret;
867}
868
869static int vbox_cursor_move(struct drm_crtc *crtc, int x, int y)
870{
871 struct vbox_private *vbox = crtc->dev->dev_private;
872 s32 crtc_x =
873 vbox->single_framebuffer ? crtc->x : to_vbox_crtc(crtc)->x_hint;
874 s32 crtc_y =
875 vbox->single_framebuffer ? crtc->y : to_vbox_crtc(crtc)->y_hint;
876 int rc;
877
878 x += vbox->cursor_hot_x;
879 y += vbox->cursor_hot_y;
880 if (x + crtc_x < 0 || y + crtc_y < 0 ||
881 x + crtc_x >= vbox->input_mapping_width ||
882 y + crtc_y >= vbox->input_mapping_width ||
883 vbox->cursor_data_size == 0)
884 return 0;
885 rc = VBoxHGSMICursorPosition(vbox->guest_pool, true, x + crtc_x,
886 y + crtc_y, NULL, NULL);
887 return rc == VINF_SUCCESS ? 0 : rc == VERR_NO_MEMORY ? -ENOMEM : rc ==
888 VERR_NOT_SUPPORTED ? -EBUSY : -EINVAL;
889}
Note: See TracBrowser for help on using the repository browser.

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