prom.c
来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 2,082 行 · 第 1/4 页
C
2,082 行
np = from ? from->allnext : allnodes; for (; np != 0; np = np->allnext) if (np->type != 0 && strcasecmp(np->type, type) == 0 && of_node_get(np)) break; if (from) of_node_put(from); read_unlock(&devtree_lock); return np;}EXPORT_SYMBOL(of_find_node_by_type);/** * of_find_compatible_node - Find a node based on type and one of the * tokens in its "compatible" property * @from: The node to start searching from or NULL, the node * you pass will not be searched, only the next one * will; typically, you pass what the previous call * returned. of_node_put() will be called on it * @type: The type string to match "device_type" or NULL to ignore * @compatible: The string to match to one of the tokens in the device * "compatible" list. * * Returns a node pointer with refcount incremented, use * of_node_put() on it when done. */struct device_node *of_find_compatible_node(struct device_node *from, const char *type, const char *compatible){ struct device_node *np; read_lock(&devtree_lock); np = from ? from->allnext : allnodes; for (; np != 0; np = np->allnext) { if (type != NULL && !(np->type != 0 && strcasecmp(np->type, type) == 0)) continue; if (device_is_compatible(np, compatible) && of_node_get(np)) break; } if (from) of_node_put(from); read_unlock(&devtree_lock); return np;}EXPORT_SYMBOL(of_find_compatible_node);/** * of_find_node_by_path - Find a node matching a full OF path * @path: The full path to match * * Returns a node pointer with refcount incremented, use * of_node_put() on it when done. */struct device_node *of_find_node_by_path(const char *path){ struct device_node *np = allnodes; read_lock(&devtree_lock); for (; np != 0; np = np->allnext) { if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0 && of_node_get(np)) break; } read_unlock(&devtree_lock); return np;}EXPORT_SYMBOL(of_find_node_by_path);/** * of_find_node_by_phandle - Find a node given a phandle * @handle: phandle of the node to find * * Returns a node pointer with refcount incremented, use * of_node_put() on it when done. */struct device_node *of_find_node_by_phandle(phandle handle){ struct device_node *np; read_lock(&devtree_lock); for (np = allnodes; np != 0; np = np->allnext) if (np->linux_phandle == handle) break; if (np) of_node_get(np); read_unlock(&devtree_lock); return np;}EXPORT_SYMBOL(of_find_node_by_phandle);/** * of_find_all_nodes - Get next node in global list * @prev: Previous node or NULL to start iteration * of_node_put() will be called on it * * Returns a node pointer with refcount incremented, use * of_node_put() on it when done. */struct device_node *of_find_all_nodes(struct device_node *prev){ struct device_node *np; read_lock(&devtree_lock); np = prev ? prev->allnext : allnodes; for (; np != 0; np = np->allnext) if (of_node_get(np)) break; if (prev) of_node_put(prev); read_unlock(&devtree_lock); return np;}EXPORT_SYMBOL(of_find_all_nodes);/** * of_get_parent - Get a node's parent if any * @node: Node to get parent * * Returns a node pointer with refcount incremented, use * of_node_put() on it when done. */struct device_node *of_get_parent(const struct device_node *node){ struct device_node *np; if (!node) return NULL; read_lock(&devtree_lock); np = of_node_get(node->parent); read_unlock(&devtree_lock); return np;}EXPORT_SYMBOL(of_get_parent);/** * of_get_next_child - Iterate a node childs * @node: parent node * @prev: previous child of the parent node, or NULL to get first * * Returns a node pointer with refcount incremented, use * of_node_put() on it when done. */struct device_node *of_get_next_child(const struct device_node *node, struct device_node *prev){ struct device_node *next; read_lock(&devtree_lock); next = prev ? prev->sibling : node->child; for (; next != 0; next = next->sibling) if (of_node_get(next)) break; if (prev) of_node_put(prev); read_unlock(&devtree_lock); return next;}EXPORT_SYMBOL(of_get_next_child);/** * of_node_get - Increment refcount of a node * @node: Node to inc refcount, NULL is supported to * simplify writing of callers * * Returns node. */struct device_node *of_node_get(struct device_node *node){ if (node) kref_get(&node->kref); return node;}EXPORT_SYMBOL(of_node_get);static inline struct device_node * kref_to_device_node(struct kref *kref){ return container_of(kref, struct device_node, kref);}/** * of_node_release - release a dynamically allocated node * @kref: kref element of the node to be released * * In of_node_put() this function is passed to kref_put() * as the destructor. */static void of_node_release(struct kref *kref){ struct device_node *node = kref_to_device_node(kref); struct property *prop = node->properties; if (!OF_IS_DYNAMIC(node)) return; while (prop) { struct property *next = prop->next; kfree(prop->name); kfree(prop->value); kfree(prop); prop = next; if (!prop) { prop = node->deadprops; node->deadprops = NULL; } } kfree(node->intrs); kfree(node->full_name); kfree(node->data); kfree(node);}/** * of_node_put - Decrement refcount of a node * @node: Node to dec refcount, NULL is supported to * simplify writing of callers * */void of_node_put(struct device_node *node){ if (node) kref_put(&node->kref, of_node_release);}EXPORT_SYMBOL(of_node_put);/* * Plug a device node into the tree and global list. */void of_attach_node(struct device_node *np){ write_lock(&devtree_lock); np->sibling = np->parent->child; np->allnext = allnodes; np->parent->child = np; allnodes = np; write_unlock(&devtree_lock);}/* * "Unplug" a node from the device tree. The caller must hold * a reference to the node. The memory associated with the node * is not freed until its refcount goes to zero. */void of_detach_node(const struct device_node *np){ struct device_node *parent; write_lock(&devtree_lock); parent = np->parent; if (allnodes == np) allnodes = np->allnext; else { struct device_node *prev; for (prev = allnodes; prev->allnext != np; prev = prev->allnext) ; prev->allnext = np->allnext; } if (parent->child == np) parent->child = np->sibling; else { struct device_node *prevsib; for (prevsib = np->parent->child; prevsib->sibling != np; prevsib = prevsib->sibling) ; prevsib->sibling = np->sibling; } write_unlock(&devtree_lock);}#ifdef CONFIG_PPC_PSERIES/* * Fix up the uninitialized fields in a new device node: * name, type, n_addrs, addrs, n_intrs, intrs, and pci-specific fields * * A lot of boot-time code is duplicated here, because functions such * as finish_node_interrupts, interpret_pci_props, etc. cannot use the * slab allocator. * * This should probably be split up into smaller chunks. */static int of_finish_dynamic_node(struct device_node *node){ struct device_node *parent = of_get_parent(node); int err = 0; phandle *ibm_phandle; node->name = get_property(node, "name", NULL); node->type = get_property(node, "device_type", NULL); if (!parent) { err = -ENODEV; goto out; } /* We don't support that function on PowerMac, at least * not yet */ if (machine_is(powermac)) return -ENODEV; /* fix up new node's linux_phandle field */ if ((ibm_phandle = (unsigned int *)get_property(node, "ibm,phandle", NULL))) node->linux_phandle = *ibm_phandle;out: of_node_put(parent); return err;}static int prom_reconfig_notifier(struct notifier_block *nb, unsigned long action, void *node){ int err; switch (action) { case PSERIES_RECONFIG_ADD: err = of_finish_dynamic_node(node); if (!err) finish_node(node, NULL, 0); if (err < 0) { printk(KERN_ERR "finish_node returned %d\n", err); err = NOTIFY_BAD; } break; default: err = NOTIFY_DONE; break; } return err;}static struct notifier_block prom_reconfig_nb = { .notifier_call = prom_reconfig_notifier, .priority = 10, /* This one needs to run first */};static int __init prom_reconfig_setup(void){ return pSeries_reconfig_notifier_register(&prom_reconfig_nb);}__initcall(prom_reconfig_setup);#endifstruct property *of_find_property(struct device_node *np, const char *name, int *lenp){ struct property *pp; read_lock(&devtree_lock); for (pp = np->properties; pp != 0; pp = pp->next) if (strcmp(pp->name, name) == 0) { if (lenp != 0) *lenp = pp->length; break; } read_unlock(&devtree_lock); return pp;}/* * Find a property with a given name for a given node * and return the value. */unsigned char *get_property(struct device_node *np, const char *name, int *lenp){ struct property *pp = of_find_property(np,name,lenp); return pp ? pp->value : NULL;}EXPORT_SYMBOL(get_property);/* * Add a property to a node */int prom_add_property(struct device_node* np, struct property* prop){ struct property **next; prop->next = NULL; write_lock(&devtree_lock); next = &np->properties; while (*next) { if (strcmp(prop->name, (*next)->name) == 0) { /* duplicate ! don't insert it */ write_unlock(&devtree_lock); return -1; } next = &(*next)->next; } *next = prop; write_unlock(&devtree_lock);#ifdef CONFIG_PROC_DEVICETREE /* try to add to proc as well if it was initialized */ if (np->pde) proc_device_tree_add_prop(np->pde, prop);#endif /* CONFIG_PROC_DEVICETREE */ return 0;}/* * Remove a property from a node. Note that we don't actually * remove it, since we have given out who-knows-how-many pointers * to the data using get-property. Instead we just move the property * to the "dead properties" list, so it won't be found any more. */int prom_remove_property(struct device_node *np, struct property *prop){ struct property **next; int found = 0; write_lock(&devtree_lock); next = &np->properties; while (*next) { if (*next == prop) { /* found the node */ *next = prop->next; prop->next = np->deadprops; np->deadprops = prop; found = 1; break; } next = &(*next)->next; } write_unlock(&devtree_lock); if (!found) return -ENODEV;#ifdef CONFIG_PROC_DEVICETREE /* try to remove the proc node as well */ if (np->pde) proc_device_tree_remove_prop(np->pde, prop);#endif /* CONFIG_PROC_DEVICETREE */ return 0;}/* * Update a property in a node. Note that we don't actually * remove it, since we have given out who-knows-how-many pointers * to the data using get-property. Instead we just move the property * to the "dead properties" list, and add the new property to the * property list */int prom_update_property(struct device_node *np, struct property *newprop, struct property *oldprop){ struct property **next; int found = 0; write_lock(&devtree_lock); next = &np->properties; while (*next) { if (*next == oldprop) { /* found the node */ newprop->next = oldprop->next; *next = newprop; oldprop->next = np->deadprops; np->deadprops = oldprop; found = 1; break; } next = &(*next)->next; } write_unlock(&devtree_lock); if (!found) return -ENODEV;#ifdef CONFIG_PROC_DEVICETREE /* try to add to proc as well if it was initialized */ if (np->pde) proc_device_tree_update_prop(np->pde, newprop, oldprop);#endif /* CONFIG_PROC_DEVICETREE */ return 0;}#ifdef CONFIG_KEXEC/* We may have allocated the flat device tree inside the crash kernel region * in prom_init. If so we need to move it out into regular memory. */void kdump_move_device_tree(void){ unsigned long start, end; struct boot_param_header *new; start = __pa((unsigned long)initial_boot_params); end = start + initial_boot_params->totalsize; if (end < crashk_res.start || start > crashk_res.end) return; new = (struct boot_param_header*) __va(lmb_alloc(initial_boot_params->totalsize, PAGE_SIZE)); memcpy(new, initial_boot_params, initial_boot_params->totalsize); initial_boot_params = new; DBG("Flat device tree blob moved to %p\n", initial_boot_params); /* XXX should we unreserve the old DT? */}#endif /* CONFIG_KEXEC */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?