blob: bfaf51506cb2668de38cabe319901a006971f707 [file] [log] [blame]
/*
* Creation Date: <2003/10/18 13:24:29 samuel>
* Time-stamp: <2004/03/27 02:00:30 samuel>
*
* <methods.c>
*
* Misc device node methods
*
* 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 "mol/mol.h"
#include "libopenbios/ofmem.h"
#include "mol/prom.h"
#include "osi_calls.h"
#include "kbd_sh.h"
/************************************************************************/
/* Power Management */
/************************************************************************/
DECLARE_NODE( powermgt, INSTALL_OPEN, 0, "/pci/pci-bridge/mac-io/power-mgt" );
/* ( -- ) */
static void
set_hybernot_flag( void )
{
}
NODE_METHODS( powermgt ) = {
{ "set-hybernot-flag", set_hybernot_flag },
};
/************************************************************************/
/* RTAS (run-time abstraction services) */
/************************************************************************/
DECLARE_NODE( rtas, INSTALL_OPEN, 0, "+/rtas" );
/* ( physbase -- rtas_callback ) */
static void
rtas_instantiate( void )
{
int physbase = POP();
int s=0x1000, size = (int)of_rtas_end - (int)of_rtas_start;
unsigned long virt;
while( s < size )
s += 0x1000;
virt = ofmem_claim_virt( 0, s, 0x1000 );
ofmem_map( physbase, virt, s, -1 );
memcpy( (char*)virt, of_rtas_start, size );
printk("RTAS instantiated at %08x\n", physbase );
flush_icache_range( (char*)virt, (char*)virt + size );
PUSH( physbase );
}
NODE_METHODS( rtas ) = {
{ "instantiate", rtas_instantiate },
{ "instantiate-rtas", rtas_instantiate },
};
/************************************************************************/
/* stdout */
/************************************************************************/
DECLARE_NODE( video_stdout, INSTALL_OPEN, 0, "Tdisplay" );
/* ( addr len -- actual ) */
static void
stdout_write( void )
{
int len = POP();
char *addr = (char*)POP();
/* printk( "%s", s ); */
console_draw_fstr(addr, len);
PUSH( len );
}
NODE_METHODS( video_stdout ) = {
{ "write", stdout_write },
};
/************************************************************************/
/* tty */
/************************************************************************/
DECLARE_NODE( tty, INSTALL_OPEN, 0, "+/mol/mol-tty" );
/* ( addr len -- actual ) */
static void
tty_read( void )
{
int ch, len = POP();
char *p = (char*)POP();
int ret=0;
if( len > 0 ) {
ret = 1;
ch = OSI_TTYGetc();
if( ch >= 0 ) {
*p = ch;
} else {
ret = 0;
OSI_USleep(1);
}
}
PUSH( ret );
}
/* ( addr len -- actual ) */
static void
tty_write( void )
{
int i, len = POP();
char *p = (char*)POP();
for( i=0; i<len; i++ )
OSI_TTYPutc( *p++ );
RET( len );
}
NODE_METHODS( tty ) = {
{ "read", tty_read },
{ "write", tty_write },
};
/************************************************************************/
/* keyboard */
/************************************************************************/
typedef struct {
int cntrl;
int shift;
int meta;
int alt;
int save_key;
char keytable[32];
} kbd_state_t;
static const unsigned char adb_ascii_table[128] =
/* 0x00 */ "asdfhgzxcv`bqwer"
/* 0x10 */ "yt123465=97-80]o"
/* 0x20 */ "u[ip\nlj'k;\\,/nm."
/* 0x30 */ "\t <\b \e "
/* 0x40 */ " . * + / - "
/* 0x50 */ " =01234567 89 "
/* 0x60 */ " "
/* 0x70 */ " ";
static const unsigned char adb_shift_table[128] =
/* 0x00 */ "ASDFHGZXCV~BQWER"
/* 0x10 */ "YT!@#$^%+(&_*)}O"
/* 0x20 */ "U{IP\nLJ\"K:|<?NM>"
/* 0x30 */ "\t <\b \e "
/* 0x40 */ " . * + / - "
/* 0x50 */ " =01234567 89 "
/* 0x60 */ " "
/* 0x70 */ " ";
DECLARE_NODE( kbd, INSTALL_OPEN, sizeof(kbd_state_t),
"/psuedo-hid/keyboard",
"/mol/mol-keyboard",
"/mol/keyboard"
);
/* ( -- keymap ) (?) */
/* should return a pointer to an array with 32 bytes (256 bits) */
static void
kbd_get_key_map( kbd_state_t *ks )
{
/* printk("met_kbd_get_key_map\n"); */
/* keytable[5] = 0x40; */
PUSH( (int)ks->keytable );
}
/* ( buf len --- actlen ) */
static void
kbd_read( kbd_state_t *ks )
{
int ret=0, len = POP();
char *p = (char*)POP();
int key;
if( !p || !len ) {
PUSH( -1 );
return;
}
if( ks->save_key ) {
*p = ks->save_key;
ks->save_key = 0;
RET( 1 );
}
OSI_USleep(1); /* be nice */
for( ; (key=OSI_GetAdbKey()) >= 0 ; ) {
int code = (key & 0x7f);
int down = !(key & 0x80);
if( code == 0x36 /* ctrl */ ) {
ks->cntrl = down;
continue;
}
if( code == 0x38 /* shift */ || code == 0x7b) {
ks->shift = down;
continue;
}
if( code == 0x37 /* command */ ) {
ks->meta = down;
continue;
}
if( code == 0x3a /* alt */ ) {
ks->alt = down;
continue;
}
if( !down )
continue;
ret = 1;
if( ks->shift )
key = adb_shift_table[ key & 0x7f ];
else
key = adb_ascii_table[ key & 0x7f ];
if( ks->meta ) {
ks->save_key = key;
key = 27;
} else if( ks->cntrl ) {
key = key - 'a' + 1;
}
*p = key;
if( !*p )
*p = 'x';
break;
}
PUSH( ret );
}
NODE_METHODS( kbd ) = {
{ "read", kbd_read },
{ "get-key-map", kbd_get_key_map },
};
/************************************************************************/
/* client interface 'quiesce' */
/************************************************************************/
DECLARE_NODE( ciface, 0, 0, "/packages/client-iface" );
/* ( -- ) */
static void
ciface_quiesce( unsigned long args[], unsigned long ret[] )
{
#if 0
unsigned long msr;
/* This seems to be the correct thing to do - but I'm not sure */
asm volatile("mfmsr %0" : "=r" (msr) : );
msr &= ~(MSR_IR | MSR_DR);
asm volatile("mtmsr %0" :: "r" (msr) );
#endif
printk("=============================================================\n\n");
prom_close();
OSI_KbdCntrl( kKbdCntrlSuspend );
}
/* ( -- ms ) */
static void
ciface_milliseconds( unsigned long args[], unsigned long ret[] )
{
static unsigned long mticks=0, usecs=0;
unsigned long t;
asm volatile("mftb %0" : "=r" (t) : );
if( mticks )
usecs += OSI_MticksToUsecs( t-mticks );
mticks = t;
PUSH( usecs/1000 );
}
NODE_METHODS( ciface ) = {
{ "quiesce", ciface_quiesce },
{ "milliseconds", ciface_milliseconds },
};
/************************************************************************/
/* MMU/memory methods */
/************************************************************************/
DECLARE_NODE( memory, INSTALL_OPEN, 0, "/memory" );
DECLARE_NODE( mmu, INSTALL_OPEN, 0, "/cpus/@0" );
DECLARE_NODE( mmu_ciface, 0, 0, "/packages/client-iface" );
/* ( phys size align --- base ) */
static void
mem_claim( void )
{
ucell align = POP();
ucell size = POP();
ucell phys = POP();
ucell ret = ofmem_claim_phys( phys, size, align );
if( ret == -1 ) {
printk("MEM: claim failure\n");
throw( -13 );
return;
}
PUSH( ret );
}
/* ( phys size --- ) */
static void
mem_release( void )
{
POP(); POP();
}
/* ( phys size align --- base ) */
static void
mmu_claim( void )
{
ucell align = POP();
ucell size = POP();
ucell phys = POP();
ucell ret = ofmem_claim_virt( phys, size, align );
if( ret == -1 ) {
printk("MMU: CLAIM failure\n");
throw( -13 );
return;
}
PUSH( ret );
}
/* ( phys size --- ) */
static void
mmu_release( void )
{
POP(); POP();
}
/* ( phys virt size mode -- [ret???] ) */
static void
mmu_map( void )
{
ucell mode = POP();
ucell size = POP();
ucell virt = POP();
ucell phys = POP();
ucell ret;
/* printk("mmu_map: %x %x %x %x\n", phys, virt, size, mode ); */
ret = ofmem_map( phys, virt, size, mode );
if( ret ) {
printk("MMU: map failure\n");
throw( -13 );
return;
}
}
/* ( virt size -- ) */
static void
mmu_unmap( void )
{
POP(); POP();
}
/* ( virt -- false | phys mode true ) */
static void
mmu_translate( void )
{
ucell mode;
ucell virt = POP();
ucell phys = ofmem_translate( virt, &mode );
if( phys == -1 ) {
PUSH( 0 );
} else {
PUSH( phys );
PUSH( mode );
PUSH( -1 );
}
}
/* ( virt size align -- baseaddr|-1 ) */
static void
ciface_claim( void )
{
ucell align = POP();
ucell size = POP();
ucell virt = POP();
ucell ret = ofmem_claim( virt, size, align );
/* printk("ciface_claim: %08x %08x %x\n", virt, size, align ); */
PUSH( ret );
}
/* ( virt size -- ) */
static void
ciface_release( void )
{
POP();
POP();
}
NODE_METHODS( memory ) = {
{ "claim", mem_claim },
{ "release", mem_release },
};
NODE_METHODS( mmu ) = {
{ "claim", mmu_claim },
{ "release", mmu_release },
{ "map", mmu_map },
{ "unmap", mmu_unmap },
{ "translate", mmu_translate },
};
NODE_METHODS( mmu_ciface ) = {
{ "cif-claim", ciface_claim },
{ "cif-release", ciface_release },
};
/************************************************************************/
/* init */
/************************************************************************/
void
node_methods_init( void )
{
REGISTER_NODE( rtas );
REGISTER_NODE( powermgt );
REGISTER_NODE( kbd );
REGISTER_NODE( video_stdout );
REGISTER_NODE( ciface );
REGISTER_NODE( memory );
REGISTER_NODE( mmu );
REGISTER_NODE( mmu_ciface );
if( OSI_CallAvailable(OSI_TTY_GETC) )
REGISTER_NODE( tty );
OSI_KbdCntrl( kKbdCntrlActivate );
}