linux/drivers/gpu/drm/bochs/bochs_drv.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 */
   4
   5#include <linux/module.h>
   6#include <linux/pci.h>
   7
   8#include <drm/drm_drv.h>
   9#include <drm/drm_aperture.h>
  10#include <drm/drm_atomic_helper.h>
  11#include <drm/drm_managed.h>
  12
  13#include "bochs.h"
  14
  15static int bochs_modeset = -1;
  16module_param_named(modeset, bochs_modeset, int, 0444);
  17MODULE_PARM_DESC(modeset, "enable/disable kernel modesetting");
  18
  19/* ---------------------------------------------------------------------- */
  20/* drm interface                                                          */
  21
  22static void bochs_unload(struct drm_device *dev)
  23{
  24        struct bochs_device *bochs = dev->dev_private;
  25
  26        bochs_mm_fini(bochs);
  27}
  28
  29static int bochs_load(struct drm_device *dev)
  30{
  31        struct bochs_device *bochs;
  32        int ret;
  33
  34        bochs = drmm_kzalloc(dev, sizeof(*bochs), GFP_KERNEL);
  35        if (bochs == NULL)
  36                return -ENOMEM;
  37        dev->dev_private = bochs;
  38        bochs->dev = dev;
  39
  40        ret = bochs_hw_init(dev);
  41        if (ret)
  42                goto err;
  43
  44        ret = bochs_mm_init(bochs);
  45        if (ret)
  46                goto err;
  47
  48        ret = bochs_kms_init(bochs);
  49        if (ret)
  50                goto err;
  51
  52        return 0;
  53
  54err:
  55        bochs_unload(dev);
  56        return ret;
  57}
  58
  59DEFINE_DRM_GEM_FOPS(bochs_fops);
  60
  61static const struct drm_driver bochs_driver = {
  62        .driver_features        = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
  63        .fops                   = &bochs_fops,
  64        .name                   = "bochs-drm",
  65        .desc                   = "bochs dispi vga interface (qemu stdvga)",
  66        .date                   = "20130925",
  67        .major                  = 1,
  68        .minor                  = 0,
  69        DRM_GEM_VRAM_DRIVER,
  70        .release                = bochs_unload,
  71};
  72
  73/* ---------------------------------------------------------------------- */
  74/* pm interface                                                           */
  75
  76#ifdef CONFIG_PM_SLEEP
  77static int bochs_pm_suspend(struct device *dev)
  78{
  79        struct drm_device *drm_dev = dev_get_drvdata(dev);
  80
  81        return drm_mode_config_helper_suspend(drm_dev);
  82}
  83
  84static int bochs_pm_resume(struct device *dev)
  85{
  86        struct drm_device *drm_dev = dev_get_drvdata(dev);
  87
  88        return drm_mode_config_helper_resume(drm_dev);
  89}
  90#endif
  91
  92static const struct dev_pm_ops bochs_pm_ops = {
  93        SET_SYSTEM_SLEEP_PM_OPS(bochs_pm_suspend,
  94                                bochs_pm_resume)
  95};
  96
  97/* ---------------------------------------------------------------------- */
  98/* pci interface                                                          */
  99
 100static int bochs_pci_probe(struct pci_dev *pdev,
 101                           const struct pci_device_id *ent)
 102{
 103        struct drm_device *dev;
 104        unsigned long fbsize;
 105        int ret;
 106
 107        fbsize = pci_resource_len(pdev, 0);
 108        if (fbsize < 4 * 1024 * 1024) {
 109                DRM_ERROR("less than 4 MB video memory, ignoring device\n");
 110                return -ENOMEM;
 111        }
 112
 113        ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, "bochsdrmfb");
 114        if (ret)
 115                return ret;
 116
 117        dev = drm_dev_alloc(&bochs_driver, &pdev->dev);
 118        if (IS_ERR(dev))
 119                return PTR_ERR(dev);
 120
 121        ret = pci_enable_device(pdev);
 122        if (ret)
 123                goto err_free_dev;
 124
 125        pci_set_drvdata(pdev, dev);
 126
 127        ret = bochs_load(dev);
 128        if (ret)
 129                goto err_free_dev;
 130
 131        ret = drm_dev_register(dev, 0);
 132        if (ret)
 133                goto err_unload;
 134
 135        drm_fbdev_generic_setup(dev, 32);
 136        return ret;
 137
 138err_unload:
 139        bochs_unload(dev);
 140err_free_dev:
 141        drm_dev_put(dev);
 142        return ret;
 143}
 144
 145static void bochs_pci_remove(struct pci_dev *pdev)
 146{
 147        struct drm_device *dev = pci_get_drvdata(pdev);
 148
 149        drm_dev_unplug(dev);
 150        drm_atomic_helper_shutdown(dev);
 151        bochs_hw_fini(dev);
 152        drm_dev_put(dev);
 153}
 154
 155static const struct pci_device_id bochs_pci_tbl[] = {
 156        {
 157                .vendor      = 0x1234,
 158                .device      = 0x1111,
 159                .subvendor   = PCI_SUBVENDOR_ID_REDHAT_QUMRANET,
 160                .subdevice   = PCI_SUBDEVICE_ID_QEMU,
 161                .driver_data = BOCHS_QEMU_STDVGA,
 162        },
 163        {
 164                .vendor      = 0x1234,
 165                .device      = 0x1111,
 166                .subvendor   = PCI_ANY_ID,
 167                .subdevice   = PCI_ANY_ID,
 168                .driver_data = BOCHS_UNKNOWN,
 169        },
 170        { /* end of list */ }
 171};
 172
 173static struct pci_driver bochs_pci_driver = {
 174        .name =         "bochs-drm",
 175        .id_table =     bochs_pci_tbl,
 176        .probe =        bochs_pci_probe,
 177        .remove =       bochs_pci_remove,
 178        .driver.pm =    &bochs_pm_ops,
 179};
 180
 181/* ---------------------------------------------------------------------- */
 182/* module init/exit                                                       */
 183
 184static int __init bochs_init(void)
 185{
 186        if (vgacon_text_force() && bochs_modeset == -1)
 187                return -EINVAL;
 188
 189        if (bochs_modeset == 0)
 190                return -EINVAL;
 191
 192        return pci_register_driver(&bochs_pci_driver);
 193}
 194
 195static void __exit bochs_exit(void)
 196{
 197        pci_unregister_driver(&bochs_pci_driver);
 198}
 199
 200module_init(bochs_init);
 201module_exit(bochs_exit);
 202
 203MODULE_DEVICE_TABLE(pci, bochs_pci_tbl);
 204MODULE_AUTHOR("Gerd Hoffmann <kraxel@redhat.com>");
 205MODULE_LICENSE("GPL");
 206