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/module.h> 11 #include <linux/pci.h> 12 #include <linux/vt_kern.h> 13 14 #include <drm/drm_aperture.h> 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 #include <drm/drm_managed.h> 21 22 #include "vbox_drv.h" 23 24 static int vbox_modeset = -1; 25 26 MODULE_PARM_DESC(modeset, "Disable/Enable modesetting"); 27 module_param_named(modeset, vbox_modeset, int, 0400); 28 29 static const struct drm_driver driver; 30 31 static const struct pci_device_id pciidlist[] = { 32 { PCI_DEVICE(0x80ee, 0xbeef) }, 33 { } 34 }; 35 MODULE_DEVICE_TABLE(pci, pciidlist); 36 37 static int vbox_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 38 { 39 struct vbox_private *vbox; 40 int ret = 0; 41 42 if (!vbox_check_supported(VBE_DISPI_ID_HGSMI)) 43 return -ENODEV; 44 45 ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, &driver); 46 if (ret) 47 return ret; 48 49 vbox = devm_drm_dev_alloc(&pdev->dev, &driver, 50 struct vbox_private, ddev); 51 if (IS_ERR(vbox)) 52 return PTR_ERR(vbox); 53 54 pci_set_drvdata(pdev, vbox); 55 mutex_init(&vbox->hw_mutex); 56 57 ret = pcim_enable_device(pdev); 58 if (ret) 59 return ret; 60 61 ret = vbox_hw_init(vbox); 62 if (ret) 63 return ret; 64 65 ret = vbox_mm_init(vbox); 66 if (ret) 67 goto err_hw_fini; 68 69 ret = vbox_mode_init(vbox); 70 if (ret) 71 goto err_hw_fini; 72 73 ret = vbox_irq_init(vbox); 74 if (ret) 75 goto err_mode_fini; 76 77 ret = drm_dev_register(&vbox->ddev, 0); 78 if (ret) 79 goto err_irq_fini; 80 81 drm_fbdev_generic_setup(&vbox->ddev, 32); 82 83 return 0; 84 85 err_irq_fini: 86 vbox_irq_fini(vbox); 87 err_mode_fini: 88 vbox_mode_fini(vbox); 89 err_hw_fini: 90 vbox_hw_fini(vbox); 91 return ret; 92 } 93 94 static void vbox_pci_remove(struct pci_dev *pdev) 95 { 96 struct vbox_private *vbox = pci_get_drvdata(pdev); 97 98 drm_dev_unregister(&vbox->ddev); 99 vbox_irq_fini(vbox); 100 vbox_mode_fini(vbox); 101 vbox_hw_fini(vbox); 102 } 103 104 #ifdef CONFIG_PM_SLEEP 105 static int vbox_pm_suspend(struct device *dev) 106 { 107 struct vbox_private *vbox = dev_get_drvdata(dev); 108 struct pci_dev *pdev = to_pci_dev(dev); 109 int error; 110 111 error = drm_mode_config_helper_suspend(&vbox->ddev); 112 if (error) 113 return error; 114 115 pci_save_state(pdev); 116 pci_disable_device(pdev); 117 pci_set_power_state(pdev, PCI_D3hot); 118 119 return 0; 120 } 121 122 static int vbox_pm_resume(struct device *dev) 123 { 124 struct vbox_private *vbox = dev_get_drvdata(dev); 125 struct pci_dev *pdev = to_pci_dev(dev); 126 127 if (pci_enable_device(pdev)) 128 return -EIO; 129 130 return drm_mode_config_helper_resume(&vbox->ddev); 131 } 132 133 static int vbox_pm_freeze(struct device *dev) 134 { 135 struct vbox_private *vbox = dev_get_drvdata(dev); 136 137 return drm_mode_config_helper_suspend(&vbox->ddev); 138 } 139 140 static int vbox_pm_thaw(struct device *dev) 141 { 142 struct vbox_private *vbox = dev_get_drvdata(dev); 143 144 return drm_mode_config_helper_resume(&vbox->ddev); 145 } 146 147 static int vbox_pm_poweroff(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 const struct dev_pm_ops vbox_pm_ops = { 155 .suspend = vbox_pm_suspend, 156 .resume = vbox_pm_resume, 157 .freeze = vbox_pm_freeze, 158 .thaw = vbox_pm_thaw, 159 .poweroff = vbox_pm_poweroff, 160 .restore = vbox_pm_resume, 161 }; 162 #endif 163 164 static struct pci_driver vbox_pci_driver = { 165 .name = DRIVER_NAME, 166 .id_table = pciidlist, 167 .probe = vbox_pci_probe, 168 .remove = vbox_pci_remove, 169 #ifdef CONFIG_PM_SLEEP 170 .driver.pm = &vbox_pm_ops, 171 #endif 172 }; 173 174 DEFINE_DRM_GEM_FOPS(vbox_fops); 175 176 static const struct drm_driver driver = { 177 .driver_features = 178 DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC, 179 180 .lastclose = drm_fb_helper_lastclose, 181 182 .fops = &vbox_fops, 183 .name = DRIVER_NAME, 184 .desc = DRIVER_DESC, 185 .date = DRIVER_DATE, 186 .major = DRIVER_MAJOR, 187 .minor = DRIVER_MINOR, 188 .patchlevel = DRIVER_PATCHLEVEL, 189 190 DRM_GEM_VRAM_DRIVER, 191 }; 192 193 static int __init vbox_init(void) 194 { 195 if (drm_firmware_drivers_only() && vbox_modeset == -1) 196 return -EINVAL; 197 198 if (vbox_modeset == 0) 199 return -EINVAL; 200 201 return pci_register_driver(&vbox_pci_driver); 202 } 203 204 static void __exit vbox_exit(void) 205 { 206 pci_unregister_driver(&vbox_pci_driver); 207 } 208 209 module_init(vbox_init); 210 module_exit(vbox_exit); 211 212 MODULE_AUTHOR("Oracle Corporation"); 213 MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); 214 MODULE_DESCRIPTION(DRIVER_DESC); 215 MODULE_LICENSE("GPL and additional rights"); 216