📄 prom.c
字号:
} if (use_of_interrupt_tree) return mem_start; ip = (int *) get_property(np, "interrupts", &l); if (ip != 0) { np->intrs = (struct interrupt_info *) mem_start; np->n_intrs = l / (2 * sizeof(int)); mem_start += np->n_intrs * sizeof(struct interrupt_info); for (i = 0; i < np->n_intrs; ++i) { np->intrs[i].line = *ip++; np->intrs[i].sense = *ip++; } } return mem_start;}static unsigned long __initinterpret_root_props(struct device_node *np, unsigned long mem_start, int naddrc, int nsizec){ struct address_range *adr; int i, l, *ip; unsigned int *rp; int rpsize = (naddrc + nsizec) * sizeof(unsigned int); rp = (unsigned int *) get_property(np, "reg", &l); if (rp != 0 && l >= rpsize) { i = 0; adr = (struct address_range *) mem_start; while ((l -= rpsize) >= 0) { adr[i].space = (naddrc >= 2? rp[naddrc-2]: 2); adr[i].address = rp[naddrc - 1]; adr[i].size = rp[naddrc + nsizec - 1]; ++i; rp += naddrc + nsizec; } np->addrs = adr; np->n_addrs = i; mem_start += i * sizeof(struct address_range); } if (use_of_interrupt_tree) return mem_start; ip = (int *) get_property(np, "AAPL,interrupts", &l); if (ip == 0) ip = (int *) get_property(np, "interrupts", &l); if (ip != 0) { np->intrs = (struct interrupt_info *) mem_start; np->n_intrs = l / sizeof(int); mem_start += np->n_intrs * sizeof(struct interrupt_info); for (i = 0; i < np->n_intrs; ++i) { np->intrs[i].line = *ip++; np->intrs[i].sense = 1; } } return mem_start;}/* * Work out the sense (active-low level / active-high edge) * of each interrupt from the device tree. */void __initprom_get_irq_senses(unsigned char *senses, int off, int max){ struct device_node *np; int i, j; /* default to level-triggered */ memset(senses, 1, max - off); if (!use_of_interrupt_tree) return; for (np = allnodes; np != 0; np = np->allnext) { for (j = 0; j < np->n_intrs; j++) { i = np->intrs[j].line; if (i >= off && i < max) senses[i-off] = np->intrs[j].sense; } }}/* * Construct and return a list of the device_nodes with a given name. */struct device_node *find_devices(const char *name){ struct device_node *head, **prevp, *np; prevp = &head; for (np = allnodes; np != 0; np = np->allnext) { if (np->name != 0 && strcasecmp(np->name, name) == 0) { *prevp = np; prevp = &np->next; } } *prevp = 0; return head;}/* * Construct and return a list of the device_nodes with a given type. */struct device_node *find_type_devices(const char *type){ struct device_node *head, **prevp, *np; prevp = &head; for (np = allnodes; np != 0; np = np->allnext) { if (np->type != 0 && strcasecmp(np->type, type) == 0) { *prevp = np; prevp = &np->next; } } *prevp = 0; return head;}/* * Returns all nodes linked together */struct device_node * __openfirmwarefind_all_nodes(void){ struct device_node *head, **prevp, *np; prevp = &head; for (np = allnodes; np != 0; np = np->allnext) { *prevp = np; prevp = &np->next; } *prevp = 0; return head;}/* Checks if the given "compat" string matches one of the strings in * the device's "compatible" property */intdevice_is_compatible(struct device_node *device, const char *compat){ const char* cp; int cplen, l; cp = (char *) get_property(device, "compatible", &cplen); if (cp == NULL) return 0; while (cplen > 0) { if (strncasecmp(cp, compat, strlen(compat)) == 0) return 1; l = strlen(cp) + 1; cp += l; cplen -= l; } return 0;}/* * Indicates whether the root node has a given value in its * compatible property. */intmachine_is_compatible(const char *compat){ struct device_node *root; root = find_path_device("/"); if (root == 0) return 0; return device_is_compatible(root, compat);}/* * Construct and return a list of the device_nodes with a given type * and compatible property. */struct device_node *find_compatible_devices(const char *type, const char *compat){ struct device_node *head, **prevp, *np; prevp = &head; for (np = allnodes; np != 0; np = np->allnext) { if (type != NULL && !(np->type != 0 && strcasecmp(np->type, type) == 0)) continue; if (device_is_compatible(np, compat)) { *prevp = np; prevp = &np->next; } } *prevp = 0; return head;}/* * Find the device_node with a given full_name. */struct device_node *find_path_device(const char *path){ struct device_node *np; for (np = allnodes; np != 0; np = np->allnext) if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0) return np; return NULL;}/* * 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 0;}/* * 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. * WARNING: out_resource->name should be initialized before calling this * function. */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; 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 "request_OF_resource(%s), parent not found\n", node->name); return -ENODEV; } /* Find us in the parent */ res = parent->child; while (res) { if (res->start == node->addrs[index].address && res->end == (res->start + node->addrs[index].size - 1)) break; 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); /* Shouldn't we enable kernel FP here ? enter_rtas will play * with MSR_FE0|MSR_FE1|MSR_FP so I assume rtas might use * floating points. If that's the case, then we need to make * sure any lazy FP context is backed up * --BenH */ 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];}void __initabort(){#ifdef CONFIG_XMON xmon(NULL);#endif for (;;) prom_exit();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -