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 2760a96a59SKay Sievers extern const char *kobject_actions[]; 2860a96a59SKay Sievers 291da177e4SLinus Torvalds int (*platform_notify)(struct device * dev) = NULL; 301da177e4SLinus Torvalds int (*platform_notify_remove)(struct device * dev) = NULL; 311da177e4SLinus Torvalds 321da177e4SLinus Torvalds /* 331da177e4SLinus Torvalds * sysfs bindings for devices. 341da177e4SLinus Torvalds */ 351da177e4SLinus Torvalds 363e95637aSAlan Stern /** 373e95637aSAlan Stern * dev_driver_string - Return a device's driver name, if at all possible 383e95637aSAlan Stern * @dev: struct device to get the name of 393e95637aSAlan Stern * 403e95637aSAlan Stern * Will return the device's driver's name if it is bound to a device. If 413e95637aSAlan Stern * the device is not bound to a device, it will return the name of the bus 423e95637aSAlan Stern * it is attached to. If it is not attached to a bus either, an empty 433e95637aSAlan Stern * string will be returned. 443e95637aSAlan Stern */ 453e95637aSAlan Stern const char *dev_driver_string(struct device *dev) 463e95637aSAlan Stern { 473e95637aSAlan Stern return dev->driver ? dev->driver->name : 48a456b702SJean Delvare (dev->bus ? dev->bus->name : 49a456b702SJean Delvare (dev->class ? dev->class->name : "")); 503e95637aSAlan Stern } 51310a922dSMatthew Wilcox EXPORT_SYMBOL(dev_driver_string); 523e95637aSAlan Stern 531da177e4SLinus Torvalds #define to_dev(obj) container_of(obj, struct device, kobj) 541da177e4SLinus Torvalds #define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr) 551da177e4SLinus Torvalds 561da177e4SLinus Torvalds static ssize_t 571da177e4SLinus Torvalds dev_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) 581da177e4SLinus Torvalds { 591da177e4SLinus Torvalds struct device_attribute * dev_attr = to_dev_attr(attr); 601da177e4SLinus Torvalds struct device * dev = to_dev(kobj); 614a0c20bfSDmitry Torokhov ssize_t ret = -EIO; 621da177e4SLinus Torvalds 631da177e4SLinus Torvalds if (dev_attr->show) 6454b6f35cSYani Ioannou ret = dev_attr->show(dev, dev_attr, buf); 651da177e4SLinus Torvalds return ret; 661da177e4SLinus Torvalds } 671da177e4SLinus Torvalds 681da177e4SLinus Torvalds static ssize_t 691da177e4SLinus Torvalds dev_attr_store(struct kobject * kobj, struct attribute * attr, 701da177e4SLinus Torvalds const char * buf, size_t count) 711da177e4SLinus Torvalds { 721da177e4SLinus Torvalds struct device_attribute * dev_attr = to_dev_attr(attr); 731da177e4SLinus Torvalds struct device * dev = to_dev(kobj); 744a0c20bfSDmitry Torokhov ssize_t ret = -EIO; 751da177e4SLinus Torvalds 761da177e4SLinus Torvalds if (dev_attr->store) 7754b6f35cSYani Ioannou ret = dev_attr->store(dev, dev_attr, buf, count); 781da177e4SLinus Torvalds return ret; 791da177e4SLinus Torvalds } 801da177e4SLinus Torvalds 811da177e4SLinus Torvalds static struct sysfs_ops dev_sysfs_ops = { 821da177e4SLinus Torvalds .show = dev_attr_show, 831da177e4SLinus Torvalds .store = dev_attr_store, 841da177e4SLinus Torvalds }; 851da177e4SLinus Torvalds 861da177e4SLinus Torvalds 871da177e4SLinus Torvalds /** 881da177e4SLinus Torvalds * device_release - free device structure. 891da177e4SLinus Torvalds * @kobj: device's kobject. 901da177e4SLinus Torvalds * 911da177e4SLinus Torvalds * This is called once the reference count for the object 921da177e4SLinus Torvalds * reaches 0. We forward the call to the device's release 931da177e4SLinus Torvalds * method, which should handle actually freeing the structure. 941da177e4SLinus Torvalds */ 951da177e4SLinus Torvalds static void device_release(struct kobject * kobj) 961da177e4SLinus Torvalds { 971da177e4SLinus Torvalds struct device * dev = to_dev(kobj); 981da177e4SLinus Torvalds 991da177e4SLinus Torvalds if (dev->release) 1001da177e4SLinus Torvalds dev->release(dev); 101f9f852dfSKay Sievers else if (dev->type && dev->type->release) 102f9f852dfSKay Sievers dev->type->release(dev); 1032620efefSGreg Kroah-Hartman else if (dev->class && dev->class->dev_release) 1042620efefSGreg Kroah-Hartman dev->class->dev_release(dev); 1051da177e4SLinus Torvalds else { 1061da177e4SLinus Torvalds printk(KERN_ERR "Device '%s' does not have a release() function, " 1071da177e4SLinus Torvalds "it is broken and must be fixed.\n", 1081da177e4SLinus Torvalds dev->bus_id); 1091da177e4SLinus Torvalds WARN_ON(1); 1101da177e4SLinus Torvalds } 1111da177e4SLinus Torvalds } 1121da177e4SLinus Torvalds 1131da177e4SLinus Torvalds static struct kobj_type ktype_device = { 1141da177e4SLinus Torvalds .release = device_release, 1151da177e4SLinus Torvalds .sysfs_ops = &dev_sysfs_ops, 1161da177e4SLinus Torvalds }; 1171da177e4SLinus Torvalds 1181da177e4SLinus Torvalds 119312c004dSKay Sievers static int dev_uevent_filter(struct kset *kset, struct kobject *kobj) 1201da177e4SLinus Torvalds { 1211da177e4SLinus Torvalds struct kobj_type *ktype = get_ktype(kobj); 1221da177e4SLinus Torvalds 1231da177e4SLinus Torvalds if (ktype == &ktype_device) { 1241da177e4SLinus Torvalds struct device *dev = to_dev(kobj); 12583b5fb4cSCornelia Huck if (dev->uevent_suppress) 12683b5fb4cSCornelia Huck return 0; 1271da177e4SLinus Torvalds if (dev->bus) 1281da177e4SLinus Torvalds return 1; 12923681e47SGreg Kroah-Hartman if (dev->class) 13023681e47SGreg Kroah-Hartman return 1; 1311da177e4SLinus Torvalds } 1321da177e4SLinus Torvalds return 0; 1331da177e4SLinus Torvalds } 1341da177e4SLinus Torvalds 135312c004dSKay Sievers static const char *dev_uevent_name(struct kset *kset, struct kobject *kobj) 1361da177e4SLinus Torvalds { 1371da177e4SLinus Torvalds struct device *dev = to_dev(kobj); 1381da177e4SLinus Torvalds 13923681e47SGreg Kroah-Hartman if (dev->bus) 1401da177e4SLinus Torvalds return dev->bus->name; 14123681e47SGreg Kroah-Hartman if (dev->class) 14223681e47SGreg Kroah-Hartman return dev->class->name; 14323681e47SGreg Kroah-Hartman return NULL; 1441da177e4SLinus Torvalds } 1451da177e4SLinus Torvalds 146312c004dSKay Sievers static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp, 1471da177e4SLinus Torvalds int num_envp, char *buffer, int buffer_size) 1481da177e4SLinus Torvalds { 1491da177e4SLinus Torvalds struct device *dev = to_dev(kobj); 1501da177e4SLinus Torvalds int i = 0; 1511da177e4SLinus Torvalds int length = 0; 1521da177e4SLinus Torvalds int retval = 0; 1531da177e4SLinus Torvalds 15423681e47SGreg Kroah-Hartman /* add the major/minor if present */ 15523681e47SGreg Kroah-Hartman if (MAJOR(dev->devt)) { 15623681e47SGreg Kroah-Hartman add_uevent_var(envp, num_envp, &i, 15723681e47SGreg Kroah-Hartman buffer, buffer_size, &length, 15823681e47SGreg Kroah-Hartman "MAJOR=%u", MAJOR(dev->devt)); 15923681e47SGreg Kroah-Hartman add_uevent_var(envp, num_envp, &i, 16023681e47SGreg Kroah-Hartman buffer, buffer_size, &length, 16123681e47SGreg Kroah-Hartman "MINOR=%u", MINOR(dev->devt)); 16223681e47SGreg Kroah-Hartman } 16323681e47SGreg Kroah-Hartman 164414264f9SKay Sievers if (dev->type && dev->type->name) 165414264f9SKay Sievers add_uevent_var(envp, num_envp, &i, 166414264f9SKay Sievers buffer, buffer_size, &length, 167414264f9SKay Sievers "DEVTYPE=%s", dev->type->name); 168414264f9SKay Sievers 169239378f1SKay Sievers if (dev->driver) 170d81d9d6bSKay Sievers add_uevent_var(envp, num_envp, &i, 171d81d9d6bSKay Sievers buffer, buffer_size, &length, 172d81d9d6bSKay Sievers "DRIVER=%s", dev->driver->name); 173239378f1SKay Sievers 174a87cb2acSKay Sievers #ifdef CONFIG_SYSFS_DEPRECATED 175239378f1SKay Sievers if (dev->class) { 176239378f1SKay Sievers struct device *parent = dev->parent; 177239378f1SKay Sievers 178239378f1SKay Sievers /* find first bus device in parent chain */ 179239378f1SKay Sievers while (parent && !parent->bus) 180239378f1SKay Sievers parent = parent->parent; 181239378f1SKay Sievers if (parent && parent->bus) { 182239378f1SKay Sievers const char *path; 183239378f1SKay Sievers 184239378f1SKay Sievers path = kobject_get_path(&parent->kobj, GFP_KERNEL); 1852c7afd12SKay Sievers if (path) { 186239378f1SKay Sievers add_uevent_var(envp, num_envp, &i, 187239378f1SKay Sievers buffer, buffer_size, &length, 188239378f1SKay Sievers "PHYSDEVPATH=%s", path); 189239378f1SKay Sievers kfree(path); 1902c7afd12SKay Sievers } 191239378f1SKay Sievers 192239378f1SKay Sievers add_uevent_var(envp, num_envp, &i, 193239378f1SKay Sievers buffer, buffer_size, &length, 194239378f1SKay Sievers "PHYSDEVBUS=%s", parent->bus->name); 195239378f1SKay Sievers 196239378f1SKay Sievers if (parent->driver) 197239378f1SKay Sievers add_uevent_var(envp, num_envp, &i, 198239378f1SKay Sievers buffer, buffer_size, &length, 199239378f1SKay Sievers "PHYSDEVDRIVER=%s", parent->driver->name); 200239378f1SKay Sievers } 201239378f1SKay Sievers } else if (dev->bus) { 202239378f1SKay Sievers add_uevent_var(envp, num_envp, &i, 203239378f1SKay Sievers buffer, buffer_size, &length, 204239378f1SKay Sievers "PHYSDEVBUS=%s", dev->bus->name); 205239378f1SKay Sievers 206239378f1SKay Sievers if (dev->driver) 207312c004dSKay Sievers add_uevent_var(envp, num_envp, &i, 2081da177e4SLinus Torvalds buffer, buffer_size, &length, 2091da177e4SLinus Torvalds "PHYSDEVDRIVER=%s", dev->driver->name); 210d81d9d6bSKay Sievers } 211239378f1SKay Sievers #endif 2121da177e4SLinus Torvalds 2131da177e4SLinus Torvalds /* terminate, set to next free slot, shrink available space */ 2141da177e4SLinus Torvalds envp[i] = NULL; 2151da177e4SLinus Torvalds envp = &envp[i]; 2161da177e4SLinus Torvalds num_envp -= i; 2171da177e4SLinus Torvalds buffer = &buffer[length]; 2181da177e4SLinus Torvalds buffer_size -= length; 2191da177e4SLinus Torvalds 220312c004dSKay Sievers if (dev->bus && dev->bus->uevent) { 2211da177e4SLinus Torvalds /* have the bus specific function add its stuff */ 222312c004dSKay Sievers retval = dev->bus->uevent(dev, envp, num_envp, buffer, buffer_size); 223f9f852dfSKay Sievers if (retval) 224f9f852dfSKay Sievers pr_debug ("%s: bus uevent() returned %d\n", 2251da177e4SLinus Torvalds __FUNCTION__, retval); 2261da177e4SLinus Torvalds } 2271da177e4SLinus Torvalds 2282620efefSGreg Kroah-Hartman if (dev->class && dev->class->dev_uevent) { 2292620efefSGreg Kroah-Hartman /* have the class specific function add its stuff */ 2302620efefSGreg Kroah-Hartman retval = dev->class->dev_uevent(dev, envp, num_envp, buffer, buffer_size); 231f9f852dfSKay Sievers if (retval) 232f9f852dfSKay Sievers pr_debug("%s: class uevent() returned %d\n", 2332620efefSGreg Kroah-Hartman __FUNCTION__, retval); 2342620efefSGreg Kroah-Hartman } 235f9f852dfSKay Sievers 236f9f852dfSKay Sievers if (dev->type && dev->type->uevent) { 237f9f852dfSKay Sievers /* have the device type specific fuction add its stuff */ 238f9f852dfSKay Sievers retval = dev->type->uevent(dev, envp, num_envp, buffer, buffer_size); 239f9f852dfSKay Sievers if (retval) 240f9f852dfSKay Sievers pr_debug("%s: dev_type uevent() returned %d\n", 241f9f852dfSKay Sievers __FUNCTION__, retval); 2422620efefSGreg Kroah-Hartman } 2432620efefSGreg Kroah-Hartman 2441da177e4SLinus Torvalds return retval; 2451da177e4SLinus Torvalds } 2461da177e4SLinus Torvalds 247312c004dSKay Sievers static struct kset_uevent_ops device_uevent_ops = { 248312c004dSKay Sievers .filter = dev_uevent_filter, 249312c004dSKay Sievers .name = dev_uevent_name, 250312c004dSKay Sievers .uevent = dev_uevent, 2511da177e4SLinus Torvalds }; 2521da177e4SLinus Torvalds 25316574dccSKay Sievers static ssize_t show_uevent(struct device *dev, struct device_attribute *attr, 25416574dccSKay Sievers char *buf) 25516574dccSKay Sievers { 25616574dccSKay Sievers struct kobject *top_kobj; 25716574dccSKay Sievers struct kset *kset; 25816574dccSKay Sievers char *envp[32]; 259c7308c81SGreg Kroah-Hartman char *data = NULL; 26016574dccSKay Sievers char *pos; 26116574dccSKay Sievers int i; 26216574dccSKay Sievers size_t count = 0; 26316574dccSKay Sievers int retval; 26416574dccSKay Sievers 26516574dccSKay Sievers /* search the kset, the device belongs to */ 26616574dccSKay Sievers top_kobj = &dev->kobj; 26716574dccSKay Sievers if (!top_kobj->kset && top_kobj->parent) { 26816574dccSKay Sievers do { 26916574dccSKay Sievers top_kobj = top_kobj->parent; 27016574dccSKay Sievers } while (!top_kobj->kset && top_kobj->parent); 27116574dccSKay Sievers } 27216574dccSKay Sievers if (!top_kobj->kset) 27316574dccSKay Sievers goto out; 27416574dccSKay Sievers kset = top_kobj->kset; 27516574dccSKay Sievers if (!kset->uevent_ops || !kset->uevent_ops->uevent) 27616574dccSKay Sievers goto out; 27716574dccSKay Sievers 27816574dccSKay Sievers /* respect filter */ 27916574dccSKay Sievers if (kset->uevent_ops && kset->uevent_ops->filter) 28016574dccSKay Sievers if (!kset->uevent_ops->filter(kset, &dev->kobj)) 28116574dccSKay Sievers goto out; 28216574dccSKay Sievers 283c7308c81SGreg Kroah-Hartman data = (char *)get_zeroed_page(GFP_KERNEL); 284c7308c81SGreg Kroah-Hartman if (!data) 285c7308c81SGreg Kroah-Hartman return -ENOMEM; 286c7308c81SGreg Kroah-Hartman 28716574dccSKay Sievers /* let the kset specific function add its keys */ 28816574dccSKay Sievers pos = data; 28916574dccSKay Sievers retval = kset->uevent_ops->uevent(kset, &dev->kobj, 29016574dccSKay Sievers envp, ARRAY_SIZE(envp), 29116574dccSKay Sievers pos, PAGE_SIZE); 29216574dccSKay Sievers if (retval) 29316574dccSKay Sievers goto out; 29416574dccSKay Sievers 29516574dccSKay Sievers /* copy keys to file */ 29616574dccSKay Sievers for (i = 0; envp[i]; i++) { 29716574dccSKay Sievers pos = &buf[count]; 29816574dccSKay Sievers count += sprintf(pos, "%s\n", envp[i]); 29916574dccSKay Sievers } 30016574dccSKay Sievers out: 301c7308c81SGreg Kroah-Hartman free_page((unsigned long)data); 30216574dccSKay Sievers return count; 30316574dccSKay Sievers } 30416574dccSKay Sievers 305a7fd6706SKay Sievers static ssize_t store_uevent(struct device *dev, struct device_attribute *attr, 306a7fd6706SKay Sievers const char *buf, size_t count) 307a7fd6706SKay Sievers { 30860a96a59SKay Sievers size_t len = count; 30960a96a59SKay Sievers enum kobject_action action; 31060a96a59SKay Sievers 31160a96a59SKay Sievers if (len && buf[len-1] == '\n') 31260a96a59SKay Sievers len--; 31360a96a59SKay Sievers 31460a96a59SKay Sievers for (action = 0; action < KOBJ_MAX; action++) { 31560a96a59SKay Sievers if (strncmp(kobject_actions[action], buf, len) != 0) 31660a96a59SKay Sievers continue; 31760a96a59SKay Sievers if (kobject_actions[action][len] != '\0') 31860a96a59SKay Sievers continue; 31960a96a59SKay Sievers kobject_uevent(&dev->kobj, action); 32060a96a59SKay Sievers goto out; 32160a96a59SKay Sievers } 32260a96a59SKay Sievers 32322af74f3SKay Sievers dev_err(dev, "uevent: unsupported action-string; this will " 32460a96a59SKay Sievers "be ignored in a future kernel version\n"); 325312c004dSKay Sievers kobject_uevent(&dev->kobj, KOBJ_ADD); 32660a96a59SKay Sievers out: 327a7fd6706SKay Sievers return count; 328a7fd6706SKay Sievers } 329a7fd6706SKay Sievers 330ad6a1e1cSTejun Heo static struct device_attribute uevent_attr = 331ad6a1e1cSTejun Heo __ATTR(uevent, S_IRUGO | S_IWUSR, show_uevent, store_uevent); 332ad6a1e1cSTejun Heo 333621a1672SDmitry Torokhov static int device_add_attributes(struct device *dev, 334621a1672SDmitry Torokhov struct device_attribute *attrs) 335de0ff00dSGreg Kroah-Hartman { 336de0ff00dSGreg Kroah-Hartman int error = 0; 337621a1672SDmitry Torokhov int i; 338de0ff00dSGreg Kroah-Hartman 339621a1672SDmitry Torokhov if (attrs) { 340621a1672SDmitry Torokhov for (i = 0; attr_name(attrs[i]); i++) { 341621a1672SDmitry Torokhov error = device_create_file(dev, &attrs[i]); 342621a1672SDmitry Torokhov if (error) 343621a1672SDmitry Torokhov break; 344621a1672SDmitry Torokhov } 345621a1672SDmitry Torokhov if (error) 346de0ff00dSGreg Kroah-Hartman while (--i >= 0) 347621a1672SDmitry Torokhov device_remove_file(dev, &attrs[i]); 348de0ff00dSGreg Kroah-Hartman } 349de0ff00dSGreg Kroah-Hartman return error; 350de0ff00dSGreg Kroah-Hartman } 351de0ff00dSGreg Kroah-Hartman 352621a1672SDmitry Torokhov static void device_remove_attributes(struct device *dev, 353621a1672SDmitry Torokhov struct device_attribute *attrs) 354de0ff00dSGreg Kroah-Hartman { 355de0ff00dSGreg Kroah-Hartman int i; 356621a1672SDmitry Torokhov 357621a1672SDmitry Torokhov if (attrs) 358621a1672SDmitry Torokhov for (i = 0; attr_name(attrs[i]); i++) 359621a1672SDmitry Torokhov device_remove_file(dev, &attrs[i]); 360621a1672SDmitry Torokhov } 361621a1672SDmitry Torokhov 362621a1672SDmitry Torokhov static int device_add_groups(struct device *dev, 363621a1672SDmitry Torokhov struct attribute_group **groups) 364621a1672SDmitry Torokhov { 365621a1672SDmitry Torokhov int error = 0; 366621a1672SDmitry Torokhov int i; 367621a1672SDmitry Torokhov 368621a1672SDmitry Torokhov if (groups) { 369621a1672SDmitry Torokhov for (i = 0; groups[i]; i++) { 370621a1672SDmitry Torokhov error = sysfs_create_group(&dev->kobj, groups[i]); 371621a1672SDmitry Torokhov if (error) { 372621a1672SDmitry Torokhov while (--i >= 0) 373621a1672SDmitry Torokhov sysfs_remove_group(&dev->kobj, groups[i]); 374621a1672SDmitry Torokhov break; 375de0ff00dSGreg Kroah-Hartman } 376de0ff00dSGreg Kroah-Hartman } 377de0ff00dSGreg Kroah-Hartman } 378621a1672SDmitry Torokhov return error; 379621a1672SDmitry Torokhov } 380621a1672SDmitry Torokhov 381621a1672SDmitry Torokhov static void device_remove_groups(struct device *dev, 382621a1672SDmitry Torokhov struct attribute_group **groups) 383621a1672SDmitry Torokhov { 384621a1672SDmitry Torokhov int i; 385621a1672SDmitry Torokhov 386621a1672SDmitry Torokhov if (groups) 387621a1672SDmitry Torokhov for (i = 0; groups[i]; i++) 388621a1672SDmitry Torokhov sysfs_remove_group(&dev->kobj, groups[i]); 389621a1672SDmitry Torokhov } 390de0ff00dSGreg Kroah-Hartman 3912620efefSGreg Kroah-Hartman static int device_add_attrs(struct device *dev) 3922620efefSGreg Kroah-Hartman { 3932620efefSGreg Kroah-Hartman struct class *class = dev->class; 394f9f852dfSKay Sievers struct device_type *type = dev->type; 395621a1672SDmitry Torokhov int error; 3962620efefSGreg Kroah-Hartman 397621a1672SDmitry Torokhov if (class) { 398621a1672SDmitry Torokhov error = device_add_attributes(dev, class->dev_attrs); 3992620efefSGreg Kroah-Hartman if (error) 400621a1672SDmitry Torokhov return error; 401f9f852dfSKay Sievers } 402f9f852dfSKay Sievers 403621a1672SDmitry Torokhov if (type) { 404621a1672SDmitry Torokhov error = device_add_groups(dev, type->groups); 405f9f852dfSKay Sievers if (error) 406621a1672SDmitry Torokhov goto err_remove_class_attrs; 407f9f852dfSKay Sievers } 408621a1672SDmitry Torokhov 409621a1672SDmitry Torokhov error = device_add_groups(dev, dev->groups); 410f9f852dfSKay Sievers if (error) 411621a1672SDmitry Torokhov goto err_remove_type_groups; 412621a1672SDmitry Torokhov 413621a1672SDmitry Torokhov return 0; 414621a1672SDmitry Torokhov 415621a1672SDmitry Torokhov err_remove_type_groups: 416621a1672SDmitry Torokhov if (type) 417621a1672SDmitry Torokhov device_remove_groups(dev, type->groups); 418621a1672SDmitry Torokhov err_remove_class_attrs: 419621a1672SDmitry Torokhov if (class) 420621a1672SDmitry Torokhov device_remove_attributes(dev, class->dev_attrs); 421f9f852dfSKay Sievers 4222620efefSGreg Kroah-Hartman return error; 4232620efefSGreg Kroah-Hartman } 4242620efefSGreg Kroah-Hartman 4252620efefSGreg Kroah-Hartman static void device_remove_attrs(struct device *dev) 4262620efefSGreg Kroah-Hartman { 4272620efefSGreg Kroah-Hartman struct class *class = dev->class; 428f9f852dfSKay Sievers struct device_type *type = dev->type; 4292620efefSGreg Kroah-Hartman 430621a1672SDmitry Torokhov device_remove_groups(dev, dev->groups); 431f9f852dfSKay Sievers 432621a1672SDmitry Torokhov if (type) 433621a1672SDmitry Torokhov device_remove_groups(dev, type->groups); 434621a1672SDmitry Torokhov 435621a1672SDmitry Torokhov if (class) 436621a1672SDmitry Torokhov device_remove_attributes(dev, class->dev_attrs); 4372620efefSGreg Kroah-Hartman } 4382620efefSGreg Kroah-Hartman 4392620efefSGreg Kroah-Hartman 44023681e47SGreg Kroah-Hartman static ssize_t show_dev(struct device *dev, struct device_attribute *attr, 44123681e47SGreg Kroah-Hartman char *buf) 44223681e47SGreg Kroah-Hartman { 44323681e47SGreg Kroah-Hartman return print_dev_t(buf, dev->devt); 44423681e47SGreg Kroah-Hartman } 44523681e47SGreg Kroah-Hartman 446ad6a1e1cSTejun Heo static struct device_attribute devt_attr = 447ad6a1e1cSTejun Heo __ATTR(dev, S_IRUGO, show_dev, NULL); 448ad6a1e1cSTejun Heo 4490863afb3SMartin Waitz /* 4500863afb3SMartin Waitz * devices_subsys - structure to be registered with kobject core. 4511da177e4SLinus Torvalds */ 4521da177e4SLinus Torvalds 453312c004dSKay Sievers decl_subsys(devices, &ktype_device, &device_uevent_ops); 4541da177e4SLinus Torvalds 4551da177e4SLinus Torvalds 4561da177e4SLinus Torvalds /** 4571da177e4SLinus Torvalds * device_create_file - create sysfs attribute file for device. 4581da177e4SLinus Torvalds * @dev: device. 4591da177e4SLinus Torvalds * @attr: device attribute descriptor. 4601da177e4SLinus Torvalds */ 4611da177e4SLinus Torvalds 4621da177e4SLinus Torvalds int device_create_file(struct device * dev, struct device_attribute * attr) 4631da177e4SLinus Torvalds { 4641da177e4SLinus Torvalds int error = 0; 4651da177e4SLinus Torvalds if (get_device(dev)) { 4661da177e4SLinus Torvalds error = sysfs_create_file(&dev->kobj, &attr->attr); 4671da177e4SLinus Torvalds put_device(dev); 4681da177e4SLinus Torvalds } 4691da177e4SLinus Torvalds return error; 4701da177e4SLinus Torvalds } 4711da177e4SLinus Torvalds 4721da177e4SLinus Torvalds /** 4731da177e4SLinus Torvalds * device_remove_file - remove sysfs attribute file. 4741da177e4SLinus Torvalds * @dev: device. 4751da177e4SLinus Torvalds * @attr: device attribute descriptor. 4761da177e4SLinus Torvalds */ 4771da177e4SLinus Torvalds 4781da177e4SLinus Torvalds void device_remove_file(struct device * dev, struct device_attribute * attr) 4791da177e4SLinus Torvalds { 4801da177e4SLinus Torvalds if (get_device(dev)) { 4811da177e4SLinus Torvalds sysfs_remove_file(&dev->kobj, &attr->attr); 4821da177e4SLinus Torvalds put_device(dev); 4831da177e4SLinus Torvalds } 4841da177e4SLinus Torvalds } 4851da177e4SLinus Torvalds 4862589f188SGreg Kroah-Hartman /** 4872589f188SGreg Kroah-Hartman * device_create_bin_file - create sysfs binary attribute file for device. 4882589f188SGreg Kroah-Hartman * @dev: device. 4892589f188SGreg Kroah-Hartman * @attr: device binary attribute descriptor. 4902589f188SGreg Kroah-Hartman */ 4912589f188SGreg Kroah-Hartman int device_create_bin_file(struct device *dev, struct bin_attribute *attr) 4922589f188SGreg Kroah-Hartman { 4932589f188SGreg Kroah-Hartman int error = -EINVAL; 4942589f188SGreg Kroah-Hartman if (dev) 4952589f188SGreg Kroah-Hartman error = sysfs_create_bin_file(&dev->kobj, attr); 4962589f188SGreg Kroah-Hartman return error; 4972589f188SGreg Kroah-Hartman } 4982589f188SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(device_create_bin_file); 4992589f188SGreg Kroah-Hartman 5002589f188SGreg Kroah-Hartman /** 5012589f188SGreg Kroah-Hartman * device_remove_bin_file - remove sysfs binary attribute file 5022589f188SGreg Kroah-Hartman * @dev: device. 5032589f188SGreg Kroah-Hartman * @attr: device binary attribute descriptor. 5042589f188SGreg Kroah-Hartman */ 5052589f188SGreg Kroah-Hartman void device_remove_bin_file(struct device *dev, struct bin_attribute *attr) 5062589f188SGreg Kroah-Hartman { 5072589f188SGreg Kroah-Hartman if (dev) 5082589f188SGreg Kroah-Hartman sysfs_remove_bin_file(&dev->kobj, attr); 5092589f188SGreg Kroah-Hartman } 5102589f188SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(device_remove_bin_file); 5112589f188SGreg Kroah-Hartman 512d9a9cdfbSAlan Stern /** 513523ded71SAlan Stern * device_schedule_callback_owner - helper to schedule a callback for a device 514d9a9cdfbSAlan Stern * @dev: device. 515d9a9cdfbSAlan Stern * @func: callback function to invoke later. 516523ded71SAlan Stern * @owner: module owning the callback routine 517d9a9cdfbSAlan Stern * 518d9a9cdfbSAlan Stern * Attribute methods must not unregister themselves or their parent device 519d9a9cdfbSAlan Stern * (which would amount to the same thing). Attempts to do so will deadlock, 520d9a9cdfbSAlan Stern * since unregistration is mutually exclusive with driver callbacks. 521d9a9cdfbSAlan Stern * 522d9a9cdfbSAlan Stern * Instead methods can call this routine, which will attempt to allocate 523d9a9cdfbSAlan Stern * and schedule a workqueue request to call back @func with @dev as its 524d9a9cdfbSAlan Stern * argument in the workqueue's process context. @dev will be pinned until 525d9a9cdfbSAlan Stern * @func returns. 526d9a9cdfbSAlan Stern * 527523ded71SAlan Stern * This routine is usually called via the inline device_schedule_callback(), 528523ded71SAlan Stern * which automatically sets @owner to THIS_MODULE. 529523ded71SAlan Stern * 530d9a9cdfbSAlan Stern * Returns 0 if the request was submitted, -ENOMEM if storage could not 531523ded71SAlan Stern * be allocated, -ENODEV if a reference to @owner isn't available. 532d9a9cdfbSAlan Stern * 533d9a9cdfbSAlan Stern * NOTE: This routine won't work if CONFIG_SYSFS isn't set! It uses an 534d9a9cdfbSAlan Stern * underlying sysfs routine (since it is intended for use by attribute 535d9a9cdfbSAlan Stern * methods), and if sysfs isn't available you'll get nothing but -ENOSYS. 536d9a9cdfbSAlan Stern */ 537523ded71SAlan Stern int device_schedule_callback_owner(struct device *dev, 538523ded71SAlan Stern void (*func)(struct device *), struct module *owner) 539d9a9cdfbSAlan Stern { 540d9a9cdfbSAlan Stern return sysfs_schedule_callback(&dev->kobj, 541523ded71SAlan Stern (void (*)(void *)) func, dev, owner); 542d9a9cdfbSAlan Stern } 543523ded71SAlan Stern EXPORT_SYMBOL_GPL(device_schedule_callback_owner); 544d9a9cdfbSAlan Stern 54534bb61f9SJames Bottomley static void klist_children_get(struct klist_node *n) 54634bb61f9SJames Bottomley { 54734bb61f9SJames Bottomley struct device *dev = container_of(n, struct device, knode_parent); 54834bb61f9SJames Bottomley 54934bb61f9SJames Bottomley get_device(dev); 55034bb61f9SJames Bottomley } 55134bb61f9SJames Bottomley 55234bb61f9SJames Bottomley static void klist_children_put(struct klist_node *n) 55334bb61f9SJames Bottomley { 55434bb61f9SJames Bottomley struct device *dev = container_of(n, struct device, knode_parent); 55534bb61f9SJames Bottomley 55634bb61f9SJames Bottomley put_device(dev); 55734bb61f9SJames Bottomley } 55834bb61f9SJames Bottomley 5591da177e4SLinus Torvalds 5601da177e4SLinus Torvalds /** 5611da177e4SLinus Torvalds * device_initialize - init device structure. 5621da177e4SLinus Torvalds * @dev: device. 5631da177e4SLinus Torvalds * 5641da177e4SLinus Torvalds * This prepares the device for use by other layers, 5651da177e4SLinus Torvalds * including adding it to the device hierarchy. 5661da177e4SLinus Torvalds * It is the first half of device_register(), if called by 5671da177e4SLinus Torvalds * that, though it can also be called separately, so one 5681da177e4SLinus Torvalds * may use @dev's fields (e.g. the refcount). 5691da177e4SLinus Torvalds */ 5701da177e4SLinus Torvalds 5711da177e4SLinus Torvalds void device_initialize(struct device *dev) 5721da177e4SLinus Torvalds { 5731da177e4SLinus Torvalds kobj_set_kset_s(dev, devices_subsys); 5741da177e4SLinus Torvalds kobject_init(&dev->kobj); 57534bb61f9SJames Bottomley klist_init(&dev->klist_children, klist_children_get, 57634bb61f9SJames Bottomley klist_children_put); 5771da177e4SLinus Torvalds INIT_LIST_HEAD(&dev->dma_pools); 57823681e47SGreg Kroah-Hartman INIT_LIST_HEAD(&dev->node); 579af70316aSmochel@digitalimplant.org init_MUTEX(&dev->sem); 5809ac7849eSTejun Heo spin_lock_init(&dev->devres_lock); 5819ac7849eSTejun Heo INIT_LIST_HEAD(&dev->devres_head); 5820ac85241SDavid Brownell device_init_wakeup(dev, 0); 58387348136SChristoph Hellwig set_dev_node(dev, -1); 5841da177e4SLinus Torvalds } 5851da177e4SLinus Torvalds 58640fa5422SGreg Kroah-Hartman #ifdef CONFIG_SYSFS_DEPRECATED 587c744aeaeSCornelia Huck static struct kobject * get_device_parent(struct device *dev, 588c744aeaeSCornelia Huck struct device *parent) 58940fa5422SGreg Kroah-Hartman { 59040fa5422SGreg Kroah-Hartman /* Set the parent to the class, not the parent device */ 59140fa5422SGreg Kroah-Hartman /* this keeps sysfs from having a symlink to make old udevs happy */ 59240fa5422SGreg Kroah-Hartman if (dev->class) 593823bccfcSGreg Kroah-Hartman return &dev->class->subsys.kobj; 59440fa5422SGreg Kroah-Hartman else if (parent) 595c744aeaeSCornelia Huck return &parent->kobj; 59640fa5422SGreg Kroah-Hartman 597c744aeaeSCornelia Huck return NULL; 59840fa5422SGreg Kroah-Hartman } 59940fa5422SGreg Kroah-Hartman #else 600c744aeaeSCornelia Huck static struct kobject *virtual_device_parent(struct device *dev) 601f0ee61a6SGreg Kroah-Hartman { 602f0ee61a6SGreg Kroah-Hartman static struct kobject *virtual_dir = NULL; 603f0ee61a6SGreg Kroah-Hartman 604f0ee61a6SGreg Kroah-Hartman if (!virtual_dir) 605823bccfcSGreg Kroah-Hartman virtual_dir = kobject_add_dir(&devices_subsys.kobj, "virtual"); 606f0ee61a6SGreg Kroah-Hartman 60786406245SKay Sievers return virtual_dir; 608f0ee61a6SGreg Kroah-Hartman } 609f0ee61a6SGreg Kroah-Hartman 610c744aeaeSCornelia Huck static struct kobject * get_device_parent(struct device *dev, 611c744aeaeSCornelia Huck struct device *parent) 61240fa5422SGreg Kroah-Hartman { 61386406245SKay Sievers if (dev->class) { 61486406245SKay Sievers struct kobject *kobj = NULL; 61586406245SKay Sievers struct kobject *parent_kobj; 61686406245SKay Sievers struct kobject *k; 61786406245SKay Sievers 61886406245SKay Sievers /* 61986406245SKay Sievers * If we have no parent, we live in "virtual". 62086406245SKay Sievers * Class-devices with a bus-device as parent, live 62186406245SKay Sievers * in a class-directory to prevent namespace collisions. 62286406245SKay Sievers */ 62386406245SKay Sievers if (parent == NULL) 62486406245SKay Sievers parent_kobj = virtual_device_parent(dev); 62586406245SKay Sievers else if (parent->class) 62686406245SKay Sievers return &parent->kobj; 62786406245SKay Sievers else 62886406245SKay Sievers parent_kobj = &parent->kobj; 62986406245SKay Sievers 63086406245SKay Sievers /* find our class-directory at the parent and reference it */ 63186406245SKay Sievers spin_lock(&dev->class->class_dirs.list_lock); 63286406245SKay Sievers list_for_each_entry(k, &dev->class->class_dirs.list, entry) 63386406245SKay Sievers if (k->parent == parent_kobj) { 63486406245SKay Sievers kobj = kobject_get(k); 63586406245SKay Sievers break; 63686406245SKay Sievers } 63786406245SKay Sievers spin_unlock(&dev->class->class_dirs.list_lock); 63886406245SKay Sievers if (kobj) 63986406245SKay Sievers return kobj; 64086406245SKay Sievers 64186406245SKay Sievers /* or create a new class-directory at the parent device */ 64286406245SKay Sievers return kobject_kset_add_dir(&dev->class->class_dirs, 64386406245SKay Sievers parent_kobj, dev->class->name); 64486406245SKay Sievers } 64586406245SKay Sievers 64686406245SKay Sievers if (parent) 647c744aeaeSCornelia Huck return &parent->kobj; 648c744aeaeSCornelia Huck return NULL; 649c744aeaeSCornelia Huck } 650c744aeaeSCornelia Huck #endif 65186406245SKay Sievers 652c744aeaeSCornelia Huck static int setup_parent(struct device *dev, struct device *parent) 653c744aeaeSCornelia Huck { 654c744aeaeSCornelia Huck struct kobject *kobj; 655c744aeaeSCornelia Huck kobj = get_device_parent(dev, parent); 656c744aeaeSCornelia Huck if (IS_ERR(kobj)) 657c744aeaeSCornelia Huck return PTR_ERR(kobj); 658c744aeaeSCornelia Huck if (kobj) 659c744aeaeSCornelia Huck dev->kobj.parent = kobj; 66040fa5422SGreg Kroah-Hartman return 0; 66140fa5422SGreg Kroah-Hartman } 66240fa5422SGreg Kroah-Hartman 6632ee97cafSCornelia Huck static int device_add_class_symlinks(struct device *dev) 6642ee97cafSCornelia Huck { 6652ee97cafSCornelia Huck int error; 6662ee97cafSCornelia Huck 6672ee97cafSCornelia Huck if (!dev->class) 6682ee97cafSCornelia Huck return 0; 6692ee97cafSCornelia Huck error = sysfs_create_link(&dev->kobj, &dev->class->subsys.kobj, 6702ee97cafSCornelia Huck "subsystem"); 6712ee97cafSCornelia Huck if (error) 6722ee97cafSCornelia Huck goto out; 6732ee97cafSCornelia Huck /* 6742ee97cafSCornelia Huck * If this is not a "fake" compatible device, then create the 6752ee97cafSCornelia Huck * symlink from the class to the device. 6762ee97cafSCornelia Huck */ 6772ee97cafSCornelia Huck if (dev->kobj.parent != &dev->class->subsys.kobj) { 6782ee97cafSCornelia Huck error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj, 6792ee97cafSCornelia Huck dev->bus_id); 6802ee97cafSCornelia Huck if (error) 6812ee97cafSCornelia Huck goto out_subsys; 6822ee97cafSCornelia Huck } 6832ee97cafSCornelia Huck /* only bus-device parents get a "device"-link */ 6842ee97cafSCornelia Huck if (dev->parent && dev->parent->bus) { 6852ee97cafSCornelia Huck error = sysfs_create_link(&dev->kobj, &dev->parent->kobj, 6862ee97cafSCornelia Huck "device"); 6872ee97cafSCornelia Huck if (error) 6882ee97cafSCornelia Huck goto out_busid; 6892ee97cafSCornelia Huck #ifdef CONFIG_SYSFS_DEPRECATED 6902ee97cafSCornelia Huck { 6912ee97cafSCornelia Huck char * class_name = make_class_name(dev->class->name, 6922ee97cafSCornelia Huck &dev->kobj); 6932ee97cafSCornelia Huck if (class_name) 6942ee97cafSCornelia Huck error = sysfs_create_link(&dev->parent->kobj, 6952ee97cafSCornelia Huck &dev->kobj, class_name); 6962ee97cafSCornelia Huck kfree(class_name); 6972ee97cafSCornelia Huck if (error) 6982ee97cafSCornelia Huck goto out_device; 6992ee97cafSCornelia Huck } 7002ee97cafSCornelia Huck #endif 7012ee97cafSCornelia Huck } 7022ee97cafSCornelia Huck return 0; 7032ee97cafSCornelia Huck 7042ee97cafSCornelia Huck #ifdef CONFIG_SYSFS_DEPRECATED 7052ee97cafSCornelia Huck out_device: 7062ee97cafSCornelia Huck if (dev->parent) 7072ee97cafSCornelia Huck sysfs_remove_link(&dev->kobj, "device"); 7082ee97cafSCornelia Huck #endif 7092ee97cafSCornelia Huck out_busid: 7102ee97cafSCornelia Huck if (dev->kobj.parent != &dev->class->subsys.kobj) 7112ee97cafSCornelia Huck sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id); 7122ee97cafSCornelia Huck out_subsys: 7132ee97cafSCornelia Huck sysfs_remove_link(&dev->kobj, "subsystem"); 7142ee97cafSCornelia Huck out: 7152ee97cafSCornelia Huck return error; 7162ee97cafSCornelia Huck } 7172ee97cafSCornelia Huck 7182ee97cafSCornelia Huck static void device_remove_class_symlinks(struct device *dev) 7192ee97cafSCornelia Huck { 7202ee97cafSCornelia Huck if (!dev->class) 7212ee97cafSCornelia Huck return; 7222ee97cafSCornelia Huck if (dev->parent) { 7232ee97cafSCornelia Huck #ifdef CONFIG_SYSFS_DEPRECATED 7242ee97cafSCornelia Huck char *class_name; 7252ee97cafSCornelia Huck 7262ee97cafSCornelia Huck class_name = make_class_name(dev->class->name, &dev->kobj); 7272ee97cafSCornelia Huck if (class_name) { 7282ee97cafSCornelia Huck sysfs_remove_link(&dev->parent->kobj, class_name); 7292ee97cafSCornelia Huck kfree(class_name); 7302ee97cafSCornelia Huck } 7312ee97cafSCornelia Huck #endif 7322ee97cafSCornelia Huck sysfs_remove_link(&dev->kobj, "device"); 7332ee97cafSCornelia Huck } 7342ee97cafSCornelia Huck if (dev->kobj.parent != &dev->class->subsys.kobj) 7352ee97cafSCornelia Huck sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id); 7362ee97cafSCornelia Huck sysfs_remove_link(&dev->kobj, "subsystem"); 7372ee97cafSCornelia Huck } 7382ee97cafSCornelia Huck 7391da177e4SLinus Torvalds /** 7401da177e4SLinus Torvalds * device_add - add device to device hierarchy. 7411da177e4SLinus Torvalds * @dev: device. 7421da177e4SLinus Torvalds * 7431da177e4SLinus Torvalds * This is part 2 of device_register(), though may be called 7441da177e4SLinus Torvalds * separately _iff_ device_initialize() has been called separately. 7451da177e4SLinus Torvalds * 7461da177e4SLinus Torvalds * This adds it to the kobject hierarchy via kobject_add(), adds it 7471da177e4SLinus Torvalds * to the global and sibling lists for the device, then 7481da177e4SLinus Torvalds * adds it to the other relevant subsystems of the driver model. 7491da177e4SLinus Torvalds */ 7501da177e4SLinus Torvalds int device_add(struct device *dev) 7511da177e4SLinus Torvalds { 7521da177e4SLinus Torvalds struct device *parent = NULL; 753c47ed219SGreg Kroah-Hartman struct class_interface *class_intf; 7541da177e4SLinus Torvalds int error = -EINVAL; 7551da177e4SLinus Torvalds 7561da177e4SLinus Torvalds dev = get_device(dev); 7571da177e4SLinus Torvalds if (!dev || !strlen(dev->bus_id)) 7581da177e4SLinus Torvalds goto Error; 7591da177e4SLinus Torvalds 76040fa5422SGreg Kroah-Hartman pr_debug("DEV: registering device: ID = '%s'\n", dev->bus_id); 761c205ef48SGreg Kroah-Hartman 7621da177e4SLinus Torvalds parent = get_device(dev->parent); 76340fa5422SGreg Kroah-Hartman error = setup_parent(dev, parent); 76440fa5422SGreg Kroah-Hartman if (error) 76540fa5422SGreg Kroah-Hartman goto Error; 7661da177e4SLinus Torvalds 7671da177e4SLinus Torvalds /* first, register with generic layer. */ 7681da177e4SLinus Torvalds kobject_set_name(&dev->kobj, "%s", dev->bus_id); 76940fa5422SGreg Kroah-Hartman error = kobject_add(&dev->kobj); 77040fa5422SGreg Kroah-Hartman if (error) 7711da177e4SLinus Torvalds goto Error; 772a7fd6706SKay Sievers 77337022644SBrian Walsh /* notify platform of device entry */ 77437022644SBrian Walsh if (platform_notify) 77537022644SBrian Walsh platform_notify(dev); 77637022644SBrian Walsh 777116af378SBenjamin Herrenschmidt /* notify clients of device entry (new way) */ 778116af378SBenjamin Herrenschmidt if (dev->bus) 779116af378SBenjamin Herrenschmidt blocking_notifier_call_chain(&dev->bus->bus_notifier, 780116af378SBenjamin Herrenschmidt BUS_NOTIFY_ADD_DEVICE, dev); 781116af378SBenjamin Herrenschmidt 782ad6a1e1cSTejun Heo error = device_create_file(dev, &uevent_attr); 783a306eea4SCornelia Huck if (error) 784a306eea4SCornelia Huck goto attrError; 785a7fd6706SKay Sievers 78623681e47SGreg Kroah-Hartman if (MAJOR(dev->devt)) { 787ad6a1e1cSTejun Heo error = device_create_file(dev, &devt_attr); 788ad6a1e1cSTejun Heo if (error) 789a306eea4SCornelia Huck goto ueventattrError; 79023681e47SGreg Kroah-Hartman } 79123681e47SGreg Kroah-Hartman 7922ee97cafSCornelia Huck error = device_add_class_symlinks(dev); 7932ee97cafSCornelia Huck if (error) 7942ee97cafSCornelia Huck goto SymlinkError; 795dc0afa83SCornelia Huck error = device_add_attrs(dev); 796dc0afa83SCornelia Huck if (error) 7972620efefSGreg Kroah-Hartman goto AttrsError; 798dc0afa83SCornelia Huck error = device_pm_add(dev); 799dc0afa83SCornelia Huck if (error) 8001da177e4SLinus Torvalds goto PMError; 801dc0afa83SCornelia Huck error = bus_add_device(dev); 802dc0afa83SCornelia Huck if (error) 8031da177e4SLinus Torvalds goto BusError; 80453877d06SKay Sievers kobject_uevent(&dev->kobj, KOBJ_ADD); 805c6a46696SCornelia Huck bus_attach_device(dev); 8061da177e4SLinus Torvalds if (parent) 807d856f1e3SJames Bottomley klist_add_tail(&dev->knode_parent, &parent->klist_children); 8081da177e4SLinus Torvalds 8095d9fd169SGreg Kroah-Hartman if (dev->class) { 8105d9fd169SGreg Kroah-Hartman down(&dev->class->sem); 811c47ed219SGreg Kroah-Hartman /* tie the class to the device */ 8125d9fd169SGreg Kroah-Hartman list_add_tail(&dev->node, &dev->class->devices); 813c47ed219SGreg Kroah-Hartman 814c47ed219SGreg Kroah-Hartman /* notify any interfaces that the device is here */ 815c47ed219SGreg Kroah-Hartman list_for_each_entry(class_intf, &dev->class->interfaces, node) 816c47ed219SGreg Kroah-Hartman if (class_intf->add_dev) 817c47ed219SGreg Kroah-Hartman class_intf->add_dev(dev, class_intf); 8185d9fd169SGreg Kroah-Hartman up(&dev->class->sem); 8195d9fd169SGreg Kroah-Hartman } 8201da177e4SLinus Torvalds Done: 8211da177e4SLinus Torvalds put_device(dev); 8221da177e4SLinus Torvalds return error; 8231da177e4SLinus Torvalds BusError: 8241da177e4SLinus Torvalds device_pm_remove(dev); 8251da177e4SLinus Torvalds PMError: 826116af378SBenjamin Herrenschmidt if (dev->bus) 827116af378SBenjamin Herrenschmidt blocking_notifier_call_chain(&dev->bus->bus_notifier, 828116af378SBenjamin Herrenschmidt BUS_NOTIFY_DEL_DEVICE, dev); 8292620efefSGreg Kroah-Hartman device_remove_attrs(dev); 8302620efefSGreg Kroah-Hartman AttrsError: 8312ee97cafSCornelia Huck device_remove_class_symlinks(dev); 8322ee97cafSCornelia Huck SymlinkError: 833ad6a1e1cSTejun Heo if (MAJOR(dev->devt)) 834ad6a1e1cSTejun Heo device_remove_file(dev, &devt_attr); 83582f0cf9bSJames Simmons 83682f0cf9bSJames Simmons if (dev->class) { 83782f0cf9bSJames Simmons sysfs_remove_link(&dev->kobj, "subsystem"); 83882f0cf9bSJames Simmons /* If this is not a "fake" compatible device, remove the 83982f0cf9bSJames Simmons * symlink from the class to the device. */ 840823bccfcSGreg Kroah-Hartman if (dev->kobj.parent != &dev->class->subsys.kobj) 841823bccfcSGreg Kroah-Hartman sysfs_remove_link(&dev->class->subsys.kobj, 84282f0cf9bSJames Simmons dev->bus_id); 84382f0cf9bSJames Simmons if (parent) { 844f7f3461dSGreg Kroah-Hartman #ifdef CONFIG_SYSFS_DEPRECATED 84582f0cf9bSJames Simmons char *class_name = make_class_name(dev->class->name, 84682f0cf9bSJames Simmons &dev->kobj); 84782f0cf9bSJames Simmons if (class_name) 84882f0cf9bSJames Simmons sysfs_remove_link(&dev->parent->kobj, 84982f0cf9bSJames Simmons class_name); 85082f0cf9bSJames Simmons kfree(class_name); 851f7f3461dSGreg Kroah-Hartman #endif 85282f0cf9bSJames Simmons sysfs_remove_link(&dev->kobj, "device"); 85382f0cf9bSJames Simmons } 85423681e47SGreg Kroah-Hartman } 855a306eea4SCornelia Huck ueventattrError: 856ad6a1e1cSTejun Heo device_remove_file(dev, &uevent_attr); 85723681e47SGreg Kroah-Hartman attrError: 858312c004dSKay Sievers kobject_uevent(&dev->kobj, KOBJ_REMOVE); 8591da177e4SLinus Torvalds kobject_del(&dev->kobj); 8601da177e4SLinus Torvalds Error: 8611da177e4SLinus Torvalds if (parent) 8621da177e4SLinus Torvalds put_device(parent); 8631da177e4SLinus Torvalds goto Done; 8641da177e4SLinus Torvalds } 8651da177e4SLinus Torvalds 8661da177e4SLinus Torvalds 8671da177e4SLinus Torvalds /** 8681da177e4SLinus Torvalds * device_register - register a device with the system. 8691da177e4SLinus Torvalds * @dev: pointer to the device structure 8701da177e4SLinus Torvalds * 8711da177e4SLinus Torvalds * This happens in two clean steps - initialize the device 8721da177e4SLinus Torvalds * and add it to the system. The two steps can be called 8731da177e4SLinus Torvalds * separately, but this is the easiest and most common. 8741da177e4SLinus Torvalds * I.e. you should only call the two helpers separately if 8751da177e4SLinus Torvalds * have a clearly defined need to use and refcount the device 8761da177e4SLinus Torvalds * before it is added to the hierarchy. 8771da177e4SLinus Torvalds */ 8781da177e4SLinus Torvalds 8791da177e4SLinus Torvalds int device_register(struct device *dev) 8801da177e4SLinus Torvalds { 8811da177e4SLinus Torvalds device_initialize(dev); 8821da177e4SLinus Torvalds return device_add(dev); 8831da177e4SLinus Torvalds } 8841da177e4SLinus Torvalds 8851da177e4SLinus Torvalds 8861da177e4SLinus Torvalds /** 8871da177e4SLinus Torvalds * get_device - increment reference count for device. 8881da177e4SLinus Torvalds * @dev: device. 8891da177e4SLinus Torvalds * 8901da177e4SLinus Torvalds * This simply forwards the call to kobject_get(), though 8911da177e4SLinus Torvalds * we do take care to provide for the case that we get a NULL 8921da177e4SLinus Torvalds * pointer passed in. 8931da177e4SLinus Torvalds */ 8941da177e4SLinus Torvalds 8951da177e4SLinus Torvalds struct device * get_device(struct device * dev) 8961da177e4SLinus Torvalds { 8971da177e4SLinus Torvalds return dev ? to_dev(kobject_get(&dev->kobj)) : NULL; 8981da177e4SLinus Torvalds } 8991da177e4SLinus Torvalds 9001da177e4SLinus Torvalds 9011da177e4SLinus Torvalds /** 9021da177e4SLinus Torvalds * put_device - decrement reference count. 9031da177e4SLinus Torvalds * @dev: device in question. 9041da177e4SLinus Torvalds */ 9051da177e4SLinus Torvalds void put_device(struct device * dev) 9061da177e4SLinus Torvalds { 9071da177e4SLinus Torvalds if (dev) 9081da177e4SLinus Torvalds kobject_put(&dev->kobj); 9091da177e4SLinus Torvalds } 9101da177e4SLinus Torvalds 9111da177e4SLinus Torvalds 9121da177e4SLinus Torvalds /** 9131da177e4SLinus Torvalds * device_del - delete device from system. 9141da177e4SLinus Torvalds * @dev: device. 9151da177e4SLinus Torvalds * 9161da177e4SLinus Torvalds * This is the first part of the device unregistration 9171da177e4SLinus Torvalds * sequence. This removes the device from the lists we control 9181da177e4SLinus Torvalds * from here, has it removed from the other driver model 9191da177e4SLinus Torvalds * subsystems it was added to in device_add(), and removes it 9201da177e4SLinus Torvalds * from the kobject hierarchy. 9211da177e4SLinus Torvalds * 9221da177e4SLinus Torvalds * NOTE: this should be called manually _iff_ device_add() was 9231da177e4SLinus Torvalds * also called manually. 9241da177e4SLinus Torvalds */ 9251da177e4SLinus Torvalds 9261da177e4SLinus Torvalds void device_del(struct device * dev) 9271da177e4SLinus Torvalds { 9281da177e4SLinus Torvalds struct device * parent = dev->parent; 929c47ed219SGreg Kroah-Hartman struct class_interface *class_intf; 9301da177e4SLinus Torvalds 9311da177e4SLinus Torvalds if (parent) 932d62c0f9fSPatrick Mochel klist_del(&dev->knode_parent); 933ad6a1e1cSTejun Heo if (MAJOR(dev->devt)) 934ad6a1e1cSTejun Heo device_remove_file(dev, &devt_attr); 935b9d9c82bSKay Sievers if (dev->class) { 936b9d9c82bSKay Sievers sysfs_remove_link(&dev->kobj, "subsystem"); 93740fa5422SGreg Kroah-Hartman /* If this is not a "fake" compatible device, remove the 93840fa5422SGreg Kroah-Hartman * symlink from the class to the device. */ 939823bccfcSGreg Kroah-Hartman if (dev->kobj.parent != &dev->class->subsys.kobj) 940823bccfcSGreg Kroah-Hartman sysfs_remove_link(&dev->class->subsys.kobj, 94140fa5422SGreg Kroah-Hartman dev->bus_id); 94264bb5d2cSGreg Kroah-Hartman if (parent) { 943f7f3461dSGreg Kroah-Hartman #ifdef CONFIG_SYSFS_DEPRECATED 94499ef3ef8SKay Sievers char *class_name = make_class_name(dev->class->name, 94599ef3ef8SKay Sievers &dev->kobj); 946cb360bbfSCornelia Huck if (class_name) 947cb360bbfSCornelia Huck sysfs_remove_link(&dev->parent->kobj, 948cb360bbfSCornelia Huck class_name); 949e9a7d305SGreg Kroah-Hartman kfree(class_name); 950f7f3461dSGreg Kroah-Hartman #endif 95199ef3ef8SKay Sievers sysfs_remove_link(&dev->kobj, "device"); 95299ef3ef8SKay Sievers } 95399ef3ef8SKay Sievers 9545d9fd169SGreg Kroah-Hartman down(&dev->class->sem); 955c47ed219SGreg Kroah-Hartman /* notify any interfaces that the device is now gone */ 956c47ed219SGreg Kroah-Hartman list_for_each_entry(class_intf, &dev->class->interfaces, node) 957c47ed219SGreg Kroah-Hartman if (class_intf->remove_dev) 958c47ed219SGreg Kroah-Hartman class_intf->remove_dev(dev, class_intf); 959c47ed219SGreg Kroah-Hartman /* remove the device from the class list */ 9605d9fd169SGreg Kroah-Hartman list_del_init(&dev->node); 9615d9fd169SGreg Kroah-Hartman up(&dev->class->sem); 96286406245SKay Sievers 96386406245SKay Sievers /* If we live in a parent class-directory, unreference it */ 96486406245SKay Sievers if (dev->kobj.parent->kset == &dev->class->class_dirs) { 96586406245SKay Sievers struct device *d; 96686406245SKay Sievers int other = 0; 96786406245SKay Sievers 96886406245SKay Sievers /* 96986406245SKay Sievers * if we are the last child of our class, delete 97086406245SKay Sievers * our class-directory at this parent 97186406245SKay Sievers */ 97286406245SKay Sievers down(&dev->class->sem); 97386406245SKay Sievers list_for_each_entry(d, &dev->class->devices, node) { 97486406245SKay Sievers if (d == dev) 97586406245SKay Sievers continue; 97686406245SKay Sievers if (d->kobj.parent == dev->kobj.parent) { 97786406245SKay Sievers other = 1; 97886406245SKay Sievers break; 97986406245SKay Sievers } 98086406245SKay Sievers } 98186406245SKay Sievers if (!other) 98286406245SKay Sievers kobject_del(dev->kobj.parent); 98386406245SKay Sievers 98486406245SKay Sievers kobject_put(dev->kobj.parent); 98586406245SKay Sievers up(&dev->class->sem); 98686406245SKay Sievers } 987b9d9c82bSKay Sievers } 988ad6a1e1cSTejun Heo device_remove_file(dev, &uevent_attr); 9892620efefSGreg Kroah-Hartman device_remove_attrs(dev); 99028953533SBenjamin Herrenschmidt bus_remove_device(dev); 9911da177e4SLinus Torvalds 9922f8d16a9STejun Heo /* 9932f8d16a9STejun Heo * Some platform devices are driven without driver attached 9942f8d16a9STejun Heo * and managed resources may have been acquired. Make sure 9952f8d16a9STejun Heo * all resources are released. 9962f8d16a9STejun Heo */ 9972f8d16a9STejun Heo devres_release_all(dev); 9982f8d16a9STejun Heo 9991da177e4SLinus Torvalds /* Notify the platform of the removal, in case they 10001da177e4SLinus Torvalds * need to do anything... 10011da177e4SLinus Torvalds */ 10021da177e4SLinus Torvalds if (platform_notify_remove) 10031da177e4SLinus Torvalds platform_notify_remove(dev); 1004116af378SBenjamin Herrenschmidt if (dev->bus) 1005116af378SBenjamin Herrenschmidt blocking_notifier_call_chain(&dev->bus->bus_notifier, 1006116af378SBenjamin Herrenschmidt BUS_NOTIFY_DEL_DEVICE, dev); 10071da177e4SLinus Torvalds device_pm_remove(dev); 1008312c004dSKay Sievers kobject_uevent(&dev->kobj, KOBJ_REMOVE); 10091da177e4SLinus Torvalds kobject_del(&dev->kobj); 10101da177e4SLinus Torvalds if (parent) 10111da177e4SLinus Torvalds put_device(parent); 10121da177e4SLinus Torvalds } 10131da177e4SLinus Torvalds 10141da177e4SLinus Torvalds /** 10151da177e4SLinus Torvalds * device_unregister - unregister device from system. 10161da177e4SLinus Torvalds * @dev: device going away. 10171da177e4SLinus Torvalds * 10181da177e4SLinus Torvalds * We do this in two parts, like we do device_register(). First, 10191da177e4SLinus Torvalds * we remove it from all the subsystems with device_del(), then 10201da177e4SLinus Torvalds * we decrement the reference count via put_device(). If that 10211da177e4SLinus Torvalds * is the final reference count, the device will be cleaned up 10221da177e4SLinus Torvalds * via device_release() above. Otherwise, the structure will 10231da177e4SLinus Torvalds * stick around until the final reference to the device is dropped. 10241da177e4SLinus Torvalds */ 10251da177e4SLinus Torvalds void device_unregister(struct device * dev) 10261da177e4SLinus Torvalds { 10271da177e4SLinus Torvalds pr_debug("DEV: Unregistering device. ID = '%s'\n", dev->bus_id); 10281da177e4SLinus Torvalds device_del(dev); 10291da177e4SLinus Torvalds put_device(dev); 10301da177e4SLinus Torvalds } 10311da177e4SLinus Torvalds 10321da177e4SLinus Torvalds 103336239577Smochel@digitalimplant.org static struct device * next_device(struct klist_iter * i) 103436239577Smochel@digitalimplant.org { 103536239577Smochel@digitalimplant.org struct klist_node * n = klist_next(i); 103636239577Smochel@digitalimplant.org return n ? container_of(n, struct device, knode_parent) : NULL; 103736239577Smochel@digitalimplant.org } 103836239577Smochel@digitalimplant.org 10391da177e4SLinus Torvalds /** 10401da177e4SLinus Torvalds * device_for_each_child - device child iterator. 1041c41455fbSRandy Dunlap * @parent: parent struct device. 10421da177e4SLinus Torvalds * @data: data for the callback. 10431da177e4SLinus Torvalds * @fn: function to be called for each device. 10441da177e4SLinus Torvalds * 1045c41455fbSRandy Dunlap * Iterate over @parent's child devices, and call @fn for each, 10461da177e4SLinus Torvalds * passing it @data. 10471da177e4SLinus Torvalds * 10481da177e4SLinus Torvalds * We check the return of @fn each time. If it returns anything 10491da177e4SLinus Torvalds * other than 0, we break out and return that value. 10501da177e4SLinus Torvalds */ 105136239577Smochel@digitalimplant.org int device_for_each_child(struct device * parent, void * data, 10521da177e4SLinus Torvalds int (*fn)(struct device *, void *)) 10531da177e4SLinus Torvalds { 105436239577Smochel@digitalimplant.org struct klist_iter i; 10551da177e4SLinus Torvalds struct device * child; 10561da177e4SLinus Torvalds int error = 0; 10571da177e4SLinus Torvalds 105836239577Smochel@digitalimplant.org klist_iter_init(&parent->klist_children, &i); 105936239577Smochel@digitalimplant.org while ((child = next_device(&i)) && !error) 106036239577Smochel@digitalimplant.org error = fn(child, data); 106136239577Smochel@digitalimplant.org klist_iter_exit(&i); 10621da177e4SLinus Torvalds return error; 10631da177e4SLinus Torvalds } 10641da177e4SLinus Torvalds 10655ab69981SCornelia Huck /** 10665ab69981SCornelia Huck * device_find_child - device iterator for locating a particular device. 10675ab69981SCornelia Huck * @parent: parent struct device 10685ab69981SCornelia Huck * @data: Data to pass to match function 10695ab69981SCornelia Huck * @match: Callback function to check device 10705ab69981SCornelia Huck * 10715ab69981SCornelia Huck * This is similar to the device_for_each_child() function above, but it 10725ab69981SCornelia Huck * returns a reference to a device that is 'found' for later use, as 10735ab69981SCornelia Huck * determined by the @match callback. 10745ab69981SCornelia Huck * 10755ab69981SCornelia Huck * The callback should return 0 if the device doesn't match and non-zero 10765ab69981SCornelia Huck * if it does. If the callback returns non-zero and a reference to the 10775ab69981SCornelia Huck * current device can be obtained, this function will return to the caller 10785ab69981SCornelia Huck * and not iterate over any more devices. 10795ab69981SCornelia Huck */ 10805ab69981SCornelia Huck struct device * device_find_child(struct device *parent, void *data, 10815ab69981SCornelia Huck int (*match)(struct device *, void *)) 10825ab69981SCornelia Huck { 10835ab69981SCornelia Huck struct klist_iter i; 10845ab69981SCornelia Huck struct device *child; 10855ab69981SCornelia Huck 10865ab69981SCornelia Huck if (!parent) 10875ab69981SCornelia Huck return NULL; 10885ab69981SCornelia Huck 10895ab69981SCornelia Huck klist_iter_init(&parent->klist_children, &i); 10905ab69981SCornelia Huck while ((child = next_device(&i))) 10915ab69981SCornelia Huck if (match(child, data) && get_device(child)) 10925ab69981SCornelia Huck break; 10935ab69981SCornelia Huck klist_iter_exit(&i); 10945ab69981SCornelia Huck return child; 10955ab69981SCornelia Huck } 10965ab69981SCornelia Huck 10971da177e4SLinus Torvalds int __init devices_init(void) 10981da177e4SLinus Torvalds { 10991da177e4SLinus Torvalds return subsystem_register(&devices_subsys); 11001da177e4SLinus Torvalds } 11011da177e4SLinus Torvalds 11021da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(device_for_each_child); 11035ab69981SCornelia Huck EXPORT_SYMBOL_GPL(device_find_child); 11041da177e4SLinus Torvalds 11051da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(device_initialize); 11061da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(device_add); 11071da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(device_register); 11081da177e4SLinus Torvalds 11091da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(device_del); 11101da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(device_unregister); 11111da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(get_device); 11121da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(put_device); 11131da177e4SLinus Torvalds 11141da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(device_create_file); 11151da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(device_remove_file); 111623681e47SGreg Kroah-Hartman 111723681e47SGreg Kroah-Hartman 111823681e47SGreg Kroah-Hartman static void device_create_release(struct device *dev) 111923681e47SGreg Kroah-Hartman { 112023681e47SGreg Kroah-Hartman pr_debug("%s called for %s\n", __FUNCTION__, dev->bus_id); 112123681e47SGreg Kroah-Hartman kfree(dev); 112223681e47SGreg Kroah-Hartman } 112323681e47SGreg Kroah-Hartman 112423681e47SGreg Kroah-Hartman /** 112523681e47SGreg Kroah-Hartman * device_create - creates a device and registers it with sysfs 112642734dafSHenrik Kretzschmar * @class: pointer to the struct class that this device should be registered to 112742734dafSHenrik Kretzschmar * @parent: pointer to the parent struct device of this new device, if any 112842734dafSHenrik Kretzschmar * @devt: the dev_t for the char device to be added 112942734dafSHenrik Kretzschmar * @fmt: string for the device's name 113023681e47SGreg Kroah-Hartman * 113142734dafSHenrik Kretzschmar * This function can be used by char device classes. A struct device 113242734dafSHenrik Kretzschmar * will be created in sysfs, registered to the specified class. 113342734dafSHenrik Kretzschmar * 113423681e47SGreg Kroah-Hartman * A "dev" file will be created, showing the dev_t for the device, if 113523681e47SGreg Kroah-Hartman * the dev_t is not 0,0. 113642734dafSHenrik Kretzschmar * If a pointer to a parent struct device is passed in, the newly created 113742734dafSHenrik Kretzschmar * struct device will be a child of that device in sysfs. 113842734dafSHenrik Kretzschmar * The pointer to the struct device will be returned from the call. 113942734dafSHenrik Kretzschmar * Any further sysfs files that might be required can be created using this 114023681e47SGreg Kroah-Hartman * pointer. 114123681e47SGreg Kroah-Hartman * 114223681e47SGreg Kroah-Hartman * Note: the struct class passed to this function must have previously 114323681e47SGreg Kroah-Hartman * been created with a call to class_create(). 114423681e47SGreg Kroah-Hartman */ 114523681e47SGreg Kroah-Hartman struct device *device_create(struct class *class, struct device *parent, 11465cbe5f8aSGreg Kroah-Hartman dev_t devt, const char *fmt, ...) 114723681e47SGreg Kroah-Hartman { 114823681e47SGreg Kroah-Hartman va_list args; 114923681e47SGreg Kroah-Hartman struct device *dev = NULL; 115023681e47SGreg Kroah-Hartman int retval = -ENODEV; 115123681e47SGreg Kroah-Hartman 115223681e47SGreg Kroah-Hartman if (class == NULL || IS_ERR(class)) 115323681e47SGreg Kroah-Hartman goto error; 115423681e47SGreg Kroah-Hartman 115523681e47SGreg Kroah-Hartman dev = kzalloc(sizeof(*dev), GFP_KERNEL); 115623681e47SGreg Kroah-Hartman if (!dev) { 115723681e47SGreg Kroah-Hartman retval = -ENOMEM; 115823681e47SGreg Kroah-Hartman goto error; 115923681e47SGreg Kroah-Hartman } 116023681e47SGreg Kroah-Hartman 116123681e47SGreg Kroah-Hartman dev->devt = devt; 116223681e47SGreg Kroah-Hartman dev->class = class; 116323681e47SGreg Kroah-Hartman dev->parent = parent; 116423681e47SGreg Kroah-Hartman dev->release = device_create_release; 116523681e47SGreg Kroah-Hartman 116623681e47SGreg Kroah-Hartman va_start(args, fmt); 116723681e47SGreg Kroah-Hartman vsnprintf(dev->bus_id, BUS_ID_SIZE, fmt, args); 116823681e47SGreg Kroah-Hartman va_end(args); 116923681e47SGreg Kroah-Hartman retval = device_register(dev); 117023681e47SGreg Kroah-Hartman if (retval) 117123681e47SGreg Kroah-Hartman goto error; 117223681e47SGreg Kroah-Hartman 117323681e47SGreg Kroah-Hartman return dev; 117423681e47SGreg Kroah-Hartman 117523681e47SGreg Kroah-Hartman error: 117623681e47SGreg Kroah-Hartman kfree(dev); 117723681e47SGreg Kroah-Hartman return ERR_PTR(retval); 117823681e47SGreg Kroah-Hartman } 117923681e47SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(device_create); 118023681e47SGreg Kroah-Hartman 118123681e47SGreg Kroah-Hartman /** 118223681e47SGreg Kroah-Hartman * device_destroy - removes a device that was created with device_create() 118342734dafSHenrik Kretzschmar * @class: pointer to the struct class that this device was registered with 118442734dafSHenrik Kretzschmar * @devt: the dev_t of the device that was previously registered 118523681e47SGreg Kroah-Hartman * 118642734dafSHenrik Kretzschmar * This call unregisters and cleans up a device that was created with a 118742734dafSHenrik Kretzschmar * call to device_create(). 118823681e47SGreg Kroah-Hartman */ 118923681e47SGreg Kroah-Hartman void device_destroy(struct class *class, dev_t devt) 119023681e47SGreg Kroah-Hartman { 119123681e47SGreg Kroah-Hartman struct device *dev = NULL; 119223681e47SGreg Kroah-Hartman struct device *dev_tmp; 119323681e47SGreg Kroah-Hartman 119423681e47SGreg Kroah-Hartman down(&class->sem); 119523681e47SGreg Kroah-Hartman list_for_each_entry(dev_tmp, &class->devices, node) { 119623681e47SGreg Kroah-Hartman if (dev_tmp->devt == devt) { 119723681e47SGreg Kroah-Hartman dev = dev_tmp; 119823681e47SGreg Kroah-Hartman break; 119923681e47SGreg Kroah-Hartman } 120023681e47SGreg Kroah-Hartman } 120123681e47SGreg Kroah-Hartman up(&class->sem); 120223681e47SGreg Kroah-Hartman 12035d9fd169SGreg Kroah-Hartman if (dev) 120423681e47SGreg Kroah-Hartman device_unregister(dev); 120523681e47SGreg Kroah-Hartman } 120623681e47SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(device_destroy); 1207a2de48caSGreg Kroah-Hartman 1208a2de48caSGreg Kroah-Hartman /** 1209a2de48caSGreg Kroah-Hartman * device_rename - renames a device 1210a2de48caSGreg Kroah-Hartman * @dev: the pointer to the struct device to be renamed 1211a2de48caSGreg Kroah-Hartman * @new_name: the new name of the device 1212a2de48caSGreg Kroah-Hartman */ 1213a2de48caSGreg Kroah-Hartman int device_rename(struct device *dev, char *new_name) 1214a2de48caSGreg Kroah-Hartman { 1215a2de48caSGreg Kroah-Hartman char *old_class_name = NULL; 1216a2de48caSGreg Kroah-Hartman char *new_class_name = NULL; 12172ee97cafSCornelia Huck char *old_device_name = NULL; 1218a2de48caSGreg Kroah-Hartman int error; 1219a2de48caSGreg Kroah-Hartman 1220a2de48caSGreg Kroah-Hartman dev = get_device(dev); 1221a2de48caSGreg Kroah-Hartman if (!dev) 1222a2de48caSGreg Kroah-Hartman return -EINVAL; 1223a2de48caSGreg Kroah-Hartman 1224a2de48caSGreg Kroah-Hartman pr_debug("DEVICE: renaming '%s' to '%s'\n", dev->bus_id, new_name); 1225a2de48caSGreg Kroah-Hartman 122699ef3ef8SKay Sievers #ifdef CONFIG_SYSFS_DEPRECATED 1227a2de48caSGreg Kroah-Hartman if ((dev->class) && (dev->parent)) 1228a2de48caSGreg Kroah-Hartman old_class_name = make_class_name(dev->class->name, &dev->kobj); 122999ef3ef8SKay Sievers #endif 1230a2de48caSGreg Kroah-Hartman 12312ee97cafSCornelia Huck old_device_name = kmalloc(BUS_ID_SIZE, GFP_KERNEL); 12322ee97cafSCornelia Huck if (!old_device_name) { 1233952ab431SJesper Juhl error = -ENOMEM; 12342ee97cafSCornelia Huck goto out; 1235952ab431SJesper Juhl } 12362ee97cafSCornelia Huck strlcpy(old_device_name, dev->bus_id, BUS_ID_SIZE); 1237a2de48caSGreg Kroah-Hartman strlcpy(dev->bus_id, new_name, BUS_ID_SIZE); 1238a2de48caSGreg Kroah-Hartman 1239a2de48caSGreg Kroah-Hartman error = kobject_rename(&dev->kobj, new_name); 12402ee97cafSCornelia Huck if (error) { 12412ee97cafSCornelia Huck strlcpy(dev->bus_id, old_device_name, BUS_ID_SIZE); 12422ee97cafSCornelia Huck goto out; 12432ee97cafSCornelia Huck } 1244a2de48caSGreg Kroah-Hartman 124599ef3ef8SKay Sievers #ifdef CONFIG_SYSFS_DEPRECATED 1246a2de48caSGreg Kroah-Hartman if (old_class_name) { 1247a2de48caSGreg Kroah-Hartman new_class_name = make_class_name(dev->class->name, &dev->kobj); 1248a2de48caSGreg Kroah-Hartman if (new_class_name) { 12492ee97cafSCornelia Huck error = sysfs_create_link(&dev->parent->kobj, 12502ee97cafSCornelia Huck &dev->kobj, new_class_name); 12512ee97cafSCornelia Huck if (error) 12522ee97cafSCornelia Huck goto out; 1253a2de48caSGreg Kroah-Hartman sysfs_remove_link(&dev->parent->kobj, old_class_name); 1254a2de48caSGreg Kroah-Hartman } 1255a2de48caSGreg Kroah-Hartman } 125699ef3ef8SKay Sievers #endif 125799ef3ef8SKay Sievers 1258a2de48caSGreg Kroah-Hartman if (dev->class) { 12592ee97cafSCornelia Huck sysfs_remove_link(&dev->class->subsys.kobj, old_device_name); 12602ee97cafSCornelia Huck error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj, 1261a2de48caSGreg Kroah-Hartman dev->bus_id); 12622ee97cafSCornelia Huck if (error) { 12632ee97cafSCornelia Huck /* Uh... how to unravel this if restoring can fail? */ 12642ee97cafSCornelia Huck dev_err(dev, "%s: sysfs_create_symlink failed (%d)\n", 12652ee97cafSCornelia Huck __FUNCTION__, error); 1266a2de48caSGreg Kroah-Hartman } 12672ee97cafSCornelia Huck } 12682ee97cafSCornelia Huck out: 1269a2de48caSGreg Kroah-Hartman put_device(dev); 1270a2de48caSGreg Kroah-Hartman 1271a2de48caSGreg Kroah-Hartman kfree(new_class_name); 1272952ab431SJesper Juhl kfree(old_class_name); 12732ee97cafSCornelia Huck kfree(old_device_name); 1274a2de48caSGreg Kroah-Hartman 1275a2de48caSGreg Kroah-Hartman return error; 1276a2de48caSGreg Kroah-Hartman } 1277a2807dbcSJohannes Berg EXPORT_SYMBOL_GPL(device_rename); 12788a82472fSCornelia Huck 12798a82472fSCornelia Huck static int device_move_class_links(struct device *dev, 12808a82472fSCornelia Huck struct device *old_parent, 12818a82472fSCornelia Huck struct device *new_parent) 12828a82472fSCornelia Huck { 1283f7f3461dSGreg Kroah-Hartman int error = 0; 12848a82472fSCornelia Huck #ifdef CONFIG_SYSFS_DEPRECATED 12858a82472fSCornelia Huck char *class_name; 12868a82472fSCornelia Huck 12878a82472fSCornelia Huck class_name = make_class_name(dev->class->name, &dev->kobj); 12888a82472fSCornelia Huck if (!class_name) { 1289cb360bbfSCornelia Huck error = -ENOMEM; 12908a82472fSCornelia Huck goto out; 12918a82472fSCornelia Huck } 12928a82472fSCornelia Huck if (old_parent) { 12938a82472fSCornelia Huck sysfs_remove_link(&dev->kobj, "device"); 12948a82472fSCornelia Huck sysfs_remove_link(&old_parent->kobj, class_name); 12958a82472fSCornelia Huck } 1296c744aeaeSCornelia Huck if (new_parent) { 1297c744aeaeSCornelia Huck error = sysfs_create_link(&dev->kobj, &new_parent->kobj, 1298c744aeaeSCornelia Huck "device"); 12998a82472fSCornelia Huck if (error) 13008a82472fSCornelia Huck goto out; 1301c744aeaeSCornelia Huck error = sysfs_create_link(&new_parent->kobj, &dev->kobj, 1302c744aeaeSCornelia Huck class_name); 13038a82472fSCornelia Huck if (error) 13048a82472fSCornelia Huck sysfs_remove_link(&dev->kobj, "device"); 1305c744aeaeSCornelia Huck } 1306c744aeaeSCornelia Huck else 1307c744aeaeSCornelia Huck error = 0; 13088a82472fSCornelia Huck out: 13098a82472fSCornelia Huck kfree(class_name); 13108a82472fSCornelia Huck return error; 13118a82472fSCornelia Huck #else 1312f7f3461dSGreg Kroah-Hartman if (old_parent) 1313f7f3461dSGreg Kroah-Hartman sysfs_remove_link(&dev->kobj, "device"); 1314f7f3461dSGreg Kroah-Hartman if (new_parent) 1315f7f3461dSGreg Kroah-Hartman error = sysfs_create_link(&dev->kobj, &new_parent->kobj, 1316f7f3461dSGreg Kroah-Hartman "device"); 1317f7f3461dSGreg Kroah-Hartman return error; 13188a82472fSCornelia Huck #endif 13198a82472fSCornelia Huck } 13208a82472fSCornelia Huck 13218a82472fSCornelia Huck /** 13228a82472fSCornelia Huck * device_move - moves a device to a new parent 13238a82472fSCornelia Huck * @dev: the pointer to the struct device to be moved 1324c744aeaeSCornelia Huck * @new_parent: the new parent of the device (can by NULL) 13258a82472fSCornelia Huck */ 13268a82472fSCornelia Huck int device_move(struct device *dev, struct device *new_parent) 13278a82472fSCornelia Huck { 13288a82472fSCornelia Huck int error; 13298a82472fSCornelia Huck struct device *old_parent; 1330c744aeaeSCornelia Huck struct kobject *new_parent_kobj; 13318a82472fSCornelia Huck 13328a82472fSCornelia Huck dev = get_device(dev); 13338a82472fSCornelia Huck if (!dev) 13348a82472fSCornelia Huck return -EINVAL; 13358a82472fSCornelia Huck 13368a82472fSCornelia Huck new_parent = get_device(new_parent); 1337c744aeaeSCornelia Huck new_parent_kobj = get_device_parent (dev, new_parent); 1338c744aeaeSCornelia Huck if (IS_ERR(new_parent_kobj)) { 1339c744aeaeSCornelia Huck error = PTR_ERR(new_parent_kobj); 1340c744aeaeSCornelia Huck put_device(new_parent); 13418a82472fSCornelia Huck goto out; 13428a82472fSCornelia Huck } 13438a82472fSCornelia Huck pr_debug("DEVICE: moving '%s' to '%s'\n", dev->bus_id, 1344c744aeaeSCornelia Huck new_parent ? new_parent->bus_id : "<NULL>"); 1345c744aeaeSCornelia Huck error = kobject_move(&dev->kobj, new_parent_kobj); 13468a82472fSCornelia Huck if (error) { 13478a82472fSCornelia Huck put_device(new_parent); 13488a82472fSCornelia Huck goto out; 13498a82472fSCornelia Huck } 13508a82472fSCornelia Huck old_parent = dev->parent; 13518a82472fSCornelia Huck dev->parent = new_parent; 13528a82472fSCornelia Huck if (old_parent) 1353acf02d23SCornelia Huck klist_remove(&dev->knode_parent); 1354c744aeaeSCornelia Huck if (new_parent) 13558a82472fSCornelia Huck klist_add_tail(&dev->knode_parent, &new_parent->klist_children); 13568a82472fSCornelia Huck if (!dev->class) 13578a82472fSCornelia Huck goto out_put; 13588a82472fSCornelia Huck error = device_move_class_links(dev, old_parent, new_parent); 13598a82472fSCornelia Huck if (error) { 13608a82472fSCornelia Huck /* We ignore errors on cleanup since we're hosed anyway... */ 13618a82472fSCornelia Huck device_move_class_links(dev, new_parent, old_parent); 13628a82472fSCornelia Huck if (!kobject_move(&dev->kobj, &old_parent->kobj)) { 1363c744aeaeSCornelia Huck if (new_parent) 1364acf02d23SCornelia Huck klist_remove(&dev->knode_parent); 13658a82472fSCornelia Huck if (old_parent) 13668a82472fSCornelia Huck klist_add_tail(&dev->knode_parent, 13678a82472fSCornelia Huck &old_parent->klist_children); 13688a82472fSCornelia Huck } 13698a82472fSCornelia Huck put_device(new_parent); 13708a82472fSCornelia Huck goto out; 13718a82472fSCornelia Huck } 13728a82472fSCornelia Huck out_put: 13738a82472fSCornelia Huck put_device(old_parent); 13748a82472fSCornelia Huck out: 13758a82472fSCornelia Huck put_device(dev); 13768a82472fSCornelia Huck return error; 13778a82472fSCornelia Huck } 13788a82472fSCornelia Huck 13798a82472fSCornelia Huck EXPORT_SYMBOL_GPL(device_move); 1380