xref: /dragonfly/sys/dev/drm/drm_drv.c (revision 932d855e)
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 
294be47400SFrançois Tigeot #include <linux/debugfs.h>
304be47400SFrançois Tigeot #include <linux/fs.h>
3124edb884SFrançois Tigeot #include <linux/module.h>
3224edb884SFrançois Tigeot #include <linux/moduleparam.h>
334be47400SFrançois Tigeot #include <linux/mount.h>
344be47400SFrançois Tigeot #include <linux/slab.h>
354be47400SFrançois Tigeot 
364be47400SFrançois Tigeot #include <drm/drm_drv.h>
3724edb884SFrançois Tigeot #include <drm/drmP.h>
384be47400SFrançois Tigeot 
391dedbd3bSFrançois Tigeot #include "drm_crtc_internal.h"
4024edb884SFrançois Tigeot #include "drm_legacy.h"
411b13d190SFrançois Tigeot #include "drm_internal.h"
4224edb884SFrançois Tigeot 
438621f407SFrançois Tigeot /*
448621f407SFrançois Tigeot  * drm_debug: Enable debug output.
458621f407SFrançois Tigeot  * Bitmask of DRM_UT_x. See include/drm/drmP.h for details.
468621f407SFrançois Tigeot  */
4791fff950Szrj #ifdef __DragonFly__
488621f407SFrançois Tigeot /* Provides three levels of debug: off, minimal, verbose */
4991fff950Szrj #if DRM_DEBUG_DEFAULT_ON == 1
5091fff950Szrj #define DRM_DEBUGBITS_ON (DRM_UT_CORE | DRM_UT_DRIVER | DRM_UT_KMS |	\
5191fff950Szrj 			  DRM_UT_PRIME| DRM_UT_ATOMIC | DRM_UT_FIOCTL)
5291fff950Szrj #elif DRM_DEBUG_DEFAULT_ON == 2
5391fff950Szrj #define DRM_DEBUGBITS_ON (DRM_UT_CORE | DRM_UT_DRIVER | DRM_UT_KMS |	\
5491fff950Szrj 			  DRM_UT_PRIME| DRM_UT_ATOMIC | DRM_UT_FIOCTL |	\
5578973132SSergey Zigachev 			  DRM_UT_PID  | DRM_UT_IOCTL  )
5691fff950Szrj #else
5791fff950Szrj #define DRM_DEBUGBITS_ON (0x0)
5891fff950Szrj #endif
5991fff950Szrj unsigned int drm_debug = DRM_DEBUGBITS_ON;	/* defaults to 0 */
6091fff950Szrj #else
618621f407SFrançois Tigeot unsigned int drm_debug = 0;
6291fff950Szrj #endif /* __DragonFly__ */
6324edb884SFrançois Tigeot EXPORT_SYMBOL(drm_debug);
6424edb884SFrançois Tigeot 
651dedbd3bSFrançois Tigeot MODULE_AUTHOR("Gareth Hughes, Leif Delgass, José Fonseca, Jon Smirl");
661dedbd3bSFrançois Tigeot MODULE_DESCRIPTION("DRM shared core routines");
678621f407SFrançois Tigeot MODULE_PARM_DESC(debug, "Enable debug output, where each bit enables a debug category.\n"
688621f407SFrançois Tigeot "\t\tBit 0 (0x01) will enable CORE messages (drm core code)\n"
698621f407SFrançois Tigeot "\t\tBit 1 (0x02) will enable DRIVER messages (drm controller code)\n"
708621f407SFrançois Tigeot "\t\tBit 2 (0x04) will enable KMS messages (modesetting code)\n"
718621f407SFrançois Tigeot "\t\tBit 3 (0x08) will enable PRIME messages (prime code)\n"
728621f407SFrançois Tigeot "\t\tBit 4 (0x10) will enable ATOMIC messages (atomic code)\n"
733f2dd94aSFrançois Tigeot "\t\tBit 5 (0x20) will enable VBL messages (vblank code)\n"
743f2dd94aSFrançois Tigeot "\t\tBit 7 (0x80) will enable LEASE messages (leasing code)");
7524edb884SFrançois Tigeot module_param_named(debug, drm_debug, int, 0600);
7624edb884SFrançois Tigeot 
77fcf17be7SFrançois Tigeot static DEFINE_MUTEX(drm_minor_lock);
7824edb884SFrançois Tigeot static struct idr drm_minors_idr;
7924edb884SFrançois Tigeot 
803f2dd94aSFrançois Tigeot /*
813f2dd94aSFrançois Tigeot  * If the drm core fails to init for whatever reason,
823f2dd94aSFrançois Tigeot  * we should prevent any drivers from registering with it.
833f2dd94aSFrançois Tigeot  * It's best to check this at drm_dev_init(), as some drivers
843f2dd94aSFrançois Tigeot  * prefer to embed struct drm_device into their own device
853f2dd94aSFrançois Tigeot  * structure and call drm_dev_init() themselves.
863f2dd94aSFrançois Tigeot  */
873f2dd94aSFrançois Tigeot static bool drm_core_init_complete = false;
883f2dd94aSFrançois Tigeot 
8924edb884SFrançois Tigeot #if 0
9024edb884SFrançois Tigeot static struct dentry *drm_debugfs_root;
9124edb884SFrançois Tigeot #endif
9224edb884SFrançois Tigeot 
drm_err(const char * func,const char * format,...)93ddc30266SFrançois Tigeot void drm_err(const char *func, const char *format, ...)
94ddc30266SFrançois Tigeot {
95ddc30266SFrançois Tigeot 	va_list args;
96ddc30266SFrançois Tigeot 
97ddc30266SFrançois Tigeot 	kprintf("error: [" DRM_NAME ":pid%d:%s] *ERROR* ", DRM_CURRENTPID, func);
98ddc30266SFrançois Tigeot 
99ddc30266SFrançois Tigeot 	va_start(args, format);
100ddc30266SFrançois Tigeot 	kvprintf(format, args);
101ddc30266SFrançois Tigeot 	va_end(args);
102ddc30266SFrançois Tigeot }
103ddc30266SFrançois Tigeot 
drm_ut_debug_printk(const char * function_name,const char * format,...)10424edb884SFrançois Tigeot void drm_ut_debug_printk(const char *function_name, const char *format, ...)
10524edb884SFrançois Tigeot {
1069286b91eSSascha Wildner 	va_list args;
10724edb884SFrançois Tigeot 
10891fff950Szrj 	if (unlikely(drm_debug & DRM_UT_PID)) {
10991fff950Szrj 		kprintf("[" DRM_NAME ":pid%d:%s] ",
11091fff950Szrj 		    DRM_CURRENTPID, function_name);
11191fff950Szrj 	} else {
11291fff950Szrj 		kprintf("[" DRM_NAME ":%s] ", function_name);
11391fff950Szrj 	}
11424edb884SFrançois Tigeot 
1159286b91eSSascha Wildner 	va_start(args, format);
11691fff950Szrj 	kvprintf(format, args);
1179286b91eSSascha Wildner 	va_end(args);
11824edb884SFrançois Tigeot }
11924edb884SFrançois Tigeot 
1201dedbd3bSFrançois Tigeot #define DRM_PRINTK_FMT "[" DRM_NAME ":%s]%s %pV"
1213f2dd94aSFrançois Tigeot #define DRM_PRINTK_FMT_DFLY "[" DRM_NAME ":%s]%s "
1221dedbd3bSFrançois Tigeot 
drm_dev_printk(const struct device * dev,const char * level,unsigned int category,const char * function_name,const char * prefix,const char * format,...)1231dedbd3bSFrançois Tigeot void drm_dev_printk(const struct device *dev, const char *level,
1241dedbd3bSFrançois Tigeot 		    unsigned int category, const char *function_name,
1251dedbd3bSFrançois Tigeot 		    const char *prefix, const char *format, ...)
12624edb884SFrançois Tigeot {
1271dedbd3bSFrançois Tigeot 	struct va_format vaf;
1281dedbd3bSFrançois Tigeot 	va_list args;
12924edb884SFrançois Tigeot 
1301dedbd3bSFrançois Tigeot 	if (category != DRM_UT_NONE && !(drm_debug & category))
1311dedbd3bSFrançois Tigeot 		return;
13224edb884SFrançois Tigeot 
1331dedbd3bSFrançois Tigeot 	va_start(args, format);
1341dedbd3bSFrançois Tigeot 	vaf.fmt = format;
1351dedbd3bSFrançois Tigeot 	vaf.va = &args;
1361dedbd3bSFrançois Tigeot 
1371dedbd3bSFrançois Tigeot 	if (dev)
1383f2dd94aSFrançois Tigeot #if 0
1391dedbd3bSFrançois Tigeot 		dev_printk(level, dev, DRM_PRINTK_FMT, function_name, prefix,
1401dedbd3bSFrançois Tigeot 			   &vaf);
1411dedbd3bSFrançois Tigeot 	else
1421dedbd3bSFrançois Tigeot 		printk("%s" DRM_PRINTK_FMT, level, function_name, prefix, &vaf);
1433f2dd94aSFrançois Tigeot #else
1443f2dd94aSFrançois Tigeot 	{
1453f2dd94aSFrançois Tigeot 		kprintf("drm_dev_printk: ");
1463f2dd94aSFrançois Tigeot 		dev_printk(level, dev, DRM_PRINTK_FMT_DFLY, function_name, prefix);
1473f2dd94aSFrançois Tigeot 		kprintf(vaf.fmt, vaf.va);
1483f2dd94aSFrançois Tigeot 	} else {
1493f2dd94aSFrançois Tigeot 		kprintf("drm_dev_printk: ");
1503f2dd94aSFrançois Tigeot 		printk("%s" DRM_PRINTK_FMT_DFLY, level, function_name, prefix);
1513f2dd94aSFrançois Tigeot 		kprintf(vaf.fmt, vaf.va);
1523f2dd94aSFrançois Tigeot 	}
1533f2dd94aSFrançois Tigeot #endif
1541dedbd3bSFrançois Tigeot 
1551dedbd3bSFrançois Tigeot 	va_end(args);
15624edb884SFrançois Tigeot }
1571dedbd3bSFrançois Tigeot EXPORT_SYMBOL(drm_dev_printk);
15824edb884SFrançois Tigeot 
drm_printk(const char * level,unsigned int category,const char * format,...)1591dedbd3bSFrançois Tigeot void drm_printk(const char *level, unsigned int category,
1601dedbd3bSFrançois Tigeot 		const char *format, ...)
16124edb884SFrançois Tigeot {
1621dedbd3bSFrançois Tigeot 	struct va_format vaf;
1631dedbd3bSFrançois Tigeot 	va_list args;
1641dedbd3bSFrançois Tigeot 
1651dedbd3bSFrançois Tigeot 	if (category != DRM_UT_NONE && !(drm_debug & category))
1661dedbd3bSFrançois Tigeot 		return;
1671dedbd3bSFrançois Tigeot 
1681dedbd3bSFrançois Tigeot 	va_start(args, format);
1691dedbd3bSFrançois Tigeot 	vaf.fmt = format;
1701dedbd3bSFrançois Tigeot 	vaf.va = &args;
1711dedbd3bSFrançois Tigeot 
1723f2dd94aSFrançois Tigeot #if 0
1731dedbd3bSFrançois Tigeot 	printk("%s" "[" DRM_NAME ":%ps]%s %pV",
1741dedbd3bSFrançois Tigeot 	       level, __builtin_return_address(0),
1751dedbd3bSFrançois Tigeot 	       strcmp(level, KERN_ERR) == 0 ? " *ERROR*" : "", &vaf);
1763f2dd94aSFrançois Tigeot #else
1773f2dd94aSFrançois Tigeot 	printk("%s" "[" DRM_NAME ":%p]%s ",
1783f2dd94aSFrançois Tigeot 	       level, __builtin_return_address(0),
1793f2dd94aSFrançois Tigeot 	       strcmp(level, KERN_ERR) == 0 ? " *ERROR*" : "");
1803f2dd94aSFrançois Tigeot 	kprintf(vaf.fmt, vaf.va);
1813f2dd94aSFrançois Tigeot #endif
1821dedbd3bSFrançois Tigeot 
1831dedbd3bSFrançois Tigeot 	va_end(args);
18424edb884SFrançois Tigeot }
1851dedbd3bSFrançois Tigeot EXPORT_SYMBOL(drm_printk);
18624edb884SFrançois Tigeot 
18724edb884SFrançois Tigeot /*
18824edb884SFrançois Tigeot  * DRM Minors
18924edb884SFrançois Tigeot  * A DRM device can provide several char-dev interfaces on the DRM-Major. Each
19024edb884SFrançois Tigeot  * of them is represented by a drm_minor object. Depending on the capabilities
19124edb884SFrançois Tigeot  * of the device-driver, different interfaces are registered.
19224edb884SFrançois Tigeot  *
19324edb884SFrançois Tigeot  * Minors can be accessed via dev->$minor_name. This pointer is either
19424edb884SFrançois Tigeot  * NULL or a valid drm_minor pointer and stays valid as long as the device is
19524edb884SFrançois Tigeot  * valid. This means, DRM minors have the same life-time as the underlying
19624edb884SFrançois Tigeot  * device. However, this doesn't mean that the minor is active. Minors are
19724edb884SFrançois Tigeot  * registered and unregistered dynamically according to device-state.
19824edb884SFrançois Tigeot  */
19924edb884SFrançois Tigeot 
drm_minor_get_slot(struct drm_device * dev,unsigned int type)20024edb884SFrançois Tigeot static struct drm_minor **drm_minor_get_slot(struct drm_device *dev,
20124edb884SFrançois Tigeot 					     unsigned int type)
20224edb884SFrançois Tigeot {
20324edb884SFrançois Tigeot 	switch (type) {
2041dedbd3bSFrançois Tigeot 	case DRM_MINOR_PRIMARY:
20524edb884SFrançois Tigeot 		return &dev->primary;
20624edb884SFrançois Tigeot 	case DRM_MINOR_RENDER:
20724edb884SFrançois Tigeot 		return &dev->render;
20824edb884SFrançois Tigeot 	case DRM_MINOR_CONTROL:
20924edb884SFrançois Tigeot 		return &dev->control;
21024edb884SFrançois Tigeot 	default:
21124edb884SFrançois Tigeot 		return NULL;
21224edb884SFrançois Tigeot 	}
21324edb884SFrançois Tigeot }
21424edb884SFrançois Tigeot 
drm_minor_alloc(struct drm_device * dev,unsigned int type)21524edb884SFrançois Tigeot static int drm_minor_alloc(struct drm_device *dev, unsigned int type)
21624edb884SFrançois Tigeot {
21724edb884SFrançois Tigeot 	struct drm_minor *minor;
21824edb884SFrançois Tigeot 	unsigned long flags;
21924edb884SFrançois Tigeot 	int r;
22024edb884SFrançois Tigeot 
22124edb884SFrançois Tigeot 	minor = kzalloc(sizeof(*minor), GFP_KERNEL);
22224edb884SFrançois Tigeot 	if (!minor)
22324edb884SFrançois Tigeot 		return -ENOMEM;
22424edb884SFrançois Tigeot 
22524edb884SFrançois Tigeot 	minor->type = type;
22624edb884SFrançois Tigeot 	minor->dev = dev;
22724edb884SFrançois Tigeot 
22824edb884SFrançois Tigeot 	idr_preload(GFP_KERNEL);
22924edb884SFrançois Tigeot 	spin_lock_irqsave(&drm_minor_lock, flags);
23024edb884SFrançois Tigeot 	r = idr_alloc(&drm_minors_idr,
23124edb884SFrançois Tigeot 		      NULL,
23224edb884SFrançois Tigeot 		      64 * type,
23324edb884SFrançois Tigeot 		      64 * (type + 1),
23424edb884SFrançois Tigeot 		      GFP_NOWAIT);
23524edb884SFrançois Tigeot 	spin_unlock_irqrestore(&drm_minor_lock, flags);
23624edb884SFrançois Tigeot 	idr_preload_end();
23724edb884SFrançois Tigeot 
23824edb884SFrançois Tigeot 	if (r < 0)
23924edb884SFrançois Tigeot 		goto err_free;
24024edb884SFrançois Tigeot 
24124edb884SFrançois Tigeot 	minor->index = r;
24224edb884SFrançois Tigeot 
24324edb884SFrançois Tigeot 	minor->kdev = drm_sysfs_minor_alloc(minor);
24424edb884SFrançois Tigeot 	if (IS_ERR(minor->kdev)) {
24524edb884SFrançois Tigeot 		r = PTR_ERR(minor->kdev);
24624edb884SFrançois Tigeot 		goto err_index;
24724edb884SFrançois Tigeot 	}
24824edb884SFrançois Tigeot 
24924edb884SFrançois Tigeot 	*drm_minor_get_slot(dev, type) = minor;
25024edb884SFrançois Tigeot 	return 0;
25124edb884SFrançois Tigeot 
25224edb884SFrançois Tigeot err_index:
25324edb884SFrançois Tigeot 	spin_lock_irqsave(&drm_minor_lock, flags);
25424edb884SFrançois Tigeot 	idr_remove(&drm_minors_idr, minor->index);
25524edb884SFrançois Tigeot 	spin_unlock_irqrestore(&drm_minor_lock, flags);
25624edb884SFrançois Tigeot err_free:
25724edb884SFrançois Tigeot 	kfree(minor);
25824edb884SFrançois Tigeot 	return r;
25924edb884SFrançois Tigeot }
26024edb884SFrançois Tigeot 
drm_minor_free(struct drm_device * dev,unsigned int type)26124edb884SFrançois Tigeot static void drm_minor_free(struct drm_device *dev, unsigned int type)
26224edb884SFrançois Tigeot {
26324edb884SFrançois Tigeot 	struct drm_minor **slot, *minor;
26424edb884SFrançois Tigeot 	unsigned long flags;
26524edb884SFrançois Tigeot 
26624edb884SFrançois Tigeot 	slot = drm_minor_get_slot(dev, type);
26724edb884SFrançois Tigeot 	minor = *slot;
26824edb884SFrançois Tigeot 	if (!minor)
26924edb884SFrançois Tigeot 		return;
27024edb884SFrançois Tigeot 
271fcf17be7SFrançois Tigeot #if 0
27224edb884SFrançois Tigeot 	put_device(minor->kdev);
273fcf17be7SFrançois Tigeot #endif
27424edb884SFrançois Tigeot 
27524edb884SFrançois Tigeot 	spin_lock_irqsave(&drm_minor_lock, flags);
27624edb884SFrançois Tigeot 	idr_remove(&drm_minors_idr, minor->index);
27724edb884SFrançois Tigeot 	spin_unlock_irqrestore(&drm_minor_lock, flags);
27824edb884SFrançois Tigeot 
27924edb884SFrançois Tigeot 	kfree(minor);
28024edb884SFrançois Tigeot 	*slot = NULL;
28124edb884SFrançois Tigeot }
28224edb884SFrançois Tigeot 
drm_minor_register(struct drm_device * dev,unsigned int type)28324edb884SFrançois Tigeot static int drm_minor_register(struct drm_device *dev, unsigned int type)
28424edb884SFrançois Tigeot {
28524edb884SFrançois Tigeot 	struct drm_minor *minor;
28624edb884SFrançois Tigeot 	unsigned long flags;
28724edb884SFrançois Tigeot 	int ret;
28824edb884SFrançois Tigeot 
28924edb884SFrançois Tigeot 	DRM_DEBUG("\n");
29024edb884SFrançois Tigeot 
29124edb884SFrançois Tigeot 	minor = *drm_minor_get_slot(dev, type);
29224edb884SFrançois Tigeot 	if (!minor)
29324edb884SFrançois Tigeot 		return 0;
29424edb884SFrançois Tigeot 
295fcf17be7SFrançois Tigeot #if 0
29624edb884SFrançois Tigeot 	ret = drm_debugfs_init(minor, minor->index, drm_debugfs_root);
29724edb884SFrançois Tigeot 	if (ret) {
29824edb884SFrançois Tigeot 		DRM_ERROR("DRM: Failed to initialize /sys/kernel/debug/dri.\n");
299a85cb24fSFrançois Tigeot 		goto err_debugfs;
30024edb884SFrançois Tigeot 	}
30124edb884SFrançois Tigeot 
30224edb884SFrançois Tigeot 	ret = device_add(minor->kdev);
30324edb884SFrançois Tigeot 	if (ret)
30424edb884SFrançois Tigeot 		goto err_debugfs;
305fcf17be7SFrançois Tigeot #endif
30624edb884SFrançois Tigeot 
30724edb884SFrançois Tigeot 	/* replace NULL with @minor so lookups will succeed from now on */
30824edb884SFrançois Tigeot 	spin_lock_irqsave(&drm_minor_lock, flags);
30924edb884SFrançois Tigeot 	idr_replace(&drm_minors_idr, minor, minor->index);
31024edb884SFrançois Tigeot 	spin_unlock_irqrestore(&drm_minor_lock, flags);
31124edb884SFrançois Tigeot 
31224edb884SFrançois Tigeot 	DRM_DEBUG("new minor registered %d\n", minor->index);
31324edb884SFrançois Tigeot 	return 0;
31424edb884SFrançois Tigeot 
315fcf17be7SFrançois Tigeot #if 0
31624edb884SFrançois Tigeot err_debugfs:
31724edb884SFrançois Tigeot 	drm_debugfs_cleanup(minor);
318fcf17be7SFrançois Tigeot #endif
3193f2dd94aSFrançois Tigeot 	return ret;
32024edb884SFrançois Tigeot }
32124edb884SFrançois Tigeot 
drm_minor_unregister(struct drm_device * dev,unsigned int type)32224edb884SFrançois Tigeot static void drm_minor_unregister(struct drm_device *dev, unsigned int type)
32324edb884SFrançois Tigeot {
32424edb884SFrançois Tigeot 	struct drm_minor *minor;
32524edb884SFrançois Tigeot 	unsigned long flags;
32624edb884SFrançois Tigeot 
32724edb884SFrançois Tigeot 	minor = *drm_minor_get_slot(dev, type);
328fcf17be7SFrançois Tigeot #if 0
32924edb884SFrançois Tigeot 	if (!minor || !device_is_registered(minor->kdev))
330fcf17be7SFrançois Tigeot #else
331fcf17be7SFrançois Tigeot 	if (!minor)
332fcf17be7SFrançois Tigeot #endif
33324edb884SFrançois Tigeot 		return;
33424edb884SFrançois Tigeot 
33524edb884SFrançois Tigeot 	/* replace @minor with NULL so lookups will fail from now on */
33624edb884SFrançois Tigeot 	spin_lock_irqsave(&drm_minor_lock, flags);
33724edb884SFrançois Tigeot 	idr_replace(&drm_minors_idr, NULL, minor->index);
33824edb884SFrançois Tigeot 	spin_unlock_irqrestore(&drm_minor_lock, flags);
33924edb884SFrançois Tigeot 
340fcf17be7SFrançois Tigeot #if 0
34124edb884SFrançois Tigeot 	device_del(minor->kdev);
342fcf17be7SFrançois Tigeot #endif
3433f2dd94aSFrançois Tigeot 	dev_set_drvdata(minor->kdev, NULL); /* safety belt */
34424edb884SFrançois Tigeot 	drm_debugfs_cleanup(minor);
34524edb884SFrançois Tigeot }
34624edb884SFrançois Tigeot 
3474be47400SFrançois Tigeot /*
34824edb884SFrançois Tigeot  * Looks up the given minor-ID and returns the respective DRM-minor object. The
34924edb884SFrançois Tigeot  * refence-count of the underlying device is increased so you must release this
35024edb884SFrançois Tigeot  * object with drm_minor_release().
35124edb884SFrançois Tigeot  *
35224edb884SFrançois Tigeot  * As long as you hold this minor, it is guaranteed that the object and the
35324edb884SFrançois Tigeot  * minor->dev pointer will stay valid! However, the device may get unplugged and
35424edb884SFrançois Tigeot  * unregistered while you hold the minor.
35524edb884SFrançois Tigeot  */
drm_minor_acquire(unsigned int minor_id)35624edb884SFrançois Tigeot struct drm_minor *drm_minor_acquire(unsigned int minor_id)
35724edb884SFrançois Tigeot {
35824edb884SFrançois Tigeot 	struct drm_minor *minor;
35924edb884SFrançois Tigeot 	unsigned long flags;
36024edb884SFrançois Tigeot 
36124edb884SFrançois Tigeot 	spin_lock_irqsave(&drm_minor_lock, flags);
36224edb884SFrançois Tigeot 	minor = idr_find(&drm_minors_idr, minor_id);
36324edb884SFrançois Tigeot 	if (minor)
3643f2dd94aSFrançois Tigeot 		drm_dev_get(minor->dev);
36524edb884SFrançois Tigeot 	spin_unlock_irqrestore(&drm_minor_lock, flags);
36624edb884SFrançois Tigeot 
36724edb884SFrançois Tigeot 	if (!minor) {
36824edb884SFrançois Tigeot 		return ERR_PTR(-ENODEV);
3693f2dd94aSFrançois Tigeot 	} else if (drm_dev_is_unplugged(minor->dev)) {
3703f2dd94aSFrançois Tigeot 		drm_dev_put(minor->dev);
37124edb884SFrançois Tigeot 		return ERR_PTR(-ENODEV);
37224edb884SFrançois Tigeot 	}
37324edb884SFrançois Tigeot 
37424edb884SFrançois Tigeot 	return minor;
37524edb884SFrançois Tigeot }
37624edb884SFrançois Tigeot 
drm_minor_release(struct drm_minor * minor)37724edb884SFrançois Tigeot void drm_minor_release(struct drm_minor *minor)
37824edb884SFrançois Tigeot {
3793f2dd94aSFrançois Tigeot 	drm_dev_put(minor->dev);
38024edb884SFrançois Tigeot }
38124edb884SFrançois Tigeot 
38224edb884SFrançois Tigeot /**
383352ff8bdSFrançois Tigeot  * DOC: driver instance overview
384352ff8bdSFrançois Tigeot  *
385a85cb24fSFrançois Tigeot  * A device instance for a drm driver is represented by &struct drm_device. This
386352ff8bdSFrançois Tigeot  * is allocated with drm_dev_alloc(), usually from bus-specific ->probe()
387352ff8bdSFrançois Tigeot  * callbacks implemented by the driver. The driver then needs to initialize all
388352ff8bdSFrançois Tigeot  * the various subsystems for the drm device like memory management, vblank
389352ff8bdSFrançois Tigeot  * handling, modesetting support and intial output configuration plus obviously
3904be47400SFrançois Tigeot  * initialize all the corresponding hardware bits. An important part of this is
3914be47400SFrançois Tigeot  * also calling drm_dev_set_unique() to set the userspace-visible unique name of
3924be47400SFrançois Tigeot  * this device instance. Finally when everything is up and running and ready for
3934be47400SFrançois Tigeot  * userspace the device instance can be published using drm_dev_register().
394352ff8bdSFrançois Tigeot  *
395352ff8bdSFrançois Tigeot  * There is also deprecated support for initalizing device instances using
396a85cb24fSFrançois Tigeot  * bus-specific helpers and the &drm_driver.load callback. But due to
397352ff8bdSFrançois Tigeot  * backwards-compatibility needs the device instance have to be published too
398352ff8bdSFrançois Tigeot  * early, which requires unpretty global locking to make safe and is therefore
399352ff8bdSFrançois Tigeot  * only support for existing drivers not yet converted to the new scheme.
400352ff8bdSFrançois Tigeot  *
401352ff8bdSFrançois Tigeot  * When cleaning up a device instance everything needs to be done in reverse:
402352ff8bdSFrançois Tigeot  * First unpublish the device instance with drm_dev_unregister(). Then clean up
403352ff8bdSFrançois Tigeot  * any other resources allocated at device initialization and drop the driver's
4043f2dd94aSFrançois Tigeot  * reference to &drm_device using drm_dev_put().
405352ff8bdSFrançois Tigeot  *
406352ff8bdSFrançois Tigeot  * Note that the lifetime rules for &drm_device instance has still a lot of
407352ff8bdSFrançois Tigeot  * historical baggage. Hence use the reference counting provided by
4083f2dd94aSFrançois Tigeot  * drm_dev_get() and drm_dev_put() only carefully.
409352ff8bdSFrançois Tigeot  *
410a85cb24fSFrançois Tigeot  * It is recommended that drivers embed &struct drm_device into their own device
411a85cb24fSFrançois Tigeot  * structure, which is supported through drm_dev_init().
412352ff8bdSFrançois Tigeot  */
413352ff8bdSFrançois Tigeot 
4143f2dd94aSFrançois Tigeot #if 0
415352ff8bdSFrançois Tigeot /**
41624edb884SFrançois Tigeot  * drm_put_dev - Unregister and release a DRM device
41724edb884SFrançois Tigeot  * @dev: DRM device
41824edb884SFrançois Tigeot  *
41924edb884SFrançois Tigeot  * Called at module unload time or when a PCI device is unplugged.
42024edb884SFrançois Tigeot  *
42124edb884SFrançois Tigeot  * Cleans up all DRM device, calling drm_lastclose().
422352ff8bdSFrançois Tigeot  *
423352ff8bdSFrançois Tigeot  * Note: Use of this function is deprecated. It will eventually go away
4243f2dd94aSFrançois Tigeot  * completely.  Please use drm_dev_unregister() and drm_dev_put() explicitly
425352ff8bdSFrançois Tigeot  * instead to make sure that the device isn't userspace accessible any more
426352ff8bdSFrançois Tigeot  * while teardown is in progress, ensuring that userspace can't access an
427352ff8bdSFrançois Tigeot  * inconsistent state.
42824edb884SFrançois Tigeot  */
42924edb884SFrançois Tigeot void drm_put_dev(struct drm_device *dev)
43024edb884SFrançois Tigeot {
43124edb884SFrançois Tigeot 	DRM_DEBUG("\n");
43224edb884SFrançois Tigeot 
43324edb884SFrançois Tigeot 	if (!dev) {
43424edb884SFrançois Tigeot 		DRM_ERROR("cleanup called no dev\n");
43524edb884SFrançois Tigeot 		return;
43624edb884SFrançois Tigeot 	}
43724edb884SFrançois Tigeot 
43824edb884SFrançois Tigeot 	drm_dev_unregister(dev);
4393f2dd94aSFrançois Tigeot 	drm_dev_put(dev);
44024edb884SFrançois Tigeot }
44124edb884SFrançois Tigeot EXPORT_SYMBOL(drm_put_dev);
44224edb884SFrançois Tigeot 
4433f2dd94aSFrançois Tigeot static void drm_device_set_unplugged(struct drm_device *dev)
44424edb884SFrançois Tigeot {
4453f2dd94aSFrançois Tigeot 	smp_wmb();
4463f2dd94aSFrançois Tigeot 	atomic_set(&dev->unplugged, 1);
4473f2dd94aSFrançois Tigeot }
448a85cb24fSFrançois Tigeot 
4493f2dd94aSFrançois Tigeot /**
4503f2dd94aSFrançois Tigeot  * drm_dev_unplug - unplug a DRM device
4513f2dd94aSFrançois Tigeot  * @dev: DRM device
4523f2dd94aSFrançois Tigeot  *
4533f2dd94aSFrançois Tigeot  * This unplugs a hotpluggable DRM device, which makes it inaccessible to
4543f2dd94aSFrançois Tigeot  * userspace operations. Entry-points can use drm_dev_is_unplugged(). This
4553f2dd94aSFrançois Tigeot  * essentially unregisters the device like drm_dev_unregister(), but can be
4563f2dd94aSFrançois Tigeot  * called while there are still open users of @dev.
4573f2dd94aSFrançois Tigeot  */
4583f2dd94aSFrançois Tigeot void drm_dev_unplug(struct drm_device *dev)
4593f2dd94aSFrançois Tigeot {
4603f2dd94aSFrançois Tigeot 	drm_dev_unregister(dev);
46124edb884SFrançois Tigeot 
46224edb884SFrançois Tigeot 	mutex_lock(&drm_global_mutex);
46324edb884SFrançois Tigeot 	drm_device_set_unplugged(dev);
4643f2dd94aSFrançois Tigeot 	if (dev->open_count == 0)
4653f2dd94aSFrançois Tigeot 		drm_dev_put(dev);
46624edb884SFrançois Tigeot 	mutex_unlock(&drm_global_mutex);
46724edb884SFrançois Tigeot }
4683f2dd94aSFrançois Tigeot EXPORT_SYMBOL(drm_dev_unplug);
46924edb884SFrançois Tigeot 
47024edb884SFrançois Tigeot /*
47124edb884SFrançois Tigeot  * DRM internal mount
47224edb884SFrançois Tigeot  * We want to be able to allocate our own "struct address_space" to control
47324edb884SFrançois Tigeot  * memory-mappings in VRAM (or stolen RAM, ...). However, core MM does not allow
47424edb884SFrançois Tigeot  * stand-alone address_space objects, so we need an underlying inode. As there
47524edb884SFrançois Tigeot  * is no way to allocate an independent inode easily, we need a fake internal
47624edb884SFrançois Tigeot  * VFS mount-point.
47724edb884SFrançois Tigeot  *
47824edb884SFrançois Tigeot  * The drm_fs_inode_new() function allocates a new inode, drm_fs_inode_free()
47924edb884SFrançois Tigeot  * frees it again. You are allowed to use iget() and iput() to get references to
48024edb884SFrançois Tigeot  * the inode. But each drm_fs_inode_new() call must be paired with exactly one
48124edb884SFrançois Tigeot  * drm_fs_inode_free() call (which does not have to be the last iput()).
48224edb884SFrançois Tigeot  * We use drm_fs_inode_*() to manage our internal VFS mount-point and share it
48324edb884SFrançois Tigeot  * between multiple inode-users. You could, technically, call
48424edb884SFrançois Tigeot  * iget() + drm_fs_inode_free() directly after alloc and sometime later do an
48524edb884SFrançois Tigeot  * iput(), but this way you'd end up with a new vfsmount for each inode.
48624edb884SFrançois Tigeot  */
48724edb884SFrançois Tigeot 
48824edb884SFrançois Tigeot static int drm_fs_cnt;
48924edb884SFrançois Tigeot static struct vfsmount *drm_fs_mnt;
49024edb884SFrançois Tigeot 
49124edb884SFrançois Tigeot static const struct dentry_operations drm_fs_dops = {
49224edb884SFrançois Tigeot 	.d_dname	= simple_dname,
49324edb884SFrançois Tigeot };
49424edb884SFrançois Tigeot 
49524edb884SFrançois Tigeot static const struct super_operations drm_fs_sops = {
49624edb884SFrançois Tigeot 	.statfs		= simple_statfs,
49724edb884SFrançois Tigeot };
49824edb884SFrançois Tigeot 
49924edb884SFrançois Tigeot static struct dentry *drm_fs_mount(struct file_system_type *fs_type, int flags,
50024edb884SFrançois Tigeot 				   const char *dev_name, void *data)
50124edb884SFrançois Tigeot {
50224edb884SFrançois Tigeot 	return mount_pseudo(fs_type,
50324edb884SFrançois Tigeot 			    "drm:",
50424edb884SFrançois Tigeot 			    &drm_fs_sops,
50524edb884SFrançois Tigeot 			    &drm_fs_dops,
50624edb884SFrançois Tigeot 			    0x010203ff);
50724edb884SFrançois Tigeot }
50824edb884SFrançois Tigeot 
50924edb884SFrançois Tigeot static struct file_system_type drm_fs_type = {
51024edb884SFrançois Tigeot 	.name		= "drm",
51124edb884SFrançois Tigeot 	.owner		= THIS_MODULE,
51224edb884SFrançois Tigeot 	.mount		= drm_fs_mount,
51324edb884SFrançois Tigeot 	.kill_sb	= kill_anon_super,
51424edb884SFrançois Tigeot };
51524edb884SFrançois Tigeot 
51624edb884SFrançois Tigeot static struct inode *drm_fs_inode_new(void)
51724edb884SFrançois Tigeot {
51824edb884SFrançois Tigeot 	struct inode *inode;
51924edb884SFrançois Tigeot 	int r;
52024edb884SFrançois Tigeot 
52124edb884SFrançois Tigeot 	r = simple_pin_fs(&drm_fs_type, &drm_fs_mnt, &drm_fs_cnt);
52224edb884SFrançois Tigeot 	if (r < 0) {
52324edb884SFrançois Tigeot 		DRM_ERROR("Cannot mount pseudo fs: %d\n", r);
52424edb884SFrançois Tigeot 		return ERR_PTR(r);
52524edb884SFrançois Tigeot 	}
52624edb884SFrançois Tigeot 
52724edb884SFrançois Tigeot 	inode = alloc_anon_inode(drm_fs_mnt->mnt_sb);
52824edb884SFrançois Tigeot 	if (IS_ERR(inode))
52924edb884SFrançois Tigeot 		simple_release_fs(&drm_fs_mnt, &drm_fs_cnt);
53024edb884SFrançois Tigeot 
53124edb884SFrançois Tigeot 	return inode;
53224edb884SFrançois Tigeot }
53324edb884SFrançois Tigeot 
53424edb884SFrançois Tigeot static void drm_fs_inode_free(struct inode *inode)
53524edb884SFrançois Tigeot {
53624edb884SFrançois Tigeot 	if (inode) {
53724edb884SFrançois Tigeot 		iput(inode);
53824edb884SFrançois Tigeot 		simple_release_fs(&drm_fs_mnt, &drm_fs_cnt);
53924edb884SFrançois Tigeot 	}
54024edb884SFrançois Tigeot }
541fcf17be7SFrançois Tigeot #endif
54224edb884SFrançois Tigeot 
54324edb884SFrançois Tigeot /**
5441dedbd3bSFrançois Tigeot  * drm_dev_init - Initialise new DRM device
5451dedbd3bSFrançois Tigeot  * @dev: DRM device
5461dedbd3bSFrançois Tigeot  * @driver: DRM driver
54724edb884SFrançois Tigeot  * @parent: Parent device object
54824edb884SFrançois Tigeot  *
5491dedbd3bSFrançois Tigeot  * Initialize a new DRM device. No device registration is done.
55024edb884SFrançois Tigeot  * Call drm_dev_register() to advertice the device to user space and register it
551352ff8bdSFrançois Tigeot  * with other core subsystems. This should be done last in the device
552352ff8bdSFrançois Tigeot  * initialization sequence to make sure userspace can't access an inconsistent
553352ff8bdSFrançois Tigeot  * state.
55424edb884SFrançois Tigeot  *
5553f2dd94aSFrançois Tigeot  * The initial ref-count of the object is 1. Use drm_dev_get() and
5563f2dd94aSFrançois Tigeot  * drm_dev_put() to take and drop further ref-counts.
55724edb884SFrançois Tigeot  *
5582c9916cdSFrançois Tigeot  * Note that for purely virtual devices @parent can be NULL.
5592c9916cdSFrançois Tigeot  *
5601dedbd3bSFrançois Tigeot  * Drivers that do not want to allocate their own device struct
561a85cb24fSFrançois Tigeot  * embedding &struct drm_device can call drm_dev_alloc() instead. For drivers
562a85cb24fSFrançois Tigeot  * that do embed &struct drm_device it must be placed first in the overall
563a85cb24fSFrançois Tigeot  * structure, and the overall structure must be allocated using kmalloc(): The
564a85cb24fSFrançois Tigeot  * drm core's release function unconditionally calls kfree() on the @dev pointer
565a85cb24fSFrançois Tigeot  * when the final reference is released. To override this behaviour, and so
566a85cb24fSFrançois Tigeot  * allow embedding of the drm_device inside the driver's device struct at an
567a85cb24fSFrançois Tigeot  * arbitrary offset, you must supply a &drm_driver.release callback and control
568a85cb24fSFrançois Tigeot  * the finalization explicitly.
5691dedbd3bSFrançois Tigeot  *
57024edb884SFrançois Tigeot  * RETURNS:
5711dedbd3bSFrançois Tigeot  * 0 on success, or error code on failure.
57224edb884SFrançois Tigeot  */
drm_dev_init(struct drm_device * dev,struct drm_driver * driver,struct device * parent)5731dedbd3bSFrançois Tigeot int drm_dev_init(struct drm_device *dev,
5741dedbd3bSFrançois Tigeot 		 struct drm_driver *driver,
57524edb884SFrançois Tigeot 		 struct device *parent)
57624edb884SFrançois Tigeot {
57724edb884SFrançois Tigeot 	int ret;
578bb916eedSFrançois Tigeot #ifdef __DragonFly__
579bb916eedSFrançois Tigeot 	struct drm_softc *softc = device_get_softc(parent->bsddev);
580bb916eedSFrançois Tigeot 
581bb916eedSFrançois Tigeot 	softc->drm_driver_data = dev;
582bb916eedSFrançois Tigeot #endif
58324edb884SFrançois Tigeot 
5843f2dd94aSFrançois Tigeot 	if (!drm_core_init_complete) {
5853f2dd94aSFrançois Tigeot 		DRM_ERROR("DRM core is not initialized\n");
5863f2dd94aSFrançois Tigeot 		return -ENODEV;
5873f2dd94aSFrançois Tigeot 	}
5883f2dd94aSFrançois Tigeot 
58924edb884SFrançois Tigeot 	kref_init(&dev->ref);
59024edb884SFrançois Tigeot 	dev->dev = parent;
59124edb884SFrançois Tigeot 	dev->driver = driver;
59224edb884SFrançois Tigeot 
59324edb884SFrançois Tigeot 	INIT_LIST_HEAD(&dev->filelist);
59424edb884SFrançois Tigeot 	INIT_LIST_HEAD(&dev->ctxlist);
59524edb884SFrançois Tigeot 	INIT_LIST_HEAD(&dev->vmalist);
59624edb884SFrançois Tigeot 	INIT_LIST_HEAD(&dev->maplist);
59724edb884SFrançois Tigeot 	INIT_LIST_HEAD(&dev->vblank_event_list);
59824edb884SFrançois Tigeot 
5999a49c39cSFrançois Tigeot 	lockinit(&dev->buf_lock, "drmdbl", 0, 0);
600a85cb24fSFrançois Tigeot 	lockinit(&dev->event_lock, "drmev", 0, 0);
601fcf17be7SFrançois Tigeot 	lockinit(&dev->struct_mutex, "drmslk", 0, LK_CANRECURSE);
602fcf17be7SFrançois Tigeot 	lockinit(&dev->filelist_mutex, "drmflm", 0, LK_CANRECURSE);
603fcf17be7SFrançois Tigeot 	lockinit(&dev->ctxlist_mutex, "drmclm", 0, LK_CANRECURSE);
604fcf17be7SFrançois Tigeot 	lockinit(&dev->master_mutex, "drmmm", 0, LK_CANRECURSE);
60524edb884SFrançois Tigeot 
606fcf17be7SFrançois Tigeot #ifndef __DragonFly__
60724edb884SFrançois Tigeot 	dev->anon_inode = drm_fs_inode_new();
60824edb884SFrançois Tigeot 	if (IS_ERR(dev->anon_inode)) {
60924edb884SFrançois Tigeot 		ret = PTR_ERR(dev->anon_inode);
61024edb884SFrançois Tigeot 		DRM_ERROR("Cannot allocate anonymous inode: %d\n", ret);
61124edb884SFrançois Tigeot 		goto err_free;
61224edb884SFrançois Tigeot 	}
613fcf17be7SFrançois Tigeot #else
614fcf17be7SFrançois Tigeot 	dev->anon_inode = NULL;
61555f3230cSFrançois Tigeot 	dev->pci_domain = pci_get_domain(dev->dev->bsddev);
61655f3230cSFrançois Tigeot 	dev->pci_bus = pci_get_bus(dev->dev->bsddev);
61755f3230cSFrançois Tigeot 	dev->pci_slot = pci_get_slot(dev->dev->bsddev);
61855f3230cSFrançois Tigeot 	dev->pci_func = pci_get_function(dev->dev->bsddev);
61955f3230cSFrançois Tigeot 	drm_sysctl_init(dev);
620fcf17be7SFrançois Tigeot #endif
62124edb884SFrançois Tigeot 
62224edb884SFrançois Tigeot 	if (drm_core_check_feature(dev, DRIVER_RENDER)) {
62324edb884SFrançois Tigeot 		ret = drm_minor_alloc(dev, DRM_MINOR_RENDER);
62424edb884SFrançois Tigeot 		if (ret)
62524edb884SFrançois Tigeot 			goto err_minors;
62624edb884SFrançois Tigeot 	}
62724edb884SFrançois Tigeot 
6281dedbd3bSFrançois Tigeot 	ret = drm_minor_alloc(dev, DRM_MINOR_PRIMARY);
62924edb884SFrançois Tigeot 	if (ret)
63024edb884SFrançois Tigeot 		goto err_minors;
63124edb884SFrançois Tigeot 
6321dedbd3bSFrançois Tigeot 	ret = drm_ht_create(&dev->map_hash, 12);
6331dedbd3bSFrançois Tigeot 	if (ret)
63424edb884SFrançois Tigeot 		goto err_minors;
63524edb884SFrançois Tigeot 
636a05eeebfSFrançois Tigeot 	drm_legacy_ctxbitmap_init(dev);
63724edb884SFrançois Tigeot 
6381b13d190SFrançois Tigeot 	if (drm_core_check_feature(dev, DRIVER_GEM)) {
63924edb884SFrançois Tigeot 		ret = drm_gem_init(dev);
64024edb884SFrançois Tigeot 		if (ret) {
64124edb884SFrançois Tigeot 			DRM_ERROR("Cannot initialize graphics execution manager (GEM)\n");
64224edb884SFrançois Tigeot 			goto err_ctxbitmap;
64324edb884SFrançois Tigeot 		}
64424edb884SFrançois Tigeot 	}
64524edb884SFrançois Tigeot 
646a85cb24fSFrançois Tigeot 	/* Use the parent device name as DRM device unique identifier, but fall
647a85cb24fSFrançois Tigeot 	 * back to the driver name for virtual devices like vgem. */
648fcf17be7SFrançois Tigeot #if 0
649a85cb24fSFrançois Tigeot 	ret = drm_dev_set_unique(dev, parent ? dev_name(parent) : driver->name);
650aee94f86SFrançois Tigeot 	if (ret)
651aee94f86SFrançois Tigeot 		goto err_setunique;
652fcf17be7SFrançois Tigeot #endif
653aee94f86SFrançois Tigeot 
6541dedbd3bSFrançois Tigeot 	return 0;
65524edb884SFrançois Tigeot 
656fcf17be7SFrançois Tigeot #if 0
657aee94f86SFrançois Tigeot err_setunique:
658aee94f86SFrançois Tigeot 	if (drm_core_check_feature(dev, DRIVER_GEM))
659aee94f86SFrançois Tigeot 		drm_gem_destroy(dev);
660fcf17be7SFrançois Tigeot #endif
66124edb884SFrançois Tigeot err_ctxbitmap:
66224edb884SFrançois Tigeot 	drm_legacy_ctxbitmap_cleanup(dev);
66324edb884SFrançois Tigeot 	drm_ht_remove(&dev->map_hash);
66424edb884SFrançois Tigeot err_minors:
6651dedbd3bSFrançois Tigeot 	drm_minor_free(dev, DRM_MINOR_PRIMARY);
66624edb884SFrançois Tigeot 	drm_minor_free(dev, DRM_MINOR_RENDER);
66724edb884SFrançois Tigeot 	drm_minor_free(dev, DRM_MINOR_CONTROL);
668fcf17be7SFrançois Tigeot #ifndef __DragonFly__
66924edb884SFrançois Tigeot 	drm_fs_inode_free(dev->anon_inode);
67024edb884SFrançois Tigeot err_free:
671fcf17be7SFrançois Tigeot #endif
67224edb884SFrançois Tigeot 	mutex_destroy(&dev->master_mutex);
6734be47400SFrançois Tigeot 	mutex_destroy(&dev->ctxlist_mutex);
6744be47400SFrançois Tigeot 	mutex_destroy(&dev->filelist_mutex);
6754be47400SFrançois Tigeot 	mutex_destroy(&dev->struct_mutex);
67655f3230cSFrançois Tigeot #ifdef __DragonFly__
67755f3230cSFrançois Tigeot 	drm_sysctl_cleanup(dev);
67855f3230cSFrançois Tigeot #endif
6791dedbd3bSFrançois Tigeot 	return ret;
6801dedbd3bSFrançois Tigeot }
6811dedbd3bSFrançois Tigeot EXPORT_SYMBOL(drm_dev_init);
6821dedbd3bSFrançois Tigeot 
6831dedbd3bSFrançois Tigeot /**
684a85cb24fSFrançois Tigeot  * drm_dev_fini - Finalize a dead DRM device
685a85cb24fSFrançois Tigeot  * @dev: DRM device
686a85cb24fSFrançois Tigeot  *
687a85cb24fSFrançois Tigeot  * Finalize a dead DRM device. This is the converse to drm_dev_init() and
688a85cb24fSFrançois Tigeot  * frees up all data allocated by it. All driver private data should be
689a85cb24fSFrançois Tigeot  * finalized first. Note that this function does not free the @dev, that is
690a85cb24fSFrançois Tigeot  * left to the caller.
691a85cb24fSFrançois Tigeot  *
692a85cb24fSFrançois Tigeot  * The ref-count of @dev must be zero, and drm_dev_fini() should only be called
693a85cb24fSFrançois Tigeot  * from a &drm_driver.release callback.
694a85cb24fSFrançois Tigeot  */
drm_dev_fini(struct drm_device * dev)695a85cb24fSFrançois Tigeot void drm_dev_fini(struct drm_device *dev)
696a85cb24fSFrançois Tigeot {
697a85cb24fSFrançois Tigeot 	drm_vblank_cleanup(dev);
698a85cb24fSFrançois Tigeot 
699a85cb24fSFrançois Tigeot 	if (drm_core_check_feature(dev, DRIVER_GEM))
700a85cb24fSFrançois Tigeot 		drm_gem_destroy(dev);
701a85cb24fSFrançois Tigeot 
702a85cb24fSFrançois Tigeot 	drm_legacy_ctxbitmap_cleanup(dev);
703a85cb24fSFrançois Tigeot 	drm_ht_remove(&dev->map_hash);
704a85cb24fSFrançois Tigeot #if 0
705a85cb24fSFrançois Tigeot 	drm_fs_inode_free(dev->anon_inode);
706a85cb24fSFrançois Tigeot #endif
707a85cb24fSFrançois Tigeot 
708a85cb24fSFrançois Tigeot 	drm_minor_free(dev, DRM_MINOR_PRIMARY);
709a85cb24fSFrançois Tigeot 	drm_minor_free(dev, DRM_MINOR_RENDER);
710a85cb24fSFrançois Tigeot 	drm_minor_free(dev, DRM_MINOR_CONTROL);
711a85cb24fSFrançois Tigeot 
712a85cb24fSFrançois Tigeot 	mutex_destroy(&dev->master_mutex);
713a85cb24fSFrançois Tigeot 	mutex_destroy(&dev->ctxlist_mutex);
714a85cb24fSFrançois Tigeot 	mutex_destroy(&dev->filelist_mutex);
715a85cb24fSFrançois Tigeot 	mutex_destroy(&dev->struct_mutex);
716a85cb24fSFrançois Tigeot 	kfree(dev->unique);
717a85cb24fSFrançois Tigeot }
718a85cb24fSFrançois Tigeot EXPORT_SYMBOL(drm_dev_fini);
719a85cb24fSFrançois Tigeot 
720a85cb24fSFrançois Tigeot /**
7211dedbd3bSFrançois Tigeot  * drm_dev_alloc - Allocate new DRM device
7221dedbd3bSFrançois Tigeot  * @driver: DRM driver to allocate device for
7231dedbd3bSFrançois Tigeot  * @parent: Parent device object
7241dedbd3bSFrançois Tigeot  *
7251dedbd3bSFrançois Tigeot  * Allocate and initialize a new DRM device. No device registration is done.
7261dedbd3bSFrançois Tigeot  * Call drm_dev_register() to advertice the device to user space and register it
7271dedbd3bSFrançois Tigeot  * with other core subsystems. This should be done last in the device
7281dedbd3bSFrançois Tigeot  * initialization sequence to make sure userspace can't access an inconsistent
7291dedbd3bSFrançois Tigeot  * state.
7301dedbd3bSFrançois Tigeot  *
7313f2dd94aSFrançois Tigeot  * The initial ref-count of the object is 1. Use drm_dev_get() and
7323f2dd94aSFrançois Tigeot  * drm_dev_put() to take and drop further ref-counts.
7331dedbd3bSFrançois Tigeot  *
7341dedbd3bSFrançois Tigeot  * Note that for purely virtual devices @parent can be NULL.
7351dedbd3bSFrançois Tigeot  *
736a85cb24fSFrançois Tigeot  * Drivers that wish to subclass or embed &struct drm_device into their
7371dedbd3bSFrançois Tigeot  * own struct should look at using drm_dev_init() instead.
7381dedbd3bSFrançois Tigeot  *
7391dedbd3bSFrançois Tigeot  * RETURNS:
7401dedbd3bSFrançois Tigeot  * Pointer to new DRM device, or ERR_PTR on failure.
7411dedbd3bSFrançois Tigeot  */
drm_dev_alloc(struct drm_driver * driver,struct device * parent)7421dedbd3bSFrançois Tigeot struct drm_device *drm_dev_alloc(struct drm_driver *driver,
7431dedbd3bSFrançois Tigeot 				 struct device *parent)
7441dedbd3bSFrançois Tigeot {
7451dedbd3bSFrançois Tigeot 	struct drm_device *dev;
7461dedbd3bSFrançois Tigeot 	int ret;
7471dedbd3bSFrançois Tigeot 
7481dedbd3bSFrançois Tigeot 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
7491dedbd3bSFrançois Tigeot 	if (!dev)
7501dedbd3bSFrançois Tigeot 		return ERR_PTR(-ENOMEM);
7511dedbd3bSFrançois Tigeot 
7521dedbd3bSFrançois Tigeot 	ret = drm_dev_init(dev, driver, parent);
7531dedbd3bSFrançois Tigeot 	if (ret) {
75424edb884SFrançois Tigeot 		kfree(dev);
7551dedbd3bSFrançois Tigeot 		return ERR_PTR(ret);
7561dedbd3bSFrançois Tigeot 	}
7571dedbd3bSFrançois Tigeot 
7581dedbd3bSFrançois Tigeot 	return dev;
75924edb884SFrançois Tigeot }
76024edb884SFrançois Tigeot EXPORT_SYMBOL(drm_dev_alloc);
76124edb884SFrançois Tigeot 
drm_dev_release(struct kref * ref)76224edb884SFrançois Tigeot static void drm_dev_release(struct kref *ref)
76324edb884SFrançois Tigeot {
76424edb884SFrançois Tigeot 	struct drm_device *dev = container_of(ref, struct drm_device, ref);
76524edb884SFrançois Tigeot 
766a85cb24fSFrançois Tigeot 	if (dev->driver->release) {
767a85cb24fSFrançois Tigeot 		dev->driver->release(dev);
768a85cb24fSFrançois Tigeot 	} else {
769a85cb24fSFrançois Tigeot 		drm_dev_fini(dev);
77024edb884SFrançois Tigeot 		kfree(dev);
77124edb884SFrançois Tigeot 	}
772a85cb24fSFrançois Tigeot }
77324edb884SFrançois Tigeot 
77424edb884SFrançois Tigeot /**
7753f2dd94aSFrançois Tigeot  * drm_dev_get - Take reference of a DRM device
77624edb884SFrançois Tigeot  * @dev: device to take reference of or NULL
77724edb884SFrançois Tigeot  *
77824edb884SFrançois Tigeot  * This increases the ref-count of @dev by one. You *must* already own a
7793f2dd94aSFrançois Tigeot  * reference when calling this. Use drm_dev_put() to drop this reference
78024edb884SFrançois Tigeot  * again.
78124edb884SFrançois Tigeot  *
78224edb884SFrançois Tigeot  * This function never fails. However, this function does not provide *any*
78324edb884SFrançois Tigeot  * guarantee whether the device is alive or running. It only provides a
78424edb884SFrançois Tigeot  * reference to the object and the memory associated with it.
78524edb884SFrançois Tigeot  */
drm_dev_get(struct drm_device * dev)7863f2dd94aSFrançois Tigeot void drm_dev_get(struct drm_device *dev)
78724edb884SFrançois Tigeot {
78824edb884SFrançois Tigeot 	if (dev)
78924edb884SFrançois Tigeot 		kref_get(&dev->ref);
79024edb884SFrançois Tigeot }
7913f2dd94aSFrançois Tigeot EXPORT_SYMBOL(drm_dev_get);
79224edb884SFrançois Tigeot 
79324edb884SFrançois Tigeot /**
7943f2dd94aSFrançois Tigeot  * drm_dev_put - Drop reference of a DRM device
79524edb884SFrançois Tigeot  * @dev: device to drop reference of or NULL
79624edb884SFrançois Tigeot  *
79724edb884SFrançois Tigeot  * This decreases the ref-count of @dev by one. The device is destroyed if the
79824edb884SFrançois Tigeot  * ref-count drops to zero.
79924edb884SFrançois Tigeot  */
drm_dev_put(struct drm_device * dev)8003f2dd94aSFrançois Tigeot void drm_dev_put(struct drm_device *dev)
80124edb884SFrançois Tigeot {
80224edb884SFrançois Tigeot 	if (dev)
80324edb884SFrançois Tigeot 		kref_put(&dev->ref, drm_dev_release);
8043f2dd94aSFrançois Tigeot }
8053f2dd94aSFrançois Tigeot EXPORT_SYMBOL(drm_dev_put);
8063f2dd94aSFrançois Tigeot 
8073f2dd94aSFrançois Tigeot /**
8083f2dd94aSFrançois Tigeot  * drm_dev_unref - Drop reference of a DRM device
8093f2dd94aSFrançois Tigeot  * @dev: device to drop reference of or NULL
8103f2dd94aSFrançois Tigeot  *
8113f2dd94aSFrançois Tigeot  * This is a compatibility alias for drm_dev_put() and should not be used by new
8123f2dd94aSFrançois Tigeot  * code.
8133f2dd94aSFrançois Tigeot  */
drm_dev_unref(struct drm_device * dev)8143f2dd94aSFrançois Tigeot void drm_dev_unref(struct drm_device *dev)
8153f2dd94aSFrançois Tigeot {
8163f2dd94aSFrançois Tigeot 	drm_dev_put(dev);
81724edb884SFrançois Tigeot }
81824edb884SFrançois Tigeot EXPORT_SYMBOL(drm_dev_unref);
81924edb884SFrançois Tigeot 
create_compat_control_link(struct drm_device * dev)8204be47400SFrançois Tigeot static int create_compat_control_link(struct drm_device *dev)
8214be47400SFrançois Tigeot {
8224be47400SFrançois Tigeot 	struct drm_minor *minor;
8234be47400SFrançois Tigeot 	char *name;
8244be47400SFrançois Tigeot 	int ret;
8254be47400SFrançois Tigeot 
8264be47400SFrançois Tigeot 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
8274be47400SFrançois Tigeot 		return 0;
8284be47400SFrançois Tigeot 
8294be47400SFrançois Tigeot 	minor = *drm_minor_get_slot(dev, DRM_MINOR_PRIMARY);
8304be47400SFrançois Tigeot 	if (!minor)
8314be47400SFrançois Tigeot 		return 0;
8324be47400SFrançois Tigeot 
8334be47400SFrançois Tigeot 	/*
8344be47400SFrançois Tigeot 	 * Some existing userspace out there uses the existing of the controlD*
8354be47400SFrançois Tigeot 	 * sysfs files to figure out whether it's a modeset driver. It only does
8364be47400SFrançois Tigeot 	 * readdir, hence a symlink is sufficient (and the least confusing
8374be47400SFrançois Tigeot 	 * option). Otherwise controlD* is entirely unused.
8384be47400SFrançois Tigeot 	 *
8394be47400SFrançois Tigeot 	 * Old controlD chardev have been allocated in the range
8404be47400SFrançois Tigeot 	 * 64-127.
8414be47400SFrançois Tigeot 	 */
8424be47400SFrançois Tigeot 	name = kasprintf(GFP_KERNEL, "controlD%d", minor->index + 64);
8434be47400SFrançois Tigeot 	if (!name)
8444be47400SFrançois Tigeot 		return -ENOMEM;
8454be47400SFrançois Tigeot 
8464be47400SFrançois Tigeot #ifndef __DragonFly__	/* DragonFly's libdrm does not need this */
8474be47400SFrançois Tigeot 	ret = sysfs_create_link(minor->kdev->kobj.parent,
8484be47400SFrançois Tigeot 				&minor->kdev->kobj,
8494be47400SFrançois Tigeot 				name);
8504be47400SFrançois Tigeot #else
8514be47400SFrançois Tigeot 	ret = 0;
8524be47400SFrançois Tigeot #endif
8534be47400SFrançois Tigeot 
8544be47400SFrançois Tigeot 	kfree(name);
8554be47400SFrançois Tigeot 
8564be47400SFrançois Tigeot 	return ret;
8574be47400SFrançois Tigeot }
8584be47400SFrançois Tigeot 
remove_compat_control_link(struct drm_device * dev)8594be47400SFrançois Tigeot static void remove_compat_control_link(struct drm_device *dev)
8604be47400SFrançois Tigeot {
8614be47400SFrançois Tigeot 	struct drm_minor *minor;
8624be47400SFrançois Tigeot 	char *name;
8634be47400SFrançois Tigeot 
8644be47400SFrançois Tigeot 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
8654be47400SFrançois Tigeot 		return;
8664be47400SFrançois Tigeot 
8674be47400SFrançois Tigeot 	minor = *drm_minor_get_slot(dev, DRM_MINOR_PRIMARY);
8684be47400SFrançois Tigeot 	if (!minor)
8694be47400SFrançois Tigeot 		return;
8704be47400SFrançois Tigeot 
8714be47400SFrançois Tigeot 	name = kasprintf(GFP_KERNEL, "controlD%d", minor->index);
8724be47400SFrançois Tigeot 	if (!name)
8734be47400SFrançois Tigeot 		return;
8744be47400SFrançois Tigeot 
8754be47400SFrançois Tigeot #ifndef __DragonFly__
8764be47400SFrançois Tigeot 	sysfs_remove_link(minor->kdev->kobj.parent, name);
8774be47400SFrançois Tigeot #endif
8784be47400SFrançois Tigeot 
8794be47400SFrançois Tigeot 	kfree(name);
8804be47400SFrançois Tigeot }
8814be47400SFrançois Tigeot 
88224edb884SFrançois Tigeot /**
88324edb884SFrançois Tigeot  * drm_dev_register - Register DRM device
88424edb884SFrançois Tigeot  * @dev: Device to register
88524edb884SFrançois Tigeot  * @flags: Flags passed to the driver's .load() function
88624edb884SFrançois Tigeot  *
88724edb884SFrançois Tigeot  * Register the DRM device @dev with the system, advertise device to user-space
88824edb884SFrançois Tigeot  * and start normal device operation. @dev must be allocated via drm_dev_alloc()
8891dedbd3bSFrançois Tigeot  * previously.
89024edb884SFrançois Tigeot  *
89124edb884SFrançois Tigeot  * Never call this twice on any device!
89224edb884SFrançois Tigeot  *
893352ff8bdSFrançois Tigeot  * NOTE: To ensure backward compatibility with existing drivers method this
894a85cb24fSFrançois Tigeot  * function calls the &drm_driver.load method after registering the device
895a85cb24fSFrançois Tigeot  * nodes, creating race conditions. Usage of the &drm_driver.load methods is
896a85cb24fSFrançois Tigeot  * therefore deprecated, drivers must perform all initialization before calling
897352ff8bdSFrançois Tigeot  * drm_dev_register().
898352ff8bdSFrançois Tigeot  *
89924edb884SFrançois Tigeot  * RETURNS:
90024edb884SFrançois Tigeot  * 0 on success, negative error code on failure.
90124edb884SFrançois Tigeot  */
drm_dev_register(struct drm_device * dev,unsigned long flags)90224edb884SFrançois Tigeot int drm_dev_register(struct drm_device *dev, unsigned long flags)
90324edb884SFrançois Tigeot {
904a85cb24fSFrançois Tigeot 	struct drm_driver *driver = dev->driver;
90524edb884SFrançois Tigeot 	int ret;
90624edb884SFrançois Tigeot 
90724edb884SFrançois Tigeot 	mutex_lock(&drm_global_mutex);
90824edb884SFrançois Tigeot 
90924edb884SFrançois Tigeot 	ret = drm_minor_register(dev, DRM_MINOR_CONTROL);
91024edb884SFrançois Tigeot 	if (ret)
91124edb884SFrançois Tigeot 		goto err_minors;
91224edb884SFrançois Tigeot 
91324edb884SFrançois Tigeot 	ret = drm_minor_register(dev, DRM_MINOR_RENDER);
91424edb884SFrançois Tigeot 	if (ret)
91524edb884SFrançois Tigeot 		goto err_minors;
91624edb884SFrançois Tigeot 
9171dedbd3bSFrançois Tigeot 	ret = drm_minor_register(dev, DRM_MINOR_PRIMARY);
91824edb884SFrançois Tigeot 	if (ret)
91924edb884SFrançois Tigeot 		goto err_minors;
92024edb884SFrançois Tigeot 
9214be47400SFrançois Tigeot 	ret = create_compat_control_link(dev);
9224be47400SFrançois Tigeot 	if (ret)
9234be47400SFrançois Tigeot 		goto err_minors;
9244be47400SFrançois Tigeot 
9254be47400SFrançois Tigeot 	dev->registered = true;
9264be47400SFrançois Tigeot 
92724edb884SFrançois Tigeot 	if (dev->driver->load) {
92824edb884SFrançois Tigeot 		ret = dev->driver->load(dev, flags);
92924edb884SFrançois Tigeot 		if (ret)
93024edb884SFrançois Tigeot 			goto err_minors;
93124edb884SFrançois Tigeot 	}
93224edb884SFrançois Tigeot 
9331dedbd3bSFrançois Tigeot 	if (drm_core_check_feature(dev, DRIVER_MODESET))
9341dedbd3bSFrançois Tigeot 		drm_modeset_register_all(dev);
9351dedbd3bSFrançois Tigeot 
93624edb884SFrançois Tigeot 	ret = 0;
937a85cb24fSFrançois Tigeot 
938a85cb24fSFrançois Tigeot 	DRM_INFO("Initialized %s %d.%d.%d %s for %s on minor %d\n",
939a85cb24fSFrançois Tigeot 		 driver->name, driver->major, driver->minor,
940a85cb24fSFrançois Tigeot 		 driver->patchlevel, driver->date,
941a85cb24fSFrançois Tigeot 		 dev->dev ? dev_name(dev->dev) : "virtual device",
942a85cb24fSFrançois Tigeot 		 dev->primary->index);
943a85cb24fSFrançois Tigeot 
94424edb884SFrançois Tigeot 	goto out_unlock;
94524edb884SFrançois Tigeot 
94624edb884SFrançois Tigeot err_minors:
9474be47400SFrançois Tigeot 	remove_compat_control_link(dev);
9481dedbd3bSFrançois Tigeot 	drm_minor_unregister(dev, DRM_MINOR_PRIMARY);
94924edb884SFrançois Tigeot 	drm_minor_unregister(dev, DRM_MINOR_RENDER);
95024edb884SFrançois Tigeot 	drm_minor_unregister(dev, DRM_MINOR_CONTROL);
95124edb884SFrançois Tigeot out_unlock:
95224edb884SFrançois Tigeot 	mutex_unlock(&drm_global_mutex);
95324edb884SFrançois Tigeot 	return ret;
95424edb884SFrançois Tigeot }
95524edb884SFrançois Tigeot EXPORT_SYMBOL(drm_dev_register);
95624edb884SFrançois Tigeot 
95724edb884SFrançois Tigeot /**
95824edb884SFrançois Tigeot  * drm_dev_unregister - Unregister DRM device
95924edb884SFrançois Tigeot  * @dev: Device to unregister
96024edb884SFrançois Tigeot  *
96124edb884SFrançois Tigeot  * Unregister the DRM device from the system. This does the reverse of
96224edb884SFrançois Tigeot  * drm_dev_register() but does not deallocate the device. The caller must call
9633f2dd94aSFrançois Tigeot  * drm_dev_put() to drop their final reference.
9643f2dd94aSFrançois Tigeot  *
9653f2dd94aSFrançois Tigeot  * A special form of unregistering for hotpluggable devices is drm_dev_unplug(),
9663f2dd94aSFrançois Tigeot  * which can be called while there are still open users of @dev.
967352ff8bdSFrançois Tigeot  *
968352ff8bdSFrançois Tigeot  * This should be called first in the device teardown code to make sure
969352ff8bdSFrançois Tigeot  * userspace can't access the device instance any more.
97024edb884SFrançois Tigeot  */
drm_dev_unregister(struct drm_device * dev)97124edb884SFrançois Tigeot void drm_dev_unregister(struct drm_device *dev)
97224edb884SFrançois Tigeot {
97324edb884SFrançois Tigeot 	struct drm_map_list *r_list, *list_temp;
97424edb884SFrançois Tigeot 
9753f2dd94aSFrançois Tigeot 	if (drm_core_check_feature(dev, DRIVER_LEGACY))
97624edb884SFrançois Tigeot 		drm_lastclose(dev);
97724edb884SFrançois Tigeot 
9784be47400SFrançois Tigeot 	dev->registered = false;
9794be47400SFrançois Tigeot 
9801dedbd3bSFrançois Tigeot 	if (drm_core_check_feature(dev, DRIVER_MODESET))
9811dedbd3bSFrançois Tigeot 		drm_modeset_unregister_all(dev);
9821dedbd3bSFrançois Tigeot 
98324edb884SFrançois Tigeot 	if (dev->driver->unload)
98424edb884SFrançois Tigeot 		dev->driver->unload(dev);
98524edb884SFrançois Tigeot 
9861dedbd3bSFrançois Tigeot #if 0
98724edb884SFrançois Tigeot 	if (dev->agp)
98824edb884SFrançois Tigeot 		drm_pci_agp_destroy(dev);
9891dedbd3bSFrançois Tigeot #endif
99024edb884SFrançois Tigeot 
99124edb884SFrançois Tigeot 	list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head)
9921b13d190SFrançois Tigeot 		drm_legacy_rmmap(dev, r_list->map);
99324edb884SFrançois Tigeot 
9944be47400SFrançois Tigeot 	remove_compat_control_link(dev);
9951dedbd3bSFrançois Tigeot 	drm_minor_unregister(dev, DRM_MINOR_PRIMARY);
99624edb884SFrançois Tigeot 	drm_minor_unregister(dev, DRM_MINOR_RENDER);
99724edb884SFrançois Tigeot 	drm_minor_unregister(dev, DRM_MINOR_CONTROL);
99824edb884SFrançois Tigeot }
99924edb884SFrançois Tigeot EXPORT_SYMBOL(drm_dev_unregister);
100024edb884SFrançois Tigeot 
10014be47400SFrançois Tigeot #if 0
10024be47400SFrançois Tigeot /**
10034be47400SFrançois Tigeot  * drm_dev_set_unique - Set the unique name of a DRM device
10044be47400SFrançois Tigeot  * @dev: device of which to set the unique name
10054be47400SFrançois Tigeot  * @name: unique name
10064be47400SFrançois Tigeot  *
10074be47400SFrançois Tigeot  * Sets the unique name of a DRM device using the specified string. Drivers
10084be47400SFrançois Tigeot  * can use this at driver probe time if the unique name of the devices they
10094be47400SFrançois Tigeot  * drive is static.
10104be47400SFrançois Tigeot  *
10114be47400SFrançois Tigeot  * Return: 0 on success or a negative error code on failure.
10124be47400SFrançois Tigeot  */
10134be47400SFrançois Tigeot int drm_dev_set_unique(struct drm_device *dev, const char *name)
10144be47400SFrançois Tigeot {
10154be47400SFrançois Tigeot 	kfree(dev->unique);
10164be47400SFrançois Tigeot 	dev->unique = kstrdup(name, GFP_KERNEL);
10174be47400SFrançois Tigeot 
10184be47400SFrançois Tigeot 	return dev->unique ? 0 : -ENOMEM;
10194be47400SFrançois Tigeot }
10204be47400SFrançois Tigeot EXPORT_SYMBOL(drm_dev_set_unique);
10214be47400SFrançois Tigeot 
102224edb884SFrançois Tigeot /*
102324edb884SFrançois Tigeot  * DRM Core
102424edb884SFrançois Tigeot  * The DRM core module initializes all global DRM objects and makes them
102524edb884SFrançois Tigeot  * available to drivers. Once setup, drivers can probe their respective
102624edb884SFrançois Tigeot  * devices.
102724edb884SFrançois Tigeot  * Currently, core management includes:
102824edb884SFrançois Tigeot  *  - The "DRM-Global" key/value database
102924edb884SFrançois Tigeot  *  - Global ID management for connectors
103024edb884SFrançois Tigeot  *  - DRM major number allocation
103124edb884SFrançois Tigeot  *  - DRM minor management
103224edb884SFrançois Tigeot  *  - DRM sysfs class
103324edb884SFrançois Tigeot  *  - DRM debugfs root
103424edb884SFrançois Tigeot  *
103524edb884SFrançois Tigeot  * Furthermore, the DRM core provides dynamic char-dev lookups. For each
103624edb884SFrançois Tigeot  * interface registered on a DRM device, you can request minor numbers from DRM
103724edb884SFrançois Tigeot  * core. DRM core takes care of major-number management and char-dev
103824edb884SFrançois Tigeot  * registration. A stub ->open() callback forwards any open() requests to the
103924edb884SFrançois Tigeot  * registered minor.
104024edb884SFrançois Tigeot  */
104124edb884SFrançois Tigeot 
104224edb884SFrançois Tigeot static int drm_stub_open(struct inode *inode, struct file *filp)
104324edb884SFrançois Tigeot {
104424edb884SFrançois Tigeot 	const struct file_operations *new_fops;
104524edb884SFrançois Tigeot 	struct drm_minor *minor;
104624edb884SFrançois Tigeot 	int err;
104724edb884SFrançois Tigeot 
104824edb884SFrançois Tigeot 	DRM_DEBUG("\n");
104924edb884SFrançois Tigeot 
105024edb884SFrançois Tigeot 	mutex_lock(&drm_global_mutex);
105124edb884SFrançois Tigeot 	minor = drm_minor_acquire(iminor(inode));
105224edb884SFrançois Tigeot 	if (IS_ERR(minor)) {
105324edb884SFrançois Tigeot 		err = PTR_ERR(minor);
105424edb884SFrançois Tigeot 		goto out_unlock;
105524edb884SFrançois Tigeot 	}
105624edb884SFrançois Tigeot 
105724edb884SFrançois Tigeot 	new_fops = fops_get(minor->dev->driver->fops);
105824edb884SFrançois Tigeot 	if (!new_fops) {
105924edb884SFrançois Tigeot 		err = -ENODEV;
106024edb884SFrançois Tigeot 		goto out_release;
106124edb884SFrançois Tigeot 	}
106224edb884SFrançois Tigeot 
106324edb884SFrançois Tigeot 	replace_fops(filp, new_fops);
106424edb884SFrançois Tigeot 	if (filp->f_op->open)
106524edb884SFrançois Tigeot 		err = filp->f_op->open(inode, filp);
106624edb884SFrançois Tigeot 	else
106724edb884SFrançois Tigeot 		err = 0;
106824edb884SFrançois Tigeot 
106924edb884SFrançois Tigeot out_release:
107024edb884SFrançois Tigeot 	drm_minor_release(minor);
107124edb884SFrançois Tigeot out_unlock:
107224edb884SFrançois Tigeot 	mutex_unlock(&drm_global_mutex);
107324edb884SFrançois Tigeot 	return err;
107424edb884SFrançois Tigeot }
107524edb884SFrançois Tigeot 
107624edb884SFrançois Tigeot static const struct file_operations drm_stub_fops = {
107724edb884SFrançois Tigeot 	.owner = THIS_MODULE,
107824edb884SFrançois Tigeot 	.open = drm_stub_open,
107924edb884SFrançois Tigeot 	.llseek = noop_llseek,
108024edb884SFrançois Tigeot };
10811dedbd3bSFrançois Tigeot #endif
10821dedbd3bSFrançois Tigeot 
drm_core_exit(void)10831dedbd3bSFrançois Tigeot static void drm_core_exit(void)
10841dedbd3bSFrançois Tigeot {
10851dedbd3bSFrançois Tigeot #if 0
10861dedbd3bSFrançois Tigeot 	unregister_chrdev(DRM_MAJOR, "drm");
10871dedbd3bSFrançois Tigeot 	debugfs_remove(drm_debugfs_root);
10881dedbd3bSFrançois Tigeot 	drm_sysfs_destroy();
10891dedbd3bSFrançois Tigeot #endif
10901dedbd3bSFrançois Tigeot 	idr_destroy(&drm_minors_idr);
10911dedbd3bSFrançois Tigeot 	drm_connector_ida_destroy();
10921dedbd3bSFrançois Tigeot 	drm_global_release();
10931dedbd3bSFrançois Tigeot }
109424edb884SFrançois Tigeot 
drm_core_init(void)109524edb884SFrançois Tigeot static int __init drm_core_init(void)
109624edb884SFrançois Tigeot {
10971dedbd3bSFrançois Tigeot #if 0
10981dedbd3bSFrançois Tigeot 	int ret;
10991dedbd3bSFrançois Tigeot #endif
110024edb884SFrançois Tigeot 
110124edb884SFrançois Tigeot 	drm_global_init();
110224edb884SFrançois Tigeot 	drm_connector_ida_init();
110324edb884SFrançois Tigeot 	idr_init(&drm_minors_idr);
110424edb884SFrançois Tigeot 
11051dedbd3bSFrançois Tigeot #if 0
1106352ff8bdSFrançois Tigeot 	ret = drm_sysfs_init();
1107352ff8bdSFrançois Tigeot 	if (ret < 0) {
11081dedbd3bSFrançois Tigeot 		DRM_ERROR("Cannot create DRM class: %d\n", ret);
11091dedbd3bSFrançois Tigeot 		goto error;
111024edb884SFrançois Tigeot 	}
111124edb884SFrançois Tigeot 
111224edb884SFrançois Tigeot 	drm_debugfs_root = debugfs_create_dir("dri", NULL);
111324edb884SFrançois Tigeot 	if (!drm_debugfs_root) {
11141dedbd3bSFrançois Tigeot 		ret = -ENOMEM;
11151dedbd3bSFrançois Tigeot 		DRM_ERROR("Cannot create debugfs-root: %d\n", ret);
11161dedbd3bSFrançois Tigeot 		goto error;
111724edb884SFrançois Tigeot 	}
111824edb884SFrançois Tigeot 
11191dedbd3bSFrançois Tigeot 	ret = register_chrdev(DRM_MAJOR, "drm", &drm_stub_fops);
11201dedbd3bSFrançois Tigeot 	if (ret < 0)
11211dedbd3bSFrançois Tigeot 		goto error;
11221dedbd3bSFrançois Tigeot #endif
11231dedbd3bSFrançois Tigeot 
11243f2dd94aSFrançois Tigeot 	drm_core_init_complete = true;
11253f2dd94aSFrançois Tigeot 
1126a85cb24fSFrançois Tigeot 	DRM_DEBUG("Initialized\n");
112724edb884SFrançois Tigeot 	return 0;
112824edb884SFrançois Tigeot 
11291dedbd3bSFrançois Tigeot #if 0
11301dedbd3bSFrançois Tigeot error:
11311dedbd3bSFrançois Tigeot 	drm_core_exit();
113224edb884SFrançois Tigeot 	return ret;
11331dedbd3bSFrançois Tigeot #endif
113424edb884SFrançois Tigeot }
113524edb884SFrançois Tigeot 
113624edb884SFrançois Tigeot module_init(drm_core_init);
113724edb884SFrançois Tigeot module_exit(drm_core_exit);
113824edb884SFrançois Tigeot 
113979f713b0SFrançois Tigeot #include <sys/devfs.h>
11405718399fSFrançois Tigeot 
11419edbd4a0SFrançois Tigeot #include <linux/export.h>
1142be348e9fSFrançois Tigeot #include <linux/dmi.h>
114318e26a6dSFrançois Tigeot #include <drm/drmP.h>
11447f3c3d6fSHasso Tepper 
11455718399fSFrançois Tigeot static int
drm_modevent(module_t mod,int type,void * data)11465718399fSFrançois Tigeot drm_modevent(module_t mod, int type, void *data)
11475718399fSFrançois Tigeot {
11485718399fSFrançois Tigeot 
11495718399fSFrançois Tigeot 	switch (type) {
11505718399fSFrançois Tigeot 	case MOD_LOAD:
11511d5dd71dSFrançois Tigeot 		TUNABLE_INT_FETCH("drm.debug", &drm_debug);
11520e32b8c5SMatthew Dillon 		linux_task_drop_callback = linux_task_drop;
11530e32b8c5SMatthew Dillon 		linux_proc_drop_callback = linux_proc_drop;
11540e32b8c5SMatthew Dillon 		break;
11550e32b8c5SMatthew Dillon 	case MOD_UNLOAD:
11560e32b8c5SMatthew Dillon 		linux_task_drop_callback = NULL;
11570e32b8c5SMatthew Dillon 		linux_proc_drop_callback = NULL;
11585718399fSFrançois Tigeot 		break;
11595718399fSFrançois Tigeot 	}
11605718399fSFrançois Tigeot 	return (0);
11615718399fSFrançois Tigeot }
11625718399fSFrançois Tigeot 
11635718399fSFrançois Tigeot static moduledata_t drm_mod = {
11645718399fSFrançois Tigeot 	"drm",
11655718399fSFrançois Tigeot 	drm_modevent,
11665718399fSFrançois Tigeot 	0
11675718399fSFrançois Tigeot };
11685718399fSFrançois Tigeot DECLARE_MODULE(drm, drm_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
11697f3c3d6fSHasso Tepper MODULE_VERSION(drm, 1);
11707f3c3d6fSHasso Tepper MODULE_DEPEND(drm, agp, 1, 1, 1);
11717f3c3d6fSHasso Tepper MODULE_DEPEND(drm, pci, 1, 1, 1);
11725718399fSFrançois Tigeot MODULE_DEPEND(drm, iicbus, 1, 1, 1);
11737f3c3d6fSHasso Tepper 
11743f2dd94aSFrançois Tigeot struct dev_ops drm_cdevsw = {
1175d268c872SFrançois Tigeot 	{ "drm", 0, D_TRACKCLOSE | D_MPSAFE },
11767f3c3d6fSHasso Tepper 	.d_open =	drm_open,
11772c845b81SSimon Schubert 	.d_close =	drm_close,
11787f3c3d6fSHasso Tepper 	.d_read =	drm_read,
11797f3c3d6fSHasso Tepper 	.d_ioctl =	drm_ioctl,
11803694ee49SSamuel J. Greear 	.d_kqfilter =	drm_kqfilter,
11815718399fSFrançois Tigeot 	.d_mmap =	drm_mmap,
11825718399fSFrançois Tigeot 	.d_mmap_single = drm_mmap_single,
11837f3c3d6fSHasso Tepper };
11847f3c3d6fSHasso Tepper 
11855718399fSFrançois Tigeot SYSCTL_NODE(_hw, OID_AUTO, drm, CTLFLAG_RW, NULL, "DRM device");
118627a0f882SMatthew Dillon SYSCTL_INT(_hw_drm, OID_AUTO, debug, CTLFLAG_RW, &drm_debug, 0,
118727a0f882SMatthew Dillon     "DRM debugging");
1188a85cb24fSFrançois Tigeot int drm_vma_debug;
1189a85cb24fSFrançois Tigeot SYSCTL_INT(_hw_drm, OID_AUTO, vma_debug, CTLFLAG_RW, &drm_vma_debug, 0,
1190a85cb24fSFrançois Tigeot     "DRM debugging");
1191b3705d71SHasso Tepper 
11923f2dd94aSFrançois Tigeot #if 0
119379f713b0SFrançois Tigeot int
119479f713b0SFrançois Tigeot drm_create_cdevs(device_t kdev)
119579f713b0SFrançois Tigeot {
119679f713b0SFrançois Tigeot 	struct drm_device *dev;
119779f713b0SFrançois Tigeot 	int error, unit;
1198bb916eedSFrançois Tigeot #ifdef __DragonFly__
1199bb916eedSFrançois Tigeot 	struct drm_softc *softc = device_get_softc(kdev);
120079f713b0SFrançois Tigeot 
1201bb916eedSFrançois Tigeot 	dev = softc->drm_driver_data;
1202bb916eedSFrançois Tigeot #endif
120379f713b0SFrançois Tigeot 	unit = device_get_unit(kdev);
120479f713b0SFrançois Tigeot 
120579f713b0SFrançois Tigeot 	dev->devnode = make_dev(&drm_cdevsw, unit, DRM_DEV_UID, DRM_DEV_GID,
120679f713b0SFrançois Tigeot 				DRM_DEV_MODE, "dri/card%d", unit);
120779f713b0SFrançois Tigeot 	error = 0;
120879f713b0SFrançois Tigeot 	if (error == 0)
120979f713b0SFrançois Tigeot 		dev->devnode->si_drv1 = dev;
121079f713b0SFrançois Tigeot 	return (error);
121179f713b0SFrançois Tigeot }
12123f2dd94aSFrançois Tigeot #endif
121379f713b0SFrançois Tigeot 
12147f3c3d6fSHasso Tepper #ifndef DRM_DEV_NAME
12157f3c3d6fSHasso Tepper #define DRM_DEV_NAME "drm"
12167f3c3d6fSHasso Tepper #endif
12177f3c3d6fSHasso Tepper 
12187f3c3d6fSHasso Tepper devclass_t drm_devclass;
12197f3c3d6fSHasso Tepper 
1220d4d73b30SFrançois Tigeot /* XXX: this is supposed to be drm_release() */
drm_cdevpriv_dtor(void * cd)122179f713b0SFrançois Tigeot void drm_cdevpriv_dtor(void *cd)
122279f713b0SFrançois Tigeot {
122379f713b0SFrançois Tigeot 	struct drm_file *file_priv = cd;
122479f713b0SFrançois Tigeot 	struct drm_device *dev = file_priv->dev;
122579f713b0SFrançois Tigeot 
122679f713b0SFrançois Tigeot 	DRM_DEBUG("open_count = %d\n", dev->open_count);
122779f713b0SFrançois Tigeot 
122879f713b0SFrançois Tigeot 	DRM_LOCK(dev);
122979f713b0SFrançois Tigeot 
123079f713b0SFrançois Tigeot 	if (dev->driver->preclose != NULL)
123179f713b0SFrançois Tigeot 		dev->driver->preclose(dev, file_priv);
123279f713b0SFrançois Tigeot 
123379f713b0SFrançois Tigeot 	/* ========================================================
123479f713b0SFrançois Tigeot 	 * Begin inline drm_release
123579f713b0SFrançois Tigeot 	 */
123679f713b0SFrançois Tigeot 
123779f713b0SFrançois Tigeot 	DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n",
123879f713b0SFrançois Tigeot 	    DRM_CURRENTPID, (long)dev->dev, dev->open_count);
123979f713b0SFrançois Tigeot 
124079f713b0SFrançois Tigeot 	if (dev->driver->driver_features & DRIVER_GEM)
124179f713b0SFrançois Tigeot 		drm_gem_release(dev, file_priv);
124279f713b0SFrançois Tigeot 
1243d4d73b30SFrançois Tigeot 	if (drm_core_check_feature(dev, DRIVER_HAVE_DMA))
12441b13d190SFrançois Tigeot 		drm_legacy_reclaim_buffers(dev, file_priv);
124579f713b0SFrançois Tigeot 
124679f713b0SFrançois Tigeot 	funsetown(&dev->buf_sigio);
124779f713b0SFrançois Tigeot 
124879f713b0SFrançois Tigeot 	if (dev->driver->postclose != NULL)
124979f713b0SFrançois Tigeot 		dev->driver->postclose(dev, file_priv);
125079f713b0SFrançois Tigeot 	list_del(&file_priv->lhead);
125179f713b0SFrançois Tigeot 
125279f713b0SFrançois Tigeot 
125379f713b0SFrançois Tigeot 	/* ========================================================
125479f713b0SFrançois Tigeot 	 * End inline drm_release
125579f713b0SFrançois Tigeot 	 */
125679f713b0SFrançois Tigeot 
1257fb572d17SFrançois Tigeot 	device_unbusy(dev->dev->bsddev);
125879f713b0SFrançois Tigeot 	if (--dev->open_count == 0) {
12598621f407SFrançois Tigeot 		drm_lastclose(dev);
126079f713b0SFrançois Tigeot 	}
126179f713b0SFrançois Tigeot 
126279f713b0SFrançois Tigeot 	DRM_UNLOCK(dev);
126379f713b0SFrançois Tigeot }
126479f713b0SFrançois Tigeot 
12655718399fSFrançois Tigeot int
drm_add_busid_modesetting(struct drm_device * dev,struct sysctl_ctx_list * ctx,struct sysctl_oid * top)12665718399fSFrançois Tigeot drm_add_busid_modesetting(struct drm_device *dev, struct sysctl_ctx_list *ctx,
12675718399fSFrançois Tigeot     struct sysctl_oid *top)
12685718399fSFrançois Tigeot {
12695718399fSFrançois Tigeot 	struct sysctl_oid *oid;
12705718399fSFrançois Tigeot 
12715718399fSFrançois Tigeot 	ksnprintf(dev->busid_str, sizeof(dev->busid_str),
12725718399fSFrançois Tigeot 	     "pci:%04x:%02x:%02x.%d", dev->pci_domain, dev->pci_bus,
12735718399fSFrançois Tigeot 	     dev->pci_slot, dev->pci_func);
12745718399fSFrançois Tigeot 	oid = SYSCTL_ADD_STRING(ctx, SYSCTL_CHILDREN(top), OID_AUTO, "busid",
12755718399fSFrançois Tigeot 	    CTLFLAG_RD, dev->busid_str, 0, NULL);
12765718399fSFrançois Tigeot 	if (oid == NULL)
12775718399fSFrançois Tigeot 		return (ENOMEM);
12785718399fSFrançois Tigeot 
12795718399fSFrançois Tigeot 	return (0);
12805718399fSFrançois Tigeot }
12815718399fSFrançois Tigeot 
12825718399fSFrançois Tigeot int
drm_mmap_single(struct dev_mmap_single_args * ap)12835718399fSFrançois Tigeot drm_mmap_single(struct dev_mmap_single_args *ap)
12845718399fSFrançois Tigeot {
128579f713b0SFrançois Tigeot 	struct drm_device *dev;
12865718399fSFrançois Tigeot 	struct cdev *kdev = ap->a_head.a_dev;
12875718399fSFrançois Tigeot 	vm_ooffset_t *offset = ap->a_offset;
12885718399fSFrançois Tigeot 	vm_size_t size = ap->a_size;
12895718399fSFrançois Tigeot 	struct vm_object **obj_res = ap->a_object;
12905718399fSFrançois Tigeot 	int nprot = ap->a_nprot;
12915718399fSFrançois Tigeot 
129279f713b0SFrançois Tigeot 	dev = drm_get_device_from_kdev(kdev);
12936f486c69SFrançois Tigeot 	if (dev->drm_ttm_bdev != NULL) {
1294*932d855eSSergey Zigachev 		return (ttm_bo_mmap_single(ap->a_fp, dev,
1295*932d855eSSergey Zigachev 					   offset, size, obj_res, nprot));
12966f486c69SFrançois Tigeot 	} else if ((dev->driver->driver_features & DRIVER_GEM) != 0) {
12976f486c69SFrançois Tigeot 		return (drm_gem_mmap_single(dev, offset, size, obj_res, nprot));
12985718399fSFrançois Tigeot 	} else {
12995718399fSFrançois Tigeot 		return (ENODEV);
13005718399fSFrançois Tigeot 	}
13015718399fSFrançois Tigeot }
13025718399fSFrançois Tigeot 
130324edb884SFrançois Tigeot #include <linux/dmi.h>
130424edb884SFrançois Tigeot 
13055718399fSFrançois Tigeot /*
13065718399fSFrançois Tigeot  * Check if dmi_system_id structure matches system DMI data
13075718399fSFrançois Tigeot  */
13085718399fSFrançois Tigeot static bool
dmi_found(const struct dmi_system_id * dsi)13095718399fSFrançois Tigeot dmi_found(const struct dmi_system_id *dsi)
13105718399fSFrançois Tigeot {
13115718399fSFrançois Tigeot 	int i, slot;
13125718399fSFrançois Tigeot 	bool found = false;
13135718399fSFrançois Tigeot 	char *sys_vendor, *board_vendor, *product_name, *board_name;
13145718399fSFrançois Tigeot 
13155718399fSFrançois Tigeot 	sys_vendor = kgetenv("smbios.system.maker");
13165718399fSFrançois Tigeot 	board_vendor = kgetenv("smbios.planar.maker");
13175718399fSFrançois Tigeot 	product_name = kgetenv("smbios.system.product");
13185718399fSFrançois Tigeot 	board_name = kgetenv("smbios.planar.product");
13195718399fSFrançois Tigeot 
13205718399fSFrançois Tigeot 	for (i = 0; i < NELEM(dsi->matches); i++) {
13215718399fSFrançois Tigeot 		slot = dsi->matches[i].slot;
13225718399fSFrançois Tigeot 		switch (slot) {
13235718399fSFrançois Tigeot 		case DMI_NONE:
13245718399fSFrançois Tigeot 			break;
13255718399fSFrançois Tigeot 		case DMI_SYS_VENDOR:
13265718399fSFrançois Tigeot 			if (sys_vendor != NULL &&
13275718399fSFrançois Tigeot 			    !strcmp(sys_vendor, dsi->matches[i].substr))
13285718399fSFrançois Tigeot 				break;
13295718399fSFrançois Tigeot 			else
13305718399fSFrançois Tigeot 				goto done;
13315718399fSFrançois Tigeot 		case DMI_BOARD_VENDOR:
13325718399fSFrançois Tigeot 			if (board_vendor != NULL &&
13335718399fSFrançois Tigeot 			    !strcmp(board_vendor, dsi->matches[i].substr))
13345718399fSFrançois Tigeot 				break;
13355718399fSFrançois Tigeot 			else
13365718399fSFrançois Tigeot 				goto done;
13375718399fSFrançois Tigeot 		case DMI_PRODUCT_NAME:
13385718399fSFrançois Tigeot 			if (product_name != NULL &&
13395718399fSFrançois Tigeot 			    !strcmp(product_name, dsi->matches[i].substr))
13405718399fSFrançois Tigeot 				break;
13415718399fSFrançois Tigeot 			else
13425718399fSFrançois Tigeot 				goto done;
13435718399fSFrançois Tigeot 		case DMI_BOARD_NAME:
13445718399fSFrançois Tigeot 			if (board_name != NULL &&
13455718399fSFrançois Tigeot 			    !strcmp(board_name, dsi->matches[i].substr))
13465718399fSFrançois Tigeot 				break;
13475718399fSFrançois Tigeot 			else
13485718399fSFrançois Tigeot 				goto done;
13495718399fSFrançois Tigeot 		default:
13505718399fSFrançois Tigeot 			goto done;
13515718399fSFrançois Tigeot 		}
13525718399fSFrançois Tigeot 	}
13535718399fSFrançois Tigeot 	found = true;
13545718399fSFrançois Tigeot 
13555718399fSFrançois Tigeot done:
13565718399fSFrançois Tigeot 	if (sys_vendor != NULL)
13575718399fSFrançois Tigeot 		kfreeenv(sys_vendor);
13585718399fSFrançois Tigeot 	if (board_vendor != NULL)
13595718399fSFrançois Tigeot 		kfreeenv(board_vendor);
13605718399fSFrançois Tigeot 	if (product_name != NULL)
13615718399fSFrançois Tigeot 		kfreeenv(product_name);
13625718399fSFrançois Tigeot 	if (board_name != NULL)
13635718399fSFrançois Tigeot 		kfreeenv(board_name);
13645718399fSFrançois Tigeot 
13655718399fSFrançois Tigeot 	return found;
13665718399fSFrançois Tigeot }
13675718399fSFrançois Tigeot 
dmi_check_system(const struct dmi_system_id * sysid)1368be348e9fSFrançois Tigeot int dmi_check_system(const struct dmi_system_id *sysid)
13695718399fSFrançois Tigeot {
13705718399fSFrançois Tigeot 	const struct dmi_system_id *dsi;
13715718399fSFrançois Tigeot 	int num = 0;
13725718399fSFrançois Tigeot 
13735718399fSFrançois Tigeot 	for (dsi = sysid; dsi->matches[0].slot != 0 ; dsi++) {
13745718399fSFrançois Tigeot 		if (dmi_found(dsi)) {
13755718399fSFrançois Tigeot 			num++;
13765718399fSFrançois Tigeot 			if (dsi->callback && dsi->callback(dsi))
13775718399fSFrançois Tigeot 				break;
13785718399fSFrançois Tigeot 		}
13795718399fSFrançois Tigeot 	}
13805718399fSFrançois Tigeot 	return (num);
13815718399fSFrançois Tigeot }
1382