VirtualBox

source: vbox/trunk/src/VBox/Additions/linux/drm/vbox_drv.c@ 69496

最後變更 在這個檔案從69496是 69143,由 vboxsync 提交於 7 年 前

Additions/linux/drm: make vboxvideo work with Linux 4.14.
bugref:8524: Additions/linux: play nicely with distribution-installed Additions

Changes needed to build against Linux 4.14, applying them to older versions
too where that will not hurt.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 8.8 KB
 
1/* $Id: vbox_drv.c 69143 2017-10-20 10:17:44Z 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_drv.c
9 * Copyright 2012 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
13 * "Software"), to deal in the Software without restriction, including
14 * without limitation the rights to use, copy, modify, merge, publish,
15 * distribute, sub license, and/or sell copies of the Software, and to
16 * permit persons to whom the Software is furnished to do so, subject to
17 * the following conditions:
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
22 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
23 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
25 * USE OR OTHER DEALINGS IN THE SOFTWARE.
26 *
27 * The above copyright notice and this permission notice (including the
28 * next paragraph) shall be included in all copies or substantial portions
29 * of the Software.
30 *
31 * Authors: Dave Airlie <[email protected]>
32 * Michael Thayer <[email protected],
33 * Hans de Goede <[email protected]>
34 */
35#include "vbox_drv.h"
36
37#include "version-generated.h"
38#include "revision-generated.h"
39
40#include <linux/module.h>
41#include <linux/console.h>
42#include <linux/vt_kern.h>
43
44#include <drm/drmP.h>
45#include <drm/drm_crtc_helper.h>
46
47int vbox_modeset = -1;
48
49MODULE_PARM_DESC(modeset, "Disable/Enable modesetting");
50module_param_named(modeset, vbox_modeset, int, 0400);
51
52static struct drm_driver driver;
53
54static const struct pci_device_id pciidlist[] = {
55 { 0x80ee, 0xbeef, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
56 { 0, 0, 0},
57};
58MODULE_DEVICE_TABLE(pci, pciidlist);
59
60static int vbox_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
61{
62 return drm_get_pci_dev(pdev, ent, &driver);
63}
64
65static void vbox_pci_remove(struct pci_dev *pdev)
66{
67 struct drm_device *dev = pci_get_drvdata(pdev);
68
69 drm_put_dev(dev);
70}
71
72static int vbox_drm_freeze(struct drm_device *dev)
73{
74 drm_kms_helper_poll_disable(dev);
75
76 pci_save_state(dev->pdev);
77
78 console_lock();
79 vbox_fbdev_set_suspend(dev, 1);
80 console_unlock();
81
82 return 0;
83}
84
85static int vbox_drm_thaw(struct drm_device *dev)
86{
87 drm_mode_config_reset(dev);
88 drm_helper_resume_force_mode(dev);
89
90 console_lock();
91 vbox_fbdev_set_suspend(dev, 0);
92 console_unlock();
93
94 return 0;
95}
96
97static int vbox_drm_resume(struct drm_device *dev)
98{
99 int ret;
100
101 if (pci_enable_device(dev->pdev))
102 return -EIO;
103
104 ret = vbox_drm_thaw(dev);
105 if (ret)
106 return ret;
107
108 drm_kms_helper_poll_enable(dev);
109
110 return 0;
111}
112
113static int vbox_pm_suspend(struct device *dev)
114{
115 struct pci_dev *pdev = to_pci_dev(dev);
116 struct drm_device *ddev = pci_get_drvdata(pdev);
117 int error;
118
119 error = vbox_drm_freeze(ddev);
120 if (error)
121 return error;
122
123 pci_disable_device(pdev);
124 pci_set_power_state(pdev, PCI_D3hot);
125
126 return 0;
127}
128
129static int vbox_pm_resume(struct device *dev)
130{
131 struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
132
133 return vbox_drm_resume(ddev);
134}
135
136static int vbox_pm_freeze(struct device *dev)
137{
138 struct pci_dev *pdev = to_pci_dev(dev);
139 struct drm_device *ddev = pci_get_drvdata(pdev);
140
141 if (!ddev || !ddev->dev_private)
142 return -ENODEV;
143
144 return vbox_drm_freeze(ddev);
145}
146
147static int vbox_pm_thaw(struct device *dev)
148{
149 struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
150
151 return vbox_drm_thaw(ddev);
152}
153
154static int vbox_pm_poweroff(struct device *dev)
155{
156 struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
157
158 return vbox_drm_freeze(ddev);
159}
160
161static const struct dev_pm_ops vbox_pm_ops = {
162 .suspend = vbox_pm_suspend,
163 .resume = vbox_pm_resume,
164 .freeze = vbox_pm_freeze,
165 .thaw = vbox_pm_thaw,
166 .poweroff = vbox_pm_poweroff,
167 .restore = vbox_pm_resume,
168};
169
170static struct pci_driver vbox_pci_driver = {
171 .name = DRIVER_NAME,
172 .id_table = pciidlist,
173 .probe = vbox_pci_probe,
174 .remove = vbox_pci_remove,
175 .driver.pm = &vbox_pm_ops,
176};
177
178#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0) && !defined(RHEL_74)
179/* This works around a bug in X servers prior to 1.18.4, which sometimes
180 * submit more dirty rectangles than the kernel is willing to handle and
181 * then disable dirty rectangle handling altogether when they see the
182 * EINVAL error. I do not want the code to hang around forever, which is
183 * why I am limiting it to certain kernel versions. We can increase the
184 * limit if some distributions uses old X servers with new kernels. */
185long vbox_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
186{
187 long rc = drm_ioctl(filp, cmd, arg);
188
189 if (cmd == DRM_IOCTL_MODE_DIRTYFB && rc == -EINVAL)
190 return -EOVERFLOW;
191
192 return rc;
193}
194#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0) && !RHEL_74 */
195
196static const struct file_operations vbox_fops = {
197 .owner = THIS_MODULE,
198 .open = drm_open,
199 .release = drm_release,
200#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0) && !defined(RHEL_74)
201 .unlocked_ioctl = vbox_ioctl,
202#else
203 .unlocked_ioctl = drm_ioctl,
204#endif
205 .mmap = vbox_mmap,
206 .poll = drm_poll,
207#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 12, 0) && !defined(RHEL_73)
208 .fasync = drm_fasync,
209#endif
210#ifdef CONFIG_COMPAT
211 .compat_ioctl = drm_compat_ioctl,
212#endif
213 .read = drm_read,
214};
215
216static int vbox_master_set(struct drm_device *dev,
217 struct drm_file *file_priv, bool from_open)
218{
219 struct vbox_private *vbox = dev->dev_private;
220
221 /*
222 * We do not yet know whether the new owner can handle hotplug, so we
223 * do not advertise dynamic modes on the first query and send a
224 * tentative hotplug notification after that to see if they query again.
225 */
226 vbox->initial_mode_queried = false;
227
228 mutex_lock(&vbox->hw_mutex);
229 /*
230 * Disable VBVA when someone releases master in case the next person
231 * tries tries to do VESA.
232 */
233 /** @todo work out if anyone is likely to and whether it will work. */
234 /*
235 * Update: we also disable it because if the new master does not do
236 * dirty rectangle reporting (e.g. old versions of Plymouth) then at
237 * least the first screen will still be updated. We enable it as soon
238 * as we receive a dirty rectangle report.
239 */
240 vbox_disable_accel(vbox);
241 mutex_unlock(&vbox->hw_mutex);
242
243 return 0;
244}
245
246#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0) && !defined(RHEL_74)
247static void vbox_master_drop(struct drm_device *dev,
248 struct drm_file *file_priv, bool from_release)
249#else
250static void vbox_master_drop(struct drm_device *dev, struct drm_file *file_priv)
251#endif
252{
253 struct vbox_private *vbox = dev->dev_private;
254
255 /* See vbox_master_set() */
256 vbox->initial_mode_queried = false;
257
258 mutex_lock(&vbox->hw_mutex);
259 vbox_disable_accel(vbox);
260 mutex_unlock(&vbox->hw_mutex);
261}
262
263static struct drm_driver driver = {
264 .driver_features =
265 DRIVER_MODESET | DRIVER_GEM | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED |
266 DRIVER_PRIME,
267 .dev_priv_size = 0,
268
269 .load = vbox_driver_load,
270 .unload = vbox_driver_unload,
271 .lastclose = vbox_driver_lastclose,
272 .master_set = vbox_master_set,
273 .master_drop = vbox_master_drop,
274#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0) || defined(RHEL_73)
275# if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
276 .set_busid = drm_pci_set_busid,
277# endif
278#endif
279
280 .fops = &vbox_fops,
281 .irq_handler = vbox_irq_handler,
282 .name = DRIVER_NAME,
283 .desc = DRIVER_DESC,
284 .date = DRIVER_DATE,
285 .major = DRIVER_MAJOR,
286 .minor = DRIVER_MINOR,
287 .patchlevel = DRIVER_PATCHLEVEL,
288
289 .gem_free_object = vbox_gem_free_object,
290 .dumb_create = vbox_dumb_create,
291 .dumb_map_offset = vbox_dumb_mmap_offset,
292#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 12, 0) && !defined(RHEL_73)
293 .dumb_destroy = vbox_dumb_destroy,
294#else
295 .dumb_destroy = drm_gem_dumb_destroy,
296#endif
297 .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
298 .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
299 .gem_prime_export = drm_gem_prime_export,
300 .gem_prime_import = drm_gem_prime_import,
301 .gem_prime_pin = vbox_gem_prime_pin,
302 .gem_prime_unpin = vbox_gem_prime_unpin,
303 .gem_prime_get_sg_table = vbox_gem_prime_get_sg_table,
304 .gem_prime_import_sg_table = vbox_gem_prime_import_sg_table,
305 .gem_prime_vmap = vbox_gem_prime_vmap,
306 .gem_prime_vunmap = vbox_gem_prime_vunmap,
307 .gem_prime_mmap = vbox_gem_prime_mmap,
308};
309
310static int __init vbox_init(void)
311{
312#ifdef CONFIG_VGA_CONSOLE || LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)
313 if (vgacon_text_force() && vbox_modeset == -1)
314 return -EINVAL;
315#endif
316
317 if (vbox_modeset == 0)
318 return -EINVAL;
319
320 return pci_register_driver(&vbox_pci_driver);
321}
322
323static void __exit vbox_exit(void)
324{
325 pci_unregister_driver(&vbox_pci_driver);
326}
327
328module_init(vbox_init);
329module_exit(vbox_exit);
330
331MODULE_AUTHOR(DRIVER_AUTHOR);
332MODULE_DESCRIPTION(DRIVER_DESC);
333MODULE_LICENSE("GPL and additional rights");
334#ifdef MODULE_VERSION
335MODULE_VERSION(VBOX_VERSION_STRING " r" __stringify(VBOX_SVN_REV));
336#endif
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette