VirtualBox

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

Last change on this file since 91413 was 90577, checked in by vboxsync, 3 years ago

Linux Host and Guest drivers: another attempt to introduce initial support for RHEL 8.5 kernels, bugref:4567.

CentOS kernel 4.18.0-326.el8 (RHEL 8,5) has backported commits from vanilla kernel 5.10+.
Fedora kernel 5.9.0-36.eln104 (RHEL 8,99) does not have some of these changes yet.
This commit attempts to move relevant code into RHEL 8,5 specific section. For some
parts of DRM code, changes are only affect RHEL 8,5 (8,99 is excluded) due to missing
commits (on 8,99) from newer kernels.

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