xref: /dragonfly/sys/dev/drm/drm_drv.c (revision 1b13d190)
19edbd4a0SFrançois Tigeot /*
224edb884SFrançois Tigeot  * Created: Fri Jan 19 10:48:35 2001 by faith@acm.org
39edbd4a0SFrançois Tigeot  *
424edb884SFrançois Tigeot  * Copyright 2001 VA Linux Systems, Inc., Sunnyvale, California.
57f3c3d6fSHasso Tepper  * All Rights Reserved.
67f3c3d6fSHasso Tepper  *
724edb884SFrançois Tigeot  * Author Rickard E. (Rik) Faith <faith@valinux.com>
824edb884SFrançois Tigeot  *
97f3c3d6fSHasso Tepper  * Permission is hereby granted, free of charge, to any person obtaining a
107f3c3d6fSHasso Tepper  * copy of this software and associated documentation files (the "Software"),
117f3c3d6fSHasso Tepper  * to deal in the Software without restriction, including without limitation
127f3c3d6fSHasso Tepper  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
137f3c3d6fSHasso Tepper  * and/or sell copies of the Software, and to permit persons to whom the
147f3c3d6fSHasso Tepper  * Software is furnished to do so, subject to the following conditions:
157f3c3d6fSHasso Tepper  *
167f3c3d6fSHasso Tepper  * The above copyright notice and this permission notice (including the next
177f3c3d6fSHasso Tepper  * paragraph) shall be included in all copies or substantial portions of the
187f3c3d6fSHasso Tepper  * Software.
197f3c3d6fSHasso Tepper  *
207f3c3d6fSHasso Tepper  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
217f3c3d6fSHasso Tepper  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
227f3c3d6fSHasso Tepper  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
2324edb884SFrançois Tigeot  * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
247f3c3d6fSHasso Tepper  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
2524edb884SFrançois Tigeot  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2624edb884SFrançois Tigeot  * DEALINGS IN THE SOFTWARE.
277f3c3d6fSHasso Tepper  */
287f3c3d6fSHasso Tepper 
2924edb884SFrançois Tigeot #include <linux/module.h>
3024edb884SFrançois Tigeot #include <linux/moduleparam.h>
3124edb884SFrançois Tigeot #include <drm/drmP.h>
3224edb884SFrançois Tigeot #include <drm/drm_core.h>
3324edb884SFrançois Tigeot #include "drm_legacy.h"
34*1b13d190SFrançois Tigeot #include "drm_internal.h"
3524edb884SFrançois Tigeot 
3624edb884SFrançois Tigeot unsigned int drm_debug = 0;	/* 1 to enable debug output */
3724edb884SFrançois Tigeot EXPORT_SYMBOL(drm_debug);
3824edb884SFrançois Tigeot 
39*1b13d190SFrançois Tigeot int drm_vblank_offdelay = 5000;    /* Default to 5000 msecs. */
4024edb884SFrançois Tigeot 
4124edb884SFrançois Tigeot unsigned int drm_timestamp_precision = 20;  /* Default to 20 usecs. */
4224edb884SFrançois Tigeot 
4324edb884SFrançois Tigeot /*
4424edb884SFrançois Tigeot  * Default to use monotonic timestamps for wait-for-vblank and page-flip
4524edb884SFrançois Tigeot  * complete events.
4624edb884SFrançois Tigeot  */
4724edb884SFrançois Tigeot unsigned int drm_timestamp_monotonic = 1;
4824edb884SFrançois Tigeot 
4924edb884SFrançois Tigeot MODULE_AUTHOR(CORE_AUTHOR);
5024edb884SFrançois Tigeot MODULE_DESCRIPTION(CORE_DESC);
5124edb884SFrançois Tigeot MODULE_LICENSE("GPL and additional rights");
5224edb884SFrançois Tigeot MODULE_PARM_DESC(debug, "Enable debug output");
53*1b13d190SFrançois Tigeot MODULE_PARM_DESC(vblankoffdelay, "Delay until vblank irq auto-disable [msecs] (0: never disable, <0: disable immediately)");
5424edb884SFrançois Tigeot MODULE_PARM_DESC(timestamp_precision_usec, "Max. error on timestamps [usecs]");
5524edb884SFrançois Tigeot MODULE_PARM_DESC(timestamp_monotonic, "Use monotonic timestamps");
5624edb884SFrançois Tigeot 
5724edb884SFrançois Tigeot module_param_named(debug, drm_debug, int, 0600);
5824edb884SFrançois Tigeot module_param_named(vblankoffdelay, drm_vblank_offdelay, int, 0600);
5924edb884SFrançois Tigeot module_param_named(timestamp_precision_usec, drm_timestamp_precision, int, 0600);
6024edb884SFrançois Tigeot module_param_named(timestamp_monotonic, drm_timestamp_monotonic, int, 0600);
6124edb884SFrançois Tigeot 
6224edb884SFrançois Tigeot #if 0
6324edb884SFrançois Tigeot static DEFINE_SPINLOCK(drm_minor_lock);
6424edb884SFrançois Tigeot static struct idr drm_minors_idr;
6524edb884SFrançois Tigeot #endif
6624edb884SFrançois Tigeot 
6724edb884SFrançois Tigeot struct class *drm_class;
6824edb884SFrançois Tigeot #if 0
6924edb884SFrançois Tigeot static struct dentry *drm_debugfs_root;
7024edb884SFrançois Tigeot #endif
7124edb884SFrançois Tigeot 
72*1b13d190SFrançois Tigeot void drm_err(const char *func, const char *format, ...)
7324edb884SFrançois Tigeot {
7424edb884SFrançois Tigeot #if 0
7524edb884SFrançois Tigeot 	struct va_format vaf;
7624edb884SFrançois Tigeot 	va_list args;
7724edb884SFrançois Tigeot 	int r;
7824edb884SFrançois Tigeot 
7924edb884SFrançois Tigeot 	va_start(args, format);
8024edb884SFrançois Tigeot 
8124edb884SFrançois Tigeot 	vaf.fmt = format;
8224edb884SFrançois Tigeot 	vaf.va = &args;
8324edb884SFrançois Tigeot 
8424edb884SFrançois Tigeot 	r = printk(KERN_ERR "[" DRM_NAME ":%s] *ERROR* %pV", func, &vaf);
8524edb884SFrançois Tigeot 
8624edb884SFrançois Tigeot 	va_end(args);
8724edb884SFrançois Tigeot 
8824edb884SFrançois Tigeot 	return r;
8924edb884SFrançois Tigeot #endif
9024edb884SFrançois Tigeot }
9124edb884SFrançois Tigeot EXPORT_SYMBOL(drm_err);
9224edb884SFrançois Tigeot 
9324edb884SFrançois Tigeot void drm_ut_debug_printk(const char *function_name, const char *format, ...)
9424edb884SFrançois Tigeot {
9524edb884SFrançois Tigeot #if 0
9624edb884SFrançois Tigeot 	struct va_format vaf;
9724edb884SFrançois Tigeot 	va_list args;
9824edb884SFrançois Tigeot 
9924edb884SFrançois Tigeot 	va_start(args, format);
10024edb884SFrançois Tigeot 	vaf.fmt = format;
10124edb884SFrançois Tigeot 	vaf.va = &args;
10224edb884SFrançois Tigeot 
10324edb884SFrançois Tigeot 	printk(KERN_DEBUG "[" DRM_NAME ":%s] %pV", function_name, &vaf);
10424edb884SFrançois Tigeot 
10524edb884SFrançois Tigeot 	va_end(args);
10624edb884SFrançois Tigeot #endif
10724edb884SFrançois Tigeot }
10824edb884SFrançois Tigeot EXPORT_SYMBOL(drm_ut_debug_printk);
10924edb884SFrançois Tigeot 
11024edb884SFrançois Tigeot #if 0
11124edb884SFrançois Tigeot struct drm_master *drm_master_create(struct drm_minor *minor)
11224edb884SFrançois Tigeot {
11324edb884SFrançois Tigeot 	struct drm_master *master;
11424edb884SFrançois Tigeot 
11524edb884SFrançois Tigeot 	master = kzalloc(sizeof(*master), GFP_KERNEL);
11624edb884SFrançois Tigeot 	if (!master)
11724edb884SFrançois Tigeot 		return NULL;
11824edb884SFrançois Tigeot 
11924edb884SFrançois Tigeot 	kref_init(&master->refcount);
12024edb884SFrançois Tigeot 	spin_lock_init(&master->lock.spinlock);
12124edb884SFrançois Tigeot 	init_waitqueue_head(&master->lock.lock_queue);
12224edb884SFrançois Tigeot 	if (drm_ht_create(&master->magiclist, DRM_MAGIC_HASH_ORDER)) {
12324edb884SFrançois Tigeot 		kfree(master);
12424edb884SFrançois Tigeot 		return NULL;
12524edb884SFrançois Tigeot 	}
12624edb884SFrançois Tigeot 	INIT_LIST_HEAD(&master->magicfree);
12724edb884SFrançois Tigeot 	master->minor = minor;
12824edb884SFrançois Tigeot 
12924edb884SFrançois Tigeot 	return master;
13024edb884SFrançois Tigeot }
13124edb884SFrançois Tigeot 
13224edb884SFrançois Tigeot struct drm_master *drm_master_get(struct drm_master *master)
13324edb884SFrançois Tigeot {
13424edb884SFrançois Tigeot 	kref_get(&master->refcount);
13524edb884SFrançois Tigeot 	return master;
13624edb884SFrançois Tigeot }
13724edb884SFrançois Tigeot EXPORT_SYMBOL(drm_master_get);
13824edb884SFrançois Tigeot 
13924edb884SFrançois Tigeot static void drm_master_destroy(struct kref *kref)
14024edb884SFrançois Tigeot {
14124edb884SFrançois Tigeot 	struct drm_master *master = container_of(kref, struct drm_master, refcount);
14224edb884SFrançois Tigeot 	struct drm_device *dev = master->minor->dev;
14324edb884SFrançois Tigeot 	struct drm_map_list *r_list, *list_temp;
14424edb884SFrançois Tigeot 
14524edb884SFrançois Tigeot 	mutex_lock(&dev->struct_mutex);
14624edb884SFrançois Tigeot 	if (dev->driver->master_destroy)
14724edb884SFrançois Tigeot 		dev->driver->master_destroy(dev, master);
14824edb884SFrançois Tigeot 
14924edb884SFrançois Tigeot 	list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head) {
15024edb884SFrançois Tigeot 		if (r_list->master == master) {
151*1b13d190SFrançois Tigeot 			drm_legacy_rmmap_locked(dev, r_list->map);
15224edb884SFrançois Tigeot 			r_list = NULL;
15324edb884SFrançois Tigeot 		}
15424edb884SFrançois Tigeot 	}
15524edb884SFrançois Tigeot 
15624edb884SFrançois Tigeot 	if (master->unique) {
15724edb884SFrançois Tigeot 		kfree(master->unique);
15824edb884SFrançois Tigeot 		master->unique = NULL;
15924edb884SFrançois Tigeot 		master->unique_len = 0;
16024edb884SFrançois Tigeot 	}
16124edb884SFrançois Tigeot 
16224edb884SFrançois Tigeot 	drm_ht_remove(&master->magiclist);
16324edb884SFrançois Tigeot 
16424edb884SFrançois Tigeot 	mutex_unlock(&dev->struct_mutex);
16524edb884SFrançois Tigeot 	kfree(master);
16624edb884SFrançois Tigeot }
16724edb884SFrançois Tigeot 
16824edb884SFrançois Tigeot void drm_master_put(struct drm_master **master)
16924edb884SFrançois Tigeot {
17024edb884SFrançois Tigeot 	kref_put(&(*master)->refcount, drm_master_destroy);
17124edb884SFrançois Tigeot 	*master = NULL;
17224edb884SFrançois Tigeot }
17324edb884SFrançois Tigeot EXPORT_SYMBOL(drm_master_put);
17424edb884SFrançois Tigeot #endif
17524edb884SFrançois Tigeot 
17624edb884SFrançois Tigeot int drm_setmaster_ioctl(struct drm_device *dev, void *data,
17724edb884SFrançois Tigeot 			struct drm_file *file_priv)
17824edb884SFrançois Tigeot {
17924edb884SFrançois Tigeot 	DRM_DEBUG("setmaster\n");
18024edb884SFrançois Tigeot 
18124edb884SFrançois Tigeot 	if (file_priv->master != 0)
18224edb884SFrançois Tigeot 		return (0);
18324edb884SFrançois Tigeot 
18424edb884SFrançois Tigeot 	return (-EPERM);
18524edb884SFrançois Tigeot }
18624edb884SFrançois Tigeot 
18724edb884SFrançois Tigeot int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
18824edb884SFrançois Tigeot 			 struct drm_file *file_priv)
18924edb884SFrançois Tigeot {
19024edb884SFrançois Tigeot 	DRM_DEBUG("dropmaster\n");
19124edb884SFrançois Tigeot 	if (file_priv->master != 0)
19224edb884SFrançois Tigeot 		return -EINVAL;
19324edb884SFrançois Tigeot 	return 0;
19424edb884SFrançois Tigeot }
19524edb884SFrançois Tigeot 
19624edb884SFrançois Tigeot #if 0
19724edb884SFrançois Tigeot /*
19824edb884SFrançois Tigeot  * DRM Minors
19924edb884SFrançois Tigeot  * A DRM device can provide several char-dev interfaces on the DRM-Major. Each
20024edb884SFrançois Tigeot  * of them is represented by a drm_minor object. Depending on the capabilities
20124edb884SFrançois Tigeot  * of the device-driver, different interfaces are registered.
20224edb884SFrançois Tigeot  *
20324edb884SFrançois Tigeot  * Minors can be accessed via dev->$minor_name. This pointer is either
20424edb884SFrançois Tigeot  * NULL or a valid drm_minor pointer and stays valid as long as the device is
20524edb884SFrançois Tigeot  * valid. This means, DRM minors have the same life-time as the underlying
20624edb884SFrançois Tigeot  * device. However, this doesn't mean that the minor is active. Minors are
20724edb884SFrançois Tigeot  * registered and unregistered dynamically according to device-state.
20824edb884SFrançois Tigeot  */
20924edb884SFrançois Tigeot 
21024edb884SFrançois Tigeot static struct drm_minor **drm_minor_get_slot(struct drm_device *dev,
21124edb884SFrançois Tigeot 					     unsigned int type)
21224edb884SFrançois Tigeot {
21324edb884SFrançois Tigeot 	switch (type) {
21424edb884SFrançois Tigeot 	case DRM_MINOR_LEGACY:
21524edb884SFrançois Tigeot 		return &dev->primary;
21624edb884SFrançois Tigeot 	case DRM_MINOR_RENDER:
21724edb884SFrançois Tigeot 		return &dev->render;
21824edb884SFrançois Tigeot 	case DRM_MINOR_CONTROL:
21924edb884SFrançois Tigeot 		return &dev->control;
22024edb884SFrançois Tigeot 	default:
22124edb884SFrançois Tigeot 		return NULL;
22224edb884SFrançois Tigeot 	}
22324edb884SFrançois Tigeot }
22424edb884SFrançois Tigeot 
22524edb884SFrançois Tigeot static int drm_minor_alloc(struct drm_device *dev, unsigned int type)
22624edb884SFrançois Tigeot {
22724edb884SFrançois Tigeot 	struct drm_minor *minor;
22824edb884SFrançois Tigeot 	unsigned long flags;
22924edb884SFrançois Tigeot 	int r;
23024edb884SFrançois Tigeot 
23124edb884SFrançois Tigeot 	minor = kzalloc(sizeof(*minor), GFP_KERNEL);
23224edb884SFrançois Tigeot 	if (!minor)
23324edb884SFrançois Tigeot 		return -ENOMEM;
23424edb884SFrançois Tigeot 
23524edb884SFrançois Tigeot 	minor->type = type;
23624edb884SFrançois Tigeot 	minor->dev = dev;
23724edb884SFrançois Tigeot 
23824edb884SFrançois Tigeot 	idr_preload(GFP_KERNEL);
23924edb884SFrançois Tigeot 	spin_lock_irqsave(&drm_minor_lock, flags);
24024edb884SFrançois Tigeot 	r = idr_alloc(&drm_minors_idr,
24124edb884SFrançois Tigeot 		      NULL,
24224edb884SFrançois Tigeot 		      64 * type,
24324edb884SFrançois Tigeot 		      64 * (type + 1),
24424edb884SFrançois Tigeot 		      GFP_NOWAIT);
24524edb884SFrançois Tigeot 	spin_unlock_irqrestore(&drm_minor_lock, flags);
24624edb884SFrançois Tigeot 	idr_preload_end();
24724edb884SFrançois Tigeot 
24824edb884SFrançois Tigeot 	if (r < 0)
24924edb884SFrançois Tigeot 		goto err_free;
25024edb884SFrançois Tigeot 
25124edb884SFrançois Tigeot 	minor->index = r;
25224edb884SFrançois Tigeot 
25324edb884SFrançois Tigeot 	minor->kdev = drm_sysfs_minor_alloc(minor);
25424edb884SFrançois Tigeot 	if (IS_ERR(minor->kdev)) {
25524edb884SFrançois Tigeot 		r = PTR_ERR(minor->kdev);
25624edb884SFrançois Tigeot 		goto err_index;
25724edb884SFrançois Tigeot 	}
25824edb884SFrançois Tigeot 
25924edb884SFrançois Tigeot 	*drm_minor_get_slot(dev, type) = minor;
26024edb884SFrançois Tigeot 	return 0;
26124edb884SFrançois Tigeot 
26224edb884SFrançois Tigeot err_index:
26324edb884SFrançois Tigeot 	spin_lock_irqsave(&drm_minor_lock, flags);
26424edb884SFrançois Tigeot 	idr_remove(&drm_minors_idr, minor->index);
26524edb884SFrançois Tigeot 	spin_unlock_irqrestore(&drm_minor_lock, flags);
26624edb884SFrançois Tigeot err_free:
26724edb884SFrançois Tigeot 	kfree(minor);
26824edb884SFrançois Tigeot 	return r;
26924edb884SFrançois Tigeot }
27024edb884SFrançois Tigeot 
27124edb884SFrançois Tigeot static void drm_minor_free(struct drm_device *dev, unsigned int type)
27224edb884SFrançois Tigeot {
27324edb884SFrançois Tigeot 	struct drm_minor **slot, *minor;
27424edb884SFrançois Tigeot 	unsigned long flags;
27524edb884SFrançois Tigeot 
27624edb884SFrançois Tigeot 	slot = drm_minor_get_slot(dev, type);
27724edb884SFrançois Tigeot 	minor = *slot;
27824edb884SFrançois Tigeot 	if (!minor)
27924edb884SFrançois Tigeot 		return;
28024edb884SFrançois Tigeot 
28124edb884SFrançois Tigeot 	drm_mode_group_destroy(&minor->mode_group);
28224edb884SFrançois Tigeot 	put_device(minor->kdev);
28324edb884SFrançois Tigeot 
28424edb884SFrançois Tigeot 	spin_lock_irqsave(&drm_minor_lock, flags);
28524edb884SFrançois Tigeot 	idr_remove(&drm_minors_idr, minor->index);
28624edb884SFrançois Tigeot 	spin_unlock_irqrestore(&drm_minor_lock, flags);
28724edb884SFrançois Tigeot 
28824edb884SFrançois Tigeot 	kfree(minor);
28924edb884SFrançois Tigeot 	*slot = NULL;
29024edb884SFrançois Tigeot }
29124edb884SFrançois Tigeot 
29224edb884SFrançois Tigeot static int drm_minor_register(struct drm_device *dev, unsigned int type)
29324edb884SFrançois Tigeot {
29424edb884SFrançois Tigeot 	struct drm_minor *minor;
29524edb884SFrançois Tigeot 	unsigned long flags;
29624edb884SFrançois Tigeot 	int ret;
29724edb884SFrançois Tigeot 
29824edb884SFrançois Tigeot 	DRM_DEBUG("\n");
29924edb884SFrançois Tigeot 
30024edb884SFrançois Tigeot 	minor = *drm_minor_get_slot(dev, type);
30124edb884SFrançois Tigeot 	if (!minor)
30224edb884SFrançois Tigeot 		return 0;
30324edb884SFrançois Tigeot 
30424edb884SFrançois Tigeot 	ret = drm_debugfs_init(minor, minor->index, drm_debugfs_root);
30524edb884SFrançois Tigeot 	if (ret) {
30624edb884SFrançois Tigeot 		DRM_ERROR("DRM: Failed to initialize /sys/kernel/debug/dri.\n");
30724edb884SFrançois Tigeot 		return ret;
30824edb884SFrançois Tigeot 	}
30924edb884SFrançois Tigeot 
31024edb884SFrançois Tigeot 	ret = device_add(minor->kdev);
31124edb884SFrançois Tigeot 	if (ret)
31224edb884SFrançois Tigeot 		goto err_debugfs;
31324edb884SFrançois Tigeot 
31424edb884SFrançois Tigeot 	/* replace NULL with @minor so lookups will succeed from now on */
31524edb884SFrançois Tigeot 	spin_lock_irqsave(&drm_minor_lock, flags);
31624edb884SFrançois Tigeot 	idr_replace(&drm_minors_idr, minor, minor->index);
31724edb884SFrançois Tigeot 	spin_unlock_irqrestore(&drm_minor_lock, flags);
31824edb884SFrançois Tigeot 
31924edb884SFrançois Tigeot 	DRM_DEBUG("new minor registered %d\n", minor->index);
32024edb884SFrançois Tigeot 	return 0;
32124edb884SFrançois Tigeot 
32224edb884SFrançois Tigeot err_debugfs:
32324edb884SFrançois Tigeot 	drm_debugfs_cleanup(minor);
32424edb884SFrançois Tigeot 	return ret;
32524edb884SFrançois Tigeot }
32624edb884SFrançois Tigeot 
32724edb884SFrançois Tigeot static void drm_minor_unregister(struct drm_device *dev, unsigned int type)
32824edb884SFrançois Tigeot {
32924edb884SFrançois Tigeot 	struct drm_minor *minor;
33024edb884SFrançois Tigeot 	unsigned long flags;
33124edb884SFrançois Tigeot 
33224edb884SFrançois Tigeot 	minor = *drm_minor_get_slot(dev, type);
33324edb884SFrançois Tigeot 	if (!minor || !device_is_registered(minor->kdev))
33424edb884SFrançois Tigeot 		return;
33524edb884SFrançois Tigeot 
33624edb884SFrançois Tigeot 	/* replace @minor with NULL so lookups will fail from now on */
33724edb884SFrançois Tigeot 	spin_lock_irqsave(&drm_minor_lock, flags);
33824edb884SFrançois Tigeot 	idr_replace(&drm_minors_idr, NULL, minor->index);
33924edb884SFrançois Tigeot 	spin_unlock_irqrestore(&drm_minor_lock, flags);
34024edb884SFrançois Tigeot 
34124edb884SFrançois Tigeot 	device_del(minor->kdev);
34224edb884SFrançois Tigeot 	dev_set_drvdata(minor->kdev, NULL); /* safety belt */
34324edb884SFrançois Tigeot 	drm_debugfs_cleanup(minor);
34424edb884SFrançois Tigeot }
34524edb884SFrançois Tigeot 
34624edb884SFrançois Tigeot /**
34724edb884SFrançois Tigeot  * drm_minor_acquire - Acquire a DRM minor
34824edb884SFrançois Tigeot  * @minor_id: Minor ID of the DRM-minor
34924edb884SFrançois Tigeot  *
35024edb884SFrançois Tigeot  * Looks up the given minor-ID and returns the respective DRM-minor object. The
35124edb884SFrançois Tigeot  * refence-count of the underlying device is increased so you must release this
35224edb884SFrançois Tigeot  * object with drm_minor_release().
35324edb884SFrançois Tigeot  *
35424edb884SFrançois Tigeot  * As long as you hold this minor, it is guaranteed that the object and the
35524edb884SFrançois Tigeot  * minor->dev pointer will stay valid! However, the device may get unplugged and
35624edb884SFrançois Tigeot  * unregistered while you hold the minor.
35724edb884SFrançois Tigeot  *
35824edb884SFrançois Tigeot  * Returns:
35924edb884SFrançois Tigeot  * Pointer to minor-object with increased device-refcount, or PTR_ERR on
36024edb884SFrançois Tigeot  * failure.
36124edb884SFrançois Tigeot  */
36224edb884SFrançois Tigeot struct drm_minor *drm_minor_acquire(unsigned int minor_id)
36324edb884SFrançois Tigeot {
36424edb884SFrançois Tigeot 	struct drm_minor *minor;
36524edb884SFrançois Tigeot 	unsigned long flags;
36624edb884SFrançois Tigeot 
36724edb884SFrançois Tigeot 	spin_lock_irqsave(&drm_minor_lock, flags);
36824edb884SFrançois Tigeot 	minor = idr_find(&drm_minors_idr, minor_id);
36924edb884SFrançois Tigeot 	if (minor)
37024edb884SFrançois Tigeot 		drm_dev_ref(minor->dev);
37124edb884SFrançois Tigeot 	spin_unlock_irqrestore(&drm_minor_lock, flags);
37224edb884SFrançois Tigeot 
37324edb884SFrançois Tigeot 	if (!minor) {
37424edb884SFrançois Tigeot 		return ERR_PTR(-ENODEV);
37524edb884SFrançois Tigeot 	} else if (drm_device_is_unplugged(minor->dev)) {
37624edb884SFrançois Tigeot 		drm_dev_unref(minor->dev);
37724edb884SFrançois Tigeot 		return ERR_PTR(-ENODEV);
37824edb884SFrançois Tigeot 	}
37924edb884SFrançois Tigeot 
38024edb884SFrançois Tigeot 	return minor;
38124edb884SFrançois Tigeot }
38224edb884SFrançois Tigeot 
38324edb884SFrançois Tigeot /**
38424edb884SFrançois Tigeot  * drm_minor_release - Release DRM minor
38524edb884SFrançois Tigeot  * @minor: Pointer to DRM minor object
38624edb884SFrançois Tigeot  *
38724edb884SFrançois Tigeot  * Release a minor that was previously acquired via drm_minor_acquire().
38824edb884SFrançois Tigeot  */
38924edb884SFrançois Tigeot void drm_minor_release(struct drm_minor *minor)
39024edb884SFrançois Tigeot {
39124edb884SFrançois Tigeot 	drm_dev_unref(minor->dev);
39224edb884SFrançois Tigeot }
39324edb884SFrançois Tigeot 
39424edb884SFrançois Tigeot /**
39524edb884SFrançois Tigeot  * drm_put_dev - Unregister and release a DRM device
39624edb884SFrançois Tigeot  * @dev: DRM device
39724edb884SFrançois Tigeot  *
39824edb884SFrançois Tigeot  * Called at module unload time or when a PCI device is unplugged.
39924edb884SFrançois Tigeot  *
40024edb884SFrançois Tigeot  * Use of this function is discouraged. It will eventually go away completely.
40124edb884SFrançois Tigeot  * Please use drm_dev_unregister() and drm_dev_unref() explicitly instead.
40224edb884SFrançois Tigeot  *
40324edb884SFrançois Tigeot  * Cleans up all DRM device, calling drm_lastclose().
40424edb884SFrançois Tigeot  */
40524edb884SFrançois Tigeot void drm_put_dev(struct drm_device *dev)
40624edb884SFrançois Tigeot {
40724edb884SFrançois Tigeot 	DRM_DEBUG("\n");
40824edb884SFrançois Tigeot 
40924edb884SFrançois Tigeot 	if (!dev) {
41024edb884SFrançois Tigeot 		DRM_ERROR("cleanup called no dev\n");
41124edb884SFrançois Tigeot 		return;
41224edb884SFrançois Tigeot 	}
41324edb884SFrançois Tigeot 
41424edb884SFrançois Tigeot 	drm_dev_unregister(dev);
41524edb884SFrançois Tigeot 	drm_dev_unref(dev);
41624edb884SFrançois Tigeot }
41724edb884SFrançois Tigeot EXPORT_SYMBOL(drm_put_dev);
41824edb884SFrançois Tigeot 
41924edb884SFrançois Tigeot void drm_unplug_dev(struct drm_device *dev)
42024edb884SFrançois Tigeot {
42124edb884SFrançois Tigeot 	/* for a USB device */
42224edb884SFrançois Tigeot 	drm_minor_unregister(dev, DRM_MINOR_LEGACY);
42324edb884SFrançois Tigeot 	drm_minor_unregister(dev, DRM_MINOR_RENDER);
42424edb884SFrançois Tigeot 	drm_minor_unregister(dev, DRM_MINOR_CONTROL);
42524edb884SFrançois Tigeot 
42624edb884SFrançois Tigeot 	mutex_lock(&drm_global_mutex);
42724edb884SFrançois Tigeot 
42824edb884SFrançois Tigeot 	drm_device_set_unplugged(dev);
42924edb884SFrançois Tigeot 
43024edb884SFrançois Tigeot 	if (dev->open_count == 0) {
43124edb884SFrançois Tigeot 		drm_put_dev(dev);
43224edb884SFrançois Tigeot 	}
43324edb884SFrançois Tigeot 	mutex_unlock(&drm_global_mutex);
43424edb884SFrançois Tigeot }
43524edb884SFrançois Tigeot EXPORT_SYMBOL(drm_unplug_dev);
43624edb884SFrançois Tigeot 
43724edb884SFrançois Tigeot /*
43824edb884SFrançois Tigeot  * DRM internal mount
43924edb884SFrançois Tigeot  * We want to be able to allocate our own "struct address_space" to control
44024edb884SFrançois Tigeot  * memory-mappings in VRAM (or stolen RAM, ...). However, core MM does not allow
44124edb884SFrançois Tigeot  * stand-alone address_space objects, so we need an underlying inode. As there
44224edb884SFrançois Tigeot  * is no way to allocate an independent inode easily, we need a fake internal
44324edb884SFrançois Tigeot  * VFS mount-point.
44424edb884SFrançois Tigeot  *
44524edb884SFrançois Tigeot  * The drm_fs_inode_new() function allocates a new inode, drm_fs_inode_free()
44624edb884SFrançois Tigeot  * frees it again. You are allowed to use iget() and iput() to get references to
44724edb884SFrançois Tigeot  * the inode. But each drm_fs_inode_new() call must be paired with exactly one
44824edb884SFrançois Tigeot  * drm_fs_inode_free() call (which does not have to be the last iput()).
44924edb884SFrançois Tigeot  * We use drm_fs_inode_*() to manage our internal VFS mount-point and share it
45024edb884SFrançois Tigeot  * between multiple inode-users. You could, technically, call
45124edb884SFrançois Tigeot  * iget() + drm_fs_inode_free() directly after alloc and sometime later do an
45224edb884SFrançois Tigeot  * iput(), but this way you'd end up with a new vfsmount for each inode.
45324edb884SFrançois Tigeot  */
45424edb884SFrançois Tigeot 
45524edb884SFrançois Tigeot static int drm_fs_cnt;
45624edb884SFrançois Tigeot static struct vfsmount *drm_fs_mnt;
45724edb884SFrançois Tigeot 
45824edb884SFrançois Tigeot static const struct dentry_operations drm_fs_dops = {
45924edb884SFrançois Tigeot 	.d_dname	= simple_dname,
46024edb884SFrançois Tigeot };
46124edb884SFrançois Tigeot 
46224edb884SFrançois Tigeot static const struct super_operations drm_fs_sops = {
46324edb884SFrançois Tigeot 	.statfs		= simple_statfs,
46424edb884SFrançois Tigeot };
46524edb884SFrançois Tigeot 
46624edb884SFrançois Tigeot static struct dentry *drm_fs_mount(struct file_system_type *fs_type, int flags,
46724edb884SFrançois Tigeot 				   const char *dev_name, void *data)
46824edb884SFrançois Tigeot {
46924edb884SFrançois Tigeot 	return mount_pseudo(fs_type,
47024edb884SFrançois Tigeot 			    "drm:",
47124edb884SFrançois Tigeot 			    &drm_fs_sops,
47224edb884SFrançois Tigeot 			    &drm_fs_dops,
47324edb884SFrançois Tigeot 			    0x010203ff);
47424edb884SFrançois Tigeot }
47524edb884SFrançois Tigeot 
47624edb884SFrançois Tigeot static struct file_system_type drm_fs_type = {
47724edb884SFrançois Tigeot 	.name		= "drm",
47824edb884SFrançois Tigeot 	.owner		= THIS_MODULE,
47924edb884SFrançois Tigeot 	.mount		= drm_fs_mount,
48024edb884SFrançois Tigeot 	.kill_sb	= kill_anon_super,
48124edb884SFrançois Tigeot };
48224edb884SFrançois Tigeot 
48324edb884SFrançois Tigeot static struct inode *drm_fs_inode_new(void)
48424edb884SFrançois Tigeot {
48524edb884SFrançois Tigeot 	struct inode *inode;
48624edb884SFrançois Tigeot 	int r;
48724edb884SFrançois Tigeot 
48824edb884SFrançois Tigeot 	r = simple_pin_fs(&drm_fs_type, &drm_fs_mnt, &drm_fs_cnt);
48924edb884SFrançois Tigeot 	if (r < 0) {
49024edb884SFrançois Tigeot 		DRM_ERROR("Cannot mount pseudo fs: %d\n", r);
49124edb884SFrançois Tigeot 		return ERR_PTR(r);
49224edb884SFrançois Tigeot 	}
49324edb884SFrançois Tigeot 
49424edb884SFrançois Tigeot 	inode = alloc_anon_inode(drm_fs_mnt->mnt_sb);
49524edb884SFrançois Tigeot 	if (IS_ERR(inode))
49624edb884SFrançois Tigeot 		simple_release_fs(&drm_fs_mnt, &drm_fs_cnt);
49724edb884SFrançois Tigeot 
49824edb884SFrançois Tigeot 	return inode;
49924edb884SFrançois Tigeot }
50024edb884SFrançois Tigeot 
50124edb884SFrançois Tigeot static void drm_fs_inode_free(struct inode *inode)
50224edb884SFrançois Tigeot {
50324edb884SFrançois Tigeot 	if (inode) {
50424edb884SFrançois Tigeot 		iput(inode);
50524edb884SFrançois Tigeot 		simple_release_fs(&drm_fs_mnt, &drm_fs_cnt);
50624edb884SFrançois Tigeot 	}
50724edb884SFrançois Tigeot }
50824edb884SFrançois Tigeot 
50924edb884SFrançois Tigeot /**
51024edb884SFrançois Tigeot  * drm_dev_alloc - Allocate new DRM device
51124edb884SFrançois Tigeot  * @driver: DRM driver to allocate device for
51224edb884SFrançois Tigeot  * @parent: Parent device object
51324edb884SFrançois Tigeot  *
51424edb884SFrançois Tigeot  * Allocate and initialize a new DRM device. No device registration is done.
51524edb884SFrançois Tigeot  * Call drm_dev_register() to advertice the device to user space and register it
51624edb884SFrançois Tigeot  * with other core subsystems.
51724edb884SFrançois Tigeot  *
51824edb884SFrançois Tigeot  * The initial ref-count of the object is 1. Use drm_dev_ref() and
51924edb884SFrançois Tigeot  * drm_dev_unref() to take and drop further ref-counts.
52024edb884SFrançois Tigeot  *
52124edb884SFrançois Tigeot  * RETURNS:
52224edb884SFrançois Tigeot  * Pointer to new DRM device, or NULL if out of memory.
52324edb884SFrançois Tigeot  */
52424edb884SFrançois Tigeot struct drm_device *drm_dev_alloc(struct drm_driver *driver,
52524edb884SFrançois Tigeot 				 struct device *parent)
52624edb884SFrançois Tigeot {
52724edb884SFrançois Tigeot 	struct drm_device *dev;
52824edb884SFrançois Tigeot 	int ret;
52924edb884SFrançois Tigeot 
53024edb884SFrançois Tigeot 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
53124edb884SFrançois Tigeot 	if (!dev)
53224edb884SFrançois Tigeot 		return NULL;
53324edb884SFrançois Tigeot 
53424edb884SFrançois Tigeot 	kref_init(&dev->ref);
53524edb884SFrançois Tigeot 	dev->dev = parent;
53624edb884SFrançois Tigeot 	dev->driver = driver;
53724edb884SFrançois Tigeot 
53824edb884SFrançois Tigeot 	INIT_LIST_HEAD(&dev->filelist);
53924edb884SFrançois Tigeot 	INIT_LIST_HEAD(&dev->ctxlist);
54024edb884SFrançois Tigeot 	INIT_LIST_HEAD(&dev->vmalist);
54124edb884SFrançois Tigeot 	INIT_LIST_HEAD(&dev->maplist);
54224edb884SFrançois Tigeot 	INIT_LIST_HEAD(&dev->vblank_event_list);
54324edb884SFrançois Tigeot 
54424edb884SFrançois Tigeot 	spin_lock_init(&dev->buf_lock);
54524edb884SFrançois Tigeot 	spin_lock_init(&dev->event_lock);
54624edb884SFrançois Tigeot 	mutex_init(&dev->struct_mutex);
54724edb884SFrançois Tigeot 	mutex_init(&dev->ctxlist_mutex);
54824edb884SFrançois Tigeot 	mutex_init(&dev->master_mutex);
54924edb884SFrançois Tigeot 
55024edb884SFrançois Tigeot 	dev->anon_inode = drm_fs_inode_new();
55124edb884SFrançois Tigeot 	if (IS_ERR(dev->anon_inode)) {
55224edb884SFrançois Tigeot 		ret = PTR_ERR(dev->anon_inode);
55324edb884SFrançois Tigeot 		DRM_ERROR("Cannot allocate anonymous inode: %d\n", ret);
55424edb884SFrançois Tigeot 		goto err_free;
55524edb884SFrançois Tigeot 	}
55624edb884SFrançois Tigeot 
55724edb884SFrançois Tigeot 	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
55824edb884SFrançois Tigeot 		ret = drm_minor_alloc(dev, DRM_MINOR_CONTROL);
55924edb884SFrançois Tigeot 		if (ret)
56024edb884SFrançois Tigeot 			goto err_minors;
56124edb884SFrançois Tigeot 	}
56224edb884SFrançois Tigeot 
56324edb884SFrançois Tigeot 	if (drm_core_check_feature(dev, DRIVER_RENDER)) {
56424edb884SFrançois Tigeot 		ret = drm_minor_alloc(dev, DRM_MINOR_RENDER);
56524edb884SFrançois Tigeot 		if (ret)
56624edb884SFrançois Tigeot 			goto err_minors;
56724edb884SFrançois Tigeot 	}
56824edb884SFrançois Tigeot 
56924edb884SFrançois Tigeot 	ret = drm_minor_alloc(dev, DRM_MINOR_LEGACY);
57024edb884SFrançois Tigeot 	if (ret)
57124edb884SFrançois Tigeot 		goto err_minors;
57224edb884SFrançois Tigeot 
57324edb884SFrançois Tigeot 	if (drm_ht_create(&dev->map_hash, 12))
57424edb884SFrançois Tigeot 		goto err_minors;
57524edb884SFrançois Tigeot 
57624edb884SFrançois Tigeot 	ret = drm_legacy_ctxbitmap_init(dev);
57724edb884SFrançois Tigeot 	if (ret) {
57824edb884SFrançois Tigeot 		DRM_ERROR("Cannot allocate memory for context bitmap.\n");
57924edb884SFrançois Tigeot 		goto err_ht;
58024edb884SFrançois Tigeot 	}
58124edb884SFrançois Tigeot 
582*1b13d190SFrançois Tigeot 	if (drm_core_check_feature(dev, DRIVER_GEM)) {
58324edb884SFrançois Tigeot 		ret = drm_gem_init(dev);
58424edb884SFrançois Tigeot 		if (ret) {
58524edb884SFrançois Tigeot 			DRM_ERROR("Cannot initialize graphics execution manager (GEM)\n");
58624edb884SFrançois Tigeot 			goto err_ctxbitmap;
58724edb884SFrançois Tigeot 		}
58824edb884SFrançois Tigeot 	}
58924edb884SFrançois Tigeot 
59024edb884SFrançois Tigeot 	return dev;
59124edb884SFrançois Tigeot 
59224edb884SFrançois Tigeot err_ctxbitmap:
59324edb884SFrançois Tigeot 	drm_legacy_ctxbitmap_cleanup(dev);
59424edb884SFrançois Tigeot err_ht:
59524edb884SFrançois Tigeot 	drm_ht_remove(&dev->map_hash);
59624edb884SFrançois Tigeot err_minors:
59724edb884SFrançois Tigeot 	drm_minor_free(dev, DRM_MINOR_LEGACY);
59824edb884SFrançois Tigeot 	drm_minor_free(dev, DRM_MINOR_RENDER);
59924edb884SFrançois Tigeot 	drm_minor_free(dev, DRM_MINOR_CONTROL);
60024edb884SFrançois Tigeot 	drm_fs_inode_free(dev->anon_inode);
60124edb884SFrançois Tigeot err_free:
60224edb884SFrançois Tigeot 	mutex_destroy(&dev->master_mutex);
60324edb884SFrançois Tigeot 	kfree(dev);
60424edb884SFrançois Tigeot 	return NULL;
60524edb884SFrançois Tigeot }
60624edb884SFrançois Tigeot EXPORT_SYMBOL(drm_dev_alloc);
60724edb884SFrançois Tigeot 
60824edb884SFrançois Tigeot static void drm_dev_release(struct kref *ref)
60924edb884SFrançois Tigeot {
61024edb884SFrançois Tigeot 	struct drm_device *dev = container_of(ref, struct drm_device, ref);
61124edb884SFrançois Tigeot 
612*1b13d190SFrançois Tigeot 	if (drm_core_check_feature(dev, DRIVER_GEM))
61324edb884SFrançois Tigeot 		drm_gem_destroy(dev);
61424edb884SFrançois Tigeot 
61524edb884SFrançois Tigeot 	drm_legacy_ctxbitmap_cleanup(dev);
61624edb884SFrançois Tigeot 	drm_ht_remove(&dev->map_hash);
61724edb884SFrançois Tigeot 	drm_fs_inode_free(dev->anon_inode);
61824edb884SFrançois Tigeot 
61924edb884SFrançois Tigeot 	drm_minor_free(dev, DRM_MINOR_LEGACY);
62024edb884SFrançois Tigeot 	drm_minor_free(dev, DRM_MINOR_RENDER);
62124edb884SFrançois Tigeot 	drm_minor_free(dev, DRM_MINOR_CONTROL);
62224edb884SFrançois Tigeot 
62324edb884SFrançois Tigeot 	mutex_destroy(&dev->master_mutex);
62424edb884SFrançois Tigeot 	kfree(dev->unique);
62524edb884SFrançois Tigeot 	kfree(dev);
62624edb884SFrançois Tigeot }
62724edb884SFrançois Tigeot 
62824edb884SFrançois Tigeot /**
62924edb884SFrançois Tigeot  * drm_dev_ref - Take reference of a DRM device
63024edb884SFrançois Tigeot  * @dev: device to take reference of or NULL
63124edb884SFrançois Tigeot  *
63224edb884SFrançois Tigeot  * This increases the ref-count of @dev by one. You *must* already own a
63324edb884SFrançois Tigeot  * reference when calling this. Use drm_dev_unref() to drop this reference
63424edb884SFrançois Tigeot  * again.
63524edb884SFrançois Tigeot  *
63624edb884SFrançois Tigeot  * This function never fails. However, this function does not provide *any*
63724edb884SFrançois Tigeot  * guarantee whether the device is alive or running. It only provides a
63824edb884SFrançois Tigeot  * reference to the object and the memory associated with it.
63924edb884SFrançois Tigeot  */
64024edb884SFrançois Tigeot void drm_dev_ref(struct drm_device *dev)
64124edb884SFrançois Tigeot {
64224edb884SFrançois Tigeot 	if (dev)
64324edb884SFrançois Tigeot 		kref_get(&dev->ref);
64424edb884SFrançois Tigeot }
64524edb884SFrançois Tigeot EXPORT_SYMBOL(drm_dev_ref);
64624edb884SFrançois Tigeot 
64724edb884SFrançois Tigeot /**
64824edb884SFrançois Tigeot  * drm_dev_unref - Drop reference of a DRM device
64924edb884SFrançois Tigeot  * @dev: device to drop reference of or NULL
65024edb884SFrançois Tigeot  *
65124edb884SFrançois Tigeot  * This decreases the ref-count of @dev by one. The device is destroyed if the
65224edb884SFrançois Tigeot  * ref-count drops to zero.
65324edb884SFrançois Tigeot  */
65424edb884SFrançois Tigeot void drm_dev_unref(struct drm_device *dev)
65524edb884SFrançois Tigeot {
65624edb884SFrançois Tigeot 	if (dev)
65724edb884SFrançois Tigeot 		kref_put(&dev->ref, drm_dev_release);
65824edb884SFrançois Tigeot }
65924edb884SFrançois Tigeot EXPORT_SYMBOL(drm_dev_unref);
66024edb884SFrançois Tigeot 
66124edb884SFrançois Tigeot /**
66224edb884SFrançois Tigeot  * drm_dev_register - Register DRM device
66324edb884SFrançois Tigeot  * @dev: Device to register
66424edb884SFrançois Tigeot  * @flags: Flags passed to the driver's .load() function
66524edb884SFrançois Tigeot  *
66624edb884SFrançois Tigeot  * Register the DRM device @dev with the system, advertise device to user-space
66724edb884SFrançois Tigeot  * and start normal device operation. @dev must be allocated via drm_dev_alloc()
66824edb884SFrançois Tigeot  * previously.
66924edb884SFrançois Tigeot  *
67024edb884SFrançois Tigeot  * Never call this twice on any device!
67124edb884SFrançois Tigeot  *
67224edb884SFrançois Tigeot  * RETURNS:
67324edb884SFrançois Tigeot  * 0 on success, negative error code on failure.
67424edb884SFrançois Tigeot  */
67524edb884SFrançois Tigeot int drm_dev_register(struct drm_device *dev, unsigned long flags)
67624edb884SFrançois Tigeot {
67724edb884SFrançois Tigeot 	int ret;
67824edb884SFrançois Tigeot 
67924edb884SFrançois Tigeot 	mutex_lock(&drm_global_mutex);
68024edb884SFrançois Tigeot 
68124edb884SFrançois Tigeot 	ret = drm_minor_register(dev, DRM_MINOR_CONTROL);
68224edb884SFrançois Tigeot 	if (ret)
68324edb884SFrançois Tigeot 		goto err_minors;
68424edb884SFrançois Tigeot 
68524edb884SFrançois Tigeot 	ret = drm_minor_register(dev, DRM_MINOR_RENDER);
68624edb884SFrançois Tigeot 	if (ret)
68724edb884SFrançois Tigeot 		goto err_minors;
68824edb884SFrançois Tigeot 
68924edb884SFrançois Tigeot 	ret = drm_minor_register(dev, DRM_MINOR_LEGACY);
69024edb884SFrançois Tigeot 	if (ret)
69124edb884SFrançois Tigeot 		goto err_minors;
69224edb884SFrançois Tigeot 
69324edb884SFrançois Tigeot 	if (dev->driver->load) {
69424edb884SFrançois Tigeot 		ret = dev->driver->load(dev, flags);
69524edb884SFrançois Tigeot 		if (ret)
69624edb884SFrançois Tigeot 			goto err_minors;
69724edb884SFrançois Tigeot 	}
69824edb884SFrançois Tigeot 
69924edb884SFrançois Tigeot 	/* setup grouping for legacy outputs */
70024edb884SFrançois Tigeot 	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
70124edb884SFrançois Tigeot 		ret = drm_mode_group_init_legacy_group(dev,
70224edb884SFrançois Tigeot 				&dev->primary->mode_group);
70324edb884SFrançois Tigeot 		if (ret)
70424edb884SFrançois Tigeot 			goto err_unload;
70524edb884SFrançois Tigeot 	}
70624edb884SFrançois Tigeot 
70724edb884SFrançois Tigeot 	ret = 0;
70824edb884SFrançois Tigeot 	goto out_unlock;
70924edb884SFrançois Tigeot 
71024edb884SFrançois Tigeot err_unload:
71124edb884SFrançois Tigeot 	if (dev->driver->unload)
71224edb884SFrançois Tigeot 		dev->driver->unload(dev);
71324edb884SFrançois Tigeot err_minors:
71424edb884SFrançois Tigeot 	drm_minor_unregister(dev, DRM_MINOR_LEGACY);
71524edb884SFrançois Tigeot 	drm_minor_unregister(dev, DRM_MINOR_RENDER);
71624edb884SFrançois Tigeot 	drm_minor_unregister(dev, DRM_MINOR_CONTROL);
71724edb884SFrançois Tigeot out_unlock:
71824edb884SFrançois Tigeot 	mutex_unlock(&drm_global_mutex);
71924edb884SFrançois Tigeot 	return ret;
72024edb884SFrançois Tigeot }
72124edb884SFrançois Tigeot EXPORT_SYMBOL(drm_dev_register);
72224edb884SFrançois Tigeot 
72324edb884SFrançois Tigeot /**
72424edb884SFrançois Tigeot  * drm_dev_unregister - Unregister DRM device
72524edb884SFrançois Tigeot  * @dev: Device to unregister
72624edb884SFrançois Tigeot  *
72724edb884SFrançois Tigeot  * Unregister the DRM device from the system. This does the reverse of
72824edb884SFrançois Tigeot  * drm_dev_register() but does not deallocate the device. The caller must call
72924edb884SFrançois Tigeot  * drm_dev_unref() to drop their final reference.
73024edb884SFrançois Tigeot  */
73124edb884SFrançois Tigeot void drm_dev_unregister(struct drm_device *dev)
73224edb884SFrançois Tigeot {
73324edb884SFrançois Tigeot 	struct drm_map_list *r_list, *list_temp;
73424edb884SFrançois Tigeot 
73524edb884SFrançois Tigeot 	drm_lastclose(dev);
73624edb884SFrançois Tigeot 
73724edb884SFrançois Tigeot 	if (dev->driver->unload)
73824edb884SFrançois Tigeot 		dev->driver->unload(dev);
73924edb884SFrançois Tigeot 
74024edb884SFrançois Tigeot 	if (dev->agp)
74124edb884SFrançois Tigeot 		drm_pci_agp_destroy(dev);
74224edb884SFrançois Tigeot 
74324edb884SFrançois Tigeot 	drm_vblank_cleanup(dev);
74424edb884SFrançois Tigeot 
74524edb884SFrançois Tigeot 	list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head)
746*1b13d190SFrançois Tigeot 		drm_legacy_rmmap(dev, r_list->map);
74724edb884SFrançois Tigeot 
74824edb884SFrançois Tigeot 	drm_minor_unregister(dev, DRM_MINOR_LEGACY);
74924edb884SFrançois Tigeot 	drm_minor_unregister(dev, DRM_MINOR_RENDER);
75024edb884SFrançois Tigeot 	drm_minor_unregister(dev, DRM_MINOR_CONTROL);
75124edb884SFrançois Tigeot }
75224edb884SFrançois Tigeot EXPORT_SYMBOL(drm_dev_unregister);
75324edb884SFrançois Tigeot 
75424edb884SFrançois Tigeot /**
75524edb884SFrançois Tigeot  * drm_dev_set_unique - Set the unique name of a DRM device
75624edb884SFrançois Tigeot  * @dev: device of which to set the unique name
75724edb884SFrançois Tigeot  * @fmt: format string for unique name
75824edb884SFrançois Tigeot  *
75924edb884SFrançois Tigeot  * Sets the unique name of a DRM device using the specified format string and
76024edb884SFrançois Tigeot  * a variable list of arguments. Drivers can use this at driver probe time if
76124edb884SFrançois Tigeot  * the unique name of the devices they drive is static.
76224edb884SFrançois Tigeot  *
76324edb884SFrançois Tigeot  * Return: 0 on success or a negative error code on failure.
76424edb884SFrançois Tigeot  */
76524edb884SFrançois Tigeot int drm_dev_set_unique(struct drm_device *dev, const char *fmt, ...)
76624edb884SFrançois Tigeot {
76724edb884SFrançois Tigeot 	va_list ap;
76824edb884SFrançois Tigeot 
76924edb884SFrançois Tigeot 	kfree(dev->unique);
77024edb884SFrançois Tigeot 
77124edb884SFrançois Tigeot 	va_start(ap, fmt);
77224edb884SFrançois Tigeot 	dev->unique = kvasprintf(GFP_KERNEL, fmt, ap);
77324edb884SFrançois Tigeot 	va_end(ap);
77424edb884SFrançois Tigeot 
77524edb884SFrançois Tigeot 	return dev->unique ? 0 : -ENOMEM;
77624edb884SFrançois Tigeot }
77724edb884SFrançois Tigeot EXPORT_SYMBOL(drm_dev_set_unique);
77824edb884SFrançois Tigeot #endif
77924edb884SFrançois Tigeot 
78024edb884SFrançois Tigeot /*
78124edb884SFrançois Tigeot  * DRM Core
78224edb884SFrançois Tigeot  * The DRM core module initializes all global DRM objects and makes them
78324edb884SFrançois Tigeot  * available to drivers. Once setup, drivers can probe their respective
78424edb884SFrançois Tigeot  * devices.
78524edb884SFrançois Tigeot  * Currently, core management includes:
78624edb884SFrançois Tigeot  *  - The "DRM-Global" key/value database
78724edb884SFrançois Tigeot  *  - Global ID management for connectors
78824edb884SFrançois Tigeot  *  - DRM major number allocation
78924edb884SFrançois Tigeot  *  - DRM minor management
79024edb884SFrançois Tigeot  *  - DRM sysfs class
79124edb884SFrançois Tigeot  *  - DRM debugfs root
79224edb884SFrançois Tigeot  *
79324edb884SFrançois Tigeot  * Furthermore, the DRM core provides dynamic char-dev lookups. For each
79424edb884SFrançois Tigeot  * interface registered on a DRM device, you can request minor numbers from DRM
79524edb884SFrançois Tigeot  * core. DRM core takes care of major-number management and char-dev
79624edb884SFrançois Tigeot  * registration. A stub ->open() callback forwards any open() requests to the
79724edb884SFrançois Tigeot  * registered minor.
79824edb884SFrançois Tigeot  */
79924edb884SFrançois Tigeot 
80024edb884SFrançois Tigeot #if 0
80124edb884SFrançois Tigeot static int drm_stub_open(struct inode *inode, struct file *filp)
80224edb884SFrançois Tigeot {
80324edb884SFrançois Tigeot 	const struct file_operations *new_fops;
80424edb884SFrançois Tigeot 	struct drm_minor *minor;
80524edb884SFrançois Tigeot 	int err;
80624edb884SFrançois Tigeot 
80724edb884SFrançois Tigeot 	DRM_DEBUG("\n");
80824edb884SFrançois Tigeot 
80924edb884SFrançois Tigeot 	mutex_lock(&drm_global_mutex);
81024edb884SFrançois Tigeot 	minor = drm_minor_acquire(iminor(inode));
81124edb884SFrançois Tigeot 	if (IS_ERR(minor)) {
81224edb884SFrançois Tigeot 		err = PTR_ERR(minor);
81324edb884SFrançois Tigeot 		goto out_unlock;
81424edb884SFrançois Tigeot 	}
81524edb884SFrançois Tigeot 
81624edb884SFrançois Tigeot 	new_fops = fops_get(minor->dev->driver->fops);
81724edb884SFrançois Tigeot 	if (!new_fops) {
81824edb884SFrançois Tigeot 		err = -ENODEV;
81924edb884SFrançois Tigeot 		goto out_release;
82024edb884SFrançois Tigeot 	}
82124edb884SFrançois Tigeot 
82224edb884SFrançois Tigeot 	replace_fops(filp, new_fops);
82324edb884SFrançois Tigeot 	if (filp->f_op->open)
82424edb884SFrançois Tigeot 		err = filp->f_op->open(inode, filp);
82524edb884SFrançois Tigeot 	else
82624edb884SFrançois Tigeot 		err = 0;
82724edb884SFrançois Tigeot 
82824edb884SFrançois Tigeot out_release:
82924edb884SFrançois Tigeot 	drm_minor_release(minor);
83024edb884SFrançois Tigeot out_unlock:
83124edb884SFrançois Tigeot 	mutex_unlock(&drm_global_mutex);
83224edb884SFrançois Tigeot 	return err;
83324edb884SFrançois Tigeot }
83424edb884SFrançois Tigeot 
83524edb884SFrançois Tigeot static const struct file_operations drm_stub_fops = {
83624edb884SFrançois Tigeot 	.owner = THIS_MODULE,
83724edb884SFrançois Tigeot 	.open = drm_stub_open,
83824edb884SFrançois Tigeot 	.llseek = noop_llseek,
83924edb884SFrançois Tigeot };
84024edb884SFrançois Tigeot 
84124edb884SFrançois Tigeot static int __init drm_core_init(void)
84224edb884SFrançois Tigeot {
84324edb884SFrançois Tigeot 	int ret = -ENOMEM;
84424edb884SFrançois Tigeot 
84524edb884SFrançois Tigeot 	drm_global_init();
84624edb884SFrançois Tigeot 	drm_connector_ida_init();
84724edb884SFrançois Tigeot 	idr_init(&drm_minors_idr);
84824edb884SFrançois Tigeot 
84924edb884SFrançois Tigeot 	if (register_chrdev(DRM_MAJOR, "drm", &drm_stub_fops))
85024edb884SFrançois Tigeot 		goto err_p1;
85124edb884SFrançois Tigeot 
85224edb884SFrançois Tigeot 	drm_class = drm_sysfs_create(THIS_MODULE, "drm");
85324edb884SFrançois Tigeot 	if (IS_ERR(drm_class)) {
85424edb884SFrançois Tigeot 		printk(KERN_ERR "DRM: Error creating drm class.\n");
85524edb884SFrançois Tigeot 		ret = PTR_ERR(drm_class);
85624edb884SFrançois Tigeot 		goto err_p2;
85724edb884SFrançois Tigeot 	}
85824edb884SFrançois Tigeot 
85924edb884SFrançois Tigeot 	drm_debugfs_root = debugfs_create_dir("dri", NULL);
86024edb884SFrançois Tigeot 	if (!drm_debugfs_root) {
86124edb884SFrançois Tigeot 		DRM_ERROR("Cannot create /sys/kernel/debug/dri\n");
86224edb884SFrançois Tigeot 		ret = -1;
86324edb884SFrançois Tigeot 		goto err_p3;
86424edb884SFrançois Tigeot 	}
86524edb884SFrançois Tigeot 
86624edb884SFrançois Tigeot 	DRM_INFO("Initialized %s %d.%d.%d %s\n",
86724edb884SFrançois Tigeot 		 CORE_NAME, CORE_MAJOR, CORE_MINOR, CORE_PATCHLEVEL, CORE_DATE);
86824edb884SFrançois Tigeot 	return 0;
86924edb884SFrançois Tigeot err_p3:
87024edb884SFrançois Tigeot 	drm_sysfs_destroy();
87124edb884SFrançois Tigeot err_p2:
87224edb884SFrançois Tigeot 	unregister_chrdev(DRM_MAJOR, "drm");
87324edb884SFrançois Tigeot 
87424edb884SFrançois Tigeot 	idr_destroy(&drm_minors_idr);
87524edb884SFrançois Tigeot err_p1:
87624edb884SFrançois Tigeot 	return ret;
87724edb884SFrançois Tigeot }
87824edb884SFrançois Tigeot 
87924edb884SFrançois Tigeot static void __exit drm_core_exit(void)
88024edb884SFrançois Tigeot {
88124edb884SFrançois Tigeot 	debugfs_remove(drm_debugfs_root);
88224edb884SFrançois Tigeot 	drm_sysfs_destroy();
88324edb884SFrançois Tigeot 
88424edb884SFrançois Tigeot 	unregister_chrdev(DRM_MAJOR, "drm");
88524edb884SFrançois Tigeot 
88624edb884SFrançois Tigeot 	drm_connector_ida_destroy();
88724edb884SFrançois Tigeot 	idr_destroy(&drm_minors_idr);
88824edb884SFrançois Tigeot }
88924edb884SFrançois Tigeot 
89024edb884SFrançois Tigeot module_init(drm_core_init);
89124edb884SFrançois Tigeot module_exit(drm_core_exit);
89224edb884SFrançois Tigeot #endif
89324edb884SFrançois Tigeot 
89479f713b0SFrançois Tigeot #include <sys/devfs.h>
8955718399fSFrançois Tigeot 
8969edbd4a0SFrançois Tigeot #include <linux/export.h>
897be348e9fSFrançois Tigeot #include <linux/dmi.h>
89818e26a6dSFrançois Tigeot #include <drm/drmP.h>
89918e26a6dSFrançois Tigeot #include <drm/drm_core.h>
9007f3c3d6fSHasso Tepper 
90164fe1516Szrj #if DRM_DEBUG_DEFAULT_ON == 1
90264fe1516Szrj #define DRM_DEBUGBITS_ON (DRM_DEBUGBITS_DEBUG | DRM_DEBUGBITS_KMS | \
90364fe1516Szrj     DRM_DEBUGBITS_FAILED_IOCTL)
90464fe1516Szrj #elif DRM_DEBUG_DEFAULT_ON == 2
90564fe1516Szrj #define DRM_DEBUGBITS_ON (DRM_DEBUGBITS_DEBUG | DRM_DEBUGBITS_KMS | \
90664fe1516Szrj     DRM_DEBUGBITS_FAILED_IOCTL | DRM_DEBUGBITS_VERBOSE)
90779f713b0SFrançois Tigeot #else
90864fe1516Szrj #define DRM_DEBUGBITS_ON (0x0)
90979f713b0SFrançois Tigeot #endif
91064fe1516Szrj 
9115718399fSFrançois Tigeot int drm_notyet_flag = 0;
9125718399fSFrançois Tigeot 
913b3705d71SHasso Tepper static int drm_load(struct drm_device *dev);
9143260c067SFrançois Tigeot drm_pci_id_list_t *drm_find_description(int vendor, int device,
9157f3c3d6fSHasso Tepper     drm_pci_id_list_t *idlist);
9167f3c3d6fSHasso Tepper 
9177f3c3d6fSHasso Tepper #define DRIVER_SOFTC(unit) \
918b3705d71SHasso Tepper 	((struct drm_device *)devclass_get_softc(drm_devclass, unit))
9197f3c3d6fSHasso Tepper 
9205718399fSFrançois Tigeot static int
9215718399fSFrançois Tigeot drm_modevent(module_t mod, int type, void *data)
9225718399fSFrançois Tigeot {
9235718399fSFrançois Tigeot 
9245718399fSFrançois Tigeot 	switch (type) {
9255718399fSFrançois Tigeot 	case MOD_LOAD:
9261d5dd71dSFrançois Tigeot 		TUNABLE_INT_FETCH("drm.debug", &drm_debug);
9275718399fSFrançois Tigeot 		TUNABLE_INT_FETCH("drm.notyet", &drm_notyet_flag);
9285718399fSFrançois Tigeot 		break;
9295718399fSFrançois Tigeot 	}
9305718399fSFrançois Tigeot 	return (0);
9315718399fSFrançois Tigeot }
9325718399fSFrançois Tigeot 
9335718399fSFrançois Tigeot static moduledata_t drm_mod = {
9345718399fSFrançois Tigeot 	"drm",
9355718399fSFrançois Tigeot 	drm_modevent,
9365718399fSFrançois Tigeot 	0
9375718399fSFrançois Tigeot };
9385718399fSFrançois Tigeot DECLARE_MODULE(drm, drm_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
9397f3c3d6fSHasso Tepper MODULE_VERSION(drm, 1);
9407f3c3d6fSHasso Tepper MODULE_DEPEND(drm, agp, 1, 1, 1);
9417f3c3d6fSHasso Tepper MODULE_DEPEND(drm, pci, 1, 1, 1);
9425718399fSFrançois Tigeot MODULE_DEPEND(drm, iicbus, 1, 1, 1);
9437f3c3d6fSHasso Tepper 
94479f713b0SFrançois Tigeot static struct dev_ops drm_cdevsw = {
945d268c872SFrançois Tigeot 	{ "drm", 0, D_TRACKCLOSE | D_MPSAFE },
9467f3c3d6fSHasso Tepper 	.d_open =	drm_open,
9472c845b81SSimon Schubert 	.d_close =	drm_close,
9487f3c3d6fSHasso Tepper 	.d_read =	drm_read,
9497f3c3d6fSHasso Tepper 	.d_ioctl =	drm_ioctl,
9503694ee49SSamuel J. Greear 	.d_kqfilter =	drm_kqfilter,
9515718399fSFrançois Tigeot 	.d_mmap =	drm_mmap,
9525718399fSFrançois Tigeot 	.d_mmap_single = drm_mmap_single,
9537f3c3d6fSHasso Tepper };
9547f3c3d6fSHasso Tepper 
9554705af8fSMarkus Pfeiffer static int drm_msi = 0;	/* Disable by default. This is because there are issues with
9564705af8fSMarkus Pfeiffer 			   freezes using MSI and i915
9574705af8fSMarkus Pfeiffer 			 */
9584705af8fSMarkus Pfeiffer TUNABLE_INT("hw.drm.msi.enable", &drm_msi);
9595718399fSFrançois Tigeot SYSCTL_NODE(_hw, OID_AUTO, drm, CTLFLAG_RW, NULL, "DRM device");
9604705af8fSMarkus Pfeiffer SYSCTL_NODE(_hw_drm, OID_AUTO, msi, CTLFLAG_RW, NULL, "DRM device msi");
9614705af8fSMarkus Pfeiffer SYSCTL_INT(_hw_drm_msi, OID_AUTO, enable, CTLFLAG_RD, &drm_msi, 0,
9625718399fSFrançois Tigeot     "Enable MSI interrupts for drm devices");
96327a0f882SMatthew Dillon SYSCTL_INT(_hw_drm, OID_AUTO, debug, CTLFLAG_RW, &drm_debug, 0,
96427a0f882SMatthew Dillon     "DRM debugging");
965b3705d71SHasso Tepper 
966b3705d71SHasso Tepper static struct drm_msi_blacklist_entry drm_msi_blacklist[] = {
967b3705d71SHasso Tepper 	{0x8086, 0x2772}, /* Intel i945G	*/ \
968b3705d71SHasso Tepper 	{0x8086, 0x27A2}, /* Intel i945GM	*/ \
969b3705d71SHasso Tepper 	{0x8086, 0x27AE}, /* Intel i945GME	*/ \
970b3705d71SHasso Tepper 	{0, 0}
971b3705d71SHasso Tepper };
972b3705d71SHasso Tepper 
9736f486c69SFrançois Tigeot static int drm_msi_is_blacklisted(struct drm_device *dev, unsigned long flags)
974b3705d71SHasso Tepper {
975b3705d71SHasso Tepper 	int i = 0;
976b3705d71SHasso Tepper 
9776f486c69SFrançois Tigeot 	if (dev->driver->use_msi != NULL) {
9786f486c69SFrançois Tigeot 		int use_msi;
9796f486c69SFrançois Tigeot 
9806f486c69SFrançois Tigeot 		use_msi = dev->driver->use_msi(dev, flags);
9816f486c69SFrançois Tigeot 
9826f486c69SFrançois Tigeot 		return (!use_msi);
9836f486c69SFrançois Tigeot 	}
9846f486c69SFrançois Tigeot 
9856f486c69SFrançois Tigeot 	/* TODO: Maybe move this to a callback in i915? */
986b3705d71SHasso Tepper 	for (i = 0; drm_msi_blacklist[i].vendor != 0; i++) {
9876f486c69SFrançois Tigeot 		if ((drm_msi_blacklist[i].vendor == dev->pci_vendor) &&
9886f486c69SFrançois Tigeot 		    (drm_msi_blacklist[i].device == dev->pci_device)) {
989b3705d71SHasso Tepper 			return 1;
990b3705d71SHasso Tepper 		}
991b3705d71SHasso Tepper 	}
992b3705d71SHasso Tepper 
993b3705d71SHasso Tepper 	return 0;
994b3705d71SHasso Tepper }
995b3705d71SHasso Tepper 
996b3705d71SHasso Tepper int drm_probe(device_t kdev, drm_pci_id_list_t *idlist)
9977f3c3d6fSHasso Tepper {
9987f3c3d6fSHasso Tepper 	drm_pci_id_list_t *id_entry;
9997f3c3d6fSHasso Tepper 	int vendor, device;
10007f3c3d6fSHasso Tepper 
100131935f45SSepherosa Ziehau 	vendor = pci_get_vendor(kdev);
100231935f45SSepherosa Ziehau 	device = pci_get_device(kdev);
1003b3705d71SHasso Tepper 
10045718399fSFrançois Tigeot 	if (pci_get_class(kdev) != PCIC_DISPLAY)
1005b3705d71SHasso Tepper 		return ENXIO;
10067f3c3d6fSHasso Tepper 
10077f3c3d6fSHasso Tepper 	id_entry = drm_find_description(vendor, device, idlist);
10087f3c3d6fSHasso Tepper 	if (id_entry != NULL) {
1009b3705d71SHasso Tepper 		if (!device_get_desc(kdev)) {
1010b3705d71SHasso Tepper 			DRM_DEBUG("desc : %s\n", device_get_desc(kdev));
1011b3705d71SHasso Tepper 			device_set_desc(kdev, id_entry->name);
1012b3705d71SHasso Tepper 		}
10137f3c3d6fSHasso Tepper 		return 0;
10147f3c3d6fSHasso Tepper 	}
10157f3c3d6fSHasso Tepper 
10167f3c3d6fSHasso Tepper 	return ENXIO;
10177f3c3d6fSHasso Tepper }
10187f3c3d6fSHasso Tepper 
1019b3705d71SHasso Tepper int drm_attach(device_t kdev, drm_pci_id_list_t *idlist)
10207f3c3d6fSHasso Tepper {
1021b3705d71SHasso Tepper 	struct drm_device *dev;
10227f3c3d6fSHasso Tepper 	drm_pci_id_list_t *id_entry;
10234705af8fSMarkus Pfeiffer 	int unit, error;
10244705af8fSMarkus Pfeiffer 	u_int irq_flags;
10254705af8fSMarkus Pfeiffer 	int msi_enable;
10267f3c3d6fSHasso Tepper 
1027b3705d71SHasso Tepper 	unit = device_get_unit(kdev);
1028b3705d71SHasso Tepper 	dev = device_get_softc(kdev);
10297f3c3d6fSHasso Tepper 
1030b3705d71SHasso Tepper 	if (!strcmp(device_get_name(kdev), "drmsub"))
10316df74fa7SFrançois Tigeot 		dev->dev = device_get_parent(kdev);
10327f3c3d6fSHasso Tepper 	else
10336df74fa7SFrançois Tigeot 		dev->dev = kdev;
1034b3705d71SHasso Tepper 
10356df74fa7SFrançois Tigeot 	dev->pci_domain = pci_get_domain(dev->dev);
10366df74fa7SFrançois Tigeot 	dev->pci_bus = pci_get_bus(dev->dev);
10376df74fa7SFrançois Tigeot 	dev->pci_slot = pci_get_slot(dev->dev);
10386df74fa7SFrançois Tigeot 	dev->pci_func = pci_get_function(dev->dev);
1039b3705d71SHasso Tepper 
10406df74fa7SFrançois Tigeot 	dev->pci_vendor = pci_get_vendor(dev->dev);
10416df74fa7SFrançois Tigeot 	dev->pci_device = pci_get_device(dev->dev);
10426df74fa7SFrançois Tigeot 	dev->pci_subvendor = pci_get_subvendor(dev->dev);
10436df74fa7SFrançois Tigeot 	dev->pci_subdevice = pci_get_subdevice(dev->dev);
10446f486c69SFrançois Tigeot 
10456f486c69SFrançois Tigeot 	id_entry = drm_find_description(dev->pci_vendor,
10466f486c69SFrançois Tigeot 	    dev->pci_device, idlist);
10476f486c69SFrançois Tigeot 	dev->id_entry = id_entry;
1048b3705d71SHasso Tepper 
1049bd121a8bSHasso Tepper 	if (drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) {
10504705af8fSMarkus Pfeiffer 		msi_enable = drm_msi;
1051b3705d71SHasso Tepper 
10524705af8fSMarkus Pfeiffer 		if (drm_msi_is_blacklisted(dev, dev->id_entry->driver_private)) {
10534705af8fSMarkus Pfeiffer 			msi_enable = 0;
1054b3705d71SHasso Tepper 		}
10554705af8fSMarkus Pfeiffer 
10564705af8fSMarkus Pfeiffer 		dev->irq_type = pci_alloc_1intr(dev->dev, msi_enable,
10574705af8fSMarkus Pfeiffer 		    &dev->irqrid, &irq_flags);
1058b3705d71SHasso Tepper 
10596df74fa7SFrançois Tigeot 		dev->irqr = bus_alloc_resource_any(dev->dev, SYS_RES_IRQ,
10604705af8fSMarkus Pfeiffer 		    &dev->irqrid, irq_flags);
10614705af8fSMarkus Pfeiffer 
1062b3705d71SHasso Tepper 		if (!dev->irqr) {
10635718399fSFrançois Tigeot 			return (ENOENT);
1064b3705d71SHasso Tepper 		}
1065b3705d71SHasso Tepper 
1066b3705d71SHasso Tepper 		dev->irq = (int) rman_get_start(dev->irqr);
1067bd121a8bSHasso Tepper 	}
1068b3705d71SHasso Tepper 
10695718399fSFrançois Tigeot 	lockinit(&dev->dev_lock, "drmdev", 0, LK_CANRECURSE);
1070b3705d71SHasso Tepper 	lwkt_serialize_init(&dev->irq_lock);
10715718399fSFrançois Tigeot 	lockinit(&dev->event_lock, "drmev", 0, LK_CANRECURSE);
1072a2fdbec6SFrançois Tigeot 	lockinit(&dev->struct_mutex, "drmslk", 0, LK_CANRECURSE);
1073b3705d71SHasso Tepper 
10746f486c69SFrançois Tigeot 	error = drm_load(dev);
10756f486c69SFrançois Tigeot 	if (error)
10766f486c69SFrançois Tigeot 		goto error;
10777f3c3d6fSHasso Tepper 
107879f713b0SFrançois Tigeot 	error = drm_create_cdevs(kdev);
107979f713b0SFrançois Tigeot 	if (error)
108079f713b0SFrançois Tigeot 		goto error;
108179f713b0SFrançois Tigeot 
10826f486c69SFrançois Tigeot 	return (error);
10836f486c69SFrançois Tigeot error:
10846f486c69SFrançois Tigeot 	if (dev->irqr) {
10856df74fa7SFrançois Tigeot 		bus_release_resource(dev->dev, SYS_RES_IRQ,
10866f486c69SFrançois Tigeot 		    dev->irqrid, dev->irqr);
10876f486c69SFrançois Tigeot 	}
10884705af8fSMarkus Pfeiffer 	if (dev->irq_type == PCI_INTR_TYPE_MSI) {
10896df74fa7SFrançois Tigeot 		pci_release_msi(dev->dev);
10906f486c69SFrançois Tigeot 	}
10916f486c69SFrançois Tigeot 	return (error);
10926f486c69SFrançois Tigeot }
10936f486c69SFrançois Tigeot 
109479f713b0SFrançois Tigeot int
109579f713b0SFrançois Tigeot drm_create_cdevs(device_t kdev)
109679f713b0SFrançois Tigeot {
109779f713b0SFrançois Tigeot 	struct drm_device *dev;
109879f713b0SFrançois Tigeot 	int error, unit;
109979f713b0SFrançois Tigeot 
110079f713b0SFrançois Tigeot 	unit = device_get_unit(kdev);
110179f713b0SFrançois Tigeot 	dev = device_get_softc(kdev);
110279f713b0SFrançois Tigeot 
110379f713b0SFrançois Tigeot 	dev->devnode = make_dev(&drm_cdevsw, unit, DRM_DEV_UID, DRM_DEV_GID,
110479f713b0SFrançois Tigeot 				DRM_DEV_MODE, "dri/card%d", unit);
110579f713b0SFrançois Tigeot 	error = 0;
110679f713b0SFrançois Tigeot 	if (error == 0)
110779f713b0SFrançois Tigeot 		dev->devnode->si_drv1 = dev;
110879f713b0SFrançois Tigeot 	return (error);
110979f713b0SFrançois Tigeot }
111079f713b0SFrançois Tigeot 
11117f3c3d6fSHasso Tepper #ifndef DRM_DEV_NAME
11127f3c3d6fSHasso Tepper #define DRM_DEV_NAME "drm"
11137f3c3d6fSHasso Tepper #endif
11147f3c3d6fSHasso Tepper 
11157f3c3d6fSHasso Tepper devclass_t drm_devclass;
11167f3c3d6fSHasso Tepper 
11177f3c3d6fSHasso Tepper drm_pci_id_list_t *drm_find_description(int vendor, int device,
11187f3c3d6fSHasso Tepper     drm_pci_id_list_t *idlist)
11197f3c3d6fSHasso Tepper {
11207f3c3d6fSHasso Tepper 	int i = 0;
11217f3c3d6fSHasso Tepper 
11227f3c3d6fSHasso Tepper 	for (i = 0; idlist[i].vendor != 0; i++) {
11237f3c3d6fSHasso Tepper 		if ((idlist[i].vendor == vendor) &&
1124b3705d71SHasso Tepper 		    ((idlist[i].device == device) ||
1125b3705d71SHasso Tepper 		    (idlist[i].device == 0))) {
11267f3c3d6fSHasso Tepper 			return &idlist[i];
11277f3c3d6fSHasso Tepper 		}
11287f3c3d6fSHasso Tepper 	}
11297f3c3d6fSHasso Tepper 	return NULL;
11307f3c3d6fSHasso Tepper }
11317f3c3d6fSHasso Tepper 
1132b3705d71SHasso Tepper static int drm_load(struct drm_device *dev)
11337f3c3d6fSHasso Tepper {
11347f3c3d6fSHasso Tepper 	int i, retcode;
11357f3c3d6fSHasso Tepper 
11367f3c3d6fSHasso Tepper 	DRM_DEBUG("\n");
11377f3c3d6fSHasso Tepper 
1138f599cd46SFrançois Tigeot 	INIT_LIST_HEAD(&dev->maplist);
11397f3c3d6fSHasso Tepper 
11407f3c3d6fSHasso Tepper 	drm_mem_init();
11417f3c3d6fSHasso Tepper 	drm_sysctl_init(dev);
11421610a1a0SFrançois Tigeot 	INIT_LIST_HEAD(&dev->filelist);
11437f3c3d6fSHasso Tepper 
11447f3c3d6fSHasso Tepper 	dev->counters  = 6;
11457f3c3d6fSHasso Tepper 	dev->types[0]  = _DRM_STAT_LOCK;
11467f3c3d6fSHasso Tepper 	dev->types[1]  = _DRM_STAT_OPENS;
11477f3c3d6fSHasso Tepper 	dev->types[2]  = _DRM_STAT_CLOSES;
11487f3c3d6fSHasso Tepper 	dev->types[3]  = _DRM_STAT_IOCTLS;
11497f3c3d6fSHasso Tepper 	dev->types[4]  = _DRM_STAT_LOCKS;
11507f3c3d6fSHasso Tepper 	dev->types[5]  = _DRM_STAT_UNLOCKS;
11517f3c3d6fSHasso Tepper 
1152c6f73aabSFrançois Tigeot 	for (i = 0; i < ARRAY_SIZE(dev->counts); i++)
11537f3c3d6fSHasso Tepper 		atomic_set(&dev->counts[i], 0);
11547f3c3d6fSHasso Tepper 
11555718399fSFrançois Tigeot 	INIT_LIST_HEAD(&dev->vblank_event_list);
11567f3c3d6fSHasso Tepper 
1157b3705d71SHasso Tepper 	if (drm_core_has_AGP(dev)) {
11587f3c3d6fSHasso Tepper 		if (drm_device_is_agp(dev))
11597f3c3d6fSHasso Tepper 			dev->agp = drm_agp_init();
1160b3705d71SHasso Tepper 		if (drm_core_check_feature(dev, DRIVER_REQUIRE_AGP) &&
1161b3705d71SHasso Tepper 		    dev->agp == NULL) {
11627f3c3d6fSHasso Tepper 			DRM_ERROR("Card isn't AGP, or couldn't initialize "
11637f3c3d6fSHasso Tepper 			    "AGP.\n");
11647f3c3d6fSHasso Tepper 			retcode = ENOMEM;
11657f3c3d6fSHasso Tepper 			goto error;
11667f3c3d6fSHasso Tepper 		}
11679d567857SJean-Sébastien Pédron 		if (dev->agp != NULL && dev->agp->agp_info.ai_aperture_base != 0) {
11689d567857SJean-Sébastien Pédron 			if (drm_mtrr_add(dev->agp->agp_info.ai_aperture_base,
11699d567857SJean-Sébastien Pédron 			    dev->agp->agp_info.ai_aperture_size, DRM_MTRR_WC) == 0)
11709d567857SJean-Sébastien Pédron 				dev->agp->agp_mtrr = 1;
11717f3c3d6fSHasso Tepper 		}
11727f3c3d6fSHasso Tepper 	}
11737f3c3d6fSHasso Tepper 
11745718399fSFrançois Tigeot 	if (dev->driver->driver_features & DRIVER_GEM) {
11755718399fSFrançois Tigeot 		retcode = drm_gem_init(dev);
11765718399fSFrançois Tigeot 		if (retcode != 0) {
11775718399fSFrançois Tigeot 			DRM_ERROR("Cannot initialize graphics execution "
11785718399fSFrançois Tigeot 				  "manager (GEM)\n");
11795718399fSFrançois Tigeot 			goto error1;
11805718399fSFrançois Tigeot 		}
11815718399fSFrançois Tigeot 	}
11825718399fSFrançois Tigeot 
11835718399fSFrançois Tigeot 	if (dev->driver->load != NULL) {
11845718399fSFrançois Tigeot 		DRM_LOCK(dev);
11855718399fSFrançois Tigeot 		/* Shared code returns -errno. */
11865718399fSFrançois Tigeot 		retcode = -dev->driver->load(dev,
11875718399fSFrançois Tigeot 		    dev->id_entry->driver_private);
11886df74fa7SFrançois Tigeot 		if (pci_enable_busmaster(dev->dev))
11895718399fSFrançois Tigeot 			DRM_ERROR("Request to enable bus-master failed.\n");
11905718399fSFrançois Tigeot 		DRM_UNLOCK(dev);
11915718399fSFrançois Tigeot 		if (retcode != 0)
11926f486c69SFrançois Tigeot 			goto error1;
11935718399fSFrançois Tigeot 	}
11945718399fSFrançois Tigeot 
11957f3c3d6fSHasso Tepper 	DRM_INFO("Initialized %s %d.%d.%d %s\n",
1196b3705d71SHasso Tepper 	    dev->driver->name,
1197b3705d71SHasso Tepper 	    dev->driver->major,
1198b3705d71SHasso Tepper 	    dev->driver->minor,
1199b3705d71SHasso Tepper 	    dev->driver->patchlevel,
1200b3705d71SHasso Tepper 	    dev->driver->date);
12017f3c3d6fSHasso Tepper 
12027f3c3d6fSHasso Tepper 	return 0;
12037f3c3d6fSHasso Tepper 
12045718399fSFrançois Tigeot error1:
12056f486c69SFrançois Tigeot 	drm_gem_destroy(dev);
12067f3c3d6fSHasso Tepper error:
12077f3c3d6fSHasso Tepper 	drm_sysctl_cleanup(dev);
12085718399fSFrançois Tigeot 	DRM_LOCK(dev);
12097f3c3d6fSHasso Tepper 	drm_lastclose(dev);
12105718399fSFrançois Tigeot 	DRM_UNLOCK(dev);
12115718399fSFrançois Tigeot 	if (dev->devnode != NULL)
12127f3c3d6fSHasso Tepper 		destroy_dev(dev->devnode);
1213b3705d71SHasso Tepper 
12145718399fSFrançois Tigeot 	lockuninit(&dev->vbl_lock);
12155718399fSFrançois Tigeot 	lockuninit(&dev->dev_lock);
12165718399fSFrançois Tigeot 	lockuninit(&dev->event_lock);
1217a2fdbec6SFrançois Tigeot 	lockuninit(&dev->struct_mutex);
1218b3705d71SHasso Tepper 
12197f3c3d6fSHasso Tepper 	return retcode;
12207f3c3d6fSHasso Tepper }
12217f3c3d6fSHasso Tepper 
12223994a83eSMarkus Pfeiffer /*
12233994a83eSMarkus Pfeiffer  * Stub is needed for devfs
12243994a83eSMarkus Pfeiffer  */
12252c845b81SSimon Schubert int drm_close(struct dev_close_args *ap)
12267f3c3d6fSHasso Tepper {
12273994a83eSMarkus Pfeiffer 	return 0;
12283994a83eSMarkus Pfeiffer }
12297f3c3d6fSHasso Tepper 
123079f713b0SFrançois Tigeot void drm_cdevpriv_dtor(void *cd)
123179f713b0SFrançois Tigeot {
123279f713b0SFrançois Tigeot 	struct drm_file *file_priv = cd;
123379f713b0SFrançois Tigeot 	struct drm_device *dev = file_priv->dev;
123479f713b0SFrançois Tigeot 	int retcode = 0;
123579f713b0SFrançois Tigeot 
123679f713b0SFrançois Tigeot 	DRM_DEBUG("open_count = %d\n", dev->open_count);
123779f713b0SFrançois Tigeot 
123879f713b0SFrançois Tigeot 	DRM_LOCK(dev);
123979f713b0SFrançois Tigeot 
124079f713b0SFrançois Tigeot 	if (dev->driver->preclose != NULL)
124179f713b0SFrançois Tigeot 		dev->driver->preclose(dev, file_priv);
124279f713b0SFrançois Tigeot 
124379f713b0SFrançois Tigeot 	/* ========================================================
124479f713b0SFrançois Tigeot 	 * Begin inline drm_release
124579f713b0SFrançois Tigeot 	 */
124679f713b0SFrançois Tigeot 
124779f713b0SFrançois Tigeot 	DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n",
124879f713b0SFrançois Tigeot 	    DRM_CURRENTPID, (long)dev->dev, dev->open_count);
124979f713b0SFrançois Tigeot 
125079f713b0SFrançois Tigeot 	if (dev->driver->driver_features & DRIVER_GEM)
125179f713b0SFrançois Tigeot 		drm_gem_release(dev, file_priv);
125279f713b0SFrançois Tigeot 
125379f713b0SFrançois Tigeot 	if (dev->lock.hw_lock && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)
125479f713b0SFrançois Tigeot 	    && dev->lock.file_priv == file_priv) {
125579f713b0SFrançois Tigeot 		DRM_DEBUG("Process %d dead, freeing lock for context %d\n",
125679f713b0SFrançois Tigeot 			  DRM_CURRENTPID,
125779f713b0SFrançois Tigeot 			  _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
125879f713b0SFrançois Tigeot 		if (dev->driver->reclaim_buffers_locked != NULL)
125979f713b0SFrançois Tigeot 			dev->driver->reclaim_buffers_locked(dev, file_priv);
126079f713b0SFrançois Tigeot 
126179f713b0SFrançois Tigeot 		drm_lock_free(&dev->lock,
126279f713b0SFrançois Tigeot 		    _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
126379f713b0SFrançois Tigeot 
126479f713b0SFrançois Tigeot 				/* FIXME: may require heavy-handed reset of
126579f713b0SFrançois Tigeot                                    hardware at this point, possibly
126679f713b0SFrançois Tigeot                                    processed via a callback to the X
126779f713b0SFrançois Tigeot                                    server. */
126879f713b0SFrançois Tigeot 	} else if (dev->driver->reclaim_buffers_locked != NULL &&
126979f713b0SFrançois Tigeot 	    dev->lock.hw_lock != NULL) {
127079f713b0SFrançois Tigeot 		/* The lock is required to reclaim buffers */
127179f713b0SFrançois Tigeot 		for (;;) {
127279f713b0SFrançois Tigeot 			if (!dev->lock.hw_lock) {
127379f713b0SFrançois Tigeot 				/* Device has been unregistered */
127479f713b0SFrançois Tigeot 				retcode = EINTR;
127579f713b0SFrançois Tigeot 				break;
127679f713b0SFrançois Tigeot 			}
127779f713b0SFrançois Tigeot 			/* Contention */
127879f713b0SFrançois Tigeot 			retcode = DRM_LOCK_SLEEP(dev, &dev->lock.lock_queue,
127979f713b0SFrançois Tigeot 			    PCATCH, "drmlk2", 0);
128079f713b0SFrançois Tigeot 			if (retcode)
128179f713b0SFrançois Tigeot 				break;
128279f713b0SFrançois Tigeot 		}
128379f713b0SFrançois Tigeot 		if (retcode == 0) {
128479f713b0SFrançois Tigeot 			dev->driver->reclaim_buffers_locked(dev, file_priv);
128579f713b0SFrançois Tigeot 		}
128679f713b0SFrançois Tigeot 	}
128779f713b0SFrançois Tigeot 
128879f713b0SFrançois Tigeot 	if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) &&
128979f713b0SFrançois Tigeot 	    !dev->driver->reclaim_buffers_locked)
1290*1b13d190SFrançois Tigeot 		drm_legacy_reclaim_buffers(dev, file_priv);
129179f713b0SFrançois Tigeot 
129279f713b0SFrançois Tigeot 	funsetown(&dev->buf_sigio);
129379f713b0SFrançois Tigeot 
129479f713b0SFrançois Tigeot 	if (dev->driver->postclose != NULL)
129579f713b0SFrançois Tigeot 		dev->driver->postclose(dev, file_priv);
129679f713b0SFrançois Tigeot 	list_del(&file_priv->lhead);
129779f713b0SFrançois Tigeot 
129879f713b0SFrançois Tigeot 
129979f713b0SFrançois Tigeot 	/* ========================================================
130079f713b0SFrançois Tigeot 	 * End inline drm_release
130179f713b0SFrançois Tigeot 	 */
130279f713b0SFrançois Tigeot 
130379f713b0SFrançois Tigeot 	atomic_inc(&dev->counts[_DRM_STAT_CLOSES]);
130479f713b0SFrançois Tigeot 	device_unbusy(dev->dev);
130579f713b0SFrançois Tigeot 	if (--dev->open_count == 0) {
130679f713b0SFrançois Tigeot 		retcode = drm_lastclose(dev);
130779f713b0SFrançois Tigeot 	}
130879f713b0SFrançois Tigeot 
130979f713b0SFrançois Tigeot 	DRM_UNLOCK(dev);
131079f713b0SFrançois Tigeot }
131179f713b0SFrançois Tigeot 
13125718399fSFrançois Tigeot int
13135718399fSFrançois Tigeot drm_add_busid_modesetting(struct drm_device *dev, struct sysctl_ctx_list *ctx,
13145718399fSFrançois Tigeot     struct sysctl_oid *top)
13155718399fSFrançois Tigeot {
13165718399fSFrançois Tigeot 	struct sysctl_oid *oid;
13175718399fSFrançois Tigeot 
13185718399fSFrançois Tigeot 	ksnprintf(dev->busid_str, sizeof(dev->busid_str),
13195718399fSFrançois Tigeot 	     "pci:%04x:%02x:%02x.%d", dev->pci_domain, dev->pci_bus,
13205718399fSFrançois Tigeot 	     dev->pci_slot, dev->pci_func);
13215718399fSFrançois Tigeot 	oid = SYSCTL_ADD_STRING(ctx, SYSCTL_CHILDREN(top), OID_AUTO, "busid",
13225718399fSFrançois Tigeot 	    CTLFLAG_RD, dev->busid_str, 0, NULL);
13235718399fSFrançois Tigeot 	if (oid == NULL)
13245718399fSFrançois Tigeot 		return (ENOMEM);
13255718399fSFrançois Tigeot 	dev->modesetting = (dev->driver->driver_features & DRIVER_MODESET) != 0;
13265718399fSFrançois Tigeot 	oid = SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(top), OID_AUTO,
13275718399fSFrançois Tigeot 	    "modesetting", CTLFLAG_RD, &dev->modesetting, 0, NULL);
13285718399fSFrançois Tigeot 	if (oid == NULL)
13295718399fSFrançois Tigeot 		return (ENOMEM);
13305718399fSFrançois Tigeot 
13315718399fSFrançois Tigeot 	return (0);
13325718399fSFrançois Tigeot }
13335718399fSFrançois Tigeot 
13345718399fSFrançois Tigeot int
13355718399fSFrançois Tigeot drm_mmap_single(struct dev_mmap_single_args *ap)
13365718399fSFrançois Tigeot {
133779f713b0SFrançois Tigeot 	struct drm_device *dev;
13385718399fSFrançois Tigeot 	struct cdev *kdev = ap->a_head.a_dev;
13395718399fSFrançois Tigeot 	vm_ooffset_t *offset = ap->a_offset;
13405718399fSFrançois Tigeot 	vm_size_t size = ap->a_size;
13415718399fSFrançois Tigeot 	struct vm_object **obj_res = ap->a_object;
13425718399fSFrançois Tigeot 	int nprot = ap->a_nprot;
13435718399fSFrançois Tigeot 
134479f713b0SFrançois Tigeot 	dev = drm_get_device_from_kdev(kdev);
13456f486c69SFrançois Tigeot 	if (dev->drm_ttm_bdev != NULL) {
13466f486c69SFrançois Tigeot 		return (ttm_bo_mmap_single(dev->drm_ttm_bdev, offset, size,
13475718399fSFrançois Tigeot 		    obj_res, nprot));
13486f486c69SFrançois Tigeot 	} else if ((dev->driver->driver_features & DRIVER_GEM) != 0) {
13496f486c69SFrançois Tigeot 		return (drm_gem_mmap_single(dev, offset, size, obj_res, nprot));
13505718399fSFrançois Tigeot 	} else {
13515718399fSFrançois Tigeot 		return (ENODEV);
13525718399fSFrançois Tigeot 	}
13535718399fSFrançois Tigeot }
13545718399fSFrançois Tigeot 
13557f3c3d6fSHasso Tepper #if DRM_LINUX
13567f3c3d6fSHasso Tepper 
13577f3c3d6fSHasso Tepper #include <sys/sysproto.h>
13587f3c3d6fSHasso Tepper 
13597f3c3d6fSHasso Tepper MODULE_DEPEND(DRIVER_NAME, linux, 1, 1, 1);
13607f3c3d6fSHasso Tepper 
13617f3c3d6fSHasso Tepper #define LINUX_IOCTL_DRM_MIN		0x6400
13627f3c3d6fSHasso Tepper #define LINUX_IOCTL_DRM_MAX		0x64ff
13637f3c3d6fSHasso Tepper 
13647f3c3d6fSHasso Tepper static linux_ioctl_function_t drm_linux_ioctl;
13657f3c3d6fSHasso Tepper static struct linux_ioctl_handler drm_handler = {drm_linux_ioctl,
13667f3c3d6fSHasso Tepper     LINUX_IOCTL_DRM_MIN, LINUX_IOCTL_DRM_MAX};
13677f3c3d6fSHasso Tepper 
13687f3c3d6fSHasso Tepper /* The bits for in/out are switched on Linux */
13697f3c3d6fSHasso Tepper #define LINUX_IOC_IN	IOC_OUT
13707f3c3d6fSHasso Tepper #define LINUX_IOC_OUT	IOC_IN
13717f3c3d6fSHasso Tepper 
13727f3c3d6fSHasso Tepper static int
13737f3c3d6fSHasso Tepper drm_linux_ioctl(DRM_STRUCTPROC *p, struct linux_ioctl_args* args)
13747f3c3d6fSHasso Tepper {
13757f3c3d6fSHasso Tepper 	int error;
13767f3c3d6fSHasso Tepper 	int cmd = args->cmd;
13777f3c3d6fSHasso Tepper 
13787f3c3d6fSHasso Tepper 	args->cmd &= ~(LINUX_IOC_IN | LINUX_IOC_OUT);
13797f3c3d6fSHasso Tepper 	if (cmd & LINUX_IOC_IN)
13807f3c3d6fSHasso Tepper 		args->cmd |= IOC_IN;
13817f3c3d6fSHasso Tepper 	if (cmd & LINUX_IOC_OUT)
13827f3c3d6fSHasso Tepper 		args->cmd |= IOC_OUT;
13837f3c3d6fSHasso Tepper 
13847f3c3d6fSHasso Tepper 	error = ioctl(p, (struct ioctl_args *)args);
13857f3c3d6fSHasso Tepper 
13867f3c3d6fSHasso Tepper 	return error;
13877f3c3d6fSHasso Tepper }
13887f3c3d6fSHasso Tepper #endif /* DRM_LINUX */
13895718399fSFrançois Tigeot 
13906f486c69SFrançois Tigeot static int
13916f486c69SFrançois Tigeot drm_core_init(void *arg)
13926f486c69SFrançois Tigeot {
13936f486c69SFrançois Tigeot 
13946f486c69SFrançois Tigeot 	drm_global_init();
13956f486c69SFrançois Tigeot 
13966f486c69SFrançois Tigeot #if DRM_LINUX
13976f486c69SFrançois Tigeot 	linux_ioctl_register_handler(&drm_handler);
13986f486c69SFrançois Tigeot #endif /* DRM_LINUX */
13996f486c69SFrançois Tigeot 
14006f486c69SFrançois Tigeot 	DRM_INFO("Initialized %s %d.%d.%d %s\n",
14016f486c69SFrançois Tigeot 		 CORE_NAME, CORE_MAJOR, CORE_MINOR, CORE_PATCHLEVEL, CORE_DATE);
14026f486c69SFrançois Tigeot 	return 0;
14036f486c69SFrançois Tigeot }
14046f486c69SFrançois Tigeot 
14056f486c69SFrançois Tigeot static void
14066f486c69SFrançois Tigeot drm_core_exit(void *arg)
14076f486c69SFrançois Tigeot {
14086f486c69SFrançois Tigeot 
14096f486c69SFrançois Tigeot #if DRM_LINUX
14106f486c69SFrançois Tigeot 	linux_ioctl_unregister_handler(&drm_handler);
14116f486c69SFrançois Tigeot #endif /* DRM_LINUX */
14126f486c69SFrançois Tigeot 
14136f486c69SFrançois Tigeot 	drm_global_release();
14146f486c69SFrançois Tigeot }
14156f486c69SFrançois Tigeot 
14166f486c69SFrançois Tigeot SYSINIT(drm_register, SI_SUB_DRIVERS, SI_ORDER_MIDDLE,
14176f486c69SFrançois Tigeot     drm_core_init, NULL);
14186f486c69SFrançois Tigeot SYSUNINIT(drm_unregister, SI_SUB_DRIVERS, SI_ORDER_MIDDLE,
14196f486c69SFrançois Tigeot     drm_core_exit, NULL);
14206f486c69SFrançois Tigeot 
142124edb884SFrançois Tigeot 
142224edb884SFrançois Tigeot #include <linux/dmi.h>
142324edb884SFrançois Tigeot 
14245718399fSFrançois Tigeot /*
14255718399fSFrançois Tigeot  * Check if dmi_system_id structure matches system DMI data
14265718399fSFrançois Tigeot  */
14275718399fSFrançois Tigeot static bool
14285718399fSFrançois Tigeot dmi_found(const struct dmi_system_id *dsi)
14295718399fSFrançois Tigeot {
14305718399fSFrançois Tigeot 	int i, slot;
14315718399fSFrançois Tigeot 	bool found = false;
14325718399fSFrançois Tigeot 	char *sys_vendor, *board_vendor, *product_name, *board_name;
14335718399fSFrançois Tigeot 
14345718399fSFrançois Tigeot 	sys_vendor = kgetenv("smbios.system.maker");
14355718399fSFrançois Tigeot 	board_vendor = kgetenv("smbios.planar.maker");
14365718399fSFrançois Tigeot 	product_name = kgetenv("smbios.system.product");
14375718399fSFrançois Tigeot 	board_name = kgetenv("smbios.planar.product");
14385718399fSFrançois Tigeot 
14395718399fSFrançois Tigeot 	for (i = 0; i < NELEM(dsi->matches); i++) {
14405718399fSFrançois Tigeot 		slot = dsi->matches[i].slot;
14415718399fSFrançois Tigeot 		switch (slot) {
14425718399fSFrançois Tigeot 		case DMI_NONE:
14435718399fSFrançois Tigeot 			break;
14445718399fSFrançois Tigeot 		case DMI_SYS_VENDOR:
14455718399fSFrançois Tigeot 			if (sys_vendor != NULL &&
14465718399fSFrançois Tigeot 			    !strcmp(sys_vendor, dsi->matches[i].substr))
14475718399fSFrançois Tigeot 				break;
14485718399fSFrançois Tigeot 			else
14495718399fSFrançois Tigeot 				goto done;
14505718399fSFrançois Tigeot 		case DMI_BOARD_VENDOR:
14515718399fSFrançois Tigeot 			if (board_vendor != NULL &&
14525718399fSFrançois Tigeot 			    !strcmp(board_vendor, dsi->matches[i].substr))
14535718399fSFrançois Tigeot 				break;
14545718399fSFrançois Tigeot 			else
14555718399fSFrançois Tigeot 				goto done;
14565718399fSFrançois Tigeot 		case DMI_PRODUCT_NAME:
14575718399fSFrançois Tigeot 			if (product_name != NULL &&
14585718399fSFrançois Tigeot 			    !strcmp(product_name, dsi->matches[i].substr))
14595718399fSFrançois Tigeot 				break;
14605718399fSFrançois Tigeot 			else
14615718399fSFrançois Tigeot 				goto done;
14625718399fSFrançois Tigeot 		case DMI_BOARD_NAME:
14635718399fSFrançois Tigeot 			if (board_name != NULL &&
14645718399fSFrançois Tigeot 			    !strcmp(board_name, dsi->matches[i].substr))
14655718399fSFrançois Tigeot 				break;
14665718399fSFrançois Tigeot 			else
14675718399fSFrançois Tigeot 				goto done;
14685718399fSFrançois Tigeot 		default:
14695718399fSFrançois Tigeot 			goto done;
14705718399fSFrançois Tigeot 		}
14715718399fSFrançois Tigeot 	}
14725718399fSFrançois Tigeot 	found = true;
14735718399fSFrançois Tigeot 
14745718399fSFrançois Tigeot done:
14755718399fSFrançois Tigeot 	if (sys_vendor != NULL)
14765718399fSFrançois Tigeot 		kfreeenv(sys_vendor);
14775718399fSFrançois Tigeot 	if (board_vendor != NULL)
14785718399fSFrançois Tigeot 		kfreeenv(board_vendor);
14795718399fSFrançois Tigeot 	if (product_name != NULL)
14805718399fSFrançois Tigeot 		kfreeenv(product_name);
14815718399fSFrançois Tigeot 	if (board_name != NULL)
14825718399fSFrançois Tigeot 		kfreeenv(board_name);
14835718399fSFrançois Tigeot 
14845718399fSFrançois Tigeot 	return found;
14855718399fSFrançois Tigeot }
14865718399fSFrançois Tigeot 
1487be348e9fSFrançois Tigeot int dmi_check_system(const struct dmi_system_id *sysid)
14885718399fSFrançois Tigeot {
14895718399fSFrançois Tigeot 	const struct dmi_system_id *dsi;
14905718399fSFrançois Tigeot 	int num = 0;
14915718399fSFrançois Tigeot 
14925718399fSFrançois Tigeot 	for (dsi = sysid; dsi->matches[0].slot != 0 ; dsi++) {
14935718399fSFrançois Tigeot 		if (dmi_found(dsi)) {
14945718399fSFrançois Tigeot 			num++;
14955718399fSFrançois Tigeot 			if (dsi->callback && dsi->callback(dsi))
14965718399fSFrançois Tigeot 				break;
14975718399fSFrançois Tigeot 		}
14985718399fSFrançois Tigeot 	}
14995718399fSFrançois Tigeot 	return (num);
15005718399fSFrançois Tigeot }
1501