18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * class.c - basic device class management 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2002-3 Patrick Mochel 68c2ecf20Sopenharmony_ci * Copyright (c) 2002-3 Open Source Development Labs 78c2ecf20Sopenharmony_ci * Copyright (c) 2003-2004 Greg Kroah-Hartman 88c2ecf20Sopenharmony_ci * Copyright (c) 2003-2004 IBM Corp. 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/device/class.h> 128c2ecf20Sopenharmony_ci#include <linux/device.h> 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <linux/init.h> 158c2ecf20Sopenharmony_ci#include <linux/string.h> 168c2ecf20Sopenharmony_ci#include <linux/kdev_t.h> 178c2ecf20Sopenharmony_ci#include <linux/err.h> 188c2ecf20Sopenharmony_ci#include <linux/slab.h> 198c2ecf20Sopenharmony_ci#include <linux/genhd.h> 208c2ecf20Sopenharmony_ci#include <linux/mutex.h> 218c2ecf20Sopenharmony_ci#include "base.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define to_class_attr(_attr) container_of(_attr, struct class_attribute, attr) 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic ssize_t class_attr_show(struct kobject *kobj, struct attribute *attr, 268c2ecf20Sopenharmony_ci char *buf) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci struct class_attribute *class_attr = to_class_attr(attr); 298c2ecf20Sopenharmony_ci struct subsys_private *cp = to_subsys_private(kobj); 308c2ecf20Sopenharmony_ci ssize_t ret = -EIO; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci if (class_attr->show) 338c2ecf20Sopenharmony_ci ret = class_attr->show(cp->class, class_attr, buf); 348c2ecf20Sopenharmony_ci return ret; 358c2ecf20Sopenharmony_ci} 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic ssize_t class_attr_store(struct kobject *kobj, struct attribute *attr, 388c2ecf20Sopenharmony_ci const char *buf, size_t count) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci struct class_attribute *class_attr = to_class_attr(attr); 418c2ecf20Sopenharmony_ci struct subsys_private *cp = to_subsys_private(kobj); 428c2ecf20Sopenharmony_ci ssize_t ret = -EIO; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci if (class_attr->store) 458c2ecf20Sopenharmony_ci ret = class_attr->store(cp->class, class_attr, buf, count); 468c2ecf20Sopenharmony_ci return ret; 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic void class_release(struct kobject *kobj) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci struct subsys_private *cp = to_subsys_private(kobj); 528c2ecf20Sopenharmony_ci struct class *class = cp->class; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci pr_debug("class '%s': release.\n", class->name); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci if (class->class_release) 578c2ecf20Sopenharmony_ci class->class_release(class); 588c2ecf20Sopenharmony_ci else 598c2ecf20Sopenharmony_ci pr_debug("class '%s' does not have a release() function, " 608c2ecf20Sopenharmony_ci "be careful\n", class->name); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci kfree(cp); 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic const struct kobj_ns_type_operations *class_child_ns_type(struct kobject *kobj) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci struct subsys_private *cp = to_subsys_private(kobj); 688c2ecf20Sopenharmony_ci struct class *class = cp->class; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci return class->ns_type; 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic const struct sysfs_ops class_sysfs_ops = { 748c2ecf20Sopenharmony_ci .show = class_attr_show, 758c2ecf20Sopenharmony_ci .store = class_attr_store, 768c2ecf20Sopenharmony_ci}; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistatic struct kobj_type class_ktype = { 798c2ecf20Sopenharmony_ci .sysfs_ops = &class_sysfs_ops, 808c2ecf20Sopenharmony_ci .release = class_release, 818c2ecf20Sopenharmony_ci .child_ns_type = class_child_ns_type, 828c2ecf20Sopenharmony_ci}; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci/* Hotplug events for classes go to the class subsys */ 858c2ecf20Sopenharmony_cistatic struct kset *class_kset; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ciint class_create_file_ns(struct class *cls, const struct class_attribute *attr, 898c2ecf20Sopenharmony_ci const void *ns) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci int error; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci if (cls) 948c2ecf20Sopenharmony_ci error = sysfs_create_file_ns(&cls->p->subsys.kobj, 958c2ecf20Sopenharmony_ci &attr->attr, ns); 968c2ecf20Sopenharmony_ci else 978c2ecf20Sopenharmony_ci error = -EINVAL; 988c2ecf20Sopenharmony_ci return error; 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_civoid class_remove_file_ns(struct class *cls, const struct class_attribute *attr, 1028c2ecf20Sopenharmony_ci const void *ns) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci if (cls) 1058c2ecf20Sopenharmony_ci sysfs_remove_file_ns(&cls->p->subsys.kobj, &attr->attr, ns); 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistatic struct class *class_get(struct class *cls) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci if (cls) 1118c2ecf20Sopenharmony_ci kset_get(&cls->p->subsys); 1128c2ecf20Sopenharmony_ci return cls; 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic void class_put(struct class *cls) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci if (cls) 1188c2ecf20Sopenharmony_ci kset_put(&cls->p->subsys); 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic struct device *klist_class_to_dev(struct klist_node *n) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci struct device_private *p = to_device_private_class(n); 1248c2ecf20Sopenharmony_ci return p->device; 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistatic void klist_class_dev_get(struct klist_node *n) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci struct device *dev = klist_class_to_dev(n); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci get_device(dev); 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic void klist_class_dev_put(struct klist_node *n) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci struct device *dev = klist_class_to_dev(n); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci put_device(dev); 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic int class_add_groups(struct class *cls, 1428c2ecf20Sopenharmony_ci const struct attribute_group **groups) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci return sysfs_create_groups(&cls->p->subsys.kobj, groups); 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic void class_remove_groups(struct class *cls, 1488c2ecf20Sopenharmony_ci const struct attribute_group **groups) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci return sysfs_remove_groups(&cls->p->subsys.kobj, groups); 1518c2ecf20Sopenharmony_ci} 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ciint __class_register(struct class *cls, struct lock_class_key *key) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci struct subsys_private *cp; 1568c2ecf20Sopenharmony_ci int error; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci pr_debug("device class '%s': registering\n", cls->name); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci cp = kzalloc(sizeof(*cp), GFP_KERNEL); 1618c2ecf20Sopenharmony_ci if (!cp) 1628c2ecf20Sopenharmony_ci return -ENOMEM; 1638c2ecf20Sopenharmony_ci klist_init(&cp->klist_devices, klist_class_dev_get, klist_class_dev_put); 1648c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&cp->interfaces); 1658c2ecf20Sopenharmony_ci kset_init(&cp->glue_dirs); 1668c2ecf20Sopenharmony_ci __mutex_init(&cp->mutex, "subsys mutex", key); 1678c2ecf20Sopenharmony_ci error = kobject_set_name(&cp->subsys.kobj, "%s", cls->name); 1688c2ecf20Sopenharmony_ci if (error) { 1698c2ecf20Sopenharmony_ci kfree(cp); 1708c2ecf20Sopenharmony_ci return error; 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci /* set the default /sys/dev directory for devices of this class */ 1748c2ecf20Sopenharmony_ci if (!cls->dev_kobj) 1758c2ecf20Sopenharmony_ci cls->dev_kobj = sysfs_dev_char_kobj; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci#if defined(CONFIG_BLOCK) 1788c2ecf20Sopenharmony_ci /* let the block class directory show up in the root of sysfs */ 1798c2ecf20Sopenharmony_ci if (!sysfs_deprecated || cls != &block_class) 1808c2ecf20Sopenharmony_ci cp->subsys.kobj.kset = class_kset; 1818c2ecf20Sopenharmony_ci#else 1828c2ecf20Sopenharmony_ci cp->subsys.kobj.kset = class_kset; 1838c2ecf20Sopenharmony_ci#endif 1848c2ecf20Sopenharmony_ci cp->subsys.kobj.ktype = &class_ktype; 1858c2ecf20Sopenharmony_ci cp->class = cls; 1868c2ecf20Sopenharmony_ci cls->p = cp; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci error = kset_register(&cp->subsys); 1898c2ecf20Sopenharmony_ci if (error) { 1908c2ecf20Sopenharmony_ci kfree(cp); 1918c2ecf20Sopenharmony_ci return error; 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci error = class_add_groups(class_get(cls), cls->class_groups); 1948c2ecf20Sopenharmony_ci class_put(cls); 1958c2ecf20Sopenharmony_ci if (error) { 1968c2ecf20Sopenharmony_ci kobject_del(&cp->subsys.kobj); 1978c2ecf20Sopenharmony_ci kfree_const(cp->subsys.kobj.name); 1988c2ecf20Sopenharmony_ci kfree(cp); 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci return error; 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(__class_register); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_civoid class_unregister(struct class *cls) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci pr_debug("device class '%s': unregistering\n", cls->name); 2078c2ecf20Sopenharmony_ci class_remove_groups(cls, cls->class_groups); 2088c2ecf20Sopenharmony_ci kset_unregister(&cls->p->subsys); 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cistatic void class_create_release(struct class *cls) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci pr_debug("%s called for %s\n", __func__, cls->name); 2148c2ecf20Sopenharmony_ci kfree(cls); 2158c2ecf20Sopenharmony_ci} 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci/** 2188c2ecf20Sopenharmony_ci * class_create - create a struct class structure 2198c2ecf20Sopenharmony_ci * @owner: pointer to the module that is to "own" this struct class 2208c2ecf20Sopenharmony_ci * @name: pointer to a string for the name of this class. 2218c2ecf20Sopenharmony_ci * @key: the lock_class_key for this class; used by mutex lock debugging 2228c2ecf20Sopenharmony_ci * 2238c2ecf20Sopenharmony_ci * This is used to create a struct class pointer that can then be used 2248c2ecf20Sopenharmony_ci * in calls to device_create(). 2258c2ecf20Sopenharmony_ci * 2268c2ecf20Sopenharmony_ci * Returns &struct class pointer on success, or ERR_PTR() on error. 2278c2ecf20Sopenharmony_ci * 2288c2ecf20Sopenharmony_ci * Note, the pointer created here is to be destroyed when finished by 2298c2ecf20Sopenharmony_ci * making a call to class_destroy(). 2308c2ecf20Sopenharmony_ci */ 2318c2ecf20Sopenharmony_cistruct class *__class_create(struct module *owner, const char *name, 2328c2ecf20Sopenharmony_ci struct lock_class_key *key) 2338c2ecf20Sopenharmony_ci{ 2348c2ecf20Sopenharmony_ci struct class *cls; 2358c2ecf20Sopenharmony_ci int retval; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci cls = kzalloc(sizeof(*cls), GFP_KERNEL); 2388c2ecf20Sopenharmony_ci if (!cls) { 2398c2ecf20Sopenharmony_ci retval = -ENOMEM; 2408c2ecf20Sopenharmony_ci goto error; 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci cls->name = name; 2448c2ecf20Sopenharmony_ci cls->owner = owner; 2458c2ecf20Sopenharmony_ci cls->class_release = class_create_release; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci retval = __class_register(cls, key); 2488c2ecf20Sopenharmony_ci if (retval) 2498c2ecf20Sopenharmony_ci goto error; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci return cls; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_cierror: 2548c2ecf20Sopenharmony_ci kfree(cls); 2558c2ecf20Sopenharmony_ci return ERR_PTR(retval); 2568c2ecf20Sopenharmony_ci} 2578c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(__class_create); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci/** 2608c2ecf20Sopenharmony_ci * class_destroy - destroys a struct class structure 2618c2ecf20Sopenharmony_ci * @cls: pointer to the struct class that is to be destroyed 2628c2ecf20Sopenharmony_ci * 2638c2ecf20Sopenharmony_ci * Note, the pointer to be destroyed must have been created with a call 2648c2ecf20Sopenharmony_ci * to class_create(). 2658c2ecf20Sopenharmony_ci */ 2668c2ecf20Sopenharmony_civoid class_destroy(struct class *cls) 2678c2ecf20Sopenharmony_ci{ 2688c2ecf20Sopenharmony_ci if ((cls == NULL) || (IS_ERR(cls))) 2698c2ecf20Sopenharmony_ci return; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci class_unregister(cls); 2728c2ecf20Sopenharmony_ci} 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci/** 2758c2ecf20Sopenharmony_ci * class_dev_iter_init - initialize class device iterator 2768c2ecf20Sopenharmony_ci * @iter: class iterator to initialize 2778c2ecf20Sopenharmony_ci * @class: the class we wanna iterate over 2788c2ecf20Sopenharmony_ci * @start: the device to start iterating from, if any 2798c2ecf20Sopenharmony_ci * @type: device_type of the devices to iterate over, NULL for all 2808c2ecf20Sopenharmony_ci * 2818c2ecf20Sopenharmony_ci * Initialize class iterator @iter such that it iterates over devices 2828c2ecf20Sopenharmony_ci * of @class. If @start is set, the list iteration will start there, 2838c2ecf20Sopenharmony_ci * otherwise if it is NULL, the iteration starts at the beginning of 2848c2ecf20Sopenharmony_ci * the list. 2858c2ecf20Sopenharmony_ci */ 2868c2ecf20Sopenharmony_civoid class_dev_iter_init(struct class_dev_iter *iter, struct class *class, 2878c2ecf20Sopenharmony_ci struct device *start, const struct device_type *type) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci struct klist_node *start_knode = NULL; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci if (start) 2928c2ecf20Sopenharmony_ci start_knode = &start->p->knode_class; 2938c2ecf20Sopenharmony_ci klist_iter_init_node(&class->p->klist_devices, &iter->ki, start_knode); 2948c2ecf20Sopenharmony_ci iter->type = type; 2958c2ecf20Sopenharmony_ci} 2968c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(class_dev_iter_init); 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci/** 2998c2ecf20Sopenharmony_ci * class_dev_iter_next - iterate to the next device 3008c2ecf20Sopenharmony_ci * @iter: class iterator to proceed 3018c2ecf20Sopenharmony_ci * 3028c2ecf20Sopenharmony_ci * Proceed @iter to the next device and return it. Returns NULL if 3038c2ecf20Sopenharmony_ci * iteration is complete. 3048c2ecf20Sopenharmony_ci * 3058c2ecf20Sopenharmony_ci * The returned device is referenced and won't be released till 3068c2ecf20Sopenharmony_ci * iterator is proceed to the next device or exited. The caller is 3078c2ecf20Sopenharmony_ci * free to do whatever it wants to do with the device including 3088c2ecf20Sopenharmony_ci * calling back into class code. 3098c2ecf20Sopenharmony_ci */ 3108c2ecf20Sopenharmony_cistruct device *class_dev_iter_next(struct class_dev_iter *iter) 3118c2ecf20Sopenharmony_ci{ 3128c2ecf20Sopenharmony_ci struct klist_node *knode; 3138c2ecf20Sopenharmony_ci struct device *dev; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci while (1) { 3168c2ecf20Sopenharmony_ci knode = klist_next(&iter->ki); 3178c2ecf20Sopenharmony_ci if (!knode) 3188c2ecf20Sopenharmony_ci return NULL; 3198c2ecf20Sopenharmony_ci dev = klist_class_to_dev(knode); 3208c2ecf20Sopenharmony_ci if (!iter->type || iter->type == dev->type) 3218c2ecf20Sopenharmony_ci return dev; 3228c2ecf20Sopenharmony_ci } 3238c2ecf20Sopenharmony_ci} 3248c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(class_dev_iter_next); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci/** 3278c2ecf20Sopenharmony_ci * class_dev_iter_exit - finish iteration 3288c2ecf20Sopenharmony_ci * @iter: class iterator to finish 3298c2ecf20Sopenharmony_ci * 3308c2ecf20Sopenharmony_ci * Finish an iteration. Always call this function after iteration is 3318c2ecf20Sopenharmony_ci * complete whether the iteration ran till the end or not. 3328c2ecf20Sopenharmony_ci */ 3338c2ecf20Sopenharmony_civoid class_dev_iter_exit(struct class_dev_iter *iter) 3348c2ecf20Sopenharmony_ci{ 3358c2ecf20Sopenharmony_ci klist_iter_exit(&iter->ki); 3368c2ecf20Sopenharmony_ci} 3378c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(class_dev_iter_exit); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci/** 3408c2ecf20Sopenharmony_ci * class_for_each_device - device iterator 3418c2ecf20Sopenharmony_ci * @class: the class we're iterating 3428c2ecf20Sopenharmony_ci * @start: the device to start with in the list, if any. 3438c2ecf20Sopenharmony_ci * @data: data for the callback 3448c2ecf20Sopenharmony_ci * @fn: function to be called for each device 3458c2ecf20Sopenharmony_ci * 3468c2ecf20Sopenharmony_ci * Iterate over @class's list of devices, and call @fn for each, 3478c2ecf20Sopenharmony_ci * passing it @data. If @start is set, the list iteration will start 3488c2ecf20Sopenharmony_ci * there, otherwise if it is NULL, the iteration starts at the 3498c2ecf20Sopenharmony_ci * beginning of the list. 3508c2ecf20Sopenharmony_ci * 3518c2ecf20Sopenharmony_ci * We check the return of @fn each time. If it returns anything 3528c2ecf20Sopenharmony_ci * other than 0, we break out and return that value. 3538c2ecf20Sopenharmony_ci * 3548c2ecf20Sopenharmony_ci * @fn is allowed to do anything including calling back into class 3558c2ecf20Sopenharmony_ci * code. There's no locking restriction. 3568c2ecf20Sopenharmony_ci */ 3578c2ecf20Sopenharmony_ciint class_for_each_device(struct class *class, struct device *start, 3588c2ecf20Sopenharmony_ci void *data, int (*fn)(struct device *, void *)) 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci struct class_dev_iter iter; 3618c2ecf20Sopenharmony_ci struct device *dev; 3628c2ecf20Sopenharmony_ci int error = 0; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci if (!class) 3658c2ecf20Sopenharmony_ci return -EINVAL; 3668c2ecf20Sopenharmony_ci if (!class->p) { 3678c2ecf20Sopenharmony_ci WARN(1, "%s called for class '%s' before it was initialized", 3688c2ecf20Sopenharmony_ci __func__, class->name); 3698c2ecf20Sopenharmony_ci return -EINVAL; 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci class_dev_iter_init(&iter, class, start, NULL); 3738c2ecf20Sopenharmony_ci while ((dev = class_dev_iter_next(&iter))) { 3748c2ecf20Sopenharmony_ci error = fn(dev, data); 3758c2ecf20Sopenharmony_ci if (error) 3768c2ecf20Sopenharmony_ci break; 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci class_dev_iter_exit(&iter); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci return error; 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(class_for_each_device); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci/** 3858c2ecf20Sopenharmony_ci * class_find_device - device iterator for locating a particular device 3868c2ecf20Sopenharmony_ci * @class: the class we're iterating 3878c2ecf20Sopenharmony_ci * @start: Device to begin with 3888c2ecf20Sopenharmony_ci * @data: data for the match function 3898c2ecf20Sopenharmony_ci * @match: function to check device 3908c2ecf20Sopenharmony_ci * 3918c2ecf20Sopenharmony_ci * This is similar to the class_for_each_dev() function above, but it 3928c2ecf20Sopenharmony_ci * returns a reference to a device that is 'found' for later use, as 3938c2ecf20Sopenharmony_ci * determined by the @match callback. 3948c2ecf20Sopenharmony_ci * 3958c2ecf20Sopenharmony_ci * The callback should return 0 if the device doesn't match and non-zero 3968c2ecf20Sopenharmony_ci * if it does. If the callback returns non-zero, this function will 3978c2ecf20Sopenharmony_ci * return to the caller and not iterate over any more devices. 3988c2ecf20Sopenharmony_ci * 3998c2ecf20Sopenharmony_ci * Note, you will need to drop the reference with put_device() after use. 4008c2ecf20Sopenharmony_ci * 4018c2ecf20Sopenharmony_ci * @match is allowed to do anything including calling back into class 4028c2ecf20Sopenharmony_ci * code. There's no locking restriction. 4038c2ecf20Sopenharmony_ci */ 4048c2ecf20Sopenharmony_cistruct device *class_find_device(struct class *class, struct device *start, 4058c2ecf20Sopenharmony_ci const void *data, 4068c2ecf20Sopenharmony_ci int (*match)(struct device *, const void *)) 4078c2ecf20Sopenharmony_ci{ 4088c2ecf20Sopenharmony_ci struct class_dev_iter iter; 4098c2ecf20Sopenharmony_ci struct device *dev; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci if (!class) 4128c2ecf20Sopenharmony_ci return NULL; 4138c2ecf20Sopenharmony_ci if (!class->p) { 4148c2ecf20Sopenharmony_ci WARN(1, "%s called for class '%s' before it was initialized", 4158c2ecf20Sopenharmony_ci __func__, class->name); 4168c2ecf20Sopenharmony_ci return NULL; 4178c2ecf20Sopenharmony_ci } 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci class_dev_iter_init(&iter, class, start, NULL); 4208c2ecf20Sopenharmony_ci while ((dev = class_dev_iter_next(&iter))) { 4218c2ecf20Sopenharmony_ci if (match(dev, data)) { 4228c2ecf20Sopenharmony_ci get_device(dev); 4238c2ecf20Sopenharmony_ci break; 4248c2ecf20Sopenharmony_ci } 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci class_dev_iter_exit(&iter); 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci return dev; 4298c2ecf20Sopenharmony_ci} 4308c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(class_find_device); 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ciint class_interface_register(struct class_interface *class_intf) 4338c2ecf20Sopenharmony_ci{ 4348c2ecf20Sopenharmony_ci struct class *parent; 4358c2ecf20Sopenharmony_ci struct class_dev_iter iter; 4368c2ecf20Sopenharmony_ci struct device *dev; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci if (!class_intf || !class_intf->class) 4398c2ecf20Sopenharmony_ci return -ENODEV; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci parent = class_get(class_intf->class); 4428c2ecf20Sopenharmony_ci if (!parent) 4438c2ecf20Sopenharmony_ci return -EINVAL; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci mutex_lock(&parent->p->mutex); 4468c2ecf20Sopenharmony_ci list_add_tail(&class_intf->node, &parent->p->interfaces); 4478c2ecf20Sopenharmony_ci if (class_intf->add_dev) { 4488c2ecf20Sopenharmony_ci class_dev_iter_init(&iter, parent, NULL, NULL); 4498c2ecf20Sopenharmony_ci while ((dev = class_dev_iter_next(&iter))) 4508c2ecf20Sopenharmony_ci class_intf->add_dev(dev, class_intf); 4518c2ecf20Sopenharmony_ci class_dev_iter_exit(&iter); 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci mutex_unlock(&parent->p->mutex); 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci return 0; 4568c2ecf20Sopenharmony_ci} 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_civoid class_interface_unregister(struct class_interface *class_intf) 4598c2ecf20Sopenharmony_ci{ 4608c2ecf20Sopenharmony_ci struct class *parent = class_intf->class; 4618c2ecf20Sopenharmony_ci struct class_dev_iter iter; 4628c2ecf20Sopenharmony_ci struct device *dev; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci if (!parent) 4658c2ecf20Sopenharmony_ci return; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci mutex_lock(&parent->p->mutex); 4688c2ecf20Sopenharmony_ci list_del_init(&class_intf->node); 4698c2ecf20Sopenharmony_ci if (class_intf->remove_dev) { 4708c2ecf20Sopenharmony_ci class_dev_iter_init(&iter, parent, NULL, NULL); 4718c2ecf20Sopenharmony_ci while ((dev = class_dev_iter_next(&iter))) 4728c2ecf20Sopenharmony_ci class_intf->remove_dev(dev, class_intf); 4738c2ecf20Sopenharmony_ci class_dev_iter_exit(&iter); 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci mutex_unlock(&parent->p->mutex); 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci class_put(parent); 4788c2ecf20Sopenharmony_ci} 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_cissize_t show_class_attr_string(struct class *class, 4818c2ecf20Sopenharmony_ci struct class_attribute *attr, char *buf) 4828c2ecf20Sopenharmony_ci{ 4838c2ecf20Sopenharmony_ci struct class_attribute_string *cs; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci cs = container_of(attr, struct class_attribute_string, attr); 4868c2ecf20Sopenharmony_ci return sysfs_emit(buf, "%s\n", cs->str); 4878c2ecf20Sopenharmony_ci} 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(show_class_attr_string); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_cistruct class_compat { 4928c2ecf20Sopenharmony_ci struct kobject *kobj; 4938c2ecf20Sopenharmony_ci}; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci/** 4968c2ecf20Sopenharmony_ci * class_compat_register - register a compatibility class 4978c2ecf20Sopenharmony_ci * @name: the name of the class 4988c2ecf20Sopenharmony_ci * 4998c2ecf20Sopenharmony_ci * Compatibility class are meant as a temporary user-space compatibility 5008c2ecf20Sopenharmony_ci * workaround when converting a family of class devices to a bus devices. 5018c2ecf20Sopenharmony_ci */ 5028c2ecf20Sopenharmony_cistruct class_compat *class_compat_register(const char *name) 5038c2ecf20Sopenharmony_ci{ 5048c2ecf20Sopenharmony_ci struct class_compat *cls; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci cls = kmalloc(sizeof(struct class_compat), GFP_KERNEL); 5078c2ecf20Sopenharmony_ci if (!cls) 5088c2ecf20Sopenharmony_ci return NULL; 5098c2ecf20Sopenharmony_ci cls->kobj = kobject_create_and_add(name, &class_kset->kobj); 5108c2ecf20Sopenharmony_ci if (!cls->kobj) { 5118c2ecf20Sopenharmony_ci kfree(cls); 5128c2ecf20Sopenharmony_ci return NULL; 5138c2ecf20Sopenharmony_ci } 5148c2ecf20Sopenharmony_ci return cls; 5158c2ecf20Sopenharmony_ci} 5168c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(class_compat_register); 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci/** 5198c2ecf20Sopenharmony_ci * class_compat_unregister - unregister a compatibility class 5208c2ecf20Sopenharmony_ci * @cls: the class to unregister 5218c2ecf20Sopenharmony_ci */ 5228c2ecf20Sopenharmony_civoid class_compat_unregister(struct class_compat *cls) 5238c2ecf20Sopenharmony_ci{ 5248c2ecf20Sopenharmony_ci kobject_put(cls->kobj); 5258c2ecf20Sopenharmony_ci kfree(cls); 5268c2ecf20Sopenharmony_ci} 5278c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(class_compat_unregister); 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci/** 5308c2ecf20Sopenharmony_ci * class_compat_create_link - create a compatibility class device link to 5318c2ecf20Sopenharmony_ci * a bus device 5328c2ecf20Sopenharmony_ci * @cls: the compatibility class 5338c2ecf20Sopenharmony_ci * @dev: the target bus device 5348c2ecf20Sopenharmony_ci * @device_link: an optional device to which a "device" link should be created 5358c2ecf20Sopenharmony_ci */ 5368c2ecf20Sopenharmony_ciint class_compat_create_link(struct class_compat *cls, struct device *dev, 5378c2ecf20Sopenharmony_ci struct device *device_link) 5388c2ecf20Sopenharmony_ci{ 5398c2ecf20Sopenharmony_ci int error; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci error = sysfs_create_link(cls->kobj, &dev->kobj, dev_name(dev)); 5428c2ecf20Sopenharmony_ci if (error) 5438c2ecf20Sopenharmony_ci return error; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci /* 5468c2ecf20Sopenharmony_ci * Optionally add a "device" link (typically to the parent), as a 5478c2ecf20Sopenharmony_ci * class device would have one and we want to provide as much 5488c2ecf20Sopenharmony_ci * backwards compatibility as possible. 5498c2ecf20Sopenharmony_ci */ 5508c2ecf20Sopenharmony_ci if (device_link) { 5518c2ecf20Sopenharmony_ci error = sysfs_create_link(&dev->kobj, &device_link->kobj, 5528c2ecf20Sopenharmony_ci "device"); 5538c2ecf20Sopenharmony_ci if (error) 5548c2ecf20Sopenharmony_ci sysfs_remove_link(cls->kobj, dev_name(dev)); 5558c2ecf20Sopenharmony_ci } 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci return error; 5588c2ecf20Sopenharmony_ci} 5598c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(class_compat_create_link); 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci/** 5628c2ecf20Sopenharmony_ci * class_compat_remove_link - remove a compatibility class device link to 5638c2ecf20Sopenharmony_ci * a bus device 5648c2ecf20Sopenharmony_ci * @cls: the compatibility class 5658c2ecf20Sopenharmony_ci * @dev: the target bus device 5668c2ecf20Sopenharmony_ci * @device_link: an optional device to which a "device" link was previously 5678c2ecf20Sopenharmony_ci * created 5688c2ecf20Sopenharmony_ci */ 5698c2ecf20Sopenharmony_civoid class_compat_remove_link(struct class_compat *cls, struct device *dev, 5708c2ecf20Sopenharmony_ci struct device *device_link) 5718c2ecf20Sopenharmony_ci{ 5728c2ecf20Sopenharmony_ci if (device_link) 5738c2ecf20Sopenharmony_ci sysfs_remove_link(&dev->kobj, "device"); 5748c2ecf20Sopenharmony_ci sysfs_remove_link(cls->kobj, dev_name(dev)); 5758c2ecf20Sopenharmony_ci} 5768c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(class_compat_remove_link); 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ciint __init classes_init(void) 5798c2ecf20Sopenharmony_ci{ 5808c2ecf20Sopenharmony_ci class_kset = kset_create_and_add("class", NULL, NULL); 5818c2ecf20Sopenharmony_ci if (!class_kset) 5828c2ecf20Sopenharmony_ci return -ENOMEM; 5838c2ecf20Sopenharmony_ci return 0; 5848c2ecf20Sopenharmony_ci} 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(class_create_file_ns); 5878c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(class_remove_file_ns); 5888c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(class_unregister); 5898c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(class_destroy); 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(class_interface_register); 5928c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(class_interface_unregister); 593