VirtualBox

source: vbox/trunk/src/VBox/Additions/linux/drm/vbox_irq.c@ 68334

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

Additions/linux/drm: refined the RHEL_7 test to distinguish between RHEL_73 (DRM patchlevel 4.6.5) and RHEL_74 (DRM patchlevel 4.10.13)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 6.5 KB
Line 
1/* $Id: vbox_irq.c 68334 2017-08-08 09:26:39Z vboxsync $ */
2/** @file
3 * VirtualBox Additions Linux kernel video driver
4 */
5
6/*
7 * Copyright (C) 2016-2017 Oracle Corporation
8 * This file is based on qxl_irq.c
9 * Copyright 2013 Red Hat Inc.
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a
12 * copy of this software and associated documentation files (the "Software"),
13 * to deal in the Software without restriction, including without limitation
14 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 * and/or sell copies of the Software, and to permit persons to whom the
16 * Software is furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included in
19 * all copies or substantial portions of the Software.
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 NONINFRINGEMENT. IN NO EVENT SHALL
24 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
25 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
26 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 * OTHER DEALINGS IN THE SOFTWARE.
28 *
29 * Authors: Dave Airlie
30 * Alon Levy
31 * Michael Thayer <michael.thayer@oracle.com,
32 * Hans de Goede <hdegoede@redhat.com>
33 */
34
35#include "vbox_drv.h"
36
37#include <VBoxVideo.h>
38
39#include <drm/drm_crtc_helper.h>
40
41static void vbox_clear_irq(void)
42{
43 outl((u32)~0, VGA_PORT_HGSMI_HOST);
44}
45
46static u32 vbox_get_flags(struct vbox_private *vbox)
47{
48 return readl(vbox->guest_heap + HOST_FLAGS_OFFSET);
49}
50
51void vbox_report_hotplug(struct vbox_private *vbox)
52{
53 schedule_work(&vbox->hotplug_work);
54}
55
56irqreturn_t vbox_irq_handler(int irq, void *arg)
57{
58 struct drm_device *dev = (struct drm_device *)arg;
59 struct vbox_private *vbox = (struct vbox_private *)dev->dev_private;
60 u32 host_flags = vbox_get_flags(vbox);
61
62 if (!(host_flags & HGSMIHOSTFLAGS_IRQ))
63 return IRQ_NONE;
64
65 /*
66 * Due to a bug in the initial host implementation of hot-plug irqs,
67 * the hot-plug and cursor capability flags were never cleared.
68 * Fortunately we can tell when they would have been set by checking
69 * that the VSYNC flag is not set.
70 */
71 if (host_flags &
72 (HGSMIHOSTFLAGS_HOTPLUG | HGSMIHOSTFLAGS_CURSOR_CAPABILITIES) &&
73 !(host_flags & HGSMIHOSTFLAGS_VSYNC))
74 vbox_report_hotplug(vbox);
75
76 vbox_clear_irq();
77
78 return IRQ_HANDLED;
79}
80
81/**
82 * Check that the position hints provided by the host are suitable for GNOME
83 * shell (i.e. all screens disjoint and hints for all enabled screens) and if
84 * not replace them with default ones. Providing valid hints improves the
85 * chances that we will get a known screen layout for pointer mapping.
86 */
87static void validate_or_set_position_hints(struct vbox_private *vbox)
88{
89 int i, j;
90 u16 currentx = 0;
91 bool valid = true;
92
93 for (i = 0; i < vbox->num_crtcs; ++i) {
94 for (j = 0; j < i; ++j) {
95 struct VBVAMODEHINT *hintsi = &vbox->last_mode_hints[i];
96 struct VBVAMODEHINT *hintsj = &vbox->last_mode_hints[j];
97
98 if (hintsi->fEnabled && hintsj->fEnabled) {
99 if (hintsi->dx >= 0xffff ||
100 hintsi->dy >= 0xffff ||
101 hintsj->dx >= 0xffff ||
102 hintsj->dy >= 0xffff ||
103 (hintsi->dx <
104 hintsj->dx + (hintsj->cx & 0x8fff) &&
105 hintsi->dx + (hintsi->cx & 0x8fff) >
106 hintsj->dx) ||
107 (hintsi->dy <
108 hintsj->dy + (hintsj->cy & 0x8fff) &&
109 hintsi->dy + (hintsi->cy & 0x8fff) >
110 hintsj->dy))
111 valid = false;
112 }
113 }
114 }
115 if (!valid)
116 for (i = 0; i < vbox->num_crtcs; ++i) {
117 if (vbox->last_mode_hints[i].fEnabled) {
118 vbox->last_mode_hints[i].dx = currentx;
119 vbox->last_mode_hints[i].dy = 0;
120 currentx +=
121 vbox->last_mode_hints[i].cx & 0x8fff;
122 }
123 }
124}
125
126/**
127 * Query the host for the most recent video mode hints.
128 */
129static void vbox_update_mode_hints(struct vbox_private *vbox)
130{
131 struct drm_device *dev = vbox->dev;
132 struct drm_connector *connector;
133 struct vbox_connector *vbox_connector;
134 struct VBVAMODEHINT *hints;
135 u16 flags;
136 bool disconnected;
137 unsigned int crtc_id;
138 int rc;
139
140 rc = VBoxHGSMIGetModeHints(vbox->guest_pool, vbox->num_crtcs,
141 vbox->last_mode_hints);
142 if (RT_FAILURE(rc)) {
143 DRM_ERROR("vboxvideo: VBoxHGSMIGetModeHints failed, rc=%i.\n",
144 rc);
145 return;
146 }
147 validate_or_set_position_hints(vbox);
148#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
149 drm_modeset_lock_all(dev);
150#else
151 mutex_lock(&dev->mode_config.mutex);
152#endif
153 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
154 vbox_connector = to_vbox_connector(connector);
155 hints =
156 &vbox->last_mode_hints[vbox_connector->vbox_crtc->crtc_id];
157 if (hints->magic == VBVAMODEHINT_MAGIC) {
158 disconnected = !(hints->fEnabled);
159 crtc_id = vbox_connector->vbox_crtc->crtc_id;
160 flags = VBVA_SCREEN_F_ACTIVE
161 | (disconnected ? VBVA_SCREEN_F_DISABLED :
162 VBVA_SCREEN_F_BLANK);
163 vbox_connector->mode_hint.width = hints->cx & 0x8fff;
164 vbox_connector->mode_hint.height = hints->cy & 0x8fff;
165 vbox_connector->vbox_crtc->x_hint = hints->dx;
166 vbox_connector->vbox_crtc->y_hint = hints->dy;
167 vbox_connector->mode_hint.disconnected = disconnected;
168 if (vbox_connector->vbox_crtc->disconnected !=
169 disconnected) {
170 VBoxHGSMIProcessDisplayInfo(vbox->guest_pool,
171 crtc_id, 0, 0, 0,
172 hints->cx * 4,
173 hints->cx,
174 hints->cy, 0,
175 flags);
176 vbox_connector->vbox_crtc->disconnected =
177 disconnected;
178 }
179 }
180 }
181#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
182 drm_modeset_unlock_all(dev);
183#else
184 mutex_unlock(&dev->mode_config.mutex);
185#endif
186}
187
188static void vbox_hotplug_worker(struct work_struct *work)
189{
190 struct vbox_private *vbox = container_of(work, struct vbox_private,
191 hotplug_work);
192
193 vbox_update_mode_hints(vbox);
194 drm_kms_helper_hotplug_event(vbox->dev);
195}
196
197int vbox_irq_init(struct vbox_private *vbox)
198{
199 int ret;
200
201 vbox_update_mode_hints(vbox);
202#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) || defined(RHEL_73)
203 ret = drm_irq_install(vbox->dev, vbox->dev->pdev->irq);
204#else
205 ret = drm_irq_install(vbox->dev);
206#endif
207 if (unlikely(ret != 0)) {
208 vbox_irq_fini(vbox);
209 DRM_ERROR("Failed installing irq: %d\n", ret);
210 return 1;
211 }
212 INIT_WORK(&vbox->hotplug_work, vbox_hotplug_worker);
213 vbox->isr_installed = true;
214 return 0;
215}
216
217void vbox_irq_fini(struct vbox_private *vbox)
218{
219 if (vbox->isr_installed) {
220 drm_irq_uninstall(vbox->dev);
221 flush_work(&vbox->hotplug_work);
222 vbox->isr_installed = false;
223 }
224}
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