Unit testing framework and devicetree framework refactoring (#50)
[lunaix-os.git] / lunaix-os / hal / devtree / dt_interrupt.c
index ab4d8b36dcf58e43f6d569cf30a6c3eea26cfdc9..905eb0243461588c15c4145cb8c1c1a5a7fb05b3 100644 (file)
 #include "devtree.h"
 
 #include <lunaix/mm/valloc.h>
-
 #include <klibc/string.h>
 
-static struct dt_intr_map*
-__get_map(struct dt_intr_node* node)
-{
-    if (!node->map) {
-        node->map = valloc(sizeof(struct dt_intr_map));
-        
-        node->map->resolved = false;
-        llist_init_head(&node->map->mapent);
-
-        INTR_TO_DTNODE(node)->base.intr_neuxs = true;
-    }
-
-    return node->map;
-}
-
-static void
-__prepare_key(struct dt_intr_mapkey* key, 
-              dt_enc_t key_raw, unsigned int keylen)
+static int 
+__ispec_sz(struct dtn* node)
 {
-    *key = (struct dt_intr_mapkey) {
-        .val = valloc(keylen * sizeof(int)),
-        .size = keylen
-    };
-
-    memcpy(key->val, key_raw, keylen * sizeof(int));
-}
-
-static inline void
-__destory_key(struct dt_intr_mapkey* key)
-{
-    vfree(key->val);
+    return node->base.intr_c + node->base.addr_c;
 }
 
-static inline unsigned int
-__interrupt_keysize(struct dt_node_base* base)
+static struct dtp_val*
+__ispec_mask(struct dtn* node)
 {
-    return dt_size_cells(base) + base->intr_c;
-}
-
-static void
-__mask_key(struct dt_intr_mapkey* k, struct dt_intr_mapkey* mask)
-{
-    for (unsigned int i = 0; i < k->size; i++)
-    {
-        k->val[i] &= mask->val[i];
-    }
-}
-
-static bool
-__compare_key(struct dt_intr_mapkey* k1, struct dt_intr_mapkey* k2)
-{
-    if (k1->size != k2->size) {
-        return false;
-    }
-
-    for (unsigned int i = 0; i < k1->size; i++)
-    {
-        if (k1->val[i] != k2->val[i]) {
-            return false;
-        }    
-    }
-    
-    return true;
-}
-
-static struct dt_node_base*
-__get_connected_nexus(struct dt_node_base* base)
-{
-    struct dt_node_base* current;
-
-    current = base;
-    while (current && !current->intr_neuxs) {
-        current = current->parent;
-    }
-
-    return current;
+    return dt_getprop(&node->base, "interrupt-map-mask");
 }
 
 void
-dt_resolve_interrupt_map(struct dt_node* node)
+dt_resolve_interrupt_map(struct dtn* node)
 {
-    struct dt_intr_node* inode;
-    struct dt_intr_map* imap;
-    struct dt_prop_iter iter;
-
-    struct dt_intr_mapent *ent;
-
-    unsigned int keysize, parent_keysize;
-    unsigned int advance;
-    dt_phnd_t parent_hnd;
+    struct dtp_val* map;
+    struct dtspec_create_ops ops = {};
     
-    inode = &node->intr;
-    if (likely(!inode->map)) {
+    ops.child_keysz = __ispec_sz;
+    ops.parent_keysz = __ispec_sz;
+    ops.get_mask = __ispec_mask;
+    
+    map = dt_getprop(&node->base, "interrupt-map");
+    if (likely(!map)) {
         return;
     }
 
-    imap = inode->map;
-    keysize = __interrupt_keysize(&node->base);
-    
-    __prepare_key(&imap->key_mask, imap->raw_mask.encoded, keysize);
-
-    dt_decode(&iter, &node->base, &imap->raw, 1);
-
-    advance = 0;
-    do 
-    {
-        advance = keysize;
-        ent = valloc(sizeof(*ent));
-
-        __prepare_key(&ent->key, iter.prop_loc, advance);
-        __mask_key(&ent->key, &imap->key_mask);
-
-        parent_hnd = dtprop_to_phnd(dtprop_extract(&iter, advance));
-        ent->parent = &dt_resolve_phandle(parent_hnd)->base;
-
-        advance++;
-        parent_keysize = __interrupt_keysize(ent->parent);
-
-        ent->parent_props.encoded = dtprop_extract(&iter, advance);
-        ent->parent_props.size = parent_keysize;
-
-        advance += parent_keysize;
-
-        llist_append(&imap->mapent, &ent->ents);
-        
-    } while (dtprop_next_n(&iter, advance));
-
-    imap->resolved = true;
+    node->intr.map = dtspec_create(node, map, &ops);
 }
 
-struct dt_prop_val*
-dt_resolve_interrupt(struct dt_node* node)
+struct dtn* 
+dt_interrupt_at(struct dtn* node, int idx, struct dtp_val* int_spec)
 {
-    struct dt_node_base* nexus;
-    struct dt_intr_node* i_nexus, *i_node;
-    struct dt_intr_mapkey key;
-    unsigned int keylen;
+    int int_cells;
+    dt_enc_t raw_specs;
+    struct dtn_intr* intr;
+    struct dtn* intr_domain;
 
-    if (!node->intr.intr.valid) {
+    intr = &node->intr;
+    if (!intr->valid || idx >= intr->nr_intrs) {
         return NULL;
     }
-
-    nexus = __get_connected_nexus(&node->base);
-    i_nexus = &BASE_TO_DTNODE(nexus)->intr;
-    i_node  = &node->intr;
-
-    if (!nexus) {
-        return &i_node->intr.arr;
-    }
-
-    keylen = __interrupt_keysize(nexus);
-    key = (struct dt_intr_mapkey) {
-        .val = valloc(keylen * sizeof(int)),
-        .size = keylen
-    };
-
-    memcpy( key.val, 
-            node->reg.encoded, dt_addr_cells(nexus) * sizeof(int));
     
-    memcpy(&key.val[dt_addr_cells(nexus)],
-            i_node->intr.arr.encoded, nexus->intr_c * sizeof(int));
-
-    __mask_key(&key, &i_nexus->map->key_mask);
+    if (!intr->extended) {
+        intr_domain = intr->parent;
+        int_cells = intr_domain->base.intr_c;
+        
+        raw_specs = &intr->raw_ispecs.encoded[int_cells * idx];
+        dtp_val_set(int_spec, raw_specs, int_cells);
 
-    struct dt_intr_mapent *pos, *n;
+        return intr_domain;
+    }
 
-    llist_for_each(pos, n, &i_nexus->map->mapent, ents) {
-        if (__compare_key(&pos->key, &key))
-        {
-            __destory_key(&key);
-            return &pos->parent_props;
+    struct dtspec_intr *p, *n;
+    llist_for_each(p, n, &intr->ext_ispecs, ispecs)
+    {
+        if (!(idx--)) {
+            *int_spec = p->val;
+            return p->domain;
         }
     }
 
-    __destory_key(&key);
     return NULL;
 }
 
 bool
-parse_stdintr_prop(struct fdt_iter* it, struct dt_intr_node* node)
+parse_stdintr_prop(struct fdt_blob* fdt, fdt_loc_t loc, struct dtn_intr* node)
 {
-    struct dt_intr_map* map;
-
-    if (propeq(it, "interrupt-map")) {
-        map = __get_map(node);
-        __mkprop_ptr(it, &map->raw);
-    }
-
-    else if (propeq(it, "interrupt-map-mask")) {
-        map = __get_map(node);
-        __mkprop_ptr(it, &map->raw_mask);
-    }
-
-    else if (propeq(it, "interrupt-parent")) {
-        node->parent_hnd = __prop_getu32(it);
+    if (propeq(fdt, loc, "interrupt-parent")) {
+        node->parent_hnd = __prop_getu32(loc);
     }
 
-    else if (propeq(it, "interrupt-extended")) {
-        node->intr.extended = true;
-        __mkprop_ptr(it, &node->intr.arr);
+    else if (propeq(fdt, loc, "interrupts-extended")) {
+        node->extended = true;
+        __mkprop_ptr(loc, &node->raw_ispecs);
     }
 
-    else if (!node->intr.extended && propeq(it, "interrupts")) {
-        node->intr.valid = true;
-        __mkprop_ptr(it, &node->intr.arr);
+    else if (!node->extended && propeq(fdt, loc, "interrupts")) {
+        __mkprop_ptr(loc, &node->raw_ispecs);
     }
 
     else {
         return false;
     }
 
+    node->valid = true;
     return true;
 }
\ No newline at end of file