2018-05-14 17:33:46 +03:00
/*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*/
2018-09-07 20:41:36 +03:00
/**
* DOC : vkms ( Virtual Kernel Modesetting )
*
* vkms is a software - only model of a kms driver that is useful for testing ,
* or for running X ( or similar ) on headless machines and be able to still
* use the GPU . vkms aims to enable a virtual display without the need for
* a hardware display capability .
*/
2018-05-14 17:33:46 +03:00
# include <linux/module.h>
# include <drm/drm_gem.h>
# include <drm/drm_crtc_helper.h>
2018-05-17 02:55:36 +03:00
# include <drm/drm_atomic_helper.h>
2018-07-12 16:41:02 +03:00
# include <drm/drm_gem_framebuffer_helper.h>
# include <drm/drm_fb_helper.h>
2018-05-14 17:33:46 +03:00
# include "vkms_drv.h"
# define DRIVER_NAME "vkms"
# define DRIVER_DESC "Virtual Kernel Mode Setting"
# define DRIVER_DATE "20180514"
# define DRIVER_MAJOR 1
# define DRIVER_MINOR 0
static struct vkms_device * vkms_device ;
2018-09-06 08:19:11 +03:00
bool enable_cursor ;
module_param_named ( enable_cursor , enable_cursor , bool , 0444 ) ;
MODULE_PARM_DESC ( enable_cursor , " Enable/Disable cursor support " ) ;
2018-05-14 17:33:46 +03:00
static const struct file_operations vkms_driver_fops = {
. owner = THIS_MODULE ,
. open = drm_open ,
. mmap = drm_gem_mmap ,
. unlocked_ioctl = drm_ioctl ,
. compat_ioctl = drm_compat_ioctl ,
. poll = drm_poll ,
. read = drm_read ,
. llseek = no_llseek ,
. release = drm_release ,
} ;
2018-07-12 05:01:47 +03:00
static const struct vm_operations_struct vkms_gem_vm_ops = {
. fault = vkms_gem_fault ,
. open = drm_gem_vm_open ,
. close = drm_gem_vm_close ,
} ;
2018-05-14 17:33:46 +03:00
static void vkms_release ( struct drm_device * dev )
{
struct vkms_device * vkms = container_of ( dev , struct vkms_device , drm ) ;
platform_device_unregister ( vkms - > platform ) ;
2018-07-19 03:40:45 +03:00
drm_atomic_helper_shutdown ( & vkms - > drm ) ;
2018-05-14 17:33:46 +03:00
drm_mode_config_cleanup ( & vkms - > drm ) ;
drm_dev_fini ( & vkms - > drm ) ;
2018-08-02 04:10:26 +03:00
destroy_workqueue ( vkms - > output . crc_workq ) ;
2018-05-14 17:33:46 +03:00
}
2018-05-15 14:30:52 +03:00
static struct drm_driver vkms_driver = {
2018-05-14 17:33:46 +03:00
. driver_features = DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_GEM ,
. release = vkms_release ,
. fops = & vkms_driver_fops ,
2018-07-12 05:01:47 +03:00
. dumb_create = vkms_dumb_create ,
. gem_vm_ops = & vkms_gem_vm_ops ,
. gem_free_object_unlocked = vkms_gem_free_object ,
2018-07-12 05:02:26 +03:00
. get_vblank_timestamp = vkms_get_vblank_timestamp ,
2018-05-14 17:33:46 +03:00
. name = DRIVER_NAME ,
. desc = DRIVER_DESC ,
. date = DRIVER_DATE ,
. major = DRIVER_MAJOR ,
. minor = DRIVER_MINOR ,
} ;
2018-05-17 02:56:21 +03:00
static const struct drm_mode_config_funcs vkms_mode_funcs = {
2018-07-12 16:41:02 +03:00
. fb_create = drm_gem_fb_create ,
2018-05-17 02:56:21 +03:00
. atomic_check = drm_atomic_helper_check ,
. atomic_commit = drm_atomic_helper_commit ,
2018-05-14 17:33:46 +03:00
} ;
2018-05-17 02:56:21 +03:00
static int vkms_modeset_init ( struct vkms_device * vkmsdev )
2018-05-14 17:33:46 +03:00
{
2018-05-17 02:56:21 +03:00
struct drm_device * dev = & vkmsdev - > drm ;
2018-05-14 17:33:46 +03:00
2018-05-17 02:56:21 +03:00
drm_mode_config_init ( dev ) ;
dev - > mode_config . funcs = & vkms_mode_funcs ;
dev - > mode_config . min_width = XRES_MIN ;
dev - > mode_config . min_height = YRES_MIN ;
dev - > mode_config . max_width = XRES_MAX ;
dev - > mode_config . max_height = YRES_MAX ;
2018-05-14 17:33:46 +03:00
2018-05-17 02:56:21 +03:00
return vkms_output_init ( vkmsdev ) ;
}
2018-05-17 02:55:36 +03:00
2018-05-14 17:33:46 +03:00
static int __init vkms_init ( void )
{
int ret ;
vkms_device = kzalloc ( sizeof ( * vkms_device ) , GFP_KERNEL ) ;
if ( ! vkms_device )
return - ENOMEM ;
vkms_device - > platform =
platform_device_register_simple ( DRIVER_NAME , - 1 , NULL , 0 ) ;
if ( IS_ERR ( vkms_device - > platform ) ) {
ret = PTR_ERR ( vkms_device - > platform ) ;
2018-10-26 13:05:50 +03:00
goto out_free ;
2018-05-14 17:33:46 +03:00
}
2018-10-26 13:05:50 +03:00
ret = drm_dev_init ( & vkms_device - > drm , & vkms_driver ,
& vkms_device - > platform - > dev ) ;
if ( ret )
goto out_unregister ;
2018-07-12 05:02:26 +03:00
vkms_device - > drm . irq_enabled = true ;
ret = drm_vblank_init ( & vkms_device - > drm , 1 ) ;
if ( ret ) {
DRM_ERROR ( " Failed to vblank \n " ) ;
goto out_fini ;
}
2018-05-17 02:56:21 +03:00
ret = vkms_modeset_init ( vkms_device ) ;
if ( ret )
2018-10-26 13:05:50 +03:00
goto out_fini ;
2018-05-14 17:33:46 +03:00
ret = drm_dev_register ( & vkms_device - > drm , 0 ) ;
if ( ret )
2018-10-26 13:05:50 +03:00
goto out_fini ;
2018-05-14 17:33:46 +03:00
return 0 ;
out_fini :
drm_dev_fini ( & vkms_device - > drm ) ;
2018-05-17 02:56:21 +03:00
2018-10-26 13:05:50 +03:00
out_unregister :
platform_device_unregister ( vkms_device - > platform ) ;
2018-05-14 17:33:46 +03:00
out_free :
kfree ( vkms_device ) ;
return ret ;
}
static void __exit vkms_exit ( void )
{
if ( ! vkms_device ) {
DRM_INFO ( " vkms_device is NULL. \n " ) ;
return ;
}
drm_dev_unregister ( & vkms_device - > drm ) ;
drm_dev_put ( & vkms_device - > drm ) ;
kfree ( vkms_device ) ;
}
module_init ( vkms_init ) ;
module_exit ( vkms_exit ) ;
2018-05-17 02:56:40 +03:00
MODULE_AUTHOR ( " Haneen Mohammed <hamohammed.sa@gmail.com> " ) ;
MODULE_AUTHOR ( " Rodrigo Siqueira <rodrigosiqueiramelo@gmail.com> " ) ;
2018-05-14 17:33:46 +03:00
MODULE_DESCRIPTION ( DRIVER_DESC ) ;
MODULE_LICENSE ( " GPL " ) ;