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