panthema / 2006 / SDIOS06 / sdios06 / src / console / console-server.cc (Download File)
/*****************************************************************
 * Source file : console.idl
 * Platform    : V4 IA32
 * Mapping     : CORBA C
 * 
 * Generated by IDL4 1.0.2 (roadrunner) on 20/07/2006 12:07
 * Report bugs to haeberlen@ira.uka.de
 *****************************************************************/

#include <idl4glue.h>
#include "console-server.h"
#include <config.h>
#include <l4/sigma0.h>
#include <stdio.h>
#include <sdi/ports.h>
#include <stdlib.h>
#include <new>
#include <assert.h>
#include <string.h>
#include <l4/thread.h>
#include <l4/ipc.h>
#include <l4/kip.h>
#include <l4/schedule.h>

#include <sdi/panic.h>
#include <sdi/log.h>
#include <sdi/locator.h>

#include <if/iflogging.h>
#include <if/ifsyscall.h>

#include "VirtualConsole.h"

L4_Bool_t ALTPressed = 0;
const int MAX_VIRT_CONSOLES = 12;
const uint16_t dataPort = 0x60u;
const uint16_t statusPort = 0x64u;
const L4_Word_t VIDEO_MEM = 0xb8000;	// Start address of the video me
char* videoMemStart;		// pointer auf Anfang des Videobereichs
size_t videoMemSize = 4000;	// Size of Videomemory: 25 * 80 *2 = 4000	
//TODO: which console has initial focus???? what happens with input, not assigned to a console?
int consoleWithFocus = 0;
VirtualConsole* consoles[MAX_VIRT_CONSOLES];

L4_ThreadId_t locatorid;

/**
 * Sets the focus from the last to the current console.
 */
void setFocusToConsole(int console) {
	consoles[consoleWithFocus]->setFocus(0);
	consoles[console]->setFocus(1);
	consoles[console]->update();
	consoleWithFocus = console;
	LogMessage("Switched to console%d", console);
}

/**
 * Creates the consoles and passes them a handle to the start of the video memory.
 */
void initConsoles() {
	for(int i=0; i<MAX_VIRT_CONSOLES; i++) {
		consoles[i] = new VirtualConsole(i, videoMemStart);
	}
	setFocusToConsole(0);
}

/* Interface console */

IDL4_INLINE void console_interrupt_implementation(CORBA_Object _caller, idl4_server_environment *_env)

{
	// Read control and Data register
	uint8_t scanCode = inb(dataPort);
	//LogMessage("Scan Code: %u", scanCode);
	//TODO: Filter switch between virtual consoles ALT-F1, ...
	if(scanCode & 0x80) {	// key released
		if(0xb8 == scanCode) {	// ALT released
			ALTPressed = 0;	
		}
	} else {	// key pressed
		// handle non-following codes
		switch(scanCode) {
			case 56:				// ALT
				ALTPressed = 1;
				break;
			case 87:
				if(ALTPressed) setFocusToConsole(10);
				break;
			case 88:
				if(ALTPressed) setFocusToConsole(11);
				break;
			case 73:	// PageUp
				consoles[consoleWithFocus]->PageUp();
				break;
			case 81:	// PageDown
				consoles[consoleWithFocus]->PageDown();
				break;
		}
		// handle following codes: 0x3b-0x44 (F1-F10)
		if((0x3b <= scanCode) && (scanCode <= 0x44)) {
			if(ALTPressed) {
				setFocusToConsole(scanCode - 0x3b);
			}
		}	
	}	
	
	// add a scancode to the input bufferof the virtual console, who has the focus
	consoles[consoleWithFocus]->addInput(scanCode);
	
	// Acknowledge interrupt to reenable IRQ	
	L4_Set_MsgTag(L4_Niltag);
	L4_MsgTag_t tag = L4_Reply(_caller);
	if(L4_IpcFailed(tag)) {
		panic("Sending IPC to reenable interrupts failed");
	}
	
	return;
}

IDL4_PUBLISH_CONSOLE_INTERRUPT(console_interrupt_implementation);

IDL4_INLINE void console_Read_implementation(CORBA_Object _caller, const objectid_t consolehandle, const uint32_t pos, const idlsize_t readsize, buffer_t *buffer, idl4_server_environment *_env)

{
	// filehandle used here as consolehandle to determine, which has the focus
	//assert(readsize < (unsigned long)buffer->_maximum);
	buffer->_length = consoles[consolehandle]->read(readsize, buffer->_buffer);	
  	return;
}

IDL4_PUBLISH_CONSOLE_READ(console_Read_implementation);

IDL4_INLINE void console_Write_implementation(CORBA_Object _caller, const objectid_t consolehandle, const uint32_t pos, idlsize_t *byteswritten, const buffer_t *buffer, idl4_server_environment *_env)

{
	// filehandle used here as consolehandle to determine, which has the focus
	*byteswritten = consoles[consolehandle]->write(buffer, pos);
	return;
}

IDL4_PUBLISH_CONSOLE_WRITE(console_Write_implementation);

IDL4_INLINE void console_GetFileSize_implementation(CORBA_Object _caller, const objectid_t filehandle, idlsize_t *filesize, idl4_server_environment *_env)

{
	// the console is no file, therefor it has no size
	*filesize = 0;
	return;
}

IDL4_PUBLISH_CONSOLE_GETFILESIZE(console_GetFileSize_implementation);

void *console_vtable_4[CONSOLE_DEFAULT_VTABLE_SIZE] = CONSOLE_DEFAULT_VTABLE_4;
void *console_vtable_discard[CONSOLE_DEFAULT_VTABLE_SIZE] = CONSOLE_DEFAULT_VTABLE_DISCARD;
void **console_itable[8] = { console_vtable_discard, console_vtable_discard, console_vtable_discard, console_vtable_discard, console_vtable_4, console_vtable_discard, console_vtable_discard, console_vtable_discard };
void *console_ktable[CONSOLE_DEFAULT_KTABLE_SIZE] = CONSOLE_DEFAULT_KTABLE;

void console_server(void)

{
  L4_ThreadId_t partner;
  L4_MsgTag_t msgtag;
  idl4_msgbuf_t msgbuf;
  long cnt;

  idl4_msgbuf_init(&msgbuf);
  for (cnt = 0;cnt < CONSOLE_STRBUF_SIZE;cnt++)
    idl4_msgbuf_add_buffer(&msgbuf, malloc(8000), 8000);

  while (1)
    {
      partner = L4_nilthread;
      msgtag.raw = 0;
      cnt = 0;

      while (1)
        {
          idl4_msgbuf_sync(&msgbuf);

          idl4_reply_and_wait(&partner, &msgtag, &msgbuf, &cnt);

          if (idl4_is_error(&msgtag))
            break;

          if (IDL4_EXPECT_FALSE(idl4_is_kernel_message(msgtag)))
            idl4_process_request(&partner, &msgtag, &msgbuf, &cnt, console_ktable[idl4_get_kernel_message_id(msgtag) & CONSOLE_KID_MASK]);
            else idl4_process_request(&partner, &msgtag, &msgbuf, &cnt, console_itable[idl4_get_interface_id(&msgtag) & CONSOLE_IID_MASK][idl4_get_function_id(&msgtag) & CONSOLE_FID_MASK]);
        }
    }
}

void console_discard(void) {
	LogMessage("ERROR: IPC Msg to console server discarded!");
}



int main () {
	/**
	 *  Initialize the console server
	 */
    LogMessage("ConsoleServer is alive");

    // Get Locator
	/* Guess locatorid TODO: use new Locataor */
	locatorid = L4_GlobalId (L4_ThreadIdUserBase (L4_KernelInterface ()) + 3, 1);
	
	// Get CORBA Environment
	CORBA_Environment env (idl4_default_environment);    
        L4_ThreadId_t syscallServerId = L4_GlobalId(0x3ffff - 4, 1);
	
	// Get Video Memory from Pager
	// synthesize pagefault message
	
	LogMessage("Synthesized PF");
	videoMemStart = (char *) 0xb8000;
	L4_Fpage_t page = L4_Sigma0_GetPage_RcvWindow(L4_nilthread,
		L4_Fpage((L4_Word_t) videoMemStart, (L4_Word_t) videoMemSize),
		L4_Fpage(0x90000000, (L4_Word_t) videoMemSize));
	if(L4_IsNilFpage(page)) {
		LogMessage("not ok");
	} else {
		LogMessage("ok (Addr: %lx Size: %lu)", L4_Address(page),
				L4_Size(page));
	}
	videoMemStart = (char*) 0x90000000;
	LogMessage("VideoMem at %p length %u", videoMemStart, videoMemSize);
    memset(videoMemStart, 0, 4000);
    
	// Create Virtual Console
	initConsoles();
	
	// Register the Virtual Consoles at the locator
	LogMessage("Register virtual consoles at the locator");
	for(int i=0; i<MAX_VIRT_CONSOLES; i++) {
		char name[128];
		snprintf(name, sizeof(name), "console%d", i);
		if(Register(GetLocator(), name, IF_FILE_ID, i) != OK)
			panic("Couldn't register console");
	}
	//IF_LOCATOR_Announce ((CORBA_Object)locatorid, IF_FILE_ID, &env);	  
    
    /*
    * Register for Interrupt 1 = keyboard
    */
    L4_Word_t intNum = 1;
    L4_ThreadId_t interruptThread = L4_GlobalId( intNum, 1 );
    L4_ThreadId_t interruptHandler = L4_Myself();
	LogMessage("Registering Console for interrupt..."); 
	unsigned long one = 1;
	L4_Word_t *word = &one; 	// the return value, 1 = no error
	IF_SYSCALL_AssociateInterrupt( (CORBA_Object)syscallServerId,
							 &interruptThread,
							 &interruptHandler,
							 word,
							 &env); 
	// check the return value, panic if word != 1			 
    if(!*word) {
    	printf("%lx ", L4_ErrorCode());
     	panic("Registering the console-server for interrupt handling failed!");
    }
		
	/**
	 * Everything ready, now let's get to work.
	 * Start the console server loop.
	 */
	 LogMessage("Sarting console_server_loop");
	 console_server();
	
	/*
	 * Clean up, when exiting. New Function?
	 */
	 //L4_DeassociateInterrupt(interruptThread);
	
    /* Spin forever */
    L4_Sleep(L4_Never);
    panic("This should never be reached!");
        
    return 0;
}