162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * class.c - basic device class management 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2002-3 Patrick Mochel 662306a36Sopenharmony_ci * Copyright (c) 2002-3 Open Source Development Labs 762306a36Sopenharmony_ci * Copyright (c) 2003-2004 Greg Kroah-Hartman 862306a36Sopenharmony_ci * Copyright (c) 2003-2004 IBM Corp. 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/device/class.h> 1262306a36Sopenharmony_ci#include <linux/device.h> 1362306a36Sopenharmony_ci#include <linux/module.h> 1462306a36Sopenharmony_ci#include <linux/init.h> 1562306a36Sopenharmony_ci#include <linux/string.h> 1662306a36Sopenharmony_ci#include <linux/kdev_t.h> 1762306a36Sopenharmony_ci#include <linux/err.h> 1862306a36Sopenharmony_ci#include <linux/slab.h> 1962306a36Sopenharmony_ci#include <linux/blkdev.h> 2062306a36Sopenharmony_ci#include <linux/mutex.h> 2162306a36Sopenharmony_ci#include "base.h" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/* /sys/class */ 2462306a36Sopenharmony_cistatic struct kset *class_kset; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#define to_class_attr(_attr) container_of(_attr, struct class_attribute, attr) 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/** 2962306a36Sopenharmony_ci * class_to_subsys - Turn a struct class into a struct subsys_private 3062306a36Sopenharmony_ci * 3162306a36Sopenharmony_ci * @class: pointer to the struct bus_type to look up 3262306a36Sopenharmony_ci * 3362306a36Sopenharmony_ci * The driver core internals need to work on the subsys_private structure, not 3462306a36Sopenharmony_ci * the external struct class pointer. This function walks the list of 3562306a36Sopenharmony_ci * registered classes in the system and finds the matching one and returns the 3662306a36Sopenharmony_ci * internal struct subsys_private that relates to that class. 3762306a36Sopenharmony_ci * 3862306a36Sopenharmony_ci * Note, the reference count of the return value is INCREMENTED if it is not 3962306a36Sopenharmony_ci * NULL. A call to subsys_put() must be done when finished with the pointer in 4062306a36Sopenharmony_ci * order for it to be properly freed. 4162306a36Sopenharmony_ci */ 4262306a36Sopenharmony_cistruct subsys_private *class_to_subsys(const struct class *class) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci struct subsys_private *sp = NULL; 4562306a36Sopenharmony_ci struct kobject *kobj; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci if (!class || !class_kset) 4862306a36Sopenharmony_ci return NULL; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci spin_lock(&class_kset->list_lock); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci if (list_empty(&class_kset->list)) 5362306a36Sopenharmony_ci goto done; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci list_for_each_entry(kobj, &class_kset->list, entry) { 5662306a36Sopenharmony_ci struct kset *kset = container_of(kobj, struct kset, kobj); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci sp = container_of_const(kset, struct subsys_private, subsys); 5962306a36Sopenharmony_ci if (sp->class == class) 6062306a36Sopenharmony_ci goto done; 6162306a36Sopenharmony_ci } 6262306a36Sopenharmony_ci sp = NULL; 6362306a36Sopenharmony_cidone: 6462306a36Sopenharmony_ci sp = subsys_get(sp); 6562306a36Sopenharmony_ci spin_unlock(&class_kset->list_lock); 6662306a36Sopenharmony_ci return sp; 6762306a36Sopenharmony_ci} 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic ssize_t class_attr_show(struct kobject *kobj, struct attribute *attr, 7062306a36Sopenharmony_ci char *buf) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci struct class_attribute *class_attr = to_class_attr(attr); 7362306a36Sopenharmony_ci struct subsys_private *cp = to_subsys_private(kobj); 7462306a36Sopenharmony_ci ssize_t ret = -EIO; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci if (class_attr->show) 7762306a36Sopenharmony_ci ret = class_attr->show(cp->class, class_attr, buf); 7862306a36Sopenharmony_ci return ret; 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistatic ssize_t class_attr_store(struct kobject *kobj, struct attribute *attr, 8262306a36Sopenharmony_ci const char *buf, size_t count) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci struct class_attribute *class_attr = to_class_attr(attr); 8562306a36Sopenharmony_ci struct subsys_private *cp = to_subsys_private(kobj); 8662306a36Sopenharmony_ci ssize_t ret = -EIO; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci if (class_attr->store) 8962306a36Sopenharmony_ci ret = class_attr->store(cp->class, class_attr, buf, count); 9062306a36Sopenharmony_ci return ret; 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistatic void class_release(struct kobject *kobj) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci struct subsys_private *cp = to_subsys_private(kobj); 9662306a36Sopenharmony_ci const struct class *class = cp->class; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci pr_debug("class '%s': release.\n", class->name); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci if (class->class_release) 10162306a36Sopenharmony_ci class->class_release(class); 10262306a36Sopenharmony_ci else 10362306a36Sopenharmony_ci pr_debug("class '%s' does not have a release() function, " 10462306a36Sopenharmony_ci "be careful\n", class->name); 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci lockdep_unregister_key(&cp->lock_key); 10762306a36Sopenharmony_ci kfree(cp); 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic const struct kobj_ns_type_operations *class_child_ns_type(const struct kobject *kobj) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci const struct subsys_private *cp = to_subsys_private(kobj); 11362306a36Sopenharmony_ci const struct class *class = cp->class; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci return class->ns_type; 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistatic const struct sysfs_ops class_sysfs_ops = { 11962306a36Sopenharmony_ci .show = class_attr_show, 12062306a36Sopenharmony_ci .store = class_attr_store, 12162306a36Sopenharmony_ci}; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic const struct kobj_type class_ktype = { 12462306a36Sopenharmony_ci .sysfs_ops = &class_sysfs_ops, 12562306a36Sopenharmony_ci .release = class_release, 12662306a36Sopenharmony_ci .child_ns_type = class_child_ns_type, 12762306a36Sopenharmony_ci}; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ciint class_create_file_ns(const struct class *cls, const struct class_attribute *attr, 13062306a36Sopenharmony_ci const void *ns) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci struct subsys_private *sp = class_to_subsys(cls); 13362306a36Sopenharmony_ci int error; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci if (!sp) 13662306a36Sopenharmony_ci return -EINVAL; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci error = sysfs_create_file_ns(&sp->subsys.kobj, &attr->attr, ns); 13962306a36Sopenharmony_ci subsys_put(sp); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci return error; 14262306a36Sopenharmony_ci} 14362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(class_create_file_ns); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_civoid class_remove_file_ns(const struct class *cls, const struct class_attribute *attr, 14662306a36Sopenharmony_ci const void *ns) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci struct subsys_private *sp = class_to_subsys(cls); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci if (!sp) 15162306a36Sopenharmony_ci return; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci sysfs_remove_file_ns(&sp->subsys.kobj, &attr->attr, ns); 15462306a36Sopenharmony_ci subsys_put(sp); 15562306a36Sopenharmony_ci} 15662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(class_remove_file_ns); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic struct device *klist_class_to_dev(struct klist_node *n) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci struct device_private *p = to_device_private_class(n); 16162306a36Sopenharmony_ci return p->device; 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic void klist_class_dev_get(struct klist_node *n) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci struct device *dev = klist_class_to_dev(n); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci get_device(dev); 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistatic void klist_class_dev_put(struct klist_node *n) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci struct device *dev = klist_class_to_dev(n); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci put_device(dev); 17662306a36Sopenharmony_ci} 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ciint class_register(const struct class *cls) 17962306a36Sopenharmony_ci{ 18062306a36Sopenharmony_ci struct subsys_private *cp; 18162306a36Sopenharmony_ci struct lock_class_key *key; 18262306a36Sopenharmony_ci int error; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci pr_debug("device class '%s': registering\n", cls->name); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci cp = kzalloc(sizeof(*cp), GFP_KERNEL); 18762306a36Sopenharmony_ci if (!cp) 18862306a36Sopenharmony_ci return -ENOMEM; 18962306a36Sopenharmony_ci klist_init(&cp->klist_devices, klist_class_dev_get, klist_class_dev_put); 19062306a36Sopenharmony_ci INIT_LIST_HEAD(&cp->interfaces); 19162306a36Sopenharmony_ci kset_init(&cp->glue_dirs); 19262306a36Sopenharmony_ci key = &cp->lock_key; 19362306a36Sopenharmony_ci lockdep_register_key(key); 19462306a36Sopenharmony_ci __mutex_init(&cp->mutex, "subsys mutex", key); 19562306a36Sopenharmony_ci error = kobject_set_name(&cp->subsys.kobj, "%s", cls->name); 19662306a36Sopenharmony_ci if (error) { 19762306a36Sopenharmony_ci kfree(cp); 19862306a36Sopenharmony_ci return error; 19962306a36Sopenharmony_ci } 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci cp->subsys.kobj.kset = class_kset; 20262306a36Sopenharmony_ci cp->subsys.kobj.ktype = &class_ktype; 20362306a36Sopenharmony_ci cp->class = cls; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci error = kset_register(&cp->subsys); 20662306a36Sopenharmony_ci if (error) 20762306a36Sopenharmony_ci goto err_out; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci error = sysfs_create_groups(&cp->subsys.kobj, cls->class_groups); 21062306a36Sopenharmony_ci if (error) { 21162306a36Sopenharmony_ci kobject_del(&cp->subsys.kobj); 21262306a36Sopenharmony_ci kfree_const(cp->subsys.kobj.name); 21362306a36Sopenharmony_ci goto err_out; 21462306a36Sopenharmony_ci } 21562306a36Sopenharmony_ci return 0; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_cierr_out: 21862306a36Sopenharmony_ci lockdep_unregister_key(key); 21962306a36Sopenharmony_ci kfree(cp); 22062306a36Sopenharmony_ci return error; 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(class_register); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_civoid class_unregister(const struct class *cls) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci struct subsys_private *sp = class_to_subsys(cls); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci if (!sp) 22962306a36Sopenharmony_ci return; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci pr_debug("device class '%s': unregistering\n", cls->name); 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci sysfs_remove_groups(&sp->subsys.kobj, cls->class_groups); 23462306a36Sopenharmony_ci kset_unregister(&sp->subsys); 23562306a36Sopenharmony_ci subsys_put(sp); 23662306a36Sopenharmony_ci} 23762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(class_unregister); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cistatic void class_create_release(const struct class *cls) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci pr_debug("%s called for %s\n", __func__, cls->name); 24262306a36Sopenharmony_ci kfree(cls); 24362306a36Sopenharmony_ci} 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci/** 24662306a36Sopenharmony_ci * class_create - create a struct class structure 24762306a36Sopenharmony_ci * @name: pointer to a string for the name of this class. 24862306a36Sopenharmony_ci * 24962306a36Sopenharmony_ci * This is used to create a struct class pointer that can then be used 25062306a36Sopenharmony_ci * in calls to device_create(). 25162306a36Sopenharmony_ci * 25262306a36Sopenharmony_ci * Returns &struct class pointer on success, or ERR_PTR() on error. 25362306a36Sopenharmony_ci * 25462306a36Sopenharmony_ci * Note, the pointer created here is to be destroyed when finished by 25562306a36Sopenharmony_ci * making a call to class_destroy(). 25662306a36Sopenharmony_ci */ 25762306a36Sopenharmony_cistruct class *class_create(const char *name) 25862306a36Sopenharmony_ci{ 25962306a36Sopenharmony_ci struct class *cls; 26062306a36Sopenharmony_ci int retval; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci cls = kzalloc(sizeof(*cls), GFP_KERNEL); 26362306a36Sopenharmony_ci if (!cls) { 26462306a36Sopenharmony_ci retval = -ENOMEM; 26562306a36Sopenharmony_ci goto error; 26662306a36Sopenharmony_ci } 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci cls->name = name; 26962306a36Sopenharmony_ci cls->class_release = class_create_release; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci retval = class_register(cls); 27262306a36Sopenharmony_ci if (retval) 27362306a36Sopenharmony_ci goto error; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci return cls; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_cierror: 27862306a36Sopenharmony_ci kfree(cls); 27962306a36Sopenharmony_ci return ERR_PTR(retval); 28062306a36Sopenharmony_ci} 28162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(class_create); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci/** 28462306a36Sopenharmony_ci * class_destroy - destroys a struct class structure 28562306a36Sopenharmony_ci * @cls: pointer to the struct class that is to be destroyed 28662306a36Sopenharmony_ci * 28762306a36Sopenharmony_ci * Note, the pointer to be destroyed must have been created with a call 28862306a36Sopenharmony_ci * to class_create(). 28962306a36Sopenharmony_ci */ 29062306a36Sopenharmony_civoid class_destroy(const struct class *cls) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci if (IS_ERR_OR_NULL(cls)) 29362306a36Sopenharmony_ci return; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci class_unregister(cls); 29662306a36Sopenharmony_ci} 29762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(class_destroy); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci/** 30062306a36Sopenharmony_ci * class_dev_iter_init - initialize class device iterator 30162306a36Sopenharmony_ci * @iter: class iterator to initialize 30262306a36Sopenharmony_ci * @class: the class we wanna iterate over 30362306a36Sopenharmony_ci * @start: the device to start iterating from, if any 30462306a36Sopenharmony_ci * @type: device_type of the devices to iterate over, NULL for all 30562306a36Sopenharmony_ci * 30662306a36Sopenharmony_ci * Initialize class iterator @iter such that it iterates over devices 30762306a36Sopenharmony_ci * of @class. If @start is set, the list iteration will start there, 30862306a36Sopenharmony_ci * otherwise if it is NULL, the iteration starts at the beginning of 30962306a36Sopenharmony_ci * the list. 31062306a36Sopenharmony_ci */ 31162306a36Sopenharmony_civoid class_dev_iter_init(struct class_dev_iter *iter, const struct class *class, 31262306a36Sopenharmony_ci const struct device *start, const struct device_type *type) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci struct subsys_private *sp = class_to_subsys(class); 31562306a36Sopenharmony_ci struct klist_node *start_knode = NULL; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci if (!sp) 31862306a36Sopenharmony_ci return; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci if (start) 32162306a36Sopenharmony_ci start_knode = &start->p->knode_class; 32262306a36Sopenharmony_ci klist_iter_init_node(&sp->klist_devices, &iter->ki, start_knode); 32362306a36Sopenharmony_ci iter->type = type; 32462306a36Sopenharmony_ci iter->sp = sp; 32562306a36Sopenharmony_ci} 32662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(class_dev_iter_init); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci/** 32962306a36Sopenharmony_ci * class_dev_iter_next - iterate to the next device 33062306a36Sopenharmony_ci * @iter: class iterator to proceed 33162306a36Sopenharmony_ci * 33262306a36Sopenharmony_ci * Proceed @iter to the next device and return it. Returns NULL if 33362306a36Sopenharmony_ci * iteration is complete. 33462306a36Sopenharmony_ci * 33562306a36Sopenharmony_ci * The returned device is referenced and won't be released till 33662306a36Sopenharmony_ci * iterator is proceed to the next device or exited. The caller is 33762306a36Sopenharmony_ci * free to do whatever it wants to do with the device including 33862306a36Sopenharmony_ci * calling back into class code. 33962306a36Sopenharmony_ci */ 34062306a36Sopenharmony_cistruct device *class_dev_iter_next(struct class_dev_iter *iter) 34162306a36Sopenharmony_ci{ 34262306a36Sopenharmony_ci struct klist_node *knode; 34362306a36Sopenharmony_ci struct device *dev; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci while (1) { 34662306a36Sopenharmony_ci knode = klist_next(&iter->ki); 34762306a36Sopenharmony_ci if (!knode) 34862306a36Sopenharmony_ci return NULL; 34962306a36Sopenharmony_ci dev = klist_class_to_dev(knode); 35062306a36Sopenharmony_ci if (!iter->type || iter->type == dev->type) 35162306a36Sopenharmony_ci return dev; 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(class_dev_iter_next); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci/** 35762306a36Sopenharmony_ci * class_dev_iter_exit - finish iteration 35862306a36Sopenharmony_ci * @iter: class iterator to finish 35962306a36Sopenharmony_ci * 36062306a36Sopenharmony_ci * Finish an iteration. Always call this function after iteration is 36162306a36Sopenharmony_ci * complete whether the iteration ran till the end or not. 36262306a36Sopenharmony_ci */ 36362306a36Sopenharmony_civoid class_dev_iter_exit(struct class_dev_iter *iter) 36462306a36Sopenharmony_ci{ 36562306a36Sopenharmony_ci klist_iter_exit(&iter->ki); 36662306a36Sopenharmony_ci subsys_put(iter->sp); 36762306a36Sopenharmony_ci} 36862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(class_dev_iter_exit); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci/** 37162306a36Sopenharmony_ci * class_for_each_device - device iterator 37262306a36Sopenharmony_ci * @class: the class we're iterating 37362306a36Sopenharmony_ci * @start: the device to start with in the list, if any. 37462306a36Sopenharmony_ci * @data: data for the callback 37562306a36Sopenharmony_ci * @fn: function to be called for each device 37662306a36Sopenharmony_ci * 37762306a36Sopenharmony_ci * Iterate over @class's list of devices, and call @fn for each, 37862306a36Sopenharmony_ci * passing it @data. If @start is set, the list iteration will start 37962306a36Sopenharmony_ci * there, otherwise if it is NULL, the iteration starts at the 38062306a36Sopenharmony_ci * beginning of the list. 38162306a36Sopenharmony_ci * 38262306a36Sopenharmony_ci * We check the return of @fn each time. If it returns anything 38362306a36Sopenharmony_ci * other than 0, we break out and return that value. 38462306a36Sopenharmony_ci * 38562306a36Sopenharmony_ci * @fn is allowed to do anything including calling back into class 38662306a36Sopenharmony_ci * code. There's no locking restriction. 38762306a36Sopenharmony_ci */ 38862306a36Sopenharmony_ciint class_for_each_device(const struct class *class, const struct device *start, 38962306a36Sopenharmony_ci void *data, int (*fn)(struct device *, void *)) 39062306a36Sopenharmony_ci{ 39162306a36Sopenharmony_ci struct subsys_private *sp = class_to_subsys(class); 39262306a36Sopenharmony_ci struct class_dev_iter iter; 39362306a36Sopenharmony_ci struct device *dev; 39462306a36Sopenharmony_ci int error = 0; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci if (!class) 39762306a36Sopenharmony_ci return -EINVAL; 39862306a36Sopenharmony_ci if (!sp) { 39962306a36Sopenharmony_ci WARN(1, "%s called for class '%s' before it was initialized", 40062306a36Sopenharmony_ci __func__, class->name); 40162306a36Sopenharmony_ci return -EINVAL; 40262306a36Sopenharmony_ci } 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci class_dev_iter_init(&iter, class, start, NULL); 40562306a36Sopenharmony_ci while ((dev = class_dev_iter_next(&iter))) { 40662306a36Sopenharmony_ci error = fn(dev, data); 40762306a36Sopenharmony_ci if (error) 40862306a36Sopenharmony_ci break; 40962306a36Sopenharmony_ci } 41062306a36Sopenharmony_ci class_dev_iter_exit(&iter); 41162306a36Sopenharmony_ci subsys_put(sp); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci return error; 41462306a36Sopenharmony_ci} 41562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(class_for_each_device); 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci/** 41862306a36Sopenharmony_ci * class_find_device - device iterator for locating a particular device 41962306a36Sopenharmony_ci * @class: the class we're iterating 42062306a36Sopenharmony_ci * @start: Device to begin with 42162306a36Sopenharmony_ci * @data: data for the match function 42262306a36Sopenharmony_ci * @match: function to check device 42362306a36Sopenharmony_ci * 42462306a36Sopenharmony_ci * This is similar to the class_for_each_dev() function above, but it 42562306a36Sopenharmony_ci * returns a reference to a device that is 'found' for later use, as 42662306a36Sopenharmony_ci * determined by the @match callback. 42762306a36Sopenharmony_ci * 42862306a36Sopenharmony_ci * The callback should return 0 if the device doesn't match and non-zero 42962306a36Sopenharmony_ci * if it does. If the callback returns non-zero, this function will 43062306a36Sopenharmony_ci * return to the caller and not iterate over any more devices. 43162306a36Sopenharmony_ci * 43262306a36Sopenharmony_ci * Note, you will need to drop the reference with put_device() after use. 43362306a36Sopenharmony_ci * 43462306a36Sopenharmony_ci * @match is allowed to do anything including calling back into class 43562306a36Sopenharmony_ci * code. There's no locking restriction. 43662306a36Sopenharmony_ci */ 43762306a36Sopenharmony_cistruct device *class_find_device(const struct class *class, const struct device *start, 43862306a36Sopenharmony_ci const void *data, 43962306a36Sopenharmony_ci int (*match)(struct device *, const void *)) 44062306a36Sopenharmony_ci{ 44162306a36Sopenharmony_ci struct subsys_private *sp = class_to_subsys(class); 44262306a36Sopenharmony_ci struct class_dev_iter iter; 44362306a36Sopenharmony_ci struct device *dev; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci if (!class) 44662306a36Sopenharmony_ci return NULL; 44762306a36Sopenharmony_ci if (!sp) { 44862306a36Sopenharmony_ci WARN(1, "%s called for class '%s' before it was initialized", 44962306a36Sopenharmony_ci __func__, class->name); 45062306a36Sopenharmony_ci return NULL; 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci class_dev_iter_init(&iter, class, start, NULL); 45462306a36Sopenharmony_ci while ((dev = class_dev_iter_next(&iter))) { 45562306a36Sopenharmony_ci if (match(dev, data)) { 45662306a36Sopenharmony_ci get_device(dev); 45762306a36Sopenharmony_ci break; 45862306a36Sopenharmony_ci } 45962306a36Sopenharmony_ci } 46062306a36Sopenharmony_ci class_dev_iter_exit(&iter); 46162306a36Sopenharmony_ci subsys_put(sp); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci return dev; 46462306a36Sopenharmony_ci} 46562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(class_find_device); 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ciint class_interface_register(struct class_interface *class_intf) 46862306a36Sopenharmony_ci{ 46962306a36Sopenharmony_ci struct subsys_private *sp; 47062306a36Sopenharmony_ci const struct class *parent; 47162306a36Sopenharmony_ci struct class_dev_iter iter; 47262306a36Sopenharmony_ci struct device *dev; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci if (!class_intf || !class_intf->class) 47562306a36Sopenharmony_ci return -ENODEV; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci parent = class_intf->class; 47862306a36Sopenharmony_ci sp = class_to_subsys(parent); 47962306a36Sopenharmony_ci if (!sp) 48062306a36Sopenharmony_ci return -EINVAL; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci /* 48362306a36Sopenharmony_ci * Reference in sp is now incremented and will be dropped when 48462306a36Sopenharmony_ci * the interface is removed in the call to class_interface_unregister() 48562306a36Sopenharmony_ci */ 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci mutex_lock(&sp->mutex); 48862306a36Sopenharmony_ci list_add_tail(&class_intf->node, &sp->interfaces); 48962306a36Sopenharmony_ci if (class_intf->add_dev) { 49062306a36Sopenharmony_ci class_dev_iter_init(&iter, parent, NULL, NULL); 49162306a36Sopenharmony_ci while ((dev = class_dev_iter_next(&iter))) 49262306a36Sopenharmony_ci class_intf->add_dev(dev); 49362306a36Sopenharmony_ci class_dev_iter_exit(&iter); 49462306a36Sopenharmony_ci } 49562306a36Sopenharmony_ci mutex_unlock(&sp->mutex); 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci return 0; 49862306a36Sopenharmony_ci} 49962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(class_interface_register); 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_civoid class_interface_unregister(struct class_interface *class_intf) 50262306a36Sopenharmony_ci{ 50362306a36Sopenharmony_ci struct subsys_private *sp; 50462306a36Sopenharmony_ci const struct class *parent = class_intf->class; 50562306a36Sopenharmony_ci struct class_dev_iter iter; 50662306a36Sopenharmony_ci struct device *dev; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci if (!parent) 50962306a36Sopenharmony_ci return; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci sp = class_to_subsys(parent); 51262306a36Sopenharmony_ci if (!sp) 51362306a36Sopenharmony_ci return; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci mutex_lock(&sp->mutex); 51662306a36Sopenharmony_ci list_del_init(&class_intf->node); 51762306a36Sopenharmony_ci if (class_intf->remove_dev) { 51862306a36Sopenharmony_ci class_dev_iter_init(&iter, parent, NULL, NULL); 51962306a36Sopenharmony_ci while ((dev = class_dev_iter_next(&iter))) 52062306a36Sopenharmony_ci class_intf->remove_dev(dev); 52162306a36Sopenharmony_ci class_dev_iter_exit(&iter); 52262306a36Sopenharmony_ci } 52362306a36Sopenharmony_ci mutex_unlock(&sp->mutex); 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci /* 52662306a36Sopenharmony_ci * Decrement the reference count twice, once for the class_to_subsys() 52762306a36Sopenharmony_ci * call in the start of this function, and the second one from the 52862306a36Sopenharmony_ci * reference increment in class_interface_register() 52962306a36Sopenharmony_ci */ 53062306a36Sopenharmony_ci subsys_put(sp); 53162306a36Sopenharmony_ci subsys_put(sp); 53262306a36Sopenharmony_ci} 53362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(class_interface_unregister); 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_cissize_t show_class_attr_string(const struct class *class, 53662306a36Sopenharmony_ci const struct class_attribute *attr, char *buf) 53762306a36Sopenharmony_ci{ 53862306a36Sopenharmony_ci struct class_attribute_string *cs; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci cs = container_of(attr, struct class_attribute_string, attr); 54162306a36Sopenharmony_ci return sysfs_emit(buf, "%s\n", cs->str); 54262306a36Sopenharmony_ci} 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(show_class_attr_string); 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_cistruct class_compat { 54762306a36Sopenharmony_ci struct kobject *kobj; 54862306a36Sopenharmony_ci}; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci/** 55162306a36Sopenharmony_ci * class_compat_register - register a compatibility class 55262306a36Sopenharmony_ci * @name: the name of the class 55362306a36Sopenharmony_ci * 55462306a36Sopenharmony_ci * Compatibility class are meant as a temporary user-space compatibility 55562306a36Sopenharmony_ci * workaround when converting a family of class devices to a bus devices. 55662306a36Sopenharmony_ci */ 55762306a36Sopenharmony_cistruct class_compat *class_compat_register(const char *name) 55862306a36Sopenharmony_ci{ 55962306a36Sopenharmony_ci struct class_compat *cls; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci cls = kmalloc(sizeof(struct class_compat), GFP_KERNEL); 56262306a36Sopenharmony_ci if (!cls) 56362306a36Sopenharmony_ci return NULL; 56462306a36Sopenharmony_ci cls->kobj = kobject_create_and_add(name, &class_kset->kobj); 56562306a36Sopenharmony_ci if (!cls->kobj) { 56662306a36Sopenharmony_ci kfree(cls); 56762306a36Sopenharmony_ci return NULL; 56862306a36Sopenharmony_ci } 56962306a36Sopenharmony_ci return cls; 57062306a36Sopenharmony_ci} 57162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(class_compat_register); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci/** 57462306a36Sopenharmony_ci * class_compat_unregister - unregister a compatibility class 57562306a36Sopenharmony_ci * @cls: the class to unregister 57662306a36Sopenharmony_ci */ 57762306a36Sopenharmony_civoid class_compat_unregister(struct class_compat *cls) 57862306a36Sopenharmony_ci{ 57962306a36Sopenharmony_ci kobject_put(cls->kobj); 58062306a36Sopenharmony_ci kfree(cls); 58162306a36Sopenharmony_ci} 58262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(class_compat_unregister); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci/** 58562306a36Sopenharmony_ci * class_compat_create_link - create a compatibility class device link to 58662306a36Sopenharmony_ci * a bus device 58762306a36Sopenharmony_ci * @cls: the compatibility class 58862306a36Sopenharmony_ci * @dev: the target bus device 58962306a36Sopenharmony_ci * @device_link: an optional device to which a "device" link should be created 59062306a36Sopenharmony_ci */ 59162306a36Sopenharmony_ciint class_compat_create_link(struct class_compat *cls, struct device *dev, 59262306a36Sopenharmony_ci struct device *device_link) 59362306a36Sopenharmony_ci{ 59462306a36Sopenharmony_ci int error; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci error = sysfs_create_link(cls->kobj, &dev->kobj, dev_name(dev)); 59762306a36Sopenharmony_ci if (error) 59862306a36Sopenharmony_ci return error; 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci /* 60162306a36Sopenharmony_ci * Optionally add a "device" link (typically to the parent), as a 60262306a36Sopenharmony_ci * class device would have one and we want to provide as much 60362306a36Sopenharmony_ci * backwards compatibility as possible. 60462306a36Sopenharmony_ci */ 60562306a36Sopenharmony_ci if (device_link) { 60662306a36Sopenharmony_ci error = sysfs_create_link(&dev->kobj, &device_link->kobj, 60762306a36Sopenharmony_ci "device"); 60862306a36Sopenharmony_ci if (error) 60962306a36Sopenharmony_ci sysfs_remove_link(cls->kobj, dev_name(dev)); 61062306a36Sopenharmony_ci } 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci return error; 61362306a36Sopenharmony_ci} 61462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(class_compat_create_link); 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci/** 61762306a36Sopenharmony_ci * class_compat_remove_link - remove a compatibility class device link to 61862306a36Sopenharmony_ci * a bus device 61962306a36Sopenharmony_ci * @cls: the compatibility class 62062306a36Sopenharmony_ci * @dev: the target bus device 62162306a36Sopenharmony_ci * @device_link: an optional device to which a "device" link was previously 62262306a36Sopenharmony_ci * created 62362306a36Sopenharmony_ci */ 62462306a36Sopenharmony_civoid class_compat_remove_link(struct class_compat *cls, struct device *dev, 62562306a36Sopenharmony_ci struct device *device_link) 62662306a36Sopenharmony_ci{ 62762306a36Sopenharmony_ci if (device_link) 62862306a36Sopenharmony_ci sysfs_remove_link(&dev->kobj, "device"); 62962306a36Sopenharmony_ci sysfs_remove_link(cls->kobj, dev_name(dev)); 63062306a36Sopenharmony_ci} 63162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(class_compat_remove_link); 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci/** 63462306a36Sopenharmony_ci * class_is_registered - determine if at this moment in time, a class is 63562306a36Sopenharmony_ci * registered in the driver core or not. 63662306a36Sopenharmony_ci * @class: the class to check 63762306a36Sopenharmony_ci * 63862306a36Sopenharmony_ci * Returns a boolean to state if the class is registered in the driver core 63962306a36Sopenharmony_ci * or not. Note that the value could switch right after this call is made, 64062306a36Sopenharmony_ci * so only use this in places where you "know" it is safe to do so (usually 64162306a36Sopenharmony_ci * to determine if the specific class has been registered yet or not). 64262306a36Sopenharmony_ci * 64362306a36Sopenharmony_ci * Be careful in using this. 64462306a36Sopenharmony_ci */ 64562306a36Sopenharmony_cibool class_is_registered(const struct class *class) 64662306a36Sopenharmony_ci{ 64762306a36Sopenharmony_ci struct subsys_private *sp = class_to_subsys(class); 64862306a36Sopenharmony_ci bool is_initialized = false; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci if (sp) { 65162306a36Sopenharmony_ci is_initialized = true; 65262306a36Sopenharmony_ci subsys_put(sp); 65362306a36Sopenharmony_ci } 65462306a36Sopenharmony_ci return is_initialized; 65562306a36Sopenharmony_ci} 65662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(class_is_registered); 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ciint __init classes_init(void) 65962306a36Sopenharmony_ci{ 66062306a36Sopenharmony_ci class_kset = kset_create_and_add("class", NULL, NULL); 66162306a36Sopenharmony_ci if (!class_kset) 66262306a36Sopenharmony_ci return -ENOMEM; 66362306a36Sopenharmony_ci return 0; 66462306a36Sopenharmony_ci} 665