diff -ruw linux-2.6.20.14/arch/mips/Kconfig linux-2.6.20.14-fbx/arch/mips/Kconfig
--- linux-2.6.20.14/arch/mips/Kconfig	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/arch/mips/Kconfig	2011-09-26 15:18:19.788452265 +0200
@@ -12,6 +12,27 @@
 	prompt "System type"
 	default SGI_IP22
 
+
+# Begin Freebox changed code
+config TANGO2
+	bool "SigmaDesigns Tango2 board"
+	select DMA_NONCOHERENT
+	select SYS_SUPPORTS_32BIT_KERNEL
+	select SYS_SUPPORTS_LITTLE_ENDIAN
+	select SYS_HAS_CPU_MIPS32_R1
+	select SYS_HAS_CPU_MIPS32_R2
+	select IRQ_CPU
+	select HW_HAS_PCI
+	select OWN_DMA
+	select DMA_TANGO2
+	select DMA_NONCOHERENT
+	select BUILTIN_FBXSERIAL
+	help
+	  Add support for Sigma Designs SMP8634 board. Say Y here to
+	  support this machine type.
+
+# End Freebox changed code
+
 config MIPS_MTX1
 	bool "4G Systems MTX-1 board"
 	select DMA_NONCOHERENT
@@ -154,6 +175,19 @@
 	  note that a kernel built with this option selected will not be
 	  able to run on normal units.
 
+# Begin Freebox changed code
+config BCM963XX
+	bool "Broadcom 63xx boards"
+	select SYS_HAS_CPU_MIPS32_R1
+	select SYS_SUPPORTS_BIG_ENDIAN
+	select SYS_SUPPORTS_32BIT_KERNEL
+	select DMA_NONCOHERENT
+	select IRQ_CPU
+	select GENERIC_HARDIRQS_NO__DO_IRQ
+	select SWAP_IO_SPACE
+	select SYS_SUPPORTS_SMP
+# End Freebox changed code
+
 config MIPS_COBALT
 	bool "Cobalt Server"
 	select DMA_NONCOHERENT
@@ -790,6 +824,17 @@
 
 endchoice
 
+
+# Begin Freebox changed code
+config DMA_TANGO2
+	bool
+	select DMA_NEED_PCI_MAP_STATE
+
+source "arch/mips/tango2/Kconfig"
+source "arch/mips/bcm963xx/Kconfig"
+
+# End Freebox changed code
+
 config KEXEC
  	bool "Kexec system call (EXPERIMENTAL)"
  	depends on EXPERIMENTAL
@@ -1199,7 +1244,7 @@
 	select CPU_SUPPORTS_32BIT_KERNEL
 	select CPU_SUPPORTS_64BIT_KERNEL
 	help
-	  The options selects support for the NEC VR4100 series of processors.
+	  The options selects support for the NEC VR41xx series of processors.
 	  Only choose this option if you have one of these processors as a
 	  kernel built with this option will not run on any other type of
 	  processor or vice versa.
@@ -2089,3 +2134,9 @@
 source "crypto/Kconfig"
 
 source "lib/Kconfig"
+
+
+config CROSS_PATH
+	string "cross path"
+	default "mips-linux-" if CPU_BIG_ENDIAN
+	default "mipsel-linux-" if CPU_LITTLE_ENDIAN
diff -ruw linux-2.6.20.14/arch/mips/kernel/cpu-probe.c linux-2.6.20.14-fbx/arch/mips/kernel/cpu-probe.c
--- linux-2.6.20.14/arch/mips/kernel/cpu-probe.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/arch/mips/kernel/cpu-probe.c	2011-09-26 15:07:53.878835709 +0200
@@ -142,6 +142,11 @@
 	case CPU_34K:
 	case CPU_74K:
  	case CPU_PR4450:
+	case CPU_BCM6338:
+	case CPU_BCM6345:
+	case CPU_BCM6348:
+	case CPU_BCM6358:
+	case CPU_BCM6368:
 		cpu_wait = r4k_wait;
 		break;
 	case CPU_TX49XX:
@@ -631,6 +636,15 @@
 static inline void cpu_probe_alchemy(struct cpuinfo_mips *c)
 {
 	decode_configs(c);
+
+	/*
+	 * For historical reasons the SB1 comes with it's own variant of
+	 * cache code which eventually will be folded into c-r4k.c.  Until
+	 * then we pretend it's got it's own cache architecture.
+	 */
+	c->options &= ~MIPS_CPU_4K_CACHE;
+	c->options |= MIPS_CPU_SB1_CACHE;
+
 	switch (c->processor_id & 0xff00) {
 	case PRID_IMP_AU1_REV1:
 	case PRID_IMP_AU1_REV2:
@@ -658,18 +672,45 @@
 	}
 }
 
-static inline void cpu_probe_sibyte(struct cpuinfo_mips *c)
+/* Begin Freebox added code */
+
+static inline void cpu_probe_broadcom(struct cpuinfo_mips *c)
 {
-	decode_configs(c);
+	decode_config1(c);
+ 	switch (c->processor_id & 0xff00) {
+	case PRID_IMP_BCM6338:
+		c->cputype = CPU_BCM6338;
+		break;
+	case PRID_IMP_BCM6345:
+		c->cputype = CPU_BCM6345;
+		break;
+	case PRID_IMP_BCM6348:
+		c->cputype = CPU_BCM6348;
+		break;
+	case PRID_IMP_BCM4350:
+		switch (c->processor_id & 0xf0) {
+		case PRID_REV_BCM6358:
+			c->cputype = CPU_BCM6358;
+			break;
+		case PRID_REV_BCM6368:
+			c->cputype = CPU_BCM6368;
+			break;
+		default:
+			c->cputype = CPU_UNKNOWN;
+			break;
+		}
+		break;
+	default:
+		c->cputype = CPU_UNKNOWN;
+		break;
+	}
+}
 
-	/*
-	 * For historical reasons the SB1 comes with it's own variant of
-	 * cache code which eventually will be folded into c-r4k.c.  Until
-	 * then we pretend it's got it's own cache architecture.
-	 */
-	c->options &= ~MIPS_CPU_4K_CACHE;
-	c->options |= MIPS_CPU_SB1_CACHE;
+/* End Freebox added code */
 
+static inline void cpu_probe_sibyte(struct cpuinfo_mips *c)
+{
+	decode_configs(c);
 	switch (c->processor_id & 0xff00) {
 	case PRID_IMP_SB1:
 		c->cputype = CPU_SB1;
@@ -729,6 +770,11 @@
 	case PRID_COMP_ALCHEMY:
 		cpu_probe_alchemy(c);
 		break;
+/* Begin Freebox added code */
+	case PRID_COMP_BROADCOM:
+		cpu_probe_broadcom(c);
+		break;
+/* End Freebox added code */
 	case PRID_COMP_SIBYTE:
 		cpu_probe_sibyte(c);
 		break;
diff -ruw linux-2.6.20.14/arch/mips/kernel/head.S linux-2.6.20.14-fbx/arch/mips/kernel/head.S
--- linux-2.6.20.14/arch/mips/kernel/head.S	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/arch/mips/kernel/head.S	2011-09-26 15:07:53.888835703 +0200
@@ -138,7 +138,7 @@
 EXPORT(stext)					# used for profiling
 EXPORT(_stext)
 
-#ifdef CONFIG_MIPS_SIM
+#if defined(CONFIG_MIPS_SIM) || defined(CONFIG_TANGO2)
 	/*
 	 * Give us a fighting chance of running if execution beings at the
 	 * kernel load address.  This is needed because this platform does
diff -ruw linux-2.6.20.14/arch/mips/kernel/proc.c linux-2.6.20.14-fbx/arch/mips/kernel/proc.c
--- linux-2.6.20.14/arch/mips/kernel/proc.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/arch/mips/kernel/proc.c	2011-09-26 15:07:53.888835703 +0200
@@ -84,8 +84,14 @@
 	[CPU_VR4181A]	= "NEC VR4181A",
 	[CPU_SR71000]	= "Sandcraft SR71000",
 	[CPU_PR4450]	= "Philips PR4450",
+	[CPU_BCM6338]	= "BCM6338",
+	[CPU_BCM6345]	= "BCM6345",
+	[CPU_BCM6348]	= "BCM6348",
+	[CPU_BCM6358]	= "BCM6358",
+	[CPU_BCM6368]	= "BCM6368",
 };
 
+extern unsigned long unaligned_instructions;
 
 static int show_cpuinfo(struct seq_file *m, void *v)
 {
@@ -136,6 +142,7 @@
 	        cpu_has_vce ? "%u" : "not available");
 	seq_printf(m, fmt, 'D', vced_count);
 	seq_printf(m, fmt, 'I', vcei_count);
+	seq_printf(m, "unaligned exceptions\t: %lu\n", unaligned_instructions);
 	seq_printf(m, "\n");
 
 	return 0;
diff -ruw linux-2.6.20.14/arch/mips/kernel/ptrace.c linux-2.6.20.14-fbx/arch/mips/kernel/ptrace.c
--- linux-2.6.20.14/arch/mips/kernel/ptrace.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/arch/mips/kernel/ptrace.c	2011-09-26 15:07:53.888835703 +0200
@@ -20,12 +20,12 @@
 #include <linux/mm.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
-#include <linux/audit.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/user.h>
 #include <linux/security.h>
-#include <linux/signal.h>
+#include <linux/audit.h>
+#include <linux/seccomp.h>
 
 #include <asm/byteorder.h>
 #include <asm/cpu.h>
@@ -473,12 +473,16 @@
  */
 asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit)
 {
+	/* do the secure computing check first */
+	secure_computing(regs->orig_eax);
+
 	if (unlikely(current->audit_context) && entryexit)
 		audit_syscall_exit(AUDITSC_RESULT(regs->regs[2]),
 		                   regs->regs[2]);
 
 	if (!(current->ptrace & PT_PTRACED))
 		goto out;
+
 	if (!test_thread_flag(TIF_SYSCALL_TRACE))
 		goto out;
 
@@ -496,9 +500,14 @@
 		send_sig(current->exit_code, current, 1);
 		current->exit_code = 0;
 	}
+
  out:
+	/* There is no ->orig_eax and that's quite intensional for now making
+	   this work will require some work in various other place before it's
+	   more than a placebo.  */
+
 	if (unlikely(current->audit_context) && !entryexit)
-		audit_syscall_entry(audit_arch(), regs->regs[2],
+		audit_syscall_entry(audit_arch(), regs->orig_eax,
 				    regs->regs[4], regs->regs[5],
 				    regs->regs[6], regs->regs[7]);
 }
diff -ruw linux-2.6.20.14/arch/mips/kernel/setup.c linux-2.6.20.14-fbx/arch/mips/kernel/setup.c
--- linux-2.6.20.14/arch/mips/kernel/setup.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/arch/mips/kernel/setup.c	2011-09-26 15:07:53.888835703 +0200
@@ -271,8 +271,7 @@
 static void __init bootmem_init(void)
 {
 	unsigned long reserved_end;
-	unsigned long highest = 0;
-	unsigned long mapstart = -1UL;
+	unsigned long mapstart = ~0UL;
 	unsigned long bootmap_size;
 	int i;
 
@@ -284,6 +283,13 @@
 	reserved_end = max(init_initrd(), PFN_UP(__pa_symbol(&_end)));
 
 	/*
+	 * max_low_pfn is not a number of pages. The number of pages
+	 * of the system is given by 'max_low_pfn - min_low_pfn'.
+	 */
+	min_low_pfn = ~0UL;
+	max_low_pfn = 0;
+
+	/*
 	 * Find the highest page frame number we have available.
 	 */
 	for (i = 0; i < boot_mem_map.nr_map; i++) {
@@ -296,8 +302,10 @@
 		end = PFN_DOWN(boot_mem_map.map[i].addr
 				+ boot_mem_map.map[i].size);
 
-		if (end > highest)
-			highest = end;
+		if (end > max_low_pfn)
+			max_low_pfn = end;
+		if (start < min_low_pfn)
+			min_low_pfn = start;
 		if (end <= reserved_end)
 			continue;
 		if (start >= mapstart)
@@ -305,22 +313,36 @@
 		mapstart = max(reserved_end, start);
 	}
 
+	if (min_low_pfn >= max_low_pfn)
+		panic("Incorrect memory mapping !!!");
+	if (min_low_pfn > ARCH_PFN_OFFSET) {
+		printk(KERN_INFO
+		       "Wasting %lu bytes for tracking %lu unused pages\n",
+		       (min_low_pfn - ARCH_PFN_OFFSET) * sizeof(struct page),
+		       min_low_pfn - ARCH_PFN_OFFSET);
+	} else if (min_low_pfn < ARCH_PFN_OFFSET) {
+		printk(KERN_INFO
+		       "%lu free pages won't be used\n",
+		       ARCH_PFN_OFFSET - min_low_pfn);
+	}
+	min_low_pfn = ARCH_PFN_OFFSET;
+
 	/*
 	 * Determine low and high memory ranges
 	 */
-	if (highest > PFN_DOWN(HIGHMEM_START)) {
+	if (max_low_pfn > PFN_DOWN(HIGHMEM_START)) {
 #ifdef CONFIG_HIGHMEM
 		highstart_pfn = PFN_DOWN(HIGHMEM_START);
-		highend_pfn = highest;
+		highend_pfn = max_low_pfn;
 #endif
-		highest = PFN_DOWN(HIGHMEM_START);
+		max_low_pfn = PFN_DOWN(HIGHMEM_START);
 	}
 
 	/*
 	 * Initialize the boot-time allocator with low memory only.
 	 */
-	bootmap_size = init_bootmem(mapstart, highest);
-
+	bootmap_size = init_bootmem_node(NODE_DATA(0), mapstart,
+					 min_low_pfn, max_low_pfn);
 	/*
 	 * Register fully available low RAM pages with the bootmem allocator.
 	 */
diff -ruw linux-2.6.20.14/arch/mips/kernel/traps.c linux-2.6.20.14-fbx/arch/mips/kernel/traps.c
--- linux-2.6.20.14/arch/mips/kernel/traps.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/arch/mips/kernel/traps.c	2011-09-26 15:07:53.888835703 +0200
@@ -669,7 +669,7 @@
 	unsigned int opcode, bcode;
 	siginfo_t info;
 
-	if (get_user(opcode, (unsigned int __user *) exception_epc(regs)))
+	if (__get_user(opcode, (unsigned int __user *) exception_epc(regs)))
 		goto out_sigsegv;
 
 	/*
@@ -718,7 +718,7 @@
 	unsigned int opcode, tcode = 0;
 	siginfo_t info;
 
-	if (get_user(opcode, (unsigned int __user *) exception_epc(regs)))
+	if (__get_user(opcode, (unsigned int __user *) exception_epc(regs)))
 		goto out_sigsegv;
 
 	/* Immediate versions don't provide a code.  */
diff -ruw linux-2.6.20.14/arch/mips/kernel/unaligned.c linux-2.6.20.14-fbx/arch/mips/kernel/unaligned.c
--- linux-2.6.20.14/arch/mips/kernel/unaligned.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/arch/mips/kernel/unaligned.c	2011-09-26 15:07:53.888835703 +0200
@@ -183,10 +183,12 @@
 			"1:\tlwl\t%0, (%2)\n"
 			"2:\tlwr\t%0, 3(%2)\n\t"
 #endif
+
 #ifdef __LITTLE_ENDIAN
 			"1:\tlwl\t%0, 3(%2)\n"
 			"2:\tlwr\t%0, (%2)\n\t"
 #endif
+
 			"li\t%1, 0\n"
 			"3:\t.section\t.fixup,\"ax\"\n\t"
 			"4:\tli\t%1, %3\n\t"
@@ -197,7 +199,8 @@
 			STR(PTR)"\t2b, 4b\n\t"
 			".previous"
 			: "=&r" (value), "=r" (res)
-			: "r" (addr), "i" (-EFAULT));
+			: "r" (addr), "i" (-EFAULT)
+			);
 		if (res)
 			goto fault;
 		*newvalue = value;
@@ -366,10 +369,12 @@
 
 		value = regs->regs[insn.i_format.rt];
 		__asm__ __volatile__ (
+
 #ifdef __BIG_ENDIAN
 			"1:\tswl\t%1,(%2)\n"
 			"2:\tswr\t%1, 3(%2)\n\t"
 #endif
+
 #ifdef __LITTLE_ENDIAN
 			"1:\tswl\t%1, 3(%2)\n"
 			"2:\tswr\t%1, (%2)\n\t"
@@ -385,7 +390,8 @@
 			STR(PTR)"\t2b, 4b\n\t"
 			".previous"
 		: "=r" (res)
-		: "r" (value), "r" (addr), "i" (-EFAULT));
+		: "r" (value), "r" (addr), "i" (-EFAULT)
+		);
 		if (res)
 			goto fault;
 		break;
diff -ruw linux-2.6.20.14/arch/mips/lib/csum_partial.S linux-2.6.20.14-fbx/arch/mips/lib/csum_partial.S
--- linux-2.6.20.14/arch/mips/lib/csum_partial.S	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/arch/mips/lib/csum_partial.S	2011-09-26 15:07:53.898835697 +0200
@@ -513,6 +513,7 @@
 	ADDC(sum, t0)
 	b	done
 	.set noreorder
+
 dst_unaligned:
 	/*
 	 * dst is unaligned
@@ -561,6 +562,7 @@
 EXC(	LDREST	t2, REST(2)(src),	l_exc_copy)
 EXC(	LDREST	t3, REST(3)(src),	l_exc_copy)
 	ADD	src, src, 4*NBYTES
+
 #ifdef CONFIG_CPU_SB1
 	nop				# improves slotting
 #endif
diff -ruw linux-2.6.20.14/arch/mips/lib/iomap.c linux-2.6.20.14-fbx/arch/mips/lib/iomap.c
--- linux-2.6.20.14/arch/mips/lib/iomap.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/arch/mips/lib/iomap.c	2011-09-26 15:07:53.898835697 +0200
@@ -3,7 +3,7 @@
  *
  *  This code is based on lib/iomap.c, by Linus Torvalds.
  *
- *  Copyright (C) 2004-2005  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2004-2005  Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -63,7 +63,7 @@
 		return ioport_map(start, len);
 	if (flags & IORESOURCE_MEM) {
 		if (flags & IORESOURCE_CACHEABLE)
-			return ioremap_cachable(start, len);
+			return ioremap(start, len);
 		return ioremap_nocache(start, len);
 	}
 
diff -ruw linux-2.6.20.14/arch/mips/lib/Makefile linux-2.6.20.14-fbx/arch/mips/lib/Makefile
--- linux-2.6.20.14/arch/mips/lib/Makefile	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/arch/mips/lib/Makefile	2011-09-26 15:07:53.898835697 +0200
@@ -3,9 +3,7 @@
 #
 
 lib-y	+= csum_partial.o memcpy.o promlib.o \
-	   strlen_user.o strncpy_user.o strnlen_user.o uncached.o
-
-obj-y	+= iomap.o
+	   strlen_user.o strncpy_user.o strnlen_user.o uncached.o iomap.o
 
 # libgcc-style stuff needed in the kernel
 lib-y += ashldi3.o ashrdi3.o lshrdi3.o
diff -ruw linux-2.6.20.14/arch/mips/lib/memcpy.S linux-2.6.20.14-fbx/arch/mips/lib/memcpy.S
--- linux-2.6.20.14/arch/mips/lib/memcpy.S	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/arch/mips/lib/memcpy.S	2011-09-26 15:07:53.898835697 +0200
@@ -309,6 +309,7 @@
 EXC(	STREST	t0, -1(t1),		s_exc)
 	jr	ra
 	 move	len, zero
+	
 dst_unaligned:
 	/*
 	 * dst is unaligned
@@ -320,6 +321,7 @@
 	 * Set match = (src and dst have same alignment)
 	 */
 #define match rem
+
 EXC(	LDFIRST	t3, FIRST(0)(src),	l_exc)
 	ADD	t2, zero, NBYTES
 EXC(	LDREST	t3, REST(0)(src),	l_exc_copy)
diff -ruw linux-2.6.20.14/arch/mips/lib-32/dump_tlb.c linux-2.6.20.14-fbx/arch/mips/lib-32/dump_tlb.c
--- linux-2.6.20.14/arch/mips/lib-32/dump_tlb.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/arch/mips/lib-32/dump_tlb.c	2011-09-26 15:07:53.898835697 +0200
@@ -40,8 +40,6 @@
 		return "256Mb";
 #endif
 	}
-
-	return "unknown";
 }
 
 #define BARRIER()					\
diff -ruw linux-2.6.20.14/arch/mips/lib-32/memset.S linux-2.6.20.14-fbx/arch/mips/lib-32/memset.S
--- linux-2.6.20.14/arch/mips/lib-32/memset.S	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/arch/mips/lib-32/memset.S	2011-09-26 15:07:53.898835697 +0200
@@ -98,6 +98,7 @@
 	andi		a2, LONGMASK		/* At most one long to go */
 
 	beqz		a2, 1f
+
 	 PTR_ADDU	a0, a2			/* What's left */
 #ifdef __MIPSEB__
 	EX(swr, a1, -1(a0), last_fixup)
diff -ruw linux-2.6.20.14/arch/mips/Makefile linux-2.6.20.14-fbx/arch/mips/Makefile
--- linux-2.6.20.14/arch/mips/Makefile	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/arch/mips/Makefile	2011-09-26 15:07:53.858835721 +0200
@@ -43,7 +43,11 @@
 endif
 
 ifdef CONFIG_CROSSCOMPILE
-CROSS_COMPILE		:= $(tool-prefix)
+ifneq ($(CONFIG_CROSS_PATH),)
+CROSS_COMPILE		:= $(patsubst "%",%,$(CONFIG_CROSS_PATH))
+else
+$(error CONFIG_CROSS_PATH is not set)
+endif
 endif
 
 ifdef CONFIG_32BIT
@@ -264,6 +268,15 @@
 libs-$(CONFIG_MIPS_XXS1500)	+= arch/mips/au1000/xxs1500/
 load-$(CONFIG_MIPS_XXS1500)	+= 0xffffffff80100000
 
+# Begin Freebox added code
+load-$(CONFIG_BCM963XX)		+= 0x80010000
+core-$(CONFIG_BCM963XX)		+= arch/mips/bcm963xx/
+
+cflags-$(CONFIG_BCM963XX)	+= -Iinclude/asm-mips/mach-bcm963xx
+cflags-$(CONFIG_BCM963XX)	+= -Iextdrivers/include/bcm963xx
+cflags-$(CONFIG_BCM963XX)	+= -Iextdrivers/include/freebox
+# End Freebox added code
+
 #
 # Cobalt Server
 #
@@ -581,6 +594,28 @@
 load-$(CONFIG_SNI_RM)		+= 0xffffffff80600000
 
 #
+# Tango2 board
+#
+include include/asm-mips/tango2/emhwlib_registers_tango2.inc
+include include/asm-mips/tango2/emhwlib_dram_tango2.inc
+
+internal_hex = 0x$(shell printf "%x" $$(($(1))))
+
+core-$(CONFIG_TANGO2)		+= arch/mips/tango2/
+cflags-$(CONFIG_TANGO2)		+= -Iinclude/asm-mips/mach-tango2
+cflags-$(CONFIG_TANGO2)		+= -Iextdrivers/include/freebox
+cflags-$(CONFIG_TANGO2)		+= -DEM86XX_CHIP=EM86XX_CHIPID_TANGO2
+cflags-$(CONFIG_TANGO2_ES1)	+= -DEM86XX_REVISION=1
+cflags-$(CONFIG_TANGO2_ES2)	+= -DEM86XX_REVISION=2
+cflags-$(CONFIG_TANGO2_ES3)	+= -DEM86XX_REVISION=3
+cflags-$(CONFIG_TANGO2_ES4)	+= -DEM86XX_REVISION=4
+cflags-$(CONFIG_TANGO2_ES5)	+= -DEM86XX_REVISION=5
+cflags-$(CONFIG_TANGO2_ES6)	+= -DEM86XX_REVISION=6
+load-$(CONFIG_TANGO2)		:= $(call internal_hex,0x80000000+	\
+					$(MEM_BASE_dram_controller_0)+	\
+					$(FM_linuxmips__ftext))
+
+#
 # Toshiba JMR-TX3927 board
 #
 core-$(CONFIG_TOSHIBA_JMR3927)	+= arch/mips/jmr3927/rbhma3100/ \
diff -ruw linux-2.6.20.14/arch/mips/mm/cache.c linux-2.6.20.14-fbx/arch/mips/mm/cache.c
--- linux-2.6.20.14/arch/mips/mm/cache.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/arch/mips/mm/cache.c	2011-09-26 15:07:53.908835691 +0200
@@ -32,6 +32,7 @@
 void (*flush_data_cache_page)(unsigned long addr);
 void (*flush_icache_all)(void);
 
+EXPORT_SYMBOL_GPL(flush_cache_page);
 EXPORT_SYMBOL_GPL(local_flush_data_cache_page);
 EXPORT_SYMBOL(flush_data_cache_page);
 
@@ -115,7 +116,6 @@
 {
 	if (cpu_has_3k_cache) {
 		extern void __weak r3k_cache_init(void);
-
 		r3k_cache_init();
 		return;
 	}
diff -ruw linux-2.6.20.14/arch/mips/mm/fault.c linux-2.6.20.14-fbx/arch/mips/mm/fault.c
--- linux-2.6.20.14/arch/mips/mm/fault.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/arch/mips/mm/fault.c	2011-09-26 15:07:53.908835691 +0200
@@ -133,10 +133,10 @@
 	if (user_mode(regs)) {
 		tsk->thread.cp0_badvaddr = address;
 		tsk->thread.error_code = write;
-#if 0
-		printk("do_page_fault() #2: sending SIGSEGV to %s for "
+#if 1
+		printk("do_page_fault() #2: sending SIGSEGV to %s[%d] for "
 		       "invalid %s\n%0*lx (epc == %0*lx, ra == %0*lx)\n",
-		       tsk->comm,
+		       tsk->comm, tsk->pid,
 		       write ? "write access to" : "read access from",
 		       field, address,
 		       field, (unsigned long) regs->cp0_epc,
diff -ruw linux-2.6.20.14/arch/mips/mm/init.c linux-2.6.20.14-fbx/arch/mips/mm/init.c
--- linux-2.6.20.14/arch/mips/mm/init.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/arch/mips/mm/init.c	2011-09-26 15:07:53.908835691 +0200
@@ -341,7 +341,6 @@
 void __init paging_init(void)
 {
 	unsigned long zones_size[MAX_NR_ZONES] = { 0, };
-	unsigned long max_dma, low;
 #ifndef CONFIG_FLATMEM
 	unsigned long zholes_size[MAX_NR_ZONES] = { 0, };
 	unsigned long i, j, pfn;
@@ -354,19 +353,19 @@
 #endif
 	kmap_coherent_init();
 
-	max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
-	low = max_low_pfn;
-
 #ifdef CONFIG_ISA
-	if (low < max_dma)
-		zones_size[ZONE_DMA] = low;
-	else {
-		zones_size[ZONE_DMA] = max_dma;
-		zones_size[ZONE_NORMAL] = low - max_dma;
+	if (max_low_pfn >= MAX_DMA_PFN)
+		if (min_low_pfn >= MAX_DMA_PFN) {
+			zones_size[ZONE_DMA] = 0;
+			zones_size[ZONE_NORMAL] = max_low_pfn - min_low_pfn;
+		} else {
+			zones_size[ZONE_DMA] = MAX_DMA_PFN - min_low_pfn;
+			zones_size[ZONE_NORMAL] = max_low_pfn - MAX_DMA_PFN;
 	}
-#else
-	zones_size[ZONE_DMA] = low;
+	else
 #endif
+	zones_size[ZONE_DMA] = max_low_pfn - min_low_pfn;
+
 #ifdef CONFIG_HIGHMEM
 	zones_size[ZONE_HIGHMEM] = highend_pfn - highstart_pfn;
 
diff -ruw linux-2.6.20.14/arch/mips/mm/Makefile linux-2.6.20.14-fbx/arch/mips/mm/Makefile
--- linux-2.6.20.14/arch/mips/mm/Makefile	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/arch/mips/mm/Makefile	2011-09-26 15:07:53.908835691 +0200
@@ -41,5 +41,6 @@
 endif
 obj-$(CONFIG_DMA_IP27)		+= dma-ip27.o
 obj-$(CONFIG_DMA_IP32)		+= dma-ip32.o
+obj-$(CONFIG_DMA_TANGO2)	+= dma-tango2.o
 
 EXTRA_AFLAGS := $(CFLAGS)
diff -ruw linux-2.6.20.14/arch/mips/mm/tlbex.c linux-2.6.20.14-fbx/arch/mips/mm/tlbex.c
--- linux-2.6.20.14/arch/mips/mm/tlbex.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/arch/mips/mm/tlbex.c	2011-09-26 15:07:53.908835691 +0200
@@ -893,6 +893,13 @@
 	case CPU_4KSC:
 	case CPU_20KC:
 	case CPU_25KF:
+/* Start Freebox added code */
+	case CPU_BCM6338:
+	case CPU_BCM6345:
+	case CPU_BCM6348:
+	case CPU_BCM6358:
+	case CPU_BCM6368:
+/* End Freebox added code */
 		tlbw(p);
 		break;
 
diff -ruw linux-2.6.20.14/arch/mips/momentum/jaguar_atx/Makefile linux-2.6.20.14-fbx/arch/mips/momentum/jaguar_atx/Makefile
--- linux-2.6.20.14/arch/mips/momentum/jaguar_atx/Makefile	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/arch/mips/momentum/jaguar_atx/Makefile	2011-09-26 15:07:53.908835691 +0200
@@ -6,7 +6,7 @@
 # unless it's something special (ie not a .c file).
 #
 
-obj-y += irq.o prom.o reset.o setup.o
+obj-y += irq.o platform.o prom.o reset.o setup.o
 
 obj-$(CONFIG_SERIAL_8250_CONSOLE) += ja-console.o
 obj-$(CONFIG_REMOTE_DEBUG) += dbg_io.o
diff -ruw linux-2.6.20.14/arch/mips/oprofile/Kconfig linux-2.6.20.14-fbx/arch/mips/oprofile/Kconfig
--- linux-2.6.20.14/arch/mips/oprofile/Kconfig	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/arch/mips/oprofile/Kconfig	2011-09-26 15:07:53.908835691 +0200
@@ -11,7 +11,7 @@
 
 config OPROFILE
 	tristate "OProfile system profiling (EXPERIMENTAL)"
-	depends on PROFILING && EXPERIMENTAL
+	depends on PROFILING && !MIPS_MT_SMTC && EXPERIMENTAL
 	help
 	  OProfile is a profiling system capable of profiling the
 	  whole system, include the kernel, kernel modules, libraries,
diff -ruw linux-2.6.20.14/arch/mips/pci/Makefile linux-2.6.20.14-fbx/arch/mips/pci/Makefile
--- linux-2.6.20.14/arch/mips/pci/Makefile	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/arch/mips/pci/Makefile	2011-09-26 15:07:53.908835691 +0200
@@ -18,6 +18,8 @@
 obj-$(CONFIG_NEC_CMBVR4133)	+= fixup-vr4133.o
 obj-$(CONFIG_MARKEINS)		+= ops-emma2rh.o pci-emma2rh.o fixup-emma2rh.o
 
+obj-$(CONFIG_BCM963XX)		+= fixup-bcm963xx.o pci-bcm963xx.o \
+					ops-bcm963xx.o
 #
 # These are still pretty much in the old state, watch, go blind.
 #
@@ -53,3 +55,6 @@
 obj-$(CONFIG_VICTOR_MPC30X)	+= fixup-mpc30x.o
 obj-$(CONFIG_ZAO_CAPCELLA)	+= fixup-capcella.o
 obj-$(CONFIG_WR_PPMC)		+= fixup-wrppmc.o
+
+obj-$(CONFIG_TANGO2)		+= pci-tango2.o fixup-tango2.o ops-tango2.o
+obj-$(CONFIG_TANGO2)		+= ops-tango2-fake.o
diff -ruw linux-2.6.20.14/arch/mips/pci/pci.c linux-2.6.20.14-fbx/arch/mips/pci/pci.c
--- linux-2.6.20.14/arch/mips/pci/pci.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/arch/mips/pci/pci.c	2011-09-26 15:07:53.918835685 +0200
@@ -103,10 +103,15 @@
 	return PCI_SLOT(dev->devfn);
 }
 
+int mips_system_has_legacy_ide;
+
+EXPORT_SYMBOL_GPL(mips_system_has_legacy_ide);
+
 static int __init pcibios_init(void)
 {
 	struct pci_controller *hose;
 	struct pci_bus *bus;
+	struct pci_dev *dev;
 	int next_busno;
 	int need_domain_info = 0;
 
@@ -150,6 +155,13 @@
 		pci_assign_unassigned_resources();
 	pci_fixup_irqs(common_swizzle, pcibios_map_irq);
 
+	if ((dev = pci_get_class(PCI_CLASS_BRIDGE_EISA << 8, NULL)) != NULL ||
+	    (dev = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL)) != NULL) {
+		pci_dev_put(dev);
+
+		mips_system_has_legacy_ide = 1;
+	}
+
 	return 0;
 }
 
diff -ruw linux-2.6.20.14/arch/mips/qemu/Makefile linux-2.6.20.14-fbx/arch/mips/qemu/Makefile
--- linux-2.6.20.14/arch/mips/qemu/Makefile	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/arch/mips/qemu/Makefile	2011-09-26 15:07:53.918835685 +0200
@@ -4,4 +4,5 @@
 
 obj-y		= q-firmware.o q-irq.o q-mem.o q-setup.o q-reset.o
 
+obj-$(CONFIG_VT) += q-vga.o
 obj-$(CONFIG_SMP) += q-smp.o
diff -ruw linux-2.6.20.14/drivers/char/Kconfig linux-2.6.20.14-fbx/drivers/char/Kconfig
--- linux-2.6.20.14/drivers/char/Kconfig	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/drivers/char/Kconfig	2011-09-26 15:07:54.298835451 +0200
@@ -372,19 +372,56 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called istallion.
 
-config AU1000_UART
-	bool "Enable Au1000 UART Support"
-	depends on SERIAL_NONSTANDARD && MIPS
+config AU1X00_GPIO
+	tristate "Alchemy Au1000 GPIO device support"
+	depends on MIPS && SOC_AU1X00
+
+config TS_AU1X00_ADS7846
+	tristate "Au1000/ADS7846 touchscreen support"
+	depends on MIPS && SOC_AU1X00
+
+config SIBYTE_SB1250_DUART
+	bool "Support for BCM1xxx onchip DUART"
+	depends on MIPS && SIBYTE_SB1xxx_SOC=y
+
+config SIBYTE_SB1250_DUART_CONSOLE
+	bool "Console on BCM1xxx DUART"
+	depends on SIBYTE_SB1250_DUART
+
+config SERIAL_DEC
+	bool "DECstation serial support"
+	depends on MACH_DECSTATION
+	default y
 	help
-	  If you have an Alchemy AU1000 processor (MIPS based) and you want
-	  to use serial ports, say Y.  Otherwise, say N.
+	  This selects whether you want to be asked about drivers for
+	  DECstation serial ports.
+
+	  Note that the answer to this question won't directly affect the
+	  kernel: saying N will just cause the configurator to skip all
+	  the questions about DECstation serial ports.
+
+	  If unsure, say Y.
+
+config SERIAL_DEC_CONSOLE
+	bool "Support for console on a DECstation serial port"
+	depends on SERIAL_DEC
+	default y
+	help
+	  If you say Y here, it will be possible to use a serial port as the
+	  system console (the system console is the device which receives all
+	  kernel messages and warnings and which allows logins in single user
+	  mode).  Note that the firmware uses ttyS0 as the serial console on
+	  the Maxine and ttyS2 on the others.
+
+	  If unsure, say Y.
 
-config AU1000_SERIAL_CONSOLE
-	bool "Enable Au1000 serial console"
-	depends on AU1000_UART
+config ZS
+	bool "Z85C30 Serial Support"
+	depends on SERIAL_DEC
+	default y
 	help
-	  If you have an Alchemy AU1000 processor (MIPS based) and you want
-	  to use a console on a serial port, say Y.  Otherwise, say N.
+	  Documentation on the Zilog 85C350 serial communications controller
+	  is downloadable at <http://www.zilog.com/pdfs/serial/z85c30.pdf>.
 
 config A2232
 	tristate "Commodore A2232 serial support (EXPERIMENTAL)"
diff -ruw linux-2.6.20.14/drivers/char/Makefile linux-2.6.20.14-fbx/drivers/char/Makefile
--- linux-2.6.20.14/drivers/char/Makefile	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/drivers/char/Makefile	2011-09-26 15:07:54.298835451 +0200
@@ -32,6 +32,7 @@
 obj-$(CONFIG_ATARI_DSP56K)	+= dsp56k.o
 obj-$(CONFIG_MOXA_SMARTIO)	+= mxser.o
 obj-$(CONFIG_MOXA_SMARTIO_NEW)	+= mxser_new.o
+obj-$(CONFIG_SIBYTE_SB1250_DUART) += sb1250_duart.o
 obj-$(CONFIG_COMPUTONE)		+= ip2/
 obj-$(CONFIG_RISCOM8)		+= riscom8.o
 obj-$(CONFIG_ISI)		+= isicom.o
@@ -54,6 +55,7 @@
 obj-$(CONFIG_VIOTAPE)		+= viotape.o
 obj-$(CONFIG_HVCS)		+= hvcs.o
 obj-$(CONFIG_SGI_MBCS)		+= mbcs.o
+obj-$(CONFIG_SERIAL_DEC)	+= decserial.o
 obj-$(CONFIG_BRIQ_PANEL)	+= briq_panel.o
 
 obj-$(CONFIG_PRINTER)		+= lp.o
@@ -80,6 +82,7 @@
 obj-$(CONFIG_DS1620)		+= ds1620.o
 obj-$(CONFIG_HW_RANDOM)		+= hw_random/
 obj-$(CONFIG_COBALT_LCD)	+= lcd.o
+obj-$(CONFIG_AU1000_GPIO)	+= au1000_gpio.o
 obj-$(CONFIG_PPDEV)		+= ppdev.o
 obj-$(CONFIG_NWBUTTON)		+= nwbutton.o
 obj-$(CONFIG_NWFLASH)		+= nwflash.o
diff -ruw linux-2.6.20.14/drivers/char/random.c linux-2.6.20.14-fbx/drivers/char/random.c
--- linux-2.6.20.14/drivers/char/random.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/drivers/char/random.c	2011-09-26 15:07:54.348835421 +0200
@@ -656,6 +656,13 @@
 	add_timer_randomness(irq_timer_state[irq], 0x100 + irq);
 }
 
+void add_raw_randomness(uint8_t *buf, int nbytes)
+{
+	add_entropy_words(&input_pool, (uint32_t *)buf, (nbytes + 3) / 4);
+	credit_entropy_store(&input_pool, nbytes);
+
+}
+
 #ifdef CONFIG_BLOCK
 void add_disk_randomness(struct gendisk *disk)
 {
diff -ruw linux-2.6.20.14/drivers/i2c/busses/Kconfig linux-2.6.20.14-fbx/drivers/i2c/busses/Kconfig
--- linux-2.6.20.14/drivers/i2c/busses/Kconfig	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/drivers/i2c/busses/Kconfig	2011-09-26 15:07:54.408835384 +0200
@@ -545,8 +545,8 @@
 	  time).  If unsure, say N.
 
 config I2C_MV64XXX
-	tristate "Marvell mv64xxx I2C Controller"
-	depends on I2C && MV64X60 && EXPERIMENTAL
+	tristate "Marvell mv64xxx/mv88fxx81 I2C Controller"
+	depends on I2C && (MV64X60 || ARCH_MV88FXX81) && EXPERIMENTAL
 	help
 	  If you say yes to this option, support will be included for the
 	  built-in I2C interface on the Marvell 64xxx line of host bridges.
@@ -564,4 +564,10 @@
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-pnx.
 
+config I2C_GPIO
+	tristate "GPIO I2C bus"
+	depends on I2C
+	select I2C_ALGOBIT
+	default n
+
 endmenu
diff -ruw linux-2.6.20.14/drivers/i2c/busses/Makefile linux-2.6.20.14-fbx/drivers/i2c/busses/Makefile
--- linux-2.6.20.14/drivers/i2c/busses/Makefile	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/drivers/i2c/busses/Makefile	2011-09-26 15:07:54.408835384 +0200
@@ -44,6 +44,7 @@
 obj-$(CONFIG_I2C_VIA)		+= i2c-via.o
 obj-$(CONFIG_I2C_VIAPRO)	+= i2c-viapro.o
 obj-$(CONFIG_I2C_VOODOO3)	+= i2c-voodoo3.o
+obj-$(CONFIG_I2C_GPIO)		+= i2c-gpio.o
 obj-$(CONFIG_SCx200_ACB)	+= scx200_acb.o
 obj-$(CONFIG_SCx200_I2C)	+= scx200_i2c.o
 
diff -ruw linux-2.6.20.14/drivers/ide/Kconfig linux-2.6.20.14-fbx/drivers/ide/Kconfig
--- linux-2.6.20.14/drivers/ide/Kconfig	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/drivers/ide/Kconfig	2011-09-26 15:07:54.418835377 +0200
@@ -798,6 +798,16 @@
        default "128"
        depends on BLK_DEV_IDE_AU1XXX
 
+config BLK_DEV_IDE_TANGO2
+       select IDE_GENERIC
+       bool "IDE for SMP863x"
+       depends on TANGO2
+
+config BLK_DEV_IDE_TANGO2_DMA
+       bool "support DMA operations"
+       default y
+       depends on BLK_DEV_IDE_TANGO2
+
 config IDE_ARM
 	def_bool ARM && (ARCH_A5K || ARCH_CLPS7500 || ARCH_RPC || ARCH_SHARK)
 
@@ -925,6 +935,12 @@
 
 	  If unsure, say N.
 
+config BLK_DEV_MMIOIDE
+	tristate "Memory Mapped IDE support"
+	help
+	  This is the IDE driver for Memory Mapped IDE devices. Like
+	  Compact Flash running in True IDE mode.
+
 choice
 	prompt "Type of MPC8xx IDE interface"
 	depends on BLK_DEV_MPC8xx_IDE
@@ -1033,7 +1049,7 @@
 endif
 
 config BLK_DEV_IDEDMA
-	def_bool BLK_DEV_IDEDMA_PCI || BLK_DEV_IDEDMA_PMAC || BLK_DEV_IDEDMA_ICS || BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
+	def_bool BLK_DEV_IDEDMA_PCI || BLK_DEV_IDEDMA_PMAC || BLK_DEV_IDEDMA_ICS || BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA || BLK_DEV_IDE_TANGO2_DMA
 
 config IDEDMA_IVB
 	bool "IGNORE word93 Validation BITS"
@@ -1052,7 +1068,7 @@
 	  It is normally safe to answer Y; however, the default is N.
 
 config IDEDMA_AUTO
-	def_bool IDEDMA_PCI_AUTO || IDEDMA_ICS_AUTO
+	def_bool IDEDMA_PCI_AUTO || IDEDMA_ICS_AUTO || BLK_DEV_IDE_TANGO2_DMA
 
 endif
 
diff -ruw linux-2.6.20.14/drivers/ide/legacy/Makefile linux-2.6.20.14-fbx/drivers/ide/legacy/Makefile
--- linux-2.6.20.14/drivers/ide/legacy/Makefile	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/drivers/ide/legacy/Makefile	2011-09-26 15:07:54.418835377 +0200
@@ -7,6 +7,8 @@
 
 obj-$(CONFIG_BLK_DEV_IDECS)		+= ide-cs.o
 
+obj-$(CONFIG_BLK_DEV_MMIOIDE)		+= mmio-ide.o
+
 # Last of all
 obj-$(CONFIG_BLK_DEV_HD)		+= hd.o
 
diff -ruw linux-2.6.20.14/drivers/ide/Makefile linux-2.6.20.14-fbx/drivers/ide/Makefile
--- linux-2.6.20.14/drivers/ide/Makefile	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/drivers/ide/Makefile	2011-09-26 15:07:54.418835377 +0200
@@ -40,6 +40,9 @@
 # built-in only drivers from h8300/
 ide-core-$(CONFIG_H8300)		+= h8300/ide-h8300.o
 
+# built-in only driver for tango2/
+ide-core-$(CONFIG_BLK_DEV_IDE_TANGO2)	+= tango2/tango2-ide.o
+
 obj-$(CONFIG_BLK_DEV_IDE)		+= ide-core.o
 obj-$(CONFIG_IDE_GENERIC)		+= ide-generic.o
 
diff -ruw linux-2.6.20.14/drivers/ide/mips/Makefile linux-2.6.20.14-fbx/drivers/ide/mips/Makefile
--- linux-2.6.20.14/drivers/ide/mips/Makefile	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/drivers/ide/mips/Makefile	2011-09-26 15:07:54.428835371 +0200
@@ -1,4 +1,4 @@
 obj-$(CONFIG_BLK_DEV_IDE_SWARM)		+= swarm.o
 obj-$(CONFIG_BLK_DEV_IDE_AU1XXX)	+= au1xxx-ide.o
 
-EXTRA_CFLAGS    := -Idrivers/ide
+CFLAGS_au1xxx-ide.o := -Idrivers/ide
diff -ruw linux-2.6.20.14/drivers/Kconfig linux-2.6.20.14-fbx/drivers/Kconfig
--- linux-2.6.20.14/drivers/Kconfig	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/drivers/Kconfig	2011-09-26 15:07:54.208835507 +0200
@@ -8,6 +8,18 @@
 
 source "drivers/mtd/Kconfig"
 
+source "drivers/fbxmtd/Kconfig"
+
+source "drivers/fbxdmamux/Kconfig"
+
+source "drivers/fbxgpio/Kconfig"
+
+source "drivers/fbxpanel/Kconfig"
+
+source "drivers/fbxspi/Kconfig"
+
+source "drivers/fbxwatchdog/Kconfig"
+
 source "drivers/parport/Kconfig"
 
 source "drivers/pnp/Kconfig"
@@ -78,6 +90,8 @@
 
 source "drivers/rtc/Kconfig"
 
+source "drivers/tango2/Kconfig"
+
 source "drivers/dma/Kconfig"
 
 source "drivers/kvm/Kconfig"
diff -ruw linux-2.6.20.14/drivers/leds/Kconfig linux-2.6.20.14-fbx/drivers/leds/Kconfig
--- linux-2.6.20.14/drivers/leds/Kconfig	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/drivers/leds/Kconfig	2011-09-26 15:07:54.538835305 +0200
@@ -115,5 +115,12 @@
 	  load average.
 	  If unsure, say Y.
 
+config LEDS_TRIGGER_NETDEV
+	tristate "LED netdev Trigger"
+	depends on LEDS_TRIGGERS
+	help
+	  This allows LEDs to be controlled by a given network device
+	  activity.
+
 endmenu
 
diff -ruw linux-2.6.20.14/drivers/leds/Makefile linux-2.6.20.14-fbx/drivers/leds/Makefile
--- linux-2.6.20.14/drivers/leds/Makefile	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/drivers/leds/Makefile	2011-09-26 15:07:54.538835305 +0200
@@ -19,3 +19,4 @@
 obj-$(CONFIG_LEDS_TRIGGER_TIMER)	+= ledtrig-timer.o
 obj-$(CONFIG_LEDS_TRIGGER_IDE_DISK)	+= ledtrig-ide-disk.o
 obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT)	+= ledtrig-heartbeat.o
+obj-$(CONFIG_LEDS_TRIGGER_NETDEV)	+= ledtrig-netdev.o
diff -ruw linux-2.6.20.14/drivers/Makefile linux-2.6.20.14-fbx/drivers/Makefile
--- linux-2.6.20.14/drivers/Makefile	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/drivers/Makefile	2011-09-26 15:07:54.208835507 +0200
@@ -39,6 +39,12 @@
 obj-$(CONFIG_IEEE1394)		+= ieee1394/
 obj-y				+= cdrom/
 obj-$(CONFIG_MTD)		+= mtd/
+obj-$(CONFIG_FREEBOX_MTD)	+= fbxmtd/
+obj-$(CONFIG_FREEBOX_GPIO)	+= fbxgpio/
+obj-$(CONFIG_FREEBOX_DMAMUX)	+= fbxdmamux/
+obj-$(CONFIG_FREEBOX_PANEL)	+= fbxpanel/
+obj-$(CONFIG_FREEBOX_SPI)	+= fbxspi/
+obj-$(CONFIG_FREEBOX_WATCHDOG)	+= fbxwatchdog/
 obj-$(CONFIG_SPI)		+= spi/
 obj-$(CONFIG_PCCARD)		+= pcmcia/
 obj-$(CONFIG_DIO)		+= dio/
@@ -80,3 +86,4 @@
 obj-$(CONFIG_DMA_ENGINE)	+= dma/
 obj-$(CONFIG_HID)		+= hid/
 obj-$(CONFIG_PPC_PS3)		+= ps3/
+obj-$(CONFIG_TANGO2)		+= tango2/
diff -ruw linux-2.6.20.14/drivers/media/dvb/Kconfig linux-2.6.20.14-fbx/drivers/media/dvb/Kconfig
--- linux-2.6.20.14/drivers/media/dvb/Kconfig	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/drivers/media/dvb/Kconfig	2011-09-26 15:07:54.558835293 +0200
@@ -44,6 +44,12 @@
 	depends on DVB_CORE && PCI && I2C
 source "drivers/media/dvb/pluto2/Kconfig"
 
+# Start Freebox added code
+comment "Supported Tango2 Adapters"
+	depends on DVB_CORE && ARCH_FBX5_B
+source "drivers/media/dvb/tango2/Kconfig"
+# End Freebox added code
+
 comment "Supported DVB Frontends"
 	depends on DVB_CORE
 source "drivers/media/dvb/frontends/Kconfig"
diff -ruw linux-2.6.20.14/drivers/media/dvb/Makefile linux-2.6.20.14-fbx/drivers/media/dvb/Makefile
--- linux-2.6.20.14/drivers/media/dvb/Makefile	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/drivers/media/dvb/Makefile	2011-09-26 15:07:54.558835293 +0200
@@ -2,4 +2,7 @@
 # Makefile for the kernel multimedia device drivers.
 #
 
-obj-y        := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ cinergyT2/ dvb-usb/ pluto2/
+# Start Freebox altered code
+#obj-y        := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ cinergyT2/ dvb-usb/ pluto2/
+obj-y        := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ cinergyT2/ dvb-usb/ pluto2/ tango2/
+# End Freebox altered code
diff -ruw linux-2.6.20.14/drivers/misc/Kconfig linux-2.6.20.14-fbx/drivers/misc/Kconfig
--- linux-2.6.20.14/drivers/misc/Kconfig	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/drivers/misc/Kconfig	2011-09-26 15:07:54.658835231 +0200
@@ -88,4 +88,14 @@
 
 	  If you have an MSI S270 laptop, say Y or M here.
 
+config CRASHZONE
+	bool "crashzone support"
+
+config BCM963XX_DSL_ALT
+	tristate "Support for 63xx DSL"
+	depends on BCM963XX
+	select FW_LOADER
+	select CRC_CCITT
+	select GENERIC_ALLOCATOR
+
 endmenu
diff -ruw linux-2.6.20.14/drivers/misc/Makefile linux-2.6.20.14-fbx/drivers/misc/Makefile
--- linux-2.6.20.14/drivers/misc/Makefile	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/drivers/misc/Makefile	2011-09-26 15:07:54.658835231 +0200
@@ -10,3 +10,5 @@
 obj-$(CONFIG_TIFM_CORE)       	+= tifm_core.o
 obj-$(CONFIG_TIFM_7XX1)       	+= tifm_7xx1.o
 obj-$(CONFIG_SGI_IOC4)		+= ioc4.o
+obj-$(CONFIG_CRASHZONE)		+= crash_zone.o
+obj-$(CONFIG_BCM963XX_DSL_ALT)	+= bcm963xx_dsl/
diff -ruw linux-2.6.20.14/drivers/net/Kconfig linux-2.6.20.14-fbx/drivers/net/Kconfig
--- linux-2.6.20.14/drivers/net/Kconfig	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/drivers/net/Kconfig	2011-09-26 15:07:54.688835213 +0200
@@ -452,6 +452,14 @@
 	  This is the driver for the onboard card of MIPS Magnum 4000,
 	  Acer PICA, Olivetti M700-10 and a few other identical OEM systems.
 
+config GALILEO_64240_ETH
+	tristate "Galileo GT64240 Ethernet support"
+	depends on NET_ETHERNET && MOMENCO_OCELOT_G
+	select MII
+	help
+	  This is the driver for the ethernet interfaces integrated into
+	  the Galileo (now Marvell) GT64240 chipset.
+
 config MIPS_AU1X00_ENET
 	bool "MIPS AU1000 Ethernet support"
 	depends on NET_ETHERNET && SOC_AU1X00
@@ -461,10 +469,6 @@
 	  If you have an Alchemy Semi AU1X00 based system
 	  say Y.  Otherwise, say N.
 
-config NET_SB1250_MAC
-	tristate "SB1250 Ethernet support"
-	depends on NET_ETHERNET && SIBYTE_SB1xxx_SOC
-
 config SGI_IOC3_ETH
 	bool "SGI IOC3 Ethernet"
 	depends on NET_ETHERNET && PCI && SGI_IP27
@@ -475,25 +479,13 @@
 	  the Ethernet-HOWTO, available from
 	  <http://www.tldp.org/docs.html#howto>.
 
-config SGI_IOC3_ETH_HW_RX_CSUM
-	bool "Receive hardware checksums"
-	depends on SGI_IOC3_ETH && INET
-	default y
-	help
-	  The SGI IOC3 network adapter supports TCP and UDP checksums in
-	  hardware to offload processing of these checksums from the CPU.  At
-	  the moment only acceleration of IPv4 is supported.  This option
-	  enables offloading for checksums on receive.  If unsure, say Y.
-
-config SGI_IOC3_ETH_HW_TX_CSUM
-	bool "Transmit hardware checksums"
-	depends on SGI_IOC3_ETH && INET
-	default y
+config MIPS_SIM_NET
+	tristate "MIPS simulator Network device (EXPERIMENTAL)"
+	depends on NETDEVICES && MIPS_SIM && EXPERIMENTAL
 	help
-	  The SGI IOC3 network adapter supports TCP and UDP checksums in
-	  hardware to offload processing of these checksums from the CPU.  At
-	  the moment only acceleration of IPv4 is supported.  This option
-	  enables offloading for checksums on transmit.  If unsure, say Y.
+	  The MIPSNET device is a simple Ethernet network device which is
+	  emulated by the MIPS Simulator.
+	  If you are not using a MIPSsim or are unsure, say N.
 
 config MIPS_SIM_NET
 	tristate "MIPS simulator Network device (EXPERIMENTAL)"
@@ -992,6 +984,20 @@
 	  <file:Documentation/networking/net-modules.txt>. The module
 	  will be called hp100.
 
+config BCM963XX_ENET
+	tristate "Broadcom 963xx internal mac support"
+	depends on NET_ETHERNET && BCM963XX
+	select MII
+	select PHYLIB
+	help
+	  If you have a network (Ethernet) controller of this type, say Y and
+	  read the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here and read
+	  <file:Documentation/networking/net-modules.txt>.  The module will be
+	  called bcm963xx_enet.
+
 config NET_ISA
 	bool "Other ISA cards"
 	depends on NET_ETHERNET && ISA
@@ -1280,6 +1286,28 @@
 	depends on IBM_EMAC && 440GX
 	default y
 
+config TANGO2_ENET
+	tristate "SMP863x Builtin Ethernet support"
+	depends on NET_ETHERNET && TANGO2
+	select MII
+	select CRC32
+	help
+	 This option adds support for the SMP863x integrated Ethernet
+	 controller.  This driver uses NAPI and generic Linux MII
+	 support.
+
+config TANGO2_ENET_FIFOCHECK
+	bool "warn when internal fifo overflows"
+	depends on TANGO2_ENET
+
+config TANGO2_ENET_OLD
+	tristate "SMP863x Builtin Ethernet support (old driver)"
+	depends on NET_ETHERNET && TANGO2
+	help
+	 This option adds support  for the SMP863x integrated Ethernet
+	 controller. This  is the orignal driver from  sigma with only
+	 small changes.
+
 config NET_PCI
 	bool "EISA, VLB, PCI and on board controllers"
 	depends on NET_ETHERNET && (ISA || EISA || PCI)
@@ -2012,6 +2040,14 @@
 	  To compile this driver as a module, choose M here: the module
 	  will be called myri_sbus.  This is recommended.
 
+config MV88FXX81_ETH
+	tristate "mv88fxx81 builtin Gigabit Ethernet support"
+	depends on ARCH_MV88FXX81
+	select MII
+	help
+	 This option adds support for the mv88Fxx81 integrated Ethernet
+	 controller.  This driver uses NAPI.
+
 config NS83820
 	tristate "National Semiconductor DP83820 support"
 	depends on PCI
@@ -2076,6 +2112,10 @@
 
 	  If in doubt, say N.
 
+config NET_SB1250_MAC
+	tristate "SB1250 Ethernet support"
+	depends on SIBYTE_SB1xxx_SOC
+
 config R8169_VLAN
 	bool "VLAN support"
 	depends on R8169 && VLAN_8021Q
@@ -2274,6 +2314,7 @@
 	tristate "Gianfar Ethernet"
 	depends on 85xx || 83xx || PPC_86xx
 	select PHYLIB
+	select CRC32
 	help
 	  This driver supports the Gigabit TSEC on the MPC83xx, MPC85xx,
 	  and MPC86xx family of chips, and the FEC on the 8540.
@@ -2315,8 +2356,8 @@
 	select MII
 	help
 	  This driver supports the gigabit Ethernet on the Marvell MV643XX
-	  chipset which is used in the Momenco Ocelot C and Jaguar ATX and
-	  Pegasos II, amongst other PPC and MIPS boards.
+	  chipset which is used in the Momenco Ocelot C Ocelot, Jaguar ATX
+	  and Pegasos II, amongst other PPC and MIPS boards.
 
 config MV643XX_ETH_0
 	bool "MV-643XX Port 0"
@@ -2339,6 +2380,20 @@
 	  This enables support for Port 2 of the Marvell MV643XX Gigabit
 	  Ethernet.
 
+config BIG_SUR_FE
+	bool "PMC-Sierra TITAN Fast Ethernet Support"
+	depends on NET_ETHERNET && PMC_BIG_SUR
+	help
+	  This enables support for the the integrated ethernet of
+	  PMC-Sierra's Big Sur SoC.
+
+config TITAN_GE
+	bool "PMC-Sierra TITAN Gigabit Ethernet Support"
+	depends on PMC_YOSEMITE
+	help
+	  This enables support for the the integrated ethernet of
+	  PMC-Sierra's Titan SoC.
+
 config QLA3XXX
 	tristate "QLogic QLA3XXX Network Driver Support"
 	depends on PCI
@@ -2766,9 +2821,13 @@
 	 See http://pptpclient.sourceforge.net/ for information on
 	 configuring PPTP clients and servers to utilize this method.
 
+config PPPOX
+	tristate "PPP over X"
+	depends on EXPERIMENTAL && PPP
+
 config PPPOE
 	tristate "PPP over Ethernet (EXPERIMENTAL)"
-	depends on EXPERIMENTAL && PPP
+	depends on PPPOX
 	help
 	  Support for PPP over Ethernet.
 
@@ -2915,4 +2974,16 @@
 config NET_POLL_CONTROLLER
 	def_bool NETPOLL
 
+config TANGO2_PCINET_H
+	tristate "SMP863x network over PCI support (smp863x side)"
+	depends on TANGO2
+
+config TANGO2_PCINET_D
+	tristate "SMP863x network over PCI support (agent side)"
+	depends on PCI
+
+config TANGO2_PCINET_D_DMAMUX
+	bool "use fbxdmamux for tx"
+	depends on TANGO2_PCINET_D && FREEBOX_DMAMUX
+
 endmenu
diff -ruw linux-2.6.20.14/drivers/net/Makefile linux-2.6.20.14-fbx/drivers/net/Makefile
--- linux-2.6.20.14/drivers/net/Makefile	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/drivers/net/Makefile	2011-09-26 15:07:54.688835213 +0200
@@ -77,6 +77,11 @@
 obj-$(CONFIG_MII) += mii.o
 obj-$(CONFIG_PHYLIB) += phy/
 
+obj-$(CONFIG_TANGO2_ENET) += tango2_enet.o
+obj-$(CONFIG_TANGO2_ENET_OLD) += tango2_enet_old.o
+obj-$(CONFIG_TANGO2_PCINET_H) += tango2_pcinet_h.o
+obj-$(CONFIG_TANGO2_PCINET_D) += tango2_pcinet_d.o
+obj-$(CONFIG_MV88FXX81_ETH) += mv88fxx81_eth.o
 obj-$(CONFIG_SUNDANCE) += sundance.o
 obj-$(CONFIG_HAMACHI) += hamachi.o
 obj-$(CONFIG_NET) += Space.o loopback.o
@@ -87,6 +92,7 @@
 obj-$(CONFIG_PCMCIA_PCNET) += 8390.o
 obj-$(CONFIG_SHAPER) += shaper.o
 obj-$(CONFIG_HP100) += hp100.o
+obj-$(CONFIG_BCM963XX_ENET) += bcm963xx_enet.o
 obj-$(CONFIG_SMC9194) += smc9194.o
 obj-$(CONFIG_FEC) += fec.o
 obj-$(CONFIG_68360_ENET) += 68360enet.o
@@ -112,13 +118,18 @@
 obj-$(CONFIG_MV643XX_ETH) += mv643xx_eth.o
 obj-$(CONFIG_QLA3XXX) += qla3xxx.o
 
+obj-$(CONFIG_GALILEO_64240_ETH) += gt64240eth.o
+obj-$(CONFIG_BIG_SUR_FE) += big_sur_ge.o
+obj-$(CONFIG_TITAN_GE) += titan_mdio.o titan_ge.o
+
 obj-$(CONFIG_PPP) += ppp_generic.o
 obj-$(CONFIG_PPP_ASYNC) += ppp_async.o
 obj-$(CONFIG_PPP_SYNC_TTY) += ppp_synctty.o
 obj-$(CONFIG_PPP_DEFLATE) += ppp_deflate.o
 obj-$(CONFIG_PPP_BSDCOMP) += bsd_comp.o
 obj-$(CONFIG_PPP_MPPE) += ppp_mppe.o
-obj-$(CONFIG_PPPOE) += pppox.o pppoe.o
+obj-$(CONFIG_PPPOX) += pppox.o
+obj-$(CONFIG_PPPOE) += pppoe.o
 
 obj-$(CONFIG_SLIP) += slip.o
 obj-$(CONFIG_SLHC) += slhc.o
diff -ruw linux-2.6.20.14/drivers/net/phy/broadcom.c linux-2.6.20.14-fbx/drivers/net/phy/broadcom.c
--- linux-2.6.20.14/drivers/net/phy/broadcom.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/drivers/net/phy/broadcom.c	2011-09-26 15:07:54.788835151 +0200
@@ -4,6 +4,8 @@
  *	Broadcom BCM5411, BCM5421 and BCM5461 Gigabit Ethernet
  *	transceivers.
  *
+ *	Broadcom BCM963xx integrated transceiver.
+ *
  *	Copyright (c) 2006  Maciej W. Rozycki
  *
  *	Inspired by code written by Amy Fong.
@@ -17,6 +19,9 @@
 #include <linux/module.h>
 #include <linux/phy.h>
 
+/*
+ * BCM54xx PHY
+ */
 #define MII_BCM54XX_ECR		0x10	/* BCM54xx extended control register */
 #define MII_BCM54XX_ECR_IM	0x1000	/* Interrupt mask */
 #define MII_BCM54XX_ECR_IF	0x0800	/* Interrupt force */
@@ -42,10 +47,23 @@
 #define MII_BCM54XX_INT_MDIX	0x2000	/* MDIX status change */
 #define MII_BCM54XX_INT_PSERR	0x4000	/* Pair swap error */
 
+/*
+ * BCM963xx integrated PHY
+ */
+#define MII_BCM963XX_IR		0x1a	/* interrupt register */
+#define MII_BCM963XX_IR_EN	0x4000	/* global interrupt enable */
+#define MII_BCM963XX_IR_DUPLEX	0x0800	/* duplex changed */
+#define MII_BCM963XX_IR_SPEED	0x0400	/* speed changed */
+#define MII_BCM963XX_IR_LINK	0x0200	/* link changed */
+#define MII_BCM963XX_IR_GMASK	0x0100	/* global interrupt mask */
+
 MODULE_DESCRIPTION("Broadcom PHY driver");
 MODULE_AUTHOR("Maciej W. Rozycki");
 MODULE_LICENSE("GPL");
 
+/*
+ * BCM54xx PHY
+ */
 static int bcm54xx_config_init(struct phy_device *phydev)
 {
 	int reg, err;
@@ -141,6 +159,91 @@
 	.driver 	= { .owner = THIS_MODULE },
 };
 
+/*
+ * BCM963xx integrated PHY
+ */
+static int bcm963xx_config_init(struct phy_device *phydev)
+{
+	int reg, err;
+
+	reg = phy_read(phydev, MII_BCM963XX_IR);
+	if (reg < 0)
+		return reg;
+
+	/* Mask interrupts globally.  */
+	reg |= MII_BCM963XX_IR_GMASK;
+	err = phy_write(phydev, MII_BCM963XX_IR, reg);
+	if (err < 0)
+		return err;
+
+	/* Unmask events we are interested in  */
+	reg = ~(MII_BCM963XX_IR_DUPLEX |
+		MII_BCM963XX_IR_SPEED |
+		MII_BCM963XX_IR_LINK) |
+		MII_BCM963XX_IR_EN;
+	err = phy_write(phydev, MII_BCM963XX_IR, reg);
+	if (err < 0)
+		return err;
+	return 0;
+}
+
+static int bcm963xx_ack_interrupt(struct phy_device *phydev)
+{
+	int reg;
+
+	/* Clear pending interrupts.  */
+	reg = phy_read(phydev, MII_BCM963XX_IR);
+	if (reg < 0)
+		return reg;
+
+	return 0;
+}
+
+static int bcm963xx_config_intr(struct phy_device *phydev)
+{
+	int reg, err;
+
+	reg = phy_read(phydev, MII_BCM963XX_IR);
+	if (reg < 0)
+		return reg;
+
+	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+		reg &= ~MII_BCM963XX_IR_GMASK;
+	else
+		reg |= MII_BCM963XX_IR_GMASK;
+
+	err = phy_write(phydev, MII_BCM963XX_IR, reg);
+	return err;
+}
+
+static struct phy_driver bcm963xx_1_driver = {
+	.phy_id		= 0x00406000,
+	.phy_id_mask	= 0xfffffc00,
+	.name		= "Broadcom BCM963XX (1)",
+	/* ASYM_PAUSE bit is marked RO in datasheet, so don't cheat */
+	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause),
+	.config_init	= bcm963xx_config_init,
+	.config_aneg	= genphy_config_aneg,
+	.read_status	= genphy_read_status,
+	.ack_interrupt	= bcm963xx_ack_interrupt,
+	.config_intr	= bcm963xx_config_intr,
+	.driver		= { .owner = THIS_MODULE },
+};
+
+/* same phy as above, with just a different OUI */
+static struct phy_driver bcm963xx_2_driver = {
+	.phy_id		= 0x002bdc00,
+	.phy_id_mask	= 0xfffffc00,
+	.name		= "Broadcom BCM963XX (2)",
+	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause),
+	.config_init	= bcm963xx_config_init,
+	.config_aneg	= genphy_config_aneg,
+	.read_status	= genphy_read_status,
+	.ack_interrupt	= bcm963xx_ack_interrupt,
+	.config_intr	= bcm963xx_config_intr,
+	.driver		= { .owner = THIS_MODULE },
+};
+
 static int __init broadcom_init(void)
 {
 	int ret;
@@ -154,8 +257,18 @@
 	ret = phy_driver_register(&bcm5461_driver);
 	if (ret)
 		goto out_5461;
+	ret = phy_driver_register(&bcm963xx_1_driver);
+	if (ret)
+		goto out_963xx_1;
+	ret = phy_driver_register(&bcm963xx_2_driver);
+	if (ret)
+		goto out_963xx_2;
 	return ret;
 
+out_963xx_2:
+	phy_driver_unregister(&bcm963xx_1_driver);
+out_963xx_1:
+	phy_driver_unregister(&bcm5461_driver);
 out_5461:
 	phy_driver_unregister(&bcm5421_driver);
 out_5421:
@@ -169,6 +282,8 @@
 	phy_driver_unregister(&bcm5461_driver);
 	phy_driver_unregister(&bcm5421_driver);
 	phy_driver_unregister(&bcm5411_driver);
+	phy_driver_unregister(&bcm963xx_1_driver);
+	phy_driver_unregister(&bcm963xx_2_driver);
 }
 
 module_init(broadcom_init);
diff -ruw linux-2.6.20.14/drivers/net/phy/phy.c linux-2.6.20.14-fbx/drivers/net/phy/phy.c
--- linux-2.6.20.14/drivers/net/phy/phy.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/drivers/net/phy/phy.c	2011-09-26 15:07:54.788835151 +0200
@@ -358,6 +358,8 @@
 
 	return 0;
 }
+EXPORT_SYMBOL(phy_mii_ioctl);
+
 
 /* phy_start_aneg
  *
@@ -610,8 +612,10 @@
 		goto phy_err;
 
 	spin_lock(&phydev->lock);
-	if ((PHY_RUNNING == phydev->state) || (PHY_NOLINK == phydev->state))
+	if ((PHY_RUNNING == phydev->state) || (PHY_NOLINK == phydev->state)) {
 		phydev->state = PHY_CHANGELINK;
+		mod_timer(&phydev->phy_timer, jiffies);
+	}
 	spin_unlock(&phydev->lock);
 
 	enable_irq(phydev->irq);
@@ -768,6 +772,9 @@
 			}
 			break;
 		case PHY_NOLINK:
+			/* don't poll if interrupt */
+			if (PHY_POLL != phydev->irq)
+				break;
 			err = phy_read_status(phydev);
 
 			if (err)
diff -ruw linux-2.6.20.14/drivers/net/ppp_generic.c linux-2.6.20.14-fbx/drivers/net/ppp_generic.c
--- linux-2.6.20.14/drivers/net/ppp_generic.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/drivers/net/ppp_generic.c	2011-09-26 15:07:54.788835151 +0200
@@ -158,6 +158,9 @@
 	struct ppp	*ppp;		/* ppp unit we're connected to */
 	struct list_head clist;		/* link in list of channels per unit */
 	rwlock_t	upl;		/* protects `ppp' */
+	/* Start Freebox added code */
+	int		stopped;
+	/* End Freebox added code */
 #ifdef CONFIG_PPP_MULTILINK
 	u8		avail;		/* flag used in multilink stuff */
 	u8		had_frag;	/* >= 1 fragments have been sent */
@@ -1011,8 +1014,23 @@
 			ppp_send_frame(ppp, skb);
 		/* If there's no work left to do, tell the core net
 		   code that we can accept some more. */
-		if (ppp->xmit_pending == 0 && skb_peek(&ppp->file.xq) == 0)
+		if (ppp->xmit_pending == 0 && skb_peek(&ppp->file.xq) == 0) {
+			/* Start Freebox added code */
+			/* only  enable  net  queue  if at  least  one
+			 * channel is not stopped */
+			struct list_head *list;
+			struct channel *pch;
+
+			list = &ppp->channels;
+			while ((list = list->next) != &ppp->channels) {
+				pch = list_entry(list, struct channel, clist);
+				if (!pch->stopped) {
 			netif_wake_queue(ppp->dev);
+					break;
+				}
+			}
+			/* End Freebox added code */
+		}
 	}
 	ppp_xmit_unlock(ppp);
 }
@@ -2089,9 +2107,27 @@
 
 	if (pch == 0)
 		return;
+	/* Start Freebox added code */
+	pch->stopped = 0;
+	/* End Freebox added code */
 	ppp_channel_push(pch);
 }
 
+/* Start Freebox added code */
+/*
+ * Callback from a channel when it want to prevent further transmit on it
+ */
+void
+ppp_output_stop(struct ppp_channel *chan)
+{
+	struct channel *pch = chan->ppp;
+
+	if (pch == 0)
+		return;
+	pch->stopped = 1;
+}
+/* End Freebox added code */
+
 /*
  * Compression control.
  */
@@ -2807,6 +2843,9 @@
 EXPORT_SYMBOL(ppp_input);
 EXPORT_SYMBOL(ppp_input_error);
 EXPORT_SYMBOL(ppp_output_wakeup);
+/* Start Freebox added code */
+EXPORT_SYMBOL(ppp_output_stop);
+/* End Freebox added code */
 EXPORT_SYMBOL(ppp_register_compressor);
 EXPORT_SYMBOL(ppp_unregister_compressor);
 MODULE_LICENSE("GPL");
diff -ruw linux-2.6.20.14/drivers/net/wireless/hostap/Kconfig linux-2.6.20.14-fbx/drivers/net/wireless/hostap/Kconfig
--- linux-2.6.20.14/drivers/net/wireless/hostap/Kconfig	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/drivers/net/wireless/hostap/Kconfig	2011-09-26 15:07:54.878835097 +0200
@@ -85,3 +85,7 @@
 
 	The driver can be compiled as a module and will be named
 	"hostap_cs.ko".
+
+config HOSTAP_CS_FBXDMAMUX
+	bool "use fbxdmamux for data transfer"
+	depends on HOSTAP_CS
diff -ruw linux-2.6.20.14/drivers/pcmcia/Kconfig linux-2.6.20.14-fbx/drivers/pcmcia/Kconfig
--- linux-2.6.20.14/drivers/pcmcia/Kconfig	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/drivers/pcmcia/Kconfig	2011-09-26 15:07:54.918835071 +0200
@@ -197,6 +197,10 @@
 	tristate "Au1x00 pcmcia support"
 	depends on SOC_AU1X00 && PCMCIA
 
+config PCMCIA_BCM963XX
+	tristate "bcm963xx pcmcia support"
+	depends on BCM963XX && PCMCIA
+
 config PCMCIA_SA1100
 	tristate "SA1100 support"
 	depends on ARM && ARCH_SA1100 && PCMCIA
diff -ruw linux-2.6.20.14/drivers/pcmcia/Makefile linux-2.6.20.14-fbx/drivers/pcmcia/Makefile
--- linux-2.6.20.14/drivers/pcmcia/Makefile	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/drivers/pcmcia/Makefile	2011-09-26 15:07:54.928835065 +0200
@@ -33,6 +33,7 @@
 obj-$(CONFIG_M32R_PCC)				+= m32r_pcc.o
 obj-$(CONFIG_M32R_CFC)				+= m32r_cfc.o
 obj-$(CONFIG_PCMCIA_AU1X00)			+= au1x00_ss.o
+obj-$(CONFIG_PCMCIA_BCM963XX)			+= bcm963xx_pcmcia.o
 obj-$(CONFIG_PCMCIA_VRC4171)			+= vrc4171_card.o
 obj-$(CONFIG_PCMCIA_VRC4173)			+= vrc4173_cardu.o
 obj-$(CONFIG_OMAP_CF)				+= omap_cf.o
diff -ruw linux-2.6.20.14/drivers/serial/Kconfig linux-2.6.20.14-fbx/drivers/serial/Kconfig
--- linux-2.6.20.14/drivers/serial/Kconfig	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/drivers/serial/Kconfig	2011-09-26 15:07:55.088834967 +0200
@@ -686,6 +686,25 @@
 	depends on SERIAL_SH_SCI=y
 	select SERIAL_CORE_CONSOLE
 
+config SERIAL_IP3106
+	bool "Enable IP3106 UART Support (Philips PNX 8xx0 SoCs)"
+	depends on MIPS && (SOC_PNX8550 || SOC_PNX8330)
+	select SERIAL_CORE
+	help
+	  If you have a Philips SoC with an IP 3106 UART in it, such as
+	  the PNX8550 or PNX8330 (MIPS based) and you want to use
+	  serial ports, say Y.  Otherwise, say N.
+
+config SERIAL_IP3106_CONSOLE
+	bool "Enable PNX8XX0 serial console"
+	depends on SERIAL_IP3106
+	select SERIAL_CORE_CONSOLE
+	help
+	  If you have a Philips SoC with an IP 3106 UART in it, such as
+	  the PNX8550 or PNX8330 (MIPS based) and you want to use
+	  a serial console, say Y.
+	  Otherwise, say N.
+
 config SERIAL_CORE
 	tristate
 
@@ -994,4 +1013,23 @@
 	  If you have enabled the serial port on the Motorola IMX
 	  CPU you can make it the console by answering Y to this option.
 
+config SERIAL_BCM963XX
+	tristate "bcm963xx serial port support"
+	select SERIAL_CORE
+	depends on BCM963XX
+	help
+	  If you have a bcm963xx CPU, you can enable its onboard
+	  serial port by enabling this options.
+
+          To compile this driver as a module, choose M here: the
+          module will be called bcm963xx_uart.
+
+config SERIAL_BCM963XX_CONSOLE
+	bool "Console on bcm963xx serial port"
+	depends on SERIAL_BCM963XX=y
+	select SERIAL_CORE_CONSOLE
+	help
+	  If you have enabled the serial port on the bcm963xx CPU
+	  you can make it the console by answering Y to this option.
+
 endmenu
diff -ruw linux-2.6.20.14/drivers/serial/Makefile linux-2.6.20.14-fbx/drivers/serial/Makefile
--- linux-2.6.20.14/drivers/serial/Makefile	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/drivers/serial/Makefile	2011-09-26 15:07:55.088834967 +0200
@@ -40,6 +40,7 @@
 obj-$(CONFIG_V850E_UART) += v850e_uart.o
 obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o
 obj-$(CONFIG_SERIAL_LH7A40X) += serial_lh7a40x.o
+obj-$(CONFIG_SERIAL_IP3106) += ip3106_uart.o
 obj-$(CONFIG_SERIAL_DZ) += dz.o
 obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o
 obj-$(CONFIG_SERIAL_SGI_L1_CONSOLE) += sn_console.o
@@ -58,3 +59,4 @@
 obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o
 obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
 obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
+obj-$(CONFIG_SERIAL_BCM963XX) += bcm963xx_uart.o
diff -ruw linux-2.6.20.14/drivers/usb/gadget/Kconfig linux-2.6.20.14-fbx/drivers/usb/gadget/Kconfig
--- linux-2.6.20.14/drivers/usb/gadget/Kconfig	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/drivers/usb/gadget/Kconfig	2011-09-26 15:07:55.268834857 +0200
@@ -176,7 +176,28 @@
 	default USB_GADGET
 	select USB_GADGET_SELECTED
 
-config USB_OTG
+config USB_GADGET_BCM963xx
+	bool "BCM963xx USB Device Controller"
+	depends on BCM963xx
+
+config USB_BCM963xx
+	tristate
+	depends on USB_GADGET_BCM963xx
+	default USB_GADGET
+	select USB_GADGET_SELECTED
+
+config USB_GADGET_VOX160
+	boolean "IKANOS VX160"
+	help
+	   This driver provides USB Device Controller driver for IKanos's VX160
+
+config USB_VOX160
+	tristate
+	depends on USB_GADGET_VOX160
+	default USB_GADGET
+	select USB_GADGET_SELECTED
+
+config USB_OMAP_OTG
 	boolean "OTG Support"
 	depends on USB_GADGET_OMAP && ARCH_OMAP_OTG && USB_OHCI_HCD
 	help
diff -ruw linux-2.6.20.14/drivers/usb/gadget/Makefile linux-2.6.20.14-fbx/drivers/usb/gadget/Makefile
--- linux-2.6.20.14/drivers/usb/gadget/Makefile	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/drivers/usb/gadget/Makefile	2011-09-26 15:07:55.268834857 +0200
@@ -8,6 +8,8 @@
 obj-$(CONFIG_USB_OMAP)		+= omap_udc.o
 obj-$(CONFIG_USB_LH7A40X)	+= lh7a40x_udc.o
 obj-$(CONFIG_USB_AT91)		+= at91_udc.o
+obj-$(CONFIG_USB_BCM963xx)	+= bcm963xx_udc.o
+obj-$(CONFIG_USB_VOX160)	+= vox160_udc.o
 
 #
 # USB gadget drivers
diff -ruw linux-2.6.20.14/drivers/usb/host/Kconfig linux-2.6.20.14-fbx/drivers/usb/host/Kconfig
--- linux-2.6.20.14/drivers/usb/host/Kconfig	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/drivers/usb/host/Kconfig	2011-09-26 15:07:55.268834857 +0200
@@ -67,6 +67,11 @@
 
 	  If unsure, say N.
 
+config USB_EHCI_BIG_ENDIAN_MMIO
+	bool
+	depends on USB_EHCI_HCD
+	default n
+
 config USB_ISP116X_HCD
 	tristate "ISP116X HCD support"
 	depends on USB
@@ -123,7 +128,7 @@
 config USB_OHCI_LITTLE_ENDIAN
 	bool
 	depends on USB_OHCI_HCD
-	default n if STB03xxx || PPC_MPC52xx
+	default n if STB03xxx || PPC_MPC52xx || BCM963XX
 	default y
 
 config USB_UHCI_HCD
diff -ruw linux-2.6.20.14/drivers/usb/host/ohci.h linux-2.6.20.14-fbx/drivers/usb/host/ohci.h
--- linux-2.6.20.14/drivers/usb/host/ohci.h	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/drivers/usb/host/ohci.h	2011-09-26 15:07:55.278834851 +0200
@@ -396,6 +396,7 @@
 #define	OHCI_QUIRK_INITRESET	0x04			/* SiS, OPTi, ... */
 #define	OHCI_BIG_ENDIAN		0x08			/* big endian HC */
 #define	OHCI_QUIRK_ZFMICRO	0x10			/* Compaq ZFMicro chipset*/
+#define	OHCI_QUIRK_TANGO2	0x100
 	// there are also chip quirks/bugs in init logic
 
 };
@@ -461,6 +462,11 @@
 #define writel_be(val, addr)	out_be32((__force unsigned *)addr, val)
 #endif
 
+#if defined(CONFIG_MIPS)
+#define readl_be(addr)		__raw_readl(addr)
+#define writel_be(val, addr)	__raw_writel(val, addr)
+#endif
+
 static inline unsigned int ohci_readl (const struct ohci_hcd *ohci,
 							__hc32 __iomem * regs)
 {
diff -ruw linux-2.6.20.14/drivers/usb/host/ohci-hcd.c linux-2.6.20.14-fbx/drivers/usb/host/ohci-hcd.c
--- linux-2.6.20.14/drivers/usb/host/ohci-hcd.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/drivers/usb/host/ohci-hcd.c	2011-09-26 15:07:55.278834851 +0200
@@ -79,6 +79,7 @@
 
 static void ohci_dump (struct ohci_hcd *ohci, int verbose);
 static int ohci_init (struct ohci_hcd *ohci);
+static void ohci_poll (unsigned long data);
 static void ohci_stop (struct usb_hcd *hcd);
 
 #include "ohci-hub.c"
@@ -109,6 +110,13 @@
 module_param (no_handshake, bool, 0);
 MODULE_PARM_DESC (no_handshake, "true (not default) disables BIOS handshake");
 
+/* polling timer to wake up ohci */
+static struct timer_list ohci_timer;
+static int polling_scale = 1;
+static int polling_interval_min = 1;
+static int polling_interval_max = HZ;
+static unsigned int polling_interval = 1;
+
 /*-------------------------------------------------------------------------*/
 
 /*
@@ -190,11 +198,13 @@
 
 	spin_lock_irqsave (&ohci->lock, flags);
 
+	if (!(ohci->flags & OHCI_QUIRK_TANGO2)) {
 	/* don't submit to a dead HC */
 	if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
 		retval = -ENODEV;
 		goto fail;
 	}
+	}
 	if (!HC_IS_RUNNING(hcd->state)) {
 		retval = -ENODEV;
 		goto fail;
@@ -626,6 +636,13 @@
 	mdelay ((temp >> 23) & 0x1fe);
 	hcd->state = HC_STATE_RUNNING;
 
+	if (ohci->flags & OHCI_QUIRK_TANGO2) {
+		init_timer(&ohci_timer);
+		ohci_timer.function = ohci_poll;
+		ohci_timer.data = (unsigned long)hcd;
+		mod_timer(&ohci_timer, jiffies + polling_interval);
+	}
+
 	ohci_dump (ohci, 1);
 
 	return 0;
@@ -656,9 +673,18 @@
 
 	/* interrupt for some other device? */
 	} else if ((ints &= ohci_readl (ohci, &regs->intrenable)) == 0) {
+		if (ohci->flags & OHCI_QUIRK_TANGO2) {
+			polling_interval <<= polling_scale;
+			/* poll at least once per second */
+			if (polling_interval > polling_interval_max)
+				polling_interval = polling_interval_max;
+		}
 		return IRQ_NOTMINE;
 	}
 
+	if (ohci->flags & OHCI_QUIRK_TANGO2)
+		polling_interval = polling_interval_min;
+
 	if (ints & OHCI_INTR_UE) {
 		disable (ohci);
 		ohci_err (ohci, "OHCI Unrecoverable Error, disabled\n");
@@ -735,6 +761,19 @@
 	return IRQ_HANDLED;
 }
 
+static void ohci_poll (unsigned long data)
+{
+	unsigned long flags;
+	struct usb_hcd *hcd = (struct usb_hcd *)data;
+
+	local_save_flags(flags);
+	ohci_irq (hcd);
+	local_irq_restore(flags);
+	mod_timer(&ohci_timer, jiffies + polling_interval);
+
+	return;
+}
+
 /*-------------------------------------------------------------------------*/
 
 static void ohci_stop (struct usb_hcd *hcd)
@@ -762,6 +801,9 @@
 		ohci->hcca = NULL;
 		ohci->hcca_dma = 0;
 	}
+
+	if (ohci->flags & OHCI_QUIRK_TANGO2)
+		del_timer_sync(&ohci_timer);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -855,63 +897,135 @@
 
 #ifdef CONFIG_PCI
 #include "ohci-pci.c"
+#define PCI_DRIVER		ohci_pci_driver
 #endif
 
 #ifdef CONFIG_SA1111
 #include "ohci-sa1111.c"
+#define SA1111_DRIVER		ohci_hcd_sa1111_driver
 #endif
 
 #ifdef CONFIG_ARCH_S3C2410
 #include "ohci-s3c2410.c"
+#define PLATFORM_DRIVER		ohci_hcd_s3c2410_driver
 #endif
 
 #ifdef CONFIG_ARCH_OMAP
 #include "ohci-omap.c"
+#define PLATFORM_DRIVER		ohci_hcd_omap_driver
 #endif
 
 #ifdef CONFIG_ARCH_LH7A404
 #include "ohci-lh7a404.c"
+#define PLATFORM_DRIVER		ohci_hcd_lh7a404_driver
 #endif
 
 #ifdef CONFIG_PXA27x
 #include "ohci-pxa27x.c"
+#define PLATFORM_DRIVER		ohci_hcd_pxa27x_driver
 #endif
 
 #ifdef CONFIG_ARCH_EP93XX
 #include "ohci-ep93xx.c"
+#define PLATFORM_DRIVER		ohci_hcd_ep93xx_driver
 #endif
 
 #ifdef CONFIG_SOC_AU1X00
 #include "ohci-au1xxx.c"
+#define PLATFORM_DRIVER		ohci_hcd_au1xxx_driver
 #endif
 
 #ifdef CONFIG_PNX8550
 #include "ohci-pnx8550.c"
+#define PLATFORM_DRIVER		ohci_hcd_pnx8550_driver
 #endif
 
 #ifdef CONFIG_USB_OHCI_HCD_PPC_SOC
 #include "ohci-ppc-soc.c"
+#define PLATFORM_DRIVER		ohci_hcd_ppc_soc_driver
 #endif
 
 #ifdef CONFIG_ARCH_AT91
 #include "ohci-at91.c"
+#define PLATFORM_DRIVER		ohci_hcd_at91_driver
 #endif
 
 #ifdef CONFIG_ARCH_PNX4008
 #include "ohci-pnx4008.c"
+#define PLATFORM_DRIVER		usb_hcd_pnx4008_driver
 #endif
 
-#if !(defined(CONFIG_PCI) \
-      || defined(CONFIG_SA1111) \
-      || defined(CONFIG_ARCH_S3C2410) \
-      || defined(CONFIG_ARCH_OMAP) \
-      || defined (CONFIG_ARCH_LH7A404) \
-      || defined (CONFIG_PXA27x) \
-      || defined (CONFIG_ARCH_EP93XX) \
-      || defined (CONFIG_SOC_AU1X00) \
-      || defined (CONFIG_USB_OHCI_HCD_PPC_SOC) \
-      || defined (CONFIG_ARCH_AT91) \
-      || defined (CONFIG_ARCH_PNX4008) \
-	)
+#ifdef CONFIG_BCM963XX
+#include "ohci-bcm963xx.c"
+#define PLATFORM_DRIVER		ohci_hcd_bcm963xx_driver
+#endif
+
+#if	!defined(PCI_DRIVER) &&		\
+	!defined(PLATFORM_DRIVER) &&	\
+	!defined(SA1111_DRIVER)
 #error "missing bus glue for ohci-hcd"
 #endif
+
+static int __init ohci_hcd_mod_init(void)
+{
+	int retval = 0;
+	int ls = 0;
+
+	if (usb_disabled())
+		return -ENODEV;
+
+	printk (KERN_DEBUG "%s: " DRIVER_INFO "\n", hcd_name);
+	pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name,
+		sizeof (struct ed), sizeof (struct td));
+
+#ifdef PLATFORM_DRIVER
+	retval = platform_driver_register(&PLATFORM_DRIVER);
+	if (retval < 0)
+		return retval;
+	ls++;
+#endif
+
+#ifdef SA1111_DRIVER
+	retval = sa1111_driver_register(&SA1111_DRIVER);
+	if (retval < 0)
+		goto error;
+	ls++;
+#endif
+
+#ifdef PCI_DRIVER
+	retval = pci_register_driver(&PCI_DRIVER);
+	if (retval < 0)
+		goto error;
+	ls++;
+#endif
+
+	return retval;
+
+	/* Error path */
+error:
+#ifdef PLATFORM_DRIVER
+	if (ls--)
+		platform_driver_unregister(&PLATFORM_DRIVER);
+#endif
+#ifdef SA1111_DRIVER
+	if (ls--)
+		sa1111_driver_unregister(&SA1111_DRIVER);
+#endif
+	return retval;
+}
+module_init(ohci_hcd_mod_init);
+
+static void __exit ohci_hcd_mod_exit(void)
+{
+#ifdef PCI_DRIVER
+	pci_unregister_driver(&PCI_DRIVER);
+#endif
+#ifdef SA1111_DRIVER
+	sa1111_driver_unregister(&SA1111_DRIVER);
+#endif
+#ifdef PLATFORM_DRIVER
+	platform_driver_unregister(&PLATFORM_DRIVER);
+#endif
+}
+module_exit(ohci_hcd_mod_exit);
+
diff -ruw linux-2.6.20.14/drivers/usb/host/ohci-pci.c linux-2.6.20.14-fbx/drivers/usb/host/ohci-pci.c
--- linux-2.6.20.14/drivers/usb/host/ohci-pci.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/drivers/usb/host/ohci-pci.c	2011-09-26 15:07:55.278834851 +0200
@@ -41,6 +41,15 @@
 	if (hcd->self.controller) {
 		struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
 
+		/* Tango2's OHCI driver needs to be interrupted periodically,
+		 * to prevent waiting indefinitely for a message answer.
+		 */
+		if (pdev->vendor == PCI_VENDOR_ID_SIGMADES
+				&& pdev->device == 0x1234) {
+			ohci->flags = OHCI_QUIRK_TANGO2;
+			ohci_dbg (ohci, "Using Tango2 polling workaround\n");
+		}
+
 		/* AMD 756, for most chips (early revs), corrupts register
 		 * values on read ... so enable the vendor workaround.
 		 */
@@ -238,23 +247,3 @@
 	.shutdown =	usb_hcd_pci_shutdown,
 };
 
-
-static int __init ohci_hcd_pci_init (void)
-{
-	printk (KERN_DEBUG "%s: " DRIVER_INFO " (PCI)\n", hcd_name);
-	if (usb_disabled())
-		return -ENODEV;
-
-	pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name,
-		sizeof (struct ed), sizeof (struct td));
-	return pci_register_driver (&ohci_pci_driver);
-}
-module_init (ohci_hcd_pci_init);
-
-/*-------------------------------------------------------------------------*/
-
-static void __exit ohci_hcd_pci_cleanup (void)
-{
-	pci_unregister_driver (&ohci_pci_driver);
-}
-module_exit (ohci_hcd_pci_cleanup);
diff -ruw linux-2.6.20.14/drivers/usb/serial/cp2101.c linux-2.6.20.14-fbx/drivers/usb/serial/cp2101.c
--- linux-2.6.20.14/drivers/usb/serial/cp2101.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/drivers/usb/serial/cp2101.c	2011-09-26 15:07:55.308834833 +0200
@@ -71,6 +71,7 @@
 	{ USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */
 	{ USB_DEVICE(0x13AD, 0x9999) }, /* Baltech card reader */
 	{ USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */
+	{ USB_DEVICE(0x0489, 0xE003) }, /* Pirelli Wifi/GSM phone */
 	{ } /* Terminating Entry */
 };
 
diff -ruw linux-2.6.20.14/drivers/video/Kconfig linux-2.6.20.14-fbx/drivers/video/Kconfig
--- linux-2.6.20.14/drivers/video/Kconfig	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/drivers/video/Kconfig	2011-09-26 15:07:55.338834815 +0200
@@ -1281,6 +1281,17 @@
 	  Please read the <file:Documentation/fb/README-sstfb.txt> for supported
 	  options and other important info  support.
 
+config FB_SMIVGX
+	tristate "Silicon Motion VoyagerGX support"
+	depends on FB && PCI && (MIPS || EXPERIMENTAL)
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	---help---
+	  This drivers supports SMI VoyagerGX 501 based PCI boards
+	  The default settings drive both a CRT and LCD.  The CRT
+	  can be turned off by passing in the no_crt option
+
 config FB_CYBLA
 	tristate "Cyberblade/i1 support"
 	depends on FB && PCI && X86_32 && !64BIT
@@ -1345,7 +1356,25 @@
 
 config FB_AU1100
 	bool "Au1100 LCD Driver"
-	depends on (FB = y) && EXPERIMENTAL && PCI && MIPS && MIPS_PB1100=y
+	depends on FB && MIPS && SOC_AU1100
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	help
+	  This is the framebuffer driver for the AMD Au1100 SOC.  It can drive
+	  various panels and CRTs by passing in kernel cmd line option
+	  au1100fb:panel=<name>.
+
+config FB_AU1200
+	bool "Au1200 LCD Driver"
+	depends on FB && MIPS && SOC_AU1200
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	help
+	  This is the framebuffer driver for the AMD Au1200 SOC.  It can drive
+	  various panels and CRTs by passing in kernel cmd line option
+	  au1200fb:panel=<name>.
 
 config FB_AU1200
 	bool "Au1200 LCD Driver"
diff -ruw linux-2.6.20.14/drivers/video/Makefile linux-2.6.20.14-fbx/drivers/video/Makefile
--- linux-2.6.20.14/drivers/video/Makefile	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/drivers/video/Makefile	2011-09-26 15:07:55.338834815 +0200
@@ -96,6 +96,7 @@
 obj-$(CONFIG_FB_TX3912)		  += tx3912fb.o
 obj-$(CONFIG_FB_S1D13XXX)	  += s1d13xxxfb.o
 obj-$(CONFIG_FB_IMX)              += imxfb.o
+obj-$(CONFIG_FB_SMIVGX)		  += smivgxfb.o
 obj-$(CONFIG_FB_S3C2410)	  += s3c2410fb.o
 obj-$(CONFIG_FB_PNX4008_DUM)	  += pnx4008/
 obj-$(CONFIG_FB_PNX4008_DUM_RGB)  += pnx4008/
diff -ruw linux-2.6.20.14/fs/exec.c linux-2.6.20.14-fbx/fs/exec.c
--- linux-2.6.20.14/fs/exec.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/fs/exec.c	2011-09-26 15:07:55.868834489 +0200
@@ -1459,9 +1459,17 @@
 	return core_waiters;
 }
 
+#define CORE_ENV_MAX_ARGS 4
+
 int do_coredump(long signr, int exit_code, struct pt_regs * regs)
 {
 	char corename[CORENAME_MAX_SIZE + 1];
+	char *core_argv[2];
+	char *core_envp[CORE_ENV_MAX_ARGS + 1];
+	char core_pid[CORENAME_MAX_SIZE + 1];
+	char core_signal[CORENAME_MAX_SIZE + 1];
+	char core_time[CORENAME_MAX_SIZE + 1];
+	char core_comm[CORENAME_MAX_SIZE + 1];
 	struct mm_struct *mm = current->mm;
 	struct linux_binfmt * binfmt;
 	struct inode * inode;
@@ -1512,8 +1520,36 @@
 	ispipe = format_corename(corename, core_pattern, signr);
 	unlock_kernel();
  	if (ispipe) {
+		int i = 0;
+		struct timeval tv;
+
+#define CORE_ENV_ADD(__buf, __fmt, __arg)				\
+	do {								\
+		if (i < CORE_ENV_MAX_ARGS ) {				\
+			snprintf(__buf, sizeof(__buf), __fmt, __arg);	\
+			core_envp[i++] = __buf;				\
+		} else							\
+			WARN_ON(1);					\
+	} while(0)
+
+		/* Create the env */
+		CORE_ENV_ADD(core_pid, "CORE_PID=%d", current->tgid);
+		CORE_ENV_ADD(core_signal, "CORE_SIGNAL=%ld", signr);
+		CORE_ENV_ADD(core_comm, "CORE_EXECUTABLE=%s", current->comm);
+
+		do_gettimeofday(&tv);
+		CORE_ENV_ADD(core_time, "CORE_TIME=%lu", tv.tv_sec);
+
+#undef CORE_ENV_ADD
+
+		core_envp[i] = NULL;
+
+		core_argv[0] = corename+1;
+		core_argv[1] = NULL;
+
 		/* SIGPIPE can happen, but it's just never processed */
- 		if(call_usermodehelper_pipe(corename+1, NULL, NULL, &file)) {
+ 		if (call_usermodehelper_pipe(core_argv[0], core_argv,
+					     core_envp, &file)) {
  			printk(KERN_INFO "Core dump to %s pipe failed\n",
 			       corename);
  			goto fail_unlock;
diff -ruw linux-2.6.20.14/fs/Kconfig linux-2.6.20.14-fbx/fs/Kconfig
--- linux-2.6.20.14/fs/Kconfig	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/fs/Kconfig	2011-09-26 15:07:55.828834515 +0200
@@ -1027,6 +1027,18 @@
 	  To compile this as a module, choose M here: the module will be called
 	  ramfs.
 
+config RAMFS_XATTR
+	bool
+	default n
+
+config RAMFS_XATTR_USER
+	bool "Enable user extended attributes on RAMFS filesystem"
+	default n
+	select RAMFS_XATTR
+	help
+	  Select this to enable extended user attributes on RAMFS
+	  filesystem.
+
 config CONFIGFS_FS
 	tristate "Userspace-driven configuration filesystem (EXPERIMENTAL)"
 	depends on SYSFS && EXPERIMENTAL
@@ -1404,6 +1416,73 @@
 
 	  If unsure, say N.
 
+config SQUASHFS
+	tristate "SquashFS 3.2 - Squashed file system support"
+	depends on BLOCK
+	select ZLIB_INFLATE
+	select SQLZMA_UNCOMP
+	help
+	  Saying Y here includes support for SquashFS 3.2 (a Compressed Read-Only File
+	  System).  Squashfs is a highly compressed read-only filesystem for Linux.
+	  It uses zlib compression to compress both files, inodes and directories.
+	  Inodes in the system are very small and all blocks are packed to minimise
+	  data overhead. Block sizes greater than 4K are supported up to a maximum of 64K.
+	  SquashFS 3.1 supports 64 bit filesystems and files (larger than 4GB), full
+	  uid/gid information, hard links and timestamps.
+
+	  Squashfs is intended for general read-only filesystem use, for archival
+	  use (i.e. in cases where a .tar.gz file may be used), and in embedded
+	  systems where low overhead is needed.  Further information and filesystem tools
+	  are available from http://squashfs.sourceforge.net.
+
+	  If you want to compile this as a module ( = code which can be
+	  inserted in and removed from the running kernel whenever you want),
+	  say M here and read <file:Documentation/modules.txt>.  The module
+	  will be called squashfs.  Note that the root file system (the one
+	  containing the directory /) cannot be compiled as a module.
+
+	  If unsure, say N.
+
+config SQUASHFS_EMBEDDED
+
+	bool "Additional options for memory-constrained systems" 
+	depends on SQUASHFS
+	default n
+	help
+	  Saying Y here allows you to specify cache sizes and how Squashfs
+	  allocates memory.  This is only intended for memory constrained
+	  systems.
+
+	  If unsure, say N.
+
+config SQUASHFS_FRAGMENT_CACHE_SIZE
+	int "Number of fragments cached" if SQUASHFS_EMBEDDED
+	depends on SQUASHFS
+	default "3"
+	help
+	  By default SquashFS caches the last 3 fragments read from
+	  the filesystem.  Increasing this amount may mean SquashFS
+	  has to re-read fragments less often from disk, at the expense
+	  of extra system memory.  Decreasing this amount will mean
+	  SquashFS uses less memory at the expense of extra reads from disk.
+
+	  Note there must be at least one cached fragment.  Anything
+	  much more than three will probably not make much difference.
+
+config SQUASHFS_VMALLOC
+	bool "Use Vmalloc rather than Kmalloc" if SQUASHFS_EMBEDDED
+	depends on SQUASHFS
+	default n
+	help
+	  By default SquashFS uses kmalloc to obtain fragment cache memory.
+	  Kmalloc memory is the standard kernel allocator, but it can fail
+	  on memory constrained systems.  Because of the way Vmalloc works,
+	  Vmalloc can succeed when kmalloc fails.  Specifying this option
+	  will make SquashFS always use Vmalloc to allocate the
+	  fragment cache memory.
+
+	  If unsure, say N.
+
 config VXFS_FS
 	tristate "FreeVxFS file system support (VERITAS VxFS(TM) compatible)"
 	depends on BLOCK
diff -ruw linux-2.6.20.14/fs/Makefile linux-2.6.20.14-fbx/fs/Makefile
--- linux-2.6.20.14/fs/Makefile	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/fs/Makefile	2011-09-26 15:07:55.828834515 +0200
@@ -68,6 +68,7 @@
 obj-$(CONFIG_JBD2)		+= jbd2/
 obj-$(CONFIG_EXT2_FS)		+= ext2/
 obj-$(CONFIG_CRAMFS)		+= cramfs/
+obj-$(CONFIG_SQUASHFS)		+= squashfs/
 obj-$(CONFIG_RAMFS)		+= ramfs/
 obj-$(CONFIG_HUGETLBFS)		+= hugetlbfs/
 obj-$(CONFIG_CODA_FS)		+= coda/
diff -ruw linux-2.6.20.14/fs/ramfs/file-mmu.c linux-2.6.20.14-fbx/fs/ramfs/file-mmu.c
--- linux-2.6.20.14/fs/ramfs/file-mmu.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/fs/ramfs/file-mmu.c	2011-09-26 15:07:55.988834417 +0200
@@ -26,6 +26,7 @@
 
 #include <linux/fs.h>
 #include <linux/mm.h>
+#include <linux/xattr.h>
 
 const struct address_space_operations ramfs_aops = {
 	.readpage	= simple_readpage,
@@ -47,4 +48,11 @@
 
 struct inode_operations ramfs_file_inode_operations = {
 	.getattr	= simple_getattr,
+#ifdef CONFIG_RAMFS_XATTR
+	.setxattr	= generic_setxattr,
+	.getxattr	= generic_getxattr,
+	.listxattr	= generic_listxattr,
+	.removexattr	= generic_removexattr,
+#endif
 };
+
diff -ruw linux-2.6.20.14/fs/ramfs/inode.c linux-2.6.20.14-fbx/fs/ramfs/inode.c
--- linux-2.6.20.14/fs/ramfs/inode.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/fs/ramfs/inode.c	2011-09-26 15:07:55.988834417 +0200
@@ -33,6 +33,7 @@
 #include <linux/smp_lock.h>
 #include <linux/backing-dev.h>
 #include <linux/ramfs.h>
+#include <linux/xattr.h>
 
 #include <asm/uaccess.h>
 #include "internal.h"
@@ -42,6 +43,7 @@
 
 static struct super_operations ramfs_ops;
 static struct inode_operations ramfs_dir_inode_operations;
+struct kmem_cache *ramfs_inode_cache;
 
 static struct backing_dev_info ramfs_backing_dev_info = {
 	.ra_pages	= 0,	/* No readahead */
@@ -50,6 +52,28 @@
 			  BDI_CAP_READ_MAP | BDI_CAP_WRITE_MAP | BDI_CAP_EXEC_MAP,
 };
 
+static struct inode *ramfs_alloc_inode(struct super_block *sb)
+{
+	struct ramfs_inode_info *rii;
+
+	rii = kmem_cache_alloc(ramfs_inode_cache, GFP_KERNEL);
+	if (!rii)
+		return NULL;
+	return &rii->vfs_inode;
+}
+
+static void ramfs_destroy_inode(struct inode *ino)
+{
+	struct ramfs_inode_info *rii;
+
+	rii = RAMFS_I(ino);
+
+#ifdef CONFIG_RAMFS_XATTR
+	ramfs_inode_purge_xattrs(rii);
+#endif
+	kmem_cache_free(ramfs_inode_cache, rii);
+}
+
 struct inode *ramfs_get_inode(struct super_block *sb, int mode, dev_t dev)
 {
 	struct inode * inode = new_inode(sb);
@@ -153,9 +177,17 @@
 	.rmdir		= simple_rmdir,
 	.mknod		= ramfs_mknod,
 	.rename		= simple_rename,
+#ifdef CONFIG_RAMFS_XATTR
+	.setxattr	= generic_setxattr,
+	.getxattr	= generic_getxattr,
+	.listxattr	= generic_listxattr,
+	.removexattr	= generic_removexattr,
+#endif
 };
 
 static struct super_operations ramfs_ops = {
+	.alloc_inode	= ramfs_alloc_inode,
+	.destroy_inode	= ramfs_destroy_inode,
 	.statfs		= simple_statfs,
 	.drop_inode	= generic_delete_inode,
 };
@@ -171,6 +203,9 @@
 	sb->s_magic = RAMFS_MAGIC;
 	sb->s_op = &ramfs_ops;
 	sb->s_time_gran = 1;
+#ifdef CONFIG_RAMFS_XATTR
+	sb->s_xattr = ramfs_xattr_handlers;
+#endif
 	inode = ramfs_get_inode(sb, S_IFDIR | 0755, 0);
 	if (!inode)
 		return -ENOMEM;
@@ -208,6 +243,21 @@
 	.kill_sb	= kill_litter_super,
 };
 
+static void ramfs_inode_init_once(void *ptr, struct kmem_cache *cachep,
+		      unsigned long flags)
+{
+	struct ramfs_inode_info *p = (struct ramfs_inode_info *)ptr;
+
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+	    SLAB_CTOR_CONSTRUCTOR) {
+		inode_init_once(&p->vfs_inode);
+#ifdef CONFIG_RAMFS_XATTR_USER
+		INIT_LIST_HEAD(&p->xattr_user_list);
+#endif
+	}
+}
+
+
 static int __init init_ramfs_fs(void)
 {
 	return register_filesystem(&ramfs_fs_type);
@@ -223,7 +273,20 @@
 
 int __init init_rootfs(void)
 {
-	return register_filesystem(&rootfs_fs_type);
+	int error;
+
+	ramfs_inode_cache = kmem_cache_create("ramfs_inode_cache",
+					      sizeof (struct ramfs_inode_info),
+					      0, 0, ramfs_inode_init_once,
+					      NULL);
+	if (!ramfs_inode_cache)
+		return -ENOMEM;
+
+	error = register_filesystem(&rootfs_fs_type);
+	if (error)
+		kmem_cache_destroy(ramfs_inode_cache);
+
+	return error;
 }
 
 MODULE_LICENSE("GPL");
diff -ruw linux-2.6.20.14/fs/ramfs/internal.h linux-2.6.20.14-fbx/fs/ramfs/internal.h
--- linux-2.6.20.14/fs/ramfs/internal.h	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/fs/ramfs/internal.h	2011-09-26 15:07:55.988834417 +0200
@@ -9,7 +9,42 @@
  * 2 of the License, or (at your option) any later version.
  */
 
+#ifndef RAMFS_INTERNAL_H
+# define RAMFS_INTERNALH
+
+/* need list_head */
+#include <linux/list.h>
 
 extern const struct address_space_operations ramfs_aops;
 extern const struct file_operations ramfs_file_operations;
 extern struct inode_operations ramfs_file_inode_operations;
+
+struct ramfs_xattr
+{
+	char *name;
+	void *data;
+	size_t data_len;
+
+	struct list_head list;
+};
+
+struct ramfs_inode_info
+{
+	struct inode vfs_inode;
+#ifdef CONFIG_RAMFS_XATTR_USER
+	struct list_head xattr_user_list;
+#endif
+};
+
+static inline struct ramfs_inode_info *RAMFS_I(struct inode *inode)
+{
+	return container_of(inode, struct ramfs_inode_info, vfs_inode);
+}
+
+#ifdef CONFIG_RAMFS_XATTR
+void ramfs_inode_purge_xattrs(struct ramfs_inode_info *rii);
+extern struct xattr_handler *ramfs_xattr_handlers[];
+#endif
+
+
+#endif /* !RAMFS_INTERNAL_H */
diff -ruw linux-2.6.20.14/fs/ramfs/Makefile linux-2.6.20.14-fbx/fs/ramfs/Makefile
--- linux-2.6.20.14/fs/ramfs/Makefile	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/fs/ramfs/Makefile	2011-09-26 15:07:55.988834417 +0200
@@ -6,4 +6,5 @@
 
 file-mmu-y := file-nommu.o
 file-mmu-$(CONFIG_MMU) := file-mmu.o
-ramfs-objs += inode.o $(file-mmu-y)
+ramfs-xattr-$(CONFIG_RAMFS_XATTR) += xattr.o
+ramfs-objs += inode.o $(file-mmu-y) $(ramfs-xattr-y)
diff -ruw linux-2.6.20.14/include/asm-generic/vmlinux.lds.h linux-2.6.20.14-fbx/include/asm-generic/vmlinux.lds.h
--- linux-2.6.20.14/include/asm-generic/vmlinux.lds.h	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/include/asm-generic/vmlinux.lds.h	2011-09-26 15:07:56.128834331 +0200
@@ -24,19 +24,19 @@
 	/* PCI quirks */						\
 	.pci_fixup        : AT(ADDR(.pci_fixup) - LOAD_OFFSET) {	\
 		VMLINUX_SYMBOL(__start_pci_fixups_early) = .;		\
-		*(.pci_fixup_early)					\
+		KEEP(*(.pci_fixup_early))				\
 		VMLINUX_SYMBOL(__end_pci_fixups_early) = .;		\
 		VMLINUX_SYMBOL(__start_pci_fixups_header) = .;		\
-		*(.pci_fixup_header)					\
+		KEEP(*(.pci_fixup_header))				\
 		VMLINUX_SYMBOL(__end_pci_fixups_header) = .;		\
 		VMLINUX_SYMBOL(__start_pci_fixups_final) = .;		\
-		*(.pci_fixup_final)					\
+		KEEP(*(.pci_fixup_final))				\
 		VMLINUX_SYMBOL(__end_pci_fixups_final) = .;		\
 		VMLINUX_SYMBOL(__start_pci_fixups_enable) = .;		\
-		*(.pci_fixup_enable)					\
+		KEEP(*(.pci_fixup_enable))				\
 		VMLINUX_SYMBOL(__end_pci_fixups_enable) = .;		\
 		VMLINUX_SYMBOL(__start_pci_fixups_resume) = .;		\
-		*(.pci_fixup_resume)					\
+		KEEP(*(.pci_fixup_resume))				\
 		VMLINUX_SYMBOL(__end_pci_fixups_resume) = .;		\
 	}								\
 									\
@@ -211,21 +211,20 @@
 		.notes : { *(.note.*) } :note
 
 #define INITCALLS							\
-  	*(.initcall0.init)						\
-  	*(.initcall0s.init)						\
-  	*(.initcall1.init)						\
-  	*(.initcall1s.init)						\
-  	*(.initcall2.init)						\
-  	*(.initcall2s.init)						\
-  	*(.initcall3.init)						\
-  	*(.initcall3s.init)						\
-  	*(.initcall4.init)						\
-  	*(.initcall4s.init)						\
-  	*(.initcall5.init)						\
-  	*(.initcall5s.init)						\
-	*(.initcallrootfs.init)						\
-  	*(.initcall6.init)						\
-  	*(.initcall6s.init)						\
-  	*(.initcall7.init)						\
-  	*(.initcall7s.init)
-
+  	KEEP(*(.initcall0.init))					\
+  	KEEP(*(.initcall0s.init))					\
+  	KEEP(*(.initcall1.init))					\
+  	KEEP(*(.initcall1s.init))					\
+  	KEEP(*(.initcall2.init))					\
+  	KEEP(*(.initcall2s.init))					\
+  	KEEP(*(.initcall3.init))					\
+  	KEEP(*(.initcall3s.init))					\
+  	KEEP(*(.initcall4.init))					\
+  	KEEP(*(.initcall4s.init))					\
+  	KEEP(*(.initcall5.init))					\
+  	KEEP(*(.initcall5s.init))					\
+	KEEP(*(.initcallrootfs.init))					\
+  	KEEP(*(.initcall6.init))					\
+  	KEEP(*(.initcall6s.init))					\
+  	KEEP(*(.initcall7.init))					\
+  	KEEP(*(.initcall7s.init))
diff -ruw linux-2.6.20.14/include/asm-mips/bootinfo.h linux-2.6.20.14-fbx/include/asm-mips/bootinfo.h
--- linux-2.6.20.14/include/asm-mips/bootinfo.h	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/include/asm-mips/bootinfo.h	2011-09-26 15:07:56.198834287 +0200
@@ -213,6 +213,27 @@
 #define MACH_GROUP_NEC_EMMA2RH 25	/* NEC EMMA2RH (was 23)		*/
 #define  MACH_NEC_MARKEINS	0	/* NEC EMMA2RH Mark-eins	*/
 
+
+/* Begin Freebox added code */
+
+/*
+ * Valid machtype for group BRCM
+ */
+#define MACH_GROUP_BRCM		23
+#define  MACH_BCM96338		1
+#define  MACH_BCM96345		2
+#define  MACH_BCM96348		3
+#define  MACH_BCM96358		4
+#define  MACH_BCM96368		5
+
+/* End Freebox added code */
+
+/*
+ * Valid machtype for group SIGMADESIGNS
+ */
+#define MACH_GROUP_SIGMADESIGNS	23	/* For SigmaDesigns Tango2 board */
+#define  MACH_TANGO2		 1	/* Tango2 */
+
 #define CL_SIZE			COMMAND_LINE_SIZE
 
 const char *get_system_type(void);
diff -ruw linux-2.6.20.14/include/asm-mips/bug.h linux-2.6.20.14-fbx/include/asm-mips/bug.h
--- linux-2.6.20.14/include/asm-mips/bug.h	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/include/asm-mips/bug.h	2011-09-26 15:07:56.198834287 +0200
@@ -18,7 +18,8 @@
 
 #define BUG_ON(condition)						\
 do {									\
-	__asm__ __volatile__("tne $0, %0" : : "r" (condition));		\
+	__asm__ __volatile__("tne $0, %0, %1"                           \
+			     : : "r" (condition), "i" (BRK_BUG));       \
 } while (0)
 
 #define HAVE_ARCH_BUG_ON
diff -ruw linux-2.6.20.14/include/asm-mips/cpu.h linux-2.6.20.14-fbx/include/asm-mips/cpu.h
--- linux-2.6.20.14/include/asm-mips/cpu.h	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/include/asm-mips/cpu.h	2011-09-26 15:07:56.208834281 +0200
@@ -90,6 +90,17 @@
 #define PRID_IMP_24KE		0x9600
 #define PRID_IMP_74K		0x9700
 
+/* Begin Freebox added code */
+
+#define PRID_IMP_BCM6338	0x9000
+#define PRID_IMP_BCM6345	0x8000
+#define PRID_IMP_BCM6348	0x9100
+#define PRID_IMP_BCM4350	0xA000
+#define PRID_REV_BCM6358	0x0010
+#define PRID_REV_BCM6368	0x0030
+
+/* End Freebox added code */
+
 /*
  * These are the PRID's for when 23:16 == PRID_COMP_SIBYTE
  */
@@ -200,7 +211,14 @@
 #define CPU_SB1A		62
 #define CPU_74K			63
 #define CPU_R14000		64
-#define CPU_LAST		64
+/* Begin Freebox added code */
+#define CPU_BCM6338		65
+#define CPU_BCM6345		66
+#define CPU_BCM6348		67
+#define CPU_BCM6358		68
+#define CPU_BCM6368		69
+/* End Freebox added code */
+#define CPU_LAST		69
 
 /*
  * ISA Level encodings
diff -ruw linux-2.6.20.14/include/asm-mips/dma.h linux-2.6.20.14-fbx/include/asm-mips/dma.h
--- linux-2.6.20.14/include/asm-mips/dma.h	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/include/asm-mips/dma.h	2011-09-26 15:07:56.208834281 +0200
@@ -91,6 +91,7 @@
 #else
 #define MAX_DMA_ADDRESS		(PAGE_OFFSET + 0x01000000)
 #endif
+#define MAX_DMA_PFN		PFN_DOWN(virt_to_phys((void *)MAX_DMA_ADDRESS))
 
 /* 8237 DMA controllers */
 #define IO_DMA1_BASE	0x00	/* 8 bit slave DMA, channels 0..3 */
diff -ruw linux-2.6.20.14/include/asm-mips/fixmap.h linux-2.6.20.14-fbx/include/asm-mips/fixmap.h
--- linux-2.6.20.14/include/asm-mips/fixmap.h	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/include/asm-mips/fixmap.h	2011-09-26 15:07:56.218834275 +0200
@@ -77,11 +77,15 @@
  * the start of the fixmap, and leave one page empty
  * at the top of mem..
  */
+#ifdef CONFIG_BCM963XX
+#define FIXADDR_TOP	((unsigned long)(long)(int)0xff000000)
+#else
 #if defined(CONFIG_CPU_TX39XX) || defined(CONFIG_CPU_TX49XX)
 #define FIXADDR_TOP	((unsigned long)(long)(int)(0xff000000 - 0x20000))
 #else
 #define FIXADDR_TOP	((unsigned long)(long)(int)0xfffe0000)
 #endif
+#endif
 #define FIXADDR_SIZE	(__end_of_fixed_addresses << PAGE_SHIFT)
 #define FIXADDR_START	(FIXADDR_TOP - FIXADDR_SIZE)
 
diff -ruw linux-2.6.20.14/include/asm-mips/io.h linux-2.6.20.14-fbx/include/asm-mips/io.h
--- linux-2.6.20.14/include/asm-mips/io.h	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/include/asm-mips/io.h	2011-09-26 15:07:56.218834275 +0200
@@ -115,7 +115,7 @@
  */
 static inline unsigned long virt_to_phys(volatile const void *address)
 {
-	return (unsigned long)address - PAGE_OFFSET;
+	return (unsigned long)address - PAGE_OFFSET + PHYS_OFFSET;
 }
 
 /*
@@ -132,7 +132,7 @@
  */
 static inline void * phys_to_virt(unsigned long address)
 {
-	return (void *)(address + PAGE_OFFSET);
+	return (void *)(address + PAGE_OFFSET - PHYS_OFFSET);
 }
 
 /*
@@ -542,7 +542,8 @@
 
 /* Create a virtual mapping cookie for a PCI BAR (memory or IO) */
 struct pci_dev;
-extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
+extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long
+			       max);
 extern void pci_iounmap(struct pci_dev *dev, void __iomem *);
 
 /*
diff -ruw linux-2.6.20.14/include/asm-mips/mman.h linux-2.6.20.14-fbx/include/asm-mips/mman.h
--- linux-2.6.20.14/include/asm-mips/mman.h	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/include/asm-mips/mman.h	2011-09-26 15:07:56.228834269 +0200
@@ -75,4 +75,10 @@
 #define MAP_ANON	MAP_ANONYMOUS
 #define MAP_FILE	0
 
+#ifdef __KERNEL__
+#ifndef arch_mmap_check
+#define arch_mmap_check(addr, len, flags)	(0)
+#endif
+#endif
+
 #endif /* _ASM_MMAN_H */
diff -ruw linux-2.6.20.14/include/asm-mips/page.h linux-2.6.20.14-fbx/include/asm-mips/page.h
--- linux-2.6.20.14/include/asm-mips/page.h	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/include/asm-mips/page.h	2011-09-26 15:07:56.228834269 +0200
@@ -34,6 +34,20 @@
 
 #ifndef __ASSEMBLY__
 
+/*
+ * This gives the physical RAM offset.
+ */
+#ifndef PHYS_OFFSET
+#define PHYS_OFFSET		0UL
+#endif
+
+/*
+ * It's normally defined only for FLATMEM config but it's
+ * used in our early mem init code for all memory models.
+ * So always define it.
+ */
+#define ARCH_PFN_OFFSET		PFN_UP(PHYS_OFFSET)
+
 #include <linux/pfn.h>
 #include <asm/io.h>
 
@@ -132,20 +146,23 @@
 /* to align the pointer to the (next) page boundary */
 #define PAGE_ALIGN(addr)	(((addr) + PAGE_SIZE - 1) & PAGE_MASK)
 
+/*
+ * __pa()/__va() should be used only during mem init.
+ */
 #if defined(CONFIG_64BIT) && !defined(CONFIG_BUILD_ELF64)
 #define __pa_page_offset(x)	((unsigned long)(x) < CKSEG0 ? PAGE_OFFSET : CKSEG0)
 #else
 #define __pa_page_offset(x)	PAGE_OFFSET
 #endif
-#define __pa(x)			((unsigned long)(x) - __pa_page_offset(x))
+#define __pa(x)		((unsigned long)(x) - __pa_page_offset(x) + PHYS_OFFSET)
+#define __va(x)		((void *)((unsigned long)(x) + PAGE_OFFSET - PHYS_OFFSET))
 #define __pa_symbol(x)		__pa(RELOC_HIDE((unsigned long)(x),0))
-#define __va(x)			((void *)((unsigned long)(x) + PAGE_OFFSET))
 
 #define pfn_to_kaddr(pfn)	__va((pfn) << PAGE_SHIFT)
 
 #ifdef CONFIG_FLATMEM
 
-#define pfn_valid(pfn)		((pfn) < max_mapnr)
+#define pfn_valid(pfn)		((pfn) >= ARCH_PFN_OFFSET && (pfn) < max_mapnr)
 
 #elif defined(CONFIG_SPARSEMEM)
 
diff -ruw linux-2.6.20.14/include/asm-mips/pgtable.h linux-2.6.20.14-fbx/include/asm-mips/pgtable.h
--- linux-2.6.20.14/include/asm-mips/pgtable.h	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/include/asm-mips/pgtable.h	2011-09-26 15:07:56.228834269 +0200
@@ -75,7 +75,7 @@
  * Conversion functions: convert a page and protection to a page entry,
  * and a page entry and page directory to the page they refer to.
  */
-#define pmd_phys(pmd)		(pmd_val(pmd) - PAGE_OFFSET)
+#define pmd_phys(pmd)		(pmd_val(pmd) - PAGE_OFFSET + PHYS_OFFSET)
 #define pmd_page(pmd)		(pfn_to_page(pmd_phys(pmd) >> PAGE_SHIFT))
 #define pmd_page_vaddr(pmd)	pmd_val(pmd)
 
diff -ruw linux-2.6.20.14/include/asm-mips/war.h linux-2.6.20.14-fbx/include/asm-mips/war.h
--- linux-2.6.20.14/include/asm-mips/war.h	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/include/asm-mips/war.h	2011-09-26 15:07:56.258834251 +0200
@@ -152,7 +152,7 @@
  *   MIPS 20Kc		RTL revision <4.0, PRID revision <?
  */
 #if defined(CONFIG_MIPS_MALTA) || defined(CONFIG_MIPS_ATLAS) || \
-    defined(CONFIG_MIPS_SEAD)
+    defined(CONFIG_MIPS_SEAD) || defined(CONFIG_BCM963xx)
 #define MIPS_CACHE_SYNC_WAR 1
 #endif
 
diff -ruw linux-2.6.20.14/include/linux/if_arp.h linux-2.6.20.14-fbx/include/linux/if_arp.h
--- linux-2.6.20.14/include/linux/if_arp.h	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/include/linux/if_arp.h	2011-09-26 15:07:56.408834159 +0200
@@ -40,6 +40,9 @@
 #define ARPHRD_METRICOM	23		/* Metricom STRIP (new IANA id)	*/
 #define	ARPHRD_IEEE1394	24		/* IEEE 1394 IPv4 - RFC 2734	*/
 #define ARPHRD_EUI64	27		/* EUI-64                       */
+/* Start Freebox added code */
+#define ARPHRD_DSL	29		/* ADSL                         */
+/* End Freebox added code */
 #define ARPHRD_INFINIBAND 32		/* InfiniBand			*/
 
 /* Dummy types for non ARP hardware */
diff -ruw linux-2.6.20.14/include/linux/if_pppox.h linux-2.6.20.14-fbx/include/linux/if_pppox.h
--- linux-2.6.20.14/include/linux/if_pppox.h	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/include/linux/if_pppox.h	2011-09-26 15:07:56.408834159 +0200
@@ -47,16 +47,27 @@
 }; 
  
 /************************************************************************ 
+ * PPPoA addressing definition
+ */
+struct pppoa_addr{
+	unsigned int    vpi;
+	unsigned int    vci;
+};
+
+/************************************************************************ 
  * Protocols supported by AF_PPPOX 
  */ 
-#define PX_PROTO_OE    0 /* Currently just PPPoE */
-#define PX_MAX_PROTO   1	
+#define PX_PROTO_OE    0
+#define PX_PROTO_OA    1
+
+#define PX_MAX_PROTO   2	
  
 struct sockaddr_pppox { 
        sa_family_t     sa_family;            /* address family, AF_PPPOX */ 
        unsigned int    sa_protocol;          /* protocol identifier */ 
        union{ 
                struct pppoe_addr       pppoe; 
+	       struct pppoa_addr       pppoa;
        }sa_addr; 
 }__attribute__ ((packed)); 
 
@@ -112,6 +123,22 @@
 } __attribute__ ((packed));
 
 #ifdef __KERNEL__
+
+#define PPPOA_ENCAP_UNKNOWN	0
+#define PPPOA_ENCAP_VCMUX	1
+#define PPPOA_ENCAP_LLC		2
+
+struct pppoa_opt
+{
+	unsigned int		vpi;
+	unsigned int		vci;
+	unsigned int		stopped;
+	struct tasklet_struct	rcv_tasklet;
+	struct sk_buff_head	rcv_queue;
+	struct tasklet_struct	wakeup_tasklet;
+	unsigned int		encap;
+};
+
 struct pppoe_opt {
 	struct net_device      *dev;	  /* device associated with socket*/
 	struct pppoe_addr	pa;	  /* what this socket is bound to*/
@@ -128,6 +155,7 @@
 	struct pppox_sock	*next;	  /* for hash table */
 	union {
 		struct pppoe_opt pppoe;
+		struct pppoa_opt pppoa;
 	} proto;
 	unsigned short		num;
 };
diff -ruw linux-2.6.20.14/include/linux/if_tunnel.h linux-2.6.20.14-fbx/include/linux/if_tunnel.h
--- linux-2.6.20.14/include/linux/if_tunnel.h	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/include/linux/if_tunnel.h	2011-09-26 15:07:56.408834159 +0200
@@ -25,6 +25,11 @@
 	__be16			o_flags;
 	__be32			i_key;
 	__be32			o_key;
+
+	/* this is the first bits to match on ipv6 address */
+	struct in6_addr		fbx6to4_zone;
+	__u8			fbx6to4_prefix;
+
 	struct iphdr		iph;
 };
 
diff -ruw linux-2.6.20.14/include/linux/in.h linux-2.6.20.14-fbx/include/linux/in.h
--- linux-2.6.20.14/include/linux/in.h	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/include/linux/in.h	2011-09-26 15:07:56.408834159 +0200
@@ -79,6 +79,10 @@
 /* BSD compatibility */
 #define IP_RECVRETOPTS	IP_RETOPTS
 
+/* TProxy original addresses */
+#define IP_ORIGADDRS	11273
+#define IP_RECVORIGADDRS	IP_ORIGADDRS
+
 /* IP_MTU_DISCOVER values */
 #define IP_PMTUDISC_DONT		0	/* Never send DF frames */
 #define IP_PMTUDISC_WANT		1	/* Use per route hints	*/
@@ -175,6 +179,13 @@
 	struct in_addr	ipi_addr;
 };
 
+struct in_origaddrs {
+        struct in_addr ioa_srcaddr;
+        struct in_addr ioa_dstaddr;
+        unsigned short int ioa_srcport;
+        unsigned short int ioa_dstport;
+};
+
 /* Structure describing an Internet (IP) socket address. */
 #define __SOCK_SIZE__	16		/* sizeof(struct sockaddr)	*/
 struct sockaddr_in {
diff -ruw linux-2.6.20.14/include/linux/Kbuild linux-2.6.20.14-fbx/include/linux/Kbuild
--- linux-2.6.20.14/include/linux/Kbuild	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/include/linux/Kbuild	2011-09-26 15:07:56.378834177 +0200
@@ -338,4 +338,8 @@
 unifdef-y += wireless.h
 unifdef-y += xfrm.h
 
+unifdef-y += fbxatm.h
+unifdef-y += fbxmtd_map_ioctl.h
+
 objhdr-y += version.h
+
diff -ruw linux-2.6.20.14/include/linux/kernel.h linux-2.6.20.14-fbx/include/linux/kernel.h
--- linux-2.6.20.14/include/linux/kernel.h	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/include/linux/kernel.h	2011-09-26 15:07:56.418834153 +0200
@@ -175,6 +175,8 @@
 		console_loglevel = 15;
 }
 
+extern void console_emergency_dump(char *buf, int *len);
+
 extern void bust_spinlocks(int yes);
 extern int oops_in_progress;		/* If set, an oops, panic(), BUG() or die() is in progress */
 extern int panic_timeout;
diff -ruw linux-2.6.20.14/include/linux/kmalloc_sizes.h linux-2.6.20.14-fbx/include/linux/kmalloc_sizes.h
--- linux-2.6.20.14/include/linux/kmalloc_sizes.h	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/include/linux/kmalloc_sizes.h	2011-09-26 15:07:56.418834153 +0200
@@ -19,12 +19,10 @@
 	CACHE(32768)
 	CACHE(65536)
 	CACHE(131072)
-#if (NR_CPUS > 512) || (MAX_NUMNODES > 256) || !defined(CONFIG_MMU)
 	CACHE(262144)
-#endif
-#ifndef CONFIG_MMU
 	CACHE(524288)
 	CACHE(1048576)
+#ifndef CONFIG_MMU
 #ifdef CONFIG_LARGE_ALLOCS
 	CACHE(2097152)
 	CACHE(4194304)
diff -ruw linux-2.6.20.14/include/linux/list.h linux-2.6.20.14-fbx/include/linux/list.h
--- linux-2.6.20.14/include/linux/list.h	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/include/linux/list.h	2011-09-26 15:07:56.418834153 +0200
@@ -369,6 +369,17 @@
 	container_of(ptr, type, member)
 
 /**
+ * list_first_entry - get the first element from a list
+ * @ptr:	the list head to take the element from.
+ * @type:	the type of the struct this is embedded in.
+ * @member:	the name of the list_struct within the struct.
+ *
+ * Note, that list is expected to be not empty.
+ */
+#define list_first_entry(ptr, type, member) \
+	list_entry((ptr)->next, type, member)
+
+/**
  * list_for_each	-	iterate over a list
  * @pos:	the &struct list_head to use as a loop cursor.
  * @head:	the head for your list.
diff -ruw linux-2.6.20.14/include/linux/netdevice.h linux-2.6.20.14-fbx/include/linux/netdevice.h
--- linux-2.6.20.14/include/linux/netdevice.h	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/include/linux/netdevice.h	2011-09-26 15:07:56.428834147 +0200
@@ -525,9 +525,26 @@
 	void                    (*poll_controller)(struct net_device *dev);
 #endif
 
+#if defined(CONFIG_FREEBOX_MVDSA) || defined(CONFIG_FREEBOX_MVDSA_MODULE)
+	int			(*fbxmvdsa_rx_fix)(struct sk_buff *skb);
+	void			*fbxmvdsa_priv;
+#endif
+
 	/* bridge stuff */
 	struct net_bridge_port	*br_port;
 
+#if defined(CONFIG_FREEBOX_BRIDGE) || defined(CONFIG_FREEBOX_BRIDGE_MODULE)
+	struct fbxbridge        *fbx_bridge;
+	struct fbxbridge        *fbx_bridge_port;
+#endif
+
+/* Start Freebox added code */
+#if defined (CONFIG_FREEBOX_L2BR) || defined(CONFIG_FREEBOX_L2BR_MODULE)
+	struct fbxl2br		*fbx_l2br;
+	struct fbxl2br_port	*fbx_l2br_port;
+#endif
+/* End Freebox added code */
+
 	/* class/net/name entry */
 	struct class_device	class_dev;
 	/* space for optional statistics and wireless sysfs groups */
diff -ruw linux-2.6.20.14/include/linux/netfilter/nf_conntrack_common.h linux-2.6.20.14-fbx/include/linux/netfilter/nf_conntrack_common.h
--- linux-2.6.20.14/include/linux/netfilter/nf_conntrack_common.h	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/include/linux/netfilter/nf_conntrack_common.h	2011-09-26 15:07:56.428834147 +0200
@@ -73,6 +73,18 @@
 	/* Connection has fixed timeout. */
 	IPS_FIXED_TIMEOUT_BIT = 10,
 	IPS_FIXED_TIMEOUT = (1 << IPS_FIXED_TIMEOUT_BIT),
+
+#if defined(CONFIG_IP_NF_TPROXY) || defined (CONFIG_IP_NF_TPROXY_MODULE)
+	/* Connection is tproxy-ed */
+	IPS_TPROXY_BIT = 11,
+	IPS_TPROXY = (1 << IPS_TPROXY_BIT),
+
+	IPS_TPROXY_RELATED_BIT = 12,
+	IPS_TPROXY_RELATED = (1 << IPS_TPROXY_RELATED_BIT),
+
+	IPS_MAY_DELETE_BIT = 12,
+	IPS_MAY_DELETE = (1 << IPS_MAY_DELETE_BIT),
+#endif
 };
 
 /* Connection tracking event bits */
diff -ruw linux-2.6.20.14/include/linux/netfilter/nf_conntrack_ftp.h linux-2.6.20.14-fbx/include/linux/netfilter/nf_conntrack_ftp.h
--- linux-2.6.20.14/include/linux/netfilter/nf_conntrack_ftp.h	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/include/linux/netfilter/nf_conntrack_ftp.h	2011-09-26 15:07:56.428834147 +0200
@@ -26,6 +26,11 @@
 	u_int32_t seq_aft_nl[IP_CT_DIR_MAX][NUM_SEQ_TO_REMEMBER];
 	/* 0 means seq_match_aft_nl not set */
 	int seq_aft_nl_num[IP_CT_DIR_MAX];
+#if defined(CONFIG_FREEBOX_BRIDGE) || defined(CONFIG_FREEBOX_BRIDGE_MODULE)
+	unsigned int is_fbxbridge;
+	unsigned long fbxbridge_remote;
+	unsigned long fbxbridge_wan;
+#endif
 };
 
 struct nf_conntrack_expect;
diff -ruw linux-2.6.20.14/include/linux/netfilter/nf_conntrack_tcp.h linux-2.6.20.14-fbx/include/linux/netfilter/nf_conntrack_tcp.h
--- linux-2.6.20.14/include/linux/netfilter/nf_conntrack_tcp.h	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/include/linux/netfilter/nf_conntrack_tcp.h	2011-09-26 15:07:56.428834147 +0200
@@ -27,6 +27,9 @@
 /* This sender sent FIN first */
 #define IP_CT_TCP_FLAG_CLOSE_INIT		0x04
 
+/* Be liberal in window checking */
+#define IP_CT_TCP_FLAG_BE_LIBERAL		0x08
+
 #ifdef __KERNEL__
 
 struct ip_ct_tcp_state {
@@ -34,7 +37,6 @@
 	u_int32_t	td_maxend;	/* max of ack + max(win, 1) */
 	u_int32_t	td_maxwin;	/* max(win) */
 	u_int8_t	td_scale;	/* window scale factor */
-	u_int8_t	loose;		/* used when connection picked up from the middle */
 	u_int8_t	flags;		/* per direction options */
 };
 
diff -ruw linux-2.6.20.14/include/linux/netfilter_ipv4/ip_conntrack_ftp.h linux-2.6.20.14-fbx/include/linux/netfilter_ipv4/ip_conntrack_ftp.h
--- linux-2.6.20.14/include/linux/netfilter_ipv4/ip_conntrack_ftp.h	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/include/linux/netfilter_ipv4/ip_conntrack_ftp.h	2011-09-26 15:07:56.428834147 +0200
@@ -26,6 +26,16 @@
 	u_int32_t seq_aft_nl[IP_CT_DIR_MAX][NUM_SEQ_TO_REMEMBER];
 	/* 0 means seq_match_aft_nl not set */
 	int seq_aft_nl_num[IP_CT_DIR_MAX];
+#if defined(CONFIG_FREEBOX_BRIDGE) || defined(CONFIG_FREEBOX_BRIDGE_MODULE)
+	unsigned int is_fbxbridge;
+	unsigned long fbxbridge_remote;
+	unsigned long fbxbridge_wan;
+#endif
+#if defined (CONFIG_FREEBOX_L2BR) || defined(CONFIG_FREEBOX_L2BR_MODULE)
+	unsigned int is_fbxl2br;
+	unsigned long fbxl2br_remote;
+	unsigned long fbxl2br_wan;
+#endif
 };
 
 struct ip_conntrack_expect;
diff -ruw linux-2.6.20.14/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.6.20.14-fbx/include/linux/netfilter_ipv4/ip_conntrack.h
--- linux-2.6.20.14/include/linux/netfilter_ipv4/ip_conntrack.h	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/include/linux/netfilter_ipv4/ip_conntrack.h	2011-09-26 15:07:56.428834147 +0200
@@ -115,6 +115,14 @@
 		int masq_index;
 #endif
 	} nat;
+
+#if defined(CONFIG_IP_NF_TPROXY) || defined (CONFIG_IP_NF_TPROXY_MODULE)
+	union _tproxy_data {
+		void *sockref;
+		struct list_head related;
+	} tproxy;
+#endif /* CONFIG_IP_NF_TPROXY */
+
 #endif /* CONFIG_IP_NF_NAT_NEEDED */
 
 #if defined(CONFIG_IP_NF_CONNTRACK_MARK)
@@ -165,6 +173,11 @@
 	/* Direction relative to the master connection. */
 	enum ip_conntrack_dir dir;
 #endif
+
+#ifdef CONFIG_IP_NF_NAT_NRES
+	/* List of registered reservations */
+	struct list_head reserved_list;
+#endif
 };
 
 #define IP_CT_EXPECT_PERMANENT	0x1
@@ -232,6 +245,8 @@
 	__ip_ct_refresh_acct(ct, 0, skb, extra_jiffies, 0);
 }
 
+extern void __death_by_timeout(unsigned long ul_conntrack);
+
 /* These are for NAT.  Icky. */
 /* Update TCP window tracking data when NAT mangles the packet */
 extern void ip_conntrack_tcp_update(struct sk_buff *skb,
@@ -240,6 +255,15 @@
 
 /* Call me when a conntrack is destroyed. */
 extern void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack);
+#ifdef CONFIG_IP_NF_NAT_NRES
+/* Call when an expectation is destroyed. */
+extern void (*ip_conntrack_expect_destroyed)(struct ip_conntrack_expect *exp);
+#endif
+
+#if defined(CONFIG_IP_NF_TPROXY) || defined (CONFIG_IP_NF_TPROXY_MODULE)
+/* Call me when a conntrack is confirmed. */
+extern void (*ip_conntrack_confirmed)(struct ip_conntrack *conntrack);
+#endif
 
 /* Fake conntrack entry for untracked connections */
 extern struct ip_conntrack ip_conntrack_untracked;
@@ -268,7 +292,8 @@
 extern void ip_ct_remove_expectations(struct ip_conntrack *ct);
 
 extern struct ip_conntrack *ip_conntrack_alloc(struct ip_conntrack_tuple *,
-					       struct ip_conntrack_tuple *);
+					       struct ip_conntrack_tuple *,
+					       int);
 
 extern void ip_conntrack_free(struct ip_conntrack *ct);
 
diff -ruw linux-2.6.20.14/include/linux/netfilter_ipv4/ip_nat_core.h linux-2.6.20.14-fbx/include/linux/netfilter_ipv4/ip_nat_core.h
--- linux-2.6.20.14/include/linux/netfilter_ipv4/ip_nat_core.h	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/include/linux/netfilter_ipv4/ip_nat_core.h	2011-09-26 15:07:56.428834147 +0200
@@ -15,4 +15,13 @@
 					 enum ip_conntrack_info ctinfo,
 					 unsigned int hooknum,
 					 struct sk_buff **pskb);
+
+#if defined(CONFIG_IP_NF_TPROXY) || defined (CONFIG_IP_NF_TPROXY_MODULE)
+extern int ip_nat_manip_pkt(u_int16_t proto,
+			    struct sk_buff **pskb,
+			    unsigned int iphdroff,
+			    const struct ip_conntrack_tuple *target,
+			    enum ip_nat_manip_type maniptype);
+#endif
+
 #endif /* _IP_NAT_CORE_H */
diff -ruw linux-2.6.20.14/include/linux/netfilter_ipv4/ip_nat.h linux-2.6.20.14-fbx/include/linux/netfilter_ipv4/ip_nat.h
--- linux-2.6.20.14/include/linux/netfilter_ipv4/ip_nat.h	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/include/linux/netfilter_ipv4/ip_nat.h	2011-09-26 15:07:56.428834147 +0200
@@ -16,6 +16,11 @@
 
 #define IP_NAT_RANGE_MAP_IPS 1
 #define IP_NAT_RANGE_PROTO_SPECIFIED 2
+#define IP_NAT_RANGE_BYPASS_HELPERS 4
+
+#ifdef CONFIG_IP_NF_NAT_NRES
+#define IP_NAT_RANGE_USE_RESERVED 8
+#endif
 
 /* NAT sequence number modifications */
 struct ip_nat_seq {
@@ -51,6 +56,9 @@
 #ifdef __KERNEL__
 #include <linux/list.h>
 
+/* call this to signal dependency on the NAT hooks */
+extern void need_nat_hooks(void);
+
 /* Protects NAT hash tables, and NAT-private part of conntracks. */
 extern rwlock_t ip_nat_lock;
 
@@ -63,6 +71,18 @@
 
 struct ip_conntrack;
 
+#ifdef CONFIG_IP_NF_NAT_NRES
+/* Structure to store reserved manips */
+struct ip_nat_reserved {
+	struct list_head hash;			/* Hash chain */
+	struct list_head exp;			/* Per-expectation list */
+	atomic_t use;				/* Reference count */
+	struct ip_conntrack_manip manip;	/* Reserved manip */
+	struct ip_conntrack_manip peer;		/* Peer (optional) */
+	u_int16_t proto;			/* Protocol number of reserved manip */
+};
+#endif
+
 /* Set up the info structure to map into this range. */
 extern unsigned int ip_nat_setup_info(struct ip_conntrack *conntrack,
 				      const struct ip_nat_range *range,
@@ -70,7 +90,39 @@
 
 /* Is this tuple already taken? (not by us)*/
 extern int ip_nat_used_tuple(const struct ip_conntrack_tuple *tuple,
-			     const struct ip_conntrack *ignored_conntrack);
+			     const struct ip_conntrack *ignored_conntrack,
+			     const enum ip_nat_manip_type maniptype,
+			     const unsigned int flags);
+
+#ifdef CONFIG_IP_NF_NAT_NRES
+struct ip_conntrack_expect;
+
+/* NAT port reservation: allocate and hash a new entry */
+extern struct ip_nat_reserved *__ip_nat_reserved_new_hash(const struct ip_conntrack_manip *manip,
+					 const u_int16_t proto, const struct ip_conntrack_manip *peer);
+
+/* NAT port reservation: unhash an entry */
+extern struct ip_nat_reserved *__ip_nat_reserved_unhash(const struct ip_conntrack_manip *manip,
+				       const u_int16_t proto, const struct ip_conntrack_manip *peer);
+
+/* NAT port reservation: free a reservation */
+extern void __ip_nat_reserved_free(struct ip_nat_reserved *res);
+
+/* NAT port reservation: register a new reservation */
+extern int ip_nat_reserved_register(struct ip_conntrack_expect *exp,
+				    const struct ip_conntrack_manip *manip,
+				    const u_int16_t proto,
+				    const struct ip_conntrack_manip *peer);
+
+/* NAT port reservation: unregister a reservation */
+extern int ip_nat_reserved_unregister(struct ip_conntrack_expect *exp,
+				      const struct ip_conntrack_manip *manip,
+				      const u_int16_t proto,
+				      const struct ip_conntrack_manip *peer);
+
+/* NAT port reservation: unregister all reservations for a given expectation */
+extern void ip_nat_reserved_unregister_all(struct ip_conntrack_expect *exp);
+#endif /*CONFIG_IP_NF_NAT_NRES*/
 
 #else  /* !__KERNEL__: iptables wants this to compile. */
 #define ip_nat_multi_range ip_nat_multi_range_compat
diff -ruw linux-2.6.20.14/include/linux/netfilter_ipv4/Kbuild linux-2.6.20.14-fbx/include/linux/netfilter_ipv4/Kbuild
--- linux-2.6.20.14/include/linux/netfilter_ipv4/Kbuild	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/include/linux/netfilter_ipv4/Kbuild	2011-09-26 15:07:56.428834147 +0200
@@ -59,3 +59,5 @@
 unifdef-y += ip_nat_rule.h
 unifdef-y += ip_queue.h
 unifdef-y += ip_tables.h
+
+unifdef-y += ip_tproxy.h
diff -ruw linux-2.6.20.14/include/linux/net.h linux-2.6.20.14-fbx/include/linux/net.h
--- linux-2.6.20.14/include/linux/net.h	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/include/linux/net.h	2011-09-26 15:07:56.428834147 +0200
@@ -24,7 +24,7 @@
 struct poll_table_struct;
 struct inode;
 
-#define NPROTO		32		/* should be enough for now..	*/
+#define NPROTO		AF_MAX		/* should be enough for now..	*/
 
 #define SYS_SOCKET	1		/* sys_socket(2)		*/
 #define SYS_BIND	2		/* sys_bind(2)			*/
@@ -223,6 +223,11 @@
 			   size_t size, int flags);
 extern int kernel_sock_ioctl(struct socket *sock, int cmd, unsigned long arg);
 
+#if defined(CONFIG_IP_NF_TPROXY) || defined (CONFIG_IP_NF_TPROXY_MODULE)
+extern void (*ip_tproxy_tcp_unhashed)(struct sock *, int proto);
+extern void (*ip_tproxy_udp_unhashed)(struct sock *, int proto);
+#endif
+
 #ifndef CONFIG_SMP
 #define SOCKOPS_WRAPPED(name) name
 #define SOCKOPS_WRAP(name, fam)
diff -ruw linux-2.6.20.14/include/linux/netlink.h linux-2.6.20.14-fbx/include/linux/netlink.h
--- linux-2.6.20.14/include/linux/netlink.h	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/include/linux/netlink.h	2011-09-26 15:07:56.438834141 +0200
@@ -24,6 +24,10 @@
 /* leave room for NETLINK_DM (DM Events) */
 #define NETLINK_SCSITRANSPORT	18	/* SCSI Transports */
 
+/* Begin Freebox added code. */
+#define NETLINK_FBXL2BR		24	/* Freebox L2 Bridge */
+/* End Freebox added code. */
+
 #define MAX_LINKS 32		
 
 struct sockaddr_nl
diff -ruw linux-2.6.20.14/include/linux/pci_ids.h linux-2.6.20.14-fbx/include/linux/pci_ids.h
--- linux-2.6.20.14/include/linux/pci_ids.h	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/include/linux/pci_ids.h	2011-09-26 15:07:56.438834141 +0200
@@ -1581,6 +1581,9 @@
 #define PCI_DEVICE_ID_3DFX_VOODOO3	0x0005
 #define PCI_DEVICE_ID_3DFX_VOODOO5	0x0009
 
+#define PCI_VENDOR_ID_SIGMADES		0x1236
+#define PCI_DEVICE_ID_SIGMADES_OHCI	0x1234
+#define PCI_DEVICE_ID_SIGMADES_EHCI	0x1235
 
 
 #define PCI_VENDOR_ID_AVM		0x1244
@@ -1614,6 +1617,9 @@
 #define PCI_VENDOR_ID_SATSAGEM		0x1267
 #define PCI_DEVICE_ID_SATSAGEM_NICCY	0x1016
 
+#define PCI_VENDOR_ID_SILICON_MOTION		0x126f
+#define PCI_DEVICE_ID_SM501_VOYAGER_GX_REV_AA	0x0501
+#define PCI_DEVICE_ID_SM501_VOYAGER_GX_REV_B	0x0510
 
 #define PCI_VENDOR_ID_ENSONIQ		0x1274
 #define PCI_DEVICE_ID_ENSONIQ_CT5880	0x5880
diff -ruw linux-2.6.20.14/include/linux/ppp_channel.h linux-2.6.20.14-fbx/include/linux/ppp_channel.h
--- linux-2.6.20.14/include/linux/ppp_channel.h	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/include/linux/ppp_channel.h	2011-09-26 15:07:56.438834141 +0200
@@ -48,6 +48,11 @@
 /* Called by the channel when it can send some more data. */
 extern void ppp_output_wakeup(struct ppp_channel *);
 
+/* Start Freebox added code */
+/* Called by the channel when it want to prevent further transmit on it */
+extern void ppp_output_stop(struct ppp_channel *);
+/* End Freebox added code */
+
 /* Called by the channel to process a received PPP packet.
    The packet should have just the 2-byte PPP protocol header. */
 extern void ppp_input(struct ppp_channel *, struct sk_buff *);
diff -ruw linux-2.6.20.14/include/linux/random.h linux-2.6.20.14-fbx/include/linux/random.h
--- linux-2.6.20.14/include/linux/random.h	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/include/linux/random.h	2011-09-26 15:07:56.448834135 +0200
@@ -48,6 +48,8 @@
 				 unsigned int value);
 extern void add_interrupt_randomness(int irq);
 
+extern void add_raw_randomness(uint8_t *buf, int nbytes);
+
 extern void get_random_bytes(void *buf, int nbytes);
 void generate_random_uuid(unsigned char uuid_out[16]);
 
diff -ruw linux-2.6.20.14/include/linux/serial_core.h linux-2.6.20.14-fbx/include/linux/serial_core.h
--- linux-2.6.20.14/include/linux/serial_core.h	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/include/linux/serial_core.h	2011-09-26 15:07:56.448834135 +0200
@@ -135,6 +135,9 @@
 /* Xilinx uartlite */
 #define PORT_UARTLITE	74
 
+/* Broadcom bcm963xx */
+#define PORT_BCM963XX	75
+
 #ifdef __KERNEL__
 
 #include <linux/compiler.h>
diff -ruw linux-2.6.20.14/include/linux/serial.h linux-2.6.20.14-fbx/include/linux/serial.h
--- linux-2.6.20.14/include/linux/serial.h	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/include/linux/serial.h	2011-09-26 15:07:56.448834135 +0200
@@ -76,7 +76,8 @@
 #define PORT_16654	11
 #define PORT_16850	12
 #define PORT_RSA	13	/* RSA-DV II/S card */
-#define PORT_MAX	13
+#define PORT_SB1250	14
+#define PORT_MAX	14
 
 #define SERIAL_IO_PORT	0
 #define SERIAL_IO_HUB6	1
diff -ruw linux-2.6.20.14/include/linux/skbuff.h linux-2.6.20.14-fbx/include/linux/skbuff.h
--- linux-2.6.20.14/include/linux/skbuff.h	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/include/linux/skbuff.h	2011-09-26 15:07:56.448834135 +0200
@@ -285,6 +285,12 @@
 				nfctinfo:3;
 	__u8			pkt_type:3,
 				fclone:2,
+#ifdef CONFIG_SKB_RECYCLE
+				cache_clean:1,
+#endif
+#if defined(CONFIG_FREEBOX_MVDSA) || defined(CONFIG_FREEBOX_MVDSA_MODULE)
+				dsa_done:1,
+#endif
 				ipvs_property:1;
 	__be16			protocol;
 
@@ -297,6 +303,9 @@
 #ifdef CONFIG_BRIDGE_NETFILTER
 	struct nf_bridge_info	*nf_bridge;
 #endif
+#ifdef CONFIG_IP_FFN
+	int			ffn_state;
+#endif
 #endif /* CONFIG_NETFILTER */
 #ifdef CONFIG_NET_SCHED
 	__u16			tc_index;	/* traffic control index */
@@ -312,6 +321,15 @@
 #endif
 
 	__u32			mark;
+	__u32			rx_class;
+
+#ifdef CONFIG_SKB_RECYCLE
+	/* callback just before skb header memory is about to be
+	 * released, memory is not freed if callback returns 1 */
+	int			(*recycle)(void *recycle_data,
+					   struct sk_buff *skb);
+	void			*recycle_data;
+#endif
 
 	/* These elements must be at the end, see alloc_skb() for details.  */
 	unsigned int		truesize;
@@ -997,6 +1015,10 @@
  * Various parts of the networking layer expect at least 16 bytes of
  * headroom, you should not reduce this.
  */
+#ifdef CONFIG_NETSKBPAD
+#define NET_SKB_PAD	CONFIG_NETSKBPAD
+#endif
+
 #ifndef NET_SKB_PAD
 #define NET_SKB_PAD	16
 #endif
@@ -1482,5 +1504,33 @@
 	return skb_shinfo(skb)->gso_size;
 }
 
+#ifdef CONFIG_SKB_RECYCLE
+static inline void skb_clean_state(struct sk_buff *skb)
+{
+	unsigned int datasize;
+	struct skb_shared_info *shinfo;
+
+	memset(skb, 0, offsetof(struct sk_buff, recycle));
+	atomic_set(&skb->users, 1);
+
+	datasize = skb->end - skb->head;
+	skb->truesize = datasize + sizeof (struct sk_buff);
+	skb->data = skb->head;
+	skb->tail = skb->head;
+
+	shinfo = skb_shinfo(skb);
+	atomic_set(&shinfo->dataref, 1);
+	shinfo->nr_frags  = 0;
+	shinfo->gso_size = 0;
+	shinfo->gso_segs = 0;
+	shinfo->gso_type = 0;
+	shinfo->ip6_frag_id = 0;
+	shinfo->frag_list = NULL;
+}
+
+extern void kfree_recycled_skbmem(struct sk_buff *skb);
+
+#endif
+
 #endif	/* __KERNEL__ */
 #endif	/* _LINUX_SKBUFF_H */
diff -ruw linux-2.6.20.14/include/linux/socket.h linux-2.6.20.14-fbx/include/linux/socket.h
--- linux-2.6.20.14/include/linux/socket.h	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/include/linux/socket.h	2011-09-26 15:07:56.458834129 +0200
@@ -187,7 +187,8 @@
 #define AF_LLC		26	/* Linux LLC			*/
 #define AF_TIPC		30	/* TIPC sockets			*/
 #define AF_BLUETOOTH	31	/* Bluetooth sockets 		*/
-#define AF_MAX		32	/* For now.. */
+#define AF_FBXATM	32
+#define AF_MAX		33	/* For now.. */
 
 /* Protocol families, same as address families. */
 #define PF_UNSPEC	AF_UNSPEC
@@ -220,6 +221,7 @@
 #define PF_LLC		AF_LLC
 #define PF_TIPC		AF_TIPC
 #define PF_BLUETOOTH	AF_BLUETOOTH
+#define PF_FBXATM	AF_FBXATM
 #define PF_MAX		AF_MAX
 
 /* Maximum queue length specifiable by listen.  */
diff -ruw linux-2.6.20.14/include/linux/sockios.h linux-2.6.20.14-fbx/include/linux/sockios.h
--- linux-2.6.20.14/include/linux/sockios.h	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/include/linux/sockios.h	2011-09-26 15:07:56.458834129 +0200
@@ -122,6 +122,28 @@
 #define SIOCBRADDIF	0x89a2		/* add interface to bridge      */
 #define SIOCBRDELIF	0x89a3		/* remove interface from bridge */
 
+/* Start Freebox added code */
+/* fbxdiverter call */
+#define SIOCGFBXDIVERT	0x89b0		/* fbxdiverter support		*/
+#define SIOCSFBXDIVERT	0x89b1		/* Set fbxdiverter options 	*/
+/* End Freebox added code */
+
+/* Start Freebox added code */
+/* fbxbridge call */
+#define SIOCGFBXBRIDGE	0x89b2		/* fbxbridge support          */
+#define SIOCSFBXBRIDGE	0x89b3		/* Set fbxbridge options      */
+/* End Freebox added code */
+
+/* Start Freebox added code */
+/* fbxmvdsa call */
+#define SIOCFBXMVDSA	0x89b4		/* fbxmvdsa support          */
+/* fbxmvdsa call */
+
+/* Start Freebox added code */
+/* fbxl2br call */
+#define SIOCFBXL2BR	0x89b5		/* fbxl2br support          */
+/* fbxl2br call */
+
 /* Device private ioctl calls */
 
 /*
diff -ruw linux-2.6.20.14/include/linux/sunrpc/xprt.h linux-2.6.20.14-fbx/include/linux/sunrpc/xprt.h
--- linux-2.6.20.14/include/linux/sunrpc/xprt.h	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/include/linux/sunrpc/xprt.h	2011-09-26 15:07:56.458834129 +0200
@@ -32,7 +32,7 @@
 
 #define RPC_MIN_RESVPORT	(1U)
 #define RPC_MAX_RESVPORT	(65535U)
-#define RPC_DEF_MIN_RESVPORT	(665U)
+#define RPC_DEF_MIN_RESVPORT	(670U)
 #define RPC_DEF_MAX_RESVPORT	(1023U)
 
 /*
diff -ruw linux-2.6.20.14/include/net/ip.h linux-2.6.20.14-fbx/include/net/ip.h
--- linux-2.6.20.14/include/net/ip.h	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/include/net/ip.h	2011-09-26 15:07:56.478834115 +0200
@@ -41,6 +41,17 @@
 #define IPSKB_XFRM_TRANSFORMED	4
 #define IPSKB_FRAG_COMPLETE	8
 #define IPSKB_REROUTED		16
+
+#if defined(CONFIG_IP_NF_TPROXY) || defined (CONFIG_IP_NF_TPROXY_MODULE)
+
+	/* these fields unfortunately do not fit into the 40 bytes of
+	 * allocated cb space... we have to allocate at least 48 bytes */
+
+	u32 orig_srcaddr;
+	u32 orig_dstaddr;
+	u16 orig_srcport;
+	u16 orig_dstport;
+#endif
 };
 
 struct ipcm_cookie
@@ -326,6 +337,14 @@
 extern atomic_t ip_frag_mem;
 
 /*
+ *	Functions provided by ip_ffn.c
+ */
+extern void ip_ffn_init(void);
+extern int ip_ffn_process(struct sk_buff *skb);
+extern void ip_ffn_add(struct sk_buff *skb);
+extern void ip_ffn_flush_all(void);
+
+/*
  *	Functions provided by ip_forward.c
  */
  
diff -ruw linux-2.6.20.14/init/do_mounts.c linux-2.6.20.14-fbx/init/do_mounts.c
--- linux-2.6.20.14/init/do_mounts.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/init/do_mounts.c	2011-09-26 15:07:56.508834097 +0200
@@ -10,6 +10,10 @@
 #include <linux/mount.h>
 #include <linux/device.h>
 
+#ifdef CONFIG_DMCRYPTATBOOT
+#include <linux/dm-ioctl.h>
+#endif
+
 #include <linux/nfs_fs.h>
 #include <linux/nfs_fs_sb.h>
 #include <linux/nfs_mount.h>
@@ -402,6 +406,122 @@
 #endif
 }
 
+#ifdef CONFIG_DMCRYPTATBOOT
+/*
+ * Create dm device
+ */
+int dm_ctl_ioctl(struct inode *inode, struct file *file,
+		 uint command, ulong u);
+
+static int dm_run_setup(void)
+{
+	struct dm_ioctl dm, *dmp;
+	struct dm_target_spec *spec;
+	uint64_t size;
+	char *data, *tmp, *major, *minor;
+	uint8_t *target_info;
+	dev_t tomap;
+	int ret, fd;
+	uint8_t key[128];
+
+	/* read config */
+	ret = -EINVAL;
+	tmp = CONFIG_DMCRYPTATBOOT_DEVICE;
+	major = minor = NULL;
+	if (tmp)
+		major = strsep(&tmp, ":");
+	if (tmp)
+		minor = strsep(&tmp, ":");
+	if (!major || !minor)
+		goto end;
+
+	/* create device to map */
+	tomap = MKDEV(simple_strtoul(major, NULL, 10),
+		      simple_strtoul(minor, NULL, 10));
+	if (create_dev("/dev/tomap", tomap))
+		goto end;
+
+	fd = sys_open("/dev/tomap", 0, 0);
+	if (fd < 0)
+		goto end;
+
+	/* fetch its size */
+	if (sys_ioctl(fd, BLKGETSIZE64, (unsigned long)&size)) {
+		sys_close(fd);
+		goto end;
+	}
+	sys_close(fd);
+	size /= 512;
+
+	/* create dm device */
+	memset(&dm, 0, sizeof (dm));
+	dm.version[0] = DM_VERSION_MAJOR;
+	dm.version[1] = DM_VERSION_MINOR;
+	dm.version[2] = DM_VERSION_PATCHLEVEL;
+	dm.data_size = sizeof (dm);
+	strcpy(dm.name, "root");
+
+	ret = dm_ctl_ioctl(NULL, NULL, DM_DEV_CREATE, (ulong)&dm);
+	if (ret < 0) {
+		printk("dm_ctl_ioctl create failed\n");
+		goto end;
+	}
+
+	/* create table */
+	data = kmalloc(sizeof (*dmp) + sizeof (*spec) + 128, GFP_KERNEL);
+	if (!data)
+		goto end;
+	dmp = (struct dm_ioctl *)data;
+	spec = (struct dm_target_spec *)(dmp + 1);
+	target_info = (uint8_t *)(spec + 1);
+
+	memset(dmp, 0, sizeof (*dmp));
+	dmp->version[0] = DM_VERSION_MAJOR;
+	dmp->version[1] = DM_VERSION_MINOR;
+	dmp->version[2] = DM_VERSION_PATCHLEVEL;
+	dmp->data_size = sizeof (*dmp) + sizeof (*spec) + 128;
+	dmp->data_start = sizeof (*dmp);
+	dmp->target_count = 1;
+	strcpy(dmp->name, "root");
+
+	memset(spec, 0, sizeof (*spec));
+	spec->sector_start = 0;
+	spec->length = size;
+	strcpy(spec->target_type, "crypt");
+
+	strcpy(key, CONFIG_DMCRYPTATBOOT_KEY);
+
+	memset(target_info, 0, 128);
+	snprintf((char *)target_info, 128, "%s %s 0 /dev/tomap 0",
+		 CONFIG_DMCRYPTATBOOT_CIPHER, key);
+	target_info[127] = 0;
+
+	ret = dm_ctl_ioctl(NULL, NULL, DM_TABLE_LOAD, (ulong)data);
+	if (ret < 0) {
+		printk("dm_ctl_ioctl table load failed\n");
+		goto end;
+	}
+
+	/* resume device */
+	memset(&dm, 0, sizeof (dm));
+	dm.version[0] = DM_VERSION_MAJOR;
+	dm.version[1] = DM_VERSION_MINOR;
+	dm.version[2] = DM_VERSION_PATCHLEVEL;
+	dm.data_size = sizeof (dm);
+	strcpy(dm.name, "root");
+
+	ret = dm_ctl_ioctl(NULL, NULL, DM_DEV_SUSPEND, (ulong)&dm);
+	if (ret < 0) {
+		printk("dm_ctl_ioctl resume failed\n");
+		goto end;
+	}
+
+	strcpy(saved_root_name, "/dev/dm-0");
+end:
+	return ret;
+}
+#endif
+
 /*
  * Prepare the namespace - decide what/where to mount, load ramdisks, etc.
  */
@@ -421,6 +541,16 @@
 
 	md_run_setup();
 
+#ifdef CONFIG_DMCRYPTATBOOT
+#ifdef CONFIG_DMCRYPTATBOOT_ONLY
+	if (dm_run_setup() != 0)
+		/* disallow other root= value */
+		saved_root_name[0] = 0;
+#else
+	dm_run_setup();
+#endif
+#endif
+
 	if (saved_root_name[0]) {
 		root_device_name = saved_root_name;
 		if (!strncmp(root_device_name, "mtd", 3)) {
diff -ruw linux-2.6.20.14/init/Kconfig linux-2.6.20.14-fbx/init/Kconfig
--- linux-2.6.20.14/init/Kconfig	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/init/Kconfig	2011-09-26 15:07:56.508834097 +0200
@@ -91,6 +91,14 @@
 	  Note: This requires Perl, and a git repository, but not necessarily
 	  the git or cogito tools to be installed.
 
+config IGNORE_COMPILE_INFO
+	bool "Ignore non constant compile time info"
+	default n
+	help
+	  This options makes  linux binary invariant across successive
+	  compilation by disabling inclusions of variant compile time
+	  data (build user, build_hostname, ...).
+
 config SWAP
 	bool "Support for paging of anonymous memory (swap)"
 	depends on MMU && BLOCK
@@ -238,6 +246,31 @@
 	  This option enables access to the kernel configuration file
 	  through /proc/config.gz.
 
+config DMCRYPTATBOOT
+	bool "Create device-mapper crypt target before root"
+	depends on DM_CRYPT
+	default n
+
+config DMCRYPTATBOOT_DEVICE
+	string "Device major:minor"
+	depends on DMCRYPTATBOOT
+
+config DMCRYPTATBOOT_CIPHER
+	string "Cipher"
+	depends on DMCRYPTATBOOT
+
+config DMCRYPTATBOOT_KEY
+	string "Key"
+	depends on DMCRYPTATBOOT
+
+config DMCRYPTATBOOT_KEY_DECRYPT
+	string "Decryption key"
+	depends on DMCRYPTATBOOT
+
+config DMCRYPTATBOOT_ONLY
+	bool "Refuse to mount something else"
+	depends on DMCRYPTATBOOT
+
 config CPUSETS
 	bool "Cpuset support"
 	depends on SMP
diff -ruw linux-2.6.20.14/init/Makefile linux-2.6.20.14-fbx/init/Makefile
--- linux-2.6.20.14/init/Makefile	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/init/Makefile	2011-09-26 15:07:56.508834097 +0200
@@ -10,8 +10,9 @@
 mounts-$(CONFIG_BLK_DEV_INITRD)	+= do_mounts_initrd.o
 mounts-$(CONFIG_BLK_DEV_MD)	+= do_mounts_md.o
 
+
 # files to be removed upon make clean
-clean-files := ../include/linux/compile.h
+clean-files := ../include/linux/compile.h dmcryptatboot_decrypt_6348.c
 
 # dependencies on generated files need to be listed explicitly
 
@@ -22,7 +23,10 @@
 # mkcompile_h will make sure to only update the
 # actual file if its content has changed.
 
+mkcompile-y := $(srctree)/scripts/mkcompile_h
+mkcompile-$(CONFIG_IGNORE_COMPILE_INFO) := $(srctree)/scripts/mkcompile_fixed_h
+
 include/linux/compile.h: FORCE
 	@echo '  CHK     $@'
-	$(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkcompile_h $@ \
+	$(Q)$(CONFIG_SHELL) $(mkcompile-y) $@ \
 	"$(UTS_MACHINE)" "$(CONFIG_SMP)" "$(CONFIG_PREEMPT)" "$(CC) $(CFLAGS)"
diff -ruw linux-2.6.20.14/init/version.c linux-2.6.20.14-fbx/init/version.c
--- linux-2.6.20.14/init/version.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/init/version.c	2011-09-26 15:07:56.508834097 +0200
@@ -34,6 +34,7 @@
 };
 EXPORT_SYMBOL_GPL(init_uts_ns);
 
+#ifndef CONFIG_IGNORE_COMPILE_INFO
 /* FIXED STRINGS! Don't touch! */
 const char linux_banner[] =
 	"Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@"
@@ -43,3 +44,11 @@
 	"%s version %s"
 	" (" LINUX_COMPILE_BY "@" LINUX_COMPILE_HOST ")"
 	" (" LINUX_COMPILER ") %s\n";
+#else
+const char linux_banner[] =
+	"Linux version " UTS_RELEASE " (" LINUX_COMPILER ") (compile infos ignored)\n";
+
+const char linux_proc_banner[] =
+	"%s version %s"
+	" (compile infos ignored) %s\n";
+#endif
diff -ruw linux-2.6.20.14/kernel/printk.c linux-2.6.20.14-fbx/kernel/printk.c
--- linux-2.6.20.14/kernel/printk.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/kernel/printk.c	2011-09-26 15:07:56.528834085 +0200
@@ -37,6 +37,10 @@
 
 #define __LOG_BUF_LEN	(1 << CONFIG_LOG_BUF_SHIFT)
 
+#ifdef CONFIG_DEBUG_LL
+extern void printascii(char *);
+#endif
+
 /* printk's without a loglevel use this.. */
 #define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */
 
@@ -163,6 +167,26 @@
 
 __setup("log_buf_len=", log_buf_len_setup);
 
+void console_emergency_dump(char *buf, int *len)
+{
+	int i, limit;
+
+	if (*len > log_buf_len)
+		*len = log_buf_len;
+	if (*len > logged_chars)
+		*len = logged_chars;
+	limit = log_end;
+
+	for (i = 0; i < *len; i++) {
+		int j;
+
+		j = limit - 1 -i;
+		if (j + log_buf_len < log_end)
+			break;
+		buf[*len - 1 - i] = LOG_BUF(j);
+	}
+}
+
 /*
  * Commands to do_syslog:
  *
@@ -537,6 +561,10 @@
 	/* Emit the output into the temporary buffer */
 	printed_len = vscnprintf(printk_buf, sizeof(printk_buf), fmt, args);
 
+#ifdef CONFIG_DEBUG_LL
+	printascii(printk_buf);
+#endif
+
 	/*
 	 * Copy the output into log_buf.  If the caller didn't provide
 	 * appropriate log level tags, we insert them here
diff -ruw linux-2.6.20.14/lib/Kconfig linux-2.6.20.14-fbx/lib/Kconfig
--- linux-2.6.20.14/lib/Kconfig	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/lib/Kconfig	2011-09-26 15:07:56.538834079 +0200
@@ -106,4 +106,19 @@
 	depends on !UML
 	default y
 
+#
+# LZMA support for squashfs LZMA.
+#
+config SQLZMA_UNCOMP
+	bool "LZMA decompression support."
+	select ZLIB_INFLATE
+
 endmenu
+
+#
+# Freebox Serial info (selected by corresponding board's Kconfig)
+#
+config BUILTIN_FBXSERIAL
+	boolean
+	select CRC32
+
diff -ruw linux-2.6.20.14/lib/Makefile linux-2.6.20.14-fbx/lib/Makefile
--- linux-2.6.20.14/lib/Makefile	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/lib/Makefile	2011-09-26 15:07:56.538834079 +0200
@@ -70,3 +70,6 @@
 
 $(obj)/crc32table.h: $(obj)/gen_crc32table
 	$(call cmd,crc32)
+
+obj-$(CONFIG_BUILTIN_FBXSERIAL) += builtin-fbxserial.o
+obj-$(CONFIG_SQLZMA_UNCOMP)	+= sqlzma-uncomp.o LzmaDecode.o
\ No newline at end of file
diff -ruw linux-2.6.20.14/Makefile linux-2.6.20.14-fbx/Makefile
--- linux-2.6.20.14/Makefile	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/Makefile	2011-09-26 15:18:19.778452271 +0200
@@ -161,7 +161,8 @@
 SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
 				  -e s/arm.*/arm/ -e s/sa110/arm/ \
 				  -e s/s390x/s390/ -e s/parisc64/parisc/ \
-				  -e s/ppc.*/powerpc/ -e s/mips.*/mips/ )
+				  -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
+				  -e s/sh.*/sh/ )
 
 # Cross compiling and selecting different set of gcc/bin-utils
 # ---------------------------------------------------------------------------
@@ -182,6 +183,10 @@
 # Default value for CROSS_COMPILE is not to prefix executables
 # Note: Some architectures assign CROSS_COMPILE in their arch/*/Makefile
 
+ifeq ($(ARCH),)
+	ARCH = $(error ARCH is not defined)
+endif
+
 ARCH		?= $(SUBARCH)
 CROSS_COMPILE	?=
 
diff -ruw linux-2.6.20.14/mm/slab.c linux-2.6.20.14-fbx/mm/slab.c
--- linux-2.6.20.14/mm/slab.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/mm/slab.c	2011-09-26 15:07:56.558834067 +0200
@@ -565,9 +565,6 @@
 #if defined(CONFIG_LARGE_ALLOCS)
 #define	MAX_OBJ_ORDER	13	/* up to 32Mb */
 #define	MAX_GFP_ORDER	13	/* up to 32Mb */
-#elif defined(CONFIG_MMU)
-#define	MAX_OBJ_ORDER	5	/* 32 pages */
-#define	MAX_GFP_ORDER	5	/* 32 pages */
 #else
 #define	MAX_OBJ_ORDER	8	/* up to 1Mb */
 #define	MAX_GFP_ORDER	8	/* up to 1Mb */
diff -ruw linux-2.6.20.14/net/8021q/vlan_dev.c linux-2.6.20.14-fbx/net/8021q/vlan_dev.c
--- linux-2.6.20.14/net/8021q/vlan_dev.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/net/8021q/vlan_dev.c	2011-09-26 15:07:56.558834067 +0200
@@ -766,6 +766,7 @@
 	struct dev_mc_list *dmi = dev->mc_list;
 
 	while (dmi) {
+#ifdef VLAN_DEBUG
 		printk(KERN_DEBUG "%s: del %.2x:%.2x:%.2x:%.2x:%.2x:%.2x mcast address from vlan interface\n",
 		       dev->name,
 		       dmi->dmi_addr[0],
@@ -774,6 +775,7 @@
 		       dmi->dmi_addr[3],
 		       dmi->dmi_addr[4],
 		       dmi->dmi_addr[5]);
+#endif
 		dev_mc_delete(dev, dmi->dmi_addr, dmi->dmi_addrlen, 0);
 		dmi = dev->mc_list;
 	}
@@ -856,6 +858,7 @@
 		for (dmi = vlan_dev->mc_list; dmi != NULL; dmi = dmi->next) {
 			if (vlan_should_add_mc(dmi, VLAN_DEV_INFO(vlan_dev)->old_mc_list)) {
 				dev_mc_add(real_dev, dmi->dmi_addr, dmi->dmi_addrlen, 0);
+#ifdef VLAN_DEBUG
 				printk(KERN_DEBUG "%s: add %.2x:%.2x:%.2x:%.2x:%.2x:%.2x mcast address to master interface\n",
 				       vlan_dev->name,
 				       dmi->dmi_addr[0],
@@ -864,6 +867,7 @@
 				       dmi->dmi_addr[3],
 				       dmi->dmi_addr[4],
 				       dmi->dmi_addr[5]);
+#endif
 			}
 		}
 
@@ -874,6 +878,7 @@
 				 * delete it from the real list on the underlying device.
 				 */
 				dev_mc_delete(real_dev, dmi->dmi_addr, dmi->dmi_addrlen, 0);
+#ifdef VLAN_DEBUG
 				printk(KERN_DEBUG "%s: del %.2x:%.2x:%.2x:%.2x:%.2x:%.2x mcast address from master interface\n",
 				       vlan_dev->name,
 				       dmi->dmi_addr[0],
@@ -882,6 +887,7 @@
 				       dmi->dmi_addr[3],
 				       dmi->dmi_addr[4],
 				       dmi->dmi_addr[5]);
+#endif
 			}
 		}
 
diff -ruw linux-2.6.20.14/net/bridge/br_device.c linux-2.6.20.14-fbx/net/bridge/br_device.c
--- linux-2.6.20.14/net/bridge/br_device.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/net/bridge/br_device.c	2011-09-26 15:07:56.568834061 +0200
@@ -90,20 +90,17 @@
 {
 	struct net_bridge *br = netdev_priv(dev);
 	struct sockaddr *addr = p;
-	struct net_bridge_port *port;
-	int err = -EADDRNOTAVAIL;
+
+	if (!is_valid_ether_addr(addr->sa_data))
+		return -EINVAL;
 
 	spin_lock_bh(&br->lock);
-	list_for_each_entry(port, &br->port_list, list) {
-		if (!compare_ether_addr(port->dev->dev_addr, addr->sa_data)) {
+	memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
 			br_stp_change_bridge_id(br, addr->sa_data);
-			err = 0;
-			break;
-		}
-	}
+	br->flags |= BR_SET_MAC_ADDR;
 	spin_unlock_bh(&br->lock);
 
-	return err;
+	return 0;
 }
 
 static void br_getinfo(struct net_device *dev, struct ethtool_drvinfo *info)
diff -ruw linux-2.6.20.14/net/bridge/br_private.h linux-2.6.20.14-fbx/net/bridge/br_private.h
--- linux-2.6.20.14/net/bridge/br_private.h	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/net/bridge/br_private.h	2011-09-26 15:07:56.568834061 +0200
@@ -96,6 +96,8 @@
 	struct hlist_head		hash[BR_HASH_SIZE];
 	struct list_head		age_list;
 	unsigned long			feature_mask;
+	unsigned long			flags;
+#define BR_SET_MAC_ADDR			0x00000001
 
 	/* STP */
 	bridge_id			designated_root;
diff -ruw linux-2.6.20.14/net/bridge/br_stp_if.c linux-2.6.20.14-fbx/net/bridge/br_stp_if.c
--- linux-2.6.20.14/net/bridge/br_stp_if.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/net/bridge/br_stp_if.c	2011-09-26 15:07:56.568834061 +0200
@@ -159,6 +159,10 @@
 	const unsigned char *addr = br_mac_zero;
 	struct net_bridge_port *p;
 
+	/* user has chosen a value so keep it */
+	if (br->flags & BR_SET_MAC_ADDR)
+		return;
+
 	list_for_each_entry(p, &br->port_list, list) {
 		if (addr == br_mac_zero ||
 		    memcmp(p->dev->dev_addr, addr, ETH_ALEN) < 0)
diff -ruw linux-2.6.20.14/net/core/dev.c linux-2.6.20.14-fbx/net/core/dev.c
--- linux-2.6.20.14/net/core/dev.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/net/core/dev.c	2011-09-26 15:07:56.578834055 +0200
@@ -110,6 +110,7 @@
 #include <linux/rcupdate.h>
 #include <linux/delay.h>
 #include <linux/wireless.h>
+#include <linux/kthread.h>
 #include <net/iw_handler.h>
 #include <asm/current.h>
 #include <linux/audit.h>
@@ -176,6 +177,18 @@
  */
 struct net_device *dev_base;
 static struct net_device **dev_tail = &dev_base;
+
+#ifdef CONFIG_NETRXTHREAD
+
+#define RXTHREAD_MAX_PROCESS	CONFIG_NETRXTHREAD_MAX_PROCESS
+#define RXTHREAD_MAX_PKTS	128
+
+static struct task_struct *krxd;
+static struct sk_buff_head krxd_pkt_queue[CONFIG_NETRXTHREAD_RX_QUEUE];
+static wait_queue_head_t krxd_wq;
+static unsigned int krxd_pkts_count;
+#endif
+
 DEFINE_RWLOCK(dev_base_lock);
 
 EXPORT_SYMBOL(dev_base);
@@ -1553,6 +1566,23 @@
 DEFINE_PER_CPU(struct netif_rx_stats, netdev_rx_stat) = { 0, };
 
 
+/* Start Freebox added code */
+#if defined(CONFIG_FREEBOX_DIVERTER) || defined(CONFIG_FREEBOX_DIVERTER_MODULE)
+int (*fbxdiverter_hook)(struct sk_buff *);
+
+static int handle_fbxdiverter(struct sk_buff *skb)
+{
+	/* try_module_get  is missing  here,  so there  is  a race  on
+	 * fbxdiverter module deletion */
+	if (!fbxdiverter_hook)
+		return 0;
+
+	return fbxdiverter_hook(skb);
+}
+#endif
+/* End Freebox added code */
+
+
 /**
  *	netif_rx	-	post buffer to the network code
  *	@skb: buffer to post
@@ -1723,6 +1753,73 @@
 #define handle_bridge(skb, pt_prev, ret, orig_dev)	(0)
 #endif
 
+
+/* Start Freebox added code */
+#if defined(CONFIG_FREEBOX_BRIDGE) || defined(CONFIG_FREEBOX_BRIDGE_MODULE)
+struct sk_buff *(*fbxbridge_handle_frame_hook)(struct fbxbridge *p, struct sk_buff *skb);
+
+struct fbxbridge;
+
+static __inline__ int handle_fbxbridge(struct sk_buff *skb,
+				       struct packet_type **pt_prev, int *ret,
+				       struct net_device *orig_dev)
+{
+	struct fbxbridge *fbxbr;
+
+	if (skb->pkt_type == PACKET_LOOPBACK ||
+	    (fbxbr = skb->dev->fbx_bridge_port) == NULL)
+		return skb;
+
+	if (skb->protocol != __constant_htons(ETH_P_IP) &&
+	    skb->protocol != __constant_htons(ETH_P_ARP))
+		return skb;
+
+	if (*pt_prev) {
+		*ret = deliver_skb(skb, *pt_prev, orig_dev);
+		*pt_prev = NULL;
+	}
+
+	return fbxbridge_handle_frame_hook(fbxbr, skb);
+}
+#else
+#define handle_fbxbridge(skb, pt_prev, ret, orig_dev)	(skb)
+#endif
+/* End Freebox added code */
+
+/* Start Freebox added code */
+#if defined(CONFIG_FREEBOX_L2BR) || defined(CONFIG_FREEBOX_L2BR_MODULE)
+struct fbxl2br_port;
+int (*fbxl2br_handle_frame_hook)(struct fbxl2br_port *p, struct sk_buff *skb);
+
+
+static __inline__ int handle_fbxl2br(struct sk_buff *skb,
+				       struct packet_type **pt_prev, int *ret,
+				       struct net_device *orig_dev)
+{
+	struct fbxl2br_port *port;
+
+	if (skb->pkt_type == PACKET_LOOPBACK ||
+	    (port = skb->dev->fbx_l2br_port) == NULL)
+		return 0;
+
+	if (skb->protocol != __constant_htons(ETH_P_IP) &&
+	    skb->protocol != __constant_htons(ETH_P_ARP) &&
+	    skb->protocol != __constant_htons(ETH_P_IPV6))
+		return 0;
+
+	if (*pt_prev) {
+		*ret = deliver_skb(skb, *pt_prev, orig_dev);
+		*pt_prev = NULL;
+	}
+
+	return fbxl2br_handle_frame_hook(port, skb);
+}
+#else
+#define handle_fbxl2br(skb, pt_prev, ret, orig_dev)	(0)
+#endif
+/* End Freebox added code */
+
+
 #ifdef CONFIG_NET_CLS_ACT
 /* TODO: Maybe we should just force sch_ingress to be compiled in
  * when CONFIG_NET_CLS_ACT is? otherwise some useless instructions
@@ -1761,23 +1858,13 @@
 }
 #endif
 
-int netif_receive_skb(struct sk_buff *skb)
+static int netif_receive_skb_end(struct sk_buff *skb)
 {
 	struct packet_type *ptype, *pt_prev;
 	struct net_device *orig_dev;
 	int ret = NET_RX_DROP;
 	__be16 type;
 
-	/* if we've gotten here through NAPI, check netpoll */
-	if (skb->dev->poll && netpoll_rx(skb))
-		return NET_RX_DROP;
-
-	if (!skb->tstamp.off_sec)
-		net_timestamp(skb);
-
-	if (!skb->iif)
-		skb->iif = skb->dev->ifindex;
-
 	orig_dev = skb_bond(skb);
 
 	if (!orig_dev)
@@ -1785,9 +1872,6 @@
 
 	__get_cpu_var(netdev_rx_stat).total++;
 
-	skb->h.raw = skb->nh.raw = skb->data;
-	skb->mac_len = skb->nh.raw - skb->mac.raw;
-
 	pt_prev = NULL;
 
 	rcu_read_lock();
@@ -1807,6 +1891,21 @@
 		}
 	}
 
+
+	/* Start Freebox added code */
+	skb = handle_fbxbridge(skb, &pt_prev, &ret, orig_dev);
+	if (!skb)
+		goto out;
+	/* End Freebox added code */
+
+	/* Start Freebox added code */
+	if (handle_fbxl2br(skb, &pt_prev, &ret, orig_dev))
+		goto out;
+	/* End Freebox added code */
+
+
+
+
 #ifdef CONFIG_NET_CLS_ACT
 	if (pt_prev) {
 		ret = deliver_skb(skb, pt_prev, orig_dev);
@@ -1852,6 +1951,118 @@
 out:
 	rcu_read_unlock();
 	return ret;
+
+}
+
+#ifdef CONFIG_NETRXTHREAD
+
+static int krxd_action(void *unused)
+{
+	struct sk_buff *skb;
+	unsigned int maxpkt_in_loop;
+
+	set_user_nice(current, -5);
+	current->flags |= PF_NOFREEZE;
+	__set_current_state(TASK_RUNNING);
+
+	maxpkt_in_loop = RXTHREAD_MAX_PROCESS;
+	while (1) {
+		unsigned int i, queue, count;
+
+		local_bh_disable();
+		count = CONFIG_NETRXTHREAD_RX_QUEUE;
+		for (i = 0; i < count; i++) {
+			queue = count - i - 1;
+			skb = skb_dequeue(&krxd_pkt_queue[queue]);
+			if (!skb)
+				continue;
+			krxd_pkts_count--;
+			break;
+		}
+
+		if (!skb) {
+			local_bh_enable();
+			wait_event_interruptible(krxd_wq,
+						 krxd_pkts_count != 0);
+			set_current_state(TASK_RUNNING);
+			maxpkt_in_loop = RXTHREAD_MAX_PROCESS;
+			continue;
+		}
+
+		netif_receive_skb_end(skb);
+		local_bh_enable();
+
+		/* only schedule when working on lowest prio queue */
+		if (queue == 0) {
+			if (--maxpkt_in_loop == 0) {
+				maxpkt_in_loop = RXTHREAD_MAX_PROCESS;
+				schedule();
+			}
+		}
+	}
+
+	return 0;
+}
+#endif
+
+int netif_receive_skb(struct sk_buff *skb)
+{
+#ifdef CONFIG_NETRXTHREAD
+	unsigned int len, queue;
+#endif
+
+#if defined(CONFIG_FREEBOX_MVDSA) || defined(CONFIG_FREEBOX_MVDSA_MODULE)
+	/* if device has dsa tag enabled, remove it */
+	if (skb->dev->fbxmvdsa_rx_fix) {
+		if (!skb->dsa_done && skb->dev->fbxmvdsa_rx_fix(skb))
+			return NET_RX_DROP;
+
+		/* unmark dsa done since we use it on tx path */
+		skb->dsa_done = 0;
+	}
+#endif
+
+	/* if we've gotten here through NAPI, check netpoll */
+	if (skb->dev->poll && netpoll_rx(skb))
+		return NET_RX_DROP;
+
+	if (!skb->tstamp.off_sec)
+		net_timestamp(skb);
+
+	if (!skb->iif)
+		skb->iif = skb->dev->ifindex;
+
+	skb->h.raw = skb->nh.raw = skb->data;
+	skb->mac_len = skb->nh.raw - skb->mac.raw;
+
+/* Start Freebox added code */
+#if defined(CONFIG_FREEBOX_DIVERTER) || defined(CONFIG_FREEBOX_DIVERTER_MODULE)
+	if (handle_fbxdiverter(skb))
+		return NET_RX_SUCCESS;
+#endif
+/* End Freebox added code */
+
+#ifndef CONFIG_NETRXTHREAD
+	return netif_receive_skb_end(skb);
+#else
+	queue = skb->rx_class;
+	if (queue >= CONFIG_NETRXTHREAD_RX_QUEUE)
+		queue = CONFIG_NETRXTHREAD_RX_QUEUE - 1;
+
+	/* queue the packet to the rx thread */
+	local_bh_disable();
+	len = skb_queue_len(&krxd_pkt_queue[queue]);
+	if (len < RXTHREAD_MAX_PKTS) {
+		__skb_queue_tail(&krxd_pkt_queue[queue], skb);
+		krxd_pkts_count++;
+		if (!len)
+			wake_up(&krxd_wq);
+	} else {
+		dev_kfree_skb(skb);
+	}
+	local_bh_enable();
+	return NET_RX_SUCCESS;
+#endif
 }
 
 static int process_backlog(struct net_device *backlog_dev, int *budget)
@@ -3521,6 +3732,19 @@
 	open_softirq(NET_TX_SOFTIRQ, net_tx_action, NULL);
 	open_softirq(NET_RX_SOFTIRQ, net_rx_action, NULL);
 
+#ifdef CONFIG_NETRXTHREAD
+	for (i = 0; i < CONFIG_NETRXTHREAD_RX_QUEUE; i++)
+		skb_queue_head_init(&krxd_pkt_queue[i]);
+	krxd_pkts_count = 0;
+	init_waitqueue_head(&krxd_wq);
+	krxd = kthread_create(krxd_action, NULL, "krxthread");
+	if (IS_ERR(krxd)) {
+		printk(KERN_ERR "unable to create krxd\n");
+		return -ENOMEM;
+	}
+	wake_up_process(krxd);
+#endif
+
 	hotcpu_notifier(dev_cpu_callback, 0);
 	dst_init();
 	dev_mcast_init();
@@ -3566,12 +3790,30 @@
 EXPORT_SYMBOL(net_disable_timestamp);
 EXPORT_SYMBOL(dev_get_flags);
 
+/* Start Freebox added code */
+#if defined(CONFIG_FREEBOX_DIVERTER_MODULE)
+EXPORT_SYMBOL(fbxdiverter_hook);
+#endif
+/* End Freebox added code */
+
 #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
 EXPORT_SYMBOL(br_handle_frame_hook);
 EXPORT_SYMBOL(br_fdb_get_hook);
 EXPORT_SYMBOL(br_fdb_put_hook);
 #endif
 
+/* Start Freebox added code */
+#if defined(CONFIG_FREEBOX_BRIDGE_MODULE)
+EXPORT_SYMBOL(fbxbridge_handle_frame_hook);
+#endif
+/* End Freebox added code */
+
+/* Start Freebox added code */
+#if defined(CONFIG_FREEBOX_L2BR_MODULE)
+EXPORT_SYMBOL(fbxl2br_handle_frame_hook);
+#endif
+/* End Freebox added code */
+
 #ifdef CONFIG_KMOD
 EXPORT_SYMBOL(dev_load);
 #endif
diff -ruw linux-2.6.20.14/net/core/skbuff.c linux-2.6.20.14-fbx/net/core/skbuff.c
--- linux-2.6.20.14/net/core/skbuff.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/net/core/skbuff.c	2011-09-26 15:07:56.578834055 +0200
@@ -244,6 +244,7 @@
 	skb_shinfo(skb)->gso_segs = 0;
 	skb_shinfo(skb)->gso_type = 0;
 	skb_shinfo(skb)->frag_list = NULL;
+
 out:
 	return skb;
 nodata:
@@ -305,7 +306,20 @@
 		skb_get(list);
 }
 
+#ifdef CONFIG_SKB_RECYCLE
+void kfree_recycled_skbmem(struct sk_buff *skb)
+{
+	kfree(skb->head);
+	kmem_cache_free(skbuff_head_cache, skb);
+}
+
+EXPORT_SYMBOL(kfree_recycled_skbmem);
+
+static void skb_release_data(struct sk_buff *skb, int may_recycle,
+			     int *recycle_verdict)
+#else
 static void skb_release_data(struct sk_buff *skb)
+#endif
 {
 	if (!skb->cloned ||
 	    !atomic_sub_return(skb->nohdr ? (1 << SKB_DATAREF_SHIFT) + 1 : 1,
@@ -319,6 +333,15 @@
 		if (skb_shinfo(skb)->frag_list)
 			skb_drop_fraglist(skb);
 
+#ifdef CONFIG_SKB_RECYCLE
+		if (may_recycle) {
+			*recycle_verdict = skb->recycle(skb->recycle_data,
+							skb);
+			if (*recycle_verdict == 1)
+				return;
+		}
+#endif
+
 		kfree(skb->head);
 	}
 }
@@ -330,8 +353,20 @@
 {
 	struct sk_buff *other;
 	atomic_t *fclone_ref;
+#ifdef CONFIG_SKB_RECYCLE
+	int recycle_verdict;
 
+	if (skb->fclone == SKB_FCLONE_UNAVAILABLE && skb->recycle) {
+		recycle_verdict = 0;
+		skb_release_data(skb, 1, &recycle_verdict);
+		if (recycle_verdict)
+			return;
+	} else
+		skb_release_data(skb, 0, NULL);
+#else
 	skb_release_data(skb);
+#endif
+
 	switch (skb->fclone) {
 	case SKB_FCLONE_UNAVAILABLE:
 		kmem_cache_free(skbuff_head_cache, skb);
@@ -475,9 +510,13 @@
 #if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE)
 	C(ipvs_property);
 #endif
+#if defined(CONFIG_FREEBOX_MVDSA) || defined(CONFIG_FREEBOX_MVDSA_MODULE)
+	C(dsa_done);
+#endif
 	C(protocol);
 	n->destructor = NULL;
 	C(mark);
+	C(rx_class);
 #ifdef CONFIG_NETFILTER
 	C(nfct);
 	nf_conntrack_get(skb->nfct);
@@ -490,6 +529,9 @@
 	C(nf_bridge);
 	nf_bridge_get(skb->nf_bridge);
 #endif
+#ifdef CONFIG_IP_FFN
+	n->ffn_state = 0;
+#endif
 #endif /*CONFIG_NETFILTER*/
 #ifdef CONFIG_NET_SCHED
 	C(tc_index);
@@ -508,6 +550,10 @@
 	C(tail);
 	C(end);
 
+#ifdef CONFIG_SKB_RECYCLE
+	C(recycle);
+	C(recycle_data);
+#endif
 	atomic_inc(&(skb_shinfo(skb)->dataref));
 	skb->cloned = 1;
 
@@ -539,6 +585,7 @@
 	new->tstamp	= old->tstamp;
 	new->destructor = NULL;
 	new->mark	= old->mark;
+	new->rx_class	= old->rx_class;
 #ifdef CONFIG_NETFILTER
 	new->nfct	= old->nfct;
 	nf_conntrack_get(old->nfct);
@@ -547,9 +594,15 @@
 	new->nfct_reasm = old->nfct_reasm;
 	nf_conntrack_get_reasm(old->nfct_reasm);
 #endif
+#ifdef CONFIG_IP_FFN
+	new->ffn_state = 0;
+#endif
 #if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE)
 	new->ipvs_property = old->ipvs_property;
 #endif
+#if defined(CONFIG_FREEBOX_MVDSA) || defined(CONFIG_FREEBOX_MVDSA_MODULE)
+	new->dsa_done = old->dsa_done;
+#endif
 #ifdef CONFIG_BRIDGE_NETFILTER
 	new->nf_bridge	= old->nf_bridge;
 	nf_bridge_get(old->nf_bridge);
@@ -566,6 +619,9 @@
 	skb_shinfo(new)->gso_size = skb_shinfo(old)->gso_size;
 	skb_shinfo(new)->gso_segs = skb_shinfo(old)->gso_segs;
 	skb_shinfo(new)->gso_type = skb_shinfo(old)->gso_type;
+#ifdef CONFIG_SKB_RECYCLE
+	new->recycle = NULL;
+#endif
 }
 
 /**
@@ -711,7 +767,12 @@
 	if (skb_shinfo(skb)->frag_list)
 		skb_clone_fraglist(skb);
 
+#ifdef CONFIG_SKB_RECYCLE
+	skb_release_data(skb, 0, NULL);
+	skb->recycle = NULL;
+#else
 	skb_release_data(skb);
+#endif
 
 	off = (data + nhead) - skb->head;
 
diff -ruw linux-2.6.20.14/net/ipv4/inet_hashtables.c linux-2.6.20.14-fbx/net/ipv4/inet_hashtables.c
--- linux-2.6.20.14/net/ipv4/inet_hashtables.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/net/ipv4/inet_hashtables.c	2011-09-26 15:07:56.598834043 +0200
@@ -61,6 +61,10 @@
 	inet_csk(sk)->icsk_bind_hash = tb;
 }
 
+#if defined(CONFIG_IP_NF_TPROXY) || defined (CONFIG_IP_NF_TPROXY_MODULE)
+void (*ip_tproxy_tcp_unhashed)(struct sock *sk, int proto) = NULL;
+#endif
+
 /*
  * Get rid of any references to a local port held by the given sock.
  */
@@ -70,6 +74,13 @@
 	struct inet_bind_hashbucket *head = &hashinfo->bhash[bhash];
 	struct inet_bind_bucket *tb;
 
+#if defined(CONFIG_IP_NF_TPROXY) || defined (CONFIG_IP_NF_TPROXY_MODULE)
+	/* ugly tproxy unassign hook
+         * FIXME: now DCCP also uses this code */
+	if (ip_tproxy_tcp_unhashed)
+		ip_tproxy_tcp_unhashed(sk, IPPROTO_TCP);
+#endif
+
 	spin_lock(&head->lock);
 	tb = inet_csk(sk)->icsk_bind_hash;
 	__sk_del_bind_node(sk);
diff -ruw linux-2.6.20.14/net/ipv4/inet_timewait_sock.c linux-2.6.20.14-fbx/net/ipv4/inet_timewait_sock.c
--- linux-2.6.20.14/net/ipv4/inet_timewait_sock.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/net/ipv4/inet_timewait_sock.c	2011-09-26 15:07:56.598834043 +0200
@@ -30,6 +30,13 @@
 	sk_node_init(&tw->tw_node);
 	write_unlock(&ehead->lock);
 
+#if defined(CONFIG_IP_NF_TPROXY) || defined (CONFIG_IP_NF_TPROXY_MODULE)
+	/* ugly tproxy unassign hook
+	 * FIXME: now DCCP also uses this code */
+	if (ip_tproxy_tcp_unhashed)
+		ip_tproxy_tcp_unhashed((struct sock *)tw, IPPROTO_TCP);
+#endif
+
 	/* Disassociate with bind bucket. */
 	bhead = &hashinfo->bhash[inet_bhashfn(tw->tw_num, hashinfo->bhash_size)];
 	spin_lock(&bhead->lock);
diff -ruw linux-2.6.20.14/net/ipv4/ipconfig.c linux-2.6.20.14-fbx/net/ipv4/ipconfig.c
--- linux-2.6.20.14/net/ipv4/ipconfig.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/net/ipv4/ipconfig.c	2011-09-26 15:07:56.598834043 +0200
@@ -622,6 +622,16 @@
 		e += sizeof(ic_req_params);
 	}
 
+	/* add vendor identifier */
+#ifdef CONFIG_IP_PNP_DHCP_IDENTIFIER
+	*e++ = 60;
+	*e++ = 6 + sizeof (CONFIG_IP_PNP_DHCP_IDENTIFIER);
+	memcpy(e, "linux-", 6);
+	e += 6;
+	memcpy(e, CONFIG_IP_PNP_DHCP_IDENTIFIER,
+	       sizeof (CONFIG_IP_PNP_DHCP_IDENTIFIER));
+	e+= sizeof (CONFIG_IP_PNP_DHCP_IDENTIFIER);
+#endif
 	*e++ = 255;	/* End of the list */
 }
 
diff -ruw linux-2.6.20.14/net/ipv4/ip_input.c linux-2.6.20.14-fbx/net/ipv4/ip_input.c
--- linux-2.6.20.14/net/ipv4/ip_input.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/net/ipv4/ip_input.c	2011-09-26 15:07:56.598834043 +0200
@@ -428,6 +428,11 @@
 		goto drop;
 	}
 
+#ifdef CONFIG_IP_FFN
+	if (!ip_ffn_process(skb))
+		return NET_RX_SUCCESS;
+#endif
+
 	/* Remove any debris in the socket control block */
 	memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
 
diff -ruw linux-2.6.20.14/net/ipv4/ip_output.c linux-2.6.20.14-fbx/net/ipv4/ip_output.c
--- linux-2.6.20.14/net/ipv4/ip_output.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/net/ipv4/ip_output.c	2011-09-26 15:07:56.598834043 +0200
@@ -153,6 +153,7 @@
 	ip_send_check(iph);
 
 	skb->priority = sk->sk_priority;
+	skb->rx_class = 1;
 
 	/* Send it out. */
 	return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
@@ -182,6 +183,11 @@
 		skb = skb2;
 	}
 
+#ifdef CONFIG_IP_FFN
+	if (skb->ffn_state == 1)
+		ip_ffn_add(skb);
+#endif
+
 	if (dst->hh)
 		return neigh_hh_output(dst->hh, skb);
 	else if (dst->neighbour)
@@ -276,6 +282,11 @@
 	skb->dev = dev;
 	skb->protocol = htons(ETH_P_IP);
 
+#ifdef CONFIG_IP_FFN
+	if (skb->ffn_state == 2)
+		return ip_finish_output(skb);
+#endif
+
 	return NF_HOOK_COND(PF_INET, NF_IP_POST_ROUTING, skb, NULL, dev,
 		            ip_finish_output,
 			    !(IPCB(skb)->flags & IPSKB_REROUTED));
@@ -360,6 +371,7 @@
 	ip_send_check(iph);
 
 	skb->priority = sk->sk_priority;
+	skb->rx_class = 1;
 
 	return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
 		       dst_output);
@@ -1255,6 +1267,7 @@
 
 	skb->priority = sk->sk_priority;
 	skb->dst = dst_clone(&rt->u.dst);
+	skb->rx_class = 1;
 
 	/* Netfilter gets whole the not fragmented skb. */
 	err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, 
@@ -1396,6 +1409,9 @@
 #if defined(CONFIG_IP_MULTICAST) && defined(CONFIG_PROC_FS)
 	igmp_mc_proc_init();
 #endif
+#ifdef CONFIG_IP_FFN
+	ip_ffn_init();
+#endif
 }
 
 EXPORT_SYMBOL(ip_generic_getfrag);
diff -ruw linux-2.6.20.14/net/ipv4/ip_sockglue.c linux-2.6.20.14-fbx/net/ipv4/ip_sockglue.c
--- linux-2.6.20.14/net/ipv4/ip_sockglue.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/net/ipv4/ip_sockglue.c	2011-09-26 15:07:56.598834043 +0200
@@ -50,6 +50,7 @@
 #define IP_CMSG_RECVOPTS	8
 #define IP_CMSG_RETOPTS		16
 #define IP_CMSG_PASSSEC		32
+#define IP_CMSG_ORIGADDRS	64
 
 /*
  *	SOL_IP control messages.
@@ -127,6 +128,25 @@
 	security_release_secctx(secdata, seclen);
 }
 
+#if defined(CONFIG_IP_NF_TPROXY) || defined (CONFIG_IP_NF_TPROXY_MODULE)
+
+void ip_cmsg_recv_origaddrs(struct msghdr *msg, struct sk_buff *skb)
+{
+        struct in_origaddrs ioa;
+
+	/* don't return original addresses if they were not set by tproxy*/
+	if (IPCB(skb)->orig_dstaddr == 0 || IPCB(skb)->orig_dstport == 0)
+		return;
+
+        ioa.ioa_srcaddr.s_addr = IPCB(skb)->orig_srcaddr;
+        ioa.ioa_srcport = IPCB(skb)->orig_srcport;
+        ioa.ioa_dstaddr.s_addr = IPCB(skb)->orig_dstaddr;
+        ioa.ioa_dstport = IPCB(skb)->orig_dstport;
+
+        put_cmsg(msg, SOL_IP, IP_ORIGADDRS, sizeof(ioa), &ioa);
+}
+
+#endif
 
 void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb)
 {
@@ -161,6 +181,13 @@
 
 	if (flags & 1)
 		ip_cmsg_recv_security(msg, skb);
+
+#if defined(CONFIG_IP_NF_TPROXY) || defined (CONFIG_IP_NF_TPROXY_MODULE)
+	if ((flags>>=1) == 0)
+		return;
+	if (flags & 1)
+		ip_cmsg_recv_origaddrs(msg, skb);
+#endif
 }
 
 int ip_cmsg_send(struct msghdr *msg, struct ipcm_cookie *ipc)
@@ -416,6 +443,9 @@
 			    (1<<IP_MTU_DISCOVER) | (1<<IP_RECVERR) | 
 			    (1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND) |
 			    (1<<IP_PASSSEC))) ||
+#if defined(CONFIG_IP_NF_TPROXY) || defined (CONFIG_IP_NF_TPROXY_MODULE)
+				optname == IP_RECVORIGADDRS ||
+#endif
 				optname == IP_MULTICAST_TTL || 
 				optname == IP_MULTICAST_LOOP) { 
 		if (optlen >= sizeof(int)) {
@@ -506,6 +536,14 @@
 			else
 				inet->cmsg_flags &= ~IP_CMSG_PASSSEC;
 			break;
+#if defined(CONFIG_IP_NF_TPROXY) || defined (CONFIG_IP_NF_TPROXY_MODULE)
+                case IP_RECVORIGADDRS:
+                        if (val)
+                                inet->cmsg_flags |= IP_CMSG_ORIGADDRS;
+                        else
+                                inet->cmsg_flags &= ~IP_CMSG_ORIGADDRS;
+                        break;
+#endif
 		case IP_TOS:	/* This sets both TOS and Precedence */
 			if (sk->sk_type == SOCK_STREAM) {
 				val &= ~3;
@@ -1014,6 +1052,11 @@
 		case IP_PASSSEC:
 			val = (inet->cmsg_flags & IP_CMSG_PASSSEC) != 0;
 			break;
+#if defined(CONFIG_IP_NF_TPROXY) || defined (CONFIG_IP_NF_TPROXY_MODULE)
+                case IP_RECVORIGADDRS:
+			val = (inet->cmsg_flags & IP_CMSG_ORIGADDRS) != 0;
+                        break;
+#endif
 		case IP_TOS:
 			val = inet->tos;
 			break;
diff -ruw linux-2.6.20.14/net/ipv4/Kconfig linux-2.6.20.14-fbx/net/ipv4/Kconfig
--- linux-2.6.20.14/net/ipv4/Kconfig	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/net/ipv4/Kconfig	2011-09-26 15:07:56.588834049 +0200
@@ -14,6 +14,13 @@
 	  <file:Documentation/networking/multicast.txt>. For most people, it's
 	  safe to say N.
 
+config IP_FFN
+	bool "IP: Fast forwarding and NAT"
+	depends on NETFILTER
+	help
+	   Provide a fast path for established conntrack entries so that
+	   packets go out ASAP.
+
 config IP_ADVANCED_ROUTER
 	bool "IP: advanced router"
 	---help---
@@ -197,6 +204,11 @@
 	  must be operating on your network.  Read
 	  <file:Documentation/nfsroot.txt> for details.
 
+config IP_PNP_DHCP_IDENTIFIER
+	string "IP: DHCP vendor class identifier"
+	depends on IP_PNP_DHCP
+	default ""
+
 config IP_PNP_BOOTP
 	bool "IP: BOOTP support"
 	depends on IP_PNP
@@ -362,6 +374,11 @@
 
 	  If unsure, say N.
 
+config INET_XFRM_GC_THRESH
+	int "IP: xfrm garbage collect threshold"
+	depends on XFRM
+	default 1024
+
 config INET_AH
 	tristate "IP: AH transformation"
 	select XFRM
diff -ruw linux-2.6.20.14/net/ipv4/Makefile linux-2.6.20.14-fbx/net/ipv4/Makefile
--- linux-2.6.20.14/net/ipv4/Makefile	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/net/ipv4/Makefile	2011-09-26 15:07:56.588834049 +0200
@@ -12,6 +12,7 @@
 	     arp.o icmp.o devinet.o af_inet.o  igmp.o \
 	     sysctl_net_ipv4.o fib_frontend.o fib_semantics.o
 
+obj-$(CONFIG_IP_FFN) += ip_ffn.o
 obj-$(CONFIG_IP_FIB_HASH) += fib_hash.o
 obj-$(CONFIG_IP_FIB_TRIE) += fib_trie.o
 obj-$(CONFIG_PROC_FS) += proc.o
diff -ruw linux-2.6.20.14/net/ipv4/netfilter/ip_conntrack_core.c linux-2.6.20.14-fbx/net/ipv4/netfilter/ip_conntrack_core.c
--- linux-2.6.20.14/net/ipv4/netfilter/ip_conntrack_core.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/net/ipv4/netfilter/ip_conntrack_core.c	2011-09-26 15:07:56.608834037 +0200
@@ -59,6 +59,9 @@
 atomic_t ip_conntrack_count = ATOMIC_INIT(0);
 
 void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack) = NULL;
+#ifdef CONFIG_IP_NF_NAT_NRES
+void (*ip_conntrack_expect_destroyed)(struct ip_conntrack_expect *expect) = NULL;
+#endif
 LIST_HEAD(ip_conntrack_expect_list);
 struct ip_conntrack_protocol *ip_ct_protos[MAX_IP_CT_PROTO] __read_mostly;
 static LIST_HEAD(helpers);
@@ -72,6 +75,10 @@
 static LIST_HEAD(unconfirmed);
 static int ip_conntrack_vmalloc __read_mostly;
 
+#if defined(CONFIG_IP_NF_TPROXY) || defined (CONFIG_IP_NF_TPROXY_MODULE)
+void (*ip_conntrack_confirmed)(struct ip_conntrack *conntrack) = NULL;
+#endif
+
 static unsigned int ip_conntrack_next_id;
 static unsigned int ip_conntrack_expect_next_id;
 #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
@@ -202,6 +209,12 @@
 	list_del(&exp->list);
 	CONNTRACK_STAT_INC(expect_delete);
 	exp->master->expecting--;
+
+#ifdef CONFIG_IP_NF_NAT_NRES
+	if (ip_conntrack_expect_destroyed)
+		ip_conntrack_expect_destroyed(exp);
+#endif
+
 	ip_conntrack_expect_put(exp);
 }
 
@@ -297,6 +310,10 @@
 	ip_ct_remove_expectations(ct);
 }
 
+#ifdef CONFIG_IP_FFN
+extern void ip_ffn_ct_destroy(struct ip_conntrack *ct);
+#endif
+
 static void
 destroy_conntrack(struct nf_conntrack *nfct)
 {
@@ -311,6 +328,10 @@
 	ip_conntrack_event(IPCT_DESTROY, ct);
 	set_bit(IPS_DYING_BIT, &ct->status);
 
+#ifdef CONFIG_IP_FFN
+	ip_ffn_ct_destroy(ct);
+#endif
+
 	helper = ct->helper;
 	if (helper && helper->destroy)
 		helper->destroy(ct);
@@ -348,6 +369,50 @@
 	ip_conntrack_free(ct);
 }
 
+static void
+__destroy_conntrack(struct nf_conntrack *nfct)
+{
+	struct ip_conntrack *ct = (struct ip_conntrack *)nfct;
+	struct ip_conntrack_protocol *proto;
+
+	DEBUGP("destroy_conntrack(%p)\n", ct);
+	IP_NF_ASSERT(atomic_read(&nfct->use) == 0);
+	IP_NF_ASSERT(!timer_pending(&ct->timeout));
+
+	ip_conntrack_event(IPCT_DESTROY, ct);
+	set_bit(IPS_DYING_BIT, &ct->status);
+
+	/* To make sure we don't get any weird locking issues here:
+	 * destroy_conntrack() MUST NOT be called with a write lock
+	 * to ip_conntrack_lock!!! -HW */
+	proto = __ip_conntrack_proto_find(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum);
+	if (proto && proto->destroy)
+		proto->destroy(ct);
+
+	if (ip_conntrack_destroyed)
+		ip_conntrack_destroyed(ct);
+
+	/* Expectations will have been removed in clean_from_lists,
+	 * except TFTP can create an expectation on the first packet,
+	 * before connection is in the list, so we need to clean here,
+	 * too. */
+	ip_ct_remove_expectations(ct);
+
+	/* We overload first tuple to link into unconfirmed list. */
+	if (!is_confirmed(ct)) {
+		BUG_ON(list_empty(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list));
+		list_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list);
+	}
+
+	CONNTRACK_STAT_INC(delete);
+
+	if (ct->master)
+		ip_conntrack_put(ct->master);
+
+	DEBUGP("destroy_conntrack: returning ct=%p to slab\n", ct);
+	ip_conntrack_free(ct);
+}
+
 static void death_by_timeout(unsigned long ul_conntrack)
 {
 	struct ip_conntrack *ct = (void *)ul_conntrack;
@@ -361,6 +426,19 @@
 	ip_conntrack_put(ct);
 }
 
+void __death_by_timeout(unsigned long ul_conntrack)
+{
+	struct ip_conntrack *ct = (void *)ul_conntrack;
+
+	/* Inside lock so preempt is disabled on module removal path.
+	 * Otherwise we can get spurious warnings. */
+	CONNTRACK_STAT_INC(delete_list);
+	clean_from_lists(ct);
+
+	if (atomic_dec_and_test(&ct->ct_general.use))
+		__destroy_conntrack((struct nf_conntrack *)ct);
+}
+
 struct ip_conntrack_tuple_hash *
 __ip_conntrack_find(const struct ip_conntrack_tuple *tuple,
 		    const struct ip_conntrack *ignored_conntrack)
@@ -477,6 +555,13 @@
 	set_bit(IPS_CONFIRMED_BIT, &ct->status);
 	CONNTRACK_STAT_INC(insert);
 	write_unlock_bh(&ip_conntrack_lock);
+
+#if defined(CONFIG_IP_NF_TPROXY) || defined (CONFIG_IP_NF_TPROXY_MODULE)
+	/* Call confirmed hook */
+	if (ip_conntrack_confirmed)
+		ip_conntrack_confirmed(ct);
+#endif
+
 	if (ct->helper)
 		ip_conntrack_event_cache(IPCT_HELPER, *pskb);
 #ifdef CONFIG_IP_NF_NAT_NEEDED
@@ -611,8 +696,11 @@
 	module_put(p->me);
 }
 
+#define MAX_SECURE_CT	256
+
 struct ip_conntrack *ip_conntrack_alloc(struct ip_conntrack_tuple *orig,
-					struct ip_conntrack_tuple *repl)
+					struct ip_conntrack_tuple *repl,
+					int secure_pool)
 {
 	struct ip_conntrack *conntrack;
 
@@ -626,7 +714,16 @@
 
 	if (ip_conntrack_max
 	    && atomic_read(&ip_conntrack_count) > ip_conntrack_max) {
-		unsigned int hash = hash_conntrack(orig);
+		unsigned int hash;
+
+		/* Try allocation from secure pool */
+		if (secure_pool &&
+		    atomic_read(&ip_conntrack_count) <
+		    ip_conntrack_max + MAX_SECURE_CT)
+			goto ok;
+
+		hash = hash_conntrack(orig);
+
 		/* Try dropping from this hash chain. */
 		if (!early_drop(&ip_conntrack_hash[hash])) {
 			atomic_dec(&ip_conntrack_count);
@@ -637,7 +734,7 @@
 			return ERR_PTR(-ENOMEM);
 		}
 	}
-
+ok:
 	conntrack = kmem_cache_alloc(ip_conntrack_cachep, GFP_ATOMIC);
 	if (!conntrack) {
 		DEBUGP("Can't allocate conntrack.\n");
@@ -681,7 +778,7 @@
 		return NULL;
 	}
 
-	conntrack = ip_conntrack_alloc(tuple, &repl_tuple);
+	conntrack = ip_conntrack_alloc(tuple, &repl_tuple, skb->rx_class != 0);
 	if (conntrack == NULL || IS_ERR(conntrack))
 		return (struct ip_conntrack_tuple_hash *)conntrack;
 
@@ -936,6 +1033,9 @@
 	}
 	new->master = me;
 	atomic_set(&new->use, 1);
+#ifdef CONFIG_IP_NF_NAT_NRES
+	INIT_LIST_HEAD(&new->reserved_list);
+#endif
 	return new;
 }
 
diff -ruw linux-2.6.20.14/net/ipv4/netfilter/ip_conntrack_ftp.c linux-2.6.20.14-fbx/net/ipv4/netfilter/ip_conntrack_ftp.c
--- linux-2.6.20.14/net/ipv4/netfilter/ip_conntrack_ftp.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/net/ipv4/netfilter/ip_conntrack_ftp.c	2011-09-26 15:07:56.608834037 +0200
@@ -19,6 +19,16 @@
 #include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
 #include <linux/moduleparam.h>
 
+#if defined(CONFIG_FREEBOX_BRIDGE) || defined(CONFIG_FREEBOX_BRIDGE_MODULE)
+#include <fbxbridge.h>
+#include <linux/netfilter_ipv4/ip_nat_helper.h>
+#endif
+
+#if defined (CONFIG_FREEBOX_L2BR) || defined(CONFIG_FREEBOX_L2BR_MODULE)
+#include <fbxl2br.h>
+#include <linux/netfilter_ipv4/ip_nat_helper.h>
+#endif
+
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Rusty Russell <rusty@rustcorp.com.au>");
 MODULE_DESCRIPTION("ftp connection tracking helper");
@@ -319,6 +329,37 @@
 		return NF_ACCEPT;
 	}
 
+#if defined(CONFIG_FREEBOX_BRIDGE) || defined(CONFIG_FREEBOX_BRIDGE_MODULE)
+	if (!ct_ftp_info->is_fbxbridge && (*pskb)->dev->fbx_bridge) {
+		struct fbxbridge *fbxbr;
+
+		fbxbr = (*pskb)->dev->fbx_bridge;
+		ct_ftp_info->is_fbxbridge = 1;
+		ct_ftp_info->fbxbridge_remote = ntohl(fbxbr->br_remote_ipaddr);
+		ct_ftp_info->fbxbridge_wan = fbxbr->wan_ipaddr;
+	}
+#endif
+
+#if defined (CONFIG_FREEBOX_L2BR) || defined(CONFIG_FREEBOX_L2BR_MODULE)
+	if (!ct_ftp_info->is_fbxl2br && (*pskb)->dev->fbx_l2br) {
+		struct fbxl2br *br;
+		struct fbxl2br_client *c;
+		struct iphdr *ip;
+
+		br = (*pskb)->dev->fbx_l2br;
+		ip = (*pskb)->nh.iph;
+
+		c = fbxl2br_get_client_by_nat_addr(br, ip->daddr);
+		if (!c)
+			goto proceed;
+
+		ct_ftp_info->is_fbxl2br = 1;
+		ct_ftp_info->fbxl2br_remote = ntohl(c->nat_addr);
+		ct_ftp_info->fbxl2br_wan = c->client_ipaddr;
+	}
+ proceed:
+#endif
+
 	th = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl*4,
 				sizeof(_tcph), &_tcph);
 	if (th == NULL)
@@ -399,6 +440,90 @@
 	 * Doesn't matter unless NAT is happening.  */
 	exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip;
 
+#if defined(CONFIG_FREEBOX_BRIDGE) || defined(CONFIG_FREEBOX_BRIDGE_MODULE)
+	if (ct_ftp_info->is_fbxbridge &&
+	    search[dir][i].ftptype == IP_CT_FTP_PORT) {
+		unsigned long orig_ip_addr;
+		unsigned short orig_port;
+		char buffer[sizeof("nnn,nnn,nnn,nnn,nnn,nnn")];
+		unsigned int len;
+
+		/* kludge: if  we are here,  then this is a  local pkt
+		 * that has  gone through internal  fbxbridge snat.
+		 *
+		 * If we see a port  command, then we mangle packet to
+		 * change  ip  address  given  to  the  remote  bridge
+		 * address */
+
+		/* check  address  is  packet  is  the  one  fbxbridge
+		 * changed */
+		orig_ip_addr = htonl((array[0] << 24) | (array[1] << 16)
+				     | (array[2] << 8) | array[3]);
+		if (orig_ip_addr != ct_ftp_info->fbxbridge_wan)
+			goto donttouch;
+
+		/* now mangle the remote address */
+		orig_port = htons(array[4] << 8 | array[5]);
+		len = sprintf(buffer, "%u,%u,%u,%u,%u,%u",
+			      NIPQUAD(ct_ftp_info->fbxbridge_remote),
+			      orig_port >> 8 , orig_port & 0xFF);
+
+		ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff,
+					 matchlen, buffer, len);
+
+		/* then adjust as if nothing happened */
+		matchlen = len;
+		array[0] = (ct_ftp_info->fbxbridge_remote >> 24) & 0xff;
+		array[1] = (ct_ftp_info->fbxbridge_remote >> 16) & 0xff;
+		array[2] = (ct_ftp_info->fbxbridge_remote >> 8) & 0xff;
+		array[3] = (ct_ftp_info->fbxbridge_remote) & 0xff;
+	}
+donttouch:
+
+#endif
+
+#if defined(CONFIG_FREEBOX_L2BR) || defined(CONFIG_FREEBOX_L2BR_MODULE)
+	if (ct_ftp_info->is_fbxl2br &&
+	    search[dir][i].ftptype == IP_CT_FTP_PORT) {
+		unsigned long orig_ip_addr;
+		unsigned short orig_port;
+		char buffer[sizeof("nnn,nnn,nnn,nnn,nnn,nnn")];
+		unsigned int len;
+
+		/* kludge: if  we are here,  then this is a  local pkt
+		 * that has  gone through internal  fbxl2br snat.
+		 *
+		 * If we see a port  command, then we mangle packet to
+		 * change  ip  address  given  to  the  remote  bridge
+		 * address */
+
+		/* check  address  is  packet  is  the  one  fbxl2br
+		 * changed */
+		orig_ip_addr = htonl((array[0] << 24) | (array[1] << 16)
+				     | (array[2] << 8) | array[3]);
+		if (orig_ip_addr != ct_ftp_info->fbxl2br_wan)
+			goto donttouch_l2br;
+
+		/* now mangle the remote address */
+		orig_port = htons(array[4] << 8 | array[5]);
+		len = sprintf(buffer, "%u,%u,%u,%u,%u,%u",
+			      NIPQUAD(ct_ftp_info->fbxl2br_remote),
+			      orig_port >> 8 , orig_port & 0xFF);
+
+		ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff,
+					 matchlen, buffer, len);
+
+		/* then adjust as if nothing happened */
+		matchlen = len;
+		array[0] = (ct_ftp_info->fbxl2br_remote >> 24) & 0xff;
+		array[1] = (ct_ftp_info->fbxl2br_remote >> 16) & 0xff;
+		array[2] = (ct_ftp_info->fbxl2br_remote >> 8) & 0xff;
+		array[3] = (ct_ftp_info->fbxl2br_remote) & 0xff;
+	}
+donttouch_l2br:
+
+#endif
+
 	if (htonl((array[0] << 24) | (array[1] << 16) | (array[2] << 8) | array[3])
 	    != ct->tuplehash[dir].tuple.src.ip) {
 		/* Enrico Scholz's passive FTP to partially RNAT'd ftp
diff -ruw linux-2.6.20.14/net/ipv4/netfilter/ip_conntrack_proto_tcp.c linux-2.6.20.14-fbx/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
--- linux-2.6.20.14/net/ipv4/netfilter/ip_conntrack_proto_tcp.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/net/ipv4/netfilter/ip_conntrack_proto_tcp.c	2011-09-26 15:07:56.608834037 +0200
@@ -31,6 +31,7 @@
 
 #include <net/tcp.h>
 
+#include <linux/netfilter/nf_conntrack_common.h>
 #include <linux/netfilter_ipv4.h>
 #include <linux/netfilter_ipv4/ip_conntrack.h>
 #include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
@@ -50,12 +51,9 @@
     If it's non-zero, we mark only out of window RST segments as INVALID. */
 int ip_ct_tcp_be_liberal __read_mostly = 0;
 
-/* When connection is picked up from the middle, how many packets are required
-   to pass in each direction when we assume we are in sync - if any side uses
-   window scaling, we lost the game. 
-   If it is set to zero, we disable picking up already established 
+/* If it is set to zero, we disable picking up already established
    connections. */
-int ip_ct_tcp_loose __read_mostly = 3;
+int ip_ct_tcp_loose __read_mostly = 1;
 
 /* Max number of the retransmitted packets without receiving an (acceptable) 
    ACK from the destination. If this number is reached, a shorter timer 
@@ -694,11 +692,10 @@
 	    	before(sack, receiver->td_end + 1),
 	    	after(ack, receiver->td_end - MAXACKWINDOW(sender)));
 	
-	if (sender->loose || receiver->loose ||
-	    (before(seq, sender->td_maxend + 1) &&
+	if (before(seq, sender->td_maxend + 1) &&
 	     after(end, sender->td_end - receiver->td_maxwin - 1) &&
 	     before(sack, receiver->td_end + 1) &&
-	     after(ack, receiver->td_end - MAXACKWINDOW(sender)))) {
+	    after(ack, receiver->td_end - MAXACKWINDOW(sender))) {
 	    	/*
 		 * Take into account window scaling (RFC 1323).
 		 */
@@ -743,15 +740,13 @@
 				state->retrans = 0;
 			}
 		}
-		/*
-		 * Close the window of disabled window tracking :-)
-		 */
-		if (sender->loose)
-			sender->loose--;
-		
 		res = 1;
 	} else {
-		if (LOG_INVALID(IPPROTO_TCP))
+		res = 0;
+		if (sender->flags & IP_CT_TCP_FLAG_BE_LIBERAL ||
+		    ip_ct_tcp_be_liberal)
+			res = 1;
+		if (!res && LOG_INVALID(IPPROTO_TCP))
 			nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
 			"ip_ct_tcp: %s ",
 			before(seq, sender->td_maxend + 1) ?
@@ -762,8 +757,6 @@
 			: "ACK is over the upper bound (ACKed data not seen yet)"
 			: "SEQ is under the lower bound (already ACKed data retransmitted)"
 			: "SEQ is over the upper bound (over the window of the receiver)");
-
-		res = ip_ct_tcp_be_liberal;
   	}
   
 	DEBUGP("tcp_in_window: res=%i sender end=%u maxend=%u maxwin=%u "
@@ -986,6 +979,15 @@
 					      NULL, "ip_ct_tcp: invalid SYN");
 			return -NF_ACCEPT;
 		}
+#if defined(CONFIG_IP_NF_TPROXY) || defined (CONFIG_IP_NF_TPROXY_MODULE)
+	case TCP_CONNTRACK_TIME_WAIT:
+		/* Set MAY_DELETE if NAT subsystem may drop connection when it is clashing */
+		if (test_bit(IPS_TPROXY_BIT, &conntrack->status)) {
+			DEBUGP(KERN_DEBUG "Marking TPROXY-related TIME_WAIT conntrack entry MAY_DELETE\n");
+			set_bit(IPS_MAY_DELETE_BIT, &conntrack->status);
+		}
+		break;
+#endif
 	case TCP_CONNTRACK_CLOSE:
 		if (index == TCP_RST_SET
 		    && ((test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)
@@ -1067,6 +1069,15 @@
 	return NF_ACCEPT;
 }
  
+#ifdef CONFIG_IP_FFN
+int external_tcp_packet(struct ip_conntrack *conntrack,
+			const struct sk_buff *skb,
+			enum ip_conntrack_info ctinfo)
+{
+	return tcp_packet(conntrack, skb, ctinfo);
+}
+#endif
+ 
 /* Called when a new connection for this protocol found. */
 static int tcp_new(struct ip_conntrack *conntrack,
 		   const struct sk_buff *skb)
@@ -1107,8 +1118,6 @@
 
 		tcp_options(skb, iph, th, &conntrack->proto.tcp.seen[0]);
 		conntrack->proto.tcp.seen[1].flags = 0;
-		conntrack->proto.tcp.seen[0].loose = 
-		conntrack->proto.tcp.seen[1].loose = 0;
 	} else if (ip_ct_tcp_loose == 0) {
 		/* Don't try to pick up connections. */
 		return 0;
@@ -1129,11 +1138,11 @@
 			conntrack->proto.tcp.seen[0].td_maxwin;
 		conntrack->proto.tcp.seen[0].td_scale = 0;
 
-		/* We assume SACK. Should we assume window scaling too? */
+		/* We assume SACK and liberal window checking to handle
+		 * window scaling */
 		conntrack->proto.tcp.seen[0].flags =
-		conntrack->proto.tcp.seen[1].flags = IP_CT_TCP_FLAG_SACK_PERM;
-		conntrack->proto.tcp.seen[0].loose = 
-		conntrack->proto.tcp.seen[1].loose = ip_ct_tcp_loose;
+		conntrack->proto.tcp.seen[1].flags = IP_CT_TCP_FLAG_SACK_PERM |
+						     IP_CT_TCP_FLAG_BE_LIBERAL;
 	}
     
 	conntrack->proto.tcp.seen[1].td_end = 0;
diff -ruw linux-2.6.20.14/net/ipv4/netfilter/ip_conntrack_proto_udp.c linux-2.6.20.14-fbx/net/ipv4/netfilter/ip_conntrack_proto_udp.c
--- linux-2.6.20.14/net/ipv4/netfilter/ip_conntrack_proto_udp.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/net/ipv4/netfilter/ip_conntrack_proto_udp.c	2011-09-26 15:07:56.608834037 +0200
@@ -81,6 +81,15 @@
 	return NF_ACCEPT;
 }
 
+#ifdef CONFIG_IP_FFN
+int external_udp_packet(struct ip_conntrack *conntrack,
+			const struct sk_buff *skb,
+			enum ip_conntrack_info ctinfo)
+{
+	return udp_packet(conntrack, skb, ctinfo);
+}
+#endif
+
 /* Called when a new connection for this protocol found. */
 static int udp_new(struct ip_conntrack *conntrack, const struct sk_buff *skb)
 {
diff -ruw linux-2.6.20.14/net/ipv4/netfilter/ip_conntrack_standalone.c linux-2.6.20.14-fbx/net/ipv4/netfilter/ip_conntrack_standalone.c
--- linux-2.6.20.14/net/ipv4/netfilter/ip_conntrack_standalone.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/net/ipv4/netfilter/ip_conntrack_standalone.c	2011-09-26 15:07:56.608834037 +0200
@@ -913,6 +913,9 @@
 EXPORT_SYMBOL(invert_tuplepr);
 EXPORT_SYMBOL(ip_conntrack_alter_reply);
 EXPORT_SYMBOL(ip_conntrack_destroyed);
+#if defined(CONFIG_IP_NF_TPROXY) || defined (CONFIG_IP_NF_TPROXY_MODULE)
+EXPORT_SYMBOL_GPL(ip_conntrack_confirmed);
+#endif
 EXPORT_SYMBOL(need_conntrack);
 EXPORT_SYMBOL(ip_conntrack_helper_register);
 EXPORT_SYMBOL(ip_conntrack_helper_unregister);
@@ -925,6 +928,9 @@
 EXPORT_SYMBOL_GPL(ip_conntrack_expect_find_get);
 EXPORT_SYMBOL(ip_conntrack_expect_related);
 EXPORT_SYMBOL(ip_conntrack_unexpect_related);
+#ifdef CONFIG_IP_NF_NAT_NRES
+EXPORT_SYMBOL(ip_conntrack_expect_destroyed);
+#endif
 EXPORT_SYMBOL_GPL(ip_conntrack_expect_list);
 EXPORT_SYMBOL_GPL(ip_ct_unlink_expect);
 
@@ -961,3 +967,6 @@
 EXPORT_SYMBOL_GPL(ip_ct_port_tuple_to_nfattr);
 EXPORT_SYMBOL_GPL(ip_ct_port_nfattr_to_tuple);
 #endif
+#if defined(CONFIG_IP_NF_TPROXY) || defined(CONFIG_IP_NF_TPROXY_MODULE)
+EXPORT_SYMBOL_GPL(__death_by_timeout);
+#endif
diff -ruw linux-2.6.20.14/net/ipv4/netfilter/ip_nat_core.c linux-2.6.20.14-fbx/net/ipv4/netfilter/ip_nat_core.c
--- linux-2.6.20.14/net/ipv4/netfilter/ip_nat_core.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/net/ipv4/netfilter/ip_nat_core.c	2011-09-26 15:07:56.608834037 +0200
@@ -14,6 +14,8 @@
 #include <linux/skbuff.h>
 #include <linux/netfilter_ipv4.h>
 #include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/list.h>
 #include <net/checksum.h>
 #include <net/icmp.h>
 #include <net/ip.h>
@@ -22,6 +24,7 @@
 #include <linux/udp.h>
 #include <linux/jhash.h>
 
+#include <linux/netfilter/nf_conntrack_common.h>
 #include <linux/netfilter_ipv4/ip_conntrack.h>
 #include <linux/netfilter_ipv4/ip_conntrack_core.h>
 #include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
@@ -38,10 +41,17 @@
 #endif
 
 DEFINE_RWLOCK(ip_nat_lock);
+EXPORT_SYMBOL_GPL(ip_nat_lock);
 
 /* Calculated at init based on memory size */
 static unsigned int ip_nat_htable_size;
 
+#ifdef CONFIG_IP_NF_NAT_NRES
+static kmem_cache_t *ip_nat_reserved_cachep;
+static atomic_t ip_nat_reserved_count;
+static struct list_head *natreserved;
+#endif
+
 static struct list_head *bysource;
 
 #define MAX_IP_NAT_PROTO 256
@@ -86,6 +96,19 @@
 			    tuple->dst.protonum, 0) % ip_nat_htable_size;
 }
 
+#ifdef CONFIG_IP_NF_NAT_NRES
+static inline unsigned int
+hash_nat_reserved(const struct ip_conntrack_manip *foreign,
+		  const struct ip_conntrack_manip *peer,
+		  const u_int16_t proto)
+{
+	return jhash_3words(foreign->ip,
+			    (proto << 16) + foreign->u.all,
+			    (peer ? (peer->ip + peer->u.all) : 0),
+			    0) % ip_nat_htable_size;
+}
+#endif
+
 /* Noone using conntrack by the time this called. */
 static void ip_nat_cleanup_conntrack(struct ip_conntrack *conn)
 {
@@ -97,10 +120,417 @@
 	write_unlock_bh(&ip_nat_lock);
 }
 
+static void __ip_nat_cleanup_conntrack(struct ip_conntrack *conn)
+{
+	if (!(conn->status & IPS_NAT_DONE_MASK))
+		return;
+
+	list_del(&conn->nat.info.bysource);
+}
+
+#ifdef CONFIG_IP_NF_NAT_NRES
+static inline int
+reserved_manip_cmp(const struct ip_nat_reserved *i,
+		   const struct ip_conntrack_manip *manip,
+		   const u_int16_t proto)
+{
+	DEBUGP("reserved_manip_cmp: manip proto %u %u.%u.%u.%u:%u, "
+	       "reservation proto %u %u.%u.%u.%u:%u\n peer %u.%u.%u.%u:%u\n",
+			proto, NIPQUAD(manip->ip), ntohs(manip->u.all),
+			i->proto, NIPQUAD(i->manip.ip), ntohs(i->manip.u.all),
+			NIPQUAD(i->peer.ip), ntohs(i->peer.u.all));
+	return (i->proto == proto &&
+		i->manip.ip == manip->ip && i->manip.u.all == manip->u.all);
+}
+
+static inline int
+reserved_manip_cmp_peer(const struct ip_nat_reserved *i,
+			const struct ip_conntrack_manip *manip,
+			const u_int16_t proto,
+			const struct ip_conntrack_manip *peer)
+{
+	DEBUGP("reserved_manip_cmp_peer: manip proto %u %u.%u.%u.%u:%u peer %u.%u.%u.%u:%u, "
+	       "reservation proto %u %u.%u.%u.%u:%u peer %u.%u.%u.%u:%u\n",
+	       proto, NIPQUAD(manip->ip), ntohs(manip->u.all),
+	       NIPQUAD(peer->ip), ntohs(peer->u.all),
+	       i->proto, NIPQUAD(i->manip.ip), ntohs(i->manip.u.all),
+	       NIPQUAD(i->peer.ip), ntohs(i->peer.u.all));
+
+	return (i->proto == proto &&
+		i->manip.ip == manip->ip && i->manip.u.all == manip->u.all &&
+		((i->peer.ip == 0) || (i->peer.ip == peer->ip && i->peer.u.all == peer->u.all)));
+}
+
+static inline int
+reserved_manip_cmp_peer_exact(const struct ip_nat_reserved *i,
+			      const struct ip_conntrack_manip *manip,
+			      const u_int16_t proto,
+			      const struct ip_conntrack_manip *peer)
+{
+	DEBUGP("reserved_manip_cmp_peer_exact: manip proto %u %u.%u.%u.%u:%u peer %u.%u.%u.%u:%u, "
+	       "reservation proto %u %u.%u.%u.%u:%u peer %u.%u.%u.%u:%u\n",
+	       proto, NIPQUAD(manip->ip), ntohs(manip->u.all),
+	       NIPQUAD(peer->ip), ntohs(peer->u.all),
+	       i->proto, NIPQUAD(i->manip.ip), ntohs(i->manip.u.all),
+	       NIPQUAD(i->peer.ip), ntohs(i->peer.u.all));
+
+	return (i->proto == proto &&
+		i->manip.ip == manip->ip && i->manip.u.all == manip->u.all &&
+		i->peer.ip == peer->ip && i->peer.u.all == peer->u.all);
+}
+
+/* Is this manip reserved?
+ * exact means full peer match is required, used for reservation deletion */
+static struct ip_nat_reserved *
+__ip_nat_reserved_find_manip(const struct ip_conntrack_manip *manip,
+			     const u_int16_t proto,
+			     const struct ip_conntrack_manip *peer,
+			     const int exact)
+{
+	struct ip_nat_reserved *i;
+	struct ip_nat_reserved *res = NULL;
+	unsigned int h = hash_nat_reserved(manip, peer, proto);
+
+	DEBUGP("__ip_nat_reserved_find_manip: find proto %u %u.%u.%u.%u:%u\n",
+			proto, NIPQUAD(manip->ip), ntohs(manip->u.all));
+
+	if (peer) {
+		if (exact)
+			list_for_each_entry(i, &natreserved[h], hash)
+				if (reserved_manip_cmp_peer_exact(i, manip, proto, peer)) {
+					res = i;
+					goto out;
+				}
+		else
+			list_for_each_entry(i, &natreserved[h], hash)
+				if (reserved_manip_cmp_peer(i, manip, proto, peer)) {
+					res = i;
+					goto out;
+				}
+	} else
+		list_for_each_entry(i, &natreserved[h], hash)
+			if (reserved_manip_cmp(i, manip, proto)) {
+				res = i;
+				goto out;
+			}
+
+out:
+	return res;
+}
+
+/* Is this tuple clashing with a reserved manip? */
+static struct ip_nat_reserved *
+__ip_nat_reserved_find_tuple(const struct ip_conntrack_tuple *tuple,
+			     enum ip_nat_manip_type maniptype)
+{
+	struct ip_conntrack_manip m = {.ip = tuple->dst.ip, .u = {.all = tuple->dst.u.all}};
+
+	if (maniptype == IP_NAT_MANIP_SRC) {
+		DEBUGP("__ip_nat_reserved_find_tuple: IP_NAT_MANIP_SRC search\n");
+		return __ip_nat_reserved_find_manip(&tuple->src, tuple->dst.protonum, &m, 0);
+	} else {
+		DEBUGP("__ip_nat_reserved_find_tuple: IP_NAT_MANIP_DST search\n");
+		return __ip_nat_reserved_find_manip(&m, tuple->dst.protonum, &tuple->src, 0);
+	}
+}
+
+static inline int
+clashing_ct_cmp(const struct ip_conntrack_tuple_hash *i, const void *data)
+{
+	const struct ip_conntrack_manip *m = (struct ip_conntrack_manip *) data;
+	const struct ip_conntrack_tuple *t = &i->tuple;
+
+	/* FIXME: every connection has two entries, we should check only the REPLY direction */
+
+	DEBUGP("clashing_ct_cmp: manip %u.%u.%u.%u:%u ct reply src %u.%u.%u.%u:%u dst %u.%u.%u.%u:%u\n",
+			NIPQUAD(m->ip), ntohs(m->u.all), NIPQUAD(t->src.ip), ntohs(t->src.u.all),
+			NIPQUAD(t->dst.ip), ntohs(t->dst.u.all));
+	return (((t->src.ip == m->ip) && (t->src.u.all == m->u.all)) ||
+		((t->dst.ip == m->ip) && (t->dst.u.all == m->u.all)));
+}
+
+/* Create a new reservation */
+struct ip_nat_reserved *
+__ip_nat_reserved_new_hash(const struct ip_conntrack_manip *manip,
+			   const u_int16_t proto,
+			   const struct ip_conntrack_manip *peer)
+{
+	struct ip_nat_reserved *res;
+	struct ip_conntrack_tuple_hash *h = NULL;
+	unsigned int hash;
+
+	DEBUGP("__ip_nat_reserved_new_hash: manip proto %u %u.%u.%u.%u:%u\n",
+			proto, NIPQUAD(manip->ip), ntohs(manip->u.all));
+
+	/* check if it's already reserved */
+	if (__ip_nat_reserved_find_manip(manip, proto, peer, 1)) {
+		DEBUGP("__ip_nat_reserved_new_hash: already reserved\n");
+		return NULL;
+	}
+
+	/* FIXME: check if a clashing connection exists... This is problematic,
+	 * since the final decision in ip_nat_used_tuple() is based on a full
+	 * tuple, but we only have a manip... =(:< */
+
+	/* Current solutuion: we provide two methods for checking:
+	 *   - Strong check: in this case, the conntrack table is scanned if an
+	 *     already existing connection uses the manip in its REPLY direction.
+	 *     if such a conntrack entry is found, the mapping fails. This check is
+	 *     extremely pessimistic, since it fails to register reservations which could
+	 *     happily coexist with current conntracks if the other side of the tuple is
+	 *     different...
+	 *   - Exact check: if the callee provides a peer manip, then an exact lookup
+	 *     can be made in the conntrack hash. This is a more fine-grained check.
+	 */
+
+	if (peer) {
+		/* Exact check */
+		struct ip_conntrack_tuple t = {.src = *peer,
+					       .dst = {.protonum = proto,
+						       .ip = manip->ip,
+						       .u = {.all = manip->u.all}}};
+		struct ip_conntrack *ctrack;
+
+		h = ip_conntrack_find_get(&t, NULL);
+
+#if defined(CONFIG_IP_NF_TPROXY) || defined (CONFIG_IP_NF_TPROXY_MODULE)
+		if ((h != NULL) &&
+		    (ctrack = tuplehash_to_ctrack(h)) &&
+		    test_bit(IPS_MAY_DELETE_BIT, &ctrack->status)) {
+			DEBUGP("Deleting old conntrack entry for NAT\n");
+			__ip_nat_cleanup_conntrack(ctrack);
+			ctrack->status &= ~IPS_NAT_DONE_MASK;
+			if (del_timer(&ctrack->timeout))
+				ctrack->timeout.function((unsigned long)ctrack);
+			ip_conntrack_put(ctrack);
+			h = NULL;
+		}
+#endif
+
+		if (h) {
+			DEBUGP("__ip_nat_reserved_new_hash: manip clashes with an already existing connection\n");
+			ip_conntrack_put(tuplehash_to_ctrack(h));
+			return NULL;
+		}
+	} else {
+		/* Strong check: we have only a manip, unfortunately we scan the whole conntrack
+		 * hash for possible clashing connections... */
+		unsigned int i;
+		int found = 0, repeat;
+		struct ip_conntrack *ctrack;
+
+		write_lock_bh(&ip_conntrack_lock);
+		for (i = 0; !found && i < ip_conntrack_htable_size; i++) {
+			do {
+				repeat = 0;
+				list_for_each_entry(h, &ip_conntrack_hash[i], list)
+					if (clashing_ct_cmp(h, manip)) {
+						found = 1;
+						break;
+					}
+				if (found &&
+				    (ctrack = tuplehash_to_ctrack(h)) &&
+				    (ctrack->status & IPS_MAY_DELETE)) {
+					DEBUGP("Deleting old conntrack entry for NAT\n");
+					__ip_nat_cleanup_conntrack(ctrack);
+					ctrack->status &= ~IPS_NAT_DONE_MASK;
+					if (del_timer(&ctrack->timeout))
+						__death_by_timeout((unsigned long)ctrack);
+					found = 0;
+					repeat = 1;
+				}
+			} while (repeat);
+		}
+		write_unlock_bh(&ip_conntrack_lock);
+
+		if (found) {
+			DEBUGP("__ip_nat_reserved_new_hash: manip clashes with an already existing connection\n");
+			return NULL;
+		}
+	}
+
+	/* else allocate a new structure */
+	res = kmem_cache_alloc(ip_nat_reserved_cachep, GFP_ATOMIC);
+	if (!res)
+		return NULL;
+
+	memset(res, 0, sizeof(*res));
+	res->proto = proto;
+	res->manip = *manip;
+	if (peer)
+		res->peer = *peer;
+
+	/* put it into the hash */
+	hash = hash_nat_reserved(manip, peer, proto);
+	atomic_inc(&ip_nat_reserved_count);
+	list_add(&res->hash, &natreserved[hash]);
+	DEBUGP("__ip_nat_reserved_new_hash: hashed manip proto %u %u.%u.%u.%u:%u\n",
+			proto, NIPQUAD(manip->ip), ntohs(manip->u.all));
+
+	return res;
+}
+EXPORT_SYMBOL_GPL(__ip_nat_reserved_new_hash);
+
+/* Register a new reservation */
+static int
+__ip_nat_reserved_register(struct ip_conntrack_expect *expect,
+			   const struct ip_conntrack_manip *manip,
+			   const u_int16_t proto,
+			   const struct ip_conntrack_manip *peer)
+{
+	struct ip_nat_reserved *res;
+
+	DEBUGP("__ip_nat_reserved_register: registering proto %u %u.%u.%u.%u:%u\n",
+			proto, NIPQUAD(manip->ip), ntohs(manip->u.all));
+
+	/* allocate and put into the hash */
+	res = __ip_nat_reserved_new_hash(manip, proto, peer);
+	if (!res)
+		return 0;
+
+	/* append to the per-expectation reserved list */
+	list_add_tail(&res->exp, &expect->reserved_list);
+
+	return 1;
+}
+
+int
+ip_nat_reserved_register(struct ip_conntrack_expect *expect,
+			 const struct ip_conntrack_manip *manip,
+			 const u_int16_t proto,
+			 const struct ip_conntrack_manip *peer)
+{
+	int ret;
+
+	write_lock_bh(&ip_nat_lock);
+
+	ret = __ip_nat_reserved_register(expect, manip, proto, peer);
+
+	write_unlock_bh(&ip_nat_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(ip_nat_reserved_register);
+
+/* Unhash a reservation */
+struct ip_nat_reserved *
+__ip_nat_reserved_unhash(const struct ip_conntrack_manip *manip,
+		         const u_int16_t proto,
+			 const struct ip_conntrack_manip *peer)
+{
+	struct ip_nat_reserved *res;
+
+	DEBUGP("__ip_nat_reserved_unhash: unhashing proto %u %u.%u.%u.%u:%u\n",
+			proto, NIPQUAD(manip->ip), ntohs(manip->u.all));
+
+	/* check if it's really reserved */
+	if (!(res = __ip_nat_reserved_find_manip(manip, proto, peer, 1))) {
+		DEBUGP("__ip_nat_reserved_unhash: trying to unreg a nonexisting reservation\n");
+		return NULL;
+	}
+
+	/* delete from the hash table */
+	list_del(&res->hash);
+
+	atomic_dec(&ip_nat_reserved_count);
+
+	return res;
+}
+EXPORT_SYMBOL_GPL(__ip_nat_reserved_unhash);
+
+/* Return a reservation structure into the slab cache */
+void
+__ip_nat_reserved_free(struct ip_nat_reserved *res)
+{
+	kmem_cache_free(ip_nat_reserved_cachep, res);
+}
+EXPORT_SYMBOL_GPL(__ip_nat_reserved_free);
+
+/* Unregister a reservation */
+static int
+__ip_nat_reserved_unregister(struct ip_conntrack_expect *expect,
+			     const struct ip_conntrack_manip *manip,
+			     const u_int16_t proto,
+			     const struct ip_conntrack_manip *peer)
+{
+	struct ip_nat_reserved *res;
+
+	DEBUGP("__ip_nat_reserved_unregister: unregistering proto %u %u.%u.%u.%u:%u\n",
+			proto, NIPQUAD(manip->ip), ntohs(manip->u.all));
+
+	/* look up and unhash */
+	res = __ip_nat_reserved_unhash(manip, proto, peer);
+	if (!res)
+		return 0;
+
+	/* delete from the per-expectation list */
+	list_del(&res->exp);
+
+	/* free the structure */
+	__ip_nat_reserved_free(res);
+
+	return 1;
+}
+
+int
+ip_nat_reserved_unregister(struct ip_conntrack_expect *expect,
+			   const struct ip_conntrack_manip *manip,
+			   const u_int16_t proto,
+			   const struct ip_conntrack_manip *peer)
+{
+	int ret;
+
+	write_lock_bh(&ip_nat_lock);
+
+	ret = __ip_nat_reserved_unregister(expect, manip, proto, peer);
+
+	write_unlock_bh(&ip_nat_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(ip_nat_reserved_unregister);
+
+/* Unregister all reservations for a given expectation */
+void
+ip_nat_reserved_unregister_all(struct ip_conntrack_expect *expect)
+{
+	struct list_head *i;
+	struct ip_nat_reserved *res;
+
+	DEBUGP("ip_nat_reserved_unregister_all: deleting all reservations for expectation %p\n",
+			expect);
+
+	write_lock_bh(&ip_nat_lock);
+
+	i = expect->reserved_list.next;
+	while (i != &expect->reserved_list) {
+		res = list_entry(i, struct ip_nat_reserved, exp);
+		i = i->next;
+
+		/* clear from lists */
+		list_del(&res->hash);
+		list_del(&res->exp);
+
+		kmem_cache_free(ip_nat_reserved_cachep, res);
+	}
+
+	write_unlock_bh(&ip_nat_lock);
+}
+EXPORT_SYMBOL_GPL(ip_nat_reserved_unregister_all);
+
+static void
+ip_nat_reserved_cleanup_expect(struct ip_conntrack_expect *expect)
+{
+	ip_nat_reserved_unregister_all(expect);
+}
+#endif /* CONFIG_IP_NF_NAT_NRES */
+
 /* Is this tuple already taken? (not by us) */
 int
 ip_nat_used_tuple(const struct ip_conntrack_tuple *tuple,
-		  const struct ip_conntrack *ignored_conntrack)
+		  const struct ip_conntrack *ignored_conntrack,
+		  const enum ip_nat_manip_type maniptype,
+		  const unsigned int flags)
 {
 	/* Conntrack tracking doesn't keep track of outgoing tuples; only
 	   incoming ones.  NAT means they don't have a fixed mapping,
@@ -108,9 +538,46 @@
 
 	   We could keep a separate hash if this proves too slow. */
 	struct ip_conntrack_tuple reply;
+	struct ip_conntrack_tuple_hash *h;
+	struct ip_conntrack *ctrack;
+#ifdef CONFIG_IP_NF_NAT_NRES
+	struct ip_nat_reserved *res;
 
+	/* check if the tuple is reserved if there are any reservations */
+	if (atomic_read(&ip_nat_reserved_count)) {
+		read_lock_bh(&ip_nat_lock);
+		res = __ip_nat_reserved_find_tuple(tuple, maniptype);
+		read_unlock_bh(&ip_nat_lock);
+
+		/* If we may not allocate reserved ports, return */
+		if (!(flags & IP_NAT_RANGE_USE_RESERVED) && res)
+			return 1;
+	}
+#endif
+
+	/* check if it's taken by an existing connection */
 	invert_tuplepr(&reply, tuple);
-	return ip_conntrack_tuple_taken(&reply, ignored_conntrack);
+	h = ip_conntrack_find_get(&reply, ignored_conntrack);
+
+#if defined(CONFIG_IP_NF_TPROXY) || defined (CONFIG_IP_NF_TPROXY_MODULE)
+	/* check if that conntrack is marked MAY_DELETE, if so, get rid of it... */
+	if ((h != NULL) &&
+	    (ctrack = tuplehash_to_ctrack(h)) &&
+	    test_bit(IPS_MAY_DELETE_BIT, &ctrack->status)) {
+		DEBUGP("Deleting old conntrack entry for NAT\n");
+		__ip_nat_cleanup_conntrack(ctrack);
+		ctrack->status &= ~IPS_NAT_DONE_MASK;
+		if (del_timer(&ctrack->timeout))
+			ctrack->timeout.function((unsigned long)ctrack);
+		ip_conntrack_put(tuplehash_to_ctrack(h));
+		h = NULL;
+	}
+#endif
+
+	if (h)
+		ip_conntrack_put(tuplehash_to_ctrack(h));
+
+	return h != NULL;
 }
 EXPORT_SYMBOL(ip_nat_used_tuple);
 
@@ -246,7 +713,7 @@
 	if (maniptype == IP_NAT_MANIP_SRC) {
 		if (find_appropriate_src(orig_tuple, tuple, range)) {
 			DEBUGP("get_unique_tuple: Found current src map\n");
-			if (!ip_nat_used_tuple(tuple, conntrack))
+			if (!ip_nat_used_tuple(tuple, conntrack, maniptype, range->flags))
 				return;
 		}
 	}
@@ -264,7 +731,7 @@
 	/* Only bother mapping if it's not already in range and unique */
 	if ((!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)
 	     || proto->in_range(tuple, maniptype, &range->min, &range->max))
-	    && !ip_nat_used_tuple(tuple, conntrack)) {
+	    && !ip_nat_used_tuple(tuple, conntrack, maniptype, range->flags)) {
 		ip_nat_proto_put(proto);
 		return;
 	}
@@ -336,8 +803,8 @@
 EXPORT_SYMBOL(ip_nat_setup_info);
 
 /* Returns true if succeeded. */
-static int
-manip_pkt(u_int16_t proto,
+int
+ip_nat_manip_pkt(u_int16_t proto,
 	  struct sk_buff **pskb,
 	  unsigned int iphdroff,
 	  const struct ip_conntrack_tuple *target,
@@ -370,6 +837,7 @@
 	}
 	return 1;
 }
+EXPORT_SYMBOL_GPL(ip_nat_manip_pkt);
 
 /* Do packet manipulations according to ip_nat_setup_info. */
 unsigned int ip_nat_packet(struct ip_conntrack *ct,
@@ -397,7 +865,7 @@
 		/* We are aiming to look like inverse of other direction. */
 		invert_tuplepr(&target, &ct->tuplehash[!dir].tuple);
 
-		if (!manip_pkt(target.dst.protonum, pskb, 0, &target, mtype))
+		if (!ip_nat_manip_pkt(target.dst.protonum, pskb, 0, &target, mtype))
 			return NF_DROP;
 	}
 	return NF_ACCEPT;
@@ -460,7 +928,7 @@
 	   pass all hooks (locally-generated ICMP).  Consider incoming
 	   packet: PREROUTING (DST manip), routing produces ICMP, goes
 	   through POSTROUTING (which must correct the DST manip). */
-	if (!manip_pkt(inside->ip.protocol, pskb,
+	if (!ip_nat_manip_pkt(inside->ip.protocol, pskb,
 		       (*pskb)->nh.iph->ihl*4
 		       + sizeof(inside->icmp),
 		       &ct->tuplehash[!dir].tuple,
@@ -489,7 +957,7 @@
 
 	if (ct->status & statusbit) {
 		invert_tuplepr(&target, &ct->tuplehash[!dir].tuple);
-		if (!manip_pkt(0, pskb, 0, &target, manip))
+		if (!ip_nat_manip_pkt(0, pskb, 0, &target, manip))
 			return 0;
 	}
 
@@ -578,10 +1046,29 @@
 	/* Leave them the same for the moment. */
 	ip_nat_htable_size = ip_conntrack_htable_size;
 
+#ifdef CONFIG_IP_NF_NAT_NRES
+	/* Create nat_reserved slab cache */
+	ip_nat_reserved_cachep = kmem_cache_create("ip_nat_reserved",
+						   sizeof(struct ip_nat_reserved), 0,
+						   SLAB_HWCACHE_ALIGN, NULL, NULL);
+	if (!ip_nat_reserved_cachep) {
+		printk(KERN_ERR "Unable to create ip_nat_reserved slab cache\n");
+		return -ENOMEM;
+	}
+#endif
+
 	/* One vmalloc for both hash tables */
+#ifndef CONFIG_IP_NF_NAT_NRES
 	bysource = vmalloc(sizeof(struct list_head) * ip_nat_htable_size);
+#else
+        bysource = vmalloc(sizeof(struct list_head) * ip_nat_htable_size * 2);
+#endif
 	if (!bysource)
-		return -ENOMEM;
+		goto free_reserved_slab;
+
+#ifdef CONFIG_IP_NF_NAT_NRES
+	natreserved = bysource + ip_nat_htable_size;
+#endif
 
 	/* Sew in builtin protocols. */
 	write_lock_bh(&ip_nat_lock);
@@ -594,15 +1081,28 @@
 
 	for (i = 0; i < ip_nat_htable_size; i++) {
 		INIT_LIST_HEAD(&bysource[i]);
+#ifdef CONFIG_IP_NF_NAT_NRES
+		INIT_LIST_HEAD(&natreserved[i]);
+#endif
 	}
 
 	/* FIXME: Man, this is a hack.  <SIGH> */
 	IP_NF_ASSERT(ip_conntrack_destroyed == NULL);
 	ip_conntrack_destroyed = &ip_nat_cleanup_conntrack;
+#ifdef CONFIG_IP_NF_NAT_NRES
+	IP_NF_ASSERT(ip_conntrack_expect_destroyed == NULL);
+	ip_conntrack_expect_destroyed = &ip_nat_reserved_cleanup_expect;
+#endif
 
 	/* Initialize fake conntrack so that NAT will skip it */
 	ip_conntrack_untracked.status |= IPS_NAT_DONE_MASK;
 	return 0;
+
+free_reserved_slab:
+#ifdef CONFIG_IP_NF_NAT_NRES
+	kmem_cache_destroy(ip_nat_reserved_cachep);
+#endif
+	return -ENOMEM;
 }
 
 /* Clear NAT section of all conntracks, in case we're loaded again. */
@@ -617,6 +1117,10 @@
 {
 	ip_ct_iterate_cleanup(&clean_nat, NULL);
 	ip_conntrack_destroyed = NULL;
+#ifdef CONFIG_IP_NF_NAT_NRES
+	ip_conntrack_expect_destroyed = NULL;
+	kmem_cache_destroy(ip_nat_reserved_cachep);
+#endif
 	vfree(bysource);
 }
 
diff -ruw linux-2.6.20.14/net/ipv4/netfilter/ip_nat_proto_gre.c linux-2.6.20.14-fbx/net/ipv4/netfilter/ip_nat_proto_gre.c
--- linux-2.6.20.14/net/ipv4/netfilter/ip_nat_proto_gre.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/net/ipv4/netfilter/ip_nat_proto_gre.c	2011-09-26 15:07:56.608834037 +0200
@@ -93,7 +93,7 @@
 
 	for (i = 0; i < range_size; i++, key++) {
 		*keyptr = htons(min + key % range_size);
-		if (!ip_nat_used_tuple(tuple, conntrack))
+		if (!ip_nat_used_tuple(tuple, conntrack, maniptype, range->flags))
 			return 1;
 	}
 
diff -ruw linux-2.6.20.14/net/ipv4/netfilter/ip_nat_proto_icmp.c linux-2.6.20.14-fbx/net/ipv4/netfilter/ip_nat_proto_icmp.c
--- linux-2.6.20.14/net/ipv4/netfilter/ip_nat_proto_icmp.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/net/ipv4/netfilter/ip_nat_proto_icmp.c	2011-09-26 15:07:56.608834037 +0200
@@ -46,7 +46,7 @@
 	for (i = 0; i < range_size; i++, id++) {
 		tuple->src.u.icmp.id = htons(ntohs(range->min.icmp.id) +
 		                             (id % range_size));
-		if (!ip_nat_used_tuple(tuple, conntrack))
+		if (!ip_nat_used_tuple(tuple, conntrack, maniptype, range->flags))
 			return 1;
 	}
 	return 0;
diff -ruw linux-2.6.20.14/net/ipv4/netfilter/ip_nat_proto_tcp.c linux-2.6.20.14-fbx/net/ipv4/netfilter/ip_nat_proto_tcp.c
--- linux-2.6.20.14/net/ipv4/netfilter/ip_nat_proto_tcp.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/net/ipv4/netfilter/ip_nat_proto_tcp.c	2011-09-26 15:07:56.608834037 +0200
@@ -77,7 +77,7 @@
 
 	for (i = 0; i < range_size; i++, port++) {
 		*portptr = htons(min + port % range_size);
-		if (!ip_nat_used_tuple(tuple, conntrack)) {
+		if (!ip_nat_used_tuple(tuple, conntrack, maniptype, range->flags)) {
 			return 1;
 		}
 	}
diff -ruw linux-2.6.20.14/net/ipv4/netfilter/ip_nat_proto_udp.c linux-2.6.20.14-fbx/net/ipv4/netfilter/ip_nat_proto_udp.c
--- linux-2.6.20.14/net/ipv4/netfilter/ip_nat_proto_udp.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/net/ipv4/netfilter/ip_nat_proto_udp.c	2011-09-26 15:07:56.608834037 +0200
@@ -76,7 +76,7 @@
 
 	for (i = 0; i < range_size; i++, port++) {
 		*portptr = htons(min + port % range_size);
-		if (!ip_nat_used_tuple(tuple, conntrack))
+		if (!ip_nat_used_tuple(tuple, conntrack, maniptype, range->flags))
 			return 1;
 	}
 	return 0;
diff -ruw linux-2.6.20.14/net/ipv4/netfilter/ip_nat_standalone.c linux-2.6.20.14-fbx/net/ipv4/netfilter/ip_nat_standalone.c
--- linux-2.6.20.14/net/ipv4/netfilter/ip_nat_standalone.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/net/ipv4/netfilter/ip_nat_standalone.c	2011-09-26 15:07:56.608834037 +0200
@@ -284,6 +284,13 @@
 	return NF_ACCEPT;
 }
 
+/* Modules depending on the NAT hooks but not using symbols from this module
+   should call this */
+void need_nat_hooks(void)
+{
+}
+EXPORT_SYMBOL_GPL(need_nat_hooks);
+
 /* We must be after connection tracking and before packet filtering. */
 
 static struct nf_hook_ops ip_nat_ops[] = {
diff -ruw linux-2.6.20.14/net/ipv4/netfilter/ip_tables.c linux-2.6.20.14-fbx/net/ipv4/netfilter/ip_tables.c
--- linux-2.6.20.14/net/ipv4/netfilter/ip_tables.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/net/ipv4/netfilter/ip_tables.c	2011-09-26 15:07:56.618834031 +0200
@@ -1145,6 +1145,11 @@
 	return ret;
 }
 
+#ifdef CONFIG_IP_FFN
+extern void ip_ffn_flush_all(void);
+#endif
+
+
 static int
 __do_replace(const char *name, unsigned int valid_hooks,
 		struct xt_table_info *newinfo, unsigned int num_counters,
@@ -1261,6 +1266,10 @@
 			      tmp.counters);
 	if (ret)
 		goto free_newinfo_untrans;
+
+#ifdef CONFIG_IP_FFN
+	ip_ffn_flush_all();
+#endif
 	return 0;
 
  free_newinfo_untrans:
diff -ruw linux-2.6.20.14/net/ipv4/netfilter/Kconfig linux-2.6.20.14-fbx/net/ipv4/netfilter/Kconfig
--- linux-2.6.20.14/net/ipv4/netfilter/Kconfig	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/net/ipv4/netfilter/Kconfig	2011-09-26 15:07:56.608834037 +0200
@@ -212,6 +212,33 @@
 
 	  To compile it as a module, choose M here.  If unsure, say Y.
 
+config IP_NF_TPROXY
+	tristate "Transparent proxying"
+	depends on IP_NF_NAT
+	help
+	  Transparent proxying. For more information see
+	  http://www.balabit.com/downloads/tproxy.
+
+	  To compile it as a module, choose M here.  If unsure, say Y.
+
+config IP_NF_MATCH_TPROXY
+	tristate "tproxy match support"
+	depends on IP_NF_TPROXY
+	help
+	  Match transparently proxied connections.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
+config IP_NF_TARGET_TPROXY
+	tristate "TPROXY target support"
+	depends on IP_NF_TPROXY
+	help
+	  This option adds a `TPROXY' target, which is almost the same as REDIRECT.
+	  It can only be used in the tproxy table, and is useful to redirect
+	  traffic to a transparent proxy.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
 config IP_NF_QUEUE
 	tristate "IP Userspace queueing via NETLINK (OBSOLETE)"
 	help
@@ -462,6 +489,16 @@
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
+config IP_NF_NAT_NRES
+	bool "NAT reservations support"
+	depends on IP_NF_NAT
+	help
+	  This option enables support for NAT reservations. This makes
+	  transparent proxying more reliable, but unneeded if you don't
+	  need TProxy support.
+
+	  If unsure, say 'N'.
+
 config IP_NF_NAT_SNMP_BASIC
 	tristate "Basic SNMP-ALG support (EXPERIMENTAL)"
 	depends on EXPERIMENTAL && IP_NF_NAT
diff -ruw linux-2.6.20.14/net/ipv4/netfilter/Makefile linux-2.6.20.14-fbx/net/ipv4/netfilter/Makefile
--- linux-2.6.20.14/net/ipv4/netfilter/Makefile	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/net/ipv4/netfilter/Makefile	2011-09-26 15:07:56.608834037 +0200
@@ -81,6 +81,7 @@
 obj-$(CONFIG_IP_NF_NAT) += iptable_nat.o
 obj-$(CONFIG_NF_NAT) += iptable_nat.o
 obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o
+obj-$(CONFIG_IP_NF_TPROXY) += iptable_tproxy.o
 
 # matches
 obj-$(CONFIG_IP_NF_MATCH_IPRANGE) += ipt_iprange.o
@@ -91,6 +92,7 @@
 obj-$(CONFIG_IP_NF_MATCH_AH) += ipt_ah.o
 obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o
 obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o
+obj-$(CONFIG_IP_NF_MATCH_TPROXY) += ipt_tproxy.o
 
 # targets
 obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o
@@ -106,6 +108,7 @@
 obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o
 obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o
 obj-$(CONFIG_IP_NF_TARGET_TTL) += ipt_TTL.o
+obj-$(CONFIG_IP_NF_TARGET_TPROXY) += ipt_TPROXY.o
 
 # generic ARP tables
 obj-$(CONFIG_IP_NF_ARPTABLES) += arp_tables.o
diff -ruw linux-2.6.20.14/net/ipv4/route.c linux-2.6.20.14-fbx/net/ipv4/route.c
--- linux-2.6.20.14/net/ipv4/route.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/net/ipv4/route.c	2011-09-26 15:07:56.618834031 +0200
@@ -3199,3 +3199,4 @@
 EXPORT_SYMBOL(__ip_select_ident);
 EXPORT_SYMBOL(ip_route_input);
 EXPORT_SYMBOL(ip_route_output_key);
+EXPORT_SYMBOL(ip_tos2prio);
diff -ruw linux-2.6.20.14/net/ipv4/tcp_ipv4.c linux-2.6.20.14-fbx/net/ipv4/tcp_ipv4.c
--- linux-2.6.20.14/net/ipv4/tcp_ipv4.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/net/ipv4/tcp_ipv4.c	2011-09-26 15:07:56.618834031 +0200
@@ -2469,6 +2469,10 @@
 EXPORT_SYMBOL(tcp_v4_send_check);
 EXPORT_SYMBOL(tcp_v4_syn_recv_sock);
 
+#if defined(CONFIG_IP_NF_TPROXY) || defined (CONFIG_IP_NF_TPROXY_MODULE)
+EXPORT_SYMBOL(ip_tproxy_tcp_unhashed);
+#endif
+
 #ifdef CONFIG_PROC_FS
 EXPORT_SYMBOL(tcp_proc_register);
 EXPORT_SYMBOL(tcp_proc_unregister);
diff -ruw linux-2.6.20.14/net/ipv4/tcp_minisocks.c linux-2.6.20.14-fbx/net/ipv4/tcp_minisocks.c
--- linux-2.6.20.14/net/ipv4/tcp_minisocks.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/net/ipv4/tcp_minisocks.c	2011-09-26 15:07:56.628834024 +0200
@@ -27,6 +27,7 @@
 #include <net/tcp.h>
 #include <net/inet_common.h>
 #include <net/xfrm.h>
+#include <linux/net.h>
 
 #ifdef CONFIG_SYSCTL
 #define SYNC_INIT 0 /* let the user enable it */
diff -ruw linux-2.6.20.14/net/ipv4/udp.c linux-2.6.20.14-fbx/net/ipv4/udp.c
--- linux-2.6.20.14/net/ipv4/udp.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/net/ipv4/udp.c	2011-09-26 15:07:56.628834024 +0200
@@ -1506,6 +1506,21 @@
 	
 }
 
+#if defined(CONFIG_IP_NF_TPROXY) || defined (CONFIG_IP_NF_TPROXY_MODULE)
+void (*ip_tproxy_udp_unhashed)(struct sock *sk, int proto) = NULL;
+#endif
+
+static void udp_v4_unhash(struct sock *sk)
+{
+#if defined(CONFIG_IP_NF_TPROXY) || defined (CONFIG_IP_NF_TPROXY_MODULE)
+	/* ugly tproxy unassign hook */
+	if (ip_tproxy_udp_unhashed)
+		ip_tproxy_udp_unhashed(sk, IPPROTO_UDP);
+#endif
+
+	udp_lib_unhash(sk);
+}
+
 struct proto udp_prot = {
  	.name		   = "UDP",
 	.owner		   = THIS_MODULE,
@@ -1521,7 +1536,7 @@
 	.sendpage	   = udp_sendpage,
 	.backlog_rcv	   = udp_queue_rcv_skb,
 	.hash		   = udp_lib_hash,
-	.unhash		   = udp_lib_unhash,
+	.unhash		   = udp_v4_unhash,
 	.get_port	   = udp_v4_get_port,
 	.obj_size	   = sizeof(struct udp_sock),
 #ifdef CONFIG_COMPAT
@@ -1728,6 +1743,10 @@
 EXPORT_SYMBOL(udp_lib_setsockopt);
 EXPORT_SYMBOL(udp_poll);
 
+#if defined(CONFIG_IP_NF_TPROXY) || defined (CONFIG_IP_NF_TPROXY_MODULE)
+EXPORT_SYMBOL(ip_tproxy_udp_unhashed);
+#endif
+
 #ifdef CONFIG_PROC_FS
 EXPORT_SYMBOL(udp_proc_register);
 EXPORT_SYMBOL(udp_proc_unregister);
diff -ruw linux-2.6.20.14/net/ipv4/xfrm4_policy.c linux-2.6.20.14-fbx/net/ipv4/xfrm4_policy.c
--- linux-2.6.20.14/net/ipv4/xfrm4_policy.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/net/ipv4/xfrm4_policy.c	2011-09-26 15:07:56.628834024 +0200
@@ -312,7 +312,7 @@
 	.update_pmtu =		xfrm4_update_pmtu,
 	.destroy =		xfrm4_dst_destroy,
 	.ifdown =		xfrm4_dst_ifdown,
-	.gc_thresh =		1024,
+	.gc_thresh =		CONFIG_INET_XFRM_GC_THRESH,
 	.entry_size =		sizeof(struct xfrm_dst),
 };
 
diff -ruw linux-2.6.20.14/net/ipv6/Kconfig linux-2.6.20.14-fbx/net/ipv6/Kconfig
--- linux-2.6.20.14/net/ipv6/Kconfig	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/net/ipv6/Kconfig	2011-09-26 15:07:56.628834024 +0200
@@ -166,6 +166,11 @@
 
 	  Saying M here will produce a module called sit.ko. If unsure, say Y.
 
+config IPV6_SIT_FBX6TO4
+	bool "sit support Freebox 6to4 scheme"
+	depends on IPV6_SIT
+	default n
+
 config IPV6_TUNNEL
 	tristate "IPv6: IPv6-in-IPv6 tunnel"
 	select INET6_TUNNEL
diff -ruw linux-2.6.20.14/net/ipv6/sit.c linux-2.6.20.14-fbx/net/ipv6/sit.c
--- linux-2.6.20.14/net/ipv6/sit.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/net/ipv6/sit.c	2011-09-26 15:07:56.638834017 +0200
@@ -162,6 +162,12 @@
 	}
 	for (tp = &tunnels[prio][h]; (t = *tp) != NULL; tp = &t->next) {
 		if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr)
+#ifdef CONFIG_IPV6_SIT_FBX6TO4
+			if (!memcmp(&parms->fbx6to4_zone,
+				    &t->parms.fbx6to4_zone,
+				    sizeof (parms->fbx6to4_zone)) &&
+			    parms->fbx6to4_prefix == t->parms.fbx6to4_prefix)
+#endif
 			return t;
 	}
 	if (!create)
@@ -396,9 +402,9 @@
 	}
 
 	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
-	kfree_skb(skb);
 	read_unlock(&ipip6_lock);
 out:
+	kfree_skb(skb);
 	return 0;
 }
 
@@ -416,6 +422,31 @@
 	return dst;
 }
 
+#ifdef CONFIG_IPV6_SIT_FBX6TO4
+/* Returns the embedded IPv4 address if the IPv6 address comes from
+   Freebox 6to4 rule */
+static inline __be32 try_fbx6to4(struct in6_addr *fbx6to4_zone,
+				 u8 fbx6to4_prefix, struct in6_addr *v6dst)
+{
+	__be32 dst = 0;
+
+	/* isolate zone according to mask */
+	if (ipv6_prefix_equal(v6dst, fbx6to4_zone, fbx6to4_prefix)) {
+		unsigned int d32_off, bits;
+
+		d32_off = fbx6to4_prefix >> 5;
+		bits = (fbx6to4_prefix & 0x1f);
+
+		dst = (ntohl(v6dst->s6_addr32[d32_off]) << bits);
+		if (bits)
+			dst |= ntohl(v6dst->s6_addr32[d32_off + 1]) >>
+				(32 - bits);
+		dst = htonl(dst);
+	}
+	return dst;
+}
+#endif
+
 /*
  *	This function assumes it is being called from dev_queue_xmit()
  *	and that skb is filled properly by that function.
@@ -445,6 +476,13 @@
 	if (skb->protocol != htons(ETH_P_IPV6))
 		goto tx_error;
 
+#ifdef CONFIG_IPV6_SIT_FBX6TO4
+	if (!dst && tunnel->parms.fbx6to4_prefix)
+		dst = try_fbx6to4(&tunnel->parms.fbx6to4_zone,
+				  tunnel->parms.fbx6to4_prefix,
+				  &iph6->daddr);
+	else
+#endif
 	if (!dst)
 		dst = try_6to4(&iph6->daddr);
 
@@ -632,6 +670,12 @@
 		if (p.iph.ttl)
 			p.iph.frag_off |= htons(IP_DF);
 
+#ifdef CONFIG_IPV6_SIT_FBX6TO4
+		/* prefix must be smaller than 95 bits since we fetch
+		 * an ip address after them */
+		if (p.fbx6to4_prefix >= 95)
+			goto done;
+#endif
 		t = ipip6_tunnel_locate(&p, cmd == SIOCADDTUNNEL);
 
 		if (dev != ipip6_fb_tunnel_dev && cmd == SIOCCHGTUNNEL) {
@@ -650,6 +694,10 @@
 				ipip6_tunnel_unlink(t);
 				t->parms.iph.saddr = p.iph.saddr;
 				t->parms.iph.daddr = p.iph.daddr;
+#ifdef CONFIG_IPV6_SIT_FBX6TO4
+				t->parms.fbx6to4_zone = p.fbx6to4_zone;
+				t->parms.fbx6to4_prefix = p.fbx6to4_prefix;
+#endif
 				memcpy(dev->dev_addr, &p.iph.saddr, 4);
 				memcpy(dev->broadcast, &p.iph.daddr, 4);
 				ipip6_tunnel_link(t);
diff -ruw linux-2.6.20.14/net/Kconfig linux-2.6.20.14-fbx/net/Kconfig
--- linux-2.6.20.14/net/Kconfig	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/net/Kconfig	2011-09-26 15:07:56.558834067 +0200
@@ -27,6 +27,10 @@
 
 menu "Networking options"
 
+config NETSKBPAD
+	int "Size reserved by dev_alloc_skb"
+	default 16
+
 config NETDEBUG
 	bool "Network packet debugging"
 	help
@@ -34,6 +38,22 @@
 	  debugging bad packets, but can overwhelm logs under denial of service
 	  attacks.
 
+config NETRXTHREAD
+	bool "Do rx network processing in kernel thread"
+
+config NETRXTHREAD_RX_QUEUE
+	int "Number of rx queues"
+	default 1
+	depends on NETRXTHREAD
+
+config NETRXTHREAD_MAX_PROCESS
+	int "Maximum number of packet to process before schedule"
+	default 4
+	depends on NETRXTHREAD
+
+config SKB_RECYCLE
+	bool "Skb recycling support"
+
 source "net/packet/Kconfig"
 source "net/unix/Kconfig"
 source "net/xfrm/Kconfig"
@@ -178,6 +198,7 @@
 source "net/econet/Kconfig"
 source "net/wanrouter/Kconfig"
 source "net/sched/Kconfig"
+source "net/fbxatm/Kconfig"
 
 menu "Network testing"
 
diff -ruw linux-2.6.20.14/net/Makefile linux-2.6.20.14-fbx/net/Makefile
--- linux-2.6.20.14/net/Makefile	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/net/Makefile	2011-09-26 15:07:56.558834067 +0200
@@ -51,3 +51,5 @@
 ifeq ($(CONFIG_NET),y)
 obj-$(CONFIG_SYSCTL)		+= sysctl_net.o
 endif
+
+obj-$(CONFIG_FBXATM)		+= fbxatm/
diff -ruw linux-2.6.20.14/net/netfilter/core.c linux-2.6.20.14-fbx/net/netfilter/core.c
--- linux-2.6.20.14/net/netfilter/core.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/net/netfilter/core.c	2011-09-26 15:07:56.648834011 +0200
@@ -153,6 +153,7 @@
 	}
 	return NF_ACCEPT;
 }
+EXPORT_SYMBOL(nf_iterate);
 
 
 /* Returns 1 if okfn() needs to be executed by the caller,
diff -ruw linux-2.6.20.14/net/sched/sch_ingress.c linux-2.6.20.14-fbx/net/sched/sch_ingress.c
--- linux-2.6.20.14/net/sched/sch_ingress.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/net/sched/sch_ingress.c	2011-09-26 15:07:56.668833999 +0200
@@ -230,7 +230,7 @@
 
 #ifndef CONFIG_NET_CLS_ACT
 #ifdef CONFIG_NETFILTER
-static unsigned int
+unsigned int
 ing_hook(unsigned int hook, struct sk_buff **pskb,
                              const struct net_device *indev,
                              const struct net_device *outdev,
diff -ruw linux-2.6.20.14/net/socket.c linux-2.6.20.14-fbx/net/socket.c
--- linux-2.6.20.14/net/socket.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/net/socket.c	2011-09-26 15:07:56.678833993 +0200
@@ -807,6 +807,68 @@
 
 EXPORT_SYMBOL(dlci_ioctl_set);
 
+/* Start Freebox added code */
+#if defined(CONFIG_FREEBOX_DIVERTER) || defined(CONFIG_FREEBOX_DIVERTER_MODULE)
+static DECLARE_MUTEX(fbxdiverter_ioctl_mutex);
+static int (*fbxdiverter_ioctl_hook)(unsigned int cmd, void __user *arg) = NULL;
+
+void fbxdiverter_set(int (*hook)(unsigned int, void __user *))
+{
+	down(&fbxdiverter_ioctl_mutex);
+	fbxdiverter_ioctl_hook = hook;
+	up(&fbxdiverter_ioctl_mutex);
+}
+EXPORT_SYMBOL(fbxdiverter_set);
+#endif
+/* End Freebox added code */
+
+/* Start Freebox added code */
+#if defined(CONFIG_FREEBOX_BRIDGE) || defined(CONFIG_FREEBOX_BRIDGE_MODULE)
+static DECLARE_MUTEX(fbxbridge_ioctl_mutex);
+static int (*fbxbridge_ioctl_hook)(unsigned int cmd, void __user *arg) = NULL;
+
+void fbxbridge_set(int (*hook)(unsigned int, void __user *))
+{
+	down(&fbxbridge_ioctl_mutex);
+	fbxbridge_ioctl_hook = hook;
+	up(&fbxbridge_ioctl_mutex);
+}
+EXPORT_SYMBOL(fbxbridge_set);
+#endif
+/* End Freebox added code */
+
+
+/* Start Freebox added code */
+#if defined(CONFIG_FREEBOX_MVDSA) || defined(CONFIG_FREEBOX_MVDSA_MODULE)
+static DECLARE_MUTEX(fbxmvdsa_ioctl_mutex);
+static int (*fbxmvdsa_ioctl_hook)(unsigned int cmd, void __user *arg) = NULL;
+
+void fbxmvdsa_set(int (*hook)(unsigned int, void __user *))
+{
+	down(&fbxmvdsa_ioctl_mutex);
+	fbxmvdsa_ioctl_hook = hook;
+	up(&fbxmvdsa_ioctl_mutex);
+}
+EXPORT_SYMBOL(fbxmvdsa_set);
+#endif
+/* End Freebox added code */
+
+/* Start Freebox added code */
+#if defined(CONFIG_FREEBOX_L2BR) || defined(CONFIG_FREEBOX_L2BR_MODULE)
+static DECLARE_MUTEX(fbxl2br_ioctl_mutex);
+static int (*fbxl2br_ioctl_hook)(unsigned int cmd, void __user *arg) = NULL;
+
+void fbxl2br_set(int (*hook)(unsigned int, void __user *))
+{
+	down(&fbxl2br_ioctl_mutex);
+	fbxl2br_ioctl_hook = hook;
+	up(&fbxl2br_ioctl_mutex);
+}
+EXPORT_SYMBOL(fbxl2br_set);
+#endif
+/* End Freebox added code */
+
+
 /*
  *	With an ioctl, arg may well be a user mode pointer, but we don't know
  *	what to do with it - that's up to the protocol still.
@@ -876,6 +938,71 @@
 				mutex_unlock(&dlci_ioctl_mutex);
 			}
 			break;
+
+/* Start Freebox added code */
+		case SIOCGFBXDIVERT:
+		case SIOCSFBXDIVERT:
+#if defined(CONFIG_FREEBOX_DIVERTER) || defined(CONFIG_FREEBOX_DIVERTER_MODULE)
+			err = -ENOPKG;
+			if (!fbxdiverter_ioctl_hook)
+				request_module("fbxdiverter");
+
+			down(&fbxdiverter_ioctl_mutex);
+			if (fbxdiverter_ioctl_hook)
+				err = fbxdiverter_ioctl_hook(cmd, argp);
+			up(&fbxdiverter_ioctl_mutex);
+			break;
+#endif
+/* End Freebox added code */
+
+/* Start Freebox added code */
+		case SIOCGFBXBRIDGE:
+		case SIOCSFBXBRIDGE:
+#if defined(CONFIG_FREEBOX_BRIDGE) || defined(CONFIG_FREEBOX_BRIDGE_MODULE)
+			err = -ENOPKG;
+			if (!fbxbridge_ioctl_hook)
+				request_module("fbxbridge");
+
+			down(&fbxbridge_ioctl_mutex);
+			if (fbxbridge_ioctl_hook)
+				err = fbxbridge_ioctl_hook(cmd, argp);
+			up(&fbxbridge_ioctl_mutex);
+			break;
+#endif
+/* End Freebox added code */
+
+/* Start Freebox added code */
+		case SIOCFBXMVDSA:
+#if defined(CONFIG_FREEBOX_MVDSA) || defined(CONFIG_FREEBOX_MVDSA_MODULE)
+			err = -ENOPKG;
+			if (!fbxmvdsa_ioctl_hook)
+				request_module("fbxmvdsa");
+
+			down(&fbxmvdsa_ioctl_mutex);
+			if (fbxmvdsa_ioctl_hook)
+				err = fbxmvdsa_ioctl_hook(cmd, argp);
+			up(&fbxmvdsa_ioctl_mutex);
+			break;
+#endif
+/* End Freebox added code */
+
+/* Start Freebox added code */
+		case SIOCFBXL2BR:
+#if defined(CONFIG_FREEBOX_L2BR) || defined(CONFIG_FREEBOX_L2BR_MODULE)
+			err = -ENOPKG;
+			if (!fbxl2br_ioctl_hook)
+				request_module("fbxl2br");
+
+			down(&fbxl2br_ioctl_mutex);
+			if (fbxl2br_ioctl_hook)
+				err = fbxl2br_ioctl_hook(cmd, argp);
+			up(&fbxl2br_ioctl_mutex);
+			break;
+#endif
+/* End Freebox added code */
+
+/* */
+
 		default:
 			err = sock->ops->ioctl(sock, cmd, arg);
 
diff -ruw linux-2.6.20.14/scripts/gen_initramfs_list.sh linux-2.6.20.14-fbx/scripts/gen_initramfs_list.sh
--- linux-2.6.20.14/scripts/gen_initramfs_list.sh	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/scripts/gen_initramfs_list.sh	2011-09-26 15:07:56.698833981 +0200
@@ -15,9 +15,9 @@
 usage() {
 cat << EOF
 Usage:
-$0 [-o <file>] [-u <uid>] [-g <gid>] {-d | <cpio_source>} ...
-	-o <file>      Create gzipped initramfs file named <file> using
-	               gen_init_cpio and gzip
+$0 [-o <file>] [-u <uid>] [-g <gid>] [-z] {-d | <cpio_source>} ...
+	-o <file>      Create initramfs file named <file> using
+	               gen_init_cpio
 	-u <uid>       User ID to map to user ID 0 (root).
 	               <uid> is only meaningful if <cpio_source>
 	               is a directory.
@@ -28,6 +28,7 @@
 	               If <cpio_source> is a .cpio file it will be used
 		       as direct input to initramfs.
 	-d             Output the default cpio list.
+	-z             gzip the output file
 
 All options except -o and -l may be repeated and are interpreted
 sequentially and immediately.  -u and -g states are preserved across
@@ -91,7 +92,7 @@
 }
 
 list_parse() {
-	echo "$1 \\"
+	[ ! -h "$1" ] && echo "$1 \\" || :
 }
 
 # for each file print a line in following format
@@ -217,6 +218,7 @@
 prog=$0
 root_uid=0
 root_gid=0
+gzipped=0
 dep_list=
 cpio_file=
 cpio_list=
@@ -230,7 +232,7 @@
 		echo "deps_initramfs := \\"
 		shift
 		;;
-	"-o")	# generate gzipped cpio image named $1
+	"-o")	# generate cpio image named $1
 		shift
 		output_file="$1"
 		cpio_list="$(mktemp ${TMPDIR:-/tmp}/cpiolist.XXXXXX)"
@@ -258,6 +260,9 @@
 			usage
 			exit 0
 			;;
+		"-z")	# gzip the cpio image
+			gzipped=1
+			;;
 		*)
 			case "$arg" in
 				"-"*)
@@ -281,7 +286,11 @@
 		cpio_tfile=${cpio_file}
 	fi
 	rm ${cpio_list}
+	if [ $gzipped -eq 1 ]; then
 	cat ${cpio_tfile} | gzip -f -9 - > ${output_file}
+	else
+	    cp ${cpio_tfile} ${output_file}
+	fi
 	[ -z ${cpio_file} ] && rm ${cpio_tfile}
 fi
 exit 0
diff -ruw linux-2.6.20.14/scripts/mod/sumversion.c linux-2.6.20.14-fbx/scripts/mod/sumversion.c
--- linux-2.6.20.14/scripts/mod/sumversion.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/scripts/mod/sumversion.c	2011-09-26 15:07:56.708833975 +0200
@@ -7,6 +7,7 @@
 #include <ctype.h>
 #include <errno.h>
 #include <string.h>
+#include <limits.h>
 #include "modpost.h"
 
 /*
diff -ruw linux-2.6.20.14/scripts/unifdef.c linux-2.6.20.14-fbx/scripts/unifdef.c
--- linux-2.6.20.14/scripts/unifdef.c	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/scripts/unifdef.c	2011-09-26 15:07:56.708833975 +0200
@@ -206,7 +206,7 @@
 static void             error(const char *);
 static int              findsym(const char *);
 static void             flushline(bool);
-static Linetype         getline(void);
+static Linetype         mygetline(void);
 static Linetype         ifeval(const char **);
 static void             ignoreoff(void);
 static void             ignoreon(void);
@@ -512,7 +512,7 @@
 
 	for (;;) {
 		linenum++;
-		lineval = getline();
+		lineval = mygetline();
 		trans_table[ifstate[depth]][lineval]();
 		debug("process %s -> %s depth %d",
 		    linetype_name[lineval],
@@ -526,7 +526,7 @@
  * help from skipcomment().
  */
 static Linetype
-getline(void)
+mygetline(void)
 {
 	const char *cp;
 	int cursym;
diff -ruw linux-2.6.20.14/sound/core/Kconfig linux-2.6.20.14-fbx/sound/core/Kconfig
--- linux-2.6.20.14/sound/core/Kconfig	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/sound/core/Kconfig	2011-09-26 15:07:56.718833969 +0200
@@ -4,7 +4,7 @@
 	depends on SND
 
 config SND_PCM
-	tristate
+	tristate "PCM API"
 	select SND_TIMER
 	depends on SND
 
diff -ruw linux-2.6.20.14/sound/oss/Kconfig linux-2.6.20.14-fbx/sound/oss/Kconfig
--- linux-2.6.20.14/sound/oss/Kconfig	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/sound/oss/Kconfig	2011-09-26 15:07:56.758833945 +0200
@@ -80,6 +80,13 @@
 	select SND_AC97_CODEC
 	depends on SOUND_PRIME && (SOC_AU1550 || SOC_AU1200)
 
+config SOUND_AU1550_I2S
+	tristate "Au1550 I2S Sound"
+	depends on SOUND_PRIME && SOC_AU1550
+	# Weird I2S driver needs I2C driver to talk to the codec...
+	select I2C
+	select I2C_AU1550
+
 config SOUND_TRIDENT
 	tristate "Trident 4DWave DX/NX, SiS 7018 or ALi 5451 PCI Audio Core"
 	depends on SOUND_PRIME && PCI
diff -ruw linux-2.6.20.14/sound/oss/Makefile linux-2.6.20.14-fbx/sound/oss/Makefile
--- linux-2.6.20.14/sound/oss/Makefile	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/sound/oss/Makefile	2011-09-26 15:07:56.758833945 +0200
@@ -45,6 +45,7 @@
 obj-$(CONFIG_SOUND_ES1371)	+= es1371.o ac97_codec.o
 obj-$(CONFIG_SOUND_VRC5477)	+= nec_vrc5477.o ac97_codec.o
 obj-$(CONFIG_SOUND_AU1550_AC97)	+= au1550_ac97.o ac97_codec.o
+obj-$(CONFIG_SOUND_AU1550_I2S)	+= au1550_i2s.o
 obj-$(CONFIG_SOUND_FUSION)	+= cs46xx.o ac97_codec.o
 obj-$(CONFIG_SOUND_TRIDENT)	+= trident.o ac97_codec.o
 obj-$(CONFIG_SOUND_EMU10K1)	+= ac97_codec.o
diff -ruw linux-2.6.20.14/usr/Kconfig linux-2.6.20.14-fbx/usr/Kconfig
--- linux-2.6.20.14/usr/Kconfig	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/usr/Kconfig	2011-09-26 15:07:56.838833895 +0200
@@ -2,6 +2,10 @@
 # Configuration for initramfs
 #
 
+config INITRAMFS_USE_GZIP
+	bool "Initramfs file is gzipped"
+	default y
+
 config INITRAMFS_SOURCE
 	string "Initramfs source file(s)"
 	default ""
diff -ruw linux-2.6.20.14/usr/Makefile linux-2.6.20.14-fbx/usr/Makefile
--- linux-2.6.20.14/usr/Makefile	2007-06-11 20:37:31.000000000 +0200
+++ linux-2.6.20.14-fbx/usr/Makefile	2011-09-26 15:07:56.838833895 +0200
@@ -22,6 +22,7 @@
 ramfs-input := $(if $(filter-out "",$(CONFIG_INITRAMFS_SOURCE)), \
 			$(shell echo $(CONFIG_INITRAMFS_SOURCE)),-d)
 ramfs-args  := \
+        $(if $(CONFIG_INITRAMFS_USE_GZIP), -z) \
         $(if $(CONFIG_INITRAMFS_ROOT_UID), -u $(CONFIG_INITRAMFS_ROOT_UID)) \
         $(if $(CONFIG_INITRAMFS_ROOT_GID), -g $(CONFIG_INITRAMFS_ROOT_GID))
 
@@ -49,4 +50,3 @@
 $(obj)/initramfs_data.cpio.gz: $(obj)/gen_init_cpio $(deps_initramfs) klibcdirs
 	$(Q)$(initramfs) -l $(ramfs-input) > $(obj)/.initramfs_data.cpio.gz.d
 	$(call if_changed,initfs)
-
diff -Nruw linux-2.6.20.14-fbx/arch/mips/bcm963xx./bcm963xx.h linux-2.6.20.14-fbx/arch/mips/bcm963xx/bcm963xx.h
--- linux-2.6.20.14-fbx/arch/mips/bcm963xx./bcm963xx.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/arch/mips/bcm963xx/bcm963xx.h	2011-09-26 15:07:53.868835715 +0200
@@ -0,0 +1,67 @@
+#ifndef ARCH_MIPS_BCM963XX_H_
+#define ARCH_MIPS_BCM963XX_H_
+
+#include <linux/init.h>
+#include <asm/mach-bcm963xx/bcm963xx_cpu.h>
+#include <asm/mach-bcm963xx/bcm963xx_cs.h>
+#include <asm/mach-bcm963xx/bcm963xx_clk.h>
+#include <asm/mach-bcm963xx/bcm963xx_regs.h>
+#include <asm/mach-bcm963xx/bcm963xx_gpio.h>
+#include <asm/mach-bcm963xx/bcm963xx_io.h>
+#include <asm/mach-bcm963xx/bcm963xx_irq.h>
+#include <asm/mach-bcm963xx/bcm963xx_timer.h>
+#include <asm/mach-bcm963xx/devices.h>
+
+#include <bcmusb_device.h>
+
+/*
+ * in cpu.c
+ */
+void __init bcm963xx_cpu_init(void);
+
+/*
+ * in early_console.c
+ */
+void __init bcm963xx_register_early_console(void);
+
+/*
+ * in prom.c
+ */
+void *__init bcm963xx_prom_init(unsigned int reserve_memory);
+unsigned int bcm963xx_get_memory_size(void);
+unsigned int bcm963xx_get_rsvd_memory_size(void);
+void *bcm963xx_get_rsvd_memory(void);
+
+/*
+ * in setup.c
+ */
+void __init bcm963xx_plat_mem_setup(void);
+void bcm963xx_machine_reboot(void);
+
+/*
+ * in enet.c
+ */
+int __init bcm963xx_enet_set_pdata(int unit,
+				   struct bcm963xx_enet_platform_data *pd);
+
+/*
+ * in dev-bcmusb.c
+ */
+void __init bcmusb_set_pdata(struct bcmusb_platform_data *pd);
+
+
+/*
+ * in smp.c
+ */
+#ifdef CONFIG_SMP
+asmlinkage void bcm963xx_ipi_irq(int id);
+#endif
+
+/*
+ * in the compiled board file
+ */
+void __init board_prom_init(void);
+void __init board_mem_setup(void);
+const char *board_get_name(void);
+
+#endif /* ! ARCH_MIPS_BCM963XX_H_ */
diff -Nruw linux-2.6.20.14-fbx/arch/mips/bcm963xx./boards/board-fbx5a.c linux-2.6.20.14-fbx/arch/mips/bcm963xx/boards/board-fbx5a.c
--- linux-2.6.20.14-fbx/arch/mips/bcm963xx./boards/board-fbx5a.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/arch/mips/bcm963xx/boards/board-fbx5a.c	2011-09-26 15:07:53.868835715 +0200
@@ -0,0 +1,462 @@
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/fbxserial.h>
+#include <linux/fbxserialinfo.h>
+#include <linux/delay.h>
+#include <linux/i2c-gpio.h>
+#include <linux/platform_device.h>
+#include <asm/reboot.h>
+#include <asm/mach-bcm963xx/board-fbx5a.h>
+#include <linux/fbxmtd.h>
+#include <linux/fbxgpio_core.h>
+#include "../bcm963xx.h"
+
+static struct fbx_serial serial;
+
+#define PFX	"board-fbx5: "
+
+/*
+ * cfe freebox version
+ */
+unsigned char cfe_version_str[128] = { 0 };
+EXPORT_SYMBOL(cfe_version_str);
+
+/*
+ * Marvell 6061 registers
+ */
+#define MARVELL_PHYPORT0		0x0
+#define MARVELL_PHYPORT1		0x1
+#define MARVELL_PHYPORT2		0x2
+#define MARVELL_PHYPORT3		0x3
+
+#define MARVELL_SWPORT0			0x8
+#define MARVELL_SWPORT1			0x9
+#define MARVELL_SWPORT2			0xa
+#define MARVELL_SWPORT3			0xb
+#define MARVELL_SWPORT4			0xc
+#define MARVELL_SWPORT5			0xd
+
+#define PORTREG_MCR			0x1
+
+#define MCR_FORCELINK_UP		(1 << 5)
+#define MCR_FORCELINK			(1 << 4)
+#define MCR_FORCEDUPLEX_FULL		(1 << 3)
+#define MCR_FORCEDUPLEX			(1 << 2)
+#define MCR_FORCESPEED_10		0x0
+#define MCR_FORCESPEED_100		0x1
+#define MCR_FORCESPEED_AUTO		0x3
+
+#define PORTREG_SWITCH_IDENTIFIER	0x3
+#define PRODUCT_NUM(x)			(((x) >> 4) & 0xfff)
+
+#define PORTREG_PCR			0x4
+#define PCR_PORTSTATE_DISABLED		0x0
+#define PCR_PORTSTATE_FORWARDING	0x3
+#define PCR_HEADER			(1 << 11)
+
+#define MARVELL_GLOBAL			0xf
+#define MARVELL_GLOBAL2			0xe
+
+
+/*
+ * try gpio reset first, and then soft reset via pll control register.
+ */
+static void fbx5a_machine_restart(char *command)
+{
+	/* stop any running watchdog */
+	bcm_wdt_writel(WDT_STOP_1, WDT_CTL_REG);
+	bcm_wdt_writel(WDT_STOP_2, WDT_CTL_REG);
+
+	printk(KERN_INFO PFX "Rebooting via board reset gpio...\n");
+	bcm963xx_gpio_set_dataout(GPIO_BOARD_RESET, 0);
+	mdelay(3000);
+
+	printk(KERN_INFO PFX "failed! fallback to softreset\n");
+	bcm963xx_machine_reboot();
+	while (1);
+}
+
+const char *board_get_name(void)
+{
+	return "Freebox ADSL v5";
+}
+
+/*
+ * Do basic marvell 6061 switch configuration
+ */
+static int marvell_6061_config(struct net_device *dev, int probe,
+			       int (*mii_read)(struct net_device *dev,
+					       int phy_id, int reg),
+			       void (*mii_write)(struct net_device *dev,
+						 int phy_id, int reg, int val))
+{
+	int val, off, i;
+
+	if (!probe)
+		return 0;
+
+	/* guess offset, check device id at two possible location */
+	off = 0;
+	val = mii_read(dev, MARVELL_SWPORT0 + off, PORTREG_SWITCH_IDENTIFIER);
+	if (PRODUCT_NUM(val) != 0x61) {
+		off = 0x10;
+		val = mii_read(dev, MARVELL_SWPORT0 + off,
+			       PORTREG_SWITCH_IDENTIFIER);
+
+		if (PRODUCT_NUM(val) != 0x61)
+			return 1;
+	}
+
+	/* force port 4 link to DOWN */
+	val = mii_read(dev, MARVELL_SWPORT4 + off, PORTREG_MCR);
+	val &= ~MCR_FORCELINK_UP;
+	val |= MCR_FORCELINK;
+	mii_write(dev, MARVELL_SWPORT4 + off, PORTREG_MCR, val);
+
+	/* force port 4 to UP 100 Mbit/s half duplex */
+	mii_write(dev, MARVELL_SWPORT4 + off, PORTREG_MCR,
+		  MCR_FORCEDUPLEX_FULL | MCR_FORCEDUPLEX |
+		  MCR_FORCESPEED_100 |
+		  MCR_FORCELINK | MCR_FORCELINK_UP);
+
+	/* enable marvell header mode on port 5 */
+	val = mii_read(dev, MARVELL_SWPORT4 + off, PORTREG_PCR);
+	val |= PCR_HEADER;
+	mii_write(dev, MARVELL_SWPORT4 + off, PORTREG_PCR, val);
+
+	/* enable forwarding on all port */
+	for (i = 0; i < 5; i++) {
+		val = mii_read(dev, MARVELL_SWPORT0 + i + off, PORTREG_PCR);
+		val |= PCR_PORTSTATE_FORWARDING;
+		mii_write(dev, MARVELL_SWPORT0 + i + off, PORTREG_PCR, val);
+	}
+
+	/* enable led/act mode for all port */
+	for (i = 0; i < 5; i++) {
+		val = mii_read(dev, MARVELL_PHYPORT0 + i + off , 0x16);
+		val &= ~0xf;
+		val |= 0xA;
+		mii_write(dev, MARVELL_PHYPORT0 + i + off, 0x16, val);
+	}
+
+	printk(KERN_INFO PFX "marvell 6061 initialized\n");
+	return 0;
+}
+
+/*
+ * platform data for mac 0, uses internal PHY
+ */
+static struct bcm963xx_enet_platform_data pd_enet0 = {
+	.has_phy		= 1,
+	.use_internal_phy	= 1,
+};
+
+/*
+ * platform data for mac 1, uses mii connection to marvel 6061
+ */
+static struct bcm963xx_enet_platform_data pd_enet1 = {
+	.phy_id			= 0,
+	.has_phy		= 0,
+	.use_external_mii	= 1,
+	.force_speed_100	= 1,
+	.force_duplex_full	= 1,
+	.use_marvell_header	= 1,
+	.mii_config		= marvell_6061_config,
+};
+
+/*
+ * platform data for usb slave
+ */
+static struct bcmusb_platform_data pd_usb;
+
+/*
+ * kernel entry point
+ */
+void __init board_prom_init(void)
+{
+	unsigned int gpio_mode;
+
+	/* get cfe version from highest ram address */
+	memcpy(cfe_version_str,
+	       (void *)KSEG1ADDR(bcm963xx_get_memory_size() - 128), 128);
+	cfe_version_str[127] = 0;
+
+	/* small sanity check */
+	if (strncmp(cfe_version_str, "CFE", 3))
+		strcpy(cfe_version_str, "UNKNOWN");
+
+	bcm_perf_writel(0, PERF_IRQMASK_REG);
+
+	/* set gpio mode for board */
+	gpio_mode = bcm_gpio_readl(GPIO_MODE_REG);
+	gpio_mode &= ~(0xfffff);
+
+	/* mii port is used */
+	gpio_mode |= (GROUP3_EXT_MII | GROUP0_EXT_MII);
+
+	/* pci is used */
+	gpio_mode |= GROUP2_PCI;
+	bcm_gpio_writel(gpio_mode, GPIO_MODE_REG);
+
+	printk(KERN_INFO PFX "freebox cfe version: %s\n", cfe_version_str);
+
+	/* serial info is 56k after the beginning of the flash */
+	fbxserialinfo_read((void*)KSEG1ADDR(0x1fc00000 + 0xE000), &serial);
+
+	/* set ethernet platform data */
+	memcpy(pd_enet0.mac_addr, &serial.mac_addr_base[0], 6);
+	memcpy(pd_enet1.mac_addr, &serial.mac_addr_base[0], 6);
+	bcm963xx_enet_set_pdata(0, &pd_enet0);
+	bcm963xx_enet_set_pdata(1, &pd_enet1);
+
+	/* set usb platform data */
+	memcpy(pd_usb.local_mac_addr, &serial.mac_addr_base[0], 6);
+	memcpy(pd_usb.remote_mac_addr, "\x00\x07\xCB\x00\00\xFF", 6);
+	bcmusb_set_pdata(&pd_usb);
+}
+
+void __init board_mem_setup(void)
+{
+	extern int panic_timeout;
+
+	/*
+	 * set reset gpio direction and make _machine_restart point to
+	 * valid code.
+	 */
+	bcm963xx_gpio_set_dataout(GPIO_BOARD_RESET, 1);
+	mdelay(5);
+	bcm963xx_gpio_set_direction(GPIO_BOARD_RESET, GPIO_DIR_OUT);
+	_machine_restart = fbx5a_machine_restart;
+
+	panic_timeout = 10;
+	panic_on_oops = 1;
+}
+
+/*
+ * create I2C bus with 2 GPIO
+ */
+static struct i2c_gpio_platform_data i2c_gpio_platform_data = {
+	.gpio_scl		= GPIO_I2C_SCL,
+	.gpio_sda		= GPIO_I2C_SDA,
+
+	.gpio_set_dataout	= bcm963xx_gpio_set_dataout,
+	.gpio_get_dataout	= bcm963xx_gpio_get_datain,
+	.gpio_set_direction	= bcm963xx_gpio_set_direction,
+};
+
+static struct platform_device i2c_gpio_device =
+{
+	.name	= "i2c-gpio",
+	.id	= -1,
+	.dev	= {
+		.platform_data	= &i2c_gpio_platform_data
+	},
+};
+
+int __init fbx5a_i2c_init(void)
+{
+	return platform_device_register(&i2c_gpio_device);
+}
+
+device_initcall(fbx5a_i2c_init);
+
+/*
+ * Freebox phone device
+ */
+static struct platform_device fbx5a_phone_device = {
+	.name	= "bcm963xx_fbxphone",
+	.id	= -1,
+};
+
+int __init fbx5a_phone_init(void)
+{
+	return platform_device_register(&fbx5a_phone_device);
+}
+
+device_initcall(fbx5a_phone_init);
+
+/*
+ * Freebox serial info stuff
+ */
+const struct fbx_serial *arch_get_serial(void)
+{
+	return &serial;
+}
+
+EXPORT_SYMBOL(arch_get_serial);
+
+/*
+ * one bank layout.
+ */
+#ifdef CONFIG_FBXBOARD_FBXMTD_LAYOUT_MAP_ONE_BANK
+struct fbxmtd_platform_part board_parts[] = {
+	{
+		.name	= "all",
+		.offset	= 0x0,
+		.flags	= FBXMTD_PART_MAP_ALL,
+	},
+	{
+		.name	= "cfe",
+		.offset	= 0x0,
+		.size	= 0xE000,
+		.flags	= FBXMTD_PART_RW,
+	},
+	{
+		.name	= "serial",
+		.offset	= 0xE000,
+		.size	= 0x2000,
+		.flags	= FBXMTD_PART_RW,
+	},
+	{
+		.name	= "nvram",
+		.offset	= 0x10000,
+		.size	= 0x10000,
+		.flags	= FBXMTD_PART_RW,
+	},
+	{
+		.name	= "bank0",
+		.offset	= 0x20000,
+		.flags	= FBXMTD_PART_HAS_FS | FBXMTD_PART_AUTOSIZE |
+			FBXMTD_PART_RW,
+	}
+};
+#endif
+
+/*
+ * two bank layout.
+ */
+#ifdef CONFIG_FBXBOARD_FBXMTD_LAYOUT_MAP_TWO_BANK
+static struct fbxmtd_platform_part board_parts[] = {
+	{
+		.name	= "all",
+		.offset	= 0x0,
+		.flags	= FBXMTD_PART_MAP_ALL,
+	},
+	{
+		.name	= "cfe",
+		.offset	= 0x0,
+		.size	= 0xE000,
+		.flags	= 0,
+	},
+	{
+		.name	= "serial",
+		.offset	= 0xE000,
+		.size	= 0x2000,
+		.flags	= 0,
+	},
+	{
+		.name	= "bank0",
+		.offset	= 0x10000,
+		.size	= 0xF0000,
+		.flags	= FBXMTD_PART_HAS_FS,
+	},
+	{
+		.name	= "nvram",
+		.offset	= 0x100000,
+		.size	= 0x10000,
+		.flags	= FBXMTD_PART_RW,
+	},
+	{
+		.name	= "bank1",
+		.offset	= 0x110000,
+		.size	= -1,
+		.flags	= FBXMTD_PART_HAS_FS | FBXMTD_PART_RW |
+			FBXMTD_PART_AUTOSIZE,
+	}
+};
+#endif
+
+/*
+ * platform device stuff.
+ */
+struct fbxmtd_platform_data board_mtd_data = {
+	.name		= "flash0",
+	.base		= 0x1fc00000,
+	.width		= 2,
+	.parts		= board_parts,
+	.num_parts	= ARRAY_SIZE(board_parts),
+};
+
+struct platform_device board_mtd_device = {
+	.name	= "fbxmtd_map_drv",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &board_mtd_data,
+	},
+};
+
+static int __init fbx5a_fbxmtd_layout_init(void)
+{
+#ifndef CONFIG_FBXBOARD_FBXMTD_LAYOUT_READ_BANK1_TAG
+	printk(KERN_INFO PFX "ignoring bank1 tag.\n");
+	board_parts[5].flags |= FBXMTD_PART_IGNORE_TAG;
+#endif
+
+#ifdef CONFIG_FBXBOARD_FBXMTD_LAYOUT_ALL_RW
+	printk(KERN_INFO PFX "making all partitions R/W.\n");
+	{
+		int i;
+
+		for (i = 0; i < ARRAY_SIZE(board_parts); ++i)
+			board_parts[i].flags |= FBXMTD_PART_RW;
+	}
+#endif
+
+#ifdef CONFIG_FBXBOARD_FBXMTD_LAYOUT_NOCRC
+	printk(KERN_INFO PFX "disabling CRC check on partitions: ");
+	{
+		int i;
+
+		for (i = 0; i < ARRAY_SIZE(board_parts); ++i) {
+			if (!(board_parts[i].flags & FBXMTD_PART_HAS_FS))
+				continue;
+			board_parts[i].flags |= FBXMTD_PART_NOCRC;
+			printk("%s ", board_parts[i].name);
+		}
+	}
+	printk(".\n");
+#endif
+
+	platform_device_register(&board_mtd_device);
+	return 0;
+}
+
+arch_initcall(fbx5a_fbxmtd_layout_init);
+
+
+/*
+ * fbxgpio
+ */
+static struct fbxgpio_operations fbx5a_gpio_ops = {
+	.get_datain = bcm963xx_gpio_get_datain,
+	.set_dataout = bcm963xx_gpio_set_dataout,
+	.set_direction = bcm963xx_gpio_set_direction,
+};
+
+static struct fbxgpio_pin fbx5a_gpio_pins[] = {
+	{
+		.pin_name       = "test-mode",
+		.direction      = GPIO_DIR_IN,
+		.pin_num	= GPIO_TEST_MODE,
+		.flags		= FBXGPIO_PIN_REVERSE_POL,
+		.ops		= &fbx5a_gpio_ops,
+	},
+
+	{  },
+};
+
+static struct platform_device fbx5a_gpio_device = {
+	.name   = "fbxgpio",
+	.id     = -1,
+	.dev    = {
+		.platform_data = &fbx5a_gpio_pins,
+	},
+};
+
+static int fbx5a_fbxgpio_init(void)
+{
+	return platform_device_register(&fbx5a_gpio_device);
+}
+
+device_initcall(fbx5a_fbxgpio_init);
diff -Nruw linux-2.6.20.14-fbx/arch/mips/bcm963xx./boards/Kconfig linux-2.6.20.14-fbx/arch/mips/bcm963xx/boards/Kconfig
--- linux-2.6.20.14-fbx/arch/mips/bcm963xx./boards/Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/arch/mips/bcm963xx/boards/Kconfig	2011-09-26 15:07:53.868835715 +0200
@@ -0,0 +1,56 @@
+choice
+	prompt "target board"
+	depends on BCM963XX
+
+config BOARD_BCM963XX
+	bool "Broadcom bcm963xx eval boards"
+
+config BOARD_FBX4
+	bool "Freebox v4"
+	select BUILTIN_FBXSERIAL
+	select FBXBOARD_FBXMTD_LAYOUT
+
+config BOARD_FBX5A
+	bool "Freebox v5a"
+	select BUILTIN_FBXSERIAL
+	select FBXBOARD_FBXMTD_LAYOUT
+
+config BOARD_FBXGW1A
+	bool "Freebox Gateway v1 A"
+
+endchoice
+
+#
+# Freebox boards common option
+#
+config FBXBOARD_FBXMTD_LAYOUT
+       bool
+
+choice
+	prompt "Flash Mapping flavour"
+	depends on FBXBOARD_FBXMTD_LAYOUT
+	default FBXBOARD_FBXMTD_LAYOUT_MAP_TWO_BANK
+
+config FBXBOARD_FBXMTD_LAYOUT_MAP_ONE_BANK
+	bool "One bank mapping."
+
+config FBXBOARD_FBXMTD_LAYOUT_MAP_TWO_BANK
+	bool "Two bank mapping."
+
+endchoice
+
+config FBXBOARD_FBXMTD_LAYOUT_READ_BANK1_TAG
+	bool "Read BANK1 tag"
+	default y
+	depends on FBXBOARD_FBXMTD_LAYOUT
+	depends on FBXBOARD_FBXMTD_LAYOUT_MAP_TWO_BANK
+
+config FBXBOARD_FBXMTD_LAYOUT_ALL_RW
+	bool "Make all partition readable and writeable"
+	default n
+	depends on FBXBOARD_FBXMTD_LAYOUT
+
+config FBXBOARD_FBXMTD_LAYOUT_NOCRC
+	bool "Disable CRC check"
+	default n
+	depends on FBXBOARD_FBXMTD_LAYOUT
diff -Nruw linux-2.6.20.14-fbx/arch/mips/bcm963xx./boards/Makefile linux-2.6.20.14-fbx/arch/mips/bcm963xx/boards/Makefile
--- linux-2.6.20.14-fbx/arch/mips/bcm963xx./boards/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/arch/mips/bcm963xx/boards/Makefile	2011-09-26 15:07:53.868835715 +0200
@@ -0,0 +1,4 @@
+obj-$(CONFIG_BOARD_BCM963XX)		+= board-bcm963xx.o
+obj-$(CONFIG_BOARD_FBX4)		+= board-fbx4.o
+obj-$(CONFIG_BOARD_FBX5A)		+= board-fbx5a.o
+obj-$(CONFIG_BOARD_FBXGW1A)		+= board-fbxgw1a.o
diff -Nruw linux-2.6.20.14-fbx/arch/mips/bcm963xx./cpu.c linux-2.6.20.14-fbx/arch/mips/bcm963xx/cpu.c
--- linux-2.6.20.14-fbx/arch/mips/bcm963xx./cpu.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/arch/mips/bcm963xx/cpu.c	2011-09-26 15:07:53.868835715 +0200
@@ -0,0 +1,248 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/cpu.h>
+#include "bcm963xx.h"
+
+unsigned long *bcm963xx_regs_base;
+int *bcm963xx_irqs;
+
+static u16 bcm963xx_cpu_id;
+static u16 bcm963xx_cpu_rev;
+static unsigned int bcm963xx_cpu_freq;
+
+/*
+ * 6348 register sets and irqs
+ */
+static unsigned long bcm96348_regs_base[] = {
+	[RSET_DSL_LMEM]		= BCM_6348_DSL_LMEM_BASE,
+	[RSET_PERF]		= BCM_6348_PERF_BASE,
+	[RSET_TIMER]		= BCM_6348_TIMER_BASE,
+	[RSET_WDT]		= BCM_6348_WDT_BASE,
+	[RSET_UART0]		= BCM_6348_UART0_BASE,
+	[RSET_GPIO]		= BCM_6348_GPIO_BASE,
+	[RSET_SPI]		= BCM_6348_SPI_BASE,
+	[RSET_UDC0]		= BCM_6348_UDC0_BASE,
+	[RSET_OHCI0]		= BCM_6348_OHCI0_BASE,
+	[RSET_OHCI_PRIV]	= BCM_6348_OHCI_PRIV_BASE,
+	[RSET_USBH_PRIV]	= BCM_6348_USBH_PRIV_BASE,
+	[RSET_MPI]		= BCM_6348_MPI_BASE,
+	[RSET_PCMCIA]		= BCM_6348_PCMCIA_BASE,
+	[RSET_SDRAM]		= BCM_6348_SDRAM_BASE,
+	[RSET_DSL]		= BCM_6348_DSL_BASE,
+	[RSET_ENET0]		= BCM_6348_ENET0_BASE,
+	[RSET_ENET1]		= BCM_6348_ENET1_BASE,
+	[RSET_ENETDMA]		= BCM_6348_ENETDMA_BASE,
+	[RSET_MEMC]		= BCM_6348_MEMC_BASE,
+	[RSET_ATM]		= BCM_6348_ATM_BASE,
+};
+
+static int bcm96348_irqs[] = {
+	[IRQ_TIMER]		= BCM_6348_TIMER_IRQ,
+	[IRQ_UART0]		= BCM_6348_UART0_IRQ,
+	[IRQ_DSL]		= BCM_6348_DSL_IRQ,
+	[IRQ_UDC0]		= BCM_6348_UDC0_IRQ,
+	[IRQ_ENET0]		= BCM_6348_ENET0_IRQ,
+	[IRQ_ENET1]		= BCM_6348_ENET1_IRQ,
+	[IRQ_ENET_PHY]		= BCM_6348_ENET_PHY_IRQ,
+	[IRQ_OHCI0]		= BCM_6348_OHCI0_IRQ,
+	[IRQ_UDC0_CTL_RX]	= BCM_6348_UDC0_CTL_RX_IRQ,
+	[IRQ_UDC0_CTL_TX]	= BCM_6348_UDC0_CTL_TX_IRQ,
+	[IRQ_UDC0_BULK_RX]	= BCM_6348_UDC0_BULK_RX_IRQ,
+	[IRQ_UDC0_BULK_TX]	= BCM_6348_UDC0_BULK_TX_IRQ,
+	[IRQ_UDC0_ISO_RX]	= BCM_6348_UDC0_ISO_RX_IRQ,
+	[IRQ_UDC0_ISO_TX]	= BCM_6348_UDC0_ISO_TX_IRQ,
+	[IRQ_PCMCIA]		= BCM_6348_PCMCIA_IRQ,
+	[IRQ_ENET0_RXDMA]	= BCM_6348_ENET0_RXDMA_IRQ,
+	[IRQ_ENET0_TXDMA]	= BCM_6348_ENET0_TXDMA_IRQ,
+	[IRQ_ENET1_RXDMA]	= BCM_6348_ENET1_RXDMA_IRQ,
+	[IRQ_ENET1_TXDMA]	= BCM_6348_ENET1_TXDMA_IRQ,
+	[IRQ_PCI]		= BCM_6348_PCI_IRQ,
+	[IRQ_ATM]		= BCM_6348_ATM_IRQ,
+};
+
+/*
+ * 6358 register sets and irqs
+ */
+static unsigned long bcm96358_regs_base[] = {
+	[RSET_DSL_LMEM]		= BCM_6358_DSL_LMEM_BASE,
+	[RSET_PERF]		= BCM_6358_PERF_BASE,
+	[RSET_TIMER]		= BCM_6358_TIMER_BASE,
+	[RSET_WDT]		= BCM_6358_WDT_BASE,
+	[RSET_UART0]		= BCM_6358_UART0_BASE,
+	[RSET_GPIO]		= BCM_6358_GPIO_BASE,
+	[RSET_SPI]		= BCM_6358_SPI_BASE,
+	[RSET_UDC0]		= BCM_6358_UDC0_BASE,
+	[RSET_OHCI0]		= BCM_6358_OHCI0_BASE,
+	[RSET_EHCI0]		= BCM_6358_EHCI0_BASE,
+	[RSET_OHCI_PRIV]	= BCM_6358_OHCI_PRIV_BASE,
+	[RSET_USBH_PRIV]	= BCM_6358_USBH_PRIV_BASE,
+	[RSET_MPI]		= BCM_6358_MPI_BASE,
+	[RSET_PCMCIA]		= BCM_6358_PCMCIA_BASE,
+	[RSET_SDRAM]		= BCM_6348_SDRAM_BASE,
+	[RSET_DSL]		= BCM_6358_DSL_BASE,
+	[RSET_ENET0]		= BCM_6358_ENET0_BASE,
+	[RSET_ENET1]		= BCM_6358_ENET1_BASE,
+	[RSET_ENETDMA]		= BCM_6358_ENETDMA_BASE,
+	[RSET_MEMC]		= BCM_6358_MEMC_BASE,
+	[RSET_ATM]		= BCM_6358_ATM_BASE,
+};
+
+static int bcm96358_irqs[] = {
+	[IRQ_TIMER]		= BCM_6358_TIMER_IRQ,
+	[IRQ_UART0]		= BCM_6358_UART0_IRQ,
+	[IRQ_DSL]		= BCM_6358_DSL_IRQ,
+	[IRQ_UDC0]		= BCM_6358_UDC0_IRQ,
+	[IRQ_ENET0]		= BCM_6358_ENET0_IRQ,
+	[IRQ_ENET1]		= BCM_6358_ENET1_IRQ,
+	[IRQ_ENET_PHY]		= BCM_6358_ENET_PHY_IRQ,
+	[IRQ_OHCI0]		= BCM_6358_OHCI0_IRQ,
+	[IRQ_EHCI0]		= BCM_6358_EHCI0_IRQ,
+	[IRQ_UDC0_CTL_RX]	= BCM_6358_UDC0_CTL_RX_IRQ,
+	[IRQ_UDC0_CTL_TX]	= BCM_6358_UDC0_CTL_TX_IRQ,
+	[IRQ_UDC0_BULK_RX]	= BCM_6358_UDC0_BULK_RX_IRQ,
+	[IRQ_UDC0_BULK_TX]	= BCM_6358_UDC0_BULK_TX_IRQ,
+	[IRQ_UDC0_ISO_RX]	= BCM_6358_UDC0_ISO_RX_IRQ,
+	[IRQ_UDC0_ISO_TX]	= BCM_6358_UDC0_ISO_TX_IRQ,
+	[IRQ_PCMCIA]		= BCM_6358_PCMCIA_IRQ,
+	[IRQ_ENET0_RXDMA]	= BCM_6358_ENET0_RXDMA_IRQ,
+	[IRQ_ENET0_TXDMA]	= BCM_6358_ENET0_TXDMA_IRQ,
+	[IRQ_ENET1_RXDMA]	= BCM_6358_ENET1_RXDMA_IRQ,
+	[IRQ_ENET1_TXDMA]	= BCM_6358_ENET1_TXDMA_IRQ,
+	[IRQ_PCI]		= BCM_6358_PCI_IRQ,
+	[IRQ_ATM]		= BCM_6358_ATM_IRQ,
+};
+
+u16 __bcm963xx_get_cpu_id(void)
+{
+	return bcm963xx_cpu_id;
+}
+
+u16 bcm963xx_get_cpu_rev(void)
+{
+	return bcm963xx_cpu_rev;
+}
+
+unsigned int bcm963xx_get_cpu_freq(void)
+{
+	return bcm963xx_cpu_freq;
+}
+
+static unsigned int detect_cpu_clock(void)
+{
+	if (BCMCPU_IS_6338())
+		return 240000000;
+	else if (BCMCPU_IS_6345())
+		return 140000000;
+	else if (BCMCPU_IS_6348()) {
+		unsigned int tmp, n1, n2, m1;
+
+		/*
+		 * 6348 frequency depends on PLL configuration:
+		 * (16MHz) * (N1 + 1) * (N2 + 2) / (M1_CPU + 1)
+		 */
+		tmp = bcm_perf_readl(PERF_MIPSPLLCTL_REG);
+		n1 = (tmp & MIPSPLLCTL_N1_MASK) >> MIPSPLLCTL_N1_SHIFT;
+		n2 = (tmp & MIPSPLLCTL_N2_MASK) >> MIPSPLLCTL_N2_SHIFT;
+		m1 = (tmp & MIPSPLLCTL_M1CPU_MASK) >> MIPSPLLCTL_M1CPU_SHIFT;
+
+		return (16 * 1000000 * (n1 + 1) * (n2 + 2) / (m1 + 1));
+	} else {
+		/* BCMCPU_IS_6358() */
+		return 300000000;
+	}
+}
+
+/*
+ * Some 6348 have a RAC (read ahead cache), and old CFE don't enable
+ * it, so do it here.
+ *
+ * Signal  trampoline code  seems to  trigger a  bug wrt  RAC, causing
+ * invalid code  to be  executed. So we  set the RAC  to automatically
+ * invalidate itself  whenever a  CACHE instruction is  executed, that
+ * seems to fix it.
+ */
+#define MIPS_BASE	0xff400000
+#define RAC_CR0		0x00
+#define RAC_PWR		(1 << 31)
+#define RAC_BRR_PF	(1 << 30)
+#define RAC_FLH		(1 << 8)
+#define RAC_DPF		(1 << 6)
+#define RAC_NCH		(1 << 5)
+#define RAC_C_INV	(1 << 4)
+#define RAC_PF_D	(1 << 3)
+#define RAC_PF_I	(1 << 2)
+#define RAC_D		(1 << 1)
+#define RAC_I		(1 << 0)
+
+#define RAC_CR1		0x04
+#define RAC_UPB_SHFT    16
+#define RAC_LWB_SHFT    0
+
+static void fixup_rac_cache(void)
+{
+	volatile unsigned int *cr0, *cr1;
+
+	cr0 = (volatile unsigned int *)(MIPS_BASE + RAC_CR0);
+	cr1 = (volatile unsigned int *)(MIPS_BASE + RAC_CR1);
+
+	/* reconfigure rac with rac_c_inv set */
+	*cr0 = RAC_I | RAC_PF_I | RAC_C_INV;
+	*cr1 = (0x2000 << RAC_UPB_SHFT);
+}
+
+void __init bcm963xx_cpu_init(void)
+{
+	unsigned int tmp, expected_cpu_id;
+	struct cpuinfo_mips *c = &current_cpu_data;
+
+	/* soc registers location depends on cpu type */
+	expected_cpu_id = 0;
+
+	switch (c->cputype) {
+	case CPU_BCM6338:
+		expected_cpu_id = BCM6338_CPU_ID;
+		break;
+	case CPU_BCM6345:
+		expected_cpu_id = BCM6345_CPU_ID;
+		break;
+	case CPU_BCM6348:
+		expected_cpu_id = BCM6348_CPU_ID;
+		bcm963xx_regs_base = bcm96348_regs_base;
+		bcm963xx_irqs = bcm96348_irqs;
+		fixup_rac_cache();
+		break;
+	case CPU_BCM6358:
+		expected_cpu_id = BCM6358_CPU_ID;
+		bcm963xx_regs_base = bcm96358_regs_base;
+		bcm963xx_irqs = bcm96358_irqs;
+		break;
+	case CPU_BCM6368:
+		break;
+	}
+
+	/* really early to panic, but delaying panic would not help
+	 * since we will never get any working console */
+	if (!expected_cpu_id)
+		panic("unsupported Broadcom CPU");
+
+	/*
+	 * bcm963xx_regs_base is set, we can access soc registers
+	 */
+
+	/* double check CPU type */
+	tmp = bcm_perf_readl(PERF_REV_REG);
+	bcm963xx_cpu_id = (tmp & REV_CHIPID_MASK) >> REV_CHIPID_SHIFT;
+	bcm963xx_cpu_rev = (tmp & REV_REVID_MASK) >> REV_REVID_SHIFT;
+
+	if (bcm963xx_cpu_id != expected_cpu_id)
+		panic("bcm63xx CPU id mismatch");
+
+	printk(KERN_INFO "Detected Broadcom 0x%04x CPU revision %02x\n",
+	       bcm963xx_cpu_id, bcm963xx_cpu_rev);
+	bcm963xx_cpu_freq = detect_cpu_clock();
+}
+
+EXPORT_SYMBOL(bcm963xx_regs_base);
+EXPORT_SYMBOL(bcm963xx_irqs);
+EXPORT_SYMBOL(__bcm963xx_get_cpu_id);
+EXPORT_SYMBOL(bcm963xx_get_cpu_rev);
diff -Nruw linux-2.6.20.14-fbx/arch/mips/bcm963xx./cs.c linux-2.6.20.14-fbx/arch/mips/bcm963xx/cs.c
--- linux-2.6.20.14-fbx/arch/mips/bcm963xx./cs.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/arch/mips/bcm963xx/cs.c	2011-09-26 15:07:53.868835715 +0200
@@ -0,0 +1,134 @@
+/*
+ * chip select access helpers
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/log2.h>
+#include "bcm963xx.h"
+
+static DEFINE_SPINLOCK(bcm963xx_cs_lock);
+
+/*
+ * check if given chip select exists
+ */
+static int is_valid_cs(unsigned int cs)
+{
+	if (cs > 6)
+		return 0;
+	return 1;
+}
+
+/*
+ * Configure chipselect base address and size (bytes).
+ * Size must be a power of two between 8k and 256M.
+ */
+int bcm963xx_set_cs_base(unsigned int cs, u32 base, unsigned int size)
+{
+	unsigned long flags;
+	u32 val;
+
+	if (!is_valid_cs(cs))
+		return -EINVAL;
+
+	/* sanity check on size */
+	if (size != roundup_pow_of_two(size))
+		return -EINVAL;
+
+	if (size < 8 * 1024 || size > 256 * 1024 * 1024)
+		return -EINVAL;
+
+	val = (base & MPI_CSBASE_BASE_MASK);
+	/* 8k => 0 - 256M => 15 */
+	val |= (ilog2(size) - ilog2(8 * 1024)) << MPI_CSBASE_SIZE_SHIFT;
+
+	spin_lock_irqsave(&bcm963xx_cs_lock, flags);
+	bcm_mpi_writel(val, MPI_CSBASE_REG(cs));
+	spin_unlock_irqrestore(&bcm963xx_cs_lock, flags);
+
+	return 0;
+}
+
+/*
+ * configure chipselect timing (ns)
+ */
+int bcm963xx_set_cs_timing(unsigned int cs, unsigned int wait,
+			   unsigned int setup, unsigned int hold)
+{
+	unsigned long flags;
+	u32 val;
+
+	if (!is_valid_cs(cs))
+		return -EINVAL;
+
+	spin_lock_irqsave(&bcm963xx_cs_lock, flags);
+	val = bcm_mpi_readl(MPI_CSCTL_REG(cs));
+	val &= ~(MPI_CSCTL_WAIT_MASK);
+	val &= ~(MPI_CSCTL_SETUP_MASK);
+	val &= ~(MPI_CSCTL_HOLD_MASK);
+	val |= wait << MPI_CSCTL_WAIT_SHIFT;
+	val |= setup << MPI_CSCTL_SETUP_SHIFT;
+	val |= hold << MPI_CSCTL_HOLD_SHIFT;
+	bcm_mpi_writel(val, MPI_CSCTL_REG(cs));
+	spin_unlock_irqrestore(&bcm963xx_cs_lock, flags);
+
+	return 0;
+}
+
+/*
+ * configure other chipselect parameter (data bus size, ...)
+ */
+int bcm963xx_set_cs_param(unsigned int cs, u32 params)
+{
+	unsigned long flags;
+	u32 val;
+
+	if (!is_valid_cs(cs))
+		return -EINVAL;
+
+	/* none of this fields apply to pcmcia */
+	if (cs == MPI_CS_PCMCIA_COMMON ||
+	    cs == MPI_CS_PCMCIA_ATTR ||
+	    cs == MPI_CS_PCMCIA_IO)
+		return -EINVAL;
+
+	spin_lock_irqsave(&bcm963xx_cs_lock, flags);
+	val = bcm_mpi_readl(MPI_CSCTL_REG(cs));
+	val &= ~(MPI_CSCTL_DATA16_MASK);
+	val &= ~(MPI_CSCTL_SYNCMODE_MASK);
+	val &= ~(MPI_CSCTL_TSIZE_MASK);
+	val &= ~(MPI_CSCTL_ENDIANSWAP_MASK);
+	val |= params;
+	bcm_mpi_writel(val, MPI_CSCTL_REG(cs));
+	spin_unlock_irqrestore(&bcm963xx_cs_lock, flags);
+
+	return 0;
+}
+
+/*
+ * set cs status (enable/disable)
+ */
+int bcm963xx_set_cs_status(unsigned int cs, int enable)
+{
+	unsigned long flags;
+	u32 val;
+
+	if (!is_valid_cs(cs))
+		return -EINVAL;
+
+	spin_lock_irqsave(&bcm963xx_cs_lock, flags);
+	val = bcm_mpi_readl(MPI_CSCTL_REG(cs));
+	if (enable)
+		val |= MPI_CSCTL_ENABLE_MASK;
+	else
+		val &= ~MPI_CSCTL_ENABLE_MASK;
+	bcm_mpi_writel(val, MPI_CSCTL_REG(cs));
+	spin_unlock_irqrestore(&bcm963xx_cs_lock, flags);
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(bcm963xx_set_cs_base);
+EXPORT_SYMBOL_GPL(bcm963xx_set_cs_timing);
+EXPORT_SYMBOL_GPL(bcm963xx_set_cs_param);
+EXPORT_SYMBOL_GPL(bcm963xx_set_cs_status);
diff -Nruw linux-2.6.20.14-fbx/arch/mips/bcm963xx./dev-bcmusb.c linux-2.6.20.14-fbx/arch/mips/bcm963xx/dev-bcmusb.c
--- linux-2.6.20.14-fbx/arch/mips/bcm963xx./dev-bcmusb.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/arch/mips/bcm963xx/dev-bcmusb.c	2011-09-26 15:07:53.868835715 +0200
@@ -0,0 +1,22 @@
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include "bcm963xx.h"
+
+static struct platform_device bcmusb_device = {
+	.name		= "bcmusb",
+	.id		= 0,
+};
+
+void __init bcmusb_set_pdata(struct bcmusb_platform_data *pd)
+{
+	bcmusb_device.dev.platform_data = pd;
+}
+
+int __init bcmusb_register(void)
+{
+	return platform_device_register(&bcmusb_device);
+}
+
+__initcall(bcmusb_register);
diff -Nruw linux-2.6.20.14-fbx/arch/mips/bcm963xx./dev-enet.c linux-2.6.20.14-fbx/arch/mips/bcm963xx/dev-enet.c
--- linux-2.6.20.14-fbx/arch/mips/bcm963xx./dev-enet.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/arch/mips/bcm963xx/dev-enet.c	2011-09-26 15:07:53.868835715 +0200
@@ -0,0 +1,132 @@
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include "bcm963xx.h"
+
+static struct resource enet_shared_resources[] = {
+	{
+		.start		= -1, /* filled at runtime */
+		.end		= -1, /* filled at runtime */
+		.flags		= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device bcm963xx_enet_shared_device = {
+	.name		= "bcm963xx_enet_shared",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(enet_shared_resources),
+	.resource	= enet_shared_resources,
+};
+
+static struct resource enet0_resources[] = {
+	{
+		.start		= -1, /* filled at runtime */
+		.end		= -1, /* filled at runtime */
+		.flags		= IORESOURCE_MEM,
+	},
+	{
+		.start		= -1, /* filled at runtime */
+		.flags		= IORESOURCE_IRQ,
+	},
+	{
+		.start		= -1, /* filled at runtime */
+		.start		= IRQ_ENET0_RXDMA,
+		.flags		= IORESOURCE_IRQ,
+	},
+	{
+		.start		= -1, /* filled at runtime */
+		.start		= IRQ_ENET0_TXDMA,
+		.flags		= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device bcm963xx_enet0_device = {
+	.name		= "bcm963xx_enet",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(enet0_resources),
+	.resource	= enet0_resources,
+};
+
+static struct resource enet1_resources[] = {
+	{
+		.start		= -1, /* filled at runtime */
+		.end		= -1, /* filled at runtime */
+		.flags		= IORESOURCE_MEM,
+	},
+	{
+		.start		= -1, /* filled at runtime */
+		.flags		= IORESOURCE_IRQ,
+	},
+	{
+		.start		= -1, /* filled at runtime */
+		.flags		= IORESOURCE_IRQ,
+	},
+	{
+		.start		= -1, /* filled at runtime */
+		.flags		= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device bcm963xx_enet1_device = {
+	.name		= "bcm963xx_enet",
+	.id		= 1,
+	.num_resources	= ARRAY_SIZE(enet1_resources),
+	.resource	= enet1_resources,
+};
+
+int __init bcm963xx_enet_set_pdata(int unit,
+				   struct bcm963xx_enet_platform_data *pd)
+{
+	if (unit > 1)
+		return -ENODEV;
+	if (unit == 0)
+		bcm963xx_enet0_device.dev.platform_data = pd;
+	else
+		bcm963xx_enet1_device.dev.platform_data = pd;
+
+	/* adjust resources in case internal phy is used */
+	if (pd->use_internal_phy) {
+		pd->phy_id = 1;
+		pd->has_phy_interrupt = 1;
+		pd->phy_interrupt = bcm_irq_number(IRQ_ENET_PHY);
+	}
+	return 0;
+}
+
+int __init bcm963xx_enet_register(void)
+{
+	int ret;
+
+	enet_shared_resources[0].start = bcm_reg_address(RSET_ENETDMA);
+	enet_shared_resources[0].end = enet_shared_resources[0].start;
+	enet_shared_resources[0].end += RSET_ENETDMA_SIZE - 1;
+
+	enet0_resources[0].start = bcm_reg_address(RSET_ENET0);
+	enet0_resources[0].end = enet0_resources[0].start;
+	enet0_resources[0].end += RSET_ENET_SIZE - 1;
+	enet0_resources[1].start = bcm_irq_number(IRQ_ENET0);
+	enet0_resources[2].start = bcm_irq_number(IRQ_ENET0_RXDMA);
+	enet0_resources[3].start = bcm_irq_number(IRQ_ENET0_TXDMA);
+
+	enet1_resources[0].start = bcm_reg_address(RSET_ENET1);
+	enet1_resources[0].end = enet1_resources[0].start;
+	enet1_resources[0].end += RSET_ENET_SIZE - 1;
+	enet1_resources[1].start = bcm_irq_number(IRQ_ENET1);
+	enet1_resources[2].start = bcm_irq_number(IRQ_ENET1_RXDMA);
+	enet1_resources[3].start = bcm_irq_number(IRQ_ENET1_TXDMA);
+
+	if ((ret = platform_device_register(&bcm963xx_enet_shared_device)))
+		return ret;
+
+	if (bcm963xx_enet0_device.dev.platform_data &&
+	    (ret = platform_device_register(&bcm963xx_enet0_device)))
+		return ret;
+
+	if (bcm963xx_enet1_device.dev.platform_data &&
+	    (ret = platform_device_register(&bcm963xx_enet1_device)))
+		return ret;
+
+	return 0;
+}
+
+__initcall(bcm963xx_enet_register);
diff -Nruw linux-2.6.20.14-fbx/arch/mips/bcm963xx./dev-fbx-atm.c linux-2.6.20.14-fbx/arch/mips/bcm963xx/dev-fbx-atm.c
--- linux-2.6.20.14-fbx/arch/mips/bcm963xx./dev-fbx-atm.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/arch/mips/bcm963xx/dev-fbx-atm.c	2011-09-26 15:07:53.868835715 +0200
@@ -0,0 +1,37 @@
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+
+#include "bcm963xx.h"
+
+static struct resource atm_resources[] = {
+	{
+		.start		= -1, /* filled at runtime */
+		.end		= -1, /* filled at runtime */
+		.flags		= IORESOURCE_MEM,
+	},
+	{
+		.start		= -1, /* filled at runtime */
+		.flags		= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device bcm963xx_fbxatm_device = {
+	.name		= "bcm63xx_fbxatm",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(atm_resources),
+	.resource	= atm_resources,
+};
+
+int __init bcm963xx_fbxatm_register(void)
+{
+	atm_resources[0].start = bcm_reg_address(RSET_ATM);
+	atm_resources[0].end = atm_resources[0].start;
+	atm_resources[0].end += RSET_ATM_SIZE - 1;
+	atm_resources[1].start = bcm_irq_number(IRQ_ATM);
+
+	return platform_device_register(&bcm963xx_fbxatm_device);
+}
+
+__initcall(bcm963xx_fbxatm_register);
diff -Nruw linux-2.6.20.14-fbx/arch/mips/bcm963xx./dev-fbx-dma.c linux-2.6.20.14-fbx/arch/mips/bcm963xx/dev-fbx-dma.c
--- linux-2.6.20.14-fbx/arch/mips/bcm963xx./dev-fbx-dma.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/arch/mips/bcm963xx/dev-fbx-dma.c	2011-09-26 15:07:53.868835715 +0200
@@ -0,0 +1,17 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+static struct platform_device bcm963xx_dma_device =
+{
+	.name	= "bcm963xx_dma",
+	.id	= -1,
+};
+
+int
+bcm963xx_dma_init(void)
+{
+	return platform_device_register(&bcm963xx_dma_device);
+}
+
+arch_initcall(bcm963xx_dma_init);
diff -Nruw linux-2.6.20.14-fbx/arch/mips/bcm963xx./dev-fbx-watchdog.c linux-2.6.20.14-fbx/arch/mips/bcm963xx/dev-fbx-watchdog.c
--- linux-2.6.20.14-fbx/arch/mips/bcm963xx./dev-fbx-watchdog.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/arch/mips/bcm963xx/dev-fbx-watchdog.c	2011-09-26 15:07:53.868835715 +0200
@@ -0,0 +1,32 @@
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include "bcm963xx.h"
+
+static struct resource wdt_resources[] = {
+	{
+		.start		= -1, /* filled at runtime */
+		.end		= -1, /* filled at runtime */
+		.flags		= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device bcm963xx_watchdog = {
+	.name		= "bcm963xx_wdt",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(wdt_resources),
+	.resource	= wdt_resources,
+};
+
+static int __init bcm963xx_watchdog_register(void)
+{
+	wdt_resources[0].start = bcm_reg_address(RSET_WDT);
+	wdt_resources[0].end = wdt_resources[0].start;
+	wdt_resources[0].end += RSET_WDT_SIZE - 1;
+
+	platform_device_register(&bcm963xx_watchdog);
+	return 0;
+}
+
+device_initcall(bcm963xx_watchdog_register);
diff -Nruw linux-2.6.20.14-fbx/arch/mips/bcm963xx./dev-uart.c linux-2.6.20.14-fbx/arch/mips/bcm963xx/dev-uart.c
--- linux-2.6.20.14-fbx/arch/mips/bcm963xx./dev-uart.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/arch/mips/bcm963xx/dev-uart.c	2011-09-26 15:07:53.868835715 +0200
@@ -0,0 +1,37 @@
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-bcm963xx/bcm963xx_io.h>
+#include <asm/mach-bcm963xx/bcm963xx_regs.h>
+#include <asm/mach-bcm963xx/bcm963xx_irq.h>
+
+static struct resource uart_resources[] = {
+	{
+		.start		= -1, /* filled at runtime */
+		.end		= -1, /* filled at runtime */
+		.flags		= IORESOURCE_MEM,
+	},
+	{
+		.start		= -1, /* filled at runtime */
+		.flags		= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device bcm963xx_uart_device = {
+	.name		= "bcm963xx_uart",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(uart_resources),
+	.resource	= uart_resources,
+};
+
+int __init bcm963xx_uart_register(void)
+{
+	uart_resources[0].start = bcm_reg_address(RSET_UART0);
+	uart_resources[0].end = uart_resources[0].start;
+	uart_resources[0].end += RSET_UART_SIZE - 1;
+	uart_resources[1].start = bcm_irq_number(IRQ_UART0);
+	return platform_device_register(&bcm963xx_uart_device);
+}
+
+__initcall(bcm963xx_uart_register);
diff -Nruw linux-2.6.20.14-fbx/arch/mips/bcm963xx./dev-usb-ohci.c linux-2.6.20.14-fbx/arch/mips/bcm963xx/dev-usb-ohci.c
--- linux-2.6.20.14-fbx/arch/mips/bcm963xx./dev-usb-ohci.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/arch/mips/bcm963xx/dev-usb-ohci.c	2011-09-26 15:07:53.868835715 +0200
@@ -0,0 +1,43 @@
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include "bcm963xx.h"
+
+static struct resource ohci_resources[] = {
+	{
+		.start		= -1, /* filled at runtime */
+		.end		= -1, /* filled at runtime */
+		.flags		= IORESOURCE_MEM,
+	},
+	{
+		.start		= -1, /* filled at runtime */
+		.flags		= IORESOURCE_IRQ,
+	},
+};
+
+static u64 ohci_dmamask = ~(u32)0;
+
+static struct platform_device bcm963xx_ohci_device = {
+	.name		= "bcm963xx_ohci",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(ohci_resources),
+	.resource	= ohci_resources,
+	.dev		= {
+		.dma_mask		= &ohci_dmamask,
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+int __init bcm963xx_ohci_register(void)
+{
+	if (!BCMCPU_IS_6348() && !BCMCPU_IS_6358())
+		return 0;
+
+	ohci_resources[0].start = bcm_reg_address(RSET_OHCI0);
+	ohci_resources[0].end = ohci_resources[0].start;
+	ohci_resources[0].end += RSET_OHCI_SIZE - 1;
+	ohci_resources[1].start = bcm_irq_number(IRQ_OHCI0);
+	return platform_device_register(&bcm963xx_ohci_device);
+}
+
+device_initcall(bcm963xx_ohci_register);
diff -Nruw linux-2.6.20.14-fbx/arch/mips/bcm963xx./early_console.c linux-2.6.20.14-fbx/arch/mips/bcm963xx/early_console.c
--- linux-2.6.20.14-fbx/arch/mips/bcm963xx./early_console.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/arch/mips/bcm963xx/early_console.c	2011-09-26 15:07:53.868835715 +0200
@@ -0,0 +1,57 @@
+#include <linux/init.h>
+#include <linux/console.h>
+#include "bcm963xx.h"
+
+static void __init wait_xfered(void)
+{
+	unsigned int val;
+
+	/* wait for any previous char to be transmitted */
+	do {
+		val = bcm_uart0_readl(UART_IR_REG);
+		if (val & UART_IR_STAT(UART_IR_TXEMPTY))
+			break;
+	} while (1);
+}
+
+static void __init console_putc(char c)
+{
+	wait_xfered();
+	bcm_uart0_writel(c, UART_FIFO_REG);
+	wait_xfered();
+}
+
+static void __init console_write(struct console *con, const char *s,
+				 unsigned int count)
+{
+	while (count-- && *s) {
+		if (*s == '\n')
+			console_putc('\r');
+		console_putc(*s++);
+	}
+}
+
+static int __init console_setup(struct console *co, char *options)
+{
+	unsigned int val;
+
+	/* keep bootloader settings for serial port, just reset
+	 * rx & tx fifo */
+	val = bcm_uart0_readl(UART_CTL_REG);
+	val |= UART_CTL_RSTRXFIFO_MASK | UART_CTL_RSTTXFIFO_MASK;
+	bcm_uart0_writel(val, UART_CTL_REG);
+	return 0;
+}
+
+static struct console bcm963xx_early_console __initdata = {
+	.name	= "prom",
+	.setup	= console_setup,
+	.write	= console_write,
+	.flags	= CON_PRINTBUFFER | CON_BOOT,
+	.index	= -1,
+};
+
+void __init bcm963xx_register_early_console(void)
+{
+	register_console(&bcm963xx_early_console);
+}
diff -Nruw linux-2.6.20.14-fbx/arch/mips/bcm963xx./gpio.c linux-2.6.20.14-fbx/arch/mips/bcm963xx/gpio.c
--- linux-2.6.20.14-fbx/arch/mips/bcm963xx./gpio.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/arch/mips/bcm963xx/gpio.c	2011-09-26 15:07:53.868835715 +0200
@@ -0,0 +1,86 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include "bcm963xx.h"
+
+static DEFINE_SPINLOCK(bcm963xx_gpio_lock);
+
+void bcm963xx_gpio_set_dataout(int gpio, int val)
+{
+	uint32_t reg;
+	uint32_t mask;
+	uint32_t tmp;
+	unsigned long flags;
+
+
+	if (gpio >= bcm963xx_gpio_count())
+		BUG();
+
+	if (gpio < 32) {
+		reg = GPIO_DATA_LO_REG;
+		mask = 1 << gpio;
+	} else {
+		reg = GPIO_DATA_HI_REG;
+		mask = 1 << (gpio - 32);
+	}
+
+	spin_lock_irqsave(&bcm963xx_gpio_lock, flags);
+	tmp = bcm_gpio_readl(reg);
+	if (val)
+		tmp |= mask;
+	else
+		tmp &= ~mask;
+	bcm_gpio_writel(tmp, reg);
+	spin_unlock_irqrestore(&bcm963xx_gpio_lock, flags);
+}
+
+int bcm963xx_gpio_get_datain(int gpio)
+{
+	uint32_t reg;
+	uint32_t mask;
+
+	if (gpio >= bcm963xx_gpio_count())
+		BUG();
+
+	if (gpio < 32) {
+		reg = GPIO_DATA_LO_REG;
+		mask = 1 << gpio;
+	} else {
+		reg = GPIO_DATA_HI_REG;
+		mask = 1 << (gpio - 32);
+	}
+
+	return !!(bcm_gpio_readl(reg) & mask);
+}
+
+void bcm963xx_gpio_set_direction(int gpio, int dir)
+{
+	uint32_t reg;
+	uint32_t mask;
+	uint32_t tmp;
+	unsigned long flags;
+
+	if (gpio >= bcm963xx_gpio_count())
+		BUG();
+
+	if (gpio < 32) {
+		reg = GPIO_CTL_LO_REG;
+		mask = 1 << gpio;
+	} else {
+		reg = GPIO_CTL_HI_REG;
+		mask = 1 << (gpio - 32);
+	}
+
+	spin_lock_irqsave(&bcm963xx_gpio_lock, flags);
+	tmp = bcm_gpio_readl(reg);
+	if (dir == GPIO_DIR_IN)
+		tmp &= ~mask;
+	else
+		tmp |= mask;
+	bcm_gpio_writel(tmp, reg);
+	spin_unlock_irqrestore(&bcm963xx_gpio_lock, flags);
+}
+
+EXPORT_SYMBOL_GPL(bcm963xx_gpio_set_dataout);
+EXPORT_SYMBOL_GPL(bcm963xx_gpio_get_datain);
+EXPORT_SYMBOL_GPL(bcm963xx_gpio_set_direction);
diff -Nruw linux-2.6.20.14-fbx/arch/mips/bcm963xx./irq.c linux-2.6.20.14-fbx/arch/mips/bcm963xx/irq.c
--- linux-2.6.20.14-fbx/arch/mips/bcm963xx./irq.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/arch/mips/bcm963xx/irq.c	2011-09-26 15:07:53.868835715 +0200
@@ -0,0 +1,384 @@
+/*
+ * irq managment for bcm963xx boards
+ *
+ * bcm963xx has two kind of interrupts:
+ *
+ * - internal interrupts: they are managed with irq mask and irq stat
+ *   in the PERF block.
+ *
+ * - external interrupts: they are managed with the external irq
+ *   control register in the PERF block.
+ *
+ * only external interrupts can have their flow type changed.
+ *
+ * Nicolas Schichan <nschichan@freebox.fr>
+ * (c) 2007, Freebox SA
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+
+#include <asm/irq_cpu.h>
+#include <asm/mipsregs.h>
+#include "bcm963xx.h"
+
+static unsigned long mapped_interrupts_bits[NR_IRQS / sizeof (unsigned long)];
+
+static inline int irq_is_mapped(unsigned int irq)
+{
+	return mapped_interrupts_bits[irq / sizeof (unsigned long)] &
+		(1 << (irq % (sizeof (unsigned long) * 8)));
+}
+
+static inline int irq_is_internal(int irq)
+{
+	return irq >= IRQ_INTERNAL_BASE;
+}
+
+static int inline irq_is_external(int irq)
+{
+	return (irq >= IRQ_EXT_0) && (irq <= IRQ_EXT_3);
+}
+
+/*
+ * dispatch internal devices IRQ (uart, enet, watchdog, ...). do not
+ * priortize any interrupt relatively to another. the static counter
+ * will resume the loop where it ended the last time we left this
+ * function.
+ */
+static void bcm963xx_irq_dispatch_internal(void)
+{
+	u32 pending;
+	static int i;
+
+	pending = bcm_perf_readl(PERF_IRQMASK_REG) &
+		bcm_perf_readl(PERF_IRQSTAT_REG);
+
+	if (!pending)
+		return ;
+
+	while (1) {
+		int to_call = i;
+
+		i = (i + 1) & 0x1f;
+		if (pending & (1 << to_call)) {
+			do_IRQ(to_call + IRQ_INTERNAL_BASE);
+			break;
+		}
+	}
+}
+
+asmlinkage void plat_irq_dispatch(void)
+{
+	u32 cause;
+
+	do {
+		cause = read_c0_cause() & read_c0_status() & ST0_IM;
+
+		if (!cause)
+			break;
+
+#ifdef CONFIG_SMP
+		if (cause & CAUSEF_IP0) {
+			bcm963xx_ipi_irq(0);
+			clear_c0_cause(CAUSEF_IP0);
+		}
+		if (cause & CAUSEF_IP1) {
+			bcm963xx_ipi_irq(1);
+			clear_c0_cause(CAUSEF_IP1);
+		}
+#endif
+		if (cause & CAUSEF_IP7)
+			do_IRQ(STATUSB_IP7 - STATUSB_IP0);
+		if (cause & CAUSEF_IP2)
+			bcm963xx_irq_dispatch_internal();
+		if (cause & CAUSEF_IP3)
+			do_IRQ(IRQ_EXT_0);
+		if (cause & CAUSEF_IP4)
+			do_IRQ(IRQ_EXT_1);
+		if (cause & CAUSEF_IP5)
+			do_IRQ(IRQ_EXT_2);
+		if (cause & CAUSEF_IP6)
+			do_IRQ(IRQ_EXT_3);
+	} while (1);
+}
+
+/*
+ * internal IRQs operations: only mask/unmask on PERF irq mask
+ * register.
+ */
+static inline void bcm963xx_internal_irq_mask(unsigned int irq)
+{
+	u32 mask;
+
+	irq -= IRQ_INTERNAL_BASE;
+	mask = bcm_perf_readl(PERF_IRQMASK_REG);
+	mask &= ~(1 << irq);
+	bcm_perf_writel(mask, PERF_IRQMASK_REG);
+}
+
+/*
+ * this will have to go when we throw BcmHal* functions to the trash.
+ */
+static void bcm963xx_internal_irq_unmask_force(unsigned int irq)
+{
+	u32 mask;
+
+	irq -= IRQ_INTERNAL_BASE;
+	mask = bcm_perf_readl(PERF_IRQMASK_REG);
+	mask |= (1 << irq);
+	bcm_perf_writel(mask, PERF_IRQMASK_REG);
+}
+
+static void bcm963xx_internal_irq_unmask(unsigned int irq)
+{
+	if (irq_is_mapped(irq))
+		return ;
+	bcm963xx_internal_irq_unmask_force(irq);
+}
+
+/*
+ * XXX: do nothing if irq has been requestd via BcmHalMapInterrupt.
+ */
+static unsigned int bcm963xx_internal_irq_startup(unsigned int irq)
+{
+	if (irq_is_mapped(irq))
+		return 0;
+	bcm963xx_internal_irq_unmask(irq);
+	return 0;
+}
+
+/*
+ * external IRQs operations: mask/unmask and clear on PERF external
+ * irq control register.
+ */
+static void bcm963xx_external_irq_mask(unsigned int irq)
+{
+	u32 reg;
+
+	irq -= IRQ_EXT_BASE;
+	reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG);
+	reg &= ~EXTIRQ_CFG_MASK(irq);
+	bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG);
+}
+
+static void bcm963xx_external_irq_unmask(unsigned int irq)
+{
+	u32 reg;
+
+	irq -= IRQ_EXT_BASE;
+	reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG);
+	reg |= EXTIRQ_CFG_MASK(irq);
+	bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG);
+}
+
+static void bcm963xx_external_irq_clear(unsigned int irq)
+{
+	u32 reg;
+
+	irq -= IRQ_EXT_BASE;
+	reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG);
+	reg |= EXTIRQ_CFG_CLEAR(irq);
+	bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG);
+}
+
+/*
+ * XXX: do nothing if irq has been requestd via BcmHalMapInterrupt.
+ */
+static unsigned int bcm963xx_external_irq_startup(unsigned int irq)
+{
+	if (irq_is_mapped(irq))
+		return 0;
+
+	set_c0_status(0x100 << (irq - IRQ_MIPS_BASE));
+	irq_enable_hazard();
+	bcm963xx_external_irq_unmask(irq);
+	return 0;
+}
+
+static void bcm963xx_external_irq_shutdown(unsigned int irq)
+{
+	bcm963xx_external_irq_mask(irq);
+	clear_c0_status(0x100 << (irq - IRQ_MIPS_BASE));
+	irq_disable_hazard();
+}
+
+/*
+ * concerning external IRQs: the broadcom code in irq.c used to have
+ * the infamous request_external_irq function, setting the external
+ * interrupt by default to level low trigger and keeping it disabled
+ * to allow the caller to set the direction accordingly before
+ * enabling it.
+ *
+ * those days are now hopefully gone. to request an external interrupt
+ * with the new code do:
+ *
+ * set_irq_type(irq, new_flow);
+ * request_irq(irq, ...);
+ *
+ * set_irq_type will call bcm963xx_irq_set_type and set all the flow
+ * for you.
+ */
+static int bcm963xx_external_irq_set_type(unsigned int irq,
+					  unsigned int flow_type)
+{
+	u32 reg;
+	struct irq_desc *desc = irq_desc + irq;
+
+	irq -= IRQ_EXT_BASE;
+
+	flow_type &= IRQ_TYPE_SENSE_MASK;
+
+	if (flow_type == IRQ_TYPE_NONE)
+		flow_type = IRQ_TYPE_LEVEL_LOW;
+
+	reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG);
+	switch (flow_type) {
+	case IRQ_TYPE_EDGE_BOTH:
+		reg &= ~EXTIRQ_CFG_LEVELSENSE(irq);
+		reg |= EXTIRQ_CFG_BOTHEDGE(irq);
+		break;
+
+	case IRQ_TYPE_EDGE_RISING:
+		reg &= ~EXTIRQ_CFG_LEVELSENSE(irq);
+		reg |= EXTIRQ_CFG_SENSE(irq);
+		reg &= ~EXTIRQ_CFG_BOTHEDGE(irq);
+		break;
+
+	case IRQ_TYPE_EDGE_FALLING:
+		reg &= ~EXTIRQ_CFG_LEVELSENSE(irq);
+		reg &= ~EXTIRQ_CFG_SENSE(irq);
+		reg &= ~EXTIRQ_CFG_BOTHEDGE(irq);
+		break;
+
+	case IRQ_TYPE_LEVEL_HIGH:
+		reg |= EXTIRQ_CFG_LEVELSENSE(irq);
+		reg |= EXTIRQ_CFG_SENSE(irq);
+		break;
+
+	case IRQ_TYPE_LEVEL_LOW:
+		reg |= EXTIRQ_CFG_LEVELSENSE(irq);
+		reg &= ~EXTIRQ_CFG_SENSE(irq);
+		break;
+
+	default:
+		printk(KERN_ERR "bogus flow type combination given !\n");
+		return -EINVAL;
+	}
+	bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG);
+
+	if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))  {
+		desc->status |= IRQ_LEVEL;
+		desc->handle_irq = handle_level_irq;
+	} else {
+		desc->handle_irq = handle_edge_irq;
+	}
+
+
+	return 0;
+}
+
+static struct irq_chip bcm963xx_internal_irq_chip = {
+	.name		= "bcm963xx_ipic",
+	.startup	= bcm963xx_internal_irq_startup,
+	.shutdown	= bcm963xx_internal_irq_mask,
+
+	.mask		= bcm963xx_internal_irq_mask,
+	.mask_ack	= bcm963xx_internal_irq_mask,
+	.unmask		= bcm963xx_internal_irq_unmask,
+};
+
+static struct irq_chip bcm963xx_external_irq_chip = {
+	.name		= "bcm963xx_epic",
+	.startup	= bcm963xx_external_irq_startup,
+	.shutdown	= bcm963xx_external_irq_shutdown,
+
+	.ack		= bcm963xx_external_irq_clear,
+
+	.mask		= bcm963xx_external_irq_mask,
+	.unmask		= bcm963xx_external_irq_unmask,
+
+	.set_type	= bcm963xx_external_irq_set_type,
+};
+
+static struct irqaction cpu_ip2_cascade_action = {
+	.handler	= no_action,
+	.name		= "cascade_ip2",
+};
+
+void __init arch_init_irq(void)
+{
+	int i;
+
+	mips_cpu_irq_init(IRQ_MIPS_BASE);
+	for (i = IRQ_INTERNAL_BASE; i < NR_IRQS; ++i)
+		set_irq_chip_and_handler(i, &bcm963xx_internal_irq_chip,
+					 handle_level_irq);
+
+	for (i = IRQ_EXT_BASE; i < IRQ_EXT_BASE + 4; ++i)
+		set_irq_chip_and_handler(i, &bcm963xx_external_irq_chip,
+					 handle_edge_irq);
+
+	setup_irq(IRQ_MIPS_BASE + 2, &cpu_ip2_cascade_action);
+}
+
+/*
+ * broadcom compatibility functions: all broadcom driver expect the
+ * interrupt layer NOT to re-enable the interrupts and rely on the
+ * fact that BcmHalMapInterrupt will NOT enable the interrupt.
+ *
+ * We recognize those interruptions mapped with the bit field
+ * mapped_interrupts_bits. The _end and the _startup functions do
+ * nothing if the irq is mapped.
+ *
+ * FIXME: throw this crap away as soon as possible.
+ */
+unsigned int BcmHalMapInterrupt(irqreturn_t (*pfunc)(int, void*),
+				unsigned int param,
+				unsigned int irq)
+{
+	char *devname;
+
+	BUG_ON(!irq_is_internal(irq));
+
+	devname = kmalloc(16, GFP_KERNEL);
+	if (!devname)
+		return -ENOMEM;
+
+	sprintf(devname, "brcm_%d", irq);
+
+
+	if (irq >= NR_IRQS)
+		return -ENODEV;
+
+	set_bit(irq, mapped_interrupts_bits);
+
+	return request_irq(irq, pfunc, IRQF_SAMPLE_RANDOM,
+			   devname, (void *)param);
+}
+
+void BcmHalInterruptEnable(unsigned int irq)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	bcm963xx_internal_irq_unmask_force(irq);
+	local_irq_restore(flags);
+}
+
+void BcmHalInterruptDisable(unsigned irq)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	bcm963xx_internal_irq_mask(irq);
+	local_irq_restore(flags);
+}
+
+
+EXPORT_SYMBOL(BcmHalMapInterrupt);
+EXPORT_SYMBOL(BcmHalInterruptDisable);
+EXPORT_SYMBOL(BcmHalInterruptEnable);
diff -Nruw linux-2.6.20.14-fbx/arch/mips/bcm963xx./Kconfig linux-2.6.20.14-fbx/arch/mips/bcm963xx/Kconfig
--- linux-2.6.20.14-fbx/arch/mips/bcm963xx./Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/arch/mips/bcm963xx/Kconfig	2011-09-26 15:07:53.868835715 +0200
@@ -0,0 +1,47 @@
+# backward compatible, to remove
+config BCM963xx
+       bool
+config BCM96348
+       bool
+       select BCM963xx
+config BCM96358
+       bool
+       select BCM963xx
+# backward compatible, to remove
+
+menu "CPU support"
+	depends on BCM963XX
+
+config BCM963XX_CPU_6338
+	bool "support 6338 CPU"
+
+config BCM963XX_CPU_6345
+	bool "support 6345 CPU"
+
+config BCM963XX_CPU_6348
+	bool "support 6348 CPU"
+	select HW_HAS_PCI
+	select USB_ARCH_HAS_OHCI
+	select USB_OHCI_BIG_ENDIAN
+	select BCM96348 # to remove
+
+config BCM963XX_CPU_6358
+	bool "support 6358 CPU"
+	select HW_HAS_PCI
+	select USB_ARCH_HAS_OHCI
+	select USB_ARCH_HAS_EHCI
+	select USB_OHCI_BIG_ENDIAN
+	select USB_EHCI_BIG_ENDIAN_MMIO
+	select BCM96358 # to remove
+
+endmenu
+
+config BCM963XX_EARLY_CONSOLE
+	bool "Early console support"
+	depends on BCM963XX
+	help
+	  Provide early console support by direct access to the
+	  on board UART. The UART must have been previously
+	  initialised by the boot loader.
+
+source "arch/mips/bcm963xx/boards/Kconfig"
diff -Nruw linux-2.6.20.14-fbx/arch/mips/bcm963xx./Makefile linux-2.6.20.14-fbx/arch/mips/bcm963xx/Makefile
--- linux-2.6.20.14-fbx/arch/mips/bcm963xx./Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/arch/mips/bcm963xx/Makefile	2011-09-26 15:07:53.868835715 +0200
@@ -0,0 +1,25 @@
+obj-y		+= cpu.o cs.o gpio.o irq.o prom.o setup.o timer.o
+
+obj-$(CONFIG_SMP)			+= smp.o smp-boot.o
+obj-$(CONFIG_BCM963XX_EARLY_CONSOLE)	+= early_console.o
+
+dev-y					+= dev-enet.o
+dev-$(CONFIG_PCMCIA_BCM963XX)		+= dev-pcmcia.o
+dev-$(CONFIG_SERIAL_BCM963XX)		+= dev-uart.o
+dev-$(CONFIG_USB_EHCI_HCD)		+= dev-usb-ehci.o
+dev-$(CONFIG_USB_OHCI_HCD)		+= dev-usb-ohci.o
+#dev-$(CONFIG_BCM963XX_DSL)		+= dev-dsl.o
+dev-$(CONFIG_BCM63XX_FBXATM)		+= dev-fbx-atm.o
+dev-$(CONFIG_FREEBOX_ATM)		+= dev-fbx-atm-legacy.o
+dev-y					+= dev-bcmusb.o
+
+# Freebox private drivers
+dev-y					+= dev-fbx-atm.o
+dev-$(CONFIG_BCM963XX_DMAMUX)		+= dev-fbx-dma.o
+dev-$(CONFIG_FREEBOX_WATCHDOG_BCM963XX)	+= dev-fbx-watchdog.o
+
+obj-y		+= $(dev-y) $(dev-m)
+obj-y		+= boards/
+
+
+EXTRA_CFLAGS    += -I$(TOPDIR)/extdrivers/bcm963xx/bcm_adsl
diff -Nruw linux-2.6.20.14-fbx/arch/mips/bcm963xx./prom.c linux-2.6.20.14-fbx/arch/mips/bcm963xx/prom.c
--- linux-2.6.20.14-fbx/arch/mips/bcm963xx./prom.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/arch/mips/bcm963xx/prom.c	2011-09-26 15:07:53.868835715 +0200
@@ -0,0 +1,81 @@
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <asm/bootinfo.h>
+#include "bcm963xx.h"
+
+static unsigned int bcm963xx_memory_size;
+
+unsigned int bcm963xx_get_memory_size(void)
+{
+	return bcm963xx_memory_size;
+}
+
+/*
+ * attempt to detect the amount of memory installed
+ */
+static unsigned int detect_memory_size(void)
+{
+	unsigned int cols, rows, is_32bits, banks;
+	u32 val;
+
+	if (BCMCPU_IS_6348()) {
+		val = bcm_sdram_readl(SDRAM_CFG_REG);
+		rows = (val & SDRAM_CFG_ROW_MASK) >> SDRAM_CFG_ROW_SHIFT;
+		cols = (val & SDRAM_CFG_COL_MASK) >> SDRAM_CFG_COL_SHIFT;
+		is_32bits = (val & SDRAM_CFG_32B_MASK) ? 1 : 0;
+		banks = (val & SDRAM_CFG_BANK_MASK) ? 2 : 1;
+	} else {
+		/* BCMCPU_IS_6358() */
+		val = bcm_memc_readl(MEMC_CFG_REG);
+		rows = (val & MEMC_CFG_ROW_MASK) >> MEMC_CFG_ROW_SHIFT;
+		cols = (val & MEMC_CFG_COL_MASK) >> MEMC_CFG_COL_SHIFT;
+		is_32bits = (val & MEMC_CFG_32B_MASK) ? 0 : 1;
+		banks = 2;
+	}
+
+	/* 0 => 11 address bits ... 2 => 13 address bits */
+	rows += 11;
+
+	/* 0 => 8 address bits ... 2 => 10 address bits */
+	cols += 8;
+
+	return (1 << (cols + rows + (is_32bits + 1) + banks));
+}
+
+/*
+ * kernel entry point
+ */
+void __init prom_init(void)
+{
+	bcm963xx_cpu_init();
+
+	/* stop any running watchdog */
+	bcm_wdt_writel(WDT_STOP_1, WDT_CTL_REG);
+	bcm_wdt_writel(WDT_STOP_2, WDT_CTL_REG);
+
+#ifdef CONFIG_BCM963XX_EARLY_CONSOLE
+	bcm963xx_register_early_console();
+#endif
+
+#ifdef CONFIG_SMP
+	prom_grab_secondary();
+#endif
+
+	/* compute available system memory and register it */
+	bcm963xx_memory_size = detect_memory_size();
+	printk(KERN_INFO "%uMB of RAM installed\n",
+	       bcm963xx_memory_size >> 20);
+
+	/* call board prom init */
+	board_prom_init();
+
+	/* assign command line from kernel config */
+	strcpy(arcs_cmdline, CONFIG_CMDLINE);
+}
+
+unsigned long __init prom_free_prom_memory(void)
+{
+	return 0;
+}
+
+EXPORT_SYMBOL(bcm963xx_get_memory_size);
diff -Nruw linux-2.6.20.14-fbx/arch/mips/bcm963xx./setup.c linux-2.6.20.14-fbx/arch/mips/bcm963xx/setup.c
--- linux-2.6.20.14-fbx/arch/mips/bcm963xx./setup.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/arch/mips/bcm963xx/setup.c	2011-09-26 15:07:53.868835715 +0200
@@ -0,0 +1,156 @@
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/crash_zone.h>
+#include <linux/bootmem.h>
+#include <asm/bootinfo.h>
+#include <asm/time.h>
+#include <asm/reboot.h>
+#include <asm/cacheflush.h>
+#include "bcm963xx.h"
+
+#define CRASHZONE_SIZE	(16 * 1024)
+
+#ifdef CONFIG_DMCRYPTATBOOT
+#include <asm/mach-bcm963xx/bcm_map_part.h>
+#endif
+
+static void *bcm963xx_dsl_memory;
+
+void *bcm963xx_get_dsl_memory(void)
+{
+	return bcm963xx_dsl_memory;
+}
+
+#if defined(CONFIG_BCM963xx_ADSL) || \
+	defined(CONFIG_BCM963xx_ADSL_MODULE) || \
+	defined(CONFIG_BCM963xx_ADSL_ALT) || \
+	defined(CONFIG_BCM963xx_ADSL_ALT_MODULE)
+#include <softdsl/AdslCoreDefs.h>
+
+unsigned int bcm963xx_get_dsl_memory_size(void)
+{
+	return ADSL_SDRAM_IMAGE_SIZE;
+}
+#else
+unsigned int bcm963xx_get_dsl_memory_size(void)
+{
+	return 0;
+}
+#endif
+
+void bcm963xx_machine_halt(void)
+{
+	printk("System halted\n");
+	while (1);
+}
+
+static void bcm6348_a1_reboot(void)
+{
+	u32 reg;
+
+	/* soft reset all blocks */
+	printk("soft-reseting all blocks ...\n");
+	reg = bcm_perf_readl(PERF_SOFTRESET_REG);
+	reg &= ~SOFTRESET_ALL_BLOCKS;
+	bcm_perf_writel(reg, PERF_SOFTRESET_REG);
+	mdelay(10);
+
+	reg = bcm_perf_readl(PERF_SOFTRESET_REG);
+	reg |= SOFTRESET_ALL_BLOCKS;
+	bcm_perf_writel(reg, PERF_SOFTRESET_REG);
+	mdelay(10);
+
+	/* Jump to the power on address. */
+	printk("jumping to reset vector.\n");
+	/* set high vectors (base at 0xbfc00000 */
+	set_c0_status(ST0_BEV | ST0_ERL);
+	/* run uncached in kseg0 */
+	change_c0_config(CONF_CM_CMASK, CONF_CM_UNCACHED);
+	__flush_cache_all();
+	/* remove all wired TLB entries */
+	write_c0_wired(0);
+	__asm__ __volatile__(
+		"jr\t%0"
+		:
+		: "r" (0xbfc00000));
+	while (1);
+}
+
+void bcm963xx_machine_reboot(void)
+{
+	u32 reg;
+
+	/* mask and clear all external irq */
+	reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG);
+	reg &= ~EXTIRQ_CFG_MASK_ALL;
+	reg |= EXTIRQ_CFG_CLEAR_ALL;
+	bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG);
+
+	if (BCMCPU_IS_6348() && (bcm963xx_get_cpu_rev() == 0xa1))
+		bcm6348_a1_reboot();
+
+	printk("triggering watchdog soft-reset...\n");
+	bcm_perf_writel(SYS_PLL_SOFT_RESET, PERF_SYS_PLL_CTL_REG);
+	while (1);
+}
+
+static void __bcm963xx_machine_reboot(char *p)
+{
+	bcm963xx_machine_reboot();
+}
+
+/*
+ * return system type in /proc/cpuinfo
+ */
+const char *get_system_type(void)
+{
+	static char buf[128];
+	sprintf(buf, "%s (0x%04x/0x%04X)",
+		board_get_name(),
+		bcm963xx_get_cpu_id(), bcm963xx_get_cpu_rev());
+	return buf;
+}
+
+static void __init bcm963xx_time_init(void)
+{
+	mips_hpt_frequency = bcm963xx_get_cpu_freq() / 2;
+}
+
+void __init plat_timer_setup(struct irqaction *irq)
+{
+	setup_irq(STATUSB_IP7 - STATUSB_IP0, irq);
+	set_c0_status(IE_IRQ5);
+}
+
+void __init plat_mem_setup(void)
+{
+	void *alloc_mem;
+
+	/* dsl processor  has to run at  a fixed offset  in memory, we
+	 * can't use bootmem allocator for this, so allocate by hand */
+	alloc_mem = (void *)bcm963xx_get_memory_size();
+
+	alloc_mem -= bcm963xx_get_dsl_memory_size();
+	bcm963xx_dsl_memory = alloc_mem;
+
+#ifdef CONFIG_CRASHZONE
+	alloc_mem -= CRASHZONE_SIZE;
+	crash_zone_set_param((void *)KSEG1ADDR(alloc_mem), CRASHZONE_SIZE);
+#endif
+
+	add_memory_region(0, (unsigned int)alloc_mem, BOOT_MEM_RAM);
+
+	_machine_halt = bcm963xx_machine_halt;
+	_machine_restart = __bcm963xx_machine_reboot;
+	pm_power_off = bcm963xx_machine_halt;
+	board_time_init = bcm963xx_time_init;
+
+	set_io_port_base(0);
+
+#ifdef CONFIG_DMCRYPTATBOOT
+	m2m_tx->srcid = m2m_tx->dstid = 0x10;
+#endif
+
+	board_mem_setup();
+}
diff -Nruw linux-2.6.20.14-fbx/arch/mips/bcm963xx./timer.c linux-2.6.20.14-fbx/arch/mips/bcm963xx/timer.c
--- linux-2.6.20.14-fbx/arch/mips/bcm963xx./timer.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/arch/mips/bcm963xx/timer.c	2011-09-26 15:07:53.868835715 +0200
@@ -0,0 +1,181 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include "bcm963xx.h"
+
+static DEFINE_SPINLOCK(timer_reg_lock);
+static DEFINE_SPINLOCK(timer_data_lock);
+
+static struct timer_data {
+	void	(*cb)(void *);
+	void	*data;
+} timer_data[BCM963XX_TIMER_COUNT];
+
+static irqreturn_t timer_interrupt(int irq, void *dev_id)
+{
+	u32 stat;
+	int i;
+
+	spin_lock(&timer_reg_lock);
+	stat = bcm_timer_readl(TIMER_IRQSTAT_REG);
+	bcm_timer_writel(stat, TIMER_IRQSTAT_REG);
+	spin_unlock(&timer_reg_lock);
+
+	for (i = 0; i < BCM963XX_TIMER_COUNT; i++) {
+		if (!(stat & TIMER_IRQSTAT_TIMER_CAUSE(i)))
+			continue;
+
+		spin_lock(&timer_data_lock);
+		if (!timer_data[i].cb) {
+			spin_unlock(&timer_data_lock);
+			continue;
+		}
+
+		timer_data[i].cb(timer_data[i].data);
+		spin_unlock(&timer_data_lock);
+	}
+
+	return IRQ_HANDLED;
+}
+
+int bcm963xx_timer_enable(int id)
+{
+	u32 reg;
+	unsigned long flags;
+
+	if (id >= BCM963XX_TIMER_COUNT)
+		return -EINVAL;
+
+	spin_lock_irqsave(&timer_reg_lock, flags);
+
+	reg = bcm_timer_readl(TIMER_CTLx_REG(id));
+	reg |= TIMER_CTL_ENABLE_MASK;
+	bcm_timer_writel(reg, TIMER_CTLx_REG(id));
+
+	reg = bcm_timer_readl(TIMER_IRQSTAT_REG);
+	reg |= TIMER_IRQSTAT_TIMER_IR_EN(id);
+	bcm_timer_writel(reg, TIMER_IRQSTAT_REG);
+
+	spin_unlock_irqrestore(&timer_reg_lock, flags);
+	return 0;
+}
+
+int bcm963xx_timer_disable(int id)
+{
+	u32 reg;
+	unsigned long flags;
+
+	if (id >= BCM963XX_TIMER_COUNT)
+		return -EINVAL;
+
+	spin_lock_irqsave(&timer_reg_lock, flags);
+
+	reg = bcm_timer_readl(TIMER_CTLx_REG(id));
+	reg &= ~TIMER_CTL_ENABLE_MASK;
+	bcm_timer_writel(reg, TIMER_CTLx_REG(id));
+
+	reg = bcm_timer_readl(TIMER_IRQSTAT_REG);
+	reg &= ~TIMER_IRQSTAT_TIMER_IR_EN(id);
+	bcm_timer_writel(reg, TIMER_IRQSTAT_REG);
+
+	spin_unlock_irqrestore(&timer_reg_lock, flags);
+	return 0;
+}
+
+int bcm963xx_timer_register(int id, void (*callback)(void *data), void *data)
+{
+	unsigned long flags;
+	int ret;
+
+	if (id >= BCM963XX_TIMER_COUNT || !callback)
+		return -EINVAL;
+
+	ret = 0;
+	spin_lock_irqsave(&timer_data_lock, flags);
+	if (timer_data[id].cb) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	timer_data[id].cb = callback;
+	timer_data[id].data = data;
+
+out:
+	spin_unlock_irqrestore(&timer_data_lock, flags);
+	return ret;
+}
+
+void bcm963xx_timer_unregister(int id)
+{
+	unsigned long flags;
+
+	if (id >= BCM963XX_TIMER_COUNT)
+		return;
+
+	spin_lock_irqsave(&timer_data_lock, flags);
+	timer_data[id].cb = NULL;
+	spin_unlock_irqrestore(&timer_data_lock, flags);
+}
+
+unsigned int bcm963xx_timer_countdown(unsigned int countdown_us)
+{
+	return (BCM963XX_FPERIPH / (1000 * 1000)) * countdown_us;
+}
+
+int bcm963xx_timer_set(int id, int monotonic, unsigned int countdown_us)
+{
+	u32 reg, countdown;
+	unsigned long flags;
+
+	if (id >= BCM963XX_TIMER_COUNT)
+		return -EINVAL;
+
+	countdown = bcm963xx_timer_countdown(countdown_us);
+	if (countdown & ~TIMER_CTL_COUNTDOWN_MASK)
+		return -EINVAL;
+
+	spin_lock_irqsave(&timer_reg_lock, flags);
+	reg = bcm_timer_readl(TIMER_CTLx_REG(id));
+
+	if (monotonic)
+		reg &= ~TIMER_CTL_MONOTONIC_MASK;
+	else
+		reg |= TIMER_CTL_MONOTONIC_MASK;
+
+	reg &= ~TIMER_CTL_COUNTDOWN_MASK;
+	reg |= countdown;
+	bcm_timer_writel(reg, TIMER_CTLx_REG(id));
+
+	spin_unlock_irqrestore(&timer_reg_lock, flags);
+	return 0;
+}
+
+int bcm963xx_timer_init(void)
+{
+	int ret, irq;
+	u32 reg;
+
+	reg = bcm_timer_readl(TIMER_IRQSTAT_REG);
+	reg &= ~TIMER_IRQSTAT_TIMER0_IR_EN;
+	reg &= ~TIMER_IRQSTAT_TIMER1_IR_EN;
+	reg &= ~TIMER_IRQSTAT_TIMER2_IR_EN;
+	bcm_timer_writel(reg, TIMER_IRQSTAT_REG);
+
+	irq = bcm_irq_number(IRQ_TIMER);
+	ret = request_irq(irq, timer_interrupt, 0, "bcm963xx_timer", NULL);
+	if (ret) {
+		printk(KERN_ERR "bcm963xx_timer: failed to register irq\n");
+		return ret;
+	}
+	return 0;
+}
+
+arch_initcall(bcm963xx_timer_init);
+
+EXPORT_SYMBOL(bcm963xx_timer_register);
+EXPORT_SYMBOL(bcm963xx_timer_unregister);
+EXPORT_SYMBOL(bcm963xx_timer_enable);
+EXPORT_SYMBOL(bcm963xx_timer_disable);
+EXPORT_SYMBOL(bcm963xx_timer_set);
+EXPORT_SYMBOL(bcm963xx_timer_countdown);
--- /dev/null	2011-06-03 14:51:38.633053002 +0200
+++ linux-2.6.20.14-fbx/arch/mips/pci/fixup-bcm963xx.c	2011-09-26 15:07:53.908835691 +0200
@@ -0,0 +1,14 @@
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <asm/mach-bcm963xx/bcm963xx_irq.h>
+
+int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+	return bcm_irq_number(IRQ_PCI);
+}
+
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+	return 0;
+}
--- /dev/null	2011-06-03 14:51:38.633053002 +0200
+++ linux-2.6.20.14-fbx/arch/mips/pci/ops-bcm963xx.c	2011-09-26 15:07:53.918835685 +0200
@@ -0,0 +1,461 @@
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+
+#include <asm/mach-bcm963xx/bcm963xx_io.h>
+#include <asm/mach-bcm963xx/bcm963xx_regs.h>
+#include "pci-bcm963xx.h"
+
+/*
+ * swizzle 32bits data to return only the needed part
+ */
+static int postprocess_read(u32 data, int where, unsigned int size)
+{
+	u32 ret;
+
+	ret = 0;
+	switch (size) {
+	case 1:
+		ret = (data >> ((where & 3) << 3)) & 0xff;
+		break;
+	case 2:
+		ret = (data >> ((where & 3) << 3)) & 0xffff;
+		break;
+	case 4:
+		ret = data;
+		break;
+	}
+	return ret;
+}
+
+static int preprocess_write(u32 orig_data, u32 val, int where,
+			    unsigned int size)
+{
+	u32 ret;
+
+	ret = 0;
+	switch (size) {
+	case 1:
+		ret = (orig_data & ~(0xff << ((where & 3) << 3))) |
+			(val << ((where & 3) << 3));
+		break;
+	case 2:
+		ret = (orig_data & ~(0xffff << ((where & 3) << 3))) |
+			(val << ((where & 3) << 3));
+		break;
+	case 4:
+		ret = val;
+		break;
+	}
+	return ret;
+}
+
+/*
+ * setup hardware for a configuration cycle with given parameters
+ */
+static int bcm963xx_setup_cfg_access(int type, unsigned int busn,
+				     unsigned int devfn, int where)
+{
+	unsigned int slot, func, reg;
+	u32 val;
+
+	slot = PCI_SLOT(devfn);
+	func = PCI_FUNC(devfn);
+	reg = where >> 2;
+
+	/* sanity check */
+	if (slot > (MPI_L2PCFG_DEVNUM_MASK >> MPI_L2PCFG_DEVNUM_SHIFT))
+		return 1;
+
+	if (func > (MPI_L2PCFG_FUNC_MASK >> MPI_L2PCFG_FUNC_SHIFT))
+		return 1;
+
+	if (reg > (MPI_L2PCFG_REG_MASK >> MPI_L2PCFG_REG_SHIFT))
+		return 1;
+
+	/* ok, setup config access */
+	val = (reg << MPI_L2PCFG_REG_SHIFT);
+	val |= (func << MPI_L2PCFG_FUNC_SHIFT);
+	val |= (slot << MPI_L2PCFG_DEVNUM_SHIFT);
+	val |= MPI_L2PCFG_CFG_USEREG_MASK;
+	val |= MPI_L2PCFG_CFG_SEL_MASK;
+	/* type 0 cycle for local bus, type 1 cycle for anything else */
+	if (type != 0) {
+		/* FIXME: how to specify bus ??? */
+		val |= (1 << MPI_L2PCFG_CFG_TYPE_SHIFT);
+	}
+	bcm_mpi_writel(val, MPI_L2PCFG_REG);
+
+	return 0;
+}
+
+static int bcm963xx_do_cfg_read(int type, unsigned int busn,
+				unsigned int devfn, int where, int size,
+				u32 *val)
+{
+	u32 data;
+
+	/* two phase cycle, first we write address, then read data at
+	 * another location, caller already has a spinlock so no need
+	 * to add one here  */
+	if (bcm963xx_setup_cfg_access(type, busn, devfn, where))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	iob();
+	data = le32_to_cpu(__raw_readl(pci_iospace_start));
+	/* restore IO space normal behaviour */
+	bcm_mpi_writel(0, MPI_L2PCFG_REG);
+
+	*val = postprocess_read(data, where, size);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int bcm963xx_do_cfg_write(int type, unsigned int busn,
+				 unsigned int devfn, int where, int size,
+				 u32 val)
+{
+	u32 data;
+
+	/* two phase cycle, first we write address, then write data to
+	 * another location, caller already has a spinlock so no need
+	 * to add one here  */
+	if (bcm963xx_setup_cfg_access(type, busn, devfn, where))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	iob();
+
+	data = le32_to_cpu(__raw_readl(pci_iospace_start));
+	data = preprocess_write(data, val, where, size);
+
+	__raw_writel(cpu_to_le32(data), pci_iospace_start);
+	wmb();
+	/* no way to know the access is done, we have to wait */
+	udelay(500);
+	/* restore IO space normal behaviour */
+	bcm_mpi_writel(0, MPI_L2PCFG_REG);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int bcm963xx_pci_read(struct pci_bus *bus, unsigned int devfn,
+			     int where, int size, u32 *val)
+{
+	int type;
+
+	type = bus->parent ? 1 : 0;
+
+	if (type == 0 && PCI_SLOT(devfn) == CARDBUS_PCI_IDSEL)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	return bcm963xx_do_cfg_read(type, bus->number, devfn,
+				    where, size, val);
+}
+
+static int bcm963xx_pci_write(struct pci_bus *bus, unsigned int devfn,
+			      int where, int size, u32 val)
+{
+	int type;
+
+	type = bus->parent ? 1 : 0;
+
+	if (type == 0 && PCI_SLOT(devfn) == CARDBUS_PCI_IDSEL)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	return bcm963xx_do_cfg_write(type, bus->number, devfn,
+				     where, size, val);
+}
+
+struct pci_ops bcm963xx_pci_ops = {
+	.read   = bcm963xx_pci_read,
+	.write  = bcm963xx_pci_write
+};
+
+#ifdef CONFIG_CARDBUS
+/*
+ * emulate configuration read access on a cardbus bridge
+ */
+#define FAKE_CB_BRIDGE_SLOT	0x1e
+
+static int fake_cb_bridge_bus_number = -1;
+
+static struct {
+	u16 pci_command;
+	u8 cb_latency;
+	u8 subordinate_busn;
+	u8 cardbus_busn;
+	u8 pci_busn;
+	int bus_assigned;
+	u16 bridge_control;
+
+	u32 mem_base0;
+	u32 mem_limit0;
+	u32 mem_base1;
+	u32 mem_limit1;
+
+	u32 io_base0;
+	u32 io_limit0;
+	u32 io_base1;
+	u32 io_limit1;
+} fake_cb_bridge_regs;
+
+static int fake_cb_bridge_read(int where, int size, u32 *val)
+{
+	unsigned int reg;
+	u32 data;
+
+	data = 0;
+	reg = where >> 2;
+	switch (reg) {
+	case (PCI_VENDOR_ID >> 2):
+	case (PCI_CB_SUBSYSTEM_VENDOR_ID >> 2):
+		/* create dummy vendor/device id from our cpu id */
+		data = (bcm963xx_get_cpu_id() << 16) | PCI_VENDOR_ID_BROADCOM;
+		break;
+
+	case (PCI_COMMAND >> 2):
+		data = (PCI_STATUS_DEVSEL_SLOW << 16);
+		data |= fake_cb_bridge_regs.pci_command;
+		break;
+
+	case (PCI_CLASS_REVISION >> 2):
+		data = (PCI_CLASS_BRIDGE_CARDBUS << 16);
+		break;
+
+	case (PCI_CACHE_LINE_SIZE >> 2):
+		data = (PCI_HEADER_TYPE_CARDBUS << 16);
+		break;
+
+	case (PCI_INTERRUPT_LINE >> 2):
+		/* bridge control */
+		data = (fake_cb_bridge_regs.bridge_control << 16);
+		/* pin:intA line:0xff */
+		data |= (0x1 << 8) | 0xff;
+		break;
+
+	case (PCI_CB_PRIMARY_BUS >> 2):
+		data = (fake_cb_bridge_regs.cb_latency << 24);
+		data |= (fake_cb_bridge_regs.subordinate_busn << 16);
+		data |= (fake_cb_bridge_regs.cardbus_busn << 8);
+		data |= fake_cb_bridge_regs.pci_busn;
+		break;
+
+	case (PCI_CB_MEMORY_BASE_0 >> 2):
+		data = fake_cb_bridge_regs.mem_base0;
+		break;
+
+	case (PCI_CB_MEMORY_LIMIT_0 >> 2):
+		data = fake_cb_bridge_regs.mem_limit0;
+		break;
+
+	case (PCI_CB_MEMORY_BASE_1 >> 2):
+		data = fake_cb_bridge_regs.mem_base1;
+		break;
+
+	case (PCI_CB_MEMORY_LIMIT_1 >> 2):
+		data = fake_cb_bridge_regs.mem_limit1;
+		break;
+
+	case (PCI_CB_IO_BASE_0 >> 2):
+		/* | 1 for 32bits io support */
+		data = fake_cb_bridge_regs.io_base0 | 0x1;
+		break;
+
+	case (PCI_CB_IO_LIMIT_0 >> 2):
+		data = fake_cb_bridge_regs.io_limit0;
+		break;
+
+	case (PCI_CB_IO_BASE_1 >> 2):
+		/* | 1 for 32bits io support */
+		data = fake_cb_bridge_regs.io_base1 | 0x1;
+		break;
+
+	case (PCI_CB_IO_LIMIT_1 >> 2):
+		data = fake_cb_bridge_regs.io_limit1;
+		break;
+	}
+
+	*val = postprocess_read(data, where, size);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+/*
+ * emulate configuration write access on a cardbus bridge
+ */
+static int fake_cb_bridge_write(int where, int size, u32 val)
+{
+	unsigned int reg;
+	u32 data, tmp;
+	int ret;
+
+	ret = fake_cb_bridge_read((where & ~0x3), 4, &data);
+	if (ret != PCIBIOS_SUCCESSFUL)
+		return ret;
+
+	data = preprocess_write(data, val, where, size);
+
+	reg = where >> 2;
+	switch (reg) {
+	case (PCI_COMMAND >> 2):
+		fake_cb_bridge_regs.pci_command = (data & 0xffff);
+		break;
+
+	case (PCI_CB_PRIMARY_BUS >> 2):
+		fake_cb_bridge_regs.cb_latency = (data >> 24) & 0xff;
+		fake_cb_bridge_regs.subordinate_busn = (data >> 16) & 0xff;
+		fake_cb_bridge_regs.cardbus_busn = (data >> 8) & 0xff;
+		fake_cb_bridge_regs.pci_busn = data & 0xff;
+		if (fake_cb_bridge_regs.cardbus_busn)
+			fake_cb_bridge_regs.bus_assigned = 1;
+		break;
+
+	case (PCI_INTERRUPT_LINE >> 2):
+		tmp = (data >> 16) & 0xffff;
+		/* disable memory prefetch support */
+		tmp &= ~PCI_CB_BRIDGE_CTL_PREFETCH_MEM0;
+		tmp &= ~PCI_CB_BRIDGE_CTL_PREFETCH_MEM1;
+		fake_cb_bridge_regs.bridge_control = tmp;
+		break;
+
+	case (PCI_CB_MEMORY_BASE_0 >> 2):
+		fake_cb_bridge_regs.mem_base0 = data;
+		break;
+
+	case (PCI_CB_MEMORY_LIMIT_0 >> 2):
+		fake_cb_bridge_regs.mem_limit0 = data;
+		break;
+
+	case (PCI_CB_MEMORY_BASE_1 >> 2):
+		fake_cb_bridge_regs.mem_base1 = data;
+		break;
+
+	case (PCI_CB_MEMORY_LIMIT_1 >> 2):
+		fake_cb_bridge_regs.mem_limit1 = data;
+		break;
+
+	case (PCI_CB_IO_BASE_0 >> 2):
+		fake_cb_bridge_regs.io_base0 = data;
+		break;
+
+	case (PCI_CB_IO_LIMIT_0 >> 2):
+		fake_cb_bridge_regs.io_limit0 = data;
+		break;
+
+	case (PCI_CB_IO_BASE_1 >> 2):
+		fake_cb_bridge_regs.io_base1 = data;
+		break;
+
+	case (PCI_CB_IO_LIMIT_1 >> 2):
+		fake_cb_bridge_regs.io_limit1 = data;
+		break;
+	}
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int bcm963xx_cb_read(struct pci_bus *bus, unsigned int devfn,
+			    int where, int size, u32 *val)
+{
+	/* snoop access to slot 0x1e on root bus, we fake a cardbus
+	 * bridge at this location */
+	if (!bus->parent && PCI_SLOT(devfn) == FAKE_CB_BRIDGE_SLOT) {
+		fake_cb_bridge_bus_number = bus->number;
+		return fake_cb_bridge_read(where, size, val);
+	}
+
+	/* a  configuration  cycle for  the  device  behind the  cardbus
+	 * bridge is  actually done as a  type 0 cycle  on the primary
+	 * bus. This means that only  one device can be on the cardbus
+	 * bus */
+	if (fake_cb_bridge_regs.bus_assigned &&
+	    bus->number == fake_cb_bridge_regs.cardbus_busn &&
+	    PCI_SLOT(devfn) == 0)
+		return bcm963xx_do_cfg_read(0, 0,
+					    PCI_DEVFN(CARDBUS_PCI_IDSEL, 0),
+					    where, size, val);
+
+	return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+static int bcm963xx_cb_write(struct pci_bus *bus, unsigned int devfn,
+			     int where, int size, u32 val)
+{
+	if (!bus->parent && PCI_SLOT(devfn) == FAKE_CB_BRIDGE_SLOT) {
+		fake_cb_bridge_bus_number = bus->number;
+		return fake_cb_bridge_write(where, size, val);
+	}
+
+	if (fake_cb_bridge_regs.bus_assigned &&
+	    bus->number == fake_cb_bridge_regs.cardbus_busn &&
+	    PCI_SLOT(devfn) == 0)
+		return bcm963xx_do_cfg_write(0, 0,
+					     PCI_DEVFN(CARDBUS_PCI_IDSEL, 0),
+					     where, size, val);
+
+	return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+struct pci_ops bcm963xx_cb_ops = {
+	.read   = bcm963xx_cb_read,
+	.write   = bcm963xx_cb_write,
+};
+
+/*
+ * only one IO window, so it  cannot be shared by PCI and cardbus, use
+ * fixup to choose and detect unhandled configuration
+ */
+static void bcm63xx_fixup(struct pci_dev *dev)
+{
+	static int io_window = -1;
+	int i, found, new_io_window;
+	u32 val;
+
+	/* look for any io resource */
+	found = 0;
+	for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+		if (pci_resource_flags(dev, i) & IORESOURCE_IO) {
+			found = 1;
+			break;
+		}
+	}
+
+	if (!found)
+		return;
+
+	/* skip our fake bus with only cardbus bridge on it */
+	if (dev->bus->number == fake_cb_bridge_bus_number)
+		return;
+
+	/* find on which bus the device is */
+	if (fake_cb_bridge_regs.bus_assigned &&
+	    dev->bus->number == fake_cb_bridge_regs.cardbus_busn &&
+	    PCI_SLOT(dev->devfn) == 0)
+		new_io_window = 1;
+	else
+		new_io_window = 0;
+
+	if (new_io_window == io_window)
+		return;
+
+	if (io_window != -1) {
+		printk(KERN_ERR "bcm963xx: both PCI and cardbus devices "
+		       "need IO, which hardware cannot do\n");
+		return;
+	}
+
+	printk(KERN_INFO "bcm963xx: PCI IO window assigned to %s\n",
+	       (new_io_window == 0) ? "PCI" : "cardbus");
+
+	val = bcm_mpi_readl(MPI_L2PIOREMAP_REG);
+	if (io_window)
+		val |= MPI_L2PREMAP_IS_CARDBUS_MASK;
+	else
+		val &= ~MPI_L2PREMAP_IS_CARDBUS_MASK;
+	bcm_mpi_writel(val, MPI_L2PIOREMAP_REG);
+
+	io_window = new_io_window;
+}
+
+DECLARE_PCI_FIXUP_ENABLE(PCI_ANY_ID, PCI_ANY_ID, bcm63xx_fixup);
+#endif
--- /dev/null	2011-06-03 14:51:38.633053002 +0200
+++ linux-2.6.20.14-fbx/arch/mips/pci/pci-bcm963xx.c	2011-09-26 15:07:53.918835685 +0200
@@ -0,0 +1,208 @@
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <asm/bootinfo.h>
+#include <asm/mach-bcm963xx/bcm963xx_io.h>
+#include <asm/mach-bcm963xx/bcm963xx_regs.h>
+
+#include "pci-bcm963xx.h"
+
+static struct resource bcm_pci_mem_resource = {
+	.name   = "bcm963xx PCI memory space",
+	.start  = BCM_PCI_MEM_BASE_PA,
+	.end    = BCM_PCI_MEM_END_PA,
+	.flags  = IORESOURCE_MEM
+};
+
+static struct resource bcm_pci_io_resource = {
+	.name   = "bcm963xx PCI IO space",
+	.start  = BCM_PCI_IO_BASE_PA,
+#ifdef CONFIG_CARDBUS
+	.end    = BCM_PCI_IO_HALF_PA,
+#else
+	.end    = BCM_PCI_IO_END_PA,
+#endif
+	.flags  = IORESOURCE_IO
+};
+
+struct pci_controller bcm963xx_controller = {
+	.pci_ops	= &bcm963xx_pci_ops,
+	.io_resource	= &bcm_pci_io_resource,
+	.mem_resource	= &bcm_pci_mem_resource,
+};
+
+/*
+ * We handle cardbus  via a fake Cardbus bridge,  memory and io spaces
+ * have to be  clearly separated from PCI one  since we have different
+ * memory decoder.
+ */
+#ifdef CONFIG_CARDBUS
+static struct resource bcm_cb_mem_resource = {
+	.name   = "bcm963xx Cardbus memory space",
+	.start  = BCM_CB_MEM_BASE_PA,
+	.end    = BCM_CB_MEM_END_PA,
+	.flags  = IORESOURCE_MEM
+};
+
+static struct resource bcm_cb_io_resource = {
+	.name   = "bcm963xx Cardbus IO space",
+	.start  = BCM_PCI_IO_HALF_PA + 1,
+	.end    = BCM_PCI_IO_END_PA,
+	.flags  = IORESOURCE_IO
+};
+
+struct pci_controller bcm963xx_cb_controller = {
+	.pci_ops	= &bcm963xx_cb_ops,
+	.io_resource	= &bcm_cb_io_resource,
+	.mem_resource	= &bcm_cb_mem_resource,
+};
+#endif
+
+static u32 bcm963xx_int_cfg_readl(u32 reg)
+{
+	u32 tmp;
+
+	tmp = reg & MPI_PCICFGCTL_CFGADDR_MASK;
+	tmp |= MPI_PCICFGCTL_WRITEEN_MASK;
+	bcm_mpi_writel(tmp, MPI_PCICFGCTL_REG);
+	iob();
+	return bcm_mpi_readl(MPI_PCICFGDATA_REG);
+}
+
+static void bcm963xx_int_cfg_writel(u32 val, u32 reg)
+{
+	u32 tmp;
+
+	tmp = reg & MPI_PCICFGCTL_CFGADDR_MASK;
+	tmp |=  MPI_PCICFGCTL_WRITEEN_MASK;
+	bcm_mpi_writel(tmp, MPI_PCICFGCTL_REG);
+	bcm_mpi_writel(val, MPI_PCICFGDATA_REG);
+}
+
+void __iomem *pci_iospace_start;
+
+static int __init bcm963xx_pci_init(void)
+{
+	unsigned int mem_size;
+	u32 val;
+
+	if (!BCMCPU_IS_6348() && !BCMCPU_IS_6358())
+		return -ENODEV;
+
+	/*
+	 * configuration  access are  done through  IO space,  remap 4
+	 * first bytes to access it from CPU.
+	 *
+	 * this means that  no io access from CPU  should happen while
+	 * we do a configuration cycle,  but there's no way we can add
+	 * a spinlock for each io access, so this is currently kind of
+	 * broken on SMP.
+	 */
+	pci_iospace_start = ioremap_nocache(BCM_PCI_IO_BASE_PA, 4);
+	if (!pci_iospace_start)
+		return -ENOMEM;
+
+	/* setup local bus to PCI access (PCI memory) */
+	val = BCM_PCI_MEM_BASE_PA & MPI_L2P_BASE_MASK;
+	bcm_mpi_writel(val, MPI_L2PMEMBASE1_REG);
+	bcm_mpi_writel(~(BCM_PCI_MEM_SIZE - 1), MPI_L2PMEMRANGE1_REG);
+	bcm_mpi_writel(val | MPI_L2PREMAP_ENABLED_MASK, MPI_L2PMEMREMAP1_REG);
+
+	/* set Cardbus IDSEL (type 0 cfg access on primary bus for
+	 * this IDSEL will be done on Cardbus instead) */
+	val = bcm_pcmcia_readl(PCMCIA_C1_REG);
+	val &= ~PCMCIA_C1_CBIDSEL_MASK;
+	val |= (CARDBUS_PCI_IDSEL << PCMCIA_C1_CBIDSEL_SHIFT);
+	bcm_pcmcia_writel(val, PCMCIA_C1_REG);
+
+#ifdef CONFIG_CARDBUS
+	/* setup local bus to PCI access (Cardbus memory) */
+	val = BCM_CB_MEM_BASE_PA & MPI_L2P_BASE_MASK;
+	bcm_mpi_writel(val, MPI_L2PMEMBASE2_REG);
+	bcm_mpi_writel(~(BCM_CB_MEM_SIZE - 1), MPI_L2PMEMRANGE2_REG);
+	val |= MPI_L2PREMAP_ENABLED_MASK | MPI_L2PREMAP_IS_CARDBUS_MASK;
+	bcm_mpi_writel(val, MPI_L2PMEMREMAP2_REG);
+#else
+	/* disable second access windows */
+	bcm_mpi_writel(0, MPI_L2PMEMREMAP2_REG);
+#endif
+
+	/* setup local bus  to PCI access (IO memory),  we have only 1
+	 * IO window  for both PCI  and cardbus, but it  cannot handle
+	 * both  at the  same time,  assume standard  PCI for  now, if
+	 * cardbus card has  IO zone, PCI fixup will  change window to
+	 * cardbus */
+	val = BCM_PCI_IO_BASE_PA & MPI_L2P_BASE_MASK;
+	bcm_mpi_writel(val, MPI_L2PIOBASE_REG);
+	bcm_mpi_writel(~(BCM_PCI_IO_SIZE - 1), MPI_L2PIORANGE_REG);
+	bcm_mpi_writel(val | MPI_L2PREMAP_ENABLED_MASK, MPI_L2PIOREMAP_REG);
+
+	/* enable PCI related GPIO pins */
+	bcm_mpi_writel(MPI_LOCBUSCTL_EN_PCI_GPIO_MASK, MPI_LOCBUSCTL_REG);
+
+	/* setup PCI to local bus access, used by PCI device to target
+	 * local RAM while bus mastering */
+	bcm963xx_int_cfg_writel(0, PCI_BASE_ADDRESS_3);
+	if (BCMCPU_IS_6358())
+		val = MPI_SP0_REMAP_ENABLE_MASK;
+	else
+		val = 0;
+	bcm_mpi_writel(val, MPI_SP0_REMAP_REG);
+
+	bcm963xx_int_cfg_writel(0x0, PCI_BASE_ADDRESS_4);
+	bcm_mpi_writel(0, MPI_SP1_REMAP_REG);
+
+	mem_size = bcm963xx_get_memory_size();
+
+	/* 6348 before rev b0 exposes only 16 MB of RAM memory through
+	 * PCI, throw a warning if we have more memory */
+	if (BCMCPU_IS_6348() && (bcm963xx_get_cpu_rev() & 0xf0) == 0xa0) {
+		if (mem_size > (16 * 1024 * 1024))
+			printk(KERN_WARNING "bcm963xx: this CPU "
+			       "revision cannot handle more than 16MB "
+			       "of RAM for PCI bus mastering\n");
+	} else {
+		/* setup sp0 range to local RAM size */
+		bcm_mpi_writel(~(mem_size - 1), MPI_SP0_RANGE_REG);
+		bcm_mpi_writel(0, MPI_SP1_RANGE_REG);
+	}
+
+	/* change  host bridge  retry  counter to  infinite number  of
+	 * retry,  needed for  some broadcom  wifi cards  with Silicon
+	 * Backplane bus where access to srom seems very slow  */
+	val = bcm963xx_int_cfg_readl(BCMPCI_REG_TIMERS);
+	val &= ~REG_TIMER_RETRY_MASK;
+	bcm963xx_int_cfg_writel(val, BCMPCI_REG_TIMERS);
+
+	/* enable memory decoder and bus mastering */
+	val = bcm963xx_int_cfg_readl(PCI_COMMAND);
+	val |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+	bcm963xx_int_cfg_writel(val, PCI_COMMAND);
+
+	/* enable read prefetching & disable byte swapping for bus
+	 * mastering transfers */
+	val = bcm_mpi_readl(MPI_PCIMODESEL_REG);
+	val &= ~MPI_PCIMODESEL_BAR1_NOSWAP_MASK;
+	val &= ~MPI_PCIMODESEL_BAR2_NOSWAP_MASK;
+	val &= ~MPI_PCIMODESEL_PREFETCH_MASK;
+	val |= (8 << MPI_PCIMODESEL_PREFETCH_SHIFT);
+	bcm_mpi_writel(val, MPI_PCIMODESEL_REG);
+
+	/* enable pci interrupt */
+	val = bcm_mpi_readl(MPI_LOCINT_REG);
+	val |= MPI_LOCINT_MASK(MPI_LOCINT_EXT_PCI_INT);
+	bcm_mpi_writel(val, MPI_LOCINT_REG);
+
+	ioport_resource.start = BCM_PCI_IO_BASE_PA;
+	ioport_resource.end = BCM_PCI_IO_END_PA;
+
+	register_pci_controller(&bcm963xx_controller);
+
+#ifdef CONFIG_CARDBUS
+	register_pci_controller(&bcm963xx_cb_controller);
+#endif
+	return 0;
+}
+
+arch_initcall(bcm963xx_pci_init);
--- /dev/null	2011-06-03 14:51:38.633053002 +0200
+++ linux-2.6.20.14-fbx/arch/mips/pci/pci-bcm963xx.h	2011-09-26 15:07:53.918835685 +0200
@@ -0,0 +1,27 @@
+#ifndef PCI_BCM963XX_H_
+#define PCI_BCM963XX_H_
+
+#include <asm/mach-bcm963xx/bcm963xx_cpu.h>
+
+/*
+ * Cardbus shares  the PCI bus, but has  no IDSEL, so a  special id is
+ * reserved for it.  If you have a standard PCI device at this id, you
+ * need to change the following definition.
+ */
+#define CARDBUS_PCI_IDSEL	0x8
+
+/* FIXME: make a standard header for these */
+int bcm963xx_get_memory_size(void);
+
+/*
+ * defined in ops-bcm963xx.c
+ */
+extern struct pci_ops bcm963xx_pci_ops;
+extern struct pci_ops bcm963xx_cb_ops;
+
+/*
+ * defined in pci-bcm963xx.c
+ */
+extern void __iomem *pci_iospace_start;
+
+#endif /* ! PCI_BCM963XX_H_ */
diff -Nruw linux-2.6.20.14-fbx/arch/mips/tango2./Kconfig linux-2.6.20.14-fbx/arch/mips/tango2/Kconfig
--- linux-2.6.20.14-fbx/arch/mips/tango2./Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/arch/mips/tango2/Kconfig	2011-09-26 15:07:53.928835679 +0200
@@ -0,0 +1,221 @@
+
+#
+# chip revision selection
+#
+choice
+	prompt "SMP863x chip revision"
+	depends on TANGO2
+	default TANGO2_ES6
+
+config TANGO2_ES1
+	bool "ES1"
+
+config TANGO2_ES2
+	bool "ES2"
+
+config TANGO2_ES3
+	bool "ES3"
+
+config TANGO2_ES4
+	bool "ES4"
+
+config TANGO2_ES5
+	bool "ES5"
+
+config TANGO2_ES6
+	bool "ES6"
+
+endchoice
+
+
+# Boards based on sigma designs 8634
+choice
+	prompt "SMP8634 target Board"
+	depends on TANGO2
+
+config ARCH_FBX5_B
+	bool "Freebox v5b"
+
+endchoice
+
+
+config TANGO2_SYSTEMRAM_ACTUALSIZE
+	int "System RAM size (in MB)"
+	depends on TANGO2
+	default 32
+	help
+	 This is the amount of RAM available to the Linux kernel. This
+	 will only be used if we can't fetch it from memcfg_t.
+
+config TANGO2_IGNORE_CMDLINE
+	bool "Ignore YAMON, XENV & memcfg command line"
+	depends on TANGO2
+	default n
+	help
+	 If you say  yes, boot command line from  YAMON, XENV & memcfg
+	 will be ignored. You can then use CONFIG_CMDLINE to force the
+	 kernel command line.
+
+config TANGO2_PROM_CONSOLE
+	bool "Register an early console"
+	depends on TANGO2
+	default n
+	help
+	 If you say yes, an light console will be available very early
+	 in the  boot process,  this is useful  if the  kernel crashes
+	 before reaching  the main console  code. The console  will be
+	 automatically replaced by the normal one after.
+	 ### NOTE: This console can only do output ###
+
+#
+# XENV stuffs
+#
+config TANGO2_XENV_READ
+	bool "Read config from XENV"
+	depends on TANGO2
+	default y
+	help
+	 If you  say yes  here, board configuration  (enabled devices,
+	 pci irq routing,  ...) will be read from  xenv space.
+
+config TANGO2_XENV_DUMP
+	bool "Dump XENV content at boot"
+	depends on TANGO2_XENV_READ
+	default n
+
+config TANGO2_XENV_READ_SAFE
+	bool "Don't boot if XENV invalid"
+	depends on TANGO2_XENV_READ
+	default n
+	help
+	 If you say yes here and XENV content is invalid, linux wont boot.
+
+
+menu "XENV failsafe/override values"
+	depends on TANGO2
+
+config TANGO2_XENV_DEF_CS0_SIZE
+	hex "CS0 size (flash0)"
+	default 0
+
+config TANGO2_XENV_DEF_CS1_SIZE
+	hex "CS1 size (flash1)"
+	default 0
+
+config TANGO2_XENV_DEF_CS2_SIZE
+	hex "CS2 size (flash2)"
+	default 0x0
+
+config TANGO2_XENV_DEF_CS3_SIZE
+	hex "CS3 size (flash3)"
+	default 0
+
+config TANGO2_XENV_DEF_UART0
+	int "UART0 enabled"
+	default 0
+
+config TANGO2_XENV_DEF_UART1
+	int "UART1 enabled"
+	default 0
+
+config TANGO2_XENV_DEF_BAUDRATE
+	int "Default baudrate"
+	default 115200
+
+config TANGO2_XENV_DEF_ENET
+	int "Ethernet enabled"
+	default 0
+
+config TANGO2_XENV_DEF_FIP
+	int "FIP enabled"
+	default 0
+
+config TANGO2_XENV_DEF_I2CM
+	int "I2CM enabled"
+	default 0
+
+config TANGO2_XENV_DEF_I2CS
+	int "I2CS enabled"
+	default 0
+
+config TANGO2_XENV_DEF_BMIDE
+	int "IDE BM controller enabled"
+	default 0
+
+config TANGO2_XENV_DEF_IR
+	int "IR enabled"
+	default 0
+
+config TANGO2_XENV_DEF_PCIHOST
+	int "PCI Host enabled"
+	default 0
+
+config TANGO2_XENV_DEF_PCI_ID1
+	int "PCI device 1 enabled"
+	default 0
+
+config TANGO2_XENV_DEF_PCI_ID1_IRQ
+	hex "PCI device 1 IRQ route"
+	default 0x0
+
+config TANGO2_XENV_DEF_PCI_ID2
+	int "PCI device 2 enabled"
+	default 0
+
+config TANGO2_XENV_DEF_PCI_ID2_IRQ
+	hex "PCI device 2 IRQ route"
+	default 0x0
+
+config TANGO2_XENV_DEF_PCI_ID3
+	int "PCI device 3 enabled"
+	default 0
+
+config TANGO2_XENV_DEF_PCI_ID3_IRQ
+	hex "PCI device 3 IRQ route"
+	default 0x0
+
+config TANGO2_XENV_DEF_PCI_ID4
+	int "PCI device 4 enabled"
+	default 0
+
+config TANGO2_XENV_DEF_PCI_ID4_IRQ
+	hex "PCI device 4 IRQ route"
+	default 0x0
+
+config TANGO2_XENV_DEF_USB
+	int "USB enabled"
+	default 0
+
+endmenu
+
+#
+# Tango 2 XENV flash mapping
+#
+comment "Tango2 XENV partition table loading options"
+	depends on TANGO2
+
+config TANGO2_FLASH_XENV
+	bool "Generate fbxmtd platform partition table using XENV data."
+	depends on TANGO2
+	default y
+
+config TANGO2_FLASH_XENV_WIDTH
+	int "Device bus width (8^n bits)"
+	default 2
+	depends on TANGO2_FLASH_XENV
+
+config TANGO2_FLASH_XENV_ALL_RW
+	bool "Make all partition RW"
+	default n
+	depends on TANGO2_FLASH_XENV
+
+config TANGO2_FLASH_XENV_CRC
+	bool "Check imagetag CRC"
+	default y
+	select CRC32
+	depends on TANGO2_FLASH_XENV && ARCH_FBX5_B
+
+config TANGO2_FLASH_XENV_READ_BANK1_TAG
+	bool "Read BANK1 tag"
+	default y
+	depends on TANGO2_FLASH_XENV && ARCH_FBX5_B
diff -Nruw linux-2.6.20.14-fbx/arch/mips/tango2./Makefile linux-2.6.20.14-fbx/arch/mips/tango2/Makefile
--- linux-2.6.20.14-fbx/arch/mips/tango2./Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/arch/mips/tango2/Makefile	2011-09-26 15:07:53.928835679 +0200
@@ -0,0 +1,15 @@
+#
+# Makefile for SigmaDesigns Tango2 board
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+
+obj-y += irq.o setup.o prom.o gbus.o gpio.o xenv_config.o mbus.o
+
+obj-$(CONFIG_TANGO2_PROM_CONSOLE) += console.o
+
+obj-$(CONFIG_TANGO2_XENV_READ) += sha1.o xenv.o
+
+obj-$(CONFIG_TANGO2_FLASH_XENV) += flash-xenv.o
--- /dev/null	2011-06-03 14:51:38.633053002 +0200
+++ linux-2.6.20.14-fbx/config	2011-09-26 15:19:45.568399713 +0200
@@ -0,0 +1,1393 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.20.14
+# Mon Sep 26 15:19:13 2011
+#
+CONFIG_MIPS=y
+
+#
+# Machine selection
+#
+# CONFIG_TANGO2 is not set
+# CONFIG_MIPS_MTX1 is not set
+# CONFIG_MIPS_BOSPORUS is not set
+# CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
+# CONFIG_MIPS_PB1500 is not set
+# CONFIG_MIPS_PB1550 is not set
+# CONFIG_MIPS_PB1200 is not set
+# CONFIG_MIPS_DB1000 is not set
+# CONFIG_MIPS_DB1100 is not set
+# CONFIG_MIPS_DB1500 is not set
+# CONFIG_MIPS_DB1550 is not set
+# CONFIG_MIPS_DB1200 is not set
+# CONFIG_MIPS_MIRAGE is not set
+# CONFIG_BASLER_EXCITE is not set
+CONFIG_BCM963XX=y
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MIPS_EV64120 is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_LASAT is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_WR_PPMC is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_MOMENCO_JAGUAR_ATX is not set
+# CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_3 is not set
+# CONFIG_MOMENCO_OCELOT_C is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
+# CONFIG_MIPS_XXS1500 is not set
+# CONFIG_PNX8550_V2PCI is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_PNX8550_STB810 is not set
+# CONFIG_DDB5477 is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_QEMU is not set
+# CONFIG_MARKEINS is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_PTSWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SNI_RM is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_TOSHIBA_RBTX4927 is not set
+# CONFIG_TOSHIBA_RBTX4938 is not set
+CONFIG_BCM963xx=y
+CONFIG_BCM96348=y
+
+#
+# CPU support
+#
+# CONFIG_BCM963XX_CPU_6338 is not set
+# CONFIG_BCM963XX_CPU_6345 is not set
+CONFIG_BCM963XX_CPU_6348=y
+# CONFIG_BCM963XX_CPU_6358 is not set
+CONFIG_BCM963XX_EARLY_CONSOLE=y
+# CONFIG_BOARD_BCM963XX is not set
+# CONFIG_BOARD_FBX4 is not set
+CONFIG_BOARD_FBX5A=y
+# CONFIG_BOARD_FBXGW1A is not set
+CONFIG_FBXBOARD_FBXMTD_LAYOUT=y
+# CONFIG_FBXBOARD_FBXMTD_LAYOUT_MAP_ONE_BANK is not set
+CONFIG_FBXBOARD_FBXMTD_LAYOUT_MAP_TWO_BANK=y
+CONFIG_FBXBOARD_FBXMTD_LAYOUT_READ_BANK1_TAG=y
+# CONFIG_FBXBOARD_FBXMTD_LAYOUT_ALL_RW is not set
+# CONFIG_FBXBOARD_FBXMTD_LAYOUT_NOCRC is not set
+# CONFIG_KEXEC is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_TIME=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
+CONFIG_CPU_BIG_ENDIAN=y
+# CONFIG_CPU_LITTLE_ENDIAN is not set
+CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
+CONFIG_IRQ_CPU=y
+CONFIG_SWAP_IO_SPACE=y
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+
+#
+# CPU selection
+#
+CONFIG_CPU_MIPS32_R1=y
+# CONFIG_CPU_MIPS32_R2 is not set
+# CONFIG_CPU_MIPS64_R1 is not set
+# CONFIG_CPU_MIPS64_R2 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+# CONFIG_CPU_SB1 is not set
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_CPU_MIPS32=y
+CONFIG_CPU_MIPSR1=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+
+#
+# Kernel type
+#
+CONFIG_32BIT=y
+# CONFIG_64BIT is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_MIPS_MT_DISABLED=y
+# CONFIG_MIPS_MT_SMP is not set
+# CONFIG_MIPS_MT_SMTC is not set
+# CONFIG_MIPS_VPE_LOADER is not set
+# CONFIG_64BIT_PHYS_ADDR is not set
+CONFIG_CPU_HAS_LLSC=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+# CONFIG_SMP is not set
+CONFIG_SYS_SUPPORTS_SMP=y
+# CONFIG_HZ_48 is not set
+# CONFIG_HZ_100 is not set
+# CONFIG_HZ_128 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_256 is not set
+# CONFIG_HZ_1000 is not set
+# CONFIG_HZ_1024 is not set
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_IGNORE_COMPILE_INFO is not set
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+# CONFIG_INITRAMFS_USE_GZIP is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+# CONFIG_FUTEX is not set
+CONFIG_EPOLL=y
+# CONFIG_SHMEM is not set
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_TINY_SHMEM=y
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+CONFIG_HW_HAS_PCI=y
+CONFIG_PCI=y
+CONFIG_MMU=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_TRAD_SIGNALS=y
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_NETSKBPAD=64
+# CONFIG_NETDEBUG is not set
+CONFIG_NETRXTHREAD=y
+CONFIG_NETRXTHREAD_RX_QUEUE=1
+CONFIG_NETRXTHREAD_MAX_PROCESS=4
+# CONFIG_SKB_RECYCLE is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=y
+# CONFIG_XFRM_SUB_POLICY is not set
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_FFN is not set
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_MULTIPLE_TABLES=y
+# CONFIG_IP_ROUTE_MULTIPATH is not set
+# CONFIG_IP_ROUTE_VERBOSE is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_DHCP_IDENTIFIER="fbx5a"
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+CONFIG_INET_XFRM_GC_THRESH=128
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=y
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_IPV6_MIP6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET6_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET6_XFRM_MODE_BEET is not set
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_SIT=y
+CONFIG_IPV6_SIT_FBX6TO4=y
+# CONFIG_IPV6_TUNNEL is not set
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+# CONFIG_NETWORK_SECMARK is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+# CONFIG_BRIDGE_NETFILTER is not set
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK is not set
+CONFIG_NF_CONNTRACK_ENABLED=y
+# CONFIG_NF_CONNTRACK_SUPPORT is not set
+CONFIG_IP_NF_CONNTRACK_SUPPORT=y
+CONFIG_IP_NF_CONNTRACK=y
+CONFIG_NETFILTER_XTABLES=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_DSCP=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set
+# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set
+# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNTRACK is not set
+# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
+# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
+# CONFIG_NETFILTER_XT_MATCH_ESP is not set
+# CONFIG_NETFILTER_XT_MATCH_HELPER is not set
+# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+# CONFIG_NETFILTER_XT_MATCH_MAC is not set
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+# CONFIG_NETFILTER_XT_MATCH_POLICY is not set
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set
+# CONFIG_NETFILTER_XT_MATCH_REALM is not set
+# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set
+# CONFIG_NETFILTER_XT_MATCH_STRING is not set
+# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set
+# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set
+
+#
+# IP: Netfilter Configuration
+#
+# CONFIG_IP_NF_CT_ACCT is not set
+# CONFIG_IP_NF_CONNTRACK_MARK is not set
+# CONFIG_IP_NF_CONNTRACK_EVENTS is not set
+# CONFIG_IP_NF_CT_PROTO_SCTP is not set
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+# CONFIG_IP_NF_NETBIOS_NS is not set
+CONFIG_IP_NF_TFTP=m
+# CONFIG_IP_NF_AMANDA is not set
+CONFIG_IP_NF_PPTP=m
+# CONFIG_IP_NF_H323 is not set
+# CONFIG_IP_NF_SIP is not set
+CONFIG_IP_NF_TPROXY=y
+# CONFIG_IP_NF_MATCH_TPROXY is not set
+CONFIG_IP_NF_TARGET_TPROXY=y
+# CONFIG_IP_NF_QUEUE is not set
+CONFIG_IP_NF_IPTABLES=y
+# CONFIG_IP_NF_MATCH_IPRANGE is not set
+CONFIG_IP_NF_MATCH_TOS=y
+# CONFIG_IP_NF_MATCH_RECENT is not set
+# CONFIG_IP_NF_MATCH_ECN is not set
+# CONFIG_IP_NF_MATCH_AH is not set
+# CONFIG_IP_NF_MATCH_TTL is not set
+# CONFIG_IP_NF_MATCH_OWNER is not set
+# CONFIG_IP_NF_MATCH_ADDRTYPE is not set
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+# CONFIG_IP_NF_TARGET_LOG is not set
+# CONFIG_IP_NF_TARGET_ULOG is not set
+CONFIG_IP_NF_TARGET_TCPMSS=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+# CONFIG_IP_NF_TARGET_NETMAP is not set
+# CONFIG_IP_NF_TARGET_SAME is not set
+# CONFIG_IP_NF_NAT_NRES is not set
+# CONFIG_IP_NF_NAT_SNMP_BASIC is not set
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_PPTP=m
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_TARGET_TOS=y
+# CONFIG_IP_NF_TARGET_ECN is not set
+# CONFIG_IP_NF_TARGET_TTL is not set
+# CONFIG_IP_NF_RAW is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+
+#
+# IPv6: Netfilter Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP6_NF_QUEUE is not set
+CONFIG_IP6_NF_IPTABLES=y
+# CONFIG_IP6_NF_MATCH_RT is not set
+# CONFIG_IP6_NF_MATCH_OPTS is not set
+# CONFIG_IP6_NF_MATCH_FRAG is not set
+# CONFIG_IP6_NF_MATCH_HL is not set
+# CONFIG_IP6_NF_MATCH_OWNER is not set
+# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set
+# CONFIG_IP6_NF_MATCH_AH is not set
+# CONFIG_IP6_NF_MATCH_EUI64 is not set
+CONFIG_IP6_NF_FILTER=y
+# CONFIG_IP6_NF_TARGET_LOG is not set
+# CONFIG_IP6_NF_TARGET_REJECT is not set
+# CONFIG_IP6_NF_MANGLE is not set
+# CONFIG_IP6_NF_RAW is not set
+
+#
+# Bridge: Netfilter Configuration
+#
+# CONFIG_BRIDGE_NF_EBTABLES is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+CONFIG_BRIDGE=y
+CONFIG_VLAN_8021Q=y
+# CONFIG_DECNET is not set
+CONFIG_LLC=y
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_FIFO=y
+# CONFIG_NET_SCH_CLK_JIFFIES is not set
+CONFIG_NET_SCH_CLK_GETTIMEOFDAY=y
+# CONFIG_NET_SCH_CLK_CPU is not set
+
+#
+# Queueing/Scheduling
+#
+# CONFIG_NET_SCH_CBQ is not set
+# CONFIG_NET_SCH_HTB is not set
+# CONFIG_NET_SCH_HFSC is not set
+CONFIG_NET_SCH_PRIO=y
+# CONFIG_NET_SCH_RED is not set
+CONFIG_NET_SCH_SFQ=y
+# CONFIG_NET_SCH_TEQL is not set
+# CONFIG_NET_SCH_TBF is not set
+# CONFIG_NET_SCH_GRED is not set
+# CONFIG_NET_SCH_DSMARK is not set
+# CONFIG_NET_SCH_NETEM is not set
+CONFIG_NET_SCH_INGRESS=y
+
+#
+# Classification
+#
+CONFIG_NET_CLS=y
+# CONFIG_NET_CLS_BASIC is not set
+# CONFIG_NET_CLS_TCINDEX is not set
+# CONFIG_NET_CLS_ROUTE4 is not set
+# CONFIG_NET_CLS_FW is not set
+CONFIG_NET_CLS_U32=y
+# CONFIG_CLS_U32_PERF is not set
+# CONFIG_CLS_U32_MARK is not set
+# CONFIG_NET_CLS_RSVP is not set
+# CONFIG_NET_CLS_RSVP6 is not set
+# CONFIG_NET_EMATCH is not set
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=y
+# CONFIG_NET_ACT_GACT is not set
+# CONFIG_NET_ACT_MIRRED is not set
+# CONFIG_NET_ACT_IPT is not set
+# CONFIG_NET_ACT_PEDIT is not set
+# CONFIG_NET_ACT_SIMP is not set
+# CONFIG_NET_CLS_IND is not set
+CONFIG_NET_ESTIMATOR=y
+# CONFIG_FBXATM is not set
+
+#
+# Network testing
+#
+CONFIG_NET_PKTGEN=y
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+CONFIG_WIRELESS_EXT=y
+CONFIG_FIB_RULES=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Freebox Memory Technology Devices (FBXMTD)
+#
+
+#
+# Core drivers
+#
+CONFIG_FREEBOX_MTD=y
+CONFIG_FREEBOX_MTD_BACKEND_AMD=y
+# CONFIG_FREEBOX_MTD_BACKEND_INTEL is not set
+CONFIG_FREEBOX_MTD_USE_DMAMUX=y
+CONFIG_FREEBOX_MTD_BLK=y
+CONFIG_FREEBOX_MTD_CHAR=y
+
+#
+# Mapping drivers
+#
+CONFIG_FREEBOX_MTD_MAP_DRV_GENERIC=y
+# CONFIG_FREEBOX_MTD_MAP_DRV_BCM963XX is not set
+# CONFIG_FREEBOX_MTD_MAP_IOCTL is not set
+
+#
+# Freebox DMA muxing support
+#
+CONFIG_FREEBOX_DMAMUX=y
+CONFIG_FREEBOX_DMAMUX_MAX_PRIO=1
+
+#
+# DMA devices
+#
+CONFIG_BCM963XX_DMAMUX=y
+
+#
+# Freebox GPIO
+#
+# CONFIG_FREEBOX_GPIO is not set
+
+#
+# Freebox Panel Support
+#
+CONFIG_FREEBOX_PANEL=m
+CONFIG_FREEBOX_PANEL_HW_PIC_FBX=m
+# CONFIG_FREEBOX_PANEL_HW_PT6959 is not set
+# CONFIG_FREEBOX_PANEL_HW_PT6311 is not set
+
+#
+# Freebox SPI support
+#
+# CONFIG_FREEBOX_SPI is not set
+
+#
+# Freebox Watchdog Support
+#
+CONFIG_FREEBOX_WATCHDOG=y
+# CONFIG_FREEBOX_WATCHDOG_CHAR is not set
+CONFIG_FREEBOX_WATCHDOG_BCM963XX=m
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# Misc devices
+#
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+CONFIG_CRASHZONE=y
+# CONFIG_BCM963XX_DSL_ALT is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_NETLINK is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_IFB is not set
+CONFIG_DUMMY=y
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+CONFIG_BROADCOM_PHY=y
+# CONFIG_FIXED_PHY is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+CONFIG_BCM963XX_ENET=y
+# CONFIG_NET_PCI is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+# CONFIG_QLA3XXX is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+# CONFIG_NET_WIRELESS_RTNETLINK is not set
+
+#
+# Obsolete Wireless cards support (pre-802.11)
+#
+# CONFIG_STRIP is not set
+
+#
+# Wireless 802.11b ISA/PCI cards support
+#
+# CONFIG_IPW2100 is not set
+# CONFIG_IPW2200 is not set
+# CONFIG_HERMES is not set
+# CONFIG_ATMEL is not set
+
+#
+# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
+#
+# CONFIG_PRISM54 is not set
+# CONFIG_USB_ZD1201 is not set
+# CONFIG_HOSTAP is not set
+CONFIG_NET_WIRELESS=y
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+CONFIG_PPP=y
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+# CONFIG_PPP_ASYNC is not set
+# CONFIG_PPP_SYNC_TTY is not set
+# CONFIG_PPP_DEFLATE is not set
+# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPP_MPPE is not set
+# CONFIG_PPPOX is not set
+# CONFIG_SLIP is not set
+CONFIG_SLHC=y
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_TANGO2_PCINET_D is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+CONFIG_PHONE=m
+# CONFIG_PHONE_IXJ is not set
+
+#
+# Input device support
+#
+# CONFIG_INPUT is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+CONFIG_SERIAL_BCM963XX=y
+CONFIG_SERIAL_BCM963XX_CONSOLE=y
+# CONFIG_UNIX98_PTYS is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=4
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=y
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
+CONFIG_I2C_GPIO=y
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+CONFIG_FIRMWARE_EDID=y
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS is not set
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_EHCI_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=m
+CONFIG_USB_OHCI_BIG_ENDIAN=y
+# CONFIG_USB_OHCI_LITTLE_ENDIAN is not set
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+
+#
+# USB Device Class drivers
+#
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Input Devices
+#
+
+#
+# USB HID Boot Protocol drivers
+#
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET_MII is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_USB_MON is not set
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+CONFIG_USB_SERIAL=y
+# CONFIG_USB_SERIAL_CONSOLE is not set
+# CONFIG_USB_SERIAL_GENERIC is not set
+# CONFIG_USB_SERIAL_AIRCABLE is not set
+# CONFIG_USB_SERIAL_AIRPRIME is not set
+# CONFIG_USB_SERIAL_ARK3116 is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+CONFIG_USB_SERIAL_CP2101=m
+# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_FUNSOFT is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
+# CONFIG_USB_SERIAL_GARMIN is not set
+# CONFIG_USB_SERIAL_IPW is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_MOS7720 is not set
+# CONFIG_USB_SERIAL_MOS7840 is not set
+# CONFIG_USB_SERIAL_NAVMAN is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_HP4X is not set
+# CONFIG_USB_SERIAL_SAFE is not set
+# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set
+# CONFIG_USB_SERIAL_TI is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OPTION is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+# CONFIG_USB_SERIAL_DEBUG is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# Virtualization
+#
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+# CONFIG_PROC_KCORE is not set
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_RAMFS_XATTR is not set
+# CONFIG_RAMFS_XATTR_USER is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+CONFIG_SQUASHFS=y
+# CONFIG_SQUASHFS_EMBEDDED is not set
+CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
+# CONFIG_SQUASHFS_VMALLOC is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_PRINTK_TIME=y
+# CONFIG_ENABLE_MUST_CHECK is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_CROSSCOMPILE=y
+CONFIG_CMDLINE="console=ttyS0,115200 ip=:::::eth0:dhcp root=/dev/nfs"
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=y
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+CONFIG_CRYPTO_AES=y
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_IOMAP_COPY=y
+CONFIG_SQLZMA_UNCOMP=y
+CONFIG_BUILTIN_FBXSERIAL=y
+CONFIG_CROSS_PATH="/opt/toolchains/mips32hwfloat-uclibc-std-0.9.30-gcc-4.2.4-binutils-2.19.50.0.1/bin/mips-linux-"
diff -Nruw linux-2.6.20.14-fbx/drivers/fbxdmamux./fbxdmamux_bcm963xx.c linux-2.6.20.14-fbx/drivers/fbxdmamux/fbxdmamux_bcm963xx.c
--- linux-2.6.20.14-fbx/drivers/fbxdmamux./fbxdmamux_bcm963xx.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/drivers/fbxdmamux/fbxdmamux_bcm963xx.c	2011-09-26 15:07:54.388835397 +0200
@@ -0,0 +1,416 @@
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/fbxdmamux.h>
+#include <linux/interrupt.h>
+
+#include <asm/mach-bcm963xx/bcm_map_part.h>
+#include <asm/mach-bcm963xx/bcm_intr.h>
+
+#include "fbxdmamux_priv.h"
+
+#define PFX	"bcm963xx_dma: "
+
+/*
+ * Two channel on bcm963xx, but channel  0 can only do external bus to
+ * SDRAM transfer, and channel 1 SDRAM to external.
+ *
+ * Both channels can do SDRAM to SRAM, but we will only use channel 0
+ * for this.
+ */
+#define CHANNEL_COUNT	2
+#define CHANNEL_RX	0
+#define CHANNEL_TX	1
+
+struct bcmdma_dev
+{
+	struct fbxdmamux_device common;
+	struct tasklet_struct dmadone_tasklet;
+
+	struct fbxdmamux_req *active_req[CHANNEL_COUNT];
+	struct list_head reqlist[CHANNEL_COUNT][FBXDMAMUX_MAX_PRIO];
+	struct list_head donelist;
+};
+
+#define BCMDMA_REQ_FLAGS_M2M	(1 << 0)
+#define BCMDMA_REQ_FLAGS_ERROR	(1 << 1)
+
+struct bcmdma_req
+{
+	unsigned int  flags;
+};
+
+/*
+ * set given channel for given request and kick it
+ */
+static void bcm_kick_dma(struct fbxdmamux_req *req, unsigned int chan)
+{
+	volatile struct m2m_dma_regs *p;
+	struct bcmdma_req *bcm_req;
+	unsigned int arch_flags;
+
+	bcm_req = req_priv(req);
+	p = (chan == CHANNEL_RX) ? m2m_rx : m2m_tx;
+
+	p->src = req->hw_src;
+	p->dst = req->hw_dst;
+	p->size = req->len >> 1;
+
+	if (chan == CHANNEL_RX) {
+		if (bcm_req->flags & BCMDMA_REQ_FLAGS_M2M)
+			p->srcid = 0x10;
+		else
+			p->srcid = 0x0;
+	}
+
+	arch_flags = 0;
+	if (req->flags & (FBXDMAMUX_FLAG_DST_NO_INCR |
+			  FBXDMAMUX_FLAG_SRC_NO_INCR))
+		arch_flags |= M2M_CTRL_NOINC;
+
+	wmb();
+	p->control = (M2M_CTRL_ENABLE | M2M_CTRL_IRQEN | M2M_CTRL_DONE_CLR |
+		      arch_flags);
+}
+
+/*
+ * start pending request on non running channels
+ */
+static int bcm_dma_schedule(struct bcmdma_dev *bcm_dev)
+{
+	unsigned long flags;
+	int i, j, found;
+
+	found = 0;
+	for (i = 0; i < CHANNEL_COUNT; i++) {
+		if (bcm_dev->active_req[i]) {
+			found = 1;
+			continue;
+		}
+
+		/* ok chan is free */
+		for (j = 0; j < FBXDMAMUX_MAX_PRIO; j++) {
+			struct list_head *head;
+			struct fbxdmamux_req *req;
+
+			head = &bcm_dev->reqlist[i][j];
+			if (list_empty(head))
+				continue;
+			/* pending request, kick it */
+			req = list_entry(head->next, struct fbxdmamux_req,
+					 list);
+			list_del(&req->list);
+			local_irq_save(flags);
+			bcm_dev->active_req[i] = req;
+			bcm_kick_dma(req, i);
+ 			local_irq_restore(flags);
+			found = 1;
+			break;
+		}
+	}
+	return found;
+}
+
+/*
+ * tasklet run on dma completion
+ */
+static void bcm_dma_done(unsigned long data)
+{
+	struct bcmdma_dev *bcm_dev;
+	struct bcmdma_req *bcm_req;
+	struct fbxdmamux_req *req;
+	unsigned long flags;
+
+	bcm_dev = (struct bcmdma_dev *)data;
+	do {
+		int error;
+
+		local_irq_save(flags);
+		if (list_empty(&bcm_dev->donelist)) {
+			local_irq_restore(flags);
+			break;
+		}
+		req = list_entry(bcm_dev->donelist.next,
+				 struct fbxdmamux_req, list);
+		list_del(&req->list);
+		local_irq_restore(flags);
+
+		bcm_req = req_priv(req);
+		error = (bcm_req->flags & BCMDMA_REQ_FLAGS_ERROR) ? 1 : 0;
+		fbxdmamux_complete(&bcm_dev->common, req, error);
+	} while (1);
+
+	bcm_dma_schedule(bcm_dev);
+}
+
+/*
+ * dma completion interrupt
+ */
+static irqreturn_t bcm_dma_done_interrupt(int irq, void *dev_id)
+{
+	struct bcmdma_dev *bcm_dev = dev_id;
+	struct bcmdma_req *bcm_req;
+	volatile struct m2m_dma_regs *p;
+	int i;
+
+	for (i = 0; i < CHANNEL_COUNT; i++) {
+		struct fbxdmamux_req *req;
+
+		p = (i == CHANNEL_RX) ? m2m_rx : m2m_tx;
+
+		if (!(p->status & M2M_STAT_DONE))
+			continue;
+
+		req = bcm_dev->active_req[i];
+		if (unlikely(!req)) {
+			printk(KERN_ERR PFX "interrupt while no dma active\n");
+			p->control |= M2M_CTRL_DONE_CLR;
+			continue;
+		}
+
+		bcm_dev->active_req[i] = NULL;
+                if (unlikely(p->status & M2M_STAT_ERROR)) {
+                        printk(KERN_ERR PFX "DMA error on channel %d\n", i);
+                        p->control |= M2M_CTRL_ERROR_CLR;
+			bcm_req = req_priv(req);
+			bcm_req->flags |= BCMDMA_REQ_FLAGS_ERROR;
+                }
+		p->control |= M2M_CTRL_DONE_CLR;
+		list_add_tail(&req->list, &bcm_dev->donelist);
+	}
+
+	/* process done request and reload */
+	tasklet_hi_schedule(&bcm_dev->dmadone_tasklet);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * using hw address of source/destination, find correct channel to use
+ * for transfer.
+ *
+ * Assume RAM is below 0x10000000, and "external" memory elsewhere
+ */
+#define BCM963XX_RAM_END	(0x10000000 - 1)
+
+static int find_appropriate_channel(struct fbxdmamux_req *req,
+				    unsigned int *channel, unsigned int *m2m)
+{
+	*m2m = 0;
+	*channel = CHANNEL_RX;
+
+	/* if we go from sdram to external, we have to use channel
+	 * 1 */
+	if (req->hw_src <= BCM963XX_RAM_END) {
+		if (req->hw_dst > BCM963XX_RAM_END)
+			*channel = CHANNEL_TX;
+		else
+			*m2m = 1;
+	}
+
+	/* 6348 has restriction, external  memory pointer should be 16
+	 * bits  aligned,  sdram  memory  pointer should  be  32  bits
+	 * aligned, transfer count should be multiple of 2 */
+	if (*channel == CHANNEL_RX) {
+		if (req->hw_dst & 0x3)
+			return 1;
+
+		if (*m2m) {
+			if (req->hw_src & 0x3)
+				return 1;
+		} else {
+			if (req->hw_src & 0x1)
+				return 1;
+		}
+	} else {
+		if (req->hw_src & 0x3)
+			return 1;
+		if (req->hw_dst & 0x1)
+			return 1;
+	}
+
+	if (req->len & 0x1)
+		return 1;
+
+	return 0;
+}
+
+/*
+ * called with bh disabled
+ */
+static int bcm_dma_submit(struct fbxdmamux_device *dev,
+			  struct fbxdmamux_req *req)
+{
+	struct bcmdma_req *bcm_req;
+	struct bcmdma_dev *bcm_dev;
+	unsigned int channel, m2m;
+
+	/* transfer size register is 16bits, and is the number of
+	 * 16bits unit to transfer, max transfer size is 128k - 4 */
+	if (req->len > ((128 << 10) - 4))
+		return 1;
+
+	if (find_appropriate_channel(req, &channel, &m2m))
+		return 1;
+
+	bcm_req = req_priv(req);
+	bcm_req->flags = 0;
+	if (m2m)
+		bcm_req->flags |= BCMDMA_REQ_FLAGS_M2M;
+
+	/* place request in correct queue, we can't race with
+	 * tasklet we're called with bh disabled */
+	bcm_dev = container_of(dev, struct bcmdma_dev, common);
+	list_add_tail(&req->list, &bcm_dev->reqlist[channel][req->priority]);
+	bcm_dma_schedule(bcm_dev);
+
+	return 0;
+}
+
+/*
+ * called with bh disabled
+ */
+static void bcm_dma_flush(struct fbxdmamux_device *dev,
+			  unsigned int cookie)
+{
+	struct bcmdma_dev *bcm_dev;
+
+	bcm_dev = container_of(dev, struct bcmdma_dev, common);
+
+	/* cookie is not considered so wait for all channel to
+	 * complete */
+	while (bcm_dma_schedule(bcm_dev))
+		cpu_relax();
+
+	while (1) {
+		int i;
+
+		rmb();
+		for (i = 0; i < CHANNEL_COUNT; i++) {
+			if (bcm_dev->active_req[i])
+				continue;
+		}
+		break;
+	}
+	bcm_dma_done((unsigned long)bcm_dev);
+}
+
+/*
+ * return device name
+ */
+static const char *bcm_dma_get_name(struct fbxdmamux_device *dev)
+{
+	return "bcm963xx_dma";
+}
+
+/*
+ * device probe
+ */
+static int bcm_dma_probe(struct platform_device *pdev)
+{
+	struct bcmdma_dev *bcm_dev;
+	int ret, i, j;
+
+	bcm_dev = kzalloc(sizeof (*bcm_dev), GFP_KERNEL);
+	if (!bcm_dev)
+		return -ENOMEM;
+	bcm_dev->common.dev = &pdev->dev;
+	bcm_dev->common.req_priv_size = sizeof (struct bcmdma_req);
+	bcm_dev->common.submit = bcm_dma_submit;
+	bcm_dev->common.flush_channel = bcm_dma_flush;
+	bcm_dev->common.get_name = bcm_dma_get_name;
+
+	for (i = 0; i < CHANNEL_COUNT; i++)
+		bcm_dev->active_req[i] = NULL;
+
+	for (i = 0; i < CHANNEL_COUNT; i++) {
+		for (j = 0; j < FBXDMAMUX_MAX_PRIO; j++)
+			INIT_LIST_HEAD(&bcm_dev->reqlist[i][j]);
+	}
+	INIT_LIST_HEAD(&bcm_dev->donelist);
+
+	tasklet_init(&bcm_dev->dmadone_tasklet, bcm_dma_done,
+		     (unsigned long)bcm_dev);
+
+	if (request_irq(INTERRUPT_ID_M2M, bcm_dma_done_interrupt, 0,
+			"bcm963xx_dma", bcm_dev)) {
+		printk(KERN_ERR PFX "request irq for dma failed\n");
+		kfree(bcm_dev);
+		return -ENODEV;
+       }
+
+	/* RX (ext -> sdram), 0x10 = sdram 0x0 = ext */
+	m2m_rx->srcid = 0x0;
+	m2m_rx->dstid = 0x10;
+
+	/* RX (sdram -> ext), 0x10 = sdram 0x0 = ext */
+#ifndef CONFIG_DMCRYPTATBOOT
+	m2m_tx->srcid = 0x10;
+	m2m_tx->dstid = 0x0;
+#endif
+
+	wmb();
+	platform_set_drvdata(pdev, bcm_dev);
+
+	if ((ret = fbxdmamux_register_device(&bcm_dev->common))) {
+		printk(KERN_ERR PFX "unable to register dma device\n");
+		goto fail;
+	}
+
+	return 0;
+
+fail:
+	free_irq(INTERRUPT_ID_M2M, NULL);
+	kfree(bcm_dev);
+	platform_set_drvdata(pdev, NULL);
+	return ret;
+}
+
+/*
+ * device remove callback
+ */
+static int bcm_dma_remove(struct platform_device *pdev)
+{
+	struct bcmdma_dev *bcm_dev;
+
+	bcm_dev = platform_get_drvdata(pdev);
+	fbxdmamux_unregister_device(&bcm_dev->common);
+	free_irq(INTERRUPT_ID_M2M, NULL);
+	tasklet_kill(&bcm_dev->dmadone_tasklet);
+	kfree(bcm_dev);
+	return 0;
+}
+
+
+struct platform_driver bcm963xx_dma_driver =
+{
+	.probe	= bcm_dma_probe,
+	.remove	= bcm_dma_remove,
+	.driver	= {
+		.name	= "bcm963xx_dma",
+	},
+};
+
+/*
+ * module entry
+ */
+static int __init bcm963xx_dma_init_module(void)
+{
+	return platform_driver_register(&bcm963xx_dma_driver);
+}
+
+/*
+ * module exit
+ */
+static void __exit bcm963xx_dma_exit_module(void)
+{
+	platform_driver_unregister(&bcm963xx_dma_driver);
+}
+
+module_init(bcm963xx_dma_init_module);
+module_exit(bcm963xx_dma_exit_module);
+
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Maxime Bizon <mbizon@freebox.fr>");
diff -Nruw linux-2.6.20.14-fbx/drivers/fbxdmamux./fbxdmamux.c linux-2.6.20.14-fbx/drivers/fbxdmamux/fbxdmamux.c
--- linux-2.6.20.14-fbx/drivers/fbxdmamux./fbxdmamux.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/drivers/fbxdmamux/fbxdmamux.c	2011-09-26 15:07:54.388835397 +0200
@@ -0,0 +1,529 @@
+/*
+ * simple, hardware independant, DMA request muxer/scheduler
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/fbxdmamux.h>
+#include <linux/dma-mapping.h>
+#include <linux/fbxdmamux.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+
+#include "fbxdmamux_priv.h"
+
+#define PFX	"fbxdmamux: "
+
+#define REQPOOL_COUNT	64
+
+/* prevent use before module_init is called */
+static unsigned int init_done = 0;
+
+/* request pool */
+static struct list_head reqpool;
+static spinlock_t reqpool_lock;
+
+/* current hardware device, if any */
+static spinlock_t dev_lock;
+static struct fbxdmamux_device *active_dev = NULL;
+
+/* device under test */
+static struct mutex totest_dev_mutex;
+static struct fbxdmamux_device *totest_dev = NULL;
+static struct work_struct totest_work;
+
+/*
+ * allocate a new request
+ */
+static struct fbxdmamux_req *alloc_req(unsigned int priv_size)
+{
+	unsigned int size;
+	size = sizeof (struct fbxdmamux_req) + priv_size + REQ_PRIV_ALIGN;
+	return kmalloc(size, GFP_KERNEL);
+}
+
+/*
+ * return a new request from pool
+ */
+struct fbxdmamux_req *fbxdmamux_req_from_pool(void)
+{
+	struct fbxdmamux_req *req;
+
+	if (unlikely(!init_done))
+		return NULL;
+
+	spin_lock_bh(&reqpool_lock);
+	if (list_empty(&reqpool)) {
+		if (active_dev && printk_ratelimit())
+			printk(KERN_WARNING PFX "request pool is empty\n");
+		spin_unlock_bh(&reqpool_lock);
+		return NULL;
+	}
+	req = list_entry(reqpool.next, struct fbxdmamux_req, list);
+	list_del(&req->list);
+	spin_unlock_bh(&reqpool_lock);
+	return req;
+}
+
+/*
+ * return request to pool
+ */
+static inline void add_to_pool(struct fbxdmamux_req *req)
+{
+	spin_lock_bh(&reqpool_lock);
+	list_add(&req->list, &reqpool);
+	spin_unlock_bh(&reqpool_lock);
+}
+
+/*
+ * fill req poll
+ */
+static void fill_req_pool(unsigned int priv_size)
+{
+	int i;
+
+	for (i = 0; i < REQPOOL_COUNT; i++) {
+		struct fbxdmamux_req *req;
+		req = alloc_req(priv_size);
+		if (!req)
+			return;
+		list_add(&req->list, &reqpool);
+	}
+}
+
+/*
+ * free all request in pool
+ */
+static void free_req_pool(void)
+{
+	struct fbxdmamux_req *req, *req2;
+
+	list_for_each_entry_safe(req, req2, &reqpool, list) {
+		list_del(&req->list);
+		kfree(req);
+	}
+}
+
+/*
+ * return  a  cookie that  is  used  to  guaranty request  (and  their
+ * completion) ordering
+ */
+int fbxdmamux_alloc_channel_cookie(void)
+{
+	static unsigned int cookie = 0;
+	cookie++;
+	if (!cookie)
+		cookie++;
+	return cookie;
+}
+
+/*
+ * submit given request to given device
+ */
+static int __fbxdmamux_submit(struct fbxdmamux_device *dev,
+			      struct fbxdmamux_req *req)
+{
+	int ret;
+
+	/* basic sanity check on request */
+	if (unlikely(req->len == 0)) {
+		printk(KERN_INFO PFX "rejected zero size request\n");
+		add_to_pool(req);
+		return 1;
+	}
+
+	if (unlikely(req->priority >= FBXDMAMUX_MAX_PRIO)) {
+		printk(KERN_INFO PFX "invalid priority %d\n", req->priority);
+		add_to_pool(req);
+		return 1;
+	}
+
+	/* get hw address and do cache stuff if needed */
+	if (!(req->flags & FBXDMAMUX_FLAG_SRC_HW)) {
+		req->hw_src = dma_map_single(dev->dev, req->virt_src,
+					     req->len, DMA_TO_DEVICE);
+	}
+
+	if (!(req->flags & FBXDMAMUX_FLAG_DST_HW)) {
+		req->hw_dst = dma_map_single(dev->dev, req->virt_dst,
+					     req->len, DMA_FROM_DEVICE);
+	}
+
+	ret = dev->submit(dev, req);
+	if (ret)
+		add_to_pool(req);
+	return ret;
+}
+
+/*
+ * submit a request to given device, sleep for completion, and return
+ * transfer status
+ */
+struct dma_completion {
+	struct completion cpt;
+	int error;
+};
+
+static void dma_completion_cb(void *cb_data, int error)
+{
+	struct dma_completion *dcpt = (struct dma_completion *)cb_data;
+
+	dcpt->error = error;
+	complete(&dcpt->cpt);
+}
+
+static int __fbxdmamux_submit_and_sleep(struct fbxdmamux_device *dev,
+					struct fbxdmamux_req *req,
+					unsigned int timeout,
+					spinlock_t *lock)
+{
+	struct dma_completion dcpt;
+	int ret;
+
+	init_completion(&dcpt.cpt);
+	req->cb_data = &dcpt;
+	req->callback = dma_completion_cb;
+	ret = __fbxdmamux_submit(dev, req);
+	if (lock)
+		spin_unlock_bh(lock);
+	else
+		local_bh_enable();
+
+	if (ret)
+		return ret;
+
+	if (timeout) {
+		ret = wait_for_completion_timeout(&dcpt.cpt, timeout);
+		if (!ret)
+			printk(KERN_ERR PFX "transfer timeout\n");
+		return (ret != 0) ? dcpt.error : 1;
+	}
+	wait_for_completion(&dcpt.cpt);
+	return dcpt.error;
+}
+
+/*
+ * submit given request to active device if any
+ */
+int fbxdmamux_submit(struct fbxdmamux_req *req)
+{
+	int ret;
+
+	if (unlikely(!init_done)) {
+		add_to_pool(req);
+		return 1;
+	}
+
+	spin_lock_bh(&dev_lock);
+	if (!active_dev) {
+		add_to_pool(req);
+		spin_unlock_bh(&dev_lock);
+		return 1;
+	}
+
+	ret = __fbxdmamux_submit(active_dev, req);
+	spin_unlock_bh(&dev_lock);
+	return ret;
+}
+
+/*
+ * submit given request to active device if any, sleep for completion,
+ * and request transfer status
+ */
+int fbxdmamux_submit_and_sleep(struct fbxdmamux_req *req, unsigned int timeout)
+{
+	int ret;
+
+	if (unlikely(!init_done)) {
+		add_to_pool(req);
+		return 1;
+	}
+
+	spin_lock_bh(&dev_lock);
+	if (!active_dev) {
+		add_to_pool(req);
+		spin_unlock(&dev_lock);
+		return 1;
+	}
+
+	ret = __fbxdmamux_submit_and_sleep(active_dev, req, timeout,
+					   &dev_lock);
+	return ret;
+}
+
+/*
+ * flush channel associated with given cookie
+ */
+void fbxdmamux_flush_channel(unsigned int cookie)
+{
+	if (unlikely(!init_done))
+		return;
+
+	spin_lock_bh(&dev_lock);
+	if (!active_dev) {
+		spin_unlock(&dev_lock);
+		return;
+	}
+
+	active_dev->flush_channel(active_dev, cookie);
+	spin_unlock_bh(&dev_lock);
+}
+
+/*
+ * called by device when request is complete
+ */
+void fbxdmamux_complete(struct fbxdmamux_device *dma_dev,
+			struct fbxdmamux_req *req, int error)
+{
+	void (*callback)(void *cb_data, int error);
+	void *cb_data;
+
+	if (!(req->flags & FBXDMAMUX_FLAG_SRC_HW))
+		dma_unmap_single(dma_dev->dev, req->hw_src,
+				 req->len, DMA_TO_DEVICE);
+
+	if (!(req->flags & FBXDMAMUX_FLAG_DST_HW))
+		dma_unmap_single(dma_dev->dev, req->hw_dst,
+				 req->len, DMA_FROM_DEVICE);
+
+	callback = req->callback;
+	cb_data = req->cb_data;
+	add_to_pool(req);
+	if (callback)
+		callback(cb_data, error);
+}
+
+/*
+ * workqueue callback, used to test device is working before we allow
+ * it to
+ */
+#define TEST_SIZE	PAGE_SIZE
+#define TEST_TIMEOUT	(HZ * 5)
+#define TEST_REQS	4
+
+static void fbxdmamux_test_device(struct work_struct *w)
+{
+	struct fbxdmamux_req *reqs[TEST_REQS];
+	char c, *bufs[TEST_REQS][2];
+	int i, j, ret;
+
+	mutex_lock(&totest_dev_mutex);
+	memset(bufs, 0, sizeof (bufs));
+	memset(reqs, 0, sizeof (reqs));
+
+	/* unregister might have been called before we run */
+	if (!totest_dev || active_dev)
+		goto out;
+
+	/* allocate memory zone for transfer */
+	for (i = 0; i < TEST_REQS; i++) {
+		for (j = 0; j < 2; j++) {
+			bufs[i][j] = kmalloc(TEST_SIZE, GFP_KERNEL);
+			if (!bufs[i][j]) {
+				printk(KERN_ERR PFX "unable to allocate "
+				       "memory for testing\n");
+				goto out_bad;
+			}
+		}
+	}
+
+	fill_req_pool(totest_dev->req_priv_size);
+
+	for (i = 0; i < TEST_REQS; i++) {
+		reqs[i] = fbxdmamux_req_from_pool();
+		if (!reqs[i]) {
+			printk(KERN_ERR PFX "not enough request in pool "
+			       "to test device\n");
+			goto out_bad;
+		}
+
+		reqs[i]->chan_cookie = 1;
+		reqs[i]->priority = 0;
+		reqs[i]->virt_src = bufs[i][0];
+		reqs[i]->virt_dst = bufs[i][1];
+		reqs[i]->len = TEST_SIZE;
+		reqs[i]->flags = 0;
+		reqs[i]->callback = NULL;
+
+		/* put some junk in src */
+		for (c = 0, j = 0; j < TEST_SIZE; j++)
+			bufs[i][0][j] = c++ + i;
+	}
+
+	printk(KERN_INFO PFX "starting test of device %s...\n",
+	       totest_dev->get_name(totest_dev));
+
+	/* burst first requests */
+	for (i = 0; i < TEST_REQS - 1; i++) {
+		local_bh_disable();
+		ret = __fbxdmamux_submit(totest_dev, reqs[i]);
+		local_bh_enable();
+		reqs[i] = NULL;
+		if (ret) {
+			printk(KERN_ERR PFX "test: submit failed\n");
+			goto out_bad;
+		}
+	}
+
+	/* request transfer and wait for it's completion for the last
+	 * one */
+	local_bh_disable();
+	ret = __fbxdmamux_submit_and_sleep(totest_dev, reqs[TEST_REQS - 1],
+					   TEST_TIMEOUT, NULL);
+	reqs[TEST_REQS - 1] = NULL;
+	if (ret) {
+		printk(KERN_ERR PFX "test: submit failed\n");
+		goto out_bad;
+	}
+
+	/* compare buffers */
+	for (i = 0; i < TEST_REQS; i++) {
+		if (memcmp(bufs[i][0], bufs[i][1], TEST_SIZE)) {
+			printk(KERN_ERR PFX "test: src and dst buffers %d are "
+			       "not the same\n", i);
+			goto out_bad;
+		}
+	}
+
+	/* set new active device */
+	printk(KERN_INFO PFX "test pass for device %s, set as active\n",
+	       totest_dev->get_name(totest_dev));
+	spin_lock_bh(&dev_lock);
+	active_dev = totest_dev;
+	spin_unlock_bh(&dev_lock);
+
+out:
+	for (i = 0; i < TEST_REQS; i++)
+		for (j = 0; j < 2; j++)
+			kfree(bufs[i][j]);
+	totest_dev = NULL;
+	mutex_unlock(&totest_dev_mutex);
+	return;
+
+out_bad:
+	printk(KERN_ERR PFX "test of device %s FAILED\n",
+	       totest_dev->get_name(totest_dev));
+	for (i = 0; i < TEST_REQS; i++) {
+		if (reqs[i])
+			add_to_pool(reqs[i]);
+		for (j = 0; j < 2; j++)
+			kfree(bufs[i][j]);
+	}
+	free_req_pool();
+
+	totest_dev = NULL;
+	mutex_unlock(&totest_dev_mutex);
+}
+
+
+/*
+ * register given device, only one  device at a time supported. Device
+ * is scheduled for testing.
+ */
+int fbxdmamux_register_device(struct fbxdmamux_device *dev)
+{
+	mutex_lock(&totest_dev_mutex);
+
+	/* one to test device at a time */
+	if (totest_dev) {
+		mutex_unlock(&totest_dev_mutex);
+		return -EBUSY;
+	}
+
+	/* one active device at a time */
+	spin_lock_bh(&dev_lock);
+	if (active_dev) {
+		spin_unlock_bh(&dev_lock);
+		mutex_unlock(&totest_dev_mutex);
+		return -EBUSY;
+	}
+	spin_unlock_bh(&dev_lock);
+
+	totest_dev = dev;
+	schedule_work(&totest_work);
+	mutex_unlock(&totest_dev_mutex);
+
+	return 0;
+}
+
+/*
+ * return list length
+ */
+static int list_length(struct list_head *head)
+{
+	struct list_head *tmp;
+	int length;
+
+	length = 0;
+	list_for_each(tmp, head)
+		length++;
+	return length;
+}
+
+/*
+ * unregister given device
+ */
+void fbxdmamux_unregister_device(struct fbxdmamux_device *dev)
+{
+again:
+	mutex_lock(&totest_dev_mutex);
+
+	/* if device is scheduled for testing, let the test finish
+	 * first*/
+	if (dev == totest_dev) {
+		mutex_unlock(&totest_dev_mutex);
+		flush_scheduled_work();
+		goto again;
+	}
+
+	spin_lock_bh(&dev_lock);
+	if (dev == active_dev)
+		active_dev = NULL;
+	spin_unlock_bh(&dev_lock);
+	/* wait for all request to go back to pool */
+	while (list_length(&reqpool) != REQPOOL_COUNT)
+		msleep(1);
+	free_req_pool();
+	mutex_unlock(&totest_dev_mutex);
+}
+
+/*
+ * module init callback
+ */
+static int __init fbxdmamux_init(void)
+{
+	printk(KERN_INFO PFX "Freebox DMA request muxer API\n");
+
+	spin_lock_init(&dev_lock);
+	mutex_init(&totest_dev_mutex);
+	INIT_WORK(&totest_work, fbxdmamux_test_device);
+
+	/* allocate pool of request */
+	spin_lock_init(&reqpool_lock);
+	INIT_LIST_HEAD(&reqpool);
+	wmb();
+	init_done = 1;
+	return 0;
+}
+
+/*
+ * module remove callback
+ */
+static void __exit fbxdmamux_exit(void)
+{
+}
+
+module_init(fbxdmamux_init);
+module_exit(fbxdmamux_exit);
+
+EXPORT_SYMBOL(fbxdmamux_req_from_pool);
+EXPORT_SYMBOL(fbxdmamux_submit);
+EXPORT_SYMBOL(fbxdmamux_submit_and_sleep);
+EXPORT_SYMBOL(fbxdmamux_alloc_channel_cookie);
+EXPORT_SYMBOL(fbxdmamux_flush_channel);
+
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0");
+MODULE_AUTHOR("Maxime Bizon <mbizon@freebox.fr>");
+
diff -Nruw linux-2.6.20.14-fbx/drivers/fbxdmamux./fbxdmamux_priv.h linux-2.6.20.14-fbx/drivers/fbxdmamux/fbxdmamux_priv.h
--- linux-2.6.20.14-fbx/drivers/fbxdmamux./fbxdmamux_priv.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/drivers/fbxdmamux/fbxdmamux_priv.h	2011-09-26 15:07:54.388835397 +0200
@@ -0,0 +1,29 @@
+
+#ifndef FBXDMAMUX_PRIV_H_
+#define FBXDMAMUX_PRIV_H_
+
+#define REQ_PRIV_ALIGN	8
+
+#define req_priv(x)	(void *)(((long)x + sizeof (*x) + \
+				REQ_PRIV_ALIGN) & ~REQ_PRIV_ALIGN)
+
+struct fbxdmamux_device
+{
+	struct device *dev;
+	unsigned int req_priv_size;
+
+	const char *(*get_name)(struct fbxdmamux_device *dma_dev);
+	int (*submit)(struct fbxdmamux_device *dma_dev,
+		      struct fbxdmamux_req *req);
+	void (*flush_channel)(struct fbxdmamux_device *dma_dev,
+			      unsigned int cookie);
+};
+
+int fbxdmamux_register_device(struct fbxdmamux_device *dev);
+
+void fbxdmamux_unregister_device(struct fbxdmamux_device *dev);
+
+void fbxdmamux_complete(struct fbxdmamux_device *dev,
+			struct fbxdmamux_req *req, int error);
+
+#endif /* !FBXDMAMUX_PRIV_H_ */
diff -Nruw linux-2.6.20.14-fbx/drivers/fbxdmamux./Kconfig linux-2.6.20.14-fbx/drivers/fbxdmamux/Kconfig
--- linux-2.6.20.14-fbx/drivers/fbxdmamux./Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/drivers/fbxdmamux/Kconfig	2011-09-26 15:07:54.388835397 +0200
@@ -0,0 +1,22 @@
+
+menu "Freebox DMA muxing support"
+
+config FREEBOX_DMAMUX
+	bool "Support for fbxdmamux"
+
+config FREEBOX_DMAMUX_MAX_PRIO
+	int "Number of priority allowed"
+	default 1
+	depends on FREEBOX_DMAMUX
+
+comment "DMA devices"
+
+config BCM963XX_DMAMUX
+	tristate "Broadcom 963xx DMA support"
+	depends on FREEBOX_DMAMUX && BCM963XX && !BCM96358
+
+config MV88FXX81_DMAMUX
+	tristate "Marvell mv88fxx81 internal DMA engine support"
+	depends on FREEBOX_DMAMUX && ARCH_MV88FXX81
+
+endmenu
diff -Nruw linux-2.6.20.14-fbx/drivers/fbxdmamux./Makefile linux-2.6.20.14-fbx/drivers/fbxdmamux/Makefile
--- linux-2.6.20.14-fbx/drivers/fbxdmamux./Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/drivers/fbxdmamux/Makefile	2011-09-26 15:07:54.388835397 +0200
@@ -0,0 +1,4 @@
+
+obj-$(CONFIG_FREEBOX_DMAMUX) += fbxdmamux.o
+obj-$(CONFIG_BCM963XX_DMAMUX) += fbxdmamux_bcm963xx.o
+obj-$(CONFIG_MV88FXX81_DMAMUX) += fbxdmamux_mv88fxx81.o
diff -Nruw linux-2.6.20.14-fbx/drivers/fbxgpio./Kconfig linux-2.6.20.14-fbx/drivers/fbxgpio/Kconfig
--- linux-2.6.20.14-fbx/drivers/fbxgpio./Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/drivers/fbxgpio/Kconfig	2011-09-26 15:07:54.388835397 +0200
@@ -0,0 +1,7 @@
+menu "Freebox GPIO"
+
+config FREEBOX_GPIO
+	tristate "Freebox GPIO control interface."
+	default n
+
+endmenu
diff -Nruw linux-2.6.20.14-fbx/drivers/fbxgpio./Makefile linux-2.6.20.14-fbx/drivers/fbxgpio/Makefile
--- linux-2.6.20.14-fbx/drivers/fbxgpio./Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/drivers/fbxgpio/Makefile	2011-09-26 15:07:54.388835397 +0200
@@ -0,0 +1,9 @@
+##
+##  Makefile<2> for linux-freebox
+##  Created by <nschichan@freebox.fr> on Wed Feb 21 18:08:48 2007
+##  Freebox SA
+##
+
+obj-$(CONFIG_FREEBOX_GPIO)	+= fbxgpio_core.o
+
+EXTRA_CFLAGS += -Werror
diff -Nruw linux-2.6.20.14-fbx/drivers/fbxmtd./fbxmtd_blk_dev.c linux-2.6.20.14-fbx/drivers/fbxmtd/fbxmtd_blk_dev.c
--- linux-2.6.20.14-fbx/drivers/fbxmtd./fbxmtd_blk_dev.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/drivers/fbxmtd/fbxmtd_blk_dev.c	2011-09-26 15:07:54.388835397 +0200
@@ -0,0 +1,368 @@
+/*
+ * Freebox Memory Technology Device r/o block device interface.
+ *
+ * Interface to the flash via a  block device. A mapping is done using
+ * minor  number  and partitions  so  a  maximum  of 8  partitions  is
+ * possible per device.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/fs.h>
+#include <linux/genhd.h>
+#include <linux/blkdev.h>
+#include <linux/kthread.h>
+
+#include <asm/atomic.h>
+#include <asm/io.h>
+
+#include <linux/fbxmtd.h>
+
+#include "fbxmtd_priv.h"
+#include "fbxmtd_blk_dev.h"
+
+#define PFX			"fbxmtd_blk: "
+#define FBXMTD_BLK_MAJOR	252
+#define PART_PER_DEVICE		FBXMTD_MAX_PART
+
+
+static struct semaphore disks_mutex;
+static struct list_head disks;
+
+/*
+ * list helpers
+ */
+static int fbxmtd_add_disk(struct fbxmtd_blk_disk *d)
+{
+	down(&disks_mutex);
+	list_add_tail(&d->list, &disks);
+	up(&disks_mutex);
+
+	return 0;
+}
+
+static void _fbxmtd_put_disk(struct fbxmtd_blk_disk *d)
+{
+	if (!atomic_dec_and_test(&d->refcount))
+		return;
+
+	fbxmtd_put_part(d->part);
+	if (d->worker)
+		kthread_stop(d->worker);
+	if (d->gd) {
+		del_gendisk(d->gd);
+		put_disk(d->gd);
+	}
+	if (d->queue)
+		blk_cleanup_queue(d->queue);
+	list_del(&d->list);
+ 	kfree(d);
+}
+
+static void fbxmtd_put_disk(struct fbxmtd_blk_disk *d)
+{
+	down(&disks_mutex);
+	_fbxmtd_put_disk(d);
+	up(&disks_mutex);
+}
+
+static void fbxmtd_put_disk_by_part(struct fbxmtd_part *part)
+{
+	struct fbxmtd_blk_disk *d;
+
+	down(&disks_mutex);
+	list_for_each_entry(d, &disks, list) {
+		if (d->part == part) {
+			_fbxmtd_put_disk(d);
+			break;
+		}
+	}
+	up(&disks_mutex);
+}
+
+
+/*
+ * blk funcs
+ */
+static int transfer(struct fbxmtd_part *part, unsigned long sector,
+		    unsigned long nsect, char *buffer, int write,
+		    int can_sleep)
+{
+	unsigned long offset = sector * 512;
+	unsigned long nbytes = nsect * 512;
+
+	/* delay write request, as they will sleep, but try to
+	 * process read request now if it's possible */
+	if (!can_sleep) {
+		if (write)
+			return -EWOULDBLOCK;
+		return fbxmtd_read_part(part, offset, buffer, nbytes, 0);
+	}
+
+	/* we can sleep */
+	if (write)
+		return fbxmtd_write_part(part, offset, buffer, nbytes);
+	return fbxmtd_read_part(part, offset, buffer, nbytes, 1);
+}
+
+/*
+ * worker thread main func
+ */
+static int kworkerthread(void *data)
+{
+	struct fbxmtd_blk_disk *disk;
+	struct request_queue *q;
+
+	disk = (struct fbxmtd_blk_disk *)data;
+	q = disk->queue;
+
+	/* we  grab queue  lock until  there  are no  more request  to
+	 * process */
+	spin_lock_irq(&disk->lock);
+	while (!kthread_should_stop()) {
+		struct request *req;
+		int ret;
+
+		/* process next request */
+		if (!(req = elv_next_request(q))) {
+			/* nothing to do, sleep */
+			spin_unlock_irq(&disk->lock);
+			wait_event_interruptible(disk->worker_wq,
+						 disk->work_to_do == 1 ||
+						 kthread_should_stop());
+			disk->work_to_do = 0;
+			spin_lock_irq(&disk->lock);
+			continue;
+		}
+
+		/* process the  request, release queue lock  as we may
+		 * sleep */
+		spin_unlock_irq(&disk->lock);
+		ret = transfer(disk->part, req->sector,
+			       req->current_nr_sectors, req->buffer,
+			       rq_data_dir(req), 1);
+		end_request(req, ret >= 0 ? 1 : 0);
+		spin_lock_irq(&disk->lock);
+	}
+	spin_unlock_irq(&disk->lock);
+
+        return 0;
+}
+
+
+static void blk_request(request_queue_t *q)
+{
+	struct fbxmtd_blk_disk *disk = q->queuedata;
+
+	/* wakeup the worker thread to request */
+	disk->work_to_do = 1;
+	wake_up(&disk->worker_wq);
+}
+
+static int blk_open(struct inode *inode, struct file *filep)
+{
+	struct fbxmtd_blk_disk *disk;
+
+	disk = (struct fbxmtd_blk_disk *)inode->i_bdev->bd_disk->private_data;
+	filep->private_data = disk;
+
+	atomic_inc(&disk->refcount);
+
+	return 0;
+}
+
+static int blk_release(struct inode *inode, struct file *filep)
+{
+	struct fbxmtd_blk_disk *disk;
+
+	disk = (struct fbxmtd_blk_disk *)inode->i_bdev->bd_disk->private_data;
+	fbxmtd_put_disk(disk);
+
+	return 0;
+}
+
+struct block_device_operations fbxmtd_blk_ops = {
+	.open = blk_open,
+	.release = blk_release,
+	.owner = THIS_MODULE,
+};
+
+
+/*
+ * setup a fbxmtd blk disk for the given partition
+ */
+static int setup_disk(struct fbxmtd_part *part)
+{
+	struct fbxmtd_blk_disk *disk;
+
+	if (!(disk = kmalloc(sizeof (struct fbxmtd_blk_disk), GFP_KERNEL)))
+		return 1;
+
+	memset(disk, 0, sizeof (struct fbxmtd_blk_disk));
+	disk->part = part;
+	snprintf(disk->name, sizeof (disk->name), "%s/%s", part->dev->name,
+		 part->name);
+	INIT_LIST_HEAD(&disk->list);
+	spin_lock_init(&disk->lock);
+	init_waitqueue_head(&disk->worker_wq);
+	atomic_set(&disk->refcount, 1);
+
+
+	/* alloc queue */
+	disk->queue = blk_init_queue(blk_request, &disk->lock);
+	if (disk->queue == NULL) {
+		printk(KERN_ERR PFX "blk_init_queue failed !\n");
+		goto free;
+	}
+	blk_queue_hardsect_size(disk->queue, 512);
+	blk_queue_max_phys_segments(disk->queue, 1);
+	disk->queue->queuedata = disk;
+
+	/* alloc gendisk */
+	if (!(disk->gd = alloc_disk(1))) {
+		printk(KERN_ERR PFX "alloc_disk failed !\n");
+		goto free;
+	}
+	snprintf(disk->gd->disk_name, sizeof (disk->gd->disk_name),
+		 "fbxmtdblk%c%d", disk->part->dev->idx + 'a', part->idx);
+
+	disk->gd->major = FBXMTD_BLK_MAJOR;
+	disk->gd->first_minor = disk->part->dev->idx * PART_PER_DEVICE +
+		part->idx;
+
+	disk->gd->queue = disk->queue;
+	disk->gd->fops = &fbxmtd_blk_ops;
+	disk->gd->private_data = disk;
+	set_capacity(disk->gd, (part->size / 512) == 0 ? 1 : part->size / 512);
+
+	/* create worker kthread */
+	disk->worker = kthread_create(kworkerthread, disk,
+				      "kfbxmtdblk/%s", part->name);
+	if (IS_ERR(disk->worker)) {
+		disk->worker = NULL;
+		printk(KERN_ERR PFX "Error creating worker kthread\n");
+		goto free;
+	}
+
+	/* add gen disk */
+	add_disk(disk->gd);
+
+	/* add disk to the list */
+	if (fbxmtd_add_disk(disk))
+		goto free;
+
+	wake_up_process(disk->worker);
+	return 0;
+free:
+	if (disk->worker)
+		kthread_stop(disk->worker);
+	if (disk->gd) {
+		del_gendisk(disk->gd);
+		put_disk(disk->gd);
+	}
+	if (disk->queue)
+		blk_cleanup_queue(disk->queue);
+	kfree(disk);
+	return 1;
+}
+
+
+static void fbxmtd_notifier_cb(void *cb_data, struct fbxmtd_part *part,
+			       uint32_t event)
+{
+	if (event == FBXMTD_EVENT_DEAD) {
+		fbxmtd_put_disk_by_part(part);
+	} else {
+		/* event == FBXMTD_EVENT_ADD */
+		if (part->size < 512 || part->size % 512) {
+			printk(KERN_INFO PFX "skipped too small or non "
+			       "512 bytes aligned partition %s\n", part->name);
+			return;
+		}
+		if (!setup_disk(part))
+			atomic_inc(&part->dev->refcount);
+	}
+}
+
+static int foreach_part_cb(void *cb_data, struct fbxmtd_part *part)
+{
+	if (part->size < 512 || part->size % 512) {
+		printk(KERN_INFO PFX "skipped too small partition %s\n",
+		       part->name);
+		return 0;
+	}
+
+	if (!setup_disk(part)) {
+		/* keep a reference on part */
+		atomic_inc(&part->dev->refcount);
+		return 0;
+	}
+	return 1;
+}
+
+
+static int __init fbxmtd_blk_init(void)
+{
+	struct fbxmtd_blk_disk *d, *d2;
+
+	printk(KERN_INFO PFX "Freebox MTD block device access support\n");
+
+	INIT_LIST_HEAD(&disks);
+	init_MUTEX(&disks_mutex);
+
+	/* register blk device */
+	if (register_blkdev(FBXMTD_BLK_MAJOR, "fbxmtd") < 0) {
+		printk(KERN_ERR PFX "Unable to get blkdev major %d\n",
+		       FBXMTD_BLK_MAJOR);
+		return -ENODEV;
+	}
+
+	/* register notifier for future addition of mtddevice */
+	if (fbxmtd_register_notifier(fbxmtd_notifier_cb, NULL,
+				     FBXMTD_EVENT_DEAD | FBXMTD_EVENT_PART)) {
+		printk(KERN_ERR PFX "Unable to register fbxmtd notifier\n");
+		goto err;
+	}
+
+	/* create disk for existing partitions */
+	if (fbxmtd_foreach_part(foreach_part_cb, NULL))
+		goto err;
+
+	return 0;
+
+err:
+	unregister_blkdev(FBXMTD_BLK_MAJOR, "fbxmtd");
+	fbxmtd_unregister_notifier(fbxmtd_notifier_cb);
+	/* put all devices */
+	down(&disks_mutex);
+	list_for_each_entry_safe(d, d2, &disks, list) {
+		_fbxmtd_put_disk(d);
+	}
+	up(&disks_mutex);
+	return -ENODEV;
+}
+
+static void __exit fbxmtd_blk_exit(void)
+{
+	struct fbxmtd_blk_disk *d, *d2;
+
+	fbxmtd_unregister_notifier(fbxmtd_notifier_cb);
+
+	/* put all devices */
+	down(&disks_mutex);
+	list_for_each_entry_safe(d, d2, &disks, list) {
+		_fbxmtd_put_disk(d);
+	}
+	up(&disks_mutex);
+
+	unregister_blkdev(FBXMTD_BLK_MAJOR, "fbxmtd");
+}
+
+
+module_init(fbxmtd_blk_init);
+module_exit(fbxmtd_blk_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0");
+MODULE_AUTHOR("Maxime Bizon <mbizon@freebox.fr>");
diff -Nruw linux-2.6.20.14-fbx/drivers/fbxmtd./fbxmtd_blk_dev.h linux-2.6.20.14-fbx/drivers/fbxmtd/fbxmtd_blk_dev.h
--- linux-2.6.20.14-fbx/drivers/fbxmtd./fbxmtd_blk_dev.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/drivers/fbxmtd/fbxmtd_blk_dev.h	2011-09-26 15:07:54.388835397 +0200
@@ -0,0 +1,22 @@
+
+#ifndef FBXMTD_BLK_DEV_H_
+# define FBXMTD_BLK_DEV_H_
+
+#include <linux/list.h>
+#include <asm/atomic.h>
+
+struct fbxmtd_blk_disk
+{
+	char name[32];
+	struct fbxmtd_part *part;
+	struct list_head list;
+	atomic_t refcount;
+        spinlock_t lock;
+        struct request_queue *queue;
+        struct gendisk *gd;
+        struct task_struct *worker;
+	wait_queue_head_t worker_wq;
+	int work_to_do;
+};
+
+#endif /* !FBXMTD_BLK_DEV_H_ */
diff -Nruw linux-2.6.20.14-fbx/drivers/fbxmtd./fbxmtd_char_dev.c linux-2.6.20.14-fbx/drivers/fbxmtd/fbxmtd_char_dev.c
--- linux-2.6.20.14-fbx/drivers/fbxmtd./fbxmtd_char_dev.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/drivers/fbxmtd/fbxmtd_char_dev.c	2011-09-26 15:07:54.388835397 +0200
@@ -0,0 +1,220 @@
+/*
+ * Freebox Memory Technology Device character device interface.
+ *
+ * Interface to  the flash via a  character device. A  mapping is done
+ * using minor  number and  partitions so a maximum  of 8  partitions is
+ * possible per device.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/fs.h>
+#include <asm/uaccess.h>
+
+#include <linux/fbxmtd.h>
+
+#include "fbxmtd_priv.h"
+
+#define PFX			"fbxmtd_chr: "
+#define FBXMTD_CHAR_MAJOR	251
+#define PART_PER_DEVICE		FBXMTD_MAX_PART
+#define MAX_KMALLOC_SIZE	0x20000
+
+/*
+ * open callback
+ * map the minor to the associated device / partition and keep track of it
+ */
+static int fbxmtd_open(struct inode *inode, struct file *file)
+{
+	struct fbxmtd_part *part;
+	int minor, dev_idx, part_idx;
+
+	/* find partition associated if any */
+	minor = MINOR(inode->i_rdev);
+	dev_idx = minor / PART_PER_DEVICE;
+	part_idx = minor % PART_PER_DEVICE;
+
+	/* get associated partition */
+	part = fbxmtd_get_part(dev_idx, part_idx);
+	if (!part)
+		return -ENODEV;
+	file->private_data = part;
+
+	return 0;
+}
+
+/*
+ * release callback
+ * put reference to the partition we have
+ */
+static int fbxmtd_release(struct inode *inode, struct file *file)
+{
+	struct fbxmtd_part *part;
+
+	part = (struct fbxmtd_part *)file->private_data;
+	fbxmtd_put_part(part);
+
+	return 0;
+}
+
+/*
+ * read callback
+ * adjust offset and count and forward request to the core
+ */
+
+static ssize_t fbxmtd_read(struct file *file, char *buffer, size_t count,
+			   loff_t *ppos)
+{
+	struct fbxmtd_part *part;
+	size_t total_len;
+	int len;
+	char *kbuf;
+
+	part = (struct fbxmtd_part *)file->private_data;
+
+	/* adjust size if count is too big */
+	if (*ppos >= part->size)
+		return 0;
+	if (count > part->size - *ppos)
+		count = part->size - *ppos;
+
+	if (count > MAX_KMALLOC_SIZE)
+		len = MAX_KMALLOC_SIZE;
+	else
+		len = count;
+
+	if (!(kbuf = kmalloc(len, GFP_KERNEL)))
+		return -ENOMEM;
+
+	total_len = 0;
+	while (count) {
+
+		if (need_resched())
+			yield();
+
+		if (count > MAX_KMALLOC_SIZE)
+			len = MAX_KMALLOC_SIZE;
+		else
+			len = count;
+
+		len = fbxmtd_read_part(part, *ppos, kbuf, len, 1);
+		if (len <= 0) {
+			kfree(kbuf);
+			return len;
+		}
+
+		if (len) {
+			if (copy_to_user(buffer, kbuf, len)) {
+				kfree(kbuf);
+				return -EFAULT;
+			}
+		}
+
+		count -= len;
+		buffer += len;
+		*ppos += len;
+		total_len += len;
+	}
+
+	kfree(kbuf);
+	return total_len;
+}
+
+
+/*
+ * write callback
+ * adjust offset and count and forward request to the core
+ */
+static ssize_t fbxmtd_write(struct file *file, const char *buffer,
+			    size_t count, loff_t *ppos)
+{
+	struct fbxmtd_part *part;
+	size_t total_len;
+	char *kbuf;
+	int len;
+
+	part = (struct fbxmtd_part *)file->private_data;
+
+	/* write access outside the partition region is an error */
+	if (*ppos >= part->size)
+		return -EINVAL;
+	if (count > part->size - *ppos)
+		return -EFBIG;
+
+	if (count > MAX_KMALLOC_SIZE)
+		len = MAX_KMALLOC_SIZE;
+	else
+		len = count;
+
+	if (!(kbuf = kmalloc(len, GFP_KERNEL)))
+		return -ENOMEM;
+
+	total_len = 0;
+	while (count) {
+
+		if (need_resched())
+			yield();
+
+		if (count > MAX_KMALLOC_SIZE)
+			len = MAX_KMALLOC_SIZE;
+		else
+			len = count;
+
+		if (copy_from_user(kbuf, buffer, len)) {
+			kfree(kbuf);
+			return -EFAULT;
+		}
+
+		len = fbxmtd_write_part(part, *ppos, kbuf, len);
+		if (len <= 0) {
+			kfree(kbuf);
+			return len;
+		}
+
+		count -= len;
+		buffer += len;
+		*ppos += len;
+		total_len += len;
+	}
+
+	kfree(kbuf);
+	return total_len;
+
+}
+
+
+static struct file_operations fbxmtd_fops = {
+	.open = fbxmtd_open,
+	.release = fbxmtd_release,
+	.read = fbxmtd_read,
+	.write = fbxmtd_write,
+	.owner = THIS_MODULE,
+};
+
+static int __init fbxmtd_chr_init(void)
+{
+	printk(KERN_INFO PFX "Freebox MTD character device access support\n");
+
+	/* register char device */
+	if (register_chrdev(FBXMTD_CHAR_MAJOR, "fbxmtd", &fbxmtd_fops) < 0) {
+		printk(KERN_ERR PFX "Unable to get chrdev major %d\n",
+		       FBXMTD_CHAR_MAJOR);
+                return -ENODEV;
+        }
+
+	return 0;
+}
+
+static void __exit fbxmtd_chr_exit(void)
+{
+	unregister_chrdev(FBXMTD_CHAR_MAJOR, "fbxmtd");
+}
+
+
+module_init(fbxmtd_chr_init);
+module_exit(fbxmtd_chr_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0");
+MODULE_AUTHOR("Maxime Bizon <mbizon@freebox.fr>");
diff -Nruw linux-2.6.20.14-fbx/drivers/fbxmtd./fbxmtd_core_amd.c linux-2.6.20.14-fbx/drivers/fbxmtd/fbxmtd_core_amd.c
--- linux-2.6.20.14-fbx/drivers/fbxmtd./fbxmtd_core_amd.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/drivers/fbxmtd/fbxmtd_core_amd.c	2011-09-26 15:07:54.388835397 +0200
@@ -0,0 +1,567 @@
+/*
+ *
+ * Support for AMD compatible flash for Freebox MTD
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+
+#include <linux/fbxmtd.h>
+
+#include "fbxmtd_priv.h"
+#include "fbxmtd_core_amd.h"
+
+#define PFX		"fbxmtd_amd: "
+#define POLL_TIMEOUT	(10 * HZ)
+
+#define SZ_1K				0x00000400
+#define SZ_2K				0x00000800
+#define SZ_4K				0x00001000
+#define SZ_8K				0x00002000
+#define SZ_16K				0x00004000
+#define SZ_32K				0x00008000
+#define SZ_64K				0x00010000
+#define SZ_128K				0x00020000
+#define SZ_256K				0x00040000
+#define SZ_512K				0x00080000
+#define SZ_1M				0x00100000
+#define SZ_2M				0x00200000
+#define SZ_4M				0x00400000
+#define SZ_8M				0x00800000
+#define SZ_16M				0x01000000
+#define SZ_32M				0x02000000
+#define SZ_64M				0x04000000
+#define SZ_128M				0x08000000
+#define SZ_256M				0x10000000
+#define SZ_512M				0x20000000
+
+/*
+ * List of known flash we support
+ */
+static const struct amd_flash_info amd_flash_infos[] = {
+
+	{
+		.mfr_id = MANUFACTURER_AMD,
+		.dev_id = AM29LV040B,
+		.name = "AMD AM29LV040B",
+		.size = SZ_512K,
+		.use_dq5 = 1,
+		.use_ext_dev_id = 0,
+		.need_tpoll_delay = 1,
+
+		.regions = {
+			{ .offset = 0x0, .size = SZ_64K, .count = 8 },
+			{ .count = 0 },
+		},
+	 },
+
+	{
+		.mfr_id = MANUFACTURER_AMD,
+		.dev_id = SPANSION_GENERIC,
+		.ext_dev_id = { 0x221A, 0x2200 },
+		.name = "AMD AM29LV320MB / S29GL032[AN]R4 (bottom)",
+		.size = SZ_4M,
+		.use_dq5 = 1,
+		.use_ext_dev_id = 1,
+		.need_tpoll_delay = 1,
+
+		.regions = {
+			{ .offset = 0x0, .size = SZ_8K, .count = 8 },
+			{ .offset = 0x10000, .size = SZ_64K, .count = 63 },
+			{ .count = 0 },
+		},
+	 },
+
+	{
+		.mfr_id = MANUFACTURER_SPANSION,
+		.dev_id = SPANSION_GENERIC,
+		.ext_dev_id = { 0x2210, 0x2200 },
+		.name = "SPANSION S29GL064[AMN]R4 (bottom)",
+		.size = SZ_8M,
+		.use_dq5 = 1,
+		.need_tpoll_delay = 1,
+		.use_ext_dev_id = 1,
+
+		.regions = {
+			{ .offset = 0x0, .size = SZ_8K, .count = 8 },
+			{ .offset = 0x10000, .size = SZ_64K, .count = 126 },
+			{ .count = 0 },
+		},
+	 },
+
+	{
+		.mfr_id = MANUFACTURER_SPANSION,
+		.dev_id = SPANSION_GENERIC,
+		.ext_dev_id = { 0x2222, 0x2201 },
+		.name = "SPANSION S29GL256[PN]",
+		.size = SZ_32M,
+		.use_dq5 = 1,
+		.use_ext_dev_id = 1,
+		.use_write_buffer = 1,
+		.need_tpoll_delay = 1,
+
+		.regions = {
+			{ .offset = 0x0, .size = SZ_128K, .count = 256 },
+			{ .count = 0 },
+		},
+	 },
+
+	{
+		.mfr_id = MANUFACTURER_SPANSION,
+		.dev_id = SPANSION_GENERIC,
+		.ext_dev_id = { 0x2221, 0x2201 },
+		.name = "SPANSION S29GL128P",
+		.size = SZ_16M,
+		.use_dq5 = 1,
+		.use_ext_dev_id = 1,
+		.use_write_buffer = 1,
+		.need_tpoll_delay = 1,
+
+		.regions = {
+			{ .offset = 0x0, .size = SZ_128K, .count = 128 },
+		},
+	},
+
+	{
+		.mfr_id = MANUFACTURER_ATMEL,
+		.dev_id = AT49BV322A,
+		.name = "ATMEL AT49BV322A (bottom)",
+		.size = SZ_4M,
+		.use_dq5 = 1,
+		.need_tpoll_delay = 0,
+
+		.regions = {
+			{ .offset = 0x0, .size = SZ_8K, .count = 8 },
+			{ .offset = 0x10000, .size = SZ_64K, .count = 63 },
+			{ .count = 0 },
+		},
+	},
+
+
+	{
+		.mfr_id = MANUFACTURER_SST,
+		.dev_id = SST39VF3201,
+		.name = "SST 39VF3201",
+		.size = SZ_4M,
+		.use_dq5 = 0,
+		.need_tpoll_delay = 0,
+
+		.regions = {
+			{ .offset = 0x0, .size = SZ_4K, .count = 1024 },
+			{ .count = 0 },
+		},
+	},
+
+	{
+		.mfr_id = MANUFACTURER_SST,
+		.dev_id = SST39VF3201_REVB,
+		.name = "SST 39VF3201 (rev B)",
+		.size = SZ_4M,
+		.use_dq5 = 0,
+		.need_tpoll_delay = 0,
+
+		.regions = {
+			{ .offset = 0x0, .size = SZ_4K, .count = 1024 },
+			{ .count = 0 },
+		},
+	},
+
+	{
+		.mfr_id = MANUFACTURER_SST,
+		.dev_id = SST39VF6401,
+		.name = "SST 39VF6401",
+		.size = SZ_8M,
+		.use_dq5 = 0,
+		.need_tpoll_delay = 0,
+
+		.regions = {
+			{ .offset = 0x0, .size = SZ_4K, .count = 2048 },
+			{ .count = 0 },
+		},
+	},
+
+
+	{
+		.mfr_id = MANUFACTURER_MACRONIX,
+		.dev_id = MX29LV320DT,
+		.name = "MX 29LV320DT (top)",
+		.size = SZ_4M,
+		.use_dq5 = 1,
+		.need_tpoll_delay = 0,
+
+		.regions = {
+			{ .offset = 0x0, .size = SZ_64K, .count = 63 },
+			{ .offset = 0x3f0000, .size = SZ_8K, .count = 8 },
+			{ .count = 0 },
+		},
+	},
+
+	/* end of list */
+	{
+		.mfr_id = 0,
+	},
+};
+
+
+/*
+ * send given command to flash wrt its width
+ */
+static uint32_t __amd_swizzle_addr(struct fbxmtd_dev_map *map, uint32_t addr)
+{
+	return addr << (map->flash_width - 1);
+}
+
+static void __amd_unlock(struct fbxmtd_dev_map *map)
+{
+	fbxmtd_bus_width_write(map, __amd_swizzle_addr(map, ADDR_UNLOCK1),
+			       CMD_UNLOCK_DATA_1);
+	fbxmtd_bus_width_write(map, __amd_swizzle_addr(map, ADDR_UNLOCK2),
+			       CMD_UNLOCK_DATA_2);
+}
+
+static void amd_reset(struct fbxmtd_dev_map *map)
+{
+	fbxmtd_bus_width_write(map, 0, CMD_RESET_DATA);
+}
+
+static void amd_cmd(struct fbxmtd_dev_map *map, uint32_t cmd)
+{
+	__amd_unlock(map);
+	fbxmtd_bus_width_write(map, __amd_swizzle_addr(map, ADDR_UNLOCK1),
+			       cmd);
+}
+
+static void amd_cmd_addr(struct fbxmtd_dev_map *map, uint32_t addr,
+			 uint32_t cmd)
+{
+	__amd_unlock(map);
+	fbxmtd_bus_width_write(map, addr, cmd);
+}
+
+/*
+ * poll status bit waiting for operation to finish
+ */
+static int amd_status_poll(struct fbxmtd_dev *dev, uint32_t offset,
+			   uint16_t data)
+{
+	struct amd_flash_info *info;
+	unsigned long timeout;
+
+	info = (struct amd_flash_info *)dev->priv_data;
+	if (info->need_tpoll_delay)
+		udelay(5);
+
+	timeout = jiffies + POLL_TIMEOUT;
+	do {
+		uint16_t flag;
+
+		flag = fbxmtd_bus_width_read(&dev->map, offset);
+		if ((flag & 0x80) == (data & 0x80)) {
+			return 0;
+		}
+
+		if (info->use_dq5 && (flag & 0x20)) {
+			flag = fbxmtd_bus_width_read(&dev->map, offset);
+			return ((flag & 0x80) == (data & 0x80)) ? 0 : 1;
+		}
+
+		if (need_resched())
+			yield();
+
+	} while (time_before(jiffies, timeout));
+
+	printk(KERN_ERR PFX "poll: timeout !\n");
+	return -ETIMEDOUT;
+}
+
+/*
+ * erase chip
+ */
+static int amd_erase_chip(struct fbxmtd_dev *dev)
+{
+	printk(KERN_INFO PFX "Erasing chip...\n");
+
+	amd_cmd(&dev->map, CMD_UNLOCK_ERASE);
+	amd_cmd(&dev->map, CMD_CHIP_ERASE);
+
+	if (amd_status_poll(dev, 0, 0xffff) < 0) {
+		printk(KERN_ERR PFX "Chip erase failed at 0x%.8x\n",
+		       (uint32_t)dev->map.base);
+		amd_reset(&dev->map);
+		return -EIO;
+	}
+	amd_reset(&dev->map);
+
+	return 0;
+}
+
+/*
+ * erase sector at given offset
+ */
+static int amd_erase_sector(struct fbxmtd_dev *dev, uint32_t offset)
+{
+	struct amd_flash_info *info;
+
+	info = (struct amd_flash_info *)dev->priv_data;
+
+	amd_cmd(&dev->map, CMD_UNLOCK_ERASE);
+	amd_cmd_addr(&dev->map, offset, CMD_SECTOR_ERASE);
+
+	if (amd_status_poll(dev, offset, 0xffff) < 0) {
+		printk(KERN_ERR PFX "Sector erase failed at 0x%.8x\n",
+		       (uint32_t)(dev->map.base + offset));
+		amd_reset(&dev->map);
+		return -EIO;
+	}
+	amd_reset(&dev->map);
+
+	return 0;
+}
+
+/*
+ * program data in buf at requested offset using write buffer method
+ * count is assumed to be % 32
+ */
+static int amd_program_buffer(struct fbxmtd_dev *dev, uint32_t offset,
+			      const uint8_t *buf, size_t count)
+{
+	int status = 0;
+	uint32_t sec_offset;
+
+	sec_offset = offset;
+	while (count > 0) {
+		unsigned int word_count;
+		uint32_t data, last_offset;
+		int i;
+
+		/* send write to buffer at sector address */
+		amd_cmd_addr(&dev->map, sec_offset, CMD_WRITE_TO_BUFFER);
+
+		/* send number of words to be programmed minus 1 */
+		word_count = 32 / dev->map.flash_width;
+		fbxmtd_bus_width_write(&dev->map, sec_offset, word_count - 1);
+
+		data = 0;
+		for (i = 0; i < word_count; i++) {
+			const uint8_t *p;
+
+			/* prevent unaligned access on buf */
+			p = buf + (i * dev->map.flash_width);
+			data = fbxmtd_get_bus_word(&dev->map, p);
+
+			/* try to program requested data */
+			fbxmtd_bus_width_write(&dev->map, offset + i * 2, data);
+		}
+
+		/* send program buffer at sector address */
+		fbxmtd_bus_width_write(&dev->map,
+				       sec_offset, CMD_PROGRAM_BUFFER);
+
+		/* poll on last offset / data */
+		last_offset = offset + 32 - dev->map.flash_width;
+		status = amd_status_poll(dev, last_offset, data);
+
+		if (status < 0) {
+			printk(KERN_ERR PFX "write buffer failed at offset "
+			       "0x%08x\n", offset);
+			amd_cmd(&dev->map, CMD_WRITE_TO_BUFFER_RESET);
+			return status;
+		}
+
+		offset += 32;
+		buf += 32;
+		count -= 32;
+	}
+
+	amd_reset(&dev->map);
+
+	return 0;
+}
+
+/*
+ * program data in buf at requested offset
+ */
+static int amd_program(struct fbxmtd_dev *dev, uint32_t offset,
+		       const uint8_t *buf, size_t count)
+{
+	struct amd_flash_info *info;
+	int status = 0;
+
+	/* sanity check */
+	if (offset % dev->map.flash_width) {
+		printk(KERN_ERR PFX "program offset must be bus aligned !\n");
+		return -EIO;
+	}
+
+	if (count % dev->map.flash_width) {
+		printk(KERN_ERR PFX "program count must be bus aligned !\n");
+		return -EIO;
+	}
+
+	info = (struct amd_flash_info *)dev->priv_data;
+
+	/* if  write buffer  is allowed  and  data to  program is  big
+	 * enough, then do it */
+	if (info->use_write_buffer && (count % 32) == 0)
+		return amd_program_buffer(dev, offset, buf, count);
+
+	while (count > 0) {
+		uint32_t data;
+
+		/* prevent unaligned access on buf */
+		data = fbxmtd_get_bus_word(&dev->map, buf);
+
+		/* no need to program in case all bits are set */
+		if (fbxmtd_bus_word_equal(&dev->map, data, 0xffffffff))
+			goto next;
+
+		/* try to program requested data */
+		amd_cmd(&dev->map, CMD_PROGRAM_UNLOCK_DATA);
+		fbxmtd_bus_width_write(&dev->map, offset, data);
+		status = amd_status_poll(dev, offset, data);
+		if (status < 0) {
+			printk(KERN_ERR PFX "program failed at offset "
+			       "0x%08x\n", offset);
+			amd_reset(&dev->map);
+			return status;
+		}
+
+next:
+		offset += dev->map.flash_width;
+		buf += dev->map.flash_width;
+		count -= dev->map.flash_width;
+	}
+	amd_reset(&dev->map);
+
+	return 0;
+}
+
+/*
+ * Probe amd flash and return flash structure if found in table
+ */
+static const struct amd_flash_info *amd_probe(struct fbxmtd_dev_map *map)
+{
+	uint32_t mfr_id;
+	uint32_t dev_id;
+	uint32_t ext_id[2];
+	int i;
+
+	/* recover from bad state */
+	amd_cmd(map, CMD_WRITE_TO_BUFFER_RESET);
+	amd_reset(map);
+
+	/* read flash id */
+	amd_cmd(map, CMD_AUTOSELECT_DATA);
+	mfr_id = fbxmtd_bus_width_read(map, map->flash_width *
+				       ADDR_MANUFACTURER);
+	dev_id = fbxmtd_bus_width_read(map, map->flash_width *
+				       ADDR_DEVICE_ID);
+	ext_id[0] = fbxmtd_bus_width_read(map, map->flash_width *
+					  ADDR_EXT_DEVICE_ID);
+	ext_id[1] = fbxmtd_bus_width_read(map, map->flash_width *
+					  (ADDR_EXT_DEVICE_ID + 1));
+
+	/* return to read mode */
+	amd_reset(map);
+
+	for (i = 0; amd_flash_infos[i].mfr_id != 0; i++) {
+		const struct amd_flash_info *info = &amd_flash_infos[i];
+
+		if (mfr_id == info->mfr_id && dev_id == info->dev_id) {
+
+			if (info->use_ext_dev_id &&
+			    (ext_id[0] != info->ext_dev_id[0] ||
+			     ext_id[1] != info->ext_dev_id[1]))
+				continue;
+
+			printk(KERN_INFO PFX "Probed %s flash at 0x%08x, "
+			       "%d bit, size %ukB\n",
+			       info->name, (uint32_t)map->base,
+			       8 * (1 << (map->flash_width - 1)),
+			       info->size / 1024);
+			if (info->use_write_buffer)
+				printk(KERN_INFO PFX
+				       " -> using write buffer programming\n");
+			return info;
+		}
+	}
+
+	if (mfr_id != 0xff && dev_id != 0xff) {
+		printk(KERN_NOTICE PFX "unknown flash at 0x%08x (man:%04x "
+		       "dev:%04x)\n", (uint32_t)map->base, mfr_id, dev_id);
+	}
+	return NULL;
+}
+
+/*
+ * return region information of device
+ */
+static struct fbxmtd_region *
+amd_get_region(struct fbxmtd_dev *dev)
+{
+	struct amd_flash_info *info;
+
+	info = (struct amd_flash_info *)dev->priv_data;
+	return info->regions;
+}
+
+/*
+ * return region information of device
+ */
+static uint32_t
+amd_get_size(struct fbxmtd_dev *dev)
+{
+	struct amd_flash_info *info;
+
+	info = (struct amd_flash_info *)dev->priv_data;
+	return info->size;
+}
+
+/*
+ * probe for an AMD flash and create mtd device if found
+ */
+struct fbxmtd_dev *fbxmtd_core_amd_probe(dma_addr_t base_phys,
+					 unsigned int flash_width)
+{
+	const struct amd_flash_info *info;
+	struct fbxmtd_dev_map map;
+	struct fbxmtd_dev *dev;
+	uint8_t *base_remap;
+
+	/* temporary remap base until we know full size */
+	if (!(base_remap = ioremap((unsigned long)base_phys, 0x20000))) {
+		printk(KERN_ERR PFX "first ioremap failed\n");
+		return NULL;
+	}
+
+	/* create temporary mapping during probe */
+	map.base = base_remap;
+	map.base_phys = base_phys;
+	map.flash_width = flash_width;
+
+	if ((info = amd_probe(&map)) == NULL) {
+		iounmap(base_remap);
+		return NULL;
+	}
+	iounmap(base_remap);
+
+	if ((dev = kmalloc(sizeof (struct fbxmtd_dev), GFP_KERNEL)) == NULL)
+		return NULL;
+
+	memset(dev, 0, sizeof (struct fbxmtd_dev));
+
+	dev->erase = amd_erase_sector;
+	dev->program = amd_program;
+	dev->chip_erase = amd_erase_chip;
+	dev->get_region_info = amd_get_region;
+	dev->get_size = amd_get_size;
+	dev->priv_data = (void *)info;
+
+	return dev;
+}
+
+EXPORT_SYMBOL(fbxmtd_core_amd_probe);
diff -Nruw linux-2.6.20.14-fbx/drivers/fbxmtd./fbxmtd_core_amd.h linux-2.6.20.14-fbx/drivers/fbxmtd/fbxmtd_core_amd.h
--- linux-2.6.20.14-fbx/drivers/fbxmtd./fbxmtd_core_amd.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/drivers/fbxmtd/fbxmtd_core_amd.h	2011-09-26 15:07:54.388835397 +0200
@@ -0,0 +1,78 @@
+
+#ifndef FBXMTD_CORE_AMD_H_
+# define FBXMTD_CORE_AMD_H_
+
+#define ADDR_MANUFACTURER		0x0000
+#define ADDR_DEVICE_ID			0x0001
+#define ADDR_SECTOR_LOCK		0x0002
+#define ADDR_HANDSHAKE			0x0003
+#define ADDR_EXT_DEVICE_ID		0x000E
+#define ADDR_UNLOCK1			0x5555
+#define ADDR_UNLOCK2			0xAAAA
+
+#define CMD_CHIP_ERASE			0x0010
+#define CMD_UNLOCK_BYPASS_MODE		0x0020
+#define CMD_SECTOR_ERASE		0x0030
+#define CMD_UNLOCK_DATA_1		0x00AA
+#define CMD_UNLOCK_DATA_2		0x0055
+#define CMD_UNLOCK_SECTOR		0x0060
+#define CMD_UNLOCK_ERASE		0x0080
+#define CMD_AUTOSELECT_DATA		0x0090
+#define CMD_PROGRAM_UNLOCK_DATA		0x00A0
+#define CMD_WRITE_TO_BUFFER		0x0025
+#define CMD_PROGRAM_BUFFER		0x0029
+#define CMD_SET_CONFIG			0x00D0
+#define CMD_RESET_DATA			0x00F0
+#define CMD_WRITE_TO_BUFFER_RESET	0x00F0
+
+#define D0_MASK				(0x0001 << 0)
+#define D1_MASK				(0x0001 << 1)
+#define D2_MASK				(0x0001 << 2)
+#define D3_MASK				(0x0001 << 3)
+#define D4_MASK				(0x0001 << 4)
+#define D5_MASK				(0x0001 << 5)
+#define D6_MASK				(0x0001 << 6)
+#define D7_MASK				(0x0001 << 7)
+
+
+#define MANUFACTURER_AMD		0x0001
+#define MANUFACTURER_FUJITSU		0x0004
+#define MANUFACTURER_ATMEL		0x001f
+#define MANUFACTURER_SPANSION		0x0001
+#define MANUFACTURER_ST			0x0020
+#define MANUFACTURER_MACRONIX		0x00C2
+#define MANUFACTURER_SST		0x00bf
+
+/* ATMEL */
+#define AT49BV322A			0x00c8
+
+/* Macronix */
+#define MX29LV320DT			0x22a7
+#define MX29LV320DB			0x22a8
+
+/* Spansion/AMD */
+#define AM29LV040B			0x004f
+#define SPANSION_GENERIC		0x227E
+
+/* SST */
+#define SST39VF3201			0x235B
+#define SST39VF3201_REVB		0x235C
+#define SST39VF6401			0x236B
+
+#define MAX_REGION	4
+
+struct amd_flash_info
+{
+	uint16_t mfr_id;
+	uint16_t dev_id;
+	uint16_t ext_dev_id[2];
+	char *name;
+	uint32_t size;
+	int use_dq5;
+	int use_ext_dev_id;
+	int use_write_buffer;
+	int need_tpoll_delay;
+	struct fbxmtd_region regions[MAX_REGION + 1];
+};
+
+#endif /* !FBXMTD_CORE_AMD_H_ */
diff -Nruw linux-2.6.20.14-fbx/drivers/fbxmtd./fbxmtd_core.c linux-2.6.20.14-fbx/drivers/fbxmtd/fbxmtd_core.c
--- linux-2.6.20.14-fbx/drivers/fbxmtd./fbxmtd_core.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/drivers/fbxmtd/fbxmtd_core.c	2011-09-26 15:07:54.388835397 +0200
@@ -0,0 +1,845 @@
+/*
+ * Freebox Memory Technology Device driver
+ *
+ * Allow transparent access to flash (handle read modify erase write),
+ * and  partitionning of  device.  Read /  write  access are  mutually
+ * exclusive.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/fbxdmamux.h>
+#include <asm/io.h>
+
+#include <linux/fbxmtd.h>
+
+#include "fbxmtd_priv.h"
+
+#define PFX	"fbxmtd: "
+
+/*
+ * notifier stuffs
+ */
+static struct list_head notifiers;
+static struct semaphore notifiers_mutex;
+
+static void fbxmtd_run_notifier(struct fbxmtd_part *part, uint32_t event)
+{
+	struct fbxmtd_notifier *n;
+
+	down(&notifiers_mutex);
+	list_for_each_entry(n, &notifiers, list) {
+		if (n->event_mask & event) {
+			n->cb(n->cb_data, part, event);
+		}
+	}
+	up(&notifiers_mutex);
+}
+
+int fbxmtd_register_notifier(void (*cb)(void *, struct fbxmtd_part *,
+					uint32_t),
+			     void *cb_data, uint32_t mask)
+{
+	struct fbxmtd_notifier *n;
+
+	if (!(n = kmalloc(sizeof (struct fbxmtd_notifier), GFP_KERNEL)))
+		return 1;
+	n->cb = cb;
+	n->cb_data = cb_data;
+	n->event_mask = mask;
+	INIT_LIST_HEAD(&n->list);
+
+	down(&notifiers_mutex);
+	list_add_tail(&n->list, &notifiers);
+	up(&notifiers_mutex);
+
+	return 0;
+}
+
+void fbxmtd_unregister_notifier(void (*cb)(void *, struct fbxmtd_part *,
+					   uint32_t))
+{
+	struct fbxmtd_notifier *n, *n2;
+
+	down(&notifiers_mutex);
+	list_for_each_entry_safe(n, n2, &notifiers, list) {
+		if (cb == n->cb) {
+			list_del(&n->list);
+			kfree(n);
+		}
+	}
+	up(&notifiers_mutex);
+}
+
+
+/*
+ * mtd device list
+ */
+static struct fbxmtd_dev *mtddevs[FBXMTD_MAX_DEVICES];
+static int mtddevs_count = 0;
+static struct semaphore mtddevs_mutex;
+
+/*
+ * helper for list access, they assume list lock is taken
+ */
+static int _add_device(struct fbxmtd_dev *dev)
+{
+	struct fbxmtd_dev *p;
+	int	i, first;
+
+	/* check for room */
+	if (mtddevs_count == FBXMTD_MAX_DEVICES) {
+		printk(KERN_ERR PFX "FBXMTD_MAX_DEVICES reached\n");
+		return 1;
+	}
+
+	/* check for name clash */
+	first = -1;
+	for (i = 0; i < FBXMTD_MAX_DEVICES; i++) {
+		p = mtddevs[i];
+		if (p == NULL) {
+			/* first empty slot */
+			if (first == -1)
+				first = i;
+			continue;
+		}
+		if (!strcmp(p->name, dev->name)) {
+			printk(KERN_ERR PFX "duplicate partition name "
+			       "\"%s\"\n", p->name);
+			return 1;
+		}
+	}
+
+	mtddevs[first] = dev;
+	dev->idx = first;
+	mtddevs_count++;
+	__module_get(THIS_MODULE);
+	init_MUTEX(&dev->sem);
+	atomic_set(&dev->refcount, 1);
+
+	return 0;
+}
+
+static struct fbxmtd_part *_get_part(unsigned int dev_idx,
+				     unsigned int part_idx)
+{
+	struct fbxmtd_dev *p;
+
+	/* find device */
+	p = mtddevs[dev_idx];
+
+	if (!p || p->dead)
+		return NULL;
+
+	/* find partition */
+	if (part_idx >= p->part_count) {
+		return NULL;
+	}
+
+	atomic_inc(&p->refcount);
+	return &p->parts[part_idx];
+}
+
+static struct fbxmtd_part *_get_part_by_name(unsigned int dev_idx,
+					     const char *part_name)
+{
+	struct fbxmtd_dev *p;
+	int i;
+
+	/* find device */
+	p = mtddevs[dev_idx];
+
+	if (!p || p->dead)
+		return NULL;
+
+	/* find partition */
+	for (i = 0; i < p->part_count; i++) {
+		if (!strcmp(p->parts[i].name, part_name)) {
+			atomic_inc(&p->refcount);
+			return &p->parts[i];
+		}
+	}
+	return NULL;
+}
+
+
+static void _put_device(struct fbxmtd_dev *dev)
+{
+	int i;
+
+	if (!atomic_dec_and_test(&dev->refcount))
+		return;
+
+	/* out of the list */
+	for (i = 0; i < FBXMTD_MAX_DEVICES; i++) {
+		if (mtddevs[i] == dev) {
+			mtddevs[i] = NULL;
+			break;
+		}
+	}
+	mtddevs_count--;
+
+	/* free it */
+	for (i = 0; i < dev->part_count; i++) {
+		if (dev->parts[i].name)
+			kfree(dev->parts[i].name);
+	}
+
+	if (dev->map.base) {
+		iounmap(dev->map.base);
+	}
+	kfree(dev->name);
+	kfree(dev);
+	module_put(THIS_MODULE);
+}
+
+/*
+ * list accessor
+ */
+static int fbxmtd_add_device(struct fbxmtd_dev *dev)
+{
+	int res;
+
+	down(&mtddevs_mutex);
+	res = _add_device(dev);
+	up(&mtddevs_mutex);
+	return res;
+}
+
+struct fbxmtd_part *fbxmtd_get_part(unsigned int dev_idx,
+				    unsigned int part_idx)
+{
+	struct fbxmtd_part *part;
+
+	if (down_interruptible(&mtddevs_mutex))
+		return NULL;
+	part = _get_part(dev_idx, part_idx);
+	up(&mtddevs_mutex);
+	return part;
+}
+
+struct fbxmtd_part *fbxmtd_get_part_by_name(unsigned int dev_idx,
+					    const char *part_name)
+{
+	struct fbxmtd_part *part;
+
+	if (down_interruptible(&mtddevs_mutex))
+		return NULL;
+	part = _get_part_by_name(dev_idx, part_name);
+	up(&mtddevs_mutex);
+	return part;
+}
+
+void fbxmtd_put_device(struct fbxmtd_dev *dev)
+{
+	down(&mtddevs_mutex);
+	_put_device(dev);
+	up(&mtddevs_mutex);
+}
+
+void fbxmtd_put_part(struct fbxmtd_part *part)
+{
+	down(&mtddevs_mutex);
+	_put_device(part->dev);
+	up(&mtddevs_mutex);
+}
+
+/*
+ * call  given callback for  each existing  partitions, if  cb returns
+ * true, a reference on partition is taken for it
+ */
+int fbxmtd_foreach_part(int (cb)(void *, struct fbxmtd_part *),
+			void *cb_data)
+{
+	int i, j;
+
+	down(&mtddevs_mutex);
+
+	for (i = 0; i < FBXMTD_MAX_DEVICES; i++) {
+		struct fbxmtd_dev *p;
+
+		p = mtddevs[i];
+
+		if (!p || p->dead)
+			continue;
+
+		for (j = 0; j < p->part_count; j++)
+			if (cb(cb_data, &p->parts[j])) {
+				up(&mtddevs_mutex);
+				return 1;
+			}
+	}
+	up(&mtddevs_mutex);
+	return 0;
+}
+
+
+/*
+ * read from fbxmtd device
+ */
+int fbxmtd_read_dev(struct fbxmtd_dev *dev, uint32_t offset, char *buffer,
+		    unsigned int count)
+{
+	uint32_t size;
+
+	/* eof if device is dead */
+	if (dev->dead)
+		return 0;
+
+	size = dev->get_size(dev);
+
+	/* access outside the device range is an error */
+	if (offset > size || count > size - offset)
+		return -EINVAL;
+
+	if (down_interruptible(&dev->sem))
+		return -ERESTARTSYS;
+
+	memcpy_fromio(buffer, dev->map.base + offset, count);
+	up(&dev->sem);
+
+	return count;
+}
+
+/*
+ * find sector or next sector boundary for current offset
+ */
+static int find_sector_boundary(struct fbxmtd_dev *dev,
+				uint32_t offset, int want_next_sector,
+				uint32_t *boundary)
+{
+	struct fbxmtd_region *regs;
+	uint32_t r_offset, i;
+
+	regs = dev->get_region_info(dev);
+
+	r_offset = 0;
+	for (i = 0; regs[i].size != 0; i++) {
+		unsigned int sector;
+
+		if (offset < regs[i].offset ||
+		    (offset >= regs[i].offset + regs[i].count * regs[i].size))
+			continue;
+
+		/* this is the right region, get sector number */
+		sector = (offset - regs[i].offset) / regs[i].size;
+
+		if (want_next_sector) {
+			/* check if this was last sector of region */
+			if (sector < regs[i].count - 1)
+				sector++;
+			else {
+				/* yes, we want first sector of next
+				 * region if it exists */
+				i++;
+				if (!regs[i].size)
+					return -EINVAL;
+				sector = 0;
+			}
+		}
+
+		*boundary = regs[i].offset + sector * regs[i].size;
+		return 0;
+	}
+
+	/* offset is outside flash */
+	return -EINVAL;
+}
+
+int fbxmtd_find_sector_boundary(struct fbxmtd_dev *dev,
+				uint32_t offset, uint32_t *boundary)
+{
+	return find_sector_boundary(dev, offset, 0, boundary);
+}
+
+int fbxmtd_find_next_sector_boundary(struct fbxmtd_dev *dev,
+				     uint32_t offset, uint32_t *boundary)
+{
+	return find_sector_boundary(dev, offset, 1, boundary);
+}
+
+
+#ifdef CONFIG_FREEBOX_MTD_USE_DMAMUX
+static int dma_transfer(uint8_t *dst, dma_addr_t hw_src, unsigned int count)
+{
+	struct fbxdmamux_req *req;
+
+	req = fbxdmamux_req_from_pool();
+	if (!req)
+		return 1;
+
+	req->chan_cookie = 0;
+	req->priority = 0;
+	req->hw_src = hw_src;
+	req->virt_dst = dst;
+	req->len = count;
+	req->flags = FBXDMAMUX_FLAG_SRC_HW;
+	return fbxdmamux_submit_and_sleep(req, HZ * 60);
+}
+#endif
+
+/*
+ * read from fbxmtd partition
+ */
+int fbxmtd_read_part(struct fbxmtd_part *part, uint32_t offset, char *buffer,
+		     unsigned int count, int can_sleep)
+{
+	/* eof if device is dead */
+	if (part->dev->dead)
+		return 0;
+
+	/* access outside the range partition is an error */
+	if (offset > part->size || count > part->size - offset)
+		return -EINVAL;
+
+	if (!can_sleep) {
+		if (down_trylock(&part->dev->sem))
+			return -EWOULDBLOCK;
+	} else {
+		if (down_interruptible(&part->dev->sem))
+			return -ERESTARTSYS;
+	}
+	/* assume we can use it as memory mapped io */
+	offset += part->offset;
+
+#ifdef CONFIG_FREEBOX_MTD_USE_DMAMUX
+	/* use dma */
+	if (!can_sleep) {
+		up(&part->dev->sem);
+		return -EWOULDBLOCK;
+	}
+
+	/* if dma transfer is not possible or failed, fallback on memcpy */
+	if (virt_addr_valid(buffer)
+	    && dma_transfer(buffer, (part->dev->map.base_phys + offset),
+			    count) == 0) {
+		up(&part->dev->sem);
+		return count;
+	}
+	/* fallback */
+#endif
+
+	/* use memcpy */
+	memcpy_fromio(buffer, part->dev->map.base + offset, count);
+	up(&part->dev->sem);
+
+	return count;
+}
+
+
+/*
+ * write to fbxmtd partition
+ */
+int fbxmtd_write_part(struct fbxmtd_part *part, uint32_t offset, char *buffer,
+		      unsigned int count)
+{
+	struct fbxmtd_dev *dev;
+	struct fbxmtd_region *regs;
+	unsigned int total_len;
+
+	/* eof if device is dead */
+	if (part->dev->dead)
+		return 0;
+
+	/* check partition is rw */
+	if (part->rw == 0)
+		return -EBADF;
+
+	/* access outside the range of the partition is an error */
+	if (offset >= part->size)
+		return -EINVAL;
+	if (count > part->size - offset)
+		return -EFBIG;
+
+	/* fetch flash region information */
+	dev = part->dev;
+	regs = dev->get_region_info(dev);
+
+	/* calculate real offset in device */
+	offset = offset + part->offset;
+
+	/* start read/erase/modify/write loop */
+	total_len = 0;
+	while (count > 0) {
+		int		i, j, res, erase_needed, program_needed;
+		int		after_all_one;
+		uint32_t	r_offset, size;
+		uint8_t		*tbuf;
+
+		/* find flash region for this offset */
+		r_offset = 0;
+		for (i = 0; regs[i].size != 0; i++) {
+			if (offset < regs[i].offset ||
+			    (offset >= regs[i].offset +
+			     regs[i].count * regs[i].size))
+				continue;
+			/* this is the right region, get sector number */
+			res = (offset - regs[i].offset) / regs[i].size;
+			r_offset = regs[i].offset + res * regs[i].size;
+			break;
+		}
+
+		if (!regs[i].size) {
+			/* oops, no region found, region desc must be wrong*/
+			printk(KERN_ERR PFX "%s/%s: couldn't find associated "
+			       "region for offset %08x\n", dev->name,
+			       part->name, offset);
+			return -EIO;
+		}
+
+		/* read the current data */
+		if (!(tbuf = kmalloc(regs[i].size, GFP_KERNEL)))
+			return -ENOMEM;
+
+		/* size is the part of the data we will overwrite */
+		size = r_offset + regs[i].size - offset;
+		if (count < size)
+			size = count;
+
+		if (down_interruptible(&dev->sem))
+			return -ERESTARTSYS;
+
+		/* read whole sector */
+		memcpy_fromio(tbuf, dev->map.base + r_offset, regs[i].size);
+
+		/*
+		 * check if we  need to erase the sector,  this is the
+		 * case if there is at  least one bit in the modified data
+		 * that has been set.
+		 *
+		 * we use a simple XOR/AND to test this, a XOR between
+		 * old  and new  data  gives us  bits  that have  been
+		 * toggled.
+		 *
+		 * If a logical AND between this and the original data
+		 * gives the same, then  all toggled bits where set in
+		 * the original data, and no erase is needed.
+		 *
+		 * orig ^ new = toggled
+		 * orig & toggled = common_modified_bits
+		 * (common_modified_bits == toggled) -> no erase needed
+		 */
+		erase_needed = 0;
+		program_needed = 0;
+		after_all_one = 1;
+
+		for (j = 0; j < size; j++) {
+			uint8_t before, after, toggled;
+
+			before = tbuf[(offset - r_offset) + j];
+			after = buffer[j];
+
+			/*
+			 * remember  if any  new byte  value is  to be
+			 * different than 0xff
+			 */
+			if (after != 0xff)
+				after_all_one = 0;
+
+			if (before != after) {
+				/*
+				 * we want to change the byte value
+				 */
+				if (after == 0xff) {
+					/*
+					 * we want to change it to
+					 * 0xff, the only way to do
+					 * this is to erase the sector
+					 */
+					erase_needed = 1;
+				} else {
+					/*
+					 * we want to  set the byte to
+					 * anything  else  than  0xff,
+					 * this  imply programming the
+					 * sector, this may also imply
+					 * erasing  if some  bits need
+					 * to be changed from 0 to 1
+					 */
+					program_needed = 1;
+					toggled = before ^ after;
+					if ((before & toggled) != toggled)
+						erase_needed = 1;
+				}
+			}
+
+			/*
+			 * if  we decide  that erasing  the  sector is
+			 * needed then all previous data will be lost,
+			 * thus  if  any new  byte  is  to  be set  to
+			 * anything else  than 0xff, then  we have to
+			 * program after erasing.
+			 */
+			if (erase_needed && !after_all_one)
+				program_needed = 1;
+
+			if (program_needed && erase_needed)
+				break;
+		}
+
+		/* modify data */
+		memcpy(tbuf + (offset - r_offset), buffer, size);
+
+		/* erase sector if needed */
+		if (erase_needed && dev->erase(dev, r_offset)) {
+			up(&dev->sem);
+			kfree(tbuf);
+			printk(KERN_ERR PFX "%s/%s: erase failed at "
+			       "[0x%08x/%d]\n", dev->name,
+			       part->name, r_offset, regs[i].size);
+			return -EIO;
+		}
+
+		/* program it with the new data */
+		if (program_needed &&
+		    dev->program(dev, r_offset, tbuf, regs[i].size)) {
+			up(&dev->sem);
+			kfree(tbuf);
+			printk(KERN_ERR PFX "%s/%s: program failed at "
+			       "[0x%08x/%d]\n", dev->name,
+			       part->name, r_offset, regs[i].size);
+			return -EIO;
+		}
+
+		up(&dev->sem);
+		kfree(tbuf);
+
+		if (printk_ratelimit())
+			printk(KERN_DEBUG PFX "%s/%s: %s%s%s%soffset=0x%08x "
+			       "segment=[0x%08x/%d]\n", dev->name,
+			       part->name,
+			       erase_needed ? "ERASE" : "",
+			       (erase_needed && program_needed) ? "/" : "",
+			       program_needed ? "PRGM" : "",
+			       (erase_needed || program_needed) ? " " : "",
+			       offset, r_offset, regs[i].size);
+
+		count -= size;
+		total_len += size;
+		offset += size;
+		buffer += size;
+
+		/* give readers a chance */
+		if (need_resched())
+			yield();
+	}
+
+	return total_len;
+}
+
+
+/*
+ * add partitions to fbxmtd device
+ */
+int fbxmtd_set_partitions(struct fbxmtd_dev *dev, struct fbxmtd_part *parts,
+			  unsigned int count)
+{
+	unsigned int	i, j, size;
+	int res;
+
+	/* grab the queue lock, so  nobody can get the device while we
+	 * are changing its partitions */
+	down(&mtddevs_mutex);
+	res = 0;
+
+	if (dev->dead) {
+		res = -ENOENT;
+		goto out;
+	}
+
+	/* can't (re)partition while device is in use */
+	if (atomic_read(&dev->refcount) > 1) {
+		printk(KERN_ERR PFX "device \"%s\" is busy\n", dev->name);
+		res = -EBUSY;
+		goto out;
+	}
+
+	/* check partitions */
+	size = dev->get_size(dev);
+	for (i = 0; i < count; i++) {
+
+		if (!parts[i].name[0]) {
+			printk(KERN_ERR PFX "invalid partition %d name\n", i);
+			res = -EINVAL;
+			goto out;
+		}
+
+		/* (size == - 1) means greatest possible size */
+		if (parts[i].size == -1)
+			parts[i].size = size - parts[i].offset;
+
+		if (parts[i].offset % 2) {
+			printk(KERN_ERR PFX "odd partition %d offset\n", i);
+			res = -EINVAL;
+			goto out;
+		}
+
+		if (parts[i].size % 2) {
+			printk(KERN_ERR PFX "odd partition %d size\n", i);
+			res = -EINVAL;
+			goto out;
+		}
+
+		if (parts[i].offset + parts[i].size > size) {
+			printk(KERN_ERR PFX "partition %d size too big\n", i);
+			res = -EINVAL;
+			goto out;
+		}
+	}
+
+	/* check all partition have different name */
+	for (i = 0; i < count; i++) {
+		for (j = 0; j < count; j++) {
+			if (i == j)
+				continue;
+			if (!strcmp(parts[i].name, parts[j].name)) {
+				printk(KERN_ERR PFX "duplicate partition "
+				       "name: %s\n", parts[i].name);
+				res = -EINVAL;
+				goto out;
+			}
+		}
+	}
+
+	/* partitions seems ok, replace previous one with new  */
+	for (i = 0; i < dev->part_count; i++) {
+		if (dev->parts[i].name) {
+			kfree(parts[i].name);
+			parts[i].name = NULL;
+		}
+	}
+
+	for (i = 0; i < count; i++) {
+		dev->parts[i] = parts[i];
+		dev->parts[i].name = kstrdup(parts[i].name, GFP_KERNEL);
+		dev->parts[i].dev = dev;
+		dev->parts[i].idx = i;
+	}
+	dev->part_count = count;
+
+out:
+	up(&mtddevs_mutex);
+
+	/* notify partition  change, only caller  may change partition
+	 * again,  so it  is  safe  to read  partition  table in  this
+	 * event */
+	for (i = 0; i < dev->part_count; i++)
+		fbxmtd_run_notifier(&dev->parts[i], FBXMTD_EVENT_ADD);
+
+	return res;
+}
+
+/*
+ * ask for device removal
+ */
+void fbxmtd_mark_dead_dev(struct fbxmtd_dev *dev)
+{
+	int i;
+
+	dev->dead = 1;
+	/* notify dead device */
+	for (i = 0; i < dev->part_count; i++)
+		fbxmtd_run_notifier(&dev->parts[i], FBXMTD_EVENT_DEAD);
+}
+
+
+/*
+ * probe for an fbxmtd device at specified address
+ */
+struct fbxmtd_dev *fbxmtd_probe(const char *name, dma_addr_t base_phys,
+				unsigned int flash_width)
+{
+	struct fbxmtd_dev *dev;
+
+	/* probe using all method we know */
+#ifdef CONFIG_FREEBOX_MTD_BACKEND_AMD
+	if ((dev = fbxmtd_core_amd_probe(base_phys, flash_width)))
+		goto found;
+#endif
+#ifdef CONFIG_FREEBOX_MTD_BACKEND_INTEL
+	if ((dev = fbxmtd_core_intel_probe(base_phys, flash_width)))
+		goto found;
+#endif
+	/* nothing found */
+	return NULL;
+
+found:
+	/* add the device */
+	if (!(dev->name = kstrdup(name, GFP_KERNEL))) {
+		printk(KERN_ERR PFX "kstrdup failed\n");
+		goto free;
+	}
+
+	/* create final flash mapping */
+	dev->map.base_phys = base_phys;
+	dev->map.flash_width = flash_width;
+	if (!(dev->map.base = ioremap_nocache((unsigned long)base_phys,
+					      dev->get_size(dev)))) {
+		printk(KERN_ERR PFX "ioremap failed\n");
+		goto free;
+	}
+
+	if (fbxmtd_add_device(dev)) {
+		printk(KERN_ERR PFX "can't add device \"%s\"\n", name);
+		goto free;
+	}
+
+	return dev;
+free:
+	if (dev->name)
+		kfree(dev->name);
+	if (dev->map.base)
+		iounmap(dev->map.base);
+	kfree(dev);
+	return NULL;
+}
+
+
+static int __init fbxmtd_init(void)
+{
+	printk(KERN_INFO PFX "Freebox Memory Technology Device driver\n");
+#ifdef CONFIG_FREEBOX_MTD_USE_DMAMUX
+	printk(KERN_INFO PFX " -> using fbxdmamux for read transfer\n");
+#endif
+
+	INIT_LIST_HEAD(&notifiers);
+	init_MUTEX(&mtddevs_mutex);
+	init_MUTEX(&notifiers_mutex);
+
+	return 0;
+}
+
+static void __exit fbxmtd_exit(void)
+{
+}
+
+
+module_init(fbxmtd_init);
+module_exit(fbxmtd_exit);
+
+EXPORT_SYMBOL(fbxmtd_probe);
+EXPORT_SYMBOL(fbxmtd_mark_dead_dev);
+EXPORT_SYMBOL(fbxmtd_set_partitions);
+EXPORT_SYMBOL(fbxmtd_foreach_part);
+
+EXPORT_SYMBOL(fbxmtd_register_notifier);
+EXPORT_SYMBOL(fbxmtd_unregister_notifier);
+
+EXPORT_SYMBOL(fbxmtd_read_dev);
+EXPORT_SYMBOL(fbxmtd_read_part);
+EXPORT_SYMBOL(fbxmtd_write_part);
+
+EXPORT_SYMBOL(fbxmtd_find_sector_boundary);
+EXPORT_SYMBOL(fbxmtd_find_next_sector_boundary);
+
+EXPORT_SYMBOL(fbxmtd_get_part_by_name);
+EXPORT_SYMBOL(fbxmtd_get_part);
+EXPORT_SYMBOL(fbxmtd_put_part);
+EXPORT_SYMBOL(fbxmtd_put_device);
+
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0");
+MODULE_AUTHOR("Maxime Bizon <mbizon@freebox.fr>");
diff -Nruw linux-2.6.20.14-fbx/drivers/fbxmtd./fbxmtd_core_io.c linux-2.6.20.14-fbx/drivers/fbxmtd/fbxmtd_core_io.c
--- linux-2.6.20.14-fbx/drivers/fbxmtd./fbxmtd_core_io.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/drivers/fbxmtd/fbxmtd_core_io.c	2011-09-26 15:07:54.388835397 +0200
@@ -0,0 +1,120 @@
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <asm/io.h>
+
+#include <linux/fbxmtd.h>
+#include "fbxmtd_priv.h"
+
+
+#define FLASH_IO_READ_8(x)	__raw_readb((void *)x)
+#define FLASH_IO_READ_16(x)	__raw_readw((void *)x)
+#define FLASH_IO_READ_32(x)	__raw_readl((void *)x)
+
+#define FLASH_IO_WRITE_8(x,d)	__raw_writeb(d, (void *)x)
+#define FLASH_IO_WRITE_16(x,d)	__raw_writew(d, (void *)x)
+#define FLASH_IO_WRITE_32(x,d)	__raw_writel(d, (void *)x)
+
+/*
+ * read/write data by doing a flash bus width access
+ */
+uint32_t fbxmtd_bus_width_read(struct fbxmtd_dev_map *map,
+			       uint32_t offset)
+{
+	uint8_t *address;
+	uint32_t val;
+
+	address = map->base + offset;
+
+	switch (map->flash_width) {
+	case 1:
+		val = (uint32_t)FLASH_IO_READ_8(address);
+		break;
+
+	case 2:
+		val = (uint32_t)FLASH_IO_READ_16(address);
+		break;
+
+	case 4:
+		val = (uint32_t)FLASH_IO_READ_32(address);
+		break;
+
+	default:
+		printk(KERN_ERR "flash width not supported\n");
+		return 0;
+	}
+	return val;
+}
+
+void fbxmtd_bus_width_write(struct fbxmtd_dev_map *map, uint32_t offset,
+			    uint32_t data)
+{
+	uint8_t *address;
+
+	address = map->base + offset;
+
+	switch (map->flash_width) {
+	case 1:
+		FLASH_IO_WRITE_8(address, data);
+		break;
+
+	case 2:
+		FLASH_IO_WRITE_16(address, data);
+		break;
+
+	case 4:
+		FLASH_IO_WRITE_32(address, data);
+		break;
+
+	default:
+		printk(KERN_ERR "flash width not supported\n");
+		break;
+	}
+}
+
+uint32_t fbxmtd_get_bus_word(struct fbxmtd_dev_map *map, const uint8_t *buf)
+{
+	uint32_t val;
+
+	switch (map->flash_width) {
+	case 1:
+		val = buf[0];
+		break;
+
+	case 2:
+		val = (buf[0] << 8) | buf[1];
+		val = be16_to_cpu(val);
+		break;
+
+	case 4:
+		val = (buf[0] << 24) | (buf[1] << 16) |
+			(buf[2] << 8) | buf[3];
+		val = be32_to_cpu(val);
+		break;
+
+	default:
+		printk(KERN_ERR "flash width not supported\n");
+		return 0;
+	}
+
+	return val;
+}
+
+int fbxmtd_bus_word_equal(struct fbxmtd_dev_map *map, uint32_t d1,
+			  uint32_t d2)
+{
+	switch (map->flash_width) {
+	case 1:
+		return ((d1 & 0xff) == (d2 & 0xff));
+
+	case 2:
+		return ((d1 & 0xffff) == (d2 & 0xffff));
+
+	case 4:
+		return ((d1 & 0xffffffff) == (d2 & 0xffffffff));
+
+	default:
+		printk(KERN_ERR "flash width not supported\n");
+		return 0;
+	}
+}
diff -Nruw linux-2.6.20.14-fbx/drivers/fbxmtd./fbxmtd_map_drv_generic.c linux-2.6.20.14-fbx/drivers/fbxmtd/fbxmtd_map_drv_generic.c
--- linux-2.6.20.14-fbx/drivers/fbxmtd./fbxmtd_map_drv_generic.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/drivers/fbxmtd/fbxmtd_map_drv_generic.c	2011-09-26 15:07:54.388835397 +0200
@@ -0,0 +1,440 @@
+/*
+ * fbxmtd_map_drv_generic.c for linux-freebox
+ * Created by <nschichan@freebox.fr> on Thu Jan 18 23:00:15 2007
+ * Freebox SA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/crc32.h>
+
+#include <fbximagetag.h>
+#include <linux/fbxmtd.h>
+
+#define PFX	"fbxmtd_map_drv_generic: "
+
+static struct fbxmtd_dev *dev = NULL;
+
+static struct fbxmtd_part partitions[FBXMTD_MAX_PART];
+uint32_t partition_count;
+
+struct cmplzma_header
+{
+	u32	dst;
+	u32	entry;
+	u32	len;
+};
+
+/*
+ * read imagetag at offset and set parts offset/size for romfs, this
+ * comes from the legacy fbxmtd map code.
+ */
+static void
+read_imagetag(struct fbxmtd_part *parent,
+	      struct fbxmtd_part *part,
+	      int check_crc, int skip_kernel)
+{
+	struct fbx_imagetag tag;
+	int ret;
+	int offset;
+
+	offset = parent->offset;
+
+	if (skip_kernel) {
+		/*
+		 * on fbx4, the CFE only know how to boot a cmplzma
+		 * compressed kernel image.
+		 *
+		 * the bank1 partition starts with a compressed kernel
+		 * image immediately followed by an image tag align on
+		 * a 4k page boundary. we skip the image here try to
+		 * look at an image tag right here.
+		 */
+		struct cmplzma_header hdr;
+
+		ret = fbxmtd_read_dev(dev, parent->offset, (u8*)&hdr,
+				      sizeof (hdr));
+		if (ret != sizeof (hdr))
+			printk(KERN_ERR PFX "%s: unable to read cmplzma "
+			       "header on at 0x%08x\n", parent->name,
+			       parent->offset);
+
+		offset += be32_to_cpu(hdr.len);
+
+		/* align offset on a 4k page boundary. */
+		offset &= ~0xfff;
+		offset += 0x1000;
+
+		printk(KERN_INFO PFX "image tag expected at 0x%08x\n", offset);
+	}
+
+	/* read the tag */
+	ret = fbxmtd_read_dev(dev, offset,
+			      (uint8_t *)&tag, sizeof (tag));
+	if (ret != sizeof(tag)) {
+		printk(KERN_ERR PFX "%s: unable to read image tag "
+		       "at 0x%08x\n", parent->name, offset);
+		return;
+	}
+
+	/* check the tag */
+	if (be32_to_cpu(tag.magic) != FBX_IMAGETAG_MAGIC) {
+		printk(KERN_NOTICE PFX "%s: invalid tag magic "
+		       "(0x%08x, expected 0x%08x)\n", parent->name,
+		       be32_to_cpu(tag.magic), FBX_IMAGETAG_MAGIC);
+		return;
+	}
+
+	if (!(be32_to_cpu(tag.flags) & FBX_IMAGETAG_FLAGS_HAS_FS)) {
+		printk(KERN_NOTICE PFX "%s: image has no FS\n", parent->name);
+		goto end;
+	}
+
+	if (check_crc)
+	{
+		unsigned char buf[512];
+		int i, len;
+		unsigned int size, crc = 0;
+
+		/* calculate CRC32 of whole  image minus the crc field
+		 * itself */
+		size = be32_to_cpu(tag.total_size);
+		for (i = 0; i < size; i += 512) {
+			/* read some data */
+			len = (size - i) > 512 ? 512 : size - i;
+			ret = fbxmtd_read_dev(dev, offset + i,
+					      buf, len);
+			if (ret != len) {
+				printk(KERN_ERR PFX
+				       "%s: unable to check crc\n",
+				       parent->name);
+				return;
+			}
+
+			/* skip image tag CRC32 field */
+			if (i == 0)
+				crc = crc32(crc, buf + 4, len - 4);
+			else
+				crc = crc32(crc, buf, len);
+		}
+
+		if (crc != be32_to_cpu(tag.crc32)) {
+			printk(KERN_NOTICE PFX "%s: invalid image CRC "
+			       "(0x%08x, expected 0x%08x)\n", parent->name,
+			       crc, be32_to_cpu(tag.crc32));
+			return;
+		}
+	}
+
+	/* set right offset for fs */
+	part->offset = offset + be32_to_cpu(tag.fs_offset);
+	part->size = be32_to_cpu(tag.fs_size);
+	/* adjust off partition */
+	if (part->size % 2) {
+		part->size++;
+	}
+
+	/*
+	 * sanity check: check that fs partition ends before the
+	 * parent end.
+	 */
+	if (offset + part->size > offset + parent->size) {
+		printk(KERN_ERR PFX "skipping partition %s, partition ends "
+		       "after parent end, makes no sense.\n", parent->name);
+		part->size = 0;
+		part->offset = 0;
+	}
+
+end:
+	tag.name[127] = 0;
+	tag.builder[31] = 0;
+	printk(KERN_INFO PFX "%s: tag \"%s\" by \"%s\"\n", parent->name,
+	       tag.name, tag.builder);
+}
+
+struct fbxmtd_platform_part *
+get_partition_by_name(const char *name, struct fbxmtd_platform_part *parts,
+		      unsigned int num)
+{
+	int i;
+
+	if (name == NULL)
+		return NULL;
+
+	for (i = 0; i < num; ++i) {
+		if (!strcmp(name, parts[i].name))
+			return &parts[i];
+	}
+	return NULL;
+}
+
+static int
+fbxmtd_map_drv_generic_probe(struct platform_device *pdev)
+{
+	int res;
+	uint32_t i;
+	struct fbxmtd_platform_data *pdat;
+	struct fbxmtd_platform_part *local_parts = NULL;
+	uint32_t size;
+
+	printk(KERN_DEBUG PFX "probe.\n");
+
+	pdat = pdev->dev.platform_data;
+
+	/* by default ... */
+	pdat->status = E_FBXMTD_FAULTY;
+
+	/* sanity check on platform data */
+	if (pdat == NULL) {
+		printk(KERN_ERR PFX "fbxmtd platform data is missing.\n");
+		return -ENODEV;
+	}
+	if (pdat->num_parts == 0 || pdat->parts == NULL) {
+		printk(KERN_ERR PFX "fbxmtd platform data is missing a "
+		       "partition table.\n");
+		return -ENODEV;
+	}
+
+	dev = fbxmtd_probe(pdat->name, pdat->base, pdat->width);
+	if (dev == NULL)
+		return -ENODEV;
+	size = dev->get_size(dev);
+	pdat->size = size;
+
+	printk(KERN_INFO PFX "flash has %iM size.\n", size >> 20);
+
+	/*
+	 * pdat->parts is const and it is good thing. however we need
+	 * to change fields, so kmalloc local_parts and memcpy it.
+	 */
+	local_parts = kmalloc(pdat->num_parts * sizeof (*local_parts),
+			      GFP_KERNEL);
+	if (local_parts == NULL) {
+		res = -ENOMEM;
+		goto out_cleanup;
+	}
+	memcpy(local_parts, pdat->parts,
+	       pdat->num_parts * sizeof (*local_parts));
+
+	/*
+	 * if FBXMTD_PART_MAP_ALL is set on partition 0 then it has
+	 * offset 0 and covers the whole flash.
+	 */
+	if (local_parts[0].flags & FBXMTD_PART_MAP_ALL) {
+		local_parts[0].offset = 0;
+		local_parts[0].size = size;
+		printk(KERN_INFO PFX "partition `%s' covers the whole "
+		       "flash.\n", pdat->parts[0].name);
+	}
+
+	/*
+	 * adjust offset values depending on roffset.
+	 */
+	for (i = 0; i < pdat->num_parts; ++i) {
+		if (local_parts[i].roffset) {
+			if (local_parts[i].roffset >= size) {
+				printk(KERN_ERR PFX "partition %s roffset "
+				       "too big!\n", local_parts[i].name);
+				local_parts[i].offset = 0;
+				local_parts[i].size = 0;
+				continue ;
+			}
+			local_parts[i].offset = size - local_parts[i].roffset;
+		}
+	}
+
+	/*
+	 * handle FBXMTD_PART_AUTOSIZE, end partition at the starting
+	 * offset of the next one, or the end of the flash.
+	 */
+	for (i = 0; i < pdat->num_parts; ++i) {
+		struct fbxmtd_platform_part *align_part;
+
+		if ((local_parts[i].flags & FBXMTD_PART_AUTOSIZE) == 0)
+			continue ;
+		align_part = get_partition_by_name(local_parts[i].align_part,
+						   local_parts,
+						   pdat->num_parts);
+		if (align_part == NULL) {
+			printk(KERN_ERR PFX "%s: no partition to align "
+			       "with, align with flash end.\n",
+			       local_parts[i].name);
+			local_parts[i].size = size - local_parts[i].offset;
+			continue ;
+		}
+
+		if (local_parts[i].offset >= align_part->offset) {
+			printk(KERN_ERR PFX "%s starts after %s: unable to "
+			       "align.\n", local_parts[i].name,
+			       align_part->name);
+			continue ;
+		}
+		local_parts[i].size = align_part->offset -
+		  local_parts[i].offset;
+	}
+
+	/*
+	 * build partition table from platform partition table. for
+	 * partitions that have the FBXMTD_PART_HAS_FS set, a
+	 * partition named $name_fs with the data found in the image
+	 * tag.
+	 */
+	for (partition_count = 0, i = 0; i < pdat->num_parts; ++i) {
+		const struct fbxmtd_platform_part *p;
+		char *name;
+
+		if (partition_count >= FBXMTD_MAX_PART) {
+			printk(KERN_ERR PFX "platform partition count too "
+			       "big.\n");
+			res = -EINVAL;
+			goto out_cleanup;
+		}
+		p = &local_parts[i];
+
+		/*
+		 * stop now if the partition is bigger than the
+		 * available flash size.
+		 */
+		if (p->offset + p->size > size)
+			break;
+
+		if (p->name) {
+			name = kstrdup(p->name, GFP_KERNEL);
+		} else {
+			/* set name to "part%d" */
+			name = kmalloc(8, GFP_KERNEL);
+		}
+		if (name == NULL) {
+			res = -ENOMEM;
+			goto out_cleanup;
+		}
+
+		if (!p->name)
+			sprintf(name, "part%d", partition_count);
+
+		partitions[partition_count].name = name;
+		partitions[partition_count].offset = p->offset;
+		partitions[partition_count].size = p->size;
+
+		if (p->flags & FBXMTD_PART_RW)
+			partitions[partition_count].rw = 1;
+		else
+			partitions[partition_count].rw = 0;
+
+
+		++partition_count;
+
+		if (p->flags & FBXMTD_PART_HAS_FS) {
+			if (partition_count >= FBXMTD_MAX_PART) {
+				printk(KERN_ERR PFX "platform partition "
+				       "count too big.\n");
+				res = -EINVAL;
+				goto out_cleanup;
+			}
+
+			name = kmalloc(strlen(p->name) + 4, GFP_KERNEL);
+			if (name == NULL) {
+				res = -ENOMEM;
+				goto out_cleanup;
+			}
+			snprintf(name, strlen(p->name) + 4, "%s_fs",
+				 p->name);
+
+			partitions[partition_count].name = name;
+			if (p->flags & FBXMTD_PART_IGNORE_TAG) {
+				partitions[partition_count].offset = 0;
+				partitions[partition_count].size = 0;
+			} else {
+				read_imagetag(&partitions[partition_count - 1],
+					      &partitions[partition_count],
+					      p->flags & FBXMTD_PART_NOCRC,
+					      p->flags & FBXMTD_PART_SKIP_KERNEL);
+			}
+			++partition_count;
+		}
+	}
+
+	/*
+	 * print partition table.
+	 */
+	printk(PFX "partition table:\n");
+	for (i = 0; i < partition_count; ++i) {
+		struct fbxmtd_part *p;
+
+		p = &partitions[i];
+		printk("  %s(%i): %08x -> %08x (%iK), %s\n",
+		       p->name, i, p->offset,
+		       p->offset + p->size, p->size >> 10,
+		       p->rw ? "rw" : "ro");
+	}
+
+	res = fbxmtd_set_partitions(dev, partitions, partition_count);
+	if (res < 0) {
+		printk(KERN_ERR PFX "failed to set partition.\n");
+	} else {
+		pdat->core_dev = dev;
+		pdat->status = E_FBXMTD_PROBED;
+	}
+
+ out_cleanup:
+	if (local_parts)
+		kfree(local_parts);
+
+	for (i = 0; i < partition_count; ++i) {
+		if (partitions[i].name) {
+			kfree(partitions[i].name);
+			partitions[i].name = NULL;
+		}
+	}
+
+	if (dev && res < 0) {
+		fbxmtd_put_device(dev);
+		dev = NULL;
+	}
+	return res;
+}
+
+static int
+fbxmtd_map_drv_generic_remove(struct platform_device *pdev)
+{
+	if (dev) {
+		fbxmtd_mark_dead_dev(dev);
+		fbxmtd_put_device(dev);
+	}
+	platform_set_drvdata(pdev, NULL);
+	return 0;
+}
+
+
+static struct platform_driver fbxmtd_map_drv_generic =
+{
+	.probe	= fbxmtd_map_drv_generic_probe,
+	.remove	= fbxmtd_map_drv_generic_remove,
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "fbxmtd_map_drv",
+	},
+};
+
+int __init
+fbxmtd_map_drv_generic_init(void)
+{
+	printk(KERN_INFO PFX "2007, Freebox SA.\n");
+
+	platform_driver_register(&fbxmtd_map_drv_generic);
+	return 0;
+}
+
+void __exit
+fbxmtd_map_drv_generic_exit(void)
+{
+	platform_driver_unregister(&fbxmtd_map_drv_generic);
+}
+
+module_init(fbxmtd_map_drv_generic_init);
+module_exit(fbxmtd_map_drv_generic_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0");
+MODULE_AUTHOR("Nicolas Schichan <nschichan@freebox.fr>");
diff -Nruw linux-2.6.20.14-fbx/drivers/fbxmtd./fbxmtd_priv.h linux-2.6.20.14-fbx/drivers/fbxmtd/fbxmtd_priv.h
--- linux-2.6.20.14-fbx/drivers/fbxmtd./fbxmtd_priv.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/drivers/fbxmtd/fbxmtd_priv.h	2011-09-26 15:07:54.388835397 +0200
@@ -0,0 +1,44 @@
+
+#ifndef FBXMTD_PRIV_H_
+# define FBXMTD_PRIV_H_
+
+/*
+ * notifier
+ */
+#define FBXMTD_EVENT_PART	(1 << 0)
+#define FBXMTD_EVENT_DEAD	(1 << 1)
+
+struct fbxmtd_notifier
+{
+	uint32_t		event_mask;
+	void			(*cb)(void *cb_data,
+				      struct fbxmtd_part *, uint32_t);
+	void			*cb_data;
+	struct list_head	list;
+};
+
+
+/*
+ * io helper used by backend
+ */
+uint32_t fbxmtd_bus_width_read(struct fbxmtd_dev_map *map,
+			       uint32_t offset);
+
+void fbxmtd_bus_width_write(struct fbxmtd_dev_map *map, uint32_t offset,
+			    uint32_t data);
+
+uint32_t fbxmtd_get_bus_word(struct fbxmtd_dev_map *map, const uint8_t *buf);
+
+int fbxmtd_bus_word_equal(struct fbxmtd_dev_map *map, uint32_t d1,
+			  uint32_t d2);
+
+
+/*
+ * backend chip handler
+ */
+struct fbxmtd_dev *fbxmtd_core_amd_probe(dma_addr_t base_phys,
+					 unsigned int flash_width);
+struct fbxmtd_dev *fbxmtd_core_intel_probe(dma_addr_t base_phys,
+					   unsigned int flash_width);
+
+#endif /* ! FBXMTD_PRIV_H_ */
diff -Nruw linux-2.6.20.14-fbx/drivers/fbxmtd./Kconfig linux-2.6.20.14-fbx/drivers/fbxmtd/Kconfig
--- linux-2.6.20.14-fbx/drivers/fbxmtd./Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/drivers/fbxmtd/Kconfig	2011-09-26 15:07:54.388835397 +0200
@@ -0,0 +1,55 @@
+menu "Freebox Memory Technology Devices (FBXMTD)"
+
+comment "Core drivers"
+
+#
+# Freebox MTD
+#
+config FREEBOX_MTD
+	tristate "Freebox Memory Technology Devices (FBXMTD) support"
+	select FREEBOX_DRIVERS
+
+config FREEBOX_MTD_BACKEND_AMD
+	bool "Support for AMD compatible flash"
+	depends on FREEBOX_MTD
+
+config FREEBOX_MTD_BACKEND_INTEL
+	bool "Support for Intel Strataflash"
+	depends on FREEBOX_MTD
+
+config FREEBOX_MTD_USE_DMAMUX
+	bool "Use fbxdmamux for transfer"
+	depends on FREEBOX_DMAMUX && FREEBOX_MTD
+
+config FREEBOX_MTD_BLK
+	tristate "Block device access to fbxmtd"
+	depends on FREEBOX_MTD && BLOCK
+
+config FREEBOX_MTD_CHAR
+	tristate "Character device access to fbxmtd"
+	depends on FREEBOX_MTD
+
+
+comment "Mapping drivers"
+
+#
+# Generic mapping driver.
+#
+config FREEBOX_MTD_MAP_DRV_GENERIC
+	tristate "Generic mapping Driver."
+	depends on FREEBOX_MTD
+	select CRC32
+
+config FREEBOX_MTD_MAP_DRV_BCM963XX
+	tristate "Broadcom 963xx flash format"
+	depends on FREEBOX_MTD
+	select CRC32
+
+#
+# Freebox MTD Map Control interface
+#
+config FREEBOX_MTD_MAP_IOCTL
+	tristate "IOCTL control interface"
+	depends on FREEBOX_MTD_MAP_DRV_GENERIC
+
+endmenu
diff -Nruw linux-2.6.20.14-fbx/drivers/fbxmtd./Makefile linux-2.6.20.14-fbx/drivers/fbxmtd/Makefile
--- linux-2.6.20.14-fbx/drivers/fbxmtd./Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/drivers/fbxmtd/Makefile	2011-09-26 15:07:54.388835397 +0200
@@ -0,0 +1,24 @@
+
+# core support
+obj-$(CONFIG_FREEBOX_MTD) += fbxmtd.o
+
+fbxmtd-objs += fbxmtd_core.o fbxmtd_core_io.o
+ifeq ($(CONFIG_FREEBOX_MTD_BACKEND_AMD),y)
+fbxmtd-objs += fbxmtd_core_amd.o
+endif
+
+ifeq ($(CONFIG_FREEBOX_MTD_BACKEND_INTEL),y)
+fbxmtd-objs += fbxmtd_core_intel.o
+endif
+
+# generic character device access support (r/w with read erase modify write)
+obj-$(CONFIG_FREEBOX_MTD_CHAR) += fbxmtd_char.o
+fbxmtd_char-objs += fbxmtd_char_dev.o
+
+# generic r/o block device access support
+obj-$(CONFIG_FREEBOX_MTD_BLK) += fbxmtd_blk.o
+fbxmtd_blk-objs += fbxmtd_blk_dev.o
+
+obj-$(CONFIG_FREEBOX_MTD_MAP_DRV_GENERIC) += fbxmtd_map_drv_generic.o
+obj-$(CONFIG_FREEBOX_MTD_MAP_DRV_BCM963XX) += fbxmtd_map_drv_bcm963xx.o
+obj-$(CONFIG_FREEBOX_MTD_MAP_IOCTL) += fbxmtd_map_ioctl.o
diff -Nruw linux-2.6.20.14-fbx/drivers/fbxpanel./fbxpanel_anim.c linux-2.6.20.14-fbx/drivers/fbxpanel/fbxpanel_anim.c
--- linux-2.6.20.14-fbx/drivers/fbxpanel./fbxpanel_anim.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/drivers/fbxpanel/fbxpanel_anim.c	2011-09-26 15:07:54.388835397 +0200
@@ -0,0 +1,389 @@
+/*
+ * fbxpanel_anim.c for linux-freebox
+ * Created by <nschichan@freebox.fr> on Thu Mar  8 16:48:56 2007
+ * Freebox SA
+ */
+
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+
+#include <asm/semaphore.h>
+
+#include <linux/fbxpanel.h>
+#include "fbxpanel_priv.h"
+
+#define	PFX	"fbxpanel_anim: "
+
+/* turning nibble */
+const static struct anim_frame anim1[] = {
+	{ { SEG_F | SEG_E, 0, 0, 0 } },
+	{ { SEG_F | SEG_A, 0, 0, 0 } },
+	{ { SEG_A, SEG_A, 0, 0 } },
+	{ { 0, SEG_A, SEG_A, 0 } },
+	{ { 0, 0, SEG_A, SEG_A } },
+	{ { 0, 0, 0, SEG_A | SEG_B } },
+	{ { 0, 0, 0, SEG_B | SEG_C } },
+	{ { 0, 0, 0, SEG_D | SEG_C } },
+	{ { 0, 0, SEG_D, SEG_D } },
+	{ { 0, SEG_D, SEG_D, 0 } },
+	{ { SEG_D, SEG_D, 0, 0 } },
+	{ { SEG_D | SEG_E, 0, 0, 0 } }
+};
+
+/* blinking ring */
+const static struct anim_frame anim2[] = {
+	{ { 0, 0, 0, 0 } },
+	{ { SEG_A | SEG_E | SEG_F | SEG_D, SEG_A | SEG_D,
+	    SEG_A | SEG_D,
+	    SEG_A | SEG_B | SEG_C | SEG_D } }
+};
+
+/* fixed ring */
+const static struct anim_frame anim3[] = {
+	{ { SEG_A | SEG_E | SEG_F | SEG_D,
+	    SEG_A | SEG_D, SEG_A | SEG_D,
+	    SEG_A | SEG_B | SEG_C | SEG_D } }
+};
+
+/* line moving up and down */
+const static struct anim_frame anim4[] = {
+	{ { SEG_A, SEG_A, SEG_A, SEG_A } },
+	{ { SEG_G, SEG_G, SEG_G, SEG_G } },
+	{ { SEG_D, SEG_D, SEG_D, SEG_D } },
+	{ { SEG_G, SEG_G, SEG_G, SEG_G } },
+};
+
+/* blinking 'PPP ' */
+const static struct anim_frame anim5[] = {
+	{ { 0, 0, 0, 0 } },
+	{ { SEG_A | SEG_F | SEG_B | SEG_G | SEG_E,
+	    SEG_A | SEG_F | SEG_B | SEG_G | SEG_E,
+	    SEG_A | SEG_F | SEG_B | SEG_G | SEG_E } }
+};
+
+#define LETTER_T	(SEG_F|SEG_E|SEG_D|SEG_G)
+#define LETTER_E	(SEG_A|SEG_F|SEG_E|SEG_D|SEG_G)
+#define LETTER_L	(SEG_F|SEG_E|SEG_D)
+#define LETTER_A	(SEG_A | SEG_B | SEG_C | SEG_E | SEG_F | SEG_G)
+#define LETTER_P	(SEG_A | SEG_B | SEG_E | SEG_F | SEG_G)
+#define LETTER_O	(SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F)
+
+#define LETTER_0 (SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F)
+#define LETTER_1 (SEG_B | SEG_C)
+#define LETTER_2 (SEG_A | SEG_B | SEG_G | SEG_E | SEG_D)
+
+/* TEL with line moving up and down */
+const static struct anim_frame anim6[] = {
+	{ { LETTER_T, LETTER_E, LETTER_L, SEG_A } },
+	{ { LETTER_T, LETTER_E, LETTER_L, SEG_G } },
+	{ { LETTER_T, LETTER_E, LETTER_L, SEG_D } },
+	{ { LETTER_T, LETTER_E, LETTER_L, SEG_G } },
+};
+
+/* flash bank0 of fiber part */
+const static struct anim_frame anim7[] = {
+	{ { LETTER_0, SEG_A, SEG_A, SEG_A } },
+	{ { LETTER_0, SEG_G, SEG_G, SEG_G } },
+	{ { LETTER_0, SEG_D, SEG_D, SEG_D } },
+	{ { LETTER_0, SEG_G, SEG_G, SEG_G } },
+};
+
+/* flash bank1 of fiber part */
+const static struct anim_frame anim8[] = {
+	{ { LETTER_1, SEG_A, SEG_A, SEG_A } },
+	{ { LETTER_1, SEG_G, SEG_G, SEG_G } },
+	{ { LETTER_1, SEG_D, SEG_D, SEG_D } },
+	{ { LETTER_1, SEG_G, SEG_G, SEG_G } },
+};
+
+/* flash bank1 of TV part */
+const static struct anim_frame anim9[] = {
+	{ { LETTER_2, SEG_A, SEG_A, SEG_A, } },
+	{ { LETTER_2, SEG_G, SEG_G, SEG_G, } },
+	{ { LETTER_2, SEG_D, SEG_D, SEG_D, } },
+	{ { LETTER_2, SEG_G, SEG_G, SEG_G, } },
+};
+
+/* download animation, optical part, bank0 */
+const static struct anim_frame anim10[] = {
+	{ { LETTER_0, SEG_G, 0, 0 } },
+	{ { LETTER_0, 0, SEG_G, 0 } },
+	{ { LETTER_0, 0, 0, SEG_G } },
+	{ { LETTER_0, 0, SEG_G, 0 } },
+};
+
+/* download animation, optical part bank1 */
+const static struct anim_frame anim11[] = {
+	{ { LETTER_1, SEG_G, 0, 0 } },
+	{ { LETTER_1, 0, SEG_G, 0 } },
+	{ { LETTER_1, 0, 0, SEG_G } },
+	{ { LETTER_1, 0, SEG_G, 0 } },
+};
+
+/* download animation, tv part */
+const static struct anim_frame anim12[] = {
+	{ { LETTER_2, SEG_G, 0, 0 } },
+	{ { LETTER_2, 0, SEG_G, 0 } },
+	{ { LETTER_2, 0, 0, SEG_G } },
+	{ { LETTER_2, 0, SEG_G, 0 } },
+};
+
+/* blinking APPL */
+const static struct anim_frame anim13[] = {
+	{ { LETTER_A, LETTER_P, LETTER_P, LETTER_L } },
+	{ { 0, 0, 0, 0 } },
+
+};
+
+struct anim
+{
+	const struct anim_frame *p;
+	unsigned int anim_size;
+	unsigned int anim_rate;
+};
+
+const static struct anim anims[] = {
+	{ anim1, sizeof (anim1) / sizeof (struct anim_frame), HZ / 2 },
+	{ anim1, sizeof (anim1) / sizeof (struct anim_frame), HZ / 10 },
+	{ anim2, sizeof (anim2) / sizeof (struct anim_frame), HZ / 2 },
+	{ anim3, sizeof (anim3) / sizeof (struct anim_frame), HZ },
+	{ anim4, sizeof (anim4) / sizeof (struct anim_frame), HZ },
+	{ anim5, sizeof (anim5) / sizeof (struct anim_frame), HZ / 2 },
+	{ anim6, sizeof (anim6) / sizeof (struct anim_frame), HZ / 2 },
+	{ anim7, sizeof (anim7) / sizeof (struct anim_frame), HZ },
+	{ anim8, sizeof (anim8) / sizeof (struct anim_frame), HZ },
+	{ anim9, sizeof (anim9) / sizeof (struct anim_frame), HZ },
+	{ anim10, sizeof (anim10) / sizeof (struct anim_frame), HZ },
+	{ anim11, sizeof (anim11) / sizeof (struct anim_frame), HZ },
+	{ anim12, sizeof (anim12) / sizeof (struct anim_frame), HZ },
+	{ anim13, sizeof (anim13) / sizeof (struct anim_frame), HZ / 2 },
+};
+
+enum {
+	E_ANIM_SLOW_SNAKE,
+	E_ANIM_FAST_SNAKE,
+	E_ANIM_BLINK_RING,
+	E_ANIM_FIXED_RING,
+	E_ANIM_LINE_UP_DOWN,
+	E_ANIM_PPP,
+	E_ANIM_TEL_FLASH,
+	E_ANIM_FLASH_BANK0,
+	E_ANIM_FLASH_BANK1,
+	E_ANIM_FLASH_TV,
+	E_ANIM_DOWNLOAD_BANK0,
+	E_ANIM_DOWNLOAD_BANK1,
+	E_ANIM_DOWNLOAD_TV,
+	E_ANIM_RECEIVE_PHONE_CALL,
+	E_ANIM_LAST,
+};
+
+/*
+ * handle animation here. we will be awoken if anyone changes the
+ * current animation number or if animation requires an update.
+ */
+static int
+kanimator_thread(void *data)
+{
+	struct fbxpanel *p;
+
+	p = data;
+
+	while (!kthread_should_stop()) {
+		int anim;
+		int i;
+
+		if (down_interruptible(&p->mutex))
+			continue ;
+
+		anim = p->current_anim;
+		if (anim == -1) {
+			/* nothing to animate, wait for anim change */
+			dprint("waiting for animation request ...\n");
+			up(&p->mutex);
+			wait_event_interruptible(p->animator_wq,
+						 p->current_anim != -1 ||
+						 kthread_should_stop());
+			continue ;
+		}
+
+		/* check for animation change */
+		if (p->last_anim != anim) {
+			p->last_anim = anim;
+
+			/*
+			 * do not set current_frame to 0 when possible
+			 * to allow smooth transitions from slow snake
+			 * to fast snake.
+			 */
+			if (anims[p->current_anim].anim_size <
+			    p->current_frame)
+				p->current_frame = 0;
+		}
+
+		if (++(p->current_frame) >= anims[anim].anim_size)
+			p->current_frame = 0;
+
+		/* update panel with current frame */
+		for (i = 0; i < 4; ++i) {
+			_fbxpanel_set_digit(p, i,
+					    p->frames[anim][p->current_frame].d[i]);
+		}
+
+		up(&p->mutex);
+		wait_event_interruptible_timeout(p->animator_wq,
+						 p->current_anim != anim,
+						 anims[anim].anim_rate);
+	}
+
+	return 0;
+}
+
+/*
+ * map generic bit values to offsets in device specific digit desc
+ * structure.
+ */
+static struct {
+	int gen_bit;
+	int offset;
+} bit_map[] = {
+	{ SEG_A,
+	  offsetof(struct digit_seg_desc, h_top) / sizeof (int) },
+	{ SEG_B,
+	  offsetof(struct digit_seg_desc, v_top_right) / sizeof (int) },
+	{ SEG_C,
+	  offsetof(struct digit_seg_desc, v_bottom_right) / sizeof (int) },
+	{ SEG_D,
+	  offsetof(struct digit_seg_desc, h_bottom) / sizeof (int) },
+	{ SEG_E,
+	  offsetof(struct digit_seg_desc, v_bottom_left) / sizeof (int)},
+	{ SEG_F,
+	  offsetof(struct digit_seg_desc, v_top_left) / sizeof (int) },
+	{ SEG_G,
+	  offsetof(struct digit_seg_desc, h_middle_left) / sizeof (int) },
+	{ SEG_G,
+	  offsetof(struct digit_seg_desc, h_middle_right) / sizeof (int)},
+};
+
+/*
+ * setup p->frames so that it contains all device specific digit
+ * values directly usable by the driver callbacks.
+ */
+static int
+build_anim_frames(struct fbxpanel *p)
+{
+	int i;
+	int err;
+	int *desc;
+
+	desc = (int*)p->digit_seg_desc;
+
+	err = -ENOMEM;
+	p->frames = kzalloc(E_ANIM_LAST * sizeof (*p->frames), GFP_KERNEL);
+	if (p->frames == NULL)
+		goto out_error;
+
+	/* loop over animations */
+	for (i = 0; i < E_ANIM_LAST; ++i) {
+		int j;
+
+		p->frames[i] = kzalloc(anims[i].anim_size *
+				       sizeof (**p->frames),
+				       GFP_KERNEL);
+		if (p->frames[i] == NULL)
+			goto out_error;
+
+		/* loop over ainmation frames  */
+		for (j = 0; j < anims[i].anim_size; ++j) {
+			int k;
+
+			/* loop over animation digits*/
+			for (k = 0; k < 4; ++k) {
+				int l;
+
+				/* loop over digit bits */
+				for (l = 0; l < 8; ++l) {
+					if (anims[i].p[j].d[k] &
+					    bit_map[l].gen_bit)
+						p->frames[i][j].d[k] |=
+						  desc[bit_map[l].offset];
+				}
+			}
+		}
+	}
+	p->anim_count = E_ANIM_LAST;
+	return 0;
+
+ out_error:
+	if (p->frames) {
+		for (i = 0; i < E_ANIM_LAST; ++i) {
+			if (p->frames[i])
+				kfree(p->frames[i]);
+		}
+		kfree(p->frames);
+		p->frames = NULL;
+	}
+	return err;
+}
+
+/*
+ * free all data allocated in build_anim_frames.
+ */
+static void
+free_anim_frames(struct fbxpanel *p)
+{
+	int i;
+
+	for (i = 0; i < E_ANIM_LAST; ++i) {
+		if (p->frames[i])
+			kfree(p->frames[i]);
+	}
+	kfree(p->frames);
+	p->frames = NULL;
+}
+
+/*
+ * build animation frames and spawn a kthread for animation.
+ *
+ * NOTE: a kanimator process is spawned for each panel available on
+ * the system.
+ */
+int
+fbxpanel_animator_init(struct fbxpanel *p)
+{
+	int err;
+
+	err = build_anim_frames(p);
+	if (err)
+		goto out_error;
+
+	init_waitqueue_head(&p->animator_wq);
+	p->animator = kthread_create(kanimator_thread, p,
+				     "kanimator/%s", p->name);
+	if (IS_ERR(p->animator)) {
+		printk(KERN_ERR PFX
+		       "unable to create animator thread for %s\n", p->name);
+		err = PTR_ERR(p->animator);
+		goto out_error;
+	}
+	p->current_anim = -1;
+	wake_up_process(p->animator);
+	return 0;
+
+ out_error:
+	if (p->frames)
+		free_anim_frames(p);
+	if (p->animator)
+		kthread_stop(p->animator);
+	return err;
+}
+
+/*
+ * stop kanimator thread and free allocated animation frames.
+ */
+int
+fbxpanel_animator_exit(struct fbxpanel *p)
+{
+	kthread_stop(p->animator);
+	free_anim_frames(p);
+	return 0;
+}
diff -Nruw linux-2.6.20.14-fbx/drivers/fbxpanel./fbxpanel_class.c linux-2.6.20.14-fbx/drivers/fbxpanel/fbxpanel_class.c
--- linux-2.6.20.14-fbx/drivers/fbxpanel./fbxpanel_class.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/drivers/fbxpanel/fbxpanel_class.c	2011-09-26 15:07:54.388835397 +0200
@@ -0,0 +1,341 @@
+/*
+ * fbxpanel.c for linux-freebox
+ * Created by <nschichan@freebox.fr> on Wed Mar  7 22:14:40 2007
+ * Freebox SA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/sched.h>
+
+#include <linux/fbxpanel.h>
+#include "fbxpanel_priv.h"
+
+#define PFX	"fbxpanel: "
+
+/*
+ * helpers with cache handling, must be called with mutex
+ * held or if kanimator is not running !
+ */
+int
+_fbxpanel_set_digit(struct fbxpanel *p, int digit, uint16_t value)
+{
+	if (digit >= p->digit_count)
+		return -EINVAL;
+
+	if (p->digit_cache[digit] == value)
+		return 0;
+	p->digit_cache[digit] = value;
+	return p->set_digit(p, digit, value);
+}
+
+/*
+ * add a len parameter since sysfs buffers are not zero terminated.
+ */
+int
+_fbxpanel_set_string(struct fbxpanel *p, const char *buf, int len)
+{
+	int ret;
+	int i;
+	int err = 0;
+
+	/* disable potentially running animation */
+	p->current_anim = -1;
+
+	if (len > p->digit_count)
+		len = p->digit_count;
+
+	ret = 0;
+	for (i = 0; i < len; ++i) {
+		uint16_t digit;
+
+		digit = p->ascii_table[(uint8_t)buf[i]];
+		if (!digit)
+			digit = p->ascii_table[' '];
+
+		err = _fbxpanel_set_digit(p, i, digit);
+		if (err) {
+			dprint("%s: unable to send digit.\n", p->name);
+			ret = err;
+		}
+	}
+	return err;
+}
+
+int
+_fbxpanel_colon_ctl(struct fbxpanel *p, int enable, int blink_msec)
+{
+	return p->set_colon_digit(p, enable, blink_msec);
+}
+
+/*
+ * display 88:88 to the front panel.
+ */
+int
+_fbxpanel_set_initial(struct fbxpanel *p)
+{
+	_fbxpanel_set_string(p, "8888", 4);
+	/* enable colon, no blink */
+	_fbxpanel_colon_ctl(p, 1, 0);
+	return 0;
+}
+
+/*
+ * terminate strings correctly since data comming from the lower layer
+ * is not zero terminated. result is stored in out.
+ */
+static void
+copyz(char *out, int out_count, const char *in, size_t in_count)
+{
+	int len;
+
+	if (in_count > out_count - 1)
+		len = in_count;
+	else
+		len = out_count;
+	strlcpy(out, in, len);
+}
+
+/*
+ * sysfs callback: update front panel string.
+ */
+static ssize_t
+store_text(struct class_device *dev, const char *buf, size_t count)
+{
+	struct fbxpanel *panel;
+	int err;
+	int ret;
+
+	panel = dev->class_data;
+
+	if (panel == NULL)
+		/* dead device */
+		return -ENODEV;
+
+	if (down_interruptible(&panel->mutex))
+		return -ERESTARTSYS;
+
+	ret = count;
+	err = _fbxpanel_set_string(panel, buf, count);
+	if (err)
+		ret = err;
+
+	up(&panel->mutex);
+	return ret;
+}
+
+/*
+ * update animation number and wakeup kanimator thread.
+ */
+static ssize_t
+store_anim(struct class_device *dev, const char *buf, size_t count)
+{
+	struct fbxpanel *panel;
+	int val;
+	char str[16];
+
+	panel = dev->class_data;
+
+	if (panel == NULL)
+		/* dead device */
+		return -ENODEV;
+
+	if (down_interruptible(&panel->mutex))
+		return -ERESTARTSYS;
+
+	copyz(str, sizeof (str), buf, count);
+	val = simple_strtoul(str, NULL, 0);
+	if (val < panel->anim_count) {
+		panel->current_anim = val;
+		wake_up(&panel->animator_wq);
+	}
+
+	up(&panel->mutex);
+	return count;
+}
+
+static ssize_t
+store_colon_ctl(struct class_device *dev, const char *buf, size_t count)
+{
+	struct fbxpanel *panel;
+	int enable;
+	int msec_blink;
+	char *end;
+	char *zbuf = NULL;
+	int err = 0;
+
+	panel = dev->class_data;
+	if (down_interruptible(&panel->mutex))
+		return -ERESTARTSYS;
+
+
+	zbuf = kmalloc(count + 1, GFP_KERNEL);
+	if (zbuf == NULL) {
+		err = -ENOMEM;
+		goto out;
+	}
+	memcpy(zbuf, buf, count);
+	zbuf[count] = 0;
+
+	enable = simple_strtol(zbuf, &end, 10);
+	if (*end != ':') {
+		err = -EINVAL;
+		goto out;
+	}
+	msec_blink = simple_strtol(end + 1, &end, 10);
+	if (*end != 0 && *end != '\n') {
+		err = -EINVAL;
+		goto out;
+	}
+
+	_fbxpanel_colon_ctl(panel, enable, msec_blink);
+
+ out:
+	if (zbuf)
+		kfree(zbuf);
+	up(&panel->mutex);
+	if (err)
+		return err;
+	return count;
+}
+
+static struct class_device_attribute panel_attributes[] = {
+	__ATTR(anim, 0600, NULL, store_anim),
+	__ATTR(text, 0600, NULL, store_text),
+	__ATTR(colon_ctl, 0600, NULL, store_colon_ctl),
+	{ },
+};
+
+static struct class fbxpanel_class =
+{
+	.name			= "fbxpanel",
+	.owner			= THIS_MODULE,
+	.class_dev_attrs	= panel_attributes,
+};
+
+/*
+ * called when there are no reference on the class device. only free
+ * dev, most of the cleanup stuff has alread been done in the
+ * fbxpanel_unregister.
+ */
+static void
+fbxpanel_release(struct class_device *dev)
+{
+	kfree(dev);
+}
+
+/*
+ * create a new class_device named $panel->name and add it to the
+ * class layer.
+ *
+ * the attributes will so be available in
+ * /sys/class/fbxpanel/$panel->name/
+ */
+int
+fbxpanel_register(struct fbxpanel *panel)
+{
+	int err;
+
+	printk(KERN_INFO PFX "registering panel %s\n", panel->name);
+	panel->class_dev = kzalloc(sizeof (*panel->class_dev), GFP_KERNEL);
+	if (panel->class_dev == NULL) {
+		err = -ENOMEM;
+		printk(KERN_ERR PFX "unable to allocate class device.\n");
+		goto out_error;
+	}
+	class_device_initialize(panel->class_dev);
+	panel->class_dev->class = &fbxpanel_class;
+	panel->class_dev->class_data = panel;
+	panel->class_dev->release = fbxpanel_release;
+	strlcpy(panel->class_dev->class_id, panel->name, BUS_ID_SIZE);
+
+	err = -ENOMEM;
+	panel->digit_cache = kzalloc(panel->digit_count * sizeof (uint16_t),
+				     GFP_KERNEL);
+	if (panel->digit_cache == NULL)
+		goto out_error;
+
+	_fbxpanel_set_initial(panel);
+
+	err = fbxpanel_animator_init(panel);
+	if (err) {
+		printk(KERN_ERR PFX "unable to init animator for %s\n",
+		       panel->name);
+		goto out_error;
+	}
+
+	err = class_device_add(panel->class_dev);
+	if (err) {
+		printk(KERN_ERR PFX "unable to add panel %s\n",
+		       panel->class_dev->class_id);
+		goto out_animator;
+	}
+
+	return 0;
+
+ out_animator:
+	fbxpanel_animator_exit(panel);
+ out_error:
+	if (panel->digit_cache)
+		kfree(panel->digit_cache);
+	if (panel->class_dev)
+		kfree(panel->class_dev);
+	return err;
+}
+
+/*
+ * cleanup everything allocated in fbxpanel_register. allocated
+ * class_device will be freed in the release callback.
+ */
+int
+fbxpanel_unregister(struct fbxpanel *panel)
+{
+	printk(KERN_INFO PFX "unregistering panel %s\n", panel->name);
+
+	class_device_del(panel->class_dev);
+	class_device_put(panel->class_dev);
+	panel->class_dev->class_data = NULL;
+
+	fbxpanel_animator_exit(panel);
+	_fbxpanel_set_initial(panel);
+	kfree(panel->digit_cache);
+	return 0;
+}
+
+/*
+ * register the fbxpanel class.
+ */
+static int __init
+fbxpanel_class_init(void)
+{
+	int err;
+
+	printk(KERN_INFO PFX "2007, Freebox SA.\n");
+
+	err = class_register(&fbxpanel_class);
+	if (err) {
+		printk(KERN_ERR PFX "unable to register fbxpanel class.\n");
+		return err;
+	}
+	return 0;
+}
+
+/*
+ * unregister the fbxpanel class.
+ */
+static void __exit
+fbxpanel_class_exit(void)
+{
+	class_unregister(&fbxpanel_class);
+}
+
+subsys_initcall(fbxpanel_class_init);
+module_exit(fbxpanel_class_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Nicolas Schichan <nschichan@freebox.fr>");
+MODULE_DESCRIPTION("Freebox Front Panel Class Device - www.freebox.fr");
+
+EXPORT_SYMBOL_GPL(fbxpanel_register);
+EXPORT_SYMBOL_GPL(fbxpanel_unregister);
diff -Nruw linux-2.6.20.14-fbx/drivers/fbxpanel./fbxpanel_hw_pic_fbx.c linux-2.6.20.14-fbx/drivers/fbxpanel/fbxpanel_hw_pic_fbx.c
--- linux-2.6.20.14-fbx/drivers/fbxpanel./fbxpanel_hw_pic_fbx.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/drivers/fbxpanel/fbxpanel_hw_pic_fbx.c	2011-09-26 15:07:54.388835397 +0200
@@ -0,0 +1,305 @@
+/*
+ * fbxpanel_hw_pic_fbx.c for linux-freebox
+ * Created by <nschichan@freebox.fr> on Wed Mar  7 23:24:33 2007
+ * Freebox SA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+
+#include <linux/fbxpanel.h>
+
+#include "fbxpanel_priv.h"
+#include "fbxpanel_hw_pic_fbx.h"
+
+#define	PFX	"fbxpanel_hw_pic_fbx: "
+
+#define I2C_RETRY_COUNT 5
+
+/*
+ * I2C with custom PIC found on V3/V4/V5A
+ */
+static unsigned short normal_i2c[] = { 0xd6 >> 1, I2C_CLIENT_END };
+
+I2C_CLIENT_INSMOD_1(fbxpanel_hw_pic_fbx);
+
+/*
+ * map ascii characters to digit value
+ */
+static const uint16_t ascii_to_panel[256] =
+{
+	['0'] = DIGIT_0,
+	['1'] = DIGIT_1,
+	['2'] = DIGIT_2,
+	['3'] = DIGIT_3,
+	['4'] = DIGIT_4,
+	['5'] = DIGIT_5,
+	['6'] = DIGIT_6,
+	['7'] = DIGIT_7,
+	['8'] = DIGIT_8,
+	['9'] = DIGIT_9,
+	['A'] = LETTER_A, ['a'] = LETTER_A,
+	['B'] = LETTER_B_M, ['b'] = LETTER_B_M,
+	['C'] = LETTER_C, ['c'] = LETTER_C,
+	['D'] = LETTER_D_M, ['d'] = LETTER_D_M,
+	['E'] = LETTER_E, ['e'] = LETTER_E,
+	['F'] = LETTER_F, ['f'] = LETTER_F,
+	['G'] = DIGIT_9, ['g'] = DIGIT_9,
+	['H'] = LETTER_H, ['h'] = LETTER_H,
+	['I'] = LETTER_I, ['i'] = LETTER_I,
+	['J'] = LETTER_J, ['j'] = LETTER_J,
+	['K'] = LETTER_K_M, ['k'] = LETTER_K_M,
+	['L'] = LETTER_L, ['l'] = LETTER_L,
+	['M'] = LETTER_M, ['m'] = LETTER_M,
+	['N'] = LETTER_N_M, ['n'] = LETTER_N_M,
+	['O'] = DIGIT_0, ['o'] = DIGIT_0,
+	['P'] = LETTER_P, ['p'] = LETTER_P,
+	['Q'] = LETTER_Q, ['q'] = LETTER_Q,
+	['R'] = LETTER_R_M, ['r'] = LETTER_R_M,
+	['S'] = LETTER_S, ['s'] = LETTER_S,
+	['T'] = LETTER_T, ['t'] = LETTER_T,
+	['U'] = LETTER_U, ['u'] = LETTER_U,
+	['V'] = LETTER_U_M, ['v'] = LETTER_U_M,
+	['W'] = LETTER_A, ['w'] = LETTER_A,
+	['X'] = LETTER_H, ['x'] = LETTER_H,
+	['Y'] = DIGIT_4, ['y'] = DIGIT_4,
+	['Z'] = DIGIT_2, ['z'] = DIGIT_2,
+	['-'] = MINUS,
+	['_'] = UNDERSCORE,
+	[' '] = SPACE,
+
+	['['] = OPENING_BRACKET,
+	[']'] = CLOSE_BRACKET,
+};
+
+/*
+ * digit layout.
+ */
+static struct digit_seg_desc digit_seg_desc =
+{
+	.h_top		= SEGA,
+	.h_middle_left	= SEGG,
+	.h_middle_right	= SEGG,
+	.h_bottom	= SEGD,
+
+	.v_top_left	= SEGF,
+	.v_top_right	= SEGB,
+
+	.v_bottom_left	= SEGE,
+	.v_bottom_right	= SEGC,
+};
+
+static int fbxpanel_hw_pic_fbx_attach_adapter(struct i2c_adapter *adapter);
+static int fbxpanel_hw_pic_fbx_detect(struct i2c_adapter *adapter,
+				      int address, int kind);
+static int fbxpanel_hw_pic_fbx_detach_client(struct i2c_client *c);
+
+static struct i2c_driver fbxpanel_hw_pic_fbx_driver =
+{
+	.driver		= {
+		.name	= "pic_fbx_panel",
+	},
+	.id		= 0x42,
+	.attach_adapter	= fbxpanel_hw_pic_fbx_attach_adapter,
+	.detach_client	= fbxpanel_hw_pic_fbx_detach_client,
+};
+
+static int
+fbxpanel_hw_pic_fbx_attach_adapter(struct i2c_adapter *adapter)
+{
+	return i2c_probe(adapter, &addr_data, fbxpanel_hw_pic_fbx_detect);
+}
+
+/*
+ * I2C send helper. handles retry for us.
+ */
+static void
+i2c_send(struct fbxpanel_pic_fbx_priv *priv, char command, char value)
+{
+	struct i2c_msg msg;
+	char data[2];
+	int loop;
+
+	data[0] = command;
+	data[1] = value;
+	msg.addr = priv->i2c_addr;
+	msg.flags = 0;
+	msg.len = 2;
+	msg.buf = data;
+
+	loop = I2C_RETRY_COUNT;
+	while (i2c_transfer(priv->i2c_ap, &msg, 1) < 0 && loop)
+		--loop;
+}
+
+/*
+ * set digit callback.
+ */
+int
+fbxpanel_pic_fbx_set_digit(struct fbxpanel *p, int digit, uint16_t value)
+{
+	if (digit > 3)
+		return 0;
+	i2c_send(p->priv, I2C_CMD_DIGIT1_VAL + digit, value & 0xff);
+	return 0;
+}
+
+int
+fbxpanel_pic_fbx_set_colon_digit(struct fbxpanel *p, int enable,
+				 int blink_msec)
+{
+	if (enable) {
+		if (blink_msec) {
+			int ticks;
+
+			ticks = blink_msec * 160 / 1000;
+			if (ticks > 0xff)
+			    ticks = 0xff;
+			i2c_send(p->priv, I2C_CMD_BLINK_SPEED, ticks);
+			i2c_send(p->priv, I2C_CMD_DIGIT5_STATE, 2);
+		} else {
+			i2c_send(p->priv, I2C_CMD_DIGIT5_STATE, 1);
+		}
+	} else {
+		i2c_send(p->priv, I2C_CMD_DIGIT5_STATE, 0);
+	}
+	return 0;
+}
+
+/*
+ * allocate a new fbxpanel structure and register it to the class
+ * layer.
+ */
+
+static int
+fbxpanel_hw_pic_fbx_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+	struct i2c_client *client = NULL;
+	struct fbxpanel_pic_fbx_priv *priv = NULL;
+	struct fbxpanel *panel = NULL;
+	int err;
+
+	printk(PFX "detecting panel at address 0x%02x\n", address);
+
+	client = kzalloc(sizeof (*client), GFP_KERNEL);
+
+	client->adapter = adapter;
+	client->addr = address;
+	client->driver = &fbxpanel_hw_pic_fbx_driver;
+	client->flags = 0;
+
+	if (client == NULL) {
+		printk(KERN_ERR PFX "unable to allocate i2c client.\n");
+		err = -ENOMEM;
+		goto out_error;
+	}
+
+	panel = kzalloc(sizeof (*panel), GFP_KERNEL);
+	if (panel == NULL) {
+		err = -ENOMEM;
+		printk(KERN_ERR PFX "unable to allocate fbxpanel driver.\n");
+		goto out_error;
+	}
+	init_MUTEX(&panel->mutex);
+
+	priv = kzalloc(sizeof (struct fbxpanel_pic_fbx_priv), GFP_KERNEL);
+	if (priv == NULL) {
+		err = -ENOMEM;
+		printk(KERN_ERR PFX "unable to allocate fbxpanel driver "
+		       "private struct.\n");
+		goto out_error;
+	}
+
+	priv->i2c_ap = adapter;
+	priv->i2c_addr = address;
+
+	panel->name = client->driver->driver.name;
+	panel->priv = priv;
+	panel->set_digit = fbxpanel_pic_fbx_set_digit;
+	panel->set_colon_digit = fbxpanel_pic_fbx_set_colon_digit;
+
+	panel->digit_count = 5; /* 4 chars + ':' */
+	panel->ascii_table = ascii_to_panel;
+	panel->digit_seg_desc = &digit_seg_desc;
+
+	i2c_set_clientdata(client, panel);
+
+	err = i2c_attach_client(client);
+	if (err) {
+		printk(KERN_ERR PFX "unable to attach i2c client.\n");
+		goto out_error;
+	}
+
+
+	/* disable colon char display */
+	i2c_send(panel->priv, I2C_CMD_DIGIT5_STATE, 0);
+	/* set colon char */
+	i2c_send(panel->priv, I2C_CMD_DIGIT5_VAL, LED1 | LED2);
+
+	err = fbxpanel_register(panel);
+	if (err) {
+		printk(KERN_ERR PFX "unable to register %s to the class "
+		       "layer.\n", panel->name);
+		goto out_detach;
+	}
+
+
+
+	return 0;
+ out_detach:
+	i2c_detach_client(client);
+ out_error:
+	if (priv)
+		kfree(priv);
+	if (panel)
+		kfree(panel);
+	if (adapter)
+		i2c_put_adapter(adapter);
+	if (client)
+		kfree(client);
+	return err;
+}
+
+/*
+ * release everything allocated in the probe function.
+ */
+int
+fbxpanel_hw_pic_fbx_detach_client(struct i2c_client *client)
+{
+	struct fbxpanel *panel;
+
+	panel = i2c_get_clientdata(client);
+	if (panel == NULL) {
+		printk(KERN_ERR PFX "no client data in i2c client.\n");
+		return -EINVAL;
+	}
+	printk(KERN_INFO PFX "removing panel %s\n", panel->name);
+	i2c_detach_client(client);
+	fbxpanel_unregister(panel);
+	kfree(panel->priv);
+	kfree(panel);
+	kfree(client);
+	return 0;
+}
+
+int __init
+fbxpanel_pic_fbx_init(void)
+{
+	printk(KERN_INFO PFX "2007, Freebox SA.\n");
+	return i2c_add_driver(&fbxpanel_hw_pic_fbx_driver);
+}
+
+void __exit
+fbxpanel_pic_fbx_exit(void)
+{
+	i2c_del_driver(&fbxpanel_hw_pic_fbx_driver);
+}
+
+module_init(fbxpanel_pic_fbx_init);
+module_exit(fbxpanel_pic_fbx_exit);
+
+MODULE_AUTHOR("Nicolas Schichan <nschichan@freebox.fr>");
+MODULE_DESCRIPTION("Freebox PIC-based Front Panel Driver - www.freebox.fr");
+MODULE_LICENSE("GPL");
diff -Nruw linux-2.6.20.14-fbx/drivers/fbxpanel./fbxpanel_hw_pic_fbx.h linux-2.6.20.14-fbx/drivers/fbxpanel/fbxpanel_hw_pic_fbx.h
--- linux-2.6.20.14-fbx/drivers/fbxpanel./fbxpanel_hw_pic_fbx.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/drivers/fbxpanel/fbxpanel_hw_pic_fbx.h	2011-09-26 15:07:54.388835397 +0200
@@ -0,0 +1,102 @@
+/*
+ * fbxpanel_hw_pic_fbx.h for linux-freebox
+ * Created by <nschichan@freebox.fr> on Thu Mar  8 14:49:48 2007
+ * Freebox SA
+ */
+
+/*
+ * HW specific bits for fbxpanel_hw_pic_fbx.
+ */
+#ifndef __FBXPANEL_HW_PIC_FBX_H
+# define __FBXPANEL_HW_PIC_FBX_H
+
+
+/*
+ * Digit segment are named this way:
+ *
+ *   A
+ * F   B
+ *   G
+ * E   C
+ *   D
+ */
+#define SEGA	(1 << 0)
+#define SEGB	(1 << 1)
+#define SEGC	(1 << 2)
+#define SEGD	(1 << 3)
+#define SEGE	(1 << 4)
+#define SEGF	(1 << 5)
+#define SEGG	(1 << 6)
+/* little dot next to digit */
+#define SEGDd	(1 << 7)
+
+/* digit 5 (middle colon, led 1 is the upper one) */
+#define LED1	(1 << 0)
+#define LED2	(1 << 1)
+
+/* conversion between letter/digit and segment */
+#define LETTER_A	(SEGA | SEGB | SEGF | SEGG | SEGE | SEGC)
+#define LETTER_B_M	(SEGF | SEGG | SEGE | SEGC | SEGD)
+#define LETTER_C	(SEGA | SEGF | SEGE | SEGD)
+#define LETTER_D_M	(SEGG | SEGE | SEGC | SEGD | SEGB)
+#define LETTER_E	(SEGA | SEGD | SEGE | SEGF | SEGG)
+#define LETTER_F	(SEGA | SEGE | SEGF | SEGG)
+#define LETTER_H	(SEGF | SEGE | SEGC | SEGG | SEGB)
+#define LETTER_I	(SEGF | SEGE)
+#define LETTER_J	(SEGB | SEGC | SEGD | SEGE)
+#define LETTER_K_M	(SEGF | SEGE | SEGG)
+#define LETTER_L	(SEGE | SEGF | SEGD)
+#define LETTER_M	(SEGA | SEGF | SEGE | SEGB | SEGC)
+#define LETTER_N_M	(SEGE | SEGG | SEGC)
+#define LETTER_P	(SEGF | SEGE | SEGA | SEGB | SEGG)
+#define LETTER_Q	(SEGA | SEGF | SEGB | SEGG | SEGC)
+#define LETTER_R_M	(SEGE | SEGG)
+#define LETTER_S	(SEGA | SEGF | SEGG | SEGC | SEGD)
+#define LETTER_T	(SEGD | SEGE | SEGF | SEGG)
+#define LETTER_U	(SEGF | SEGE | SEGD | SEGB | SEGC)
+#define LETTER_U_M	(SEGE | SEGD | SEGC)
+
+#define DIGIT_0		(SEGA | SEGB | SEGC | SEGD | SEGE | SEGF)
+#define DIGIT_1		(SEGB | SEGC)
+#define DIGIT_2		(SEGA | SEGB | SEGG | SEGE | SEGD)
+#define DIGIT_3		(SEGA | SEGB | SEGC | SEGD | SEGG)
+#define DIGIT_4		(SEGF | SEGG | SEGB | SEGC)
+#define DIGIT_5		(SEGA | SEGF | SEGG | SEGC | SEGD)
+#define DIGIT_6		(SEGA | SEGF | SEGE | SEGD | SEGC | SEGG)
+#define DIGIT_7		(SEGA | SEGB | SEGC)
+#define DIGIT_8		(SEGA | SEGB | SEGC | SEGD | SEGE | SEGF | SEGG)
+#define DIGIT_9		(SEGA | SEGB | SEGC | SEGD | SEGF | SEGG)
+
+#define MINUS		(SEGG)
+#define SPACE		(0)
+#define UNDERSCORE	(SEGD)
+
+#define OPENING_BRACKET	(SEGA | SEGF | SEGE | SEGD)
+#define CLOSE_BRACKET	(SEGA | SEGB | SEGC | SEGD)
+
+/* commands */
+#define I2C_CMD_SHUTDOWN	0x00	/* blank the panel */
+#define I2C_CMD_DIGIT1_VAL	0x01	/* change digit 1 value */
+#define I2C_CMD_DIGIT2_VAL	0x02	/* change digit 2 value */
+#define I2C_CMD_DIGIT3_VAL	0x03	/* change digit 3 value */
+#define I2C_CMD_DIGIT4_VAL	0x04	/* change digit 4 value */
+#define I2C_CMD_DIGIT5_VAL	0x04	/* change digit 5 (colon) value */
+#define I2C_CMD_REFRESH_RATE	0x06	/* rate, 0 -> 0.1, 0xff -> 25.6 */
+#define I2C_CMD_REFRESH_CYCLE	0x07	/* refresh duty cycle */
+#define I2C_CMD_BLINK_SPEED	0x08	/* 0 -> 10ms, 0xff -> 2560 ms */
+#define I2C_CMD_HOURS		0x09	/* unused */
+#define I2C_CMD_MINUTES		0x0a	/* unused */
+#define I2C_CMD_CHANNEL		0x0b	/* unused */
+#define I2C_CMD_DIGIT1_STATE	0x11	/* change digit 1 state */
+#define I2C_CMD_DIGIT2_STATE	0x12	/* change digit 2 state */
+#define I2C_CMD_DIGIT3_STATE	0x13	/* change digit 3 state */
+#define I2C_CMD_DIGIT4_STATE	0x14	/* change digit 4 state */
+#define I2C_CMD_DIGIT5_STATE	0x15	/* change digit 5 (colon) state */
+
+struct fbxpanel_pic_fbx_priv
+{
+	uint32_t i2c_addr;
+	struct i2c_adapter *i2c_ap;
+};
+
+#endif /* !FBXPANEL_HW_PIC_FBX_H */
diff -Nruw linux-2.6.20.14-fbx/drivers/fbxpanel./fbxpanel_priv.h linux-2.6.20.14-fbx/drivers/fbxpanel/fbxpanel_priv.h
--- linux-2.6.20.14-fbx/drivers/fbxpanel./fbxpanel_priv.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/drivers/fbxpanel/fbxpanel_priv.h	2011-09-26 15:07:54.388835397 +0200
@@ -0,0 +1,47 @@
+/*
+ * fbxpanel_priv.h for linux-freebox
+ * Created by <nschichan@freebox.fr> on Thu Mar  8 16:51:04 2007
+ * Freebox SA
+ */
+
+#ifndef __FBXPANEL_PRIV_H
+# define __FBXPANEL_PRIV_H
+
+struct fbxpanel;
+
+int fbxpanel_animator_init(struct fbxpanel *p);
+int fbxpanel_animator_exit(struct fbxpanel *p);
+
+/* debug stuff */
+/* #define DEBUG */
+#ifdef DEBUG
+#define dprint(Fmt, Arg...)	printk(PFX Fmt, ##Arg)
+#else
+#define dprint(Fmt, Arg...)	do { } while (0)
+#endif
+
+
+struct anim_frame
+{
+	uint8_t d[4];
+};
+
+struct dev_anim_frame
+{
+	uint16_t d[4];
+};
+
+#define SEG_A	(1 << 6)
+#define SEG_B	(1 << 5)
+#define SEG_C	(1 << 4)
+#define SEG_D	(1 << 3)
+#define SEG_E	(1 << 2)
+#define SEG_F	(1 << 1)
+#define SEG_G	(1 << 0)
+
+int _fbxpanel_set_digit(struct fbxpanel *p, int digit, uint16_t value);
+int _fbxpanel_set_state(struct fbxpanel *p, int digit, int value);
+int _fbxpanel_set_blink_speed(struct fbxpanel *p, uint32_t value);
+
+
+#endif /* !__FBXPANEL_PRIV_H */
diff -Nruw linux-2.6.20.14-fbx/drivers/fbxpanel./Kconfig linux-2.6.20.14-fbx/drivers/fbxpanel/Kconfig
--- linux-2.6.20.14-fbx/drivers/fbxpanel./Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/drivers/fbxpanel/Kconfig	2011-09-26 15:07:54.388835397 +0200
@@ -0,0 +1,25 @@
+menu "Freebox Panel Support"
+
+config FREEBOX_PANEL
+	tristate "Freebox Panel Management"
+	default n
+
+config FREEBOX_PANEL_HW_PIC_FBX
+	tristate "I2C PIC-based Panel driver."
+	default n
+	depends on FREEBOX_PANEL
+	select I2C
+
+config FREEBOX_PANEL_HW_PT6959
+	tristate "Princeton 6959-based Panel driver."
+	default n
+	depends on FREEBOX_PANEL
+	select FREEBOX_SPI
+
+config FREEBOX_PANEL_HW_PT6311
+	tristate "Princeton 6311-based Panel driver."
+	default n
+	depends on FREEBOX_PANEL
+	select FREEBOX_SPI
+
+endmenu
diff -Nruw linux-2.6.20.14-fbx/drivers/fbxpanel./Makefile linux-2.6.20.14-fbx/drivers/fbxpanel/Makefile
--- linux-2.6.20.14-fbx/drivers/fbxpanel./Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/drivers/fbxpanel/Makefile	2011-09-26 15:07:54.388835397 +0200
@@ -0,0 +1,9 @@
+obj-$(CONFIG_FREEBOX_PANEL)	+= fbxpanel.o
+
+fbxpanel-objs = fbxpanel_class.o fbxpanel_anim.o
+
+obj-$(CONFIG_FREEBOX_PANEL_HW_PIC_FBX)	+= fbxpanel_hw_pic_fbx.o
+obj-$(CONFIG_FREEBOX_PANEL_HW_PT6959)	+= fbxpanel_hw_pt6959.o
+obj-$(CONFIG_FREEBOX_PANEL_HW_PT6311)	+= fbxpanel_hw_pt6311.o
+
+EXTRA_CFLAGS += -Werror
diff -Nruw linux-2.6.20.14-fbx/drivers/fbxspi./Kconfig linux-2.6.20.14-fbx/drivers/fbxspi/Kconfig
--- linux-2.6.20.14-fbx/drivers/fbxspi./Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/drivers/fbxspi/Kconfig	2011-09-26 15:07:54.388835397 +0200
@@ -0,0 +1,13 @@
+menu "Freebox SPI support"
+
+config FREEBOX_SPI
+	bool "Freebox SPI core"
+	default n
+
+config FREEBOX_SPI_HW_MV88F5181
+	tristate "Support Marvell 88F5181 SPI Hardware."
+	default n
+	depends on FREEBOX_SPI
+	depends on ARCH_MV88FXX81
+
+endmenu
diff -Nruw linux-2.6.20.14-fbx/drivers/fbxspi./Makefile linux-2.6.20.14-fbx/drivers/fbxspi/Makefile
--- linux-2.6.20.14-fbx/drivers/fbxspi./Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/drivers/fbxspi/Makefile	2011-09-26 15:07:54.388835397 +0200
@@ -0,0 +1,10 @@
+##
+##  Makefile for linux-freebox
+##  Created by <nschichan@freebox.fr> on Tue Mar 13 12:35:37 2007
+##  Freebox SA
+##
+
+obj-$(CONFIG_FREEBOX_SPI)		+= fbxspi.o
+obj-$(CONFIG_FREEBOX_SPI_HW_MV88F5181)	+= fbxspi_hw_mv88f5181.o
+
+EXTRA_CFLAGS += -Werror
diff -Nruw linux-2.6.20.14-fbx/drivers/fbxwatchdog./fbxwatchdog_bcm963xx.c linux-2.6.20.14-fbx/drivers/fbxwatchdog/fbxwatchdog_bcm963xx.c
--- linux-2.6.20.14-fbx/drivers/fbxwatchdog./fbxwatchdog_bcm963xx.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/drivers/fbxwatchdog/fbxwatchdog_bcm963xx.c	2011-09-26 15:07:54.388835397 +0200
@@ -0,0 +1,232 @@
+/*
+ * fbxwatchdog_bcm963xx.c for fbxwatchdog
+ * Created by <nschichan@freebox.fr> on Wed Jun 13 15:36:38 2007
+ * Freebox SA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+
+#include <linux/fbxwatchdog.h>
+
+#include <asm/mach-bcm963xx/bcm963xx_regs.h>
+#include <asm/mach-bcm963xx/bcm963xx_io.h>
+#include <asm/mach-bcm963xx/bcm963xx_timer.h>
+
+#define PFX "fbxwatchdog_bcm963xx: "
+
+struct fbxwatchdog_bcm963xx_priv {
+	struct resource *reg_res;
+	void __iomem	*base;
+};
+
+/*
+ * io helpers to access mac registers
+ */
+static inline u32 wdt_readl(struct fbxwatchdog_bcm963xx_priv *priv, u32 off)
+{
+	return bcm_readl(priv->base + off);
+}
+
+static inline void wdt_writel(struct fbxwatchdog_bcm963xx_priv *priv,
+			      u32 val, u32 off)
+{
+	bcm_writel(val, priv->base + off);
+}
+
+/*
+ * callback is called when half the hw countdown is reached
+ */
+static void bcm_watchdog_timer(void *dev_id)
+{
+	struct fbxwatchdog_bcm963xx_priv *priv;
+	struct fbxwatchdog *wdt;
+
+	wdt = dev_id;
+	priv = wdt->priv;
+	spin_lock(&wdt->lock);
+
+	if (!wdt->enabled) {
+		printk(KERN_CRIT "watchdog is still enabled, stopping !\n");
+		wdt_writel(priv, WDT_STOP_1, WDT_CTL_REG);
+		wdt_writel(priv, WDT_STOP_2, WDT_CTL_REG);
+		goto out;
+	}
+
+	/* clear interrupt and reload */
+	wdt_writel(priv, WDT_START_1, WDT_CTL_REG);
+	wdt_writel(priv, WDT_START_2, WDT_CTL_REG);
+
+	if (wdt->cb)
+		wdt->cb(wdt);
+
+out:
+	spin_unlock(&wdt->lock);
+}
+
+static int bcm963xx_wdt_init(struct fbxwatchdog *wdt)
+{
+	int ret;
+	u32 countdown;
+
+	ret = bcm963xx_timer_register(TIMER_WDT_ID, bcm_watchdog_timer, wdt);
+	if (ret)
+		return ret;
+
+	/* install a 1 sec watchdog, that gives 2 irq/s */
+	countdown = bcm963xx_timer_countdown(1000 * 1000);
+	wdt_writel(wdt->priv, countdown, WDT_DEFVAL_REG);
+
+	return 0;
+}
+
+static int bcm963xx_wdt_cleanup(struct fbxwatchdog *wdt)
+{
+	bcm963xx_timer_unregister(TIMER_WDT_ID);
+	return 0;
+}
+
+static int bcm963xx_wdt_start(struct fbxwatchdog *wdt)
+{
+	printk(KERN_INFO PFX "watchdog enabled\n");
+	wdt_writel(wdt->priv, WDT_START_1, WDT_CTL_REG);
+	wdt_writel(wdt->priv, WDT_START_2, WDT_CTL_REG);
+	return 0;
+}
+
+static int bcm963xx_wdt_stop(struct fbxwatchdog *wdt)
+{
+	wdt_writel(wdt->priv, WDT_STOP_1, WDT_CTL_REG);
+	wdt_writel(wdt->priv, WDT_STOP_2, WDT_CTL_REG);
+	printk(KERN_INFO PFX "watchdog disabled\n");
+	return 0;
+}
+
+static int fbxwatchdog_platform_probe(struct platform_device *pdev)
+{
+	struct fbxwatchdog_bcm963xx_priv *priv = NULL;
+	struct fbxwatchdog *wdt = NULL;
+	struct resource *res;
+	unsigned int regmem_size = 0;
+	int err = 0;
+
+	wdt = kzalloc(sizeof (*wdt), GFP_KERNEL);
+	if (!wdt) {
+		printk(KERN_WARNING PFX "unable to allocate memory for "
+		       "watchdog.\n");
+		err = -ENOMEM;
+		goto out_error;
+	}
+
+	priv = kzalloc(sizeof (*priv), GFP_KERNEL);
+	if (!priv) {
+		printk(KERN_WARNING PFX "unable to allocate memory for "
+		       "watchdog priv.\n");
+		err = -ENOMEM;
+		goto out_error;
+	}
+
+	wdt->name = pdev->name;
+	wdt->priv = priv;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		err = -EINVAL;
+		goto out_error;
+	}
+
+	regmem_size = res->end - res->start + 1;
+	if (!request_mem_region(res->start, regmem_size,
+				"bcm963xx_watchdog")) {
+		err = -EINVAL;
+		goto out_error;
+	}
+	priv->reg_res = res;
+
+	priv->base = ioremap(res->start, regmem_size);
+	if (!priv->base) {
+		err = -ENOMEM;
+		goto out_error;
+	}
+
+	wdt->wdt_init = bcm963xx_wdt_init;
+	wdt->wdt_cleanup = bcm963xx_wdt_cleanup;
+	wdt->wdt_start = bcm963xx_wdt_start;
+	wdt->wdt_stop = bcm963xx_wdt_stop;
+
+	err = fbxwatchdog_register(wdt);
+	if (err) {
+		printk(KERN_WARNING PFX "unable to register watchdog %s.\n",
+		       wdt->name);
+		goto out_error;
+	}
+
+	platform_set_drvdata(pdev, wdt);
+
+	return 0;
+
+out_error:
+	if (wdt)
+		kfree(wdt);
+	if (priv) {
+		if (priv->reg_res)
+			release_mem_region(priv->reg_res->start, regmem_size);
+		if (priv->base)
+			iounmap(priv->base);
+		kfree(priv);
+	}
+	return err;
+}
+
+static int fbxwatchdog_platform_remove(struct platform_device *pdev)
+{
+	struct fbxwatchdog_bcm963xx_priv *priv = NULL;
+	struct fbxwatchdog *wdt;
+	unsigned int regmem_size;
+
+	wdt = platform_get_drvdata(pdev);
+	if (!wdt) {
+		BUG();
+		return -ENODEV;
+	}
+
+	fbxwatchdog_unregister(wdt);
+	priv = wdt->priv;
+	regmem_size = priv->reg_res->end - priv->reg_res->start + 1;
+	release_mem_region(priv->reg_res->start, regmem_size);
+	iounmap(priv->base);
+	kfree(wdt->priv);
+	kfree(wdt);
+	return 0;
+}
+
+struct platform_driver fbxwatchdog_platform_driver =
+{
+	.probe		= fbxwatchdog_platform_probe,
+	.remove		= fbxwatchdog_platform_remove,
+	.driver		= {
+		.name	= "bcm963xx_wdt",
+	},
+};
+
+static int __init fbxwatchdog_bcm963xx_init(void)
+{
+	printk(KERN_INFO PFX "2007, Freebox SA.\n");
+	platform_driver_register(&fbxwatchdog_platform_driver);
+	return 0;
+}
+
+static void __exit fbxwatchdog_bcm963xx_exit(void)
+{
+	platform_driver_unregister(&fbxwatchdog_platform_driver);
+}
+
+module_init(fbxwatchdog_bcm963xx_init);
+module_exit(fbxwatchdog_bcm963xx_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Nicolas Schichan <nschichan@freebox.fr>");
+MODULE_DESCRIPTION("Freebox Watchdog, bcm963xx specific bits - www.freebox.fr");
+
diff -Nruw linux-2.6.20.14-fbx/drivers/fbxwatchdog./fbxwatchdog_core.c linux-2.6.20.14-fbx/drivers/fbxwatchdog/fbxwatchdog_core.c
--- linux-2.6.20.14-fbx/drivers/fbxwatchdog./fbxwatchdog_core.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/drivers/fbxwatchdog/fbxwatchdog_core.c	2011-09-26 15:07:54.388835397 +0200
@@ -0,0 +1,328 @@
+/*
+ * fbxwatchdog.c for fbxwatchdog
+ * Created by <nschichan@freebox.fr> on Mon Jun 11 19:26:20 2007
+ * Freebox SA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/reboot.h>
+#include <linux/timer.h>
+#include <linux/jiffies.h>
+
+#include <linux/fbxwatchdog.h>
+
+#define SOFTTIMER_FREQ	(HZ / 10)
+
+#define PFX "fbxwatchdog: "
+
+static ssize_t
+show_enabled(struct class_device *dev, char *buf)
+{
+	struct fbxwatchdog *wdt;
+
+	wdt = dev->class_data;
+	if (!wdt) {
+		printk(KERN_DEBUG "ignoring request to dead watchdog.\n");
+		return -ENODEV;
+	}
+
+	return snprintf(buf, PAGE_SIZE, "%i\n", wdt->enabled);
+}
+
+/*
+ * start/stop watchdog depending on the value of the first character
+ * of buf. set countdown_min to a sane value.
+ */
+static ssize_t
+store_enabled(struct class_device *dev, const char *buf, size_t count)
+{
+	struct fbxwatchdog *wdt;
+	unsigned long flags;
+
+	wdt = dev->class_data;
+	if (!wdt) {
+		printk(KERN_DEBUG "ignoring request to dead watchdog.\n");
+		return -ENODEV;
+	}
+
+	if (count == 0)
+		return 0;
+
+
+	spin_lock_irqsave(&wdt->lock, flags);
+	switch (*buf) {
+	case '0':
+		if (wdt->enabled) {
+			wdt->enabled = 0;
+			wdt->wdt_stop(wdt);
+		}
+		break;
+
+	case '1':
+		if (!wdt->enabled) {
+			wdt->enabled = 1;
+			wdt->wdt_start(wdt);
+			wdt->countdown_min = INT_MAX;
+		}
+		break;
+
+	default:
+		break;
+	}
+	spin_unlock_irqrestore(&wdt->lock, flags);
+
+	return count;
+}
+
+static ssize_t
+show_countdown(struct class_device *dev, char *buf)
+{
+	struct fbxwatchdog *wdt;
+
+	wdt = dev->class_data;
+	if (!wdt) {
+		printk(KERN_DEBUG "ignoring request to dead watchdog.\n");
+		return -ENODEV;
+	}
+
+	return snprintf(buf, PAGE_SIZE, "%i\n", wdt->countdown);
+}
+
+/*
+ * update watchdog countdown with the userland value given in buf.
+ */
+static ssize_t
+store_countdown(struct class_device *dev, const char *buf, size_t count)
+{
+	struct fbxwatchdog *wdt;
+	int countdown;
+	char *ptr;
+
+	wdt = dev->class_data;
+	if (!wdt) {
+		printk(KERN_DEBUG "ignoring request to dead watchdog.\n");
+		return -ENODEV;
+	}
+
+	if (count == 0)
+		return 0;
+
+	ptr = kzalloc(count + 1, GFP_KERNEL);
+	if (!ptr)
+		return -ENOMEM;
+	strlcpy(ptr, buf, count + 1);
+
+	countdown = simple_strtoul(ptr, NULL, 10);
+	wdt->countdown = countdown;
+	kfree(ptr);
+
+	return count;
+}
+
+static ssize_t
+show_countdown_min(struct class_device *dev, char *buf)
+{
+	struct fbxwatchdog *wdt;
+
+	wdt = dev->class_data;
+	if (!wdt) {
+		printk(KERN_DEBUG "ignoring request to dead watchdog.\n");
+		return -ENODEV;
+	}
+
+	return snprintf(buf, PAGE_SIZE, "%i\n", wdt->countdown_min);
+}
+
+static struct class_device_attribute fbxwatchdog_attributes[] = {
+	__ATTR(enabled, 0600, show_enabled, store_enabled),
+	__ATTR(countdown, 0600, show_countdown, store_countdown),
+	__ATTR(countdown_min, 0400, show_countdown_min, NULL),
+	{ },
+};
+
+static struct class fbxwatchdog_class =
+{
+	.name			= "fbxwatchdog",
+	.owner			= THIS_MODULE,
+	.class_dev_attrs	= fbxwatchdog_attributes,
+};
+
+/*
+ * software timer callback: decrement countdown and update
+ * countdown_min if needed. this is called 10 times per second.
+ */
+static void fbxwatchdog_timer_cb(unsigned long data)
+{
+	struct fbxwatchdog *wdt;
+
+	wdt = (struct fbxwatchdog *)data;
+
+	if (wdt->enabled) {
+		wdt->countdown -= jiffies_to_msecs(SOFTTIMER_FREQ);
+		if (wdt->countdown < wdt->countdown_min)
+			wdt->countdown_min = wdt->countdown;
+	}
+
+	wdt->timer.expires = jiffies + SOFTTIMER_FREQ;
+	add_timer(&wdt->timer);
+}
+
+/*
+ * called from half life interrupt handler, panic if countdown is too
+ * low (ie if userland has not reset countdown to before it reached
+ * 0).
+ */
+static void fbxwatchdog_halflife_cb(struct fbxwatchdog *wdt)
+{
+	if (wdt->countdown <= 0) {
+		wdt->wdt_stop(wdt);
+		panic("software fbxwatchdog triggered");
+	}
+}
+
+/*
+ * called when there are no reference on the class device. only free
+ * dev, most of the cleanup stuff has alread been done in the
+ * fbxwatchdog_unregister.
+ */
+static void
+fbxwatchdog_release(struct class_device *dev)
+{
+	printk(KERN_DEBUG PFX "releasing dead device: %s\n", dev->class_id);
+	kfree(dev);
+}
+
+/*
+ * register a new watchdog device.
+ */
+int
+fbxwatchdog_register(struct fbxwatchdog *wdt)
+{
+	int err = 0;
+
+	if (wdt == NULL)
+		return -EFAULT;
+
+	printk(KERN_INFO PFX "registering watchdog %s\n", wdt->name);
+
+	wdt->class_dev = kzalloc(sizeof (struct class_device), GFP_KERNEL);
+	if (!wdt->class_dev) {
+		printk(KERN_ERR PFX "unable to allocate class device.\n");
+		err = -ENOMEM;
+		goto out_error;
+	}
+
+	class_device_initialize(wdt->class_dev);
+	wdt->class_dev->class = &fbxwatchdog_class;
+	wdt->class_dev->class_data = wdt;
+	wdt->class_dev->release = fbxwatchdog_release;
+	strlcpy(wdt->class_dev->class_id, wdt->name, BUS_ID_SIZE);
+
+	err = class_device_add(wdt->class_dev);
+	if (err) {
+		printk(KERN_ERR PFX "unable to register class device %s\n",
+		       wdt->name);
+		goto out_error;
+	}
+
+	/* start countdown soft timer */
+	init_timer(&wdt->timer);
+	wdt->timer.function = fbxwatchdog_timer_cb;
+	wdt->timer.data = (unsigned long)wdt;
+	wdt->timer.expires = jiffies + SOFTTIMER_FREQ;
+	add_timer(&wdt->timer);
+
+	spin_lock_init(&wdt->lock);
+
+	wdt->cb = fbxwatchdog_halflife_cb;
+	err = wdt->wdt_init(wdt);
+	if (err) {
+		printk(KERN_ERR PFX "unable to do low level init of "
+		       "watchdog %s.\n", wdt->name);
+		goto out_del_timer;
+	}
+
+#ifdef CONFIG_FREEBOX_WATCHDOG_CHAR
+	err = fbxwatchdog_char_add(wdt);
+	if (err) {
+		printk(KERN_ERR PFX "unable to add %s to the fbxwatchdog char "
+		       "device interface.\n", wdt->name);
+		goto out_wdt_cleanup;
+	}
+#endif
+
+	return 0;
+
+#ifdef CONFIG_FREEBOX_WATCHDOG_CHAR
+ out_wdt_cleanup:
+	wdt->wdt_cleanup(wdt);
+#endif
+
+ out_del_timer:
+	del_timer_sync(&wdt->timer);
+	class_device_del(wdt->class_dev);
+	class_device_put(wdt->class_dev);
+ out_error:
+	if (wdt->class_dev)
+		kfree(wdt);
+	return err;
+}
+
+int
+fbxwatchdog_unregister(struct fbxwatchdog *wdt)
+{
+	printk(KERN_INFO PFX "registering watchdog %s\n", wdt->name);
+
+	if (wdt->enabled) {
+		unsigned long flags;
+
+		printk(KERN_WARNING "removing enabled watchdog.\n");
+		spin_lock_irqsave(&wdt->lock, flags);
+		wdt->wdt_stop(wdt);
+		spin_unlock_irqrestore(&wdt->lock, flags);
+	}
+
+#ifdef CONFIG_FREEBOX_WATCHDOG_CHAR
+	fbxwatchdog_char_remove(wdt);
+#endif
+	wdt->wdt_cleanup(wdt);
+	del_timer_sync(&wdt->timer);
+	class_device_del(wdt->class_dev);
+	class_device_put(wdt->class_dev);
+	wdt->class_dev->class_data = NULL;
+	return 0;
+}
+
+static int __init
+fbxwatchdog_init(void)
+{
+	int err;
+
+	printk(KERN_INFO PFX "2007, Freebox SA.\n");
+	err = class_register(&fbxwatchdog_class);
+	if (err) {
+		printk(KERN_ERR PFX "");
+		return -1;
+	}
+
+	return 0;
+}
+
+static void __exit
+fbxwatchdog_exit(void)
+{
+	class_unregister(&fbxwatchdog_class);
+}
+
+
+EXPORT_SYMBOL_GPL(fbxwatchdog_register);
+EXPORT_SYMBOL_GPL(fbxwatchdog_unregister);
+
+module_init(fbxwatchdog_init);
+module_exit(fbxwatchdog_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Nicolas Schichan <nschichan@freebox.fr>");
+MODULE_DESCRIPTION("Freebox Watchdog Core - www.freebox.fr");
diff -Nruw linux-2.6.20.14-fbx/drivers/fbxwatchdog./Kconfig linux-2.6.20.14-fbx/drivers/fbxwatchdog/Kconfig
--- linux-2.6.20.14-fbx/drivers/fbxwatchdog./Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/drivers/fbxwatchdog/Kconfig	2011-09-26 15:07:54.388835397 +0200
@@ -0,0 +1,24 @@
+menu "Freebox Watchdog Support"
+
+config FREEBOX_WATCHDOG
+	tristate "Freebox Watchdog"
+	default n
+
+config FREEBOX_WATCHDOG_CHAR
+	bool "Freebox Watchdog char device interface."
+	depends on FREEBOX_WATCHDOG
+	default n
+
+config FREEBOX_WATCHDOG_MV88F5181
+	tristate "Marvell 88f5181 Freebox Watchdog support"
+	depends on FREEBOX_WATCHDOG
+	depends on ARCH_MV88FXX81
+	default n
+
+config FREEBOX_WATCHDOG_BCM963XX
+	tristate "Broadcom 963xx Freebox Watchdog support"
+	depends on FREEBOX_WATCHDOG
+	depends on BCM963XX
+	default n
+
+endmenu
diff -Nruw linux-2.6.20.14-fbx/drivers/fbxwatchdog./Makefile linux-2.6.20.14-fbx/drivers/fbxwatchdog/Makefile
--- linux-2.6.20.14-fbx/drivers/fbxwatchdog./Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/drivers/fbxwatchdog/Makefile	2011-09-26 15:07:54.388835397 +0200
@@ -0,0 +1,10 @@
+
+obj-$(CONFIG_FREEBOX_WATCHDOG) += fbxwatchdog.o
+
+fbxwatchdog-objs = fbxwatchdog_core.o
+ifeq ($(CONFIG_FREEBOX_WATCHDOG_CHAR),y)
+fbxwatchdog-objs += fbxwatchdog_char.o
+endif
+
+obj-$(CONFIG_FREEBOX_WATCHDOG_MV88F5181) += fbxwatchdog_mv88f5181.o
+obj-$(CONFIG_FREEBOX_WATCHDOG_BCM963XX)	+= fbxwatchdog_bcm963xx.o
--- /dev/null	2011-06-03 14:51:38.633053002 +0200
+++ linux-2.6.20.14-fbx/drivers/i2c/busses/i2c-gpio.c	2011-09-26 15:07:54.408835384 +0200
@@ -0,0 +1,158 @@
+/*
+ * i2c-gpio.c for linux-freebox
+ * Created by <nschichan@freebox.fr> on Tue Mar  6 13:42:48 2007
+ * Freebox SA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/platform_device.h>
+#include <linux/i2c-gpio.h>
+
+#define PFX "i2c-gpio: "
+
+enum {
+	E_GPIO_SCL,
+	E_GPIO_SDA,
+};
+
+static void
+i2c_gpio_setscl(void *data, int state)
+{
+	struct i2c_gpio_platform_data *pdat = data;
+
+	pdat->gpio_set_dataout(pdat->gpio_scl, state);
+}
+
+static void
+i2c_gpio_setsda(void *data, int state)
+{
+	struct i2c_gpio_platform_data *pdat = data;
+
+	if (state) {
+		pdat->gpio_set_direction(pdat->gpio_sda, 1);
+	} else {
+		pdat->gpio_set_direction(pdat->gpio_sda, 0);
+		pdat->gpio_set_dataout(pdat->gpio_sda, 0);
+	}
+}
+
+static int
+i2c_gpio_getsda(void *data)
+{
+	struct i2c_gpio_platform_data *pdat = data;
+
+	return pdat->gpio_get_dataout(pdat->gpio_sda);
+}
+
+/*
+ * kzalloc adapter and algorithm data. attach adapter to driver data
+ * for easy retrieval when removing the driver.
+ */
+static int
+i2c_gpio_probe(struct platform_device *pdev)
+{
+	int err;
+	struct i2c_adapter *adapter = NULL;
+	struct i2c_algo_bit_data *algo = NULL;
+	struct i2c_gpio_platform_data *pdat;
+
+	pdat = pdev->dev.platform_data;
+
+	adapter = kzalloc(sizeof (*adapter), GFP_KERNEL);
+	if (adapter == NULL) {
+		err = -ENOMEM;
+		goto out_error;
+	}
+
+	strcpy(adapter->name, "GPIO I2C bus");
+	adapter->owner = THIS_MODULE;
+
+	algo = kzalloc(sizeof (*algo), GFP_KERNEL);
+	if (algo == NULL) {
+		err = -ENOMEM;
+		goto out_error;
+	}
+
+	algo->setsda = i2c_gpio_setsda;
+	algo->getsda = i2c_gpio_getsda;
+	algo->setscl = i2c_gpio_setscl;
+	algo->udelay = 50;
+	algo->timeout = 0;
+	algo->data = pdat;
+
+	adapter->algo_data = algo;
+
+	/* configure gpio direction/output default values */
+	pdat->gpio_set_dataout(pdat->gpio_scl, 1);
+	pdat->gpio_set_direction(pdat->gpio_scl, 0);
+	pdat->gpio_set_direction(pdat->gpio_sda, 1);
+
+	/* add i2c adapter */
+	err = i2c_bit_add_bus(adapter);
+	if (err < 0) {
+		printk(KERN_ERR PFX "unable to add gpio I2C bus.\n");
+		err = -ENODEV;
+		goto out_error;
+	}
+
+	platform_set_drvdata(pdev, adapter);
+
+	return 0;
+
+ out_error:
+	if (adapter)
+		kfree(adapter);
+	if (algo)
+		kfree(algo);
+	return err;
+}
+
+/*
+ * remove adapter and kfree algo and adapter.
+ */
+static int
+i2c_gpio_remove(struct platform_device *pdev)
+{
+	struct i2c_adapter *a;
+
+	a = platform_get_drvdata(pdev);
+	if (i2c_del_adapter(a) < 0)
+		return -EINVAL;
+	kfree(a->algo_data);
+	kfree(a);
+	return 0;
+}
+
+struct platform_driver i2c_gpio_driver =
+{
+	.probe	= i2c_gpio_probe,
+	.remove	= i2c_gpio_remove,
+	.driver	= {
+		.name	= "i2c-gpio",
+		.owner	= THIS_MODULE,
+	},
+};
+
+int __init
+i2c_gpio_init(void)
+{
+	printk(KERN_INFO PFX "2007, Freebox SA\n");
+	return platform_driver_register(&i2c_gpio_driver);
+}
+
+void __exit
+i2c_gpio_exit(void)
+{
+	platform_driver_unregister(&i2c_gpio_driver);
+}
+
+
+
+module_init(i2c_gpio_init);
+module_exit(i2c_gpio_exit);
+
+MODULE_AUTHOR("Nicolas Schichan <nschichan@freebox.fr>");
+MODULE_LICENSE("GPL");
diff -Nruw linux-2.6.20.14-fbx/drivers/media/dvb/tango2./Kconfig linux-2.6.20.14-fbx/drivers/media/dvb/tango2/Kconfig
--- linux-2.6.20.14-fbx/drivers/media/dvb/tango2./Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/drivers/media/dvb/tango2/Kconfig	2011-09-26 15:07:54.578835279 +0200
@@ -0,0 +1,11 @@
+config DVB_TANGO2
+	tristate "Tango2 DVB adapter"
+	depends on DVB_CORE && ARCH_FBX5_B
+	select I2C
+	select I2C_ALGOBIT
+	select DVB_TDA1004X
+	select DVB_PLL
+
+config DVB_TANGO2_TESTBED
+	bool "extended testing and useful error codes"
+	depends on DVB_TANGO2
diff -Nruw linux-2.6.20.14-fbx/drivers/media/dvb/tango2./Makefile linux-2.6.20.14-fbx/drivers/media/dvb/tango2/Makefile
--- linux-2.6.20.14-fbx/drivers/media/dvb/tango2./Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/drivers/media/dvb/tango2/Makefile	2011-09-26 15:07:54.578835279 +0200
@@ -0,0 +1,5 @@
+obj-$(CONFIG_DVB_TANGO2) = tango2_dvb.o
+
+tango2_dvb-objs	:= tango2.o
+
+EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff -Nruw linux-2.6.20.14-fbx/drivers/misc/bcm963xx_dsl./Makefile linux-2.6.20.14-fbx/drivers/misc/bcm963xx_dsl/Makefile
--- linux-2.6.20.14-fbx/drivers/misc/bcm963xx_dsl./Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/drivers/misc/bcm963xx_dsl/Makefile	2011-09-26 15:07:54.658835231 +0200
@@ -0,0 +1,13 @@
+obj-$(CONFIG_BCM963XX_DSL_ALT) += bcm963xx_dsl.o
+
+bcm963xx_dsl-objs +=	bcm_dsl.o		\
+			bcm_dsl_cdata.o		\
+			bcm_dsl_ovhdata.o
+
+bcm963xx_dsl-objs +=	adsl_fbxprocfs.o
+
+bcm963xx_dsl-objs +=	bcm_dsl_debug.o
+bcm963xx_dsl-objs +=	phy_strings.o
+bcm963xx_dsl-objs +=	g992_strings.o
+
+bcm963xx_dsl-objs +=	hdlc.o
--- /dev/null	2011-06-03 14:51:38.633053002 +0200
+++ linux-2.6.20.14-fbx/drivers/misc/crash_zone.c	2011-09-26 15:07:54.658835231 +0200
@@ -0,0 +1,145 @@
+#include <linux/init.h>
+#include <linux/crash_zone.h>
+#include <linux/proc_fs.h>
+#include <asm/checksum.h>
+
+static unsigned char *dead_zone = NULL;
+static unsigned int dead_zone_size;
+
+#define CRASH_DATA_SIZE	(dead_zone_size - sizeof (struct crash_zone))
+
+static inline unsigned short int csum_data(const unsigned char *buff, int len)
+{
+	return csum_fold(csum_partial(buff, len, 0));
+}
+
+static int crash_zone_read_proc(char *page, char **start, off_t off,
+				int count, int *eof, void *data)
+{
+	struct crash_header *crash_zone;
+	int datalen;
+
+	/* check crash zone */
+	if (!dead_zone) {
+		printk(KERN_DEBUG "dead zone unset\n");
+		goto empty;
+	}
+
+	crash_zone = (struct crash_header *)dead_zone;
+	if (crash_zone->magic != CRASH_MAGIC) {
+		printk(KERN_DEBUG "bad crash zone magic\n");
+		goto empty;
+	}
+
+	if (crash_zone->len > dead_zone_size) {
+		printk(KERN_DEBUG "bad crash zone len\n");
+		goto empty;
+	}
+
+	if (csum_data((unsigned char *)crash_zone, crash_zone->len)) {
+		printk(KERN_DEBUG "bad crash zone checksum\n");
+		goto empty;
+	}
+
+	/* copy crash data */
+	datalen = crash_zone->len - sizeof (struct crash_header);
+	if (off + count >= datalen) {
+		*eof = 1;
+		count = datalen - off;
+	}
+
+	*start = page;
+	if (count > 0) {
+		memcpy(page, &crash_zone->data + off, count);
+		return count;
+	}
+
+	return 0;
+
+empty:
+	*eof = 1;
+	return 0;
+}
+
+static int crash_zone_write_proc(struct file *file, const char *buffer,
+				 unsigned long count, void *data)
+{
+	struct crash_header *crash_zone;
+	int len;
+
+	if (!dead_zone)
+		return count;
+
+	/* empty the crash zone */
+	crash_zone = (struct crash_header *)dead_zone;
+	len = sizeof (struct crash_header);
+	crash_zone->magic = CRASH_MAGIC;
+	crash_zone->len = len;
+	crash_zone->checksum = 0;
+	crash_zone->checksum = csum_data((unsigned char *)crash_zone, len);
+
+	return count;
+}
+
+static int crash_zone_panic_event(struct notifier_block *self,
+				  unsigned long event, void *data)
+{
+	struct crash_header *crash_zone;
+	int data_len, len;
+
+	if (!dead_zone)
+		return NOTIFY_DONE;
+
+	crash_zone = (struct crash_header *)dead_zone;
+
+	/* copy current kernel log into crash zone */
+	data_len = dead_zone_size - sizeof (struct crash_header);
+	console_emergency_dump(&crash_zone->data, &data_len);
+
+	/* checksum area */
+	len = data_len + sizeof (struct crash_header);
+	crash_zone->magic = CRASH_MAGIC;
+	crash_zone->len = len;
+	crash_zone->checksum = 0;
+	crash_zone->checksum = csum_data((unsigned char *)crash_zone, len);
+	printk("Panic log saved in crash zone\n");
+
+        return NOTIFY_DONE;
+}
+
+static struct notifier_block crash_panic_block = {
+	crash_zone_panic_event,
+        NULL,
+        INT_MAX /* try to do it first */
+};
+
+void __init crash_zone_set_param(unsigned char *zone, unsigned int size)
+{
+	dead_zone = zone;
+	dead_zone_size = size;
+}
+
+static int __init crash_zone_init(void)
+{
+	struct proc_dir_entry	*proc;
+
+	/* create crash proc entry */
+	proc = create_proc_entry("crash_zone", 0, NULL);
+	if (!proc)
+		return 1;
+	proc->read_proc  = crash_zone_read_proc;
+	proc->write_proc = crash_zone_write_proc;
+
+	/* register panic notifier */
+	atomic_notifier_chain_register(&panic_notifier_list,
+				       &crash_panic_block);
+	return 0;
+}
+
+static void __exit crash_zone_exit(void)
+{
+
+}
+
+module_init(crash_zone_init);
+module_exit(crash_zone_exit);
--- /dev/null	2011-06-03 14:51:38.633053002 +0200
+++ linux-2.6.20.14-fbx/drivers/net/bcm963xx_enet.c	2011-09-26 15:07:54.708835201 +0200
@@ -0,0 +1,1935 @@
+/*
+ * Driver for BCM963xx builtin Ethernet mac
+ *
+ * Copyright (C) 2007 Maxime Bizon <mbizon@freebox.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <linux/ethtool.h>
+#include <linux/crc32.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-bcm963xx/devices.h>
+#include <asm/mach-bcm963xx/bcm963xx_io.h>
+
+#include "bcm963xx_enet.h"
+
+static char bcm_enet_driver_name[] = "bcm963xx_enet";
+static char bcm_enet_driver_version[] = "1.0";
+
+static int copybreak __read_mostly = 128;
+module_param(copybreak, int, 0);
+MODULE_PARM_DESC(copybreak, "Receive copy threshold");
+
+/* io memory shared between all devices */
+static void __iomem *bcm_enet_shared_base;
+
+/*
+ * io helpers to access mac registers
+ */
+static inline u32 enet_readl(struct bcm_enet_priv *priv, u32 off)
+{
+	return bcm_readl(priv->base + off);
+}
+
+static inline void enet_writel(struct bcm_enet_priv *priv,
+			       u32 val, u32 off)
+{
+	bcm_writel(val, priv->base + off);
+}
+
+/*
+ * io helpers to access shared registers
+ */
+static inline u32 enet_dma_readl(struct bcm_enet_priv *priv, u32 off)
+{
+	return bcm_readl(bcm_enet_shared_base + off);
+}
+
+static inline void enet_dma_writel(struct bcm_enet_priv *priv,
+				       u32 val, u32 off)
+{
+	bcm_writel(val, bcm_enet_shared_base + off);
+}
+
+/*
+ * write given data into mii register and wait for transfer to end
+ * with timeout (average measured transfer time is 25us)
+ */
+static int do_mdio_op(struct bcm_enet_priv *priv, unsigned int data)
+{
+	int limit;
+
+	/* make sure mii interrupt status is cleared */
+	enet_writel(priv, ENET_IR_MII, ENET_IR_REG);
+
+	enet_writel(priv, data, ENET_MIIDATA_REG);
+	wmb();
+
+	/* busy wait on mii interrupt bit, with timeout */
+	limit = 1000;
+	do {
+		if (enet_readl(priv, ENET_IR_REG) & ENET_IR_MII)
+			break;
+		udelay(1);
+	} while (limit-- >= 0);
+
+	return (limit < 0) ? 1 : 0;
+}
+
+/*
+ * MII internal read callback
+ */
+static int bcm_enet_mdio_read(struct bcm_enet_priv *priv, int mii_id,
+			      int regnum)
+{
+	u32 tmp, val;
+
+	tmp = regnum << ENET_MIIDATA_REG_SHIFT;
+	tmp |= 0x2 << ENET_MIIDATA_TA_SHIFT;
+	tmp |= mii_id << ENET_MIIDATA_PHYID_SHIFT;
+	tmp |= ENET_MIIDATA_OP_READ_MASK;
+
+	if (do_mdio_op(priv, tmp))
+		return -1;
+
+	val = enet_readl(priv, ENET_MIIDATA_REG);
+	val &= 0xffff;
+	return val;
+}
+
+/*
+ * MII internal write callback
+ */
+static int bcm_enet_mdio_write(struct bcm_enet_priv *priv, int mii_id,
+			       int regnum, u16 value)
+{
+	u32 tmp;
+
+	tmp = (value & 0xffff) << ENET_MIIDATA_DATA_SHIFT;
+	tmp |= 0x2 << ENET_MIIDATA_TA_SHIFT;
+	tmp |= regnum << ENET_MIIDATA_REG_SHIFT;
+	tmp |= mii_id << ENET_MIIDATA_PHYID_SHIFT;
+	tmp |= ENET_MIIDATA_OP_WRITE_MASK;
+
+	(void)do_mdio_op(priv, tmp);
+	return 0;
+}
+
+/*
+ * MII read callback from phylib
+ */
+static int bcm_enet_mdio_read_phylib(struct mii_bus *bus, int mii_id,
+				     int regnum)
+{
+	return bcm_enet_mdio_read(bus->priv, mii_id, regnum);
+}
+
+/*
+ * MII write callback from phylib
+ */
+static int bcm_enet_mdio_write_phylib(struct mii_bus *bus, int mii_id,
+				      int regnum, u16 value)
+{
+	return bcm_enet_mdio_write(bus->priv, mii_id, regnum, value);
+}
+
+/*
+ * MII read callback from mii core
+ */
+static int bcm_enet_mdio_read_mii(struct net_device *dev, int mii_id,
+				  int regnum)
+{
+	return bcm_enet_mdio_read(netdev_priv(dev), mii_id, regnum);
+}
+
+/*
+ * MII write callback from mii core
+ */
+static void bcm_enet_mdio_write_mii(struct net_device *dev, int mii_id,
+				    int regnum, int value)
+{
+	bcm_enet_mdio_write(netdev_priv(dev), mii_id, regnum, value);
+}
+
+/*
+ * refill rx queue
+ */
+static int bcm_enet_refill_rx(struct net_device *dev)
+{
+	struct bcm_enet_priv *priv;
+
+	priv = netdev_priv(dev);
+
+	while (priv->rx_desc_count < priv->rx_ring_size) {
+		struct bcm_enet_desc *desc;
+		struct sk_buff *skb;
+		dma_addr_t p;
+		int desc_idx;
+		u32 len_stat;
+
+		desc_idx = priv->rx_dirty_desc;
+		desc = &priv->rx_desc_cpu[desc_idx];
+
+		if (!priv->rx_skb[desc_idx]) {
+			skb = netdev_alloc_skb(dev, BCMENET_RX_SKB_SIZE);
+			if (!skb)
+				break;
+			priv->rx_skb[desc_idx] = skb;
+
+			p = dma_map_single(&priv->pdev->dev, skb->data,
+					   BCMENET_RX_SKB_SIZE,
+					   DMA_FROM_DEVICE);
+			desc->address = p;
+		}
+
+		len_stat = BCMENET_RX_SKB_SIZE << DMADESC_LENGTH_SHIFT;
+		len_stat |= DMADESC_OWNER_MASK;
+		if (priv->rx_dirty_desc == priv->rx_ring_size - 1) {
+			len_stat |= DMADESC_WRAP_MASK;
+			priv->rx_dirty_desc = 0;
+		} else {
+			priv->rx_dirty_desc++;
+		}
+		wmb();
+		desc->len_stat = len_stat;
+
+		priv->rx_desc_count++;
+
+		/* tell dma engine we allocated one buffer */
+		enet_dma_writel(priv, 1, ENETDMA_BUFALLOC_REG(priv->rx_chan));
+	}
+
+	/* If rx ring is still empty, set a timer to try allocating
+	 * again at a later time. */
+	if (priv->rx_desc_count == 0 && netif_running(dev)) {
+		dev_warn(&priv->pdev->dev, "unable to refill rx ring\n");
+		priv->rx_timeout.expires = jiffies + HZ;
+		add_timer(&priv->rx_timeout);
+	}
+
+	return 0;
+}
+
+/*
+ * timer callback to defer refill rx queue in case we're OOM
+ */
+static void bcm_enet_refill_rx_timer(unsigned long data)
+{
+	struct net_device *dev;
+	struct bcm_enet_priv *priv;
+
+	dev = (struct net_device *)data;
+	priv = netdev_priv(dev);
+
+	spin_lock(&priv->rx_lock);
+	bcm_enet_refill_rx((struct net_device *)data);
+	spin_unlock(&priv->rx_lock);
+}
+
+/*
+ * extract packet from rx queue
+ */
+static int bcm_enet_receive_queue(struct net_device *dev, int budget)
+{
+	struct bcm_enet_priv *priv;
+	struct device *kdev;
+	int processed;
+
+	priv = netdev_priv(dev);
+	kdev = &priv->pdev->dev;
+	processed = 0;
+
+	/* don't scan ring further than number of refilled
+	 * descriptor */
+	if (budget > priv->rx_desc_count)
+		budget = priv->rx_desc_count;
+
+	do {
+		struct bcm_enet_desc *desc;
+		struct sk_buff *skb;
+		int desc_idx;
+		u32 len_stat;
+		unsigned int len;
+
+		desc_idx = priv->rx_curr_desc;
+		desc = &priv->rx_desc_cpu[desc_idx];
+
+		/* make sure we actually read the descriptor status at
+		 * each loop */
+		rmb();
+
+		len_stat = desc->len_stat;
+
+		/* break if dma ownership belongs to hw */
+		if (len_stat & DMADESC_OWNER_MASK)
+			break;
+
+		processed++;
+		priv->rx_curr_desc++;
+		if (priv->rx_curr_desc == priv->rx_ring_size)
+			priv->rx_curr_desc = 0;
+		priv->rx_desc_count--;
+
+		/* if the packet does not have start of packet _and_
+		 * end of packet flag set, then just recycle it */
+		if ((len_stat & DMADESC_ESOP_MASK) != DMADESC_ESOP_MASK) {
+			priv->stats.rx_dropped++;
+			continue;
+		}
+
+		/* recycle packet if it's marked as bad */
+		if (unlikely(len_stat & DMADESC_ERR_MASK)) {
+			priv->stats.rx_errors++;
+
+			if (len_stat & DMADESC_OVSIZE_MASK)
+				priv->stats.rx_length_errors++;
+			if (len_stat & DMADESC_CRC_MASK)
+				priv->stats.rx_crc_errors++;
+			if (len_stat & DMADESC_UNDER_MASK)
+				priv->stats.rx_frame_errors++;
+			if (len_stat & DMADESC_OV_MASK)
+				priv->stats.rx_fifo_errors++;
+			continue;
+		}
+
+		/* valid packet */
+		skb = priv->rx_skb[desc_idx];
+		len = (len_stat & DMADESC_LENGTH_MASK) >> DMADESC_LENGTH_SHIFT;
+		/* don't include FCS */
+		len -= 4;
+
+		if (len < copybreak) {
+			struct sk_buff *nskb;
+
+			nskb = netdev_alloc_skb(dev, len + 2);
+			if (!nskb) {
+				/* forget packet, just rearm desc */
+				priv->stats.rx_dropped++;
+				continue;
+			}
+
+			/* since we're copying the data, we can align
+			 * them properly */
+			if (!priv->use_marvell_header)
+				skb_reserve(nskb, NET_IP_ALIGN);
+			dma_sync_single_for_cpu(kdev, desc->address,
+						len, DMA_FROM_DEVICE);
+			memcpy(nskb->data, skb->data, len);
+			dma_sync_single_for_device(kdev, desc->address,
+						   len, DMA_FROM_DEVICE);
+			skb = nskb;
+		} else {
+			dma_unmap_single(&priv->pdev->dev, desc->address,
+					 BCMENET_RX_SKB_SIZE, DMA_FROM_DEVICE);
+			priv->rx_skb[desc_idx] = NULL;
+		}
+
+		skb_put(skb, len);
+		if (priv->use_marvell_header) {
+			skb_pull(skb, 2);
+			len -= 2;
+		}
+		skb->dev = dev;
+		skb->protocol = eth_type_trans(skb, dev);
+		priv->stats.rx_packets++;
+		priv->stats.rx_bytes += len;
+		dev->last_rx = jiffies;
+		netif_receive_skb(skb);
+
+	} while (--budget > 0);
+
+	if (processed || !priv->rx_desc_count) {
+		bcm_enet_refill_rx(dev);
+
+		/* kick rx dma */
+		enet_dma_writel(priv, ENETDMA_CHANCFG_EN_MASK,
+				ENETDMA_CHANCFG_REG(priv->rx_chan));
+	}
+
+	return processed;
+}
+
+/*
+ * try to or force reclaim of transmitted buffers
+ */
+static int bcm_enet_tx_reclaim(struct net_device *dev, int force)
+{
+	struct bcm_enet_priv *priv;
+	int released;
+
+	priv = netdev_priv(dev);
+	released = 0;
+
+	while (priv->tx_desc_count < priv->tx_ring_size) {
+		struct bcm_enet_desc *desc;
+		struct sk_buff *skb;
+
+		/* We run in a bh and fight against start_xmit, which
+		 * is called with bh disabled  */
+		spin_lock(&priv->tx_lock);
+
+		desc = &priv->tx_desc_cpu[priv->tx_dirty_desc];
+
+		if (!force && (desc->len_stat & DMADESC_OWNER_MASK)) {
+			spin_unlock(&priv->tx_lock);
+			break;
+		}
+
+		/* ensure other field of the descriptor were not read
+		 * before we checked ownership */
+		rmb();
+
+		skb = priv->tx_skb[priv->tx_dirty_desc];
+		priv->tx_skb[priv->tx_dirty_desc] = NULL;
+		dma_unmap_single(&priv->pdev->dev, desc->address, skb->len,
+				 DMA_TO_DEVICE);
+
+		priv->tx_dirty_desc++;
+		if (priv->tx_dirty_desc == priv->tx_ring_size)
+			priv->tx_dirty_desc = 0;
+		priv->tx_desc_count++;
+
+		spin_unlock(&priv->tx_lock);
+
+		if (desc->len_stat & DMADESC_UNDER_MASK)
+			priv->stats.tx_errors++;
+
+		dev_kfree_skb(skb);
+		released++;
+	}
+
+	if (netif_queue_stopped(dev) && released)
+		netif_wake_queue(dev);
+
+	return released;
+}
+
+/*
+ * poll func, called by network core
+ */
+static int bcm_enet_poll(struct net_device *dev, int *budget)
+{
+	struct bcm_enet_priv *priv;
+	int orig_budget, tx_work_done, rx_work_done;
+
+	priv = netdev_priv(dev);
+
+	/* ack interrupts */
+	enet_dma_writel(priv, ENETDMA_IR_PKTDONE_MASK,
+			ENETDMA_IR_REG(priv->rx_chan));
+	enet_dma_writel(priv, ENETDMA_IR_PKTDONE_MASK,
+			ENETDMA_IR_REG(priv->tx_chan));
+
+	/* reclaim sent skb */
+	tx_work_done = bcm_enet_tx_reclaim(dev, 0);
+
+	orig_budget = *budget;
+	if (orig_budget > dev->quota)
+		orig_budget = dev->quota;
+
+	spin_lock(&priv->rx_lock);
+	rx_work_done = bcm_enet_receive_queue(dev, orig_budget);
+	spin_unlock(&priv->rx_lock);
+
+	*budget -= rx_work_done;
+	dev->quota -= rx_work_done;
+
+	if (rx_work_done >= orig_budget || tx_work_done > 0) {
+		/* rx/tx queue is not yet empty/clean */
+		return 1;
+	}
+
+	/* no more packet in rx/tx queue, remove device from poll
+	 * queue */
+	netif_rx_complete(dev);
+
+	/* restore rx/tx interrupt */
+	enet_dma_writel(priv, ENETDMA_IR_PKTDONE_MASK,
+			ENETDMA_IRMASK_REG(priv->rx_chan));
+	enet_dma_writel(priv, ENETDMA_IR_PKTDONE_MASK,
+			ENETDMA_IRMASK_REG(priv->tx_chan));
+
+	return 0;
+}
+
+/*
+ * mac interrupt handler
+ */
+static irqreturn_t bcm_enet_isr_mac(int irq, void *dev_id)
+{
+	struct net_device *dev;
+	struct bcm_enet_priv *priv;
+	u32 stat;
+
+	dev = dev_id;
+	priv = netdev_priv(dev);
+
+	stat = enet_readl(priv, ENET_IR_REG);
+	if (!(stat & ENET_IR_MIB))
+		return IRQ_NONE;
+
+	enet_writel(priv, ENET_IR_MIB, ENET_IR_REG);
+
+	/* read mib registers in workqueue */
+	schedule_work(&priv->mib_update_task);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * rx/tx dma interrupt handler
+ */
+static irqreturn_t bcm_enet_isr_dma(int irq, void *dev_id)
+{
+	struct net_device *dev;
+	struct bcm_enet_priv *priv;
+
+	dev = dev_id;
+	priv = netdev_priv(dev);
+
+	/* mask rx/tx interrupts */
+	enet_dma_writel(priv, 0, ENETDMA_IRMASK_REG(priv->rx_chan));
+	enet_dma_writel(priv, 0, ENETDMA_IRMASK_REG(priv->tx_chan));
+
+	netif_rx_schedule(dev);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * tx request callback
+ */
+static int bcm_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct bcm_enet_priv *priv;
+	struct bcm_enet_desc *desc;
+	u32 len_stat;
+	int ret;
+
+	priv = netdev_priv(dev);
+
+	/* lock against tx reclaim */
+	spin_lock(&priv->tx_lock);
+
+	/* make sure  the tx hw queue  is not full,  should not happen
+	 * since we stop queue before it's the case */
+	if (unlikely(!priv->tx_desc_count)) {
+		netif_stop_queue(dev);
+		dev_err(&priv->pdev->dev, "xmit called with no tx desc "
+			"available?\n");
+		ret = NETDEV_TX_BUSY;
+		goto out_unlock;
+	}
+
+	/* add marvell header if needed */
+	if (priv->use_marvell_header) {
+		if (skb_shared(skb) || skb_header_cloned(skb)) {
+			struct sk_buff *nskb;
+
+			nskb = pskb_copy(skb, GFP_ATOMIC);
+			if (!nskb) {
+				ret = NETDEV_TX_BUSY;
+				goto out_unlock;
+			}
+			dev_kfree_skb(skb);
+			skb = nskb;
+		}
+
+		if (unlikely(skb_headroom(skb) < 2)) {
+			dev_err(&priv->pdev->dev, ": not enough "
+				"headroom to add marvell header\n");
+			dev_kfree_skb(skb);
+			ret = NETDEV_TX_OK;
+			goto out_unlock;
+		}
+		skb_push(skb, 2);
+
+		/*
+		 * Workaround for fbx5a, sometimes switch seems to see
+		 * a non zero marvell header (PAUSE frame), and update
+		 * VLAN map register with bogus data, making the port
+		 * unusable.
+		 *
+		 * Setting VLAN  table of port 4 to  its default value
+		 * without setting  ForceMap bit is a  nop, but ensure
+		 * that  each packet  sent  will update  the VLAN  map
+		 * register with correct data.
+		 */
+		skb->data[0] = 0;
+		skb->data[1] = 0x2f;
+
+		/* workaround a crc generation problem if skb is too
+		 * small */
+		if (skb->len < 64) {
+			int needed = 64 - skb->len;
+			char *data;
+
+			if (unlikely(skb_tailroom(skb) < needed)) {
+				struct sk_buff *nskb;
+
+				nskb = skb_copy_expand(skb, 0, needed,
+						       GFP_ATOMIC);
+				if (!nskb) {
+					ret = NETDEV_TX_BUSY;
+					goto out_unlock;
+				}
+				dev_kfree_skb(skb);
+				skb = nskb;
+			}
+			data = skb_put(skb, needed);
+			memset(data, 0, needed);
+		}
+	}
+
+	/* point to the next available desc */
+	desc = &priv->tx_desc_cpu[priv->tx_curr_desc];
+	priv->tx_skb[priv->tx_curr_desc] = skb;
+
+	/* fill descriptor */
+	desc->address = dma_map_single(&priv->pdev->dev, skb->data, skb->len,
+				       DMA_TO_DEVICE);
+
+	len_stat = (skb->len << DMADESC_LENGTH_SHIFT) & DMADESC_LENGTH_MASK;
+	len_stat |= DMADESC_ESOP_MASK |
+		DMADESC_APPEND_CRC |
+		DMADESC_OWNER_MASK;
+
+	priv->tx_curr_desc++;
+	if (priv->tx_curr_desc == priv->tx_ring_size) {
+		priv->tx_curr_desc = 0;
+		len_stat |= DMADESC_WRAP_MASK;
+	}
+	priv->tx_desc_count--;
+
+	/* dma might be already polling, make sure we update desc
+	 * fields in correct order */
+	wmb();
+	desc->len_stat = len_stat;
+	wmb();
+
+	/* kick tx dma */
+	enet_dma_writel(priv, ENETDMA_CHANCFG_EN_MASK,
+			ENETDMA_CHANCFG_REG(priv->tx_chan));
+
+	/* stop queue if no more desc available */
+	if (!priv->tx_desc_count)
+		netif_stop_queue(dev);
+
+	priv->stats.tx_bytes += skb->len;
+	priv->stats.tx_packets++;
+	dev->trans_start = jiffies;
+	ret = NETDEV_TX_OK;
+
+out_unlock:
+	spin_unlock(&priv->tx_lock);
+	return ret;
+}
+
+/*
+ * Change the interface's mac address.
+ */
+static int bcm_enet_set_mac_address(struct net_device *dev, void *p)
+{
+	struct bcm_enet_priv *priv;
+	struct sockaddr *addr = p;
+	u32 val;
+
+	priv = netdev_priv(dev);
+	memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
+
+	/* use perfect match register 0 to store my mac address */
+	val = (dev->dev_addr[2] << 24) | (dev->dev_addr[3] << 16) |
+		(dev->dev_addr[4] << 8) | dev->dev_addr[5];
+	enet_writel(priv, val, ENET_PML_REG(0));
+
+	val = (dev->dev_addr[0] << 8 | dev->dev_addr[1]);
+	val |= ENET_PMH_DATAVALID_MASK;
+	enet_writel(priv, val, ENET_PMH_REG(0));
+
+	return 0;
+}
+
+/*
+ * Change rx mode (promiscous/allmulti) and update multicast list
+ */
+static void bcm_enet_set_multicast_list(struct net_device *dev)
+{
+	struct bcm_enet_priv *priv;
+	struct dev_mc_list *mc_list;
+	u32 val;
+	int i;
+
+	priv = netdev_priv(dev);
+
+	val = enet_readl(priv, ENET_RXCFG_REG);
+
+	if (!priv->use_marvell_header) {
+		if (dev->flags & IFF_PROMISC)
+			val |= ENET_RXCFG_PROMISC_MASK;
+		else
+			val &= ~ENET_RXCFG_PROMISC_MASK;
+	}
+
+	/* only 3 perfect match registers left, first one is used for
+	 * own mac address */
+	if ((dev->flags & IFF_ALLMULTI) || dev->mc_count > 3)
+		val |= ENET_RXCFG_ALLMCAST_MASK;
+	else
+		val &= ~ENET_RXCFG_ALLMCAST_MASK;
+
+	/* no need to set perfect match registers if we catch all
+	 * multicast */
+	if (val & ENET_RXCFG_ALLMCAST_MASK) {
+		enet_writel(priv, val, ENET_RXCFG_REG);
+		return;
+	}
+
+	for (i = 0, mc_list = dev->mc_list;
+	     (mc_list != NULL) && (i < dev->mc_count) && (i < 3);
+	     i++, mc_list = mc_list->next) {
+		u8 *dmi_addr;
+		u32 tmp;
+
+		/* filter non ethernet address */
+		if (mc_list->dmi_addrlen != 6)
+			continue;
+
+		/* update perfect match registers */
+		dmi_addr = mc_list->dmi_addr;
+		tmp = (dmi_addr[2] << 24) | (dmi_addr[3] << 16) |
+			(dmi_addr[4] << 8) | dmi_addr[5];
+		enet_writel(priv, tmp, ENET_PML_REG(i + 1));
+
+		tmp = (dmi_addr[0] << 8 | dmi_addr[1]);
+		tmp |= ENET_PMH_DATAVALID_MASK;
+		enet_writel(priv, tmp, ENET_PMH_REG(i + 1));
+	}
+
+	for (; i < 3; i++) {
+		enet_writel(priv, 0, ENET_PML_REG(i + 1));
+		enet_writel(priv, 0, ENET_PMH_REG(i + 1));
+	}
+
+	enet_writel(priv, val, ENET_RXCFG_REG);
+}
+
+/*
+ * set mac duplex parameters
+ */
+static void bcm_enet_set_duplex(struct bcm_enet_priv *priv, int fullduplex)
+{
+	u32 val;
+
+	val = enet_readl(priv, ENET_TXCTL_REG);
+	if (fullduplex)
+		val |= ENET_TXCTL_FD_MASK;
+	else
+		val &= ~ENET_TXCTL_FD_MASK;
+	enet_writel(priv, val, ENET_TXCTL_REG);
+}
+
+/*
+ * set mac flow control parameters
+ */
+static void bcm_enet_set_flow(struct bcm_enet_priv *priv, int rx_en, int tx_en)
+{
+	u32 val;
+
+	/* rx flow control (pause frame handling) */
+	val = enet_readl(priv, ENET_RXCFG_REG);
+	if (rx_en)
+		val |= ENET_RXCFG_ENFLOW_MASK;
+	else
+		val &= ~ENET_RXCFG_ENFLOW_MASK;
+	enet_writel(priv, val, ENET_RXCFG_REG);
+
+	/* tx flow control (pause frame generation) */
+	val = enet_dma_readl(priv, ENETDMA_CFG_REG);
+	if (tx_en)
+		val |= ENETDMA_CFG_FLOWCH_MASK(priv->rx_chan);
+	else
+		val &= ~ENETDMA_CFG_FLOWCH_MASK(priv->rx_chan);
+	enet_dma_writel(priv, val, ENETDMA_CFG_REG);
+}
+
+/*
+ * link changed callback (from phylib)
+ */
+static void bcm_enet_adjust_phy_link(struct net_device *dev)
+{
+	struct bcm_enet_priv *priv;
+	struct phy_device *phydev;
+	int status_changed;
+
+	priv = netdev_priv(dev);
+	phydev = priv->phydev;
+	status_changed = 0;
+
+	if (priv->old_link != phydev->link) {
+		status_changed = 1;
+		priv->old_link = phydev->link;
+		if (phydev->link)
+			netif_schedule(dev);
+	}
+
+	/* reflect duplex change in mac configuration */
+	if (phydev->link && phydev->duplex != priv->old_duplex) {
+		bcm_enet_set_duplex(priv,
+				    (phydev->duplex == DUPLEX_FULL) ? 1 : 0);
+		status_changed = 1;
+		priv->old_duplex = phydev->duplex;
+	}
+
+	/* enable flow control if remote advertise it (trust phylib to
+	 * check that duplex is full */
+	if (phydev->link && phydev->pause != priv->old_pause) {
+		int rx_pause_en, tx_pause_en;
+
+		if (phydev->pause) {
+			/* pause was advertised by lpa and us */
+			rx_pause_en = 1;
+			tx_pause_en = 1;
+		} else if (!priv->pause_auto) {
+			/* pause setting overrided by user */
+			rx_pause_en = priv->pause_rx;
+			tx_pause_en = priv->pause_tx;
+		} else {
+			rx_pause_en = 0;
+			tx_pause_en = 0;
+		}
+
+		bcm_enet_set_flow(priv, rx_pause_en, tx_pause_en);
+		status_changed = 1;
+		priv->old_pause = phydev->pause;
+	}
+
+	if (status_changed) {
+		pr_info("%s: link %s", dev->name, phydev->link ?
+			"UP" : "DOWN");
+		if (phydev->link)
+			printk(" - %d/%s - flow control %s", phydev->speed,
+			       DUPLEX_FULL == phydev->duplex ? "full" : "half",
+			       phydev->pause == 1 ? "rx&tx" : "off");
+
+		printk("\n");
+	}
+}
+
+/*
+ * link changed callback (if phylib is not used)
+ */
+static void bcm_enet_adjust_link(struct net_device *dev)
+{
+	struct bcm_enet_priv *priv;
+
+	priv = netdev_priv(dev);
+	bcm_enet_set_duplex(priv, priv->force_duplex_full);
+	bcm_enet_set_flow(priv, priv->pause_rx, priv->pause_tx);
+	netif_carrier_on(dev);
+
+	pr_info("%s: link forced UP - %d/%s - flow control %s/%s\n",
+		dev->name,
+		priv->force_speed_100 ? 100 : 10,
+		priv->force_duplex_full ? "full" : "half",
+		priv->pause_rx ? "rx" : "off",
+		priv->pause_tx ? "tx" : "off");
+}
+
+/*
+ * open callback, allocate dma rings & buffers and start rx operation
+ */
+static int bcm_enet_open(struct net_device *dev)
+{
+	struct bcm_enet_priv *priv;
+	struct sockaddr addr;
+	struct device *kdev;
+	struct phy_device *phydev;
+	int irq_requested, i, ret;
+	unsigned int size;
+	char phy_id[BUS_ID_SIZE];
+	void *p;
+	u32 val;
+
+	priv = netdev_priv(dev);
+	kdev = &priv->pdev->dev;
+
+	if (priv->has_phy) {
+		/* connect to PHY */
+		snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT,
+			 priv->mac_id, priv->phy_id);
+
+		phydev = phy_connect(dev, phy_id, &bcm_enet_adjust_phy_link, 0,
+				     PHY_INTERFACE_MODE_MII);
+
+		if (IS_ERR(phydev)) {
+			dev_err(kdev, "could not attach to PHY\n");
+			return PTR_ERR(phydev);
+		}
+
+		/* mask with MAC supported features */
+		phydev->supported &= (SUPPORTED_10baseT_Half |
+				      SUPPORTED_10baseT_Full |
+				      SUPPORTED_100baseT_Half |
+				      SUPPORTED_100baseT_Full |
+				      SUPPORTED_Autoneg |
+				      SUPPORTED_Pause |
+				      SUPPORTED_MII);
+		phydev->advertising = phydev->supported;
+
+		if (priv->pause_auto && priv->pause_rx && priv->pause_tx)
+			phydev->advertising |= SUPPORTED_Pause;
+		else
+			phydev->advertising &= ~SUPPORTED_Pause;
+
+		dev_info(kdev, "attached PHY at address %d [%s]\n",
+			 phydev->addr, phydev->drv->name);
+
+		priv->old_link = 0;
+		priv->old_duplex = -1;
+		priv->old_pause = -1;
+		priv->phydev = phydev;
+	}
+
+	/* mask all interrupts and request them */
+	enet_writel(priv, 0, ENET_IRMASK_REG);
+	enet_dma_writel(priv, 0, ENETDMA_IRMASK_REG(priv->rx_chan));
+	enet_dma_writel(priv, 0, ENETDMA_IRMASK_REG(priv->tx_chan));
+
+	irq_requested = 0;
+	ret = request_irq(dev->irq, bcm_enet_isr_mac, 0, dev->name, dev);
+	if (ret)
+		goto out;
+	irq_requested++;
+
+	ret = request_irq(priv->irq_rx, bcm_enet_isr_dma,
+			  IRQF_SAMPLE_RANDOM | IRQF_DISABLED, dev->name, dev);
+	if (ret)
+		goto out;
+	irq_requested++;
+
+	ret = request_irq(priv->irq_tx, bcm_enet_isr_dma,
+			  IRQF_DISABLED, dev->name, dev);
+	if (ret)
+		goto out;
+	irq_requested++;
+
+	/* initialize perfect match registers */
+	for (i = 0; i < 4; i++) {
+		enet_writel(priv, 0, ENET_PML_REG(i));
+		enet_writel(priv, 0, ENET_PMH_REG(i));
+	}
+
+	/* write device mac address */
+	memcpy(addr.sa_data, dev->dev_addr, ETH_ALEN);
+	bcm_enet_set_mac_address(dev, &addr);
+
+	/* allocate rx dma ring */
+	size = priv->rx_ring_size * sizeof(struct bcm_enet_desc);
+	p = dma_alloc_coherent(kdev, size, &priv->rx_desc_dma, GFP_KERNEL);
+	if (!p) {
+		dev_err(kdev, "cannot allocate rx ring %u\n", size);
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	memset(p, 0, size);
+	priv->rx_desc_alloc_size = size;
+	priv->rx_desc_cpu = p;
+
+	/* allocate tx dma ring */
+	size = priv->tx_ring_size * sizeof(struct bcm_enet_desc);
+	p = dma_alloc_coherent(kdev, size, &priv->tx_desc_dma, GFP_KERNEL);
+	if (!p) {
+		dev_err(kdev, "cannot allocate tx ring\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	memset(p, 0, size);
+	priv->tx_desc_alloc_size = size;
+	priv->tx_desc_cpu = p;
+
+	priv->tx_skb = kzalloc(sizeof(struct sk_buff *) * priv->tx_ring_size,
+			       GFP_KERNEL);
+	if (!priv->tx_skb) {
+		dev_err(kdev, "cannot allocate rx skb queue\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	priv->tx_desc_count = priv->tx_ring_size;
+	priv->tx_dirty_desc = 0;
+	priv->tx_curr_desc = 0;
+	spin_lock_init(&priv->tx_lock);
+
+	/* init & fill rx ring with skbs */
+	priv->rx_skb = kzalloc(sizeof(struct sk_buff *) * priv->rx_ring_size,
+			       GFP_KERNEL);
+	if (!priv->rx_skb) {
+		dev_err(kdev, "cannot allocate rx skb queue\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	priv->rx_desc_count = 0;
+	priv->rx_dirty_desc = 0;
+	priv->rx_curr_desc = 0;
+
+	/* initialize flow control buffer allocation */
+	enet_dma_writel(priv, ENETDMA_BUFALLOC_FORCE_MASK | 0,
+			ENETDMA_BUFALLOC_REG(priv->rx_chan));
+
+	if (bcm_enet_refill_rx(dev)) {
+		dev_err(kdev, "cannot allocate rx skb queue\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	if (priv->use_marvell_header) {
+		val = enet_readl(priv, ENET_RXCFG_REG);
+		val |= ENET_RXCFG_PROMISC_MASK;
+		enet_writel(priv, val, ENET_RXCFG_REG);
+	}
+
+	/* write rx & tx ring addresses */
+	enet_dma_writel(priv, priv->rx_desc_dma,
+			ENETDMA_RSTART_REG(priv->rx_chan));
+	enet_dma_writel(priv, priv->tx_desc_dma,
+			ENETDMA_RSTART_REG(priv->tx_chan));
+
+	/* clear remaining state ram for rx & tx channel */
+	enet_dma_writel(priv, 0, ENETDMA_SRAM2_REG(priv->rx_chan));
+	enet_dma_writel(priv, 0, ENETDMA_SRAM2_REG(priv->tx_chan));
+	enet_dma_writel(priv, 0, ENETDMA_SRAM3_REG(priv->rx_chan));
+	enet_dma_writel(priv, 0, ENETDMA_SRAM3_REG(priv->tx_chan));
+	enet_dma_writel(priv, 0, ENETDMA_SRAM4_REG(priv->rx_chan));
+	enet_dma_writel(priv, 0, ENETDMA_SRAM4_REG(priv->tx_chan));
+
+	/* set max rx/tx length */
+	size = priv->use_marvell_header ? 2 : 0;
+	enet_writel(priv, BCMENET_MAX_RX_SIZE + size, ENET_RXMAXLEN_REG);
+	enet_writel(priv, BCMENET_MAX_TX_SIZE + size, ENET_TXMAXLEN_REG);
+
+	/* set dma maximum burst len */
+	enet_dma_writel(priv, BCMENET_DMA_MAXBURST,
+			ENETDMA_MAXBURST_REG(priv->rx_chan));
+	enet_dma_writel(priv, BCMENET_DMA_MAXBURST,
+			ENETDMA_MAXBURST_REG(priv->tx_chan));
+
+	/* set correct transmit fifo watermark */
+	enet_writel(priv, BCMENET_TX_FIFO_TRESH, ENET_TXWMARK_REG);
+
+	/* set flow control low/high threshold to 1/3 / 2/3 */
+	val = priv->rx_ring_size / 3;
+	enet_dma_writel(priv, val, ENETDMA_FLOWCL_REG(priv->rx_chan));
+	val = (priv->rx_ring_size * 2) / 3;
+	enet_dma_writel(priv, val, ENETDMA_FLOWCH_REG(priv->rx_chan));
+
+	/* all set, enable mac and interrupts, start dma engine and
+	 * kick rx dma channel */
+	wmb();
+	enet_writel(priv, ENET_CTL_ENABLE_MASK, ENET_CTL_REG);
+	enet_dma_writel(priv, ENETDMA_CFG_EN_MASK, ENETDMA_CFG_REG);
+	enet_dma_writel(priv, ENETDMA_CHANCFG_EN_MASK,
+			ENETDMA_CHANCFG_REG(priv->rx_chan));
+
+	/* watch "mib counters about to overflow" interrupt */
+	enet_writel(priv, ENET_IR_MIB, ENET_IRMASK_REG);
+	enet_writel(priv, ENET_IR_MIB, ENET_IR_REG);
+
+	/* watch "packet transferred" interrupt in rx and tx */
+	enet_dma_writel(priv, ENETDMA_IR_PKTDONE_MASK,
+			ENETDMA_IRMASK_REG(priv->rx_chan));
+	enet_dma_writel(priv, ENETDMA_IR_PKTDONE_MASK,
+			ENETDMA_IRMASK_REG(priv->tx_chan));
+	enet_dma_writel(priv, ENETDMA_IR_PKTDONE_MASK,
+			ENETDMA_IR_REG(priv->rx_chan));
+	enet_dma_writel(priv, ENETDMA_IR_PKTDONE_MASK,
+			ENETDMA_IR_REG(priv->tx_chan));
+
+
+	if (priv->has_phy)
+		phy_start(priv->phydev);
+	else
+		bcm_enet_adjust_link(dev);
+
+	netif_start_queue(dev);
+	return 0;
+
+out:
+	if (irq_requested > 2)
+		free_irq(priv->irq_tx, dev);
+	if (irq_requested > 1)
+		free_irq(priv->irq_rx, dev);
+	if (irq_requested > 0)
+		free_irq(dev->irq, dev);
+	for (i = 0; i < priv->rx_ring_size; i++) {
+		struct bcm_enet_desc *desc;
+
+		if (!priv->rx_skb[i])
+			continue;
+
+		desc = &priv->rx_desc_cpu[i];
+		dma_unmap_single(kdev, desc->address, BCMENET_RX_SKB_SIZE,
+				 DMA_FROM_DEVICE);
+		kfree_skb(priv->rx_skb[i]);
+	}
+	if (priv->rx_desc_cpu)
+		dma_free_coherent(kdev, priv->rx_desc_alloc_size,
+				  priv->rx_desc_cpu, priv->rx_desc_dma);
+	if (priv->tx_desc_cpu)
+		dma_free_coherent(kdev, priv->tx_desc_alloc_size,
+				  priv->tx_desc_cpu, priv->tx_desc_dma);
+	if (priv->rx_skb)
+		kfree(priv->rx_skb);
+	if (priv->tx_skb)
+		kfree(priv->tx_skb);
+	return ret;
+}
+
+/*
+ * disable mac
+ */
+static void bcm_enet_disable_mac(struct bcm_enet_priv *priv)
+{
+	int limit;
+	u32 val;
+
+	val = enet_readl(priv, ENET_CTL_REG);
+	val |= ENET_CTL_DISABLE_MASK;
+	enet_writel(priv, val, ENET_CTL_REG);
+
+	limit = 1000;
+	do {
+		u32 val;
+
+		val = enet_readl(priv, ENET_CTL_REG);
+		if (!(val & ENET_CTL_DISABLE_MASK))
+			break;
+		udelay(1);
+	} while (limit--);
+}
+
+/*
+ * disable dma in given channel
+ */
+static void bcm_enet_disable_dma(struct bcm_enet_priv *priv, int chan)
+{
+	int limit;
+
+	enet_dma_writel(priv, 0, ENETDMA_CHANCFG_REG(chan));
+
+	limit = 1000;
+	do {
+		u32 val;
+
+		val = enet_dma_readl(priv, ENETDMA_CHANCFG_REG(chan));
+		if (!(val & ENETDMA_CHANCFG_EN_MASK))
+			break;
+		udelay(1);
+	} while (limit--);
+}
+
+/*
+ * stop callback
+ */
+static int bcm_enet_stop(struct net_device *dev)
+{
+	struct bcm_enet_priv *priv;
+	struct device *kdev;
+	int i;
+
+	priv = netdev_priv(dev);
+	kdev = &priv->pdev->dev;
+
+	netif_stop_queue(dev);
+	if (priv->has_phy)
+		phy_stop(priv->phydev);
+	del_timer_sync(&priv->rx_timeout);
+
+	/* mask all interrupts */
+	enet_writel(priv, 0, ENET_IRMASK_REG);
+	enet_dma_writel(priv, 0, ENETDMA_IRMASK_REG(priv->rx_chan));
+	enet_dma_writel(priv, 0, ENETDMA_IRMASK_REG(priv->tx_chan));
+
+	/* disable dma & mac */
+	bcm_enet_disable_dma(priv, priv->tx_chan);
+	bcm_enet_disable_dma(priv, priv->rx_chan);
+	bcm_enet_disable_mac(priv);
+
+	/* force reclaim of all tx buffers */
+	bcm_enet_tx_reclaim(dev, 1);
+
+	/* free the rx skb ring */
+	for (i = 0; i < priv->rx_ring_size; i++) {
+		struct bcm_enet_desc *desc;
+
+		if (!priv->rx_skb[i])
+			continue;
+
+		desc = &priv->rx_desc_cpu[i];
+		dma_unmap_single(kdev, desc->address, BCMENET_RX_SKB_SIZE,
+				 DMA_FROM_DEVICE);
+		kfree_skb(priv->rx_skb[i]);
+	}
+
+	/* free remaining allocated memory */
+	kfree(priv->rx_skb);
+	kfree(priv->tx_skb);
+	dma_free_coherent(kdev, priv->rx_desc_alloc_size,
+			  priv->rx_desc_cpu, priv->rx_desc_dma);
+	dma_free_coherent(kdev, priv->tx_desc_alloc_size,
+			  priv->tx_desc_cpu, priv->tx_desc_dma);
+	free_irq(priv->irq_tx, dev);
+	free_irq(priv->irq_rx, dev);
+	free_irq(dev->irq, dev);
+
+	/* release phy */
+	if (priv->has_phy) {
+		phy_disconnect(priv->phydev);
+		priv->phydev = NULL;
+	}
+
+	return 0;
+}
+
+/*
+ * core request to return device rx/tx stats
+ */
+static struct net_device_stats *bcm_enet_get_stats(struct net_device *dev)
+{
+	struct bcm_enet_priv *priv;
+
+	priv = netdev_priv(dev);
+	return &priv->stats;
+}
+
+/*
+ * ethtool callbacks
+ */
+struct bcm_enet_stats {
+	char stat_string[ETH_GSTRING_LEN];
+	int sizeof_stat;
+	int stat_offset;
+	int mib_reg;
+};
+
+#define GEN_STAT(m) sizeof(((struct bcm_enet_priv *)0)->m), \
+				offsetof(struct bcm_enet_priv, m)
+
+static const struct bcm_enet_stats bcm_enet_gstrings_stats[] = {
+	{ "rx_packets", GEN_STAT(stats.rx_packets), -1 },
+	{ "tx_packets",	GEN_STAT(stats.tx_packets), -1 },
+	{ "rx_bytes", GEN_STAT(stats.rx_bytes), -1 },
+	{ "tx_bytes", GEN_STAT(stats.tx_bytes), -1 },
+	{ "rx_errors", GEN_STAT(stats.rx_errors), -1 },
+	{ "tx_errors", GEN_STAT(stats.tx_errors), -1 },
+	{ "rx_dropped",	GEN_STAT(stats.rx_dropped), -1 },
+	{ "tx_dropped",	GEN_STAT(stats.tx_dropped), -1 },
+
+	{ "rx_good_octets", GEN_STAT(mib.rx_gd_octets), ETH_MIB_RX_GD_OCTETS},
+	{ "rx_good_pkts", GEN_STAT(mib.rx_gd_pkts), ETH_MIB_RX_GD_PKTS },
+	{ "rx_broadcast", GEN_STAT(mib.rx_brdcast), ETH_MIB_RX_BRDCAST },
+	{ "rx_multicast", GEN_STAT(mib.rx_mult), ETH_MIB_RX_MULT },
+	{ "rx_64_octets", GEN_STAT(mib.rx_64), ETH_MIB_RX_64 },
+	{ "rx_65_127_oct", GEN_STAT(mib.rx_65_127), ETH_MIB_RX_65_127 },
+	{ "rx_128_255_oct", GEN_STAT(mib.rx_128_255), ETH_MIB_RX_128_255 },
+	{ "rx_256_511_oct", GEN_STAT(mib.rx_256_511), ETH_MIB_RX_256_511 },
+	{ "rx_512_1023_oct", GEN_STAT(mib.rx_512_1023), ETH_MIB_RX_512_1023 },
+	{ "rx_1024_max_oct", GEN_STAT(mib.rx_1024_max), ETH_MIB_RX_1024_MAX },
+	{ "rx_jabber", GEN_STAT(mib.rx_jab), ETH_MIB_RX_JAB },
+	{ "rx_oversize", GEN_STAT(mib.rx_ovr), ETH_MIB_RX_OVR },
+	{ "rx_fragment", GEN_STAT(mib.rx_frag), ETH_MIB_RX_FRAG },
+	{ "rx_dropped",	GEN_STAT(mib.rx_drop), ETH_MIB_RX_DROP },
+	{ "rx_crc_align", GEN_STAT(mib.rx_crc_align), ETH_MIB_RX_CRC_ALIGN },
+	{ "rx_undersize", GEN_STAT(mib.rx_und), ETH_MIB_RX_UND },
+	{ "rx_crc", GEN_STAT(mib.rx_crc), ETH_MIB_RX_CRC },
+	{ "rx_align", GEN_STAT(mib.rx_align), ETH_MIB_RX_ALIGN },
+	{ "rx_symbol_error", GEN_STAT(mib.rx_sym), ETH_MIB_RX_SYM },
+	{ "rx_pause", GEN_STAT(mib.rx_pause), ETH_MIB_RX_PAUSE },
+	{ "rx_control", GEN_STAT(mib.rx_cntrl), ETH_MIB_RX_CNTRL },
+
+	{ "tx_good_octets", GEN_STAT(mib.tx_gd_octets), ETH_MIB_TX_GD_OCTETS },
+	{ "tx_good_pkts", GEN_STAT(mib.tx_gd_pkts), ETH_MIB_TX_GD_PKTS },
+	{ "tx_broadcast", GEN_STAT(mib.tx_brdcast), ETH_MIB_TX_BRDCAST },
+	{ "tx_multicast", GEN_STAT(mib.tx_mult), ETH_MIB_TX_MULT },
+	{ "tx_64_oct", GEN_STAT(mib.tx_64), ETH_MIB_TX_64 },
+	{ "tx_65_127_oct", GEN_STAT(mib.tx_65_127), ETH_MIB_TX_65_127 },
+	{ "tx_128_255_oct", GEN_STAT(mib.tx_128_255), ETH_MIB_TX_128_255 },
+	{ "tx_256_511_oct", GEN_STAT(mib.tx_256_511), ETH_MIB_TX_256_511 },
+	{ "tx_512_1023_oct", GEN_STAT(mib.tx_512_1023), ETH_MIB_TX_512_1023},
+	{ "tx_1024_max_oct", GEN_STAT(mib.tx_1024_max), ETH_MIB_TX_1024_MAX },
+	{ "tx_jabber", GEN_STAT(mib.tx_jab), ETH_MIB_TX_JAB },
+	{ "tx_oversize", GEN_STAT(mib.tx_ovr), ETH_MIB_TX_OVR },
+	{ "tx_fragment", GEN_STAT(mib.tx_frag), ETH_MIB_TX_FRAG },
+	{ "tx_underrun", GEN_STAT(mib.tx_underrun), ETH_MIB_TX_UNDERRUN },
+	{ "tx_collisions", GEN_STAT(mib.tx_col), ETH_MIB_TX_COL },
+	{ "tx_single_collision", GEN_STAT(mib.tx_1_col), ETH_MIB_TX_1_COL },
+	{ "tx_multiple_collision", GEN_STAT(mib.tx_m_col), ETH_MIB_TX_M_COL },
+	{ "tx_excess_collision", GEN_STAT(mib.tx_ex_col), ETH_MIB_TX_EX_COL },
+	{ "tx_late_collision", GEN_STAT(mib.tx_late), ETH_MIB_TX_LATE },
+	{ "tx_deferred", GEN_STAT(mib.tx_def), ETH_MIB_TX_DEF },
+	{ "tx_carrier_sense", GEN_STAT(mib.tx_crs), ETH_MIB_TX_CRS },
+	{ "tx_pause", GEN_STAT(mib.tx_pause), ETH_MIB_TX_PAUSE },
+
+};
+
+#define BCM_ENET_STATS_LEN	\
+	sizeof(bcm_enet_gstrings_stats) / sizeof(struct bcm_enet_stats)
+
+static const u32 unused_mib_regs[] = {
+	ETH_MIB_TX_ALL_OCTETS,
+	ETH_MIB_TX_ALL_PKTS,
+	ETH_MIB_RX_ALL_OCTETS,
+	ETH_MIB_RX_ALL_PKTS,
+};
+
+static void bcm_enet_get_drvinfo(struct net_device *netdev,
+				 struct ethtool_drvinfo *drvinfo)
+{
+	strncpy(drvinfo->driver, bcm_enet_driver_name, 32);
+	strncpy(drvinfo->version, bcm_enet_driver_version, 32);
+	strncpy(drvinfo->fw_version, "N/A", 32);
+	strncpy(drvinfo->bus_info, "bcm963xx", 32);
+	drvinfo->n_stats = BCM_ENET_STATS_LEN;
+}
+
+static int bcm_enet_get_stats_count(struct net_device *netdev)
+{
+	return BCM_ENET_STATS_LEN;
+}
+
+static void bcm_enet_get_strings(struct net_device *netdev,
+				 u32 stringset, u8 *data)
+{
+	int i;
+
+	switch (stringset) {
+	case ETH_SS_STATS:
+		for (i=0; i < BCM_ENET_STATS_LEN; i++) {
+			memcpy(data + i * ETH_GSTRING_LEN,
+			       bcm_enet_gstrings_stats[i].stat_string,
+			       ETH_GSTRING_LEN);
+		}
+		break;
+	}
+}
+
+static void bcm_enet_update_mib_counters(struct work_struct *t)
+{
+	struct bcm_enet_priv *priv;
+	int i;
+
+
+	priv = container_of(t, struct bcm_enet_priv, mib_update_task);
+
+	mutex_lock(&priv->mib_update_lock);
+	for (i = 0; i < BCM_ENET_STATS_LEN; i++) {
+		const struct bcm_enet_stats *s;
+		uint32_t val;
+		char *p;
+
+		s = &bcm_enet_gstrings_stats[i];
+		if (s->mib_reg == -1)
+			continue;
+
+		val = enet_readl(priv, ENET_MIB_REG(s->mib_reg));
+		p = (char *)priv + s->stat_offset;
+
+		if (s->sizeof_stat == sizeof(u64))
+			*(u64 *)p += val;
+		else
+			*(u32 *)p += val;
+	}
+
+	/* also empty unused mib counters to make sure mib counter
+	 * overflow interrupt is cleared */
+	for (i = 0; i < ARRAY_SIZE(unused_mib_regs); i++)
+		(void)enet_readl(priv, ENET_MIB_REG(unused_mib_regs[i]));
+
+	mutex_unlock(&priv->mib_update_lock);
+}
+
+static void bcm_enet_get_ethtool_stats(struct net_device *netdev,
+				       struct ethtool_stats *stats,
+				       u64 *data)
+{
+	struct bcm_enet_priv *priv;
+	int i;
+
+	priv = netdev->priv;
+	bcm_enet_update_mib_counters(&priv->mib_update_task);
+
+	mutex_lock(&priv->mib_update_lock);
+	for (i = 0; i < BCM_ENET_STATS_LEN; i++) {
+		const struct bcm_enet_stats *s;
+		char *p;
+
+		s = &bcm_enet_gstrings_stats[i];
+		p = (char *)priv + s->stat_offset;
+		data[i] = (s->sizeof_stat == sizeof(u64)) ?
+			*(u64 *)p : *(u32 *)p;
+	}
+	mutex_unlock(&priv->mib_update_lock);
+}
+
+static int bcm_enet_get_settings(struct net_device *dev,
+				 struct ethtool_cmd *cmd)
+{
+	struct bcm_enet_priv *priv;
+
+	priv = netdev_priv(dev);
+
+	cmd->maxrxpkt = 0;
+	cmd->maxtxpkt = 0;
+
+	if (priv->has_phy) {
+		if (!priv->phydev)
+			return -ENODEV;
+		return phy_ethtool_gset(priv->phydev, cmd);
+	} else {
+		cmd->autoneg = 0;
+		cmd->speed = (priv->force_speed_100) ? SPEED_100 : SPEED_10;
+		cmd->duplex = (priv->force_duplex_full) ?
+			DUPLEX_FULL : DUPLEX_HALF;
+		cmd->supported = ADVERTISED_10baseT_Half  |
+			ADVERTISED_10baseT_Full |
+			ADVERTISED_100baseT_Half |
+			ADVERTISED_100baseT_Full;
+		cmd->advertising = 0;
+		cmd->port = PORT_MII;
+		cmd->transceiver = XCVR_EXTERNAL;
+	}
+	return 0;
+}
+
+static int bcm_enet_set_settings(struct net_device *dev,
+				 struct ethtool_cmd *cmd)
+{
+	struct bcm_enet_priv *priv;
+
+	priv = netdev_priv(dev);
+	if (priv->has_phy) {
+		if (!priv->phydev)
+			return -ENODEV;
+		return phy_ethtool_sset(priv->phydev, cmd);
+	} else {
+
+		if (cmd->autoneg ||
+		    (cmd->speed != SPEED_100 && cmd->speed != SPEED_10) ||
+		    cmd->port != PORT_MII)
+			return -EINVAL;
+
+		priv->force_speed_100 = (cmd->speed == SPEED_100) ? 1 : 0;
+		priv->force_duplex_full = (cmd->duplex == DUPLEX_FULL) ? 1 : 0;
+
+		if (netif_running(dev))
+			bcm_enet_adjust_link(dev);
+		return 0;
+	}
+}
+
+static void bcm_enet_get_ringparam(struct net_device *dev,
+				   struct ethtool_ringparam *ering)
+{
+	struct bcm_enet_priv *priv;
+
+	priv = netdev_priv(dev);
+
+	/* rx/tx ring is actually only limited by memory */
+	ering->rx_max_pending = 8192;
+	ering->tx_max_pending = 8192;
+	ering->rx_mini_max_pending = 0;
+	ering->rx_jumbo_max_pending = 0;
+	ering->rx_pending = priv->rx_ring_size;
+	ering->tx_pending = priv->tx_ring_size;
+}
+
+static int bcm_enet_set_ringparam(struct net_device *dev,
+				  struct ethtool_ringparam *ering)
+{
+	struct bcm_enet_priv *priv;
+	int was_running;
+
+	priv = netdev_priv(dev);
+
+	was_running = 0;
+	if (netif_running(dev)) {
+		bcm_enet_stop(dev);
+		was_running = 1;
+	}
+
+	priv->rx_ring_size = ering->rx_pending;
+	priv->tx_ring_size = ering->tx_pending;
+
+	if (was_running) {
+		int err;
+
+		err = bcm_enet_open(dev);
+		if (err)
+			dev_close(dev);
+		else
+			bcm_enet_set_multicast_list(dev);
+	}
+	return 0;
+}
+
+static void bcm_enet_get_pauseparam(struct net_device *dev,
+				    struct ethtool_pauseparam *ecmd)
+{
+	struct bcm_enet_priv *priv;
+
+	priv = netdev_priv(dev);
+	ecmd->autoneg = priv->pause_auto;
+	ecmd->rx_pause = priv->pause_rx;
+	ecmd->tx_pause = priv->pause_tx;
+}
+
+static int bcm_enet_set_pauseparam(struct net_device *dev,
+				   struct ethtool_pauseparam *ecmd)
+{
+	struct bcm_enet_priv *priv;
+
+	priv = netdev_priv(dev);
+
+	if (priv->has_phy) {
+		if (ecmd->autoneg && (ecmd->rx_pause != ecmd->tx_pause)) {
+			/* asymetric pause mode not supported,
+			 * actually possible but integrated PHY has RO
+			 * asym_pause bit */
+			return -EINVAL;
+		}
+	} else {
+		/* no pause autoneg on direct mii connection */
+		if (ecmd->autoneg)
+			return -EINVAL;
+	}
+
+	priv->pause_auto = ecmd->autoneg;
+	priv->pause_rx = ecmd->rx_pause;
+	priv->pause_tx = ecmd->tx_pause;
+
+	return 0;
+}
+
+static struct ethtool_ops bcm_enet_ethtool_ops = {
+	.get_strings		= bcm_enet_get_strings,
+	.get_stats_count	= bcm_enet_get_stats_count,
+	.get_ethtool_stats      = bcm_enet_get_ethtool_stats,
+	.get_settings		= bcm_enet_get_settings,
+	.set_settings		= bcm_enet_set_settings,
+	.get_drvinfo		= bcm_enet_get_drvinfo,
+	.get_link		= ethtool_op_get_link,
+	.get_ringparam		= bcm_enet_get_ringparam,
+	.set_ringparam		= bcm_enet_set_ringparam,
+	.get_pauseparam		= bcm_enet_get_pauseparam,
+	.set_pauseparam		= bcm_enet_set_pauseparam,
+};
+
+static int bcm_enet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	struct bcm_enet_priv *priv;
+
+	priv = netdev_priv(dev);
+	if (priv->has_phy) {
+		if (!priv->phydev)
+			return -ENODEV;
+		return phy_mii_ioctl(priv->phydev, if_mii(rq), cmd);
+	} else {
+		struct mii_if_info mii;
+
+		mii.dev = dev;
+		mii.mdio_read = bcm_enet_mdio_read_mii;
+		mii.mdio_write = bcm_enet_mdio_write_mii;
+		mii.phy_id = 0;
+		mii.phy_id_mask = 0x3f;
+		mii.reg_num_mask = 0x1f;
+		return generic_mii_ioctl(&mii, if_mii(rq), cmd, NULL);
+	}
+}
+
+/*
+ * preinit hardware to allow mii operation while device is down
+ */
+static void bcm_enet_hw_preinit(struct bcm_enet_priv *priv)
+{
+	u32 val;
+	int limit;
+
+	/* make sure mac is disabled */
+	bcm_enet_disable_mac(priv);
+
+	/* soft reset mac */
+	val = ENET_CTL_SRESET_MASK;
+	enet_writel(priv, val, ENET_CTL_REG);
+	wmb();
+
+	limit = 1000;
+	do {
+		val = enet_readl(priv, ENET_CTL_REG);
+		if (!(val & ENET_CTL_SRESET_MASK))
+			break;
+		udelay(1);
+	} while (limit--);
+
+	/* select correct mii interface */
+	val = enet_readl(priv, ENET_CTL_REG);
+	if (priv->use_external_mii) {
+		val |= ENET_CTL_EPHYSEL_MASK;
+	} else
+		val &= ~ENET_CTL_EPHYSEL_MASK;
+	enet_writel(priv, val, ENET_CTL_REG);
+
+	/* turn on mdc clock */
+	enet_writel(priv, (0x1f << ENET_MIISC_MDCFREQDIV_SHIFT) |
+		    ENET_MIISC_PREAMBLEEN_MASK, ENET_MIISC_REG);
+
+	/* set mib counters to self-clear when read */
+	enet_writel(priv, ENET_MIBCTL_RDCLEAR_MASK, ENET_MIBCTL_REG);
+}
+
+/*
+ * allocate netdevice, request register memory and register device.
+ */
+static int __devinit bcm_enet_probe(struct platform_device *pdev)
+{
+	struct bcm_enet_priv *priv;
+	struct net_device *dev;
+	struct bcm963xx_enet_platform_data *pd;
+	struct resource *res_mem, *res_irq, *res_irq_rx, *res_irq_tx;
+	struct mii_bus *bus;
+	unsigned int iomem_size;
+	int i, ret, mdio_registered, mem_requested;
+
+	/* stop if shared driver failed, assume driver->probe will be
+	 * called in the same order we register devices (correct ?) */
+	if (!bcm_enet_shared_base)
+		return -ENODEV;
+
+	mdio_registered = mem_requested = 0;
+
+	res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	res_irq_rx = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
+	res_irq_tx = platform_get_resource(pdev, IORESOURCE_IRQ, 2);
+	if (!res_mem || !res_irq || !res_irq_rx || !res_irq_tx)
+		return -ENODEV;
+
+	ret = 0;
+	dev = alloc_etherdev(sizeof(*priv));
+	if (!dev)
+		return -ENOMEM;
+	priv = netdev_priv(dev);
+	memset(priv, 0, sizeof(*priv));
+
+	iomem_size = res_mem->end - res_mem->start + 1;
+	if (!request_mem_region(res_mem->start, iomem_size, "bcm963xx_enet")) {
+		ret = -EBUSY;
+		goto err;
+	}
+	mem_requested = 1;
+
+	priv->base = ioremap(res_mem->start, iomem_size);
+	if (priv->base == NULL) {
+		ret = -ENOMEM;
+		goto err;
+	}
+	dev->irq = priv->irq = res_irq->start;
+	priv->irq_rx = res_irq_rx->start;
+	priv->irq_tx = res_irq_tx->start;
+	priv->mac_id = pdev->id;
+
+	/* get rx & tx dma channel id for this mac */
+	if (priv->mac_id == 0) {
+		priv->rx_chan = 0;
+		priv->tx_chan = 1;
+	} else {
+		priv->rx_chan = 2;
+		priv->tx_chan = 3;
+	}
+
+	/* initialize default and fetch platform data */
+	priv->rx_ring_size = BCMENET_DEF_RX_DESC;
+	priv->tx_ring_size = BCMENET_DEF_TX_DESC;
+
+	pd = pdev->dev.platform_data;
+	if (pd) {
+		memcpy(dev->dev_addr, pd->mac_addr, ETH_ALEN);
+		priv->has_phy = pd->has_phy;
+		priv->phy_id = pd->phy_id;
+		priv->has_phy_interrupt = pd->has_phy_interrupt;
+		priv->phy_interrupt = pd->phy_interrupt;
+		priv->use_external_mii = pd->use_external_mii;
+		priv->use_marvell_header = pd->use_marvell_header;
+		priv->pause_auto = pd->pause_auto;
+		priv->pause_rx = pd->pause_rx;
+		priv->pause_tx = pd->pause_tx;
+		priv->force_duplex_full = pd->force_duplex_full;
+		priv->force_speed_100 = pd->force_speed_100;
+	}
+
+	bcm_enet_hw_preinit(priv);
+
+	/* MII bus registration */
+	if (priv->has_phy) {
+		bus = &priv->mii_bus;
+		bus->name = "bcm963xx_enet MII bus";
+		bus->dev = &pdev->dev;
+		bus->priv = priv;
+		bus->read = bcm_enet_mdio_read_phylib;
+		bus->write = bcm_enet_mdio_write_phylib;
+		bus->id = priv->mac_id;
+
+		/* only probe bus where we think the PHY is, because
+		 * the mdio read operation return 0 instead of 0xffff
+		 * if a slave is not present on hw */
+		bus->phy_mask = ~(1 << priv->phy_id);
+
+		bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
+		if (!bus->irq)
+			goto err;
+
+		if (priv->has_phy_interrupt)
+			bus->irq[priv->phy_id] = priv->phy_interrupt;
+		else
+			bus->irq[priv->phy_id] = PHY_POLL;
+
+		if ((ret = mdiobus_register(bus))) {
+			dev_err(&pdev->dev, "unable to register mdio bus\n");
+			goto err;
+		}
+		mdio_registered = 1;
+	} else {
+
+		/* run platform code to initialize PHY device */
+		if (pd->mii_config &&
+		    pd->mii_config(dev, 1, bcm_enet_mdio_read_mii,
+				   bcm_enet_mdio_write_mii)) {
+			dev_err(&pdev->dev, "unable to configure mdio bus\n");
+			goto err;
+		}
+	}
+
+	spin_lock_init(&priv->rx_lock);
+
+	/* init rx timeout (used for oom) */
+	init_timer(&priv->rx_timeout);
+	priv->rx_timeout.function = bcm_enet_refill_rx_timer;
+	priv->rx_timeout.data = (unsigned long)dev;
+
+	/* init the mib update lock&work */
+	mutex_init(&priv->mib_update_lock);
+	INIT_WORK(&priv->mib_update_task, bcm_enet_update_mib_counters);
+
+	/* zero mib counters */
+	for (i = 0; i < ENET_MIB_REG_COUNT; i++)
+		enet_writel(priv, 0, ENET_MIB_REG(i));
+
+	/* register netdevice */
+	dev->open = bcm_enet_open;
+	dev->stop = bcm_enet_stop;
+	dev->hard_start_xmit = bcm_enet_start_xmit;
+	dev->get_stats = bcm_enet_get_stats;
+	dev->set_mac_address = bcm_enet_set_mac_address;
+	dev->set_multicast_list = bcm_enet_set_multicast_list;
+	dev->poll = bcm_enet_poll;
+	dev->do_ioctl = bcm_enet_ioctl;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = bcm_enet_netpoll;
+#endif
+	if (priv->use_marvell_header)
+		dev->hard_header_len += 4;
+
+	dev->weight = 16;
+	SET_ETHTOOL_OPS(dev, &bcm_enet_ethtool_ops);
+
+	if ((ret = register_netdev(dev)))
+		goto err;
+
+	netif_carrier_off(dev);
+	platform_set_drvdata(pdev, dev);
+	priv->pdev = pdev;
+	SET_NETDEV_DEV(dev, &pdev->dev);
+	SET_MODULE_OWNER(dev);
+
+	return 0;
+
+err:
+	if (mem_requested)
+		release_mem_region(res_mem->start, iomem_size);
+	if (mdio_registered)
+		mdiobus_unregister(&priv->mii_bus);
+	kfree(priv->mii_bus.irq);
+	if (priv->base) {
+		/* turn off mdc clock */
+		enet_writel(priv, 0, ENET_MIISC_REG);
+		iounmap(priv->base);
+	}
+	free_netdev(dev);
+	return ret;
+}
+
+
+/*
+ * exit func, stops hardware and unregisters netdevice
+ */
+static int __devexit bcm_enet_remove(struct platform_device *pdev)
+{
+	struct bcm_enet_priv *priv;
+	struct net_device *dev;
+	struct resource *res;
+
+	/* stop netdevice */
+	dev = platform_get_drvdata(pdev);
+	priv = netdev_priv(dev);
+	unregister_netdev(dev);
+
+	/* make sure no mib update is scheduled */
+	flush_scheduled_work();
+
+	if (priv->has_phy) {
+		mdiobus_unregister(&priv->mii_bus);
+		kfree(priv->mii_bus.irq);
+	} else {
+		struct bcm963xx_enet_platform_data *pd;
+
+		pd = pdev->dev.platform_data;
+		if (pd && pd->mii_config)
+			pd->mii_config(dev, 0, bcm_enet_mdio_read_mii,
+				       bcm_enet_mdio_write_mii);
+	}
+
+	/* turn off mdc clock */
+	enet_writel(priv, 0, ENET_MIISC_REG);
+
+	/* release device resources */
+	iounmap(priv->base);
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	release_mem_region(res->start, res->end - res->start + 1);
+
+	free_netdev(dev);
+	return 0;
+}
+
+struct platform_driver bcm963xx_enet_driver = {
+	.probe	= bcm_enet_probe,
+	.remove	= __devexit_p(bcm_enet_remove),
+	.driver	= {
+		.name	= "bcm963xx_enet",
+		.owner  = THIS_MODULE,
+	},
+};
+
+/*
+ * reserve & remap memory space shared between all macs
+ */
+static int __devinit bcm_enet_shared_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	unsigned int iomem_size;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	iomem_size = res->end - res->start + 1;
+	if (!request_mem_region(res->start, iomem_size, "bcm963xx_enet_dma"))
+		return -EBUSY;
+
+	bcm_enet_shared_base = ioremap(res->start, iomem_size);
+	if (!bcm_enet_shared_base) {
+		release_mem_region(res->start, iomem_size);
+		return -ENOMEM;
+	}
+	return 0;
+}
+
+static int __devexit bcm_enet_shared_remove(struct platform_device *pdev)
+{
+	struct resource *res;
+
+	iounmap(bcm_enet_shared_base);
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	release_mem_region(res->start, res->end - res->start + 1);
+	return 0;
+}
+
+/*
+ * this "shared" driver is needed because both macs share a single
+ * address space
+ */
+struct platform_driver bcm963xx_enet_shared_driver = {
+	.probe	= bcm_enet_shared_probe,
+	.remove	= __devexit_p(bcm_enet_shared_remove),
+	.driver	= {
+		.name	= "bcm963xx_enet_shared",
+		.owner  = THIS_MODULE,
+	},
+};
+
+/*
+ * entry point
+ */
+static int __init bcm_enet_init(void)
+{
+	int ret;
+	u32 ckctl;
+
+	/*
+	 * enable EMAC clock at module load, we cannot do this at
+	 * device probe time, since we have two MAC integrated.
+	 */
+	ckctl = bcm_perf_readl(PERF_CKCTL_REG);
+	ckctl |= CKCTL_EMAC_EN;
+	bcm_perf_writel(ckctl, PERF_CKCTL_REG);
+
+	if ((ret = platform_driver_register(&bcm963xx_enet_shared_driver)))
+		return ret;
+
+	if ((ret = platform_driver_register(&bcm963xx_enet_driver)))
+		platform_driver_unregister(&bcm963xx_enet_shared_driver);
+
+	return ret;
+}
+
+static void __exit bcm_enet_exit(void)
+{
+	u32 ckctl;
+
+	platform_driver_unregister(&bcm963xx_enet_driver);
+	platform_driver_unregister(&bcm963xx_enet_shared_driver);
+
+	/*
+	 * disable EMAC clock at here, we cannot do this at device
+	 * remove time since there may still be one of the MAC in use.
+	 */
+	ckctl = bcm_perf_readl(PERF_CKCTL_REG);
+	ckctl &= ~CKCTL_EMAC_EN;
+	bcm_perf_writel(ckctl, PERF_CKCTL_REG);
+}
+
+
+module_init(bcm_enet_init);
+module_exit(bcm_enet_exit);
+
+MODULE_DESCRIPTION("BCM963xx internal ethernet mac driver");
+MODULE_AUTHOR("Maxime Bizon <mbizon@freebox.fr>");
+MODULE_LICENSE("GPL");
--- /dev/null	2011-06-03 14:51:38.633053002 +0200
+++ linux-2.6.20.14-fbx/drivers/net/bcm963xx_enet.h	2011-09-26 15:07:54.708835201 +0200
@@ -0,0 +1,290 @@
+#ifndef BCM963XX_ENET_H_
+#define BCM963XX_ENET_H_
+
+#include <linux/types.h>
+#include <linux/mii.h>
+#include <linux/mutex.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-bcm963xx/bcm963xx_regs.h>
+#include <asm/mach-bcm963xx/bcm963xx_irq.h>
+
+
+/* default number of descriptor */
+#define BCMENET_DEF_RX_DESC	64
+#define BCMENET_DEF_TX_DESC	32
+
+/* maximum burst len for dma (4 bytes unit) */
+#define BCMENET_DMA_MAXBURST	16
+
+/* tx transmit threshold (4 bytes unit), fifo is 256 bytes, the value
+ * must be low enough so that a DMA transfer of above burst length can
+ * not overflow the fifo  */
+#define BCMENET_TX_FIFO_TRESH	32
+
+/* maximum rx/tx packet size */
+#define	BCMENET_MAX_RX_SIZE	(ETH_FRAME_LEN + 4 + 4) /* vlan + fcs */
+#define	BCMENET_MAX_TX_SIZE	(ETH_FRAME_LEN + 4 + 4)
+
+/* add + 2 for optional marvell header */
+#define BCMENET_RX_SKB_SIZE	ALIGN(BCMENET_MAX_RX_SIZE + 2, \
+				      BCMENET_DMA_MAXBURST * 4)
+
+/*
+ * rx/tx dma descriptor
+ */
+struct bcm_enet_desc {
+	u32 len_stat;
+	u32 address;
+};
+
+#define DMADESC_LENGTH_SHIFT	16
+#define DMADESC_LENGTH_MASK	(0xfff << DMADESC_LENGTH_SHIFT)
+#define DMADESC_OWNER_MASK	(1 << 15)
+#define DMADESC_EOP_MASK	(1 << 14)
+#define DMADESC_SOP_MASK	(1 << 13)
+#define DMADESC_ESOP_MASK	(DMADESC_EOP_MASK | DMADESC_SOP_MASK)
+#define DMADESC_WRAP_MASK	(1 << 12)
+
+#define DMADESC_UNDER_MASK	(1 << 9)
+#define DMADESC_APPEND_CRC	(1 << 8)
+#define DMADESC_OVSIZE_MASK	(1 << 4)
+#define DMADESC_RXER_MASK	(1 << 2)
+#define DMADESC_CRC_MASK	(1 << 1)
+#define DMADESC_OV_MASK		(1 << 0)
+#define DMADESC_ERR_MASK	(DMADESC_UNDER_MASK | \
+				DMADESC_OVSIZE_MASK | \
+				DMADESC_RXER_MASK | \
+				DMADESC_CRC_MASK | \
+				DMADESC_OV_MASK)
+
+
+/*
+ * MIB Counters register definitions
+*/
+#define ETH_MIB_TX_GD_OCTETS			0
+#define ETH_MIB_TX_GD_PKTS			1
+#define ETH_MIB_TX_ALL_OCTETS			2
+#define ETH_MIB_TX_ALL_PKTS			3
+#define ETH_MIB_TX_BRDCAST			4
+#define ETH_MIB_TX_MULT				5
+#define ETH_MIB_TX_64				6
+#define ETH_MIB_TX_65_127			7
+#define ETH_MIB_TX_128_255			8
+#define ETH_MIB_TX_256_511			9
+#define ETH_MIB_TX_512_1023			10
+#define ETH_MIB_TX_1024_MAX			11
+#define ETH_MIB_TX_JAB				12
+#define ETH_MIB_TX_OVR				13
+#define ETH_MIB_TX_FRAG				14
+#define ETH_MIB_TX_UNDERRUN			15
+#define ETH_MIB_TX_COL				16
+#define ETH_MIB_TX_1_COL			17
+#define ETH_MIB_TX_M_COL			18
+#define ETH_MIB_TX_EX_COL			19
+#define ETH_MIB_TX_LATE				20
+#define ETH_MIB_TX_DEF				21
+#define ETH_MIB_TX_CRS				22
+#define ETH_MIB_TX_PAUSE			23
+
+#define ETH_MIB_RX_GD_OCTETS			32
+#define ETH_MIB_RX_GD_PKTS			33
+#define ETH_MIB_RX_ALL_OCTETS			34
+#define ETH_MIB_RX_ALL_PKTS			35
+#define ETH_MIB_RX_BRDCAST			36
+#define ETH_MIB_RX_MULT				37
+#define ETH_MIB_RX_64				38
+#define ETH_MIB_RX_65_127			39
+#define ETH_MIB_RX_128_255			40
+#define ETH_MIB_RX_256_511			41
+#define ETH_MIB_RX_512_1023			42
+#define ETH_MIB_RX_1024_MAX			43
+#define ETH_MIB_RX_JAB				44
+#define ETH_MIB_RX_OVR				45
+#define ETH_MIB_RX_FRAG				46
+#define ETH_MIB_RX_DROP				47
+#define ETH_MIB_RX_CRC_ALIGN			48
+#define ETH_MIB_RX_UND				49
+#define ETH_MIB_RX_CRC				50
+#define ETH_MIB_RX_ALIGN			51
+#define ETH_MIB_RX_SYM				52
+#define ETH_MIB_RX_PAUSE			53
+#define ETH_MIB_RX_CNTRL			54
+
+
+struct bcm_enet_mib_counters {
+	u64 tx_gd_octets;
+	u32 tx_gd_pkts;
+	u32 tx_all_octets;
+	u32 tx_all_pkts;
+	u32 tx_brdcast;
+	u32 tx_mult;
+	u32 tx_64;
+	u32 tx_65_127;
+	u32 tx_128_255;
+	u32 tx_256_511;
+	u32 tx_512_1023;
+	u32 tx_1024_max;
+	u32 tx_jab;
+	u32 tx_ovr;
+	u32 tx_frag;
+	u32 tx_underrun;
+	u32 tx_col;
+	u32 tx_1_col;
+	u32 tx_m_col;
+	u32 tx_ex_col;
+	u32 tx_late;
+	u32 tx_def;
+	u32 tx_crs;
+	u32 tx_pause;
+	u64 rx_gd_octets;
+	u32 rx_gd_pkts;
+	u32 rx_all_octets;
+	u32 rx_all_pkts;
+	u32 rx_brdcast;
+	u32 rx_mult;
+	u32 rx_64;
+	u32 rx_65_127;
+	u32 rx_128_255;
+	u32 rx_256_511;
+	u32 rx_512_1023;
+	u32 rx_1024_max;
+	u32 rx_jab;
+	u32 rx_ovr;
+	u32 rx_frag;
+	u32 rx_drop;
+	u32 rx_crc_align;
+	u32 rx_und;
+	u32 rx_crc;
+	u32 rx_align;
+	u32 rx_sym;
+	u32 rx_pause;
+	u32 rx_cntrl;
+};
+
+
+struct bcm_enet_priv {
+
+	/* mac id (from platform device id) */
+	int mac_id;
+
+	/* base remapped address of device */
+	void __iomem *base;
+
+	/* mac irq, rx_dma irq, tx_dma irq */
+	int irq;
+	int irq_rx;
+	int irq_tx;
+
+	/* hw view of rx & tx dma ring */
+	dma_addr_t rx_desc_dma;
+	dma_addr_t tx_desc_dma;
+
+	/* allocated size (in bytes) for rx & tx dma ring */
+	unsigned int rx_desc_alloc_size;
+	unsigned int tx_desc_alloc_size;
+
+
+	/* dma channel id for rx */
+	int rx_chan;
+
+	/* number of dma desc in rx ring */
+	int rx_ring_size;
+
+	/* cpu view of rx dma ring */
+	struct bcm_enet_desc *rx_desc_cpu;
+
+	/* current number of armed descriptor given to hardware for rx */
+	int rx_desc_count;
+
+	/* next rx descriptor to fetch from hardware */
+	int rx_curr_desc;
+
+	/* next dirty rx descriptor to refill */
+	int rx_dirty_desc;
+
+	/* list of skb given to hw for rx */
+	struct sk_buff **rx_skb;
+
+	/* used when rx skb allocation failed, so we defer rx queue
+	 * refill */
+	struct timer_list rx_timeout;
+
+	/* lock rx_timeout against rx normal operation */
+	spinlock_t rx_lock;
+
+
+	/* dma channel id for tx */
+	int tx_chan;
+
+	/* number of dma desc in tx ring */
+	int tx_ring_size;
+
+	/* cpu view of rx dma ring */
+	struct bcm_enet_desc *tx_desc_cpu;
+
+	/* number of available descriptor for tx */
+	int tx_desc_count;
+
+	/* next tx descriptor avaiable */
+	int tx_curr_desc;
+
+	/* next dirty tx descriptor to reclaim */
+	int tx_dirty_desc;
+
+	/* list of skb given to hw for tx */
+	struct sk_buff **tx_skb;
+
+	/* lock used by tx reclaim and xmit */
+	spinlock_t tx_lock;
+
+
+	/* set if internal phy is ignored and external mii interface
+	 * is selected */
+	int use_external_mii;
+
+	/* set if remote supports marvell routing header */
+	int use_marvell_header;
+
+	/* set if a phy is connected, phy address must be known,
+	 * probing is not possible */
+	int has_phy;
+	int phy_id;
+
+	/* set if connected phy has an associated irq */
+	int has_phy_interrupt;
+	int phy_interrupt;
+
+	/* used when a phy is connected (phylib used) */
+	struct mii_bus mii_bus;
+	struct phy_device *phydev;
+	int old_link;
+	int old_duplex;
+	int old_pause;
+
+	/* used when no phy is connected */
+	int force_speed_100;
+	int force_duplex_full;
+
+	/* pause parameters */
+	int pause_auto;
+	int pause_rx;
+	int pause_tx;
+
+	/* stats */
+	struct net_device_stats stats;
+	struct bcm_enet_mib_counters mib;
+
+	/* after mib interrupt, mib registers update is done in this
+	 * work queue */
+	struct work_struct mib_update_task;
+
+	/* lock mib update between userspace request and workqueue */
+	struct mutex mib_update_lock;
+
+	/* platform device reference */
+	struct platform_device *pdev;
+};
+
+#endif /* ! BCM963XX_ENET_H_ */
--- /dev/null	2011-06-03 14:51:38.633053002 +0200
+++ linux-2.6.20.14-fbx/drivers/serial/bcm963xx_uart.c	2011-09-26 15:07:55.088834967 +0200
@@ -0,0 +1,886 @@
+/*
+ *  drivers/serial/bcm963xx_uart.c
+ *
+ * Derived from many drivers using generic_serial interface.
+ *
+ *  Copyright (C) 2007 Maxime Bizon
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ *  Serial driver for BCM963xx integrated UART.
+ *
+ * Hardware flow control was _not_ tested since I only have RX/TX on
+ * my board.
+ */
+#if defined(CONFIG_SERIAL_BCM963XX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/console.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/sysrq.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+
+#include <asm/mach-bcm963xx/bcm963xx_clk.h>
+#include <asm/mach-bcm963xx/bcm963xx_irq.h>
+#include <asm/mach-bcm963xx/bcm963xx_regs.h>
+#include <asm/mach-bcm963xx/bcm963xx_io.h>
+
+#define BCM963XX_NR_UARTS	2
+
+static struct uart_port ports[BCM963XX_NR_UARTS];
+
+/*
+ * rx interrupt mask / stat
+ *
+ * mask:
+ *  - rx fifo full
+ *  - rx fifo above threshold
+ *  - rx fifo not empty for too long
+ */
+#define UART_RX_INT_MASK	(UART_IR_MASK(UART_IR_RXOVER) |		\
+				UART_IR_MASK(UART_IR_RXTHRESH) |	\
+				UART_IR_MASK(UART_IR_RXTIMEOUT))
+
+#define UART_RX_INT_STAT	(UART_IR_STAT(UART_IR_RXOVER) |		\
+				UART_IR_STAT(UART_IR_RXTHRESH) |	\
+				UART_IR_STAT(UART_IR_RXTIMEOUT))
+
+/*
+ * tx interrupt mask / stat
+ *
+ * mask:
+ * - tx fifo empty
+ * - tx fifo below threshold
+ */
+#define UART_TX_INT_MASK	(UART_IR_MASK(UART_IR_TXEMPTY) |	\
+				UART_IR_MASK(UART_IR_TXTRESH))
+
+#define UART_TX_INT_STAT	(UART_IR_STAT(UART_IR_TXEMPTY) |	\
+				UART_IR_STAT(UART_IR_TXTRESH))
+
+/*
+ * external input interrupt
+ *
+ * mask: any edge on CTS, DCD
+ */
+#define UART_EXTINP_INT_MASK	UART_EXTINP_IRMASK(UART_EXTINP_IR_CTS) |\
+				UART_EXTINP_IRMASK(UART_EXTINP_IR_DCD)
+
+/*
+ * handy uart register accessor
+ */
+static inline unsigned int bcm_uart_readl(struct uart_port *port,
+					 unsigned int offset)
+{
+	return bcm_readl(port->membase + offset);
+}
+
+static inline void bcm_uart_writel(struct uart_port *port,
+				  unsigned int value, unsigned int offset)
+{
+	bcm_writel(value, port->membase + offset);
+}
+
+/*
+ * serial core request to check if uart tx fifo is empty
+ */
+static unsigned int bcm_uart_tx_empty(struct uart_port *port)
+{
+	unsigned int val;
+
+	val = bcm_uart_readl(port, UART_IR_REG);
+	return (val & UART_IR_STAT(UART_IR_TXEMPTY)) ? 1 : 0;
+}
+
+/*
+ * serial core request to set RTS and DTR pin state and loopback mode
+ */
+static void bcm_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+	unsigned int val;
+
+	val = bcm_uart_readl(port, UART_MCTL_REG);
+	val &= ~(UART_MCTL_DTR_MASK | UART_MCTL_RTS_MASK);
+	/* invert of written value is reflected on the pin */
+	if (!(mctrl & TIOCM_DTR))
+		val |= UART_MCTL_DTR_MASK;
+	if (!(mctrl & TIOCM_RTS))
+		val |= UART_MCTL_RTS_MASK;
+	bcm_uart_writel(port, val, UART_MCTL_REG);
+
+	val = bcm_uart_readl(port, UART_CTL_REG);
+	if (mctrl & TIOCM_LOOP)
+		val |= UART_CTL_LOOPBACK_MASK;
+	else
+		val &= ~UART_CTL_LOOPBACK_MASK;
+	bcm_uart_writel(port, val, UART_CTL_REG);
+}
+
+/*
+ * serial core request to return RI, CTS, DCD and DSR pin state
+ */
+static unsigned int bcm_uart_get_mctrl(struct uart_port *port)
+{
+	unsigned int val, mctrl;
+
+	mctrl = 0;
+	val = bcm_uart_readl(port, UART_EXTINP_REG);
+	if (val & UART_EXTINP_RI_MASK)
+		mctrl |= TIOCM_RI;
+	if (val & UART_EXTINP_CTS_MASK)
+		mctrl |= TIOCM_CTS;
+	if (val & UART_EXTINP_DCD_MASK)
+		mctrl |= TIOCM_CD;
+	if (val & UART_EXTINP_DSR_MASK)
+		mctrl |= TIOCM_DSR;
+	return mctrl;
+}
+
+/*
+ * serial core request to disable tx ASAP (used for flow control)
+ */
+static void bcm_uart_stop_tx(struct uart_port *port)
+{
+	unsigned int val;
+
+	val = bcm_uart_readl(port, UART_CTL_REG);
+	val &= ~(UART_CTL_TXEN_MASK);
+	bcm_uart_writel(port, val, UART_CTL_REG);
+
+	val = bcm_uart_readl(port, UART_IR_REG);
+	val &= ~UART_TX_INT_MASK;
+	bcm_uart_writel(port, val, UART_IR_REG);
+}
+
+/*
+ * serial core request to (re)enable tx
+ */
+static void bcm_uart_start_tx(struct uart_port *port)
+{
+	unsigned int val;
+
+	val = bcm_uart_readl(port, UART_IR_REG);
+	val |= UART_TX_INT_MASK;
+	bcm_uart_writel(port, val, UART_IR_REG);
+
+	val = bcm_uart_readl(port, UART_CTL_REG);
+	val |= UART_CTL_TXEN_MASK;
+	bcm_uart_writel(port, val, UART_CTL_REG);
+}
+
+/*
+ * serial core request to stop rx, called before port shutdown
+ */
+static void bcm_uart_stop_rx(struct uart_port *port)
+{
+	unsigned int val;
+
+	val = bcm_uart_readl(port, UART_IR_REG);
+	val &= ~UART_RX_INT_MASK;
+	bcm_uart_writel(port, val, UART_IR_REG);
+}
+
+/*
+ * serial core request to enable modem status interrupt reporting
+ */
+static void bcm_uart_enable_ms(struct uart_port *port)
+{
+	unsigned int val;
+
+	val = bcm_uart_readl(port, UART_IR_REG);
+	val |= UART_IR_MASK(UART_IR_EXTIP);
+	bcm_uart_writel(port, val, UART_IR_REG);
+}
+
+/*
+ * serial core request to start/stop emitting break char
+ */
+static void bcm_uart_break_ctl(struct uart_port *port, int ctl)
+{
+	unsigned long flags;
+	unsigned int val;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	val = bcm_uart_readl(port, UART_CTL_REG);
+	if (ctl)
+		val |= UART_CTL_XMITBRK_MASK;
+	else
+		val &= ~UART_CTL_XMITBRK_MASK;
+	bcm_uart_writel(port, val, UART_CTL_REG);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/*
+ * return port type in string format
+ */
+static const char *bcm_uart_type(struct uart_port *port)
+{
+	return (port->type == PORT_BCM963XX) ? "bcm963xx_uart" : NULL;
+}
+
+/*
+ * read all chars in rx fifo and send them to core
+ */
+static void bcm_uart_do_rx(struct uart_port *port)
+{
+	struct tty_struct *tty;
+	unsigned int max_count;
+
+	/* limit number of char read in interrupt, should not be
+	 * higher than fifo size anyway since we're much faster than
+	 * serial port */
+	max_count = 32;
+	tty = port->info->tty;
+	do {
+		unsigned int iestat, c, cstat;
+		char flag;
+
+		/* get overrun/fifo empty information from ier
+		 * register */
+		iestat = bcm_uart_readl(port, UART_IR_REG);
+		if (!(iestat & UART_IR_STAT(UART_IR_RXNOTEMPTY)))
+			break;
+
+		cstat = c = bcm_uart_readl(port, UART_FIFO_REG);
+		port->icount.rx++;
+		flag = TTY_NORMAL;
+		c &= 0xff;
+
+		if (unlikely((cstat & UART_FIFO_ANYERR_MASK))) {
+			/* do stats first */
+			if (cstat & UART_FIFO_BRKDET_MASK) {
+				port->icount.brk++;
+				if (uart_handle_break(port))
+					continue;
+			}
+
+			if (cstat & UART_FIFO_PARERR_MASK)
+				port->icount.parity++;
+			if (cstat & UART_FIFO_FRAMEERR_MASK)
+				port->icount.frame++;
+
+			/* update flag wrt read_status_mask */
+			cstat &= port->read_status_mask;
+			if (cstat & UART_FIFO_BRKDET_MASK)
+				flag = TTY_BREAK;
+			if (cstat & UART_FIFO_FRAMEERR_MASK)
+				flag = TTY_FRAME;
+			if (cstat & UART_FIFO_PARERR_MASK)
+				flag = TTY_PARITY;
+		}
+
+		if (uart_handle_sysrq_char(port, c))
+			continue;
+
+		if (unlikely(iestat & UART_IR_STAT(UART_IR_RXOVER))) {
+			port->icount.overrun++;
+			tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+		}
+
+		if ((cstat & port->ignore_status_mask) == 0)
+			tty_insert_flip_char(tty, c, flag);
+
+	} while (--max_count);
+
+	tty_flip_buffer_push(tty);
+}
+
+/*
+ * fill tx fifo with chars to send, stop when fifo is about to be full
+ * or when all chars have been sent.
+ */
+static void bcm_uart_do_tx(struct uart_port *port)
+{
+	struct circ_buf *xmit;
+	unsigned int val, max_count;
+
+	if (port->x_char) {
+		bcm_uart_writel(port, port->x_char, UART_FIFO_REG);
+		port->icount.tx++;
+		port->x_char = 0;
+		return;
+	}
+
+	if (uart_tx_stopped(port)) {
+		bcm_uart_stop_tx(port);
+		return;
+	}
+
+	xmit = &port->info->xmit;
+	if (uart_circ_empty(xmit)) {
+		goto txq_empty;
+	}
+
+	val = bcm_uart_readl(port, UART_MCTL_REG);
+	val = (val & UART_MCTL_TXFIFOFILL_MASK) >> UART_MCTL_TXFIFOFILL_SHIFT;
+	max_count = port->fifosize - val;
+
+	while (max_count--) {
+		unsigned int c;
+
+		c = xmit->buf[xmit->tail];
+		bcm_uart_writel(port, c, UART_FIFO_REG);
+		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+		port->icount.tx++;
+		if (uart_circ_empty(xmit))
+			break;
+	}
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(port);
+
+	if (uart_circ_empty(xmit))
+		goto txq_empty;
+	return;
+
+txq_empty:
+	/* nothing to send, disable transmit interrupt */
+	val = bcm_uart_readl(port, UART_IR_REG);
+	val &= ~UART_TX_INT_MASK;
+	bcm_uart_writel(port, val, UART_IR_REG);
+	return;
+}
+
+/*
+ * process uart interrupt
+ */
+static irqreturn_t bcm_uart_interrupt(int irq, void *dev_id)
+{
+	struct uart_port *port;
+	unsigned int irqstat;
+
+	port = dev_id;
+	spin_lock(&port->lock);
+
+	irqstat = bcm_uart_readl(port, UART_IR_REG);
+	if (irqstat & UART_RX_INT_STAT)
+		bcm_uart_do_rx(port);
+
+	if (irqstat & UART_TX_INT_STAT)
+		bcm_uart_do_tx(port);
+
+	if (irqstat & UART_IR_MASK(UART_IR_EXTIP)) {
+		unsigned int estat;
+
+		estat = bcm_uart_readl(port, UART_EXTINP_REG);
+		if (estat & UART_EXTINP_IRSTAT(UART_EXTINP_IR_CTS))
+			uart_handle_cts_change(port,
+					       estat & UART_EXTINP_CTS_MASK);
+		if (estat & UART_EXTINP_IRSTAT(UART_EXTINP_IR_DCD))
+			uart_handle_dcd_change(port,
+					       estat & UART_EXTINP_DCD_MASK);
+	}
+
+	spin_unlock(&port->lock);
+	return IRQ_HANDLED;
+}
+
+/*
+ * enable rx & tx operation on uart
+ */
+static void bcm_uart_enable(struct uart_port *port)
+{
+	unsigned int val;
+
+	val = bcm_uart_readl(port, UART_CTL_REG);
+	val |= (UART_CTL_BRGEN_MASK | UART_CTL_TXEN_MASK | UART_CTL_RXEN_MASK);
+	bcm_uart_writel(port, val, UART_CTL_REG);
+}
+
+/*
+ * disable rx & tx operation on uart
+ */
+static void bcm_uart_disable(struct uart_port *port)
+{
+	unsigned int val;
+
+	val = bcm_uart_readl(port, UART_CTL_REG);
+	val &= ~(UART_CTL_BRGEN_MASK | UART_CTL_TXEN_MASK |
+		 UART_CTL_RXEN_MASK);
+	bcm_uart_writel(port, val, UART_CTL_REG);
+}
+
+/*
+ * clear all unread data in rx fifo and unsent data in tx fifo
+ */
+static void bcm_uart_flush(struct uart_port *port)
+{
+	unsigned int val;
+
+	/* empty rx and tx fifo */
+	val = bcm_uart_readl(port, UART_CTL_REG);
+	val |= UART_CTL_RSTRXFIFO_MASK | UART_CTL_RSTTXFIFO_MASK;
+	bcm_uart_writel(port, val, UART_CTL_REG);
+
+	/* read any pending char to make sure all irq status are
+	 * cleared */
+	(void)bcm_uart_readl(port, UART_FIFO_REG);
+}
+
+/*
+ * serial core request to initialize uart and start rx operation
+ */
+static int bcm_uart_startup(struct uart_port *port)
+{
+	unsigned int val;
+	int ret;
+
+	/* mask all irq and flush port */
+	bcm_uart_disable(port);
+	bcm_uart_writel(port, 0, UART_IR_REG);
+	bcm_uart_flush(port);
+
+	/* clear any pending external input interrupt */
+	(void)bcm_uart_readl(port, UART_EXTINP_REG);
+
+	/* set rx/tx fifo thresh to fifo half size */
+	val = bcm_uart_readl(port, UART_MCTL_REG);
+	val &= ~(UART_MCTL_RXFIFOTHRESH_MASK | UART_MCTL_TXFIFOTHRESH_MASK);
+	val |= (port->fifosize / 2) << UART_MCTL_RXFIFOTHRESH_SHIFT;
+	val |= (port->fifosize / 2) << UART_MCTL_TXFIFOTHRESH_SHIFT;
+	bcm_uart_writel(port, val, UART_MCTL_REG);
+
+	/* set rx fifo timeout to 1 char time */
+	val = bcm_uart_readl(port, UART_CTL_REG);
+	val &= ~UART_CTL_RXTMOUTCNT_MASK;
+	val |= 1 << UART_CTL_RXTMOUTCNT_SHIFT;
+	bcm_uart_writel(port, val, UART_CTL_REG);
+
+	/* report any edge on dcd and cts */
+	val = UART_EXTINP_INT_MASK;
+	val |= UART_EXTINP_DCD_NOSENSE_MASK;
+	val |= UART_EXTINP_CTS_NOSENSE_MASK;
+	bcm_uart_writel(port, val, UART_EXTINP_REG);
+
+	/* register irq and enable rx interrupts */
+	ret = request_irq(port->irq, bcm_uart_interrupt, 0,
+			  bcm_uart_type(port), port);
+	if (ret)
+		return ret;
+	bcm_uart_writel(port, UART_RX_INT_MASK, UART_IR_REG);
+	bcm_uart_enable(port);
+	return 0;
+}
+
+/*
+ * serial core request to flush & disable uart
+ */
+static void bcm_uart_shutdown(struct uart_port *port)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&port->lock, flags);
+	bcm_uart_writel(port, 0, UART_IR_REG);
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	bcm_uart_disable(port);
+	bcm_uart_flush(port);
+	free_irq(port->irq, port);
+}
+
+/*
+ * serial core request to change current uart setting
+ */
+static void bcm_uart_set_termios(struct uart_port *port,
+				 struct ktermios *new,
+				 struct ktermios *old)
+{
+	unsigned int ctl, baud, quot, ier;
+	unsigned long flags;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	/* disable uart while changing speed */
+	bcm_uart_disable(port);
+	bcm_uart_flush(port);
+
+	/* update Control register */
+	ctl = bcm_uart_readl(port, UART_CTL_REG);
+	ctl &= ~UART_CTL_BITSPERSYM_MASK;
+
+	switch (new->c_cflag & CSIZE) {
+	case CS5:
+		ctl |= (0 << UART_CTL_BITSPERSYM_SHIFT);
+		break;
+	case CS6:
+		ctl |= (1 << UART_CTL_BITSPERSYM_SHIFT);
+		break;
+	case CS7:
+		ctl |= (2 << UART_CTL_BITSPERSYM_SHIFT);
+		break;
+	default:
+		ctl |= (3 << UART_CTL_BITSPERSYM_SHIFT);
+		break;
+	}
+
+	ctl &= ~UART_CTL_STOPBITS_MASK;
+	if (new->c_cflag & CSTOPB)
+		ctl |= UART_CTL_STOPBITS_2;
+	else
+		ctl |= UART_CTL_STOPBITS_1;
+
+	ctl &= ~(UART_CTL_RXPAREN_MASK | UART_CTL_TXPAREN_MASK);
+	if (new->c_cflag & PARENB)
+		ctl |= (UART_CTL_RXPAREN_MASK | UART_CTL_TXPAREN_MASK);
+	ctl &= ~(UART_CTL_RXPAREVEN_MASK | UART_CTL_TXPAREVEN_MASK);
+	if (new->c_cflag & PARODD)
+		ctl |= (UART_CTL_RXPAREVEN_MASK | UART_CTL_TXPAREVEN_MASK);
+	bcm_uart_writel(port, ctl, UART_CTL_REG);
+
+	/* update Baudword register */
+	baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16);
+	quot = uart_get_divisor(port, baud) - 1;
+	bcm_uart_writel(port, quot, UART_BAUD_REG);
+
+	/* update Interrupt register */
+	ier = bcm_uart_readl(port, UART_IR_REG);
+
+	ier &= ~UART_IR_MASK(UART_IR_EXTIP);
+	if (UART_ENABLE_MS(port, new->c_cflag))
+		ier |= UART_IR_MASK(UART_IR_EXTIP);
+
+	bcm_uart_writel(port, ier, UART_IR_REG);
+
+	/* update read/ignore mask */
+	port->read_status_mask = UART_FIFO_VALID_MASK;
+	if (new->c_iflag & INPCK) {
+		port->read_status_mask |= UART_FIFO_FRAMEERR_MASK;
+		port->read_status_mask |= UART_FIFO_PARERR_MASK;
+	}
+	if (new->c_iflag & (BRKINT))
+		port->read_status_mask |= UART_FIFO_BRKDET_MASK;
+
+	port->ignore_status_mask = 0;
+	if (new->c_iflag & IGNPAR)
+		port->ignore_status_mask |= UART_FIFO_PARERR_MASK;
+	if (new->c_iflag & IGNBRK)
+		port->ignore_status_mask |= UART_FIFO_BRKDET_MASK;
+	if (!(new->c_cflag & CREAD))
+		port->ignore_status_mask |= UART_FIFO_VALID_MASK;
+
+	uart_update_timeout(port, new->c_cflag, baud);
+	bcm_uart_enable(port);
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/*
+ * serial core request to claim uart iomem
+ */
+static int bcm_uart_request_port(struct uart_port *port)
+{
+	unsigned int size;
+
+	size = RSET_UART_SIZE;
+	if (!request_mem_region(port->mapbase, size, "bcm963xx")) {
+		dev_err(port->dev, "Memory region busy\n");
+		return -EBUSY;
+	}
+
+	port->membase = ioremap(port->mapbase, size);
+	if (!port->membase) {
+		dev_err(port->dev, "Unable to map registers\n");
+		release_mem_region(port->mapbase, size);
+		return -EBUSY;
+	}
+	return 0;
+}
+
+/*
+ * serial core request to release uart iomem
+ */
+static void bcm_uart_release_port(struct uart_port *port)
+{
+	release_mem_region(port->mapbase, RSET_UART_SIZE);
+	iounmap(port->membase);
+}
+
+/*
+ * serial core request to do any port required autoconfiguration
+ */
+static void bcm_uart_config_port(struct uart_port *port, int flags)
+{
+	if (flags & UART_CONFIG_TYPE) {
+		if (bcm_uart_request_port(port))
+			return;
+		port->type = PORT_BCM963XX;
+	}
+}
+
+/*
+ * serial core request to check that port information in serinfo are
+ * suitable
+ */
+static int bcm_uart_verify_port(struct uart_port *port,
+				struct serial_struct *serinfo)
+{
+	if (port->type != PORT_BCM963XX)
+		return -EINVAL;
+	if (port->irq != serinfo->irq)
+		return -EINVAL;
+	if (port->iotype != serinfo->io_type)
+		return -EINVAL;
+	if (port->mapbase != (unsigned long)serinfo->iomem_base)
+		return -EINVAL;
+	return 0;
+}
+
+/* serial core callbacks */
+static struct uart_ops bcm_uart_ops = {
+	.tx_empty	= bcm_uart_tx_empty,
+	.get_mctrl	= bcm_uart_get_mctrl,
+	.set_mctrl	= bcm_uart_set_mctrl,
+	.start_tx	= bcm_uart_start_tx,
+	.stop_tx	= bcm_uart_stop_tx,
+	.stop_rx	= bcm_uart_stop_rx,
+	.enable_ms	= bcm_uart_enable_ms,
+	.break_ctl	= bcm_uart_break_ctl,
+	.startup	= bcm_uart_startup,
+	.shutdown	= bcm_uart_shutdown,
+	.set_termios	= bcm_uart_set_termios,
+	.type		= bcm_uart_type,
+	.release_port	= bcm_uart_release_port,
+	.request_port	= bcm_uart_request_port,
+	.config_port	= bcm_uart_config_port,
+	.verify_port	= bcm_uart_verify_port,
+};
+
+
+
+#ifdef CONFIG_SERIAL_BCM963XX_CONSOLE
+static inline void wait_for_xmitr(struct uart_port *port)
+{
+	unsigned int tmout;
+
+	/* Wait up to 10ms for the character(s) to be sent. */
+	tmout = 10000;
+	while (--tmout) {
+		unsigned int val;
+
+		val = bcm_uart_readl(port, UART_IR_REG);
+		if (val & UART_IR_STAT(UART_IR_TXEMPTY))
+			break;
+		udelay(1);
+	}
+
+	/* Wait up to 1s for flow control if necessary */
+	if (port->flags & UPF_CONS_FLOW) {
+		tmout = 1000000;
+		while (--tmout) {
+			unsigned int val;
+
+			val = bcm_uart_readl(port, UART_EXTINP_REG);
+			if (val & UART_EXTINP_CTS_MASK)
+				break;
+			udelay(1);
+		}
+	}
+}
+
+/*
+ * output given char
+ */
+static void bcm_console_putchar(struct uart_port *port, int ch)
+{
+	wait_for_xmitr(port);
+	bcm_uart_writel(port, ch, UART_FIFO_REG);
+}
+
+/*
+ * console core request to output given string
+ */
+static void bcm_console_write(struct console *co, const char *s,
+			      unsigned int count)
+{
+	struct uart_port *port;
+	unsigned long flags;
+	int locked;
+
+	port = &ports[co->index];
+
+	local_irq_save(flags);
+	if (port->sysrq) {
+		/* bcm_uart_interrupt() already took the lock */
+		locked = 0;
+	} else if (oops_in_progress) {
+		locked = spin_trylock(&port->lock);
+	} else {
+		spin_lock(&port->lock);
+		locked = 1;
+	}
+
+	/* call helper to deal with \r\n */
+	uart_console_write(port, s, count, bcm_console_putchar);
+
+	/* and wait for char to be transmitted */
+	wait_for_xmitr(port);
+
+	if (locked)
+		spin_unlock(&port->lock);
+	local_irq_restore(flags);
+}
+
+/*
+ * console core request to setup given console, find matching uart
+ * port and setup it.
+ */
+static int bcm_console_setup(struct console *co, char *options)
+{
+	struct uart_port *port;
+	int baud = 9600;
+	int bits = 8;
+	int parity = 'n';
+	int flow = 'n';
+
+	if (co->index < 0 || co->index >= BCM963XX_NR_UARTS)
+		return -EINVAL;
+	port = &ports[co->index];
+	if (!port->membase)
+		return -ENODEV;
+	if (options)
+		uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+	return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver bcm_uart_driver;
+
+static struct console bcm963xx_console = {
+	.name		= "ttyS",
+	.write		= bcm_console_write,
+	.device		= uart_console_device,
+	.setup		= bcm_console_setup,
+	.flags		= CON_PRINTBUFFER,
+	.index		= -1,
+	.data		= &bcm_uart_driver,
+};
+
+static int __init bcm963xx_console_init(void)
+{
+	register_console(&bcm963xx_console);
+	return 0;
+}
+
+console_initcall(bcm963xx_console_init);
+
+#define BCM963XX_CONSOLE	&bcm963xx_console
+#else
+#define BCM963XX_CONSOLE	NULL
+#endif /* CONFIG_SERIAL_BCM963XX_CONSOLE */
+
+static struct uart_driver bcm_uart_driver = {
+	.owner		= THIS_MODULE,
+	.driver_name	= "bcm963xx_uart",
+	.dev_name	= "ttyS",
+	.major		= TTY_MAJOR,
+	.minor		= 64,
+	.nr		= 2,
+	.cons		= BCM963XX_CONSOLE,
+};
+
+/*
+ * platform driver probe/remove callback
+ */
+static int __devinit bcm_uart_probe(struct platform_device *pdev)
+{
+	struct resource *res_mem, *res_irq;
+	struct uart_port *port;
+	int ret;
+
+	if (pdev->id < 0 || pdev->id >= BCM963XX_NR_UARTS)
+		return -EINVAL;
+
+	if (ports[pdev->id].membase)
+		return -EBUSY;
+
+	res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res_mem)
+		return -ENODEV;
+
+	res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res_irq)
+		return -ENODEV;
+
+	port = &ports[pdev->id];
+	memset(port, 0, sizeof (*port));
+	port->iotype = UPIO_MEM;
+	port->mapbase = res_mem->start;
+	port->irq = res_irq->start;
+	port->ops = &bcm_uart_ops;
+	port->flags = UPF_BOOT_AUTOCONF;
+	port->dev = &pdev->dev;
+	port->fifosize = 16;
+	port->uartclk = BCM963XX_FPERIPH / 2;
+	port->line = pdev->id;
+
+	ret = uart_add_one_port(&bcm_uart_driver, port);
+	if (ret) {
+		ports[pdev->id].membase = 0;
+		return ret;
+	}
+	platform_set_drvdata(pdev, port);
+	return 0;
+}
+
+static int __devexit bcm_uart_remove(struct platform_device *pdev)
+{
+	struct uart_port *port;
+
+	port = platform_get_drvdata(pdev);
+	uart_remove_one_port(&bcm_uart_driver, port);
+	platform_set_drvdata(pdev, NULL);
+	/* mark port as free */
+	ports[pdev->id].membase = 0;
+	return 0;
+}
+
+/*
+ * platform driver stuff
+ */
+static struct platform_driver bcm_uart_platform_driver = {
+	.probe	= bcm_uart_probe,
+	.remove	= __devexit_p(bcm_uart_remove),
+	.driver	= {
+		.owner = THIS_MODULE,
+		.name  = "bcm963xx_uart",
+	},
+};
+
+static int __init bcm_uart_init(void)
+{
+	int ret;
+
+	ret = uart_register_driver(&bcm_uart_driver);
+	if (ret)
+		return ret;
+
+	ret = platform_driver_register(&bcm_uart_platform_driver);
+	if (ret)
+		uart_unregister_driver(&bcm_uart_driver);
+
+	return ret;
+}
+
+static void __exit bcm_uart_exit(void)
+{
+	platform_driver_unregister(&bcm_uart_platform_driver);
+	uart_unregister_driver(&bcm_uart_driver);
+}
+
+module_init (bcm_uart_init);
+module_exit (bcm_uart_exit);
+
+MODULE_AUTHOR ("Maxime Bizon <mbizon@freebox.fr>");
+MODULE_DESCRIPTION ("Broadcom 963xx integrated uart driver");
+MODULE_LICENSE ("GPL");
diff -Nruw linux-2.6.20.14-fbx/drivers/tango2./Kconfig linux-2.6.20.14-fbx/drivers/tango2/Kconfig
--- linux-2.6.20.14-fbx/drivers/tango2./Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/drivers/tango2/Kconfig	2011-09-26 15:07:55.248834869 +0200
@@ -0,0 +1,30 @@
+#
+# TANGO2 devices configuration
+#
+
+menu "Tango2 devices"
+	depends on TANGO2
+
+config TANGO2_FIP
+	tristate "Front panel support"
+	select INPUT
+	---help---
+	  Tango2 FIP front panel support.
+
+config TANGO2_GPIO
+	tristate "GPIO sysfs support"
+	---help---
+	  Export GPIO attributes in sysfs.
+
+config TANGO2_IR
+	tristate "IR support"
+	---help---
+	  Tango2 IR (NEC/RC5/RC6) support.
+
+config TANGO2_FB
+	tristate "Framebuffer support"
+	depends on FB
+	---help---
+	  Tango2 framebuffer support.
+
+endmenu
diff -Nruw linux-2.6.20.14-fbx/drivers/tango2./Makefile linux-2.6.20.14-fbx/drivers/tango2/Makefile
--- linux-2.6.20.14-fbx/drivers/tango2./Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/drivers/tango2/Makefile	2011-09-26 15:07:55.248834869 +0200
@@ -0,0 +1,6 @@
+# Makefile for the TANGO2 device drivers
+
+obj-$(CONFIG_TANGO2_FIP) += fip.o
+obj-$(CONFIG_TANGO2_GPIO) += gpio.o
+obj-$(CONFIG_TANGO2_IR) += ir.o
+obj-$(CONFIG_TANGO2_FB) += fb.o
--- /dev/null	2011-06-03 14:51:38.633053002 +0200
+++ linux-2.6.20.14-fbx/drivers/usb/host/ohci-bcm963xx.c	2011-09-26 15:07:55.278834851 +0200
@@ -0,0 +1,135 @@
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <asm/mach-bcm963xx/bcm963xx_cpu.h>
+#include <asm/mach-bcm963xx/bcm963xx_regs.h>
+#include <asm/mach-bcm963xx/bcm963xx_io.h>
+
+static int __devinit ohci_bcm963xx_start(struct usb_hcd *hcd)
+{
+	struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+	int ret;
+
+	if ((ret = ohci_init(ohci)) < 0)
+		return ret;
+
+	/* FIXME: autodetected port 2 is shared with USB slave */
+
+	if ((ret = ohci_run(ohci)) < 0) {
+		err("can't start %s", hcd->self.bus_name);
+		ohci_stop(hcd);
+		return ret;
+	}
+	return 0;
+}
+
+static const struct hc_driver ohci_bcm963xx_hc_driver = {
+	.description =		hcd_name,
+	.product_desc =		"BCM963XX integrated OHCI controller",
+	.hcd_priv_size =	sizeof (struct ohci_hcd),
+
+	.irq =			ohci_irq,
+	.flags =		HCD_USB11 | HCD_MEMORY,
+	.start =		ohci_bcm963xx_start,
+	.stop =			ohci_stop,
+	.shutdown =		ohci_shutdown,
+	.urb_enqueue =		ohci_urb_enqueue,
+	.urb_dequeue =		ohci_urb_dequeue,
+	.endpoint_disable =	ohci_endpoint_disable,
+	.get_frame_number =	ohci_get_frame,
+	.hub_status_data =	ohci_hub_status_data,
+	.hub_control =		ohci_hub_control,
+	.hub_irq_enable =	ohci_rhsc_enable,
+	.start_port_reset =	ohci_start_port_reset,
+};
+
+static int ohci_hcd_bcm963xx_drv_probe(struct platform_device *pdev)
+{
+	struct resource *res_mem, *res_irq;
+	struct usb_hcd *hcd;
+	u32 reg;
+	int ret;
+
+	res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res_mem || !res_irq)
+		return -ENODEV;
+
+	if (BCMCPU_IS_6348()) {
+		/* enable USB host clock */
+		reg = bcm_perf_readl(PERF_CKCTL_REG);
+		reg |= CKCTL_USBHOST_EN;
+		bcm_perf_writel(reg, PERF_CKCTL_REG);
+		msleep(100);
+
+		reg = 0;
+		bcm_rset_writel(RSET_OHCI_PRIV, reg, OHCI_PRIV_REG);
+	} else if (BCMCPU_IS_6358()) {
+		reg = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SWAP_REG);
+		reg &= ~USBH_PRIV_SWAP_OHCI_ENDN_MASK;
+		reg |= USBH_PRIV_SWAP_OHCI_DATA_MASK;
+		bcm_rset_writel(RSET_USBH_PRIV, reg, USBH_PRIV_SWAP_REG);
+		/* don't ask... */
+		bcm_rset_writel(RSET_USBH_PRIV, 0x1c0020, USBH_PRIV_TEST_REG);
+	} else
+		return 0;
+
+	hcd = usb_create_hcd(&ohci_bcm963xx_hc_driver, &pdev->dev, "bcm963xx");
+	if (!hcd)
+		return -ENOMEM;
+	hcd->rsrc_start = res_mem->start;
+	hcd->rsrc_len = res_mem->end - res_mem->start + 1;
+
+	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+		pr_debug("request_mem_region failed\n");
+		ret = -EBUSY;
+		goto out;
+	}
+
+	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+	if (!hcd->regs) {
+		pr_debug("ioremap failed\n");
+		ret = -EIO;
+		goto out1;
+	}
+
+	ohci_hcd_init(hcd_to_ohci(hcd));
+
+	ret = usb_add_hcd(hcd, res_irq->start, 0);
+	if (ret)
+		goto out2;
+
+	platform_set_drvdata(pdev, hcd);
+	return 0;
+
+out2:
+	iounmap(hcd->regs);
+out1:
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+out:
+	usb_put_hcd(hcd);
+	return ret;
+}
+
+static int ohci_hcd_bcm963xx_drv_remove(struct platform_device *pdev)
+{
+	struct usb_hcd *hcd;
+
+	hcd = platform_get_drvdata(pdev);
+	usb_remove_hcd(hcd);
+	iounmap(hcd->regs);
+	usb_put_hcd(hcd);
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+	platform_set_drvdata(pdev, NULL);
+	return 0;
+}
+
+static struct platform_driver ohci_hcd_bcm963xx_driver = {
+	.probe		= ohci_hcd_bcm963xx_drv_probe,
+	.remove		= __devexit_p(ohci_hcd_bcm963xx_drv_remove),
+	.shutdown	= usb_hcd_platform_shutdown,
+	.driver		= {
+		.name	= "bcm963xx_ohci",
+		.owner	= THIS_MODULE,
+		.bus	= &platform_bus_type
+	},
+};
diff -Nruw linux-2.6.20.14-fbx/extdrivers./include/bcm963xx/bcmusb_device.h linux-2.6.20.14-fbx/extdrivers/include/bcm963xx/bcmusb_device.h
--- linux-2.6.20.14-fbx/extdrivers./include/bcm963xx/bcmusb_device.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/extdrivers/include/bcm963xx/bcmusb_device.h	2011-09-26 15:07:55.658834619 +0200
@@ -0,0 +1,11 @@
+#ifndef BCMUSB_DEVICE_H_
+#define BCMUSB_DEVICE_H_
+
+#include <linux/if_ether.h>
+
+struct bcmusb_platform_data {
+	char local_mac_addr[ETH_ALEN];
+	char remote_mac_addr[ETH_ALEN];
+};
+
+#endif /* !BCMUSB_DEVICE_H_ */
diff -Nruw linux-2.6.20.14-fbx/extdrivers./include/freebox/fbximagetag.h linux-2.6.20.14-fbx/extdrivers/include/freebox/fbximagetag.h
--- linux-2.6.20.14-fbx/extdrivers./include/freebox/fbximagetag.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/extdrivers/include/freebox/fbximagetag.h	2011-09-26 15:07:55.658834619 +0200
@@ -0,0 +1,29 @@
+
+#ifndef FBXIMAGETAG_H_
+# define FBXIMAGETAG_H_
+
+#define FBX_IMAGETAG_MAGIC		0x3658382b
+#define FBX_IMAGETAG_VERSION		1
+
+#define FBX_IMAGETAG_FLAGS_HAS_KERNEL   (1 << 0)
+#define FBX_IMAGETAG_FLAGS_HAS_FS       (1 << 1)
+#define FBX_IMAGETAG_FLAGS_SKRYPTED_KERNEL	(1 << 2)
+#define FBX_IMAGETAG_BANKNUM_SHIFT		0x3
+#define FBX_IMAGETAG_BANKNUM_MASK		0x1
+
+struct fbx_imagetag {
+	uint32_t        crc32;		/* for whole image minus this field */
+	uint32_t        magic;
+	uint32_t        version;
+	uint32_t        total_size;	/* in bytes */
+	char		name[128];	/* zero terminated */
+	uint32_t	build_date;	/* seconds since epoch */
+	char		builder[32];	/* builder name */
+	uint32_t        flags;
+	uint32_t        kernel_offset;	/* in bytes from origin */
+	uint32_t	kernel_size;	/* in bytes */
+	uint32_t        fs_offset;	/* in bytes from origin */
+	uint32_t        fs_size;	/* in bytes from origin */
+} __attribute__((packed));
+
+#endif /* FBXIMAGETAG_H_ */
diff -Nruw linux-2.6.20.14-fbx/fs/squashfs./inode.c linux-2.6.20.14-fbx/fs/squashfs/inode.c
--- linux-2.6.20.14-fbx/fs/squashfs./inode.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/fs/squashfs/inode.c	2011-09-26 15:07:55.998834410 +0200
@@ -0,0 +1,2428 @@
+/*
+ * Squashfs - a compressed read only filesystem for Linux
+ *
+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007
+ * Phillip Lougher <phillip@lougher.org.uk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2,
+ * or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * inode.c
+ */
+
+#include <linux/squashfs_fs.h>
+#include <linux/module.h>
+#include <linux/zlib.h>
+#include <linux/fs.h>
+#include <linux/squashfs_fs_sb.h>
+#include <linux/squashfs_fs_i.h>
+#include <linux/buffer_head.h>
+#include <linux/vfs.h>
+#include <linux/vmalloc.h>
+#include <linux/smp_lock.h>
+
+#include "squashfs.h"
+#include "linux/sqlzma.h"
+#include "linux/sqmagic.h"
+
+#define KeepPreemptive
+#undef KeepPreemptive
+struct sqlzma {
+#ifdef KeepPreemptive
+	struct mutex mtx;
+#endif
+	unsigned char read_data[SQUASHFS_FILE_MAX_SIZE];
+	struct sqlzma_un un;
+};
+static DEFINE_PER_CPU(struct sqlzma *, sqlzma);
+
+#define dpri(fmt, args...) /* printk("%s:%d: " fmt, __func__, __LINE__, ##args) */
+#define dpri_un(un)	dpri("un{%d, {%d %p}, {%d %p}, {%d %p}}\n", \
+			     (un)->un_lzma, (un)->un_a[0].sz, (un)->un_a[0].buf, \
+			     (un)->un_a[1].sz, (un)->un_a[1].buf, \
+			     (un)->un_a[2].sz, (un)->un_a[2].buf)
+
+static void vfs_read_inode(struct inode *i);
+static struct dentry *squashfs_get_parent(struct dentry *child);
+static int squashfs_read_inode(struct inode *i, squashfs_inode_t inode);
+static int squashfs_statfs(struct dentry *, struct kstatfs *);
+static int squashfs_symlink_readpage(struct file *file, struct page *page);
+static long long read_blocklist(struct inode *inode, int index,
+				int readahead_blks, char *block_list,
+				unsigned short **block_p, unsigned int *bsize);
+static int squashfs_readpage(struct file *file, struct page *page);
+static int squashfs_readpage4K(struct file *file, struct page *page);
+static int squashfs_readdir(struct file *, void *, filldir_t);
+static struct dentry *squashfs_lookup(struct inode *, struct dentry *,
+				struct nameidata *);
+static int squashfs_remount(struct super_block *s, int *flags, char *data);
+static void squashfs_put_super(struct super_block *);
+static int squashfs_get_sb(struct file_system_type *,int, const char *, void *,
+				struct vfsmount *);
+static struct inode *squashfs_alloc_inode(struct super_block *sb);
+static void squashfs_destroy_inode(struct inode *inode);
+static int init_inodecache(void);
+static void destroy_inodecache(void);
+
+static struct file_system_type squashfs_fs_type = {
+	.owner = THIS_MODULE,
+	.name = "squashfs",
+	.get_sb = squashfs_get_sb,
+	.kill_sb = kill_block_super,
+	.fs_flags = FS_REQUIRES_DEV
+};
+
+static const unsigned char squashfs_filetype_table[] = {
+	DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK
+};
+
+static struct super_operations squashfs_super_ops = {
+	.alloc_inode = squashfs_alloc_inode,
+	.destroy_inode = squashfs_destroy_inode,
+	.statfs = squashfs_statfs,
+	.put_super = squashfs_put_super,
+	.remount_fs = squashfs_remount
+};
+
+static struct super_operations squashfs_export_super_ops = {
+	.alloc_inode = squashfs_alloc_inode,
+	.destroy_inode = squashfs_destroy_inode,
+	.statfs = squashfs_statfs,
+	.put_super = squashfs_put_super,
+	.read_inode = vfs_read_inode
+};
+
+static struct export_operations squashfs_export_ops = {
+	.get_parent = squashfs_get_parent
+};
+
+SQSH_EXTERN const struct address_space_operations squashfs_symlink_aops = {
+	.readpage = squashfs_symlink_readpage
+};
+
+SQSH_EXTERN const struct address_space_operations squashfs_aops = {
+	.readpage = squashfs_readpage
+};
+
+SQSH_EXTERN const struct address_space_operations squashfs_aops_4K = {
+	.readpage = squashfs_readpage4K
+};
+
+static const struct file_operations squashfs_dir_ops = {
+	.read = generic_read_dir,
+	.readdir = squashfs_readdir
+};
+
+SQSH_EXTERN struct inode_operations squashfs_dir_inode_ops = {
+	.lookup = squashfs_lookup
+};
+
+
+static struct buffer_head *get_block_length(struct super_block *s,
+				int *cur_index, int *offset, int *c_byte)
+{
+	struct squashfs_sb_info *msblk = s->s_fs_info;
+	unsigned short temp;
+	struct buffer_head *bh;
+
+	if (!(bh = sb_bread(s, *cur_index)))
+		goto out;
+
+	if (msblk->devblksize - *offset == 1) {
+		if (msblk->swap)
+			((unsigned char *) &temp)[1] = *((unsigned char *)
+				(bh->b_data + *offset));
+		else
+			((unsigned char *) &temp)[0] = *((unsigned char *)
+				(bh->b_data + *offset));
+		brelse(bh);
+		if (!(bh = sb_bread(s, ++(*cur_index))))
+			goto out;
+		if (msblk->swap)
+			((unsigned char *) &temp)[0] = *((unsigned char *)
+				bh->b_data); 
+		else
+			((unsigned char *) &temp)[1] = *((unsigned char *)
+				bh->b_data); 
+		*c_byte = temp;
+		*offset = 1;
+	} else {
+		if (msblk->swap) {
+			((unsigned char *) &temp)[1] = *((unsigned char *)
+				(bh->b_data + *offset));
+			((unsigned char *) &temp)[0] = *((unsigned char *)
+				(bh->b_data + *offset + 1)); 
+		} else {
+			((unsigned char *) &temp)[0] = *((unsigned char *)
+				(bh->b_data + *offset));
+			((unsigned char *) &temp)[1] = *((unsigned char *)
+				(bh->b_data + *offset + 1)); 
+		}
+		*c_byte = temp;
+		*offset += 2;
+	}
+
+	if (SQUASHFS_CHECK_DATA(msblk->sblk.flags)) {
+		if (*offset == msblk->devblksize) {
+			brelse(bh);
+			if (!(bh = sb_bread(s, ++(*cur_index))))
+				goto out;
+			*offset = 0;
+		}
+		if (*((unsigned char *) (bh->b_data + *offset)) !=
+						SQUASHFS_MARKER_BYTE) {
+			ERROR("Metadata block marker corrupt @ %x\n",
+						*cur_index);
+			brelse(bh);
+			goto out;
+		}
+		(*offset)++;
+	}
+	return bh;
+
+out:
+	return NULL;
+}
+
+
+SQSH_EXTERN unsigned int squashfs_read_data(struct super_block *s, char *buffer,
+			long long index, unsigned int length,
+			long long *next_index, int srclength)
+{
+	struct squashfs_sb_info *msblk = s->s_fs_info;
+	struct squashfs_super_block *sblk = &msblk->sblk;
+	struct buffer_head *bh[((SQUASHFS_FILE_MAX_SIZE - 1) >>
+			msblk->devblksize_log2) + 2];
+	unsigned int offset = index & ((1 << msblk->devblksize_log2) - 1);
+	unsigned int cur_index = index >> msblk->devblksize_log2;
+	int bytes, avail_bytes, b = 0, k = 0;
+	unsigned int compressed;
+	unsigned int c_byte = length;
+
+	if (c_byte) {
+		bytes = msblk->devblksize - offset;
+		compressed = SQUASHFS_COMPRESSED_BLOCK(c_byte);
+		c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte);
+
+		TRACE("Block @ 0x%llx, %scompressed size %d, src size %d\n", index, compressed
+					? "" : "un", (unsigned int) c_byte, srclength);
+
+		if (c_byte > srclength || index < 0 || (index + c_byte) > sblk->bytes_used)
+			goto read_failure;
+
+		if (!(bh[0] = sb_getblk(s, cur_index)))
+			goto block_release;
+
+		for (b = 1; bytes < c_byte; b++) {
+			if (!(bh[b] = sb_getblk(s, ++cur_index)))
+				goto block_release;
+			bytes += msblk->devblksize;
+		}
+		ll_rw_block(READ, b, bh);
+	} else {
+		if (index < 0 || (index + 2) > sblk->bytes_used)
+			goto read_failure;
+
+		if (!(bh[0] = get_block_length(s, &cur_index, &offset,
+								&c_byte)))
+			goto read_failure;
+
+		bytes = msblk->devblksize - offset;
+		compressed = SQUASHFS_COMPRESSED(c_byte);
+		c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
+
+		TRACE("Block @ 0x%llx, %scompressed size %d\n", index, compressed
+					? "" : "un", (unsigned int) c_byte);
+
+		if (c_byte > srclength || (index + c_byte) > sblk->bytes_used)
+			goto read_failure;
+
+		for (b = 1; bytes < c_byte; b++) {
+			if (!(bh[b] = sb_getblk(s, ++cur_index)))
+				goto block_release;
+			bytes += msblk->devblksize;
+		}
+		ll_rw_block(READ, b - 1, bh + 1);
+	}
+
+	if (compressed) {
+		int zlib_err = Z_STREAM_END;
+		int rest, start;
+		enum {Src, Dst};
+		struct sized_buf sbuf[2];
+		struct sqlzma *percpu;
+
+		/*
+	 	* uncompress block
+	 	*/
+		for (k = 0; k < b; k++) {
+			wait_on_buffer(bh[k]);
+			if (!buffer_uptodate(bh[k]))
+				goto block_release;
+		}
+
+		avail_bytes = 0;
+		for (k = 0; !avail_bytes && k < b; k++) {
+			avail_bytes = msblk->devblksize - offset;
+			if (c_byte < avail_bytes)
+				avail_bytes = c_byte;
+			if (avail_bytes)
+				break;
+			offset = 0;
+			brelse(bh[k]);
+		}
+		bytes = 0;
+		if (!avail_bytes)
+			goto block_release; // nothing to be process
+
+		start = k;
+		/* it disables preemption */
+		percpu = get_cpu_var(sqlzma);
+#ifdef KeepPreemptive
+		put_cpu_var(sqlzma);
+		mutex_lock(&percpu->mtx);
+#endif
+
+		for (; k < b; k++) {
+			memcpy(percpu->read_data + bytes, bh[k]->b_data + offset,
+			       avail_bytes);
+			bytes += avail_bytes;
+			offset = 0;
+			brelse(bh[k]);
+			avail_bytes = msblk->devblksize - offset;
+			rest = c_byte - bytes;
+			if (rest < avail_bytes)
+				avail_bytes = rest;
+		}
+
+		sbuf[Src].buf = percpu->read_data;
+		sbuf[Src].sz = bytes;
+		sbuf[Dst].buf = buffer;
+		sbuf[Dst].sz = srclength;
+		dpri_un(&percpu->un);
+		dpri("src %d %p, dst %d %p\n", sbuf[Src].sz, sbuf[Src].buf,
+		     sbuf[Dst].sz, sbuf[Dst].buf);
+		zlib_err = sqlzma_un(&percpu->un, sbuf + Src, sbuf + Dst);
+		bytes = percpu->un.un_reslen;
+
+#ifdef KeepPreemptive
+		mutex_unlock(&percpu->mtx);
+#else
+		put_cpu_var(sqlzma);
+#endif
+		if (unlikely(zlib_err)) {
+			dpri("zlib_err %d\n", zlib_err);
+			goto release_mutex;
+		}
+	} else {
+		int i;
+
+		for(i = 0; i < b; i++) {
+			wait_on_buffer(bh[i]);
+			if(!buffer_uptodate(bh[i]))
+				goto block_release;
+		}
+
+		for (bytes = 0; k < b; k++) {
+			avail_bytes = (c_byte - bytes) > (msblk->devblksize - offset) ?
+					msblk->devblksize - offset :
+					c_byte - bytes;
+			memcpy(buffer + bytes, bh[k]->b_data + offset, avail_bytes);
+			bytes += avail_bytes;
+			offset = 0;
+			brelse(bh[k]);
+		}
+	}
+
+	if (next_index)
+		*next_index = index + c_byte + (length ? 0 :
+				(SQUASHFS_CHECK_DATA(msblk->sblk.flags)
+				 ? 3 : 2));
+	return bytes;
+
+release_mutex:
+	//mutex_unlock(&msblk->read_data_mutex);
+
+block_release:
+	for (; k < b; k++)
+		brelse(bh[k]);
+
+read_failure:
+	ERROR("sb_bread failed reading block 0x%x\n", cur_index);
+	return 0;
+}
+
+
+SQSH_EXTERN int squashfs_get_cached_block(struct super_block *s, char *buffer,
+				long long block, unsigned int offset,
+				int length, long long *next_block,
+				unsigned int *next_offset)
+{
+	struct squashfs_sb_info *msblk = s->s_fs_info;
+	int n, i, bytes, return_length = length;
+	long long next_index;
+
+	TRACE("Entered squashfs_get_cached_block [%llx:%x]\n", block, offset);
+
+	while ( 1 ) {
+		for (i = 0; i < SQUASHFS_CACHED_BLKS; i++) 
+			if (msblk->block_cache[i].block == block)
+				break; 
+		
+		mutex_lock(&msblk->block_cache_mutex);
+
+		if (i == SQUASHFS_CACHED_BLKS) {
+			/* read inode header block */
+			for (i = msblk->next_cache, n = SQUASHFS_CACHED_BLKS;
+					n ; n --, i = (i + 1) %
+					SQUASHFS_CACHED_BLKS)
+				if (msblk->block_cache[i].block !=
+							SQUASHFS_USED_BLK)
+					break;
+
+			if (n == 0) {
+				wait_queue_t wait;
+
+				init_waitqueue_entry(&wait, current);
+				add_wait_queue(&msblk->waitq, &wait);
+				set_current_state(TASK_UNINTERRUPTIBLE);
+ 				mutex_unlock(&msblk->block_cache_mutex);
+				schedule();
+				set_current_state(TASK_RUNNING);
+				remove_wait_queue(&msblk->waitq, &wait);
+				continue;
+			}
+			msblk->next_cache = (i + 1) % SQUASHFS_CACHED_BLKS;
+
+			if (msblk->block_cache[i].block ==
+							SQUASHFS_INVALID_BLK) {
+				if (!(msblk->block_cache[i].data =
+						kmalloc(SQUASHFS_METADATA_SIZE,
+						GFP_KERNEL))) {
+					ERROR("Failed to allocate cache"
+							"block\n");
+					mutex_unlock(&msblk->block_cache_mutex);
+					goto out;
+				}
+			}
+	
+			msblk->block_cache[i].block = SQUASHFS_USED_BLK;
+			mutex_unlock(&msblk->block_cache_mutex);
+
+			msblk->block_cache[i].length = squashfs_read_data(s,
+				msblk->block_cache[i].data, block, 0, &next_index, SQUASHFS_METADATA_SIZE);
+			if (msblk->block_cache[i].length == 0) {
+				ERROR("Unable to read cache block [%llx:%x]\n",
+						block, offset);
+				mutex_lock(&msblk->block_cache_mutex);
+				msblk->block_cache[i].block = SQUASHFS_INVALID_BLK;
+				kfree(msblk->block_cache[i].data);
+				wake_up(&msblk->waitq);
+				mutex_unlock(&msblk->block_cache_mutex);
+				goto out;
+			}
+
+			mutex_lock(&msblk->block_cache_mutex);
+			wake_up(&msblk->waitq);
+			msblk->block_cache[i].block = block;
+			msblk->block_cache[i].next_index = next_index;
+			TRACE("Read cache block [%llx:%x]\n", block, offset);
+		}
+
+		if (msblk->block_cache[i].block != block) {
+			mutex_unlock(&msblk->block_cache_mutex);
+			continue;
+		}
+
+		bytes = msblk->block_cache[i].length - offset;
+
+		if (bytes < 1) {
+			mutex_unlock(&msblk->block_cache_mutex);
+			goto out;
+		} else if (bytes >= length) {
+			if (buffer)
+				memcpy(buffer, msblk->block_cache[i].data +
+						offset, length);
+			if (msblk->block_cache[i].length - offset == length) {
+				*next_block = msblk->block_cache[i].next_index;
+				*next_offset = 0;
+			} else {
+				*next_block = block;
+				*next_offset = offset + length;
+			}
+			mutex_unlock(&msblk->block_cache_mutex);
+			goto finish;
+		} else {
+			if (buffer) {
+				memcpy(buffer, msblk->block_cache[i].data +
+						offset, bytes);
+				buffer += bytes;
+			}
+			block = msblk->block_cache[i].next_index;
+			mutex_unlock(&msblk->block_cache_mutex);
+			length -= bytes;
+			offset = 0;
+		}
+	}
+
+finish:
+	return return_length;
+out:
+	return 0;
+}
+
+
+static int get_fragment_location(struct super_block *s, unsigned int fragment,
+				long long *fragment_start_block,
+				unsigned int *fragment_size)
+{
+	struct squashfs_sb_info *msblk = s->s_fs_info;
+	long long start_block =
+		msblk->fragment_index[SQUASHFS_FRAGMENT_INDEX(fragment)];
+	int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment);
+	struct squashfs_fragment_entry fragment_entry;
+
+	if (msblk->swap) {
+		struct squashfs_fragment_entry sfragment_entry;
+
+		if (!squashfs_get_cached_block(s, (char *) &sfragment_entry,
+					start_block, offset,
+					sizeof(sfragment_entry), &start_block,
+					&offset))
+			goto out;
+		SQUASHFS_SWAP_FRAGMENT_ENTRY(&fragment_entry, &sfragment_entry);
+	} else
+		if (!squashfs_get_cached_block(s, (char *) &fragment_entry,
+					start_block, offset,
+					sizeof(fragment_entry), &start_block,
+					&offset))
+			goto out;
+
+	*fragment_start_block = fragment_entry.start_block;
+	*fragment_size = fragment_entry.size;
+
+	return 1;
+
+out:
+	return 0;
+}
+
+
+SQSH_EXTERN void release_cached_fragment(struct squashfs_sb_info *msblk, struct
+					squashfs_fragment_cache *fragment)
+{
+	mutex_lock(&msblk->fragment_mutex);
+	fragment->locked --;
+	wake_up(&msblk->fragment_wait_queue);
+	mutex_unlock(&msblk->fragment_mutex);
+}
+
+
+SQSH_EXTERN struct squashfs_fragment_cache *get_cached_fragment(struct super_block
+					*s, long long start_block,
+					int length)
+{
+	int i, n;
+	struct squashfs_sb_info *msblk = s->s_fs_info;
+	struct squashfs_super_block *sblk = &msblk->sblk;
+
+	while ( 1 ) {
+		mutex_lock(&msblk->fragment_mutex);
+
+		for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS &&
+				msblk->fragment[i].block != start_block; i++);
+
+		if (i == SQUASHFS_CACHED_FRAGMENTS) {
+			for (i = msblk->next_fragment, n =
+				SQUASHFS_CACHED_FRAGMENTS; n &&
+				msblk->fragment[i].locked; n--, i = (i + 1) %
+				SQUASHFS_CACHED_FRAGMENTS);
+
+			if (n == 0) {
+				wait_queue_t wait;
+
+				init_waitqueue_entry(&wait, current);
+				add_wait_queue(&msblk->fragment_wait_queue,
+									&wait);
+				set_current_state(TASK_UNINTERRUPTIBLE);
+				mutex_unlock(&msblk->fragment_mutex);
+				schedule();
+				set_current_state(TASK_RUNNING);
+				remove_wait_queue(&msblk->fragment_wait_queue,
+									&wait);
+				continue;
+			}
+			msblk->next_fragment = (msblk->next_fragment + 1) %
+				SQUASHFS_CACHED_FRAGMENTS;
+			
+			if (msblk->fragment[i].data == NULL)
+				if (!(msblk->fragment[i].data = SQUASHFS_ALLOC
+						(SQUASHFS_FILE_MAX_SIZE))) {
+					ERROR("Failed to allocate fragment "
+							"cache block\n");
+					mutex_unlock(&msblk->fragment_mutex);
+					goto out;
+				}
+
+			msblk->fragment[i].block = SQUASHFS_INVALID_BLK;
+			msblk->fragment[i].locked = 1;
+			mutex_unlock(&msblk->fragment_mutex);
+
+			if (!(msblk->fragment[i].length = squashfs_read_data(s,
+						msblk->fragment[i].data,
+						start_block, length, NULL, sblk->block_size))) {
+				ERROR("Unable to read fragment cache block "
+							"[%llx]\n", start_block);
+				msblk->fragment[i].locked = 0;
+				smp_mb();
+				goto out;
+			}
+
+			mutex_lock(&msblk->fragment_mutex);
+			msblk->fragment[i].block = start_block;
+			TRACE("New fragment %d, start block %lld, locked %d\n",
+						i, msblk->fragment[i].block,
+						msblk->fragment[i].locked);
+			mutex_unlock(&msblk->fragment_mutex);
+			break;
+		}
+
+		msblk->fragment[i].locked++;
+		mutex_unlock(&msblk->fragment_mutex);
+		TRACE("Got fragment %d, start block %lld, locked %d\n", i,
+						msblk->fragment[i].block,
+						msblk->fragment[i].locked);
+		break;
+	}
+
+	return &msblk->fragment[i];
+
+out:
+	return NULL;
+}
+
+
+static void squashfs_new_inode(struct squashfs_sb_info *msblk, struct inode *i,
+		struct squashfs_base_inode_header *inodeb)
+{
+	i->i_ino = inodeb->inode_number;
+	i->i_mtime.tv_sec = inodeb->mtime;
+	i->i_atime.tv_sec = inodeb->mtime;
+	i->i_ctime.tv_sec = inodeb->mtime;
+	i->i_uid = msblk->uid[inodeb->uid];
+	i->i_mode = inodeb->mode;
+	i->i_size = 0;
+	if (inodeb->guid == SQUASHFS_GUIDS)
+		i->i_gid = i->i_uid;
+	else
+		i->i_gid = msblk->guid[inodeb->guid];
+}
+
+
+static squashfs_inode_t squashfs_inode_lookup(struct super_block *s, int ino)
+{
+	struct squashfs_sb_info *msblk = s->s_fs_info;
+	long long start = msblk->inode_lookup_table[SQUASHFS_LOOKUP_BLOCK(ino - 1)];
+	int offset = SQUASHFS_LOOKUP_BLOCK_OFFSET(ino - 1);
+	squashfs_inode_t inode;
+
+	TRACE("Entered squashfs_inode_lookup, inode_number = %d\n", ino);
+
+	if (msblk->swap) {
+		squashfs_inode_t sinode;
+
+		if (!squashfs_get_cached_block(s, (char *) &sinode, start, offset,
+					sizeof(sinode), &start, &offset))
+			goto out;
+		SQUASHFS_SWAP_INODE_T((&inode), &sinode);
+	} else if (!squashfs_get_cached_block(s, (char *) &inode, start, offset,
+					sizeof(inode), &start, &offset))
+			goto out;
+
+	TRACE("squashfs_inode_lookup, inode = 0x%llx\n", inode);
+
+	return inode;
+
+out:
+	return SQUASHFS_INVALID_BLK;
+}
+	
+
+static void vfs_read_inode(struct inode *i)
+{
+	struct squashfs_sb_info *msblk = i->i_sb->s_fs_info;
+	squashfs_inode_t inode = squashfs_inode_lookup(i->i_sb, i->i_ino);
+
+	TRACE("Entered vfs_read_inode\n");
+
+	if(inode != SQUASHFS_INVALID_BLK)
+		(msblk->read_inode)(i, inode);
+}
+
+
+static struct dentry *squashfs_get_parent(struct dentry *child)
+{
+	struct inode *i = child->d_inode;
+	struct inode *parent = iget(i->i_sb, SQUASHFS_I(i)->u.s2.parent_inode);
+	struct dentry *rv;
+
+	TRACE("Entered squashfs_get_parent\n");
+
+	if(parent == NULL) {
+		rv = ERR_PTR(-EACCES);
+		goto out;
+	}
+
+	rv = d_alloc_anon(parent);
+	if(rv == NULL)
+		rv = ERR_PTR(-ENOMEM);
+
+out:
+	return rv;
+}
+
+	
+SQSH_EXTERN struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode, unsigned int inode_number)
+{
+	struct squashfs_sb_info *msblk = s->s_fs_info;
+	struct inode *i = iget_locked(s, inode_number);
+
+	TRACE("Entered squashfs_iget\n");
+
+	if(i && (i->i_state & I_NEW)) {
+		(msblk->read_inode)(i, inode);
+		unlock_new_inode(i);
+	}
+
+	return i;
+}
+
+
+static int squashfs_read_inode(struct inode *i, squashfs_inode_t inode)
+{
+	struct super_block *s = i->i_sb;
+	struct squashfs_sb_info *msblk = s->s_fs_info;
+	struct squashfs_super_block *sblk = &msblk->sblk;
+	long long block = SQUASHFS_INODE_BLK(inode) +
+		sblk->inode_table_start;
+	unsigned int offset = SQUASHFS_INODE_OFFSET(inode);
+	long long next_block;
+	unsigned int next_offset;
+	union squashfs_inode_header id, sid;
+	struct squashfs_base_inode_header *inodeb = &id.base,
+					  *sinodeb = &sid.base;
+
+	TRACE("Entered squashfs_read_inode\n");
+
+	if (msblk->swap) {
+		if (!squashfs_get_cached_block(s, (char *) sinodeb, block,
+					offset, sizeof(*sinodeb), &next_block,
+					&next_offset))
+			goto failed_read;
+		SQUASHFS_SWAP_BASE_INODE_HEADER(inodeb, sinodeb,
+					sizeof(*sinodeb));
+	} else
+		if (!squashfs_get_cached_block(s, (char *) inodeb, block,
+					offset, sizeof(*inodeb), &next_block,
+					&next_offset))
+			goto failed_read;
+
+	squashfs_new_inode(msblk, i, inodeb);
+
+	switch(inodeb->inode_type) {
+		case SQUASHFS_FILE_TYPE: {
+			unsigned int frag_size;
+			long long frag_blk;
+			struct squashfs_reg_inode_header *inodep = &id.reg;
+			struct squashfs_reg_inode_header *sinodep = &sid.reg;
+				
+			if (msblk->swap) {
+				if (!squashfs_get_cached_block(s, (char *)
+						sinodep, block, offset,
+						sizeof(*sinodep), &next_block,
+						&next_offset))
+					goto failed_read;
+				SQUASHFS_SWAP_REG_INODE_HEADER(inodep, sinodep);
+			} else
+				if (!squashfs_get_cached_block(s, (char *)
+						inodep, block, offset,
+						sizeof(*inodep), &next_block,
+						&next_offset))
+					goto failed_read;
+
+			frag_blk = SQUASHFS_INVALID_BLK;
+			if (inodep->fragment != SQUASHFS_INVALID_FRAG &&
+					!get_fragment_location(s,
+					inodep->fragment, &frag_blk, &frag_size))
+				goto failed_read;
+				
+			i->i_nlink = 1;
+			i->i_size = inodep->file_size;
+			i->i_fop = &generic_ro_fops;
+			i->i_mode |= S_IFREG;
+			i->i_blocks = ((i->i_size - 1) >> 9) + 1;
+			SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;
+			SQUASHFS_I(i)->u.s1.fragment_size = frag_size;
+			SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;
+			SQUASHFS_I(i)->start_block = inodep->start_block;
+			SQUASHFS_I(i)->u.s1.block_list_start = next_block;
+			SQUASHFS_I(i)->offset = next_offset;
+			if (sblk->block_size > 4096)
+				i->i_data.a_ops = &squashfs_aops;
+			else
+				i->i_data.a_ops = &squashfs_aops_4K;
+
+			TRACE("File inode %x:%x, start_block %llx, "
+					"block_list_start %llx, offset %x\n",
+					SQUASHFS_INODE_BLK(inode), offset,
+					inodep->start_block, next_block,
+					next_offset);
+			break;
+		}
+		case SQUASHFS_LREG_TYPE: {
+			unsigned int frag_size;
+			long long frag_blk;
+			struct squashfs_lreg_inode_header *inodep = &id.lreg;
+			struct squashfs_lreg_inode_header *sinodep = &sid.lreg;
+				
+			if (msblk->swap) {
+				if (!squashfs_get_cached_block(s, (char *)
+						sinodep, block, offset,
+						sizeof(*sinodep), &next_block,
+						&next_offset))
+					goto failed_read;
+				SQUASHFS_SWAP_LREG_INODE_HEADER(inodep, sinodep);
+			} else
+				if (!squashfs_get_cached_block(s, (char *)
+						inodep, block, offset,
+						sizeof(*inodep), &next_block,
+						&next_offset))
+					goto failed_read;
+
+			frag_blk = SQUASHFS_INVALID_BLK;
+			if (inodep->fragment != SQUASHFS_INVALID_FRAG &&
+					!get_fragment_location(s,
+					inodep->fragment, &frag_blk, &frag_size))
+				goto failed_read;
+				
+			i->i_nlink = inodep->nlink;
+			i->i_size = inodep->file_size;
+			i->i_fop = &generic_ro_fops;
+			i->i_mode |= S_IFREG;
+			i->i_blocks = ((i->i_size - 1) >> 9) + 1;
+			SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;
+			SQUASHFS_I(i)->u.s1.fragment_size = frag_size;
+			SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;
+			SQUASHFS_I(i)->start_block = inodep->start_block;
+			SQUASHFS_I(i)->u.s1.block_list_start = next_block;
+			SQUASHFS_I(i)->offset = next_offset;
+			if (sblk->block_size > 4096)
+				i->i_data.a_ops = &squashfs_aops;
+			else
+				i->i_data.a_ops = &squashfs_aops_4K;
+
+			TRACE("File inode %x:%x, start_block %llx, "
+					"block_list_start %llx, offset %x\n",
+					SQUASHFS_INODE_BLK(inode), offset,
+					inodep->start_block, next_block,
+					next_offset);
+			break;
+		}
+		case SQUASHFS_DIR_TYPE: {
+			struct squashfs_dir_inode_header *inodep = &id.dir;
+			struct squashfs_dir_inode_header *sinodep = &sid.dir;
+
+			if (msblk->swap) {
+				if (!squashfs_get_cached_block(s, (char *)
+						sinodep, block, offset,
+						sizeof(*sinodep), &next_block,
+						&next_offset))
+					goto failed_read;
+				SQUASHFS_SWAP_DIR_INODE_HEADER(inodep, sinodep);
+			} else
+				if (!squashfs_get_cached_block(s, (char *)
+						inodep, block, offset,
+						sizeof(*inodep), &next_block,
+						&next_offset))
+					goto failed_read;
+
+			i->i_nlink = inodep->nlink;
+			i->i_size = inodep->file_size;
+			i->i_op = &squashfs_dir_inode_ops;
+			i->i_fop = &squashfs_dir_ops;
+			i->i_mode |= S_IFDIR;
+			SQUASHFS_I(i)->start_block = inodep->start_block;
+			SQUASHFS_I(i)->offset = inodep->offset;
+			SQUASHFS_I(i)->u.s2.directory_index_count = 0;
+			SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode;
+
+			TRACE("Directory inode %x:%x, start_block %x, offset "
+					"%x\n", SQUASHFS_INODE_BLK(inode),
+					offset, inodep->start_block,
+					inodep->offset);
+			break;
+		}
+		case SQUASHFS_LDIR_TYPE: {
+			struct squashfs_ldir_inode_header *inodep = &id.ldir;
+			struct squashfs_ldir_inode_header *sinodep = &sid.ldir;
+
+			if (msblk->swap) {
+				if (!squashfs_get_cached_block(s, (char *)
+						sinodep, block, offset,
+						sizeof(*sinodep), &next_block,
+						&next_offset))
+					goto failed_read;
+				SQUASHFS_SWAP_LDIR_INODE_HEADER(inodep,
+						sinodep);
+			} else
+				if (!squashfs_get_cached_block(s, (char *)
+						inodep, block, offset,
+						sizeof(*inodep), &next_block,
+						&next_offset))
+					goto failed_read;
+
+			i->i_nlink = inodep->nlink;
+			i->i_size = inodep->file_size;
+			i->i_op = &squashfs_dir_inode_ops;
+			i->i_fop = &squashfs_dir_ops;
+			i->i_mode |= S_IFDIR;
+			SQUASHFS_I(i)->start_block = inodep->start_block;
+			SQUASHFS_I(i)->offset = inodep->offset;
+			SQUASHFS_I(i)->u.s2.directory_index_start = next_block;
+			SQUASHFS_I(i)->u.s2.directory_index_offset =
+								next_offset;
+			SQUASHFS_I(i)->u.s2.directory_index_count =
+								inodep->i_count;
+			SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode;
+
+			TRACE("Long directory inode %x:%x, start_block %x, "
+					"offset %x\n",
+					SQUASHFS_INODE_BLK(inode), offset,
+					inodep->start_block, inodep->offset);
+			break;
+		}
+		case SQUASHFS_SYMLINK_TYPE: {
+			struct squashfs_symlink_inode_header *inodep =
+								&id.symlink;
+			struct squashfs_symlink_inode_header *sinodep =
+								&sid.symlink;
+	
+			if (msblk->swap) {
+				if (!squashfs_get_cached_block(s, (char *)
+						sinodep, block, offset,
+						sizeof(*sinodep), &next_block,
+						&next_offset))
+					goto failed_read;
+				SQUASHFS_SWAP_SYMLINK_INODE_HEADER(inodep,
+								sinodep);
+			} else
+				if (!squashfs_get_cached_block(s, (char *)
+						inodep, block, offset,
+						sizeof(*inodep), &next_block,
+						&next_offset))
+					goto failed_read;
+
+			i->i_nlink = inodep->nlink;
+			i->i_size = inodep->symlink_size;
+			i->i_op = &page_symlink_inode_operations;
+			i->i_data.a_ops = &squashfs_symlink_aops;
+			i->i_mode |= S_IFLNK;
+			SQUASHFS_I(i)->start_block = next_block;
+			SQUASHFS_I(i)->offset = next_offset;
+
+			TRACE("Symbolic link inode %x:%x, start_block %llx, "
+					"offset %x\n",
+					SQUASHFS_INODE_BLK(inode), offset,
+					next_block, next_offset);
+			break;
+		 }
+		 case SQUASHFS_BLKDEV_TYPE:
+		 case SQUASHFS_CHRDEV_TYPE: {
+			struct squashfs_dev_inode_header *inodep = &id.dev;
+			struct squashfs_dev_inode_header *sinodep = &sid.dev;
+
+			if (msblk->swap) {
+				if (!squashfs_get_cached_block(s, (char *)
+						sinodep, block, offset,
+						sizeof(*sinodep), &next_block,
+						&next_offset))
+					goto failed_read;
+				SQUASHFS_SWAP_DEV_INODE_HEADER(inodep, sinodep);
+			} else	
+				if (!squashfs_get_cached_block(s, (char *)
+						inodep, block, offset,
+						sizeof(*inodep), &next_block,
+						&next_offset))
+					goto failed_read;
+
+			i->i_nlink = inodep->nlink;
+			i->i_mode |= (inodeb->inode_type ==
+					SQUASHFS_CHRDEV_TYPE) ?  S_IFCHR :
+					S_IFBLK;
+			init_special_inode(i, i->i_mode,
+					old_decode_dev(inodep->rdev));
+
+			TRACE("Device inode %x:%x, rdev %x\n",
+					SQUASHFS_INODE_BLK(inode), offset,
+					inodep->rdev);
+			break;
+		 }
+		 case SQUASHFS_FIFO_TYPE:
+		 case SQUASHFS_SOCKET_TYPE: {
+			struct squashfs_ipc_inode_header *inodep = &id.ipc;
+			struct squashfs_ipc_inode_header *sinodep = &sid.ipc;
+
+			if (msblk->swap) {
+				if (!squashfs_get_cached_block(s, (char *)
+						sinodep, block, offset,
+						sizeof(*sinodep), &next_block,
+						&next_offset))
+					goto failed_read;
+				SQUASHFS_SWAP_IPC_INODE_HEADER(inodep, sinodep);
+			} else	
+				if (!squashfs_get_cached_block(s, (char *)
+						inodep, block, offset,
+						sizeof(*inodep), &next_block,
+						&next_offset))
+					goto failed_read;
+
+			i->i_nlink = inodep->nlink;
+			i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE)
+							? S_IFIFO : S_IFSOCK;
+			init_special_inode(i, i->i_mode, 0);
+			break;
+		 }
+		 default:
+			ERROR("Unknown inode type %d in squashfs_iget!\n",
+					inodeb->inode_type);
+			goto failed_read1;
+	}
+	
+	return 1;
+
+failed_read:
+	ERROR("Unable to read inode [%llx:%x]\n", block, offset);
+
+failed_read1:
+	make_bad_inode(i);
+	return 0;
+}
+
+
+static int read_inode_lookup_table(struct super_block *s)
+{
+	struct squashfs_sb_info *msblk = s->s_fs_info;
+	struct squashfs_super_block *sblk = &msblk->sblk;
+	unsigned int length = SQUASHFS_LOOKUP_BLOCK_BYTES(sblk->inodes);
+
+	TRACE("In read_inode_lookup_table, length %d\n", length);
+
+	/* Allocate inode lookup table */
+	if (!(msblk->inode_lookup_table = kmalloc(length, GFP_KERNEL))) {
+		ERROR("Failed to allocate inode lookup table\n");
+		return 0;
+	}
+   
+	if (!squashfs_read_data(s, (char *) msblk->inode_lookup_table,
+			sblk->lookup_table_start, length |
+			SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, length)) {
+		ERROR("unable to read inode lookup table\n");
+		return 0;
+	}
+
+	if (msblk->swap) {
+		int i;
+		long long block;
+
+		for (i = 0; i < SQUASHFS_LOOKUP_BLOCKS(sblk->inodes); i++) {
+			SQUASHFS_SWAP_LOOKUP_BLOCKS((&block),
+						&msblk->inode_lookup_table[i], 1);
+			msblk->inode_lookup_table[i] = block;
+		}
+	}
+
+	return 1;
+}
+
+
+static int read_fragment_index_table(struct super_block *s)
+{
+	struct squashfs_sb_info *msblk = s->s_fs_info;
+	struct squashfs_super_block *sblk = &msblk->sblk;
+	unsigned int length = SQUASHFS_FRAGMENT_INDEX_BYTES(sblk->fragments);
+
+	if(length == 0)
+		return 1;
+
+	/* Allocate fragment index table */
+	if (!(msblk->fragment_index = kmalloc(length, GFP_KERNEL))) {
+		ERROR("Failed to allocate fragment index table\n");
+		return 0;
+	}
+   
+	if (!squashfs_read_data(s, (char *) msblk->fragment_index,
+			sblk->fragment_table_start, length |
+			SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, length)) {
+		ERROR("unable to read fragment index table\n");
+		return 0;
+	}
+
+	if (msblk->swap) {
+		int i;
+		long long fragment;
+
+		for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES(sblk->fragments); i++) {
+			SQUASHFS_SWAP_FRAGMENT_INDEXES((&fragment),
+						&msblk->fragment_index[i], 1);
+			msblk->fragment_index[i] = fragment;
+		}
+	}
+
+	return 1;
+}
+
+
+static int supported_squashfs_filesystem(struct squashfs_sb_info *msblk, int silent)
+{
+	struct squashfs_super_block *sblk = &msblk->sblk;
+
+	msblk->read_inode = squashfs_read_inode;
+	msblk->read_blocklist = read_blocklist;
+	msblk->read_fragment_index_table = read_fragment_index_table;
+
+	if (sblk->s_major == 1) {
+		if (!squashfs_1_0_supported(msblk)) {
+			SERROR("Major/Minor mismatch, Squashfs 1.0 filesystems "
+				"are unsupported\n");
+			SERROR("Please recompile with "
+				"Squashfs 1.0 support enabled\n");
+			return 0;
+		}
+	} else if (sblk->s_major == 2) {
+		if (!squashfs_2_0_supported(msblk)) {
+			SERROR("Major/Minor mismatch, Squashfs 2.0 filesystems "
+				"are unsupported\n");
+			SERROR("Please recompile with "
+				"Squashfs 2.0 support enabled\n");
+			return 0;
+		}
+	} else if(sblk->s_major != SQUASHFS_MAJOR || sblk->s_minor >
+			SQUASHFS_MINOR) {
+		SERROR("Major/Minor mismatch, trying to mount newer %d.%d "
+				"filesystem\n", sblk->s_major, sblk->s_minor);
+		SERROR("Please update your kernel\n");
+		return 0;
+	}
+
+	return 1;
+}
+
+
+static int squashfs_fill_super(struct super_block *s, void *data, int silent)
+{
+	struct squashfs_sb_info *msblk;
+	struct squashfs_super_block *sblk;
+	int i, err;
+	char b[BDEVNAME_SIZE];
+	struct inode *root;
+	void *label;
+
+	TRACE("Entered squashfs_read_superblock\n");
+
+	err = -ENOMEM;
+	if (!(s->s_fs_info = kmalloc(sizeof(struct squashfs_sb_info),
+						GFP_KERNEL))) {
+		ERROR("Failed to allocate superblock\n");
+		goto failure;
+	}
+	label = &&out_fsinfo;
+	memset(s->s_fs_info, 0, sizeof(struct squashfs_sb_info));
+	msblk = s->s_fs_info;
+	sblk = &msblk->sblk;
+	
+	msblk->devblksize = sb_min_blocksize(s, BLOCK_SIZE);
+	msblk->devblksize_log2 = ffz(~msblk->devblksize);
+
+	//mutex_init(&msblk->read_data_mutex);
+	mutex_init(&msblk->read_page_mutex);
+	mutex_init(&msblk->block_cache_mutex);
+	mutex_init(&msblk->fragment_mutex);
+	mutex_init(&msblk->meta_index_mutex);
+	
+	init_waitqueue_head(&msblk->waitq);
+	init_waitqueue_head(&msblk->fragment_wait_queue);
+
+	err = -EINVAL;
+	sblk->bytes_used = sizeof(struct squashfs_super_block);
+	if (!squashfs_read_data(s, (char *) sblk, SQUASHFS_START,
+					sizeof(struct squashfs_super_block) |
+					SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, sizeof(struct squashfs_super_block))) {
+		SERROR("unable to read superblock\n");
+		goto *label;
+	}
+
+	/* Check it is a SQUASHFS superblock */
+	s->s_magic = sblk->s_magic;
+	msblk->swap = 0;
+	dpri("magic 0x%x\n", sblk->s_magic);
+	switch (sblk->s_magic) {
+		struct squashfs_super_block ssblk;
+
+	case SQUASHFS_MAGIC_SWAP:
+		/*FALLTHROUGH*/
+	case SQUASHFS_MAGIC_LZMA_SWAP:
+		WARNING("Mounting a different endian SQUASHFS "
+			"filesystem on %s\n", bdevname(s->s_bdev, b));
+
+		SQUASHFS_SWAP_SUPER_BLOCK(&ssblk, sblk);
+		memcpy(sblk, &ssblk, sizeof(struct squashfs_super_block));
+		msblk->swap = 1;
+		/*FALLTHROUGH*/
+	case SQUASHFS_MAGIC:
+	case SQUASHFS_MAGIC_LZMA:
+		break;
+	default:
+		SERROR("Can't find a SQUASHFS superblock on %s\n",
+		       bdevname(s->s_bdev, b));
+		goto *label;
+	}
+
+	{
+		struct sqlzma *p;
+		dpri("block_size %d\n", sblk->block_size);
+		BUG_ON(sblk->block_size > sizeof(p->read_data));
+	}
+
+	/* Check the MAJOR & MINOR versions */
+	err = -EINVAL;
+	if(!supported_squashfs_filesystem(msblk, silent))
+		goto *label;
+
+	/* Check the filesystem does not extend beyond the end of the
+	   block device */
+	if(sblk->bytes_used < 0 || sblk->bytes_used > i_size_read(s->s_bdev->bd_inode))
+		goto *label;
+
+	/* Check the root inode for sanity */
+	if (SQUASHFS_INODE_OFFSET(sblk->root_inode) > SQUASHFS_METADATA_SIZE)
+		goto *label;
+
+	TRACE("Found valid superblock on %s\n", bdevname(s->s_bdev, b));
+	TRACE("Inodes are %scompressed\n",
+					SQUASHFS_UNCOMPRESSED_INODES
+					(sblk->flags) ? "un" : "");
+	TRACE("Data is %scompressed\n",
+					SQUASHFS_UNCOMPRESSED_DATA(sblk->flags)
+					? "un" : "");
+	TRACE("Check data is %s present in the filesystem\n",
+					SQUASHFS_CHECK_DATA(sblk->flags) ?
+					"" : "not");
+	TRACE("Filesystem size %lld bytes\n", sblk->bytes_used);
+	TRACE("Block size %d\n", sblk->block_size);
+	TRACE("Number of inodes %d\n", sblk->inodes);
+	if (sblk->s_major > 1)
+		TRACE("Number of fragments %d\n", sblk->fragments);
+	TRACE("Number of uids %d\n", sblk->no_uids);
+	TRACE("Number of gids %d\n", sblk->no_guids);
+	TRACE("sblk->inode_table_start %llx\n", sblk->inode_table_start);
+	TRACE("sblk->directory_table_start %llx\n", sblk->directory_table_start);
+	if (sblk->s_major > 1)
+		TRACE("sblk->fragment_table_start %llx\n",
+					sblk->fragment_table_start);
+	TRACE("sblk->uid_start %llx\n", sblk->uid_start);
+
+	s->s_flags |= MS_RDONLY;
+	s->s_op = &squashfs_super_ops;
+
+	/* Init inode_table block pointer array */
+	err = -ENOMEM;
+	if (!(msblk->block_cache = kmalloc(sizeof(struct squashfs_cache) *
+					SQUASHFS_CACHED_BLKS, GFP_KERNEL))) {
+		ERROR("Failed to allocate block cache\n");
+		goto *label;
+	}
+	label = &&out_block_cache;
+
+	for (i = 0; i < SQUASHFS_CACHED_BLKS; i++)
+		msblk->block_cache[i].block = SQUASHFS_INVALID_BLK;
+
+	msblk->next_cache = 0;
+
+	/* Allocate read_page block */
+	if (!(msblk->read_page = kmalloc(sblk->block_size, GFP_KERNEL))) {
+		ERROR("Failed to allocate read_page block\n");
+		goto *label;
+	}
+	label = &&out_read_page;
+
+	/* Allocate uid and gid tables */
+	if (!(msblk->uid = kmalloc((sblk->no_uids + sblk->no_guids) *
+					sizeof(unsigned int), GFP_KERNEL))) {
+		ERROR("Failed to allocate uid/gid table\n");
+		goto *label;
+	}
+	label = &&out_uid;
+	msblk->guid = msblk->uid + sblk->no_uids;
+   
+	dpri("swap %d\n", msblk->swap);
+	err = -EINVAL;
+	if (msblk->swap) {
+		unsigned int suid[sblk->no_uids + sblk->no_guids];
+
+		if (!squashfs_read_data(s, (char *) &suid, sblk->uid_start,
+					((sblk->no_uids + sblk->no_guids) *
+					 sizeof(unsigned int)) |
+					SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, (sblk->no_uids + sblk->no_guids) * sizeof(unsigned int))) {
+			ERROR("unable to read uid/gid table\n");
+			goto *label;
+		}
+
+		SQUASHFS_SWAP_DATA(msblk->uid, suid, (sblk->no_uids +
+			sblk->no_guids), (sizeof(unsigned int) * 8));
+	} else
+		if (!squashfs_read_data(s, (char *) msblk->uid, sblk->uid_start,
+					((sblk->no_uids + sblk->no_guids) *
+					 sizeof(unsigned int)) |
+					SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, (sblk->no_uids + sblk->no_guids) * sizeof(unsigned int))) {
+			ERROR("unable to read uid/gid table\n");
+			goto *label;
+		}
+
+
+	if (sblk->s_major == 1 && squashfs_1_0_supported(msblk))
+		goto allocate_root;
+
+	err = -ENOMEM;
+	if (!(msblk->fragment = kmalloc(sizeof(struct squashfs_fragment_cache) *
+				SQUASHFS_CACHED_FRAGMENTS, GFP_KERNEL))) {
+		ERROR("Failed to allocate fragment block cache\n");
+		goto *label;
+	}
+	label = &&out_fragment;
+
+	for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++) {
+		msblk->fragment[i].locked = 0;
+		msblk->fragment[i].block = SQUASHFS_INVALID_BLK;
+		msblk->fragment[i].data = NULL;
+	}
+
+	msblk->next_fragment = 0;
+
+	/* Allocate and read fragment index table */
+	if (msblk->read_fragment_index_table(s) == 0)
+		goto *label;
+
+	if(sblk->s_major < 3 || sblk->lookup_table_start == SQUASHFS_INVALID_BLK)
+		goto allocate_root;
+
+	/* Allocate and read inode lookup table */
+	if (read_inode_lookup_table(s) == 0)
+		goto failed_mount;
+
+	s->s_op = &squashfs_export_super_ops;
+	s->s_export_op = &squashfs_export_ops;
+
+allocate_root:
+	dpri("alloate_root\n");
+	root = new_inode(s);
+	if ((msblk->read_inode)(root, sblk->root_inode) == 0) {
+		iput(root);
+		goto failed_mount;
+	}
+	insert_inode_hash(root);
+
+	if ((s->s_root = d_alloc_root(root)) == NULL) {
+		ERROR("Root inode create failed\n");
+		iput(root);
+		goto failed_mount;
+	}
+
+	TRACE("Leaving squashfs_read_super\n");
+	return 0;
+
+failed_mount:
+	kfree(msblk->inode_lookup_table);
+	kfree(msblk->fragment_index);
+	kfree(msblk->fragment_index_2);
+ out_fragment:
+	kfree(msblk->fragment);
+ out_uid:
+	kfree(msblk->uid);
+ out_read_page:
+	kfree(msblk->read_page);
+ out_block_cache:
+	kfree(msblk->block_cache);
+ out_fsinfo:
+	kfree(s->s_fs_info);
+	s->s_fs_info = NULL;
+ failure:
+	return err;
+}
+
+
+static int squashfs_statfs(struct dentry *dentry, struct kstatfs *buf)
+{
+	struct squashfs_sb_info *msblk = dentry->d_sb->s_fs_info;
+	struct squashfs_super_block *sblk = &msblk->sblk;
+
+	TRACE("Entered squashfs_statfs\n");
+
+	buf->f_type = sblk->s_magic;
+	buf->f_bsize = sblk->block_size;
+	buf->f_blocks = ((sblk->bytes_used - 1) >> sblk->block_log) + 1;
+	buf->f_bfree = buf->f_bavail = 0;
+	buf->f_files = sblk->inodes;
+	buf->f_ffree = 0;
+	buf->f_namelen = SQUASHFS_NAME_LEN;
+
+	return 0;
+}
+
+
+static int squashfs_symlink_readpage(struct file *file, struct page *page)
+{
+	struct inode *inode = page->mapping->host;
+	int index = page->index << PAGE_CACHE_SHIFT, length, bytes;
+	long long block = SQUASHFS_I(inode)->start_block;
+	int offset = SQUASHFS_I(inode)->offset;
+	void *pageaddr = kmap(page);
+
+	TRACE("Entered squashfs_symlink_readpage, page index %ld, start block "
+				"%llx, offset %x\n", page->index,
+				SQUASHFS_I(inode)->start_block,
+				SQUASHFS_I(inode)->offset);
+
+	for (length = 0; length < index; length += bytes) {
+		if (!(bytes = squashfs_get_cached_block(inode->i_sb, NULL,
+				block, offset, PAGE_CACHE_SIZE, &block,
+				&offset))) {
+			ERROR("Unable to read symbolic link [%llx:%x]\n", block,
+					offset);
+			goto skip_read;
+		}
+	}
+
+	if (length != index) {
+		ERROR("(squashfs_symlink_readpage) length != index\n");
+		bytes = 0;
+		goto skip_read;
+	}
+
+	bytes = (i_size_read(inode) - length) > PAGE_CACHE_SIZE ? PAGE_CACHE_SIZE :
+					i_size_read(inode) - length;
+
+	if (!(bytes = squashfs_get_cached_block(inode->i_sb, pageaddr, block,
+					offset, bytes, &block, &offset)))
+		ERROR("Unable to read symbolic link [%llx:%x]\n", block, offset);
+
+skip_read:
+	memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
+	kunmap(page);
+	flush_dcache_page(page);
+	SetPageUptodate(page);
+	unlock_page(page);
+
+	return 0;
+}
+
+
+struct meta_index *locate_meta_index(struct inode *inode, int index, int offset)
+{
+	struct meta_index *meta = NULL;
+	struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
+	int i;
+
+	mutex_lock(&msblk->meta_index_mutex);
+
+	TRACE("locate_meta_index: index %d, offset %d\n", index, offset);
+
+	if(msblk->meta_index == NULL)
+		goto not_allocated;
+
+	for (i = 0; i < SQUASHFS_META_NUMBER; i ++)
+		if (msblk->meta_index[i].inode_number == inode->i_ino &&
+				msblk->meta_index[i].offset >= offset &&
+				msblk->meta_index[i].offset <= index &&
+				msblk->meta_index[i].locked == 0) {
+			TRACE("locate_meta_index: entry %d, offset %d\n", i,
+					msblk->meta_index[i].offset);
+			meta = &msblk->meta_index[i];
+			offset = meta->offset;
+		}
+
+	if (meta)
+		meta->locked = 1;
+
+not_allocated:
+	mutex_unlock(&msblk->meta_index_mutex);
+
+	return meta;
+}
+
+
+struct meta_index *empty_meta_index(struct inode *inode, int offset, int skip)
+{
+	struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
+	struct meta_index *meta = NULL;
+	int i;
+
+	mutex_lock(&msblk->meta_index_mutex);
+
+	TRACE("empty_meta_index: offset %d, skip %d\n", offset, skip);
+
+	if(msblk->meta_index == NULL) {
+		if (!(msblk->meta_index = kmalloc(sizeof(struct meta_index) *
+					SQUASHFS_META_NUMBER, GFP_KERNEL))) {
+			ERROR("Failed to allocate meta_index\n");
+			goto failed;
+		}
+		for(i = 0; i < SQUASHFS_META_NUMBER; i++) {
+			msblk->meta_index[i].inode_number = 0;
+			msblk->meta_index[i].locked = 0;
+		}
+		msblk->next_meta_index = 0;
+	}
+
+	for(i = SQUASHFS_META_NUMBER; i &&
+			msblk->meta_index[msblk->next_meta_index].locked; i --)
+		msblk->next_meta_index = (msblk->next_meta_index + 1) %
+			SQUASHFS_META_NUMBER;
+
+	if(i == 0) {
+		TRACE("empty_meta_index: failed!\n");
+		goto failed;
+	}
+
+	TRACE("empty_meta_index: returned meta entry %d, %p\n",
+			msblk->next_meta_index,
+			&msblk->meta_index[msblk->next_meta_index]);
+
+	meta = &msblk->meta_index[msblk->next_meta_index];
+	msblk->next_meta_index = (msblk->next_meta_index + 1) %
+			SQUASHFS_META_NUMBER;
+
+	meta->inode_number = inode->i_ino;
+	meta->offset = offset;
+	meta->skip = skip;
+	meta->entries = 0;
+	meta->locked = 1;
+
+failed:
+	mutex_unlock(&msblk->meta_index_mutex);
+	return meta;
+}
+
+
+void release_meta_index(struct inode *inode, struct meta_index *meta)
+{
+	meta->locked = 0;
+	smp_mb();
+}
+
+
+static int read_block_index(struct super_block *s, int blocks, char *block_list,
+		long long *start_block, int *offset)
+{
+	struct squashfs_sb_info *msblk = s->s_fs_info;
+	unsigned int *block_listp;
+	int block = 0;
+	
+	if (msblk->swap) {
+		char sblock_list[blocks << 2];
+
+		if (!squashfs_get_cached_block(s, sblock_list, *start_block,
+				*offset, blocks << 2, start_block, offset)) {
+			ERROR("Unable to read block list [%llx:%x]\n",
+				*start_block, *offset);
+			goto failure;
+		}
+		SQUASHFS_SWAP_INTS(((unsigned int *)block_list),
+				((unsigned int *)sblock_list), blocks);
+	} else
+		if (!squashfs_get_cached_block(s, block_list, *start_block,
+				*offset, blocks << 2, start_block, offset)) {
+			ERROR("Unable to read block list [%llx:%x]\n",
+				*start_block, *offset);
+			goto failure;
+		}
+
+	for (block_listp = (unsigned int *) block_list; blocks;
+				block_listp++, blocks --)
+		block += SQUASHFS_COMPRESSED_SIZE_BLOCK(*block_listp);
+
+	return block;
+
+failure:
+	return -1;
+}
+
+
+#define SIZE 256
+
+static inline int calculate_skip(int blocks) {
+	int skip = (blocks - 1) / ((SQUASHFS_SLOTS * SQUASHFS_META_ENTRIES + 1) * SQUASHFS_META_INDEXES);
+	return skip >= 7 ? 7 : skip + 1;
+}
+
+
+static int get_meta_index(struct inode *inode, int index,
+		long long *index_block, int *index_offset,
+		long long *data_block, char *block_list)
+{
+	struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
+	struct squashfs_super_block *sblk = &msblk->sblk;
+	int skip = calculate_skip(i_size_read(inode) >> sblk->block_log);
+	int offset = 0;
+	struct meta_index *meta;
+	struct meta_entry *meta_entry;
+	long long cur_index_block = SQUASHFS_I(inode)->u.s1.block_list_start;
+	int cur_offset = SQUASHFS_I(inode)->offset;
+	long long cur_data_block = SQUASHFS_I(inode)->start_block;
+	int i;
+ 
+	index /= SQUASHFS_META_INDEXES * skip;
+
+	while ( offset < index ) {
+		meta = locate_meta_index(inode, index, offset + 1);
+
+		if (meta == NULL) {
+			if ((meta = empty_meta_index(inode, offset + 1,
+							skip)) == NULL)
+				goto all_done;
+		} else {
+			if(meta->entries == 0)
+				goto failed;
+			offset = index < meta->offset + meta->entries ? index :
+				meta->offset + meta->entries - 1;
+			meta_entry = &meta->meta_entry[offset - meta->offset];
+			cur_index_block = meta_entry->index_block + sblk->inode_table_start;
+			cur_offset = meta_entry->offset;
+			cur_data_block = meta_entry->data_block;
+			TRACE("get_meta_index: offset %d, meta->offset %d, "
+				"meta->entries %d\n", offset, meta->offset,
+				meta->entries);
+			TRACE("get_meta_index: index_block 0x%llx, offset 0x%x"
+				" data_block 0x%llx\n", cur_index_block,
+				cur_offset, cur_data_block);
+		}
+
+		for (i = meta->offset + meta->entries; i <= index &&
+				i < meta->offset + SQUASHFS_META_ENTRIES; i++) {
+			int blocks = skip * SQUASHFS_META_INDEXES;
+
+			while (blocks) {
+				int block = blocks > (SIZE >> 2) ? (SIZE >> 2) :
+					blocks;
+				int res = read_block_index(inode->i_sb, block,
+					block_list, &cur_index_block,
+					&cur_offset);
+
+				if (res == -1)
+					goto failed;
+
+				cur_data_block += res;
+				blocks -= block;
+			}
+
+			meta_entry = &meta->meta_entry[i - meta->offset];
+			meta_entry->index_block = cur_index_block - sblk->inode_table_start;
+			meta_entry->offset = cur_offset;
+			meta_entry->data_block = cur_data_block;
+			meta->entries ++;
+			offset ++;
+		}
+
+		TRACE("get_meta_index: meta->offset %d, meta->entries %d\n",
+				meta->offset, meta->entries);
+
+		release_meta_index(inode, meta);
+	}
+
+all_done:
+	*index_block = cur_index_block;
+	*index_offset = cur_offset;
+	*data_block = cur_data_block;
+
+	return offset * SQUASHFS_META_INDEXES * skip;
+
+failed:
+	release_meta_index(inode, meta);
+	return -1;
+}
+
+
+static long long read_blocklist(struct inode *inode, int index,
+				int readahead_blks, char *block_list,
+				unsigned short **block_p, unsigned int *bsize)
+{
+	long long block_ptr;
+	int offset;
+	long long block;
+	int res = get_meta_index(inode, index, &block_ptr, &offset, &block,
+		block_list);
+
+	TRACE("read_blocklist: res %d, index %d, block_ptr 0x%llx, offset"
+		       " 0x%x, block 0x%llx\n", res, index, block_ptr, offset,
+		       block);
+
+	if(res == -1)
+		goto failure;
+
+	index -= res;
+
+	while ( index ) {
+		int blocks = index > (SIZE >> 2) ? (SIZE >> 2) : index;
+		int res = read_block_index(inode->i_sb, blocks, block_list,
+			&block_ptr, &offset);
+		if (res == -1)
+			goto failure;
+		block += res;
+		index -= blocks;
+	}
+
+	if (read_block_index(inode->i_sb, 1, block_list,
+			&block_ptr, &offset) == -1)
+		goto failure;
+	*bsize = *((unsigned int *) block_list);
+
+	return block;
+
+failure:
+	return 0;
+}
+
+
+static int squashfs_readpage(struct file *file, struct page *page)
+{
+	struct inode *inode = page->mapping->host;
+	struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
+	struct squashfs_super_block *sblk = &msblk->sblk;
+	unsigned char *block_list;
+	long long block;
+	unsigned int bsize, i = 0, bytes = 0, byte_offset = 0;
+	int index = page->index >> (sblk->block_log - PAGE_CACHE_SHIFT);
+ 	void *pageaddr;
+	struct squashfs_fragment_cache *fragment = NULL;
+	char *data_ptr = msblk->read_page;
+	
+	int mask = (1 << (sblk->block_log - PAGE_CACHE_SHIFT)) - 1;
+	int start_index = page->index & ~mask;
+	int end_index = start_index | mask;
+
+	TRACE("Entered squashfs_readpage, page index %lx, start block %llx\n",
+					page->index,
+					SQUASHFS_I(inode)->start_block);
+
+	if (!(block_list = kmalloc(SIZE, GFP_KERNEL))) {
+		ERROR("Failed to allocate block_list\n");
+		goto skip_read;
+	}
+
+	if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
+					PAGE_CACHE_SHIFT))
+		goto skip_read;
+
+	if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK
+					|| index < (i_size_read(inode) >>
+					sblk->block_log)) {
+		if ((block = (msblk->read_blocklist)(inode, index, 1,
+					block_list, NULL, &bsize)) == 0)
+			goto skip_read;
+
+		mutex_lock(&msblk->read_page_mutex);
+		
+		if (!(bytes = squashfs_read_data(inode->i_sb, msblk->read_page,
+					block, bsize, NULL, sblk->block_size))) {
+			ERROR("Unable to read page, block %llx, size %x\n", block,
+					bsize);
+			mutex_unlock(&msblk->read_page_mutex);
+			goto skip_read;
+		}
+	} else {
+		if ((fragment = get_cached_fragment(inode->i_sb,
+					SQUASHFS_I(inode)->
+					u.s1.fragment_start_block,
+					SQUASHFS_I(inode)->u.s1.fragment_size))
+					== NULL) {
+			ERROR("Unable to read page, block %llx, size %x\n",
+					SQUASHFS_I(inode)->
+					u.s1.fragment_start_block,
+					(int) SQUASHFS_I(inode)->
+					u.s1.fragment_size);
+			goto skip_read;
+		}
+		bytes = SQUASHFS_I(inode)->u.s1.fragment_offset +
+					(i_size_read(inode) & (sblk->block_size
+					- 1));
+		byte_offset = SQUASHFS_I(inode)->u.s1.fragment_offset;
+		data_ptr = fragment->data;
+	}
+
+	for (i = start_index; i <= end_index && byte_offset < bytes;
+					i++, byte_offset += PAGE_CACHE_SIZE) {
+		struct page *push_page;
+		int avail = (bytes - byte_offset) > PAGE_CACHE_SIZE ?
+					PAGE_CACHE_SIZE : bytes - byte_offset;
+
+		TRACE("bytes %d, i %d, byte_offset %d, available_bytes %d\n",
+					bytes, i, byte_offset, avail);
+
+		push_page = (i == page->index) ? page :
+			grab_cache_page_nowait(page->mapping, i);
+
+		if (!push_page)
+			continue;
+
+		if (PageUptodate(push_page))
+			goto skip_page;
+
+ 		pageaddr = kmap_atomic(push_page, KM_USER0);
+		memcpy(pageaddr, data_ptr + byte_offset, avail);
+		memset(pageaddr + avail, 0, PAGE_CACHE_SIZE - avail);
+		kunmap_atomic(pageaddr, KM_USER0);
+		flush_dcache_page(push_page);
+		SetPageUptodate(push_page);
+skip_page:
+		unlock_page(push_page);
+		if(i != page->index)
+			page_cache_release(push_page);
+	}
+
+	if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK
+					|| index < (i_size_read(inode) >>
+					sblk->block_log))
+		mutex_unlock(&msblk->read_page_mutex);
+	else
+		release_cached_fragment(msblk, fragment);
+
+	kfree(block_list);
+	return 0;
+
+skip_read:
+	pageaddr = kmap_atomic(page, KM_USER0);
+	memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
+	kunmap_atomic(pageaddr, KM_USER0);
+	flush_dcache_page(page);
+	SetPageUptodate(page);
+	unlock_page(page);
+
+	kfree(block_list);
+	return 0;
+}
+
+
+static int squashfs_readpage4K(struct file *file, struct page *page)
+{
+	struct inode *inode = page->mapping->host;
+	struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
+	struct squashfs_super_block *sblk = &msblk->sblk;
+	unsigned char *block_list;
+	long long block;
+	unsigned int bsize, bytes = 0;
+ 	void *pageaddr;
+	
+	TRACE("Entered squashfs_readpage4K, page index %lx, start block %llx\n",
+					page->index,
+					SQUASHFS_I(inode)->start_block);
+
+	if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
+					PAGE_CACHE_SHIFT)) {
+		block_list = NULL;
+		goto skip_read;
+	}
+
+	if (!(block_list = kmalloc(SIZE, GFP_KERNEL))) {
+		ERROR("Failed to allocate block_list\n");
+		goto skip_read;
+	}
+
+	if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK
+					|| page->index < (i_size_read(inode) >>
+					sblk->block_log)) {
+		block = (msblk->read_blocklist)(inode, page->index, 1,
+					block_list, NULL, &bsize);
+		if(block == 0)
+			goto skip_read;
+
+		mutex_lock(&msblk->read_page_mutex);
+		bytes = squashfs_read_data(inode->i_sb, msblk->read_page, block,
+					bsize, NULL, sblk->block_size);
+		if (bytes) {
+			pageaddr = kmap_atomic(page, KM_USER0);
+			memcpy(pageaddr, msblk->read_page, bytes);
+			kunmap_atomic(pageaddr, KM_USER0);
+		} else
+			ERROR("Unable to read page, block %llx, size %x\n",
+					block, bsize);
+		mutex_unlock(&msblk->read_page_mutex);
+	} else {
+		struct squashfs_fragment_cache *fragment =
+			get_cached_fragment(inode->i_sb,
+					SQUASHFS_I(inode)->
+					u.s1.fragment_start_block,
+					SQUASHFS_I(inode)-> u.s1.fragment_size);
+		if (fragment) {
+			bytes = i_size_read(inode) & (sblk->block_size - 1);
+			pageaddr = kmap_atomic(page, KM_USER0);
+			memcpy(pageaddr, fragment->data + SQUASHFS_I(inode)->
+					u.s1.fragment_offset, bytes);
+			kunmap_atomic(pageaddr, KM_USER0);
+			release_cached_fragment(msblk, fragment);
+		} else
+			ERROR("Unable to read page, block %llx, size %x\n",
+					SQUASHFS_I(inode)->
+					u.s1.fragment_start_block, (int)
+					SQUASHFS_I(inode)-> u.s1.fragment_size);
+	}
+
+skip_read:
+	pageaddr = kmap_atomic(page, KM_USER0);
+	memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
+	kunmap_atomic(pageaddr, KM_USER0);
+	flush_dcache_page(page);
+	SetPageUptodate(page);
+	unlock_page(page);
+
+	kfree(block_list);
+	return 0;
+}
+
+
+static int get_dir_index_using_offset(struct super_block *s, long long 
+				*next_block, unsigned int *next_offset,
+				long long index_start,
+				unsigned int index_offset, int i_count,
+				long long f_pos)
+{
+	struct squashfs_sb_info *msblk = s->s_fs_info;
+	struct squashfs_super_block *sblk = &msblk->sblk;
+	int i, length = 0;
+	struct squashfs_dir_index index;
+
+	TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %d\n",
+					i_count, (unsigned int) f_pos);
+
+	f_pos =- 3;
+	if (f_pos == 0)
+		goto finish;
+
+	for (i = 0; i < i_count; i++) {
+		if (msblk->swap) {
+			struct squashfs_dir_index sindex;
+			squashfs_get_cached_block(s, (char *) &sindex,
+					index_start, index_offset,
+					sizeof(sindex), &index_start,
+					&index_offset);
+			SQUASHFS_SWAP_DIR_INDEX(&index, &sindex);
+		} else
+			squashfs_get_cached_block(s, (char *) &index,
+					index_start, index_offset,
+					sizeof(index), &index_start,
+					&index_offset);
+
+		if (index.index > f_pos)
+			break;
+
+		squashfs_get_cached_block(s, NULL, index_start, index_offset,
+					index.size + 1, &index_start,
+					&index_offset);
+
+		length = index.index;
+		*next_block = index.start_block + sblk->directory_table_start;
+	}
+
+	*next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
+
+finish:
+	return length + 3;
+}
+
+
+static int get_dir_index_using_name(struct super_block *s, long long
+				*next_block, unsigned int *next_offset,
+				long long index_start,
+				unsigned int index_offset, int i_count,
+				const char *name, int size)
+{
+	struct squashfs_sb_info *msblk = s->s_fs_info;
+	struct squashfs_super_block *sblk = &msblk->sblk;
+	int i, length = 0;
+	struct squashfs_dir_index *index;
+	char *str;
+
+	TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count);
+
+	if (!(str = kmalloc(sizeof(struct squashfs_dir_index) +
+		(SQUASHFS_NAME_LEN + 1) * 2, GFP_KERNEL))) {
+		ERROR("Failed to allocate squashfs_dir_index\n");
+		goto failure;
+	}
+
+	index = (struct squashfs_dir_index *) (str + SQUASHFS_NAME_LEN + 1);
+	strncpy(str, name, size);
+	str[size] = '\0';
+
+	for (i = 0; i < i_count; i++) {
+		if (msblk->swap) {
+			struct squashfs_dir_index sindex;
+			squashfs_get_cached_block(s, (char *) &sindex,
+					index_start, index_offset,
+					sizeof(sindex), &index_start,
+					&index_offset);
+			SQUASHFS_SWAP_DIR_INDEX(index, &sindex);
+		} else
+			squashfs_get_cached_block(s, (char *) index,
+					index_start, index_offset,
+					sizeof(struct squashfs_dir_index),
+					&index_start, &index_offset);
+
+		squashfs_get_cached_block(s, index->name, index_start,
+					index_offset, index->size + 1,
+					&index_start, &index_offset);
+
+		index->name[index->size + 1] = '\0';
+
+		if (strcmp(index->name, str) > 0)
+			break;
+
+		length = index->index;
+		*next_block = index->start_block + sblk->directory_table_start;
+	}
+
+	*next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
+	kfree(str);
+failure:
+	return length + 3;
+}
+
+		
+static int squashfs_readdir(struct file *file, void *dirent, filldir_t filldir)
+{
+	struct inode *i = file->f_dentry->d_inode;
+	struct squashfs_sb_info *msblk = i->i_sb->s_fs_info;
+	struct squashfs_super_block *sblk = &msblk->sblk;
+	long long next_block = SQUASHFS_I(i)->start_block +
+		sblk->directory_table_start;
+	int next_offset = SQUASHFS_I(i)->offset, length = 0,
+		dir_count;
+	struct squashfs_dir_header dirh;
+	struct squashfs_dir_entry *dire;
+
+	TRACE("Entered squashfs_readdir [%llx:%x]\n", next_block, next_offset);
+
+	if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) +
+		SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) {
+		ERROR("Failed to allocate squashfs_dir_entry\n");
+		goto finish;
+	}
+
+	while(file->f_pos < 3) {
+		char *name;
+		int size, i_ino;
+
+		if(file->f_pos == 0) {
+			name = ".";
+			size = 1;
+			i_ino = i->i_ino;
+		} else {
+			name = "..";
+			size = 2;
+			i_ino = SQUASHFS_I(i)->u.s2.parent_inode;
+		}
+		TRACE("Calling filldir(%x, %s, %d, %d, %d, %d)\n",
+				(unsigned int) dirent, name, size, (int)
+				file->f_pos, i_ino,
+				squashfs_filetype_table[1]);
+
+		if (filldir(dirent, name, size,
+				file->f_pos, i_ino,
+				squashfs_filetype_table[1]) < 0) {
+				TRACE("Filldir returned less than 0\n");
+				goto finish;
+		}
+		file->f_pos += size;
+	}
+
+	length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset,
+				SQUASHFS_I(i)->u.s2.directory_index_start,
+				SQUASHFS_I(i)->u.s2.directory_index_offset,
+				SQUASHFS_I(i)->u.s2.directory_index_count,
+				file->f_pos);
+
+	while (length < i_size_read(i)) {
+		/* read directory header */
+		if (msblk->swap) {
+			struct squashfs_dir_header sdirh;
+			
+			if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
+					next_block, next_offset, sizeof(sdirh),
+					&next_block, &next_offset))
+				goto failed_read;
+
+			length += sizeof(sdirh);
+			SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh);
+		} else {
+			if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
+					next_block, next_offset, sizeof(dirh),
+					&next_block, &next_offset))
+				goto failed_read;
+
+			length += sizeof(dirh);
+		}
+
+		dir_count = dirh.count + 1;
+		while (dir_count--) {
+			if (msblk->swap) {
+				struct squashfs_dir_entry sdire;
+				if (!squashfs_get_cached_block(i->i_sb, (char *)
+						&sdire, next_block, next_offset,
+						sizeof(sdire), &next_block,
+						&next_offset))
+					goto failed_read;
+				
+				length += sizeof(sdire);
+				SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire);
+			} else {
+				if (!squashfs_get_cached_block(i->i_sb, (char *)
+						dire, next_block, next_offset,
+						sizeof(*dire), &next_block,
+						&next_offset))
+					goto failed_read;
+
+				length += sizeof(*dire);
+			}
+
+			if (!squashfs_get_cached_block(i->i_sb, dire->name,
+						next_block, next_offset,
+						dire->size + 1, &next_block,
+						&next_offset))
+				goto failed_read;
+
+			length += dire->size + 1;
+
+			if (file->f_pos >= length)
+				continue;
+
+			dire->name[dire->size + 1] = '\0';
+
+			TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d, %d)\n",
+					(unsigned int) dirent, dire->name,
+					dire->size + 1, (int) file->f_pos,
+					dirh.start_block, dire->offset,
+					dirh.inode_number + dire->inode_number,
+					squashfs_filetype_table[dire->type]);
+
+			if (filldir(dirent, dire->name, dire->size + 1,
+					file->f_pos,
+					dirh.inode_number + dire->inode_number,
+					squashfs_filetype_table[dire->type])
+					< 0) {
+				TRACE("Filldir returned less than 0\n");
+				goto finish;
+			}
+			file->f_pos = length;
+		}
+	}
+
+finish:
+	kfree(dire);
+	return 0;
+
+failed_read:
+	ERROR("Unable to read directory block [%llx:%x]\n", next_block,
+		next_offset);
+	kfree(dire);
+	return 0;
+}
+
+
+static struct dentry *squashfs_lookup(struct inode *i, struct dentry *dentry,
+				struct nameidata *nd)
+{
+	const unsigned char *name = dentry->d_name.name;
+	int len = dentry->d_name.len;
+	struct inode *inode = NULL;
+	struct squashfs_sb_info *msblk = i->i_sb->s_fs_info;
+	struct squashfs_super_block *sblk = &msblk->sblk;
+	long long next_block = SQUASHFS_I(i)->start_block +
+				sblk->directory_table_start;
+	int next_offset = SQUASHFS_I(i)->offset, length = 0,
+				dir_count;
+	struct squashfs_dir_header dirh;
+	struct squashfs_dir_entry *dire;
+
+	TRACE("Entered squashfs_lookup [%llx:%x]\n", next_block, next_offset);
+
+	if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) +
+		SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) {
+		ERROR("Failed to allocate squashfs_dir_entry\n");
+		goto exit_lookup;
+	}
+
+	if (len > SQUASHFS_NAME_LEN)
+		goto exit_lookup;
+
+	length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset,
+				SQUASHFS_I(i)->u.s2.directory_index_start,
+				SQUASHFS_I(i)->u.s2.directory_index_offset,
+				SQUASHFS_I(i)->u.s2.directory_index_count, name,
+				len);
+
+	while (length < i_size_read(i)) {
+		/* read directory header */
+		if (msblk->swap) {
+			struct squashfs_dir_header sdirh;
+			if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
+					next_block, next_offset, sizeof(sdirh),
+					&next_block, &next_offset))
+				goto failed_read;
+
+			length += sizeof(sdirh);
+			SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh);
+		} else {
+			if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
+					next_block, next_offset, sizeof(dirh),
+					&next_block, &next_offset))
+				goto failed_read;
+
+			length += sizeof(dirh);
+		}
+
+		dir_count = dirh.count + 1;
+		while (dir_count--) {
+			if (msblk->swap) {
+				struct squashfs_dir_entry sdire;
+				if (!squashfs_get_cached_block(i->i_sb, (char *)
+						&sdire, next_block,next_offset,
+						sizeof(sdire), &next_block,
+						&next_offset))
+					goto failed_read;
+				
+				length += sizeof(sdire);
+				SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire);
+			} else {
+				if (!squashfs_get_cached_block(i->i_sb, (char *)
+						dire, next_block,next_offset,
+						sizeof(*dire), &next_block,
+						&next_offset))
+					goto failed_read;
+
+				length += sizeof(*dire);
+			}
+
+			if (!squashfs_get_cached_block(i->i_sb, dire->name,
+					next_block, next_offset, dire->size + 1,
+					&next_block, &next_offset))
+				goto failed_read;
+
+			length += dire->size + 1;
+
+			if (name[0] < dire->name[0])
+				goto exit_lookup;
+
+			if ((len == dire->size + 1) && !strncmp(name, dire->name, len)) {
+				squashfs_inode_t ino = SQUASHFS_MKINODE(dirh.start_block,
+								dire->offset);
+
+				TRACE("calling squashfs_iget for directory "
+					"entry %s, inode %x:%x, %d\n", name,
+					dirh.start_block, dire->offset,
+					dirh.inode_number + dire->inode_number);
+
+				inode = squashfs_iget(i->i_sb, ino, dirh.inode_number + dire->inode_number);
+
+				goto exit_lookup;
+			}
+		}
+	}
+
+exit_lookup:
+	kfree(dire);
+	if (inode)
+		return d_splice_alias(inode, dentry);
+	d_add(dentry, inode);
+	return ERR_PTR(0);
+
+failed_read:
+	ERROR("Unable to read directory block [%llx:%x]\n", next_block,
+		next_offset);
+	goto exit_lookup;
+}
+
+
+static int squashfs_remount(struct super_block *s, int *flags, char *data)
+{
+	*flags |= MS_RDONLY;
+	return 0;
+}
+
+
+static void squashfs_put_super(struct super_block *s)
+{
+	int i;
+
+	if (s->s_fs_info) {
+		struct squashfs_sb_info *sbi = s->s_fs_info;
+		if (sbi->block_cache)
+			for (i = 0; i < SQUASHFS_CACHED_BLKS; i++)
+				if (sbi->block_cache[i].block !=
+							SQUASHFS_INVALID_BLK)
+					kfree(sbi->block_cache[i].data);
+		if (sbi->fragment)
+			for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++) 
+				SQUASHFS_FREE(sbi->fragment[i].data);
+		kfree(sbi->fragment);
+		kfree(sbi->block_cache);
+		kfree(sbi->read_page);
+		kfree(sbi->uid);
+		kfree(sbi->fragment_index);
+		kfree(sbi->fragment_index_2);
+		kfree(sbi->meta_index);
+		kfree(s->s_fs_info);
+		s->s_fs_info = NULL;
+	}
+}
+
+
+static int squashfs_get_sb(struct file_system_type *fs_type, int flags,
+				const char *dev_name, void *data,
+				struct vfsmount *mnt)
+{
+	return get_sb_bdev(fs_type, flags, dev_name, data, squashfs_fill_super,
+				mnt);
+}
+
+
+static void free_sqlzma(void)
+{
+	int cpu;
+	struct sqlzma *p;
+
+	for_each_online_cpu(cpu) {
+		p = per_cpu(sqlzma, cpu);
+		if (p) {
+#ifdef KeepPreemptive
+			mutex_destroy(&p->mtx);
+#endif
+			sqlzma_fin(&p->un);
+			kfree(p);
+		}
+	}
+}
+
+static int __init init_squashfs_fs(void)
+{
+	struct sqlzma *p;
+	int cpu;
+	int err = init_inodecache();
+	if (err)
+		goto out;
+
+	for_each_online_cpu(cpu) {
+		dpri("%d: %p\n", cpu, per_cpu(sqlzma, cpu));
+		err = -ENOMEM;
+		p = kmalloc(sizeof(struct sqlzma), GFP_KERNEL);
+		if (p) {
+#ifdef KeepPreemptive
+			mutex_init(&p->mtx);
+#endif
+			err = sqlzma_init(&p->un, 1, 0);
+			if (unlikely(err)) {
+				ERROR("Failed to intialize uncompress workspace\n");
+				break;
+			}
+			per_cpu(sqlzma, cpu) = p;
+			err = 0;
+		} else
+			break;
+	}
+	if (unlikely(err)) {
+		free_sqlzma();
+		goto out;
+	}
+
+	printk(KERN_INFO "squashfs: version 3.2-r2 (2007/01/15) "
+		"Phillip Lougher\n"
+		"squashfs: LZMA suppport for slax.org by jro\n");
+
+	if ((err = register_filesystem(&squashfs_fs_type))) {
+		free_sqlzma();
+		destroy_inodecache();
+	}
+
+out:
+	return err;
+}
+
+
+static void __exit exit_squashfs_fs(void)
+{
+	unregister_filesystem(&squashfs_fs_type);
+	free_sqlzma();
+	destroy_inodecache();
+}
+
+
+static struct kmem_cache * squashfs_inode_cachep;
+
+
+static struct inode *squashfs_alloc_inode(struct super_block *sb)
+{
+	struct squashfs_inode_info *ei;
+	ei = kmem_cache_alloc(squashfs_inode_cachep, GFP_KERNEL);
+	if (!ei)
+		return NULL;
+	return &ei->vfs_inode;
+}
+
+
+static void squashfs_destroy_inode(struct inode *inode)
+{
+	kmem_cache_free(squashfs_inode_cachep, SQUASHFS_I(inode));
+}
+
+
+static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags)
+{
+	struct squashfs_inode_info *ei = foo;
+
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+							SLAB_CTOR_CONSTRUCTOR)
+		inode_init_once(&ei->vfs_inode);
+}
+ 
+
+static int __init init_inodecache(void)
+{
+	squashfs_inode_cachep = kmem_cache_create("squashfs_inode_cache",
+	     sizeof(struct squashfs_inode_info),
+	     0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
+	     init_once, NULL);
+	if (squashfs_inode_cachep == NULL)
+		return -ENOMEM;
+	return 0;
+}
+
+
+static void destroy_inodecache(void)
+{
+	kmem_cache_destroy(squashfs_inode_cachep);
+}
+
+
+module_init(init_squashfs_fs);
+module_exit(exit_squashfs_fs);
+MODULE_DESCRIPTION("squashfs 3.2-r2, a compressed read-only filesystem, and LZMA suppport for slax.org");
+MODULE_AUTHOR("Phillip Lougher <phillip@lougher.org.uk>, and LZMA suppport for slax.org by jro");
+MODULE_LICENSE("GPL");
diff -Nruw linux-2.6.20.14-fbx/fs/squashfs./Makefile linux-2.6.20.14-fbx/fs/squashfs/Makefile
--- linux-2.6.20.14-fbx/fs/squashfs./Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/fs/squashfs/Makefile	2011-09-26 15:07:55.998834410 +0200
@@ -0,0 +1,7 @@
+#
+# Makefile for the linux squashfs routines.
+#
+
+obj-$(CONFIG_SQUASHFS) += squashfs.o
+squashfs-y += inode.o
+squashfs-y += squashfs2_0.o
diff -Nruw linux-2.6.20.14-fbx/fs/squashfs./squashfs2_0.c linux-2.6.20.14-fbx/fs/squashfs/squashfs2_0.c
--- linux-2.6.20.14-fbx/fs/squashfs./squashfs2_0.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/fs/squashfs/squashfs2_0.c	2011-09-26 15:07:55.998834410 +0200
@@ -0,0 +1,742 @@
+/*
+ * Squashfs - a compressed read only filesystem for Linux
+ *
+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007
+ * Phillip Lougher <phillip@lougher.org.uk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2,
+ * or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * squashfs2_0.c
+ */
+
+#include <linux/squashfs_fs.h>
+#include <linux/module.h>
+#include <linux/zlib.h>
+#include <linux/fs.h>
+#include <linux/squashfs_fs_sb.h>
+#include <linux/squashfs_fs_i.h>
+
+#include "squashfs.h"
+static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir);
+static struct dentry *squashfs_lookup_2(struct inode *, struct dentry *,
+				struct nameidata *);
+
+static struct file_operations squashfs_dir_ops_2 = {
+	.read = generic_read_dir,
+	.readdir = squashfs_readdir_2
+};
+
+static struct inode_operations squashfs_dir_inode_ops_2 = {
+	.lookup = squashfs_lookup_2
+};
+
+static unsigned char squashfs_filetype_table[] = {
+	DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK
+};
+
+static int read_fragment_index_table_2(struct super_block *s)
+{
+	struct squashfs_sb_info *msblk = s->s_fs_info;
+	struct squashfs_super_block *sblk = &msblk->sblk;
+
+	if (!(msblk->fragment_index_2 = kmalloc(SQUASHFS_FRAGMENT_INDEX_BYTES_2
+					(sblk->fragments), GFP_KERNEL))) {
+		ERROR("Failed to allocate uid/gid table\n");
+		return 0;
+	}
+   
+	if (SQUASHFS_FRAGMENT_INDEX_BYTES_2(sblk->fragments) &&
+					!squashfs_read_data(s, (char *)
+					msblk->fragment_index_2,
+					sblk->fragment_table_start,
+					SQUASHFS_FRAGMENT_INDEX_BYTES_2
+					(sblk->fragments) |
+					SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, SQUASHFS_FRAGMENT_INDEX_BYTES_2(sblk->fragments))) {
+		ERROR("unable to read fragment index table\n");
+		return 0;
+	}
+
+	if (msblk->swap) {
+		int i;
+		unsigned int fragment;
+
+		for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES_2(sblk->fragments);
+									i++) {
+			SQUASHFS_SWAP_FRAGMENT_INDEXES_2((&fragment),
+						&msblk->fragment_index_2[i], 1);
+			msblk->fragment_index_2[i] = fragment;
+		}
+	}
+
+	return 1;
+}
+
+
+static int get_fragment_location_2(struct super_block *s, unsigned int fragment,
+				long long *fragment_start_block,
+				unsigned int *fragment_size)
+{
+	struct squashfs_sb_info *msblk = s->s_fs_info;
+	long long start_block =
+		msblk->fragment_index_2[SQUASHFS_FRAGMENT_INDEX_2(fragment)];
+	int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET_2(fragment);
+	struct squashfs_fragment_entry_2 fragment_entry;
+
+	if (msblk->swap) {
+		struct squashfs_fragment_entry_2 sfragment_entry;
+
+		if (!squashfs_get_cached_block(s, (char *) &sfragment_entry,
+					start_block, offset,
+					sizeof(sfragment_entry), &start_block,
+					&offset))
+			goto out;
+		SQUASHFS_SWAP_FRAGMENT_ENTRY_2(&fragment_entry, &sfragment_entry);
+	} else
+		if (!squashfs_get_cached_block(s, (char *) &fragment_entry,
+					start_block, offset,
+					sizeof(fragment_entry), &start_block,
+					&offset))
+			goto out;
+
+	*fragment_start_block = fragment_entry.start_block;
+	*fragment_size = fragment_entry.size;
+
+	return 1;
+
+out:
+	return 0;
+}
+
+
+static void squashfs_new_inode(struct squashfs_sb_info *msblk, struct inode *i,
+		struct squashfs_base_inode_header_2 *inodeb, unsigned int ino)
+{
+	struct squashfs_super_block *sblk = &msblk->sblk;
+
+	i->i_ino = ino;
+	i->i_mtime.tv_sec = sblk->mkfs_time;
+	i->i_atime.tv_sec = sblk->mkfs_time;
+	i->i_ctime.tv_sec = sblk->mkfs_time;
+	i->i_uid = msblk->uid[inodeb->uid];
+	i->i_mode = inodeb->mode;
+	i->i_nlink = 1;
+	i->i_size = 0;
+	if (inodeb->guid == SQUASHFS_GUIDS)
+		i->i_gid = i->i_uid;
+	else
+		i->i_gid = msblk->guid[inodeb->guid];
+}
+
+
+static int squashfs_read_inode_2(struct inode *i, squashfs_inode_t inode)
+{
+	struct super_block *s = i->i_sb;
+	struct squashfs_sb_info *msblk = s->s_fs_info;
+	struct squashfs_super_block *sblk = &msblk->sblk;
+	unsigned int block = SQUASHFS_INODE_BLK(inode) +
+		sblk->inode_table_start;
+	unsigned int offset = SQUASHFS_INODE_OFFSET(inode);
+	unsigned int ino = i->i_ino;
+	long long next_block;
+	unsigned int next_offset;
+	union squashfs_inode_header_2 id, sid;
+	struct squashfs_base_inode_header_2 *inodeb = &id.base,
+					  *sinodeb = &sid.base;
+
+	TRACE("Entered squashfs_iget\n");
+
+	if (msblk->swap) {
+		if (!squashfs_get_cached_block(s, (char *) sinodeb, block,
+					offset, sizeof(*sinodeb), &next_block,
+					&next_offset))
+			goto failed_read;
+		SQUASHFS_SWAP_BASE_INODE_HEADER_2(inodeb, sinodeb,
+					sizeof(*sinodeb));
+	} else
+		if (!squashfs_get_cached_block(s, (char *) inodeb, block,
+					offset, sizeof(*inodeb), &next_block,
+					&next_offset))
+			goto failed_read;
+
+	squashfs_new_inode(msblk, i, inodeb, ino);
+
+	switch(inodeb->inode_type) {
+		case SQUASHFS_FILE_TYPE: {
+			struct squashfs_reg_inode_header_2 *inodep = &id.reg;
+			struct squashfs_reg_inode_header_2 *sinodep = &sid.reg;
+			long long frag_blk;
+			unsigned int frag_size = 0;
+				
+			if (msblk->swap) {
+				if (!squashfs_get_cached_block(s, (char *)
+						sinodep, block, offset,
+						sizeof(*sinodep), &next_block,
+						&next_offset))
+					goto failed_read;
+				SQUASHFS_SWAP_REG_INODE_HEADER_2(inodep, sinodep);
+			} else
+				if (!squashfs_get_cached_block(s, (char *)
+						inodep, block, offset,
+						sizeof(*inodep), &next_block,
+						&next_offset))
+					goto failed_read;
+
+			frag_blk = SQUASHFS_INVALID_BLK;
+			if (inodep->fragment != SQUASHFS_INVALID_FRAG &&
+					!get_fragment_location_2(s,
+					inodep->fragment, &frag_blk, &frag_size))
+				goto failed_read;
+				
+			i->i_size = inodep->file_size;
+			i->i_fop = &generic_ro_fops;
+			i->i_mode |= S_IFREG;
+			i->i_mtime.tv_sec = inodep->mtime;
+			i->i_atime.tv_sec = inodep->mtime;
+			i->i_ctime.tv_sec = inodep->mtime;
+			i->i_blocks = ((i->i_size - 1) >> 9) + 1;
+			SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;
+			SQUASHFS_I(i)->u.s1.fragment_size = frag_size;
+			SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;
+			SQUASHFS_I(i)->start_block = inodep->start_block;
+			SQUASHFS_I(i)->u.s1.block_list_start = next_block;
+			SQUASHFS_I(i)->offset = next_offset;
+			if (sblk->block_size > 4096)
+				i->i_data.a_ops = &squashfs_aops;
+			else
+				i->i_data.a_ops = &squashfs_aops_4K;
+
+			TRACE("File inode %x:%x, start_block %x, "
+					"block_list_start %llx, offset %x\n",
+					SQUASHFS_INODE_BLK(inode), offset,
+					inodep->start_block, next_block,
+					next_offset);
+			break;
+		}
+		case SQUASHFS_DIR_TYPE: {
+			struct squashfs_dir_inode_header_2 *inodep = &id.dir;
+			struct squashfs_dir_inode_header_2 *sinodep = &sid.dir;
+
+			if (msblk->swap) {
+				if (!squashfs_get_cached_block(s, (char *)
+						sinodep, block, offset,
+						sizeof(*sinodep), &next_block,
+						&next_offset))
+					goto failed_read;
+				SQUASHFS_SWAP_DIR_INODE_HEADER_2(inodep, sinodep);
+			} else
+				if (!squashfs_get_cached_block(s, (char *)
+						inodep, block, offset,
+						sizeof(*inodep), &next_block,
+						&next_offset))
+					goto failed_read;
+
+			i->i_size = inodep->file_size;
+			i->i_op = &squashfs_dir_inode_ops_2;
+			i->i_fop = &squashfs_dir_ops_2;
+			i->i_mode |= S_IFDIR;
+			i->i_mtime.tv_sec = inodep->mtime;
+			i->i_atime.tv_sec = inodep->mtime;
+			i->i_ctime.tv_sec = inodep->mtime;
+			SQUASHFS_I(i)->start_block = inodep->start_block;
+			SQUASHFS_I(i)->offset = inodep->offset;
+			SQUASHFS_I(i)->u.s2.directory_index_count = 0;
+			SQUASHFS_I(i)->u.s2.parent_inode = 0;
+
+			TRACE("Directory inode %x:%x, start_block %x, offset "
+					"%x\n", SQUASHFS_INODE_BLK(inode),
+					offset, inodep->start_block,
+					inodep->offset);
+			break;
+		}
+		case SQUASHFS_LDIR_TYPE: {
+			struct squashfs_ldir_inode_header_2 *inodep = &id.ldir;
+			struct squashfs_ldir_inode_header_2 *sinodep = &sid.ldir;
+
+			if (msblk->swap) {
+				if (!squashfs_get_cached_block(s, (char *)
+						sinodep, block, offset,
+						sizeof(*sinodep), &next_block,
+						&next_offset))
+					goto failed_read;
+				SQUASHFS_SWAP_LDIR_INODE_HEADER_2(inodep,
+						sinodep);
+			} else
+				if (!squashfs_get_cached_block(s, (char *)
+						inodep, block, offset,
+						sizeof(*inodep), &next_block,
+						&next_offset))
+					goto failed_read;
+
+			i->i_size = inodep->file_size;
+			i->i_op = &squashfs_dir_inode_ops_2;
+			i->i_fop = &squashfs_dir_ops_2;
+			i->i_mode |= S_IFDIR;
+			i->i_mtime.tv_sec = inodep->mtime;
+			i->i_atime.tv_sec = inodep->mtime;
+			i->i_ctime.tv_sec = inodep->mtime;
+			SQUASHFS_I(i)->start_block = inodep->start_block;
+			SQUASHFS_I(i)->offset = inodep->offset;
+			SQUASHFS_I(i)->u.s2.directory_index_start = next_block;
+			SQUASHFS_I(i)->u.s2.directory_index_offset =
+								next_offset;
+			SQUASHFS_I(i)->u.s2.directory_index_count =
+								inodep->i_count;
+			SQUASHFS_I(i)->u.s2.parent_inode = 0;
+
+			TRACE("Long directory inode %x:%x, start_block %x, "
+					"offset %x\n",
+					SQUASHFS_INODE_BLK(inode), offset,
+					inodep->start_block, inodep->offset);
+			break;
+		}
+		case SQUASHFS_SYMLINK_TYPE: {
+			struct squashfs_symlink_inode_header_2 *inodep =
+								&id.symlink;
+			struct squashfs_symlink_inode_header_2 *sinodep =
+								&sid.symlink;
+	
+			if (msblk->swap) {
+				if (!squashfs_get_cached_block(s, (char *)
+						sinodep, block, offset,
+						sizeof(*sinodep), &next_block,
+						&next_offset))
+					goto failed_read;
+				SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(inodep,
+								sinodep);
+			} else
+				if (!squashfs_get_cached_block(s, (char *)
+						inodep, block, offset,
+						sizeof(*inodep), &next_block,
+						&next_offset))
+					goto failed_read;
+
+			i->i_size = inodep->symlink_size;
+			i->i_op = &page_symlink_inode_operations;
+			i->i_data.a_ops = &squashfs_symlink_aops;
+			i->i_mode |= S_IFLNK;
+			SQUASHFS_I(i)->start_block = next_block;
+			SQUASHFS_I(i)->offset = next_offset;
+
+			TRACE("Symbolic link inode %x:%x, start_block %llx, "
+					"offset %x\n",
+					SQUASHFS_INODE_BLK(inode), offset,
+					next_block, next_offset);
+			break;
+		 }
+		 case SQUASHFS_BLKDEV_TYPE:
+		 case SQUASHFS_CHRDEV_TYPE: {
+			struct squashfs_dev_inode_header_2 *inodep = &id.dev;
+			struct squashfs_dev_inode_header_2 *sinodep = &sid.dev;
+
+			if (msblk->swap) {
+				if (!squashfs_get_cached_block(s, (char *)
+						sinodep, block, offset,
+						sizeof(*sinodep), &next_block,
+						&next_offset))
+					goto failed_read;
+				SQUASHFS_SWAP_DEV_INODE_HEADER_2(inodep, sinodep);
+			} else	
+				if (!squashfs_get_cached_block(s, (char *)
+						inodep, block, offset,
+						sizeof(*inodep), &next_block,
+						&next_offset))
+					goto failed_read;
+
+			i->i_mode |= (inodeb->inode_type ==
+					SQUASHFS_CHRDEV_TYPE) ?  S_IFCHR :
+					S_IFBLK;
+			init_special_inode(i, i->i_mode,
+					old_decode_dev(inodep->rdev));
+
+			TRACE("Device inode %x:%x, rdev %x\n",
+					SQUASHFS_INODE_BLK(inode), offset,
+					inodep->rdev);
+			break;
+		 }
+		 case SQUASHFS_FIFO_TYPE:
+		 case SQUASHFS_SOCKET_TYPE: {
+
+			i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE)
+							? S_IFIFO : S_IFSOCK;
+			init_special_inode(i, i->i_mode, 0);
+			break;
+		 }
+		 default:
+			ERROR("Unknown inode type %d in squashfs_iget!\n",
+					inodeb->inode_type);
+			goto failed_read1;
+	}
+	
+	return 1;
+
+failed_read:
+	ERROR("Unable to read inode [%x:%x]\n", block, offset);
+
+failed_read1:
+	return 0;
+}
+
+
+static int get_dir_index_using_offset(struct super_block *s, long long 
+				*next_block, unsigned int *next_offset,
+				long long index_start,
+				unsigned int index_offset, int i_count,
+				long long f_pos)
+{
+	struct squashfs_sb_info *msblk = s->s_fs_info;
+	struct squashfs_super_block *sblk = &msblk->sblk;
+	int i, length = 0;
+	struct squashfs_dir_index_2 index;
+
+	TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %d\n",
+					i_count, (unsigned int) f_pos);
+
+	if (f_pos == 0)
+		goto finish;
+
+	for (i = 0; i < i_count; i++) {
+		if (msblk->swap) {
+			struct squashfs_dir_index_2 sindex;
+			squashfs_get_cached_block(s, (char *) &sindex,
+					index_start, index_offset,
+					sizeof(sindex), &index_start,
+					&index_offset);
+			SQUASHFS_SWAP_DIR_INDEX_2(&index, &sindex);
+		} else
+			squashfs_get_cached_block(s, (char *) &index,
+					index_start, index_offset,
+					sizeof(index), &index_start,
+					&index_offset);
+
+		if (index.index > f_pos)
+			break;
+
+		squashfs_get_cached_block(s, NULL, index_start, index_offset,
+					index.size + 1, &index_start,
+					&index_offset);
+
+		length = index.index;
+		*next_block = index.start_block + sblk->directory_table_start;
+	}
+
+	*next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
+
+finish:
+	return length;
+}
+
+
+static int get_dir_index_using_name(struct super_block *s, long long
+				*next_block, unsigned int *next_offset,
+				long long index_start,
+				unsigned int index_offset, int i_count,
+				const char *name, int size)
+{
+	struct squashfs_sb_info *msblk = s->s_fs_info;
+	struct squashfs_super_block *sblk = &msblk->sblk;
+	int i, length = 0;
+	struct squashfs_dir_index_2 *index;
+	char *str;
+
+	TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count);
+
+	if (!(str = kmalloc(sizeof(struct squashfs_dir_index) +
+		(SQUASHFS_NAME_LEN + 1) * 2, GFP_KERNEL))) {
+		ERROR("Failed to allocate squashfs_dir_index\n");
+		goto failure;
+	}
+
+	index = (struct squashfs_dir_index_2 *) (str + SQUASHFS_NAME_LEN + 1);
+	strncpy(str, name, size);
+	str[size] = '\0';
+
+	for (i = 0; i < i_count; i++) {
+		if (msblk->swap) {
+			struct squashfs_dir_index_2 sindex;
+			squashfs_get_cached_block(s, (char *) &sindex,
+					index_start, index_offset,
+					sizeof(sindex), &index_start,
+					&index_offset);
+			SQUASHFS_SWAP_DIR_INDEX_2(index, &sindex);
+		} else
+			squashfs_get_cached_block(s, (char *) index,
+					index_start, index_offset,
+					sizeof(struct squashfs_dir_index_2),
+					&index_start, &index_offset);
+
+		squashfs_get_cached_block(s, index->name, index_start,
+					index_offset, index->size + 1,
+					&index_start, &index_offset);
+
+		index->name[index->size + 1] = '\0';
+
+		if (strcmp(index->name, str) > 0)
+			break;
+
+		length = index->index;
+		*next_block = index->start_block + sblk->directory_table_start;
+	}
+
+	*next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
+	kfree(str);
+failure:
+	return length;
+}
+
+		
+static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir)
+{
+	struct inode *i = file->f_dentry->d_inode;
+	struct squashfs_sb_info *msblk = i->i_sb->s_fs_info;
+	struct squashfs_super_block *sblk = &msblk->sblk;
+	long long next_block = SQUASHFS_I(i)->start_block +
+		sblk->directory_table_start;
+	int next_offset = SQUASHFS_I(i)->offset, length = 0,
+		dir_count;
+	struct squashfs_dir_header_2 dirh;
+	struct squashfs_dir_entry_2 *dire;
+
+	TRACE("Entered squashfs_readdir_2 [%llx:%x]\n", next_block, next_offset);
+
+	if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) +
+		SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) {
+		ERROR("Failed to allocate squashfs_dir_entry\n");
+		goto finish;
+	}
+
+	length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset,
+				SQUASHFS_I(i)->u.s2.directory_index_start,
+				SQUASHFS_I(i)->u.s2.directory_index_offset,
+				SQUASHFS_I(i)->u.s2.directory_index_count,
+				file->f_pos);
+
+	while (length < i_size_read(i)) {
+		/* read directory header */
+		if (msblk->swap) {
+			struct squashfs_dir_header_2 sdirh;
+			
+			if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
+					next_block, next_offset, sizeof(sdirh),
+					&next_block, &next_offset))
+				goto failed_read;
+
+			length += sizeof(sdirh);
+			SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh);
+		} else {
+			if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
+					next_block, next_offset, sizeof(dirh),
+					&next_block, &next_offset))
+				goto failed_read;
+
+			length += sizeof(dirh);
+		}
+
+		dir_count = dirh.count + 1;
+		while (dir_count--) {
+			if (msblk->swap) {
+				struct squashfs_dir_entry_2 sdire;
+				if (!squashfs_get_cached_block(i->i_sb, (char *)
+						&sdire, next_block, next_offset,
+						sizeof(sdire), &next_block,
+						&next_offset))
+					goto failed_read;
+				
+				length += sizeof(sdire);
+				SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire);
+			} else {
+				if (!squashfs_get_cached_block(i->i_sb, (char *)
+						dire, next_block, next_offset,
+						sizeof(*dire), &next_block,
+						&next_offset))
+					goto failed_read;
+
+				length += sizeof(*dire);
+			}
+
+			if (!squashfs_get_cached_block(i->i_sb, dire->name,
+						next_block, next_offset,
+						dire->size + 1, &next_block,
+						&next_offset))
+				goto failed_read;
+
+			length += dire->size + 1;
+
+			if (file->f_pos >= length)
+				continue;
+
+			dire->name[dire->size + 1] = '\0';
+
+			TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d)\n",
+					(unsigned int) dirent, dire->name,
+					dire->size + 1, (int) file->f_pos,
+					dirh.start_block, dire->offset,
+					squashfs_filetype_table[dire->type]);
+
+			if (filldir(dirent, dire->name, dire->size + 1,
+					file->f_pos, SQUASHFS_MK_VFS_INODE(
+					dirh.start_block, dire->offset),
+					squashfs_filetype_table[dire->type])
+					< 0) {
+				TRACE("Filldir returned less than 0\n");
+				goto finish;
+			}
+			file->f_pos = length;
+		}
+	}
+
+finish:
+	kfree(dire);
+	return 0;
+
+failed_read:
+	ERROR("Unable to read directory block [%llx:%x]\n", next_block,
+		next_offset);
+	kfree(dire);
+	return 0;
+}
+
+
+static struct dentry *squashfs_lookup_2(struct inode *i, struct dentry *dentry,
+				struct nameidata *nd)
+{
+	const unsigned char *name = dentry->d_name.name;
+	int len = dentry->d_name.len;
+	struct inode *inode = NULL;
+	struct squashfs_sb_info *msblk = i->i_sb->s_fs_info;
+	struct squashfs_super_block *sblk = &msblk->sblk;
+	long long next_block = SQUASHFS_I(i)->start_block +
+				sblk->directory_table_start;
+	int next_offset = SQUASHFS_I(i)->offset, length = 0,
+				dir_count;
+	struct squashfs_dir_header_2 dirh;
+	struct squashfs_dir_entry_2 *dire;
+	int sorted = sblk->s_major == 2 && sblk->s_minor >= 1;
+
+	TRACE("Entered squashfs_lookup_2 [%llx:%x]\n", next_block, next_offset);
+
+	if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) +
+		SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) {
+		ERROR("Failed to allocate squashfs_dir_entry\n");
+		goto exit_loop;
+	}
+
+	if (len > SQUASHFS_NAME_LEN)
+		goto exit_loop;
+
+	length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset,
+				SQUASHFS_I(i)->u.s2.directory_index_start,
+				SQUASHFS_I(i)->u.s2.directory_index_offset,
+				SQUASHFS_I(i)->u.s2.directory_index_count, name,
+				len);
+
+	while (length < i_size_read(i)) {
+		/* read directory header */
+		if (msblk->swap) {
+			struct squashfs_dir_header_2 sdirh;
+			if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
+					next_block, next_offset, sizeof(sdirh),
+					&next_block, &next_offset))
+				goto failed_read;
+
+			length += sizeof(sdirh);
+			SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh);
+		} else {
+			if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
+					next_block, next_offset, sizeof(dirh),
+					&next_block, &next_offset))
+				goto failed_read;
+
+			length += sizeof(dirh);
+		}
+
+		dir_count = dirh.count + 1;
+		while (dir_count--) {
+			if (msblk->swap) {
+				struct squashfs_dir_entry_2 sdire;
+				if (!squashfs_get_cached_block(i->i_sb, (char *)
+						&sdire, next_block,next_offset,
+						sizeof(sdire), &next_block,
+						&next_offset))
+					goto failed_read;
+				
+				length += sizeof(sdire);
+				SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire);
+			} else {
+				if (!squashfs_get_cached_block(i->i_sb, (char *)
+						dire, next_block,next_offset,
+						sizeof(*dire), &next_block,
+						&next_offset))
+					goto failed_read;
+
+				length += sizeof(*dire);
+			}
+
+			if (!squashfs_get_cached_block(i->i_sb, dire->name,
+					next_block, next_offset, dire->size + 1,
+					&next_block, &next_offset))
+				goto failed_read;
+
+			length += dire->size + 1;
+
+			if (sorted && name[0] < dire->name[0])
+				goto exit_loop;
+
+			if ((len == dire->size + 1) && !strncmp(name,
+						dire->name, len)) {
+				squashfs_inode_t ino =
+					SQUASHFS_MKINODE(dirh.start_block,
+					dire->offset);
+				unsigned int inode_number = SQUASHFS_MK_VFS_INODE(dirh.start_block,
+					dire->offset);
+
+				TRACE("calling squashfs_iget for directory "
+					"entry %s, inode %x:%x, %lld\n", name,
+					dirh.start_block, dire->offset, ino);
+
+				inode = squashfs_iget(i->i_sb, ino, inode_number);
+
+				goto exit_loop;
+			}
+		}
+	}
+
+exit_loop:
+	kfree(dire);
+	d_add(dentry, inode);
+	return ERR_PTR(0);
+
+failed_read:
+	ERROR("Unable to read directory block [%llx:%x]\n", next_block,
+		next_offset);
+	goto exit_loop;
+}
+
+
+int squashfs_2_0_supported(struct squashfs_sb_info *msblk)
+{
+	struct squashfs_super_block *sblk = &msblk->sblk;
+
+	msblk->read_inode = squashfs_read_inode_2;
+	msblk->read_fragment_index_table = read_fragment_index_table_2;
+
+	sblk->bytes_used = sblk->bytes_used_2;
+	sblk->uid_start = sblk->uid_start_2;
+	sblk->guid_start = sblk->guid_start_2;
+	sblk->inode_table_start = sblk->inode_table_start_2;
+	sblk->directory_table_start = sblk->directory_table_start_2;
+	sblk->fragment_table_start = sblk->fragment_table_start_2;
+
+	return 1;
+}
diff -Nruw linux-2.6.20.14-fbx/fs/squashfs./squashfs.h linux-2.6.20.14-fbx/fs/squashfs/squashfs.h
--- linux-2.6.20.14-fbx/fs/squashfs./squashfs.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/fs/squashfs/squashfs.h	2011-09-26 15:07:55.998834410 +0200
@@ -0,0 +1,87 @@
+/*
+ * Squashfs - a compressed read only filesystem for Linux
+ *
+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007
+ * Phillip Lougher <phillip@lougher.org.uk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2,
+ * or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * squashfs.h
+ */
+
+#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
+#undef CONFIG_SQUASHFS_1_0_COMPATIBILITY
+#endif
+
+#ifdef SQUASHFS_TRACE
+#define TRACE(s, args...)	printk(KERN_NOTICE "SQUASHFS: "s, ## args)
+#else
+#define TRACE(s, args...)	{}
+#endif
+
+#define ERROR(s, args...)	printk(KERN_ERR "SQUASHFS error: "s, ## args)
+
+#define SERROR(s, args...)	do { \
+				if (!silent) \
+				printk(KERN_ERR "SQUASHFS error: "s, ## args);\
+				} while(0)
+
+#define WARNING(s, args...)	printk(KERN_WARNING "SQUASHFS: "s, ## args)
+
+static inline struct squashfs_inode_info *SQUASHFS_I(struct inode *inode)
+{
+	return list_entry(inode, struct squashfs_inode_info, vfs_inode);
+}
+
+#if defined(CONFIG_SQUASHFS_1_0_COMPATIBILITY ) || defined(CONFIG_SQUASHFS_2_0_COMPATIBILITY)
+#define SQSH_EXTERN
+extern unsigned int squashfs_read_data(struct super_block *s, char *buffer,
+				long long index, unsigned int length,
+				long long *next_index, int srclength);
+extern int squashfs_get_cached_block(struct super_block *s, char *buffer,
+				long long block, unsigned int offset,
+				int length, long long *next_block,
+				unsigned int *next_offset);
+extern void release_cached_fragment(struct squashfs_sb_info *msblk, struct
+					squashfs_fragment_cache *fragment);
+extern struct squashfs_fragment_cache *get_cached_fragment(struct super_block
+					*s, long long start_block,
+					int length);
+extern struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode, unsigned int inode_number);
+extern const struct address_space_operations squashfs_symlink_aops;
+extern const struct address_space_operations squashfs_aops;
+extern const struct address_space_operations squashfs_aops_4K;
+extern struct inode_operations squashfs_dir_inode_ops;
+#else
+#define SQSH_EXTERN static
+#endif
+
+#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
+extern int squashfs_1_0_supported(struct squashfs_sb_info *msblk);
+#else
+static inline int squashfs_1_0_supported(struct squashfs_sb_info *msblk)
+{
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY
+extern int squashfs_2_0_supported(struct squashfs_sb_info *msblk);
+#else
+static inline int squashfs_2_0_supported(struct squashfs_sb_info *msblk)
+{
+	return 0;
+}
+#endif
diff -Nruw linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx./6348_intr.h linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx/6348_intr.h
--- linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx./6348_intr.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx/6348_intr.h	2011-09-26 15:07:56.218834275 +0200
@@ -0,0 +1,80 @@
+/*
+<:copyright-gpl 
+ Copyright 2003 Broadcom Corp. All Rights Reserved. 
+ 
+ This program is free software; you can distribute it and/or modify it 
+ under the terms of the GNU General Public License (Version 2) as 
+ published by the Free Software Foundation. 
+ 
+ This program is distributed in the hope it will be useful, but WITHOUT 
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License 
+ for more details. 
+ 
+ You should have received a copy of the GNU General Public License along 
+ with this program; if not, write to the Free Software Foundation, Inc., 
+ 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. 
+:>
+*/
+
+#ifndef __6348_INTR_H
+#define __6348_INTR_H
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+/*=====================================================================*/
+/* BCM6348 External Interrupt Level Assignments                       */
+/*=====================================================================*/
+#define INTERRUPT_ID_EXTERNAL_0         3
+#define INTERRUPT_ID_EXTERNAL_1         4
+#define INTERRUPT_ID_EXTERNAL_2         5
+#define INTERRUPT_ID_EXTERNAL_3         6
+
+/*=====================================================================*/
+/* BCM6348 Timer Interrupt Level Assignments                          */
+/*=====================================================================*/
+#define MIPS_TIMER_INT                  7
+
+/*=====================================================================*/
+/* Peripheral ISR Table Offset                                              */
+/*=====================================================================*/
+#define INTERNAL_ISR_TABLE_OFFSET       8
+
+/*=====================================================================*/
+/* Logical Peripheral Interrupt IDs                                    */
+/*=====================================================================*/
+
+#define INTERRUPT_ID_TIMER               (INTERNAL_ISR_TABLE_OFFSET + 0)
+#define INTERRUPT_ID_SPI                 (INTERNAL_ISR_TABLE_OFFSET + 1)
+#define INTERRUPT_ID_UART                (INTERNAL_ISR_TABLE_OFFSET + 2)
+#define INTERRUPT_ID_ADSL                (INTERNAL_ISR_TABLE_OFFSET + 4)
+#define INTERRUPT_ID_ATM                 (INTERNAL_ISR_TABLE_OFFSET + 5)
+#define INTERRUPT_ID_USBS                (INTERNAL_ISR_TABLE_OFFSET + 6)
+#define INTERRUPT_ID_EMAC2               (INTERNAL_ISR_TABLE_OFFSET + 7)
+#define INTERRUPT_ID_EMAC1               (INTERNAL_ISR_TABLE_OFFSET + 8)
+#define INTERRUPT_ID_EPHY                (INTERNAL_ISR_TABLE_OFFSET + 9)
+#define INTERRUPT_ID_M2M                 (INTERNAL_ISR_TABLE_OFFSET + 10)
+#define INTERRUPT_ID_ACLC                (INTERNAL_ISR_TABLE_OFFSET + 11)
+#define INTERRUPT_ID_USBH                (INTERNAL_ISR_TABLE_OFFSET + 12)
+#define INTERRUPT_ID_SDRAM               (INTERNAL_ISR_TABLE_OFFSET + 13)
+#define INTERRUPT_ID_USB_CNTL_RX_DMA     (INTERNAL_ISR_TABLE_OFFSET + 14)
+#define INTERRUPT_ID_USB_CNTL_TX_DMA     (INTERNAL_ISR_TABLE_OFFSET + 15)
+#define INTERRUPT_ID_USB_BULK_RX_DMA     (INTERNAL_ISR_TABLE_OFFSET + 16)
+#define INTERRUPT_ID_USB_BULK_TX_DMA     (INTERNAL_ISR_TABLE_OFFSET + 17)
+#define INTERRUPT_ID_USB_ISO_RX_DMA      (INTERNAL_ISR_TABLE_OFFSET + 18)
+#define INTERRUPT_ID_USB_ISO_TX_DMA      (INTERNAL_ISR_TABLE_OFFSET + 19)
+#define INTERRUPT_ID_EMAC1_RX_DMA        (INTERNAL_ISR_TABLE_OFFSET + 20)
+#define INTERRUPT_ID_EMAC1_TX_DMA        (INTERNAL_ISR_TABLE_OFFSET + 21)
+#define INTERRUPT_ID_EMAC2_RX_DMA        (INTERNAL_ISR_TABLE_OFFSET + 22)
+#define INTERRUPT_ID_EMAC2_TX_DMA        (INTERNAL_ISR_TABLE_OFFSET + 23)
+#define INTERRUPT_ID_MPI                 (INTERNAL_ISR_TABLE_OFFSET + 24)
+#define INTERRUPT_ID_DG                  (INTERNAL_ISR_TABLE_OFFSET + 25)
+
+#ifdef __cplusplus
+    }
+#endif                    
+
+#endif  /* __BCM6348_H */
+
diff -Nruw linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx./6348_map_part.h linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx/6348_map_part.h
--- linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx./6348_map_part.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx/6348_map_part.h	2011-09-26 15:07:56.218834275 +0200
@@ -0,0 +1,530 @@
+/*
+<:copyright-gpl 
+ Copyright 2002 Broadcom Corp. All Rights Reserved. 
+ 
+ This program is free software; you can distribute it and/or modify it 
+ under the terms of the GNU General Public License (Version 2) as 
+ published by the Free Software Foundation. 
+ 
+ This program is distributed in the hope it will be useful, but WITHOUT 
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License 
+ for more details. 
+ 
+ You should have received a copy of the GNU General Public License along 
+ with this program; if not, write to the Free Software Foundation, Inc., 
+ 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. 
+:>
+*/
+
+#ifndef __BCM6348_MAP_H
+#define __BCM6348_MAP_H
+
+#include "bcmtypes.h"
+
+#define PERF_BASE           0xfffe0000
+#define TIMR_BASE           0xfffe0200    
+#define UART_BASE           0xfffe0300
+#define GPIO_BASE           0xfffe0400
+#define MPI_BASE            0xfffe2000    /* MPI control registers */
+#define USB_HOST_BASE       0xfffe1b00    /* USB host registers */
+#define USB_HOST_NON_OHCI   0xfffe1c00    /* USB host non-OHCI registers */
+
+typedef struct PerfControl {
+  uint32        RevID;
+  uint16        testControl;
+  uint16        blkEnables;
+#define EMAC_CLK_EN     0x0010
+#define SAR_CLK_EN      0x0020
+#define USBS_CLK_EN     0x0040
+#define USBH_CLK_EN     0x0100
+
+  uint32        pll_control;
+#define SOFT_RESET 0x00000001
+
+  uint32        IrqMask;
+  uint32        IrqStatus;
+
+  uint32        ExtIrqCfg;
+#define EI_SENSE_SHFT   0
+#define EI_STATUS_SHFT  5
+#define EI_CLEAR_SHFT   10
+#define EI_MASK_SHFT    15
+#define EI_INSENS_SHFT  20
+#define EI_LEVEL_SHFT   25
+
+  uint32        unused[4];      /* (18) */
+  uint32        BlockSoftReset; /* (28) */
+#define BSR_SPI             0x00000001
+#define BSR_EMAC            0x00000004
+#define BSR_USBH            0x00000008
+#define BSR_USBS            0x00000010
+#define BSR_ADSL            0x00000020
+#define BSR_DMAMEM          0x00000040
+#define BSR_SAR             0x00000080
+#define BSR_ACLC            0x00000100
+#define BSR_ADSL_MIPS_PLL   0x00000400
+#define BSR_ALL_BLOCKS      \
+    (BSR_SPI | BSR_EMAC | BSR_USBH | BSR_USBS | BSR_ADSL | BSR_DMAMEM | \
+     BSR_SAR | BSR_ACLC | BSR_ADSL_MIPS_PLL) 
+  uint32        unused2[2];     /* (2c) */
+  uint32        PllStrap;       /* (34) */
+#define PLL_N1_SHFT         20
+#define PLL_N1_MASK         (7<<PLL_N1_SHFT)
+#define PLL_N2_SHFT         15
+#define PLL_N2_MASK         (0x1f<<PLL_N2_SHFT)
+#define PLL_M1_REF_SHFT     12
+#define PLL_M1_REF_MASK     (7<<PLL_M1_REF_SHFT)
+#define PLL_M2_REF_SHFT     9
+#define PLL_M2_REF_MASK     (7<<PLL_M2_REF_SHFT)
+#define PLL_M1_CPU_SHFT     6
+#define PLL_M1_CPU_MASK     (7<<PLL_M1_CPU_SHFT)
+#define PLL_M1_BUS_SHFT     3
+#define PLL_M1_BUS_MASK     (7<<PLL_M1_BUS_SHFT)
+#define PLL_M2_BUS_SHFT     0
+#define PLL_M2_BUS_MASK     (7<<PLL_M2_BUS_SHFT)
+} PerfControl;
+
+#define PERF ((volatile PerfControl * const) PERF_BASE)
+
+typedef struct Timer {
+  uint16        unused0;
+  byte          TimerMask;
+#define TIMER0EN        0x01
+#define TIMER1EN        0x02
+#define TIMER2EN        0x04
+  byte          TimerInts;
+#define TIMER0          0x01
+#define TIMER1          0x02
+#define TIMER2          0x04
+#define WATCHDOG        0x08
+  uint32        TimerCtl0;
+  uint32        TimerCtl1;
+  uint32        TimerCtl2;
+#define TIMERENABLE     0x80000000
+#define RSTCNTCLR       0x40000000      
+  uint32        TimerCnt0;
+  uint32        TimerCnt1;
+  uint32        TimerCnt2;
+  uint32        WatchDogDefCount;
+
+  /* Write 0xff00 0x00ff to Start timer
+   * Write 0xee00 0x00ee to Stop and re-load default count
+   * Read from this register returns current watch dog count
+   */
+  uint32        WatchDogCtl;
+
+  /* Number of 40-MHz ticks for WD Reset pulse to last */
+  uint32        WDResetCount;
+} Timer;
+
+#define TIMER ((volatile Timer * const) TIMR_BASE)
+
+typedef struct UartChannel {
+  byte          unused0;
+  byte          control;
+#define BRGEN           0x80    /* Control register bit defs */
+#define TXEN            0x40
+#define RXEN            0x20
+#define LOOPBK          0x10
+#define TXPARITYEN      0x08
+#define TXPARITYEVEN    0x04
+#define RXPARITYEN      0x02
+#define RXPARITYEVEN    0x01
+
+  byte          config;
+#define XMITBREAK       0x40
+#define BITS5SYM        0x00
+#define BITS6SYM        0x10
+#define BITS7SYM        0x20
+#define BITS8SYM        0x30
+#define ONESTOP         0x07
+#define TWOSTOP         0x0f
+  /* 4-LSBS represent STOP bits/char
+   * in 1/8 bit-time intervals.  Zero
+   * represents 1/8 stop bit interval.
+   * Fifteen represents 2 stop bits.
+   */
+  byte          fifoctl;
+#define RSTTXFIFOS      0x80
+#define RSTRXFIFOS      0x40
+  /* 5-bit TimeoutCnt is in low bits of this register.
+   *  This count represents the number of characters 
+   *  idle times before setting receive Irq when below threshold
+   */
+  uint32        baudword;
+  /* When divide SysClk/2/(1+baudword) we should get 32*bit-rate
+   */
+
+  byte          txf_levl;       /* Read-only fifo depth */
+  byte          rxf_levl;       /* Read-only fifo depth */
+  byte          fifocfg;        /* Upper 4-bits are TxThresh, Lower are
+                                 *      RxThreshold.  Irq can be asserted
+                                 *      when rx fifo> thresh, txfifo<thresh
+                                 */
+  byte          prog_out;       /* Set value of DTR (Bit0), RTS (Bit1)
+                                 *  if these bits are also enabled to GPIO_o
+                                 */
+#define	DTREN	0x01
+#define	RTSEN	0x02
+
+  byte          unused1;
+  byte          DeltaIPEdgeNoSense;     /* Low 4-bits, set corr bit to 1 to 
+                                         * detect irq on rising AND falling 
+                                         * edges for corresponding GPIO_i
+                                         * if enabled (edge insensitive)
+                                         */
+  byte          DeltaIPConfig_Mask;     /* Upper 4 bits: 1 for posedge sense
+                                         *      0 for negedge sense if
+                                         *      not configured for edge
+                                         *      insensitive (see above)
+                                         * Lower 4 bits: Mask to enable change
+                                         *  detection IRQ for corresponding
+                                         *  GPIO_i
+                                         */
+  byte          DeltaIP_SyncIP;         /* Upper 4 bits show which bits
+                                         *  have changed (may set IRQ).
+                                         *  read automatically clears bit
+                                         * Lower 4 bits are actual status
+                                         */
+
+  uint16        intMask;				/* Same Bit defs for Mask and status */
+  uint16        intStatus;
+#define DELTAIP         0x0001
+#define TXUNDERR        0x0002
+#define TXOVFERR        0x0004
+#define TXFIFOTHOLD     0x0008
+#define TXREADLATCH     0x0010
+#define TXFIFOEMT       0x0020
+#define RXUNDERR        0x0040
+#define RXOVFERR        0x0080
+#define RXTIMEOUT       0x0100
+#define RXFIFOFULL      0x0200
+#define RXFIFOTHOLD     0x0400
+#define RXFIFONE        0x0800
+#define RXFRAMERR       0x1000
+#define RXPARERR        0x2000
+#define RXBRK           0x4000
+
+  uint16        unused2;
+  uint16        Data;                   /* Write to TX, Read from RX */
+                                        /* bits 11:8 are BRK,PAR,FRM errors */
+
+  uint32		unused3;
+  uint32		unused4;
+} Uart;
+
+#define UART ((volatile Uart * const) UART_BASE)
+
+typedef struct GpioControl {
+  uint32        GPIODir_high; /* bits 36:32 */
+  uint32        GPIODir;      /* bits 31:00 */
+  uint32        GPIOio_high;  /* bits 36:32 */
+  uint32        GPIOio;       /* bits 31:00 */
+  uint32        LEDCtrl;
+#define         LED3_STROBE             0x08000000
+#define         LED2_STROBE             0x04000000
+#define         LED1_STROBE             0x02000000
+#define         LED0_STROBE             0x01000000
+#define         LED_TEST                0x00010000
+#define         LED3_DISABLE_LINK_ACT   0x00008000
+#define         LED2_DISABLE_LINK_ACT   0x00004000
+#define         LED1_DISABLE_LINK_ACT   0x00002000
+#define         LED0_DISABLE_LINK_ACT   0x00001000
+#define         LED_INTERVAL_SET_MASK   0x00000f00
+#define         LED_INTERVAL_SET_320MS  0x00000500
+#define         LED_INTERVAL_SET_160MS  0x00000400
+#define         LED_INTERVAL_SET_80MS   0x00000300
+#define         LED_INTERVAL_SET_40MS   0x00000200
+#define         LED_INTERVAL_SET_20MS   0x00000100
+#define         LED3_ON                 0x00000080
+#define         LED2_ON                 0x00000040
+#define         LED1_ON                 0x00000020
+#define         LED0_ON                 0x00000010
+#define         LED3_ENABLE             0x00000008
+#define         LED2_ENABLE             0x00000004
+#define         LED1_ENABLE             0x00000002
+#define         LED0_ENABLE             0x00000001
+  uint32        SpiSlaveCfg;
+#define         SPI_SLAVE_RESET         0x00010000
+#define         SPI_RESTRICT            0x00000400
+#define         SPI_DELAY_DISABLE       0x00000200
+#define         SPI_PROBE_MUX_SEL_MASK  0x000001e0
+#define         SPI_SER_ADDR_CFG_MASK   0x0000000c
+#define         SPI_MODE                0x00000001
+  uint32        GPIOMode;
+#define         GROUP4_DIAG             0x00090000
+#define         GROUP4_UTOPIA           0x00080000
+#define         GROUP4_LEGACY_LED       0x00030000
+#define         GROUP4_MII_SNOOP        0x00020000
+#define         GROUP4_EXT_EPHY         0x00010000
+#define         GROUP3_DIAG             0x00009000
+#define         GROUP3_UTOPIA           0x00008000
+#define         GROUP3_EXT_MII          0x00007000
+#define         GROUP2_DIAG             0x00000900
+#define         GROUP2_PCI              0x00000500
+#define         GROUP1_DIAG             0x00000090
+#define         GROUP1_UTOPIA           0x00000080
+#define         GROUP1_SPI_UART         0x00000060
+#define         GROUP1_SPI_MASTER       0x00000060
+#define         GROUP1_MII_PCCARD       0x00000040
+#define         GROUP1_MII_SNOOP        0x00000020
+#define         GROUP1_EXT_EPHY         0x00000010
+#define         GROUP0_DIAG             0x00000009
+#define         GROUP0_EXT_MII          0x00000007
+
+} GpioControl;
+
+#define GPIO ((volatile GpioControl * const) GPIO_BASE)
+
+/* Number to mask conversion macro used for GPIODir and GPIOio */
+#define GPIO_NUM_TOTAL_BITS_MASK        0x3f
+#define GPIO_NUM_MAX_BITS_MASK          0x1f
+#define GPIO_NUM_TO_MASK(X)             ( (((X) & GPIO_NUM_TOTAL_BITS_MASK) < 32) ? (1 << ((X) & GPIO_NUM_MAX_BITS_MASK)) : (0) )
+
+/* Number to mask conversion macro used for GPIODir_high and GPIOio_high */
+#define GPIO_NUM_MAX_BITS_MASK_HIGH     0x07
+#define GPIO_NUM_TO_MASK_HIGH(X)        ( (((X) & GPIO_NUM_TOTAL_BITS_MASK) >= 32) ? (1 << ((X-32) & GPIO_NUM_MAX_BITS_MASK_HIGH)) : (0) )
+
+
+/*
+** External Bus Interface
+*/
+typedef struct EbiChipSelect {
+  uint32        base;                   /* base address in upper 24 bits */
+#define EBI_SIZE_8K         0
+#define EBI_SIZE_16K        1
+#define EBI_SIZE_32K        2
+#define EBI_SIZE_64K        3
+#define EBI_SIZE_128K       4
+#define EBI_SIZE_256K       5
+#define EBI_SIZE_512K       6
+#define EBI_SIZE_1M         7
+#define EBI_SIZE_2M         8
+#define EBI_SIZE_4M         9
+#define EBI_SIZE_8M         10
+#define EBI_SIZE_16M        11
+#define EBI_SIZE_32M        12
+#define EBI_SIZE_64M        13
+#define EBI_SIZE_128M       14
+#define EBI_SIZE_256M       15
+  uint32        config;
+#define EBI_ENABLE          0x00000001      /* .. enable this range */
+#define EBI_WAIT_STATES     0x0000000e      /* .. mask for wait states */
+#define EBI_WTST_SHIFT      1               /* .. for shifting wait states */
+#define EBI_WORD_WIDE       0x00000010      /* .. 16-bit peripheral, else 8 */
+#define EBI_WREN            0x00000020      /* enable posted writes */
+#define EBI_POLARITY        0x00000040      /* .. set to invert something, 
+                                        **    don't know what yet */
+#define EBI_TS_TA_MODE      0x00000080      /* .. use TS/TA mode */
+#define EBI_TS_SEL          0x00000100      /* .. drive tsize, not bs_b */
+#define EBI_FIFO            0x00000200      /* .. use fifo */
+#define EBI_RE              0x00000400      /* .. Reverse Endian */
+#define EBI_SETUP_SHIFT     16
+#define EBI_HOLD_SHIFT      20
+} EbiChipSelect;
+
+typedef struct MpiRegisters {
+  EbiChipSelect cs[7];                  /* size chip select configuration */
+#define EBI_CS0_BASE            0
+#define EBI_CS1_BASE            1
+#define EBI_CS2_BASE            2
+#define EBI_CS3_BASE            3
+#define PCMCIA_COMMON_BASE      4
+#define PCMCIA_ATTRIBUTE_BASE   5
+#define PCMCIA_IO_BASE          6
+  uint32        unused0[2];             /* reserved */
+  uint32        ebi_control;            /* ebi control */
+  uint32        unused1[4];             /* reserved */
+#define EBI_ACCESS_TIMEOUT      0x000007FF
+  uint32        pcmcia_cntl1;           /* pcmcia control 1 */
+#define PCCARD_CARD_RESET       0x00040000
+#define CARDBUS_ENABLE          0x00008000
+#define PCMCIA_ENABLE           0x00004000
+#define PCMCIA_GPIO_ENABLE      0x00002000
+#define CARDBUS_IDSEL           0x00001F00
+#define VS2_OEN                 0x00000080
+#define VS1_OEN                 0x00000040
+#define VS2_OUT                 0x00000020
+#define VS1_OUT                 0x00000010
+#define VS2_IN                  0x00000008
+#define VS1_IN                  0x00000004
+#define CD2_IN                  0x00000002
+#define CD1_IN                  0x00000001
+#define VS_MASK                 0x0000000C
+#define CD_MASK                 0x00000003
+  uint32        unused2;                /* reserved */
+  uint32        pcmcia_cntl2;           /* pcmcia control 2 */
+#define PCMCIA_BYTESWAP_DIS     0x00000002
+#define PCMCIA_HALFWORD_EN      0x00000001
+#define RW_ACTIVE_CNT_BIT       2
+#define INACTIVE_CNT_BIT        8
+#define CE_SETUP_CNT_BIT        16
+#define CE_HOLD_CNT_BIT         24
+  uint32        unused3[40];            /* reserved */
+
+  uint32        sp0range;               /* PCI to internal system bus address space */
+  uint32        sp0remap;
+  uint32        sp0cfg;
+  uint32        sp1range;
+  uint32        sp1remap;
+  uint32        sp1cfg;
+
+  uint32        EndianCfg;
+
+  uint32        l2pcfgctl;              /* internal system bus to PCI IO/Cfg control */
+#define DIR_CFG_SEL             0x80000000 /* change from PCI I/O access to PCI config access */
+#define DIR_CFG_USEREG          0x40000000 /* use this register info for PCI configuration access */
+#define DEVICE_NUMBER           0x00007C00 /* device number for the PCI configuration access */
+#define FUNC_NUMBER             0x00000300 /* function number for the PCI configuration access */
+#define REG_NUMBER              0x000000FC /* register number for the PCI configuration access */
+#define CONFIG_TYPE             0x00000003 /* configuration type for the PCI configuration access */
+
+  uint32        l2pmrange1;             /* internal system bus to PCI memory space */
+#define PCI_SIZE_64K            0xFFFF0000
+#define PCI_SIZE_128K           0xFFFE0000
+#define PCI_SIZE_256K           0xFFFC0000
+#define PCI_SIZE_512K           0xFFF80000
+#define PCI_SIZE_1M             0xFFF00000
+#define PCI_SIZE_2M             0xFFE00000
+#define PCI_SIZE_4M             0xFFC00000
+#define PCI_SIZE_8M             0xFF800000
+#define PCI_SIZE_16M            0xFF000000
+#define PCI_SIZE_32M            0xFE000000
+  uint32        l2pmbase1;              /* kseg0 or kseg1 address & 0x1FFFFFFF */
+  uint32        l2pmremap1;
+#define CARDBUS_MEM             0x00000004
+#define MEM_WINDOW_EN           0x00000001
+  uint32        l2pmrange2;
+  uint32        l2pmbase2;
+  uint32        l2pmremap2;
+  uint32        l2piorange;             /* internal system bus to PCI I/O space */
+  uint32        l2piobase;
+  uint32        l2pioremap;
+
+  uint32        pcimodesel;
+#define PCI2_INT_BUS_RD_PREFECH 0x000000F0
+#define PCI_BAR2_NOSWAP         0x00000002 /* BAR at offset 0x20 */
+#define PCI_BAR1_NOSWAP         0x00000001 /* BAR at affset 0x1c */
+
+  uint32        pciintstat;             /* PCI interrupt mask/status */
+#define MAILBOX1_SENT           0x08
+#define MAILBOX0_SENT           0x04
+#define MAILBOX1_MSG_RCV        0x02
+#define MAILBOX0_MSG_RCV        0x01
+  uint32        locbuscntrl;            /* internal system bus control */
+#define DIR_U2P_NOSWAP          0x00000002
+#define EN_PCI_GPIO             0x00000001
+  uint32        locintstat;             /* internal system bus interrupt mask/status */
+#define CSERR                   0x0200
+#define SERR                    0x0100
+#define EXT_PCI_INT             0x0080
+#define DIR_FAILED              0x0040
+#define DIR_COMPLETE            0x0020
+#define PCI_CFG                 0x0010
+  uint32        unused5[7];
+
+  uint32        mailbox0;
+  uint32        mailbox1;
+
+  uint32        pcicfgcntrl;            /* internal system bus PCI configuration control */
+#define PCI_CFG_REG_WRITE_EN    0x00000080
+#define PCI_CFG_ADDR            0x0000003C
+  uint32        pcicfgdata;             /* internal system bus PCI configuration data */
+
+  uint32        locch2ctl;              /* PCI to interrnal system bus DMA (downstream) local control */
+#define MPI_DMA_HALT            0x00000008  /* idle after finish current memory burst */
+#define MPI_DMA_PKT_HALT        0x00000004  /* idle after an EOP flag is detected */
+#define MPI_DMA_STALL           0x00000002  /* idle after an EOP flag is detected */
+#define MPI_DMA_ENABLE          0x00000001  /* set to enable channel */
+  uint32        locch2intStat;
+#define MPI_DMA_NO_DESC         0x00000004  /* no valid descriptors */
+#define MPI_DMA_DONE            0x00000002  /* packet xfer complete */
+#define MPI_DMA_BUFF_DONE       0x00000001  /* buffer done */
+  uint32        locch2intMask;
+  uint32        unused6;
+  uint32        locch2descaddr;
+  uint32        locch2status1;
+#define LOCAL_DESC_STATE        0xE0000000
+#define PCI_DESC_STATE          0x1C000000
+#define BYTE_DONE               0x03FFC000
+#define RING_ADDR               0x00003FFF
+  uint32        locch2status2;
+#define BUFPTR_OFFSET           0x1FFF0000
+#define PCI_MASTER_STATE        0x000000C0
+#define LOC_MASTER_STATE        0x00000038
+#define CONTROL_STATE           0x00000007
+  uint32        unused7;
+
+  uint32        locch1Ctl;              /*internal system bus to PCI DMA (upstream) local control */
+#define DMA_U2P_LE              0x00000200  /* local bus is little endian */
+#define DMA_U2P_NOSWAP          0x00000100  /* lccal bus is little endian but no data swapped */
+  uint32        locch1intstat;
+  uint32        locch1intmask;
+  uint32        unused8;
+  uint32        locch1descaddr;
+  uint32        locch1status1;
+  uint32        locch1status2;
+  uint32        unused9;
+
+  uint32        pcich1ctl;              /* internal system bus to PCI DMA PCI control */
+  uint32        pcich1intstat;
+  uint32        pcich1intmask;
+  uint32        pcich1descaddr;
+  uint32        pcich1status1;
+  uint32        pcich1status2;
+
+  uint32        pcich2Ctl;              /* PCI to internal system bus DMA PCI control */
+  uint32        pcich2intstat;
+  uint32        pcich2intmask;
+  uint32        pcich2descaddr;
+  uint32        pcich2status1;
+  uint32        pcich2status2;
+
+  uint32        perm_id;                /* permanent device and vendor id */
+  uint32        perm_rev;               /* permanent revision id */
+} MpiRegisters;
+
+#define MPI ((volatile MpiRegisters * const) MPI_BASE)
+
+/* PCI configuration address space start offset 0x40 */
+#define BRCM_PCI_CONFIG_TIMER               0x40
+#define BRCM_PCI_CONFIG_TIMER_RETRY_MASK	0x0000FF00
+#define BRCM_PCI_CONFIG_TIMER_TRDY_MASK		0x000000FF
+
+/* USB host non-Open HCI register, USB_HOST_NON_OHCI, bit definitions. */
+#define NON_OHCI_ENABLE_PORT1   0x00000001 /* Use USB port 1 for host, not dev */
+#define NON_OHCI_BYTE_SWAP      0x00000008 /* Swap USB host registers */
+
+#define USBH_NON_OHCI ((volatile unsigned long * const) USB_HOST_NON_OHCI)
+
+struct			m2m_dma_regs
+{
+	unsigned int	src;
+	unsigned int	dst;
+	unsigned int	size;
+	unsigned int	control;
+	unsigned int	status;
+	unsigned int	srcid;
+	unsigned int	dstid;
+};
+
+#define M2M_BASE   0xfffe2800
+
+#define m2m_rx ((volatile struct m2m_dma_regs *) (M2M_BASE))
+#define m2m_tx ((volatile struct m2m_dma_regs *) (M2M_BASE + 0x40))
+
+#define M2M_CTRL_ENABLE         (0x1 << 0)
+#define M2M_CTRL_IRQEN          (0x1 << 1)
+#define M2M_CTRL_ERROR_CLR      (0x1 << 6)
+#define M2M_CTRL_DONE_CLR       (0x1 << 7)
+#define M2M_CTRL_NOINC          (0x1 << 8)
+#define M2M_CTRL_PCMCIASWAP     (0x1 << 9)
+#define M2M_CTRL_SWAPBYTE       (0x1 << 10)
+#define M2M_CTRL_ENDIAN         (0x1 << 11)
+
+#define M2M_STAT_DONE           (0x1 << 0)
+#define M2M_STAT_ERROR          (0x1 << 1)
+
+#endif
+
diff -Nruw linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx./bcm963xx_clk.h linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx/bcm963xx_clk.h
--- linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx./bcm963xx_clk.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx/bcm963xx_clk.h	2011-09-26 15:07:56.218834275 +0200
@@ -0,0 +1,6 @@
+#ifndef BCM963XX_CLK_H_
+#define BCM963XX_CLK_H_
+
+#define BCM963XX_FPERIPH	(50 * 1000 * 1000)
+
+#endif /* ! BCM963XX_CLK_H_ */
diff -Nruw linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx./bcm963xx_cpu.h linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx/bcm963xx_cpu.h
--- linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx./bcm963xx_cpu.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx/bcm963xx_cpu.h	2011-09-26 15:07:56.218834275 +0200
@@ -0,0 +1,74 @@
+#ifndef BCM963XX_CPU_H_
+#define BCM963XX_CPU_H_
+
+#include <linux/types.h>
+
+#define BCM6338_CPU_ID		0x6338
+#define BCM6345_CPU_ID		0x6345
+#define BCM6348_CPU_ID		0x6348
+#define BCM6358_CPU_ID		0x6358
+
+u16 __bcm963xx_get_cpu_id(void);
+u16 bcm963xx_get_cpu_rev(void);
+unsigned int bcm963xx_get_cpu_freq(void);
+
+/*
+ * idea stolen from arm mach-types.h
+ */
+#ifdef CONFIG_BCM963XX_CPU_6338
+# ifdef bcm963xx_get_cpu_id
+#  undef bcm963xx_get_cpu_id
+#  define bcm963xx_get_cpu_id()	__bcm963xx_get_cpu_id()
+#  define BCMCPU_RUNTIME_DETECT
+# else
+#  define bcm963xx_get_cpu_id()	BCM6338_CPU_ID
+# endif
+# define BCMCPU_IS_6338()	(bcm963xx_get_cpu_id() == BCM6338_CPU_ID)
+#else
+# define BCMCPU_IS_6338()	(0)
+#endif
+
+#ifdef CONFIG_BCM963XX_CPU_6345
+# ifdef bcm963xx_get_cpu_id
+#  undef bcm963xx_get_cpu_id
+#  define bcm963xx_get_cpu_id()	__bcm963xx_get_cpu_id()
+#  define BCMCPU_RUNTIME_DETECT
+# else
+#  define bcm963xx_get_cpu_id()	BCM6345_CPU_ID
+# endif
+# define BCMCPU_IS_6345()	(bcm963xx_get_cpu_id() == BCM6345_CPU_ID)
+#else
+# define BCMCPU_IS_6345()	(0)
+#endif
+
+#ifdef CONFIG_BCM963XX_CPU_6348
+# ifdef bcm963xx_get_cpu_id
+#  undef bcm963xx_get_cpu_id
+#  define bcm963xx_get_cpu_id()	__bcm963xx_get_cpu_id()
+#  define BCMCPU_RUNTIME_DETECT
+# else
+#  define bcm963xx_get_cpu_id()	BCM6348_CPU_ID
+# endif
+# define BCMCPU_IS_6348()	(bcm963xx_get_cpu_id() == BCM6348_CPU_ID)
+#else
+# define BCMCPU_IS_6348()	(0)
+#endif
+
+#ifdef CONFIG_BCM963XX_CPU_6358
+# ifdef bcm963xx_get_cpu_id
+#  undef bcm963xx_get_cpu_id
+#  define bcm963xx_get_cpu_id()	__bcm963xx_get_cpu_id()
+#  define BCMCPU_RUNTIME_DETECT
+# else
+#  define bcm963xx_get_cpu_id()	BCM6358_CPU_ID
+# endif
+# define BCMCPU_IS_6358()	(bcm963xx_get_cpu_id() == BCM6358_CPU_ID)
+#else
+# define BCMCPU_IS_6358()	(0)
+#endif
+
+#ifndef bcm963xx_get_cpu_id
+#error "No CPU support configured"
+#endif
+
+#endif /* !BCM963XX_CPU_H_ */
diff -Nruw linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx./bcm963xx_cs.h linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx/bcm963xx_cs.h
--- linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx./bcm963xx_cs.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx/bcm963xx_cs.h	2011-09-26 15:07:56.218834275 +0200
@@ -0,0 +1,13 @@
+/*
+ * chip select configuration
+ */
+#ifndef BCM963XX_CS_H
+# define BCM963XX_CS_H
+
+int bcm963xx_set_cs_base(unsigned int cs, u32 base, unsigned int size);
+int bcm963xx_set_cs_timing(unsigned int cs, unsigned int wait,
+			   unsigned int setup, unsigned int hold);
+int bcm963xx_set_cs_param(unsigned int cs, u32 flags);
+int bcm963xx_set_cs_status(unsigned int cs, int enable);
+
+#endif /* !BCM963XX_CS_H */
diff -Nruw linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx./bcm963xx_gpio.h linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx/bcm963xx_gpio.h
--- linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx./bcm963xx_gpio.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx/bcm963xx_gpio.h	2011-09-26 15:07:56.218834275 +0200
@@ -0,0 +1,36 @@
+/*
+ * gpio for broadcom 963xx
+ */
+
+#ifndef BCM963XX_GPIO_H
+# define BCM963XX_GPIO_H
+
+#include "bcm963xx_cpu.h"
+
+void bcm963xx_gpio_set_dataout(int gpio, int val);
+int bcm963xx_gpio_get_datain(int gpio);
+void bcm963xx_gpio_set_direction(int gpio, int is_input);
+
+#define GPIO_DIR_OUT	0x0
+#define GPIO_DIR_IN	0x1
+
+/*
+ * all helpers will BUG() if gpio number >= than the return value of
+ * this function.
+ */
+static inline unsigned long bcm963xx_gpio_count(void)
+{
+	switch (bcm963xx_get_cpu_id()) {
+	case BCM6358_CPU_ID:
+		return 40;
+	case BCM6348_CPU_ID:
+	default:
+		/*
+		 * XXX: assume 37 for all other broadcom chip of the
+		 * 963xx family.
+		 */
+		return 37;
+	}
+}
+
+#endif /* !BCM963XX_GPIO_H */
diff -Nruw linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx./bcm963xx_io.h linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx/bcm963xx_io.h
--- linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx./bcm963xx_io.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx/bcm963xx_io.h	2011-09-26 15:07:56.218834275 +0200
@@ -0,0 +1,194 @@
+#ifndef BCM963XX_IO_H_
+#define BCM963XX_IO_H_
+
+#include "bcm963xx_cpu.h"
+#include "bcm963xx_regs.h"
+
+/*
+ * Physical memory map, RAM is mapped at 0x0.
+ *
+ * Note that size MUST be a power of two.
+ */
+#define BCM_PCMCIA_COMMON_BASE_PA	(0x20000000)
+#define BCM_PCMCIA_COMMON_SIZE		(16 * 1024 * 1024)
+#define BCM_PCMCIA_COMMON_END_PA	(BCM_PCMCIA_COMMON_BASE_PA +	\
+					 BCM_PCMCIA_COMMON_SIZE - 1)
+
+#define BCM_PCMCIA_ATTR_BASE_PA		(0x21000000)
+#define BCM_PCMCIA_ATTR_SIZE		(16 * 1024 * 1024)
+#define BCM_PCMCIA_ATTR_END_PA		(BCM_PCMCIA_ATTR_BASE_PA +	\
+					 BCM_PCMCIA_ATTR_SIZE - 1)
+
+#define BCM_PCMCIA_IO_BASE_PA		(0x22000000)
+#define BCM_PCMCIA_IO_SIZE		(64 * 1024)
+#define BCM_PCMCIA_IO_END_PA		(BCM_PCMCIA_IO_BASE_PA +	\
+					BCM_PCMCIA_IO_SIZE - 1)
+
+#define BCM_PCI_MEM_BASE_PA		(0x30000000)
+#define BCM_PCI_MEM_SIZE		(128 * 1024 * 1024)
+#define BCM_PCI_MEM_END_PA		(BCM_PCI_MEM_BASE_PA +		\
+					BCM_PCI_MEM_SIZE - 1)
+
+#define BCM_PCI_IO_BASE_PA		(0x08000000)
+#define BCM_PCI_IO_SIZE			(64 * 1024)
+#define BCM_PCI_IO_END_PA		(BCM_PCI_IO_BASE_PA +		\
+					BCM_PCI_IO_SIZE - 1)
+#define BCM_PCI_IO_HALF_PA		(BCM_PCI_IO_BASE_PA +		\
+					(BCM_PCI_IO_SIZE / 2) - 1)
+
+#define BCM_CB_MEM_BASE_PA		(0x38000000)
+#define BCM_CB_MEM_SIZE			(128 * 1024 * 1024)
+#define BCM_CB_MEM_END_PA		(BCM_CB_MEM_BASE_PA +		\
+					BCM_CB_MEM_SIZE - 1)
+
+
+/*
+ * Internal registers are accessed through KSEG3
+ */
+#define BCM_REGS_VA(x)	((void __iomem *)(x))
+
+#define bcm_readb(a)	(*(volatile unsigned char *)	BCM_REGS_VA(a))
+#define bcm_readw(a)	(*(volatile unsigned short *)	BCM_REGS_VA(a))
+#define bcm_readl(a)	(*(volatile unsigned int *)	BCM_REGS_VA(a))
+#define bcm_writeb(v,a)	(*(volatile unsigned char *)	BCM_REGS_VA((a)) = (v))
+#define bcm_writew(v,a)	(*(volatile unsigned short *)	BCM_REGS_VA((a)) = (v))
+#define bcm_writel(v,a)	(*(volatile unsigned int *)	BCM_REGS_VA((a)) = (v))
+
+/*
+ * While registers sets are mostly the same across 63xx CPU, base
+ * address of these sets do change.
+ */
+extern unsigned long *bcm963xx_regs_base;
+
+static inline unsigned long bcm_reg_address(enum bcm963xx_regs_set set)
+{
+#ifdef BCMCPU_RUNTIME_DETECT
+	return bcm963xx_regs_base[set];
+#else
+#ifdef CONFIG_BCM963XX_CPU_6348
+	switch (set) {
+	case RSET_DSL_LMEM:
+		return BCM_6348_DSL_LMEM_BASE;
+	case RSET_PERF:
+		return BCM_6348_PERF_BASE;
+	case RSET_TIMER:
+		return BCM_6348_TIMER_BASE;
+	case RSET_WDT:
+		return BCM_6348_WDT_BASE;
+	case RSET_UART0:
+		return BCM_6348_UART0_BASE;
+	case RSET_GPIO:
+		return BCM_6348_GPIO_BASE;
+	case RSET_SPI:
+		return BCM_6348_SPI_BASE;
+	case RSET_UDC0:
+		return BCM_6348_UDC0_BASE;
+	case RSET_OHCI0:
+		return BCM_6348_OHCI0_BASE;
+	case RSET_OHCI_PRIV:
+		return BCM_6348_OHCI_PRIV_BASE;
+	case RSET_USBH_PRIV:
+		return BCM_6348_USBH_PRIV_BASE;
+	case RSET_MPI:
+		return BCM_6348_MPI_BASE;
+	case RSET_PCMCIA:
+		return BCM_6348_PCMCIA_BASE;
+	case RSET_DSL:
+		return BCM_6348_DSL_BASE;
+	case RSET_ENET0:
+		return BCM_6348_ENET0_BASE;
+	case RSET_ENET1:
+		return BCM_6348_ENET1_BASE;
+	case RSET_ENETDMA:
+		return BCM_6348_ENETDMA_BASE;
+	case RSET_EHCI0:
+		return BCM_6348_EHCI0_BASE;
+	case RSET_SDRAM:
+		return BCM_6348_SDRAM_BASE;
+	case RSET_MEMC:
+		return BCM_6348_MEMC_BASE;
+	case RSET_ATM:
+		return BCM_6348_ATM_BASE;
+	}
+#endif
+#ifdef CONFIG_BCM963XX_CPU_6358
+	switch (set) {
+	case RSET_DSL_LMEM:
+		return BCM_6358_DSL_LMEM_BASE;
+	case RSET_PERF:
+		return BCM_6358_PERF_BASE;
+	case RSET_TIMER:
+		return BCM_6358_TIMER_BASE;
+	case RSET_WDT:
+		return BCM_6358_WDT_BASE;
+	case RSET_UART0:
+		return BCM_6358_UART0_BASE;
+	case RSET_GPIO:
+		return BCM_6358_GPIO_BASE;
+	case RSET_SPI:
+		return BCM_6358_SPI_BASE;
+	case RSET_UDC0:
+		return BCM_6358_UDC0_BASE;
+	case RSET_OHCI0:
+		return BCM_6358_OHCI0_BASE;
+	case RSET_OHCI_PRIV:
+		return BCM_6358_OHCI_PRIV_BASE;
+	case RSET_USBH_PRIV:
+		return BCM_6358_USBH_PRIV_BASE;
+	case RSET_MPI:
+		return BCM_6358_MPI_BASE;
+	case RSET_PCMCIA:
+		return BCM_6358_PCMCIA_BASE;
+	case RSET_ENET0:
+		return BCM_6358_ENET0_BASE;
+	case RSET_ENET1:
+		return BCM_6358_ENET1_BASE;
+	case RSET_ENETDMA:
+		return BCM_6358_ENETDMA_BASE;
+	case RSET_DSL:
+		return BCM_6358_DSL_BASE;
+	case RSET_EHCI0:
+		return BCM_6358_EHCI0_BASE;
+	case RSET_SDRAM:
+		return BCM_6358_SDRAM_BASE;
+	case RSET_MEMC:
+		return BCM_6358_MEMC_BASE;
+	case RSET_ATM:
+		return BCM_6358_ATM_BASE;
+	}
+#endif
+#endif
+	/* unreached */
+	return 0;
+}
+
+#define bcm_rset_readb(s,o)	bcm_readb(bcm_reg_address(s) + (o))
+#define bcm_rset_readw(s,o)	bcm_readw(bcm_reg_address(s) + (o))
+#define bcm_rset_readl(s,o)	bcm_readl(bcm_reg_address(s) + (o))
+#define bcm_rset_writeb(s,v,o)	bcm_writeb((v), bcm_reg_address(s) + (o))
+#define bcm_rset_writew(s,v,o)	bcm_writew((v), bcm_reg_address(s) + (o))
+#define bcm_rset_writel(s,v,o)	bcm_writel((v), bcm_reg_address(s) + (o))
+
+/*
+ * helpers for frequently used register sets
+ */
+#define bcm_perf_readl(o)	bcm_rset_readl(RSET_PERF, (o))
+#define bcm_perf_writel(v,o)	bcm_rset_writel(RSET_PERF, (v), (o))
+#define bcm_timer_readl(o)	bcm_rset_readl(RSET_TIMER, (o))
+#define bcm_timer_writel(v,o)	bcm_rset_writel(RSET_TIMER, (v), (o))
+#define bcm_wdt_readl(o)	bcm_rset_readl(RSET_WDT, (o))
+#define bcm_wdt_writel(v,o)	bcm_rset_writel(RSET_WDT, (v), (o))
+#define bcm_gpio_readl(o)	bcm_rset_readl(RSET_GPIO, (o))
+#define bcm_gpio_writel(v,o)	bcm_rset_writel(RSET_GPIO, (v), (o))
+#define bcm_uart0_readl(o)	bcm_rset_readl(RSET_UART0, (o))
+#define bcm_uart0_writel(v,o)	bcm_rset_writel(RSET_UART0, (v), (o))
+#define bcm_mpi_readl(o)	bcm_rset_readl(RSET_MPI, (o))
+#define bcm_mpi_writel(v,o)	bcm_rset_writel(RSET_MPI, (v), (o))
+#define bcm_pcmcia_readl(o)	bcm_rset_readl(RSET_PCMCIA, (o))
+#define bcm_pcmcia_writel(v,o)	bcm_rset_writel(RSET_PCMCIA, (v), (o))
+#define bcm_sdram_readl(o)	bcm_rset_readl(RSET_SDRAM, (o))
+#define bcm_sdram_writel(v,o)	bcm_rset_writel(RSET_SDRAM, (v), (o))
+#define bcm_memc_readl(o)	bcm_rset_readl(RSET_MEMC, (o))
+#define bcm_memc_writel(v,o)	bcm_rset_writel(RSET_MEMC, (v), (o))
+
+#endif /* ! BCM963XX_IO_H_ */
diff -Nruw linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx./bcm963xx_irq.h linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx/bcm963xx_irq.h
--- linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx./bcm963xx_irq.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx/bcm963xx_irq.h	2011-09-26 15:07:56.218834275 +0200
@@ -0,0 +1,97 @@
+#ifndef BCM963XX_IRQ_H_
+#define BCM963XX_IRQ_H_
+
+#define IRQ_MIPS_BASE			0
+#define IRQ_INTERNAL_BASE		8
+
+#define IRQ_EXT_BASE			(IRQ_MIPS_BASE + 3)
+#define IRQ_EXT_0			(IRQ_EXT_BASE + 0)
+#define IRQ_EXT_1			(IRQ_EXT_BASE + 1)
+#define IRQ_EXT_2			(IRQ_EXT_BASE + 2)
+#define IRQ_EXT_3			(IRQ_EXT_BASE + 3)
+
+/*
+ * 6348 irqs
+ */
+#define BCM_6348_TIMER_IRQ		(IRQ_INTERNAL_BASE + 0)
+#define BCM_6348_UART0_IRQ		(IRQ_INTERNAL_BASE + 2)
+#define BCM_6348_DSL_IRQ		(IRQ_INTERNAL_BASE + 4)
+#define BCM_6348_ATM_IRQ		(IRQ_INTERNAL_BASE + 5)
+#define BCM_6348_UDC0_IRQ		(IRQ_INTERNAL_BASE + 6)
+#define BCM_6348_ENET1_IRQ		(IRQ_INTERNAL_BASE + 7)
+#define BCM_6348_ENET0_IRQ		(IRQ_INTERNAL_BASE + 8)
+#define BCM_6348_ENET_PHY_IRQ		(IRQ_INTERNAL_BASE + 9)
+#define BCM_6348_OHCI0_IRQ		(IRQ_INTERNAL_BASE + 12)
+#define BCM_6348_UDC0_CTL_RX_IRQ	(IRQ_INTERNAL_BASE + 14)
+#define BCM_6348_UDC0_CTL_TX_IRQ	(IRQ_INTERNAL_BASE + 15)
+#define BCM_6348_UDC0_BULK_RX_IRQ	(IRQ_INTERNAL_BASE + 16)
+#define BCM_6348_UDC0_BULK_TX_IRQ	(IRQ_INTERNAL_BASE + 17)
+#define BCM_6348_UDC0_ISO_RX_IRQ	(IRQ_INTERNAL_BASE + 18)
+#define BCM_6348_UDC0_ISO_TX_IRQ	(IRQ_INTERNAL_BASE + 19)
+#define BCM_6348_ENET0_RXDMA_IRQ	(IRQ_INTERNAL_BASE + 20)
+#define BCM_6348_ENET0_TXDMA_IRQ	(IRQ_INTERNAL_BASE + 21)
+#define BCM_6348_ENET1_RXDMA_IRQ	(IRQ_INTERNAL_BASE + 22)
+#define BCM_6348_ENET1_TXDMA_IRQ	(IRQ_INTERNAL_BASE + 23)
+#define BCM_6348_PCMCIA_IRQ		(IRQ_INTERNAL_BASE + 24)
+#define BCM_6348_PCI_IRQ		(IRQ_INTERNAL_BASE + 24)
+
+/*
+ * 6358 irqs
+ */
+#define BCM_6358_TIMER_IRQ		(IRQ_INTERNAL_BASE + 0)
+#define BCM_6358_UART0_IRQ		(IRQ_INTERNAL_BASE + 2)
+#define BCM_6358_OHCI0_IRQ		(IRQ_INTERNAL_BASE + 5)
+#define BCM_6358_ENET1_IRQ		(IRQ_INTERNAL_BASE + 6)
+#define BCM_6358_UDC0_IRQ		(IRQ_INTERNAL_BASE + 7)
+#define BCM_6358_ENET0_IRQ		(IRQ_INTERNAL_BASE + 8)
+#define BCM_6358_ENET_PHY_IRQ		(IRQ_INTERNAL_BASE + 9)
+#define BCM_6358_EHCI0_IRQ		(IRQ_INTERNAL_BASE + 10)
+#define BCM_6358_ENET0_RXDMA_IRQ	(IRQ_INTERNAL_BASE + 15)
+#define BCM_6358_ENET0_TXDMA_IRQ	(IRQ_INTERNAL_BASE + 16)
+#define BCM_6358_ENET1_RXDMA_IRQ	(IRQ_INTERNAL_BASE + 17)
+#define BCM_6358_ENET1_TXDMA_IRQ	(IRQ_INTERNAL_BASE + 18)
+#define BCM_6358_ATM_IRQ		(IRQ_INTERNAL_BASE + 19)
+#define BCM_6358_DSL_IRQ		(IRQ_INTERNAL_BASE + 29)
+#define BCM_6358_PCI_IRQ		(IRQ_INTERNAL_BASE + 31)
+#define BCM_6358_UDC0_CTL_RX_IRQ	(IRQ_INTERNAL_BASE + 14)
+#define BCM_6358_UDC0_CTL_TX_IRQ	(IRQ_INTERNAL_BASE + 15)
+#define BCM_6358_UDC0_BULK_RX_IRQ	(IRQ_INTERNAL_BASE + 16)
+#define BCM_6358_UDC0_BULK_TX_IRQ	(IRQ_INTERNAL_BASE + 17)
+#define BCM_6358_UDC0_ISO_RX_IRQ	(IRQ_INTERNAL_BASE + 18)
+#define BCM_6358_UDC0_ISO_TX_IRQ	(IRQ_INTERNAL_BASE + 19)
+#define BCM_6358_PCMCIA_IRQ		(IRQ_INTERNAL_BASE + 24)
+
+enum bcm963xx_irq {
+	IRQ_TIMER = 0,
+	IRQ_UART0,
+	IRQ_DSL,
+	IRQ_UDC0,
+	IRQ_ENET0,
+	IRQ_ENET1,
+	IRQ_ENET_PHY,
+	IRQ_OHCI0,
+	IRQ_EHCI0,
+	IRQ_UDC0_CTL_RX,
+	IRQ_UDC0_CTL_TX,
+	IRQ_UDC0_BULK_RX,
+	IRQ_UDC0_BULK_TX,
+	IRQ_UDC0_ISO_RX,
+	IRQ_UDC0_ISO_TX,
+	IRQ_PCMCIA0,
+	IRQ_ENET0_RXDMA,
+	IRQ_ENET0_TXDMA,
+	IRQ_ENET1_RXDMA,
+	IRQ_ENET1_TXDMA,
+	IRQ_PCI,
+	IRQ_PCMCIA,
+	IRQ_ATM,
+};
+
+extern int *bcm963xx_irqs;
+
+static inline int bcm_irq_number(enum bcm963xx_irq irq)
+{
+	return bcm963xx_irqs[irq];
+}
+
+#endif /* ! BCM963XX_IRQ_H_ */
diff -Nruw linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx./bcm963xx_regs.h linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx/bcm963xx_regs.h
--- linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx./bcm963xx_regs.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx/bcm963xx_regs.h	2011-09-26 15:07:56.218834275 +0200
@@ -0,0 +1,825 @@
+#ifndef BCM963XX_REGS_H_
+#define BCM963XX_REGS_H_
+
+/*
+ * CPU "register" sets and their size
+ */
+enum bcm963xx_regs_set {
+	RSET_DSL_LMEM = 0,
+	RSET_PERF,
+	RSET_TIMER,
+	RSET_WDT,
+	RSET_UART0,
+	RSET_GPIO,
+	RSET_SPI,
+	RSET_UDC0,
+	RSET_OHCI0,
+	RSET_OHCI_PRIV,
+	RSET_USBH_PRIV,
+	RSET_MPI,
+	RSET_PCMCIA,
+	RSET_DSL,
+	RSET_ENET0,
+	RSET_ENET1,
+	RSET_ENETDMA,
+	RSET_EHCI0,
+	RSET_SDRAM,
+	RSET_MEMC,
+	RSET_ATM,
+};
+
+#define RSET_DSL_LMEM_SIZE		(64 * 1024 * 4)
+#define RSET_DSL_SIZE			4096
+#define RSET_WDT_SIZE			12
+#define RSET_ENET_SIZE			2048
+#define RSET_ENETDMA_SIZE		2048
+#define RSET_UART_SIZE			24
+#define RSET_UDC_SIZE			256
+#define RSET_OHCI_SIZE			256
+#define RSET_EHCI_SIZE			256
+#define RSET_PCMCIA_SIZE		12
+#define RSET_ATM_SIZE			4096
+
+/*
+ * 6348 register sets base address
+ */
+#define BCM_6348_DSL_LMEM_BASE		(0xfff00000)
+#define BCM_6348_PERF_BASE		(0xfffe0000)
+#define BCM_6348_TIMER_BASE		(0xfffe0200)
+#define BCM_6348_WDT_BASE		(0xfffe021c)
+#define BCM_6348_UART0_BASE		(0xfffe0300)
+#define BCM_6348_GPIO_BASE		(0xfffe0400)
+#define BCM_6348_SPI_BASE		(0xfffe0c00)
+#define BCM_6348_UDC0_BASE		(0xfffe1000)
+#define BCM_6348_OHCI0_BASE		(0xfffe1b00)
+#define BCM_6348_OHCI_PRIV_BASE		(0xfffe1c00)
+#define BCM_6348_USBH_PRIV_BASE		(0xdeadbeef)
+#define BCM_6348_MPI_BASE		(0xfffe2000)
+#define BCM_6348_PCMCIA_BASE		(0xfffe2054)
+#define BCM_6348_DSL_BASE		(0xfffe3000)
+#define BCM_6348_ENET0_BASE		(0xfffe6000)
+#define BCM_6348_ENET1_BASE		(0xfffe6800)
+#define BCM_6348_ENETDMA_BASE		(0xfffe7000)
+#define BCM_6348_EHCI0_BASE		(0xdeadbeef)
+#define BCM_6348_SDRAM_BASE		(0xfffe2300)
+#define BCM_6348_MEMC_BASE		(0xdeadbeef)
+#define BCM_6348_ATM_BASE		(0xfffe4000)
+
+/*
+ * 6358 register sets base address
+ */
+#define BCM_6358_DSL_LMEM_BASE		(0xfff00000)
+#define BCM_6358_PERF_BASE		(0xfffe0000)
+#define BCM_6358_TIMER_BASE		(0xfffe0040)
+#define BCM_6358_WDT_BASE		(0xfffe005c)
+#define BCM_6358_UART0_BASE		(0xfffe0100)
+#define BCM_6358_GPIO_BASE		(0xfffe0080)
+#define BCM_6358_SPI_BASE		(0xdeadbeef)
+#define BCM_6358_UDC0_BASE		(0xfffe0800)
+#define BCM_6358_OHCI0_BASE		(0xfffe1400)
+#define BCM_6358_OHCI_PRIV_BASE		(0xdeadbeef)
+#define BCM_6358_USBH_PRIV_BASE		(0xfffe1500)
+#define BCM_6358_MPI_BASE		(0xfffe1000)
+#define BCM_6358_PCMCIA_BASE		(0xfffe1054)
+#define BCM_6358_DSL_BASE		(0xfffe3000)
+#define BCM_6358_ENET0_BASE		(0xfffe4000)
+#define BCM_6358_ENET1_BASE		(0xfffe4800)
+#define BCM_6358_ENETDMA_BASE		(0xfffe5000)
+#define BCM_6358_EHCI0_BASE		(0xfffe1300)
+#define BCM_6358_SDRAM_BASE		(0xdeadbeef)
+#define BCM_6358_MEMC_BASE		(0xfffe1200)
+#define BCM_6358_ATM_BASE		(0xfffe2000)
+
+
+/*************************************************************************
+ * _REG relative to RSET_PERF
+ *************************************************************************/
+
+/* Chip Identifier / Revision register */
+#define PERF_REV_REG			0x0
+#define REV_CHIPID_SHIFT		16
+#define REV_CHIPID_MASK			(0xffff << REV_CHIPID_SHIFT)
+#define REV_REVID_SHIFT			0
+#define REV_REVID_MASK			(0xffff << REV_REVID_SHIFT)
+
+/* clock control register */
+#define PERF_CKCTL_REG			0x4
+#define CKCTL_ADSLPHY_EN		(1 << 0)
+#define CKCTL_MPI_EN			(1 << 1)
+#define CKCTL_SRAM_EN			(1 << 2)
+#define CKCTL_M2M_EN			(1 << 3)
+#define CKCTL_EMAC_EN			(1 << 4)
+#define CKCTL_SAR_EN			(1 << 5)
+#define CKCTL_USBDEV_EN			(1 << 6)
+#define CKCTL_USBHOST_EN		(1 << 8)
+#define CKCTL_SPI_EN			(1 << 9)
+
+/* System PLL Control register  */
+#define PERF_SYS_PLL_CTL_REG		0x8
+#define SYS_PLL_SOFT_RESET		0x1
+
+/* Interrupt Mask register */
+#define PERF_IRQMASK_REG		0xc
+#define PERF_IRQSTAT_REG		0x10
+
+/* Interrupt Status register */
+#define PERF_IRQSTAT_REG		0x10
+
+/* External Interrupt Configuration register */
+#define PERF_EXTIRQ_CFG_REG		0x14
+#define EXTIRQ_CFG_SENSE(x)		(1 << (x))
+#define EXTIRQ_CFG_STAT(x)		(1 << (x + 5))
+#define EXTIRQ_CFG_CLEAR(x)		(1 << (x + 10))
+#define EXTIRQ_CFG_MASK(x)		(1 << (x + 15))
+#define EXTIRQ_CFG_BOTHEDGE(x)		(1 << (x + 20))
+#define EXTIRQ_CFG_LEVELSENSE(x)	(1 << (x + 25))
+
+#define EXTIRQ_CFG_CLEAR_ALL		(0xf << 10)
+#define EXTIRQ_CFG_MASK_ALL		(0xf << 15)
+
+/* Soft Reset register */
+#define PERF_SOFTRESET_REG		0x28
+#define SOFTRESET_SPI_MASK		(1 << 0)
+#define SOFTRESET_ENET_MASK		(1 << 2)
+#define SOFTRESET_USBH_MASK		(1 << 3)
+#define SOFTRESET_USBS_MASK		(1 << 4)
+#define SOFTRESET_ADSL_MASK		(1 << 5)
+#define SOFTRESET_DMAMEM_MASK		(1 << 6)
+#define SOFTRESET_SAR_MASK		(1 << 7)
+#define SOFTRESET_ACLC_MASK		(1 << 8)
+#define SOFTRESET_ADSLMIPSPLL_MASK	(1 << 10)
+
+#define SOFTRESET_ALL_BLOCKS	 (SOFTRESET_SPI_MASK |		\
+				  SOFTRESET_ENET_MASK |		\
+				  SOFTRESET_USBH_MASK |		\
+				  SOFTRESET_USBS_MASK |		\
+				  SOFTRESET_ADSL_MASK |		\
+				  SOFTRESET_DMAMEM_MASK |	\
+				  SOFTRESET_SAR_MASK |		\
+				  SOFTRESET_ACLC_MASK |		\
+				  SOFTRESET_ADSLMIPSPLL_MASK)
+
+/* MIPS PLL control register */
+#define PERF_MIPSPLLCTL_REG		0x34
+#define MIPSPLLCTL_N1_SHIFT		20
+#define MIPSPLLCTL_N1_MASK		(0x7 << MIPSPLLCTL_N1_SHIFT)
+#define MIPSPLLCTL_N2_SHIFT		15
+#define MIPSPLLCTL_N2_MASK		(0x1f << MIPSPLLCTL_N2_SHIFT)
+#define MIPSPLLCTL_M1REF_SHIFT		12
+#define MIPSPLLCTL_M1REF_MASK		(0x7 << MIPSPLLCTL_M1REF_SHIFT)
+#define MIPSPLLCTL_M2REF_SHIFT		9
+#define MIPSPLLCTL_M2REF_MASK		(0x7 << MIPSPLLCTL_M2REF_SHIFT)
+#define MIPSPLLCTL_M1CPU_SHIFT		6
+#define MIPSPLLCTL_M1CPU_MASK		(0x7 << MIPSPLLCTL_M1CPU_SHIFT)
+#define MIPSPLLCTL_M1BUS_SHIFT		3
+#define MIPSPLLCTL_M1BUS_MASK		(0x7 << MIPSPLLCTL_M1BUS_SHIFT)
+#define MIPSPLLCTL_M2BUS_SHIFT		0
+#define MIPSPLLCTL_M2BUS_MASK		(0x7 << MIPSPLLCTL_M2BUS_SHIFT)
+
+/* ADSL PHY PLL Control register */
+#define PERF_ADSLPLLCTL_REG		0x38
+#define ADSLPLLCTL_N1_SHIFT		20
+#define ADSLPLLCTL_N1_MASK		(0x7 << ADSLPLLCTL_N1_SHIFT)
+#define ADSLPLLCTL_N2_SHIFT		15
+#define ADSLPLLCTL_N2_MASK		(0x1f << ADSLPLLCTL_N2_SHIFT)
+#define ADSLPLLCTL_M1REF_SHIFT		12
+#define ADSLPLLCTL_M1REF_MASK		(0x7 << ADSLPLLCTL_M1REF_SHIFT)
+#define ADSLPLLCTL_M2REF_SHIFT		9
+#define ADSLPLLCTL_M2REF_MASK		(0x7 << ADSLPLLCTL_M2REF_SHIFT)
+#define ADSLPLLCTL_M1CPU_SHIFT		6
+#define ADSLPLLCTL_M1CPU_MASK		(0x7 << ADSLPLLCTL_M1CPU_SHIFT)
+#define ADSLPLLCTL_M1BUS_SHIFT		3
+#define ADSLPLLCTL_M1BUS_MASK		(0x7 << ADSLPLLCTL_M1BUS_SHIFT)
+#define ADSLPLLCTL_M2BUS_SHIFT		0
+#define ADSLPLLCTL_M2BUS_MASK		(0x7 << ADSLPLLCTL_M2BUS_SHIFT)
+
+#define ADSLPLLCTL_VAL(n1,n2,m1ref,m2ref,m1cpu,m1bus,m2bus)		\
+				(((n1) << ADSLPLLCTL_N1_SHIFT) |	\
+				((n2) << ADSLPLLCTL_N2_SHIFT) |		\
+				((m1ref) << ADSLPLLCTL_M1REF_SHIFT) |	\
+				((m2ref) << ADSLPLLCTL_M2REF_SHIFT) |	\
+				((m1cpu) << ADSLPLLCTL_M1CPU_SHIFT) |	\
+				((m1bus) << ADSLPLLCTL_M1BUS_SHIFT) |	\
+				((m2bus) << ADSLPLLCTL_M2BUS_SHIFT))
+
+
+/*************************************************************************
+ * _REG relative to RSET_TIMER
+ *************************************************************************/
+
+#define BCM963XX_TIMER_COUNT		4
+#define TIMER_T0_ID			0
+#define TIMER_T1_ID			1
+#define TIMER_T2_ID			2
+#define TIMER_WDT_ID			3
+
+/* Timer irqstat register */
+#define TIMER_IRQSTAT_REG		0
+#define TIMER_IRQSTAT_TIMER_CAUSE(x)	(1 << (x))
+#define TIMER_IRQSTAT_TIMER0_CAUSE	(1 << 0)
+#define TIMER_IRQSTAT_TIMER1_CAUSE	(1 << 1)
+#define TIMER_IRQSTAT_TIMER2_CAUSE	(1 << 2)
+#define TIMER_IRQSTAT_WDT_CAUSE		(1 << 3)
+#define TIMER_IRQSTAT_TIMER_IR_EN(x)	(1 << ((x) + 8))
+#define TIMER_IRQSTAT_TIMER0_IR_EN	(1 << 8)
+#define TIMER_IRQSTAT_TIMER1_IR_EN	(1 << 9)
+#define TIMER_IRQSTAT_TIMER2_IR_EN	(1 << 10)
+
+/* Timer control register */
+#define TIMER_CTLx_REG(x)		(0x4 + (x * 4))
+#define TIMER_CTL0_REG			0x4
+#define TIMER_CTL1_REG			0x8
+#define TIMER_CTL2_REG			0xC
+#define TIMER_CTL_COUNTDOWN_MASK	(0x3fffffff)
+#define TIMER_CTL_MONOTONIC_MASK	(1 << 30)
+#define TIMER_CTL_ENABLE_MASK		(1 << 31)
+
+
+/*************************************************************************
+ * _REG relative to RSET_WDT
+ *************************************************************************/
+
+/* Watchdog default count register */
+#define WDT_DEFVAL_REG			0x0
+
+/* Watchdog control register */
+#define WDT_CTL_REG			0x4
+
+/* Watchdog control register constants */
+#define WDT_START_1			(0xff00)
+#define WDT_START_2			(0x00ff)
+#define WDT_STOP_1			(0xee00)
+#define WDT_STOP_2			(0x00ee)
+
+/* Watchdog reset length register */
+#define WDT_RSTLEN_REG			0x8
+
+
+/*************************************************************************
+ * _REG relative to RSET_UARTx
+ *************************************************************************/
+
+/* UART Control Register */
+#define UART_CTL_REG			0x0
+#define UART_CTL_RXTMOUTCNT_SHIFT	0
+#define UART_CTL_RXTMOUTCNT_MASK	(0x1f << UART_CTL_RXTMOUTCNT_SHIFT)
+#define UART_CTL_RSTTXDN_SHIFT		5
+#define UART_CTL_RSTTXDN_MASK		(1 << UART_CTL_RSTTXDN_SHIFT)
+#define UART_CTL_RSTRXFIFO_SHIFT		6
+#define UART_CTL_RSTRXFIFO_MASK		(1 << UART_CTL_RSTRXFIFO_SHIFT)
+#define UART_CTL_RSTTXFIFO_SHIFT		7
+#define UART_CTL_RSTTXFIFO_MASK		(1 << UART_CTL_RSTTXFIFO_SHIFT)
+#define UART_CTL_STOPBITS_SHIFT		8
+#define UART_CTL_STOPBITS_MASK		(0xf << UART_CTL_STOPBITS_SHIFT)
+#define UART_CTL_STOPBITS_1		(0x7 << UART_CTL_STOPBITS_SHIFT)
+#define UART_CTL_STOPBITS_2		(0xf << UART_CTL_STOPBITS_SHIFT)
+#define UART_CTL_BITSPERSYM_SHIFT	12
+#define UART_CTL_BITSPERSYM_MASK	(0x3 << UART_CTL_BITSPERSYM_SHIFT)
+#define UART_CTL_XMITBRK_SHIFT		14
+#define UART_CTL_XMITBRK_MASK		(1 << UART_CTL_XMITBRK_SHIFT)
+#define UART_CTL_RSVD_SHIFT		15
+#define UART_CTL_RSVD_MASK		(1 << UART_CTL_RSVD_SHIFT)
+#define UART_CTL_RXPAREVEN_SHIFT		16
+#define UART_CTL_RXPAREVEN_MASK		(1 << UART_CTL_RXPAREVEN_SHIFT)
+#define UART_CTL_RXPAREN_SHIFT		17
+#define UART_CTL_RXPAREN_MASK		(1 << UART_CTL_RXPAREN_SHIFT)
+#define UART_CTL_TXPAREVEN_SHIFT		18
+#define UART_CTL_TXPAREVEN_MASK		(1 << UART_CTL_TXPAREVEN_SHIFT)
+#define UART_CTL_TXPAREN_SHIFT		18
+#define UART_CTL_TXPAREN_MASK		(1 << UART_CTL_TXPAREN_SHIFT)
+#define UART_CTL_LOOPBACK_SHIFT		20
+#define UART_CTL_LOOPBACK_MASK		(1 << UART_CTL_LOOPBACK_SHIFT)
+#define UART_CTL_RXEN_SHIFT		21
+#define UART_CTL_RXEN_MASK		(1 << UART_CTL_RXEN_SHIFT)
+#define UART_CTL_TXEN_SHIFT		22
+#define UART_CTL_TXEN_MASK		(1 << UART_CTL_TXEN_SHIFT)
+#define UART_CTL_BRGEN_SHIFT		23
+#define UART_CTL_BRGEN_MASK		(1 << UART_CTL_BRGEN_SHIFT)
+
+/* UART Baudword register */
+#define UART_BAUD_REG			0x4
+
+/* UART Misc Control register */
+#define UART_MCTL_REG			0x8
+#define UART_MCTL_DTR_SHIFT		0
+#define UART_MCTL_DTR_MASK		(1 << UART_MCTL_DTR_SHIFT)
+#define UART_MCTL_RTS_SHIFT		1
+#define UART_MCTL_RTS_MASK		(1 << UART_MCTL_RTS_SHIFT)
+#define UART_MCTL_RXFIFOTHRESH_SHIFT	8
+#define UART_MCTL_RXFIFOTHRESH_MASK	(0xf << UART_MCTL_RXFIFOTHRESH_SHIFT)
+#define UART_MCTL_TXFIFOTHRESH_SHIFT	12
+#define UART_MCTL_TXFIFOTHRESH_MASK	(0xf << UART_MCTL_TXFIFOTHRESH_SHIFT)
+#define UART_MCTL_RXFIFOFILL_SHIFT	16
+#define UART_MCTL_RXFIFOFILL_MASK	(0x1f << UART_MCTL_RXFIFOFILL_SHIFT)
+#define UART_MCTL_TXFIFOFILL_SHIFT	24
+#define UART_MCTL_TXFIFOFILL_MASK	(0x1f << UART_MCTL_TXFIFOFILL_SHIFT)
+
+/* UART External Input Configuration register */
+#define UART_EXTINP_REG			0xc
+#define UART_EXTINP_RI_SHIFT		0
+#define UART_EXTINP_RI_MASK		(1 << UART_EXTINP_RI_SHIFT)
+#define UART_EXTINP_CTS_SHIFT		1
+#define UART_EXTINP_CTS_MASK		(1 << UART_EXTINP_CTS_SHIFT)
+#define UART_EXTINP_DCD_SHIFT		2
+#define UART_EXTINP_DCD_MASK		(1 << UART_EXTINP_DCD_SHIFT)
+#define UART_EXTINP_DSR_SHIFT		3
+#define UART_EXTINP_DSR_MASK		(1 << UART_EXTINP_DSR_SHIFT)
+#define UART_EXTINP_IRSTAT(x)		(1 << (x + 4))
+#define UART_EXTINP_IRMASK(x)		(1 << (x + 8))
+#define UART_EXTINP_IR_RI		0
+#define UART_EXTINP_IR_CTS		1
+#define UART_EXTINP_IR_DCD		2
+#define UART_EXTINP_IR_DSR		3
+#define UART_EXTINP_RI_NOSENSE_SHIFT	16
+#define UART_EXTINP_RI_NOSENSE_MASK	(1 << UART_EXTINP_RI_NOSENSE_SHIFT)
+#define UART_EXTINP_CTS_NOSENSE_SHIFT	17
+#define UART_EXTINP_CTS_NOSENSE_MASK	(1 << UART_EXTINP_CTS_NOSENSE_SHIFT)
+#define UART_EXTINP_DCD_NOSENSE_SHIFT	18
+#define UART_EXTINP_DCD_NOSENSE_MASK	(1 << UART_EXTINP_DCD_NOSENSE_SHIFT)
+#define UART_EXTINP_DSR_NOSENSE_SHIFT	19
+#define UART_EXTINP_DSR_NOSENSE_MASK	(1 << UART_EXTINP_DSR_NOSENSE_SHIFT)
+
+/* UART Interrupt register */
+#define UART_IR_REG			0x10
+#define UART_IR_MASK(x)			(1 << (x + 16))
+#define UART_IR_STAT(x)			(1 << (x))
+#define UART_IR_EXTIP			0
+#define UART_IR_TXUNDER			1
+#define UART_IR_TXOVER			2
+#define UART_IR_TXTRESH			3
+#define UART_IR_TXRDLATCH		4
+#define UART_IR_TXEMPTY			5
+#define UART_IR_RXUNDER			6
+#define UART_IR_RXOVER			7
+#define UART_IR_RXTIMEOUT		8
+#define UART_IR_RXFULL			9
+#define UART_IR_RXTHRESH		10
+#define UART_IR_RXNOTEMPTY		11
+#define UART_IR_RXFRAMEERR		12
+#define UART_IR_RXPARERR		13
+#define UART_IR_RXBRK			14
+#define UART_IR_TXDONE			15
+
+/* UART Fifo register */
+#define UART_FIFO_REG			0x14
+#define UART_FIFO_VALID_SHIFT		0
+#define UART_FIFO_VALID_MASK		0xff
+#define UART_FIFO_FRAMEERR_SHIFT	8
+#define UART_FIFO_FRAMEERR_MASK		(1 << UART_FIFO_FRAMEERR_SHIFT)
+#define UART_FIFO_PARERR_SHIFT		9
+#define UART_FIFO_PARERR_MASK		(1 << UART_FIFO_PARERR_SHIFT)
+#define UART_FIFO_BRKDET_SHIFT		10
+#define UART_FIFO_BRKDET_MASK		(1 << UART_FIFO_BRKDET_SHIFT)
+#define UART_FIFO_ANYERR_MASK		(UART_FIFO_FRAMEERR_MASK |	\
+					UART_FIFO_PARERR_MASK |		\
+					UART_FIFO_BRKDET_MASK)
+
+
+/*************************************************************************
+ * _REG relative to RSET_GPIO
+ *************************************************************************/
+
+/* GPIO registers */
+#define GPIO_CTL_HI_REG			0x0
+#define GPIO_CTL_LO_REG			0x4
+#define GPIO_DATA_HI_REG		0x8
+#define GPIO_DATA_LO_REG		0xC
+
+/* GPIO mux registers and constants */
+#define GPIO_MODE_REG			0x18
+
+#define GROUP4_DIAG			0x00090000
+#define GROUP4_UTOPIA			0x00080000
+#define GROUP4_LEGACY_LED		0x00030000
+#define GROUP4_MII_SNOOP		0x00020000
+#define GROUP4_EXT_EPHY			0x00010000
+#define GROUP3_DIAG			0x00009000
+#define GROUP3_UTOPIA			0x00008000
+#define GROUP3_EXT_MII			0x00007000
+#define GROUP2_DIAG			0x00000900
+#define GROUP2_PCI			0x00000500
+#define GROUP1_DIAG			0x00000090
+#define GROUP1_UTOPIA			0x00000080
+#define GROUP1_SPI_UART			0x00000060
+#define GROUP1_SPI_MASTER		0x00000060
+#define GROUP1_MII_PCCARD		0x00000040
+#define GROUP1_MII_SNOOP		0x00000020
+#define GROUP1_EXT_EPHY			0x00000010
+#define GROUP0_DIAG			0x00000009
+#define GROUP0_EXT_MII			0x00000007
+
+
+/*************************************************************************
+ * _REG relative to RSET_ENET
+ *************************************************************************/
+
+/* Receiver Configuration register */
+#define ENET_RXCFG_REG			0x0
+#define ENET_RXCFG_ALLMCAST_SHIFT	1
+#define ENET_RXCFG_ALLMCAST_MASK	(1 << ENET_RXCFG_ALLMCAST_SHIFT)
+#define ENET_RXCFG_PROMISC_SHIFT	3
+#define ENET_RXCFG_PROMISC_MASK		(1 << ENET_RXCFG_PROMISC_SHIFT)
+#define ENET_RXCFG_LOOPBACK_SHIFT	4
+#define ENET_RXCFG_LOOPBACK_MASK	(1 << ENET_RXCFG_LOOPBACK_SHIFT)
+#define ENET_RXCFG_ENFLOW_SHIFT		5
+#define ENET_RXCFG_ENFLOW_MASK		(1 << ENET_RXCFG_ENFLOW_SHIFT)
+
+/* Receive Maximum Length register */
+#define ENET_RXMAXLEN_REG		0x4
+#define ENET_RXMAXLEN_SHIFT		0
+#define ENET_RXMAXLEN_MASK		(0x7ff << ENET_RXMAXLEN_SHIFT)
+
+/* Transmit Maximum Length register */
+#define ENET_TXMAXLEN_REG		0x8
+#define ENET_TXMAXLEN_SHIFT		0
+#define ENET_TXMAXLEN_MASK		(0x7ff << ENET_TXMAXLEN_SHIFT)
+
+/* MII Status/Control register */
+#define ENET_MIISC_REG			0x10
+#define ENET_MIISC_MDCFREQDIV_SHIFT	0
+#define ENET_MIISC_MDCFREQDIV_MASK	(0x7f << ENET_MIISC_MDCFREQDIV_SHIFT)
+#define ENET_MIISC_PREAMBLEEN_SHIFT	7
+#define ENET_MIISC_PREAMBLEEN_MASK	(1 << ENET_MIISC_PREAMBLEEN_SHIFT)
+
+/* MII Data register */
+#define ENET_MIIDATA_REG		0x14
+#define ENET_MIIDATA_DATA_SHIFT		0
+#define ENET_MIIDATA_DATA_MASK		(0xffff << ENET_MIIDATA_DATA_SHIFT)
+#define ENET_MIIDATA_TA_SHIFT		16
+#define ENET_MIIDATA_TA_MASK		(0x3 << ENET_MIIDATA_TA_SHIFT)
+#define ENET_MIIDATA_REG_SHIFT		18
+#define ENET_MIIDATA_REG_MASK		(0x1f << ENET_MIIDATA_REG_SHIFT)
+#define ENET_MIIDATA_PHYID_SHIFT	23
+#define ENET_MIIDATA_PHYID_MASK		(0x1f << ENET_MIIDATA_PHYID_SHIFT)
+#define ENET_MIIDATA_OP_READ_MASK	(0x6 << 28)
+#define ENET_MIIDATA_OP_WRITE_MASK	(0x5 << 28)
+
+/* Ethernet Interrupt Mask register */
+#define ENET_IRMASK_REG			0x18
+
+/* Ethernet Interrupt register */
+#define ENET_IR_REG			0x1c
+#define ENET_IR_MII			(1 << 0)
+#define ENET_IR_MIB			(1 << 1)
+#define ENET_IR_FLOWC			(1 << 2)
+
+/* Ethernet Control register */
+#define ENET_CTL_REG			0x2c
+#define ENET_CTL_ENABLE_SHIFT		0
+#define ENET_CTL_ENABLE_MASK		(1 << ENET_CTL_ENABLE_SHIFT)
+#define ENET_CTL_DISABLE_SHIFT		1
+#define ENET_CTL_DISABLE_MASK		(1 << ENET_CTL_DISABLE_SHIFT)
+#define ENET_CTL_SRESET_SHIFT		2
+#define ENET_CTL_SRESET_MASK		(1 << ENET_CTL_SRESET_SHIFT)
+#define ENET_CTL_EPHYSEL_SHIFT		3
+#define ENET_CTL_EPHYSEL_MASK		(1 << ENET_CTL_EPHYSEL_SHIFT)
+
+/* Transmit Control register */
+#define ENET_TXCTL_REG			0x30
+#define ENET_TXCTL_FD_SHIFT		0
+#define ENET_TXCTL_FD_MASK		(1 << ENET_TXCTL_FD_SHIFT)
+
+/* Transmit Watermask register */
+#define ENET_TXWMARK_REG		0x34
+#define ENET_TXWMARK_WM_SHIFT		0
+#define ENET_TXWMARK_WM_MASK		(0x3f << ENET_TXWMARK_WM_SHIFT)
+
+/* MIB Control register */
+#define ENET_MIBCTL_REG			0x38
+#define ENET_MIBCTL_RDCLEAR_SHIFT	0
+#define ENET_MIBCTL_RDCLEAR_MASK	(1 << ENET_MIBCTL_RDCLEAR_SHIFT)
+
+/* Perfect Match Data Low register */
+#define ENET_PML_REG(x)			(0x58 + (x) * 8)
+#define ENET_PMH_REG(x)			(0x5c + (x) * 8)
+#define ENET_PMH_DATAVALID_SHIFT	16
+#define ENET_PMH_DATAVALID_MASK		(1 << ENET_PMH_DATAVALID_SHIFT)
+
+/* MIB register */
+#define ENET_MIB_REG(x)			(0x200 + (x) * 4)
+#define ENET_MIB_REG_COUNT		55
+
+
+/*************************************************************************
+ * _REG relative to RSET_ENETDMA
+ *************************************************************************/
+
+
+/* Controller Configuration Register */
+#define ENETDMA_CFG_REG			(0x0)
+#define ENETDMA_CFG_EN_SHIFT		0
+#define ENETDMA_CFG_EN_MASK		(1 << ENETDMA_CFG_EN_SHIFT)
+#define ENETDMA_CFG_FLOWCH_MASK(x)	(1 << ((x >> 1) + 1))
+
+/* Flow Control Descriptor Low Threshold register */
+#define ENETDMA_FLOWCL_REG(x)		(0x4 + (x) * 6)
+
+/* Flow Control Descriptor High Threshold register */
+#define ENETDMA_FLOWCH_REG(x)		(0x8 + (x) * 6)
+
+/* Flow Control Descriptor Buffer Alloca Threshold register */
+#define ENETDMA_BUFALLOC_REG(x)		(0xc + (x) * 6)
+#define ENETDMA_BUFALLOC_FORCE_SHIFT	31
+#define ENETDMA_BUFALLOC_FORCE_MASK	(1 << ENETDMA_BUFALLOC_FORCE_SHIFT)
+
+/* Channel Configuration register */
+#define ENETDMA_CHANCFG_REG(x)		(0x100 + (x) * 0x10)
+#define ENETDMA_CHANCFG_EN_SHIFT	0
+#define ENETDMA_CHANCFG_EN_MASK		(1 << ENETDMA_CHANCFG_EN_SHIFT)
+#define ENETDMA_CHANCFG_PKTHALT_SHIFT	1
+#define ENETDMA_CHANCFG_PKTHALT_MASK	(1 << ENETDMA_CHANCFG_PKTHALT_SHIFT)
+
+/* Interrupt Control/Status register */
+#define ENETDMA_IR_REG(x)		(0x104 + (x) * 0x10)
+#define ENETDMA_IR_BUFDONE_MASK		(1 << 0)
+#define ENETDMA_IR_PKTDONE_MASK		(1 << 1)
+#define ENETDMA_IR_NOTOWNER_MASK	(1 << 2)
+
+/* Interrupt Mask register */
+#define ENETDMA_IRMASK_REG(x)		(0x108 + (x) * 0x10)
+
+/* Maximum Burst Length */
+#define ENETDMA_MAXBURST_REG(x)		(0x10C + (x) * 0x10)
+
+/* Ring Start Address register */
+#define ENETDMA_RSTART_REG(x)		(0x200 + (x) * 0x10)
+
+/* State Ram Word 2 */
+#define ENETDMA_SRAM2_REG(x)		(0x204 + (x) * 0x10)
+
+/* State Ram Word 3 */
+#define ENETDMA_SRAM3_REG(x)		(0x208 + (x) * 0x10)
+
+/* State Ram Word 4 */
+#define ENETDMA_SRAM4_REG(x)		(0x20c + (x) * 0x10)
+
+
+/*************************************************************************
+ * _REG relative to RSET_OHCI_PRIV
+ *************************************************************************/
+
+#define OHCI_PRIV_REG			0x0
+#define OHCI_PRIV_PORT1_HOST_SHIFT	0
+#define OHCI_PRIV_PORT1_HOST_MASK	(1 << OHCI_PRIV_PORT1_HOST_SHIFT)
+#define OHCI_PRIV_REG_SWAP_SHIFT	3
+#define OHCI_PRIV_REG_SWAP_MASK		(1 << OHCI_PRIV_REG_SWAP_SHIFT)
+
+
+/*************************************************************************
+ * _REG relative to RSET_USBH_PRIV
+ *************************************************************************/
+
+#define USBH_PRIV_SWAP_REG		0x0
+#define USBH_PRIV_SWAP_EHCI_ENDN_SHIFT	4
+#define USBH_PRIV_SWAP_EHCI_ENDN_MASK	(1 << USBH_PRIV_SWAP_EHCI_ENDN_SHIFT)
+#define USBH_PRIV_SWAP_EHCI_DATA_SHIFT	3
+#define USBH_PRIV_SWAP_EHCI_DATA_MASK	(1 << USBH_PRIV_SWAP_EHCI_DATA_SHIFT)
+#define USBH_PRIV_SWAP_OHCI_ENDN_SHIFT	1
+#define USBH_PRIV_SWAP_OHCI_ENDN_MASK	(1 << USBH_PRIV_SWAP_OHCI_ENDN_SHIFT)
+#define USBH_PRIV_SWAP_OHCI_DATA_SHIFT	0
+#define USBH_PRIV_SWAP_OHCI_DATA_MASK	(1 << USBH_PRIV_SWAP_OHCI_DATA_SHIFT)
+
+#define USBH_PRIV_TEST_REG		0x24
+
+
+/*************************************************************************
+ * _REG relative to RSET_MPI
+ *************************************************************************/
+
+/* well known (hard wired) chip select */
+#define MPI_CS_PCMCIA_COMMON		4
+#define MPI_CS_PCMCIA_ATTR		5
+#define MPI_CS_PCMCIA_IO		6
+
+/* Chip select base register */
+#define MPI_CSBASE_REG(x)		(0x0 + (x) * 8)
+#define MPI_CSBASE_BASE_SHIFT		13
+#define MPI_CSBASE_BASE_MASK		(0x1ffff << MPI_CSBASE_BASE_SHIFT)
+#define MPI_CSBASE_SIZE_SHIFT		0
+#define MPI_CSBASE_SIZE_MASK		(0xf << MPI_CSBASE_SIZE_SHIFT)
+
+#define MPI_CSBASE_SIZE_8K		0
+#define MPI_CSBASE_SIZE_16K		1
+#define MPI_CSBASE_SIZE_32K		2
+#define MPI_CSBASE_SIZE_64K		3
+#define MPI_CSBASE_SIZE_128K		4
+#define MPI_CSBASE_SIZE_256K		5
+#define MPI_CSBASE_SIZE_512K		6
+#define MPI_CSBASE_SIZE_1M		7
+#define MPI_CSBASE_SIZE_2M		8
+#define MPI_CSBASE_SIZE_4M		9
+#define MPI_CSBASE_SIZE_8M		10
+#define MPI_CSBASE_SIZE_16M		11
+#define MPI_CSBASE_SIZE_32M		12
+#define MPI_CSBASE_SIZE_64M		13
+#define MPI_CSBASE_SIZE_128M		14
+#define MPI_CSBASE_SIZE_256M		15
+
+/* Chip select control register */
+#define MPI_CSCTL_REG(x)		(0x4 + (x) * 8)
+#define MPI_CSCTL_ENABLE_MASK		(1 << 0)
+#define MPI_CSCTL_WAIT_SHIFT		1
+#define MPI_CSCTL_WAIT_MASK		(0x7 << MPI_CSCTL_WAIT_SHIFT)
+#define MPI_CSCTL_DATA16_MASK		(1 << 4)
+#define MPI_CSCTL_SYNCMODE_MASK		(1 << 7)
+#define MPI_CSCTL_TSIZE_MASK		(1 << 8)
+#define MPI_CSCTL_ENDIANSWAP_MASK	(1 << 10)
+#define MPI_CSCTL_SETUP_SHIFT		16
+#define MPI_CSCTL_SETUP_MASK		(0xf << MPI_CSCTL_SETUP_SHIFT)
+#define MPI_CSCTL_HOLD_SHIFT		20
+#define MPI_CSCTL_HOLD_MASK		(0xf << MPI_CSCTL_HOLD_SHIFT)
+
+/* PCI registers */
+#define MPI_SP0_RANGE_REG		0x100
+#define MPI_SP0_REMAP_REG		0x104
+#define MPI_SP0_REMAP_ENABLE_MASK	(1 << 0)
+#define MPI_SP1_RANGE_REG		0x10C
+#define MPI_SP1_REMAP_REG		0x110
+#define MPI_SP1_REMAP_ENABLE_MASK	(1 << 0)
+
+#define MPI_L2PCFG_REG			0x11C
+#define MPI_L2PCFG_CFG_TYPE_SHIFT	0
+#define MPI_L2PCFG_CFG_TYPE_MASK	(0x3 << MPI_L2PCFG_CFG_TYPE_SHIFT)
+#define MPI_L2PCFG_REG_SHIFT		2
+#define MPI_L2PCFG_REG_MASK		(0x3f << MPI_L2PCFG_REG_SHIFT)
+#define MPI_L2PCFG_FUNC_SHIFT		8
+#define MPI_L2PCFG_FUNC_MASK		(0x7 << MPI_L2PCFG_FUNC_SHIFT)
+#define MPI_L2PCFG_DEVNUM_SHIFT		11
+#define MPI_L2PCFG_DEVNUM_MASK		(0x1f << MPI_L2PCFG_DEVNUM_SHIFT)
+#define MPI_L2PCFG_CFG_USEREG_MASK	(1 << 30)
+#define MPI_L2PCFG_CFG_SEL_MASK		(1 << 31)
+
+#define MPI_L2PMEMRANGE1_REG		0x120
+#define MPI_L2PMEMBASE1_REG		0x124
+#define MPI_L2PMEMREMAP1_REG		0x128
+#define MPI_L2PMEMRANGE2_REG		0x12C
+#define MPI_L2PMEMBASE2_REG		0x130
+#define MPI_L2PMEMREMAP2_REG		0x134
+#define MPI_L2PIORANGE_REG		0x138
+#define MPI_L2PIOBASE_REG		0x13C
+#define MPI_L2PIOREMAP_REG		0x140
+#define MPI_L2P_BASE_MASK		(0xffff8000)
+#define MPI_L2PREMAP_ENABLED_MASK	(1 << 0)
+#define MPI_L2PREMAP_IS_CARDBUS_MASK	(1 << 2)
+
+#define MPI_PCIMODESEL_REG		0x144
+#define MPI_PCIMODESEL_BAR1_NOSWAP_MASK	(1 << 0)
+#define MPI_PCIMODESEL_BAR2_NOSWAP_MASK	(1 << 1)
+#define MPI_PCIMODESEL_EXT_ARB_MASK	(1 << 2)
+#define MPI_PCIMODESEL_PREFETCH_SHIFT	4
+#define MPI_PCIMODESEL_PREFETCH_MASK	(0xf << MPI_PCIMODESEL_PREFETCH_SHIFT)
+
+#define MPI_LOCBUSCTL_REG		0x14C
+#define MPI_LOCBUSCTL_EN_PCI_GPIO_MASK	(1 << 0)
+#define MPI_LOCBUSCTL_U2P_NOSWAP_MASK	(1 << 1)
+
+#define MPI_LOCINT_REG			0x150
+#define MPI_LOCINT_MASK(x)		(1 << (x + 16))
+#define MPI_LOCINT_STAT(x)		(1 << (x))
+#define MPI_LOCINT_DIR_FAILED		6
+#define MPI_LOCINT_EXT_PCI_INT		7
+#define MPI_LOCINT_SERR			8
+#define MPI_LOCINT_CSERR		9
+
+#define MPI_PCICFGCTL_REG		0x178
+#define MPI_PCICFGCTL_CFGADDR_SHIFT	2
+#define MPI_PCICFGCTL_CFGADDR_MASK	(0x1f << MPI_PCICFGCTL_CFGADDR_SHIFT)
+#define MPI_PCICFGCTL_WRITEEN_MASK	(1 << 7)
+
+#define MPI_PCICFGDATA_REG		0x17C
+
+/* PCI host bridge custom register */
+#define BCMPCI_REG_TIMERS		0x40
+#define REG_TIMER_TRDY_SHIFT		0
+#define REG_TIMER_TRDY_MASK		(0xff << REG_TIMER_TRDY_SHIFT)
+#define REG_TIMER_RETRY_SHIFT		8
+#define REG_TIMER_RETRY_MASK		(0xff << REG_TIMER_RETRY_SHIFT)
+
+
+/*************************************************************************
+ * _REG relative to RSET_PCMCIA
+ *************************************************************************/
+
+#define PCMCIA_C1_REG			0x0
+#define PCMCIA_C1_CD1_MASK		(1 << 0)
+#define PCMCIA_C1_CD2_MASK		(1 << 1)
+#define PCMCIA_C1_VS1_MASK		(1 << 2)
+#define PCMCIA_C1_VS2_MASK		(1 << 3)
+#define PCMCIA_C1_VS1OE_MASK		(1 << 6)
+#define PCMCIA_C1_VS2OE_MASK		(1 << 7)
+#define PCMCIA_C1_CBIDSEL_SHIFT		(8)
+#define PCMCIA_C1_CBIDSEL_MASK		(0x1f << PCMCIA_C1_CBIDSEL_SHIFT)
+#define PCMCIA_C1_EN_PCMCIA_GPIO_MASK	(1 << 13)
+#define PCMCIA_C1_EN_PCMCIA_MASK	(1 << 14)
+#define PCMCIA_C1_EN_CARDBUS_MASK	(1 << 15)
+#define PCMCIA_C1_RESET_MASK		(1 << 18)
+
+#define PCMCIA_C2_REG			0x8
+#define PCMCIA_C2_DATA16_MASK		(1 << 0)
+#define PCMCIA_C2_BYTESWAP_MASK		(1 << 1)
+#define PCMCIA_C2_RWCOUNT_SHIFT		2
+#define PCMCIA_C2_RWCOUNT_MASK		(0x3f << PCMCIA_C2_RWCOUNT_SHIFT)
+#define PCMCIA_C2_INACTIVE_SHIFT	8
+#define PCMCIA_C2_INACTIVE_MASK		(0x3f << PCMCIA_C2_INACTIVE_SHIFT)
+#define PCMCIA_C2_SETUP_SHIFT		16
+#define PCMCIA_C2_SETUP_MASK		(0x3f << PCMCIA_C2_SETUP_SHIFT)
+#define PCMCIA_C2_HOLD_SHIFT		24
+#define PCMCIA_C2_HOLD_MASK		(0x3f << PCMCIA_C2_HOLD_SHIFT)
+
+
+/*************************************************************************
+ * _REG relative to RSET_SDRAM
+ *************************************************************************/
+
+#define SDRAM_CFG_REG			0x0
+#define SDRAM_CFG_ROW_SHIFT		4
+#define SDRAM_CFG_ROW_MASK		(0x3 << SDRAM_CFG_ROW_SHIFT)
+#define SDRAM_CFG_COL_SHIFT		6
+#define SDRAM_CFG_COL_MASK		(0x3 << SDRAM_CFG_COL_SHIFT)
+#define SDRAM_CFG_32B_SHIFT		10
+#define SDRAM_CFG_32B_MASK		(1 << SDRAM_CFG_32B_SHIFT)
+#define SDRAM_CFG_BANK_SHIFT		13
+#define SDRAM_CFG_BANK_MASK		(1 << SDRAM_CFG_BANK_SHIFT)
+
+#define SDRAM_PRIO_REG			0x2C
+#define SDRAM_PRIO_MIPS_SHIFT		29
+#define SDRAM_PRIO_MIPS_MASK		(1 << SDRAM_PRIO_MIPS_SHIFT)
+#define SDRAM_PRIO_ADSL_SHIFT		30
+#define SDRAM_PRIO_ADSL_MASK		(1 << SDRAM_PRIO_ADSL_SHIFT)
+#define SDRAM_PRIO_EN_SHIFT		31
+#define SDRAM_PRIO_EN_MASK		(1 << SDRAM_PRIO_EN_SHIFT)
+
+/*************************************************************************
+ * _REG relative to RSET_MEMC
+ *************************************************************************/
+
+#define MEMC_CFG_REG			0x4
+#define MEMC_CFG_32B_SHIFT		1
+#define MEMC_CFG_32B_MASK		(1 << MEMC_CFG_32B_SHIFT)
+#define MEMC_CFG_COL_SHIFT		3
+#define MEMC_CFG_COL_MASK		(0x3 << MEMC_CFG_COL_SHIFT)
+#define MEMC_CFG_ROW_SHIFT		6
+#define MEMC_CFG_ROW_MASK		(0x3 << MEMC_CFG_ROW_SHIFT)
+
+/*************************************************************************
+ * _REG relative to RSET_SPI
+ *************************************************************************/
+
+/* SPI control register 1 */
+#define SPI_CTL1_REG			0
+#define SPI_CTL1_CMD_DONE_MASK		(1 << 8)
+#define SPI_CTL1_RX_OVER_MASK		(1 << 9)
+#define SPI_CTL1_TX_UNDER_MASK		(1 << 10)
+#define SPI_CTL1_TX_OVER_MASK		(1 << 11)
+#define SPI_CTL1_RX_UNDER_MAXK		(1 << 12)
+
+#define SPI_CTL1_CMD_NOOP		0
+#define SPI_CTL1_CMD_SOFT_RESET		1
+#define SPI_CTL1_CMD_HARD_RESET		2
+#define SPI_CTL1_CMD_START_IMMEDIATE	3
+#define SPI_CTL1_CMD_SHIFT		16
+#define SPI_CTL1_CMD_MASK		(0xffff << SPI_CTL1_CMD_SHIFT)
+
+#define SPI_CTL1_DEVID_ID_SHIFT		20
+#define SPI_CTL1_PREPEND_SHIFT		24
+#define SPI_CTL1_ONE_BYTE_SHIFT		27
+#define SPI_CTL1_ONE_BYTE_MASK		(1 << SPI_CTL1_ONE_BYTE_SHIFT)
+#define SPI_CTL1_ONE_WIRE_SHIFT		28
+#define SPI_CTL1_ONE_WIRE_MASK		(1 << SPI_CTL1_ONE_WIRE_SHIFT)
+
+/* SPI control register 2 */
+#define SPI_CTL2_REG			4
+#define SPI_CTL2_FILL_BYTE_MASK		0xff
+#define SPI_CTL2_CLK_0_391MHZ		1
+#define SPI_CTL2_CLK_0_781MHZ		2
+#define SPI_CTL2_CLK_1_563MHZ		3
+#define SPI_CTL2_CLK_3_125MHZ		4
+#define SPI_CTL2_CLK_6_250MHZ		5
+#define SPI_CTL2_CLK_12_50MHZ		6
+#define SPI_CTL2_CLK_SHIFT		8
+#define SPI_CTL2_CLK_MASK		(0x7 << SPI_CTL2_CLK_SHIFT)
+
+#define SPI_CTL2_INTMASK_SHIFT		24
+#define SPI_CTL2_INTMASK_MASK		(0xff << SPI_CTL2_INTMASK_SHIFT)
+
+/* SPI tail register */
+#define SPI_TAIL_REG			8
+#define SPI_TAIL_RX_SHIFT		0
+#define SPI_TAIL_RX_MASK		(0x7f << SPI_TAIL_RX_SHIFT)
+#define SPI_TAIL_RX_MSG_SHIFT		16
+#define SPI_TAIL_RX_MSG_MASK		(0x7f << SPI_TAIL_RX_MSG_SHIFT)
+
+/* SPI tx message fifo */
+#define SPI_TX_REG			0x40
+#define SPI_TX_BYTE_CNT_SHIFT		0
+#define SPI_TX_BYTE_CNT_MASK		(0x3f << SPI_TX_BYTE_CNT_SHIFT)
+#define SPI_TX_TYPE_FD_RW		0
+#define SPI_TX_TYPE_HD_W		1
+#define SPI_TX_TYPE_HD_R		2
+#define SPI_TX_TYPE_SHIFT		6
+#define SPI_TX_TYPE_MASK		(0x3 << SPI_TX_TYPE_SHIFT)
+
+/* SPI rx message fifo */
+#define SPI_RX_REG			0x80
+
+#endif /* BCM963XX_REGS_H_ */
diff -Nruw linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx./bcm963xx_timer.h linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx/bcm963xx_timer.h
--- linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx./bcm963xx_timer.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx/bcm963xx_timer.h	2011-09-26 15:07:56.218834275 +0200
@@ -0,0 +1,11 @@
+#ifndef BCM963XX_TIMER_H_
+#define BCM963XX_TIMER_H_
+
+int bcm963xx_timer_register(int id, void (*callback)(void *data), void *data);
+void bcm963xx_timer_unregister(int id);
+int bcm963xx_timer_set(int id, int monotonic, unsigned int countdown_us);
+int bcm963xx_timer_enable(int id);
+int bcm963xx_timer_disable(int id);
+unsigned int bcm963xx_timer_countdown(unsigned int countdown_us);
+
+#endif /* !BCM963XX_TIMER_H_ */
diff -Nruw linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx./bcm_intr.h linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx/bcm_intr.h
--- linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx./bcm_intr.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx/bcm_intr.h	2011-09-26 15:07:56.218834275 +0200
@@ -0,0 +1,59 @@
+/*
+<:copyright-gpl 
+ Copyright 2003 Broadcom Corp. All Rights Reserved. 
+ 
+ This program is free software; you can distribute it and/or modify it 
+ under the terms of the GNU General Public License (Version 2) as 
+ published by the Free Software Foundation. 
+ 
+ This program is distributed in the hope it will be useful, but WITHOUT 
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License 
+ for more details. 
+ 
+ You should have received a copy of the GNU General Public License along 
+ with this program; if not, write to the Free Software Foundation, Inc., 
+ 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. 
+:>
+*/
+
+#ifndef __BCM_INTR_H
+#define __BCM_INTR_H
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+#if defined(CONFIG_BCM96338)
+#include <6338_intr.h>
+#endif
+#if defined(CONFIG_BCM96345)
+#include <6345_intr.h>
+#endif
+#if defined(CONFIG_BCM96348)
+#include <6348_intr.h>
+#endif
+
+/* defines */
+struct pt_regs;
+typedef int (*FN_HANDLER) (int, void *);
+
+/* prototypes */
+extern void enable_brcm_irq(unsigned int irq);
+extern void disable_brcm_irq(unsigned int irq);
+extern int request_external_irq(unsigned int irq,
+    FN_HANDLER handler, unsigned long irqflags, 
+    const char * devname, void *dev_id);
+extern unsigned int BcmHalMapInterrupt(FN_HANDLER isr, unsigned int param,
+    unsigned int interruptId);
+extern void dump_intr_regs(void);
+
+void BcmHalInterruptEnable(unsigned int irq);
+
+void BcmHalInterruptDisable(unsigned irq);
+
+#ifdef __cplusplus
+    }
+#endif
+
+#endif
diff -Nruw linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx./bcm_map_part.h linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx/bcm_map_part.h
--- linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx./bcm_map_part.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx/bcm_map_part.h	2011-09-26 15:07:56.218834275 +0200
@@ -0,0 +1,34 @@
+/*
+<:copyright-gpl 
+ Copyright 2004 Broadcom Corp. All Rights Reserved. 
+ 
+ This program is free software; you can distribute it and/or modify it 
+ under the terms of the GNU General Public License (Version 2) as 
+ published by the Free Software Foundation. 
+ 
+ This program is distributed in the hope it will be useful, but WITHOUT 
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License 
+ for more details. 
+ 
+ You should have received a copy of the GNU General Public License along 
+ with this program; if not, write to the Free Software Foundation, Inc., 
+ 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. 
+:>
+*/
+
+#ifndef __BCM_MAP_PART_H
+#define __BCM_MAP_PART_H
+
+#if defined(CONFIG_BCM96338)
+#include <6338_map_part.h>
+#endif
+#if defined(CONFIG_BCM96345)
+#include <6345_map_part.h>
+#endif
+#if defined(CONFIG_BCM96348)
+#include <6348_map_part.h>
+#endif
+
+#endif
+
diff -Nruw linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx./bcmtypes.h linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx/bcmtypes.h
--- linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx./bcmtypes.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx/bcmtypes.h	2011-09-26 15:07:56.218834275 +0200
@@ -0,0 +1,160 @@
+/*
+<:copyright-gpl 
+ Copyright 2002 Broadcom Corp. All Rights Reserved. 
+ 
+ This program is free software; you can distribute it and/or modify it 
+ under the terms of the GNU General Public License (Version 2) as 
+ published by the Free Software Foundation. 
+ 
+ This program is distributed in the hope it will be useful, but WITHOUT 
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License 
+ for more details. 
+ 
+ You should have received a copy of the GNU General Public License along 
+ with this program; if not, write to the Free Software Foundation, Inc., 
+ 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. 
+:>
+*/
+
+//
+// bcmtypes.h - misc useful typedefs
+//
+#ifndef BCMTYPES_H
+#define BCMTYPES_H
+
+// These are also defined in typedefs.h in the application area, so I need to
+// protect against re-definition.
+
+#ifndef _TYPEDEFS_H_
+typedef unsigned char   uint8;
+typedef unsigned short  uint16;
+typedef unsigned long   uint32;
+typedef signed char     int8;
+typedef signed short    int16;
+typedef signed long     int32;
+#endif
+
+typedef unsigned char   byte;
+// typedef unsigned long   sem_t;
+
+typedef unsigned long   HANDLE,*PULONG,DWORD,*PDWORD;
+typedef signed long     LONG,*PLONG;
+
+typedef unsigned int    *PUINT;
+typedef signed int      INT;
+
+typedef unsigned short  *PUSHORT;
+typedef signed short    SHORT,*PSHORT;
+typedef unsigned short  WORD,*PWORD;
+
+typedef unsigned char   *PUCHAR;
+typedef signed char     *PCHAR;
+
+typedef void            *PVOID;
+
+typedef unsigned char   BOOLEAN, *PBOOL, *PBOOLEAN;
+
+typedef unsigned char   BYTE,*PBYTE;
+
+//#ifndef __GNUC__
+//The following has been defined in Vxworks internally: vxTypesOld.h
+//redefine under vxworks will cause error
+typedef signed int      *PINT;
+
+typedef signed char     INT8;
+typedef signed short    INT16;
+typedef signed long     INT32;
+
+typedef unsigned char   UINT8;
+typedef unsigned short  UINT16;
+typedef unsigned long   UINT32;
+
+typedef unsigned char   UCHAR;
+typedef unsigned short  USHORT;
+typedef unsigned int    UINT;
+typedef unsigned long   ULONG;
+
+typedef void            VOID;
+typedef unsigned char   BOOL;
+
+//#endif  /* __GNUC__ */
+
+
+// These are also defined in typedefs.h in the application area, so I need to
+// protect against re-definition.
+#ifndef TYPEDEFS_H
+
+// Maximum and minimum values for a signed 16 bit integer.
+#define MAX_INT16 32767
+#define MIN_INT16 -32768
+
+// Useful for true/false return values.  This uses the
+// Taligent notation (k for constant).
+typedef enum
+{
+    kFalse = 0,
+    kTrue = 1
+} Bool;
+
+#endif
+
+/* macros to protect against unaligned accesses */
+
+#if 0
+/* first arg is an address, second is a value */
+#define PUT16( a, d ) { 		\
+  *((byte *)a) = (byte)((d)>>8); 	\
+  *(((byte *)a)+1) = (byte)(d); 	\
+}
+
+#define PUT32( a, d ) { 		\
+  *((byte *)a) = (byte)((d)>>24); 	\
+  *(((byte *)a)+1) = (byte)((d)>>16); 	\
+  *(((byte *)a)+2) = (byte)((d)>>8); 	\
+  *(((byte *)a)+3) = (byte)(d); 	\
+}
+
+/* first arg is an address, returns a value */
+#define GET16( a ) ( 			\
+  (*((byte *)a) << 8) |			\
+  (*(((byte *)a)+1))	 		\
+)
+
+#define GET32( a ) ( 			\
+  (*((byte *)a) << 24)     |		\
+  (*(((byte *)a)+1) << 16) | 		\
+  (*(((byte *)a)+2) << 8)  | 		\
+  (*(((byte *)a)+3))	 		\
+)
+#endif
+
+#ifndef YES
+#define YES 1
+#endif
+
+#ifndef NO
+#define NO  0
+#endif
+
+#ifndef IN
+#define IN
+#endif
+
+#ifndef OUT
+#define OUT
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE  0
+#endif
+
+#define READ32(addr)        (*(volatile UINT32 *)((ULONG)&addr))
+#define READ16(addr)        (*(volatile UINT16 *)((ULONG)&addr))
+#define READ8(addr)         (*(volatile UINT8  *)((ULONG)&addr))
+
+#endif
diff -Nruw linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx./board-fbx5a.h linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx/board-fbx5a.h
--- linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx./board-fbx5a.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx/board-fbx5a.h	2011-09-26 15:07:56.218834275 +0200
@@ -0,0 +1,18 @@
+/*
+ * fbx5a specific bits, gpio numbers, ...
+ */
+
+#ifndef BOARD_FBX5A_H
+# define BOARD_FBX5A_H
+
+/* GPIO numbers */
+# define GPIO_TEST_MODE		1
+# define GPIO_SLAC_RESET	2
+# define GPIO_RANDOM		6
+# define GPIO_I2C_SDA		28
+# define GPIO_I2C_SCL		29
+# define GPIO_SLAC_IRQ		33
+# define GPIO_SWITCH_IRQ	34
+# define GPIO_BOARD_RESET	36
+
+#endif /* !BOARD_FBX5A_H */
diff -Nruw linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx./cpu-feature-overrides.h linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx/cpu-feature-overrides.h
--- linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx./cpu-feature-overrides.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx/cpu-feature-overrides.h	2011-09-26 15:07:56.218834275 +0200
@@ -0,0 +1,43 @@
+#ifndef __ASM_MACH_BCM963XX_CPU_FEATURE_OVERRIDES_H
+#define __ASM_MACH_BCM963XX_CPU_FEATURE_OVERRIDES_H
+
+#include <bcm963xx_cpu.h>
+
+#define cpu_has_tlb			1
+#define cpu_has_4kex			4
+#define cpu_has_4ktlb			8
+#define cpu_has_4k_cache		1
+#define cpu_has_fpu			0
+#define cpu_has_32fpr			0
+#define cpu_has_counter			0x40
+#define cpu_has_watch			0
+#define cpu_has_mips16			0
+#define cpu_has_divec			0x200
+#define cpu_has_vce			0
+#define cpu_has_cache_cdex_p		0
+#define cpu_has_cache_cdex_s		0
+#define cpu_has_prefetch		0x40000
+#define cpu_has_mcheck			0x2000
+#define cpu_has_ejtag			0x4000
+#define cpu_has_llsc			0x10000
+#define cpu_has_vtag_icache		0
+
+#if !defined(BCMCPU_RUNTIME_DETECT) && defined(CONFIG_BCM963XX_CPU_6348)
+#define cpu_has_dc_aliases		0
+#endif
+
+#define cpu_has_ic_fills_f_dc		0
+
+#define cpu_has_nofpuex			0
+#define cpu_has_64bits			0
+#define cpu_has_64bit_zero_reg		0
+#define cpu_has_64bit_gp_regs		0
+#define cpu_has_64bit_addresses		0
+
+#define cpu_has_subset_pcaches		0
+
+#define cpu_dcache_line_size()		16
+#define cpu_icache_line_size()		16
+#define cpu_scache_line_size()		0
+
+#endif /* __ASM_MACH_BCM963XX_CPU_FEATURE_OVERRIDES_H */
diff -Nruw linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx./devices.h linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx/devices.h
--- linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx./devices.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/include/asm-mips/mach-bcm963xx/devices.h	2011-09-26 15:07:56.218834275 +0200
@@ -0,0 +1,77 @@
+#ifndef ASM_BCM963XX_DEVICES_H_
+#define ASM_BCM963XX_DEVICES_H_
+
+#include <linux/if_ether.h>
+
+/*
+ * on board ethernet platform data
+ */
+struct bcm963xx_enet_platform_data {
+	char mac_addr[ETH_ALEN];
+	int use_marvell_header;
+
+	int use_external_mii;
+
+	int has_phy;
+
+	/* if has_phy, then set use_internal_phy or fill phy info */
+	int use_internal_phy;
+	int phy_id;
+	int has_phy_interrupt;
+	int phy_interrupt;
+
+	int pause_auto;
+	int pause_rx;
+	int pause_tx;
+
+	/* if !has_phy, set desired forced speed/duplex */
+	int force_speed_100;
+	int force_duplex_full;
+
+	/* if !has_phy, set callback to perform mii device
+	 * init/remove */
+	int (*mii_config)(struct net_device *dev, int probe,
+			  int (*mii_read)(struct net_device *dev,
+					  int phy_id, int reg),
+			  void (*mii_write)(struct net_device *dev,
+					    int phy_id, int reg, int val));
+};
+
+/*
+ * dsl driver platform data
+ */
+struct bcm963xx_dsl_platform_data {
+
+	/* when filling dma desc, where to read/send cells */
+	unsigned long rx_cell_bus_address;
+	unsigned long tx_cell_bus_address;
+};
+
+/*
+ * USB Device Controller driver platform data
+ */
+struct bcm963xx_udc_platform_data {
+	int ctl_in_dma_irq;
+	int ctl_out_dma_irq;
+	int ctl_in_dma_channel;
+	int ctl_out_dma_channel;
+
+	int bulk_in_dma_irq;
+	int bulk_out_dma_irq;
+	int bulk_in_dma_channel;
+	int bulk_out_dma_channel;
+
+	int iso_in_dma_irq;
+	int iso_out_dma_irq;
+	int iso_in_dma_channel;
+	int iso_out_dma_channel;
+};
+
+/*
+ * PCMCIA driver platform data
+ */
+struct bcm963xx_pcmcia_platform_data {
+	unsigned int ready_gpio;
+};
+
+#endif /* ! ASM_BCM963XX_DEVICES_H_ */
diff -Nruw linux-2.6.20.14-fbx/include/asm-mips/tango2./emhwlib_dram_tango2.inc linux-2.6.20.14-fbx/include/asm-mips/tango2/emhwlib_dram_tango2.inc
--- linux-2.6.20.14-fbx/include/asm-mips/tango2./emhwlib_dram_tango2.inc	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/include/asm-mips/tango2/emhwlib_dram_tango2.inc	2011-09-26 15:07:56.248834257 +0200
@@ -0,0 +1,32 @@
+#
+#******************************************************
+#* This file is generated automatically, DO NOT EDIT! *
+#******************************************************
+#*
+#* destined to be included by a shell script or a Makefile (keep syntax adapted to both)
+#*
+#* emhwlib/include/emhwlib_dram_tango2.inc (generated from emhwlib/include/emhwlib_dram_tango2.h)
+#*
+#* Copyright (c) Sigma Designs, Inc. 2003. All rights reserved.
+#*
+i386=0x1
+linux=0x1
+unix=0x1
+FM_GNET=0x0
+FM_SCRATCH=0xf08
+FM_MEMCFG=0xfc0
+FM_IRQHANDLER_API=0x1000
+FM_XTASK_API=0x9e00
+FM_XOSDBG=0xa000
+FM_XTASK1DBG=0xc000
+FM_XTASK2DBG=0xd000
+FM_XTASK3DBG=0xe000
+FM_XTASK4DBG=0xf000
+FM_SCRATCH2=0x10000
+FM_DRAMCALIBRATION=0x1f000
+FM_RESERVED=0x20000
+FM_ZBOOT=0x1000000
+FM_YAMON_text_ram=0x1000000
+FM_YAMON__ftext_init=0x1100000
+FM_yamon_appl__ftext=0x1110000
+FM_linuxmips__ftext=0x20000
diff -Nruw linux-2.6.20.14-fbx/include/asm-mips/tango2./emhwlib_registers_tango2.inc linux-2.6.20.14-fbx/include/asm-mips/tango2/emhwlib_registers_tango2.inc
--- linux-2.6.20.14-fbx/include/asm-mips/tango2./emhwlib_registers_tango2.inc	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/include/asm-mips/tango2/emhwlib_registers_tango2.inc	2011-09-26 15:07:56.248834257 +0200
@@ -0,0 +1,1191 @@
+#
+#******************************************************
+#* This file is generated automatically, DO NOT EDIT! *
+#******************************************************
+#*
+#* destined to be included by a shell script or a Makefile (keep syntax adapted to both)
+#*
+#* emhwlib_hal/include/tango2/emhwlib_registers_tango2.inc (generated from emhwlib_hal/include/tango2/emhwlib_registers_tango2.h)
+#*
+#* Copyright (c) Sigma Designs, Inc. 2003. All rights reserved.
+#*
+i386=0x1
+linux=0x1
+unix=0x1
+REG_BASE_system_block=0x10000
+SYS_clkgen0_pll=0x0
+SYS_clkgen0_div=0x4
+SYS_clkgen1_pll=0x8
+SYS_clkgen1_div=0xc
+SYS_clkgen2_pll=0x10
+SYS_clkgen2_div=0x14
+SYS_clkgen3_pll=0x18
+SYS_clkgen3_div=0x1c
+SYS_avclk_mux=0x38
+SYS_sysclk_mux=0x3c
+SYS_clk_cnt=0x40
+SYS_xtal_in_cnt=0x48
+DRAM_vbus_w0_cfg=0x300
+DRAM_vbus_w1_cfg=0x304
+DRAM_vbus_w2_cfg=0x308
+DRAM_vbus_w3_cfg=0x30c
+DRAM_vbus_r0_cfg=0x340
+DRAM_vbus_r1_cfg=0x344
+DRAM_vbus_r2_cfg=0x348
+DRAM_vbus_r3_cfg=0x34c
+DRAM_vbus_r4_cfg=0x350
+DRAM_vbus_r5_cfg=0x354
+DRAM_vbus_r6_cfg=0x358
+DRAM_vbus_r7_cfg=0x35c
+DRAM_vbus_r8_cfg=0x360
+DRAM_vbus_r9_cfg=0x364
+DRAM_vbus_r10_cfg=0x368
+DRAM_vbus_r11_cfg=0x36c
+DRAM_mbus_w0_cfg=0x200
+DRAM_mbus_w1_cfg=0x204
+DRAM_mbus_w2_cfg=0x208
+DRAM_mbus_w3_cfg=0x20c
+DRAM_mbus_w4_cfg=0x210
+DRAM_mbus_w5_cfg=0x214
+DRAM_mbus_w6_cfg=0x218
+DRAM_mbus_w7_cfg=0x21c
+DRAM_mbus_w8_cfg=0x220
+DRAM_mbus_w9_cfg=0x224
+DRAM_mbus_w10_cfg=0x228
+DRAM_mbus_r0_cfg=0x240
+DRAM_mbus_r1_cfg=0x244
+DRAM_mbus_r2_cfg=0x248
+DRAM_mbus_r3_cfg=0x24c
+DRAM_mbus_r4_cfg=0x250
+DRAM_mbus_r5_cfg=0x254
+DRAM_mbus_r6_cfg=0x258
+DRAM_mbus_r7_cfg=0x25c
+DRAM_mbus_r8_cfg=0x260
+DRAM_mbus_r9_cfg=0x264
+DRAM_mbus_r10_cfg=0x268
+SYS_hostclk_mux=0x30
+SYS_sysclk_premux=0x34
+SYS_rnd_cnt=0x44
+SYS_cnt_cfg=0x4c
+SYS_cfg_cnt0=0x50
+SYS_cfg_cnt1=0x54
+SYS_cfg_cnt2=0x58
+SYS_cfg_cnt3=0x5c
+SYS_cfg_cnt4=0x60
+SYS_cleandiv0_div=0x80
+SYS_cleandiv1_div=0x88
+SYS_cleandiv2_div=0x90
+SYS_cleandiv4_div=0xa0
+SYS_cleandiv5_div=0xa8
+SYS_cleandiv6_div=0xb0
+SYS_cleandiv7_div=0xb8
+SYS_cleandiv8_div=0xc0
+SYS_cleandiv9_div=0xc8
+SYS_cleandiv10_div=0xd0
+MARB_mid01_cfg=0x200
+MARB_mid21_cfg=0x204
+MARB_mid02_cfg=0x208
+MARB_mid22_cfg=0x20c
+MARB_mid04_cfg=0x210
+MARB_mid24_cfg=0x214
+MARB_mid25_cfg=0x218
+MARB_mid08_cfg=0x21c
+MARB_mid28_cfg=0x220
+MARB_mid29_cfg=0x224
+MARB_mid0C_cfg=0x228
+MARB_mid2C_cfg=0x22c
+MARB_mid10_cfg=0x230
+MARB_mid30_cfg=0x234
+MARB_mid31_cfg=0x238
+MARB_mid12_cfg=0x23c
+MARB_mid32_cfg=0x240
+VARB_mid01_cfg=0x300
+VARB_mid02_cfg=0x304
+VARB_mid21_cfg=0x308
+VARB_mid22_cfg=0x30c
+VARB_mid23_cfg=0x310
+VARB_mid24_cfg=0x314
+VARB_mid25_cfg=0x318
+VARB_mid26_cfg=0x31c
+VARB_mid27_cfg=0x320
+VARB_mid28_cfg=0x324
+VARB_mid29_cfg=0x328
+VARB_mid2A_cfg=0x32c
+VARB_mid10_cfg=0x330
+VARB_mid30_cfg=0x334
+VARB_mid31_cfg=0x338
+IARB_mid01_cfg=0x400
+IARB_mid02_cfg=0x404
+SYS_gpio_dir=0x500
+SYS_gpio_data=0x504
+SYS_gpio_int=0x508
+SYS_gpio15_pwm=0x510
+SYS_gpio14_pwm=0x514
+REG_BASE_dram_controller_0=0x30000
+MEM_BASE_dram_controller_0=0x10000000
+REG_BASE_dram_controller_1=0x40000
+MEM_BASE_dram_controller_1=0x20000000
+REG_BASE_dram_controller_2=0x50000
+MEM_BASE_dram_controller_2=0x30000000
+DRAM_dunit_cfg=0x0
+DRAM_dunit_delay0_ctrl=0x4
+DRAM_dunit_delay1_ctrl=0x8
+DRAM_dunit_auto_delay=0xc
+DRAM_dunit_delay_probe=0x10
+DRAM_dunit_effective_delay=0x14
+DRAM_dunit_bw_probe_cfg=0x20
+DRAM_dunit_bw_probe_cnt=0x24
+DRAM_dunit_flush_buffer=0x104
+REG_BASE_host_interface=0x20000
+MEM_BASE_host_interface=0x40000000
+IDE_data=0x0
+IDE_error=0x4
+IDE_count=0x8
+IDE_start_sector=0xc
+IDE_cylinder_lo=0x10
+IDE_cylinder_hi=0x14
+IDE_head_device=0x18
+IDE_cmd_stat=0x1c
+IDE_irq_stat=0x218
+IDE_cmd_stat__=0x21c
+PB_timing0=0x800
+PB_timing1=0x804
+PB_timing2=0x808
+PB_timing3=0x80c
+PB_timing4=0x810
+PB_timing5=0x814
+PB_default_timing=0x818
+PB_use_timing0=0x81c
+PB_use_timing1=0x820
+PB_use_timing2=0x824
+PB_use_timing3=0x828
+PB_use_timing4=0x82c
+PB_use_timing5=0x830
+PB_CS_config=0x834
+PB_automode_start_address=0x840
+PB_automode_control=0x844
+SFLA_status=0xa000
+SFLA_read_parameters=0xa008
+SFLA_drive_pads=0xa00c
+SFLA_driver_speed=0xa010
+SFLA_N_for_Send_Get=0xa020
+SFLA_read_data=0xa030
+SFLA_Send_1=0xa040
+SFLA_Send_8=0xa044
+SFLA_Send_16=0xa048
+SFLA_Send_32=0xa04c
+SFLA_Send_Get_1=0xa050
+SFLA_Send_Get_8=0xa054
+SFLA_Send_Get_16=0xa058
+SFLA_Send_Get_32=0xa05c
+SFLA_Chip_Select=0xa060
+SFLA_Chip_Deselect=0xa064
+SFLA_Send_N=0xa068
+SFLA_Get_SlaveOut=0xa070
+SFLA_Wait_Timer=0xa074
+SFLA_Send_Get_N=0xa078
+EMHWLIB_IS_HOST=0xe000
+HOST_REG1=0xfed0
+HOST_REG2=0xfed4
+READ_ADDRESS=0xfec0
+READ_COUNTER=0xfec4
+READ_ENABLE=0xfec8
+READ_REVERSE=0xfecc
+WRITE_ADDRESS=0xfed8
+WRITE_COUNTER=0xfedc
+WRITE_ENABLE=0xfee0
+BURST=0xfee4
+PCI_TIMEOUT=0x8000
+PCI_TIMEOUT_STATUS=0x8004
+PCI_TIMER=0x8008
+PCI_TIMER_TEST=0x800c
+PCI_WAKEUP=0x8010
+PCI_REGION_0_BASE=0x9000
+PCI_REGION_1_BASE=0x9004
+PCI_REGION_2_BASE=0x9008
+PCI_REGION_3_BASE=0x900c
+PCI_REGION_4_BASE=0x9010
+PCI_REGION_5_BASE=0x9014
+PCI_REGION_6_BASE=0x9018
+PCI_REGION_7_BASE=0x901c
+PCI_irq_status=0x9020
+PCI_irq_set=0x9024
+PCI_irq_clear=0x9028
+SBOX_FIFO_RESET=0x90a0
+SBOX_ROUTE=0x90a8
+output_SBOX_MBUS_W0=0x9080
+output_SBOX_MBUS_W1=0x9084
+output_SBOX_PCI_MASTER=0x9088
+output_SBOX_PCI_SLAVE=0x908c
+output_SBOX_CIPHER=0x9090
+output_SBOX_IDE_ISA=0x9094
+output_SBOX_IDE_DVD=0x9098
+input_keep_SBOX=0x0
+input_MBUS_R0_SBOX=0x1
+input_MBUS_R1_SBOX=0x2
+input_PCI_MASTER_SBOX=0x3
+input_PCI_SLAVE_SBOX=0x4
+input_CIPHER_SBOX=0x5
+input_IDE_DVD_SBOX=0x6
+input_IDE_ISA_SBOX=0x7
+input_SFLA_SBOX=0x8
+input_unconnected_SBOX=0xf
+host_mutex0=0x9040
+host_mutex1=0x9044
+host_mutex2=0x9048
+host_mutex3=0x904c
+host_mutex4=0x9050
+host_mutex5=0x9054
+host_mutex6=0x9058
+host_mutex7=0x905c
+host_mutex8=0x9060
+host_mutex9=0x9064
+host_mutex10=0x9068
+host_mutex11=0x906c
+host_mutex12=0x9070
+host_mutex13=0x9074
+host_mutex14=0x9078
+host_mutex15=0x907c
+PCI_host_reg5=0xfe94
+PCI_chip_is_host=0xfe90
+IDECTRL_idesrc=0x20d0
+IDECTRL_pri_drv1udmatim1=0x20e0
+IDECTRL_pri_drv1udmatim2=0x20f0
+IDECTRL_pri_idectl=0x2100
+IDECTRL_pri_drv0tim=0x2110
+IDECTRL_pri_drv1tim=0x2120
+IDECTRL_idemisc=0x2130
+IDECTRL_idestatus=0x2140
+IDECTRL_udmactl=0x2150
+IDECTRL_pri_drv0udmatim1=0x2160
+IDECTRL_pri_drv0udmatim2=0x2170
+IDECTRL_pref_st=0x2310
+IDECTRL_pri_ctrlblock=0x2398
+IDECTRL_pri_cmdblock=0x23c0
+IDECTRL_bmic=0x2400
+IDECTRL_bmis=0x2410
+IDECTRL_bmidtp=0x2420
+IDECTRL_ide_dmaptr=0x2780
+IDECTRL_ide_dmalen=0x2790
+IDECTRL_pio_prefetch_data=0x27c0
+MEM_BASE_pfla=0x40000000
+PB_CS0_OFFSET=0x0
+PB_CS1_OFFSET=0x4000000
+PB_CS2_OFFSET=0x8000000
+PB_CS3_OFFSET=0xc000000
+ETH_gpio_dir=0x710c
+ETH_gpio_data=0x7110
+PCI_host_reg1=0xfed0
+PCI_host_reg2=0xfed4
+PCI_host_reg3=0xfe80
+PCI_host_reg4=0xfe84
+PCI_pcictrl_reg1=0xfe88
+PCI_pcictrl_reg2=0xfe8c
+PCI_pcictrl_reg3=0xfefc
+PCI_REG0=0xfee8
+PCI_REG1=0xfeec
+PCI_REG2=0xfef0
+PCI_REG3=0xfef4
+PCI_CONFIG=0xfef8
+MIF_W0_ADD=0xb000
+MIF_W0_CNT=0xb004
+MIF_W0_SKIP=0xb008
+MIF_W0_CMD=0xb00c
+MIF_W1_ADD=0xb040
+MIF_W1_CNT=0xb044
+MIF_W1_SKIP=0xb048
+MIF_W1_CMD=0xb04c
+MIF_R0_ADD=0xb080
+MIF_R0_CNT=0xb084
+MIF_R0_SKIP=0xb088
+MIF_R0_CMD=0xb08c
+MIF_R1_ADD=0xb0c0
+MIF_R1_CNT=0xb0c4
+MIF_R1_SKIP=0xb0c8
+MIF_R1_CMD=0xb0cc
+MBUS_IDLE=0x0
+MBUS_LINEAR=0x1
+MBUS_DOUBLE=0x2
+MBUS_RECTANGLE=0x3
+MBUS_VOID=0x4
+MBUS_LINEAR_VOID=0x5
+MBUS_DOUBLE_VOID=0x6
+MBUS_RECTANGLE_VOID=0x7
+MBUS_TILED=0x8
+GBUS_MUTEX_XPU=0x14
+GBUS_MUTEX_PT110=0x16
+GBUS_MUTEX_TDMX=0x19
+GBUS_MUTEX_AUDIO_0=0x1b
+GBUS_MUTEX_AUDIO_1=0x1c
+GBUS_MUTEX_MPEG_0=0x1d
+GBUS_MUTEX_MPEG_1=0x1e
+GBUS_MUTEX_HOST=0x1f
+GBUS_MUTEX_LOCAL=0x10
+REG_BASE_cpu_block=0x60000
+CPU_time0_load=0xc500
+CPU_time0_value=0xc504
+CPU_time0_ctrl=0xc508
+CPU_time0_clr=0xc50c
+CPU_time1_load=0xc600
+CPU_time1_value=0xc604
+CPU_time1_ctrl=0xc608
+CPU_time1_clr=0xc60c
+CPU_rtc_data=0xc800
+CPU_rtc_match=0xc804
+CPU_rtc_stat=0xc808
+CPU_rtc_load=0xc80c
+CPU_rtc_ctrl=0xc810
+CPU_irq_status=0xe000
+CPU_irq_rawstat=0xe004
+CPU_irq_enableset=0xe008
+CPU_irq_enableclr=0xe00c
+CPU_irq_softset=0xe010
+CPU_irq_softclr=0xe014
+CPU_fiq_status=0xe100
+CPU_fiq_rawstat=0xe104
+CPU_fiq_enableset=0xe108
+CPU_fiq_enableclr=0xe10c
+CPU_fiq_softset=0xe110
+CPU_fiq_softclr=0xe114
+CPU_edge_status=0xe200
+CPU_edge_rawstat=0xe204
+CPU_edge_config_rise=0xe208
+CPU_edge_config_fall=0xe20c
+CPU_SOFT_INT=0x1
+CPU_UART0_INT=0x2
+CPU_UART1_INT=0x4
+CPU_TIMER0_INT=0x20
+CPU_TIMER1_INT=0x40
+CPU_HOST_MBUS_W0_INT=0x200
+CPU_HOST_MBUS_W1_INT=0x400
+CPU_HOST_MBUS_R0_INT=0x800
+CPU_HOST_MBUS_R1_INT=0x1000
+CPU_PCI_INTA=0x2000
+CPU_PCI_INTB=0x4000
+CPU_PCI_INTC=0x8000
+CPU_PCI_INTD=0x10000
+CPU_PCI_FAULT_INT=0x100000
+CPU_INFRARED_INT=0x200000
+CPU_SFLA_INT=0x10
+CPU_DVD_INT=0x80
+CPU_ETH_INT=0x100
+CPU_DMAIDE_INT=0x20000
+CPU_IDE_INT=0x40000
+CPU_FRONTPANEL_INT=0x80000
+CPU_I2C_INT=0x400000
+CPU_GFX_ACCEL_INT=0x800000
+CPU_VSYNC0_INT=0x1000000
+CPU_VSYNC1_INT=0x2000000
+CPU_VSYNC2_INT=0x4000000
+CPU_VSYNC3_INT=0x8000000
+CPU_VSYNC4_INT=0x10000000
+CPU_VSYNC4BKEND_INT=0x20000000
+CPU_VSYNC5_INT=0x40000000
+CPU_VSYNC5BKEND_INT=0x80000000
+CPU_SMARTCARD_HI_INT=0x1
+CPU_HDMI_HI_INT=0x2
+CPU_HDMI_I2C_HI_INT=0x4
+CPU_VBUS_W0_HI_INT=0x8
+CPU_VBUS_W3_HI_INT=0x10
+CPU_ETH_PHY_HI_INT=0x20
+CPU_ETH_MAC_HI_INT=0x40
+CPU_USB_OHCI_MAC_HI_INT=0x80
+CPU_USB_EHCI_MAC_HI_INT=0x100
+LOG2_CPU_SOFT_INT=0x0
+LOG2_CPU_UART0_INT=0x1
+LOG2_CPU_UART1_INT=0x2
+LOG2_CPU_TIMER0_INT=0x5
+LOG2_CPU_TIMER1_INT=0x6
+LOG2_CPU_DVD_INT=0x7
+LOG2_CPU_RTC_INT=0x8
+LOG2_CPU_HOST_MBUS_W0_INT=0x9
+LOG2_CPU_HOST_MBUS_W1_INT=0xa
+LOG2_CPU_HOST_MBUS_R0_INT=0xb
+LOG2_CPU_HOST_MBUS_R1_INT=0xc
+LOG2_CPU_PCI_INTA=0xd
+LOG2_CPU_PCI_INTB=0xe
+LOG2_CPU_PCI_INTC=0xf
+LOG2_CPU_PCI_INTD=0x10
+LOG2_CPU_DMAIDE_INT=0x11
+LOG2_CPU_IDE_INT=0x12
+LOG2_CPU_FRONTPANEL_INT=0x13
+LOG2_CPU_PCI_FAULT_INT=0x14
+LOG2_CPU_INFRARED_INT=0x15
+LOG2_CPU_I2C_INT=0x16
+LOG2_CPU_GFX_ACCEL_INT=0x17
+LOG2_CPU_VSYNC0_INT=0x18
+LOG2_CPU_VSYNC1_INT=0x19
+LOG2_CPU_VSYNC2_INT=0x1a
+LOG2_CPU_VSYNC3_INT=0x1b
+LOG2_CPU_VSYNC4_INT=0x1c
+LOG2_CPU_VSYNC4BKEND_INT=0x1d
+LOG2_CPU_VSYNC5_INT=0x1e
+LOG2_CPU_VSYNC5BKEND_INT=0x1f
+LOG2_CPU_SMARTCARD_INT=0x20
+LOG2_CPU_HDMI_INT=0x21
+LOG2_CPU_HDMI_I2C_INT=0x22
+LOG2_CPU_VBUS_W0_INT=0x23
+LOG2_CPU_VBUS_W3_INT=0x24
+LOG2_CPU_ETH_PHY_INT=0x25
+LOG2_CPU_ETH_MAC_INT=0x26
+LOG2_CPU_USB_OHCI_INT=0x27
+LOG2_CPU_USB_EHCI_INT=0x28
+CPU_edge_status_hi=0xe220
+CPU_edge_rawstat_hi=0xe224
+CPU_edge_config_rise_hi=0xe228
+CPU_edge_config_fall_hi=0xe22c
+CPU_irq_status_hi=0xe018
+CPU_irq_rawstat_hi=0xe01c
+CPU_irq_enableset_hi=0xe020
+CPU_irq_enableclr_hi=0xe024
+CPU_fiq_status_hi=0xe118
+CPU_fiq_rawstat_hi=0xe11c
+CPU_fiq_enableset_hi=0xe120
+CPU_fiq_enableclr_hi=0xe124
+CPU_iiq_status=0xe300
+CPU_iiq_rawstat=0xe304
+CPU_iiq_enableset=0xe308
+CPU_iiq_enableclr=0xe30c
+CPU_iiq_softset=0xe310
+CPU_iiq_softclr=0xe314
+CPU_iiq_status_hi=0xe318
+CPU_iiq_rawstat_hi=0xe31c
+CPU_iiq_enableset_hi=0xe320
+CPU_iiq_enableclr_hi=0xe324
+CPU_UART_GPIOMODE=0x38
+CPU_UART_GPIODIR=0x30
+CPU_UART_GPIODATA=0x34
+CPU_edge_config_rise_set=0xe210
+CPU_edge_config_rise_clr=0xe214
+CPU_edge_config_fall_set=0xe218
+CPU_edge_config_fall_clr=0xe21c
+CPU_edge_config_rise_set_hi=0xe230
+CPU_edge_config_rise_clr_hi=0xe234
+CPU_edge_config_fall_set_hi=0xe238
+CPU_edge_config_fall_clr_hi=0xe23c
+CPU_pm_select_0=0xc900
+CPU_pm_counter_0=0xc904
+CPU_pm_select_1=0xc908
+CPU_pm_counter_1=0xc90c
+CPU_remap=0xf000
+CPU_remap1=0xf004
+CPU_remap2=0xf008
+CPU_remap3=0xf00c
+CPU_remap4=0xf010
+CPU_remap_address=0x1fc00000
+CPU_remap1_address=0x0
+CPU_remap2_address=0x4000000
+CPU_remap3_address=0x8000000
+CPU_remap4_address=0xc000000
+REG_BASE_xpu_block=0xe0000
+REG_BASE_irq_handler_block=0xe0000
+G2L_BIST_BUSY=0xffe0
+G2L_BIST_PASS=0xffe4
+G2L_BIST_MASK=0xffe8
+G2L_RESET_CONTROL=0xfffc
+CPU_UART0_base=0xc100
+CPU_UART1_base=0xc200
+CPU_UART_RBR=0x0
+CPU_UART_THR=0x4
+CPU_UART_IER=0x8
+CPU_UART_IIR=0xc
+CPU_UART_FCR=0x10
+CPU_UART_LCR=0x14
+CPU_UART_MCR=0x18
+CPU_UART_LSR=0x1c
+CPU_UART_MSR=0x20
+CPU_UART_SCR=0x24
+CPU_UART_CLKDIV=0x28
+CPU_UART_CLKSEL=0x2c
+REG_BASE_display_block=0x70000
+VO_run=0x0
+VO_reset_datapath=0x4
+VO_reset_timing=0x8
+VO_reset_config=0xc
+VO_reset_mode_0=0x14
+VO_reset_mode_1=0x18
+VIF_w0=0x4000
+VIF_w1=0x4100
+VIF_w2=0x4200
+VIF_w3=0x4f00
+VIF_r0=0x4300
+VIF_r1=0x4400
+VIF_r2=0x4500
+VIF_r3=0x4600
+VIF_r4=0x4700
+VIF_r5=0x4800
+VIF_r6=0x4900
+VIF_r7=0x4a00
+VIF_r8=0x4b00
+VIF_r9=0x4c00
+VIF_r10=0x4d00
+VIF_r11=0x4e00
+VIF_offs=0x100
+VIF_add=0x0
+VIF_cnt=0x4
+VIF_skip=0x8
+VIF_cmd=0xc
+VIF_addB=0x10
+VIF_cntB=0x14
+VIF_skipB=0x18
+VBUS_IDLE=0x0
+VBUS_LINEAR=0x1
+VBUS_DOUBLE=0x2
+VBUS_RECTANGLE=0x3
+VBUS_DOUBLE_FIELD=0x4
+VBUS_DOUBLE_RECTANGLE=0x5
+VBUS_8BYTE_COLUMN=0x6
+VBUS_VOID=0x8
+VBUS_LINEAR_VOID=0x9
+VBUS_DOUBLE_VOID=0xa
+VBUS_RECTANGLE_VOID=0xb
+VBUS_DOUBLE_FIELD_VOID=0xc
+VBUS_DOUBLE_RECTANGLE_VOID=0xd
+VBUS_8BYTE_COLUMN_VOID=0xe
+VO_hdmi_reset_bit=0x17
+VO_hdmi_config=0x3d00
+VO_hdmi_i2c=0x3dc0
+VO_hdmi_keymem=0x3e00
+VO_osd_reset_bit=0x3
+VO_osd_format_hds=0x300
+VO_osd_output_size=0x304
+VO_osd_scale_factor=0x308
+VO_osd_scale_phase_flicker=0x30c
+VO_osd_alpha_routing=0x310
+VO_osd_key_color=0x314
+VO_osd_lut=0x9000
+VO_osd_lut0=0x9000
+VO_cursor_reset_bit=0x1
+VO_cursor_size_ctrl=0x100
+VO_cursor_lut=0x140
+VO_cursor_lut0=0x140
+VO_cursor_lut1=0x144
+VO_cursor_lut2=0x148
+VO_cursor_lut3=0x14c
+VO_cursor_lut4=0x150
+VO_cursor_lut5=0x154
+VO_cursor_lut6=0x158
+VO_cursor_lut7=0x15c
+VO_cursor_lut8=0x160
+VO_cursor_lut9=0x164
+VO_cursor_lut10=0x168
+VO_cursor_lut11=0x16c
+VO_cursor_lut12=0x170
+VO_cursor_lut13=0x174
+VO_cursor_lut14=0x178
+VO_cursor_lut15=0x17c
+VO_cursor_pix=0x8000
+VO_cursor_pix0=0x8000
+VO_main_reset_bit=0x4
+VO_main_format_hds=0x400
+VO_main_output_size=0x404
+VO_main_scale_factor=0x408
+VO_main_scale_phase=0x40c
+VO_main_phase=0x40c
+VO_main_alpha_deint_routing=0x410
+VO_main_deint2=0x414
+VO_main_bcs=0x418
+VO_main_pulldown=0x41c
+VO_main_strip_filter=0x420
+VO_main_nonlinear_0=0x424
+VO_main_nonlinear_1=0x428
+VO_main_bcs2=0x42c
+VO_subp_reset_bit=0x2
+VO_subp_format_hds=0x200
+VO_subp_output_size=0x204
+VO_subp_scale_factor=0x208
+VO_subp_scale_phase_routing=0x20c
+VO_sp_lut=0x9400
+VO_sp_lut0=0x9400
+VO_VCR_reset_bit=0x5
+VO_VCR_format_hds=0x500
+VO_VCR_output_size=0x504
+VO_VCR_scale_factor=0x508
+VO_VCR_scale_phase=0x50c
+VO_VCR_phase=0x50c
+VO_VCR_alpha_routing=0x510
+VO_VCR_key_color=0x514
+VO_VCR_bcs=0x518
+VO_VCR_strip_edge=0x51c
+VO_VCR_nonlinear_0=0x520
+VO_VCR_nonlinear_1=0x524
+VO_VCR_tiling=0x528
+VO_VCR_bcs2=0x52c
+VO_VCR_lut=0xa000
+VO_VCR_lut0=0xa000
+VO_CRT_reset_bit=0x6
+VO_CRT_format_hds=0x600
+VO_CRT_output_size=0x604
+VO_CRT_scale_factor=0x608
+VO_CRT_scale_phase=0x60c
+VO_CRT_phase=0x60c
+VO_CRT_alpha_routing=0x610
+VO_CRT_key_color=0x614
+VO_CRT_bcs=0x618
+VO_CRT_strip_edge=0x61c
+VO_CRT_nonlinear_0=0x620
+VO_CRT_nonlinear_1=0x624
+VO_CRT_tiling=0x628
+VO_CRT_bcs2=0x62c
+VO_CRT_lut=0xb000
+VO_CRT_lut0=0xb000
+VO_GFX_reset_bit=0x7
+VO_GFX_format_hds=0x700
+VO_GFX_output_size=0x704
+VO_GFX_scale_factor=0x708
+VO_GFX_scale_phase=0x70c
+VO_GFX_phase=0x70c
+VO_GFX_alpha_routing=0x710
+VO_GFX_key_color=0x714
+VO_GFX_bcs=0x718
+VO_GFX_strip_edge=0x71c
+VO_GFX_nonlinear_0=0x720
+VO_GFX_nonlinear_1=0x724
+VO_GFX_tiling=0x728
+VO_GFX_bcs2=0x72c
+VO_GFX_lut=0xc000
+VO_GFX_lut0=0xc000
+VO_mix_reset_bit=0x8
+VO_mix_gfx_pos=0x800
+VO_mix_crt_pos=0x804
+VO_mix_vcr_pos=0x808
+VO_mix_sp_pos=0x80c
+VO_mix_mv_pos=0x810
+VO_mix_osd_pos=0x814
+VO_mix_gin_pos=0x818
+VO_mix_cur_pos=0x81c
+VO_mix_index=0x820
+VO_mix_frame_size=0x824
+VO_mix_background=0x828
+VO_vcrmix_reset_bit=0x9
+VO_vcrmix_gfx_pos=0x900
+VO_vcrmix_crt_pos=0x904
+VO_vcrmix_sp_pos=0x908
+VO_vcrmix_vcr_pos=0x90c
+VO_vcrmix_index=0x910
+VO_vcrmix_frame_size=0x914
+VO_vcrmix_background=0x918
+VO_color_bars_reset_bit=0xb
+VO_color_bars_ctrl=0xd00
+VO_color_bars_size=0xd04
+VO_routing_reset_bit=0x16
+VO_routing_ctrl=0x1208
+VO_vid_in_reset_bit=0x10
+VO_vid_in_format=0xb00
+VO_vid_in_data_size=0xb04
+VO_vid_in_data_Xoffset=0xb08
+VO_vid_in_data_Yoffset=0xb0c
+VO_vid_in_hz_sync=0xb10
+VO_vid_in_vt_sync=0xb14
+VO_vid_in_sync_coord=0xb18
+VO_vid_in_top_vbi=0xb1c
+VO_vid_in_bot_vbi=0xb20
+VO_vid_in_counters=0xb24
+VO_vid_in_vbi_size=0xb28
+VO_vid_in_vbi_vsm=0xb2c
+VO_vid_in_vbi_Voffset=0xb30
+VO_vid_in_format2=0xb34
+VO_vid_in_counters2=0xb38
+VO_graph_in_reset_bit=0x11
+VO_graph_in_format=0xc00
+VO_graph_in_alpha_routing=0xc04
+VO_graph_in_key_color=0xc08
+VO_graph_in_data_size=0xc0c
+VO_graph_in_data_Xoffset=0xc10
+VO_graph_in_data_Yoffset=0xc14
+VO_graph_in_hz_sync=0xc18
+VO_graph_in_vt_sync=0xc1c
+VO_graph_in_sync_coord=0xc20
+VO_graph_in_sync_offset=0xc24
+VO_graph_in_top_vbi=0xc28
+VO_graph_in_bot_vbi=0xc2c
+VO_graph_in_counters=0xc30
+VO_graph_in_format2=0xc34
+VO_graph_in_counters2=0xc38
+VO_graph_in_vbi_size=0xc3c
+VO_graph_in_vbi_vsm=0xc40
+VO_graph_in_vbi_Voffset=0xc44
+VO_digit_out_reset_bit=0x12
+VO_digit_out_conv0=0xe00
+VO_digit_out_conv1=0xe04
+VO_digit_out_conv2=0xe08
+VO_digit_out_conv3=0xe0c
+VO_digit_out_conv4=0xe10
+VO_digit_out_conv5=0xe14
+VO_digit_out_format=0xe20
+VO_digit_out_Xoffset=0xe24
+VO_digit_out_Yoffset=0xe28
+VO_digit_out_hz_sync=0xe2c
+VO_digit_out_vt_sync=0xe30
+VO_digit_out_vsync_coord=0xe34
+VO_digit_out_pads_config=0x20
+VO_digit_out_gamma_lut0=0xf000
+VO_digit_out_temp_lut0=0xf400
+VO_digit_out_sync_ext_sync=0xe38
+VO_main_analog_reset_bit=0x13
+VO_main_analog_conv0=0xf00
+VO_main_analog_conv1=0xf04
+VO_main_analog_conv2=0xf08
+VO_main_analog_conv3=0xf0c
+VO_main_analog_conv4=0xf10
+VO_main_analog_conv5=0xf14
+VO_main_analog_xoffset_field=0xf18
+VO_main_analog_yoffset=0xf1c
+VO_main_analog_cvbs_conv0=0xf20
+VO_main_analog_cvbs_conv1=0xf24
+VO_main_analog_cvbs_conv2=0xf28
+VO_main_analog_cvbs_conv3=0xf2c
+VO_main_analog_cvbs_conv4=0xf30
+VO_main_analog_cvbs_conv5=0xf34
+VO_main_analog_TV_config=0xf40
+VO_main_analog_TV_size=0xf44
+VO_main_analog_TV_hsync=0xf48
+VO_main_analog_TV_vsync_O_0=0xf4c
+VO_main_analog_TV_vsync_O_1=0xf50
+VO_main_analog_TV_vsync_E_0=0xf54
+VO_main_analog_TV_vsync_E_1=0xf58
+VO_main_analog_TV_HD_hsync_info=0xf5c
+VO_main_analog_TV_HD_vsync=0xf60
+VO_main_analog_TV_CGMS=0xf64
+VO_main_analog_TV_CC_AGC=0xf68
+VO_main_analog_TV_test_config=0xf6c
+VO_main_analog_TV_teletext_config=0xf70
+VO_main_analog_TV_MV_N_0_22=0xf80
+VO_main_analog_TV_MV_N_1_2_3_4=0xf84
+VO_main_analog_TV_MV_N_5_6_7_8=0xf88
+VO_main_analog_TV_MV_N_9_10_11=0xf8c
+VO_main_analog_TV_MV_N_12_13_14=0xf90
+VO_main_analog_TV_MV_N_15_16_17_18=0xf94
+VO_main_analog_TV_MV_N_19_20_21=0xf98
+VO_main_analog_TV_timing_sync=0xf7c
+VO_component_out_reset_bit=0x14
+VO_component_out_conv0=0x1000
+VO_component_out_conv1=0x1004
+VO_component_out_conv2=0x1008
+VO_component_out_conv3=0x100c
+VO_component_out_conv4=0x1010
+VO_component_out_conv5=0x1014
+VO_component_out_xoffset_field=0x1018
+VO_component_out_yoffset=0x101c
+VO_component_out_TV_config=0x1040
+VO_component_out_TV_size=0x1044
+VO_component_out_TV_hsync=0x1048
+VO_component_out_TV_vsync_O_0=0x104c
+VO_component_out_TV_vsync_O_1=0x1050
+VO_component_out_TV_vsync_E_0=0x1054
+VO_component_out_TV_vsync_E_1=0x1058
+VO_component_out_TV_HD_hsync_info=0x105c
+VO_component_out_TV_HD_vsync=0x1060
+VO_component_out_TV_CGMS=0x1064
+VO_component_out_TV_CC_AGC=0x1068
+VO_component_out_TV_test_config=0x106c
+VO_component_out_TV_MV_N_0_22=0x1080
+VO_component_out_TV_MV_N_1_2_3_4=0x1084
+VO_component_out_TV_MV_N_5_6_7_8=0x1088
+VO_component_out_TV_MV_N_9_10_11=0x108c
+VO_component_out_TV_MV_N_12_13_14=0x1090
+VO_component_out_TV_MV_N_15_16_17_18=0x1094
+VO_component_out_TV_MV_N_19_20_21=0x1098
+VO_component_out_TV_timing_sync=0x1078
+VO_composite_out_reset_bit=0x15
+VO_composite_out_bcs=0x1100
+VO_composite_out_Xoffset=0x1104
+VO_composite_out_Yoffset=0x1108
+VO_composite_out_TV_config=0x1140
+VO_composite_out_TV_size=0x1144
+VO_composite_out_TV_hsync=0x1148
+VO_composite_out_TV_vsync_O_0=0x114c
+VO_composite_out_TV_vsync_O_1=0x1150
+VO_composite_out_TV_vsync_E_0=0x1154
+VO_composite_out_TV_vsync_E_1=0x1158
+VO_composite_out_TV_CGMS=0x1164
+VO_composite_out_TV_CC_AGC=0x1168
+VO_composite_out_TV_test_config=0x116c
+VO_composite_out_TV_MV_N_0_22=0x1180
+VO_composite_out_TV_MV_N_1_2_3_4=0x1184
+VO_composite_out_TV_MV_N_5_6_7_8=0x1188
+VO_composite_out_TV_MV_N_9_10_11=0x118c
+VO_composite_out_TV_MV_N_12_13_14=0x1190
+VO_composite_out_TV_MV_N_15_16_17_18=0x1194
+VO_composite_out_TV_MV_N_19_20_21=0x1198
+REG_BASE_demux_engine=0xa0000
+MEM_BASE_demux_engine=0x140000
+PMEM_BASE_demux_engine=0x140000
+DMEM_BASE_demux_engine=0x150000
+demux_MISC_dr_mode=0x2f00
+demux_MISC_dr_length=0x2f01
+demux_MISC_dr_address=0x2f02
+demux_MISC_dw_mode=0x2f04
+demux_MISC_dw_length=0x2f05
+demux_MISC_dw_address=0x2f06
+demux_MISC_reset0=0x2f08
+demux_MISC_reset1=0x2f09
+demux_MISC_interrupt=0x2f0a
+demux_MISC_timer_div=0x2f0b
+demux_MISC_timer_count=0x2f0c
+demux_mutex0=0x2f10
+demux_mutex1=0x2f11
+demux_mutex2=0x2f12
+demux_mutex3=0x2f13
+demux_mutex4=0x2f14
+demux_mutex5=0x2f15
+demux_mutex6=0x2f16
+demux_mutex7=0x2f17
+demux_GBUSIF_MAIN_WADD=0x2ea0
+demux_GBUSIF_MAIN_RADD=0x2ea1
+demux_GBUSIF_MAIN_BYTE=0x2ea2
+demux_GBUSIF_MAIN_WORD=0x2ea3
+demux_GBUSIF_MAIN_DWORD=0x2ea4
+demux_GBUSIF_MAIN_STATUS=0x2ea5
+demux_GBUSIF_ISR_WADD=0x2ea8
+demux_GBUSIF_ISR_RADD=0x2ea9
+demux_GBUSIF_ISR_BYTE=0x2eaa
+demux_GBUSIF_ISR_WORD=0x2eab
+demux_GBUSIF_ISR_DWORD=0x2eac
+demux_GBUSIF_ISR_STATUS=0x2ead
+demux_MBUSIF_w0_add=0x2ec0
+demux_MBUSIF_w0_cnt=0x2ec1
+demux_MBUSIF_w0_skip=0x2ec2
+demux_MBUSIF_w0_cmd=0x2ec3
+demux_MBUSIF_r0_add=0x2ed0
+demux_MBUSIF_r0_cnt=0x2ed1
+demux_MBUSIF_r0_skip=0x2ed2
+demux_MBUSIF_r0_cmd=0x2ed3
+demux_cipher_c2_secret_key=0x2c00
+demux_cipher_c2_key_lsb=0x2c70
+demux_cipher_c2_key_msb=0x2c71
+demux_cipher_c2g_ecb_data_lsb=0x2c72
+demux_cipher_c2g_ecb_data_msb=0x2c73
+demux_cipher_c2_flags=0x2c74
+demux_cipher_multi2_syst_key=0x2c80
+demux_cipher_multi2_data_key=0x2c88
+demux_cipher_multi2_iv=0x2c8a
+demux_cipher_multi2_flags=0x2c8c
+demux_cipher_config=0x2c8f
+demux_cipher_rc4_key_0=0x2e40
+demux_cipher_rc4_key_1=0x2e41
+demux_cipher_rc4_key_2=0x2e42
+demux_cipher_rc4_key_3=0x2e43
+demux_cipher_rc4_key_4=0x2e44
+demux_cipher_rc4_key_5=0x2e45
+demux_cipher_rc4_key_6=0x2e46
+demux_cipher_rc4_key_7=0x2e47
+demux_cipher_rc4_flags=0x2e48
+demux_cipher_des_key1_1=0x2e50
+demux_cipher_des_key1_2=0x2e51
+demux_cipher_des_key2_1=0x2e52
+demux_cipher_des_key2_2=0x2e53
+demux_cipher_des_key3_1=0x2e54
+demux_cipher_des_key3_2=0x2e55
+demux_cipher_des_IV_1=0x2e56
+demux_cipher_des_IV_2=0x2e57
+demux_cipher_des_flags=0x2e58
+demux_cipher_dvbcsa_key_lsb=0x2e5c
+demux_cipher_dvbcsa_key_msb=0x2e5d
+demux_cipher_dvbcsa_flags=0x2e5e
+demux_cipher_aes_key_1=0x2e60
+demux_cipher_aes_key_2=0x2e61
+demux_cipher_aes_key_3=0x2e62
+demux_cipher_aes_key_4=0x2e63
+demux_cipher_aes_key_5=0x2e64
+demux_cipher_aes_key_6=0x2e65
+demux_cipher_aes_key_7=0x2e66
+demux_cipher_aes_key_8=0x2e67
+demux_cipher_aes_flags=0x2e68
+demux_cipher_aes_IV_1=0x2e69
+demux_cipher_aes_IV_2=0x2e6a
+demux_cipher_aes_IV_3=0x2e6b
+demux_cipher_aes_IV_4=0x2e6c
+demux_cipher_aes_IV_5=0x2e6d
+demux_cipher_aes_IV_6=0x2e6e
+demux_cipher_aes_IV_7=0x2e6f
+demux_cipher_aes_IV_8=0x2e70
+demux_cipher_dvd_cnt=0x2e78
+demux_cipher_dvd_tklo=0x2e7a
+demux_cipher_dvd_tkhi=0x2e7b
+demux_cipher_dvd_state0=0x2e7c
+demux_cipher_dvd_state1=0x2e7d
+demux_cw_ram_multi2_syst_key=0x2a00
+demux_cw_ram_multi2_data_key=0x2a80
+demux_cw_ram_multi2_iv=0x2aa0
+demux_cw_ram_rc4_key=0x2ac0
+demux_cw_ram_aes_key=0x2b00
+demux_cw_ram_aes_iv=0x2b08
+demux_cw_ram_dvbcsa_key=0x2b60
+demux_cw_ram_des_key1=0x2b80
+demux_cw_ram_des_key2=0x2ba0
+demux_cw_ram_des_key3=0x2bc0
+demux_cw_ram_des_iv=0x2be0
+demux_section_filter_start=0x3800
+demux_channel_status=0x3e08
+demux_channel_config_routing=0x3e09
+demux_ts_frame_size=0x3e0a
+demux_pat0_pidentry=0x3cc0
+demux_pat0_outputmask=0x3cc1
+demux_cat0_pidentry=0x3cc2
+demux_cat0_outputmask=0x3cc3
+demux_mgt0_pidentry=0x3cc4
+demux_mgt0_outputmask=0x3cc5
+demux_pcr0_outputmask=0x3cc6
+demux_pat1_pidentry=0x3cc8
+demux_pat1_outputmask=0x3cc9
+demux_cat1_pidentry=0x3cca
+demux_cat1_outputmask=0x3ccb
+demux_mgt1_pidentry=0x3ccc
+demux_mgt1_outputmask=0x3ccd
+demux_pcr1_outputmask=0x3cce
+demux_pat2_pidentry=0x3cd0
+demux_pat2_outputmask=0x3cd1
+demux_cat2_pidentry=0x3cd2
+demux_cat2_outputmask=0x3cd3
+demux_mgt2_pidentry=0x3cd4
+demux_mgt2_outputmask=0x3cd5
+demux_pcr2_outputmask=0x3cd6
+demux_splice0_status=0x3ce0
+demux_splice1_status=0x3ce1
+demux_splice2_status=0x3ce2
+demux_pid_bank=0x3d00
+demux_spi_write_ptr0=0x1e08
+demux_spi_write_ptr1=0x1e09
+demux_spi_write_ptr2=0x1e0a
+demux_spi_write_ptr3=0x1e0b
+demux_spi_routing=0x1e0c
+demux_spi_clk_phase=0x1e0d
+demux_spi_sync_bytes=0x1e0e
+demux_idma_write_ptr=0x1e18
+demux_idma_cnt=0x1e19
+demux_odma_read_ptr=0x1e20
+demux_odma_cnt=0x1e21
+demux_odma_sc_stat=0x1e22
+demux_odma_sc_match=0x1e23
+demux_sbox_mode=0x1e28
+demux_MISC_UNRESET_MASK=0xd800
+demux_MISC_RESET_MASK=0xd8d8
+demux_SP_init=0x7fe
+REG_BASE_mpeg_engine_0=0x80000
+MEM_BASE_mpeg_engine_0=0x100000
+PMEM_BASE_mpeg_engine_0=0x100000
+DMEM_BASE_mpeg_engine_0=0x110000
+REG_BASE_mpeg_engine_1=0x90000
+MEM_BASE_mpeg_engine_1=0x120000
+PMEM_BASE_mpeg_engine_1=0x120000
+DMEM_BASE_mpeg_engine_1=0x130000
+mpeg_mutex0=0xfe0
+mpeg_mutex1=0xfe1
+mpeg_mutex2=0xfe2
+mpeg_mutex3=0xfe3
+mpeg_mutex4=0xfe4
+mpeg_mutex5=0xfe5
+mpeg_mutex6=0xfe6
+mpeg_mutex7=0xfe7
+RBUS_offset=0x4000
+mpeg_MBUSIF_w0_addlo=0xe80
+mpeg_MBUSIF_w0_addhi=0xe81
+mpeg_MBUSIF_w0_xcnt=0xe82
+mpeg_MBUSIF_w0_ycnt=0xe83
+mpeg_MBUSIF_w0_skiplo=0xe84
+mpeg_MBUSIF_w0_skiphi=0xe85
+mpeg_MBUSIF_w0_cmd=0xe86
+mpeg_MBUSIF_w0_vbuf_width=0xe87
+mpeg_MBUSIF_r0_addlo=0xe90
+mpeg_MBUSIF_r0_addhi=0xe91
+mpeg_MBUSIF_r0_xcnt=0xe92
+mpeg_MBUSIF_r0_ycnt=0xe93
+mpeg_MBUSIF_r0_skiplo=0xe94
+mpeg_MBUSIF_r0_skiphi=0xe95
+mpeg_MBUSIF_r0_cmd=0xe96
+mpeg_MBUSIF_r0_vbuf_width=0xe97
+mpeg_MBUSIF_r1_addlo=0xea0
+mpeg_MBUSIF_r1_addhi=0xea1
+mpeg_MBUSIF_r1_xcnt=0xea2
+mpeg_MBUSIF_r1_ycnt=0xea3
+mpeg_MBUSIF_r1_skiplo=0xea4
+mpeg_MBUSIF_r1_skiphi=0xea5
+mpeg_MBUSIF_r1_cmd=0xea6
+mpeg_MBUSIF_r1_vbuf_width=0xea7
+mpeg_MBUSIF_w1_addlo=0xeb0
+mpeg_MBUSIF_w1_addhi=0xeb1
+mpeg_MBUSIF_w1_xcnt=0xeb2
+mpeg_MBUSIF_w1_ycnt=0xeb3
+mpeg_MBUSIF_w1_skiplo=0xeb4
+mpeg_MBUSIF_w1_skiphi=0xeb5
+mpeg_MBUSIF_w1_cmd=0xeb6
+mpeg_MBUSIF_w1_vbuf_width=0xeb7
+mpeg_MBUSIF_r2_addlo=0xec0
+mpeg_MBUSIF_r2_addhi=0xec1
+mpeg_MBUSIF_r2_xcnt=0xec2
+mpeg_MBUSIF_r2_ycnt=0xec3
+mpeg_MBUSIF_r2_skiplo=0xec4
+mpeg_MBUSIF_r2_skiphi=0xec5
+mpeg_MBUSIF_r2_cmd=0xec6
+mpeg_MBUSIF_r2_vbuf_width=0xec7
+mpeg_GBUSIF_MAIN_WADD_LOW=0xfa0
+mpeg_GBUSIF_MAIN_WADD_HIGH=0xfa1
+mpeg_GBUSIF_MAIN_RADD_LOW=0xfa2
+mpeg_GBUSIF_MAIN_RADD_HIGH=0xfa3
+mpeg_GBUSIF_MAIN_BYTE=0xfa4
+mpeg_GBUSIF_MAIN_WORD=0xfa5
+mpeg_GBUSIF_MAIN_DWORD_LOW=0xfa6
+mpeg_GBUSIF_MAIN_DWORD_HIGH=0xfa7
+mpeg_GBUSIF_MAIN_STATUS=0xfa8
+mpeg_GBUSIF_ISR_WADD_LOW=0xfb0
+mpeg_GBUSIF_ISR_WADD_HIGH=0xfb1
+mpeg_GBUSIF_ISR_RADD_LOW=0xfb2
+mpeg_GBUSIF_ISR_RADD_HIGH=0xfb3
+mpeg_GBUSIF_ISR_BYTE=0xfb4
+mpeg_GBUSIF_ISR_WORD=0xfb5
+mpeg_GBUSIF_ISR_DWORD_LOW=0xfb6
+mpeg_GBUSIF_ISR_DWORD_HIGH=0xfb7
+mpeg_GBUSIF_ISR_STATUS=0xfb8
+mpeg_MISC_dr_mode=0xff0
+mpeg_MISC_dr_length=0xff1
+mpeg_MISC_dr_address=0xff2
+mpeg_MISC_sbox_mode=0xff3
+mpeg_MISC_dw_mode=0xff4
+mpeg_MISC_dw_length=0xff5
+mpeg_MISC_dw_address=0xff6
+mpeg_MISC_codec_type=0xff7
+mpeg_MISC_reset0=0xff8
+mpeg_MISC_reset1=0xff9
+mpeg_MISC_interrupt=0xffa
+mpeg_MISC_timer_div=0xffb
+mpeg_MISC_timer_count=0xffc
+mpeg_MISC_sbox_read_ctrl=0xffd
+mpeg_MISC_sbox_write_ctrl=0xffe
+mpeg_MISC_reserved2=0xfff
+mpeg_MISC_UNRESET_MASK=0x3500
+mpeg_MISC_RESET_MASK=0x3535
+mpeg_SP_init=0x7fe
+REG_BASE_audio_engine_0=0xc0000
+MEM_BASE_audio_engine_0=0x180000
+PMEM_BASE_audio_engine_0=0x180000
+DMEM_BASE_audio_engine_0=0x190000
+REG_BASE_audio_engine_1=0xd0000
+MEM_BASE_audio_engine_1=0x1a0000
+PMEM_BASE_audio_engine_1=0x1a0000
+DMEM_BASE_audio_engine_1=0x1b0000
+audio_SO_L0_DATA=0x3e00
+audio_SO_R0_DATA=0x3e01
+audio_SO_L1_DATA=0x3e02
+audio_SO_R1_DATA=0x3e03
+audio_SO_L2_DATA=0x3e04
+audio_SO_R2_DATA=0x3e05
+audio_SO_LS_DATA=0x3e06
+audio_SO_RS_DATA=0x3e07
+audio_SO_CH_INTR=0x3e08
+audio_SO_CH_CTRL=0x3e09
+audio_SO_SPDIF_CH_STAT=0x3e0a
+audio_SO_AUDIO_CLK_DIV=0x3e0e
+audio_SI_L0_DATA=0x3e40
+audio_SI_R0_DATA=0x3e41
+audio_SI_STATUS=0x3e42
+audio_SI_CONF=0x3e43
+audio_SI_SPDIF_STATUS=0x3e44
+audio_mutex0=0x3e90
+audio_mutex1=0x3e91
+audio_mutex2=0x3e92
+audio_mutex3=0x3e93
+audio_mutex4=0x3e94
+audio_mutex5=0x3e95
+audio_mutex6=0x3e96
+audio_mutex7=0x3e97
+audio_MBUSIF_w0_add=0x3ec0
+audio_MBUSIF_w0_cnt=0x3ec1
+audio_MBUSIF_w0_skip=0x3ec2
+audio_MBUSIF_w0_cmd=0x3ec3
+audio_MBUSIF_r0_add=0x3ed0
+audio_MBUSIF_r0_cnt=0x3ed1
+audio_MBUSIF_r0_skip=0x3ed2
+audio_MBUSIF_r0_cmd=0x3ed3
+audio_GBUSIF_MAIN_WADD=0x3ea0
+audio_GBUSIF_MAIN_RADD=0x3ea1
+audio_GBUSIF_MAIN_BYTE=0x3ea2
+audio_GBUSIF_MAIN_WORD=0x3ea3
+audio_GBUSIF_MAIN_DWORD=0x3ea4
+audio_GBUSIF_MAIN_STATUS=0x3ea5
+audio_GBUSIF_ISR_WADD=0x3ea8
+audio_GBUSIF_ISR_RADD=0x3ea9
+audio_GBUSIF_ISR_BYTE=0x3eaa
+audio_GBUSIF_ISR_WORD=0x3eab
+audio_GBUSIF_ISR_DWORD=0x3eac
+audio_GBUSIF_ISR_STATUS=0x3ead
+audio_MISC_dr_mode=0x3e80
+audio_MISC_dr_length=0x3e81
+audio_MISC_dr_address=0x3e82
+audio_MISC_dw_mode=0x3e84
+audio_MISC_dw_length=0x3e85
+audio_MISC_dw_address=0x3e86
+audio_MISC_reset0=0x3e88
+audio_MISC_reset1=0x3e89
+audio_MISC_interrupt=0x3e8a
+audio_MISC_timer_div=0x3e8b
+audio_MISC_timer_count=0x3e8c
+audio_MISC_UNRESET_MASK=0xc300
+audio_MISC_RESET_MASK=0xc3c3
+audio_SP_init=0x1ffe
+I2C_MASTER_CONFIG=0x80
+I2C_MASTER_CLK_DIV=0x84
+I2C_MASTER_DEV_ADDR=0x88
+I2C_MASTER_ADDR=0x8c
+I2C_MASTER_DATA_OUT=0x90
+I2C_MASTER_DATA_IN=0x94
+I2C_MASTER_STATUS=0x98
+I2C_MASTER_STARTXFER=0x9c
+I2C_MASTER_BYTE_CNT=0xa0
+I2C_MASTER_INTEN=0xa4
+I2C_MASTER_INT=0xa8
+I2C_SLAVE_ADDR_REG=0xc0
+I2C_SLAVE_DATAOUT=0xc4
+I2C_SLAVE_DATAIN=0xc8
+I2C_SLAVE_STATUS=0xcc
+I2C_SLAVE_INTEN=0xd0
+I2C_SLAVE_INT=0xd4
+I2C_SLAVE_BUS_HOLD=0xd8
+VO_graph_acc_reset_bit=0xa
+VO_graph_acc_reset_mask=0x300000
+VO_graph_acc_reset_run=0x0
+VO_graph_acc_reset_path=0x100000
+VO_graph_acc_reset_time=0x200000
+VO_graph_acc_reset_conf=0x300000
+VO_graph_acc_X_format=0xa00
+VO_graph_acc_X_alpha=0xa04
+VO_graph_acc_X_keycolor=0xa08
+VO_graph_acc_Y_format=0xa0c
+VO_graph_acc_Y_keycolor=0xa10
+VO_graph_acc_control=0xa14
+VO_graph_acc_font=0xa18
+VO_graph_acc_fill=0xa18
+VO_graph_acc_control2=0xa1c
+VO_graph_acc_Z_format=0xa20
+VO_graph_acc_lut0=0xd000
+VO_graph_acc_FILL=0x0
+VO_graph_acc_BLEND=0x1
+VO_graph_acc_MOVE=0x2
+VO_graph_acc_REPLACE=0x3
+VO_graph_acc_RASTER=0x4
+VO_graph_acc_mode_control=0xa80
+VO_graph_acc_DRAM_read_address=0xa84
+VO_graph_acc_DRAM_write_address=0xa88
+VO_graph_acc_X_bounding_box=0xa8c
+VO_graph_acc_Y_bounding_box=0xa90
+VO_graph_acc_scaling_and_contours=0xa94
+VO_graph_acc_matrix_coeffs_scale=0xa98
+VO_graph_acc_matrix_coeffs_cross_scale=0xa9c
+VO_graph_acc_matrix_coeffs_offset=0xaa0
+VO_graph_acc_grd_color0=0xa40
+VO_graph_acc_grd_color1=0xa44
+VO_graph_acc_grd_scale_factor=0xa48
+VO_graph_acc_grd_vt_scale_init=0xa4c
+VO_graph_acc_grd_init_square_dist=0xa50
+VO_graph_acc_grd_ext_radius=0xa54
+VO_graph_acc_grd_int_radius=0xa58
+VO_graph_acc_grd_center=0xa5c
+VO_graph_acc_grd_control=0xa60
+VO_VP_conf=0x600
+VO_VP_size=0x604
+VO_HDSD_reset_bit=0xc
+VO_HDSD_read_reset_bit=0xd
+VO_HDSD_config=0x1300
+VO_HDSD_xscale=0x1304
+VO_HDSD_yscale=0x1308
+VO_HDSD_dump=0x130c
--- /dev/null	2011-06-03 14:51:38.633053002 +0200
+++ linux-2.6.20.14-fbx/include/linux/crash_zone.h	2011-09-26 15:07:56.388834171 +0200
@@ -0,0 +1,16 @@
+#ifndef CRASH_ZONE_H
+#define CRASH_ZONE_H
+
+#define CRASH_MAGIC	0xa7cecd6a
+
+struct crash_header
+{
+	unsigned int magic;
+	unsigned int len;
+	unsigned short checksum;
+	unsigned char data;
+};
+
+void __init crash_zone_set_param(unsigned char *zone, unsigned int size);
+
+#endif /* ! CRASH_ZONE_H */
--- /dev/null	2011-06-03 14:51:38.633053002 +0200
+++ linux-2.6.20.14-fbx/include/linux/fbxatm.h	2011-09-26 15:07:56.398834165 +0200
@@ -0,0 +1,156 @@
+/*
+ * Generic fbxatm definition, exported to userspace
+ */
+#ifndef LINUX_FBXATM_H_
+#define LINUX_FBXATM_H_
+
+#include <linux/types.h>
+#include <linux/if.h>
+
+#define FBXATM_IOCTL_MAGIC		0xd3
+
+/* allow userspace usage without up to date kernel headers */
+#ifndef PF_FBXATM
+#define PF_FBXATM			32
+#define AF_FBXATM			PF_FBXATM
+#endif
+
+struct fbxatm_vcc_id {
+	int				dev_idx;
+	__u32				vpi;
+	__u32				vci;
+};
+
+enum fbxatm_vcc_user {
+	FBXATM_VCC_USER_NONE = 0,
+	FBXATM_VCC_USER_2684,
+	FBXATM_VCC_USER_PPPOA,
+};
+
+enum fbxatm_vcc_traffic_class {
+	FBXATM_VCC_TC_UBR_NO_PCR = 0,
+	FBXATM_VCC_TC_UBR,
+};
+
+#define FBXATM_VCC_MAX_PRIO		7
+
+struct fbxatm_vcc_qos {
+	__u32				traffic_class;
+	__u32				max_sdu;
+	__u32				max_buffered_pkt;
+	__u32				priority;
+};
+
+
+/*
+ * VCC related
+ */
+struct fbxatm_vcc_params {
+	/* ADD/DEL/GET */
+	struct fbxatm_vcc_id		id;
+
+	/* ADD/GET */
+	struct fbxatm_vcc_qos		qos;
+
+	/* GET */
+	enum fbxatm_vcc_user		user;
+};
+
+#define FBXATM_IOCADD		_IOW(FBXATM_IOCTL_MAGIC,	1,	\
+					struct fbxatm_vcc_params)
+
+#define FBXATM_IOCDEL		_IOR(FBXATM_IOCTL_MAGIC,	2,	\
+					struct fbxatm_vcc_params)
+
+#define FBXATM_IOCGET		_IOWR(FBXATM_IOCTL_MAGIC,	3,	\
+					struct fbxatm_vcc_params)
+
+
+struct fbxatm_vcc_drop_params {
+	struct fbxatm_vcc_id		id;
+	unsigned int			drop_count;
+};
+
+#define FBXATM_IOCDROP		_IOWR(FBXATM_IOCTL_MAGIC,	5,	\
+					struct fbxatm_vcc_drop_params)
+
+/*
+ * OAM related
+ */
+enum fbxatm_oam_ping_type {
+	FBXATM_OAM_PING_SEG_F4	= 0,
+	FBXATM_OAM_PING_SEG_F5,
+	FBXATM_OAM_PING_E2E_F4,
+	FBXATM_OAM_PING_E2E_F5,
+};
+
+struct fbxatm_oam_ping_req {
+	/* only dev_idx for F4 */
+	struct fbxatm_vcc_id		id;
+
+	__u8				llid[16];
+	enum fbxatm_oam_ping_type	type;
+};
+
+#define FBXATM_IOCOAMPING	_IOWR(FBXATM_IOCTL_MAGIC,	10,	\
+				      struct fbxatm_oam_ping_req)
+
+
+/*
+ * PPPOA related
+ */
+enum fbxatm_pppoa_encap {
+	FBXATM_EPPPOA_AUTODETECT = 0,
+	FBXATM_EPPPOA_VCMUX,
+	FBXATM_EPPPOA_LLC,
+};
+
+struct fbxatm_pppoa_vcc_params {
+	struct fbxatm_vcc_id		id;
+	__u32				encap;
+	__u32				cur_encap;
+};
+
+#define FBXATM_PPPOA_IOCADD	_IOW(FBXATM_IOCTL_MAGIC,	20,	\
+					struct fbxatm_pppoa_vcc_params)
+
+#define FBXATM_PPPOA_IOCDEL	_IOW(FBXATM_IOCTL_MAGIC,	21,	\
+					struct fbxatm_pppoa_vcc_params)
+
+#define FBXATM_PPPOA_IOCGET	_IOWR(FBXATM_IOCTL_MAGIC,	22,	\
+					struct fbxatm_pppoa_vcc_params)
+
+
+
+/*
+ * 2684 related
+ */
+enum fbxatm_2684_encap {
+	FBXATM_E2684_VCMUX = 0,
+	FBXATM_E2684_LLC,
+};
+
+enum fbxatm_2684_payload {
+	FBXATM_P2684_BRIDGE = 0,
+	FBXATM_P2684_ROUTED,
+};
+
+struct fbxatm_2684_vcc_params {
+	struct fbxatm_vcc_id		id;
+
+	__u32				encap;
+	__u32				payload;
+	char				dev_name[IFNAMSIZ];
+};
+
+
+#define FBXATM_2684_IOCADD	_IOW(FBXATM_IOCTL_MAGIC,	30,	\
+					struct fbxatm_2684_vcc_params)
+
+#define FBXATM_2684_IOCDEL	_IOW(FBXATM_IOCTL_MAGIC,	31,	\
+					struct fbxatm_2684_vcc_params)
+
+#define FBXATM_2684_IOCGET	_IOWR(FBXATM_IOCTL_MAGIC,	32,	\
+					struct fbxatm_2684_vcc_params)
+
+#endif /* LINUX_FBXATM_H_ */
--- /dev/null	2011-06-03 14:51:38.633053002 +0200
+++ linux-2.6.20.14-fbx/include/linux/fbxdmamux.h	2011-09-26 15:07:56.398834165 +0200
@@ -0,0 +1,51 @@
+
+#ifndef FBXDMAMUX_H_
+#define FBXDMAMUX_H_
+
+#include <linux/list.h>
+
+/* wether to increment or not the src/dst address while
+ * transferring */
+#define FBXDMAMUX_FLAG_SRC_NO_INCR	(1 << 0)
+#define FBXDMAMUX_FLAG_DST_NO_INCR	(1 << 1)
+
+/* wether to src/dst address are already hw */
+#define FBXDMAMUX_FLAG_SRC_HW		(1 << 2)
+#define FBXDMAMUX_FLAG_DST_HW		(1 << 3)
+
+#define FBXDMAMUX_MAX_PRIO		CONFIG_FREEBOX_DMAMUX_MAX_PRIO
+
+struct fbxdmamux_req
+{
+	/* request with same channel cookie are guaranted to be served
+	 * in order */
+	unsigned char	chan_cookie;
+	/* 0 > fast > medium > slow > 4 */
+	unsigned char	priority;
+	unsigned char	flags;
+
+	void		*virt_src;
+	void		*virt_dst;
+	dma_addr_t	hw_src;
+	dma_addr_t	hw_dst;
+	unsigned int	len;
+
+	void		(*callback)(void *cb_data, int error);
+	void		*cb_data;
+
+	/* fields below are opaque to caller */
+	struct list_head list;
+};
+
+struct fbxdmamux_req *fbxdmamux_req_from_pool(void);
+
+int fbxdmamux_alloc_channel_cookie(void);
+
+int fbxdmamux_submit(struct fbxdmamux_req *req);
+
+int fbxdmamux_submit_and_sleep(struct fbxdmamux_req *req,
+			       unsigned int timeout);
+
+void fbxdmamux_flush_channel(unsigned int cookie);
+
+#endif /* !FBXDMAMUX_H_ */
--- /dev/null	2011-06-03 14:51:38.633053002 +0200
+++ linux-2.6.20.14-fbx/include/linux/fbxgpio_core.h	2011-09-26 15:07:56.398834165 +0200
@@ -0,0 +1,45 @@
+/*
+ * fbxgpio.h for linux-freebox
+ * Created by <nschichan@freebox.fr> on Wed Feb 21 22:09:46 2007
+ * Freebox SA
+ */
+
+#ifndef FBXGPIO_H
+# define FBXGPIO_H
+
+# include <linux/types.h>
+
+/* can change pin direction */
+#define FBXGPIO_PIN_DIR_RW	(1 << 0)
+#define FBXGPIO_PIN_REVERSE_POL	(1 << 1)
+
+struct fbxgpio_operations
+{
+	int  (*get_datain)(int gpio);
+	void (*set_dataout)(int gpio, int val);
+	int  (*get_dataout)(int gpio);
+	void (*set_direction)(int gpio, int dir);
+	int  (*get_direction)(int gpio);
+};
+
+
+struct fbxgpio_pin
+{
+	const char	*pin_name;
+	uint32_t	flags;
+	int		direction;
+	int		pin_num;
+	struct fbxgpio_operations	*ops;
+
+	struct class_device *class_dev;
+	unsigned int	cur_dataout;
+};
+
+
+#define GPIO_DIR_IN	0x1
+#define GPIO_DIR_OUT	0x0
+
+int fbxgpio_register_pin(struct fbxgpio_pin *pin);
+void fbxgpio_unregister_pin(struct fbxgpio_pin *pin);
+
+#endif /* !FBXGPIO_H */
--- /dev/null	2011-06-03 14:51:38.633053002 +0200
+++ linux-2.6.20.14-fbx/include/linux/fbxmtd.h	2011-09-26 15:07:56.398834165 +0200
@@ -0,0 +1,211 @@
+
+#ifndef FBXMTD_H_
+# define FBXMTD_H_
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/sched.h>
+#endif
+
+#define FBXMTD_MAX_DEVICES	2
+
+/* hide all hot stuff from userland */
+#ifdef __KERNEL__
+
+struct fbxmtd_dev;
+
+/*
+ * fbxmtd partition
+ */
+struct fbxmtd_part
+{
+	char			*name;
+	uint32_t		offset;
+	uint32_t		size;
+	int			idx;
+	int			rw;
+
+	struct fbxmtd_dev	*dev;
+};
+
+/*
+ * fbxmtd flash sector information
+ */
+struct fbxmtd_region
+{
+	uint32_t		offset;
+	uint32_t		size;
+	uint32_t		count;
+};
+
+/*
+ * fbxmtd device mapping
+ */
+struct fbxmtd_dev_map
+{
+	/* base physical address of mtd device */
+	dma_addr_t		base_phys;
+
+	/* flash bus width (1: 8bits, 2: 16buts, 4: 32bits) */
+	unsigned int		flash_width;
+
+	/* remapped address */
+	uint8_t			*base;
+};
+
+/*
+ * fbxmtd device
+ */
+#define FBXMTD_MAX_PART		16
+
+struct fbxmtd_dev
+{
+	char			*name;
+	struct semaphore	sem;
+	int			dead;
+	atomic_t		refcount;
+	int			idx;
+
+	struct fbxmtd_dev_map	map;
+
+	struct fbxmtd_part	parts[FBXMTD_MAX_PART];
+	unsigned int		part_count;
+
+
+	/* the following callback are set by chip backend */
+	int			(*erase)(struct fbxmtd_dev *dev,
+					 uint32_t offset);
+
+	int			(*chip_erase)(struct fbxmtd_dev *dev);
+
+	int			(*program)(struct fbxmtd_dev *dev,
+					   uint32_t offset, const uint8_t *buf,
+					   size_t count);
+
+	struct fbxmtd_region	*(*get_region_info)(struct fbxmtd_dev *dev);
+
+	uint32_t		(*get_size)(struct fbxmtd_dev *dev);
+
+	void			*priv_data;
+};
+
+/*
+ * notifier for partition add/dead
+ */
+#define FBXMTD_EVENT_ADD	(1 << 0)
+#define FBXMTD_EVENT_DEAD	(1 << 1)
+
+int fbxmtd_register_notifier(void (*cb)(void *, struct fbxmtd_part *,
+					uint32_t),
+			     void *cb_data, uint32_t mask);
+
+void fbxmtd_unregister_notifier(void (*cb)(void *, struct fbxmtd_part *,
+					   uint32_t));
+
+
+/*
+ * core functions
+ */
+struct fbxmtd_part *fbxmtd_get_part(unsigned int dev_idx,
+				    unsigned int part_idx);
+
+struct fbxmtd_part *fbxmtd_get_part_by_name(unsigned int dev_idx,
+					    const char *part_name);
+
+void fbxmtd_put_part(struct fbxmtd_part *part);
+
+void fbxmtd_put_device(struct fbxmtd_dev *dev);
+
+int fbxmtd_read_part(struct fbxmtd_part *part, uint32_t offset, char *buffer,
+		     unsigned int count, int can_sleep);
+
+int fbxmtd_read_dev(struct fbxmtd_dev *dev, uint32_t offset, char *buffer,
+		    unsigned int count);
+
+int fbxmtd_find_sector_boundary(struct fbxmtd_dev *dev,
+				uint32_t offset, uint32_t *boundary);
+
+int fbxmtd_find_next_sector_boundary(struct fbxmtd_dev *dev,
+				     uint32_t offset, uint32_t *boundary);
+
+int fbxmtd_write_part(struct fbxmtd_part *part, uint32_t offset, char *buffer,
+		      unsigned int count);
+
+int fbxmtd_set_partitions(struct fbxmtd_dev *dev, struct fbxmtd_part *parts,
+			  unsigned int count);
+
+struct fbxmtd_dev *fbxmtd_probe(const char *name, dma_addr_t base,
+				unsigned int flash_width);
+
+void fbxmtd_mark_dead_dev(struct fbxmtd_dev *dev);
+
+int fbxmtd_foreach_part(int (cb)(void *, struct fbxmtd_part *),
+			void *cb_data);
+
+int fbxmtd_foreach_dev(int (cb)(void *, struct fbxmtd_dev *),
+		       void *cb_data);
+
+/*
+ * generic map driver data
+ */
+struct fbxmtd_platform_data
+{
+	const char *			name;
+	int				status;
+	dma_addr_t			base;
+	uint32_t			width;
+	uint32_t			size; /* filled by map driver */
+	struct fbxmtd_platform_part	*parts;
+	uint32_t			num_parts;
+	struct fbxmtd_dev		*core_dev;
+};
+
+struct fbxmtd_platform_part
+{
+	char		*name;
+	char		*align_part;
+	uint32_t	offset;
+	uint32_t	roffset;
+	uint32_t	size;
+	uint32_t	flags;
+};
+
+/*
+ * bcm963xx map driver data
+ */
+struct fbxmtd_bcm963xx_platform_data {
+	char				*name;
+	dma_addr_t			base;
+	unsigned int			width;
+	unsigned int			psi_size;
+	u8				*boot_addr;
+	int				all_rw;
+};
+
+#endif /* __KERNEL__ */
+
+enum {
+	E_FBXMTD_NOT_PROBED,
+	E_FBXMTD_PROBED,
+	E_FBXMTD_FAULTY,
+};
+
+/* try to read image tag and set the _fs related partition */
+#define FBXMTD_PART_HAS_FS	(1 << 0)
+/* Read/Write partition */
+#define FBXMTD_PART_RW		(1 << 1)
+/* do not check CRC of image tag. */
+#define FBXMTD_PART_NOCRC	(1 << 2)
+/*
+ * only for first partition: means that the size of the partition is
+ * the size of the flash
+ */
+#define FBXMTD_PART_MAP_ALL	(1 << 3)
+/* Adjust size automatically with the next partition */
+#define FBXMTD_PART_AUTOSIZE	(1 << 4)
+#define FBXMTD_PART_IGNORE_TAG	(1 << 5)
+#define FBXMTD_PART_SKIP_KERNEL	(1 << 6)
+
+
+#endif /* !FBXMTD_H_ */
--- /dev/null	2011-06-03 14:51:38.633053002 +0200
+++ linux-2.6.20.14-fbx/include/linux/fbxmtd_map_ioctl.h	2011-09-26 15:07:56.398834165 +0200
@@ -0,0 +1,52 @@
+/*
+ * fbxmtd_map_ioctl.h for linux-freebox
+ * Created by <nschichan@freebox.fr> on Thu Feb  8 20:37:28 2007
+ * Freebox SA
+ */
+
+#ifndef FBXMTD_MAP_IOCTL_H
+# define FBXMTD_MAP_IOCTL_H
+
+/*
+ * IOCTL interface
+ */
+#define FBXMTD_MINOR	242
+
+#define FBXMTD_MAP_IOCTL_MAX_DEV	2
+#define FBXMTD_MAP_IOCTL_MAX_PART	16
+
+struct fbxmtd_map_ioctl_part
+{
+	char		name[32];
+	uint32_t	offset;
+	uint32_t	size;
+	uint32_t	flags;
+};
+
+struct fbxmtd_map_ioctl_dev
+{
+	char				name[32];
+	uint32_t			base_phys;
+	int				bus_width;
+	uint32_t			size;
+	uint32_t			status;
+	struct fbxmtd_map_ioctl_part	parts[FBXMTD_MAP_IOCTL_MAX_PART];
+	int				num_parts;
+};
+
+#define FBXMTD_MAP_IOCTL_NR	0x42
+
+struct fbxmtd_map_ioctl_query
+{
+	uint32_t	cmd;
+	uint32_t	param;
+	int		result;
+	void __user	*user_buf;
+	uint32_t	user_buf_size;
+};
+
+#define FBXMTDCTL_CMD_GET_DEVICES	0x1
+#define FBXMTDCTL_CMD_ADD_DEVICE	0x2
+#define FBXMTDCTL_CMD_DEL_DEVICE	0x3
+
+#endif /* !FBXMTD_MAP_IOCTL_H */
--- /dev/null	2011-06-03 14:51:38.633053002 +0200
+++ linux-2.6.20.14-fbx/include/linux/fbxpanel.h	2011-09-26 15:07:56.398834165 +0200
@@ -0,0 +1,97 @@
+/*
+ * fbxpanel.h for linux-freebox
+ * Created by <nschichan@freebox.fr> on Wed Mar  7 22:07:50 2007
+ * Freebox SA
+ */
+
+#ifndef __FBXPANEL_H
+# define __FBXPANEL_H
+
+enum {
+	E_PANEL_METHOD_SPI,
+	E_PANEL_METHOD_I2C,
+};
+
+enum {
+	E_DIGIT_STATE_OFF,
+	E_DIGIT_STATE_ON,
+	E_DIGIT_STATE_BLINK,
+};
+
+/*
+ * panel digit layout:
+ *
+ * +---+    +---+
+ * |\|/|    |   |
+ * +-+-+ or +---+
+ * |/|\|    |   |
+ * +---+    +---+
+ *
+ * allow 7/14 seg display description.
+ *
+ * in 7 segment mode, d_* should be set to 0. h_middle_left and
+ * h_middle_right should be set to the same value.
+ */
+struct digit_seg_desc
+{
+	int h_top;
+	int h_middle_left;
+	int h_middle_right;
+	int h_bottom;
+
+	int v_top_left;
+	int v_top_middle;
+	int v_top_right;
+
+	int v_bottom_left;
+	int v_bottom_middle;
+	int v_bottom_right;
+
+	int d_bottom_right;
+	int d_bottom_left;
+	int d_top_right;
+	int d_top_left;
+};
+
+struct fbxpanel_pic_fbx_platform_data
+{
+	const char *name;
+	uint32_t i2c_addr;
+};
+
+struct fbxpanel
+{
+	const char *name;
+	int digit_count;
+	const uint16_t *ascii_table;
+
+	int (*set_digit)(struct fbxpanel *p, int digit, uint16_t val);
+	int (*set_colon_digit)(struct fbxpanel *p, int enable, int blink_msec);
+
+	void *priv;
+	struct class_device *class_dev;
+
+	struct digit_seg_desc *digit_seg_desc;
+
+	/* lock between animator and process storing data to sysfs */
+	struct semaphore mutex;
+
+	/* animator thread stuff */
+	struct task_struct *animator;
+	wait_queue_head_t animator_wq;
+
+	int current_anim;
+	int anim_count;
+	int last_anim;
+	int current_frame;
+
+	uint16_t *digit_cache;
+
+	/* device specific animation frames */
+	struct dev_anim_frame	**frames;
+};
+
+int fbxpanel_register(struct fbxpanel *p);
+int fbxpanel_unregister(struct fbxpanel *p);
+
+#endif /* !__FBXPANEL_H */
--- /dev/null	2011-06-03 14:51:38.633053002 +0200
+++ linux-2.6.20.14-fbx/include/linux/fbxserial.h	2011-09-26 15:07:56.398834165 +0200
@@ -0,0 +1,113 @@
+
+#ifndef FBXSERIAL_H_
+# define FBXSERIAL_H_
+
+/*
+ * some part of serial may vary, we use abstract struct to store this,
+ * data content depends on type.
+ */
+#define EXTINFO_SIZE		128
+#define EXTINFO_MAX_COUNT	16
+
+/*
+ * extdev desc
+ */
+#define EXTINFO_TYPE_EXTDEV	1
+
+#define EXTDEV_TYPE_BUNDLE	1
+#define EXTDEV_TYPE_MAX		2
+
+struct fbx_serial_extinfo
+{
+	uint32_t			type;
+
+	union {
+		/* extdev */
+		struct {
+			uint32_t	type;
+			uint32_t	model;
+			char		serial[64];
+		} extdev;
+
+		/* raw access */
+		unsigned char		data[EXTINFO_SIZE];
+	} u;
+}  __attribute__ ((packed));;
+
+
+/*
+ * master serial structure
+ */
+
+#define FBXSERIAL_VERSION	1
+
+#define FBXSERIAL_MAGIC		0x2d9521ab
+
+#define MAC_ADDR_SIZE		6
+#define RANDOM_DATA_SIZE	32
+
+/*
+ * this  is the  maximum size  we accept  to check  crc32  against, so
+ * structure may no grow larger than this
+ */
+#define FBXSERIAL_MAX_SIZE	8192
+
+struct fbx_serial
+{
+	uint32_t crc32;
+	uint32_t magic;
+	uint32_t struct_version;
+	uint32_t len;
+
+	/* board serial */
+        uint16_t type;
+        uint8_t version;
+        uint8_t manufacturer;
+        uint16_t year;
+        uint8_t week;
+        uint32_t number;
+        uint32_t flags;
+
+	/* mac address base */
+	uint8_t mac_addr_base[MAC_ADDR_SIZE];
+
+	/* mac address count */
+	uint8_t mac_count;
+
+	/* random data */
+	uint8_t random_data[RANDOM_DATA_SIZE];
+
+	/* last update of data (seconds since epoch) */
+	uint32_t last_modified;
+
+	/* count of following extinfo tag */
+	uint32_t extinfo_count;
+
+	/* beginning of extended info */
+	struct fbx_serial_extinfo	extinfos[EXTINFO_MAX_COUNT];
+
+} __attribute__ ((packed));
+
+
+/*
+ * default value to use in case magic is wrong (no cksum in that case)
+ */
+#define DEFAULT_SERIAL_INFO		\
+	{ 0, FBXSERIAL_MAGIC,		\
+	FBXSERIAL_VERSION,		\
+	sizeof (struct fbx_serial),	\
+	0, 0, '_', 0, 0, 0, 0,		\
+	"\x00\x07\xCB\x00\x00\xFD",	\
+	1,				\
+	{ 0 },				\
+	0, 0 }
+
+static inline void
+fbxserial_set_default(struct fbx_serial *serial)
+{
+        static const struct fbx_serial    def = DEFAULT_SERIAL_INFO;
+
+        memcpy(serial, &def, sizeof (def));
+}
+
+#endif /* FBXSERIAL_H_ */
--- /dev/null	2011-06-03 14:51:38.633053002 +0200
+++ linux-2.6.20.14-fbx/include/linux/fbxserialinfo.h	2011-09-26 15:07:56.398834165 +0200
@@ -0,0 +1,24 @@
+
+#ifndef FBXSERIALINFO_H_
+# define FBXSERIALINFO_H_
+
+struct fbx_serial;
+
+void
+fbxserialinfo_get_random(unsigned char *data, unsigned int len);
+
+void
+fbxserialinfo_get_mac_addr(unsigned char *data);
+
+int
+fbxserialinfo_read(void *data, struct fbx_serial *out);
+
+struct fbx_serial *fbxserialinfo_get(void);
+
+/*
+ * implemented in board specific code: we do not want static variables
+ * in the builtin fbxserial code.
+ */
+const struct fbx_serial *arch_get_serial(void);
+
+#endif /* FBXSERIALINFO_H_ */
--- /dev/null	2011-06-03 14:51:38.633053002 +0200
+++ linux-2.6.20.14-fbx/include/linux/fbxwatchdog.h	2011-09-26 15:07:56.398834165 +0200
@@ -0,0 +1,54 @@
+/*
+ * fbxwatchdog.h for fbxwatchdog
+ * Created by <nschichan@freebox.fr> on Mon Jun 11 20:48:54 2007
+ * Freebox SA
+ */
+
+#ifndef FBXWATCHDOG_H
+# define FBXWATCHDOG_H
+
+struct fbxwatchdog
+{
+	const char *name;
+	void *priv;
+
+	int enabled;
+	int countdown;
+	int countdown_min;
+
+	int (*wdt_init)(struct fbxwatchdog *wdt);
+	int (*wdt_cleanup)(struct fbxwatchdog *wdt);
+
+	/*
+	 * wdt_start and wdt_stop are called with wdt->lock held and irq
+	 * disabled.
+	 */
+	int (*wdt_start)(struct fbxwatchdog *wdt);
+	int (*wdt_stop)(struct fbxwatchdog *wdt);
+
+	/*
+	 * cb is called from interrupt/softirq context (depends on the
+	 * underlying driver/hardware).
+	 */
+	void (*cb)(struct fbxwatchdog *wdt);
+
+	struct timer_list timer;
+
+	struct class_device *class_dev;
+
+	/*
+	 * protect interrupt handlers & start/stop methods running in
+	 * thead context.
+	 */
+	spinlock_t	lock;
+};
+
+int fbxwatchdog_register(struct fbxwatchdog *wdt);
+int fbxwatchdog_unregister(struct fbxwatchdog *wdt);
+
+#ifdef CONFIG_FREEBOX_WATCHDOG_CHAR
+int fbxwatchdog_char_add(struct fbxwatchdog *wdt);
+void fbxwatchdog_char_remove(struct fbxwatchdog *wdt);
+#endif
+
+#endif /* !FBXWATCHDOG_H */
--- /dev/null	2011-06-03 14:51:38.633053002 +0200
+++ linux-2.6.20.14-fbx/include/linux/i2c-gpio.h	2011-09-26 15:07:56.408834159 +0200
@@ -0,0 +1,24 @@
+/*
+ * i2c-gpio.h for linux-freebox
+ * Created by <nschichan@freebox.fr> on Tue Mar  6 20:26:31 2007
+ * Freebox SA
+ */
+
+#ifndef __I2C_GPIO_H
+# define __I2C_GPIO_H
+
+struct i2c_gpio_platform_data
+{
+	int gpio_scl;
+	int gpio_sda;
+
+	/*
+	 * the bare minimum until we merge the generic GPIO layer in
+	 * the kernel
+	 */
+	void (*gpio_set_dataout)(int gpio, int val);
+	int  (*gpio_get_dataout)(int gpio);
+	void (*gpio_set_direction)(int gpio, int dir);
+};
+
+#endif /* !__I2C_GPIO_H */
--- /dev/null	2011-06-03 14:51:38.633053002 +0200
+++ linux-2.6.20.14-fbx/include/linux/LzmaDecode.h	2011-09-26 15:07:56.378834177 +0200
@@ -0,0 +1,113 @@
+/* 
+  LzmaDecode.h
+  LZMA Decoder interface
+
+  LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01)
+  http://www.7-zip.org/
+
+  LZMA SDK is licensed under two licenses:
+  1) GNU Lesser General Public License (GNU LGPL)
+  2) Common Public License (CPL)
+  It means that you can select one of these two licenses and 
+  follow rules of that license.
+
+  SPECIAL EXCEPTION:
+  Igor Pavlov, as the author of this code, expressly permits you to 
+  statically or dynamically link your code (or bind by name) to the 
+  interfaces of this file without subjecting your linked code to the 
+  terms of the CPL or GNU LGPL. Any modifications or additions 
+  to this file, however, are subject to the LGPL or CPL terms.
+*/
+
+#ifndef __LZMADECODE_H
+#define __LZMADECODE_H
+
+#include "LzmaTypes.h"
+
+/* #define _LZMA_IN_CB */
+/* Use callback for input data */
+
+/* #define _LZMA_OUT_READ */
+/* Use read function for output data */
+
+/* #define _LZMA_PROB32 */
+/* It can increase speed on some 32-bit CPUs, 
+   but memory usage will be doubled in that case */
+
+/* #define _LZMA_LOC_OPT */
+/* Enable local speed optimizations inside code */
+
+#ifdef _LZMA_PROB32
+#define CProb UInt32
+#else
+#define CProb UInt16
+#endif
+
+#define LZMA_RESULT_OK 0
+#define LZMA_RESULT_DATA_ERROR 1
+
+#ifdef _LZMA_IN_CB
+typedef struct _ILzmaInCallback
+{
+  int (*Read)(void *object, const unsigned char **buffer, SizeT *bufferSize);
+} ILzmaInCallback;
+#endif
+
+#define LZMA_BASE_SIZE 1846
+#define LZMA_LIT_SIZE 768
+
+#define LZMA_PROPERTIES_SIZE 5
+
+typedef struct _CLzmaProperties
+{
+  int lc;
+  int lp;
+  int pb;
+  #ifdef _LZMA_OUT_READ
+  UInt32 DictionarySize;
+  #endif
+}CLzmaProperties;
+
+int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size);
+
+#define LzmaGetNumProbs(Properties) (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((Properties)->lc + (Properties)->lp)))
+
+#define kLzmaNeedInitId (-2)
+
+typedef struct _CLzmaDecoderState
+{
+  CLzmaProperties Properties;
+  CProb *Probs;
+
+  #ifdef _LZMA_IN_CB
+  const unsigned char *Buffer;
+  const unsigned char *BufferLim;
+  #endif
+
+  #ifdef _LZMA_OUT_READ
+  unsigned char *Dictionary;
+  UInt32 Range;
+  UInt32 Code;
+  UInt32 DictionaryPos;
+  UInt32 GlobalPos;
+  UInt32 DistanceLimit;
+  UInt32 Reps[4];
+  int State;
+  int RemainLen;
+  unsigned char TempDictionary[4];
+  #endif
+} CLzmaDecoderState;
+
+#ifdef _LZMA_OUT_READ
+#define LzmaDecoderInit(vs) { (vs)->RemainLen = kLzmaNeedInitId; }
+#endif
+
+int LzmaDecode(CLzmaDecoderState *vs,
+    #ifdef _LZMA_IN_CB
+    ILzmaInCallback *inCallback,
+    #else
+    const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed,
+    #endif
+    unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed);
+
+#endif
--- /dev/null	2011-06-03 14:51:38.633053002 +0200
+++ linux-2.6.20.14-fbx/include/linux/LzmaTypes.h	2011-09-26 15:07:56.378834177 +0200
@@ -0,0 +1,45 @@
+/* 
+LzmaTypes.h 
+
+Types for LZMA Decoder
+
+This file written and distributed to public domain by Igor Pavlov.
+This file is part of LZMA SDK 4.40 (2006-05-01)
+*/
+
+#ifndef __LZMATYPES_H
+#define __LZMATYPES_H
+
+#ifndef _7ZIP_BYTE_DEFINED
+#define _7ZIP_BYTE_DEFINED
+typedef unsigned char Byte;
+#endif 
+
+#ifndef _7ZIP_UINT16_DEFINED
+#define _7ZIP_UINT16_DEFINED
+typedef unsigned short UInt16;
+#endif 
+
+#ifndef _7ZIP_UINT32_DEFINED
+#define _7ZIP_UINT32_DEFINED
+#ifdef _LZMA_UINT32_IS_ULONG
+typedef unsigned long UInt32;
+#else
+typedef unsigned int UInt32;
+#endif
+#endif 
+
+/* #define _LZMA_SYSTEM_SIZE_T */
+/* Use system's size_t. You can use it to enable 64-bit sizes supporting */
+
+#ifndef _7ZIP_SIZET_DEFINED
+#define _7ZIP_SIZET_DEFINED
+#ifdef _LZMA_SYSTEM_SIZE_T
+#include <stddef.h>
+typedef size_t SizeT;
+#else
+typedef UInt32 SizeT;
+#endif
+#endif
+
+#endif
--- /dev/null	2011-06-03 14:51:38.633053002 +0200
+++ linux-2.6.20.14-fbx/include/linux/netfilter_ipv4/iptable_tproxy.h	2011-09-26 15:07:56.428834147 +0200
@@ -0,0 +1,66 @@
+#ifndef _IPTABLE_TPROXY_H
+#define _IPTABLE_TPROXY_H
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/time.h>
+#include <asm/atomic.h>
+#include <net/sock.h>
+
+struct ip_tproxy_sockref;
+
+struct ip_tproxy_hash
+{
+	struct list_head list;
+	struct ip_tproxy_sockref *sockref;
+};
+
+struct ip_tproxy_sockref
+{
+	int flags;
+	atomic_t references;
+
+	u8 proto;
+
+	/* foreign address associated with a local socket */
+	u32 faddr;
+	u16 fport;
+
+	/* local socket address */
+	u32 laddr;
+	u16 lport;
+
+	/* remote addresses, needed for datagram protocols when the peer
+	 * sends the packet triggering the NAT translation. (as there might
+	 * be multiple sockrefs on the same foreign address).
+	 */
+	u32 raddr;
+	u16 rport;
+
+	/* hash chains indexed by local and foreign addresses */
+	struct ip_tproxy_hash bylocal, byforeign;
+
+	/* lock protecting access to related list */
+	spinlock_t relatedlock;
+	/* number of related connections */
+	atomic_t related;
+	/* list of related connections */
+	struct list_head relatedct;
+
+	/* socket which we were assigned to */
+	struct sock *assigned_to;
+
+	/* How many sockets use this sockref? Used for mark-only sockrefs,
+	 * which can be shared between multiple sockets bound to the same local
+	 * address */
+	atomic_t socket_count;
+
+	/* when was this entry inserted in hash */
+	struct timespec tv_hashed;
+};
+
+extern int
+ip_tproxy_setup_nat(struct sk_buff **pskb, int hooknum,
+		    struct ip_tproxy_sockref *sr, unsigned int flags);
+
+#endif
--- /dev/null	2011-06-03 14:51:38.633053002 +0200
+++ linux-2.6.20.14-fbx/include/linux/netfilter_ipv4/ip_tproxy.h	2011-09-26 15:07:56.428834147 +0200
@@ -0,0 +1,78 @@
+/*
+ * Transparent proxy support for Linux/iptables
+ *
+ * Copyright (c) 2002-2004 BalaBit IT Ltd.
+ * Author: Balázs Scheidler
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef _IP_TPROXY_H
+#define _IP_TPROXY_H
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#include <linux/in.h>
+#else
+#include <netinet/in.h>
+#ifndef IP_RECVORIGADDRS
+#define IP_RECVORIGADDRS	11273
+#define IP_ORIGADDRS	IP_RECVORIGADDRS
+struct in_origaddrs {
+        struct in_addr ioa_srcaddr;
+        struct in_addr ioa_dstaddr;
+        unsigned short int ioa_srcport;
+        unsigned short int ioa_dstport;
+};
+#endif
+#endif
+
+/*
+ * used in setsockopt(SOL_IP, IP_TPROXY) should not collide
+ * with values in <linux/in.h>
+ */
+
+#define IP_TPROXY	11274
+
+/* tproxy operations */
+enum {
+	TPROXY_VERSION = 0,
+	TPROXY_ASSIGN,
+	TPROXY_UNASSIGN,
+	TPROXY_QUERY,
+	TPROXY_FLAGS,
+	TPROXY_ALLOC,
+	TPROXY_CONNECT
+};
+
+/* bitfields in IP_TPROXY_FLAGS */
+#define ITP_CONNECT     0x00000001
+#define ITP_LISTEN      0x00000002
+#define ITP_ESTABLISHED 0x00000004
+
+#define ITP_ONCE        0x00010000
+#define ITP_MARK        0x00020000
+#define ITP_APPLIED     0x00040000
+#define ITP_UNIDIR      0x00080000
+
+struct in_tproxy_addr{
+	struct in_addr	faddr;
+	u_int16_t	fport;
+};
+
+struct in_tproxy {
+	/* fixed part, should not change between versions */
+	u_int32_t op;
+	/* extensible part */
+	union _in_args {
+		u_int32_t		version;
+		struct in_tproxy_addr	addr;
+		u_int32_t		flags;
+	} v;
+};
+
+#endif
+
--- /dev/null	2011-06-03 14:51:38.633053002 +0200
+++ linux-2.6.20.14-fbx/include/linux/netfilter_ipv4/ipt_TPROXY.h	2011-09-26 15:07:56.428834147 +0200
@@ -0,0 +1,24 @@
+/*
+ * Transparent proxy support for Linux/iptables
+ *
+ * Copyright (c) 2002-2004 BalaBit IT Ltd.
+ * Author: Balázs Scheidler
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef _IPT_TPROXY_H_target
+#define _IPT_TPROXY_H_target
+
+struct ipt_tproxy_target_info {
+	u_int32_t mark_mask;
+	u_int32_t mark_value;
+	u_int32_t laddr;
+	u_int16_t lport;
+};
+
+#endif /*_IPT_TPROXY_H_target*/
+
--- /dev/null	2011-06-03 14:51:38.633053002 +0200
+++ linux-2.6.20.14-fbx/include/linux/sqlzma.h	2011-09-26 15:07:56.458834129 +0200
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2006 Junjiro Okajima
+ * Copyright (C) 2006 Tomas Matejicek, slax.org
+ *
+ * LICENSE follows the described one in lzma.
+ */
+
+/* $Id: sqlzma.h,v 1.13 2007/01/07 15:12:48 jro Exp $ */
+
+#ifndef __sqlzma_h__
+#define __sqlzma_h__
+
+#ifndef __KERNEL__
+#include <stdlib.h>
+#include <string.h>
+#include <zlib.h>
+#ifdef _REENTRANT
+#include <pthread.h>
+#endif
+#else
+#include <linux/zlib.h>
+#endif
+#define _7ZIP_BYTE_DEFINED
+
+/*
+ * detect the compression method automatically by the first byte of compressed
+ * data.
+ * according to rfc1950, the first byte of zlib compression must be 0x?8.
+ */
+#define is_lzma(c)	(c == 0x5d)
+
+/* ---------------------------------------------------------------------- */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef __KERNEL__
+/* for mksquashfs only */
+int sqlzma_cm(int lzma, z_stream *stream, Bytef *next_in, uInt avail_in,
+	      Bytef *next_out, uInt avail_out);
+#endif
+
+/* ---------------------------------------------------------------------- */
+/*
+ * Three patterns for sqlzma uncompression. very dirty code.
+ * - kernel space (squashfs kernel module)
+ * - user space with pthread (mksquashfs)
+ * - user space without pthread (unsquashfs)
+ */
+
+struct sized_buf {
+	unsigned int	sz;
+	unsigned char	*buf;
+};
+
+enum {SQUN_PROB, SQUN_RESULT, SQUN_LAST};
+struct sqlzma_un {
+	int			un_lzma;
+	struct sized_buf	un_a[SQUN_LAST];
+	unsigned char		un_prob[31960]; /* unlzma 64KB */
+	z_stream		un_stream;
+#define un_cmbuf	un_stream.next_in
+#define un_cmlen	un_stream.avail_in
+#define un_resbuf	un_stream.next_out
+#define un_resroom	un_stream.avail_out
+#define un_reslen	un_stream.total_out
+};
+
+int sqlzma_init(struct sqlzma_un *un, int do_lzma, unsigned int res_sz);
+int sqlzma_un(struct sqlzma_un *un, struct sized_buf *src, struct sized_buf *dst);
+void sqlzma_fin(struct sqlzma_un *un);
+
+/* ---------------------------------------------------------------------- */
+
+#ifdef __cplusplus
+};
+#endif
+#endif
--- /dev/null	2011-06-03 14:51:38.633053002 +0200
+++ linux-2.6.20.14-fbx/include/linux/sqmagic.h	2011-09-26 15:07:56.458834129 +0200
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2006 Junjiro Okajima
+ * Copyright (C) 2006 Tomas Matejicek, slax.org
+ *
+ * LICENSE must follow the one in squashfs.
+ */
+
+/* $Id: sqmagic.h,v 1.2 2006/11/27 03:54:58 jro Exp $ */
+
+#ifndef __sqmagic_h__
+#define __sqmagic_h__
+
+/* see SQUASHFS_MAGIC in squashfs_fs.h */
+#define SQUASHFS_MAGIC_LZMA		0x71736873
+#define SQUASHFS_MAGIC_LZMA_SWAP	0x73687371
+
+#endif
--- /dev/null	2011-06-03 14:51:38.633053002 +0200
+++ linux-2.6.20.14-fbx/include/linux/squashfs_fs.h	2011-09-26 15:07:56.458834129 +0200
@@ -0,0 +1,934 @@
+#ifndef SQUASHFS_FS
+#define SQUASHFS_FS
+
+/*
+ * Squashfs
+ *
+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007
+ * Phillip Lougher <phillip@lougher.org.uk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2,
+ * or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * squashfs_fs.h
+ */
+
+#ifndef CONFIG_SQUASHFS_2_0_COMPATIBILITY
+#define CONFIG_SQUASHFS_2_0_COMPATIBILITY
+#endif
+
+#ifdef	CONFIG_SQUASHFS_VMALLOC
+#define SQUASHFS_ALLOC(a)		vmalloc(a)
+#define SQUASHFS_FREE(a)		vfree(a)
+#else
+#define SQUASHFS_ALLOC(a)		kmalloc(a, GFP_KERNEL)
+#define SQUASHFS_FREE(a)		kfree(a)
+#endif
+#define SQUASHFS_CACHED_FRAGMENTS	CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE	
+#define SQUASHFS_MAJOR			3
+#define SQUASHFS_MINOR			0
+#define SQUASHFS_MAGIC			0x73717368
+#define SQUASHFS_MAGIC_SWAP		0x68737173
+#define SQUASHFS_START			0
+
+/* size of metadata (inode and directory) blocks */
+#define SQUASHFS_METADATA_SIZE		8192
+#define SQUASHFS_METADATA_LOG		13
+
+/* default size of data blocks */
+#define SQUASHFS_FILE_SIZE		65536
+#define SQUASHFS_FILE_LOG		16
+
+#define SQUASHFS_FILE_MAX_SIZE		65536
+
+/* Max number of uids and gids */
+#define SQUASHFS_UIDS			256
+#define SQUASHFS_GUIDS			255
+
+/* Max length of filename (not 255) */
+#define SQUASHFS_NAME_LEN		256
+
+#define SQUASHFS_INVALID		((long long) 0xffffffffffff)
+#define SQUASHFS_INVALID_FRAG		((unsigned int) 0xffffffff)
+#define SQUASHFS_INVALID_BLK		((long long) -1)
+#define SQUASHFS_USED_BLK		((long long) -2)
+
+/* Filesystem flags */
+#define SQUASHFS_NOI			0
+#define SQUASHFS_NOD			1
+#define SQUASHFS_CHECK			2
+#define SQUASHFS_NOF			3
+#define SQUASHFS_NO_FRAG		4
+#define SQUASHFS_ALWAYS_FRAG		5
+#define SQUASHFS_DUPLICATE		6
+#define SQUASHFS_EXPORT			7
+
+#define SQUASHFS_BIT(flag, bit)		((flag >> bit) & 1)
+
+#define SQUASHFS_UNCOMPRESSED_INODES(flags)	SQUASHFS_BIT(flags, \
+						SQUASHFS_NOI)
+
+#define SQUASHFS_UNCOMPRESSED_DATA(flags)	SQUASHFS_BIT(flags, \
+						SQUASHFS_NOD)
+
+#define SQUASHFS_UNCOMPRESSED_FRAGMENTS(flags)	SQUASHFS_BIT(flags, \
+						SQUASHFS_NOF)
+
+#define SQUASHFS_NO_FRAGMENTS(flags)		SQUASHFS_BIT(flags, \
+						SQUASHFS_NO_FRAG)
+
+#define SQUASHFS_ALWAYS_FRAGMENTS(flags)	SQUASHFS_BIT(flags, \
+						SQUASHFS_ALWAYS_FRAG)
+
+#define SQUASHFS_DUPLICATES(flags)		SQUASHFS_BIT(flags, \
+						SQUASHFS_DUPLICATE)
+
+#define SQUASHFS_EXPORTABLE(flags)		SQUASHFS_BIT(flags, \
+						SQUASHFS_EXPORT)
+
+#define SQUASHFS_CHECK_DATA(flags)		SQUASHFS_BIT(flags, \
+						SQUASHFS_CHECK)
+
+#define SQUASHFS_MKFLAGS(noi, nod, check_data, nof, no_frag, always_frag, \
+		duplicate_checking, exortable)	(noi | (nod << 1) | (check_data << 2) \
+		| (nof << 3) | (no_frag << 4) | (always_frag << 5) | \
+		(duplicate_checking << 6) | (exportable << 7))
+
+/* Max number of types and file types */
+#define SQUASHFS_DIR_TYPE		1
+#define SQUASHFS_FILE_TYPE		2
+#define SQUASHFS_SYMLINK_TYPE		3
+#define SQUASHFS_BLKDEV_TYPE		4
+#define SQUASHFS_CHRDEV_TYPE		5
+#define SQUASHFS_FIFO_TYPE		6
+#define SQUASHFS_SOCKET_TYPE		7
+#define SQUASHFS_LDIR_TYPE		8
+#define SQUASHFS_LREG_TYPE		9
+
+/* 1.0 filesystem type definitions */
+#define SQUASHFS_TYPES			5
+#define SQUASHFS_IPC_TYPE		0
+
+/* Flag whether block is compressed or uncompressed, bit is set if block is
+ * uncompressed */
+#define SQUASHFS_COMPRESSED_BIT		(1 << 15)
+
+#define SQUASHFS_COMPRESSED_SIZE(B)	(((B) & ~SQUASHFS_COMPRESSED_BIT) ? \
+		(B) & ~SQUASHFS_COMPRESSED_BIT :  SQUASHFS_COMPRESSED_BIT)
+
+#define SQUASHFS_COMPRESSED(B)		(!((B) & SQUASHFS_COMPRESSED_BIT))
+
+#define SQUASHFS_COMPRESSED_BIT_BLOCK		(1 << 24)
+
+#define SQUASHFS_COMPRESSED_SIZE_BLOCK(B)	(((B) & \
+	~SQUASHFS_COMPRESSED_BIT_BLOCK) ? (B) & \
+	~SQUASHFS_COMPRESSED_BIT_BLOCK : SQUASHFS_COMPRESSED_BIT_BLOCK)
+
+#define SQUASHFS_COMPRESSED_BLOCK(B)	(!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK))
+
+/*
+ * Inode number ops.  Inodes consist of a compressed block number, and an
+ * uncompressed  offset within that block
+ */
+#define SQUASHFS_INODE_BLK(a)		((unsigned int) ((a) >> 16))
+
+#define SQUASHFS_INODE_OFFSET(a)	((unsigned int) ((a) & 0xffff))
+
+#define SQUASHFS_MKINODE(A, B)		((squashfs_inode_t)(((squashfs_inode_t) (A)\
+					<< 16) + (B)))
+
+/* Compute 32 bit VFS inode number from squashfs inode number */
+#define SQUASHFS_MK_VFS_INODE(a, b)	((unsigned int) (((a) << 8) + \
+					((b) >> 2) + 1))
+/* XXX */
+
+/* Translate between VFS mode and squashfs mode */
+#define SQUASHFS_MODE(a)		((a) & 0xfff)
+
+/* fragment and fragment table defines */
+#define SQUASHFS_FRAGMENT_BYTES(A)	((A) * sizeof(struct squashfs_fragment_entry))
+
+#define SQUASHFS_FRAGMENT_INDEX(A)	(SQUASHFS_FRAGMENT_BYTES(A) / \
+					SQUASHFS_METADATA_SIZE)
+
+#define SQUASHFS_FRAGMENT_INDEX_OFFSET(A)	(SQUASHFS_FRAGMENT_BYTES(A) % \
+						SQUASHFS_METADATA_SIZE)
+
+#define SQUASHFS_FRAGMENT_INDEXES(A)	((SQUASHFS_FRAGMENT_BYTES(A) + \
+					SQUASHFS_METADATA_SIZE - 1) / \
+					SQUASHFS_METADATA_SIZE)
+
+#define SQUASHFS_FRAGMENT_INDEX_BYTES(A)	(SQUASHFS_FRAGMENT_INDEXES(A) *\
+						sizeof(long long))
+
+/* inode lookup table defines */
+#define SQUASHFS_LOOKUP_BYTES(A)	((A) * sizeof(squashfs_inode_t))
+
+#define SQUASHFS_LOOKUP_BLOCK(A)		(SQUASHFS_LOOKUP_BYTES(A) / \
+						SQUASHFS_METADATA_SIZE)
+
+#define SQUASHFS_LOOKUP_BLOCK_OFFSET(A)		(SQUASHFS_LOOKUP_BYTES(A) % \
+						SQUASHFS_METADATA_SIZE)
+
+#define SQUASHFS_LOOKUP_BLOCKS(A)	((SQUASHFS_LOOKUP_BYTES(A) + \
+					SQUASHFS_METADATA_SIZE - 1) / \
+					SQUASHFS_METADATA_SIZE)
+
+#define SQUASHFS_LOOKUP_BLOCK_BYTES(A)	(SQUASHFS_LOOKUP_BLOCKS(A) *\
+					sizeof(long long))
+
+/* cached data constants for filesystem */
+#define SQUASHFS_CACHED_BLKS		8
+
+#define SQUASHFS_MAX_FILE_SIZE_LOG	64
+
+#define SQUASHFS_MAX_FILE_SIZE		((long long) 1 << \
+					(SQUASHFS_MAX_FILE_SIZE_LOG - 2))
+
+#define SQUASHFS_MARKER_BYTE		0xff
+
+/* meta index cache */
+#define SQUASHFS_META_INDEXES	(SQUASHFS_METADATA_SIZE / sizeof(unsigned int))
+#define SQUASHFS_META_ENTRIES	31
+#define SQUASHFS_META_NUMBER	8
+#define SQUASHFS_SLOTS		4
+
+struct meta_entry {
+	long long		data_block;
+	unsigned int		index_block;
+	unsigned short		offset;
+	unsigned short		pad;
+};
+
+struct meta_index {
+	unsigned int		inode_number;
+	unsigned int		offset;
+	unsigned short		entries;
+	unsigned short		skip;
+	unsigned short		locked;
+	unsigned short		pad;
+	struct meta_entry	meta_entry[SQUASHFS_META_ENTRIES];
+};
+
+
+/*
+ * definitions for structures on disk
+ */
+
+typedef long long		squashfs_block_t;
+typedef long long		squashfs_inode_t;
+
+struct squashfs_super_block {
+	unsigned int		s_magic;
+	unsigned int		inodes;
+	unsigned int		bytes_used_2;
+	unsigned int		uid_start_2;
+	unsigned int		guid_start_2;
+	unsigned int		inode_table_start_2;
+	unsigned int		directory_table_start_2;
+	unsigned int		s_major:16;
+	unsigned int		s_minor:16;
+	unsigned int		block_size_1:16;
+	unsigned int		block_log:16;
+	unsigned int		flags:8;
+	unsigned int		no_uids:8;
+	unsigned int		no_guids:8;
+	unsigned int		mkfs_time /* time of filesystem creation */;
+	squashfs_inode_t	root_inode;
+	unsigned int		block_size;
+	unsigned int		fragments;
+	unsigned int		fragment_table_start_2;
+	long long		bytes_used;
+	long long		uid_start;
+	long long		guid_start;
+	long long		inode_table_start;
+	long long		directory_table_start;
+	long long		fragment_table_start;
+	long long		lookup_table_start;
+} __attribute__ ((packed));
+
+struct squashfs_dir_index {
+	unsigned int		index;
+	unsigned int		start_block;
+	unsigned char		size;
+	unsigned char		name[0];
+} __attribute__ ((packed));
+
+#define SQUASHFS_BASE_INODE_HEADER		\
+	unsigned int		inode_type:4;	\
+	unsigned int		mode:12;	\
+	unsigned int		uid:8;		\
+	unsigned int		guid:8;		\
+	unsigned int		mtime;		\
+	unsigned int 		inode_number;
+
+struct squashfs_base_inode_header {
+	SQUASHFS_BASE_INODE_HEADER;
+} __attribute__ ((packed));
+
+struct squashfs_ipc_inode_header {
+	SQUASHFS_BASE_INODE_HEADER;
+	unsigned int		nlink;
+} __attribute__ ((packed));
+
+struct squashfs_dev_inode_header {
+	SQUASHFS_BASE_INODE_HEADER;
+	unsigned int		nlink;
+	unsigned short		rdev;
+} __attribute__ ((packed));
+	
+struct squashfs_symlink_inode_header {
+	SQUASHFS_BASE_INODE_HEADER;
+	unsigned int		nlink;
+	unsigned short		symlink_size;
+	char			symlink[0];
+} __attribute__ ((packed));
+
+struct squashfs_reg_inode_header {
+	SQUASHFS_BASE_INODE_HEADER;
+	squashfs_block_t	start_block;
+	unsigned int		fragment;
+	unsigned int		offset;
+	unsigned int		file_size;
+	unsigned short		block_list[0];
+} __attribute__ ((packed));
+
+struct squashfs_lreg_inode_header {
+	SQUASHFS_BASE_INODE_HEADER;
+	unsigned int		nlink;
+	squashfs_block_t	start_block;
+	unsigned int		fragment;
+	unsigned int		offset;
+	long long		file_size;
+	unsigned short		block_list[0];
+} __attribute__ ((packed));
+
+struct squashfs_dir_inode_header {
+	SQUASHFS_BASE_INODE_HEADER;
+	unsigned int		nlink;
+	unsigned int		file_size:19;
+	unsigned int		offset:13;
+	unsigned int		start_block;
+	unsigned int		parent_inode;
+} __attribute__  ((packed));
+
+struct squashfs_ldir_inode_header {
+	SQUASHFS_BASE_INODE_HEADER;
+	unsigned int		nlink;
+	unsigned int		file_size:27;
+	unsigned int		offset:13;
+	unsigned int		start_block;
+	unsigned int		i_count:16;
+	unsigned int		parent_inode;
+	struct squashfs_dir_index	index[0];
+} __attribute__  ((packed));
+
+union squashfs_inode_header {
+	struct squashfs_base_inode_header	base;
+	struct squashfs_dev_inode_header	dev;
+	struct squashfs_symlink_inode_header	symlink;
+	struct squashfs_reg_inode_header	reg;
+	struct squashfs_lreg_inode_header	lreg;
+	struct squashfs_dir_inode_header	dir;
+	struct squashfs_ldir_inode_header	ldir;
+	struct squashfs_ipc_inode_header	ipc;
+};
+	
+struct squashfs_dir_entry {
+	unsigned int		offset:13;
+	unsigned int		type:3;
+	unsigned int		size:8;
+	int			inode_number:16;
+	char			name[0];
+} __attribute__ ((packed));
+
+struct squashfs_dir_header {
+	unsigned int		count:8;
+	unsigned int		start_block;
+	unsigned int		inode_number;
+} __attribute__ ((packed));
+
+struct squashfs_fragment_entry {
+	long long		start_block;
+	unsigned int		size;
+	unsigned int		pending;
+} __attribute__ ((packed));
+
+extern int squashfs_uncompress_block(void *d, int dstlen, void *s, int srclen);
+extern int squashfs_uncompress_init(void);
+extern int squashfs_uncompress_exit(void);
+
+/*
+ * macros to convert each packed bitfield structure from little endian to big
+ * endian and vice versa.  These are needed when creating or using a filesystem
+ * on a machine with different byte ordering to the target architecture.
+ *
+ */
+
+#define SQUASHFS_SWAP_START \
+	int bits;\
+	int b_pos;\
+	unsigned long long val;\
+	unsigned char *s;\
+	unsigned char *d;
+
+#define SQUASHFS_SWAP_SUPER_BLOCK(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_super_block));\
+	SQUASHFS_SWAP((s)->s_magic, d, 0, 32);\
+	SQUASHFS_SWAP((s)->inodes, d, 32, 32);\
+	SQUASHFS_SWAP((s)->bytes_used_2, d, 64, 32);\
+	SQUASHFS_SWAP((s)->uid_start_2, d, 96, 32);\
+	SQUASHFS_SWAP((s)->guid_start_2, d, 128, 32);\
+	SQUASHFS_SWAP((s)->inode_table_start_2, d, 160, 32);\
+	SQUASHFS_SWAP((s)->directory_table_start_2, d, 192, 32);\
+	SQUASHFS_SWAP((s)->s_major, d, 224, 16);\
+	SQUASHFS_SWAP((s)->s_minor, d, 240, 16);\
+	SQUASHFS_SWAP((s)->block_size_1, d, 256, 16);\
+	SQUASHFS_SWAP((s)->block_log, d, 272, 16);\
+	SQUASHFS_SWAP((s)->flags, d, 288, 8);\
+	SQUASHFS_SWAP((s)->no_uids, d, 296, 8);\
+	SQUASHFS_SWAP((s)->no_guids, d, 304, 8);\
+	SQUASHFS_SWAP((s)->mkfs_time, d, 312, 32);\
+	SQUASHFS_SWAP((s)->root_inode, d, 344, 64);\
+	SQUASHFS_SWAP((s)->block_size, d, 408, 32);\
+	SQUASHFS_SWAP((s)->fragments, d, 440, 32);\
+	SQUASHFS_SWAP((s)->fragment_table_start_2, d, 472, 32);\
+	SQUASHFS_SWAP((s)->bytes_used, d, 504, 64);\
+	SQUASHFS_SWAP((s)->uid_start, d, 568, 64);\
+	SQUASHFS_SWAP((s)->guid_start, d, 632, 64);\
+	SQUASHFS_SWAP((s)->inode_table_start, d, 696, 64);\
+	SQUASHFS_SWAP((s)->directory_table_start, d, 760, 64);\
+	SQUASHFS_SWAP((s)->fragment_table_start, d, 824, 64);\
+	SQUASHFS_SWAP((s)->lookup_table_start, d, 888, 64);\
+}
+
+#define SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\
+	SQUASHFS_MEMSET(s, d, n);\
+	SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
+	SQUASHFS_SWAP((s)->mode, d, 4, 12);\
+	SQUASHFS_SWAP((s)->uid, d, 16, 8);\
+	SQUASHFS_SWAP((s)->guid, d, 24, 8);\
+	SQUASHFS_SWAP((s)->mtime, d, 32, 32);\
+	SQUASHFS_SWAP((s)->inode_number, d, 64, 32);
+
+#define SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, n) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\
+}
+
+#define SQUASHFS_SWAP_IPC_INODE_HEADER(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
+			sizeof(struct squashfs_ipc_inode_header))\
+	SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
+}
+
+#define SQUASHFS_SWAP_DEV_INODE_HEADER(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
+			sizeof(struct squashfs_dev_inode_header)); \
+	SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
+	SQUASHFS_SWAP((s)->rdev, d, 128, 16);\
+}
+
+#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
+			sizeof(struct squashfs_symlink_inode_header));\
+	SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
+	SQUASHFS_SWAP((s)->symlink_size, d, 128, 16);\
+}
+
+#define SQUASHFS_SWAP_REG_INODE_HEADER(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
+			sizeof(struct squashfs_reg_inode_header));\
+	SQUASHFS_SWAP((s)->start_block, d, 96, 64);\
+	SQUASHFS_SWAP((s)->fragment, d, 160, 32);\
+	SQUASHFS_SWAP((s)->offset, d, 192, 32);\
+	SQUASHFS_SWAP((s)->file_size, d, 224, 32);\
+}
+
+#define SQUASHFS_SWAP_LREG_INODE_HEADER(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
+			sizeof(struct squashfs_lreg_inode_header));\
+	SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
+	SQUASHFS_SWAP((s)->start_block, d, 128, 64);\
+	SQUASHFS_SWAP((s)->fragment, d, 192, 32);\
+	SQUASHFS_SWAP((s)->offset, d, 224, 32);\
+	SQUASHFS_SWAP((s)->file_size, d, 256, 64);\
+}
+
+#define SQUASHFS_SWAP_DIR_INODE_HEADER(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
+			sizeof(struct squashfs_dir_inode_header));\
+	SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
+	SQUASHFS_SWAP((s)->file_size, d, 128, 19);\
+	SQUASHFS_SWAP((s)->offset, d, 147, 13);\
+	SQUASHFS_SWAP((s)->start_block, d, 160, 32);\
+	SQUASHFS_SWAP((s)->parent_inode, d, 192, 32);\
+}
+
+#define SQUASHFS_SWAP_LDIR_INODE_HEADER(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
+			sizeof(struct squashfs_ldir_inode_header));\
+	SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
+	SQUASHFS_SWAP((s)->file_size, d, 128, 27);\
+	SQUASHFS_SWAP((s)->offset, d, 155, 13);\
+	SQUASHFS_SWAP((s)->start_block, d, 168, 32);\
+	SQUASHFS_SWAP((s)->i_count, d, 200, 16);\
+	SQUASHFS_SWAP((s)->parent_inode, d, 216, 32);\
+}
+
+#define SQUASHFS_SWAP_DIR_INDEX(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index));\
+	SQUASHFS_SWAP((s)->index, d, 0, 32);\
+	SQUASHFS_SWAP((s)->start_block, d, 32, 32);\
+	SQUASHFS_SWAP((s)->size, d, 64, 8);\
+}
+
+#define SQUASHFS_SWAP_DIR_HEADER(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header));\
+	SQUASHFS_SWAP((s)->count, d, 0, 8);\
+	SQUASHFS_SWAP((s)->start_block, d, 8, 32);\
+	SQUASHFS_SWAP((s)->inode_number, d, 40, 32);\
+}
+
+#define SQUASHFS_SWAP_DIR_ENTRY(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry));\
+	SQUASHFS_SWAP((s)->offset, d, 0, 13);\
+	SQUASHFS_SWAP((s)->type, d, 13, 3);\
+	SQUASHFS_SWAP((s)->size, d, 16, 8);\
+	SQUASHFS_SWAP((s)->inode_number, d, 24, 16);\
+}
+
+#define SQUASHFS_SWAP_FRAGMENT_ENTRY(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry));\
+	SQUASHFS_SWAP((s)->start_block, d, 0, 64);\
+	SQUASHFS_SWAP((s)->size, d, 64, 32);\
+}
+
+#define SQUASHFS_SWAP_INODE_T(s, d) SQUASHFS_SWAP_LONG_LONGS(s, d, 1)
+
+#define SQUASHFS_SWAP_SHORTS(s, d, n) {\
+	int entry;\
+	int bit_position;\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, n * 2);\
+	for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
+			16)\
+		SQUASHFS_SWAP(s[entry], d, bit_position, 16);\
+}
+
+#define SQUASHFS_SWAP_INTS(s, d, n) {\
+	int entry;\
+	int bit_position;\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, n * 4);\
+	for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
+			32)\
+		SQUASHFS_SWAP(s[entry], d, bit_position, 32);\
+}
+
+#define SQUASHFS_SWAP_LONG_LONGS(s, d, n) {\
+	int entry;\
+	int bit_position;\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, n * 8);\
+	for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
+			64)\
+		SQUASHFS_SWAP(s[entry], d, bit_position, 64);\
+}
+
+#define SQUASHFS_SWAP_DATA(s, d, n, bits) {\
+	int entry;\
+	int bit_position;\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, n * bits / 8);\
+	for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
+			bits)\
+		SQUASHFS_SWAP(s[entry], d, bit_position, bits);\
+}
+
+#define SQUASHFS_SWAP_FRAGMENT_INDEXES(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n)
+#define SQUASHFS_SWAP_LOOKUP_BLOCKS(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n)
+
+#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
+
+struct squashfs_base_inode_header_1 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:4; /* index into uid table */
+	unsigned int		guid:4; /* index into guid table */
+} __attribute__ ((packed));
+
+struct squashfs_ipc_inode_header_1 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:4; /* index into uid table */
+	unsigned int		guid:4; /* index into guid table */
+	unsigned int		type:4;
+	unsigned int		offset:4;
+} __attribute__ ((packed));
+
+struct squashfs_dev_inode_header_1 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:4; /* index into uid table */
+	unsigned int		guid:4; /* index into guid table */
+	unsigned short		rdev;
+} __attribute__ ((packed));
+	
+struct squashfs_symlink_inode_header_1 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:4; /* index into uid table */
+	unsigned int		guid:4; /* index into guid table */
+	unsigned short		symlink_size;
+	char			symlink[0];
+} __attribute__ ((packed));
+
+struct squashfs_reg_inode_header_1 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:4; /* index into uid table */
+	unsigned int		guid:4; /* index into guid table */
+	unsigned int		mtime;
+	unsigned int		start_block;
+	unsigned int		file_size:32;
+	unsigned short		block_list[0];
+} __attribute__ ((packed));
+
+struct squashfs_dir_inode_header_1 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:4; /* index into uid table */
+	unsigned int		guid:4; /* index into guid table */
+	unsigned int		file_size:19;
+	unsigned int		offset:13;
+	unsigned int		mtime;
+	unsigned int		start_block:24;
+} __attribute__  ((packed));
+
+#define SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n) \
+	SQUASHFS_MEMSET(s, d, n);\
+	SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
+	SQUASHFS_SWAP((s)->mode, d, 4, 12);\
+	SQUASHFS_SWAP((s)->uid, d, 16, 4);\
+	SQUASHFS_SWAP((s)->guid, d, 20, 4);
+
+#define SQUASHFS_SWAP_BASE_INODE_HEADER_1(s, d, n) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n)\
+}
+
+#define SQUASHFS_SWAP_IPC_INODE_HEADER_1(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
+			sizeof(struct squashfs_ipc_inode_header_1));\
+	SQUASHFS_SWAP((s)->type, d, 24, 4);\
+	SQUASHFS_SWAP((s)->offset, d, 28, 4);\
+}
+
+#define SQUASHFS_SWAP_DEV_INODE_HEADER_1(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
+			sizeof(struct squashfs_dev_inode_header_1));\
+	SQUASHFS_SWAP((s)->rdev, d, 24, 16);\
+}
+
+#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_1(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
+			sizeof(struct squashfs_symlink_inode_header_1));\
+	SQUASHFS_SWAP((s)->symlink_size, d, 24, 16);\
+}
+
+#define SQUASHFS_SWAP_REG_INODE_HEADER_1(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
+			sizeof(struct squashfs_reg_inode_header_1));\
+	SQUASHFS_SWAP((s)->mtime, d, 24, 32);\
+	SQUASHFS_SWAP((s)->start_block, d, 56, 32);\
+	SQUASHFS_SWAP((s)->file_size, d, 88, 32);\
+}
+
+#define SQUASHFS_SWAP_DIR_INODE_HEADER_1(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
+			sizeof(struct squashfs_dir_inode_header_1));\
+	SQUASHFS_SWAP((s)->file_size, d, 24, 19);\
+	SQUASHFS_SWAP((s)->offset, d, 43, 13);\
+	SQUASHFS_SWAP((s)->mtime, d, 56, 32);\
+	SQUASHFS_SWAP((s)->start_block, d, 88, 24);\
+}
+
+#endif
+
+#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY
+
+struct squashfs_dir_index_2 {
+	unsigned int		index:27;
+	unsigned int		start_block:29;
+	unsigned char		size;
+	unsigned char		name[0];
+} __attribute__ ((packed));
+
+struct squashfs_base_inode_header_2 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:8; /* index into uid table */
+	unsigned int		guid:8; /* index into guid table */
+} __attribute__ ((packed));
+
+struct squashfs_ipc_inode_header_2 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:8; /* index into uid table */
+	unsigned int		guid:8; /* index into guid table */
+} __attribute__ ((packed));
+
+struct squashfs_dev_inode_header_2 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:8; /* index into uid table */
+	unsigned int		guid:8; /* index into guid table */
+	unsigned short		rdev;
+} __attribute__ ((packed));
+	
+struct squashfs_symlink_inode_header_2 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:8; /* index into uid table */
+	unsigned int		guid:8; /* index into guid table */
+	unsigned short		symlink_size;
+	char			symlink[0];
+} __attribute__ ((packed));
+
+struct squashfs_reg_inode_header_2 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:8; /* index into uid table */
+	unsigned int		guid:8; /* index into guid table */
+	unsigned int		mtime;
+	unsigned int		start_block;
+	unsigned int		fragment;
+	unsigned int		offset;
+	unsigned int		file_size:32;
+	unsigned short		block_list[0];
+} __attribute__ ((packed));
+
+struct squashfs_dir_inode_header_2 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:8; /* index into uid table */
+	unsigned int		guid:8; /* index into guid table */
+	unsigned int		file_size:19;
+	unsigned int		offset:13;
+	unsigned int		mtime;
+	unsigned int		start_block:24;
+} __attribute__  ((packed));
+
+struct squashfs_ldir_inode_header_2 {
+	unsigned int		inode_type:4;
+	unsigned int		mode:12; /* protection */
+	unsigned int		uid:8; /* index into uid table */
+	unsigned int		guid:8; /* index into guid table */
+	unsigned int		file_size:27;
+	unsigned int		offset:13;
+	unsigned int		mtime;
+	unsigned int		start_block:24;
+	unsigned int		i_count:16;
+	struct squashfs_dir_index_2	index[0];
+} __attribute__  ((packed));
+
+union squashfs_inode_header_2 {
+	struct squashfs_base_inode_header_2	base;
+	struct squashfs_dev_inode_header_2	dev;
+	struct squashfs_symlink_inode_header_2	symlink;
+	struct squashfs_reg_inode_header_2	reg;
+	struct squashfs_dir_inode_header_2	dir;
+	struct squashfs_ldir_inode_header_2	ldir;
+	struct squashfs_ipc_inode_header_2	ipc;
+};
+	
+struct squashfs_dir_header_2 {
+	unsigned int		count:8;
+	unsigned int		start_block:24;
+} __attribute__ ((packed));
+
+struct squashfs_dir_entry_2 {
+	unsigned int		offset:13;
+	unsigned int		type:3;
+	unsigned int		size:8;
+	char			name[0];
+} __attribute__ ((packed));
+
+struct squashfs_fragment_entry_2 {
+	unsigned int		start_block;
+	unsigned int		size;
+} __attribute__ ((packed));
+
+#define SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\
+	SQUASHFS_MEMSET(s, d, n);\
+	SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
+	SQUASHFS_SWAP((s)->mode, d, 4, 12);\
+	SQUASHFS_SWAP((s)->uid, d, 16, 8);\
+	SQUASHFS_SWAP((s)->guid, d, 24, 8);\
+
+#define SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, n) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\
+}
+
+#define SQUASHFS_SWAP_IPC_INODE_HEADER_2(s, d) \
+	SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, sizeof(struct squashfs_ipc_inode_header_2))
+
+#define SQUASHFS_SWAP_DEV_INODE_HEADER_2(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
+			sizeof(struct squashfs_dev_inode_header_2)); \
+	SQUASHFS_SWAP((s)->rdev, d, 32, 16);\
+}
+
+#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
+			sizeof(struct squashfs_symlink_inode_header_2));\
+	SQUASHFS_SWAP((s)->symlink_size, d, 32, 16);\
+}
+
+#define SQUASHFS_SWAP_REG_INODE_HEADER_2(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
+			sizeof(struct squashfs_reg_inode_header_2));\
+	SQUASHFS_SWAP((s)->mtime, d, 32, 32);\
+	SQUASHFS_SWAP((s)->start_block, d, 64, 32);\
+	SQUASHFS_SWAP((s)->fragment, d, 96, 32);\
+	SQUASHFS_SWAP((s)->offset, d, 128, 32);\
+	SQUASHFS_SWAP((s)->file_size, d, 160, 32);\
+}
+
+#define SQUASHFS_SWAP_DIR_INODE_HEADER_2(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
+			sizeof(struct squashfs_dir_inode_header_2));\
+	SQUASHFS_SWAP((s)->file_size, d, 32, 19);\
+	SQUASHFS_SWAP((s)->offset, d, 51, 13);\
+	SQUASHFS_SWAP((s)->mtime, d, 64, 32);\
+	SQUASHFS_SWAP((s)->start_block, d, 96, 24);\
+}
+
+#define SQUASHFS_SWAP_LDIR_INODE_HEADER_2(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
+			sizeof(struct squashfs_ldir_inode_header_2));\
+	SQUASHFS_SWAP((s)->file_size, d, 32, 27);\
+	SQUASHFS_SWAP((s)->offset, d, 59, 13);\
+	SQUASHFS_SWAP((s)->mtime, d, 72, 32);\
+	SQUASHFS_SWAP((s)->start_block, d, 104, 24);\
+	SQUASHFS_SWAP((s)->i_count, d, 128, 16);\
+}
+
+#define SQUASHFS_SWAP_DIR_INDEX_2(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index_2));\
+	SQUASHFS_SWAP((s)->index, d, 0, 27);\
+	SQUASHFS_SWAP((s)->start_block, d, 27, 29);\
+	SQUASHFS_SWAP((s)->size, d, 56, 8);\
+}
+#define SQUASHFS_SWAP_DIR_HEADER_2(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header_2));\
+	SQUASHFS_SWAP((s)->count, d, 0, 8);\
+	SQUASHFS_SWAP((s)->start_block, d, 8, 24);\
+}
+
+#define SQUASHFS_SWAP_DIR_ENTRY_2(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry_2));\
+	SQUASHFS_SWAP((s)->offset, d, 0, 13);\
+	SQUASHFS_SWAP((s)->type, d, 13, 3);\
+	SQUASHFS_SWAP((s)->size, d, 16, 8);\
+}
+
+#define SQUASHFS_SWAP_FRAGMENT_ENTRY_2(s, d) {\
+	SQUASHFS_SWAP_START\
+	SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry_2));\
+	SQUASHFS_SWAP((s)->start_block, d, 0, 32);\
+	SQUASHFS_SWAP((s)->size, d, 32, 32);\
+}
+
+#define SQUASHFS_SWAP_FRAGMENT_INDEXES_2(s, d, n) SQUASHFS_SWAP_INTS(s, d, n)
+
+/* fragment and fragment table defines */
+#define SQUASHFS_FRAGMENT_BYTES_2(A)	(A * sizeof(struct squashfs_fragment_entry_2))
+
+#define SQUASHFS_FRAGMENT_INDEX_2(A)	(SQUASHFS_FRAGMENT_BYTES_2(A) / \
+					SQUASHFS_METADATA_SIZE)
+
+#define SQUASHFS_FRAGMENT_INDEX_OFFSET_2(A)	(SQUASHFS_FRAGMENT_BYTES_2(A) % \
+						SQUASHFS_METADATA_SIZE)
+
+#define SQUASHFS_FRAGMENT_INDEXES_2(A)	((SQUASHFS_FRAGMENT_BYTES_2(A) + \
+					SQUASHFS_METADATA_SIZE - 1) / \
+					SQUASHFS_METADATA_SIZE)
+
+#define SQUASHFS_FRAGMENT_INDEX_BYTES_2(A)	(SQUASHFS_FRAGMENT_INDEXES_2(A) *\
+						sizeof(int))
+
+#endif
+
+#ifdef __KERNEL__
+
+/*
+ * macros used to swap each structure entry, taking into account
+ * bitfields and different bitfield placing conventions on differing
+ * architectures
+ */
+
+#include <asm/byteorder.h>
+
+#ifdef __BIG_ENDIAN
+	/* convert from little endian to big endian */
+#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, \
+		tbits, b_pos)
+#else
+	/* convert from big endian to little endian */ 
+#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, \
+		tbits, 64 - tbits - b_pos)
+#endif
+
+#define _SQUASHFS_SWAP(value, p, pos, tbits, SHIFT) {\
+	b_pos = pos % 8;\
+	val = 0;\
+	s = (unsigned char *)p + (pos / 8);\
+	d = ((unsigned char *) &val) + 7;\
+	for(bits = 0; bits < (tbits + b_pos); bits += 8) \
+		*d-- = *s++;\
+	value = (val >> (SHIFT))/* & ((1 << tbits) - 1)*/;\
+}
+
+#define SQUASHFS_MEMSET(s, d, n)	memset(s, 0, n);
+
+#endif
+#endif
--- /dev/null	2011-06-03 14:51:38.633053002 +0200
+++ linux-2.6.20.14-fbx/include/linux/squashfs_fs_i.h	2011-09-26 15:07:56.458834129 +0200
@@ -0,0 +1,45 @@
+#ifndef SQUASHFS_FS_I
+#define SQUASHFS_FS_I
+/*
+ * Squashfs
+ *
+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007
+ * Phillip Lougher <phillip@lougher.org.uk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2,
+ * or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * squashfs_fs_i.h
+ */
+
+struct squashfs_inode_info {
+	long long	start_block;
+	unsigned int	offset;
+	union {
+		struct {
+			long long	fragment_start_block;
+			unsigned int	fragment_size;
+			unsigned int	fragment_offset;
+			long long	block_list_start;
+		} s1;
+		struct {
+			long long	directory_index_start;
+			unsigned int	directory_index_offset;
+			unsigned int	directory_index_count;
+			unsigned int	parent_inode;
+		} s2;
+	} u;
+	struct inode	vfs_inode;
+};
+#endif
--- /dev/null	2011-06-03 14:51:38.633053002 +0200
+++ linux-2.6.20.14-fbx/include/linux/squashfs_fs_sb.h	2011-09-26 15:07:56.458834129 +0200
@@ -0,0 +1,74 @@
+#ifndef SQUASHFS_FS_SB
+#define SQUASHFS_FS_SB
+/*
+ * Squashfs
+ *
+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007
+ * Phillip Lougher <phillip@lougher.org.uk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2,
+ * or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * squashfs_fs_sb.h
+ */
+
+#include <linux/squashfs_fs.h>
+#include "sqlzma.h"
+
+struct squashfs_cache {
+	long long	block;
+	int		length;
+	long long	next_index;
+	char		*data;
+};
+
+struct squashfs_fragment_cache {
+	long long	block;
+	int		length;
+	unsigned int	locked;
+	char		*data;
+};
+
+struct squashfs_sb_info {
+	struct squashfs_super_block	sblk;
+	int			devblksize;
+	int			devblksize_log2;
+	int			swap;
+	struct squashfs_cache	*block_cache;
+	struct squashfs_fragment_cache	*fragment;
+	int			next_cache;
+	int			next_fragment;
+	int			next_meta_index;
+	unsigned int		*uid;
+	unsigned int		*guid;
+	long long		*fragment_index;
+	unsigned int		*fragment_index_2;
+	char			*read_page;
+	//struct mutex		read_data_mutex;
+	struct mutex		read_page_mutex;
+	struct mutex		block_cache_mutex;
+	struct mutex		fragment_mutex;
+	struct mutex		meta_index_mutex;
+	wait_queue_head_t	waitq;
+	wait_queue_head_t	fragment_wait_queue;
+	struct meta_index	*meta_index;
+	long long		*inode_lookup_table;
+	int			(*read_inode)(struct inode *i,  squashfs_inode_t \
+				inode);
+	long long		(*read_blocklist)(struct inode *inode, int \
+				index, int readahead_blks, char *block_list, \
+				unsigned short **block_p, unsigned int *bsize);
+	int			(*read_fragment_index_table)(struct super_block *s);
+};
+#endif
--- /dev/null	2011-06-03 14:51:38.633053002 +0200
+++ linux-2.6.20.14-fbx/lib/builtin-fbxserial.c	2011-09-26 15:07:56.538834079 +0200
@@ -0,0 +1,131 @@
+/*
+ * builtin-fbxserialinfo.c for linux-freebox
+ * Created by <nschichan@freebox.fr> on Thu Feb  1 19:12:08 2007
+ * Freebox SA
+ *
+ * Licence GPL: see COPYING for details.
+ */
+
+/*
+ * this file contains fbxserialinfo related function that need to
+ * built-in in the kernel.
+ */
+
+#include <linux/compiler.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/crc32.h>
+
+#include <asm/io.h>
+
+#include <linux/fbxserial.h>
+#include <linux/fbxserialinfo.h>
+
+#define PFX "builtin-fbxserial: "
+
+static void __init
+fbxserialinfo_use_default(struct fbx_serial *serial)
+{
+	printk(KERN_WARNING PFX "warning: using default serial infos\n");
+	fbxserial_set_default(serial);
+}
+
+/*
+ * add trailing 0 for bundle string here.
+ */
+static void __init
+bundle_fixup(struct fbx_serial *serial)
+{
+	struct fbx_serial_extinfo *p;
+	int i;
+
+	for (i = 0; i < be32_to_cpu(serial->extinfo_count); i++) {
+
+		if (i >= EXTINFO_MAX_COUNT)
+			break;
+
+		p = &serial->extinfos[i];
+		if (be32_to_cpu(p->type) == EXTINFO_TYPE_EXTDEV &&
+		    be32_to_cpu(p->u.extdev.type) == EXTDEV_TYPE_BUNDLE) {
+			int size;
+
+			size = sizeof (p->u.extdev.serial);
+			p->u.extdev.serial[size - 1] = 0;
+		}
+	}
+}
+
+/*
+ * called from  arch code early  in the boot sequence.   This function
+ * returns 1  in case serial infos are  invalid/unreadable and default
+ * values have been used.
+ */
+int __init
+fbxserialinfo_read(void *data, struct fbx_serial *out)
+{
+	uint32_t sum;
+
+	/*
+	 * get partial serial data from flash/whatever.
+	 */
+	memcpy(out, data, sizeof (*out));
+
+	/* check magic first */
+	if (be32_to_cpu(out->magic) != FBXSERIAL_MAGIC) {
+		printk(KERN_NOTICE PFX "invalid magic (%08x, expected %08x), "
+			"using defaults !\n", be32_to_cpu(out->magic),
+		       FBXSERIAL_MAGIC);
+		goto out_default;
+	}
+
+	/* fetch size for which we have to check CRC */
+	if (be32_to_cpu(out->len) > FBXSERIAL_MAX_SIZE) {
+		printk(KERN_NOTICE PFX "structure size too big (%d), "
+		       "using defaults !\n", be32_to_cpu(out->len));
+		goto out_default;
+	}
+
+	/* compute and check checksum */
+	sum = crc32(0, data + 4, be32_to_cpu(out->len) - 4);
+
+	if (be32_to_cpu(out->crc32) != sum) {
+		printk(KERN_NOTICE PFX "invalid checksum (%08x, "
+		       "expected %08x), using defaults !\n", sum,
+		       be32_to_cpu(out->crc32));
+		goto out_default;
+	}
+
+	printk(KERN_INFO PFX "Found valid serial infos !\n");
+	bundle_fixup(out);
+	return 0;
+
+ out_default:
+	fbxserialinfo_use_default(out);
+	bundle_fixup(out);
+	return 1;
+}
+
+void
+fbxserialinfo_get_random(unsigned char *data, unsigned int len)
+{
+	const struct fbx_serial *s;
+
+	s = arch_get_serial();
+
+	if (len > sizeof (s->random_data))
+		len = sizeof (s->random_data);
+
+	memcpy(data, s->random_data, len);
+}
+EXPORT_SYMBOL(fbxserialinfo_get_random);
+
+void
+fbxserialinfo_get_mac_addr(unsigned char *data)
+{
+	const struct fbx_serial *s;
+
+	s = arch_get_serial();
+	memcpy(data, s->mac_addr_base, MAC_ADDR_SIZE);
+}
+EXPORT_SYMBOL(fbxserialinfo_get_mac_addr);
--- /dev/null	2011-06-03 14:51:38.633053002 +0200
+++ linux-2.6.20.14-fbx/lib/LzmaDecode.c	2011-09-26 15:07:56.538834079 +0200
@@ -0,0 +1,584 @@
+/*
+  LzmaDecode.c
+  LZMA Decoder (optimized for Speed version)
+  
+  LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01)
+  http://www.7-zip.org/
+
+  LZMA SDK is licensed under two licenses:
+  1) GNU Lesser General Public License (GNU LGPL)
+  2) Common Public License (CPL)
+  It means that you can select one of these two licenses and 
+  follow rules of that license.
+
+  SPECIAL EXCEPTION:
+  Igor Pavlov, as the author of this Code, expressly permits you to 
+  statically or dynamically link your Code (or bind by name) to the 
+  interfaces of this file without subjecting your linked Code to the 
+  terms of the CPL or GNU LGPL. Any modifications or additions 
+  to this file, however, are subject to the LGPL or CPL terms.
+*/
+
+#include "LzmaDecode.h"
+
+#define kNumTopBits 24
+#define kTopValue ((UInt32)1 << kNumTopBits)
+
+#define kNumBitModelTotalBits 11
+#define kBitModelTotal (1 << kNumBitModelTotalBits)
+#define kNumMoveBits 5
+
+#define RC_READ_BYTE (*Buffer++)
+
+#define RC_INIT2 Code = 0; Range = 0xFFFFFFFF; \
+  { int i; for(i = 0; i < 5; i++) { RC_TEST; Code = (Code << 8) | RC_READ_BYTE; }}
+
+#ifdef _LZMA_IN_CB
+
+#define RC_TEST { if (Buffer == BufferLim) \
+  { SizeT size; int result = InCallback->Read(InCallback, &Buffer, &size); if (result != LZMA_RESULT_OK) return result; \
+  BufferLim = Buffer + size; if (size == 0) return LZMA_RESULT_DATA_ERROR; }}
+
+#define RC_INIT Buffer = BufferLim = 0; RC_INIT2
+
+#else
+
+#define RC_TEST { if (Buffer == BufferLim) return LZMA_RESULT_DATA_ERROR; }
+
+#define RC_INIT(buffer, bufferSize) Buffer = buffer; BufferLim = buffer + bufferSize; RC_INIT2
+ 
+#endif
+
+#define RC_NORMALIZE if (Range < kTopValue) { RC_TEST; Range <<= 8; Code = (Code << 8) | RC_READ_BYTE; }
+
+#define IfBit0(p) RC_NORMALIZE; bound = (Range >> kNumBitModelTotalBits) * *(p); if (Code < bound)
+#define UpdateBit0(p) Range = bound; *(p) += (kBitModelTotal - *(p)) >> kNumMoveBits;
+#define UpdateBit1(p) Range -= bound; Code -= bound; *(p) -= (*(p)) >> kNumMoveBits;
+
+#define RC_GET_BIT2(p, mi, A0, A1) IfBit0(p) \
+  { UpdateBit0(p); mi <<= 1; A0; } else \
+  { UpdateBit1(p); mi = (mi + mi) + 1; A1; } 
+  
+#define RC_GET_BIT(p, mi) RC_GET_BIT2(p, mi, ; , ;)               
+
+#define RangeDecoderBitTreeDecode(probs, numLevels, res) \
+  { int i = numLevels; res = 1; \
+  do { CProb *p = probs + res; RC_GET_BIT(p, res) } while(--i != 0); \
+  res -= (1 << numLevels); }
+
+
+#define kNumPosBitsMax 4
+#define kNumPosStatesMax (1 << kNumPosBitsMax)
+
+#define kLenNumLowBits 3
+#define kLenNumLowSymbols (1 << kLenNumLowBits)
+#define kLenNumMidBits 3
+#define kLenNumMidSymbols (1 << kLenNumMidBits)
+#define kLenNumHighBits 8
+#define kLenNumHighSymbols (1 << kLenNumHighBits)
+
+#define LenChoice 0
+#define LenChoice2 (LenChoice + 1)
+#define LenLow (LenChoice2 + 1)
+#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
+#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
+#define kNumLenProbs (LenHigh + kLenNumHighSymbols) 
+
+
+#define kNumStates 12
+#define kNumLitStates 7
+
+#define kStartPosModelIndex 4
+#define kEndPosModelIndex 14
+#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
+
+#define kNumPosSlotBits 6
+#define kNumLenToPosStates 4
+
+#define kNumAlignBits 4
+#define kAlignTableSize (1 << kNumAlignBits)
+
+#define kMatchMinLen 2
+
+#define IsMatch 0
+#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
+#define IsRepG0 (IsRep + kNumStates)
+#define IsRepG1 (IsRepG0 + kNumStates)
+#define IsRepG2 (IsRepG1 + kNumStates)
+#define IsRep0Long (IsRepG2 + kNumStates)
+#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
+#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
+#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
+#define LenCoder (Align + kAlignTableSize)
+#define RepLenCoder (LenCoder + kNumLenProbs)
+#define Literal (RepLenCoder + kNumLenProbs)
+
+#if Literal != LZMA_BASE_SIZE
+StopCompilingDueBUG
+#endif
+
+int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size)
+{
+  unsigned char prop0;
+  if (size < LZMA_PROPERTIES_SIZE)
+    return LZMA_RESULT_DATA_ERROR;
+  prop0 = propsData[0];
+  if (prop0 >= (9 * 5 * 5))
+    return LZMA_RESULT_DATA_ERROR;
+  {
+    for (propsRes->pb = 0; prop0 >= (9 * 5); propsRes->pb++, prop0 -= (9 * 5));
+    for (propsRes->lp = 0; prop0 >= 9; propsRes->lp++, prop0 -= 9);
+    propsRes->lc = prop0;
+    /*
+    unsigned char remainder = (unsigned char)(prop0 / 9);
+    propsRes->lc = prop0 % 9;
+    propsRes->pb = remainder / 5;
+    propsRes->lp = remainder % 5;
+    */
+  }
+
+  #ifdef _LZMA_OUT_READ
+  {
+    int i;
+    propsRes->DictionarySize = 0;
+    for (i = 0; i < 4; i++)
+      propsRes->DictionarySize += (UInt32)(propsData[1 + i]) << (i * 8);
+    if (propsRes->DictionarySize == 0)
+      propsRes->DictionarySize = 1;
+  }
+  #endif
+  return LZMA_RESULT_OK;
+}
+
+#define kLzmaStreamWasFinishedId (-1)
+
+int LzmaDecode(CLzmaDecoderState *vs,
+    #ifdef _LZMA_IN_CB
+    ILzmaInCallback *InCallback,
+    #else
+    const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed,
+    #endif
+    unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed)
+{
+  CProb *p = vs->Probs;
+  SizeT nowPos = 0;
+  Byte previousByte = 0;
+  UInt32 posStateMask = (1 << (vs->Properties.pb)) - 1;
+  UInt32 literalPosMask = (1 << (vs->Properties.lp)) - 1;
+  int lc = vs->Properties.lc;
+
+  #ifdef _LZMA_OUT_READ
+  
+  UInt32 Range = vs->Range;
+  UInt32 Code = vs->Code;
+  #ifdef _LZMA_IN_CB
+  const Byte *Buffer = vs->Buffer;
+  const Byte *BufferLim = vs->BufferLim;
+  #else
+  const Byte *Buffer = inStream;
+  const Byte *BufferLim = inStream + inSize;
+  #endif
+  int state = vs->State;
+  UInt32 rep0 = vs->Reps[0], rep1 = vs->Reps[1], rep2 = vs->Reps[2], rep3 = vs->Reps[3];
+  int len = vs->RemainLen;
+  UInt32 globalPos = vs->GlobalPos;
+  UInt32 distanceLimit = vs->DistanceLimit;
+
+  Byte *dictionary = vs->Dictionary;
+  UInt32 dictionarySize = vs->Properties.DictionarySize;
+  UInt32 dictionaryPos = vs->DictionaryPos;
+
+  Byte tempDictionary[4];
+
+  #ifndef _LZMA_IN_CB
+  *inSizeProcessed = 0;
+  #endif
+  *outSizeProcessed = 0;
+  if (len == kLzmaStreamWasFinishedId)
+    return LZMA_RESULT_OK;
+
+  if (dictionarySize == 0)
+  {
+    dictionary = tempDictionary;
+    dictionarySize = 1;
+    tempDictionary[0] = vs->TempDictionary[0];
+  }
+
+  if (len == kLzmaNeedInitId)
+  {
+    {
+      UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp));
+      UInt32 i;
+      for (i = 0; i < numProbs; i++)
+        p[i] = kBitModelTotal >> 1; 
+      rep0 = rep1 = rep2 = rep3 = 1;
+      state = 0;
+      globalPos = 0;
+      distanceLimit = 0;
+      dictionaryPos = 0;
+      dictionary[dictionarySize - 1] = 0;
+      #ifdef _LZMA_IN_CB
+      RC_INIT;
+      #else
+      RC_INIT(inStream, inSize);
+      #endif
+    }
+    len = 0;
+  }
+  while(len != 0 && nowPos < outSize)
+  {
+    UInt32 pos = dictionaryPos - rep0;
+    if (pos >= dictionarySize)
+      pos += dictionarySize;
+    outStream[nowPos++] = dictionary[dictionaryPos] = dictionary[pos];
+    if (++dictionaryPos == dictionarySize)
+      dictionaryPos = 0;
+    len--;
+  }
+  if (dictionaryPos == 0)
+    previousByte = dictionary[dictionarySize - 1];
+  else
+    previousByte = dictionary[dictionaryPos - 1];
+
+  #else /* if !_LZMA_OUT_READ */
+
+  int state = 0;
+  UInt32 rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1;
+  int len = 0;
+  const Byte *Buffer;
+  const Byte *BufferLim;
+  UInt32 Range;
+  UInt32 Code;
+
+  #ifndef _LZMA_IN_CB
+  *inSizeProcessed = 0;
+  #endif
+  *outSizeProcessed = 0;
+
+  {
+    UInt32 i;
+    UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp));
+    for (i = 0; i < numProbs; i++)
+      p[i] = kBitModelTotal >> 1;
+  }
+  
+  #ifdef _LZMA_IN_CB
+  RC_INIT;
+  #else
+  RC_INIT(inStream, inSize);
+  #endif
+
+  #endif /* _LZMA_OUT_READ */
+
+  while(nowPos < outSize)
+  {
+    CProb *prob;
+    UInt32 bound;
+    int posState = (int)(
+        (nowPos 
+        #ifdef _LZMA_OUT_READ
+        + globalPos
+        #endif
+        )
+        & posStateMask);
+
+    prob = p + IsMatch + (state << kNumPosBitsMax) + posState;
+    IfBit0(prob)
+    {
+      int symbol = 1;
+      UpdateBit0(prob)
+      prob = p + Literal + (LZMA_LIT_SIZE * 
+        (((
+        (nowPos 
+        #ifdef _LZMA_OUT_READ
+        + globalPos
+        #endif
+        )
+        & literalPosMask) << lc) + (previousByte >> (8 - lc))));
+
+      if (state >= kNumLitStates)
+      {
+        int matchByte;
+        #ifdef _LZMA_OUT_READ
+        UInt32 pos = dictionaryPos - rep0;
+        if (pos >= dictionarySize)
+          pos += dictionarySize;
+        matchByte = dictionary[pos];
+        #else
+        matchByte = outStream[nowPos - rep0];
+        #endif
+        do
+        {
+          int bit;
+          CProb *probLit;
+          matchByte <<= 1;
+          bit = (matchByte & 0x100);
+          probLit = prob + 0x100 + bit + symbol;
+          RC_GET_BIT2(probLit, symbol, if (bit != 0) break, if (bit == 0) break)
+        }
+        while (symbol < 0x100);
+      }
+      while (symbol < 0x100)
+      {
+        CProb *probLit = prob + symbol;
+        RC_GET_BIT(probLit, symbol)
+      }
+      previousByte = (Byte)symbol;
+
+      outStream[nowPos++] = previousByte;
+      #ifdef _LZMA_OUT_READ
+      if (distanceLimit < dictionarySize)
+        distanceLimit++;
+
+      dictionary[dictionaryPos] = previousByte;
+      if (++dictionaryPos == dictionarySize)
+        dictionaryPos = 0;
+      #endif
+      if (state < 4) state = 0;
+      else if (state < 10) state -= 3;
+      else state -= 6;
+    }
+    else             
+    {
+      UpdateBit1(prob);
+      prob = p + IsRep + state;
+      IfBit0(prob)
+      {
+        UpdateBit0(prob);
+        rep3 = rep2;
+        rep2 = rep1;
+        rep1 = rep0;
+        state = state < kNumLitStates ? 0 : 3;
+        prob = p + LenCoder;
+      }
+      else
+      {
+        UpdateBit1(prob);
+        prob = p + IsRepG0 + state;
+        IfBit0(prob)
+        {
+          UpdateBit0(prob);
+          prob = p + IsRep0Long + (state << kNumPosBitsMax) + posState;
+          IfBit0(prob)
+          {
+            #ifdef _LZMA_OUT_READ
+            UInt32 pos;
+            #endif
+            UpdateBit0(prob);
+            
+            #ifdef _LZMA_OUT_READ
+            if (distanceLimit == 0)
+            #else
+            if (nowPos == 0)
+            #endif
+              return LZMA_RESULT_DATA_ERROR;
+            
+            state = state < kNumLitStates ? 9 : 11;
+            #ifdef _LZMA_OUT_READ
+            pos = dictionaryPos - rep0;
+            if (pos >= dictionarySize)
+              pos += dictionarySize;
+            previousByte = dictionary[pos];
+            dictionary[dictionaryPos] = previousByte;
+            if (++dictionaryPos == dictionarySize)
+              dictionaryPos = 0;
+            #else
+            previousByte = outStream[nowPos - rep0];
+            #endif
+            outStream[nowPos++] = previousByte;
+            #ifdef _LZMA_OUT_READ
+            if (distanceLimit < dictionarySize)
+              distanceLimit++;
+            #endif
+
+            continue;
+          }
+          else
+          {
+            UpdateBit1(prob);
+          }
+        }
+        else
+        {
+          UInt32 distance;
+          UpdateBit1(prob);
+          prob = p + IsRepG1 + state;
+          IfBit0(prob)
+          {
+            UpdateBit0(prob);
+            distance = rep1;
+          }
+          else 
+          {
+            UpdateBit1(prob);
+            prob = p + IsRepG2 + state;
+            IfBit0(prob)
+            {
+              UpdateBit0(prob);
+              distance = rep2;
+            }
+            else
+            {
+              UpdateBit1(prob);
+              distance = rep3;
+              rep3 = rep2;
+            }
+            rep2 = rep1;
+          }
+          rep1 = rep0;
+          rep0 = distance;
+        }
+        state = state < kNumLitStates ? 8 : 11;
+        prob = p + RepLenCoder;
+      }
+      {
+        int numBits, offset;
+        CProb *probLen = prob + LenChoice;
+        IfBit0(probLen)
+        {
+          UpdateBit0(probLen);
+          probLen = prob + LenLow + (posState << kLenNumLowBits);
+          offset = 0;
+          numBits = kLenNumLowBits;
+        }
+        else
+        {
+          UpdateBit1(probLen);
+          probLen = prob + LenChoice2;
+          IfBit0(probLen)
+          {
+            UpdateBit0(probLen);
+            probLen = prob + LenMid + (posState << kLenNumMidBits);
+            offset = kLenNumLowSymbols;
+            numBits = kLenNumMidBits;
+          }
+          else
+          {
+            UpdateBit1(probLen);
+            probLen = prob + LenHigh;
+            offset = kLenNumLowSymbols + kLenNumMidSymbols;
+            numBits = kLenNumHighBits;
+          }
+        }
+        RangeDecoderBitTreeDecode(probLen, numBits, len);
+        len += offset;
+      }
+
+      if (state < 4)
+      {
+        int posSlot;
+        state += kNumLitStates;
+        prob = p + PosSlot +
+            ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << 
+            kNumPosSlotBits);
+        RangeDecoderBitTreeDecode(prob, kNumPosSlotBits, posSlot);
+        if (posSlot >= kStartPosModelIndex)
+        {
+          int numDirectBits = ((posSlot >> 1) - 1);
+          rep0 = (2 | ((UInt32)posSlot & 1));
+          if (posSlot < kEndPosModelIndex)
+          {
+            rep0 <<= numDirectBits;
+            prob = p + SpecPos + rep0 - posSlot - 1;
+          }
+          else
+          {
+            numDirectBits -= kNumAlignBits;
+            do
+            {
+              RC_NORMALIZE
+              Range >>= 1;
+              rep0 <<= 1;
+              if (Code >= Range)
+              {
+                Code -= Range;
+                rep0 |= 1;
+              }
+            }
+            while (--numDirectBits != 0);
+            prob = p + Align;
+            rep0 <<= kNumAlignBits;
+            numDirectBits = kNumAlignBits;
+          }
+          {
+            int i = 1;
+            int mi = 1;
+            do
+            {
+              CProb *prob3 = prob + mi;
+              RC_GET_BIT2(prob3, mi, ; , rep0 |= i);
+              i <<= 1;
+            }
+            while(--numDirectBits != 0);
+          }
+        }
+        else
+          rep0 = posSlot;
+        if (++rep0 == (UInt32)(0))
+        {
+          /* it's for stream version */
+          len = kLzmaStreamWasFinishedId;
+          break;
+        }
+      }
+
+      len += kMatchMinLen;
+      #ifdef _LZMA_OUT_READ
+      if (rep0 > distanceLimit) 
+      #else
+      if (rep0 > nowPos)
+      #endif
+        return LZMA_RESULT_DATA_ERROR;
+
+      #ifdef _LZMA_OUT_READ
+      if (dictionarySize - distanceLimit > (UInt32)len)
+        distanceLimit += len;
+      else
+        distanceLimit = dictionarySize;
+      #endif
+
+      do
+      {
+        #ifdef _LZMA_OUT_READ
+        UInt32 pos = dictionaryPos - rep0;
+        if (pos >= dictionarySize)
+          pos += dictionarySize;
+        previousByte = dictionary[pos];
+        dictionary[dictionaryPos] = previousByte;
+        if (++dictionaryPos == dictionarySize)
+          dictionaryPos = 0;
+        #else
+        previousByte = outStream[nowPos - rep0];
+        #endif
+        len--;
+        outStream[nowPos++] = previousByte;
+      }
+      while(len != 0 && nowPos < outSize);
+    }
+  }
+  RC_NORMALIZE;
+
+  #ifdef _LZMA_OUT_READ
+  vs->Range = Range;
+  vs->Code = Code;
+  vs->DictionaryPos = dictionaryPos;
+  vs->GlobalPos = globalPos + (UInt32)nowPos;
+  vs->DistanceLimit = distanceLimit;
+  vs->Reps[0] = rep0;
+  vs->Reps[1] = rep1;
+  vs->Reps[2] = rep2;
+  vs->Reps[3] = rep3;
+  vs->State = state;
+  vs->RemainLen = len;
+  vs->TempDictionary[0] = tempDictionary[0];
+  #endif
+
+  #ifdef _LZMA_IN_CB
+  vs->Buffer = Buffer;
+  vs->BufferLim = BufferLim;
+  #else
+  *inSizeProcessed = (SizeT)(Buffer - inStream);
+  #endif
+  *outSizeProcessed = nowPos;
+  return LZMA_RESULT_OK;
+}
--- /dev/null	2011-06-03 14:51:38.633053002 +0200
+++ linux-2.6.20.14-fbx/lib/LzmaDecode.h	2011-09-26 15:07:56.538834079 +0200
@@ -0,0 +1,113 @@
+/* 
+  LzmaDecode.h
+  LZMA Decoder interface
+
+  LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01)
+  http://www.7-zip.org/
+
+  LZMA SDK is licensed under two licenses:
+  1) GNU Lesser General Public License (GNU LGPL)
+  2) Common Public License (CPL)
+  It means that you can select one of these two licenses and 
+  follow rules of that license.
+
+  SPECIAL EXCEPTION:
+  Igor Pavlov, as the author of this code, expressly permits you to 
+  statically or dynamically link your code (or bind by name) to the 
+  interfaces of this file without subjecting your linked code to the 
+  terms of the CPL or GNU LGPL. Any modifications or additions 
+  to this file, however, are subject to the LGPL or CPL terms.
+*/
+
+#ifndef __LZMADECODE_H
+#define __LZMADECODE_H
+
+#include "linux/LzmaTypes.h"
+
+/* #define _LZMA_IN_CB */
+/* Use callback for input data */
+
+/* #define _LZMA_OUT_READ */
+/* Use read function for output data */
+
+/* #define _LZMA_PROB32 */
+/* It can increase speed on some 32-bit CPUs, 
+   but memory usage will be doubled in that case */
+
+/* #define _LZMA_LOC_OPT */
+/* Enable local speed optimizations inside code */
+
+#ifdef _LZMA_PROB32
+#define CProb UInt32
+#else
+#define CProb UInt16
+#endif
+
+#define LZMA_RESULT_OK 0
+#define LZMA_RESULT_DATA_ERROR 1
+
+#ifdef _LZMA_IN_CB
+typedef struct _ILzmaInCallback
+{
+  int (*Read)(void *object, const unsigned char **buffer, SizeT *bufferSize);
+} ILzmaInCallback;
+#endif
+
+#define LZMA_BASE_SIZE 1846
+#define LZMA_LIT_SIZE 768
+
+#define LZMA_PROPERTIES_SIZE 5
+
+typedef struct _CLzmaProperties
+{
+  int lc;
+  int lp;
+  int pb;
+  #ifdef _LZMA_OUT_READ
+  UInt32 DictionarySize;
+  #endif
+}CLzmaProperties;
+
+int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size);
+
+#define LzmaGetNumProbs(Properties) (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((Properties)->lc + (Properties)->lp)))
+
+#define kLzmaNeedInitId (-2)
+
+typedef struct _CLzmaDecoderState
+{
+  CLzmaProperties Properties;
+  CProb *Probs;
+
+  #ifdef _LZMA_IN_CB
+  const unsigned char *Buffer;
+  const unsigned char *BufferLim;
+  #endif
+
+  #ifdef _LZMA_OUT_READ
+  unsigned char *Dictionary;
+  UInt32 Range;
+  UInt32 Code;
+  UInt32 DictionaryPos;
+  UInt32 GlobalPos;
+  UInt32 DistanceLimit;
+  UInt32 Reps[4];
+  int State;
+  int RemainLen;
+  unsigned char TempDictionary[4];
+  #endif
+} CLzmaDecoderState;
+
+#ifdef _LZMA_OUT_READ
+#define LzmaDecoderInit(vs) { (vs)->RemainLen = kLzmaNeedInitId; }
+#endif
+
+int LzmaDecode(CLzmaDecoderState *vs,
+    #ifdef _LZMA_IN_CB
+    ILzmaInCallback *inCallback,
+    #else
+    const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed,
+    #endif
+    unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed);
+
+#endif
--- /dev/null	2011-06-03 14:51:38.633053002 +0200
+++ linux-2.6.20.14-fbx/lib/sqlzma-uncomp.c	2011-09-26 15:07:56.538834079 +0200
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2006, 2007 Junjiro Okajima
+ * Copyright (C) 2006, 2007 Tomas Matejicek, slax.org
+ *
+ * LICENSE follows the described one in lzma.txt.
+ */
+
+/* $Id: uncomp.c,v 1.29 2007/01/08 05:12:50 jro Exp $ */
+
+/* extract some parts from lzma443/C/7zip/Compress/LZMA_C/LzmaTest.c */
+
+#ifndef __KERNEL__
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <pthread.h>
+#define unlikely(x)		__builtin_expect(!!(x), 0)
+#define BUG_ON(x)		assert(!(x))
+/* sqlzma buffers are always larger than a page. true? */
+#define kmalloc(sz,gfp)		malloc(sz)
+#define kfree(p)		free(p)
+#define zlib_inflate(s, f)	inflate(s, f)
+#define zlib_inflateInit(s)	inflateInit(s)
+#define zlib_inflateReset(s)	inflateReset(s)
+#define zlib_inflateEnd(s)	inflateEnd(s)
+#else
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/vmalloc.h>
+#ifndef WARN_ON_ONCE
+#define WARN_ON_ONCE(b)	WARN_ON(b)
+#endif
+#endif /* __KERNEL__ */
+
+#include "linux/sqlzma.h"
+#include "linux/LzmaDecode.h"
+
+static int LzmaUncompress(struct sqlzma_un *un)
+{
+	int err, i, ret;
+	size_t outSize, inProcessed, outProcessed, srclen;
+	/* it's about 24-80 bytes structure, if int is 32-bit */
+	CLzmaDecoderState state;
+	unsigned char *dst, *src, a[8];
+	struct sized_buf *sbuf;
+
+	/* Decode LZMA properties and allocate memory */
+	err = -EINVAL;
+	src = un->un_cmbuf;
+	ret = LzmaDecodeProperties(&state.Properties, src, LZMA_PROPERTIES_SIZE);
+	src += LZMA_PROPERTIES_SIZE;
+	if (unlikely(ret != LZMA_RESULT_OK))
+		goto out;
+	i = LzmaGetNumProbs(&state.Properties);
+	if (unlikely(i <= 0))
+		i = 1;
+	i *= sizeof(CProb);
+	sbuf = un->un_a + SQUN_PROB;
+	if (unlikely(sbuf->sz < i)) {
+		if (sbuf->buf && sbuf->buf != un->un_prob)
+			kfree(sbuf->buf);
+#ifdef __KERNEL__
+		printk("%s:%d: %d --> %d\n", __func__, __LINE__, sbuf->sz, i);
+#else
+		printf("%d --> %d\n", sbuf->sz, i);
+#endif
+		err = -ENOMEM;
+		sbuf->sz = 0;
+		sbuf->buf = kmalloc(i, GFP_ATOMIC);
+		if (unlikely(!sbuf->buf))
+			goto out;
+		sbuf->sz = i;
+	}
+	state.Probs = (void*)sbuf->buf;
+
+	/* Read uncompressed size */
+	memcpy(a, src, sizeof(a));
+	src += sizeof(a);
+	outSize = a[0] | (a[1] << 8) | (a[2] << 16) | (a[3] << 24);
+
+	err = -EINVAL;
+	dst = un->un_resbuf;
+	if (unlikely(!dst || outSize > un->un_reslen))
+		goto out;
+	un->un_reslen = outSize;
+	srclen = un->un_cmlen - (src - un->un_cmbuf);
+
+	/* Decompress */
+	err = LzmaDecode(&state, src, srclen, &inProcessed, dst, outSize,
+			 &outProcessed);
+	if (err)
+		err = -EINVAL;
+
+ out:
+#ifndef __KERNEL__
+	if (err)
+		fprintf(stderr, "err %d\n", err);
+#endif
+	return err;
+}
+
+int sqlzma_un(struct sqlzma_un *un, struct sized_buf *src,
+	      struct sized_buf *dst)
+{
+	int err, by_lzma = 0;
+	if (un->un_lzma && is_lzma(*src->buf)) {
+		by_lzma = 1;
+		un->un_cmbuf = src->buf;
+		un->un_cmlen = src->sz;
+		un->un_resbuf = dst->buf;
+		un->un_reslen = dst->sz;
+
+		/* this library is thread-safe */
+		err = LzmaUncompress(un);
+		goto out;
+	}
+
+	err = zlib_inflateReset(&un->un_stream);
+	if (unlikely(err != Z_OK))
+		goto out;
+	un->un_stream.next_in = src->buf;
+	un->un_stream.avail_in = src->sz;
+	un->un_stream.next_out = dst->buf;
+	un->un_stream.avail_out = dst->sz;
+	err = zlib_inflate(&un->un_stream, Z_FINISH);
+	if (err == Z_STREAM_END)
+		err = 0;
+
+ out:
+	if (err) {
+#ifdef __KERNEL__
+		WARN_ON_ONCE(1);
+#else
+		char a[64] = "ZLIB ";
+		if (by_lzma) {
+			strcpy(a, "LZMA ");
+#ifdef _REENTRANT
+			strerror_r(err, a + 5, sizeof(a) - 5);
+#else
+			strncat(a, strerror(err), sizeof(a) - 5);
+#endif
+		} else
+			strncat(a, zError(err), sizeof(a) - 5);
+		fprintf(stderr, "%s: %.*s\n", __func__, sizeof(a), a);
+#endif
+	}
+	return err;
+}
+
+int sqlzma_init(struct sqlzma_un *un, int do_lzma, unsigned int res_sz)
+{
+	int err;
+
+	err = -ENOMEM;
+	un->un_lzma = do_lzma;
+	memset(un->un_a, 0, sizeof(un->un_a));
+	un->un_a[SQUN_PROB].buf = un->un_prob;
+	un->un_a[SQUN_PROB].sz = sizeof(un->un_prob);
+	if (res_sz) {
+		un->un_a[SQUN_RESULT].buf = kmalloc(res_sz, GFP_KERNEL);
+		if (unlikely(!un->un_a[SQUN_RESULT].buf))
+			return err;
+		un->un_a[SQUN_RESULT].sz = res_sz;
+	}
+
+	un->un_stream.next_in = NULL;
+	un->un_stream.avail_in = 0;
+#ifdef __KERNEL__
+	un->un_stream.workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL);
+	if (unlikely(!un->un_stream.workspace))
+		return err;
+#else
+	un->un_stream.opaque = NULL;
+	un->un_stream.zalloc = Z_NULL;
+	un->un_stream.zfree = Z_NULL;
+#endif
+	err = zlib_inflateInit(&un->un_stream);
+	if (unlikely(err == Z_MEM_ERROR))
+		return -ENOMEM;
+	BUG_ON(err);
+	return err;
+}
+
+void sqlzma_fin(struct sqlzma_un *un)
+{
+	int i;
+	for (i = 0; i < SQUN_LAST; i++)
+		if (un->un_a[i].buf && un->un_a[i].buf != un->un_prob)
+			kfree(un->un_a[i].buf);
+	BUG_ON(zlib_inflateEnd(&un->un_stream) != Z_OK);
+}
+
+#ifdef __KERNEL__
+EXPORT_SYMBOL(sqlzma_un);
+EXPORT_SYMBOL(sqlzma_init);
+EXPORT_SYMBOL(sqlzma_fin);
+
+#if 0
+static int __init sqlzma_init(void)
+{
+	return 0;
+}
+
+static void __exit sqlzma_exit(void)
+{
+}
+
+module_init(sqlzma_init);
+module_exit(sqlzma_exit);
+#endif
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Junjiro Okajima <hooanon05 at yahoo dot co dot jp>");
+MODULE_VERSION("$Id: uncomp.c,v 1.29 2007/01/08 05:12:50 jro Exp $");
+MODULE_DESCRIPTION("LZMA uncompress for squashfs. "
+		   "Some functions for squashfs to support LZMA and "
+		   "a tiny wrapper for LzmaDecode.c in LZMA SDK from www.7-zip.org.");
+#endif
diff -Nruw linux-2.6.20.14-fbx/net/fbxatm./Kconfig linux-2.6.20.14-fbx/net/fbxatm/Kconfig
--- linux-2.6.20.14-fbx/net/fbxatm./Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/net/fbxatm/Kconfig	2011-09-26 15:07:56.588834049 +0200
@@ -0,0 +1,2 @@
+config FBXATM
+	tristate "Freebox Asynchronous Transfer Mode (ATM)"
diff -Nruw linux-2.6.20.14-fbx/net/fbxatm./Makefile linux-2.6.20.14-fbx/net/fbxatm/Makefile
--- linux-2.6.20.14-fbx/net/fbxatm./Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.14-fbx/net/fbxatm/Makefile	2011-09-26 15:07:56.588834049 +0200
@@ -0,0 +1,10 @@
+obj-$(CONFIG_FBXATM) += fbxatm.o
+
+fbxatm-y := 	fbxatm_core.o	\
+		fbxatm_2684.o	\
+		fbxatm_dev.o	\
+		fbxatm_procfs.o	\
+		fbxatm_sysfs.o	\
+		crc10.o
+
+fbxatm-$(CONFIG_PPP) += fbxatm_pppoa.o
--- /dev/null	2011-06-03 14:51:38.633053002 +0200
+++ linux-2.6.20.14-fbx/net/ipv4/netfilter/iptable_tproxy.c	2011-09-26 15:07:56.618834031 +0200
@@ -0,0 +1,1860 @@
+/*
+ * Transparent proxy support for Linux/iptables
+ *
+ * Copyright (c) 2002-2004 BalaBit IT Ltd.
+ * Author: Balázs Scheidler, Krisztián Kovács
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+
+#include <linux/sysctl.h>
+#include <linux/vmalloc.h>
+#include <linux/net.h>
+#include <linux/slab.h>
+#include <linux/if.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/netdevice.h>
+#include <linux/time.h>
+#include <net/tcp.h>
+#include <net/udp.h>
+#include <net/sock.h>
+#include <asm/uaccess.h>
+#include <net/inet_timewait_sock.h>
+
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_TPROXY.h>
+#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter_ipv4/ip_nat.h>
+#include <linux/netfilter_ipv4/ip_nat_core.h>
+
+#include <linux/netfilter_ipv4/ip_tproxy.h>
+#include <linux/netfilter_ipv4/iptable_tproxy.h>
+
+#define ASSERT_READ_LOCK(x)
+#define ASSERT_WRITE_LOCK(x)
+DEFINE_RWLOCK(ip_tproxy_lock);
+
+#define TPROXY_VALID_HOOKS ((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT))
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(args...)
+#endif
+
+#define TPROXY_MAJOR_VERSION 2
+#define TPROXY_MINOR_VERSION 0
+#define TPROXY_PATCH_VERSION 6
+
+#define TPROXY_FULL_VERSION ((TPROXY_MAJOR_VERSION << 24) | \
+			     (TPROXY_MINOR_VERSION << 16) | \
+			     TPROXY_PATCH_VERSION)
+
+#define MAJOR_VERSION(x) ((x >> 24) & 0xff)
+#define MINOR_VERSION(x) ((x >> 16) & 0xff)
+#define PATCH_VERSION(x) (x & 0xffff)
+
+/* simple and buggy, but enough for us */
+#define MIN(a,b) ((a < b) ? a : b)
+
+static struct
+{
+	struct ipt_replace repl;
+	struct ipt_standard entries[2];
+	struct ipt_error term;
+} initial_table
+= { { "tproxy", TPROXY_VALID_HOOKS, 3,
+      sizeof(struct ipt_standard) * 2 + sizeof(struct ipt_error),
+      { [NF_IP_PRE_ROUTING] 0,
+	[NF_IP_LOCAL_OUT] sizeof(struct ipt_standard) },
+      { [NF_IP_PRE_ROUTING] 0,
+	[NF_IP_LOCAL_OUT] sizeof(struct ipt_standard) },
+      0, NULL, { } },
+    {
+	    /* PRE_ROUTING */
+	    { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+		0,
+		sizeof(struct ipt_entry),
+		sizeof(struct ipt_standard),
+		0, { 0, 0 }, { } },
+	      { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
+		-NF_ACCEPT - 1 } },
+	    /* LOCAL_OUT */
+	    { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+		0,
+		sizeof(struct ipt_entry),
+		sizeof(struct ipt_standard),
+		0, { 0, 0 }, { } },
+	      { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
+		-NF_ACCEPT - 1 } }
+    },
+    /* ERROR */
+    { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+	0,
+	sizeof(struct ipt_entry),
+	sizeof(struct ipt_error),
+	0, { 0, 0 }, { } },
+      { { { { IPT_ALIGN(sizeof(struct ipt_error_target)), IPT_ERROR_TARGET } },
+	  { } },
+	"ERROR"
+      }
+    }
+};
+
+static struct ipt_table tproxy_table = {
+	.name		= "tproxy",
+	.valid_hooks	= TPROXY_VALID_HOOKS,
+	.lock		= RW_LOCK_UNLOCKED,
+	.me		= THIS_MODULE,
+	.af		= AF_INET,
+};
+
+static void (*ip_conntrack_destroyed_old)(struct ip_conntrack *ct) = NULL;
+
+/* NAT entry setup flags */
+#define TN_BIDIR	1
+#define TN_STOREREF	2
+
+/* user settable flags */
+#define TF_NAT_ONCE	  0x00000001 /* this entry is applied only once */
+#define TF_LISTEN	  0x00000002 /* this entry is meant for listening */
+#define TF_CONNECT	  0x00000004 /* this entry is meant for connecting */
+#define TF_UNIDIR	  0x00000008 /* this entry is a listening UDP socket,
+					and only an unidirectional nat is to be applied */
+
+/* state flags */
+#define TF_HASHED	  0x00010000 /* entry hashed in hashtable */
+#define TF_CONNECT_ONLY	  0x00020000 /* conflicting foreign address */
+#define TF_MARK_ONLY	  0x00040000 /* have packets in this session mark as tproxy but don't apply translation */
+#define TF_NAT_APPLIED	  0x00080000 /* NAT already applied, ignore this entry during NAT search */
+#define TF_ORPHAN	  0x00100000 /* Parent (listening) socket was closed */
+
+#ifdef CONFIG_IP_NF_NAT_NRES
+#define TF_NAT_RESERVED	  0x00200000 /* a NAT reservation was allocated for the sockref's foreign address */
+#define TF_NAT_PEER	  0x00400000 /* raddr was also specified at NAT reservation */
+#endif
+
+#define TF_STATE_MASK	  0xffff0000
+
+static int hashsize = 0;
+module_param(hashsize, uint, 0600);
+
+int ip_tproxy_htable_size = 127;
+struct list_head *ip_tproxy_bylocal;
+struct list_head *ip_tproxy_byforeign;
+kmem_cache_t *ip_tproxy_sockref_table;
+int ip_tproxy_htable_count = 0;
+struct ip_conntrack ip_tproxy_fake_ct;
+
+static u32
+ip_tproxy_hash_fn(u32 addr, u16 port, u8 proto)
+{
+	return ntohl(addr + (port<<8) + proto) % ip_tproxy_htable_size;
+}
+
+/* allocate memory and initialize a sockref structure */
+static struct ip_tproxy_sockref *
+ip_tproxy_sockref_new(void)
+{
+	struct ip_tproxy_sockref *sr;
+
+	sr = kmem_cache_zalloc(ip_tproxy_sockref_table, GFP_ATOMIC);
+	if (!sr)
+		return NULL;
+
+	atomic_set(&sr->references, 1);
+	sr->bylocal.sockref = sr;
+	sr->byforeign.sockref = sr;
+	sr->relatedlock = SPIN_LOCK_UNLOCKED;
+	INIT_LIST_HEAD(&sr->relatedct);
+	atomic_set(&sr->socket_count, 1);
+
+	return sr;
+}
+
+/* increase reference count for a sockref entry */
+static inline void
+ip_tproxy_sockref_ref(struct ip_tproxy_sockref *sr)
+{
+	atomic_inc(&sr->references);
+}
+
+/* decrease refcount for the entry, and free the structure if needed */
+static inline void
+ip_tproxy_sockref_unref(struct ip_tproxy_sockref *sr)
+{
+	if (atomic_dec_and_test(&sr->references)) {
+		kmem_cache_free(ip_tproxy_sockref_table, sr);
+	}
+}
+
+/* put a sockref entry in the hash tables */
+static void
+ip_tproxy_hash(struct ip_tproxy_sockref *sr)
+{
+	u32 fhash = ip_tproxy_hash_fn(sr->faddr, sr->fport, sr->proto);
+	u32 lhash = ip_tproxy_hash_fn(sr->laddr, sr->lport, sr->proto);
+
+	sr->flags |= TF_HASHED;
+	sr->tv_hashed = xtime;
+
+	DEBUGP(KERN_DEBUG "IP_TPROXY: ip_tproxy_hash(): hashing sockref, "
+	       "lhash=%d, fhash=%d, %p, %02x, %08x:%04x -> %08x:%04x\n",
+	       lhash, fhash, sr, sr->proto, sr->laddr,
+	       sr->lport, sr->faddr, sr->fport);
+
+	ip_tproxy_sockref_ref(sr);
+
+	list_add_tail(&sr->bylocal.list, &ip_tproxy_bylocal[lhash]);
+	list_add_tail(&sr->byforeign.list, &ip_tproxy_byforeign[fhash]);
+	ip_tproxy_htable_count++;
+}
+
+/* delete sockref from the hash tables */
+static void
+ip_tproxy_unhash(struct ip_tproxy_sockref *sr)
+{
+	DEBUGP(KERN_DEBUG "IP_TPROXY: ip_tproxy_hash(): unhashing sockref, "
+	       "%p, %02x, %08x:%04x -> %08x:%04x\n",
+	       sr, sr->proto, sr->laddr, sr->lport, sr->faddr, sr->fport);
+
+	if (sr->flags & TF_HASHED) {
+		list_del(&sr->bylocal.list);
+		list_del(&sr->byforeign.list);
+		sr->flags &= ~TF_HASHED;
+		ip_tproxy_sockref_unref(sr);
+		ip_tproxy_htable_count--;
+	}
+	else {
+		printk(KERN_WARNING "IP_TPROXY: unhashing a sockref which was "
+		       "not hashed before, %p, flags=%x\n",
+		       sr, sr->flags);
+	}
+}
+
+/* change the fport of the sockref to the specified value, and modify foreign hash
+ * accordingly (used when not specifying an exact foreign port, and NAT allocates a
+ * free port number for the sockref) */
+static void
+ip_tproxy_rehash_fport(struct ip_tproxy_sockref *sr, u16 fport)
+{
+	u32 fhash = ip_tproxy_hash_fn(sr->faddr, fport, sr->proto);
+
+	DEBUGP(KERN_DEBUG "IP_TPROXY: ip_tproxy_rehash_fport(): rehashing sockref, "
+	       "%p, %02x, %08x:%04x -> %08x:%04x, new fport %04x\n",
+	       sr, sr->proto, sr->laddr, sr->lport,
+	       sr->faddr, sr->fport, fport);
+
+	if (sr->flags & TF_HASHED) {
+		list_del(&sr->byforeign.list);
+		sr->fport = fport;
+		list_add_tail(&sr->byforeign.list, &ip_tproxy_byforeign[fhash]);
+	}
+}
+
+/* add a conntrack entry to the related list of the sockref */
+static void
+ip_tproxy_relatedct_add(struct ip_tproxy_sockref *sr, struct ip_conntrack *ct)
+{
+#ifdef IP_TPROXY_DEBUG
+	struct ip_conntrack *p;
+#endif
+
+	if (test_and_set_bit(IPS_TPROXY_RELATED_BIT, &ct->status)) {
+		/* this conntrack is already related to another sockref! */
+		return;
+	}
+
+	spin_lock_bh(&sr->relatedlock);
+
+#ifdef IP_TPROXY_DEBUG
+	/* check if it's already in the list */
+	list_for_each_entry(p, &sr->relatedct, tproxy.related) {
+		if (ct == p)
+			goto out;
+	}
+#endif
+
+	/* each related conntrack adds one to the reference count of the sockref */
+	ip_tproxy_sockref_ref(sr);
+	atomic_inc(&sr->related);
+	/* since we store a pointer to the conntrack, we should get a reference */
+	atomic_inc(&ct->ct_general.use);
+	list_add(&ct->tproxy.related, &sr->relatedct);
+
+#ifdef IP_TPROXY_DEBUG
+out:
+#endif
+	spin_unlock_bh(&sr->relatedlock);
+}
+
+/* called by conntrack when a connection is confirmed */
+static void
+ip_tproxy_confirmed(struct ip_conntrack *ct)
+{
+	struct ip_tproxy_sockref *sr = (struct ip_tproxy_sockref *)ct->tproxy.sockref;
+
+	/* check if it was marked by tproxy and not yet a related sockref */
+	if (test_bit(IPS_TPROXY_BIT, &ct->status) &&
+	    !test_bit(IPS_TPROXY_RELATED_BIT, &ct->status) &&
+	    sr) {
+		ct->tproxy.sockref = NULL;
+
+		/* put it on the sockref's related list */
+		if (sr->proto == IPPROTO_UDP)
+			ip_tproxy_relatedct_add(sr, ct);
+
+		/* drop reference to sockref */
+		ip_tproxy_sockref_unref(sr);
+	}
+}
+
+/* called by conntrack when a connection is destroyed */
+static void
+ip_tproxy_conntrack_destroyed(struct ip_conntrack *ct)
+{
+	/* check if it's not confirmed, but marked by tproxy */
+	if (!is_confirmed(ct) &&
+	    !test_bit(IPS_TPROXY_RELATED_BIT, &ct->status) &&
+	    test_and_clear_bit(IPS_TPROXY_BIT, &ct->status) &&
+	    ct->tproxy.sockref != NULL) {
+		/* drop reference */
+		ip_tproxy_sockref_unref((struct ip_tproxy_sockref *)ct->tproxy.sockref);
+		ct->tproxy.sockref = NULL;
+	}
+
+	if (ip_conntrack_destroyed_old)
+		ip_conntrack_destroyed_old(ct);
+}
+
+static int
+sockref_listen_cmp(const struct ip_tproxy_sockref *sr, const u32 raddr, const u16 rport,
+		   const struct ip_conntrack *ct)
+{
+	return (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip == sr->faddr) &&
+	       (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.all == sr->fport) &&
+	       (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum == sr->proto) &&
+	       ((raddr == 0) || (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip == raddr)) &&
+	       ((rport == 0) || (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.all == rport));
+}
+
+/* delete matching related connections from the sockref's list and delete them from
+ * the conntrack hash if requested */
+static void
+ip_tproxy_kill_related(struct ip_tproxy_sockref *sr, u32 raddr, u16 rport,
+		       int cmpfn(const struct ip_tproxy_sockref *, const u32 raddr,
+				 const u16 rport, const struct ip_conntrack *),
+		       int delete)
+{
+	struct ip_conntrack *ct, *p;
+
+	spin_lock_bh(&sr->relatedlock);
+
+	list_for_each_entry_safe(ct, p, &sr->relatedct, tproxy.related) {
+		/* if a compare function was given, don't delete unmatched entries */
+		if (cmpfn && !cmpfn(sr, raddr, rport, ct))
+			continue;
+
+		/* delete the conntrack entry from our related list, update related counter */
+		list_del(&ct->tproxy.related);
+		atomic_dec(&sr->related);
+
+#ifdef CONFIG_NETFILTER_DEBUG
+		/* clear IPS_TPROXY_RELATED flag from the conntrack */
+		if (!test_and_clear_bit(IPS_TPROXY_RELATED_BIT, &ct->status)) {
+			/* this is a bug: IPS_TPROXY_RELATED is not set for a conntrack? */
+			printk(KERN_WARNING "IP_TPROXY: IPS_TPROXY_RELATED not set "
+			       "for a related conntrack\n");
+		}
+#endif
+
+		/* should we delete the entry from the conntrack hash? */
+		if (delete && del_timer(&ct->timeout))
+			ct->timeout.function((unsigned long)ct);
+
+		/* unreference conntrack and sockref */
+		ip_conntrack_put(ct);
+		ip_tproxy_sockref_unref(sr);
+	}
+
+	spin_unlock_bh(&sr->relatedlock);
+}
+
+/* remove/kill related connections for the given sockref */
+static void
+ip_tproxy_kill_conntracks(struct ip_tproxy_sockref *sr,
+			  u32 raddr, u16 rport, int delete)
+{
+	if (sr->flags & TF_CONNECT) {
+		/* this is an established UDP "connection" or a CONNECT-ed
+		 * sockref, we delete all related connections from our list */
+		ip_tproxy_kill_related(sr, raddr, rport, NULL, delete);
+	} else if (sr->flags & TF_LISTEN) {
+		/* for listening sockrefs, we have to delete one specific
+		 * connection only, with both endpoints matching */
+		ip_tproxy_kill_related(sr, raddr, rport, sockref_listen_cmp, delete);
+	}
+}
+
+static void *ip_tproxy_seq_start(struct seq_file *seq, loff_t *pos)
+{
+	/* we use seq_file->private pointer as an int */
+	unsigned int *bucket = (unsigned int *)&seq->private;
+
+	read_lock_bh(&ip_tproxy_lock);
+
+	if (*pos >= ip_tproxy_htable_size)
+		return NULL;
+
+	*bucket = *pos;
+	return bucket;
+}
+
+static void *ip_tproxy_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	unsigned int *bucket = (unsigned int *)v;
+
+	*pos = ++(*bucket);
+	if (*pos > ip_tproxy_htable_size)
+		return NULL;
+
+	return bucket;
+}
+
+static void ip_tproxy_seq_stop(struct seq_file *seq, void *v)
+{
+	read_unlock_bh(&ip_tproxy_lock);
+}
+
+/* print information about a sockref, used by the procfs interface */
+static unsigned int
+ip_tproxy_print_sockref(const struct ip_tproxy_hash *h, struct seq_file *seq)
+{
+	struct ip_tproxy_sockref *sr = h->sockref;
+
+	IP_NF_ASSERT(sr);
+
+	return seq_printf(seq, "%05d %08x:%04x %08x:%04x %08x:%04x %08x %05u %06u %10ld:%06ld\n",
+			sr->proto, sr->faddr, sr->fport, sr->laddr,
+			sr->lport, sr->raddr, sr->rport, sr->flags,
+			atomic_read(&sr->related), atomic_read(&sr->socket_count),
+			sr->tv_hashed.tv_sec, sr->tv_hashed.tv_nsec) ? 1 : 0;
+}
+
+static int ip_tproxy_seq_show(struct seq_file *seq, void *v)
+{
+	unsigned int *bucket = (unsigned int *)v;
+	struct ip_tproxy_hash *h;
+
+	list_for_each_entry(h, &ip_tproxy_bylocal[*bucket], list)
+		if (ip_tproxy_print_sockref(h, seq))
+			return 1;
+
+	return 0;
+}
+
+static struct seq_operations ip_tproxy_seq_ops = {
+	.start = ip_tproxy_seq_start,
+	.next  = ip_tproxy_seq_next,
+	.stop  = ip_tproxy_seq_stop,
+	.show  = ip_tproxy_seq_show
+};
+
+static int ip_tproxy_proc_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &ip_tproxy_seq_ops);
+}
+
+static struct file_operations ip_tproxy_file_ops = {
+	.owner	 = THIS_MODULE,
+	.open	 = ip_tproxy_proc_open,
+	.read	 = seq_read,
+	.llseek	 = seq_lseek,
+	.release = seq_release
+};
+
+/* lookup sockref based on the local address. refcount is not incremented on the returned sockref */
+struct ip_tproxy_sockref *
+ip_tproxy_sockref_find_local(u32 addr, u16 port, u8 proto, int fresh, u32 raddr, u16 rport)
+{
+	u32 hash = ip_tproxy_hash_fn(addr, port, proto);
+	struct ip_tproxy_hash *h;
+	struct ip_tproxy_sockref *sr, *best = NULL;
+
+	ASSERT_READ_LOCK(&ip_tproxy_bylocal[hash]);
+	DEBUGP(KERN_DEBUG "IP_TPROXY: ip_tproxy_sockref_find_local(): "
+	       "entered, %08x:%04x\n", addr, port);
+
+	list_for_each_entry(h, &ip_tproxy_bylocal[hash], list) {
+		sr = h->sockref;
+
+		DEBUGP(KERN_DEBUG "IP_TPROXY: sockref_cmpfn_local(): sr: %08x:%04x "
+		       "(foreign: %08x:%04x remote: %08x:%04x), searched: "
+		       "%08x:%04x (remote: %08x:%04x)\n",
+		       sr->laddr, sr->lport, sr->faddr, sr->fport,
+		       sr->raddr, sr->rport, addr, port, raddr, rport);
+
+		if (sr->laddr == addr && sr->lport == port && sr->proto == proto) {
+			/* fresh means orphaned entries should be skipped */
+			if (fresh && (sr->flags & TF_ORPHAN))
+				continue;
+
+			if (raddr == 0 && rport == 0) {
+				/* not interested in remote address */
+				return sr;
+			}
+			else if (sr->raddr == raddr && sr->rport == rport) {
+				/* complete match */
+				return sr;
+			}
+			else if (sr->raddr == 0 && sr->rport == 0) {
+				/* unconnected sockref if complete match not found */
+				best = sr;
+			}
+		}
+	}
+
+	return best;
+}
+
+/* lookup sockref based on the foreign address. refcount is not incremented on the returned sockref */
+struct ip_tproxy_sockref *
+ip_tproxy_sockref_find_foreign(u32 addr, u16 port, u8 proto, u32 raddr, u16 rport)
+{
+	u32 hash = ip_tproxy_hash_fn(addr, port, proto);
+	struct ip_tproxy_hash *h;
+	struct ip_tproxy_sockref *sr, *best = NULL;
+
+	ASSERT_READ_LOCK(&ip_tproxy_byforeign[hash]);
+	DEBUGP(KERN_DEBUG "IP_TPROXY: ip_tproxy_sockref_find_foreign(): "
+	       "entered, %08x:%04x\n", addr, port);
+
+	list_for_each_entry(h, &ip_tproxy_byforeign[hash], list) {
+		sr = h->sockref;
+
+		DEBUGP(KERN_DEBUG "IP_TPROXY: sockref_cmpfn_foreign(): sr: %08x:%04x "
+		       "(remote: %08x:%04x), searched: %08x:%04x (remote: %08x:%04x)\n",
+		       sr->faddr, sr->fport, sr->raddr, sr->rport, addr, port, raddr, rport);
+
+		if (sr->faddr == addr && sr->fport == port && sr->proto == proto) {
+			if (raddr == 0 && rport == 0) {
+				/* not interested in remote address */
+				return sr;
+			}
+			else if (sr->raddr == raddr && sr->rport == rport) {
+				/* complete match */
+				return sr;
+			}
+			else if (sr->raddr == 0 && sr->rport == 0) {
+				/* unconnected sockref if complete match not found */
+				best = sr;
+			}
+		}
+	}
+
+	return best;
+}
+
+/* delete all sockrefs currently in the hash tables
+ * FIXME: we might have a race here. If our hook is running while to module
+ * is unloading, bad things might happen. */
+static void
+ip_tproxy_sockref_table_free(void)
+{
+	int i;
+	struct ip_tproxy_hash *h, *p;
+
+	for (i = 0; i < ip_tproxy_htable_size; i++) {
+		list_for_each_entry_safe(h, p, &ip_tproxy_bylocal[i], list) {
+			list_del(&h->list);
+			ip_tproxy_kill_conntracks(h->sockref, 0, 0, 0);
+			ip_tproxy_sockref_unref(h->sockref);
+		}
+		ip_tproxy_byforeign[i].prev = ip_tproxy_byforeign[i].next = &ip_tproxy_byforeign[i];
+	}
+}
+
+/* setup a bidirectional NAT mapping for the given connection, using the values specified by
+ * the assigned sockref */
+static int
+ip_tproxy_setup_nat_bidir(struct ip_conntrack *ct, int hooknum, struct ip_tproxy_sockref *sr, unsigned int flags)
+{
+	struct ip_nat_range range;
+	u32 newip = 0;
+	u16 newport = 0;
+	int res;
+
+	if (is_confirmed(ct) || ip_nat_initialized(ct, HOOK2MANIP(hooknum))) {
+		return NF_ACCEPT;
+	}
+
+	DEBUGP(KERN_DEBUG "IP_TPROXY: ip_tproxy_setup_nat(): adding nat "
+	       "entry hooknum=%d %08x:%04x -> %08x:%04x\n", hooknum, sr->laddr,
+	       sr->lport, sr->faddr, sr->fport);
+
+	range.flags = IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_BYPASS_HELPERS;
+
+	if (hooknum == NF_IP_POST_ROUTING) {
+		/* in POSTROUTING we perform an SNAT to the foreign address */
+		newip = sr->faddr;
+		newport = sr->fport;
+	}
+	else if (hooknum == NF_IP_PRE_ROUTING || hooknum == NF_IP_LOCAL_OUT) {
+		/* in PREROUTING and LOCAL_OUT we perform a DNAT to our socket address */
+
+		newip = sr->laddr;
+		newport = sr->lport;
+	}
+
+	range.min_ip = range.max_ip = newip;
+
+	/* if port number was specified */
+	if (newport != 0) {
+		if (sr->proto == IPPROTO_TCP) {
+			range.min.tcp.port = range.max.tcp.port = newport;
+			range.flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
+		}
+		else if (sr->proto == IPPROTO_UDP) {
+			range.min.udp.port = range.max.udp.port = newport;
+			range.flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
+		}
+#ifdef CONFIG_IP_NF_NAT_NRES
+		if (sr->flags & TF_NAT_RESERVED)
+			range.flags |= IP_NAT_RANGE_USE_RESERVED;
+#endif
+	}
+
+	res = ip_nat_setup_info(ct, &range, hooknum);
+
+	if (res != NF_ACCEPT) {
+		printk(KERN_WARNING "IP_TPROXY: error applying NAT mapping, "
+		       "hooknum=%d %08x:%04x -> %08x:%04x\n",
+		       hooknum, sr->laddr, sr->lport, newip, newport);
+	} else {
+		/* we store a reference to the sockref in the conntrack */
+		if (!test_and_set_bit(IPS_TPROXY_BIT, &ct->status)) {
+			if (flags & TN_STOREREF) {
+				ip_tproxy_sockref_ref(sr);
+				ct->tproxy.sockref = sr;
+			}
+		}
+
+		if ((newport == 0) && (ct->status & IPS_SRC_NAT) && (sr->flags & TF_HASHED)) {
+			u16 fport = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.all;
+			write_lock_bh(&ip_tproxy_lock);
+			/* FIXME: necessary and correct? */
+			ip_tproxy_rehash_fport(sr, fport);
+			write_unlock_bh(&ip_tproxy_lock);
+		}
+	}
+
+	return res;
+}
+
+/* redirect incoming packet to the appropriate local port (UDP specific) */
+static int
+ip_tproxy_setup_nat_unidir(struct sk_buff **pskb, int hooknum, struct ip_tproxy_sockref *sr)
+{
+	enum ip_nat_manip_type manip_type;
+	struct sk_buff *skb = *pskb;
+	struct ip_conntrack_tuple tuple;
+
+	/* free the original conntrack entry, and assign the fake one */
+	nf_conntrack_put(skb->nfct);
+	skb->nfct = &ip_tproxy_fake_ct.ct_general;
+	skb->nfctinfo = IP_CT_NEW;
+	nf_conntrack_get(skb->nfct);
+
+	/* fill tuple structure with new information */
+	tuple.dst.protonum = skb->nh.iph->protocol;
+
+	if (hooknum == NF_IP_POST_ROUTING) {
+		/* in POSTROUTING we perform an SNAT to the foreign address */
+		tuple.src.ip = sr->faddr;
+		tuple.src.u.udp.port = sr->fport;
+		manip_type = IP_NAT_MANIP_SRC;
+	} else if (hooknum == NF_IP_PRE_ROUTING || hooknum == NF_IP_LOCAL_OUT) {
+		/* in PREROUTING and LOCAL_OUT we perform a DNAT to our socket address */
+		tuple.dst.ip = sr->laddr;
+		tuple.dst.u.udp.port = sr->lport;
+		manip_type = IP_NAT_MANIP_DST;
+	} else
+		return NF_DROP;
+
+	/* manipulate packet "by hand" */
+	if (unlikely(!ip_nat_manip_pkt(skb->nh.iph->protocol, pskb, 0, &tuple, manip_type))) {
+		DEBUGP(KERN_DEBUG "IP_TPROXY: ip_tproxy_setup_nat_unidir(): "
+		       "failed to rewrite packet header\n");
+		return NF_DROP;
+	}
+
+	return NF_ACCEPT;
+}
+
+/* setup NAT for the packet */
+int
+ip_tproxy_setup_nat(struct sk_buff **pskb, int hooknum, struct ip_tproxy_sockref *sr, unsigned int flags)
+{
+	if (sr->proto == IPPROTO_TCP || (flags & TN_BIDIR)) {
+		struct ip_conntrack *ct;
+		enum ip_conntrack_info ctinfo;
+
+		ct = ip_conntrack_get(*pskb, &ctinfo);
+		return ip_tproxy_setup_nat_bidir(ct, hooknum, sr, flags);
+	} else if (sr->proto == IPPROTO_UDP)
+		return ip_tproxy_setup_nat_unidir(pskb, hooknum, sr);
+
+	return NF_DROP;
+}
+EXPORT_SYMBOL_GPL(ip_tproxy_setup_nat);
+
+/* This is a gross hack */
+static void
+ip_tproxy_save_orig_addrs(struct sk_buff *skb)
+{
+	struct iphdr *iph = skb->nh.iph;
+	u16 *tports, _tports[2];
+
+	tports = skb_header_pointer(skb, iph->ihl * 4, sizeof(_tports), &_tports);
+	if (tports != NULL) {
+		IPCB(skb)->orig_srcaddr = iph->saddr;
+		IPCB(skb)->orig_srcport = tports[0];
+		IPCB(skb)->orig_dstaddr = iph->daddr;
+		IPCB(skb)->orig_dstport = tports[1];
+	}
+}
+
+/* tproxy Netfilter hook */
+static unsigned int
+ip_tproxy_fn(unsigned int hooknum,
+	     struct sk_buff **pskb,
+	     const struct net_device *in,
+	     const struct net_device *out,
+	     int (*okfn)(struct sk_buff *))
+{
+	struct ip_conntrack *ct;
+	enum ip_conntrack_info ctinfo;
+	unsigned int verdict = NF_ACCEPT;
+
+	ct = ip_conntrack_get(*pskb, &ctinfo);
+
+	if (ct && ctinfo == IP_CT_NEW) {
+		struct iphdr *iph = (*pskb)->nh.iph;
+		u16 *tports, _tports[2];
+		struct ip_tproxy_sockref *sr = NULL;
+
+		tports = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl * 4,
+					    sizeof(_tports), &_tports);
+		if (tports == NULL) {
+			DEBUGP(KERN_DEBUG "IP_TPROXY: ip_tproxy_fn(): "
+			       "failed to copy protocol header\n");
+			return NF_DROP;
+		}
+
+		DEBUGP(KERN_DEBUG "IP_TPROXY: ip_tproxy_fn(): new connection, "
+		       "hook=%d, %08x:%04x -> %08x:%04x\n",
+		       hooknum, iph->saddr, tports[0], iph->daddr, tports[1]);
+
+		ip_tproxy_save_orig_addrs(*pskb);
+		read_lock_bh(&ip_tproxy_lock);
+		if (hooknum == NF_IP_PRE_ROUTING || hooknum == NF_IP_LOCAL_OUT) {
+
+			/*
+			 * We either received a connection from the network (PREROUTING case)
+			 * or a local process generated one (LOCAL_OUT case).
+			 *
+			 * In either case we check whether a proxy bound to the
+			 * destination of this connection.
+			 *
+			 * As a special case we check in LOCAL_OUT whether the
+			 * connection was initiated by a local proxy, and if it
+			 * was we mark the connection as such and skip the
+			 * tproxy table.
+			 */
+
+			/* destination address is interesting */
+
+			sr = ip_tproxy_sockref_find_foreign(iph->daddr, tports[1],
+						iph->protocol, iph->saddr, tports[0]);
+
+			if (sr && sr->flags & TF_ORPHAN) {
+				/* This sockref is orphaned, the listening socket is already unassigned,
+				 * so it should not be used for setting up NAT for a new connection. */
+				sr = NULL;
+			}
+
+			if (sr && (sr->flags & (TF_LISTEN|TF_MARK_ONLY)) == 0) {
+				DEBUGP(KERN_DEBUG "IP_TPROXY: ip_tproxy_fn(PREROUTING), "
+				       "entry found but flags = 0\n");
+				sr = NULL;
+			}
+
+			if (hooknum == NF_IP_LOCAL_OUT &&
+			    !sr &&
+			    (sr = ip_tproxy_sockref_find_local(iph->saddr, tports[0],
+							       iph->protocol, 1, iph->daddr,
+							       tports[1]))) {
+				DEBUGP("IP_TPROXY: tproxy initiated session in local "
+				       "output, sr->flags=%04x\n", sr->flags);
+				if ((sr->flags & TF_MARK_ONLY) == 0)
+					sr = NULL;
+			}
+		}
+		else if (hooknum == NF_IP_POST_ROUTING) {
+
+			/*
+			 * We detected a new connection just leaving this box, so
+			 * we now have a chance to add a translation changing
+			 * the source address of all packets. We want to do this
+			 * if the connection was initiated by a transparent proxy
+			 * which registered another address to rewrite the source into.
+			 *
+			 * A proxy registered an entry if find_local returns non-NULL.
+			 */
+
+			/* source address is interesting */
+
+			sr = ip_tproxy_sockref_find_local(iph->saddr, tports[0], iph->protocol,
+					1, iph->daddr, tports[1]);
+			if (sr && (sr->flags & (TF_CONNECT|TF_MARK_ONLY)) == 0) {
+				DEBUGP(KERN_DEBUG "IP_TPROXY: ip_tproxy_fn(POSTROUTING), "
+				       "entry found but flags = 0\n");
+				sr = NULL;
+			}
+		}
+		else {
+			printk(KERN_WARNING "IP_TPROXY: hook function called at hooks other "
+			       "than NF_IP_PRE_ROUTING, NF_IP_POST_ROUTING or "
+			       "NF_IP_LOCAL_OUT, hooknum=%d\n", hooknum);
+			verdict = NF_DROP;
+		}
+
+		/*
+		 * sockref will not be freed, as the hash is read locked here
+		 * and by the time we unlock it we own a reference
+		 */
+
+		if (sr) {
+			if (sr->flags & TF_MARK_ONLY) {
+				/*
+				 * A MARK_ONLY entry indicates that although the proxy
+				 * doesn't want any address rewrite to be performed
+				 * it registered its connection as one originating
+				 * from a transparent proxy, so -m tproxy matches it.
+				 *
+				 * It is a convinience feature, so administrators
+				 * can simply let tproxied traffic through their filter
+				 * table.
+				 */
+				DEBUGP(KERN_DEBUG "IP_TPROXY: mark only entry...\n");
+
+				if (!test_and_set_bit(IPS_TPROXY_BIT, &ct->status))
+					ct->tproxy.sockref = NULL;
+
+				sr = NULL;
+			}
+			else {
+				/* we'll have a reference to the sockref after releasing the lock */
+				ip_tproxy_sockref_ref(sr);
+			}
+		}
+		read_unlock_bh(&ip_tproxy_lock);
+
+		DEBUGP(KERN_DEBUG "IP_TPROXY: ip_tproxy_fn(): sockref looked up, sr=%p\n", sr);
+		if (sr) {
+
+			/* sockref found it is a real translation as
+			 * MARK_ONLY was handled above so we apply the
+			 * necessary NAT function
+			 */
+
+			/* apply NAT mapping */
+			unsigned int dirflag = !(sr->flags & TF_UNIDIR) ? TN_BIDIR : 0;
+			if (ip_tproxy_setup_nat(pskb, hooknum, sr, dirflag | TN_STOREREF) == NF_ACCEPT) {
+				/* FIXME: hmm. there might be races involved
+				 * with TF_NAT_APPLIED, as another processor
+				 * might be processing the same sockref.
+				 */
+				sr->flags |= TF_NAT_APPLIED;
+			} else {
+				/* Applying the NAT mapping failed, we should drop the packet */
+				verdict = NF_DROP;
+			}
+
+			/* drop reference */
+			ip_tproxy_sockref_unref(sr);
+		} /* if (sr) */
+		else if (!test_bit(IPS_TPROXY_BIT, &ct->status) &&
+			 (hooknum == NF_IP_PRE_ROUTING || hooknum == NF_IP_LOCAL_OUT)) {
+
+			/* there was no matching sockref, so we consult the
+			 * TPROXY table
+			 */
+
+			verdict = ipt_do_table(pskb, hooknum, in, out, &tproxy_table);
+		}
+	}
+
+	return verdict;
+}
+
+#ifdef CONFIG_IP_NF_NAT_NRES
+static inline struct ip_nat_reserved *
+ip_tproxy_nat_reserve(const u32 faddr, const u16 fport, int proto, const u32 raddr, const u16 rport)
+{
+	struct ip_conntrack_manip m = {.ip = faddr, .u = {.all = fport}};
+	struct ip_conntrack_manip p = {.ip = raddr, .u = {.all = rport}};
+	struct ip_nat_reserved *res;
+
+	DEBUGP(KERN_DEBUG "IP_TPROXY: ip_tproxy_nat_reserve proto %u foreign "
+	       "%u.%u.%u.%u:%u peer %u.%u.%u.%u:%u\n",
+	       proto, NIPQUAD(faddr), ntohs(fport), NIPQUAD(raddr), ntohs(rport));
+
+	write_lock_bh(&ip_nat_lock);
+	res = __ip_nat_reserved_new_hash(&m, proto, (raddr && rport) ? &p : NULL);
+	write_unlock_bh(&ip_nat_lock);
+
+	return res;
+}
+
+static void
+ip_tproxy_nat_reserved_free(struct ip_tproxy_sockref *sr)
+{
+	struct ip_nat_reserved *res;
+	struct ip_conntrack_manip m = {.ip = sr->faddr, .u = {.all = sr->fport}};
+	struct ip_conntrack_manip p = {.ip = sr->raddr, .u = {.all = sr->rport}};
+
+	/* free NAT reservation */
+	if (sr->flags & TF_NAT_RESERVED) {
+		write_lock_bh(&ip_nat_lock);
+		if (sr->flags & TF_NAT_PEER)
+			res = __ip_nat_reserved_unhash(&m, sr->proto, &p);
+		else
+			res = __ip_nat_reserved_unhash(&m, sr->proto, NULL);
+		write_unlock_bh(&ip_nat_lock);
+
+		if (res) {
+			sr->flags &= ~(TF_NAT_RESERVED | TF_NAT_PEER);
+			__ip_nat_reserved_free(res);
+		}
+	}
+}
+#endif
+
+/* This routine dynamically allocates a foreign port if the proxy requests this
+ * by setting fport to 0. We try to use the same algorithm the local stack
+ * uses to allocate a port. The routine itself is only used when we need to
+ * allocate a foreign port _before_ sending the first packet, standard connect
+ * sockets get their foreign port allocated by the NAT subsystem. */
+static inline int
+ip_tproxy_sockref_uniq(struct ip_tproxy_sockref *sr)
+{
+	int min, max, rover, left;
+	static int ip_tproxy_port_rover = 0;
+
+	DEBUGP(KERN_DEBUG "IP_TPROXY: ip_tproxy_sockref_uniq\n");
+	min = sysctl_local_port_range[0];
+	max = sysctl_local_port_range[1];
+	rover = ip_tproxy_port_rover;
+	left = (max - min) + 1;
+	do {
+		rover++;
+		if (rover < min || rover > max)
+			rover = min;
+		if (ip_tproxy_sockref_find_foreign(sr->faddr, htons(rover),
+						   sr->proto, sr->raddr,
+						   sr->rport) == NULL) {
+#ifdef CONFIG_IP_NF_NAT_NRES
+			/* unique entry found, try to reserve in NAT */
+			if (ip_tproxy_nat_reserve(sr->faddr, htons(rover), sr->proto, sr->raddr, sr->rport))
+#endif
+				break;
+		}
+	} while (--left > 0);
+
+	if (left == 0) {
+		printk(KERN_WARNING "IP_TPROXY: out of free foreign ports, "
+		       "increase local_port_range\n");
+		return 0;
+	} else if (rover == 0) {
+		printk(KERN_WARNING "IP_TPROXY: hm?? ip_tproxy_sockref_uniq, "
+		       "left != 0 && rover == 0\n");
+	} else {
+		/* succeeded */
+		DEBUGP(KERN_DEBUG "IP_TPROXY: ip_tproxy_sockref_uniq, "
+		       "allocated port=%d\n", rover);
+
+		ip_tproxy_port_rover = rover;
+
+#ifdef CONFIG_IP_NF_NAT_NRES
+		sr->flags |= TF_NAT_RESERVED;
+		if (sr->raddr && sr->rport)
+			sr->flags |= TF_NAT_PEER;
+#endif
+		ip_tproxy_rehash_fport(sr, htons(rover));
+	}
+
+	return rover;
+}
+
+static int
+ip_tproxy_setsockopt_version(struct sock *sk, int proto, struct in_tproxy *itp)
+{
+	int res = 0;
+	u_int32_t ver = itp->v.version;
+
+	DEBUGP(KERN_DEBUG "IP_TPROXY: IP_TPROXY_VERSION\n");
+
+	if ((MAJOR_VERSION(ver) != TPROXY_MAJOR_VERSION) ||
+	    (MINOR_VERSION(ver) > TPROXY_MINOR_VERSION))
+		res = -EINVAL;
+
+	return res;
+}
+
+static int
+ip_tproxy_setsockopt_assign(struct sock *sk, int proto, struct in_tproxy *itp)
+{
+	int foreign_matches, res = 0;
+	struct ip_tproxy_sockref *sr, *tsr = NULL;
+	struct inet_sock *inet = inet_sk(sk);
+
+	DEBUGP(KERN_DEBUG "IP_TPROXY: IP_TPROXY_ASSIGN %08x:%04x\n",
+	       inet->rcv_saddr, inet->sport);
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	if ((sk->sk_socket == NULL) ||
+	    (sk->sk_socket->state != SS_UNCONNECTED)) {
+		DEBUGP(KERN_DEBUG "IP_TPROXY: socket is not SS_UNCONNECTED "
+		       "during assign\n");
+		return -EINVAL;
+	}
+
+	if (!inet->rcv_saddr || !inet->sport)
+		return -EINVAL;
+
+	read_lock_bh(&ip_tproxy_lock);
+
+	DEBUGP(KERN_DEBUG "IP_TPROXY: count=%d\n", ip_tproxy_htable_count);
+
+	/* check if this socket was already assigned a sockref */
+	sr = ip_tproxy_sockref_find_local(inet->rcv_saddr, inet->sport, proto, 0, 0, 0);
+
+	/* NOTE: this is a HACK, and trusts the userspace app.
+	   We allow to assign multiple sockrefs to a single
+	   local addr:port pair _iff_ the foreign address is
+	   0.0.0.0:0 to allow UDP sessions to be bound to
+	   the same socket while keeping the 'mark as
+	   tproxy' packet mechanism.
+
+	   Maybe we should assign sockrefs to the struct sock *
+	   address instead.
+	*/
+	if (sr) {
+		if (itp->v.addr.faddr.s_addr || itp->v.addr.fport) {
+			printk("IP_TPROXY: socket already assigned, reuse=%d, "
+			       "%08x:%04x, sr->faddr=%08x:%04x, flags=%x, "
+			       "sr->tv_hashed=%ld:%ld\n", sk->sk_reuse,
+			       inet->rcv_saddr, inet->sport, sr->faddr, sr->fport,
+			       sr->flags, sr->tv_hashed.tv_sec, sr->tv_hashed.tv_nsec);
+			res = -EEXIST;
+			goto read_unlk;
+		} else {
+			DEBUGP(KERN_DEBUG "IP_TPROXY: IP_TPROXY_ASSIGN local address "
+			       "already taken, sharing this sockref\n");
+
+			/* increase socket count of sockref, indicating that it is
+			 * shared between multiple sockets */
+			atomic_inc(&sr->socket_count);
+			goto read_unlk;
+		}
+	}
+
+	/* check if the foreign address specified has already been taken.
+	 * if it has, the socket can only be used for connecting, provided
+	 * sk->sk_reuse is true, otherwise fail */
+
+	if (itp->v.addr.faddr.s_addr && itp->v.addr.fport != 0 &&
+	    (tsr = ip_tproxy_sockref_find_foreign(itp->v.addr.faddr.s_addr, itp->v.addr.fport, proto, 0, 0))) {
+		if (!sk->sk_reuse) {
+			res = -EADDRINUSE;
+			goto read_unlk;
+		}
+		foreign_matches = 1;
+	} else {
+		foreign_matches = 0;
+	}
+
+	/* we performed all checks, now allocate and fill a new
+	 * sockref */
+
+	sr = ip_tproxy_sockref_new();
+	if (!sr) {
+		printk(KERN_WARNING "IP_TPROXY: drained? cannot allocate sockref\n");
+		res = -ENOBUFS;
+		goto read_unlk;
+	}
+	sr->flags = 0;
+	sr->proto = proto;
+	sr->faddr = itp->v.addr.faddr.s_addr;
+	sr->fport = itp->v.addr.fport;
+	sr->laddr = inet->rcv_saddr;
+	sr->lport = inet->sport;
+	sr->assigned_to = sk;
+
+	if (itp->v.addr.faddr.s_addr == 0) {
+		/* we store the local address as foreign as well
+		 * for mark only connections, so find_foreign
+		 * finds this entry as well */
+
+		sr->flags |= TF_MARK_ONLY;
+		sr->faddr = sr->laddr;
+		sr->fport = sr->lport;
+	}
+	else if (foreign_matches) {
+		/* sk->sk_reuse was true */
+		/* if the existing sockref is mark only, or has its remote
+		 * endpoint specified, we have a chance not to clash with it,
+		 * otherwise this sockref will be connect-only */
+
+		if ((tsr->flags & TF_MARK_ONLY) || (tsr->raddr != 0 && tsr->rport != 0)) {
+			DEBUGP(KERN_DEBUG "IP_TPROXY: IP_TPROXY_ASSIGN omitting "
+			       "CONNECT_ONLY, other sockref is mark-only or connected\n");
+		} else {
+			sr->flags |= TF_CONNECT_ONLY;
+			DEBUGP(KERN_DEBUG "IP_TPROXY: IP_TPROXY_ASSIGN setting "
+			       "sr %p CONNECT_ONLY\n", sr);
+		}
+	}
+
+	DEBUGP(KERN_DEBUG "IP_TPROXY: IP_TPROXY_ASSIGN sr %p faddr:fport "
+	       "%08x:%04x flags %08x\n", sr, sr->faddr, sr->fport, sr->flags);
+
+#ifdef CONFIG_IP_NF_NAT_NRES
+	/* If SO_REUSE is not set and foreign port was specified, we should
+	 * allocate a NAT reservation right now. This mode is used by range
+	 * binds, so being pessimistic at NAT reservation clash checks causes
+	 * the caller to proceed to the next port and try again. */
+	if (itp->v.addr.faddr.s_addr && itp->v.addr.fport &&
+	    !foreign_matches && !sk->sk_reuse) {
+		/* we should register a NAT reservatinon */
+		if (ip_tproxy_nat_reserve(sr->faddr, sr->fport, proto, 0, 0)) {
+			sr->flags |= TF_NAT_RESERVED;
+			sr->flags &= ~TF_NAT_PEER;
+		} else {
+			/* failed to register NAT reservation, bail out */
+			DEBUGP(KERN_DEBUG "IP_TPROXY: IP_TPROXY_ASSIGN cannot "
+			       "register NAT reservation %08x:%04x\n",
+			       sr->faddr, sr->fport);
+
+			res = -EINVAL;
+			ip_tproxy_sockref_unref(sr);
+			goto read_unlk;
+		}
+	}
+#endif
+
+	read_unlock_bh(&ip_tproxy_lock);
+	write_lock_bh(&ip_tproxy_lock);
+	/* here we should check if we've won the race: if a sockref is in the
+	 * local hash by the time we acquired the write lock, we've lost */
+	if (!(tsr = ip_tproxy_sockref_find_local(inet->rcv_saddr,
+						 inet->sport, proto, 0, 0, 0)))
+		ip_tproxy_hash(sr);
+	write_unlock_bh(&ip_tproxy_lock);
+
+	if (tsr) {
+		/* we've lost the race */
+		res = -EINVAL;
+	}
+
+	/* the hashtable stores a reference, if hashing succeeded */
+	ip_tproxy_sockref_unref(sr);
+
+	return res;
+
+ read_unlk:
+	read_unlock_bh(&ip_tproxy_lock);
+	return res;
+}
+
+static int
+ip_tproxy_setsockopt_unassign(struct sock *sk, int proto, struct in_tproxy *itp)
+{
+	int res = 0, unhash = 0;
+	u32 saddr, daddr;
+	u16 sport, dport;
+	struct ip_tproxy_sockref *sr;
+
+	/* connection and time_wait socksets have to be handled differently */
+	if (sk->sk_state == TCP_TIME_WAIT) {
+		struct inet_timewait_sock *tw = inet_twsk(sk);
+		saddr = tw->tw_rcv_saddr;
+		daddr = tw->tw_daddr;
+		sport = tw->tw_sport;
+		dport = tw->tw_dport;
+	} else {
+		struct inet_sock *inet = inet_sk(sk);
+		saddr = inet->rcv_saddr;
+		daddr = inet->daddr;
+		sport = inet->sport;
+		dport = inet->dport;
+	}
+
+	/* break the connection between this socket and
+	 * a foreign address. This is implicitly performed
+	 * when the socket is closed */
+
+	DEBUGP(KERN_DEBUG "IP_TPROXY: IP_TPROXY_UNASSIGN %08x:%04x\n", saddr, sport);
+
+	write_lock_bh(&ip_tproxy_lock);
+	sr = ip_tproxy_sockref_find_local(saddr, sport, proto, 0, daddr, dport);
+
+	if (!sr) {
+		DEBUGP(KERN_DEBUG "IP_TPROXY: IP_TPROXY_UNASSIGN not unhashing socket, "
+		       "%08x:%04x, proto=%d\n",
+		       saddr, sport, proto);
+		res = -ENOENT;
+		goto write_unlk;
+	}
+
+	/* Delete appropriate related connections and set 'unhash' if
+	 * we have to unhash the sockref. */
+
+	/* Handle mark-only sockrefs separately: mark-only sockrefs don't have
+	 * related conntrack entries, so there is no need to bother to delete
+	 * the correct one from the related list. However, mark-only entries
+	 * can be shared, which means that more than one sockets are bound to
+	 * the same local address, and they are using the same sockref to have
+	 * matching connections marked. Because of this, we may unhash the
+	 * sockref only if there are no sockets left */
+	if (sr->flags & TF_MARK_ONLY) {
+		DEBUGP(KERN_DEBUG "IP_TPROXY: IP_TPROXY_UNASSIGN unassigning "
+		       "mark-only sockref %08x:%04x\n", saddr, sport);
+		if (atomic_dec_and_test(&sr->socket_count)) {
+			/* this was the last socket using this sockref */
+			unhash = 1;
+		}
+	} else switch (proto) {
+	case IPPROTO_TCP:
+		if ((sr->flags & TF_LISTEN)) {
+			if (sr->assigned_to != sk) {
+				/* unassigning the socket of a connection
+				 * established to a listening socket */
+				DEBUGP(KERN_DEBUG "IP_TPROXY: IP_TPROXY_UNASSIGN unassigning "
+				       "TCP listen related %08x:%04x -> %08x:%04x\n",
+				       daddr, dport, saddr, sport);
+			} else {
+				/* unassigning a listening socket, don't destroy just mark invalid */
+				DEBUGP(KERN_DEBUG "IP_TPROXY: IP_TPROXY_UNASSIGN unassigning "
+				       "TCP listen socket %08x:%04x\n", saddr, sport);
+				sr->flags |= TF_ORPHAN;
+				sr->assigned_to = NULL;
+			}
+
+			/* we have to unhash if there are no more related
+			 * connections and the listening socket is closed as
+			 * well */
+			if (!atomic_read(&sr->related) && !sr->assigned_to)
+				unhash = 1;
+
+		} else if (sr->flags & TF_CONNECT) {
+			/* unassigning a connect socket */
+			DEBUGP(KERN_DEBUG "IP_TPROXY: IP_TPROXY_UNASSIGN unassigning "
+			       "TCP connect %08x:%04x\n", saddr, sport);
+			unhash = 1;
+		}
+		break;
+
+	case IPPROTO_UDP:
+		DEBUGP(KERN_DEBUG "IP_TPROXY: IP_TPROXY_UNASSIGN unassigning UDP "
+		       "%08x:%04x\n", saddr, sport);
+		ip_tproxy_kill_conntracks(sr, 0, 0, 1);
+		unhash = 1;
+		break;
+	}
+
+	/* unhash sockref if we don't need it anymore */
+	if (unhash) {
+#ifdef CONFIG_IP_NF_NAT_NRES
+		ip_tproxy_nat_reserved_free(sr);
+#endif
+		ip_tproxy_unhash(sr);
+	}
+
+ write_unlk:
+	write_unlock_bh(&ip_tproxy_lock);
+
+	return res;
+}
+
+static int
+ip_tproxy_setsockopt_flags(struct sock *sk, int proto, struct in_tproxy *itp)
+{
+	int res = 0;
+	struct ip_tproxy_sockref *sr;
+	u_int32_t flags = itp->v.flags;
+	struct inet_sock *inet = inet_sk(sk);
+
+	/* specify translation flags for this socket */
+
+	DEBUGP(KERN_DEBUG "IP_TPROXY: IP_TPROXY_FLAGS %08x:%04x\n",
+	       inet->rcv_saddr, inet->sport);
+
+	/* we don't check CAP_NET_ADMIN here, it was checked when this entry was hashed */
+
+	DEBUGP(KERN_DEBUG "IP_TPROXY: IP_TPROXY_FLAGS flags to set %08x\n",
+	       flags);
+
+	/* FIXME: since read locks cannot be upgraded, we need a write lock if
+	 * foreign port allocation will be needed... */
+	write_lock_bh(&ip_tproxy_lock);
+	sr = ip_tproxy_sockref_find_local(inet->rcv_saddr, inet->sport, proto,
+					  0, inet->daddr, inet->dport);
+	if (!sr) {
+		res = -ENOENT;
+		goto write_unlk;
+	}
+
+	DEBUGP(KERN_DEBUG "IP_TPROXY: IP_TPROXY_FLAGS sr %p flags %08x\n", sr, sr->flags);
+
+	/* Don't do anything in case of MARK_ONLY sockrefs */
+	if (sr->flags & TF_MARK_ONLY) {
+		DEBUGP(KERN_DEBUG "IP_TPROXY: IP_TPROXY_FLAGS sr %p mark only, "
+		       "doing nothing\n", sr);
+		goto write_unlk;
+	}
+
+	/* clear user-settable flags */
+	sr->flags &= TF_STATE_MASK;
+
+	/* set TF_CONNECT/TF_LISTEN if needed */
+	switch (flags & (ITP_CONNECT | ITP_LISTEN | ITP_ESTABLISHED)) {
+	case ITP_CONNECT:
+		sr->flags |= TF_CONNECT;
+		ip_tproxy_kill_conntracks(sr, 0, 0, 1);
+		break;
+	case ITP_LISTEN:
+		if (sr->flags & TF_CONNECT_ONLY) {
+			DEBUGP(KERN_DEBUG "IP_TPROXY: IP_TPROXY_FLAGS sr %p: "
+					   "trying to set ITP_LISTEN on a connect only sockref\n",
+					   sr);
+			res = -EINVAL;
+			break;
+		}
+		sr->flags |= TF_LISTEN;
+		ip_tproxy_kill_conntracks(sr, 0, 0, 1);
+		break;
+	case ITP_ESTABLISHED:
+		DEBUGP(KERN_DEBUG "IP_TPROXY: IP_TPROXY_FLAGS: establishing sr %p "
+		       "raddr:rport %08x:%04x daddr:dport %08x:%04x\n",
+			sr, sr->raddr, sr->rport, inet->daddr, inet->dport);
+
+		if (sr->raddr == 0 || sr->rport == 0) {
+			DEBUGP(KERN_DEBUG "IP_TPROXY: IP_TPROXY_FLAGS sr %p: "
+			       "trying to set ITP_ESTABLISHED on a not connected sockref\n",
+			       sr);
+			res = -EINVAL;
+		}
+		sr->flags |= TF_LISTEN | TF_CONNECT;
+		ip_tproxy_kill_conntracks(sr, 0, 0, 1);
+		break;
+	default:
+		DEBUGP(KERN_DEBUG "IP_TPROXY: IP_TPROXY_FLAGS sr %p: "
+				  "invalid combination of flags %x\n", sr, flags);
+		/* FIXME: indicate error, if no CONNECT/LISTEN/ESTABLISHED was given? */
+		break;
+	}
+
+	/* Set TF_NAT_ONCE and TF_UNIDIR if needed */
+	sr->flags |= (flags & ITP_ONCE ? TF_NAT_ONCE : 0) |
+		     (flags & ITP_UNIDIR ? TF_UNIDIR : 0);
+
+#ifdef CONFIG_IP_NF_NAT_NRES
+	/* reserve NAT mappings if raddr is specified and sk->sk_reuse is set */
+	if (flags & (ITP_CONNECT | ITP_ESTABLISHED) &&
+	    sr->faddr && sr->fport && sr->raddr && sr->rport && sk->sk_reuse) {
+		if (ip_tproxy_nat_reserve(sr->faddr, sr->fport, proto, sr->raddr, sr->rport)) {
+			sr->flags |= (TF_NAT_RESERVED | TF_NAT_PEER);
+		} else {
+			DEBUGP(KERN_DEBUG "IP_TPROXY: IP_TPROXY_FLAGS sr %p: "
+					  "failed to register NAT reservation\n", sr);
+			res = -EINVAL;
+			goto write_unlk;
+		}
+	}
+#endif
+
+ write_unlk:
+	write_unlock_bh(&ip_tproxy_lock);
+
+	return res;
+}
+
+static int
+ip_tproxy_setsockopt_alloc(struct sock *sk, int proto, struct in_tproxy *itp)
+{
+	int res = 0;
+	struct ip_tproxy_sockref *sr;
+	struct inet_sock *inet = inet_sk(sk);
+
+	/* we'd like to force allocation of a unique foreign address, if one's not specified */
+	DEBUGP(KERN_DEBUG "IP_TPROXY: IP_TPROXY_ALLOC %08x:%04x\n",
+	       inet->rcv_saddr, inet->sport);
+
+	write_lock_bh(&ip_tproxy_lock);
+	sr = ip_tproxy_sockref_find_local(inet->rcv_saddr, inet->sport, proto, 0, inet->daddr, inet->dport);
+	if (!sr) {
+		res = -ENOENT;
+		goto write_unlk;
+	}
+
+	DEBUGP(KERN_DEBUG "IP_TPROXY: IP_TPROXY_ALLOC sr %p, current foreign "
+	       "%08x:%04x\n", sr, sr->faddr, sr->fport);
+
+	if (sr->flags & TF_MARK_ONLY) {
+		DEBUGP("IP_TPROXY: IP_TPROXY_ALLOC sr %p mark only, "
+		       "doing nothing\n", sr);
+		goto write_unlk;
+	}
+
+	if (sr->faddr && sr->fport) {
+		/* foreign port already assigned */
+		res = -EINVAL;
+		goto write_unlk;
+	}
+
+	if (ip_tproxy_sockref_uniq(sr) == 0) {
+		/* allocating a foreign port failed */
+		DEBUGP(KERN_DEBUG "IP_TPROXY: failed to allocate foreign port "
+		       "for listening sockref\n");
+		res = -EFAULT;
+		goto write_unlk;
+	}
+
+ write_unlk:
+	write_unlock_bh(&ip_tproxy_lock);
+
+	return res;
+}
+
+static int
+ip_tproxy_setsockopt_connect(struct sock *sk, int proto, struct in_tproxy *itp)
+{
+	int res = 0;
+	struct ip_tproxy_sockref *sr;
+	struct inet_sock *inet = inet_sk(sk);
+
+	DEBUGP(KERN_DEBUG "IP_TPROXY: IP_TPROXY_CONNECT %08x:%04x\n",
+	       inet->rcv_saddr, inet->sport);
+
+	/* Look up in the local sockref hash */
+	read_lock_bh(&ip_tproxy_lock);
+	sr = ip_tproxy_sockref_find_local(inet->rcv_saddr, inet->sport, proto,
+					  0, inet->daddr, inet->dport);
+	if (!sr) {
+		res = -ENOENT;
+		goto read_unlk;
+	}
+
+	DEBUGP(KERN_DEBUG "IP_TPROXY: IP_TPROXY_CONNECT sr %p, current "
+	       "raddr:rport %08x:%04x\n", sr, sr->raddr, sr->rport);
+
+	if (sr->flags & TF_MARK_ONLY) {
+		DEBUGP(KERN_DEBUG "IP_TPROXY: IP_TPROXY_CONNECT sr %p "
+		       "mark only\n", sr);
+		goto read_unlk;
+	}
+
+	/* store remote address */
+	if (itp->v.addr.faddr.s_addr && itp->v.addr.fport) {
+		sr->raddr = itp->v.addr.faddr.s_addr;
+		sr->rport = itp->v.addr.fport;
+		DEBUGP(KERN_DEBUG "IP_TPROXY: IP_TPROXY_CONNECT sr %p, "
+		       "new raddr:rport %08x:%04x\n", sr, sr->raddr, sr->rport);
+	}
+
+ read_unlk:
+	read_unlock_bh(&ip_tproxy_lock);
+
+	return res;
+}
+
+static int
+ip_tproxy_setsockopt(struct sock *sk, int optval, void __user *user, unsigned int len)
+{
+	int proto;
+	int res = 0;
+	unsigned int mlen;
+	struct in_tproxy itp;
+
+	/* get protocol number of the socket */
+	proto = sk->sk_protocol;
+	if ((proto != IPPROTO_UDP) && (proto != IPPROTO_TCP))
+		return -EINVAL;
+
+	if (len < sizeof(itp.op) + sizeof(itp.v.version))
+		return -EINVAL;
+
+	mlen = MIN(sizeof(itp), len);
+
+	if (copy_from_user(&itp, user, mlen))
+		return -EFAULT;
+
+	switch (itp.op) {
+		case TPROXY_VERSION:
+			res = ip_tproxy_setsockopt_version(sk, proto, &itp);
+			break;
+		case TPROXY_ASSIGN:
+			res = ip_tproxy_setsockopt_assign(sk, proto, &itp);
+			break;
+		case TPROXY_UNASSIGN:
+			res = ip_tproxy_setsockopt_unassign(sk, proto, &itp);
+			break;
+		case TPROXY_FLAGS:
+			res = ip_tproxy_setsockopt_flags(sk, proto, &itp);
+			break;
+		case TPROXY_ALLOC:
+			res = ip_tproxy_setsockopt_alloc(sk, proto, &itp);
+			break;
+		case TPROXY_CONNECT:
+			res = ip_tproxy_setsockopt_connect(sk, proto, &itp);
+			break;
+		default:
+			res = -ENOPROTOOPT;
+			break;
+	}
+
+	return res;
+}
+
+static int
+ip_tproxy_getsockopt_version(struct sock *sk, int proto, struct in_tproxy *itp)
+{
+	DEBUGP(KERN_DEBUG "IP_TPROXY: IP_TPROXY_VERSION\n");
+
+	itp->v.version = TPROXY_FULL_VERSION;
+
+	return 0;
+}
+
+static int
+ip_tproxy_getsockopt_query(struct sock *sk, int proto, struct in_tproxy *itp)
+{
+	int res = 0;
+	struct ip_tproxy_sockref *sr;
+	struct inet_sock *inet = inet_sk(sk);
+
+	DEBUGP(KERN_DEBUG "IP_TPROXY: IP_TPROXY_QUERY %08x:%04x\n",
+	       inet->rcv_saddr, inet->sport);
+
+	read_lock_bh(&ip_tproxy_lock);
+
+	sr = ip_tproxy_sockref_find_local(inet->rcv_saddr, inet->sport, proto,
+					  0, inet->daddr, inet->dport);
+	if (sr) {
+		itp->v.addr.faddr.s_addr = sr->faddr;
+		itp->v.addr.fport = sr->fport;
+		DEBUGP(KERN_DEBUG "IP_TPROXY: IP_TPROXY_QUERY found sr %p "
+		       "faddr:fport %08x:%04x\n", sr, sr->faddr, sr->fport);
+	} else
+		res = -ENOENT;
+
+	read_unlock_bh(&ip_tproxy_lock);
+
+	return res;
+}
+
+static int
+ip_tproxy_getsockopt_flags(struct sock *sk, int proto, struct in_tproxy *itp)
+{
+	int res = 0;
+	u_int32_t flags;
+	struct ip_tproxy_sockref *sr;
+	struct inet_sock *inet = inet_sk(sk);
+
+	DEBUGP(KERN_DEBUG "IP_TPROXY: IP_TPROXY_FLAGS get %08x:%04x\n",
+	       inet->rcv_saddr, inet->sport);
+
+	read_lock_bh(&ip_tproxy_lock);
+
+	sr = ip_tproxy_sockref_find_local(inet->rcv_saddr, inet->sport, proto,
+					  0, inet->daddr, inet->dport);
+	if (!sr) {
+		res = -ENOENT;
+		goto read_unlk;
+	}
+
+	flags = 0;
+	if ((sr->flags & (TF_CONNECT+TF_LISTEN)) == (TF_CONNECT+TF_LISTEN))
+		flags |= ITP_ESTABLISHED;
+	else if (sr->flags & TF_CONNECT)
+		flags |= ITP_CONNECT;
+	else if (sr->flags & TF_LISTEN)
+		flags |= ITP_LISTEN;
+
+	if (sr->flags & TF_UNIDIR)
+		flags |= ITP_UNIDIR;
+	if (sr->flags & TF_NAT_ONCE)
+		flags |= ITP_ONCE;
+	if (sr->flags & TF_MARK_ONLY)
+		flags |= ITP_MARK;
+	if (sr->flags & TF_NAT_APPLIED)
+		flags |= ITP_APPLIED;
+
+	DEBUGP(KERN_DEBUG "IP_TPROXY: IP_TPROXY_FLAGS found sr %p faddr:fport "
+	       "%08x:%04x flags %08x\n", sr, sr->faddr, sr->fport, sr->flags);
+
+	itp->v.flags = flags;
+
+ read_unlk:
+	read_unlock_bh(&ip_tproxy_lock);
+
+	return res;
+}
+
+static int
+ip_tproxy_getsockopt(struct sock *sk, int optval, void __user *user, int *len)
+{
+	int proto;
+	int res = 0;
+	unsigned int mlen;
+	struct in_tproxy itp;
+
+	proto = sk->sk_protocol;
+	if ((proto != IPPROTO_UDP) && (proto != IPPROTO_TCP))
+		return -EINVAL;
+
+	if (*len < sizeof(itp.op) + sizeof(itp.v.version))
+		return -EINVAL;
+
+	mlen = MIN(sizeof(itp), *len);
+
+	if (copy_from_user(&itp, user, mlen))
+		return -EFAULT;
+
+	switch (itp.op) {
+		case TPROXY_VERSION:
+			res = ip_tproxy_getsockopt_version(sk, proto, &itp);
+			break;
+		case TPROXY_QUERY:
+			res = ip_tproxy_getsockopt_query(sk, proto, &itp);
+			break;
+		case TPROXY_FLAGS:
+			res = ip_tproxy_getsockopt_flags(sk, proto, &itp);
+			break;
+		default:
+			res = -ENOPROTOOPT;
+			break;
+	}
+
+	/* copy data to userspace */
+	/* FIXME: we do this even when res != 0, is this a problem? */
+	if (copy_to_user(user, &itp, mlen))
+		res = -EFAULT;
+
+	return res;
+}
+
+/* callback function: called when a socket gets unhashed by the UDP or TCP stack */
+static void
+ip_tproxy_close(struct sock *sk, int proto)
+{
+	if (proto)
+		ip_tproxy_setsockopt_unassign(sk, proto, NULL);
+}
+
+/* fake timeout function needed by the fake conntrack entry, in theory, it never
+ * runs */
+static void
+ip_tproxy_fake_timeout(unsigned long null_ptr)
+{
+	printk("IP_TPROXY: Fake timeout called!");
+}
+
+static struct nf_hook_ops ip_tproxy_pre_ops = {
+	.hook		= ip_tproxy_fn,
+	.owner		= THIS_MODULE,
+	.pf		= PF_INET,
+	.hooknum	= NF_IP_PRE_ROUTING,
+	.priority	= -130
+};
+
+static struct nf_hook_ops ip_tproxy_post_ops = {
+	.hook		= ip_tproxy_fn,
+	.owner		= THIS_MODULE,
+	.pf		= PF_INET,
+	.hooknum	= NF_IP_POST_ROUTING,
+	.priority	= -130
+};
+
+static struct nf_hook_ops ip_tproxy_local_out_ops = {
+	.hook		= ip_tproxy_fn,
+	.owner		= THIS_MODULE,
+	.pf		= PF_INET,
+	.hooknum	= NF_IP_LOCAL_OUT,
+	.priority	= -130
+};
+
+static struct nf_sockopt_ops ip_tproxy_sockopts = {
+	.pf		= PF_INET,
+	.set_optmin	= IP_TPROXY,
+	.set_optmax	= IP_TPROXY + 1,
+	.set		= ip_tproxy_setsockopt,
+	.get_optmin	= IP_TPROXY,
+	.get_optmax	= IP_TPROXY + 1,
+	.get		= ip_tproxy_getsockopt,
+};
+
+/* init or cleanup the tproxy module */
+static int
+init_or_cleanup(int startup)
+{
+	int ret = 0;
+	int i;
+	struct proc_dir_entry *proc;
+
+	if (!startup) {
+		goto clean_all;
+	}
+
+	/* we depend on the NAT hooks being operational */
+	need_nat_hooks();
+
+	/* use our own fake conntrack entry, which indicates that packet was
+	   tproxied, this let's us use the same -m tproxy match in our filter
+	   rules.  The original idea of using a fake conntrack entry to avoid
+	   conntracking is by Jozsef Kadlecsik */
+
+	atomic_set(&ip_tproxy_fake_ct.ct_general.use, 1);
+	ip_tproxy_fake_ct.timeout.function = ip_tproxy_fake_timeout;
+	ip_tproxy_fake_ct.status |= IPS_CONFIRMED | IPS_TPROXY | IPS_NAT_DONE_MASK;
+
+	ip_tproxy_sockref_table = kmem_cache_create("ip_tproxy", sizeof(struct ip_tproxy_sockref), 0,
+						    SLAB_HWCACHE_ALIGN, NULL, NULL);
+
+	if (!ip_tproxy_sockref_table) {
+		ret = -ENOMEM;
+		goto clean_nothing;
+	}
+
+	if (hashsize)
+		ip_tproxy_htable_size = hashsize;
+	else
+		ip_tproxy_htable_size = 127;
+
+	ip_tproxy_bylocal = (struct list_head *) vmalloc(sizeof(struct list_head) *
+							 ip_tproxy_htable_size * 2);
+	if (!ip_tproxy_bylocal) {
+		ret = -ENOMEM;
+		goto clean_sockref_table;
+	}
+	ip_tproxy_byforeign = (struct list_head *) ip_tproxy_bylocal + ip_tproxy_htable_size;
+
+	for (i = 0; i < ip_tproxy_htable_size; i++) {
+		INIT_LIST_HEAD(&ip_tproxy_bylocal[i]);
+		INIT_LIST_HEAD(&ip_tproxy_byforeign[i]);
+	}
+
+	proc = proc_net_create("tproxy", 0, NULL);
+	if (!proc) goto clean_sockref_hash;
+	proc->proc_fops = &ip_tproxy_file_ops;
+
+	ret = ipt_register_table(&tproxy_table, &initial_table.repl);
+	if (ret < 0) {
+		printk("IP_TPROXY: can't register tproxy table.\n");
+		goto clean_proc;
+	}
+
+	ret = nf_register_hook(&ip_tproxy_local_out_ops);
+	if (ret < 0) {
+		printk("IP_TPROXY: can't register local out hook.\n");
+		goto clean_table;
+	}
+
+	ret = nf_register_hook(&ip_tproxy_post_ops);
+	if (ret < 0) {
+		printk("IP_TPROXY: can't register postrouting hook.\n");
+		goto clean_loops;
+	}
+
+	ret = nf_register_hook(&ip_tproxy_pre_ops);
+	if (ret < 0) {
+		printk("IP_TPROXY: can't register prerouting hook.\n");
+		goto clean_postops;
+	}
+
+	nf_register_sockopt(&ip_tproxy_sockopts);
+
+	ip_tproxy_udp_unhashed = ip_tproxy_close;
+	ip_tproxy_tcp_unhashed = ip_tproxy_close;
+
+	/* initialize confirm and destroy callbacks */
+	ip_conntrack_confirmed = ip_tproxy_confirmed;
+	ip_conntrack_destroyed_old = ip_conntrack_destroyed;
+	ip_conntrack_destroyed = ip_tproxy_conntrack_destroyed;
+
+	printk("IP_TPROXY: Transparent proxy support initialized 2.0.6\n"
+	       "IP_TPROXY: Copyright (c) 2002-2006 BalaBit IT Ltd.\n");
+	return ret;
+
+ clean_all:
+	ip_conntrack_destroyed = ip_conntrack_destroyed_old;
+	ip_conntrack_confirmed = NULL;
+
+	ip_tproxy_udp_unhashed = NULL;
+	ip_tproxy_tcp_unhashed = NULL;
+
+	nf_unregister_sockopt(&ip_tproxy_sockopts);
+
+	nf_unregister_hook(&ip_tproxy_pre_ops);
+
+ clean_postops:
+	nf_unregister_hook(&ip_tproxy_post_ops);
+
+ clean_loops:
+	nf_unregister_hook(&ip_tproxy_local_out_ops);
+
+ clean_table:
+	ipt_unregister_table(&tproxy_table);
+
+ clean_proc:
+	proc_net_remove("tproxy");
+
+ clean_sockref_hash:
+	ip_tproxy_sockref_table_free();
+	vfree(ip_tproxy_bylocal);
+
+ clean_sockref_table:
+	kmem_cache_destroy(ip_tproxy_sockref_table);
+
+ clean_nothing:
+	return ret;
+}
+
+static int __init init(void)
+{
+	return init_or_cleanup(1);
+}
+
+static void __exit fini(void)
+{
+	init_or_cleanup(0);
+}
+
+module_init(init);
+module_exit(fini);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Balázs Scheidler <bazsi@balabit.hu>");
+MODULE_DESCRIPTION("Netfilter transparent proxy core module.");
--- /dev/null	2011-06-03 14:51:38.633053002 +0200
+++ linux-2.6.20.14-fbx/net/ipv4/netfilter/ipt_TPROXY.c	2011-09-26 15:07:56.618834031 +0200
@@ -0,0 +1,136 @@
+/*
+ * Transparent proxy support for Linux/iptables
+ *
+ * Copyright (c) 2002-2004 BalaBit IT Ltd.
+ * Author: Balázs Scheidler
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+#include <linux/inetdevice.h>
+#include <net/checksum.h>
+
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_TPROXY.h>
+#include <linux/netfilter_ipv4/iptable_tproxy.h>
+
+/* determine ip address of the interface the packet came in */
+static u32
+determine_local_ip(struct sk_buff *skb, int hooknum)
+{
+	struct in_device *indev;
+	u32 ip;
+
+	if (hooknum == NF_IP_LOCAL_OUT)
+		return htonl(0x7f000001);
+
+	indev = in_dev_get(skb->dev);
+
+	if (!indev) {
+		printk(KERN_WARNING "IP_TPROXY: No IP protocol on incoming "
+		       "interface during redirect, dropping packet.\n");
+		return 0;
+	}
+	if (!indev->ifa_list) {
+		printk(KERN_WARNING "IP_TPROXY: No IP address on incoming "
+		       "interface during redirect, dropping packet.\n");
+		in_dev_put(indev);
+		return 0;
+	}
+
+	ip = indev->ifa_list->ifa_local;
+	in_dev_put(indev);
+
+	return ip;
+}
+
+static unsigned int
+target(struct sk_buff **pskb,
+       const struct net_device *in,
+       const struct net_device *out,
+       unsigned int hooknum,
+       const struct xt_target *target,
+       const void *targinfo)
+{
+	const struct ipt_tproxy_target_info *info = targinfo;
+	struct ip_tproxy_sockref sr;
+	u16 *ports, _ports[2];
+	struct iphdr *iph = (*pskb)->nh.iph;
+
+	/* TCP/UDP only */
+	if ((iph->protocol != IPPROTO_TCP) &&
+	    (iph->protocol != IPPROTO_UDP))
+		return NF_ACCEPT;
+
+	/* get ports */
+	ports = skb_header_pointer(*pskb, iph->ihl * 4,
+				   sizeof(_ports), &_ports);
+	if (ports == NULL)
+		return NF_DROP;
+
+	/* set up fake sockref */
+	memset(&sr, 0, sizeof(sr));
+	sr.proto = iph->protocol;
+
+	/* use the original address/port if none is specified in the rule */
+	if (info->laddr)
+		sr.laddr = info->laddr;
+	else
+		sr.laddr = determine_local_ip(*pskb, hooknum);
+
+	if (info->lport)
+		sr.lport = info->lport;
+	else
+		sr.lport = ports[1];
+
+	/* set up mapping */
+	return ip_tproxy_setup_nat(pskb, hooknum, &sr, 0);
+}
+
+static int
+checkentry(const char *tablename,
+	   const void *e,
+	   const struct xt_target *target,
+           void *targinfo,
+           unsigned int hook_mask)
+{
+	if (strcmp(tablename, "tproxy") != 0) {
+		printk(KERN_WARNING "TPROXY: can only be called from \"tproxy\" table, not \"%s\"\n", tablename);
+		return 0;
+	}
+
+	return 1;
+}
+
+static struct ipt_target ipt_tproxy_reg = {
+	.name		= "TPROXY",
+	.target		= target,
+	.targetsize	= sizeof(struct ipt_tproxy_target_info),
+	.checkentry	= checkentry,
+	.me		= THIS_MODULE,
+};
+
+static int __init init(void)
+{
+	if (ipt_register_target(&ipt_tproxy_reg))
+		return -EINVAL;
+
+	return 0;
+}
+
+static void __exit fini(void)
+{
+	ipt_unregister_target(&ipt_tproxy_reg);
+}
+
+module_init(init);
+module_exit(fini);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Balázs Scheidler <bazsi@balabit.hu>");
+MODULE_DESCRIPTION("Netfilter transparent proxy TPROXY target module.");
