11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * drivers/base/core.c - core driver model code (device registration, etc) 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (c) 2002-3 Patrick Mochel 51da177e4SLinus Torvalds * Copyright (c) 2002-3 Open Source Development Labs 664bb5d2cSGreg Kroah-Hartman * Copyright (c) 2006 Greg Kroah-Hartman <gregkh@suse.de> 764bb5d2cSGreg Kroah-Hartman * Copyright (c) 2006 Novell, Inc. 81da177e4SLinus Torvalds * 91da177e4SLinus Torvalds * This file is released under the GPLv2 101da177e4SLinus Torvalds * 111da177e4SLinus Torvalds */ 121da177e4SLinus Torvalds 131da177e4SLinus Torvalds #include <linux/device.h> 141da177e4SLinus Torvalds #include <linux/err.h> 151da177e4SLinus Torvalds #include <linux/init.h> 161da177e4SLinus Torvalds #include <linux/module.h> 171da177e4SLinus Torvalds #include <linux/slab.h> 181da177e4SLinus Torvalds #include <linux/string.h> 1923681e47SGreg Kroah-Hartman #include <linux/kdev_t.h> 20116af378SBenjamin Herrenschmidt #include <linux/notifier.h> 21da231fd5SKay Sievers #include <linux/genhd.h> 22815d2d50SAndrew Morton #include <linux/kallsyms.h> 236188e10dSMatthew Wilcox #include <linux/semaphore.h> 241da177e4SLinus Torvalds 251da177e4SLinus Torvalds #include "base.h" 261da177e4SLinus Torvalds #include "power/power.h" 271da177e4SLinus Torvalds 281da177e4SLinus Torvalds int (*platform_notify)(struct device *dev) = NULL; 291da177e4SLinus Torvalds int (*platform_notify_remove)(struct device *dev) = NULL; 301da177e4SLinus Torvalds 314e886c29SGreg Kroah-Hartman #ifdef CONFIG_BLOCK 324e886c29SGreg Kroah-Hartman static inline int device_is_not_partition(struct device *dev) 334e886c29SGreg Kroah-Hartman { 344e886c29SGreg Kroah-Hartman return !(dev->type == &part_type); 354e886c29SGreg Kroah-Hartman } 364e886c29SGreg Kroah-Hartman #else 374e886c29SGreg Kroah-Hartman static inline int device_is_not_partition(struct device *dev) 384e886c29SGreg Kroah-Hartman { 394e886c29SGreg Kroah-Hartman return 1; 404e886c29SGreg Kroah-Hartman } 414e886c29SGreg Kroah-Hartman #endif 421da177e4SLinus Torvalds 433e95637aSAlan Stern /** 443e95637aSAlan Stern * dev_driver_string - Return a device's driver name, if at all possible 453e95637aSAlan Stern * @dev: struct device to get the name of 463e95637aSAlan Stern * 473e95637aSAlan Stern * Will return the device's driver's name if it is bound to a device. If 483e95637aSAlan Stern * the device is not bound to a device, it will return the name of the bus 493e95637aSAlan Stern * it is attached to. If it is not attached to a bus either, an empty 503e95637aSAlan Stern * string will be returned. 513e95637aSAlan Stern */ 523e95637aSAlan Stern const char *dev_driver_string(struct device *dev) 533e95637aSAlan Stern { 543e95637aSAlan Stern return dev->driver ? dev->driver->name : 55a456b702SJean Delvare (dev->bus ? dev->bus->name : 56a456b702SJean Delvare (dev->class ? dev->class->name : "")); 573e95637aSAlan Stern } 58310a922dSMatthew Wilcox EXPORT_SYMBOL(dev_driver_string); 593e95637aSAlan Stern 601da177e4SLinus Torvalds #define to_dev(obj) container_of(obj, struct device, kobj) 611da177e4SLinus Torvalds #define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr) 621da177e4SLinus Torvalds 634a3ad20cSGreg Kroah-Hartman static ssize_t dev_attr_show(struct kobject *kobj, struct attribute *attr, 644a3ad20cSGreg Kroah-Hartman char *buf) 651da177e4SLinus Torvalds { 661da177e4SLinus Torvalds struct device_attribute *dev_attr = to_dev_attr(attr); 671da177e4SLinus Torvalds struct device *dev = to_dev(kobj); 684a0c20bfSDmitry Torokhov ssize_t ret = -EIO; 691da177e4SLinus Torvalds 701da177e4SLinus Torvalds if (dev_attr->show) 7154b6f35cSYani Ioannou ret = dev_attr->show(dev, dev_attr, buf); 72815d2d50SAndrew Morton if (ret >= (ssize_t)PAGE_SIZE) { 73815d2d50SAndrew Morton print_symbol("dev_attr_show: %s returned bad count\n", 74815d2d50SAndrew Morton (unsigned long)dev_attr->show); 75815d2d50SAndrew Morton } 761da177e4SLinus Torvalds return ret; 771da177e4SLinus Torvalds } 781da177e4SLinus Torvalds 794a3ad20cSGreg Kroah-Hartman static ssize_t dev_attr_store(struct kobject *kobj, struct attribute *attr, 801da177e4SLinus Torvalds const char *buf, size_t count) 811da177e4SLinus Torvalds { 821da177e4SLinus Torvalds struct device_attribute *dev_attr = to_dev_attr(attr); 831da177e4SLinus Torvalds struct device *dev = to_dev(kobj); 844a0c20bfSDmitry Torokhov ssize_t ret = -EIO; 851da177e4SLinus Torvalds 861da177e4SLinus Torvalds if (dev_attr->store) 8754b6f35cSYani Ioannou ret = dev_attr->store(dev, dev_attr, buf, count); 881da177e4SLinus Torvalds return ret; 891da177e4SLinus Torvalds } 901da177e4SLinus Torvalds 911da177e4SLinus Torvalds static struct sysfs_ops dev_sysfs_ops = { 921da177e4SLinus Torvalds .show = dev_attr_show, 931da177e4SLinus Torvalds .store = dev_attr_store, 941da177e4SLinus Torvalds }; 951da177e4SLinus Torvalds 961da177e4SLinus Torvalds 971da177e4SLinus Torvalds /** 981da177e4SLinus Torvalds * device_release - free device structure. 991da177e4SLinus Torvalds * @kobj: device's kobject. 1001da177e4SLinus Torvalds * 1011da177e4SLinus Torvalds * This is called once the reference count for the object 1021da177e4SLinus Torvalds * reaches 0. We forward the call to the device's release 1031da177e4SLinus Torvalds * method, which should handle actually freeing the structure. 1041da177e4SLinus Torvalds */ 1051da177e4SLinus Torvalds static void device_release(struct kobject *kobj) 1061da177e4SLinus Torvalds { 1071da177e4SLinus Torvalds struct device *dev = to_dev(kobj); 1081da177e4SLinus Torvalds 1091da177e4SLinus Torvalds if (dev->release) 1101da177e4SLinus Torvalds dev->release(dev); 111f9f852dfSKay Sievers else if (dev->type && dev->type->release) 112f9f852dfSKay Sievers dev->type->release(dev); 1132620efefSGreg Kroah-Hartman else if (dev->class && dev->class->dev_release) 1142620efefSGreg Kroah-Hartman dev->class->dev_release(dev); 1151da177e4SLinus Torvalds else { 1164a3ad20cSGreg Kroah-Hartman printk(KERN_ERR "Device '%s' does not have a release() " 1174a3ad20cSGreg Kroah-Hartman "function, it is broken and must be fixed.\n", 1181da177e4SLinus Torvalds dev->bus_id); 1191da177e4SLinus Torvalds WARN_ON(1); 1201da177e4SLinus Torvalds } 1211da177e4SLinus Torvalds } 1221da177e4SLinus Torvalds 1238f4afc41SGreg Kroah-Hartman static struct kobj_type device_ktype = { 1241da177e4SLinus Torvalds .release = device_release, 1251da177e4SLinus Torvalds .sysfs_ops = &dev_sysfs_ops, 1261da177e4SLinus Torvalds }; 1271da177e4SLinus Torvalds 1281da177e4SLinus Torvalds 129312c004dSKay Sievers static int dev_uevent_filter(struct kset *kset, struct kobject *kobj) 1301da177e4SLinus Torvalds { 1311da177e4SLinus Torvalds struct kobj_type *ktype = get_ktype(kobj); 1321da177e4SLinus Torvalds 1338f4afc41SGreg Kroah-Hartman if (ktype == &device_ktype) { 1341da177e4SLinus Torvalds struct device *dev = to_dev(kobj); 13583b5fb4cSCornelia Huck if (dev->uevent_suppress) 13683b5fb4cSCornelia Huck return 0; 1371da177e4SLinus Torvalds if (dev->bus) 1381da177e4SLinus Torvalds return 1; 13923681e47SGreg Kroah-Hartman if (dev->class) 14023681e47SGreg Kroah-Hartman return 1; 1411da177e4SLinus Torvalds } 1421da177e4SLinus Torvalds return 0; 1431da177e4SLinus Torvalds } 1441da177e4SLinus Torvalds 145312c004dSKay Sievers static const char *dev_uevent_name(struct kset *kset, struct kobject *kobj) 1461da177e4SLinus Torvalds { 1471da177e4SLinus Torvalds struct device *dev = to_dev(kobj); 1481da177e4SLinus Torvalds 14923681e47SGreg Kroah-Hartman if (dev->bus) 1501da177e4SLinus Torvalds return dev->bus->name; 15123681e47SGreg Kroah-Hartman if (dev->class) 15223681e47SGreg Kroah-Hartman return dev->class->name; 15323681e47SGreg Kroah-Hartman return NULL; 1541da177e4SLinus Torvalds } 1551da177e4SLinus Torvalds 1567eff2e7aSKay Sievers static int dev_uevent(struct kset *kset, struct kobject *kobj, 1577eff2e7aSKay Sievers struct kobj_uevent_env *env) 1581da177e4SLinus Torvalds { 1591da177e4SLinus Torvalds struct device *dev = to_dev(kobj); 1601da177e4SLinus Torvalds int retval = 0; 1611da177e4SLinus Torvalds 16223681e47SGreg Kroah-Hartman /* add the major/minor if present */ 16323681e47SGreg Kroah-Hartman if (MAJOR(dev->devt)) { 1647eff2e7aSKay Sievers add_uevent_var(env, "MAJOR=%u", MAJOR(dev->devt)); 1657eff2e7aSKay Sievers add_uevent_var(env, "MINOR=%u", MINOR(dev->devt)); 16623681e47SGreg Kroah-Hartman } 16723681e47SGreg Kroah-Hartman 168414264f9SKay Sievers if (dev->type && dev->type->name) 1697eff2e7aSKay Sievers add_uevent_var(env, "DEVTYPE=%s", dev->type->name); 170414264f9SKay Sievers 171239378f1SKay Sievers if (dev->driver) 1727eff2e7aSKay Sievers add_uevent_var(env, "DRIVER=%s", dev->driver->name); 173239378f1SKay Sievers 174a87cb2acSKay Sievers #ifdef CONFIG_SYSFS_DEPRECATED 175239378f1SKay Sievers if (dev->class) { 176239378f1SKay Sievers struct device *parent = dev->parent; 177239378f1SKay Sievers 178239378f1SKay Sievers /* find first bus device in parent chain */ 179239378f1SKay Sievers while (parent && !parent->bus) 180239378f1SKay Sievers parent = parent->parent; 181239378f1SKay Sievers if (parent && parent->bus) { 182239378f1SKay Sievers const char *path; 183239378f1SKay Sievers 184239378f1SKay Sievers path = kobject_get_path(&parent->kobj, GFP_KERNEL); 1852c7afd12SKay Sievers if (path) { 1867eff2e7aSKay Sievers add_uevent_var(env, "PHYSDEVPATH=%s", path); 187239378f1SKay Sievers kfree(path); 1882c7afd12SKay Sievers } 189239378f1SKay Sievers 1907eff2e7aSKay Sievers add_uevent_var(env, "PHYSDEVBUS=%s", parent->bus->name); 191239378f1SKay Sievers 192239378f1SKay Sievers if (parent->driver) 1937eff2e7aSKay Sievers add_uevent_var(env, "PHYSDEVDRIVER=%s", 1947eff2e7aSKay Sievers parent->driver->name); 195239378f1SKay Sievers } 196239378f1SKay Sievers } else if (dev->bus) { 1977eff2e7aSKay Sievers add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name); 198239378f1SKay Sievers 199239378f1SKay Sievers if (dev->driver) 2004a3ad20cSGreg Kroah-Hartman add_uevent_var(env, "PHYSDEVDRIVER=%s", 2014a3ad20cSGreg Kroah-Hartman dev->driver->name); 202d81d9d6bSKay Sievers } 203239378f1SKay Sievers #endif 2041da177e4SLinus Torvalds 2051da177e4SLinus Torvalds /* have the bus specific function add its stuff */ 2067eff2e7aSKay Sievers if (dev->bus && dev->bus->uevent) { 2077eff2e7aSKay Sievers retval = dev->bus->uevent(dev, env); 208f9f852dfSKay Sievers if (retval) 2097dc72b28SGreg Kroah-Hartman pr_debug("device: '%s': %s: bus uevent() returned %d\n", 2107dc72b28SGreg Kroah-Hartman dev->bus_id, __FUNCTION__, retval); 2111da177e4SLinus Torvalds } 2121da177e4SLinus Torvalds 2132620efefSGreg Kroah-Hartman /* have the class specific function add its stuff */ 2147eff2e7aSKay Sievers if (dev->class && dev->class->dev_uevent) { 2157eff2e7aSKay Sievers retval = dev->class->dev_uevent(dev, env); 216f9f852dfSKay Sievers if (retval) 2177dc72b28SGreg Kroah-Hartman pr_debug("device: '%s': %s: class uevent() " 2187dc72b28SGreg Kroah-Hartman "returned %d\n", dev->bus_id, 2192620efefSGreg Kroah-Hartman __FUNCTION__, retval); 2202620efefSGreg Kroah-Hartman } 221f9f852dfSKay Sievers 222f9f852dfSKay Sievers /* have the device type specific fuction add its stuff */ 2237eff2e7aSKay Sievers if (dev->type && dev->type->uevent) { 2247eff2e7aSKay Sievers retval = dev->type->uevent(dev, env); 225f9f852dfSKay Sievers if (retval) 2267dc72b28SGreg Kroah-Hartman pr_debug("device: '%s': %s: dev_type uevent() " 2277dc72b28SGreg Kroah-Hartman "returned %d\n", dev->bus_id, 228f9f852dfSKay Sievers __FUNCTION__, retval); 2292620efefSGreg Kroah-Hartman } 2302620efefSGreg Kroah-Hartman 2311da177e4SLinus Torvalds return retval; 2321da177e4SLinus Torvalds } 2331da177e4SLinus Torvalds 234312c004dSKay Sievers static struct kset_uevent_ops device_uevent_ops = { 235312c004dSKay Sievers .filter = dev_uevent_filter, 236312c004dSKay Sievers .name = dev_uevent_name, 237312c004dSKay Sievers .uevent = dev_uevent, 2381da177e4SLinus Torvalds }; 2391da177e4SLinus Torvalds 24016574dccSKay Sievers static ssize_t show_uevent(struct device *dev, struct device_attribute *attr, 24116574dccSKay Sievers char *buf) 24216574dccSKay Sievers { 24316574dccSKay Sievers struct kobject *top_kobj; 24416574dccSKay Sievers struct kset *kset; 2457eff2e7aSKay Sievers struct kobj_uevent_env *env = NULL; 24616574dccSKay Sievers int i; 24716574dccSKay Sievers size_t count = 0; 24816574dccSKay Sievers int retval; 24916574dccSKay Sievers 25016574dccSKay Sievers /* search the kset, the device belongs to */ 25116574dccSKay Sievers top_kobj = &dev->kobj; 2525c5daf65SKay Sievers while (!top_kobj->kset && top_kobj->parent) 25316574dccSKay Sievers top_kobj = top_kobj->parent; 25416574dccSKay Sievers if (!top_kobj->kset) 25516574dccSKay Sievers goto out; 2565c5daf65SKay Sievers 25716574dccSKay Sievers kset = top_kobj->kset; 25816574dccSKay Sievers if (!kset->uevent_ops || !kset->uevent_ops->uevent) 25916574dccSKay Sievers goto out; 26016574dccSKay Sievers 26116574dccSKay Sievers /* respect filter */ 26216574dccSKay Sievers if (kset->uevent_ops && kset->uevent_ops->filter) 26316574dccSKay Sievers if (!kset->uevent_ops->filter(kset, &dev->kobj)) 26416574dccSKay Sievers goto out; 26516574dccSKay Sievers 2667eff2e7aSKay Sievers env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL); 2677eff2e7aSKay Sievers if (!env) 268c7308c81SGreg Kroah-Hartman return -ENOMEM; 269c7308c81SGreg Kroah-Hartman 27016574dccSKay Sievers /* let the kset specific function add its keys */ 2717eff2e7aSKay Sievers retval = kset->uevent_ops->uevent(kset, &dev->kobj, env); 27216574dccSKay Sievers if (retval) 27316574dccSKay Sievers goto out; 27416574dccSKay Sievers 27516574dccSKay Sievers /* copy keys to file */ 2767eff2e7aSKay Sievers for (i = 0; i < env->envp_idx; i++) 2777eff2e7aSKay Sievers count += sprintf(&buf[count], "%s\n", env->envp[i]); 27816574dccSKay Sievers out: 2797eff2e7aSKay Sievers kfree(env); 28016574dccSKay Sievers return count; 28116574dccSKay Sievers } 28216574dccSKay Sievers 283a7fd6706SKay Sievers static ssize_t store_uevent(struct device *dev, struct device_attribute *attr, 284a7fd6706SKay Sievers const char *buf, size_t count) 285a7fd6706SKay Sievers { 28660a96a59SKay Sievers enum kobject_action action; 28760a96a59SKay Sievers 2885c5daf65SKay Sievers if (kobject_action_type(buf, count, &action) == 0) { 28960a96a59SKay Sievers kobject_uevent(&dev->kobj, action); 29060a96a59SKay Sievers goto out; 29160a96a59SKay Sievers } 29260a96a59SKay Sievers 29322af74f3SKay Sievers dev_err(dev, "uevent: unsupported action-string; this will " 29460a96a59SKay Sievers "be ignored in a future kernel version\n"); 295312c004dSKay Sievers kobject_uevent(&dev->kobj, KOBJ_ADD); 29660a96a59SKay Sievers out: 297a7fd6706SKay Sievers return count; 298a7fd6706SKay Sievers } 299a7fd6706SKay Sievers 300ad6a1e1cSTejun Heo static struct device_attribute uevent_attr = 301ad6a1e1cSTejun Heo __ATTR(uevent, S_IRUGO | S_IWUSR, show_uevent, store_uevent); 302ad6a1e1cSTejun Heo 303621a1672SDmitry Torokhov static int device_add_attributes(struct device *dev, 304621a1672SDmitry Torokhov struct device_attribute *attrs) 305de0ff00dSGreg Kroah-Hartman { 306de0ff00dSGreg Kroah-Hartman int error = 0; 307621a1672SDmitry Torokhov int i; 308de0ff00dSGreg Kroah-Hartman 309621a1672SDmitry Torokhov if (attrs) { 310621a1672SDmitry Torokhov for (i = 0; attr_name(attrs[i]); i++) { 311621a1672SDmitry Torokhov error = device_create_file(dev, &attrs[i]); 312621a1672SDmitry Torokhov if (error) 313621a1672SDmitry Torokhov break; 314621a1672SDmitry Torokhov } 315621a1672SDmitry Torokhov if (error) 316de0ff00dSGreg Kroah-Hartman while (--i >= 0) 317621a1672SDmitry Torokhov device_remove_file(dev, &attrs[i]); 318de0ff00dSGreg Kroah-Hartman } 319de0ff00dSGreg Kroah-Hartman return error; 320de0ff00dSGreg Kroah-Hartman } 321de0ff00dSGreg Kroah-Hartman 322621a1672SDmitry Torokhov static void device_remove_attributes(struct device *dev, 323621a1672SDmitry Torokhov struct device_attribute *attrs) 324de0ff00dSGreg Kroah-Hartman { 325de0ff00dSGreg Kroah-Hartman int i; 326621a1672SDmitry Torokhov 327621a1672SDmitry Torokhov if (attrs) 328621a1672SDmitry Torokhov for (i = 0; attr_name(attrs[i]); i++) 329621a1672SDmitry Torokhov device_remove_file(dev, &attrs[i]); 330621a1672SDmitry Torokhov } 331621a1672SDmitry Torokhov 332621a1672SDmitry Torokhov static int device_add_groups(struct device *dev, 333621a1672SDmitry Torokhov struct attribute_group **groups) 334621a1672SDmitry Torokhov { 335621a1672SDmitry Torokhov int error = 0; 336621a1672SDmitry Torokhov int i; 337621a1672SDmitry Torokhov 338621a1672SDmitry Torokhov if (groups) { 339621a1672SDmitry Torokhov for (i = 0; groups[i]; i++) { 340621a1672SDmitry Torokhov error = sysfs_create_group(&dev->kobj, groups[i]); 341621a1672SDmitry Torokhov if (error) { 342621a1672SDmitry Torokhov while (--i >= 0) 3434a3ad20cSGreg Kroah-Hartman sysfs_remove_group(&dev->kobj, 3444a3ad20cSGreg Kroah-Hartman groups[i]); 345621a1672SDmitry Torokhov break; 346de0ff00dSGreg Kroah-Hartman } 347de0ff00dSGreg Kroah-Hartman } 348de0ff00dSGreg Kroah-Hartman } 349621a1672SDmitry Torokhov return error; 350621a1672SDmitry Torokhov } 351621a1672SDmitry Torokhov 352621a1672SDmitry Torokhov static void device_remove_groups(struct device *dev, 353621a1672SDmitry Torokhov struct attribute_group **groups) 354621a1672SDmitry Torokhov { 355621a1672SDmitry Torokhov int i; 356621a1672SDmitry Torokhov 357621a1672SDmitry Torokhov if (groups) 358621a1672SDmitry Torokhov for (i = 0; groups[i]; i++) 359621a1672SDmitry Torokhov sysfs_remove_group(&dev->kobj, groups[i]); 360621a1672SDmitry Torokhov } 361de0ff00dSGreg Kroah-Hartman 3622620efefSGreg Kroah-Hartman static int device_add_attrs(struct device *dev) 3632620efefSGreg Kroah-Hartman { 3642620efefSGreg Kroah-Hartman struct class *class = dev->class; 365f9f852dfSKay Sievers struct device_type *type = dev->type; 366621a1672SDmitry Torokhov int error; 3672620efefSGreg Kroah-Hartman 368621a1672SDmitry Torokhov if (class) { 369621a1672SDmitry Torokhov error = device_add_attributes(dev, class->dev_attrs); 3702620efefSGreg Kroah-Hartman if (error) 371621a1672SDmitry Torokhov return error; 372f9f852dfSKay Sievers } 373f9f852dfSKay Sievers 374621a1672SDmitry Torokhov if (type) { 375621a1672SDmitry Torokhov error = device_add_groups(dev, type->groups); 376f9f852dfSKay Sievers if (error) 377621a1672SDmitry Torokhov goto err_remove_class_attrs; 378f9f852dfSKay Sievers } 379621a1672SDmitry Torokhov 380621a1672SDmitry Torokhov error = device_add_groups(dev, dev->groups); 381f9f852dfSKay Sievers if (error) 382621a1672SDmitry Torokhov goto err_remove_type_groups; 383621a1672SDmitry Torokhov 384621a1672SDmitry Torokhov return 0; 385621a1672SDmitry Torokhov 386621a1672SDmitry Torokhov err_remove_type_groups: 387621a1672SDmitry Torokhov if (type) 388621a1672SDmitry Torokhov device_remove_groups(dev, type->groups); 389621a1672SDmitry Torokhov err_remove_class_attrs: 390621a1672SDmitry Torokhov if (class) 391621a1672SDmitry Torokhov device_remove_attributes(dev, class->dev_attrs); 392f9f852dfSKay Sievers 3932620efefSGreg Kroah-Hartman return error; 3942620efefSGreg Kroah-Hartman } 3952620efefSGreg Kroah-Hartman 3962620efefSGreg Kroah-Hartman static void device_remove_attrs(struct device *dev) 3972620efefSGreg Kroah-Hartman { 3982620efefSGreg Kroah-Hartman struct class *class = dev->class; 399f9f852dfSKay Sievers struct device_type *type = dev->type; 4002620efefSGreg Kroah-Hartman 401621a1672SDmitry Torokhov device_remove_groups(dev, dev->groups); 402f9f852dfSKay Sievers 403621a1672SDmitry Torokhov if (type) 404621a1672SDmitry Torokhov device_remove_groups(dev, type->groups); 405621a1672SDmitry Torokhov 406621a1672SDmitry Torokhov if (class) 407621a1672SDmitry Torokhov device_remove_attributes(dev, class->dev_attrs); 4082620efefSGreg Kroah-Hartman } 4092620efefSGreg Kroah-Hartman 4102620efefSGreg Kroah-Hartman 41123681e47SGreg Kroah-Hartman static ssize_t show_dev(struct device *dev, struct device_attribute *attr, 41223681e47SGreg Kroah-Hartman char *buf) 41323681e47SGreg Kroah-Hartman { 41423681e47SGreg Kroah-Hartman return print_dev_t(buf, dev->devt); 41523681e47SGreg Kroah-Hartman } 41623681e47SGreg Kroah-Hartman 417ad6a1e1cSTejun Heo static struct device_attribute devt_attr = 418ad6a1e1cSTejun Heo __ATTR(dev, S_IRUGO, show_dev, NULL); 419ad6a1e1cSTejun Heo 420881c6cfdSGreg Kroah-Hartman /* kset to create /sys/devices/ */ 421881c6cfdSGreg Kroah-Hartman struct kset *devices_kset; 4221da177e4SLinus Torvalds 4231da177e4SLinus Torvalds /** 4241da177e4SLinus Torvalds * device_create_file - create sysfs attribute file for device. 4251da177e4SLinus Torvalds * @dev: device. 4261da177e4SLinus Torvalds * @attr: device attribute descriptor. 4271da177e4SLinus Torvalds */ 4281da177e4SLinus Torvalds int device_create_file(struct device *dev, struct device_attribute *attr) 4291da177e4SLinus Torvalds { 4301da177e4SLinus Torvalds int error = 0; 4310c98b19fSCornelia Huck if (dev) 4321da177e4SLinus Torvalds error = sysfs_create_file(&dev->kobj, &attr->attr); 4331da177e4SLinus Torvalds return error; 4341da177e4SLinus Torvalds } 4351da177e4SLinus Torvalds 4361da177e4SLinus Torvalds /** 4371da177e4SLinus Torvalds * device_remove_file - remove sysfs attribute file. 4381da177e4SLinus Torvalds * @dev: device. 4391da177e4SLinus Torvalds * @attr: device attribute descriptor. 4401da177e4SLinus Torvalds */ 4411da177e4SLinus Torvalds void device_remove_file(struct device *dev, struct device_attribute *attr) 4421da177e4SLinus Torvalds { 4430c98b19fSCornelia Huck if (dev) 4441da177e4SLinus Torvalds sysfs_remove_file(&dev->kobj, &attr->attr); 4451da177e4SLinus Torvalds } 4461da177e4SLinus Torvalds 4472589f188SGreg Kroah-Hartman /** 4482589f188SGreg Kroah-Hartman * device_create_bin_file - create sysfs binary attribute file for device. 4492589f188SGreg Kroah-Hartman * @dev: device. 4502589f188SGreg Kroah-Hartman * @attr: device binary attribute descriptor. 4512589f188SGreg Kroah-Hartman */ 4522589f188SGreg Kroah-Hartman int device_create_bin_file(struct device *dev, struct bin_attribute *attr) 4532589f188SGreg Kroah-Hartman { 4542589f188SGreg Kroah-Hartman int error = -EINVAL; 4552589f188SGreg Kroah-Hartman if (dev) 4562589f188SGreg Kroah-Hartman error = sysfs_create_bin_file(&dev->kobj, attr); 4572589f188SGreg Kroah-Hartman return error; 4582589f188SGreg Kroah-Hartman } 4592589f188SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(device_create_bin_file); 4602589f188SGreg Kroah-Hartman 4612589f188SGreg Kroah-Hartman /** 4622589f188SGreg Kroah-Hartman * device_remove_bin_file - remove sysfs binary attribute file 4632589f188SGreg Kroah-Hartman * @dev: device. 4642589f188SGreg Kroah-Hartman * @attr: device binary attribute descriptor. 4652589f188SGreg Kroah-Hartman */ 4662589f188SGreg Kroah-Hartman void device_remove_bin_file(struct device *dev, struct bin_attribute *attr) 4672589f188SGreg Kroah-Hartman { 4682589f188SGreg Kroah-Hartman if (dev) 4692589f188SGreg Kroah-Hartman sysfs_remove_bin_file(&dev->kobj, attr); 4702589f188SGreg Kroah-Hartman } 4712589f188SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(device_remove_bin_file); 4722589f188SGreg Kroah-Hartman 473d9a9cdfbSAlan Stern /** 474523ded71SAlan Stern * device_schedule_callback_owner - helper to schedule a callback for a device 475d9a9cdfbSAlan Stern * @dev: device. 476d9a9cdfbSAlan Stern * @func: callback function to invoke later. 477523ded71SAlan Stern * @owner: module owning the callback routine 478d9a9cdfbSAlan Stern * 479d9a9cdfbSAlan Stern * Attribute methods must not unregister themselves or their parent device 480d9a9cdfbSAlan Stern * (which would amount to the same thing). Attempts to do so will deadlock, 481d9a9cdfbSAlan Stern * since unregistration is mutually exclusive with driver callbacks. 482d9a9cdfbSAlan Stern * 483d9a9cdfbSAlan Stern * Instead methods can call this routine, which will attempt to allocate 484d9a9cdfbSAlan Stern * and schedule a workqueue request to call back @func with @dev as its 485d9a9cdfbSAlan Stern * argument in the workqueue's process context. @dev will be pinned until 486d9a9cdfbSAlan Stern * @func returns. 487d9a9cdfbSAlan Stern * 488523ded71SAlan Stern * This routine is usually called via the inline device_schedule_callback(), 489523ded71SAlan Stern * which automatically sets @owner to THIS_MODULE. 490523ded71SAlan Stern * 491d9a9cdfbSAlan Stern * Returns 0 if the request was submitted, -ENOMEM if storage could not 492523ded71SAlan Stern * be allocated, -ENODEV if a reference to @owner isn't available. 493d9a9cdfbSAlan Stern * 494d9a9cdfbSAlan Stern * NOTE: This routine won't work if CONFIG_SYSFS isn't set! It uses an 495d9a9cdfbSAlan Stern * underlying sysfs routine (since it is intended for use by attribute 496d9a9cdfbSAlan Stern * methods), and if sysfs isn't available you'll get nothing but -ENOSYS. 497d9a9cdfbSAlan Stern */ 498523ded71SAlan Stern int device_schedule_callback_owner(struct device *dev, 499523ded71SAlan Stern void (*func)(struct device *), struct module *owner) 500d9a9cdfbSAlan Stern { 501d9a9cdfbSAlan Stern return sysfs_schedule_callback(&dev->kobj, 502523ded71SAlan Stern (void (*)(void *)) func, dev, owner); 503d9a9cdfbSAlan Stern } 504523ded71SAlan Stern EXPORT_SYMBOL_GPL(device_schedule_callback_owner); 505d9a9cdfbSAlan Stern 50634bb61f9SJames Bottomley static void klist_children_get(struct klist_node *n) 50734bb61f9SJames Bottomley { 50834bb61f9SJames Bottomley struct device *dev = container_of(n, struct device, knode_parent); 50934bb61f9SJames Bottomley 51034bb61f9SJames Bottomley get_device(dev); 51134bb61f9SJames Bottomley } 51234bb61f9SJames Bottomley 51334bb61f9SJames Bottomley static void klist_children_put(struct klist_node *n) 51434bb61f9SJames Bottomley { 51534bb61f9SJames Bottomley struct device *dev = container_of(n, struct device, knode_parent); 51634bb61f9SJames Bottomley 51734bb61f9SJames Bottomley put_device(dev); 51834bb61f9SJames Bottomley } 51934bb61f9SJames Bottomley 5201da177e4SLinus Torvalds /** 5211da177e4SLinus Torvalds * device_initialize - init device structure. 5221da177e4SLinus Torvalds * @dev: device. 5231da177e4SLinus Torvalds * 5241da177e4SLinus Torvalds * This prepares the device for use by other layers, 5251da177e4SLinus Torvalds * including adding it to the device hierarchy. 5261da177e4SLinus Torvalds * It is the first half of device_register(), if called by 5271da177e4SLinus Torvalds * that, though it can also be called separately, so one 5281da177e4SLinus Torvalds * may use @dev's fields (e.g. the refcount). 5291da177e4SLinus Torvalds */ 5301da177e4SLinus Torvalds void device_initialize(struct device *dev) 5311da177e4SLinus Torvalds { 532881c6cfdSGreg Kroah-Hartman dev->kobj.kset = devices_kset; 533f9cb074bSGreg Kroah-Hartman kobject_init(&dev->kobj, &device_ktype); 53434bb61f9SJames Bottomley klist_init(&dev->klist_children, klist_children_get, 53534bb61f9SJames Bottomley klist_children_put); 5361da177e4SLinus Torvalds INIT_LIST_HEAD(&dev->dma_pools); 53723681e47SGreg Kroah-Hartman INIT_LIST_HEAD(&dev->node); 538af70316aSmochel@digitalimplant.org init_MUTEX(&dev->sem); 5399ac7849eSTejun Heo spin_lock_init(&dev->devres_lock); 5409ac7849eSTejun Heo INIT_LIST_HEAD(&dev->devres_head); 5410ac85241SDavid Brownell device_init_wakeup(dev, 0); 54287348136SChristoph Hellwig set_dev_node(dev, -1); 5431da177e4SLinus Torvalds } 5441da177e4SLinus Torvalds 54540fa5422SGreg Kroah-Hartman #ifdef CONFIG_SYSFS_DEPRECATED 546c744aeaeSCornelia Huck static struct kobject *get_device_parent(struct device *dev, 547c744aeaeSCornelia Huck struct device *parent) 54840fa5422SGreg Kroah-Hartman { 549da231fd5SKay Sievers /* class devices without a parent live in /sys/class/<classname>/ */ 5503eb215deSDmitry Torokhov if (dev->class && (!parent || parent->class != dev->class)) 551823bccfcSGreg Kroah-Hartman return &dev->class->subsys.kobj; 552da231fd5SKay Sievers /* all other devices keep their parent */ 55340fa5422SGreg Kroah-Hartman else if (parent) 554c744aeaeSCornelia Huck return &parent->kobj; 55540fa5422SGreg Kroah-Hartman 556c744aeaeSCornelia Huck return NULL; 55740fa5422SGreg Kroah-Hartman } 558da231fd5SKay Sievers 559da231fd5SKay Sievers static inline void cleanup_device_parent(struct device *dev) {} 56063b6971aSCornelia Huck static inline void cleanup_glue_dir(struct device *dev, 56163b6971aSCornelia Huck struct kobject *glue_dir) {} 56240fa5422SGreg Kroah-Hartman #else 563c744aeaeSCornelia Huck static struct kobject *virtual_device_parent(struct device *dev) 564f0ee61a6SGreg Kroah-Hartman { 565f0ee61a6SGreg Kroah-Hartman static struct kobject *virtual_dir = NULL; 566f0ee61a6SGreg Kroah-Hartman 567f0ee61a6SGreg Kroah-Hartman if (!virtual_dir) 5684ff6abffSGreg Kroah-Hartman virtual_dir = kobject_create_and_add("virtual", 569881c6cfdSGreg Kroah-Hartman &devices_kset->kobj); 570f0ee61a6SGreg Kroah-Hartman 57186406245SKay Sievers return virtual_dir; 572f0ee61a6SGreg Kroah-Hartman } 573f0ee61a6SGreg Kroah-Hartman 574c744aeaeSCornelia Huck static struct kobject *get_device_parent(struct device *dev, 575c744aeaeSCornelia Huck struct device *parent) 57640fa5422SGreg Kroah-Hartman { 57743968d2fSGreg Kroah-Hartman int retval; 57843968d2fSGreg Kroah-Hartman 57986406245SKay Sievers if (dev->class) { 58086406245SKay Sievers struct kobject *kobj = NULL; 58186406245SKay Sievers struct kobject *parent_kobj; 58286406245SKay Sievers struct kobject *k; 58386406245SKay Sievers 58486406245SKay Sievers /* 58586406245SKay Sievers * If we have no parent, we live in "virtual". 5860f4dafc0SKay Sievers * Class-devices with a non class-device as parent, live 5870f4dafc0SKay Sievers * in a "glue" directory to prevent namespace collisions. 58886406245SKay Sievers */ 58986406245SKay Sievers if (parent == NULL) 59086406245SKay Sievers parent_kobj = virtual_device_parent(dev); 59186406245SKay Sievers else if (parent->class) 59286406245SKay Sievers return &parent->kobj; 59386406245SKay Sievers else 59486406245SKay Sievers parent_kobj = &parent->kobj; 59586406245SKay Sievers 59686406245SKay Sievers /* find our class-directory at the parent and reference it */ 59786406245SKay Sievers spin_lock(&dev->class->class_dirs.list_lock); 59886406245SKay Sievers list_for_each_entry(k, &dev->class->class_dirs.list, entry) 59986406245SKay Sievers if (k->parent == parent_kobj) { 60086406245SKay Sievers kobj = kobject_get(k); 60186406245SKay Sievers break; 60286406245SKay Sievers } 60386406245SKay Sievers spin_unlock(&dev->class->class_dirs.list_lock); 60486406245SKay Sievers if (kobj) 60586406245SKay Sievers return kobj; 60686406245SKay Sievers 60786406245SKay Sievers /* or create a new class-directory at the parent device */ 60843968d2fSGreg Kroah-Hartman k = kobject_create(); 60943968d2fSGreg Kroah-Hartman if (!k) 61043968d2fSGreg Kroah-Hartman return NULL; 61143968d2fSGreg Kroah-Hartman k->kset = &dev->class->class_dirs; 612b2d6db58SGreg Kroah-Hartman retval = kobject_add(k, parent_kobj, "%s", dev->class->name); 61343968d2fSGreg Kroah-Hartman if (retval < 0) { 61443968d2fSGreg Kroah-Hartman kobject_put(k); 61543968d2fSGreg Kroah-Hartman return NULL; 61643968d2fSGreg Kroah-Hartman } 6170f4dafc0SKay Sievers /* do not emit an uevent for this simple "glue" directory */ 61843968d2fSGreg Kroah-Hartman return k; 61986406245SKay Sievers } 62086406245SKay Sievers 62186406245SKay Sievers if (parent) 622c744aeaeSCornelia Huck return &parent->kobj; 623c744aeaeSCornelia Huck return NULL; 624c744aeaeSCornelia Huck } 625da231fd5SKay Sievers 62663b6971aSCornelia Huck static void cleanup_glue_dir(struct device *dev, struct kobject *glue_dir) 627da231fd5SKay Sievers { 6280f4dafc0SKay Sievers /* see if we live in a "glue" directory */ 629c1fe539aSCornelia Huck if (!glue_dir || !dev->class || 630c1fe539aSCornelia Huck glue_dir->kset != &dev->class->class_dirs) 631da231fd5SKay Sievers return; 632da231fd5SKay Sievers 6330f4dafc0SKay Sievers kobject_put(glue_dir); 634da231fd5SKay Sievers } 63563b6971aSCornelia Huck 63663b6971aSCornelia Huck static void cleanup_device_parent(struct device *dev) 63763b6971aSCornelia Huck { 63863b6971aSCornelia Huck cleanup_glue_dir(dev, dev->kobj.parent); 63963b6971aSCornelia Huck } 640c744aeaeSCornelia Huck #endif 64186406245SKay Sievers 64263b6971aSCornelia Huck static void setup_parent(struct device *dev, struct device *parent) 643c744aeaeSCornelia Huck { 644c744aeaeSCornelia Huck struct kobject *kobj; 645c744aeaeSCornelia Huck kobj = get_device_parent(dev, parent); 646c744aeaeSCornelia Huck if (kobj) 647c744aeaeSCornelia Huck dev->kobj.parent = kobj; 64840fa5422SGreg Kroah-Hartman } 64940fa5422SGreg Kroah-Hartman 6502ee97cafSCornelia Huck static int device_add_class_symlinks(struct device *dev) 6512ee97cafSCornelia Huck { 6522ee97cafSCornelia Huck int error; 6532ee97cafSCornelia Huck 6542ee97cafSCornelia Huck if (!dev->class) 6552ee97cafSCornelia Huck return 0; 656da231fd5SKay Sievers 6572ee97cafSCornelia Huck error = sysfs_create_link(&dev->kobj, &dev->class->subsys.kobj, 6582ee97cafSCornelia Huck "subsystem"); 6592ee97cafSCornelia Huck if (error) 6602ee97cafSCornelia Huck goto out; 661da231fd5SKay Sievers 662da231fd5SKay Sievers #ifdef CONFIG_SYSFS_DEPRECATED 663da231fd5SKay Sievers /* stacked class devices need a symlink in the class directory */ 664edfaa7c3SKay Sievers if (dev->kobj.parent != &dev->class->subsys.kobj && 6654e886c29SGreg Kroah-Hartman device_is_not_partition(dev)) { 6662ee97cafSCornelia Huck error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj, 6672ee97cafSCornelia Huck dev->bus_id); 6682ee97cafSCornelia Huck if (error) 6692ee97cafSCornelia Huck goto out_subsys; 6702ee97cafSCornelia Huck } 671da231fd5SKay Sievers 6724e886c29SGreg Kroah-Hartman if (dev->parent && device_is_not_partition(dev)) { 6734f01a757SDmitry Torokhov struct device *parent = dev->parent; 6744f01a757SDmitry Torokhov char *class_name; 6754f01a757SDmitry Torokhov 6764f01a757SDmitry Torokhov /* 677da231fd5SKay Sievers * stacked class devices have the 'device' link 678da231fd5SKay Sievers * pointing to the bus device instead of the parent 6794f01a757SDmitry Torokhov */ 6804f01a757SDmitry Torokhov while (parent->class && !parent->bus && parent->parent) 6814f01a757SDmitry Torokhov parent = parent->parent; 6824f01a757SDmitry Torokhov 6834f01a757SDmitry Torokhov error = sysfs_create_link(&dev->kobj, 6844f01a757SDmitry Torokhov &parent->kobj, 6852ee97cafSCornelia Huck "device"); 6862ee97cafSCornelia Huck if (error) 6872ee97cafSCornelia Huck goto out_busid; 6884f01a757SDmitry Torokhov 6894f01a757SDmitry Torokhov class_name = make_class_name(dev->class->name, 6902ee97cafSCornelia Huck &dev->kobj); 6912ee97cafSCornelia Huck if (class_name) 6922ee97cafSCornelia Huck error = sysfs_create_link(&dev->parent->kobj, 6932ee97cafSCornelia Huck &dev->kobj, class_name); 6942ee97cafSCornelia Huck kfree(class_name); 6952ee97cafSCornelia Huck if (error) 6962ee97cafSCornelia Huck goto out_device; 6972ee97cafSCornelia Huck } 698da231fd5SKay Sievers return 0; 699da231fd5SKay Sievers 700da231fd5SKay Sievers out_device: 7014e886c29SGreg Kroah-Hartman if (dev->parent && device_is_not_partition(dev)) 702da231fd5SKay Sievers sysfs_remove_link(&dev->kobj, "device"); 703da231fd5SKay Sievers out_busid: 704edfaa7c3SKay Sievers if (dev->kobj.parent != &dev->class->subsys.kobj && 7054e886c29SGreg Kroah-Hartman device_is_not_partition(dev)) 706da231fd5SKay Sievers sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id); 7074f01a757SDmitry Torokhov #else 708da231fd5SKay Sievers /* link in the class directory pointing to the device */ 709da231fd5SKay Sievers error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj, 710da231fd5SKay Sievers dev->bus_id); 711da231fd5SKay Sievers if (error) 712da231fd5SKay Sievers goto out_subsys; 713da231fd5SKay Sievers 7144e886c29SGreg Kroah-Hartman if (dev->parent && device_is_not_partition(dev)) { 7154f01a757SDmitry Torokhov error = sysfs_create_link(&dev->kobj, &dev->parent->kobj, 7164f01a757SDmitry Torokhov "device"); 7174f01a757SDmitry Torokhov if (error) 7184f01a757SDmitry Torokhov goto out_busid; 7192ee97cafSCornelia Huck } 7202ee97cafSCornelia Huck return 0; 7212ee97cafSCornelia Huck 7222ee97cafSCornelia Huck out_busid: 7232ee97cafSCornelia Huck sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id); 724da231fd5SKay Sievers #endif 725da231fd5SKay Sievers 7262ee97cafSCornelia Huck out_subsys: 7272ee97cafSCornelia Huck sysfs_remove_link(&dev->kobj, "subsystem"); 7282ee97cafSCornelia Huck out: 7292ee97cafSCornelia Huck return error; 7302ee97cafSCornelia Huck } 7312ee97cafSCornelia Huck 7322ee97cafSCornelia Huck static void device_remove_class_symlinks(struct device *dev) 7332ee97cafSCornelia Huck { 7342ee97cafSCornelia Huck if (!dev->class) 7352ee97cafSCornelia Huck return; 736da231fd5SKay Sievers 7372ee97cafSCornelia Huck #ifdef CONFIG_SYSFS_DEPRECATED 7384e886c29SGreg Kroah-Hartman if (dev->parent && device_is_not_partition(dev)) { 7392ee97cafSCornelia Huck char *class_name; 7402ee97cafSCornelia Huck 7412ee97cafSCornelia Huck class_name = make_class_name(dev->class->name, &dev->kobj); 7422ee97cafSCornelia Huck if (class_name) { 7432ee97cafSCornelia Huck sysfs_remove_link(&dev->parent->kobj, class_name); 7442ee97cafSCornelia Huck kfree(class_name); 7452ee97cafSCornelia Huck } 7462ee97cafSCornelia Huck sysfs_remove_link(&dev->kobj, "device"); 7472ee97cafSCornelia Huck } 748da231fd5SKay Sievers 749edfaa7c3SKay Sievers if (dev->kobj.parent != &dev->class->subsys.kobj && 7504e886c29SGreg Kroah-Hartman device_is_not_partition(dev)) 7512ee97cafSCornelia Huck sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id); 752da231fd5SKay Sievers #else 7534e886c29SGreg Kroah-Hartman if (dev->parent && device_is_not_partition(dev)) 754da231fd5SKay Sievers sysfs_remove_link(&dev->kobj, "device"); 755da231fd5SKay Sievers 756da231fd5SKay Sievers sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id); 757da231fd5SKay Sievers #endif 758da231fd5SKay Sievers 7592ee97cafSCornelia Huck sysfs_remove_link(&dev->kobj, "subsystem"); 7602ee97cafSCornelia Huck } 7612ee97cafSCornelia Huck 7621da177e4SLinus Torvalds /** 7631da177e4SLinus Torvalds * device_add - add device to device hierarchy. 7641da177e4SLinus Torvalds * @dev: device. 7651da177e4SLinus Torvalds * 7661da177e4SLinus Torvalds * This is part 2 of device_register(), though may be called 7671da177e4SLinus Torvalds * separately _iff_ device_initialize() has been called separately. 7681da177e4SLinus Torvalds * 769b2d6db58SGreg Kroah-Hartman * This adds it to the kobject hierarchy via kobject_add(), adds it 7701da177e4SLinus Torvalds * to the global and sibling lists for the device, then 7711da177e4SLinus Torvalds * adds it to the other relevant subsystems of the driver model. 7721da177e4SLinus Torvalds */ 7731da177e4SLinus Torvalds int device_add(struct device *dev) 7741da177e4SLinus Torvalds { 7751da177e4SLinus Torvalds struct device *parent = NULL; 776c47ed219SGreg Kroah-Hartman struct class_interface *class_intf; 777775b64d2SRafael J. Wysocki int error; 778775b64d2SRafael J. Wysocki 7791da177e4SLinus Torvalds dev = get_device(dev); 780775b64d2SRafael J. Wysocki if (!dev || !strlen(dev->bus_id)) { 781775b64d2SRafael J. Wysocki error = -EINVAL; 782c1fe539aSCornelia Huck goto Done; 783775b64d2SRafael J. Wysocki } 7841da177e4SLinus Torvalds 7857dc72b28SGreg Kroah-Hartman pr_debug("device: '%s': %s\n", dev->bus_id, __FUNCTION__); 786c205ef48SGreg Kroah-Hartman 7871da177e4SLinus Torvalds parent = get_device(dev->parent); 78863b6971aSCornelia Huck setup_parent(dev, parent); 7891da177e4SLinus Torvalds 7901da177e4SLinus Torvalds /* first, register with generic layer. */ 791b2d6db58SGreg Kroah-Hartman error = kobject_add(&dev->kobj, dev->kobj.parent, "%s", dev->bus_id); 79240fa5422SGreg Kroah-Hartman if (error) 7931da177e4SLinus Torvalds goto Error; 794a7fd6706SKay Sievers 79537022644SBrian Walsh /* notify platform of device entry */ 79637022644SBrian Walsh if (platform_notify) 79737022644SBrian Walsh platform_notify(dev); 79837022644SBrian Walsh 799116af378SBenjamin Herrenschmidt /* notify clients of device entry (new way) */ 800116af378SBenjamin Herrenschmidt if (dev->bus) 801c6f7e72aSGreg Kroah-Hartman blocking_notifier_call_chain(&dev->bus->p->bus_notifier, 802116af378SBenjamin Herrenschmidt BUS_NOTIFY_ADD_DEVICE, dev); 803116af378SBenjamin Herrenschmidt 804ad6a1e1cSTejun Heo error = device_create_file(dev, &uevent_attr); 805a306eea4SCornelia Huck if (error) 806a306eea4SCornelia Huck goto attrError; 807a7fd6706SKay Sievers 80823681e47SGreg Kroah-Hartman if (MAJOR(dev->devt)) { 809ad6a1e1cSTejun Heo error = device_create_file(dev, &devt_attr); 810ad6a1e1cSTejun Heo if (error) 811a306eea4SCornelia Huck goto ueventattrError; 81223681e47SGreg Kroah-Hartman } 81323681e47SGreg Kroah-Hartman 8142ee97cafSCornelia Huck error = device_add_class_symlinks(dev); 8152ee97cafSCornelia Huck if (error) 8162ee97cafSCornelia Huck goto SymlinkError; 817dc0afa83SCornelia Huck error = device_add_attrs(dev); 818dc0afa83SCornelia Huck if (error) 8192620efefSGreg Kroah-Hartman goto AttrsError; 820dec13c15SDaniel Drake error = dpm_sysfs_add(dev); 821dc0afa83SCornelia Huck if (error) 8221da177e4SLinus Torvalds goto PMError; 823dec13c15SDaniel Drake device_pm_add(dev); 824dc0afa83SCornelia Huck error = bus_add_device(dev); 825dc0afa83SCornelia Huck if (error) 8261da177e4SLinus Torvalds goto BusError; 82753877d06SKay Sievers kobject_uevent(&dev->kobj, KOBJ_ADD); 828c6a46696SCornelia Huck bus_attach_device(dev); 8291da177e4SLinus Torvalds if (parent) 830d856f1e3SJames Bottomley klist_add_tail(&dev->knode_parent, &parent->klist_children); 8311da177e4SLinus Torvalds 8325d9fd169SGreg Kroah-Hartman if (dev->class) { 8335d9fd169SGreg Kroah-Hartman down(&dev->class->sem); 834c47ed219SGreg Kroah-Hartman /* tie the class to the device */ 8355d9fd169SGreg Kroah-Hartman list_add_tail(&dev->node, &dev->class->devices); 836c47ed219SGreg Kroah-Hartman 837c47ed219SGreg Kroah-Hartman /* notify any interfaces that the device is here */ 838c47ed219SGreg Kroah-Hartman list_for_each_entry(class_intf, &dev->class->interfaces, node) 839c47ed219SGreg Kroah-Hartman if (class_intf->add_dev) 840c47ed219SGreg Kroah-Hartman class_intf->add_dev(dev, class_intf); 8415d9fd169SGreg Kroah-Hartman up(&dev->class->sem); 8425d9fd169SGreg Kroah-Hartman } 8431da177e4SLinus Torvalds Done: 8441da177e4SLinus Torvalds put_device(dev); 8451da177e4SLinus Torvalds return error; 8461da177e4SLinus Torvalds BusError: 8471da177e4SLinus Torvalds device_pm_remove(dev); 8481da177e4SLinus Torvalds PMError: 849116af378SBenjamin Herrenschmidt if (dev->bus) 850c6f7e72aSGreg Kroah-Hartman blocking_notifier_call_chain(&dev->bus->p->bus_notifier, 851116af378SBenjamin Herrenschmidt BUS_NOTIFY_DEL_DEVICE, dev); 8522620efefSGreg Kroah-Hartman device_remove_attrs(dev); 8532620efefSGreg Kroah-Hartman AttrsError: 8542ee97cafSCornelia Huck device_remove_class_symlinks(dev); 8552ee97cafSCornelia Huck SymlinkError: 856ad6a1e1cSTejun Heo if (MAJOR(dev->devt)) 857ad6a1e1cSTejun Heo device_remove_file(dev, &devt_attr); 858a306eea4SCornelia Huck ueventattrError: 859ad6a1e1cSTejun Heo device_remove_file(dev, &uevent_attr); 86023681e47SGreg Kroah-Hartman attrError: 861312c004dSKay Sievers kobject_uevent(&dev->kobj, KOBJ_REMOVE); 8621da177e4SLinus Torvalds kobject_del(&dev->kobj); 8631da177e4SLinus Torvalds Error: 86463b6971aSCornelia Huck cleanup_device_parent(dev); 8651da177e4SLinus Torvalds if (parent) 8661da177e4SLinus Torvalds put_device(parent); 8671da177e4SLinus Torvalds goto Done; 8681da177e4SLinus Torvalds } 8691da177e4SLinus Torvalds 8701da177e4SLinus Torvalds /** 8711da177e4SLinus Torvalds * device_register - register a device with the system. 8721da177e4SLinus Torvalds * @dev: pointer to the device structure 8731da177e4SLinus Torvalds * 8741da177e4SLinus Torvalds * This happens in two clean steps - initialize the device 8751da177e4SLinus Torvalds * and add it to the system. The two steps can be called 8761da177e4SLinus Torvalds * separately, but this is the easiest and most common. 8771da177e4SLinus Torvalds * I.e. you should only call the two helpers separately if 8781da177e4SLinus Torvalds * have a clearly defined need to use and refcount the device 8791da177e4SLinus Torvalds * before it is added to the hierarchy. 8801da177e4SLinus Torvalds */ 8811da177e4SLinus Torvalds int device_register(struct device *dev) 8821da177e4SLinus Torvalds { 8831da177e4SLinus Torvalds device_initialize(dev); 8841da177e4SLinus Torvalds return device_add(dev); 8851da177e4SLinus Torvalds } 8861da177e4SLinus Torvalds 8871da177e4SLinus Torvalds /** 8881da177e4SLinus Torvalds * get_device - increment reference count for device. 8891da177e4SLinus Torvalds * @dev: device. 8901da177e4SLinus Torvalds * 8911da177e4SLinus Torvalds * This simply forwards the call to kobject_get(), though 8921da177e4SLinus Torvalds * we do take care to provide for the case that we get a NULL 8931da177e4SLinus Torvalds * pointer passed in. 8941da177e4SLinus Torvalds */ 8951da177e4SLinus Torvalds struct device *get_device(struct device *dev) 8961da177e4SLinus Torvalds { 8971da177e4SLinus Torvalds return dev ? to_dev(kobject_get(&dev->kobj)) : NULL; 8981da177e4SLinus Torvalds } 8991da177e4SLinus Torvalds 9001da177e4SLinus Torvalds /** 9011da177e4SLinus Torvalds * put_device - decrement reference count. 9021da177e4SLinus Torvalds * @dev: device in question. 9031da177e4SLinus Torvalds */ 9041da177e4SLinus Torvalds void put_device(struct device *dev) 9051da177e4SLinus Torvalds { 906edfaa7c3SKay Sievers /* might_sleep(); */ 9071da177e4SLinus Torvalds if (dev) 9081da177e4SLinus Torvalds kobject_put(&dev->kobj); 9091da177e4SLinus Torvalds } 9101da177e4SLinus Torvalds 9111da177e4SLinus Torvalds /** 9121da177e4SLinus Torvalds * device_del - delete device from system. 9131da177e4SLinus Torvalds * @dev: device. 9141da177e4SLinus Torvalds * 9151da177e4SLinus Torvalds * This is the first part of the device unregistration 9161da177e4SLinus Torvalds * sequence. This removes the device from the lists we control 9171da177e4SLinus Torvalds * from here, has it removed from the other driver model 9181da177e4SLinus Torvalds * subsystems it was added to in device_add(), and removes it 9191da177e4SLinus Torvalds * from the kobject hierarchy. 9201da177e4SLinus Torvalds * 9211da177e4SLinus Torvalds * NOTE: this should be called manually _iff_ device_add() was 9221da177e4SLinus Torvalds * also called manually. 9231da177e4SLinus Torvalds */ 9241da177e4SLinus Torvalds void device_del(struct device *dev) 9251da177e4SLinus Torvalds { 9261da177e4SLinus Torvalds struct device *parent = dev->parent; 927c47ed219SGreg Kroah-Hartman struct class_interface *class_intf; 9281da177e4SLinus Torvalds 929775b64d2SRafael J. Wysocki device_pm_remove(dev); 9301da177e4SLinus Torvalds if (parent) 931d62c0f9fSPatrick Mochel klist_del(&dev->knode_parent); 932ad6a1e1cSTejun Heo if (MAJOR(dev->devt)) 933ad6a1e1cSTejun Heo device_remove_file(dev, &devt_attr); 934b9d9c82bSKay Sievers if (dev->class) { 935da231fd5SKay Sievers device_remove_class_symlinks(dev); 93699ef3ef8SKay Sievers 9375d9fd169SGreg Kroah-Hartman down(&dev->class->sem); 938c47ed219SGreg Kroah-Hartman /* notify any interfaces that the device is now gone */ 939c47ed219SGreg Kroah-Hartman list_for_each_entry(class_intf, &dev->class->interfaces, node) 940c47ed219SGreg Kroah-Hartman if (class_intf->remove_dev) 941c47ed219SGreg Kroah-Hartman class_intf->remove_dev(dev, class_intf); 942c47ed219SGreg Kroah-Hartman /* remove the device from the class list */ 9435d9fd169SGreg Kroah-Hartman list_del_init(&dev->node); 9445d9fd169SGreg Kroah-Hartman up(&dev->class->sem); 945b9d9c82bSKay Sievers } 946ad6a1e1cSTejun Heo device_remove_file(dev, &uevent_attr); 9472620efefSGreg Kroah-Hartman device_remove_attrs(dev); 94828953533SBenjamin Herrenschmidt bus_remove_device(dev); 9491da177e4SLinus Torvalds 9502f8d16a9STejun Heo /* 9512f8d16a9STejun Heo * Some platform devices are driven without driver attached 9522f8d16a9STejun Heo * and managed resources may have been acquired. Make sure 9532f8d16a9STejun Heo * all resources are released. 9542f8d16a9STejun Heo */ 9552f8d16a9STejun Heo devres_release_all(dev); 9562f8d16a9STejun Heo 9571da177e4SLinus Torvalds /* Notify the platform of the removal, in case they 9581da177e4SLinus Torvalds * need to do anything... 9591da177e4SLinus Torvalds */ 9601da177e4SLinus Torvalds if (platform_notify_remove) 9611da177e4SLinus Torvalds platform_notify_remove(dev); 962116af378SBenjamin Herrenschmidt if (dev->bus) 963c6f7e72aSGreg Kroah-Hartman blocking_notifier_call_chain(&dev->bus->p->bus_notifier, 964116af378SBenjamin Herrenschmidt BUS_NOTIFY_DEL_DEVICE, dev); 965312c004dSKay Sievers kobject_uevent(&dev->kobj, KOBJ_REMOVE); 966da231fd5SKay Sievers cleanup_device_parent(dev); 9671da177e4SLinus Torvalds kobject_del(&dev->kobj); 9681da177e4SLinus Torvalds put_device(parent); 9691da177e4SLinus Torvalds } 9701da177e4SLinus Torvalds 9711da177e4SLinus Torvalds /** 9721da177e4SLinus Torvalds * device_unregister - unregister device from system. 9731da177e4SLinus Torvalds * @dev: device going away. 9741da177e4SLinus Torvalds * 9751da177e4SLinus Torvalds * We do this in two parts, like we do device_register(). First, 9761da177e4SLinus Torvalds * we remove it from all the subsystems with device_del(), then 9771da177e4SLinus Torvalds * we decrement the reference count via put_device(). If that 9781da177e4SLinus Torvalds * is the final reference count, the device will be cleaned up 9791da177e4SLinus Torvalds * via device_release() above. Otherwise, the structure will 9801da177e4SLinus Torvalds * stick around until the final reference to the device is dropped. 9811da177e4SLinus Torvalds */ 9821da177e4SLinus Torvalds void device_unregister(struct device *dev) 9831da177e4SLinus Torvalds { 9847dc72b28SGreg Kroah-Hartman pr_debug("device: '%s': %s\n", dev->bus_id, __FUNCTION__); 9851da177e4SLinus Torvalds device_del(dev); 9861da177e4SLinus Torvalds put_device(dev); 9871da177e4SLinus Torvalds } 9881da177e4SLinus Torvalds 98936239577Smochel@digitalimplant.org static struct device *next_device(struct klist_iter *i) 99036239577Smochel@digitalimplant.org { 99136239577Smochel@digitalimplant.org struct klist_node *n = klist_next(i); 99236239577Smochel@digitalimplant.org return n ? container_of(n, struct device, knode_parent) : NULL; 99336239577Smochel@digitalimplant.org } 99436239577Smochel@digitalimplant.org 9951da177e4SLinus Torvalds /** 9961da177e4SLinus Torvalds * device_for_each_child - device child iterator. 997c41455fbSRandy Dunlap * @parent: parent struct device. 9981da177e4SLinus Torvalds * @data: data for the callback. 9991da177e4SLinus Torvalds * @fn: function to be called for each device. 10001da177e4SLinus Torvalds * 1001c41455fbSRandy Dunlap * Iterate over @parent's child devices, and call @fn for each, 10021da177e4SLinus Torvalds * passing it @data. 10031da177e4SLinus Torvalds * 10041da177e4SLinus Torvalds * We check the return of @fn each time. If it returns anything 10051da177e4SLinus Torvalds * other than 0, we break out and return that value. 10061da177e4SLinus Torvalds */ 100736239577Smochel@digitalimplant.org int device_for_each_child(struct device *parent, void *data, 10084a3ad20cSGreg Kroah-Hartman int (*fn)(struct device *dev, void *data)) 10091da177e4SLinus Torvalds { 101036239577Smochel@digitalimplant.org struct klist_iter i; 10111da177e4SLinus Torvalds struct device *child; 10121da177e4SLinus Torvalds int error = 0; 10131da177e4SLinus Torvalds 101436239577Smochel@digitalimplant.org klist_iter_init(&parent->klist_children, &i); 101536239577Smochel@digitalimplant.org while ((child = next_device(&i)) && !error) 101636239577Smochel@digitalimplant.org error = fn(child, data); 101736239577Smochel@digitalimplant.org klist_iter_exit(&i); 10181da177e4SLinus Torvalds return error; 10191da177e4SLinus Torvalds } 10201da177e4SLinus Torvalds 10215ab69981SCornelia Huck /** 10225ab69981SCornelia Huck * device_find_child - device iterator for locating a particular device. 10235ab69981SCornelia Huck * @parent: parent struct device 10245ab69981SCornelia Huck * @data: Data to pass to match function 10255ab69981SCornelia Huck * @match: Callback function to check device 10265ab69981SCornelia Huck * 10275ab69981SCornelia Huck * This is similar to the device_for_each_child() function above, but it 10285ab69981SCornelia Huck * returns a reference to a device that is 'found' for later use, as 10295ab69981SCornelia Huck * determined by the @match callback. 10305ab69981SCornelia Huck * 10315ab69981SCornelia Huck * The callback should return 0 if the device doesn't match and non-zero 10325ab69981SCornelia Huck * if it does. If the callback returns non-zero and a reference to the 10335ab69981SCornelia Huck * current device can be obtained, this function will return to the caller 10345ab69981SCornelia Huck * and not iterate over any more devices. 10355ab69981SCornelia Huck */ 10365ab69981SCornelia Huck struct device *device_find_child(struct device *parent, void *data, 10374a3ad20cSGreg Kroah-Hartman int (*match)(struct device *dev, void *data)) 10385ab69981SCornelia Huck { 10395ab69981SCornelia Huck struct klist_iter i; 10405ab69981SCornelia Huck struct device *child; 10415ab69981SCornelia Huck 10425ab69981SCornelia Huck if (!parent) 10435ab69981SCornelia Huck return NULL; 10445ab69981SCornelia Huck 10455ab69981SCornelia Huck klist_iter_init(&parent->klist_children, &i); 10465ab69981SCornelia Huck while ((child = next_device(&i))) 10475ab69981SCornelia Huck if (match(child, data) && get_device(child)) 10485ab69981SCornelia Huck break; 10495ab69981SCornelia Huck klist_iter_exit(&i); 10505ab69981SCornelia Huck return child; 10515ab69981SCornelia Huck } 10525ab69981SCornelia Huck 10531da177e4SLinus Torvalds int __init devices_init(void) 10541da177e4SLinus Torvalds { 1055881c6cfdSGreg Kroah-Hartman devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL); 1056881c6cfdSGreg Kroah-Hartman if (!devices_kset) 1057881c6cfdSGreg Kroah-Hartman return -ENOMEM; 1058881c6cfdSGreg Kroah-Hartman return 0; 10591da177e4SLinus Torvalds } 10601da177e4SLinus Torvalds 10611da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(device_for_each_child); 10625ab69981SCornelia Huck EXPORT_SYMBOL_GPL(device_find_child); 10631da177e4SLinus Torvalds 10641da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(device_initialize); 10651da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(device_add); 10661da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(device_register); 10671da177e4SLinus Torvalds 10681da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(device_del); 10691da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(device_unregister); 10701da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(get_device); 10711da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(put_device); 10721da177e4SLinus Torvalds 10731da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(device_create_file); 10741da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(device_remove_file); 107523681e47SGreg Kroah-Hartman 107623681e47SGreg Kroah-Hartman 107723681e47SGreg Kroah-Hartman static void device_create_release(struct device *dev) 107823681e47SGreg Kroah-Hartman { 10797dc72b28SGreg Kroah-Hartman pr_debug("device: '%s': %s\n", dev->bus_id, __FUNCTION__); 108023681e47SGreg Kroah-Hartman kfree(dev); 108123681e47SGreg Kroah-Hartman } 108223681e47SGreg Kroah-Hartman 108323681e47SGreg Kroah-Hartman /** 108423681e47SGreg Kroah-Hartman * device_create - creates a device and registers it with sysfs 108542734dafSHenrik Kretzschmar * @class: pointer to the struct class that this device should be registered to 108642734dafSHenrik Kretzschmar * @parent: pointer to the parent struct device of this new device, if any 108742734dafSHenrik Kretzschmar * @devt: the dev_t for the char device to be added 108842734dafSHenrik Kretzschmar * @fmt: string for the device's name 108923681e47SGreg Kroah-Hartman * 109042734dafSHenrik Kretzschmar * This function can be used by char device classes. A struct device 109142734dafSHenrik Kretzschmar * will be created in sysfs, registered to the specified class. 109242734dafSHenrik Kretzschmar * 109323681e47SGreg Kroah-Hartman * A "dev" file will be created, showing the dev_t for the device, if 109423681e47SGreg Kroah-Hartman * the dev_t is not 0,0. 109542734dafSHenrik Kretzschmar * If a pointer to a parent struct device is passed in, the newly created 109642734dafSHenrik Kretzschmar * struct device will be a child of that device in sysfs. 109742734dafSHenrik Kretzschmar * The pointer to the struct device will be returned from the call. 109842734dafSHenrik Kretzschmar * Any further sysfs files that might be required can be created using this 109923681e47SGreg Kroah-Hartman * pointer. 110023681e47SGreg Kroah-Hartman * 110123681e47SGreg Kroah-Hartman * Note: the struct class passed to this function must have previously 110223681e47SGreg Kroah-Hartman * been created with a call to class_create(). 110323681e47SGreg Kroah-Hartman */ 110423681e47SGreg Kroah-Hartman struct device *device_create(struct class *class, struct device *parent, 11055cbe5f8aSGreg Kroah-Hartman dev_t devt, const char *fmt, ...) 110623681e47SGreg Kroah-Hartman { 110723681e47SGreg Kroah-Hartman va_list args; 110823681e47SGreg Kroah-Hartman struct device *dev = NULL; 110923681e47SGreg Kroah-Hartman int retval = -ENODEV; 111023681e47SGreg Kroah-Hartman 111123681e47SGreg Kroah-Hartman if (class == NULL || IS_ERR(class)) 111223681e47SGreg Kroah-Hartman goto error; 111323681e47SGreg Kroah-Hartman 111423681e47SGreg Kroah-Hartman dev = kzalloc(sizeof(*dev), GFP_KERNEL); 111523681e47SGreg Kroah-Hartman if (!dev) { 111623681e47SGreg Kroah-Hartman retval = -ENOMEM; 111723681e47SGreg Kroah-Hartman goto error; 111823681e47SGreg Kroah-Hartman } 111923681e47SGreg Kroah-Hartman 112023681e47SGreg Kroah-Hartman dev->devt = devt; 112123681e47SGreg Kroah-Hartman dev->class = class; 112223681e47SGreg Kroah-Hartman dev->parent = parent; 112323681e47SGreg Kroah-Hartman dev->release = device_create_release; 112423681e47SGreg Kroah-Hartman 112523681e47SGreg Kroah-Hartman va_start(args, fmt); 112623681e47SGreg Kroah-Hartman vsnprintf(dev->bus_id, BUS_ID_SIZE, fmt, args); 112723681e47SGreg Kroah-Hartman va_end(args); 112823681e47SGreg Kroah-Hartman retval = device_register(dev); 112923681e47SGreg Kroah-Hartman if (retval) 113023681e47SGreg Kroah-Hartman goto error; 113123681e47SGreg Kroah-Hartman 113223681e47SGreg Kroah-Hartman return dev; 113323681e47SGreg Kroah-Hartman 113423681e47SGreg Kroah-Hartman error: 113523681e47SGreg Kroah-Hartman kfree(dev); 113623681e47SGreg Kroah-Hartman return ERR_PTR(retval); 113723681e47SGreg Kroah-Hartman } 113823681e47SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(device_create); 113923681e47SGreg Kroah-Hartman 1140cd35449bSDave Young static int __match_devt(struct device *dev, void *data) 114123681e47SGreg Kroah-Hartman { 1142cd35449bSDave Young dev_t *devt = data; 114323681e47SGreg Kroah-Hartman 1144cd35449bSDave Young return dev->devt == *devt; 1145775b64d2SRafael J. Wysocki } 114623681e47SGreg Kroah-Hartman 1147775b64d2SRafael J. Wysocki /** 1148775b64d2SRafael J. Wysocki * device_destroy - removes a device that was created with device_create() 1149775b64d2SRafael J. Wysocki * @class: pointer to the struct class that this device was registered with 1150775b64d2SRafael J. Wysocki * @devt: the dev_t of the device that was previously registered 1151775b64d2SRafael J. Wysocki * 1152775b64d2SRafael J. Wysocki * This call unregisters and cleans up a device that was created with a 1153775b64d2SRafael J. Wysocki * call to device_create(). 1154775b64d2SRafael J. Wysocki */ 1155775b64d2SRafael J. Wysocki void device_destroy(struct class *class, dev_t devt) 1156775b64d2SRafael J. Wysocki { 1157775b64d2SRafael J. Wysocki struct device *dev; 1158775b64d2SRafael J. Wysocki 1159cd35449bSDave Young dev = class_find_device(class, &devt, __match_devt); 1160cd35449bSDave Young if (dev) { 1161cd35449bSDave Young put_device(dev); 116223681e47SGreg Kroah-Hartman device_unregister(dev); 116323681e47SGreg Kroah-Hartman } 1164cd35449bSDave Young } 116523681e47SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(device_destroy); 1166a2de48caSGreg Kroah-Hartman 1167775b64d2SRafael J. Wysocki #ifdef CONFIG_PM_SLEEP 1168775b64d2SRafael J. Wysocki /** 1169775b64d2SRafael J. Wysocki * destroy_suspended_device - asks the PM core to remove a suspended device 1170775b64d2SRafael J. Wysocki * @class: pointer to the struct class that this device was registered with 1171775b64d2SRafael J. Wysocki * @devt: the dev_t of the device that was previously registered 1172775b64d2SRafael J. Wysocki * 1173775b64d2SRafael J. Wysocki * This call notifies the PM core of the necessity to unregister a suspended 1174775b64d2SRafael J. Wysocki * device created with a call to device_create() (devices cannot be 1175775b64d2SRafael J. Wysocki * unregistered directly while suspended, since the PM core holds their 1176775b64d2SRafael J. Wysocki * semaphores at that time). 1177775b64d2SRafael J. Wysocki * 1178775b64d2SRafael J. Wysocki * It can only be called within the scope of a system sleep transition. In 1179775b64d2SRafael J. Wysocki * practice this means it has to be directly or indirectly invoked either by 1180775b64d2SRafael J. Wysocki * a suspend or resume method, or by the PM core (e.g. via 1181775b64d2SRafael J. Wysocki * disable_nonboot_cpus() or enable_nonboot_cpus()). 1182775b64d2SRafael J. Wysocki */ 1183775b64d2SRafael J. Wysocki void destroy_suspended_device(struct class *class, dev_t devt) 1184775b64d2SRafael J. Wysocki { 1185775b64d2SRafael J. Wysocki struct device *dev; 1186775b64d2SRafael J. Wysocki 1187cd35449bSDave Young dev = class_find_device(class, &devt, __match_devt); 1188cd35449bSDave Young if (dev) { 1189775b64d2SRafael J. Wysocki device_pm_schedule_removal(dev); 1190cd35449bSDave Young put_device(dev); 1191cd35449bSDave Young } 1192775b64d2SRafael J. Wysocki } 1193775b64d2SRafael J. Wysocki EXPORT_SYMBOL_GPL(destroy_suspended_device); 1194775b64d2SRafael J. Wysocki #endif /* CONFIG_PM_SLEEP */ 1195775b64d2SRafael J. Wysocki 1196a2de48caSGreg Kroah-Hartman /** 1197a2de48caSGreg Kroah-Hartman * device_rename - renames a device 1198a2de48caSGreg Kroah-Hartman * @dev: the pointer to the struct device to be renamed 1199a2de48caSGreg Kroah-Hartman * @new_name: the new name of the device 1200a2de48caSGreg Kroah-Hartman */ 1201a2de48caSGreg Kroah-Hartman int device_rename(struct device *dev, char *new_name) 1202a2de48caSGreg Kroah-Hartman { 1203a2de48caSGreg Kroah-Hartman char *old_class_name = NULL; 1204a2de48caSGreg Kroah-Hartman char *new_class_name = NULL; 12052ee97cafSCornelia Huck char *old_device_name = NULL; 1206a2de48caSGreg Kroah-Hartman int error; 1207a2de48caSGreg Kroah-Hartman 1208a2de48caSGreg Kroah-Hartman dev = get_device(dev); 1209a2de48caSGreg Kroah-Hartman if (!dev) 1210a2de48caSGreg Kroah-Hartman return -EINVAL; 1211a2de48caSGreg Kroah-Hartman 12127dc72b28SGreg Kroah-Hartman pr_debug("device: '%s': %s: renaming to '%s'\n", dev->bus_id, 12137dc72b28SGreg Kroah-Hartman __FUNCTION__, new_name); 1214a2de48caSGreg Kroah-Hartman 121599ef3ef8SKay Sievers #ifdef CONFIG_SYSFS_DEPRECATED 1216a2de48caSGreg Kroah-Hartman if ((dev->class) && (dev->parent)) 1217a2de48caSGreg Kroah-Hartman old_class_name = make_class_name(dev->class->name, &dev->kobj); 121899ef3ef8SKay Sievers #endif 1219a2de48caSGreg Kroah-Hartman 12202ee97cafSCornelia Huck old_device_name = kmalloc(BUS_ID_SIZE, GFP_KERNEL); 12212ee97cafSCornelia Huck if (!old_device_name) { 1222952ab431SJesper Juhl error = -ENOMEM; 12232ee97cafSCornelia Huck goto out; 1224952ab431SJesper Juhl } 12252ee97cafSCornelia Huck strlcpy(old_device_name, dev->bus_id, BUS_ID_SIZE); 1226a2de48caSGreg Kroah-Hartman strlcpy(dev->bus_id, new_name, BUS_ID_SIZE); 1227a2de48caSGreg Kroah-Hartman 1228a2de48caSGreg Kroah-Hartman error = kobject_rename(&dev->kobj, new_name); 12292ee97cafSCornelia Huck if (error) { 12302ee97cafSCornelia Huck strlcpy(dev->bus_id, old_device_name, BUS_ID_SIZE); 12312ee97cafSCornelia Huck goto out; 12322ee97cafSCornelia Huck } 1233a2de48caSGreg Kroah-Hartman 123499ef3ef8SKay Sievers #ifdef CONFIG_SYSFS_DEPRECATED 1235a2de48caSGreg Kroah-Hartman if (old_class_name) { 1236a2de48caSGreg Kroah-Hartman new_class_name = make_class_name(dev->class->name, &dev->kobj); 1237a2de48caSGreg Kroah-Hartman if (new_class_name) { 12382ee97cafSCornelia Huck error = sysfs_create_link(&dev->parent->kobj, 12392ee97cafSCornelia Huck &dev->kobj, new_class_name); 12402ee97cafSCornelia Huck if (error) 12412ee97cafSCornelia Huck goto out; 1242a2de48caSGreg Kroah-Hartman sysfs_remove_link(&dev->parent->kobj, old_class_name); 1243a2de48caSGreg Kroah-Hartman } 1244a2de48caSGreg Kroah-Hartman } 124560b8cabdSKay Sievers #else 1246a2de48caSGreg Kroah-Hartman if (dev->class) { 12472ee97cafSCornelia Huck sysfs_remove_link(&dev->class->subsys.kobj, old_device_name); 12482ee97cafSCornelia Huck error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj, 1249a2de48caSGreg Kroah-Hartman dev->bus_id); 12502ee97cafSCornelia Huck if (error) { 12512ee97cafSCornelia Huck dev_err(dev, "%s: sysfs_create_symlink failed (%d)\n", 12522ee97cafSCornelia Huck __FUNCTION__, error); 1253a2de48caSGreg Kroah-Hartman } 12542ee97cafSCornelia Huck } 125560b8cabdSKay Sievers #endif 125660b8cabdSKay Sievers 12572ee97cafSCornelia Huck out: 1258a2de48caSGreg Kroah-Hartman put_device(dev); 1259a2de48caSGreg Kroah-Hartman 1260a2de48caSGreg Kroah-Hartman kfree(new_class_name); 1261952ab431SJesper Juhl kfree(old_class_name); 12622ee97cafSCornelia Huck kfree(old_device_name); 1263a2de48caSGreg Kroah-Hartman 1264a2de48caSGreg Kroah-Hartman return error; 1265a2de48caSGreg Kroah-Hartman } 1266a2807dbcSJohannes Berg EXPORT_SYMBOL_GPL(device_rename); 12678a82472fSCornelia Huck 12688a82472fSCornelia Huck static int device_move_class_links(struct device *dev, 12698a82472fSCornelia Huck struct device *old_parent, 12708a82472fSCornelia Huck struct device *new_parent) 12718a82472fSCornelia Huck { 1272f7f3461dSGreg Kroah-Hartman int error = 0; 12738a82472fSCornelia Huck #ifdef CONFIG_SYSFS_DEPRECATED 12748a82472fSCornelia Huck char *class_name; 12758a82472fSCornelia Huck 12768a82472fSCornelia Huck class_name = make_class_name(dev->class->name, &dev->kobj); 12778a82472fSCornelia Huck if (!class_name) { 1278cb360bbfSCornelia Huck error = -ENOMEM; 12798a82472fSCornelia Huck goto out; 12808a82472fSCornelia Huck } 12818a82472fSCornelia Huck if (old_parent) { 12828a82472fSCornelia Huck sysfs_remove_link(&dev->kobj, "device"); 12838a82472fSCornelia Huck sysfs_remove_link(&old_parent->kobj, class_name); 12848a82472fSCornelia Huck } 1285c744aeaeSCornelia Huck if (new_parent) { 1286c744aeaeSCornelia Huck error = sysfs_create_link(&dev->kobj, &new_parent->kobj, 1287c744aeaeSCornelia Huck "device"); 12888a82472fSCornelia Huck if (error) 12898a82472fSCornelia Huck goto out; 1290c744aeaeSCornelia Huck error = sysfs_create_link(&new_parent->kobj, &dev->kobj, 1291c744aeaeSCornelia Huck class_name); 12928a82472fSCornelia Huck if (error) 12938a82472fSCornelia Huck sysfs_remove_link(&dev->kobj, "device"); 12944a3ad20cSGreg Kroah-Hartman } else 1295c744aeaeSCornelia Huck error = 0; 12968a82472fSCornelia Huck out: 12978a82472fSCornelia Huck kfree(class_name); 12988a82472fSCornelia Huck return error; 12998a82472fSCornelia Huck #else 1300f7f3461dSGreg Kroah-Hartman if (old_parent) 1301f7f3461dSGreg Kroah-Hartman sysfs_remove_link(&dev->kobj, "device"); 1302f7f3461dSGreg Kroah-Hartman if (new_parent) 1303f7f3461dSGreg Kroah-Hartman error = sysfs_create_link(&dev->kobj, &new_parent->kobj, 1304f7f3461dSGreg Kroah-Hartman "device"); 1305f7f3461dSGreg Kroah-Hartman return error; 13068a82472fSCornelia Huck #endif 13078a82472fSCornelia Huck } 13088a82472fSCornelia Huck 13098a82472fSCornelia Huck /** 13108a82472fSCornelia Huck * device_move - moves a device to a new parent 13118a82472fSCornelia Huck * @dev: the pointer to the struct device to be moved 1312c744aeaeSCornelia Huck * @new_parent: the new parent of the device (can by NULL) 13138a82472fSCornelia Huck */ 13148a82472fSCornelia Huck int device_move(struct device *dev, struct device *new_parent) 13158a82472fSCornelia Huck { 13168a82472fSCornelia Huck int error; 13178a82472fSCornelia Huck struct device *old_parent; 1318c744aeaeSCornelia Huck struct kobject *new_parent_kobj; 13198a82472fSCornelia Huck 13208a82472fSCornelia Huck dev = get_device(dev); 13218a82472fSCornelia Huck if (!dev) 13228a82472fSCornelia Huck return -EINVAL; 13238a82472fSCornelia Huck 13248a82472fSCornelia Huck new_parent = get_device(new_parent); 1325c744aeaeSCornelia Huck new_parent_kobj = get_device_parent(dev, new_parent); 132663b6971aSCornelia Huck 13277dc72b28SGreg Kroah-Hartman pr_debug("device: '%s': %s: moving to '%s'\n", dev->bus_id, 13287dc72b28SGreg Kroah-Hartman __FUNCTION__, new_parent ? new_parent->bus_id : "<NULL>"); 1329c744aeaeSCornelia Huck error = kobject_move(&dev->kobj, new_parent_kobj); 13308a82472fSCornelia Huck if (error) { 133163b6971aSCornelia Huck cleanup_glue_dir(dev, new_parent_kobj); 13328a82472fSCornelia Huck put_device(new_parent); 13338a82472fSCornelia Huck goto out; 13348a82472fSCornelia Huck } 13358a82472fSCornelia Huck old_parent = dev->parent; 13368a82472fSCornelia Huck dev->parent = new_parent; 13378a82472fSCornelia Huck if (old_parent) 1338acf02d23SCornelia Huck klist_remove(&dev->knode_parent); 1339c744aeaeSCornelia Huck if (new_parent) 13408a82472fSCornelia Huck klist_add_tail(&dev->knode_parent, &new_parent->klist_children); 13418a82472fSCornelia Huck if (!dev->class) 13428a82472fSCornelia Huck goto out_put; 13438a82472fSCornelia Huck error = device_move_class_links(dev, old_parent, new_parent); 13448a82472fSCornelia Huck if (error) { 13458a82472fSCornelia Huck /* We ignore errors on cleanup since we're hosed anyway... */ 13468a82472fSCornelia Huck device_move_class_links(dev, new_parent, old_parent); 13478a82472fSCornelia Huck if (!kobject_move(&dev->kobj, &old_parent->kobj)) { 1348c744aeaeSCornelia Huck if (new_parent) 1349acf02d23SCornelia Huck klist_remove(&dev->knode_parent); 13508a82472fSCornelia Huck if (old_parent) 13518a82472fSCornelia Huck klist_add_tail(&dev->knode_parent, 13528a82472fSCornelia Huck &old_parent->klist_children); 13538a82472fSCornelia Huck } 135463b6971aSCornelia Huck cleanup_glue_dir(dev, new_parent_kobj); 13558a82472fSCornelia Huck put_device(new_parent); 13568a82472fSCornelia Huck goto out; 13578a82472fSCornelia Huck } 13588a82472fSCornelia Huck out_put: 13598a82472fSCornelia Huck put_device(old_parent); 13608a82472fSCornelia Huck out: 13618a82472fSCornelia Huck put_device(dev); 13628a82472fSCornelia Huck return error; 13638a82472fSCornelia Huck } 13648a82472fSCornelia Huck EXPORT_SYMBOL_GPL(device_move); 136537b0c020SGreg Kroah-Hartman 136637b0c020SGreg Kroah-Hartman /** 136737b0c020SGreg Kroah-Hartman * device_shutdown - call ->shutdown() on each device to shutdown. 136837b0c020SGreg Kroah-Hartman */ 136937b0c020SGreg Kroah-Hartman void device_shutdown(void) 137037b0c020SGreg Kroah-Hartman { 137137b0c020SGreg Kroah-Hartman struct device *dev, *devn; 137237b0c020SGreg Kroah-Hartman 137337b0c020SGreg Kroah-Hartman list_for_each_entry_safe_reverse(dev, devn, &devices_kset->list, 137437b0c020SGreg Kroah-Hartman kobj.entry) { 137537b0c020SGreg Kroah-Hartman if (dev->bus && dev->bus->shutdown) { 137637b0c020SGreg Kroah-Hartman dev_dbg(dev, "shutdown\n"); 137737b0c020SGreg Kroah-Hartman dev->bus->shutdown(dev); 137837b0c020SGreg Kroah-Hartman } else if (dev->driver && dev->driver->shutdown) { 137937b0c020SGreg Kroah-Hartman dev_dbg(dev, "shutdown\n"); 138037b0c020SGreg Kroah-Hartman dev->driver->shutdown(dev); 138137b0c020SGreg Kroah-Hartman } 138237b0c020SGreg Kroah-Hartman } 138337b0c020SGreg Kroah-Hartman } 1384