2008-12-12 04:30:53 +08:00
|
|
|
/*
|
2006-04-26 23:08:19 +08:00
|
|
|
* Creation Date: <2003/11/25 14:29:08 samuel>
|
|
|
|
* Time-stamp: <2004/03/27 01:13:53 samuel>
|
2008-12-12 04:30:53 +08:00
|
|
|
*
|
2006-04-26 23:08:19 +08:00
|
|
|
* <client.c>
|
2008-12-12 04:30:53 +08:00
|
|
|
*
|
2006-04-26 23:08:19 +08:00
|
|
|
* OpenFirmware client interface
|
2008-12-12 04:30:53 +08:00
|
|
|
*
|
2006-04-26 23:08:19 +08:00
|
|
|
* Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se)
|
2008-12-12 04:30:53 +08:00
|
|
|
*
|
2006-04-26 23:08:19 +08:00
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* version 2
|
2008-12-12 04:30:53 +08:00
|
|
|
*
|
2006-04-26 23:08:19 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "openbios/config.h"
|
|
|
|
#include "openbios/bindings.h"
|
|
|
|
#include "openbios/of.h"
|
|
|
|
|
2009-06-06 17:58:11 +08:00
|
|
|
/* Uncomment to enable debug printout of client interface calls */
|
|
|
|
//#define DEBUG_CIF
|
|
|
|
|
2008-12-12 04:30:53 +08:00
|
|
|
/* OF client interface. r3 points to the argument array. On return,
|
2006-04-26 23:08:19 +08:00
|
|
|
* r3 should contain 0==true or -1==false. r4-r12,cr0,cr1 may
|
|
|
|
* be modified freely.
|
|
|
|
*
|
|
|
|
* -1 should only be returned if the control transfer to OF fails
|
|
|
|
* (it doesn't) or if the function is unimplemented.
|
|
|
|
*/
|
|
|
|
|
|
|
|
typedef struct prom_args {
|
|
|
|
const char *service;
|
2007-07-12 03:46:26 +08:00
|
|
|
long nargs;
|
|
|
|
long nret;
|
2006-04-26 23:08:19 +08:00
|
|
|
ulong args[10]; /* MAX NUM ARGS! */
|
|
|
|
} prom_args_t;
|
|
|
|
|
|
|
|
|
|
|
|
/* call-method, interpret */
|
|
|
|
static int
|
|
|
|
handle_calls( prom_args_t *pb )
|
|
|
|
{
|
|
|
|
int i, dstacksave = dstackcnt;
|
2009-06-06 17:58:11 +08:00
|
|
|
long val;
|
2008-12-12 04:30:53 +08:00
|
|
|
|
2009-06-06 17:58:11 +08:00
|
|
|
#ifdef DEBUG_CIF
|
|
|
|
printk("%s %s ([%ld] -- [%ld])\n", pb->service, (char *)pb->args[0],
|
|
|
|
pb->nargs, pb->nret);
|
|
|
|
#endif
|
2006-04-26 23:08:19 +08:00
|
|
|
|
|
|
|
for( i=pb->nargs-1; i>=0; i-- )
|
|
|
|
PUSH( pb->args[i] );
|
|
|
|
|
|
|
|
push_str( pb->service );
|
|
|
|
fword("client-call-iface");
|
|
|
|
|
|
|
|
for( i=0; i<pb->nret && dstackcnt > dstacksave; i++ ) {
|
2009-06-06 17:58:11 +08:00
|
|
|
val = POP();
|
2006-04-26 23:08:19 +08:00
|
|
|
pb->args[pb->nargs + i] = val;
|
|
|
|
|
|
|
|
/* don't pop args if an exception occured */
|
|
|
|
if( !i && val )
|
|
|
|
break;
|
|
|
|
}
|
2009-06-06 17:58:11 +08:00
|
|
|
#ifdef DEBUG_CIF
|
2006-04-26 23:08:19 +08:00
|
|
|
/* useful for debug but not necessarily an error */
|
|
|
|
if( i != pb->nret || dstacksave != dstacksave ) {
|
2009-06-06 17:58:11 +08:00
|
|
|
printk("%s '%s': possible argument error (%ld--%ld) got %d\n",
|
2006-04-26 23:08:19 +08:00
|
|
|
pb->service, (char*)pb->args[0], pb->nargs-2, pb->nret, i );
|
|
|
|
}
|
2008-12-12 04:30:53 +08:00
|
|
|
|
2009-06-06 17:58:11 +08:00
|
|
|
printk("handle_calls return: ");
|
|
|
|
for (i = 0; i < pb->nret; i++) {
|
|
|
|
printk("%lx ", pb->args[pb->nargs + i]);
|
|
|
|
}
|
|
|
|
printk("\n");
|
|
|
|
#endif
|
2006-04-26 23:08:19 +08:00
|
|
|
dstackcnt = dstacksave;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
of_client_interface( int *params )
|
|
|
|
{
|
|
|
|
prom_args_t *pb = (prom_args_t*)params;
|
|
|
|
int val, i, dstacksave;
|
|
|
|
|
|
|
|
if( pb->nargs < 0 || pb->nret < 0 )
|
|
|
|
return -1;
|
2009-06-06 17:58:11 +08:00
|
|
|
#ifdef DEBUG_CIF
|
2006-04-26 23:08:19 +08:00
|
|
|
printk("of_client_interface: %s ", pb->service );
|
|
|
|
for( i=0; i<pb->nargs; i++ )
|
|
|
|
printk("%lx ", pb->args[i] );
|
|
|
|
printk("\n");
|
2008-12-12 04:30:53 +08:00
|
|
|
#endif
|
2006-04-26 23:08:19 +08:00
|
|
|
|
|
|
|
/* call-method exceptions are special */
|
|
|
|
if( !strcmp("call-method", pb->service) || !strcmp("interpret", pb->service) )
|
|
|
|
return handle_calls( pb );
|
2008-12-12 04:30:53 +08:00
|
|
|
|
2006-04-26 23:08:19 +08:00
|
|
|
dstacksave = dstackcnt;
|
|
|
|
for( i=0; i<pb->nargs; i++ )
|
|
|
|
PUSH( pb->args[i] );
|
|
|
|
|
|
|
|
push_str( pb->service );
|
|
|
|
fword("client-iface");
|
|
|
|
|
|
|
|
if( (val=POP()) ) {
|
|
|
|
dstackcnt = dstacksave;
|
|
|
|
if( val == -1 )
|
2008-11-30 00:24:51 +08:00
|
|
|
printk("Unimplemented service %s ([%ld] -- [%ld])\n",
|
2006-04-26 23:08:19 +08:00
|
|
|
pb->service, pb->nargs, pb->nret );
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
for( i=0; i<pb->nret && dstackcnt > dstacksave ; i++ )
|
|
|
|
pb->args[pb->nargs + i] = POP();
|
2008-12-12 04:30:53 +08:00
|
|
|
|
2009-06-06 17:58:11 +08:00
|
|
|
#ifdef DEBUG_CIF
|
2006-04-26 23:08:19 +08:00
|
|
|
if( i != pb->nret || dstackcnt != dstacksave ) {
|
2008-12-12 04:30:53 +08:00
|
|
|
printk("service %s: argument count error (%d %d)\n",
|
2006-04-26 23:08:19 +08:00
|
|
|
pb->service, i, dstackcnt - dstacksave );
|
|
|
|
dstackcnt = dstacksave;
|
|
|
|
}
|
2009-06-06 17:58:11 +08:00
|
|
|
|
|
|
|
printk("of_client_interface return:");
|
|
|
|
for (i = 0; i < pb->nret; i++) {
|
|
|
|
printk("%lx ", pb->args[pb->nargs + i]);
|
|
|
|
}
|
|
|
|
printk("\n");
|
|
|
|
#endif
|
2006-04-26 23:08:19 +08:00
|
|
|
return 0;
|
|
|
|
}
|