VirtualBox

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

Last change on this file since 60307 was 60300, checked in by vboxsync, 9 years ago

bugref:8087: Additions/x11: support non-root X server: add heuristic code to the kernel driver to detect the cursor hot-spot in case we are running old user space code which does not tell us about it. In theory we could easily extend this to work with older kernel versions which did not have the hot-spot API at all, but since older versions of X.Org could not use kernel drivers by default it does not gain us much.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.4 KB
Line 
1/* $Id: vbox_mode.c 60300 2016-04-03 19:31:33Z vboxsync $ */
2/** @file
3 * VirtualBox Additions Linux kernel video driver
4 */
5
6/*
7 * Copyright (C) 2013 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 <airlied@redhat.com>
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
77 LogFunc(("vboxvideo: %d: vbox_crtc=%p, CRTC_FB(crtc)=%p\n", __LINE__,
78 vbox_crtc, CRTC_FB(crtc)));
79 vbox = crtc->dev->dev_private;
80 width = mode->hdisplay ? mode->hdisplay : 640;
81 height = mode->vdisplay ? mode->vdisplay : 480;
82 crtc_id = vbox_crtc->crtc_id;
83 bpp = crtc->enabled ? CRTC_FB(crtc)->bits_per_pixel : 32;
84#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
85 pitch = crtc->enabled ? CRTC_FB(crtc)->pitch : width * bpp / 8;
86#else
87 pitch = crtc->enabled ? CRTC_FB(crtc)->pitches[0] : width * bpp / 8;
88#endif
89 /* This is the old way of setting graphics modes. It assumed one screen
90 * and a frame-buffer at the start of video RAM. On older versions of
91 * VirtualBox, certain parts of the code still assume that the first
92 * screen is programmed this way, so try to fake it. */
93 if ( vbox_crtc->crtc_id == 0
94 && crtc->enabled
95 && vbox_crtc->fb_offset / pitch < 0xffff - crtc->y
96 && vbox_crtc->fb_offset % (bpp / 8) == 0)
97 VBoxVideoSetModeRegisters(width, height, pitch * 8 / bpp,
98 CRTC_FB(crtc)->bits_per_pixel, 0,
99 vbox_crtc->fb_offset % pitch / bpp * 8 + crtc->x,
100 vbox_crtc->fb_offset / pitch + crtc->y);
101 flags = VBVA_SCREEN_F_ACTIVE;
102 flags |= (crtc->enabled && !vbox_crtc->blanked ? 0 : VBVA_SCREEN_F_BLANK);
103 flags |= (vbox_crtc->disconnected ? VBVA_SCREEN_F_DISABLED : 0);
104 VBoxHGSMIProcessDisplayInfo(&vbox->submit_info, vbox_crtc->crtc_id,
105 crtc->x, crtc->y,
106 crtc->x * bpp / 8 + crtc->y * pitch,
107 pitch, width, height,
108 vbox_crtc->blanked ? 0 : bpp, flags);
109 VBoxHGSMIReportFlagsLocation(&vbox->submit_info, vbox->host_flags_offset);
110 vbox_enable_caps(vbox);
111 LogFunc(("vboxvideo: %d\n", __LINE__));
112}
113
114static int vbox_set_view(struct drm_crtc *crtc)
115{
116 struct vbox_crtc *vbox_crtc = to_vbox_crtc(crtc);
117 struct vbox_private *vbox = crtc->dev->dev_private;
118 void *p;
119
120 LogFunc(("vboxvideo: %d: vbox_crtc=%p\n", __LINE__, vbox_crtc));
121 /* Tell the host about the view. This design originally targeted the
122 * Windows XP driver architecture and assumed that each screen would have
123 * a dedicated frame buffer with the command buffer following it, the whole
124 * being a "view". The host works out which screen a command buffer belongs
125 * to by checking whether it is in the first view, then whether it is in the
126 * second and so on. The first match wins. We cheat around this by making
127 * the first view be the managed memory plus the first command buffer, the
128 * second the same plus the second buffer and so on. */
129 p = VBoxHGSMIBufferAlloc(&vbox->submit_info, sizeof(VBVAINFOVIEW), HGSMI_CH_VBVA,
130 VBVA_INFO_VIEW);
131 if (p)
132 {
133 VBVAINFOVIEW *pInfo = (VBVAINFOVIEW *)p;
134 pInfo->u32ViewIndex = vbox_crtc->crtc_id;
135 pInfo->u32ViewOffset = vbox_crtc->fb_offset;
136 pInfo->u32ViewSize = vbox->vram_size - vbox_crtc->fb_offset
137 + vbox_crtc->crtc_id * VBVA_MIN_BUFFER_SIZE;
138 pInfo->u32MaxScreenSize = vbox->vram_size - vbox_crtc->fb_offset;
139 VBoxHGSMIBufferSubmit(&vbox->submit_info, p);
140 VBoxHGSMIBufferFree(&vbox->submit_info, p);
141 }
142 else
143 return -ENOMEM;
144 LogFunc(("vboxvideo: %d: p=%p\n", __LINE__, p));
145 return 0;
146}
147
148static void vbox_crtc_load_lut(struct drm_crtc *crtc)
149{
150
151}
152
153static void vbox_crtc_dpms(struct drm_crtc *crtc, int mode)
154{
155 struct vbox_crtc *vbox_crtc = to_vbox_crtc(crtc);
156 struct vbox_private *vbox = crtc->dev->dev_private;
157
158 LogFunc(("vboxvideo: %d: vbox_crtc=%p, mode=%d\n", __LINE__, vbox_crtc,
159 mode));
160 switch (mode) {
161 case DRM_MODE_DPMS_ON:
162 vbox_crtc->blanked = false;
163 break;
164 case DRM_MODE_DPMS_STANDBY:
165 case DRM_MODE_DPMS_SUSPEND:
166 case DRM_MODE_DPMS_OFF:
167 vbox_crtc->blanked = true;
168 break;
169 }
170 mutex_lock(&vbox->hw_mutex);
171 vbox_do_modeset(crtc, &crtc->hwmode);
172 mutex_unlock(&vbox->hw_mutex);
173 LogFunc(("vboxvideo: %d\n", __LINE__));
174}
175
176static bool vbox_crtc_mode_fixup(struct drm_crtc *crtc,
177 const struct drm_display_mode *mode,
178 struct drm_display_mode *adjusted_mode)
179{
180 return true;
181}
182
183/* We move buffers which are not in active use out of VRAM to save memory. */
184static int vbox_crtc_do_set_base(struct drm_crtc *crtc,
185 struct drm_framebuffer *fb,
186 int x, int y, int atomic)
187{
188 struct vbox_private *vbox = crtc->dev->dev_private;
189 struct vbox_crtc *vbox_crtc = to_vbox_crtc(crtc);
190 struct drm_gem_object *obj;
191 struct vbox_framebuffer *vbox_fb;
192 struct vbox_bo *bo;
193 int ret;
194 u64 gpu_addr;
195
196 LogFunc(("vboxvideo: %d: fb=%p, vbox_crtc=%p\n", __LINE__, fb, vbox_crtc));
197 /* push the previous fb to system ram */
198 if (!atomic && fb) {
199 vbox_fb = to_vbox_framebuffer(fb);
200 obj = vbox_fb->obj;
201 bo = gem_to_vbox_bo(obj);
202 ret = vbox_bo_reserve(bo, false);
203 if (ret)
204 return ret;
205 vbox_bo_push_sysram(bo);
206 vbox_bo_unreserve(bo);
207 }
208
209 vbox_fb = to_vbox_framebuffer(CRTC_FB(crtc));
210 obj = vbox_fb->obj;
211 bo = gem_to_vbox_bo(obj);
212
213 ret = vbox_bo_reserve(bo, false);
214 if (ret)
215 return ret;
216
217 ret = vbox_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr);
218 if (ret) {
219 vbox_bo_unreserve(bo);
220 return ret;
221 }
222
223 if (&vbox->fbdev->afb == vbox_fb) {
224 /* if pushing console in kmap it */
225 ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
226 if (ret)
227 DRM_ERROR("failed to kmap fbcon\n");
228 vbox_disable_accel(vbox);
229 vbox_disable_caps(vbox);
230 }
231 else {
232 vbox_enable_accel(vbox);
233 vbox_enable_caps(vbox);
234 }
235 vbox_bo_unreserve(bo);
236
237 /* vbox_set_start_address_crt1(crtc, (u32)gpu_addr); */
238 vbox_crtc->fb_offset = gpu_addr;
239 if (vbox_crtc->crtc_id == 0) {
240 vbox->input_mapping_width = CRTC_FB(crtc)->width;
241 vbox->input_mapping_height = CRTC_FB(crtc)->height;
242 }
243 LogFunc(("vboxvideo: %d: vbox_fb=%p, obj=%p, bo=%p, gpu_addr=%u\n",
244 __LINE__, vbox_fb, obj, bo, (unsigned)gpu_addr));
245 return 0;
246}
247
248static int vbox_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
249 struct drm_framebuffer *old_fb)
250{
251 LogFunc(("vboxvideo: %d\n", __LINE__));
252 return vbox_crtc_do_set_base(crtc, old_fb, x, y, 0);
253}
254
255static int vbox_crtc_mode_set(struct drm_crtc *crtc,
256 struct drm_display_mode *mode,
257 struct drm_display_mode *adjusted_mode,
258 int x, int y,
259 struct drm_framebuffer *old_fb)
260{
261 struct vbox_private *vbox = crtc->dev->dev_private;
262 int rc = 0;
263
264 LogFunc(("vboxvideo: %d: vbox=%p\n", __LINE__, vbox));
265 vbox_crtc_mode_set_base(crtc, x, y, old_fb);
266 mutex_lock(&vbox->hw_mutex);
267 rc = vbox_set_view(crtc);
268 if (!rc)
269 vbox_do_modeset(crtc, mode);
270 /* Note that the input mapping is always relative to the first screen. */
271 VBoxHGSMIUpdateInputMapping(&vbox->submit_info, 0, 0,
272 vbox->input_mapping_width,
273 vbox->input_mapping_height);
274 mutex_unlock(&vbox->hw_mutex);
275 LogFunc(("vboxvideo: %d\n", __LINE__));
276 return rc;
277}
278
279static void vbox_crtc_disable(struct drm_crtc *crtc)
280{
281
282}
283
284static void vbox_crtc_prepare(struct drm_crtc *crtc)
285{
286
287}
288
289static void vbox_crtc_commit(struct drm_crtc *crtc)
290{
291
292}
293
294
295static const struct drm_crtc_helper_funcs vbox_crtc_helper_funcs = {
296 .dpms = vbox_crtc_dpms,
297 .mode_fixup = vbox_crtc_mode_fixup,
298 .mode_set = vbox_crtc_mode_set,
299 /* .mode_set_base = vbox_crtc_mode_set_base, */
300 .disable = vbox_crtc_disable,
301 .load_lut = vbox_crtc_load_lut,
302 .prepare = vbox_crtc_prepare,
303 .commit = vbox_crtc_commit,
304
305};
306
307static void vbox_crtc_reset(struct drm_crtc *crtc)
308{
309
310}
311
312
313static void vbox_crtc_destroy(struct drm_crtc *crtc)
314{
315 drm_crtc_cleanup(crtc);
316 kfree(crtc);
317}
318
319static const struct drm_crtc_funcs vbox_crtc_funcs = {
320 .cursor_move = vbox_cursor_move,
321 .cursor_set2 = vbox_cursor_set2,
322 .reset = vbox_crtc_reset,
323 .set_config = drm_crtc_helper_set_config,
324 /* .gamma_set = vbox_crtc_gamma_set, */
325 .destroy = vbox_crtc_destroy,
326};
327
328static struct vbox_crtc *vbox_crtc_init(struct drm_device *dev, unsigned i)
329{
330 struct vbox_crtc *vbox_crtc;
331
332 LogFunc(("vboxvideo: %d\n", __LINE__));
333 vbox_crtc = kzalloc(sizeof(struct vbox_crtc), GFP_KERNEL);
334 if (!vbox_crtc)
335 return NULL;
336 vbox_crtc->crtc_id = i;
337
338 drm_crtc_init(dev, &vbox_crtc->base, &vbox_crtc_funcs);
339 drm_mode_crtc_set_gamma_size(&vbox_crtc->base, 256);
340 drm_crtc_helper_add(&vbox_crtc->base, &vbox_crtc_helper_funcs);
341 LogFunc(("vboxvideo: %d: crtc=%p\n", __LINE__, vbox_crtc));
342
343 return vbox_crtc;
344}
345
346static void vbox_encoder_destroy(struct drm_encoder *encoder)
347{
348 LogFunc(("vboxvideo: %d: encoder=%p\n", __LINE__, encoder));
349 drm_encoder_cleanup(encoder);
350 kfree(encoder);
351}
352
353#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
354static struct drm_encoder *drm_encoder_find(struct drm_device *dev, uint32_t id)
355{
356 struct drm_mode_object *mo;
357 mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_ENCODER);
358 return mo ? obj_to_encoder(mo) : NULL;
359}
360#endif
361
362static struct drm_encoder *vbox_best_single_encoder(struct drm_connector *connector)
363{
364 int enc_id = connector->encoder_ids[0];
365
366 LogFunc(("vboxvideo: %d: connector=%p\n", __LINE__, connector));
367 /* pick the encoder ids */
368 if (enc_id)
369 return drm_encoder_find(connector->dev, enc_id);
370 LogFunc(("vboxvideo: %d\n", __LINE__));
371 return NULL;
372}
373
374
375static const struct drm_encoder_funcs vbox_enc_funcs = {
376 .destroy = vbox_encoder_destroy,
377};
378
379static void vbox_encoder_dpms(struct drm_encoder *encoder, int mode)
380{
381
382}
383
384static bool vbox_mode_fixup(struct drm_encoder *encoder,
385 const struct drm_display_mode *mode,
386 struct drm_display_mode *adjusted_mode)
387{
388 return true;
389}
390
391static void vbox_encoder_mode_set(struct drm_encoder *encoder,
392 struct drm_display_mode *mode,
393 struct drm_display_mode *adjusted_mode)
394{
395}
396
397static void vbox_encoder_prepare(struct drm_encoder *encoder)
398{
399
400}
401
402static void vbox_encoder_commit(struct drm_encoder *encoder)
403{
404
405}
406
407
408static const struct drm_encoder_helper_funcs vbox_enc_helper_funcs = {
409 .dpms = vbox_encoder_dpms,
410 .mode_fixup = vbox_mode_fixup,
411 .prepare = vbox_encoder_prepare,
412 .commit = vbox_encoder_commit,
413 .mode_set = vbox_encoder_mode_set,
414};
415
416static struct drm_encoder *vbox_encoder_init(struct drm_device *dev, unsigned i)
417{
418 struct vbox_encoder *vbox_encoder;
419
420 LogFunc(("vboxvideo: %d: dev=%d\n", __LINE__));
421 vbox_encoder = kzalloc(sizeof(struct vbox_encoder), GFP_KERNEL);
422 if (!vbox_encoder)
423 return NULL;
424
425 drm_encoder_init(dev, &vbox_encoder->base, &vbox_enc_funcs,
426 DRM_MODE_ENCODER_DAC
427#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
428 , NULL
429#endif
430 );
431 drm_encoder_helper_add(&vbox_encoder->base, &vbox_enc_helper_funcs);
432
433 vbox_encoder->base.possible_crtcs = 1 << i;
434 LogFunc(("vboxvideo: %d: vbox_encoder=%p\n", __LINE__, vbox_encoder));
435 return &vbox_encoder->base;
436}
437
438static int vbox_get_modes(struct drm_connector *connector)
439{
440 struct vbox_connector *vbox_connector = NULL;
441 struct drm_display_mode *mode = NULL;
442 struct vbox_private *vbox = NULL;
443 unsigned num_modes = 0;
444 int preferred_width, preferred_height;
445
446 LogFunc(("vboxvideo: %d: connector=%p\n", __LINE__, connector));
447 vbox_connector = to_vbox_connector(connector);
448 vbox = connector->dev->dev_private;
449 if (!vbox->fbdev_init)
450 return drm_add_modes_noedid(connector, 800, 600);
451 num_modes = drm_add_modes_noedid(connector, 2560, 1600);
452 preferred_width = vbox_connector->mode_hint.width ? vbox_connector->mode_hint.width : 1024;
453 preferred_height = vbox_connector->mode_hint.height ? vbox_connector->mode_hint.height : 768;
454 mode = drm_cvt_mode(connector->dev, preferred_width, preferred_height, 60, false,
455 false, false);
456 if (mode)
457 {
458 mode->type |= DRM_MODE_TYPE_PREFERRED;
459 drm_mode_probed_add(connector, mode);
460 ++num_modes;
461 }
462 return num_modes;
463}
464
465static int vbox_mode_valid(struct drm_connector *connector,
466 struct drm_display_mode *mode)
467{
468 return MODE_OK;
469}
470
471static void vbox_connector_destroy(struct drm_connector *connector)
472{
473 struct vbox_connector *vbox_connector = NULL;
474
475 LogFunc(("vboxvideo: %d: connector=%p\n", __LINE__, connector));
476 vbox_connector = to_vbox_connector(connector);
477#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
478 drm_sysfs_connector_remove(connector);
479#else
480 drm_connector_unregister(connector);
481#endif
482 drm_connector_cleanup(connector);
483 kfree(connector);
484}
485
486static enum drm_connector_status
487vbox_connector_detect(struct drm_connector *connector, bool force)
488{
489 struct vbox_connector *vbox_connector = NULL;
490
491 (void) force;
492 LogFunc(("vboxvideo: %d: connector=%p\n", __LINE__, connector));
493 vbox_connector = to_vbox_connector(connector);
494 return vbox_connector->mode_hint.disconnected ?
495 connector_status_disconnected : connector_status_connected;
496}
497
498static int vbox_fill_modes(struct drm_connector *connector, uint32_t max_x, uint32_t max_y)
499{
500 struct vbox_connector *vbox_connector;
501 struct drm_device *dev;
502 struct drm_display_mode *mode, *iterator;
503
504 LogFunc(("vboxvideo: %d: connector=%p, max_x=%lu, max_y = %lu\n", __LINE__,
505 connector, (unsigned long)max_x, (unsigned long)max_y));
506 vbox_connector = to_vbox_connector(connector);
507 dev = vbox_connector->base.dev;
508 list_for_each_entry_safe(mode, iterator, &connector->modes, head)
509 {
510 list_del(&mode->head);
511 drm_mode_destroy(dev, mode);
512 }
513 return drm_helper_probe_single_connector_modes(connector, max_x, max_y);
514}
515
516static const struct drm_connector_helper_funcs vbox_connector_helper_funcs = {
517 .mode_valid = vbox_mode_valid,
518 .get_modes = vbox_get_modes,
519 .best_encoder = vbox_best_single_encoder,
520};
521
522static const struct drm_connector_funcs vbox_connector_funcs = {
523 .dpms = drm_helper_connector_dpms,
524 .detect = vbox_connector_detect,
525 .fill_modes = vbox_fill_modes,
526 .destroy = vbox_connector_destroy,
527};
528
529static int vbox_connector_init(struct drm_device *dev,
530 struct vbox_crtc *vbox_crtc,
531 struct drm_encoder *encoder)
532{
533 struct vbox_connector *vbox_connector;
534 struct drm_connector *connector;
535
536 LogFunc(("vboxvideo: %d: dev=%p, encoder=%p\n", __LINE__, dev,
537 encoder));
538 vbox_connector = kzalloc(sizeof(struct vbox_connector), GFP_KERNEL);
539 if (!vbox_connector)
540 return -ENOMEM;
541
542 connector = &vbox_connector->base;
543 vbox_connector->vbox_crtc = vbox_crtc;
544
545 drm_connector_init(dev, connector, &vbox_connector_funcs,
546 DRM_MODE_CONNECTOR_VGA);
547 drm_connector_helper_add(connector, &vbox_connector_helper_funcs);
548
549 connector->interlace_allowed = 0;
550 connector->doublescan_allowed = 0;
551
552#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
553 drm_mode_create_suggested_offset_properties(dev);
554 drm_object_attach_property(&connector->base,
555 dev->mode_config.suggested_x_property, 0);
556 drm_object_attach_property(&connector->base,
557 dev->mode_config.suggested_y_property, 0);
558#endif
559#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
560 drm_sysfs_connector_add(connector);
561#else
562 drm_connector_register(connector);
563#endif
564
565 drm_mode_connector_attach_encoder(connector, encoder);
566
567 LogFunc(("vboxvideo: %d: connector=%p\n", __LINE__, connector));
568 return 0;
569}
570
571int vbox_mode_init(struct drm_device *dev)
572{
573 struct vbox_private *vbox = dev->dev_private;
574 struct drm_encoder *encoder;
575 struct vbox_crtc *vbox_crtc;
576 unsigned i;
577 /* vbox_cursor_init(dev); */
578 LogFunc(("vboxvideo: %d: dev=%p\n", __LINE__, dev));
579 for (i = 0; i < vbox->num_crtcs; ++i)
580 {
581 vbox_crtc = vbox_crtc_init(dev, i);
582 if (!vbox_crtc)
583 return -ENOMEM;
584 encoder = vbox_encoder_init(dev, i);
585 if (!encoder)
586 return -ENOMEM;
587 vbox_connector_init(dev, vbox_crtc, encoder);
588 }
589 return 0;
590}
591
592void vbox_mode_fini(struct drm_device *dev)
593{
594 /* vbox_cursor_fini(dev); */
595}
596
597
598void vbox_refresh_modes(struct drm_device *dev)
599{
600 struct vbox_private *vbox = dev->dev_private;
601 struct drm_crtc *crtci;
602
603 LogFunc(("vboxvideo: %d\n", __LINE__));
604 mutex_lock(&vbox->hw_mutex);
605 list_for_each_entry(crtci, &dev->mode_config.crtc_list, head)
606 vbox_do_modeset(crtci, &crtci->hwmode);
607 mutex_unlock(&vbox->hw_mutex);
608 LogFunc(("vboxvideo: %d\n", __LINE__));
609}
610
611
612/** Copy the ARGB image and generate the mask, which is needed in case the host
613 * does not support ARGB cursors. The mask is a 1BPP bitmap with the bit set
614 * if the corresponding alpha value in the ARGB image is greater than 0xF0. */
615static void copy_cursor_image(u8 *src, u8 *dst, int width, int height,
616 size_t mask_size)
617{
618 unsigned i, j;
619 size_t line_size = (width + 7) / 8;
620
621 memcpy(dst + mask_size, src, width * height * 4);
622 for (i = 0; i < height; ++i)
623 for (j = 0; j < width; ++j)
624 if (((uint32_t *)src)[i * width + j] > 0xf0000000)
625 dst[i * line_size + j / 8] |= (0x80 >> (j % 8));
626}
627
628static int vbox_cursor_set2(struct drm_crtc *crtc, struct drm_file *file_priv,
629 uint32_t handle, uint32_t width, uint32_t height,
630 int32_t hot_x, int32_t hot_y)
631{
632 struct vbox_private *vbox = crtc->dev->dev_private;
633 struct vbox_crtc *vbox_crtc = to_vbox_crtc(crtc);
634 struct drm_gem_object *obj;
635 struct vbox_bo *bo;
636 int ret, rc;
637 struct ttm_bo_kmap_obj uobj_map;
638 u8 *src;
639 u8 *dst = NULL;
640 u32 caps = 0;
641 size_t data_size, mask_size;
642 bool src_isiomem;
643
644 if (!handle) {
645 bool cursor_enabled = false;
646 struct drm_crtc *crtci;
647
648 /* Hide cursor. */
649 vbox_crtc->cursor_enabled = false;
650 list_for_each_entry(crtci, &vbox->dev->mode_config.crtc_list, head)
651 if (to_vbox_crtc(crtci)->cursor_enabled)
652 cursor_enabled = true;
653 if (!cursor_enabled)
654 VBoxHGSMIUpdatePointerShape(&vbox->submit_info, 0, 0, 0, 0, 0, NULL, 0);
655 return 0;
656 }
657 vbox_crtc->cursor_enabled = true;
658 if ( width > VBOX_MAX_CURSOR_WIDTH || height > VBOX_MAX_CURSOR_HEIGHT
659 || width == 0 || height == 0)
660 return -EINVAL;
661 rc = VBoxQueryConfHGSMI(&vbox->submit_info,
662 VBOX_VBVA_CONF32_CURSOR_CAPABILITIES, &caps);
663 ret = -RTErrConvertToErrno(rc);
664 if (ret)
665 return ret;
666 if ( caps & VMMDEV_MOUSE_HOST_CANNOT_HWPOINTER
667 || !(caps & VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE))
668 return -EINVAL;
669
670 obj = drm_gem_object_lookup(crtc->dev, file_priv, handle);
671 if (obj)
672 {
673 bo = gem_to_vbox_bo(obj);
674 ret = vbox_bo_reserve(bo, false);
675 if (!ret)
676 {
677 /* The mask must be calculated based on the alpha channel, one bit
678 * per ARGB word, and must be 32-bit padded. */
679 mask_size = ((width + 7) / 8 * height + 3) & ~3;
680 data_size = width * height * 4 + mask_size;
681 vbox->cursor_hot_x = min((uint32_t)max(hot_x, 0), width);
682 vbox->cursor_hot_y = min((uint32_t)max(hot_y, 0), height);
683 vbox->cursor_width = width;
684 vbox->cursor_height = height;
685 vbox->cursor_data_size = data_size;
686 dst = vbox->cursor_data;
687 ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &uobj_map);
688 if (!ret)
689 {
690 src = ttm_kmap_obj_virtual(&uobj_map, &src_isiomem);
691 if (!src_isiomem)
692 {
693 uint32_t flags = VBOX_MOUSE_POINTER_VISIBLE
694 | VBOX_MOUSE_POINTER_SHAPE
695 | VBOX_MOUSE_POINTER_ALPHA;
696 copy_cursor_image(src, dst, width, height, mask_size);
697 rc = VBoxHGSMIUpdatePointerShape(&vbox->submit_info, flags,
698 vbox->cursor_hot_x,
699 vbox->cursor_hot_y,
700 width, height, dst,
701 data_size);
702 ret = -RTErrConvertToErrno(rc);
703 }
704 else
705 DRM_ERROR("src cursor bo should be in main memory\n");
706 ttm_bo_kunmap(&uobj_map);
707 }
708 else
709 vbox->cursor_data_size = 0;
710 vbox_bo_unreserve(bo);
711 }
712 drm_gem_object_unreference_unlocked(obj);
713 }
714 else
715 {
716 DRM_ERROR("Cannot find cursor object %x for crtc\n", handle);
717 ret = -ENOENT;
718 }
719 return ret;
720}
721
722static int vbox_cursor_move(struct drm_crtc *crtc,
723 int x, int y)
724{
725 struct vbox_private *vbox = crtc->dev->dev_private;
726 uint32_t flags = VBOX_MOUSE_POINTER_VISIBLE
727 | VBOX_MOUSE_POINTER_SHAPE
728 | VBOX_MOUSE_POINTER_ALPHA;
729 uint32_t host_x, host_y;
730 uint32_t hot_x = 0;
731 uint32_t hot_y = 0;
732 int rc;
733
734 /* We compare these to unsigned later and don't need to handle negative. */
735 if (x + crtc->x < 0 || y + crtc->y < 0 || vbox->cursor_data_size == 0)
736 return 0;
737 rc = VBoxHGSMICursorPosition(&vbox->submit_info, true, x + crtc->x,
738 y + crtc->y, &host_x, &host_y);
739 if (RT_FAILURE(rc))
740 return -RTErrConvertToErrno(rc);
741 if (x + crtc->x < host_x)
742 hot_x = min(host_x - x - crtc->x, vbox->cursor_width);
743 if (y + crtc->y < host_y)
744 hot_y = min(host_y - y - crtc->y, vbox->cursor_height);
745 if (hot_x == vbox->cursor_hot_x && hot_y == vbox->cursor_hot_y)
746 return 0;
747 vbox->cursor_hot_x = hot_x;
748 vbox->cursor_hot_y = hot_y;
749 rc = VBoxHGSMIUpdatePointerShape(&vbox->submit_info, flags, hot_x, hot_y,
750 vbox->cursor_width, vbox->cursor_height,
751 vbox->cursor_data,
752 vbox->cursor_data_size);
753 return -RTErrConvertToErrno(rc);
754}
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