Linux-libre 5.4.49-gnu
[librecmc/linux-libre.git] / drivers / gpu / drm / bochs / bochs_drv.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  */
4
5 #include <linux/module.h>
6 #include <linux/pci.h>
7
8 #include <drm/drm_drv.h>
9 #include <drm/drm_atomic_helper.h>
10
11 #include "bochs.h"
12
13 static int bochs_modeset = -1;
14 module_param_named(modeset, bochs_modeset, int, 0444);
15 MODULE_PARM_DESC(modeset, "enable/disable kernel modesetting");
16
17 /* ---------------------------------------------------------------------- */
18 /* drm interface                                                          */
19
20 static void bochs_unload(struct drm_device *dev)
21 {
22         struct bochs_device *bochs = dev->dev_private;
23
24         bochs_kms_fini(bochs);
25         bochs_mm_fini(bochs);
26         bochs_hw_fini(dev);
27         kfree(bochs);
28         dev->dev_private = NULL;
29 }
30
31 static int bochs_load(struct drm_device *dev)
32 {
33         struct bochs_device *bochs;
34         int ret;
35
36         bochs = kzalloc(sizeof(*bochs), GFP_KERNEL);
37         if (bochs == NULL)
38                 return -ENOMEM;
39         dev->dev_private = bochs;
40         bochs->dev = dev;
41
42         ret = bochs_hw_init(dev);
43         if (ret)
44                 goto err;
45
46         ret = bochs_mm_init(bochs);
47         if (ret)
48                 goto err;
49
50         ret = bochs_kms_init(bochs);
51         if (ret)
52                 goto err;
53
54         return 0;
55
56 err:
57         bochs_unload(dev);
58         return ret;
59 }
60
61 static const struct file_operations bochs_fops = {
62         .owner          = THIS_MODULE,
63         DRM_VRAM_MM_FILE_OPERATIONS
64 };
65
66 static struct drm_driver bochs_driver = {
67         .driver_features        = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
68         .fops                   = &bochs_fops,
69         .name                   = "bochs-drm",
70         .desc                   = "bochs dispi vga interface (qemu stdvga)",
71         .date                   = "20130925",
72         .major                  = 1,
73         .minor                  = 0,
74         DRM_GEM_VRAM_DRIVER,
75 };
76
77 /* ---------------------------------------------------------------------- */
78 /* pm interface                                                           */
79
80 #ifdef CONFIG_PM_SLEEP
81 static int bochs_pm_suspend(struct device *dev)
82 {
83         struct drm_device *drm_dev = dev_get_drvdata(dev);
84
85         return drm_mode_config_helper_suspend(drm_dev);
86 }
87
88 static int bochs_pm_resume(struct device *dev)
89 {
90         struct drm_device *drm_dev = dev_get_drvdata(dev);
91
92         return drm_mode_config_helper_resume(drm_dev);
93 }
94 #endif
95
96 static const struct dev_pm_ops bochs_pm_ops = {
97         SET_SYSTEM_SLEEP_PM_OPS(bochs_pm_suspend,
98                                 bochs_pm_resume)
99 };
100
101 /* ---------------------------------------------------------------------- */
102 /* pci interface                                                          */
103
104 static int bochs_pci_probe(struct pci_dev *pdev,
105                            const struct pci_device_id *ent)
106 {
107         struct drm_device *dev;
108         unsigned long fbsize;
109         int ret;
110
111         fbsize = pci_resource_len(pdev, 0);
112         if (fbsize < 4 * 1024 * 1024) {
113                 DRM_ERROR("less than 4 MB video memory, ignoring device\n");
114                 return -ENOMEM;
115         }
116
117         ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, 0, "bochsdrmfb");
118         if (ret)
119                 return ret;
120
121         dev = drm_dev_alloc(&bochs_driver, &pdev->dev);
122         if (IS_ERR(dev))
123                 return PTR_ERR(dev);
124
125         ret = pci_enable_device(pdev);
126         if (ret)
127                 goto err_free_dev;
128
129         dev->pdev = pdev;
130         pci_set_drvdata(pdev, dev);
131
132         ret = bochs_load(dev);
133         if (ret)
134                 goto err_free_dev;
135
136         ret = drm_dev_register(dev, 0);
137         if (ret)
138                 goto err_unload;
139
140         drm_fbdev_generic_setup(dev, 32);
141         return ret;
142
143 err_unload:
144         bochs_unload(dev);
145 err_free_dev:
146         drm_dev_put(dev);
147         return ret;
148 }
149
150 static void bochs_pci_remove(struct pci_dev *pdev)
151 {
152         struct drm_device *dev = pci_get_drvdata(pdev);
153
154         drm_atomic_helper_shutdown(dev);
155         drm_dev_unregister(dev);
156         bochs_unload(dev);
157         drm_dev_put(dev);
158 }
159
160 static const struct pci_device_id bochs_pci_tbl[] = {
161         {
162                 .vendor      = 0x1234,
163                 .device      = 0x1111,
164                 .subvendor   = PCI_SUBVENDOR_ID_REDHAT_QUMRANET,
165                 .subdevice   = PCI_SUBDEVICE_ID_QEMU,
166                 .driver_data = BOCHS_QEMU_STDVGA,
167         },
168         {
169                 .vendor      = 0x1234,
170                 .device      = 0x1111,
171                 .subvendor   = PCI_ANY_ID,
172                 .subdevice   = PCI_ANY_ID,
173                 .driver_data = BOCHS_UNKNOWN,
174         },
175         { /* end of list */ }
176 };
177
178 static struct pci_driver bochs_pci_driver = {
179         .name =         "bochs-drm",
180         .id_table =     bochs_pci_tbl,
181         .probe =        bochs_pci_probe,
182         .remove =       bochs_pci_remove,
183         .driver.pm =    &bochs_pm_ops,
184 };
185
186 /* ---------------------------------------------------------------------- */
187 /* module init/exit                                                       */
188
189 static int __init bochs_init(void)
190 {
191         if (vgacon_text_force() && bochs_modeset == -1)
192                 return -EINVAL;
193
194         if (bochs_modeset == 0)
195                 return -EINVAL;
196
197         return pci_register_driver(&bochs_pci_driver);
198 }
199
200 static void __exit bochs_exit(void)
201 {
202         pci_unregister_driver(&bochs_pci_driver);
203 }
204
205 module_init(bochs_init);
206 module_exit(bochs_exit);
207
208 MODULE_DEVICE_TABLE(pci, bochs_pci_tbl);
209 MODULE_AUTHOR("Gerd Hoffmann <kraxel@redhat.com>");
210 MODULE_LICENSE("GPL");