BT_ERROR bt_of_irq_map_raw(struct bt_device_node *parent, const BT_be32 *intspec, BT_u32 ointsize, const BT_be32 *addr, struct bt_of_irq *out_irq) { struct bt_device_node *ipar, *tnode, *old = NULL, *newpar = NULL; const BT_be32 *tmp, *imap, *imask; BT_u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0; BT_u32 imaplen, match, i; ipar = bt_of_node_get(parent); do { tmp = bt_of_get_property(ipar, "#interrupt-cells", NULL); if(tmp) { intsize = bt_be32_to_cpu(*tmp); break; } tnode = ipar; ipar = bt_of_irq_find_parent(ipar); bt_of_node_put(tnode); } while(ipar); if(!ipar) { goto fail; } if(ointsize != intsize) { return BT_ERR_GENERIC; } old = bt_of_node_get(ipar); do { tmp = bt_of_get_property(old, "#address-cells", NULL); tnode = bt_of_get_parent(old); bt_of_node_put(old); old = tnode; } while(old && !tmp); bt_of_node_put(old); old = NULL; addrsize = (!tmp) ? 2 : bt_be32_to_cpu(*tmp); while(ipar) { if(bt_of_get_property(ipar, "interrupt-controller", NULL)) { for(i = 0; i < intsize; i++) { out_irq->specifier[i] = bt_of_read_number(intspec + i, 1); out_irq->size = intsize; out_irq->controller = ipar; bt_of_node_put(old); return BT_ERR_NONE; } } // look for interrupt map and parse. imap = bt_of_get_property(ipar, "interrupt-map", &imaplen); if(!imap) { newpar = bt_of_irq_find_parent(ipar); goto skiplevel; } imaplen /= sizeof(BT_u32); imask = bt_of_get_property(ipar, "interrupt-map-mask", NULL); if(!addr && addrsize != 0) { goto fail; } match = 0; while(imaplen > (addrsize + intsize + 1) && !match) { match = 1; for(i = 0; i < addrsize && match; ++i) { BT_be32 mask = imask ? imask[i] : bt_cpu_to_be32(0xffffffffu); match = ((addr[i] ^ imap[i]) & mask) == 0; } for(; i < (addrsize + intsize) && match; ++i) { BT_be32 mask = imask ? imask[i] : bt_cpu_to_be32(0xffffffffu); match = ((intspec[i-addrsize] ^ imap[i]) & mask) == 0; } imap += addrsize + intsize; imaplen -= addrsize + intsize; // Get the int parent. newpar = bt_of_find_node_by_phandle(bt_be32_to_cpu(*imap)); imap++; --imaplen; if(!newpar) { goto fail; } tmp = bt_of_get_property(newpar, "#interrupt-cells", NULL); if(!tmp) { goto fail; } newintsize = bt_be32_to_cpu(*tmp); tmp = bt_of_get_property(newpar, "#address-cells", NULL); newaddrsize = (!tmp) ? 0 : bt_be32_to_cpu(*tmp); if(imaplen < (newaddrsize + newintsize)) { goto fail; } imap += newaddrsize + newintsize; imaplen -= newaddrsize + newintsize; } if(!match) { goto fail; } bt_of_node_put(old); old = bt_of_node_get(newpar); addrsize = newaddrsize; intsize = newintsize; intspec = imap - intsize; addr = intspec - addrsize; skiplevel: bt_of_node_put(ipar); ipar = newpar; newpar = NULL; } fail: bt_of_node_put(ipar); bt_of_node_put(old); bt_of_node_put(newpar); return BT_ERR_GENERIC; }
static int fdt_parse_property(BT_HANDLE hStdout, char **values, int count, char **data, int *len, int *bAllocated) { char *valp = values[0]; int stridx = 0; *len = 0; *bAllocated = 0; if(values[0][0] == '<') { // Array of cells dec/hex // Assume data required == (count - 2) * 4 bytes + 8 for good measure. *data = BT_kMalloc((sizeof(BT_u32) * (count - 2)) + 8); *bAllocated = 1; char *dat = *data; valp++; while((stridx < count) && (*valp != '>')) { if(!*valp) { valp = values[++stridx]; continue; } char *copy = valp; BT_u32 val = strtoul(valp, &valp, 0); *(BT_be32 *) dat = bt_cpu_to_be32(val); dat += 4; *len += 4; if((valp - copy) <= 0) { bt_fprintf(hStdout, "Could not convert \"%s\"\n", copy); return -1; } } if(*valp != '>') { bt_fprintf(hStdout, "Unexpected character %c\n", *valp); return -1; } } else if(values[0][0] == '[') { // Byte stream, (just hex) // Assume data required == (count - 2) * 1bytes, + 4 bytes for good measure *data = BT_kMalloc((sizeof(char) * (count - 2)) + 4); *bAllocated = 1; char *dat = *data; valp++; while((stridx < count) && (*valp != ']')) { if(!*valp) { valp = values[++stridx]; continue; } if(!isxdigit((int)*valp)) { break; } int temp = strtoul(valp, &valp, 16); *dat++ = (char) (temp & 0xFF); *len = *len + 1; } if(*valp != ']') { bt_fprintf(hStdout, "Unexpected character '%c'\n", *valp); return -1; } } else { // Assume a string to be copied directly to data! *data = values[0]; *bAllocated = 0; *len += strlen(values[0]) + 1; } return 0; }