0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029 #include <linux/debugfs.h>
0030 #include <linux/fs.h>
0031 #include <linux/module.h>
0032 #include <linux/moduleparam.h>
0033 #include <linux/mount.h>
0034 #include <linux/pseudo_fs.h>
0035 #include <linux/slab.h>
0036 #include <linux/srcu.h>
0037
0038 #include <drm/drm_cache.h>
0039 #include <drm/drm_client.h>
0040 #include <drm/drm_color_mgmt.h>
0041 #include <drm/drm_drv.h>
0042 #include <drm/drm_file.h>
0043 #include <drm/drm_managed.h>
0044 #include <drm/drm_mode_object.h>
0045 #include <drm/drm_print.h>
0046 #include <drm/drm_privacy_screen_machine.h>
0047
0048 #include "drm_crtc_internal.h"
0049 #include "drm_internal.h"
0050 #include "drm_legacy.h"
0051
0052 MODULE_AUTHOR("Gareth Hughes, Leif Delgass, José Fonseca, Jon Smirl");
0053 MODULE_DESCRIPTION("DRM shared core routines");
0054 MODULE_LICENSE("GPL and additional rights");
0055
0056 static DEFINE_SPINLOCK(drm_minor_lock);
0057 static struct idr drm_minors_idr;
0058
0059
0060
0061
0062
0063
0064
0065
0066 static bool drm_core_init_complete;
0067
0068 static struct dentry *drm_debugfs_root;
0069
0070 DEFINE_STATIC_SRCU(drm_unplug_srcu);
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085 static struct drm_minor **drm_minor_get_slot(struct drm_device *dev,
0086 unsigned int type)
0087 {
0088 switch (type) {
0089 case DRM_MINOR_PRIMARY:
0090 return &dev->primary;
0091 case DRM_MINOR_RENDER:
0092 return &dev->render;
0093 default:
0094 BUG();
0095 }
0096 }
0097
0098 static void drm_minor_alloc_release(struct drm_device *dev, void *data)
0099 {
0100 struct drm_minor *minor = data;
0101 unsigned long flags;
0102
0103 WARN_ON(dev != minor->dev);
0104
0105 put_device(minor->kdev);
0106
0107 spin_lock_irqsave(&drm_minor_lock, flags);
0108 idr_remove(&drm_minors_idr, minor->index);
0109 spin_unlock_irqrestore(&drm_minor_lock, flags);
0110 }
0111
0112 static int drm_minor_alloc(struct drm_device *dev, unsigned int type)
0113 {
0114 struct drm_minor *minor;
0115 unsigned long flags;
0116 int r;
0117
0118 minor = drmm_kzalloc(dev, sizeof(*minor), GFP_KERNEL);
0119 if (!minor)
0120 return -ENOMEM;
0121
0122 minor->type = type;
0123 minor->dev = dev;
0124
0125 idr_preload(GFP_KERNEL);
0126 spin_lock_irqsave(&drm_minor_lock, flags);
0127 r = idr_alloc(&drm_minors_idr,
0128 NULL,
0129 64 * type,
0130 64 * (type + 1),
0131 GFP_NOWAIT);
0132 spin_unlock_irqrestore(&drm_minor_lock, flags);
0133 idr_preload_end();
0134
0135 if (r < 0)
0136 return r;
0137
0138 minor->index = r;
0139
0140 r = drmm_add_action_or_reset(dev, drm_minor_alloc_release, minor);
0141 if (r)
0142 return r;
0143
0144 minor->kdev = drm_sysfs_minor_alloc(minor);
0145 if (IS_ERR(minor->kdev))
0146 return PTR_ERR(minor->kdev);
0147
0148 *drm_minor_get_slot(dev, type) = minor;
0149 return 0;
0150 }
0151
0152 static int drm_minor_register(struct drm_device *dev, unsigned int type)
0153 {
0154 struct drm_minor *minor;
0155 unsigned long flags;
0156 int ret;
0157
0158 DRM_DEBUG("\n");
0159
0160 minor = *drm_minor_get_slot(dev, type);
0161 if (!minor)
0162 return 0;
0163
0164 ret = drm_debugfs_init(minor, minor->index, drm_debugfs_root);
0165 if (ret) {
0166 DRM_ERROR("DRM: Failed to initialize /sys/kernel/debug/dri.\n");
0167 goto err_debugfs;
0168 }
0169
0170 ret = device_add(minor->kdev);
0171 if (ret)
0172 goto err_debugfs;
0173
0174
0175 spin_lock_irqsave(&drm_minor_lock, flags);
0176 idr_replace(&drm_minors_idr, minor, minor->index);
0177 spin_unlock_irqrestore(&drm_minor_lock, flags);
0178
0179 DRM_DEBUG("new minor registered %d\n", minor->index);
0180 return 0;
0181
0182 err_debugfs:
0183 drm_debugfs_cleanup(minor);
0184 return ret;
0185 }
0186
0187 static void drm_minor_unregister(struct drm_device *dev, unsigned int type)
0188 {
0189 struct drm_minor *minor;
0190 unsigned long flags;
0191
0192 minor = *drm_minor_get_slot(dev, type);
0193 if (!minor || !device_is_registered(minor->kdev))
0194 return;
0195
0196
0197 spin_lock_irqsave(&drm_minor_lock, flags);
0198 idr_replace(&drm_minors_idr, NULL, minor->index);
0199 spin_unlock_irqrestore(&drm_minor_lock, flags);
0200
0201 device_del(minor->kdev);
0202 dev_set_drvdata(minor->kdev, NULL);
0203 drm_debugfs_cleanup(minor);
0204 }
0205
0206
0207
0208
0209
0210
0211
0212
0213
0214
0215 struct drm_minor *drm_minor_acquire(unsigned int minor_id)
0216 {
0217 struct drm_minor *minor;
0218 unsigned long flags;
0219
0220 spin_lock_irqsave(&drm_minor_lock, flags);
0221 minor = idr_find(&drm_minors_idr, minor_id);
0222 if (minor)
0223 drm_dev_get(minor->dev);
0224 spin_unlock_irqrestore(&drm_minor_lock, flags);
0225
0226 if (!minor) {
0227 return ERR_PTR(-ENODEV);
0228 } else if (drm_dev_is_unplugged(minor->dev)) {
0229 drm_dev_put(minor->dev);
0230 return ERR_PTR(-ENODEV);
0231 }
0232
0233 return minor;
0234 }
0235
0236 void drm_minor_release(struct drm_minor *minor)
0237 {
0238 drm_dev_put(minor->dev);
0239 }
0240
0241
0242
0243
0244
0245
0246
0247
0248
0249
0250
0251
0252
0253
0254
0255
0256
0257
0258
0259
0260
0261
0262
0263
0264
0265
0266
0267
0268
0269
0270
0271
0272
0273
0274
0275
0276
0277
0278
0279
0280
0281
0282
0283
0284
0285
0286
0287
0288
0289
0290
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300
0301
0302
0303
0304
0305
0306
0307
0308
0309
0310
0311
0312
0313
0314
0315
0316
0317
0318
0319
0320
0321
0322
0323
0324
0325
0326
0327
0328
0329
0330
0331
0332
0333
0334
0335
0336
0337
0338
0339
0340
0341
0342
0343
0344
0345
0346
0347
0348
0349
0350
0351
0352
0353
0354
0355
0356
0357
0358
0359
0360
0361
0362
0363
0364
0365
0366
0367
0368
0369
0370
0371
0372
0373
0374
0375
0376
0377
0378
0379
0380
0381
0382
0383
0384
0385
0386
0387
0388
0389
0390
0391
0392
0393
0394
0395
0396
0397
0398
0399
0400 void drm_put_dev(struct drm_device *dev)
0401 {
0402 DRM_DEBUG("\n");
0403
0404 if (!dev) {
0405 DRM_ERROR("cleanup called no dev\n");
0406 return;
0407 }
0408
0409 drm_dev_unregister(dev);
0410 drm_dev_put(dev);
0411 }
0412 EXPORT_SYMBOL(drm_put_dev);
0413
0414
0415
0416
0417
0418
0419
0420
0421
0422
0423
0424
0425
0426 bool drm_dev_enter(struct drm_device *dev, int *idx)
0427 {
0428 *idx = srcu_read_lock(&drm_unplug_srcu);
0429
0430 if (dev->unplugged) {
0431 srcu_read_unlock(&drm_unplug_srcu, *idx);
0432 return false;
0433 }
0434
0435 return true;
0436 }
0437 EXPORT_SYMBOL(drm_dev_enter);
0438
0439
0440
0441
0442
0443
0444
0445
0446 void drm_dev_exit(int idx)
0447 {
0448 srcu_read_unlock(&drm_unplug_srcu, idx);
0449 }
0450 EXPORT_SYMBOL(drm_dev_exit);
0451
0452
0453
0454
0455
0456
0457
0458
0459
0460
0461
0462 void drm_dev_unplug(struct drm_device *dev)
0463 {
0464
0465
0466
0467
0468
0469
0470 dev->unplugged = true;
0471 synchronize_srcu(&drm_unplug_srcu);
0472
0473 drm_dev_unregister(dev);
0474
0475
0476 unmap_mapping_range(dev->anon_inode->i_mapping, 0, 0, 1);
0477 }
0478 EXPORT_SYMBOL(drm_dev_unplug);
0479
0480
0481
0482
0483
0484
0485
0486
0487
0488
0489
0490
0491
0492
0493
0494
0495
0496
0497
0498 static int drm_fs_cnt;
0499 static struct vfsmount *drm_fs_mnt;
0500
0501 static int drm_fs_init_fs_context(struct fs_context *fc)
0502 {
0503 return init_pseudo(fc, 0x010203ff) ? 0 : -ENOMEM;
0504 }
0505
0506 static struct file_system_type drm_fs_type = {
0507 .name = "drm",
0508 .owner = THIS_MODULE,
0509 .init_fs_context = drm_fs_init_fs_context,
0510 .kill_sb = kill_anon_super,
0511 };
0512
0513 static struct inode *drm_fs_inode_new(void)
0514 {
0515 struct inode *inode;
0516 int r;
0517
0518 r = simple_pin_fs(&drm_fs_type, &drm_fs_mnt, &drm_fs_cnt);
0519 if (r < 0) {
0520 DRM_ERROR("Cannot mount pseudo fs: %d\n", r);
0521 return ERR_PTR(r);
0522 }
0523
0524 inode = alloc_anon_inode(drm_fs_mnt->mnt_sb);
0525 if (IS_ERR(inode))
0526 simple_release_fs(&drm_fs_mnt, &drm_fs_cnt);
0527
0528 return inode;
0529 }
0530
0531 static void drm_fs_inode_free(struct inode *inode)
0532 {
0533 if (inode) {
0534 iput(inode);
0535 simple_release_fs(&drm_fs_mnt, &drm_fs_cnt);
0536 }
0537 }
0538
0539
0540
0541
0542
0543
0544
0545
0546
0547
0548
0549
0550
0551
0552
0553
0554
0555
0556
0557
0558
0559
0560
0561
0562
0563
0564 static void drm_dev_init_release(struct drm_device *dev, void *res)
0565 {
0566 drm_legacy_ctxbitmap_cleanup(dev);
0567 drm_legacy_remove_map_hash(dev);
0568 drm_fs_inode_free(dev->anon_inode);
0569
0570 put_device(dev->dev);
0571
0572
0573 dev->dev = NULL;
0574 mutex_destroy(&dev->master_mutex);
0575 mutex_destroy(&dev->clientlist_mutex);
0576 mutex_destroy(&dev->filelist_mutex);
0577 mutex_destroy(&dev->struct_mutex);
0578 drm_legacy_destroy_members(dev);
0579 }
0580
0581 static int drm_dev_init(struct drm_device *dev,
0582 const struct drm_driver *driver,
0583 struct device *parent)
0584 {
0585 struct inode *inode;
0586 int ret;
0587
0588 if (!drm_core_init_complete) {
0589 DRM_ERROR("DRM core is not initialized\n");
0590 return -ENODEV;
0591 }
0592
0593 if (WARN_ON(!parent))
0594 return -EINVAL;
0595
0596 kref_init(&dev->ref);
0597 dev->dev = get_device(parent);
0598 dev->driver = driver;
0599
0600 INIT_LIST_HEAD(&dev->managed.resources);
0601 spin_lock_init(&dev->managed.lock);
0602
0603
0604 dev->driver_features = ~0u;
0605
0606 drm_legacy_init_members(dev);
0607 INIT_LIST_HEAD(&dev->filelist);
0608 INIT_LIST_HEAD(&dev->filelist_internal);
0609 INIT_LIST_HEAD(&dev->clientlist);
0610 INIT_LIST_HEAD(&dev->vblank_event_list);
0611
0612 spin_lock_init(&dev->event_lock);
0613 mutex_init(&dev->struct_mutex);
0614 mutex_init(&dev->filelist_mutex);
0615 mutex_init(&dev->clientlist_mutex);
0616 mutex_init(&dev->master_mutex);
0617
0618 ret = drmm_add_action(dev, drm_dev_init_release, NULL);
0619 if (ret)
0620 return ret;
0621
0622 inode = drm_fs_inode_new();
0623 if (IS_ERR(inode)) {
0624 ret = PTR_ERR(inode);
0625 DRM_ERROR("Cannot allocate anonymous inode: %d\n", ret);
0626 goto err;
0627 }
0628
0629 dev->anon_inode = inode;
0630
0631 if (drm_core_check_feature(dev, DRIVER_RENDER)) {
0632 ret = drm_minor_alloc(dev, DRM_MINOR_RENDER);
0633 if (ret)
0634 goto err;
0635 }
0636
0637 ret = drm_minor_alloc(dev, DRM_MINOR_PRIMARY);
0638 if (ret)
0639 goto err;
0640
0641 ret = drm_legacy_create_map_hash(dev);
0642 if (ret)
0643 goto err;
0644
0645 drm_legacy_ctxbitmap_init(dev);
0646
0647 if (drm_core_check_feature(dev, DRIVER_GEM)) {
0648 ret = drm_gem_init(dev);
0649 if (ret) {
0650 DRM_ERROR("Cannot initialize graphics execution manager (GEM)\n");
0651 goto err;
0652 }
0653 }
0654
0655 ret = drm_dev_set_unique(dev, dev_name(parent));
0656 if (ret)
0657 goto err;
0658
0659 return 0;
0660
0661 err:
0662 drm_managed_release(dev);
0663
0664 return ret;
0665 }
0666
0667 static void devm_drm_dev_init_release(void *data)
0668 {
0669 drm_dev_put(data);
0670 }
0671
0672 static int devm_drm_dev_init(struct device *parent,
0673 struct drm_device *dev,
0674 const struct drm_driver *driver)
0675 {
0676 int ret;
0677
0678 ret = drm_dev_init(dev, driver, parent);
0679 if (ret)
0680 return ret;
0681
0682 return devm_add_action_or_reset(parent,
0683 devm_drm_dev_init_release, dev);
0684 }
0685
0686 void *__devm_drm_dev_alloc(struct device *parent,
0687 const struct drm_driver *driver,
0688 size_t size, size_t offset)
0689 {
0690 void *container;
0691 struct drm_device *drm;
0692 int ret;
0693
0694 container = kzalloc(size, GFP_KERNEL);
0695 if (!container)
0696 return ERR_PTR(-ENOMEM);
0697
0698 drm = container + offset;
0699 ret = devm_drm_dev_init(parent, drm, driver);
0700 if (ret) {
0701 kfree(container);
0702 return ERR_PTR(ret);
0703 }
0704 drmm_add_final_kfree(drm, container);
0705
0706 return container;
0707 }
0708 EXPORT_SYMBOL(__devm_drm_dev_alloc);
0709
0710
0711
0712
0713
0714
0715
0716
0717
0718
0719
0720
0721
0722 struct drm_device *drm_dev_alloc(const struct drm_driver *driver,
0723 struct device *parent)
0724 {
0725 struct drm_device *dev;
0726 int ret;
0727
0728 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
0729 if (!dev)
0730 return ERR_PTR(-ENOMEM);
0731
0732 ret = drm_dev_init(dev, driver, parent);
0733 if (ret) {
0734 kfree(dev);
0735 return ERR_PTR(ret);
0736 }
0737
0738 drmm_add_final_kfree(dev, dev);
0739
0740 return dev;
0741 }
0742 EXPORT_SYMBOL(drm_dev_alloc);
0743
0744 static void drm_dev_release(struct kref *ref)
0745 {
0746 struct drm_device *dev = container_of(ref, struct drm_device, ref);
0747
0748 if (dev->driver->release)
0749 dev->driver->release(dev);
0750
0751 drm_managed_release(dev);
0752
0753 kfree(dev->managed.final_kfree);
0754 }
0755
0756
0757
0758
0759
0760
0761
0762
0763
0764
0765
0766
0767
0768 void drm_dev_get(struct drm_device *dev)
0769 {
0770 if (dev)
0771 kref_get(&dev->ref);
0772 }
0773 EXPORT_SYMBOL(drm_dev_get);
0774
0775
0776
0777
0778
0779
0780
0781
0782 void drm_dev_put(struct drm_device *dev)
0783 {
0784 if (dev)
0785 kref_put(&dev->ref, drm_dev_release);
0786 }
0787 EXPORT_SYMBOL(drm_dev_put);
0788
0789 static int create_compat_control_link(struct drm_device *dev)
0790 {
0791 struct drm_minor *minor;
0792 char *name;
0793 int ret;
0794
0795 if (!drm_core_check_feature(dev, DRIVER_MODESET))
0796 return 0;
0797
0798 minor = *drm_minor_get_slot(dev, DRM_MINOR_PRIMARY);
0799 if (!minor)
0800 return 0;
0801
0802
0803
0804
0805
0806
0807
0808
0809
0810
0811 name = kasprintf(GFP_KERNEL, "controlD%d", minor->index + 64);
0812 if (!name)
0813 return -ENOMEM;
0814
0815 ret = sysfs_create_link(minor->kdev->kobj.parent,
0816 &minor->kdev->kobj,
0817 name);
0818
0819 kfree(name);
0820
0821 return ret;
0822 }
0823
0824 static void remove_compat_control_link(struct drm_device *dev)
0825 {
0826 struct drm_minor *minor;
0827 char *name;
0828
0829 if (!drm_core_check_feature(dev, DRIVER_MODESET))
0830 return;
0831
0832 minor = *drm_minor_get_slot(dev, DRM_MINOR_PRIMARY);
0833 if (!minor)
0834 return;
0835
0836 name = kasprintf(GFP_KERNEL, "controlD%d", minor->index + 64);
0837 if (!name)
0838 return;
0839
0840 sysfs_remove_link(minor->kdev->kobj.parent, name);
0841
0842 kfree(name);
0843 }
0844
0845
0846
0847
0848
0849
0850
0851
0852
0853
0854
0855
0856
0857
0858
0859
0860
0861
0862
0863
0864
0865 int drm_dev_register(struct drm_device *dev, unsigned long flags)
0866 {
0867 const struct drm_driver *driver = dev->driver;
0868 int ret;
0869
0870 if (!driver->load)
0871 drm_mode_config_validate(dev);
0872
0873 WARN_ON(!dev->managed.final_kfree);
0874
0875 if (drm_dev_needs_global_mutex(dev))
0876 mutex_lock(&drm_global_mutex);
0877
0878 ret = drm_minor_register(dev, DRM_MINOR_RENDER);
0879 if (ret)
0880 goto err_minors;
0881
0882 ret = drm_minor_register(dev, DRM_MINOR_PRIMARY);
0883 if (ret)
0884 goto err_minors;
0885
0886 ret = create_compat_control_link(dev);
0887 if (ret)
0888 goto err_minors;
0889
0890 dev->registered = true;
0891
0892 if (dev->driver->load) {
0893 ret = dev->driver->load(dev, flags);
0894 if (ret)
0895 goto err_minors;
0896 }
0897
0898 if (drm_core_check_feature(dev, DRIVER_MODESET))
0899 drm_modeset_register_all(dev);
0900
0901 DRM_INFO("Initialized %s %d.%d.%d %s for %s on minor %d\n",
0902 driver->name, driver->major, driver->minor,
0903 driver->patchlevel, driver->date,
0904 dev->dev ? dev_name(dev->dev) : "virtual device",
0905 dev->primary->index);
0906
0907 goto out_unlock;
0908
0909 err_minors:
0910 remove_compat_control_link(dev);
0911 drm_minor_unregister(dev, DRM_MINOR_PRIMARY);
0912 drm_minor_unregister(dev, DRM_MINOR_RENDER);
0913 out_unlock:
0914 if (drm_dev_needs_global_mutex(dev))
0915 mutex_unlock(&drm_global_mutex);
0916 return ret;
0917 }
0918 EXPORT_SYMBOL(drm_dev_register);
0919
0920
0921
0922
0923
0924
0925
0926
0927
0928
0929
0930
0931
0932
0933
0934 void drm_dev_unregister(struct drm_device *dev)
0935 {
0936 if (drm_core_check_feature(dev, DRIVER_LEGACY))
0937 drm_lastclose(dev);
0938
0939 dev->registered = false;
0940
0941 drm_client_dev_unregister(dev);
0942
0943 if (drm_core_check_feature(dev, DRIVER_MODESET))
0944 drm_modeset_unregister_all(dev);
0945
0946 if (dev->driver->unload)
0947 dev->driver->unload(dev);
0948
0949 drm_legacy_pci_agp_destroy(dev);
0950 drm_legacy_rmmaps(dev);
0951
0952 remove_compat_control_link(dev);
0953 drm_minor_unregister(dev, DRM_MINOR_PRIMARY);
0954 drm_minor_unregister(dev, DRM_MINOR_RENDER);
0955 }
0956 EXPORT_SYMBOL(drm_dev_unregister);
0957
0958
0959
0960
0961
0962
0963
0964
0965
0966
0967
0968
0969 int drm_dev_set_unique(struct drm_device *dev, const char *name)
0970 {
0971 drmm_kfree(dev, dev->unique);
0972 dev->unique = drmm_kstrdup(dev, name, GFP_KERNEL);
0973
0974 return dev->unique ? 0 : -ENOMEM;
0975 }
0976 EXPORT_SYMBOL(drm_dev_set_unique);
0977
0978
0979
0980
0981
0982
0983
0984
0985
0986
0987
0988
0989
0990
0991
0992
0993
0994
0995
0996
0997
0998 static int drm_stub_open(struct inode *inode, struct file *filp)
0999 {
1000 const struct file_operations *new_fops;
1001 struct drm_minor *minor;
1002 int err;
1003
1004 DRM_DEBUG("\n");
1005
1006 minor = drm_minor_acquire(iminor(inode));
1007 if (IS_ERR(minor))
1008 return PTR_ERR(minor);
1009
1010 new_fops = fops_get(minor->dev->driver->fops);
1011 if (!new_fops) {
1012 err = -ENODEV;
1013 goto out;
1014 }
1015
1016 replace_fops(filp, new_fops);
1017 if (filp->f_op->open)
1018 err = filp->f_op->open(inode, filp);
1019 else
1020 err = 0;
1021
1022 out:
1023 drm_minor_release(minor);
1024
1025 return err;
1026 }
1027
1028 static const struct file_operations drm_stub_fops = {
1029 .owner = THIS_MODULE,
1030 .open = drm_stub_open,
1031 .llseek = noop_llseek,
1032 };
1033
1034 static void drm_core_exit(void)
1035 {
1036 drm_privacy_screen_lookup_exit();
1037 unregister_chrdev(DRM_MAJOR, "drm");
1038 debugfs_remove(drm_debugfs_root);
1039 drm_sysfs_destroy();
1040 idr_destroy(&drm_minors_idr);
1041 drm_connector_ida_destroy();
1042 }
1043
1044 static int __init drm_core_init(void)
1045 {
1046 int ret;
1047
1048 drm_connector_ida_init();
1049 idr_init(&drm_minors_idr);
1050 drm_memcpy_init_early();
1051
1052 ret = drm_sysfs_init();
1053 if (ret < 0) {
1054 DRM_ERROR("Cannot create DRM class: %d\n", ret);
1055 goto error;
1056 }
1057
1058 drm_debugfs_root = debugfs_create_dir("dri", NULL);
1059
1060 ret = register_chrdev(DRM_MAJOR, "drm", &drm_stub_fops);
1061 if (ret < 0)
1062 goto error;
1063
1064 drm_privacy_screen_lookup_init();
1065
1066 drm_core_init_complete = true;
1067
1068 DRM_DEBUG("Initialized\n");
1069 return 0;
1070
1071 error:
1072 drm_core_exit();
1073 return ret;
1074 }
1075
1076 module_init(drm_core_init);
1077 module_exit(drm_core_exit);