VirtualBox

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

Last change on this file since 66891 was 66544, checked in by vboxsync, 8 years ago

bugref:8524: Additions/linux: play nicely with distribution-installed Additions
Change header of files which are expected to end up in the Linux kernel to the MIT licence to simplify life for people wanting to port vboxvideo to other kernels and to simplify synchronising changes back to VirtualBox. Update author information in files which have it, but do not add it to files which do not.

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