VirtualBox

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

最後變更 在這個檔案從76553是 76553,由 vboxsync 提交於 6 年 前

scm --update-copyright-year

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 9.0 KB
 
1/* $Id: vbox_drv.c 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * VirtualBox Additions Linux kernel video driver
4 */
5
6/*
7 * Copyright (C) 2013-2019 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 <linux/module.h>
36#include <linux/console.h>
37#include <linux/vt_kern.h>
38
39#include <drm/drmP.h>
40#include <drm/drm_crtc_helper.h>
41
42#include "vbox_drv.h"
43
44#include "version-generated.h"
45#include "revision-generated.h"
46
47static int 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
72#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0) && !defined(RHEL_74)
73static void drm_fb_helper_set_suspend_unlocked(struct drm_fb_helper *fb_helper,
74 bool suspend)
75{
76 if (!fb_helper || !fb_helper->fbdev)
77 return;
78
79 console_lock();
80 fb_set_suspend(fb_helper->fbdev, suspend);
81 console_unlock();
82}
83#endif
84
85static int vbox_drm_freeze(struct drm_device *dev)
86{
87 struct vbox_private *vbox = dev->dev_private;
88
89 drm_kms_helper_poll_disable(dev);
90
91 pci_save_state(dev->pdev);
92
93 drm_fb_helper_set_suspend_unlocked(&vbox->fbdev->helper, true);
94
95 return 0;
96}
97
98static int vbox_drm_thaw(struct drm_device *dev)
99{
100 struct vbox_private *vbox = dev->dev_private;
101
102 drm_mode_config_reset(dev);
103 drm_helper_resume_force_mode(dev);
104 drm_fb_helper_set_suspend_unlocked(&vbox->fbdev->helper, false);
105
106 return 0;
107}
108
109static int vbox_drm_resume(struct drm_device *dev)
110{
111 int ret;
112
113 if (pci_enable_device(dev->pdev))
114 return -EIO;
115
116 ret = vbox_drm_thaw(dev);
117 if (ret)
118 return ret;
119
120 drm_kms_helper_poll_enable(dev);
121
122 return 0;
123}
124
125static int vbox_pm_suspend(struct device *dev)
126{
127 struct pci_dev *pdev = to_pci_dev(dev);
128 struct drm_device *ddev = pci_get_drvdata(pdev);
129 int error;
130
131 error = vbox_drm_freeze(ddev);
132 if (error)
133 return error;
134
135 pci_disable_device(pdev);
136 pci_set_power_state(pdev, PCI_D3hot);
137
138 return 0;
139}
140
141static int vbox_pm_resume(struct device *dev)
142{
143 struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
144
145 return vbox_drm_resume(ddev);
146}
147
148static int vbox_pm_freeze(struct device *dev)
149{
150 struct pci_dev *pdev = to_pci_dev(dev);
151 struct drm_device *ddev = pci_get_drvdata(pdev);
152
153 if (!ddev || !ddev->dev_private)
154 return -ENODEV;
155
156 return vbox_drm_freeze(ddev);
157}
158
159static int vbox_pm_thaw(struct device *dev)
160{
161 struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
162
163 return vbox_drm_thaw(ddev);
164}
165
166static int vbox_pm_poweroff(struct device *dev)
167{
168 struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
169
170 return vbox_drm_freeze(ddev);
171}
172
173static const struct dev_pm_ops vbox_pm_ops = {
174 .suspend = vbox_pm_suspend,
175 .resume = vbox_pm_resume,
176 .freeze = vbox_pm_freeze,
177 .thaw = vbox_pm_thaw,
178 .poweroff = vbox_pm_poweroff,
179 .restore = vbox_pm_resume,
180};
181
182static struct pci_driver vbox_pci_driver = {
183 .name = DRIVER_NAME,
184 .id_table = pciidlist,
185 .probe = vbox_pci_probe,
186 .remove = vbox_pci_remove,
187 .driver.pm = &vbox_pm_ops,
188};
189
190#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0) && !defined(RHEL_74)
191/* This works around a bug in X servers prior to 1.18.4, which sometimes
192 * submit more dirty rectangles than the kernel is willing to handle and
193 * then disable dirty rectangle handling altogether when they see the
194 * EINVAL error. I do not want the code to hang around forever, which is
195 * why I am limiting it to certain kernel versions. We can increase the
196 * limit if some distributions uses old X servers with new kernels. */
197long vbox_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
198{
199 long rc = drm_ioctl(filp, cmd, arg);
200
201 if (cmd == DRM_IOCTL_MODE_DIRTYFB && rc == -EINVAL)
202 return -EOVERFLOW;
203
204 return rc;
205}
206#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0) && !RHEL_74 */
207
208static const struct file_operations vbox_fops = {
209 .owner = THIS_MODULE,
210 .open = drm_open,
211 .release = drm_release,
212#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0) && !defined(RHEL_74)
213 .unlocked_ioctl = vbox_ioctl,
214#else
215 .unlocked_ioctl = drm_ioctl,
216#endif
217 .mmap = vbox_mmap,
218 .poll = drm_poll,
219#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 12, 0) && !defined(RHEL_70)
220 .fasync = drm_fasync,
221#endif
222#ifdef CONFIG_COMPAT
223 .compat_ioctl = drm_compat_ioctl,
224#endif
225 .read = drm_read,
226};
227
228static int vbox_master_set(struct drm_device *dev,
229 struct drm_file *file_priv, bool from_open)
230{
231 struct vbox_private *vbox = dev->dev_private;
232
233 /*
234 * We do not yet know whether the new owner can handle hotplug, so we
235 * do not advertise dynamic modes on the first query and send a
236 * tentative hotplug notification after that to see if they query again.
237 */
238 vbox->initial_mode_queried = false;
239
240 mutex_lock(&vbox->hw_mutex);
241 /* Start the refresh timer in case the user does not provide dirty
242 * rectangles. */
243 vbox->need_refresh_timer = true;
244 schedule_delayed_work(&vbox->refresh_work, VBOX_REFRESH_PERIOD);
245 mutex_unlock(&vbox->hw_mutex);
246
247 return 0;
248}
249
250#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0) && !defined(RHEL_74)
251static void vbox_master_drop(struct drm_device *dev,
252 struct drm_file *file_priv, bool from_release)
253#else
254static void vbox_master_drop(struct drm_device *dev, struct drm_file *file_priv)
255#endif
256{
257 struct vbox_private *vbox = dev->dev_private;
258
259 /* See vbox_master_set() */
260 vbox->initial_mode_queried = false;
261 vbox_report_caps(vbox);
262
263 mutex_lock(&vbox->hw_mutex);
264 vbox->need_refresh_timer = false;
265 mutex_unlock(&vbox->hw_mutex);
266}
267
268static struct drm_driver driver = {
269 .driver_features =
270 DRIVER_MODESET | DRIVER_GEM | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED |
271 DRIVER_PRIME,
272 .dev_priv_size = 0,
273
274 .load = vbox_driver_load,
275 .unload = vbox_driver_unload,
276 .lastclose = vbox_driver_lastclose,
277 .master_set = vbox_master_set,
278 .master_drop = vbox_master_drop,
279#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0) || defined(RHEL_73)
280# if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0) && !defined(RHEL_75)
281 .set_busid = drm_pci_set_busid,
282# endif
283#endif
284
285 .fops = &vbox_fops,
286 .irq_handler = vbox_irq_handler,
287 .name = DRIVER_NAME,
288 .desc = DRIVER_DESC,
289 .date = DRIVER_DATE,
290 .major = DRIVER_MAJOR,
291 .minor = DRIVER_MINOR,
292 .patchlevel = DRIVER_PATCHLEVEL,
293
294 .gem_free_object = vbox_gem_free_object,
295 .dumb_create = vbox_dumb_create,
296 .dumb_map_offset = vbox_dumb_mmap_offset,
297#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 12, 0) && !defined(RHEL_73)
298 .dumb_destroy = vbox_dumb_destroy,
299#else
300 .dumb_destroy = drm_gem_dumb_destroy,
301#endif
302 .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
303 .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
304 .gem_prime_export = drm_gem_prime_export,
305 .gem_prime_import = drm_gem_prime_import,
306 .gem_prime_pin = vbox_gem_prime_pin,
307 .gem_prime_unpin = vbox_gem_prime_unpin,
308 .gem_prime_get_sg_table = vbox_gem_prime_get_sg_table,
309 .gem_prime_import_sg_table = vbox_gem_prime_import_sg_table,
310 .gem_prime_vmap = vbox_gem_prime_vmap,
311 .gem_prime_vunmap = vbox_gem_prime_vunmap,
312 .gem_prime_mmap = vbox_gem_prime_mmap,
313};
314
315static int __init vbox_init(void)
316{
317#if defined(CONFIG_VGA_CONSOLE) || LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)
318 if (vgacon_text_force() && vbox_modeset == -1)
319 return -EINVAL;
320#endif
321
322 if (vbox_modeset == 0)
323 return -EINVAL;
324
325 return pci_register_driver(&vbox_pci_driver);
326}
327
328static void __exit vbox_exit(void)
329{
330 pci_unregister_driver(&vbox_pci_driver);
331}
332
333module_init(vbox_init);
334module_exit(vbox_exit);
335
336MODULE_AUTHOR(DRIVER_AUTHOR);
337MODULE_DESCRIPTION(DRIVER_DESC);
338MODULE_LICENSE("GPL and additional rights");
339#ifdef MODULE_VERSION
340MODULE_VERSION(VBOX_VERSION_STRING " r" __stringify(VBOX_SVN_REV));
341#endif
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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