Index: Makefile
===================================================================
RCS file: /cvsroot/free60/xell/Makefile,v
retrieving revision 1.7
diff -u -p -r1.7 Makefile
--- Makefile	22 Jan 2008 23:20:41 -0000	1.7
+++ Makefile	2 Feb 2008 20:24:39 -0000
@@ -32,9 +32,9 @@ LWIP_OBJS = ./lwip/core/tcp_in.o \
 
 OBJS = startup2.o main.o string.o vsprintf.o ctype.o time.o  \
 	cache.o  $(LWIP_OBJS)  network.o tftp.o httpd/httpd.o httpd/vfs.o dtc.o \
-	cdrom.o xenos.o font_8x16.o
+	cdrom.o xenos.o font_8x16.o smc.o menu.o
 
-BUILD = xell-serial xell-readcd
+BUILD = xell-serial xell-readcd
 
 TARGETS = $(foreach name,$(BUILD),$(addprefix $(name).,bin elf elf32))
 
Index: cdrom.c
===================================================================
RCS file: /cvsroot/free60/xell/cdrom.c,v
retrieving revision 1.1
diff -u -p -r1.1 cdrom.c
--- cdrom.c	19 Mar 2007 20:10:03 -0000	1.1
+++ cdrom.c	2 Feb 2008 20:24:40 -0000
@@ -292,26 +292,25 @@ int read_directory(int sector, int len, 
 
 extern int execute_elf_at(void *dst, int len, const char *args);
 
-void try_boot_cdrom(void)
+int iso9660_load_file(char *filename, void* addr)
 {
-	int sector, size, kernel_sector, kernel_size;
+	int sector, size, file_sector, file_size;
+	char fnamebuf[258];
 	struct pvd_s *pvd = 0;
 	
-	set_modeb();
-	
 	printf(" * reading CD/DVD...\n");
 	
 	if (read_sector(sector_buffer, 16, 1))
 	{
 		printf(" ! failed to read PVD\n");
-		return;
+		return -1;
 	}
 
 	pvd = (void*)sector_buffer;
 	if (memcmp(sector_buffer, "\1CD001\1", 8))
 	{
 		printf(" ! no iso9660!\n");
-		return;
+		return -1;
 	}
 	
 	printf("root_direntry offset: %d\n", (int)(&((struct pvd_s *)0)->root_direntry));
@@ -321,46 +320,62 @@ void try_boot_cdrom(void)
 	if (!sector)
 	{
 		printf(" ! root direntry not found\n");
-		return;
+		return -1;
 	}
 	
 	printf(" ! root at lba=%02x, size=%d\n", sector, size);
-	if (
-		read_directory(sector, size, "vmlinux;1", &kernel_sector, &kernel_size) && 
-		read_directory(sector, size, "vmlinux.;1", &kernel_sector, &kernel_size))
+
+	strcpy(fnamebuf, filename);
+	strcat(fnamebuf, ";1");
+	if (read_directory(sector, size, fnamebuf, &file_sector, &file_size))
 	{
-		printf(" ! xenon kernel image not found\n");
-		return;
+		strcpy(fnamebuf, filename);
+		strcat(fnamebuf, ".;1");
+		if (read_directory(sector, size, fnamebuf, &file_sector, &file_size))
+		{
+			printf(" ! '%s' not found\n", filename);
+			return -1;
+		}
 	}
 	
-	printf(" ! found kernel at lba=%d, size=%d\n", kernel_sector, kernel_size);
+	printf(" ! found '%s' at lba=%d, size=%d\n", fnamebuf, file_sector, file_size);
 	
-	printf(" ! loading kernel...\n");
+	printf(" ! loading file...\n");
 
-	void *addr = (void*)LOADER_RAW;
-	
-	int s = kernel_size;
+	int s = file_size;
 	
 	while (1)
 	{
-		printf("\r * %08x -> %p... ", kernel_sector, addr);
+		printf("\r * %08x -> %p... ", file_sector, addr);
 		
-		int num = (kernel_size + 0x7ff) / 0x800;
+		int num = (s + 0x7ff) / 0x800;
 		if (num > 64)
 			num = 64;
 		
-		if (read_sector(addr, kernel_sector, num))
+		if (read_sector(addr, file_sector, num))
 		{
 			printf("\n ! read sector failed!\n");
 			break;
 		}
 		
-		addr += num * 0x800; kernel_sector+=num; kernel_size -= num * 0x800;
-		if (kernel_size <= 0)
+		addr += num * 0x800; file_sector+=num; s -= num * 0x800;
+		if (s <= 0)
 		{
-			printf("\n * done! executing kernel!\n");
-			execute_elf_at((void*)LOADER_RAW, s, "");
-			return;
+			printf("\n * done!\n");
+			return file_size;
 		}
 	}
+	return -1;
+}
+
+void try_boot_cdrom(char *filename)
+{
+	int size;
+	set_modeb();
+	
+	if (!filename)
+		filename = "vmlinux";
+	if ((size = iso9660_load_file(filename, (void*)LOADER_RAW)) >= 0) {
+		execute_elf_at((void*)LOADER_RAW, size, "");
+	}
 }
Index: main.c
===================================================================
RCS file: /cvsroot/free60/xell/main.c,v
retrieving revision 1.5
diff -u -p -r1.5 main.c
--- main.c	24 Jan 2008 22:04:43 -0000	1.5
+++ main.c	2 Feb 2008 20:24:41 -0000
@@ -7,9 +7,15 @@
 #include <time.h>
 #include "version.h"
 
-extern void try_boot_cdrom(void);
+#define MENU
+/* cdrom.c: */
+extern int iso9660_load_file(char *filename, void* addr);
+extern void try_boot_cdrom(char *);
+/* xenos.c: */
 extern void xenos_init();
 extern void xenos_putch(const char c);
+/* menu.c: */
+extern void main_menu();
 
 #include "elf_abi.h"
 
@@ -19,7 +25,7 @@ static void putch(unsigned char c)
 	*(volatile uint32_t*)0x80000200ea001014 = (c << 24) & 0xFF000000;
 }
 
-static int kbhit(void)
+int kbhit(void)
 {
 	uint32_t status;
 	
@@ -172,7 +178,9 @@ int start(int pir, unsigned long hrmor, 
 {
 	secondary_hold_addr = 0;
 
+#ifndef TARGET_xell
 	int exc[]={0x100, 0x200, 0x300, 0x380, 0x400, 0x480, 0x500, 0x600, 0x700, 0x800, 0x900, 0x980, 0xC00, 0xD00, 0xF00, 0xF20, 0x1300, 0x1600, 0x1700, 0x1800};
+#endif
 
 	int i;
 
@@ -182,6 +190,9 @@ int start(int pir, unsigned long hrmor, 
 
 	printf("\nXeLL - Xenon linux loader " LONGVERSION "\n");
 
+#ifdef TARGET_xell
+	printf(" * WARNING: Bootstrapped XeLL not catching CPUs...\n");
+#else
 	printf(" * Attempting to catch all CPUs...\n");
 
 	for (i=0; i<sizeof(exc)/sizeof(*exc); ++i)
@@ -210,6 +221,7 @@ int start(int pir, unsigned long hrmor, 
 	}
 	
 	printf(" * success.\n");
+#endif
 
 			/* re-reset interrupt controllers. especially, remove their pending IPI IRQs. */
 	for (i=1; i<6; ++i)
@@ -236,11 +248,18 @@ int start(int pir, unsigned long hrmor, 
 	if (get_online_processors() != 0x3f)
 		printf("WARNING: not all processors could be woken up.\n");
 
+#ifdef MENU
+	print_network_config();
+	main_menu();
+#endif
 	printf(" * try booting from CDROM\n");
-	try_boot_cdrom();
+	try_boot_cdrom("vmlinux");
 	printf(" * try booting tftp\n");
 	boot_tftp("10.0.0.1", "/tftpboot/xenon");
+	boot_tftp("10.0.0.1", "/tftpboot/vmlinux-2.6.21.sda2.sata.fbfix");
+	printf(" * booting failed\n");
 	printf(" * HTTP listen\n");
+	print_network_config();
 	while (1) network_poll();
 
 	return 0;
Index: network.c
===================================================================
RCS file: /cvsroot/free60/xell/network.c,v
retrieving revision 1.1
diff -u -p -r1.1 network.c
--- network.c	19 Mar 2007 20:10:04 -0000	1.1
+++ network.c	2 Feb 2008 20:24:41 -0000
@@ -12,8 +12,8 @@
 #include "lwip/tcp.h"
 #include "netif/etharp.h"
 
-static struct netif netif;
-static struct ip_addr ipaddr, netmask, gw;
+struct netif netif;
+struct ip_addr ipaddr, netmask, gw;
 static tb_t now, start;
 
 extern void enet_poll(struct netif *netif);
@@ -59,6 +59,13 @@ void network_init()
 	printf("ok!\n");
 }
 
+void print_network_config()
+{
+#define NTOA(ip) (int)((ip.addr>>24)&0xff), (int)((ip.addr>>16)&0xff), (int)((ip.addr>>8)&0xff), (int)(ip.addr&0xff)
+	printf(" * XeLL network config: %d.%d.%d.%d / %d.%d.%d.%d\n",
+		NTOA(ipaddr), NTOA(netmask));
+}
+
 void network_poll()
 {
 	mftb(&now);
Index: string.c
===================================================================
RCS file: /cvsroot/free60/xell/string.c,v
retrieving revision 1.1
diff -u -p -r1.1 string.c
--- string.c	19 Mar 2007 20:10:04 -0000	1.1
+++ string.c	2 Feb 2008 20:24:41 -0000
@@ -53,7 +53,6 @@ int strnicmp(const char *s1, const char 
 }
 #endif
 
-char * ___strtok;
 #endif
 
 #ifndef __HAVE_ARCH_STRCPY
@@ -249,8 +248,9 @@ size_t strnlen(const char * s, size_t co
 }
 #endif
 
-#if 0
+#if 1
 #ifndef __HAVE_ARCH_STRSPN
+char * ___strtok;
 /**
  * strspn - Calculate the length of the initial substring of @s which only
  * 	contain letters in @accept
Index: vsprintf.c
===================================================================
RCS file: /cvsroot/free60/xell/vsprintf.c,v
retrieving revision 1.1
diff -u -p -r1.1 vsprintf.c
--- vsprintf.c	19 Mar 2007 20:10:05 -0000	1.1
+++ vsprintf.c	2 Feb 2008 20:24:42 -0000
@@ -51,7 +51,7 @@ long simple_strtol(const char *cp,char *
 /* we use this so that we can do without the ctype library */
 #define is_digit(c)	((c) >= '0' && (c) <= '9')
 
-static int skip_atoi(const char **s)
+int skip_atoi(const char **s)
 {
 	int i=0;
 
Index: xenos.c
===================================================================
RCS file: /cvsroot/free60/xell/xenos.c,v
retrieving revision 1.4
diff -u -p -r1.4 xenos.c
--- xenos.c	24 Jan 2008 22:04:43 -0000	1.4
+++ xenos.c	2 Feb 2008 20:24:42 -0000
@@ -33,7 +33,7 @@ uint32_t xenos_color[2] = { 0xD8444E00, 
 
 /* can't initialize xenos_fb with zero due to late BSS init,
  * instead init it in xenos_preinit() */
-unsigned char *xenos_fb;
+unsigned char *xenos_fb = 0LL;
 
 int cursor_x, cursor_y,
     max_x, max_y;
@@ -121,7 +121,11 @@ void xenos_newline() {
 }
 
 static inline void xenos_putch_impl(const char c) {
-	if (c == '\r') {
+	if (c == '\t') {
+		/* move to the next multiple of 8 */
+		cursor_x += 7;
+		cursor_x &= ~7;
+	} else if (c == '\r') {
 		cursor_x = 0;
 	} else if (c == '\n') {
 		xenos_newline();
@@ -159,18 +163,18 @@ void xenos_putch(const char c) {
 
 /* This was added to improve userfriendlyness */
 char* xenos_ascii = "\n"
-	" ======================================================\n"
-	" =        ==========================       ====      ==\n"
-	" =  ===============================  =====  ==   ==   =\n"
-	" =  ===============================  =========  ====  =\n"
-	" =  ========  =   ====   ====   ===       ====  ====  =\n"
-	" =      ====    =  ==  =  ==  =  ==   ===  ===  ====  =\n"
-	" =  ========  =======     ==     ==  =====  ==  ====  =\n"
-	" =  ========  =======  =====  =====  =====  ==  ====  =\n"
-	" =  ========  =======  =  ==  =  ===  ===   ==   ==   =\n"
-	" =  ========  ========   ====   =====     =====      ==\n"
-	" ======================================================\n"
-	"\n             XeLL - Xenon Linux Loader " VERSION "\n\n";
+	" ######################################################\n"
+	" #        ##########################       ####      ##\n"
+	" #  ###############################  #####  ##   ##   #\n"
+	" #  ###############################  #########  ####  #\n"
+	" #  ########  #   ####   ####   ###       ####  ####  #\n"
+	" #      ####    #  ##  #  ##  #  ##   ###  ###  ####  #\n"
+	" #  ########  #######     ##     ##  #####  ##  ####  #\n"
+	" #  ########  #######  #####  #####  #####  ##  ####  #\n"
+	" #  ########  #######  #  ##  #  ###  ###   ##   ##   #\n"
+	" #  ########  ########   ####   #####     #####      ##\n"
+	" ######################################################\n"
+	"           XeLL - Xenon Linux Loader " VERSION "\n\n";
 
 void xenos_asciiart() {
 	char *p = xenos_ascii;
Index: httpd/fsdata.c
===================================================================
RCS file: /cvsroot/free60/xell/httpd/fsdata.c,v
retrieving revision 1.1
diff -u -p -r1.1 fsdata.c
--- httpd/fsdata.c	19 Mar 2007 20:10:07 -0000	1.1
+++ httpd/fsdata.c	2 Feb 2008 20:24:42 -0000
@@ -1,3 +1,4 @@
 static struct vfs_entry_s vfs_entries[]={
+	{"/index.dhtml", "<h1>hello World!</h1>", 21, "text/html"},
 	{0, 0, 0, 0}
 };
Index: include/network.h
===================================================================
RCS file: /cvsroot/free60/xell/include/network.h,v
retrieving revision 1.1
diff -u -p -r1.1 network.h
--- include/network.h	19 Mar 2007 20:10:12 -0000	1.1
+++ include/network.h	2 Feb 2008 20:24:42 -0000
@@ -3,5 +3,6 @@
 
 void network_init();
 void network_poll();
+void print_network_config();
 
 #endif
--- /dev/null	2008-02-01 11:16:58.813598151 +0100
+++ menu.c	2008-02-02 21:24:02.899577932 +0100
@@ -0,0 +1,266 @@
+#include <vsprintf.h>
+#include <string.h>
+#include <network.h>
+#include <lwip/inet.h>
+#include <lwip/netif.h>
+#include <processor.h>
+#include <time.h>
+
+extern int kbhit(void);
+extern int getchar(void);
+extern int iso9660_load_file(char *filename, void* addr);
+extern void try_boot_cdrom(char *);
+
+/* from smc.c: */
+extern int smc_poll();
+extern int smc_getkey();
+extern int ignore_power;
+
+/* from network.c: */
+extern struct ip_addr ipaddr, netmask, gw;
+extern struct netif netif;
+
+
+/*----------------------------------------------------------------------*/
+
+#define MAXOPTS 32
+
+enum source {
+	SRC_DEFAULT,
+	SRC_TFTP,
+	SRC_CD,
+	SRC_HDD,
+	SRC_MAX
+};
+
+char *sourcenames[SRC_MAX] = {
+	"same source as XeLL",
+	"TFTP",
+	"CD-ROM",
+	"Hard Disk"
+};
+
+struct file {
+};
+
+struct boot {
+	enum source src;
+	char *path;
+	char *title;
+};
+
+void print_bootopt(struct boot *b) {
+	printf("Boot config \"%s\"\n", b->title);
+	printf("	Kernel: \"%s\" %i\n", b->path, b->src);
+}
+
+#define isspace(c) ((c)==' ' || (c)=='\r' || (c)=='\n' || (c)=='\t')
+
+/* skip leading whitespace in string at ptr */
+#define SKIP_WS(ptr) while (isspace(*ptr)) ptr++;
+
+/* macro to parse a command and execute according code
+ *
+ * @ptr: pointer to command line start (will be changed)
+ * @opt: command name (i.e. "timeout")
+ * @optlen: strlen(opt) (i.e. 7)
+ * @code: what to execute when the command is matched
+ **/
+#define IFOPT(ptr, opt, optlen, code) \
+	if ((0 == strncmp(ptr, opt, optlen)) && isspace(ptr[optlen])) { \
+		ptr += optlen + 1; \
+		SKIP_WS(ptr); \
+		code; \
+	}
+
+/* global boot config vars:
+ * boot_optc: number of boot entries
+ * boot_opt: boot menu entries
+ * boot_opt[0] = default fallback entries, no real boot menu
+ **/
+int boot_optc;
+struct boot boot_opt[MAXOPTS];
+
+int boot_timeout;
+struct in_addr boot_ip, boot_netmask, boot_server;
+char *tftp_server;
+
+void parse_source(enum source src, char *data) {
+	if (boot_optc == MAXOPTS) {
+		printf("Maximum number of menu entries reached!\n");
+		return;
+	}
+	char *tmp = strpbrk(data, " \t");
+	if (tmp) {
+		*tmp++ = '\0';
+		SKIP_WS(tmp);
+		boot_opt[boot_optc].src = src;
+		boot_opt[boot_optc].path = data;
+		boot_opt[boot_optc].title = tmp;
+		boot_optc++;
+	} else {
+		printf("Missing whitespace in source line: \"%s\"\n", data);
+	}
+}
+
+void parse_input_line(char *data) {
+	char *tmp;
+
+	SKIP_WS(data);
+	IFOPT(data, "ip", 2, 
+		tmp = strchr(data, '/');
+		if (tmp) {
+			*tmp = '\0';
+			tmp++;
+			inet_aton(data, (struct in_addr*)&ipaddr.addr);
+			inet_aton(tmp, (struct in_addr*)&netmask.addr);
+			netif_set_addr(&netif, &ipaddr, &netmask, &gw);
+			print_network_config();
+		} else printf("Error: missing netmask");
+	) else
+	IFOPT(data, "server", 6, 
+		inet_aton(data, &boot_server);
+		tftp_server = data;
+		//printf("TFTP: %08x\n", boot_server.s_addr);
+	) else
+	IFOPT(data, "timeout", 7, 
+		boot_timeout = skip_atoi(&data);
+	) else
+	IFOPT(data, "tftp", 4,
+		parse_source(SRC_TFTP, data);
+	) else
+	IFOPT(data, "cd", 2,
+		parse_source(SRC_CD, data);
+	) else
+	IFOPT(data, "hdd", 3,
+		parse_source(SRC_HDD, data);
+	) else {
+		printf("Ignoring unknown command: \"%s\"\n", data); 
+	}
+}
+
+/* parse a zero terminated config file string */
+void parse_config(char *data) {
+	char *next, *eol;
+
+	boot_optc = 0;
+	boot_timeout = 30;
+
+	while (data && *data) {
+
+		/* find EOL and replace with NUL byte */
+		eol = strpbrk(data, "\r\n");
+		if (eol == NULL) {
+			next = NULL;
+		} else {
+			*eol = '\0';
+			next = eol + 1;
+		}
+		//printf("%p param %s\n", data, data);
+
+		parse_input_line(data);
+		data = next;
+
+		if (data)
+			SKIP_WS(data);
+	}
+}
+
+#define POWER_BTN -3
+
+int user_prompt(int defaultchoice, int max, int timeout) {
+	int redraw = 1;
+	int min = 1;
+	int delta, olddelta = -1;
+	int ignore_power_last = ignore_power;
+	tb_t start, now;
+
+	mftb(&start);
+	delta = 0;
+	while (delta <= timeout) {
+		/* measure seconds since menu start */
+		mftb(&now);
+		delta = tb_diff_sec(&now, &start);
+		/* test if prompt update is needed */
+		if (delta != olddelta) {
+			olddelta = delta;
+			redraw = 1;
+		}
+		/* redraw prompt - clear line, then print prompt */
+		if (redraw) {
+			printf("                                                                      \r[%02d] > ",
+				timeout - delta);
+			redraw = 0;
+		}
+
+		if (smc_poll()) {
+			int ch = smc_getkey();
+			if (ch >= min && ch <= max)
+				return ch;
+			redraw = 1;
+			/* check for Power button */
+			if (ignore_power_last != ignore_power)
+				return POWER_BTN;
+		}
+
+		if (kbhit()) {
+			char ch = getchar();
+			int num = ch - '0';
+			printf("\nyou pressed '%c'\n", ch);
+			if (num >= min && num <= max)
+				return num;
+			redraw = 1;
+		}
+
+		network_poll();
+	}
+	printf("Timeout.\n");
+	return defaultchoice;
+}
+
+char xell_config[4096];
+
+void main_menu() {
+	int defchoice = 1;
+	int cfg_size = iso9660_load_file("xell.cfg", xell_config);
+	if (cfg_size >= 0) {
+		printf("XeLL config:\n%s", xell_config);
+	}
+
+	parse_config(xell_config);
+
+	/* Allow power button for menu selection */
+	ignore_power = boot_optc;
+
+	while (1) {
+		int opt;
+		printf("XeLL Main Menu. Please choose from:\n\n");
+		for (opt = 1; opt <= boot_optc; opt++) {
+			printf("  <%i> %s - %s%s\n", opt, boot_opt[opt-1].title,
+				sourcenames[boot_opt[opt-1].src],
+				defchoice == opt?" (default)":"");
+		}
+		int choice = user_prompt(defchoice, boot_optc, boot_timeout);
+		if (choice == POWER_BTN) {
+			defchoice++;
+			boot_timeout = 5;
+			continue;
+		}
+
+		struct boot *b = &boot_opt[choice-1];
+		printf("[###] > Booting %s: %s from %s\n", b->title, b->path, sourcenames[b->src]);
+		switch (b->src) {
+		case SRC_TFTP:
+			boot_tftp(tftp_server, b->path);
+			break;
+		case SRC_CD:
+			try_boot_cdrom(b->path);
+			break;
+		default:
+			printf("Not yet implemented, aborting menu!\n");
+			//usleep(1000);
+			return;
+		}
+	}
+}
+
--- /dev/null	2008-02-01 11:16:58.813598151 +0100
+++ smc.c	2008-02-02 21:06:14.972974096 +0100
@@ -0,0 +1,88 @@
+/* smc-ir.c - minimal IR receiver driver for XeLL
+ *
+ * Copyright (C) 2008 Georg Lukas <georg@boerde.de>
+ *
+ * This software is provided under the GNU GPL License v2.
+ */
+#include <cache.h>
+#include <types.h>
+#include <string.h>
+#include <vsprintf.h>
+
+volatile uint32_t *smc_base = (volatile uint32_t*)0x200ea001000LL;
+
+int ignore_power = 3;
+
+static inline unsigned int swap32(unsigned int v)
+{
+	return ((v&0xFF) << 24) | ((v&0xFF00)<<8) | ((v&0xFF0000)>>8) | ((v&0xFF000000)>>24);
+}
+
+
+int smc_hasdata() {
+	return (swap32(smc_base[0x94/4]) & 4);
+}
+
+int smc_get(uint32_t *msg) {
+	int pos;
+	if (swap32(smc_base[0x94/4]) & 4) {
+		smc_base[0x94/4] = swap32(4);
+		for (pos=0; pos < 4; pos++)
+			msg[pos] = smc_base[0x90/4];
+		smc_base[0x94/4] = 0;
+		return 1;
+	}
+	return 0;
+}
+
+void smc_send(uint32_t *msg) {
+	int pos;
+	while (!(swap32(smc_base[0x84/4]) & 4));
+
+	smc_base[0x84/4] = swap32(4);
+	for (pos=0; pos < 4; pos++)
+		smc_base[0x80/4] = msg[pos];
+	smc_base[0x84/4] = 0;
+}
+
+int smc_lastkey = -1;
+
+int smc_getkey() {
+	int ret = smc_lastkey;
+	smc_lastkey = -1;
+	return ret;
+}
+
+int smc_poll() {
+	unsigned char msg[16], ans[16];
+	memset(msg, 0, 16);
+
+	if (smc_get((void*)&msg)) {
+		if (ignore_power &&
+		   ((msg[0] == 0x83 && msg[1] == 0x11 && msg[2] == 0x01)
+#ifdef BLOCK_IR_REMOTE_POWER
+		   || (msg[0] == 0x83 && msg[1] == 0x20 && msg[2] == 0x01)
+#endif
+		   )) {
+			printf("PowerNAK");
+			memset(ans, 0, 16);
+			ans[0] = 0x82;
+			ans[1] = 0x04;
+			ans[2] = 0x33;
+			smc_send((void*)ans);
+			ignore_power--;
+		} else
+			printf("Received");
+		int i;
+		if (msg[0] == 0x83 && msg[1] == 0x23) {
+			smc_lastkey = msg[3];
+			printf(" IR code %d\n", smc_lastkey);
+		} else
+			for (i=0; i<16; i++)
+				printf(" %02x", (uint32_t)msg[i]);
+		printf("\n");
+		return 1;
+	}
+	return 0;
+}
+
--- /dev/null	2008-02-01 11:16:58.813598151 +0100
+++ xell.cfg	2008-02-02 21:02:52.986856142 +0100
@@ -0,0 +1,9 @@
+ip 192.168.0.250/255.255.255.0
+server 192.168.0.31
+timeout 99
+
+cd   vmlinux		Linux-sda2
+cd   vmlinux-initramfs	Recovery Linux
+hdd  vmlinux		to be implemented
+tftp /tftpboot/xenon	Xenon from TFTP
+tftp /tftpboot/vmlinux-2.6.21.sda2.sata.fbfix Linux-sda2 from TFTP
