#include <l4/types.h>
#include <piggybacker/string.h>
#include <piggybacker/ieee1275.h>
#include <piggybacker/1275tree.h>
#include <piggybacker/io.h>
#define NAME_BUFSIZ	256
device_t *device_find( device_t *list, const char *name )
{
    while( list->handle )
    {
	if( !strcmp_of(list->name, name) )
	    return list;
	list = device_next( list );
    }
    return (device_t *)0;
}
device_t *device_find_handle( device_t *list, L4_Word32_t handle )
{
    while( list->handle )
    {
	if( list->handle == handle )
	    return list;
	list = device_next( list );
    }
    return (device_t *)0;
}
item_t *item_find( device_t *dev, const char *name )
{
    L4_Word_t i;
    item_t *item_name, *item_data;
    i = 0;
    item_name = item_first( dev );
    item_data = item_next( item_name );
    while( i < dev->prop_count )
    {
	if( !strcmp(item_name->data, name) )
	    return item_data;
	item_name = item_next( item_data );
	item_data = item_next( item_name );
	i++;
    }
    return (item_t *)0;
}
static void spill_node( device_t *dev, prom_handle_t node )
{
    item_t *item, *prev_item, *prop;
    int r;
    L4_Word_t start_offset;
    dev->prop_count = 0;
    dev->prop_size = 0;
    item = item_first( dev );
    start_offset = (L4_Word_t)item;
    
    prev_item = item;
    *prev_item->data = '\0';	
    
    r = prom_next_prop( node, prev_item->data, item->data );
    
    while( r > 0 ) 
    {
	
	dev->prop_count++;
	prev_item = item;
	
	item->len = strlen( item->data ) + 1;	
	
	prop = item_next( item );
	prop->len = prom_get_prop_len( node, item->data );
	if( prop->len < 0 )
	    prop->len = 0;
	else
	{
	    prom_get_prop( node, item->data, prop->data, prop->len );
	    if( (prop->len == 4) && 
		    !strcmp_of(dev->name, "/chosen") )
	    {
		
		L4_Word32_t *handle = (L4_Word32_t *)&prop->data;
		*handle = (L4_Word_t)prom_instance_to_package( (void*)(L4_Word_t)*handle );
	    }
	}
	
	item = item_next( prop );
	
	r = prom_next_prop( node, prev_item->data, item->data );
    }
    dev->prop_size = (L4_Word_t)item - start_offset;
}
static void shift_str( char *name, int shift_point )
    
{
    do {
	name[shift_point] = name[shift_point+1];
	shift_point++;
    } while( name[shift_point] );
}
L4_Word_t build_device_tree( char *spill )
{
    prom_handle_t next, node;
    int len;
    device_t *dev;
    node = prom_nav_tree( ROOT_PROM_HANDLE, "peer" );
    dev = device_first( spill );
    while( node != INVALID_PROM_HANDLE ) {
	
	len = prom_package_to_path( node, dev->name, NAME_BUFSIZ );
	if( len > 0 ) {
	    dev->len = len + 1;	
	    dev->handle = (L4_Word_t)node;
	    if( (int)strlen(dev->name) != len )
		shift_str( dev->name, strlen(dev->name) );
	    spill_node( dev, node );
	    dev = device_next( dev );
	}
	
	next = prom_nav_tree( node, "child" );
	if( next != INVALID_PROM_HANDLE ) {
	    node = next;
	    continue;
	}
	
	next = prom_nav_tree( node, "peer" );
	if( next != INVALID_PROM_HANDLE ) {
	    node = next;
	    continue;
	}
	
	while( 1 ) {
    	    node = prom_nav_tree( node, "parent" );
    	    if( node == INVALID_PROM_HANDLE )
    		break;
	    next = prom_nav_tree( node, "peer" );	
	    if( next != INVALID_PROM_HANDLE ) {
		node = next;
		break;
	    }
	}
    }
    
    dev->handle = dev->len = 0;
    dev->prop_count = dev->prop_size = 0;
    return (L4_Word_t)dev - (L4_Word_t)spill;
}