| .. | .. |
|---|
| 28 | 28 | * Alon Levy <alevy@redhat.com> |
|---|
| 29 | 29 | */ |
|---|
| 30 | 30 | |
|---|
| 31 | | -#include <linux/module.h> |
|---|
| 32 | | -#include <linux/console.h> |
|---|
| 33 | | - |
|---|
| 34 | | -#include <drm/drmP.h> |
|---|
| 35 | | -#include <drm/drm.h> |
|---|
| 36 | | -#include <drm/drm_crtc_helper.h> |
|---|
| 37 | 31 | #include "qxl_drv.h" |
|---|
| 32 | +#include <linux/console.h> |
|---|
| 33 | +#include <linux/module.h> |
|---|
| 34 | +#include <linux/pci.h> |
|---|
| 35 | + |
|---|
| 36 | +#include <drm/drm.h> |
|---|
| 37 | +#include <drm/drm_atomic_helper.h> |
|---|
| 38 | +#include <drm/drm_drv.h> |
|---|
| 39 | +#include <drm/drm_file.h> |
|---|
| 40 | +#include <drm/drm_modeset_helper.h> |
|---|
| 41 | +#include <drm/drm_prime.h> |
|---|
| 42 | +#include <drm/drm_probe_helper.h> |
|---|
| 43 | + |
|---|
| 38 | 44 | #include "qxl_object.h" |
|---|
| 39 | 45 | |
|---|
| 40 | 46 | static const struct pci_device_id pciidlist[] = { |
|---|
| .. | .. |
|---|
| 58 | 64 | static struct drm_driver qxl_driver; |
|---|
| 59 | 65 | static struct pci_driver qxl_pci_driver; |
|---|
| 60 | 66 | |
|---|
| 67 | +static bool is_vga(struct pci_dev *pdev) |
|---|
| 68 | +{ |
|---|
| 69 | + return pdev->class == PCI_CLASS_DISPLAY_VGA << 8; |
|---|
| 70 | +} |
|---|
| 71 | + |
|---|
| 61 | 72 | static int |
|---|
| 62 | 73 | qxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) |
|---|
| 63 | 74 | { |
|---|
| .. | .. |
|---|
| 70 | 81 | return -EINVAL; /* TODO: ENODEV ? */ |
|---|
| 71 | 82 | } |
|---|
| 72 | 83 | |
|---|
| 73 | | - qdev = kzalloc(sizeof(struct qxl_device), GFP_KERNEL); |
|---|
| 74 | | - if (!qdev) |
|---|
| 84 | + qdev = devm_drm_dev_alloc(&pdev->dev, &qxl_driver, |
|---|
| 85 | + struct qxl_device, ddev); |
|---|
| 86 | + if (IS_ERR(qdev)) { |
|---|
| 87 | + pr_err("Unable to init drm dev"); |
|---|
| 75 | 88 | return -ENOMEM; |
|---|
| 89 | + } |
|---|
| 76 | 90 | |
|---|
| 77 | 91 | ret = pci_enable_device(pdev); |
|---|
| 78 | 92 | if (ret) |
|---|
| 79 | | - goto free_dev; |
|---|
| 93 | + return ret; |
|---|
| 80 | 94 | |
|---|
| 81 | | - ret = qxl_device_init(qdev, &qxl_driver, pdev); |
|---|
| 95 | + ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "qxl"); |
|---|
| 82 | 96 | if (ret) |
|---|
| 83 | 97 | goto disable_pci; |
|---|
| 98 | + |
|---|
| 99 | + if (is_vga(pdev) && pdev->revision < 5) { |
|---|
| 100 | + ret = vga_get_interruptible(pdev, VGA_RSRC_LEGACY_IO); |
|---|
| 101 | + if (ret) { |
|---|
| 102 | + DRM_ERROR("can't get legacy vga ioports\n"); |
|---|
| 103 | + goto disable_pci; |
|---|
| 104 | + } |
|---|
| 105 | + } |
|---|
| 106 | + |
|---|
| 107 | + ret = qxl_device_init(qdev, pdev); |
|---|
| 108 | + if (ret) |
|---|
| 109 | + goto put_vga; |
|---|
| 84 | 110 | |
|---|
| 85 | 111 | ret = qxl_modeset_init(qdev); |
|---|
| 86 | 112 | if (ret) |
|---|
| .. | .. |
|---|
| 93 | 119 | if (ret) |
|---|
| 94 | 120 | goto modeset_cleanup; |
|---|
| 95 | 121 | |
|---|
| 122 | + drm_fbdev_generic_setup(&qdev->ddev, 32); |
|---|
| 96 | 123 | return 0; |
|---|
| 97 | 124 | |
|---|
| 98 | 125 | modeset_cleanup: |
|---|
| 99 | 126 | qxl_modeset_fini(qdev); |
|---|
| 100 | 127 | unload: |
|---|
| 101 | 128 | qxl_device_fini(qdev); |
|---|
| 129 | +put_vga: |
|---|
| 130 | + if (is_vga(pdev) && pdev->revision < 5) |
|---|
| 131 | + vga_put(pdev, VGA_RSRC_LEGACY_IO); |
|---|
| 102 | 132 | disable_pci: |
|---|
| 103 | 133 | pci_disable_device(pdev); |
|---|
| 104 | | -free_dev: |
|---|
| 105 | | - kfree(qdev); |
|---|
| 134 | + |
|---|
| 106 | 135 | return ret; |
|---|
| 136 | +} |
|---|
| 137 | + |
|---|
| 138 | +static void qxl_drm_release(struct drm_device *dev) |
|---|
| 139 | +{ |
|---|
| 140 | + struct qxl_device *qdev = to_qxl(dev); |
|---|
| 141 | + |
|---|
| 142 | + /* |
|---|
| 143 | + * TODO: qxl_device_fini() call should be in qxl_pci_remove(), |
|---|
| 144 | + * reodering qxl_modeset_fini() + qxl_device_fini() calls is |
|---|
| 145 | + * non-trivial though. |
|---|
| 146 | + */ |
|---|
| 147 | + qxl_modeset_fini(qdev); |
|---|
| 148 | + qxl_device_fini(qdev); |
|---|
| 107 | 149 | } |
|---|
| 108 | 150 | |
|---|
| 109 | 151 | static void |
|---|
| 110 | 152 | qxl_pci_remove(struct pci_dev *pdev) |
|---|
| 111 | 153 | { |
|---|
| 112 | 154 | struct drm_device *dev = pci_get_drvdata(pdev); |
|---|
| 113 | | - struct qxl_device *qdev = dev->dev_private; |
|---|
| 114 | 155 | |
|---|
| 115 | 156 | drm_dev_unregister(dev); |
|---|
| 116 | | - |
|---|
| 117 | | - qxl_modeset_fini(qdev); |
|---|
| 118 | | - qxl_device_fini(qdev); |
|---|
| 119 | | - |
|---|
| 120 | | - dev->dev_private = NULL; |
|---|
| 121 | | - kfree(qdev); |
|---|
| 122 | | - drm_dev_unref(dev); |
|---|
| 157 | + drm_atomic_helper_shutdown(dev); |
|---|
| 158 | + if (is_vga(pdev) && pdev->revision < 5) |
|---|
| 159 | + vga_put(pdev, VGA_RSRC_LEGACY_IO); |
|---|
| 123 | 160 | } |
|---|
| 124 | 161 | |
|---|
| 125 | | -static const struct file_operations qxl_fops = { |
|---|
| 126 | | - .owner = THIS_MODULE, |
|---|
| 127 | | - .open = drm_open, |
|---|
| 128 | | - .release = drm_release, |
|---|
| 129 | | - .unlocked_ioctl = drm_ioctl, |
|---|
| 130 | | - .poll = drm_poll, |
|---|
| 131 | | - .read = drm_read, |
|---|
| 132 | | - .mmap = qxl_mmap, |
|---|
| 133 | | -}; |
|---|
| 162 | +DEFINE_DRM_GEM_FOPS(qxl_fops); |
|---|
| 134 | 163 | |
|---|
| 135 | 164 | static int qxl_drm_freeze(struct drm_device *dev) |
|---|
| 136 | 165 | { |
|---|
| 137 | 166 | struct pci_dev *pdev = dev->pdev; |
|---|
| 138 | | - struct qxl_device *qdev = dev->dev_private; |
|---|
| 167 | + struct qxl_device *qdev = to_qxl(dev); |
|---|
| 139 | 168 | int ret; |
|---|
| 140 | 169 | |
|---|
| 141 | 170 | ret = drm_mode_config_helper_suspend(dev); |
|---|
| .. | .. |
|---|
| 157 | 186 | |
|---|
| 158 | 187 | static int qxl_drm_resume(struct drm_device *dev, bool thaw) |
|---|
| 159 | 188 | { |
|---|
| 160 | | - struct qxl_device *qdev = dev->dev_private; |
|---|
| 189 | + struct qxl_device *qdev = to_qxl(dev); |
|---|
| 161 | 190 | |
|---|
| 162 | 191 | qdev->ram_header->int_mask = QXL_INTERRUPT_MASK; |
|---|
| 163 | 192 | if (!thaw) { |
|---|
| .. | .. |
|---|
| 200 | 229 | |
|---|
| 201 | 230 | static int qxl_pm_thaw(struct device *dev) |
|---|
| 202 | 231 | { |
|---|
| 203 | | - struct pci_dev *pdev = to_pci_dev(dev); |
|---|
| 204 | | - struct drm_device *drm_dev = pci_get_drvdata(pdev); |
|---|
| 232 | + struct drm_device *drm_dev = dev_get_drvdata(dev); |
|---|
| 205 | 233 | |
|---|
| 206 | 234 | return qxl_drm_resume(drm_dev, true); |
|---|
| 207 | 235 | } |
|---|
| 208 | 236 | |
|---|
| 209 | 237 | static int qxl_pm_freeze(struct device *dev) |
|---|
| 210 | 238 | { |
|---|
| 211 | | - struct pci_dev *pdev = to_pci_dev(dev); |
|---|
| 212 | | - struct drm_device *drm_dev = pci_get_drvdata(pdev); |
|---|
| 239 | + struct drm_device *drm_dev = dev_get_drvdata(dev); |
|---|
| 213 | 240 | |
|---|
| 214 | 241 | return qxl_drm_freeze(drm_dev); |
|---|
| 215 | 242 | } |
|---|
| .. | .. |
|---|
| 218 | 245 | { |
|---|
| 219 | 246 | struct pci_dev *pdev = to_pci_dev(dev); |
|---|
| 220 | 247 | struct drm_device *drm_dev = pci_get_drvdata(pdev); |
|---|
| 221 | | - struct qxl_device *qdev = drm_dev->dev_private; |
|---|
| 248 | + struct qxl_device *qdev = to_qxl(drm_dev); |
|---|
| 222 | 249 | |
|---|
| 223 | 250 | qxl_io_reset(qdev); |
|---|
| 224 | 251 | return qxl_drm_resume(drm_dev, false); |
|---|
| .. | .. |
|---|
| 241 | 268 | }; |
|---|
| 242 | 269 | |
|---|
| 243 | 270 | static struct drm_driver qxl_driver = { |
|---|
| 244 | | - .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | |
|---|
| 245 | | - DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | |
|---|
| 246 | | - DRIVER_ATOMIC, |
|---|
| 271 | + .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, |
|---|
| 247 | 272 | |
|---|
| 248 | 273 | .dumb_create = qxl_mode_dumb_create, |
|---|
| 249 | 274 | .dumb_map_offset = qxl_mode_dumb_mmap, |
|---|
| .. | .. |
|---|
| 252 | 277 | #endif |
|---|
| 253 | 278 | .prime_handle_to_fd = drm_gem_prime_handle_to_fd, |
|---|
| 254 | 279 | .prime_fd_to_handle = drm_gem_prime_fd_to_handle, |
|---|
| 255 | | - .gem_prime_export = drm_gem_prime_export, |
|---|
| 256 | | - .gem_prime_import = drm_gem_prime_import, |
|---|
| 257 | | - .gem_prime_pin = qxl_gem_prime_pin, |
|---|
| 258 | | - .gem_prime_unpin = qxl_gem_prime_unpin, |
|---|
| 259 | | - .gem_prime_get_sg_table = qxl_gem_prime_get_sg_table, |
|---|
| 260 | 280 | .gem_prime_import_sg_table = qxl_gem_prime_import_sg_table, |
|---|
| 261 | | - .gem_prime_vmap = qxl_gem_prime_vmap, |
|---|
| 262 | | - .gem_prime_vunmap = qxl_gem_prime_vunmap, |
|---|
| 263 | 281 | .gem_prime_mmap = qxl_gem_prime_mmap, |
|---|
| 264 | | - .gem_free_object_unlocked = qxl_gem_object_free, |
|---|
| 265 | | - .gem_open_object = qxl_gem_object_open, |
|---|
| 266 | | - .gem_close_object = qxl_gem_object_close, |
|---|
| 267 | 282 | .fops = &qxl_fops, |
|---|
| 268 | 283 | .ioctls = qxl_ioctls, |
|---|
| 269 | 284 | .irq_handler = qxl_irq_handler, |
|---|
| .. | .. |
|---|
| 273 | 288 | .major = 0, |
|---|
| 274 | 289 | .minor = 1, |
|---|
| 275 | 290 | .patchlevel = 0, |
|---|
| 291 | + |
|---|
| 292 | + .release = qxl_drm_release, |
|---|
| 276 | 293 | }; |
|---|
| 277 | 294 | |
|---|
| 278 | 295 | static int __init qxl_init(void) |
|---|