linux/drivers/gpu/drm/bochs/bochs_drv.c
<<
>>
Prefs
   1/*
   2 * This program is free software; you can redistribute it and/or modify
   3 * it under the terms of the GNU General Public License as published by
   4 * the Free Software Foundation; either version 2 of the License, or
   5 * (at your option) any later version.
   6 */
   7
   8#include <linux/mm.h>
   9#include <linux/module.h>
  10#include <linux/slab.h>
  11
  12#include "bochs.h"
  13
  14static bool enable_fbdev = true;
  15module_param_named(fbdev, enable_fbdev, bool, 0444);
  16MODULE_PARM_DESC(fbdev, "register fbdev device");
  17
  18/* ---------------------------------------------------------------------- */
  19/* drm interface                                                          */
  20
  21static int bochs_unload(struct drm_device *dev)
  22{
  23        struct bochs_device *bochs = dev->dev_private;
  24
  25        bochs_fbdev_fini(bochs);
  26        bochs_kms_fini(bochs);
  27        bochs_mm_fini(bochs);
  28        bochs_hw_fini(dev);
  29        kfree(bochs);
  30        dev->dev_private = NULL;
  31        return 0;
  32}
  33
  34static int bochs_load(struct drm_device *dev, unsigned long flags)
  35{
  36        struct bochs_device *bochs;
  37        int ret;
  38
  39        bochs = kzalloc(sizeof(*bochs), GFP_KERNEL);
  40        if (bochs == NULL)
  41                return -ENOMEM;
  42        dev->dev_private = bochs;
  43        bochs->dev = dev;
  44
  45        ret = bochs_hw_init(dev, flags);
  46        if (ret)
  47                goto err;
  48
  49        ret = bochs_mm_init(bochs);
  50        if (ret)
  51                goto err;
  52
  53        ret = bochs_kms_init(bochs);
  54        if (ret)
  55                goto err;
  56
  57        if (enable_fbdev)
  58                bochs_fbdev_init(bochs);
  59
  60        return 0;
  61
  62err:
  63        bochs_unload(dev);
  64        return ret;
  65}
  66
  67static const struct file_operations bochs_fops = {
  68        .owner          = THIS_MODULE,
  69        .open           = drm_open,
  70        .release        = drm_release,
  71        .unlocked_ioctl = drm_ioctl,
  72#ifdef CONFIG_COMPAT
  73        .compat_ioctl   = drm_compat_ioctl,
  74#endif
  75        .poll           = drm_poll,
  76        .read           = drm_read,
  77        .llseek         = no_llseek,
  78        .mmap           = bochs_mmap,
  79};
  80
  81static struct drm_driver bochs_driver = {
  82        .driver_features        = DRIVER_GEM | DRIVER_MODESET,
  83        .load                   = bochs_load,
  84        .unload                 = bochs_unload,
  85        .set_busid              = drm_pci_set_busid,
  86        .fops                   = &bochs_fops,
  87        .name                   = "bochs-drm",
  88        .desc                   = "bochs dispi vga interface (qemu stdvga)",
  89        .date                   = "20130925",
  90        .major                  = 1,
  91        .minor                  = 0,
  92        .gem_free_object        = bochs_gem_free_object,
  93        .dumb_create            = bochs_dumb_create,
  94        .dumb_map_offset        = bochs_dumb_mmap_offset,
  95        .dumb_destroy           = drm_gem_dumb_destroy,
  96};
  97
  98/* ---------------------------------------------------------------------- */
  99/* pm interface                                                           */
 100
 101#ifdef CONFIG_PM_SLEEP
 102static int bochs_pm_suspend(struct device *dev)
 103{
 104        struct pci_dev *pdev = to_pci_dev(dev);
 105        struct drm_device *drm_dev = pci_get_drvdata(pdev);
 106        struct bochs_device *bochs = drm_dev->dev_private;
 107
 108        drm_kms_helper_poll_disable(drm_dev);
 109
 110        if (bochs->fb.initialized) {
 111                console_lock();
 112                drm_fb_helper_set_suspend(&bochs->fb.helper, 1);
 113                console_unlock();
 114        }
 115
 116        return 0;
 117}
 118
 119static int bochs_pm_resume(struct device *dev)
 120{
 121        struct pci_dev *pdev = to_pci_dev(dev);
 122        struct drm_device *drm_dev = pci_get_drvdata(pdev);
 123        struct bochs_device *bochs = drm_dev->dev_private;
 124
 125        drm_helper_resume_force_mode(drm_dev);
 126
 127        if (bochs->fb.initialized) {
 128                console_lock();
 129                drm_fb_helper_set_suspend(&bochs->fb.helper, 0);
 130                console_unlock();
 131        }
 132
 133        drm_kms_helper_poll_enable(drm_dev);
 134        return 0;
 135}
 136#endif
 137
 138static const struct dev_pm_ops bochs_pm_ops = {
 139        SET_SYSTEM_SLEEP_PM_OPS(bochs_pm_suspend,
 140                                bochs_pm_resume)
 141};
 142
 143/* ---------------------------------------------------------------------- */
 144/* pci interface                                                          */
 145
 146static int bochs_kick_out_firmware_fb(struct pci_dev *pdev)
 147{
 148        struct apertures_struct *ap;
 149
 150        ap = alloc_apertures(1);
 151        if (!ap)
 152                return -ENOMEM;
 153
 154        ap->ranges[0].base = pci_resource_start(pdev, 0);
 155        ap->ranges[0].size = pci_resource_len(pdev, 0);
 156        remove_conflicting_framebuffers(ap, "bochsdrmfb", false);
 157        kfree(ap);
 158
 159        return 0;
 160}
 161
 162static int bochs_pci_probe(struct pci_dev *pdev,
 163                           const struct pci_device_id *ent)
 164{
 165        int ret;
 166
 167        ret = bochs_kick_out_firmware_fb(pdev);
 168        if (ret)
 169                return ret;
 170
 171        return drm_get_pci_dev(pdev, ent, &bochs_driver);
 172}
 173
 174static void bochs_pci_remove(struct pci_dev *pdev)
 175{
 176        struct drm_device *dev = pci_get_drvdata(pdev);
 177
 178        drm_put_dev(dev);
 179}
 180
 181static const struct pci_device_id bochs_pci_tbl[] = {
 182        {
 183                .vendor      = 0x1234,
 184                .device      = 0x1111,
 185                .subvendor   = PCI_SUBVENDOR_ID_REDHAT_QUMRANET,
 186                .subdevice   = PCI_SUBDEVICE_ID_QEMU,
 187                .driver_data = BOCHS_QEMU_STDVGA,
 188        },
 189        {
 190                .vendor      = 0x1234,
 191                .device      = 0x1111,
 192                .subvendor   = PCI_ANY_ID,
 193                .subdevice   = PCI_ANY_ID,
 194                .driver_data = BOCHS_UNKNOWN,
 195        },
 196        { /* end of list */ }
 197};
 198
 199static struct pci_driver bochs_pci_driver = {
 200        .name =         "bochs-drm",
 201        .id_table =     bochs_pci_tbl,
 202        .probe =        bochs_pci_probe,
 203        .remove =       bochs_pci_remove,
 204        .driver.pm =    &bochs_pm_ops,
 205};
 206
 207/* ---------------------------------------------------------------------- */
 208/* module init/exit                                                       */
 209
 210static int __init bochs_init(void)
 211{
 212        return drm_pci_init(&bochs_driver, &bochs_pci_driver);
 213}
 214
 215static void __exit bochs_exit(void)
 216{
 217        drm_pci_exit(&bochs_driver, &bochs_pci_driver);
 218}
 219
 220module_init(bochs_init);
 221module_exit(bochs_exit);
 222
 223MODULE_DEVICE_TABLE(pci, bochs_pci_tbl);
 224MODULE_AUTHOR("Gerd Hoffmann <kraxel@redhat.com>");
 225MODULE_LICENSE("GPL");
 226