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 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 .open = drm_open, 195 .release = drm_release, 196 .unlocked_ioctl = drm_ioctl, 197 .compat_ioctl = drm_compat_ioctl, 198 .mmap = vbox_mmap, 199 .poll = drm_poll, 200 .read = drm_read, 201 }; 202 203 static struct drm_driver driver = { 204 .driver_features = 205 DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | DRIVER_ATOMIC, 206 207 .lastclose = drm_fb_helper_lastclose, 208 209 .fops = &vbox_fops, 210 .irq_handler = vbox_irq_handler, 211 .name = DRIVER_NAME, 212 .desc = DRIVER_DESC, 213 .date = DRIVER_DATE, 214 .major = DRIVER_MAJOR, 215 .minor = DRIVER_MINOR, 216 .patchlevel = DRIVER_PATCHLEVEL, 217 218 .gem_free_object_unlocked = vbox_gem_free_object, 219 .dumb_create = vbox_dumb_create, 220 .dumb_map_offset = vbox_dumb_mmap_offset, 221 .prime_handle_to_fd = drm_gem_prime_handle_to_fd, 222 .prime_fd_to_handle = drm_gem_prime_fd_to_handle, 223 .gem_prime_export = drm_gem_prime_export, 224 .gem_prime_import = drm_gem_prime_import, 225 .gem_prime_pin = vbox_gem_prime_pin, 226 .gem_prime_unpin = vbox_gem_prime_unpin, 227 .gem_prime_get_sg_table = vbox_gem_prime_get_sg_table, 228 .gem_prime_import_sg_table = vbox_gem_prime_import_sg_table, 229 .gem_prime_vmap = vbox_gem_prime_vmap, 230 .gem_prime_vunmap = vbox_gem_prime_vunmap, 231 .gem_prime_mmap = vbox_gem_prime_mmap, 232 }; 233 234 static int __init vbox_init(void) 235 { 236 #ifdef CONFIG_VGA_CONSOLE 237 if (vgacon_text_force() && vbox_modeset == -1) 238 return -EINVAL; 239 #endif 240 241 if (vbox_modeset == 0) 242 return -EINVAL; 243 244 return pci_register_driver(&vbox_pci_driver); 245 } 246 247 static void __exit vbox_exit(void) 248 { 249 pci_unregister_driver(&vbox_pci_driver); 250 } 251 252 module_init(vbox_init); 253 module_exit(vbox_exit); 254 255 MODULE_AUTHOR("Oracle Corporation"); 256 MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); 257 MODULE_DESCRIPTION(DRIVER_DESC); 258 MODULE_LICENSE("GPL and additional rights"); 259