]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/staging/vboxvideo/vbox_drv.c
staging: vboxvideo: Use more drm_fb_helper functions
[linux.git] / drivers / staging / vboxvideo / vbox_drv.c
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
52 static struct drm_fb_helper_funcs vbox_fb_helper_funcs = {
53         .fb_probe = vboxfb_create,
54 };
55
56 static int vbox_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
57 {
58         struct vbox_private *vbox;
59         int ret = 0;
60
61         if (!vbox_check_supported(VBE_DISPI_ID_HGSMI))
62                 return -ENODEV;
63
64         vbox = kzalloc(sizeof(*vbox), GFP_KERNEL);
65         if (!vbox)
66                 return -ENOMEM;
67
68         ret = drm_dev_init(&vbox->ddev, &driver, &pdev->dev);
69         if (ret) {
70                 kfree(vbox);
71                 return ret;
72         }
73
74         vbox->ddev.pdev = pdev;
75         vbox->ddev.dev_private = vbox;
76         pci_set_drvdata(pdev, vbox);
77         mutex_init(&vbox->hw_mutex);
78
79         ret = pci_enable_device(pdev);
80         if (ret)
81                 goto err_dev_put;
82
83         ret = vbox_hw_init(vbox);
84         if (ret)
85                 goto err_pci_disable;
86
87         ret = vbox_mm_init(vbox);
88         if (ret)
89                 goto err_hw_fini;
90
91         ret = vbox_mode_init(vbox);
92         if (ret)
93                 goto err_mm_fini;
94
95         ret = vbox_irq_init(vbox);
96         if (ret)
97                 goto err_mode_fini;
98
99         ret = drm_fb_helper_fbdev_setup(&vbox->ddev, &vbox->fb_helper,
100                                         &vbox_fb_helper_funcs, 32,
101                                         vbox->num_crtcs);
102         if (ret)
103                 goto err_irq_fini;
104
105         ret = drm_dev_register(&vbox->ddev, 0);
106         if (ret)
107                 goto err_fbdev_fini;
108
109         return 0;
110
111 err_fbdev_fini:
112         vbox_fbdev_fini(vbox);
113 err_irq_fini:
114         vbox_irq_fini(vbox);
115 err_mode_fini:
116         vbox_mode_fini(vbox);
117 err_mm_fini:
118         vbox_mm_fini(vbox);
119 err_hw_fini:
120         vbox_hw_fini(vbox);
121 err_pci_disable:
122         pci_disable_device(pdev);
123 err_dev_put:
124         drm_dev_put(&vbox->ddev);
125         return ret;
126 }
127
128 static void vbox_pci_remove(struct pci_dev *pdev)
129 {
130         struct vbox_private *vbox = pci_get_drvdata(pdev);
131
132         drm_dev_unregister(&vbox->ddev);
133         vbox_fbdev_fini(vbox);
134         vbox_irq_fini(vbox);
135         vbox_mode_fini(vbox);
136         vbox_mm_fini(vbox);
137         vbox_hw_fini(vbox);
138         drm_dev_put(&vbox->ddev);
139 }
140
141 static int vbox_pm_suspend(struct device *dev)
142 {
143         struct vbox_private *vbox = dev_get_drvdata(dev);
144         int error;
145
146         error = drm_mode_config_helper_suspend(&vbox->ddev);
147         if (error)
148                 return error;
149
150         pci_save_state(vbox->ddev.pdev);
151         pci_disable_device(vbox->ddev.pdev);
152         pci_set_power_state(vbox->ddev.pdev, PCI_D3hot);
153
154         return 0;
155 }
156
157 static int vbox_pm_resume(struct device *dev)
158 {
159         struct vbox_private *vbox = dev_get_drvdata(dev);
160
161         if (pci_enable_device(vbox->ddev.pdev))
162                 return -EIO;
163
164         return drm_mode_config_helper_resume(&vbox->ddev);
165 }
166
167 static int vbox_pm_freeze(struct device *dev)
168 {
169         struct vbox_private *vbox = dev_get_drvdata(dev);
170
171         return drm_mode_config_helper_suspend(&vbox->ddev);
172 }
173
174 static int vbox_pm_thaw(struct device *dev)
175 {
176         struct vbox_private *vbox = dev_get_drvdata(dev);
177
178         return drm_mode_config_helper_resume(&vbox->ddev);
179 }
180
181 static int vbox_pm_poweroff(struct device *dev)
182 {
183         struct vbox_private *vbox = dev_get_drvdata(dev);
184
185         return drm_mode_config_helper_suspend(&vbox->ddev);
186 }
187
188 static const struct dev_pm_ops vbox_pm_ops = {
189         .suspend = vbox_pm_suspend,
190         .resume = vbox_pm_resume,
191         .freeze = vbox_pm_freeze,
192         .thaw = vbox_pm_thaw,
193         .poweroff = vbox_pm_poweroff,
194         .restore = vbox_pm_resume,
195 };
196
197 static struct pci_driver vbox_pci_driver = {
198         .name = DRIVER_NAME,
199         .id_table = pciidlist,
200         .probe = vbox_pci_probe,
201         .remove = vbox_pci_remove,
202         .driver.pm = &vbox_pm_ops,
203 };
204
205 static const struct file_operations vbox_fops = {
206         .owner = THIS_MODULE,
207         .open = drm_open,
208         .release = drm_release,
209         .unlocked_ioctl = drm_ioctl,
210         .mmap = vbox_mmap,
211         .poll = drm_poll,
212 #ifdef CONFIG_COMPAT
213         .compat_ioctl = drm_compat_ioctl,
214 #endif
215         .read = drm_read,
216 };
217
218 static int vbox_master_set(struct drm_device *dev,
219                            struct drm_file *file_priv, bool from_open)
220 {
221         struct vbox_private *vbox = dev->dev_private;
222
223         /*
224          * We do not yet know whether the new owner can handle hotplug, so we
225          * do not advertise dynamic modes on the first query and send a
226          * tentative hotplug notification after that to see if they query again.
227          */
228         vbox->initial_mode_queried = false;
229
230         mutex_lock(&vbox->hw_mutex);
231         /*
232          * Disable VBVA when someone releases master in case the next person
233          * tries tries to do VESA.
234          */
235         /** @todo work out if anyone is likely to and whether it will work. */
236         /*
237          * Update: we also disable it because if the new master does not do
238          * dirty rectangle reporting (e.g. old versions of Plymouth) then at
239          * least the first screen will still be updated. We enable it as soon
240          * as we receive a dirty rectangle report.
241          */
242         vbox_disable_accel(vbox);
243         mutex_unlock(&vbox->hw_mutex);
244
245         return 0;
246 }
247
248 static void vbox_master_drop(struct drm_device *dev, struct drm_file *file_priv)
249 {
250         struct vbox_private *vbox = dev->dev_private;
251
252         /* See vbox_master_set() */
253         vbox->initial_mode_queried = false;
254
255         mutex_lock(&vbox->hw_mutex);
256         vbox_disable_accel(vbox);
257         mutex_unlock(&vbox->hw_mutex);
258 }
259
260 static struct drm_driver driver = {
261         .driver_features =
262             DRIVER_MODESET | DRIVER_GEM | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED |
263             DRIVER_PRIME | DRIVER_ATOMIC,
264         .dev_priv_size = 0,
265
266         .lastclose = drm_fb_helper_lastclose,
267         .master_set = vbox_master_set,
268         .master_drop = vbox_master_drop,
269
270         .fops = &vbox_fops,
271         .irq_handler = vbox_irq_handler,
272         .name = DRIVER_NAME,
273         .desc = DRIVER_DESC,
274         .date = DRIVER_DATE,
275         .major = DRIVER_MAJOR,
276         .minor = DRIVER_MINOR,
277         .patchlevel = DRIVER_PATCHLEVEL,
278
279         .gem_free_object_unlocked = vbox_gem_free_object,
280         .dumb_create = vbox_dumb_create,
281         .dumb_map_offset = vbox_dumb_mmap_offset,
282         .dumb_destroy = drm_gem_dumb_destroy,
283         .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
284         .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
285         .gem_prime_export = drm_gem_prime_export,
286         .gem_prime_import = drm_gem_prime_import,
287         .gem_prime_pin = vbox_gem_prime_pin,
288         .gem_prime_unpin = vbox_gem_prime_unpin,
289         .gem_prime_get_sg_table = vbox_gem_prime_get_sg_table,
290         .gem_prime_import_sg_table = vbox_gem_prime_import_sg_table,
291         .gem_prime_vmap = vbox_gem_prime_vmap,
292         .gem_prime_vunmap = vbox_gem_prime_vunmap,
293         .gem_prime_mmap = vbox_gem_prime_mmap,
294 };
295
296 static int __init vbox_init(void)
297 {
298 #ifdef CONFIG_VGA_CONSOLE
299         if (vgacon_text_force() && vbox_modeset == -1)
300                 return -EINVAL;
301 #endif
302
303         if (vbox_modeset == 0)
304                 return -EINVAL;
305
306         return pci_register_driver(&vbox_pci_driver);
307 }
308
309 static void __exit vbox_exit(void)
310 {
311         pci_unregister_driver(&vbox_pci_driver);
312 }
313
314 module_init(vbox_init);
315 module_exit(vbox_exit);
316
317 MODULE_AUTHOR("Oracle Corporation");
318 MODULE_DESCRIPTION(DRIVER_DESC);
319 MODULE_LICENSE("GPL and additional rights");