]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/gpu/drm/bochs/bochs_drv.c
Linux 5.6-rc7
[linux.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 DEFINE_DRM_GEM_FOPS(bochs_fops);
62
63 static struct drm_driver bochs_driver = {
64         .driver_features        = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
65         .fops                   = &bochs_fops,
66         .name                   = "bochs-drm",
67         .desc                   = "bochs dispi vga interface (qemu stdvga)",
68         .date                   = "20130925",
69         .major                  = 1,
70         .minor                  = 0,
71         DRM_GEM_VRAM_DRIVER,
72 };
73
74 /* ---------------------------------------------------------------------- */
75 /* pm interface                                                           */
76
77 #ifdef CONFIG_PM_SLEEP
78 static int bochs_pm_suspend(struct device *dev)
79 {
80         struct drm_device *drm_dev = dev_get_drvdata(dev);
81
82         return drm_mode_config_helper_suspend(drm_dev);
83 }
84
85 static int bochs_pm_resume(struct device *dev)
86 {
87         struct drm_device *drm_dev = dev_get_drvdata(dev);
88
89         return drm_mode_config_helper_resume(drm_dev);
90 }
91 #endif
92
93 static const struct dev_pm_ops bochs_pm_ops = {
94         SET_SYSTEM_SLEEP_PM_OPS(bochs_pm_suspend,
95                                 bochs_pm_resume)
96 };
97
98 /* ---------------------------------------------------------------------- */
99 /* pci interface                                                          */
100
101 static int bochs_pci_probe(struct pci_dev *pdev,
102                            const struct pci_device_id *ent)
103 {
104         struct drm_device *dev;
105         unsigned long fbsize;
106         int ret;
107
108         fbsize = pci_resource_len(pdev, 0);
109         if (fbsize < 4 * 1024 * 1024) {
110                 DRM_ERROR("less than 4 MB video memory, ignoring device\n");
111                 return -ENOMEM;
112         }
113
114         ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "bochsdrmfb");
115         if (ret)
116                 return ret;
117
118         dev = drm_dev_alloc(&bochs_driver, &pdev->dev);
119         if (IS_ERR(dev))
120                 return PTR_ERR(dev);
121
122         ret = pci_enable_device(pdev);
123         if (ret)
124                 goto err_free_dev;
125
126         dev->pdev = pdev;
127         pci_set_drvdata(pdev, dev);
128
129         ret = bochs_load(dev);
130         if (ret)
131                 goto err_free_dev;
132
133         ret = drm_dev_register(dev, 0);
134         if (ret)
135                 goto err_unload;
136
137         drm_fbdev_generic_setup(dev, 32);
138         return ret;
139
140 err_unload:
141         bochs_unload(dev);
142 err_free_dev:
143         drm_dev_put(dev);
144         return ret;
145 }
146
147 static void bochs_pci_remove(struct pci_dev *pdev)
148 {
149         struct drm_device *dev = pci_get_drvdata(pdev);
150
151         drm_atomic_helper_shutdown(dev);
152         drm_dev_unregister(dev);
153         bochs_unload(dev);
154         drm_dev_put(dev);
155 }
156
157 static const struct pci_device_id bochs_pci_tbl[] = {
158         {
159                 .vendor      = 0x1234,
160                 .device      = 0x1111,
161                 .subvendor   = PCI_SUBVENDOR_ID_REDHAT_QUMRANET,
162                 .subdevice   = PCI_SUBDEVICE_ID_QEMU,
163                 .driver_data = BOCHS_QEMU_STDVGA,
164         },
165         {
166                 .vendor      = 0x1234,
167                 .device      = 0x1111,
168                 .subvendor   = PCI_ANY_ID,
169                 .subdevice   = PCI_ANY_ID,
170                 .driver_data = BOCHS_UNKNOWN,
171         },
172         { /* end of list */ }
173 };
174
175 static struct pci_driver bochs_pci_driver = {
176         .name =         "bochs-drm",
177         .id_table =     bochs_pci_tbl,
178         .probe =        bochs_pci_probe,
179         .remove =       bochs_pci_remove,
180         .driver.pm =    &bochs_pm_ops,
181 };
182
183 /* ---------------------------------------------------------------------- */
184 /* module init/exit                                                       */
185
186 static int __init bochs_init(void)
187 {
188         if (vgacon_text_force() && bochs_modeset == -1)
189                 return -EINVAL;
190
191         if (bochs_modeset == 0)
192                 return -EINVAL;
193
194         return pci_register_driver(&bochs_pci_driver);
195 }
196
197 static void __exit bochs_exit(void)
198 {
199         pci_unregister_driver(&bochs_pci_driver);
200 }
201
202 module_init(bochs_init);
203 module_exit(bochs_exit);
204
205 MODULE_DEVICE_TABLE(pci, bochs_pci_tbl);
206 MODULE_AUTHOR("Gerd Hoffmann <kraxel@redhat.com>");
207 MODULE_LICENSE("GPL");