linux/fs/proc/proc_devtree.c
<<
>>
Prefs
   1/*
   2 * proc_devtree.c - handles /proc/device-tree
   3 *
   4 * Copyright 1997 Paul Mackerras
   5 */
   6#include <linux/errno.h>
   7#include <linux/init.h>
   8#include <linux/time.h>
   9#include <linux/proc_fs.h>
  10#include <linux/seq_file.h>
  11#include <linux/printk.h>
  12#include <linux/stat.h>
  13#include <linux/string.h>
  14#include <linux/of.h>
  15#include <linux/export.h>
  16#include <linux/slab.h>
  17#include <asm/prom.h>
  18#include <asm/uaccess.h>
  19#include "internal.h"
  20
  21static inline void set_node_proc_entry(struct device_node *np,
  22                                       struct proc_dir_entry *de)
  23{
  24#ifdef HAVE_ARCH_DEVTREE_FIXUPS
  25        np->pde = de;
  26#endif
  27}
  28
  29static struct proc_dir_entry *proc_device_tree;
  30
  31/*
  32 * Supply data on a read from /proc/device-tree/node/property.
  33 */
  34static int property_proc_show(struct seq_file *m, void *v)
  35{
  36        struct property *pp = m->private;
  37
  38        seq_write(m, pp->value, pp->length);
  39        return 0;
  40}
  41
  42static int property_proc_open(struct inode *inode, struct file *file)
  43{
  44        return single_open(file, property_proc_show, __PDE_DATA(inode));
  45}
  46
  47static const struct file_operations property_proc_fops = {
  48        .owner          = THIS_MODULE,
  49        .open           = property_proc_open,
  50        .read           = seq_read,
  51        .llseek         = seq_lseek,
  52        .release        = single_release,
  53};
  54
  55/*
  56 * For a node with a name like "gc@10", we make symlinks called "gc"
  57 * and "@10" to it.
  58 */
  59
  60/*
  61 * Add a property to a node
  62 */
  63static struct proc_dir_entry *
  64__proc_device_tree_add_prop(struct proc_dir_entry *de, struct property *pp,
  65                const char *name)
  66{
  67        struct proc_dir_entry *ent;
  68
  69        /*
  70         * Unfortunately proc_register puts each new entry
  71         * at the beginning of the list.  So we rearrange them.
  72         */
  73        ent = proc_create_data(name,
  74                               strncmp(name, "security-", 9) ? S_IRUGO : S_IRUSR,
  75                               de, &property_proc_fops, pp);
  76        if (ent == NULL)
  77                return NULL;
  78
  79        if (!strncmp(name, "security-", 9))
  80                ent->size = 0; /* don't leak number of password chars */
  81        else
  82                ent->size = pp->length;
  83
  84        return ent;
  85}
  86
  87
  88void proc_device_tree_add_prop(struct proc_dir_entry *pde, struct property *prop)
  89{
  90        __proc_device_tree_add_prop(pde, prop, prop->name);
  91}
  92
  93void proc_device_tree_remove_prop(struct proc_dir_entry *pde,
  94                                  struct property *prop)
  95{
  96        remove_proc_entry(prop->name, pde);
  97}
  98
  99void proc_device_tree_update_prop(struct proc_dir_entry *pde,
 100                                  struct property *newprop,
 101                                  struct property *oldprop)
 102{
 103        struct proc_dir_entry *ent;
 104
 105        if (!oldprop) {
 106                proc_device_tree_add_prop(pde, newprop);
 107                return;
 108        }
 109
 110        for (ent = pde->subdir; ent != NULL; ent = ent->next)
 111                if (ent->data == oldprop)
 112                        break;
 113        if (ent == NULL) {
 114                pr_warn("device-tree: property \"%s\" does not exist\n",
 115                        oldprop->name);
 116        } else {
 117                ent->data = newprop;
 118                ent->size = newprop->length;
 119        }
 120}
 121
 122/*
 123 * Various dodgy firmware might give us nodes and/or properties with
 124 * conflicting names. That's generally ok, except for exporting via /proc,
 125 * so munge names here to ensure they're unique.
 126 */
 127
 128static int duplicate_name(struct proc_dir_entry *de, const char *name)
 129{
 130        struct proc_dir_entry *ent;
 131        int found = 0;
 132
 133        spin_lock(&proc_subdir_lock);
 134
 135        for (ent = de->subdir; ent != NULL; ent = ent->next) {
 136                if (strcmp(ent->name, name) == 0) {
 137                        found = 1;
 138                        break;
 139                }
 140        }
 141
 142        spin_unlock(&proc_subdir_lock);
 143
 144        return found;
 145}
 146
 147static const char *fixup_name(struct device_node *np, struct proc_dir_entry *de,
 148                const char *name)
 149{
 150        char *fixed_name;
 151        int fixup_len = strlen(name) + 2 + 1; /* name + #x + \0 */
 152        int i = 1, size;
 153
 154realloc:
 155        fixed_name = kmalloc(fixup_len, GFP_KERNEL);
 156        if (fixed_name == NULL) {
 157                pr_err("device-tree: Out of memory trying to fixup "
 158                       "name \"%s\"\n", name);
 159                return name;
 160        }
 161
 162retry:
 163        size = snprintf(fixed_name, fixup_len, "%s#%d", name, i);
 164        size++; /* account for NULL */
 165
 166        if (size > fixup_len) {
 167                /* We ran out of space, free and reallocate. */
 168                kfree(fixed_name);
 169                fixup_len = size;
 170                goto realloc;
 171        }
 172
 173        if (duplicate_name(de, fixed_name)) {
 174                /* Multiple duplicates. Retry with a different offset. */
 175                i++;
 176                goto retry;
 177        }
 178
 179        pr_warn("device-tree: Duplicate name in %s, renamed to \"%s\"\n",
 180                np->full_name, fixed_name);
 181
 182        return fixed_name;
 183}
 184
 185/*
 186 * Process a node, adding entries for its children and its properties.
 187 */
 188void proc_device_tree_add_node(struct device_node *np,
 189                               struct proc_dir_entry *de)
 190{
 191        struct property *pp;
 192        struct proc_dir_entry *ent;
 193        struct device_node *child;
 194        const char *p;
 195
 196        set_node_proc_entry(np, de);
 197        for (child = NULL; (child = of_get_next_child(np, child));) {
 198                /* Use everything after the last slash, or the full name */
 199                p = kbasename(child->full_name);
 200
 201                if (duplicate_name(de, p))
 202                        p = fixup_name(np, de, p);
 203
 204                ent = proc_mkdir(p, de);
 205                if (ent == NULL)
 206                        break;
 207                proc_device_tree_add_node(child, ent);
 208        }
 209        of_node_put(child);
 210
 211        for (pp = np->properties; pp != NULL; pp = pp->next) {
 212                p = pp->name;
 213
 214                if (strchr(p, '/'))
 215                        continue;
 216
 217                if (duplicate_name(de, p))
 218                        p = fixup_name(np, de, p);
 219
 220                ent = __proc_device_tree_add_prop(de, pp, p);
 221                if (ent == NULL)
 222                        break;
 223        }
 224}
 225
 226/*
 227 * Called on initialization to set up the /proc/device-tree subtree
 228 */
 229void __init proc_device_tree_init(void)
 230{
 231        struct device_node *root;
 232
 233        proc_device_tree = proc_mkdir("device-tree", NULL);
 234        if (proc_device_tree == NULL)
 235                return;
 236        root = of_find_node_by_path("/");
 237        if (root == NULL) {
 238                pr_debug("/proc/device-tree: can't find root\n");
 239                return;
 240        }
 241        proc_device_tree_add_node(root, proc_device_tree);
 242        of_node_put(root);
 243}
 244