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