/** * del_node * * @param phandle */ static void del_node(unsigned int phandle) { char *name = find_phandle(phandle); char delcmd[128] = "remove_node "; if (name == NULL) say(DEBUG, "Delete node error: Invalid phandle %8.8x", phandle); else { strcat(delcmd,name); do_update(delcmd, strlen(delcmd)); } }
/** * add_new_node * * @param phandle * @param drcindex */ static void add_new_node(unsigned int phandle, unsigned int drcindex) { char *path; int rtas_rc; struct of_node *new_nodes;/* nodes returned from configure_connector */ new_nodes = configure_connector(drcindex); path = find_phandle(phandle); if (path == NULL) { say(DEBUG, "Cannot find pnahdle %x\n", phandle); return; } rtas_rc = add_device_tree_nodes(path, new_nodes); if (rtas_rc) say(DEBUG, "add_device_tree_nodes failed at %s\n", path); }
/* * Find the interrupt parent of a node. */ static struct device_node * __init intr_parent(struct device_node *p) { phandle *parp; parp = (phandle *) get_property(p, "interrupt-parent", NULL); if (parp == NULL) return p->parent; p = find_phandle(*parp); if (p != NULL) return p; /* * On a powermac booted with BootX, we don't get to know the * phandles for any nodes, so find_phandle will return NULL. * Fortunately these machines only have one interrupt controller * so there isn't in fact any ambiguity. -- paulus */ if (num_interrupt_controllers == 1) p = dflt_interrupt_controller; return p; }
/** * update_properties * * @param phandle * @returns 0 on success, !0 otherwise */ static int update_properties(unsigned int phandle) { int rc; char cmd[DR_PATH_MAX]; char *longcmd = NULL; char *newcmd; int cmdlen = 0; int proplen = 0; unsigned int wa[1024]; unsigned int *op; unsigned int nprop; unsigned int vd; int lenpos = 0; char *pname; unsigned int i; int more = 0; char *name = find_phandle(phandle); int initial = 1; memset(wa, 0x00, 16); wa[0] = phandle; do { say(DEBUG, "about to call rtas_update_properties. work area:\n" "phandle %8.8x, node %s\n" " %8.8x %8.8x %8.8x %8.8x\n", phandle, name ? name : "NULL", wa[0], wa[1], wa[2], wa[3]); rc = rtas_update_properties((char *)wa, 1); if (rc && rc != 1) { say(DEBUG, "Error %d from rtas_update_properties()\n", rc); return 1; } say(DEBUG, "successful rtas_update_properties (more %d)\n", rc); op = wa+4; nprop = *op++; /* After the initial call to rtas_update_properties the first * property value descriptor in the buffer is the path of the * node being updated. Format is as follows: * * property name - 1 byte set to NULL 0x00 * value descriptor - 4 bytes containing length of value string * value string - fully qualified path name of updated node * */ if (initial) { say(DEBUG, "Null byte = %2.2x, ", *((char *)op)); op = (unsigned int *)(((char *)op) + 1); vd = *op++; say(DEBUG, "string length = %u, path = %s\n", vd, ((char *)op)); op = (unsigned int *)(((char *)op) + vd); initial = 0; /* The path we are skipping is inclusive in the * property count. */ nprop--; } for (i = 0; i < nprop; i++) { pname = (char *)op; op = (unsigned int *)(pname + strlen(pname) + 1); vd = *op++; switch (vd) { case 0x00000000: say(DEBUG, "%s - name only property %s\n", name, pname); break; case 0x80000000: say(DEBUG, "%s - delete property %s\n", name, pname); sprintf(cmd,"remove_property %u %s", phandle, pname); do_update(cmd, strlen(cmd) + 1); break; default: if (vd & 0x80000000) { say(DEBUG, "partial property!\n"); /* twos compliment of length */ vd = ~vd + 1; more = 1; } else { more = 0; } say(DEBUG, "%s - updating property %s length " "%d\n", name, pname, vd); /* See if we have a partially completed * command */ if (longcmd) { newcmd = zalloc(cmdlen + vd); memcpy(newcmd, longcmd, cmdlen); free(longcmd); longcmd = newcmd; } else { longcmd = zalloc(vd+128); /* Build the command with a length * of six zeros */ lenpos = sprintf(longcmd, "update_property %u " "%s ", phandle, pname); strcat(longcmd, "000000 "); cmdlen = strlen(longcmd); } memcpy(longcmd + cmdlen, op, vd); cmdlen += vd; proplen += vd; if (! more) { /* Now update the length to its actual * value and do a hideous fixup of * the new trailing null */ sprintf(longcmd+lenpos,"%06d",proplen); longcmd[lenpos+6] = ' '; do_update(longcmd, cmdlen); free(longcmd); longcmd = NULL; cmdlen = 0; proplen = 0; } op = (unsigned int *)(((char *)op) + vd); } } } while (rc == 1); return 0; }
/* * Map an interrupt from a device up to the platform interrupt * descriptor. */ static int __init map_interrupt(unsigned int **irq, struct device_node **ictrler, struct device_node *np, unsigned int *ints, int nintrc) { struct device_node *p, *ipar; unsigned int *imap, *imask, *ip; int i, imaplen, match; int newintrc, newaddrc; unsigned int *reg; int naddrc; reg = (unsigned int *) get_property(np, "reg", NULL); naddrc = prom_n_addr_cells(np); p = intr_parent(np); while (p != NULL) { if (get_property(p, "interrupt-controller", NULL) != NULL) /* this node is an interrupt controller, stop here */ break; imap = (unsigned int *) get_property(p, "interrupt-map", &imaplen); if (imap == NULL) { p = intr_parent(p); continue; } imask = (unsigned int *) get_property(p, "interrupt-map-mask", NULL); if (imask == NULL) { printk("oops, %s has interrupt-map but no mask\n", p->full_name); return 0; } imaplen /= sizeof(unsigned int); match = 0; ipar = NULL; while (imaplen > 0 && !match) { /* check the child-interrupt field */ match = 1; for (i = 0; i < naddrc && match; ++i) match = ((reg[i] ^ imap[i]) & imask[i]) == 0; for (; i < naddrc + nintrc && match; ++i) match = ((ints[i-naddrc] ^ imap[i]) & imask[i]) == 0; imap += naddrc + nintrc; imaplen -= naddrc + nintrc; /* grab the interrupt parent */ ipar = find_phandle((phandle) *imap++); --imaplen; if (ipar == NULL && num_interrupt_controllers == 1) /* cope with BootX not giving us phandles */ ipar = dflt_interrupt_controller; if (ipar == NULL) { printk("oops, no int parent %x in map of %s\n", imap[-1], p->full_name); return 0; } /* find the parent's # addr and intr cells */ ip = (unsigned int *) get_property(ipar, "#interrupt-cells", NULL); if (ip == NULL) { printk("oops, no #interrupt-cells on %s\n", ipar->full_name); return 0; } newintrc = *ip; ip = (unsigned int *) get_property(ipar, "#address-cells", NULL); newaddrc = (ip == NULL)? 0: *ip; imap += newaddrc + newintrc; imaplen -= newaddrc + newintrc; } if (imaplen < 0) { printk("oops, error decoding int-map on %s, len=%d\n", p->full_name, imaplen); return 0; } if (!match) { printk("oops, no match in %s int-map for %s\n", p->full_name, np->full_name); return 0; } p = ipar; naddrc = newaddrc; nintrc = newintrc; ints = imap - nintrc; reg = ints - naddrc; } if (p == NULL) printk("hmmm, int tree for %s doesn't have ctrler\n", np->full_name); *irq = ints; *ictrler = p; return nintrc; }