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; 30e105b8bfSDan Williams static struct kobject *dev_kobj; 31e105b8bfSDan Williams struct kobject *sysfs_dev_char_kobj; 32e105b8bfSDan Williams struct kobject *sysfs_dev_block_kobj; 331da177e4SLinus Torvalds 344e886c29SGreg Kroah-Hartman #ifdef CONFIG_BLOCK 354e886c29SGreg Kroah-Hartman static inline int device_is_not_partition(struct device *dev) 364e886c29SGreg Kroah-Hartman { 374e886c29SGreg Kroah-Hartman return !(dev->type == &part_type); 384e886c29SGreg Kroah-Hartman } 394e886c29SGreg Kroah-Hartman #else 404e886c29SGreg Kroah-Hartman static inline int device_is_not_partition(struct device *dev) 414e886c29SGreg Kroah-Hartman { 424e886c29SGreg Kroah-Hartman return 1; 434e886c29SGreg Kroah-Hartman } 444e886c29SGreg Kroah-Hartman #endif 451da177e4SLinus Torvalds 463e95637aSAlan Stern /** 473e95637aSAlan Stern * dev_driver_string - Return a device's driver name, if at all possible 483e95637aSAlan Stern * @dev: struct device to get the name of 493e95637aSAlan Stern * 503e95637aSAlan Stern * Will return the device's driver's name if it is bound to a device. If 513e95637aSAlan Stern * the device is not bound to a device, it will return the name of the bus 523e95637aSAlan Stern * it is attached to. If it is not attached to a bus either, an empty 533e95637aSAlan Stern * string will be returned. 543e95637aSAlan Stern */ 553e95637aSAlan Stern const char *dev_driver_string(struct device *dev) 563e95637aSAlan Stern { 573e95637aSAlan Stern return dev->driver ? dev->driver->name : 58a456b702SJean Delvare (dev->bus ? dev->bus->name : 59a456b702SJean Delvare (dev->class ? dev->class->name : "")); 603e95637aSAlan Stern } 61310a922dSMatthew Wilcox EXPORT_SYMBOL(dev_driver_string); 623e95637aSAlan Stern 631da177e4SLinus Torvalds #define to_dev(obj) container_of(obj, struct device, kobj) 641da177e4SLinus Torvalds #define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr) 651da177e4SLinus Torvalds 664a3ad20cSGreg Kroah-Hartman static ssize_t dev_attr_show(struct kobject *kobj, struct attribute *attr, 674a3ad20cSGreg Kroah-Hartman char *buf) 681da177e4SLinus Torvalds { 691da177e4SLinus Torvalds struct device_attribute *dev_attr = to_dev_attr(attr); 701da177e4SLinus Torvalds struct device *dev = to_dev(kobj); 714a0c20bfSDmitry Torokhov ssize_t ret = -EIO; 721da177e4SLinus Torvalds 731da177e4SLinus Torvalds if (dev_attr->show) 7454b6f35cSYani Ioannou ret = dev_attr->show(dev, dev_attr, buf); 75815d2d50SAndrew Morton if (ret >= (ssize_t)PAGE_SIZE) { 76815d2d50SAndrew Morton print_symbol("dev_attr_show: %s returned bad count\n", 77815d2d50SAndrew Morton (unsigned long)dev_attr->show); 78815d2d50SAndrew Morton } 791da177e4SLinus Torvalds return ret; 801da177e4SLinus Torvalds } 811da177e4SLinus Torvalds 824a3ad20cSGreg Kroah-Hartman static ssize_t dev_attr_store(struct kobject *kobj, struct attribute *attr, 831da177e4SLinus Torvalds const char *buf, size_t count) 841da177e4SLinus Torvalds { 851da177e4SLinus Torvalds struct device_attribute *dev_attr = to_dev_attr(attr); 861da177e4SLinus Torvalds struct device *dev = to_dev(kobj); 874a0c20bfSDmitry Torokhov ssize_t ret = -EIO; 881da177e4SLinus Torvalds 891da177e4SLinus Torvalds if (dev_attr->store) 9054b6f35cSYani Ioannou ret = dev_attr->store(dev, dev_attr, buf, count); 911da177e4SLinus Torvalds return ret; 921da177e4SLinus Torvalds } 931da177e4SLinus Torvalds 941da177e4SLinus Torvalds static struct sysfs_ops dev_sysfs_ops = { 951da177e4SLinus Torvalds .show = dev_attr_show, 961da177e4SLinus Torvalds .store = dev_attr_store, 971da177e4SLinus Torvalds }; 981da177e4SLinus Torvalds 991da177e4SLinus Torvalds 1001da177e4SLinus Torvalds /** 1011da177e4SLinus Torvalds * device_release - free device structure. 1021da177e4SLinus Torvalds * @kobj: device's kobject. 1031da177e4SLinus Torvalds * 1041da177e4SLinus Torvalds * This is called once the reference count for the object 1051da177e4SLinus Torvalds * reaches 0. We forward the call to the device's release 1061da177e4SLinus Torvalds * method, which should handle actually freeing the structure. 1071da177e4SLinus Torvalds */ 1081da177e4SLinus Torvalds static void device_release(struct kobject *kobj) 1091da177e4SLinus Torvalds { 1101da177e4SLinus Torvalds struct device *dev = to_dev(kobj); 1111da177e4SLinus Torvalds 1121da177e4SLinus Torvalds if (dev->release) 1131da177e4SLinus Torvalds dev->release(dev); 114f9f852dfSKay Sievers else if (dev->type && dev->type->release) 115f9f852dfSKay Sievers dev->type->release(dev); 1162620efefSGreg Kroah-Hartman else if (dev->class && dev->class->dev_release) 1172620efefSGreg Kroah-Hartman dev->class->dev_release(dev); 1181da177e4SLinus Torvalds else { 1194a3ad20cSGreg Kroah-Hartman printk(KERN_ERR "Device '%s' does not have a release() " 1204a3ad20cSGreg Kroah-Hartman "function, it is broken and must be fixed.\n", 1211da177e4SLinus Torvalds dev->bus_id); 1221da177e4SLinus Torvalds WARN_ON(1); 1231da177e4SLinus Torvalds } 1241da177e4SLinus Torvalds } 1251da177e4SLinus Torvalds 1268f4afc41SGreg Kroah-Hartman static struct kobj_type device_ktype = { 1271da177e4SLinus Torvalds .release = device_release, 1281da177e4SLinus Torvalds .sysfs_ops = &dev_sysfs_ops, 1291da177e4SLinus Torvalds }; 1301da177e4SLinus Torvalds 1311da177e4SLinus Torvalds 132312c004dSKay Sievers static int dev_uevent_filter(struct kset *kset, struct kobject *kobj) 1331da177e4SLinus Torvalds { 1341da177e4SLinus Torvalds struct kobj_type *ktype = get_ktype(kobj); 1351da177e4SLinus Torvalds 1368f4afc41SGreg Kroah-Hartman if (ktype == &device_ktype) { 1371da177e4SLinus Torvalds struct device *dev = to_dev(kobj); 13883b5fb4cSCornelia Huck if (dev->uevent_suppress) 13983b5fb4cSCornelia Huck return 0; 1401da177e4SLinus Torvalds if (dev->bus) 1411da177e4SLinus Torvalds return 1; 14223681e47SGreg Kroah-Hartman if (dev->class) 14323681e47SGreg Kroah-Hartman return 1; 1441da177e4SLinus Torvalds } 1451da177e4SLinus Torvalds return 0; 1461da177e4SLinus Torvalds } 1471da177e4SLinus Torvalds 148312c004dSKay Sievers static const char *dev_uevent_name(struct kset *kset, struct kobject *kobj) 1491da177e4SLinus Torvalds { 1501da177e4SLinus Torvalds struct device *dev = to_dev(kobj); 1511da177e4SLinus Torvalds 15223681e47SGreg Kroah-Hartman if (dev->bus) 1531da177e4SLinus Torvalds return dev->bus->name; 15423681e47SGreg Kroah-Hartman if (dev->class) 15523681e47SGreg Kroah-Hartman return dev->class->name; 15623681e47SGreg Kroah-Hartman return NULL; 1571da177e4SLinus Torvalds } 1581da177e4SLinus Torvalds 1597eff2e7aSKay Sievers static int dev_uevent(struct kset *kset, struct kobject *kobj, 1607eff2e7aSKay Sievers struct kobj_uevent_env *env) 1611da177e4SLinus Torvalds { 1621da177e4SLinus Torvalds struct device *dev = to_dev(kobj); 1631da177e4SLinus Torvalds int retval = 0; 1641da177e4SLinus Torvalds 16523681e47SGreg Kroah-Hartman /* add the major/minor if present */ 16623681e47SGreg Kroah-Hartman if (MAJOR(dev->devt)) { 1677eff2e7aSKay Sievers add_uevent_var(env, "MAJOR=%u", MAJOR(dev->devt)); 1687eff2e7aSKay Sievers add_uevent_var(env, "MINOR=%u", MINOR(dev->devt)); 16923681e47SGreg Kroah-Hartman } 17023681e47SGreg Kroah-Hartman 171414264f9SKay Sievers if (dev->type && dev->type->name) 1727eff2e7aSKay Sievers add_uevent_var(env, "DEVTYPE=%s", dev->type->name); 173414264f9SKay Sievers 174239378f1SKay Sievers if (dev->driver) 1757eff2e7aSKay Sievers add_uevent_var(env, "DRIVER=%s", dev->driver->name); 176239378f1SKay Sievers 177a87cb2acSKay Sievers #ifdef CONFIG_SYSFS_DEPRECATED 178239378f1SKay Sievers if (dev->class) { 179239378f1SKay Sievers struct device *parent = dev->parent; 180239378f1SKay Sievers 181239378f1SKay Sievers /* find first bus device in parent chain */ 182239378f1SKay Sievers while (parent && !parent->bus) 183239378f1SKay Sievers parent = parent->parent; 184239378f1SKay Sievers if (parent && parent->bus) { 185239378f1SKay Sievers const char *path; 186239378f1SKay Sievers 187239378f1SKay Sievers path = kobject_get_path(&parent->kobj, GFP_KERNEL); 1882c7afd12SKay Sievers if (path) { 1897eff2e7aSKay Sievers add_uevent_var(env, "PHYSDEVPATH=%s", path); 190239378f1SKay Sievers kfree(path); 1912c7afd12SKay Sievers } 192239378f1SKay Sievers 1937eff2e7aSKay Sievers add_uevent_var(env, "PHYSDEVBUS=%s", parent->bus->name); 194239378f1SKay Sievers 195239378f1SKay Sievers if (parent->driver) 1967eff2e7aSKay Sievers add_uevent_var(env, "PHYSDEVDRIVER=%s", 1977eff2e7aSKay Sievers parent->driver->name); 198239378f1SKay Sievers } 199239378f1SKay Sievers } else if (dev->bus) { 2007eff2e7aSKay Sievers add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name); 201239378f1SKay Sievers 202239378f1SKay Sievers if (dev->driver) 2034a3ad20cSGreg Kroah-Hartman add_uevent_var(env, "PHYSDEVDRIVER=%s", 2044a3ad20cSGreg Kroah-Hartman dev->driver->name); 205d81d9d6bSKay Sievers } 206239378f1SKay Sievers #endif 2071da177e4SLinus Torvalds 2081da177e4SLinus Torvalds /* have the bus specific function add its stuff */ 2097eff2e7aSKay Sievers if (dev->bus && dev->bus->uevent) { 2107eff2e7aSKay Sievers retval = dev->bus->uevent(dev, env); 211f9f852dfSKay Sievers if (retval) 2127dc72b28SGreg Kroah-Hartman pr_debug("device: '%s': %s: bus uevent() returned %d\n", 2132b3a302aSHarvey Harrison dev->bus_id, __func__, retval); 2141da177e4SLinus Torvalds } 2151da177e4SLinus Torvalds 2162620efefSGreg Kroah-Hartman /* have the class specific function add its stuff */ 2177eff2e7aSKay Sievers if (dev->class && dev->class->dev_uevent) { 2187eff2e7aSKay Sievers retval = dev->class->dev_uevent(dev, env); 219f9f852dfSKay Sievers if (retval) 2207dc72b28SGreg Kroah-Hartman pr_debug("device: '%s': %s: class uevent() " 2217dc72b28SGreg Kroah-Hartman "returned %d\n", dev->bus_id, 2222b3a302aSHarvey Harrison __func__, retval); 2232620efefSGreg Kroah-Hartman } 224f9f852dfSKay Sievers 225f9f852dfSKay Sievers /* have the device type specific fuction add its stuff */ 2267eff2e7aSKay Sievers if (dev->type && dev->type->uevent) { 2277eff2e7aSKay Sievers retval = dev->type->uevent(dev, env); 228f9f852dfSKay Sievers if (retval) 2297dc72b28SGreg Kroah-Hartman pr_debug("device: '%s': %s: dev_type uevent() " 2307dc72b28SGreg Kroah-Hartman "returned %d\n", dev->bus_id, 2312b3a302aSHarvey Harrison __func__, retval); 2322620efefSGreg Kroah-Hartman } 2332620efefSGreg Kroah-Hartman 2341da177e4SLinus Torvalds return retval; 2351da177e4SLinus Torvalds } 2361da177e4SLinus Torvalds 237312c004dSKay Sievers static struct kset_uevent_ops device_uevent_ops = { 238312c004dSKay Sievers .filter = dev_uevent_filter, 239312c004dSKay Sievers .name = dev_uevent_name, 240312c004dSKay Sievers .uevent = dev_uevent, 2411da177e4SLinus Torvalds }; 2421da177e4SLinus Torvalds 24316574dccSKay Sievers static ssize_t show_uevent(struct device *dev, struct device_attribute *attr, 24416574dccSKay Sievers char *buf) 24516574dccSKay Sievers { 24616574dccSKay Sievers struct kobject *top_kobj; 24716574dccSKay Sievers struct kset *kset; 2487eff2e7aSKay Sievers struct kobj_uevent_env *env = NULL; 24916574dccSKay Sievers int i; 25016574dccSKay Sievers size_t count = 0; 25116574dccSKay Sievers int retval; 25216574dccSKay Sievers 25316574dccSKay Sievers /* search the kset, the device belongs to */ 25416574dccSKay Sievers top_kobj = &dev->kobj; 2555c5daf65SKay Sievers while (!top_kobj->kset && top_kobj->parent) 25616574dccSKay Sievers top_kobj = top_kobj->parent; 25716574dccSKay Sievers if (!top_kobj->kset) 25816574dccSKay Sievers goto out; 2595c5daf65SKay Sievers 26016574dccSKay Sievers kset = top_kobj->kset; 26116574dccSKay Sievers if (!kset->uevent_ops || !kset->uevent_ops->uevent) 26216574dccSKay Sievers goto out; 26316574dccSKay Sievers 26416574dccSKay Sievers /* respect filter */ 26516574dccSKay Sievers if (kset->uevent_ops && kset->uevent_ops->filter) 26616574dccSKay Sievers if (!kset->uevent_ops->filter(kset, &dev->kobj)) 26716574dccSKay Sievers goto out; 26816574dccSKay Sievers 2697eff2e7aSKay Sievers env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL); 2707eff2e7aSKay Sievers if (!env) 271c7308c81SGreg Kroah-Hartman return -ENOMEM; 272c7308c81SGreg Kroah-Hartman 27316574dccSKay Sievers /* let the kset specific function add its keys */ 2747eff2e7aSKay Sievers retval = kset->uevent_ops->uevent(kset, &dev->kobj, env); 27516574dccSKay Sievers if (retval) 27616574dccSKay Sievers goto out; 27716574dccSKay Sievers 27816574dccSKay Sievers /* copy keys to file */ 2797eff2e7aSKay Sievers for (i = 0; i < env->envp_idx; i++) 2807eff2e7aSKay Sievers count += sprintf(&buf[count], "%s\n", env->envp[i]); 28116574dccSKay Sievers out: 2827eff2e7aSKay Sievers kfree(env); 28316574dccSKay Sievers return count; 28416574dccSKay Sievers } 28516574dccSKay Sievers 286a7fd6706SKay Sievers static ssize_t store_uevent(struct device *dev, struct device_attribute *attr, 287a7fd6706SKay Sievers const char *buf, size_t count) 288a7fd6706SKay Sievers { 28960a96a59SKay Sievers enum kobject_action action; 29060a96a59SKay Sievers 2915c5daf65SKay Sievers if (kobject_action_type(buf, count, &action) == 0) { 29260a96a59SKay Sievers kobject_uevent(&dev->kobj, action); 29360a96a59SKay Sievers goto out; 29460a96a59SKay Sievers } 29560a96a59SKay Sievers 29622af74f3SKay Sievers dev_err(dev, "uevent: unsupported action-string; this will " 29760a96a59SKay Sievers "be ignored in a future kernel version\n"); 298312c004dSKay Sievers kobject_uevent(&dev->kobj, KOBJ_ADD); 29960a96a59SKay Sievers out: 300a7fd6706SKay Sievers return count; 301a7fd6706SKay Sievers } 302a7fd6706SKay Sievers 303ad6a1e1cSTejun Heo static struct device_attribute uevent_attr = 304ad6a1e1cSTejun Heo __ATTR(uevent, S_IRUGO | S_IWUSR, show_uevent, store_uevent); 305ad6a1e1cSTejun Heo 306621a1672SDmitry Torokhov static int device_add_attributes(struct device *dev, 307621a1672SDmitry Torokhov struct device_attribute *attrs) 308de0ff00dSGreg Kroah-Hartman { 309de0ff00dSGreg Kroah-Hartman int error = 0; 310621a1672SDmitry Torokhov int i; 311de0ff00dSGreg Kroah-Hartman 312621a1672SDmitry Torokhov if (attrs) { 313621a1672SDmitry Torokhov for (i = 0; attr_name(attrs[i]); i++) { 314621a1672SDmitry Torokhov error = device_create_file(dev, &attrs[i]); 315621a1672SDmitry Torokhov if (error) 316621a1672SDmitry Torokhov break; 317621a1672SDmitry Torokhov } 318621a1672SDmitry Torokhov if (error) 319de0ff00dSGreg Kroah-Hartman while (--i >= 0) 320621a1672SDmitry Torokhov device_remove_file(dev, &attrs[i]); 321de0ff00dSGreg Kroah-Hartman } 322de0ff00dSGreg Kroah-Hartman return error; 323de0ff00dSGreg Kroah-Hartman } 324de0ff00dSGreg Kroah-Hartman 325621a1672SDmitry Torokhov static void device_remove_attributes(struct device *dev, 326621a1672SDmitry Torokhov struct device_attribute *attrs) 327de0ff00dSGreg Kroah-Hartman { 328de0ff00dSGreg Kroah-Hartman int i; 329621a1672SDmitry Torokhov 330621a1672SDmitry Torokhov if (attrs) 331621a1672SDmitry Torokhov for (i = 0; attr_name(attrs[i]); i++) 332621a1672SDmitry Torokhov device_remove_file(dev, &attrs[i]); 333621a1672SDmitry Torokhov } 334621a1672SDmitry Torokhov 335621a1672SDmitry Torokhov static int device_add_groups(struct device *dev, 336621a1672SDmitry Torokhov struct attribute_group **groups) 337621a1672SDmitry Torokhov { 338621a1672SDmitry Torokhov int error = 0; 339621a1672SDmitry Torokhov int i; 340621a1672SDmitry Torokhov 341621a1672SDmitry Torokhov if (groups) { 342621a1672SDmitry Torokhov for (i = 0; groups[i]; i++) { 343621a1672SDmitry Torokhov error = sysfs_create_group(&dev->kobj, groups[i]); 344621a1672SDmitry Torokhov if (error) { 345621a1672SDmitry Torokhov while (--i >= 0) 3464a3ad20cSGreg Kroah-Hartman sysfs_remove_group(&dev->kobj, 3474a3ad20cSGreg Kroah-Hartman groups[i]); 348621a1672SDmitry Torokhov break; 349de0ff00dSGreg Kroah-Hartman } 350de0ff00dSGreg Kroah-Hartman } 351de0ff00dSGreg Kroah-Hartman } 352621a1672SDmitry Torokhov return error; 353621a1672SDmitry Torokhov } 354621a1672SDmitry Torokhov 355621a1672SDmitry Torokhov static void device_remove_groups(struct device *dev, 356621a1672SDmitry Torokhov struct attribute_group **groups) 357621a1672SDmitry Torokhov { 358621a1672SDmitry Torokhov int i; 359621a1672SDmitry Torokhov 360621a1672SDmitry Torokhov if (groups) 361621a1672SDmitry Torokhov for (i = 0; groups[i]; i++) 362621a1672SDmitry Torokhov sysfs_remove_group(&dev->kobj, groups[i]); 363621a1672SDmitry Torokhov } 364de0ff00dSGreg Kroah-Hartman 3652620efefSGreg Kroah-Hartman static int device_add_attrs(struct device *dev) 3662620efefSGreg Kroah-Hartman { 3672620efefSGreg Kroah-Hartman struct class *class = dev->class; 368f9f852dfSKay Sievers struct device_type *type = dev->type; 369621a1672SDmitry Torokhov int error; 3702620efefSGreg Kroah-Hartman 371621a1672SDmitry Torokhov if (class) { 372621a1672SDmitry Torokhov error = device_add_attributes(dev, class->dev_attrs); 3732620efefSGreg Kroah-Hartman if (error) 374621a1672SDmitry Torokhov return error; 375f9f852dfSKay Sievers } 376f9f852dfSKay Sievers 377621a1672SDmitry Torokhov if (type) { 378621a1672SDmitry Torokhov error = device_add_groups(dev, type->groups); 379f9f852dfSKay Sievers if (error) 380621a1672SDmitry Torokhov goto err_remove_class_attrs; 381f9f852dfSKay Sievers } 382621a1672SDmitry Torokhov 383621a1672SDmitry Torokhov error = device_add_groups(dev, dev->groups); 384f9f852dfSKay Sievers if (error) 385621a1672SDmitry Torokhov goto err_remove_type_groups; 386621a1672SDmitry Torokhov 387621a1672SDmitry Torokhov return 0; 388621a1672SDmitry Torokhov 389621a1672SDmitry Torokhov err_remove_type_groups: 390621a1672SDmitry Torokhov if (type) 391621a1672SDmitry Torokhov device_remove_groups(dev, type->groups); 392621a1672SDmitry Torokhov err_remove_class_attrs: 393621a1672SDmitry Torokhov if (class) 394621a1672SDmitry Torokhov device_remove_attributes(dev, class->dev_attrs); 395f9f852dfSKay Sievers 3962620efefSGreg Kroah-Hartman return error; 3972620efefSGreg Kroah-Hartman } 3982620efefSGreg Kroah-Hartman 3992620efefSGreg Kroah-Hartman static void device_remove_attrs(struct device *dev) 4002620efefSGreg Kroah-Hartman { 4012620efefSGreg Kroah-Hartman struct class *class = dev->class; 402f9f852dfSKay Sievers struct device_type *type = dev->type; 4032620efefSGreg Kroah-Hartman 404621a1672SDmitry Torokhov device_remove_groups(dev, dev->groups); 405f9f852dfSKay Sievers 406621a1672SDmitry Torokhov if (type) 407621a1672SDmitry Torokhov device_remove_groups(dev, type->groups); 408621a1672SDmitry Torokhov 409621a1672SDmitry Torokhov if (class) 410621a1672SDmitry Torokhov device_remove_attributes(dev, class->dev_attrs); 4112620efefSGreg Kroah-Hartman } 4122620efefSGreg Kroah-Hartman 4132620efefSGreg Kroah-Hartman 41423681e47SGreg Kroah-Hartman static ssize_t show_dev(struct device *dev, struct device_attribute *attr, 41523681e47SGreg Kroah-Hartman char *buf) 41623681e47SGreg Kroah-Hartman { 41723681e47SGreg Kroah-Hartman return print_dev_t(buf, dev->devt); 41823681e47SGreg Kroah-Hartman } 41923681e47SGreg Kroah-Hartman 420ad6a1e1cSTejun Heo static struct device_attribute devt_attr = 421ad6a1e1cSTejun Heo __ATTR(dev, S_IRUGO, show_dev, NULL); 422ad6a1e1cSTejun Heo 423881c6cfdSGreg Kroah-Hartman /* kset to create /sys/devices/ */ 424881c6cfdSGreg Kroah-Hartman struct kset *devices_kset; 4251da177e4SLinus Torvalds 4261da177e4SLinus Torvalds /** 4271da177e4SLinus Torvalds * device_create_file - create sysfs attribute file for device. 4281da177e4SLinus Torvalds * @dev: device. 4291da177e4SLinus Torvalds * @attr: device attribute descriptor. 4301da177e4SLinus Torvalds */ 4311da177e4SLinus Torvalds int device_create_file(struct device *dev, struct device_attribute *attr) 4321da177e4SLinus Torvalds { 4331da177e4SLinus Torvalds int error = 0; 4340c98b19fSCornelia Huck if (dev) 4351da177e4SLinus Torvalds error = sysfs_create_file(&dev->kobj, &attr->attr); 4361da177e4SLinus Torvalds return error; 4371da177e4SLinus Torvalds } 4381da177e4SLinus Torvalds 4391da177e4SLinus Torvalds /** 4401da177e4SLinus Torvalds * device_remove_file - remove sysfs attribute file. 4411da177e4SLinus Torvalds * @dev: device. 4421da177e4SLinus Torvalds * @attr: device attribute descriptor. 4431da177e4SLinus Torvalds */ 4441da177e4SLinus Torvalds void device_remove_file(struct device *dev, struct device_attribute *attr) 4451da177e4SLinus Torvalds { 4460c98b19fSCornelia Huck if (dev) 4471da177e4SLinus Torvalds sysfs_remove_file(&dev->kobj, &attr->attr); 4481da177e4SLinus Torvalds } 4491da177e4SLinus Torvalds 4502589f188SGreg Kroah-Hartman /** 4512589f188SGreg Kroah-Hartman * device_create_bin_file - create sysfs binary attribute file for device. 4522589f188SGreg Kroah-Hartman * @dev: device. 4532589f188SGreg Kroah-Hartman * @attr: device binary attribute descriptor. 4542589f188SGreg Kroah-Hartman */ 4552589f188SGreg Kroah-Hartman int device_create_bin_file(struct device *dev, struct bin_attribute *attr) 4562589f188SGreg Kroah-Hartman { 4572589f188SGreg Kroah-Hartman int error = -EINVAL; 4582589f188SGreg Kroah-Hartman if (dev) 4592589f188SGreg Kroah-Hartman error = sysfs_create_bin_file(&dev->kobj, attr); 4602589f188SGreg Kroah-Hartman return error; 4612589f188SGreg Kroah-Hartman } 4622589f188SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(device_create_bin_file); 4632589f188SGreg Kroah-Hartman 4642589f188SGreg Kroah-Hartman /** 4652589f188SGreg Kroah-Hartman * device_remove_bin_file - remove sysfs binary attribute file 4662589f188SGreg Kroah-Hartman * @dev: device. 4672589f188SGreg Kroah-Hartman * @attr: device binary attribute descriptor. 4682589f188SGreg Kroah-Hartman */ 4692589f188SGreg Kroah-Hartman void device_remove_bin_file(struct device *dev, struct bin_attribute *attr) 4702589f188SGreg Kroah-Hartman { 4712589f188SGreg Kroah-Hartman if (dev) 4722589f188SGreg Kroah-Hartman sysfs_remove_bin_file(&dev->kobj, attr); 4732589f188SGreg Kroah-Hartman } 4742589f188SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(device_remove_bin_file); 4752589f188SGreg Kroah-Hartman 476d9a9cdfbSAlan Stern /** 477523ded71SAlan Stern * device_schedule_callback_owner - helper to schedule a callback for a device 478d9a9cdfbSAlan Stern * @dev: device. 479d9a9cdfbSAlan Stern * @func: callback function to invoke later. 480523ded71SAlan Stern * @owner: module owning the callback routine 481d9a9cdfbSAlan Stern * 482d9a9cdfbSAlan Stern * Attribute methods must not unregister themselves or their parent device 483d9a9cdfbSAlan Stern * (which would amount to the same thing). Attempts to do so will deadlock, 484d9a9cdfbSAlan Stern * since unregistration is mutually exclusive with driver callbacks. 485d9a9cdfbSAlan Stern * 486d9a9cdfbSAlan Stern * Instead methods can call this routine, which will attempt to allocate 487d9a9cdfbSAlan Stern * and schedule a workqueue request to call back @func with @dev as its 488d9a9cdfbSAlan Stern * argument in the workqueue's process context. @dev will be pinned until 489d9a9cdfbSAlan Stern * @func returns. 490d9a9cdfbSAlan Stern * 491523ded71SAlan Stern * This routine is usually called via the inline device_schedule_callback(), 492523ded71SAlan Stern * which automatically sets @owner to THIS_MODULE. 493523ded71SAlan Stern * 494d9a9cdfbSAlan Stern * Returns 0 if the request was submitted, -ENOMEM if storage could not 495523ded71SAlan Stern * be allocated, -ENODEV if a reference to @owner isn't available. 496d9a9cdfbSAlan Stern * 497d9a9cdfbSAlan Stern * NOTE: This routine won't work if CONFIG_SYSFS isn't set! It uses an 498d9a9cdfbSAlan Stern * underlying sysfs routine (since it is intended for use by attribute 499d9a9cdfbSAlan Stern * methods), and if sysfs isn't available you'll get nothing but -ENOSYS. 500d9a9cdfbSAlan Stern */ 501523ded71SAlan Stern int device_schedule_callback_owner(struct device *dev, 502523ded71SAlan Stern void (*func)(struct device *), struct module *owner) 503d9a9cdfbSAlan Stern { 504d9a9cdfbSAlan Stern return sysfs_schedule_callback(&dev->kobj, 505523ded71SAlan Stern (void (*)(void *)) func, dev, owner); 506d9a9cdfbSAlan Stern } 507523ded71SAlan Stern EXPORT_SYMBOL_GPL(device_schedule_callback_owner); 508d9a9cdfbSAlan Stern 50934bb61f9SJames Bottomley static void klist_children_get(struct klist_node *n) 51034bb61f9SJames Bottomley { 51134bb61f9SJames Bottomley struct device *dev = container_of(n, struct device, knode_parent); 51234bb61f9SJames Bottomley 51334bb61f9SJames Bottomley get_device(dev); 51434bb61f9SJames Bottomley } 51534bb61f9SJames Bottomley 51634bb61f9SJames Bottomley static void klist_children_put(struct klist_node *n) 51734bb61f9SJames Bottomley { 51834bb61f9SJames Bottomley struct device *dev = container_of(n, struct device, knode_parent); 51934bb61f9SJames Bottomley 52034bb61f9SJames Bottomley put_device(dev); 52134bb61f9SJames Bottomley } 52234bb61f9SJames Bottomley 5231da177e4SLinus Torvalds /** 5241da177e4SLinus Torvalds * device_initialize - init device structure. 5251da177e4SLinus Torvalds * @dev: device. 5261da177e4SLinus Torvalds * 5271da177e4SLinus Torvalds * This prepares the device for use by other layers, 5281da177e4SLinus Torvalds * including adding it to the device hierarchy. 5291da177e4SLinus Torvalds * It is the first half of device_register(), if called by 5301da177e4SLinus Torvalds * that, though it can also be called separately, so one 5311da177e4SLinus Torvalds * may use @dev's fields (e.g. the refcount). 5321da177e4SLinus Torvalds */ 5331da177e4SLinus Torvalds void device_initialize(struct device *dev) 5341da177e4SLinus Torvalds { 535881c6cfdSGreg Kroah-Hartman dev->kobj.kset = devices_kset; 536f9cb074bSGreg Kroah-Hartman kobject_init(&dev->kobj, &device_ktype); 53734bb61f9SJames Bottomley klist_init(&dev->klist_children, klist_children_get, 53834bb61f9SJames Bottomley klist_children_put); 5391da177e4SLinus Torvalds INIT_LIST_HEAD(&dev->dma_pools); 54023681e47SGreg Kroah-Hartman INIT_LIST_HEAD(&dev->node); 541af70316aSmochel@digitalimplant.org init_MUTEX(&dev->sem); 5429ac7849eSTejun Heo spin_lock_init(&dev->devres_lock); 5439ac7849eSTejun Heo INIT_LIST_HEAD(&dev->devres_head); 5440ac85241SDavid Brownell device_init_wakeup(dev, 0); 54587348136SChristoph Hellwig set_dev_node(dev, -1); 5461da177e4SLinus Torvalds } 5471da177e4SLinus Torvalds 54840fa5422SGreg Kroah-Hartman #ifdef CONFIG_SYSFS_DEPRECATED 549c744aeaeSCornelia Huck static struct kobject *get_device_parent(struct device *dev, 550c744aeaeSCornelia Huck struct device *parent) 55140fa5422SGreg Kroah-Hartman { 552da231fd5SKay Sievers /* class devices without a parent live in /sys/class/<classname>/ */ 5533eb215deSDmitry Torokhov if (dev->class && (!parent || parent->class != dev->class)) 5547c71448bSGreg Kroah-Hartman return &dev->class->p->subsys.kobj; 555da231fd5SKay Sievers /* all other devices keep their parent */ 55640fa5422SGreg Kroah-Hartman else if (parent) 557c744aeaeSCornelia Huck return &parent->kobj; 55840fa5422SGreg Kroah-Hartman 559c744aeaeSCornelia Huck return NULL; 56040fa5422SGreg Kroah-Hartman } 561da231fd5SKay Sievers 562da231fd5SKay Sievers static inline void cleanup_device_parent(struct device *dev) {} 56363b6971aSCornelia Huck static inline void cleanup_glue_dir(struct device *dev, 56463b6971aSCornelia Huck struct kobject *glue_dir) {} 56540fa5422SGreg Kroah-Hartman #else 566c744aeaeSCornelia Huck static struct kobject *virtual_device_parent(struct device *dev) 567f0ee61a6SGreg Kroah-Hartman { 568f0ee61a6SGreg Kroah-Hartman static struct kobject *virtual_dir = NULL; 569f0ee61a6SGreg Kroah-Hartman 570f0ee61a6SGreg Kroah-Hartman if (!virtual_dir) 5714ff6abffSGreg Kroah-Hartman virtual_dir = kobject_create_and_add("virtual", 572881c6cfdSGreg Kroah-Hartman &devices_kset->kobj); 573f0ee61a6SGreg Kroah-Hartman 57486406245SKay Sievers return virtual_dir; 575f0ee61a6SGreg Kroah-Hartman } 576f0ee61a6SGreg Kroah-Hartman 577c744aeaeSCornelia Huck static struct kobject *get_device_parent(struct device *dev, 578c744aeaeSCornelia Huck struct device *parent) 57940fa5422SGreg Kroah-Hartman { 58043968d2fSGreg Kroah-Hartman int retval; 58143968d2fSGreg Kroah-Hartman 58286406245SKay Sievers if (dev->class) { 58386406245SKay Sievers struct kobject *kobj = NULL; 58486406245SKay Sievers struct kobject *parent_kobj; 58586406245SKay Sievers struct kobject *k; 58686406245SKay Sievers 58786406245SKay Sievers /* 58886406245SKay Sievers * If we have no parent, we live in "virtual". 5890f4dafc0SKay Sievers * Class-devices with a non class-device as parent, live 5900f4dafc0SKay Sievers * in a "glue" directory to prevent namespace collisions. 59186406245SKay Sievers */ 59286406245SKay Sievers if (parent == NULL) 59386406245SKay Sievers parent_kobj = virtual_device_parent(dev); 59486406245SKay Sievers else if (parent->class) 59586406245SKay Sievers return &parent->kobj; 59686406245SKay Sievers else 59786406245SKay Sievers parent_kobj = &parent->kobj; 59886406245SKay Sievers 59986406245SKay Sievers /* find our class-directory at the parent and reference it */ 6007c71448bSGreg Kroah-Hartman spin_lock(&dev->class->p->class_dirs.list_lock); 6017c71448bSGreg Kroah-Hartman list_for_each_entry(k, &dev->class->p->class_dirs.list, entry) 60286406245SKay Sievers if (k->parent == parent_kobj) { 60386406245SKay Sievers kobj = kobject_get(k); 60486406245SKay Sievers break; 60586406245SKay Sievers } 6067c71448bSGreg Kroah-Hartman spin_unlock(&dev->class->p->class_dirs.list_lock); 60786406245SKay Sievers if (kobj) 60886406245SKay Sievers return kobj; 60986406245SKay Sievers 61086406245SKay Sievers /* or create a new class-directory at the parent device */ 61143968d2fSGreg Kroah-Hartman k = kobject_create(); 61243968d2fSGreg Kroah-Hartman if (!k) 61343968d2fSGreg Kroah-Hartman return NULL; 6147c71448bSGreg Kroah-Hartman k->kset = &dev->class->p->class_dirs; 615b2d6db58SGreg Kroah-Hartman retval = kobject_add(k, parent_kobj, "%s", dev->class->name); 61643968d2fSGreg Kroah-Hartman if (retval < 0) { 61743968d2fSGreg Kroah-Hartman kobject_put(k); 61843968d2fSGreg Kroah-Hartman return NULL; 61943968d2fSGreg Kroah-Hartman } 6200f4dafc0SKay Sievers /* do not emit an uevent for this simple "glue" directory */ 62143968d2fSGreg Kroah-Hartman return k; 62286406245SKay Sievers } 62386406245SKay Sievers 62486406245SKay Sievers if (parent) 625c744aeaeSCornelia Huck return &parent->kobj; 626c744aeaeSCornelia Huck return NULL; 627c744aeaeSCornelia Huck } 628da231fd5SKay Sievers 62963b6971aSCornelia Huck static void cleanup_glue_dir(struct device *dev, struct kobject *glue_dir) 630da231fd5SKay Sievers { 6310f4dafc0SKay Sievers /* see if we live in a "glue" directory */ 632c1fe539aSCornelia Huck if (!glue_dir || !dev->class || 6337c71448bSGreg Kroah-Hartman glue_dir->kset != &dev->class->p->class_dirs) 634da231fd5SKay Sievers return; 635da231fd5SKay Sievers 6360f4dafc0SKay Sievers kobject_put(glue_dir); 637da231fd5SKay Sievers } 63863b6971aSCornelia Huck 63963b6971aSCornelia Huck static void cleanup_device_parent(struct device *dev) 64063b6971aSCornelia Huck { 64163b6971aSCornelia Huck cleanup_glue_dir(dev, dev->kobj.parent); 64263b6971aSCornelia Huck } 643c744aeaeSCornelia Huck #endif 64486406245SKay Sievers 64563b6971aSCornelia Huck static void setup_parent(struct device *dev, struct device *parent) 646c744aeaeSCornelia Huck { 647c744aeaeSCornelia Huck struct kobject *kobj; 648c744aeaeSCornelia Huck kobj = get_device_parent(dev, parent); 649c744aeaeSCornelia Huck if (kobj) 650c744aeaeSCornelia Huck dev->kobj.parent = kobj; 65140fa5422SGreg Kroah-Hartman } 65240fa5422SGreg Kroah-Hartman 6532ee97cafSCornelia Huck static int device_add_class_symlinks(struct device *dev) 6542ee97cafSCornelia Huck { 6552ee97cafSCornelia Huck int error; 6562ee97cafSCornelia Huck 6572ee97cafSCornelia Huck if (!dev->class) 6582ee97cafSCornelia Huck return 0; 659da231fd5SKay Sievers 6607c71448bSGreg Kroah-Hartman error = sysfs_create_link(&dev->kobj, &dev->class->p->subsys.kobj, 6612ee97cafSCornelia Huck "subsystem"); 6622ee97cafSCornelia Huck if (error) 6632ee97cafSCornelia Huck goto out; 664da231fd5SKay Sievers 665da231fd5SKay Sievers #ifdef CONFIG_SYSFS_DEPRECATED 666da231fd5SKay Sievers /* stacked class devices need a symlink in the class directory */ 6677c71448bSGreg Kroah-Hartman if (dev->kobj.parent != &dev->class->p->subsys.kobj && 6684e886c29SGreg Kroah-Hartman device_is_not_partition(dev)) { 6697c71448bSGreg Kroah-Hartman error = sysfs_create_link(&dev->class->p->subsys.kobj, 6707c71448bSGreg Kroah-Hartman &dev->kobj, dev->bus_id); 6712ee97cafSCornelia Huck if (error) 6722ee97cafSCornelia Huck goto out_subsys; 6732ee97cafSCornelia Huck } 674da231fd5SKay Sievers 6754e886c29SGreg Kroah-Hartman if (dev->parent && device_is_not_partition(dev)) { 6764f01a757SDmitry Torokhov struct device *parent = dev->parent; 6774f01a757SDmitry Torokhov char *class_name; 6784f01a757SDmitry Torokhov 6794f01a757SDmitry Torokhov /* 680da231fd5SKay Sievers * stacked class devices have the 'device' link 681da231fd5SKay Sievers * pointing to the bus device instead of the parent 6824f01a757SDmitry Torokhov */ 6834f01a757SDmitry Torokhov while (parent->class && !parent->bus && parent->parent) 6844f01a757SDmitry Torokhov parent = parent->parent; 6854f01a757SDmitry Torokhov 6864f01a757SDmitry Torokhov error = sysfs_create_link(&dev->kobj, 6874f01a757SDmitry Torokhov &parent->kobj, 6882ee97cafSCornelia Huck "device"); 6892ee97cafSCornelia Huck if (error) 6902ee97cafSCornelia Huck goto out_busid; 6914f01a757SDmitry Torokhov 6924f01a757SDmitry Torokhov class_name = make_class_name(dev->class->name, 6932ee97cafSCornelia Huck &dev->kobj); 6942ee97cafSCornelia Huck if (class_name) 6952ee97cafSCornelia Huck error = sysfs_create_link(&dev->parent->kobj, 6962ee97cafSCornelia Huck &dev->kobj, class_name); 6972ee97cafSCornelia Huck kfree(class_name); 6982ee97cafSCornelia Huck if (error) 6992ee97cafSCornelia Huck goto out_device; 7002ee97cafSCornelia Huck } 701da231fd5SKay Sievers return 0; 702da231fd5SKay Sievers 703da231fd5SKay Sievers out_device: 7044e886c29SGreg Kroah-Hartman if (dev->parent && device_is_not_partition(dev)) 705da231fd5SKay Sievers sysfs_remove_link(&dev->kobj, "device"); 706da231fd5SKay Sievers out_busid: 7077c71448bSGreg Kroah-Hartman if (dev->kobj.parent != &dev->class->p->subsys.kobj && 7084e886c29SGreg Kroah-Hartman device_is_not_partition(dev)) 7097c71448bSGreg Kroah-Hartman sysfs_remove_link(&dev->class->p->subsys.kobj, dev->bus_id); 7104f01a757SDmitry Torokhov #else 711da231fd5SKay Sievers /* link in the class directory pointing to the device */ 7127c71448bSGreg Kroah-Hartman error = sysfs_create_link(&dev->class->p->subsys.kobj, &dev->kobj, 713da231fd5SKay Sievers dev->bus_id); 714da231fd5SKay Sievers if (error) 715da231fd5SKay Sievers goto out_subsys; 716da231fd5SKay Sievers 7174e886c29SGreg Kroah-Hartman if (dev->parent && device_is_not_partition(dev)) { 7184f01a757SDmitry Torokhov error = sysfs_create_link(&dev->kobj, &dev->parent->kobj, 7194f01a757SDmitry Torokhov "device"); 7204f01a757SDmitry Torokhov if (error) 7214f01a757SDmitry Torokhov goto out_busid; 7222ee97cafSCornelia Huck } 7232ee97cafSCornelia Huck return 0; 7242ee97cafSCornelia Huck 7252ee97cafSCornelia Huck out_busid: 7267c71448bSGreg Kroah-Hartman sysfs_remove_link(&dev->class->p->subsys.kobj, dev->bus_id); 727da231fd5SKay Sievers #endif 728da231fd5SKay Sievers 7292ee97cafSCornelia Huck out_subsys: 7302ee97cafSCornelia Huck sysfs_remove_link(&dev->kobj, "subsystem"); 7312ee97cafSCornelia Huck out: 7322ee97cafSCornelia Huck return error; 7332ee97cafSCornelia Huck } 7342ee97cafSCornelia Huck 7352ee97cafSCornelia Huck static void device_remove_class_symlinks(struct device *dev) 7362ee97cafSCornelia Huck { 7372ee97cafSCornelia Huck if (!dev->class) 7382ee97cafSCornelia Huck return; 739da231fd5SKay Sievers 7402ee97cafSCornelia Huck #ifdef CONFIG_SYSFS_DEPRECATED 7414e886c29SGreg Kroah-Hartman if (dev->parent && device_is_not_partition(dev)) { 7422ee97cafSCornelia Huck char *class_name; 7432ee97cafSCornelia Huck 7442ee97cafSCornelia Huck class_name = make_class_name(dev->class->name, &dev->kobj); 7452ee97cafSCornelia Huck if (class_name) { 7462ee97cafSCornelia Huck sysfs_remove_link(&dev->parent->kobj, class_name); 7472ee97cafSCornelia Huck kfree(class_name); 7482ee97cafSCornelia Huck } 7492ee97cafSCornelia Huck sysfs_remove_link(&dev->kobj, "device"); 7502ee97cafSCornelia Huck } 751da231fd5SKay Sievers 7527c71448bSGreg Kroah-Hartman if (dev->kobj.parent != &dev->class->p->subsys.kobj && 7534e886c29SGreg Kroah-Hartman device_is_not_partition(dev)) 7547c71448bSGreg Kroah-Hartman sysfs_remove_link(&dev->class->p->subsys.kobj, dev->bus_id); 755da231fd5SKay Sievers #else 7564e886c29SGreg Kroah-Hartman if (dev->parent && device_is_not_partition(dev)) 757da231fd5SKay Sievers sysfs_remove_link(&dev->kobj, "device"); 758da231fd5SKay Sievers 7597c71448bSGreg Kroah-Hartman sysfs_remove_link(&dev->class->p->subsys.kobj, dev->bus_id); 760da231fd5SKay Sievers #endif 761da231fd5SKay Sievers 7622ee97cafSCornelia Huck sysfs_remove_link(&dev->kobj, "subsystem"); 7632ee97cafSCornelia Huck } 7642ee97cafSCornelia Huck 7651da177e4SLinus Torvalds /** 766413c239fSStephen Rothwell * dev_set_name - set a device name 767413c239fSStephen Rothwell * @dev: device 76846232366SRandy Dunlap * @fmt: format string for the device's name 769413c239fSStephen Rothwell */ 770413c239fSStephen Rothwell int dev_set_name(struct device *dev, const char *fmt, ...) 771413c239fSStephen Rothwell { 772413c239fSStephen Rothwell va_list vargs; 773413c239fSStephen Rothwell 774413c239fSStephen Rothwell va_start(vargs, fmt); 775413c239fSStephen Rothwell vsnprintf(dev->bus_id, sizeof(dev->bus_id), fmt, vargs); 776413c239fSStephen Rothwell va_end(vargs); 777413c239fSStephen Rothwell return 0; 778413c239fSStephen Rothwell } 779413c239fSStephen Rothwell EXPORT_SYMBOL_GPL(dev_set_name); 780413c239fSStephen Rothwell 781413c239fSStephen Rothwell /** 782e105b8bfSDan Williams * device_to_dev_kobj - select a /sys/dev/ directory for the device 783e105b8bfSDan Williams * @dev: device 784e105b8bfSDan Williams * 785e105b8bfSDan Williams * By default we select char/ for new entries. Setting class->dev_obj 786e105b8bfSDan Williams * to NULL prevents an entry from being created. class->dev_kobj must 787e105b8bfSDan Williams * be set (or cleared) before any devices are registered to the class 788e105b8bfSDan Williams * otherwise device_create_sys_dev_entry() and 789e105b8bfSDan Williams * device_remove_sys_dev_entry() will disagree about the the presence 790e105b8bfSDan Williams * of the link. 791e105b8bfSDan Williams */ 792e105b8bfSDan Williams static struct kobject *device_to_dev_kobj(struct device *dev) 793e105b8bfSDan Williams { 794e105b8bfSDan Williams struct kobject *kobj; 795e105b8bfSDan Williams 796e105b8bfSDan Williams if (dev->class) 797e105b8bfSDan Williams kobj = dev->class->dev_kobj; 798e105b8bfSDan Williams else 799e105b8bfSDan Williams kobj = sysfs_dev_char_kobj; 800e105b8bfSDan Williams 801e105b8bfSDan Williams return kobj; 802e105b8bfSDan Williams } 803e105b8bfSDan Williams 804e105b8bfSDan Williams static int device_create_sys_dev_entry(struct device *dev) 805e105b8bfSDan Williams { 806e105b8bfSDan Williams struct kobject *kobj = device_to_dev_kobj(dev); 807e105b8bfSDan Williams int error = 0; 808e105b8bfSDan Williams char devt_str[15]; 809e105b8bfSDan Williams 810e105b8bfSDan Williams if (kobj) { 811e105b8bfSDan Williams format_dev_t(devt_str, dev->devt); 812e105b8bfSDan Williams error = sysfs_create_link(kobj, &dev->kobj, devt_str); 813e105b8bfSDan Williams } 814e105b8bfSDan Williams 815e105b8bfSDan Williams return error; 816e105b8bfSDan Williams } 817e105b8bfSDan Williams 818e105b8bfSDan Williams static void device_remove_sys_dev_entry(struct device *dev) 819e105b8bfSDan Williams { 820e105b8bfSDan Williams struct kobject *kobj = device_to_dev_kobj(dev); 821e105b8bfSDan Williams char devt_str[15]; 822e105b8bfSDan Williams 823e105b8bfSDan Williams if (kobj) { 824e105b8bfSDan Williams format_dev_t(devt_str, dev->devt); 825e105b8bfSDan Williams sysfs_remove_link(kobj, devt_str); 826e105b8bfSDan Williams } 827e105b8bfSDan Williams } 828e105b8bfSDan Williams 829e105b8bfSDan Williams /** 8301da177e4SLinus Torvalds * device_add - add device to device hierarchy. 8311da177e4SLinus Torvalds * @dev: device. 8321da177e4SLinus Torvalds * 8331da177e4SLinus Torvalds * This is part 2 of device_register(), though may be called 8341da177e4SLinus Torvalds * separately _iff_ device_initialize() has been called separately. 8351da177e4SLinus Torvalds * 836b2d6db58SGreg Kroah-Hartman * This adds it to the kobject hierarchy via kobject_add(), adds it 8371da177e4SLinus Torvalds * to the global and sibling lists for the device, then 8381da177e4SLinus Torvalds * adds it to the other relevant subsystems of the driver model. 8391da177e4SLinus Torvalds */ 8401da177e4SLinus Torvalds int device_add(struct device *dev) 8411da177e4SLinus Torvalds { 8421da177e4SLinus Torvalds struct device *parent = NULL; 843c47ed219SGreg Kroah-Hartman struct class_interface *class_intf; 844775b64d2SRafael J. Wysocki int error; 845775b64d2SRafael J. Wysocki 8461da177e4SLinus Torvalds dev = get_device(dev); 847775b64d2SRafael J. Wysocki if (!dev || !strlen(dev->bus_id)) { 848775b64d2SRafael J. Wysocki error = -EINVAL; 849c1fe539aSCornelia Huck goto Done; 850775b64d2SRafael J. Wysocki } 8511da177e4SLinus Torvalds 8522b3a302aSHarvey Harrison pr_debug("device: '%s': %s\n", dev->bus_id, __func__); 853c205ef48SGreg Kroah-Hartman 8541da177e4SLinus Torvalds parent = get_device(dev->parent); 85563b6971aSCornelia Huck setup_parent(dev, parent); 8561da177e4SLinus Torvalds 8570d358f22SYinghai Lu /* use parent numa_node */ 8580d358f22SYinghai Lu if (parent) 8590d358f22SYinghai Lu set_dev_node(dev, dev_to_node(parent)); 8600d358f22SYinghai Lu 8611da177e4SLinus Torvalds /* first, register with generic layer. */ 862b2d6db58SGreg Kroah-Hartman error = kobject_add(&dev->kobj, dev->kobj.parent, "%s", dev->bus_id); 86340fa5422SGreg Kroah-Hartman if (error) 8641da177e4SLinus Torvalds goto Error; 865a7fd6706SKay Sievers 86637022644SBrian Walsh /* notify platform of device entry */ 86737022644SBrian Walsh if (platform_notify) 86837022644SBrian Walsh platform_notify(dev); 86937022644SBrian Walsh 870116af378SBenjamin Herrenschmidt /* notify clients of device entry (new way) */ 871116af378SBenjamin Herrenschmidt if (dev->bus) 872c6f7e72aSGreg Kroah-Hartman blocking_notifier_call_chain(&dev->bus->p->bus_notifier, 873116af378SBenjamin Herrenschmidt BUS_NOTIFY_ADD_DEVICE, dev); 874116af378SBenjamin Herrenschmidt 875ad6a1e1cSTejun Heo error = device_create_file(dev, &uevent_attr); 876a306eea4SCornelia Huck if (error) 877a306eea4SCornelia Huck goto attrError; 878a7fd6706SKay Sievers 87923681e47SGreg Kroah-Hartman if (MAJOR(dev->devt)) { 880ad6a1e1cSTejun Heo error = device_create_file(dev, &devt_attr); 881ad6a1e1cSTejun Heo if (error) 882a306eea4SCornelia Huck goto ueventattrError; 883e105b8bfSDan Williams 884e105b8bfSDan Williams error = device_create_sys_dev_entry(dev); 885e105b8bfSDan Williams if (error) 886e105b8bfSDan Williams goto devtattrError; 88723681e47SGreg Kroah-Hartman } 88823681e47SGreg Kroah-Hartman 8892ee97cafSCornelia Huck error = device_add_class_symlinks(dev); 8902ee97cafSCornelia Huck if (error) 8912ee97cafSCornelia Huck goto SymlinkError; 892dc0afa83SCornelia Huck error = device_add_attrs(dev); 893dc0afa83SCornelia Huck if (error) 8942620efefSGreg Kroah-Hartman goto AttrsError; 895dc0afa83SCornelia Huck error = bus_add_device(dev); 896dc0afa83SCornelia Huck if (error) 8971da177e4SLinus Torvalds goto BusError; 89857eee3d2SRafael J. Wysocki error = device_pm_add(dev); 89957eee3d2SRafael J. Wysocki if (error) 90057eee3d2SRafael J. Wysocki goto PMError; 90153877d06SKay Sievers kobject_uevent(&dev->kobj, KOBJ_ADD); 902c6a46696SCornelia Huck bus_attach_device(dev); 9031da177e4SLinus Torvalds if (parent) 904d856f1e3SJames Bottomley klist_add_tail(&dev->knode_parent, &parent->klist_children); 9051da177e4SLinus Torvalds 9065d9fd169SGreg Kroah-Hartman if (dev->class) { 9077c71448bSGreg Kroah-Hartman down(&dev->class->p->sem); 908c47ed219SGreg Kroah-Hartman /* tie the class to the device */ 90997ae69fdSGreg Kroah-Hartman list_add_tail(&dev->node, &dev->class->p->class_devices); 910c47ed219SGreg Kroah-Hartman 911c47ed219SGreg Kroah-Hartman /* notify any interfaces that the device is here */ 912*184f1f77SGreg Kroah-Hartman list_for_each_entry(class_intf, 913*184f1f77SGreg Kroah-Hartman &dev->class->p->class_interfaces, node) 914c47ed219SGreg Kroah-Hartman if (class_intf->add_dev) 915c47ed219SGreg Kroah-Hartman class_intf->add_dev(dev, class_intf); 9167c71448bSGreg Kroah-Hartman up(&dev->class->p->sem); 9175d9fd169SGreg Kroah-Hartman } 9181da177e4SLinus Torvalds Done: 9191da177e4SLinus Torvalds put_device(dev); 9201da177e4SLinus Torvalds return error; 9211da177e4SLinus Torvalds PMError: 92257eee3d2SRafael J. Wysocki bus_remove_device(dev); 92357eee3d2SRafael J. Wysocki BusError: 924116af378SBenjamin Herrenschmidt if (dev->bus) 925c6f7e72aSGreg Kroah-Hartman blocking_notifier_call_chain(&dev->bus->p->bus_notifier, 926116af378SBenjamin Herrenschmidt BUS_NOTIFY_DEL_DEVICE, dev); 9272620efefSGreg Kroah-Hartman device_remove_attrs(dev); 9282620efefSGreg Kroah-Hartman AttrsError: 9292ee97cafSCornelia Huck device_remove_class_symlinks(dev); 9302ee97cafSCornelia Huck SymlinkError: 931ad6a1e1cSTejun Heo if (MAJOR(dev->devt)) 932e105b8bfSDan Williams device_remove_sys_dev_entry(dev); 933e105b8bfSDan Williams devtattrError: 934e105b8bfSDan Williams if (MAJOR(dev->devt)) 935ad6a1e1cSTejun Heo device_remove_file(dev, &devt_attr); 936a306eea4SCornelia Huck ueventattrError: 937ad6a1e1cSTejun Heo device_remove_file(dev, &uevent_attr); 93823681e47SGreg Kroah-Hartman attrError: 939312c004dSKay Sievers kobject_uevent(&dev->kobj, KOBJ_REMOVE); 9401da177e4SLinus Torvalds kobject_del(&dev->kobj); 9411da177e4SLinus Torvalds Error: 94263b6971aSCornelia Huck cleanup_device_parent(dev); 9431da177e4SLinus Torvalds if (parent) 9441da177e4SLinus Torvalds put_device(parent); 9451da177e4SLinus Torvalds goto Done; 9461da177e4SLinus Torvalds } 9471da177e4SLinus Torvalds 9481da177e4SLinus Torvalds /** 9491da177e4SLinus Torvalds * device_register - register a device with the system. 9501da177e4SLinus Torvalds * @dev: pointer to the device structure 9511da177e4SLinus Torvalds * 9521da177e4SLinus Torvalds * This happens in two clean steps - initialize the device 9531da177e4SLinus Torvalds * and add it to the system. The two steps can be called 9541da177e4SLinus Torvalds * separately, but this is the easiest and most common. 9551da177e4SLinus Torvalds * I.e. you should only call the two helpers separately if 9561da177e4SLinus Torvalds * have a clearly defined need to use and refcount the device 9571da177e4SLinus Torvalds * before it is added to the hierarchy. 9581da177e4SLinus Torvalds */ 9591da177e4SLinus Torvalds int device_register(struct device *dev) 9601da177e4SLinus Torvalds { 9611da177e4SLinus Torvalds device_initialize(dev); 9621da177e4SLinus Torvalds return device_add(dev); 9631da177e4SLinus Torvalds } 9641da177e4SLinus Torvalds 9651da177e4SLinus Torvalds /** 9661da177e4SLinus Torvalds * get_device - increment reference count for device. 9671da177e4SLinus Torvalds * @dev: device. 9681da177e4SLinus Torvalds * 9691da177e4SLinus Torvalds * This simply forwards the call to kobject_get(), though 9701da177e4SLinus Torvalds * we do take care to provide for the case that we get a NULL 9711da177e4SLinus Torvalds * pointer passed in. 9721da177e4SLinus Torvalds */ 9731da177e4SLinus Torvalds struct device *get_device(struct device *dev) 9741da177e4SLinus Torvalds { 9751da177e4SLinus Torvalds return dev ? to_dev(kobject_get(&dev->kobj)) : NULL; 9761da177e4SLinus Torvalds } 9771da177e4SLinus Torvalds 9781da177e4SLinus Torvalds /** 9791da177e4SLinus Torvalds * put_device - decrement reference count. 9801da177e4SLinus Torvalds * @dev: device in question. 9811da177e4SLinus Torvalds */ 9821da177e4SLinus Torvalds void put_device(struct device *dev) 9831da177e4SLinus Torvalds { 984edfaa7c3SKay Sievers /* might_sleep(); */ 9851da177e4SLinus Torvalds if (dev) 9861da177e4SLinus Torvalds kobject_put(&dev->kobj); 9871da177e4SLinus Torvalds } 9881da177e4SLinus Torvalds 9891da177e4SLinus Torvalds /** 9901da177e4SLinus Torvalds * device_del - delete device from system. 9911da177e4SLinus Torvalds * @dev: device. 9921da177e4SLinus Torvalds * 9931da177e4SLinus Torvalds * This is the first part of the device unregistration 9941da177e4SLinus Torvalds * sequence. This removes the device from the lists we control 9951da177e4SLinus Torvalds * from here, has it removed from the other driver model 9961da177e4SLinus Torvalds * subsystems it was added to in device_add(), and removes it 9971da177e4SLinus Torvalds * from the kobject hierarchy. 9981da177e4SLinus Torvalds * 9991da177e4SLinus Torvalds * NOTE: this should be called manually _iff_ device_add() was 10001da177e4SLinus Torvalds * also called manually. 10011da177e4SLinus Torvalds */ 10021da177e4SLinus Torvalds void device_del(struct device *dev) 10031da177e4SLinus Torvalds { 10041da177e4SLinus Torvalds struct device *parent = dev->parent; 1005c47ed219SGreg Kroah-Hartman struct class_interface *class_intf; 10061da177e4SLinus Torvalds 1007775b64d2SRafael J. Wysocki device_pm_remove(dev); 10081da177e4SLinus Torvalds if (parent) 1009d62c0f9fSPatrick Mochel klist_del(&dev->knode_parent); 1010e105b8bfSDan Williams if (MAJOR(dev->devt)) { 1011e105b8bfSDan Williams device_remove_sys_dev_entry(dev); 1012ad6a1e1cSTejun Heo device_remove_file(dev, &devt_attr); 1013e105b8bfSDan Williams } 1014b9d9c82bSKay Sievers if (dev->class) { 1015da231fd5SKay Sievers device_remove_class_symlinks(dev); 101699ef3ef8SKay Sievers 10177c71448bSGreg Kroah-Hartman down(&dev->class->p->sem); 1018c47ed219SGreg Kroah-Hartman /* notify any interfaces that the device is now gone */ 1019*184f1f77SGreg Kroah-Hartman list_for_each_entry(class_intf, 1020*184f1f77SGreg Kroah-Hartman &dev->class->p->class_interfaces, node) 1021c47ed219SGreg Kroah-Hartman if (class_intf->remove_dev) 1022c47ed219SGreg Kroah-Hartman class_intf->remove_dev(dev, class_intf); 1023c47ed219SGreg Kroah-Hartman /* remove the device from the class list */ 10245d9fd169SGreg Kroah-Hartman list_del_init(&dev->node); 10257c71448bSGreg Kroah-Hartman up(&dev->class->p->sem); 1026b9d9c82bSKay Sievers } 1027ad6a1e1cSTejun Heo device_remove_file(dev, &uevent_attr); 10282620efefSGreg Kroah-Hartman device_remove_attrs(dev); 102928953533SBenjamin Herrenschmidt bus_remove_device(dev); 10301da177e4SLinus Torvalds 10312f8d16a9STejun Heo /* 10322f8d16a9STejun Heo * Some platform devices are driven without driver attached 10332f8d16a9STejun Heo * and managed resources may have been acquired. Make sure 10342f8d16a9STejun Heo * all resources are released. 10352f8d16a9STejun Heo */ 10362f8d16a9STejun Heo devres_release_all(dev); 10372f8d16a9STejun Heo 10381da177e4SLinus Torvalds /* Notify the platform of the removal, in case they 10391da177e4SLinus Torvalds * need to do anything... 10401da177e4SLinus Torvalds */ 10411da177e4SLinus Torvalds if (platform_notify_remove) 10421da177e4SLinus Torvalds platform_notify_remove(dev); 1043116af378SBenjamin Herrenschmidt if (dev->bus) 1044c6f7e72aSGreg Kroah-Hartman blocking_notifier_call_chain(&dev->bus->p->bus_notifier, 1045116af378SBenjamin Herrenschmidt BUS_NOTIFY_DEL_DEVICE, dev); 1046312c004dSKay Sievers kobject_uevent(&dev->kobj, KOBJ_REMOVE); 1047da231fd5SKay Sievers cleanup_device_parent(dev); 10481da177e4SLinus Torvalds kobject_del(&dev->kobj); 10491da177e4SLinus Torvalds put_device(parent); 10501da177e4SLinus Torvalds } 10511da177e4SLinus Torvalds 10521da177e4SLinus Torvalds /** 10531da177e4SLinus Torvalds * device_unregister - unregister device from system. 10541da177e4SLinus Torvalds * @dev: device going away. 10551da177e4SLinus Torvalds * 10561da177e4SLinus Torvalds * We do this in two parts, like we do device_register(). First, 10571da177e4SLinus Torvalds * we remove it from all the subsystems with device_del(), then 10581da177e4SLinus Torvalds * we decrement the reference count via put_device(). If that 10591da177e4SLinus Torvalds * is the final reference count, the device will be cleaned up 10601da177e4SLinus Torvalds * via device_release() above. Otherwise, the structure will 10611da177e4SLinus Torvalds * stick around until the final reference to the device is dropped. 10621da177e4SLinus Torvalds */ 10631da177e4SLinus Torvalds void device_unregister(struct device *dev) 10641da177e4SLinus Torvalds { 10652b3a302aSHarvey Harrison pr_debug("device: '%s': %s\n", dev->bus_id, __func__); 10661da177e4SLinus Torvalds device_del(dev); 10671da177e4SLinus Torvalds put_device(dev); 10681da177e4SLinus Torvalds } 10691da177e4SLinus Torvalds 107036239577Smochel@digitalimplant.org static struct device *next_device(struct klist_iter *i) 107136239577Smochel@digitalimplant.org { 107236239577Smochel@digitalimplant.org struct klist_node *n = klist_next(i); 107336239577Smochel@digitalimplant.org return n ? container_of(n, struct device, knode_parent) : NULL; 107436239577Smochel@digitalimplant.org } 107536239577Smochel@digitalimplant.org 10761da177e4SLinus Torvalds /** 10771da177e4SLinus Torvalds * device_for_each_child - device child iterator. 1078c41455fbSRandy Dunlap * @parent: parent struct device. 10791da177e4SLinus Torvalds * @data: data for the callback. 10801da177e4SLinus Torvalds * @fn: function to be called for each device. 10811da177e4SLinus Torvalds * 1082c41455fbSRandy Dunlap * Iterate over @parent's child devices, and call @fn for each, 10831da177e4SLinus Torvalds * passing it @data. 10841da177e4SLinus Torvalds * 10851da177e4SLinus Torvalds * We check the return of @fn each time. If it returns anything 10861da177e4SLinus Torvalds * other than 0, we break out and return that value. 10871da177e4SLinus Torvalds */ 108836239577Smochel@digitalimplant.org int device_for_each_child(struct device *parent, void *data, 10894a3ad20cSGreg Kroah-Hartman int (*fn)(struct device *dev, void *data)) 10901da177e4SLinus Torvalds { 109136239577Smochel@digitalimplant.org struct klist_iter i; 10921da177e4SLinus Torvalds struct device *child; 10931da177e4SLinus Torvalds int error = 0; 10941da177e4SLinus Torvalds 109536239577Smochel@digitalimplant.org klist_iter_init(&parent->klist_children, &i); 109636239577Smochel@digitalimplant.org while ((child = next_device(&i)) && !error) 109736239577Smochel@digitalimplant.org error = fn(child, data); 109836239577Smochel@digitalimplant.org klist_iter_exit(&i); 10991da177e4SLinus Torvalds return error; 11001da177e4SLinus Torvalds } 11011da177e4SLinus Torvalds 11025ab69981SCornelia Huck /** 11035ab69981SCornelia Huck * device_find_child - device iterator for locating a particular device. 11045ab69981SCornelia Huck * @parent: parent struct device 11055ab69981SCornelia Huck * @data: Data to pass to match function 11065ab69981SCornelia Huck * @match: Callback function to check device 11075ab69981SCornelia Huck * 11085ab69981SCornelia Huck * This is similar to the device_for_each_child() function above, but it 11095ab69981SCornelia Huck * returns a reference to a device that is 'found' for later use, as 11105ab69981SCornelia Huck * determined by the @match callback. 11115ab69981SCornelia Huck * 11125ab69981SCornelia Huck * The callback should return 0 if the device doesn't match and non-zero 11135ab69981SCornelia Huck * if it does. If the callback returns non-zero and a reference to the 11145ab69981SCornelia Huck * current device can be obtained, this function will return to the caller 11155ab69981SCornelia Huck * and not iterate over any more devices. 11165ab69981SCornelia Huck */ 11175ab69981SCornelia Huck struct device *device_find_child(struct device *parent, void *data, 11184a3ad20cSGreg Kroah-Hartman int (*match)(struct device *dev, void *data)) 11195ab69981SCornelia Huck { 11205ab69981SCornelia Huck struct klist_iter i; 11215ab69981SCornelia Huck struct device *child; 11225ab69981SCornelia Huck 11235ab69981SCornelia Huck if (!parent) 11245ab69981SCornelia Huck return NULL; 11255ab69981SCornelia Huck 11265ab69981SCornelia Huck klist_iter_init(&parent->klist_children, &i); 11275ab69981SCornelia Huck while ((child = next_device(&i))) 11285ab69981SCornelia Huck if (match(child, data) && get_device(child)) 11295ab69981SCornelia Huck break; 11305ab69981SCornelia Huck klist_iter_exit(&i); 11315ab69981SCornelia Huck return child; 11325ab69981SCornelia Huck } 11335ab69981SCornelia Huck 11341da177e4SLinus Torvalds int __init devices_init(void) 11351da177e4SLinus Torvalds { 1136881c6cfdSGreg Kroah-Hartman devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL); 1137881c6cfdSGreg Kroah-Hartman if (!devices_kset) 1138881c6cfdSGreg Kroah-Hartman return -ENOMEM; 1139e105b8bfSDan Williams dev_kobj = kobject_create_and_add("dev", NULL); 1140e105b8bfSDan Williams if (!dev_kobj) 1141e105b8bfSDan Williams goto dev_kobj_err; 1142e105b8bfSDan Williams sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj); 1143e105b8bfSDan Williams if (!sysfs_dev_block_kobj) 1144e105b8bfSDan Williams goto block_kobj_err; 1145e105b8bfSDan Williams sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj); 1146e105b8bfSDan Williams if (!sysfs_dev_char_kobj) 1147e105b8bfSDan Williams goto char_kobj_err; 1148e105b8bfSDan Williams 1149881c6cfdSGreg Kroah-Hartman return 0; 1150e105b8bfSDan Williams 1151e105b8bfSDan Williams char_kobj_err: 1152e105b8bfSDan Williams kobject_put(sysfs_dev_block_kobj); 1153e105b8bfSDan Williams block_kobj_err: 1154e105b8bfSDan Williams kobject_put(dev_kobj); 1155e105b8bfSDan Williams dev_kobj_err: 1156e105b8bfSDan Williams kset_unregister(devices_kset); 1157e105b8bfSDan Williams return -ENOMEM; 11581da177e4SLinus Torvalds } 11591da177e4SLinus Torvalds 11601da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(device_for_each_child); 11615ab69981SCornelia Huck EXPORT_SYMBOL_GPL(device_find_child); 11621da177e4SLinus Torvalds 11631da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(device_initialize); 11641da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(device_add); 11651da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(device_register); 11661da177e4SLinus Torvalds 11671da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(device_del); 11681da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(device_unregister); 11691da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(get_device); 11701da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(put_device); 11711da177e4SLinus Torvalds 11721da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(device_create_file); 11731da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(device_remove_file); 117423681e47SGreg Kroah-Hartman 117523681e47SGreg Kroah-Hartman 117623681e47SGreg Kroah-Hartman static void device_create_release(struct device *dev) 117723681e47SGreg Kroah-Hartman { 11782b3a302aSHarvey Harrison pr_debug("device: '%s': %s\n", dev->bus_id, __func__); 117923681e47SGreg Kroah-Hartman kfree(dev); 118023681e47SGreg Kroah-Hartman } 118123681e47SGreg Kroah-Hartman 118223681e47SGreg Kroah-Hartman /** 11838882b394SGreg Kroah-Hartman * device_create_vargs - creates a device and registers it with sysfs 11848882b394SGreg Kroah-Hartman * @class: pointer to the struct class that this device should be registered to 11858882b394SGreg Kroah-Hartman * @parent: pointer to the parent struct device of this new device, if any 11868882b394SGreg Kroah-Hartman * @devt: the dev_t for the char device to be added 11878882b394SGreg Kroah-Hartman * @drvdata: the data to be added to the device for callbacks 11888882b394SGreg Kroah-Hartman * @fmt: string for the device's name 11898882b394SGreg Kroah-Hartman * @args: va_list for the device's name 11908882b394SGreg Kroah-Hartman * 11918882b394SGreg Kroah-Hartman * This function can be used by char device classes. A struct device 11928882b394SGreg Kroah-Hartman * will be created in sysfs, registered to the specified class. 11938882b394SGreg Kroah-Hartman * 11948882b394SGreg Kroah-Hartman * A "dev" file will be created, showing the dev_t for the device, if 11958882b394SGreg Kroah-Hartman * the dev_t is not 0,0. 11968882b394SGreg Kroah-Hartman * If a pointer to a parent struct device is passed in, the newly created 11978882b394SGreg Kroah-Hartman * struct device will be a child of that device in sysfs. 11988882b394SGreg Kroah-Hartman * The pointer to the struct device will be returned from the call. 11998882b394SGreg Kroah-Hartman * Any further sysfs files that might be required can be created using this 12008882b394SGreg Kroah-Hartman * pointer. 12018882b394SGreg Kroah-Hartman * 12028882b394SGreg Kroah-Hartman * Note: the struct class passed to this function must have previously 12038882b394SGreg Kroah-Hartman * been created with a call to class_create(). 12048882b394SGreg Kroah-Hartman */ 12058882b394SGreg Kroah-Hartman struct device *device_create_vargs(struct class *class, struct device *parent, 12068882b394SGreg Kroah-Hartman dev_t devt, void *drvdata, const char *fmt, 12078882b394SGreg Kroah-Hartman va_list args) 12088882b394SGreg Kroah-Hartman { 12098882b394SGreg Kroah-Hartman struct device *dev = NULL; 12108882b394SGreg Kroah-Hartman int retval = -ENODEV; 12118882b394SGreg Kroah-Hartman 12128882b394SGreg Kroah-Hartman if (class == NULL || IS_ERR(class)) 12138882b394SGreg Kroah-Hartman goto error; 12148882b394SGreg Kroah-Hartman 12158882b394SGreg Kroah-Hartman dev = kzalloc(sizeof(*dev), GFP_KERNEL); 12168882b394SGreg Kroah-Hartman if (!dev) { 12178882b394SGreg Kroah-Hartman retval = -ENOMEM; 12188882b394SGreg Kroah-Hartman goto error; 12198882b394SGreg Kroah-Hartman } 12208882b394SGreg Kroah-Hartman 12218882b394SGreg Kroah-Hartman dev->devt = devt; 12228882b394SGreg Kroah-Hartman dev->class = class; 12238882b394SGreg Kroah-Hartman dev->parent = parent; 12248882b394SGreg Kroah-Hartman dev->release = device_create_release; 12258882b394SGreg Kroah-Hartman dev_set_drvdata(dev, drvdata); 12268882b394SGreg Kroah-Hartman 12278882b394SGreg Kroah-Hartman vsnprintf(dev->bus_id, BUS_ID_SIZE, fmt, args); 12288882b394SGreg Kroah-Hartman retval = device_register(dev); 12298882b394SGreg Kroah-Hartman if (retval) 12308882b394SGreg Kroah-Hartman goto error; 12318882b394SGreg Kroah-Hartman 12328882b394SGreg Kroah-Hartman return dev; 12338882b394SGreg Kroah-Hartman 12348882b394SGreg Kroah-Hartman error: 12358882b394SGreg Kroah-Hartman kfree(dev); 12368882b394SGreg Kroah-Hartman return ERR_PTR(retval); 12378882b394SGreg Kroah-Hartman } 12388882b394SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(device_create_vargs); 12398882b394SGreg Kroah-Hartman 12408882b394SGreg Kroah-Hartman /** 12414e106739SGreg Kroah-Hartman * device_create - creates a device and registers it with sysfs 12428882b394SGreg Kroah-Hartman * @class: pointer to the struct class that this device should be registered to 12438882b394SGreg Kroah-Hartman * @parent: pointer to the parent struct device of this new device, if any 12448882b394SGreg Kroah-Hartman * @devt: the dev_t for the char device to be added 12458882b394SGreg Kroah-Hartman * @drvdata: the data to be added to the device for callbacks 12468882b394SGreg Kroah-Hartman * @fmt: string for the device's name 12478882b394SGreg Kroah-Hartman * 12488882b394SGreg Kroah-Hartman * This function can be used by char device classes. A struct device 12498882b394SGreg Kroah-Hartman * will be created in sysfs, registered to the specified class. 12508882b394SGreg Kroah-Hartman * 12518882b394SGreg Kroah-Hartman * A "dev" file will be created, showing the dev_t for the device, if 12528882b394SGreg Kroah-Hartman * the dev_t is not 0,0. 12538882b394SGreg Kroah-Hartman * If a pointer to a parent struct device is passed in, the newly created 12548882b394SGreg Kroah-Hartman * struct device will be a child of that device in sysfs. 12558882b394SGreg Kroah-Hartman * The pointer to the struct device will be returned from the call. 12568882b394SGreg Kroah-Hartman * Any further sysfs files that might be required can be created using this 12578882b394SGreg Kroah-Hartman * pointer. 12588882b394SGreg Kroah-Hartman * 12598882b394SGreg Kroah-Hartman * Note: the struct class passed to this function must have previously 12608882b394SGreg Kroah-Hartman * been created with a call to class_create(). 12618882b394SGreg Kroah-Hartman */ 12624e106739SGreg Kroah-Hartman struct device *device_create(struct class *class, struct device *parent, 12634e106739SGreg Kroah-Hartman dev_t devt, void *drvdata, const char *fmt, ...) 12648882b394SGreg Kroah-Hartman { 12658882b394SGreg Kroah-Hartman va_list vargs; 12668882b394SGreg Kroah-Hartman struct device *dev; 12678882b394SGreg Kroah-Hartman 12688882b394SGreg Kroah-Hartman va_start(vargs, fmt); 12698882b394SGreg Kroah-Hartman dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs); 12708882b394SGreg Kroah-Hartman va_end(vargs); 12718882b394SGreg Kroah-Hartman return dev; 12728882b394SGreg Kroah-Hartman } 12734e106739SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(device_create); 12748882b394SGreg Kroah-Hartman 1275cd35449bSDave Young static int __match_devt(struct device *dev, void *data) 127623681e47SGreg Kroah-Hartman { 1277cd35449bSDave Young dev_t *devt = data; 127823681e47SGreg Kroah-Hartman 1279cd35449bSDave Young return dev->devt == *devt; 1280775b64d2SRafael J. Wysocki } 128123681e47SGreg Kroah-Hartman 1282775b64d2SRafael J. Wysocki /** 1283775b64d2SRafael J. Wysocki * device_destroy - removes a device that was created with device_create() 1284775b64d2SRafael J. Wysocki * @class: pointer to the struct class that this device was registered with 1285775b64d2SRafael J. Wysocki * @devt: the dev_t of the device that was previously registered 1286775b64d2SRafael J. Wysocki * 1287775b64d2SRafael J. Wysocki * This call unregisters and cleans up a device that was created with a 1288775b64d2SRafael J. Wysocki * call to device_create(). 1289775b64d2SRafael J. Wysocki */ 1290775b64d2SRafael J. Wysocki void device_destroy(struct class *class, dev_t devt) 1291775b64d2SRafael J. Wysocki { 1292775b64d2SRafael J. Wysocki struct device *dev; 1293775b64d2SRafael J. Wysocki 1294695794aeSGreg Kroah-Hartman dev = class_find_device(class, NULL, &devt, __match_devt); 1295cd35449bSDave Young if (dev) { 1296cd35449bSDave Young put_device(dev); 129723681e47SGreg Kroah-Hartman device_unregister(dev); 129823681e47SGreg Kroah-Hartman } 1299cd35449bSDave Young } 130023681e47SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(device_destroy); 1301a2de48caSGreg Kroah-Hartman 1302a2de48caSGreg Kroah-Hartman /** 1303a2de48caSGreg Kroah-Hartman * device_rename - renames a device 1304a2de48caSGreg Kroah-Hartman * @dev: the pointer to the struct device to be renamed 1305a2de48caSGreg Kroah-Hartman * @new_name: the new name of the device 1306a2de48caSGreg Kroah-Hartman */ 1307a2de48caSGreg Kroah-Hartman int device_rename(struct device *dev, char *new_name) 1308a2de48caSGreg Kroah-Hartman { 1309a2de48caSGreg Kroah-Hartman char *old_class_name = NULL; 1310a2de48caSGreg Kroah-Hartman char *new_class_name = NULL; 13112ee97cafSCornelia Huck char *old_device_name = NULL; 1312a2de48caSGreg Kroah-Hartman int error; 1313a2de48caSGreg Kroah-Hartman 1314a2de48caSGreg Kroah-Hartman dev = get_device(dev); 1315a2de48caSGreg Kroah-Hartman if (!dev) 1316a2de48caSGreg Kroah-Hartman return -EINVAL; 1317a2de48caSGreg Kroah-Hartman 13187dc72b28SGreg Kroah-Hartman pr_debug("device: '%s': %s: renaming to '%s'\n", dev->bus_id, 13192b3a302aSHarvey Harrison __func__, new_name); 1320a2de48caSGreg Kroah-Hartman 132199ef3ef8SKay Sievers #ifdef CONFIG_SYSFS_DEPRECATED 1322a2de48caSGreg Kroah-Hartman if ((dev->class) && (dev->parent)) 1323a2de48caSGreg Kroah-Hartman old_class_name = make_class_name(dev->class->name, &dev->kobj); 132499ef3ef8SKay Sievers #endif 1325a2de48caSGreg Kroah-Hartman 13262ee97cafSCornelia Huck old_device_name = kmalloc(BUS_ID_SIZE, GFP_KERNEL); 13272ee97cafSCornelia Huck if (!old_device_name) { 1328952ab431SJesper Juhl error = -ENOMEM; 13292ee97cafSCornelia Huck goto out; 1330952ab431SJesper Juhl } 13312ee97cafSCornelia Huck strlcpy(old_device_name, dev->bus_id, BUS_ID_SIZE); 1332a2de48caSGreg Kroah-Hartman strlcpy(dev->bus_id, new_name, BUS_ID_SIZE); 1333a2de48caSGreg Kroah-Hartman 1334a2de48caSGreg Kroah-Hartman error = kobject_rename(&dev->kobj, new_name); 13352ee97cafSCornelia Huck if (error) { 13362ee97cafSCornelia Huck strlcpy(dev->bus_id, old_device_name, BUS_ID_SIZE); 13372ee97cafSCornelia Huck goto out; 13382ee97cafSCornelia Huck } 1339a2de48caSGreg Kroah-Hartman 134099ef3ef8SKay Sievers #ifdef CONFIG_SYSFS_DEPRECATED 1341a2de48caSGreg Kroah-Hartman if (old_class_name) { 1342a2de48caSGreg Kroah-Hartman new_class_name = make_class_name(dev->class->name, &dev->kobj); 1343a2de48caSGreg Kroah-Hartman if (new_class_name) { 13442ee97cafSCornelia Huck error = sysfs_create_link(&dev->parent->kobj, 13452ee97cafSCornelia Huck &dev->kobj, new_class_name); 13462ee97cafSCornelia Huck if (error) 13472ee97cafSCornelia Huck goto out; 1348a2de48caSGreg Kroah-Hartman sysfs_remove_link(&dev->parent->kobj, old_class_name); 1349a2de48caSGreg Kroah-Hartman } 1350a2de48caSGreg Kroah-Hartman } 135160b8cabdSKay Sievers #else 1352a2de48caSGreg Kroah-Hartman if (dev->class) { 13537c71448bSGreg Kroah-Hartman error = sysfs_create_link(&dev->class->p->subsys.kobj, 13547c71448bSGreg Kroah-Hartman &dev->kobj, dev->bus_id); 13550599ad53SStephen Hemminger if (error) 13560599ad53SStephen Hemminger goto out; 13577c71448bSGreg Kroah-Hartman sysfs_remove_link(&dev->class->p->subsys.kobj, 13587c71448bSGreg Kroah-Hartman old_device_name); 13592ee97cafSCornelia Huck } 136060b8cabdSKay Sievers #endif 136160b8cabdSKay Sievers 13622ee97cafSCornelia Huck out: 1363a2de48caSGreg Kroah-Hartman put_device(dev); 1364a2de48caSGreg Kroah-Hartman 1365a2de48caSGreg Kroah-Hartman kfree(new_class_name); 1366952ab431SJesper Juhl kfree(old_class_name); 13672ee97cafSCornelia Huck kfree(old_device_name); 1368a2de48caSGreg Kroah-Hartman 1369a2de48caSGreg Kroah-Hartman return error; 1370a2de48caSGreg Kroah-Hartman } 1371a2807dbcSJohannes Berg EXPORT_SYMBOL_GPL(device_rename); 13728a82472fSCornelia Huck 13738a82472fSCornelia Huck static int device_move_class_links(struct device *dev, 13748a82472fSCornelia Huck struct device *old_parent, 13758a82472fSCornelia Huck struct device *new_parent) 13768a82472fSCornelia Huck { 1377f7f3461dSGreg Kroah-Hartman int error = 0; 13788a82472fSCornelia Huck #ifdef CONFIG_SYSFS_DEPRECATED 13798a82472fSCornelia Huck char *class_name; 13808a82472fSCornelia Huck 13818a82472fSCornelia Huck class_name = make_class_name(dev->class->name, &dev->kobj); 13828a82472fSCornelia Huck if (!class_name) { 1383cb360bbfSCornelia Huck error = -ENOMEM; 13848a82472fSCornelia Huck goto out; 13858a82472fSCornelia Huck } 13868a82472fSCornelia Huck if (old_parent) { 13878a82472fSCornelia Huck sysfs_remove_link(&dev->kobj, "device"); 13888a82472fSCornelia Huck sysfs_remove_link(&old_parent->kobj, class_name); 13898a82472fSCornelia Huck } 1390c744aeaeSCornelia Huck if (new_parent) { 1391c744aeaeSCornelia Huck error = sysfs_create_link(&dev->kobj, &new_parent->kobj, 1392c744aeaeSCornelia Huck "device"); 13938a82472fSCornelia Huck if (error) 13948a82472fSCornelia Huck goto out; 1395c744aeaeSCornelia Huck error = sysfs_create_link(&new_parent->kobj, &dev->kobj, 1396c744aeaeSCornelia Huck class_name); 13978a82472fSCornelia Huck if (error) 13988a82472fSCornelia Huck sysfs_remove_link(&dev->kobj, "device"); 13994a3ad20cSGreg Kroah-Hartman } else 1400c744aeaeSCornelia Huck error = 0; 14018a82472fSCornelia Huck out: 14028a82472fSCornelia Huck kfree(class_name); 14038a82472fSCornelia Huck return error; 14048a82472fSCornelia Huck #else 1405f7f3461dSGreg Kroah-Hartman if (old_parent) 1406f7f3461dSGreg Kroah-Hartman sysfs_remove_link(&dev->kobj, "device"); 1407f7f3461dSGreg Kroah-Hartman if (new_parent) 1408f7f3461dSGreg Kroah-Hartman error = sysfs_create_link(&dev->kobj, &new_parent->kobj, 1409f7f3461dSGreg Kroah-Hartman "device"); 1410f7f3461dSGreg Kroah-Hartman return error; 14118a82472fSCornelia Huck #endif 14128a82472fSCornelia Huck } 14138a82472fSCornelia Huck 14148a82472fSCornelia Huck /** 14158a82472fSCornelia Huck * device_move - moves a device to a new parent 14168a82472fSCornelia Huck * @dev: the pointer to the struct device to be moved 1417c744aeaeSCornelia Huck * @new_parent: the new parent of the device (can by NULL) 14188a82472fSCornelia Huck */ 14198a82472fSCornelia Huck int device_move(struct device *dev, struct device *new_parent) 14208a82472fSCornelia Huck { 14218a82472fSCornelia Huck int error; 14228a82472fSCornelia Huck struct device *old_parent; 1423c744aeaeSCornelia Huck struct kobject *new_parent_kobj; 14248a82472fSCornelia Huck 14258a82472fSCornelia Huck dev = get_device(dev); 14268a82472fSCornelia Huck if (!dev) 14278a82472fSCornelia Huck return -EINVAL; 14288a82472fSCornelia Huck 14298a82472fSCornelia Huck new_parent = get_device(new_parent); 1430c744aeaeSCornelia Huck new_parent_kobj = get_device_parent(dev, new_parent); 143163b6971aSCornelia Huck 14327dc72b28SGreg Kroah-Hartman pr_debug("device: '%s': %s: moving to '%s'\n", dev->bus_id, 14332b3a302aSHarvey Harrison __func__, new_parent ? new_parent->bus_id : "<NULL>"); 1434c744aeaeSCornelia Huck error = kobject_move(&dev->kobj, new_parent_kobj); 14358a82472fSCornelia Huck if (error) { 143663b6971aSCornelia Huck cleanup_glue_dir(dev, new_parent_kobj); 14378a82472fSCornelia Huck put_device(new_parent); 14388a82472fSCornelia Huck goto out; 14398a82472fSCornelia Huck } 14408a82472fSCornelia Huck old_parent = dev->parent; 14418a82472fSCornelia Huck dev->parent = new_parent; 14428a82472fSCornelia Huck if (old_parent) 1443acf02d23SCornelia Huck klist_remove(&dev->knode_parent); 14440d358f22SYinghai Lu if (new_parent) { 14458a82472fSCornelia Huck klist_add_tail(&dev->knode_parent, &new_parent->klist_children); 14460d358f22SYinghai Lu set_dev_node(dev, dev_to_node(new_parent)); 14470d358f22SYinghai Lu } 14480d358f22SYinghai Lu 14498a82472fSCornelia Huck if (!dev->class) 14508a82472fSCornelia Huck goto out_put; 14518a82472fSCornelia Huck error = device_move_class_links(dev, old_parent, new_parent); 14528a82472fSCornelia Huck if (error) { 14538a82472fSCornelia Huck /* We ignore errors on cleanup since we're hosed anyway... */ 14548a82472fSCornelia Huck device_move_class_links(dev, new_parent, old_parent); 14558a82472fSCornelia Huck if (!kobject_move(&dev->kobj, &old_parent->kobj)) { 1456c744aeaeSCornelia Huck if (new_parent) 1457acf02d23SCornelia Huck klist_remove(&dev->knode_parent); 14580d358f22SYinghai Lu dev->parent = old_parent; 14590d358f22SYinghai Lu if (old_parent) { 14608a82472fSCornelia Huck klist_add_tail(&dev->knode_parent, 14618a82472fSCornelia Huck &old_parent->klist_children); 14620d358f22SYinghai Lu set_dev_node(dev, dev_to_node(old_parent)); 14630d358f22SYinghai Lu } 14648a82472fSCornelia Huck } 146563b6971aSCornelia Huck cleanup_glue_dir(dev, new_parent_kobj); 14668a82472fSCornelia Huck put_device(new_parent); 14678a82472fSCornelia Huck goto out; 14688a82472fSCornelia Huck } 14698a82472fSCornelia Huck out_put: 14708a82472fSCornelia Huck put_device(old_parent); 14718a82472fSCornelia Huck out: 14728a82472fSCornelia Huck put_device(dev); 14738a82472fSCornelia Huck return error; 14748a82472fSCornelia Huck } 14758a82472fSCornelia Huck EXPORT_SYMBOL_GPL(device_move); 147637b0c020SGreg Kroah-Hartman 147737b0c020SGreg Kroah-Hartman /** 147837b0c020SGreg Kroah-Hartman * device_shutdown - call ->shutdown() on each device to shutdown. 147937b0c020SGreg Kroah-Hartman */ 148037b0c020SGreg Kroah-Hartman void device_shutdown(void) 148137b0c020SGreg Kroah-Hartman { 148237b0c020SGreg Kroah-Hartman struct device *dev, *devn; 148337b0c020SGreg Kroah-Hartman 148437b0c020SGreg Kroah-Hartman list_for_each_entry_safe_reverse(dev, devn, &devices_kset->list, 148537b0c020SGreg Kroah-Hartman kobj.entry) { 148637b0c020SGreg Kroah-Hartman if (dev->bus && dev->bus->shutdown) { 148737b0c020SGreg Kroah-Hartman dev_dbg(dev, "shutdown\n"); 148837b0c020SGreg Kroah-Hartman dev->bus->shutdown(dev); 148937b0c020SGreg Kroah-Hartman } else if (dev->driver && dev->driver->shutdown) { 149037b0c020SGreg Kroah-Hartman dev_dbg(dev, "shutdown\n"); 149137b0c020SGreg Kroah-Hartman dev->driver->shutdown(dev); 149237b0c020SGreg Kroah-Hartman } 149337b0c020SGreg Kroah-Hartman } 1494e105b8bfSDan Williams kobject_put(sysfs_dev_char_kobj); 1495e105b8bfSDan Williams kobject_put(sysfs_dev_block_kobj); 1496e105b8bfSDan Williams kobject_put(dev_kobj); 149737b0c020SGreg Kroah-Hartman } 1498