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