1 /*
2  *   Creation Date: <2003/10/18 13:24:29 samuel>
3  *   Time-stamp: <2004/03/27 02:00:30 samuel>
4  *
5  *	<methods.c>
6  *
7  *	Misc device node methods
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 "mol/mol.h"
21 #include "libopenbios/ofmem.h"
22 #include "mol/prom.h"
23 #include "osi_calls.h"
24 #include "kbd_sh.h"
25 
26 /************************************************************************/
27 /*	Power Management						*/
28 /************************************************************************/
29 
30 DECLARE_NODE( powermgt, INSTALL_OPEN, 0, "/pci/pci-bridge/mac-io/power-mgt" );
31 
32 /* ( -- ) */
33 static void
set_hybernot_flag(void)34 set_hybernot_flag( void )
35 {
36 }
37 
38 NODE_METHODS( powermgt ) = {
39 	{ "set-hybernot-flag",	set_hybernot_flag	},
40 };
41 
42 
43 /************************************************************************/
44 /*	RTAS (run-time abstraction services)				*/
45 /************************************************************************/
46 
47 DECLARE_NODE( rtas, INSTALL_OPEN, 0, "+/rtas" );
48 
49 /* ( physbase -- rtas_callback ) */
50 static void
rtas_instantiate(void)51 rtas_instantiate( void )
52 {
53 	int physbase = POP();
54 	int s=0x1000, size = (int)of_rtas_end - (int)of_rtas_start;
55 	unsigned long virt;
56 
57 	while( s < size )
58 		s += 0x1000;
59 	virt = ofmem_claim_virt( 0, s, 0x1000 );
60 	ofmem_map( physbase, virt, s, -1 );
61 	memcpy( (char*)virt, of_rtas_start, size );
62 
63 	printk("RTAS instantiated at %08x\n", physbase );
64 	flush_icache_range( (char*)virt, (char*)virt + size );
65 
66 	PUSH( physbase );
67 }
68 
69 NODE_METHODS( rtas ) = {
70 	{ "instantiate",	rtas_instantiate },
71 	{ "instantiate-rtas",	rtas_instantiate },
72 };
73 
74 
75 
76 /************************************************************************/
77 /*	stdout								*/
78 /************************************************************************/
79 
80 DECLARE_NODE( video_stdout, INSTALL_OPEN, 0, "Tdisplay" );
81 
82 /* ( addr len -- actual ) */
83 static void
stdout_write(void)84 stdout_write( void )
85 {
86 	int len = POP();
87 	char *addr = (char*)POP();
88 
89 	/* printk( "%s", s ); */
90         console_draw_fstr(addr, len);
91 
92 	PUSH( len );
93 }
94 
95 NODE_METHODS( video_stdout ) = {
96 	{ "write",	stdout_write	},
97 };
98 
99 
100 /************************************************************************/
101 /*	tty								*/
102 /************************************************************************/
103 
104 DECLARE_NODE( tty, INSTALL_OPEN, 0, "+/mol/mol-tty" );
105 
106 /* ( addr len -- actual ) */
107 static void
tty_read(void)108 tty_read( void )
109 {
110 	int ch, len = POP();
111 	char *p = (char*)POP();
112 	int ret=0;
113 
114 	if( len > 0 ) {
115 		ret = 1;
116 		ch = OSI_TTYGetc();
117 		if( ch >= 0 ) {
118 			*p = ch;
119 		} else {
120 			ret = 0;
121 			OSI_USleep(1);
122 		}
123 	}
124 	PUSH( ret );
125 }
126 
127 /* ( addr len -- actual ) */
128 static void
tty_write(void)129 tty_write( void )
130 {
131 	int i, len = POP();
132 	char *p = (char*)POP();
133 	for( i=0; i<len; i++ )
134 		OSI_TTYPutc( *p++ );
135 	RET( len );
136 }
137 
138 NODE_METHODS( tty ) = {
139 	{ "read",	tty_read	},
140 	{ "write",	tty_write	},
141 };
142 
143 
144 /************************************************************************/
145 /*	keyboard							*/
146 /************************************************************************/
147 
148 typedef struct {
149 	int	cntrl;
150 	int	shift;
151 	int	meta;
152 	int	alt;
153 	int	save_key;
154 	char 	keytable[32];
155 } kbd_state_t;
156 
157 static const unsigned char adb_ascii_table[128] =
158 	/* 0x00 */	"asdfhgzxcv`bqwer"
159 	/* 0x10 */	"yt123465=97-80]o"
160 	/* 0x20 */	"u[ip\nlj'k;\\,/nm."
161 	/* 0x30 */	"\t <\b \e          "
162 	/* 0x40 */	" . * +     /  - "
163 	/* 0x50 */	" =01234567 89   "
164 	/* 0x60 */	"                "
165 	/* 0x70 */	"                ";
166 
167 static const unsigned char adb_shift_table[128] =
168 	/* 0x00 */	"ASDFHGZXCV~BQWER"
169 	/* 0x10 */	"YT!@#$^%+(&_*)}O"
170 	/* 0x20 */	"U{IP\nLJ\"K:|<?NM>"
171 	/* 0x30 */	"\t <\b \e          "
172 	/* 0x40 */	" . * +     /  - "
173 	/* 0x50 */	" =01234567 89   "
174 	/* 0x60 */	"                "
175 	/* 0x70 */	"                ";
176 
177 DECLARE_NODE( kbd, INSTALL_OPEN, sizeof(kbd_state_t),
178       "/psuedo-hid/keyboard",
179       "/mol/mol-keyboard",
180       "/mol/keyboard"
181 );
182 
183 /* ( -- keymap ) (?) */
184 /* should return a pointer to an array with 32 bytes (256 bits) */
185 static void
kbd_get_key_map(kbd_state_t * ks)186 kbd_get_key_map( kbd_state_t *ks )
187 {
188 	/* printk("met_kbd_get_key_map\n"); */
189 
190 	/* keytable[5] = 0x40; */
191 	PUSH( (int)ks->keytable );
192 }
193 
194 /* ( buf len --- actlen ) */
195 static void
kbd_read(kbd_state_t * ks)196 kbd_read( kbd_state_t *ks )
197 {
198 	int ret=0, len = POP();
199 	char *p = (char*)POP();
200 	int key;
201 
202 	if( !p || !len ) {
203 		PUSH( -1 );
204 		return;
205 	}
206 
207 	if( ks->save_key ) {
208 		*p = ks->save_key;
209 		ks->save_key = 0;
210 		RET( 1 );
211 	}
212 	OSI_USleep(1);	/* be nice */
213 
214 	for( ; (key=OSI_GetAdbKey()) >= 0 ; ) {
215 		int code = (key & 0x7f);
216 		int down = !(key & 0x80);
217 
218 		if( code == 0x36 /* ctrl */ ) {
219 			ks->cntrl = down;
220 			continue;
221 		}
222 		if( code == 0x38 /* shift */ || code == 0x7b) {
223 			ks->shift = down;
224 			continue;
225 		}
226 		if( code == 0x37 /* command */ ) {
227 			ks->meta = down;
228 			continue;
229 		}
230 		if( code == 0x3a /* alt */ ) {
231 			ks->alt = down;
232 			continue;
233 		}
234 		if( !down )
235 			continue;
236 
237 		ret = 1;
238 		if( ks->shift )
239 			key = adb_shift_table[ key & 0x7f ];
240 		else
241 			key = adb_ascii_table[ key & 0x7f ];
242 
243 		if( ks->meta ) {
244 			ks->save_key = key;
245 			key = 27;
246 		} else if( ks->cntrl ) {
247 			key = key - 'a' + 1;
248 		}
249 		*p = key;
250 		if( !*p )
251 			*p = 'x';
252 		break;
253 	}
254 	PUSH( ret );
255 }
256 
257 NODE_METHODS( kbd ) = {
258 	{ "read",		kbd_read		},
259 	{ "get-key-map",	kbd_get_key_map		},
260 };
261 
262 
263 /************************************************************************/
264 /*	client interface 'quiesce'					*/
265 /************************************************************************/
266 
267 DECLARE_NODE( ciface, 0, 0, "/packages/client-iface" );
268 
269 /* ( -- ) */
270 static void
ciface_quiesce(unsigned long args[],unsigned long ret[])271 ciface_quiesce( unsigned long args[], unsigned long ret[] )
272 {
273 #if 0
274 	unsigned long msr;
275 	/* This seems to be the correct thing to do - but I'm not sure */
276 	asm volatile("mfmsr %0" : "=r" (msr) : );
277 	msr &= ~(MSR_IR | MSR_DR);
278 	asm volatile("mtmsr %0" :: "r" (msr) );
279 #endif
280 	printk("=============================================================\n\n");
281 	prom_close();
282 
283 	OSI_KbdCntrl( kKbdCntrlSuspend );
284 }
285 
286 /* ( -- ms ) */
287 static void
ciface_milliseconds(unsigned long args[],unsigned long ret[])288 ciface_milliseconds( unsigned long args[], unsigned long ret[] )
289 {
290 	static unsigned long mticks=0, usecs=0;
291 	unsigned long t;
292 
293 	asm volatile("mftb %0" : "=r" (t) : );
294 	if( mticks )
295 		usecs += OSI_MticksToUsecs( t-mticks );
296 	mticks = t;
297 
298 	PUSH( usecs/1000 );
299 }
300 
301 
302 NODE_METHODS( ciface ) = {
303 	{ "quiesce",		ciface_quiesce		},
304 	{ "milliseconds",	ciface_milliseconds	},
305 };
306 
307 
308 /************************************************************************/
309 /*	MMU/memory methods						*/
310 /************************************************************************/
311 
312 DECLARE_NODE( memory, INSTALL_OPEN, 0, "/memory" );
313 DECLARE_NODE( mmu, INSTALL_OPEN, 0, "/cpus/@0" );
314 DECLARE_NODE( mmu_ciface, 0, 0, "/packages/client-iface" );
315 
316 
317 /* ( phys size align --- base ) */
318 static void
mem_claim(void)319 mem_claim( void )
320 {
321 	ucell align = POP();
322 	ucell size = POP();
323 	ucell phys = POP();
324 	ucell ret = ofmem_claim_phys( phys, size, align );
325 
326 	if( ret == -1 ) {
327 		printk("MEM: claim failure\n");
328 		throw( -13 );
329 		return;
330 	}
331 	PUSH( ret );
332 }
333 
334 /* ( phys size --- ) */
335 static void
mem_release(void)336 mem_release( void )
337 {
338 	POP(); POP();
339 }
340 
341 /* ( phys size align --- base ) */
342 static void
mmu_claim(void)343 mmu_claim( void )
344 {
345 	ucell align = POP();
346 	ucell size = POP();
347 	ucell phys = POP();
348 	ucell ret = ofmem_claim_virt( phys, size, align );
349 
350 	if( ret == -1 ) {
351 		printk("MMU: CLAIM failure\n");
352 		throw( -13 );
353 		return;
354 	}
355 	PUSH( ret );
356 }
357 
358 /* ( phys size --- ) */
359 static void
mmu_release(void)360 mmu_release( void )
361 {
362 	POP(); POP();
363 }
364 
365 /* ( phys virt size mode -- [ret???] ) */
366 static void
mmu_map(void)367 mmu_map( void )
368 {
369 	ucell mode = POP();
370 	ucell size = POP();
371 	ucell virt = POP();
372 	ucell phys = POP();
373 	ucell ret;
374 
375 	/* printk("mmu_map: %x %x %x %x\n", phys, virt, size, mode ); */
376 	ret = ofmem_map( phys, virt, size, mode );
377 
378 	if( ret ) {
379 		printk("MMU: map failure\n");
380 		throw( -13 );
381 		return;
382 	}
383 }
384 
385 /* ( virt size -- ) */
386 static void
mmu_unmap(void)387 mmu_unmap( void )
388 {
389 	POP(); POP();
390 }
391 
392 /* ( virt -- false | phys mode true ) */
393 static void
mmu_translate(void)394 mmu_translate( void )
395 {
396 	ucell mode;
397 	ucell virt = POP();
398 	ucell phys = ofmem_translate( virt, &mode );
399 
400 	if( phys == -1 ) {
401 		PUSH( 0 );
402 	} else {
403 		PUSH( phys );
404 		PUSH( mode );
405 		PUSH( -1 );
406 	}
407 }
408 
409 /* ( virt size align -- baseaddr|-1 ) */
410 static void
ciface_claim(void)411 ciface_claim( void )
412 {
413 	ucell align = POP();
414 	ucell size = POP();
415 	ucell virt = POP();
416 	ucell ret = ofmem_claim( virt, size, align );
417 
418 	/* printk("ciface_claim: %08x %08x %x\n", virt, size, align ); */
419 	PUSH( ret );
420 }
421 
422 /* ( virt size -- ) */
423 static void
ciface_release(void)424 ciface_release( void )
425 {
426 	POP();
427 	POP();
428 }
429 
430 
431 NODE_METHODS( memory ) = {
432 	{ "claim",		mem_claim		},
433 	{ "release",		mem_release		},
434 };
435 
436 NODE_METHODS( mmu ) = {
437 	{ "claim",		mmu_claim		},
438 	{ "release",		mmu_release		},
439 	{ "map",		mmu_map			},
440 	{ "unmap",		mmu_unmap		},
441 	{ "translate",		mmu_translate		},
442 };
443 
444 NODE_METHODS( mmu_ciface ) = {
445 	{ "cif-claim",		ciface_claim		},
446 	{ "cif-release",	ciface_release		},
447 };
448 
449 
450 /************************************************************************/
451 /*	init								*/
452 /************************************************************************/
453 
454 void
node_methods_init(void)455 node_methods_init( void )
456 {
457 	REGISTER_NODE( rtas );
458 	REGISTER_NODE( powermgt );
459 	REGISTER_NODE( kbd );
460 	REGISTER_NODE( video_stdout );
461 	REGISTER_NODE( ciface );
462 	REGISTER_NODE( memory );
463 	REGISTER_NODE( mmu );
464 	REGISTER_NODE( mmu_ciface );
465 
466 	if( OSI_CallAvailable(OSI_TTY_GETC) )
467 		REGISTER_NODE( tty );
468 
469 	OSI_KbdCntrl( kKbdCntrlActivate );
470 }
471