Merge branch 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus

* 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus: (28 commits)
  [MIPS] Rework cobalt_board_id
  [MIPS] Use RTC_CMOS for Cobalt
  [MIPS] Use platform_device for Cobalt UART
  [MIPS] Separate Alchemy processor based boards config
  [MIPS] Fix build error in atomic64_cmpxchg
  [MIPS] Run checksyscalls for N32 and O32 ABI
  [MIPS] tlbex: use __maybe_unused
  [MIPS] excite: use __maybe_unused
  [MIPS] Add extern cobalt_board_id
  [MIPS] Remove unused CONFIG_TOSHIBA_BOARDS
  [MIPS] Rename tb0229_defconfig to tb0219_defconfig
  [MIPS] Update tb0229_defconfig; add CONFIG_GPIO_TB0219.
  [MIPS] Add minimum defconfig for RBHMA4200
  [MIPS] SB1: Build fix.
  [MIPS] Drop __devinit tag from allocate_irqno() and free_irqno()
  [MIPS] clocksource: use CLOCKSOURCE_MASK() macro
  [MIPS] Remove LIMITED_DMA support
  [MIPS] Remove Momenco Jaguar ATX support
  [MIPS] Remove Momenco Ocelot G support
  [MIPS] FPU hazard handling
  ...
diff --git a/Documentation/SubmitChecklist b/Documentation/SubmitChecklist
index 6491b2c..3af3e65 100644
--- a/Documentation/SubmitChecklist
+++ b/Documentation/SubmitChecklist
@@ -73,9 +73,9 @@
     If the new code is substantial, addition of subsystem-specific fault
     injection might be appropriate.
 
-22: Newly-added code has been compiled with `gcc -W'.  This will generate
-    lots of noise, but is good for finding bugs like "warning: comparison
-    between signed and unsigned".
+22: Newly-added code has been compiled with `gcc -W' (use "make
+    EXTRA_CFLAGS=-W").  This will generate lots of noise, but is good for
+    finding bugs like "warning: comparison between signed and unsigned".
 
 23: Tested after it has been merged into the -mm patchset to make sure
     that it still works with all of the other queued patches and various
diff --git a/Documentation/gpio.txt b/Documentation/gpio.txt
index f8528db..e8be0ab 100644
--- a/Documentation/gpio.txt
+++ b/Documentation/gpio.txt
@@ -66,7 +66,9 @@
 used for several very different kinds of GPIO controller.
 
 That said, if the convention is supported on their platform, drivers should
-use it when possible:
+use it when possible.  Platforms should declare GENERIC_GPIO support in
+Kconfig (boolean true), which multi-platform drivers can depend on when
+using the include file:
 
 	#include <asm/gpio.h>
 
diff --git a/arch/frv/kernel/gdb-stub.c b/arch/frv/kernel/gdb-stub.c
index 9550f37..1e7a101 100644
--- a/arch/frv/kernel/gdb-stub.c
+++ b/arch/frv/kernel/gdb-stub.c
@@ -1195,7 +1195,7 @@
 /*
  *
  */
-static void __attribute__((unused)) gdbstub_show_regs(void)
+static void __maybe_unused gdbstub_show_regs(void)
 {
 	unsigned long *reg;
 	int loop;
@@ -1223,7 +1223,7 @@
 /*
  * dump debugging regs
  */
-static void __attribute__((unused)) gdbstub_dump_debugregs(void)
+static void __maybe_unused gdbstub_dump_debugregs(void)
 {
 	gdbstub_printk("DCR    %08lx  ", __debug_status.dcr);
 	gdbstub_printk("BRR    %08lx\n", __debug_status.brr);
@@ -2079,25 +2079,25 @@
  * GDB wants to call malloc() and free() to allocate memory for calling kernel
  * functions directly from its command line
  */
-static void *malloc(size_t size) __attribute__((unused));
+static void *malloc(size_t size) __maybe_unused;
 static void *malloc(size_t size)
 {
 	return kmalloc(size, GFP_ATOMIC);
 }
 
-static void free(void *p) __attribute__((unused));
+static void free(void *p) __maybe_unused;
 static void free(void *p)
 {
 	kfree(p);
 }
 
-static uint32_t ___get_HSR0(void) __attribute__((unused));
+static uint32_t ___get_HSR0(void) __maybe_unused;
 static uint32_t ___get_HSR0(void)
 {
 	return __get_HSR(0);
 }
 
-static uint32_t ___set_HSR0(uint32_t x) __attribute__((unused));
+static uint32_t ___set_HSR0(uint32_t x) __maybe_unused;
 static uint32_t ___set_HSR0(uint32_t x)
 {
 	__set_HSR(0, x);
diff --git a/arch/h8300/kernel/syscalls.S b/arch/h8300/kernel/syscalls.S
index dab98fd..54e21c3 100644
--- a/arch/h8300/kernel/syscalls.S
+++ b/arch/h8300/kernel/syscalls.S
@@ -31,7 +31,7 @@
 	.long SYMBOL_NAME(sys_mknod)
 	.long SYMBOL_NAME(sys_chmod)		/* 15 */
 	.long SYMBOL_NAME(sys_chown16)
-	.long SYMBOL_NAME(sys_ni_syscall)				/* old break syscall holder */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* old break syscall holder */
 	.long SYMBOL_NAME(sys_stat)
 	.long SYMBOL_NAME(sys_lseek)
 	.long SYMBOL_NAME(sys_getpid)		/* 20 */
@@ -45,11 +45,11 @@
 	.long SYMBOL_NAME(sys_fstat)
 	.long SYMBOL_NAME(sys_pause)
 	.long SYMBOL_NAME(sys_utime)		/* 30 */
-	.long SYMBOL_NAME(sys_ni_syscall)				/* old stty syscall holder */
-	.long SYMBOL_NAME(sys_ni_syscall)				/* old gtty syscall holder */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* old stty syscall holder */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* old gtty syscall holder */
 	.long SYMBOL_NAME(sys_access)
 	.long SYMBOL_NAME(sys_nice)
-	.long SYMBOL_NAME(sys_ni_syscall)	/* 35 */		/* old ftime syscall holder */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* 35 old ftime syscall holder */
 	.long SYMBOL_NAME(sys_sync)
 	.long SYMBOL_NAME(sys_kill)
 	.long SYMBOL_NAME(sys_rename)
@@ -58,7 +58,7 @@
 	.long SYMBOL_NAME(sys_dup)
 	.long SYMBOL_NAME(sys_pipe)
 	.long SYMBOL_NAME(sys_times)
-	.long SYMBOL_NAME(sys_ni_syscall)				/* old prof syscall holder */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* old prof syscall holder */
 	.long SYMBOL_NAME(sys_brk)		/* 45 */
 	.long SYMBOL_NAME(sys_setgid16)
 	.long SYMBOL_NAME(sys_getgid16)
@@ -66,13 +66,13 @@
 	.long SYMBOL_NAME(sys_geteuid16)
 	.long SYMBOL_NAME(sys_getegid16)	/* 50 */
 	.long SYMBOL_NAME(sys_acct)
-	.long SYMBOL_NAME(sys_umount)					/* recycled never used phys() */
-	.long SYMBOL_NAME(sys_ni_syscall)				/* old lock syscall holder */
+	.long SYMBOL_NAME(sys_umount)		/* recycled never used phys() */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* old lock syscall holder */
 	.long SYMBOL_NAME(sys_ioctl)
 	.long SYMBOL_NAME(sys_fcntl)		/* 55 */
-	.long SYMBOL_NAME(sys_ni_syscall)				/* old mpx syscall holder */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* old mpx syscall holder */
 	.long SYMBOL_NAME(sys_setpgid)
-	.long SYMBOL_NAME(sys_ni_syscall)				/* old ulimit syscall holder */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* old ulimit syscall holder */
 	.long SYMBOL_NAME(sys_ni_syscall)
 	.long SYMBOL_NAME(sys_umask)		/* 60 */
 	.long SYMBOL_NAME(sys_chroot)
@@ -112,7 +112,7 @@
 	.long SYMBOL_NAME(sys_fchown16)		/* 95 */
 	.long SYMBOL_NAME(sys_getpriority)
 	.long SYMBOL_NAME(sys_setpriority)
-	.long SYMBOL_NAME(sys_ni_syscall)				/* old profil syscall holder */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* old profil syscall holder */
 	.long SYMBOL_NAME(sys_statfs)
 	.long SYMBOL_NAME(sys_fstatfs)		/* 100 */
 	.long SYMBOL_NAME(sys_ni_syscall)	/* ioperm for i386 */
@@ -202,8 +202,8 @@
 	.long SYMBOL_NAME(sys_capset)           /* 185 */
 	.long SYMBOL_NAME(sys_sigaltstack)
 	.long SYMBOL_NAME(sys_sendfile)
-	.long SYMBOL_NAME(sys_ni_syscall)		/* streams1 */
-	.long SYMBOL_NAME(sys_ni_syscall)		/* streams2 */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* streams1 */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* streams2 */
 	.long SYMBOL_NAME(sys_vfork)            /* 190 */
 	.long SYMBOL_NAME(sys_getrlimit)
 	.long SYMBOL_NAME(sys_mmap2)
@@ -236,10 +236,10 @@
 	.long SYMBOL_NAME(sys_ni_syscall)
 	.long SYMBOL_NAME(sys_getdents64)	/* 220 */
 	.long SYMBOL_NAME(sys_fcntl64)
-	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for TUX */
-	.long SYMBOL_NAME(sys_ni_syscall)
+	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved TUX */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved Security */
 	.long SYMBOL_NAME(sys_gettid)
-	.long SYMBOL_NAME(sys_ni_syscall)	/* 225 */ /* sys_readahead */
+	.long SYMBOL_NAME(sys_readahead)	/* 225 */
 	.long SYMBOL_NAME(sys_setxattr)
 	.long SYMBOL_NAME(sys_lsetxattr)
 	.long SYMBOL_NAME(sys_fsetxattr)
@@ -257,8 +257,8 @@
 	.long SYMBOL_NAME(sys_futex)		/* 240 */
 	.long SYMBOL_NAME(sys_sched_setaffinity)
 	.long SYMBOL_NAME(sys_sched_getaffinity)
-	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_set_thread_area */
-	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_get_thread_area */
+	.long SYMBOL_NAME(sys_ni_syscall)
+	.long SYMBOL_NAME(sys_ni_syscall)
 	.long SYMBOL_NAME(sys_io_setup)		/* 245 */
 	.long SYMBOL_NAME(sys_io_destroy)
 	.long SYMBOL_NAME(sys_io_getevents)
@@ -288,8 +288,8 @@
 	.long SYMBOL_NAME(sys_utimes)
  	.long SYMBOL_NAME(sys_fadvise64_64)
 	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_vserver */
-	.long SYMBOL_NAME(sys_mbind)
-	.long SYMBOL_NAME(sys_get_mempolicy)
+	.long SYMBOL_NAME(sys_ni_syscall)
+	.long SYMBOL_NAME(sys_get_mempolicy)	/* 275 */
 	.long SYMBOL_NAME(sys_set_mempolicy)
 	.long SYMBOL_NAME(sys_mq_open)
 	.long SYMBOL_NAME(sys_mq_unlink)
@@ -297,16 +297,42 @@
 	.long SYMBOL_NAME(sys_mq_timedreceive)	/* 280 */
 	.long SYMBOL_NAME(sys_mq_notify)
 	.long SYMBOL_NAME(sys_mq_getsetattr)
-	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for kexec */
 	.long SYMBOL_NAME(sys_waitid)
-	.long SYMBOL_NAME(sys_ni_syscall)	/* 285 */ /* available */
-	.long SYMBOL_NAME(sys_add_key)
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_kexec_load */
+	.long SYMBOL_NAME(sys_add_key) 		/* 285 */
 	.long SYMBOL_NAME(sys_request_key)
 	.long SYMBOL_NAME(sys_keyctl)
-
-	.rept NR_syscalls-(.-SYMBOL_NAME(sys_call_table))/4
-		.long SYMBOL_NAME(sys_ni_syscall)
-	.endr
+	.long SYMBOL_NAME(sys_ioprio_set)
+	.long SYMBOL_NAME(sys_ioprio_get)	/* 290 */
+	.long SYMBOL_NAME(sys_inotify_init)
+	.long SYMBOL_NAME(sys_inotify_add_watch)
+	.long SYMBOL_NAME(sys_inotify_rm_watch)
+	.long SYMBOL_NAME(sys_migrate_pages)
+	.long SYMBOL_NAME(sys_openat)		/* 295 */
+	.long SYMBOL_NAME(sys_mkdirat)
+	.long SYMBOL_NAME(sys_mknodat)
+	.long SYMBOL_NAME(sys_fchownat)
+	.long SYMBOL_NAME(sys_futimesat)
+	.long SYMBOL_NAME(sys_fstatat64)	/* 300 */
+	.long SYMBOL_NAME(sys_unlinkat)
+	.long SYMBOL_NAME(sys_renameat)
+	.long SYMBOL_NAME(sys_linkat)
+	.long SYMBOL_NAME(sys_symlinkat)
+	.long SYMBOL_NAME(sys_readlinkat)	/* 305 */
+	.long SYMBOL_NAME(sys_fchmodat)
+	.long SYMBOL_NAME(sys_faccessat)
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_pselect6 */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_ppoll */
+	.long SYMBOL_NAME(sys_unshare)		/* 310 */
+	.long SYMBOL_NAME(sys_set_robust_list)
+	.long SYMBOL_NAME(sys_get_robust_list)
+	.long SYMBOL_NAME(sys_splice)
+	.long SYMBOL_NAME(sys_sync_file_range)
+	.long SYMBOL_NAME(sys_tee)		/* 315 */
+	.long SYMBOL_NAME(sys_vmsplice)
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_move_pages */
+	.long SYMBOL_NAME(sys_getcpu)
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_epoll_pwait */
 
 	.macro	call_sp addr
 	mov.l	#SYMBOL_NAME(\addr),er6
diff --git a/arch/i386/kernel/syscall_table.S b/arch/i386/kernel/syscall_table.S
index 0772678..bf6adce 100644
--- a/arch/i386/kernel/syscall_table.S
+++ b/arch/i386/kernel/syscall_table.S
@@ -320,3 +320,6 @@
 	.long sys_getcpu
 	.long sys_epoll_pwait
 	.long sys_utimensat		/* 320 */
+	.long sys_signalfd
+	.long sys_timerfd
+	.long sys_eventfd
diff --git a/arch/ia64/ia32/audit.c b/arch/ia64/ia32/audit.c
index 92d7d0c..8850fe4 100644
--- a/arch/ia64/ia32/audit.c
+++ b/arch/ia64/ia32/audit.c
@@ -20,6 +20,11 @@
 ~0U
 };
 
+unsigned ia32_signal_class[] = {
+#include <asm-generic/audit_signal.h>
+~0U
+};
+
 int ia32_classify_syscall(unsigned syscall)
 {
 	switch(syscall) {
diff --git a/arch/ia64/kernel/audit.c b/arch/ia64/kernel/audit.c
index 0468255..f3802ae 100644
--- a/arch/ia64/kernel/audit.c
+++ b/arch/ia64/kernel/audit.c
@@ -23,6 +23,20 @@
 ~0U
 };
 
+static unsigned signal_class[] = {
+#include <asm-generic/audit_signal.h>
+~0U
+};
+
+int audit_classify_arch(int arch)
+{
+#ifdef CONFIG_IA32_SUPPORT
+	if (arch == AUDIT_ARCH_I386)
+		return 1;
+#endif
+	return 0;
+}
+
 int audit_classify_syscall(int abi, unsigned syscall)
 {
 #ifdef CONFIG_IA32_SUPPORT
@@ -49,15 +63,18 @@
 	extern __u32 ia32_write_class[];
 	extern __u32 ia32_read_class[];
 	extern __u32 ia32_chattr_class[];
+	extern __u32 ia32_signal_class[];
 	audit_register_class(AUDIT_CLASS_WRITE_32, ia32_write_class);
 	audit_register_class(AUDIT_CLASS_READ_32, ia32_read_class);
 	audit_register_class(AUDIT_CLASS_DIR_WRITE_32, ia32_dir_class);
 	audit_register_class(AUDIT_CLASS_CHATTR_32, ia32_chattr_class);
+	audit_register_class(AUDIT_CLASS_SIGNAL_32, ia32_signal_class);
 #endif
 	audit_register_class(AUDIT_CLASS_WRITE, write_class);
 	audit_register_class(AUDIT_CLASS_READ, read_class);
 	audit_register_class(AUDIT_CLASS_DIR_WRITE, dir_class);
 	audit_register_class(AUDIT_CLASS_CHATTR, chattr_class);
+	audit_register_class(AUDIT_CLASS_SIGNAL, signal_class);
 	return 0;
 }
 
diff --git a/arch/m32r/Kconfig b/arch/m32r/Kconfig
index 9740d6b..c3bb8a75 100644
--- a/arch/m32r/Kconfig
+++ b/arch/m32r/Kconfig
@@ -241,6 +241,10 @@
 	bool
 	default y
 
+config SCHED_NO_NO_OMIT_FRAME_POINTER
+        bool
+        default y
+
 config PREEMPT
 	bool "Preemptible Kernel"
 	help
diff --git a/arch/m32r/mm/mmu.S b/arch/m32r/mm/mmu.S
index 8bb74b1..49a6d16 100644
--- a/arch/m32r/mm/mmu.S
+++ b/arch/m32r/mm/mmu.S
@@ -163,7 +163,8 @@
 
 	; pte_data = (unsigned long)pte_val(*pte);
 	ld	r2, @r3			; r2: pte data
-	or3	r2, r2, #2		; _PAGE_PRESENT(=2)
+	and3	r3, r2, #2		; _PAGE_PRESENT(=2) check
+	beqz	r3, 3f
 
 	.fillinsn
 5:
@@ -264,11 +265,8 @@
 ;
 	and3	r1, r1, #0xeff
 	ldi	r4, #611		; _KERNPG_TABLE(=611)
-	beq	r1, r4, 4f		; !pmd_bad(*pmd) ?
-	.fillinsn
-3:
-	ldi	r1, #0			; r1: pte_data = 0
-	bra	5f
+	bne	r1, r4, 3f		; !pmd_bad(*pmd) ?
+
 	.fillinsn
 4:
 	; pte = pte_offset(pmd, address);
@@ -282,8 +280,10 @@
 	add	r4, r3			; r4: pte
 	; pte_data = (unsigned long)pte_val(*pte);
 	ld	r1, @r4			; r1: pte_data
-	.fillinsn
+	and3	r3, r1, #2		; _PAGE_PRESENT(=2) check
+	beqz	r3, 3f
 
+	.fillinsn
 ;; set tlb
 ; r0: address, r1: pte_data, r2: entry
 ; r3,r4: (free)
@@ -295,8 +295,7 @@
 	and3	r4, r4, #(MMU_CONTEXT_ASID_MASK)
 	or	r3, r4
 	st	r3, @r2
-	or3	r4, r1, #2		; _PAGE_PRESENT(=2)
-	st	r4, @(4,r2)		; set_tlb_data(entry, pte_data);
+	st	r1, @(4,r2)		; set_tlb_data(entry, pte_data);
 
 	ld	r4, @sp+
 	ld	r3, @sp+
@@ -306,6 +305,11 @@
 	ld	sp, @sp+
 	rte
 
+	.fillinsn
+3:
+	ldi	r1, #2			; r1: pte_data = 0 | _PAGE_PRESENT(=2)
+	bra	5b
+
 #else
 #error unknown isa configuration
 #endif
diff --git a/arch/powerpc/kernel/audit.c b/arch/powerpc/kernel/audit.c
index 7fe5e63..a4dab7c 100644
--- a/arch/powerpc/kernel/audit.c
+++ b/arch/powerpc/kernel/audit.c
@@ -23,6 +23,20 @@
 ~0U
 };
 
+static unsigned signal_class[] = {
+#include <asm-generic/audit_signal.h>
+~0U
+};
+
+int audit_classify_arch(int arch)
+{
+#ifdef CONFIG_PPC64
+	if (arch == AUDIT_ARCH_PPC)
+		return 1;
+#endif
+	return 0;
+}
+
 int audit_classify_syscall(int abi, unsigned syscall)
 {
 #ifdef CONFIG_PPC64
@@ -51,15 +65,18 @@
 	extern __u32 ppc32_write_class[];
 	extern __u32 ppc32_read_class[];
 	extern __u32 ppc32_chattr_class[];
+	extern __u32 ppc32_signal_class[];
 	audit_register_class(AUDIT_CLASS_WRITE_32, ppc32_write_class);
 	audit_register_class(AUDIT_CLASS_READ_32, ppc32_read_class);
 	audit_register_class(AUDIT_CLASS_DIR_WRITE_32, ppc32_dir_class);
 	audit_register_class(AUDIT_CLASS_CHATTR_32, ppc32_chattr_class);
+	audit_register_class(AUDIT_CLASS_SIGNAL_32, ppc32_signal_class);
 #endif
 	audit_register_class(AUDIT_CLASS_WRITE, write_class);
 	audit_register_class(AUDIT_CLASS_READ, read_class);
 	audit_register_class(AUDIT_CLASS_DIR_WRITE, dir_class);
 	audit_register_class(AUDIT_CLASS_CHATTR, chattr_class);
+	audit_register_class(AUDIT_CLASS_SIGNAL, signal_class);
 	return 0;
 }
 
diff --git a/arch/powerpc/kernel/compat_audit.c b/arch/powerpc/kernel/compat_audit.c
index 640d4bb..108ff14 100644
--- a/arch/powerpc/kernel/compat_audit.c
+++ b/arch/powerpc/kernel/compat_audit.c
@@ -21,6 +21,11 @@
 ~0U
 };
 
+unsigned ppc32_signal_class[] = {
+#include <asm-generic/audit_signal.h>
+~0U
+};
+
 int ppc32_classify_syscall(unsigned syscall)
 {
 	switch(syscall) {
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 9ed4931..068377a 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -173,7 +173,7 @@
 		lv1_get_version_info(&tmp);
 	}
 
-	hard_irq_enable();
+	__hard_irq_enable();
 }
 #endif /* CONFIG_PPC64 */
 
diff --git a/arch/powerpc/kernel/swsusp.c b/arch/powerpc/kernel/swsusp.c
index 064a7ba..77b7b34 100644
--- a/arch/powerpc/kernel/swsusp.c
+++ b/arch/powerpc/kernel/swsusp.c
@@ -36,8 +36,4 @@
 #ifdef CONFIG_PPC32
 	set_context(current->active_mm->context.id, current->active_mm->pgd);
 #endif
-
-#ifdef CONFIG_PPC64
-	hard_irq_enable();
-#endif
 }
diff --git a/arch/powerpc/platforms/cell/pervasive.c b/arch/powerpc/platforms/cell/pervasive.c
index 8c20f0f..812bf56 100644
--- a/arch/powerpc/platforms/cell/pervasive.c
+++ b/arch/powerpc/platforms/cell/pervasive.c
@@ -43,12 +43,10 @@
 	unsigned long ctrl, thread_switch_control;
 
 	/*
-	 * We need to hard disable interrupts, but we also need to mark them
-	 * hard disabled in the PACA so that the local_irq_enable() done by
-	 * our caller upon return propertly hard enables.
+	 * We need to hard disable interrupts, the local_irq_enable() done by
+	 * our caller upon return will hard re-enable.
 	 */
 	hard_irq_disable();
-	get_paca()->hard_enabled = 0;
 
 	ctrl = mfspr(SPRN_CTRLF);
 
diff --git a/arch/s390/kernel/audit.c b/arch/s390/kernel/audit.c
index 0741d91..d1c76fe 100644
--- a/arch/s390/kernel/audit.c
+++ b/arch/s390/kernel/audit.c
@@ -23,6 +23,20 @@
 ~0U
 };
 
+static unsigned signal_class[] = {
+#include <asm-generic/audit_signal.h>
+~0U
+};
+
+int audit_classify_arch(int arch)
+{
+#ifdef CONFIG_COMPAT
+	if (arch == AUDIT_ARCH_S390)
+		return 1;
+#endif
+	return 0;
+}
+
 int audit_classify_syscall(int abi, unsigned syscall)
 {
 #ifdef CONFIG_COMPAT
@@ -51,15 +65,18 @@
 	extern __u32 s390_write_class[];
 	extern __u32 s390_read_class[];
 	extern __u32 s390_chattr_class[];
+	extern __u32 s390_signal_class[];
 	audit_register_class(AUDIT_CLASS_WRITE_32, s390_write_class);
 	audit_register_class(AUDIT_CLASS_READ_32, s390_read_class);
 	audit_register_class(AUDIT_CLASS_DIR_WRITE_32, s390_dir_class);
 	audit_register_class(AUDIT_CLASS_CHATTR_32, s390_chattr_class);
+	audit_register_class(AUDIT_CLASS_SIGNAL_32, s390_signal_class);
 #endif
 	audit_register_class(AUDIT_CLASS_WRITE, write_class);
 	audit_register_class(AUDIT_CLASS_READ, read_class);
 	audit_register_class(AUDIT_CLASS_DIR_WRITE, dir_class);
 	audit_register_class(AUDIT_CLASS_CHATTR, chattr_class);
+	audit_register_class(AUDIT_CLASS_SIGNAL, signal_class);
 	return 0;
 }
 
diff --git a/arch/s390/kernel/compat_audit.c b/arch/s390/kernel/compat_audit.c
index 16d9436..0569f51 100644
--- a/arch/s390/kernel/compat_audit.c
+++ b/arch/s390/kernel/compat_audit.c
@@ -21,6 +21,11 @@
 ~0U
 };
 
+unsigned s390_signal_class[] = {
+#include <asm-generic/audit_signal.h>
+~0U
+};
+
 int s390_classify_syscall(unsigned syscall)
 {
 	switch(syscall) {
diff --git a/arch/sparc64/kernel/audit.c b/arch/sparc64/kernel/audit.c
index aef19cc..24d7f4b 100644
--- a/arch/sparc64/kernel/audit.c
+++ b/arch/sparc64/kernel/audit.c
@@ -23,6 +23,20 @@
 ~0U
 };
 
+static unsigned signal_class[] = {
+#include <asm-generic/audit_signal.h>
+~0U
+};
+
+int audit_classify_arch(int arch)
+{
+#ifdef CONFIG_SPARC32_COMPAT
+	if (arch == AUDIT_ARCH_SPARC)
+		return 1;
+#endif
+	return 0;
+}
+
 int audit_classify_syscall(int abi, unsigned syscall)
 {
 #ifdef CONFIG_SPARC32_COMPAT
@@ -51,15 +65,18 @@
 	extern __u32 sparc32_write_class[];
 	extern __u32 sparc32_read_class[];
 	extern __u32 sparc32_chattr_class[];
+	extern __u32 sparc32_signal_class[];
 	audit_register_class(AUDIT_CLASS_WRITE_32, sparc32_write_class);
 	audit_register_class(AUDIT_CLASS_READ_32, sparc32_read_class);
 	audit_register_class(AUDIT_CLASS_DIR_WRITE_32, sparc32_dir_class);
 	audit_register_class(AUDIT_CLASS_CHATTR_32, sparc32_chattr_class);
+	audit_register_class(AUDIT_CLASS_SIGNAL_32, sparc32_signal_class);
 #endif
 	audit_register_class(AUDIT_CLASS_WRITE, write_class);
 	audit_register_class(AUDIT_CLASS_READ, read_class);
 	audit_register_class(AUDIT_CLASS_DIR_WRITE, dir_class);
 	audit_register_class(AUDIT_CLASS_CHATTR, chattr_class);
+	audit_register_class(AUDIT_CLASS_SIGNAL, signal_class);
 	return 0;
 }
 
diff --git a/arch/sparc64/kernel/compat_audit.c b/arch/sparc64/kernel/compat_audit.c
index cca96c9..c197948 100644
--- a/arch/sparc64/kernel/compat_audit.c
+++ b/arch/sparc64/kernel/compat_audit.c
@@ -20,6 +20,11 @@
 ~0U
 };
 
+unsigned sparc32_signal_class[] = {
+#include <asm-generic/audit_signal.h>
+~0U
+};
+
 int sparc32_classify_syscall(unsigned syscall)
 {
 	switch(syscall) {
diff --git a/arch/um/Kconfig b/arch/um/Kconfig
index b9c0f30..c504312 100644
--- a/arch/um/Kconfig
+++ b/arch/um/Kconfig
@@ -277,7 +277,8 @@
 
 config KERNEL_STACK_ORDER
 	int "Kernel stack size order"
-	default 2
+	default 1 if 64BIT
+	default 0 if !64BIT
 	help
 	This option determines the size of UML kernel stacks.  They will
 	be 1 << order pages.  The default is OK unless you're running Valgrind
diff --git a/arch/um/defconfig b/arch/um/defconfig
index f938fa8..a54d0ef 100644
--- a/arch/um/defconfig
+++ b/arch/um/defconfig
@@ -86,7 +86,7 @@
 # CONFIG_MAGIC_SYSRQ is not set
 CONFIG_NEST_LEVEL=0
 # CONFIG_HIGHMEM is not set
-CONFIG_KERNEL_STACK_ORDER=2
+CONFIG_KERNEL_STACK_ORDER=0
 CONFIG_UML_REAL_TIME_CLOCK=y
 
 #
diff --git a/arch/um/include/common-offsets.h b/arch/um/include/common-offsets.h
index 5593a80..541f4a8 100644
--- a/arch/um/include/common-offsets.h
+++ b/arch/um/include/common-offsets.h
@@ -28,3 +28,5 @@
 
 /* For crypto assembler code. */
 DEFINE(crypto_tfm_ctx_offset, offsetof(struct crypto_tfm, __crt_ctx));
+
+DEFINE(UM_THREAD_SIZE, THREAD_SIZE);
diff --git a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h
index 50a4969..8d7f7c1 100644
--- a/arch/um/include/kern_util.h
+++ b/arch/um/include/kern_util.h
@@ -117,4 +117,7 @@
 
 extern void copy_sc(union uml_pt_regs *regs, void *from);
 
+unsigned long to_irq_stack(int sig, unsigned long *mask_out);
+unsigned long from_irq_stack(int nested);
+
 #endif
diff --git a/arch/um/include/os.h b/arch/um/include/os.h
index 688d181..4d9fb263 100644
--- a/arch/um/include/os.h
+++ b/arch/um/include/os.h
@@ -272,7 +272,6 @@
 
 /* util.c */
 extern void stack_protections(unsigned long address);
-extern void task_protections(unsigned long address);
 extern int raw(int fd);
 extern void setup_machinename(char *machine_out);
 extern void setup_hostinfo(char *buf, int len);
diff --git a/arch/um/kernel/dyn.lds.S b/arch/um/kernel/dyn.lds.S
index e36f92b..87a4e44 100644
--- a/arch/um/kernel/dyn.lds.S
+++ b/arch/um/kernel/dyn.lds.S
@@ -97,6 +97,8 @@
   .data           : {
     . = ALIGN(KERNEL_STACK_SIZE);		/* init_task */
     *(.data.init_task)
+    . = ALIGN(KERNEL_STACK_SIZE);
+    *(.data.init_irqstack)
     *(.data .data.* .gnu.linkonce.d.*)
     SORT(CONSTRUCTORS)
   }
diff --git a/arch/um/kernel/init_task.c b/arch/um/kernel/init_task.c
index cda91aa..d4f1d1a 100644
--- a/arch/um/kernel/init_task.c
+++ b/arch/um/kernel/init_task.c
@@ -1,5 +1,5 @@
-/* 
- * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+/*
+ * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,intel.linux}.com)
  * Licensed under the GPL
  */
 
@@ -33,28 +33,20 @@
 /*
  * Initial thread structure.
  *
- * We need to make sure that this is 16384-byte aligned due to the
+ * We need to make sure that this is aligned due to the
  * way process stacks are handled. This is done by having a special
  * "init_task" linker map entry..
  */
 
-union thread_union init_thread_union 
-__attribute__((__section__(".data.init_task"))) = 
-{ INIT_THREAD_INFO(init_task) };
+union thread_union init_thread_union
+	__attribute__((__section__(".data.init_task"))) =
+		{ INIT_THREAD_INFO(init_task) };
+
+union thread_union cpu0_irqstack
+	__attribute__((__section__(".data.init_irqstack"))) =
+		{ INIT_THREAD_INFO(init_task) };
 
 void unprotect_stack(unsigned long stack)
 {
-	os_protect_memory((void *) stack, (1 << CONFIG_KERNEL_STACK_ORDER) * PAGE_SIZE,
-		       1, 1, 0);
+	os_protect_memory((void *) stack, THREAD_SIZE, 1, 1, 0);
 }
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c
index 8f2ed36..dba04d8 100644
--- a/arch/um/kernel/irq.c
+++ b/arch/um/kernel/irq.c
@@ -1,4 +1,4 @@
-/* 
+/*
  * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
  * Licensed under the GPL
  * Derived (i.e. mostly copied) from arch/i386/kernel/irq.c:
@@ -32,6 +32,7 @@
 #include "sigio.h"
 #include "um_malloc.h"
 #include "misc_constants.h"
+#include "as-layout.h"
 
 /*
  * Generic, controller-independent functions:
@@ -53,7 +54,7 @@
 	if (i < NR_IRQS) {
 		spin_lock_irqsave(&irq_desc[i].lock, flags);
 		action = irq_desc[i].action;
-		if (!action) 
+		if (!action)
 			goto skip;
 		seq_printf(p, "%3d: ",i);
 #ifndef CONFIG_SMP
@@ -468,3 +469,113 @@
  out:
 	return err;
 }
+
+/*
+ * IRQ stack entry and exit:
+ *
+ * Unlike i386, UML doesn't receive IRQs on the normal kernel stack
+ * and switch over to the IRQ stack after some preparation.  We use
+ * sigaltstack to receive signals on a separate stack from the start.
+ * These two functions make sure the rest of the kernel won't be too
+ * upset by being on a different stack.  The IRQ stack has a
+ * thread_info structure at the bottom so that current et al continue
+ * to work.
+ *
+ * to_irq_stack copies the current task's thread_info to the IRQ stack
+ * thread_info and sets the tasks's stack to point to the IRQ stack.
+ *
+ * from_irq_stack copies the thread_info struct back (flags may have
+ * been modified) and resets the task's stack pointer.
+ *
+ * Tricky bits -
+ *
+ * What happens when two signals race each other?  UML doesn't block
+ * signals with sigprocmask, SA_DEFER, or sa_mask, so a second signal
+ * could arrive while a previous one is still setting up the
+ * thread_info.
+ *
+ * There are three cases -
+ *     The first interrupt on the stack - sets up the thread_info and
+ * handles the interrupt
+ *     A nested interrupt interrupting the copying of the thread_info -
+ * can't handle the interrupt, as the stack is in an unknown state
+ *     A nested interrupt not interrupting the copying of the
+ * thread_info - doesn't do any setup, just handles the interrupt
+ *
+ * The first job is to figure out whether we interrupted stack setup.
+ * This is done by xchging the signal mask with thread_info->pending.
+ * If the value that comes back is zero, then there is no setup in
+ * progress, and the interrupt can be handled.  If the value is
+ * non-zero, then there is stack setup in progress.  In order to have
+ * the interrupt handled, we leave our signal in the mask, and it will
+ * be handled by the upper handler after it has set up the stack.
+ *
+ * Next is to figure out whether we are the outer handler or a nested
+ * one.  As part of setting up the stack, thread_info->real_thread is
+ * set to non-NULL (and is reset to NULL on exit).  This is the
+ * nesting indicator.  If it is non-NULL, then the stack is already
+ * set up and the handler can run.
+ */
+
+static unsigned long pending_mask;
+
+unsigned long to_irq_stack(int sig, unsigned long *mask_out)
+{
+	struct thread_info *ti;
+	unsigned long mask, old;
+	int nested;
+
+	mask = xchg(&pending_mask, 1 << sig);
+	if(mask != 0){
+		/* If any interrupts come in at this point, we want to
+		 * make sure that their bits aren't lost by our
+		 * putting our bit in.  So, this loop accumulates bits
+		 * until xchg returns the same value that we put in.
+		 * When that happens, there were no new interrupts,
+		 * and pending_mask contains a bit for each interrupt
+		 * that came in.
+		 */
+		old = 1 << sig;
+		do {
+			old |= mask;
+			mask = xchg(&pending_mask, old);
+		} while(mask != old);
+		return 1;
+	}
+
+	ti = current_thread_info();
+	nested = (ti->real_thread != NULL);
+	if(!nested){
+		struct task_struct *task;
+		struct thread_info *tti;
+
+		task = cpu_tasks[ti->cpu].task;
+		tti = task_thread_info(task);
+		*ti = *tti;
+		ti->real_thread = tti;
+		task->stack = ti;
+	}
+
+	mask = xchg(&pending_mask, 0);
+	*mask_out |= mask | nested;
+	return 0;
+}
+
+unsigned long from_irq_stack(int nested)
+{
+	struct thread_info *ti, *to;
+	unsigned long mask;
+
+	ti = current_thread_info();
+
+	pending_mask = 1;
+
+	to = ti->real_thread;
+	current->stack = to;
+	ti->real_thread = NULL;
+	*to = *ti;
+
+	mask = xchg(&pending_mask, 0);
+	return mask & ~1;
+}
+
diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c
index a96ae1a..2a69a7c 100644
--- a/arch/um/kernel/skas/process.c
+++ b/arch/um/kernel/skas/process.c
@@ -163,8 +163,12 @@
 
 extern int userspace_pid[];
 
+extern char cpu0_irqstack[];
+
 int start_uml_skas(void)
 {
+	stack_protections((unsigned long) &cpu0_irqstack);
+	set_sigstack(cpu0_irqstack, THREAD_SIZE);
 	if(proc_mm)
 		userspace_pid[0] = start_userspace(0);
 
diff --git a/arch/um/kernel/tt/exec_kern.c b/arch/um/kernel/tt/exec_kern.c
index 98e2174..40126cb 100644
--- a/arch/um/kernel/tt/exec_kern.c
+++ b/arch/um/kernel/tt/exec_kern.c
@@ -57,7 +57,7 @@
 	enable_timer();
 	free_page(stack);
 	protect_memory(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1);
-	task_protections((unsigned long) current_thread);
+	stack_protections((unsigned long) current_thread);
 	force_flush_all();
 	unblock_signals();
 }
diff --git a/arch/um/kernel/tt/process_kern.c b/arch/um/kernel/tt/process_kern.c
index c631303..74347ad 100644
--- a/arch/um/kernel/tt/process_kern.c
+++ b/arch/um/kernel/tt/process_kern.c
@@ -209,7 +209,7 @@
 	if(current->mm != current->parent->mm)
 		protect_memory(uml_reserved, high_physmem - uml_reserved, 1, 
 			       1, 0, 1);
-	task_protections((unsigned long) current_thread);
+	stack_protections((unsigned long) current_thread);
 
 	free_page(current->thread.temp_stack);
 	local_irq_disable();
diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c
index 1cf954a..ecc458f 100644
--- a/arch/um/kernel/um_arch.c
+++ b/arch/um/kernel/um_arch.c
@@ -459,7 +459,7 @@
 
 	uml_postsetup();
 
-	task_protections((unsigned long) &init_thread_info);
+	stack_protections((unsigned long) &init_thread_info);
 	os_flush_stdout();
 
 	return CHOOSE_MODE(start_uml_tt(), start_uml_skas());
diff --git a/arch/um/kernel/uml.lds.S b/arch/um/kernel/uml.lds.S
index f630127..bc59f97 100644
--- a/arch/um/kernel/uml.lds.S
+++ b/arch/um/kernel/uml.lds.S
@@ -59,6 +59,8 @@
   {
     . = ALIGN(KERNEL_STACK_SIZE);		/* init_task */
     *(.data.init_task)
+    . = ALIGN(KERNEL_STACK_SIZE);
+    *(.data.init_irqstack)
     *(.data)
     *(.gnu.linkonce.d*)
     CONSTRUCTORS
diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c
index 48d4934..18e5c8b 100644
--- a/arch/um/os-Linux/signal.c
+++ b/arch/um/os-Linux/signal.c
@@ -61,15 +61,19 @@
 
 static void real_alarm_handler(int sig, struct sigcontext *sc)
 {
+	union uml_pt_regs regs;
+
 	if(sig == SIGALRM)
 		switch_timers(0);
 
-	CHOOSE_MODE_PROC(sig_handler_common_tt, sig_handler_common_skas,
-			 sig, sc);
+	if(sc != NULL)
+		copy_sc(&regs, sc);
+	regs.skas.is_user = 0;
+	unblock_signals();
+	timer_handler(sig, &regs);
 
 	if(sig == SIGALRM)
 		switch_timers(1);
-
 }
 
 void alarm_handler(int sig, struct sigcontext *sc)
@@ -113,6 +117,46 @@
 
 void (*handlers[_NSIG])(int sig, struct sigcontext *sc);
 
+void handle_signal(int sig, struct sigcontext *sc)
+{
+	unsigned long pending = 0;
+
+	do {
+		int nested, bail;
+
+		/*
+		 * pending comes back with one bit set for each
+		 * interrupt that arrived while setting up the stack,
+		 * plus a bit for this interrupt, plus the zero bit is
+		 * set if this is a nested interrupt.
+		 * If bail is true, then we interrupted another
+		 * handler setting up the stack.  In this case, we
+		 * have to return, and the upper handler will deal
+		 * with this interrupt.
+		 */
+		bail = to_irq_stack(sig, &pending);
+		if(bail)
+			return;
+
+		nested = pending & 1;
+		pending &= ~1;
+
+		while((sig = ffs(pending)) != 0){
+			sig--;
+			pending &= ~(1 << sig);
+			(*handlers[sig])(sig, sc);
+		}
+
+		/* Again, pending comes back with a mask of signals
+		 * that arrived while tearing down the stack.  If this
+		 * is non-zero, we just go back, set up the stack
+		 * again, and handle the new interrupts.
+		 */
+		if(!nested)
+			pending = from_irq_stack(nested);
+	} while(pending);
+}
+
 extern void hard_handler(int sig);
 
 void set_handler(int sig, void (*handler)(int), int flags, ...)
diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c
index 6a0e466..f9d2f85 100644
--- a/arch/um/os-Linux/skas/process.c
+++ b/arch/um/os-Linux/skas/process.c
@@ -288,7 +288,8 @@
 void userspace(union uml_pt_regs *regs)
 {
 	int err, status, op, pid = userspace_pid[0];
-	int local_using_sysemu; /*To prevent races if using_sysemu changes under us.*/
+	/* To prevent races if using_sysemu changes under us.*/
+	int local_using_sysemu;
 
 	while(1){
 		restore_registers(pid, regs);
@@ -296,7 +297,8 @@
 		/* Now we set local_using_sysemu to be used for one loop */
 		local_using_sysemu = get_using_sysemu();
 
-		op = SELECT_PTRACE_OPERATION(local_using_sysemu, singlestepping(NULL));
+		op = SELECT_PTRACE_OPERATION(local_using_sysemu,
+					     singlestepping(NULL));
 
 		err = ptrace(op, pid, 0, 0);
 		if(err)
@@ -490,8 +492,8 @@
 void new_thread(void *stack, jmp_buf *buf, void (*handler)(void))
 {
 	(*buf)[0].JB_IP = (unsigned long) handler;
-	(*buf)[0].JB_SP = (unsigned long) stack +
-		(PAGE_SIZE << UML_CONFIG_KERNEL_STACK_ORDER) - sizeof(void *);
+	(*buf)[0].JB_SP = (unsigned long) stack + UM_THREAD_SIZE -
+		sizeof(void *);
 }
 
 #define INIT_JMP_NEW_THREAD 0
@@ -533,8 +535,7 @@
 	case INIT_JMP_NEW_THREAD:
 		(*switch_buf)[0].JB_IP = (unsigned long) new_thread_handler;
 		(*switch_buf)[0].JB_SP = (unsigned long) stack +
-			(PAGE_SIZE << UML_CONFIG_KERNEL_STACK_ORDER) -
-			sizeof(void *);
+			UM_THREAD_SIZE - sizeof(void *);
 		break;
 	case INIT_JMP_CALLBACK:
 		(*cb_proc)(cb_arg);
diff --git a/arch/um/os-Linux/sys-i386/signal.c b/arch/um/os-Linux/sys-i386/signal.c
index 0d3eae5..f311609 100644
--- a/arch/um/os-Linux/sys-i386/signal.c
+++ b/arch/um/os-Linux/sys-i386/signal.c
@@ -1,15 +1,13 @@
 /*
- * Copyright (C) 2006 Jeff Dike (jdike@addtoit.com)
+ * Copyright (C) 2006 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  * Licensed under the GPL
  */
 
 #include <signal.h>
 
-extern void (*handlers[])(int sig, struct sigcontext *sc);
+extern void handle_signal(int sig, struct sigcontext *sc);
 
 void hard_handler(int sig)
 {
-	struct sigcontext *sc = (struct sigcontext *) (&sig + 1);
-
-	(*handlers[sig])(sig, sc);
+	handle_signal(sig, (struct sigcontext *) (&sig + 1));
 }
diff --git a/arch/um/os-Linux/sys-x86_64/signal.c b/arch/um/os-Linux/sys-x86_64/signal.c
index 3f369e5..82a3888 100644
--- a/arch/um/os-Linux/sys-x86_64/signal.c
+++ b/arch/um/os-Linux/sys-x86_64/signal.c
@@ -1,16 +1,16 @@
 /*
- * Copyright (C) 2006 Jeff Dike (jdike@addtoit.com)
+ * Copyright (C) 2006 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  * Licensed under the GPL
  */
 
 #include <signal.h>
 
-extern void (*handlers[])(int sig, struct sigcontext *sc);
+extern void handle_signal(int sig, struct sigcontext *sc);
 
 void hard_handler(int sig)
 {
 	struct ucontext *uc;
 	asm("movq %%rdx, %0" : "=r" (uc));
 
-	(*handlers[sig])(sig, (struct sigcontext *) &uc->uc_mcontext);
+	handle_signal(sig, (struct sigcontext *) &uc->uc_mcontext);
 }
diff --git a/arch/um/os-Linux/util.c b/arch/um/os-Linux/util.c
index c307a89..7cbcf48 100644
--- a/arch/um/os-Linux/util.c
+++ b/arch/um/os-Linux/util.c
@@ -33,25 +33,8 @@
 
 void stack_protections(unsigned long address)
 {
-	int prot = PROT_READ | PROT_WRITE | PROT_EXEC;
-
-	if(mprotect((void *) address, UM_KERN_PAGE_SIZE, prot) < 0)
-		panic("protecting stack failed, errno = %d", errno);
-}
-
-void task_protections(unsigned long address)
-{
-	unsigned long guard = address + UM_KERN_PAGE_SIZE;
-	unsigned long stack = guard + UM_KERN_PAGE_SIZE;
-	int prot = 0, pages;
-
-#ifdef notdef
-	if(mprotect((void *) stack, UM_KERN_PAGE_SIZE, prot) < 0)
-		panic("protecting guard page failed, errno = %d", errno);
-#endif
-	pages = (1 << UML_CONFIG_KERNEL_STACK_ORDER) - 2;
-	prot = PROT_READ | PROT_WRITE | PROT_EXEC;
-	if(mprotect((void *) stack, pages * UM_KERN_PAGE_SIZE, prot) < 0)
+	if(mprotect((void *) address, UM_THREAD_SIZE,
+		    PROT_READ | PROT_WRITE | PROT_EXEC) < 0)
 		panic("protecting stack failed, errno = %d", errno);
 }
 
@@ -72,7 +55,7 @@
 
 	/* XXX tcsetattr could have applied only some changes
 	 * (and cfmakeraw() is a set of changes) */
-	return(0);
+	return 0;
 }
 
 void setup_machinename(char *machine_out)
diff --git a/arch/x86_64/ia32/audit.c b/arch/x86_64/ia32/audit.c
index 92d7d0c..8850fe4 100644
--- a/arch/x86_64/ia32/audit.c
+++ b/arch/x86_64/ia32/audit.c
@@ -20,6 +20,11 @@
 ~0U
 };
 
+unsigned ia32_signal_class[] = {
+#include <asm-generic/audit_signal.h>
+~0U
+};
+
 int ia32_classify_syscall(unsigned syscall)
 {
 	switch(syscall) {
diff --git a/arch/x86_64/ia32/ia32entry.S b/arch/x86_64/ia32/ia32entry.S
index f210683..52be79b 100644
--- a/arch/x86_64/ia32/ia32entry.S
+++ b/arch/x86_64/ia32/ia32entry.S
@@ -716,4 +716,7 @@
 	.quad sys_getcpu
 	.quad sys_epoll_pwait
 	.quad compat_sys_utimensat	/* 320 */
+	.quad sys_signalfd
+	.quad sys_timerfd
+	.quad sys_eventfd
 ia32_syscall_end:		
diff --git a/arch/x86_64/kernel/audit.c b/arch/x86_64/kernel/audit.c
index 21f3338..06d3e5a 100644
--- a/arch/x86_64/kernel/audit.c
+++ b/arch/x86_64/kernel/audit.c
@@ -23,6 +23,20 @@
 ~0U
 };
 
+static unsigned signal_class[] = {
+#include <asm-generic/audit_signal.h>
+~0U
+};
+
+int audit_classify_arch(int arch)
+{
+#ifdef CONFIG_IA32_EMULATION
+	if (arch == AUDIT_ARCH_I386)
+		return 1;
+#endif
+	return 0;
+}
+
 int audit_classify_syscall(int abi, unsigned syscall)
 {
 #ifdef CONFIG_IA32_EMULATION
@@ -49,15 +63,18 @@
 	extern __u32 ia32_write_class[];
 	extern __u32 ia32_read_class[];
 	extern __u32 ia32_chattr_class[];
+	extern __u32 ia32_signal_class[];
 	audit_register_class(AUDIT_CLASS_WRITE_32, ia32_write_class);
 	audit_register_class(AUDIT_CLASS_READ_32, ia32_read_class);
 	audit_register_class(AUDIT_CLASS_DIR_WRITE_32, ia32_dir_class);
 	audit_register_class(AUDIT_CLASS_CHATTR_32, ia32_chattr_class);
+	audit_register_class(AUDIT_CLASS_SIGNAL_32, ia32_signal_class);
 #endif
 	audit_register_class(AUDIT_CLASS_WRITE, write_class);
 	audit_register_class(AUDIT_CLASS_READ, read_class);
 	audit_register_class(AUDIT_CLASS_DIR_WRITE, dir_class);
 	audit_register_class(AUDIT_CLASS_CHATTR, chattr_class);
+	audit_register_class(AUDIT_CLASS_SIGNAL, signal_class);
 	return 0;
 }
 
diff --git a/arch/x86_64/kernel/head64.c b/arch/x86_64/kernel/head64.c
index 213d90e..6c34bdd 100644
--- a/arch/x86_64/kernel/head64.c
+++ b/arch/x86_64/kernel/head64.c
@@ -62,13 +62,6 @@
 {
 	int i;
 
-	/*
-	 * Make sure kernel is aligned to 2MB address. Catching it at compile
-	 * time is better. Change your config file and compile the kernel
-	 * for a 2MB aligned address (CONFIG_PHYSICAL_START)
-	 */
-	BUILD_BUG_ON(CONFIG_PHYSICAL_START & (__KERNEL_ALIGN - 1));
-
 	/* clear bss before set_intr_gate with early_idt_handler */
 	clear_bss();
 
diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c
index 17e1889..74a567a 100644
--- a/block/ll_rw_blk.c
+++ b/block/ll_rw_blk.c
@@ -3116,7 +3116,7 @@
  * bi_sector for remaps as it sees fit.  So the values of these fields
  * should NOT be depended on after the call to generic_make_request.
  */
-void generic_make_request(struct bio *bio)
+static inline void __generic_make_request(struct bio *bio)
 {
 	request_queue_t *q;
 	sector_t maxsector;
@@ -3215,6 +3215,57 @@
 	} while (ret);
 }
 
+/*
+ * We only want one ->make_request_fn to be active at a time,
+ * else stack usage with stacked devices could be a problem.
+ * So use current->bio_{list,tail} to keep a list of requests
+ * submited by a make_request_fn function.
+ * current->bio_tail is also used as a flag to say if
+ * generic_make_request is currently active in this task or not.
+ * If it is NULL, then no make_request is active.  If it is non-NULL,
+ * then a make_request is active, and new requests should be added
+ * at the tail
+ */
+void generic_make_request(struct bio *bio)
+{
+	if (current->bio_tail) {
+		/* make_request is active */
+		*(current->bio_tail) = bio;
+		bio->bi_next = NULL;
+		current->bio_tail = &bio->bi_next;
+		return;
+	}
+	/* following loop may be a bit non-obvious, and so deserves some
+	 * explanation.
+	 * Before entering the loop, bio->bi_next is NULL (as all callers
+	 * ensure that) so we have a list with a single bio.
+	 * We pretend that we have just taken it off a longer list, so
+	 * we assign bio_list to the next (which is NULL) and bio_tail
+	 * to &bio_list, thus initialising the bio_list of new bios to be
+	 * added.  __generic_make_request may indeed add some more bios
+	 * through a recursive call to generic_make_request.  If it
+	 * did, we find a non-NULL value in bio_list and re-enter the loop
+	 * from the top.  In this case we really did just take the bio
+	 * of the top of the list (no pretending) and so fixup bio_list and
+	 * bio_tail or bi_next, and call into __generic_make_request again.
+	 *
+	 * The loop was structured like this to make only one call to
+	 * __generic_make_request (which is important as it is large and
+	 * inlined) and to keep the structure simple.
+	 */
+	BUG_ON(bio->bi_next);
+	do {
+		current->bio_list = bio->bi_next;
+		if (bio->bi_next == NULL)
+			current->bio_tail = &current->bio_list;
+		else
+			bio->bi_next = NULL;
+		__generic_make_request(bio);
+		bio = current->bio_list;
+	} while (bio);
+	current->bio_tail = NULL; /* deactivate */
+}
+
 EXPORT_SYMBOL(generic_make_request);
 
 /**
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 0f4203b..6055b9c 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -307,7 +307,9 @@
 
 	if (hu) {
 		struct hci_dev *hdev = hu->hdev;
-		hci_uart_close(hdev);
+
+		if (hdev)
+			hci_uart_close(hdev);
 
 		if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) {
 			hu->proto->close(hu);
@@ -473,12 +475,18 @@
 			tty->low_latency = 1;
 		} else
 			return -EBUSY;
+		break;
 
 	case HCIUARTGETPROTO:
 		if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
 			return hu->proto->id;
 		return -EUNATCH;
 
+	case HCIUARTGETDEVICE:
+		if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
+			return hu->hdev->id;
+		return -EUNATCH;
+
 	default:
 		err = n_tty_ioctl(tty, file, cmd, arg);
 		break;
diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h
index b250e67..1097ce7 100644
--- a/drivers/bluetooth/hci_uart.h
+++ b/drivers/bluetooth/hci_uart.h
@@ -28,8 +28,9 @@
 #endif
 
 /* Ioctls */
-#define HCIUARTSETPROTO	_IOW('U', 200, int)
-#define HCIUARTGETPROTO	_IOR('U', 201, int)
+#define HCIUARTSETPROTO		_IOW('U', 200, int)
+#define HCIUARTGETPROTO		_IOR('U', 201, int)
+#define HCIUARTGETDEVICE	_IOR('U', 202, int)
 
 /* UART protocols */
 #define HCI_UART_MAX_PROTO	4
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
index 6ac3ca4..b3d4ccc 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -1544,21 +1544,18 @@
 }
 
 struct tty_ldisc tty_ldisc_N_TTY = {
-	TTY_LDISC_MAGIC,	/* magic */
-	"n_tty",		/* name */
-	0,			/* num */
-	0,			/* flags */
-	n_tty_open,		/* open */
-	n_tty_close,		/* close */
-	n_tty_flush_buffer,	/* flush_buffer */
-	n_tty_chars_in_buffer,	/* chars_in_buffer */
-	read_chan,		/* read */
-	write_chan,		/* write */
-	n_tty_ioctl,		/* ioctl */
-	n_tty_set_termios,	/* set_termios */
-	normal_poll,		/* poll */
-	NULL,			/* hangup */
-	n_tty_receive_buf,	/* receive_buf */
-	n_tty_write_wakeup	/* write_wakeup */
+	.magic           = TTY_LDISC_MAGIC,
+	.name            = "n_tty",
+	.open            = n_tty_open,
+	.close           = n_tty_close,
+	.flush_buffer    = n_tty_flush_buffer,
+	.chars_in_buffer = n_tty_chars_in_buffer,
+	.read            = read_chan,
+	.write           = write_chan,
+	.ioctl           = n_tty_ioctl,
+	.set_termios     = n_tty_set_termios,
+	.poll            = normal_poll,
+	.receive_buf     = n_tty_receive_buf,
+	.write_wakeup    = n_tty_write_wakeup
 };
 
diff --git a/drivers/char/rio/riocmd.c b/drivers/char/rio/riocmd.c
index 245f031..8cc60b6 100644
--- a/drivers/char/rio/riocmd.c
+++ b/drivers/char/rio/riocmd.c
@@ -402,7 +402,7 @@
 		rio_dprintk(RIO_DEBUG_CMD, "CONTROL information: Host number %Zd, name ``%s''\n", HostP - p->RIOHosts, HostP->Name);
 		rio_dprintk(RIO_DEBUG_CMD, "CONTROL information: Rup number  0x%x\n", rup);
 
-		if (Rup >= (unsigned short) MAX_RUP) {
+		if (Rup < (unsigned short) MAX_RUP) {
 			rio_dprintk(RIO_DEBUG_CMD, "CONTROL information: This is the RUP for RTA ``%s''\n", HostP->Mapping[Rup].Name);
 		} else
 			rio_dprintk(RIO_DEBUG_CMD, "CONTROL information: This is the RUP for link ``%c'' of host ``%s''\n", ('A' + Rup - MAX_RUP), HostP->Name);
diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c
index 61a63da..a3fd7e7 100644
--- a/drivers/char/rocket.c
+++ b/drivers/char/rocket.c
@@ -1014,9 +1014,6 @@
 	/*
 	 * Info->count is now 1; so it's safe to sleep now.
 	 */
-	info->session = process_session(current);
-	info->pgrp = process_group(current);
-
 	if ((info->flags & ROCKET_INITIALIZED) == 0) {
 		cp = &info->channel;
 		sSetRxTrigger(cp, TRIG_1);
diff --git a/drivers/char/rocket_int.h b/drivers/char/rocket_int.h
index 89b4d7b..b4c53df 100644
--- a/drivers/char/rocket_int.h
+++ b/drivers/char/rocket_int.h
@@ -1158,8 +1158,6 @@
 	int xmit_head;
 	int xmit_tail;
 	int xmit_cnt;
-	int session;
-	int pgrp;
 	int cd_status;
 	int ignore_status_mask;
 	int read_status_mask;
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c
index 2a7736b..02b49bc 100644
--- a/drivers/char/synclink_gt.c
+++ b/drivers/char/synclink_gt.c
@@ -1171,6 +1171,112 @@
 }
 
 /*
+ * support for 32 bit ioctl calls on 64 bit systems
+ */
+#ifdef CONFIG_COMPAT
+static long get_params32(struct slgt_info *info, struct MGSL_PARAMS32 __user *user_params)
+{
+	struct MGSL_PARAMS32 tmp_params;
+
+	DBGINFO(("%s get_params32\n", info->device_name));
+	tmp_params.mode            = (compat_ulong_t)info->params.mode;
+	tmp_params.loopback        = info->params.loopback;
+	tmp_params.flags           = info->params.flags;
+	tmp_params.encoding        = info->params.encoding;
+	tmp_params.clock_speed     = (compat_ulong_t)info->params.clock_speed;
+	tmp_params.addr_filter     = info->params.addr_filter;
+	tmp_params.crc_type        = info->params.crc_type;
+	tmp_params.preamble_length = info->params.preamble_length;
+	tmp_params.preamble        = info->params.preamble;
+	tmp_params.data_rate       = (compat_ulong_t)info->params.data_rate;
+	tmp_params.data_bits       = info->params.data_bits;
+	tmp_params.stop_bits       = info->params.stop_bits;
+	tmp_params.parity          = info->params.parity;
+	if (copy_to_user(user_params, &tmp_params, sizeof(struct MGSL_PARAMS32)))
+		return -EFAULT;
+	return 0;
+}
+
+static long set_params32(struct slgt_info *info, struct MGSL_PARAMS32 __user *new_params)
+{
+	struct MGSL_PARAMS32 tmp_params;
+
+	DBGINFO(("%s set_params32\n", info->device_name));
+	if (copy_from_user(&tmp_params, new_params, sizeof(struct MGSL_PARAMS32)))
+		return -EFAULT;
+
+	spin_lock(&info->lock);
+	info->params.mode            = tmp_params.mode;
+	info->params.loopback        = tmp_params.loopback;
+	info->params.flags           = tmp_params.flags;
+	info->params.encoding        = tmp_params.encoding;
+	info->params.clock_speed     = tmp_params.clock_speed;
+	info->params.addr_filter     = tmp_params.addr_filter;
+	info->params.crc_type        = tmp_params.crc_type;
+	info->params.preamble_length = tmp_params.preamble_length;
+	info->params.preamble        = tmp_params.preamble;
+	info->params.data_rate       = tmp_params.data_rate;
+	info->params.data_bits       = tmp_params.data_bits;
+	info->params.stop_bits       = tmp_params.stop_bits;
+	info->params.parity          = tmp_params.parity;
+	spin_unlock(&info->lock);
+
+ 	change_params(info);
+
+	return 0;
+}
+
+static long slgt_compat_ioctl(struct tty_struct *tty, struct file *file,
+			 unsigned int cmd, unsigned long arg)
+{
+	struct slgt_info *info = tty->driver_data;
+	int rc = -ENOIOCTLCMD;
+
+	if (sanity_check(info, tty->name, "compat_ioctl"))
+		return -ENODEV;
+	DBGINFO(("%s compat_ioctl() cmd=%08X\n", info->device_name, cmd));
+
+	switch (cmd) {
+
+	case MGSL_IOCSPARAMS32:
+		rc = set_params32(info, compat_ptr(arg));
+		break;
+
+	case MGSL_IOCGPARAMS32:
+		rc = get_params32(info, compat_ptr(arg));
+		break;
+
+	case MGSL_IOCGPARAMS:
+	case MGSL_IOCSPARAMS:
+	case MGSL_IOCGTXIDLE:
+	case MGSL_IOCGSTATS:
+	case MGSL_IOCWAITEVENT:
+	case MGSL_IOCGIF:
+	case MGSL_IOCSGPIO:
+	case MGSL_IOCGGPIO:
+	case MGSL_IOCWAITGPIO:
+	case TIOCGICOUNT:
+		rc = ioctl(tty, file, cmd, (unsigned long)(compat_ptr(arg)));
+		break;
+
+	case MGSL_IOCSTXIDLE:
+	case MGSL_IOCTXENABLE:
+	case MGSL_IOCRXENABLE:
+	case MGSL_IOCTXABORT:
+	case TIOCMIWAIT:
+	case MGSL_IOCSIF:
+		rc = ioctl(tty, file, cmd, arg);
+		break;
+	}
+
+	DBGINFO(("%s compat_ioctl() cmd=%08X rc=%d\n", info->device_name, cmd, rc));
+	return rc;
+}
+#else
+#define slgt_compat_ioctl NULL
+#endif /* ifdef CONFIG_COMPAT */
+
+/*
  * proc fs support
  */
 static inline int line_info(char *buf, struct slgt_info *info)
@@ -3446,6 +3552,7 @@
 	.chars_in_buffer = chars_in_buffer,
 	.flush_buffer = flush_buffer,
 	.ioctl = ioctl,
+	.compat_ioctl = slgt_compat_ioctl,
 	.throttle = throttle,
 	.unthrottle = unthrottle,
 	.send_xchar = send_xchar,
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index fc662e4..fe62c21 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -151,6 +151,12 @@
 static int tty_release(struct inode *, struct file *);
 int tty_ioctl(struct inode * inode, struct file * file,
 	      unsigned int cmd, unsigned long arg);
+#ifdef CONFIG_COMPAT
+static long tty_compat_ioctl(struct file * file, unsigned int cmd,
+				unsigned long arg);
+#else
+#define tty_compat_ioctl NULL
+#endif
 static int tty_fasync(int fd, struct file * filp, int on);
 static void release_tty(struct tty_struct *tty, int idx);
 static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);
@@ -1143,8 +1149,8 @@
 	return POLLIN | POLLOUT | POLLERR | POLLHUP | POLLRDNORM | POLLWRNORM;
 }
 
-static int hung_up_tty_ioctl(struct inode * inode, struct file * file,
-			     unsigned int cmd, unsigned long arg)
+static long hung_up_tty_ioctl(struct file * file,
+			      unsigned int cmd, unsigned long arg)
 {
 	return cmd == TIOCSPGRP ? -ENOTTY : -EIO;
 }
@@ -1155,6 +1161,7 @@
 	.write		= tty_write,
 	.poll		= tty_poll,
 	.ioctl		= tty_ioctl,
+	.compat_ioctl	= tty_compat_ioctl,
 	.open		= tty_open,
 	.release	= tty_release,
 	.fasync		= tty_fasync,
@@ -1167,6 +1174,7 @@
 	.write		= tty_write,
 	.poll		= tty_poll,
 	.ioctl		= tty_ioctl,
+	.compat_ioctl	= tty_compat_ioctl,
 	.open		= ptmx_open,
 	.release	= tty_release,
 	.fasync		= tty_fasync,
@@ -1179,6 +1187,7 @@
 	.write		= redirected_tty_write,
 	.poll		= tty_poll,
 	.ioctl		= tty_ioctl,
+	.compat_ioctl	= tty_compat_ioctl,
 	.open		= tty_open,
 	.release	= tty_release,
 	.fasync		= tty_fasync,
@@ -1189,7 +1198,8 @@
 	.read		= hung_up_tty_read,
 	.write		= hung_up_tty_write,
 	.poll		= hung_up_tty_poll,
-	.ioctl		= hung_up_tty_ioctl,
+	.unlocked_ioctl = hung_up_tty_ioctl,
+	.compat_ioctl	= hung_up_tty_ioctl,
 	.release	= tty_release,
 };
 
@@ -3357,6 +3367,32 @@
 	return retval;
 }
 
+#ifdef CONFIG_COMPAT
+static long tty_compat_ioctl(struct file * file, unsigned int cmd,
+				unsigned long arg)
+{
+	struct inode *inode = file->f_dentry->d_inode;
+	struct tty_struct *tty = file->private_data;
+	struct tty_ldisc *ld;
+	int retval = -ENOIOCTLCMD;
+
+	if (tty_paranoia_check(tty, inode, "tty_ioctl"))
+		return -EINVAL;
+
+	if (tty->driver->compat_ioctl) {
+		retval = (tty->driver->compat_ioctl)(tty, file, cmd, arg);
+		if (retval != -ENOIOCTLCMD)
+			return retval;
+	}
+
+	ld = tty_ldisc_ref_wait(tty);
+	if (ld->compat_ioctl)
+		retval = ld->compat_ioctl(tty, file, cmd, arg);
+	tty_ldisc_deref(ld);
+
+	return retval;
+}
+#endif
 
 /*
  * This implements the "Secure Attention Key" ---  the idea is to
@@ -3689,6 +3725,7 @@
 	driver->write_room = op->write_room;
 	driver->chars_in_buffer = op->chars_in_buffer;
 	driver->ioctl = op->ioctl;
+	driver->compat_ioctl = op->compat_ioctl;
 	driver->set_termios = op->set_termios;
 	driver->throttle = op->throttle;
 	driver->unthrottle = op->unthrottle;
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index a19b65e..7f81789 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -240,11 +240,94 @@
 }
 #endif
 
+static inline int match_scancode(int code, int scancode)
+{
+	if (scancode == 0)
+		return 1;
+	return ((code & (HID_USAGE_PAGE | HID_USAGE)) == scancode);
+}
+
+static inline int match_keycode(int code, int keycode)
+{
+	if (keycode == 0)
+		return 1;
+	return (code == keycode);
+}
+
+static struct hid_usage *hidinput_find_key(struct hid_device *hid,
+		int scancode, int keycode)
+{
+	int i, j, k;
+	struct hid_report *report;
+	struct hid_usage *usage;
+
+	for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) {
+		list_for_each_entry(report, &hid->report_enum[k].report_list, list) {
+			for (i = 0; i < report->maxfield; i++) {
+				for ( j = 0; j < report->field[i]->maxusage; j++) {
+					usage = report->field[i]->usage + j;
+					if (usage->type == EV_KEY &&
+						match_scancode(usage->hid, scancode) &&
+						match_keycode(usage->code, keycode))
+						return usage;
+				}
+			}
+		}
+	}
+	return NULL;
+}
+
+static int hidinput_getkeycode(struct input_dev *dev, int scancode,
+				int *keycode)
+{
+	struct hid_device *hid = dev->private;
+	struct hid_usage *usage;
+	
+	usage = hidinput_find_key(hid, scancode, 0);
+	if (usage) {
+		*keycode = usage->code;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int hidinput_setkeycode(struct input_dev *dev, int scancode,
+				int keycode)
+{
+	struct hid_device *hid = dev->private;
+	struct hid_usage *usage;
+	int old_keycode;
+	
+	if (keycode < 0 || keycode > KEY_MAX)
+		return -EINVAL;
+	
+	usage = hidinput_find_key(hid, scancode, 0);
+	if (usage) {
+		old_keycode = usage->code;
+		usage->code = keycode;
+		
+		clear_bit(old_keycode, dev->keybit);
+		set_bit(usage->code, dev->keybit);
+#ifdef CONFIG_HID_DEBUG
+		printk (KERN_DEBUG "Assigned keycode %d to HID usage code %x\n", keycode, scancode);
+#endif
+		/* Set the keybit for the old keycode if the old keycode is used
+		 * by another key */
+		if (hidinput_find_key (hid, 0, old_keycode))
+			set_bit(old_keycode, dev->keybit);
+		
+		return 0;
+	}
+	
+	return -EINVAL;
+}
+
+
 static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field,
 				     struct hid_usage *usage)
 {
 	struct input_dev *input = hidinput->input;
-	struct hid_device *device = input->private;
+	struct hid_device *device = input_get_drvdata(input);
 	int max = 0, code;
 	unsigned long *bit = NULL;
 
@@ -553,6 +636,7 @@
 				case 0x1015: map_key_clear(KEY_RECORD);		break;
 				case 0x1016: map_key_clear(KEY_PLAYER);		break;
 				case 0x1017: map_key_clear(KEY_EJECTCD);	break;
+				case 0x1018: map_key_clear(KEY_MEDIA);          break;
 				case 0x1019: map_key_clear(KEY_PROG1);		break;
 				case 0x101a: map_key_clear(KEY_PROG2);		break;
 				case 0x101b: map_key_clear(KEY_PROG3);		break;
@@ -560,9 +644,12 @@
 				case 0x1020: map_key_clear(KEY_ZOOMOUT);	break;
 				case 0x1021: map_key_clear(KEY_ZOOMRESET);	break;
 				case 0x1023: map_key_clear(KEY_CLOSE);		break;
+				case 0x1027: map_key_clear(KEY_MENU);           break;
 				/* this one is marked as 'Rotate' */
 				case 0x1028: map_key_clear(KEY_ANGLE);		break;
 				case 0x1029: map_key_clear(KEY_SHUFFLE);	break;
+				case 0x102a: map_key_clear(KEY_BACK);           break;
+				case 0x102b: map_key_clear(KEY_CYCLEWINDOWS);   break;
 				case 0x1041: map_key_clear(KEY_BATTERY);	break;
 				case 0x1042: map_key_clear(KEY_WORDPROCESSOR);	break;
 				case 0x1043: map_key_clear(KEY_SPREADSHEET);	break;
@@ -855,13 +942,15 @@
 
 static int hidinput_open(struct input_dev *dev)
 {
-	struct hid_device *hid = dev->private;
+	struct hid_device *hid = input_get_drvdata(dev);
+
 	return hid->hid_open(hid);
 }
 
 static void hidinput_close(struct input_dev *dev)
 {
-	struct hid_device *hid = dev->private;
+	struct hid_device *hid = input_get_drvdata(dev);
+
 	hid->hid_close(hid);
 }
 
@@ -909,10 +998,12 @@
 					return -1;
 				}
 
-				input_dev->private = hid;
+				input_set_drvdata(input_dev, hid);
 				input_dev->event = hid->hidinput_input_event;
 				input_dev->open = hidinput_open;
 				input_dev->close = hidinput_close;
+				input_dev->setkeycode = hidinput_setkeycode;
+				input_dev->getkeycode = hidinput_getkeycode;
 
 				input_dev->name = hid->name;
 				input_dev->phys = hid->phys;
@@ -921,7 +1012,7 @@
 				input_dev->id.vendor  = hid->vendor;
 				input_dev->id.product = hid->product;
 				input_dev->id.version = hid->version;
-				input_dev->cdev.dev = hid->dev;
+				input_dev->dev.parent = hid->dev;
 				hidinput->input = input_dev;
 				list_add_tail(&hidinput->list, &hid->inputs);
 			}
diff --git a/drivers/hid/usbhid/Kconfig b/drivers/hid/usbhid/Kconfig
index 7c87bdc..1b4b572 100644
--- a/drivers/hid/usbhid/Kconfig
+++ b/drivers/hid/usbhid/Kconfig
@@ -25,12 +25,12 @@
 	depends on USB_HID && INPUT=n
 
 config USB_HIDINPUT_POWERBOOK
-	bool "Enable support for iBook/PowerBook special keys"
+	bool "Enable support for iBook/PowerBook/MacBook/MacBookPro special keys"
 	default n
 	depends on USB_HID
 	help
 	  Say Y here if you want support for the special keys (Fn, Numlock) on
-	  Apple iBooks and PowerBooks.
+	  Apple iBooks, PowerBooks, MacBooks and MacBook Pros.
 
 	  If unsure, say N.
 
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index 91d6103..d91b9da 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -446,7 +446,7 @@
 
 static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
 {
-	struct hid_device *hid = dev->private;
+	struct hid_device *hid = input_get_drvdata(dev);
 	struct hid_field *field;
 	int offset;
 
@@ -626,14 +626,10 @@
 {
 	struct usbhid_device *usbhid = hid->driver_data;
 
-	if (usbhid->inbuf)
-		usb_buffer_free(dev, usbhid->bufsize, usbhid->inbuf, usbhid->inbuf_dma);
-	if (usbhid->outbuf)
-		usb_buffer_free(dev, usbhid->bufsize, usbhid->outbuf, usbhid->outbuf_dma);
-	if (usbhid->cr)
-		usb_buffer_free(dev, sizeof(*(usbhid->cr)), usbhid->cr, usbhid->cr_dma);
-	if (usbhid->ctrlbuf)
-		usb_buffer_free(dev, usbhid->bufsize, usbhid->ctrlbuf, usbhid->ctrlbuf_dma);
+	usb_buffer_free(dev, usbhid->bufsize, usbhid->inbuf, usbhid->inbuf_dma);
+	usb_buffer_free(dev, usbhid->bufsize, usbhid->outbuf, usbhid->outbuf_dma);
+	usb_buffer_free(dev, sizeof(*(usbhid->cr)), usbhid->cr, usbhid->cr_dma);
+	usb_buffer_free(dev, usbhid->bufsize, usbhid->ctrlbuf, usbhid->ctrlbuf_dma);
 }
 
 /*
@@ -692,6 +688,30 @@
 	}
 }
 
+/*
+ * Some USB barcode readers from cypress have usage min and usage max in
+ * the wrong order
+ */
+static void hid_fixup_cypress_descriptor(unsigned char *rdesc, int rsize)
+{
+	short fixed = 0;
+	int i;
+
+	for (i = 0; i < rsize - 4; i++) {
+		if (rdesc[i] == 0x29 && rdesc [i+2] == 0x19) {
+			unsigned char tmp;
+
+			rdesc[i] = 0x19; rdesc[i+2] = 0x29;
+			tmp = rdesc[i+3];
+			rdesc[i+3] = rdesc[i+1];
+			rdesc[i+1] = tmp;
+		}
+	}
+
+	if (fixed)
+		info("Fixing up Cypress report descriptor");
+}
+
 static struct hid_device *usb_hid_configure(struct usb_interface *intf)
 {
 	struct usb_host_interface *interface = intf->cur_altsetting;
@@ -758,6 +778,9 @@
 	if (quirks & HID_QUIRK_LOGITECH_DESCRIPTOR)
 		hid_fixup_logitech_descriptor(rdesc, rsize);
 
+	if (quirks & HID_QUIRK_SWAPPED_MIN_MAX)
+		hid_fixup_cypress_descriptor(rdesc, rsize);
+
 #ifdef CONFIG_HID_DEBUG
 	printk(KERN_DEBUG __FILE__ ": report descriptor (size %u, read %d) = ", rsize, n);
 	for (n = 0; n < rsize; n++)
diff --git a/drivers/hid/usbhid/hid-lgff.c b/drivers/hid/usbhid/hid-lgff.c
index 92d2553..c5cd410 100644
--- a/drivers/hid/usbhid/hid-lgff.c
+++ b/drivers/hid/usbhid/hid-lgff.c
@@ -60,7 +60,7 @@
 
 static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *effect)
 {
-	struct hid_device *hid = dev->private;
+	struct hid_device *hid = input_get_drvdata(dev);
 	struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
 	struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
 	int x, y;
diff --git a/drivers/hid/usbhid/hid-plff.c b/drivers/hid/usbhid/hid-plff.c
index 76d2e6e..d6a8f2b 100644
--- a/drivers/hid/usbhid/hid-plff.c
+++ b/drivers/hid/usbhid/hid-plff.c
@@ -37,7 +37,7 @@
 static int hid_plff_play(struct input_dev *dev, void *data,
 			 struct ff_effect *effect)
 {
-	struct hid_device *hid = dev->private;
+	struct hid_device *hid = input_get_drvdata(dev);
 	struct plff_device *plff = data;
 	int left, right;
 
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
index 17a8755..f6c4145 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -92,6 +92,8 @@
 #define USB_DEVICE_ID_CYPRESS_MOUSE	0x0001
 #define USB_DEVICE_ID_CYPRESS_HIDCOM	0x5500
 #define USB_DEVICE_ID_CYPRESS_ULTRAMOUSE	0x7417
+#define USB_DEVICE_ID_CYPRESS_BARCODE_1	0xde61
+#define USB_DEVICE_ID_CYPRESS_BARCODE_2	0xde64
 
 #define USB_VENDOR_ID_DELL		0x413c
 #define USB_DEVICE_ID_DELL_W7658	0x2005
@@ -193,6 +195,7 @@
 
 #define USB_VENDOR_ID_LOGITECH		0x046d
 #define USB_DEVICE_ID_LOGITECH_RECEIVER	0xc101
+#define USB_DEVICE_ID_LOGITECH_WHEEL	0xc294
 #define USB_DEVICE_ID_S510_RECEIVER	0xc50c
 #define USB_DEVICE_ID_S510_RECEIVER_2	0xc517
 #define USB_DEVICE_ID_MX3000_RECEIVER	0xc513
@@ -422,6 +425,7 @@
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
@@ -445,6 +449,9 @@
 
 	{ USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_W7658, HID_QUIRK_RESET_LEDS },
 
+	{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1, HID_QUIRK_SWAPPED_MIN_MAX },
+	{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2, HID_QUIRK_SWAPPED_MIN_MAX },
+
 	{ 0, 0 }
 };
 
diff --git a/drivers/hid/usbhid/hid-tmff.c b/drivers/hid/usbhid/hid-tmff.c
index ab67331..ab5ba6e 100644
--- a/drivers/hid/usbhid/hid-tmff.c
+++ b/drivers/hid/usbhid/hid-tmff.c
@@ -59,7 +59,7 @@
 
 static int hid_tmff_play(struct input_dev *dev, void *data, struct ff_effect *effect)
 {
-	struct hid_device *hid = dev->private;
+	struct hid_device *hid = input_get_drvdata(dev);
 	struct tmff_device *tmff = data;
 	int left, right;	/* Rumbling */
 
diff --git a/drivers/hid/usbhid/hid-zpff.c b/drivers/hid/usbhid/hid-zpff.c
index 7bd8238..a7fbffc 100644
--- a/drivers/hid/usbhid/hid-zpff.c
+++ b/drivers/hid/usbhid/hid-zpff.c
@@ -37,7 +37,7 @@
 static int hid_zpff_play(struct input_dev *dev, void *data,
 			 struct ff_effect *effect)
 {
-	struct hid_device *hid = dev->private;
+	struct hid_device *hid = input_get_drvdata(dev);
 	struct zpff_device *zpff = data;
 	int left, right;
 
diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c
index a8b3d66..488d61b 100644
--- a/drivers/hid/usbhid/hiddev.c
+++ b/drivers/hid/usbhid/hiddev.c
@@ -51,6 +51,7 @@
 	wait_queue_head_t wait;
 	struct hid_device *hid;
 	struct list_head list;
+	spinlock_t list_lock;
 };
 
 struct hiddev_list {
@@ -161,7 +162,9 @@
 {
 	struct hiddev *hiddev = hid->hiddev;
 	struct hiddev_list *list;
+	unsigned long flags;
 
+	spin_lock_irqsave(&hiddev->list_lock, flags);
 	list_for_each_entry(list, &hiddev->list, node) {
 		if (uref->field_index != HID_FIELD_INDEX_NONE ||
 		    (list->flags & HIDDEV_FLAG_REPORT) != 0) {
@@ -171,6 +174,7 @@
 			kill_fasync(&list->fasync, SIGIO, POLL_IN);
 		}
 	}
+	spin_unlock_irqrestore(&hiddev->list_lock, flags);
 
 	wake_up_interruptible(&hiddev->wait);
 }
@@ -235,9 +239,13 @@
 static int hiddev_release(struct inode * inode, struct file * file)
 {
 	struct hiddev_list *list = file->private_data;
+	unsigned long flags;
 
 	hiddev_fasync(-1, file, 0);
+
+	spin_lock_irqsave(&list->hiddev->list_lock, flags);
 	list_del(&list->node);
+	spin_unlock_irqrestore(&list->hiddev->list_lock, flags);
 
 	if (!--list->hiddev->open) {
 		if (list->hiddev->exist)
@@ -257,6 +265,7 @@
 static int hiddev_open(struct inode *inode, struct file *file)
 {
 	struct hiddev_list *list;
+	unsigned long flags;
 
 	int i = iminor(inode) - HIDDEV_MINOR_BASE;
 
@@ -267,7 +276,11 @@
 		return -ENOMEM;
 
 	list->hiddev = hiddev_table[i];
+
+	spin_lock_irqsave(&list->hiddev->list_lock, flags);
 	list_add_tail(&list->node, &hiddev_table[i]->list);
+	spin_unlock_irqrestore(&list->hiddev->list_lock, flags);
+
 	file->private_data = list;
 
 	if (!list->hiddev->open++)
@@ -773,6 +786,7 @@
 
 	init_waitqueue_head(&hiddev->wait);
 	INIT_LIST_HEAD(&hiddev->list);
+	spin_lock_init(&hiddev->list_lock);
 	hiddev->hid = hid;
 	hiddev->exist = 1;
 
diff --git a/drivers/hid/usbhid/usbkbd.c b/drivers/hid/usbhid/usbkbd.c
index 65aa12e8..1309787 100644
--- a/drivers/hid/usbhid/usbkbd.c
+++ b/drivers/hid/usbhid/usbkbd.c
@@ -133,12 +133,11 @@
 static int usb_kbd_event(struct input_dev *dev, unsigned int type,
 			 unsigned int code, int value)
 {
-	struct usb_kbd *kbd = dev->private;
+	struct usb_kbd *kbd = input_get_drvdata(dev);
 
 	if (type != EV_LED)
 		return -1;
 
-
 	kbd->newleds = (!!test_bit(LED_KANA,    dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) |
 		       (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL,   dev->led) << 1) |
 		       (!!test_bit(LED_NUML,    dev->led));
@@ -175,7 +174,7 @@
 
 static int usb_kbd_open(struct input_dev *dev)
 {
-	struct usb_kbd *kbd = dev->private;
+	struct usb_kbd *kbd = input_get_drvdata(dev);
 
 	kbd->irq->dev = kbd->usbdev;
 	if (usb_submit_urb(kbd->irq, GFP_KERNEL))
@@ -186,7 +185,7 @@
 
 static void usb_kbd_close(struct input_dev *dev)
 {
-	struct usb_kbd *kbd = dev->private;
+	struct usb_kbd *kbd = input_get_drvdata(dev);
 
 	usb_kill_urb(kbd->irq);
 }
@@ -211,12 +210,9 @@
 {
 	usb_free_urb(kbd->irq);
 	usb_free_urb(kbd->led);
-	if (kbd->new)
-		usb_buffer_free(dev, 8, kbd->new, kbd->new_dma);
-	if (kbd->cr)
-		usb_buffer_free(dev, sizeof(struct usb_ctrlrequest), kbd->cr, kbd->cr_dma);
-	if (kbd->leds)
-		usb_buffer_free(dev, 1, kbd->leds, kbd->leds_dma);
+	usb_buffer_free(dev, 8, kbd->new, kbd->new_dma);
+	usb_buffer_free(dev, sizeof(struct usb_ctrlrequest), kbd->cr, kbd->cr_dma);
+	usb_buffer_free(dev, 1, kbd->leds, kbd->leds_dma);
 }
 
 static int usb_kbd_probe(struct usb_interface *iface,
@@ -274,8 +270,9 @@
 	input_dev->name = kbd->name;
 	input_dev->phys = kbd->phys;
 	usb_to_input_id(dev, &input_dev->id);
-	input_dev->cdev.dev = &iface->dev;
-	input_dev->private = kbd;
+	input_dev->dev.parent = &iface->dev;
+
+	input_set_drvdata(input_dev, kbd);
 
 	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP);
 	input_dev->ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL) | BIT(LED_COMPOSE) | BIT(LED_KANA);
diff --git a/drivers/hid/usbhid/usbmouse.c b/drivers/hid/usbhid/usbmouse.c
index 573776d..5345c73 100644
--- a/drivers/hid/usbhid/usbmouse.c
+++ b/drivers/hid/usbhid/usbmouse.c
@@ -96,7 +96,7 @@
 
 static int usb_mouse_open(struct input_dev *dev)
 {
-	struct usb_mouse *mouse = dev->private;
+	struct usb_mouse *mouse = input_get_drvdata(dev);
 
 	mouse->irq->dev = mouse->usbdev;
 	if (usb_submit_urb(mouse->irq, GFP_KERNEL))
@@ -107,7 +107,7 @@
 
 static void usb_mouse_close(struct input_dev *dev)
 {
-	struct usb_mouse *mouse = dev->private;
+	struct usb_mouse *mouse = input_get_drvdata(dev);
 
 	usb_kill_urb(mouse->irq);
 }
@@ -171,7 +171,7 @@
 	input_dev->name = mouse->name;
 	input_dev->phys = mouse->phys;
 	usb_to_input_id(dev, &input_dev->id);
-	input_dev->cdev.dev = &intf->dev;
+	input_dev->dev.parent = &intf->dev;
 
 	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
 	input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
@@ -179,7 +179,8 @@
 	input_dev->keybit[LONG(BTN_MOUSE)] |= BIT(BTN_SIDE) | BIT(BTN_EXTRA);
 	input_dev->relbit[0] |= BIT(REL_WHEEL);
 
-	input_dev->private = mouse;
+	input_set_drvdata(input_dev, mouse);
+
 	input_dev->open = usb_mouse_open;
 	input_dev->close = usb_mouse_close;
 
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 55a7259..b234729 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -336,7 +336,7 @@
 
 	if (compat) {
 		len = NBITS_COMPAT(maxbit) * sizeof(compat_long_t);
-		if (len < maxlen)
+		if (len > maxlen)
 			len = maxlen;
 
 		for (i = 0; i < len / sizeof(compat_long_t); i++)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 65814b0..c10ce91 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -5103,7 +5103,7 @@
 		 *
 		 * Note: the following is an unsigned comparison.
 		 */
-		if ((curr_events - rdev->last_events + 4096) > 8192) {
+		if ((long)curr_events - (long)rdev->last_events > 4096) {
 			rdev->last_events = curr_events;
 			idle = 0;
 		}
diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig
index 7c8ccc0..829da9a 100644
--- a/drivers/net/irda/Kconfig
+++ b/drivers/net/irda/Kconfig
@@ -141,6 +141,20 @@
 	  To activate support for ACTiSYS IR-200L dongle you will have to
 	  start irattach like this: "irattach -d act200l".
 
+config KINGSUN_DONGLE
+	tristate "KingSun/DonShine DS-620 IrDA-USB dongle"
+	depends on IRDA && USB && EXPERIMENTAL
+	help
+	  Say Y or M here if you want to build support for the KingSun/DonShine
+	  DS-620 IrDA-USB bridge device driver.
+
+	  This USB bridge does not conform to the IrDA-USB device class
+	  specification, and therefore needs its own specific driver. This
+	  dongle supports SIR speed only (9600 bps).
+
+	  To compile it as a module, choose M here: the module will be called
+	  kingsun-sir.
+
 comment "Old SIR device drivers"
 
 config IRPORT_SIR
diff --git a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile
index 5be09f1..233a2f9 100644
--- a/drivers/net/irda/Makefile
+++ b/drivers/net/irda/Makefile
@@ -45,6 +45,7 @@
 obj-$(CONFIG_ACT200L_DONGLE)	+= act200l-sir.o
 obj-$(CONFIG_MA600_DONGLE)	+= ma600-sir.o
 obj-$(CONFIG_TOIM3232_DONGLE)	+= toim3232-sir.o
+obj-$(CONFIG_KINGSUN_DONGLE)	+= kingsun-sir.o
 
 # The SIR helper module
 sir-dev-objs := sir_dev.o sir_dongle.o
diff --git a/drivers/net/irda/kingsun-sir.c b/drivers/net/irda/kingsun-sir.c
new file mode 100644
index 0000000..2174291
--- /dev/null
+++ b/drivers/net/irda/kingsun-sir.c
@@ -0,0 +1,657 @@
+/*****************************************************************************
+*
+* Filename:      kingsun-sir.c
+* Version:       0.1.1
+* Description:   Irda KingSun/DonShine USB Dongle
+* Status:        Experimental
+* Author:        Alex Villac�s Lasso <a_villacis@palosanto.com>
+*
+*  	Based on stir4200 and mcs7780 drivers, with (strange?) differences
+*
+*	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.
+*
+*	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.
+*
+*****************************************************************************/
+
+/*
+ * This is my current (2007-04-25) understanding of how this dongle is supposed
+ * to work. This is based on reverse-engineering and examination of the packet
+ * data sent and received by the WinXP driver using USBSnoopy. Feel free to
+ * update here as more of this dongle is known:
+ *
+ * General: Unlike the other USB IrDA dongles, this particular dongle exposes,
+ * not two bulk (in and out) endpoints, but two *interrupt* ones. This dongle,
+ * like the bulk based ones (stir4200.c and mcs7780.c), requires polling in
+ * order to receive data.
+ * Transmission: Just like stir4200, this dongle uses a raw stream of data,
+ * which needs to be wrapped and escaped in a similar way as in stir4200.c.
+ * Reception: Poll-based, as in stir4200. Each read returns the contents of a
+ * 8-byte buffer, of which the first byte (LSB) indicates the number of bytes
+ * (1-7) of valid data contained within the remaining 7 bytes. For example, if
+ * the buffer had the following contents:
+ *  06 ff ff ff c0 01 04 aa
+ * This means that (06) there are 6 bytes of valid data. The byte 0xaa at the
+ * end is garbage (left over from a previous reception) and is discarded.
+ * If a read returns an "impossible" value as the length of valid data (such as
+ * 0x36) in the first byte, then the buffer is uninitialized (as is the case of
+ * first plug-in) and its contents should be discarded. There is currently no
+ * evidence that the top 5 bits of the 1st byte of the buffer can have values
+ * other than 0 once reception begins.
+ * Once valid bytes are collected, the assembled stream is a sequence of
+ * wrapped IrDA frames that is unwrapped and unescaped as in stir4200.c.
+ * BIG FAT WARNING: the dongle does *not* reset the RX buffer in any way after
+ * a successful read from the host, which means that in absence of further
+ * reception, repeated reads from the dongle will return the exact same
+ * contents repeatedly. Attempts to be smart and cache a previous read seem
+ * to result in corrupted packets, so this driver depends on the unwrap logic
+ * to sort out any repeated reads.
+ * Speed change: no commands observed so far to change speed, assumed fixed
+ * 9600bps (SIR).
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kref.h>
+#include <linux/usb.h>
+#include <linux/device.h>
+#include <linux/crc32.h>
+
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+#include <asm/uaccess.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/wrapper.h>
+#include <net/irda/crc.h>
+
+/*
+ * According to lsusb, 0x07c0 is assigned to
+ * "Code Mercenaries Hard- und Software GmbH"
+ */
+#define KING_VENDOR_ID 0x07c0
+#define KING_PRODUCT_ID 0x4200
+
+/* These are the currently known USB ids */
+static struct usb_device_id dongles[] = {
+    /* KingSun Co,Ltd  IrDA/USB Bridge */
+    { USB_DEVICE(KING_VENDOR_ID, KING_PRODUCT_ID) },
+    { }
+};
+
+MODULE_DEVICE_TABLE(usb, dongles);
+
+#define KINGSUN_MTT 0x07
+
+#define KINGSUN_FIFO_SIZE		4096
+#define KINGSUN_EP_IN			0
+#define KINGSUN_EP_OUT			1
+
+struct kingsun_cb {
+	struct usb_device *usbdev;      /* init: probe_irda */
+	struct net_device *netdev;      /* network layer */
+	struct irlap_cb   *irlap;       /* The link layer we are binded to */
+	struct net_device_stats stats;	/* network statistics */
+	struct qos_info   qos;
+
+	__u8		  *in_buf;	/* receive buffer */
+	__u8		  *out_buf;	/* transmit buffer */
+	__u8		  max_rx;	/* max. atomic read from dongle
+					   (usually 8), also size of in_buf */
+	__u8		  max_tx;	/* max. atomic write to dongle
+					   (usually 8) */
+
+	iobuff_t  	  rx_buff;	/* receive unwrap state machine */
+	struct timeval	  rx_time;
+	spinlock_t lock;
+	int receiving;
+
+	__u8 ep_in;
+	__u8 ep_out;
+
+	struct urb	 *tx_urb;
+	struct urb	 *rx_urb;
+};
+
+/* Callback transmission routine */
+static void kingsun_send_irq(struct urb *urb)
+{
+	struct kingsun_cb *kingsun = urb->context;
+	struct net_device *netdev = kingsun->netdev;
+
+	/* in process of stopping, just drop data */
+	if (!netif_running(kingsun->netdev)) {
+		err("kingsun_send_irq: Network not running!");
+		return;
+	}
+
+	/* unlink, shutdown, unplug, other nasties */
+	if (urb->status != 0) {
+		err("kingsun_send_irq: urb asynchronously failed - %d",
+		    urb->status);
+	}
+	netif_wake_queue(netdev);
+}
+
+/*
+ * Called from net/core when new frame is available.
+ */
+static int kingsun_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+	struct kingsun_cb *kingsun;
+	int wraplen;
+	int ret = 0;
+
+	if (skb == NULL || netdev == NULL)
+		return -EINVAL;
+
+	netif_stop_queue(netdev);
+
+	/* the IRDA wrapping routines don't deal with non linear skb */
+	SKB_LINEAR_ASSERT(skb);
+
+	kingsun = netdev_priv(netdev);
+
+	spin_lock(&kingsun->lock);
+
+	/* Append data to the end of whatever data remains to be transmitted */
+	wraplen = async_wrap_skb(skb,
+		kingsun->out_buf,
+		KINGSUN_FIFO_SIZE);
+
+	/* Calculate how much data can be transmitted in this urb */
+	usb_fill_int_urb(kingsun->tx_urb, kingsun->usbdev,
+		usb_sndintpipe(kingsun->usbdev, kingsun->ep_out),
+		kingsun->out_buf, wraplen, kingsun_send_irq,
+		kingsun, 1);
+
+	if ((ret = usb_submit_urb(kingsun->tx_urb, GFP_ATOMIC))) {
+		err("kingsun_hard_xmit: failed tx_urb submit: %d", ret);
+		switch (ret) {
+		case -ENODEV:
+		case -EPIPE:
+			break;
+		default:
+			kingsun->stats.tx_errors++;
+			netif_start_queue(netdev);
+		}
+	} else {
+		kingsun->stats.tx_packets++;
+		kingsun->stats.tx_bytes += skb->len;
+	}
+
+	dev_kfree_skb(skb);
+	spin_unlock(&kingsun->lock);
+
+	return ret;
+}
+
+/* Receive callback function */
+static void kingsun_rcv_irq(struct urb *urb)
+{
+	struct kingsun_cb *kingsun = urb->context;
+	int ret;
+
+	/* in process of stopping, just drop data */
+	if (!netif_running(kingsun->netdev)) {
+		kingsun->receiving = 0;
+		return;
+	}
+
+	/* unlink, shutdown, unplug, other nasties */
+	if (urb->status != 0) {
+		err("kingsun_rcv_irq: urb asynchronously failed - %d",
+		    urb->status);
+		kingsun->receiving = 0;
+		return;
+	}
+
+	if (urb->actual_length == kingsun->max_rx) {
+		__u8 *bytes = urb->transfer_buffer;
+		int i;
+
+		/* The very first byte in the buffer indicates the length of
+		   valid data in the read. This byte must be in the range
+		   1..kingsun->max_rx -1 . Values outside this range indicate
+		   an uninitialized Rx buffer when the dongle has just been
+		   plugged in. */
+		if (bytes[0] >= 1 && bytes[0] < kingsun->max_rx) {
+			for (i = 1; i <= bytes[0]; i++) {
+				async_unwrap_char(kingsun->netdev,
+						  &kingsun->stats,
+						  &kingsun->rx_buff, bytes[i]);
+			}
+			kingsun->netdev->last_rx = jiffies;
+			do_gettimeofday(&kingsun->rx_time);
+			kingsun->receiving =
+				(kingsun->rx_buff.state != OUTSIDE_FRAME)
+				? 1 : 0;
+		}
+	} else if (urb->actual_length > 0) {
+		err("%s(): Unexpected response length, expected %d got %d",
+		    __FUNCTION__, kingsun->max_rx, urb->actual_length);
+	}
+	/* This urb has already been filled in kingsun_net_open */
+	ret = usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+/*
+ * Function kingsun_net_open (dev)
+ *
+ *    Network device is taken up. Usually this is done by "ifconfig irda0 up"
+ */
+static int kingsun_net_open(struct net_device *netdev)
+{
+	struct kingsun_cb *kingsun = netdev_priv(netdev);
+	int err = -ENOMEM;
+	char hwname[16];
+
+	/* At this point, urbs are NULL, and skb is NULL (see kingsun_probe) */
+	kingsun->receiving = 0;
+
+	/* Initialize for SIR to copy data directly into skb.  */
+	kingsun->rx_buff.in_frame = FALSE;
+	kingsun->rx_buff.state = OUTSIDE_FRAME;
+	kingsun->rx_buff.truesize = IRDA_SKB_MAX_MTU;
+	kingsun->rx_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU);
+	if (!kingsun->rx_buff.skb)
+		goto free_mem;
+
+	skb_reserve(kingsun->rx_buff.skb, 1);
+	kingsun->rx_buff.head = kingsun->rx_buff.skb->data;
+	do_gettimeofday(&kingsun->rx_time);
+
+	kingsun->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!kingsun->rx_urb)
+		goto free_mem;
+
+	kingsun->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!kingsun->tx_urb)
+		goto free_mem;
+
+	/*
+	 * Now that everything should be initialized properly,
+	 * Open new IrLAP layer instance to take care of us...
+	 */
+	sprintf(hwname, "usb#%d", kingsun->usbdev->devnum);
+	kingsun->irlap = irlap_open(netdev, &kingsun->qos, hwname);
+	if (!kingsun->irlap) {
+		err("kingsun-sir: irlap_open failed");
+		goto free_mem;
+	}
+
+	/* Start first reception */
+	usb_fill_int_urb(kingsun->rx_urb, kingsun->usbdev,
+			  usb_rcvintpipe(kingsun->usbdev, kingsun->ep_in),
+			  kingsun->in_buf, kingsun->max_rx,
+			  kingsun_rcv_irq, kingsun, 1);
+	kingsun->rx_urb->status = 0;
+	err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
+	if (err) {
+		err("kingsun-sir: first urb-submit failed: %d", err);
+		goto close_irlap;
+	}
+
+	netif_start_queue(netdev);
+
+	/* Situation at this point:
+	   - all work buffers allocated
+	   - urbs allocated and ready to fill
+	   - max rx packet known (in max_rx)
+	   - unwrap state machine initialized, in state outside of any frame
+	   - receive request in progress
+	   - IrLAP layer started, about to hand over packets to send
+	 */
+
+	return 0;
+
+ close_irlap:
+	irlap_close(kingsun->irlap);
+ free_mem:
+	if (kingsun->tx_urb) {
+		usb_free_urb(kingsun->tx_urb);
+		kingsun->tx_urb = NULL;
+	}
+	if (kingsun->rx_urb) {
+		usb_free_urb(kingsun->rx_urb);
+		kingsun->rx_urb = NULL;
+	}
+	if (kingsun->rx_buff.skb) {
+		kfree_skb(kingsun->rx_buff.skb);
+		kingsun->rx_buff.skb = NULL;
+		kingsun->rx_buff.head = NULL;
+	}
+	return err;
+}
+
+/*
+ * Function kingsun_net_close (kingsun)
+ *
+ *    Network device is taken down. Usually this is done by
+ *    "ifconfig irda0 down"
+ */
+static int kingsun_net_close(struct net_device *netdev)
+{
+	struct kingsun_cb *kingsun = netdev_priv(netdev);
+
+	/* Stop transmit processing */
+	netif_stop_queue(netdev);
+
+	/* Mop up receive && transmit urb's */
+	usb_kill_urb(kingsun->tx_urb);
+	usb_kill_urb(kingsun->rx_urb);
+
+	usb_free_urb(kingsun->tx_urb);
+	usb_free_urb(kingsun->rx_urb);
+
+	kingsun->tx_urb = NULL;
+	kingsun->rx_urb = NULL;
+
+	kfree_skb(kingsun->rx_buff.skb);
+	kingsun->rx_buff.skb = NULL;
+	kingsun->rx_buff.head = NULL;
+	kingsun->rx_buff.in_frame = FALSE;
+	kingsun->rx_buff.state = OUTSIDE_FRAME;
+	kingsun->receiving = 0;
+
+	/* Stop and remove instance of IrLAP */
+	if (kingsun->irlap)
+		irlap_close(kingsun->irlap);
+
+	kingsun->irlap = NULL;
+
+	return 0;
+}
+
+/*
+ * IOCTLs : Extra out-of-band network commands...
+ */
+static int kingsun_net_ioctl(struct net_device *netdev, struct ifreq *rq,
+			     int cmd)
+{
+	struct if_irda_req *irq = (struct if_irda_req *) rq;
+	struct kingsun_cb *kingsun = netdev_priv(netdev);
+	int ret = 0;
+
+	switch (cmd) {
+	case SIOCSBANDWIDTH: /* Set bandwidth */
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+
+		/* Check if the device is still there */
+		if (netif_device_present(kingsun->netdev))
+			/* No observed commands for speed change */
+			ret = -EOPNOTSUPP;
+		break;
+
+	case SIOCSMEDIABUSY: /* Set media busy */
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+
+		/* Check if the IrDA stack is still there */
+		if (netif_running(kingsun->netdev))
+			irda_device_set_media_busy(kingsun->netdev, TRUE);
+		break;
+
+	case SIOCGRECEIVING:
+		/* Only approximately true */
+		irq->ifr_receiving = kingsun->receiving;
+		break;
+
+	default:
+		ret = -EOPNOTSUPP;
+	}
+
+	return ret;
+}
+
+/*
+ * Get device stats (for /proc/net/dev and ifconfig)
+ */
+static struct net_device_stats *
+kingsun_net_get_stats(struct net_device *netdev)
+{
+	struct kingsun_cb *kingsun = netdev_priv(netdev);
+	return &kingsun->stats;
+}
+
+/*
+ * This routine is called by the USB subsystem for each new device
+ * in the system. We need to check if the device is ours, and in
+ * this case start handling it.
+ */
+static int kingsun_probe(struct usb_interface *intf,
+		      const struct usb_device_id *id)
+{
+	struct usb_host_interface *interface;
+	struct usb_endpoint_descriptor *endpoint;
+
+	struct usb_device *dev = interface_to_usbdev(intf);
+	struct kingsun_cb *kingsun = NULL;
+	struct net_device *net = NULL;
+	int ret = -ENOMEM;
+	int pipe, maxp_in, maxp_out;
+	__u8 ep_in;
+	__u8 ep_out;
+
+	/* Check that there really are two interrupt endpoints.
+	   Check based on the one in drivers/usb/input/usbmouse.c
+	 */
+	interface = intf->cur_altsetting;
+	if (interface->desc.bNumEndpoints != 2) {
+		err("kingsun-sir: expected 2 endpoints, found %d",
+		    interface->desc.bNumEndpoints);
+		return -ENODEV;
+	}
+	endpoint = &interface->endpoint[KINGSUN_EP_IN].desc;
+	if (!usb_endpoint_is_int_in(endpoint)) {
+		err("kingsun-sir: endpoint 0 is not interrupt IN");
+		return -ENODEV;
+	}
+
+	ep_in = endpoint->bEndpointAddress;
+	pipe = usb_rcvintpipe(dev, ep_in);
+	maxp_in = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+	if (maxp_in > 255 || maxp_in <= 1) {
+		err("%s: endpoint 0 has max packet size %d not in range",
+		    __FILE__, maxp_in);
+		return -ENODEV;
+	}
+
+	endpoint = &interface->endpoint[KINGSUN_EP_OUT].desc;
+	if (!usb_endpoint_is_int_out(endpoint)) {
+		err("kingsun-sir: endpoint 1 is not interrupt OUT");
+		return -ENODEV;
+	}
+
+	ep_out = endpoint->bEndpointAddress;
+	pipe = usb_sndintpipe(dev, ep_out);
+	maxp_out = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+
+	/* Allocate network device container. */
+	net = alloc_irdadev(sizeof(*kingsun));
+	if(!net)
+		goto err_out1;
+
+	SET_MODULE_OWNER(net);
+	SET_NETDEV_DEV(net, &intf->dev);
+	kingsun = netdev_priv(net);
+	kingsun->irlap = NULL;
+	kingsun->tx_urb = NULL;
+	kingsun->rx_urb = NULL;
+	kingsun->ep_in = ep_in;
+	kingsun->ep_out = ep_out;
+	kingsun->in_buf = NULL;
+	kingsun->out_buf = NULL;
+	kingsun->max_rx = (__u8)maxp_in;
+	kingsun->max_tx = (__u8)maxp_out;
+	kingsun->netdev = net;
+	kingsun->usbdev = dev;
+	kingsun->rx_buff.in_frame = FALSE;
+	kingsun->rx_buff.state = OUTSIDE_FRAME;
+	kingsun->rx_buff.skb = NULL;
+	kingsun->receiving = 0;
+	spin_lock_init(&kingsun->lock);
+
+	/* Allocate input buffer */
+	kingsun->in_buf = (__u8 *)kmalloc(kingsun->max_rx, GFP_KERNEL);
+	if (!kingsun->in_buf)
+		goto free_mem;
+
+	/* Allocate output buffer */
+	kingsun->out_buf = (__u8 *)kmalloc(KINGSUN_FIFO_SIZE, GFP_KERNEL);
+	if (!kingsun->out_buf)
+		goto free_mem;
+
+	printk(KERN_INFO "KingSun/DonShine IRDA/USB found at address %d, "
+		"Vendor: %x, Product: %x\n",
+	       dev->devnum, le16_to_cpu(dev->descriptor.idVendor),
+	       le16_to_cpu(dev->descriptor.idProduct));
+
+	/* Initialize QoS for this device */
+	irda_init_max_qos_capabilies(&kingsun->qos);
+
+	/* That's the Rx capability. */
+	kingsun->qos.baud_rate.bits       &= IR_9600;
+	kingsun->qos.min_turn_time.bits   &= KINGSUN_MTT;
+	irda_qos_bits_to_value(&kingsun->qos);
+
+	/* Override the network functions we need to use */
+	net->hard_start_xmit = kingsun_hard_xmit;
+	net->open            = kingsun_net_open;
+	net->stop            = kingsun_net_close;
+	net->get_stats	     = kingsun_net_get_stats;
+	net->do_ioctl        = kingsun_net_ioctl;
+
+	ret = register_netdev(net);
+	if (ret != 0)
+		goto free_mem;
+
+	info("IrDA: Registered KingSun/DonShine device %s", net->name);
+
+	usb_set_intfdata(intf, kingsun);
+
+	/* Situation at this point:
+	   - all work buffers allocated
+	   - urbs not allocated, set to NULL
+	   - max rx packet known (in max_rx)
+	   - unwrap state machine (partially) initialized, but skb == NULL
+	 */
+
+	return 0;
+
+free_mem:
+	if (kingsun->out_buf) kfree(kingsun->out_buf);
+	if (kingsun->in_buf) kfree(kingsun->in_buf);
+	free_netdev(net);
+err_out1:
+	return ret;
+}
+
+/*
+ * The current device is removed, the USB layer tell us to shut it down...
+ */
+static void kingsun_disconnect(struct usb_interface *intf)
+{
+	struct kingsun_cb *kingsun = usb_get_intfdata(intf);
+
+	if (!kingsun)
+		return;
+
+	unregister_netdev(kingsun->netdev);
+
+	/* Mop up receive && transmit urb's */
+	if (kingsun->tx_urb != NULL) {
+		usb_kill_urb(kingsun->tx_urb);
+		usb_free_urb(kingsun->tx_urb);
+		kingsun->tx_urb = NULL;
+	}
+	if (kingsun->rx_urb != NULL) {
+		usb_kill_urb(kingsun->rx_urb);
+		usb_free_urb(kingsun->rx_urb);
+		kingsun->rx_urb = NULL;
+	}
+
+	kfree(kingsun->out_buf);
+	kfree(kingsun->in_buf);
+	free_netdev(kingsun->netdev);
+
+	usb_set_intfdata(intf, NULL);
+}
+
+#ifdef CONFIG_PM
+/* USB suspend, so power off the transmitter/receiver */
+static int kingsun_suspend(struct usb_interface *intf, pm_message_t message)
+{
+	struct kingsun_cb *kingsun = usb_get_intfdata(intf);
+
+	netif_device_detach(kingsun->netdev);
+	if (kingsun->tx_urb != NULL) usb_kill_urb(kingsun->tx_urb);
+	if (kingsun->rx_urb != NULL) usb_kill_urb(kingsun->rx_urb);
+	return 0;
+}
+
+/* Coming out of suspend, so reset hardware */
+static int kingsun_resume(struct usb_interface *intf)
+{
+	struct kingsun_cb *kingsun = usb_get_intfdata(intf);
+
+	if (kingsun->rx_urb != NULL)
+		usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
+	netif_device_attach(kingsun->netdev);
+
+	return 0;
+}
+#endif
+
+/*
+ * USB device callbacks
+ */
+static struct usb_driver irda_driver = {
+	.name		= "kingsun-sir",
+	.probe		= kingsun_probe,
+	.disconnect	= kingsun_disconnect,
+	.id_table	= dongles,
+#ifdef CONFIG_PM
+	.suspend	= kingsun_suspend,
+	.resume		= kingsun_resume,
+#endif
+};
+
+/*
+ * Module insertion
+ */
+static int __init kingsun_init(void)
+{
+	return usb_register(&irda_driver);
+}
+module_init(kingsun_init);
+
+/*
+ * Module removal
+ */
+static void __exit kingsun_cleanup(void)
+{
+	/* Deregister the driver and remove all pending instances */
+	usb_deregister(&irda_driver);
+}
+module_exit(kingsun_cleanup);
+
+MODULE_AUTHOR("Alex Villac�s Lasso <a_villacis@palosanto.com>");
+MODULE_DESCRIPTION("IrDA-USB Dongle Driver for KingSun/DonShine");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index bfcfd10..95ce8f4 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -397,7 +397,7 @@
 
 config RTC_DRV_RS5C313
 	tristate "Ricoh RS5C313"
-	depends on RTC_CLASS && BROKEN
+	depends on RTC_CLASS && SH_LANDISK
 	help
 	  If you say yes here you get support for the Ricoh RS5C313 RTC chips.
 
diff --git a/drivers/rtc/rtc-rs5c313.c b/drivers/rtc/rtc-rs5c313.c
index 9d6de37..66eb133 100644
--- a/drivers/rtc/rtc-rs5c313.c
+++ b/drivers/rtc/rtc-rs5c313.c
@@ -126,7 +126,7 @@
 static unsigned char rs5c313_read_data(void)
 {
 	int i;
-	unsigned char data;
+	unsigned char data = 0;
 
 	for (i = 0; i < 8; i++) {
 		ndelay(700);
@@ -194,7 +194,7 @@
 	return;
 }
 
-static inline unsigned char rs5c313_read_cntreg(unsigned char addr)
+static inline unsigned char rs5c313_read_cntreg(void)
 {
 	return rs5c313_read_reg(RS5C313_ADDR_CNTREG);
 }
@@ -212,7 +212,9 @@
 static int rs5c313_rtc_read_time(struct device *dev, struct rtc_time *tm)
 {
 	int data;
+	int cnt;
 
+	cnt = 0;
 	while (1) {
 		RS5C313_CEENABLE;	/* CE:H */
 
@@ -225,6 +227,10 @@
 		RS5C313_CEDISABLE;
 		ndelay(700);	/* CE:L */
 
+		if (cnt++ > 100) {
+			dev_err(dev, "%s: timeout error\n", __FUNCTION__);
+			return -EIO;
+		}
 	}
 
 	data = rs5c313_read_reg(RS5C313_ADDR_SEC);
@@ -266,7 +272,9 @@
 static int rs5c313_rtc_set_time(struct device *dev, struct rtc_time *tm)
 {
 	int data;
+	int cnt;
 
+	cnt = 0;
 	/* busy check. */
 	while (1) {
 		RS5C313_CEENABLE;	/* CE:H */
@@ -279,6 +287,11 @@
 		RS5C313_MISCOP;
 		RS5C313_CEDISABLE;
 		ndelay(700);	/* CE:L */
+
+		if (cnt++ > 100) {
+			dev_err(dev, "%s: timeout error\n", __FUNCTION__);
+			return -EIO;
+		}
 	}
 
 	data = BIN2BCD(tm->tm_sec);
@@ -317,6 +330,7 @@
 static void rs5c313_check_xstp_bit(void)
 {
 	struct rtc_time tm;
+	int cnt;
 
 	RS5C313_CEENABLE;	/* CE:H */
 	if (rs5c313_read_cntreg() & RS5C313_CNTREG_WTEN_XSTP) {
@@ -326,12 +340,16 @@
 		rs5c313_write_cntreg(0x07);
 
 		/* busy check. */
-		while (rs5c313_read_cntreg() & RS5C313_CNTREG_ADJ_BSY)
+		for (cnt = 0; cnt < 100; cnt++) {
+			if (!(rs5c313_read_cntreg() & RS5C313_CNTREG_ADJ_BSY))
+				break;
 			RS5C313_MISCOP;
+		}
 
 		memset(&tm, 0, sizeof(struct rtc_time));
 		tm.tm_mday 	= 1;
-		tm.tm_mon 	= 1;
+		tm.tm_mon 	= 1 - 1;
+		tm.tm_year 	= 2000 - 1900;
 
 		rs5c313_rtc_set_time(NULL, &tm);
 		printk(KERN_ERR "RICHO RS5C313: invalid value, resetting to "
@@ -356,7 +374,7 @@
 
 	platform_set_drvdata(pdev, rtc);
 
-	return err;
+	return 0;
 }
 
 static int __devexit rs5c313_rtc_remove(struct platform_device *pdev)
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 7c9d37f..5e3f748 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -107,6 +107,13 @@
 	  This enables using the Freescale iMX SPI controller in master
 	  mode.
 
+config SPI_MPC52xx_PSC
+	tristate "Freescale MPC52xx PSC SPI controller"
+	depends on SPI_MASTER && PPC_MPC52xx && EXPERIMENTAL
+	help
+	  This enables using the Freescale MPC52xx Programmable Serial
+	  Controller in master SPI mode.
+
 config SPI_MPC83xx
 	tristate "Freescale MPC83xx SPI controller"
 	depends on SPI_MASTER && PPC_83xx && EXPERIMENTAL
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 624b636..5788d86 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -19,6 +19,7 @@
 obj-$(CONFIG_SPI_IMX)			+= spi_imx.o
 obj-$(CONFIG_SPI_PXA2XX)		+= pxa2xx_spi.o
 obj-$(CONFIG_SPI_OMAP_UWIRE)		+= omap_uwire.o
+obj-$(CONFIG_SPI_MPC52xx_PSC)		+= mpc52xx_psc_spi.o
 obj-$(CONFIG_SPI_MPC83xx)		+= spi_mpc83xx.o
 obj-$(CONFIG_SPI_S3C24XX_GPIO)		+= spi_s3c24xx_gpio.o
 obj-$(CONFIG_SPI_S3C24XX)		+= spi_s3c24xx.o
diff --git a/drivers/spi/mpc52xx_psc_spi.c b/drivers/spi/mpc52xx_psc_spi.c
new file mode 100644
index 0000000..052359f
--- /dev/null
+++ b/drivers/spi/mpc52xx_psc_spi.c
@@ -0,0 +1,654 @@
+/*
+ * MPC52xx SPC in SPI mode driver.
+ *
+ * Maintainer: Dragos Carp
+ *
+ * Copyright (C) 2006 TOPTICA Photonics AG.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+
+#if defined(CONFIG_PPC_MERGE)
+#include <asm/of_platform.h>
+#else
+#include <linux/platform_device.h>
+#endif
+
+#include <linux/workqueue.h>
+#include <linux/completion.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/spi/spi.h>
+#include <linux/fsl_devices.h>
+
+#include <asm/mpc52xx.h>
+#include <asm/mpc52xx_psc.h>
+
+#define MCLK 20000000 /* PSC port MClk in hz */
+
+struct mpc52xx_psc_spi {
+	/* fsl_spi_platform data */
+	void (*activate_cs)(u8, u8);
+	void (*deactivate_cs)(u8, u8);
+	u32 sysclk;
+
+	/* driver internal data */
+	struct mpc52xx_psc __iomem *psc;
+	unsigned int irq;
+	u8 bits_per_word;
+	u8 busy;
+
+	struct workqueue_struct *workqueue;
+	struct work_struct work;
+
+	struct list_head queue;
+	spinlock_t lock;
+
+	struct completion done;
+};
+
+/* controller state */
+struct mpc52xx_psc_spi_cs {
+	int bits_per_word;
+	int speed_hz;
+};
+
+/* set clock freq, clock ramp, bits per work
+ * if t is NULL then reset the values to the default values
+ */
+static int mpc52xx_psc_spi_transfer_setup(struct spi_device *spi,
+		struct spi_transfer *t)
+{
+	struct mpc52xx_psc_spi_cs *cs = spi->controller_state;
+
+	cs->speed_hz = (t && t->speed_hz)
+			? t->speed_hz : spi->max_speed_hz;
+	cs->bits_per_word = (t && t->bits_per_word)
+			? t->bits_per_word : spi->bits_per_word;
+	cs->bits_per_word = ((cs->bits_per_word + 7) / 8) * 8;
+	return 0;
+}
+
+static void mpc52xx_psc_spi_activate_cs(struct spi_device *spi)
+{
+	struct mpc52xx_psc_spi_cs *cs = spi->controller_state;
+	struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);
+	struct mpc52xx_psc __iomem *psc = mps->psc;
+	u32 sicr;
+	u16 ccr;
+
+	sicr = in_be32(&psc->sicr);
+
+	/* Set clock phase and polarity */
+	if (spi->mode & SPI_CPHA)
+		sicr |= 0x00001000;
+	else
+		sicr &= ~0x00001000;
+	if (spi->mode & SPI_CPOL)
+		sicr |= 0x00002000;
+	else
+		sicr &= ~0x00002000;
+
+	if (spi->mode & SPI_LSB_FIRST)
+		sicr |= 0x10000000;
+	else
+		sicr &= ~0x10000000;
+	out_be32(&psc->sicr, sicr);
+
+	/* Set clock frequency and bits per word
+	 * Because psc->ccr is defined as 16bit register instead of 32bit
+	 * just set the lower byte of BitClkDiv
+	 */
+	ccr = in_be16(&psc->ccr);
+	ccr &= 0xFF00;
+	if (cs->speed_hz)
+		ccr |= (MCLK / cs->speed_hz - 1) & 0xFF;
+	else /* by default SPI Clk 1MHz */
+		ccr |= (MCLK / 1000000 - 1) & 0xFF;
+	out_be16(&psc->ccr, ccr);
+	mps->bits_per_word = cs->bits_per_word;
+
+	if (mps->activate_cs)
+		mps->activate_cs(spi->chip_select,
+				(spi->mode & SPI_CS_HIGH) ? 1 : 0);
+}
+
+static void mpc52xx_psc_spi_deactivate_cs(struct spi_device *spi)
+{
+	struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);
+
+	if (mps->deactivate_cs)
+		mps->deactivate_cs(spi->chip_select,
+				(spi->mode & SPI_CS_HIGH) ? 1 : 0);
+}
+
+#define MPC52xx_PSC_BUFSIZE (MPC52xx_PSC_RFNUM_MASK + 1)
+/* wake up when 80% fifo full */
+#define MPC52xx_PSC_RFALARM (MPC52xx_PSC_BUFSIZE * 20 / 100)
+
+static int mpc52xx_psc_spi_transfer_rxtx(struct spi_device *spi,
+						struct spi_transfer *t)
+{
+	struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);
+	struct mpc52xx_psc __iomem *psc = mps->psc;
+	unsigned rb = 0;	/* number of bytes receieved */
+	unsigned sb = 0;	/* number of bytes sent */
+	unsigned char *rx_buf = (unsigned char *)t->rx_buf;
+	unsigned char *tx_buf = (unsigned char *)t->tx_buf;
+	unsigned rfalarm;
+	unsigned send_at_once = MPC52xx_PSC_BUFSIZE;
+	unsigned recv_at_once;
+	unsigned bpw = mps->bits_per_word / 8;
+
+	if (!t->tx_buf && !t->rx_buf && t->len)
+		return -EINVAL;
+
+	/* enable transmiter/receiver */
+	out_8(&psc->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);
+	while (rb < t->len) {
+		if (t->len - rb > MPC52xx_PSC_BUFSIZE) {
+			rfalarm = MPC52xx_PSC_RFALARM;
+		} else {
+			send_at_once = t->len - sb;
+			rfalarm = MPC52xx_PSC_BUFSIZE - (t->len - rb);
+		}
+
+		dev_dbg(&spi->dev, "send %d bytes...\n", send_at_once);
+		if (tx_buf) {
+			for (; send_at_once; sb++, send_at_once--) {
+				/* set EOF flag */
+				if (mps->bits_per_word
+						&& (sb + 1) % bpw == 0)
+					out_8(&psc->ircr2, 0x01);
+				out_8(&psc->mpc52xx_psc_buffer_8, tx_buf[sb]);
+			}
+		} else {
+			for (; send_at_once; sb++, send_at_once--) {
+				/* set EOF flag */
+				if (mps->bits_per_word
+						&& ((sb + 1) % bpw) == 0)
+					out_8(&psc->ircr2, 0x01);
+				out_8(&psc->mpc52xx_psc_buffer_8, 0);
+			}
+		}
+
+
+		/* enable interupts and wait for wake up
+		 * if just one byte is expected the Rx FIFO genererates no
+		 * FFULL interrupt, so activate the RxRDY interrupt
+		 */
+		out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
+		if (t->len - rb == 1) {
+			out_8(&psc->mode, 0);
+		} else {
+			out_8(&psc->mode, MPC52xx_PSC_MODE_FFULL);
+			out_be16(&psc->rfalarm, rfalarm);
+		}
+		out_be16(&psc->mpc52xx_psc_imr, MPC52xx_PSC_IMR_RXRDY);
+		wait_for_completion(&mps->done);
+		recv_at_once = in_be16(&psc->rfnum);
+		dev_dbg(&spi->dev, "%d bytes received\n", recv_at_once);
+
+		send_at_once = recv_at_once;
+		if (rx_buf) {
+			for (; recv_at_once; rb++, recv_at_once--)
+				rx_buf[rb] = in_8(&psc->mpc52xx_psc_buffer_8);
+		} else {
+			for (; recv_at_once; rb++, recv_at_once--)
+				in_8(&psc->mpc52xx_psc_buffer_8);
+		}
+	}
+	/* disable transmiter/receiver */
+	out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
+
+	return 0;
+}
+
+static void mpc52xx_psc_spi_work(struct work_struct *work)
+{
+	struct mpc52xx_psc_spi *mps =
+		container_of(work, struct mpc52xx_psc_spi, work);
+
+	spin_lock_irq(&mps->lock);
+	mps->busy = 1;
+	while (!list_empty(&mps->queue)) {
+		struct spi_message *m;
+		struct spi_device *spi;
+		struct spi_transfer *t = NULL;
+		unsigned cs_change;
+		int status;
+
+		m = container_of(mps->queue.next, struct spi_message, queue);
+		list_del_init(&m->queue);
+		spin_unlock_irq(&mps->lock);
+
+		spi = m->spi;
+		cs_change = 1;
+		status = 0;
+		list_for_each_entry (t, &m->transfers, transfer_list) {
+			if (t->bits_per_word || t->speed_hz) {
+				status = mpc52xx_psc_spi_transfer_setup(spi, t);
+				if (status < 0)
+					break;
+			}
+
+			if (cs_change)
+				mpc52xx_psc_spi_activate_cs(spi);
+			cs_change = t->cs_change;
+
+			status = mpc52xx_psc_spi_transfer_rxtx(spi, t);
+			if (status)
+				break;
+			m->actual_length += t->len;
+
+			if (t->delay_usecs)
+				udelay(t->delay_usecs);
+
+			if (cs_change)
+				mpc52xx_psc_spi_deactivate_cs(spi);
+		}
+
+		m->status = status;
+		m->complete(m->context);
+
+		if (status || !cs_change)
+			mpc52xx_psc_spi_deactivate_cs(spi);
+
+		mpc52xx_psc_spi_transfer_setup(spi, NULL);
+
+		spin_lock_irq(&mps->lock);
+	}
+	mps->busy = 0;
+	spin_unlock_irq(&mps->lock);
+}
+
+static int mpc52xx_psc_spi_setup(struct spi_device *spi)
+{
+	struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);
+	struct mpc52xx_psc_spi_cs *cs = spi->controller_state;
+	unsigned long flags;
+
+	if (spi->bits_per_word%8)
+		return -EINVAL;
+
+	if (!cs) {
+		cs = kzalloc(sizeof *cs, GFP_KERNEL);
+		if (!cs)
+			return -ENOMEM;
+		spi->controller_state = cs;
+	}
+
+	cs->bits_per_word = spi->bits_per_word;
+	cs->speed_hz = spi->max_speed_hz;
+
+	spin_lock_irqsave(&mps->lock, flags);
+	if (!mps->busy)
+		mpc52xx_psc_spi_deactivate_cs(spi);
+	spin_unlock_irqrestore(&mps->lock, flags);
+
+	return 0;
+}
+
+static int mpc52xx_psc_spi_transfer(struct spi_device *spi,
+		struct spi_message *m)
+{
+	struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);
+	unsigned long flags;
+
+	m->actual_length = 0;
+	m->status = -EINPROGRESS;
+
+	spin_lock_irqsave(&mps->lock, flags);
+	list_add_tail(&m->queue, &mps->queue);
+	queue_work(mps->workqueue, &mps->work);
+	spin_unlock_irqrestore(&mps->lock, flags);
+
+	return 0;
+}
+
+static void mpc52xx_psc_spi_cleanup(struct spi_device *spi)
+{
+	kfree(spi->controller_state);
+}
+
+static int mpc52xx_psc_spi_port_config(int psc_id, struct mpc52xx_psc_spi *mps)
+{
+	struct mpc52xx_cdm __iomem *cdm;
+	struct mpc52xx_gpio __iomem *gpio;
+	struct mpc52xx_psc __iomem *psc = mps->psc;
+	u32 ul;
+	u32 mclken_div;
+	int ret = 0;
+
+#if defined(CONFIG_PPC_MERGE)
+	cdm = mpc52xx_find_and_map("mpc52xx-cdm");
+	gpio = mpc52xx_find_and_map("mpc52xx-gpio");
+#else
+	cdm = ioremap(MPC52xx_PA(MPC52xx_CDM_OFFSET), MPC52xx_CDM_SIZE);
+	gpio = ioremap(MPC52xx_PA(MPC52xx_GPIO_OFFSET), MPC52xx_GPIO_SIZE);
+#endif
+	if (!cdm || !gpio) {
+		printk(KERN_ERR "Error mapping CDM/GPIO\n");
+		ret = -EFAULT;
+		goto unmap_regs;
+	}
+
+	/* default sysclk is 512MHz */
+	mclken_div = 0x8000 |
+		(((mps->sysclk ? mps->sysclk : 512000000) / MCLK) & 0x1FF);
+
+	switch (psc_id) {
+	case 1:
+		ul = in_be32(&gpio->port_config);
+		ul &= 0xFFFFFFF8;
+		ul |= 0x00000006;
+		out_be32(&gpio->port_config, ul);
+		out_be16(&cdm->mclken_div_psc1, mclken_div);
+		ul = in_be32(&cdm->clk_enables);
+		ul |= 0x00000020;
+		out_be32(&cdm->clk_enables, ul);
+		break;
+	case 2:
+		ul = in_be32(&gpio->port_config);
+		ul &= 0xFFFFFF8F;
+		ul |= 0x00000060;
+		out_be32(&gpio->port_config, ul);
+		out_be16(&cdm->mclken_div_psc2, mclken_div);
+		ul = in_be32(&cdm->clk_enables);
+		ul |= 0x00000040;
+		out_be32(&cdm->clk_enables, ul);
+		break;
+	case 3:
+		ul = in_be32(&gpio->port_config);
+		ul &= 0xFFFFF0FF;
+		ul |= 0x00000600;
+		out_be32(&gpio->port_config, ul);
+		out_be16(&cdm->mclken_div_psc3, mclken_div);
+		ul = in_be32(&cdm->clk_enables);
+		ul |= 0x00000080;
+		out_be32(&cdm->clk_enables, ul);
+		break;
+	case 6:
+		ul = in_be32(&gpio->port_config);
+		ul &= 0xFF8FFFFF;
+		ul |= 0x00700000;
+		out_be32(&gpio->port_config, ul);
+		out_be16(&cdm->mclken_div_psc6, mclken_div);
+		ul = in_be32(&cdm->clk_enables);
+		ul |= 0x00000010;
+		out_be32(&cdm->clk_enables, ul);
+		break;
+	default:
+		ret = -EINVAL;
+		goto unmap_regs;
+	}
+
+	/* Reset the PSC into a known state */
+	out_8(&psc->command, MPC52xx_PSC_RST_RX);
+	out_8(&psc->command, MPC52xx_PSC_RST_TX);
+	out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
+
+	/* Disable interrupts, interrupts are based on alarm level */
+	out_be16(&psc->mpc52xx_psc_imr, 0);
+	out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
+	out_8(&psc->rfcntl, 0);
+	out_8(&psc->mode, MPC52xx_PSC_MODE_FFULL);
+
+	/* Configure 8bit codec mode as a SPI master and use EOF flags */
+	/* SICR_SIM_CODEC8|SICR_GENCLK|SICR_SPI|SICR_MSTR|SICR_USEEOF */
+	out_be32(&psc->sicr, 0x0180C800);
+	out_be16(&psc->ccr, 0x070F); /* by default SPI Clk 1MHz */
+
+	/* Set 2ms DTL delay */
+	out_8(&psc->ctur, 0x00);
+	out_8(&psc->ctlr, 0x84);
+
+	mps->bits_per_word = 8;
+
+unmap_regs:
+	if (cdm)
+		iounmap(cdm);
+	if (gpio)
+		iounmap(gpio);
+
+	return ret;
+}
+
+static irqreturn_t mpc52xx_psc_spi_isr(int irq, void *dev_id)
+{
+	struct mpc52xx_psc_spi *mps = (struct mpc52xx_psc_spi *)dev_id;
+	struct mpc52xx_psc __iomem *psc = mps->psc;
+
+	/* disable interrupt and wake up the work queue */
+	if (in_be16(&psc->mpc52xx_psc_isr) & MPC52xx_PSC_IMR_RXRDY) {
+		out_be16(&psc->mpc52xx_psc_imr, 0);
+		complete(&mps->done);
+		return IRQ_HANDLED;
+	}
+	return IRQ_NONE;
+}
+
+/* bus_num is used only for the case dev->platform_data == NULL */
+static int __init mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr,
+				u32 size, unsigned int irq, s16 bus_num)
+{
+	struct fsl_spi_platform_data *pdata = dev->platform_data;
+	struct mpc52xx_psc_spi *mps;
+	struct spi_master *master;
+	int ret;
+
+	if (pdata == NULL)
+		return -ENODEV;
+
+	master = spi_alloc_master(dev, sizeof *mps);
+	if (master == NULL)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, master);
+	mps = spi_master_get_devdata(master);
+
+	mps->irq = irq;
+	if (pdata == NULL) {
+		dev_warn(dev, "probe called without platform data, no "
+				"(de)activate_cs function will be called\n");
+		mps->activate_cs = NULL;
+		mps->deactivate_cs = NULL;
+		mps->sysclk = 0;
+		master->bus_num = bus_num;
+		master->num_chipselect = 255;
+	} else {
+		mps->activate_cs = pdata->activate_cs;
+		mps->deactivate_cs = pdata->deactivate_cs;
+		mps->sysclk = pdata->sysclk;
+		master->bus_num = pdata->bus_num;
+		master->num_chipselect = pdata->max_chipselect;
+	}
+	master->setup = mpc52xx_psc_spi_setup;
+	master->transfer = mpc52xx_psc_spi_transfer;
+	master->cleanup = mpc52xx_psc_spi_cleanup;
+
+	mps->psc = ioremap(regaddr, size);
+	if (!mps->psc) {
+		dev_err(dev, "could not ioremap I/O port range\n");
+		ret = -EFAULT;
+		goto free_master;
+	}
+
+	ret = request_irq(mps->irq, mpc52xx_psc_spi_isr, 0, "mpc52xx-psc-spi",
+				mps);
+	if (ret)
+		goto free_master;
+
+	ret = mpc52xx_psc_spi_port_config(master->bus_num, mps);
+	if (ret < 0)
+		goto free_irq;
+
+	spin_lock_init(&mps->lock);
+	init_completion(&mps->done);
+	INIT_WORK(&mps->work, mpc52xx_psc_spi_work);
+	INIT_LIST_HEAD(&mps->queue);
+
+	mps->workqueue = create_singlethread_workqueue(
+		master->cdev.dev->bus_id);
+	if (mps->workqueue == NULL) {
+		ret = -EBUSY;
+		goto free_irq;
+	}
+
+	ret = spi_register_master(master);
+	if (ret < 0)
+		goto unreg_master;
+
+	return ret;
+
+unreg_master:
+	destroy_workqueue(mps->workqueue);
+free_irq:
+	free_irq(mps->irq, mps);
+free_master:
+	if (mps->psc)
+		iounmap(mps->psc);
+	spi_master_put(master);
+
+	return ret;
+}
+
+static int __exit mpc52xx_psc_spi_do_remove(struct device *dev)
+{
+	struct spi_master *master = dev_get_drvdata(dev);
+	struct mpc52xx_psc_spi *mps = spi_master_get_devdata(master);
+
+	flush_workqueue(mps->workqueue);
+	destroy_workqueue(mps->workqueue);
+	spi_unregister_master(master);
+	free_irq(mps->irq, mps);
+	if (mps->psc)
+		iounmap(mps->psc);
+
+	return 0;
+}
+
+#if !defined(CONFIG_PPC_MERGE)
+static int __init mpc52xx_psc_spi_probe(struct platform_device *dev)
+{
+	switch(dev->id) {
+	case 1:
+	case 2:
+	case 3:
+	case 6:
+		return mpc52xx_psc_spi_do_probe(&dev->dev,
+			MPC52xx_PA(MPC52xx_PSCx_OFFSET(dev->id)),
+			MPC52xx_PSC_SIZE, platform_get_irq(dev, 0), dev->id);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int __exit mpc52xx_psc_spi_remove(struct platform_device *dev)
+{
+	return mpc52xx_psc_spi_do_remove(&dev->dev);
+}
+
+static struct platform_driver mpc52xx_psc_spi_platform_driver = {
+	.remove = __exit_p(mpc52xx_psc_spi_remove),
+	.driver = {
+		.name = "mpc52xx-psc-spi",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init mpc52xx_psc_spi_init(void)
+{
+	return platform_driver_probe(&mpc52xx_psc_spi_platform_driver,
+			mpc52xx_psc_spi_probe);
+}
+module_init(mpc52xx_psc_spi_init);
+
+static void __exit mpc52xx_psc_spi_exit(void)
+{
+	platform_driver_unregister(&mpc52xx_psc_spi_platform_driver);
+}
+module_exit(mpc52xx_psc_spi_exit);
+
+#else	/* defined(CONFIG_PPC_MERGE) */
+
+static int __init mpc52xx_psc_spi_of_probe(struct of_device *op,
+	const struct of_device_id *match)
+{
+	const u32 *regaddr_p;
+	u64 regaddr64, size64;
+	s16 id = -1;
+
+	regaddr_p = of_get_address(op->node, 0, &size64, NULL);
+	if (!regaddr_p) {
+		printk(KERN_ERR "Invalid PSC address\n");
+		return -EINVAL;
+	}
+	regaddr64 = of_translate_address(op->node, regaddr_p);
+
+	if (op->dev.platform_data == NULL) {
+		struct device_node *np;
+		int i = 0;
+
+		for_each_node_by_type(np, "spi") {
+			if (of_find_device_by_node(np) == op) {
+				id = i;
+				break;
+			}
+			i++;
+		}
+	}
+
+	return mpc52xx_psc_spi_do_probe(&op->dev, (u32)regaddr64, (u32)size64,
+					irq_of_parse_and_map(op->node, 0), id);
+}
+
+static int __exit mpc52xx_psc_spi_of_remove(struct of_device *op)
+{
+	return mpc52xx_psc_spi_do_remove(&op->dev);
+}
+
+static struct of_device_id mpc52xx_psc_spi_of_match[] = {
+	{ .type = "spi", .compatible = "mpc52xx-psc-spi", },
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, mpc52xx_psc_spi_of_match);
+
+static struct of_platform_driver mpc52xx_psc_spi_of_driver = {
+	.owner = THIS_MODULE,
+	.name = "mpc52xx-psc-spi",
+	.match_table = mpc52xx_psc_spi_of_match,
+	.probe = mpc52xx_psc_spi_of_probe,
+	.remove = __exit_p(mpc52xx_psc_spi_of_remove),
+	.driver = {
+		.name = "mpc52xx-psc-spi",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init mpc52xx_psc_spi_init(void)
+{
+	return of_register_platform_driver(&mpc52xx_psc_spi_of_driver);
+}
+module_init(mpc52xx_psc_spi_init);
+
+static void __exit mpc52xx_psc_spi_exit(void)
+{
+	of_unregister_platform_driver(&mpc52xx_psc_spi_of_driver);
+}
+module_exit(mpc52xx_psc_spi_exit);
+
+#endif	/* defined(CONFIG_PPC_MERGE) */
+
+MODULE_AUTHOR("Dragos Carp");
+MODULE_DESCRIPTION("MPC52xx PSC SPI Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index f544388..eebcb70 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -748,6 +748,22 @@
 	  working with S1D13806). Product specs at
 	  <http://www.erd.epson.com/vdc/html/legacy_13xxx.htm>
 
+config FB_ATMEL
+	tristate "AT91/AT32 LCD Controller support"
+	depends on FB && (ARCH_AT91SAM9261 || ARCH_AT91SAM9263 || AVR32)
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	help
+	  This enables support for the AT91/AT32 LCD Controller.
+
+config FB_INTSRAM
+	bool "Frame Buffer in internal SRAM"
+	depends on FB_ATMEL && ARCH_AT91SAM9261
+	help
+	  Say Y if you want to map Frame Buffer in internal SRAM. Say N if you want
+	  to let frame buffer in external SDRAM.
+
 config FB_NVIDIA
 	tristate "nVidia Framebuffer Support"
 	depends on FB && PCI
@@ -780,6 +796,15 @@
 	  independently validate video mode parameters, you should say Y
 	  here.
 
+config FB_NVIDIA_DEBUG
+	bool "Lots of debug output"
+	depends on FB_NVIDIA
+	default n
+	help
+	  Say Y here if you want the nVidia driver to output all sorts
+	  of debugging information to provide to the maintainer when
+	  something goes wrong.
+
 config FB_NVIDIA_BACKLIGHT
 	bool "Support for backlight control"
 	depends on FB_NVIDIA
@@ -819,7 +844,7 @@
 	  here.
 
 config FB_RIVA_DEBUG
-	bool "Lots of debug output from Riva(nVidia) driver"
+	bool "Lots of debug output"
 	depends on FB_RIVA
 	default n
 	help
@@ -1431,8 +1456,11 @@
 	  and ICS 5342 RAMDAC.
 
 config FB_PM3
-	tristate "Permedia3 support"
-	depends on FB && PCI && BROKEN
+	tristate "Permedia3 support (EXPERIMENTAL)"
+	depends on FB && PCI && EXPERIMENTAL
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
 	help
 	  This is the frame buffer device driver for the 3DLabs Permedia3
 	  chipset, used in Formac ProFormance III, 3DLabs Oxygen VX1 &
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 0b70567..bd8b052 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -87,6 +87,7 @@
 obj-$(CONFIG_FB_SA1100)           += sa1100fb.o
 obj-$(CONFIG_FB_HIT)              += hitfb.o
 obj-$(CONFIG_FB_EPSON1355)	  += epson1355fb.o
+obj-$(CONFIG_FB_ATMEL)		  += atmel_lcdfb.o
 obj-$(CONFIG_FB_PVR2)             += pvr2fb.o
 obj-$(CONFIG_FB_VOODOO1)          += sstfb.o
 obj-$(CONFIG_FB_ARMCLCD)	  += amba-clcd.o
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
new file mode 100644
index 0000000..e1d5bd0
--- /dev/null
+++ b/drivers/video/atmel_lcdfb.c
@@ -0,0 +1,752 @@
+/*
+ *  Driver for AT91/AT32 LCD Controller
+ *
+ *  Copyright (C) 2007 Atmel Corporation
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include <asm/arch/board.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/gpio.h>
+
+#include <video/atmel_lcdc.h>
+
+#define lcdc_readl(sinfo, reg)		__raw_readl((sinfo)->mmio+(reg))
+#define lcdc_writel(sinfo, reg, val)	__raw_writel((val), (sinfo)->mmio+(reg))
+
+/* configurable parameters */
+#define ATMEL_LCDC_CVAL_DEFAULT		0xc8
+#define ATMEL_LCDC_DMA_BURST_LEN	8
+
+#if defined(CONFIG_ARCH_AT91SAM9263)
+#define ATMEL_LCDC_FIFO_SIZE		2048
+#else
+#define ATMEL_LCDC_FIFO_SIZE		512
+#endif
+
+#if defined(CONFIG_ARCH_AT91)
+#define	ATMEL_LCDFB_FBINFO_DEFAULT	FBINFO_DEFAULT
+
+static inline void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
+					struct fb_var_screeninfo *var)
+{
+
+}
+#elif defined(CONFIG_AVR32)
+#define	ATMEL_LCDFB_FBINFO_DEFAULT	(FBINFO_DEFAULT \
+					| FBINFO_PARTIAL_PAN_OK \
+					| FBINFO_HWACCEL_XPAN \
+					| FBINFO_HWACCEL_YPAN)
+
+static void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
+				     struct fb_var_screeninfo *var)
+{
+	u32 dma2dcfg;
+	u32 pixeloff;
+
+	pixeloff = (var->xoffset * var->bits_per_pixel) & 0x1f;
+
+	dma2dcfg = ((var->xres_virtual - var->xres) * var->bits_per_pixel) / 8;
+	dma2dcfg |= pixeloff << ATMEL_LCDC_PIXELOFF_OFFSET;
+	lcdc_writel(sinfo, ATMEL_LCDC_DMA2DCFG, dma2dcfg);
+
+	/* Update configuration */
+	lcdc_writel(sinfo, ATMEL_LCDC_DMACON,
+		    lcdc_readl(sinfo, ATMEL_LCDC_DMACON)
+		    | ATMEL_LCDC_DMAUPDT);
+}
+#endif
+
+
+static struct fb_fix_screeninfo atmel_lcdfb_fix __initdata = {
+	.type		= FB_TYPE_PACKED_PIXELS,
+	.visual		= FB_VISUAL_TRUECOLOR,
+	.xpanstep	= 0,
+	.ypanstep	= 0,
+	.ywrapstep	= 0,
+	.accel		= FB_ACCEL_NONE,
+};
+
+
+static void atmel_lcdfb_update_dma(struct fb_info *info,
+			       struct fb_var_screeninfo *var)
+{
+	struct atmel_lcdfb_info *sinfo = info->par;
+	struct fb_fix_screeninfo *fix = &info->fix;
+	unsigned long dma_addr;
+
+	dma_addr = (fix->smem_start + var->yoffset * fix->line_length
+		    + var->xoffset * var->bits_per_pixel / 8);
+
+	dma_addr &= ~3UL;
+
+	/* Set framebuffer DMA base address and pixel offset */
+	lcdc_writel(sinfo, ATMEL_LCDC_DMABADDR1, dma_addr);
+
+	atmel_lcdfb_update_dma2d(sinfo, var);
+}
+
+static inline void atmel_lcdfb_free_video_memory(struct atmel_lcdfb_info *sinfo)
+{
+	struct fb_info *info = sinfo->info;
+
+	dma_free_writecombine(info->device, info->fix.smem_len,
+				info->screen_base, info->fix.smem_start);
+}
+
+/**
+ *	atmel_lcdfb_alloc_video_memory - Allocate framebuffer memory
+ *	@sinfo: the frame buffer to allocate memory for
+ */
+static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo)
+{
+	struct fb_info *info = sinfo->info;
+	struct fb_var_screeninfo *var = &info->var;
+
+	info->fix.smem_len = (var->xres_virtual * var->yres_virtual
+			    * ((var->bits_per_pixel + 7) / 8));
+
+	info->screen_base = dma_alloc_writecombine(info->device, info->fix.smem_len,
+					(dma_addr_t *)&info->fix.smem_start, GFP_KERNEL);
+
+	if (!info->screen_base) {
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+/**
+ *      atmel_lcdfb_check_var - Validates a var passed in.
+ *      @var: frame buffer variable screen structure
+ *      @info: frame buffer structure that represents a single frame buffer
+ *
+ *	Checks to see if the hardware supports the state requested by
+ *	var passed in. This function does not alter the hardware
+ *	state!!!  This means the data stored in struct fb_info and
+ *	struct atmel_lcdfb_info do not change. This includes the var
+ *	inside of struct fb_info.  Do NOT change these. This function
+ *	can be called on its own if we intent to only test a mode and
+ *	not actually set it. The stuff in modedb.c is a example of
+ *	this. If the var passed in is slightly off by what the
+ *	hardware can support then we alter the var PASSED in to what
+ *	we can do. If the hardware doesn't support mode change a
+ *	-EINVAL will be returned by the upper layers. You don't need
+ *	to implement this function then. If you hardware doesn't
+ *	support changing the resolution then this function is not
+ *	needed. In this case the driver would just provide a var that
+ *	represents the static state the screen is in.
+ *
+ *	Returns negative errno on error, or zero on success.
+ */
+static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
+			     struct fb_info *info)
+{
+	struct device *dev = info->device;
+	struct atmel_lcdfb_info *sinfo = info->par;
+	unsigned long clk_value_khz;
+
+	clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
+
+	dev_dbg(dev, "%s:\n", __func__);
+	dev_dbg(dev, "  resolution: %ux%u\n", var->xres, var->yres);
+	dev_dbg(dev, "  pixclk:     %lu KHz\n", PICOS2KHZ(var->pixclock));
+	dev_dbg(dev, "  bpp:        %u\n", var->bits_per_pixel);
+	dev_dbg(dev, "  clk:        %lu KHz\n", clk_value_khz);
+
+	if ((PICOS2KHZ(var->pixclock) * var->bits_per_pixel / 8) > clk_value_khz) {
+		dev_err(dev, "%lu KHz pixel clock is too fast\n", PICOS2KHZ(var->pixclock));
+		return -EINVAL;
+	}
+
+	/* Force same alignment for each line */
+	var->xres = (var->xres + 3) & ~3UL;
+	var->xres_virtual = (var->xres_virtual + 3) & ~3UL;
+
+	var->red.msb_right = var->green.msb_right = var->blue.msb_right = 0;
+	var->transp.msb_right = 0;
+	var->transp.offset = var->transp.length = 0;
+	var->xoffset = var->yoffset = 0;
+
+	switch (var->bits_per_pixel) {
+	case 2:
+	case 4:
+	case 8:
+		var->red.offset = var->green.offset = var->blue.offset = 0;
+		var->red.length = var->green.length = var->blue.length
+			= var->bits_per_pixel;
+		break;
+	case 15:
+	case 16:
+		var->red.offset = 0;
+		var->green.offset = 5;
+		var->blue.offset = 10;
+		var->red.length = var->green.length = var->blue.length = 5;
+		break;
+	case 24:
+	case 32:
+		var->red.offset = 0;
+		var->green.offset = 8;
+		var->blue.offset = 16;
+		var->red.length = var->green.length = var->blue.length = 8;
+		break;
+	default:
+		dev_err(dev, "color depth %d not supported\n",
+					var->bits_per_pixel);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ *      atmel_lcdfb_set_par - Alters the hardware state.
+ *      @info: frame buffer structure that represents a single frame buffer
+ *
+ *	Using the fb_var_screeninfo in fb_info we set the resolution
+ *	of the this particular framebuffer. This function alters the
+ *	par AND the fb_fix_screeninfo stored in fb_info. It doesn't
+ *	not alter var in fb_info since we are using that data. This
+ *	means we depend on the data in var inside fb_info to be
+ *	supported by the hardware.  atmel_lcdfb_check_var is always called
+ *	before atmel_lcdfb_set_par to ensure this.  Again if you can't
+ *	change the resolution you don't need this function.
+ *
+ */
+static int atmel_lcdfb_set_par(struct fb_info *info)
+{
+	struct atmel_lcdfb_info *sinfo = info->par;
+	unsigned long value;
+	unsigned long clk_value_khz;
+
+	dev_dbg(info->device, "%s:\n", __func__);
+	dev_dbg(info->device, "  * resolution: %ux%u (%ux%u virtual)\n",
+		 info->var.xres, info->var.yres,
+		 info->var.xres_virtual, info->var.yres_virtual);
+
+	/* Turn off the LCD controller and the DMA controller */
+	lcdc_writel(sinfo, ATMEL_LCDC_PWRCON, sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET);
+
+	lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0);
+
+	if (info->var.bits_per_pixel <= 8)
+		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+	else
+		info->fix.visual = FB_VISUAL_TRUECOLOR;
+
+	info->fix.line_length = info->var.xres_virtual * (info->var.bits_per_pixel / 8);
+
+	/* Re-initialize the DMA engine... */
+	dev_dbg(info->device, "  * update DMA engine\n");
+	atmel_lcdfb_update_dma(info, &info->var);
+
+	/* ...set frame size and burst length = 8 words (?) */
+	value = (info->var.yres * info->var.xres * info->var.bits_per_pixel) / 32;
+	value |= ((ATMEL_LCDC_DMA_BURST_LEN - 1) << ATMEL_LCDC_BLENGTH_OFFSET);
+	lcdc_writel(sinfo, ATMEL_LCDC_DMAFRMCFG, value);
+
+	/* Now, the LCDC core... */
+
+	/* Set pixel clock */
+	clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
+
+	value = clk_value_khz / PICOS2KHZ(info->var.pixclock);
+
+	if (clk_value_khz % PICOS2KHZ(info->var.pixclock))
+		value++;
+
+	value = (value / 2) - 1;
+
+	if (value <= 0) {
+		dev_notice(info->device, "Bypassing pixel clock divider\n");
+		lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS);
+	} else
+		lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, value << ATMEL_LCDC_CLKVAL_OFFSET);
+
+	/* Initialize control register 2 */
+	value = sinfo->default_lcdcon2;
+
+	if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
+		value |= ATMEL_LCDC_INVLINE_INVERTED;
+	if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
+		value |= ATMEL_LCDC_INVFRAME_INVERTED;
+
+	switch (info->var.bits_per_pixel) {
+		case 1:	value |= ATMEL_LCDC_PIXELSIZE_1; break;
+		case 2: value |= ATMEL_LCDC_PIXELSIZE_2; break;
+		case 4: value |= ATMEL_LCDC_PIXELSIZE_4; break;
+		case 8: value |= ATMEL_LCDC_PIXELSIZE_8; break;
+		case 15: /* fall through */
+		case 16: value |= ATMEL_LCDC_PIXELSIZE_16; break;
+		case 24: value |= ATMEL_LCDC_PIXELSIZE_24; break;
+		case 32: value |= ATMEL_LCDC_PIXELSIZE_32; break;
+		default: BUG(); break;
+	}
+	dev_dbg(info->device, "  * LCDCON2 = %08lx\n", value);
+	lcdc_writel(sinfo, ATMEL_LCDC_LCDCON2, value);
+
+	/* Vertical timing */
+	value = (info->var.vsync_len - 1) << ATMEL_LCDC_VPW_OFFSET;
+	value |= info->var.upper_margin << ATMEL_LCDC_VBP_OFFSET;
+	value |= info->var.lower_margin;
+	dev_dbg(info->device, "  * LCDTIM1 = %08lx\n", value);
+	lcdc_writel(sinfo, ATMEL_LCDC_TIM1, value);
+
+	/* Horizontal timing */
+	value = (info->var.right_margin - 1) << ATMEL_LCDC_HFP_OFFSET;
+	value |= (info->var.hsync_len - 1) << ATMEL_LCDC_HPW_OFFSET;
+	value |= (info->var.left_margin - 1);
+	dev_dbg(info->device, "  * LCDTIM2 = %08lx\n", value);
+	lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value);
+
+	/* Display size */
+	value = (info->var.xres - 1) << ATMEL_LCDC_HOZVAL_OFFSET;
+	value |= info->var.yres - 1;
+	lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value);
+
+	/* FIFO Threshold: Use formula from data sheet */
+	value = ATMEL_LCDC_FIFO_SIZE - (2 * ATMEL_LCDC_DMA_BURST_LEN + 3);
+	lcdc_writel(sinfo, ATMEL_LCDC_FIFO, value);
+
+	/* Toggle LCD_MODE every frame */
+	lcdc_writel(sinfo, ATMEL_LCDC_MVAL, 0);
+
+	/* Disable all interrupts */
+	lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
+
+	/* Set contrast */
+	value = ATMEL_LCDC_PS_DIV8 | ATMEL_LCDC_POL_POSITIVE | ATMEL_LCDC_ENA_PWMENABLE;
+	lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, value);
+	lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
+	/* ...wait for DMA engine to become idle... */
+	while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
+		msleep(10);
+
+	dev_dbg(info->device, "  * re-enable DMA engine\n");
+	/* ...and enable it with updated configuration */
+	lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon);
+
+	dev_dbg(info->device, "  * re-enable LCDC core\n");
+	lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
+		(sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET) | ATMEL_LCDC_PWR);
+
+	dev_dbg(info->device, "  * DONE\n");
+
+	return 0;
+}
+
+static inline unsigned int chan_to_field(unsigned int chan, const struct fb_bitfield *bf)
+{
+	chan &= 0xffff;
+	chan >>= 16 - bf->length;
+	return chan << bf->offset;
+}
+
+/**
+ *  	atmel_lcdfb_setcolreg - Optional function. Sets a color register.
+ *      @regno: Which register in the CLUT we are programming
+ *      @red: The red value which can be up to 16 bits wide
+ *	@green: The green value which can be up to 16 bits wide
+ *	@blue:  The blue value which can be up to 16 bits wide.
+ *	@transp: If supported the alpha value which can be up to 16 bits wide.
+ *      @info: frame buffer info structure
+ *
+ *  	Set a single color register. The values supplied have a 16 bit
+ *  	magnitude which needs to be scaled in this function for the hardware.
+ *	Things to take into consideration are how many color registers, if
+ *	any, are supported with the current color visual. With truecolor mode
+ *	no color palettes are supported. Here a psuedo palette is created
+ *	which we store the value in pseudo_palette in struct fb_info. For
+ *	pseudocolor mode we have a limited color palette. To deal with this
+ *	we can program what color is displayed for a particular pixel value.
+ *	DirectColor is similar in that we can program each color field. If
+ *	we have a static colormap we don't need to implement this function.
+ *
+ *	Returns negative errno on error, or zero on success. In an
+ *	ideal world, this would have been the case, but as it turns
+ *	out, the other drivers return 1 on failure, so that's what
+ *	we're going to do.
+ */
+static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red,
+			     unsigned int green, unsigned int blue,
+			     unsigned int transp, struct fb_info *info)
+{
+	struct atmel_lcdfb_info *sinfo = info->par;
+	unsigned int val;
+	u32 *pal;
+	int ret = 1;
+
+	if (info->var.grayscale)
+		red = green = blue = (19595 * red + 38470 * green
+				      + 7471 * blue) >> 16;
+
+	switch (info->fix.visual) {
+	case FB_VISUAL_TRUECOLOR:
+		if (regno < 16) {
+			pal = info->pseudo_palette;
+
+			val  = chan_to_field(red, &info->var.red);
+			val |= chan_to_field(green, &info->var.green);
+			val |= chan_to_field(blue, &info->var.blue);
+
+			pal[regno] = val;
+			ret = 0;
+		}
+		break;
+
+	case FB_VISUAL_PSEUDOCOLOR:
+		if (regno < 256) {
+			val  = ((red   >> 11) & 0x001f);
+			val |= ((green >>  6) & 0x03e0);
+			val |= ((blue  >>  1) & 0x7c00);
+
+			/*
+			 * TODO: intensity bit. Maybe something like
+			 *   ~(red[10] ^ green[10] ^ blue[10]) & 1
+			 */
+
+			lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val);
+			ret = 0;
+		}
+		break;
+	}
+
+	return ret;
+}
+
+static int atmel_lcdfb_pan_display(struct fb_var_screeninfo *var,
+			       struct fb_info *info)
+{
+	dev_dbg(info->device, "%s\n", __func__);
+
+	atmel_lcdfb_update_dma(info, var);
+
+	return 0;
+}
+
+static struct fb_ops atmel_lcdfb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_check_var	= atmel_lcdfb_check_var,
+	.fb_set_par	= atmel_lcdfb_set_par,
+	.fb_setcolreg	= atmel_lcdfb_setcolreg,
+	.fb_pan_display	= atmel_lcdfb_pan_display,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+};
+
+static irqreturn_t atmel_lcdfb_interrupt(int irq, void *dev_id)
+{
+	struct fb_info *info = dev_id;
+	struct atmel_lcdfb_info *sinfo = info->par;
+	u32 status;
+
+	status = lcdc_readl(sinfo, ATMEL_LCDC_ISR);
+	lcdc_writel(sinfo, ATMEL_LCDC_IDR, status);
+	return IRQ_HANDLED;
+}
+
+static int __init atmel_lcdfb_init_fbinfo(struct atmel_lcdfb_info *sinfo)
+{
+	struct fb_info *info = sinfo->info;
+	int ret = 0;
+
+	memset_io(info->screen_base, 0, info->fix.smem_len);
+	info->var.activate |= FB_ACTIVATE_FORCE | FB_ACTIVATE_NOW;
+
+	dev_info(info->device,
+	       "%luKiB frame buffer at %08lx (mapped at %p)\n",
+	       (unsigned long)info->fix.smem_len / 1024,
+	       (unsigned long)info->fix.smem_start,
+	       info->screen_base);
+
+	/* Allocate colormap */
+	ret = fb_alloc_cmap(&info->cmap, 256, 0);
+	if (ret < 0)
+		dev_err(info->device, "Alloc color map failed\n");
+
+	return ret;
+}
+
+static void atmel_lcdfb_start_clock(struct atmel_lcdfb_info *sinfo)
+{
+	if (sinfo->bus_clk)
+		clk_enable(sinfo->bus_clk);
+	clk_enable(sinfo->lcdc_clk);
+}
+
+static void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo)
+{
+	if (sinfo->bus_clk)
+		clk_disable(sinfo->bus_clk);
+	clk_disable(sinfo->lcdc_clk);
+}
+
+
+static int __init atmel_lcdfb_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct fb_info *info;
+	struct atmel_lcdfb_info *sinfo;
+	struct atmel_lcdfb_info *pdata_sinfo;
+	struct resource *regs = NULL;
+	struct resource *map = NULL;
+	int ret;
+
+	dev_dbg(dev, "%s BEGIN\n", __func__);
+
+	ret = -ENOMEM;
+	info = framebuffer_alloc(sizeof(struct atmel_lcdfb_info), dev);
+	if (!info) {
+		dev_err(dev, "cannot allocate memory\n");
+		goto out;
+	}
+
+	sinfo = info->par;
+
+	if (dev->platform_data) {
+		pdata_sinfo = (struct atmel_lcdfb_info *)dev->platform_data;
+		sinfo->default_bpp = pdata_sinfo->default_bpp;
+		sinfo->default_dmacon = pdata_sinfo->default_dmacon;
+		sinfo->default_lcdcon2 = pdata_sinfo->default_lcdcon2;
+		sinfo->default_monspecs = pdata_sinfo->default_monspecs;
+		sinfo->atmel_lcdfb_power_control = pdata_sinfo->atmel_lcdfb_power_control;
+		sinfo->guard_time = pdata_sinfo->guard_time;
+	} else {
+		dev_err(dev, "cannot get default configuration\n");
+		goto free_info;
+	}
+	sinfo->info = info;
+	sinfo->pdev = pdev;
+
+	strcpy(info->fix.id, sinfo->pdev->name);
+	info->flags = ATMEL_LCDFB_FBINFO_DEFAULT;
+	info->pseudo_palette = sinfo->pseudo_palette;
+	info->fbops = &atmel_lcdfb_ops;
+
+	memcpy(&info->monspecs, sinfo->default_monspecs, sizeof(info->monspecs));
+	info->fix = atmel_lcdfb_fix;
+
+	/* Enable LCDC Clocks */
+	if (cpu_is_at91sam9261() || cpu_is_at32ap7000()) {
+		sinfo->bus_clk = clk_get(dev, "hck1");
+		if (IS_ERR(sinfo->bus_clk)) {
+			ret = PTR_ERR(sinfo->bus_clk);
+			goto free_info;
+		}
+	}
+	sinfo->lcdc_clk = clk_get(dev, "lcdc_clk");
+	if (IS_ERR(sinfo->lcdc_clk)) {
+		ret = PTR_ERR(sinfo->lcdc_clk);
+		goto put_bus_clk;
+	}
+	atmel_lcdfb_start_clock(sinfo);
+
+	ret = fb_find_mode(&info->var, info, NULL, info->monspecs.modedb,
+			info->monspecs.modedb_len, info->monspecs.modedb,
+			sinfo->default_bpp);
+	if (!ret) {
+		dev_err(dev, "no suitable video mode found\n");
+		goto stop_clk;
+	}
+
+
+	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!regs) {
+		dev_err(dev, "resources unusable\n");
+		ret = -ENXIO;
+		goto stop_clk;
+	}
+
+	sinfo->irq_base = platform_get_irq(pdev, 0);
+	if (sinfo->irq_base < 0) {
+		dev_err(dev, "unable to get irq\n");
+		ret = sinfo->irq_base;
+		goto stop_clk;
+	}
+
+	/* Initialize video memory */
+	map = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (map) {
+		/* use a pre-allocated memory buffer */
+		info->fix.smem_start = map->start;
+		info->fix.smem_len = map->end - map->start + 1;
+		if (!request_mem_region(info->fix.smem_start,
+					info->fix.smem_len, pdev->name)) {
+			ret = -EBUSY;
+			goto stop_clk;
+		}
+
+		info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
+		if (!info->screen_base)
+			goto release_intmem;
+	} else {
+		/* alocate memory buffer */
+		ret = atmel_lcdfb_alloc_video_memory(sinfo);
+		if (ret < 0) {
+			dev_err(dev, "cannot allocate framebuffer: %d\n", ret);
+			goto stop_clk;
+		}
+	}
+
+	/* LCDC registers */
+	info->fix.mmio_start = regs->start;
+	info->fix.mmio_len = regs->end - regs->start + 1;
+
+	if (!request_mem_region(info->fix.mmio_start,
+				info->fix.mmio_len, pdev->name)) {
+		ret = -EBUSY;
+		goto free_fb;
+	}
+
+	sinfo->mmio = ioremap(info->fix.mmio_start, info->fix.mmio_len);
+	if (!sinfo->mmio) {
+		dev_err(dev, "cannot map LCDC registers\n");
+		goto release_mem;
+	}
+
+	/* interrupt */
+	ret = request_irq(sinfo->irq_base, atmel_lcdfb_interrupt, 0, pdev->name, info);
+	if (ret) {
+		dev_err(dev, "request_irq failed: %d\n", ret);
+		goto unmap_mmio;
+	}
+
+	ret = atmel_lcdfb_init_fbinfo(sinfo);
+	if (ret < 0) {
+		dev_err(dev, "init fbinfo failed: %d\n", ret);
+		goto unregister_irqs;
+	}
+
+	/*
+	 * This makes sure that our colour bitfield
+	 * descriptors are correctly initialised.
+	 */
+	atmel_lcdfb_check_var(&info->var, info);
+
+	ret = fb_set_var(info, &info->var);
+	if (ret) {
+		dev_warn(dev, "unable to set display parameters\n");
+		goto free_cmap;
+	}
+
+	dev_set_drvdata(dev, info);
+
+	/*
+	 * Tell the world that we're ready to go
+	 */
+	ret = register_framebuffer(info);
+	if (ret < 0) {
+		dev_err(dev, "failed to register framebuffer device: %d\n", ret);
+		goto free_cmap;
+	}
+
+	/* Power up the LCDC screen */
+	if (sinfo->atmel_lcdfb_power_control)
+		sinfo->atmel_lcdfb_power_control(1);
+
+	dev_info(dev, "fb%d: Atmel LCDC at 0x%08lx (mapped at %p), irq %lu\n",
+		       info->node, info->fix.mmio_start, sinfo->mmio, sinfo->irq_base);
+
+	return 0;
+
+
+free_cmap:
+	fb_dealloc_cmap(&info->cmap);
+unregister_irqs:
+	free_irq(sinfo->irq_base, info);
+unmap_mmio:
+	iounmap(sinfo->mmio);
+release_mem:
+ 	release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
+free_fb:
+	if (map)
+		iounmap(info->screen_base);
+	else
+		atmel_lcdfb_free_video_memory(sinfo);
+
+release_intmem:
+	if (map)
+		release_mem_region(info->fix.smem_start, info->fix.smem_len);
+stop_clk:
+	atmel_lcdfb_stop_clock(sinfo);
+	clk_put(sinfo->lcdc_clk);
+put_bus_clk:
+	if (sinfo->bus_clk)
+		clk_put(sinfo->bus_clk);
+free_info:
+	framebuffer_release(info);
+out:
+	dev_dbg(dev, "%s FAILED\n", __func__);
+	return ret;
+}
+
+static int __exit atmel_lcdfb_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct fb_info *info = dev_get_drvdata(dev);
+	struct atmel_lcdfb_info *sinfo = info->par;
+
+	if (!sinfo)
+		return 0;
+
+	if (sinfo->atmel_lcdfb_power_control)
+		sinfo->atmel_lcdfb_power_control(0);
+	unregister_framebuffer(info);
+	atmel_lcdfb_stop_clock(sinfo);
+	clk_put(sinfo->lcdc_clk);
+	if (sinfo->bus_clk)
+		clk_put(sinfo->bus_clk);
+	fb_dealloc_cmap(&info->cmap);
+	free_irq(sinfo->irq_base, info);
+	iounmap(sinfo->mmio);
+ 	release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
+	if (platform_get_resource(pdev, IORESOURCE_MEM, 1)) {
+		iounmap(info->screen_base);
+		release_mem_region(info->fix.smem_start, info->fix.smem_len);
+	} else {
+		atmel_lcdfb_free_video_memory(sinfo);
+	}
+
+	dev_set_drvdata(dev, NULL);
+	framebuffer_release(info);
+
+	return 0;
+}
+
+static struct platform_driver atmel_lcdfb_driver = {
+	.remove		= __exit_p(atmel_lcdfb_remove),
+	.driver		= {
+		.name	= "atmel_lcdfb",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init atmel_lcdfb_init(void)
+{
+	return platform_driver_probe(&atmel_lcdfb_driver, atmel_lcdfb_probe);
+}
+
+static void __exit atmel_lcdfb_exit(void)
+{
+	platform_driver_unregister(&atmel_lcdfb_driver);
+}
+
+module_init(atmel_lcdfb_init);
+module_exit(atmel_lcdfb_exit);
+
+MODULE_DESCRIPTION("AT91/AT32 LCD Controller framebuffer driver");
+MODULE_AUTHOR("Nicolas Ferre <nicolas.ferre@rfo.atmel.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
index aa3935d..63b85bf 100644
--- a/drivers/video/console/Kconfig
+++ b/drivers/video/console/Kconfig
@@ -19,13 +19,6 @@
 
 	  Say Y.
 
-#	if [ "$CONFIG_PCI" = "y" -a "$CONFIG_VGA_CONSOLE" = "y" ]; then
-#	   bool '   Allow VGA on any bus?' CONFIG_VGA_HOSE
-#	   if [ "$CONFIG_VGA_HOSE" = "y" ]; then
-#	      define_bool CONFIG_DUMMY_CONSOLE y
-#	   fi
-#	fi
-
 config VGACON_SOFT_SCROLLBACK
        bool "Enable Scrollback Buffer in System RAM"
        depends on VGA_CONSOLE
diff --git a/drivers/video/nvidia/nv_hw.c b/drivers/video/nvidia/nv_hw.c
index c627955..aff11bb 100644
--- a/drivers/video/nvidia/nv_hw.c
+++ b/drivers/video/nvidia/nv_hw.c
@@ -149,7 +149,9 @@
 		pll = NV_RD32(par->PMC, 0x4024);
 		M = pll & 0xFF;
 		N = (pll >> 8) & 0xFF;
-		if (((par->Chipset & 0xfff0) == 0x0290) || ((par->Chipset & 0xfff0) == 0x0390) || ((par->Chipset & 0xfff0) == 0x02E0)) {
+		if (((par->Chipset & 0xfff0) == 0x0290) ||
+			((par->Chipset & 0xfff0) == 0x0390) ||
+			((par->Chipset & 0xfff0) == 0x02E0)) {
 			MB = 1;
 			NB = 1;
 		} else {
diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c
index f85edf0..41f6365 100644
--- a/drivers/video/nvidia/nvidia.c
+++ b/drivers/video/nvidia/nvidia.c
@@ -37,7 +37,6 @@
 #include "nv_proto.h"
 #include "nv_dma.h"
 
-#undef CONFIG_FB_NVIDIA_DEBUG
 #ifdef CONFIG_FB_NVIDIA_DEBUG
 #define NVTRACE          printk
 #else
diff --git a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c
index 1ac5264..ab5e668 100644
--- a/drivers/video/pm2fb.c
+++ b/drivers/video/pm2fb.c
@@ -204,17 +204,6 @@
 }
 #endif
 
-static void wait_pm2(struct pm2fb_par* par) {
-
-	WAIT_FIFO(par, 1);
-	pm2_WR(par, PM2R_SYNC, 0);
-	mb();
-	do {
-		while (pm2_RD(par, PM2R_OUT_FIFO_WORDS) == 0);
-		rmb();
-	} while (pm2_RD(par, PM2R_OUT_FIFO) != PM2TAG(PM2R_SYNC));
-}
-
 /*
  * partial products for the supported horizontal resolutions.
  */
@@ -1050,13 +1039,30 @@
 	return 0;
 }
 
+static int pm2fb_sync(struct fb_info *info)
+{
+	struct pm2fb_par *par = info->par;
+
+	WAIT_FIFO(par, 1);
+	pm2_WR(par, PM2R_SYNC, 0);
+	mb();
+	do {
+		while (pm2_RD(par, PM2R_OUT_FIFO_WORDS) == 0)
+			udelay(10);
+		rmb();
+	} while (pm2_RD(par, PM2R_OUT_FIFO) != PM2TAG(PM2R_SYNC));
+
+	return 0;
+}
+
 /*
  * block operation. copy=0: rectangle fill, copy=1: rectangle copy.
  */
-static void pm2fb_block_op(struct pm2fb_par* par, int copy,
+static void pm2fb_block_op(struct fb_info* info, int copy,
 				s32 xsrc, s32 ysrc,
 				s32 x, s32 y, s32 w, s32 h,
 				u32 color) {
+	struct pm2fb_par *par = info->par;
 
 	if (!w || !h)
 		return;
@@ -1076,13 +1082,11 @@
 				(x<xsrc ? PM2F_INCREASE_X : 0) |
 				(y<ysrc ? PM2F_INCREASE_Y : 0) |
 				(copy ? 0 : PM2F_RENDER_FASTFILL));
-	wait_pm2(par);
 }
 
 static void pm2fb_fillrect (struct fb_info *info,
 				const struct fb_fillrect *region)
 {
-	struct pm2fb_par *par = info->par;
 	struct fb_fillrect modded;
 	int vxres, vyres;
 	u32 color = (info->fix.visual == FB_VISUAL_TRUECOLOR) ?
@@ -1116,7 +1120,7 @@
 		color |= color << 16;
 
 	if(info->var.bits_per_pixel != 24)
-		pm2fb_block_op(par, 0, 0, 0,
+		pm2fb_block_op(info, 0, 0, 0,
 				modded.dx, modded.dy,
 				modded.width, modded.height, color);
 	else
@@ -1126,7 +1130,6 @@
 static void pm2fb_copyarea(struct fb_info *info,
 				const struct fb_copyarea *area)
 {
-	struct pm2fb_par *par = info->par;
 	struct fb_copyarea modded;
 	u32 vxres, vyres;
 
@@ -1156,7 +1159,7 @@
 	if(modded.dy + modded.height > vyres)
 		modded.height = vyres - modded.dy;
 
-	pm2fb_block_op(par, 1, modded.sx, modded.sy,
+	pm2fb_block_op(info, 1, modded.sx, modded.sy,
 			modded.dx, modded.dy,
 			modded.width, modded.height, 0);
 }
@@ -1177,6 +1180,7 @@
 	.fb_fillrect	= pm2fb_fillrect,
 	.fb_copyarea	= pm2fb_copyarea,
 	.fb_imageblit	= cfb_imageblit,
+	.fb_sync	= pm2fb_sync,
 };
 
 /*
diff --git a/drivers/video/pm3fb.c b/drivers/video/pm3fb.c
index bd787e8..6c4dfcb0 100644
--- a/drivers/video/pm3fb.c
+++ b/drivers/video/pm3fb.c
@@ -1,55 +1,25 @@
 /*
  *  linux/drivers/video/pm3fb.c -- 3DLabs Permedia3 frame buffer device
- *  
- *  Copyright (C) 2001 Romain Dolbeau <dolbeau@irisa.fr>
+ *
+ *  Copyright (C) 2001 Romain Dolbeau <romain@dolbeau.org>.
+ *
+ *  Ported to 2.6 kernel on 1 May 2007 by Krzysztof Helt <krzysztof.h1@wp.pl>
+ *	based on pm2fb.c
+ *
  *  Based on code written by:
- *           Sven Luther, <luther@dpt-info.u-strasbg.fr>
- *           Alan Hourihane, <alanh@fairlite.demon.co.uk>
- *           Russell King, <rmk@arm.linux.org.uk>
+ *	   Sven Luther, <luther@dpt-info.u-strasbg.fr>
+ *	   Alan Hourihane, <alanh@fairlite.demon.co.uk>
+ *	   Russell King, <rmk@arm.linux.org.uk>
  *  Based on linux/drivers/video/skeletonfb.c:
  *	Copyright (C) 1997 Geert Uytterhoeven
  *  Based on linux/driver/video/pm2fb.c:
- *      Copyright (C) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT)
- *      Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com)
+ *	Copyright (C) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT)
+ *	Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com)
  *
  *  This file is subject to the terms and conditions of the GNU General Public
  *  License. See the file COPYING in the main directory of this archive for
  *  more details.
  *
- *  $Header: /cvsroot/linux/drivers/video/pm3fb.c,v 1.1 2002/02/25 19:11:06 marcelo Exp $
- *
- *  CHANGELOG:
- *  Mon Feb 11 10:35:48 MET 2002, v 1.4.11B: Cosmetic update.
- *  Wed Jan 23 14:16:59 MET 2002, v 1.4.11: Preliminary 2.5.x support, patch for 2.5.2.
- *  Wed Nov 28 11:08:29 MET 2001, v 1.4.10: potential bug fix for SDRAM-based board, patch for 2.4.16.
- *  Thu Sep 20 10:24:42 MET DST 2001, v 1.4.9: sync bug fix, preliminary flatpanel support, better timings.
- *  Tue Aug 28 10:13:01 MET DST 2001, v 1.4.8: memory timings check, minor bug fixes.
- *  Wed Jul 18 19:06:14 CEST 2001, v 1.4.7: Mode fix (800x600-100, 1024x768-100 changed), using HW panning + accel bug fix.
- *  Mon Jun 25 10:33:56 MET DST 2001, v 1.4.6: Depth 12 fix, chip reset ioctl, moved memory erase ioctl to DEBUG.
- *  Wed Jun 20 11:13:08 MET DST 2001, v 1.4.5: Fixed missing blinking cursor in 8bpp, code cleaning, memory erase IOCTL.
- *  Mon Jun 18 16:00:27 CEST 2001, v 1.4.4: Depth 12 (RGBA 4444) support, code cleaning.
- *  Fri Jun 15 13:53:01 CEST 2001, v 1.4.3: Removed warnings, depth 15 support, add 'depth' option.
- *  Thu Jun 14 10:13:52 MET DST 2001, v 1.4.2: Fixed depth switching bug, preliminary 15bpp (RGB5551) support.
- *  Thu Apr 12 11:16:45 MET DST 2001, v 1.4.1B: Doc updates.
- *  Fri Apr  6 11:12:53 MET DST 2001, v 1.4.1: Configure.help, minor cleanup
- *  Thu Mar 29 10:56:50 MET DST 2001, v 1.4.0: Module & module options support (note: linux patch changed, 2.2.19 added).
- *  Thu Mar 15 15:30:31 MET 2001, v 1.3.2: Fixed mirroring bug on little-endian.
- *  Wed Mar 14 21:25:54 CET 2001, v 1.3.1: Fixed bug in BlockMove (_bmov).
- *  Tue Mar 13 10:53:19 MET 2001, v 1.3.0: Character drawing hardware support (in all width between 1 and 16), fixes.
- *  Thu Mar  8 10:20:16 MET 2001, v 1.2.2: Better J2000 support, "font:" option.
- *  Tue Mar  6 21:25:04 CET 2001, v 1.2.1: Better acceleration support.
- *  Mon Mar  5 21:54:17 CET 2001, v 1.2.0: Partial acceleration support (clear & bmove)
- *  Mon Mar  5 12:52:15 CET 2001, v 1.1.3: Big pan_display fix.
- *  Sun Mar  4 22:21:50 CET 2001, v 1.1.2: (numerous) bug fixes.
- *  Fri Mar  2 15:54:07 CET 2001, v 1.1.1: Might have Appian J2000 support, resource mangement in 2.4
- *  Wed Feb 28 18:21:35 CET 2001, v 1.1.0: Might have multiple boards support (added, but not yest tested)
- *  Tue Feb 27 17:31:12 CET 2001, v 1.0.6: fixes boot-time mode select, add more default mode
- *  Tue Feb 27 14:01:36 CET 2001, v 1.0.5: fixes (1.0.4 was broken for 2.2), cleaning up
- *  Mon Feb 26 23:17:36 CET 2001, v 1.0.4: preliminary 2.4.x support, dropped (useless on pm3) partial product, more OF fix
- *  Mon Feb 26 20:59:05 CET 2001, v 1.0.3: No more shadow register (and wasted memory), endianess fix, use OF-preset resolution by default
- *  Wed Feb 21 22:09:30 CET 2001, v 1.0.2: Code cleaning for future multiboard support, better OF support, bugs fix
- *  Wed Feb 21 19:58:56 CET 2001, v 1.0.1: OpenFirmware support, fixed memory detection, better debug support, code cleaning
- *  Wed Feb 21 14:47:06 CET 2001, v 1.0.0: First working version
  */
 
 #include <linux/module.h>
@@ -58,856 +28,155 @@
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
-#include <linux/vmalloc.h>
 #include <linux/delay.h>
-#include <linux/interrupt.h>
 #include <linux/fb.h>
 #include <linux/init.h>
 #include <linux/pci.h>
-#include <linux/ioport.h>
-#include <linux/ctype.h>
 
-#include <video/fbcon.h>
-#include <video/fbcon-mfb.h>
-#include <video/fbcon-cfb2.h>
-#include <video/fbcon-cfb4.h>
-#include <video/fbcon-cfb8.h>
-#include <video/fbcon-cfb16.h>
-#include <video/fbcon-cfb24.h>
-#include <video/fbcon-cfb32.h>
 #include <video/pm3fb.h>
 
-#include <asm/io.h>
-#include <asm/uaccess.h>
-
-#ifdef CONFIG_FB_OF
-#include <asm/prom.h>
+#if !defined(CONFIG_PCI)
+#error "Only generic PCI cards supported."
 #endif
 
-/* ************************************* */
-/* ***** The various "global" data ***** */
-/* ************************************* */
+#undef PM3FB_MASTER_DEBUG
+#ifdef PM3FB_MASTER_DEBUG
+#define DPRINTK(a,b...)	printk(KERN_DEBUG "pm3fb: %s: " a, __FUNCTION__ , ## b)
+#else
+#define DPRINTK(a,b...)
+#endif
 
-/* those will need a rework for multiple board support */
-/* Driver name */
-static const char permedia3_name[16] = "Permedia3";
+/*
+ * Driver data
+ */
+static char *mode_option __devinitdata;
 
-/* the fb_par struct, mandatory */
-struct pm3fb_par {
-	u32 pixclock;		/* pixclock in KHz */
+/*
+ *  If your driver supports multiple boards, you should make the
+ *  below data types arrays, or allocate them dynamically (using kmalloc()).
+ */
 
-	u32 width;		/* width of virtual screen */
-	u32 height;		/* height of virtual screen */
-
-	u32 hsstart;		/* horiz. sync start */
-	u32 hsend;		/* horiz. sync end */
-	u32 hbend;		/* horiz. blank end (also gate end) */
-	u32 htotal;		/* total width (w/ sync & blank) */
-
-	u32 vsstart;		/* vert. sync start */
-	u32 vsend;		/* vert. sync end */
-	u32 vbend;		/* vert. blank end */
-	u32 vtotal;		/* total height (w/ sync & blank) */
-
-	u32 stride;		/* screen stride */
-	u32 base;		/* screen base (xoffset+yoffset) in 128 bits unit */
-	/* NOTE : unlike other pm3 stuff above, stored *after* shiftbpp. don't ask */
-	u32 depth;		/* screen depth (8, 12, 15, 16 or 32) */
-	u32 video;		/* video control (hsync,vsync) */
+/*
+ * This structure defines the hardware state of the graphics card. Normally
+ * you place this in a header file in linux/include/video. This file usually
+ * also includes register information. That allows other driver subsystems
+ * and userland applications the ability to use the same header file to
+ * avoid duplicate work and easy porting of software.
+ */
+struct pm3_par {
+	unsigned char	__iomem *v_regs;/* virtual address of p_regs */
+	u32		video;		/* video flags before blanking */
+	u32		base;		/* screen base (xoffset+yoffset) in 128 bits unit */
+	u32 		palette[16];
 };
 
-/* memory timings */
-struct pm3fb_timings
+/*
+ * Here we define the default structs fb_fix_screeninfo and fb_var_screeninfo
+ * if we don't use modedb. If we do use modedb see pm3fb_init how to use it
+ * to get a fb_var_screeninfo. Otherwise define a default var as well.
+ */
+static struct fb_fix_screeninfo pm3fb_fix __devinitdata = {
+	.id =		"Permedia3",
+	.type =		FB_TYPE_PACKED_PIXELS,
+	.visual =	FB_VISUAL_PSEUDOCOLOR,
+	.xpanstep =	1,
+	.ypanstep =	1,
+	.ywrapstep =	0,
+	.accel =	FB_ACCEL_NONE,
+};
+
+/*
+ * Utility functions
+ */
+
+static inline u32 PM3_READ_REG(struct pm3_par *par, s32 off)
 {
-	unsigned long caps;
-	unsigned long timings;
-	unsigned long control;
-	unsigned long refresh;
-	unsigned long powerdown;
-};
-typedef enum pm3fb_timing_result { pm3fb_timing_ok, pm3fb_timing_problem, pm3fb_timing_retry } pm3fb_timing_result;
-#define PM3FB_UNKNOWN_TIMING_VALUE ((unsigned long)-1)
-#define PM3FB_UNKNOWN_TIMINGS { PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE }
-
-/* the fb_info struct, mandatory */
-struct pm3fb_info {
-	struct fb_info_gen gen;
-	unsigned long board_num; /* internal board number */
-	unsigned long use_current;
-	struct pm3fb_par *current_par;
-	struct pci_dev *dev;    /* PCI device */
-	unsigned long board_type; /* index in the cardbase */
-	unsigned char *fb_base;	/* framebuffer memory base */
-	u32 fb_size;		/* framebuffer memory size */
-	unsigned char *p_fb;	/* physical address of frame buffer */
-	unsigned char *v_fb;	/* virtual address of frame buffer */
-	unsigned char *pIOBase;	/* physical address of registers region, must be rg_base or rg_base+PM2_REGS_SIZE depending on the host endianness */
-	unsigned char *vIOBase;	/* address of registers after ioremap() */
-	struct {
-		u8 transp;
-		u8 red;
-		u8 green;
-		u8 blue;
-	} palette[256];
-	union {
-#ifdef FBCON_HAS_CFB16
-		u16 cmap12[16]; /* RGBA 4444 */
-		u16 cmap15[16]; /* RGBA 5551 */
-		u16 cmap16[16]; /* RGBA 5650 */
-#endif
-#ifdef FBCON_HAS_CFB32
-		u32 cmap32[16];
-#endif
-	} cmap;
-	struct pm3fb_timings memt;
-};
-
-/* regular resolution database*/
-static struct {
-	char name[16];
-	struct pm3fb_par user_mode;
-} mode_base[] __initdata = {
-	{
-		"default-800x600", {
-	49500, 800, 600, 16, 96, 256, 1056, 1, 4, 25, 625,
-			    800, 0, 8,
-			    PM3VideoControl_ENABLE |
-			    PM3VideoControl_HSYNC_ACTIVE_HIGH
-			    |
-			    PM3VideoControl_VSYNC_ACTIVE_HIGH
-			    | PM3VideoControl_PIXELSIZE_8BIT}}, {
-		"1024x768-74", {
-	78752, 1024, 768, 32, 128, 304, 1328, 1, 4, 38,
-			    806, 1024, 0, 8,
-			    PM3VideoControl_ENABLE |
-			    PM3VideoControl_HSYNC_ACTIVE_HIGH
-			    |
-			    PM3VideoControl_VSYNC_ACTIVE_HIGH
-			    | PM3VideoControl_PIXELSIZE_8BIT}}, {
-		"1024x768-74-32", {
-			78752, 1024, 768, 32, 128, 304, 1328, 1, 4, 38,
-			806, 1024, 0, 32,
-			PM3VideoControl_ENABLE |
-			PM3VideoControl_HSYNC_ACTIVE_HIGH
-			|
-			PM3VideoControl_VSYNC_ACTIVE_HIGH
-			| PM3VideoControl_PIXELSIZE_32BIT}},
-/* Generated mode : "1600x1024", for the SGI 1600SW flat panel*/
-	{
-		"SGI1600SW", {
-			108000, 1600, 1024, 16, 56, 104, 1704, 3, 6, 32,
-			1056, 1600, 0, 8,
-			PM3VideoControl_ENABLE|
-			PM3VideoControl_HSYNC_ACTIVE_LOW|PM3VideoControl_VSYNC_ACTIVE_LOW|
-			PM3VideoControl_PIXELSIZE_32BIT}}, 
-/* ##### auto-generated mode, by fbtimings2pm3 */
-/* Generated mode : "640x480-60" */
-	{
-		"640x480-60", {
-	25174, 640, 480, 16, 112, 160, 800, 10, 12, 45,
-			    525, 640, 0, 8,
-			    PM3VideoControl_ENABLE |
-			    PM3VideoControl_HSYNC_ACTIVE_LOW
-			    |
-			    PM3VideoControl_VSYNC_ACTIVE_LOW
-			    | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "640x480-72" */
-	{
-		"640x480-72", {
-	31199, 640, 480, 24, 64, 192, 832, 9, 12, 40, 520,
-			    640, 0, 8,
-			    PM3VideoControl_ENABLE |
-			    PM3VideoControl_HSYNC_ACTIVE_LOW
-			    |
-			    PM3VideoControl_VSYNC_ACTIVE_LOW
-			    | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "640x480-75" */
-	{
-		"640x480-75", {
-	31499, 640, 480, 16, 80, 200, 840, 1, 4, 20, 500,
-			    640, 0, 8,
-			    PM3VideoControl_ENABLE |
-			    PM3VideoControl_HSYNC_ACTIVE_LOW
-			    |
-			    PM3VideoControl_VSYNC_ACTIVE_LOW
-			    | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "640x480-90" */
-	{
-		"640x480-90", {
-	39909, 640, 480, 32, 72, 192, 832, 25, 39, 53, 533,
-			    640, 0, 8,
-			    PM3VideoControl_ENABLE |
-			    PM3VideoControl_HSYNC_ACTIVE_LOW
-			    |
-			    PM3VideoControl_VSYNC_ACTIVE_LOW
-			    | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "640x480-100" */
-	{
-		"640x480-100", {
-	44899, 640, 480, 32, 160, 208, 848, 22, 34, 51,
-			    531, 640, 0, 8,
-			    PM3VideoControl_ENABLE |
-			    PM3VideoControl_HSYNC_ACTIVE_LOW
-			    |
-			    PM3VideoControl_VSYNC_ACTIVE_LOW
-			    | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "800x600-48-lace" */
-/* INTERLACED NOT SUPPORTED
-  {"800x600-48-lace", {35999, 800, 600, 80, 208, 264, 1064, 11, 23, 102, 702, 800, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, 
-   INTERLACED NOT SUPPORTED */
-/* Generated mode : "800x600-56" */
-	{
-		"800x600-56", {
-	35999, 800, 600, 24, 96, 224, 1024, 1, 3, 25, 625,
-			    800, 0, 8,
-			    PM3VideoControl_ENABLE |
-			    PM3VideoControl_HSYNC_ACTIVE_HIGH
-			    |
-			    PM3VideoControl_VSYNC_ACTIVE_HIGH
-			    | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "800x600-60" */
-	{
-		"800x600-60", {
-	40000, 800, 600, 40, 168, 256, 1056, 1, 5, 28, 628,
-			    800, 0, 8,
-			    PM3VideoControl_ENABLE |
-			    PM3VideoControl_HSYNC_ACTIVE_HIGH
-			    |
-			    PM3VideoControl_VSYNC_ACTIVE_HIGH
-			    | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "800x600-70" */
-	{
-		"800x600-70", {
-	44899, 800, 600, 24, 168, 208, 1008, 9, 21, 36,
-			    636, 800, 0, 8,
-			    PM3VideoControl_ENABLE |
-			    PM3VideoControl_HSYNC_ACTIVE_HIGH
-			    |
-			    PM3VideoControl_VSYNC_ACTIVE_LOW
-			    | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "800x600-72" */
-	{
-		"800x600-72", {
-	50000, 800, 600, 56, 176, 240, 1040, 37, 43, 66,
-			    666, 800, 0, 8,
-			    PM3VideoControl_ENABLE |
-			    PM3VideoControl_HSYNC_ACTIVE_HIGH
-			    |
-			    PM3VideoControl_VSYNC_ACTIVE_HIGH
-			    | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "800x600-75" */
-	{
-		"800x600-75", {
-	49497, 800, 600, 16, 96, 256, 1056, 1, 4, 25, 625,
-			    800, 0, 8,
-			    PM3VideoControl_ENABLE |
-			    PM3VideoControl_HSYNC_ACTIVE_HIGH
-			    |
-			    PM3VideoControl_VSYNC_ACTIVE_HIGH
-			    | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "800x600-90" */
-	{
-		"800x600-90", {
-	56637, 800, 600, 8, 72, 192, 992, 8, 19, 35, 635,
-			    800, 0, 8,
-			    PM3VideoControl_ENABLE |
-			    PM3VideoControl_HSYNC_ACTIVE_HIGH
-			    |
-			    PM3VideoControl_VSYNC_ACTIVE_HIGH
-			    | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "800x600-100", from /etc/fb.modes */
-/* DISABLED, hsstart == 0
-	{
-		"800x600-100", {
-	67499, 800, 600, 0, 64, 280, 1080, 7, 11, 25, 625,
-			    800, 0, 8,
-			    PM3VideoControl_ENABLE |
-			    PM3VideoControl_HSYNC_ACTIVE_HIGH
-			    |
-			    PM3VideoControl_VSYNC_ACTIVE_HIGH
-			    | PM3VideoControl_PIXELSIZE_8BIT}},
-*/
-/* Generated mode : "800x600-100", from ??? */
-	{
-		"800x600-100", {
-			69650, 800, 600, 64, 128, 288, 1088, 4, 10, 40, 640, 800, 0, 8,
-			PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_LOW|
-			PM3VideoControl_VSYNC_ACTIVE_LOW|PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1024x768-43-lace" */
-/* INTERLACED NOT SUPPORTED
-  {"1024x768-43-lace", {44899, 1024, 768, 8, 184, 240, 1264, 1, 9, 49, 817, 1024, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, 
-   INTERLACED NOT SUPPORTED */
-/* Generated mode : "1024x768-60" */
-	{
-		"1024x768-60", {
-	64998, 1024, 768, 24, 160, 320, 1344, 3, 9, 38,
-			    806, 1024, 0, 8,
-			    PM3VideoControl_ENABLE |
-			    PM3VideoControl_HSYNC_ACTIVE_LOW
-			    |
-			    PM3VideoControl_VSYNC_ACTIVE_LOW
-			    | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1024x768-70" */
-	{
-		"1024x768-70", {
-	74996, 1024, 768, 24, 160, 304, 1328, 3, 9, 38,
-			    806, 1024, 0, 8,
-			    PM3VideoControl_ENABLE |
-			    PM3VideoControl_HSYNC_ACTIVE_LOW
-			    |
-			    PM3VideoControl_VSYNC_ACTIVE_LOW
-			    | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1024x768-72" */
-	{
-		"1024x768-72", {
-	74996, 10224, 768, 24, 160, 264, 10488, 3, 9, 38,
-			    806, 10224, 0, 8,
-			    PM3VideoControl_ENABLE |
-			    PM3VideoControl_HSYNC_ACTIVE_LOW
-			    |
-			    PM3VideoControl_VSYNC_ACTIVE_LOW
-			    | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1024x768-75" */
-	{
-		"1024x768-75", {
-	78746, 1024, 768, 16, 112, 288, 1312, 1, 4, 32,
-			    800, 1024, 0, 8,
-			    PM3VideoControl_ENABLE |
-			    PM3VideoControl_HSYNC_ACTIVE_HIGH
-			    |
-			    PM3VideoControl_VSYNC_ACTIVE_HIGH
-			    | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1024x768-90" */
-	{
-		"1024x768-90", {
-	100000, 1024, 768, 0, 96, 288, 1312, 21, 36, 77,
-			    845, 1024, 0, 8,
-			    PM3VideoControl_ENABLE |
-			    PM3VideoControl_HSYNC_ACTIVE_LOW
-			    |
-			    PM3VideoControl_VSYNC_ACTIVE_LOW
-			    | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1024x768-100", from /etc/fb.modes */
-/* DISABLED, vsstart == 0
-	{
-		"1024x768-100", {
-	109998, 1024, 768, 0, 88, 368, 1392, 0, 8, 24, 792,
-			    1024, 0, 8,
-			    PM3VideoControl_ENABLE |
-			    PM3VideoControl_HSYNC_ACTIVE_LOW
-			    |
-			    PM3VideoControl_VSYNC_ACTIVE_LOW
-			    | PM3VideoControl_PIXELSIZE_8BIT}},
-*/
-/* Generated mode : "1024x768-100", from ??? */
-	{
-		"1024x768-100", {
-			115500, 1024, 768, 32, 224, 416, 1440, 3, 13, 34, 802, 1024, 0, 8,
-			PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_LOW|
-			PM3VideoControl_VSYNC_ACTIVE_LOW|PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1152x864-43-lace" */
-/* INTERLACED NOT SUPPORTED
-  {"1152x864-43-lace", {64998, 1152, 864, 72, 200, 264, 1416, 78, 87, 191, 1055, 1152, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, 
-   INTERLACED NOT SUPPORTED */
-/* Generated mode : "1152x864-47-lace" */
-/* INTERLACED NOT SUPPORTED
-  {"1152x864-47-lace", {64998, 1152, 864, 88, 216, 296, 1448, 30, 39, 83, 947, 1152, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, 
-   INTERLACED NOT SUPPORTED */
-/* Generated mode : "1152x864-60" */
-	{
-		"1152x864-60", {
-	80000, 1152, 864, 64, 176, 304, 1456, 6, 11, 52,
-			    916, 1152, 0, 8,
-			    PM3VideoControl_ENABLE |
-			    PM3VideoControl_HSYNC_ACTIVE_HIGH
-			    |
-			    PM3VideoControl_VSYNC_ACTIVE_HIGH
-			    | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1152x864-70" */
-	{
-		"1152x864-70", {
-	100000, 1152, 864, 40, 192, 360, 1512, 13, 24, 81,
-			    945, 1152, 0, 8,
-			    PM3VideoControl_ENABLE |
-			    PM3VideoControl_HSYNC_ACTIVE_HIGH
-			    |
-			    PM3VideoControl_VSYNC_ACTIVE_HIGH
-			    | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1152x864-75" */
-	{
-		"1152x864-75", {
-	109998, 1152, 864, 24, 168, 312, 1464, 45, 53, 138,
-			    1002, 1152, 0, 8,
-			    PM3VideoControl_ENABLE |
-			    PM3VideoControl_HSYNC_ACTIVE_HIGH
-			    |
-			    PM3VideoControl_VSYNC_ACTIVE_HIGH
-			    | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1152x864-80" */
-	{
-		"1152x864-80", {
-	109998, 1152, 864, 16, 128, 288, 1440, 30, 37, 94,
-			    958, 1152, 0, 8,
-			    PM3VideoControl_ENABLE |
-			    PM3VideoControl_HSYNC_ACTIVE_HIGH
-			    |
-			    PM3VideoControl_VSYNC_ACTIVE_HIGH
-			    | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1280x1024-43-lace" */
-/* INTERLACED NOT SUPPORTED
-  {"1280x1024-43-lace", {80000, 1024, 1024, 80, 160, 320, 1344, 50, 60, 125, 1149, 1024, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, 
-   INTERLACED NOT SUPPORTED */
-/* Generated mode : "1280x1024-47-lace" */
-/* INTERLACED NOT SUPPORTED
-  {"1280x1024-47-lace", {80000, 1280, 1024, 80, 160, 320, 1600, 1, 11, 29, 1053, 1280, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, 
-   INTERLACED NOT SUPPORTED */
-/* Generated mode : "1280x1024-60" */
-	{
-		"1280x1024-60", {
-	107991, 1280, 1024, 48, 160, 408, 1688, 1, 4, 42,
-			    1066, 1280, 0, 8,
-			    PM3VideoControl_ENABLE |
-			    PM3VideoControl_HSYNC_ACTIVE_HIGH
-			    |
-			    PM3VideoControl_VSYNC_ACTIVE_HIGH
-			    | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1280x1024-70" */
-	{
-		"1280x1024-70", {
-	125992, 1280, 1024, 80, 192, 408, 1688, 1, 6, 42,
-			    1066, 1280, 0, 8,
-			    PM3VideoControl_ENABLE |
-			    PM3VideoControl_HSYNC_ACTIVE_HIGH
-			    |
-			    PM3VideoControl_VSYNC_ACTIVE_HIGH
-			    | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1280x1024-74" */
-	{
-		"1280x1024-74", {
-	134989, 1280, 1024, 32, 176, 432, 1712, 0, 30, 40,
-			    1064, 1280, 0, 8,
-			    PM3VideoControl_ENABLE |
-			    PM3VideoControl_HSYNC_ACTIVE_HIGH
-			    |
-			    PM3VideoControl_VSYNC_ACTIVE_HIGH
-			    | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1280x1024-75" */
-	{
-		"1280x1024-75", {
-	134989, 1280, 1024, 16, 160, 408, 1688, 1, 4, 42,
-			    1066, 1280, 0, 8,
-			    PM3VideoControl_ENABLE |
-			    PM3VideoControl_HSYNC_ACTIVE_HIGH
-			    |
-			    PM3VideoControl_VSYNC_ACTIVE_HIGH
-			    | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1600x1200-60" */
-	{
-		"1600x1200-60", {
-	155981, 1600, 1200, 32, 192, 448, 2048, 10, 18, 70,
-			    1270, 1600, 0, 8,
-			    PM3VideoControl_ENABLE |
-			    PM3VideoControl_HSYNC_ACTIVE_LOW
-			    |
-			    PM3VideoControl_VSYNC_ACTIVE_LOW
-			    | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1600x1200-66" */
-	{
-		"1600x1200-66", {
-	171998, 1600, 1200, 40, 176, 480, 2080, 3, 6, 53,
-			    1253, 1600, 0, 8,
-			    PM3VideoControl_ENABLE |
-			    PM3VideoControl_HSYNC_ACTIVE_LOW
-			    |
-			    PM3VideoControl_VSYNC_ACTIVE_LOW
-			    | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1600x1200-76" */
-	{
-		"1600x1200-76", {
-	197980, 1600, 1200, 40, 176, 480, 2080, 3, 8, 50,
-			    1250, 1600, 0, 8,
-			    PM3VideoControl_ENABLE |
-			    PM3VideoControl_HSYNC_ACTIVE_LOW
-			    |
-			    PM3VideoControl_VSYNC_ACTIVE_LOW
-			    | PM3VideoControl_PIXELSIZE_8BIT}},
-/* ##### end of auto-generated mode */
-	{
-	"\0",}
-};
-
-/* more mandatory stuff (see skeletonfb.c + framebuffer driver HOWTO */
-static struct pm3fb_info fb_info[PM3_MAX_BOARD];
-static struct pm3fb_par current_par[PM3_MAX_BOARD];
-static int current_par_valid[PM3_MAX_BOARD];
-/* to allow explicit filtering of board */
-short bus[PM3_MAX_BOARD];
-short slot[PM3_MAX_BOARD];
-short func[PM3_MAX_BOARD];
-short disable[PM3_MAX_BOARD];
-short noaccel[PM3_MAX_BOARD];
-char fontn[PM3_MAX_BOARD][PM3_FONTNAME_SIZE];
-short depth[PM3_MAX_BOARD];
-short flatpanel[PM3_MAX_BOARD];
-static struct display disp[PM3_MAX_BOARD];
-static char g_options[PM3_OPTIONS_SIZE] __initdata = "pm3fb,dummy";
-short printtimings = 0;
-short forcesize[PM3_MAX_BOARD];
-
-/* ********************* */
-/* ***** prototype ***** */
-/* ********************* */
-/* card-specific */
-static void pm3fb_j2000_setup(struct pm3fb_info *l_fb_info);
-/* permedia3-specific */
-static pm3fb_timing_result pm3fb_preserve_memory_timings(struct pm3fb_info *l_fb_info);
-static pm3fb_timing_result pm3fb_try_memory_timings(struct pm3fb_info *l_fb_info);
-static void pm3fb_write_memory_timings(struct pm3fb_info *l_fb_info);
-static unsigned long pm3fb_read_dac_reg(struct pm3fb_info *l_fb_info,
-					unsigned long r);
-static unsigned long pm3fb_CalculateClock(struct pm3fb_info *l_fb_info, unsigned long reqclock,	/* In kHz units */
-					  unsigned long refclock,	/* In kHz units */
-					  unsigned char *prescale,	/* ClkPreScale */
-					  unsigned char *feedback,	/* ClkFeedBackScale */
-					  unsigned char *postscale
-					  /* ClkPostScale */ );
-static void pm3fb_clear_memory(struct pm3fb_info *l_fb_info, u32 cc);
-static void pm3fb_clear_colormap(struct pm3fb_info *l_fb_info, unsigned char r, unsigned char g, unsigned char b);
-static void pm3fb_common_init(struct pm3fb_info *l_fb_info);
-static int pm3fb_Shiftbpp(struct pm3fb_info *l_fb_info,
-			  unsigned long depth, int v);
-static int pm3fb_Unshiftbpp(struct pm3fb_info *l_fb_info,
-			    unsigned long depth, int v);
-static void pm3fb_mapIO(struct pm3fb_info *l_fb_info);
-static void pm3fb_unmapIO(struct pm3fb_info *l_fb_info);
-#if defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 2)
-static void pm3fb_show_cur_mode(struct pm3fb_info *l_fb_info);
-#endif
-static void pm3fb_show_cur_timing(struct pm3fb_info *l_fb_info);
-static void pm3fb_write_mode(struct pm3fb_info *l_fb_info);
-static void pm3fb_read_mode(struct pm3fb_info *l_fb_info,
-			    struct pm3fb_par *curpar);
-static unsigned long pm3fb_size_memory(struct pm3fb_info *l_fb_info);
-/* accelerated permedia3-specific */
-#ifdef PM3FB_USE_ACCEL
-static void pm3fb_wait_pm3(struct pm3fb_info *l_fb_info);
-static void pm3fb_init_engine(struct pm3fb_info *l_fb_info);
-#ifdef FBCON_HAS_CFB32
-static void pm3fb_cfb32_clear(struct vc_data *conp,
-			      struct display *p,
-			      int sy, int sx, int height, int width);
-static void pm3fb_cfb32_clear_margins(struct vc_data *conp,
-				      struct display *p, int bottom_only);
-#endif /* FBCON_HAS_CFB32 */
-#ifdef FBCON_HAS_CFB16
-static void pm3fb_cfb16_clear(struct vc_data *conp,
-			      struct display *p,
-			      int sy, int sx, int height, int width);
-static void pm3fb_cfb16_clear_margins(struct vc_data *conp,
-				      struct display *p, int bottom_only);
-#endif /* FBCON_HAS_CFB16 */
-#ifdef FBCON_HAS_CFB8
-static void pm3fb_cfb8_clear(struct vc_data *conp,
-			     struct display *p,
-			     int sy, int sx, int height, int width);
-static void pm3fb_cfb8_clear_margins(struct vc_data *conp,
-				     struct display *p, int bottom_only);
-#endif /* FBCON_HAS_CFB8 */
-#if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB32)
-static void pm3fb_cfbX_bmove(struct display *p,
-			     int sy, int sx,
-			     int dy, int dx, int height, int width);
-static void pm3fb_cfbX_putc(struct vc_data *conp, struct display *p,
-			    int c, int yy, int xx);
-static void pm3fb_cfbX_putcs(struct vc_data *conp, struct display *p,
-			     const unsigned short *s, int count, int yy,
-			     int xx);
-static void pm3fb_cfbX_revc(struct display *p, int xx, int yy);
-#endif /* FBCON_HAS_CFB8 || FBCON_HAS_CFB16 || FBCON_HAS_CFB32 */
-#endif /* PM3FB_USE_ACCEL */
-/* pre-init */
-static void pm3fb_mode_setup(char *mode, unsigned long board_num);
-static void pm3fb_pciid_setup(char *pciid, unsigned long board_num);
-static char *pm3fb_boardnum_setup(char *options, unsigned long *bn);
-static void pm3fb_real_setup(char *options);
-/* fbdev */
-static int pm3fb_encode_fix(struct fb_fix_screeninfo *fix,
-			    const void *par, struct fb_info_gen *info);
-static int pm3fb_decode_var(const struct fb_var_screeninfo *var,
-			    void *par, struct fb_info_gen *info);
-static void pm3fb_encode_depth(struct fb_var_screeninfo *var, long d);
-static int pm3fb_encode_var(struct fb_var_screeninfo *var,
-			    const void *par, struct fb_info_gen *info);
-static void pm3fb_get_par(void *par, struct fb_info_gen *info);
-static void pm3fb_set_par(const void *par, struct fb_info_gen *info);
-static void pm3fb_set_color(struct pm3fb_info *l_fb_info,
-			    unsigned char regno, unsigned char r,
-			    unsigned char g, unsigned char b);
-static int pm3fb_getcolreg(unsigned regno, unsigned *red, unsigned *green,
-			   unsigned *blue, unsigned *transp,
-			   struct fb_info *info);
-static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green,
-			   unsigned blue, unsigned transp,
-			   struct fb_info *info);
-static int pm3fb_blank(int blank_mode, struct fb_info_gen *info);
-static void pm3fb_set_disp(const void *par, struct display *disp,
-			   struct fb_info_gen *info);
-static void pm3fb_detect(void);
-static int pm3fb_pan_display(const struct fb_var_screeninfo *var,
-			     struct fb_info_gen *info);
-static int pm3fb_ioctl(struct fb_info *info, u_int cmd, u_long arg);
-
-
-/* the struct that hold them together */
-struct fbgen_hwswitch pm3fb_switch = {
-	pm3fb_detect, pm3fb_encode_fix, pm3fb_decode_var, pm3fb_encode_var,
-	pm3fb_get_par, pm3fb_set_par, pm3fb_getcolreg, 
-	pm3fb_pan_display, pm3fb_blank, pm3fb_set_disp
-};
-
-static struct fb_ops pm3fb_ops = {
-	.owner =	THIS_MODULE,
-	.fb_get_fix =	fbgen_get_fix,
-	.fb_get_var =	fbgen_get_var,
-	.fb_set_var =	fbgen_set_var,
-	.fb_get_cmap =	fbgen_get_cmap,
-	.fb_set_cmap =	fbgen_set_cmap,
-	.fb_setcolreg =	pm3fb_setcolreg,
-	.fb_pan_display =fbgen_pan_display,
-	.fb_blank =	fbgen_blank,
-	.fb_ioctl =	pm3fb_ioctl,
-};
-
-#ifdef PM3FB_USE_ACCEL
-#ifdef FBCON_HAS_CFB32
-static struct display_switch pm3fb_cfb32 = {
-	fbcon_cfb32_setup, pm3fb_cfbX_bmove, pm3fb_cfb32_clear,
-	pm3fb_cfbX_putc, pm3fb_cfbX_putcs, pm3fb_cfbX_revc,
-	NULL /* cursor() */ , NULL /* set_font() */ ,
-	pm3fb_cfb32_clear_margins,
-	FONTWIDTHRANGE(1, 16)	/* true only if accelerated... */
-};
-#endif /* FBCON_HAS_CFB32 */
-#ifdef FBCON_HAS_CFB16
-static struct display_switch pm3fb_cfb16 = {
-	fbcon_cfb16_setup, pm3fb_cfbX_bmove, pm3fb_cfb16_clear,
-	pm3fb_cfbX_putc, pm3fb_cfbX_putcs, pm3fb_cfbX_revc,
-	NULL /* cursor() */ , NULL /* set_font() */ ,
-	pm3fb_cfb16_clear_margins,
-	FONTWIDTHRANGE(1, 16)	/* true only if accelerated... */
-};
-#endif /* FBCON_HAS_CFB16 */
-#ifdef FBCON_HAS_CFB8
-static struct display_switch pm3fb_cfb8 = {
-	fbcon_cfb8_setup, pm3fb_cfbX_bmove, pm3fb_cfb8_clear,
-	pm3fb_cfbX_putc, pm3fb_cfbX_putcs, pm3fb_cfbX_revc,
-	NULL /* cursor() */ , NULL /* set_font() */ ,
-	pm3fb_cfb8_clear_margins,
-	FONTWIDTHRANGE(1, 16)	/* true only if accelerated... */
-};
-#endif /* FBCON_HAS_CFB8 */
-#endif /* PM3FB_USE_ACCEL */
-
-/* ****************************** */
-/* ***** card-specific data ***** */
-/* ****************************** */
-struct pm3fb_card_timings {
-	unsigned long memsize; /* 0 for last value (i.e. default) */
-	struct pm3fb_timings memt;
-};
-
-static struct pm3fb_card_timings t_FormacProFormance3[] = {
-	{ 16, { 0x02e311b8, 0x06100205, 0x08000002, 0x00000079, 0x00000000} },
-	{ 0, { 0x02e311b8, 0x06100205, 0x08000002, 0x00000079, 0x00000000} } /* from 16 MB PF3 */
-};
-
-static struct pm3fb_card_timings t_AppianJeronimo2000[] = {
-	{ 32, { 0x02e311B8, 0x07424905, 0x0c000003, 0x00000061, 0x00000000} },
-	{ 0, { 0x02e311B8, 0x07424905, 0x0c000003, 0x00000061, 0x00000000} } /* from 32MB J2000 */
-};
-
-static struct pm3fb_card_timings t_3DLabsOxygenVX1[] = {
-	{ 32, { 0x30e311b8, 0x08501204, 0x08000002, 0x0000006b, 0x00000000} },
-	{ 0, { 0x30e311b8, 0x08501204, 0x08000002, 0x0000006b, 0x00000000} } /* from 32MB VX1 */
-};
-
-static struct {
-		char cardname[32]; /* recognized card name */
-		u16 subvendor; /* subvendor of the card */
-		u16 subdevice; /* subdevice of the card */
-		u8  func; /* function of the card to which the extra init apply */
-		void (*specific_setup)(struct pm3fb_info *l_fb_info); /* card/func specific setup, done before _any_ FB access */
-	struct pm3fb_card_timings *c_memt; /* defauls timings for the boards */
-} cardbase[] = {
-	{ "Unknown Permedia3 board", 0xFFFF, 0xFFFF, 0xFF, NULL, NULL },
-	{ "Appian Jeronimo 2000 head 1", 0x1097, 0x3d32, 1, NULL,
-	  t_AppianJeronimo2000
-	},
-	{ "Appian Jeronimo 2000 head 2", 0x1097, 0x3d32, 2, pm3fb_j2000_setup,
-	  t_AppianJeronimo2000
-	},
-	{ "Formac ProFormance 3", PCI_VENDOR_ID_3DLABS, 0x000a, 0, NULL, /* Formac use 3DLabs ID ?!? */
-	  t_FormacProFormance3
-	},
-	{ "3DLabs Permedia3 Create!", PCI_VENDOR_ID_3DLABS, 0x0127, 0, NULL, NULL },
-	{ "3DLabs Oxygen VX1 PCI", PCI_VENDOR_ID_3DLABS, 0x0121, 0, NULL,
-	  t_3DLabsOxygenVX1
-	},
-	{ "3DLabs Oxygen VX1 AGP", PCI_VENDOR_ID_3DLABS, 0x0125, 0, NULL, NULL },
-	{ "3DLabs Oxygen VX1-16 AGP", PCI_VENDOR_ID_3DLABS, 0x0140, 0, NULL, NULL },
-	{ "3DLabs Oxygen VX1-1600SW PCI", PCI_VENDOR_ID_3DLABS, 0x0800, 0, NULL, NULL },
-	{ "\0", 0x0, 0x0, 0, NULL, NULL }
-};
-
-/* ********************************** */
-/* ***** card-specific function ***** */
-/* ********************************** */
-static void pm3fb_j2000_setup(struct pm3fb_info *l_fb_info)
-{       /* the appian j2000 require more initialization of the second head */
-	/* l_fb_info must point to the _second_ head of the J2000 */
-	
-	DTRACE;
-
-	l_fb_info->memt = t_AppianJeronimo2000[0].memt; /* 32 MB, first and only j2000 ? */
-	
-	pm3fb_write_memory_timings(l_fb_info);
+	return fb_readl(par->v_regs + off);
 }
 
-/* *************************************** */
-/* ***** permedia3-specific function ***** */
-/* *************************************** */
-static pm3fb_timing_result pm3fb_preserve_memory_timings(struct pm3fb_info *l_fb_info)
+static inline void PM3_WRITE_REG(struct pm3_par *par, s32 off, u32 v)
 {
-	l_fb_info->memt.caps = PM3_READ_REG(PM3LocalMemCaps);
-	l_fb_info->memt.timings = PM3_READ_REG(PM3LocalMemTimings);
-	l_fb_info->memt.control = PM3_READ_REG(PM3LocalMemControl);
-	l_fb_info->memt.refresh = PM3_READ_REG(PM3LocalMemRefresh);
-	l_fb_info->memt.powerdown = PM3_READ_REG(PM3LocalMemPowerDown);
+	fb_writel(v, par->v_regs + off);
+}
 
-	if ((l_fb_info->memt.caps == PM3FB_UNKNOWN_TIMING_VALUE) ||
-	    (l_fb_info->memt.timings == PM3FB_UNKNOWN_TIMING_VALUE) ||
-	    (l_fb_info->memt.control == PM3FB_UNKNOWN_TIMING_VALUE) ||
-	    (l_fb_info->memt.refresh == PM3FB_UNKNOWN_TIMING_VALUE) ||
-	    (l_fb_info->memt.powerdown == PM3FB_UNKNOWN_TIMING_VALUE))
-	{
-		printk(KERN_ERR "pm3fb: invalid memory timings in permedia3 board #%ld\n", l_fb_info->board_num);
-		return(pm3fb_try_memory_timings(l_fb_info));
+static inline void PM3_WAIT(struct pm3_par *par, u32 n)
+{
+	while (PM3_READ_REG(par, PM3InFIFOSpace) < n);
+}
+
+static inline void PM3_SLOW_WRITE_REG(struct pm3_par *par, s32 off, u32 v)
+{
+	if (par->v_regs) {
+		mb();
+		PM3_WAIT(par, 1);
+		wmb();
+		PM3_WRITE_REG(par, off, v);
 	}
-	return(pm3fb_timing_ok);
 }
 
-static pm3fb_timing_result pm3fb_try_memory_timings(struct pm3fb_info *l_fb_info)
+static inline void PM3_SET_INDEX(struct pm3_par *par, unsigned index)
 {
-	if (cardbase[l_fb_info->board_type].c_memt)
-	{
-		int i = 0, done = 0;
-		while (!done)
-		{
-			if ((cardbase[l_fb_info->board_type].c_memt[i].memsize == l_fb_info->fb_size)
-			    || !(cardbase[l_fb_info->board_type].c_memt[i].memsize))
-			{ /* will use the 0-sized timings by default */
-				done = 1;
-				l_fb_info->memt = cardbase[l_fb_info->board_type].c_memt[i].memt;
-				printk(KERN_WARNING  "pm3fb: trying to use predefined memory timings for permedia3 board #%ld (%s, %ld MB)\n",
-				       l_fb_info->board_num,
-				       cardbase[l_fb_info->board_type].cardname,
-				       cardbase[l_fb_info->board_type].c_memt[i].memsize);
-				pm3fb_write_memory_timings(l_fb_info);
-				return(pm3fb_timing_retry);
-			}
-			i++;
-		}
-	} else
-		return(pm3fb_timing_problem);
-	return(pm3fb_timing_ok);
+	PM3_SLOW_WRITE_REG(par, PM3RD_IndexHigh, (index >> 8) & 0xff);
+	PM3_SLOW_WRITE_REG(par, PM3RD_IndexLow, index & 0xff);
 }
 
-static void pm3fb_write_memory_timings(struct pm3fb_info *l_fb_info)
+static inline void PM3_WRITE_DAC_REG(struct pm3_par *par, unsigned r, u8 v)
 {
-	unsigned char m, n, p;
-	unsigned long clockused;
-	
-	PM3_SLOW_WRITE_REG(PM3LocalMemCaps, l_fb_info->memt.caps);
-	PM3_SLOW_WRITE_REG(PM3LocalMemTimings, l_fb_info->memt.timings);
-	PM3_SLOW_WRITE_REG(PM3LocalMemControl, l_fb_info->memt.control);
-	PM3_SLOW_WRITE_REG(PM3LocalMemRefresh, l_fb_info->memt.refresh);
-	PM3_SLOW_WRITE_REG(PM3LocalMemPowerDown, l_fb_info->memt.powerdown);
-
-	clockused =
-	    pm3fb_CalculateClock(l_fb_info, 2 * 105000, PM3_REF_CLOCK, &m,
-				 &n, &p);
-
-	PM3_WRITE_DAC_REG(PM3RD_KClkPreScale, m);
-	PM3_WRITE_DAC_REG(PM3RD_KClkFeedbackScale, n);
-	PM3_WRITE_DAC_REG(PM3RD_KClkPostScale, p);
-	PM3_WRITE_DAC_REG(PM3RD_KClkControl,
-			  PM3RD_KClkControl_STATE_RUN |
-			  PM3RD_KClkControl_SOURCE_PLL |
-			  PM3RD_KClkControl_ENABLE);
-	PM3_WRITE_DAC_REG(PM3RD_MClkControl,
-			  PM3RD_MClkControl_STATE_RUN |
-			  PM3RD_MClkControl_SOURCE_KCLK |
-			  PM3RD_MClkControl_ENABLE);
-	PM3_WRITE_DAC_REG(PM3RD_SClkControl,
-			  PM3RD_SClkControl_STATE_RUN |
-			  PM3RD_SClkControl_SOURCE_PCLK |
-			  PM3RD_SClkControl_ENABLE);
+	PM3_SET_INDEX(par, r);
+	wmb();
+	PM3_WRITE_REG(par, PM3RD_IndexedData, v);
 }
 
-static unsigned long pm3fb_read_dac_reg(struct pm3fb_info *l_fb_info,
-					unsigned long r)
+static inline void pm3fb_set_color(struct pm3_par *par, unsigned char regno,
+			unsigned char r, unsigned char g, unsigned char b)
 {
-	DASSERT((l_fb_info->vIOBase != (unsigned char *) (-1)),
-		"l_fb_info->vIOBase mapped in read dac reg\n");
-	PM3_SET_INDEX(r);
-	mb();
-	return (PM3_READ_REG(PM3RD_IndexedData));
+	PM3_SLOW_WRITE_REG(par, PM3RD_PaletteWriteAddress, regno);
+	PM3_SLOW_WRITE_REG(par, PM3RD_PaletteData, r);
+	PM3_SLOW_WRITE_REG(par, PM3RD_PaletteData, g);
+	PM3_SLOW_WRITE_REG(par, PM3RD_PaletteData, b);
+}
+
+static void pm3fb_clear_colormap(struct pm3_par *par,
+			unsigned char r, unsigned char g, unsigned char b)
+{
+	int i;
+
+	for (i = 0; i < 256 ; i++) /* fill color map with white */
+		pm3fb_set_color(par, i, r, g, b);
+
 }
 
 /* Calculating various clock parameter */
-static unsigned long pm3fb_CalculateClock(struct pm3fb_info *l_fb_info, unsigned long reqclock,	/* In kHz units */
-					  unsigned long refclock,	/* In kHz units */
-					  unsigned char *prescale,	/* ClkPreScale */
-					  unsigned char *feedback,	/* ClkFeedBackScale */
-					  unsigned char *postscale
-					  /* ClkPostScale */ )
+static void pm3fb_calculate_clock(unsigned long reqclock,
+				unsigned char *prescale,
+				unsigned char *feedback,
+				unsigned char *postscale)
 {
 	int f, pre, post;
 	unsigned long freq;
 	long freqerr = 1000;
-	unsigned long actualclock = 0;
-
-	DTRACE;
+	long currerr;
 
 	for (f = 1; f < 256; f++) {
 		for (pre = 1; pre < 256; pre++) {
 			for (post = 0; post < 5; post++) {
-				freq =
-				    ((2 * refclock * f) /
-				     (pre * (1 << post)));
-				if ((reqclock > freq - freqerr)
-				    && (reqclock < freq + freqerr)) {
-					freqerr =
-					    (reqclock >
-					     freq) ? reqclock -
-					    freq : freq - reqclock;
+				freq = ((2*PM3_REF_CLOCK * f) >> post) / pre;
+				currerr = (reqclock > freq)
+					? reqclock - freq
+					: freq - reqclock;
+				if (currerr < freqerr) {
+					freqerr = currerr;
 					*feedback = f;
 					*prescale = pre;
 					*postscale = post;
-					actualclock = freq;
 				}
 			}
 		}
 	}
-
-	return (actualclock);
 }
 
-static int pm3fb_Shiftbpp(struct pm3fb_info *l_fb_info,
-			  unsigned long depth, int v)
+static inline int pm3fb_shift_bpp(unsigned long depth, int v)
 {
-	DTRACE;
-	
 	switch (depth) {
 	case 8:
 		return (v >> 4);
@@ -918,181 +187,59 @@
 	case 32:
 		return (v >> 2);
 	}
-	DPRINTK(1, "Unsupported depth %ld\n", depth);
-	return (0);
-}
-
-static int pm3fb_Unshiftbpp(struct pm3fb_info *l_fb_info,
-			    unsigned long depth, int v)
-{
-	DTRACE;
-
-	switch (depth) {
-	case 8:
-		return (v << 4);
-	case 12:	
-	case 15:
-	case 16:
-		return (v << 3);
-	case 32:
-		return (v << 2);
-	}
-	DPRINTK(1, "Unsupported depth %ld\n", depth);
-	return (0);
-}
-
-static void pm3fb_mapIO(struct pm3fb_info *l_fb_info)
-{
-	DTRACE;
-
-	l_fb_info->vIOBase =
-	    ioremap((unsigned long) l_fb_info->pIOBase, PM3_REGS_SIZE);
-	l_fb_info->v_fb =
-	    ioremap((unsigned long) l_fb_info->p_fb, l_fb_info->fb_size);
-	DPRINTK(2, "IO mapping : IOBase %lx / %lx, fb %lx / %lx\n",
-		(unsigned long) l_fb_info->pIOBase,
-		(unsigned long) l_fb_info->vIOBase,
-		(unsigned long) l_fb_info->p_fb,
-		(unsigned long) l_fb_info->v_fb);
-}
-
-static void pm3fb_unmapIO(struct pm3fb_info *l_fb_info)
-{
-	DTRACE;
-
-	iounmap(l_fb_info->vIOBase);
-	iounmap(l_fb_info->v_fb);
-	l_fb_info->vIOBase = (unsigned char *) -1;
-	l_fb_info->v_fb = (unsigned char *) -1;
-}
-
-#if defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 2)
-static void pm3fb_show_cur_mode(struct pm3fb_info *l_fb_info)
-{
-	DPRINTK(2, "PM3Aperture0: 0x%08x\n", PM3_READ_REG(PM3Aperture0));
-	DPRINTK(2, "PM3Aperture1: 0x%08x\n", PM3_READ_REG(PM3Aperture1));
-	DPRINTK(2, "PM3ByAperture1Mode: 0x%08x\n",
-		PM3_READ_REG(PM3ByAperture1Mode));
-	DPRINTK(2, "PM3ByAperture2Mode: 0x%08x\n",
-		PM3_READ_REG(PM3ByAperture2Mode));
-	DPRINTK(2, "PM3ChipConfig: 0x%08x\n", PM3_READ_REG(PM3ChipConfig));
-	DPRINTK(2, "PM3FIFODis: 0x%08x\n", PM3_READ_REG(PM3FIFODis));
-	DPRINTK(2, "PM3HTotal: 0x%08x\n", PM3_READ_REG(PM3HTotal));
-	DPRINTK(2, "PM3HbEnd: 0x%08x\n", PM3_READ_REG(PM3HbEnd));
-	DPRINTK(2, "PM3HgEnd: 0x%08x\n", PM3_READ_REG(PM3HgEnd));
-	DPRINTK(2, "PM3HsEnd: 0x%08x\n", PM3_READ_REG(PM3HsEnd));
-	DPRINTK(2, "PM3HsStart: 0x%08x\n", PM3_READ_REG(PM3HsStart));
-	DPRINTK(2, "PM3MemBypassWriteMask: 0x%08x\n",
-		PM3_READ_REG(PM3MemBypassWriteMask));
-	DPRINTK(2, "PM3RD_IndexControl: 0x%08x\n",
-		PM3_READ_REG(PM3RD_IndexControl));
-	DPRINTK(2, "PM3ScreenBase: 0x%08x\n", PM3_READ_REG(PM3ScreenBase));
-	DPRINTK(2, "PM3ScreenStride: 0x%08x\n",
-		PM3_READ_REG(PM3ScreenStride));
-	DPRINTK(2, "PM3VClkCtl: 0x%08x\n", PM3_READ_REG(PM3VClkCtl));
-	DPRINTK(2, "PM3VTotal: 0x%08x\n", PM3_READ_REG(PM3VTotal));
-	DPRINTK(2, "PM3VbEnd: 0x%08x\n", PM3_READ_REG(PM3VbEnd));
-	DPRINTK(2, "PM3VideoControl: 0x%08x\n",
-		PM3_READ_REG(PM3VideoControl));
-	DPRINTK(2, "PM3VsEnd: 0x%08x\n", PM3_READ_REG(PM3VsEnd));
-	DPRINTK(2, "PM3VsStart: 0x%08x\n", PM3_READ_REG(PM3VsStart));
-
-	DPRINTK(2, "PM3RD_ColorFormat: %ld\n",
-		PM3_READ_DAC_REG(PM3RD_ColorFormat));
-	DPRINTK(2, "PM3RD_DACControl: %ld\n",
-		PM3_READ_DAC_REG(PM3RD_DACControl));
-	DPRINTK(2, "PM3RD_DClk0FeedbackScale: %ld\n",
-		PM3_READ_DAC_REG(PM3RD_DClk0FeedbackScale));
-	DPRINTK(2, "PM3RD_DClk0PostScale: %ld\n",
-		PM3_READ_DAC_REG(PM3RD_DClk0PostScale));
-	DPRINTK(2, "PM3RD_DClk0PreScale: %ld\n",
-		PM3_READ_DAC_REG(PM3RD_DClk0PreScale));
-	DPRINTK(2, "[not set] PM3RD_IndexControl: %ld\n",
-		PM3_READ_DAC_REG(PM3RD_IndexControl));
-	DPRINTK(2, "PM3RD_MiscControl: %ld\n",
-		PM3_READ_DAC_REG(PM3RD_MiscControl));
-	DPRINTK(2, "PM3RD_PixelSize: %ld\n",
-		PM3_READ_DAC_REG(PM3RD_PixelSize));
-	DPRINTK(2, "PM3RD_SyncControl: %ld\n",
-		PM3_READ_DAC_REG(PM3RD_SyncControl));
-}
-
-#endif /* defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 2) */
-static void pm3fb_show_cur_timing(struct pm3fb_info *l_fb_info)
-{
-	u16 subvendor, subdevice;
-
-	if ((!pci_read_config_word
-	     (l_fb_info->dev, PCI_SUBSYSTEM_VENDOR_ID, &subvendor))
-	    &&
-	    (!pci_read_config_word
-	     (l_fb_info->dev, PCI_SUBSYSTEM_ID, &subdevice))) {
-		/* well, nothing... */
-	} else {
-		subvendor = subdevice = (u16)-1;
-	}
-
-	printk(KERN_INFO "pm3fb: memory timings for board #%ld (subvendor: 0x%hx, subdevice: 0x%hx)\n", l_fb_info->board_num, subvendor, subdevice);
-	printk(KERN_INFO " PM3LocalMemCaps: 0x%08x\n",
-	       PM3_READ_REG(PM3LocalMemCaps));
-	printk(KERN_INFO " PM3LocalMemTimings: 0x%08x\n",
-	       PM3_READ_REG(PM3LocalMemTimings));
-	printk(KERN_INFO " PM3LocalMemControl: 0x%08x\n",
-	       PM3_READ_REG(PM3LocalMemControl));
-	printk(KERN_INFO " PM3LocalMemRefresh: 0x%08x\n",
-	       PM3_READ_REG(PM3LocalMemRefresh));
-	printk(KERN_INFO " PM3LocalMemPowerDown: 0x%08x\n",
-	       PM3_READ_REG(PM3LocalMemPowerDown));
+	DPRINTK("Unsupported depth %ld\n", depth);
+	return 0;
 }
 
 /* write the mode to registers */
-static void pm3fb_write_mode(struct pm3fb_info *l_fb_info)
+static void pm3fb_write_mode(struct fb_info *info)
 {
+	struct pm3_par *par = info->par;
 	char tempsync = 0x00, tempmisc = 0x00;
-	DTRACE;
+	const u32 hsstart = info->var.right_margin;
+	const u32 hsend = hsstart + info->var.hsync_len;
+	const u32 hbend = hsend + info->var.left_margin;
+	const u32 xres = (info->var.xres + 31) & ~31;
+	const u32 htotal = xres + hbend;
+	const u32 vsstart = info->var.lower_margin;
+	const u32 vsend = vsstart + info->var.vsync_len;
+	const u32 vbend = vsend + info->var.upper_margin;
+	const u32 vtotal = info->var.yres + vbend;
+	const u32 width = (info->var.xres_virtual + 7) & ~7;
 
-	PM3_SLOW_WRITE_REG(PM3MemBypassWriteMask, 0xffffffff);
-	PM3_SLOW_WRITE_REG(PM3Aperture0, 0x00000000);
-	PM3_SLOW_WRITE_REG(PM3Aperture1, 0x00000000);
-	PM3_SLOW_WRITE_REG(PM3FIFODis, 0x00000007);
+	PM3_SLOW_WRITE_REG(par, PM3MemBypassWriteMask, 0xffffffff);
+	PM3_SLOW_WRITE_REG(par, PM3Aperture0, 0x00000000);
+	PM3_SLOW_WRITE_REG(par, PM3Aperture1, 0x00000000);
+	PM3_SLOW_WRITE_REG(par, PM3FIFODis, 0x00000007);
 
-	PM3_SLOW_WRITE_REG(PM3HTotal,
-			   pm3fb_Shiftbpp(l_fb_info,
-					  l_fb_info->current_par->depth,
-					  l_fb_info->current_par->htotal -
-					  1));
-	PM3_SLOW_WRITE_REG(PM3HsEnd,
-			   pm3fb_Shiftbpp(l_fb_info,
-					  l_fb_info->current_par->depth,
-					  l_fb_info->current_par->hsend));
-	PM3_SLOW_WRITE_REG(PM3HsStart,
-			   pm3fb_Shiftbpp(l_fb_info,
-					  l_fb_info->current_par->depth,
-					  l_fb_info->current_par->
+	PM3_SLOW_WRITE_REG(par, PM3HTotal,
+			   pm3fb_shift_bpp(info->var.bits_per_pixel,
+					  htotal - 1));
+	PM3_SLOW_WRITE_REG(par, PM3HsEnd,
+			   pm3fb_shift_bpp(info->var.bits_per_pixel,
+					  hsend));
+	PM3_SLOW_WRITE_REG(par, PM3HsStart,
+			   pm3fb_shift_bpp(info->var.bits_per_pixel,
 					  hsstart));
-	PM3_SLOW_WRITE_REG(PM3HbEnd,
-			   pm3fb_Shiftbpp(l_fb_info,
-					  l_fb_info->current_par->depth,
-					  l_fb_info->current_par->hbend));
-	PM3_SLOW_WRITE_REG(PM3HgEnd,
-			   pm3fb_Shiftbpp(l_fb_info,
-					  l_fb_info->current_par->depth,
-					  l_fb_info->current_par->hbend));
-	PM3_SLOW_WRITE_REG(PM3ScreenStride,
-			   pm3fb_Shiftbpp(l_fb_info,
-					  l_fb_info->current_par->depth,
-					  l_fb_info->current_par->stride));
-	PM3_SLOW_WRITE_REG(PM3VTotal, l_fb_info->current_par->vtotal - 1);
-	PM3_SLOW_WRITE_REG(PM3VsEnd, l_fb_info->current_par->vsend - 1);
-	PM3_SLOW_WRITE_REG(PM3VsStart,
-			   l_fb_info->current_par->vsstart - 1);
-	PM3_SLOW_WRITE_REG(PM3VbEnd, l_fb_info->current_par->vbend);
+	PM3_SLOW_WRITE_REG(par, PM3HbEnd,
+			   pm3fb_shift_bpp(info->var.bits_per_pixel,
+					  hbend));
+	PM3_SLOW_WRITE_REG(par, PM3HgEnd,
+			   pm3fb_shift_bpp(info->var.bits_per_pixel,
+					  hbend));
+	PM3_SLOW_WRITE_REG(par, PM3ScreenStride,
+			   pm3fb_shift_bpp(info->var.bits_per_pixel,
+					  width));
+	PM3_SLOW_WRITE_REG(par, PM3VTotal, vtotal - 1);
+	PM3_SLOW_WRITE_REG(par, PM3VsEnd, vsend - 1);
+	PM3_SLOW_WRITE_REG(par, PM3VsStart, vsstart - 1);
+	PM3_SLOW_WRITE_REG(par, PM3VbEnd, vbend);
 
-	switch (l_fb_info->current_par->depth) {
+	switch (info->var.bits_per_pixel) {
 	case 8:
-		PM3_SLOW_WRITE_REG(PM3ByAperture1Mode,
+		PM3_SLOW_WRITE_REG(par, PM3ByAperture1Mode,
 				   PM3ByApertureMode_PIXELSIZE_8BIT);
-		PM3_SLOW_WRITE_REG(PM3ByAperture2Mode,
+		PM3_SLOW_WRITE_REG(par, PM3ByAperture2Mode,
 				   PM3ByApertureMode_PIXELSIZE_8BIT);
 		break;
 
@@ -1100,15 +247,15 @@
 	case 15:
 	case 16:
 #ifndef __BIG_ENDIAN
-		PM3_SLOW_WRITE_REG(PM3ByAperture1Mode,
+		PM3_SLOW_WRITE_REG(par, PM3ByAperture1Mode,
 				   PM3ByApertureMode_PIXELSIZE_16BIT);
-		PM3_SLOW_WRITE_REG(PM3ByAperture2Mode,
+		PM3_SLOW_WRITE_REG(par, PM3ByAperture2Mode,
 				   PM3ByApertureMode_PIXELSIZE_16BIT);
 #else
-		PM3_SLOW_WRITE_REG(PM3ByAperture1Mode,
+		PM3_SLOW_WRITE_REG(par, PM3ByAperture1Mode,
 				   PM3ByApertureMode_PIXELSIZE_16BIT |
 				   PM3ByApertureMode_BYTESWAP_BADC);
-		PM3_SLOW_WRITE_REG(PM3ByAperture2Mode,
+		PM3_SLOW_WRITE_REG(par, PM3ByAperture2Mode,
 				   PM3ByApertureMode_PIXELSIZE_16BIT |
 				   PM3ByApertureMode_BYTESWAP_BADC);
 #endif /* ! __BIG_ENDIAN */
@@ -1116,23 +263,23 @@
 
 	case 32:
 #ifndef __BIG_ENDIAN
-		PM3_SLOW_WRITE_REG(PM3ByAperture1Mode,
+		PM3_SLOW_WRITE_REG(par, PM3ByAperture1Mode,
 				   PM3ByApertureMode_PIXELSIZE_32BIT);
-		PM3_SLOW_WRITE_REG(PM3ByAperture2Mode,
+		PM3_SLOW_WRITE_REG(par, PM3ByAperture2Mode,
 				   PM3ByApertureMode_PIXELSIZE_32BIT);
 #else
-		PM3_SLOW_WRITE_REG(PM3ByAperture1Mode,
+		PM3_SLOW_WRITE_REG(par, PM3ByAperture1Mode,
 				   PM3ByApertureMode_PIXELSIZE_32BIT |
 				   PM3ByApertureMode_BYTESWAP_DCBA);
-		PM3_SLOW_WRITE_REG(PM3ByAperture2Mode,
+		PM3_SLOW_WRITE_REG(par, PM3ByAperture2Mode,
 				   PM3ByApertureMode_PIXELSIZE_32BIT |
 				   PM3ByApertureMode_BYTESWAP_DCBA);
 #endif /* ! __BIG_ENDIAN */
 		break;
 
 	default:
-		DPRINTK(1, "Unsupported depth %d\n",
-			l_fb_info->current_par->depth);
+		DPRINTK("Unsupported depth %d\n",
+			info->var.bits_per_pixel);
 		break;
 	}
 
@@ -1143,95 +290,86 @@
 	 * sync options in PM3RD_SyncControl.  --rmk
 	 */
 	{
-		unsigned int video = l_fb_info->current_par->video;
+		unsigned int video = par->video;
 
 		video &= ~(PM3VideoControl_HSYNC_MASK |
 			   PM3VideoControl_VSYNC_MASK);
 		video |= PM3VideoControl_HSYNC_ACTIVE_HIGH |
 			 PM3VideoControl_VSYNC_ACTIVE_HIGH;
-		PM3_SLOW_WRITE_REG(PM3VideoControl, video);
+		PM3_SLOW_WRITE_REG(par, PM3VideoControl, video);
 	}
-	PM3_SLOW_WRITE_REG(PM3VClkCtl,
-			   (PM3_READ_REG(PM3VClkCtl) & 0xFFFFFFFC));
-	PM3_SLOW_WRITE_REG(PM3ScreenBase, l_fb_info->current_par->base);
-	PM3_SLOW_WRITE_REG(PM3ChipConfig,
-			   (PM3_READ_REG(PM3ChipConfig) & 0xFFFFFFFD));
+	PM3_SLOW_WRITE_REG(par, PM3VClkCtl,
+			   (PM3_READ_REG(par, PM3VClkCtl) & 0xFFFFFFFC));
+	PM3_SLOW_WRITE_REG(par, PM3ScreenBase, par->base);
+	PM3_SLOW_WRITE_REG(par, PM3ChipConfig,
+			   (PM3_READ_REG(par, PM3ChipConfig) & 0xFFFFFFFD));
 
 	{
-		unsigned char m;	/* ClkPreScale */
-		unsigned char n;	/* ClkFeedBackScale */
-		unsigned char p;	/* ClkPostScale */
-		(void)pm3fb_CalculateClock(l_fb_info, l_fb_info->current_par->pixclock, PM3_REF_CLOCK, &m, &n, &p);
+		unsigned char uninitialized_var(m);	/* ClkPreScale */
+		unsigned char uninitialized_var(n);	/* ClkFeedBackScale */
+		unsigned char uninitialized_var(p);	/* ClkPostScale */
+		unsigned long pixclock = PICOS2KHZ(info->var.pixclock);
 
-		DPRINTK(2,
-			"Pixclock: %d, Pre: %d, Feedback: %d, Post: %d\n",
-			l_fb_info->current_par->pixclock, (int) m, (int) n,
-			(int) p);
+		(void)pm3fb_calculate_clock(pixclock, &m, &n, &p);
 
-		PM3_WRITE_DAC_REG(PM3RD_DClk0PreScale, m);
-		PM3_WRITE_DAC_REG(PM3RD_DClk0FeedbackScale, n);
-		PM3_WRITE_DAC_REG(PM3RD_DClk0PostScale, p);
+		DPRINTK("Pixclock: %ld, Pre: %d, Feedback: %d, Post: %d\n",
+			pixclock, (int) m, (int) n, (int) p);
+
+		PM3_WRITE_DAC_REG(par, PM3RD_DClk0PreScale, m);
+		PM3_WRITE_DAC_REG(par, PM3RD_DClk0FeedbackScale, n);
+		PM3_WRITE_DAC_REG(par, PM3RD_DClk0PostScale, p);
 	}
 	/*
-	   PM3_WRITE_DAC_REG(PM3RD_IndexControl, 0x00);
+	   PM3_WRITE_DAC_REG(par, PM3RD_IndexControl, 0x00);
 	 */
 	/*
-	   PM3_SLOW_WRITE_REG(PM3RD_IndexControl, 0x00);
+	   PM3_SLOW_WRITE_REG(par, PM3RD_IndexControl, 0x00);
 	 */
-	if ((l_fb_info->current_par->video & PM3VideoControl_HSYNC_MASK) ==
+	if ((par->video & PM3VideoControl_HSYNC_MASK) ==
 	    PM3VideoControl_HSYNC_ACTIVE_HIGH)
 		tempsync |= PM3RD_SyncControl_HSYNC_ACTIVE_HIGH;
-	if ((l_fb_info->current_par->video & PM3VideoControl_VSYNC_MASK) ==
+	if ((par->video & PM3VideoControl_VSYNC_MASK) ==
 	    PM3VideoControl_VSYNC_ACTIVE_HIGH)
 		tempsync |= PM3RD_SyncControl_VSYNC_ACTIVE_HIGH;
-	
-	PM3_WRITE_DAC_REG(PM3RD_SyncControl, tempsync);
-	DPRINTK(2, "PM3RD_SyncControl: %d\n", tempsync);
-	
-	if (flatpanel[l_fb_info->board_num])
-	{
-		PM3_WRITE_DAC_REG(PM3RD_DACControl, PM3RD_DACControl_BLANK_PEDESTAL_ENABLE);
-		PM3_WAIT(2);
-		PM3_WRITE_REG(PM3VSConfiguration, 0x06);
-		PM3_WRITE_REG(0x5a00, 1 << 14); /* black magic... */
-		tempmisc = PM3RD_MiscControl_VSB_OUTPUT_ENABLE;
-	}
-	else
-		PM3_WRITE_DAC_REG(PM3RD_DACControl, 0x00);
 
-	switch (l_fb_info->current_par->depth) {
+	PM3_WRITE_DAC_REG(par, PM3RD_SyncControl, tempsync);
+	DPRINTK("PM3RD_SyncControl: %d\n", tempsync);
+
+	PM3_WRITE_DAC_REG(par, PM3RD_DACControl, 0x00);
+
+	switch (info->var.bits_per_pixel) {
 	case 8:
-		PM3_WRITE_DAC_REG(PM3RD_PixelSize,
+		PM3_WRITE_DAC_REG(par, PM3RD_PixelSize,
 				  PM3RD_PixelSize_8_BIT_PIXELS);
-		PM3_WRITE_DAC_REG(PM3RD_ColorFormat,
+		PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat,
 				  PM3RD_ColorFormat_CI8_COLOR |
 				  PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW);
 		tempmisc |= PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
 		break;
 	case 12:
-		PM3_WRITE_DAC_REG(PM3RD_PixelSize,
+		PM3_WRITE_DAC_REG(par, PM3RD_PixelSize,
 				  PM3RD_PixelSize_16_BIT_PIXELS);
-		PM3_WRITE_DAC_REG(PM3RD_ColorFormat,
+		PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat,
 				  PM3RD_ColorFormat_4444_COLOR |
 				  PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW |
 				  PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE);
 		tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
 			PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
-		break;		
+		break;
 	case 15:
-		PM3_WRITE_DAC_REG(PM3RD_PixelSize,
+		PM3_WRITE_DAC_REG(par, PM3RD_PixelSize,
 				  PM3RD_PixelSize_16_BIT_PIXELS);
-		PM3_WRITE_DAC_REG(PM3RD_ColorFormat,
+		PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat,
 				  PM3RD_ColorFormat_5551_FRONT_COLOR |
 				  PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW |
 				  PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE);
 		tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
 			PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
-		break;		
+		break;
 	case 16:
-		PM3_WRITE_DAC_REG(PM3RD_PixelSize,
+		PM3_WRITE_DAC_REG(par, PM3RD_PixelSize,
 				  PM3RD_PixelSize_16_BIT_PIXELS);
-		PM3_WRITE_DAC_REG(PM3RD_ColorFormat,
+		PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat,
 				  PM3RD_ColorFormat_565_FRONT_COLOR |
 				  PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW |
 				  PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE);
@@ -1239,1936 +377,280 @@
 			PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
 		break;
 	case 32:
-		PM3_WRITE_DAC_REG(PM3RD_PixelSize,
+		PM3_WRITE_DAC_REG(par, PM3RD_PixelSize,
 				  PM3RD_PixelSize_32_BIT_PIXELS);
-		PM3_WRITE_DAC_REG(PM3RD_ColorFormat,
+		PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat,
 				  PM3RD_ColorFormat_8888_COLOR |
 				  PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW);
 		tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
 			PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
 		break;
 	}
-	PM3_WRITE_DAC_REG(PM3RD_MiscControl, tempmisc);
-	
-	PM3_SHOW_CUR_MODE;
+	PM3_WRITE_DAC_REG(par, PM3RD_MiscControl, tempmisc);
 }
 
-static void pm3fb_read_mode(struct pm3fb_info *l_fb_info,
-			    struct pm3fb_par *curpar)
+/*
+ * hardware independent functions
+ */
+int pm3fb_init(void);
+int pm3fb_setup(char*);
+
+static int pm3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 {
-	unsigned long pixsize1, pixsize2, clockused;
-	unsigned long pre, feedback, post;
+	u32 lpitch;
 
-	DTRACE;
-
-	clockused = PM3_READ_REG(PM3VClkCtl);
-
-	switch (clockused) {
-	case 3:
-		pre = PM3_READ_DAC_REG(PM3RD_DClk3PreScale);
-		feedback = PM3_READ_DAC_REG(PM3RD_DClk3FeedbackScale);
-		post = PM3_READ_DAC_REG(PM3RD_DClk3PostScale);
-
-		DPRINTK(2,
-			"DClk3 parameter: Pre: %ld, Feedback: %ld, Post: %ld ; giving pixclock: %ld\n",
-			pre, feedback, post, PM3_SCALE_TO_CLOCK(pre,
-								feedback,
-								post));
-		break;
-	case 2:
-		pre = PM3_READ_DAC_REG(PM3RD_DClk2PreScale);
-		feedback = PM3_READ_DAC_REG(PM3RD_DClk2FeedbackScale);
-		post = PM3_READ_DAC_REG(PM3RD_DClk2PostScale);
-
-		DPRINTK(2,
-			"DClk2 parameter: Pre: %ld, Feedback: %ld, Post: %ld ; giving pixclock: %ld\n",
-			pre, feedback, post, PM3_SCALE_TO_CLOCK(pre,
-								feedback,
-								post));
-		break;
-	case 1:
-		pre = PM3_READ_DAC_REG(PM3RD_DClk1PreScale);
-		feedback = PM3_READ_DAC_REG(PM3RD_DClk1FeedbackScale);
-		post = PM3_READ_DAC_REG(PM3RD_DClk1PostScale);
-
-		DPRINTK(2,
-			"DClk1 parameter: Pre: %ld, Feedback: %ld, Post: %ld ; giving pixclock: %ld\n",
-			pre, feedback, post, PM3_SCALE_TO_CLOCK(pre,
-								feedback,
-								post));
-		break;
-	case 0:
-		pre = PM3_READ_DAC_REG(PM3RD_DClk0PreScale);
-		feedback = PM3_READ_DAC_REG(PM3RD_DClk0FeedbackScale);
-		post = PM3_READ_DAC_REG(PM3RD_DClk0PostScale);
-
-		DPRINTK(2,
-			"DClk0 parameter: Pre: %ld, Feedback: %ld, Post: %ld ; giving pixclock: %ld\n",
-			pre, feedback, post, PM3_SCALE_TO_CLOCK(pre,
-								feedback,
-								post));
-		break;
-	default:
-		pre = feedback = post = 0;
-		DPRINTK(1, "Unknowk D clock used : %ld\n", clockused);
-		break;
-	}
-
-	curpar->pixclock = PM3_SCALE_TO_CLOCK(pre, feedback, post);
-
-	pixsize1 =
-	    PM3ByApertureMode_PIXELSIZE_MASK &
-	    (PM3_READ_REG(PM3ByAperture1Mode));
-	pixsize2 =
-	    PM3ByApertureMode_PIXELSIZE_MASK &
-	    (PM3_READ_REG(PM3ByAperture2Mode));
-
-	DASSERT((pixsize1 == pixsize2),
-		"pixsize the same in both aperture\n");
-
-	if (pixsize1 & PM3ByApertureMode_PIXELSIZE_32BIT)
-		curpar->depth = 32;
-	else if (pixsize1 & PM3ByApertureMode_PIXELSIZE_16BIT)
-	{
-		curpar->depth = 16;
-	}
-	else
-		curpar->depth = 8;
-
-	/* not sure if I need to add one on the next ; it give better result with */
-	curpar->htotal =
-	    pm3fb_Unshiftbpp(l_fb_info, curpar->depth,
-			     1 + PM3_READ_REG(PM3HTotal));
-	curpar->hsend =
-	    pm3fb_Unshiftbpp(l_fb_info, curpar->depth,
-			     PM3_READ_REG(PM3HsEnd));
-	curpar->hsstart =
-	    pm3fb_Unshiftbpp(l_fb_info, curpar->depth,
-			     PM3_READ_REG(PM3HsStart));
-	curpar->hbend =
-	    pm3fb_Unshiftbpp(l_fb_info, curpar->depth,
-			     PM3_READ_REG(PM3HbEnd));
-
-	curpar->stride =
-	    pm3fb_Unshiftbpp(l_fb_info, curpar->depth,
-			     PM3_READ_REG(PM3ScreenStride));
-
-	curpar->vtotal = 1 + PM3_READ_REG(PM3VTotal);
-	curpar->vsend = 1 + PM3_READ_REG(PM3VsEnd);
-	curpar->vsstart = 1 + PM3_READ_REG(PM3VsStart);
-	curpar->vbend = PM3_READ_REG(PM3VbEnd);
-
-	curpar->video = PM3_READ_REG(PM3VideoControl);
-
-	curpar->base = PM3_READ_REG(PM3ScreenBase);
-	curpar->width = curpar->htotal - curpar->hbend; /* make virtual == displayed resolution */
-	curpar->height = curpar->vtotal - curpar->vbend;
-
-	DPRINTK(2, "Found : %d * %d, %d Khz, stride is %08x\n",
-		curpar->width, curpar->height, curpar->pixclock,
-		curpar->stride);
-}
-
-static unsigned long pm3fb_size_memory(struct pm3fb_info *l_fb_info)
-{
-	unsigned long memsize = 0, tempBypass, i, temp1, temp2;
-	u16 subvendor, subdevice;
-	pm3fb_timing_result ptr;
-
-	DTRACE;
-
-	l_fb_info->fb_size = 64 * 1024 * 1024;	/* pm3 aperture always 64 MB */
-	pm3fb_mapIO(l_fb_info);	/* temporary map IO */
-
-	DASSERT((l_fb_info->vIOBase != NULL),
-		"IO successfully mapped before mem detect\n");
-	DASSERT((l_fb_info->v_fb != NULL),
-		"FB successfully mapped before mem detect\n");
-
-	/* card-specific stuff, *before* accessing *any* FB memory */
-	if ((!pci_read_config_word
-	     (l_fb_info->dev, PCI_SUBSYSTEM_VENDOR_ID, &subvendor))
-	    &&
-	    (!pci_read_config_word
-	     (l_fb_info->dev, PCI_SUBSYSTEM_ID, &subdevice))) {
-		i = 0; l_fb_info->board_type = 0;
-		while ((cardbase[i].cardname[0]) && !(l_fb_info->board_type)) {
-			if ((cardbase[i].subvendor == subvendor) &&
-			    (cardbase[i].subdevice == subdevice) &&
-			    (cardbase[i].func == PCI_FUNC(l_fb_info->dev->devfn))) {
-				DPRINTK(2, "Card #%ld is an %s\n",
-					l_fb_info->board_num,
-					cardbase[i].cardname);
-				if (cardbase[i].specific_setup)
-					cardbase[i].specific_setup(l_fb_info);
-				l_fb_info->board_type = i;
-			}
-			i++;
-		}
-		if (!l_fb_info->board_type) {
-			DPRINTK(1, "Card #%ld is an unknown 0x%04x / 0x%04x\n",
-				l_fb_info->board_num, subvendor, subdevice);
-		}
-	} else {
-		printk(KERN_ERR "pm3fb: Error: pci_read_config_word failed, board #%ld\n",
-		       l_fb_info->board_num);
-	}
-
-	if (printtimings)
-		pm3fb_show_cur_timing(l_fb_info);
-	
-	/* card-specific setup is done, we preserve the final
-           memory timing for future reference */
-	if ((ptr = pm3fb_preserve_memory_timings(l_fb_info)) == pm3fb_timing_problem) { /* memory timings were wrong ! oops.... */
-		return(0);
-	}
-	
-	tempBypass = PM3_READ_REG(PM3MemBypassWriteMask);
-
-	DPRINTK(2, "PM3MemBypassWriteMask was: 0x%08lx\n", tempBypass);
-
-	PM3_SLOW_WRITE_REG(PM3MemBypassWriteMask, 0xFFFFFFFF);
-
-	/* pm3 split up memory, replicates, and do a lot of nasty stuff IMHO ;-) */
-	for (i = 0; i < 32; i++) {
-		fb_writel(i * 0x00345678,
-			  (l_fb_info->v_fb + (i * 1048576)));
-		mb();
-		temp1 = fb_readl((l_fb_info->v_fb + (i * 1048576)));
-
-		/* Let's check for wrapover, write will fail at 16MB boundary */
-		if (temp1 == (i * 0x00345678))
-			memsize = i;
-		else
-			break;
-	}
-
-	DPRINTK(2, "First detect pass already got %ld MB\n", memsize + 1);
-
-	if (memsize == i) {
-		for (i = 0; i < 32; i++) {
-			/* Clear first 32MB ; 0 is 0, no need to byteswap */
-			writel(0x0000000,
-			       (l_fb_info->v_fb + (i * 1048576)));
-			mb();
-		}
-
-		for (i = 32; i < 64; i++) {
-			fb_writel(i * 0x00345678,
-				  (l_fb_info->v_fb + (i * 1048576)));
-			mb();
-			temp1 =
-			    fb_readl((l_fb_info->v_fb + (i * 1048576)));
-			temp2 =
-			    fb_readl((l_fb_info->v_fb +
-				      ((i - 32) * 1048576)));
-			if ((temp1 == (i * 0x00345678)) && (temp2 == 0))	/* different value, different RAM... */
-				memsize = i;
-			else
-				break;
-		}
-	}
-
-	DPRINTK(2, "Second detect pass got %ld MB\n", memsize + 1);
-
-	PM3_SLOW_WRITE_REG(PM3MemBypassWriteMask, tempBypass);
-
-	pm3fb_unmapIO(l_fb_info);
-	memsize = 1048576 * (memsize + 1);
-
-	DPRINTK(2, "Returning 0x%08lx bytes\n", memsize);
-
-	if (forcesize[l_fb_info->board_num] && ((forcesize[l_fb_info->board_num] * 1048576) != memsize))
-	{
-		printk(KERN_WARNING "pm3fb: mismatch between probed (%ld MB) and specified (%hd MB) memory size, using SPECIFIED !\n", memsize, forcesize[l_fb_info->board_num]);
-		memsize = 1048576 * forcesize[l_fb_info->board_num];
-	}
-	
-	l_fb_info->fb_size = memsize;
-	
-	if (ptr == pm3fb_timing_retry)
-	{
-		printk(KERN_WARNING "pm3fb: retrying memory timings check");
-		if (pm3fb_try_memory_timings(l_fb_info) == pm3fb_timing_problem)
-			return(0);
-	}
-	
-	return (memsize);
-}
-
-static void pm3fb_clear_memory(struct pm3fb_info *l_fb_info, u32 cc)
-{
-	int i;
-
-	DTRACE;
-
-	for (i = 0; i < (l_fb_info->fb_size / sizeof(u32)) ; i++) /* clear entire FB memory to black */
-	{
-		fb_writel(cc, (l_fb_info->v_fb + (i * sizeof(u32))));
-	}
-}
-
-static void pm3fb_clear_colormap(struct pm3fb_info *l_fb_info, unsigned char r, unsigned char g, unsigned char b)
-{
-	int i;
-
-	DTRACE;
-
-	for (i = 0; i < 256 ; i++) /* fill color map with white */
-		pm3fb_set_color(l_fb_info, i, r, g, b);
-
-}
-
-/* common initialisation */
-static void pm3fb_common_init(struct pm3fb_info *l_fb_info)
-{
-	DTRACE;
-
-	DPRINTK(2, "Initializing board #%ld @ %lx\n", l_fb_info->board_num,
-		(unsigned long) l_fb_info);
-
-	strcpy(l_fb_info->gen.info.modename, permedia3_name);
-	disp[l_fb_info->board_num].scrollmode = 0;	/* SCROLL_YNOMOVE; *//* 0 means "let fbcon choose" */
-	l_fb_info->gen.parsize = sizeof(struct pm3fb_par);
-	l_fb_info->gen.info.changevar = NULL;
-	l_fb_info->gen.info.fbops = &pm3fb_ops;
-	l_fb_info->gen.info.disp = &(disp[l_fb_info->board_num]);
-	if (fontn[l_fb_info->board_num][0])
-		strcpy(l_fb_info->gen.info.fontname,
-		       fontn[l_fb_info->board_num]);
-	l_fb_info->gen.info.switch_con = &fbgen_switch;
-	l_fb_info->gen.info.updatevar = &fbgen_update_var;	/* */
-	l_fb_info->gen.info.flags = FBINFO_FLAG_DEFAULT;
-
-	pm3fb_mapIO(l_fb_info);
-
-	pm3fb_clear_memory(l_fb_info, 0);
-	pm3fb_clear_colormap(l_fb_info, 0, 0, 0);
-
-	(void) fbgen_get_var(&(disp[l_fb_info->board_num]).var, -1,
-			     &l_fb_info->gen.info);
-
-	if (depth[l_fb_info->board_num]) /* override mode-defined depth */
-	{
-		pm3fb_encode_depth(&(disp[l_fb_info->board_num]).var, depth[l_fb_info->board_num]);
-		(disp[l_fb_info->board_num]).var.bits_per_pixel = depth2bpp(depth[l_fb_info->board_num]);
-	}
-
-	(void) fbgen_do_set_var(&(disp[l_fb_info->board_num]).var, 1,
-				&l_fb_info->gen);
-
-	fbgen_set_disp(-1, &l_fb_info->gen);
-
-	do_install_cmap(0, &l_fb_info->gen.info);
-
-	if (register_framebuffer(&l_fb_info->gen.info) < 0) {
-		DPRINTK(1, "Couldn't register framebuffer\n");
-		return;
-	}
-
-	PM3_WRITE_DAC_REG(PM3RD_CursorMode,
-			  PM3RD_CursorMode_CURSOR_DISABLE);
-	
-	PM3_SHOW_CUR_MODE;
-	
-	pm3fb_write_mode(l_fb_info);
-	
-	printk("fb%d: %s, using %uK of video memory (%s)\n",
-	       l_fb_info->gen.info.node,
-	       permedia3_name, (u32) (l_fb_info->fb_size >> 10),
-	       cardbase[l_fb_info->board_type].cardname);
-}
-
-/* **************************************************** */
-/* ***** accelerated permedia3-specific functions ***** */
-/* **************************************************** */
-#ifdef PM3FB_USE_ACCEL
-static void pm3fb_wait_pm3(struct pm3fb_info *l_fb_info)
-{
-	DTRACE;
-
-	PM3_SLOW_WRITE_REG(PM3FilterMode, PM3FilterModeSync);
-	PM3_SLOW_WRITE_REG(PM3Sync, 0);
-	mb();
-	do {
-		while ((PM3_READ_REG(PM3OutFIFOWords)) == 0);
-		rmb();
-	} while ((PM3_READ_REG(PM3OutputFifo)) != PM3Sync_Tag);
-}
-
-static void pm3fb_init_engine(struct pm3fb_info *l_fb_info)
-{
-	PM3_SLOW_WRITE_REG(PM3FilterMode, PM3FilterModeSync);
-	PM3_SLOW_WRITE_REG(PM3StatisticMode, 0x0);
-	PM3_SLOW_WRITE_REG(PM3DeltaMode, 0x0);
-	PM3_SLOW_WRITE_REG(PM3RasterizerMode, 0x0);
-	PM3_SLOW_WRITE_REG(PM3ScissorMode, 0x0);
-	PM3_SLOW_WRITE_REG(PM3LineStippleMode, 0x0);
-	PM3_SLOW_WRITE_REG(PM3AreaStippleMode, 0x0);
-	PM3_SLOW_WRITE_REG(PM3GIDMode, 0x0);
-	PM3_SLOW_WRITE_REG(PM3DepthMode, 0x0);
-	PM3_SLOW_WRITE_REG(PM3StencilMode, 0x0);
-	PM3_SLOW_WRITE_REG(PM3StencilData, 0x0);
-	PM3_SLOW_WRITE_REG(PM3ColorDDAMode, 0x0);
-	PM3_SLOW_WRITE_REG(PM3TextureCoordMode, 0x0);
-	PM3_SLOW_WRITE_REG(PM3TextureIndexMode0, 0x0);
-	PM3_SLOW_WRITE_REG(PM3TextureIndexMode1, 0x0);
-	PM3_SLOW_WRITE_REG(PM3TextureReadMode, 0x0);
-	PM3_SLOW_WRITE_REG(PM3LUTMode, 0x0);
-	PM3_SLOW_WRITE_REG(PM3TextureFilterMode, 0x0);
-	PM3_SLOW_WRITE_REG(PM3TextureCompositeMode, 0x0);
-	PM3_SLOW_WRITE_REG(PM3TextureApplicationMode, 0x0);
-	PM3_SLOW_WRITE_REG(PM3TextureCompositeColorMode1, 0x0);
-	PM3_SLOW_WRITE_REG(PM3TextureCompositeAlphaMode1, 0x0);
-	PM3_SLOW_WRITE_REG(PM3TextureCompositeColorMode0, 0x0);
-	PM3_SLOW_WRITE_REG(PM3TextureCompositeAlphaMode0, 0x0);
-	PM3_SLOW_WRITE_REG(PM3FogMode, 0x0);
-	PM3_SLOW_WRITE_REG(PM3ChromaTestMode, 0x0);
-	PM3_SLOW_WRITE_REG(PM3AlphaTestMode, 0x0);
-	PM3_SLOW_WRITE_REG(PM3AntialiasMode, 0x0);
-	PM3_SLOW_WRITE_REG(PM3YUVMode, 0x0);
-	PM3_SLOW_WRITE_REG(PM3AlphaBlendColorMode, 0x0);
-	PM3_SLOW_WRITE_REG(PM3AlphaBlendAlphaMode, 0x0);
-	PM3_SLOW_WRITE_REG(PM3DitherMode, 0x0);
-	PM3_SLOW_WRITE_REG(PM3LogicalOpMode, 0x0);
-	PM3_SLOW_WRITE_REG(PM3RouterMode, 0x0);
-	PM3_SLOW_WRITE_REG(PM3Window, 0x0);
-
-	PM3_SLOW_WRITE_REG(PM3Config2D, 0x0);
-
-	PM3_SLOW_WRITE_REG(PM3SpanColorMask, 0xffffffff);
-
-	PM3_SLOW_WRITE_REG(PM3XBias, 0x0);
-	PM3_SLOW_WRITE_REG(PM3YBias, 0x0);
-	PM3_SLOW_WRITE_REG(PM3DeltaControl, 0x0);
-
-	PM3_SLOW_WRITE_REG(PM3BitMaskPattern, 0xffffffff);
-
-	PM3_SLOW_WRITE_REG(PM3FBDestReadEnables,
-			   PM3FBDestReadEnables_E(0xff) |
-			   PM3FBDestReadEnables_R(0xff) |
-			   PM3FBDestReadEnables_ReferenceAlpha(0xff));
-	PM3_SLOW_WRITE_REG(PM3FBDestReadBufferAddr0, 0x0);
-	PM3_SLOW_WRITE_REG(PM3FBDestReadBufferOffset0, 0x0);
-	PM3_SLOW_WRITE_REG(PM3FBDestReadBufferWidth0,
-			   PM3FBDestReadBufferWidth_Width(l_fb_info->
-							  current_par->
-							  width));
-
-	PM3_SLOW_WRITE_REG(PM3FBDestReadMode,
-			   PM3FBDestReadMode_ReadEnable |
-			   PM3FBDestReadMode_Enable0);
-	PM3_SLOW_WRITE_REG(PM3FBSourceReadBufferAddr, 0x0);
-	PM3_SLOW_WRITE_REG(PM3FBSourceReadBufferOffset, 0x0);
-	PM3_SLOW_WRITE_REG(PM3FBSourceReadBufferWidth,
-			   PM3FBSourceReadBufferWidth_Width(l_fb_info->
-							    current_par->
-							    width));
-	PM3_SLOW_WRITE_REG(PM3FBSourceReadMode,
-			   PM3FBSourceReadMode_Blocking |
-			   PM3FBSourceReadMode_ReadEnable);
-
-	{
-		unsigned long rm = 1;
-		switch (l_fb_info->current_par->depth) {
-		case 8:
-			PM3_SLOW_WRITE_REG(PM3PixelSize,
-					   PM3PixelSize_GLOBAL_8BIT);
-			break;
-		case 12:
-		case 15:
-		case 16:
-			PM3_SLOW_WRITE_REG(PM3PixelSize,
-					   PM3PixelSize_GLOBAL_16BIT);
-			break;
-		case 32:
-			PM3_SLOW_WRITE_REG(PM3PixelSize,
-					   PM3PixelSize_GLOBAL_32BIT);
-			break;
-		default:
-			DPRINTK(1, "Unsupported depth %d\n",
-				l_fb_info->current_par->depth);
-			break;
-		}
-		PM3_SLOW_WRITE_REG(PM3RasterizerMode, rm);
-	}
-
-	PM3_SLOW_WRITE_REG(PM3FBSoftwareWriteMask, 0xffffffff);
-	PM3_SLOW_WRITE_REG(PM3FBHardwareWriteMask, 0xffffffff);
-	PM3_SLOW_WRITE_REG(PM3FBWriteMode,
-			   PM3FBWriteMode_WriteEnable |
-			   PM3FBWriteMode_OpaqueSpan |
-			   PM3FBWriteMode_Enable0);
-	PM3_SLOW_WRITE_REG(PM3FBWriteBufferAddr0, 0x0);
-	PM3_SLOW_WRITE_REG(PM3FBWriteBufferOffset0, 0x0);
-	PM3_SLOW_WRITE_REG(PM3FBWriteBufferWidth0,
-			   PM3FBWriteBufferWidth_Width(l_fb_info->
-						       current_par->
-						       width));
-
-	PM3_SLOW_WRITE_REG(PM3SizeOfFramebuffer, 0x0);
-	{
-		unsigned long sofb = (8UL * l_fb_info->fb_size) /
-			((depth2bpp(l_fb_info->current_par->depth))
-			 * l_fb_info->current_par->width);	/* size in lines of FB */
-		if (sofb > 4095)
-			PM3_SLOW_WRITE_REG(PM3SizeOfFramebuffer, 4095);
-		else
-			PM3_SLOW_WRITE_REG(PM3SizeOfFramebuffer, sofb);
-		
-		switch (l_fb_info->current_par->depth) {
-		case 8:
-			PM3_SLOW_WRITE_REG(PM3DitherMode,
-					   (1 << 10) | (2 << 3));
-			break;
-		case 12:
-		case 15:
-		case 16:
-			PM3_SLOW_WRITE_REG(PM3DitherMode,
-					   (1 << 10) | (1 << 3));
-			break;
-		case 32:
-			PM3_SLOW_WRITE_REG(PM3DitherMode,
-					   (1 << 10) | (0 << 3));
-			break;
-		default:
-			DPRINTK(1, "Unsupported depth %d\n",
-				l_fb_info->current_par->depth);
-			break;
-		}
-	}
-
-	PM3_SLOW_WRITE_REG(PM3dXDom, 0x0);
-	PM3_SLOW_WRITE_REG(PM3dXSub, 0x0);
-	PM3_SLOW_WRITE_REG(PM3dY, (1 << 16));
-	PM3_SLOW_WRITE_REG(PM3StartXDom, 0x0);
-	PM3_SLOW_WRITE_REG(PM3StartXSub, 0x0);
-	PM3_SLOW_WRITE_REG(PM3StartY, 0x0);
-	PM3_SLOW_WRITE_REG(PM3Count, 0x0);
-	
-/* Disable LocalBuffer. better safe than sorry */
-	PM3_SLOW_WRITE_REG(PM3LBDestReadMode, 0x0);
-	PM3_SLOW_WRITE_REG(PM3LBDestReadEnables, 0x0);
-	PM3_SLOW_WRITE_REG(PM3LBSourceReadMode, 0x0);
-	PM3_SLOW_WRITE_REG(PM3LBWriteMode, 0x0);
-	
-	pm3fb_wait_pm3(l_fb_info);
-}
-
-#ifdef FBCON_HAS_CFB32
-static void pm3fb_cfb32_clear(struct vc_data *conp,
-			      struct display *p,
-			      int sy, int sx, int height, int width)
-{
-	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
-	u32 c;
-
-	DTRACE;
-
-	sx = sx * fontwidth(p);
-	width = width * fontwidth(p);
-	sy = sy * fontheight(p);
-	height = height * fontheight(p);
-	c = ((u32 *) p->dispsw_data)[attr_bgcol_ec(p, conp)];
-
-	/* block fills in 32bpp are hard, but in low res (width <= 1600 :-)
-	   we can use 16bpp operations, but not if NoWriteMask is on (SDRAM)  */
-	if ((l_fb_info->current_par->width > 1600) ||
-	    (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)) {
-		PM3_WAIT(4);
-
-		PM3_WRITE_REG(PM3Config2D,
-					  PM3Config2D_UseConstantSource |
-					  PM3Config2D_ForegroundROPEnable |
-					  (PM3Config2D_ForegroundROP(0x3)) |	/* Ox3 is GXcopy */
-					  PM3Config2D_FBWriteEnable);
-
-		PM3_WRITE_REG(PM3ForegroundColor, c);
-
-		PM3_WRITE_REG(PM3RectanglePosition,
-			      (PM3RectanglePosition_XOffset(sx)) |
-			      (PM3RectanglePosition_YOffset(sy)));
-
-		PM3_WRITE_REG(PM3Render2D,
-			      PM3Render2D_XPositive |
-			      PM3Render2D_YPositive |
-			      PM3Render2D_Operation_Normal |
-			      PM3Render2D_SpanOperation |
-			      (PM3Render2D_Width(width)) |
-			      (PM3Render2D_Height(height)));
-	} else {
-		PM3_WAIT(8);
-
-		PM3_WRITE_REG(PM3FBBlockColor, c);
-
-		PM3_WRITE_REG(PM3PixelSize, PM3PixelSize_GLOBAL_16BIT);
-
-		PM3_WRITE_REG(PM3FBWriteBufferWidth0,
-			      PM3FBWriteBufferWidth_Width(l_fb_info->
-							  current_par->
-							  width << 1));
-
-		PM3_WRITE_REG(PM3Config2D,
-					  PM3Config2D_UseConstantSource |
-					  PM3Config2D_ForegroundROPEnable |
-					  (PM3Config2D_ForegroundROP(0x3)) |	/* Ox3 is GXcopy */
-					  PM3Config2D_FBWriteEnable);
-
-		PM3_WRITE_REG(PM3RectanglePosition,
-			      (PM3RectanglePosition_XOffset(sx << 1)) |
-			      (PM3RectanglePosition_YOffset(sy)));
-
-		PM3_WRITE_REG(PM3Render2D,
-			      PM3Render2D_XPositive |
-			      PM3Render2D_YPositive |
-			      PM3Render2D_Operation_Normal |
-			      (PM3Render2D_Width(width << 1)) |
-			      (PM3Render2D_Height(height)));
-
-		PM3_WRITE_REG(PM3FBWriteBufferWidth0,
-			      PM3FBWriteBufferWidth_Width(l_fb_info->
-							  current_par->
-							  width));
-
-		PM3_WRITE_REG(PM3PixelSize, PM3PixelSize_GLOBAL_32BIT);
-	}
-
-	pm3fb_wait_pm3(l_fb_info);
-}
-
-static void pm3fb_cfb32_clear_margins(struct vc_data *conp,
-				      struct display *p, int bottom_only)
-{
-	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
-	int sx, sy;
-	u32 c;
-
-	DTRACE;
-
-	sx = conp->vc_cols * fontwidth(p);	/* right margin */
-	sy = conp->vc_rows * fontheight(p);	/* bottom margin */
-	c = ((u32 *) p->dispsw_data)[attr_bgcol_ec(p, conp)];
-
-	if (!bottom_only) {	/* right margin top->bottom */
-		PM3_WAIT(4);
-
-		PM3_WRITE_REG(PM3Config2D,
-					  PM3Config2D_UseConstantSource |
-					  PM3Config2D_ForegroundROPEnable |
-					  (PM3Config2D_ForegroundROP(0x3)) |	/* Ox3 is GXcopy */
-					  PM3Config2D_FBWriteEnable);
-
-		PM3_WRITE_REG(PM3ForegroundColor, c);
-
-		PM3_WRITE_REG(PM3RectanglePosition,
-			      (PM3RectanglePosition_XOffset
-			       (p->var.xoffset +
-				sx)) | (PM3RectanglePosition_YOffset(p->
-								     var.
-								     yoffset)));
-
-		PM3_WRITE_REG(PM3Render2D,
-			      PM3Render2D_XPositive |
-			      PM3Render2D_YPositive |
-			      PM3Render2D_Operation_Normal |
-			      PM3Render2D_SpanOperation |
-			      (PM3Render2D_Width(p->var.xres - sx)) |
-			      (PM3Render2D_Height(p->var.yres)));
-	}
-
-	/* bottom margin left -> right */
-	PM3_WAIT(4);
-
-	PM3_WRITE_REG(PM3Config2D,
-				  PM3Config2D_UseConstantSource |
-				  PM3Config2D_ForegroundROPEnable |
-				  (PM3Config2D_ForegroundROP(0x3)) |	/* Ox3 is GXcopy */
-				  PM3Config2D_FBWriteEnable);
-
-	PM3_WRITE_REG(PM3ForegroundColor, c);
-
-	PM3_WRITE_REG(PM3RectanglePosition,
-		      (PM3RectanglePosition_XOffset(p->var.xoffset)) |
-		      (PM3RectanglePosition_YOffset(p->var.yoffset + sy)));
-
-	PM3_WRITE_REG(PM3Render2D,
-		      PM3Render2D_XPositive |
-		      PM3Render2D_YPositive |
-		      PM3Render2D_Operation_Normal |
-		      PM3Render2D_SpanOperation |
-		      (PM3Render2D_Width(p->var.xres)) |
-		      (PM3Render2D_Height(p->var.yres - sy)));
-
-	pm3fb_wait_pm3(l_fb_info);
-}
-#endif /* FBCON_HAS_CFB32 */
-#ifdef FBCON_HAS_CFB16
-static void pm3fb_cfb16_clear(struct vc_data *conp,
-			      struct display *p,
-			      int sy, int sx, int height, int width)
-{
-	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
-	u32 c;
-
-	DTRACE;
-
-	sx = sx * fontwidth(p);
-	width = width * fontwidth(p);
-	sy = sy * fontheight(p);
-	height = height * fontheight(p);
-	c = ((u16 *) p->dispsw_data)[attr_bgcol_ec(p, conp)];
-	c = c | (c << 16);
-
-	PM3_WAIT(4);
-
-	if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
-		PM3_WRITE_REG(PM3ForegroundColor, c);
-	else
-		PM3_WRITE_REG(PM3FBBlockColor, c);
-
-	PM3_WRITE_REG(PM3Config2D,
-				  PM3Config2D_UseConstantSource |
-				  PM3Config2D_ForegroundROPEnable |
-				  (PM3Config2D_ForegroundROP(0x3)) |	/* Ox3 is GXcopy */
-				  PM3Config2D_FBWriteEnable);
-
-	PM3_WRITE_REG(PM3RectanglePosition,
-		      (PM3RectanglePosition_XOffset(sx)) |
-		      (PM3RectanglePosition_YOffset(sy)));
-	
-	if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
-		PM3_WRITE_REG(PM3Render2D,
-			      PM3Render2D_XPositive |
-			      PM3Render2D_YPositive |
-			      PM3Render2D_Operation_Normal |
-			      PM3Render2D_SpanOperation |
-			      (PM3Render2D_Width(width)) |
-			      (PM3Render2D_Height(height)));
-	else
-		PM3_WRITE_REG(PM3Render2D,
-			      PM3Render2D_XPositive |
-			      PM3Render2D_YPositive |
-			      PM3Render2D_Operation_Normal |
-			      (PM3Render2D_Width(width)) |
-			      (PM3Render2D_Height(height)));
-	
-	pm3fb_wait_pm3(l_fb_info);
-}
-
-static void pm3fb_cfb16_clear_margins(struct vc_data *conp,
-				      struct display *p, int bottom_only)
-{
-	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
-	int sx, sy;
-	u32 c;
-
-	DTRACE;
-
-	sx = conp->vc_cols * fontwidth(p);	/* right margin */
-	sy = conp->vc_rows * fontheight(p);	/* bottom margin */
-	c = ((u16 *) p->dispsw_data)[attr_bgcol_ec(p, conp)];
-	c = c | (c << 16);
-
-	if (!bottom_only) {	/* right margin top->bottom */
-		PM3_WAIT(4);
-
-		PM3_WRITE_REG(PM3Config2D,
-					  PM3Config2D_UseConstantSource |
-					  PM3Config2D_ForegroundROPEnable |
-					  (PM3Config2D_ForegroundROP(0x3)) |	/* Ox3 is GXcopy */
-					  PM3Config2D_FBWriteEnable);
-		
-		if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
-			PM3_WRITE_REG(PM3ForegroundColor, c);
-		else
-			PM3_WRITE_REG(PM3FBBlockColor, c);
-		
-		PM3_WRITE_REG(PM3RectanglePosition,
-			      (PM3RectanglePosition_XOffset
-			       (p->var.xoffset +
-				sx)) | (PM3RectanglePosition_YOffset(p->
-								     var.
-								     yoffset)));
-		if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
-			PM3_WRITE_REG(PM3Render2D,
-				      PM3Render2D_XPositive |
-				      PM3Render2D_YPositive |
-				      PM3Render2D_Operation_Normal |
-				      PM3Render2D_SpanOperation |
-				      (PM3Render2D_Width(p->var.xres - sx)) |
-				      (PM3Render2D_Height(p->var.yres)));
-		else
-			PM3_WRITE_REG(PM3Render2D,
-				      PM3Render2D_XPositive |
-				      PM3Render2D_YPositive |
-				      PM3Render2D_Operation_Normal |
-				      (PM3Render2D_Width(p->var.xres - sx)) |
-				      (PM3Render2D_Height(p->var.yres)));
-	}
-	
-	/* bottom margin left -> right */
-	PM3_WAIT(4);
-	
-	PM3_WRITE_REG(PM3Config2D,
-		      PM3Config2D_UseConstantSource |
-		      PM3Config2D_ForegroundROPEnable |
-		      (PM3Config2D_ForegroundROP(0x3)) |	/* Ox3 is GXcopy */
-		      PM3Config2D_FBWriteEnable);
-	
-	if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
-		PM3_WRITE_REG(PM3ForegroundColor, c);
-	else
-		PM3_WRITE_REG(PM3FBBlockColor, c);
-	
-	
-	PM3_WRITE_REG(PM3RectanglePosition,
-		      (PM3RectanglePosition_XOffset(p->var.xoffset)) |
-		      (PM3RectanglePosition_YOffset(p->var.yoffset + sy)));
-	
-	if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
-		PM3_WRITE_REG(PM3Render2D,
-			      PM3Render2D_XPositive |
-			      PM3Render2D_YPositive |
-			      PM3Render2D_Operation_Normal |
-			      PM3Render2D_SpanOperation |
-			      (PM3Render2D_Width(p->var.xres)) |
-			      (PM3Render2D_Height(p->var.yres - sy)));
-	else
-		PM3_WRITE_REG(PM3Render2D,
-			      PM3Render2D_XPositive |
-			      PM3Render2D_YPositive |
-			      PM3Render2D_Operation_Normal |
-			      (PM3Render2D_Width(p->var.xres)) |
-			      (PM3Render2D_Height(p->var.yres - sy)));
-
-	pm3fb_wait_pm3(l_fb_info);
-}
-#endif /* FBCON_HAS_CFB16 */
-#ifdef FBCON_HAS_CFB8
-static void pm3fb_cfb8_clear(struct vc_data *conp,
-			     struct display *p,
-			     int sy, int sx, int height, int width)
-{
-	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
-	u32 c;
-
-	DTRACE;
-
-	sx = sx * fontwidth(p);
-	width = width * fontwidth(p);
-	sy = sy * fontheight(p);
-	height = height * fontheight(p);
-
-	c = attr_bgcol_ec(p, conp);
-	c |= c << 8;
-	c |= c << 16;
-
-	PM3_WAIT(4);
-
-	PM3_WRITE_REG(PM3Config2D,
-				  PM3Config2D_UseConstantSource |
-				  PM3Config2D_ForegroundROPEnable |
-				  (PM3Config2D_ForegroundROP(0x3)) |	/* Ox3 is GXcopy */
-				  PM3Config2D_FBWriteEnable);
-
-	PM3_WRITE_REG(PM3ForegroundColor, c);
-
-	PM3_WRITE_REG(PM3RectanglePosition,
-		      (PM3RectanglePosition_XOffset(sx)) |
-		      (PM3RectanglePosition_YOffset(sy)));
-
-	PM3_WRITE_REG(PM3Render2D,
-		      PM3Render2D_XPositive |
-		      PM3Render2D_YPositive |
-		      PM3Render2D_Operation_Normal |
-		      PM3Render2D_SpanOperation |
-		      (PM3Render2D_Width(width)) |
-		      (PM3Render2D_Height(height)));
-
-	pm3fb_wait_pm3(l_fb_info);
-}
-
-static void pm3fb_cfb8_clear_margins(struct vc_data *conp,
-				     struct display *p, int bottom_only)
-{
-	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
-	int sx, sy;
-	u32 c;
-
-	DTRACE;
-
-	sx = conp->vc_cols * fontwidth(p);	/* right margin */
-	sy = conp->vc_rows * fontheight(p);	/* bottom margin */
-	c = attr_bgcol_ec(p, conp);
-	c |= c << 8;
-	c |= c << 16;
-
-	if (!bottom_only) {	/* right margin top->bottom */
-		PM3_WAIT(4);
-
-		PM3_WRITE_REG(PM3Config2D,
-					  PM3Config2D_UseConstantSource |
-					  PM3Config2D_ForegroundROPEnable |
-					  (PM3Config2D_ForegroundROP(0x3)) |	/* Ox3 is GXcopy */
-					  PM3Config2D_FBWriteEnable);
-
-		PM3_WRITE_REG(PM3ForegroundColor, c);
-
-		PM3_WRITE_REG(PM3RectanglePosition,
-			      (PM3RectanglePosition_XOffset
-			       (p->var.xoffset +
-				sx)) | (PM3RectanglePosition_YOffset(p->
-								     var.
-								     yoffset)));
-
-		PM3_WRITE_REG(PM3Render2D,
-			      PM3Render2D_XPositive |
-			      PM3Render2D_YPositive |
-			      PM3Render2D_Operation_Normal |
-			      PM3Render2D_SpanOperation |
-			      (PM3Render2D_Width(p->var.xres - sx)) |
-			      (PM3Render2D_Height(p->var.yres)));
-	}
-
-	/* bottom margin left -> right */
-	PM3_WAIT(4);
-
-	PM3_WRITE_REG(PM3Config2D,
-				  PM3Config2D_UseConstantSource |
-				  PM3Config2D_ForegroundROPEnable |
-				  (PM3Config2D_ForegroundROP(0x3)) |	/* Ox3 is GXcopy */
-				  PM3Config2D_FBWriteEnable);
-
-	PM3_WRITE_REG(PM3ForegroundColor, c);
-
-	PM3_WRITE_REG(PM3RectanglePosition,
-		      (PM3RectanglePosition_XOffset(p->var.xoffset)) |
-		      (PM3RectanglePosition_YOffset(p->var.yoffset + sy)));
-
-	PM3_WRITE_REG(PM3Render2D,
-		      PM3Render2D_XPositive |
-		      PM3Render2D_YPositive |
-		      PM3Render2D_Operation_Normal |
-		      PM3Render2D_SpanOperation |
-		      (PM3Render2D_Width(p->var.xres)) |
-		      (PM3Render2D_Height(p->var.yres - sy)));
-
-	pm3fb_wait_pm3(l_fb_info);
-}
-#endif /* FBCON_HAS_CFB8 */
-#if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB32)
-static void pm3fb_cfbX_bmove(struct display *p,
-			     int sy, int sx,
-			     int dy, int dx, int height, int width)
-{
-	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
-	int x_align, o_x, o_y;
-
-	DTRACE;
-
-	sx = sx * fontwidth(p);
-	dx = dx * fontwidth(p);
-	width = width * fontwidth(p);
-	sy = sy * fontheight(p);
-	dy = dy * fontheight(p);
-	height = height * fontheight(p);
-
-	o_x = sx - dx;		/*(sx > dx ) ? (sx - dx) : (dx - sx); */
-	o_y = sy - dy;		/*(sy > dy ) ? (sy - dy) : (dy - sy); */
-
-	x_align = (sx & 0x1f);
-
-	PM3_WAIT(6);
-
-	PM3_WRITE_REG(PM3Config2D,
-				  PM3Config2D_UserScissorEnable |
-				  PM3Config2D_ForegroundROPEnable |
-				  PM3Config2D_Blocking |
-				  (PM3Config2D_ForegroundROP(0x3)) |	/* Ox3 is GXcopy */
-				  PM3Config2D_FBWriteEnable);
-
-	PM3_WRITE_REG(PM3ScissorMinXY,
-		      ((dy & 0x0fff) << 16) | (dx & 0x0fff));
-	PM3_WRITE_REG(PM3ScissorMaxXY,
-				  (((dy + height) & 0x0fff) << 16) |
-				  ((dx + width) & 0x0fff));
-
-	PM3_WRITE_REG(PM3FBSourceReadBufferOffset,
-		      PM3FBSourceReadBufferOffset_XOffset(o_x) |
-		      PM3FBSourceReadBufferOffset_YOffset(o_y));
-
-	PM3_WRITE_REG(PM3RectanglePosition,
-		      (PM3RectanglePosition_XOffset(dx - x_align)) |
-		      (PM3RectanglePosition_YOffset(dy)));
-
-	PM3_WRITE_REG(PM3Render2D,
-		      ((sx > dx) ? PM3Render2D_XPositive : 0) |
-		      ((sy > dy) ? PM3Render2D_YPositive : 0) |
-		      PM3Render2D_Operation_Normal |
-		      PM3Render2D_SpanOperation |
-		      PM3Render2D_FBSourceReadEnable |
-		      (PM3Render2D_Width(width + x_align)) |
-		      (PM3Render2D_Height(height)));
-
-	pm3fb_wait_pm3(l_fb_info);
-}
-
-static void pm3fb_cfbX_putc(struct vc_data *conp, struct display *p,
-			    int c, int yy, int xx)
-{
-	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
-	u8 *cdat, asx = 0, asy = 0, o_x = 0, o_y = 0;
-	u32 fgx, bgx, ldat;
-	int sx, sy, i;
-
-	DTRACE;
-
-	if (l_fb_info->current_par->depth == 8)
-		fgx = attr_fgcol(p, c);
-	else if (depth2bpp(l_fb_info->current_par->depth) == 16)
-		fgx = ((u16 *) p->dispsw_data)[attr_fgcol(p, c)];
-	else
-		fgx = ((u32 *) p->dispsw_data)[attr_fgcol(p, c)];
-
-	PM3_COLOR(fgx);
-
-	if (l_fb_info->current_par->depth == 8)
-		bgx = attr_bgcol(p, c);
-	else if (depth2bpp(l_fb_info->current_par->depth) == 16)
-		bgx = ((u16 *) p->dispsw_data)[attr_bgcol(p, c)];
-	else
-		bgx = ((u32 *) p->dispsw_data)[attr_bgcol(p, c)];
-
-	PM3_COLOR(bgx);
-
-	PM3_WAIT(4);
-
-	PM3_WRITE_REG(PM3Config2D,
-				  PM3Config2D_UseConstantSource |
-				  PM3Config2D_ForegroundROPEnable |
-				  (PM3Config2D_ForegroundROP(0x3)) |	/* Ox3 is GXcopy */
-				  PM3Config2D_FBWriteEnable | PM3Config2D_OpaqueSpan);
-
-	PM3_WRITE_REG(PM3ForegroundColor, fgx);
-	PM3_WRITE_REG(PM3FillBackgroundColor, bgx);
-
-	/* WARNING : address select X need to specify 8 bits for fontwidth <= 8 */
-	/* and 16 bits for fontwidth <= 16 */
-	/* same in _putcs, same for Y and fontheight */
-	if (fontwidth(p) <= 8)
-		asx = 2;
-	else if (fontwidth(p) <= 16)
-		asx = 3;	/* look OK */
-	if (fontheight(p) <= 8)
-		asy = 2;
-	else if (fontheight(p) <= 16)
-		asy = 3;	/* look OK */
-	else if (fontheight(p) <= 32)
-		asy = 4;	/* look OK */
-
-	sx = xx * fontwidth(p);
-	sy = yy * fontheight(p);
-
-	if (fontwidth(p) <= 8)
-		o_x = (8 - (sx & 0x7)) & 0x7;
-	else if (fontwidth(p) <= 16)
-		o_x = (16 - (sx & 0xF)) & 0xF;
-	if (fontheight(p) <= 8)
-		o_y = (8 - (sy & 0x7)) & 0x7;
-	else if (fontheight(p) <= 16)
-		o_y = (16 - (sy & 0xF)) & 0xF;
-	else if (fontheight(p) <= 32)
-		o_y = (32 - (sy & 0x1F)) & 0x1F;
-
-	PM3_WRITE_REG(PM3AreaStippleMode, (o_x << 7) | (o_y << 12) |	/* x_offset, y_offset in pattern */
-		      (1 << 18) |	/* BE */
-		      1 | (asx << 1) | (asy << 4) |	/* address select x/y */
-		      (1 << 20));	/* OpaqueSpan */
-
-	if (fontwidth(p) <= 8) {
-		cdat = p->fontdata + (c & p->charmask) * fontheight(p);
-	} else {
-		cdat =
-		    p->fontdata +
-		    ((c & p->charmask) * (fontheight(p) << 1));
-	}
-
-	PM3_WAIT(2 + fontheight(p));
-
-	for (i = 0; i < fontheight(p); i++) {	/* assume fontheight <= 32 */
-		if (fontwidth(p) <= 8) {
-			ldat = *cdat++;
-		} else {	/* assume fontwidth <= 16 ATM */
-
-			ldat = ((*cdat++) << 8);
-			ldat |= *cdat++;
-		}
-		PM3_WRITE_REG(AreaStipplePattern_indexed(i), ldat);
-	}
-
-	PM3_WRITE_REG(PM3RectanglePosition,
-		      (PM3RectanglePosition_XOffset(sx)) |
-		      (PM3RectanglePosition_YOffset(sy)));
-
-	PM3_WRITE_REG(PM3Render2D,
-		      PM3Render2D_AreaStippleEnable |
-		      PM3Render2D_XPositive |
-		      PM3Render2D_YPositive |
-		      PM3Render2D_Operation_Normal |
-		      PM3Render2D_SpanOperation |
-		      (PM3Render2D_Width(fontwidth(p))) |
-		      (PM3Render2D_Height(fontheight(p))));
-
-	pm3fb_wait_pm3(l_fb_info);
-}
-
-static void pm3fb_cfbX_putcs(struct vc_data *conp, struct display *p,
-			     const unsigned short *s, int count, int yy,
-			     int xx)
-{
-	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
-	u8 *cdat, asx = 0, asy = 0, o_x = 0, o_y = 0;
-	u32 fgx, bgx, ldat;
-	int sx, sy, i, j;
-	u16 sc;
-
-	DTRACE;
-
-	sc = scr_readw(s);
-	if (l_fb_info->current_par->depth == 8)
-		fgx = attr_fgcol(p, sc);
-	else if (depth2bpp(l_fb_info->current_par->depth) == 16)
-		fgx = ((u16 *) p->dispsw_data)[attr_fgcol(p, sc)];
-	else
-		fgx = ((u32 *) p->dispsw_data)[attr_fgcol(p, sc)];
-	
-	PM3_COLOR(fgx);
-	
-	if (l_fb_info->current_par->depth == 8)
-		bgx = attr_bgcol(p, sc);
-	else if (depth2bpp(l_fb_info->current_par->depth) == 16)
-		bgx = ((u16 *) p->dispsw_data)[attr_bgcol(p, sc)];
-	else
-		bgx = ((u32 *) p->dispsw_data)[attr_bgcol(p, sc)];
-	
-	PM3_COLOR(bgx);
-
-	PM3_WAIT(4);
-
-	PM3_WRITE_REG(PM3Config2D,
-				  PM3Config2D_UseConstantSource |
-				  PM3Config2D_ForegroundROPEnable |
-				  (PM3Config2D_ForegroundROP(0x3)) |	/* Ox3 is GXcopy */
-				  PM3Config2D_FBWriteEnable |
-				  PM3Config2D_OpaqueSpan);
-
-	PM3_WRITE_REG(PM3ForegroundColor, fgx);
-	PM3_WRITE_REG(PM3FillBackgroundColor, bgx);
-
-	/* WARNING : address select X need to specify 8 bits for fontwidth <= 8 */
-	/* and 16 bits for fontwidth <= 16 */
-	/* same in _putc, same for Y and fontheight */
-	if (fontwidth(p) <= 8)
-		asx = 2;
-	else if (fontwidth(p) <= 16)
-		asx = 3;	/* look OK */
-	if (fontheight(p) <= 8)
-		asy = 2;
-	else if (fontheight(p) <= 16)
-		asy = 3;	/* look OK */
-	else if (fontheight(p) <= 32)
-		asy = 4;	/* look OK */
-
-	sy = yy * fontheight(p);
-
-	if (fontheight(p) <= 8)
-		o_y = (8 - (sy & 0x7)) & 0x7;
-	else if (fontheight(p) <= 16)
-		o_y = (16 - (sy & 0xF)) & 0xF;
-	else if (fontheight(p) <= 32)
-		o_y = (32 - (sy & 0x1F)) & 0x1F;
-
-	for (j = 0; j < count; j++) {
-		sc = scr_readw(s + j);
-		if (fontwidth(p) <= 8)
-			cdat = p->fontdata +
-				(sc & p->charmask) * fontheight(p);
-		else
-			cdat = p->fontdata +
-				((sc & p->charmask) * fontheight(p) << 1);
-		
-		sx = (xx + j) * fontwidth(p);
-
-		if (fontwidth(p) <= 8)
-			o_x = (8 - (sx & 0x7)) & 0x7;
-		else if (fontwidth(p) <= 16)
-			o_x = (16 - (sx & 0xF)) & 0xF;
-
-		PM3_WAIT(3 + fontheight(p));
-
-		PM3_WRITE_REG(PM3AreaStippleMode, (o_x << 7) | (o_y << 12) | /* x_offset, y_offset in pattern */
-			      (1 << 18) | /* BE */
-			      1 | (asx << 1) | (asy << 4) | /* address select x/y */
-			      (1 << 20)); /* OpaqueSpan */
-
-		for (i = 0; i < fontheight(p); i++) { /* assume fontheight <= 32 */
-			if (fontwidth(p) <= 8) {
-				ldat = *cdat++;
-			} else { /* assume fontwidth <= 16 ATM */
-				ldat = ((*cdat++) << 8);
-				ldat |= *cdat++;
-			}
-			PM3_WRITE_REG(AreaStipplePattern_indexed(i), ldat);
-		}
-
-		PM3_WRITE_REG(PM3RectanglePosition,
-			      (PM3RectanglePosition_XOffset(sx)) |
-			      (PM3RectanglePosition_YOffset(sy)));
-
-		PM3_WRITE_REG(PM3Render2D,
-			      PM3Render2D_AreaStippleEnable |
-			      PM3Render2D_XPositive |
-			      PM3Render2D_YPositive |
-			      PM3Render2D_Operation_Normal |
-			      PM3Render2D_SpanOperation |
-			      (PM3Render2D_Width(fontwidth(p))) |
-			      (PM3Render2D_Height(fontheight(p))));
-	}
-	pm3fb_wait_pm3(l_fb_info);
-}
-
-static void pm3fb_cfbX_revc(struct display *p, int xx, int yy)
-{
-	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
-
-	xx = xx * fontwidth(p);
-	yy = yy * fontheight(p);
-
-	if (l_fb_info->current_par->depth == 8)
-	{
-		if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
-			PM3_SLOW_WRITE_REG(PM3FBSoftwareWriteMask, 0x0F0F0F0F);
-		else
-			PM3_SLOW_WRITE_REG(PM3FBHardwareWriteMask, 0x0F0F0F0F);
-	}
-
-	PM3_WAIT(3);
-
-	PM3_WRITE_REG(PM3Config2D,
-				  PM3Config2D_UseConstantSource |
-				  PM3Config2D_ForegroundROPEnable |
-				  (PM3Config2D_ForegroundROP(0xa)) |	/* Oxa is GXinvert */
-				  PM3Config2D_FBDestReadEnable |
-				  PM3Config2D_FBWriteEnable);
-
-	PM3_WRITE_REG(PM3RectanglePosition,
-		      (PM3RectanglePosition_XOffset(xx)) |
-		      (PM3RectanglePosition_YOffset(yy)));
-
-	PM3_WRITE_REG(PM3Render2D,
-		      PM3Render2D_XPositive |
-		      PM3Render2D_YPositive |
-		      PM3Render2D_Operation_Normal |
-		      PM3Render2D_SpanOperation |
-		      (PM3Render2D_Width(fontwidth(p))) |
-		      (PM3Render2D_Height(fontheight(p))));
-
-	pm3fb_wait_pm3(l_fb_info);
-
-	if (l_fb_info->current_par->depth == 8)
-	{
-		if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
-			PM3_SLOW_WRITE_REG(PM3FBSoftwareWriteMask, 0xFFFFFFFF);
-		else
-			PM3_SLOW_WRITE_REG(PM3FBHardwareWriteMask, 0xFFFFFFFF);
-	}
-}
-
-#endif /* FBCON_HAS_CFB8 || FBCON_HAS_CFB16 || FBCON_HAS_CFB32 */
-#endif /* PM3FB_USE_ACCEL */
-/* *********************************** */
-/* ***** pre-init board(s) setup ***** */
-/* *********************************** */
-
-static void pm3fb_mode_setup(char *mode, unsigned long board_num)
-{
-	struct pm3fb_info *l_fb_info = &(fb_info[board_num]);
-	struct pm3fb_par *l_fb_par = &(current_par[board_num]);
-	unsigned long i = 0;
-
-	current_par_valid[board_num] = 0;
-
-	if (!strncmp(mode, "current", 7)) {
-		l_fb_info->use_current = 1;	/* default w/ OpenFirmware */
-	} else {
-		while ((mode_base[i].name[0])
-		       && (!current_par_valid[board_num])) {
-			if (!
-			    (strncmp
-			     (mode, mode_base[i].name,
-			      strlen(mode_base[i].name)))) {
-				memcpy(l_fb_par, &(mode_base[i].user_mode),
-				       sizeof(struct pm3fb_par));
-				current_par_valid[board_num] = 1;
-				DPRINTK(2, "Mode set to %s\n",
-					mode_base[i].name);
-			}
-			i++;
-		}
-		DASSERT(current_par_valid[board_num],
-			"Valid mode on command line\n");
-	}
-}
-
-static void pm3fb_pciid_setup(char *pciid, unsigned long board_num)
-{
-	short l_bus = -1, l_slot = -1, l_func = -1;
-	char *next;
-
-	if (pciid) {
-		l_bus = simple_strtoul(pciid, &next, 10);
-		if (next && (next[0] == ':')) {
-			pciid = next + 1;
-			l_slot = simple_strtoul(pciid, &next, 10);
-			if (next && (next[0] == ':')) {
-				pciid = next + 1;
-				l_func =
-				    simple_strtoul(pciid, (char **) NULL,
-						   10);
-			}
-		}
-	} else
-		return;
-
-	if ((l_bus >= 0) && (l_slot >= 0) && (l_func >= 0)) {
-		bus[board_num] = l_bus;
-		slot[board_num] = l_slot;
-		func[board_num] = l_func;
-		DPRINTK(2, "Board #%ld will be PciId: %hd:%hd:%hd\n",
-			board_num, l_bus, l_slot, l_func);
-	} else {
-		DPRINTK(1, "Invalid PciId: %hd:%hd:%hd for board #%ld\n",
-			l_bus, l_slot, l_func, board_num);
-	}
-}
-
-static void pm3fb_font_setup(char *lf, unsigned long board_num)
-{
-	unsigned long lfs = strlen(lf);
-
-	if (lfs > (PM3_FONTNAME_SIZE - 1)) {
-		DPRINTK(1, "Fontname %s too long\n", lf);
-		return;
-	}
-	strlcpy(fontn[board_num], lf, lfs + 1);
-}
-
-static void pm3fb_bootdepth_setup(char *bds, unsigned long board_num)
-{
-	unsigned long bd = simple_strtoul(bds, (char **) NULL, 10);
-
-	if (!(depth_supported(bd))) {
-		printk(KERN_WARNING "pm3fb: ignoring invalid depth %s for board #%ld\n",
-		       bds, board_num);
-		return;
-	}
-	depth[board_num] = bd;
-}
-
-static void pm3fb_forcesize_setup(char *bds, unsigned long board_num)
-{
-	unsigned long bd = simple_strtoul(bds, (char **) NULL, 10);
-
-	if (bd > 64) {
-		printk(KERN_WARNING "pm3fb: ignoring invalid memory size %s for board #%ld\n",
-		       bds, board_num);
-		return;
-	}
-	forcesize[board_num] = bd;
-}
-
-static char *pm3fb_boardnum_setup(char *options, unsigned long *bn)
-{
-	char *next;
-
-	if (!(isdigit(options[0]))) {
-		(*bn) = 0;
-		return (options);
-	}
-
-	(*bn) = simple_strtoul(options, &next, 10);
-
-	if (next && (next[0] == ':') && ((*bn) >= 0)
-	    && ((*bn) <= PM3_MAX_BOARD)) {
-		DPRINTK(2, "Board_num seen as %ld\n", (*bn));
-		return (next + 1);
-	} else {
-		(*bn) = 0;
-		DPRINTK(2, "Board_num default to %ld\n", (*bn));
-		return (options);
-	}
-}
-
-static void pm3fb_real_setup(char *options)
-{
-	char *next;
-	unsigned long i, bn;
-	struct pm3fb_info *l_fb_info;
-
-	DTRACE;
-
-	DPRINTK(2, "Options : %s\n", options);
-
-	for (i = 0; i < PM3_MAX_BOARD; i++) {
-		l_fb_info = &(fb_info[i]);
-		memset(l_fb_info, 0, sizeof(struct pm3fb_info));
-		l_fb_info->gen.fbhw = &pm3fb_switch;
-		l_fb_info->board_num = i;
-		current_par_valid[i] = 0;
-		slot[i] = -1;
-		func[i] = -1;
-		bus[i] = -1;
-		disable[i] = 0;
-		noaccel[i] = 0;
-		fontn[i][0] = '\0';
-		depth[i] = 0;
-		l_fb_info->current_par = &(current_par[i]);
-	}
-
-	/* eat up prefix pm3fb and whatever is used as separator i.e. :,= */
-	if (!strncmp(options, "pm3fb", 5)) {
-		options += 5;
-		while (((*options) == ',') || ((*options) == ':')
-		       || ((*options) == '='))
-			options++;
-	}
-
-	while (options) {
-		bn = 0;
-		if ((next = strchr(options, ','))) {
-			(*next) = '\0';
-			next++;
-		}
-
-		if (!strncmp(options, "mode:", 5)) {
-			options = pm3fb_boardnum_setup(options + 5, &bn);
-			DPRINTK(2, "Setting mode for board #%ld\n", bn);
-			pm3fb_mode_setup(options, bn);
-		} else if (!strncmp(options, "off:", 4)) {
-			options = pm3fb_boardnum_setup(options + 4, &bn);
-			DPRINTK(2, "Disabling board #%ld\n", bn);
-			disable[bn] = 1;
-		} else if (!strncmp(options, "off", 3)) {	/* disable everything */
-			for (i = 0; i < PM3_MAX_BOARD; i++)
-				disable[i] = 1;
-		} else if (!strncmp(options, "disable:", 8)) {
-			options = pm3fb_boardnum_setup(options + 8, &bn);
-			DPRINTK(2, "Disabling board #%ld\n", bn);
-			disable[bn] = 1;
-		} else if (!strncmp(options, "pciid:", 6)) {
-			options = pm3fb_boardnum_setup(options + 6, &bn);
-			DPRINTK(2, "Setting PciID for board #%ld\n", bn);
-			pm3fb_pciid_setup(options, bn);
-		} else if (!strncmp(options, "noaccel:", 8)) {
-			options = pm3fb_boardnum_setup(options + 8, &bn);
-			noaccel[bn] = 1;
-		} else if (!strncmp(options, "font:", 5)) {
-			options = pm3fb_boardnum_setup(options + 5, &bn);
-			pm3fb_font_setup(options, bn);
-		} else if (!strncmp(options, "depth:", 6)) {
-			options = pm3fb_boardnum_setup(options + 6, &bn);
-			pm3fb_bootdepth_setup(options, bn);
-		} else if (!strncmp(options, "printtimings", 12)) {
-			printtimings = 1;
-		} else if (!strncmp(options, "flatpanel:", 10)) {
-			options = pm3fb_boardnum_setup(options + 10, &bn);
-			flatpanel[bn] = 1;
-		} else if (!strncmp(options, "forcesize:", 10)) {
-			options = pm3fb_boardnum_setup(options + 10, &bn);
-			pm3fb_forcesize_setup(options, bn);
-		}
-		options = next;
-	}
-}
-
-/* ********************************************** */
-/* ***** framebuffer API standard functions ***** */
-/* ********************************************** */
-
-static int pm3fb_encode_fix(struct fb_fix_screeninfo *fix,
-			    const void *par, struct fb_info_gen *info)
-{
-	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
-	struct pm3fb_par *p = (struct pm3fb_par *) par;
-
-	DTRACE;
-
-	strcpy(fix->id, permedia3_name);
-	fix->smem_start = (unsigned long)l_fb_info->p_fb;
-	fix->smem_len = l_fb_info->fb_size;
-	fix->mmio_start = (unsigned long)l_fb_info->pIOBase;
-	fix->mmio_len = PM3_REGS_SIZE;
-#ifdef PM3FB_USE_ACCEL
-	if (!(noaccel[l_fb_info->board_num]))
-		fix->accel = FB_ACCEL_3DLABS_PERMEDIA3;
-	else
-#endif /* PM3FB_USE_ACCEL */
-		fix->accel = FB_ACCEL_NONE;
-	fix->type = FB_TYPE_PACKED_PIXELS;
-	fix->visual =
-	    (p->depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
-	if (current_par_valid[l_fb_info->board_num])
-		fix->line_length =
-			l_fb_info->current_par->width *
-			depth2ByPP(l_fb_info->current_par->depth);
-	else
-		fix->line_length = 0;
-	fix->xpanstep = 64 / depth2bpp(p->depth);
-	fix->ypanstep = 1;
-	fix->ywrapstep = 0;
-	return (0);
-}
-
-static int pm3fb_decode_var(const struct fb_var_screeninfo *var,
-			    void *par, struct fb_info_gen *info)
-{
-	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
-	struct pm3fb_par *p = (struct pm3fb_par *) par;
-	struct pm3fb_par temp_p;
-	u32 xres;
-
-	DTRACE;
-
-	DASSERT((var != NULL), "fb_var_screeninfo* not NULL");
-	DASSERT((p != NULL), "pm3fb_par* not NULL");
-	DASSERT((l_fb_info != NULL), "pm3fb_info* not NULL");
-
-	memset(&temp_p, 0, sizeof(struct pm3fb_par));
-	temp_p.width = (var->xres_virtual + 7) & ~7;
-	temp_p.height = var->yres_virtual;
-
-	if (!(depth_supported(var->bits_per_pixel))) /* round unsupported up to a multiple of 8 */
-		temp_p.depth = depth2bpp(var->bits_per_pixel);
-	else
-		temp_p.depth = var->bits_per_pixel;
-
-	temp_p.depth = (temp_p.depth > 32) ? 32 : temp_p.depth; /* max 32 */
-	temp_p.depth = (temp_p.depth == 24) ? 32 : temp_p.depth; /* 24 unsupported, round-up to 32 */
-
-	if ((temp_p.depth == 16) && (var->red.length == 5) && (var->green.length == 5) && (var->blue.length == 5))
-		temp_p.depth = 15; /* RGBA 5551 is stored as depth 15 */
-
-	if ((temp_p.depth == 16) && (var->red.length == 4) && (var->green.length == 4) && (var->blue.length == 4))
-		temp_p.depth = 12; /* RGBA 4444  is stored as depth 12 */
-
-
-	DPRINTK(2,
-		"xres: %d, yres: %d, vxres: %d, vyres: %d ; xoffset:%d, yoffset: %d\n",
-		var->xres, var->yres, var->xres_virtual, var->yres_virtual,
-		var->xoffset, var->yoffset);
-
-	xres = (var->xres + 31) & ~31;
-	if (temp_p.width < xres + var->xoffset)
-		temp_p.width = xres + var->xoffset;
-	if (temp_p.height < var->yres + var->yoffset)
-		temp_p.height = var->yres + var->yoffset;
-
-	if (temp_p.width > 2048) {
-		DPRINTK(1, "virtual width not supported: %u\n",
-			temp_p.width);
-		return (-EINVAL);
-	}
-	if (var->yres < 200) {
-		DPRINTK(1, "height not supported: %u\n", (u32) var->yres);
-		return (-EINVAL);
-	}
-	if (temp_p.height < 200 || temp_p.height > 4095) {
-		DPRINTK(1, "virtual height not supported: %u\n",
-			temp_p.height);
-		return (-EINVAL);
-	}
-	if (!(depth_supported(temp_p.depth))) {
-		DPRINTK(1, "depth not supported: %u\n", temp_p.depth);
-		return (-EINVAL);
-	}
-	if ((temp_p.width * temp_p.height * depth2ByPP(temp_p.depth)) >
-	    l_fb_info->fb_size) {
-		DPRINTK(1, "no memory for screen (%ux%ux%u)\n",
-			temp_p.width, temp_p.height, temp_p.depth);
-		return (-EINVAL);
-	}
-
-	if ((!var->pixclock) ||
-	    (!var->right_margin) ||
-	    (!var->hsync_len) ||
-	    (!var->left_margin) ||
-	    (!var->lower_margin) ||
-	    (!var->vsync_len) || (!var->upper_margin)
-	    ) {
-		unsigned long i = 0, done = 0;
-		printk(KERN_WARNING "pm3fb: refusing to use a likely wrong timing\n");
-
-		while ((mode_base[i].user_mode.width) && !done) {
-			if ((mode_base[i].user_mode.width == temp_p.width)
-			    && (mode_base[i].user_mode.height ==
-				temp_p.height)) {
-				printk(KERN_NOTICE "pm3fb: using close match %s\n",
-				       mode_base[i].name);
-				temp_p = mode_base[i].user_mode;
-				done = 1;
-			}
-			i++;
-		}
-		if (!done)
-			return (-EINVAL);
-	} else {
-		temp_p.pixclock = PICOS2KHZ(var->pixclock);
-		if (temp_p.pixclock > PM3_MAX_PIXCLOCK) {
-			DPRINTK(1, "pixclock too high (%uKHz)\n",
-				temp_p.pixclock);
-			return (-EINVAL);
-		}
-
-		temp_p.hsstart = var->right_margin;
-		temp_p.hsend = var->right_margin + var->hsync_len;
-		temp_p.hbend =
-		    var->right_margin + var->hsync_len + var->left_margin;
-		temp_p.htotal = xres + temp_p.hbend;
-
-		temp_p.vsstart = var->lower_margin;
-		temp_p.vsend = var->lower_margin + var->vsync_len;
-		temp_p.vbend =
-		    var->lower_margin + var->vsync_len + var->upper_margin;
-		temp_p.vtotal = var->yres + temp_p.vbend;
-
-		temp_p.stride = temp_p.width;
-
-		DPRINTK(2, "Using %d * %d, %d Khz, stride is %08x\n",
-			temp_p.width, temp_p.height, temp_p.pixclock,
-			temp_p.stride);
-
-		temp_p.base =
-		    pm3fb_Shiftbpp(l_fb_info, temp_p.depth,
-				   (var->yoffset * xres) + var->xoffset);
-
-		temp_p.video = 0;
-
-		if (var->sync & FB_SYNC_HOR_HIGH_ACT)
-			temp_p.video |= PM3VideoControl_HSYNC_ACTIVE_HIGH;
-		else
-			temp_p.video |= PM3VideoControl_HSYNC_ACTIVE_LOW;
-
-		if (var->sync & FB_SYNC_VERT_HIGH_ACT)
-			temp_p.video |= PM3VideoControl_VSYNC_ACTIVE_HIGH;
-		else
-			temp_p.video |= PM3VideoControl_VSYNC_ACTIVE_LOW;
-
-		if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
-			DPRINTK(1, "Interlaced mode not supported\n\n");
-			return (-EINVAL);
-		}
-
-		if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE)
-			temp_p.video |= PM3VideoControl_LINE_DOUBLE_ON;
-		else
-			temp_p.video |= PM3VideoControl_LINE_DOUBLE_OFF;
-
-		if (var->activate == FB_ACTIVATE_NOW)
-			temp_p.video |= PM3VideoControl_ENABLE;
-		else {
-			temp_p.video |= PM3VideoControl_DISABLE;
-			DPRINTK(2, "PM3Video disabled\n");
-		}
-
-		switch (temp_p.depth) {
-		case 8:
-			temp_p.video |= PM3VideoControl_PIXELSIZE_8BIT;
-			break;
-		case 12:
-		case 15:
-		case 16:
-			temp_p.video |= PM3VideoControl_PIXELSIZE_16BIT;
-			break;
-		case 32:
-			temp_p.video |= PM3VideoControl_PIXELSIZE_32BIT;
-			break;
-		default:
-			DPRINTK(1, "Unsupported depth\n");
-			break;
-		}
-	}
-	(*p) = temp_p;
-
-#ifdef PM3FB_USE_ACCEL
-	if (var->accel_flags & FB_ACCELF_TEXT)
-		noaccel[l_fb_info->board_num] = 0;
-	else
-		noaccel[l_fb_info->board_num] = 1;
-#endif /* PM3FB_USE_ACCEL */
-
-	return (0);
-}
-
-static void pm3fb_encode_depth(struct fb_var_screeninfo *var, long d)
-{
-	switch (d) {
+	var->transp.offset = 0;
+	var->transp.length = 0;
+	switch(var->bits_per_pixel) {
 	case 8:
 		var->red.length = var->green.length = var->blue.length = 8;
 		var->red.offset = var->green.offset = var->blue.offset = 0;
-		var->transp.offset = var->transp.length = 0;
 		break;
-
 	case 12:
-		var->red.offset = 8;
-		var->red.length = 4;
+		var->red.offset   = 8;
+		var->red.length   = 4;
 		var->green.offset = 4;
 		var->green.length = 4;
-		var->blue.offset = 0;
-		var->blue.length = 4;
+		var->blue.offset  = 0;
+		var->blue.length  = 4;
 		var->transp.offset = 12;
 		var->transp.length = 4;
-		break;
-
 	case 15:
-		var->red.offset = 10;
-		var->red.length = 5;
+		var->red.offset   = 10;
+		var->red.length   = 5;
 		var->green.offset = 5;
 		var->green.length = 5;
-		var->blue.offset = 0;
-		var->blue.length = 5;
+		var->blue.offset  = 0;
+		var->blue.length  = 5;
 		var->transp.offset = 15;
 		var->transp.length = 1;
 		break;
-
 	case 16:
-		var->red.offset = 11;
-		var->red.length = 5;
+		var->red.offset   = 11;
+		var->red.length   = 5;
 		var->green.offset = 5;
 		var->green.length = 6;
-		var->blue.offset = 0;
-		var->blue.length = 5;
-		var->transp.offset = var->transp.length = 0;
+		var->blue.offset  = 0;
+		var->blue.length  = 5;
 		break;
-
 	case 32:
 		var->transp.offset = 24;
-		var->red.offset = 16;
+		var->transp.length = 8;
+		var->red.offset	  = 16;
 		var->green.offset = 8;
-		var->blue.offset = 0;
-		var->red.length = var->green.length =
-			var->blue.length = var->transp.length = 8;
+		var->blue.offset  = 0;
+		var->red.length = var->green.length = var->blue.length = 8;
 		break;
-
 	default:
-		DPRINTK(1, "Unsupported depth %ld\n", d);
-		break;
+		DPRINTK("depth not supported: %u\n", var->bits_per_pixel);
+		return -EINVAL;
 	}
-}
-
-static int pm3fb_encode_var(struct fb_var_screeninfo *var,
-			    const void *par, struct fb_info_gen *info)
-{
-	struct pm3fb_par *p = (struct pm3fb_par *) par;
-	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
-
-	u32 base;
-
-	DTRACE;
-
-	DASSERT((var != NULL), "fb_var_screeninfo* not NULL");
-	DASSERT((p != NULL), "pm3fb_par* not NULL");
-	DASSERT((info != NULL), "fb_info_gen* not NULL");
-
-	memset(var, 0, sizeof(struct fb_var_screeninfo));
-
-#ifdef PM3FB_USE_ACCEL
-	if (!(noaccel[l_fb_info->board_num]))
-		var->accel_flags |= FB_ACCELF_TEXT;
-#endif /* PM3FB_USE_ACCEL */
-
-	var->xres_virtual = p->width;
-	var->yres_virtual = p->height;
-	var->xres = p->htotal - p->hbend;
-	var->yres = p->vtotal - p->vbend;
-
-	DPRINTK(2, "xres = %d, yres : %d\n", var->xres, var->yres);
-
-	var->right_margin = p->hsstart;
-	var->hsync_len = p->hsend - p->hsstart;
-	var->left_margin = p->hbend - p->hsend;
-	var->lower_margin = p->vsstart;
-	var->vsync_len = p->vsend - p->vsstart;
-	var->upper_margin = p->vbend - p->vsend;
-	var->bits_per_pixel = depth2bpp(p->depth);
-	
-	pm3fb_encode_depth(var, p->depth);
-
-	base = pm3fb_Unshiftbpp(l_fb_info, p->depth, p->base);
-
-	var->xoffset = base % var->xres;
-	var->yoffset = base / var->xres;
-
 	var->height = var->width = -1;
 
-	var->pixclock = KHZ2PICOS(p->pixclock);
-
-	if ((p->video & PM3VideoControl_HSYNC_MASK) ==
-	    PM3VideoControl_HSYNC_ACTIVE_HIGH)
-		var->sync |= FB_SYNC_HOR_HIGH_ACT;
-	if ((p->video & PM3VideoControl_VSYNC_MASK) ==
-	    PM3VideoControl_VSYNC_ACTIVE_HIGH)
-		var->sync |= FB_SYNC_VERT_HIGH_ACT;
-	if (p->video & PM3VideoControl_LINE_DOUBLE_ON)
-		var->vmode = FB_VMODE_DOUBLE;
-
-	return (0);
-}
-
-static void pm3fb_get_par(void *par, struct fb_info_gen *info)
-{
-	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
-
-	DTRACE;
-
-	if (!current_par_valid[l_fb_info->board_num]) {
-		if (l_fb_info->use_current)
-			pm3fb_read_mode(l_fb_info, l_fb_info->current_par);
-		else
-			memcpy(l_fb_info->current_par,
-			       &(mode_base[0].user_mode),
-			       sizeof(struct pm3fb_par));
-		current_par_valid[l_fb_info->board_num] = 1;
+	if (var->xres != var->xres_virtual) {
+		DPRINTK("virtual x resolution != physical x resolution not supported\n");
+		return -EINVAL;
 	}
-	*((struct pm3fb_par *) par) = *(l_fb_info->current_par);
-}
 
-static void pm3fb_set_par(const void *par, struct fb_info_gen *info)
-{
-	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
-
-	DTRACE;
-
-	*(l_fb_info->current_par) = *((struct pm3fb_par *) par);
-	current_par_valid[l_fb_info->board_num] = 1;
-
-	pm3fb_write_mode(l_fb_info);
-
-#ifdef PM3FB_USE_ACCEL
-	pm3fb_init_engine(l_fb_info);
-#endif /* PM3FB_USE_ACCEL */
-}
-
-static void pm3fb_set_color(struct pm3fb_info *l_fb_info,
-			    unsigned char regno, unsigned char r,
-			    unsigned char g, unsigned char b)
-{
-	DTRACE;
-
-	PM3_SLOW_WRITE_REG(PM3RD_PaletteWriteAddress, regno);
-	PM3_SLOW_WRITE_REG(PM3RD_PaletteData, r);
-	PM3_SLOW_WRITE_REG(PM3RD_PaletteData, g);
-	PM3_SLOW_WRITE_REG(PM3RD_PaletteData, b);
-}
-
-static int pm3fb_getcolreg(unsigned regno, unsigned *red, unsigned *green,
-			   unsigned *blue, unsigned *transp,
-			   struct fb_info *info)
-{
-	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
-
-	DTRACE;
-
-	if (regno < 256) {
-		*red =
-		    l_fb_info->palette[regno].red << 8 | l_fb_info->
-		    palette[regno].red;
-		*green =
-		    l_fb_info->palette[regno].green << 8 | l_fb_info->
-		    palette[regno].green;
-		*blue =
-		    l_fb_info->palette[regno].blue << 8 | l_fb_info->
-		    palette[regno].blue;
-		*transp =
-		    l_fb_info->palette[regno].transp << 8 | l_fb_info->
-		    palette[regno].transp;
+	if (var->yres > var->yres_virtual) {
+		DPRINTK("virtual y resolution < physical y resolution not possible\n");
+		return -EINVAL;
 	}
-	return (regno > 255);
+
+	if (var->xoffset) {
+		DPRINTK("xoffset not supported\n");
+		return -EINVAL;
+	}
+
+	if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
+		DPRINTK("interlace not supported\n");
+		return -EINVAL;
+	}
+
+	var->xres = (var->xres + 31) & ~31; /* could sometimes be 8 */
+	lpitch = var->xres * ((var->bits_per_pixel + 7)>>3);
+
+	if (var->xres < 200 || var->xres > 2048) {
+		DPRINTK("width not supported: %u\n", var->xres);
+		return -EINVAL;
+	}
+
+	if (var->yres < 200 || var->yres > 4095) {
+		DPRINTK("height not supported: %u\n", var->yres);
+		return -EINVAL;
+	}
+
+	if (lpitch * var->yres_virtual > info->fix.smem_len) {
+		DPRINTK("no memory for screen (%ux%ux%u)\n",
+			var->xres, var->yres_virtual, var->bits_per_pixel);
+		return -EINVAL;
+	}
+
+	if (PICOS2KHZ(var->pixclock) > PM3_MAX_PIXCLOCK) {
+		DPRINTK("pixclock too high (%ldKHz)\n", PICOS2KHZ(var->pixclock));
+		return -EINVAL;
+	}
+
+	var->accel_flags = 0;	/* Can't mmap if this is on */
+
+	DPRINTK("Checking graphics mode at %dx%d depth %d\n",
+		var->xres, var->yres, var->bits_per_pixel);
+	return 0;
+}
+
+static int pm3fb_set_par(struct fb_info *info)
+{
+	struct pm3_par *par = info->par;
+	const u32 xres = (info->var.xres + 31) & ~31;
+	const int depth = (info->var.bits_per_pixel + 7) & ~7;
+
+	par->base = pm3fb_shift_bpp(info->var.bits_per_pixel,
+					(info->var.yoffset * xres)
+					+ info->var.xoffset);
+	par->video = 0;
+
+	if (info->var.sync & FB_SYNC_HOR_HIGH_ACT)
+		par->video |= PM3VideoControl_HSYNC_ACTIVE_HIGH;
+	else
+		par->video |= PM3VideoControl_HSYNC_ACTIVE_LOW;
+
+	if (info->var.sync & FB_SYNC_VERT_HIGH_ACT)
+		par->video |= PM3VideoControl_VSYNC_ACTIVE_HIGH;
+	else
+		par->video |= PM3VideoControl_VSYNC_ACTIVE_LOW;
+
+	if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE)
+		par->video |= PM3VideoControl_LINE_DOUBLE_ON;
+	else
+		par->video |= PM3VideoControl_LINE_DOUBLE_OFF;
+
+	if (info->var.activate == FB_ACTIVATE_NOW)
+		par->video |= PM3VideoControl_ENABLE;
+	else {
+		par->video |= PM3VideoControl_DISABLE;
+		DPRINTK("PM3Video disabled\n");
+	}
+	switch (depth) {
+	case 8:
+		par->video |= PM3VideoControl_PIXELSIZE_8BIT;
+		break;
+	case 12:
+	case 15:
+	case 16:
+		par->video |= PM3VideoControl_PIXELSIZE_16BIT;
+		break;
+	case 32:
+		par->video |= PM3VideoControl_PIXELSIZE_32BIT;
+		break;
+	default:
+		DPRINTK("Unsupported depth\n");
+		break;
+	}
+
+	info->fix.visual =
+		(depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
+	info->fix.line_length = ((info->var.xres_virtual + 7)  & ~7)
+					* depth / 8;
+
+/*	pm3fb_clear_memory(info, 0);*/
+	pm3fb_clear_colormap(par, 0, 0, 0);
+	PM3_WRITE_DAC_REG(par, PM3RD_CursorMode,
+			  PM3RD_CursorMode_CURSOR_DISABLE);
+	pm3fb_write_mode(info);
+	return 0;
 }
 
 static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green,
 			   unsigned blue, unsigned transp,
 			   struct fb_info *info)
 {
-	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
+	struct pm3_par *par = info->par;
 
-	DTRACE;
+	if (regno >= 256)  /* no. of hw registers */
+	   return -EINVAL;
 
-	if (regno < 16) {
-		switch (l_fb_info->current_par->depth) {
-#ifdef FBCON_HAS_CFB8
+	/* grayscale works only partially under directcolor */
+	if (info->var.grayscale) {
+	   /* grayscale = 0.30*R + 0.59*G + 0.11*B */
+	   red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
+	}
+
+	/* Directcolor:
+	 *   var->{color}.offset contains start of bitfield
+	 *   var->{color}.length contains length of bitfield
+	 *   {hardwarespecific} contains width of DAC
+	 *   pseudo_palette[X] is programmed to (X << red.offset) |
+	 *				      (X << green.offset) |
+	 *				      (X << blue.offset)
+	 *   RAMDAC[X] is programmed to (red, green, blue)
+	 *   color depth = SUM(var->{color}.length)
+	 *
+	 * Pseudocolor:
+	 *	var->{color}.offset is 0
+	 *	var->{color}.length contains width of DAC or the number of unique
+	 *			colors available (color depth)
+	 *	pseudo_palette is not used
+	 *	RAMDAC[X] is programmed to (red, green, blue)
+	 *	color depth = var->{color}.length
+	 */
+
+	/*
+	 * This is the point where the color is converted to something that
+	 * is acceptable by the hardware.
+	 */
+#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
+	red = CNVT_TOHW(red, info->var.red.length);
+	green = CNVT_TOHW(green, info->var.green.length);
+	blue = CNVT_TOHW(blue, info->var.blue.length);
+	transp = CNVT_TOHW(transp, info->var.transp.length);
+#undef CNVT_TOHW
+
+	if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
+	info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
+		u32 v;
+
+		if (regno >= 16)
+			return -EINVAL;
+
+		v = (red << info->var.red.offset) |
+			(green << info->var.green.offset) |
+			(blue << info->var.blue.offset) |
+			(transp << info->var.transp.offset);
+
+		switch (info->var.bits_per_pixel) {
 		case 8:
 			break;
-#endif
-#ifdef FBCON_HAS_CFB16
-		case 12:
-			l_fb_info->cmap.cmap12[regno] =
-				(((u32) red & 0xf000) >> 4) |
-				(((u32) green & 0xf000) >> 8) |
-				(((u32) blue & 0xf000) >> 12);
-			break;
-
-		case 15:
-			l_fb_info->cmap.cmap15[regno] =
-				(((u32) red & 0xf800) >> 1) |
-				(((u32) green & 0xf800) >> 6) |
-				(((u32) blue & 0xf800) >> 11);
-			break;
-
 		case 16:
-			l_fb_info->cmap.cmap16[regno] =
-			    ((u32) red & 0xf800) |
-			    (((u32) green & 0xfc00) >> 5) |
-			    (((u32) blue & 0xf800) >> 11);
-			break;
-#endif
-#ifdef FBCON_HAS_CFB32
+		case 24:
 		case 32:
-			l_fb_info->cmap.cmap32[regno] =
-			    (((u32) transp & 0xff00) << 16) |
-			    (((u32) red & 0xff00) << 8) |
-			    (((u32) green & 0xff00)) |
-			    (((u32) blue & 0xff00) >> 8);
-			break;
-#endif
-		default:
-			DPRINTK(1, "bad depth %u\n",
-				l_fb_info->current_par->depth);
+			((u32*)(info->pseudo_palette))[regno] = v;
 			break;
 		}
+		return 0;
 	}
-	if (regno < 256) {
-		l_fb_info->palette[regno].red = red >> 8;
-		l_fb_info->palette[regno].green = green >> 8;
-		l_fb_info->palette[regno].blue = blue >> 8;
-		l_fb_info->palette[regno].transp = transp >> 8;
-		if (l_fb_info->current_par->depth == 8)
-			pm3fb_set_color(l_fb_info, regno, red >> 8,
-					green >> 8, blue >> 8);
-	}
-	return (regno > 255);
+	else if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR)
+		pm3fb_set_color(par, regno, red, green, blue);
+
+	return 0;
 }
 
-static int pm3fb_blank(int blank_mode, struct fb_info_gen *info)
+static int pm3fb_pan_display(struct fb_var_screeninfo *var,
+				 struct fb_info *info)
 {
-	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
-	u32 video;
+	struct pm3_par *par = info->par;
+	const u32 xres = (var->xres + 31) & ~31;
 
-	DTRACE;
+	par->base = pm3fb_shift_bpp(var->bits_per_pixel,
+					(var->yoffset * xres)
+					+ var->xoffset);
+	PM3_SLOW_WRITE_REG(par, PM3ScreenBase, par->base);
+	return 0;
+}
 
-	if (!current_par_valid[l_fb_info->board_num])
-		return (1);
-
-	video = l_fb_info->current_par->video;
+static int pm3fb_blank(int blank_mode, struct fb_info *info)
+{
+	struct pm3_par *par = info->par;
+	u32 video = par->video;
 
 	/*
 	 * Oxygen VX1 - it appears that setting PM3VideoControl and
@@ -3181,454 +663,345 @@
 	video |= PM3VideoControl_HSYNC_ACTIVE_HIGH |
 		 PM3VideoControl_VSYNC_ACTIVE_HIGH;
 
-	if (blank_mode > 0) {
-		switch (blank_mode - 1) {
-
-		case VESA_NO_BLANKING:	/* FIXME */
-			video = video & ~(PM3VideoControl_ENABLE);
-			break;
-
-		case VESA_HSYNC_SUSPEND:
-			video = video & ~(PM3VideoControl_HSYNC_MASK |
-					  PM3VideoControl_BLANK_ACTIVE_LOW);
-			break;
-		case VESA_VSYNC_SUSPEND:
-			video = video & ~(PM3VideoControl_VSYNC_MASK |
-					  PM3VideoControl_BLANK_ACTIVE_LOW);
-			break;
-		case VESA_POWERDOWN:
-			video = video & ~(PM3VideoControl_HSYNC_MASK |
-					  PM3VideoControl_VSYNC_MASK |
-					  PM3VideoControl_BLANK_ACTIVE_LOW);
-			break;
-		default:
-			DPRINTK(1, "Unsupported blanking %d\n",
-				blank_mode);
-			return (1);
-			break;
-		}
-	}
-
-	PM3_SLOW_WRITE_REG(PM3VideoControl, video);
-
-	return (0);
-}
-
-static void pm3fb_set_disp(const void *par, struct display *disp,
-			   struct fb_info_gen *info)
-{
-	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
-	struct pm3fb_par *p = (struct pm3fb_par *) par;
-	u32 flags;
-
-	DTRACE;
-
-	local_irq_save(flags);
-	info->info.screen_base = l_fb_info->v_fb;
-	switch (p->depth) {
-#ifdef FBCON_HAS_CFB8
-	case 8:
-#ifdef PM3FB_USE_ACCEL
-		if (!(noaccel[l_fb_info->board_num]))
-			disp->dispsw = &pm3fb_cfb8;
-		else
-#endif /* PM3FB_USE_ACCEL */
-			disp->dispsw = &fbcon_cfb8;
+	switch (blank_mode) {
+	case FB_BLANK_UNBLANK:
+		video = video | PM3VideoControl_ENABLE;
 		break;
-#endif
-#ifdef FBCON_HAS_CFB16
-	case 12:
-#ifdef PM3FB_USE_ACCEL
-		if (!(noaccel[l_fb_info->board_num]))
-			disp->dispsw = &pm3fb_cfb16;
-		else
-#endif /* PM3FB_USE_ACCEL */
-			disp->dispsw = &fbcon_cfb16;
-		disp->dispsw_data = l_fb_info->cmap.cmap12;
+	case FB_BLANK_NORMAL:	/* FIXME */
+		video = video & ~(PM3VideoControl_ENABLE);
 		break;
-	case 15:
-#ifdef PM3FB_USE_ACCEL
-		if (!(noaccel[l_fb_info->board_num]))
-			disp->dispsw = &pm3fb_cfb16;
-		else
-#endif /* PM3FB_USE_ACCEL */
-			disp->dispsw = &fbcon_cfb16;
-		disp->dispsw_data = l_fb_info->cmap.cmap15;
+	case FB_BLANK_HSYNC_SUSPEND:
+		video = video & ~(PM3VideoControl_HSYNC_MASK |
+				  PM3VideoControl_BLANK_ACTIVE_LOW);
 		break;
-	case 16:
-#ifdef PM3FB_USE_ACCEL
-		if (!(noaccel[l_fb_info->board_num]))
-			disp->dispsw = &pm3fb_cfb16;
-		else
-#endif /* PM3FB_USE_ACCEL */
-			disp->dispsw = &fbcon_cfb16;
-		disp->dispsw_data = l_fb_info->cmap.cmap16;
+	case FB_BLANK_VSYNC_SUSPEND:
+		video = video & ~(PM3VideoControl_VSYNC_MASK |
+				  PM3VideoControl_BLANK_ACTIVE_LOW);
 		break;
-#endif
-#ifdef FBCON_HAS_CFB32
-	case 32:
-#ifdef PM3FB_USE_ACCEL
-		if (!(noaccel[l_fb_info->board_num]))
-			disp->dispsw = &pm3fb_cfb32;
-		else
-#endif /* PM3FB_USE_ACCEL */
-			disp->dispsw = &fbcon_cfb32;
-		disp->dispsw_data = l_fb_info->cmap.cmap32;
+	case FB_BLANK_POWERDOWN:
+		video = video & ~(PM3VideoControl_HSYNC_MASK |
+				  PM3VideoControl_VSYNC_MASK |
+				  PM3VideoControl_BLANK_ACTIVE_LOW);
 		break;
-#endif /* FBCON_HAS_CFB32 */
 	default:
-		disp->dispsw = &fbcon_dummy;
-		DPRINTK(1, "Invalid depth, using fbcon_dummy\n");
-		break;
-	}
-	local_irq_restore(flags);
-}
-
-/* */
-static void pm3fb_detect(void)
-{
-	struct pci_dev *dev_array[PM3_MAX_BOARD];
-	struct pci_dev *dev = NULL;
-	struct pm3fb_info *l_fb_info = &(fb_info[0]);
-	unsigned long i, j, done;
-
-	DTRACE;
-
-	for (i = 0; i < PM3_MAX_BOARD; i++) {
-		dev_array[i] = NULL;
-		fb_info[i].dev = NULL;
+		DPRINTK("Unsupported blanking %d\n", blank_mode);
+		return 1;
 	}
 
-	dev = pci_get_device(PCI_VENDOR_ID_3DLABS,
-			    PCI_DEVICE_ID_3DLABS_PERMEDIA3, dev);
+	PM3_SLOW_WRITE_REG(par,PM3VideoControl, video);
 
-	for (i = 0; ((i < PM3_MAX_BOARD) && dev); i++) {
-		dev_array[i] = dev;
-		dev = pci_get_device(PCI_VENDOR_ID_3DLABS,
-				    PCI_DEVICE_ID_3DLABS_PERMEDIA3, dev);
-	}
-
-	if (dev) {		/* more than PM3_MAX_BOARD */
-		printk(KERN_WARNING "pm3fb: Warning: more than %d boards found\n",
-		       PM3_MAX_BOARD);
-	}
-
-	if (!dev_array[0]) {	/* not a single board, abort */
-		return;
-	}
-
-	/* allocate user-defined boards */
-	for (i = 0; i < PM3_MAX_BOARD; i++) {
-		if ((bus[i] >= 0) && (slot[i] >= 0) && (func[i] >= 0)) {
-			for (j = 0; j < PM3_MAX_BOARD; j++) {
-				if ((dev_array[j] != NULL) &&
-				    (dev_array[j]->bus->number == bus[i])
-				    && (PCI_SLOT(dev_array[j]->devfn) ==
-					slot[i])
-				    && (PCI_FUNC(dev_array[j]->devfn) ==
-					func[i])) {
-					fb_info[i].dev = dev_array[j];
-					dev_array[j] = NULL;
-				}
-			}
-		}
-	}
-	/* allocate remaining boards */
-	for (i = 0; i < PM3_MAX_BOARD; i++) {
-		if (fb_info[i].dev == NULL) {
-			done = 0;
-			for (j = 0; ((j < PM3_MAX_BOARD) && (!done)); j++) {
-				if (dev_array[j] != NULL) {
-					fb_info[i].dev = dev_array[j];
-					dev_array[j] = NULL;
-					done = 1;
-				}
-			}
-		}
-	}
-
-	/* at that point, all PCI Permedia3 are detected and allocated */
-	/* now, initialize... or not */
-	for (i = 0; i < PM3_MAX_BOARD; i++) {
-		l_fb_info = &(fb_info[i]);
-		if (l_fb_info->dev && !disable[i]) {	/* PCI device was found and not disabled by user */
-			DPRINTK(2,
-				"found @%lx Vendor %lx Device %lx ; base @ : %lx - %lx - %lx - %lx - %lx - %lx, irq %ld\n",
-				(unsigned long) l_fb_info->dev,
-				(unsigned long) l_fb_info->dev->vendor,
-				(unsigned long) l_fb_info->dev->device,
-				(unsigned long)
-				pci_resource_start(l_fb_info->dev, 0),
-				(unsigned long)
-				pci_resource_start(l_fb_info->dev, 1),
-				(unsigned long)
-				pci_resource_start(l_fb_info->dev, 2),
-				(unsigned long)
-				pci_resource_start(l_fb_info->dev, 3),
-				(unsigned long)
-				pci_resource_start(l_fb_info->dev, 4),
-				(unsigned long)
-				pci_resource_start(l_fb_info->dev, 5),
-				(unsigned long) l_fb_info->dev->irq);
-
-			l_fb_info->pIOBase =
-			    (unsigned char *)
-			    pci_resource_start(l_fb_info->dev, 0);
-#ifdef __BIG_ENDIAN
-			l_fb_info->pIOBase += PM3_REGS_SIZE;
-#endif
-			l_fb_info->vIOBase = (unsigned char *) -1;
-			l_fb_info->p_fb =
-			    (unsigned char *)
-			    pci_resource_start(l_fb_info->dev, 1);
-			l_fb_info->v_fb = (unsigned char *) -1;
-
-				if (!request_mem_region
-			    ((unsigned long)l_fb_info->p_fb, 64 * 1024 * 1024, /* request full aperture size */
-			     "pm3fb")) {
-				printk
-				    (KERN_ERR "pm3fb: Error: couldn't request framebuffer memory, board #%ld\n",
-				     l_fb_info->board_num);
-				continue;
-			}
-			if (!request_mem_region
-			    ((unsigned long)l_fb_info->pIOBase, PM3_REGS_SIZE,
-			     "pm3fb I/O regs")) {
-				printk
-				    (KERN_ERR "pm3fb: Error: couldn't request IObase memory, board #%ld\n",
-				     l_fb_info->board_num);
-				continue;
-			}
-			if (forcesize[l_fb_info->board_num])
-				l_fb_info->fb_size = forcesize[l_fb_info->board_num];
-
-			l_fb_info->fb_size =
-			    pm3fb_size_memory(l_fb_info);
-				if (l_fb_info->fb_size) {
-				(void) pci_enable_device(l_fb_info->dev);
-				pm3fb_common_init(l_fb_info);
-			} else
-				printk(KERN_ERR "pm3fb: memory problem, not enabling board #%ld\n", l_fb_info->board_num);
-		}
-	}
-}
-
-static int pm3fb_pan_display(const struct fb_var_screeninfo *var,
-			     struct fb_info_gen *info)
-{
-	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
-
-	DTRACE;
-
-	if (!current_par_valid[l_fb_info->board_num])
-		return -EINVAL;
-
-	l_fb_info->current_par->base =	/* in 128 bits chunk - i.e. AFTER Shiftbpp */
-	    pm3fb_Shiftbpp(l_fb_info,
-			   l_fb_info->current_par->depth,
-			   (var->yoffset * l_fb_info->current_par->width) +
-			   var->xoffset);
-	PM3_SLOW_WRITE_REG(PM3ScreenBase, l_fb_info->current_par->base);
 	return 0;
 }
 
-static int pm3fb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
+	/*
+	 *  Frame buffer operations
+	 */
+
+static struct fb_ops pm3fb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_check_var	= pm3fb_check_var,
+	.fb_set_par	= pm3fb_set_par,
+	.fb_setcolreg	= pm3fb_setcolreg,
+	.fb_pan_display	= pm3fb_pan_display,
+	.fb_fillrect	= cfb_fillrect,		/* Needed !!! */
+	.fb_copyarea	= cfb_copyarea,		/* Needed !!! */
+	.fb_imageblit	= cfb_imageblit,	/* Needed !!! */
+	.fb_blank	= pm3fb_blank,
+};
+
+/* ------------------------------------------------------------------------- */
+
+	/*
+	 *  Initialization
+	 */
+
+/* mmio register are already mapped when this function is called */
+/* the pm3fb_fix.smem_start is also set */
+static unsigned long pm3fb_size_memory(struct pm3_par *par)
 {
-	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
-	u32 cm, i;
-#ifdef PM3FB_MASTER_DEBUG
-	char cc[3];
-#endif /* PM3FB_MASTER_DEBUG */
+	unsigned long	memsize = 0, tempBypass, i, temp1, temp2;
+	unsigned char	__iomem *screen_mem;
 
-	switch(cmd)
+	pm3fb_fix.smem_len = 64 * 1024 * 1024; /* request full aperture size */
+	/* Linear frame buffer - request region and map it. */
+	if (!request_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len,
+				 "pm3fb smem")) {
+		printk(KERN_WARNING "pm3fb: Can't reserve smem.\n");
+		return 0;
+	}
+	screen_mem =
+		ioremap_nocache(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
+	if (!screen_mem) {
+		printk(KERN_WARNING "pm3fb: Can't ioremap smem area.\n");
+		release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
+		return 0;
+	}
+
+	/* TODO: card-specific stuff, *before* accessing *any* FB memory */
+	/* For Appian Jeronimo 2000 board second head */
+
+	tempBypass = PM3_READ_REG(par, PM3MemBypassWriteMask);
+
+	DPRINTK("PM3MemBypassWriteMask was: 0x%08lx\n", tempBypass);
+
+	PM3_SLOW_WRITE_REG(par, PM3MemBypassWriteMask, 0xFFFFFFFF);
+
+	/* pm3 split up memory, replicates, and do a lot of nasty stuff IMHO ;-) */
+	for (i = 0; i < 32; i++) {
+		fb_writel(i * 0x00345678,
+			  (screen_mem + (i * 1048576)));
+		mb();
+		temp1 = fb_readl((screen_mem + (i * 1048576)));
+
+		/* Let's check for wrapover, write will fail at 16MB boundary */
+		if (temp1 == (i * 0x00345678))
+			memsize = i;
+		else
+			break;
+	}
+
+	DPRINTK("First detect pass already got %ld MB\n", memsize + 1);
+
+	if (memsize + 1 == i) {
+		for (i = 0; i < 32; i++) {
+			/* Clear first 32MB ; 0 is 0, no need to byteswap */
+			writel(0x0000000,
+			       (screen_mem + (i * 1048576)));
+			mb();
+		}
+
+		for (i = 32; i < 64; i++) {
+			fb_writel(i * 0x00345678,
+				  (screen_mem + (i * 1048576)));
+			mb();
+			temp1 =
+			    fb_readl((screen_mem + (i * 1048576)));
+			temp2 =
+			    fb_readl((screen_mem + ((i - 32) * 1048576)));
+			/* different value, different RAM... */
+			if ((temp1 == (i * 0x00345678)) && (temp2 == 0))
+				memsize = i;
+			else
+				break;
+		}
+	}
+	DPRINTK("Second detect pass got %ld MB\n", memsize + 1);
+
+	PM3_SLOW_WRITE_REG(par, PM3MemBypassWriteMask, tempBypass);
+
+	iounmap(screen_mem);
+	release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
+	memsize = 1048576 * (memsize + 1);
+
+	DPRINTK("Returning 0x%08lx bytes\n", memsize);
+
+	return memsize;
+}
+
+static int __devinit pm3fb_probe(struct pci_dev *dev,
+				  const struct pci_device_id *ent)
+{
+	struct fb_info *info;
+	struct pm3_par *par;
+	struct device* device = &dev->dev; /* for pci drivers */
+	int err, retval = -ENXIO;
+
+	err = pci_enable_device(dev);
+	if (err) {
+		printk(KERN_WARNING "pm3fb: Can't enable PCI dev: %d\n", err);
+		return err;
+	}
+	/*
+	 * Dynamically allocate info and par
+	 */
+	info = framebuffer_alloc(sizeof(struct pm3_par), device);
+
+	if (!info)
+		return -ENOMEM;
+	par = info->par;
+
+	/*
+	 * Here we set the screen_base to the virtual memory address
+	 * for the framebuffer.
+	 */
+	pm3fb_fix.mmio_start = pci_resource_start(dev, 0);
+	pm3fb_fix.mmio_len = PM3_REGS_SIZE;
+
+	/* Registers - request region and map it. */
+	if (!request_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len,
+				 "pm3fb regbase")) {
+		printk(KERN_WARNING "pm3fb: Can't reserve regbase.\n");
+		goto err_exit_neither;
+	}
+	par->v_regs =
+		ioremap_nocache(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len);
+	if (!par->v_regs) {
+		printk(KERN_WARNING "pm3fb: Can't remap %s register area.\n",
+			pm3fb_fix.id);
+		release_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len);
+		goto err_exit_neither;
+	}
+
+#if defined(__BIG_ENDIAN)
+	pm3fb_fix.mmio_start += PM3_REGS_SIZE;
+	DPRINTK("Adjusting register base for big-endian.\n");
+#endif
+	/* Linear frame buffer - request region and map it. */
+	pm3fb_fix.smem_start = pci_resource_start(dev, 1);
+	pm3fb_fix.smem_len = pm3fb_size_memory(par);
+	if (!pm3fb_fix.smem_len)
 	{
-#ifdef PM3FB_MASTER_DEBUG
-	case PM3FBIO_CLEARMEMORY:
-		if (copy_from_user(&cm, (void *)arg, sizeof(u32)))
-			return(-EFAULT);
-		pm3fb_clear_memory(l_fb_info, cm);
-		return(0);
-		break;
+		printk(KERN_WARNING "pm3fb: Can't find memory on board.\n");
+		goto err_exit_mmio;
+	}
+	if (!request_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len,
+				 "pm3fb smem")) {
+		printk(KERN_WARNING "pm3fb: Can't reserve smem.\n");
+		goto err_exit_mmio;
+	}
+	info->screen_base =
+		ioremap_nocache(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
+	if (!info->screen_base) {
+		printk(KERN_WARNING "pm3fb: Can't ioremap smem area.\n");
+		release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
+		goto err_exit_mmio;
+	}
+	info->screen_size = pm3fb_fix.smem_len;
 
-	case PM3FBIO_CLEARCMAP:
-		if (copy_from_user(cc, (void*)arg, 3 * sizeof(char)))
-			return(-EFAULT);
-		pm3fb_clear_colormap(l_fb_info, cc[0], cc[1], cc[2]);
-		return(0);
-		break;
-#endif /* PM3FB_MASTER_DEBUG */
+	info->fbops = &pm3fb_ops;
 
-	case PM3FBIO_RESETCHIP:
-		cm = 1;
-		PM3_SLOW_WRITE_REG(PM3ResetStatus, 1);
-		for (i = 0 ; (i < 10000) && cm ; i++)
-		{
-			PM3_DELAY(10);
-			cm = PM3_READ_REG(PM3ResetStatus);
-		}
-		if (cm)
-		{
-			printk(KERN_ERR "pm3fb: chip reset failed with status 0x%x\n", cm);
-			return(-EIO);
-		}
-		/* first thing first, reload memory timings */
-		pm3fb_write_memory_timings(l_fb_info);
-#ifdef PM3FB_USE_ACCEL
-		pm3fb_init_engine(l_fb_info);
-#endif /* PM3FB_USE_ACCEL */
-		pm3fb_write_mode(l_fb_info);
-		return(0);
-		break;
+	par->video = PM3_READ_REG(par, PM3VideoControl);
 
-	default:
-		DPRINTK(2, "unknown ioctl: %d (%x)\n", cmd, cmd);
-		return(-EINVAL);
+	info->fix = pm3fb_fix;
+	info->pseudo_palette = par->palette;
+	info->flags = FBINFO_DEFAULT;/* | FBINFO_HWACCEL_YPAN;*/
+
+	/*
+	 * This should give a reasonable default video mode. The following is
+	 * done when we can set a video mode.
+	 */
+	if (!mode_option)
+		mode_option = "640x480@60";
+
+	retval = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8);
+
+	if (!retval || retval == 4) {
+		retval = -EINVAL;
+		goto err_exit_both;
+	}
+
+	/* This has to been done !!! */
+	if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
+		retval = -ENOMEM;
+		goto err_exit_both;
+	}
+
+	/*
+	 * For drivers that can...
+	 */
+	pm3fb_check_var(&info->var, info);
+
+	if (register_framebuffer(info) < 0) {
+		retval = -EINVAL;
+		goto err_exit_all;
+	}
+	printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
+	   info->fix.id);
+	pci_set_drvdata(dev, info); /* or dev_set_drvdata(device, info) */
+	return 0;
+
+ err_exit_all:
+	fb_dealloc_cmap(&info->cmap);
+ err_exit_both:
+	iounmap(info->screen_base);
+	release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
+ err_exit_mmio:
+	iounmap(par->v_regs);
+	release_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len);
+ err_exit_neither:
+	framebuffer_release(info);
+	return retval;
+}
+
+	/*
+	 *  Cleanup
+	 */
+static void __devexit pm3fb_remove(struct pci_dev *dev)
+{
+	struct fb_info *info = pci_get_drvdata(dev);
+
+	if (info) {
+		struct fb_fix_screeninfo *fix = &info->fix;
+		struct pm3_par *par = info->par;
+
+		unregister_framebuffer(info);
+		fb_dealloc_cmap(&info->cmap);
+
+		iounmap(info->screen_base);
+		release_mem_region(fix->smem_start, fix->smem_len);
+		iounmap(par->v_regs);
+		release_mem_region(fix->mmio_start, fix->mmio_len);
+
+		pci_set_drvdata(dev, NULL);
+		framebuffer_release(info);
 	}
 }
 
-/* ****************************************** */
-/* ***** standard FB API init functions ***** */
-/* ****************************************** */
+static struct pci_device_id pm3fb_id_table[] = {
+	{ PCI_VENDOR_ID_3DLABS, 0x0a,
+	  PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
+	  0xff0000, 0 },
+	{ 0, }
+};
 
-int __init pm3fb_setup(char *options)
-{
-	long opsi = strlen(options);
+/* For PCI drivers */
+static struct pci_driver pm3fb_driver = {
+	.name =		"pm3fb",
+	.id_table =	pm3fb_id_table,
+	.probe =	pm3fb_probe,
+	.remove =	__devexit_p(pm3fb_remove),
+};
 
-	DTRACE;
-
-	memcpy(g_options, options,
-	       ((opsi + 1) >
-		PM3_OPTIONS_SIZE) ? PM3_OPTIONS_SIZE : (opsi + 1));
-	g_options[PM3_OPTIONS_SIZE - 1] = 0;
-
-	return (0);
-}
+MODULE_DEVICE_TABLE(pci, pm3fb_id_table);
 
 int __init pm3fb_init(void)
 {
-	DTRACE;
+	/*
+	 *  For kernel boot options (in 'video=pm3fb:<options>' format)
+	 */
+#ifndef MODULE
+	char *option = NULL;
 
-	DPRINTK(2, "This is pm3fb.c, CVS version: $Header: /cvsroot/linux/drivers/video/pm3fb.c,v 1.1 2002/02/25 19:11:06 marcelo Exp $");
+	if (fb_get_options("pm3fb", &option))
+		return -ENODEV;
+	pm3fb_setup(option);
+#endif
 
-	pm3fb_real_setup(g_options);
-
-	pm3fb_detect();
-
-	if (!fb_info[0].dev) {	/* not even one board ??? */
-		DPRINTK(1, "No PCI Permedia3 board detected\n");
-	}
-	return (0);
+	return pci_register_driver(&pm3fb_driver);
 }
 
-/* ************************* */
-/* **** Module support ***** */
-/* ************************* */
+static void __exit pm3fb_exit(void)
+{
+	pci_unregister_driver(&pm3fb_driver);
+}
 
 #ifdef MODULE
-MODULE_AUTHOR("Romain Dolbeau");
-MODULE_DESCRIPTION("Permedia3 framebuffer device driver");
-static char *mode[PM3_MAX_BOARD];
-module_param_array(mode, charp, NULL, 0);
-MODULE_PARM_DESC(mode,"video mode");
-module_param_array(disable, short, NULL, 0);
-MODULE_PARM_DESC(disable,"disable board");
-static short off[PM3_MAX_BOARD];
-module_param_array(off, short, NULL, 0);
-MODULE_PARM_DESC(off,"disable board");
-static char *pciid[PM3_MAX_BOARD];
-module_param_array(pciid, charp, NULL, 0);
-MODULE_PARM_DESC(pciid,"board PCI Id");
-module_param_array(noaccel, short, NULL, 0);
-MODULE_PARM_DESC(noaccel,"disable accel");
-static char *font[PM3_MAX_BOARD];
-module_param_array(font, charp, NULL, 0);
-MODULE_PARM_DESC(font,"choose font");
-module_param(depth, short, NULL, 0);
-MODULE_PARM_DESC(depth,"boot-time depth");
-module_param(printtimings, short, NULL, 0);
-MODULE_PARM_DESC(printtimings, "print the memory timings of the card(s)");
-module_param(forcesize, short, NULL, 0);
-MODULE_PARM_DESC(forcesize, "force specified memory size");
+	/*
+	 *  Setup
+	 */
+
 /*
-MODULE_SUPPORTED_DEVICE("Permedia3 PCI boards")
-MODULE_GENERIC_TABLE(gtype,name)
-MODULE_DEVICE_TABLE(type,name)
-*/
-
-void pm3fb_build_options(void)
+ * Only necessary if your driver takes special options,
+ * otherwise we fall back on the generic fb_setup().
+ */
+int __init pm3fb_setup(char *options)
 {
-	int i;
-	char ts[128];
-
-	strcpy(g_options, "pm3fb");
-	for (i = 0; i < PM3_MAX_BOARD ; i++)
-	{
-		if (mode[i])
-		{
-			sprintf(ts, ",mode:%d:%s", i, mode[i]);
-			strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options));
-		}
-		if (disable[i] || off[i])
-		{
-			sprintf(ts, ",disable:%d:", i);
-			strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options));
-		}
-		if (pciid[i])
-		{
-			sprintf(ts, ",pciid:%d:%s", i, pciid[i]);
-			strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options));
-		}
-		if (noaccel[i])
-		{
-			sprintf(ts, ",noaccel:%d:", i);
-			strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options));
-		}
-		if (font[i])
-		{
-			sprintf(ts, ",font:%d:%s", i, font[i]);
-			strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options));
-		}
-		if (depth[i])
-		{
-			sprintf(ts, ",depth:%d:%d", i, depth[i]);
-			strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options));
-		}
-	}
-	g_options[PM3_OPTIONS_SIZE - 1] = '\0';
-	DPRINTK(1, "pm3fb use options: %s\n", g_options);
-}
-
-int init_module(void)
-{
-	DTRACE;
-
-	pm3fb_build_options();
-
-	pm3fb_init();
-
+	/* Parse user speficied options (`video=pm3fb:') */
 	return 0;
 }
-
-void cleanup_module(void)
-{
-	DTRACE;
-	{
-		unsigned long i;
-		struct pm3fb_info *l_fb_info;
-		for (i = 0; i < PM3_MAX_BOARD; i++) {
-			l_fb_info = &(fb_info[i]);
-			pci_dev_put(l_fb_info->dev);
-			if (l_fb_info->dev != NULL  && !(disable[l_fb_info->board_num])) {
-				if (l_fb_info->vIOBase != (unsigned char *) -1) {
-					pm3fb_unmapIO(l_fb_info);
-					release_mem_region(l_fb_info->p_fb,
-						   l_fb_info->fb_size);
-					release_mem_region(l_fb_info->pIOBase,
-						   PM3_REGS_SIZE);
-				}
-				unregister_framebuffer(&l_fb_info->gen.info);
-			}
-		}
-	}
-}
 #endif /* MODULE */
+
+module_init(pm3fb_init);
+module_exit(pm3fb_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/riva/rivafb-i2c.c b/drivers/video/riva/rivafb-i2c.c
index 76e6ce3..a0e22ac 100644
--- a/drivers/video/riva/rivafb-i2c.c
+++ b/drivers/video/riva/rivafb-i2c.c
@@ -70,8 +70,6 @@
 	if (VGA_RD08(par->riva.PCIO, 0x3d5) & 0x04)
 		val = 1;
 
-	val = VGA_RD08(par->riva.PCIO, 0x3d5);
-
 	return val;
 }
 
diff --git a/fs/Makefile b/fs/Makefile
index 9edf411..720c29d 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -22,6 +22,10 @@
 obj-$(CONFIG_INOTIFY)		+= inotify.o
 obj-$(CONFIG_INOTIFY_USER)	+= inotify_user.o
 obj-$(CONFIG_EPOLL)		+= eventpoll.o
+obj-$(CONFIG_ANON_INODES)	+= anon_inodes.o
+obj-$(CONFIG_SIGNALFD)		+= signalfd.o
+obj-$(CONFIG_TIMERFD)		+= timerfd.o
+obj-$(CONFIG_EVENTFD)		+= eventfd.o
 obj-$(CONFIG_COMPAT)		+= compat.o compat_ioctl.o
 
 nfsd-$(CONFIG_NFSD)		:= nfsctl.o
diff --git a/fs/afs/afs.h b/fs/afs/afs.h
index 52d0752..2452579 100644
--- a/fs/afs/afs.h
+++ b/fs/afs/afs.h
@@ -16,6 +16,9 @@
 
 #define AFS_MAXCELLNAME	64		/* maximum length of a cell name */
 #define AFS_MAXVOLNAME	64		/* maximum length of a volume name */
+#define AFSNAMEMAX	256		/* maximum length of a filename plus NUL */
+#define AFSPATHMAX	1024		/* maximum length of a pathname plus NUL */
+#define AFSOPAQUEMAX	1024		/* maximum length of an opaque field */
 
 typedef unsigned			afs_volid_t;
 typedef unsigned			afs_vnodeid_t;
@@ -143,4 +146,24 @@
 	time_t			creation;	/* volume creation time */
 };
 
+/*
+ * AFS volume status record
+ */
+struct afs_volume_status {
+	u32			vid;		/* volume ID */
+	u32			parent_id;	/* parent volume ID */
+	u8			online;		/* true if volume currently online and available */
+	u8			in_service;	/* true if volume currently in service */
+	u8			blessed;	/* same as in_service */
+	u8			needs_salvage;	/* true if consistency checking required */
+	u32			type;		/* volume type (afs_voltype_t) */
+	u32			min_quota;	/* minimum space set aside (blocks) */
+	u32			max_quota;	/* maximum space this volume may occupy (blocks) */
+	u32			blocks_in_use;	/* space this volume currently occupies (blocks) */
+	u32			part_blocks_avail; /* space available in volume's partition */
+	u32			part_max_blocks; /* size of volume's partition */
+};
+
+#define AFS_BLOCK_SIZE	1024
+
 #endif /* AFS_H */
diff --git a/fs/afs/afs_fs.h b/fs/afs/afs_fs.h
index d963ef4..a18c374 100644
--- a/fs/afs/afs_fs.h
+++ b/fs/afs/afs_fs.h
@@ -28,7 +28,8 @@
 	FSMAKEDIR		= 141,	/* AFS Create a directory */
 	FSREMOVEDIR		= 142,	/* AFS Remove a directory */
 	FSGIVEUPCALLBACKS	= 147,	/* AFS Discard callback promises */
-	FSGETVOLUMEINFO		= 148,	/* AFS Get root volume information */
+	FSGETVOLUMEINFO		= 148,	/* AFS Get information about a volume */
+	FSGETVOLUMESTATUS	= 149,	/* AFS Get volume status information */
 	FSGETROOTVOLUME		= 151,	/* AFS Get root volume name */
 	FSLOOKUP		= 161,	/* AFS lookup file in directory */
 	FSFETCHDATA64		= 65537, /* AFS Fetch file data */
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index 2fb3127..719af4f 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -497,7 +497,7 @@
 
 	ASSERTCMP(dentry->d_inode, ==, NULL);
 
-	if (dentry->d_name.len > 255) {
+	if (dentry->d_name.len >= AFSNAMEMAX) {
 		_leave(" = -ENAMETOOLONG");
 		return ERR_PTR(-ENAMETOOLONG);
 	}
@@ -736,7 +736,7 @@
 	       dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, mode);
 
 	ret = -ENAMETOOLONG;
-	if (dentry->d_name.len > 255)
+	if (dentry->d_name.len >= AFSNAMEMAX)
 		goto error;
 
 	key = afs_request_key(dvnode->volume->cell);
@@ -801,7 +801,7 @@
 	       dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name);
 
 	ret = -ENAMETOOLONG;
-	if (dentry->d_name.len > 255)
+	if (dentry->d_name.len >= AFSNAMEMAX)
 		goto error;
 
 	key = afs_request_key(dvnode->volume->cell);
@@ -847,7 +847,7 @@
 	       dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name);
 
 	ret = -ENAMETOOLONG;
-	if (dentry->d_name.len > 255)
+	if (dentry->d_name.len >= AFSNAMEMAX)
 		goto error;
 
 	key = afs_request_key(dvnode->volume->cell);
@@ -921,7 +921,7 @@
 	       dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, mode);
 
 	ret = -ENAMETOOLONG;
-	if (dentry->d_name.len > 255)
+	if (dentry->d_name.len >= AFSNAMEMAX)
 		goto error;
 
 	key = afs_request_key(dvnode->volume->cell);
@@ -990,7 +990,7 @@
 	       dentry->d_name.name);
 
 	ret = -ENAMETOOLONG;
-	if (dentry->d_name.len > 255)
+	if (dentry->d_name.len >= AFSNAMEMAX)
 		goto error;
 
 	key = afs_request_key(dvnode->volume->cell);
@@ -1038,11 +1038,11 @@
 	       content);
 
 	ret = -ENAMETOOLONG;
-	if (dentry->d_name.len > 255)
+	if (dentry->d_name.len >= AFSNAMEMAX)
 		goto error;
 
 	ret = -EINVAL;
-	if (strlen(content) > 1023)
+	if (strlen(content) >= AFSPATHMAX)
 		goto error;
 
 	key = afs_request_key(dvnode->volume->cell);
@@ -1112,7 +1112,7 @@
 	       new_dentry->d_name.name);
 
 	ret = -ENAMETOOLONG;
-	if (new_dentry->d_name.len > 255)
+	if (new_dentry->d_name.len >= AFSNAMEMAX)
 		goto error;
 
 	key = afs_request_key(orig_dvnode->volume->cell);
diff --git a/fs/afs/file.c b/fs/afs/file.c
index 3e25795..9c0e721 100644
--- a/fs/afs/file.c
+++ b/fs/afs/file.c
@@ -236,7 +236,7 @@
 {
 	int ret = 1;
 
-	kenter("{%lu},%lu", page->index, offset);
+	_enter("{%lu},%lu", page->index, offset);
 
 	BUG_ON(!PageLocked(page));
 
diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c
index 56cc0ef..5dff130 100644
--- a/fs/afs/fsclient.c
+++ b/fs/afs/fsclient.c
@@ -202,6 +202,29 @@
 }
 
 /*
+ * decode an AFSFetchVolumeStatus block
+ */
+static void xdr_decode_AFSFetchVolumeStatus(const __be32 **_bp,
+					    struct afs_volume_status *vs)
+{
+	const __be32 *bp = *_bp;
+
+	vs->vid			= ntohl(*bp++);
+	vs->parent_id		= ntohl(*bp++);
+	vs->online		= ntohl(*bp++);
+	vs->in_service		= ntohl(*bp++);
+	vs->blessed		= ntohl(*bp++);
+	vs->needs_salvage	= ntohl(*bp++);
+	vs->type		= ntohl(*bp++);
+	vs->min_quota		= ntohl(*bp++);
+	vs->max_quota		= ntohl(*bp++);
+	vs->blocks_in_use	= ntohl(*bp++);
+	vs->part_blocks_avail	= ntohl(*bp++);
+	vs->part_max_blocks	= ntohl(*bp++);
+	*_bp = bp;
+}
+
+/*
  * deliver reply data to an FS.FetchStatus
  */
 static int afs_deliver_fs_fetch_status(struct afs_call *call,
@@ -1450,3 +1473,278 @@
 
 	return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
 }
+
+/*
+ * deliver reply data to an FS.GetVolumeStatus
+ */
+static int afs_deliver_fs_get_volume_status(struct afs_call *call,
+					    struct sk_buff *skb, bool last)
+{
+	const __be32 *bp;
+	char *p;
+	int ret;
+
+	_enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
+
+	switch (call->unmarshall) {
+	case 0:
+		call->offset = 0;
+		call->unmarshall++;
+
+		/* extract the returned status record */
+	case 1:
+		_debug("extract status");
+		ret = afs_extract_data(call, skb, last, call->buffer,
+				       12 * 4);
+		switch (ret) {
+		case 0:		break;
+		case -EAGAIN:	return 0;
+		default:	return ret;
+		}
+
+		bp = call->buffer;
+		xdr_decode_AFSFetchVolumeStatus(&bp, call->reply2);
+		call->offset = 0;
+		call->unmarshall++;
+
+		/* extract the volume name length */
+	case 2:
+		ret = afs_extract_data(call, skb, last, &call->tmp, 4);
+		switch (ret) {
+		case 0:		break;
+		case -EAGAIN:	return 0;
+		default:	return ret;
+		}
+
+		call->count = ntohl(call->tmp);
+		_debug("volname length: %u", call->count);
+		if (call->count >= AFSNAMEMAX)
+			return -EBADMSG;
+		call->offset = 0;
+		call->unmarshall++;
+
+		/* extract the volume name */
+	case 3:
+		_debug("extract volname");
+		if (call->count > 0) {
+			ret = afs_extract_data(call, skb, last, call->reply3,
+					       call->count);
+			switch (ret) {
+			case 0:		break;
+			case -EAGAIN:	return 0;
+			default:	return ret;
+			}
+		}
+
+		p = call->reply3;
+		p[call->count] = 0;
+		_debug("volname '%s'", p);
+
+		call->offset = 0;
+		call->unmarshall++;
+
+		/* extract the volume name padding */
+		if ((call->count & 3) == 0) {
+			call->unmarshall++;
+			goto no_volname_padding;
+		}
+		call->count = 4 - (call->count & 3);
+
+	case 4:
+		ret = afs_extract_data(call, skb, last, call->buffer,
+				       call->count);
+		switch (ret) {
+		case 0:		break;
+		case -EAGAIN:	return 0;
+		default:	return ret;
+		}
+
+		call->offset = 0;
+		call->unmarshall++;
+	no_volname_padding:
+
+		/* extract the offline message length */
+	case 5:
+		ret = afs_extract_data(call, skb, last, &call->tmp, 4);
+		switch (ret) {
+		case 0:		break;
+		case -EAGAIN:	return 0;
+		default:	return ret;
+		}
+
+		call->count = ntohl(call->tmp);
+		_debug("offline msg length: %u", call->count);
+		if (call->count >= AFSNAMEMAX)
+			return -EBADMSG;
+		call->offset = 0;
+		call->unmarshall++;
+
+		/* extract the offline message */
+	case 6:
+		_debug("extract offline");
+		if (call->count > 0) {
+			ret = afs_extract_data(call, skb, last, call->reply3,
+					       call->count);
+			switch (ret) {
+			case 0:		break;
+			case -EAGAIN:	return 0;
+			default:	return ret;
+			}
+		}
+
+		p = call->reply3;
+		p[call->count] = 0;
+		_debug("offline '%s'", p);
+
+		call->offset = 0;
+		call->unmarshall++;
+
+		/* extract the offline message padding */
+		if ((call->count & 3) == 0) {
+			call->unmarshall++;
+			goto no_offline_padding;
+		}
+		call->count = 4 - (call->count & 3);
+
+	case 7:
+		ret = afs_extract_data(call, skb, last, call->buffer,
+				       call->count);
+		switch (ret) {
+		case 0:		break;
+		case -EAGAIN:	return 0;
+		default:	return ret;
+		}
+
+		call->offset = 0;
+		call->unmarshall++;
+	no_offline_padding:
+
+		/* extract the message of the day length */
+	case 8:
+		ret = afs_extract_data(call, skb, last, &call->tmp, 4);
+		switch (ret) {
+		case 0:		break;
+		case -EAGAIN:	return 0;
+		default:	return ret;
+		}
+
+		call->count = ntohl(call->tmp);
+		_debug("motd length: %u", call->count);
+		if (call->count >= AFSNAMEMAX)
+			return -EBADMSG;
+		call->offset = 0;
+		call->unmarshall++;
+
+		/* extract the message of the day */
+	case 9:
+		_debug("extract motd");
+		if (call->count > 0) {
+			ret = afs_extract_data(call, skb, last, call->reply3,
+					       call->count);
+			switch (ret) {
+			case 0:		break;
+			case -EAGAIN:	return 0;
+			default:	return ret;
+			}
+		}
+
+		p = call->reply3;
+		p[call->count] = 0;
+		_debug("motd '%s'", p);
+
+		call->offset = 0;
+		call->unmarshall++;
+
+		/* extract the message of the day padding */
+		if ((call->count & 3) == 0) {
+			call->unmarshall++;
+			goto no_motd_padding;
+		}
+		call->count = 4 - (call->count & 3);
+
+	case 10:
+		ret = afs_extract_data(call, skb, last, call->buffer,
+				       call->count);
+		switch (ret) {
+		case 0:		break;
+		case -EAGAIN:	return 0;
+		default:	return ret;
+		}
+
+		call->offset = 0;
+		call->unmarshall++;
+	no_motd_padding:
+
+	case 11:
+		_debug("trailer %d", skb->len);
+		if (skb->len != 0)
+			return -EBADMSG;
+		break;
+	}
+
+	if (!last)
+		return 0;
+
+	_leave(" = 0 [done]");
+	return 0;
+}
+
+/*
+ * destroy an FS.GetVolumeStatus call
+ */
+static void afs_get_volume_status_call_destructor(struct afs_call *call)
+{
+	kfree(call->reply3);
+	call->reply3 = NULL;
+	afs_flat_call_destructor(call);
+}
+
+/*
+ * FS.GetVolumeStatus operation type
+ */
+static const struct afs_call_type afs_RXFSGetVolumeStatus = {
+	.name		= "FS.GetVolumeStatus",
+	.deliver	= afs_deliver_fs_get_volume_status,
+	.abort_to_error	= afs_abort_to_error,
+	.destructor	= afs_get_volume_status_call_destructor,
+};
+
+/*
+ * fetch the status of a volume
+ */
+int afs_fs_get_volume_status(struct afs_server *server,
+			     struct key *key,
+			     struct afs_vnode *vnode,
+			     struct afs_volume_status *vs,
+			     const struct afs_wait_mode *wait_mode)
+{
+	struct afs_call *call;
+	__be32 *bp;
+	void *tmpbuf;
+
+	_enter("");
+
+	tmpbuf = kmalloc(AFSOPAQUEMAX, GFP_KERNEL);
+	if (!tmpbuf)
+		return -ENOMEM;
+
+	call = afs_alloc_flat_call(&afs_RXFSGetVolumeStatus, 2 * 4, 12 * 4);
+	if (!call) {
+		kfree(tmpbuf);
+		return -ENOMEM;
+	}
+
+	call->key = key;
+	call->reply = vnode;
+	call->reply2 = vs;
+	call->reply3 = tmpbuf;
+	call->service_id = FS_SERVICE;
+	call->port = htons(AFS_FS_PORT);
+
+	/* marshall the parameters */
+	bp = call->request;
+	bp[0] = htonl(FSGETVOLUMESTATUS);
+	bp[1] = htonl(vnode->fid.vid);
+
+	return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
+}
diff --git a/fs/afs/inode.c b/fs/afs/inode.c
index 515a5d1..47f5fed 100644
--- a/fs/afs/inode.c
+++ b/fs/afs/inode.c
@@ -209,11 +209,15 @@
  */
 void afs_zap_data(struct afs_vnode *vnode)
 {
-	_enter("zap data {%x:%u}", vnode->fid.vid, vnode->fid.vnode);
+	_enter("{%x:%u}", vnode->fid.vid, vnode->fid.vnode);
 
 	/* nuke all the non-dirty pages that aren't locked, mapped or being
-	 * written back */
-	invalidate_remote_inode(&vnode->vfs_inode);
+	 * written back in a regular file and completely discard the pages in a
+	 * directory or symlink */
+	if (S_ISREG(vnode->vfs_inode.i_mode))
+		invalidate_remote_inode(&vnode->vfs_inode);
+	else
+		invalidate_inode_pages2(vnode->vfs_inode.i_mapping);
 }
 
 /*
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index a30d4fa..4953ba5 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -506,6 +506,10 @@
 extern int afs_fs_setattr(struct afs_server *, struct key *,
 			  struct afs_vnode *, struct iattr *,
 			  const struct afs_wait_mode *);
+extern int afs_fs_get_volume_status(struct afs_server *, struct key *,
+				    struct afs_vnode *,
+				    struct afs_volume_status *,
+				    const struct afs_wait_mode *);
 
 /*
  * inode.c
@@ -672,6 +676,8 @@
 extern int afs_vnode_store_data(struct afs_writeback *, pgoff_t, pgoff_t,
 				unsigned, unsigned);
 extern int afs_vnode_setattr(struct afs_vnode *, struct key *, struct iattr *);
+extern int afs_vnode_get_volume_status(struct afs_vnode *, struct key *,
+				       struct afs_volume_status *);
 
 /*
  * volume.c
diff --git a/fs/afs/super.c b/fs/afs/super.c
index d24be33..579af63 100644
--- a/fs/afs/super.c
+++ b/fs/afs/super.c
@@ -21,22 +21,20 @@
 #include <linux/fs.h>
 #include <linux/pagemap.h>
 #include <linux/parser.h>
+#include <linux/statfs.h>
 #include "internal.h"
 
 #define AFS_FS_MAGIC 0x6B414653 /* 'kAFS' */
 
 static void afs_i_init_once(void *foo, struct kmem_cache *cachep,
 			    unsigned long flags);
-
 static int afs_get_sb(struct file_system_type *fs_type,
 		      int flags, const char *dev_name,
 		      void *data, struct vfsmount *mnt);
-
 static struct inode *afs_alloc_inode(struct super_block *sb);
-
 static void afs_put_super(struct super_block *sb);
-
 static void afs_destroy_inode(struct inode *inode);
+static int afs_statfs(struct dentry *dentry, struct kstatfs *buf);
 
 struct file_system_type afs_fs_type = {
 	.owner		= THIS_MODULE,
@@ -47,7 +45,7 @@
 };
 
 static const struct super_operations afs_super_ops = {
-	.statfs		= simple_statfs,
+	.statfs		= afs_statfs,
 	.alloc_inode	= afs_alloc_inode,
 	.drop_inode	= generic_delete_inode,
 	.write_inode	= afs_write_inode,
@@ -488,6 +486,7 @@
 	vnode->flags		= 1 << AFS_VNODE_UNSET;
 	vnode->cb_promised	= false;
 
+	_leave(" = %p", &vnode->vfs_inode);
 	return &vnode->vfs_inode;
 }
 
@@ -498,7 +497,7 @@
 {
 	struct afs_vnode *vnode = AFS_FS_I(inode);
 
-	_enter("{%lu}", inode->i_ino);
+	_enter("%p{%x:%u}", inode, vnode->fid.vid, vnode->fid.vnode);
 
 	_debug("DESTROY INODE %p", inode);
 
@@ -507,3 +506,36 @@
 	kmem_cache_free(afs_inode_cachep, vnode);
 	atomic_dec(&afs_count_active_inodes);
 }
+
+/*
+ * return information about an AFS volume
+ */
+static int afs_statfs(struct dentry *dentry, struct kstatfs *buf)
+{
+	struct afs_volume_status vs;
+	struct afs_vnode *vnode = AFS_FS_I(dentry->d_inode);
+	struct key *key;
+	int ret;
+
+	key = afs_request_key(vnode->volume->cell);
+	if (IS_ERR(key))
+		return PTR_ERR(key);
+
+	ret = afs_vnode_get_volume_status(vnode, key, &vs);
+	key_put(key);
+	if (ret < 0) {
+		_leave(" = %d", ret);
+		return ret;
+	}
+
+	buf->f_type	= dentry->d_sb->s_magic;
+	buf->f_bsize	= AFS_BLOCK_SIZE;
+	buf->f_namelen	= AFSNAMEMAX - 1;
+
+	if (vs.max_quota == 0)
+		buf->f_blocks = vs.part_max_blocks;
+	else
+		buf->f_blocks = vs.max_quota;
+	buf->f_bavail = buf->f_bfree = buf->f_blocks - vs.blocks_in_use;
+	return 0;
+}
diff --git a/fs/afs/vnode.c b/fs/afs/vnode.c
index ec81466..c36c98c 100644
--- a/fs/afs/vnode.c
+++ b/fs/afs/vnode.c
@@ -175,24 +175,33 @@
 {
 	struct afs_server *server;
 
+	_enter("{%p}", vnode->server);
+
 	set_bit(AFS_VNODE_DELETED, &vnode->flags);
 
 	server = vnode->server;
-	if (vnode->cb_promised) {
-		spin_lock(&server->cb_lock);
+	if (server) {
 		if (vnode->cb_promised) {
-			rb_erase(&vnode->cb_promise, &server->cb_promises);
-			vnode->cb_promised = false;
+			spin_lock(&server->cb_lock);
+			if (vnode->cb_promised) {
+				rb_erase(&vnode->cb_promise,
+					 &server->cb_promises);
+				vnode->cb_promised = false;
+			}
+			spin_unlock(&server->cb_lock);
 		}
-		spin_unlock(&server->cb_lock);
+
+		spin_lock(&server->fs_lock);
+		rb_erase(&vnode->server_rb, &server->fs_vnodes);
+		spin_unlock(&server->fs_lock);
+
+		vnode->server = NULL;
+		afs_put_server(server);
+	} else {
+		ASSERT(!vnode->cb_promised);
 	}
 
-	spin_lock(&vnode->server->fs_lock);
-	rb_erase(&vnode->server_rb, &vnode->server->fs_vnodes);
-	spin_unlock(&vnode->server->fs_lock);
-
-	vnode->server = NULL;
-	afs_put_server(server);
+	_leave("");
 }
 
 /*
@@ -225,7 +234,7 @@
  */
 static void afs_vnode_status_update_failed(struct afs_vnode *vnode, int ret)
 {
-	_enter("%p,%d", vnode, ret);
+	_enter("{%x:%u},%d", vnode->fid.vid, vnode->fid.vnode, ret);
 
 	spin_lock(&vnode->lock);
 
@@ -860,3 +869,55 @@
 	spin_unlock(&vnode->lock);
 	return PTR_ERR(server);
 }
+
+/*
+ * get the status of a volume
+ */
+int afs_vnode_get_volume_status(struct afs_vnode *vnode, struct key *key,
+				struct afs_volume_status *vs)
+{
+	struct afs_server *server;
+	int ret;
+
+	_enter("%s{%x:%u.%u},%x,",
+	       vnode->volume->vlocation->vldb.name,
+	       vnode->fid.vid,
+	       vnode->fid.vnode,
+	       vnode->fid.unique,
+	       key_serial(key));
+
+	/* this op will fetch the status */
+	spin_lock(&vnode->lock);
+	vnode->update_cnt++;
+	spin_unlock(&vnode->lock);
+
+	do {
+		/* pick a server to query */
+		server = afs_volume_pick_fileserver(vnode);
+		if (IS_ERR(server))
+			goto no_server;
+
+		_debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
+
+		ret = afs_fs_get_volume_status(server, key, vnode, vs, &afs_sync_call);
+
+	} while (!afs_volume_release_fileserver(vnode, server, ret));
+
+	/* adjust the flags */
+	if (ret == 0) {
+		afs_vnode_finalise_status_update(vnode, server);
+		afs_put_server(server);
+	} else {
+		afs_vnode_status_update_failed(vnode, ret);
+	}
+
+	_leave(" = %d", ret);
+	return ret;
+
+no_server:
+	spin_lock(&vnode->lock);
+	vnode->update_cnt--;
+	ASSERTCMP(vnode->update_cnt, >=, 0);
+	spin_unlock(&vnode->lock);
+	return PTR_ERR(server);
+}
diff --git a/fs/afs/write.c b/fs/afs/write.c
index 67ae4db..28f3751 100644
--- a/fs/afs/write.c
+++ b/fs/afs/write.c
@@ -395,8 +395,9 @@
 		if (n == 0)
 			goto no_more;
 		if (pages[0]->index != start) {
-			for (n--; n >= 0; n--)
-				put_page(pages[n]);
+			do {
+				put_page(pages[--n]);
+			} while (n > 0);
 			goto no_more;
 		}
 
diff --git a/fs/aio.c b/fs/aio.c
index ac1c158..dbe699e 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -30,6 +30,7 @@
 #include <linux/highmem.h>
 #include <linux/workqueue.h>
 #include <linux/security.h>
+#include <linux/eventfd.h>
 
 #include <asm/kmap_types.h>
 #include <asm/uaccess.h>
@@ -417,6 +418,7 @@
 	req->private = NULL;
 	req->ki_iovec = NULL;
 	INIT_LIST_HEAD(&req->ki_run_list);
+	req->ki_eventfd = ERR_PTR(-EINVAL);
 
 	/* Check if the completion queue has enough free space to
 	 * accept an event from this io.
@@ -458,6 +460,8 @@
 {
 	assert_spin_locked(&ctx->ctx_lock);
 
+	if (!IS_ERR(req->ki_eventfd))
+		fput(req->ki_eventfd);
 	if (req->ki_dtor)
 		req->ki_dtor(req);
 	if (req->ki_iovec != &req->ki_inline_vec)
@@ -942,6 +946,14 @@
 		return 1;
 	}
 
+	/*
+	 * Check if the user asked us to deliver the result through an
+	 * eventfd. The eventfd_signal() function is safe to be called
+	 * from IRQ context.
+	 */
+	if (!IS_ERR(iocb->ki_eventfd))
+		eventfd_signal(iocb->ki_eventfd, 1);
+
 	info = &ctx->ring_info;
 
 	/* add a completion event to the ring buffer.
@@ -1526,8 +1538,7 @@
 	ssize_t ret;
 
 	/* enforce forwards compatibility on users */
-	if (unlikely(iocb->aio_reserved1 || iocb->aio_reserved2 ||
-		     iocb->aio_reserved3)) {
+	if (unlikely(iocb->aio_reserved1 || iocb->aio_reserved2)) {
 		pr_debug("EINVAL: io_submit: reserve field set\n");
 		return -EINVAL;
 	}
@@ -1551,6 +1562,19 @@
 		fput(file);
 		return -EAGAIN;
 	}
+	if (iocb->aio_flags & IOCB_FLAG_RESFD) {
+		/*
+		 * If the IOCB_FLAG_RESFD flag of aio_flags is set, get an
+		 * instance of the file* now. The file descriptor must be
+		 * an eventfd() fd, and will be signaled for each completed
+		 * event using the eventfd_signal() function.
+		 */
+		req->ki_eventfd = eventfd_fget((int) iocb->aio_resfd);
+		if (unlikely(IS_ERR(req->ki_eventfd))) {
+			ret = PTR_ERR(req->ki_eventfd);
+			goto out_put_req;
+		}
+	}
 
 	req->ki_filp = file;
 	ret = put_user(req->ki_key, &user_iocb->aio_key);
diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c
new file mode 100644
index 0000000..40fe3a3
--- /dev/null
+++ b/fs/anon_inodes.c
@@ -0,0 +1,200 @@
+/*
+ *  fs/anon_inodes.c
+ *
+ *  Copyright (C) 2007  Davide Libenzi <davidel@xmailserver.org>
+ *
+ *  Thanks to Arnd Bergmann for code review and suggestions.
+ *  More changes for Thomas Gleixner suggestions.
+ *
+ */
+
+#include <linux/file.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/mount.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/magic.h>
+#include <linux/anon_inodes.h>
+
+#include <asm/uaccess.h>
+
+static struct vfsmount *anon_inode_mnt __read_mostly;
+static struct inode *anon_inode_inode;
+static const struct file_operations anon_inode_fops;
+
+static int anon_inodefs_get_sb(struct file_system_type *fs_type, int flags,
+			       const char *dev_name, void *data,
+			       struct vfsmount *mnt)
+{
+	return get_sb_pseudo(fs_type, "anon_inode:", NULL, ANON_INODE_FS_MAGIC,
+			     mnt);
+}
+
+static int anon_inodefs_delete_dentry(struct dentry *dentry)
+{
+	/*
+	 * We faked vfs to believe the dentry was hashed when we created it.
+	 * Now we restore the flag so that dput() will work correctly.
+	 */
+	dentry->d_flags |= DCACHE_UNHASHED;
+	return 1;
+}
+
+static struct file_system_type anon_inode_fs_type = {
+	.name		= "anon_inodefs",
+	.get_sb		= anon_inodefs_get_sb,
+	.kill_sb	= kill_anon_super,
+};
+static struct dentry_operations anon_inodefs_dentry_operations = {
+	.d_delete	= anon_inodefs_delete_dentry,
+};
+
+/**
+ * anon_inode_getfd - creates a new file instance by hooking it up to and
+ *                    anonymous inode, and a dentry that describe the "class"
+ *                    of the file
+ *
+ * @pfd:     [out]   pointer to the file descriptor
+ * @dpinode: [out]   pointer to the inode
+ * @pfile:   [out]   pointer to the file struct
+ * @name:    [in]    name of the "class" of the new file
+ * @fops     [in]    file operations for the new file
+ * @priv     [in]    private data for the new file (will be file's private_data)
+ *
+ * Creates a new file by hooking it on a single inode. This is useful for files
+ * that do not need to have a full-fledged inode in order to operate correctly.
+ * All the files created with anon_inode_getfd() will share a single inode, by
+ * hence saving memory and avoiding code duplication for the file/inode/dentry
+ * setup.
+ */
+int anon_inode_getfd(int *pfd, struct inode **pinode, struct file **pfile,
+		     const char *name, const struct file_operations *fops,
+		     void *priv)
+{
+	struct qstr this;
+	struct dentry *dentry;
+	struct inode *inode;
+	struct file *file;
+	int error, fd;
+
+	if (IS_ERR(anon_inode_inode))
+		return -ENODEV;
+	file = get_empty_filp();
+	if (!file)
+		return -ENFILE;
+
+	inode = igrab(anon_inode_inode);
+	if (IS_ERR(inode)) {
+		error = PTR_ERR(inode);
+		goto err_put_filp;
+	}
+
+	error = get_unused_fd();
+	if (error < 0)
+		goto err_iput;
+	fd = error;
+
+	/*
+	 * Link the inode to a directory entry by creating a unique name
+	 * using the inode sequence number.
+	 */
+	error = -ENOMEM;
+	this.name = name;
+	this.len = strlen(name);
+	this.hash = 0;
+	dentry = d_alloc(anon_inode_mnt->mnt_sb->s_root, &this);
+	if (!dentry)
+		goto err_put_unused_fd;
+	dentry->d_op = &anon_inodefs_dentry_operations;
+	/* Do not publish this dentry inside the global dentry hash table */
+	dentry->d_flags &= ~DCACHE_UNHASHED;
+	d_instantiate(dentry, inode);
+
+	file->f_path.mnt = mntget(anon_inode_mnt);
+	file->f_path.dentry = dentry;
+	file->f_mapping = inode->i_mapping;
+
+	file->f_pos = 0;
+	file->f_flags = O_RDWR;
+	file->f_op = fops;
+	file->f_mode = FMODE_READ | FMODE_WRITE;
+	file->f_version = 0;
+	file->private_data = priv;
+
+	fd_install(fd, file);
+
+	*pfd = fd;
+	*pinode = inode;
+	*pfile = file;
+	return 0;
+
+err_put_unused_fd:
+	put_unused_fd(fd);
+err_iput:
+	iput(inode);
+err_put_filp:
+	put_filp(file);
+	return error;
+}
+
+/*
+ * A single inode exist for all anon_inode files. Contrary to pipes,
+ * anon_inode inodes has no per-instance data associated, so we can avoid
+ * the allocation of multiple of them.
+ */
+static struct inode *anon_inode_mkinode(void)
+{
+	struct inode *inode = new_inode(anon_inode_mnt->mnt_sb);
+
+	if (!inode)
+		return ERR_PTR(-ENOMEM);
+
+	inode->i_fop = &anon_inode_fops;
+
+	/*
+	 * Mark the inode dirty from the very beginning,
+	 * that way it will never be moved to the dirty
+	 * list because mark_inode_dirty() will think
+	 * that it already _is_ on the dirty list.
+	 */
+	inode->i_state = I_DIRTY;
+	inode->i_mode = S_IRUSR | S_IWUSR;
+	inode->i_uid = current->fsuid;
+	inode->i_gid = current->fsgid;
+	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+	return inode;
+}
+
+static int __init anon_inode_init(void)
+{
+	int error;
+
+	error = register_filesystem(&anon_inode_fs_type);
+	if (error)
+		goto err_exit;
+	anon_inode_mnt = kern_mount(&anon_inode_fs_type);
+	if (IS_ERR(anon_inode_mnt)) {
+		error = PTR_ERR(anon_inode_mnt);
+		goto err_unregister_filesystem;
+	}
+	anon_inode_inode = anon_inode_mkinode();
+	if (IS_ERR(anon_inode_inode)) {
+		error = PTR_ERR(anon_inode_inode);
+		goto err_mntput;
+	}
+
+	return 0;
+
+err_mntput:
+	mntput(anon_inode_mnt);
+err_unregister_filesystem:
+	unregister_filesystem(&anon_inode_fs_type);
+err_exit:
+	panic(KERN_ERR "anon_inode_init() failed (%d)\n", error);
+}
+
+fs_initcall(anon_inode_init);
+
diff --git a/fs/autofs/autofs_i.h b/fs/autofs/autofs_i.h
index 4ef5444..8b4cca3 100644
--- a/fs/autofs/autofs_i.h
+++ b/fs/autofs/autofs_i.h
@@ -101,7 +101,7 @@
 struct autofs_sb_info {
 	u32 magic;
 	struct file *pipe;
-	pid_t oz_pgrp;
+	struct pid *oz_pgrp;
 	int catatonic;
 	struct super_block *sb;
 	unsigned long exp_timeout;
@@ -122,7 +122,7 @@
    filesystem without "magic".) */
 
 static inline int autofs_oz_mode(struct autofs_sb_info *sbi) {
-	return sbi->catatonic || process_group(current) == sbi->oz_pgrp;
+	return sbi->catatonic || task_pgrp(current) == sbi->oz_pgrp;
 }
 
 /* Hash operations */
diff --git a/fs/autofs/inode.c b/fs/autofs/inode.c
index aa0b61f..e7204d7 100644
--- a/fs/autofs/inode.c
+++ b/fs/autofs/inode.c
@@ -34,12 +34,14 @@
 	if (!sbi)
 		goto out_kill_sb;
 
-	if ( !sbi->catatonic )
+	if (!sbi->catatonic)
 		autofs_catatonic_mode(sbi); /* Free wait queues, close pipe */
 
+	put_pid(sbi->oz_pgrp);
+
 	autofs_hash_nuke(sbi);
-	for ( n = 0 ; n < AUTOFS_MAX_SYMLINKS ; n++ ) {
-		if ( test_bit(n, sbi->symlink_bitmap) )
+	for (n = 0; n < AUTOFS_MAX_SYMLINKS; n++) {
+		if (test_bit(n, sbi->symlink_bitmap))
 			kfree(sbi->symlink[n].data);
 	}
 
@@ -69,7 +71,8 @@
 	{Opt_err, NULL}
 };
 
-static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid, pid_t *pgrp, int *minproto, int *maxproto)
+static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid,
+		pid_t *pgrp, int *minproto, int *maxproto)
 {
 	char *p;
 	substring_t args[MAX_OPT_ARGS];
@@ -138,9 +141,10 @@
 	int pipefd;
 	struct autofs_sb_info *sbi;
 	int minproto, maxproto;
+	pid_t pgid;
 
 	sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
-	if ( !sbi )
+	if (!sbi)
 		goto fail_unlock;
 	DPRINTK(("autofs: starting up, sbi = %p\n",sbi));
 
@@ -149,7 +153,6 @@
 	sbi->pipe = NULL;
 	sbi->catatonic = 1;
 	sbi->exp_timeout = 0;
-	sbi->oz_pgrp = process_group(current);
 	autofs_initialize_hash(&sbi->dirhash);
 	sbi->queues = NULL;
 	memset(sbi->symlink_bitmap, 0, sizeof(long)*AUTOFS_SYMLINK_BITMAP_LEN);
@@ -169,26 +172,36 @@
 		goto fail_iput;
 
 	/* Can this call block?  - WTF cares? s is locked. */
-	if ( parse_options(data,&pipefd,&root_inode->i_uid,&root_inode->i_gid,&sbi->oz_pgrp,&minproto,&maxproto) ) {
+	if (parse_options(data, &pipefd, &root_inode->i_uid,
+				&root_inode->i_gid, &pgid, &minproto,
+				&maxproto)) {
 		printk("autofs: called with bogus options\n");
 		goto fail_dput;
 	}
 
 	/* Couldn't this be tested earlier? */
-	if ( minproto > AUTOFS_PROTO_VERSION || 
-	     maxproto < AUTOFS_PROTO_VERSION ) {
+	if (minproto > AUTOFS_PROTO_VERSION ||
+	     maxproto < AUTOFS_PROTO_VERSION) {
 		printk("autofs: kernel does not match daemon version\n");
 		goto fail_dput;
 	}
 
-	DPRINTK(("autofs: pipe fd = %d, pgrp = %u\n", pipefd, sbi->oz_pgrp));
-	pipe = fget(pipefd);
-	
-	if ( !pipe ) {
-		printk("autofs: could not open pipe file descriptor\n");
+	DPRINTK(("autofs: pipe fd = %d, pgrp = %u\n", pipefd, pgid));
+	sbi->oz_pgrp = find_get_pid(pgid);
+
+	if (!sbi->oz_pgrp) {
+		printk("autofs: could not find process group %d\n", pgid);
 		goto fail_dput;
 	}
-	if ( !pipe->f_op || !pipe->f_op->write )
+
+	pipe = fget(pipefd);
+	
+	if (!pipe) {
+		printk("autofs: could not open pipe file descriptor\n");
+		goto fail_put_pid;
+	}
+
+	if (!pipe->f_op || !pipe->f_op->write)
 		goto fail_fput;
 	sbi->pipe = pipe;
 	sbi->catatonic = 0;
@@ -202,6 +215,8 @@
 fail_fput:
 	printk("autofs: pipe file descriptor does not contain proper ops\n");
 	fput(pipe);
+fail_put_pid:
+	put_pid(sbi->oz_pgrp);
 fail_dput:
 	dput(root);
 	goto fail_free;
@@ -230,7 +245,7 @@
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
 	inode->i_blocks = 0;
 
-	if ( ino == AUTOFS_ROOT_INO ) {
+	if (ino == AUTOFS_ROOT_INO) {
 		inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR;
 		inode->i_op = &autofs_root_inode_operations;
 		inode->i_fop = &autofs_root_operations;
@@ -241,12 +256,12 @@
 	inode->i_uid = inode->i_sb->s_root->d_inode->i_uid;
 	inode->i_gid = inode->i_sb->s_root->d_inode->i_gid;
 	
-	if ( ino >= AUTOFS_FIRST_SYMLINK && ino < AUTOFS_FIRST_DIR_INO ) {
+	if (ino >= AUTOFS_FIRST_SYMLINK && ino < AUTOFS_FIRST_DIR_INO) {
 		/* Symlink inode - should be in symlink list */
 		struct autofs_symlink *sl;
 
 		n = ino - AUTOFS_FIRST_SYMLINK;
-		if ( n >= AUTOFS_MAX_SYMLINKS || !test_bit(n,sbi->symlink_bitmap)) {
+		if (n >= AUTOFS_MAX_SYMLINKS || !test_bit(n,sbi->symlink_bitmap)) {
 			printk("autofs: Looking for bad symlink inode %u\n", (unsigned int) ino);
 			return;
 		}
diff --git a/fs/autofs/root.c b/fs/autofs/root.c
index f259720..c148953 100644
--- a/fs/autofs/root.c
+++ b/fs/autofs/root.c
@@ -67,8 +67,8 @@
 		filp->f_pos = ++nr;
 		/* fall through */
 	default:
-		while ( onr = nr, ent = autofs_hash_enum(dirhash,&nr,ent) ) {
-			if ( !ent->dentry || d_mountpoint(ent->dentry) ) {
+		while (onr = nr, ent = autofs_hash_enum(dirhash,&nr,ent)) {
+			if (!ent->dentry || d_mountpoint(ent->dentry)) {
 				if (filldir(dirent,ent->name,ent->len,onr,ent->ino,DT_UNKNOWN) < 0)
 					goto out;
 				filp->f_pos = nr;
@@ -88,10 +88,10 @@
 	struct autofs_dir_ent *ent;
 	int status = 0;
 
-	if ( !(ent = autofs_hash_lookup(&sbi->dirhash, &dentry->d_name)) ) {
+	if (!(ent = autofs_hash_lookup(&sbi->dirhash, &dentry->d_name))) {
 		do {
-			if ( status && dentry->d_inode ) {
-				if ( status != -ENOENT )
+			if (status && dentry->d_inode) {
+				if (status != -ENOENT)
 					printk("autofs warning: lookup failure on positive dentry, status = %d, name = %s\n", status, dentry->d_name.name);
 				return 0; /* Try to get the kernel to invalidate this dentry */
 			}
@@ -106,7 +106,7 @@
 				return 1;
 			}
 			status = autofs_wait(sbi, &dentry->d_name);
-		} while (!(ent = autofs_hash_lookup(&sbi->dirhash, &dentry->d_name)) );
+		} while (!(ent = autofs_hash_lookup(&sbi->dirhash, &dentry->d_name)));
 	}
 
 	/* Abuse this field as a pointer to the directory entry, used to
@@ -124,13 +124,13 @@
 
 	/* If this is a directory that isn't a mount point, bitch at the
 	   daemon and fix it in user space */
-	if ( S_ISDIR(dentry->d_inode->i_mode) && !d_mountpoint(dentry) ) {
+	if (S_ISDIR(dentry->d_inode->i_mode) && !d_mountpoint(dentry)) {
 		return !autofs_wait(sbi, &dentry->d_name);
 	}
 
 	/* We don't update the usages for the autofs daemon itself, this
 	   is necessary for recursive autofs mounts */
-	if ( !autofs_oz_mode(sbi) ) {
+	if (!autofs_oz_mode(sbi)) {
 		autofs_update_usage(&sbi->dirhash,ent);
 	}
 
@@ -157,7 +157,7 @@
 	sbi = autofs_sbi(dir->i_sb);
 
 	/* Pending dentry */
-	if ( dentry->d_flags & DCACHE_AUTOFS_PENDING ) {
+	if (dentry->d_flags & DCACHE_AUTOFS_PENDING) {
 		if (autofs_oz_mode(sbi))
 			res = 1;
 		else
@@ -173,7 +173,7 @@
 	}
 		
 	/* Check for a non-mountpoint directory */
-	if ( S_ISDIR(dentry->d_inode->i_mode) && !d_mountpoint(dentry) ) {
+	if (S_ISDIR(dentry->d_inode->i_mode) && !d_mountpoint(dentry)) {
 		if (autofs_oz_mode(sbi))
 			res = 1;
 		else
@@ -183,9 +183,9 @@
 	}
 
 	/* Update the usage list */
-	if ( !autofs_oz_mode(sbi) ) {
+	if (!autofs_oz_mode(sbi)) {
 		ent = (struct autofs_dir_ent *) dentry->d_time;
-		if ( ent )
+		if (ent)
 			autofs_update_usage(&sbi->dirhash,ent);
 	}
 	unlock_kernel();
@@ -213,8 +213,10 @@
 	sbi = autofs_sbi(dir->i_sb);
 
 	oz_mode = autofs_oz_mode(sbi);
-	DPRINTK(("autofs_lookup: pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d\n",
-		 current->pid, process_group(current), sbi->catatonic, oz_mode));
+	DPRINTK(("autofs_lookup: pid = %u, pgrp = %u, catatonic = %d, "
+				"oz_mode = %d\n", pid_nr(task_pid(current)),
+				process_group(current), sbi->catatonic,
+				oz_mode));
 
 	/*
 	 * Mark the dentry incomplete, but add it. This is needed so
@@ -258,7 +260,7 @@
 	 * doesn't do the right thing for all system calls, but it should
 	 * be OK for the operations we permit from an autofs.
 	 */
-	if ( dentry->d_inode && d_unhashed(dentry) )
+	if (dentry->d_inode && d_unhashed(dentry))
 		return ERR_PTR(-ENOENT);
 
 	return NULL;
@@ -277,18 +279,18 @@
 	autofs_say(dentry->d_name.name,dentry->d_name.len);
 
 	lock_kernel();
-	if ( !autofs_oz_mode(sbi) ) {
+	if (!autofs_oz_mode(sbi)) {
 		unlock_kernel();
 		return -EACCES;
 	}
 
-	if ( autofs_hash_lookup(dh, &dentry->d_name) ) {
+	if (autofs_hash_lookup(dh, &dentry->d_name)) {
 		unlock_kernel();
 		return -EEXIST;
 	}
 
 	n = find_first_zero_bit(sbi->symlink_bitmap,AUTOFS_MAX_SYMLINKS);
-	if ( n >= AUTOFS_MAX_SYMLINKS ) {
+	if (n >= AUTOFS_MAX_SYMLINKS) {
 		unlock_kernel();
 		return -ENOSPC;
 	}
@@ -297,14 +299,14 @@
 	sl = &sbi->symlink[n];
 	sl->len = strlen(symname);
 	sl->data = kmalloc(slsize = sl->len+1, GFP_KERNEL);
-	if ( !sl->data ) {
+	if (!sl->data) {
 		clear_bit(n,sbi->symlink_bitmap);
 		unlock_kernel();
 		return -ENOSPC;
 	}
 
 	ent = kmalloc(sizeof(struct autofs_dir_ent), GFP_KERNEL);
-	if ( !ent ) {
+	if (!ent) {
 		kfree(sl->data);
 		clear_bit(n,sbi->symlink_bitmap);
 		unlock_kernel();
@@ -312,7 +314,7 @@
 	}
 
 	ent->name = kmalloc(dentry->d_name.len+1, GFP_KERNEL);
-	if ( !ent->name ) {
+	if (!ent->name) {
 		kfree(sl->data);
 		kfree(ent);
 		clear_bit(n,sbi->symlink_bitmap);
@@ -354,23 +356,23 @@
 
 	/* This allows root to remove symlinks */
 	lock_kernel();
-	if ( !autofs_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) ) {
+	if (!autofs_oz_mode(sbi) && !capable(CAP_SYS_ADMIN)) {
 		unlock_kernel();
 		return -EACCES;
 	}
 
 	ent = autofs_hash_lookup(dh, &dentry->d_name);
-	if ( !ent ) {
+	if (!ent) {
 		unlock_kernel();
 		return -ENOENT;
 	}
 
 	n = ent->ino - AUTOFS_FIRST_SYMLINK;
-	if ( n >= AUTOFS_MAX_SYMLINKS ) {
+	if (n >= AUTOFS_MAX_SYMLINKS) {
 		unlock_kernel();
 		return -EISDIR;	/* It's a directory, dummy */
 	}
-	if ( !test_bit(n,sbi->symlink_bitmap) ) {
+	if (!test_bit(n,sbi->symlink_bitmap)) {
 		unlock_kernel();
 		return -EINVAL;	/* Nonexistent symlink?  Shouldn't happen */
 	}
@@ -392,23 +394,23 @@
 	struct autofs_dir_ent *ent;
 
 	lock_kernel();
-	if ( !autofs_oz_mode(sbi) ) {
+	if (!autofs_oz_mode(sbi)) {
 		unlock_kernel();
 		return -EACCES;
 	}
 
 	ent = autofs_hash_lookup(dh, &dentry->d_name);
-	if ( !ent ) {
+	if (!ent) {
 		unlock_kernel();
 		return -ENOENT;
 	}
 
-	if ( (unsigned int)ent->ino < AUTOFS_FIRST_DIR_INO ) {
+	if ((unsigned int)ent->ino < AUTOFS_FIRST_DIR_INO) {
 		unlock_kernel();
 		return -ENOTDIR; /* Not a directory */
 	}
 
-	if ( ent->dentry != dentry ) {
+	if (ent->dentry != dentry) {
 		printk("autofs_rmdir: odentry != dentry for entry %s\n", dentry->d_name.name);
 	}
 
@@ -429,18 +431,18 @@
 	ino_t ino;
 
 	lock_kernel();
-	if ( !autofs_oz_mode(sbi) ) {
+	if (!autofs_oz_mode(sbi)) {
 		unlock_kernel();
 		return -EACCES;
 	}
 
 	ent = autofs_hash_lookup(dh, &dentry->d_name);
-	if ( ent ) {
+	if (ent) {
 		unlock_kernel();
 		return -EEXIST;
 	}
 
-	if ( sbi->next_dir_ino < AUTOFS_FIRST_DIR_INO ) {
+	if (sbi->next_dir_ino < AUTOFS_FIRST_DIR_INO) {
 		printk("autofs: Out of inode numbers -- what the heck did you do??\n");
 		unlock_kernel();
 		return -ENOSPC;
@@ -448,13 +450,13 @@
 	ino = sbi->next_dir_ino++;
 
 	ent = kmalloc(sizeof(struct autofs_dir_ent), GFP_KERNEL);
-	if ( !ent ) {
+	if (!ent) {
 		unlock_kernel();
 		return -ENOSPC;
 	}
 
 	ent->name = kmalloc(dentry->d_name.len+1, GFP_KERNEL);
-	if ( !ent->name ) {
+	if (!ent->name) {
 		kfree(ent);
 		unlock_kernel();
 		return -ENOSPC;
@@ -483,7 +485,7 @@
 	    put_user(sbi->exp_timeout / HZ, p))
 		return -EFAULT;
 
-	if ( ntimeout > ULONG_MAX/HZ )
+	if (ntimeout > ULONG_MAX/HZ)
 		sbi->exp_timeout = 0;
 	else
 		sbi->exp_timeout = ntimeout * HZ;
@@ -511,15 +513,14 @@
 	pkt.hdr.proto_version = AUTOFS_PROTO_VERSION;
 	pkt.hdr.type = autofs_ptype_expire;
 
-	if ( !sbi->exp_timeout ||
-	     !(ent = autofs_expire(sb,sbi,mnt)) )
+	if (!sbi->exp_timeout || !(ent = autofs_expire(sb,sbi,mnt)))
 		return -EAGAIN;
 
 	pkt.len = ent->len;
 	memcpy(pkt.name, ent->name, pkt.len);
 	pkt.name[pkt.len] = '\0';
 
-	if ( copy_to_user(pkt_p, &pkt, sizeof(struct autofs_packet_expire)) )
+	if (copy_to_user(pkt_p, &pkt, sizeof(struct autofs_packet_expire)))
 		return -EFAULT;
 
 	return 0;
@@ -537,11 +538,11 @@
 
 	DPRINTK(("autofs_ioctl: cmd = 0x%08x, arg = 0x%08lx, sbi = %p, pgrp = %u\n",cmd,arg,sbi,process_group(current)));
 
-	if ( _IOC_TYPE(cmd) != _IOC_TYPE(AUTOFS_IOC_FIRST) ||
-	     _IOC_NR(cmd) - _IOC_NR(AUTOFS_IOC_FIRST) >= AUTOFS_IOC_COUNT )
+	if (_IOC_TYPE(cmd) != _IOC_TYPE(AUTOFS_IOC_FIRST) ||
+	     _IOC_NR(cmd) - _IOC_NR(AUTOFS_IOC_FIRST) >= AUTOFS_IOC_COUNT)
 		return -ENOTTY;
 	
-	if ( !autofs_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) )
+	if (!autofs_oz_mode(sbi) && !capable(CAP_SYS_ADMIN))
 		return -EPERM;
 	
 	switch(cmd) {
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
index 5769a2f..692364e8 100644
--- a/fs/autofs4/inode.c
+++ b/fs/autofs4/inode.c
@@ -218,8 +218,7 @@
 };
 
 static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid,
-			 pid_t *pgrp, unsigned int *type,
-			 int *minproto, int *maxproto)
+		pid_t *pgrp, unsigned int *type, int *minproto, int *maxproto)
 {
 	char *p;
 	substring_t args[MAX_OPT_ARGS];
@@ -314,7 +313,7 @@
 	struct autofs_info *ino;
 
 	sbi = kmalloc(sizeof(*sbi), GFP_KERNEL);
-	if ( !sbi )
+	if (!sbi)
 		goto fail_unlock;
 	DPRINTK("starting up, sbi = %p",sbi);
 
@@ -363,10 +362,9 @@
 	root->d_fsdata = ino;
 
 	/* Can this call block? */
-	if (parse_options(data, &pipefd,
-			  &root_inode->i_uid, &root_inode->i_gid,
-			  &sbi->oz_pgrp, &sbi->type,
-			  &sbi->min_proto, &sbi->max_proto)) {
+	if (parse_options(data, &pipefd, &root_inode->i_uid, &root_inode->i_gid,
+				&sbi->oz_pgrp, &sbi->type, &sbi->min_proto,
+				&sbi->max_proto)) {
 		printk("autofs: called with bogus options\n");
 		goto fail_dput;
 	}
@@ -396,11 +394,11 @@
 	DPRINTK("pipe fd = %d, pgrp = %u", pipefd, sbi->oz_pgrp);
 	pipe = fget(pipefd);
 	
-	if ( !pipe ) {
+	if (!pipe) {
 		printk("autofs: could not open pipe file descriptor\n");
 		goto fail_dput;
 	}
-	if ( !pipe->f_op || !pipe->f_op->write )
+	if (!pipe->f_op || !pipe->f_op->write)
 		goto fail_fput;
 	sbi->pipe = pipe;
 	sbi->pipefd = pipefd;
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index 15170f4..2d4c8a3 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -759,7 +759,7 @@
 	struct autofs_info *p_ino;
 	
 	/* This allows root to remove symlinks */
-	if ( !autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) )
+	if (!autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN))
 		return -EACCES;
 
 	if (atomic_dec_and_test(&ino->count)) {
@@ -833,7 +833,7 @@
 	struct autofs_info *p_ino;
 	struct inode *inode;
 
-	if ( !autofs4_oz_mode(sbi) )
+	if (!autofs4_oz_mode(sbi))
 		return -EACCES;
 
 	DPRINTK("dentry %p, creating %.*s",
@@ -871,11 +871,11 @@
 	int rv;
 	unsigned long ntimeout;
 
-	if ( (rv = get_user(ntimeout, p)) ||
-	     (rv = put_user(sbi->exp_timeout/HZ, p)) )
+	if ((rv = get_user(ntimeout, p)) ||
+	     (rv = put_user(sbi->exp_timeout/HZ, p)))
 		return rv;
 
-	if ( ntimeout > ULONG_MAX/HZ )
+	if (ntimeout > ULONG_MAX/HZ)
 		sbi->exp_timeout = 0;
 	else
 		sbi->exp_timeout = ntimeout * HZ;
@@ -906,7 +906,7 @@
 	DPRINTK("returning %d", sbi->needs_reghost);
 
 	status = put_user(sbi->needs_reghost, p);
-	if ( status )
+	if (status)
 		return status;
 
 	sbi->needs_reghost = 0;
@@ -975,11 +975,11 @@
 	DPRINTK("cmd = 0x%08x, arg = 0x%08lx, sbi = %p, pgrp = %u",
 		cmd,arg,sbi,process_group(current));
 
-	if ( _IOC_TYPE(cmd) != _IOC_TYPE(AUTOFS_IOC_FIRST) ||
-	     _IOC_NR(cmd) - _IOC_NR(AUTOFS_IOC_FIRST) >= AUTOFS_IOC_COUNT )
+	if (_IOC_TYPE(cmd) != _IOC_TYPE(AUTOFS_IOC_FIRST) ||
+	     _IOC_NR(cmd) - _IOC_NR(AUTOFS_IOC_FIRST) >= AUTOFS_IOC_COUNT)
 		return -ENOTTY;
 	
-	if ( !autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) )
+	if (!autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN))
 		return -EPERM;
 	
 	switch(cmd) {
diff --git a/fs/compat.c b/fs/compat.c
index 9cf75df..7b21b0a 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -46,6 +46,7 @@
 #include <linux/tsacct_kern.h>
 #include <linux/security.h>
 #include <linux/highmem.h>
+#include <linux/signal.h>
 #include <linux/poll.h>
 #include <linux/mm.h>
 #include <linux/eventpoll.h>
@@ -2199,3 +2200,51 @@
 #endif /* TIF_RESTORE_SIGMASK */
 
 #endif /* CONFIG_EPOLL */
+
+#ifdef CONFIG_SIGNALFD
+
+asmlinkage long compat_sys_signalfd(int ufd,
+				    const compat_sigset_t __user *sigmask,
+				    compat_size_t sigsetsize)
+{
+	compat_sigset_t ss32;
+	sigset_t tmp;
+	sigset_t __user *ksigmask;
+
+	if (sigsetsize != sizeof(compat_sigset_t))
+		return -EINVAL;
+	if (copy_from_user(&ss32, sigmask, sizeof(ss32)))
+		return -EFAULT;
+	sigset_from_compat(&tmp, &ss32);
+	ksigmask = compat_alloc_user_space(sizeof(sigset_t));
+	if (copy_to_user(ksigmask, &tmp, sizeof(sigset_t)))
+		return -EFAULT;
+
+	return sys_signalfd(ufd, ksigmask, sizeof(sigset_t));
+}
+
+#endif /* CONFIG_SIGNALFD */
+
+#ifdef CONFIG_TIMERFD
+
+asmlinkage long compat_sys_timerfd(int ufd, int clockid, int flags,
+				   const struct compat_itimerspec __user *utmr)
+{
+	long res;
+	struct itimerspec t;
+	struct itimerspec __user *ut;
+
+	res = -EFAULT;
+	if (get_compat_itimerspec(&t, utmr))
+		goto err_exit;
+	ut = compat_alloc_user_space(sizeof(*ut));
+	if (copy_to_user(ut, &t, sizeof(t)) )
+		goto err_exit;
+
+	res = sys_timerfd(ufd, clockid, flags, ut);
+err_exit:
+	return res;
+}
+
+#endif /* CONFIG_TIMERFD */
+
diff --git a/fs/eventfd.c b/fs/eventfd.c
new file mode 100644
index 0000000..480e2b3
--- /dev/null
+++ b/fs/eventfd.c
@@ -0,0 +1,228 @@
+/*
+ *  fs/eventfd.c
+ *
+ *  Copyright (C) 2007  Davide Libenzi <davidel@xmailserver.org>
+ *
+ */
+
+#include <linux/file.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/anon_inodes.h>
+#include <linux/eventfd.h>
+
+struct eventfd_ctx {
+	spinlock_t lock;
+	wait_queue_head_t wqh;
+	/*
+	 * Every time that a write(2) is performed on an eventfd, the
+	 * value of the __u64 being written is added to "count" and a
+	 * wakeup is performed on "wqh". A read(2) will return the "count"
+	 * value to userspace, and will reset "count" to zero. The kernel
+	 * size eventfd_signal() also, adds to the "count" counter and
+	 * issue a wakeup.
+	 */
+	__u64 count;
+};
+
+/*
+ * Adds "n" to the eventfd counter "count". Returns "n" in case of
+ * success, or a value lower then "n" in case of coutner overflow.
+ * This function is supposed to be called by the kernel in paths
+ * that do not allow sleeping. In this function we allow the counter
+ * to reach the ULLONG_MAX value, and we signal this as overflow
+ * condition by returining a POLLERR to poll(2).
+ */
+int eventfd_signal(struct file *file, int n)
+{
+	struct eventfd_ctx *ctx = file->private_data;
+	unsigned long flags;
+
+	if (n < 0)
+		return -EINVAL;
+	spin_lock_irqsave(&ctx->lock, flags);
+	if (ULLONG_MAX - ctx->count < n)
+		n = (int) (ULLONG_MAX - ctx->count);
+	ctx->count += n;
+	if (waitqueue_active(&ctx->wqh))
+		wake_up_locked(&ctx->wqh);
+	spin_unlock_irqrestore(&ctx->lock, flags);
+
+	return n;
+}
+
+static int eventfd_release(struct inode *inode, struct file *file)
+{
+	kfree(file->private_data);
+	return 0;
+}
+
+static unsigned int eventfd_poll(struct file *file, poll_table *wait)
+{
+	struct eventfd_ctx *ctx = file->private_data;
+	unsigned int events = 0;
+	unsigned long flags;
+
+	poll_wait(file, &ctx->wqh, wait);
+
+	spin_lock_irqsave(&ctx->lock, flags);
+	if (ctx->count > 0)
+		events |= POLLIN;
+	if (ctx->count == ULLONG_MAX)
+		events |= POLLERR;
+	if (ULLONG_MAX - 1 > ctx->count)
+		events |= POLLOUT;
+	spin_unlock_irqrestore(&ctx->lock, flags);
+
+	return events;
+}
+
+static ssize_t eventfd_read(struct file *file, char __user *buf, size_t count,
+			    loff_t *ppos)
+{
+	struct eventfd_ctx *ctx = file->private_data;
+	ssize_t res;
+	__u64 ucnt;
+	DECLARE_WAITQUEUE(wait, current);
+
+	if (count < sizeof(ucnt))
+		return -EINVAL;
+	spin_lock_irq(&ctx->lock);
+	res = -EAGAIN;
+	ucnt = ctx->count;
+	if (ucnt > 0)
+		res = sizeof(ucnt);
+	else if (!(file->f_flags & O_NONBLOCK)) {
+		__add_wait_queue(&ctx->wqh, &wait);
+		for (res = 0;;) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			if (ctx->count > 0) {
+				ucnt = ctx->count;
+				res = sizeof(ucnt);
+				break;
+			}
+			if (signal_pending(current)) {
+				res = -ERESTARTSYS;
+				break;
+			}
+			spin_unlock_irq(&ctx->lock);
+			schedule();
+			spin_lock_irq(&ctx->lock);
+		}
+		__remove_wait_queue(&ctx->wqh, &wait);
+		__set_current_state(TASK_RUNNING);
+	}
+	if (res > 0) {
+		ctx->count = 0;
+		if (waitqueue_active(&ctx->wqh))
+			wake_up_locked(&ctx->wqh);
+	}
+	spin_unlock_irq(&ctx->lock);
+	if (res > 0 && put_user(ucnt, (__u64 __user *) buf))
+		return -EFAULT;
+
+	return res;
+}
+
+static ssize_t eventfd_write(struct file *file, const char __user *buf, size_t count,
+			     loff_t *ppos)
+{
+	struct eventfd_ctx *ctx = file->private_data;
+	ssize_t res;
+	__u64 ucnt;
+	DECLARE_WAITQUEUE(wait, current);
+
+	if (count < sizeof(ucnt))
+		return -EINVAL;
+	if (copy_from_user(&ucnt, buf, sizeof(ucnt)))
+		return -EFAULT;
+	if (ucnt == ULLONG_MAX)
+		return -EINVAL;
+	spin_lock_irq(&ctx->lock);
+	res = -EAGAIN;
+	if (ULLONG_MAX - ctx->count > ucnt)
+		res = sizeof(ucnt);
+	else if (!(file->f_flags & O_NONBLOCK)) {
+		__add_wait_queue(&ctx->wqh, &wait);
+		for (res = 0;;) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			if (ULLONG_MAX - ctx->count > ucnt) {
+				res = sizeof(ucnt);
+				break;
+			}
+			if (signal_pending(current)) {
+				res = -ERESTARTSYS;
+				break;
+			}
+			spin_unlock_irq(&ctx->lock);
+			schedule();
+			spin_lock_irq(&ctx->lock);
+		}
+		__remove_wait_queue(&ctx->wqh, &wait);
+		__set_current_state(TASK_RUNNING);
+	}
+	if (res > 0) {
+		ctx->count += ucnt;
+		if (waitqueue_active(&ctx->wqh))
+			wake_up_locked(&ctx->wqh);
+	}
+	spin_unlock_irq(&ctx->lock);
+
+	return res;
+}
+
+static const struct file_operations eventfd_fops = {
+	.release	= eventfd_release,
+	.poll		= eventfd_poll,
+	.read		= eventfd_read,
+	.write		= eventfd_write,
+};
+
+struct file *eventfd_fget(int fd)
+{
+	struct file *file;
+
+	file = fget(fd);
+	if (!file)
+		return ERR_PTR(-EBADF);
+	if (file->f_op != &eventfd_fops) {
+		fput(file);
+		return ERR_PTR(-EINVAL);
+	}
+
+	return file;
+}
+
+asmlinkage long sys_eventfd(unsigned int count)
+{
+	int error, fd;
+	struct eventfd_ctx *ctx;
+	struct file *file;
+	struct inode *inode;
+
+	ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	init_waitqueue_head(&ctx->wqh);
+	spin_lock_init(&ctx->lock);
+	ctx->count = count;
+
+	/*
+	 * When we call this, the initialization must be complete, since
+	 * anon_inode_getfd() will install the fd.
+	 */
+	error = anon_inode_getfd(&fd, &inode, &file, "[eventfd]",
+				 &eventfd_fops, ctx);
+	if (!error)
+		return fd;
+
+	kfree(ctx);
+	return error;
+}
+
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
index b5c7ca5..1aad34e 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -11,7 +11,6 @@
  *
  */
 
-#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -34,6 +33,7 @@
 #include <linux/mount.h>
 #include <linux/bitops.h>
 #include <linux/mutex.h>
+#include <linux/anon_inodes.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/io.h>
@@ -41,7 +41,6 @@
 #include <asm/atomic.h>
 #include <asm/semaphore.h>
 
-
 /*
  * LOCKING:
  * There are three level of locking required by epoll :
@@ -74,9 +73,6 @@
  * a greater scalability.
  */
 
-
-#define EVENTPOLLFS_MAGIC 0x03111965 /* My birthday should work for this :) */
-
 #define DEBUG_EPOLL 0
 
 #if DEBUG_EPOLL > 0
@@ -106,7 +102,6 @@
 
 #define EP_MAX_EVENTS (INT_MAX / sizeof(struct epoll_event))
 
-
 struct epoll_filefd {
 	struct file *file;
 	int fd;
@@ -224,43 +219,6 @@
 	struct epitem *epi;
 };
 
-
-
-static void ep_poll_safewake_init(struct poll_safewake *psw);
-static void ep_poll_safewake(struct poll_safewake *psw, wait_queue_head_t *wq);
-static int ep_getfd(int *efd, struct inode **einode, struct file **efile,
-		    struct eventpoll *ep);
-static int ep_alloc(struct eventpoll **pep);
-static void ep_free(struct eventpoll *ep);
-static struct epitem *ep_find(struct eventpoll *ep, struct file *file, int fd);
-static void ep_use_epitem(struct epitem *epi);
-static void ep_release_epitem(struct epitem *epi);
-static void ep_ptable_queue_proc(struct file *file, wait_queue_head_t *whead,
-				 poll_table *pt);
-static void ep_rbtree_insert(struct eventpoll *ep, struct epitem *epi);
-static int ep_insert(struct eventpoll *ep, struct epoll_event *event,
-		     struct file *tfile, int fd);
-static int ep_modify(struct eventpoll *ep, struct epitem *epi,
-		     struct epoll_event *event);
-static void ep_unregister_pollwait(struct eventpoll *ep, struct epitem *epi);
-static int ep_unlink(struct eventpoll *ep, struct epitem *epi);
-static int ep_remove(struct eventpoll *ep, struct epitem *epi);
-static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *key);
-static int ep_eventpoll_close(struct inode *inode, struct file *file);
-static unsigned int ep_eventpoll_poll(struct file *file, poll_table *wait);
-static int ep_send_events(struct eventpoll *ep, struct list_head *txlist,
-			  struct epoll_event __user *events, int maxevents);
-static int ep_events_transfer(struct eventpoll *ep,
-			      struct epoll_event __user *events,
-			      int maxevents);
-static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,
-		   int maxevents, long timeout);
-static int eventpollfs_delete_dentry(struct dentry *dentry);
-static struct inode *ep_eventpoll_inode(void);
-static int eventpollfs_get_sb(struct file_system_type *fs_type,
-			      int flags, const char *dev_name,
-			      void *data, struct vfsmount *mnt);
-
 /*
  * This semaphore is used to serialize ep_free() and eventpoll_release_file().
  */
@@ -275,37 +233,6 @@
 /* Slab cache used to allocate "struct eppoll_entry" */
 static struct kmem_cache *pwq_cache __read_mostly;
 
-/* Virtual fs used to allocate inodes for eventpoll files */
-static struct vfsmount *eventpoll_mnt __read_mostly;
-
-/* File callbacks that implement the eventpoll file behaviour */
-static const struct file_operations eventpoll_fops = {
-	.release	= ep_eventpoll_close,
-	.poll		= ep_eventpoll_poll
-};
-
-/*
- * This is used to register the virtual file system from where
- * eventpoll inodes are allocated.
- */
-static struct file_system_type eventpoll_fs_type = {
-	.name		= "eventpollfs",
-	.get_sb		= eventpollfs_get_sb,
-	.kill_sb	= kill_anon_super,
-};
-
-/* Very basic directory entry operations for the eventpoll virtual file system */
-static struct dentry_operations eventpollfs_dentry_operations = {
-	.d_delete	= eventpollfs_delete_dentry,
-};
-
-
-
-/* Fast test to see if the file is an evenpoll file */
-static inline int is_file_epoll(struct file *f)
-{
-	return f->f_op == &eventpoll_fops;
-}
 
 /* Setup the structure that is used as key for the rb-tree */
 static inline void ep_set_ffd(struct epoll_filefd *ffd,
@@ -374,7 +301,6 @@
 	spin_lock_init(&psw->lock);
 }
 
-
 /*
  * Perform a safe wake up of the poll wait list. The problem is that
  * with the new callback'd wake up system, it is possible that the
@@ -429,400 +355,145 @@
 	spin_unlock_irqrestore(&psw->lock, flags);
 }
 
+/*
+ * This function unregister poll callbacks from the associated file descriptor.
+ * Since this must be called without holding "ep->lock" the atomic exchange trick
+ * will protect us from multiple unregister.
+ */
+static void ep_unregister_pollwait(struct eventpoll *ep, struct epitem *epi)
+{
+	int nwait;
+	struct list_head *lsthead = &epi->pwqlist;
+	struct eppoll_entry *pwq;
+
+	/* This is called without locks, so we need the atomic exchange */
+	nwait = xchg(&epi->nwait, 0);
+
+	if (nwait) {
+		while (!list_empty(lsthead)) {
+			pwq = list_first_entry(lsthead, struct eppoll_entry, llink);
+
+			list_del_init(&pwq->llink);
+			remove_wait_queue(pwq->whead, &pwq->wait);
+			kmem_cache_free(pwq_cache, pwq);
+		}
+	}
+}
 
 /*
- * This is called from eventpoll_release() to unlink files from the eventpoll
- * interface. We need to have this facility to cleanup correctly files that are
- * closed without being removed from the eventpoll interface.
+ * Unlink the "struct epitem" from all places it might have been hooked up.
+ * This function must be called with write IRQ lock on "ep->lock".
  */
-void eventpoll_release_file(struct file *file)
+static int ep_unlink(struct eventpoll *ep, struct epitem *epi)
 {
-	struct list_head *lsthead = &file->f_ep_links;
-	struct eventpoll *ep;
-	struct epitem *epi;
+	int error;
 
 	/*
-	 * We don't want to get "file->f_ep_lock" because it is not
-	 * necessary. It is not necessary because we're in the "struct file"
-	 * cleanup path, and this means that noone is using this file anymore.
-	 * The only hit might come from ep_free() but by holding the semaphore
-	 * will correctly serialize the operation. We do need to acquire
-	 * "ep->sem" after "epmutex" because ep_remove() requires it when called
-	 * from anywhere but ep_free().
+	 * It can happen that this one is called for an item already unlinked.
+	 * The check protect us from doing a double unlink ( crash ).
 	 */
-	mutex_lock(&epmutex);
+	error = -ENOENT;
+	if (!ep_rb_linked(&epi->rbn))
+		goto error_return;
 
-	while (!list_empty(lsthead)) {
-		epi = list_first_entry(lsthead, struct epitem, fllink);
+	/*
+	 * Clear the event mask for the unlinked item. This will avoid item
+	 * notifications to be sent after the unlink operation from inside
+	 * the kernel->userspace event transfer loop.
+	 */
+	epi->event.events = 0;
 
-		ep = epi->ep;
+	/*
+	 * At this point is safe to do the job, unlink the item from our rb-tree.
+	 * This operation togheter with the above check closes the door to
+	 * double unlinks.
+	 */
+	ep_rb_erase(&epi->rbn, &ep->rbr);
+
+	/*
+	 * If the item we are going to remove is inside the ready file descriptors
+	 * we want to remove it from this list to avoid stale events.
+	 */
+	if (ep_is_linked(&epi->rdllink))
+		list_del_init(&epi->rdllink);
+
+	error = 0;
+error_return:
+
+	DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_unlink(%p, %p) = %d\n",
+		     current, ep, epi->ffd.file, error));
+
+	return error;
+}
+
+/*
+ * Increment the usage count of the "struct epitem" making it sure
+ * that the user will have a valid pointer to reference.
+ */
+static void ep_use_epitem(struct epitem *epi)
+{
+	atomic_inc(&epi->usecnt);
+}
+
+/*
+ * Decrement ( release ) the usage count by signaling that the user
+ * has finished using the structure. It might lead to freeing the
+ * structure itself if the count goes to zero.
+ */
+static void ep_release_epitem(struct epitem *epi)
+{
+	if (atomic_dec_and_test(&epi->usecnt))
+		kmem_cache_free(epi_cache, epi);
+}
+
+/*
+ * Removes a "struct epitem" from the eventpoll RB tree and deallocates
+ * all the associated resources.
+ */
+static int ep_remove(struct eventpoll *ep, struct epitem *epi)
+{
+	int error;
+	unsigned long flags;
+	struct file *file = epi->ffd.file;
+
+	/*
+	 * Removes poll wait queue hooks. We _have_ to do this without holding
+	 * the "ep->lock" otherwise a deadlock might occur. This because of the
+	 * sequence of the lock acquisition. Here we do "ep->lock" then the wait
+	 * queue head lock when unregistering the wait queue. The wakeup callback
+	 * will run by holding the wait queue head lock and will call our callback
+	 * that will try to get "ep->lock".
+	 */
+	ep_unregister_pollwait(ep, epi);
+
+	/* Remove the current item from the list of epoll hooks */
+	spin_lock(&file->f_ep_lock);
+	if (ep_is_linked(&epi->fllink))
 		list_del_init(&epi->fllink);
-		down_write(&ep->sem);
-		ep_remove(ep, epi);
-		up_write(&ep->sem);
-	}
+	spin_unlock(&file->f_ep_lock);
 
-	mutex_unlock(&epmutex);
-}
+	/* We need to acquire the write IRQ lock before calling ep_unlink() */
+	write_lock_irqsave(&ep->lock, flags);
 
+	/* Really unlink the item from the RB tree */
+	error = ep_unlink(ep, epi);
 
-/*
- * It opens an eventpoll file descriptor by suggesting a storage of "size"
- * file descriptors. The size parameter is just an hint about how to size
- * data structures. It won't prevent the user to store more than "size"
- * file descriptors inside the epoll interface. It is the kernel part of
- * the userspace epoll_create(2).
- */
-asmlinkage long sys_epoll_create(int size)
-{
-	int error, fd = -1;
-	struct eventpoll *ep;
-	struct inode *inode;
-	struct file *file;
+	write_unlock_irqrestore(&ep->lock, flags);
 
-	DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d)\n",
-		     current, size));
-
-	/*
-	 * Sanity check on the size parameter, and create the internal data
-	 * structure ( "struct eventpoll" ).
-	 */
-	error = -EINVAL;
-	if (size <= 0 || (error = ep_alloc(&ep)) != 0)
-		goto eexit_1;
-
-	/*
-	 * Creates all the items needed to setup an eventpoll file. That is,
-	 * a file structure, and inode and a free file descriptor.
-	 */
-	error = ep_getfd(&fd, &inode, &file, ep);
 	if (error)
-		goto eexit_2;
+		goto error_return;
 
-	DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n",
-		     current, size, fd));
+	/* At this point it is safe to free the eventpoll item */
+	ep_release_epitem(epi);
 
-	return fd;
-
-eexit_2:
-	ep_free(ep);
-	kfree(ep);
-eexit_1:
-	DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n",
-		     current, size, error));
-	return error;
-}
-
-
-/*
- * The following function implements the controller interface for
- * the eventpoll file that enables the insertion/removal/change of
- * file descriptors inside the interest set.  It represents
- * the kernel part of the user space epoll_ctl(2).
- */
-asmlinkage long
-sys_epoll_ctl(int epfd, int op, int fd, struct epoll_event __user *event)
-{
-	int error;
-	struct file *file, *tfile;
-	struct eventpoll *ep;
-	struct epitem *epi;
-	struct epoll_event epds;
-
-	DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_ctl(%d, %d, %d, %p)\n",
-		     current, epfd, op, fd, event));
-
-	error = -EFAULT;
-	if (ep_op_has_event(op) &&
-	    copy_from_user(&epds, event, sizeof(struct epoll_event)))
-		goto eexit_1;
-
-	/* Get the "struct file *" for the eventpoll file */
-	error = -EBADF;
-	file = fget(epfd);
-	if (!file)
-		goto eexit_1;
-
-	/* Get the "struct file *" for the target file */
-	tfile = fget(fd);
-	if (!tfile)
-		goto eexit_2;
-
-	/* The target file descriptor must support poll */
-	error = -EPERM;
-	if (!tfile->f_op || !tfile->f_op->poll)
-		goto eexit_3;
-
-	/*
-	 * We have to check that the file structure underneath the file descriptor
-	 * the user passed to us _is_ an eventpoll file. And also we do not permit
-	 * adding an epoll file descriptor inside itself.
-	 */
-	error = -EINVAL;
-	if (file == tfile || !is_file_epoll(file))
-		goto eexit_3;
-
-	/*
-	 * At this point it is safe to assume that the "private_data" contains
-	 * our own data structure.
-	 */
-	ep = file->private_data;
-
-	down_write(&ep->sem);
-
-	/* Try to lookup the file inside our RB tree */
-	epi = ep_find(ep, tfile, fd);
-
-	error = -EINVAL;
-	switch (op) {
-	case EPOLL_CTL_ADD:
-		if (!epi) {
-			epds.events |= POLLERR | POLLHUP;
-
-			error = ep_insert(ep, &epds, tfile, fd);
-		} else
-			error = -EEXIST;
-		break;
-	case EPOLL_CTL_DEL:
-		if (epi)
-			error = ep_remove(ep, epi);
-		else
-			error = -ENOENT;
-		break;
-	case EPOLL_CTL_MOD:
-		if (epi) {
-			epds.events |= POLLERR | POLLHUP;
-			error = ep_modify(ep, epi, &epds);
-		} else
-			error = -ENOENT;
-		break;
-	}
-
-	/*
-	 * The function ep_find() increments the usage count of the structure
-	 * so, if this is not NULL, we need to release it.
-	 */
-	if (epi)
-		ep_release_epitem(epi);
-
-	up_write(&ep->sem);
-
-eexit_3:
-	fput(tfile);
-eexit_2:
-	fput(file);
-eexit_1:
-	DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_ctl(%d, %d, %d, %p) = %d\n",
-		     current, epfd, op, fd, event, error));
+	error = 0;
+error_return:
+	DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_remove(%p, %p) = %d\n",
+		     current, ep, file, error));
 
 	return error;
 }
 
-
-/*
- * Implement the event wait interface for the eventpoll file. It is the kernel
- * part of the user space epoll_wait(2).
- */
-asmlinkage long sys_epoll_wait(int epfd, struct epoll_event __user *events,
-			       int maxevents, int timeout)
-{
-	int error;
-	struct file *file;
-	struct eventpoll *ep;
-
-	DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_wait(%d, %p, %d, %d)\n",
-		     current, epfd, events, maxevents, timeout));
-
-	/* The maximum number of event must be greater than zero */
-	if (maxevents <= 0 || maxevents > EP_MAX_EVENTS)
-		return -EINVAL;
-
-	/* Verify that the area passed by the user is writeable */
-	if (!access_ok(VERIFY_WRITE, events, maxevents * sizeof(struct epoll_event))) {
-		error = -EFAULT;
-		goto eexit_1;
-	}
-
-	/* Get the "struct file *" for the eventpoll file */
-	error = -EBADF;
-	file = fget(epfd);
-	if (!file)
-		goto eexit_1;
-
-	/*
-	 * We have to check that the file structure underneath the fd
-	 * the user passed to us _is_ an eventpoll file.
-	 */
-	error = -EINVAL;
-	if (!is_file_epoll(file))
-		goto eexit_2;
-
-	/*
-	 * At this point it is safe to assume that the "private_data" contains
-	 * our own data structure.
-	 */
-	ep = file->private_data;
-
-	/* Time to fish for events ... */
-	error = ep_poll(ep, events, maxevents, timeout);
-
-eexit_2:
-	fput(file);
-eexit_1:
-	DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_wait(%d, %p, %d, %d) = %d\n",
-		     current, epfd, events, maxevents, timeout, error));
-
-	return error;
-}
-
-
-#ifdef TIF_RESTORE_SIGMASK
-
-/*
- * Implement the event wait interface for the eventpoll file. It is the kernel
- * part of the user space epoll_pwait(2).
- */
-asmlinkage long sys_epoll_pwait(int epfd, struct epoll_event __user *events,
-		int maxevents, int timeout, const sigset_t __user *sigmask,
-		size_t sigsetsize)
-{
-	int error;
-	sigset_t ksigmask, sigsaved;
-
-	/*
-	 * If the caller wants a certain signal mask to be set during the wait,
-	 * we apply it here.
-	 */
-	if (sigmask) {
-		if (sigsetsize != sizeof(sigset_t))
-			return -EINVAL;
-		if (copy_from_user(&ksigmask, sigmask, sizeof(ksigmask)))
-			return -EFAULT;
-		sigdelsetmask(&ksigmask, sigmask(SIGKILL) | sigmask(SIGSTOP));
-		sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
-	}
-
-	error = sys_epoll_wait(epfd, events, maxevents, timeout);
-
-	/*
-	 * If we changed the signal mask, we need to restore the original one.
-	 * In case we've got a signal while waiting, we do not restore the
-	 * signal mask yet, and we allow do_signal() to deliver the signal on
-	 * the way back to userspace, before the signal mask is restored.
-	 */
-	if (sigmask) {
-		if (error == -EINTR) {
-			memcpy(&current->saved_sigmask, &sigsaved,
-				sizeof(sigsaved));
-			set_thread_flag(TIF_RESTORE_SIGMASK);
-		} else
-			sigprocmask(SIG_SETMASK, &sigsaved, NULL);
-	}
-
-	return error;
-}
-
-#endif /* #ifdef TIF_RESTORE_SIGMASK */
-
-
-/*
- * Creates the file descriptor to be used by the epoll interface.
- */
-static int ep_getfd(int *efd, struct inode **einode, struct file **efile,
-		    struct eventpoll *ep)
-{
-	struct qstr this;
-	char name[32];
-	struct dentry *dentry;
-	struct inode *inode;
-	struct file *file;
-	int error, fd;
-
-	/* Get an ready to use file */
-	error = -ENFILE;
-	file = get_empty_filp();
-	if (!file)
-		goto eexit_1;
-
-	/* Allocates an inode from the eventpoll file system */
-	inode = ep_eventpoll_inode();
-	if (IS_ERR(inode)) {
-		error = PTR_ERR(inode);
-		goto eexit_2;
-	}
-
-	/* Allocates a free descriptor to plug the file onto */
-	error = get_unused_fd();
-	if (error < 0)
-		goto eexit_3;
-	fd = error;
-
-	/*
-	 * Link the inode to a directory entry by creating a unique name
-	 * using the inode number.
-	 */
-	error = -ENOMEM;
-	sprintf(name, "[%lu]", inode->i_ino);
-	this.name = name;
-	this.len = strlen(name);
-	this.hash = inode->i_ino;
-	dentry = d_alloc(eventpoll_mnt->mnt_sb->s_root, &this);
-	if (!dentry)
-		goto eexit_4;
-	dentry->d_op = &eventpollfs_dentry_operations;
-	d_add(dentry, inode);
-	file->f_path.mnt = mntget(eventpoll_mnt);
-	file->f_path.dentry = dentry;
-	file->f_mapping = inode->i_mapping;
-
-	file->f_pos = 0;
-	file->f_flags = O_RDONLY;
-	file->f_op = &eventpoll_fops;
-	file->f_mode = FMODE_READ;
-	file->f_version = 0;
-	file->private_data = ep;
-
-	/* Install the new setup file into the allocated fd. */
-	fd_install(fd, file);
-
-	*efd = fd;
-	*einode = inode;
-	*efile = file;
-	return 0;
-
-eexit_4:
-	put_unused_fd(fd);
-eexit_3:
-	iput(inode);
-eexit_2:
-	put_filp(file);
-eexit_1:
-	return error;
-}
-
-
-static int ep_alloc(struct eventpoll **pep)
-{
-	struct eventpoll *ep = kzalloc(sizeof(*ep), GFP_KERNEL);
-
-	if (!ep)
-		return -ENOMEM;
-
-	rwlock_init(&ep->lock);
-	init_rwsem(&ep->sem);
-	init_waitqueue_head(&ep->wq);
-	init_waitqueue_head(&ep->poll_wait);
-	INIT_LIST_HEAD(&ep->rdllist);
-	ep->rbr = RB_ROOT;
-
-	*pep = ep;
-
-	DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_alloc() ep=%p\n",
-		     current, ep));
-	return 0;
-}
-
-
 static void ep_free(struct eventpoll *ep)
 {
 	struct rb_node *rbp;
@@ -865,6 +536,104 @@
 	mutex_unlock(&epmutex);
 }
 
+static int ep_eventpoll_release(struct inode *inode, struct file *file)
+{
+	struct eventpoll *ep = file->private_data;
+
+	if (ep) {
+		ep_free(ep);
+		kfree(ep);
+	}
+
+	DNPRINTK(3, (KERN_INFO "[%p] eventpoll: close() ep=%p\n", current, ep));
+	return 0;
+}
+
+static unsigned int ep_eventpoll_poll(struct file *file, poll_table *wait)
+{
+	unsigned int pollflags = 0;
+	unsigned long flags;
+	struct eventpoll *ep = file->private_data;
+
+	/* Insert inside our poll wait queue */
+	poll_wait(file, &ep->poll_wait, wait);
+
+	/* Check our condition */
+	read_lock_irqsave(&ep->lock, flags);
+	if (!list_empty(&ep->rdllist))
+		pollflags = POLLIN | POLLRDNORM;
+	read_unlock_irqrestore(&ep->lock, flags);
+
+	return pollflags;
+}
+
+/* File callbacks that implement the eventpoll file behaviour */
+static const struct file_operations eventpoll_fops = {
+	.release	= ep_eventpoll_release,
+	.poll		= ep_eventpoll_poll
+};
+
+/* Fast test to see if the file is an evenpoll file */
+static inline int is_file_epoll(struct file *f)
+{
+	return f->f_op == &eventpoll_fops;
+}
+
+/*
+ * This is called from eventpoll_release() to unlink files from the eventpoll
+ * interface. We need to have this facility to cleanup correctly files that are
+ * closed without being removed from the eventpoll interface.
+ */
+void eventpoll_release_file(struct file *file)
+{
+	struct list_head *lsthead = &file->f_ep_links;
+	struct eventpoll *ep;
+	struct epitem *epi;
+
+	/*
+	 * We don't want to get "file->f_ep_lock" because it is not
+	 * necessary. It is not necessary because we're in the "struct file"
+	 * cleanup path, and this means that noone is using this file anymore.
+	 * The only hit might come from ep_free() but by holding the semaphore
+	 * will correctly serialize the operation. We do need to acquire
+	 * "ep->sem" after "epmutex" because ep_remove() requires it when called
+	 * from anywhere but ep_free().
+	 */
+	mutex_lock(&epmutex);
+
+	while (!list_empty(lsthead)) {
+		epi = list_first_entry(lsthead, struct epitem, fllink);
+
+		ep = epi->ep;
+		list_del_init(&epi->fllink);
+		down_write(&ep->sem);
+		ep_remove(ep, epi);
+		up_write(&ep->sem);
+	}
+
+	mutex_unlock(&epmutex);
+}
+
+static int ep_alloc(struct eventpoll **pep)
+{
+	struct eventpoll *ep = kzalloc(sizeof(*ep), GFP_KERNEL);
+
+	if (!ep)
+		return -ENOMEM;
+
+	rwlock_init(&ep->lock);
+	init_rwsem(&ep->sem);
+	init_waitqueue_head(&ep->wq);
+	init_waitqueue_head(&ep->poll_wait);
+	INIT_LIST_HEAD(&ep->rdllist);
+	ep->rbr = RB_ROOT;
+
+	*pep = ep;
+
+	DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_alloc() ep=%p\n",
+		     current, ep));
+	return 0;
+}
 
 /*
  * Search the file inside the eventpoll tree. It add usage count to
@@ -902,31 +671,59 @@
 	return epir;
 }
 
-
 /*
- * Increment the usage count of the "struct epitem" making it sure
- * that the user will have a valid pointer to reference.
+ * This is the callback that is passed to the wait queue wakeup
+ * machanism. It is called by the stored file descriptors when they
+ * have events to report.
  */
-static void ep_use_epitem(struct epitem *epi)
+static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *key)
 {
+	int pwake = 0;
+	unsigned long flags;
+	struct epitem *epi = ep_item_from_wait(wait);
+	struct eventpoll *ep = epi->ep;
 
-	atomic_inc(&epi->usecnt);
+	DNPRINTK(3, (KERN_INFO "[%p] eventpoll: poll_callback(%p) epi=%p ep=%p\n",
+		     current, epi->ffd.file, epi, ep));
+
+	write_lock_irqsave(&ep->lock, flags);
+
+	/*
+	 * If the event mask does not contain any poll(2) event, we consider the
+	 * descriptor to be disabled. This condition is likely the effect of the
+	 * EPOLLONESHOT bit that disables the descriptor when an event is received,
+	 * until the next EPOLL_CTL_MOD will be issued.
+	 */
+	if (!(epi->event.events & ~EP_PRIVATE_BITS))
+		goto is_disabled;
+
+	/* If this file is already in the ready list we exit soon */
+	if (ep_is_linked(&epi->rdllink))
+		goto is_linked;
+
+	list_add_tail(&epi->rdllink, &ep->rdllist);
+
+is_linked:
+	/*
+	 * Wake up ( if active ) both the eventpoll wait list and the ->poll()
+	 * wait list.
+	 */
+	if (waitqueue_active(&ep->wq))
+		__wake_up_locked(&ep->wq, TASK_UNINTERRUPTIBLE |
+				 TASK_INTERRUPTIBLE);
+	if (waitqueue_active(&ep->poll_wait))
+		pwake++;
+
+is_disabled:
+	write_unlock_irqrestore(&ep->lock, flags);
+
+	/* We have to call this outside the lock */
+	if (pwake)
+		ep_poll_safewake(&psw, &ep->poll_wait);
+
+	return 1;
 }
 
-
-/*
- * Decrement ( release ) the usage count by signaling that the user
- * has finished using the structure. It might lead to freeing the
- * structure itself if the count goes to zero.
- */
-static void ep_release_epitem(struct epitem *epi)
-{
-
-	if (atomic_dec_and_test(&epi->usecnt))
-		kmem_cache_free(epi_cache, epi);
-}
-
-
 /*
  * This is the callback that is used to add our wait queue to the
  * target file wakeup lists.
@@ -950,7 +747,6 @@
 	}
 }
 
-
 static void ep_rbtree_insert(struct eventpoll *ep, struct epitem *epi)
 {
 	int kcmp;
@@ -970,7 +766,6 @@
 	rb_insert_color(&epi->rbn, &ep->rbr);
 }
 
-
 static int ep_insert(struct eventpoll *ep, struct epoll_event *event,
 		     struct file *tfile, int fd)
 {
@@ -981,7 +776,7 @@
 
 	error = -ENOMEM;
 	if (!(epi = kmem_cache_alloc(epi_cache, GFP_KERNEL)))
-		goto eexit_1;
+		goto error_return;
 
 	/* Item initialization follow here ... */
 	ep_rb_initnode(&epi->rbn);
@@ -1011,7 +806,7 @@
 	 * high memory pressure.
 	 */
 	if (epi->nwait < 0)
-		goto eexit_2;
+		goto error_unregister;
 
 	/* Add the current item to the list of active epoll hook for this file */
 	spin_lock(&tfile->f_ep_lock);
@@ -1046,7 +841,7 @@
 
 	return 0;
 
-eexit_2:
+error_unregister:
 	ep_unregister_pollwait(ep, epi);
 
 	/*
@@ -1059,11 +854,10 @@
 	write_unlock_irqrestore(&ep->lock, flags);
 
 	kmem_cache_free(epi_cache, epi);
-eexit_1:
+error_return:
 	return error;
 }
 
-
 /*
  * Modify the interest event mask by dropping an event if the new mask
  * has a match in the current file status.
@@ -1126,216 +920,6 @@
 	return 0;
 }
 
-
-/*
- * This function unregister poll callbacks from the associated file descriptor.
- * Since this must be called without holding "ep->lock" the atomic exchange trick
- * will protect us from multiple unregister.
- */
-static void ep_unregister_pollwait(struct eventpoll *ep, struct epitem *epi)
-{
-	int nwait;
-	struct list_head *lsthead = &epi->pwqlist;
-	struct eppoll_entry *pwq;
-
-	/* This is called without locks, so we need the atomic exchange */
-	nwait = xchg(&epi->nwait, 0);
-
-	if (nwait) {
-		while (!list_empty(lsthead)) {
-			pwq = list_first_entry(lsthead, struct eppoll_entry, llink);
-
-			list_del_init(&pwq->llink);
-			remove_wait_queue(pwq->whead, &pwq->wait);
-			kmem_cache_free(pwq_cache, pwq);
-		}
-	}
-}
-
-
-/*
- * Unlink the "struct epitem" from all places it might have been hooked up.
- * This function must be called with write IRQ lock on "ep->lock".
- */
-static int ep_unlink(struct eventpoll *ep, struct epitem *epi)
-{
-	int error;
-
-	/*
-	 * It can happen that this one is called for an item already unlinked.
-	 * The check protect us from doing a double unlink ( crash ).
-	 */
-	error = -ENOENT;
-	if (!ep_rb_linked(&epi->rbn))
-		goto eexit_1;
-
-	/*
-	 * Clear the event mask for the unlinked item. This will avoid item
-	 * notifications to be sent after the unlink operation from inside
-	 * the kernel->userspace event transfer loop.
-	 */
-	epi->event.events = 0;
-
-	/*
-	 * At this point is safe to do the job, unlink the item from our rb-tree.
-	 * This operation togheter with the above check closes the door to
-	 * double unlinks.
-	 */
-	ep_rb_erase(&epi->rbn, &ep->rbr);
-
-	/*
-	 * If the item we are going to remove is inside the ready file descriptors
-	 * we want to remove it from this list to avoid stale events.
-	 */
-	if (ep_is_linked(&epi->rdllink))
-		list_del_init(&epi->rdllink);
-
-	error = 0;
-eexit_1:
-
-	DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_unlink(%p, %p) = %d\n",
-		     current, ep, epi->ffd.file, error));
-
-	return error;
-}
-
-
-/*
- * Removes a "struct epitem" from the eventpoll RB tree and deallocates
- * all the associated resources.
- */
-static int ep_remove(struct eventpoll *ep, struct epitem *epi)
-{
-	int error;
-	unsigned long flags;
-	struct file *file = epi->ffd.file;
-
-	/*
-	 * Removes poll wait queue hooks. We _have_ to do this without holding
-	 * the "ep->lock" otherwise a deadlock might occur. This because of the
-	 * sequence of the lock acquisition. Here we do "ep->lock" then the wait
-	 * queue head lock when unregistering the wait queue. The wakeup callback
-	 * will run by holding the wait queue head lock and will call our callback
-	 * that will try to get "ep->lock".
-	 */
-	ep_unregister_pollwait(ep, epi);
-
-	/* Remove the current item from the list of epoll hooks */
-	spin_lock(&file->f_ep_lock);
-	if (ep_is_linked(&epi->fllink))
-		list_del_init(&epi->fllink);
-	spin_unlock(&file->f_ep_lock);
-
-	/* We need to acquire the write IRQ lock before calling ep_unlink() */
-	write_lock_irqsave(&ep->lock, flags);
-
-	/* Really unlink the item from the RB tree */
-	error = ep_unlink(ep, epi);
-
-	write_unlock_irqrestore(&ep->lock, flags);
-
-	if (error)
-		goto eexit_1;
-
-	/* At this point it is safe to free the eventpoll item */
-	ep_release_epitem(epi);
-
-	error = 0;
-eexit_1:
-	DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_remove(%p, %p) = %d\n",
-		     current, ep, file, error));
-
-	return error;
-}
-
-
-/*
- * This is the callback that is passed to the wait queue wakeup
- * machanism. It is called by the stored file descriptors when they
- * have events to report.
- */
-static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *key)
-{
-	int pwake = 0;
-	unsigned long flags;
-	struct epitem *epi = ep_item_from_wait(wait);
-	struct eventpoll *ep = epi->ep;
-
-	DNPRINTK(3, (KERN_INFO "[%p] eventpoll: poll_callback(%p) epi=%p ep=%p\n",
-		     current, epi->ffd.file, epi, ep));
-
-	write_lock_irqsave(&ep->lock, flags);
-
-	/*
-	 * If the event mask does not contain any poll(2) event, we consider the
-	 * descriptor to be disabled. This condition is likely the effect of the
-	 * EPOLLONESHOT bit that disables the descriptor when an event is received,
-	 * until the next EPOLL_CTL_MOD will be issued.
-	 */
-	if (!(epi->event.events & ~EP_PRIVATE_BITS))
-		goto is_disabled;
-
-	/* If this file is already in the ready list we exit soon */
-	if (ep_is_linked(&epi->rdllink))
-		goto is_linked;
-
-	list_add_tail(&epi->rdllink, &ep->rdllist);
-
-is_linked:
-	/*
-	 * Wake up ( if active ) both the eventpoll wait list and the ->poll()
-	 * wait list.
-	 */
-	if (waitqueue_active(&ep->wq))
-		__wake_up_locked(&ep->wq, TASK_UNINTERRUPTIBLE |
-				 TASK_INTERRUPTIBLE);
-	if (waitqueue_active(&ep->poll_wait))
-		pwake++;
-
-is_disabled:
-	write_unlock_irqrestore(&ep->lock, flags);
-
-	/* We have to call this outside the lock */
-	if (pwake)
-		ep_poll_safewake(&psw, &ep->poll_wait);
-
-	return 1;
-}
-
-
-static int ep_eventpoll_close(struct inode *inode, struct file *file)
-{
-	struct eventpoll *ep = file->private_data;
-
-	if (ep) {
-		ep_free(ep);
-		kfree(ep);
-	}
-
-	DNPRINTK(3, (KERN_INFO "[%p] eventpoll: close() ep=%p\n", current, ep));
-	return 0;
-}
-
-
-static unsigned int ep_eventpoll_poll(struct file *file, poll_table *wait)
-{
-	unsigned int pollflags = 0;
-	unsigned long flags;
-	struct eventpoll *ep = file->private_data;
-
-	/* Insert inside our poll wait queue */
-	poll_wait(file, &ep->poll_wait, wait);
-
-	/* Check our condition */
-	read_lock_irqsave(&ep->lock, flags);
-	if (!list_empty(&ep->rdllist))
-		pollflags = POLLIN | POLLRDNORM;
-	read_unlock_irqrestore(&ep->lock, flags);
-
-	return pollflags;
-}
-
-
 /*
  * This function is called without holding the "ep->lock" since the call to
  * __copy_to_user() might sleep, and also f_op->poll() might reenable the IRQ
@@ -1447,7 +1031,6 @@
 	return eventcnt == 0 ? error: eventcnt;
 }
 
-
 /*
  * Perform the transfer of events to user space.
  */
@@ -1483,7 +1066,6 @@
 	return eventcnt;
 }
 
-
 static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,
 		   int maxevents, long timeout)
 {
@@ -1553,52 +1135,262 @@
 	return res;
 }
 
-static int eventpollfs_delete_dentry(struct dentry *dentry)
+/*
+ * It opens an eventpoll file descriptor by suggesting a storage of "size"
+ * file descriptors. The size parameter is just an hint about how to size
+ * data structures. It won't prevent the user to store more than "size"
+ * file descriptors inside the epoll interface. It is the kernel part of
+ * the userspace epoll_create(2).
+ */
+asmlinkage long sys_epoll_create(int size)
 {
+	int error, fd = -1;
+	struct eventpoll *ep;
+	struct inode *inode;
+	struct file *file;
 
-	return 1;
-}
-
-static struct inode *ep_eventpoll_inode(void)
-{
-	int error = -ENOMEM;
-	struct inode *inode = new_inode(eventpoll_mnt->mnt_sb);
-
-	if (!inode)
-		goto eexit_1;
-
-	inode->i_fop = &eventpoll_fops;
+	DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d)\n",
+		     current, size));
 
 	/*
-	 * Mark the inode dirty from the very beginning,
-	 * that way it will never be moved to the dirty
-	 * list because mark_inode_dirty() will think
-	 * that it already _is_ on the dirty list.
+	 * Sanity check on the size parameter, and create the internal data
+	 * structure ( "struct eventpoll" ).
 	 */
-	inode->i_state = I_DIRTY;
-	inode->i_mode = S_IRUSR | S_IWUSR;
-	inode->i_uid = current->fsuid;
-	inode->i_gid = current->fsgid;
-	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-	return inode;
+	error = -EINVAL;
+	if (size <= 0 || (error = ep_alloc(&ep)) != 0)
+		goto error_return;
 
-eexit_1:
-	return ERR_PTR(error);
+	/*
+	 * Creates all the items needed to setup an eventpoll file. That is,
+	 * a file structure, and inode and a free file descriptor.
+	 */
+	error = anon_inode_getfd(&fd, &inode, &file, "[eventpoll]",
+				 &eventpoll_fops, ep);
+	if (error)
+		goto error_free;
+
+	DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n",
+		     current, size, fd));
+
+	return fd;
+
+error_free:
+	ep_free(ep);
+	kfree(ep);
+error_return:
+	DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n",
+		     current, size, error));
+	return error;
 }
 
-static int
-eventpollfs_get_sb(struct file_system_type *fs_type, int flags,
-		   const char *dev_name, void *data, struct vfsmount *mnt)
+/*
+ * The following function implements the controller interface for
+ * the eventpoll file that enables the insertion/removal/change of
+ * file descriptors inside the interest set.  It represents
+ * the kernel part of the user space epoll_ctl(2).
+ */
+asmlinkage long sys_epoll_ctl(int epfd, int op, int fd,
+			      struct epoll_event __user *event)
 {
-	return get_sb_pseudo(fs_type, "eventpoll:", NULL, EVENTPOLLFS_MAGIC,
-			     mnt);
+	int error;
+	struct file *file, *tfile;
+	struct eventpoll *ep;
+	struct epitem *epi;
+	struct epoll_event epds;
+
+	DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_ctl(%d, %d, %d, %p)\n",
+		     current, epfd, op, fd, event));
+
+	error = -EFAULT;
+	if (ep_op_has_event(op) &&
+	    copy_from_user(&epds, event, sizeof(struct epoll_event)))
+		goto error_return;
+
+	/* Get the "struct file *" for the eventpoll file */
+	error = -EBADF;
+	file = fget(epfd);
+	if (!file)
+		goto error_return;
+
+	/* Get the "struct file *" for the target file */
+	tfile = fget(fd);
+	if (!tfile)
+		goto error_fput;
+
+	/* The target file descriptor must support poll */
+	error = -EPERM;
+	if (!tfile->f_op || !tfile->f_op->poll)
+		goto error_tgt_fput;
+
+	/*
+	 * We have to check that the file structure underneath the file descriptor
+	 * the user passed to us _is_ an eventpoll file. And also we do not permit
+	 * adding an epoll file descriptor inside itself.
+	 */
+	error = -EINVAL;
+	if (file == tfile || !is_file_epoll(file))
+		goto error_tgt_fput;
+
+	/*
+	 * At this point it is safe to assume that the "private_data" contains
+	 * our own data structure.
+	 */
+	ep = file->private_data;
+
+	down_write(&ep->sem);
+
+	/* Try to lookup the file inside our RB tree */
+	epi = ep_find(ep, tfile, fd);
+
+	error = -EINVAL;
+	switch (op) {
+	case EPOLL_CTL_ADD:
+		if (!epi) {
+			epds.events |= POLLERR | POLLHUP;
+
+			error = ep_insert(ep, &epds, tfile, fd);
+		} else
+			error = -EEXIST;
+		break;
+	case EPOLL_CTL_DEL:
+		if (epi)
+			error = ep_remove(ep, epi);
+		else
+			error = -ENOENT;
+		break;
+	case EPOLL_CTL_MOD:
+		if (epi) {
+			epds.events |= POLLERR | POLLHUP;
+			error = ep_modify(ep, epi, &epds);
+		} else
+			error = -ENOENT;
+		break;
+	}
+	/*
+	 * The function ep_find() increments the usage count of the structure
+	 * so, if this is not NULL, we need to release it.
+	 */
+	if (epi)
+		ep_release_epitem(epi);
+	up_write(&ep->sem);
+
+error_tgt_fput:
+	fput(tfile);
+error_fput:
+	fput(file);
+error_return:
+	DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_ctl(%d, %d, %d, %p) = %d\n",
+		     current, epfd, op, fd, event, error));
+
+	return error;
 }
 
+/*
+ * Implement the event wait interface for the eventpoll file. It is the kernel
+ * part of the user space epoll_wait(2).
+ */
+asmlinkage long sys_epoll_wait(int epfd, struct epoll_event __user *events,
+			       int maxevents, int timeout)
+{
+	int error;
+	struct file *file;
+	struct eventpoll *ep;
+
+	DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_wait(%d, %p, %d, %d)\n",
+		     current, epfd, events, maxevents, timeout));
+
+	/* The maximum number of event must be greater than zero */
+	if (maxevents <= 0 || maxevents > EP_MAX_EVENTS)
+		return -EINVAL;
+
+	/* Verify that the area passed by the user is writeable */
+	if (!access_ok(VERIFY_WRITE, events, maxevents * sizeof(struct epoll_event))) {
+		error = -EFAULT;
+		goto error_return;
+	}
+
+	/* Get the "struct file *" for the eventpoll file */
+	error = -EBADF;
+	file = fget(epfd);
+	if (!file)
+		goto error_return;
+
+	/*
+	 * We have to check that the file structure underneath the fd
+	 * the user passed to us _is_ an eventpoll file.
+	 */
+	error = -EINVAL;
+	if (!is_file_epoll(file))
+		goto error_fput;
+
+	/*
+	 * At this point it is safe to assume that the "private_data" contains
+	 * our own data structure.
+	 */
+	ep = file->private_data;
+
+	/* Time to fish for events ... */
+	error = ep_poll(ep, events, maxevents, timeout);
+
+error_fput:
+	fput(file);
+error_return:
+	DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_wait(%d, %p, %d, %d) = %d\n",
+		     current, epfd, events, maxevents, timeout, error));
+
+	return error;
+}
+
+#ifdef TIF_RESTORE_SIGMASK
+
+/*
+ * Implement the event wait interface for the eventpoll file. It is the kernel
+ * part of the user space epoll_pwait(2).
+ */
+asmlinkage long sys_epoll_pwait(int epfd, struct epoll_event __user *events,
+		int maxevents, int timeout, const sigset_t __user *sigmask,
+		size_t sigsetsize)
+{
+	int error;
+	sigset_t ksigmask, sigsaved;
+
+	/*
+	 * If the caller wants a certain signal mask to be set during the wait,
+	 * we apply it here.
+	 */
+	if (sigmask) {
+		if (sigsetsize != sizeof(sigset_t))
+			return -EINVAL;
+		if (copy_from_user(&ksigmask, sigmask, sizeof(ksigmask)))
+			return -EFAULT;
+		sigdelsetmask(&ksigmask, sigmask(SIGKILL) | sigmask(SIGSTOP));
+		sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
+	}
+
+	error = sys_epoll_wait(epfd, events, maxevents, timeout);
+
+	/*
+	 * If we changed the signal mask, we need to restore the original one.
+	 * In case we've got a signal while waiting, we do not restore the
+	 * signal mask yet, and we allow do_signal() to deliver the signal on
+	 * the way back to userspace, before the signal mask is restored.
+	 */
+	if (sigmask) {
+		if (error == -EINTR) {
+			memcpy(&current->saved_sigmask, &sigsaved,
+				sizeof(sigsaved));
+			set_thread_flag(TIF_RESTORE_SIGMASK);
+		} else
+			sigprocmask(SIG_SETMASK, &sigsaved, NULL);
+	}
+
+	return error;
+}
+
+#endif /* #ifdef TIF_RESTORE_SIGMASK */
 
 static int __init eventpoll_init(void)
 {
-	int error;
-
 	mutex_init(&epmutex);
 
 	/* Initialize the structure used to perform safe poll wait head wake ups */
@@ -1614,39 +1406,7 @@
 			sizeof(struct eppoll_entry), 0,
 			EPI_SLAB_DEBUG|SLAB_PANIC, NULL, NULL);
 
-	/*
-	 * Register the virtual file system that will be the source of inodes
-	 * for the eventpoll files
-	 */
-	error = register_filesystem(&eventpoll_fs_type);
-	if (error)
-		goto epanic;
-
-	/* Mount the above commented virtual file system */
-	eventpoll_mnt = kern_mount(&eventpoll_fs_type);
-	error = PTR_ERR(eventpoll_mnt);
-	if (IS_ERR(eventpoll_mnt))
-		goto epanic;
-
-	DNPRINTK(3, (KERN_INFO "[%p] eventpoll: successfully initialized.\n",
-			current));
 	return 0;
-
-epanic:
-	panic("eventpoll_init() failed\n");
 }
+fs_initcall(eventpoll_init);
 
-
-static void __exit eventpoll_exit(void)
-{
-	/* Undo all operations done inside eventpoll_init() */
-	unregister_filesystem(&eventpoll_fs_type);
-	mntput(eventpoll_mnt);
-	kmem_cache_destroy(pwq_cache);
-	kmem_cache_destroy(epi_cache);
-}
-
-module_init(eventpoll_init);
-module_exit(eventpoll_exit);
-
-MODULE_LICENSE("GPL");
diff --git a/fs/exec.c b/fs/exec.c
index 1ba85c7..70fa365 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -50,6 +50,7 @@
 #include <linux/tsacct_kern.h>
 #include <linux/cn_proc.h>
 #include <linux/audit.h>
+#include <linux/signalfd.h>
 
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
@@ -582,6 +583,13 @@
 	int count;
 
 	/*
+	 * Tell all the sighand listeners that this sighand has
+	 * been detached. The signalfd_detach() function grabs the
+	 * sighand lock, if signal listeners are present on the sighand.
+	 */
+	signalfd_detach(tsk);
+
+	/*
 	 * If we don't share sighandlers, then we aren't sharing anything
 	 * and we can just re-use it all.
 	 */
@@ -702,7 +710,7 @@
 		 */
 		detach_pid(tsk, PIDTYPE_PID);
 		tsk->pid = leader->pid;
-		attach_pid(tsk, PIDTYPE_PID,  tsk->pid);
+		attach_pid(tsk, PIDTYPE_PID,  find_pid(tsk->pid));
 		transfer_pid(leader, tsk, PIDTYPE_PGID);
 		transfer_pid(leader, tsk, PIDTYPE_SID);
 		list_replace_rcu(&leader->tasks, &tsk->tasks);
@@ -757,8 +765,7 @@
 		spin_unlock(&oldsighand->siglock);
 		write_unlock_irq(&tasklist_lock);
 
-		if (atomic_dec_and_test(&oldsighand->count))
-			kmem_cache_free(sighand_cachep, oldsighand);
+		__cleanup_sighand(oldsighand);
 	}
 
 	BUG_ON(!thread_group_leader(tsk));
@@ -1488,6 +1495,8 @@
 	int flag = 0;
 	int ispipe = 0;
 
+	audit_core_dumps(signr);
+
 	binfmt = current->binfmt;
 	if (!binfmt || !binfmt->core_dump)
 		goto fail;
diff --git a/fs/mpage.c b/fs/mpage.c
index 0fb914f..c1698f2 100644
--- a/fs/mpage.c
+++ b/fs/mpage.c
@@ -454,11 +454,18 @@
  * written, so it can intelligently allocate a suitably-sized BIO.  For now,
  * just allocate full-size (16-page) BIOs.
  */
-static struct bio *
-__mpage_writepage(struct bio *bio, struct page *page, get_block_t get_block,
-	sector_t *last_block_in_bio, int *ret, struct writeback_control *wbc,
-	writepage_t writepage_fn)
+struct mpage_data {
+	struct bio *bio;
+	sector_t last_block_in_bio;
+	get_block_t *get_block;
+	unsigned use_writepage;
+};
+
+static int __mpage_writepage(struct page *page, struct writeback_control *wbc,
+			     void *data)
 {
+	struct mpage_data *mpd = data;
+	struct bio *bio = mpd->bio;
 	struct address_space *mapping = page->mapping;
 	struct inode *inode = page->mapping->host;
 	const unsigned blkbits = inode->i_blkbits;
@@ -476,6 +483,7 @@
 	int length;
 	struct buffer_head map_bh;
 	loff_t i_size = i_size_read(inode);
+	int ret = 0;
 
 	if (page_has_buffers(page)) {
 		struct buffer_head *head = page_buffers(page);
@@ -538,7 +546,7 @@
 
 		map_bh.b_state = 0;
 		map_bh.b_size = 1 << blkbits;
-		if (get_block(inode, block_in_file, &map_bh, 1))
+		if (mpd->get_block(inode, block_in_file, &map_bh, 1))
 			goto confused;
 		if (buffer_new(&map_bh))
 			unmap_underlying_metadata(map_bh.b_bdev,
@@ -584,7 +592,7 @@
 	/*
 	 * This page will go to BIO.  Do we need to send this BIO off first?
 	 */
-	if (bio && *last_block_in_bio != blocks[0] - 1)
+	if (bio && mpd->last_block_in_bio != blocks[0] - 1)
 		bio = mpage_bio_submit(WRITE, bio);
 
 alloc_new:
@@ -641,7 +649,7 @@
 					boundary_block, 1 << blkbits);
 		}
 	} else {
-		*last_block_in_bio = blocks[blocks_per_page - 1];
+		mpd->last_block_in_bio = blocks[blocks_per_page - 1];
 	}
 	goto out;
 
@@ -649,18 +657,19 @@
 	if (bio)
 		bio = mpage_bio_submit(WRITE, bio);
 
-	if (writepage_fn) {
-		*ret = (*writepage_fn)(page, wbc);
+	if (mpd->use_writepage) {
+		ret = mapping->a_ops->writepage(page, wbc);
 	} else {
-		*ret = -EAGAIN;
+		ret = -EAGAIN;
 		goto out;
 	}
 	/*
 	 * The caller has a ref on the inode, so *mapping is stable
 	 */
-	mapping_set_error(mapping, *ret);
+	mapping_set_error(mapping, ret);
 out:
-	return bio;
+	mpd->bio = bio;
+	return ret;
 }
 
 /**
@@ -683,120 +692,27 @@
  * the call was made get new I/O started against them.  If wbc->sync_mode is
  * WB_SYNC_ALL then we were called for data integrity and we must wait for
  * existing IO to complete.
- *
- * If you fix this you should check generic_writepages() also!
  */
 int
 mpage_writepages(struct address_space *mapping,
 		struct writeback_control *wbc, get_block_t get_block)
 {
-	struct backing_dev_info *bdi = mapping->backing_dev_info;
-	struct bio *bio = NULL;
-	sector_t last_block_in_bio = 0;
-	int ret = 0;
-	int done = 0;
-	int (*writepage)(struct page *page, struct writeback_control *wbc);
-	struct pagevec pvec;
-	int nr_pages;
-	pgoff_t index;
-	pgoff_t end;		/* Inclusive */
-	int scanned = 0;
-	int range_whole = 0;
+	int ret;
 
-	if (wbc->nonblocking && bdi_write_congested(bdi)) {
-		wbc->encountered_congestion = 1;
-		return 0;
+	if (!get_block)
+		ret = generic_writepages(mapping, wbc);
+	else {
+		struct mpage_data mpd = {
+			.bio = NULL,
+			.last_block_in_bio = 0,
+			.get_block = get_block,
+			.use_writepage = 1,
+		};
+
+		ret = write_cache_pages(mapping, wbc, __mpage_writepage, &mpd);
+		if (mpd.bio)
+			mpage_bio_submit(WRITE, mpd.bio);
 	}
-
-	writepage = NULL;
-	if (get_block == NULL)
-		writepage = mapping->a_ops->writepage;
-
-	pagevec_init(&pvec, 0);
-	if (wbc->range_cyclic) {
-		index = mapping->writeback_index; /* Start from prev offset */
-		end = -1;
-	} else {
-		index = wbc->range_start >> PAGE_CACHE_SHIFT;
-		end = wbc->range_end >> PAGE_CACHE_SHIFT;
-		if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
-			range_whole = 1;
-		scanned = 1;
-	}
-retry:
-	while (!done && (index <= end) &&
-			(nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
-			PAGECACHE_TAG_DIRTY,
-			min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1))) {
-		unsigned i;
-
-		scanned = 1;
-		for (i = 0; i < nr_pages; i++) {
-			struct page *page = pvec.pages[i];
-
-			/*
-			 * At this point we hold neither mapping->tree_lock nor
-			 * lock on the page itself: the page may be truncated or
-			 * invalidated (changing page->mapping to NULL), or even
-			 * swizzled back from swapper_space to tmpfs file
-			 * mapping
-			 */
-
-			lock_page(page);
-
-			if (unlikely(page->mapping != mapping)) {
-				unlock_page(page);
-				continue;
-			}
-
-			if (!wbc->range_cyclic && page->index > end) {
-				done = 1;
-				unlock_page(page);
-				continue;
-			}
-
-			if (wbc->sync_mode != WB_SYNC_NONE)
-				wait_on_page_writeback(page);
-
-			if (PageWriteback(page) ||
-					!clear_page_dirty_for_io(page)) {
-				unlock_page(page);
-				continue;
-			}
-
-			if (writepage) {
-				ret = (*writepage)(page, wbc);
-				mapping_set_error(mapping, ret);
-			} else {
-				bio = __mpage_writepage(bio, page, get_block,
-						&last_block_in_bio, &ret, wbc,
-						page->mapping->a_ops->writepage);
-			}
-			if (unlikely(ret == AOP_WRITEPAGE_ACTIVATE))
-				unlock_page(page);
-			if (ret || (--(wbc->nr_to_write) <= 0))
-				done = 1;
-			if (wbc->nonblocking && bdi_write_congested(bdi)) {
-				wbc->encountered_congestion = 1;
-				done = 1;
-			}
-		}
-		pagevec_release(&pvec);
-		cond_resched();
-	}
-	if (!scanned && !done) {
-		/*
-		 * We hit the last page and there is more work to be done: wrap
-		 * back to the start of the file
-		 */
-		scanned = 1;
-		index = 0;
-		goto retry;
-	}
-	if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
-		mapping->writeback_index = index;
-	if (bio)
-		mpage_bio_submit(WRITE, bio);
 	return ret;
 }
 EXPORT_SYMBOL(mpage_writepages);
@@ -804,15 +720,15 @@
 int mpage_writepage(struct page *page, get_block_t get_block,
 	struct writeback_control *wbc)
 {
-	int ret = 0;
-	struct bio *bio;
-	sector_t last_block_in_bio = 0;
-
-	bio = __mpage_writepage(NULL, page, get_block,
-			&last_block_in_bio, &ret, wbc, NULL);
-	if (bio)
-		mpage_bio_submit(WRITE, bio);
-
+	struct mpage_data mpd = {
+		.bio = NULL,
+		.last_block_in_bio = 0,
+		.get_block = get_block,
+		.use_writepage = 0,
+	};
+	int ret = __mpage_writepage(page, wbc, &mpd);
+	if (mpd.bio)
+		mpage_bio_submit(WRITE, mpd.bio);
 	return ret;
 }
 EXPORT_SYMBOL(mpage_writepage);
diff --git a/fs/namei.c b/fs/namei.c
index b3780e3..5e2d98d 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1719,7 +1719,7 @@
 	 * It already exists.
 	 */
 	mutex_unlock(&dir->d_inode->i_mutex);
-	audit_inode_update(path.dentry->d_inode);
+	audit_inode(pathname, path.dentry->d_inode);
 
 	error = -EEXIST;
 	if (flag & O_EXCL)
diff --git a/fs/partitions/Kconfig b/fs/partitions/Kconfig
index 0120704..7638a1c 100644
--- a/fs/partitions/Kconfig
+++ b/fs/partitions/Kconfig
@@ -239,7 +239,7 @@
 
 config SYSV68_PARTITION
 	bool "SYSV68 partition table support" if PARTITION_ADVANCED
-	default y if M68K
+	default y if VME
 	help
 	  Say Y here if you would like to be able to read the hard disk
 	  partition table format used by Motorola Delta machines (using
diff --git a/fs/partitions/efi.c b/fs/partitions/efi.c
index 1bea610..e7b0700 100644
--- a/fs/partitions/efi.c
+++ b/fs/partitions/efi.c
@@ -152,7 +152,7 @@
 }
 
 static inline int
-pmbr_part_valid(struct partition *part, u64 lastlba)
+pmbr_part_valid(struct partition *part)
 {
         if (part->sys_ind == EFI_PMBR_OSTYPE_EFI_GPT &&
             le32_to_cpu(part->start_sect) == 1UL)
@@ -163,7 +163,6 @@
 /**
  * is_pmbr_valid(): test Protective MBR for validity
  * @mbr: pointer to a legacy mbr structure
- * @lastlba: last_lba for the whole device
  *
  * Description: Returns 1 if PMBR is valid, 0 otherwise.
  * Validity depends on two things:
@@ -171,13 +170,13 @@
  *  2) One partition of type 0xEE is found
  */
 static int
-is_pmbr_valid(legacy_mbr *mbr, u64 lastlba)
+is_pmbr_valid(legacy_mbr *mbr)
 {
 	int i;
 	if (!mbr || le16_to_cpu(mbr->signature) != MSDOS_MBR_SIGNATURE)
                 return 0;
 	for (i = 0; i < 4; i++)
-		if (pmbr_part_valid(&mbr->partition_record[i], lastlba))
+		if (pmbr_part_valid(&mbr->partition_record[i]))
                         return 1;
 	return 0;
 }
@@ -516,7 +515,7 @@
 	int good_pgpt = 0, good_agpt = 0, good_pmbr = 0;
 	gpt_header *pgpt = NULL, *agpt = NULL;
 	gpt_entry *pptes = NULL, *aptes = NULL;
-	legacy_mbr *legacymbr = NULL;
+	legacy_mbr *legacymbr;
 	u64 lastlba;
 	if (!bdev || !gpt || !ptes)
 		return 0;
@@ -528,9 +527,8 @@
                 if (legacymbr) {
                         read_lba(bdev, 0, (u8 *) legacymbr,
                                  sizeof (*legacymbr));
-                        good_pmbr = is_pmbr_valid(legacymbr, lastlba);
+                        good_pmbr = is_pmbr_valid(legacymbr);
                         kfree(legacymbr);
-                        legacymbr=NULL;
                 }
                 if (!good_pmbr)
                         goto fail;
diff --git a/fs/signalfd.c b/fs/signalfd.c
new file mode 100644
index 0000000..7cfeab4
--- /dev/null
+++ b/fs/signalfd.c
@@ -0,0 +1,349 @@
+/*
+ *  fs/signalfd.c
+ *
+ *  Copyright (C) 2003  Linus Torvalds
+ *
+ *  Mon Mar 5, 2007: Davide Libenzi <davidel@xmailserver.org>
+ *      Changed ->read() to return a siginfo strcture instead of signal number.
+ *      Fixed locking in ->poll().
+ *      Added sighand-detach notification.
+ *      Added fd re-use in sys_signalfd() syscall.
+ *      Now using anonymous inode source.
+ *      Thanks to Oleg Nesterov for useful code review and suggestions.
+ *      More comments and suggestions from Arnd Bergmann.
+ */
+
+#include <linux/file.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/list.h>
+#include <linux/anon_inodes.h>
+#include <linux/signalfd.h>
+
+struct signalfd_ctx {
+	struct list_head lnk;
+	wait_queue_head_t wqh;
+	sigset_t sigmask;
+	struct task_struct *tsk;
+};
+
+struct signalfd_lockctx {
+	struct task_struct *tsk;
+	unsigned long flags;
+};
+
+/*
+ * Tries to acquire the sighand lock. We do not increment the sighand
+ * use count, and we do not even pin the task struct, so we need to
+ * do it inside an RCU read lock, and we must be prepared for the
+ * ctx->tsk going to NULL (in signalfd_deliver()), and for the sighand
+ * being detached. We return 0 if the sighand has been detached, or
+ * 1 if we were able to pin the sighand lock.
+ */
+static int signalfd_lock(struct signalfd_ctx *ctx, struct signalfd_lockctx *lk)
+{
+	struct sighand_struct *sighand = NULL;
+
+	rcu_read_lock();
+	lk->tsk = rcu_dereference(ctx->tsk);
+	if (likely(lk->tsk != NULL))
+		sighand = lock_task_sighand(lk->tsk, &lk->flags);
+	rcu_read_unlock();
+
+	if (sighand && !ctx->tsk) {
+		unlock_task_sighand(lk->tsk, &lk->flags);
+		sighand = NULL;
+	}
+
+	return sighand != NULL;
+}
+
+static void signalfd_unlock(struct signalfd_lockctx *lk)
+{
+	unlock_task_sighand(lk->tsk, &lk->flags);
+}
+
+/*
+ * This must be called with the sighand lock held.
+ */
+void signalfd_deliver(struct task_struct *tsk, int sig)
+{
+	struct sighand_struct *sighand = tsk->sighand;
+	struct signalfd_ctx *ctx, *tmp;
+
+	BUG_ON(!sig);
+	list_for_each_entry_safe(ctx, tmp, &sighand->signalfd_list, lnk) {
+		/*
+		 * We use a negative signal value as a way to broadcast that the
+		 * sighand has been orphaned, so that we can notify all the
+		 * listeners about this. Remember the ctx->sigmask is inverted,
+		 * so if the user is interested in a signal, that corresponding
+		 * bit will be zero.
+		 */
+		if (sig < 0) {
+			if (ctx->tsk == tsk) {
+				ctx->tsk = NULL;
+				list_del_init(&ctx->lnk);
+				wake_up(&ctx->wqh);
+			}
+		} else {
+			if (!sigismember(&ctx->sigmask, sig))
+				wake_up(&ctx->wqh);
+		}
+	}
+}
+
+static void signalfd_cleanup(struct signalfd_ctx *ctx)
+{
+	struct signalfd_lockctx lk;
+
+	/*
+	 * This is tricky. If the sighand is gone, we do not need to remove
+	 * context from the list, the list itself won't be there anymore.
+	 */
+	if (signalfd_lock(ctx, &lk)) {
+		list_del(&ctx->lnk);
+		signalfd_unlock(&lk);
+	}
+	kfree(ctx);
+}
+
+static int signalfd_release(struct inode *inode, struct file *file)
+{
+	signalfd_cleanup(file->private_data);
+	return 0;
+}
+
+static unsigned int signalfd_poll(struct file *file, poll_table *wait)
+{
+	struct signalfd_ctx *ctx = file->private_data;
+	unsigned int events = 0;
+	struct signalfd_lockctx lk;
+
+	poll_wait(file, &ctx->wqh, wait);
+
+	/*
+	 * Let the caller get a POLLIN in this case, ala socket recv() when
+	 * the peer disconnects.
+	 */
+	if (signalfd_lock(ctx, &lk)) {
+		if (next_signal(&lk.tsk->pending, &ctx->sigmask) > 0 ||
+		    next_signal(&lk.tsk->signal->shared_pending,
+				&ctx->sigmask) > 0)
+			events |= POLLIN;
+		signalfd_unlock(&lk);
+	} else
+		events |= POLLIN;
+
+	return events;
+}
+
+/*
+ * Copied from copy_siginfo_to_user() in kernel/signal.c
+ */
+static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo,
+			     siginfo_t const *kinfo)
+{
+	long err;
+
+	BUILD_BUG_ON(sizeof(struct signalfd_siginfo) != 128);
+
+	/*
+	 * Unused memebers should be zero ...
+	 */
+	err = __clear_user(uinfo, sizeof(*uinfo));
+
+	/*
+	 * If you change siginfo_t structure, please be sure
+	 * this code is fixed accordingly.
+	 */
+	err |= __put_user(kinfo->si_signo, &uinfo->signo);
+	err |= __put_user(kinfo->si_errno, &uinfo->err);
+	err |= __put_user((short)kinfo->si_code, &uinfo->code);
+	switch (kinfo->si_code & __SI_MASK) {
+	case __SI_KILL:
+		err |= __put_user(kinfo->si_pid, &uinfo->pid);
+		err |= __put_user(kinfo->si_uid, &uinfo->uid);
+		break;
+	case __SI_TIMER:
+		 err |= __put_user(kinfo->si_tid, &uinfo->tid);
+		 err |= __put_user(kinfo->si_overrun, &uinfo->overrun);
+		 err |= __put_user((long)kinfo->si_ptr, &uinfo->svptr);
+		break;
+	case __SI_POLL:
+		err |= __put_user(kinfo->si_band, &uinfo->band);
+		err |= __put_user(kinfo->si_fd, &uinfo->fd);
+		break;
+	case __SI_FAULT:
+		err |= __put_user((long)kinfo->si_addr, &uinfo->addr);
+#ifdef __ARCH_SI_TRAPNO
+		err |= __put_user(kinfo->si_trapno, &uinfo->trapno);
+#endif
+		break;
+	case __SI_CHLD:
+		err |= __put_user(kinfo->si_pid, &uinfo->pid);
+		err |= __put_user(kinfo->si_uid, &uinfo->uid);
+		err |= __put_user(kinfo->si_status, &uinfo->status);
+		err |= __put_user(kinfo->si_utime, &uinfo->utime);
+		err |= __put_user(kinfo->si_stime, &uinfo->stime);
+		break;
+	case __SI_RT: /* This is not generated by the kernel as of now. */
+	case __SI_MESGQ: /* But this is */
+		err |= __put_user(kinfo->si_pid, &uinfo->pid);
+		err |= __put_user(kinfo->si_uid, &uinfo->uid);
+		err |= __put_user((long)kinfo->si_ptr, &uinfo->svptr);
+		break;
+	default: /* this is just in case for now ... */
+		err |= __put_user(kinfo->si_pid, &uinfo->pid);
+		err |= __put_user(kinfo->si_uid, &uinfo->uid);
+		break;
+	}
+
+	return err ? -EFAULT: sizeof(*uinfo);
+}
+
+/*
+ * Returns either the size of a "struct signalfd_siginfo", or zero if the
+ * sighand we are attached to, has been orphaned. The "count" parameter
+ * must be at least the size of a "struct signalfd_siginfo".
+ */
+static ssize_t signalfd_read(struct file *file, char __user *buf, size_t count,
+			     loff_t *ppos)
+{
+	struct signalfd_ctx *ctx = file->private_data;
+	ssize_t res = 0;
+	int locked, signo;
+	siginfo_t info;
+	struct signalfd_lockctx lk;
+	DECLARE_WAITQUEUE(wait, current);
+
+	if (count < sizeof(struct signalfd_siginfo))
+		return -EINVAL;
+	locked = signalfd_lock(ctx, &lk);
+	if (!locked)
+		return 0;
+	res = -EAGAIN;
+	signo = dequeue_signal(lk.tsk, &ctx->sigmask, &info);
+	if (signo == 0 && !(file->f_flags & O_NONBLOCK)) {
+		add_wait_queue(&ctx->wqh, &wait);
+		for (;;) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			signo = dequeue_signal(lk.tsk, &ctx->sigmask, &info);
+			if (signo != 0)
+				break;
+			if (signal_pending(current)) {
+				res = -ERESTARTSYS;
+				break;
+			}
+			signalfd_unlock(&lk);
+			schedule();
+			locked = signalfd_lock(ctx, &lk);
+			if (unlikely(!locked)) {
+				/*
+				 * Let the caller read zero byte, ala socket
+				 * recv() when the peer disconnect. This test
+				 * must be done before doing a dequeue_signal(),
+				 * because if the sighand has been orphaned,
+				 * the dequeue_signal() call is going to crash.
+				 */
+				res = 0;
+				break;
+			}
+		}
+		remove_wait_queue(&ctx->wqh, &wait);
+		__set_current_state(TASK_RUNNING);
+	}
+	if (likely(locked))
+		signalfd_unlock(&lk);
+	if (likely(signo))
+		res = signalfd_copyinfo((struct signalfd_siginfo __user *) buf,
+					&info);
+
+	return res;
+}
+
+static const struct file_operations signalfd_fops = {
+	.release	= signalfd_release,
+	.poll		= signalfd_poll,
+	.read		= signalfd_read,
+};
+
+/*
+ * Create a file descriptor that is associated with our signal
+ * state. We can pass it around to others if we want to, but
+ * it will always be _our_ signal state.
+ */
+asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemask)
+{
+	int error;
+	sigset_t sigmask;
+	struct signalfd_ctx *ctx;
+	struct sighand_struct *sighand;
+	struct file *file;
+	struct inode *inode;
+	struct signalfd_lockctx lk;
+
+	if (sizemask != sizeof(sigset_t) ||
+	    copy_from_user(&sigmask, user_mask, sizeof(sigmask)))
+		return error = -EINVAL;
+	sigdelsetmask(&sigmask, sigmask(SIGKILL) | sigmask(SIGSTOP));
+	signotset(&sigmask);
+
+	if (ufd == -1) {
+		ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
+		if (!ctx)
+			return -ENOMEM;
+
+		init_waitqueue_head(&ctx->wqh);
+		ctx->sigmask = sigmask;
+		ctx->tsk = current;
+
+		sighand = current->sighand;
+		/*
+		 * Add this fd to the list of signal listeners.
+		 */
+		spin_lock_irq(&sighand->siglock);
+		list_add_tail(&ctx->lnk, &sighand->signalfd_list);
+		spin_unlock_irq(&sighand->siglock);
+
+		/*
+		 * When we call this, the initialization must be complete, since
+		 * anon_inode_getfd() will install the fd.
+		 */
+		error = anon_inode_getfd(&ufd, &inode, &file, "[signalfd]",
+					 &signalfd_fops, ctx);
+		if (error)
+			goto err_fdalloc;
+	} else {
+		file = fget(ufd);
+		if (!file)
+			return -EBADF;
+		ctx = file->private_data;
+		if (file->f_op != &signalfd_fops) {
+			fput(file);
+			return -EINVAL;
+		}
+		/*
+		 * We need to be prepared of the fact that the sighand this fd
+		 * is attached to, has been detched. In that case signalfd_lock()
+		 * will return 0, and we'll just skip setting the new mask.
+		 */
+		if (signalfd_lock(ctx, &lk)) {
+			ctx->sigmask = sigmask;
+			signalfd_unlock(&lk);
+		}
+		wake_up(&ctx->wqh);
+		fput(file);
+	}
+
+	return ufd;
+
+err_fdalloc:
+	signalfd_cleanup(ctx);
+	return error;
+}
+
diff --git a/fs/timerfd.c b/fs/timerfd.c
new file mode 100644
index 0000000..e329e37
--- /dev/null
+++ b/fs/timerfd.c
@@ -0,0 +1,227 @@
+/*
+ *  fs/timerfd.c
+ *
+ *  Copyright (C) 2007  Davide Libenzi <davidel@xmailserver.org>
+ *
+ *
+ *  Thanks to Thomas Gleixner for code reviews and useful comments.
+ *
+ */
+
+#include <linux/file.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/time.h>
+#include <linux/hrtimer.h>
+#include <linux/anon_inodes.h>
+#include <linux/timerfd.h>
+
+struct timerfd_ctx {
+	struct hrtimer tmr;
+	ktime_t tintv;
+	spinlock_t lock;
+	wait_queue_head_t wqh;
+	int expired;
+};
+
+/*
+ * This gets called when the timer event triggers. We set the "expired"
+ * flag, but we do not re-arm the timer (in case it's necessary,
+ * tintv.tv64 != 0) until the timer is read.
+ */
+static enum hrtimer_restart timerfd_tmrproc(struct hrtimer *htmr)
+{
+	struct timerfd_ctx *ctx = container_of(htmr, struct timerfd_ctx, tmr);
+	unsigned long flags;
+
+	spin_lock_irqsave(&ctx->lock, flags);
+	ctx->expired = 1;
+	wake_up_locked(&ctx->wqh);
+	spin_unlock_irqrestore(&ctx->lock, flags);
+
+	return HRTIMER_NORESTART;
+}
+
+static void timerfd_setup(struct timerfd_ctx *ctx, int clockid, int flags,
+			  const struct itimerspec *ktmr)
+{
+	enum hrtimer_mode htmode;
+	ktime_t texp;
+
+	htmode = (flags & TFD_TIMER_ABSTIME) ?
+		HRTIMER_MODE_ABS: HRTIMER_MODE_REL;
+
+	texp = timespec_to_ktime(ktmr->it_value);
+	ctx->expired = 0;
+	ctx->tintv = timespec_to_ktime(ktmr->it_interval);
+	hrtimer_init(&ctx->tmr, clockid, htmode);
+	ctx->tmr.expires = texp;
+	ctx->tmr.function = timerfd_tmrproc;
+	if (texp.tv64 != 0)
+		hrtimer_start(&ctx->tmr, texp, htmode);
+}
+
+static int timerfd_release(struct inode *inode, struct file *file)
+{
+	struct timerfd_ctx *ctx = file->private_data;
+
+	hrtimer_cancel(&ctx->tmr);
+	kfree(ctx);
+	return 0;
+}
+
+static unsigned int timerfd_poll(struct file *file, poll_table *wait)
+{
+	struct timerfd_ctx *ctx = file->private_data;
+	unsigned int events = 0;
+	unsigned long flags;
+
+	poll_wait(file, &ctx->wqh, wait);
+
+	spin_lock_irqsave(&ctx->lock, flags);
+	if (ctx->expired)
+		events |= POLLIN;
+	spin_unlock_irqrestore(&ctx->lock, flags);
+
+	return events;
+}
+
+static ssize_t timerfd_read(struct file *file, char __user *buf, size_t count,
+			    loff_t *ppos)
+{
+	struct timerfd_ctx *ctx = file->private_data;
+	ssize_t res;
+	u32 ticks = 0;
+	DECLARE_WAITQUEUE(wait, current);
+
+	if (count < sizeof(ticks))
+		return -EINVAL;
+	spin_lock_irq(&ctx->lock);
+	res = -EAGAIN;
+	if (!ctx->expired && !(file->f_flags & O_NONBLOCK)) {
+		__add_wait_queue(&ctx->wqh, &wait);
+		for (res = 0;;) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			if (ctx->expired) {
+				res = 0;
+				break;
+			}
+			if (signal_pending(current)) {
+				res = -ERESTARTSYS;
+				break;
+			}
+			spin_unlock_irq(&ctx->lock);
+			schedule();
+			spin_lock_irq(&ctx->lock);
+		}
+		__remove_wait_queue(&ctx->wqh, &wait);
+		__set_current_state(TASK_RUNNING);
+	}
+	if (ctx->expired) {
+		ctx->expired = 0;
+		if (ctx->tintv.tv64 != 0) {
+			/*
+			 * If tintv.tv64 != 0, this is a periodic timer that
+			 * needs to be re-armed. We avoid doing it in the timer
+			 * callback to avoid DoS attacks specifying a very
+			 * short timer period.
+			 */
+			ticks = (u32)
+				hrtimer_forward(&ctx->tmr,
+						hrtimer_cb_get_time(&ctx->tmr),
+						ctx->tintv);
+			hrtimer_restart(&ctx->tmr);
+		} else
+			ticks = 1;
+	}
+	spin_unlock_irq(&ctx->lock);
+	if (ticks)
+		res = put_user(ticks, buf) ? -EFAULT: sizeof(ticks);
+	return res;
+}
+
+static const struct file_operations timerfd_fops = {
+	.release	= timerfd_release,
+	.poll		= timerfd_poll,
+	.read		= timerfd_read,
+};
+
+asmlinkage long sys_timerfd(int ufd, int clockid, int flags,
+			    const struct itimerspec __user *utmr)
+{
+	int error;
+	struct timerfd_ctx *ctx;
+	struct file *file;
+	struct inode *inode;
+	struct itimerspec ktmr;
+
+	if (copy_from_user(&ktmr, utmr, sizeof(ktmr)))
+		return -EFAULT;
+
+	if (clockid != CLOCK_MONOTONIC &&
+	    clockid != CLOCK_REALTIME)
+		return -EINVAL;
+	if (!timespec_valid(&ktmr.it_value) ||
+	    !timespec_valid(&ktmr.it_interval))
+		return -EINVAL;
+
+	if (ufd == -1) {
+		ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
+		if (!ctx)
+			return -ENOMEM;
+
+		init_waitqueue_head(&ctx->wqh);
+		spin_lock_init(&ctx->lock);
+
+		timerfd_setup(ctx, clockid, flags, &ktmr);
+
+		/*
+		 * When we call this, the initialization must be complete, since
+		 * anon_inode_getfd() will install the fd.
+		 */
+		error = anon_inode_getfd(&ufd, &inode, &file, "[timerfd]",
+					 &timerfd_fops, ctx);
+		if (error)
+			goto err_tmrcancel;
+	} else {
+		file = fget(ufd);
+		if (!file)
+			return -EBADF;
+		ctx = file->private_data;
+		if (file->f_op != &timerfd_fops) {
+			fput(file);
+			return -EINVAL;
+		}
+		/*
+		 * We need to stop the existing timer before reprogramming
+		 * it to the new values.
+		 */
+		for (;;) {
+			spin_lock_irq(&ctx->lock);
+			if (hrtimer_try_to_cancel(&ctx->tmr) >= 0)
+				break;
+			spin_unlock_irq(&ctx->lock);
+			cpu_relax();
+		}
+		/*
+		 * Re-program the timer to the new value ...
+		 */
+		timerfd_setup(ctx, clockid, flags, &ktmr);
+
+		spin_unlock_irq(&ctx->lock);
+		fput(file);
+	}
+
+	return ufd;
+
+err_tmrcancel:
+	hrtimer_cancel(&ctx->tmr);
+	kfree(ctx);
+	return error;
+}
+
diff --git a/fs/xattr.c b/fs/xattr.c
index 9f4568b..4523aca 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -350,6 +350,7 @@
 	f = fget(fd);
 	if (!f)
 		return error;
+	audit_inode(NULL, f->f_path.dentry->d_inode);
 	error = getxattr(f->f_path.dentry, name, value, size);
 	fput(f);
 	return error;
@@ -422,6 +423,7 @@
 	f = fget(fd);
 	if (!f)
 		return error;
+	audit_inode(NULL, f->f_path.dentry->d_inode);
 	error = listxattr(f->f_path.dentry, list, size);
 	fput(f);
 	return error;
diff --git a/include/asm-alpha/poll.h b/include/asm-alpha/poll.h
index 76f8935..c98509d 100644
--- a/include/asm-alpha/poll.h
+++ b/include/asm-alpha/poll.h
@@ -1,25 +1 @@
-#ifndef __ALPHA_POLL_H
-#define __ALPHA_POLL_H
-
-#define POLLIN		(1 << 0)
-#define POLLPRI		(1 << 1)
-#define POLLOUT		(1 << 2)
-#define POLLERR		(1 << 3)
-#define POLLHUP		(1 << 4)
-#define POLLNVAL	(1 << 5)
-#define POLLRDNORM	(1 << 6)
-#define POLLRDBAND	(1 << 7)
-#define POLLWRNORM	(1 << 8)
-#define POLLWRBAND	(1 << 9)
-#define POLLMSG		(1 << 10)
-#define POLLREMOVE	(1 << 12)
-#define POLLRDHUP       (1 << 13)
-
-
-struct pollfd {
-	int fd;
-	short events;
-	short revents;
-};
-
-#endif
+#include <asm-generic/poll.h>
diff --git a/include/asm-arm/poll.h b/include/asm-arm/poll.h
index 5030b2b..c98509d 100644
--- a/include/asm-arm/poll.h
+++ b/include/asm-arm/poll.h
@@ -1,27 +1 @@
-#ifndef __ASMARM_POLL_H
-#define __ASMARM_POLL_H
-
-/* These are specified by iBCS2 */
-#define POLLIN		0x0001
-#define POLLPRI		0x0002
-#define POLLOUT		0x0004
-#define POLLERR		0x0008
-#define POLLHUP		0x0010
-#define POLLNVAL	0x0020
-
-/* The rest seem to be more-or-less nonstandard. Check them! */
-#define POLLRDNORM	0x0040
-#define POLLRDBAND	0x0080
-#define POLLWRNORM	0x0100
-#define POLLWRBAND	0x0200
-#define POLLMSG		0x0400
-#define POLLREMOVE	0x1000
-#define POLLRDHUP       0x2000
-
-struct pollfd {
-	int fd;
-	short events;
-	short revents;
-};
-
-#endif
+#include <asm-generic/poll.h>
diff --git a/include/asm-arm26/poll.h b/include/asm-arm26/poll.h
index 9ccb7f4..1170e70 100644
--- a/include/asm-arm26/poll.h
+++ b/include/asm-arm26/poll.h
@@ -1,26 +1,8 @@
 #ifndef __ASMARM_POLL_H
 #define __ASMARM_POLL_H
 
-/* These are specified by iBCS2 */
-#define POLLIN		0x0001
-#define POLLPRI		0x0002
-#define POLLOUT		0x0004
-#define POLLERR		0x0008
-#define POLLHUP		0x0010
-#define POLLNVAL	0x0020
+#include <asm-generic/poll.h>
 
-/* The rest seem to be more-or-less nonstandard. Check them! */
-#define POLLRDNORM	0x0040
-#define POLLRDBAND	0x0080
-#define POLLWRNORM	0x0100
-#define POLLWRBAND	0x0200
-#define POLLMSG		0x0400
-#define POLLRDHUP       0x2000
-
-struct pollfd {
-	int fd;
-	short events;
-	short revents;
-};
+#undef POLLREMOVE
 
 #endif
diff --git a/include/asm-avr32/poll.h b/include/asm-avr32/poll.h
index 736e297..c98509d 100644
--- a/include/asm-avr32/poll.h
+++ b/include/asm-avr32/poll.h
@@ -1,27 +1 @@
-#ifndef __ASM_AVR32_POLL_H
-#define __ASM_AVR32_POLL_H
-
-/* These are specified by iBCS2 */
-#define POLLIN		0x0001
-#define POLLPRI		0x0002
-#define POLLOUT		0x0004
-#define POLLERR		0x0008
-#define POLLHUP		0x0010
-#define POLLNVAL	0x0020
-
-/* The rest seem to be more-or-less nonstandard. Check them! */
-#define POLLRDNORM	0x0040
-#define POLLRDBAND	0x0080
-#define POLLWRNORM	0x0100
-#define POLLWRBAND	0x0200
-#define POLLMSG		0x0400
-#define POLLREMOVE	0x1000
-#define POLLRDHUP	0x2000
-
-struct pollfd {
-	int fd;
-	short events;
-	short revents;
-};
-
-#endif /* __ASM_AVR32_POLL_H */
+#include <asm-generic/poll.h>
diff --git a/include/asm-cris/poll.h b/include/asm-cris/poll.h
index 1b25d4c..c98509d 100644
--- a/include/asm-cris/poll.h
+++ b/include/asm-cris/poll.h
@@ -1,26 +1 @@
-#ifndef __ASM_CRIS_POLL_H
-#define __ASM_CRIS_POLL_H
-
-/* taken from asm-alpha */
-
-#define POLLIN		1
-#define POLLPRI		2
-#define POLLOUT		4
-#define POLLERR		8
-#define POLLHUP		16
-#define POLLNVAL	32
-#define POLLRDNORM	64
-#define POLLRDBAND	128
-#define POLLWRNORM	256
-#define POLLWRBAND	512
-#define POLLMSG		1024
-#define POLLREMOVE	4096
-#define POLLRDHUP       8192
-
-struct pollfd {
-	int fd;
-	short events;
-	short revents;
-};
-
-#endif
+#include <asm-generic/poll.h>
diff --git a/include/asm-frv/poll.h b/include/asm-frv/poll.h
index c8fe880..0d01479 100644
--- a/include/asm-frv/poll.h
+++ b/include/asm-frv/poll.h
@@ -1,24 +1,12 @@
 #ifndef _ASM_POLL_H
 #define _ASM_POLL_H
 
-#define POLLIN		  1
-#define POLLPRI		  2
-#define POLLOUT		  4
-#define POLLERR		  8
-#define POLLHUP		 16
-#define POLLNVAL	 32
-#define POLLRDNORM	 64
 #define POLLWRNORM	POLLOUT
-#define POLLRDBAND	128
 #define POLLWRBAND	256
-#define POLLMSG		0x0400
-#define POLLRDHUP       0x2000
 
-struct pollfd {
-	int fd;
-	short events;
-	short revents;
-};
+#include <asm-generic/poll.h>
+
+#undef POLLREMOVE
 
 #endif
 
diff --git a/include/asm-generic/Kbuild b/include/asm-generic/Kbuild
index fa14f8c..5bfeef7 100644
--- a/include/asm-generic/Kbuild
+++ b/include/asm-generic/Kbuild
@@ -4,6 +4,7 @@
 header-y += ioctl.h
 header-y += ipc.h
 header-y += mman.h
+header-y += poll.h
 header-y += signal.h
 header-y += statfs.h
 
diff --git a/include/asm-generic/audit_signal.h b/include/asm-generic/audit_signal.h
new file mode 100644
index 0000000..6feab7f
--- /dev/null
+++ b/include/asm-generic/audit_signal.h
@@ -0,0 +1,3 @@
+__NR_kill,
+__NR_tgkill,
+__NR_tkill,
diff --git a/include/asm-generic/poll.h b/include/asm-generic/poll.h
new file mode 100644
index 0000000..44bce83
--- /dev/null
+++ b/include/asm-generic/poll.h
@@ -0,0 +1,37 @@
+#ifndef __ASM_GENERIC_POLL_H
+#define __ASM_GENERIC_POLL_H
+
+/* These are specified by iBCS2 */
+#define POLLIN		0x0001
+#define POLLPRI		0x0002
+#define POLLOUT		0x0004
+#define POLLERR		0x0008
+#define POLLHUP		0x0010
+#define POLLNVAL	0x0020
+
+/* The rest seem to be more-or-less nonstandard. Check them! */
+#define POLLRDNORM	0x0040
+#define POLLRDBAND	0x0080
+#ifndef POLLWRNORM
+#define POLLWRNORM	0x0100
+#endif
+#ifndef POLLWRBAND
+#define POLLWRBAND	0x0200
+#endif
+#ifndef POLLMSG
+#define POLLMSG		0x0400
+#endif
+#ifndef POLLREMOVE
+#define POLLREMOVE	0x1000
+#endif
+#ifndef POLLRDHUP
+#define POLLRDHUP       0x2000
+#endif
+
+struct pollfd {
+	int fd;
+	short events;
+	short revents;
+};
+
+#endif	/* __ASM_GENERIC_POLL_H */
diff --git a/include/asm-h8300/poll.h b/include/asm-h8300/poll.h
index fc52103..f61540c 100644
--- a/include/asm-h8300/poll.h
+++ b/include/asm-h8300/poll.h
@@ -1,23 +1,11 @@
 #ifndef __H8300_POLL_H
 #define __H8300_POLL_H
 
-#define POLLIN		  1
-#define POLLPRI		  2
-#define POLLOUT		  4
-#define POLLERR		  8
-#define POLLHUP		 16
-#define POLLNVAL	 32
-#define POLLRDNORM	 64
 #define POLLWRNORM	POLLOUT
-#define POLLRDBAND	128
 #define POLLWRBAND	256
-#define POLLMSG		0x0400
-#define POLLRDHUP       0x2000
 
-struct pollfd {
-	int fd;
-	short events;
-	short revents;
-};
+#include <asm-generic/poll.h>
+
+#undef POLLREMOVE
 
 #endif
diff --git a/include/asm-h8300/unistd.h b/include/asm-h8300/unistd.h
index 7ddd414..99f3c35 100644
--- a/include/asm-h8300/unistd.h
+++ b/include/asm-h8300/unistd.h
@@ -21,7 +21,7 @@
 #define __NR_time		 13
 #define __NR_mknod		 14
 #define __NR_chmod		 15
-#define __NR_chown		 16
+#define __NR_lchown		 16
 #define __NR_break		 17
 #define __NR_oldstat		 18
 #define __NR_lseek		 19
@@ -115,10 +115,10 @@
 #define __NR_lstat		107
 #define __NR_fstat		108
 #define __NR_olduname		109
-#define __NR_iopl		/* 110 */ not supported
+#define __NR_iopl		110
 #define __NR_vhangup		111
-#define __NR_idle		/* 112 */ Obsolete
-#define __NR_vm86		/* 113 */ not supported
+#define __NR_idle		112
+#define __NR_vm86old		113
 #define __NR_wait4		114
 #define __NR_swapoff		115
 #define __NR_sysinfo		116
@@ -128,7 +128,7 @@
 #define __NR_clone		120
 #define __NR_setdomainname	121
 #define __NR_uname		122
-#define __NR_cacheflush		123
+#define __NR_modify_ldt		123
 #define __NR_adjtimex		124
 #define __NR_mprotect		125
 #define __NR_sigprocmask	126
@@ -171,7 +171,7 @@
 #define __NR_mremap		163
 #define __NR_setresuid		164
 #define __NR_getresuid		165
-#define __NR_getpagesize	166
+#define __NR_vm86		166
 #define __NR_query_module	167
 #define __NR_poll		168
 #define __NR_nfsservctl		169
@@ -187,7 +187,7 @@
 #define __NR_rt_sigsuspend	179
 #define __NR_pread64		180
 #define __NR_pwrite64		181
-#define __NR_lchown		182
+#define __NR_chown		182
 #define __NR_getcwd		183
 #define __NR_capget		184
 #define __NR_capset		185
@@ -203,7 +203,7 @@
 #define __NR_stat64		195
 #define __NR_lstat64		196
 #define __NR_fstat64		197
-#define __NR_chown32		198
+#define __NR_lchown32		198
 #define __NR_getuid32		199
 #define __NR_getgid32		200
 #define __NR_geteuid32		201
@@ -217,15 +217,18 @@
 #define __NR_getresuid32	209
 #define __NR_setresgid32	210
 #define __NR_getresgid32	211
-#define __NR_lchown32		212
+#define __NR_chown32		212
 #define __NR_setuid32		213
 #define __NR_setgid32		214
 #define __NR_setfsuid32		215
 #define __NR_setfsgid32		216
 #define __NR_pivot_root		217
+#define __NR_mincore		218
+#define __NR_madvise		219
+#define __NR_madvise1		219
 #define __NR_getdents64		220
 #define __NR_fcntl64		221
-#define __NR_security		223
+/* 223 is unused */
 #define __NR_gettid		224
 #define __NR_readahead		225
 #define __NR_setxattr		226
@@ -252,13 +255,13 @@
 #define __NR_io_getevents	247
 #define __NR_io_submit		248
 #define __NR_io_cancel		249
-#define __NR_alloc_hugepages	250
-#define __NR_free_hugepages	251
+#define __NR_fadvise64		250
+/* 251 is available for reuse (was briefly sys_set_zone_reclaim) */
 #define __NR_exit_group		252
 #define __NR_lookup_dcookie	253
-#define __NR_sys_epoll_create	254
-#define __NR_sys_epoll_ctl	255
-#define __NR_sys_epoll_wait	256
+#define __NR_epoll_create	254
+#define __NR_epoll_ctl		255
+#define __NR_epoll_wait		256
 #define __NR_remap_file_pages	257
 #define __NR_set_tid_address	258
 #define __NR_timer_create	259
@@ -291,10 +294,41 @@
 #define __NR_add_key		286
 #define __NR_request_key	287
 #define __NR_keyctl		288
+#define __NR_ioprio_set		289
+#define __NR_ioprio_get		290
+#define __NR_inotify_init	291
+#define __NR_inotify_add_watch	292
+#define __NR_inotify_rm_watch	293
+#define __NR_migrate_pages	294
+#define __NR_openat		295
+#define __NR_mkdirat		296
+#define __NR_mknodat		297
+#define __NR_fchownat		298
+#define __NR_futimesat		299
+#define __NR_fstatat64		300
+#define __NR_unlinkat		301
+#define __NR_renameat		302
+#define __NR_linkat		303
+#define __NR_symlinkat		304
+#define __NR_readlinkat		305
+#define __NR_fchmodat		306
+#define __NR_faccessat		307
+#define __NR_pselect6		308
+#define __NR_ppoll		309
+#define __NR_unshare		310
+#define __NR_set_robust_list	311
+#define __NR_get_robust_list	312
+#define __NR_splice		313
+#define __NR_sync_file_range	314
+#define __NR_tee		315
+#define __NR_vmsplice		316
+#define __NR_move_pages		317
+#define __NR_getcpu		318
+#define __NR_epoll_pwait	319
 
 #ifdef __KERNEL__
 
-#define NR_syscalls 289
+#define NR_syscalls 320
 
 #define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_OLD_READDIR
diff --git a/include/asm-i386/alternative.h b/include/asm-i386/alternative.h
index 0f70b37..eb7da54 100644
--- a/include/asm-i386/alternative.h
+++ b/include/asm-i386/alternative.h
@@ -98,6 +98,12 @@
 		      ".previous" : output : [feat] "i" (feature), ##input)
 
 /*
+ * use this macro(s) if you need more than one output parameter
+ * in alternative_io
+ */
+#define ASM_OUTPUT2(a, b) a, b
+
+/*
  * Alternative inline assembly for SMP.
  *
  * The LOCK_PREFIX macro defined here replaces the LOCK and
diff --git a/include/asm-i386/poll.h b/include/asm-i386/poll.h
index 2cd4929..c98509d 100644
--- a/include/asm-i386/poll.h
+++ b/include/asm-i386/poll.h
@@ -1,27 +1 @@
-#ifndef __i386_POLL_H
-#define __i386_POLL_H
-
-/* These are specified by iBCS2 */
-#define POLLIN		0x0001
-#define POLLPRI		0x0002
-#define POLLOUT		0x0004
-#define POLLERR		0x0008
-#define POLLHUP		0x0010
-#define POLLNVAL	0x0020
-
-/* The rest seem to be more-or-less nonstandard. Check them! */
-#define POLLRDNORM	0x0040
-#define POLLRDBAND	0x0080
-#define POLLWRNORM	0x0100
-#define POLLWRBAND	0x0200
-#define POLLMSG		0x0400
-#define POLLREMOVE	0x1000
-#define POLLRDHUP       0x2000
-
-struct pollfd {
-	int fd;
-	short events;
-	short revents;
-};
-
-#endif
+#include <asm-generic/poll.h>
diff --git a/include/asm-i386/tsc.h b/include/asm-i386/tsc.h
index 3f3c1fa..62c091f 100644
--- a/include/asm-i386/tsc.h
+++ b/include/asm-i386/tsc.h
@@ -35,14 +35,16 @@
 static __always_inline cycles_t get_cycles_sync(void)
 {
 	unsigned long long ret;
-	unsigned eax;
+	unsigned eax, edx;
 
 	/*
   	 * Use RDTSCP if possible; it is guaranteed to be synchronous
  	 * and doesn't cause a VMEXIT on Hypervisors
 	 */
 	alternative_io(ASM_NOP3, ".byte 0x0f,0x01,0xf9", X86_FEATURE_RDTSCP,
-			 	 "=A" (ret), "0" (0ULL) : "ecx", "memory");
+		       ASM_OUTPUT2("=a" (eax), "=d" (edx)),
+		       "a" (0U), "d" (0U) : "ecx", "memory");
+	ret = (((unsigned long long)edx) << 32) | ((unsigned long long)eax);
 	if (ret)
 		return ret;
 
diff --git a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h
index bd21e79..e84ace1 100644
--- a/include/asm-i386/unistd.h
+++ b/include/asm-i386/unistd.h
@@ -326,10 +326,13 @@
 #define __NR_getcpu		318
 #define __NR_epoll_pwait	319
 #define __NR_utimensat		320
+#define __NR_signalfd		321
+#define __NR_timerfd		322
+#define __NR_eventfd		323
 
 #ifdef __KERNEL__
 
-#define NR_syscalls 321
+#define NR_syscalls 324
 
 #define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_OLD_READDIR
diff --git a/include/asm-ia64/poll.h b/include/asm-ia64/poll.h
index bcaf9f1..c98509d 100644
--- a/include/asm-ia64/poll.h
+++ b/include/asm-ia64/poll.h
@@ -1,32 +1 @@
-#ifndef _ASM_IA64_POLL_H
-#define _ASM_IA64_POLL_H
-
-/*
- * poll(2) bit definitions.  Based on <asm-i386/poll.h>.
- *
- * Modified 1998, 1999, 2002
- *	David Mosberger-Tang <davidm@hpl.hp.com>, Hewlett-Packard Co
- */
-
-#define POLLIN		0x0001
-#define POLLPRI		0x0002
-#define POLLOUT		0x0004
-#define POLLERR		0x0008
-#define POLLHUP		0x0010
-#define POLLNVAL	0x0020
-
-#define POLLRDNORM	0x0040
-#define POLLRDBAND	0x0080
-#define POLLWRNORM	0x0100
-#define POLLWRBAND	0x0200
-#define POLLMSG		0x0400
-#define POLLREMOVE	0x1000
-#define POLLRDHUP       0x2000
-
-struct pollfd {
-	int fd;
-	short events;
-	short revents;
-};
-
-#endif /* _ASM_IA64_POLL_H */
+#include <asm-generic/poll.h>
diff --git a/include/asm-m32r/pgtable-2level.h b/include/asm-m32r/pgtable-2level.h
index 7509257..bca3475 100644
--- a/include/asm-m32r/pgtable-2level.h
+++ b/include/asm-m32r/pgtable-2level.h
@@ -71,8 +71,8 @@
 #define pfn_pmd(pfn, prot)	__pmd(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
 
 #define PTE_FILE_MAX_BITS	29
-#define pte_to_pgoff(pte)	(((pte_val(pte) >> 2) & 0xef) | (((pte_val(pte) >> 10)) << 7))
-#define pgoff_to_pte(off)	((pte_t) { (((off) & 0xef) << 2) | (((off) >> 7) << 10) | _PAGE_FILE })
+#define pte_to_pgoff(pte)	(((pte_val(pte) >> 2) & 0x7f) | (((pte_val(pte) >> 10)) << 7))
+#define pgoff_to_pte(off)	((pte_t) { (((off) & 0x7f) << 2) | (((off) >> 7) << 10) | _PAGE_FILE })
 
 #endif /* __KERNEL__ */
 #endif /* _ASM_M32R_PGTABLE_2LEVEL_H */
diff --git a/include/asm-m32r/pgtable.h b/include/asm-m32r/pgtable.h
index 8b2a2f1..6604303 100644
--- a/include/asm-m32r/pgtable.h
+++ b/include/asm-m32r/pgtable.h
@@ -366,7 +366,7 @@
 #define pte_unmap_nested(pte)	do { } while (0)
 
 /* Encode and de-code a swap entry */
-#define __swp_type(x)			(((x).val >> 2) & 0x3f)
+#define __swp_type(x)			(((x).val >> 2) & 0x1f)
 #define __swp_offset(x)			((x).val >> 10)
 #define __swp_entry(type, offset)	\
 	((swp_entry_t) { ((type) << 2) | ((offset) << 10) })
diff --git a/include/asm-m32r/poll.h b/include/asm-m32r/poll.h
index 9e0e700..c98509d 100644
--- a/include/asm-m32r/poll.h
+++ b/include/asm-m32r/poll.h
@@ -1,32 +1 @@
-#ifndef _ASM_M32R_POLL_H
-#define _ASM_M32R_POLL_H
-
-/*
- * poll(2) bit definitions.  Based on <asm-i386/poll.h>.
- *
- * Modified 2004
- *      Hirokazu Takata <takata at linux-m32r.org>
- */
-
-#define POLLIN		0x0001
-#define POLLPRI		0x0002
-#define POLLOUT		0x0004
-#define POLLERR		0x0008
-#define POLLHUP		0x0010
-#define POLLNVAL	0x0020
-
-#define POLLRDNORM	0x0040
-#define POLLRDBAND	0x0080
-#define POLLWRNORM	0x0100
-#define POLLWRBAND	0x0200
-#define POLLMSG		0x0400
-#define POLLREMOVE	0x1000
-#define POLLRDHUP       0x2000
-
-struct pollfd {
-	int fd;
-	short events;
-	short revents;
-};
-
-#endif  /* _ASM_M32R_POLL_H */
+#include <asm-generic/poll.h>
diff --git a/include/asm-m32r/system.h b/include/asm-m32r/system.h
index f62f5c9..b291b2f 100644
--- a/include/asm-m32r/system.h
+++ b/include/asm-m32r/system.h
@@ -21,12 +21,22 @@
  * `next' and `prev' should be struct task_struct, but it isn't always defined
  */
 
+#if defined(CONFIG_FRAME_POINTER) || \
+	!defined(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER)
+#define M32R_PUSH_FP "	push fp\n"
+#define M32R_POP_FP  "	pop  fp\n"
+#else
+#define M32R_PUSH_FP ""
+#define M32R_POP_FP  ""
+#endif
+
 #define switch_to(prev, next, last)  do { \
 	__asm__ __volatile__ ( \
 		"	seth	lr, #high(1f)				\n" \
 		"	or3	lr, lr, #low(1f)			\n" \
 		"	st	lr, @%4  ; store old LR			\n" \
 		"	ld	lr, @%5  ; load new LR			\n" \
+			M32R_PUSH_FP \
 		"	st	sp, @%2  ; store old SP			\n" \
 		"	ld	sp, @%3  ; load new SP			\n" \
 		"	push	%1  ; store `prev' on new stack		\n" \
@@ -34,6 +44,7 @@
 		"	.fillinsn					\n" \
 		"1:							\n" \
 		"	pop	%0  ; restore `__last' from new stack	\n" \
+			M32R_POP_FP \
 		: "=r" (last) \
 		: "0" (prev), \
 		  "r" (&(prev->thread.sp)), "r" (&(next->thread.sp)), \
diff --git a/include/asm-m68k/poll.h b/include/asm-m68k/poll.h
index 0fb8843..f080fcd 100644
--- a/include/asm-m68k/poll.h
+++ b/include/asm-m68k/poll.h
@@ -1,24 +1,9 @@
 #ifndef __m68k_POLL_H
 #define __m68k_POLL_H
 
-#define POLLIN		  1
-#define POLLPRI		  2
-#define POLLOUT		  4
-#define POLLERR		  8
-#define POLLHUP		 16
-#define POLLNVAL	 32
-#define POLLRDNORM	 64
 #define POLLWRNORM	POLLOUT
-#define POLLRDBAND	128
 #define POLLWRBAND	256
-#define POLLMSG		0x0400
-#define POLLREMOVE	0x1000
-#define POLLRDHUP       0x2000
 
-struct pollfd {
-	int fd;
-	short events;
-	short revents;
-};
+#include <asm-generic/poll.h>
 
 #endif
diff --git a/include/asm-mips/poll.h b/include/asm-mips/poll.h
index 70881f8..47b9520 100644
--- a/include/asm-mips/poll.h
+++ b/include/asm-mips/poll.h
@@ -1,28 +1,9 @@
 #ifndef __ASM_POLL_H
 #define __ASM_POLL_H
 
-#define POLLIN		0x0001
-#define POLLPRI		0x0002
-#define POLLOUT		0x0004
-
-#define POLLERR		0x0008
-#define POLLHUP		0x0010
-#define POLLNVAL	0x0020
-
-#define POLLRDNORM	0x0040
-#define POLLRDBAND	0x0080
 #define POLLWRNORM	POLLOUT
 #define POLLWRBAND	0x0100
 
-/* These seem to be more or less nonstandard ...  */
-#define POLLMSG		0x0400
-#define POLLREMOVE	0x1000
-#define POLLRDHUP       0x2000
-
-struct pollfd {
-	int fd;
-	short events;
-	short revents;
-};
+#include <asm-generic/poll.h>
 
 #endif /* __ASM_POLL_H */
diff --git a/include/asm-parisc/poll.h b/include/asm-parisc/poll.h
index 20e4d03..c98509d 100644
--- a/include/asm-parisc/poll.h
+++ b/include/asm-parisc/poll.h
@@ -1,27 +1 @@
-#ifndef __PARISC_POLL_H
-#define __PARISC_POLL_H
-
-/* These are specified by iBCS2 */
-#define POLLIN		0x0001
-#define POLLPRI		0x0002
-#define POLLOUT		0x0004
-#define POLLERR		0x0008
-#define POLLHUP		0x0010
-#define POLLNVAL	0x0020
-
-/* The rest seem to be more-or-less nonstandard. Check them! */
-#define POLLRDNORM	0x0040
-#define POLLRDBAND	0x0080
-#define POLLWRNORM	0x0100
-#define POLLWRBAND	0x0200
-#define POLLMSG		0x0400
-#define POLLREMOVE	0x1000
-#define POLLRDHUP       0x2000
-
-struct pollfd {
-	int fd;
-	short events;
-	short revents;
-};
-
-#endif
+#include <asm-generic/poll.h>
diff --git a/include/asm-powerpc/hw_irq.h b/include/asm-powerpc/hw_irq.h
index 9e4dd98..a7b60bf 100644
--- a/include/asm-powerpc/hw_irq.h
+++ b/include/asm-powerpc/hw_irq.h
@@ -48,8 +48,15 @@
 
 #define irqs_disabled()		(local_get_flags() == 0)
 
-#define hard_irq_enable()	__mtmsrd(mfmsr() | MSR_EE, 1)
-#define hard_irq_disable()	__mtmsrd(mfmsr() & ~MSR_EE, 1)
+#define __hard_irq_enable()	__mtmsrd(mfmsr() | MSR_EE, 1)
+#define __hard_irq_disable()	__mtmsrd(mfmsr() & ~MSR_EE, 1)
+
+#define  hard_irq_disable()			\
+	do {					\
+		__hard_irq_disable();		\
+		get_paca()->soft_enabled = 0;	\
+		get_paca()->hard_enabled = 0;	\
+	} while(0)
 
 #else
 
diff --git a/include/asm-powerpc/poll.h b/include/asm-powerpc/poll.h
index 9c7d126..c98509d 100644
--- a/include/asm-powerpc/poll.h
+++ b/include/asm-powerpc/poll.h
@@ -1,24 +1 @@
-#ifndef _ASM_POWERPC_POLL_H
-#define _ASM_POWERPC_POLL_H
-
-#define POLLIN		0x0001
-#define POLLPRI		0x0002
-#define POLLOUT		0x0004
-#define POLLERR		0x0008
-#define POLLHUP		0x0010
-#define POLLNVAL	0x0020
-#define POLLRDNORM	0x0040
-#define POLLRDBAND	0x0080
-#define POLLWRNORM	0x0100
-#define POLLWRBAND	0x0200
-#define POLLMSG		0x0400
-#define POLLREMOVE	0x1000
-#define POLLRDHUP       0x2000
-
-struct pollfd {
-	int fd;
-	short events;
-	short revents;
-};
-
-#endif	/* _ASM_POWERPC_POLL_H */
+#include <asm-generic/poll.h>
diff --git a/include/asm-s390/poll.h b/include/asm-s390/poll.h
index 6f7f65a..c98509d 100644
--- a/include/asm-s390/poll.h
+++ b/include/asm-s390/poll.h
@@ -1,35 +1 @@
-/*
- *  include/asm-s390/poll.h
- *
- *  S390 version
- *
- *  Derived from "include/asm-i386/poll.h"
- */
-
-#ifndef __S390_POLL_H
-#define __S390_POLL_H
-
-/* These are specified by iBCS2 */
-#define POLLIN          0x0001
-#define POLLPRI         0x0002
-#define POLLOUT         0x0004
-#define POLLERR         0x0008
-#define POLLHUP         0x0010
-#define POLLNVAL        0x0020
-
-/* The rest seem to be more-or-less nonstandard. Check them! */
-#define POLLRDNORM	0x0040
-#define POLLRDBAND	0x0080
-#define POLLWRNORM	0x0100
-#define POLLWRBAND	0x0200
-#define POLLMSG		0x0400
-#define POLLREMOVE	0x1000
-#define POLLRDHUP       0x2000
-
-struct pollfd {
-	int fd;
-	short events;
-	short revents;
-};
-
-#endif
+#include <asm-generic/poll.h>
diff --git a/include/asm-sh/poll.h b/include/asm-sh/poll.h
index dbca9b3..c98509d 100644
--- a/include/asm-sh/poll.h
+++ b/include/asm-sh/poll.h
@@ -1,27 +1 @@
-#ifndef __ASM_SH_POLL_H
-#define __ASM_SH_POLL_H
-
-/* These are specified by iBCS2 */
-#define POLLIN		0x0001
-#define POLLPRI		0x0002
-#define POLLOUT		0x0004
-#define POLLERR		0x0008
-#define POLLHUP		0x0010
-#define POLLNVAL	0x0020
-
-/* The rest seem to be more-or-less nonstandard. Check them! */
-#define POLLRDNORM	0x0040
-#define POLLRDBAND	0x0080
-#define POLLWRNORM	0x0100
-#define POLLWRBAND	0x0200
-#define POLLMSG		0x0400
-#define POLLREMOVE	0x1000
-#define POLLRDHUP       0x2000
-
-struct pollfd {
-	int fd;
-	short events;
-	short revents;
-};
-
-#endif /* __ASM_SH_POLL_H */
+#include <asm-generic/poll.h>
diff --git a/include/asm-sh64/poll.h b/include/asm-sh64/poll.h
index 3a6cbad..ca29502 100644
--- a/include/asm-sh64/poll.h
+++ b/include/asm-sh64/poll.h
@@ -1,37 +1,8 @@
 #ifndef __ASM_SH64_POLL_H
 #define __ASM_SH64_POLL_H
 
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * include/asm-sh64/poll.h
- *
- * Copyright (C) 2000, 2001  Paolo Alberelli
- *
- */
+#include <asm-generic/poll.h>
 
-/* These are specified by iBCS2 */
-#define POLLIN		0x0001
-#define POLLPRI		0x0002
-#define POLLOUT		0x0004
-#define POLLERR		0x0008
-#define POLLHUP		0x0010
-#define POLLNVAL	0x0020
-
-/* The rest seem to be more-or-less nonstandard. Check them! */
-#define POLLRDNORM	0x0040
-#define POLLRDBAND	0x0080
-#define POLLWRNORM	0x0100
-#define POLLWRBAND	0x0200
-#define POLLMSG		0x0400
-#define POLLRDHUP       0x2000
-
-struct pollfd {
-	int fd;
-	short events;
-	short revents;
-};
+#undef POLLREMOVE
 
 #endif /* __ASM_SH64_POLL_H */
diff --git a/include/asm-sparc/poll.h b/include/asm-sparc/poll.h
index 26f13fb..091d3ad 100644
--- a/include/asm-sparc/poll.h
+++ b/include/asm-sparc/poll.h
@@ -1,24 +1,12 @@
 #ifndef __SPARC_POLL_H
 #define __SPARC_POLL_H
 
-#define POLLIN		  1
-#define POLLPRI		  2
-#define POLLOUT		  4
-#define POLLERR		  8
-#define POLLHUP		 16
-#define POLLNVAL	 32
-#define POLLRDNORM	 64
 #define POLLWRNORM	POLLOUT
-#define POLLRDBAND	128
 #define POLLWRBAND	256
 #define POLLMSG		512
 #define POLLREMOVE	1024
 #define POLLRDHUP       2048
 
-struct pollfd {
-	int fd;
-	short events;
-	short revents;
-};
+#include <asm-generic/poll.h>
 
 #endif
diff --git a/include/asm-sparc64/poll.h b/include/asm-sparc64/poll.h
index ab6b0d1..ebeeb38 100644
--- a/include/asm-sparc64/poll.h
+++ b/include/asm-sparc64/poll.h
@@ -1,24 +1,12 @@
 #ifndef __SPARC64_POLL_H
 #define __SPARC64_POLL_H
 
-#define POLLIN		  1
-#define POLLPRI		  2
-#define POLLOUT		  4
-#define POLLERR		  8
-#define POLLHUP		 16
-#define POLLNVAL	 32
-#define POLLRDNORM	 64
 #define POLLWRNORM	POLLOUT
-#define POLLRDBAND	128
 #define POLLWRBAND	256
 #define POLLMSG		512
 #define POLLREMOVE	1024
 #define POLLRDHUP       2048
 
-struct pollfd {
-	int fd;
-	short events;
-	short revents;
-};
+#include <asm-generic/poll.h>
 
 #endif
diff --git a/include/asm-um/thread_info.h b/include/asm-um/thread_info.h
index 261e2f4..18a13ba 100644
--- a/include/asm-um/thread_info.h
+++ b/include/asm-um/thread_info.h
@@ -22,6 +22,7 @@
 					 	   0-0xBFFFFFFF for user
 						   0-0xFFFFFFFF for kernel */
 	struct restart_block    restart_block;
+	struct thread_info	*real_thread;    /* Points to non-IRQ stack */
 };
 
 #define INIT_THREAD_INFO(tsk)			\
@@ -35,6 +36,7 @@
 	.restart_block =  {			\
 		.fn =  do_no_restart_syscall,	\
 	},					\
+	.real_thread = NULL,			\
 }
 
 #define init_thread_info	(init_thread_union.thread_info)
diff --git a/include/asm-v850/poll.h b/include/asm-v850/poll.h
index c10176c..803cad0 100644
--- a/include/asm-v850/poll.h
+++ b/include/asm-v850/poll.h
@@ -1,24 +1,9 @@
 #ifndef __V850_POLL_H__
 #define __V850_POLL_H__
 
-#define POLLIN		0x0001
-#define POLLPRI		0x0002
-#define POLLOUT		0x0004
-#define POLLERR		0x0008
-#define POLLHUP		0x0010
-#define POLLNVAL	0x0020
-#define POLLRDNORM	0x0040
 #define POLLWRNORM	POLLOUT
-#define POLLRDBAND	0x0080
 #define POLLWRBAND	0x0100
-#define POLLMSG		0x0400
-#define POLLREMOVE	0x1000
-#define POLLRDHUP       0x2000
 
-struct pollfd {
-	int fd;
-	short events;
-	short revents;
-};
+#include <asm-generic/poll.h>
 
 #endif /* __V850_POLL_H__ */
diff --git a/include/asm-x86_64/alternative.h b/include/asm-x86_64/alternative.h
index a09fe85..a094276 100644
--- a/include/asm-x86_64/alternative.h
+++ b/include/asm-x86_64/alternative.h
@@ -103,6 +103,12 @@
 		      ".previous" : output : [feat] "i" (feature), ##input)
 
 /*
+ * use this macro(s) if you need more than one output parameter
+ * in alternative_io
+ */
+#define ASM_OUTPUT2(a, b) a, b
+
+/*
  * Alternative inline assembly for SMP.
  *
  * The LOCK_PREFIX macro defined here replaces the LOCK and
diff --git a/include/asm-x86_64/page.h b/include/asm-x86_64/page.h
index dee632f..e327c83 100644
--- a/include/asm-x86_64/page.h
+++ b/include/asm-x86_64/page.h
@@ -80,6 +80,15 @@
 #define __PHYSICAL_START	CONFIG_PHYSICAL_START
 #define __KERNEL_ALIGN		0x200000
 
+/*
+ * Make sure kernel is aligned to 2MB address. Catching it at compile
+ * time is better. Change your config file and compile the kernel
+ * for a 2MB aligned address (CONFIG_PHYSICAL_START)
+ */
+#if (CONFIG_PHYSICAL_START % __KERNEL_ALIGN) != 0
+#error "CONFIG_PHYSICAL_START must be a multiple of 2MB"
+#endif
+
 #define __START_KERNEL		(__START_KERNEL_map + __PHYSICAL_START)
 #define __START_KERNEL_map	_AC(0xffffffff80000000, UL)
 #define __PAGE_OFFSET           _AC(0xffff810000000000, UL)
diff --git a/include/asm-x86_64/poll.h b/include/asm-x86_64/poll.h
index c0475a9..c98509d 100644
--- a/include/asm-x86_64/poll.h
+++ b/include/asm-x86_64/poll.h
@@ -1,27 +1 @@
-#ifndef __x86_64_POLL_H
-#define __x86_64_POLL_H
-
-/* These are specified by iBCS2 */
-#define POLLIN		0x0001
-#define POLLPRI		0x0002
-#define POLLOUT		0x0004
-#define POLLERR		0x0008
-#define POLLHUP		0x0010
-#define POLLNVAL	0x0020
-
-/* The rest seem to be more-or-less nonstandard. Check them! */
-#define POLLRDNORM	0x0040
-#define POLLRDBAND	0x0080
-#define POLLWRNORM	0x0100
-#define POLLWRBAND	0x0200
-#define POLLMSG		0x0400
-#define POLLREMOVE	0x1000
-#define POLLRDHUP       0x2000
-
-struct pollfd {
-	int fd;
-	short events;
-	short revents;
-};
-
-#endif
+#include <asm-generic/poll.h>
diff --git a/include/asm-x86_64/unistd.h b/include/asm-x86_64/unistd.h
index 5957039..ae1ed05 100644
--- a/include/asm-x86_64/unistd.h
+++ b/include/asm-x86_64/unistd.h
@@ -621,6 +621,15 @@
 __SYSCALL(__NR_move_pages, sys_move_pages)
 #define __NR_utimensat		280
 __SYSCALL(__NR_utimensat, sys_utimensat)
+#define __IGNORE_getcpu		/* implemented as a vsyscall */
+#define __NR_epoll_pwait	281
+__SYSCALL(__NR_epoll_pwait, sys_epoll_pwait)
+#define __NR_signalfd		282
+__SYSCALL(__NR_signalfd, sys_signalfd)
+#define __NR_timerfd		282
+__SYSCALL(__NR_timerfd, sys_timerfd)
+#define __NR_eventfd		283
+__SYSCALL(__NR_eventfd, sys_eventfd)
 
 #ifndef __NO_STUBS
 #define __ARCH_WANT_OLD_READDIR
diff --git a/include/asm-xtensa/poll.h b/include/asm-xtensa/poll.h
index 6fd9477..9d2d599 100644
--- a/include/asm-xtensa/poll.h
+++ b/include/asm-xtensa/poll.h
@@ -11,28 +11,10 @@
 #ifndef _XTENSA_POLL_H
 #define _XTENSA_POLL_H
 
-
-#define POLLIN		0x0001
-#define POLLPRI		0x0002
-#define POLLOUT		0x0004
-
-#define POLLERR		0x0008
-#define POLLHUP		0x0010
-#define POLLNVAL	0x0020
-
-#define POLLRDNORM	0x0040
-#define POLLRDBAND	0x0080
 #define POLLWRNORM	POLLOUT
 #define POLLWRBAND	0x0100
-
-#define POLLMSG		0x0400
 #define POLLREMOVE	0x0800
-#define POLLRDHUP       0x2000
 
-struct pollfd {
-	int fd;
-	short events;
-	short revents;
-};
+#include <asm-generic/poll.h>
 
 #endif /* _XTENSA_POLL_H */
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 94cc04a..bcd01f2 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -140,7 +140,6 @@
 header-y += sockios.h
 header-y += som.h
 header-y += sound.h
-header-y += synclink.h
 header-y += taskstats.h
 header-y += telephony.h
 header-y += termios.h
@@ -191,6 +190,7 @@
 unifdef-y += errqueue.h
 unifdef-y += ethtool.h
 unifdef-y += eventpoll.h
+unifdef-y += signalfd.h
 unifdef-y += ext2_fs.h
 unifdef-y += ext3_fs.h
 unifdef-y += fb.h
@@ -320,6 +320,7 @@
 unifdef-y += soundcard.h
 unifdef-y += stat.h
 unifdef-y += stddef.h
+unifdef-y += synclink.h
 unifdef-y += sysctl.h
 unifdef-y += tcp.h
 unifdef-y += time.h
diff --git a/include/linux/aio.h b/include/linux/aio.h
index 43dc2eb..b903fc0 100644
--- a/include/linux/aio.h
+++ b/include/linux/aio.h
@@ -119,6 +119,12 @@
 
 	struct list_head	ki_list;	/* the aio core uses this
 						 * for cancellation */
+
+	/*
+	 * If the aio_resfd field of the userspace iocb is not zero,
+	 * this is the underlying file* to deliver event to.
+	 */
+	struct file		*ki_eventfd;
 };
 
 #define is_sync_kiocb(iocb)	((iocb)->ki_key == KIOCB_SYNC_KEY)
diff --git a/include/linux/aio_abi.h b/include/linux/aio_abi.h
index e3ca0a4..9e01729 100644
--- a/include/linux/aio_abi.h
+++ b/include/linux/aio_abi.h
@@ -45,6 +45,14 @@
 	IOCB_CMD_PWRITEV = 8,
 };
 
+/*
+ * Valid flags for the "aio_flags" member of the "struct iocb".
+ *
+ * IOCB_FLAG_RESFD - Set if the "aio_resfd" member of the "struct iocb"
+ *                   is valid.
+ */
+#define IOCB_FLAG_RESFD		(1 << 0)
+
 /* read() from /dev/aio returns these structures. */
 struct io_event {
 	__u64		data;		/* the data field from the iocb */
@@ -84,7 +92,15 @@
 
 	/* extra parameters */
 	__u64	aio_reserved2;	/* TODO: use this for a (struct sigevent *) */
-	__u64	aio_reserved3;
+
+	/* flags for the "struct iocb" */
+	__u32	aio_flags;
+
+	/*
+	 * if the IOCB_FLAG_RESFD flag of "aio_flags" is set, this is an
+	 * eventfd to signal AIO readiness to
+	 */
+	__u32	aio_resfd;
 }; /* 64 bytes */
 
 #undef IFBIG
diff --git a/include/linux/anon_inodes.h b/include/linux/anon_inodes.h
new file mode 100644
index 0000000..b2e1ba3
--- /dev/null
+++ b/include/linux/anon_inodes.h
@@ -0,0 +1,16 @@
+/*
+ *  include/linux/anon_inodes.h
+ *
+ *  Copyright (C) 2007  Davide Libenzi <davidel@xmailserver.org>
+ *
+ */
+
+#ifndef _LINUX_ANON_INODES_H
+#define _LINUX_ANON_INODES_H
+
+int anon_inode_getfd(int *pfd, struct inode **pinode, struct file **pfile,
+		     const char *name, const struct file_operations *fops,
+		     void *priv);
+
+#endif /* _LINUX_ANON_INODES_H */
+
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 773e30d..fccc6e5 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -91,6 +91,7 @@
 #define AUDIT_MQ_GETSETATTR	1315	/* POSIX MQ get/set attribute record type */
 #define AUDIT_KERNEL_OTHER	1316	/* For use by 3rd party modules */
 #define AUDIT_FD_PAIR		1317    /* audit record for pipe/socketpair */
+#define AUDIT_OBJ_PID		1318	/* ptrace target */
 
 #define AUDIT_AVC		1400	/* SE Linux avc denial or grant */
 #define AUDIT_SELINUX_ERR	1401	/* Internal SE Linux Errors */
@@ -111,6 +112,7 @@
 #define AUDIT_FIRST_KERN_ANOM_MSG   1700
 #define AUDIT_LAST_KERN_ANOM_MSG    1799
 #define AUDIT_ANOM_PROMISCUOUS      1700 /* Device changed promiscuous mode */
+#define AUDIT_ANOM_ABEND            1701 /* Process ended abnormally */
 
 #define AUDIT_KERNEL		2000	/* Asynchronous audit record. NOT A REQUEST. */
 
@@ -148,6 +150,8 @@
 #define AUDIT_CLASS_READ_32 5
 #define AUDIT_CLASS_WRITE 6
 #define AUDIT_CLASS_WRITE_32 7
+#define AUDIT_CLASS_SIGNAL 8
+#define AUDIT_CLASS_SIGNAL_32 9
 
 /* This bitmask is used to validate user input.  It represents all bits that
  * are currently used in an audit field constant understood by the kernel.
@@ -337,6 +341,7 @@
 #define AUDITSC_RESULT(x) ( ((long)(x))<0?AUDITSC_FAILURE:AUDITSC_SUCCESS )
 extern int __init audit_register_class(int class, unsigned *list);
 extern int audit_classify_syscall(int abi, unsigned syscall);
+extern int audit_classify_arch(int arch);
 #ifdef CONFIG_AUDITSYSCALL
 /* These are defined in auditsc.c */
 				/* Public API */
@@ -351,7 +356,8 @@
 extern void __audit_inode(const char *name, const struct inode *inode);
 extern void __audit_inode_child(const char *dname, const struct inode *inode,
 				const struct inode *parent);
-extern void __audit_inode_update(const struct inode *inode);
+extern void __audit_ptrace(struct task_struct *t);
+
 static inline int audit_dummy_context(void)
 {
 	void *p = current->audit_context;
@@ -372,9 +378,12 @@
 	if (unlikely(!audit_dummy_context()))
 		__audit_inode_child(dname, inode, parent);
 }
-static inline void audit_inode_update(const struct inode *inode) {
+void audit_core_dumps(long signr);
+
+static inline void audit_ptrace(struct task_struct *t)
+{
 	if (unlikely(!audit_dummy_context()))
-		__audit_inode_update(inode);
+		__audit_ptrace(t);
 }
 
 				/* Private API (for audit.c only) */
@@ -447,6 +456,7 @@
 	return 0;
 }
 extern int audit_n_rules;
+extern int audit_signals;
 #else
 #define audit_alloc(t) ({ 0; })
 #define audit_free(t) do { ; } while (0)
@@ -457,10 +467,9 @@
 #define audit_putname(n) do { ; } while (0)
 #define __audit_inode(n,i) do { ; } while (0)
 #define __audit_inode_child(d,i,p) do { ; } while (0)
-#define __audit_inode_update(i) do { ; } while (0)
 #define audit_inode(n,i) do { ; } while (0)
 #define audit_inode_child(d,i,p) do { ; } while (0)
-#define audit_inode_update(i) do { ; } while (0)
+#define audit_core_dumps(i) do { ; } while (0)
 #define auditsc_get_stamp(c,t,s) do { BUG(); } while (0)
 #define audit_get_loginuid(c) ({ -1; })
 #define audit_log_task_context(b) do { ; } while (0)
@@ -477,7 +486,9 @@
 #define audit_mq_timedreceive(d,l,p,t) ({ 0; })
 #define audit_mq_notify(d,n) ({ 0; })
 #define audit_mq_getsetattr(d,s) ({ 0; })
+#define audit_ptrace(t) ((void)0)
 #define audit_n_rules 0
+#define audit_signals 0
 #endif
 
 #ifdef CONFIG_AUDIT
diff --git a/include/linux/compat.h b/include/linux/compat.h
index 70a157a..636502c 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -225,6 +225,11 @@
 	return lhs->tv_nsec - rhs->tv_nsec;
 }
 
+extern int get_compat_itimerspec(struct itimerspec *dst,
+				 const struct compat_itimerspec __user *src);
+extern int put_compat_itimerspec(struct compat_itimerspec __user *dst,
+				 const struct itimerspec *src);
+
 asmlinkage long compat_sys_adjtimex(struct compat_timex __user *utp);
 
 extern int compat_printk(const char *fmt, ...);
diff --git a/include/linux/eventfd.h b/include/linux/eventfd.h
new file mode 100644
index 0000000..0d6ecc6
--- /dev/null
+++ b/include/linux/eventfd.h
@@ -0,0 +1,29 @@
+/*
+ *  include/linux/eventfd.h
+ *
+ *  Copyright (C) 2007  Davide Libenzi <davidel@xmailserver.org>
+ *
+ */
+
+#ifndef _LINUX_EVENTFD_H
+#define _LINUX_EVENTFD_H
+
+
+#ifdef __KERNEL__
+
+#ifdef CONFIG_EVENTFD
+
+struct file *eventfd_fget(int fd);
+int eventfd_signal(struct file *file, int n);
+
+#else /* CONFIG_EVENTFD */
+
+#define eventfd_fget(fd) ERR_PTR(-ENOSYS)
+#define eventfd_signal(f, n) 0
+
+#endif /* CONFIG_EVENTFD */
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_EVENTFD_H */
+
diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index f589559..4c03ee3 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -434,6 +434,10 @@
 
 #endif
 
-#endif
+#else /* CONFIG_BLOCK */
+
+static inline void printk_all_partitions(void) { }
+
+#endif /* CONFIG_BLOCK */
 
 #endif
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 37076b1..827ee74 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -275,6 +275,7 @@
 #define HID_QUIRK_LOGITECH_DESCRIPTOR		0x00100000
 #define HID_QUIRK_DUPLICATE_USAGES		0x00200000
 #define HID_QUIRK_RESET_LEDS			0x00400000
+#define HID_QUIRK_SWAPPED_MIN_MAX		0x00800000
 
 /*
  * This is the global environment of the parser. This information is
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index 45170b2..276ccaa 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -65,9 +65,9 @@
 	.posix_timers	 = LIST_HEAD_INIT(sig.posix_timers),		\
 	.cpu_timers	= INIT_CPU_TIMERS(sig.cpu_timers),		\
 	.rlim		= INIT_RLIMITS,					\
-	.pgrp		= 1,						\
+	.pgrp		= 0,						\
 	.tty_old_pgrp   = NULL,						\
-	{ .__session      = 1},						\
+	{ .__session      = 0},						\
 }
 
 extern struct nsproxy init_nsproxy;
@@ -84,10 +84,33 @@
 	.count		= ATOMIC_INIT(1), 				\
 	.action		= { { { .sa_handler = NULL, } }, },		\
 	.siglock	= __SPIN_LOCK_UNLOCKED(sighand.siglock),	\
+	.signalfd_list	= LIST_HEAD_INIT(sighand.signalfd_list),	\
 }
 
 extern struct group_info init_groups;
 
+#define INIT_STRUCT_PID {						\
+	.count 		= ATOMIC_INIT(1),				\
+	.nr		= 0, 						\
+	/* Don't put this struct pid in pid_hash */			\
+	.pid_chain	= { .next = NULL, .pprev = NULL },		\
+	.tasks		= {						\
+		{ .first = &init_task.pids[PIDTYPE_PID].node },		\
+		{ .first = &init_task.pids[PIDTYPE_PGID].node },	\
+		{ .first = &init_task.pids[PIDTYPE_SID].node },		\
+	},								\
+	.rcu		= RCU_HEAD_INIT,				\
+}
+
+#define INIT_PID_LINK(type) 					\
+{								\
+	.node = {						\
+		.next = NULL,					\
+		.pprev = &init_struct_pid.tasks[type].first,	\
+	},							\
+	.pid = &init_struct_pid,				\
+}
+
 /*
  *  INIT_TASK is used to set up the first task table, touch at
  * your own risk!. Base=0, limit=0x1fffff (=2MB)
@@ -139,6 +162,11 @@
 	.cpu_timers	= INIT_CPU_TIMERS(tsk.cpu_timers),		\
 	.fs_excl	= ATOMIC_INIT(0),				\
 	.pi_lock	= __SPIN_LOCK_UNLOCKED(tsk.pi_lock),		\
+	.pids = {							\
+		[PIDTYPE_PID]  = INIT_PID_LINK(PIDTYPE_PID),		\
+		[PIDTYPE_PGID] = INIT_PID_LINK(PIDTYPE_PGID),		\
+		[PIDTYPE_SID]  = INIT_PID_LINK(PIDTYPE_SID),		\
+	},								\
 	INIT_TRACE_IRQFLAGS						\
 	INIT_LOCKDEP							\
 }
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index f7b01b9..5323f62 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -241,6 +241,16 @@
 #define save_and_cli(x)	save_and_cli(&x)
 #endif /* CONFIG_SMP */
 
+/* Some architectures might implement lazy enabling/disabling of
+ * interrupts. In some cases, such as stop_machine, we might want
+ * to ensure that after a local_irq_disable(), interrupts have
+ * really been disabled in hardware. Such architectures need to
+ * implement the following hook.
+ */
+#ifndef hard_irq_disable
+#define hard_irq_disable()	do { } while(0)
+#endif
+
 /* PLEASE, avoid to allocate new softirqs, if you need not _really_ high
    frequency threaded job scheduling. For almost all the purposes
    tasklets are more than enough. F.e. all serial device BHs et
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 8645181..eec0d13 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -213,6 +213,17 @@
 
 extern void dump_stack(void);
 
+enum {
+	DUMP_PREFIX_NONE,
+	DUMP_PREFIX_ADDRESS,
+	DUMP_PREFIX_OFFSET
+};
+extern void hex_dump_to_buffer(const void *buf, size_t len, char *linebuf,
+				size_t linebuflen);
+extern void print_hex_dump(const char *level, int prefix_type,
+				void *buf, size_t len);
+#define hex_asc(x)	"0123456789abcdef"[x]
+
 #ifdef DEBUG
 /* If you are writing a driver, please use dev_dbg instead */
 #define pr_debug(fmt,arg...) \
diff --git a/include/linux/magic.h b/include/linux/magic.h
index a9c6567..9d713c0 100644
--- a/include/linux/magic.h
+++ b/include/linux/magic.h
@@ -14,6 +14,7 @@
 #define ISOFS_SUPER_MAGIC	0x9660
 #define JFFS2_SUPER_MAGIC	0x72b6
 #define KVMFS_SUPER_MAGIC	0x19700426
+#define ANON_INODE_FS_MAGIC	0x09041934
 
 #define MINIX_SUPER_MAGIC	0x137F		/* original minix fs */
 #define MINIX_SUPER_MAGIC2	0x138F		/* minix fs, 30 char names */
diff --git a/include/linux/module.h b/include/linux/module.h
index 792d483..e6e0f86 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -124,7 +124,7 @@
  */
 #define MODULE_LICENSE(_license) MODULE_INFO(license, _license)
 
-/* Author, ideally of form NAME <EMAIL>[, NAME <EMAIL>]*[ and NAME <EMAIL>] */
+/* Author, ideally of form NAME[, NAME]*[ and NAME] */
 #define MODULE_AUTHOR(_author) MODULE_INFO(author, _author)
   
 /* What your module does. */
diff --git a/include/linux/mpage.h b/include/linux/mpage.h
index cc5fb75..068a0c9 100644
--- a/include/linux/mpage.h
+++ b/include/linux/mpage.h
@@ -12,7 +12,6 @@
 #ifdef CONFIG_BLOCK
 
 struct writeback_control;
-typedef int (writepage_t)(struct page *page, struct writeback_control *wbc);
 
 int mpage_readpages(struct address_space *mapping, struct list_head *pages,
 				unsigned nr_pages, get_block_t get_block);
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 3044622..f671cd2 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -467,6 +467,8 @@
 	/* device index hash chain */
 	struct hlist_node	index_hlist;
 
+	struct net_device	*link_watch_next;
+
 	/* register/unregister state machine */
 	enum { NETREG_UNINITIALIZED=0,
 	       NETREG_REGISTERED,	/* completed register_netdevice */
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index 022edfa..7e733a6 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -54,6 +54,14 @@
 	unsigned char data[0];
 };
 
+#define XT_TARGET_INIT(__name, __size)					       \
+{									       \
+	.target.u.user = {						       \
+		.target_size	= XT_ALIGN(__size),			       \
+		.name		= __name,				       \
+	},								       \
+}
+
 struct xt_standard_target
 {
 	struct xt_entry_target target;
diff --git a/include/linux/netfilter_arp/arp_tables.h b/include/linux/netfilter_arp/arp_tables.h
index 24c8786d..584cd1b 100644
--- a/include/linux/netfilter_arp/arp_tables.h
+++ b/include/linux/netfilter_arp/arp_tables.h
@@ -238,6 +238,47 @@
  */
 #ifdef __KERNEL__
 
+/* Standard entry. */
+struct arpt_standard
+{
+	struct arpt_entry entry;
+	struct arpt_standard_target target;
+};
+
+struct arpt_error_target
+{
+	struct arpt_entry_target target;
+	char errorname[ARPT_FUNCTION_MAXNAMELEN];
+};
+
+struct arpt_error
+{
+	struct arpt_entry entry;
+	struct arpt_error_target target;
+};
+
+#define ARPT_ENTRY_INIT(__size)						       \
+{									       \
+	.target_offset	= sizeof(struct arpt_entry),			       \
+	.next_offset	= (__size),					       \
+}
+
+#define ARPT_STANDARD_INIT(__verdict)					       \
+{									       \
+	.entry		= ARPT_ENTRY_INIT(sizeof(struct arpt_standard)),       \
+	.target		= XT_TARGET_INIT(ARPT_STANDARD_TARGET,		       \
+					 sizeof(struct arpt_standard_target)), \
+	.target.verdict	= -(__verdict) - 1,				       \
+}
+
+#define ARPT_ERROR_INIT							       \
+{									       \
+	.entry		= ARPT_ENTRY_INIT(sizeof(struct arpt_error)),	       \
+	.target		= XT_TARGET_INIT(ARPT_ERROR_TARGET,		       \
+					 sizeof(struct arpt_error_target)),    \
+	.target.errorname = "ERROR",					       \
+}
+
 #define arpt_register_target(tgt) 	\
 ({	(tgt)->family = NF_ARP;		\
  	xt_register_target(tgt); })
diff --git a/include/linux/netfilter_ipv4/ip_tables.h b/include/linux/netfilter_ipv4/ip_tables.h
index 9527296..2f46dd7 100644
--- a/include/linux/netfilter_ipv4/ip_tables.h
+++ b/include/linux/netfilter_ipv4/ip_tables.h
@@ -295,6 +295,28 @@
 	struct ipt_error_target target;
 };
 
+#define IPT_ENTRY_INIT(__size)						       \
+{									       \
+	.target_offset	= sizeof(struct ipt_entry),			       \
+	.next_offset	= (__size),					       \
+}
+
+#define IPT_STANDARD_INIT(__verdict)					       \
+{									       \
+	.entry		= IPT_ENTRY_INIT(sizeof(struct ipt_standard)),	       \
+	.target		= XT_TARGET_INIT(IPT_STANDARD_TARGET,		       \
+					 sizeof(struct xt_standard_target)),   \
+	.target.verdict	= -(__verdict) - 1,				       \
+}
+
+#define IPT_ERROR_INIT							       \
+{									       \
+	.entry		= IPT_ENTRY_INIT(sizeof(struct ipt_error)),	       \
+	.target		= XT_TARGET_INIT(IPT_ERROR_TARGET,		       \
+					 sizeof(struct ipt_error_target)),     \
+	.target.errorname = "ERROR",					       \
+}
+
 extern unsigned int ipt_do_table(struct sk_buff **pskb,
 				 unsigned int hook,
 				 const struct net_device *in,
diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h
index 61aa104..4686f83 100644
--- a/include/linux/netfilter_ipv6/ip6_tables.h
+++ b/include/linux/netfilter_ipv6/ip6_tables.h
@@ -123,6 +123,28 @@
 	struct ip6t_error_target target;
 };
 
+#define IP6T_ENTRY_INIT(__size)						       \
+{									       \
+	.target_offset	= sizeof(struct ip6t_entry),			       \
+	.next_offset	= (__size),					       \
+}
+
+#define IP6T_STANDARD_INIT(__verdict)					       \
+{									       \
+	.entry		= IP6T_ENTRY_INIT(sizeof(struct ip6t_standard)),       \
+	.target		= XT_TARGET_INIT(IP6T_STANDARD_TARGET,		       \
+					 sizeof(struct ip6t_standard_target)), \
+	.target.verdict	= -(__verdict) - 1,				       \
+}
+
+#define IP6T_ERROR_INIT							       \
+{									       \
+	.entry		= IP6T_ENTRY_INIT(sizeof(struct ip6t_error)),	       \
+	.target		= XT_TARGET_INIT(IP6T_ERROR_TARGET,		       \
+					 sizeof(struct ip6t_error_target)),    \
+	.target.errorname = "ERROR",					       \
+}
+
 /*
  * New IP firewall options for [gs]etsockopt at the RAW IP level.
  * Unlike BSD Linux inherits IP options so you don't have to use
diff --git a/include/linux/pid.h b/include/linux/pid.h
index 2ac27f9..1e0e4e3 100644
--- a/include/linux/pid.h
+++ b/include/linux/pid.h
@@ -51,6 +51,8 @@
 	struct rcu_head rcu;
 };
 
+extern struct pid init_struct_pid;
+
 struct pid_link
 {
 	struct hlist_node node;
@@ -76,8 +78,7 @@
  * write-held.
  */
 extern int FASTCALL(attach_pid(struct task_struct *task,
-				enum pid_type type, int nr));
-
+				enum pid_type type, struct pid *pid));
 extern void FASTCALL(detach_pid(struct task_struct *task, enum pid_type));
 extern void FASTCALL(transfer_pid(struct task_struct *old,
 				  struct task_struct *new, enum pid_type));
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 17b72d8..a81897e 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -88,6 +88,7 @@
 
 struct exec_domain;
 struct futex_pi_state;
+struct bio;
 
 /*
  * List of flags we want to share for kernel threads,
@@ -391,6 +392,7 @@
 	atomic_t		count;
 	struct k_sigaction	action[_NSIG];
 	spinlock_t		siglock;
+	struct list_head        signalfd_list;
 };
 
 struct pacct_struct {
@@ -469,6 +471,7 @@
 	cputime_t utime, stime, cutime, cstime;
 	unsigned long nvcsw, nivcsw, cnvcsw, cnivcsw;
 	unsigned long min_flt, maj_flt, cmin_flt, cmaj_flt;
+	unsigned long inblock, oublock, cinblock, coublock;
 
 	/*
 	 * Cumulative ns of scheduled CPU time for dead threads in the
@@ -1014,6 +1017,9 @@
 /* journalling filesystem info */
 	void *journal_info;
 
+/* stacked block device info */
+	struct bio *bio_list, **bio_tail;
+
 /* VM state */
 	struct reclaim_state *reclaim_state;
 
diff --git a/include/linux/signal.h b/include/linux/signal.h
index 3fa0fab..9a5eac5 100644
--- a/include/linux/signal.h
+++ b/include/linux/signal.h
@@ -233,6 +233,7 @@
 	return sig <= _NSIG ? 1 : 0;
 }
 
+extern int next_signal(struct sigpending *pending, sigset_t *mask);
 extern int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p);
 extern int __group_send_sig_info(int, struct siginfo *, struct task_struct *);
 extern long do_sigpending(void __user *, unsigned long);
diff --git a/include/linux/signalfd.h b/include/linux/signalfd.h
new file mode 100644
index 0000000..5104294
--- /dev/null
+++ b/include/linux/signalfd.h
@@ -0,0 +1,97 @@
+/*
+ *  include/linux/signalfd.h
+ *
+ *  Copyright (C) 2007  Davide Libenzi <davidel@xmailserver.org>
+ *
+ */
+
+#ifndef _LINUX_SIGNALFD_H
+#define _LINUX_SIGNALFD_H
+
+
+struct signalfd_siginfo {
+	__u32 signo;
+	__s32 err;
+	__s32 code;
+	__u32 pid;
+	__u32 uid;
+	__s32 fd;
+	__u32 tid;
+	__u32 band;
+	__u32 overrun;
+	__u32 trapno;
+	__s32 status;
+	__s32 svint;
+	__u64 svptr;
+	__u64 utime;
+	__u64 stime;
+	__u64 addr;
+
+	/*
+	 * Pad strcture to 128 bytes. Remember to update the
+	 * pad size when you add new memebers. We use a fixed
+	 * size structure to avoid compatibility problems with
+	 * future versions, and we leave extra space for additional
+	 * members. We use fixed size members because this strcture
+	 * comes out of a read(2) and we really don't want to have
+	 * a compat on read(2).
+	 */
+	__u8 __pad[48];
+};
+
+
+#ifdef __KERNEL__
+
+#ifdef CONFIG_SIGNALFD
+
+/*
+ * Deliver the signal to listening signalfd. This must be called
+ * with the sighand lock held. Same are the following that end up
+ * calling signalfd_deliver().
+ */
+void signalfd_deliver(struct task_struct *tsk, int sig);
+
+/*
+ * No need to fall inside signalfd_deliver() if no signal listeners
+ * are available.
+ */
+static inline void signalfd_notify(struct task_struct *tsk, int sig)
+{
+	if (unlikely(!list_empty(&tsk->sighand->signalfd_list)))
+		signalfd_deliver(tsk, sig);
+}
+
+/*
+ * The signal -1 is used to notify the signalfd that the sighand
+ * is on its way to be detached.
+ */
+static inline void signalfd_detach_locked(struct task_struct *tsk)
+{
+	if (unlikely(!list_empty(&tsk->sighand->signalfd_list)))
+		signalfd_deliver(tsk, -1);
+}
+
+static inline void signalfd_detach(struct task_struct *tsk)
+{
+	struct sighand_struct *sighand = tsk->sighand;
+
+	if (unlikely(!list_empty(&sighand->signalfd_list))) {
+		spin_lock_irq(&sighand->siglock);
+		signalfd_deliver(tsk, -1);
+		spin_unlock_irq(&sighand->siglock);
+	}
+}
+
+#else /* CONFIG_SIGNALFD */
+
+#define signalfd_deliver(t, s) do { } while (0)
+#define signalfd_notify(t, s) do { } while (0)
+#define signalfd_detach_locked(t) do { } while (0)
+#define signalfd_detach(t) do { } while (0)
+
+#endif /* CONFIG_SIGNALFD */
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_SIGNALFD_H */
+
diff --git a/include/linux/synclink.h b/include/linux/synclink.h
index c8b0426..5562fbf 100644
--- a/include/linux/synclink.h
+++ b/include/linux/synclink.h
@@ -291,4 +291,28 @@
 #define MGSL_IOCGGPIO		_IOR(MGSL_MAGIC_IOC,17,struct gpio_desc)
 #define MGSL_IOCWAITGPIO	_IOWR(MGSL_MAGIC_IOC,18,struct gpio_desc)
 
+#ifdef __KERNEL__
+/* provide 32 bit ioctl compatibility on 64 bit systems */
+#ifdef CONFIG_COMPAT
+#include <linux/compat.h>
+struct MGSL_PARAMS32 {
+	compat_ulong_t	mode;
+	unsigned char	loopback;
+	unsigned short	flags;
+	unsigned char	encoding;
+	compat_ulong_t	clock_speed;
+	unsigned char	addr_filter;
+	unsigned short	crc_type;
+	unsigned char	preamble_length;
+	unsigned char	preamble;
+	compat_ulong_t	data_rate;
+	unsigned char	data_bits;
+	unsigned char	stop_bits;
+	unsigned char	parity;
+};
+#define MGSL_IOCSPARAMS32 _IOW(MGSL_MAGIC_IOC,0,struct MGSL_PARAMS32)
+#define MGSL_IOCGPARAMS32 _IOR(MGSL_MAGIC_IOC,1,struct MGSL_PARAMS32)
+#endif
+#endif
+
 #endif /* _SYNCLINK_H_ */
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 3139f44..b02070e 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -604,6 +604,10 @@
 asmlinkage long sys_set_robust_list(struct robust_list_head __user *head,
 				    size_t len);
 asmlinkage long sys_getcpu(unsigned __user *cpu, unsigned __user *node, struct getcpu_cache __user *cache);
+asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemask);
+asmlinkage long sys_timerfd(int ufd, int clockid, int flags,
+			    const struct itimerspec __user *utmr);
+asmlinkage long sys_eventfd(unsigned int count);
 
 int kernel_execve(const char *filename, char *const argv[], char *const envp[]);
 
diff --git a/include/linux/task_io_accounting_ops.h b/include/linux/task_io_accounting_ops.h
index df2a319..1218733 100644
--- a/include/linux/task_io_accounting_ops.h
+++ b/include/linux/task_io_accounting_ops.h
@@ -10,11 +10,29 @@
 	current->ioac.read_bytes += bytes;
 }
 
+/*
+ * We approximate number of blocks, because we account bytes only.
+ * A 'block' is 512 bytes
+ */
+static inline unsigned long task_io_get_inblock(const struct task_struct *p)
+{
+	return p->ioac.read_bytes >> 9;
+}
+
 static inline void task_io_account_write(size_t bytes)
 {
 	current->ioac.write_bytes += bytes;
 }
 
+/*
+ * We approximate number of blocks, because we account bytes only.
+ * A 'block' is 512 bytes
+ */
+static inline unsigned long task_io_get_oublock(const struct task_struct *p)
+{
+	return p->ioac.write_bytes >> 9;
+}
+
 static inline void task_io_account_cancelled_write(size_t bytes)
 {
 	current->ioac.cancelled_write_bytes += bytes;
@@ -31,10 +49,20 @@
 {
 }
 
+static inline unsigned long task_io_get_inblock(const struct task_struct *p)
+{
+	return 0;
+}
+
 static inline void task_io_account_write(size_t bytes)
 {
 }
 
+static inline unsigned long task_io_get_oublock(const struct task_struct *p)
+{
+	return 0;
+}
+
 static inline void task_io_account_cancelled_write(size_t bytes)
 {
 }
diff --git a/include/linux/timerfd.h b/include/linux/timerfd.h
new file mode 100644
index 0000000..cf2b10d
--- /dev/null
+++ b/include/linux/timerfd.h
@@ -0,0 +1,17 @@
+/*
+ *  include/linux/timerfd.h
+ *
+ *  Copyright (C) 2007  Davide Libenzi <davidel@xmailserver.org>
+ *
+ */
+
+#ifndef _LINUX_TIMERFD_H
+#define _LINUX_TIMERFD_H
+
+
+#define TFD_TIMER_ABSTIME (1 << 0)
+
+
+
+#endif /* _LINUX_TIMERFD_H */
+
diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h
index 659487e..85c95cd 100644
--- a/include/linux/tty_driver.h
+++ b/include/linux/tty_driver.h
@@ -52,6 +52,11 @@
  * 	This routine allows the tty driver to implement
  *	device-specific ioctl's.  If the ioctl number passed in cmd
  * 	is not recognized by the driver, it should return ENOIOCTLCMD.
+ *
+ * long (*compat_ioctl)(struct tty_struct *tty, struct file * file,
+ * 	                unsigned int cmd, unsigned long arg);
+ *
+ * 	implement ioctl processing for 32 bit process on 64 bit system
  * 
  * void (*set_termios)(struct tty_struct *tty, struct ktermios * old);
  *
@@ -132,6 +137,8 @@
 	int  (*chars_in_buffer)(struct tty_struct *tty);
 	int  (*ioctl)(struct tty_struct *tty, struct file * file,
 		    unsigned int cmd, unsigned long arg);
+	long (*compat_ioctl)(struct tty_struct *tty, struct file * file,
+			     unsigned int cmd, unsigned long arg);
 	void (*set_termios)(struct tty_struct *tty, struct ktermios * old);
 	void (*throttle)(struct tty_struct * tty);
 	void (*unthrottle)(struct tty_struct * tty);
@@ -193,6 +200,8 @@
 	int  (*chars_in_buffer)(struct tty_struct *tty);
 	int  (*ioctl)(struct tty_struct *tty, struct file * file,
 		    unsigned int cmd, unsigned long arg);
+	long (*compat_ioctl)(struct tty_struct *tty, struct file * file,
+			     unsigned int cmd, unsigned long arg);
 	void (*set_termios)(struct tty_struct *tty, struct ktermios * old);
 	void (*throttle)(struct tty_struct * tty);
 	void (*unthrottle)(struct tty_struct * tty);
diff --git a/include/linux/tty_ldisc.h b/include/linux/tty_ldisc.h
index d75932e..6226504 100644
--- a/include/linux/tty_ldisc.h
+++ b/include/linux/tty_ldisc.h
@@ -59,6 +59,11 @@
  * 	low-level driver can "grab" an ioctl request before the line
  * 	discpline has a chance to see it.
  * 
+ * long	(*compat_ioctl)(struct tty_struct * tty, struct file * file,
+ * 		        unsigned int cmd, unsigned long arg);
+ *
+ *      Process ioctl calls from 32-bit process on 64-bit system
+ *
  * void	(*set_termios)(struct tty_struct *tty, struct ktermios * old);
  *
  * 	This function notifies the line discpline that a change has
@@ -118,6 +123,8 @@
 			 const unsigned char * buf, size_t nr);	
 	int	(*ioctl)(struct tty_struct * tty, struct file * file,
 			 unsigned int cmd, unsigned long arg);
+	long	(*compat_ioctl)(struct tty_struct * tty, struct file * file,
+				unsigned int cmd, unsigned long arg);
 	void	(*set_termios)(struct tty_struct *tty, struct ktermios * old);
 	unsigned int (*poll)(struct tty_struct *, struct file *,
 			     struct poll_table_struct *);
diff --git a/include/linux/writeback.h b/include/linux/writeback.h
index daa6c12..050915b 100644
--- a/include/linux/writeback.h
+++ b/include/linux/writeback.h
@@ -111,9 +111,15 @@
 	balance_dirty_pages_ratelimited_nr(mapping, 1);
 }
 
+typedef int (*writepage_t)(struct page *page, struct writeback_control *wbc,
+				void *data);
+
 int pdflush_operation(void (*fn)(unsigned long), unsigned long arg0);
-extern int generic_writepages(struct address_space *mapping,
-			      struct writeback_control *wbc);
+int generic_writepages(struct address_space *mapping,
+		       struct writeback_control *wbc);
+int write_cache_pages(struct address_space *mapping,
+		      struct writeback_control *wbc, writepage_t writepage,
+		      void *data);
 int do_writepages(struct address_space *mapping, struct writeback_control *wbc);
 int sync_page_range(struct inode *inode, struct address_space *mapping,
 			loff_t pos, loff_t count);
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
index 1c6b8bd..4732432 100644
--- a/include/net/netfilter/nf_conntrack.h
+++ b/include/net/netfilter/nf_conntrack.h
@@ -183,13 +183,6 @@
 
 extern void nf_conntrack_flush(void);
 
-extern struct nf_conntrack_helper *
-nf_ct_helper_find_get( const struct nf_conntrack_tuple *tuple);
-extern void nf_ct_helper_put(struct nf_conntrack_helper *helper);
-
-extern struct nf_conntrack_helper *
-__nf_conntrack_helper_find_byname(const char *name);
-
 extern int nf_ct_invert_tuplepr(struct nf_conntrack_tuple *inverse,
 				const struct nf_conntrack_tuple *orig);
 
diff --git a/include/net/netfilter/nf_conntrack_l3proto.h b/include/net/netfilter/nf_conntrack_l3proto.h
index f32f714..96a58d8 100644
--- a/include/net/netfilter/nf_conntrack_l3proto.h
+++ b/include/net/netfilter/nf_conntrack_l3proto.h
@@ -56,9 +56,6 @@
 	 */
 	int (*new)(struct nf_conn *conntrack, const struct sk_buff *skb);
 
-	/* Called when a conntrack entry is destroyed */
-	void (*destroy)(struct nf_conn *conntrack);
-
 	/*
 	 * Called before tracking. 
 	 *	*dataoff: offset of protocol header (TCP, UDP,...) in *pskb
diff --git a/include/net/netfilter/nf_nat_rule.h b/include/net/netfilter/nf_nat_rule.h
index e765654..f974318 100644
--- a/include/net/netfilter/nf_nat_rule.h
+++ b/include/net/netfilter/nf_nat_rule.h
@@ -10,16 +10,11 @@
 			    unsigned int hooknum,
 			    const struct net_device *in,
 			    const struct net_device *out,
-			    struct nf_conn *ct,
-			    struct nf_nat_info *info);
+			    struct nf_conn *ct);
 
 extern unsigned int
-alloc_null_binding(struct nf_conn *ct,
-		   struct nf_nat_info *info,
-		   unsigned int hooknum);
+alloc_null_binding(struct nf_conn *ct, unsigned int hooknum);
 
 extern unsigned int
-alloc_null_binding_confirmed(struct nf_conn *ct,
-			     struct nf_nat_info *info,
-			     unsigned int hooknum);
+alloc_null_binding_confirmed(struct nf_conn *ct, unsigned int hooknum);
 #endif /* _NF_NAT_RULE_H */
diff --git a/include/net/udp.h b/include/net/udp.h
index 98755eb..496f89d 100644
--- a/include/net/udp.h
+++ b/include/net/udp.h
@@ -119,9 +119,16 @@
 }
 
 
+struct udp_get_port_ops {
+	int (*saddr_cmp)(const struct sock *sk1, const struct sock *sk2);
+	int (*saddr_any)(const struct sock *sk);
+	unsigned int (*hash_port_and_rcv_saddr)(__u16 port,
+						const struct sock *sk);
+};
+
 /* net/ipv4/udp.c */
 extern int	udp_get_port(struct sock *sk, unsigned short snum,
-			     int (*saddr_cmp)(const struct sock *, const struct sock *));
+			     const struct udp_get_port_ops *ops);
 extern void	udp_err(struct sk_buff *, u32);
 
 extern int	udp_sendmsg(struct kiocb *iocb, struct sock *sk,
diff --git a/include/net/udplite.h b/include/net/udplite.h
index 635b0ea..50b4b42 100644
--- a/include/net/udplite.h
+++ b/include/net/udplite.h
@@ -120,5 +120,5 @@
 
 extern void	udplite4_register(void);
 extern int 	udplite_get_port(struct sock *sk, unsigned short snum,
-			int (*scmp)(const struct sock *, const struct sock *));
+				 const struct udp_get_port_ops *ops);
 #endif	/* _UDPLITE_H */
diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h
new file mode 100644
index 0000000..4eea637
--- /dev/null
+++ b/include/video/atmel_lcdc.h
@@ -0,0 +1,196 @@
+/*
+ *  Header file for AT91/AT32 LCD Controller
+ *
+ *  Data structure and register user interface
+ *
+ *  Copyright (C) 2007 Atmel Corporation
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef __ATMEL_LCDC_H__
+#define __ATMEL_LCDC_H__
+
+ /* LCD Controller info data structure */
+struct atmel_lcdfb_info {
+	spinlock_t		lock;
+	struct fb_info		*info;
+	void __iomem		*mmio;
+	unsigned long		irq_base;
+
+	unsigned int		guard_time;
+	struct platform_device	*pdev;
+	struct clk		*bus_clk;
+	struct clk		*lcdc_clk;
+	unsigned int		default_bpp;
+	unsigned int		default_lcdcon2;
+	unsigned int		default_dmacon;
+	void (*atmel_lcdfb_power_control)(int on);
+	struct fb_monspecs	*default_monspecs;
+	u32			pseudo_palette[16];
+};
+
+#define ATMEL_LCDC_DMABADDR1	0x00
+#define ATMEL_LCDC_DMABADDR2	0x04
+#define ATMEL_LCDC_DMAFRMPT1	0x08
+#define ATMEL_LCDC_DMAFRMPT2	0x0c
+#define ATMEL_LCDC_DMAFRMADD1	0x10
+#define ATMEL_LCDC_DMAFRMADD2	0x14
+
+#define ATMEL_LCDC_DMAFRMCFG	0x18
+#define	ATMEL_LCDC_FRSIZE	(0x7fffff <<  0)
+#define	ATMEL_LCDC_BLENGTH_OFFSET	24
+#define	ATMEL_LCDC_BLENGTH	(0x7f     << ATMEL_LCDC_BLENGTH_OFFSET)
+
+#define ATMEL_LCDC_DMACON	0x1c
+#define	ATMEL_LCDC_DMAEN	(0x1 << 0)
+#define	ATMEL_LCDC_DMARST	(0x1 << 1)
+#define	ATMEL_LCDC_DMABUSY	(0x1 << 2)
+#define		ATMEL_LCDC_DMAUPDT	(0x1 << 3)
+#define		ATMEL_LCDC_DMA2DEN	(0x1 << 4)
+
+#define ATMEL_LCDC_DMA2DCFG	0x20
+#define		ATMEL_LCDC_ADDRINC_OFFSET	0
+#define		ATMEL_LCDC_ADDRINC		(0xffff)
+#define		ATMEL_LCDC_PIXELOFF_OFFSET	24
+#define		ATMEL_LCDC_PIXELOFF		(0x1f << 24)
+
+#define ATMEL_LCDC_LCDCON1	0x0800
+#define	ATMEL_LCDC_BYPASS	(1     <<  0)
+#define	ATMEL_LCDC_CLKVAL_OFFSET	12
+#define	ATMEL_LCDC_CLKVAL	(0x1ff << ATMEL_LCDC_CLKVAL_OFFSET)
+#define	ATMEL_LCDC_LINCNT	(0x7ff << 21)
+
+#define ATMEL_LCDC_LCDCON2	0x0804
+#define	ATMEL_LCDC_DISTYPE	(3 << 0)
+#define		ATMEL_LCDC_DISTYPE_STNMONO	(0 << 0)
+#define		ATMEL_LCDC_DISTYPE_STNCOLOR	(1 << 0)
+#define		ATMEL_LCDC_DISTYPE_TFT		(2 << 0)
+#define	ATMEL_LCDC_SCANMOD	(1 << 2)
+#define		ATMEL_LCDC_SCANMOD_SINGLE	(0 << 2)
+#define		ATMEL_LCDC_SCANMOD_DUAL		(1 << 2)
+#define	ATMEL_LCDC_IFWIDTH	(3 << 3)
+#define		ATMEL_LCDC_IFWIDTH_4		(0 << 3)
+#define		ATMEL_LCDC_IFWIDTH_8		(1 << 3)
+#define		ATMEL_LCDC_IFWIDTH_16		(2 << 3)
+#define	ATMEL_LCDC_PIXELSIZE	(7 << 5)
+#define		ATMEL_LCDC_PIXELSIZE_1		(0 << 5)
+#define		ATMEL_LCDC_PIXELSIZE_2		(1 << 5)
+#define		ATMEL_LCDC_PIXELSIZE_4		(2 << 5)
+#define		ATMEL_LCDC_PIXELSIZE_8		(3 << 5)
+#define		ATMEL_LCDC_PIXELSIZE_16		(4 << 5)
+#define		ATMEL_LCDC_PIXELSIZE_24		(5 << 5)
+#define		ATMEL_LCDC_PIXELSIZE_32		(6 << 5)
+#define	ATMEL_LCDC_INVVD	(1 << 8)
+#define		ATMEL_LCDC_INVVD_NORMAL		(0 << 8)
+#define		ATMEL_LCDC_INVVD_INVERTED	(1 << 8)
+#define	ATMEL_LCDC_INVFRAME	(1 << 9 )
+#define		ATMEL_LCDC_INVFRAME_NORMAL	(0 << 9)
+#define		ATMEL_LCDC_INVFRAME_INVERTED	(1 << 9)
+#define	ATMEL_LCDC_INVLINE	(1 << 10)
+#define		ATMEL_LCDC_INVLINE_NORMAL	(0 << 10)
+#define		ATMEL_LCDC_INVLINE_INVERTED	(1 << 10)
+#define	ATMEL_LCDC_INVCLK	(1 << 11)
+#define		ATMEL_LCDC_INVCLK_NORMAL	(0 << 11)
+#define		ATMEL_LCDC_INVCLK_INVERTED	(1 << 11)
+#define	ATMEL_LCDC_INVDVAL	(1 << 12)
+#define		ATMEL_LCDC_INVDVAL_NORMAL	(0 << 12)
+#define		ATMEL_LCDC_INVDVAL_INVERTED	(1 << 12)
+#define	ATMEL_LCDC_CLKMOD	(1 << 15)
+#define		ATMEL_LCDC_CLKMOD_ACTIVEDISPLAY	(0 << 15)
+#define		ATMEL_LCDC_CLKMOD_ALWAYSACTIVE	(1 << 15)
+#define	ATMEL_LCDC_MEMOR	(1 << 31)
+#define		ATMEL_LCDC_MEMOR_BIG		(0 << 31)
+#define		ATMEL_LCDC_MEMOR_LITTLE		(1 << 31)
+
+#define ATMEL_LCDC_TIM1		0x0808
+#define	ATMEL_LCDC_VFP		(0xff <<  0)
+#define	ATMEL_LCDC_VBP_OFFSET		8
+#define	ATMEL_LCDC_VBP		(0xff <<  ATMEL_LCDC_VBP_OFFSET)
+#define	ATMEL_LCDC_VPW_OFFSET		16
+#define	ATMEL_LCDC_VPW		(0x3f << ATMEL_LCDC_VPW_OFFSET)
+#define	ATMEL_LCDC_VHDLY_OFFSET		24
+#define	ATMEL_LCDC_VHDLY	(0xf  << ATMEL_LCDC_VHDLY_OFFSET)
+
+#define ATMEL_LCDC_TIM2		0x080c
+#define	ATMEL_LCDC_HBP		(0xff  <<  0)
+#define	ATMEL_LCDC_HPW_OFFSET		8
+#define	ATMEL_LCDC_HPW		(0x3f  <<  ATMEL_LCDC_HPW_OFFSET)
+#define	ATMEL_LCDC_HFP_OFFSET		21
+#define	ATMEL_LCDC_HFP		(0x7ff << ATMEL_LCDC_HFP_OFFSET)
+
+#define ATMEL_LCDC_LCDFRMCFG	0x0810
+#define	ATMEL_LCDC_LINEVAL	(0x7ff <<  0)
+#define	ATMEL_LCDC_HOZVAL_OFFSET	21
+#define	ATMEL_LCDC_HOZVAL	(0x7ff << ATMEL_LCDC_HOZVAL_OFFSET)
+
+#define ATMEL_LCDC_FIFO		0x0814
+#define	ATMEL_LCDC_FIFOTH	(0xffff)
+
+#define ATMEL_LCDC_MVAL		0x0818
+
+#define ATMEL_LCDC_DP1_2	0x081c
+#define ATMEL_LCDC_DP4_7	0x0820
+#define ATMEL_LCDC_DP3_5	0x0824
+#define ATMEL_LCDC_DP2_3	0x0828
+#define ATMEL_LCDC_DP5_7	0x082c
+#define ATMEL_LCDC_DP3_4	0x0830
+#define ATMEL_LCDC_DP4_5	0x0834
+#define ATMEL_LCDC_DP6_7	0x0838
+#define	ATMEL_LCDC_DP1_2_VAL	(0xff)
+#define	ATMEL_LCDC_DP4_7_VAL	(0xfffffff)
+#define	ATMEL_LCDC_DP3_5_VAL	(0xfffff)
+#define	ATMEL_LCDC_DP2_3_VAL	(0xfff)
+#define	ATMEL_LCDC_DP5_7_VAL	(0xfffffff)
+#define	ATMEL_LCDC_DP3_4_VAL	(0xffff)
+#define	ATMEL_LCDC_DP4_5_VAL	(0xfffff)
+#define	ATMEL_LCDC_DP6_7_VAL	(0xfffffff)
+
+#define ATMEL_LCDC_PWRCON	0x083c
+#define	ATMEL_LCDC_PWR		(1    <<  0)
+#define	ATMEL_LCDC_GUARDT_OFFSET	1
+#define	ATMEL_LCDC_GUARDT	(0x7f <<  ATMEL_LCDC_GUARDT_OFFSET)
+#define	ATMEL_LCDC_BUSY		(1    << 31)
+
+#define ATMEL_LCDC_CONTRAST_CTR	0x0840
+#define	ATMEL_LCDC_PS		(3 << 0)
+#define		ATMEL_LCDC_PS_DIV1		(0 << 0)
+#define		ATMEL_LCDC_PS_DIV2		(1 << 0)
+#define		ATMEL_LCDC_PS_DIV4		(2 << 0)
+#define		ATMEL_LCDC_PS_DIV8		(3 << 0)
+#define	ATMEL_LCDC_POL		(1 << 2)
+#define		ATMEL_LCDC_POL_NEGATIVE		(0 << 2)
+#define		ATMEL_LCDC_POL_POSITIVE		(1 << 2)
+#define	ATMEL_LCDC_ENA		(1 << 3)
+#define		ATMEL_LCDC_ENA_PWMDISABLE	(0 << 3)
+#define		ATMEL_LCDC_ENA_PWMENABLE	(1 << 3)
+
+#define ATMEL_LCDC_CONTRAST_VAL	0x0844
+#define	ATMEL_LCDC_CVAL	(0xff)
+
+#define ATMEL_LCDC_IER		0x0848
+#define ATMEL_LCDC_IDR		0x084c
+#define ATMEL_LCDC_IMR		0x0850
+#define ATMEL_LCDC_ISR		0x0854
+#define ATMEL_LCDC_ICR		0x0858
+#define	ATMEL_LCDC_LNI		(1 << 0)
+#define	ATMEL_LCDC_LSTLNI	(1 << 1)
+#define	ATMEL_LCDC_EOFI		(1 << 2)
+#define	ATMEL_LCDC_UFLWI	(1 << 4)
+#define	ATMEL_LCDC_OWRI		(1 << 5)
+#define	ATMEL_LCDC_MERI		(1 << 6)
+
+#define ATMEL_LCDC_LUT(n)	(0x0c00 + ((n)*4))
+
+#endif /* __ATMEL_LCDC_H__ */
diff --git a/include/video/pm3fb.h b/include/video/pm3fb.h
index 94c7d2d..d52e45a 100644
--- a/include/video/pm3fb.h
+++ b/include/video/pm3fb.h
@@ -7,9 +7,6 @@
  *  This file is subject to the terms and conditions of the GNU General Public
  *  License. See the file COPYING in the main directory of this archive for
  *  more details.
- *
- *  $Header: /cvsroot/linux/drivers/video/pm3fb.h,v 1.1 2002/02/25 19:11:06 marcelo Exp $
- *
  */
 
 #ifndef PM3FB_H
@@ -1119,117 +1116,10 @@
 /* ***** pm3fb useful define and macro ***** */
 /* ***************************************** */
 
-/* permedia3 -specific definitions */
-#define PM3_SCALE_TO_CLOCK(pr, fe, po) ((2 * PM3_REF_CLOCK * fe) / (pr * (1 << (po))))
-
-/* in case it's not in linux/pci.h */
-#ifndef PCI_DEVICE_ID_3DLABS_PERMEDIA3
-#define PCI_DEVICE_ID_3DLABS_PERMEDIA3 0x000a
-#endif
-
-/* max number of simultaneous board */
-#define PM3_MAX_BOARD 4
-
 /* max size of options */
 #define PM3_OPTIONS_SIZE 256
 
 /* max size of font name */
 #define PM3_FONTNAME_SIZE 40
 
-/* do we want accelerated console  */
-#define PM3FB_USE_ACCEL 1
-
-/* for driver debugging ONLY */
-/* 0 = assert only, 1 = error, 2 = info, 3+ = verbose */
-/* define PM3FB_MASTER_DEBUG 1 */
-#if defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 3)
-#define PM3FB_TRACE
-#endif /* defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 3) */
-
-#ifdef PM3FB_MASTER_DEBUG
-#define DPRINTK(l,a,b...) do { if ((l) <= PM3FB_MASTER_DEBUG) printk("pm3fb: %s: " a, __FUNCTION__ , ## b); } while (0)
-#define DASSERT(t,a,b...) do { if (!(t)) printk("pm3fb: _assert failed: %s: " a, __FUNCTION__ , ## b); } while (0)
-#ifdef PM3FB_TRACE
-#define DTRACE printk("pm3fb: _enter %s\n", __FUNCTION__)
-#else /* PM3FB_TRACE */
-#define DTRACE
-#endif /* PM3FB_TRACE */
-#else /* PM3FB_MASTER_DEBUG */
-#define DPRINTK(l,a,b...)
-#define DASSERT(t,a,b...)
-#define DTRACE
-#endif /* PM3FB_MASTER_DEBUG */
-
-#if defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 2)
-#define PM3_SHOW_CUR_MODE pm3fb_show_cur_mode(l_fb_info)
-#else
-#define PM3_SHOW_CUR_MODE /* pm3fb_show_cur_mode() */
-#endif
-
-/* ******************************************** */
-/* ***** A bunch of register-access macro ***** */
-/* ******************************************** */
-
-#define PM3_WRITE_REG(r, v) fb_writel(v, (l_fb_info->vIOBase + r))
-#define PM3_READ_REG(r) fb_readl((l_fb_info->vIOBase + r))
-
-
-#define depth2bpp(d) ((d + 7L) & ~7L)
-#define depth2ByPP(d) (depth2bpp(d) / 8)
-
-#define depth_supported(d) ((d == 8) || (d == 12) || (d == 15) || (d == 16) || (d==32))
-
-
-#define PM3_WAIT(n) \
-do{ \
-	while(PM3_READ_REG(PM3InFIFOSpace)<(n)); \
-} while(0)
-
-#define PM3_DELAY(x) do { \
-        int delay = x; \
-        unsigned char tmp; \
-        while(delay--){tmp = PM3_READ_REG(PM3InFIFOSpace);}; \
-} while(0)
-
-#define PM3_SLOW_WRITE_REG(r,v)	\
-do{                             \
-    DASSERT((l_fb_info->vIOBase != (unsigned char*)(-1)), "l_fb_info->vIOBase mapped in slow write\n"); \
-	mb();                   \
-	PM3_WAIT(1);            \
-	mb();                   \
-    PM3_WRITE_REG(r,v);     \
-} while(0)
-
-#define PM3_SET_INDEX(index) \
-do{ \
-	PM3_SLOW_WRITE_REG(PM3RD_IndexHigh,(((index)>>8)&0xff)); \
-	PM3_SLOW_WRITE_REG(PM3RD_IndexLow,((index)&0xff)); \
-} while(0)
-
-#define PM3_WRITE_DAC_REG(r, v) \
-do { \
-     DASSERT((l_fb_info->vIOBase != (unsigned char*)(-1)), "l_fb_info->vIOBase mapped in write dac reg\n"); \
-     PM3_SET_INDEX(r); \
-     mb(); \
-     PM3_WRITE_REG(PM3RD_IndexedData, v); \
-} while (0)
-
-/* next one is really a function, added as a macro to be consistent */
-#define PM3_READ_DAC_REG(r) pm3fb_read_dac_reg(l_fb_info, r)
-
-
-#define PM3_COLOR(c) \
-do { \
-  if (l_fb_info->current_par->depth == 8) \
-    { \
-      c = (c & 0xFF); \
-      c = c | (c << 8); \
-    } \
-  if ((l_fb_info->current_par->depth == 8) || (depth2bpp(l_fb_info->current_par->depth) == 16)) \
-    { \
-      c = (c & 0xFFFF); \
-      c = c | (c << 16); \
-    } \
-} while (0)
-
 #endif /* PM3FB_H */
diff --git a/init/Kconfig b/init/Kconfig
index 322b1f8..4e009fd 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -475,13 +475,53 @@
 	  support for "fast userspace mutexes".  The resulting kernel may not
 	  run glibc-based applications correctly.
 
+config ANON_INODES
+	bool "Enable anonymous inode source" if EMBEDDED
+	default y
+	help
+	  Anonymous inode source for pseudo-files like epoll, signalfd,
+	  timerfd and eventfd.
+
+	  If unsure, say Y.
+
 config EPOLL
 	bool "Enable eventpoll support" if EMBEDDED
 	default y
+	depends on ANON_INODES
 	help
 	  Disabling this option will cause the kernel to be built without
 	  support for epoll family of system calls.
 
+config SIGNALFD
+	bool "Enable signalfd() system call" if EMBEDDED
+	depends on ANON_INODES
+	default y
+	help
+	  Enable the signalfd() system call that allows to receive signals
+	  on a file descriptor.
+
+	  If unsure, say Y.
+
+config TIMERFD
+	bool "Enable timerfd() system call" if EMBEDDED
+	depends on ANON_INODES
+	default y
+	help
+	  Enable the timerfd() system call that allows to receive timer
+	  events on a file descriptor.
+
+	  If unsure, say Y.
+
+config EVENTFD
+	bool "Enable eventfd() system call" if EMBEDDED
+	depends on ANON_INODES
+	default y
+	help
+	  Enable the eventfd() system call that allows to receive both
+	  kernel notification (ie. KAIO) or userspace notifications.
+
+	  If unsure, say Y.
+
 config SHMEM
 	bool "Use full shmem filesystem" if EMBEDDED
 	default y
diff --git a/init/main.c b/init/main.c
index e8d080c..1940fa7 100644
--- a/init/main.c
+++ b/init/main.c
@@ -801,6 +801,7 @@
 	 */
 	init_pid_ns.child_reaper = current;
 
+	__set_special_pids(1, 1);
 	cad_pid = task_pid(current);
 
 	smp_prepare_cpus(max_cpus);
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index d17821d..fab5707 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -681,6 +681,7 @@
 
 	if (oflag & O_CREAT) {
 		if (dentry->d_inode) {	/* entry already exists */
+			audit_inode(name, dentry->d_inode);
 			error = -EEXIST;
 			if (oflag & O_EXCL)
 				goto out;
@@ -693,6 +694,7 @@
 		error = -ENOENT;
 		if (!dentry->d_inode)
 			goto out;
+		audit_inode(name, dentry->d_inode);
 		filp = do_open(dentry, oflag);
 	}
 
@@ -840,6 +842,7 @@
 	if (unlikely(filp->f_op != &mqueue_file_operations))
 		goto out_fput;
 	info = MQUEUE_I(inode);
+	audit_inode(NULL, inode);
 
 	if (unlikely(!(filp->f_mode & FMODE_WRITE)))
 		goto out_fput;
@@ -923,6 +926,7 @@
 	if (unlikely(filp->f_op != &mqueue_file_operations))
 		goto out_fput;
 	info = MQUEUE_I(inode);
+	audit_inode(NULL, inode);
 
 	if (unlikely(!(filp->f_mode & FMODE_READ)))
 		goto out_fput;
diff --git a/kernel/audit.h b/kernel/audit.h
index a337023..815d6f5 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -83,6 +83,7 @@
 	u32			field_count;
 	char			*filterkey; /* ties events to rules */
 	struct audit_field	*fields;
+	struct audit_field	*arch_f; /* quick access to arch field */
 	struct audit_field	*inode_f; /* quick access to an inode field */
 	struct audit_watch	*watch;	/* associated watch */
 	struct list_head	rlist;	/* entry in audit_watch.rules list */
@@ -131,17 +132,19 @@
 extern int selinux_audit_rule_update(void);
 
 #ifdef CONFIG_AUDITSYSCALL
-extern void __audit_signal_info(int sig, struct task_struct *t);
-static inline void audit_signal_info(int sig, struct task_struct *t)
+extern int __audit_signal_info(int sig, struct task_struct *t);
+static inline int audit_signal_info(int sig, struct task_struct *t)
 {
-	if (unlikely(audit_pid && t->tgid == audit_pid))
-		__audit_signal_info(sig, t);
+	if (unlikely((audit_pid && t->tgid == audit_pid) ||
+		     (audit_signals && !audit_dummy_context())))
+		return __audit_signal_info(sig, t);
+	return 0;
 }
 extern enum audit_state audit_filter_inodes(struct task_struct *,
 					    struct audit_context *);
 extern void audit_set_auditable(struct audit_context *);
 #else
-#define audit_signal_info(s,t)
+#define audit_signal_info(s,t) AUDIT_DISABLED
 #define audit_filter_inodes(t,c) AUDIT_DISABLED
 #define audit_set_auditable(c)
 #endif
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 3749193..6c61263 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -311,6 +311,43 @@
 	return classes[class][AUDIT_WORD(syscall)] & AUDIT_BIT(syscall);
 }
 
+static inline int audit_match_class_bits(int class, u32 *mask)
+{
+	int i;
+
+	if (classes[class]) {
+		for (i = 0; i < AUDIT_BITMASK_SIZE; i++)
+			if (mask[i] & classes[class][i])
+				return 0;
+	}
+	return 1;
+}
+
+static int audit_match_signal(struct audit_entry *entry)
+{
+	struct audit_field *arch = entry->rule.arch_f;
+
+	if (!arch) {
+		/* When arch is unspecified, we must check both masks on biarch
+		 * as syscall number alone is ambiguous. */
+		return (audit_match_class_bits(AUDIT_CLASS_SIGNAL,
+					       entry->rule.mask) &&
+			audit_match_class_bits(AUDIT_CLASS_SIGNAL_32,
+					       entry->rule.mask));
+	}
+
+	switch(audit_classify_arch(arch->val)) {
+	case 0: /* native */
+		return (audit_match_class_bits(AUDIT_CLASS_SIGNAL,
+					       entry->rule.mask));
+	case 1: /* 32bit on biarch */
+		return (audit_match_class_bits(AUDIT_CLASS_SIGNAL_32,
+					       entry->rule.mask));
+	default:
+		return 1;
+	}
+}
+
 /* Common user-space to kernel rule translation. */
 static inline struct audit_entry *audit_to_entry_common(struct audit_rule *rule)
 {
@@ -429,6 +466,7 @@
 				err = -EINVAL;
 				goto exit_free;
 			}
+			entry->rule.arch_f = f;
 			break;
 		case AUDIT_PERM:
 			if (f->val & ~15)
@@ -519,7 +557,6 @@
 		case AUDIT_FSGID:
 		case AUDIT_LOGINUID:
 		case AUDIT_PERS:
-		case AUDIT_ARCH:
 		case AUDIT_MSGTYPE:
 		case AUDIT_PPID:
 		case AUDIT_DEVMAJOR:
@@ -531,6 +568,9 @@
 		case AUDIT_ARG2:
 		case AUDIT_ARG3:
 			break;
+		case AUDIT_ARCH:
+			entry->rule.arch_f = f;
+			break;
 		case AUDIT_SUBJ_USER:
 		case AUDIT_SUBJ_ROLE:
 		case AUDIT_SUBJ_TYPE:
@@ -1221,6 +1261,9 @@
 #ifdef CONFIG_AUDITSYSCALL
 	if (!dont_count)
 		audit_n_rules++;
+
+	if (!audit_match_signal(entry))
+		audit_signals++;
 #endif
 	mutex_unlock(&audit_filter_mutex);
 
@@ -1294,6 +1337,9 @@
 #ifdef CONFIG_AUDITSYSCALL
 	if (!dont_count)
 		audit_n_rules--;
+
+	if (!audit_match_signal(entry))
+		audit_signals--;
 #endif
 	mutex_unlock(&audit_filter_mutex);
 
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 628c7ac..e36481e 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -78,17 +78,15 @@
  * for saving names from getname(). */
 #define AUDIT_NAMES    20
 
-/* AUDIT_NAMES_RESERVED is the number of slots we reserve in the
- * audit_context from being used for nameless inodes from
- * path_lookup. */
-#define AUDIT_NAMES_RESERVED 7
-
 /* Indicates that audit should log the full pathname. */
 #define AUDIT_NAME_FULL -1
 
 /* number of audit rules */
 int audit_n_rules;
 
+/* determines whether we collect data for signals sent */
+int audit_signals;
+
 /* When fs/namei.c:getname() is called, we store the pointer in name and
  * we don't let putname() free it (instead we free all of the saved
  * pointers at syscall exit time).
@@ -114,6 +112,9 @@
 
 #define AUDIT_AUX_IPCPERM	0
 
+/* Number of target pids per aux struct. */
+#define AUDIT_AUX_PIDS	16
+
 struct audit_aux_data_mq_open {
 	struct audit_aux_data	d;
 	int			oflag;
@@ -181,6 +182,13 @@
 	struct vfsmount		*mnt;
 };
 
+struct audit_aux_data_pids {
+	struct audit_aux_data	d;
+	pid_t			target_pid[AUDIT_AUX_PIDS];
+	u32			target_sid[AUDIT_AUX_PIDS];
+	int			pid_count;
+};
+
 /* The per-task audit context. */
 struct audit_context {
 	int		    dummy;	/* must be the first element */
@@ -201,6 +209,7 @@
 	struct vfsmount *   pwdmnt;
 	struct audit_context *previous; /* For nested syscalls */
 	struct audit_aux_data *aux;
+	struct audit_aux_data *aux_pids;
 
 				/* Save things to print about task_struct */
 	pid_t		    pid, ppid;
@@ -209,6 +218,9 @@
 	unsigned long	    personality;
 	int		    arch;
 
+	pid_t		    target_pid;
+	u32		    target_sid;
+
 #if AUDIT_DEBUG
 	int		    put_count;
 	int		    ino_count;
@@ -654,6 +666,10 @@
 		context->aux = aux->next;
 		kfree(aux);
 	}
+	while ((aux = context->aux_pids)) {
+		context->aux_pids = aux->next;
+		kfree(aux);
+	}
 }
 
 static inline void audit_zero_context(struct audit_context *context,
@@ -795,6 +811,29 @@
 	audit_log_task_context(ab);
 }
 
+static int audit_log_pid_context(struct audit_context *context, pid_t pid,
+				 u32 sid)
+{
+	struct audit_buffer *ab;
+	char *s = NULL;
+	u32 len;
+	int rc = 0;
+
+	ab = audit_log_start(context, GFP_KERNEL, AUDIT_OBJ_PID);
+	if (!ab)
+		return 1;
+
+	if (selinux_sid_to_string(sid, &s, &len)) {
+		audit_log_format(ab, "opid=%d obj=(none)", pid);
+		rc = 1;
+	} else
+		audit_log_format(ab, "opid=%d  obj=%s", pid, s);
+	audit_log_end(ab);
+	kfree(s);
+
+	return rc;
+}
+
 static void audit_log_exit(struct audit_context *context, struct task_struct *tsk)
 {
 	int i, call_panic = 0;
@@ -973,6 +1012,21 @@
 		audit_log_end(ab);
 	}
 
+	for (aux = context->aux_pids; aux; aux = aux->next) {
+		struct audit_aux_data_pids *axs = (void *)aux;
+		int i;
+
+		for (i = 0; i < axs->pid_count; i++)
+			if (audit_log_pid_context(context, axs->target_pid[i],
+						  axs->target_sid[i]))
+				call_panic = 1;
+	}
+
+	if (context->target_pid &&
+	    audit_log_pid_context(context, context->target_pid,
+				  context->target_sid))
+			call_panic = 1;
+
 	if (context->pwd && context->pwdmnt) {
 		ab = audit_log_start(context, GFP_KERNEL, AUDIT_CWD);
 		if (ab) {
@@ -1193,6 +1247,10 @@
 	} else {
 		audit_free_names(context);
 		audit_free_aux(context);
+		context->aux = NULL;
+		context->aux_pids = NULL;
+		context->target_pid = 0;
+		context->target_sid = 0;
 		kfree(context->filterkey);
 		context->filterkey = NULL;
 		tsk->audit_context = context;
@@ -1226,6 +1284,7 @@
 	context->names[context->name_count].name_len = AUDIT_NAME_FULL;
 	context->names[context->name_count].name_put = 1;
 	context->names[context->name_count].ino  = (unsigned long)-1;
+	context->names[context->name_count].osid = 0;
 	++context->name_count;
 	if (!context->pwd) {
 		read_lock(&current->fs->lock);
@@ -1279,6 +1338,28 @@
 #endif
 }
 
+static int audit_inc_name_count(struct audit_context *context,
+				const struct inode *inode)
+{
+	if (context->name_count >= AUDIT_NAMES) {
+		if (inode)
+			printk(KERN_DEBUG "name_count maxed, losing inode data: "
+			       "dev=%02x:%02x, inode=%lu",
+			       MAJOR(inode->i_sb->s_dev),
+			       MINOR(inode->i_sb->s_dev),
+			       inode->i_ino);
+
+		else
+			printk(KERN_DEBUG "name_count maxed, losing inode data");
+		return 1;
+	}
+	context->name_count++;
+#if AUDIT_DEBUG
+	context->ino_count++;
+#endif
+	return 0;
+}
+
 /* Copy inode data into an audit_names. */
 static void audit_copy_inode(struct audit_names *name, const struct inode *inode)
 {
@@ -1316,13 +1397,10 @@
 	else {
 		/* FIXME: how much do we care about inodes that have no
 		 * associated name? */
-		if (context->name_count >= AUDIT_NAMES - AUDIT_NAMES_RESERVED)
+		if (audit_inc_name_count(context, inode))
 			return;
-		idx = context->name_count++;
+		idx = context->name_count - 1;
 		context->names[idx].name = NULL;
-#if AUDIT_DEBUG
-		++context->ino_count;
-#endif
 	}
 	audit_copy_inode(&context->names[idx], inode);
 }
@@ -1346,7 +1424,7 @@
 {
 	int idx;
 	struct audit_context *context = current->audit_context;
-	const char *found_name = NULL;
+	const char *found_parent = NULL, *found_child = NULL;
 	int dirlen = 0;
 
 	if (!context->in_syscall)
@@ -1354,88 +1432,73 @@
 
 	/* determine matching parent */
 	if (!dname)
-		goto update_context;
-	for (idx = 0; idx < context->name_count; idx++)
-		if (context->names[idx].ino == parent->i_ino) {
-			const char *name = context->names[idx].name;
+		goto add_names;
 
-			if (!name)
-				continue;
+	/* parent is more likely, look for it first */
+	for (idx = 0; idx < context->name_count; idx++) {
+		struct audit_names *n = &context->names[idx];
 
-			if (audit_compare_dname_path(dname, name, &dirlen) == 0) {
-				context->names[idx].name_len = dirlen;
-				found_name = name;
-				break;
-			}
+		if (!n->name)
+			continue;
+
+		if (n->ino == parent->i_ino &&
+		    !audit_compare_dname_path(dname, n->name, &dirlen)) {
+			n->name_len = dirlen; /* update parent data in place */
+			found_parent = n->name;
+			goto add_names;
 		}
-
-update_context:
-	idx = context->name_count;
-	if (context->name_count == AUDIT_NAMES) {
-		printk(KERN_DEBUG "name_count maxed and losing %s\n",
-			found_name ?: "(null)");
-		return;
 	}
-	context->name_count++;
-#if AUDIT_DEBUG
-	context->ino_count++;
-#endif
-	/* Re-use the name belonging to the slot for a matching parent directory.
-	 * All names for this context are relinquished in audit_free_names() */
-	context->names[idx].name = found_name;
-	context->names[idx].name_len = AUDIT_NAME_FULL;
-	context->names[idx].name_put = 0;	/* don't call __putname() */
 
-	if (!inode)
-		context->names[idx].ino = (unsigned long)-1;
-	else
-		audit_copy_inode(&context->names[idx], inode);
+	/* no matching parent, look for matching child */
+	for (idx = 0; idx < context->name_count; idx++) {
+		struct audit_names *n = &context->names[idx];
 
-	/* A parent was not found in audit_names, so copy the inode data for the
-	 * provided parent. */
-	if (!found_name) {
-		idx = context->name_count;
-		if (context->name_count == AUDIT_NAMES) {
-			printk(KERN_DEBUG
-				"name_count maxed and losing parent inode data: dev=%02x:%02x, inode=%lu",
-				MAJOR(parent->i_sb->s_dev),
-				MINOR(parent->i_sb->s_dev),
-				parent->i_ino);
-			return;
+		if (!n->name)
+			continue;
+
+		/* strcmp() is the more likely scenario */
+		if (!strcmp(dname, n->name) ||
+		     !audit_compare_dname_path(dname, n->name, &dirlen)) {
+			if (inode)
+				audit_copy_inode(n, inode);
+			else
+				n->ino = (unsigned long)-1;
+			found_child = n->name;
+			goto add_names;
 		}
-		context->name_count++;
-#if AUDIT_DEBUG
-		context->ino_count++;
-#endif
+	}
+
+add_names:
+	if (!found_parent) {
+		if (audit_inc_name_count(context, parent))
+			return;
+		idx = context->name_count - 1;
+		context->names[idx].name = NULL;
 		audit_copy_inode(&context->names[idx], parent);
 	}
-}
 
-/**
- * audit_inode_update - update inode info for last collected name
- * @inode: inode being audited
- *
- * When open() is called on an existing object with the O_CREAT flag, the inode
- * data audit initially collects is incorrect.  This additional hook ensures
- * audit has the inode data for the actual object to be opened.
- */
-void __audit_inode_update(const struct inode *inode)
-{
-	struct audit_context *context = current->audit_context;
-	int idx;
+	if (!found_child) {
+		if (audit_inc_name_count(context, inode))
+			return;
+		idx = context->name_count - 1;
 
-	if (!context->in_syscall || !inode)
-		return;
+		/* Re-use the name belonging to the slot for a matching parent
+		 * directory. All names for this context are relinquished in
+		 * audit_free_names() */
+		if (found_parent) {
+			context->names[idx].name = found_parent;
+			context->names[idx].name_len = AUDIT_NAME_FULL;
+			/* don't call __putname() */
+			context->names[idx].name_put = 0;
+		} else {
+			context->names[idx].name = NULL;
+		}
 
-	if (context->name_count == 0) {
-		context->name_count++;
-#if AUDIT_DEBUG
-		context->ino_count++;
-#endif
+		if (inode)
+			audit_copy_inode(&context->names[idx], inode);
+		else
+			context->names[idx].ino = (unsigned long)-1;
 	}
-	idx = context->name_count - 1;
-
-	audit_copy_inode(&context->names[idx], inode);
 }
 
 /**
@@ -1880,6 +1943,14 @@
 	return 0;
 }
 
+void __audit_ptrace(struct task_struct *t)
+{
+	struct audit_context *context = current->audit_context;
+
+	context->target_pid = t->pid;
+	selinux_get_task_sid(t, &context->target_sid);
+}
+
 /**
  * audit_avc_path - record the granting or denial of permissions
  * @dentry: dentry to record
@@ -1918,15 +1989,17 @@
  * If the audit subsystem is being terminated, record the task (pid)
  * and uid that is doing that.
  */
-void __audit_signal_info(int sig, struct task_struct *t)
+int __audit_signal_info(int sig, struct task_struct *t)
 {
+	struct audit_aux_data_pids *axp;
+	struct task_struct *tsk = current;
+	struct audit_context *ctx = tsk->audit_context;
 	extern pid_t audit_sig_pid;
 	extern uid_t audit_sig_uid;
 	extern u32 audit_sig_sid;
 
-	if (sig == SIGTERM || sig == SIGHUP || sig == SIGUSR1) {
-		struct task_struct *tsk = current;
-		struct audit_context *ctx = tsk->audit_context;
+	if (audit_pid && t->tgid == audit_pid &&
+	    (sig == SIGTERM || sig == SIGHUP || sig == SIGUSR1)) {
 		audit_sig_pid = tsk->pid;
 		if (ctx)
 			audit_sig_uid = ctx->loginuid;
@@ -1934,4 +2007,72 @@
 			audit_sig_uid = tsk->uid;
 		selinux_get_task_sid(tsk, &audit_sig_sid);
 	}
+
+	if (!audit_signals) /* audit_context checked in wrapper */
+		return 0;
+
+	/* optimize the common case by putting first signal recipient directly
+	 * in audit_context */
+	if (!ctx->target_pid) {
+		ctx->target_pid = t->tgid;
+		selinux_get_task_sid(t, &ctx->target_sid);
+		return 0;
+	}
+
+	axp = (void *)ctx->aux_pids;
+	if (!axp || axp->pid_count == AUDIT_AUX_PIDS) {
+		axp = kzalloc(sizeof(*axp), GFP_ATOMIC);
+		if (!axp)
+			return -ENOMEM;
+
+		axp->d.type = AUDIT_OBJ_PID;
+		axp->d.next = ctx->aux_pids;
+		ctx->aux_pids = (void *)axp;
+	}
+	BUG_ON(axp->pid_count > AUDIT_AUX_PIDS);
+
+	axp->target_pid[axp->pid_count] = t->tgid;
+	selinux_get_task_sid(t, &axp->target_sid[axp->pid_count]);
+	axp->pid_count++;
+
+	return 0;
+}
+
+/**
+ * audit_core_dumps - record information about processes that end abnormally
+ * @sig: signal value
+ *
+ * If a process ends with a core dump, something fishy is going on and we
+ * should record the event for investigation.
+ */
+void audit_core_dumps(long signr)
+{
+	struct audit_buffer *ab;
+	u32 sid;
+
+	if (!audit_enabled)
+		return;
+
+	if (signr == SIGQUIT)	/* don't care for those */
+		return;
+
+	ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_ANOM_ABEND);
+	audit_log_format(ab, "auid=%u uid=%u gid=%u",
+			audit_get_loginuid(current->audit_context),
+			current->uid, current->gid);
+	selinux_get_task_sid(current, &sid);
+	if (sid) {
+		char *ctx = NULL;
+		u32 len;
+
+		if (selinux_sid_to_string(sid, &ctx, &len))
+			audit_log_format(ab, " ssid=%u", sid);
+		else
+			audit_log_format(ab, " subj=%s", ctx);
+		kfree(ctx);
+	}
+	audit_log_format(ab, " pid=%d comm=", current->pid);
+	audit_log_untrustedstring(ab, current->comm);
+	audit_log_format(ab, " sig=%ld", signr);
+	audit_log_end(ab);
 }
diff --git a/kernel/compat.c b/kernel/compat.c
index cebb4c2..3bae374 100644
--- a/kernel/compat.c
+++ b/kernel/compat.c
@@ -475,8 +475,8 @@
 	return min_length;
 }
 
-static int get_compat_itimerspec(struct itimerspec *dst, 
-				 struct compat_itimerspec __user *src)
+int get_compat_itimerspec(struct itimerspec *dst,
+			  const struct compat_itimerspec __user *src)
 { 
 	if (get_compat_timespec(&dst->it_interval, &src->it_interval) ||
 	    get_compat_timespec(&dst->it_value, &src->it_value))
@@ -484,8 +484,8 @@
 	return 0;
 } 
 
-static int put_compat_itimerspec(struct compat_itimerspec __user *dst, 
-				 struct itimerspec *src)
+int put_compat_itimerspec(struct compat_itimerspec __user *dst,
+			  const struct itimerspec *src)
 { 
 	if (put_compat_timespec(&src->it_interval, &dst->it_interval) ||
 	    put_compat_timespec(&src->it_value, &dst->it_value))
diff --git a/kernel/exit.c b/kernel/exit.c
index b0c6f0c..c6d14b8 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -24,6 +24,7 @@
 #include <linux/pid_namespace.h>
 #include <linux/ptrace.h>
 #include <linux/profile.h>
+#include <linux/signalfd.h>
 #include <linux/mount.h>
 #include <linux/proc_fs.h>
 #include <linux/kthread.h>
@@ -42,6 +43,7 @@
 #include <linux/audit.h> /* for audit_free() */
 #include <linux/resource.h>
 #include <linux/blkdev.h>
+#include <linux/task_io_accounting_ops.h>
 
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
@@ -82,6 +84,14 @@
 	sighand = rcu_dereference(tsk->sighand);
 	spin_lock(&sighand->siglock);
 
+	/*
+	 * Notify that this sighand has been detached. This must
+	 * be called with the tsk->sighand lock held. Also, this
+	 * access tsk->sighand internally, so it must be called
+	 * before tsk->sighand is reset.
+	 */
+	signalfd_detach_locked(tsk);
+
 	posix_cpu_timers_exit(tsk);
 	if (atomic_dec_and_test(&sig->count))
 		posix_cpu_timers_exit_group(tsk);
@@ -113,6 +123,8 @@
 		sig->nvcsw += tsk->nvcsw;
 		sig->nivcsw += tsk->nivcsw;
 		sig->sched_time += tsk->sched_time;
+		sig->inblock += task_io_get_inblock(tsk);
+		sig->oublock += task_io_get_oublock(tsk);
 		sig = NULL; /* Marker for below. */
 	}
 
@@ -299,12 +311,12 @@
 	if (process_session(curr) != session) {
 		detach_pid(curr, PIDTYPE_SID);
 		set_signal_session(curr->signal, session);
-		attach_pid(curr, PIDTYPE_SID, session);
+		attach_pid(curr, PIDTYPE_SID, find_pid(session));
 	}
 	if (process_group(curr) != pgrp) {
 		detach_pid(curr, PIDTYPE_PGID);
 		curr->signal->pgrp = pgrp;
-		attach_pid(curr, PIDTYPE_PGID, pgrp);
+		attach_pid(curr, PIDTYPE_PGID, find_pid(pgrp));
 	}
 }
 
@@ -1193,6 +1205,12 @@
 			p->nvcsw + sig->nvcsw + sig->cnvcsw;
 		psig->cnivcsw +=
 			p->nivcsw + sig->nivcsw + sig->cnivcsw;
+		psig->cinblock +=
+			task_io_get_inblock(p) +
+			sig->inblock + sig->cinblock;
+		psig->coublock +=
+			task_io_get_oublock(p) +
+			sig->oublock + sig->coublock;
 		spin_unlock_irq(&p->parent->sighand->siglock);
 	}
 
diff --git a/kernel/fork.c b/kernel/fork.c
index 5dd3979..49530e4 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -875,6 +875,7 @@
 	sig->utime = sig->stime = sig->cutime = sig->cstime = cputime_zero;
 	sig->nvcsw = sig->nivcsw = sig->cnvcsw = sig->cnivcsw = 0;
 	sig->min_flt = sig->maj_flt = sig->cmin_flt = sig->cmaj_flt = 0;
+	sig->inblock = sig->oublock = sig->cinblock = sig->coublock = 0;
 	sig->sched_time = 0;
 	INIT_LIST_HEAD(&sig->cpu_timers[0]);
 	INIT_LIST_HEAD(&sig->cpu_timers[1]);
@@ -955,7 +956,7 @@
 					unsigned long stack_size,
 					int __user *parent_tidptr,
 					int __user *child_tidptr,
-					int pid)
+					struct pid *pid)
 {
 	int retval;
 	struct task_struct *p = NULL;
@@ -1022,7 +1023,7 @@
 	p->did_exec = 0;
 	delayacct_tsk_init(p);	/* Must remain after dup_task_struct() */
 	copy_flags(clone_flags, p);
-	p->pid = pid;
+	p->pid = pid_nr(pid);
 	retval = -EFAULT;
 	if (clone_flags & CLONE_PARENT_SETTID)
 		if (put_user(p->pid, parent_tidptr))
@@ -1251,13 +1252,13 @@
 			p->signal->tty = current->signal->tty;
 			p->signal->pgrp = process_group(current);
 			set_signal_session(p->signal, process_session(current));
-			attach_pid(p, PIDTYPE_PGID, process_group(p));
-			attach_pid(p, PIDTYPE_SID, process_session(p));
+			attach_pid(p, PIDTYPE_PGID, task_pgrp(current));
+			attach_pid(p, PIDTYPE_SID, task_session(current));
 
 			list_add_tail_rcu(&p->tasks, &init_task.tasks);
 			__get_cpu_var(process_counts)++;
 		}
-		attach_pid(p, PIDTYPE_PID, p->pid);
+		attach_pid(p, PIDTYPE_PID, pid);
 		nr_threads++;
 	}
 
@@ -1321,7 +1322,8 @@
 	struct task_struct *task;
 	struct pt_regs regs;
 
-	task = copy_process(CLONE_VM, 0, idle_regs(&regs), 0, NULL, NULL, 0);
+	task = copy_process(CLONE_VM, 0, idle_regs(&regs), 0, NULL, NULL,
+				&init_struct_pid);
 	if (!IS_ERR(task))
 		init_idle(task, cpu);
 
@@ -1371,7 +1373,7 @@
 			clone_flags |= CLONE_PTRACE;
 	}
 
-	p = copy_process(clone_flags, stack_start, regs, stack_size, parent_tidptr, child_tidptr, nr);
+	p = copy_process(clone_flags, stack_start, regs, stack_size, parent_tidptr, child_tidptr, pid);
 	/*
 	 * Do this prior waking up the new thread - the thread pointer
 	 * might get invalid after that point, if the thread exits quickly.
@@ -1420,12 +1422,15 @@
 #define ARCH_MIN_MMSTRUCT_ALIGN 0
 #endif
 
-static void sighand_ctor(void *data, struct kmem_cache *cachep, unsigned long flags)
+static void sighand_ctor(void *data, struct kmem_cache *cachep,
+			unsigned long flags)
 {
 	struct sighand_struct *sighand = data;
 
-	if (flags & SLAB_CTOR_CONSTRUCTOR)
+	if (flags & SLAB_CTOR_CONSTRUCTOR) {
 		spin_lock_init(&sighand->siglock);
+		INIT_LIST_HEAD(&sighand->signalfd_list);
+	}
 }
 
 void __init proc_caches_init(void)
@@ -1451,7 +1456,6 @@
 			SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
 }
 
-
 /*
  * Check constraints on flags passed to the unshare system call and
  * force unsharing of additional process context as appropriate.
diff --git a/kernel/pid.c b/kernel/pid.c
index d3ad724..eb66bd2 100644
--- a/kernel/pid.c
+++ b/kernel/pid.c
@@ -27,11 +27,13 @@
 #include <linux/bootmem.h>
 #include <linux/hash.h>
 #include <linux/pid_namespace.h>
+#include <linux/init_task.h>
 
 #define pid_hashfn(nr) hash_long((unsigned long)nr, pidhash_shift)
 static struct hlist_head *pid_hash;
 static int pidhash_shift;
 static struct kmem_cache *pid_cachep;
+struct pid init_struct_pid = INIT_STRUCT_PID;
 
 int pid_max = PID_MAX_DEFAULT;
 
@@ -247,13 +249,16 @@
 }
 EXPORT_SYMBOL_GPL(find_pid);
 
-int fastcall attach_pid(struct task_struct *task, enum pid_type type, int nr)
+/*
+ * attach_pid() must be called with the tasklist_lock write-held.
+ */
+int fastcall attach_pid(struct task_struct *task, enum pid_type type,
+		struct pid *pid)
 {
 	struct pid_link *link;
-	struct pid *pid;
 
 	link = &task->pids[type];
-	link->pid = pid = find_pid(nr);
+	link->pid = pid;
 	hlist_add_head_rcu(&link->node, &pid->tasks[type]);
 
 	return 0;
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 4d50e06..ad7949a 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -18,6 +18,7 @@
 #include <linux/ptrace.h>
 #include <linux/security.h>
 #include <linux/signal.h>
+#include <linux/audit.h>
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
@@ -161,6 +162,8 @@
 {
 	int retval;
 
+	audit_ptrace(task);
+
 	retval = -EPERM;
 	if (task->pid <= 1)
 		goto out;
diff --git a/kernel/signal.c b/kernel/signal.c
index 2ac3a66..364fc95 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -21,6 +21,7 @@
 #include <linux/syscalls.h>
 #include <linux/ptrace.h>
 #include <linux/signal.h>
+#include <linux/signalfd.h>
 #include <linux/capability.h>
 #include <linux/freezer.h>
 #include <linux/pid_namespace.h>
@@ -113,8 +114,7 @@
 
 /* Given the mask, find the first available signal that should be serviced. */
 
-static int
-next_signal(struct sigpending *pending, sigset_t *mask)
+int next_signal(struct sigpending *pending, sigset_t *mask)
 {
 	unsigned long i, *s, *m, x;
 	int sig = 0;
@@ -497,6 +497,11 @@
 	int error = -EINVAL;
 	if (!valid_signal(sig))
 		return error;
+
+	error = audit_signal_info(sig, t); /* Let audit system see the signal */
+	if (error)
+		return error;
+
 	error = -EPERM;
 	if ((info == SEND_SIG_NOINFO || (!is_si_special(info) && SI_FROMUSER(info)))
 	    && ((sig != SIGCONT) ||
@@ -506,10 +511,7 @@
 	    && !capable(CAP_KILL))
 		return error;
 
-	error = security_task_kill(t, info, sig, 0);
-	if (!error)
-		audit_signal_info(sig, t); /* Let audit system see the signal */
-	return error;
+	return security_task_kill(t, info, sig, 0);
 }
 
 /* forward decl */
@@ -630,6 +632,12 @@
 	int ret = 0;
 
 	/*
+	 * Deliver the signal to listening signalfds. This must be called
+	 * with the sighand lock held.
+	 */
+	signalfd_notify(t, sig);
+
+	/*
 	 * fast-pathed signals for kernel-internal things like SIGSTOP
 	 * or SIGKILL.
 	 */
@@ -1280,6 +1288,11 @@
 		ret = 1;
 		goto out;
 	}
+	/*
+	 * Deliver the signal to listening signalfds. This must be called
+	 * with the sighand lock held.
+	 */
+	signalfd_notify(p, sig);
 
 	list_add_tail(&q->list, &p->pending.list);
 	sigaddset(&p->pending.signal, sig);
@@ -1323,6 +1336,11 @@
 		q->info.si_overrun++;
 		goto out;
 	} 
+	/*
+	 * Deliver the signal to listening signalfds. This must be called
+	 * with the sighand lock held.
+	 */
+	signalfd_notify(p, sig);
 
 	/*
 	 * Put this signal on the shared-pending queue.
@@ -1983,6 +2001,8 @@
 	/*
 	 * If you change siginfo_t structure, please be sure
 	 * this code is fixed accordingly.
+	 * Please remember to update the signalfd_copyinfo() function
+	 * inside fs/signalfd.c too, in case siginfo_t changes.
 	 * It should never copy any pad contained in the structure
 	 * to avoid security leaks, but must copy the generic
 	 * 3 ints plus the relevant union member.
diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c
index daabb74..fcee2a8 100644
--- a/kernel/stop_machine.c
+++ b/kernel/stop_machine.c
@@ -8,6 +8,8 @@
 #include <linux/sched.h>
 #include <linux/stop_machine.h>
 #include <linux/syscalls.h>
+#include <linux/interrupt.h>
+
 #include <asm/atomic.h>
 #include <asm/semaphore.h>
 #include <asm/uaccess.h>
@@ -45,6 +47,7 @@
 		if (stopmachine_state == STOPMACHINE_DISABLE_IRQ 
 		    && !irqs_disabled) {
 			local_irq_disable();
+			hard_irq_disable();
 			irqs_disabled = 1;
 			/* Ack: irqs disabled. */
 			smp_mb(); /* Must read state first. */
@@ -124,6 +127,7 @@
 
 	/* Make them disable irqs. */
 	local_irq_disable();
+	hard_irq_disable();
 	stopmachine_set_state(STOPMACHINE_DISABLE_IRQ);
 
 	return 0;
diff --git a/kernel/sys.c b/kernel/sys.c
index cdb7e94..872271c 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -14,6 +14,7 @@
 #include <linux/prctl.h>
 #include <linux/highuid.h>
 #include <linux/fs.h>
+#include <linux/resource.h>
 #include <linux/kernel.h>
 #include <linux/kexec.h>
 #include <linux/workqueue.h>
@@ -29,6 +30,7 @@
 #include <linux/signal.h>
 #include <linux/cn_proc.h>
 #include <linux/getcpu.h>
+#include <linux/task_io_accounting_ops.h>
 
 #include <linux/compat.h>
 #include <linux/syscalls.h>
@@ -658,7 +660,7 @@
 	int error = -EINVAL;
 	struct pid *pgrp;
 
-	if (which > 2 || which < 0)
+	if (which > PRIO_USER || which < PRIO_PROCESS)
 		goto out;
 
 	/* normalize: avoid signed division (rounding problems) */
@@ -722,7 +724,7 @@
 	long niceval, retval = -ESRCH;
 	struct pid *pgrp;
 
-	if (which > 2 || which < 0)
+	if (which > PRIO_USER || which < PRIO_PROCESS)
 		return -EINVAL;
 
 	read_lock(&tasklist_lock);
@@ -1486,7 +1488,7 @@
 	if (process_group(p) != pgid) {
 		detach_pid(p, PIDTYPE_PGID);
 		p->signal->pgrp = pgid;
-		attach_pid(p, PIDTYPE_PGID, pgid);
+		attach_pid(p, PIDTYPE_PGID, find_pid(pgid));
 	}
 
 	err = 0;
@@ -2082,6 +2084,8 @@
 			r->ru_nivcsw = p->signal->cnivcsw;
 			r->ru_minflt = p->signal->cmin_flt;
 			r->ru_majflt = p->signal->cmaj_flt;
+			r->ru_inblock = p->signal->cinblock;
+			r->ru_oublock = p->signal->coublock;
 
 			if (who == RUSAGE_CHILDREN)
 				break;
@@ -2093,6 +2097,8 @@
 			r->ru_nivcsw += p->signal->nivcsw;
 			r->ru_minflt += p->signal->min_flt;
 			r->ru_majflt += p->signal->maj_flt;
+			r->ru_inblock += p->signal->inblock;
+			r->ru_oublock += p->signal->oublock;
 			t = p;
 			do {
 				utime = cputime_add(utime, t->utime);
@@ -2101,6 +2107,8 @@
 				r->ru_nivcsw += t->nivcsw;
 				r->ru_minflt += t->min_flt;
 				r->ru_majflt += t->maj_flt;
+				r->ru_inblock += task_io_get_inblock(t);
+				r->ru_oublock += task_io_get_oublock(t);
 				t = next_thread(t);
 			} while (t != p);
 			break;
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index d7306d0..b6d77a8 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -141,3 +141,8 @@
 cond_syscall(sys_bdflush);
 cond_syscall(sys_ioprio_set);
 cond_syscall(sys_ioprio_get);
+
+/* New file descriptors */
+cond_syscall(sys_signalfd);
+cond_syscall(sys_timerfd);
+cond_syscall(sys_eventfd);
diff --git a/lib/Makefile b/lib/Makefile
index 1f65b46..c8c8e20 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -13,7 +13,7 @@
 lib-y	+= kobject.o kref.o kobject_uevent.o klist.o
 
 obj-y += div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \
-	 bust_spinlocks.o
+	 bust_spinlocks.o hexdump.o
 
 ifeq ($(CONFIG_DEBUG_KOBJECT),y)
 CFLAGS_kobject.o += -DDEBUG
diff --git a/lib/audit.c b/lib/audit.c
index 3b1289f..8e7dc1c 100644
--- a/lib/audit.c
+++ b/lib/audit.c
@@ -23,6 +23,16 @@
 ~0U
 };
 
+static unsigned signal_class[] = {
+#include <asm-generic/audit_signal.h>
+~0U
+};
+
+int audit_classify_arch(int arch)
+{
+	return 0;
+}
+
 int audit_classify_syscall(int abi, unsigned syscall)
 {
 	switch(syscall) {
@@ -49,6 +59,7 @@
 	audit_register_class(AUDIT_CLASS_READ, read_class);
 	audit_register_class(AUDIT_CLASS_DIR_WRITE, dir_class);
 	audit_register_class(AUDIT_CLASS_CHATTR, chattr_class);
+	audit_register_class(AUDIT_CLASS_SIGNAL, signal_class);
 	return 0;
 }
 
diff --git a/lib/hexdump.c b/lib/hexdump.c
new file mode 100644
index 0000000..e6da5b7
--- /dev/null
+++ b/lib/hexdump.c
@@ -0,0 +1,104 @@
+/*
+ * lib/hexdump.c
+ *
+ * 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. See README and COPYING for
+ * more details.
+ */
+
+#include <linux/types.h>
+#include <linux/ctype.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+/**
+ * hex_dump_to_buffer - convert a blob of data to "hex ASCII" in memory
+ * @buf: data blob to dump
+ * @len: number of bytes in the @buf
+ * @linebuf: where to put the converted data
+ * @linebuflen: total size of @linebuf, including space for terminating NUL
+ *
+ * hex_dump_to_buffer() works on one "line" of output at a time, i.e.,
+ * 16 bytes of input data converted to hex + ASCII output.
+ *
+ * Given a buffer of u8 data, hex_dump_to_buffer() converts the input data
+ * to a hex + ASCII dump at the supplied memory location.
+ * The converted output is always NUL-terminated.
+ *
+ * E.g.:
+ *	hex_dump_to_buffer(frame->data, frame->len, linebuf, sizeof(linebuf));
+ *
+ * example output buffer:
+ * 40414243 44454647 48494a4b 4c4d4e4f  @ABCDEFGHIJKLMNO
+ */
+void hex_dump_to_buffer(const void *buf, size_t len, char *linebuf,
+			size_t linebuflen)
+{
+	const u8 *ptr = buf;
+	u8 ch;
+	int j, lx = 0;
+
+	for (j = 0; (j < 16) && (j < len) && (lx + 3) < linebuflen; j++) {
+		if (j && !(j % 4))
+			linebuf[lx++] = ' ';
+		ch = ptr[j];
+		linebuf[lx++] = hex_asc(ch >> 4);
+		linebuf[lx++] = hex_asc(ch & 0x0f);
+	}
+	if ((lx + 2) < linebuflen) {
+		linebuf[lx++] = ' ';
+		linebuf[lx++] = ' ';
+	}
+	for (j = 0; (j < 16) && (j < len) && (lx + 2) < linebuflen; j++)
+		linebuf[lx++] = isprint(ptr[j]) ? ptr[j] : '.';
+	linebuf[lx++] = '\0';
+}
+EXPORT_SYMBOL(hex_dump_to_buffer);
+
+/**
+ * print_hex_dump - print a text hex dump to syslog for a binary blob of data
+ * @level: kernel log level (e.g. KERN_DEBUG)
+ * @prefix_type: controls whether prefix of an offset, address, or none
+ *  is printed (%DUMP_PREFIX_OFFSET, %DUMP_PREFIX_ADDRESS, %DUMP_PREFIX_NONE)
+ * @buf: data blob to dump
+ * @len: number of bytes in the @buf
+ *
+ * Given a buffer of u8 data, print_hex_dump() prints a hex + ASCII dump
+ * to the kernel log at the specified kernel log level, with an optional
+ * leading prefix.
+ *
+ * E.g.:
+ *   print_hex_dump(KERN_DEBUG, DUMP_PREFIX_ADDRESS, frame->data, frame->len);
+ *
+ * Example output using %DUMP_PREFIX_OFFSET:
+ * 0009ab42: 40414243 44454647 48494a4b 4c4d4e4f  @ABCDEFGHIJKLMNO
+ * Example output using %DUMP_PREFIX_ADDRESS:
+ * ffffffff88089af0: 70717273 74757677 78797a7b 7c7d7e7f  pqrstuvwxyz{|}~.
+ */
+void print_hex_dump(const char *level, int prefix_type, void *buf, size_t len)
+{
+	u8 *ptr = buf;
+	int i, linelen, remaining = len;
+	unsigned char linebuf[100];
+
+	for (i = 0; i < len; i += 16) {
+		linelen = min(remaining, 16);
+		remaining -= 16;
+		hex_dump_to_buffer(ptr + i, linelen, linebuf, sizeof(linebuf));
+
+		switch (prefix_type) {
+		case DUMP_PREFIX_ADDRESS:
+			printk("%s%*p: %s\n", level,
+				(int)(2 * sizeof(void *)), ptr + i, linebuf);
+			break;
+		case DUMP_PREFIX_OFFSET:
+			printk("%s%.8x: %s\n", level, i, linebuf);
+			break;
+		default:
+			printk("%s%s\n", level, linebuf);
+			break;
+		}
+	}
+}
+EXPORT_SYMBOL(print_hex_dump);
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index 63cd888..eec1481 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -588,31 +588,27 @@
 }
 
 /**
- * generic_writepages - walk the list of dirty pages of the given address space and writepage() all of them.
+ * write_cache_pages - walk the list of dirty pages of the given address space and write all of them.
  * @mapping: address space structure to write
  * @wbc: subtract the number of written pages from *@wbc->nr_to_write
+ * @writepage: function called for each page
+ * @data: data passed to writepage function
  *
- * This is a library function, which implements the writepages()
- * address_space_operation.
- *
- * If a page is already under I/O, generic_writepages() skips it, even
+ * If a page is already under I/O, write_cache_pages() skips it, even
  * if it's dirty.  This is desirable behaviour for memory-cleaning writeback,
  * but it is INCORRECT for data-integrity system calls such as fsync().  fsync()
  * and msync() need to guarantee that all the data which was dirty at the time
  * the call was made get new I/O started against them.  If wbc->sync_mode is
  * WB_SYNC_ALL then we were called for data integrity and we must wait for
  * existing IO to complete.
- *
- * Derived from mpage_writepages() - if you fix this you should check that
- * also!
  */
-int generic_writepages(struct address_space *mapping,
-		       struct writeback_control *wbc)
+int write_cache_pages(struct address_space *mapping,
+		      struct writeback_control *wbc, writepage_t writepage,
+		      void *data)
 {
 	struct backing_dev_info *bdi = mapping->backing_dev_info;
 	int ret = 0;
 	int done = 0;
-	int (*writepage)(struct page *page, struct writeback_control *wbc);
 	struct pagevec pvec;
 	int nr_pages;
 	pgoff_t index;
@@ -625,12 +621,6 @@
 		return 0;
 	}
 
-	writepage = mapping->a_ops->writepage;
-
-	/* deal with chardevs and other special file */
-	if (!writepage)
-		return 0;
-
 	pagevec_init(&pvec, 0);
 	if (wbc->range_cyclic) {
 		index = mapping->writeback_index; /* Start from prev offset */
@@ -682,8 +672,7 @@
 				continue;
 			}
 
-			ret = (*writepage)(page, wbc);
-			mapping_set_error(mapping, ret);
+			ret = (*writepage)(page, wbc, data);
 
 			if (unlikely(ret == AOP_WRITEPAGE_ACTIVATE))
 				unlock_page(page);
@@ -710,6 +699,38 @@
 		mapping->writeback_index = index;
 	return ret;
 }
+EXPORT_SYMBOL(write_cache_pages);
+
+/*
+ * Function used by generic_writepages to call the real writepage
+ * function and set the mapping flags on error
+ */
+static int __writepage(struct page *page, struct writeback_control *wbc,
+		       void *data)
+{
+	struct address_space *mapping = data;
+	int ret = mapping->a_ops->writepage(page, wbc);
+	mapping_set_error(mapping, ret);
+	return ret;
+}
+
+/**
+ * generic_writepages - walk the list of dirty pages of the given address space and writepage() all of them.
+ * @mapping: address space structure to write
+ * @wbc: subtract the number of written pages from *@wbc->nr_to_write
+ *
+ * This is a library function, which implements the writepages()
+ * address_space_operation.
+ */
+int generic_writepages(struct address_space *mapping,
+		       struct writeback_control *wbc)
+{
+	/* deal with chardevs and other special file */
+	if (!mapping->a_ops->writepage)
+		return 0;
+
+	return write_cache_pages(mapping, wbc, __writepage, mapping);
+}
 
 EXPORT_SYMBOL(generic_writepages);
 
diff --git a/mm/thrash.c b/mm/thrash.c
index 9ef9071..c4c5205 100644
--- a/mm/thrash.c
+++ b/mm/thrash.c
@@ -48,9 +48,8 @@
 		if (current_interval < current->mm->last_interval)
 			current->mm->token_priority++;
 		else {
-			current->mm->token_priority--;
-			if (unlikely(current->mm->token_priority < 0))
-				current->mm->token_priority = 0;
+			if (likely(current->mm->token_priority > 0))
+				current->mm->token_priority--;
 		}
 		/* Check if we deserve the token */
 		if (current->mm->token_priority >
diff --git a/mm/vmstat.c b/mm/vmstat.c
index 9832d9a..8faf27e 100644
--- a/mm/vmstat.c
+++ b/mm/vmstat.c
@@ -698,7 +698,7 @@
 {
 	struct delayed_work *vmstat_work = &per_cpu(vmstat_work, cpu);
 
-	INIT_DELAYED_WORK(vmstat_work, vmstat_update);
+	INIT_DELAYED_WORK_DEFERRABLE(vmstat_work, vmstat_update);
 	schedule_delayed_work_on(cpu, vmstat_work, HZ + cpu);
 }
 
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index d342e89..ceadfcf 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -174,7 +174,7 @@
 
 static int hidp_hidinput_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
 {
-	struct hid_device *hid = dev->private;
+	struct hid_device *hid = input_get_drvdata(dev);
 	struct hidp_session *session = hid->driver_data;
 
 	return hidp_queue_event(session, dev, type, code, value);
@@ -182,7 +182,7 @@
 
 static int hidp_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
 {
-	struct hidp_session *session = dev->private;
+	struct hidp_session *session = input_get_drvdata(dev);
 
 	return hidp_queue_event(session, dev, type, code, value);
 }
@@ -630,7 +630,7 @@
 	struct input_dev *input = session->input;
 	int i;
 
-	input->private = session;
+	input_set_drvdata(input, session);
 
 	input->name = "Bluetooth HID Boot Protocol Device";
 
@@ -663,7 +663,7 @@
 		input->relbit[0] |= BIT(REL_WHEEL);
 	}
 
-	input->cdev.dev = hidp_get_device(session);
+	input->dev.parent = hidp_get_device(session);
 
 	input->event = hidp_input_event;
 
@@ -737,10 +737,8 @@
 	list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].report_list, list)
 		hidp_send_report(session, report);
 
-	if (hidinput_connect(hid) == 0) {
+	if (hidinput_connect(hid) == 0)
 		hid->claimed |= HID_CLAIMED_INPUT;
-		hid_ff_init(hid);
-	}
 }
 
 int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock)
@@ -864,7 +862,7 @@
 	if (session->hid)
 		hid_free_device(session->hid);
 
-	kfree(session->input);
+	input_free_device(session->input);
 	kfree(session);
 	return err;
 }
diff --git a/net/core/link_watch.c b/net/core/link_watch.c
index e3c26a9..a5e372b 100644
--- a/net/core/link_watch.c
+++ b/net/core/link_watch.c
@@ -19,7 +19,6 @@
 #include <linux/rtnetlink.h>
 #include <linux/jiffies.h>
 #include <linux/spinlock.h>
-#include <linux/list.h>
 #include <linux/slab.h>
 #include <linux/workqueue.h>
 #include <linux/bitops.h>
@@ -27,8 +26,7 @@
 
 
 enum lw_bits {
-	LW_RUNNING = 0,
-	LW_SE_USED
+	LW_URGENT = 0,
 };
 
 static unsigned long linkwatch_flags;
@@ -37,17 +35,9 @@
 static void linkwatch_event(struct work_struct *dummy);
 static DECLARE_DELAYED_WORK(linkwatch_work, linkwatch_event);
 
-static LIST_HEAD(lweventlist);
+static struct net_device *lweventlist;
 static DEFINE_SPINLOCK(lweventlist_lock);
 
-struct lw_event {
-	struct list_head list;
-	struct net_device *dev;
-};
-
-/* Avoid kmalloc() for most systems */
-static struct lw_event singleevent;
-
 static unsigned char default_operstate(const struct net_device *dev)
 {
 	if (!netif_carrier_ok(dev))
@@ -87,25 +77,102 @@
 }
 
 
-/* Must be called with the rtnl semaphore held */
-void linkwatch_run_queue(void)
+static int linkwatch_urgent_event(struct net_device *dev)
 {
-	struct list_head head, *n, *next;
+	return netif_running(dev) && netif_carrier_ok(dev) &&
+	       dev->qdisc != dev->qdisc_sleeping;
+}
+
+
+static void linkwatch_add_event(struct net_device *dev)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&lweventlist_lock, flags);
+	dev->link_watch_next = lweventlist;
+	lweventlist = dev;
+	spin_unlock_irqrestore(&lweventlist_lock, flags);
+}
+
+
+static void linkwatch_schedule_work(int urgent)
+{
+	unsigned long delay = linkwatch_nextevent - jiffies;
+
+	if (test_bit(LW_URGENT, &linkwatch_flags))
+		return;
+
+	/* Minimise down-time: drop delay for up event. */
+	if (urgent) {
+		if (test_and_set_bit(LW_URGENT, &linkwatch_flags))
+			return;
+		delay = 0;
+	}
+
+	/* If we wrap around we'll delay it by at most HZ. */
+	if (delay > HZ)
+		delay = 0;
+
+	/*
+	 * This is true if we've scheduled it immeditately or if we don't
+	 * need an immediate execution and it's already pending.
+	 */
+	if (schedule_delayed_work(&linkwatch_work, delay) == !delay)
+		return;
+
+	/* Don't bother if there is nothing urgent. */
+	if (!test_bit(LW_URGENT, &linkwatch_flags))
+		return;
+
+	/* It's already running which is good enough. */
+	if (!cancel_delayed_work(&linkwatch_work))
+		return;
+
+	/* Otherwise we reschedule it again for immediate exection. */
+	schedule_delayed_work(&linkwatch_work, 0);
+}
+
+
+static void __linkwatch_run_queue(int urgent_only)
+{
+	struct net_device *next;
+
+	/*
+	 * Limit the number of linkwatch events to one
+	 * per second so that a runaway driver does not
+	 * cause a storm of messages on the netlink
+	 * socket.  This limit does not apply to up events
+	 * while the device qdisc is down.
+	 */
+	if (!urgent_only)
+		linkwatch_nextevent = jiffies + HZ;
+	/* Limit wrap-around effect on delay. */
+	else if (time_after(linkwatch_nextevent, jiffies + HZ))
+		linkwatch_nextevent = jiffies;
+
+	clear_bit(LW_URGENT, &linkwatch_flags);
 
 	spin_lock_irq(&lweventlist_lock);
-	list_replace_init(&lweventlist, &head);
+	next = lweventlist;
+	lweventlist = NULL;
 	spin_unlock_irq(&lweventlist_lock);
 
-	list_for_each_safe(n, next, &head) {
-		struct lw_event *event = list_entry(n, struct lw_event, list);
-		struct net_device *dev = event->dev;
+	while (next) {
+		struct net_device *dev = next;
 
-		if (event == &singleevent) {
-			clear_bit(LW_SE_USED, &linkwatch_flags);
-		} else {
-			kfree(event);
+		next = dev->link_watch_next;
+
+		if (urgent_only && !linkwatch_urgent_event(dev)) {
+			linkwatch_add_event(dev);
+			continue;
 		}
 
+		/*
+		 * Make sure the above read is complete since it can be
+		 * rewritten as soon as we clear the bit below.
+		 */
+		smp_mb__before_clear_bit();
+
 		/* We are about to handle this device,
 		 * so new events can be accepted
 		 */
@@ -124,58 +191,39 @@
 
 		dev_put(dev);
 	}
+
+	if (lweventlist)
+		linkwatch_schedule_work(0);
+}
+
+
+/* Must be called with the rtnl semaphore held */
+void linkwatch_run_queue(void)
+{
+	__linkwatch_run_queue(0);
 }
 
 
 static void linkwatch_event(struct work_struct *dummy)
 {
-	/* Limit the number of linkwatch events to one
-	 * per second so that a runaway driver does not
-	 * cause a storm of messages on the netlink
-	 * socket
-	 */
-	linkwatch_nextevent = jiffies + HZ;
-	clear_bit(LW_RUNNING, &linkwatch_flags);
-
 	rtnl_lock();
-	linkwatch_run_queue();
+	__linkwatch_run_queue(time_after(linkwatch_nextevent, jiffies));
 	rtnl_unlock();
 }
 
 
 void linkwatch_fire_event(struct net_device *dev)
 {
+	int urgent = linkwatch_urgent_event(dev);
+
 	if (!test_and_set_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state)) {
-		unsigned long flags;
-		struct lw_event *event;
-
-		if (test_and_set_bit(LW_SE_USED, &linkwatch_flags)) {
-			event = kmalloc(sizeof(struct lw_event), GFP_ATOMIC);
-
-			if (unlikely(event == NULL)) {
-				clear_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state);
-				return;
-			}
-		} else {
-			event = &singleevent;
-		}
-
 		dev_hold(dev);
-		event->dev = dev;
 
-		spin_lock_irqsave(&lweventlist_lock, flags);
-		list_add_tail(&event->list, &lweventlist);
-		spin_unlock_irqrestore(&lweventlist_lock, flags);
+		linkwatch_add_event(dev);
+	} else if (!urgent)
+		return;
 
-		if (!test_and_set_bit(LW_RUNNING, &linkwatch_flags)) {
-			unsigned long delay = linkwatch_nextevent - jiffies;
-
-			/* If we wrap around we'll delay it by at most HZ. */
-			if (delay > HZ)
-				delay = 0;
-			schedule_delayed_work(&linkwatch_work, delay);
-		}
-	}
+	linkwatch_schedule_work(urgent);
 }
 
 EXPORT_SYMBOL(linkwatch_fire_event);
diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c
index 7edea2a..75c0230 100644
--- a/net/ipv4/netfilter/arptable_filter.c
+++ b/net/ipv4/netfilter/arptable_filter.c
@@ -15,128 +15,34 @@
 #define FILTER_VALID_HOOKS ((1 << NF_ARP_IN) | (1 << NF_ARP_OUT) | \
 			   (1 << NF_ARP_FORWARD))
 
-/* Standard entry. */
-struct arpt_standard
-{
-	struct arpt_entry entry;
-	struct arpt_standard_target target;
-};
-
-struct arpt_error_target
-{
-	struct arpt_entry_target target;
-	char errorname[ARPT_FUNCTION_MAXNAMELEN];
-};
-
-struct arpt_error
-{
-	struct arpt_entry entry;
-	struct arpt_error_target target;
-};
-
 static struct
 {
 	struct arpt_replace repl;
 	struct arpt_standard entries[3];
 	struct arpt_error term;
-} initial_table __initdata
-= { { "filter", FILTER_VALID_HOOKS, 4,
-      sizeof(struct arpt_standard) * 3 + sizeof(struct arpt_error),
-      { [NF_ARP_IN] = 0,
-	[NF_ARP_OUT] = sizeof(struct arpt_standard),
-	[NF_ARP_FORWARD] = 2 * sizeof(struct arpt_standard), },
-      { [NF_ARP_IN] = 0,
-	[NF_ARP_OUT] = sizeof(struct arpt_standard),
-	[NF_ARP_FORWARD] = 2 * sizeof(struct arpt_standard), },
-      0, NULL, { } },
-    {
-	    /* ARP_IN */
-	    {
-		    {
-			    {
-				    { 0 }, { 0 }, { 0 }, { 0 },
-				    0, 0,
-				    { { 0, }, { 0, } },
-				    { { 0, }, { 0, } },
-				    0, 0,
-				    0, 0,
-				    0, 0,
-				    "", "", { 0 }, { 0 },
-				    0, 0
-			    },
-			    sizeof(struct arpt_entry),
-			    sizeof(struct arpt_standard),
-			    0,
-			    { 0, 0 }, { } },
-		    { { { { ARPT_ALIGN(sizeof(struct arpt_standard_target)), "" } }, { } },
-		      -NF_ACCEPT - 1 }
-	    },
-	    /* ARP_OUT */
-	    {
-		    {
-			    {
-				    { 0 }, { 0 }, { 0 }, { 0 },
-				    0, 0,
-				    { { 0, }, { 0, } },
-				    { { 0, }, { 0, } },
-				    0, 0,
-				    0, 0,
-				    0, 0,
-				    "", "", { 0 }, { 0 },
-				    0, 0
-			    },
-			    sizeof(struct arpt_entry),
-			    sizeof(struct arpt_standard),
-			    0,
-			    { 0, 0 }, { } },
-		    { { { { ARPT_ALIGN(sizeof(struct arpt_standard_target)), "" } }, { } },
-		      -NF_ACCEPT - 1 }
-	    },
-	    /* ARP_FORWARD */
-	    {
-		    {
-			    {
-				    { 0 }, { 0 }, { 0 }, { 0 },
-				    0, 0,
-				    { { 0, }, { 0, } },
-				    { { 0, }, { 0, } },
-				    0, 0,
-				    0, 0,
-				    0, 0,
-				    "", "", { 0 }, { 0 },
-				    0, 0
-			    },
-			    sizeof(struct arpt_entry),
-			    sizeof(struct arpt_standard),
-			    0,
-			    { 0, 0 }, { } },
-		    { { { { ARPT_ALIGN(sizeof(struct arpt_standard_target)), "" } }, { } },
-		      -NF_ACCEPT - 1 }
-	    }
-    },
-    /* ERROR */
-    {
-	    {
-		    {
-			    { 0 }, { 0 }, { 0 }, { 0 },
-			    0, 0,
-			    { { 0, }, { 0, } },
-			    { { 0, }, { 0, } },
-			    0, 0,
-			    0, 0,
-			    0, 0,
-			    "", "", { 0 }, { 0 },
-			    0, 0
-		    },
-		    sizeof(struct arpt_entry),
-		    sizeof(struct arpt_error),
-		    0,
-		    { 0, 0 }, { } },
-	    { { { { ARPT_ALIGN(sizeof(struct arpt_error_target)), ARPT_ERROR_TARGET } },
-		{ } },
-	      "ERROR"
-	    }
-    }
+} initial_table __initdata = {
+	.repl = {
+		.name = "filter",
+		.valid_hooks = FILTER_VALID_HOOKS,
+		.num_entries = 4,
+		.size = sizeof(struct arpt_standard) * 3 + sizeof(struct arpt_error),
+		.hook_entry = {
+			[NF_ARP_IN] = 0,
+			[NF_ARP_OUT] = sizeof(struct arpt_standard),
+			[NF_ARP_FORWARD] = 2 * sizeof(struct arpt_standard),
+		},
+		.underflow = {
+			[NF_ARP_IN] = 0,
+			[NF_ARP_OUT] = sizeof(struct arpt_standard),
+			[NF_ARP_FORWARD] = 2 * sizeof(struct arpt_standard),
+		},
+	},
+	.entries = {
+		ARPT_STANDARD_INIT(NF_ACCEPT),	/* ARP_IN */
+		ARPT_STANDARD_INIT(NF_ACCEPT),	/* ARP_OUT */
+		ARPT_STANDARD_INIT(NF_ACCEPT),	/* ARP_FORWARD */
+	},
+	.term = ARPT_ERROR_INIT,
 };
 
 static struct arpt_table packet_filter = {
diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c
index 4272890..4f51c1d 100644
--- a/net/ipv4/netfilter/iptable_filter.c
+++ b/net/ipv4/netfilter/iptable_filter.c
@@ -26,53 +26,29 @@
 	struct ipt_replace repl;
 	struct ipt_standard entries[3];
 	struct ipt_error term;
-} initial_table __initdata
-= { { "filter", FILTER_VALID_HOOKS, 4,
-      sizeof(struct ipt_standard) * 3 + sizeof(struct ipt_error),
-      { [NF_IP_LOCAL_IN] = 0,
-	[NF_IP_FORWARD] = sizeof(struct ipt_standard),
-	[NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2 },
-      { [NF_IP_LOCAL_IN] = 0,
-	[NF_IP_FORWARD] = sizeof(struct ipt_standard),
-	[NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2 },
-      0, NULL, { } },
-    {
-	    /* LOCAL_IN */
-	    { { { { 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 } },
-	    /* FORWARD */
-	    { { { { 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"
-      }
-    }
+} initial_table __initdata = {
+	.repl = {
+		.name = "filter",
+		.valid_hooks = FILTER_VALID_HOOKS,
+		.num_entries = 4,
+		.size = sizeof(struct ipt_standard) * 3 + sizeof(struct ipt_error),
+		.hook_entry = {
+			[NF_IP_LOCAL_IN] = 0,
+			[NF_IP_FORWARD] = sizeof(struct ipt_standard),
+			[NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2,
+		},
+		.underflow = {
+			[NF_IP_LOCAL_IN] = 0,
+			[NF_IP_FORWARD] = sizeof(struct ipt_standard),
+			[NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2,
+		},
+	},
+	.entries = {
+		IPT_STANDARD_INIT(NF_ACCEPT),	/* LOCAL_IN */
+		IPT_STANDARD_INIT(NF_ACCEPT),	/* FORWARD */
+		IPT_STANDARD_INIT(NF_ACCEPT),	/* LOCAL_OUT */
+	},
+	.term = IPT_ERROR_INIT,			/* ERROR */
 };
 
 static struct xt_table packet_filter = {
@@ -105,7 +81,8 @@
 	if ((*pskb)->len < sizeof(struct iphdr)
 	    || ip_hdrlen(*pskb) < sizeof(struct iphdr)) {
 		if (net_ratelimit())
-			printk("ipt_hook: happy cracking.\n");
+			printk("iptable_filter: ignoring short SOCK_RAW "
+			       "packet.\n");
 		return NF_ACCEPT;
 	}
 
diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c
index 9278802..902446f 100644
--- a/net/ipv4/netfilter/iptable_mangle.c
+++ b/net/ipv4/netfilter/iptable_mangle.c
@@ -33,73 +33,35 @@
 	struct ipt_replace repl;
 	struct ipt_standard entries[5];
 	struct ipt_error term;
-} initial_table __initdata
-= { { "mangle", MANGLE_VALID_HOOKS, 6,
-      sizeof(struct ipt_standard) * 5 + sizeof(struct ipt_error),
-      { [NF_IP_PRE_ROUTING] 	= 0,
-	[NF_IP_LOCAL_IN] 	= sizeof(struct ipt_standard),
-	[NF_IP_FORWARD] 	= sizeof(struct ipt_standard) * 2,
-	[NF_IP_LOCAL_OUT] 	= sizeof(struct ipt_standard) * 3,
-	[NF_IP_POST_ROUTING] 	= sizeof(struct ipt_standard) * 4 },
-      { [NF_IP_PRE_ROUTING] 	= 0,
-	[NF_IP_LOCAL_IN] 	= sizeof(struct ipt_standard),
-	[NF_IP_FORWARD] 	= sizeof(struct ipt_standard) * 2,
-	[NF_IP_LOCAL_OUT] 	= sizeof(struct ipt_standard) * 3,
-	[NF_IP_POST_ROUTING]	= sizeof(struct ipt_standard) * 4 },
-      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_IN */
-	    { { { { 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 } },
-	    /* FORWARD */
-	    { { { { 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 } },
-	    /* POST_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 } },
-    },
-    /* 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"
-      }
-    }
+} initial_table __initdata = {
+	.repl = {
+		.name = "mangle",
+		.valid_hooks = MANGLE_VALID_HOOKS,
+		.num_entries = 6,
+		.size = sizeof(struct ipt_standard) * 5 + sizeof(struct ipt_error),
+		.hook_entry = {
+			[NF_IP_PRE_ROUTING] 	= 0,
+			[NF_IP_LOCAL_IN] 	= sizeof(struct ipt_standard),
+			[NF_IP_FORWARD] 	= sizeof(struct ipt_standard) * 2,
+			[NF_IP_LOCAL_OUT] 	= sizeof(struct ipt_standard) * 3,
+			[NF_IP_POST_ROUTING] 	= sizeof(struct ipt_standard) * 4,
+		},
+		.underflow = {
+			[NF_IP_PRE_ROUTING] 	= 0,
+			[NF_IP_LOCAL_IN] 	= sizeof(struct ipt_standard),
+			[NF_IP_FORWARD] 	= sizeof(struct ipt_standard) * 2,
+			[NF_IP_LOCAL_OUT] 	= sizeof(struct ipt_standard) * 3,
+			[NF_IP_POST_ROUTING]	= sizeof(struct ipt_standard) * 4,
+		},
+	},
+	.entries = {
+		IPT_STANDARD_INIT(NF_ACCEPT),	/* PRE_ROUTING */
+		IPT_STANDARD_INIT(NF_ACCEPT),	/* LOCAL_IN */
+		IPT_STANDARD_INIT(NF_ACCEPT),	/* FORWARD */
+		IPT_STANDARD_INIT(NF_ACCEPT),	/* LOCAL_OUT */
+		IPT_STANDARD_INIT(NF_ACCEPT),	/* POST_ROUTING */
+	},
+	.term = IPT_ERROR_INIT,			/* ERROR */
 };
 
 static struct xt_table packet_mangler = {
@@ -138,7 +100,8 @@
 	if ((*pskb)->len < sizeof(struct iphdr)
 	    || ip_hdrlen(*pskb) < sizeof(struct iphdr)) {
 		if (net_ratelimit())
-			printk("ipt_hook: happy cracking.\n");
+			printk("iptable_mangle: ignoring short SOCK_RAW "
+			       "packet.\n");
 		return NF_ACCEPT;
 	}
 
diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c
index 18c3d4c..d6e5033 100644
--- a/net/ipv4/netfilter/iptable_raw.c
+++ b/net/ipv4/netfilter/iptable_raw.c
@@ -5,6 +5,7 @@
  */
 #include <linux/module.h>
 #include <linux/netfilter_ipv4/ip_tables.h>
+#include <net/ip.h>
 
 #define RAW_VALID_HOOKS ((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT))
 
@@ -21,62 +22,18 @@
 		.size = sizeof(struct ipt_standard) * 2 + sizeof(struct ipt_error),
 		.hook_entry = {
 			[NF_IP_PRE_ROUTING] = 0,
-			[NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) },
+			[NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard)
+		},
 		.underflow = {
 			[NF_IP_PRE_ROUTING] = 0,
-			[NF_IP_LOCAL_OUT]  = sizeof(struct ipt_standard) },
+			[NF_IP_LOCAL_OUT]  = sizeof(struct ipt_standard)
+		},
 	},
 	.entries = {
-	     /* PRE_ROUTING */
-	     {
-		     .entry = {
-			     .target_offset = sizeof(struct ipt_entry),
-			     .next_offset = sizeof(struct ipt_standard),
-		     },
-		     .target = {
-			  .target = {
-				  .u = {
-					  .target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)),
-				  },
-			  },
-			  .verdict = -NF_ACCEPT - 1,
-		     },
-	     },
-
-	     /* LOCAL_OUT */
-	     {
-		     .entry = {
-			     .target_offset = sizeof(struct ipt_entry),
-			     .next_offset = sizeof(struct ipt_standard),
-		     },
-		     .target = {
-			     .target = {
-				     .u = {
-					     .target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)),
-				     },
-			     },
-			     .verdict = -NF_ACCEPT - 1,
-		     },
-	     },
+		IPT_STANDARD_INIT(NF_ACCEPT),	/* PRE_ROUTING */
+		IPT_STANDARD_INIT(NF_ACCEPT),	/* LOCAL_OUT */
 	},
-	/* ERROR */
-	.term = {
-		.entry = {
-			.target_offset = sizeof(struct ipt_entry),
-			.next_offset = sizeof(struct ipt_error),
-		},
-		.target = {
-			.target = {
-				.u = {
-					.user = {
-						.target_size = IPT_ALIGN(sizeof(struct ipt_error_target)),
-						.name = IPT_ERROR_TARGET,
-					},
-				},
-			},
-			.errorname = "ERROR",
-		},
-	}
+	.term = IPT_ERROR_INIT,			/* ERROR */
 };
 
 static struct xt_table packet_raw = {
@@ -98,6 +55,24 @@
 	return ipt_do_table(pskb, hook, in, out, &packet_raw);
 }
 
+static unsigned int
+ipt_local_hook(unsigned int hook,
+	       struct sk_buff **pskb,
+	       const struct net_device *in,
+	       const struct net_device *out,
+	       int (*okfn)(struct sk_buff *))
+{
+	/* root is playing with raw sockets. */
+	if ((*pskb)->len < sizeof(struct iphdr) ||
+	    ip_hdrlen(*pskb) < sizeof(struct iphdr)) {
+		if (net_ratelimit())
+			printk("iptable_raw: ignoring short SOCK_RAW"
+			       "packet.\n");
+		return NF_ACCEPT;
+	}
+	return ipt_do_table(pskb, hook, in, out, &packet_raw);
+}
+
 /* 'raw' is the very first table. */
 static struct nf_hook_ops ipt_ops[] = {
 	{
@@ -108,7 +83,7 @@
 		.owner = THIS_MODULE,
 	},
 	{
-		.hook = ipt_hook,
+		.hook = ipt_local_hook,
 		.pf = PF_INET,
 		.hooknum = NF_IP_LOCAL_OUT,
 		.priority = NF_IP_PRI_RAW,
diff --git a/net/ipv4/netfilter/nf_nat_rule.c b/net/ipv4/netfilter/nf_nat_rule.c
index 2534f71..6740736 100644
--- a/net/ipv4/netfilter/nf_nat_rule.c
+++ b/net/ipv4/netfilter/nf_nat_rule.c
@@ -46,77 +46,20 @@
 		.hook_entry = {
 			[NF_IP_PRE_ROUTING] = 0,
 			[NF_IP_POST_ROUTING] = sizeof(struct ipt_standard),
-			[NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2 },
+			[NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2
+		},
 		.underflow = {
 			[NF_IP_PRE_ROUTING] = 0,
 			[NF_IP_POST_ROUTING] = sizeof(struct ipt_standard),
-			[NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2 },
+			[NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2
+		},
 	},
 	.entries = {
-		/* PRE_ROUTING */
-		{
-			.entry = {
-				.target_offset = sizeof(struct ipt_entry),
-				.next_offset = sizeof(struct ipt_standard),
-			},
-			.target = {
-				.target = {
-					.u = {
-						.target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)),
-					},
-				},
-				.verdict = -NF_ACCEPT - 1,
-			},
-		},
-		/* POST_ROUTING */
-		{
-			.entry = {
-				.target_offset = sizeof(struct ipt_entry),
-				.next_offset = sizeof(struct ipt_standard),
-			},
-			.target = {
-				.target = {
-					.u = {
-						.target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)),
-					},
-				},
-				.verdict = -NF_ACCEPT - 1,
-			},
-		},
-		/* LOCAL_OUT */
-		{
-			.entry = {
-				.target_offset = sizeof(struct ipt_entry),
-				.next_offset = sizeof(struct ipt_standard),
-			},
-			.target = {
-				.target = {
-					.u = {
-						.target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)),
-					},
-				},
-				.verdict = -NF_ACCEPT - 1,
-			},
-		},
+		IPT_STANDARD_INIT(NF_ACCEPT),	/* PRE_ROUTING */
+		IPT_STANDARD_INIT(NF_ACCEPT),	/* POST_ROUTING */
+		IPT_STANDARD_INIT(NF_ACCEPT),	/* LOCAL_OUT */
 	},
-	/* ERROR */
-	.term = {
-		.entry = {
-			.target_offset = sizeof(struct ipt_entry),
-			.next_offset = sizeof(struct ipt_error),
-		},
-		.target = {
-			.target = {
-				.u = {
-					.user = {
-						.target_size = IPT_ALIGN(sizeof(struct ipt_error_target)),
-						.name = IPT_ERROR_TARGET,
-					},
-				},
-			},
-			.errorname = "ERROR",
-		},
-	}
+	.term = IPT_ERROR_INIT,			/* ERROR */
 };
 
 static struct xt_table nat_table = {
@@ -230,9 +173,7 @@
 }
 
 inline unsigned int
-alloc_null_binding(struct nf_conn *ct,
-		   struct nf_nat_info *info,
-		   unsigned int hooknum)
+alloc_null_binding(struct nf_conn *ct, unsigned int hooknum)
 {
 	/* Force range to this IP; let proto decide mapping for
 	   per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED).
@@ -251,9 +192,7 @@
 }
 
 unsigned int
-alloc_null_binding_confirmed(struct nf_conn *ct,
-			     struct nf_nat_info *info,
-			     unsigned int hooknum)
+alloc_null_binding_confirmed(struct nf_conn *ct, unsigned int hooknum)
 {
 	__be32 ip
 		= (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC
@@ -275,8 +214,7 @@
 		     unsigned int hooknum,
 		     const struct net_device *in,
 		     const struct net_device *out,
-		     struct nf_conn *ct,
-		     struct nf_nat_info *info)
+		     struct nf_conn *ct)
 {
 	int ret;
 
@@ -285,7 +223,7 @@
 	if (ret == NF_ACCEPT) {
 		if (!nf_nat_initialized(ct, HOOK2MANIP(hooknum)))
 			/* NUL mapping */
-			ret = alloc_null_binding(ct, info, hooknum);
+			ret = alloc_null_binding(ct, hooknum);
 	}
 	return ret;
 }
diff --git a/net/ipv4/netfilter/nf_nat_standalone.c b/net/ipv4/netfilter/nf_nat_standalone.c
index 64bbed2..55dac36 100644
--- a/net/ipv4/netfilter/nf_nat_standalone.c
+++ b/net/ipv4/netfilter/nf_nat_standalone.c
@@ -80,7 +80,6 @@
 	struct nf_conn *ct;
 	enum ip_conntrack_info ctinfo;
 	struct nf_conn_nat *nat;
-	struct nf_nat_info *info;
 	/* maniptype == SRC for postrouting. */
 	enum nf_nat_manip_type maniptype = HOOK2MANIP(hooknum);
 
@@ -129,7 +128,6 @@
 		}
 		/* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */
 	case IP_CT_NEW:
-		info = &nat->info;
 
 		/* Seen it before?  This can happen for loopback, retrans,
 		   or local packets.. */
@@ -138,14 +136,13 @@
 
 			if (unlikely(nf_ct_is_confirmed(ct)))
 				/* NAT module was loaded late */
-				ret = alloc_null_binding_confirmed(ct, info,
-								   hooknum);
+				ret = alloc_null_binding_confirmed(ct, hooknum);
 			else if (hooknum == NF_IP_LOCAL_IN)
 				/* LOCAL_IN hook doesn't have a chain!  */
-				ret = alloc_null_binding(ct, info, hooknum);
+				ret = alloc_null_binding(ct, hooknum);
 			else
 				ret = nf_nat_rule_find(pskb, hooknum, in, out,
-						       ct, info);
+						       ct);
 
 			if (ret != NF_ACCEPT) {
 				return ret;
@@ -160,10 +157,8 @@
 		/* ESTABLISHED */
 		NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED ||
 			     ctinfo == (IP_CT_ESTABLISHED+IP_CT_IS_REPLY));
-		info = &nat->info;
 	}
 
-	NF_CT_ASSERT(info);
 	return nf_nat_packet(ct, ctinfo, hooknum, pskb);
 }
 
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 66026df..4c7e95f 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -118,15 +118,15 @@
  * Note about this hash function :
  * Typical use is probably daddr = 0, only dport is going to vary hash
  */
-static inline unsigned int hash_port_and_addr(__u16 port, __be32 addr)
+static inline unsigned int udp_hash_port(__u16 port)
 {
-	addr ^= addr >> 16;
-	addr ^= addr >> 8;
-	return port ^ addr;
+	return port;
 }
 
 static inline int __udp_lib_port_inuse(unsigned int hash, int port,
-	__be32 daddr, struct hlist_head udptable[])
+				       const struct sock *this_sk,
+				       struct hlist_head udptable[],
+				       const struct udp_get_port_ops *ops)
 {
 	struct sock *sk;
 	struct hlist_node *node;
@@ -138,7 +138,10 @@
 		inet = inet_sk(sk);
 		if (inet->num != port)
 			continue;
-		if (inet->rcv_saddr == daddr)
+		if (this_sk) {
+			if (ops->saddr_cmp(sk, this_sk))
+				return 1;
+		} else if (ops->saddr_any(sk))
 			return 1;
 	}
 	return 0;
@@ -151,12 +154,11 @@
  *  @snum:        port number to look up
  *  @udptable:    hash list table, must be of UDP_HTABLE_SIZE
  *  @port_rover:  pointer to record of last unallocated port
- *  @saddr_comp:  AF-dependent comparison of bound local IP addresses
+ *  @ops:         AF-dependent address operations
  */
 int __udp_lib_get_port(struct sock *sk, unsigned short snum,
 		       struct hlist_head udptable[], int *port_rover,
-		       int (*saddr_comp)(const struct sock *sk1,
-					 const struct sock *sk2 )    )
+		       const struct udp_get_port_ops *ops)
 {
 	struct hlist_node *node;
 	struct hlist_head *head;
@@ -176,8 +178,7 @@
 		for (i = 0; i < UDP_HTABLE_SIZE; i++, result++) {
 			int size;
 
-			hash = hash_port_and_addr(result,
-					inet_sk(sk)->rcv_saddr);
+			hash = ops->hash_port_and_rcv_saddr(result, sk);
 			head = &udptable[hash & (UDP_HTABLE_SIZE - 1)];
 			if (hlist_empty(head)) {
 				if (result > sysctl_local_port_range[1])
@@ -203,17 +204,16 @@
 				result = sysctl_local_port_range[0]
 					+ ((result - sysctl_local_port_range[0]) &
 					   (UDP_HTABLE_SIZE - 1));
-			hash = hash_port_and_addr(result, 0);
+			hash = udp_hash_port(result);
 			if (__udp_lib_port_inuse(hash, result,
-						 0, udptable))
+						 NULL, udptable, ops))
 				continue;
-			if (!inet_sk(sk)->rcv_saddr)
+			if (ops->saddr_any(sk))
 				break;
 
-			hash = hash_port_and_addr(result,
-					inet_sk(sk)->rcv_saddr);
+			hash = ops->hash_port_and_rcv_saddr(result, sk);
 			if (! __udp_lib_port_inuse(hash, result,
-				inet_sk(sk)->rcv_saddr, udptable))
+						   sk, udptable, ops))
 				break;
 		}
 		if (i >= (1 << 16) / UDP_HTABLE_SIZE)
@@ -221,7 +221,7 @@
 gotit:
 		*port_rover = snum = result;
 	} else {
-		hash = hash_port_and_addr(snum, 0);
+		hash = udp_hash_port(snum);
 		head = &udptable[hash & (UDP_HTABLE_SIZE - 1)];
 
 		sk_for_each(sk2, node, head)
@@ -231,12 +231,11 @@
 			    (!sk2->sk_reuse || !sk->sk_reuse) &&
 			    (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if ||
 			     sk2->sk_bound_dev_if == sk->sk_bound_dev_if) &&
-			    (*saddr_comp)(sk, sk2))
+			    ops->saddr_cmp(sk, sk2))
 				goto fail;
 
-		if (inet_sk(sk)->rcv_saddr) {
-			hash = hash_port_and_addr(snum,
-						  inet_sk(sk)->rcv_saddr);
+		if (!ops->saddr_any(sk)) {
+			hash = ops->hash_port_and_rcv_saddr(snum, sk);
 			head = &udptable[hash & (UDP_HTABLE_SIZE - 1)];
 
 			sk_for_each(sk2, node, head)
@@ -248,7 +247,7 @@
 				     !sk->sk_bound_dev_if ||
 				     sk2->sk_bound_dev_if ==
 				     sk->sk_bound_dev_if) &&
-				    (*saddr_comp)(sk, sk2))
+				    ops->saddr_cmp(sk, sk2))
 					goto fail;
 		}
 	}
@@ -266,12 +265,12 @@
 }
 
 int udp_get_port(struct sock *sk, unsigned short snum,
-			int (*scmp)(const struct sock *, const struct sock *))
+		 const struct udp_get_port_ops *ops)
 {
-	return  __udp_lib_get_port(sk, snum, udp_hash, &udp_port_rover, scmp);
+	return  __udp_lib_get_port(sk, snum, udp_hash, &udp_port_rover, ops);
 }
 
-int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2)
+static int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2)
 {
 	struct inet_sock *inet1 = inet_sk(sk1), *inet2 = inet_sk(sk2);
 
@@ -280,9 +279,33 @@
 		   inet1->rcv_saddr == inet2->rcv_saddr      ));
 }
 
+static int ipv4_rcv_saddr_any(const struct sock *sk)
+{
+	return !inet_sk(sk)->rcv_saddr;
+}
+
+static inline unsigned int ipv4_hash_port_and_addr(__u16 port, __be32 addr)
+{
+	addr ^= addr >> 16;
+	addr ^= addr >> 8;
+	return port ^ addr;
+}
+
+static unsigned int ipv4_hash_port_and_rcv_saddr(__u16 port,
+						 const struct sock *sk)
+{
+	return ipv4_hash_port_and_addr(port, inet_sk(sk)->rcv_saddr);
+}
+
+const struct udp_get_port_ops udp_ipv4_ops = {
+	.saddr_cmp = ipv4_rcv_saddr_equal,
+	.saddr_any = ipv4_rcv_saddr_any,
+	.hash_port_and_rcv_saddr = ipv4_hash_port_and_rcv_saddr,
+};
+
 static inline int udp_v4_get_port(struct sock *sk, unsigned short snum)
 {
-	return udp_get_port(sk, snum, ipv4_rcv_saddr_equal);
+	return udp_get_port(sk, snum, &udp_ipv4_ops);
 }
 
 /* UDP is nearly always wildcards out the wazoo, it makes no sense to try
@@ -297,8 +320,8 @@
 	unsigned int hash, hashwild;
 	int score, best = -1, hport = ntohs(dport);
 
- 	hash = hash_port_and_addr(hport, daddr);
- 	hashwild = hash_port_and_addr(hport, 0);
+	hash = ipv4_hash_port_and_addr(hport, daddr);
+	hashwild = udp_hash_port(hport);
 
 	read_lock(&udp_hash_lock);
 
@@ -1198,8 +1221,8 @@
 	struct sock *sk, *skw, *sknext;
 	int dif;
 	int hport = ntohs(uh->dest);
-	unsigned int hash = hash_port_and_addr(hport, daddr);
-	unsigned int hashwild = hash_port_and_addr(hport, 0);
+	unsigned int hash = ipv4_hash_port_and_addr(hport, daddr);
+	unsigned int hashwild = udp_hash_port(hport);
 
 	dif = skb->dev->ifindex;
 
diff --git a/net/ipv4/udp_impl.h b/net/ipv4/udp_impl.h
index 820a477..06d9419 100644
--- a/net/ipv4/udp_impl.h
+++ b/net/ipv4/udp_impl.h
@@ -5,14 +5,14 @@
 #include <net/protocol.h>
 #include <net/inet_common.h>
 
+extern const struct udp_get_port_ops udp_ipv4_ops;
+
 extern int  	__udp4_lib_rcv(struct sk_buff *, struct hlist_head [], int );
 extern void 	__udp4_lib_err(struct sk_buff *, u32, struct hlist_head []);
 
 extern int	__udp_lib_get_port(struct sock *sk, unsigned short snum,
 				   struct hlist_head udptable[], int *port_rover,
-				   int (*)(const struct sock*,const struct sock*));
-extern int	ipv4_rcv_saddr_equal(const struct sock *, const struct sock *);
-
+				   const struct udp_get_port_ops *ops);
 
 extern int	udp_setsockopt(struct sock *sk, int level, int optname,
 			       char __user *optval, int optlen);
diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c
index f34fd68..3653b32 100644
--- a/net/ipv4/udplite.c
+++ b/net/ipv4/udplite.c
@@ -19,14 +19,15 @@
 static int		udplite_port_rover;
 
 int udplite_get_port(struct sock *sk, unsigned short p,
-		     int (*c)(const struct sock *, const struct sock *))
+		     const struct udp_get_port_ops *ops)
 {
-	return  __udp_lib_get_port(sk, p, udplite_hash, &udplite_port_rover, c);
+	return  __udp_lib_get_port(sk, p, udplite_hash,
+				   &udplite_port_rover, ops);
 }
 
 static int udplite_v4_get_port(struct sock *sk, unsigned short snum)
 {
-	return udplite_get_port(sk, snum, ipv4_rcv_saddr_equal);
+	return udplite_get_port(sk, snum, &udp_ipv4_ops);
 }
 
 static int udplite_rcv(struct sk_buff *skb)
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index d02685c..c7ea248 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -4204,6 +4204,10 @@
 		return err;
 
 	ip6_null_entry.rt6i_idev = in6_dev_get(&loopback_dev);
+#ifdef CONFIG_IPV6_MULTIPLE_TABLES
+	ip6_prohibit_entry.rt6i_idev = in6_dev_get(&loopback_dev);
+	ip6_blk_hole_entry.rt6i_idev = in6_dev_get(&loopback_dev);
+#endif
 
 	register_netdevice_notifier(&ipv6_dev_notf);
 
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 6d8e4ac..14be0b9 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -660,6 +660,14 @@
   Hop-by-hop options.
  **********************************/
 
+/*
+ * Note: we cannot rely on skb->dst before we assign it in ip6_route_input().
+ */
+static inline struct inet6_dev *ipv6_skb_idev(struct sk_buff *skb)
+{
+	return skb->dst ? ip6_dst_idev(skb->dst) : __in6_dev_get(skb->dev);
+}
+
 /* Router Alert as of RFC 2711 */
 
 static int ipv6_hop_ra(struct sk_buff **skbp, int optoff)
@@ -688,25 +696,25 @@
 	if (nh[optoff + 1] != 4 || (optoff & 3) != 2) {
 		LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n",
 			       nh[optoff+1]);
-		IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
+		IP6_INC_STATS_BH(ipv6_skb_idev(skb),
 				 IPSTATS_MIB_INHDRERRORS);
 		goto drop;
 	}
 
 	pkt_len = ntohl(*(__be32 *)(nh + optoff + 2));
 	if (pkt_len <= IPV6_MAXPLEN) {
-		IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS);
+		IP6_INC_STATS_BH(ipv6_skb_idev(skb), IPSTATS_MIB_INHDRERRORS);
 		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff+2);
 		return 0;
 	}
 	if (ipv6_hdr(skb)->payload_len) {
-		IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS);
+		IP6_INC_STATS_BH(ipv6_skb_idev(skb), IPSTATS_MIB_INHDRERRORS);
 		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff);
 		return 0;
 	}
 
 	if (pkt_len > skb->len - sizeof(struct ipv6hdr)) {
-		IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INTRUNCATEDPKTS);
+		IP6_INC_STATS_BH(ipv6_skb_idev(skb), IPSTATS_MIB_INTRUNCATEDPKTS);
 		goto drop;
 	}
 
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index f508171..4704b5f 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -463,10 +463,17 @@
 		 */
 		if (xrlim_allow(dst, 1*HZ))
 			ndisc_send_redirect(skb, n, target);
-	} else if (ipv6_addr_type(&hdr->saddr)&(IPV6_ADDR_MULTICAST|IPV6_ADDR_LOOPBACK
-						|IPV6_ADDR_LINKLOCAL)) {
+	} else {
+		int addrtype = ipv6_addr_type(&hdr->saddr);
+
 		/* This check is security critical. */
-		goto error;
+		if (addrtype & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LOOPBACK))
+			goto error;
+		if (addrtype & IPV6_ADDR_LINKLOCAL) {
+			icmpv6_send(skb, ICMPV6_DEST_UNREACH,
+				ICMPV6_NOT_NEIGHBOUR, 0, skb->dev);
+			goto error;
+		}
 	}
 
 	if (skb->len > dst_mtu(dst)) {
diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c
index 76f0cf6..7e32e2a 100644
--- a/net/ipv6/netfilter/ip6table_filter.c
+++ b/net/ipv6/netfilter/ip6table_filter.c
@@ -24,53 +24,29 @@
 	struct ip6t_replace repl;
 	struct ip6t_standard entries[3];
 	struct ip6t_error term;
-} initial_table __initdata
-= { { "filter", FILTER_VALID_HOOKS, 4,
-      sizeof(struct ip6t_standard) * 3 + sizeof(struct ip6t_error),
-      { [NF_IP6_LOCAL_IN] = 0,
-	[NF_IP6_FORWARD] = sizeof(struct ip6t_standard),
-	[NF_IP6_LOCAL_OUT] = sizeof(struct ip6t_standard) * 2 },
-      { [NF_IP6_LOCAL_IN] = 0,
-	[NF_IP6_FORWARD] = sizeof(struct ip6t_standard),
-	[NF_IP6_LOCAL_OUT] = sizeof(struct ip6t_standard) * 2 },
-      0, NULL, { } },
-    {
-	    /* LOCAL_IN */
-	    { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
-		0,
-		sizeof(struct ip6t_entry),
-		sizeof(struct ip6t_standard),
-		0, { 0, 0 }, { } },
-	      { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
-		-NF_ACCEPT - 1 } },
-	    /* FORWARD */
-	    { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
-		0,
-		sizeof(struct ip6t_entry),
-		sizeof(struct ip6t_standard),
-		0, { 0, 0 }, { } },
-	      { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
-		-NF_ACCEPT - 1 } },
-	    /* LOCAL_OUT */
-	    { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
-		0,
-		sizeof(struct ip6t_entry),
-		sizeof(struct ip6t_standard),
-		0, { 0, 0 }, { } },
-	      { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
-		-NF_ACCEPT - 1 } }
-    },
-    /* ERROR */
-    { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
-	0,
-	sizeof(struct ip6t_entry),
-	sizeof(struct ip6t_error),
-	0, { 0, 0 }, { } },
-      { { { { IP6T_ALIGN(sizeof(struct ip6t_error_target)), IP6T_ERROR_TARGET } },
-	  { } },
-	"ERROR"
-      }
-    }
+} initial_table __initdata = {
+	.repl = {
+		.name = "filter",
+		.valid_hooks = FILTER_VALID_HOOKS,
+		.num_entries = 4,
+		.size = sizeof(struct ip6t_standard) * 3 + sizeof(struct ip6t_error),
+		.hook_entry = {
+			[NF_IP6_LOCAL_IN] = 0,
+			[NF_IP6_FORWARD] = sizeof(struct ip6t_standard),
+			[NF_IP6_LOCAL_OUT] = sizeof(struct ip6t_standard) * 2
+		},
+		.underflow = {
+			[NF_IP6_LOCAL_IN] = 0,
+			[NF_IP6_FORWARD] = sizeof(struct ip6t_standard),
+			[NF_IP6_LOCAL_OUT] = sizeof(struct ip6t_standard) * 2
+		},
+	},
+	.entries = {
+		IP6T_STANDARD_INIT(NF_ACCEPT),	/* LOCAL_IN */
+		IP6T_STANDARD_INIT(NF_ACCEPT),	/* FORWARD */
+		IP6T_STANDARD_INIT(NF_ACCEPT),	/* LOCAL_OUT */
+	},
+	.term = IP6T_ERROR_INIT,		/* ERROR */
 };
 
 static struct xt_table packet_filter = {
diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c
index a9f10e3..f2d2649 100644
--- a/net/ipv6/netfilter/ip6table_mangle.c
+++ b/net/ipv6/netfilter/ip6table_mangle.c
@@ -32,73 +32,35 @@
 	struct ip6t_replace repl;
 	struct ip6t_standard entries[5];
 	struct ip6t_error term;
-} initial_table __initdata
-= { { "mangle", MANGLE_VALID_HOOKS, 6,
-      sizeof(struct ip6t_standard) * 5 + sizeof(struct ip6t_error),
-      { [NF_IP6_PRE_ROUTING] 	= 0,
-	[NF_IP6_LOCAL_IN]	= sizeof(struct ip6t_standard),
-	[NF_IP6_FORWARD]	= sizeof(struct ip6t_standard) * 2,
-	[NF_IP6_LOCAL_OUT] 	= sizeof(struct ip6t_standard) * 3,
-	[NF_IP6_POST_ROUTING]	= sizeof(struct ip6t_standard) * 4},
-      { [NF_IP6_PRE_ROUTING] 	= 0,
-	[NF_IP6_LOCAL_IN]	= sizeof(struct ip6t_standard),
-	[NF_IP6_FORWARD]	= sizeof(struct ip6t_standard) * 2,
-	[NF_IP6_LOCAL_OUT] 	= sizeof(struct ip6t_standard) * 3,
-	[NF_IP6_POST_ROUTING]	= sizeof(struct ip6t_standard) * 4},
-      0, NULL, { } },
-    {
-	    /* PRE_ROUTING */
-	    { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
-		0,
-		sizeof(struct ip6t_entry),
-		sizeof(struct ip6t_standard),
-		0, { 0, 0 }, { } },
-	      { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
-		-NF_ACCEPT - 1 } },
-	    /* LOCAL_IN */
-	    { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
-		0,
-		sizeof(struct ip6t_entry),
-		sizeof(struct ip6t_standard),
-		0, { 0, 0 }, { } },
-	      { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
-		-NF_ACCEPT - 1 } },
-	    /* FORWARD */
-	    { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
-		0,
-		sizeof(struct ip6t_entry),
-		sizeof(struct ip6t_standard),
-		0, { 0, 0 }, { } },
-	      { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
-		-NF_ACCEPT - 1 } },
-	    /* LOCAL_OUT */
-	    { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
-		0,
-		sizeof(struct ip6t_entry),
-		sizeof(struct ip6t_standard),
-		0, { 0, 0 }, { } },
-	      { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
-		-NF_ACCEPT - 1 } },
-	    /* POST_ROUTING */
-	    { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
-		0,
-		sizeof(struct ip6t_entry),
-		sizeof(struct ip6t_standard),
-		0, { 0, 0 }, { } },
-	      { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
-		-NF_ACCEPT - 1 } }
-    },
-    /* ERROR */
-    { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
-	0,
-	sizeof(struct ip6t_entry),
-	sizeof(struct ip6t_error),
-	0, { 0, 0 }, { } },
-      { { { { IP6T_ALIGN(sizeof(struct ip6t_error_target)), IP6T_ERROR_TARGET } },
-	  { } },
-	"ERROR"
-      }
-    }
+} initial_table __initdata = {
+	.repl = {
+		.name = "mangle",
+		.valid_hooks = MANGLE_VALID_HOOKS,
+		.num_entries = 6,
+		.size = sizeof(struct ip6t_standard) * 5 + sizeof(struct ip6t_error),
+		.hook_entry = {
+			[NF_IP6_PRE_ROUTING] 	= 0,
+			[NF_IP6_LOCAL_IN]	= sizeof(struct ip6t_standard),
+			[NF_IP6_FORWARD]	= sizeof(struct ip6t_standard) * 2,
+			[NF_IP6_LOCAL_OUT] 	= sizeof(struct ip6t_standard) * 3,
+			[NF_IP6_POST_ROUTING]	= sizeof(struct ip6t_standard) * 4,
+		},
+		.underflow = {
+			[NF_IP6_PRE_ROUTING] 	= 0,
+			[NF_IP6_LOCAL_IN]	= sizeof(struct ip6t_standard),
+			[NF_IP6_FORWARD]	= sizeof(struct ip6t_standard) * 2,
+			[NF_IP6_LOCAL_OUT] 	= sizeof(struct ip6t_standard) * 3,
+			[NF_IP6_POST_ROUTING]	= sizeof(struct ip6t_standard) * 4,
+		},
+	},
+	.entries = {
+		IP6T_STANDARD_INIT(NF_ACCEPT),	/* PRE_ROUTING */
+		IP6T_STANDARD_INIT(NF_ACCEPT),	/* LOCAL_IN */
+		IP6T_STANDARD_INIT(NF_ACCEPT),	/* FORWARD */
+		IP6T_STANDARD_INIT(NF_ACCEPT),	/* LOCAL_OUT */
+		IP6T_STANDARD_INIT(NF_ACCEPT),	/* POST_ROUTING */
+	},
+	.term = IP6T_ERROR_INIT,		/* ERROR */
 };
 
 static struct xt_table packet_mangler = {
diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c
index a3eb5b8..0acda45 100644
--- a/net/ipv6/netfilter/ip6table_raw.c
+++ b/net/ipv6/netfilter/ip6table_raw.c
@@ -35,56 +35,10 @@
 		},
 	},
 	.entries = {
-		/* PRE_ROUTING */
-		{
-			.entry = {
-				.target_offset = sizeof(struct ip6t_entry),
-				.next_offset = sizeof(struct ip6t_standard),
-			},
-			.target = {
-				.target = {
-					.u = {
-						.target_size = IP6T_ALIGN(sizeof(struct ip6t_standard_target)),
-					},
-				},
-				.verdict = -NF_ACCEPT - 1,
-			},
-		},
-
-		/* LOCAL_OUT */
-		{
-			.entry = {
-				.target_offset = sizeof(struct ip6t_entry),
-				.next_offset = sizeof(struct ip6t_standard),
-			},
-			.target = {
-				.target = {
-					.u = {
-						.target_size = IP6T_ALIGN(sizeof(struct ip6t_standard_target)),
-					},
-				},
-				.verdict = -NF_ACCEPT - 1,
-			},
-		},
+		IP6T_STANDARD_INIT(NF_ACCEPT),	/* PRE_ROUTING */
+		IP6T_STANDARD_INIT(NF_ACCEPT),	/* LOCAL_OUT */
 	},
-	/* ERROR */
-	.term = {
-		.entry = {
-			.target_offset = sizeof(struct ip6t_entry),
-			.next_offset = sizeof(struct ip6t_error),
-		},
-		.target = {
-			.target = {
-				.u = {
-					.user = {
-						.target_size = IP6T_ALIGN(sizeof(struct ip6t_error_target)),
-						.name = IP6T_ERROR_TARGET,
-					},
-				},
-			},
-			.errorname = "ERROR",
-		},
-	}
+	.term = IP6T_ERROR_INIT,		/* ERROR */
 };
 
 static struct xt_table packet_raw = {
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index b083c09..a7ae59c 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -52,9 +52,28 @@
 
 DEFINE_SNMP_STAT(struct udp_mib, udp_stats_in6) __read_mostly;
 
+static int ipv6_rcv_saddr_any(const struct sock *sk)
+{
+	struct ipv6_pinfo *np = inet6_sk(sk);
+
+	return ipv6_addr_any(&np->rcv_saddr);
+}
+
+static unsigned int ipv6_hash_port_and_rcv_saddr(__u16 port,
+						 const struct sock *sk)
+{
+	return port;
+}
+
+const struct udp_get_port_ops udp_ipv6_ops = {
+	.saddr_cmp = ipv6_rcv_saddr_equal,
+	.saddr_any = ipv6_rcv_saddr_any,
+	.hash_port_and_rcv_saddr = ipv6_hash_port_and_rcv_saddr,
+};
+
 static inline int udp_v6_get_port(struct sock *sk, unsigned short snum)
 {
-	return udp_get_port(sk, snum, ipv6_rcv_saddr_equal);
+	return udp_get_port(sk, snum, &udp_ipv6_ops);
 }
 
 static struct sock *__udp6_lib_lookup(struct in6_addr *saddr, __be16 sport,
diff --git a/net/ipv6/udp_impl.h b/net/ipv6/udp_impl.h
index 6e252f3..36b0c11 100644
--- a/net/ipv6/udp_impl.h
+++ b/net/ipv6/udp_impl.h
@@ -6,6 +6,8 @@
 #include <net/addrconf.h>
 #include <net/inet_common.h>
 
+extern const struct udp_get_port_ops udp_ipv6_ops;
+
 extern int  	__udp6_lib_rcv(struct sk_buff **, struct hlist_head [], int );
 extern void 	__udp6_lib_err(struct sk_buff *, struct inet6_skb_parm *,
 			       int , int , int , __be32 , struct hlist_head []);
diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c
index f54016a..c40a513 100644
--- a/net/ipv6/udplite.c
+++ b/net/ipv6/udplite.c
@@ -37,7 +37,7 @@
 
 static int udplite_v6_get_port(struct sock *sk, unsigned short snum)
 {
-	return udplite_get_port(sk, snum, ipv6_rcv_saddr_equal);
+	return udplite_get_port(sk, snum, &udp_ipv6_ops);
 }
 
 struct proto udplitev6_prot = {
diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c
index 822917d..3e07e9d 100644
--- a/net/mac80211/ieee80211_sta.c
+++ b/net/mac80211/ieee80211_sta.c
@@ -17,6 +17,7 @@
  * scan result table filtering (by capability (privacy, IBSS/BSS, WPA/RSN IE,
  *    SSID)
  */
+#include <linux/delay.h>
 #include <linux/if_ether.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
@@ -27,7 +28,6 @@
 #include <linux/rtnetlink.h>
 #include <net/iw_handler.h>
 #include <asm/types.h>
-#include <asm/delay.h>
 
 #include <net/mac80211.h>
 #include "ieee80211_i.h"
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index e132c8a..e8b5c2d 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -299,7 +299,6 @@
 {
 	struct nf_conn *ct = (struct nf_conn *)nfct;
 	struct nf_conn_help *help = nfct_help(ct);
-	struct nf_conntrack_l3proto *l3proto;
 	struct nf_conntrack_l4proto *l4proto;
 	typeof(nf_conntrack_destroyed) destroyed;
 
@@ -317,10 +316,6 @@
 	 * destroy_conntrack() MUST NOT be called with a write lock
 	 * to nf_conntrack_lock!!! -HW */
 	rcu_read_lock();
-	l3proto = __nf_ct_l3proto_find(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.l3num);
-	if (l3proto && l3proto->destroy)
-		l3proto->destroy(ct);
-
 	l4proto = __nf_ct_l4proto_find(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.l3num,
 				       ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum);
 	if (l4proto && l4proto->destroy)
@@ -893,8 +888,13 @@
 	NF_CT_DUMP_TUPLE(newreply);
 
 	ct->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply;
-	if (!ct->master && help && help->expecting == 0)
-		help->helper = __nf_ct_helper_find(newreply);
+	if (!ct->master && help && help->expecting == 0) {
+		struct nf_conntrack_helper *helper;
+		helper = __nf_ct_helper_find(newreply);
+		if (helper)
+			memset(&help->help, 0, sizeof(help->help));
+		help->helper = helper;
+	}
 	write_unlock_bh(&nf_conntrack_lock);
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_alter_reply);
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index aa1a97ee..d6d39e2 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -830,11 +830,6 @@
 	char *helpname;
 	int err;
 
-	if (!help) {
-		/* FIXME: we need to reallocate and rehash */
-		return -EBUSY;
-	}
-
 	/* don't change helper of sibling connections */
 	if (ct->master)
 		return -EINVAL;
@@ -843,25 +838,34 @@
 	if (err < 0)
 		return err;
 
-	helper = __nf_conntrack_helper_find_byname(helpname);
-	if (!helper) {
-		if (!strcmp(helpname, ""))
-			helper = NULL;
-		else
-			return -EINVAL;
-	}
-
-	if (help->helper) {
-		if (!helper) {
+	if (!strcmp(helpname, "")) {
+		if (help && help->helper) {
 			/* we had a helper before ... */
 			nf_ct_remove_expectations(ct);
 			help->helper = NULL;
-		} else {
-			/* need to zero data of old helper */
-			memset(&help->help, 0, sizeof(help->help));
 		}
+
+		return 0;
 	}
 
+	if (!help) {
+		/* FIXME: we need to reallocate and rehash */
+		return -EBUSY;
+	}
+
+	helper = __nf_conntrack_helper_find_byname(helpname);
+	if (helper == NULL)
+		return -EINVAL;
+
+	if (help->helper == helper)
+		return 0;
+
+	if (help->helper)
+		/* we had a helper before ... */
+		nf_ct_remove_expectations(ct);
+
+	/* need to zero data of old helper */
+	memset(&help->help, 0, sizeof(help->help));
 	help->helper = helper;
 
 	return 0;
diff --git a/net/netfilter/xt_conntrack.c b/net/netfilter/xt_conntrack.c
index f4ea8fe..189ded5 100644
--- a/net/netfilter/xt_conntrack.c
+++ b/net/netfilter/xt_conntrack.c
@@ -134,12 +134,66 @@
 	nf_ct_l3proto_module_put(match->family);
 }
 
+#ifdef CONFIG_COMPAT
+struct compat_xt_conntrack_info
+{
+	compat_uint_t			statemask;
+	compat_uint_t			statusmask;
+	struct ip_conntrack_old_tuple	tuple[IP_CT_DIR_MAX];
+	struct in_addr			sipmsk[IP_CT_DIR_MAX];
+	struct in_addr			dipmsk[IP_CT_DIR_MAX];
+	compat_ulong_t			expires_min;
+	compat_ulong_t			expires_max;
+	u_int8_t			flags;
+	u_int8_t			invflags;
+};
+
+static void compat_from_user(void *dst, void *src)
+{
+	struct compat_xt_conntrack_info *cm = src;
+	struct xt_conntrack_info m = {
+		.statemask	= cm->statemask,
+		.statusmask	= cm->statusmask,
+		.expires_min	= cm->expires_min,
+		.expires_max	= cm->expires_max,
+		.flags		= cm->flags,
+		.invflags	= cm->invflags,
+	};
+	memcpy(m.tuple, cm->tuple, sizeof(m.tuple));
+	memcpy(m.sipmsk, cm->sipmsk, sizeof(m.sipmsk));
+	memcpy(m.dipmsk, cm->dipmsk, sizeof(m.dipmsk));
+	memcpy(dst, &m, sizeof(m));
+}
+
+static int compat_to_user(void __user *dst, void *src)
+{
+	struct xt_conntrack_info *m = src;
+	struct compat_xt_conntrack_info cm = {
+		.statemask	= m->statemask,
+		.statusmask	= m->statusmask,
+		.expires_min	= m->expires_min,
+		.expires_max	= m->expires_max,
+		.flags		= m->flags,
+		.invflags	= m->invflags,
+	};
+	memcpy(cm.tuple, m->tuple, sizeof(cm.tuple));
+	memcpy(cm.sipmsk, m->sipmsk, sizeof(cm.sipmsk));
+	memcpy(cm.dipmsk, m->dipmsk, sizeof(cm.dipmsk));
+	return copy_to_user(dst, &cm, sizeof(cm)) ? -EFAULT : 0;
+}
+#endif
+
 static struct xt_match conntrack_match = {
 	.name		= "conntrack",
 	.match		= match,
 	.checkentry	= checkentry,
 	.destroy	= destroy,
 	.matchsize	= sizeof(struct xt_conntrack_info),
+#ifdef CONFIG_COMPAT
+	.compatsize	= sizeof(struct compat_xt_conntrack_info),
+	.compat_from_user = compat_from_user,
+	.compat_to_user	= compat_to_user,
+#endif
 	.family		= AF_INET,
 	.me		= THIS_MODULE,
 };
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 3385ee5..f28bb2d 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -71,12 +71,9 @@
 
 
 /* Kick device.
-   Note, that this procedure can be called by a watchdog timer, so that
-   we do not check dev->tbusy flag here.
 
-   Returns:  0  - queue is empty.
-	    >0  - queue is not empty, but throttled.
-	    <0  - queue is not empty. Device is throttled, if dev->tbusy != 0.
+   Returns:  0  - queue is empty or throttled.
+	    >0  - queue is not empty.
 
    NOTE: Called under dev->queue_lock with locally disabled BH.
 */
@@ -115,7 +112,7 @@
 					kfree_skb(skb);
 					if (net_ratelimit())
 						printk(KERN_DEBUG "Dead loop on netdevice %s, fix it urgently!\n", dev->name);
-					return -1;
+					goto out;
 				}
 				__get_cpu_var(netdev_rx_stat).cpu_collision++;
 				goto requeue;
@@ -135,10 +132,12 @@
 						netif_tx_unlock(dev);
 					}
 					spin_lock(&dev->queue_lock);
-					return -1;
+					q = dev->qdisc;
+					goto out;
 				}
 				if (ret == NETDEV_TX_LOCKED && nolock) {
 					spin_lock(&dev->queue_lock);
+					q = dev->qdisc;
 					goto collision;
 				}
 			}
@@ -163,26 +162,28 @@
 		 */
 
 requeue:
-		if (skb->next)
+		if (unlikely(q == &noop_qdisc))
+			kfree_skb(skb);
+		else if (skb->next)
 			dev->gso_skb = skb;
 		else
 			q->ops->requeue(skb, q);
 		netif_schedule(dev);
-		return 1;
+		return 0;
 	}
+
+out:
 	BUG_ON((int) q->q.qlen < 0);
 	return q->q.qlen;
 }
 
 void __qdisc_run(struct net_device *dev)
 {
-	if (unlikely(dev->qdisc == &noop_qdisc))
-		goto out;
+	do {
+		if (!qdisc_restart(dev))
+			break;
+	} while (!netif_queue_stopped(dev));
 
-	while (qdisc_restart(dev) < 0 && !netif_queue_stopped(dev))
-		/* NOTHING */;
-
-out:
 	clear_bit(__LINK_STATE_QDISC_RUNNING, &dev->state);
 }
 
@@ -544,6 +545,7 @@
 void dev_deactivate(struct net_device *dev)
 {
 	struct Qdisc *qdisc;
+	struct sk_buff *skb;
 
 	spin_lock_bh(&dev->queue_lock);
 	qdisc = dev->qdisc;
@@ -551,8 +553,12 @@
 
 	qdisc_reset(qdisc);
 
+	skb = dev->gso_skb;
+	dev->gso_skb = NULL;
 	spin_unlock_bh(&dev->queue_lock);
 
+	kfree_skb(skb);
+
 	dev_watchdog_down(dev);
 
 	/* Wait for outstanding dev_queue_xmit calls. */
@@ -561,11 +567,6 @@
 	/* Wait for outstanding qdisc_run calls. */
 	while (test_bit(__LINK_STATE_QDISC_RUNNING, &dev->state))
 		yield();
-
-	if (dev->gso_skb) {
-		kfree_skb(dev->gso_skb);
-		dev->gso_skb = NULL;
-	}
 }
 
 void dev_init_scheduler(struct net_device *dev)
diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c
index d24914d..f05ad9a 100644
--- a/net/sched/sch_teql.c
+++ b/net/sched/sch_teql.c
@@ -94,14 +94,13 @@
 	struct net_device *dev = sch->dev;
 	struct teql_sched_data *q = qdisc_priv(sch);
 
-	__skb_queue_tail(&q->q, skb);
-	if (q->q.qlen <= dev->tx_queue_len) {
+	if (q->q.qlen < dev->tx_queue_len) {
+		__skb_queue_tail(&q->q, skb);
 		sch->bstats.bytes += skb->len;
 		sch->bstats.packets++;
 		return 0;
 	}
 
-	__skb_unlink(skb, &q->q);
 	kfree_skb(skb);
 	sch->qstats.drops++;
 	return NET_XMIT_DROP;
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 83a76ba..4dcdabf 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -4164,6 +4164,7 @@
 	rwlock_t *addr_lock;
 	int err = 0;
 	void *addrs;
+	void *buf;
 	int bytes_copied = 0;
 
 	if (len != sizeof(struct sctp_getaddrs_old))
@@ -4217,13 +4218,14 @@
 		}
 	}
 
+	buf = addrs;
 	list_for_each(pos, &bp->address_list) {
 		addr = list_entry(pos, struct sctp_sockaddr_entry, list);
 		memcpy(&temp, &addr->a, sizeof(temp));
 		sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp);
 		addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
-		memcpy(addrs, &temp, addrlen);
-		to += addrlen;
+		memcpy(buf, &temp, addrlen);
+		buf += addrlen;
 		bytes_copied += addrlen;
 		cnt ++;
 		if (cnt >= getaddrs.addr_num) break;
@@ -4266,6 +4268,7 @@
 	size_t space_left;
 	int bytes_copied = 0;
 	void *addrs;
+	void *buf;
 
 	if (len <= sizeof(struct sctp_getaddrs))
 		return -EINVAL;
@@ -4316,6 +4319,7 @@
 		}
 	}
 
+	buf = addrs;
 	list_for_each(pos, &bp->address_list) {
 		addr = list_entry(pos, struct sctp_sockaddr_entry, list);
 		memcpy(&temp, &addr->a, sizeof(temp));
@@ -4325,8 +4329,8 @@
 			err =  -ENOMEM; /*fixme: right error?*/
 			goto error;
 		}
-		memcpy(addrs, &temp, addrlen);
-		to += addrlen;
+		memcpy(buf, &temp, addrlen);
+		buf += addrlen;
 		bytes_copied += addrlen;
 		cnt ++;
 		space_left -= addrlen;
@@ -5227,7 +5231,12 @@
 	/* Allocate HMAC for generating cookie. */
 	if (sctp_hmac_alg) {
 		tfm = crypto_alloc_hash(sctp_hmac_alg, 0, CRYPTO_ALG_ASYNC);
-		if (!tfm) {
+		if (IS_ERR(tfm)) {
+			if (net_ratelimit()) {
+				printk(KERN_INFO
+				       "SCTP: failed to load transform for %s: %ld\n",
+					sctp_hmac_alg, PTR_ERR(tfm));
+			}
 			err = -ENOSYS;
 			goto out;
 		}
diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
index 661ea2d..bfecb35 100644
--- a/net/sctp/ulpevent.c
+++ b/net/sctp/ulpevent.c
@@ -141,11 +141,6 @@
 	 * an ABORT, so we need to include it in the sac_info.
 	 */
 	if (chunk) {
-		/* sctp_inqu_pop() has allready pulled off the chunk
-		 * header.  We need to put it back temporarily
-		 */
-		skb_push(chunk->skb, sizeof(sctp_chunkhdr_t));
-
 		/* Copy the chunk data to a new skb and reserve enough
 		 * head room to use as notification.
 		 */
@@ -155,9 +150,6 @@
 		if (!skb)
 			goto fail;
 
-		/* put back the chunk header now that we have a copy */
-		skb_pull(chunk->skb, sizeof(sctp_chunkhdr_t));
-
 		/* Embed the event fields inside the cloned skb.  */
 		event = sctp_skb2event(skb);
 		sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize);
@@ -168,7 +160,8 @@
 
 		/* Trim the buffer to the right length.  */
 		skb_trim(skb, sizeof(struct sctp_assoc_change) +
-			 ntohs(chunk->chunk_hdr->length));
+			 ntohs(chunk->chunk_hdr->length) -
+			 sizeof(sctp_chunkhdr_t));
 	} else {
 		event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change),
 				  MSG_NOTIFICATION, gfp);