0001
0002 #include <linux/of.h>
0003 #include <linux/slab.h>
0004
0005 #include "of_private.h"
0006
0007
0008 static int of_node_is_initialized(const struct device_node *node)
0009 {
0010 return node && node->kobj.state_initialized;
0011 }
0012
0013
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
0024 }
0025 #endif
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
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
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
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
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
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
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
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 }