1989d42e8SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * attribute_container.c - implementation of a simple container for classes 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Copyright (c) 2005 - James Bottomley <James.Bottomley@steeleye.com> 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * The basic idea here is to enable a device to be attached to an 81da177e4SLinus Torvalds * aritrary numer of classes without having to allocate storage for them. 91da177e4SLinus Torvalds * Instead, the contained classes select the devices they need to attach 101da177e4SLinus Torvalds * to via a matching function. 111da177e4SLinus Torvalds */ 121da177e4SLinus Torvalds 131da177e4SLinus Torvalds #include <linux/attribute_container.h> 141da177e4SLinus Torvalds #include <linux/device.h> 151da177e4SLinus Torvalds #include <linux/kernel.h> 161da177e4SLinus Torvalds #include <linux/slab.h> 171da177e4SLinus Torvalds #include <linux/list.h> 181da177e4SLinus Torvalds #include <linux/module.h> 19f8916c11SMichael S. Tsirkin #include <linux/mutex.h> 201da177e4SLinus Torvalds 21a1bdc7aaSBen Dooks #include "base.h" 22a1bdc7aaSBen Dooks 231da177e4SLinus Torvalds /* This is a private structure used to tie the classdev and the 241da177e4SLinus Torvalds * container .. it should never be visible outside this file */ 251da177e4SLinus Torvalds struct internal_container { 2653c165e0SJames Bottomley struct klist_node node; 271da177e4SLinus Torvalds struct attribute_container *cont; 28ee959b00STony Jones struct device classdev; 291da177e4SLinus Torvalds }; 301da177e4SLinus Torvalds 31caf39e87SLinus Torvalds static void internal_container_klist_get(struct klist_node *n) 32caf39e87SLinus Torvalds { 33caf39e87SLinus Torvalds struct internal_container *ic = 34caf39e87SLinus Torvalds container_of(n, struct internal_container, node); 35ee959b00STony Jones get_device(&ic->classdev); 36caf39e87SLinus Torvalds } 37caf39e87SLinus Torvalds 38caf39e87SLinus Torvalds static void internal_container_klist_put(struct klist_node *n) 39caf39e87SLinus Torvalds { 40caf39e87SLinus Torvalds struct internal_container *ic = 41caf39e87SLinus Torvalds container_of(n, struct internal_container, node); 42ee959b00STony Jones put_device(&ic->classdev); 43caf39e87SLinus Torvalds } 44caf39e87SLinus Torvalds 45caf39e87SLinus Torvalds 461da177e4SLinus Torvalds /** 471da177e4SLinus Torvalds * attribute_container_classdev_to_container - given a classdev, return the container 481da177e4SLinus Torvalds * 491da177e4SLinus Torvalds * @classdev: the class device created by attribute_container_add_device. 501da177e4SLinus Torvalds * 511da177e4SLinus Torvalds * Returns the container associated with this classdev. 521da177e4SLinus Torvalds */ 531da177e4SLinus Torvalds struct attribute_container * 54ee959b00STony Jones attribute_container_classdev_to_container(struct device *classdev) 551da177e4SLinus Torvalds { 561da177e4SLinus Torvalds struct internal_container *ic = 571da177e4SLinus Torvalds container_of(classdev, struct internal_container, classdev); 581da177e4SLinus Torvalds return ic->cont; 591da177e4SLinus Torvalds } 601da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(attribute_container_classdev_to_container); 611da177e4SLinus Torvalds 62db1118a4SDenis Cheng static LIST_HEAD(attribute_container_list); 631da177e4SLinus Torvalds 6461a2f59aSMatthias Kaehlcke static DEFINE_MUTEX(attribute_container_mutex); 651da177e4SLinus Torvalds 661da177e4SLinus Torvalds /** 671da177e4SLinus Torvalds * attribute_container_register - register an attribute container 681da177e4SLinus Torvalds * 691da177e4SLinus Torvalds * @cont: The container to register. This must be allocated by the 701da177e4SLinus Torvalds * callee and should also be zeroed by it. 711da177e4SLinus Torvalds */ 721da177e4SLinus Torvalds int 731da177e4SLinus Torvalds attribute_container_register(struct attribute_container *cont) 741da177e4SLinus Torvalds { 751da177e4SLinus Torvalds INIT_LIST_HEAD(&cont->node); 76caf39e87SLinus Torvalds klist_init(&cont->containers, internal_container_klist_get, 77caf39e87SLinus Torvalds internal_container_klist_put); 781da177e4SLinus Torvalds 7961a2f59aSMatthias Kaehlcke mutex_lock(&attribute_container_mutex); 801da177e4SLinus Torvalds list_add_tail(&cont->node, &attribute_container_list); 8161a2f59aSMatthias Kaehlcke mutex_unlock(&attribute_container_mutex); 821da177e4SLinus Torvalds 831da177e4SLinus Torvalds return 0; 841da177e4SLinus Torvalds } 851da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(attribute_container_register); 861da177e4SLinus Torvalds 871da177e4SLinus Torvalds /** 881da177e4SLinus Torvalds * attribute_container_unregister - remove a container registration 891da177e4SLinus Torvalds * 901da177e4SLinus Torvalds * @cont: previously registered container to remove 911da177e4SLinus Torvalds */ 921da177e4SLinus Torvalds int 931da177e4SLinus Torvalds attribute_container_unregister(struct attribute_container *cont) 941da177e4SLinus Torvalds { 951da177e4SLinus Torvalds int retval = -EBUSY; 96481026dbSCosmin Dragomir 9761a2f59aSMatthias Kaehlcke mutex_lock(&attribute_container_mutex); 9853c165e0SJames Bottomley spin_lock(&cont->containers.k_lock); 9953c165e0SJames Bottomley if (!list_empty(&cont->containers.k_list)) 1001da177e4SLinus Torvalds goto out; 1011da177e4SLinus Torvalds retval = 0; 1021da177e4SLinus Torvalds list_del(&cont->node); 1031da177e4SLinus Torvalds out: 10453c165e0SJames Bottomley spin_unlock(&cont->containers.k_lock); 10561a2f59aSMatthias Kaehlcke mutex_unlock(&attribute_container_mutex); 1061da177e4SLinus Torvalds return retval; 1071da177e4SLinus Torvalds 1081da177e4SLinus Torvalds } 1091da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(attribute_container_unregister); 1101da177e4SLinus Torvalds 1111da177e4SLinus Torvalds /* private function used as class release */ 112ee959b00STony Jones static void attribute_container_release(struct device *classdev) 1131da177e4SLinus Torvalds { 1141da177e4SLinus Torvalds struct internal_container *ic 1151da177e4SLinus Torvalds = container_of(classdev, struct internal_container, classdev); 116ee959b00STony Jones struct device *dev = classdev->parent; 1171da177e4SLinus Torvalds 1181da177e4SLinus Torvalds kfree(ic); 1191da177e4SLinus Torvalds put_device(dev); 1201da177e4SLinus Torvalds } 1211da177e4SLinus Torvalds 1221da177e4SLinus Torvalds /** 1231da177e4SLinus Torvalds * attribute_container_add_device - see if any container is interested in dev 1241da177e4SLinus Torvalds * 1251da177e4SLinus Torvalds * @dev: device to add attributes to 1261da177e4SLinus Torvalds * @fn: function to trigger addition of class device. 1271da177e4SLinus Torvalds * 1281da177e4SLinus Torvalds * This function allocates storage for the class device(s) to be 1291da177e4SLinus Torvalds * attached to dev (one for each matching attribute_container). If no 1301da177e4SLinus Torvalds * fn is provided, the code will simply register the class device via 131ee959b00STony Jones * device_add. If a function is provided, it is expected to add 1321da177e4SLinus Torvalds * the class device at the appropriate time. One of the things that 1331da177e4SLinus Torvalds * might be necessary is to allocate and initialise the classdev and 1341da177e4SLinus Torvalds * then add it a later time. To do this, call this routine for 1351da177e4SLinus Torvalds * allocation and initialisation and then use 136ee959b00STony Jones * attribute_container_device_trigger() to call device_add() on 1371da177e4SLinus Torvalds * it. Note: after this, the class device contains a reference to dev 1381da177e4SLinus Torvalds * which is not relinquished until the release of the classdev. 1391da177e4SLinus Torvalds */ 1401da177e4SLinus Torvalds void 1411da177e4SLinus Torvalds attribute_container_add_device(struct device *dev, 1421da177e4SLinus Torvalds int (*fn)(struct attribute_container *, 1431da177e4SLinus Torvalds struct device *, 144ee959b00STony Jones struct device *)) 1451da177e4SLinus Torvalds { 1461da177e4SLinus Torvalds struct attribute_container *cont; 1471da177e4SLinus Torvalds 14861a2f59aSMatthias Kaehlcke mutex_lock(&attribute_container_mutex); 1491da177e4SLinus Torvalds list_for_each_entry(cont, &attribute_container_list, node) { 1501da177e4SLinus Torvalds struct internal_container *ic; 1511da177e4SLinus Torvalds 1521da177e4SLinus Torvalds if (attribute_container_no_classdevs(cont)) 1531da177e4SLinus Torvalds continue; 1541da177e4SLinus Torvalds 1551da177e4SLinus Torvalds if (!cont->match(cont, dev)) 1561da177e4SLinus Torvalds continue; 1574aed0644SJiri Slaby 1584aed0644SJiri Slaby ic = kzalloc(sizeof(*ic), GFP_KERNEL); 1591da177e4SLinus Torvalds if (!ic) { 160a369a7ebSJoe Perches dev_err(dev, "failed to allocate class container\n"); 1611da177e4SLinus Torvalds continue; 1621da177e4SLinus Torvalds } 1634aed0644SJiri Slaby 1641da177e4SLinus Torvalds ic->cont = cont; 165ee959b00STony Jones device_initialize(&ic->classdev); 166ee959b00STony Jones ic->classdev.parent = get_device(dev); 1671da177e4SLinus Torvalds ic->classdev.class = cont->class; 168ee959b00STony Jones cont->class->dev_release = attribute_container_release; 16902aa2a37SKees Cook dev_set_name(&ic->classdev, "%s", dev_name(dev)); 1701da177e4SLinus Torvalds if (fn) 1711da177e4SLinus Torvalds fn(cont, dev, &ic->classdev); 1721da177e4SLinus Torvalds else 1731da177e4SLinus Torvalds attribute_container_add_class_device(&ic->classdev); 17453c165e0SJames Bottomley klist_add_tail(&ic->node, &cont->containers); 1751da177e4SLinus Torvalds } 17661a2f59aSMatthias Kaehlcke mutex_unlock(&attribute_container_mutex); 1771da177e4SLinus Torvalds } 1781da177e4SLinus Torvalds 17953c165e0SJames Bottomley /* FIXME: can't break out of this unless klist_iter_exit is also 18053c165e0SJames Bottomley * called before doing the break 18153c165e0SJames Bottomley */ 18253c165e0SJames Bottomley #define klist_for_each_entry(pos, head, member, iter) \ 18353c165e0SJames Bottomley for (klist_iter_init(head, iter); (pos = ({ \ 18453c165e0SJames Bottomley struct klist_node *n = klist_next(iter); \ 185caf39e87SLinus Torvalds n ? container_of(n, typeof(*pos), member) : \ 186caf39e87SLinus Torvalds ({ klist_iter_exit(iter) ; NULL; }); \ 18753c165e0SJames Bottomley })) != NULL;) 18853c165e0SJames Bottomley 18953c165e0SJames Bottomley 1901da177e4SLinus Torvalds /** 1911da177e4SLinus Torvalds * attribute_container_remove_device - make device eligible for removal. 1921da177e4SLinus Torvalds * 1931da177e4SLinus Torvalds * @dev: The generic device 1941da177e4SLinus Torvalds * @fn: A function to call to remove the device 1951da177e4SLinus Torvalds * 1961da177e4SLinus Torvalds * This routine triggers device removal. If fn is NULL, then it is 197ee959b00STony Jones * simply done via device_unregister (note that if something 1981da177e4SLinus Torvalds * still has a reference to the classdev, then the memory occupied 1991da177e4SLinus Torvalds * will not be freed until the classdev is released). If you want a 2001da177e4SLinus Torvalds * two phase release: remove from visibility and then delete the 2011da177e4SLinus Torvalds * device, then you should use this routine with a fn that calls 202ee959b00STony Jones * device_del() and then use attribute_container_device_trigger() 203ee959b00STony Jones * to do the final put on the classdev. 2041da177e4SLinus Torvalds */ 2051da177e4SLinus Torvalds void 2061da177e4SLinus Torvalds attribute_container_remove_device(struct device *dev, 2071da177e4SLinus Torvalds void (*fn)(struct attribute_container *, 2081da177e4SLinus Torvalds struct device *, 209ee959b00STony Jones struct device *)) 2101da177e4SLinus Torvalds { 2111da177e4SLinus Torvalds struct attribute_container *cont; 2121da177e4SLinus Torvalds 21361a2f59aSMatthias Kaehlcke mutex_lock(&attribute_container_mutex); 2141da177e4SLinus Torvalds list_for_each_entry(cont, &attribute_container_list, node) { 21553c165e0SJames Bottomley struct internal_container *ic; 21653c165e0SJames Bottomley struct klist_iter iter; 2171da177e4SLinus Torvalds 2181da177e4SLinus Torvalds if (attribute_container_no_classdevs(cont)) 2191da177e4SLinus Torvalds continue; 2201da177e4SLinus Torvalds 2211da177e4SLinus Torvalds if (!cont->match(cont, dev)) 2221da177e4SLinus Torvalds continue; 22353c165e0SJames Bottomley 22453c165e0SJames Bottomley klist_for_each_entry(ic, &cont->containers, node, &iter) { 225ee959b00STony Jones if (dev != ic->classdev.parent) 2261da177e4SLinus Torvalds continue; 227caf39e87SLinus Torvalds klist_del(&ic->node); 2281da177e4SLinus Torvalds if (fn) 2291da177e4SLinus Torvalds fn(cont, dev, &ic->classdev); 2301da177e4SLinus Torvalds else { 2311da177e4SLinus Torvalds attribute_container_remove_attrs(&ic->classdev); 232ee959b00STony Jones device_unregister(&ic->classdev); 2331da177e4SLinus Torvalds } 2341da177e4SLinus Torvalds } 2351da177e4SLinus Torvalds } 23661a2f59aSMatthias Kaehlcke mutex_unlock(&attribute_container_mutex); 2371da177e4SLinus Torvalds } 2381da177e4SLinus Torvalds 2397c1ef338SGabriel Krisman Bertazi static int 2407c1ef338SGabriel Krisman Bertazi do_attribute_container_device_trigger_safe(struct device *dev, 2417c1ef338SGabriel Krisman Bertazi struct attribute_container *cont, 2427c1ef338SGabriel Krisman Bertazi int (*fn)(struct attribute_container *, 2437c1ef338SGabriel Krisman Bertazi struct device *, struct device *), 2447c1ef338SGabriel Krisman Bertazi int (*undo)(struct attribute_container *, 2457c1ef338SGabriel Krisman Bertazi struct device *, struct device *)) 2467c1ef338SGabriel Krisman Bertazi { 2477c1ef338SGabriel Krisman Bertazi int ret; 2487c1ef338SGabriel Krisman Bertazi struct internal_container *ic, *failed; 2497c1ef338SGabriel Krisman Bertazi struct klist_iter iter; 2507c1ef338SGabriel Krisman Bertazi 2517c1ef338SGabriel Krisman Bertazi if (attribute_container_no_classdevs(cont)) 2527c1ef338SGabriel Krisman Bertazi return fn(cont, dev, NULL); 2537c1ef338SGabriel Krisman Bertazi 2547c1ef338SGabriel Krisman Bertazi klist_for_each_entry(ic, &cont->containers, node, &iter) { 2557c1ef338SGabriel Krisman Bertazi if (dev == ic->classdev.parent) { 2567c1ef338SGabriel Krisman Bertazi ret = fn(cont, dev, &ic->classdev); 2577c1ef338SGabriel Krisman Bertazi if (ret) { 2587c1ef338SGabriel Krisman Bertazi failed = ic; 2597c1ef338SGabriel Krisman Bertazi klist_iter_exit(&iter); 2607c1ef338SGabriel Krisman Bertazi goto fail; 2617c1ef338SGabriel Krisman Bertazi } 2627c1ef338SGabriel Krisman Bertazi } 2637c1ef338SGabriel Krisman Bertazi } 2647c1ef338SGabriel Krisman Bertazi return 0; 2657c1ef338SGabriel Krisman Bertazi 2667c1ef338SGabriel Krisman Bertazi fail: 2677c1ef338SGabriel Krisman Bertazi if (!undo) 2687c1ef338SGabriel Krisman Bertazi return ret; 2697c1ef338SGabriel Krisman Bertazi 2707c1ef338SGabriel Krisman Bertazi /* Attempt to undo the work partially done. */ 2717c1ef338SGabriel Krisman Bertazi klist_for_each_entry(ic, &cont->containers, node, &iter) { 2727c1ef338SGabriel Krisman Bertazi if (ic == failed) { 2737c1ef338SGabriel Krisman Bertazi klist_iter_exit(&iter); 2747c1ef338SGabriel Krisman Bertazi break; 2757c1ef338SGabriel Krisman Bertazi } 2767c1ef338SGabriel Krisman Bertazi if (dev == ic->classdev.parent) 2777c1ef338SGabriel Krisman Bertazi undo(cont, dev, &ic->classdev); 2787c1ef338SGabriel Krisman Bertazi } 2797c1ef338SGabriel Krisman Bertazi return ret; 2807c1ef338SGabriel Krisman Bertazi } 2817c1ef338SGabriel Krisman Bertazi 2827c1ef338SGabriel Krisman Bertazi /** 2837c1ef338SGabriel Krisman Bertazi * attribute_container_device_trigger_safe - execute a trigger for each 2847c1ef338SGabriel Krisman Bertazi * matching classdev or fail all of them. 2857c1ef338SGabriel Krisman Bertazi * 2867c1ef338SGabriel Krisman Bertazi * @dev: The generic device to run the trigger for 287a6daf4bbSYang Yingliang * @fn: the function to execute for each classdev. 288a6daf4bbSYang Yingliang * @undo: A function to undo the work previously done in case of error 2897c1ef338SGabriel Krisman Bertazi * 2907c1ef338SGabriel Krisman Bertazi * This function is a safe version of 2917c1ef338SGabriel Krisman Bertazi * attribute_container_device_trigger. It stops on the first error and 2927c1ef338SGabriel Krisman Bertazi * undo the partial work that has been done, on previous classdev. It 2937c1ef338SGabriel Krisman Bertazi * is guaranteed that either they all succeeded, or none of them 2947c1ef338SGabriel Krisman Bertazi * succeeded. 2957c1ef338SGabriel Krisman Bertazi */ 2967c1ef338SGabriel Krisman Bertazi int 2977c1ef338SGabriel Krisman Bertazi attribute_container_device_trigger_safe(struct device *dev, 2987c1ef338SGabriel Krisman Bertazi int (*fn)(struct attribute_container *, 2997c1ef338SGabriel Krisman Bertazi struct device *, 3007c1ef338SGabriel Krisman Bertazi struct device *), 3017c1ef338SGabriel Krisman Bertazi int (*undo)(struct attribute_container *, 3027c1ef338SGabriel Krisman Bertazi struct device *, 3037c1ef338SGabriel Krisman Bertazi struct device *)) 3047c1ef338SGabriel Krisman Bertazi { 3057c1ef338SGabriel Krisman Bertazi struct attribute_container *cont, *failed = NULL; 3067c1ef338SGabriel Krisman Bertazi int ret = 0; 3077c1ef338SGabriel Krisman Bertazi 3087c1ef338SGabriel Krisman Bertazi mutex_lock(&attribute_container_mutex); 3097c1ef338SGabriel Krisman Bertazi 3107c1ef338SGabriel Krisman Bertazi list_for_each_entry(cont, &attribute_container_list, node) { 3117c1ef338SGabriel Krisman Bertazi 3127c1ef338SGabriel Krisman Bertazi if (!cont->match(cont, dev)) 3137c1ef338SGabriel Krisman Bertazi continue; 3147c1ef338SGabriel Krisman Bertazi 3157c1ef338SGabriel Krisman Bertazi ret = do_attribute_container_device_trigger_safe(dev, cont, 3167c1ef338SGabriel Krisman Bertazi fn, undo); 3177c1ef338SGabriel Krisman Bertazi if (ret) { 3187c1ef338SGabriel Krisman Bertazi failed = cont; 3197c1ef338SGabriel Krisman Bertazi break; 3207c1ef338SGabriel Krisman Bertazi } 3217c1ef338SGabriel Krisman Bertazi } 3227c1ef338SGabriel Krisman Bertazi 3237c1ef338SGabriel Krisman Bertazi if (ret && !WARN_ON(!undo)) { 3247c1ef338SGabriel Krisman Bertazi list_for_each_entry(cont, &attribute_container_list, node) { 3257c1ef338SGabriel Krisman Bertazi 3267c1ef338SGabriel Krisman Bertazi if (failed == cont) 3277c1ef338SGabriel Krisman Bertazi break; 3287c1ef338SGabriel Krisman Bertazi 3297c1ef338SGabriel Krisman Bertazi if (!cont->match(cont, dev)) 3307c1ef338SGabriel Krisman Bertazi continue; 3317c1ef338SGabriel Krisman Bertazi 3327c1ef338SGabriel Krisman Bertazi do_attribute_container_device_trigger_safe(dev, cont, 3337c1ef338SGabriel Krisman Bertazi undo, NULL); 3347c1ef338SGabriel Krisman Bertazi } 3357c1ef338SGabriel Krisman Bertazi } 3367c1ef338SGabriel Krisman Bertazi 3377c1ef338SGabriel Krisman Bertazi mutex_unlock(&attribute_container_mutex); 3387c1ef338SGabriel Krisman Bertazi return ret; 3397c1ef338SGabriel Krisman Bertazi 3407c1ef338SGabriel Krisman Bertazi } 3417c1ef338SGabriel Krisman Bertazi 3421da177e4SLinus Torvalds /** 3431da177e4SLinus Torvalds * attribute_container_device_trigger - execute a trigger for each matching classdev 3441da177e4SLinus Torvalds * 3451da177e4SLinus Torvalds * @dev: The generic device to run the trigger for 346a6daf4bbSYang Yingliang * @fn: the function to execute for each classdev. 3471da177e4SLinus Torvalds * 34803aca7b2SXiubo Li * This function is for executing a trigger when you need to know both 349*6a36d828SDr. David Alan Gilbert * the container and the classdev. 3501da177e4SLinus Torvalds */ 3511da177e4SLinus Torvalds void 3521da177e4SLinus Torvalds attribute_container_device_trigger(struct device *dev, 3531da177e4SLinus Torvalds int (*fn)(struct attribute_container *, 3541da177e4SLinus Torvalds struct device *, 355ee959b00STony Jones struct device *)) 3561da177e4SLinus Torvalds { 3571da177e4SLinus Torvalds struct attribute_container *cont; 3581da177e4SLinus Torvalds 35961a2f59aSMatthias Kaehlcke mutex_lock(&attribute_container_mutex); 3601da177e4SLinus Torvalds list_for_each_entry(cont, &attribute_container_list, node) { 36153c165e0SJames Bottomley struct internal_container *ic; 36253c165e0SJames Bottomley struct klist_iter iter; 3631da177e4SLinus Torvalds 3641da177e4SLinus Torvalds if (!cont->match(cont, dev)) 3651da177e4SLinus Torvalds continue; 3661da177e4SLinus Torvalds 367ebd8bb76SJames Bottomley if (attribute_container_no_classdevs(cont)) { 368ebd8bb76SJames Bottomley fn(cont, dev, NULL); 369ebd8bb76SJames Bottomley continue; 370ebd8bb76SJames Bottomley } 371ebd8bb76SJames Bottomley 37253c165e0SJames Bottomley klist_for_each_entry(ic, &cont->containers, node, &iter) { 373ee959b00STony Jones if (dev == ic->classdev.parent) 3741da177e4SLinus Torvalds fn(cont, dev, &ic->classdev); 3751da177e4SLinus Torvalds } 3761da177e4SLinus Torvalds } 37761a2f59aSMatthias Kaehlcke mutex_unlock(&attribute_container_mutex); 3781da177e4SLinus Torvalds } 3791da177e4SLinus Torvalds 3801da177e4SLinus Torvalds /** 3811da177e4SLinus Torvalds * attribute_container_add_attrs - add attributes 3821da177e4SLinus Torvalds * 3831da177e4SLinus Torvalds * @classdev: The class device 3841da177e4SLinus Torvalds * 3851da177e4SLinus Torvalds * This simply creates all the class device sysfs files from the 3861da177e4SLinus Torvalds * attributes listed in the container 3871da177e4SLinus Torvalds */ 3881da177e4SLinus Torvalds int 389ee959b00STony Jones attribute_container_add_attrs(struct device *classdev) 3901da177e4SLinus Torvalds { 3911da177e4SLinus Torvalds struct attribute_container *cont = 3921da177e4SLinus Torvalds attribute_container_classdev_to_container(classdev); 393ee959b00STony Jones struct device_attribute **attrs = cont->attrs; 3941da177e4SLinus Torvalds int i, error; 3951da177e4SLinus Torvalds 396fd110971SJames Bottomley BUG_ON(attrs && cont->grp); 397fd110971SJames Bottomley 398fd110971SJames Bottomley if (!attrs && !cont->grp) 3991da177e4SLinus Torvalds return 0; 4001da177e4SLinus Torvalds 401fd110971SJames Bottomley if (cont->grp) 402fd110971SJames Bottomley return sysfs_create_group(&classdev->kobj, cont->grp); 403fd110971SJames Bottomley 4041da177e4SLinus Torvalds for (i = 0; attrs[i]; i++) { 405ebd09ec9SJames Bottomley sysfs_attr_init(&attrs[i]->attr); 406ee959b00STony Jones error = device_create_file(classdev, attrs[i]); 4071da177e4SLinus Torvalds if (error) 4081da177e4SLinus Torvalds return error; 4091da177e4SLinus Torvalds } 4101da177e4SLinus Torvalds 4111da177e4SLinus Torvalds return 0; 4121da177e4SLinus Torvalds } 4131da177e4SLinus Torvalds 4141da177e4SLinus Torvalds /** 415ee959b00STony Jones * attribute_container_add_class_device - same function as device_add 4161da177e4SLinus Torvalds * 4171da177e4SLinus Torvalds * @classdev: the class device to add 4181da177e4SLinus Torvalds * 419ee959b00STony Jones * This performs essentially the same function as device_add except for 4201da177e4SLinus Torvalds * attribute containers, namely add the classdev to the system and then 4211da177e4SLinus Torvalds * create the attribute files 4221da177e4SLinus Torvalds */ 4231da177e4SLinus Torvalds int 424ee959b00STony Jones attribute_container_add_class_device(struct device *classdev) 4251da177e4SLinus Torvalds { 426ee959b00STony Jones int error = device_add(classdev); 427481026dbSCosmin Dragomir 4281da177e4SLinus Torvalds if (error) 4291da177e4SLinus Torvalds return error; 4301da177e4SLinus Torvalds return attribute_container_add_attrs(classdev); 4311da177e4SLinus Torvalds } 4321da177e4SLinus Torvalds 4331da177e4SLinus Torvalds /** 4341da177e4SLinus Torvalds * attribute_container_remove_attrs - remove any attribute files 4351da177e4SLinus Torvalds * 4361da177e4SLinus Torvalds * @classdev: The class device to remove the files from 4371da177e4SLinus Torvalds * 4381da177e4SLinus Torvalds */ 4391da177e4SLinus Torvalds void 440ee959b00STony Jones attribute_container_remove_attrs(struct device *classdev) 4411da177e4SLinus Torvalds { 4421da177e4SLinus Torvalds struct attribute_container *cont = 4431da177e4SLinus Torvalds attribute_container_classdev_to_container(classdev); 444ee959b00STony Jones struct device_attribute **attrs = cont->attrs; 4451da177e4SLinus Torvalds int i; 4461da177e4SLinus Torvalds 447fd110971SJames Bottomley if (!attrs && !cont->grp) 4481da177e4SLinus Torvalds return; 4491da177e4SLinus Torvalds 450fd110971SJames Bottomley if (cont->grp) { 451fd110971SJames Bottomley sysfs_remove_group(&classdev->kobj, cont->grp); 452fd110971SJames Bottomley return ; 453fd110971SJames Bottomley } 454fd110971SJames Bottomley 4551da177e4SLinus Torvalds for (i = 0; attrs[i]; i++) 456ee959b00STony Jones device_remove_file(classdev, attrs[i]); 4571da177e4SLinus Torvalds } 4581da177e4SLinus Torvalds 4591da177e4SLinus Torvalds /** 4601da177e4SLinus Torvalds * attribute_container_class_device_del - equivalent of class_device_del 4611da177e4SLinus Torvalds * 4621da177e4SLinus Torvalds * @classdev: the class device 4631da177e4SLinus Torvalds * 4641da177e4SLinus Torvalds * This function simply removes all the attribute files and then calls 465ee959b00STony Jones * device_del. 4661da177e4SLinus Torvalds */ 4671da177e4SLinus Torvalds void 468ee959b00STony Jones attribute_container_class_device_del(struct device *classdev) 4691da177e4SLinus Torvalds { 4701da177e4SLinus Torvalds attribute_container_remove_attrs(classdev); 471ee959b00STony Jones device_del(classdev); 4721da177e4SLinus Torvalds } 4731da177e4SLinus Torvalds 474d0a7e574SJames Bottomley /** 475d0a7e574SJames Bottomley * attribute_container_find_class_device - find the corresponding class_device 476d0a7e574SJames Bottomley * 477d0a7e574SJames Bottomley * @cont: the container 478d0a7e574SJames Bottomley * @dev: the generic device 479d0a7e574SJames Bottomley * 480d0a7e574SJames Bottomley * Looks up the device in the container's list of class devices and returns 481d0a7e574SJames Bottomley * the corresponding class_device. 482d0a7e574SJames Bottomley */ 483ee959b00STony Jones struct device * 484d0a7e574SJames Bottomley attribute_container_find_class_device(struct attribute_container *cont, 485d0a7e574SJames Bottomley struct device *dev) 486d0a7e574SJames Bottomley { 487ee959b00STony Jones struct device *cdev = NULL; 488d0a7e574SJames Bottomley struct internal_container *ic; 48953c165e0SJames Bottomley struct klist_iter iter; 490d0a7e574SJames Bottomley 49153c165e0SJames Bottomley klist_for_each_entry(ic, &cont->containers, node, &iter) { 492ee959b00STony Jones if (ic->classdev.parent == dev) { 493d0a7e574SJames Bottomley cdev = &ic->classdev; 49453c165e0SJames Bottomley /* FIXME: must exit iterator then break */ 49553c165e0SJames Bottomley klist_iter_exit(&iter); 496d0a7e574SJames Bottomley break; 497d0a7e574SJames Bottomley } 498d0a7e574SJames Bottomley } 499d0a7e574SJames Bottomley 500d0a7e574SJames Bottomley return cdev; 501d0a7e574SJames Bottomley } 502d0a7e574SJames Bottomley EXPORT_SYMBOL_GPL(attribute_container_find_class_device); 503