1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright (C) 2013-2017 Oracle Corporation 4 * This file is based on ast_drv.c 5 * Copyright 2012 Red Hat Inc. 6 * Authors: Dave Airlie <airlied@redhat.com> 7 * Michael Thayer <michael.thayer@oracle.com, 8 * Hans de Goede <hdegoede@redhat.com> 9 */ 10 #include <linux/console.h> 11 #include <linux/module.h> 12 #include <linux/pci.h> 13 #include <linux/vt_kern.h> 14 15 #include <drm/drm_crtc_helper.h> 16 #include <drm/drm_drv.h> 17 #include <drm/drm_fb_helper.h> 18 #include <drm/drm_file.h> 19 #include <drm/drm_ioctl.h> 20 21 #include "vbox_drv.h" 22 23 static int vbox_modeset = -1; 24 25 MODULE_PARM_DESC(modeset, "Disable/Enable modesetting"); 26 module_param_named(modeset, vbox_modeset, int, 0400); 27 28 static struct drm_driver driver; 29 30 static const struct pci_device_id pciidlist[] = { 31 { PCI_DEVICE(0x80ee, 0xbeef) }, 32 { } 33 }; 34 MODULE_DEVICE_TABLE(pci, pciidlist); 35 36 static int vbox_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 37 { 38 struct vbox_private *vbox; 39 int ret = 0; 40 41 if (!vbox_check_supported(VBE_DISPI_ID_HGSMI)) 42 return -ENODEV; 43 44 ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "vboxvideodrmfb"); 45 if (ret) 46 return ret; 47 48 vbox = kzalloc(sizeof(*vbox), GFP_KERNEL); 49 if (!vbox) 50 return -ENOMEM; 51 52 ret = drm_dev_init(&vbox->ddev, &driver, &pdev->dev); 53 if (ret) { 54 kfree(vbox); 55 return ret; 56 } 57 58 vbox->ddev.pdev = pdev; 59 vbox->ddev.dev_private = vbox; 60 pci_set_drvdata(pdev, vbox); 61 mutex_init(&vbox->hw_mutex); 62 63 ret = pci_enable_device(pdev); 64 if (ret) 65 goto err_dev_put; 66 67 ret = vbox_hw_init(vbox); 68 if (ret) 69 goto err_pci_disable; 70 71 ret = vbox_mm_init(vbox); 72 if (ret) 73 goto err_hw_fini; 74 75 ret = vbox_mode_init(vbox); 76 if (ret) 77 goto err_mm_fini; 78 79 ret = vbox_irq_init(vbox); 80 if (ret) 81 goto err_mode_fini; 82 83 ret = drm_fbdev_generic_setup(&vbox->ddev, 32); 84 if (ret) 85 goto err_irq_fini; 86 87 ret = drm_dev_register(&vbox->ddev, 0); 88 if (ret) 89 goto err_irq_fini; 90 91 return 0; 92 93 err_irq_fini: 94 vbox_irq_fini(vbox); 95 err_mode_fini: 96 vbox_mode_fini(vbox); 97 err_mm_fini: 98 vbox_mm_fini(vbox); 99 err_hw_fini: 100 vbox_hw_fini(vbox); 101 err_pci_disable: 102 pci_disable_device(pdev); 103 err_dev_put: 104 drm_dev_put(&vbox->ddev); 105 return ret; 106 } 107 108 static void vbox_pci_remove(struct pci_dev *pdev) 109 { 110 struct vbox_private *vbox = pci_get_drvdata(pdev); 111 112 drm_dev_unregister(&vbox->ddev); 113 vbox_irq_fini(vbox); 114 vbox_mode_fini(vbox); 115 vbox_mm_fini(vbox); 116 vbox_hw_fini(vbox); 117 drm_dev_put(&vbox->ddev); 118 } 119 120 #ifdef CONFIG_PM_SLEEP 121 static int vbox_pm_suspend(struct device *dev) 122 { 123 struct vbox_private *vbox = dev_get_drvdata(dev); 124 int error; 125 126 error = drm_mode_config_helper_suspend(&vbox->ddev); 127 if (error) 128 return error; 129 130 pci_save_state(vbox->ddev.pdev); 131 pci_disable_device(vbox->ddev.pdev); 132 pci_set_power_state(vbox->ddev.pdev, PCI_D3hot); 133 134 return 0; 135 } 136 137 static int vbox_pm_resume(struct device *dev) 138 { 139 struct vbox_private *vbox = dev_get_drvdata(dev); 140 141 if (pci_enable_device(vbox->ddev.pdev)) 142 return -EIO; 143 144 return drm_mode_config_helper_resume(&vbox->ddev); 145 } 146 147 static int vbox_pm_freeze(struct device *dev) 148 { 149 struct vbox_private *vbox = dev_get_drvdata(dev); 150 151 return drm_mode_config_helper_suspend(&vbox->ddev); 152 } 153 154 static int vbox_pm_thaw(struct device *dev) 155 { 156 struct vbox_private *vbox = dev_get_drvdata(dev); 157 158 return drm_mode_config_helper_resume(&vbox->ddev); 159 } 160 161 static int vbox_pm_poweroff(struct device *dev) 162 { 163 struct vbox_private *vbox = dev_get_drvdata(dev); 164 165 return drm_mode_config_helper_suspend(&vbox->ddev); 166 } 167 168 static const struct dev_pm_ops vbox_pm_ops = { 169 .suspend = vbox_pm_suspend, 170 .resume = vbox_pm_resume, 171 .freeze = vbox_pm_freeze, 172 .thaw = vbox_pm_thaw, 173 .poweroff = vbox_pm_poweroff, 174 .restore = vbox_pm_resume, 175 }; 176 #endif 177 178 static struct pci_driver vbox_pci_driver = { 179 .name = DRIVER_NAME, 180 .id_table = pciidlist, 181 .probe = vbox_pci_probe, 182 .remove = vbox_pci_remove, 183 #ifdef CONFIG_PM_SLEEP 184 .driver.pm = &vbox_pm_ops, 185 #endif 186 }; 187 188 DEFINE_DRM_GEM_FOPS(vbox_fops); 189 190 static struct drm_driver driver = { 191 .driver_features = 192 DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC, 193 194 .lastclose = drm_fb_helper_lastclose, 195 196 .fops = &vbox_fops, 197 .irq_handler = vbox_irq_handler, 198 .name = DRIVER_NAME, 199 .desc = DRIVER_DESC, 200 .date = DRIVER_DATE, 201 .major = DRIVER_MAJOR, 202 .minor = DRIVER_MINOR, 203 .patchlevel = DRIVER_PATCHLEVEL, 204 205 DRM_GEM_VRAM_DRIVER, 206 }; 207 208 static int __init vbox_init(void) 209 { 210 #ifdef CONFIG_VGA_CONSOLE 211 if (vgacon_text_force() && vbox_modeset == -1) 212 return -EINVAL; 213 #endif 214 215 if (vbox_modeset == 0) 216 return -EINVAL; 217 218 return pci_register_driver(&vbox_pci_driver); 219 } 220 221 static void __exit vbox_exit(void) 222 { 223 pci_unregister_driver(&vbox_pci_driver); 224 } 225 226 module_init(vbox_init); 227 module_exit(vbox_exit); 228 229 MODULE_AUTHOR("Oracle Corporation"); 230 MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); 231 MODULE_DESCRIPTION(DRIVER_DESC); 232 MODULE_LICENSE("GPL and additional rights"); 233