blob: 9b4308b11cec6b9047561fcd114fdcd9e512aa5b [file] [log] [blame]
/*
* Creation Date: <2003/11/24 12:30:18 samuel>
* Time-stamp: <2004/01/07 19:37:38 samuel>
*
* <bindings.c>
*
* Forth bindings
*
* Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2
*
*/
#include "config.h"
#include "libopenbios/bindings.h"
#include "libc/string.h"
#include "libc/stdlib.h"
#include "libc/byteorder.h"
/************************************************************************/
/* forth interface glue */
/************************************************************************/
void
push_str( const char *str )
{
PUSH( pointer2cell(str) );
PUSH( str ? strlen(str) : 0 );
}
/* WARNING: sloooow - AVOID */
cell
feval( const char *str )
{
push_str( str );
return eword("evaluate", 2);
}
cell
_eword( const char *word, xt_t *cache_xt, int nargs )
{
static xt_t catch_xt = 0;
cell ret = -1;
if( !catch_xt )
catch_xt = findword("catch");
if( !*cache_xt )
*cache_xt = findword( (char*)word );
if( *cache_xt ) {
PUSH_xt( *cache_xt );
enterforth( catch_xt );
if( (ret=POP()) )
dstackcnt -= nargs;
}
return ret;
}
/* note: only the built-in dictionary is searched */
int
_fword( const char *word, xt_t *cache_xt )
{
if( !*cache_xt )
*cache_xt = findword( (char*)word );
if( *cache_xt ) {
enterforth( *cache_xt );
return 0;
}
return -1;
}
int
_selfword( const char *method, xt_t *cache_xt )
{
if( !*cache_xt )
*cache_xt = find_ih_method( method, my_self() );
if( *cache_xt ) {
enterforth( *cache_xt );
return 0;
}
return -1;
}
int
_parword( const char *method, xt_t *cache_xt )
{
if( !*cache_xt )
*cache_xt = find_ih_method( method, my_parent() );
if( *cache_xt ) {
enterforth( *cache_xt );
return 0;
}
return -1;
}
void
bind_func( const char *name, void (*func)(void) )
{
PUSH( pointer2cell(func) );
push_str( name );
fword("is-cfunc");
}
void
bind_xtfunc( const char *name, xt_t xt, ucell arg, void (*func)(void) )
{
PUSH_xt( xt );
PUSH( arg );
PUSH( pointer2cell(func) );
push_str( name );
fword("is-xt-cfunc");
}
xt_t
bind_noname_func( void (*func)(void) )
{
PUSH( pointer2cell(func) );
fword("is-noname-cfunc");
return POP_xt();
}
void
throw( int error )
{
PUSH( error );
fword("throw");
}
/************************************************************************/
/* ihandle related */
/************************************************************************/
phandle_t
ih_to_phandle( ihandle_t ih )
{
PUSH_ih( ih );
fword("ihandle>phandle");
return POP_ph();
}
ihandle_t
my_parent( void )
{
fword("my-parent");
return POP_ih();
}
ihandle_t
my_self( void )
{
fword("my-self");
return POP_ih();
}
xt_t
find_package_method( const char *method, phandle_t ph )
{
if (method == NULL) {
push_str("");
} else {
push_str( method );
}
PUSH_ph( ph );
fword("find-method");
if( POP() )
return POP_xt();
return 0;
}
xt_t
find_ih_method( const char *method, ihandle_t ih )
{
return find_package_method( method, ih_to_phandle(ih) );
}
xt_t
find_parent_method( const char *method )
{
return find_ih_method( method, my_parent() );
}
void
call_package( xt_t xt, ihandle_t ihandle )
{
PUSH_xt( xt );
PUSH_ih( ihandle );
fword("call-package");
}
void
call_parent( xt_t xt )
{
PUSH_xt( xt );
fword("call-parent");
}
void
call_parent_method( const char *method )
{
push_str( method );
fword("$call-parent");
}
/************************************************************************/
/* open/close package/dev */
/************************************************************************/
ihandle_t
open_dev( const char *spec )
{
push_str( spec );
fword("open-dev");
return POP_ih();
}
void
close_dev( ihandle_t ih )
{
PUSH_ih( ih );
fword("close-dev");
}
ihandle_t
open_package( const char *argstr, phandle_t ph )
{
push_str( argstr );
PUSH_ph( ph );
fword("open-package");
return POP_ih();
}
void
close_package( ihandle_t ih )
{
PUSH_ih( ih );
fword("close-package");
}
/************************************************************************/
/* ihandle arguments */
/************************************************************************/
char *
pop_fstr_copy( void )
{
int len = POP();
char *str, *p = (char*)cell2pointer(POP());
if( !len )
return NULL;
str = malloc( len + 1 );
if( !str )
return NULL;
memcpy( str, p, len );
str[len] = 0;
return str;
}
char *
my_args_copy( void )
{
fword("my-args");
return pop_fstr_copy();
}
/************************************************************************/
/* properties */
/************************************************************************/
void
set_property( phandle_t ph, const char *name, const char *buf, int len )
{
if( !ph ) {
printk("set_property: NULL phandle\n");
return;
}
PUSH(pointer2cell(buf));
PUSH(len);
push_str( name );
PUSH_ph(ph);
fword("set-property");
}
void
set_int_property( phandle_t ph, const char *name, u32 val )
{
u32 swapped=__cpu_to_be32(val);
set_property( ph, name, (char*)&swapped, sizeof(swapped) );
}
char *
get_property( phandle_t ph, const char *name, int *retlen )
{
int len;
if( retlen )
*retlen = -1;
push_str( name );
PUSH_ph( ph );
fword("get-package-property");
if( POP() )
return NULL;
len = POP();
if( retlen )
*retlen = len;
return (char*)cell2pointer(POP());
}
u32
get_int_property( phandle_t ph, const char *name, int *retlen )
{
u32 *p;
if( !(p=(u32 *)get_property(ph, name, retlen)) )
return 0;
return __be32_to_cpu(*p);
}
/************************************************************************/
/* device selection / iteration */
/************************************************************************/
void
activate_dev( phandle_t ph )
{
PUSH_ph( ph );
fword("active-package!");
}
phandle_t
activate_device( const char *str )
{
phandle_t ph = find_dev( str );
activate_dev( ph );
return ph;
}
void
device_end( void )
{
fword("device-end");
}
phandle_t
get_cur_dev( void )
{
fword("active-package");
return POP_ph();
}
phandle_t
find_dev( const char *path )
{
phandle_t ret = 0;
push_str( path );
fword("(find-dev)");
if( POP() )
return POP_ph();
return ret;
}
char *
get_path_from_ph( phandle_t ph )
{
PUSH(ph);
fword("get-package-path");
return pop_fstr_copy();
}
phandle_t
dt_iter_begin( void )
{
fword("iterate-tree-begin");
return POP_ph();
}
phandle_t
dt_iterate( phandle_t last_tree )
{
if( !last_tree )
return dt_iter_begin();
PUSH_ph( last_tree );
fword("iterate-tree");
return POP_ph();
}
phandle_t
dt_iterate_type( phandle_t last_tree, const char *type )
{
if( !last_tree )
last_tree = dt_iter_begin();
/* root node is never matched but we don't care about that */
while( (last_tree = dt_iterate(last_tree)) ) {
char *s = get_property( last_tree, "device_type", NULL );
if( s && !strcmp(type, s) )
break;
}
return last_tree;
}
/************************************************************************/
/* node methods */
/************************************************************************/
void
make_openable( int only_parents )
{
phandle_t ph, save_ph = get_cur_dev();
PUSH_ph( save_ph );
for( ;; ) {
if( only_parents++ )
fword("parent");
if( !(ph=POP_ph()) )
break;
activate_dev( ph );
PUSH_ph( ph );
fword("is-open");
}
activate_dev( save_ph );
}
static void
call1_func( void )
{
void (*func)(cell v);
func = (void*)cell2pointer(POP());
(*func)( POP() );
}
static void
add_methods( int flags, int size, const method_t *methods, int nmet )
{
xt_t xt=0;
int i;
/* nodes might be matched multiple times */
if( find_package_method(methods[0].name, get_cur_dev()) )
return;
if( size ) {
PUSH( size );
fword("is-ibuf");
xt = POP_xt();
}
for( i=0; i<nmet; i++ ) {
/* null-name methods specify static initializers */
if( !methods[i].name ) {
typedef void (*initfunc)( void *p );
char *buf = NULL;
if( xt ) {
enterforth( xt );
buf = (char*)cell2pointer(POP());
}
(*(initfunc)methods[i].func)( buf );
continue;
}
if( !size )
bind_func( methods[i].name, methods[i].func );
else
bind_xtfunc( methods[i].name, xt, pointer2cell(methods[i].func),
&call1_func );
}
if( flags & INSTALL_OPEN )
make_openable(0);
}
void
bind_node_methods(phandle_t ph, int flags, int size, const method_t *methods, int nmet)
{
phandle_t save_ph = get_cur_dev();
activate_dev(ph);
add_methods(flags, size, methods, nmet);
activate_dev( save_ph );
}
void
bind_node( int flags, int size, const char * const *paths, int npaths,
const method_t *methods, int nmet )
{
phandle_t save_ph = get_cur_dev();
int i;
for( i=0; i<npaths; i++ ) {
const char *name = paths[i];
/* type matching? */
if( *name == 'T' ) {
phandle_t ph = 0;
name++;
while( (ph=dt_iterate_type(ph, name)) ) {
activate_dev( ph );
add_methods( flags, size, methods, nmet );
}
continue;
}
/* path patching */
if( activate_device(name) )
add_methods( flags, size, methods, nmet );
else if( *name == '+' ) {
/* create node (and missing parents) */
if( !activate_device(++name) ) {
push_str( name );
fword("create-node");
}
add_methods( flags, size, methods, nmet );
}
}
activate_dev( save_ph );
}
phandle_t
bind_new_node( int flags, int size, const char *name,
const method_t *methods, int nmet )
{
phandle_t save_ph = get_cur_dev();
phandle_t new_ph;
/* create node */
push_str( name );
fword("create-node");
add_methods( flags, size, methods, nmet );
new_ph = get_cur_dev();
activate_dev( save_ph );
return new_ph;
}