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> 211da177e4SLinus Torvalds 221da177e4SLinus Torvalds #include <asm/semaphore.h> 231da177e4SLinus Torvalds 241da177e4SLinus Torvalds #include "base.h" 251da177e4SLinus Torvalds #include "power/power.h" 261da177e4SLinus Torvalds 271da177e4SLinus Torvalds int (*platform_notify)(struct device * dev) = NULL; 281da177e4SLinus Torvalds int (*platform_notify_remove)(struct device * dev) = NULL; 291da177e4SLinus Torvalds 301da177e4SLinus Torvalds /* 311da177e4SLinus Torvalds * sysfs bindings for devices. 321da177e4SLinus Torvalds */ 331da177e4SLinus Torvalds 343e95637aSAlan Stern /** 353e95637aSAlan Stern * dev_driver_string - Return a device's driver name, if at all possible 363e95637aSAlan Stern * @dev: struct device to get the name of 373e95637aSAlan Stern * 383e95637aSAlan Stern * Will return the device's driver's name if it is bound to a device. If 393e95637aSAlan Stern * the device is not bound to a device, it will return the name of the bus 403e95637aSAlan Stern * it is attached to. If it is not attached to a bus either, an empty 413e95637aSAlan Stern * string will be returned. 423e95637aSAlan Stern */ 433e95637aSAlan Stern const char *dev_driver_string(struct device *dev) 443e95637aSAlan Stern { 453e95637aSAlan Stern return dev->driver ? dev->driver->name : 46a456b702SJean Delvare (dev->bus ? dev->bus->name : 47a456b702SJean Delvare (dev->class ? dev->class->name : "")); 483e95637aSAlan Stern } 49310a922dSMatthew Wilcox EXPORT_SYMBOL(dev_driver_string); 503e95637aSAlan Stern 511da177e4SLinus Torvalds #define to_dev(obj) container_of(obj, struct device, kobj) 521da177e4SLinus Torvalds #define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr) 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds static ssize_t 551da177e4SLinus Torvalds dev_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) 561da177e4SLinus Torvalds { 571da177e4SLinus Torvalds struct device_attribute * dev_attr = to_dev_attr(attr); 581da177e4SLinus Torvalds struct device * dev = to_dev(kobj); 594a0c20bfSDmitry Torokhov ssize_t ret = -EIO; 601da177e4SLinus Torvalds 611da177e4SLinus Torvalds if (dev_attr->show) 6254b6f35cSYani Ioannou ret = dev_attr->show(dev, dev_attr, buf); 631da177e4SLinus Torvalds return ret; 641da177e4SLinus Torvalds } 651da177e4SLinus Torvalds 661da177e4SLinus Torvalds static ssize_t 671da177e4SLinus Torvalds dev_attr_store(struct kobject * kobj, struct attribute * attr, 681da177e4SLinus Torvalds const char * buf, size_t count) 691da177e4SLinus Torvalds { 701da177e4SLinus Torvalds struct device_attribute * dev_attr = to_dev_attr(attr); 711da177e4SLinus Torvalds struct device * dev = to_dev(kobj); 724a0c20bfSDmitry Torokhov ssize_t ret = -EIO; 731da177e4SLinus Torvalds 741da177e4SLinus Torvalds if (dev_attr->store) 7554b6f35cSYani Ioannou ret = dev_attr->store(dev, dev_attr, buf, count); 761da177e4SLinus Torvalds return ret; 771da177e4SLinus Torvalds } 781da177e4SLinus Torvalds 791da177e4SLinus Torvalds static struct sysfs_ops dev_sysfs_ops = { 801da177e4SLinus Torvalds .show = dev_attr_show, 811da177e4SLinus Torvalds .store = dev_attr_store, 821da177e4SLinus Torvalds }; 831da177e4SLinus Torvalds 841da177e4SLinus Torvalds 851da177e4SLinus Torvalds /** 861da177e4SLinus Torvalds * device_release - free device structure. 871da177e4SLinus Torvalds * @kobj: device's kobject. 881da177e4SLinus Torvalds * 891da177e4SLinus Torvalds * This is called once the reference count for the object 901da177e4SLinus Torvalds * reaches 0. We forward the call to the device's release 911da177e4SLinus Torvalds * method, which should handle actually freeing the structure. 921da177e4SLinus Torvalds */ 931da177e4SLinus Torvalds static void device_release(struct kobject * kobj) 941da177e4SLinus Torvalds { 951da177e4SLinus Torvalds struct device * dev = to_dev(kobj); 961da177e4SLinus Torvalds 971da177e4SLinus Torvalds if (dev->release) 981da177e4SLinus Torvalds dev->release(dev); 99f9f852dfSKay Sievers else if (dev->type && dev->type->release) 100f9f852dfSKay Sievers dev->type->release(dev); 1012620efefSGreg Kroah-Hartman else if (dev->class && dev->class->dev_release) 1022620efefSGreg Kroah-Hartman dev->class->dev_release(dev); 1031da177e4SLinus Torvalds else { 1041da177e4SLinus Torvalds printk(KERN_ERR "Device '%s' does not have a release() function, " 1051da177e4SLinus Torvalds "it is broken and must be fixed.\n", 1061da177e4SLinus Torvalds dev->bus_id); 1071da177e4SLinus Torvalds WARN_ON(1); 1081da177e4SLinus Torvalds } 1091da177e4SLinus Torvalds } 1101da177e4SLinus Torvalds 1118f4afc41SGreg Kroah-Hartman static struct kobj_type device_ktype = { 1121da177e4SLinus Torvalds .release = device_release, 1131da177e4SLinus Torvalds .sysfs_ops = &dev_sysfs_ops, 1141da177e4SLinus Torvalds }; 1151da177e4SLinus Torvalds 1161da177e4SLinus Torvalds 117312c004dSKay Sievers static int dev_uevent_filter(struct kset *kset, struct kobject *kobj) 1181da177e4SLinus Torvalds { 1191da177e4SLinus Torvalds struct kobj_type *ktype = get_ktype(kobj); 1201da177e4SLinus Torvalds 1218f4afc41SGreg Kroah-Hartman if (ktype == &device_ktype) { 1221da177e4SLinus Torvalds struct device *dev = to_dev(kobj); 12383b5fb4cSCornelia Huck if (dev->uevent_suppress) 12483b5fb4cSCornelia Huck return 0; 1251da177e4SLinus Torvalds if (dev->bus) 1261da177e4SLinus Torvalds return 1; 12723681e47SGreg Kroah-Hartman if (dev->class) 12823681e47SGreg Kroah-Hartman return 1; 1291da177e4SLinus Torvalds } 1301da177e4SLinus Torvalds return 0; 1311da177e4SLinus Torvalds } 1321da177e4SLinus Torvalds 133312c004dSKay Sievers static const char *dev_uevent_name(struct kset *kset, struct kobject *kobj) 1341da177e4SLinus Torvalds { 1351da177e4SLinus Torvalds struct device *dev = to_dev(kobj); 1361da177e4SLinus Torvalds 13723681e47SGreg Kroah-Hartman if (dev->bus) 1381da177e4SLinus Torvalds return dev->bus->name; 13923681e47SGreg Kroah-Hartman if (dev->class) 14023681e47SGreg Kroah-Hartman return dev->class->name; 14123681e47SGreg Kroah-Hartman return NULL; 1421da177e4SLinus Torvalds } 1431da177e4SLinus Torvalds 1447eff2e7aSKay Sievers static int dev_uevent(struct kset *kset, struct kobject *kobj, 1457eff2e7aSKay Sievers struct kobj_uevent_env *env) 1461da177e4SLinus Torvalds { 1471da177e4SLinus Torvalds struct device *dev = to_dev(kobj); 1481da177e4SLinus Torvalds int retval = 0; 1491da177e4SLinus Torvalds 15023681e47SGreg Kroah-Hartman /* add the major/minor if present */ 15123681e47SGreg Kroah-Hartman if (MAJOR(dev->devt)) { 1527eff2e7aSKay Sievers add_uevent_var(env, "MAJOR=%u", MAJOR(dev->devt)); 1537eff2e7aSKay Sievers add_uevent_var(env, "MINOR=%u", MINOR(dev->devt)); 15423681e47SGreg Kroah-Hartman } 15523681e47SGreg Kroah-Hartman 156414264f9SKay Sievers if (dev->type && dev->type->name) 1577eff2e7aSKay Sievers add_uevent_var(env, "DEVTYPE=%s", dev->type->name); 158414264f9SKay Sievers 159239378f1SKay Sievers if (dev->driver) 1607eff2e7aSKay Sievers add_uevent_var(env, "DRIVER=%s", dev->driver->name); 161239378f1SKay Sievers 162a87cb2acSKay Sievers #ifdef CONFIG_SYSFS_DEPRECATED 163239378f1SKay Sievers if (dev->class) { 164239378f1SKay Sievers struct device *parent = dev->parent; 165239378f1SKay Sievers 166239378f1SKay Sievers /* find first bus device in parent chain */ 167239378f1SKay Sievers while (parent && !parent->bus) 168239378f1SKay Sievers parent = parent->parent; 169239378f1SKay Sievers if (parent && parent->bus) { 170239378f1SKay Sievers const char *path; 171239378f1SKay Sievers 172239378f1SKay Sievers path = kobject_get_path(&parent->kobj, GFP_KERNEL); 1732c7afd12SKay Sievers if (path) { 1747eff2e7aSKay Sievers add_uevent_var(env, "PHYSDEVPATH=%s", path); 175239378f1SKay Sievers kfree(path); 1762c7afd12SKay Sievers } 177239378f1SKay Sievers 1787eff2e7aSKay Sievers add_uevent_var(env, "PHYSDEVBUS=%s", parent->bus->name); 179239378f1SKay Sievers 180239378f1SKay Sievers if (parent->driver) 1817eff2e7aSKay Sievers add_uevent_var(env, "PHYSDEVDRIVER=%s", 1827eff2e7aSKay Sievers parent->driver->name); 183239378f1SKay Sievers } 184239378f1SKay Sievers } else if (dev->bus) { 1857eff2e7aSKay Sievers add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name); 186239378f1SKay Sievers 187239378f1SKay Sievers if (dev->driver) 1887eff2e7aSKay Sievers add_uevent_var(env, "PHYSDEVDRIVER=%s", dev->driver->name); 189d81d9d6bSKay Sievers } 190239378f1SKay Sievers #endif 1911da177e4SLinus Torvalds 1921da177e4SLinus Torvalds /* have the bus specific function add its stuff */ 1937eff2e7aSKay Sievers if (dev->bus && dev->bus->uevent) { 1947eff2e7aSKay Sievers retval = dev->bus->uevent(dev, env); 195f9f852dfSKay Sievers if (retval) 196f9f852dfSKay Sievers pr_debug ("%s: bus uevent() returned %d\n", 1971da177e4SLinus Torvalds __FUNCTION__, retval); 1981da177e4SLinus Torvalds } 1991da177e4SLinus Torvalds 2002620efefSGreg Kroah-Hartman /* have the class specific function add its stuff */ 2017eff2e7aSKay Sievers if (dev->class && dev->class->dev_uevent) { 2027eff2e7aSKay Sievers retval = dev->class->dev_uevent(dev, env); 203f9f852dfSKay Sievers if (retval) 204f9f852dfSKay Sievers pr_debug("%s: class uevent() returned %d\n", 2052620efefSGreg Kroah-Hartman __FUNCTION__, retval); 2062620efefSGreg Kroah-Hartman } 207f9f852dfSKay Sievers 208f9f852dfSKay Sievers /* have the device type specific fuction add its stuff */ 2097eff2e7aSKay Sievers if (dev->type && dev->type->uevent) { 2107eff2e7aSKay Sievers retval = dev->type->uevent(dev, env); 211f9f852dfSKay Sievers if (retval) 212f9f852dfSKay Sievers pr_debug("%s: dev_type uevent() returned %d\n", 213f9f852dfSKay Sievers __FUNCTION__, retval); 2142620efefSGreg Kroah-Hartman } 2152620efefSGreg Kroah-Hartman 2161da177e4SLinus Torvalds return retval; 2171da177e4SLinus Torvalds } 2181da177e4SLinus Torvalds 219312c004dSKay Sievers static struct kset_uevent_ops device_uevent_ops = { 220312c004dSKay Sievers .filter = dev_uevent_filter, 221312c004dSKay Sievers .name = dev_uevent_name, 222312c004dSKay Sievers .uevent = dev_uevent, 2231da177e4SLinus Torvalds }; 2241da177e4SLinus Torvalds 22516574dccSKay Sievers static ssize_t show_uevent(struct device *dev, struct device_attribute *attr, 22616574dccSKay Sievers char *buf) 22716574dccSKay Sievers { 22816574dccSKay Sievers struct kobject *top_kobj; 22916574dccSKay Sievers struct kset *kset; 2307eff2e7aSKay Sievers struct kobj_uevent_env *env = NULL; 23116574dccSKay Sievers int i; 23216574dccSKay Sievers size_t count = 0; 23316574dccSKay Sievers int retval; 23416574dccSKay Sievers 23516574dccSKay Sievers /* search the kset, the device belongs to */ 23616574dccSKay Sievers top_kobj = &dev->kobj; 2375c5daf65SKay Sievers while (!top_kobj->kset && top_kobj->parent) 23816574dccSKay Sievers top_kobj = top_kobj->parent; 23916574dccSKay Sievers if (!top_kobj->kset) 24016574dccSKay Sievers goto out; 2415c5daf65SKay Sievers 24216574dccSKay Sievers kset = top_kobj->kset; 24316574dccSKay Sievers if (!kset->uevent_ops || !kset->uevent_ops->uevent) 24416574dccSKay Sievers goto out; 24516574dccSKay Sievers 24616574dccSKay Sievers /* respect filter */ 24716574dccSKay Sievers if (kset->uevent_ops && kset->uevent_ops->filter) 24816574dccSKay Sievers if (!kset->uevent_ops->filter(kset, &dev->kobj)) 24916574dccSKay Sievers goto out; 25016574dccSKay Sievers 2517eff2e7aSKay Sievers env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL); 2527eff2e7aSKay Sievers if (!env) 253c7308c81SGreg Kroah-Hartman return -ENOMEM; 254c7308c81SGreg Kroah-Hartman 25516574dccSKay Sievers /* let the kset specific function add its keys */ 2567eff2e7aSKay Sievers retval = kset->uevent_ops->uevent(kset, &dev->kobj, env); 25716574dccSKay Sievers if (retval) 25816574dccSKay Sievers goto out; 25916574dccSKay Sievers 26016574dccSKay Sievers /* copy keys to file */ 2617eff2e7aSKay Sievers for (i = 0; i < env->envp_idx; i++) 2627eff2e7aSKay Sievers count += sprintf(&buf[count], "%s\n", env->envp[i]); 26316574dccSKay Sievers out: 2647eff2e7aSKay Sievers kfree(env); 26516574dccSKay Sievers return count; 26616574dccSKay Sievers } 26716574dccSKay Sievers 268a7fd6706SKay Sievers static ssize_t store_uevent(struct device *dev, struct device_attribute *attr, 269a7fd6706SKay Sievers const char *buf, size_t count) 270a7fd6706SKay Sievers { 27160a96a59SKay Sievers enum kobject_action action; 27260a96a59SKay Sievers 2735c5daf65SKay Sievers if (kobject_action_type(buf, count, &action) == 0) { 27460a96a59SKay Sievers kobject_uevent(&dev->kobj, action); 27560a96a59SKay Sievers goto out; 27660a96a59SKay Sievers } 27760a96a59SKay Sievers 27822af74f3SKay Sievers dev_err(dev, "uevent: unsupported action-string; this will " 27960a96a59SKay Sievers "be ignored in a future kernel version\n"); 280312c004dSKay Sievers kobject_uevent(&dev->kobj, KOBJ_ADD); 28160a96a59SKay Sievers out: 282a7fd6706SKay Sievers return count; 283a7fd6706SKay Sievers } 284a7fd6706SKay Sievers 285ad6a1e1cSTejun Heo static struct device_attribute uevent_attr = 286ad6a1e1cSTejun Heo __ATTR(uevent, S_IRUGO | S_IWUSR, show_uevent, store_uevent); 287ad6a1e1cSTejun Heo 288621a1672SDmitry Torokhov static int device_add_attributes(struct device *dev, 289621a1672SDmitry Torokhov struct device_attribute *attrs) 290de0ff00dSGreg Kroah-Hartman { 291de0ff00dSGreg Kroah-Hartman int error = 0; 292621a1672SDmitry Torokhov int i; 293de0ff00dSGreg Kroah-Hartman 294621a1672SDmitry Torokhov if (attrs) { 295621a1672SDmitry Torokhov for (i = 0; attr_name(attrs[i]); i++) { 296621a1672SDmitry Torokhov error = device_create_file(dev, &attrs[i]); 297621a1672SDmitry Torokhov if (error) 298621a1672SDmitry Torokhov break; 299621a1672SDmitry Torokhov } 300621a1672SDmitry Torokhov if (error) 301de0ff00dSGreg Kroah-Hartman while (--i >= 0) 302621a1672SDmitry Torokhov device_remove_file(dev, &attrs[i]); 303de0ff00dSGreg Kroah-Hartman } 304de0ff00dSGreg Kroah-Hartman return error; 305de0ff00dSGreg Kroah-Hartman } 306de0ff00dSGreg Kroah-Hartman 307621a1672SDmitry Torokhov static void device_remove_attributes(struct device *dev, 308621a1672SDmitry Torokhov struct device_attribute *attrs) 309de0ff00dSGreg Kroah-Hartman { 310de0ff00dSGreg Kroah-Hartman int i; 311621a1672SDmitry Torokhov 312621a1672SDmitry Torokhov if (attrs) 313621a1672SDmitry Torokhov for (i = 0; attr_name(attrs[i]); i++) 314621a1672SDmitry Torokhov device_remove_file(dev, &attrs[i]); 315621a1672SDmitry Torokhov } 316621a1672SDmitry Torokhov 317621a1672SDmitry Torokhov static int device_add_groups(struct device *dev, 318621a1672SDmitry Torokhov struct attribute_group **groups) 319621a1672SDmitry Torokhov { 320621a1672SDmitry Torokhov int error = 0; 321621a1672SDmitry Torokhov int i; 322621a1672SDmitry Torokhov 323621a1672SDmitry Torokhov if (groups) { 324621a1672SDmitry Torokhov for (i = 0; groups[i]; i++) { 325621a1672SDmitry Torokhov error = sysfs_create_group(&dev->kobj, groups[i]); 326621a1672SDmitry Torokhov if (error) { 327621a1672SDmitry Torokhov while (--i >= 0) 328621a1672SDmitry Torokhov sysfs_remove_group(&dev->kobj, groups[i]); 329621a1672SDmitry Torokhov break; 330de0ff00dSGreg Kroah-Hartman } 331de0ff00dSGreg Kroah-Hartman } 332de0ff00dSGreg Kroah-Hartman } 333621a1672SDmitry Torokhov return error; 334621a1672SDmitry Torokhov } 335621a1672SDmitry Torokhov 336621a1672SDmitry Torokhov static void device_remove_groups(struct device *dev, 337621a1672SDmitry Torokhov struct attribute_group **groups) 338621a1672SDmitry Torokhov { 339621a1672SDmitry Torokhov int i; 340621a1672SDmitry Torokhov 341621a1672SDmitry Torokhov if (groups) 342621a1672SDmitry Torokhov for (i = 0; groups[i]; i++) 343621a1672SDmitry Torokhov sysfs_remove_group(&dev->kobj, groups[i]); 344621a1672SDmitry Torokhov } 345de0ff00dSGreg Kroah-Hartman 3462620efefSGreg Kroah-Hartman static int device_add_attrs(struct device *dev) 3472620efefSGreg Kroah-Hartman { 3482620efefSGreg Kroah-Hartman struct class *class = dev->class; 349f9f852dfSKay Sievers struct device_type *type = dev->type; 350621a1672SDmitry Torokhov int error; 3512620efefSGreg Kroah-Hartman 352621a1672SDmitry Torokhov if (class) { 353621a1672SDmitry Torokhov error = device_add_attributes(dev, class->dev_attrs); 3542620efefSGreg Kroah-Hartman if (error) 355621a1672SDmitry Torokhov return error; 356f9f852dfSKay Sievers } 357f9f852dfSKay Sievers 358621a1672SDmitry Torokhov if (type) { 359621a1672SDmitry Torokhov error = device_add_groups(dev, type->groups); 360f9f852dfSKay Sievers if (error) 361621a1672SDmitry Torokhov goto err_remove_class_attrs; 362f9f852dfSKay Sievers } 363621a1672SDmitry Torokhov 364621a1672SDmitry Torokhov error = device_add_groups(dev, dev->groups); 365f9f852dfSKay Sievers if (error) 366621a1672SDmitry Torokhov goto err_remove_type_groups; 367621a1672SDmitry Torokhov 368621a1672SDmitry Torokhov return 0; 369621a1672SDmitry Torokhov 370621a1672SDmitry Torokhov err_remove_type_groups: 371621a1672SDmitry Torokhov if (type) 372621a1672SDmitry Torokhov device_remove_groups(dev, type->groups); 373621a1672SDmitry Torokhov err_remove_class_attrs: 374621a1672SDmitry Torokhov if (class) 375621a1672SDmitry Torokhov device_remove_attributes(dev, class->dev_attrs); 376f9f852dfSKay Sievers 3772620efefSGreg Kroah-Hartman return error; 3782620efefSGreg Kroah-Hartman } 3792620efefSGreg Kroah-Hartman 3802620efefSGreg Kroah-Hartman static void device_remove_attrs(struct device *dev) 3812620efefSGreg Kroah-Hartman { 3822620efefSGreg Kroah-Hartman struct class *class = dev->class; 383f9f852dfSKay Sievers struct device_type *type = dev->type; 3842620efefSGreg Kroah-Hartman 385621a1672SDmitry Torokhov device_remove_groups(dev, dev->groups); 386f9f852dfSKay Sievers 387621a1672SDmitry Torokhov if (type) 388621a1672SDmitry Torokhov device_remove_groups(dev, type->groups); 389621a1672SDmitry Torokhov 390621a1672SDmitry Torokhov if (class) 391621a1672SDmitry Torokhov device_remove_attributes(dev, class->dev_attrs); 3922620efefSGreg Kroah-Hartman } 3932620efefSGreg Kroah-Hartman 3942620efefSGreg Kroah-Hartman 39523681e47SGreg Kroah-Hartman static ssize_t show_dev(struct device *dev, struct device_attribute *attr, 39623681e47SGreg Kroah-Hartman char *buf) 39723681e47SGreg Kroah-Hartman { 39823681e47SGreg Kroah-Hartman return print_dev_t(buf, dev->devt); 39923681e47SGreg Kroah-Hartman } 40023681e47SGreg Kroah-Hartman 401ad6a1e1cSTejun Heo static struct device_attribute devt_attr = 402ad6a1e1cSTejun Heo __ATTR(dev, S_IRUGO, show_dev, NULL); 403ad6a1e1cSTejun Heo 4040863afb3SMartin Waitz /* 4050863afb3SMartin Waitz * devices_subsys - structure to be registered with kobject core. 4061da177e4SLinus Torvalds */ 4071da177e4SLinus Torvalds 4083514facaSGreg Kroah-Hartman decl_subsys(devices, &device_uevent_ops); 4091da177e4SLinus Torvalds 4101da177e4SLinus Torvalds 4111da177e4SLinus Torvalds /** 4121da177e4SLinus Torvalds * device_create_file - create sysfs attribute file for device. 4131da177e4SLinus Torvalds * @dev: device. 4141da177e4SLinus Torvalds * @attr: device attribute descriptor. 4151da177e4SLinus Torvalds */ 4161da177e4SLinus Torvalds 4171da177e4SLinus Torvalds int device_create_file(struct device * dev, struct device_attribute * attr) 4181da177e4SLinus Torvalds { 4191da177e4SLinus Torvalds int error = 0; 4201da177e4SLinus Torvalds if (get_device(dev)) { 4211da177e4SLinus Torvalds error = sysfs_create_file(&dev->kobj, &attr->attr); 4221da177e4SLinus Torvalds put_device(dev); 4231da177e4SLinus Torvalds } 4241da177e4SLinus Torvalds return error; 4251da177e4SLinus Torvalds } 4261da177e4SLinus Torvalds 4271da177e4SLinus Torvalds /** 4281da177e4SLinus Torvalds * device_remove_file - remove sysfs attribute file. 4291da177e4SLinus Torvalds * @dev: device. 4301da177e4SLinus Torvalds * @attr: device attribute descriptor. 4311da177e4SLinus Torvalds */ 4321da177e4SLinus Torvalds 4331da177e4SLinus Torvalds void device_remove_file(struct device * dev, struct device_attribute * attr) 4341da177e4SLinus Torvalds { 4351da177e4SLinus Torvalds if (get_device(dev)) { 4361da177e4SLinus Torvalds sysfs_remove_file(&dev->kobj, &attr->attr); 4371da177e4SLinus Torvalds put_device(dev); 4381da177e4SLinus Torvalds } 4391da177e4SLinus Torvalds } 4401da177e4SLinus Torvalds 4412589f188SGreg Kroah-Hartman /** 4422589f188SGreg Kroah-Hartman * device_create_bin_file - create sysfs binary attribute file for device. 4432589f188SGreg Kroah-Hartman * @dev: device. 4442589f188SGreg Kroah-Hartman * @attr: device binary attribute descriptor. 4452589f188SGreg Kroah-Hartman */ 4462589f188SGreg Kroah-Hartman int device_create_bin_file(struct device *dev, struct bin_attribute *attr) 4472589f188SGreg Kroah-Hartman { 4482589f188SGreg Kroah-Hartman int error = -EINVAL; 4492589f188SGreg Kroah-Hartman if (dev) 4502589f188SGreg Kroah-Hartman error = sysfs_create_bin_file(&dev->kobj, attr); 4512589f188SGreg Kroah-Hartman return error; 4522589f188SGreg Kroah-Hartman } 4532589f188SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(device_create_bin_file); 4542589f188SGreg Kroah-Hartman 4552589f188SGreg Kroah-Hartman /** 4562589f188SGreg Kroah-Hartman * device_remove_bin_file - remove sysfs binary attribute file 4572589f188SGreg Kroah-Hartman * @dev: device. 4582589f188SGreg Kroah-Hartman * @attr: device binary attribute descriptor. 4592589f188SGreg Kroah-Hartman */ 4602589f188SGreg Kroah-Hartman void device_remove_bin_file(struct device *dev, struct bin_attribute *attr) 4612589f188SGreg Kroah-Hartman { 4622589f188SGreg Kroah-Hartman if (dev) 4632589f188SGreg Kroah-Hartman sysfs_remove_bin_file(&dev->kobj, attr); 4642589f188SGreg Kroah-Hartman } 4652589f188SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(device_remove_bin_file); 4662589f188SGreg Kroah-Hartman 467d9a9cdfbSAlan Stern /** 468523ded71SAlan Stern * device_schedule_callback_owner - helper to schedule a callback for a device 469d9a9cdfbSAlan Stern * @dev: device. 470d9a9cdfbSAlan Stern * @func: callback function to invoke later. 471523ded71SAlan Stern * @owner: module owning the callback routine 472d9a9cdfbSAlan Stern * 473d9a9cdfbSAlan Stern * Attribute methods must not unregister themselves or their parent device 474d9a9cdfbSAlan Stern * (which would amount to the same thing). Attempts to do so will deadlock, 475d9a9cdfbSAlan Stern * since unregistration is mutually exclusive with driver callbacks. 476d9a9cdfbSAlan Stern * 477d9a9cdfbSAlan Stern * Instead methods can call this routine, which will attempt to allocate 478d9a9cdfbSAlan Stern * and schedule a workqueue request to call back @func with @dev as its 479d9a9cdfbSAlan Stern * argument in the workqueue's process context. @dev will be pinned until 480d9a9cdfbSAlan Stern * @func returns. 481d9a9cdfbSAlan Stern * 482523ded71SAlan Stern * This routine is usually called via the inline device_schedule_callback(), 483523ded71SAlan Stern * which automatically sets @owner to THIS_MODULE. 484523ded71SAlan Stern * 485d9a9cdfbSAlan Stern * Returns 0 if the request was submitted, -ENOMEM if storage could not 486523ded71SAlan Stern * be allocated, -ENODEV if a reference to @owner isn't available. 487d9a9cdfbSAlan Stern * 488d9a9cdfbSAlan Stern * NOTE: This routine won't work if CONFIG_SYSFS isn't set! It uses an 489d9a9cdfbSAlan Stern * underlying sysfs routine (since it is intended for use by attribute 490d9a9cdfbSAlan Stern * methods), and if sysfs isn't available you'll get nothing but -ENOSYS. 491d9a9cdfbSAlan Stern */ 492523ded71SAlan Stern int device_schedule_callback_owner(struct device *dev, 493523ded71SAlan Stern void (*func)(struct device *), struct module *owner) 494d9a9cdfbSAlan Stern { 495d9a9cdfbSAlan Stern return sysfs_schedule_callback(&dev->kobj, 496523ded71SAlan Stern (void (*)(void *)) func, dev, owner); 497d9a9cdfbSAlan Stern } 498523ded71SAlan Stern EXPORT_SYMBOL_GPL(device_schedule_callback_owner); 499d9a9cdfbSAlan Stern 50034bb61f9SJames Bottomley static void klist_children_get(struct klist_node *n) 50134bb61f9SJames Bottomley { 50234bb61f9SJames Bottomley struct device *dev = container_of(n, struct device, knode_parent); 50334bb61f9SJames Bottomley 50434bb61f9SJames Bottomley get_device(dev); 50534bb61f9SJames Bottomley } 50634bb61f9SJames Bottomley 50734bb61f9SJames Bottomley static void klist_children_put(struct klist_node *n) 50834bb61f9SJames Bottomley { 50934bb61f9SJames Bottomley struct device *dev = container_of(n, struct device, knode_parent); 51034bb61f9SJames Bottomley 51134bb61f9SJames Bottomley put_device(dev); 51234bb61f9SJames Bottomley } 51334bb61f9SJames Bottomley 5141da177e4SLinus Torvalds 5151da177e4SLinus Torvalds /** 5161da177e4SLinus Torvalds * device_initialize - init device structure. 5171da177e4SLinus Torvalds * @dev: device. 5181da177e4SLinus Torvalds * 5191da177e4SLinus Torvalds * This prepares the device for use by other layers, 5201da177e4SLinus Torvalds * including adding it to the device hierarchy. 5211da177e4SLinus Torvalds * It is the first half of device_register(), if called by 5221da177e4SLinus Torvalds * that, though it can also be called separately, so one 5231da177e4SLinus Torvalds * may use @dev's fields (e.g. the refcount). 5241da177e4SLinus Torvalds */ 5251da177e4SLinus Torvalds 5261da177e4SLinus Torvalds void device_initialize(struct device *dev) 5271da177e4SLinus Torvalds { 5283514facaSGreg Kroah-Hartman dev->kobj.kset = &devices_subsys; 5293514facaSGreg Kroah-Hartman dev->kobj.ktype = &device_ktype; 5301da177e4SLinus Torvalds kobject_init(&dev->kobj); 53134bb61f9SJames Bottomley klist_init(&dev->klist_children, klist_children_get, 53234bb61f9SJames Bottomley klist_children_put); 5331da177e4SLinus Torvalds INIT_LIST_HEAD(&dev->dma_pools); 53423681e47SGreg Kroah-Hartman INIT_LIST_HEAD(&dev->node); 535af70316aSmochel@digitalimplant.org init_MUTEX(&dev->sem); 5369ac7849eSTejun Heo spin_lock_init(&dev->devres_lock); 5379ac7849eSTejun Heo INIT_LIST_HEAD(&dev->devres_head); 5380ac85241SDavid Brownell device_init_wakeup(dev, 0); 53987348136SChristoph Hellwig set_dev_node(dev, -1); 5401da177e4SLinus Torvalds } 5411da177e4SLinus Torvalds 54240fa5422SGreg Kroah-Hartman #ifdef CONFIG_SYSFS_DEPRECATED 543c744aeaeSCornelia Huck static struct kobject * get_device_parent(struct device *dev, 544c744aeaeSCornelia Huck struct device *parent) 54540fa5422SGreg Kroah-Hartman { 5463eb215deSDmitry Torokhov /* 5473eb215deSDmitry Torokhov * Set the parent to the class, not the parent device 5483eb215deSDmitry Torokhov * for topmost devices in class hierarchy. 5493eb215deSDmitry Torokhov * This keeps sysfs from having a symlink to make old 5503eb215deSDmitry Torokhov * udevs happy 5513eb215deSDmitry Torokhov */ 5523eb215deSDmitry Torokhov if (dev->class && (!parent || parent->class != dev->class)) 553823bccfcSGreg Kroah-Hartman return &dev->class->subsys.kobj; 55440fa5422SGreg Kroah-Hartman else if (parent) 555c744aeaeSCornelia Huck return &parent->kobj; 55640fa5422SGreg Kroah-Hartman 557c744aeaeSCornelia Huck return NULL; 55840fa5422SGreg Kroah-Hartman } 55940fa5422SGreg Kroah-Hartman #else 560c744aeaeSCornelia Huck static struct kobject *virtual_device_parent(struct device *dev) 561f0ee61a6SGreg Kroah-Hartman { 562f0ee61a6SGreg Kroah-Hartman static struct kobject *virtual_dir = NULL; 563f0ee61a6SGreg Kroah-Hartman 564f0ee61a6SGreg Kroah-Hartman if (!virtual_dir) 5654ff6abffSGreg Kroah-Hartman virtual_dir = kobject_create_and_add("virtual", 5664ff6abffSGreg Kroah-Hartman &devices_subsys.kobj); 567f0ee61a6SGreg Kroah-Hartman 56886406245SKay Sievers return virtual_dir; 569f0ee61a6SGreg Kroah-Hartman } 570f0ee61a6SGreg Kroah-Hartman 571c744aeaeSCornelia Huck static struct kobject * get_device_parent(struct device *dev, 572c744aeaeSCornelia Huck struct device *parent) 57340fa5422SGreg Kroah-Hartman { 57486406245SKay Sievers if (dev->class) { 57586406245SKay Sievers struct kobject *kobj = NULL; 57686406245SKay Sievers struct kobject *parent_kobj; 57786406245SKay Sievers struct kobject *k; 57886406245SKay Sievers 57986406245SKay Sievers /* 58086406245SKay Sievers * If we have no parent, we live in "virtual". 58186406245SKay Sievers * Class-devices with a bus-device as parent, live 58286406245SKay Sievers * in a class-directory to prevent namespace collisions. 58386406245SKay Sievers */ 58486406245SKay Sievers if (parent == NULL) 58586406245SKay Sievers parent_kobj = virtual_device_parent(dev); 58686406245SKay Sievers else if (parent->class) 58786406245SKay Sievers return &parent->kobj; 58886406245SKay Sievers else 58986406245SKay Sievers parent_kobj = &parent->kobj; 59086406245SKay Sievers 59186406245SKay Sievers /* find our class-directory at the parent and reference it */ 59286406245SKay Sievers spin_lock(&dev->class->class_dirs.list_lock); 59386406245SKay Sievers list_for_each_entry(k, &dev->class->class_dirs.list, entry) 59486406245SKay Sievers if (k->parent == parent_kobj) { 59586406245SKay Sievers kobj = kobject_get(k); 59686406245SKay Sievers break; 59786406245SKay Sievers } 59886406245SKay Sievers spin_unlock(&dev->class->class_dirs.list_lock); 59986406245SKay Sievers if (kobj) 60086406245SKay Sievers return kobj; 60186406245SKay Sievers 60286406245SKay Sievers /* or create a new class-directory at the parent device */ 60386406245SKay Sievers return kobject_kset_add_dir(&dev->class->class_dirs, 60486406245SKay Sievers parent_kobj, dev->class->name); 60586406245SKay Sievers } 60686406245SKay Sievers 60786406245SKay Sievers if (parent) 608c744aeaeSCornelia Huck return &parent->kobj; 609c744aeaeSCornelia Huck return NULL; 610c744aeaeSCornelia Huck } 611c744aeaeSCornelia Huck #endif 61286406245SKay Sievers 613c744aeaeSCornelia Huck static int setup_parent(struct device *dev, struct device *parent) 614c744aeaeSCornelia Huck { 615c744aeaeSCornelia Huck struct kobject *kobj; 616c744aeaeSCornelia Huck kobj = get_device_parent(dev, parent); 617c744aeaeSCornelia Huck if (IS_ERR(kobj)) 618c744aeaeSCornelia Huck return PTR_ERR(kobj); 619c744aeaeSCornelia Huck if (kobj) 620c744aeaeSCornelia Huck dev->kobj.parent = kobj; 62140fa5422SGreg Kroah-Hartman return 0; 62240fa5422SGreg Kroah-Hartman } 62340fa5422SGreg Kroah-Hartman 6242ee97cafSCornelia Huck static int device_add_class_symlinks(struct device *dev) 6252ee97cafSCornelia Huck { 6262ee97cafSCornelia Huck int error; 6272ee97cafSCornelia Huck 6282ee97cafSCornelia Huck if (!dev->class) 6292ee97cafSCornelia Huck return 0; 6302ee97cafSCornelia Huck error = sysfs_create_link(&dev->kobj, &dev->class->subsys.kobj, 6312ee97cafSCornelia Huck "subsystem"); 6322ee97cafSCornelia Huck if (error) 6332ee97cafSCornelia Huck goto out; 6342ee97cafSCornelia Huck /* 6352ee97cafSCornelia Huck * If this is not a "fake" compatible device, then create the 6362ee97cafSCornelia Huck * symlink from the class to the device. 6372ee97cafSCornelia Huck */ 6382ee97cafSCornelia Huck if (dev->kobj.parent != &dev->class->subsys.kobj) { 6392ee97cafSCornelia Huck error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj, 6402ee97cafSCornelia Huck dev->bus_id); 6412ee97cafSCornelia Huck if (error) 6422ee97cafSCornelia Huck goto out_subsys; 6432ee97cafSCornelia Huck } 64427907689SCornelia Huck if (dev->parent) { 6454f01a757SDmitry Torokhov #ifdef CONFIG_SYSFS_DEPRECATED 6464f01a757SDmitry Torokhov { 6474f01a757SDmitry Torokhov struct device *parent = dev->parent; 6484f01a757SDmitry Torokhov char *class_name; 6494f01a757SDmitry Torokhov 6504f01a757SDmitry Torokhov /* 6514f01a757SDmitry Torokhov * In old sysfs stacked class devices had 'device' 6524f01a757SDmitry Torokhov * link pointing to real device instead of parent 6534f01a757SDmitry Torokhov */ 6544f01a757SDmitry Torokhov while (parent->class && !parent->bus && parent->parent) 6554f01a757SDmitry Torokhov parent = parent->parent; 6564f01a757SDmitry Torokhov 6574f01a757SDmitry Torokhov error = sysfs_create_link(&dev->kobj, 6584f01a757SDmitry Torokhov &parent->kobj, 6592ee97cafSCornelia Huck "device"); 6602ee97cafSCornelia Huck if (error) 6612ee97cafSCornelia Huck goto out_busid; 6624f01a757SDmitry Torokhov 6634f01a757SDmitry Torokhov class_name = make_class_name(dev->class->name, 6642ee97cafSCornelia Huck &dev->kobj); 6652ee97cafSCornelia Huck if (class_name) 6662ee97cafSCornelia Huck error = sysfs_create_link(&dev->parent->kobj, 6672ee97cafSCornelia Huck &dev->kobj, class_name); 6682ee97cafSCornelia Huck kfree(class_name); 6692ee97cafSCornelia Huck if (error) 6702ee97cafSCornelia Huck goto out_device; 6712ee97cafSCornelia Huck } 6724f01a757SDmitry Torokhov #else 6734f01a757SDmitry Torokhov error = sysfs_create_link(&dev->kobj, &dev->parent->kobj, 6744f01a757SDmitry Torokhov "device"); 6754f01a757SDmitry Torokhov if (error) 6764f01a757SDmitry Torokhov goto out_busid; 6772ee97cafSCornelia Huck #endif 6782ee97cafSCornelia Huck } 6792ee97cafSCornelia Huck return 0; 6802ee97cafSCornelia Huck 6812ee97cafSCornelia Huck #ifdef CONFIG_SYSFS_DEPRECATED 6822ee97cafSCornelia Huck out_device: 6832ee97cafSCornelia Huck if (dev->parent) 6842ee97cafSCornelia Huck sysfs_remove_link(&dev->kobj, "device"); 6852ee97cafSCornelia Huck #endif 6862ee97cafSCornelia Huck out_busid: 6872ee97cafSCornelia Huck if (dev->kobj.parent != &dev->class->subsys.kobj) 6882ee97cafSCornelia Huck sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id); 6892ee97cafSCornelia Huck out_subsys: 6902ee97cafSCornelia Huck sysfs_remove_link(&dev->kobj, "subsystem"); 6912ee97cafSCornelia Huck out: 6922ee97cafSCornelia Huck return error; 6932ee97cafSCornelia Huck } 6942ee97cafSCornelia Huck 6952ee97cafSCornelia Huck static void device_remove_class_symlinks(struct device *dev) 6962ee97cafSCornelia Huck { 6972ee97cafSCornelia Huck if (!dev->class) 6982ee97cafSCornelia Huck return; 6992ee97cafSCornelia Huck if (dev->parent) { 7002ee97cafSCornelia Huck #ifdef CONFIG_SYSFS_DEPRECATED 7012ee97cafSCornelia Huck char *class_name; 7022ee97cafSCornelia Huck 7032ee97cafSCornelia Huck class_name = make_class_name(dev->class->name, &dev->kobj); 7042ee97cafSCornelia Huck if (class_name) { 7052ee97cafSCornelia Huck sysfs_remove_link(&dev->parent->kobj, class_name); 7062ee97cafSCornelia Huck kfree(class_name); 7072ee97cafSCornelia Huck } 7082ee97cafSCornelia Huck #endif 7092ee97cafSCornelia Huck sysfs_remove_link(&dev->kobj, "device"); 7102ee97cafSCornelia Huck } 7112ee97cafSCornelia Huck if (dev->kobj.parent != &dev->class->subsys.kobj) 7122ee97cafSCornelia Huck sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id); 7132ee97cafSCornelia Huck sysfs_remove_link(&dev->kobj, "subsystem"); 7142ee97cafSCornelia Huck } 7152ee97cafSCornelia Huck 7161da177e4SLinus Torvalds /** 7171da177e4SLinus Torvalds * device_add - add device to device hierarchy. 7181da177e4SLinus Torvalds * @dev: device. 7191da177e4SLinus Torvalds * 7201da177e4SLinus Torvalds * This is part 2 of device_register(), though may be called 7211da177e4SLinus Torvalds * separately _iff_ device_initialize() has been called separately. 7221da177e4SLinus Torvalds * 7231da177e4SLinus Torvalds * This adds it to the kobject hierarchy via kobject_add(), adds it 7241da177e4SLinus Torvalds * to the global and sibling lists for the device, then 7251da177e4SLinus Torvalds * adds it to the other relevant subsystems of the driver model. 7261da177e4SLinus Torvalds */ 7271da177e4SLinus Torvalds int device_add(struct device *dev) 7281da177e4SLinus Torvalds { 7291da177e4SLinus Torvalds struct device *parent = NULL; 730c47ed219SGreg Kroah-Hartman struct class_interface *class_intf; 731775b64d2SRafael J. Wysocki int error; 732775b64d2SRafael J. Wysocki 733775b64d2SRafael J. Wysocki error = pm_sleep_lock(); 734775b64d2SRafael J. Wysocki if (error) { 735775b64d2SRafael J. Wysocki dev_warn(dev, "Suspicious %s during suspend\n", __FUNCTION__); 736775b64d2SRafael J. Wysocki dump_stack(); 737775b64d2SRafael J. Wysocki return error; 738775b64d2SRafael J. Wysocki } 7391da177e4SLinus Torvalds 7401da177e4SLinus Torvalds dev = get_device(dev); 741775b64d2SRafael J. Wysocki if (!dev || !strlen(dev->bus_id)) { 742775b64d2SRafael J. Wysocki error = -EINVAL; 7431da177e4SLinus Torvalds goto Error; 744775b64d2SRafael J. Wysocki } 7451da177e4SLinus Torvalds 74640fa5422SGreg Kroah-Hartman pr_debug("DEV: registering device: ID = '%s'\n", dev->bus_id); 747c205ef48SGreg Kroah-Hartman 7481da177e4SLinus Torvalds parent = get_device(dev->parent); 74940fa5422SGreg Kroah-Hartman error = setup_parent(dev, parent); 75040fa5422SGreg Kroah-Hartman if (error) 75140fa5422SGreg Kroah-Hartman goto Error; 7521da177e4SLinus Torvalds 7531da177e4SLinus Torvalds /* first, register with generic layer. */ 7541da177e4SLinus Torvalds kobject_set_name(&dev->kobj, "%s", dev->bus_id); 75540fa5422SGreg Kroah-Hartman error = kobject_add(&dev->kobj); 75640fa5422SGreg Kroah-Hartman if (error) 7571da177e4SLinus Torvalds goto Error; 758a7fd6706SKay Sievers 75937022644SBrian Walsh /* notify platform of device entry */ 76037022644SBrian Walsh if (platform_notify) 76137022644SBrian Walsh platform_notify(dev); 76237022644SBrian Walsh 763116af378SBenjamin Herrenschmidt /* notify clients of device entry (new way) */ 764116af378SBenjamin Herrenschmidt if (dev->bus) 765116af378SBenjamin Herrenschmidt blocking_notifier_call_chain(&dev->bus->bus_notifier, 766116af378SBenjamin Herrenschmidt BUS_NOTIFY_ADD_DEVICE, dev); 767116af378SBenjamin Herrenschmidt 768ad6a1e1cSTejun Heo error = device_create_file(dev, &uevent_attr); 769a306eea4SCornelia Huck if (error) 770a306eea4SCornelia Huck goto attrError; 771a7fd6706SKay Sievers 77223681e47SGreg Kroah-Hartman if (MAJOR(dev->devt)) { 773ad6a1e1cSTejun Heo error = device_create_file(dev, &devt_attr); 774ad6a1e1cSTejun Heo if (error) 775a306eea4SCornelia Huck goto ueventattrError; 77623681e47SGreg Kroah-Hartman } 77723681e47SGreg Kroah-Hartman 7782ee97cafSCornelia Huck error = device_add_class_symlinks(dev); 7792ee97cafSCornelia Huck if (error) 7802ee97cafSCornelia Huck goto SymlinkError; 781dc0afa83SCornelia Huck error = device_add_attrs(dev); 782dc0afa83SCornelia Huck if (error) 7832620efefSGreg Kroah-Hartman goto AttrsError; 784dec13c15SDaniel Drake error = dpm_sysfs_add(dev); 785dc0afa83SCornelia Huck if (error) 7861da177e4SLinus Torvalds goto PMError; 787dec13c15SDaniel Drake device_pm_add(dev); 788dc0afa83SCornelia Huck error = bus_add_device(dev); 789dc0afa83SCornelia Huck if (error) 7901da177e4SLinus Torvalds goto BusError; 79153877d06SKay Sievers kobject_uevent(&dev->kobj, KOBJ_ADD); 792c6a46696SCornelia Huck bus_attach_device(dev); 7931da177e4SLinus Torvalds if (parent) 794d856f1e3SJames Bottomley klist_add_tail(&dev->knode_parent, &parent->klist_children); 7951da177e4SLinus Torvalds 7965d9fd169SGreg Kroah-Hartman if (dev->class) { 7975d9fd169SGreg Kroah-Hartman down(&dev->class->sem); 798c47ed219SGreg Kroah-Hartman /* tie the class to the device */ 7995d9fd169SGreg Kroah-Hartman list_add_tail(&dev->node, &dev->class->devices); 800c47ed219SGreg Kroah-Hartman 801c47ed219SGreg Kroah-Hartman /* notify any interfaces that the device is here */ 802c47ed219SGreg Kroah-Hartman list_for_each_entry(class_intf, &dev->class->interfaces, node) 803c47ed219SGreg Kroah-Hartman if (class_intf->add_dev) 804c47ed219SGreg Kroah-Hartman class_intf->add_dev(dev, class_intf); 8055d9fd169SGreg Kroah-Hartman up(&dev->class->sem); 8065d9fd169SGreg Kroah-Hartman } 8071da177e4SLinus Torvalds Done: 8081da177e4SLinus Torvalds put_device(dev); 809775b64d2SRafael J. Wysocki pm_sleep_unlock(); 8101da177e4SLinus Torvalds return error; 8111da177e4SLinus Torvalds BusError: 8121da177e4SLinus Torvalds device_pm_remove(dev); 813dec13c15SDaniel Drake dpm_sysfs_remove(dev); 8141da177e4SLinus Torvalds PMError: 815116af378SBenjamin Herrenschmidt if (dev->bus) 816116af378SBenjamin Herrenschmidt blocking_notifier_call_chain(&dev->bus->bus_notifier, 817116af378SBenjamin Herrenschmidt BUS_NOTIFY_DEL_DEVICE, dev); 8182620efefSGreg Kroah-Hartman device_remove_attrs(dev); 8192620efefSGreg Kroah-Hartman AttrsError: 8202ee97cafSCornelia Huck device_remove_class_symlinks(dev); 8212ee97cafSCornelia Huck SymlinkError: 822ad6a1e1cSTejun Heo if (MAJOR(dev->devt)) 823ad6a1e1cSTejun Heo device_remove_file(dev, &devt_attr); 82482f0cf9bSJames Simmons 82582f0cf9bSJames Simmons if (dev->class) { 82682f0cf9bSJames Simmons sysfs_remove_link(&dev->kobj, "subsystem"); 82782f0cf9bSJames Simmons /* If this is not a "fake" compatible device, remove the 82882f0cf9bSJames Simmons * symlink from the class to the device. */ 829823bccfcSGreg Kroah-Hartman if (dev->kobj.parent != &dev->class->subsys.kobj) 830823bccfcSGreg Kroah-Hartman sysfs_remove_link(&dev->class->subsys.kobj, 83182f0cf9bSJames Simmons dev->bus_id); 83282f0cf9bSJames Simmons if (parent) { 833f7f3461dSGreg Kroah-Hartman #ifdef CONFIG_SYSFS_DEPRECATED 83482f0cf9bSJames Simmons char *class_name = make_class_name(dev->class->name, 83582f0cf9bSJames Simmons &dev->kobj); 83682f0cf9bSJames Simmons if (class_name) 83782f0cf9bSJames Simmons sysfs_remove_link(&dev->parent->kobj, 83882f0cf9bSJames Simmons class_name); 83982f0cf9bSJames Simmons kfree(class_name); 840f7f3461dSGreg Kroah-Hartman #endif 84182f0cf9bSJames Simmons sysfs_remove_link(&dev->kobj, "device"); 84282f0cf9bSJames Simmons } 84323681e47SGreg Kroah-Hartman } 844a306eea4SCornelia Huck ueventattrError: 845ad6a1e1cSTejun Heo device_remove_file(dev, &uevent_attr); 84623681e47SGreg Kroah-Hartman attrError: 847312c004dSKay Sievers kobject_uevent(&dev->kobj, KOBJ_REMOVE); 8481da177e4SLinus Torvalds kobject_del(&dev->kobj); 8491da177e4SLinus Torvalds Error: 8501da177e4SLinus Torvalds if (parent) 8511da177e4SLinus Torvalds put_device(parent); 8521da177e4SLinus Torvalds goto Done; 8531da177e4SLinus Torvalds } 8541da177e4SLinus Torvalds 8551da177e4SLinus Torvalds 8561da177e4SLinus Torvalds /** 8571da177e4SLinus Torvalds * device_register - register a device with the system. 8581da177e4SLinus Torvalds * @dev: pointer to the device structure 8591da177e4SLinus Torvalds * 8601da177e4SLinus Torvalds * This happens in two clean steps - initialize the device 8611da177e4SLinus Torvalds * and add it to the system. The two steps can be called 8621da177e4SLinus Torvalds * separately, but this is the easiest and most common. 8631da177e4SLinus Torvalds * I.e. you should only call the two helpers separately if 8641da177e4SLinus Torvalds * have a clearly defined need to use and refcount the device 8651da177e4SLinus Torvalds * before it is added to the hierarchy. 8661da177e4SLinus Torvalds */ 8671da177e4SLinus Torvalds 8681da177e4SLinus Torvalds int device_register(struct device *dev) 8691da177e4SLinus Torvalds { 8701da177e4SLinus Torvalds device_initialize(dev); 8711da177e4SLinus Torvalds return device_add(dev); 8721da177e4SLinus Torvalds } 8731da177e4SLinus Torvalds 8741da177e4SLinus Torvalds 8751da177e4SLinus Torvalds /** 8761da177e4SLinus Torvalds * get_device - increment reference count for device. 8771da177e4SLinus Torvalds * @dev: device. 8781da177e4SLinus Torvalds * 8791da177e4SLinus Torvalds * This simply forwards the call to kobject_get(), though 8801da177e4SLinus Torvalds * we do take care to provide for the case that we get a NULL 8811da177e4SLinus Torvalds * pointer passed in. 8821da177e4SLinus Torvalds */ 8831da177e4SLinus Torvalds 8841da177e4SLinus Torvalds struct device * get_device(struct device * dev) 8851da177e4SLinus Torvalds { 8861da177e4SLinus Torvalds return dev ? to_dev(kobject_get(&dev->kobj)) : NULL; 8871da177e4SLinus Torvalds } 8881da177e4SLinus Torvalds 8891da177e4SLinus Torvalds 8901da177e4SLinus Torvalds /** 8911da177e4SLinus Torvalds * put_device - decrement reference count. 8921da177e4SLinus Torvalds * @dev: device in question. 8931da177e4SLinus Torvalds */ 8941da177e4SLinus Torvalds void put_device(struct device * dev) 8951da177e4SLinus Torvalds { 8961da177e4SLinus Torvalds if (dev) 8971da177e4SLinus Torvalds kobject_put(&dev->kobj); 8981da177e4SLinus Torvalds } 8991da177e4SLinus Torvalds 9001da177e4SLinus Torvalds 9011da177e4SLinus Torvalds /** 9021da177e4SLinus Torvalds * device_del - delete device from system. 9031da177e4SLinus Torvalds * @dev: device. 9041da177e4SLinus Torvalds * 9051da177e4SLinus Torvalds * This is the first part of the device unregistration 9061da177e4SLinus Torvalds * sequence. This removes the device from the lists we control 9071da177e4SLinus Torvalds * from here, has it removed from the other driver model 9081da177e4SLinus Torvalds * subsystems it was added to in device_add(), and removes it 9091da177e4SLinus Torvalds * from the kobject hierarchy. 9101da177e4SLinus Torvalds * 9111da177e4SLinus Torvalds * NOTE: this should be called manually _iff_ device_add() was 9121da177e4SLinus Torvalds * also called manually. 9131da177e4SLinus Torvalds */ 9141da177e4SLinus Torvalds 9151da177e4SLinus Torvalds void device_del(struct device * dev) 9161da177e4SLinus Torvalds { 9171da177e4SLinus Torvalds struct device * parent = dev->parent; 918c47ed219SGreg Kroah-Hartman struct class_interface *class_intf; 9191da177e4SLinus Torvalds 920775b64d2SRafael J. Wysocki device_pm_remove(dev); 9211da177e4SLinus Torvalds if (parent) 922d62c0f9fSPatrick Mochel klist_del(&dev->knode_parent); 923ad6a1e1cSTejun Heo if (MAJOR(dev->devt)) 924ad6a1e1cSTejun Heo device_remove_file(dev, &devt_attr); 925b9d9c82bSKay Sievers if (dev->class) { 926b9d9c82bSKay Sievers sysfs_remove_link(&dev->kobj, "subsystem"); 92740fa5422SGreg Kroah-Hartman /* If this is not a "fake" compatible device, remove the 92840fa5422SGreg Kroah-Hartman * symlink from the class to the device. */ 929823bccfcSGreg Kroah-Hartman if (dev->kobj.parent != &dev->class->subsys.kobj) 930823bccfcSGreg Kroah-Hartman sysfs_remove_link(&dev->class->subsys.kobj, 93140fa5422SGreg Kroah-Hartman dev->bus_id); 93264bb5d2cSGreg Kroah-Hartman if (parent) { 933f7f3461dSGreg Kroah-Hartman #ifdef CONFIG_SYSFS_DEPRECATED 93499ef3ef8SKay Sievers char *class_name = make_class_name(dev->class->name, 93599ef3ef8SKay Sievers &dev->kobj); 936cb360bbfSCornelia Huck if (class_name) 937cb360bbfSCornelia Huck sysfs_remove_link(&dev->parent->kobj, 938cb360bbfSCornelia Huck class_name); 939e9a7d305SGreg Kroah-Hartman kfree(class_name); 940f7f3461dSGreg Kroah-Hartman #endif 94199ef3ef8SKay Sievers sysfs_remove_link(&dev->kobj, "device"); 94299ef3ef8SKay Sievers } 94399ef3ef8SKay Sievers 9445d9fd169SGreg Kroah-Hartman down(&dev->class->sem); 945c47ed219SGreg Kroah-Hartman /* notify any interfaces that the device is now gone */ 946c47ed219SGreg Kroah-Hartman list_for_each_entry(class_intf, &dev->class->interfaces, node) 947c47ed219SGreg Kroah-Hartman if (class_intf->remove_dev) 948c47ed219SGreg Kroah-Hartman class_intf->remove_dev(dev, class_intf); 949c47ed219SGreg Kroah-Hartman /* remove the device from the class list */ 9505d9fd169SGreg Kroah-Hartman list_del_init(&dev->node); 9515d9fd169SGreg Kroah-Hartman up(&dev->class->sem); 95286406245SKay Sievers 95386406245SKay Sievers /* If we live in a parent class-directory, unreference it */ 95486406245SKay Sievers if (dev->kobj.parent->kset == &dev->class->class_dirs) { 95586406245SKay Sievers struct device *d; 95686406245SKay Sievers int other = 0; 95786406245SKay Sievers 95886406245SKay Sievers /* 95986406245SKay Sievers * if we are the last child of our class, delete 96086406245SKay Sievers * our class-directory at this parent 96186406245SKay Sievers */ 96286406245SKay Sievers down(&dev->class->sem); 96386406245SKay Sievers list_for_each_entry(d, &dev->class->devices, node) { 96486406245SKay Sievers if (d == dev) 96586406245SKay Sievers continue; 96686406245SKay Sievers if (d->kobj.parent == dev->kobj.parent) { 96786406245SKay Sievers other = 1; 96886406245SKay Sievers break; 96986406245SKay Sievers } 97086406245SKay Sievers } 97186406245SKay Sievers if (!other) 97286406245SKay Sievers kobject_del(dev->kobj.parent); 97386406245SKay Sievers 97486406245SKay Sievers kobject_put(dev->kobj.parent); 97586406245SKay Sievers up(&dev->class->sem); 97686406245SKay Sievers } 977b9d9c82bSKay Sievers } 978ad6a1e1cSTejun Heo device_remove_file(dev, &uevent_attr); 9792620efefSGreg Kroah-Hartman device_remove_attrs(dev); 98028953533SBenjamin Herrenschmidt bus_remove_device(dev); 9811da177e4SLinus Torvalds 9822f8d16a9STejun Heo /* 9832f8d16a9STejun Heo * Some platform devices are driven without driver attached 9842f8d16a9STejun Heo * and managed resources may have been acquired. Make sure 9852f8d16a9STejun Heo * all resources are released. 9862f8d16a9STejun Heo */ 9872f8d16a9STejun Heo devres_release_all(dev); 9882f8d16a9STejun Heo 9891da177e4SLinus Torvalds /* Notify the platform of the removal, in case they 9901da177e4SLinus Torvalds * need to do anything... 9911da177e4SLinus Torvalds */ 9921da177e4SLinus Torvalds if (platform_notify_remove) 9931da177e4SLinus Torvalds platform_notify_remove(dev); 994116af378SBenjamin Herrenschmidt if (dev->bus) 995116af378SBenjamin Herrenschmidt blocking_notifier_call_chain(&dev->bus->bus_notifier, 996116af378SBenjamin Herrenschmidt BUS_NOTIFY_DEL_DEVICE, dev); 997312c004dSKay Sievers kobject_uevent(&dev->kobj, KOBJ_REMOVE); 9981da177e4SLinus Torvalds kobject_del(&dev->kobj); 9991da177e4SLinus Torvalds if (parent) 10001da177e4SLinus Torvalds put_device(parent); 10011da177e4SLinus Torvalds } 10021da177e4SLinus Torvalds 10031da177e4SLinus Torvalds /** 10041da177e4SLinus Torvalds * device_unregister - unregister device from system. 10051da177e4SLinus Torvalds * @dev: device going away. 10061da177e4SLinus Torvalds * 10071da177e4SLinus Torvalds * We do this in two parts, like we do device_register(). First, 10081da177e4SLinus Torvalds * we remove it from all the subsystems with device_del(), then 10091da177e4SLinus Torvalds * we decrement the reference count via put_device(). If that 10101da177e4SLinus Torvalds * is the final reference count, the device will be cleaned up 10111da177e4SLinus Torvalds * via device_release() above. Otherwise, the structure will 10121da177e4SLinus Torvalds * stick around until the final reference to the device is dropped. 10131da177e4SLinus Torvalds */ 10141da177e4SLinus Torvalds void device_unregister(struct device * dev) 10151da177e4SLinus Torvalds { 10161da177e4SLinus Torvalds pr_debug("DEV: Unregistering device. ID = '%s'\n", dev->bus_id); 10171da177e4SLinus Torvalds device_del(dev); 10181da177e4SLinus Torvalds put_device(dev); 10191da177e4SLinus Torvalds } 10201da177e4SLinus Torvalds 10211da177e4SLinus Torvalds 102236239577Smochel@digitalimplant.org static struct device * next_device(struct klist_iter * i) 102336239577Smochel@digitalimplant.org { 102436239577Smochel@digitalimplant.org struct klist_node * n = klist_next(i); 102536239577Smochel@digitalimplant.org return n ? container_of(n, struct device, knode_parent) : NULL; 102636239577Smochel@digitalimplant.org } 102736239577Smochel@digitalimplant.org 10281da177e4SLinus Torvalds /** 10291da177e4SLinus Torvalds * device_for_each_child - device child iterator. 1030c41455fbSRandy Dunlap * @parent: parent struct device. 10311da177e4SLinus Torvalds * @data: data for the callback. 10321da177e4SLinus Torvalds * @fn: function to be called for each device. 10331da177e4SLinus Torvalds * 1034c41455fbSRandy Dunlap * Iterate over @parent's child devices, and call @fn for each, 10351da177e4SLinus Torvalds * passing it @data. 10361da177e4SLinus Torvalds * 10371da177e4SLinus Torvalds * We check the return of @fn each time. If it returns anything 10381da177e4SLinus Torvalds * other than 0, we break out and return that value. 10391da177e4SLinus Torvalds */ 104036239577Smochel@digitalimplant.org int device_for_each_child(struct device * parent, void * data, 10411da177e4SLinus Torvalds int (*fn)(struct device *, void *)) 10421da177e4SLinus Torvalds { 104336239577Smochel@digitalimplant.org struct klist_iter i; 10441da177e4SLinus Torvalds struct device * child; 10451da177e4SLinus Torvalds int error = 0; 10461da177e4SLinus Torvalds 104736239577Smochel@digitalimplant.org klist_iter_init(&parent->klist_children, &i); 104836239577Smochel@digitalimplant.org while ((child = next_device(&i)) && !error) 104936239577Smochel@digitalimplant.org error = fn(child, data); 105036239577Smochel@digitalimplant.org klist_iter_exit(&i); 10511da177e4SLinus Torvalds return error; 10521da177e4SLinus Torvalds } 10531da177e4SLinus Torvalds 10545ab69981SCornelia Huck /** 10555ab69981SCornelia Huck * device_find_child - device iterator for locating a particular device. 10565ab69981SCornelia Huck * @parent: parent struct device 10575ab69981SCornelia Huck * @data: Data to pass to match function 10585ab69981SCornelia Huck * @match: Callback function to check device 10595ab69981SCornelia Huck * 10605ab69981SCornelia Huck * This is similar to the device_for_each_child() function above, but it 10615ab69981SCornelia Huck * returns a reference to a device that is 'found' for later use, as 10625ab69981SCornelia Huck * determined by the @match callback. 10635ab69981SCornelia Huck * 10645ab69981SCornelia Huck * The callback should return 0 if the device doesn't match and non-zero 10655ab69981SCornelia Huck * if it does. If the callback returns non-zero and a reference to the 10665ab69981SCornelia Huck * current device can be obtained, this function will return to the caller 10675ab69981SCornelia Huck * and not iterate over any more devices. 10685ab69981SCornelia Huck */ 10695ab69981SCornelia Huck struct device * device_find_child(struct device *parent, void *data, 10705ab69981SCornelia Huck int (*match)(struct device *, void *)) 10715ab69981SCornelia Huck { 10725ab69981SCornelia Huck struct klist_iter i; 10735ab69981SCornelia Huck struct device *child; 10745ab69981SCornelia Huck 10755ab69981SCornelia Huck if (!parent) 10765ab69981SCornelia Huck return NULL; 10775ab69981SCornelia Huck 10785ab69981SCornelia Huck klist_iter_init(&parent->klist_children, &i); 10795ab69981SCornelia Huck while ((child = next_device(&i))) 10805ab69981SCornelia Huck if (match(child, data) && get_device(child)) 10815ab69981SCornelia Huck break; 10825ab69981SCornelia Huck klist_iter_exit(&i); 10835ab69981SCornelia Huck return child; 10845ab69981SCornelia Huck } 10855ab69981SCornelia Huck 10861da177e4SLinus Torvalds int __init devices_init(void) 10871da177e4SLinus Torvalds { 10881da177e4SLinus Torvalds return subsystem_register(&devices_subsys); 10891da177e4SLinus Torvalds } 10901da177e4SLinus Torvalds 10911da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(device_for_each_child); 10925ab69981SCornelia Huck EXPORT_SYMBOL_GPL(device_find_child); 10931da177e4SLinus Torvalds 10941da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(device_initialize); 10951da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(device_add); 10961da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(device_register); 10971da177e4SLinus Torvalds 10981da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(device_del); 10991da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(device_unregister); 11001da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(get_device); 11011da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(put_device); 11021da177e4SLinus Torvalds 11031da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(device_create_file); 11041da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(device_remove_file); 110523681e47SGreg Kroah-Hartman 110623681e47SGreg Kroah-Hartman 110723681e47SGreg Kroah-Hartman static void device_create_release(struct device *dev) 110823681e47SGreg Kroah-Hartman { 110923681e47SGreg Kroah-Hartman pr_debug("%s called for %s\n", __FUNCTION__, dev->bus_id); 111023681e47SGreg Kroah-Hartman kfree(dev); 111123681e47SGreg Kroah-Hartman } 111223681e47SGreg Kroah-Hartman 111323681e47SGreg Kroah-Hartman /** 111423681e47SGreg Kroah-Hartman * device_create - creates a device and registers it with sysfs 111542734dafSHenrik Kretzschmar * @class: pointer to the struct class that this device should be registered to 111642734dafSHenrik Kretzschmar * @parent: pointer to the parent struct device of this new device, if any 111742734dafSHenrik Kretzschmar * @devt: the dev_t for the char device to be added 111842734dafSHenrik Kretzschmar * @fmt: string for the device's name 111923681e47SGreg Kroah-Hartman * 112042734dafSHenrik Kretzschmar * This function can be used by char device classes. A struct device 112142734dafSHenrik Kretzschmar * will be created in sysfs, registered to the specified class. 112242734dafSHenrik Kretzschmar * 112323681e47SGreg Kroah-Hartman * A "dev" file will be created, showing the dev_t for the device, if 112423681e47SGreg Kroah-Hartman * the dev_t is not 0,0. 112542734dafSHenrik Kretzschmar * If a pointer to a parent struct device is passed in, the newly created 112642734dafSHenrik Kretzschmar * struct device will be a child of that device in sysfs. 112742734dafSHenrik Kretzschmar * The pointer to the struct device will be returned from the call. 112842734dafSHenrik Kretzschmar * Any further sysfs files that might be required can be created using this 112923681e47SGreg Kroah-Hartman * pointer. 113023681e47SGreg Kroah-Hartman * 113123681e47SGreg Kroah-Hartman * Note: the struct class passed to this function must have previously 113223681e47SGreg Kroah-Hartman * been created with a call to class_create(). 113323681e47SGreg Kroah-Hartman */ 113423681e47SGreg Kroah-Hartman struct device *device_create(struct class *class, struct device *parent, 11355cbe5f8aSGreg Kroah-Hartman dev_t devt, const char *fmt, ...) 113623681e47SGreg Kroah-Hartman { 113723681e47SGreg Kroah-Hartman va_list args; 113823681e47SGreg Kroah-Hartman struct device *dev = NULL; 113923681e47SGreg Kroah-Hartman int retval = -ENODEV; 114023681e47SGreg Kroah-Hartman 114123681e47SGreg Kroah-Hartman if (class == NULL || IS_ERR(class)) 114223681e47SGreg Kroah-Hartman goto error; 114323681e47SGreg Kroah-Hartman 114423681e47SGreg Kroah-Hartman dev = kzalloc(sizeof(*dev), GFP_KERNEL); 114523681e47SGreg Kroah-Hartman if (!dev) { 114623681e47SGreg Kroah-Hartman retval = -ENOMEM; 114723681e47SGreg Kroah-Hartman goto error; 114823681e47SGreg Kroah-Hartman } 114923681e47SGreg Kroah-Hartman 115023681e47SGreg Kroah-Hartman dev->devt = devt; 115123681e47SGreg Kroah-Hartman dev->class = class; 115223681e47SGreg Kroah-Hartman dev->parent = parent; 115323681e47SGreg Kroah-Hartman dev->release = device_create_release; 115423681e47SGreg Kroah-Hartman 115523681e47SGreg Kroah-Hartman va_start(args, fmt); 115623681e47SGreg Kroah-Hartman vsnprintf(dev->bus_id, BUS_ID_SIZE, fmt, args); 115723681e47SGreg Kroah-Hartman va_end(args); 115823681e47SGreg Kroah-Hartman retval = device_register(dev); 115923681e47SGreg Kroah-Hartman if (retval) 116023681e47SGreg Kroah-Hartman goto error; 116123681e47SGreg Kroah-Hartman 116223681e47SGreg Kroah-Hartman return dev; 116323681e47SGreg Kroah-Hartman 116423681e47SGreg Kroah-Hartman error: 116523681e47SGreg Kroah-Hartman kfree(dev); 116623681e47SGreg Kroah-Hartman return ERR_PTR(retval); 116723681e47SGreg Kroah-Hartman } 116823681e47SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(device_create); 116923681e47SGreg Kroah-Hartman 117023681e47SGreg Kroah-Hartman /** 1171775b64d2SRafael J. Wysocki * find_device - finds a device that was created with device_create() 117242734dafSHenrik Kretzschmar * @class: pointer to the struct class that this device was registered with 117342734dafSHenrik Kretzschmar * @devt: the dev_t of the device that was previously registered 117423681e47SGreg Kroah-Hartman */ 1175775b64d2SRafael J. Wysocki static struct device *find_device(struct class *class, dev_t devt) 117623681e47SGreg Kroah-Hartman { 117723681e47SGreg Kroah-Hartman struct device *dev = NULL; 117823681e47SGreg Kroah-Hartman struct device *dev_tmp; 117923681e47SGreg Kroah-Hartman 118023681e47SGreg Kroah-Hartman down(&class->sem); 118123681e47SGreg Kroah-Hartman list_for_each_entry(dev_tmp, &class->devices, node) { 118223681e47SGreg Kroah-Hartman if (dev_tmp->devt == devt) { 118323681e47SGreg Kroah-Hartman dev = dev_tmp; 118423681e47SGreg Kroah-Hartman break; 118523681e47SGreg Kroah-Hartman } 118623681e47SGreg Kroah-Hartman } 118723681e47SGreg Kroah-Hartman up(&class->sem); 1188775b64d2SRafael J. Wysocki return dev; 1189775b64d2SRafael J. Wysocki } 119023681e47SGreg Kroah-Hartman 1191775b64d2SRafael J. Wysocki /** 1192775b64d2SRafael J. Wysocki * device_destroy - removes a device that was created with device_create() 1193775b64d2SRafael J. Wysocki * @class: pointer to the struct class that this device was registered with 1194775b64d2SRafael J. Wysocki * @devt: the dev_t of the device that was previously registered 1195775b64d2SRafael J. Wysocki * 1196775b64d2SRafael J. Wysocki * This call unregisters and cleans up a device that was created with a 1197775b64d2SRafael J. Wysocki * call to device_create(). 1198775b64d2SRafael J. Wysocki */ 1199775b64d2SRafael J. Wysocki void device_destroy(struct class *class, dev_t devt) 1200775b64d2SRafael J. Wysocki { 1201775b64d2SRafael J. Wysocki struct device *dev; 1202775b64d2SRafael J. Wysocki 1203775b64d2SRafael J. Wysocki dev = find_device(class, devt); 12045d9fd169SGreg Kroah-Hartman if (dev) 120523681e47SGreg Kroah-Hartman device_unregister(dev); 120623681e47SGreg Kroah-Hartman } 120723681e47SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(device_destroy); 1208a2de48caSGreg Kroah-Hartman 1209775b64d2SRafael J. Wysocki #ifdef CONFIG_PM_SLEEP 1210775b64d2SRafael J. Wysocki /** 1211775b64d2SRafael J. Wysocki * destroy_suspended_device - asks the PM core to remove a suspended device 1212775b64d2SRafael J. Wysocki * @class: pointer to the struct class that this device was registered with 1213775b64d2SRafael J. Wysocki * @devt: the dev_t of the device that was previously registered 1214775b64d2SRafael J. Wysocki * 1215775b64d2SRafael J. Wysocki * This call notifies the PM core of the necessity to unregister a suspended 1216775b64d2SRafael J. Wysocki * device created with a call to device_create() (devices cannot be 1217775b64d2SRafael J. Wysocki * unregistered directly while suspended, since the PM core holds their 1218775b64d2SRafael J. Wysocki * semaphores at that time). 1219775b64d2SRafael J. Wysocki * 1220775b64d2SRafael J. Wysocki * It can only be called within the scope of a system sleep transition. In 1221775b64d2SRafael J. Wysocki * practice this means it has to be directly or indirectly invoked either by 1222775b64d2SRafael J. Wysocki * a suspend or resume method, or by the PM core (e.g. via 1223775b64d2SRafael J. Wysocki * disable_nonboot_cpus() or enable_nonboot_cpus()). 1224775b64d2SRafael J. Wysocki */ 1225775b64d2SRafael J. Wysocki void destroy_suspended_device(struct class *class, dev_t devt) 1226775b64d2SRafael J. Wysocki { 1227775b64d2SRafael J. Wysocki struct device *dev; 1228775b64d2SRafael J. Wysocki 1229775b64d2SRafael J. Wysocki dev = find_device(class, devt); 1230775b64d2SRafael J. Wysocki if (dev) 1231775b64d2SRafael J. Wysocki device_pm_schedule_removal(dev); 1232775b64d2SRafael J. Wysocki } 1233775b64d2SRafael J. Wysocki EXPORT_SYMBOL_GPL(destroy_suspended_device); 1234775b64d2SRafael J. Wysocki #endif /* CONFIG_PM_SLEEP */ 1235775b64d2SRafael J. Wysocki 1236a2de48caSGreg Kroah-Hartman /** 1237a2de48caSGreg Kroah-Hartman * device_rename - renames a device 1238a2de48caSGreg Kroah-Hartman * @dev: the pointer to the struct device to be renamed 1239a2de48caSGreg Kroah-Hartman * @new_name: the new name of the device 1240a2de48caSGreg Kroah-Hartman */ 1241a2de48caSGreg Kroah-Hartman int device_rename(struct device *dev, char *new_name) 1242a2de48caSGreg Kroah-Hartman { 1243a2de48caSGreg Kroah-Hartman char *old_class_name = NULL; 1244a2de48caSGreg Kroah-Hartman char *new_class_name = NULL; 12452ee97cafSCornelia Huck char *old_device_name = NULL; 1246a2de48caSGreg Kroah-Hartman int error; 1247a2de48caSGreg Kroah-Hartman 1248a2de48caSGreg Kroah-Hartman dev = get_device(dev); 1249a2de48caSGreg Kroah-Hartman if (!dev) 1250a2de48caSGreg Kroah-Hartman return -EINVAL; 1251a2de48caSGreg Kroah-Hartman 1252a2de48caSGreg Kroah-Hartman pr_debug("DEVICE: renaming '%s' to '%s'\n", dev->bus_id, new_name); 1253a2de48caSGreg Kroah-Hartman 125499ef3ef8SKay Sievers #ifdef CONFIG_SYSFS_DEPRECATED 1255a2de48caSGreg Kroah-Hartman if ((dev->class) && (dev->parent)) 1256a2de48caSGreg Kroah-Hartman old_class_name = make_class_name(dev->class->name, &dev->kobj); 125799ef3ef8SKay Sievers #endif 1258a2de48caSGreg Kroah-Hartman 12592ee97cafSCornelia Huck old_device_name = kmalloc(BUS_ID_SIZE, GFP_KERNEL); 12602ee97cafSCornelia Huck if (!old_device_name) { 1261952ab431SJesper Juhl error = -ENOMEM; 12622ee97cafSCornelia Huck goto out; 1263952ab431SJesper Juhl } 12642ee97cafSCornelia Huck strlcpy(old_device_name, dev->bus_id, BUS_ID_SIZE); 1265a2de48caSGreg Kroah-Hartman strlcpy(dev->bus_id, new_name, BUS_ID_SIZE); 1266a2de48caSGreg Kroah-Hartman 1267a2de48caSGreg Kroah-Hartman error = kobject_rename(&dev->kobj, new_name); 12682ee97cafSCornelia Huck if (error) { 12692ee97cafSCornelia Huck strlcpy(dev->bus_id, old_device_name, BUS_ID_SIZE); 12702ee97cafSCornelia Huck goto out; 12712ee97cafSCornelia Huck } 1272a2de48caSGreg Kroah-Hartman 127399ef3ef8SKay Sievers #ifdef CONFIG_SYSFS_DEPRECATED 1274a2de48caSGreg Kroah-Hartman if (old_class_name) { 1275a2de48caSGreg Kroah-Hartman new_class_name = make_class_name(dev->class->name, &dev->kobj); 1276a2de48caSGreg Kroah-Hartman if (new_class_name) { 12772ee97cafSCornelia Huck error = sysfs_create_link(&dev->parent->kobj, 12782ee97cafSCornelia Huck &dev->kobj, new_class_name); 12792ee97cafSCornelia Huck if (error) 12802ee97cafSCornelia Huck goto out; 1281a2de48caSGreg Kroah-Hartman sysfs_remove_link(&dev->parent->kobj, old_class_name); 1282a2de48caSGreg Kroah-Hartman } 1283a2de48caSGreg Kroah-Hartman } 128460b8cabdSKay Sievers #else 1285a2de48caSGreg Kroah-Hartman if (dev->class) { 12862ee97cafSCornelia Huck sysfs_remove_link(&dev->class->subsys.kobj, old_device_name); 12872ee97cafSCornelia Huck error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj, 1288a2de48caSGreg Kroah-Hartman dev->bus_id); 12892ee97cafSCornelia Huck if (error) { 12902ee97cafSCornelia Huck dev_err(dev, "%s: sysfs_create_symlink failed (%d)\n", 12912ee97cafSCornelia Huck __FUNCTION__, error); 1292a2de48caSGreg Kroah-Hartman } 12932ee97cafSCornelia Huck } 129460b8cabdSKay Sievers #endif 129560b8cabdSKay Sievers 12962ee97cafSCornelia Huck out: 1297a2de48caSGreg Kroah-Hartman put_device(dev); 1298a2de48caSGreg Kroah-Hartman 1299a2de48caSGreg Kroah-Hartman kfree(new_class_name); 1300952ab431SJesper Juhl kfree(old_class_name); 13012ee97cafSCornelia Huck kfree(old_device_name); 1302a2de48caSGreg Kroah-Hartman 1303a2de48caSGreg Kroah-Hartman return error; 1304a2de48caSGreg Kroah-Hartman } 1305a2807dbcSJohannes Berg EXPORT_SYMBOL_GPL(device_rename); 13068a82472fSCornelia Huck 13078a82472fSCornelia Huck static int device_move_class_links(struct device *dev, 13088a82472fSCornelia Huck struct device *old_parent, 13098a82472fSCornelia Huck struct device *new_parent) 13108a82472fSCornelia Huck { 1311f7f3461dSGreg Kroah-Hartman int error = 0; 13128a82472fSCornelia Huck #ifdef CONFIG_SYSFS_DEPRECATED 13138a82472fSCornelia Huck char *class_name; 13148a82472fSCornelia Huck 13158a82472fSCornelia Huck class_name = make_class_name(dev->class->name, &dev->kobj); 13168a82472fSCornelia Huck if (!class_name) { 1317cb360bbfSCornelia Huck error = -ENOMEM; 13188a82472fSCornelia Huck goto out; 13198a82472fSCornelia Huck } 13208a82472fSCornelia Huck if (old_parent) { 13218a82472fSCornelia Huck sysfs_remove_link(&dev->kobj, "device"); 13228a82472fSCornelia Huck sysfs_remove_link(&old_parent->kobj, class_name); 13238a82472fSCornelia Huck } 1324c744aeaeSCornelia Huck if (new_parent) { 1325c744aeaeSCornelia Huck error = sysfs_create_link(&dev->kobj, &new_parent->kobj, 1326c744aeaeSCornelia Huck "device"); 13278a82472fSCornelia Huck if (error) 13288a82472fSCornelia Huck goto out; 1329c744aeaeSCornelia Huck error = sysfs_create_link(&new_parent->kobj, &dev->kobj, 1330c744aeaeSCornelia Huck class_name); 13318a82472fSCornelia Huck if (error) 13328a82472fSCornelia Huck sysfs_remove_link(&dev->kobj, "device"); 1333c744aeaeSCornelia Huck } 1334c744aeaeSCornelia Huck else 1335c744aeaeSCornelia Huck error = 0; 13368a82472fSCornelia Huck out: 13378a82472fSCornelia Huck kfree(class_name); 13388a82472fSCornelia Huck return error; 13398a82472fSCornelia Huck #else 1340f7f3461dSGreg Kroah-Hartman if (old_parent) 1341f7f3461dSGreg Kroah-Hartman sysfs_remove_link(&dev->kobj, "device"); 1342f7f3461dSGreg Kroah-Hartman if (new_parent) 1343f7f3461dSGreg Kroah-Hartman error = sysfs_create_link(&dev->kobj, &new_parent->kobj, 1344f7f3461dSGreg Kroah-Hartman "device"); 1345f7f3461dSGreg Kroah-Hartman return error; 13468a82472fSCornelia Huck #endif 13478a82472fSCornelia Huck } 13488a82472fSCornelia Huck 13498a82472fSCornelia Huck /** 13508a82472fSCornelia Huck * device_move - moves a device to a new parent 13518a82472fSCornelia Huck * @dev: the pointer to the struct device to be moved 1352c744aeaeSCornelia Huck * @new_parent: the new parent of the device (can by NULL) 13538a82472fSCornelia Huck */ 13548a82472fSCornelia Huck int device_move(struct device *dev, struct device *new_parent) 13558a82472fSCornelia Huck { 13568a82472fSCornelia Huck int error; 13578a82472fSCornelia Huck struct device *old_parent; 1358c744aeaeSCornelia Huck struct kobject *new_parent_kobj; 13598a82472fSCornelia Huck 13608a82472fSCornelia Huck dev = get_device(dev); 13618a82472fSCornelia Huck if (!dev) 13628a82472fSCornelia Huck return -EINVAL; 13638a82472fSCornelia Huck 13648a82472fSCornelia Huck new_parent = get_device(new_parent); 1365c744aeaeSCornelia Huck new_parent_kobj = get_device_parent (dev, new_parent); 1366c744aeaeSCornelia Huck if (IS_ERR(new_parent_kobj)) { 1367c744aeaeSCornelia Huck error = PTR_ERR(new_parent_kobj); 1368c744aeaeSCornelia Huck put_device(new_parent); 13698a82472fSCornelia Huck goto out; 13708a82472fSCornelia Huck } 13718a82472fSCornelia Huck pr_debug("DEVICE: moving '%s' to '%s'\n", dev->bus_id, 1372c744aeaeSCornelia Huck new_parent ? new_parent->bus_id : "<NULL>"); 1373c744aeaeSCornelia Huck error = kobject_move(&dev->kobj, new_parent_kobj); 13748a82472fSCornelia Huck if (error) { 13758a82472fSCornelia Huck put_device(new_parent); 13768a82472fSCornelia Huck goto out; 13778a82472fSCornelia Huck } 13788a82472fSCornelia Huck old_parent = dev->parent; 13798a82472fSCornelia Huck dev->parent = new_parent; 13808a82472fSCornelia Huck if (old_parent) 1381acf02d23SCornelia Huck klist_remove(&dev->knode_parent); 1382c744aeaeSCornelia Huck if (new_parent) 13838a82472fSCornelia Huck klist_add_tail(&dev->knode_parent, &new_parent->klist_children); 13848a82472fSCornelia Huck if (!dev->class) 13858a82472fSCornelia Huck goto out_put; 13868a82472fSCornelia Huck error = device_move_class_links(dev, old_parent, new_parent); 13878a82472fSCornelia Huck if (error) { 13888a82472fSCornelia Huck /* We ignore errors on cleanup since we're hosed anyway... */ 13898a82472fSCornelia Huck device_move_class_links(dev, new_parent, old_parent); 13908a82472fSCornelia Huck if (!kobject_move(&dev->kobj, &old_parent->kobj)) { 1391c744aeaeSCornelia Huck if (new_parent) 1392acf02d23SCornelia Huck klist_remove(&dev->knode_parent); 13938a82472fSCornelia Huck if (old_parent) 13948a82472fSCornelia Huck klist_add_tail(&dev->knode_parent, 13958a82472fSCornelia Huck &old_parent->klist_children); 13968a82472fSCornelia Huck } 13978a82472fSCornelia Huck put_device(new_parent); 13988a82472fSCornelia Huck goto out; 13998a82472fSCornelia Huck } 14008a82472fSCornelia Huck out_put: 14018a82472fSCornelia Huck put_device(old_parent); 14028a82472fSCornelia Huck out: 14038a82472fSCornelia Huck put_device(dev); 14048a82472fSCornelia Huck return error; 14058a82472fSCornelia Huck } 14068a82472fSCornelia Huck 14078a82472fSCornelia Huck EXPORT_SYMBOL_GPL(device_move); 1408