VirtualBox

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

Last change on this file since 67175 was 66544, checked in by vboxsync, 8 years ago

bugref:8524: Additions/linux: play nicely with distribution-installed Additions
Change header of files which are expected to end up in the Linux kernel to the MIT licence to simplify life for people wanting to port vboxvideo to other kernels and to simplify synchronising changes back to VirtualBox. Update author information in files which have it, but do not add it to files which do not.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.2 KB
Line 
1/* $Id: vbox_drv.c 66544 2017-04-12 17:02:30Z 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{
56 {0x80ee, 0xbeef, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
57 {0, 0, 0},
58};
59
60MODULE_DEVICE_TABLE(pci, pciidlist);
61
62static int vbox_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
63{
64 return drm_get_pci_dev(pdev, ent, &driver);
65}
66
67
68static void vbox_pci_remove(struct pci_dev *pdev)
69{
70 struct drm_device *dev = pci_get_drvdata(pdev);
71
72 drm_put_dev(dev);
73}
74
75
76
77static int vbox_drm_freeze(struct drm_device *dev)
78{
79 drm_kms_helper_poll_disable(dev);
80
81 pci_save_state(dev->pdev);
82
83 console_lock();
84 vbox_fbdev_set_suspend(dev, 1);
85 console_unlock();
86 return 0;
87}
88
89static int vbox_drm_thaw(struct drm_device *dev)
90{
91 int error = 0;
92
93 drm_mode_config_reset(dev);
94 drm_helper_resume_force_mode(dev);
95
96 console_lock();
97 vbox_fbdev_set_suspend(dev, 0);
98 console_unlock();
99 return error;
100}
101
102static int vbox_drm_resume(struct drm_device *dev)
103{
104 int ret;
105
106 if (pci_enable_device(dev->pdev))
107 return -EIO;
108
109 ret = vbox_drm_thaw(dev);
110 if (ret)
111 return ret;
112
113 drm_kms_helper_poll_enable(dev);
114 return 0;
115}
116
117static int vbox_pm_suspend(struct device *dev)
118{
119 struct pci_dev *pdev = to_pci_dev(dev);
120 struct drm_device *ddev = pci_get_drvdata(pdev);
121 int error;
122
123 error = vbox_drm_freeze(ddev);
124 if (error)
125 return error;
126
127 pci_disable_device(pdev);
128 pci_set_power_state(pdev, PCI_D3hot);
129 return 0;
130}
131
132static int vbox_pm_resume(struct device *dev)
133{
134 struct pci_dev *pdev = to_pci_dev(dev);
135 struct drm_device *ddev = pci_get_drvdata(pdev);
136 return vbox_drm_resume(ddev);
137}
138
139static int vbox_pm_freeze(struct device *dev)
140{
141 struct pci_dev *pdev = to_pci_dev(dev);
142 struct drm_device *ddev = pci_get_drvdata(pdev);
143
144 if (!ddev || !ddev->dev_private)
145 return -ENODEV;
146 return vbox_drm_freeze(ddev);
147
148}
149
150static int vbox_pm_thaw(struct device *dev)
151{
152 struct pci_dev *pdev = to_pci_dev(dev);
153 struct drm_device *ddev = pci_get_drvdata(pdev);
154 return vbox_drm_thaw(ddev);
155}
156
157static int vbox_pm_poweroff(struct device *dev)
158{
159 struct pci_dev *pdev = to_pci_dev(dev);
160 struct drm_device *ddev = pci_get_drvdata(pdev);
161
162 return vbox_drm_freeze(ddev);
163}
164
165static const struct dev_pm_ops vbox_pm_ops = {
166 .suspend = vbox_pm_suspend,
167 .resume = vbox_pm_resume,
168 .freeze = vbox_pm_freeze,
169 .thaw = vbox_pm_thaw,
170 .poweroff = vbox_pm_poweroff,
171 .restore = vbox_pm_resume,
172};
173
174static struct pci_driver vbox_pci_driver =
175{
176 .name = DRIVER_NAME,
177 .id_table = pciidlist,
178 .probe = vbox_pci_probe,
179 .remove = vbox_pci_remove,
180 .driver.pm = &vbox_pm_ops,
181};
182
183#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0)
184/* This works around a bug in X servers prior to 1.18.4, which sometimes
185 * submit more dirty rectangles than the kernel is willing to handle and
186 * then disable dirty rectangle handling altogether when they see the
187 * EINVAL error. I do not want the code to hang around forever, which is
188 * why I am limiting it to certain kernel versions. We can increase the
189 * limit if some distributions uses old X servers with new kernels. */
190long vbox_ioctl(struct file *filp,
191 unsigned int cmd, unsigned long arg)
192{
193 long rc = drm_ioctl(filp, cmd, arg);
194 if (cmd == DRM_IOCTL_MODE_DIRTYFB && rc == -EINVAL)
195 return -EOVERFLOW;
196 return rc;
197}
198#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0) */
199
200static const struct file_operations vbox_fops =
201{
202 .owner = THIS_MODULE,
203 .open = drm_open,
204 .release = drm_release,
205#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0)
206 .unlocked_ioctl = vbox_ioctl,
207#else
208 .unlocked_ioctl = drm_ioctl,
209#endif
210 .mmap = vbox_mmap,
211 .poll = drm_poll,
212#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 12, 0)
213 .fasync = drm_fasync,
214#endif
215#ifdef CONFIG_COMPAT
216 .compat_ioctl = drm_compat_ioctl,
217#endif
218 .read = drm_read,
219};
220
221static int vbox_master_set(struct drm_device *dev,
222 struct drm_file *file_priv,
223 bool from_open)
224{
225 struct vbox_private *vbox = dev->dev_private;
226 /* We do not yet know whether the new owner can handle hotplug, so we
227 * do not advertise dynamic modes on the first query and send a
228 * tentative hotplug notification after that to see if they query again. */
229 vbox->initial_mode_queried = false;
230 mutex_lock(&vbox->hw_mutex);
231 /* Disable VBVA when someone releases master in case the next person tries
232 * to do VESA. */
233 /** @todo work out if anyone is likely to and whether it will even work. */
234 /* Update: we also disable it because if the new master does not do dirty
235 * rectangle reporting (e.g. old versions of Plymouth) then at least the
236 * first screen will still be updated. We enable it as soon as we
237 * receive a dirty rectangle report. */
238 vbox_disable_accel(vbox);
239 mutex_unlock(&vbox->hw_mutex);
240 return 0;
241}
242
243#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0)
244static void vbox_master_drop(struct drm_device *dev,
245 struct drm_file *file_priv,
246 bool from_release)
247#else
248static void vbox_master_drop(struct drm_device *dev,
249 struct drm_file *file_priv)
250#endif
251{
252 struct vbox_private *vbox = dev->dev_private;
253 /* See vbox_master_set() */
254 vbox->initial_mode_queried = false;
255 mutex_lock(&vbox->hw_mutex);
256 vbox_disable_accel(vbox);
257 mutex_unlock(&vbox->hw_mutex);
258}
259
260static struct drm_driver driver =
261{
262 .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_PRIME,
263 .dev_priv_size = 0,
264
265 .load = vbox_driver_load,
266 .unload = vbox_driver_unload,
267 .lastclose = vbox_driver_lastclose,
268 .master_set = vbox_master_set,
269 .master_drop = vbox_master_drop,
270#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
271 .set_busid = drm_pci_set_busid,
272#endif
273
274 .fops = &vbox_fops,
275 .irq_handler = vbox_irq_handler,
276 .name = DRIVER_NAME,
277 .desc = DRIVER_DESC,
278 .date = DRIVER_DATE,
279 .major = DRIVER_MAJOR,
280 .minor = DRIVER_MINOR,
281 .patchlevel = DRIVER_PATCHLEVEL,
282
283 .gem_free_object = vbox_gem_free_object,
284 .dumb_create = vbox_dumb_create,
285 .dumb_map_offset = vbox_dumb_mmap_offset,
286#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 12, 0)
287 .dumb_destroy = vbox_dumb_destroy,
288#else
289 .dumb_destroy = drm_gem_dumb_destroy,
290#endif
291 .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
292 .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
293 .gem_prime_export = drm_gem_prime_export,
294 .gem_prime_import = drm_gem_prime_import,
295 .gem_prime_pin = vbox_gem_prime_pin,
296 .gem_prime_unpin = vbox_gem_prime_unpin,
297 .gem_prime_get_sg_table = vbox_gem_prime_get_sg_table,
298 .gem_prime_import_sg_table = vbox_gem_prime_import_sg_table,
299 .gem_prime_vmap = vbox_gem_prime_vmap,
300 .gem_prime_vunmap = vbox_gem_prime_vunmap,
301 .gem_prime_mmap = vbox_gem_prime_mmap,
302
303};
304
305static int __init vbox_init(void)
306{
307#ifdef CONFIG_VGA_CONSOLE
308 if (vgacon_text_force() && vbox_modeset == -1)
309 return -EINVAL;
310#endif
311
312 if (vbox_modeset == 0)
313 return -EINVAL;
314
315 return drm_pci_init(&driver, &vbox_pci_driver);
316}
317static void __exit vbox_exit(void)
318{
319 drm_pci_exit(&driver, &vbox_pci_driver);
320}
321
322module_init(vbox_init);
323module_exit(vbox_exit);
324
325MODULE_AUTHOR(DRIVER_AUTHOR);
326MODULE_DESCRIPTION(DRIVER_DESC);
327MODULE_LICENSE("GPL and additional rights");
328#ifdef MODULE_VERSION
329MODULE_VERSION(VBOX_VERSION_STRING " r" RT_XSTR(VBOX_SVN_REV));
330#endif
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