VirtualBox

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

Last change on this file since 58222 was 58129, checked in by vboxsync, 9 years ago

linux/drm: Fixed incorrect file headers. (copy + past is difficult, apparently)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.0 KB
Line 
1/* $Id: vbox_mode.c 58129 2015-10-08 22:29:48Z 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-vbox
24 * Copyright (c) 2005 ASPEED Technology Inc.
25 *
26 * Permission is hereby granted, free of charge, to any person obtaining a
27 * copy of this software and associated documentation files (the
28 * "Software"), to deal in the Software without restriction, including
29 * without limitation the rights to use, copy, modify, merge, publish,
30 * distribute, sub license, and/or sell copies of the Software, and to
31 * permit persons to whom the Software is furnished to do so, subject to
32 * the following conditions:
33 *
34 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
35 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
36 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
37 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
38 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
39 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
40 * USE OR OTHER DEALINGS IN THE SOFTWARE.
41 *
42 * The above copyright notice and this permission notice (including the
43 * next paragraph) shall be included in all copies or substantial portions
44 * of the Software.
45 *
46 */
47/*
48 * Authors: Dave Airlie <[email protected]>
49 */
50#include "vbox_drv.h"
51
52#include <VBox/VBoxVideo.h>
53
54#include <linux/export.h>
55#include <drm/drm_crtc_helper.h>
56#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
57# include <drm/drm_plane_helper.h>
58#endif
59
60static int vbox_cursor_set2(struct drm_crtc *crtc, struct drm_file *file_priv,
61 uint32_t handle, uint32_t width, uint32_t height,
62 int32_t hot_x, int32_t hot_y);
63static int vbox_cursor_move(struct drm_crtc *crtc, int x, int y);
64
65/** Set a graphics mode. Poke any required values into registers, do an HGSMI
66 * mode set and tell the host we support advanced graphics functions.
67 */
68static void vbox_do_modeset(struct drm_crtc *crtc,
69 const struct drm_display_mode *mode)
70{
71 struct vbox_crtc *vbox_crtc = to_vbox_crtc(crtc);
72 struct vbox_private *vbox;
73 int width, height, cBPP, pitch;
74 unsigned iCrtc;
75 uint16_t fFlags;
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 iCrtc = vbox_crtc->crtc_id;
83 cBPP = 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 * cBPP / 8;
86#else
87 pitch = crtc->enabled ? CRTC_FB(crtc)->pitches[0] : width * cBPP / 8;
88#endif
89 /* if (vbox_crtc->crtc_id == 0 && crtc->enabled)
90 VBoxVideoSetModeRegisters(width, height, pitch * 8 / cBPP,
91 CRTC_FB(crtc)->bits_per_pixel, 0,
92 crtc->x, crtc->y); */
93 fFlags = VBVA_SCREEN_F_ACTIVE;
94 fFlags |= (crtc->enabled ? 0 : VBVA_SCREEN_F_DISABLED);
95 VBoxHGSMIProcessDisplayInfo(&vbox->Ctx, vbox_crtc->crtc_id,
96 crtc->x, crtc->y,
97 crtc->x * cBPP / 8 + crtc->y * pitch,
98 pitch, width, height,
99 vbox_crtc->fBlanked ? 0 : cBPP, fFlags);
100 LogFunc(("vboxvideo: %d\n", __LINE__));
101}
102
103static int vbox_set_view(struct drm_crtc *crtc)
104{
105 struct vbox_crtc *vbox_crtc = to_vbox_crtc(crtc);
106 struct vbox_private *vbox = crtc->dev->dev_private;
107 void *p;
108
109 LogFunc(("vboxvideo: %d: vbox_crtc=%p\n", __LINE__, vbox_crtc));
110 /* Tell the host about the view. This design originally targeted the
111 * Windows XP driver architecture and assumed that each screen would have
112 * a dedicated frame buffer with the command buffer following it, the whole
113 * being a "view". The host works out which screen a command buffer belongs
114 * to by checking whether it is in the first view, then whether it is in the
115 * second and so on. The first match wins. We cheat around this by making
116 * the first view be the managed memory plus the first command buffer, the
117 * second the same plus the second buffer and so on. */
118 p = VBoxHGSMIBufferAlloc(&vbox->Ctx, sizeof(VBVAINFOVIEW), HGSMI_CH_VBVA,
119 VBVA_INFO_VIEW);
120 if (p)
121 {
122 VBVAINFOVIEW *pInfo = (VBVAINFOVIEW *)p;
123 pInfo->u32ViewIndex = vbox_crtc->crtc_id;
124 pInfo->u32ViewOffset = vbox_crtc->offFB;
125 pInfo->u32ViewSize = vbox->vram_size - vbox_crtc->offFB
126 + vbox_crtc->crtc_id * VBVA_MIN_BUFFER_SIZE;
127 pInfo->u32MaxScreenSize = vbox->vram_size - vbox_crtc->offFB;
128 VBoxHGSMIBufferSubmit(&vbox->Ctx, p);
129 VBoxHGSMIBufferFree(&vbox->Ctx, p);
130 }
131 else
132 return -ENOMEM;
133 LogFunc(("vboxvideo: %d: p=%p\n", __LINE__, p));
134 return 0;
135}
136
137static void vbox_crtc_load_lut(struct drm_crtc *crtc)
138{
139
140}
141
142static void vbox_crtc_dpms(struct drm_crtc *crtc, int mode)
143{
144 struct vbox_crtc *vbox_crtc = to_vbox_crtc(crtc);
145 struct vbox_private *vbox = crtc->dev->dev_private;
146 unsigned long flags;
147
148 LogFunc(("vboxvideo: %d: vbox_crtc=%p, mode=%d\n", __LINE__, vbox_crtc,
149 mode));
150 switch (mode)
151 {
152 case DRM_MODE_DPMS_ON:
153 vbox_crtc->fBlanked = false;
154 break;
155 case DRM_MODE_DPMS_STANDBY:
156 case DRM_MODE_DPMS_SUSPEND:
157 case DRM_MODE_DPMS_OFF:
158 vbox_crtc->fBlanked = true;
159 break;
160 }
161 spin_lock_irqsave(&vbox->dev_lock, flags);
162 vbox_do_modeset(crtc, &crtc->hwmode);
163 spin_unlock_irqrestore(&vbox->dev_lock, flags);
164 LogFunc(("vboxvideo: %d\n", __LINE__));
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
174static int vbox_crtc_do_set_base(struct drm_crtc *crtc,
175 struct drm_framebuffer *fb,
176 int x, int y, int atomic)
177{
178 struct vbox_private *vbox = crtc->dev->dev_private;
179 struct vbox_crtc *vbox_crtc = to_vbox_crtc(crtc);
180 struct drm_gem_object *obj;
181 struct vbox_framebuffer *vbox_fb;
182 struct vbox_bo *bo;
183 int ret;
184 u64 gpu_addr;
185
186 LogFunc(("vboxvideo: %d: fb=%p, vbox_crtc=%p\n", __LINE__, fb, vbox_crtc));
187
188 vbox_fb = to_vbox_framebuffer(CRTC_FB(crtc));
189 obj = vbox_fb->obj;
190 bo = gem_to_vbox_bo(obj);
191
192 ret = vbox_bo_reserve(bo, false);
193 if (ret)
194 return ret;
195
196 ret = vbox_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr);
197 if (ret)
198 {
199 vbox_bo_unreserve(bo);
200 return ret;
201 }
202
203 if (&vbox->fbdev->afb == vbox_fb)
204 {
205 /* if pushing console in kmap it */
206 ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
207 if (ret)
208 DRM_ERROR("failed to kmap fbcon\n");
209 }
210 vbox_bo_unreserve(bo);
211
212 /* vbox_set_start_address_crt1(crtc, (u32)gpu_addr); */
213 vbox_crtc->offFB = gpu_addr;
214
215 LogFunc(("vboxvideo: %d: vbox_fb=%p, obj=%p, bo=%p, gpu_addr=%u\n",
216 __LINE__, vbox_fb, obj, bo, (unsigned)gpu_addr));
217 return 0;
218}
219
220static int vbox_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
221 struct drm_framebuffer *old_fb)
222{
223 LogFunc(("vboxvideo: %d\n", __LINE__));
224 return vbox_crtc_do_set_base(crtc, old_fb, x, y, 0);
225}
226
227static int vbox_crtc_mode_set(struct drm_crtc *crtc,
228 struct drm_display_mode *mode,
229 struct drm_display_mode *adjusted_mode,
230 int x, int y,
231 struct drm_framebuffer *old_fb)
232{
233 struct vbox_private *vbox = crtc->dev->dev_private;
234 unsigned long flags;
235 int rc = 0;
236
237 LogFunc(("vboxvideo: %d: vbox=%p\n", __LINE__, vbox));
238 vbox_crtc_mode_set_base(crtc, x, y, old_fb);
239 spin_lock_irqsave(&vbox->dev_lock, flags);
240 rc = vbox_set_view(crtc);
241 if (!rc)
242 vbox_do_modeset(crtc, mode);
243 spin_unlock_irqrestore(&vbox->dev_lock, flags);
244 LogFunc(("vboxvideo: %d\n", __LINE__));
245 return rc;
246}
247
248static void vbox_crtc_disable(struct drm_crtc *crtc)
249{
250
251}
252
253static void vbox_crtc_prepare(struct drm_crtc *crtc)
254{
255
256}
257
258static void vbox_crtc_commit(struct drm_crtc *crtc)
259{
260
261}
262
263
264static const struct drm_crtc_helper_funcs vbox_crtc_helper_funcs =
265{
266 .dpms = vbox_crtc_dpms,
267 .mode_fixup = vbox_crtc_mode_fixup,
268 .mode_set = vbox_crtc_mode_set,
269 /* .mode_set_base = vbox_crtc_mode_set_base, */
270 .disable = vbox_crtc_disable,
271 .load_lut = vbox_crtc_load_lut,
272 .prepare = vbox_crtc_prepare,
273 .commit = vbox_crtc_commit,
274
275};
276
277static void vbox_crtc_reset(struct drm_crtc *crtc)
278{
279
280}
281
282
283static void vbox_crtc_destroy(struct drm_crtc *crtc)
284{
285 drm_crtc_cleanup(crtc);
286 kfree(crtc);
287}
288
289static const struct drm_crtc_funcs vbox_crtc_funcs =
290{
291 .cursor_move = vbox_cursor_move,
292#ifdef DRM_IOCTL_MODE_CURSOR2
293 .cursor_set2 = vbox_cursor_set2,
294#endif
295 .reset = vbox_crtc_reset,
296 .set_config = drm_crtc_helper_set_config,
297 /* .gamma_set = vbox_crtc_gamma_set, */
298 .destroy = vbox_crtc_destroy,
299};
300
301int vbox_crtc_init(struct drm_device *pDev, unsigned i)
302{
303 struct vbox_crtc *pCrtc;
304
305 LogFunc(("vboxvideo: %d\n", __LINE__));
306 pCrtc = kzalloc(sizeof(struct vbox_crtc), GFP_KERNEL);
307 if (!pCrtc)
308 return -ENOMEM;
309 pCrtc->crtc_id = i;
310
311 drm_crtc_init(pDev, &pCrtc->base, &vbox_crtc_funcs);
312 drm_mode_crtc_set_gamma_size(&pCrtc->base, 256);
313 drm_crtc_helper_add(&pCrtc->base, &vbox_crtc_helper_funcs);
314 LogFunc(("vboxvideo: %d: pCrtc=%p\n", __LINE__, pCrtc));
315
316 return 0;
317}
318
319
320static void vbox_encoder_destroy(struct drm_encoder *encoder)
321{
322 LogFunc(("vboxvideo: %d: encoder=%p\n", __LINE__, encoder));
323 drm_encoder_cleanup(encoder);
324 kfree(encoder);
325}
326
327
328static struct drm_encoder *vbox_best_single_encoder(struct drm_connector *connector)
329{
330 int enc_id = connector->encoder_ids[0];
331 struct drm_mode_object *obj;
332 struct drm_encoder *encoder;
333
334 LogFunc(("vboxvideo: %d: connector=%p\n", __LINE__, connector));
335 /* pick the encoder ids */
336 if (enc_id)
337 {
338 obj = drm_mode_object_find(connector->dev, enc_id, DRM_MODE_OBJECT_ENCODER);
339 if (!obj)
340 return NULL;
341 encoder = obj_to_encoder(obj);
342 LogFunc(("vboxvideo: %d: encoder=%p\n", __LINE__, encoder));
343 return encoder;
344 }
345 LogFunc(("vboxvideo: %d\n", __LINE__));
346 return NULL;
347}
348
349
350static const struct drm_encoder_funcs vbox_enc_funcs =
351{
352 .destroy = vbox_encoder_destroy,
353};
354
355static void vbox_encoder_dpms(struct drm_encoder *encoder, int mode)
356{
357
358}
359
360static bool vbox_mode_fixup(struct drm_encoder *encoder,
361 const struct drm_display_mode *mode,
362 struct drm_display_mode *adjusted_mode)
363{
364 return true;
365}
366
367static void vbox_encoder_mode_set(struct drm_encoder *encoder,
368 struct drm_display_mode *mode,
369 struct drm_display_mode *adjusted_mode)
370{
371}
372
373static void vbox_encoder_prepare(struct drm_encoder *encoder)
374{
375
376}
377
378static void vbox_encoder_commit(struct drm_encoder *encoder)
379{
380
381}
382
383
384static const struct drm_encoder_helper_funcs vbox_enc_helper_funcs =
385{
386 .dpms = vbox_encoder_dpms,
387 .mode_fixup = vbox_mode_fixup,
388 .prepare = vbox_encoder_prepare,
389 .commit = vbox_encoder_commit,
390 .mode_set = vbox_encoder_mode_set,
391};
392
393struct drm_encoder *vbox_encoder_init(struct drm_device *dev, unsigned i)
394{
395 struct vbox_encoder *vbox_encoder;
396
397 LogFunc(("vboxvideo: %d: dev=%d\n", __LINE__));
398 vbox_encoder = kzalloc(sizeof(struct vbox_encoder), GFP_KERNEL);
399 if (!vbox_encoder)
400 return NULL;
401
402 drm_encoder_init(dev, &vbox_encoder->base, &vbox_enc_funcs,
403 DRM_MODE_ENCODER_DAC);
404 drm_encoder_helper_add(&vbox_encoder->base, &vbox_enc_helper_funcs);
405
406 vbox_encoder->base.possible_crtcs = 1 << i;
407 LogFunc(("vboxvideo: %d: vbox_encoder=%p\n", __LINE__, vbox_encoder));
408 return &vbox_encoder->base;
409}
410
411static int vbox_get_modes(struct drm_connector *pConnector)
412{
413 struct vbox_connector *pVBoxConnector = NULL;
414 struct drm_display_mode *pMode = NULL;
415 unsigned cModes = 0;
416
417 LogFunc(("vboxvideo: %d: pConnector=%p\n", __LINE__, pConnector));
418 pVBoxConnector = to_vbox_connector(pConnector);
419 cModes = drm_add_modes_noedid(pConnector, 1024, 768);
420 if (pVBoxConnector->modeHint.cX && pVBoxConnector->modeHint.cY)
421 {
422 pMode = drm_cvt_mode(pConnector->dev, pVBoxConnector->modeHint.cX,
423 pVBoxConnector->modeHint.cY, 60, false, false,
424 false);
425 if (pMode)
426 {
427 pMode->type |= DRM_MODE_TYPE_PREFERRED;
428 drm_mode_probed_add(pConnector, pMode);
429 ++cModes;
430 }
431 }
432 return cModes;
433}
434
435static int vbox_mode_valid(struct drm_connector *connector,
436 struct drm_display_mode *mode)
437{
438 return MODE_OK;
439}
440
441static void vbox_connector_destroy(struct drm_connector *pConnector)
442{
443 struct vbox_connector *pVBoxConnector = NULL;
444
445 LogFunc(("vboxvideo: %d: connector=%p\n", __LINE__, pConnector));
446 pVBoxConnector = to_vbox_connector(pConnector);
447 device_remove_file(pConnector->dev->dev, &pVBoxConnector->deviceAttribute);
448#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
449 drm_sysfs_connector_remove(pConnector);
450#else
451 drm_connector_unregister(pConnector);
452#endif
453 drm_connector_cleanup(pConnector);
454 kfree(pConnector);
455}
456
457static enum drm_connector_status
458vbox_connector_detect(struct drm_connector *connector, bool force)
459{
460 return connector_status_connected;
461}
462
463static const struct drm_connector_helper_funcs vbox_connector_helper_funcs =
464{
465 .mode_valid = vbox_mode_valid,
466 .get_modes = vbox_get_modes,
467 .best_encoder = vbox_best_single_encoder,
468};
469
470static const struct drm_connector_funcs vbox_connector_funcs =
471{
472 .dpms = drm_helper_connector_dpms,
473 .detect = vbox_connector_detect,
474 .fill_modes = drm_helper_probe_single_connector_modes,
475 .destroy = vbox_connector_destroy,
476};
477
478ssize_t vbox_connector_write_sysfs(struct device *pDev,
479 struct device_attribute *pAttr,
480 const char *psz, size_t cch)
481{
482 struct vbox_connector *pVBoxConnector;
483 struct drm_device *pDrmDev;
484 struct vbox_private *pVBox;
485 int cX, cY;
486 char ch;
487
488 LogFunc(("vboxvideo: %d: pDev=%p, pAttr=%p, psz=%s, cch=%llu\n", __LINE__,
489 pDev, pAttr, psz, (unsigned long long)cch));
490 pVBoxConnector = container_of(pAttr, struct vbox_connector,
491 deviceAttribute);
492 pDrmDev = pVBoxConnector->base.dev;
493 pVBox = pDrmDev->dev_private;
494 if (sscanf(psz, "%5dx%5d\n%c", &cX, &cY, &ch) != 2)
495 return -EINVAL;
496 if ( cX < 64 || cX > VBE_DISPI_MAX_XRES
497 || cY < 64 || cY > VBE_DISPI_MAX_YRES)
498 return -EINVAL;
499 pVBoxConnector->modeHint.cX = (uint16_t)cX;
500 pVBoxConnector->modeHint.cY = (uint16_t)cY;
501 drm_helper_hpd_irq_event(pVBoxConnector->base.dev);
502 if (pVBox->fbdev)
503 drm_fb_helper_hotplug_event(&pVBox->fbdev->helper);
504 LogFunc(("vboxvideo: %d\n", __LINE__));
505 return cch;
506}
507
508int vbox_connector_init(struct drm_device *pDev, unsigned cScreen,
509 struct drm_encoder *pEncoder)
510{
511 struct vbox_connector *pVBoxConnector;
512 struct drm_connector *pConnector;
513 int rc;
514
515 LogFunc(("vboxvideo: %d: pDev=%p, pEncoder=%p\n", __LINE__, pDev,
516 pEncoder));
517 pVBoxConnector = kzalloc(sizeof(struct vbox_connector), GFP_KERNEL);
518 if (!pVBoxConnector)
519 return -ENOMEM;
520
521 pConnector = &pVBoxConnector->base;
522
523 /*
524 * Set up the sysfs file we use for getting video mode hints from user
525 * space.
526 */
527 snprintf(pVBoxConnector->szName, sizeof(pVBoxConnector->szName),
528 "vbox_screen_%u", cScreen);
529 pVBoxConnector->deviceAttribute.attr.name = pVBoxConnector->szName;
530 pVBoxConnector->deviceAttribute.attr.mode = S_IWUSR;
531 pVBoxConnector->deviceAttribute.show = NULL;
532 pVBoxConnector->deviceAttribute.store = vbox_connector_write_sysfs;
533 rc = device_create_file(pDev->dev, &pVBoxConnector->deviceAttribute);
534 if (rc < 0)
535 {
536 kfree(pVBoxConnector);
537 return rc;
538 }
539 drm_connector_init(pDev, pConnector, &vbox_connector_funcs,
540 DRM_MODE_CONNECTOR_VGA);
541 drm_connector_helper_add(pConnector, &vbox_connector_helper_funcs);
542
543 pConnector->interlace_allowed = 0;
544 pConnector->doublescan_allowed = 0;
545
546#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
547 drm_sysfs_connector_add(pConnector);
548#else
549 drm_connector_register(pConnector);
550#endif
551
552 /* The connector supports hot-plug detection: we promise to call
553 * "drm_helper_hpd_irq_event" when hot-plugging occurs. */
554 pConnector->polled = DRM_CONNECTOR_POLL_HPD;
555
556 drm_mode_connector_attach_encoder(pConnector, pEncoder);
557
558 LogFunc(("vboxvideo: %d: pConnector=%p\n", __LINE__, pConnector));
559 return 0;
560}
561
562#if 0
563/* allocate cursor cache and pin at start of VRAM */
564int vbox_cursor_init(struct drm_device *dev)
565{
566 struct vbox_private *vbox = dev->dev_private;
567 int size;
568 int ret;
569 struct drm_gem_object *obj;
570 struct vbox_bo *bo;
571 uint64_t gpu_addr;
572
573 size = (AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE) * AST_DEFAULT_HWC_NUM;
574
575 ret = vbox_gem_create(dev, size, true, &obj);
576 if (ret)
577 return ret;
578 bo = gem_to_vbox_bo(obj);
579 ret = vbox_bo_reserve(bo, false);
580 if (unlikely(ret != 0))
581 goto fail;
582
583 ret = vbox_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr);
584 vbox_bo_unreserve(bo);
585 if (ret)
586 goto fail;
587
588 /* kmap the object */
589 ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &vbox->cache_kmap);
590 if (ret)
591 goto fail;
592
593 vbox->cursor_cache = obj;
594 vbox->cursor_cache_gpu_addr = gpu_addr;
595 DRM_DEBUG_KMS("pinned cursor cache at %llx\n", vbox->cursor_cache_gpu_addr);
596 return 0;
597fail:
598 return ret;
599}
600
601void vbox_cursor_fini(struct drm_device *dev)
602{
603 struct vbox_private *vbox = dev->dev_private;
604 ttm_bo_kunmap(&vbox->cache_kmap);
605 drm_gem_object_unreference_unlocked(vbox->cursor_cache);
606}
607#endif
608
609int vbox_mode_init(struct drm_device *pDev)
610{
611 struct vbox_private *pVBox = pDev->dev_private;
612 struct drm_encoder *pEncoder;
613 unsigned i;
614 /* vbox_cursor_init(dev); */
615 LogFunc(("vboxvideo: %d: pDev=%p\n", __LINE__, pDev));
616 for (i = 0; i < pVBox->cCrtcs; ++i)
617 {
618 vbox_crtc_init(pDev, i);
619 pEncoder = vbox_encoder_init(pDev, i);
620 if (pEncoder)
621 vbox_connector_init(pDev, i, pEncoder);
622 }
623 return 0;
624}
625
626void vbox_mode_fini(struct drm_device *dev)
627{
628 /* vbox_cursor_fini(dev); */
629}
630
631
632void VBoxRefreshModes(struct drm_device *pDev)
633{
634 struct vbox_private *vbox = pDev->dev_private;
635 struct drm_crtc *crtci;
636 unsigned long flags;
637
638 LogFunc(("vboxvideo: %d\n", __LINE__));
639 spin_lock_irqsave(&vbox->dev_lock, flags);
640 list_for_each_entry(crtci, &pDev->mode_config.crtc_list, head)
641 vbox_do_modeset(crtci, &crtci->hwmode);
642 spin_unlock_irqrestore(&vbox->dev_lock, flags);
643 LogFunc(("vboxvideo: %d\n", __LINE__));
644}
645
646
647/** Copy the ARGB image and generate the mask, which is needed in case the host
648 * does not support ARGB cursors. The mask is a 1BPP bitmap with the bit set
649 * if the corresponding alpha value in the ARGB image is greater than 0xF0. */
650static void copy_cursor_image(u8 *src, u8 *dst, int width, int height,
651 size_t cbMask)
652{
653 unsigned i, j;
654 size_t cbLine = (width + 7) / 8;
655
656 memcpy(dst + cbMask, src, width * height * 4);
657 for (i = 0; i < height; ++i)
658 for (j = 0; j < width; ++j)
659 if (((uint32_t *)src)[i * width + j] > 0xf0000000)
660 dst[i * cbLine + j / 8] |= (0x80 >> (j % 8));
661}
662
663static int vbox_cursor_set2(struct drm_crtc *crtc, struct drm_file *file_priv,
664 uint32_t handle, uint32_t width, uint32_t height,
665 int32_t hot_x, int32_t hot_y)
666{
667 struct vbox_private *vbox = crtc->dev->dev_private;
668 struct vbox_crtc *vbox_crtc = to_vbox_crtc(crtc);
669 struct drm_gem_object *obj;
670 struct vbox_bo *bo;
671 int ret, rc;
672 struct ttm_bo_kmap_obj uobj_map;
673 u8 *src;
674 u8 *dst = NULL;
675 size_t cbData, cbMask;
676 bool src_isiomem;
677
678 if (!handle) {
679 /* Hide cursor. */
680 VBoxHGSMIUpdatePointerShape(&vbox->Ctx, 0, 0, 0, 0, 0, NULL, 0);
681 return 0;
682 }
683 if ( width > VBOX_MAX_CURSOR_WIDTH || height > VBOX_MAX_CURSOR_HEIGHT
684 || width == 0 || hot_x > width || height == 0 || hot_y > height)
685 return -EINVAL;
686
687 obj = drm_gem_object_lookup(crtc->dev, file_priv, handle);
688 if (obj)
689 {
690 bo = gem_to_vbox_bo(obj);
691 ret = vbox_bo_reserve(bo, false);
692 if (!ret)
693 {
694 /* The mask must be calculated based on the alpha channel, one bit
695 * per ARGB word, and must be 32-bit padded. */
696 cbMask = ((width + 7) / 8 * height + 3) & ~3;
697 cbData = width * height * 4 + cbMask;
698 dst = kmalloc(cbData, GFP_KERNEL);
699 if (dst)
700 {
701 ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &uobj_map);
702 if (!ret)
703 {
704 src = ttm_kmap_obj_virtual(&uobj_map, &src_isiomem);
705 if (!src_isiomem)
706 {
707 uint32_t fFlags = VBOX_MOUSE_POINTER_VISIBLE
708 | VBOX_MOUSE_POINTER_SHAPE
709 | VBOX_MOUSE_POINTER_ALPHA;
710 copy_cursor_image(src, dst, width, height, cbMask);
711 rc = VBoxHGSMIUpdatePointerShape(&vbox->Ctx, fFlags,
712 hot_x, hot_y, width,
713 height, dst, cbData);
714 ret = RTErrConvertToErrno(rc);
715 }
716 else
717 DRM_ERROR("src cursor bo should be in main memory\n");
718 ttm_bo_kunmap(&uobj_map);
719 }
720 kfree(dst);
721 }
722 vbox_bo_unreserve(bo);
723 }
724 drm_gem_object_unreference_unlocked(obj);
725 }
726 else
727 {
728 DRM_ERROR("Cannot find cursor object %x for crtc\n", handle);
729 ret = -ENOENT;
730 }
731 return ret;
732}
733
734static int vbox_cursor_move(struct drm_crtc *crtc,
735 int x, int y)
736{
737 return 0;
738}
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