1 /*
2  *   Creation Date: <2003/11/24 12:30:18 samuel>
3  *   Time-stamp: <2004/01/07 19:37:38 samuel>
4  *
5  *	<bindings.c>
6  *
7  *	Forth bindings
8  *
9  *   Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se)
10  *
11  *   This program is free software; you can redistribute it and/or
12  *   modify it under the terms of the GNU General Public License
13  *   version 2
14  *
15  */
16 
17 #include "config.h"
18 #include "libopenbios/bindings.h"
19 #include "libc/string.h"
20 #include "libc/stdlib.h"
21 #include "libc/byteorder.h"
22 
23 
24 /************************************************************************/
25 /*	forth interface glue						*/
26 /************************************************************************/
27 
28 void
push_str(const char * str)29 push_str( const char *str )
30 {
31 	PUSH( pointer2cell(str) );
32 	PUSH( str ? strlen(str) : 0 );
33 }
34 
35 /* WARNING: sloooow - AVOID */
36 cell
feval(const char * str)37 feval( const char *str )
38 {
39 	push_str( str );
40 	return eword("evaluate", 2);
41 }
42 
43 cell
_eword(const char * word,xt_t * cache_xt,int nargs)44 _eword( const char *word, xt_t *cache_xt, int nargs )
45 {
46 	static xt_t catch_xt = 0;
47 	cell ret = -1;
48 
49 	if( !catch_xt )
50 		catch_xt = findword("catch");
51 	if( !*cache_xt )
52 		*cache_xt = findword( (char*)word );
53 
54 	if( *cache_xt ) {
55 		PUSH_xt( *cache_xt );
56 		enterforth( catch_xt );
57 		if( (ret=POP()) )
58 			dstackcnt -= nargs;
59 	}
60 	return ret;
61 }
62 
63 /* note: only the built-in dictionary is searched */
64 int
_fword(const char * word,xt_t * cache_xt)65 _fword( const char *word, xt_t *cache_xt )
66 {
67 	if( !*cache_xt )
68 		*cache_xt = findword( (char*)word );
69 
70 	if( *cache_xt ) {
71 		enterforth( *cache_xt );
72 		return 0;
73 	}
74 	return -1;
75 }
76 
77 int
_selfword(const char * method,xt_t * cache_xt)78 _selfword( const char *method, xt_t *cache_xt )
79 {
80 	if( !*cache_xt )
81 		*cache_xt = find_ih_method( method, my_self() );
82 	if( *cache_xt ) {
83 		enterforth( *cache_xt );
84 		return 0;
85 	}
86 	return -1;
87 }
88 
89 int
_parword(const char * method,xt_t * cache_xt)90 _parword( const char *method, xt_t *cache_xt )
91 {
92 	if( !*cache_xt )
93 		*cache_xt = find_ih_method( method, my_parent() );
94 	if( *cache_xt ) {
95 		enterforth( *cache_xt );
96 		return 0;
97 	}
98 	return -1;
99 }
100 
101 void
bind_func(const char * name,void (* func)(void))102 bind_func( const char *name, void (*func)(void) )
103 {
104 	PUSH( pointer2cell(func) );
105 	push_str( name );
106 	fword("is-cfunc");
107 }
108 
109 void
bind_xtfunc(const char * name,xt_t xt,ucell arg,void (* func)(void))110 bind_xtfunc( const char *name, xt_t xt, ucell arg, void (*func)(void) )
111 {
112 	PUSH_xt( xt );
113 	PUSH( arg );
114 	PUSH( pointer2cell(func) );
115 	push_str( name );
116 	fword("is-xt-cfunc");
117 }
118 
119 xt_t
bind_noname_func(void (* func)(void))120 bind_noname_func( void (*func)(void) )
121 {
122 	PUSH( pointer2cell(func) );
123 	fword("is-noname-cfunc");
124 	return POP_xt();
125 }
126 
127 void
throw(int error)128 throw( int error )
129 {
130 	PUSH( error );
131 	fword("throw");
132 }
133 
134 
135 /************************************************************************/
136 /*	ihandle related							*/
137 /************************************************************************/
138 
139 phandle_t
ih_to_phandle(ihandle_t ih)140 ih_to_phandle( ihandle_t ih )
141 {
142 	PUSH_ih( ih );
143 	fword("ihandle>phandle");
144 	return POP_ph();
145 }
146 
147 ihandle_t
my_parent(void)148 my_parent( void )
149 {
150 	fword("my-parent");
151 	return POP_ih();
152 }
153 
154 ihandle_t
my_self(void)155 my_self( void )
156 {
157 	fword("my-self");
158 	return POP_ih();
159 }
160 
161 xt_t
find_package_method(const char * method,phandle_t ph)162 find_package_method( const char *method, phandle_t ph )
163 {
164 	if (method == NULL) {
165 		push_str("");
166 	} else {
167 		push_str( method );
168 	}
169 
170 	PUSH_ph( ph );
171 	fword("find-method");
172 	if( POP() )
173 		return POP_xt();
174 	return 0;
175 }
176 
177 xt_t
find_ih_method(const char * method,ihandle_t ih)178 find_ih_method( const char *method, ihandle_t ih )
179 {
180 	return find_package_method( method, ih_to_phandle(ih) );
181 }
182 
183 
184 xt_t
find_parent_method(const char * method)185 find_parent_method( const char *method )
186 {
187 	return find_ih_method( method, my_parent() );
188 }
189 
190 void
call_package(xt_t xt,ihandle_t ihandle)191 call_package( xt_t xt, ihandle_t ihandle )
192 {
193 	PUSH_xt( xt );
194 	PUSH_ih( ihandle );
195 	fword("call-package");
196 }
197 
198 void
call_parent(xt_t xt)199 call_parent( xt_t xt )
200 {
201 	PUSH_xt( xt );
202 	fword("call-parent");
203 }
204 
205 void
call_parent_method(const char * method)206 call_parent_method( const char *method )
207 {
208 	push_str( method );
209 	fword("$call-parent");
210 }
211 
212 
213 /************************************************************************/
214 /*	open/close package/dev						*/
215 /************************************************************************/
216 
217 ihandle_t
open_dev(const char * spec)218 open_dev( const char *spec )
219 {
220 	push_str( spec );
221 	fword("open-dev");
222 	return POP_ih();
223 }
224 
225 void
close_dev(ihandle_t ih)226 close_dev( ihandle_t ih )
227 {
228 	PUSH_ih( ih );
229 	fword("close-dev");
230 }
231 
232 ihandle_t
open_package(const char * argstr,phandle_t ph)233 open_package( const char *argstr, phandle_t ph )
234 {
235 	push_str( argstr );
236 	PUSH_ph( ph );
237 	fword("open-package");
238 	return POP_ih();
239 }
240 
241 void
close_package(ihandle_t ih)242 close_package( ihandle_t ih )
243 {
244 	PUSH_ih( ih );
245 	fword("close-package");
246 }
247 
248 
249 /************************************************************************/
250 /*	ihandle arguments						*/
251 /************************************************************************/
252 
253 char *
pop_fstr_copy(void)254 pop_fstr_copy( void )
255 {
256 	int len = POP();
257 	char *str, *p = (char*)cell2pointer(POP());
258 	if( !len )
259 		return NULL;
260 	str = malloc( len + 1 );
261         if( !str )
262                 return NULL;
263 	memcpy( str, p, len );
264 	str[len] = 0;
265 	return str;
266 }
267 
268 char *
my_args_copy(void)269 my_args_copy( void )
270 {
271 	fword("my-args");
272 	return pop_fstr_copy();
273 }
274 
275 
276 /************************************************************************/
277 /*	properties							*/
278 /************************************************************************/
279 
280 void
set_property(phandle_t ph,const char * name,const char * buf,int len)281 set_property( phandle_t ph, const char *name, const char *buf, int len )
282 {
283 	if( !ph ) {
284 		printk("set_property: NULL phandle\n");
285 		return;
286 	}
287 	PUSH(pointer2cell(buf));
288 	PUSH(len);
289 	push_str( name );
290 	PUSH_ph(ph);
291 	fword("set-property");
292 }
293 
294 void
set_int_property(phandle_t ph,const char * name,u32 val)295 set_int_property( phandle_t ph, const char *name, u32 val )
296 {
297 	u32 swapped=__cpu_to_be32(val);
298 	set_property( ph, name, (char*)&swapped, sizeof(swapped) );
299 }
300 
301 char *
get_property(phandle_t ph,const char * name,int * retlen)302 get_property( phandle_t ph, const char *name, int *retlen )
303 {
304 	int len;
305 
306 	if( retlen )
307 		*retlen = -1;
308 
309 	push_str( name );
310 	PUSH_ph( ph );
311 	fword("get-package-property");
312 	if( POP() )
313 		return NULL;
314 	len = POP();
315 	if( retlen )
316 		*retlen = len;
317 	return (char*)cell2pointer(POP());
318 }
319 
320 u32
get_int_property(phandle_t ph,const char * name,int * retlen)321 get_int_property( phandle_t ph, const char *name, int *retlen )
322 {
323 	u32 *p;
324 
325 	if( !(p=(u32 *)get_property(ph, name, retlen)) )
326 		return 0;
327 	return __be32_to_cpu(*p);
328 }
329 
330 
331 /************************************************************************/
332 /*	device selection / iteration					*/
333 /************************************************************************/
334 
335 void
activate_dev(phandle_t ph)336 activate_dev( phandle_t ph )
337 {
338 	PUSH_ph( ph );
339 	fword("active-package!");
340 }
341 
342 phandle_t
activate_device(const char * str)343 activate_device( const char *str )
344 {
345 	phandle_t ph = find_dev( str );
346 	activate_dev( ph );
347 	return ph;
348 }
349 
350 void
device_end(void)351 device_end( void )
352 {
353 	fword("device-end");
354 }
355 
356 phandle_t
get_cur_dev(void)357 get_cur_dev( void )
358 {
359 	fword("active-package");
360 	return POP_ph();
361 }
362 
363 phandle_t
find_dev(const char * path)364 find_dev( const char *path )
365 {
366 	phandle_t ret = 0;
367 	push_str( path );
368 	fword("(find-dev)");
369 	if( POP() )
370 		return POP_ph();
371 	return ret;
372 }
373 
374 char *
get_path_from_ph(phandle_t ph)375 get_path_from_ph( phandle_t ph )
376 {
377 	PUSH(ph);
378 	fword("get-package-path");
379 	return pop_fstr_copy();
380 }
381 
382 phandle_t
dt_iter_begin(void)383 dt_iter_begin( void )
384 {
385 	fword("iterate-tree-begin");
386 	return POP_ph();
387 }
388 
389 phandle_t
dt_iterate(phandle_t last_tree)390 dt_iterate( phandle_t last_tree )
391 {
392         if( !last_tree )
393 		return dt_iter_begin();
394 
395         PUSH_ph( last_tree );
396 	fword("iterate-tree");
397 	return POP_ph();
398 }
399 
400 phandle_t
dt_iterate_type(phandle_t last_tree,const char * type)401 dt_iterate_type( phandle_t last_tree, const char *type )
402 {
403         if( !last_tree )
404                 last_tree = dt_iter_begin();
405 
406 	/* root node is never matched but we don't care about that */
407         while( (last_tree = dt_iterate(last_tree)) ) {
408                 char *s = get_property( last_tree, "device_type", NULL );
409 		if( s && !strcmp(type, s) )
410 			break;
411 	}
412         return last_tree;
413 }
414 
415 
416 /************************************************************************/
417 /*	node methods							*/
418 /************************************************************************/
419 
420 void
make_openable(int only_parents)421 make_openable( int only_parents )
422 {
423 	phandle_t ph, save_ph = get_cur_dev();
424 	PUSH_ph( save_ph );
425 
426 	for( ;; ) {
427 		if( only_parents++ )
428 			fword("parent");
429 		if( !(ph=POP_ph()) )
430 			break;
431 		activate_dev( ph );
432 		PUSH_ph( ph );
433 		fword("is-open");
434 	}
435 	activate_dev( save_ph );
436 }
437 
438 static void
call1_func(void)439 call1_func( void )
440 {
441 	void (*func)(cell v);
442 	func = (void*)cell2pointer(POP());
443 
444 	(*func)( POP() );
445 }
446 
447 
448 static void
add_methods(int flags,int size,const method_t * methods,int nmet)449 add_methods( int flags, int size, const method_t *methods, int nmet )
450 {
451 	xt_t xt=0;
452 	int i;
453 
454 	/* nodes might be matched multiple times */
455 	if( find_package_method(methods[0].name, get_cur_dev()) )
456 		return;
457 
458 	if( size ) {
459 		PUSH( size );
460 		fword("is-ibuf");
461 		xt = POP_xt();
462 	}
463 
464 	for( i=0; i<nmet; i++ ) {
465 		/* null-name methods specify static initializers */
466 		if( !methods[i].name ) {
467 			typedef void (*initfunc)( void *p );
468 			char *buf = NULL;
469 			if( xt ) {
470 				enterforth( xt );
471 				buf = (char*)cell2pointer(POP());
472 			}
473 			(*(initfunc)methods[i].func)( buf );
474 			continue;
475 		}
476 		if( !size )
477 			bind_func( methods[i].name, methods[i].func );
478 		else
479 			bind_xtfunc( methods[i].name, xt, pointer2cell(methods[i].func),
480 				     &call1_func );
481 	}
482 
483 	if( flags & INSTALL_OPEN )
484 		make_openable(0);
485 }
486 
487 void
bind_node_methods(phandle_t ph,int flags,int size,const method_t * methods,int nmet)488 bind_node_methods(phandle_t ph, int flags, int size, const method_t *methods, int nmet)
489 {
490 	phandle_t save_ph = get_cur_dev();
491 
492 	activate_dev(ph);
493 	add_methods(flags, size, methods, nmet);
494 	activate_dev( save_ph );
495 }
496 
497 void
bind_node(int flags,int size,const char * const * paths,int npaths,const method_t * methods,int nmet)498 bind_node( int flags, int size, const char * const *paths, int npaths,
499 	   const method_t *methods, int nmet )
500 {
501 	phandle_t save_ph = get_cur_dev();
502 	int i;
503 
504 	for( i=0; i<npaths; i++ ) {
505 		const char *name = paths[i];
506 
507 		/* type matching? */
508 		if( *name == 'T' ) {
509 			phandle_t ph = 0;
510 			name++;
511 			while( (ph=dt_iterate_type(ph, name)) ) {
512 				activate_dev( ph );
513 				add_methods( flags, size, methods, nmet );
514 			}
515 			continue;
516 		}
517 
518 		/* path patching */
519 		if( activate_device(name) )
520 			add_methods( flags, size, methods, nmet );
521 		else if( *name == '+' ) {
522 			/* create node (and missing parents) */
523 			if( !activate_device(++name) ) {
524 				push_str( name );
525 				fword("create-node");
526 			}
527 			add_methods( flags, size, methods, nmet );
528 		}
529 	}
530 	activate_dev( save_ph );
531 }
532 
533 phandle_t
bind_new_node(int flags,int size,const char * name,const method_t * methods,int nmet)534 bind_new_node( int flags, int size, const char *name,
535 	   const method_t *methods, int nmet )
536 {
537 	phandle_t save_ph = get_cur_dev();
538 	phandle_t new_ph;
539 	/* create node */
540 	push_str( name );
541 	fword("create-node");
542 	add_methods( flags, size, methods, nmet );
543     new_ph = get_cur_dev();
544 
545 	activate_dev( save_ph );
546 	return new_ph;
547 }
548