2018-10-18 17:03:32 +02:00
// SPDX-License-Identifier: MIT
2017-07-06 16:06:01 +02:00
/*
* Copyright ( C ) 2013 - 2017 Oracle Corporation
* This file is based on ast_drv . c
* Copyright 2012 Red Hat Inc .
* Authors : Dave Airlie < airlied @ redhat . com >
* Michael Thayer < michael . thayer @ oracle . com ,
* Hans de Goede < hdegoede @ redhat . com >
*/
# include <linux/console.h>
2019-01-26 13:25:23 +01:00
# include <linux/module.h>
# include <linux/pci.h>
2017-07-06 16:06:01 +02:00
# include <linux/vt_kern.h>
# include <drm/drm_crtc_helper.h>
2019-01-26 13:25:23 +01:00
# include <drm/drm_drv.h>
2019-10-11 15:48:06 +02:00
# include <drm/drm_fb_helper.h>
2019-01-26 13:25:23 +01:00
# include <drm/drm_file.h>
# include <drm/drm_ioctl.h>
2020-03-23 15:49:17 +01:00
# include <drm/drm_managed.h>
2017-07-06 16:06:01 +02:00
# include "vbox_drv.h"
2017-07-19 10:36:16 +01:00
static int vbox_modeset = - 1 ;
2017-07-06 16:06:01 +02:00
MODULE_PARM_DESC ( modeset , " Disable/Enable modesetting " ) ;
module_param_named ( modeset , vbox_modeset , int , 0400 ) ;
static struct drm_driver driver ;
static const struct pci_device_id pciidlist [ ] = {
2018-10-22 16:57:46 +02:00
{ PCI_DEVICE ( 0x80ee , 0xbeef ) } ,
{ }
2017-07-06 16:06:01 +02:00
} ;
MODULE_DEVICE_TABLE ( pci , pciidlist ) ;
static int vbox_pci_probe ( struct pci_dev * pdev , const struct pci_device_id * ent )
{
2018-09-18 19:44:30 +02:00
struct vbox_private * vbox ;
2018-06-03 23:24:45 -03:00
int ret = 0 ;
2018-09-18 19:44:29 +02:00
if ( ! vbox_check_supported ( VBE_DISPI_ID_HGSMI ) )
return - ENODEV ;
2020-03-25 15:43:10 +01:00
ret = drm_fb_helper_remove_conflicting_pci_framebuffers ( pdev , " vboxvideodrmfb " ) ;
if ( ret )
return ret ;
2020-04-15 09:39:38 +02:00
vbox = devm_drm_dev_alloc ( & pdev - > dev , & driver ,
struct vbox_private , ddev ) ;
if ( IS_ERR ( vbox ) )
return PTR_ERR ( vbox ) ;
2018-09-18 19:44:29 +02:00
2018-09-18 19:44:30 +02:00
vbox - > ddev . pdev = pdev ;
pci_set_drvdata ( pdev , vbox ) ;
2018-09-18 19:44:29 +02:00
mutex_init ( & vbox - > hw_mutex ) ;
2020-04-15 09:39:40 +02:00
ret = pcim_enable_device ( pdev ) ;
2018-09-18 19:44:30 +02:00
if ( ret )
2020-04-15 09:39:38 +02:00
return ret ;
2018-09-18 19:44:30 +02:00
2018-09-18 19:44:29 +02:00
ret = vbox_hw_init ( vbox ) ;
2018-06-03 23:24:45 -03:00
if ( ret )
2020-04-15 09:39:40 +02:00
return ret ;
2018-06-03 23:24:45 -03:00
2018-09-18 19:44:29 +02:00
ret = vbox_mm_init ( vbox ) ;
2018-06-03 23:24:45 -03:00
if ( ret )
2018-09-18 19:44:29 +02:00
goto err_hw_fini ;
2018-06-03 23:24:45 -03:00
2018-09-18 19:44:30 +02:00
ret = vbox_mode_init ( vbox ) ;
2018-09-18 19:44:29 +02:00
if ( ret )
goto err_mm_fini ;
ret = vbox_irq_init ( vbox ) ;
if ( ret )
goto err_mode_fini ;
2018-09-18 19:44:30 +02:00
ret = drm_dev_register ( & vbox - > ddev , 0 ) ;
2018-09-18 19:44:29 +02:00
if ( ret )
2019-10-11 15:48:06 +02:00
goto err_irq_fini ;
2018-09-18 19:44:29 +02:00
2020-04-08 10:26:40 +02:00
drm_fbdev_generic_setup ( & vbox - > ddev , 32 ) ;
2018-09-18 19:44:29 +02:00
return 0 ;
err_irq_fini :
vbox_irq_fini ( vbox ) ;
err_mode_fini :
2018-09-18 19:44:30 +02:00
vbox_mode_fini ( vbox ) ;
2018-09-18 19:44:29 +02:00
err_mm_fini :
vbox_mm_fini ( vbox ) ;
err_hw_fini :
vbox_hw_fini ( vbox ) ;
2018-06-03 23:24:45 -03:00
return ret ;
2017-07-06 16:06:01 +02:00
}
static void vbox_pci_remove ( struct pci_dev * pdev )
{
2018-09-18 19:44:30 +02:00
struct vbox_private * vbox = pci_get_drvdata ( pdev ) ;
2017-07-06 16:06:01 +02:00
2018-09-18 19:44:30 +02:00
drm_dev_unregister ( & vbox - > ddev ) ;
2018-09-18 19:44:29 +02:00
vbox_irq_fini ( vbox ) ;
2018-09-18 19:44:30 +02:00
vbox_mode_fini ( vbox ) ;
2018-09-18 19:44:29 +02:00
vbox_mm_fini ( vbox ) ;
vbox_hw_fini ( vbox ) ;
2017-07-06 16:06:01 +02:00
}
2018-10-22 16:57:47 +02:00
# ifdef CONFIG_PM_SLEEP
2017-07-06 16:06:01 +02:00
static int vbox_pm_suspend ( struct device * dev )
{
2018-09-18 19:44:30 +02:00
struct vbox_private * vbox = dev_get_drvdata ( dev ) ;
2017-07-06 16:06:01 +02:00
int error ;
2018-09-29 14:18:19 +02:00
error = drm_mode_config_helper_suspend ( & vbox - > ddev ) ;
2017-07-06 16:06:01 +02:00
if ( error )
return error ;
2018-09-29 14:18:19 +02:00
pci_save_state ( vbox - > ddev . pdev ) ;
2018-09-18 19:44:30 +02:00
pci_disable_device ( vbox - > ddev . pdev ) ;
pci_set_power_state ( vbox - > ddev . pdev , PCI_D3hot ) ;
2017-07-06 16:06:01 +02:00
return 0 ;
}
static int vbox_pm_resume ( struct device * dev )
{
2018-09-18 19:44:30 +02:00
struct vbox_private * vbox = dev_get_drvdata ( dev ) ;
2017-07-06 16:06:01 +02:00
2018-09-18 19:44:31 +02:00
if ( pci_enable_device ( vbox - > ddev . pdev ) )
return - EIO ;
2018-09-29 14:18:19 +02:00
return drm_mode_config_helper_resume ( & vbox - > ddev ) ;
2017-07-06 16:06:01 +02:00
}
static int vbox_pm_freeze ( struct device * dev )
{
2018-09-18 19:44:30 +02:00
struct vbox_private * vbox = dev_get_drvdata ( dev ) ;
2017-07-06 16:06:01 +02:00
2018-09-29 14:18:19 +02:00
return drm_mode_config_helper_suspend ( & vbox - > ddev ) ;
2017-07-06 16:06:01 +02:00
}
static int vbox_pm_thaw ( struct device * dev )
{
2018-09-18 19:44:30 +02:00
struct vbox_private * vbox = dev_get_drvdata ( dev ) ;
2017-07-06 16:06:01 +02:00
2018-09-29 14:18:19 +02:00
return drm_mode_config_helper_resume ( & vbox - > ddev ) ;
2017-07-06 16:06:01 +02:00
}
static int vbox_pm_poweroff ( struct device * dev )
{
2018-09-18 19:44:30 +02:00
struct vbox_private * vbox = dev_get_drvdata ( dev ) ;
2017-07-06 16:06:01 +02:00
2018-09-29 14:18:19 +02:00
return drm_mode_config_helper_suspend ( & vbox - > ddev ) ;
2017-07-06 16:06:01 +02:00
}
static const struct dev_pm_ops vbox_pm_ops = {
. suspend = vbox_pm_suspend ,
. resume = vbox_pm_resume ,
. freeze = vbox_pm_freeze ,
. thaw = vbox_pm_thaw ,
. poweroff = vbox_pm_poweroff ,
. restore = vbox_pm_resume ,
} ;
2018-10-22 16:57:47 +02:00
# endif
2017-07-06 16:06:01 +02:00
static struct pci_driver vbox_pci_driver = {
. name = DRIVER_NAME ,
. id_table = pciidlist ,
. probe = vbox_pci_probe ,
. remove = vbox_pci_remove ,
2018-10-22 16:57:47 +02:00
# ifdef CONFIG_PM_SLEEP
2017-07-06 16:06:01 +02:00
. driver . pm = & vbox_pm_ops ,
2018-10-22 16:57:47 +02:00
# endif
2017-07-06 16:06:01 +02:00
} ;
2019-10-16 13:52:03 +02:00
DEFINE_DRM_GEM_FOPS ( vbox_fops ) ;
2017-07-06 16:06:01 +02:00
static struct drm_driver driver = {
. driver_features =
2019-06-17 17:39:24 +02:00
DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC ,
2017-07-06 16:06:01 +02:00
2018-09-29 14:18:25 +02:00
. lastclose = drm_fb_helper_lastclose ,
2017-07-06 16:06:01 +02:00
. fops = & vbox_fops ,
. irq_handler = vbox_irq_handler ,
. name = DRIVER_NAME ,
. desc = DRIVER_DESC ,
. date = DRIVER_DATE ,
. major = DRIVER_MAJOR ,
. minor = DRIVER_MINOR ,
. patchlevel = DRIVER_PATCHLEVEL ,
2019-05-08 10:26:28 +02:00
DRM_GEM_VRAM_DRIVER ,
2017-07-06 16:06:01 +02:00
} ;
static int __init vbox_init ( void )
{
# ifdef CONFIG_VGA_CONSOLE
if ( vgacon_text_force ( ) & & vbox_modeset = = - 1 )
return - EINVAL ;
# endif
if ( vbox_modeset = = 0 )
return - EINVAL ;
2017-07-19 11:46:57 +10:00
return pci_register_driver ( & vbox_pci_driver ) ;
2017-07-06 16:06:01 +02:00
}
static void __exit vbox_exit ( void )
{
2017-07-19 11:46:57 +10:00
pci_unregister_driver ( & vbox_pci_driver ) ;
2017-07-06 16:06:01 +02:00
}
module_init ( vbox_init ) ;
module_exit ( vbox_exit ) ;
MODULE_AUTHOR ( " Oracle Corporation " ) ;
2018-10-22 16:57:48 +02:00
MODULE_AUTHOR ( " Hans de Goede <hdegoede@redhat.com> " ) ;
2017-07-06 16:06:01 +02:00
MODULE_DESCRIPTION ( DRIVER_DESC ) ;
MODULE_LICENSE ( " GPL and additional rights " ) ;