+/*
+ * Various dodgy firmware might give us nodes and/or properties with
+ * conflicting names. That's generally ok, except for exporting via /proc,
+ * so munge names here to ensure they're unique.
+ */
+
+static int duplicate_name(struct proc_dir_entry *de, const char *name)
+{
+ struct proc_dir_entry *ent;
+ int found = 0;
+
+ spin_lock(&proc_subdir_lock);
+
+ for (ent = de->subdir; ent != NULL; ent = ent->next) {
+ if (strcmp(ent->name, name) == 0) {
+ found = 1;
+ break;
+ }
+ }
+
+ spin_unlock(&proc_subdir_lock);
+
+ return found;
+}
+
+static const char *fixup_name(struct device_node *np, struct proc_dir_entry *de,
+ const char *name)
+{
+ char *fixed_name;
+ int fixup_len = strlen(name) + 2 + 1; /* name + #x + \0 */
+ int i = 1, size;
+
+realloc:
+ fixed_name = kmalloc(fixup_len, GFP_KERNEL);
+ if (fixed_name == NULL) {
+ printk(KERN_ERR "device-tree: Out of memory trying to fixup "
+ "name \"%s\"\n", name);
+ return name;
+ }
+
+retry:
+ size = snprintf(fixed_name, fixup_len, "%s#%d", name, i);
+ size++; /* account for NULL */
+
+ if (size > fixup_len) {
+ /* We ran out of space, free and reallocate. */
+ kfree(fixed_name);
+ fixup_len = size;
+ goto realloc;
+ }
+
+ if (duplicate_name(de, fixed_name)) {
+ /* Multiple duplicates. Retry with a different offset. */
+ i++;
+ goto retry;
+ }
+
+ printk(KERN_WARNING "device-tree: Duplicate name in %s, "
+ "renamed to \"%s\"\n", np->full_name, fixed_name);
+
+ return fixed_name;
+}
+