linux/drivers/gpu/drm/vkms/vkms_drv.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2
   3/**
   4 * DOC: vkms (Virtual Kernel Modesetting)
   5 *
   6 * vkms is a software-only model of a kms driver that is useful for testing,
   7 * or for running X (or similar) on headless machines and be able to still
   8 * use the GPU. vkms aims to enable a virtual display without the need for
   9 * a hardware display capability.
  10 */
  11
  12#include <linux/module.h>
  13#include <drm/drm_gem.h>
  14#include <drm/drm_atomic_helper.h>
  15#include <drm/drm_gem_framebuffer_helper.h>
  16#include <drm/drm_fb_helper.h>
  17#include <drm/drm_probe_helper.h>
  18#include "vkms_drv.h"
  19
  20#define DRIVER_NAME     "vkms"
  21#define DRIVER_DESC     "Virtual Kernel Mode Setting"
  22#define DRIVER_DATE     "20180514"
  23#define DRIVER_MAJOR    1
  24#define DRIVER_MINOR    0
  25
  26static struct vkms_device *vkms_device;
  27
  28bool enable_cursor;
  29module_param_named(enable_cursor, enable_cursor, bool, 0444);
  30MODULE_PARM_DESC(enable_cursor, "Enable/Disable cursor support");
  31
  32static const struct file_operations vkms_driver_fops = {
  33        .owner          = THIS_MODULE,
  34        .open           = drm_open,
  35        .mmap           = drm_gem_mmap,
  36        .unlocked_ioctl = drm_ioctl,
  37        .compat_ioctl   = drm_compat_ioctl,
  38        .poll           = drm_poll,
  39        .read           = drm_read,
  40        .llseek         = no_llseek,
  41        .release        = drm_release,
  42};
  43
  44static const struct vm_operations_struct vkms_gem_vm_ops = {
  45        .fault = vkms_gem_fault,
  46        .open = drm_gem_vm_open,
  47        .close = drm_gem_vm_close,
  48};
  49
  50static void vkms_release(struct drm_device *dev)
  51{
  52        struct vkms_device *vkms = container_of(dev, struct vkms_device, drm);
  53
  54        platform_device_unregister(vkms->platform);
  55        drm_atomic_helper_shutdown(&vkms->drm);
  56        drm_mode_config_cleanup(&vkms->drm);
  57        drm_dev_fini(&vkms->drm);
  58        destroy_workqueue(vkms->output.crc_workq);
  59}
  60
  61static struct drm_driver vkms_driver = {
  62        .driver_features        = DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_GEM,
  63        .release                = vkms_release,
  64        .fops                   = &vkms_driver_fops,
  65        .dumb_create            = vkms_dumb_create,
  66        .gem_vm_ops             = &vkms_gem_vm_ops,
  67        .gem_free_object_unlocked = vkms_gem_free_object,
  68        .get_vblank_timestamp   = vkms_get_vblank_timestamp,
  69
  70        .name                   = DRIVER_NAME,
  71        .desc                   = DRIVER_DESC,
  72        .date                   = DRIVER_DATE,
  73        .major                  = DRIVER_MAJOR,
  74        .minor                  = DRIVER_MINOR,
  75};
  76
  77static const struct drm_mode_config_funcs vkms_mode_funcs = {
  78        .fb_create = drm_gem_fb_create,
  79        .atomic_check = drm_atomic_helper_check,
  80        .atomic_commit = drm_atomic_helper_commit,
  81};
  82
  83static int vkms_modeset_init(struct vkms_device *vkmsdev)
  84{
  85        struct drm_device *dev = &vkmsdev->drm;
  86
  87        drm_mode_config_init(dev);
  88        dev->mode_config.funcs = &vkms_mode_funcs;
  89        dev->mode_config.min_width = XRES_MIN;
  90        dev->mode_config.min_height = YRES_MIN;
  91        dev->mode_config.max_width = XRES_MAX;
  92        dev->mode_config.max_height = YRES_MAX;
  93        dev->mode_config.preferred_depth = 24;
  94
  95        return vkms_output_init(vkmsdev);
  96}
  97
  98static int __init vkms_init(void)
  99{
 100        int ret;
 101
 102        vkms_device = kzalloc(sizeof(*vkms_device), GFP_KERNEL);
 103        if (!vkms_device)
 104                return -ENOMEM;
 105
 106        vkms_device->platform =
 107                platform_device_register_simple(DRIVER_NAME, -1, NULL, 0);
 108        if (IS_ERR(vkms_device->platform)) {
 109                ret = PTR_ERR(vkms_device->platform);
 110                goto out_free;
 111        }
 112
 113        ret = drm_dev_init(&vkms_device->drm, &vkms_driver,
 114                           &vkms_device->platform->dev);
 115        if (ret)
 116                goto out_unregister;
 117
 118        vkms_device->drm.irq_enabled = true;
 119
 120        ret = drm_vblank_init(&vkms_device->drm, 1);
 121        if (ret) {
 122                DRM_ERROR("Failed to vblank\n");
 123                goto out_fini;
 124        }
 125
 126        ret = vkms_modeset_init(vkms_device);
 127        if (ret)
 128                goto out_fini;
 129
 130        ret = drm_dev_register(&vkms_device->drm, 0);
 131        if (ret)
 132                goto out_fini;
 133
 134        return 0;
 135
 136out_fini:
 137        drm_dev_fini(&vkms_device->drm);
 138
 139out_unregister:
 140        platform_device_unregister(vkms_device->platform);
 141
 142out_free:
 143        kfree(vkms_device);
 144        return ret;
 145}
 146
 147static void __exit vkms_exit(void)
 148{
 149        if (!vkms_device) {
 150                DRM_INFO("vkms_device is NULL.\n");
 151                return;
 152        }
 153
 154        drm_dev_unregister(&vkms_device->drm);
 155        drm_dev_put(&vkms_device->drm);
 156
 157        kfree(vkms_device);
 158}
 159
 160module_init(vkms_init);
 161module_exit(vkms_exit);
 162
 163MODULE_AUTHOR("Haneen Mohammed <hamohammed.sa@gmail.com>");
 164MODULE_AUTHOR("Rodrigo Siqueira <rodrigosiqueiramelo@gmail.com>");
 165MODULE_DESCRIPTION(DRIVER_DESC);
 166MODULE_LICENSE("GPL");
 167