Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #include <linux/of.h>
0003 #include <linux/slab.h>
0004 
0005 #include "of_private.h"
0006 
0007 /* true when node is initialized */
0008 static int of_node_is_initialized(const struct device_node *node)
0009 {
0010     return node && node->kobj.state_initialized;
0011 }
0012 
0013 /* true when node is attached (i.e. present on sysfs) */
0014 int of_node_is_attached(const struct device_node *node)
0015 {
0016     return node && node->kobj.state_in_sysfs;
0017 }
0018 
0019 
0020 #ifndef CONFIG_OF_DYNAMIC
0021 static void of_node_release(struct kobject *kobj)
0022 {
0023     /* Without CONFIG_OF_DYNAMIC, no nodes gets freed */
0024 }
0025 #endif /* CONFIG_OF_DYNAMIC */
0026 
0027 struct kobj_type of_node_ktype = {
0028     .release = of_node_release,
0029 };
0030 
0031 static ssize_t of_node_property_read(struct file *filp, struct kobject *kobj,
0032                 struct bin_attribute *bin_attr, char *buf,
0033                 loff_t offset, size_t count)
0034 {
0035     struct property *pp = container_of(bin_attr, struct property, attr);
0036     return memory_read_from_buffer(buf, count, &offset, pp->value, pp->length);
0037 }
0038 
0039 /* always return newly allocated name, caller must free after use */
0040 static const char *safe_name(struct kobject *kobj, const char *orig_name)
0041 {
0042     const char *name = orig_name;
0043     struct kernfs_node *kn;
0044     int i = 0;
0045 
0046     /* don't be a hero. After 16 tries give up */
0047     while (i < 16 && (kn = sysfs_get_dirent(kobj->sd, name))) {
0048         sysfs_put(kn);
0049         if (name != orig_name)
0050             kfree(name);
0051         name = kasprintf(GFP_KERNEL, "%s#%i", orig_name, ++i);
0052     }
0053 
0054     if (name == orig_name) {
0055         name = kstrdup(orig_name, GFP_KERNEL);
0056     } else {
0057         pr_warn("Duplicate name in %s, renamed to \"%s\"\n",
0058             kobject_name(kobj), name);
0059     }
0060     return name;
0061 }
0062 
0063 int __of_add_property_sysfs(struct device_node *np, struct property *pp)
0064 {
0065     int rc;
0066 
0067     /* Important: Don't leak passwords */
0068     bool secure = strncmp(pp->name, "security-", 9) == 0;
0069 
0070     if (!IS_ENABLED(CONFIG_SYSFS))
0071         return 0;
0072 
0073     if (!of_kset || !of_node_is_attached(np))
0074         return 0;
0075 
0076     sysfs_bin_attr_init(&pp->attr);
0077     pp->attr.attr.name = safe_name(&np->kobj, pp->name);
0078     pp->attr.attr.mode = secure ? 0400 : 0444;
0079     pp->attr.size = secure ? 0 : pp->length;
0080     pp->attr.read = of_node_property_read;
0081 
0082     rc = sysfs_create_bin_file(&np->kobj, &pp->attr);
0083     WARN(rc, "error adding attribute %s to node %pOF\n", pp->name, np);
0084     return rc;
0085 }
0086 
0087 void __of_sysfs_remove_bin_file(struct device_node *np, struct property *prop)
0088 {
0089     if (!IS_ENABLED(CONFIG_SYSFS))
0090         return;
0091 
0092     sysfs_remove_bin_file(&np->kobj, &prop->attr);
0093     kfree(prop->attr.attr.name);
0094 }
0095 
0096 void __of_remove_property_sysfs(struct device_node *np, struct property *prop)
0097 {
0098     /* at early boot, bail here and defer setup to of_init() */
0099     if (of_kset && of_node_is_attached(np))
0100         __of_sysfs_remove_bin_file(np, prop);
0101 }
0102 
0103 void __of_update_property_sysfs(struct device_node *np, struct property *newprop,
0104         struct property *oldprop)
0105 {
0106     /* At early boot, bail out and defer setup to of_init() */
0107     if (!of_kset)
0108         return;
0109 
0110     if (oldprop)
0111         __of_sysfs_remove_bin_file(np, oldprop);
0112     __of_add_property_sysfs(np, newprop);
0113 }
0114 
0115 int __of_attach_node_sysfs(struct device_node *np)
0116 {
0117     const char *name;
0118     struct kobject *parent;
0119     struct property *pp;
0120     int rc;
0121 
0122     if (!IS_ENABLED(CONFIG_SYSFS) || !of_kset)
0123         return 0;
0124 
0125     np->kobj.kset = of_kset;
0126     if (!np->parent) {
0127         /* Nodes without parents are new top level trees */
0128         name = safe_name(&of_kset->kobj, "base");
0129         parent = NULL;
0130     } else {
0131         name = safe_name(&np->parent->kobj, kbasename(np->full_name));
0132         parent = &np->parent->kobj;
0133     }
0134     if (!name)
0135         return -ENOMEM;
0136 
0137     rc = kobject_add(&np->kobj, parent, "%s", name);
0138     kfree(name);
0139     if (rc)
0140         return rc;
0141 
0142     for_each_property_of_node(np, pp)
0143         __of_add_property_sysfs(np, pp);
0144 
0145     of_node_get(np);
0146     return 0;
0147 }
0148 
0149 void __of_detach_node_sysfs(struct device_node *np)
0150 {
0151     struct property *pp;
0152 
0153     BUG_ON(!of_node_is_initialized(np));
0154     if (!of_kset)
0155         return;
0156 
0157     /* only remove properties if on sysfs */
0158     if (of_node_is_attached(np)) {
0159         for_each_property_of_node(np, pp)
0160             __of_sysfs_remove_bin_file(np, pp);
0161         kobject_del(&np->kobj);
0162     }
0163 
0164     of_node_put(np);
0165 }