📄 prom.c
字号:
* of_find_node_by_name - Find a node by it's "name" 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 * @name: The name string to match against * * Returns a node pointer with refcount incremented, use * of_node_put() on it when done. */struct device_node *of_find_node_by_name(struct device_node *from, const char *name){ struct device_node *np = from ? from->allnext : allnodes; for (; np != 0; np = np->allnext) if (np->name != 0 && strcasecmp(np->name, name) == 0) break; if (from) of_node_put(from); return of_node_get(np);}/** * of_find_node_by_type - Find a node by it's "device_type" 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 * @name: The type string to match against * * Returns a node pointer with refcount incremented, use * of_node_put() on it when done. */struct device_node *of_find_node_by_type(struct device_node *from, const char *type){ struct device_node *np = from ? from->allnext : allnodes; for (; np != 0; np = np->allnext) if (np->type != 0 && strcasecmp(np->type, type) == 0) break; if (from) of_node_put(from); return of_node_get(np);}/** * of_find_compatible_node - Find a node based on type and one of the * tokens in it's "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 = 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)) break; } if (from) of_node_put(from); return of_node_get(np);}/** * 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; for (; np != 0; np = np->allnext) if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0) break; return of_node_get(np);}/** * 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){ return of_node_get(prev ? prev->allnext : allnodes);}/** * 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){ return node ? of_node_get(node->parent) : NULL;}/** * 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 = prev ? prev->sibling : node->child; for (; next != 0; next = next->sibling) if (of_node_get(next)) break; if (prev) of_node_put(prev); return next;}/** * of_node_get - Increment refcount of a node * @node: Node to inc refcount, NULL is supported to * simplify writing of callers * * Returns the node itself or NULL if gone. Current implementation * does nothing as we don't yet do dynamic node allocation on ppc32 */struct device_node *of_node_get(struct device_node *node){ return node;}/** * of_node_put - Decrement refcount of a node * @node: Node to dec refcount, NULL is supported to * simplify writing of callers * * Current implementation does nothing as we don't yet do dynamic node * allocation on ppc32 */void of_node_put(struct device_node *node){}/* * Find the device_node with a given phandle. */static struct device_node * __initfind_phandle(phandle ph){ struct device_node *np; for (np = allnodes; np != 0; np = np->allnext) if (np->node == ph) return np; return NULL;}/* * 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; for (pp = np->properties; pp != 0; pp = pp->next) if (pp->name != NULL && strcmp(pp->name, name) == 0) { if (lenp != 0) *lenp = pp->length; return pp->value; } return NULL;}/* * Add a property to a node */void __openfirmwareprom_add_property(struct device_node* np, struct property* prop){ struct property **next = &np->properties; prop->next = NULL; while (*next) next = &(*next)->next; *next = prop;}/* I quickly hacked that one, check against spec ! */static inline unsigned long __openfirmwarebus_space_to_resource_flags(unsigned int bus_space){ u8 space = (bus_space >> 24) & 0xf; if (space == 0) space = 0x02; if (space == 0x02) return IORESOURCE_MEM; else if (space == 0x01) return IORESOURCE_IO; else { printk(KERN_WARNING "prom.c: bus_space_to_resource_flags(), space: %x\n", bus_space); return 0; }}static struct resource* __openfirmwarefind_parent_pci_resource(struct pci_dev* pdev, struct address_range *range){ unsigned long mask; int i; /* Check this one */ mask = bus_space_to_resource_flags(range->space); for (i=0; i<DEVICE_COUNT_RESOURCE; i++) { if ((pdev->resource[i].flags & mask) == mask && pdev->resource[i].start <= range->address && pdev->resource[i].end > range->address) { if ((range->address + range->size - 1) > pdev->resource[i].end) { /* Add better message */ printk(KERN_WARNING "PCI/OF resource overlap !\n"); return NULL; } break; } } if (i == DEVICE_COUNT_RESOURCE) return NULL; return &pdev->resource[i];}/* * Request an OF device resource. Currently handles child of PCI devices, * or other nodes attached to the root node. Ultimately, put some * link to resources in the OF node. */struct resource* __openfirmwarerequest_OF_resource(struct device_node* node, int index, const char* name_postfix){ struct pci_dev* pcidev; u8 pci_bus, pci_devfn; unsigned long iomask; struct device_node* nd; struct resource* parent; struct resource *res = NULL; int nlen, plen; if (index >= node->n_addrs) goto fail; /* Sanity check on bus space */ iomask = bus_space_to_resource_flags(node->addrs[index].space); if (iomask & IORESOURCE_MEM) parent = &iomem_resource; else if (iomask & IORESOURCE_IO) parent = &ioport_resource; else goto fail; /* Find a PCI parent if any */ nd = node; pcidev = NULL; while(nd) { if (!pci_device_from_OF_node(nd, &pci_bus, &pci_devfn)) pcidev = pci_find_slot(pci_bus, pci_devfn); if (pcidev) break; nd = nd->parent; } if (pcidev) parent = find_parent_pci_resource(pcidev, &node->addrs[index]); if (!parent) { printk(KERN_WARNING "request_OF_resource(%s), parent not found\n", node->name); goto fail; } res = __request_region(parent, node->addrs[index].address, node->addrs[index].size, NULL); if (!res) goto fail; nlen = strlen(node->name); plen = name_postfix ? strlen(name_postfix) : 0; res->name = (const char *)kmalloc(nlen+plen+1, GFP_KERNEL); if (res->name) { strcpy((char *)res->name, node->name); if (plen) strcpy((char *)res->name+nlen, name_postfix); } return res;fail: return NULL;}int __openfirmwarerelease_OF_resource(struct device_node* node, int index){ struct pci_dev* pcidev; u8 pci_bus, pci_devfn; unsigned long iomask, start, end; struct device_node* nd; struct resource* parent; struct resource *res = NULL; if (index >= node->n_addrs) return -EINVAL; /* Sanity check on bus space */ iomask = bus_space_to_resource_flags(node->addrs[index].space); if (iomask & IORESOURCE_MEM) parent = &iomem_resource; else if (iomask & IORESOURCE_IO) parent = &ioport_resource; else return -EINVAL; /* Find a PCI parent if any */ nd = node; pcidev = NULL; while(nd) { if (!pci_device_from_OF_node(nd, &pci_bus, &pci_devfn)) pcidev = pci_find_slot(pci_bus, pci_devfn); if (pcidev) break; nd = nd->parent; } if (pcidev) parent = find_parent_pci_resource(pcidev, &node->addrs[index]); if (!parent) { printk(KERN_WARNING "release_OF_resource(%s), parent not found\n", node->name); return -ENODEV; } /* Find us in the parent and its childs */ res = parent->child; start = node->addrs[index].address; end = start + node->addrs[index].size - 1; while (res) { if (res->start == start && res->end == end && (res->flags & IORESOURCE_BUSY)) break; if (res->start <= start && res->end >= end) res = res->child; else res = res->sibling; } if (!res) return -ENODEV; if (res->name) { kfree(res->name); res->name = NULL; } release_resource(res); kfree(res); return 0;}#if 0void __openfirmwareprint_properties(struct device_node *np){ struct property *pp; char *cp; int i, n; for (pp = np->properties; pp != 0; pp = pp->next) { printk(KERN_INFO "%s", pp->name); for (i = strlen(pp->name); i < 16; ++i) printk(" "); cp = (char *) pp->value; for (i = pp->length; i > 0; --i, ++cp) if ((i > 1 && (*cp < 0x20 || *cp > 0x7e)) || (i == 1 && *cp != 0)) break; if (i == 0 && pp->length > 1) { /* looks like a string */ printk(" %s\n", (char *) pp->value); } else { /* dump it in hex */ n = pp->length; if (n > 64) n = 64; if (pp->length % 4 == 0) { unsigned int *p = (unsigned int *) pp->value; n /= 4; for (i = 0; i < n; ++i) { if (i != 0 && (i % 4) == 0) printk("\n "); printk(" %08x", *p++); } } else { unsigned char *bp = pp->value; for (i = 0; i < n; ++i) { if (i != 0 && (i % 16) == 0) printk("\n "); printk(" %02x", *bp++); } } printk("\n"); if (pp->length > 64) printk(" ... (length = %d)\n", pp->length); } }}#endifstatic spinlock_t rtas_lock = SPIN_LOCK_UNLOCKED;/* this can be called after setup -- Cort */int __openfirmwarecall_rtas(const char *service, int nargs, int nret, unsigned long *outputs, ...){ va_list list; int i; unsigned long s; struct device_node *rtas; int *tokp; union { unsigned long words[16]; double align; } u; rtas = find_devices("rtas"); if (rtas == NULL) return -1; tokp = (int *) get_property(rtas, service, NULL); if (tokp == NULL) { printk(KERN_ERR "No RTAS service called %s\n", service); return -1; } u.words[0] = *tokp; u.words[1] = nargs; u.words[2] = nret; va_start(list, outputs); for (i = 0; i < nargs; ++i) u.words[i+3] = va_arg(list, unsigned long); va_end(list); /* * RTAS doesn't use floating point. * Or at least, according to the CHRP spec we enter RTAS * with FP disabled, and it doesn't change the FP registers. * -- paulus. */ spin_lock_irqsave(&rtas_lock, s); enter_rtas((void *)__pa(&u)); spin_unlock_irqrestore(&rtas_lock, s); if (nret > 1 && outputs != NULL) for (i = 0; i < nret-1; ++i) outputs[i] = u.words[i+nargs+4]; return u.words[nargs+3];}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -