• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013-2017 Oracle Corporation
3  * This file is based on ast_drv.c
4  * Copyright 2012 Red Hat Inc.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sub license, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
17  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
18  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20  * USE OR OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * The above copyright notice and this permission notice (including the
23  * next paragraph) shall be included in all copies or substantial portions
24  * of the Software.
25  *
26  * Authors: Dave Airlie <airlied@redhat.com>
27  *          Michael Thayer <michael.thayer@oracle.com,
28  *          Hans de Goede <hdegoede@redhat.com>
29  */
30 #include <linux/module.h>
31 #include <linux/console.h>
32 #include <linux/vt_kern.h>
33 
34 #include <drm/drmP.h>
35 #include <drm/drm_crtc_helper.h>
36 
37 #include "vbox_drv.h"
38 
39 static int vbox_modeset = -1;
40 
41 MODULE_PARM_DESC(modeset, "Disable/Enable modesetting");
42 module_param_named(modeset, vbox_modeset, int, 0400);
43 
44 static struct drm_driver driver;
45 
46 static const struct pci_device_id pciidlist[] = {
47 	{ 0x80ee, 0xbeef, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
48 	{ 0, 0, 0},
49 };
50 MODULE_DEVICE_TABLE(pci, pciidlist);
51 
vbox_pci_probe(struct pci_dev * pdev,const struct pci_device_id * ent)52 static int vbox_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
53 {
54 	return drm_get_pci_dev(pdev, ent, &driver);
55 }
56 
vbox_pci_remove(struct pci_dev * pdev)57 static void vbox_pci_remove(struct pci_dev *pdev)
58 {
59 	struct drm_device *dev = pci_get_drvdata(pdev);
60 
61 	drm_put_dev(dev);
62 }
63 
vbox_drm_freeze(struct drm_device * dev)64 static int vbox_drm_freeze(struct drm_device *dev)
65 {
66 	struct vbox_private *vbox = dev->dev_private;
67 
68 	drm_kms_helper_poll_disable(dev);
69 
70 	pci_save_state(dev->pdev);
71 
72 	drm_fb_helper_set_suspend_unlocked(&vbox->fbdev->helper, true);
73 
74 	return 0;
75 }
76 
vbox_drm_thaw(struct drm_device * dev)77 static int vbox_drm_thaw(struct drm_device *dev)
78 {
79 	struct vbox_private *vbox = dev->dev_private;
80 
81 	drm_mode_config_reset(dev);
82 	drm_helper_resume_force_mode(dev);
83 	drm_fb_helper_set_suspend_unlocked(&vbox->fbdev->helper, false);
84 
85 	return 0;
86 }
87 
vbox_drm_resume(struct drm_device * dev)88 static int vbox_drm_resume(struct drm_device *dev)
89 {
90 	int ret;
91 
92 	if (pci_enable_device(dev->pdev))
93 		return -EIO;
94 
95 	ret = vbox_drm_thaw(dev);
96 	if (ret)
97 		return ret;
98 
99 	drm_kms_helper_poll_enable(dev);
100 
101 	return 0;
102 }
103 
vbox_pm_suspend(struct device * dev)104 static int vbox_pm_suspend(struct device *dev)
105 {
106 	struct pci_dev *pdev = to_pci_dev(dev);
107 	struct drm_device *ddev = pci_get_drvdata(pdev);
108 	int error;
109 
110 	error = vbox_drm_freeze(ddev);
111 	if (error)
112 		return error;
113 
114 	pci_disable_device(pdev);
115 	pci_set_power_state(pdev, PCI_D3hot);
116 
117 	return 0;
118 }
119 
vbox_pm_resume(struct device * dev)120 static int vbox_pm_resume(struct device *dev)
121 {
122 	struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
123 
124 	return vbox_drm_resume(ddev);
125 }
126 
vbox_pm_freeze(struct device * dev)127 static int vbox_pm_freeze(struct device *dev)
128 {
129 	struct pci_dev *pdev = to_pci_dev(dev);
130 	struct drm_device *ddev = pci_get_drvdata(pdev);
131 
132 	if (!ddev || !ddev->dev_private)
133 		return -ENODEV;
134 
135 	return vbox_drm_freeze(ddev);
136 }
137 
vbox_pm_thaw(struct device * dev)138 static int vbox_pm_thaw(struct device *dev)
139 {
140 	struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
141 
142 	return vbox_drm_thaw(ddev);
143 }
144 
vbox_pm_poweroff(struct device * dev)145 static int vbox_pm_poweroff(struct device *dev)
146 {
147 	struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
148 
149 	return vbox_drm_freeze(ddev);
150 }
151 
152 static const struct dev_pm_ops vbox_pm_ops = {
153 	.suspend = vbox_pm_suspend,
154 	.resume = vbox_pm_resume,
155 	.freeze = vbox_pm_freeze,
156 	.thaw = vbox_pm_thaw,
157 	.poweroff = vbox_pm_poweroff,
158 	.restore = vbox_pm_resume,
159 };
160 
161 static struct pci_driver vbox_pci_driver = {
162 	.name = DRIVER_NAME,
163 	.id_table = pciidlist,
164 	.probe = vbox_pci_probe,
165 	.remove = vbox_pci_remove,
166 	.driver.pm = &vbox_pm_ops,
167 };
168 
169 static const struct file_operations vbox_fops = {
170 	.owner = THIS_MODULE,
171 	.open = drm_open,
172 	.release = drm_release,
173 	.unlocked_ioctl = drm_ioctl,
174 	.mmap = vbox_mmap,
175 	.poll = drm_poll,
176 #ifdef CONFIG_COMPAT
177 	.compat_ioctl = drm_compat_ioctl,
178 #endif
179 	.read = drm_read,
180 };
181 
vbox_master_set(struct drm_device * dev,struct drm_file * file_priv,bool from_open)182 static int vbox_master_set(struct drm_device *dev,
183 			   struct drm_file *file_priv, bool from_open)
184 {
185 	struct vbox_private *vbox = dev->dev_private;
186 
187 	/*
188 	 * We do not yet know whether the new owner can handle hotplug, so we
189 	 * do not advertise dynamic modes on the first query and send a
190 	 * tentative hotplug notification after that to see if they query again.
191 	 */
192 	vbox->initial_mode_queried = false;
193 
194 	mutex_lock(&vbox->hw_mutex);
195 	/*
196 	 * Disable VBVA when someone releases master in case the next person
197 	 * tries tries to do VESA.
198 	 */
199 	/** @todo work out if anyone is likely to and whether it will work. */
200 	/*
201 	 * Update: we also disable it because if the new master does not do
202 	 * dirty rectangle reporting (e.g. old versions of Plymouth) then at
203 	 * least the first screen will still be updated. We enable it as soon
204 	 * as we receive a dirty rectangle report.
205 	 */
206 	vbox_disable_accel(vbox);
207 	mutex_unlock(&vbox->hw_mutex);
208 
209 	return 0;
210 }
211 
vbox_master_drop(struct drm_device * dev,struct drm_file * file_priv)212 static void vbox_master_drop(struct drm_device *dev, struct drm_file *file_priv)
213 {
214 	struct vbox_private *vbox = dev->dev_private;
215 
216 	/* See vbox_master_set() */
217 	vbox->initial_mode_queried = false;
218 
219 	mutex_lock(&vbox->hw_mutex);
220 	vbox_disable_accel(vbox);
221 	mutex_unlock(&vbox->hw_mutex);
222 }
223 
224 static struct drm_driver driver = {
225 	.driver_features =
226 	    DRIVER_MODESET | DRIVER_GEM | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED |
227 	    DRIVER_PRIME,
228 	.dev_priv_size = 0,
229 
230 	.load = vbox_driver_load,
231 	.unload = vbox_driver_unload,
232 	.lastclose = vbox_driver_lastclose,
233 	.master_set = vbox_master_set,
234 	.master_drop = vbox_master_drop,
235 
236 	.fops = &vbox_fops,
237 	.irq_handler = vbox_irq_handler,
238 	.name = DRIVER_NAME,
239 	.desc = DRIVER_DESC,
240 	.date = DRIVER_DATE,
241 	.major = DRIVER_MAJOR,
242 	.minor = DRIVER_MINOR,
243 	.patchlevel = DRIVER_PATCHLEVEL,
244 
245 	.gem_free_object = vbox_gem_free_object,
246 	.dumb_create = vbox_dumb_create,
247 	.dumb_map_offset = vbox_dumb_mmap_offset,
248 	.dumb_destroy = drm_gem_dumb_destroy,
249 	.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
250 	.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
251 	.gem_prime_export = drm_gem_prime_export,
252 	.gem_prime_import = drm_gem_prime_import,
253 	.gem_prime_pin = vbox_gem_prime_pin,
254 	.gem_prime_unpin = vbox_gem_prime_unpin,
255 	.gem_prime_get_sg_table = vbox_gem_prime_get_sg_table,
256 	.gem_prime_import_sg_table = vbox_gem_prime_import_sg_table,
257 	.gem_prime_vmap = vbox_gem_prime_vmap,
258 	.gem_prime_vunmap = vbox_gem_prime_vunmap,
259 	.gem_prime_mmap = vbox_gem_prime_mmap,
260 };
261 
vbox_init(void)262 static int __init vbox_init(void)
263 {
264 #ifdef CONFIG_VGA_CONSOLE
265 	if (vgacon_text_force() && vbox_modeset == -1)
266 		return -EINVAL;
267 #endif
268 
269 	if (vbox_modeset == 0)
270 		return -EINVAL;
271 
272 	return pci_register_driver(&vbox_pci_driver);
273 }
274 
vbox_exit(void)275 static void __exit vbox_exit(void)
276 {
277 	pci_unregister_driver(&vbox_pci_driver);
278 }
279 
280 module_init(vbox_init);
281 module_exit(vbox_exit);
282 
283 MODULE_AUTHOR("Oracle Corporation");
284 MODULE_DESCRIPTION(DRIVER_DESC);
285 MODULE_LICENSE("GPL and additional rights");
286