1 // SPDX-License-Identifier: GPL-2.0-or-later
6 #include <linux/module.h>
7 #include <linux/slab.h>
8 #include <drm/drm_fb_helper.h>
9 #include <drm/drm_probe_helper.h>
10 #include <drm/drm_atomic_helper.h>
14 static int bochs_modeset = -1;
15 module_param_named(modeset, bochs_modeset, int, 0444);
16 MODULE_PARM_DESC(modeset, "enable/disable kernel modesetting");
18 /* ---------------------------------------------------------------------- */
21 static void bochs_unload(struct drm_device *dev)
23 struct bochs_device *bochs = dev->dev_private;
25 bochs_kms_fini(bochs);
29 dev->dev_private = NULL;
32 static int bochs_load(struct drm_device *dev)
34 struct bochs_device *bochs;
37 bochs = kzalloc(sizeof(*bochs), GFP_KERNEL);
40 dev->dev_private = bochs;
43 ret = bochs_hw_init(dev);
47 ret = bochs_mm_init(bochs);
51 ret = bochs_kms_init(bochs);
62 static const struct file_operations bochs_fops = {
64 DRM_VRAM_MM_FILE_OPERATIONS
67 static struct drm_driver bochs_driver = {
68 .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC |
72 .desc = "bochs dispi vga interface (qemu stdvga)",
77 DRM_GEM_VRAM_DRIVER_PRIME,
80 /* ---------------------------------------------------------------------- */
83 #ifdef CONFIG_PM_SLEEP
84 static int bochs_pm_suspend(struct device *dev)
86 struct pci_dev *pdev = to_pci_dev(dev);
87 struct drm_device *drm_dev = pci_get_drvdata(pdev);
89 return drm_mode_config_helper_suspend(drm_dev);
92 static int bochs_pm_resume(struct device *dev)
94 struct pci_dev *pdev = to_pci_dev(dev);
95 struct drm_device *drm_dev = pci_get_drvdata(pdev);
97 return drm_mode_config_helper_resume(drm_dev);
101 static const struct dev_pm_ops bochs_pm_ops = {
102 SET_SYSTEM_SLEEP_PM_OPS(bochs_pm_suspend,
106 /* ---------------------------------------------------------------------- */
109 static int bochs_pci_probe(struct pci_dev *pdev,
110 const struct pci_device_id *ent)
112 struct drm_device *dev;
113 unsigned long fbsize;
116 fbsize = pci_resource_len(pdev, 0);
117 if (fbsize < 4 * 1024 * 1024) {
118 DRM_ERROR("less than 4 MB video memory, ignoring device\n");
122 ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, 0, "bochsdrmfb");
126 dev = drm_dev_alloc(&bochs_driver, &pdev->dev);
130 ret = pci_enable_device(pdev);
135 pci_set_drvdata(pdev, dev);
137 ret = bochs_load(dev);
141 ret = drm_dev_register(dev, 0);
145 drm_fbdev_generic_setup(dev, 32);
155 static void bochs_pci_remove(struct pci_dev *pdev)
157 struct drm_device *dev = pci_get_drvdata(pdev);
159 drm_atomic_helper_shutdown(dev);
160 drm_dev_unregister(dev);
165 static const struct pci_device_id bochs_pci_tbl[] = {
169 .subvendor = PCI_SUBVENDOR_ID_REDHAT_QUMRANET,
170 .subdevice = PCI_SUBDEVICE_ID_QEMU,
171 .driver_data = BOCHS_QEMU_STDVGA,
176 .subvendor = PCI_ANY_ID,
177 .subdevice = PCI_ANY_ID,
178 .driver_data = BOCHS_UNKNOWN,
180 { /* end of list */ }
183 static struct pci_driver bochs_pci_driver = {
185 .id_table = bochs_pci_tbl,
186 .probe = bochs_pci_probe,
187 .remove = bochs_pci_remove,
188 .driver.pm = &bochs_pm_ops,
191 /* ---------------------------------------------------------------------- */
192 /* module init/exit */
194 static int __init bochs_init(void)
196 if (vgacon_text_force() && bochs_modeset == -1)
199 if (bochs_modeset == 0)
202 return pci_register_driver(&bochs_pci_driver);
205 static void __exit bochs_exit(void)
207 pci_unregister_driver(&bochs_pci_driver);
210 module_init(bochs_init);
211 module_exit(bochs_exit);
213 MODULE_DEVICE_TABLE(pci, bochs_pci_tbl);
214 MODULE_AUTHOR("Gerd Hoffmann <kraxel@redhat.com>");
215 MODULE_LICENSE("GPL");