VirtualBox

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

Last change on this file since 68848 was 68848, checked in by vboxsync, 7 years ago

Additions/linux/drm: lots of formatting changes to match kernel style.
bugref:8524: Additions/linux: play nicely with distribution-installed Additions

This change makes a lot of formatting changes to the Linux Additions drm
driver, with no intended changes to functionality, and much of the
formatting change done using the sed script which installs the driver
sources to the Additions archive. Hans de Goede's clean-up of the driver for
submission to staging is the base for these changes.

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