Index: uspace/srv/console/console.c
===================================================================
--- uspace/srv/console/console.c	(revision 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ uspace/srv/console/console.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -328,5 +328,4 @@
 		case KBD_PUSHCHAR:
 			/* got key from keyboard driver */
-			
 			retval = 0;
 			c = IPC_GET_ARG1(call);
Index: uspace/srv/fb/Makefile
===================================================================
--- uspace/srv/fb/Makefile	(revision 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ uspace/srv/fb/Makefile	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -66,6 +66,12 @@
 endif
 ifeq ($(ARCH), mips32)
-	SOURCES += msim.c
+	SOURCES += msim.c \
+                   serial_console.c
 	CFLAGS += -DMSIM_ENABLED -DFB_INVERT_ENDIAN
+endif
+ifeq ($(ARCH), sparc64)
+	SOURCES += sgcn.c \
+	           serial_console.c
+	CFLAGS += -DSGCN_ENABLED
 endif
 
Index: uspace/srv/fb/main.c
===================================================================
--- uspace/srv/fb/main.c	(revision 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ uspace/srv/fb/main.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -39,4 +39,5 @@
 #include "ega.h"
 #include "msim.h"
+#include "sgcn.h"
 #include "main.h"
 
@@ -80,4 +81,10 @@
 	}
 #endif
+#ifdef SGCN_ENABLED
+	if ((!initialized) && (sysinfo_value("fb.kind") == 4)) {
+		if (sgcn_init() == 0)
+			initialized = true;
+	}
+#endif
 
 	if (!initialized)
Index: uspace/srv/fb/msim.c
===================================================================
--- uspace/srv/fb/msim.c	(revision 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ uspace/srv/fb/msim.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -50,4 +50,5 @@
 #include <ddi.h>
 
+#include "serial_console.h"
 #include "msim.h"
 
@@ -65,55 +66,4 @@
 {
 	*virt_addr = c;
-}
-
-static void msim_puts(char *str)
-{
-	while (*str)
-		*virt_addr = *(str++);
-}
-
-static void msim_clrscr(void)
-{
-	msim_puts("\033[2J");
-}
-
-static void msim_goto(const unsigned int row, const unsigned int col)
-{
-	if ((row > HEIGHT) || (col > WIDTH))
-		return;
-	
-	char control[MAX_CONTROL];
-	snprintf(control, MAX_CONTROL, "\033[%u;%uf", row + 1, col + 1);
-	msim_puts(control);
-}
-
-static void msim_set_style(const unsigned int mode)
-{
-	char control[MAX_CONTROL];
-	snprintf(control, MAX_CONTROL, "\033[%um", mode);
-	msim_puts(control);
-}
-
-static void msim_cursor_disable(void)
-{
-	msim_puts("\033[?25l");
-}
-
-static void msim_cursor_enable(void)
-{
-	msim_puts("\033[?25h");
-}
-
-static void msim_scroll(int i)
-{
-	if (i > 0) {
-		msim_goto(HEIGHT - 1, 0);
-		while (i--)
-			msim_puts("\033D");
-	} else if (i < 0) {
-		msim_goto(0, 0);
-		while (i++)
-			msim_puts("\033M");
-	}
 }
 
@@ -142,7 +92,7 @@
 	/* Clear the terminal, set scrolling region
 	   to 0 - 25 lines */
-	msim_clrscr();
-	msim_goto(0, 0);
-	msim_puts("\033[0;25r");
+	serial_clrscr();
+	serial_goto(0, 0);
+	serial_puts("\033[0;25r");
 	
 	while (true) {
@@ -158,5 +108,5 @@
 			newcol = IPC_GET_ARG3(call);
 			if ((lastcol != newcol) || (lastrow != newrow))
-				msim_goto(newrow, newcol);
+				serial_goto(newrow, newcol);
 			lastcol = newcol + 1;
 			lastrow = newrow;
@@ -167,5 +117,5 @@
 			newrow = IPC_GET_ARG1(call);
 			newcol = IPC_GET_ARG2(call);
-			msim_goto(newrow, newcol);
+			serial_goto(newrow, newcol);
 			lastrow = newrow;
 			lastcol = newcol;
@@ -176,5 +126,5 @@
 			continue;
 		case FB_CLEAR:
-			msim_clrscr();
+			serial_clrscr();
 			retval = 0;
 			break;
@@ -183,7 +133,7 @@
 			bgcolor = IPC_GET_ARG2(call);
 			if (fgcolor < bgcolor)
-				msim_set_style(0);
+				serial_set_style(0);
 			else
-				msim_set_style(7);
+				serial_set_style(7);
 			retval = 0;
 			break;
@@ -194,13 +144,13 @@
 				break;
 			}
-			msim_scroll(i);
-			msim_goto(lastrow, lastcol);
+			serial_scroll(i);
+			serial_goto(lastrow, lastcol);
 			retval = 0;
 			break;
 		case FB_CURSOR_VISIBILITY:
 			if(IPC_GET_ARG1(call))
-				msim_cursor_enable();
+				serial_cursor_enable();
 			else
-				msim_cursor_disable();
+				serial_cursor_disable();
 			retval = 0;
 			break;
@@ -219,4 +169,6 @@
 	physmem_map(phys_addr, virt_addr, 1, AS_AREA_READ | AS_AREA_WRITE);
 	
+	serial_console_init(msim_putc, WIDTH, HEIGHT);
+	
 	async_set_client_connection(msim_client_connection);
 	return 0;
Index: uspace/srv/fb/serial_console.c
===================================================================
--- uspace/srv/fb/serial_console.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
+++ uspace/srv/fb/serial_console.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2006 Ondrej Palkovsky
+ * Copyright (c) 2008 Martin Decky
+ * Copyright (c) 2008 Pavel Rimsky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @defgroup serial Serial console
+ * @brief    Serial console services (putc, puts, clear screen, cursor goto,...)
+ * @{
+ */ 
+
+/** @file
+ */
+
+#include <stdio.h>
+
+#include "serial_console.h"
+
+#define MAX_CONTROL 20
+
+static uint32_t width;
+static uint32_t height;
+static putc_function_t putc_function;
+
+void serial_puts(char *str)
+{
+	while (*str)
+		putc_function(*(str++));
+}
+
+void serial_goto(const unsigned int row, const unsigned int col)
+{
+	if ((row > height) || (col > width))
+		return;
+	
+	char control[20];
+	snprintf(control, 20, "\033[%u;%uf", row + 1, col + 1);
+	serial_puts(control);
+}
+
+void serial_clrscr(void)
+{
+	serial_puts("\033[2J");
+}
+
+void serial_scroll(int i)
+{
+	if (i > 0) {
+		serial_goto(height - 1, 0);
+		while (i--)
+			serial_puts("\033D");
+	} else if (i < 0) {
+		serial_goto(0, 0);
+		while (i++)
+			serial_puts("\033M");
+	}
+}
+
+void serial_set_style(const unsigned int mode)
+{
+	char control[MAX_CONTROL];
+	snprintf(control, MAX_CONTROL, "\033[%um", mode);
+	serial_puts(control);
+}
+
+void serial_cursor_disable(void)
+{
+	serial_puts("\033[?25l");
+}
+
+void serial_cursor_enable(void)
+{
+	serial_puts("\033[?25h");
+}
+
+void serial_console_init(putc_function_t putc_fn, uint32_t w, uint32_t h)
+{
+	width = w;
+	height = h;
+	putc_function = putc_fn;
+}
+
+/** 
+ * @}
+ */
Index: uspace/srv/fb/serial_console.h
===================================================================
--- uspace/srv/fb/serial_console.h	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
+++ uspace/srv/fb/serial_console.h	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2008 Pavel Rimsky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @defgroup serial Serial console
+ * @brief    Serial console services (putc, puts, clear screen, cursor goto,...)
+ * @{
+ */ 
+
+/** @file
+ */
+
+#ifndef FB_SERIAL_CONSOLE_H_
+#define FB_SERIAL_CONSOLE_H_
+
+typedef void (*putc_function_t)(char);
+
+void serial_puts(char *str);
+void serial_goto(const unsigned int row, const unsigned int col);
+void serial_clrscr(void);
+void serial_scroll(int i);
+void serial_set_style(const unsigned int mode);
+void serial_cursor_disable(void);
+void serial_cursor_enable(void);
+void serial_console_init(putc_function_t putc_fn, uint32_t w, uint32_t h);
+
+#endif
Index: uspace/srv/fb/sgcn.c
===================================================================
--- uspace/srv/fb/sgcn.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
+++ uspace/srv/fb/sgcn.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2006 Ondrej Palkovsky
+ * Copyright (c) 2008 Martin Decky
+ * Copyright (c) 2008 Pavel Rimsky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @defgroup sgcnfb SGCN
+ * @brief	userland driver of the Serengeti console output
+ * @{
+ */ 
+/** @file
+ */
+
+#include <async.h>
+#include <ipc/ipc.h>
+#include <ipc/fb.h>
+#include <sysinfo.h>
+#include <as.h>
+#include <errno.h>
+#include <stdio.h>
+#include <ddi.h>
+
+#include "serial_console.h"
+#include "sgcn.h"
+
+#define WIDTH 80
+#define HEIGHT 24
+
+/**
+ * Virtual address mapped to SRAM.
+ */
+static uintptr_t sram_virt_addr;
+
+/**
+ * SGCN buffer offset within SGCN.
+ */
+static uintptr_t sram_buffer_offset;
+
+/* Allow only 1 connection */
+static int client_connected = 0;
+
+/**
+ * SGCN buffer header. It is placed at the very beginning of the SGCN
+ * buffer. 
+ */
+typedef struct {
+	/** hard-wired to "CON" */
+	char magic[4];
+	
+	/** we don't need this */
+	char unused[24];
+
+	/** offset within the SGCN buffer of the output buffer start */
+	uint32_t out_begin;
+	
+	/** offset within the SGCN buffer of the output buffer end */
+	uint32_t out_end;
+	
+	/** offset within the SGCN buffer of the output buffer read pointer */
+	uint32_t out_rdptr;
+	
+	/** offset within the SGCN buffer of the output buffer write pointer */
+	uint32_t out_wrptr;
+} __attribute__ ((packed)) sgcn_buffer_header_t;
+
+
+/*
+ * Returns a pointer to the object of a given type which is placed at the given
+ * offset from the console buffer beginning.
+ */
+#define SGCN_BUFFER(type, offset) \
+		((type *) (sram_virt_addr + sram_buffer_offset + (offset)))
+
+/** Returns a pointer to the console buffer header. */
+#define SGCN_BUFFER_HEADER	(SGCN_BUFFER(sgcn_buffer_header_t, 0))
+
+/**
+ * Pushes the character to the SGCN serial.
+ * @param c	character to be pushed
+ */
+static void sgcn_putc(char c)
+{
+	uint32_t begin = SGCN_BUFFER_HEADER->out_begin;
+	uint32_t end = SGCN_BUFFER_HEADER->out_end;
+	uint32_t size = end - begin;
+	
+	/* we need pointers to volatile variables */
+	volatile char *buf_ptr = (volatile char *)
+		SGCN_BUFFER(char, SGCN_BUFFER_HEADER->out_wrptr);
+	volatile uint32_t *out_wrptr_ptr = &(SGCN_BUFFER_HEADER->out_wrptr);
+	volatile uint32_t *out_rdptr_ptr = &(SGCN_BUFFER_HEADER->out_rdptr);
+
+	uint32_t new_wrptr = (((*out_wrptr_ptr) - begin + 1) % size) + begin;
+	while (*out_rdptr_ptr == new_wrptr)
+		;
+	*buf_ptr = c;
+	*out_wrptr_ptr = new_wrptr;
+}
+
+/**
+ * Main function of the thread serving client connections.
+ */
+static void sgcn_client_connection(ipc_callid_t iid, ipc_call_t *icall)
+{
+	int retval;
+	ipc_callid_t callid;
+	ipc_call_t call;
+	char c;
+	int lastcol = 0;
+	int lastrow = 0;
+	int newcol;
+	int newrow;
+	int fgcolor;
+	int bgcolor;
+	int i;
+	
+	if (client_connected) {
+		ipc_answer_0(iid, ELIMIT);
+		return;
+	}
+	
+	client_connected = 1;
+	ipc_answer_0(iid, EOK);
+	
+	/* Clear the terminal, set scrolling region
+	   to 0 - 24 lines */
+	serial_clrscr();
+	serial_goto(0, 0);
+	serial_puts("\033[0;24r");
+	
+	while (true) {
+		callid = async_get_call(&call);
+		switch (IPC_GET_METHOD(call)) {
+		case IPC_M_PHONE_HUNGUP:
+			client_connected = 0;
+			ipc_answer_0(callid, EOK);
+			return;
+		case FB_PUTCHAR:
+			c = IPC_GET_ARG1(call);
+			newrow = IPC_GET_ARG2(call);
+			newcol = IPC_GET_ARG3(call);
+			if ((lastcol != newcol) || (lastrow != newrow))
+				serial_goto(newrow, newcol);
+			lastcol = newcol + 1;
+			lastrow = newrow;
+			sgcn_putc(c);
+			retval = 0;
+			break;
+		case FB_CURSOR_GOTO:
+			newrow = IPC_GET_ARG1(call);
+			newcol = IPC_GET_ARG2(call);
+			serial_goto(newrow, newcol);
+			lastrow = newrow;
+			lastcol = newcol;
+			retval = 0;
+			break;
+		case FB_GET_CSIZE:
+			ipc_answer_2(callid, EOK, HEIGHT, WIDTH);
+			continue;
+		case FB_CLEAR:
+			serial_clrscr();
+			retval = 0;
+			break;
+		case FB_SET_STYLE:
+			fgcolor = IPC_GET_ARG1(call);
+			bgcolor = IPC_GET_ARG2(call);
+			if (fgcolor < bgcolor)
+				serial_set_style(0);
+			else
+				serial_set_style(7);
+			retval = 0;
+			break;
+		case FB_SCROLL:
+			i = IPC_GET_ARG1(call);
+			if ((i > HEIGHT) || (i < -HEIGHT)) {
+				retval = EINVAL;
+				break;
+			}
+			serial_scroll(i);
+			serial_goto(lastrow, lastcol);
+			retval = 0;
+			break;
+		case FB_CURSOR_VISIBILITY:
+			if(IPC_GET_ARG1(call))
+				serial_cursor_enable();
+			else
+				serial_cursor_disable();
+			retval = 0;
+			break;
+		default:
+			retval = ENOENT;
+		}
+		ipc_answer_0(callid, retval);
+	}
+}
+
+/**
+ * Initializes the SGCN serial driver.
+ */
+int sgcn_init(void)
+{
+	sram_virt_addr = (uintptr_t) as_get_mappable_page(
+		sysinfo_value("sram.area.size"));
+	int result = physmem_map(
+		(void *) sysinfo_value("sram.address.physical"),
+		(void *) sram_virt_addr,
+		sysinfo_value("sram.area.size") / PAGE_SIZE,
+		AS_AREA_READ | AS_AREA_WRITE
+		);
+	if (result != 0) {
+		printf("SGCN: uspace driver couldn't map physical memory: %d\n",
+			result);
+	}
+	
+	serial_console_init(sgcn_putc, WIDTH, HEIGHT);
+	
+	sram_buffer_offset = sysinfo_value("sram.buffer.offset");
+	
+	async_set_client_connection(sgcn_client_connection);
+	return 0;
+}
+
+/** 
+ * @}
+ */
+ 
Index: uspace/srv/fb/sgcn.h
===================================================================
--- uspace/srv/fb/sgcn.h	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
+++ uspace/srv/fb/sgcn.h	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2008 Pavel Rimsky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @defgroup sgcnfb SGCN
+ * @brief	userland driver of the Serengeti console output
+ * @{
+ */
+ 
+/** @file
+ */
+
+#ifndef FB_SGCN_H_
+#define FB_SGCN_H_
+
+int sgcn_init(void);
+
+#endif
+
+/** 
+ * @}
+ */
Index: uspace/srv/kbd/Makefile
===================================================================
--- uspace/srv/kbd/Makefile	(revision 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ uspace/srv/kbd/Makefile	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -79,7 +79,9 @@
 ifeq ($(ARCH), sparc64)
 	ARCH_SOURCES += \
-		arch/$(ARCH)/src/scanc.c
+		arch/$(ARCH)/src/scanc.c \
+		arch/$(ARCH)/src/sgcn.c
 	GENARCH_SOURCES = \
-		genarch/src/kbd.c
+		genarch/src/kbd.c \
+		genarch/src/nofb.c
 endif
 ifeq ($(ARCH), arm32)
@@ -87,5 +89,8 @@
 		arch/$(ARCH)/src/kbd_gxemul.c
 endif
-
+ifeq ($(ARCH), mips32)
+	GENARCH_SOURCES += \
+	    genarch/src/nofb.c
+endif
 
 GENERIC_OBJECTS := $(addsuffix .o,$(basename $(GENERIC_SOURCES)))
Index: uspace/srv/kbd/arch/mips32/src/kbd.c
===================================================================
--- uspace/srv/kbd/arch/mips32/src/kbd.c	(revision 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ uspace/srv/kbd/arch/mips32/src/kbd.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -35,4 +35,5 @@
  */
 #include <arch/kbd.h>
+#include <genarch/nofb.h>
 #include <ipc/ipc.h>
 #include <sysinfo.h>
@@ -100,144 +101,4 @@
 */
 
-static int kbd_arch_process_no_fb(keybuffer_t *keybuffer, int scan_code)
-{
-
-	static unsigned long buf = 0;
-	static int count = 0;	
-
-	/* Please preserve this code (it can be used to determine scancodes)
-	
-	keybuffer_push(keybuffer, to_hex((scan_code>>4)&0xf));
-	keybuffer_push(keybuffer, to_hex(scan_code&0xf));
-	keybuffer_push(keybuffer, ' ');
-	keybuffer_push(keybuffer, ' ');
-	
-	return 1;
-	*/
-	
-	if(scan_code == 0x7e) {
-		switch (buf) {
-		case MSIM_KEY_F5:
-			keybuffer_push(keybuffer,FUNCTION_KEYS | 5);
-			buf = count = 0;
-			return 1;
-		case MSIM_KEY_F6:
-			keybuffer_push(keybuffer,FUNCTION_KEYS | 6);
-			buf = count = 0;
-			return 1;
-		case MSIM_KEY_F7:
-			keybuffer_push(keybuffer,FUNCTION_KEYS | 7);
-			buf = count = 0;
-			return 1;
-		case MSIM_KEY_F8:
-			keybuffer_push(keybuffer,FUNCTION_KEYS | 8);
-			buf = count = 0;
-			return 1;
-		case MSIM_KEY_F9:
-			keybuffer_push(keybuffer,FUNCTION_KEYS | 9);
-			buf = count = 0;
-			return 1;
-		case MSIM_KEY_F10:
-			keybuffer_push(keybuffer,FUNCTION_KEYS | 10);
-			buf = count = 0;
-			return 1;
-		case MSIM_KEY_F11:
-			keybuffer_push(keybuffer,FUNCTION_KEYS | 11);
-			buf = count = 0;
-			return 1;
-		case MSIM_KEY_F12:
-			keybuffer_push(keybuffer,FUNCTION_KEYS | 12);
-			buf = count = 0;
-			return 1;
-		default:
-			keybuffer_push(keybuffer, buf & 0xff);
-			keybuffer_push(keybuffer, (buf >> 8) &0xff);
-			keybuffer_push(keybuffer, (buf >> 16) &0xff);
-			keybuffer_push(keybuffer, (buf >> 24) &0xff);
-			keybuffer_push(keybuffer, scan_code);
-			buf = count = 0;
-			return 1;
-		}
-	}
-
-	buf |= ((unsigned long) scan_code)<<(8*(count++));
-	
-	if((buf & 0xff) != (MSIM_KEY_F1 & 0xff)) {
-		keybuffer_push(keybuffer, buf);
-		buf = count = 0;
-		return 1;
-	}
-
-	if (count <= 1) 
-		return 1;
-
-	if ((buf & 0xffff) != (MSIM_KEY_F1 & 0xffff) 
-		&& (buf & 0xffff) != (MSIM_KEY_F5 & 0xffff) ) {
-
-		keybuffer_push(keybuffer, buf & 0xff);
-		keybuffer_push(keybuffer, (buf >> 8) &0xff);
-		buf = count = 0;
-		return 1;
-	}
-
-	if (count <= 2) 
-		return 1;
-
-	switch (buf) {
-	case MSIM_KEY_F1:
-		keybuffer_push(keybuffer,FUNCTION_KEYS | 1);
-		buf = count = 0;
-		return 1;
-	case MSIM_KEY_F2:
-		keybuffer_push(keybuffer,FUNCTION_KEYS | 2);
-		buf = count = 0;
-		return 1;
-	case MSIM_KEY_F3:
-		keybuffer_push(keybuffer,FUNCTION_KEYS | 3);
-		buf = count = 0;
-		return 1;
-	case MSIM_KEY_F4:
-		keybuffer_push(keybuffer,FUNCTION_KEYS | 4);
-		buf = count = 0;
-		return 1;
-	}
-
-
-	if((buf & 0xffffff) != (MSIM_KEY_F5 & 0xffffff)
-		&& (buf & 0xffffff) != (MSIM_KEY_F9 & 0xffffff)) {
-
-		keybuffer_push(keybuffer, buf & 0xff);
-		keybuffer_push(keybuffer, (buf >> 8) & 0xff);
-		keybuffer_push(keybuffer, (buf >> 16) & 0xff);
-		buf=count=0;
-		return 1;
-	}
-
-	if (count <= 3)
-		return 1;
-	
-	switch (buf) {
-	case MSIM_KEY_F5:
-	case MSIM_KEY_F6:
-	case MSIM_KEY_F7:
-	case MSIM_KEY_F8:
-	case MSIM_KEY_F9:
-	case MSIM_KEY_F10:
-	case MSIM_KEY_F11:
-	case MSIM_KEY_F12:
-		return 1;
-	default:
-		keybuffer_push(keybuffer, buf & 0xff);
-		keybuffer_push(keybuffer, (buf >> 8) &0xff);
-		keybuffer_push(keybuffer, (buf >> 16) &0xff);
-		keybuffer_push(keybuffer, (buf >> 24) &0xff);
-		buf = count = 0;
-		return 1;
-	}
-	return 1;
-}
-
-
-
 static int kbd_arch_process_fb(keybuffer_t *keybuffer, int scan_code)
 {
@@ -372,5 +233,5 @@
 		return kbd_arch_process_fb(keybuffer, scan_code);
 
-	return kbd_arch_process_no_fb(keybuffer, scan_code);
+	return kbd_process_no_fb(keybuffer, scan_code);
 }
 /** @}
Index: uspace/srv/kbd/arch/sparc64/include/sgcn.h
===================================================================
--- uspace/srv/kbd/arch/sparc64/include/sgcn.h	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
+++ uspace/srv/kbd/arch/sparc64/include/sgcn.h	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2008 Pavel Rimsky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup kbdsparc64 sparc64
+ * @brief	Serengeti-specific parts of uspace keyboard handler.
+ * @ingroup  kbd
+ * @{
+ */ 
+/** @file
+ */
+
+#ifndef KBD_sparc64_SGCN_H_
+#define KBD_sparc64_SGCN_H_
+
+void sgcn_init(void);
+void sgcn_key_pressed(void);
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/kbd/arch/sparc64/src/kbd.c
===================================================================
--- uspace/srv/kbd/arch/sparc64/src/kbd.c	(revision 0258e67a9860351d5c8ebbc0ba42775dc5966c35)
+++ uspace/srv/kbd/arch/sparc64/src/kbd.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -36,4 +36,5 @@
 
 #include <arch/kbd.h>
+#include <arch/sgcn.h>
 #include <ipc/ipc.h>
 #include <sysinfo.h>
@@ -79,4 +80,5 @@
 #define KBD_Z8530	1
 #define KBD_NS16550	2
+#define KBD_SGCN	3
 
 int kbd_arch_init(void)
@@ -92,4 +94,7 @@
 		ipc_register_irq(sysinfo_value("kbd.inr"), sysinfo_value("kbd.devno"), 0, &ns16550_kbd);
 		break;
+	case KBD_SGCN:
+		sgcn_init();
+		break;
 	default:
 		break;
@@ -101,4 +106,9 @@
 int kbd_arch_process(keybuffer_t *keybuffer, ipc_call_t *call)
 {
+	if (sysinfo_value("kbd.type") == KBD_SGCN) {
+		sgcn_key_pressed();
+		return 1;
+	}
+	
 	int scan_code = IPC_GET_ARG1(*call);
 
Index: uspace/srv/kbd/arch/sparc64/src/sgcn.c
===================================================================
--- uspace/srv/kbd/arch/sparc64/src/sgcn.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
+++ uspace/srv/kbd/arch/sparc64/src/sgcn.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2008 Pavel Rimsky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup kbdsparc64 sparc64
+ * @brief	Serengeti-specific parts of uspace keyboard handler.
+ * @ingroup  kbd
+ * @{
+ */ 
+/** @file
+ */
+
+#include <arch/sgcn.h>
+#include <as.h>
+#include <ddi.h>
+#include <ipc/ipc.h>
+#include <kbd.h>
+#include <genarch/nofb.h>
+#include <genarch/kbd.h>
+#include <sysinfo.h>
+#include <stdio.h>
+#include <futex.h>
+
+/**
+ * SGCN buffer header. It is placed at the very beginning of the SGCN
+ * buffer. 
+ */
+typedef struct {
+	/** hard-wired to "CON" */
+	char magic[4];
+	
+	/** we don't need this */
+	char unused[8];
+	
+	/** offset within the SGCN buffer of the input buffer start */
+	uint32_t in_begin;
+	
+	/** offset within the SGCN buffer of the input buffer end */
+	uint32_t in_end;
+	
+	/** offset within the SGCN buffer of the input buffer read pointer */
+	uint32_t in_rdptr;
+	
+	/** offset within the SGCN buffer of the input buffer write pointer */
+	uint32_t in_wrptr;
+} __attribute__ ((packed)) sgcn_buffer_header_t;
+
+/*
+ * Returns a pointer to the object of a given type which is placed at the given
+ * offset from the console buffer beginning.
+ */
+#define SGCN_BUFFER(type, offset) \
+		((type *) (sram_virt_addr + sram_buffer_offset + (offset)))
+
+/** Returns a pointer to the console buffer header. */
+#define SGCN_BUFFER_HEADER	(SGCN_BUFFER(sgcn_buffer_header_t, 0))
+
+extern keybuffer_t keybuffer;
+
+/**
+ * Virtual address mapped to SRAM.
+ */
+static uintptr_t sram_virt_addr;
+
+/**
+ * SGCN buffer offset within SGCN.
+ */
+static uintptr_t sram_buffer_offset;
+
+/**
+ * Initializes the SGCN driver.
+ * Maps the physical memory (SRAM) and registers the interrupt. 
+ */
+void sgcn_init(void)
+{
+	sram_virt_addr = (uintptr_t) as_get_mappable_page(
+		sysinfo_value("sram.area.size"));
+	int result = physmem_map(
+		(void *) sysinfo_value("sram.address.physical"),
+		(void *) sram_virt_addr,
+		sysinfo_value("sram.area.size") / PAGE_SIZE,
+		AS_AREA_READ | AS_AREA_WRITE
+		);
+	if (result != 0) {
+		printf("SGCN: uspace driver could not map physical memory.");
+	}
+	
+	sram_buffer_offset = sysinfo_value("sram.buffer.offset");
+	ipc_register_irq(sysinfo_value("kbd.inr"), sysinfo_value("kbd.devno"),
+		0, (void *) 0);
+}
+
+/**
+ * Handler of the "key pressed" event. Reads codes of all the pressed keys from
+ * the buffer. 
+ */
+void sgcn_key_pressed(void)
+{
+	char c;
+	
+	uint32_t begin = SGCN_BUFFER_HEADER->in_begin;
+	uint32_t end = SGCN_BUFFER_HEADER->in_end;
+	uint32_t size = end - begin;
+	
+	volatile char *buf_ptr = (volatile char *)
+		SGCN_BUFFER(char, SGCN_BUFFER_HEADER->in_rdptr);
+	volatile uint32_t *in_wrptr_ptr = &(SGCN_BUFFER_HEADER->in_wrptr);
+	volatile uint32_t *in_rdptr_ptr = &(SGCN_BUFFER_HEADER->in_rdptr);
+	
+	while (*in_rdptr_ptr != *in_wrptr_ptr) {
+		c = *buf_ptr;
+		*in_rdptr_ptr = (((*in_rdptr_ptr) - begin + 1) % size) + begin;
+		buf_ptr = (volatile char *)
+			SGCN_BUFFER(char, SGCN_BUFFER_HEADER->in_rdptr);
+		if (c == '\r') {
+                        c = '\n';
+                }
+		kbd_process_no_fb(&keybuffer, c);
+	}
+}
+
+/** @}
+ */
Index: uspace/srv/kbd/genarch/include/nofb.h
===================================================================
--- uspace/srv/kbd/genarch/include/nofb.h	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
+++ uspace/srv/kbd/genarch/include/nofb.h	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2008 Pavel Rimsky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup kbd
+ * @{
+ */ 
+/** @file
+ */
+
+#ifndef KBD_genarch_NOFB_H_
+#define KBD_genarch_NOFB_H_
+
+
+#include <key_buffer.h>
+#include <genarch/scanc.h>
+
+extern int kbd_process_no_fb(keybuffer_t *keybuffer, int scan_code);
+
+#endif
+
+/**
+ * @}
+ */ 
Index: uspace/srv/kbd/genarch/src/nofb.c
===================================================================
--- uspace/srv/kbd/genarch/src/nofb.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
+++ uspace/srv/kbd/genarch/src/nofb.c	(revision 965dc18d04fb8a15431d34485959f4aa8e6ec4b5)
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2006 Josef Cejka
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup kbdmips32 mips32
+ * @brief	HelenOS mips32 arch dependent parts of uspace keyboard handler.
+ * @ingroup  kbd
+ * @{
+ */ 
+ 
+/** @file
+ */
+
+#include <genarch/nofb.h>
+#include <stdio.h> // DELETE!!!
+
+#define KEY_F1 0x504f1bL
+#define KEY_F2 0x514f1bL
+#define KEY_F3 0x524f1bL
+#define KEY_F4 0x534f1bL
+#define KEY_F5 0x35315b1bL
+#define KEY_F6 0x37315b1bL
+#define KEY_F7 0x38315b1bL
+#define KEY_F8 0x39315b1bL
+#define KEY_F9 0x30325b1bL
+#define KEY_F10 0x31325b1bL
+#define KEY_F11 0x33325b1bL
+#define KEY_F12 0x34325b1bL
+
+/**
+ * Processes the key pressed - pushes the key code into the key buffer.
+ * Used in MSIM and Serengeti, i.e. non-framebuffer consoles.
+ */
+int kbd_process_no_fb(keybuffer_t *keybuffer, int scan_code)
+{
+	static unsigned long buf = 0;
+	static int count = 0;	
+	
+	if(scan_code == 0x7e) {
+		switch (buf) {
+		case KEY_F5:
+			keybuffer_push(keybuffer,FUNCTION_KEYS | 5);
+			buf = count = 0;
+			return 1;
+		case KEY_F6:
+			keybuffer_push(keybuffer,FUNCTION_KEYS | 6);
+			buf = count = 0;
+			return 1;
+		case KEY_F7:
+			keybuffer_push(keybuffer,FUNCTION_KEYS | 7);
+			buf = count = 0;
+			return 1;
+		case KEY_F8:
+			keybuffer_push(keybuffer,FUNCTION_KEYS | 8);
+			buf = count = 0;
+			return 1;
+		case KEY_F9:
+			keybuffer_push(keybuffer,FUNCTION_KEYS | 9);
+			buf = count = 0;
+			return 1;
+		case KEY_F10:
+			keybuffer_push(keybuffer,FUNCTION_KEYS | 10);
+			buf = count = 0;
+			return 1;
+		case KEY_F11:
+			keybuffer_push(keybuffer,FUNCTION_KEYS | 11);
+			buf = count = 0;
+			return 1;
+		case KEY_F12:
+			keybuffer_push(keybuffer,FUNCTION_KEYS | 12);
+			buf = count = 0;
+			return 1;
+		default:
+			keybuffer_push(keybuffer, buf & 0xff);
+			keybuffer_push(keybuffer, (buf >> 8) &0xff);
+			keybuffer_push(keybuffer, (buf >> 16) &0xff);
+			keybuffer_push(keybuffer, (buf >> 24) &0xff);
+			keybuffer_push(keybuffer, scan_code);
+			buf = count = 0;
+			return 1;
+		}
+	}
+
+	buf |= ((unsigned long) scan_code)<<(8*(count++));
+	
+	if((buf & 0xff) != (KEY_F1 & 0xff)) {
+		keybuffer_push(keybuffer, buf);
+		buf = count = 0;
+		return 1;
+	}
+
+	if (count <= 1) 
+		return 1;
+
+	if ((buf & 0xffff) != (KEY_F1 & 0xffff) 
+		&& (buf & 0xffff) != (KEY_F5 & 0xffff) ) {
+
+		keybuffer_push(keybuffer, buf & 0xff);
+		keybuffer_push(keybuffer, (buf >> 8) &0xff);
+		buf = count = 0;
+		return 1;
+	}
+
+	if (count <= 2) 
+		return 1;
+
+	switch (buf) {
+	case KEY_F1:
+		keybuffer_push(keybuffer,FUNCTION_KEYS | 1);
+		buf = count = 0;
+		return 1;
+	case KEY_F2:
+		keybuffer_push(keybuffer,FUNCTION_KEYS | 2);
+		buf = count = 0;
+		return 1;
+	case KEY_F3:
+		keybuffer_push(keybuffer,FUNCTION_KEYS | 3);
+		buf = count = 0;
+		return 1;
+	case KEY_F4:
+		keybuffer_push(keybuffer,FUNCTION_KEYS | 4);
+		buf = count = 0;
+		return 1;
+	}
+
+
+	if((buf & 0xffffff) != (KEY_F5 & 0xffffff)
+		&& (buf & 0xffffff) != (KEY_F9 & 0xffffff)) {
+
+		keybuffer_push(keybuffer, buf & 0xff);
+		keybuffer_push(keybuffer, (buf >> 8) & 0xff);
+		keybuffer_push(keybuffer, (buf >> 16) & 0xff);
+		buf=count=0;
+		return 1;
+	}
+
+	if (count <= 3)
+		return 1;
+	
+	switch (buf) {
+	case KEY_F5:
+	case KEY_F6:
+	case KEY_F7:
+	case KEY_F8:
+	case KEY_F9:
+	case KEY_F10:
+	case KEY_F11:
+	case KEY_F12:
+		return 1;
+	default:
+		keybuffer_push(keybuffer, buf & 0xff);
+		keybuffer_push(keybuffer, (buf >> 8) &0xff);
+		keybuffer_push(keybuffer, (buf >> 16) &0xff);
+		keybuffer_push(keybuffer, (buf >> 24) &0xff);
+		buf = count = 0;
+		return 1;
+	}
+
+	return 1;
+}
+
+/** @}
+ */
