root/drivers/gpu/drm/vkms/vkms_drv.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. vkms_release
  2. vkms_atomic_commit_tail
  3. vkms_modeset_init
  4. vkms_init
  5. vkms_exit

   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 <linux/platform_device.h>
  14 
  15 #include <drm/drm_atomic.h>
  16 #include <drm/drm_atomic_helper.h>
  17 #include <drm/drm_drv.h>
  18 #include <drm/drm_fb_helper.h>
  19 #include <drm/drm_file.h>
  20 #include <drm/drm_gem.h>
  21 #include <drm/drm_gem_framebuffer_helper.h>
  22 #include <drm/drm_ioctl.h>
  23 #include <drm/drm_probe_helper.h>
  24 #include <drm/drm_vblank.h>
  25 
  26 #include "vkms_drv.h"
  27 
  28 #define DRIVER_NAME     "vkms"
  29 #define DRIVER_DESC     "Virtual Kernel Mode Setting"
  30 #define DRIVER_DATE     "20180514"
  31 #define DRIVER_MAJOR    1
  32 #define DRIVER_MINOR    0
  33 
  34 static struct vkms_device *vkms_device;
  35 
  36 bool enable_cursor;
  37 module_param_named(enable_cursor, enable_cursor, bool, 0444);
  38 MODULE_PARM_DESC(enable_cursor, "Enable/Disable cursor support");
  39 
  40 static const struct file_operations vkms_driver_fops = {
  41         .owner          = THIS_MODULE,
  42         .open           = drm_open,
  43         .mmap           = drm_gem_mmap,
  44         .unlocked_ioctl = drm_ioctl,
  45         .compat_ioctl   = drm_compat_ioctl,
  46         .poll           = drm_poll,
  47         .read           = drm_read,
  48         .llseek         = no_llseek,
  49         .release        = drm_release,
  50 };
  51 
  52 static const struct vm_operations_struct vkms_gem_vm_ops = {
  53         .fault = vkms_gem_fault,
  54         .open = drm_gem_vm_open,
  55         .close = drm_gem_vm_close,
  56 };
  57 
  58 static void vkms_release(struct drm_device *dev)
  59 {
  60         struct vkms_device *vkms = container_of(dev, struct vkms_device, drm);
  61 
  62         platform_device_unregister(vkms->platform);
  63         drm_atomic_helper_shutdown(&vkms->drm);
  64         drm_mode_config_cleanup(&vkms->drm);
  65         drm_dev_fini(&vkms->drm);
  66         destroy_workqueue(vkms->output.composer_workq);
  67 }
  68 
  69 static void vkms_atomic_commit_tail(struct drm_atomic_state *old_state)
  70 {
  71         struct drm_device *dev = old_state->dev;
  72         struct drm_crtc *crtc;
  73         struct drm_crtc_state *old_crtc_state;
  74         int i;
  75 
  76         drm_atomic_helper_commit_modeset_disables(dev, old_state);
  77 
  78         drm_atomic_helper_commit_planes(dev, old_state, 0);
  79 
  80         drm_atomic_helper_commit_modeset_enables(dev, old_state);
  81 
  82         drm_atomic_helper_fake_vblank(old_state);
  83 
  84         drm_atomic_helper_commit_hw_done(old_state);
  85 
  86         drm_atomic_helper_wait_for_vblanks(dev, old_state);
  87 
  88         for_each_old_crtc_in_state(old_state, crtc, old_crtc_state, i) {
  89                 struct vkms_crtc_state *vkms_state =
  90                         to_vkms_crtc_state(old_crtc_state);
  91 
  92                 flush_work(&vkms_state->composer_work);
  93         }
  94 
  95         drm_atomic_helper_cleanup_planes(dev, old_state);
  96 }
  97 
  98 static struct drm_driver vkms_driver = {
  99         .driver_features        = DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_GEM,
 100         .release                = vkms_release,
 101         .fops                   = &vkms_driver_fops,
 102         .dumb_create            = vkms_dumb_create,
 103         .gem_vm_ops             = &vkms_gem_vm_ops,
 104         .gem_free_object_unlocked = vkms_gem_free_object,
 105         .get_vblank_timestamp   = vkms_get_vblank_timestamp,
 106 
 107         .name                   = DRIVER_NAME,
 108         .desc                   = DRIVER_DESC,
 109         .date                   = DRIVER_DATE,
 110         .major                  = DRIVER_MAJOR,
 111         .minor                  = DRIVER_MINOR,
 112 };
 113 
 114 static const struct drm_mode_config_funcs vkms_mode_funcs = {
 115         .fb_create = drm_gem_fb_create,
 116         .atomic_check = drm_atomic_helper_check,
 117         .atomic_commit = drm_atomic_helper_commit,
 118 };
 119 
 120 static const struct drm_mode_config_helper_funcs vkms_mode_config_helpers = {
 121         .atomic_commit_tail = vkms_atomic_commit_tail,
 122 };
 123 
 124 static int vkms_modeset_init(struct vkms_device *vkmsdev)
 125 {
 126         struct drm_device *dev = &vkmsdev->drm;
 127 
 128         drm_mode_config_init(dev);
 129         dev->mode_config.funcs = &vkms_mode_funcs;
 130         dev->mode_config.min_width = XRES_MIN;
 131         dev->mode_config.min_height = YRES_MIN;
 132         dev->mode_config.max_width = XRES_MAX;
 133         dev->mode_config.max_height = YRES_MAX;
 134         dev->mode_config.preferred_depth = 24;
 135         dev->mode_config.helper_private = &vkms_mode_config_helpers;
 136 
 137         return vkms_output_init(vkmsdev, 0);
 138 }
 139 
 140 static int __init vkms_init(void)
 141 {
 142         int ret;
 143 
 144         vkms_device = kzalloc(sizeof(*vkms_device), GFP_KERNEL);
 145         if (!vkms_device)
 146                 return -ENOMEM;
 147 
 148         vkms_device->platform =
 149                 platform_device_register_simple(DRIVER_NAME, -1, NULL, 0);
 150         if (IS_ERR(vkms_device->platform)) {
 151                 ret = PTR_ERR(vkms_device->platform);
 152                 goto out_free;
 153         }
 154 
 155         ret = drm_dev_init(&vkms_device->drm, &vkms_driver,
 156                            &vkms_device->platform->dev);
 157         if (ret)
 158                 goto out_unregister;
 159 
 160         vkms_device->drm.irq_enabled = true;
 161 
 162         ret = drm_vblank_init(&vkms_device->drm, 1);
 163         if (ret) {
 164                 DRM_ERROR("Failed to vblank\n");
 165                 goto out_fini;
 166         }
 167 
 168         ret = vkms_modeset_init(vkms_device);
 169         if (ret)
 170                 goto out_fini;
 171 
 172         ret = drm_dev_register(&vkms_device->drm, 0);
 173         if (ret)
 174                 goto out_fini;
 175 
 176         return 0;
 177 
 178 out_fini:
 179         drm_dev_fini(&vkms_device->drm);
 180 
 181 out_unregister:
 182         platform_device_unregister(vkms_device->platform);
 183 
 184 out_free:
 185         kfree(vkms_device);
 186         return ret;
 187 }
 188 
 189 static void __exit vkms_exit(void)
 190 {
 191         if (!vkms_device) {
 192                 DRM_INFO("vkms_device is NULL.\n");
 193                 return;
 194         }
 195 
 196         drm_dev_unregister(&vkms_device->drm);
 197         drm_dev_put(&vkms_device->drm);
 198 
 199         kfree(vkms_device);
 200 }
 201 
 202 module_init(vkms_init);
 203 module_exit(vkms_exit);
 204 
 205 MODULE_AUTHOR("Haneen Mohammed <hamohammed.sa@gmail.com>");
 206 MODULE_AUTHOR("Rodrigo Siqueira <rodrigosiqueiramelo@gmail.com>");
 207 MODULE_DESCRIPTION(DRIVER_DESC);
 208 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */