VirtualBox

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

Last change on this file since 65193 was 64919, checked in by vboxsync, 8 years ago

bugref:8677: Additions/Graphics/Wayland: Fedora 25 issues: fix sending virtual screen offset hints (recent guests only). If the hints are not for disjoint screen areas (GNOME Shell requires this), replace them with default ones. Having valid hints lets us know the virtual screen layout inside GNOME Shell/Wayland unless the user has manually changed it inside the guest, and we need this information to get the (absolute) pointer input mapping right. The code also detects and handles separately the special cases of the fbdev console being active and X.Org (a single large framebuffer for all screens in video memory).

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