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 1111da177e4SLinus Torvalds static struct kobj_type ktype_device = { 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 1211da177e4SLinus Torvalds if (ktype == &ktype_device) { 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 144312c004dSKay Sievers static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp, 1451da177e4SLinus Torvalds int num_envp, char *buffer, int buffer_size) 1461da177e4SLinus Torvalds { 1471da177e4SLinus Torvalds struct device *dev = to_dev(kobj); 1481da177e4SLinus Torvalds int i = 0; 1491da177e4SLinus Torvalds int length = 0; 1501da177e4SLinus Torvalds int retval = 0; 1511da177e4SLinus Torvalds 15223681e47SGreg Kroah-Hartman /* add the major/minor if present */ 15323681e47SGreg Kroah-Hartman if (MAJOR(dev->devt)) { 15423681e47SGreg Kroah-Hartman add_uevent_var(envp, num_envp, &i, 15523681e47SGreg Kroah-Hartman buffer, buffer_size, &length, 15623681e47SGreg Kroah-Hartman "MAJOR=%u", MAJOR(dev->devt)); 15723681e47SGreg Kroah-Hartman add_uevent_var(envp, num_envp, &i, 15823681e47SGreg Kroah-Hartman buffer, buffer_size, &length, 15923681e47SGreg Kroah-Hartman "MINOR=%u", MINOR(dev->devt)); 16023681e47SGreg Kroah-Hartman } 16123681e47SGreg Kroah-Hartman 162414264f9SKay Sievers if (dev->type && dev->type->name) 163414264f9SKay Sievers add_uevent_var(envp, num_envp, &i, 164414264f9SKay Sievers buffer, buffer_size, &length, 165414264f9SKay Sievers "DEVTYPE=%s", dev->type->name); 166414264f9SKay Sievers 167239378f1SKay Sievers if (dev->driver) 168d81d9d6bSKay Sievers add_uevent_var(envp, num_envp, &i, 169d81d9d6bSKay Sievers buffer, buffer_size, &length, 170d81d9d6bSKay Sievers "DRIVER=%s", dev->driver->name); 171239378f1SKay Sievers 172a87cb2acSKay Sievers #ifdef CONFIG_SYSFS_DEPRECATED 173239378f1SKay Sievers if (dev->class) { 174239378f1SKay Sievers struct device *parent = dev->parent; 175239378f1SKay Sievers 176239378f1SKay Sievers /* find first bus device in parent chain */ 177239378f1SKay Sievers while (parent && !parent->bus) 178239378f1SKay Sievers parent = parent->parent; 179239378f1SKay Sievers if (parent && parent->bus) { 180239378f1SKay Sievers const char *path; 181239378f1SKay Sievers 182239378f1SKay Sievers path = kobject_get_path(&parent->kobj, GFP_KERNEL); 183239378f1SKay Sievers add_uevent_var(envp, num_envp, &i, 184239378f1SKay Sievers buffer, buffer_size, &length, 185239378f1SKay Sievers "PHYSDEVPATH=%s", path); 186239378f1SKay Sievers kfree(path); 187239378f1SKay Sievers 188239378f1SKay Sievers add_uevent_var(envp, num_envp, &i, 189239378f1SKay Sievers buffer, buffer_size, &length, 190239378f1SKay Sievers "PHYSDEVBUS=%s", parent->bus->name); 191239378f1SKay Sievers 192239378f1SKay Sievers if (parent->driver) 193239378f1SKay Sievers add_uevent_var(envp, num_envp, &i, 194239378f1SKay Sievers buffer, buffer_size, &length, 195239378f1SKay Sievers "PHYSDEVDRIVER=%s", parent->driver->name); 196239378f1SKay Sievers } 197239378f1SKay Sievers } else if (dev->bus) { 198239378f1SKay Sievers add_uevent_var(envp, num_envp, &i, 199239378f1SKay Sievers buffer, buffer_size, &length, 200239378f1SKay Sievers "PHYSDEVBUS=%s", dev->bus->name); 201239378f1SKay Sievers 202239378f1SKay Sievers if (dev->driver) 203312c004dSKay Sievers add_uevent_var(envp, num_envp, &i, 2041da177e4SLinus Torvalds buffer, buffer_size, &length, 2051da177e4SLinus Torvalds "PHYSDEVDRIVER=%s", dev->driver->name); 206d81d9d6bSKay Sievers } 207239378f1SKay Sievers #endif 2081da177e4SLinus Torvalds 2091da177e4SLinus Torvalds /* terminate, set to next free slot, shrink available space */ 2101da177e4SLinus Torvalds envp[i] = NULL; 2111da177e4SLinus Torvalds envp = &envp[i]; 2121da177e4SLinus Torvalds num_envp -= i; 2131da177e4SLinus Torvalds buffer = &buffer[length]; 2141da177e4SLinus Torvalds buffer_size -= length; 2151da177e4SLinus Torvalds 216312c004dSKay Sievers if (dev->bus && dev->bus->uevent) { 2171da177e4SLinus Torvalds /* have the bus specific function add its stuff */ 218312c004dSKay Sievers retval = dev->bus->uevent(dev, envp, num_envp, buffer, buffer_size); 219f9f852dfSKay Sievers if (retval) 220f9f852dfSKay Sievers pr_debug ("%s: bus uevent() returned %d\n", 2211da177e4SLinus Torvalds __FUNCTION__, retval); 2221da177e4SLinus Torvalds } 2231da177e4SLinus Torvalds 2242620efefSGreg Kroah-Hartman if (dev->class && dev->class->dev_uevent) { 2252620efefSGreg Kroah-Hartman /* have the class specific function add its stuff */ 2262620efefSGreg Kroah-Hartman retval = dev->class->dev_uevent(dev, envp, num_envp, buffer, buffer_size); 227f9f852dfSKay Sievers if (retval) 228f9f852dfSKay Sievers pr_debug("%s: class uevent() returned %d\n", 2292620efefSGreg Kroah-Hartman __FUNCTION__, retval); 2302620efefSGreg Kroah-Hartman } 231f9f852dfSKay Sievers 232f9f852dfSKay Sievers if (dev->type && dev->type->uevent) { 233f9f852dfSKay Sievers /* have the device type specific fuction add its stuff */ 234f9f852dfSKay Sievers retval = dev->type->uevent(dev, envp, num_envp, buffer, buffer_size); 235f9f852dfSKay Sievers if (retval) 236f9f852dfSKay Sievers pr_debug("%s: dev_type uevent() returned %d\n", 237f9f852dfSKay Sievers __FUNCTION__, retval); 2382620efefSGreg Kroah-Hartman } 2392620efefSGreg Kroah-Hartman 2401da177e4SLinus Torvalds return retval; 2411da177e4SLinus Torvalds } 2421da177e4SLinus Torvalds 243312c004dSKay Sievers static struct kset_uevent_ops device_uevent_ops = { 244312c004dSKay Sievers .filter = dev_uevent_filter, 245312c004dSKay Sievers .name = dev_uevent_name, 246312c004dSKay Sievers .uevent = dev_uevent, 2471da177e4SLinus Torvalds }; 2481da177e4SLinus Torvalds 24916574dccSKay Sievers static ssize_t show_uevent(struct device *dev, struct device_attribute *attr, 25016574dccSKay Sievers char *buf) 25116574dccSKay Sievers { 25216574dccSKay Sievers struct kobject *top_kobj; 25316574dccSKay Sievers struct kset *kset; 25416574dccSKay Sievers char *envp[32]; 25516574dccSKay Sievers char data[PAGE_SIZE]; 25616574dccSKay Sievers char *pos; 25716574dccSKay Sievers int i; 25816574dccSKay Sievers size_t count = 0; 25916574dccSKay Sievers int retval; 26016574dccSKay Sievers 26116574dccSKay Sievers /* search the kset, the device belongs to */ 26216574dccSKay Sievers top_kobj = &dev->kobj; 26316574dccSKay Sievers if (!top_kobj->kset && top_kobj->parent) { 26416574dccSKay Sievers do { 26516574dccSKay Sievers top_kobj = top_kobj->parent; 26616574dccSKay Sievers } while (!top_kobj->kset && top_kobj->parent); 26716574dccSKay Sievers } 26816574dccSKay Sievers if (!top_kobj->kset) 26916574dccSKay Sievers goto out; 27016574dccSKay Sievers kset = top_kobj->kset; 27116574dccSKay Sievers if (!kset->uevent_ops || !kset->uevent_ops->uevent) 27216574dccSKay Sievers goto out; 27316574dccSKay Sievers 27416574dccSKay Sievers /* respect filter */ 27516574dccSKay Sievers if (kset->uevent_ops && kset->uevent_ops->filter) 27616574dccSKay Sievers if (!kset->uevent_ops->filter(kset, &dev->kobj)) 27716574dccSKay Sievers goto out; 27816574dccSKay Sievers 27916574dccSKay Sievers /* let the kset specific function add its keys */ 28016574dccSKay Sievers pos = data; 28116574dccSKay Sievers retval = kset->uevent_ops->uevent(kset, &dev->kobj, 28216574dccSKay Sievers envp, ARRAY_SIZE(envp), 28316574dccSKay Sievers pos, PAGE_SIZE); 28416574dccSKay Sievers if (retval) 28516574dccSKay Sievers goto out; 28616574dccSKay Sievers 28716574dccSKay Sievers /* copy keys to file */ 28816574dccSKay Sievers for (i = 0; envp[i]; i++) { 28916574dccSKay Sievers pos = &buf[count]; 29016574dccSKay Sievers count += sprintf(pos, "%s\n", envp[i]); 29116574dccSKay Sievers } 29216574dccSKay Sievers out: 29316574dccSKay Sievers return count; 29416574dccSKay Sievers } 29516574dccSKay Sievers 296a7fd6706SKay Sievers static ssize_t store_uevent(struct device *dev, struct device_attribute *attr, 297a7fd6706SKay Sievers const char *buf, size_t count) 298a7fd6706SKay Sievers { 299312c004dSKay Sievers kobject_uevent(&dev->kobj, KOBJ_ADD); 300a7fd6706SKay Sievers return count; 301a7fd6706SKay Sievers } 302a7fd6706SKay Sievers 303621a1672SDmitry Torokhov static int device_add_attributes(struct device *dev, 304621a1672SDmitry Torokhov struct device_attribute *attrs) 305de0ff00dSGreg Kroah-Hartman { 306de0ff00dSGreg Kroah-Hartman int error = 0; 307621a1672SDmitry Torokhov int i; 308de0ff00dSGreg Kroah-Hartman 309621a1672SDmitry Torokhov if (attrs) { 310621a1672SDmitry Torokhov for (i = 0; attr_name(attrs[i]); i++) { 311621a1672SDmitry Torokhov error = device_create_file(dev, &attrs[i]); 312621a1672SDmitry Torokhov if (error) 313621a1672SDmitry Torokhov break; 314621a1672SDmitry Torokhov } 315621a1672SDmitry Torokhov if (error) 316de0ff00dSGreg Kroah-Hartman while (--i >= 0) 317621a1672SDmitry Torokhov device_remove_file(dev, &attrs[i]); 318de0ff00dSGreg Kroah-Hartman } 319de0ff00dSGreg Kroah-Hartman return error; 320de0ff00dSGreg Kroah-Hartman } 321de0ff00dSGreg Kroah-Hartman 322621a1672SDmitry Torokhov static void device_remove_attributes(struct device *dev, 323621a1672SDmitry Torokhov struct device_attribute *attrs) 324de0ff00dSGreg Kroah-Hartman { 325de0ff00dSGreg Kroah-Hartman int i; 326621a1672SDmitry Torokhov 327621a1672SDmitry Torokhov if (attrs) 328621a1672SDmitry Torokhov for (i = 0; attr_name(attrs[i]); i++) 329621a1672SDmitry Torokhov device_remove_file(dev, &attrs[i]); 330621a1672SDmitry Torokhov } 331621a1672SDmitry Torokhov 332621a1672SDmitry Torokhov static int device_add_groups(struct device *dev, 333621a1672SDmitry Torokhov struct attribute_group **groups) 334621a1672SDmitry Torokhov { 335621a1672SDmitry Torokhov int error = 0; 336621a1672SDmitry Torokhov int i; 337621a1672SDmitry Torokhov 338621a1672SDmitry Torokhov if (groups) { 339621a1672SDmitry Torokhov for (i = 0; groups[i]; i++) { 340621a1672SDmitry Torokhov error = sysfs_create_group(&dev->kobj, groups[i]); 341621a1672SDmitry Torokhov if (error) { 342621a1672SDmitry Torokhov while (--i >= 0) 343621a1672SDmitry Torokhov sysfs_remove_group(&dev->kobj, groups[i]); 344621a1672SDmitry Torokhov break; 345de0ff00dSGreg Kroah-Hartman } 346de0ff00dSGreg Kroah-Hartman } 347de0ff00dSGreg Kroah-Hartman } 348621a1672SDmitry Torokhov return error; 349621a1672SDmitry Torokhov } 350621a1672SDmitry Torokhov 351621a1672SDmitry Torokhov static void device_remove_groups(struct device *dev, 352621a1672SDmitry Torokhov struct attribute_group **groups) 353621a1672SDmitry Torokhov { 354621a1672SDmitry Torokhov int i; 355621a1672SDmitry Torokhov 356621a1672SDmitry Torokhov if (groups) 357621a1672SDmitry Torokhov for (i = 0; groups[i]; i++) 358621a1672SDmitry Torokhov sysfs_remove_group(&dev->kobj, groups[i]); 359621a1672SDmitry Torokhov } 360de0ff00dSGreg Kroah-Hartman 3612620efefSGreg Kroah-Hartman static int device_add_attrs(struct device *dev) 3622620efefSGreg Kroah-Hartman { 3632620efefSGreg Kroah-Hartman struct class *class = dev->class; 364f9f852dfSKay Sievers struct device_type *type = dev->type; 365621a1672SDmitry Torokhov int error; 3662620efefSGreg Kroah-Hartman 367621a1672SDmitry Torokhov if (class) { 368621a1672SDmitry Torokhov error = device_add_attributes(dev, class->dev_attrs); 3692620efefSGreg Kroah-Hartman if (error) 370621a1672SDmitry Torokhov return error; 371f9f852dfSKay Sievers } 372f9f852dfSKay Sievers 373621a1672SDmitry Torokhov if (type) { 374621a1672SDmitry Torokhov error = device_add_groups(dev, type->groups); 375f9f852dfSKay Sievers if (error) 376621a1672SDmitry Torokhov goto err_remove_class_attrs; 377f9f852dfSKay Sievers } 378621a1672SDmitry Torokhov 379621a1672SDmitry Torokhov error = device_add_groups(dev, dev->groups); 380f9f852dfSKay Sievers if (error) 381621a1672SDmitry Torokhov goto err_remove_type_groups; 382621a1672SDmitry Torokhov 383621a1672SDmitry Torokhov return 0; 384621a1672SDmitry Torokhov 385621a1672SDmitry Torokhov err_remove_type_groups: 386621a1672SDmitry Torokhov if (type) 387621a1672SDmitry Torokhov device_remove_groups(dev, type->groups); 388621a1672SDmitry Torokhov err_remove_class_attrs: 389621a1672SDmitry Torokhov if (class) 390621a1672SDmitry Torokhov device_remove_attributes(dev, class->dev_attrs); 391f9f852dfSKay Sievers 3922620efefSGreg Kroah-Hartman return error; 3932620efefSGreg Kroah-Hartman } 3942620efefSGreg Kroah-Hartman 3952620efefSGreg Kroah-Hartman static void device_remove_attrs(struct device *dev) 3962620efefSGreg Kroah-Hartman { 3972620efefSGreg Kroah-Hartman struct class *class = dev->class; 398f9f852dfSKay Sievers struct device_type *type = dev->type; 3992620efefSGreg Kroah-Hartman 400621a1672SDmitry Torokhov device_remove_groups(dev, dev->groups); 401f9f852dfSKay Sievers 402621a1672SDmitry Torokhov if (type) 403621a1672SDmitry Torokhov device_remove_groups(dev, type->groups); 404621a1672SDmitry Torokhov 405621a1672SDmitry Torokhov if (class) 406621a1672SDmitry Torokhov device_remove_attributes(dev, class->dev_attrs); 4072620efefSGreg Kroah-Hartman } 4082620efefSGreg Kroah-Hartman 4092620efefSGreg Kroah-Hartman 41023681e47SGreg Kroah-Hartman static ssize_t show_dev(struct device *dev, struct device_attribute *attr, 41123681e47SGreg Kroah-Hartman char *buf) 41223681e47SGreg Kroah-Hartman { 41323681e47SGreg Kroah-Hartman return print_dev_t(buf, dev->devt); 41423681e47SGreg Kroah-Hartman } 41523681e47SGreg Kroah-Hartman 4160863afb3SMartin Waitz /* 4170863afb3SMartin Waitz * devices_subsys - structure to be registered with kobject core. 4181da177e4SLinus Torvalds */ 4191da177e4SLinus Torvalds 420312c004dSKay Sievers decl_subsys(devices, &ktype_device, &device_uevent_ops); 4211da177e4SLinus Torvalds 4221da177e4SLinus Torvalds 4231da177e4SLinus Torvalds /** 4241da177e4SLinus Torvalds * device_create_file - create sysfs attribute file for device. 4251da177e4SLinus Torvalds * @dev: device. 4261da177e4SLinus Torvalds * @attr: device attribute descriptor. 4271da177e4SLinus Torvalds */ 4281da177e4SLinus Torvalds 4291da177e4SLinus Torvalds int device_create_file(struct device * dev, struct device_attribute * attr) 4301da177e4SLinus Torvalds { 4311da177e4SLinus Torvalds int error = 0; 4321da177e4SLinus Torvalds if (get_device(dev)) { 4331da177e4SLinus Torvalds error = sysfs_create_file(&dev->kobj, &attr->attr); 4341da177e4SLinus Torvalds put_device(dev); 4351da177e4SLinus Torvalds } 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 4451da177e4SLinus Torvalds void device_remove_file(struct device * dev, struct device_attribute * attr) 4461da177e4SLinus Torvalds { 4471da177e4SLinus Torvalds if (get_device(dev)) { 4481da177e4SLinus Torvalds sysfs_remove_file(&dev->kobj, &attr->attr); 4491da177e4SLinus Torvalds put_device(dev); 4501da177e4SLinus Torvalds } 4511da177e4SLinus Torvalds } 4521da177e4SLinus Torvalds 4532589f188SGreg Kroah-Hartman /** 4542589f188SGreg Kroah-Hartman * device_create_bin_file - create sysfs binary attribute file for device. 4552589f188SGreg Kroah-Hartman * @dev: device. 4562589f188SGreg Kroah-Hartman * @attr: device binary attribute descriptor. 4572589f188SGreg Kroah-Hartman */ 4582589f188SGreg Kroah-Hartman int device_create_bin_file(struct device *dev, struct bin_attribute *attr) 4592589f188SGreg Kroah-Hartman { 4602589f188SGreg Kroah-Hartman int error = -EINVAL; 4612589f188SGreg Kroah-Hartman if (dev) 4622589f188SGreg Kroah-Hartman error = sysfs_create_bin_file(&dev->kobj, attr); 4632589f188SGreg Kroah-Hartman return error; 4642589f188SGreg Kroah-Hartman } 4652589f188SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(device_create_bin_file); 4662589f188SGreg Kroah-Hartman 4672589f188SGreg Kroah-Hartman /** 4682589f188SGreg Kroah-Hartman * device_remove_bin_file - remove sysfs binary attribute file 4692589f188SGreg Kroah-Hartman * @dev: device. 4702589f188SGreg Kroah-Hartman * @attr: device binary attribute descriptor. 4712589f188SGreg Kroah-Hartman */ 4722589f188SGreg Kroah-Hartman void device_remove_bin_file(struct device *dev, struct bin_attribute *attr) 4732589f188SGreg Kroah-Hartman { 4742589f188SGreg Kroah-Hartman if (dev) 4752589f188SGreg Kroah-Hartman sysfs_remove_bin_file(&dev->kobj, attr); 4762589f188SGreg Kroah-Hartman } 4772589f188SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(device_remove_bin_file); 4782589f188SGreg Kroah-Hartman 479d9a9cdfbSAlan Stern /** 480d9a9cdfbSAlan Stern * device_schedule_callback - helper to schedule a callback for a device 481d9a9cdfbSAlan Stern * @dev: device. 482d9a9cdfbSAlan Stern * @func: callback function to invoke later. 483d9a9cdfbSAlan Stern * 484d9a9cdfbSAlan Stern * Attribute methods must not unregister themselves or their parent device 485d9a9cdfbSAlan Stern * (which would amount to the same thing). Attempts to do so will deadlock, 486d9a9cdfbSAlan Stern * since unregistration is mutually exclusive with driver callbacks. 487d9a9cdfbSAlan Stern * 488d9a9cdfbSAlan Stern * Instead methods can call this routine, which will attempt to allocate 489d9a9cdfbSAlan Stern * and schedule a workqueue request to call back @func with @dev as its 490d9a9cdfbSAlan Stern * argument in the workqueue's process context. @dev will be pinned until 491d9a9cdfbSAlan Stern * @func returns. 492d9a9cdfbSAlan Stern * 493d9a9cdfbSAlan Stern * Returns 0 if the request was submitted, -ENOMEM if storage could not 494d9a9cdfbSAlan Stern * be allocated. 495d9a9cdfbSAlan Stern * 496d9a9cdfbSAlan Stern * NOTE: This routine won't work if CONFIG_SYSFS isn't set! It uses an 497d9a9cdfbSAlan Stern * underlying sysfs routine (since it is intended for use by attribute 498d9a9cdfbSAlan Stern * methods), and if sysfs isn't available you'll get nothing but -ENOSYS. 499d9a9cdfbSAlan Stern */ 500d9a9cdfbSAlan Stern int device_schedule_callback(struct device *dev, 501d9a9cdfbSAlan Stern void (*func)(struct device *)) 502d9a9cdfbSAlan Stern { 503d9a9cdfbSAlan Stern return sysfs_schedule_callback(&dev->kobj, 504d9a9cdfbSAlan Stern (void (*)(void *)) func, dev); 505d9a9cdfbSAlan Stern } 506d9a9cdfbSAlan Stern EXPORT_SYMBOL_GPL(device_schedule_callback); 507d9a9cdfbSAlan Stern 50834bb61f9SJames Bottomley static void klist_children_get(struct klist_node *n) 50934bb61f9SJames Bottomley { 51034bb61f9SJames Bottomley struct device *dev = container_of(n, struct device, knode_parent); 51134bb61f9SJames Bottomley 51234bb61f9SJames Bottomley get_device(dev); 51334bb61f9SJames Bottomley } 51434bb61f9SJames Bottomley 51534bb61f9SJames Bottomley static void klist_children_put(struct klist_node *n) 51634bb61f9SJames Bottomley { 51734bb61f9SJames Bottomley struct device *dev = container_of(n, struct device, knode_parent); 51834bb61f9SJames Bottomley 51934bb61f9SJames Bottomley put_device(dev); 52034bb61f9SJames Bottomley } 52134bb61f9SJames Bottomley 5221da177e4SLinus Torvalds 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 5341da177e4SLinus Torvalds void device_initialize(struct device *dev) 5351da177e4SLinus Torvalds { 5361da177e4SLinus Torvalds kobj_set_kset_s(dev, devices_subsys); 5371da177e4SLinus Torvalds kobject_init(&dev->kobj); 53834bb61f9SJames Bottomley klist_init(&dev->klist_children, klist_children_get, 53934bb61f9SJames Bottomley klist_children_put); 5401da177e4SLinus Torvalds INIT_LIST_HEAD(&dev->dma_pools); 54123681e47SGreg Kroah-Hartman INIT_LIST_HEAD(&dev->node); 542af70316aSmochel@digitalimplant.org init_MUTEX(&dev->sem); 5439ac7849eSTejun Heo spin_lock_init(&dev->devres_lock); 5449ac7849eSTejun Heo INIT_LIST_HEAD(&dev->devres_head); 5450ac85241SDavid Brownell device_init_wakeup(dev, 0); 54687348136SChristoph Hellwig set_dev_node(dev, -1); 5471da177e4SLinus Torvalds } 5481da177e4SLinus Torvalds 54940fa5422SGreg Kroah-Hartman #ifdef CONFIG_SYSFS_DEPRECATED 550c744aeaeSCornelia Huck static struct kobject * get_device_parent(struct device *dev, 551c744aeaeSCornelia Huck struct device *parent) 55240fa5422SGreg Kroah-Hartman { 55340fa5422SGreg Kroah-Hartman /* Set the parent to the class, not the parent device */ 55440fa5422SGreg Kroah-Hartman /* this keeps sysfs from having a symlink to make old udevs happy */ 55540fa5422SGreg Kroah-Hartman if (dev->class) 556c744aeaeSCornelia Huck return &dev->class->subsys.kset.kobj; 55740fa5422SGreg Kroah-Hartman else if (parent) 558c744aeaeSCornelia Huck return &parent->kobj; 55940fa5422SGreg Kroah-Hartman 560c744aeaeSCornelia Huck return NULL; 56140fa5422SGreg Kroah-Hartman } 56240fa5422SGreg Kroah-Hartman #else 563c744aeaeSCornelia Huck static struct kobject *virtual_device_parent(struct device *dev) 564f0ee61a6SGreg Kroah-Hartman { 565f0ee61a6SGreg Kroah-Hartman static struct kobject *virtual_dir = NULL; 566f0ee61a6SGreg Kroah-Hartman 567f0ee61a6SGreg Kroah-Hartman if (!virtual_dir) 568f0ee61a6SGreg Kroah-Hartman virtual_dir = kobject_add_dir(&devices_subsys.kset.kobj, "virtual"); 569f0ee61a6SGreg Kroah-Hartman 57086406245SKay Sievers return virtual_dir; 571f0ee61a6SGreg Kroah-Hartman } 572f0ee61a6SGreg Kroah-Hartman 573c744aeaeSCornelia Huck static struct kobject * get_device_parent(struct device *dev, 574c744aeaeSCornelia Huck struct device *parent) 57540fa5422SGreg Kroah-Hartman { 57686406245SKay Sievers if (dev->class) { 57786406245SKay Sievers struct kobject *kobj = NULL; 57886406245SKay Sievers struct kobject *parent_kobj; 57986406245SKay Sievers struct kobject *k; 58086406245SKay Sievers 58186406245SKay Sievers /* 58286406245SKay Sievers * If we have no parent, we live in "virtual". 58386406245SKay Sievers * Class-devices with a bus-device as parent, live 58486406245SKay Sievers * in a class-directory to prevent namespace collisions. 58586406245SKay Sievers */ 58686406245SKay Sievers if (parent == NULL) 58786406245SKay Sievers parent_kobj = virtual_device_parent(dev); 58886406245SKay Sievers else if (parent->class) 58986406245SKay Sievers return &parent->kobj; 59086406245SKay Sievers else 59186406245SKay Sievers parent_kobj = &parent->kobj; 59286406245SKay Sievers 59386406245SKay Sievers /* find our class-directory at the parent and reference it */ 59486406245SKay Sievers spin_lock(&dev->class->class_dirs.list_lock); 59586406245SKay Sievers list_for_each_entry(k, &dev->class->class_dirs.list, entry) 59686406245SKay Sievers if (k->parent == parent_kobj) { 59786406245SKay Sievers kobj = kobject_get(k); 59886406245SKay Sievers break; 59986406245SKay Sievers } 60086406245SKay Sievers spin_unlock(&dev->class->class_dirs.list_lock); 60186406245SKay Sievers if (kobj) 60286406245SKay Sievers return kobj; 60386406245SKay Sievers 60486406245SKay Sievers /* or create a new class-directory at the parent device */ 60586406245SKay Sievers return kobject_kset_add_dir(&dev->class->class_dirs, 60686406245SKay Sievers parent_kobj, dev->class->name); 60786406245SKay Sievers } 60886406245SKay Sievers 60986406245SKay Sievers if (parent) 610c744aeaeSCornelia Huck return &parent->kobj; 611c744aeaeSCornelia Huck return NULL; 612c744aeaeSCornelia Huck } 613c744aeaeSCornelia Huck #endif 61486406245SKay Sievers 615c744aeaeSCornelia Huck static int setup_parent(struct device *dev, struct device *parent) 616c744aeaeSCornelia Huck { 617c744aeaeSCornelia Huck struct kobject *kobj; 618c744aeaeSCornelia Huck kobj = get_device_parent(dev, parent); 619c744aeaeSCornelia Huck if (IS_ERR(kobj)) 620c744aeaeSCornelia Huck return PTR_ERR(kobj); 621c744aeaeSCornelia Huck if (kobj) 622c744aeaeSCornelia Huck dev->kobj.parent = kobj; 62340fa5422SGreg Kroah-Hartman return 0; 62440fa5422SGreg Kroah-Hartman } 62540fa5422SGreg Kroah-Hartman 6261da177e4SLinus Torvalds /** 6271da177e4SLinus Torvalds * device_add - add device to device hierarchy. 6281da177e4SLinus Torvalds * @dev: device. 6291da177e4SLinus Torvalds * 6301da177e4SLinus Torvalds * This is part 2 of device_register(), though may be called 6311da177e4SLinus Torvalds * separately _iff_ device_initialize() has been called separately. 6321da177e4SLinus Torvalds * 6331da177e4SLinus Torvalds * This adds it to the kobject hierarchy via kobject_add(), adds it 6341da177e4SLinus Torvalds * to the global and sibling lists for the device, then 6351da177e4SLinus Torvalds * adds it to the other relevant subsystems of the driver model. 6361da177e4SLinus Torvalds */ 6371da177e4SLinus Torvalds int device_add(struct device *dev) 6381da177e4SLinus Torvalds { 6391da177e4SLinus Torvalds struct device *parent = NULL; 640e9a7d305SGreg Kroah-Hartman char *class_name = NULL; 641c47ed219SGreg Kroah-Hartman struct class_interface *class_intf; 6421da177e4SLinus Torvalds int error = -EINVAL; 6431da177e4SLinus Torvalds 6441da177e4SLinus Torvalds dev = get_device(dev); 6451da177e4SLinus Torvalds if (!dev || !strlen(dev->bus_id)) 6461da177e4SLinus Torvalds goto Error; 6471da177e4SLinus Torvalds 64840fa5422SGreg Kroah-Hartman pr_debug("DEV: registering device: ID = '%s'\n", dev->bus_id); 649c205ef48SGreg Kroah-Hartman 6501da177e4SLinus Torvalds parent = get_device(dev->parent); 65140fa5422SGreg Kroah-Hartman error = setup_parent(dev, parent); 65240fa5422SGreg Kroah-Hartman if (error) 65340fa5422SGreg Kroah-Hartman goto Error; 6541da177e4SLinus Torvalds 6551da177e4SLinus Torvalds /* first, register with generic layer. */ 6561da177e4SLinus Torvalds kobject_set_name(&dev->kobj, "%s", dev->bus_id); 65740fa5422SGreg Kroah-Hartman error = kobject_add(&dev->kobj); 65840fa5422SGreg Kroah-Hartman if (error) 6591da177e4SLinus Torvalds goto Error; 660a7fd6706SKay Sievers 66137022644SBrian Walsh /* notify platform of device entry */ 66237022644SBrian Walsh if (platform_notify) 66337022644SBrian Walsh platform_notify(dev); 66437022644SBrian Walsh 665116af378SBenjamin Herrenschmidt /* notify clients of device entry (new way) */ 666116af378SBenjamin Herrenschmidt if (dev->bus) 667116af378SBenjamin Herrenschmidt blocking_notifier_call_chain(&dev->bus->bus_notifier, 668116af378SBenjamin Herrenschmidt BUS_NOTIFY_ADD_DEVICE, dev); 669116af378SBenjamin Herrenschmidt 670a7fd6706SKay Sievers dev->uevent_attr.attr.name = "uevent"; 67116574dccSKay Sievers dev->uevent_attr.attr.mode = S_IRUGO | S_IWUSR; 672a7fd6706SKay Sievers if (dev->driver) 673a7fd6706SKay Sievers dev->uevent_attr.attr.owner = dev->driver->owner; 674a7fd6706SKay Sievers dev->uevent_attr.store = store_uevent; 67516574dccSKay Sievers dev->uevent_attr.show = show_uevent; 676a306eea4SCornelia Huck error = device_create_file(dev, &dev->uevent_attr); 677a306eea4SCornelia Huck if (error) 678a306eea4SCornelia Huck goto attrError; 679a7fd6706SKay Sievers 68023681e47SGreg Kroah-Hartman if (MAJOR(dev->devt)) { 68123681e47SGreg Kroah-Hartman struct device_attribute *attr; 68223681e47SGreg Kroah-Hartman attr = kzalloc(sizeof(*attr), GFP_KERNEL); 68323681e47SGreg Kroah-Hartman if (!attr) { 68423681e47SGreg Kroah-Hartman error = -ENOMEM; 685a306eea4SCornelia Huck goto ueventattrError; 68623681e47SGreg Kroah-Hartman } 68723681e47SGreg Kroah-Hartman attr->attr.name = "dev"; 68823681e47SGreg Kroah-Hartman attr->attr.mode = S_IRUGO; 68923681e47SGreg Kroah-Hartman if (dev->driver) 69023681e47SGreg Kroah-Hartman attr->attr.owner = dev->driver->owner; 69123681e47SGreg Kroah-Hartman attr->show = show_dev; 69223681e47SGreg Kroah-Hartman error = device_create_file(dev, attr); 69323681e47SGreg Kroah-Hartman if (error) { 69423681e47SGreg Kroah-Hartman kfree(attr); 695a306eea4SCornelia Huck goto ueventattrError; 69623681e47SGreg Kroah-Hartman } 69723681e47SGreg Kroah-Hartman 69823681e47SGreg Kroah-Hartman dev->devt_attr = attr; 69923681e47SGreg Kroah-Hartman } 70023681e47SGreg Kroah-Hartman 701b9d9c82bSKay Sievers if (dev->class) { 702b9d9c82bSKay Sievers sysfs_create_link(&dev->kobj, &dev->class->subsys.kset.kobj, 703b9d9c82bSKay Sievers "subsystem"); 70440fa5422SGreg Kroah-Hartman /* If this is not a "fake" compatible device, then create the 70540fa5422SGreg Kroah-Hartman * symlink from the class to the device. */ 70640fa5422SGreg Kroah-Hartman if (dev->kobj.parent != &dev->class->subsys.kset.kobj) 70740fa5422SGreg Kroah-Hartman sysfs_create_link(&dev->class->subsys.kset.kobj, 70840fa5422SGreg Kroah-Hartman &dev->kobj, dev->bus_id); 70964bb5d2cSGreg Kroah-Hartman if (parent) { 710cb360bbfSCornelia Huck sysfs_create_link(&dev->kobj, &dev->parent->kobj, 711cb360bbfSCornelia Huck "device"); 712f7f3461dSGreg Kroah-Hartman #ifdef CONFIG_SYSFS_DEPRECATED 713cb360bbfSCornelia Huck class_name = make_class_name(dev->class->name, 714cb360bbfSCornelia Huck &dev->kobj); 715cb360bbfSCornelia Huck if (class_name) 716cb360bbfSCornelia Huck sysfs_create_link(&dev->parent->kobj, 717cb360bbfSCornelia Huck &dev->kobj, class_name); 71899ef3ef8SKay Sievers #endif 71964bb5d2cSGreg Kroah-Hartman } 720f7f3461dSGreg Kroah-Hartman } 72123681e47SGreg Kroah-Hartman 7222620efefSGreg Kroah-Hartman if ((error = device_add_attrs(dev))) 7232620efefSGreg Kroah-Hartman goto AttrsError; 7241da177e4SLinus Torvalds if ((error = device_pm_add(dev))) 7251da177e4SLinus Torvalds goto PMError; 7261da177e4SLinus Torvalds if ((error = bus_add_device(dev))) 7271da177e4SLinus Torvalds goto BusError; 72853877d06SKay Sievers kobject_uevent(&dev->kobj, KOBJ_ADD); 729c6a46696SCornelia Huck bus_attach_device(dev); 7301da177e4SLinus Torvalds if (parent) 731d856f1e3SJames Bottomley klist_add_tail(&dev->knode_parent, &parent->klist_children); 7321da177e4SLinus Torvalds 7335d9fd169SGreg Kroah-Hartman if (dev->class) { 7345d9fd169SGreg Kroah-Hartman down(&dev->class->sem); 735c47ed219SGreg Kroah-Hartman /* tie the class to the device */ 7365d9fd169SGreg Kroah-Hartman list_add_tail(&dev->node, &dev->class->devices); 737c47ed219SGreg Kroah-Hartman 738c47ed219SGreg Kroah-Hartman /* notify any interfaces that the device is here */ 739c47ed219SGreg Kroah-Hartman list_for_each_entry(class_intf, &dev->class->interfaces, node) 740c47ed219SGreg Kroah-Hartman if (class_intf->add_dev) 741c47ed219SGreg Kroah-Hartman class_intf->add_dev(dev, class_intf); 7425d9fd169SGreg Kroah-Hartman up(&dev->class->sem); 7435d9fd169SGreg Kroah-Hartman } 7441da177e4SLinus Torvalds Done: 745e9a7d305SGreg Kroah-Hartman kfree(class_name); 7461da177e4SLinus Torvalds put_device(dev); 7471da177e4SLinus Torvalds return error; 7481da177e4SLinus Torvalds BusError: 7491da177e4SLinus Torvalds device_pm_remove(dev); 7501da177e4SLinus Torvalds PMError: 751116af378SBenjamin Herrenschmidt if (dev->bus) 752116af378SBenjamin Herrenschmidt blocking_notifier_call_chain(&dev->bus->bus_notifier, 753116af378SBenjamin Herrenschmidt BUS_NOTIFY_DEL_DEVICE, dev); 7542620efefSGreg Kroah-Hartman device_remove_attrs(dev); 7552620efefSGreg Kroah-Hartman AttrsError: 75623681e47SGreg Kroah-Hartman if (dev->devt_attr) { 75723681e47SGreg Kroah-Hartman device_remove_file(dev, dev->devt_attr); 75823681e47SGreg Kroah-Hartman kfree(dev->devt_attr); 75982f0cf9bSJames Simmons } 76082f0cf9bSJames Simmons 76182f0cf9bSJames Simmons if (dev->class) { 76282f0cf9bSJames Simmons sysfs_remove_link(&dev->kobj, "subsystem"); 76382f0cf9bSJames Simmons /* If this is not a "fake" compatible device, remove the 76482f0cf9bSJames Simmons * symlink from the class to the device. */ 76582f0cf9bSJames Simmons if (dev->kobj.parent != &dev->class->subsys.kset.kobj) 76682f0cf9bSJames Simmons sysfs_remove_link(&dev->class->subsys.kset.kobj, 76782f0cf9bSJames Simmons dev->bus_id); 76882f0cf9bSJames Simmons if (parent) { 769f7f3461dSGreg Kroah-Hartman #ifdef CONFIG_SYSFS_DEPRECATED 77082f0cf9bSJames Simmons char *class_name = make_class_name(dev->class->name, 77182f0cf9bSJames Simmons &dev->kobj); 77282f0cf9bSJames Simmons if (class_name) 77382f0cf9bSJames Simmons sysfs_remove_link(&dev->parent->kobj, 77482f0cf9bSJames Simmons class_name); 77582f0cf9bSJames Simmons kfree(class_name); 776f7f3461dSGreg Kroah-Hartman #endif 77782f0cf9bSJames Simmons sysfs_remove_link(&dev->kobj, "device"); 77882f0cf9bSJames Simmons } 77923681e47SGreg Kroah-Hartman } 780a306eea4SCornelia Huck ueventattrError: 781a306eea4SCornelia Huck device_remove_file(dev, &dev->uevent_attr); 78223681e47SGreg Kroah-Hartman attrError: 783312c004dSKay Sievers kobject_uevent(&dev->kobj, KOBJ_REMOVE); 7841da177e4SLinus Torvalds kobject_del(&dev->kobj); 7851da177e4SLinus Torvalds Error: 7861da177e4SLinus Torvalds if (parent) 7871da177e4SLinus Torvalds put_device(parent); 7881da177e4SLinus Torvalds goto Done; 7891da177e4SLinus Torvalds } 7901da177e4SLinus Torvalds 7911da177e4SLinus Torvalds 7921da177e4SLinus Torvalds /** 7931da177e4SLinus Torvalds * device_register - register a device with the system. 7941da177e4SLinus Torvalds * @dev: pointer to the device structure 7951da177e4SLinus Torvalds * 7961da177e4SLinus Torvalds * This happens in two clean steps - initialize the device 7971da177e4SLinus Torvalds * and add it to the system. The two steps can be called 7981da177e4SLinus Torvalds * separately, but this is the easiest and most common. 7991da177e4SLinus Torvalds * I.e. you should only call the two helpers separately if 8001da177e4SLinus Torvalds * have a clearly defined need to use and refcount the device 8011da177e4SLinus Torvalds * before it is added to the hierarchy. 8021da177e4SLinus Torvalds */ 8031da177e4SLinus Torvalds 8041da177e4SLinus Torvalds int device_register(struct device *dev) 8051da177e4SLinus Torvalds { 8061da177e4SLinus Torvalds device_initialize(dev); 8071da177e4SLinus Torvalds return device_add(dev); 8081da177e4SLinus Torvalds } 8091da177e4SLinus Torvalds 8101da177e4SLinus Torvalds 8111da177e4SLinus Torvalds /** 8121da177e4SLinus Torvalds * get_device - increment reference count for device. 8131da177e4SLinus Torvalds * @dev: device. 8141da177e4SLinus Torvalds * 8151da177e4SLinus Torvalds * This simply forwards the call to kobject_get(), though 8161da177e4SLinus Torvalds * we do take care to provide for the case that we get a NULL 8171da177e4SLinus Torvalds * pointer passed in. 8181da177e4SLinus Torvalds */ 8191da177e4SLinus Torvalds 8201da177e4SLinus Torvalds struct device * get_device(struct device * dev) 8211da177e4SLinus Torvalds { 8221da177e4SLinus Torvalds return dev ? to_dev(kobject_get(&dev->kobj)) : NULL; 8231da177e4SLinus Torvalds } 8241da177e4SLinus Torvalds 8251da177e4SLinus Torvalds 8261da177e4SLinus Torvalds /** 8271da177e4SLinus Torvalds * put_device - decrement reference count. 8281da177e4SLinus Torvalds * @dev: device in question. 8291da177e4SLinus Torvalds */ 8301da177e4SLinus Torvalds void put_device(struct device * dev) 8311da177e4SLinus Torvalds { 8321da177e4SLinus Torvalds if (dev) 8331da177e4SLinus Torvalds kobject_put(&dev->kobj); 8341da177e4SLinus Torvalds } 8351da177e4SLinus Torvalds 8361da177e4SLinus Torvalds 8371da177e4SLinus Torvalds /** 8381da177e4SLinus Torvalds * device_del - delete device from system. 8391da177e4SLinus Torvalds * @dev: device. 8401da177e4SLinus Torvalds * 8411da177e4SLinus Torvalds * This is the first part of the device unregistration 8421da177e4SLinus Torvalds * sequence. This removes the device from the lists we control 8431da177e4SLinus Torvalds * from here, has it removed from the other driver model 8441da177e4SLinus Torvalds * subsystems it was added to in device_add(), and removes it 8451da177e4SLinus Torvalds * from the kobject hierarchy. 8461da177e4SLinus Torvalds * 8471da177e4SLinus Torvalds * NOTE: this should be called manually _iff_ device_add() was 8481da177e4SLinus Torvalds * also called manually. 8491da177e4SLinus Torvalds */ 8501da177e4SLinus Torvalds 8511da177e4SLinus Torvalds void device_del(struct device * dev) 8521da177e4SLinus Torvalds { 8531da177e4SLinus Torvalds struct device * parent = dev->parent; 854c47ed219SGreg Kroah-Hartman struct class_interface *class_intf; 8551da177e4SLinus Torvalds 8561da177e4SLinus Torvalds if (parent) 857d62c0f9fSPatrick Mochel klist_del(&dev->knode_parent); 85882189b98SCatalin Marinas if (dev->devt_attr) { 85923681e47SGreg Kroah-Hartman device_remove_file(dev, dev->devt_attr); 86082189b98SCatalin Marinas kfree(dev->devt_attr); 86182189b98SCatalin Marinas } 862b9d9c82bSKay Sievers if (dev->class) { 863b9d9c82bSKay Sievers sysfs_remove_link(&dev->kobj, "subsystem"); 86440fa5422SGreg Kroah-Hartman /* If this is not a "fake" compatible device, remove the 86540fa5422SGreg Kroah-Hartman * symlink from the class to the device. */ 86640fa5422SGreg Kroah-Hartman if (dev->kobj.parent != &dev->class->subsys.kset.kobj) 86740fa5422SGreg Kroah-Hartman sysfs_remove_link(&dev->class->subsys.kset.kobj, 86840fa5422SGreg Kroah-Hartman dev->bus_id); 86964bb5d2cSGreg Kroah-Hartman if (parent) { 870f7f3461dSGreg Kroah-Hartman #ifdef CONFIG_SYSFS_DEPRECATED 87199ef3ef8SKay Sievers char *class_name = make_class_name(dev->class->name, 87299ef3ef8SKay Sievers &dev->kobj); 873cb360bbfSCornelia Huck if (class_name) 874cb360bbfSCornelia Huck sysfs_remove_link(&dev->parent->kobj, 875cb360bbfSCornelia Huck class_name); 876e9a7d305SGreg Kroah-Hartman kfree(class_name); 877f7f3461dSGreg Kroah-Hartman #endif 87899ef3ef8SKay Sievers sysfs_remove_link(&dev->kobj, "device"); 87999ef3ef8SKay Sievers } 88099ef3ef8SKay Sievers 8815d9fd169SGreg Kroah-Hartman down(&dev->class->sem); 882c47ed219SGreg Kroah-Hartman /* notify any interfaces that the device is now gone */ 883c47ed219SGreg Kroah-Hartman list_for_each_entry(class_intf, &dev->class->interfaces, node) 884c47ed219SGreg Kroah-Hartman if (class_intf->remove_dev) 885c47ed219SGreg Kroah-Hartman class_intf->remove_dev(dev, class_intf); 886c47ed219SGreg Kroah-Hartman /* remove the device from the class list */ 8875d9fd169SGreg Kroah-Hartman list_del_init(&dev->node); 8885d9fd169SGreg Kroah-Hartman up(&dev->class->sem); 88986406245SKay Sievers 89086406245SKay Sievers /* If we live in a parent class-directory, unreference it */ 89186406245SKay Sievers if (dev->kobj.parent->kset == &dev->class->class_dirs) { 89286406245SKay Sievers struct device *d; 89386406245SKay Sievers int other = 0; 89486406245SKay Sievers 89586406245SKay Sievers /* 89686406245SKay Sievers * if we are the last child of our class, delete 89786406245SKay Sievers * our class-directory at this parent 89886406245SKay Sievers */ 89986406245SKay Sievers down(&dev->class->sem); 90086406245SKay Sievers list_for_each_entry(d, &dev->class->devices, node) { 90186406245SKay Sievers if (d == dev) 90286406245SKay Sievers continue; 90386406245SKay Sievers if (d->kobj.parent == dev->kobj.parent) { 90486406245SKay Sievers other = 1; 90586406245SKay Sievers break; 90686406245SKay Sievers } 90786406245SKay Sievers } 90886406245SKay Sievers if (!other) 90986406245SKay Sievers kobject_del(dev->kobj.parent); 91086406245SKay Sievers 91186406245SKay Sievers kobject_put(dev->kobj.parent); 91286406245SKay Sievers up(&dev->class->sem); 91386406245SKay Sievers } 914b9d9c82bSKay Sievers } 915a7fd6706SKay Sievers device_remove_file(dev, &dev->uevent_attr); 9162620efefSGreg Kroah-Hartman device_remove_attrs(dev); 91728953533SBenjamin Herrenschmidt bus_remove_device(dev); 9181da177e4SLinus Torvalds 9192f8d16a9STejun Heo /* 9202f8d16a9STejun Heo * Some platform devices are driven without driver attached 9212f8d16a9STejun Heo * and managed resources may have been acquired. Make sure 9222f8d16a9STejun Heo * all resources are released. 9232f8d16a9STejun Heo */ 9242f8d16a9STejun Heo devres_release_all(dev); 9252f8d16a9STejun Heo 9261da177e4SLinus Torvalds /* Notify the platform of the removal, in case they 9271da177e4SLinus Torvalds * need to do anything... 9281da177e4SLinus Torvalds */ 9291da177e4SLinus Torvalds if (platform_notify_remove) 9301da177e4SLinus Torvalds platform_notify_remove(dev); 931116af378SBenjamin Herrenschmidt if (dev->bus) 932116af378SBenjamin Herrenschmidt blocking_notifier_call_chain(&dev->bus->bus_notifier, 933116af378SBenjamin Herrenschmidt BUS_NOTIFY_DEL_DEVICE, dev); 9341da177e4SLinus Torvalds device_pm_remove(dev); 935312c004dSKay Sievers kobject_uevent(&dev->kobj, KOBJ_REMOVE); 9361da177e4SLinus Torvalds kobject_del(&dev->kobj); 9371da177e4SLinus Torvalds if (parent) 9381da177e4SLinus Torvalds put_device(parent); 9391da177e4SLinus Torvalds } 9401da177e4SLinus Torvalds 9411da177e4SLinus Torvalds /** 9421da177e4SLinus Torvalds * device_unregister - unregister device from system. 9431da177e4SLinus Torvalds * @dev: device going away. 9441da177e4SLinus Torvalds * 9451da177e4SLinus Torvalds * We do this in two parts, like we do device_register(). First, 9461da177e4SLinus Torvalds * we remove it from all the subsystems with device_del(), then 9471da177e4SLinus Torvalds * we decrement the reference count via put_device(). If that 9481da177e4SLinus Torvalds * is the final reference count, the device will be cleaned up 9491da177e4SLinus Torvalds * via device_release() above. Otherwise, the structure will 9501da177e4SLinus Torvalds * stick around until the final reference to the device is dropped. 9511da177e4SLinus Torvalds */ 9521da177e4SLinus Torvalds void device_unregister(struct device * dev) 9531da177e4SLinus Torvalds { 9541da177e4SLinus Torvalds pr_debug("DEV: Unregistering device. ID = '%s'\n", dev->bus_id); 9551da177e4SLinus Torvalds device_del(dev); 9561da177e4SLinus Torvalds put_device(dev); 9571da177e4SLinus Torvalds } 9581da177e4SLinus Torvalds 9591da177e4SLinus Torvalds 96036239577Smochel@digitalimplant.org static struct device * next_device(struct klist_iter * i) 96136239577Smochel@digitalimplant.org { 96236239577Smochel@digitalimplant.org struct klist_node * n = klist_next(i); 96336239577Smochel@digitalimplant.org return n ? container_of(n, struct device, knode_parent) : NULL; 96436239577Smochel@digitalimplant.org } 96536239577Smochel@digitalimplant.org 9661da177e4SLinus Torvalds /** 9671da177e4SLinus Torvalds * device_for_each_child - device child iterator. 968c41455fbSRandy Dunlap * @parent: parent struct device. 9691da177e4SLinus Torvalds * @data: data for the callback. 9701da177e4SLinus Torvalds * @fn: function to be called for each device. 9711da177e4SLinus Torvalds * 972c41455fbSRandy Dunlap * Iterate over @parent's child devices, and call @fn for each, 9731da177e4SLinus Torvalds * passing it @data. 9741da177e4SLinus Torvalds * 9751da177e4SLinus Torvalds * We check the return of @fn each time. If it returns anything 9761da177e4SLinus Torvalds * other than 0, we break out and return that value. 9771da177e4SLinus Torvalds */ 97836239577Smochel@digitalimplant.org int device_for_each_child(struct device * parent, void * data, 9791da177e4SLinus Torvalds int (*fn)(struct device *, void *)) 9801da177e4SLinus Torvalds { 98136239577Smochel@digitalimplant.org struct klist_iter i; 9821da177e4SLinus Torvalds struct device * child; 9831da177e4SLinus Torvalds int error = 0; 9841da177e4SLinus Torvalds 98536239577Smochel@digitalimplant.org klist_iter_init(&parent->klist_children, &i); 98636239577Smochel@digitalimplant.org while ((child = next_device(&i)) && !error) 98736239577Smochel@digitalimplant.org error = fn(child, data); 98836239577Smochel@digitalimplant.org klist_iter_exit(&i); 9891da177e4SLinus Torvalds return error; 9901da177e4SLinus Torvalds } 9911da177e4SLinus Torvalds 9925ab69981SCornelia Huck /** 9935ab69981SCornelia Huck * device_find_child - device iterator for locating a particular device. 9945ab69981SCornelia Huck * @parent: parent struct device 9955ab69981SCornelia Huck * @data: Data to pass to match function 9965ab69981SCornelia Huck * @match: Callback function to check device 9975ab69981SCornelia Huck * 9985ab69981SCornelia Huck * This is similar to the device_for_each_child() function above, but it 9995ab69981SCornelia Huck * returns a reference to a device that is 'found' for later use, as 10005ab69981SCornelia Huck * determined by the @match callback. 10015ab69981SCornelia Huck * 10025ab69981SCornelia Huck * The callback should return 0 if the device doesn't match and non-zero 10035ab69981SCornelia Huck * if it does. If the callback returns non-zero and a reference to the 10045ab69981SCornelia Huck * current device can be obtained, this function will return to the caller 10055ab69981SCornelia Huck * and not iterate over any more devices. 10065ab69981SCornelia Huck */ 10075ab69981SCornelia Huck struct device * device_find_child(struct device *parent, void *data, 10085ab69981SCornelia Huck int (*match)(struct device *, void *)) 10095ab69981SCornelia Huck { 10105ab69981SCornelia Huck struct klist_iter i; 10115ab69981SCornelia Huck struct device *child; 10125ab69981SCornelia Huck 10135ab69981SCornelia Huck if (!parent) 10145ab69981SCornelia Huck return NULL; 10155ab69981SCornelia Huck 10165ab69981SCornelia Huck klist_iter_init(&parent->klist_children, &i); 10175ab69981SCornelia Huck while ((child = next_device(&i))) 10185ab69981SCornelia Huck if (match(child, data) && get_device(child)) 10195ab69981SCornelia Huck break; 10205ab69981SCornelia Huck klist_iter_exit(&i); 10215ab69981SCornelia Huck return child; 10225ab69981SCornelia Huck } 10235ab69981SCornelia Huck 10241da177e4SLinus Torvalds int __init devices_init(void) 10251da177e4SLinus Torvalds { 10261da177e4SLinus Torvalds return subsystem_register(&devices_subsys); 10271da177e4SLinus Torvalds } 10281da177e4SLinus Torvalds 10291da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(device_for_each_child); 10305ab69981SCornelia Huck EXPORT_SYMBOL_GPL(device_find_child); 10311da177e4SLinus Torvalds 10321da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(device_initialize); 10331da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(device_add); 10341da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(device_register); 10351da177e4SLinus Torvalds 10361da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(device_del); 10371da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(device_unregister); 10381da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(get_device); 10391da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(put_device); 10401da177e4SLinus Torvalds 10411da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(device_create_file); 10421da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(device_remove_file); 104323681e47SGreg Kroah-Hartman 104423681e47SGreg Kroah-Hartman 104523681e47SGreg Kroah-Hartman static void device_create_release(struct device *dev) 104623681e47SGreg Kroah-Hartman { 104723681e47SGreg Kroah-Hartman pr_debug("%s called for %s\n", __FUNCTION__, dev->bus_id); 104823681e47SGreg Kroah-Hartman kfree(dev); 104923681e47SGreg Kroah-Hartman } 105023681e47SGreg Kroah-Hartman 105123681e47SGreg Kroah-Hartman /** 105223681e47SGreg Kroah-Hartman * device_create - creates a device and registers it with sysfs 105342734dafSHenrik Kretzschmar * @class: pointer to the struct class that this device should be registered to 105442734dafSHenrik Kretzschmar * @parent: pointer to the parent struct device of this new device, if any 105542734dafSHenrik Kretzschmar * @devt: the dev_t for the char device to be added 105642734dafSHenrik Kretzschmar * @fmt: string for the device's name 105723681e47SGreg Kroah-Hartman * 105842734dafSHenrik Kretzschmar * This function can be used by char device classes. A struct device 105942734dafSHenrik Kretzschmar * will be created in sysfs, registered to the specified class. 106042734dafSHenrik Kretzschmar * 106123681e47SGreg Kroah-Hartman * A "dev" file will be created, showing the dev_t for the device, if 106223681e47SGreg Kroah-Hartman * the dev_t is not 0,0. 106342734dafSHenrik Kretzschmar * If a pointer to a parent struct device is passed in, the newly created 106442734dafSHenrik Kretzschmar * struct device will be a child of that device in sysfs. 106542734dafSHenrik Kretzschmar * The pointer to the struct device will be returned from the call. 106642734dafSHenrik Kretzschmar * Any further sysfs files that might be required can be created using this 106723681e47SGreg Kroah-Hartman * pointer. 106823681e47SGreg Kroah-Hartman * 106923681e47SGreg Kroah-Hartman * Note: the struct class passed to this function must have previously 107023681e47SGreg Kroah-Hartman * been created with a call to class_create(). 107123681e47SGreg Kroah-Hartman */ 107223681e47SGreg Kroah-Hartman struct device *device_create(struct class *class, struct device *parent, 10735cbe5f8aSGreg Kroah-Hartman dev_t devt, const char *fmt, ...) 107423681e47SGreg Kroah-Hartman { 107523681e47SGreg Kroah-Hartman va_list args; 107623681e47SGreg Kroah-Hartman struct device *dev = NULL; 107723681e47SGreg Kroah-Hartman int retval = -ENODEV; 107823681e47SGreg Kroah-Hartman 107923681e47SGreg Kroah-Hartman if (class == NULL || IS_ERR(class)) 108023681e47SGreg Kroah-Hartman goto error; 108123681e47SGreg Kroah-Hartman 108223681e47SGreg Kroah-Hartman dev = kzalloc(sizeof(*dev), GFP_KERNEL); 108323681e47SGreg Kroah-Hartman if (!dev) { 108423681e47SGreg Kroah-Hartman retval = -ENOMEM; 108523681e47SGreg Kroah-Hartman goto error; 108623681e47SGreg Kroah-Hartman } 108723681e47SGreg Kroah-Hartman 108823681e47SGreg Kroah-Hartman dev->devt = devt; 108923681e47SGreg Kroah-Hartman dev->class = class; 109023681e47SGreg Kroah-Hartman dev->parent = parent; 109123681e47SGreg Kroah-Hartman dev->release = device_create_release; 109223681e47SGreg Kroah-Hartman 109323681e47SGreg Kroah-Hartman va_start(args, fmt); 109423681e47SGreg Kroah-Hartman vsnprintf(dev->bus_id, BUS_ID_SIZE, fmt, args); 109523681e47SGreg Kroah-Hartman va_end(args); 109623681e47SGreg Kroah-Hartman retval = device_register(dev); 109723681e47SGreg Kroah-Hartman if (retval) 109823681e47SGreg Kroah-Hartman goto error; 109923681e47SGreg Kroah-Hartman 110023681e47SGreg Kroah-Hartman return dev; 110123681e47SGreg Kroah-Hartman 110223681e47SGreg Kroah-Hartman error: 110323681e47SGreg Kroah-Hartman kfree(dev); 110423681e47SGreg Kroah-Hartman return ERR_PTR(retval); 110523681e47SGreg Kroah-Hartman } 110623681e47SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(device_create); 110723681e47SGreg Kroah-Hartman 110823681e47SGreg Kroah-Hartman /** 110923681e47SGreg Kroah-Hartman * device_destroy - removes a device that was created with device_create() 111042734dafSHenrik Kretzschmar * @class: pointer to the struct class that this device was registered with 111142734dafSHenrik Kretzschmar * @devt: the dev_t of the device that was previously registered 111223681e47SGreg Kroah-Hartman * 111342734dafSHenrik Kretzschmar * This call unregisters and cleans up a device that was created with a 111442734dafSHenrik Kretzschmar * call to device_create(). 111523681e47SGreg Kroah-Hartman */ 111623681e47SGreg Kroah-Hartman void device_destroy(struct class *class, dev_t devt) 111723681e47SGreg Kroah-Hartman { 111823681e47SGreg Kroah-Hartman struct device *dev = NULL; 111923681e47SGreg Kroah-Hartman struct device *dev_tmp; 112023681e47SGreg Kroah-Hartman 112123681e47SGreg Kroah-Hartman down(&class->sem); 112223681e47SGreg Kroah-Hartman list_for_each_entry(dev_tmp, &class->devices, node) { 112323681e47SGreg Kroah-Hartman if (dev_tmp->devt == devt) { 112423681e47SGreg Kroah-Hartman dev = dev_tmp; 112523681e47SGreg Kroah-Hartman break; 112623681e47SGreg Kroah-Hartman } 112723681e47SGreg Kroah-Hartman } 112823681e47SGreg Kroah-Hartman up(&class->sem); 112923681e47SGreg Kroah-Hartman 11305d9fd169SGreg Kroah-Hartman if (dev) 113123681e47SGreg Kroah-Hartman device_unregister(dev); 113223681e47SGreg Kroah-Hartman } 113323681e47SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(device_destroy); 1134a2de48caSGreg Kroah-Hartman 1135a2de48caSGreg Kroah-Hartman /** 1136a2de48caSGreg Kroah-Hartman * device_rename - renames a device 1137a2de48caSGreg Kroah-Hartman * @dev: the pointer to the struct device to be renamed 1138a2de48caSGreg Kroah-Hartman * @new_name: the new name of the device 1139a2de48caSGreg Kroah-Hartman */ 1140a2de48caSGreg Kroah-Hartman int device_rename(struct device *dev, char *new_name) 1141a2de48caSGreg Kroah-Hartman { 1142a2de48caSGreg Kroah-Hartman char *old_class_name = NULL; 1143a2de48caSGreg Kroah-Hartman char *new_class_name = NULL; 1144a2de48caSGreg Kroah-Hartman char *old_symlink_name = NULL; 1145a2de48caSGreg Kroah-Hartman int error; 1146a2de48caSGreg Kroah-Hartman 1147a2de48caSGreg Kroah-Hartman dev = get_device(dev); 1148a2de48caSGreg Kroah-Hartman if (!dev) 1149a2de48caSGreg Kroah-Hartman return -EINVAL; 1150a2de48caSGreg Kroah-Hartman 1151a2de48caSGreg Kroah-Hartman pr_debug("DEVICE: renaming '%s' to '%s'\n", dev->bus_id, new_name); 1152a2de48caSGreg Kroah-Hartman 115399ef3ef8SKay Sievers #ifdef CONFIG_SYSFS_DEPRECATED 1154a2de48caSGreg Kroah-Hartman if ((dev->class) && (dev->parent)) 1155a2de48caSGreg Kroah-Hartman old_class_name = make_class_name(dev->class->name, &dev->kobj); 115699ef3ef8SKay Sievers #endif 1157a2de48caSGreg Kroah-Hartman 1158a2de48caSGreg Kroah-Hartman if (dev->class) { 1159a2de48caSGreg Kroah-Hartman old_symlink_name = kmalloc(BUS_ID_SIZE, GFP_KERNEL); 1160952ab431SJesper Juhl if (!old_symlink_name) { 1161952ab431SJesper Juhl error = -ENOMEM; 1162952ab431SJesper Juhl goto out_free_old_class; 1163952ab431SJesper Juhl } 1164a2de48caSGreg Kroah-Hartman strlcpy(old_symlink_name, dev->bus_id, BUS_ID_SIZE); 1165a2de48caSGreg Kroah-Hartman } 1166a2de48caSGreg Kroah-Hartman 1167a2de48caSGreg Kroah-Hartman strlcpy(dev->bus_id, new_name, BUS_ID_SIZE); 1168a2de48caSGreg Kroah-Hartman 1169a2de48caSGreg Kroah-Hartman error = kobject_rename(&dev->kobj, new_name); 1170a2de48caSGreg Kroah-Hartman 117199ef3ef8SKay Sievers #ifdef CONFIG_SYSFS_DEPRECATED 1172a2de48caSGreg Kroah-Hartman if (old_class_name) { 1173a2de48caSGreg Kroah-Hartman new_class_name = make_class_name(dev->class->name, &dev->kobj); 1174a2de48caSGreg Kroah-Hartman if (new_class_name) { 1175a2de48caSGreg Kroah-Hartman sysfs_create_link(&dev->parent->kobj, &dev->kobj, 1176a2de48caSGreg Kroah-Hartman new_class_name); 1177a2de48caSGreg Kroah-Hartman sysfs_remove_link(&dev->parent->kobj, old_class_name); 1178a2de48caSGreg Kroah-Hartman } 1179a2de48caSGreg Kroah-Hartman } 118099ef3ef8SKay Sievers #endif 118199ef3ef8SKay Sievers 1182a2de48caSGreg Kroah-Hartman if (dev->class) { 1183a2de48caSGreg Kroah-Hartman sysfs_remove_link(&dev->class->subsys.kset.kobj, 1184a2de48caSGreg Kroah-Hartman old_symlink_name); 1185a2de48caSGreg Kroah-Hartman sysfs_create_link(&dev->class->subsys.kset.kobj, &dev->kobj, 1186a2de48caSGreg Kroah-Hartman dev->bus_id); 1187a2de48caSGreg Kroah-Hartman } 1188a2de48caSGreg Kroah-Hartman put_device(dev); 1189a2de48caSGreg Kroah-Hartman 1190a2de48caSGreg Kroah-Hartman kfree(new_class_name); 1191a2de48caSGreg Kroah-Hartman kfree(old_symlink_name); 1192952ab431SJesper Juhl out_free_old_class: 1193952ab431SJesper Juhl kfree(old_class_name); 1194a2de48caSGreg Kroah-Hartman 1195a2de48caSGreg Kroah-Hartman return error; 1196a2de48caSGreg Kroah-Hartman } 1197a2807dbcSJohannes Berg EXPORT_SYMBOL_GPL(device_rename); 11988a82472fSCornelia Huck 11998a82472fSCornelia Huck static int device_move_class_links(struct device *dev, 12008a82472fSCornelia Huck struct device *old_parent, 12018a82472fSCornelia Huck struct device *new_parent) 12028a82472fSCornelia Huck { 1203f7f3461dSGreg Kroah-Hartman int error = 0; 12048a82472fSCornelia Huck #ifdef CONFIG_SYSFS_DEPRECATED 12058a82472fSCornelia Huck char *class_name; 12068a82472fSCornelia Huck 12078a82472fSCornelia Huck class_name = make_class_name(dev->class->name, &dev->kobj); 12088a82472fSCornelia Huck if (!class_name) { 1209cb360bbfSCornelia Huck error = -ENOMEM; 12108a82472fSCornelia Huck goto out; 12118a82472fSCornelia Huck } 12128a82472fSCornelia Huck if (old_parent) { 12138a82472fSCornelia Huck sysfs_remove_link(&dev->kobj, "device"); 12148a82472fSCornelia Huck sysfs_remove_link(&old_parent->kobj, class_name); 12158a82472fSCornelia Huck } 1216c744aeaeSCornelia Huck if (new_parent) { 1217c744aeaeSCornelia Huck error = sysfs_create_link(&dev->kobj, &new_parent->kobj, 1218c744aeaeSCornelia Huck "device"); 12198a82472fSCornelia Huck if (error) 12208a82472fSCornelia Huck goto out; 1221c744aeaeSCornelia Huck error = sysfs_create_link(&new_parent->kobj, &dev->kobj, 1222c744aeaeSCornelia Huck class_name); 12238a82472fSCornelia Huck if (error) 12248a82472fSCornelia Huck sysfs_remove_link(&dev->kobj, "device"); 1225c744aeaeSCornelia Huck } 1226c744aeaeSCornelia Huck else 1227c744aeaeSCornelia Huck error = 0; 12288a82472fSCornelia Huck out: 12298a82472fSCornelia Huck kfree(class_name); 12308a82472fSCornelia Huck return error; 12318a82472fSCornelia Huck #else 1232f7f3461dSGreg Kroah-Hartman if (old_parent) 1233f7f3461dSGreg Kroah-Hartman sysfs_remove_link(&dev->kobj, "device"); 1234f7f3461dSGreg Kroah-Hartman if (new_parent) 1235f7f3461dSGreg Kroah-Hartman error = sysfs_create_link(&dev->kobj, &new_parent->kobj, 1236f7f3461dSGreg Kroah-Hartman "device"); 1237f7f3461dSGreg Kroah-Hartman return error; 12388a82472fSCornelia Huck #endif 12398a82472fSCornelia Huck } 12408a82472fSCornelia Huck 12418a82472fSCornelia Huck /** 12428a82472fSCornelia Huck * device_move - moves a device to a new parent 12438a82472fSCornelia Huck * @dev: the pointer to the struct device to be moved 1244c744aeaeSCornelia Huck * @new_parent: the new parent of the device (can by NULL) 12458a82472fSCornelia Huck */ 12468a82472fSCornelia Huck int device_move(struct device *dev, struct device *new_parent) 12478a82472fSCornelia Huck { 12488a82472fSCornelia Huck int error; 12498a82472fSCornelia Huck struct device *old_parent; 1250c744aeaeSCornelia Huck struct kobject *new_parent_kobj; 12518a82472fSCornelia Huck 12528a82472fSCornelia Huck dev = get_device(dev); 12538a82472fSCornelia Huck if (!dev) 12548a82472fSCornelia Huck return -EINVAL; 12558a82472fSCornelia Huck 12568a82472fSCornelia Huck new_parent = get_device(new_parent); 1257c744aeaeSCornelia Huck new_parent_kobj = get_device_parent (dev, new_parent); 1258c744aeaeSCornelia Huck if (IS_ERR(new_parent_kobj)) { 1259c744aeaeSCornelia Huck error = PTR_ERR(new_parent_kobj); 1260c744aeaeSCornelia Huck put_device(new_parent); 12618a82472fSCornelia Huck goto out; 12628a82472fSCornelia Huck } 12638a82472fSCornelia Huck pr_debug("DEVICE: moving '%s' to '%s'\n", dev->bus_id, 1264c744aeaeSCornelia Huck new_parent ? new_parent->bus_id : "<NULL>"); 1265c744aeaeSCornelia Huck error = kobject_move(&dev->kobj, new_parent_kobj); 12668a82472fSCornelia Huck if (error) { 12678a82472fSCornelia Huck put_device(new_parent); 12688a82472fSCornelia Huck goto out; 12698a82472fSCornelia Huck } 12708a82472fSCornelia Huck old_parent = dev->parent; 12718a82472fSCornelia Huck dev->parent = new_parent; 12728a82472fSCornelia Huck if (old_parent) 1273acf02d23SCornelia Huck klist_remove(&dev->knode_parent); 1274c744aeaeSCornelia Huck if (new_parent) 12758a82472fSCornelia Huck klist_add_tail(&dev->knode_parent, &new_parent->klist_children); 12768a82472fSCornelia Huck if (!dev->class) 12778a82472fSCornelia Huck goto out_put; 12788a82472fSCornelia Huck error = device_move_class_links(dev, old_parent, new_parent); 12798a82472fSCornelia Huck if (error) { 12808a82472fSCornelia Huck /* We ignore errors on cleanup since we're hosed anyway... */ 12818a82472fSCornelia Huck device_move_class_links(dev, new_parent, old_parent); 12828a82472fSCornelia Huck if (!kobject_move(&dev->kobj, &old_parent->kobj)) { 1283c744aeaeSCornelia Huck if (new_parent) 1284acf02d23SCornelia Huck klist_remove(&dev->knode_parent); 12858a82472fSCornelia Huck if (old_parent) 12868a82472fSCornelia Huck klist_add_tail(&dev->knode_parent, 12878a82472fSCornelia Huck &old_parent->klist_children); 12888a82472fSCornelia Huck } 12898a82472fSCornelia Huck put_device(new_parent); 12908a82472fSCornelia Huck goto out; 12918a82472fSCornelia Huck } 12928a82472fSCornelia Huck out_put: 12938a82472fSCornelia Huck put_device(old_parent); 12948a82472fSCornelia Huck out: 12958a82472fSCornelia Huck put_device(dev); 12968a82472fSCornelia Huck return error; 12978a82472fSCornelia Huck } 12988a82472fSCornelia Huck 12998a82472fSCornelia Huck EXPORT_SYMBOL_GPL(device_move); 1300