18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * attribute_container.c - implementation of a simple container for classes 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2005 - James Bottomley <James.Bottomley@steeleye.com> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * The basic idea here is to enable a device to be attached to an 88c2ecf20Sopenharmony_ci * aritrary numer of classes without having to allocate storage for them. 98c2ecf20Sopenharmony_ci * Instead, the contained classes select the devices they need to attach 108c2ecf20Sopenharmony_ci * to via a matching function. 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/attribute_container.h> 148c2ecf20Sopenharmony_ci#include <linux/device.h> 158c2ecf20Sopenharmony_ci#include <linux/kernel.h> 168c2ecf20Sopenharmony_ci#include <linux/slab.h> 178c2ecf20Sopenharmony_ci#include <linux/list.h> 188c2ecf20Sopenharmony_ci#include <linux/module.h> 198c2ecf20Sopenharmony_ci#include <linux/mutex.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include "base.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci/* This is a private structure used to tie the classdev and the 248c2ecf20Sopenharmony_ci * container .. it should never be visible outside this file */ 258c2ecf20Sopenharmony_cistruct internal_container { 268c2ecf20Sopenharmony_ci struct klist_node node; 278c2ecf20Sopenharmony_ci struct attribute_container *cont; 288c2ecf20Sopenharmony_ci struct device classdev; 298c2ecf20Sopenharmony_ci}; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic void internal_container_klist_get(struct klist_node *n) 328c2ecf20Sopenharmony_ci{ 338c2ecf20Sopenharmony_ci struct internal_container *ic = 348c2ecf20Sopenharmony_ci container_of(n, struct internal_container, node); 358c2ecf20Sopenharmony_ci get_device(&ic->classdev); 368c2ecf20Sopenharmony_ci} 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic void internal_container_klist_put(struct klist_node *n) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci struct internal_container *ic = 418c2ecf20Sopenharmony_ci container_of(n, struct internal_container, node); 428c2ecf20Sopenharmony_ci put_device(&ic->classdev); 438c2ecf20Sopenharmony_ci} 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci/** 478c2ecf20Sopenharmony_ci * attribute_container_classdev_to_container - given a classdev, return the container 488c2ecf20Sopenharmony_ci * 498c2ecf20Sopenharmony_ci * @classdev: the class device created by attribute_container_add_device. 508c2ecf20Sopenharmony_ci * 518c2ecf20Sopenharmony_ci * Returns the container associated with this classdev. 528c2ecf20Sopenharmony_ci */ 538c2ecf20Sopenharmony_cistruct attribute_container * 548c2ecf20Sopenharmony_ciattribute_container_classdev_to_container(struct device *classdev) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci struct internal_container *ic = 578c2ecf20Sopenharmony_ci container_of(classdev, struct internal_container, classdev); 588c2ecf20Sopenharmony_ci return ic->cont; 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(attribute_container_classdev_to_container); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic LIST_HEAD(attribute_container_list); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(attribute_container_mutex); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci/** 678c2ecf20Sopenharmony_ci * attribute_container_register - register an attribute container 688c2ecf20Sopenharmony_ci * 698c2ecf20Sopenharmony_ci * @cont: The container to register. This must be allocated by the 708c2ecf20Sopenharmony_ci * callee and should also be zeroed by it. 718c2ecf20Sopenharmony_ci */ 728c2ecf20Sopenharmony_ciint 738c2ecf20Sopenharmony_ciattribute_container_register(struct attribute_container *cont) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&cont->node); 768c2ecf20Sopenharmony_ci klist_init(&cont->containers, internal_container_klist_get, 778c2ecf20Sopenharmony_ci internal_container_klist_put); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci mutex_lock(&attribute_container_mutex); 808c2ecf20Sopenharmony_ci list_add_tail(&cont->node, &attribute_container_list); 818c2ecf20Sopenharmony_ci mutex_unlock(&attribute_container_mutex); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci return 0; 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(attribute_container_register); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci/** 888c2ecf20Sopenharmony_ci * attribute_container_unregister - remove a container registration 898c2ecf20Sopenharmony_ci * 908c2ecf20Sopenharmony_ci * @cont: previously registered container to remove 918c2ecf20Sopenharmony_ci */ 928c2ecf20Sopenharmony_ciint 938c2ecf20Sopenharmony_ciattribute_container_unregister(struct attribute_container *cont) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci int retval = -EBUSY; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci mutex_lock(&attribute_container_mutex); 988c2ecf20Sopenharmony_ci spin_lock(&cont->containers.k_lock); 998c2ecf20Sopenharmony_ci if (!list_empty(&cont->containers.k_list)) 1008c2ecf20Sopenharmony_ci goto out; 1018c2ecf20Sopenharmony_ci retval = 0; 1028c2ecf20Sopenharmony_ci list_del(&cont->node); 1038c2ecf20Sopenharmony_ci out: 1048c2ecf20Sopenharmony_ci spin_unlock(&cont->containers.k_lock); 1058c2ecf20Sopenharmony_ci mutex_unlock(&attribute_container_mutex); 1068c2ecf20Sopenharmony_ci return retval; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(attribute_container_unregister); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci/* private function used as class release */ 1128c2ecf20Sopenharmony_cistatic void attribute_container_release(struct device *classdev) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci struct internal_container *ic 1158c2ecf20Sopenharmony_ci = container_of(classdev, struct internal_container, classdev); 1168c2ecf20Sopenharmony_ci struct device *dev = classdev->parent; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci kfree(ic); 1198c2ecf20Sopenharmony_ci put_device(dev); 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci/** 1238c2ecf20Sopenharmony_ci * attribute_container_add_device - see if any container is interested in dev 1248c2ecf20Sopenharmony_ci * 1258c2ecf20Sopenharmony_ci * @dev: device to add attributes to 1268c2ecf20Sopenharmony_ci * @fn: function to trigger addition of class device. 1278c2ecf20Sopenharmony_ci * 1288c2ecf20Sopenharmony_ci * This function allocates storage for the class device(s) to be 1298c2ecf20Sopenharmony_ci * attached to dev (one for each matching attribute_container). If no 1308c2ecf20Sopenharmony_ci * fn is provided, the code will simply register the class device via 1318c2ecf20Sopenharmony_ci * device_add. If a function is provided, it is expected to add 1328c2ecf20Sopenharmony_ci * the class device at the appropriate time. One of the things that 1338c2ecf20Sopenharmony_ci * might be necessary is to allocate and initialise the classdev and 1348c2ecf20Sopenharmony_ci * then add it a later time. To do this, call this routine for 1358c2ecf20Sopenharmony_ci * allocation and initialisation and then use 1368c2ecf20Sopenharmony_ci * attribute_container_device_trigger() to call device_add() on 1378c2ecf20Sopenharmony_ci * it. Note: after this, the class device contains a reference to dev 1388c2ecf20Sopenharmony_ci * which is not relinquished until the release of the classdev. 1398c2ecf20Sopenharmony_ci */ 1408c2ecf20Sopenharmony_civoid 1418c2ecf20Sopenharmony_ciattribute_container_add_device(struct device *dev, 1428c2ecf20Sopenharmony_ci int (*fn)(struct attribute_container *, 1438c2ecf20Sopenharmony_ci struct device *, 1448c2ecf20Sopenharmony_ci struct device *)) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci struct attribute_container *cont; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci mutex_lock(&attribute_container_mutex); 1498c2ecf20Sopenharmony_ci list_for_each_entry(cont, &attribute_container_list, node) { 1508c2ecf20Sopenharmony_ci struct internal_container *ic; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci if (attribute_container_no_classdevs(cont)) 1538c2ecf20Sopenharmony_ci continue; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci if (!cont->match(cont, dev)) 1568c2ecf20Sopenharmony_ci continue; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci ic = kzalloc(sizeof(*ic), GFP_KERNEL); 1598c2ecf20Sopenharmony_ci if (!ic) { 1608c2ecf20Sopenharmony_ci dev_err(dev, "failed to allocate class container\n"); 1618c2ecf20Sopenharmony_ci continue; 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci ic->cont = cont; 1658c2ecf20Sopenharmony_ci device_initialize(&ic->classdev); 1668c2ecf20Sopenharmony_ci ic->classdev.parent = get_device(dev); 1678c2ecf20Sopenharmony_ci ic->classdev.class = cont->class; 1688c2ecf20Sopenharmony_ci cont->class->dev_release = attribute_container_release; 1698c2ecf20Sopenharmony_ci dev_set_name(&ic->classdev, "%s", dev_name(dev)); 1708c2ecf20Sopenharmony_ci if (fn) 1718c2ecf20Sopenharmony_ci fn(cont, dev, &ic->classdev); 1728c2ecf20Sopenharmony_ci else 1738c2ecf20Sopenharmony_ci attribute_container_add_class_device(&ic->classdev); 1748c2ecf20Sopenharmony_ci klist_add_tail(&ic->node, &cont->containers); 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci mutex_unlock(&attribute_container_mutex); 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci/* FIXME: can't break out of this unless klist_iter_exit is also 1808c2ecf20Sopenharmony_ci * called before doing the break 1818c2ecf20Sopenharmony_ci */ 1828c2ecf20Sopenharmony_ci#define klist_for_each_entry(pos, head, member, iter) \ 1838c2ecf20Sopenharmony_ci for (klist_iter_init(head, iter); (pos = ({ \ 1848c2ecf20Sopenharmony_ci struct klist_node *n = klist_next(iter); \ 1858c2ecf20Sopenharmony_ci n ? container_of(n, typeof(*pos), member) : \ 1868c2ecf20Sopenharmony_ci ({ klist_iter_exit(iter) ; NULL; }); \ 1878c2ecf20Sopenharmony_ci })) != NULL;) 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci/** 1918c2ecf20Sopenharmony_ci * attribute_container_remove_device - make device eligible for removal. 1928c2ecf20Sopenharmony_ci * 1938c2ecf20Sopenharmony_ci * @dev: The generic device 1948c2ecf20Sopenharmony_ci * @fn: A function to call to remove the device 1958c2ecf20Sopenharmony_ci * 1968c2ecf20Sopenharmony_ci * This routine triggers device removal. If fn is NULL, then it is 1978c2ecf20Sopenharmony_ci * simply done via device_unregister (note that if something 1988c2ecf20Sopenharmony_ci * still has a reference to the classdev, then the memory occupied 1998c2ecf20Sopenharmony_ci * will not be freed until the classdev is released). If you want a 2008c2ecf20Sopenharmony_ci * two phase release: remove from visibility and then delete the 2018c2ecf20Sopenharmony_ci * device, then you should use this routine with a fn that calls 2028c2ecf20Sopenharmony_ci * device_del() and then use attribute_container_device_trigger() 2038c2ecf20Sopenharmony_ci * to do the final put on the classdev. 2048c2ecf20Sopenharmony_ci */ 2058c2ecf20Sopenharmony_civoid 2068c2ecf20Sopenharmony_ciattribute_container_remove_device(struct device *dev, 2078c2ecf20Sopenharmony_ci void (*fn)(struct attribute_container *, 2088c2ecf20Sopenharmony_ci struct device *, 2098c2ecf20Sopenharmony_ci struct device *)) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci struct attribute_container *cont; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci mutex_lock(&attribute_container_mutex); 2148c2ecf20Sopenharmony_ci list_for_each_entry(cont, &attribute_container_list, node) { 2158c2ecf20Sopenharmony_ci struct internal_container *ic; 2168c2ecf20Sopenharmony_ci struct klist_iter iter; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci if (attribute_container_no_classdevs(cont)) 2198c2ecf20Sopenharmony_ci continue; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci if (!cont->match(cont, dev)) 2228c2ecf20Sopenharmony_ci continue; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci klist_for_each_entry(ic, &cont->containers, node, &iter) { 2258c2ecf20Sopenharmony_ci if (dev != ic->classdev.parent) 2268c2ecf20Sopenharmony_ci continue; 2278c2ecf20Sopenharmony_ci klist_del(&ic->node); 2288c2ecf20Sopenharmony_ci if (fn) 2298c2ecf20Sopenharmony_ci fn(cont, dev, &ic->classdev); 2308c2ecf20Sopenharmony_ci else { 2318c2ecf20Sopenharmony_ci attribute_container_remove_attrs(&ic->classdev); 2328c2ecf20Sopenharmony_ci device_unregister(&ic->classdev); 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci mutex_unlock(&attribute_container_mutex); 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_cistatic int 2408c2ecf20Sopenharmony_cido_attribute_container_device_trigger_safe(struct device *dev, 2418c2ecf20Sopenharmony_ci struct attribute_container *cont, 2428c2ecf20Sopenharmony_ci int (*fn)(struct attribute_container *, 2438c2ecf20Sopenharmony_ci struct device *, struct device *), 2448c2ecf20Sopenharmony_ci int (*undo)(struct attribute_container *, 2458c2ecf20Sopenharmony_ci struct device *, struct device *)) 2468c2ecf20Sopenharmony_ci{ 2478c2ecf20Sopenharmony_ci int ret; 2488c2ecf20Sopenharmony_ci struct internal_container *ic, *failed; 2498c2ecf20Sopenharmony_ci struct klist_iter iter; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci if (attribute_container_no_classdevs(cont)) 2528c2ecf20Sopenharmony_ci return fn(cont, dev, NULL); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci klist_for_each_entry(ic, &cont->containers, node, &iter) { 2558c2ecf20Sopenharmony_ci if (dev == ic->classdev.parent) { 2568c2ecf20Sopenharmony_ci ret = fn(cont, dev, &ic->classdev); 2578c2ecf20Sopenharmony_ci if (ret) { 2588c2ecf20Sopenharmony_ci failed = ic; 2598c2ecf20Sopenharmony_ci klist_iter_exit(&iter); 2608c2ecf20Sopenharmony_ci goto fail; 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci return 0; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_cifail: 2678c2ecf20Sopenharmony_ci if (!undo) 2688c2ecf20Sopenharmony_ci return ret; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci /* Attempt to undo the work partially done. */ 2718c2ecf20Sopenharmony_ci klist_for_each_entry(ic, &cont->containers, node, &iter) { 2728c2ecf20Sopenharmony_ci if (ic == failed) { 2738c2ecf20Sopenharmony_ci klist_iter_exit(&iter); 2748c2ecf20Sopenharmony_ci break; 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci if (dev == ic->classdev.parent) 2778c2ecf20Sopenharmony_ci undo(cont, dev, &ic->classdev); 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci return ret; 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci/** 2838c2ecf20Sopenharmony_ci * attribute_container_device_trigger_safe - execute a trigger for each 2848c2ecf20Sopenharmony_ci * matching classdev or fail all of them. 2858c2ecf20Sopenharmony_ci * 2868c2ecf20Sopenharmony_ci * @dev: The generic device to run the trigger for 2878c2ecf20Sopenharmony_ci * @fn the function to execute for each classdev. 2888c2ecf20Sopenharmony_ci * @undo A function to undo the work previously done in case of error 2898c2ecf20Sopenharmony_ci * 2908c2ecf20Sopenharmony_ci * This function is a safe version of 2918c2ecf20Sopenharmony_ci * attribute_container_device_trigger. It stops on the first error and 2928c2ecf20Sopenharmony_ci * undo the partial work that has been done, on previous classdev. It 2938c2ecf20Sopenharmony_ci * is guaranteed that either they all succeeded, or none of them 2948c2ecf20Sopenharmony_ci * succeeded. 2958c2ecf20Sopenharmony_ci */ 2968c2ecf20Sopenharmony_ciint 2978c2ecf20Sopenharmony_ciattribute_container_device_trigger_safe(struct device *dev, 2988c2ecf20Sopenharmony_ci int (*fn)(struct attribute_container *, 2998c2ecf20Sopenharmony_ci struct device *, 3008c2ecf20Sopenharmony_ci struct device *), 3018c2ecf20Sopenharmony_ci int (*undo)(struct attribute_container *, 3028c2ecf20Sopenharmony_ci struct device *, 3038c2ecf20Sopenharmony_ci struct device *)) 3048c2ecf20Sopenharmony_ci{ 3058c2ecf20Sopenharmony_ci struct attribute_container *cont, *failed = NULL; 3068c2ecf20Sopenharmony_ci int ret = 0; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci mutex_lock(&attribute_container_mutex); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci list_for_each_entry(cont, &attribute_container_list, node) { 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci if (!cont->match(cont, dev)) 3138c2ecf20Sopenharmony_ci continue; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci ret = do_attribute_container_device_trigger_safe(dev, cont, 3168c2ecf20Sopenharmony_ci fn, undo); 3178c2ecf20Sopenharmony_ci if (ret) { 3188c2ecf20Sopenharmony_ci failed = cont; 3198c2ecf20Sopenharmony_ci break; 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci if (ret && !WARN_ON(!undo)) { 3248c2ecf20Sopenharmony_ci list_for_each_entry(cont, &attribute_container_list, node) { 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci if (failed == cont) 3278c2ecf20Sopenharmony_ci break; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci if (!cont->match(cont, dev)) 3308c2ecf20Sopenharmony_ci continue; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci do_attribute_container_device_trigger_safe(dev, cont, 3338c2ecf20Sopenharmony_ci undo, NULL); 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci mutex_unlock(&attribute_container_mutex); 3388c2ecf20Sopenharmony_ci return ret; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci} 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci/** 3438c2ecf20Sopenharmony_ci * attribute_container_device_trigger - execute a trigger for each matching classdev 3448c2ecf20Sopenharmony_ci * 3458c2ecf20Sopenharmony_ci * @dev: The generic device to run the trigger for 3468c2ecf20Sopenharmony_ci * @fn the function to execute for each classdev. 3478c2ecf20Sopenharmony_ci * 3488c2ecf20Sopenharmony_ci * This function is for executing a trigger when you need to know both 3498c2ecf20Sopenharmony_ci * the container and the classdev. If you only care about the 3508c2ecf20Sopenharmony_ci * container, then use attribute_container_trigger() instead. 3518c2ecf20Sopenharmony_ci */ 3528c2ecf20Sopenharmony_civoid 3538c2ecf20Sopenharmony_ciattribute_container_device_trigger(struct device *dev, 3548c2ecf20Sopenharmony_ci int (*fn)(struct attribute_container *, 3558c2ecf20Sopenharmony_ci struct device *, 3568c2ecf20Sopenharmony_ci struct device *)) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci struct attribute_container *cont; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci mutex_lock(&attribute_container_mutex); 3618c2ecf20Sopenharmony_ci list_for_each_entry(cont, &attribute_container_list, node) { 3628c2ecf20Sopenharmony_ci struct internal_container *ic; 3638c2ecf20Sopenharmony_ci struct klist_iter iter; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci if (!cont->match(cont, dev)) 3668c2ecf20Sopenharmony_ci continue; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci if (attribute_container_no_classdevs(cont)) { 3698c2ecf20Sopenharmony_ci fn(cont, dev, NULL); 3708c2ecf20Sopenharmony_ci continue; 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci klist_for_each_entry(ic, &cont->containers, node, &iter) { 3748c2ecf20Sopenharmony_ci if (dev == ic->classdev.parent) 3758c2ecf20Sopenharmony_ci fn(cont, dev, &ic->classdev); 3768c2ecf20Sopenharmony_ci } 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci mutex_unlock(&attribute_container_mutex); 3798c2ecf20Sopenharmony_ci} 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci/** 3828c2ecf20Sopenharmony_ci * attribute_container_trigger - trigger a function for each matching container 3838c2ecf20Sopenharmony_ci * 3848c2ecf20Sopenharmony_ci * @dev: The generic device to activate the trigger for 3858c2ecf20Sopenharmony_ci * @fn: the function to trigger 3868c2ecf20Sopenharmony_ci * 3878c2ecf20Sopenharmony_ci * This routine triggers a function that only needs to know the 3888c2ecf20Sopenharmony_ci * matching containers (not the classdev) associated with a device. 3898c2ecf20Sopenharmony_ci * It is more lightweight than attribute_container_device_trigger, so 3908c2ecf20Sopenharmony_ci * should be used in preference unless the triggering function 3918c2ecf20Sopenharmony_ci * actually needs to know the classdev. 3928c2ecf20Sopenharmony_ci */ 3938c2ecf20Sopenharmony_civoid 3948c2ecf20Sopenharmony_ciattribute_container_trigger(struct device *dev, 3958c2ecf20Sopenharmony_ci int (*fn)(struct attribute_container *, 3968c2ecf20Sopenharmony_ci struct device *)) 3978c2ecf20Sopenharmony_ci{ 3988c2ecf20Sopenharmony_ci struct attribute_container *cont; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci mutex_lock(&attribute_container_mutex); 4018c2ecf20Sopenharmony_ci list_for_each_entry(cont, &attribute_container_list, node) { 4028c2ecf20Sopenharmony_ci if (cont->match(cont, dev)) 4038c2ecf20Sopenharmony_ci fn(cont, dev); 4048c2ecf20Sopenharmony_ci } 4058c2ecf20Sopenharmony_ci mutex_unlock(&attribute_container_mutex); 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci/** 4098c2ecf20Sopenharmony_ci * attribute_container_add_attrs - add attributes 4108c2ecf20Sopenharmony_ci * 4118c2ecf20Sopenharmony_ci * @classdev: The class device 4128c2ecf20Sopenharmony_ci * 4138c2ecf20Sopenharmony_ci * This simply creates all the class device sysfs files from the 4148c2ecf20Sopenharmony_ci * attributes listed in the container 4158c2ecf20Sopenharmony_ci */ 4168c2ecf20Sopenharmony_ciint 4178c2ecf20Sopenharmony_ciattribute_container_add_attrs(struct device *classdev) 4188c2ecf20Sopenharmony_ci{ 4198c2ecf20Sopenharmony_ci struct attribute_container *cont = 4208c2ecf20Sopenharmony_ci attribute_container_classdev_to_container(classdev); 4218c2ecf20Sopenharmony_ci struct device_attribute **attrs = cont->attrs; 4228c2ecf20Sopenharmony_ci int i, error; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci BUG_ON(attrs && cont->grp); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci if (!attrs && !cont->grp) 4278c2ecf20Sopenharmony_ci return 0; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci if (cont->grp) 4308c2ecf20Sopenharmony_ci return sysfs_create_group(&classdev->kobj, cont->grp); 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci for (i = 0; attrs[i]; i++) { 4338c2ecf20Sopenharmony_ci sysfs_attr_init(&attrs[i]->attr); 4348c2ecf20Sopenharmony_ci error = device_create_file(classdev, attrs[i]); 4358c2ecf20Sopenharmony_ci if (error) 4368c2ecf20Sopenharmony_ci return error; 4378c2ecf20Sopenharmony_ci } 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci return 0; 4408c2ecf20Sopenharmony_ci} 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci/** 4438c2ecf20Sopenharmony_ci * attribute_container_add_class_device - same function as device_add 4448c2ecf20Sopenharmony_ci * 4458c2ecf20Sopenharmony_ci * @classdev: the class device to add 4468c2ecf20Sopenharmony_ci * 4478c2ecf20Sopenharmony_ci * This performs essentially the same function as device_add except for 4488c2ecf20Sopenharmony_ci * attribute containers, namely add the classdev to the system and then 4498c2ecf20Sopenharmony_ci * create the attribute files 4508c2ecf20Sopenharmony_ci */ 4518c2ecf20Sopenharmony_ciint 4528c2ecf20Sopenharmony_ciattribute_container_add_class_device(struct device *classdev) 4538c2ecf20Sopenharmony_ci{ 4548c2ecf20Sopenharmony_ci int error = device_add(classdev); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci if (error) 4578c2ecf20Sopenharmony_ci return error; 4588c2ecf20Sopenharmony_ci return attribute_container_add_attrs(classdev); 4598c2ecf20Sopenharmony_ci} 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci/** 4628c2ecf20Sopenharmony_ci * attribute_container_add_class_device_adapter - simple adapter for triggers 4638c2ecf20Sopenharmony_ci * 4648c2ecf20Sopenharmony_ci * This function is identical to attribute_container_add_class_device except 4658c2ecf20Sopenharmony_ci * that it is designed to be called from the triggers 4668c2ecf20Sopenharmony_ci */ 4678c2ecf20Sopenharmony_ciint 4688c2ecf20Sopenharmony_ciattribute_container_add_class_device_adapter(struct attribute_container *cont, 4698c2ecf20Sopenharmony_ci struct device *dev, 4708c2ecf20Sopenharmony_ci struct device *classdev) 4718c2ecf20Sopenharmony_ci{ 4728c2ecf20Sopenharmony_ci return attribute_container_add_class_device(classdev); 4738c2ecf20Sopenharmony_ci} 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci/** 4768c2ecf20Sopenharmony_ci * attribute_container_remove_attrs - remove any attribute files 4778c2ecf20Sopenharmony_ci * 4788c2ecf20Sopenharmony_ci * @classdev: The class device to remove the files from 4798c2ecf20Sopenharmony_ci * 4808c2ecf20Sopenharmony_ci */ 4818c2ecf20Sopenharmony_civoid 4828c2ecf20Sopenharmony_ciattribute_container_remove_attrs(struct device *classdev) 4838c2ecf20Sopenharmony_ci{ 4848c2ecf20Sopenharmony_ci struct attribute_container *cont = 4858c2ecf20Sopenharmony_ci attribute_container_classdev_to_container(classdev); 4868c2ecf20Sopenharmony_ci struct device_attribute **attrs = cont->attrs; 4878c2ecf20Sopenharmony_ci int i; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci if (!attrs && !cont->grp) 4908c2ecf20Sopenharmony_ci return; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci if (cont->grp) { 4938c2ecf20Sopenharmony_ci sysfs_remove_group(&classdev->kobj, cont->grp); 4948c2ecf20Sopenharmony_ci return ; 4958c2ecf20Sopenharmony_ci } 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci for (i = 0; attrs[i]; i++) 4988c2ecf20Sopenharmony_ci device_remove_file(classdev, attrs[i]); 4998c2ecf20Sopenharmony_ci} 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci/** 5028c2ecf20Sopenharmony_ci * attribute_container_class_device_del - equivalent of class_device_del 5038c2ecf20Sopenharmony_ci * 5048c2ecf20Sopenharmony_ci * @classdev: the class device 5058c2ecf20Sopenharmony_ci * 5068c2ecf20Sopenharmony_ci * This function simply removes all the attribute files and then calls 5078c2ecf20Sopenharmony_ci * device_del. 5088c2ecf20Sopenharmony_ci */ 5098c2ecf20Sopenharmony_civoid 5108c2ecf20Sopenharmony_ciattribute_container_class_device_del(struct device *classdev) 5118c2ecf20Sopenharmony_ci{ 5128c2ecf20Sopenharmony_ci attribute_container_remove_attrs(classdev); 5138c2ecf20Sopenharmony_ci device_del(classdev); 5148c2ecf20Sopenharmony_ci} 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci/** 5178c2ecf20Sopenharmony_ci * attribute_container_find_class_device - find the corresponding class_device 5188c2ecf20Sopenharmony_ci * 5198c2ecf20Sopenharmony_ci * @cont: the container 5208c2ecf20Sopenharmony_ci * @dev: the generic device 5218c2ecf20Sopenharmony_ci * 5228c2ecf20Sopenharmony_ci * Looks up the device in the container's list of class devices and returns 5238c2ecf20Sopenharmony_ci * the corresponding class_device. 5248c2ecf20Sopenharmony_ci */ 5258c2ecf20Sopenharmony_cistruct device * 5268c2ecf20Sopenharmony_ciattribute_container_find_class_device(struct attribute_container *cont, 5278c2ecf20Sopenharmony_ci struct device *dev) 5288c2ecf20Sopenharmony_ci{ 5298c2ecf20Sopenharmony_ci struct device *cdev = NULL; 5308c2ecf20Sopenharmony_ci struct internal_container *ic; 5318c2ecf20Sopenharmony_ci struct klist_iter iter; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci klist_for_each_entry(ic, &cont->containers, node, &iter) { 5348c2ecf20Sopenharmony_ci if (ic->classdev.parent == dev) { 5358c2ecf20Sopenharmony_ci cdev = &ic->classdev; 5368c2ecf20Sopenharmony_ci /* FIXME: must exit iterator then break */ 5378c2ecf20Sopenharmony_ci klist_iter_exit(&iter); 5388c2ecf20Sopenharmony_ci break; 5398c2ecf20Sopenharmony_ci } 5408c2ecf20Sopenharmony_ci } 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci return cdev; 5438c2ecf20Sopenharmony_ci} 5448c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(attribute_container_find_class_device); 545