struct bt_device_node *bt_of_get_bootlogger() { struct bt_device_node *root; struct bt_device_node *p; const BT_be32 *phandle_logger; root = bt_of_find_node_by_path("/"); if(!root) { return NULL; } phandle_logger = bt_of_get_property(root, "boot-logger", NULL); if(!phandle_logger) { return NULL; } p = bt_of_find_node_by_phandle(bt_be32_to_cpu(*((BT_u32 *) (phandle_logger)))); if(!p) { return NULL; } return p; }
struct bt_device_node *bt_of_irq_find_parent(struct bt_device_node *child) { struct bt_device_node *p; const BT_be32 *phandle_intc; if(!bt_of_node_get(child)) { return NULL; } do { phandle_intc = bt_of_get_property(child, "interrupt-parent", NULL); if(!phandle_intc) { p = bt_of_get_parent(child); } else { p = bt_of_find_node_by_phandle(bt_be32_to_cpu(*((BT_u32 *) (phandle_intc)))); } bt_of_node_put(child); child = p; } while(p && !bt_of_get_property(p, "#interrupt-cells", NULL)); return p; }
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; }