blob: e30bb0d7c67a9de5c11130916a012db2b90d1045 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/**
2 * \file drm_stub.h
3 * Stub support
4 *
5 * \author Rickard E. (Rik) Faith <faith@valinux.com>
6 */
7
8/*
9 * Created: Fri Jan 19 10:48:35 2001 by faith@acm.org
10 *
11 * Copyright 2001 VA Linux Systems, Inc., Sunnyvale, California.
12 * All Rights Reserved.
13 *
14 * Permission is hereby granted, free of charge, to any person obtaining a
15 * copy of this software and associated documentation files (the "Software"),
16 * to deal in the Software without restriction, including without limitation
17 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
18 * and/or sell copies of the Software, and to permit persons to whom the
19 * Software is furnished to do so, subject to the following conditions:
20 *
21 * The above copyright notice and this permission notice (including the next
22 * paragraph) shall be included in all copies or substantial portions of the
23 * Software.
24 *
25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
28 * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
29 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
30 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
31 * DEALINGS IN THE SOFTWARE.
32 */
33
34#include <linux/module.h>
35#include <linux/moduleparam.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090036#include <linux/slab.h>
David Howells760285e2012-10-02 18:01:07 +010037#include <drm/drmP.h>
38#include <drm/drm_core.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039
Dave Airlieb5e89ed2005-09-25 14:28:13 +100040unsigned int drm_debug = 0; /* 1 to enable debug output */
Linus Torvalds1da177e2005-04-16 15:20:36 -070041EXPORT_SYMBOL(drm_debug);
42
Mario Kleiner27641c32010-10-23 04:20:23 +020043unsigned int drm_vblank_offdelay = 5000; /* Default to 5000 msecs. */
44EXPORT_SYMBOL(drm_vblank_offdelay);
45
46unsigned int drm_timestamp_precision = 20; /* Default to 20 usecs. */
47EXPORT_SYMBOL(drm_timestamp_precision);
48
Imre Deakc61eef72012-10-23 18:53:26 +000049/*
50 * Default to use monotonic timestamps for wait-for-vblank and page-flip
51 * complete events.
52 */
53unsigned int drm_timestamp_monotonic = 1;
54
Dave Airlieb5e89ed2005-09-25 14:28:13 +100055MODULE_AUTHOR(CORE_AUTHOR);
56MODULE_DESCRIPTION(CORE_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -070057MODULE_LICENSE("GPL and additional rights");
Linus Torvalds1da177e2005-04-16 15:20:36 -070058MODULE_PARM_DESC(debug, "Enable debug output");
Mario Kleiner27641c32010-10-23 04:20:23 +020059MODULE_PARM_DESC(vblankoffdelay, "Delay until vblank irq auto-disable [msecs]");
60MODULE_PARM_DESC(timestamp_precision_usec, "Max. error on timestamps [usecs]");
Imre Deakc61eef72012-10-23 18:53:26 +000061MODULE_PARM_DESC(timestamp_monotonic, "Use monotonic timestamps");
Linus Torvalds1da177e2005-04-16 15:20:36 -070062
Dave Jonesc0758142005-10-03 15:02:20 -040063module_param_named(debug, drm_debug, int, 0600);
Mario Kleiner27641c32010-10-23 04:20:23 +020064module_param_named(vblankoffdelay, drm_vblank_offdelay, int, 0600);
65module_param_named(timestamp_precision_usec, drm_timestamp_precision, int, 0600);
Imre Deakc61eef72012-10-23 18:53:26 +000066module_param_named(timestamp_monotonic, drm_timestamp_monotonic, int, 0600);
Linus Torvalds1da177e2005-04-16 15:20:36 -070067
Dave Airlie2c14f282008-04-21 16:47:32 +100068struct idr drm_minors_idr;
69
Greg Kroah-Hartman0650fd52006-01-20 14:08:59 -080070struct class *drm_class;
Ben Gamari955b12d2009-02-17 20:08:49 -050071struct dentry *drm_debugfs_root;
Joe Perches5ad3d882011-04-17 20:35:51 -070072
73int drm_err(const char *func, const char *format, ...)
74{
75 struct va_format vaf;
76 va_list args;
77 int r;
78
79 va_start(args, format);
80
81 vaf.fmt = format;
82 vaf.va = &args;
83
84 r = printk(KERN_ERR "[" DRM_NAME ":%s] *ERROR* %pV", func, &vaf);
85
86 va_end(args);
87
88 return r;
89}
90EXPORT_SYMBOL(drm_err);
91
yakui_zhao4fefcb22009-06-02 14:09:47 +080092void drm_ut_debug_printk(unsigned int request_level,
93 const char *prefix,
94 const char *function_name,
95 const char *format, ...)
96{
97 va_list args;
Linus Torvalds1da177e2005-04-16 15:20:36 -070098
yakui_zhao4fefcb22009-06-02 14:09:47 +080099 if (drm_debug & request_level) {
100 if (function_name)
101 printk(KERN_DEBUG "[%s:%s], ", prefix, function_name);
102 va_start(args, format);
103 vprintk(format, args);
104 va_end(args);
105 }
106}
107EXPORT_SYMBOL(drm_ut_debug_printk);
Joe Perches5ad3d882011-04-17 20:35:51 -0700108
Dave Airlie2c14f282008-04-21 16:47:32 +1000109static int drm_minor_get_id(struct drm_device *dev, int type)
110{
Dave Airlie2c14f282008-04-21 16:47:32 +1000111 int ret;
112 int base = 0, limit = 63;
113
Dave Airlief453ba02008-11-07 14:05:41 -0800114 if (type == DRM_MINOR_CONTROL) {
Kristian Høgsberg24f40032013-08-08 19:10:21 +0200115 base += 64;
116 limit = base + 63;
117 } else if (type == DRM_MINOR_RENDER) {
118 base += 128;
119 limit = base + 63;
120 }
Dave Airlief453ba02008-11-07 14:05:41 -0800121
Dave Airlie2c14f282008-04-21 16:47:32 +1000122 mutex_lock(&dev->struct_mutex);
Tejun Heo2e928812013-02-27 17:04:08 -0800123 ret = idr_alloc(&drm_minors_idr, NULL, base, limit, GFP_KERNEL);
Dave Airlie2c14f282008-04-21 16:47:32 +1000124 mutex_unlock(&dev->struct_mutex);
Dave Airlie2c14f282008-04-21 16:47:32 +1000125
Tejun Heo2e928812013-02-27 17:04:08 -0800126 return ret == -ENOSPC ? -EINVAL : ret;
Dave Airlie2c14f282008-04-21 16:47:32 +1000127}
128
Dave Airlie7c1c2872008-11-28 14:22:24 +1000129struct drm_master *drm_master_create(struct drm_minor *minor)
130{
131 struct drm_master *master;
132
Eric Anholt9a298b22009-03-24 12:23:04 -0700133 master = kzalloc(sizeof(*master), GFP_KERNEL);
Dave Airlie7c1c2872008-11-28 14:22:24 +1000134 if (!master)
135 return NULL;
136
137 kref_init(&master->refcount);
138 spin_lock_init(&master->lock.spinlock);
139 init_waitqueue_head(&master->lock.lock_queue);
140 drm_ht_create(&master->magiclist, DRM_MAGIC_HASH_ORDER);
141 INIT_LIST_HEAD(&master->magicfree);
142 master->minor = minor;
143
144 list_add_tail(&master->head, &minor->master_list);
145
146 return master;
147}
148
149struct drm_master *drm_master_get(struct drm_master *master)
150{
151 kref_get(&master->refcount);
152 return master;
153}
Thomas Hellstrom85bb0c32009-12-06 21:46:28 +0100154EXPORT_SYMBOL(drm_master_get);
Dave Airlie7c1c2872008-11-28 14:22:24 +1000155
156static void drm_master_destroy(struct kref *kref)
157{
158 struct drm_master *master = container_of(kref, struct drm_master, refcount);
159 struct drm_magic_entry *pt, *next;
160 struct drm_device *dev = master->minor->dev;
Dave Airliec1ff85d2009-01-19 17:17:58 +1000161 struct drm_map_list *r_list, *list_temp;
Dave Airlie7c1c2872008-11-28 14:22:24 +1000162
163 list_del(&master->head);
164
165 if (dev->driver->master_destroy)
166 dev->driver->master_destroy(dev, master);
167
Dave Airliec1ff85d2009-01-19 17:17:58 +1000168 list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head) {
169 if (r_list->master == master) {
170 drm_rmmap_locked(dev, r_list->map);
171 r_list = NULL;
172 }
173 }
174
Dave Airlie7c1c2872008-11-28 14:22:24 +1000175 if (master->unique) {
Eric Anholt9a298b22009-03-24 12:23:04 -0700176 kfree(master->unique);
Dave Airlie7c1c2872008-11-28 14:22:24 +1000177 master->unique = NULL;
178 master->unique_len = 0;
179 }
180
Chris Wilson6e350232010-07-24 18:29:36 +0100181 kfree(dev->devname);
182 dev->devname = NULL;
183
Dave Airlie7c1c2872008-11-28 14:22:24 +1000184 list_for_each_entry_safe(pt, next, &master->magicfree, head) {
185 list_del(&pt->head);
186 drm_ht_remove_item(&master->magiclist, &pt->hash_item);
Eric Anholt9a298b22009-03-24 12:23:04 -0700187 kfree(pt);
Dave Airlie7c1c2872008-11-28 14:22:24 +1000188 }
189
190 drm_ht_remove(&master->magiclist);
191
Eric Anholt9a298b22009-03-24 12:23:04 -0700192 kfree(master);
Dave Airlie7c1c2872008-11-28 14:22:24 +1000193}
194
195void drm_master_put(struct drm_master **master)
196{
197 kref_put(&(*master)->refcount, drm_master_destroy);
198 *master = NULL;
199}
Thomas Hellstrom85bb0c32009-12-06 21:46:28 +0100200EXPORT_SYMBOL(drm_master_put);
Dave Airlie7c1c2872008-11-28 14:22:24 +1000201
202int drm_setmaster_ioctl(struct drm_device *dev, void *data,
203 struct drm_file *file_priv)
204{
Benjamin Gaignard53ef1602013-06-26 17:58:59 +0200205 int ret = 0;
Thomas Hellstrom862302f2009-12-02 18:15:25 +0000206
Jonas Bonn6b008422009-04-16 09:00:02 +0200207 if (file_priv->is_master)
208 return 0;
209
Dave Airlie7c1c2872008-11-28 14:22:24 +1000210 if (file_priv->minor->master && file_priv->minor->master != file_priv->master)
211 return -EINVAL;
212
213 if (!file_priv->master)
214 return -EINVAL;
215
David Herrmann08bec5b2012-11-15 13:04:37 +0000216 if (file_priv->minor->master)
217 return -EINVAL;
218
219 mutex_lock(&dev->struct_mutex);
220 file_priv->minor->master = drm_master_get(file_priv->master);
221 file_priv->is_master = 1;
222 if (dev->driver->master_set) {
223 ret = dev->driver->master_set(dev, file_priv, false);
224 if (unlikely(ret != 0)) {
225 file_priv->is_master = 0;
226 drm_master_put(&file_priv->minor->master);
Thomas Hellstrom862302f2009-12-02 18:15:25 +0000227 }
Dave Airlie7c1c2872008-11-28 14:22:24 +1000228 }
David Herrmann08bec5b2012-11-15 13:04:37 +0000229 mutex_unlock(&dev->struct_mutex);
Dave Airlie7c1c2872008-11-28 14:22:24 +1000230
Benjamin Gaignard53ef1602013-06-26 17:58:59 +0200231 return ret;
Dave Airlie7c1c2872008-11-28 14:22:24 +1000232}
233
234int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
235 struct drm_file *file_priv)
236{
Jonas Bonn6b008422009-04-16 09:00:02 +0200237 if (!file_priv->is_master)
Dave Airlie7c1c2872008-11-28 14:22:24 +1000238 return -EINVAL;
Jonas Bonn6b008422009-04-16 09:00:02 +0200239
Dave Airlie07f1c7a2009-04-20 09:32:50 +1000240 if (!file_priv->minor->master)
241 return -EINVAL;
242
Dave Airlie7c1c2872008-11-28 14:22:24 +1000243 mutex_lock(&dev->struct_mutex);
Thomas Hellstrom862302f2009-12-02 18:15:25 +0000244 if (dev->driver->master_drop)
245 dev->driver->master_drop(dev, file_priv, false);
Dave Airlie7c1c2872008-11-28 14:22:24 +1000246 drm_master_put(&file_priv->minor->master);
Jonas Bonn6b008422009-04-16 09:00:02 +0200247 file_priv->is_master = 0;
Dave Airlie7c1c2872008-11-28 14:22:24 +1000248 mutex_unlock(&dev->struct_mutex);
249 return 0;
250}
251
Jordan Crousedcdb1672010-05-27 13:40:25 -0600252int drm_fill_in_dev(struct drm_device *dev,
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000253 const struct pci_device_id *ent,
254 struct drm_driver *driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255{
256 int retcode;
257
Dave Airliebd1b3312007-05-26 05:01:51 +1000258 INIT_LIST_HEAD(&dev->filelist);
Dave Airlie7c158ac2007-07-11 12:05:36 +1000259 INIT_LIST_HEAD(&dev->ctxlist);
260 INIT_LIST_HEAD(&dev->vmalist);
261 INIT_LIST_HEAD(&dev->maplist);
Kristian Høgsbergc9a9c5e2009-09-12 04:33:34 +1000262 INIT_LIST_HEAD(&dev->vblank_event_list);
Dave Airlie7c158ac2007-07-11 12:05:36 +1000263
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 spin_lock_init(&dev->count_lock);
Kristian Høgsbergc9a9c5e2009-09-12 04:33:34 +1000265 spin_lock_init(&dev->event_lock);
Dave Airlie30e2fb12006-02-02 19:37:46 +1100266 mutex_init(&dev->struct_mutex);
267 mutex_init(&dev->ctxlist_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268
Thomas Hellstrom8d153f72006-08-07 22:36:47 +1000269 if (drm_ht_create(&dev->map_hash, 12)) {
Thomas Hellstrom8d153f72006-08-07 22:36:47 +1000270 return -ENOMEM;
271 }
Dave Airlie836cf042005-07-10 19:27:04 +1000272
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 /* the DRM has 6 basic counters */
274 dev->counters = 6;
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000275 dev->types[0] = _DRM_STAT_LOCK;
276 dev->types[1] = _DRM_STAT_OPENS;
277 dev->types[2] = _DRM_STAT_CLOSES;
278 dev->types[3] = _DRM_STAT_IOCTLS;
279 dev->types[4] = _DRM_STAT_LOCKS;
280 dev->types[5] = _DRM_STAT_UNLOCKS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281
282 dev->driver = driver;
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000283
Dave Airlie8410ea32010-12-15 03:16:38 +1000284 if (dev->driver->bus->agp_init) {
285 retcode = dev->driver->bus->agp_init(dev);
286 if (retcode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 goto error_out_unreg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 }
289
Daniel Vetter7c510132013-08-08 15:41:21 +0200290 drm_legacy_ctxbitmap_init(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291
Eric Anholt673a3942008-07-30 12:06:12 -0700292 if (driver->driver_features & DRIVER_GEM) {
293 retcode = drm_gem_init(dev);
294 if (retcode) {
295 DRM_ERROR("Cannot initialize graphics execution "
296 "manager (GEM)\n");
297 goto error_out_unreg;
298 }
299 }
300
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 return 0;
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000302
303 error_out_unreg:
Dave Airlie22eae942005-11-10 22:16:34 +1100304 drm_lastclose(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 return retcode;
306}
Dave Airlie9c1dfc52012-03-20 06:59:29 +0000307EXPORT_SYMBOL(drm_fill_in_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310/**
311 * Get a secondary minor number.
312 *
313 * \param dev device data structure
314 * \param sec-minor structure to hold the assigned minor
315 * \return negative number on failure.
316 *
Daniel Vettercb6458f2013-08-08 15:41:34 +0200317 * Search an empty entry and initialize it to the given parameters. This
318 * routines assigns minor numbers to secondary heads of multi-headed cards
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 */
Jordan Crousedcdb1672010-05-27 13:40:25 -0600320int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, int type)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321{
Dave Airlie2c14f282008-04-21 16:47:32 +1000322 struct drm_minor *new_minor;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 int ret;
Dave Airlie2c14f282008-04-21 16:47:32 +1000324 int minor_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325
326 DRM_DEBUG("\n");
327
Dave Airlie2c14f282008-04-21 16:47:32 +1000328 minor_id = drm_minor_get_id(dev, type);
329 if (minor_id < 0)
330 return minor_id;
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000331
Dave Airlie2c14f282008-04-21 16:47:32 +1000332 new_minor = kzalloc(sizeof(struct drm_minor), GFP_KERNEL);
333 if (!new_minor) {
334 ret = -ENOMEM;
335 goto err_idr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 }
Dave Airlie2c14f282008-04-21 16:47:32 +1000337
338 new_minor->type = type;
339 new_minor->device = MKDEV(DRM_MAJOR, minor_id);
340 new_minor->dev = dev;
341 new_minor->index = minor_id;
Dave Airlie7c1c2872008-11-28 14:22:24 +1000342 INIT_LIST_HEAD(&new_minor->master_list);
Dave Airlie2c14f282008-04-21 16:47:32 +1000343
344 idr_replace(&drm_minors_idr, new_minor, minor_id);
345
Ben Gamari955b12d2009-02-17 20:08:49 -0500346#if defined(CONFIG_DEBUG_FS)
347 ret = drm_debugfs_init(new_minor, minor_id, drm_debugfs_root);
348 if (ret) {
GeunSik Lim156f5a72009-06-02 15:01:37 +0900349 DRM_ERROR("DRM: Failed to initialize /sys/kernel/debug/dri.\n");
Daniel Vettercb6458f2013-08-08 15:41:34 +0200350 goto err_mem;
Ben Gamari955b12d2009-02-17 20:08:49 -0500351 }
352#endif
Dave Airlie2c14f282008-04-21 16:47:32 +1000353
354 ret = drm_sysfs_device_add(new_minor);
355 if (ret) {
356 printk(KERN_ERR
357 "DRM: Error sysfs_device_add.\n");
Daniel Vettercb6458f2013-08-08 15:41:34 +0200358 goto err_debugfs;
Dave Airlie2c14f282008-04-21 16:47:32 +1000359 }
360 *minor = new_minor;
361
362 DRM_DEBUG("new minor assigned %d\n", minor_id);
363 return 0;
364
365
Daniel Vettercb6458f2013-08-08 15:41:34 +0200366err_debugfs:
367#if defined(CONFIG_DEBUG_FS)
368 drm_debugfs_cleanup(new_minor);
Dave Airlie2c14f282008-04-21 16:47:32 +1000369err_mem:
Daniel Vettercb6458f2013-08-08 15:41:34 +0200370#endif
Dave Airlie2c14f282008-04-21 16:47:32 +1000371 kfree(new_minor);
372err_idr:
373 idr_remove(&drm_minors_idr, minor_id);
374 *minor = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 return ret;
376}
Dave Airlie9c1dfc52012-03-20 06:59:29 +0000377EXPORT_SYMBOL(drm_get_minor);
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000378
Dave Airliec94f7022005-07-07 21:03:38 +1000379/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 * Put a secondary minor number.
381 *
382 * \param sec_minor - structure to be released
383 * \return always zero
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 */
Dave Airlie2c14f282008-04-21 16:47:32 +1000385int drm_put_minor(struct drm_minor **minor_p)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386{
Dave Airlie2c14f282008-04-21 16:47:32 +1000387 struct drm_minor *minor = *minor_p;
Eric Anholt673a3942008-07-30 12:06:12 -0700388
Dave Airlie2c14f282008-04-21 16:47:32 +1000389 DRM_DEBUG("release secondary minor %d\n", minor->index);
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000390
Ben Gamari955b12d2009-02-17 20:08:49 -0500391#if defined(CONFIG_DEBUG_FS)
392 drm_debugfs_cleanup(minor);
393#endif
394
Dave Airlie2c14f282008-04-21 16:47:32 +1000395 drm_sysfs_device_remove(minor);
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000396
Dave Airlie2c14f282008-04-21 16:47:32 +1000397 idr_remove(&drm_minors_idr, minor->index);
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000398
Dave Airlie2c14f282008-04-21 16:47:32 +1000399 kfree(minor);
400 *minor_p = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 return 0;
402}
Dave Airlie9c1dfc52012-03-20 06:59:29 +0000403EXPORT_SYMBOL(drm_put_minor);
Kristian Høgsberg112b7152009-01-04 16:55:33 -0500404
Dave Airlie2c07a212012-02-20 14:18:07 +0000405static void drm_unplug_minor(struct drm_minor *minor)
406{
407 drm_sysfs_device_remove(minor);
408}
409
Kristian Høgsberg112b7152009-01-04 16:55:33 -0500410/**
411 * Called via drm_exit() at module unload time or when pci device is
412 * unplugged.
413 *
414 * Cleans up all DRM device, calling drm_lastclose().
415 *
Kristian Høgsberg112b7152009-01-04 16:55:33 -0500416 */
417void drm_put_dev(struct drm_device *dev)
418{
Julia Lawallecca0682009-07-11 09:50:09 +0200419 struct drm_driver *driver;
Kristian Høgsberg112b7152009-01-04 16:55:33 -0500420 struct drm_map_list *r_list, *list_temp;
421
422 DRM_DEBUG("\n");
423
424 if (!dev) {
425 DRM_ERROR("cleanup called no dev\n");
426 return;
427 }
Julia Lawallecca0682009-07-11 09:50:09 +0200428 driver = dev->driver;
Kristian Høgsberg112b7152009-01-04 16:55:33 -0500429
Kristian Høgsberg112b7152009-01-04 16:55:33 -0500430 drm_lastclose(dev);
431
Kristian Høgsberg112b7152009-01-04 16:55:33 -0500432 if (dev->driver->unload)
433 dev->driver->unload(dev);
434
David Herrmann28ec7112013-07-27 16:37:00 +0200435 if (dev->driver->bus->agp_destroy)
436 dev->driver->bus->agp_destroy(dev);
Kristian Høgsberg112b7152009-01-04 16:55:33 -0500437
Jesse Barnesb78315f2010-03-26 11:07:16 -0700438 drm_vblank_cleanup(dev);
439
Kristian Høgsberg112b7152009-01-04 16:55:33 -0500440 list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head)
441 drm_rmmap(dev, r_list->map);
Ben Skeggs30ddbd92009-03-02 11:13:04 +1000442 drm_ht_remove(&dev->map_hash);
443
Daniel Vetter7c510132013-08-08 15:41:21 +0200444 drm_legacy_ctxbitmap_cleanup(dev);
Kristian Høgsberg112b7152009-01-04 16:55:33 -0500445
446 if (drm_core_check_feature(dev, DRIVER_MODESET))
447 drm_put_minor(&dev->control);
448
449 if (driver->driver_features & DRIVER_GEM)
450 drm_gem_destroy(dev);
451
452 drm_put_minor(&dev->primary);
453
Dave Airliea250b9f2010-12-15 07:13:55 +1000454 list_del(&dev->driver_item);
Sachin Kamat66141d32012-11-19 09:44:59 +0000455 kfree(dev->devname);
Eric Anholt9a298b22009-03-24 12:23:04 -0700456 kfree(dev);
Kristian Høgsberg112b7152009-01-04 16:55:33 -0500457}
458EXPORT_SYMBOL(drm_put_dev);
Dave Airlie2c07a212012-02-20 14:18:07 +0000459
460void drm_unplug_dev(struct drm_device *dev)
461{
462 /* for a USB device */
463 if (drm_core_check_feature(dev, DRIVER_MODESET))
464 drm_unplug_minor(dev->control);
465 drm_unplug_minor(dev->primary);
466
467 mutex_lock(&drm_global_mutex);
468
469 drm_device_set_unplugged(dev);
470
471 if (dev->open_count == 0) {
472 drm_put_dev(dev);
473 }
474 mutex_unlock(&drm_global_mutex);
475}
476EXPORT_SYMBOL(drm_unplug_dev);