diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/alpha/config.in linux-2.4.27-leo/arch/alpha/config.in
--- linux-2.4.27/arch/alpha/config.in	2004-02-20 14:11:37.000000000 +0000
+++ linux-2.4.27-leo/arch/alpha/config.in	2004-09-17 03:19:57.000000000 +0100
@@ -468,3 +468,12 @@
 
 source crypto/Config.in
 source lib/Config.in
+
+mainmenu_option next_comment
+comment 'Grsecurity'
+bool 'Grsecurity' CONFIG_GRKERNSEC
+if [ "$CONFIG_GRKERNSEC" = "y" ]; then
+	source grsecurity/Config.in
+fi
+endmenu
+
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/alpha/kernel/osf_sys.c linux-2.4.27-leo/arch/alpha/kernel/osf_sys.c
--- linux-2.4.27/arch/alpha/kernel/osf_sys.c	2003-06-13 15:51:29.000000000 +0100
+++ linux-2.4.27-leo/arch/alpha/kernel/osf_sys.c	2004-09-17 03:19:57.000000000 +0100
@@ -33,6 +33,7 @@
 #include <linux/file.h>
 #include <linux/types.h>
 #include <linux/ipc.h>
+#include <linux/grsecurity.h>
 
 #include <asm/fpu.h>
 #include <asm/io.h>
@@ -230,6 +231,11 @@
 	struct file *file = NULL;
 	unsigned long ret = -EBADF;
 
+#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC
+	if (flags & MAP_MIRROR)
+		return -EINVAL;
+#endif
+
 #if 0
 	if (flags & (_MAP_HASSEMAPHORE | _MAP_INHERIT | _MAP_UNALIGNED))
 		printk("%s: unimplemented OSF mmap flags %04lx\n", 
@@ -240,6 +246,13 @@
 		if (!file)
 			goto out;
 	}
+
+	if(gr_handle_mmap(file, prot)) {
+		fput(file);
+		ret = -EACCES;
+		goto out;
+	}
+
 	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 	down_write(&current->mm->mmap_sem);
 	ret = do_mmap(file, addr, len, prot, flags, off);
@@ -1357,6 +1370,10 @@
 	   merely specific addresses, but regions of memory -- perhaps
 	   this feature should be incorporated into all ports?  */
 
+#ifdef CONFIG_GRKERNSEC_PAX_RANDMMAP
+	if (!(current->flags & PF_PAX_RANDMMAP) || !filp)
+#endif
+
 	if (addr) {
 		addr = arch_get_unmapped_area_1 (PAGE_ALIGN(addr), len, limit);
 		if (addr != -ENOMEM)
@@ -1364,8 +1381,15 @@
 	}
 
 	/* Next, try allocating at TASK_UNMAPPED_BASE.  */
-	addr = arch_get_unmapped_area_1 (PAGE_ALIGN(TASK_UNMAPPED_BASE),
-					 len, limit);
+
+	addr = TASK_UNMAPPED_BASE;
+
+#ifdef CONFIG_GRKERNSEC_PAX_RANDMMAP
+	if (current->flags & PF_PAX_RANDMMAP)
+		addr += current->mm->delta_mmap;
+#endif
+
+	addr = arch_get_unmapped_area_1 (PAGE_ALIGN(addr), len, limit);
 	if (addr != -ENOMEM)
 		return addr;
 
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/alpha/kernel/process.c linux-2.4.27-leo/arch/alpha/kernel/process.c
--- linux-2.4.27/arch/alpha/kernel/process.c	2003-08-25 12:44:39.000000000 +0100
+++ linux-2.4.27-leo/arch/alpha/kernel/process.c	2004-09-17 03:19:36.000000000 +0100
@@ -186,6 +186,7 @@
 	args.mode = mode;
 	args.restart_cmd = restart_cmd;
 #ifdef CONFIG_SMP
+	preempt_disable();
 	smp_call_function(common_shutdown_1, &args, 1, 0);
 #endif
 	common_shutdown_1(&args);
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/alpha/kernel/ptrace.c linux-2.4.27-leo/arch/alpha/kernel/ptrace.c
--- linux-2.4.27/arch/alpha/kernel/ptrace.c	2003-06-13 15:51:29.000000000 +0100
+++ linux-2.4.27-leo/arch/alpha/kernel/ptrace.c	2004-09-17 03:19:57.000000000 +0100
@@ -13,6 +13,7 @@
 #include <linux/ptrace.h>
 #include <linux/user.h>
 #include <linux/slab.h>
+#include <linux/grsecurity.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -275,6 +276,10 @@
 	read_unlock(&tasklist_lock);
 	if (!child)
 		goto out_notsk;
+
+	if(gr_handle_ptrace(child, request))
+		goto out;
+
 	if (request == PTRACE_ATTACH) {
 		ret = ptrace_attach(child);
 		goto out;
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/alpha/mm/fault.c linux-2.4.27-leo/arch/alpha/mm/fault.c
--- linux-2.4.27/arch/alpha/mm/fault.c	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.27-leo/arch/alpha/mm/fault.c	2004-09-17 03:19:57.000000000 +0100
@@ -53,6 +53,139 @@
 	__reload_thread(&current->thread);
 }
 
+/*
+ * PaX: decide what to do with offenders (regs->pc = fault address)
+ *
+ * returns 1 when task should be killed
+ *         2 when patched PLT trampoline was detected
+ *         3 when unpatched PLT trampoline was detected
+ *	   4 when legitimate ET_EXEC was detected
+ */
+#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC
+static int pax_handle_fetch_fault(struct pt_regs *regs)
+{
+	int err;
+
+#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC
+	if (current->flags & PF_PAX_RANDEXEC) {
+		if (regs->pc >= current->mm->start_code &&
+		    regs->pc < current->mm->end_code)
+		{
+			if (regs->r26 == regs->pc)
+				return 1;
+			regs->pc += current->mm->delta_exec;
+			return 4;
+		}
+	}
+#endif
+
+#ifdef CONFIG_GRKERNSEC_PAX_EMUPLT
+	do { /* PaX: patched PLT emulation #1 */
+		unsigned int ldah, ldq, jmp;
+
+		err = get_user(ldah, (unsigned int *)regs->pc);
+		err |= get_user(ldq, (unsigned int *)(regs->pc+4));
+		err |= get_user(jmp, (unsigned int *)(regs->pc+8));
+
+		if (err)
+			break;
+
+		if ((ldah & 0xFFFF0000U)== 0x277B0000U &&
+		    (ldq & 0xFFFF0000U) == 0xA77B0000U &&
+		    jmp == 0x6BFB0000U)
+		{
+			unsigned long r27, addr;
+			unsigned long addrh = (ldah | 0xFFFFFFFFFFFF0000UL) << 16;
+			unsigned long addrl = ldq | 0xFFFFFFFFFFFF0000UL;
+
+			addr = regs->r27 + ((addrh ^ 0x80000000UL) + 0x80000000UL) + ((addrl ^ 0x8000UL) + 0x8000UL);
+			err = get_user(r27, (unsigned long*)addr);
+			if (err)
+				break;
+
+			regs->r27 = r27;
+			regs->pc = r27;
+			return 2;
+		}
+	} while (0);
+
+	do { /* PaX: patched PLT emulation #2 */
+		unsigned int ldah, lda, br;
+
+		err = get_user(ldah, (unsigned int *)regs->pc);
+		err |= get_user(lda, (unsigned int *)(regs->pc+4));
+		err |= get_user(br, (unsigned int *)(regs->pc+8));
+
+		if (err)
+			break;
+
+		if ((ldah & 0xFFFF0000U)== 0x277B0000U &&
+		    (lda & 0xFFFF0000U) == 0xA77B0000U &&
+		    (br & 0xFFE00000U) == 0xC3E00000U)
+		{
+			unsigned long addr = br | 0xFFFFFFFFFFE00000UL;
+			unsigned long addrh = (ldah | 0xFFFFFFFFFFFF0000UL) << 16;
+			unsigned long addrl = lda | 0xFFFFFFFFFFFF0000UL;
+
+			regs->r27 += ((addrh ^ 0x80000000UL) + 0x80000000UL) + ((addrl ^ 0x8000UL) + 0x8000UL);
+			regs->pc += 12 + (((addr ^ 0x00100000UL) + 0x00100000UL) << 2);
+			return 2;
+		}
+	} while (0);
+
+	do { /* PaX: unpatched PLT emulation */
+		unsigned int br;
+
+		err = get_user(br, (unsigned int *)regs->pc);
+
+		if (!err && (br & 0xFFE00000U) == 0xC3800000U) {
+			unsigned int br2, ldq, nop, jmp;
+			unsigned long addr = br | 0xFFFFFFFFFFE00000UL, resolver;
+
+			addr = regs->pc + 4 + (((addr ^ 0x00100000UL) + 0x00100000UL) << 2);
+			err = get_user(br2, (unsigned int *)addr);  
+			err |= get_user(ldq, (unsigned int *)(addr+4));
+			err |= get_user(nop, (unsigned int *)(addr+8));
+			err |= get_user(jmp, (unsigned int *)(addr+12));
+			err |= get_user(resolver, (unsigned long *)(addr+16));
+
+			if (err)
+				break;
+
+			if (br2 == 0xC3600000U &&
+			    ldq == 0xA77B000CU &&
+			    nop == 0x47FF041FU &&
+			    jmp == 0x6B7B0000U)
+			{
+				regs->r28 = regs->pc+4;
+				regs->r27 = addr+16;
+				regs->pc = resolver;
+				return 3;
+			}
+		}
+	} while (0);
+#endif
+
+	return 1;
+}
+
+void pax_report_insns(void *pc)
+{
+	unsigned long i;
+
+	printk(KERN_ERR "PAX: bytes at PC: ");
+	for (i = 0; i < 5; i++) {
+		unsigned int c;
+		if (get_user(c, (unsigned int*)pc+i)) {
+			printk("<invalid address>.");
+			break;
+		}
+		printk("%08x ", c);
+	}
+	printk("\n");
+}
+#endif
+
 
 /*
  * This routine handles page faults.  It determines the address,
@@ -133,8 +266,32 @@
 good_area:
 	info.si_code = SEGV_ACCERR;
 	if (cause < 0) {
-		if (!(vma->vm_flags & VM_EXEC))
+		if (!(vma->vm_flags & VM_EXEC)) {
+
+#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC
+			if (!(current->flags & PF_PAX_PAGEEXEC) || address != regs->pc)
+				goto bad_area;
+
+			up_read(&mm->mmap_sem);
+			switch(pax_handle_fetch_fault(regs)) {
+
+#ifdef CONFIG_GRKERNSEC_PAX_EMUPLT
+			case 2:
+			case 3:
+				return;
+#endif
+
+#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC
+			case 4:
+				return;
+#endif
+			}
+			pax_report_fault(regs, (void*)regs->pc, (void*)rdusp());
+			do_exit(SIGKILL);
+#else
 			goto bad_area;
+#endif
+		}
 	} else if (!cause) {
 		/* Allow reads even for write-only mappings */
 		if (!(vma->vm_flags & (VM_READ | VM_WRITE)))
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/arm/config.in linux-2.4.27-leo/arch/arm/config.in
--- linux-2.4.27/arch/arm/config.in	2004-02-20 14:11:37.000000000 +0000
+++ linux-2.4.27-leo/arch/arm/config.in	2004-09-17 03:19:57.000000000 +0100
@@ -736,3 +736,11 @@
 
 source crypto/Config.in
 source lib/Config.in
+
+mainmenu_option next_comment
+comment 'Grsecurity'
+bool 'Grsecurity' CONFIG_GRKERNSEC
+if [ "$CONFIG_GRKERNSEC" = "y" ]; then
+	source grsecurity/Config.in
+fi
+endmenu
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/cris/config.in linux-2.4.27-leo/arch/cris/config.in
--- linux-2.4.27/arch/cris/config.in	2004-02-20 14:11:37.000000000 +0000
+++ linux-2.4.27-leo/arch/cris/config.in	2004-09-17 03:19:57.000000000 +0100
@@ -276,3 +276,12 @@
 source crypto/Config.in
 source lib/Config.in
 endmenu
+
+mainmenu_option next_comment
+comment 'Grsecurity'
+bool 'Grsecurity' CONFIG_GRKERNSEC
+if [ "$CONFIG_GRKERNSEC" = "y" ]; then
+    source grsecurity/Config.in
+fi
+endmenu
+
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/i386/boot/bootsect.S linux-2.4.27-leo/arch/i386/boot/bootsect.S
--- linux-2.4.27/arch/i386/boot/bootsect.S	2003-08-25 12:44:39.000000000 +0100
+++ linux-2.4.27-leo/arch/i386/boot/bootsect.S	2004-09-17 03:19:57.000000000 +0100
@@ -237,7 +237,7 @@
 #ifdef __BIG_KERNEL__
 					# look in setup.S for bootsect_kludge
 	bootsect_kludge = 0x220		# 0x200 + 0x20 which is the size of the
-	lcall	bootsect_kludge		# bootsector + bootsect_kludge offset
+	lcall	*bootsect_kludge	# bootsector + bootsect_kludge offset
 #else
 	movw	%es, %ax
 	subw	$SYSSEG, %ax
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/i386/boot/setup.S linux-2.4.27-leo/arch/i386/boot/setup.S
--- linux-2.4.27/arch/i386/boot/setup.S	2004-02-20 14:11:37.000000000 +0000
+++ linux-2.4.27-leo/arch/i386/boot/setup.S	2004-09-17 03:19:57.000000000 +0100
@@ -637,7 +637,7 @@
 	cmpw	$0, %cs:realmode_swtch
 	jz	rmodeswtch_normal
 
-	lcall	%cs:realmode_swtch
+	lcall	*%cs:realmode_swtch
 
 	jmp	rmodeswtch_end
 
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/i386/config.in linux-2.4.27-leo/arch/i386/config.in
--- linux-2.4.27/arch/i386/config.in	2004-02-20 14:11:37.000000000 +0000
+++ linux-2.4.27-leo/arch/i386/config.in	2004-09-17 03:19:57.000000000 +0100
@@ -99,6 +99,7 @@
 fi
 if [ "$CONFIG_M686" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
+   define_bool CONFIG_X86_ALIGNMENT_16 y
    define_bool CONFIG_X86_HAS_TSC y
    define_bool CONFIG_X86_GOOD_APIC y
    bool 'PGE extensions (not for Cyrix/Transmeta)' CONFIG_X86_PGE
@@ -108,6 +109,7 @@
 fi
 if [ "$CONFIG_MPENTIUMIII" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
+   define_bool CONFIG_X86_ALIGNMENT_16 y
    define_bool CONFIG_X86_HAS_TSC y
    define_bool CONFIG_X86_GOOD_APIC y
    define_bool CONFIG_X86_PGE y
@@ -116,6 +118,7 @@
 fi
 if [ "$CONFIG_MPENTIUM4" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 7
+   define_bool CONFIG_X86_ALIGNMENT_16 y
    define_bool CONFIG_X86_HAS_TSC y
    define_bool CONFIG_X86_GOOD_APIC y
    define_bool CONFIG_X86_PGE y
@@ -135,6 +138,7 @@
 fi
 if [ "$CONFIG_MK7" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 6
+   define_bool CONFIG_X86_ALIGNMENT_16 y
    define_bool CONFIG_X86_HAS_TSC y
    define_bool CONFIG_X86_GOOD_APIC y
    define_bool CONFIG_X86_USE_3DNOW y
@@ -225,6 +229,7 @@
 bool 'Math emulation' CONFIG_MATH_EMULATION
 bool 'MTRR (Memory Type Range Register) support' CONFIG_MTRR
 bool 'Symmetric multi-processing support' CONFIG_SMP
+bool 'Preemptible Kernel' CONFIG_PREEMPT
 if [ "$CONFIG_SMP" != "y" ]; then
    bool 'Local APIC support on uniprocessors' CONFIG_X86_UP_APIC
    dep_bool 'IO-APIC support on uniprocessors' CONFIG_X86_UP_IOAPIC $CONFIG_X86_UP_APIC
@@ -258,9 +263,12 @@
    fi
 fi
 
-if [ "$CONFIG_SMP" = "y" -a "$CONFIG_X86_CMPXCHG" = "y" ]; then
-   define_bool CONFIG_HAVE_DEC_LOCK y
+if [ "$CONFIG_SMP" = "y" -o "$CONFIG_PREEMPT" = "y" ]; then
+   if [ "$CONFIG_X86_CMPXCHG" = "y" ]; then
+      define_bool CONFIG_HAVE_DEC_LOCK y
+   fi
 fi
+
 endmenu
 
 mainmenu_option next_comment
@@ -487,3 +495,11 @@
 
 source crypto/Config.in
 source lib/Config.in
+
+mainmenu_option next_comment
+comment 'Grsecurity'
+bool 'Grsecurity' CONFIG_GRKERNSEC
+if [ "$CONFIG_GRKERNSEC" = "y" ]; then
+	source grsecurity/Config.in
+fi
+endmenu
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/i386/kernel/apm.c linux-2.4.27-leo/arch/i386/kernel/apm.c
--- linux-2.4.27/arch/i386/kernel/apm.c	2003-08-25 12:44:39.000000000 +0100
+++ linux-2.4.27-leo/arch/i386/kernel/apm.c	2004-09-17 03:19:57.000000000 +0100
@@ -614,7 +614,7 @@
 	__asm__ __volatile__(APM_DO_ZERO_SEGS
 		"pushl %%edi\n\t"
 		"pushl %%ebp\n\t"
-		"lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry) "\n\t"
+		"lcall *%%ss:" SYMBOL_NAME_STR(apm_bios_entry) "\n\t"
 		"setc %%al\n\t"
 		"popl %%ebp\n\t"
 		"popl %%edi\n\t"
@@ -666,7 +666,7 @@
 		__asm__ __volatile__(APM_DO_ZERO_SEGS
 			"pushl %%edi\n\t"
 			"pushl %%ebp\n\t"
-			"lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry) "\n\t"
+			"lcall *%%ss:" SYMBOL_NAME_STR(apm_bios_entry) "\n\t"
 			"setc %%bl\n\t"
 			"popl %%ebp\n\t"
 			"popl %%edi\n\t"
@@ -1985,6 +1985,12 @@
 		 __va((unsigned long)0x40 << 4));
 	_set_limit((char *)&gdt[APM_40 >> 3], 4095 - (0x40 << 4));
 
+#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC
+	set_base(gdt2[APM_40 >> 3],
+		__va((unsigned long)0x40 << 4));
+	_set_limit((char *)&gdt2[APM_40 >> 3], 4095 - (0x40 << 4));
+#endif
+
 	apm_bios_entry.offset = apm_info.bios.offset;
 	apm_bios_entry.segment = APM_CS;
 	set_base(gdt[APM_CS >> 3],
@@ -1993,6 +1999,16 @@
 		 __va((unsigned long)apm_info.bios.cseg_16 << 4));
 	set_base(gdt[APM_DS >> 3],
 		 __va((unsigned long)apm_info.bios.dseg << 4));
+
+#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC
+	set_base(gdt2[APM_CS >> 3],
+		__va((unsigned long)apm_info.bios.cseg << 4));
+	set_base(gdt2[APM_CS_16 >> 3],
+		__va((unsigned long)apm_info.bios.cseg_16 << 4));
+	set_base(gdt2[APM_DS >> 3],
+		__va((unsigned long)apm_info.bios.dseg << 4));
+#endif
+
 #ifndef APM_RELAX_SEGMENTS
 	if (apm_info.bios.version == 0x100) {
 #endif
@@ -2002,6 +2018,13 @@
 		_set_limit((char *)&gdt[APM_CS_16 >> 3], 64 * 1024 - 1);
 		/* For the DEC Hinote Ultra CT475 (and others?) */
 		_set_limit((char *)&gdt[APM_DS >> 3], 64 * 1024 - 1);
+
+#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC
+		_set_limit((char *)&gdt2[APM_CS >> 3], 64 * 1024 - 1);
+		_set_limit((char *)&gdt2[APM_CS_16 >> 3], 64 * 1024 - 1);
+		_set_limit((char *)&gdt2[APM_DS >> 3], 64 * 1024 - 1);
+#endif
+
 #ifndef APM_RELAX_SEGMENTS
 	} else {
 		_set_limit((char *)&gdt[APM_CS >> 3],
@@ -2010,6 +2033,16 @@
 			(apm_info.bios.cseg_16_len - 1) & 0xffff);
 		_set_limit((char *)&gdt[APM_DS >> 3],
 			(apm_info.bios.dseg_len - 1) & 0xffff);
+
+#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC
+		_set_limit((char *)&gdt2[APM_CS >> 3],
+			(apm_info.bios.cseg_len - 1) & 0xffff);
+		_set_limit((char *)&gdt2[APM_CS_16 >> 3],
+			(apm_info.bios.cseg_16_len - 1) & 0xffff);
+		_set_limit((char *)&gdt2[APM_DS >> 3],
+			(apm_info.bios.dseg_len - 1) & 0xffff);
+#endif
+
 	}
 #endif
 
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/i386/kernel/cpuid.c linux-2.4.27-leo/arch/i386/kernel/cpuid.c
--- linux-2.4.27/arch/i386/kernel/cpuid.c	2001-10-11 17:04:57.000000000 +0100
+++ linux-2.4.27-leo/arch/i386/kernel/cpuid.c	2004-09-17 03:19:36.000000000 +0100
@@ -60,7 +60,8 @@
 static inline void do_cpuid(int cpu, u32 reg, u32 *data)
 {
   struct cpuid_command cmd;
-  
+
+  preempt_disable();
   if ( cpu == smp_processor_id() ) {
     cpuid(reg, &data[0], &data[1], &data[2], &data[3]);
   } else {
@@ -70,6 +71,7 @@
     
     smp_call_function(cpuid_smp_cpuid, &cmd, 1, 1);
   }
+  preempt_enable();
 }
 #else /* ! CONFIG_SMP */
 
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/i386/kernel/dmi_scan.c linux-2.4.27-leo/arch/i386/kernel/dmi_scan.c
--- linux-2.4.27/arch/i386/kernel/dmi_scan.c	2004-05-19 21:34:36.000000000 +0100
+++ linux-2.4.27-leo/arch/i386/kernel/dmi_scan.c	2004-09-20 21:34:47.000000000 +0100
@@ -15,6 +15,7 @@
 #include "pci-i386.h"
 
 unsigned long dmi_broken;
+int is_unsafe_smbus;
 int is_sony_vaio_laptop;
 
 struct dmi_header
@@ -371,6 +372,19 @@
 }		
 
 /*
+ * Don't access SMBus on IBM systems which get corrupted eeproms 
+ */
+
+static __init int disable_smbus(struct dmi_blacklist *d)
+{   
+	if (is_unsafe_smbus == 0) {
+		is_unsafe_smbus = 1;
+		printk(KERN_INFO "%s machine detected. Disabling SMBus accesses.\n", d->ident);
+	}
+	return 0;
+}
+
+/*
  * Check for a Sony Vaio system
  *
  * On a Sony system we want to enable the use of the sonypi
@@ -675,6 +689,10 @@
 			NO_MATCH, NO_MATCH,
 			} },
 
+	{ disable_smbus, "IBM", {
+			MATCH(DMI_SYS_VENDOR, "IBM"),
+			NO_MATCH, NO_MATCH, NO_MATCH
+			} },
 	{ sony_vaio_laptop, "Sony Vaio", { /* This is a Sony Vaio laptop */
 			MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
 			MATCH(DMI_PRODUCT_NAME, "PCG-"),
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/i386/kernel/entry.S linux-2.4.27-leo/arch/i386/kernel/entry.S
--- linux-2.4.27/arch/i386/kernel/entry.S	2003-06-13 15:51:29.000000000 +0100
+++ linux-2.4.27-leo/arch/i386/kernel/entry.S	2004-09-17 03:19:57.000000000 +0100
@@ -73,7 +73,7 @@
  * these are offsets into the task-struct.
  */
 state		=  0
-flags		=  4
+preempt_count	=  4
 sigpending	=  8
 addr_limit	= 12
 exec_domain	= 16
@@ -81,8 +81,28 @@
 tsk_ptrace	= 24
 processor	= 52
 
+/* These are offsets into the irq_stat structure
+ * There is one per cpu and it is aligned to 32
+ * byte boundry (we put that here as a shift count)
+ */
+irq_array_shift                 = CONFIG_X86_L1_CACHE_SHIFT
+
+irq_stat_local_irq_count        = 4
+irq_stat_local_bh_count         = 8
+
 ENOSYS = 38
 
+#ifdef CONFIG_SMP
+#define GET_CPU_INDX	movl processor(%ebx),%eax;  \
+                        shll $irq_array_shift,%eax
+#define GET_CURRENT_CPU_INDX GET_CURRENT(%ebx); \
+                             GET_CPU_INDX
+#define CPU_INDX (,%eax)
+#else
+#define GET_CPU_INDX
+#define GET_CURRENT_CPU_INDX GET_CURRENT(%ebx)
+#define CPU_INDX
+#endif
 
 #define SAVE_ALL \
 	cld; \
@@ -209,6 +229,17 @@
 	jae badsys
 	call *SYMBOL_NAME(sys_call_table)(,%eax,4)
 	movl %eax,EAX(%esp)		# save the return value
+
+#ifdef CONFIG_GRKERNSEC_PAX_RANDKSTACK
+	cli                             # need_resched and signals atomic test
+	cmpl $0,need_resched(%ebx)
+	jne reschedule
+	cmpl $0,sigpending(%ebx)
+	jne signal_return
+	call SYMBOL_NAME(pax_randomize_kstack)
+	jmp restore_all
+#endif
+
 ENTRY(ret_from_sys_call)
 	cli				# need_resched and signals atomic test
 	cmpl $0,need_resched(%ebx)
@@ -255,12 +286,30 @@
 	ALIGN
 ENTRY(ret_from_intr)
 	GET_CURRENT(%ebx)
+#ifdef CONFIG_PREEMPT
+	cli
+	decl preempt_count(%ebx)
+#endif
 ret_from_exception:
 	movl EFLAGS(%esp),%eax		# mix EFLAGS and CS
 	movb CS(%esp),%al
 	testl $(VM_MASK | 3),%eax	# return to VM86 mode or non-supervisor?
 	jne ret_from_sys_call
+#ifdef CONFIG_PREEMPT
+	cmpl $0,preempt_count(%ebx)
+	jnz restore_all
+	cmpl $0,need_resched(%ebx)
+	jz restore_all
+	movl SYMBOL_NAME(irq_stat)+irq_stat_local_bh_count CPU_INDX,%ecx
+	addl SYMBOL_NAME(irq_stat)+irq_stat_local_irq_count CPU_INDX,%ecx
+	jnz restore_all
+	incl preempt_count(%ebx)
+	sti
+	call SYMBOL_NAME(preempt_schedule)
+	jmp ret_from_intr
+#else
 	jmp restore_all
+#endif
 
 	ALIGN
 reschedule:
@@ -297,6 +346,9 @@
 	GET_CURRENT(%ebx)
 	call *%edi
 	addl $8,%esp
+#ifdef CONFIG_PREEMPT
+	cli
+#endif
 	jmp ret_from_exception
 
 ENTRY(coprocessor_error)
@@ -316,12 +368,18 @@
 	movl %cr0,%eax
 	testl $0x4,%eax			# EM (math emulation bit)
 	jne device_not_available_emulate
+#ifdef CONFIG_PREEMPT
+	cli
+#endif
 	call SYMBOL_NAME(math_state_restore)
 	jmp ret_from_exception
 device_not_available_emulate:
 	pushl $0		# temporary storage for ORIG_EIP
 	call  SYMBOL_NAME(math_emulate)
 	addl $4,%esp
+#ifdef CONFIG_PREEMPT
+	cli
+#endif
 	jmp ret_from_exception
 
 ENTRY(debug)
@@ -389,8 +447,56 @@
 	jmp error_code
 
 ENTRY(page_fault)
+#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC
+	ALIGN
+	pushl $ SYMBOL_NAME(pax_do_page_fault)
+#else
 	pushl $ SYMBOL_NAME(do_page_fault)
+#endif
+
+#ifndef CONFIG_GRKERNSEC_PAX_EMUTRAMP
 	jmp error_code
+#else
+	pushl %ds
+	pushl %eax
+	xorl %eax,%eax
+	pushl %ebp
+	pushl %edi
+	pushl %esi
+	pushl %edx
+	decl %eax			# eax = -1
+	pushl %ecx
+	pushl %ebx
+	cld
+	movl %es,%ecx
+	movl ORIG_EAX(%esp), %esi	# get the error code
+	movl ES(%esp), %edi		# get the function address
+	movl %eax, ORIG_EAX(%esp)
+	movl %ecx, ES(%esp)
+	movl %esp,%edx
+	pushl %esi			# push the error code
+	pushl %edx			# push the pt_regs pointer
+	movl $(__KERNEL_DS),%edx
+	movl %edx,%ds
+	movl %edx,%es
+	GET_CURRENT(%ebx)
+	call *%edi
+	addl $8,%esp
+	decl %eax
+	jnz ret_from_exception
+
+	popl %ebx
+	popl %ecx
+	popl %edx
+	popl %esi
+	popl %edi
+	popl %ebp
+	popl %eax
+	popl %ds
+	popl %es
+	addl $4,%esp
+	jmp system_call
+#endif
 
 ENTRY(machine_check)
 	pushl $0
@@ -402,7 +508,7 @@
 	pushl $ SYMBOL_NAME(do_spurious_interrupt_bug)
 	jmp error_code
 
-.data
+.section .rodata, "a",@progbits
 ENTRY(sys_call_table)
 	.long SYMBOL_NAME(sys_ni_syscall)	/* 0  -  old "setup()" system call*/
 	.long SYMBOL_NAME(sys_exit)
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/i386/kernel/head.S linux-2.4.27-leo/arch/i386/kernel/head.S
--- linux-2.4.27/arch/i386/kernel/head.S	2003-11-28 18:26:19.000000000 +0000
+++ linux-2.4.27-leo/arch/i386/kernel/head.S	2004-09-17 03:19:57.000000000 +0100
@@ -37,10 +37,17 @@
 #define X86_VENDOR_ID	CPU_PARAMS+36	/* tied to NCAPINTS in cpufeature.h */
 
 /*
+ * Real beginning of normal "text" segment
+ */
+ENTRY(stext)
+ENTRY(_stext)
+
+/*
  * swapper_pg_dir is the main page directory, address 0x00101000
  *
  * On entry, %esi points to the real-mode code as a 32-bit pointer.
  */
+.global startup_32
 startup_32:
 /*
  * Set segments to known values
@@ -86,7 +93,7 @@
 				   PRESENT+RW+USER */
 2:	stosl
 	add $0x1000,%eax
-	cmp $empty_zero_page-__PAGE_OFFSET,%edi
+	cmp $0x00c00007,%eax
 	jne 2b
 
 /*
@@ -100,9 +107,19 @@
 	movl %eax,%cr0		/* ..and set paging (PG) bit */
 	jmp 1f			/* flush the prefetch-queue */
 1:
+
+#if !defined(CONFIG_GRKERNSEC_PAX_KERNEXEC) || defined(CONFIG_SMP)
+
+#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC
+	orw  %bx,%bx
+	jz  1f
+#endif
+
 	movl $1f,%eax
 	jmp *%eax		/* make sure eip is relocated */
 1:
+#endif
+
 	/* Set up the stack pointer */
 	lss stack_start,%esp
 
@@ -121,7 +138,7 @@
  */
 	xorl %eax,%eax
 	movl $ SYMBOL_NAME(__bss_start),%edi
-	movl $ SYMBOL_NAME(_end),%ecx
+	movl $ SYMBOL_NAME(__bss_end),%ecx
 	subl %edi,%ecx
 	rep
 	stosb
@@ -272,8 +289,6 @@
 	jmp L6			# main should never return here, but
 				# just in case, we know what happens.
 
-ready:	.byte 0
-
 /*
  * We depend on ET to be correct. This checks for 287/387.
  */
@@ -319,13 +334,6 @@
 	jne rp_sidt
 	ret
 
-ENTRY(stack_start)
-	.long SYMBOL_NAME(init_task_union)+8192
-	.long __KERNEL_DS
-
-/* This is the default interrupt "handler" :-) */
-int_msg:
-	.asciz "Unknown interrupt\n"
 	ALIGN
 ignore_int:
 	cld
@@ -347,6 +355,18 @@
 	popl %eax
 	iret
 
+.data
+ready:	.byte 0
+
+ENTRY(stack_start)
+	.long SYMBOL_NAME(init_task_union)+8192
+	.long __KERNEL_DS
+
+.section .rodata,"a"
+/* This is the default interrupt "handler" :-) */
+int_msg:
+	.asciz "Unknown interrupt\n"
+
 /*
  * The interrupt descriptor table has room for 256 idt's,
  * the global descriptor table is dependent on the number
@@ -372,54 +392,77 @@
 SYMBOL_NAME(gdt):
 	.long SYMBOL_NAME(gdt_table)
 
+#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC
+.globl SYMBOL_NAME(gdt2)
+	.word 0
+gdt_descr2:
+	.word GDT_ENTRIES*8-1
+SYMBOL_NAME(gdt2):
+	.long SYMBOL_NAME(gdt_table2)
+#endif
+
 /*
  * This is initialized to create an identity-mapping at 0-8M (for bootup
  * purposes) and another mapping of the 0-8M area at virtual address
  * PAGE_OFFSET.
  */
-.org 0x1000
+.section .data.swapper_pg_dir,"a",@progbits
 ENTRY(swapper_pg_dir)
-	.long 0x00102007
-	.long 0x00103007
-	.fill BOOT_USER_PGD_PTRS-2,4,0
+	.long pg0-__PAGE_OFFSET+7
+	.long pg1-__PAGE_OFFSET+7
+	.long pg2-__PAGE_OFFSET+7
+	.fill BOOT_USER_PGD_PTRS-3,4,0
 	/* default: 766 entries */
-	.long 0x00102007
-	.long 0x00103007
+	.long pg0-__PAGE_OFFSET+7
+	.long pg1-__PAGE_OFFSET+7
+	.long pg2-__PAGE_OFFSET+7
 	/* default: 254 entries */
-	.fill BOOT_KERNEL_PGD_PTRS-2,4,0
+	.fill BOOT_KERNEL_PGD_PTRS-3,4,0
+
+#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC
+ENTRY(kernexec_pg_dir)
+	.fill 1024,4,0
+#endif
 
 /*
  * The page tables are initialized to only 8MB here - the final page
  * tables are set up later depending on memory size.
  */
-.org 0x2000
+.section .data.pg0,"a",@progbits
 ENTRY(pg0)
+	.fill 1024,4,0
 
-.org 0x3000
+.section .data.pg1,"a",@progbits
 ENTRY(pg1)
+	.fill 1024,4,0
+
+.section .data.pg2,"a",@progbits
+ENTRY(pg2)
+	.fill 1024,4,0
 
 /*
  * empty_zero_page must immediately follow the page tables ! (The
  * initialization loop counts until empty_zero_page)
  */
-
-.org 0x4000
+.section .rodata.empty_zero_page,"a",@progbits
 ENTRY(empty_zero_page)
-
-.org 0x5000
+	.fill 1024,4,0
 
 /*
- * Real beginning of normal "text" segment
+ * The IDT has to be page-aligned to simplify the Pentium
+ * F0 0F bug workaround.  We have a special link segment
+ * for this.
  */
-ENTRY(stext)
-ENTRY(_stext)
+.section .rodata.idt,"a",@progbits
+ENTRY(idt_table)
+	.fill 256,8,0
 
 /*
  * This starts the data section. Note that the above is all
  * in the text section because it has alignment requirements
  * that we cannot fulfill any other way.
  */
-.data
+.section .rodata,"a",@progbits
 
 ALIGN
 /*
@@ -430,19 +473,61 @@
  */
 ENTRY(gdt_table)
 	.quad 0x0000000000000000	/* NULL descriptor */
-	.quad 0x0000000000000000	/* not used */
-	.quad 0x00cf9a000000ffff	/* 0x10 kernel 4GB code at 0x00000000 */
-	.quad 0x00cf92000000ffff	/* 0x18 kernel 4GB data at 0x00000000 */
-	.quad 0x00cffa000000ffff	/* 0x23 user   4GB code at 0x00000000 */
-	.quad 0x00cff2000000ffff	/* 0x2b user   4GB data at 0x00000000 */
+
+#if defined(CONFIG_GRKERNSEC_PAX_KERNEXEC) && defined(CONFIG_PCI_BIOS)
+	.quad 0x00cf9b000000ffff        /* 0x08 kernel 4GB code at 0x00000000 */
+#else
+	.quad 0x0000000000000000        /* not used */
+#endif
+#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC
+	.quad 0xc0cf9b400000ffff        /* 0x10 kernel 4GB code at 0xc0400000 */
+#else
+	.quad 0x00cf9b000000ffff        /* 0x10 kernel 4GB code at 0x00000000 */
+#endif
+
+	.quad 0x00cf93000000ffff	/* 0x18 kernel 4GB data at 0x00000000 */
+	.quad 0x00cffb000000ffff	/* 0x23 user   4GB code at 0x00000000 */
+	.quad 0x00cff3000000ffff	/* 0x2b user   4GB data at 0x00000000 */
+	.quad 0x0000000000000000        /* not used */
+	.quad 0x0000000000000000        /* not used */
+	/*
+	 * The APM segments have byte granularity and their bases
+	 * and limits are set at run time.
+	 */
+	.quad 0x0040930000000000        /* 0x40 APM set up for bad BIOS's */
+	.quad 0x00409b0000000000        /* 0x48 APM CS    code */
+	.quad 0x00009b0000000000        /* 0x50 APM CS 16 code (16 bit) */
+	.quad 0x0040930000000000        /* 0x58 APM DS    data */
+	.fill NR_CPUS*4,8,0             /* space for TSS's and LDT's */
+
+#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC
+ENTRY(gdt_table2)
+	.quad 0x0000000000000000        /* NULL descriptor */
+
+#if defined(CONFIG_GRKERNSEC_PAX_KERNEXEC) && defined(CONFIG_PCI_BIOS)
+	.quad 0x00cf9b000000ffff        /* 0x08 kernel 4GB code at 0x00000000 */
+#else
+	.quad 0x0000000000000000        /* not used */
+#endif
+#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC
+	.quad 0xc0cf9b400000ffff        /* 0x10 kernel 4GB code at 0xc0400000 */
+#else
+	.quad 0x00cf9b000000ffff        /* 0x10 kernel 4GB code at 0x00000000 */
+#endif
+
+	.quad 0x00cf93000000ffff        /* 0x18 kernel 4GB data at 0x00000000 */
+	.quad 0x60c5fb000000ffff        /* 0x23 user 1.5GB code at 0x60000000 */
+	.quad 0x00c5f3000000ffff        /* 0x2b user 1.5GB data at 0x00000000 */
+
 	.quad 0x0000000000000000	/* not used */
 	.quad 0x0000000000000000	/* not used */
 	/*
 	 * The APM segments have byte granularity and their bases
 	 * and limits are set at run time.
 	 */
-	.quad 0x0040920000000000	/* 0x40 APM set up for bad BIOS's */
-	.quad 0x00409a0000000000	/* 0x48 APM CS    code */
-	.quad 0x00009a0000000000	/* 0x50 APM CS 16 code (16 bit) */
-	.quad 0x0040920000000000	/* 0x58 APM DS    data */
+	.quad 0x0040930000000000	/* 0x40 APM set up for bad BIOS's */
+	.quad 0x00409b0000000000	/* 0x48 APM CS    code */
+	.quad 0x00009b0000000000	/* 0x50 APM CS 16 code (16 bit) */
+	.quad 0x0040930000000000	/* 0x58 APM DS    data */
 	.fill NR_CPUS*4,8,0		/* space for TSS's and LDT's */
+#endif
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/i386/kernel/i386_ksyms.c linux-2.4.27-leo/arch/i386/kernel/i386_ksyms.c
--- linux-2.4.27/arch/i386/kernel/i386_ksyms.c	2004-05-19 21:34:36.000000000 +0100
+++ linux-2.4.27-leo/arch/i386/kernel/i386_ksyms.c	2004-09-20 21:34:47.000000000 +0100
@@ -74,6 +74,9 @@
 EXPORT_SYMBOL(get_cmos_time);
 EXPORT_SYMBOL(apm_info);
 EXPORT_SYMBOL(gdt);
+#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC
+EXPORT_SYMBOL(gdt2);
+#endif
 EXPORT_SYMBOL(empty_zero_page);
 
 #ifdef CONFIG_DEBUG_IOVIRT
@@ -179,6 +182,9 @@
 EXPORT_SYMBOL(atomic_dec_and_lock);
 #endif
 
+extern int is_unsafe_smbus;
+EXPORT_SYMBOL(is_unsafe_smbus);
+
 extern int is_sony_vaio_laptop;
 EXPORT_SYMBOL(is_sony_vaio_laptop);
 
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/i386/kernel/i387.c linux-2.4.27-leo/arch/i386/kernel/i387.c
--- linux-2.4.27/arch/i386/kernel/i387.c	2003-08-25 12:44:39.000000000 +0100
+++ linux-2.4.27-leo/arch/i386/kernel/i387.c	2004-09-17 03:19:36.000000000 +0100
@@ -10,6 +10,7 @@
 
 #include <linux/config.h>
 #include <linux/sched.h>
+#include <linux/spinlock.h>
 #include <linux/init.h>
 #include <asm/processor.h>
 #include <asm/i387.h>
@@ -89,6 +90,8 @@
 {
 	struct task_struct *tsk = current;
 
+	preempt_disable();
+	
 	if (tsk->flags & PF_USEDFPU) {
 		__save_init_fpu(tsk);
 		return;
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/i386/kernel/init_task.c linux-2.4.27-leo/arch/i386/kernel/init_task.c
--- linux-2.4.27/arch/i386/kernel/init_task.c	2001-09-17 23:29:09.000000000 +0100
+++ linux-2.4.27-leo/arch/i386/kernel/init_task.c	2004-09-17 03:19:57.000000000 +0100
@@ -29,5 +29,9 @@
  * section. Since TSS's are completely CPU-local, we want them
  * on exact cacheline boundaries, to eliminate cacheline ping-pong.
  */ 
-struct tss_struct init_tss[NR_CPUS] __cacheline_aligned = { [0 ... NR_CPUS-1] = INIT_TSS };
 
+#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC
+struct tss_struct init_tss[NR_CPUS] __attribute__((__aligned__(SMP_CACHE_BYTES), __section__(".rodata"))) = { [0 ... NR_CPUS-1] = INIT_TSS };
+#else
+struct tss_struct init_tss[NR_CPUS] __cacheline_aligned = { [0 ... NR_CPUS-1] = INIT_TSS };
+#endif
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/i386/kernel/ioport.c linux-2.4.27-leo/arch/i386/kernel/ioport.c
--- linux-2.4.27/arch/i386/kernel/ioport.c	2003-06-13 15:51:29.000000000 +0100
+++ linux-2.4.27-leo/arch/i386/kernel/ioport.c	2004-09-17 03:19:57.000000000 +0100
@@ -14,6 +14,8 @@
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/stddef.h>
+#include <linux/grsecurity.h>
+#include <asm/desc.h>
 
 /* Set EXTENT bits starting at BASE in BITMAP to value TURN_ON. */
 static void set_bitmap(unsigned long *bitmap, short base, short extent, int new_value)
@@ -55,17 +57,31 @@
 asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int turn_on)
 {
 	struct thread_struct * t = &current->thread;
-	struct tss_struct * tss = init_tss + smp_processor_id();
+	struct tss_struct * tss;
+
+#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC
+	unsigned long flags, cr3;
+#endif
 
 	if ((from + num <= from) || (from + num > IO_BITMAP_SIZE*32))
 		return -EINVAL;
+#ifdef CONFIG_GRKERNSEC_IO
+	if (turn_on) {
+		gr_handle_ioperm();
+#else
 	if (turn_on && !capable(CAP_SYS_RAWIO))
+#endif
 		return -EPERM;
+#ifdef CONFIG_GRKERNSEC_IO
+	}
+#endif
 	/*
 	 * If it's the first ioperm() call in this thread's lifetime, set the
 	 * IO bitmap up. ioperm() is much less timing critical than clone(),
 	 * this is why we delay this operation until now:
 	 */
+	preempt_disable();
+	tss = init_tss + smp_processor_id();
 	if (!t->ioperm) {
 		/*
 		 * just in case ...
@@ -78,12 +94,22 @@
 	 * do it in the per-thread copy and in the TSS ...
 	 */
 	set_bitmap(t->io_bitmap, from, num, !turn_on);
+
+#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC
+	pax_open_kernel(flags, cr3);
+#endif
+
 	if (tss->bitmap == IO_BITMAP_OFFSET) { /* already active? */
 		set_bitmap(tss->io_bitmap, from, num, !turn_on);
 	} else {
 		memcpy(tss->io_bitmap, t->io_bitmap, IO_BITMAP_BYTES);
 		tss->bitmap = IO_BITMAP_OFFSET; /* Activate it in the TSS */
 	}
+	preempt_enable();
+
+#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC
+	pax_close_kernel(flags, cr3);
+#endif
 
 	return 0;
 }
@@ -109,8 +135,13 @@
 		return -EINVAL;
 	/* Trying to gain more privileges? */
 	if (level > old) {
+#ifdef CONFIG_GRKERNSEC_IO
+		gr_handle_iopl();
+		return -EPERM;
+#else
 		if (!capable(CAP_SYS_RAWIO))
 			return -EPERM;
+#endif
 	}
 	regs->eflags = (regs->eflags & 0xffffcfff) | (level << 12);
 	return 0;
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/i386/kernel/irq.c linux-2.4.27-leo/arch/i386/kernel/irq.c
--- linux-2.4.27/arch/i386/kernel/irq.c	2003-11-28 18:26:19.000000000 +0000
+++ linux-2.4.27-leo/arch/i386/kernel/irq.c	2004-09-17 03:19:36.000000000 +0100
@@ -284,9 +284,11 @@
 				show("wait_on_irq");
 				count = ~0;
 			}
+			preempt_disable();
 			__sti();
 			SYNC_OTHER_CORES(cpu);
 			__cli();
+			preempt_enable_no_resched();
 			if (irqs_running())
 				continue;
 			if (global_irq_lock)
@@ -360,8 +362,9 @@
 
 	__save_flags(flags);
 	if (flags & (1 << EFLAGS_IF_SHIFT)) {
-		int cpu = smp_processor_id();
+		int cpu;
 		__cli();
+		cpu = smp_processor_id();
 		if (!local_irq_count(cpu))
 			get_irqlock(cpu);
 	}
@@ -369,11 +372,14 @@
 
 void __global_sti(void)
 {
-	int cpu = smp_processor_id();
+	int cpu;
 
+	preempt_disable();
+	cpu = smp_processor_id();
 	if (!local_irq_count(cpu))
 		release_irqlock(cpu);
 	__sti();
+	preempt_enable();
 }
 
 /*
@@ -388,13 +394,15 @@
 	int retval;
 	int local_enabled;
 	unsigned long flags;
-	int cpu = smp_processor_id();
+	int cpu;
 
 	__save_flags(flags);
 	local_enabled = (flags >> EFLAGS_IF_SHIFT) & 1;
 	/* default to local */
 	retval = 2 + local_enabled;
 
+	preempt_disable();
+	cpu = smp_processor_id();
 	/* check for global flags if we're not in an interrupt */
 	if (!local_irq_count(cpu)) {
 		if (local_enabled)
@@ -402,6 +410,7 @@
 		if (global_irq_holder == cpu)
 			retval = 0;
 	}
+	preempt_enable();
 	return retval;
 }
 
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/i386/kernel/ldt.c linux-2.4.27-leo/arch/i386/kernel/ldt.c
--- linux-2.4.27/arch/i386/kernel/ldt.c	2004-02-20 14:11:37.000000000 +0000
+++ linux-2.4.27-leo/arch/i386/kernel/ldt.c	2004-09-17 03:19:57.000000000 +0100
@@ -151,7 +151,7 @@
 {
 	int err;
 	unsigned long size;
-	void *address;
+	const void *address;
 
 	err = 0;
 	address = &default_ldt[0];
@@ -214,6 +214,13 @@
 		}
 	}
 
+#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC
+	if ((current->flags & PF_PAX_SEGMEXEC) && (ldt_info.contents & 2)) {
+		error = -EINVAL;
+		goto out_unlock;
+	}
+#endif
+
 	entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
 		  (ldt_info.limit & 0x0ffff);
 	entry_2 = (ldt_info.base_addr & 0xff000000) |
@@ -224,7 +231,7 @@
 		  ((ldt_info.seg_not_present ^ 1) << 15) |
 		  (ldt_info.seg_32bit << 22) |
 		  (ldt_info.limit_in_pages << 23) |
-		  0x7000;
+		  0x7100;
 	if (!oldmode)
 		entry_2 |= (ldt_info.useable << 20);
 
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/i386/kernel/microcode.c linux-2.4.27-leo/arch/i386/kernel/microcode.c
--- linux-2.4.27/arch/i386/kernel/microcode.c	2004-05-19 21:34:36.000000000 +0100
+++ linux-2.4.27-leo/arch/i386/kernel/microcode.c	2004-09-17 03:19:36.000000000 +0100
@@ -397,15 +397,18 @@
 {
 	int i, error;
 
+	preempt_disable();
 	if (smp_call_function(collect_cpu_info, NULL, 1, 1) != 0) {
 		printk(KERN_ERR "microcode: Error! Could not run on all processors\n");
 		error = -EIO;
+		preempt_enable();
 		goto out;
 	}
 	collect_cpu_info(NULL);
 
 	if ((error = find_matching_ucodes())) {
 		printk(KERN_ERR "microcode: Error in the microcode data\n");
+		preempt_enable();
 		goto out_free;
 	}
 
@@ -414,6 +417,7 @@
 		error = -EIO;
 	}
 	do_update_one(NULL);
+	preempt_enable();
 
 out_free:
 	for (i = 0; i < smp_num_cpus; i++) {
@@ -428,6 +432,7 @@
 		}
 	}
 out:
+
 	return error;
 }
 
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/i386/kernel/msr.c linux-2.4.27-leo/arch/i386/kernel/msr.c
--- linux-2.4.27/arch/i386/kernel/msr.c	2001-10-11 17:04:57.000000000 +0100
+++ linux-2.4.27-leo/arch/i386/kernel/msr.c	2004-09-17 03:19:36.000000000 +0100
@@ -114,8 +114,9 @@
 {
   struct msr_command cmd;
 
+  preempt_disable();
   if ( cpu == smp_processor_id() ) {
-    return wrmsr_eio(reg, eax, edx);
+    cmd.err = wrmsr_eio(reg, eax, edx);
   } else {
     cmd.cpu = cpu;
     cmd.reg = reg;
@@ -123,16 +124,19 @@
     cmd.data[1] = edx;
     
     smp_call_function(msr_smp_wrmsr, &cmd, 1, 1);
-    return cmd.err;
   }
+
+  preempt_enable();
+  return cmd.err;
 }
 
 static inline int do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx)
 {
   struct msr_command cmd;
 
+  preempt_disable();
   if ( cpu == smp_processor_id() ) {
-    return rdmsr_eio(reg, eax, edx);
+    cmd.err = rdmsr_eio(reg, eax, edx);
   } else {
     cmd.cpu = cpu;
     cmd.reg = reg;
@@ -141,9 +145,10 @@
     
     *eax = cmd.data[0];
     *edx = cmd.data[1];
-
-    return cmd.err;
   }
+
+  preempt_enable();
+  return cmd.err;
 }
 
 #else /* ! CONFIG_SMP */
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/i386/kernel/mtrr.c linux-2.4.27-leo/arch/i386/kernel/mtrr.c
--- linux-2.4.27/arch/i386/kernel/mtrr.c	2004-09-17 02:38:42.000000000 +0100
+++ linux-2.4.27-leo/arch/i386/kernel/mtrr.c	2004-09-17 03:19:36.000000000 +0100
@@ -1065,6 +1065,9 @@
     wait_barrier_execute = TRUE;
     wait_barrier_cache_enable = TRUE;
     atomic_set (&undone_count, smp_num_cpus - 1);
+
+    preempt_disable();
+
     /*  Start the ball rolling on other CPUs  */
     if (smp_call_function (ipi_handler, &data, 1, 0) != 0)
 	panic ("mtrr: timed out waiting for other CPUs\n");
@@ -1090,6 +1093,9 @@
 	then enable the local cache and return  */
     wait_barrier_cache_enable = FALSE;
     set_mtrr_done (&ctxt);
+
+    preempt_enable();
+
 }   /*  End Function set_mtrr_smp  */
 
 
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/i386/kernel/pci-pc.c linux-2.4.27-leo/arch/i386/kernel/pci-pc.c
--- linux-2.4.27/arch/i386/kernel/pci-pc.c	2004-09-17 02:38:42.000000000 +0100
+++ linux-2.4.27-leo/arch/i386/kernel/pci-pc.c	2004-09-17 03:19:57.000000000 +0100
@@ -17,6 +17,7 @@
 #include <asm/io.h>
 #include <asm/smp.h>
 #include <asm/smpboot.h>
+#include <asm/desc.h>
 
 #include "pci-i386.h"
 
@@ -575,10 +576,16 @@
  * the array there.
  */
 
+#if defined(CONFIG_GRKERNSEC_PAX_KERNEXEC) && defined(CONFIG_PCI_BIOS)
+#define __FLAT_KERNEL_CS 0x08
+#else
+#define __FLAT_KERNEL_CS __KERNEL_CS
+#endif
+
 static struct {
 	unsigned long address;
 	unsigned short segment;
-} bios32_indirect = { 0, __KERNEL_CS };
+} bios32_indirect = { 0, __FLAT_KERNEL_CS };
 
 /*
  * Returns the entry point for the given service, NULL on error
@@ -619,7 +626,9 @@
 static struct {
 	unsigned long address;
 	unsigned short segment;
-} pci_indirect = { 0, __KERNEL_CS };
+} pci_indirect = { 0, __FLAT_KERNEL_CS };
+
+#undef __FLAT_KERNEL_CS
 
 static int pci_bios_present;
 
@@ -1490,6 +1499,7 @@
 	if ((pci_probe & PCI_BIOS_SORT) && !(pci_probe & PCI_NO_SORT))
 		pcibios_sort();
 #endif
+
 }
 
 char * __devinit  pcibios_setup(char *str)
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/i386/kernel/process.c linux-2.4.27-leo/arch/i386/kernel/process.c
--- linux-2.4.27/arch/i386/kernel/process.c	2004-02-20 14:11:37.000000000 +0000
+++ linux-2.4.27-leo/arch/i386/kernel/process.c	2004-09-17 03:19:57.000000000 +0100
@@ -209,18 +209,18 @@
    doesn't work with at least one type of 486 motherboard.  It is easy
    to stop this code working; hence the copious comments. */
 
-static unsigned long long
+static const unsigned long long
 real_mode_gdt_entries [3] =
 {
 	0x0000000000000000ULL,	/* Null descriptor */
-	0x00009a000000ffffULL,	/* 16-bit real-mode 64k code at 0x00000000 */
-	0x000092000100ffffULL	/* 16-bit real-mode 64k data at 0x00000100 */
+	0x00009b000000ffffULL,	/* 16-bit real-mode 64k code at 0x00000000 */
+	0x000093000100ffffULL	/* 16-bit real-mode 64k data at 0x00000100 */
 };
 
 static struct
 {
 	unsigned short       size __attribute__ ((packed));
-	unsigned long long * base __attribute__ ((packed));
+	const unsigned long long * base __attribute__ ((packed));
 }
 real_mode_gdt = { sizeof (real_mode_gdt_entries) - 1, real_mode_gdt_entries },
 real_mode_idt = { 0x3ff, 0 },
@@ -552,7 +552,7 @@
 {
 	struct pt_regs * childregs;
 
-	childregs = ((struct pt_regs *) (THREAD_SIZE + (unsigned long) p)) - 1;
+	childregs = ((struct pt_regs *) (THREAD_SIZE + (unsigned long) p - sizeof(unsigned long))) - 1;
 	struct_cpy(childregs, regs);
 	childregs->eax = 0;
 	childregs->esp = esp;
@@ -613,6 +613,16 @@
 	dump->u_fpvalid = dump_fpu (regs, &dump->i387);
 }
 
+#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC
+void pax_switch_segments(struct task_struct * tsk)
+{
+	if (tsk->flags & PF_PAX_SEGMEXEC)
+		__asm__ __volatile__("lgdt %0": "=m" (gdt_descr2));
+	else
+		__asm__ __volatile__("lgdt %0": "=m" (gdt_descr));
+}
+#endif
+
 /*
  * This special macro can be used to load a debugging register
  */
@@ -650,12 +660,15 @@
 				 *next = &next_p->thread;
 	struct tss_struct *tss = init_tss + smp_processor_id();
 
+#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC
+	unsigned long flags, cr3;
+#endif
+
 	unlazy_fpu(prev_p);
 
-	/*
-	 * Reload esp0, LDT and the page table pointer:
-	 */
-	tss->esp0 = next->esp0;
+#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC
+	pax_switch_segments(next_p);
+#endif
 
 	/*
 	 * Save away %fs and %gs. No need to save %es and %ds, as
@@ -683,6 +696,15 @@
 		loaddebug(next, 7);
 	}
 
+#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC
+	pax_open_kernel(flags, cr3);
+#endif
+
+	/*
+	 * Reload esp0, LDT and the page table pointer:
+	 */
+	tss->esp0 = next->esp0;
+
 	if (prev->ioperm || next->ioperm) {
 		if (next->ioperm) {
 			/*
@@ -705,6 +727,11 @@
 			 */
 			tss->bitmap = INVALID_IO_BITMAP_OFFSET;
 	}
+
+#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC
+	pax_close_kernel(flags, cr3);
+#endif
+
 }
 
 asmlinkage int sys_fork(struct pt_regs regs)
@@ -792,3 +819,43 @@
 }
 #undef last_sched
 #undef first_sched
+
+#ifdef CONFIG_GRKERNSEC_PAX_RANDKSTACK
+asmlinkage void pax_randomize_kstack(void)
+{
+	struct tss_struct *tss = init_tss + smp_processor_id();
+	unsigned long time;
+
+#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC
+	unsigned long flags, cr3;
+#endif
+
+#ifdef CONFIG_GRKERNSEC_PAX_SOFTMODE
+	if (!pax_aslr)
+		return;
+#endif
+
+	rdtscl(time);
+
+	/* P4 seems to return a 0 LSB, ignore it */
+#ifdef CONFIG_MPENTIUM4
+	time &= 0x3EUL;
+	time <<= 1;
+#else
+	time &= 0x1FUL;
+	time <<= 2;
+#endif
+
+#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC
+	pax_open_kernel(flags, cr3);
+#endif
+
+	tss->esp0 ^= time;
+	current->thread.esp0 = tss->esp0;
+
+#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC
+	pax_close_kernel(flags, cr3);
+#endif
+
+}
+#endif
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/i386/kernel/ptrace.c linux-2.4.27-leo/arch/i386/kernel/ptrace.c
--- linux-2.4.27/arch/i386/kernel/ptrace.c	2002-08-03 01:39:42.000000000 +0100
+++ linux-2.4.27-leo/arch/i386/kernel/ptrace.c	2004-09-17 03:19:57.000000000 +0100
@@ -13,6 +13,7 @@
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
+#include <linux/grsecurity.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -177,6 +178,9 @@
 	if (pid == 1)		/* you may not mess with init */
 		goto out_tsk;
 
+	if(gr_handle_ptrace(child, request))
+		goto out_tsk;
+
 	if (request == PTRACE_ATTACH) {
 		ret = ptrace_attach(child);
 		goto out_tsk;
@@ -256,6 +260,17 @@
 			  if(addr < (long) &dummy->u_debugreg[4] &&
 			     ((unsigned long) data) >= TASK_SIZE-3) break;
 			  
+#ifdef CONFIG_GRKERNSEC
+			  if(addr >= (long) &dummy->u_debugreg[0] &&
+			     addr <= (long) &dummy->u_debugreg[3]){
+				  long reg   = (addr - (long) &dummy->u_debugreg[0]) >> 2;
+				  long type  = (child->thread.debugreg[7] >> (DR_CONTROL_SHIFT + 4*reg)) & 3;
+				  long align = (child->thread.debugreg[7] >> (DR_CONTROL_SHIFT + 2 + 4*reg)) & 3;
+				  if((type & 1) && (data & align))
+					break;
+			  }
+#endif
+
 			  if(addr == (long) &dummy->u_debugreg[7]) {
 				  data &= ~DR_CONTROL_RESERVED;
 				  for(i=0; i<4; i++)
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/i386/kernel/setup.c linux-2.4.27-leo/arch/i386/kernel/setup.c
--- linux-2.4.27/arch/i386/kernel/setup.c	2004-09-17 02:38:42.000000000 +0100
+++ linux-2.4.27-leo/arch/i386/kernel/setup.c	2004-09-17 03:19:57.000000000 +0100
@@ -170,7 +170,7 @@
 extern void mcheck_init(struct cpuinfo_x86 *c);
 extern void dmi_scan_machine(void);
 extern int root_mountflags;
-extern char _text, _etext, _edata, _end;
+extern char _text, _etext, _data, _edata, _end;
 
 static int have_cpuid_p(void) __init;
 
@@ -1215,7 +1215,7 @@
 
 	code_resource.start = virt_to_bus(&_text);
 	code_resource.end = virt_to_bus(&_etext)-1;
-	data_resource.start = virt_to_bus(&_etext);
+	data_resource.start = virt_to_bus(&_data);
 	data_resource.end = virt_to_bus(&_edata)-1;
 
 	parse_cmdline_early(cmdline_p);
@@ -3221,7 +3221,7 @@
 	set_tss_desc(nr,t);
 	gdt_table[__TSS(nr)].b &= 0xfffffdff;
 	load_TR(nr);
-	load_LDT(&init_mm.context);
+	_load_LDT(&init_mm.context);
 
 	/*
 	 * Clear all 6 debug registers:
@@ -3287,7 +3287,16 @@
 	printk(KERN_INFO "Your Pentium Pro seems ok.\n");
 	return 0;
 }
-	
+
+#ifdef CONFIG_GRKERNSEC_PAX_SOFTMODE
+static int __init setup_pax_softmode(char *str)
+{
+	get_option (&str, &pax_softmode);
+	return 1;
+}
+__setup("pax_softmode=", setup_pax_softmode);
+#endif
+
 /*
  * Local Variables:
  * mode:c
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/i386/kernel/smp.c linux-2.4.27-leo/arch/i386/kernel/smp.c
--- linux-2.4.27/arch/i386/kernel/smp.c	2003-06-13 15:51:29.000000000 +0100
+++ linux-2.4.27-leo/arch/i386/kernel/smp.c	2004-09-17 03:19:36.000000000 +0100
@@ -360,10 +360,14 @@
 
 asmlinkage void smp_invalidate_interrupt (void)
 {
-	unsigned long cpu = smp_processor_id();
+	unsigned long cpu;
+
+	preempt_disable();
+
+	cpu = smp_processor_id();
 
 	if (!test_bit(cpu, &flush_cpumask))
-		return;
+		goto out;
 		/* 
 		 * This was a BUG() but until someone can quote me the
 		 * line from the intel manual that guarantees an IPI to
@@ -384,6 +388,8 @@
 	}
 	ack_APIC_irq();
 	clear_bit(cpu, &flush_cpumask);
+out:
+	preempt_enable();
 }
 
 static void flush_tlb_others (unsigned long cpumask, struct mm_struct *mm,
@@ -433,17 +439,22 @@
 void flush_tlb_current_task(void)
 {
 	struct mm_struct *mm = current->mm;
-	unsigned long cpu_mask = mm->cpu_vm_mask & ~(1 << smp_processor_id());
+	unsigned long cpu_mask;
 
+	preempt_disable();
+	cpu_mask = mm->cpu_vm_mask & ~(1UL << smp_processor_id());
 	local_flush_tlb();
 	if (cpu_mask)
 		flush_tlb_others(cpu_mask, mm, FLUSH_ALL);
+	preempt_enable();
 }
 
 void flush_tlb_mm (struct mm_struct * mm)
 {
-	unsigned long cpu_mask = mm->cpu_vm_mask & ~(1 << smp_processor_id());
+	unsigned long cpu_mask;
 
+	preempt_disable();
+	cpu_mask = mm->cpu_vm_mask & ~(1UL << smp_processor_id());
 	if (current->active_mm == mm) {
 		if (current->mm)
 			local_flush_tlb();
@@ -452,13 +463,16 @@
 	}
 	if (cpu_mask)
 		flush_tlb_others(cpu_mask, mm, FLUSH_ALL);
+	preempt_enable();
 }
 
 void flush_tlb_page(struct vm_area_struct * vma, unsigned long va)
 {
 	struct mm_struct *mm = vma->vm_mm;
-	unsigned long cpu_mask = mm->cpu_vm_mask & ~(1 << smp_processor_id());
+	unsigned long cpu_mask;
 
+	preempt_disable();
+	cpu_mask = mm->cpu_vm_mask & ~(1UL << smp_processor_id());
 	if (current->active_mm == mm) {
 		if(current->mm)
 			__flush_tlb_one(va);
@@ -468,6 +482,7 @@
 
 	if (cpu_mask)
 		flush_tlb_others(cpu_mask, mm, va);
+	preempt_enable();
 }
 
 static inline void do_flush_tlb_all_local(void)
@@ -486,9 +501,11 @@
 
 void flush_tlb_all(void)
 {
+	preempt_disable();
 	smp_call_function (flush_tlb_all_ipi,0,1,1);
 
 	do_flush_tlb_all_local();
+	preempt_enable();
 }
 
 /*
@@ -572,7 +589,7 @@
 static void stop_this_cpu (void * dummy)
 {
 	/*
-	 * Remove this CPU:
+	 * Remove this CPU: assumes preemption is disabled
 	 */
 	clear_bit(smp_processor_id(), &cpu_online_map);
 	__cli();
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/i386/kernel/sys_i386.c linux-2.4.27-leo/arch/i386/kernel/sys_i386.c
--- linux-2.4.27/arch/i386/kernel/sys_i386.c	2003-08-25 12:44:39.000000000 +0100
+++ linux-2.4.27-leo/arch/i386/kernel/sys_i386.c	2004-09-17 03:19:57.000000000 +0100
@@ -18,6 +18,7 @@
 #include <linux/mman.h>
 #include <linux/file.h>
 #include <linux/utsname.h>
+#include <linux/grsecurity.h>
 
 #include <asm/uaccess.h>
 #include <asm/ipc.h>
@@ -48,6 +49,11 @@
 	int error = -EBADF;
 	struct file * file = NULL;
 
+#if defined(CONFIG_GRKERNSEC_PAX_SEGMEXEC) || defined(CONFIG_GRKERNSEC_PAX_RANDEXEC)
+	if (flags & MAP_MIRROR)
+		return -EINVAL;
+#endif
+
 	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 	if (!(flags & MAP_ANONYMOUS)) {
 		file = fget(fd);
@@ -55,6 +61,12 @@
 			goto out;
 	}
 
+	if(gr_handle_mmap(file, prot)) {
+		fput(file);
+		error = -EACCES;
+		goto out;
+	}
+
 	down_write(&current->mm->mmap_sem);
 	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
 	up_write(&current->mm->mmap_sem);
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/i386/kernel/trampoline.S linux-2.4.27-leo/arch/i386/kernel/trampoline.S
--- linux-2.4.27/arch/i386/kernel/trampoline.S	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.27-leo/arch/i386/kernel/trampoline.S	2004-09-17 03:19:57.000000000 +0100
@@ -54,7 +54,7 @@
 	lmsw	%ax		# into protected mode
 	jmp	flush_instr
 flush_instr:
-	ljmpl	$__KERNEL_CS, $0x00100000
+	ljmpl	$__KERNEL_CS, $SYMBOL_NAME(startup_32)-__PAGE_OFFSET
 			# jump to startup_32 in arch/i386/kernel/head.S
 
 idt_48:
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/i386/kernel/traps.c linux-2.4.27-leo/arch/i386/kernel/traps.c
--- linux-2.4.27/arch/i386/kernel/traps.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.27-leo/arch/i386/kernel/traps.c	2004-09-17 03:19:57.000000000 +0100
@@ -54,15 +54,10 @@
 asmlinkage void lcall7(void);
 asmlinkage void lcall27(void);
 
-struct desc_struct default_ldt[] = { { 0, 0 }, { 0, 0 }, { 0, 0 },
+const struct desc_struct default_ldt[] = { { 0, 0 }, { 0, 0 }, { 0, 0 },
 		{ 0, 0 }, { 0, 0 } };
 
-/*
- * The IDT has to be page-aligned to simplify the Pentium
- * F0 0F bug workaround.. We have a special link segment
- * for this.
- */
-struct desc_struct idt_table[256] __attribute__((__section__(".data.idt"))) = { {0, 0}, };
+extern struct desc_struct idt_table[256];
 
 asmlinkage void divide_error(void);
 asmlinkage void debug(void);
@@ -228,14 +223,23 @@
 		show_stack((unsigned long*)esp);
 
 		printk("\nCode: ");
+
+#ifndef CONFIG_GRKERNSEC_PAX_KERNEXEC
 		if(regs->eip < PAGE_OFFSET)
 			goto bad;
+#endif
 
 		for(i=0;i<20;i++)
 		{
 			unsigned char c;
+
+#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC
+			if(__get_user(c, &((unsigned char*)regs->eip)[i+__KERNEL_TEXT_OFFSET])) {
+#else
 			if(__get_user(c, &((unsigned char*)regs->eip)[i])) {
 bad:
+#endif
+
 				printk(" Bad EIP value.");
 				break;
 			}
@@ -258,8 +262,13 @@
 
 	eip = regs->eip;
 
+#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC
+	eip += __KERNEL_TEXT_OFFSET;
+#else
 	if (eip < PAGE_OFFSET)
 		goto no_bug;
+#endif
+
 	if (__get_user(ud2, (unsigned short *)eip))
 		goto no_bug;
 	if (ud2 != 0x0b0f)
@@ -267,7 +276,13 @@
 	if (__get_user(line, (unsigned short *)(eip + 2)))
 		goto bug;
 	if (__get_user(file, (char **)(eip + 4)) ||
+
+#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC
+		__get_user(c, file + __KERNEL_TEXT_OFFSET))
+#else
 		(unsigned long)file < PAGE_OFFSET || __get_user(c, file))
+#endif
+
 		file = "<bad filename>";
 
 	printk("kernel BUG at %s:%d!\n", file, line);
@@ -422,6 +437,13 @@
 			regs->eip = fixup;
 			return;
 		}
+
+#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC
+		if ((regs->xcs & 0xFFFF) == __KERNEL_CS)
+				die("PAX: suspicious general protection fault", regs, error_code);
+		else
+#endif
+
 		die("general protection fault", regs, error_code);
 	}
 }
@@ -527,13 +549,12 @@
 {
 	unsigned int condition;
 	struct task_struct *tsk = current;
-	unsigned long eip = regs->eip;
 	siginfo_t info;
 
 	__asm__ __volatile__("movl %%db6,%0" : "=r" (condition));
 
 	/* If the user set TF, it's simplest to clear it right away. */
-	if ((eip >=PAGE_OFFSET) && (regs->eflags & TF_MASK))
+	if (!(regs->xcs & 3) && (regs->eflags & TF_MASK) && !(regs->eflags & VM_MASK))
 		goto clear_TF;
 
 	/* Mask out spurious debug traps due to lazy DR7 setting */
@@ -751,6 +772,8 @@
  *
  * Careful.. There are problems with IBM-designed IRQ13 behaviour.
  * Don't touch unless you *really* know how it works.
+ *
+ * Must be called with kernel preemption disabled.
  */
 asmlinkage void math_state_restore(struct pt_regs regs)
 {
@@ -826,7 +849,7 @@
 	_set_gate(idt_table+n,15,3,addr);
 }
 
-static void __init set_call_gate(void *a, void *addr)
+static void __init set_call_gate(const void *a, void *addr)
 {
 	_set_gate(a,12,3,addr);
 }
@@ -852,14 +875,45 @@
 	"rorl $16,%%eax" \
 	: "=m"(*(n)) : "a" (addr), "r"(n), "ir"(limit), "i"(type))
 
-void set_tss_desc(unsigned int n, void *addr)
+void set_tss_desc(unsigned int n, const void *addr)
 {
 	_set_tssldt_desc(gdt_table+__TSS(n), (int)addr, 235, 0x89);
+
+#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC
+	_set_tssldt_desc(gdt_table2+__TSS(n), (int)addr, 235, 0x89);
+#endif
+
 }
 
-void set_ldt_desc(unsigned int n, void *addr, unsigned int size)
+void __set_ldt_desc(unsigned int n, const void *addr, unsigned int size)
 {
 	_set_tssldt_desc(gdt_table+__LDT(n), (int)addr, ((size << 3)-1), 0x82);
+
+#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC
+	_set_tssldt_desc(gdt_table2+__LDT(n), (int)addr, ((size << 3)-1), 0x82);
+#endif
+
+}
+
+void set_ldt_desc(unsigned int n, const void *addr, unsigned int size)
+{
+
+#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC
+	unsigned long flags, cr3;
+
+	pax_open_kernel(flags, cr3);
+#endif
+
+	_set_tssldt_desc(gdt_table+__LDT(n), (int)addr, ((size << 3)-1), 0x82);
+
+#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC
+	_set_tssldt_desc(gdt_table2+__LDT(n), (int)addr, ((size << 3)-1), 0x82);
+#endif
+
+#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC
+	pax_close_kernel(flags, cr3);
+#endif
+
 }
 
 #ifdef CONFIG_X86_VISWS_APIC
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/i386/kernel/vm86.c linux-2.4.27-leo/arch/i386/kernel/vm86.c
--- linux-2.4.27/arch/i386/kernel/vm86.c	2003-08-25 12:44:39.000000000 +0100
+++ linux-2.4.27-leo/arch/i386/kernel/vm86.c	2004-09-17 03:19:57.000000000 +0100
@@ -44,6 +44,7 @@
 #include <asm/pgalloc.h>
 #include <asm/io.h>
 #include <asm/irq.h>
+#include <asm/desc.h>
 
 /*
  * Known problems:
@@ -97,6 +98,10 @@
 	struct pt_regs *ret;
 	unsigned long tmp;
 
+#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC
+	unsigned long flags, cr3;
+#endif
+
 	if (!current->thread.vm86_info) {
 		printk("no vm86_info: BAD\n");
 		do_exit(SIGSEGV);
@@ -111,7 +116,17 @@
 		do_exit(SIGSEGV);
 	}
 	tss = init_tss + smp_processor_id();
+
+#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC
+	pax_open_kernel(flags, cr3);
+#endif
+
 	tss->esp0 = current->thread.esp0 = current->thread.saved_esp0;
+
+#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC
+	pax_close_kernel(flags, cr3);
+#endif
+
 	current->thread.saved_esp0 = 0;
 	ret = KVM86->regs32;
 	return ret;
@@ -237,6 +252,11 @@
 static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk)
 {
 	struct tss_struct *tss;
+
+#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC
+	unsigned long flags, cr3;
+#endif
+
 /*
  * make sure the vm86() system call doesn't try to do anything silly
  */
@@ -278,8 +298,17 @@
 	info->regs32->eax = 0;
 	tsk->thread.saved_esp0 = tsk->thread.esp0;
 	tss = init_tss + smp_processor_id();
+
+#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC
+	pax_open_kernel(flags, cr3);
+#endif
+
 	tss->esp0 = tsk->thread.esp0 = (unsigned long) &info->VM86_TSS_ESP0;
 
+#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC
+	pax_close_kernel(flags, cr3);
+#endif
+
 	tsk->thread.screen_bitmap = info->screen_bitmap;
 	if (info->flags & VM86_SCREEN_BITMAP)
 		mark_screen_rdonly(tsk);
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/i386/lib/dec_and_lock.c linux-2.4.27-leo/arch/i386/lib/dec_and_lock.c
--- linux-2.4.27/arch/i386/lib/dec_and_lock.c	2000-07-08 02:20:16.000000000 +0100
+++ linux-2.4.27-leo/arch/i386/lib/dec_and_lock.c	2004-09-17 03:19:36.000000000 +0100
@@ -8,6 +8,7 @@
  */
 
 #include <linux/spinlock.h>
+#include <linux/sched.h>
 #include <asm/atomic.h>
 
 int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/i386/Makefile linux-2.4.27-leo/arch/i386/Makefile
--- linux-2.4.27/arch/i386/Makefile	2003-06-13 15:51:29.000000000 +0100
+++ linux-2.4.27-leo/arch/i386/Makefile	2004-09-17 03:19:57.000000000 +0100
@@ -114,6 +114,9 @@
 
 MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
 
+arch/i386/vmlinux.lds: arch/i386/vmlinux.lds.S FORCE
+	$(CPP) -C -P -I$(HPATH) -D__KERNEL__ -imacros $(HPATH)/linux/config.h -imacros $(HPATH)/asm-i386/segment.h -imacros $(HPATH)/asm-i386/page.h -Ui386 arch/i386/vmlinux.lds.S >arch/i386/vmlinux.lds
+
 vmlinux: arch/i386/vmlinux.lds
 
 FORCE: ;
@@ -150,6 +153,7 @@
 	@$(MAKEBOOT) clean
 
 archmrproper:
+	rm -f arch/i386/vmlinux.lds
 
 archdep:
 	@$(MAKEBOOT) dep
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/i386/mm/fault.c linux-2.4.27-leo/arch/i386/mm/fault.c
--- linux-2.4.27/arch/i386/mm/fault.c	2004-09-17 02:38:42.000000000 +0100
+++ linux-2.4.27-leo/arch/i386/mm/fault.c	2004-09-17 03:19:57.000000000 +0100
@@ -19,6 +19,8 @@
 #include <linux/init.h>
 #include <linux/tty.h>
 #include <linux/vt_kern.h>		/* For unblank_screen() */
+#include <linux/unistd.h>
+#include <linux/compiler.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -127,6 +129,10 @@
 asmlinkage void do_invalid_op(struct pt_regs *, unsigned long);
 extern unsigned long idt;
 
+#if defined(CONFIG_GRKERNSEC_PAX_PAGEEXEC) || defined(CONFIG_GRKERNSEC_PAX_EMUTRAMP) || defined(CONFIG_GRKERNSEC_PAX_RANDEXEC)
+static int pax_handle_fetch_fault(struct pt_regs *regs);
+#endif
+
 /*
  * This routine handles page faults.  It determines the address,
  * and the problem, and then passes it off to one of the appropriate
@@ -137,23 +143,31 @@
  *	bit 1 == 0 means read, 1 means write
  *	bit 2 == 0 means kernel, 1 means user-mode
  */
-asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
+#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC
+static int do_page_fault(struct pt_regs *regs, unsigned long error_code, unsigned long address)
+#else
+asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long error_code)
+#endif
 {
 	struct task_struct *tsk;
 	struct mm_struct *mm;
 	struct vm_area_struct * vma;
+#ifndef CONFIG_GRKERNSEC_PAX_PAGEEXEC
 	unsigned long address;
+#endif
 	unsigned long page;
 	unsigned long fixup;
 	int write;
 	siginfo_t info;
 
+#ifndef CONFIG_GRKERNSEC_PAX_PAGEEXEC
 	/* get the address */
 	__asm__("movl %%cr2,%0":"=r" (address));
 
 	/* It's safe to allow irq's after cr2 has been saved */
 	if (regs->eflags & X86_EFLAGS_IF)
 		local_irq_enable();
+#endif
 
 	tsk = current;
 
@@ -258,7 +272,7 @@
 			tsk->thread.screen_bitmap |= 1 << bit;
 	}
 	up_read(&mm->mmap_sem);
-	return;
+	return 0;
 
 /*
  * Something tried to access memory that isn't in our memory map..
@@ -269,6 +283,37 @@
 
 	/* User mode accesses just cause a SIGSEGV */
 	if (error_code & 4) {
+#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC
+		if (current->flags & PF_PAX_SEGMEXEC) {
+
+#if defined(CONFIG_GRKERNSEC_PAX_EMUTRAMP) || defined(CONFIG_GRKERNSEC_PAX_RANDEXEC)
+		if ((error_code == 4) && (regs->eip + SEGMEXEC_TASK_SIZE == address)) {
+			switch (pax_handle_fetch_fault(regs)) {
+
+#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC
+			case 5:
+				return 0;
+#endif
+
+#ifdef CONFIG_GRKERNSEC_PAX_EMUTRAMP
+			case 4:
+				return 0;
+			case 3:
+			case 2:
+				return 1;
+#endif
+
+			}
+		}
+#endif
+
+			if (address >= SEGMEXEC_TASK_SIZE) {
+				pax_report_fault(regs, (void*)regs->eip, (void*)regs->esp);
+				do_exit(SIGKILL);
+			}
+		}
+#endif
+
 		tsk->thread.cr2 = address;
 		/* Kernel addresses are always protection faults */
 		tsk->thread.error_code = error_code | (address >= TASK_SIZE);
@@ -278,7 +323,7 @@
 		/* info.si_code has been set above */
 		info.si_addr = (void *)address;
 		force_sig_info(SIGSEGV, &info, tsk);
-		return;
+		return 0;
 	}
 
 	/*
@@ -291,7 +336,7 @@
 
 		if (nr == 6) {
 			do_invalid_op(regs, 0);
-			return;
+			return 0;
 		}
 	}
 
@@ -299,7 +344,7 @@
 	/* Are we prepared to handle this kernel fault?  */
 	if ((fixup = search_exception_table(regs->eip)) != 0) {
 		regs->eip = fixup;
-		return;
+		return 0;
 	}
 
 /*
@@ -311,6 +356,18 @@
 
 	if (address < PAGE_SIZE)
 		printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
+
+#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC
+	else if (init_mm.start_code + __KERNEL_TEXT_OFFSET <= address && address < init_mm.end_code + __KERNEL_TEXT_OFFSET) {
+		if (tsk->curr_ip)
+			printk(KERN_ERR "PAX: From %u.%u.%u.%u: %s:%d, uid/euid: %u/%u, attempted to modify kernel code",
+					 NIPQUAD(tsk->curr_ip), tsk->comm, tsk->pid, tsk->uid, tsk->euid);
+		else
+			printk(KERN_ERR "PAX: %s:%d, uid/euid: %u/%u, attempted to modify kernel code",
+					 tsk->comm, tsk->pid, tsk->uid, tsk->euid);
+	}
+#endif
+
 	else
 		printk(KERN_ALERT "Unable to handle kernel paging request");
 	printk(" at virtual address %08lx\n",address);
@@ -363,7 +420,7 @@
 	/* Kernel mode? Handle exceptions or die */
 	if (!(error_code & 4))
 		goto no_context;
-	return;
+	return 0;
 
 vmalloc_fault:
 	{
@@ -396,6 +453,448 @@
 		pte_k = pte_offset(pmd_k, address);
 		if (!pte_present(*pte_k))
 			goto no_context;
-		return;
+		return 0;
 	}
 }
+#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC
+/* PaX: called with the page_table_lock spinlock held */
+static inline pte_t * pax_get_pte(struct mm_struct *mm, unsigned long address)
+{
+	pgd_t *pgd;
+	pmd_t *pmd;
+
+	pgd = pgd_offset(mm, address);
+	if (!pgd || !pgd_present(*pgd))
+		return 0;
+	pmd = pmd_offset(pgd, address);
+	if (!pmd || !pmd_present(*pmd))
+		return 0;
+	return pte_offset(pmd, address);
+}
+#endif
+
+/*
+ * PaX: decide what to do with offenders (regs->eip = fault address)
+ *
+ * returns 1 when task should be killed
+ *         2 when sigreturn trampoline was detected
+ *         3 when rt_sigreturn trampoline was detected
+ *         4 when gcc trampoline was detected
+ *	   5 when legitimate ET_EXEC was detected
+ */
+#if defined(CONFIG_GRKERNSEC_PAX_PAGEEXEC) || defined(CONFIG_GRKERNSEC_PAX_SEGMEXEC)
+static int pax_handle_fetch_fault(struct pt_regs *regs)
+{
+#ifdef CONFIG_GRKERNSEC_PAX_EMUTRAMP
+	static const unsigned char trans[8] = {6, 1, 2, 0, 13, 5, 3, 4};
+#endif
+	int err;
+	
+#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC
+	if (current->flags & PF_PAX_RANDEXEC) {
+		unsigned long esp_4;
+		if (regs->eip >= current->mm->start_code &&
+		    regs->eip < current->mm->end_code)
+		{
+			err = get_user(esp_4, (unsigned long*)(regs->esp-4UL));
+			if (err || esp_4 == regs->eip)
+				return 1;
+			regs->eip += current->mm->delta_exec;
+			return 5;
+		}
+	}
+#endif
+
+#ifdef CONFIG_GRKERNSEC_PAX_EMUTRAMP
+
+#ifndef CONFIG_GRKERNSEC_PAX_EMUSIGRT
+	if (!(current->flags & PF_PAX_EMUTRAMP))
+		return 1;
+#endif
+
+	do { /* PaX: sigreturn emulation */
+		unsigned char pop, mov;
+		unsigned short sys;
+		unsigned long nr;
+
+		err = get_user(pop, (unsigned char *)(regs->eip));
+		err |= get_user(mov, (unsigned char *)(regs->eip + 1));
+		err |= get_user(nr, (unsigned long *)(regs->eip + 2));
+		err |= get_user(sys, (unsigned short *)(regs->eip + 6));
+
+		if (err)
+			break;
+
+		if (pop == 0x58 &&
+		    mov == 0xb8 &&
+		    nr == __NR_sigreturn &&
+		    sys == 0x80cd)
+		{
+
+#ifdef CONFIG_GRKERNSEC_PAX_EMUSIGRT
+			int sig;
+			struct k_sigaction *ka;
+			__sighandler_t handler;
+
+			if (get_user(sig, (int *)regs->esp))
+				return 1;
+			if (sig < 1 || sig > _NSIG || sig == SIGKILL || sig == SIGSTOP)
+				return 1;
+			ka = &current->sig->action[sig-1];
+			handler = ka->sa.sa_handler;
+			if (handler == SIG_DFL || handler == SIG_IGN) {
+				if (!(current->flags & PF_PAX_EMUTRAMP))
+					return 1;
+			} else if (ka->sa.sa_flags & SA_SIGINFO)
+				return 1;
+#endif
+
+			regs->esp += 4;
+			regs->eax = nr;
+			regs->eip += 8;
+			return 2;
+		}
+	} while (0);
+
+	do { /* PaX: rt_sigreturn emulation */
+		unsigned char mov;
+		unsigned short sys;
+		unsigned long nr;
+
+		err = get_user(mov, (unsigned char *)(regs->eip));
+		err |= get_user(nr, (unsigned long *)(regs->eip + 1));
+		err |= get_user(sys, (unsigned short *)(regs->eip + 5));
+
+		if (err)
+			break;
+
+		if (mov == 0xb8 &&
+		    nr == __NR_rt_sigreturn &&
+		    sys == 0x80cd)
+		{
+
+#ifdef CONFIG_GRKERNSEC_PAX_EMUSIGRT
+			int sig;
+			struct k_sigaction *ka;
+			__sighandler_t handler;
+
+			if (get_user(sig, (int *)regs->esp))
+				return 1;
+			if (sig < 1 || sig > _NSIG || sig == SIGKILL || sig == SIGSTOP)
+				return 1;
+			ka = &current->sig->action[sig-1];
+			handler = ka->sa.sa_handler;
+			if (handler == SIG_DFL || handler == SIG_IGN) {
+				if (!(current->flags & PF_PAX_EMUTRAMP))
+					return 1;
+			} else if (!(ka->sa.sa_flags & SA_SIGINFO))
+				return 1;
+#endif
+
+			regs->eax = nr;
+			regs->eip += 7;
+			return 3;
+		}
+	} while (0);
+
+#ifdef CONFIG_GRKERNSEC_PAX_EMUSIGRT
+	if (!(current->flags & PF_PAX_EMUTRAMP))
+		return 1;
+#endif
+
+	do { /* PaX: gcc trampoline emulation #1 */
+		unsigned char mov1, mov2;
+		unsigned short jmp;
+		unsigned long addr1, addr2, ret;
+		unsigned short call;
+
+		err = get_user(mov1, (unsigned char *)regs->eip);
+		err |= get_user(addr1, (unsigned long *)(regs->eip + 1));
+		err |= get_user(mov2, (unsigned char *)(regs->eip + 5));
+		err |= get_user(addr2, (unsigned long *)(regs->eip + 6));
+		err |= get_user(jmp, (unsigned short *)(regs->eip + 10));
+		err |= get_user(ret, (unsigned long *)regs->esp);
+
+		if (err)
+			break;
+
+		err = get_user(call, (unsigned short *)(ret-2));
+		if (err)
+			break;
+
+		if ((mov1 & 0xF8) == 0xB8 &&
+		    (mov2 & 0xF8) == 0xB8 &&
+		    (mov1 & 0x07) != (mov2 & 0x07) &&
+		    (jmp & 0xF8FF) == 0xE0FF &&
+		    (mov2 & 0x07) == ((jmp>>8) & 0x07) &&
+		    (call & 0xF8FF) == 0xD0FF &&
+		    regs->eip == ((unsigned long*)regs)[trans[(call>>8) & 0x07]])
+		{
+			((unsigned long *)regs)[trans[mov1 & 0x07]] = addr1;
+			((unsigned long *)regs)[trans[mov2 & 0x07]] = addr2;
+			regs->eip = addr2;
+			return 4;
+		}
+	} while (0);
+
+	do { /* PaX: gcc trampoline emulation #2 */
+		unsigned char mov, jmp;
+		unsigned long addr1, addr2, ret;
+		unsigned short call;
+
+		err = get_user(mov, (unsigned char *)regs->eip);
+		err |= get_user(addr1, (unsigned long *)(regs->eip + 1));
+		err |= get_user(jmp, (unsigned char *)(regs->eip + 5));
+		err |= get_user(addr2, (unsigned long *)(regs->eip + 6));
+		err |= get_user(ret, (unsigned long *)regs->esp);
+
+		if (err)
+			break;
+
+		err = get_user(call, (unsigned short *)(ret-2));
+		if (err)
+			break;
+
+		if ((mov & 0xF8) == 0xB8 &&
+		    jmp == 0xE9 &&
+		    (call & 0xF8FF) == 0xD0FF &&
+		    regs->eip == ((unsigned long*)regs)[trans[(call>>8) & 0x07]])
+		{
+			((unsigned long *)regs)[trans[mov & 0x07]] = addr1;
+			regs->eip += addr2 + 10;
+			return 4;
+		}
+	} while (0);
+
+	do { /* PaX: gcc trampoline emulation #3 */
+		unsigned char mov, jmp;
+		char offset;
+		unsigned long addr1, addr2, ret;
+		unsigned short call;
+
+		err = get_user(mov, (unsigned char *)regs->eip);
+		err |= get_user(addr1, (unsigned long *)(regs->eip + 1));
+		err |= get_user(jmp, (unsigned char *)(regs->eip + 5));
+		err |= get_user(addr2, (unsigned long *)(regs->eip + 6));
+		err |= get_user(ret, (unsigned long *)regs->esp);
+
+		if (err)
+			break;
+
+		err = get_user(call, (unsigned short *)(ret-3));
+		err |= get_user(offset, (char *)(ret-1));
+		if (err)
+			break;
+
+		if ((mov & 0xF8) == 0xB8 &&
+		    jmp == 0xE9 &&
+		    call == 0x55FF)
+		{
+			unsigned long addr;
+
+			err = get_user(addr, (unsigned long*)(regs->ebp + (unsigned long)(long)offset));
+			if (err || regs->eip != addr)
+				break;
+
+			((unsigned long *)regs)[trans[mov & 0x07]] = addr1;
+			regs->eip += addr2 + 10;
+			return 4;
+		}
+	} while (0);
+
+	do { /* PaX: gcc trampoline emulation #4 */
+		unsigned char mov, jmp, sib;
+		char offset;
+		unsigned long addr1, addr2, ret;
+		unsigned short call;
+
+		err = get_user(mov, (unsigned char *)regs->eip);
+		err |= get_user(addr1, (unsigned long *)(regs->eip + 1));
+		err |= get_user(jmp, (unsigned char *)(regs->eip + 5));
+		err |= get_user(addr2, (unsigned long *)(regs->eip + 6));
+		err |= get_user(ret, (unsigned long *)regs->esp);
+
+		if (err)
+			break;
+
+		err = get_user(call, (unsigned short *)(ret-4));
+		err |= get_user(sib, (unsigned char *)(ret-2));
+		err |= get_user(offset, (char *)(ret-1));
+		if (err)
+			break;
+
+		if ((mov & 0xF8) == 0xB8 &&
+		    jmp == 0xE9 &&
+		    call == 0x54FF &&
+		    sib == 0x24)
+		{
+			unsigned long addr;
+
+			err = get_user(addr, (unsigned long*)(regs->esp + 4 + (unsigned long)(long)offset));
+			if (err || regs->eip != addr)
+				break;
+
+			((unsigned long *)regs)[trans[mov & 0x07]] = addr1;
+			regs->eip += addr2 + 10;
+			return 4;
+		}
+	} while (0);
+
+	do { /* PaX: gcc trampoline emulation #5 */
+		unsigned char mov, jmp, sib;
+		unsigned long addr1, addr2, ret, offset;
+		unsigned short call;
+
+		err = get_user(mov, (unsigned char *)regs->eip);
+		err |= get_user(addr1, (unsigned long *)(regs->eip + 1));
+		err |= get_user(jmp, (unsigned char *)(regs->eip + 5));
+		err |= get_user(addr2, (unsigned long *)(regs->eip + 6));
+		err |= get_user(ret, (unsigned long *)regs->esp);
+
+		if (err)
+			break;
+
+		err = get_user(call, (unsigned short *)(ret-7));
+		err |= get_user(sib, (unsigned char *)(ret-5));
+		err |= get_user(offset, (unsigned long *)(ret-4));
+		if (err)
+			break;
+
+		if ((mov & 0xF8) == 0xB8 &&
+		    jmp == 0xE9 &&
+		    call == 0x94FF &&
+		    sib == 0x24)
+		{
+			unsigned long addr;
+
+			err = get_user(addr, (unsigned long*)(regs->esp + 4 + offset));
+			if (err || regs->eip != addr)
+				break;
+
+			((unsigned long *)regs)[trans[mov & 0x07]] = addr1;
+			regs->eip += addr2 + 10;
+			return 4;
+		}
+	} while (0);
+#endif
+
+	return 1; /* PaX in action */
+}
+#endif
+
+#if defined(CONFIG_GRKERNSEC_PAX_PAGEEXEC) || defined(CONFIG_GRKERNSEC_PAX_SEGMEXEC)
+void pax_report_insns(void *pc)
+{
+	unsigned long i;
+
+	printk(KERN_ERR "PAX: bytes at PC: ");
+	for (i = 0; i < 20; i++) {
+		unsigned char c;
+		if (get_user(c, (unsigned char*)pc+i)) {
+			printk("<invalid address>.");
+			break;
+		}
+		printk("%02x ", c);
+	}
+	printk("\n");
+}
+#endif
+
+#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC
+/*
+ * PaX: handle the extra page faults or pass it down to the original handler
+ *
+ * returns 0 when nothing special was detected
+ *         1 when sigreturn trampoline (syscall) has to be emulated
+ */
+asmlinkage int pax_do_page_fault(struct pt_regs *regs, unsigned long error_code)
+{
+	struct mm_struct *mm = current->mm;
+	unsigned long address;
+	pte_t *pte;
+	unsigned char pte_mask;
+	int ret;
+
+	__asm__("movl %%cr2,%0":"=r" (address));
+
+	/* It's safe to allow irq's after cr2 has been saved */
+	if (likely(regs->eflags & X86_EFLAGS_IF))
+		local_irq_enable();
+
+	if (unlikely((error_code & 5) != 5 ||
+		     address >= TASK_SIZE ||
+		     !(current->flags & PF_PAX_PAGEEXEC)))
+		return do_page_fault(regs, error_code, address);
+
+	/* PaX: it's our fault, let's handle it if we can */
+
+	/* PaX: take a look at read faults before acquiring any locks */
+	if (unlikely((error_code == 5) && (regs->eip == address))) { 
+		/* instruction fetch attempt from a protected page in user mode */
+		ret = pax_handle_fetch_fault(regs);
+		switch (ret) {
+#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC
+		case 5:
+			return 0;
+#endif
+
+#ifdef CONFIG_GRKERNSEC_PAX_EMUTRAMP
+		case 4:
+			return 0;
+		case 3:
+		case 2:
+			return 1;
+#endif
+		}
+		pax_report_fault(regs, (void*)regs->eip, (void*)regs->esp);
+		do_exit(SIGKILL);
+	}
+
+	pte_mask = _PAGE_ACCESSED | _PAGE_USER | ((error_code & 2) << (_PAGE_BIT_DIRTY-1));
+
+	spin_lock(&mm->page_table_lock);
+	pte = pax_get_pte(mm, address);
+	if (unlikely(!pte || !(pte_val(*pte) & _PAGE_PRESENT) || pte_exec(*pte))) {
+		spin_unlock(&mm->page_table_lock);
+		do_page_fault(regs, error_code, address);
+		return 0;
+	}
+
+	if (unlikely((error_code == 7) && !pte_write(*pte))) {
+		/* write attempt to a protected page in user mode */
+		spin_unlock(&mm->page_table_lock);
+		do_page_fault(regs, error_code, address);
+		return 0;
+	}
+
+	/*
+	 * PaX: fill DTLB with user rights and retry
+	 */
+	__asm__ __volatile__ (
+		"orb %2,%1\n"
+#if defined(CONFIG_M586) || defined(CONFIG_M586TSC)
+/*   
+ * PaX: let this uncommented 'invlpg' remind us on the behaviour of Intel's   
+ * (and AMD's) TLBs. namely, they do not cache PTEs that would raise *any*
+ * page fault when examined during a TLB load attempt. this is true not only
+ * for PTEs holding a non-present entry but also present entries that will
+ * raise a page fault (such as those set up by PaX, or the copy-on-write
+ * mechanism). in effect it means that we do *not* need to flush the TLBs
+ * for our target pages since their PTEs are simply not in the TLBs at all.
+ * the best thing in omitting it is that we gain around 15-20% speed in the
+ * fast path of the page fault handler and can get rid of tracing since we
+ * can no longer flush unintended entries.
+ */
+
+		"invlpg %0\n"
+#endif
+
+		"testb $0,%0\n"
+		"xorb %3,%1\n"
+		:
+		: "m" (*(char*)address), "m" (*(char*)pte) , "q" (pte_mask) , "i" (_PAGE_USER)
+		: "memory", "cc");
+	spin_unlock(&mm->page_table_lock);
+	return 0;
+}
+#endif
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/i386/mm/init.c linux-2.4.27-leo/arch/i386/mm/init.c
--- linux-2.4.27/arch/i386/mm/init.c	2004-05-19 21:34:36.000000000 +0100
+++ linux-2.4.27-leo/arch/i386/mm/init.c	2004-09-17 03:19:57.000000000 +0100
@@ -37,6 +37,7 @@
 #include <asm/e820.h>
 #include <asm/apic.h>
 #include <asm/tlb.h>
+#include <asm/desc.h>
 
 mmu_gather_t mmu_gathers[NR_CPUS];
 unsigned long highstart_pfn, highend_pfn;
@@ -46,6 +47,7 @@
 int do_check_pgt_cache(int low, int high)
 {
 	int freed = 0;
+	preempt_disable();
 	if(pgtable_cache_size > high) {
 		do {
 			if (pgd_quicklist) {
@@ -62,6 +64,7 @@
 			}
 		} while(pgtable_cache_size > low);
 	}
+	preempt_enable();
 	return freed;
 }
 
@@ -122,7 +125,7 @@
 
 /* References to section boundaries */
 
-extern char _text, _etext, _edata, __bss_start, _end;
+extern char _text, _etext, _data, _edata, __bss_start, _end;
 extern char __init_begin, __init_end;
 
 static inline void set_pte_phys (unsigned long vaddr,
@@ -365,6 +368,10 @@
 
 	__flush_tlb_all();
 
+#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC
+	memcpy(kernexec_pg_dir, swapper_pg_dir, sizeof(kernexec_pg_dir));
+#endif
+
 #ifdef CONFIG_HIGHMEM
 	kmap_init();
 #endif
@@ -529,7 +536,7 @@
 	reservedpages = free_pages_init();
 
 	codesize =  (unsigned long) &_etext - (unsigned long) &_text;
-	datasize =  (unsigned long) &_edata - (unsigned long) &_etext;
+	datasize =  (unsigned long) &_edata - (unsigned long) &_data;
 	initsize =  (unsigned long) &__init_end - (unsigned long) &__init_begin;
 
 	printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init, %ldk highmem)\n",
@@ -597,6 +604,43 @@
 		totalram_pages++;
 	}
 	printk (KERN_INFO "Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10);
+
+#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC
+	/* PaX: limit KERNEL_CS to actual size */
+	{
+		unsigned long limit;
+		pgd_t *pgd;
+		pmd_t *pmd;
+
+		limit = (unsigned long)&_etext >> PAGE_SHIFT;
+		gdt_table[2].a = (gdt_table[2].a & 0xFFFF0000UL) | (limit & 0x0FFFFUL);
+		gdt_table[2].b = (gdt_table[2].b & 0xFFF0FFFFUL) | (limit & 0xF0000UL);
+
+#ifdef CONFIG_PCI_BIOS
+		printk(KERN_INFO "PAX: warning, PCI BIOS might still be in use, keeping flat KERNEL_CS.\n");
+#endif
+
+#ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC
+		gdt_table2[2].a = (gdt_table2[2].a & 0xFFFF0000UL) | (limit & 0x0FFFFUL);
+		gdt_table2[2].b = (gdt_table2[2].b & 0xFFF0FFFFUL) | (limit & 0xF0000UL);
+#endif
+
+	/* PaX: make KERNEL_CS read-only */
+		for (addr = __KERNEL_TEXT_OFFSET; addr < __KERNEL_TEXT_OFFSET + 0x00400000UL; addr += (1UL << PMD_SHIFT)) {
+			pgd = pgd_offset_k(addr);
+			pmd = pmd_offset(pgd, addr);
+			set_pmd(pmd, __pmd(pmd_val(*pmd) & ~_PAGE_GLOBAL));
+		}
+		memcpy(kernexec_pg_dir, swapper_pg_dir, sizeof(kernexec_pg_dir));
+		for (addr = __KERNEL_TEXT_OFFSET; addr < __KERNEL_TEXT_OFFSET + 0x00400000UL; addr += (1UL << PMD_SHIFT)) {
+			pgd = pgd_offset_k(addr);
+			pmd = pmd_offset(pgd, addr);
+			set_pmd(pmd, __pmd(pmd_val(*pmd) & ~_PAGE_RW));
+		}
+		flush_tlb_all();
+	}
+#endif
+
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/i386/mm/ioremap.c linux-2.4.27-leo/arch/i386/mm/ioremap.c
--- linux-2.4.27/arch/i386/mm/ioremap.c	2003-11-28 18:26:19.000000000 +0000
+++ linux-2.4.27-leo/arch/i386/mm/ioremap.c	2004-09-17 03:19:57.000000000 +0100
@@ -49,7 +49,7 @@
 	if (address >= end)
 		BUG();
 	do {
-		pte_t * pte = pte_alloc(&init_mm, pmd, address);
+		pte_t * pte = pte_alloc_kernel(&init_mm, pmd, address);
 		if (!pte)
 			return -ENOMEM;
 		remap_area_pte(pte, address, end - address, address + phys_addr, flags);
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/i386/vmlinux.lds linux-2.4.27-leo/arch/i386/vmlinux.lds
--- linux-2.4.27/arch/i386/vmlinux.lds	2002-02-25 19:37:53.000000000 +0000
+++ linux-2.4.27-leo/arch/i386/vmlinux.lds	1970-01-01 01:00:00.000000000 +0100
@@ -1,82 +0,0 @@
-/* ld script to make i386 Linux kernel
- * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>;
- */
-OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
-OUTPUT_ARCH(i386)
-ENTRY(_start)
-SECTIONS
-{
-  . = 0xC0000000 + 0x100000;
-  _text = .;			/* Text and read-only data */
-  .text : {
-	*(.text)
-	*(.fixup)
-	*(.gnu.warning)
-	} = 0x9090
-
-  _etext = .;			/* End of text section */
-
-  .rodata : { *(.rodata) *(.rodata.*) }
-  .kstrtab : { *(.kstrtab) }
-
-  . = ALIGN(16);		/* Exception table */
-  __start___ex_table = .;
-  __ex_table : { *(__ex_table) }
-  __stop___ex_table = .;
-
-  __start___ksymtab = .;	/* Kernel symbol table */
-  __ksymtab : { *(__ksymtab) }
-  __stop___ksymtab = .;
-
-  .data : {			/* Data */
-	*(.data)
-	CONSTRUCTORS
-	}
-
-  _edata = .;			/* End of data section */
-
-  . = ALIGN(8192);		/* init_task */
-  .data.init_task : { *(.data.init_task) }
-
-  . = ALIGN(4096);		/* Init code and data */
-  __init_begin = .;
-  .text.init : { *(.text.init) }
-  .data.init : { *(.data.init) }
-  . = ALIGN(16);
-  __setup_start = .;
-  .setup.init : { *(.setup.init) }
-  __setup_end = .;
-  __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
-  __initcall_end = .;
-  . = ALIGN(4096);
-  __init_end = .;
-
-  . = ALIGN(4096);
-  .data.page_aligned : { *(.data.idt) }
-
-  . = ALIGN(32);
-  .data.cacheline_aligned : { *(.data.cacheline_aligned) }
-
-  __bss_start = .;		/* BSS */
-  .bss : {
-	*(.bss)
-	}
-  _end = . ;
-
-  /* Sections to be discarded */
-  /DISCARD/ : {
-	*(.text.exit)
-	*(.data.exit)
-	*(.exitcall.exit)
-	}
-
-  /* Stabs debugging sections.  */
-  .stab 0 : { *(.stab) }
-  .stabstr 0 : { *(.stabstr) }
-  .stab.excl 0 : { *(.stab.excl) }
-  .stab.exclstr 0 : { *(.stab.exclstr) }
-  .stab.index 0 : { *(.stab.index) }
-  .stab.indexstr 0 : { *(.stab.indexstr) }
-  .comment 0 : { *(.comment) }
-}
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/i386/vmlinux.lds.S linux-2.4.27-leo/arch/i386/vmlinux.lds.S
--- linux-2.4.27/arch/i386/vmlinux.lds.S	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.27-leo/arch/i386/vmlinux.lds.S	2004-09-17 03:19:57.000000000 +0100
@@ -0,0 +1,125 @@
+/* ld script to make i386 Linux kernel
+ * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>;
+ */
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH(i386)
+ENTRY(_start)
+SECTIONS
+{
+  . = __PAGE_OFFSET + 0x100000;
+  .text.startup : {
+	BYTE(0xEA) /* jmp far */
+	LONG(startup_32 + __KERNEL_TEXT_OFFSET - __PAGE_OFFSET)
+	SHORT(__KERNEL_CS)
+	}
+
+  . = ALIGN(32);
+  _data = .;
+  .data : {			/* Data */
+	*(.data)
+	CONSTRUCTORS
+	}
+
+  . = ALIGN(32);
+  .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+
+  . = ALIGN(8192);
+  .data.init_task : { *(.data.init_task) }
+
+  . = ALIGN(4096);
+  .data.page_aligned : {
+	*(.data.swapper_pg_dir)
+	*(.data.pg0)
+	*(.data.pg1)
+	*(.data.pg2)
+	}
+
+  _edata = .;			/* End of data section */
+
+  __bss_start = .;		/* BSS */
+  .bss : {
+	*(.bss)
+	LONG(0)
+	} 
+  __bss_end = . ;
+
+  . = ALIGN(4096);		/* Init code and data */
+  __init_begin = .;
+  .data.init : { *(.data.init) }
+  . = ALIGN(16);
+  __setup_start = .;
+  .setup.init : { *(.setup.init) }
+  __setup_end = .;
+  __initcall_start = .;
+  .initcall.init : { *(.initcall.init) }
+  __initcall_end = .;
+
+#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC
+  __text_init_start = .;
+  .text.init (. - __KERNEL_TEXT_OFFSET) : AT (__text_init_start) {
+	*(.text.init)
+	. = ALIGN(4*1024*1024) - 1;
+	BYTE(0)
+	}
+  __init_end = . + __KERNEL_TEXT_OFFSET;
+
+/*
+ * PaX: this must be kept in synch with the KERNEL_CS base
+ * in the GDTs in arch/i386/kernel/head.S
+ */
+  _text = .;			/* Text and read-only data */
+  .text : AT (. + __KERNEL_TEXT_OFFSET) {
+#else
+  .text.init : { *(.text.init) }
+  . = ALIGN(4096);
+  __init_end = .;
+  _text = .;			/* Text and read-only data */
+  .text : {
+#endif
+
+	*(.text)
+	*(.fixup)
+	*(.gnu.warning)
+	} = 0x9090
+
+  _etext = .;			/* End of text section */
+  . = ALIGN(4096);
+  . += __KERNEL_TEXT_OFFSET;
+  .rodata.page_aligned : {
+	*(.rodata.empty_zero_page)
+	*(.rodata.idt)
+	}
+  .rodata : { *(.rodata) *(.rodata.*) }
+  .kstrtab : { *(.kstrtab) }
+
+  . = ALIGN(16);		/* Exception table */
+  __start___ex_table = .;
+  __ex_table : { *(__ex_table) }
+  __stop___ex_table = .;
+
+  __start___ksymtab = .;	/* Kernel symbol table */
+  __ksymtab : { *(__ksymtab) }
+  __stop___ksymtab = .;
+
+#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC
+  _end = ALIGN(4*1024*1024);
+#else
+  _end = .;
+#endif
+
+  /* Sections to be discarded */
+  /DISCARD/ : {
+	*(.text.exit)
+	*(.data.exit)
+	*(.exitcall.exit)
+	}
+
+  /* Stabs debugging sections.  */
+  .stab 0 : { *(.stab) }
+  .stabstr 0 : { *(.stabstr) }
+  .stab.excl 0 : { *(.stab.excl) }
+  .stab.exclstr 0 : { *(.stab.exclstr) }
+  .stab.index 0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment 0 : { *(.comment) }
+}
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/ia64/config.in linux-2.4.27-leo/arch/ia64/config.in
--- linux-2.4.27/arch/ia64/config.in	2004-02-20 14:11:37.000000000 +0000
+++ linux-2.4.27-leo/arch/ia64/config.in	2004-09-17 03:19:58.000000000 +0100
@@ -319,3 +319,12 @@
 int 'Kernel messages buffer length shift (0 = default)' CONFIG_LOG_BUF_SHIFT 0
 
 endmenu
+
+mainmenu_option next_comment
+comment 'Grsecurity'
+bool 'Grsecurity' CONFIG_GRKERNSEC
+if [ "$CONFIG_GRKERNSEC" = "y" ]; then
+    source grsecurity/Config.in
+fi
+endmenu
+
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/ia64/kernel/ptrace.c linux-2.4.27-leo/arch/ia64/kernel/ptrace.c
--- linux-2.4.27/arch/ia64/kernel/ptrace.c	2004-05-19 21:34:36.000000000 +0100
+++ linux-2.4.27-leo/arch/ia64/kernel/ptrace.c	2004-09-17 03:19:58.000000000 +0100
@@ -16,6 +16,7 @@
 #include <linux/ptrace.h>
 #include <linux/smp_lock.h>
 #include <linux/user.h>
+#include <linux/grsecurity.h>
 
 #include <asm/pgtable.h>
 #include <asm/processor.h>
@@ -1299,6 +1300,9 @@
 	if (pid == 1)		/* no messing around with init! */
 		goto out_tsk;
 
+	if (gr_handle_ptrace(child, request))
+		goto out_tsk;
+
 	if (request == PTRACE_ATTACH) {
 		ret = ptrace_attach(child);
 		goto out_tsk;
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/ia64/kernel/sys_ia64.c linux-2.4.27-leo/arch/ia64/kernel/sys_ia64.c
--- linux-2.4.27/arch/ia64/kernel/sys_ia64.c	2004-02-20 14:11:37.000000000 +0000
+++ linux-2.4.27-leo/arch/ia64/kernel/sys_ia64.c	2004-09-17 03:19:58.000000000 +0100
@@ -16,6 +16,7 @@
 #include <linux/smp_lock.h>
 #include <linux/highuid.h>
 #include <linux/hugetlb.h>
+#include <linux/grsecurity.h>
 
 #include <asm/shmparam.h>
 #include <asm/uaccess.h>
@@ -211,6 +212,11 @@
 		goto out;
 	}
 
+	if (gr_handle_mmap(file, prot)) {
+		addr = -EACCES;
+		goto out;
+	}
+
 	down_write(&current->mm->mmap_sem);
 	addr = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
 	up_write(&current->mm->mmap_sem);
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/m68k/config.in linux-2.4.27-leo/arch/m68k/config.in
--- linux-2.4.27/arch/m68k/config.in	2004-02-20 14:11:37.000000000 +0000
+++ linux-2.4.27-leo/arch/m68k/config.in	2004-09-17 03:19:58.000000000 +0100
@@ -557,3 +557,11 @@
 
 source crypto/Config.in
 source lib/Config.in
+
+mainmenu_option next_comment
+comment 'Grsecurity'
+bool 'Grsecurity' CONFIG_GRKERNSEC
+if [ "$CONFIG_GRKERNSEC" = "y" ]; then
+	source grsecurity/Config.in
+fi
+endmenu
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/mips/config.in linux-2.4.27-leo/arch/mips/config.in
--- linux-2.4.27/arch/mips/config.in	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.27-leo/arch/mips/config.in	2004-09-17 03:19:58.000000000 +0100
@@ -7,3 +7,11 @@
 define_bool CONFIG_MIPS64 n
 
 source arch/mips/config-shared.in
+
+mainmenu_option next_comment
+comment 'Grsecurity'
+bool 'Grsecurity' CONFIG_GRKERNSEC
+if [ "$CONFIG_GRKERNSEC" = "y" ]; then
+        source grsecurity/Config.in
+fi
+endmenu
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/mips/config-shared.in linux-2.4.27-leo/arch/mips/config-shared.in
--- linux-2.4.27/arch/mips/config-shared.in	2004-02-20 14:11:37.000000000 +0000
+++ linux-2.4.27-leo/arch/mips/config-shared.in	2004-09-17 03:19:36.000000000 +0100
@@ -937,6 +937,7 @@
    define_bool CONFIG_HOTPLUG_PCI n
 fi
 
+dep_bool 'Preemptible Kernel' CONFIG_PREEMPT $CONFIG_NEW_IRQ
 bool 'System V IPC' CONFIG_SYSVIPC
 bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
 bool 'Sysctl support' CONFIG_SYSCTL
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/mips/kernel/i8259.c linux-2.4.27-leo/arch/mips/kernel/i8259.c
--- linux-2.4.27/arch/mips/kernel/i8259.c	2003-08-25 12:44:40.000000000 +0100
+++ linux-2.4.27-leo/arch/mips/kernel/i8259.c	2004-09-17 03:19:36.000000000 +0100
@@ -8,6 +8,7 @@
  * Copyright (C) 1992 Linus Torvalds
  * Copyright (C) 1994 - 2000 Ralf Baechle
  */
+#include <linux/sched.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/mips/kernel/irq.c linux-2.4.27-leo/arch/mips/kernel/irq.c
--- linux-2.4.27/arch/mips/kernel/irq.c	2004-02-20 14:11:38.000000000 +0000
+++ linux-2.4.27-leo/arch/mips/kernel/irq.c	2004-09-17 03:19:36.000000000 +0100
@@ -8,6 +8,8 @@
  * Copyright (C) 1992 Linus Torvalds
  * Copyright (C) 1994 - 2000 Ralf Baechle
  */
+
+#include <linux/sched.h>
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
@@ -19,11 +21,13 @@
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/random.h>
-#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/ptrace.h>
 
 #include <asm/atomic.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
+#include <asm/debug.h>
 
 /*
  * Controller mappings for all interrupt sources:
@@ -429,6 +433,8 @@
 	struct irqaction * action;
 	unsigned int status;
 
+	preempt_disable();
+
 	kstat.irqs[cpu][irq]++;
 	spin_lock(&desc->lock);
 	desc->handler->ack(irq);
@@ -490,6 +496,27 @@
 
 	if (softirq_pending(cpu))
 		do_softirq();
+
+#if defined(CONFIG_PREEMPT)
+	while (--current->preempt_count == 0) {
+		db_assert(intr_off());
+		db_assert(!in_interrupt());
+
+		if (current->need_resched == 0) {
+			break;
+		}
+
+		current->preempt_count ++;
+		sti();
+		if (user_mode(regs)) {
+			schedule();
+		} else {
+			preempt_schedule();
+		}
+		cli();
+	}
+#endif
+
 	return 1;
 }
 
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/mips/mm/extable.c linux-2.4.27-leo/arch/mips/mm/extable.c
--- linux-2.4.27/arch/mips/mm/extable.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.27-leo/arch/mips/mm/extable.c	2004-09-17 03:19:36.000000000 +0100
@@ -3,6 +3,7 @@
  */
 #include <linux/config.h>
 #include <linux/module.h>
+#include <linux/sched.h>
 #include <linux/spinlock.h>
 #include <asm/uaccess.h>
 
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/mips/mm/fault.c linux-2.4.27-leo/arch/mips/mm/fault.c
--- linux-2.4.27/arch/mips/mm/fault.c	2003-08-25 12:44:40.000000000 +0100
+++ linux-2.4.27-leo/arch/mips/mm/fault.c	2004-09-17 03:19:58.000000000 +0100
@@ -69,6 +69,24 @@
 	}
 }
 
+#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC
+void pax_report_insns(void *pc)
+{
+	unsigned long i;
+
+	printk(KERN_ERR "PAX: bytes at PC: ");
+	for (i = 0; i < 5; i++) {
+		unsigned int c;
+		if (get_user(c, (unsigned int*)pc+i)) {
+			printk("<invalid address>.");
+			break;
+		}
+		printk("%08x ", c);
+	}
+	printk("\n");
+}
+#endif
+
 /*
  * This routine handles page faults.  It determines the address,
  * and the problem, and then passes it off to one of the appropriate
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/mips64/config.in linux-2.4.27-leo/arch/mips64/config.in
--- linux-2.4.27/arch/mips64/config.in	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.27-leo/arch/mips64/config.in	2004-09-17 03:19:58.000000000 +0100
@@ -7,3 +7,11 @@
 define_bool CONFIG_MIPS64 y
 
 source arch/mips/config-shared.in
+
+mainmenu_option next_comment
+comment 'Grsecurity'
+bool 'Grsecurity' CONFIG_GRKERNSEC
+if [ "$CONFIG_GRKERNSEC" = "y" ]; then
+        source grsecurity/Config.in
+fi
+endmenu
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/mips64/kernel/ioctl32.c linux-2.4.27-leo/arch/mips64/kernel/ioctl32.c
--- linux-2.4.27/arch/mips64/kernel/ioctl32.c	2004-02-20 14:11:38.000000000 +0000
+++ linux-2.4.27-leo/arch/mips64/kernel/ioctl32.c	2004-09-17 03:19:08.000000000 +0100
@@ -62,6 +62,7 @@
 
 #include <linux/mtd/mtd.h>
 #include <linux/serial.h>
+#include <linux/dm-ioctl.h>
 
 #ifdef CONFIG_SIBYTE_TBPROF
 #include <asm/sibyte/trace_prof.h>
@@ -2327,6 +2328,22 @@
 	IOCTL32_DEFAULT(RESTART_ARRAY_RW),
 #endif /* CONFIG_MD */
 
+#if defined(CONFIG_BLK_DEV_DM) || defined(CONFIG_BLK_DEV_DM_MODULE)
+	IOCTL32_DEFAULT(DM_VERSION),
+	IOCTL32_DEFAULT(DM_REMOVE_ALL),
+	IOCTL32_DEFAULT(DM_DEV_CREATE),
+	IOCTL32_DEFAULT(DM_DEV_REMOVE),
+	IOCTL32_DEFAULT(DM_TABLE_LOAD),
+	IOCTL32_DEFAULT(DM_DEV_SUSPEND),
+	IOCTL32_DEFAULT(DM_DEV_RENAME),
+	IOCTL32_DEFAULT(DM_TABLE_DEPS),
+	IOCTL32_DEFAULT(DM_DEV_STATUS),
+	IOCTL32_DEFAULT(DM_TABLE_STATUS),
+	IOCTL32_DEFAULT(DM_DEV_WAIT),
+	IOCTL32_DEFAULT(DM_LIST_DEVICES),
+	IOCTL32_DEFAULT(DM_TABLE_CLEAR),
+#endif /* CONFIG_BLK_DEV_DM */
+
 #ifdef CONFIG_SIBYTE_TBPROF
 	IOCTL32_DEFAULT(SBPROF_ZBSTART),
 	IOCTL32_DEFAULT(SBPROF_ZBSTOP),
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/mips64/mm/fault.c linux-2.4.27-leo/arch/mips64/mm/fault.c
--- linux-2.4.27/arch/mips64/mm/fault.c	2004-02-20 14:11:38.000000000 +0000
+++ linux-2.4.27-leo/arch/mips64/mm/fault.c	2004-09-17 03:19:58.000000000 +0100
@@ -90,6 +90,24 @@
 	}
 }
 
+#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC
+void pax_report_insns(void *pc)
+{
+	unsigned long i;
+
+	printk(KERN_ERR "PAX: bytes at PC: ");
+	for (i = 0; i < 5; i++) {
+		unsigned int c;
+		if (get_user(c, (unsigned int*)pc+i)) {
+			printk("<invalid address>.");
+			break;
+		}
+		printk("%08x ", c);
+	}
+	printk("\n");
+}
+#endif
+
 /*
  * This routine handles page faults.  It determines the address,
  * and the problem, and then passes it off to one of the appropriate
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/parisc/config.in linux-2.4.27-leo/arch/parisc/config.in
--- linux-2.4.27/arch/parisc/config.in	2004-02-20 14:11:38.000000000 +0000
+++ linux-2.4.27-leo/arch/parisc/config.in	2004-09-17 03:19:58.000000000 +0100
@@ -204,3 +204,11 @@
 
 source crypto/Config.in
 source lib/Config.in
+
+mainmenu_option next_comment
+comment 'Grsecurity'
+bool 'Grsecurity' CONFIG_GRKERNSEC
+if [ "$CONFIG_GRKERNSEC" = "y" ]; then
+	source grsecurity/Config.in
+fi
+endmenu
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/parisc/kernel/ioctl32.c linux-2.4.27-leo/arch/parisc/kernel/ioctl32.c
--- linux-2.4.27/arch/parisc/kernel/ioctl32.c	2003-08-25 12:44:40.000000000 +0100
+++ linux-2.4.27-leo/arch/parisc/kernel/ioctl32.c	2004-09-17 03:19:58.000000000 +0100
@@ -55,6 +55,7 @@
 #define max max */
 #include <linux/lvm.h>
 #endif /* LVM */
+#include <linux/dm-ioctl.h>
 
 #include <scsi/scsi.h>
 /* Ugly hack. */
@@ -1434,7 +1435,11 @@
 	 * To have permissions to do most of the vt ioctls, we either have
 	 * to be the owner of the tty, or super-user.
 	 */
+#ifdef CONFIG_GRKERNSEC
+	if (current->tty == tty || capable(CAP_SYS_TTY_CONFIG))
+#else
 	if (current->tty == tty || suser())
+#endif
 		return 1;
 	return 0;                                                    
 }
@@ -3423,6 +3428,22 @@
 COMPATIBLE_IOCTL(LV_BMAP)
 COMPATIBLE_IOCTL(LV_SNAPSHOT_USE_RATE)
 #endif /* LVM */
+/* Device-Mapper */
+#if defined(CONFIG_BLK_DEV_DM) || defined(CONFIG_BLK_DEV_DM_MODULE)
+COMPATIBLE_IOCTL(DM_VERSION)
+COMPATIBLE_IOCTL(DM_REMOVE_ALL)
+COMPATIBLE_IOCTL(DM_DEV_CREATE)
+COMPATIBLE_IOCTL(DM_DEV_REMOVE)
+COMPATIBLE_IOCTL(DM_TABLE_LOAD)
+COMPATIBLE_IOCTL(DM_DEV_SUSPEND)
+COMPATIBLE_IOCTL(DM_DEV_RENAME)
+COMPATIBLE_IOCTL(DM_TABLE_DEPS)
+COMPATIBLE_IOCTL(DM_DEV_STATUS)
+COMPATIBLE_IOCTL(DM_TABLE_STATUS)
+COMPATIBLE_IOCTL(DM_DEV_WAIT)
+COMPATIBLE_IOCTL(DM_LIST_DEVICES)
+COMPATIBLE_IOCTL(DM_TABLE_CLEAR)
+#endif /* CONFIG_BLK_DEV_DM */
 #if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE)
 COMPATIBLE_IOCTL(DRM_IOCTL_GET_MAGIC)
 COMPATIBLE_IOCTL(DRM_IOCTL_IRQ_BUSID)
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/parisc/kernel/ptrace.c linux-2.4.27-leo/arch/parisc/kernel/ptrace.c
--- linux-2.4.27/arch/parisc/kernel/ptrace.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.27-leo/arch/parisc/kernel/ptrace.c	2004-09-17 03:19:58.000000000 +0100
@@ -15,7 +15,7 @@
 #include <linux/ptrace.h>
 #include <linux/user.h>
 #include <linux/personality.h>
-
+#include <linux/grsecurity.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
@@ -119,6 +119,9 @@
 	if (pid == 1)		/* no messing around with init! */
 		goto out_tsk;
 
+	if (gr_handle_ptrace(child, request))
+		goto out_tsk;
+
 	if (request == PTRACE_ATTACH) {
 		ret = ptrace_attach(child);
 		goto out_tsk;
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/parisc/kernel/sys_parisc32.c linux-2.4.27-leo/arch/parisc/kernel/sys_parisc32.c
--- linux-2.4.27/arch/parisc/kernel/sys_parisc32.c	2003-06-13 15:51:31.000000000 +0100
+++ linux-2.4.27-leo/arch/parisc/kernel/sys_parisc32.c	2004-09-17 03:19:58.000000000 +0100
@@ -50,6 +50,7 @@
 #include <linux/highmem.h>
 #include <linux/highuid.h>
 #include <linux/mman.h>
+#include <linux/grsecurity.h>
 
 #include <asm/types.h>
 #include <asm/uaccess.h>
@@ -177,6 +178,11 @@
 	struct file *file;
 	int retval;
 	int i;
+#ifdef CONFIG_GRKERNSEC
+	struct file *old_exec_file;
+	struct acl_subject_label *old_acl;
+	struct rlimit old_rlim[RLIM_NLIMITS];
+#endif
 
 	file = open_exec(filename);
 
@@ -184,7 +190,26 @@
 	if (IS_ERR(file))
 		return retval;
 
+	gr_learn_resource(current, RLIMIT_NPROC, atomic_read(&current->user->processes), 1);
+
+	if (gr_handle_nproc()) {
+		allow_write_access(file);
+		fput(file);
+		return -EAGAIN;
+	}
+
+	if (!gr_acl_handle_execve(file->f_dentry, file->f_vfsmnt)) {
+		allow_write_access(file);
+		fput(file);
+		return -EACCES;
+	}
+
 	bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
+
+#ifdef CONFIG_GRKERNSEC_PAX_RANDUSTACK
+	bprm.p -= (get_random_long() & ~(sizeof(void *)-1)) & ~PAGE_MASK;
+#endif
+
 	memset(bprm.page, 0, MAX_ARG_PAGES*sizeof(bprm.page[0]));
 
 	DBG(("do_execve32(%s, %p, %p, %p)\n", filename, argv, envp, regs));
@@ -209,11 +234,24 @@
 	if (retval < 0)
 		goto out;
 	
+	if (!gr_tpe_allow(file)) {
+		retval = -EACCES;
+		goto out;
+	}
+
+	if (gr_check_crash_exec(file)) {
+		retval = -EACCES;
+		goto out;
+	}
+
 	retval = copy_strings_kernel(1, &bprm.filename, &bprm);
 	if (retval < 0)
 		goto out;
 
 	bprm.exec = bprm.p;
+
+	gr_log_chroot_exec(file->f_dentry, file->f_vfsmnt);
+
 	retval = copy_strings32(bprm.envc, envp, &bprm);
 	if (retval < 0)
 		goto out;
@@ -222,11 +260,32 @@
 	if (retval < 0)
 		goto out;
 
+#ifdef CONFIG_GRKERNSEC
+	old_acl = current->acl;
+	memcpy(old_rlim, current->rlim, sizeof(old_rlim));
+	old_exec_file = current->exec_file;
+	get_file(file);
+	current->exec_file = file;
+#endif
+
+	gr_set_proc_label(file->f_dentry, file->f_vfsmnt);
+
 	retval = search_binary_handler(&bprm,regs);
-	if (retval >= 0)
+	if (retval >= 0) {
+#ifdef CONFIG_GRKERNSEC
+		if (old_exec_file)
+			fput(old_exec_file);
+#endif
 		/* execve success */
 		return retval;
+	}
 
+#ifdef CONFIG_GRKERNSEC
+	current->acl = old_acl;
+	memcpy(current->rlim, old_rlim, sizeof(old_rlim));
+	fput(current->exec_file);
+	current->exec_file = old_exec_file;
+#endif
 out:
 	/* Something went wrong, return the inode and free the argument pages*/
 	allow_write_access(bprm.file);
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/parisc/kernel/sys_parisc.c linux-2.4.27-leo/arch/parisc/kernel/sys_parisc.c
--- linux-2.4.27/arch/parisc/kernel/sys_parisc.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.27-leo/arch/parisc/kernel/sys_parisc.c	2004-09-17 03:19:58.000000000 +0100
@@ -12,6 +12,7 @@
 #include <linux/mman.h>
 #include <linux/shm.h>
 #include <linux/smp_lock.h>
+#include <linux/grsecurity.h>
 
 int sys_pipe(int *fildes)
 {
@@ -90,6 +91,11 @@
 		inode = filp->f_dentry->d_inode;
 	}
 
+#ifdef CONFIG_GRKERNSEC_PAX_RANDMMAP
+	if ((current->flags & PF_PAX_RANDMMAP) && (!addr || filp))
+		addr = TASK_UNMAPPED_BASE + current->mm->delta_mmap;
+#endif
+
 	if (inode && (flags & MAP_SHARED) && (inode->i_mapping->i_mmap_shared)) {
 		addr = get_shared_area(inode, addr, len, pgoff);
 	} else {
@@ -104,12 +110,23 @@
 {
 	struct file * file = NULL;
 	unsigned long error = -EBADF;
+
+#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC
+	if (flags & MAP_MIRROR)
+		return -EINVAL;
+#endif
+
 	if (!(flags & MAP_ANONYMOUS)) {
 		file = fget(fd);
 		if (!file)
 			goto out;
 	}
 
+	if (gr_handle_mmap(file, prot)) {
+		fput(file);
+		return -EACCES;
+	}
+
 	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 
 	down_write(&current->mm->mmap_sem);
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/parisc/kernel/traps.c linux-2.4.27-leo/arch/parisc/kernel/traps.c
--- linux-2.4.27/arch/parisc/kernel/traps.c	2003-08-25 12:44:40.000000000 +0100
+++ linux-2.4.27-leo/arch/parisc/kernel/traps.c	2004-09-17 03:19:58.000000000 +0100
@@ -637,9 +637,7 @@
 
 			down_read(&current->mm->mmap_sem);
 			vma = find_vma(current->mm,regs->iaoq[0]);
-			if (vma && (regs->iaoq[0] >= vma->vm_start)
-				&& (vma->vm_flags & VM_EXEC)) {
-
+			if (vma && (regs->iaoq[0] >= vma->vm_start)) {
 				fault_address = regs->iaoq[0];
 				fault_space = regs->iasq[0];
 
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/parisc/mm/fault.c linux-2.4.27-leo/arch/parisc/mm/fault.c
--- linux-2.4.27/arch/parisc/mm/fault.c	2003-06-13 15:51:31.000000000 +0100
+++ linux-2.4.27-leo/arch/parisc/mm/fault.c	2004-09-17 03:19:58.000000000 +0100
@@ -15,6 +15,7 @@
 #include <linux/ptrace.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
+#include <linux/unistd.h>
 
 #include <asm/uaccess.h>
 #include <asm/traps.h>
@@ -53,7 +54,7 @@
 static unsigned long
 parisc_acctyp(unsigned long code, unsigned int inst)
 {
-	if (code == 6 || code == 16)
+	if (code == 6 || code == 7 || code == 16)
 	    return VM_EXEC;
 
 	switch (inst & 0xf0000000) {
@@ -139,6 +140,136 @@
 			}
 #endif
 
+/*
+ * PaX: decide what to do with offenders (instruction_pointer(regs) = fault address)
+ *
+ * returns 1 when task should be killed 
+ *	   2 when rt_sigreturn trampoline was detected
+ *	   3 when unpatched PLT trampoline was detected
+ *	   4 when legitimate ET_EXEC was detected
+ */
+#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC  
+static int pax_handle_fetch_fault(struct pt_regs *regs)
+{
+	int err;
+
+#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC
+	if (current->flags & PF_PAX_RANDEXEC) {
+		if (instruction_pointer(regs) >= current->mm->start_code &&
+		    instruction_pointer(regs) < current->mm->end_code)
+		{
+#if 0
+			/* PaX: this needs fixing */
+			if ((regs->gr[2] & ~3UL) == instruction_pointer(regs))
+				return 1;
+#endif
+			regs->iaoq[0] += current->mm->delta_exec;
+			if ((regs->iaoq[1] & ~3UL) >= current->mm->start_code &&
+			    (regs->iaoq[1] & ~3UL) < current->mm->end_code)
+				regs->iaoq[1] += current->mm->delta_exec;
+			return 4;
+		}
+	}
+#endif
+
+#ifdef CONFIG_GRKERNSEC_PAX_EMUPLT
+	do { /* PaX: unpatched PLT emulation */
+		unsigned int bl, depwi;
+
+		err = get_user(bl, (unsigned int*)instruction_pointer(regs));
+		err |= get_user(depwi, (unsigned int*)(instruction_pointer(regs)+4));
+
+		if (err)
+			break;
+
+		if (bl == 0xEA9F1FDDU && depwi == 0xD6801C1EU) {
+			unsigned int ldw, bv, ldw2, addr = instruction_pointer(regs)-12;
+
+			err = get_user(ldw, (unsigned int*)addr);
+			err |= get_user(bv, (unsigned int*)(addr+4));
+			err |= get_user(ldw2, (unsigned int*)(addr+8));
+
+			if (err)
+				break;
+
+			if (ldw == 0x0E801096U &&
+			    bv == 0xEAC0C000U &&
+			    ldw2 == 0x0E881095U)
+			{
+				unsigned int resolver, map;
+
+				err = get_user(resolver, (unsigned int*)(instruction_pointer(regs)+8));
+				err |= get_user(map, (unsigned int*)(instruction_pointer(regs)+12));
+				if (err)
+					break;
+
+				regs->gr[20] = instruction_pointer(regs)+8;
+				regs->gr[21] = map;
+				regs->gr[22] = resolver;
+				regs->iaoq[0] = resolver | 3UL;
+				regs->iaoq[1] = regs->iaoq[0] + 4;
+				return 3;
+			}
+		}
+	} while (0);
+#endif
+ 
+#ifdef CONFIG_GRKERNSEC_PAX_EMUTRAMP
+
+#ifndef CONFIG_GRKERNSEC_PAX_EMUSIGRT
+	if (!(current->flags & PF_PAX_EMUTRAMP))
+		return 1;
+#endif
+
+	do { /* PaX: rt_sigreturn emulation */
+		unsigned int ldi1, ldi2, bel, nop;
+
+		err = get_user(ldi1, (unsigned int *)instruction_pointer(regs));
+		err |= get_user(ldi2, (unsigned int *)(instruction_pointer(regs)+4));
+		err |= get_user(bel, (unsigned int *)(instruction_pointer(regs)+8));
+		err |= get_user(nop, (unsigned int *)(instruction_pointer(regs)+12));
+
+		if (err)
+			break;
+
+                if ((ldi1 == 0x34190000U || ldi1 == 0x34190002U) &&
+		    ldi2 == 0x3414015AU &&
+		    bel == 0xE4008200U &&
+		    nop == 0x08000240U)
+		{
+			regs->gr[25] = (ldi1 & 2) >> 1;
+			regs->gr[20] = __NR_rt_sigreturn;
+			regs->gr[31] = regs->iaoq[1] + 16;
+			regs->sr[0] = regs->iasq[1];
+			regs->iaoq[0] = 0x100UL;
+			regs->iaoq[1] = regs->iaoq[0] + 4;
+			regs->iasq[0] = regs->sr[2];
+			regs->iasq[1] = regs->sr[2];
+			return 2;
+		}
+	} while (0);
+#endif
+
+	return 1;
+}
+
+void pax_report_insns(void *pc)
+{
+	unsigned long i;
+
+	printk(KERN_ERR "PAX: bytes at PC: ");
+	for (i = 0; i < 5; i++) {
+		unsigned int c;
+		if (get_user(c, (unsigned int*)pc+i)) {
+			printk("<invalid address>.");
+			break;
+		}
+		printk("%08x ", c);
+	}
+	printk("\n");
+}
+#endif
+
 void do_page_fault(struct pt_regs *regs, unsigned long code,
 			      unsigned long address)
 {
@@ -164,8 +295,38 @@
 
 	acc_type = parisc_acctyp(code,regs->iir);
 
-	if ((vma->vm_flags & acc_type) != acc_type)
+	if ((vma->vm_flags & acc_type) != acc_type) {
+
+#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC
+		if ((current->flags & PF_PAX_PAGEEXEC) && (acc_type & VM_EXEC) &&
+		    (address & ~3UL) == instruction_pointer(regs))
+		   {
+			up_read(&mm->mmap_sem);
+			switch(pax_handle_fetch_fault(regs)) {
+
+#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC
+			case 4:
+				return;
+#endif
+
+#ifdef CONFIG_GRKERNSEC_PAX_EMUPLT
+			case 3:
+				return;
+#endif
+
+#ifdef CONFIG_GRKERNSEC_PAX_EMUTRAMP
+			case 2:
+				return;
+#endif
+
+			}
+			pax_report_fault(regs, (void*)instruction_pointer(regs), (void*)regs->gr[30]);
+			do_exit(SIGKILL);
+		}
+#endif
+
 		goto bad_area;
+	}
 
 	/*
 	 * If for any reason at all we couldn't handle the fault, make
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/ppc/config.in linux-2.4.27-leo/arch/ppc/config.in
--- linux-2.4.27/arch/ppc/config.in	2004-09-17 02:38:42.000000000 +0100
+++ linux-2.4.27-leo/arch/ppc/config.in	2004-09-17 03:19:58.000000000 +0100
@@ -167,6 +167,8 @@
   int  'Maximum number of CPUs (2-32)' CONFIG_NR_CPUS 32
 fi
 
+bool 'Preemptible kernel support' CONFIG_PREEMPT
+
 if [ "$CONFIG_6xx" = "y" -a "$CONFIG_8260" = "n" ];then
   bool 'AltiVec Support' CONFIG_ALTIVEC
   bool 'Thermal Management Support' CONFIG_TAU
@@ -666,3 +668,12 @@
 int 'Kernel messages buffer length shift (0 = default)' CONFIG_LOG_BUF_SHIFT 0
 
 endmenu
+
+mainmenu_option next_comment
+comment 'Grsecurity'
+bool 'Grsecurity' CONFIG_GRKERNSEC
+if [ "$CONFIG_GRKERNSEC" = "y" ]; then
+    source grsecurity/Config.in
+fi
+endmenu
+
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/ppc/kernel/entry.S linux-2.4.27-leo/arch/ppc/kernel/entry.S
--- linux-2.4.27/arch/ppc/kernel/entry.S	2004-05-19 21:34:36.000000000 +0100
+++ linux-2.4.27-leo/arch/ppc/kernel/entry.S	2004-09-17 03:19:36.000000000 +0100
@@ -287,6 +287,46 @@
 	 */
 	cmpi	0,r3,0
 	beq	restore
+#ifdef CONFIG_PREEMPT
+	lwz	r3,PREEMPT_COUNT(r2)
+	cmpi	0,r3,1
+	bge	ret_from_except
+	lwz	r5,_MSR(r1)
+	andi.	r5,r5,MSR_PR
+	bne	do_signal_ret
+	lwz	r5,NEED_RESCHED(r2)
+	cmpi	0,r5,0
+	beq	ret_from_except
+	lis	r3,irq_stat@h
+	ori	r3,r3,irq_stat@l
+#ifdef CONFIG_SMP
+	lwz     r5,CPU(r2)
+	rlwinm  r5,r5,5,0,26
+	add     r3,r3,r5
+#endif
+	lwz	r5,4(r3)
+	lwz	r3,8(r3)
+	add	r3,r3,r5
+	cmpi	0,r3,0
+	bne	ret_from_except
+	lwz	r3,PREEMPT_COUNT(r2)
+	addi	r3,r3,1
+	stw	r3,PREEMPT_COUNT(r2)
+	mfmsr	r0
+	ori	r0,r0,MSR_EE
+	mtmsr	r0
+	sync
+	bl	preempt_schedule
+	mfmsr	r0
+	rlwinm	r0,r0,0,17,15
+	mtmsr	r0
+	sync
+	lwz	r3,PREEMPT_COUNT(r2)
+	subi	r3,r3,1
+	stw	r3,PREEMPT_COUNT(r2)
+	li	r3,1
+	b	ret_from_intercept
+#endif /* CONFIG_PREEMPT */
 	.globl	ret_from_except
 ret_from_except:
 	lwz	r3,_MSR(r1)	/* Returning to user mode? */
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/ppc/kernel/head_4xx.S linux-2.4.27-leo/arch/ppc/kernel/head_4xx.S
--- linux-2.4.27/arch/ppc/kernel/head_4xx.S	2003-11-28 18:26:19.000000000 +0000
+++ linux-2.4.27-leo/arch/ppc/kernel/head_4xx.S	2004-09-17 03:19:58.000000000 +0100
@@ -296,15 +296,12 @@
 
 	/* Most of the Linux PTE is ready to load into the TLB LO.
 	 * We set ZSEL, where only the LS-bit determines user access.
-	 * We set execute, because we don't have the granularity to
-	 * properly set this at the page level (Linux problem).
 	 * If shared is set, we cause a zero PID->TID load.
 	 * Many of these bits are software only.  Bits we don't set
 	 * here we (properly should) assume have the appropriate value.
 	 */
 	li	r22, 0x0ce2
 	andc	r21, r21, r22		/* Make sure 20, 21 are zero */
-	ori	r21, r21, _PAGE_HWEXEC	/* make it executable */
 
 	/* find the TLB index that caused the fault.  It has to be here.
 	*/
@@ -783,7 +780,6 @@
 	stw	r23, tlb_4xx_index@l(0)
 
 6:
-	ori	r21, r21, _PAGE_HWEXEC		/* make it executable */
 	tlbwe	r21, r23, TLB_DATA		/* Load TLB LO */
 
 	/* Create EPN.  This is the faulting address plus a static
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/ppc/kernel/irq.c linux-2.4.27-leo/arch/ppc/kernel/irq.c
--- linux-2.4.27/arch/ppc/kernel/irq.c	2003-11-28 18:26:19.000000000 +0000
+++ linux-2.4.27-leo/arch/ppc/kernel/irq.c	2004-09-17 03:19:36.000000000 +0100
@@ -551,6 +551,34 @@
 	return 1; /* lets ret_from_int know we can do checks */
 }
 
+#ifdef CONFIG_PREEMPT
+int
+preempt_intercept(struct pt_regs *regs)
+{
+	int ret;
+
+	preempt_disable();
+
+	switch(regs->trap) {
+	case 0x500:
+		ret = do_IRQ(regs);
+		break;
+#ifndef CONFIG_4xx
+	case 0x900:
+#else
+	case 0x1000:
+#endif
+		ret = timer_interrupt(regs);
+		break;
+	default:
+		BUG();
+	}
+
+	preempt_enable();
+	return ret;
+}
+#endif /* CONFIG_PREEMPT */
+
 unsigned long probe_irq_on (void)
 {
 	return 0;
@@ -647,11 +675,13 @@
 				show("wait_on_irq");
 				count = ~0;
 			}
+			preempt_disable();
 			__sti();
 			/* don't worry about the lock race Linus found
 			 * on intel here. -- Cort
 			 */
 			__cli();
+			preempt_enable_no_resched();
 			if (atomic_read(&global_irq_count))
 				continue;
 			if (global_irq_lock)
@@ -727,6 +757,8 @@
 	global_irq_holder = cpu;
 }
 
+#define	EFLAGS_IF_SHIFT	15
+
 /*
  * A global "cli()" while in an interrupt context
  * turns into just a local cli(). Interrupts
@@ -744,9 +776,10 @@
 	unsigned long flags;
 
 	__save_flags(flags);
-	if (flags & (1 << 15)) {
-		int cpu = smp_processor_id();
+	if (flags & (1 << EFLAGS_IF_SHIFT)) {
+		int cpu;
 		__cli();
+		cpu = smp_processor_id();
 		if (!local_irq_count(cpu))
 			get_irqlock(cpu);
 	}
@@ -754,11 +787,14 @@
 
 void __global_sti(void)
 {
-	int cpu = smp_processor_id();
+	int cpu;
 
+	preempt_disable();
+	cpu = smp_processor_id();
 	if (!local_irq_count(cpu))
 		release_irqlock(cpu);
 	__sti();
+	preempt_enable();
 }
 
 /*
@@ -773,19 +809,23 @@
 	int retval;
 	int local_enabled;
 	unsigned long flags;
+	int cpu;
 
 	__save_flags(flags);
-	local_enabled = (flags >> 15) & 1;
+	local_enabled = (flags >> EFLAGS_IF_SHIFT) & 1;
 	/* default to local */
 	retval = 2 + local_enabled;
 
 	/* check for global flags if we're not in an interrupt */
-	if (!local_irq_count(smp_processor_id())) {
+	preempt_disable();
+	cpu = smp_processor_id();
+	if (!local_irq_count(cpu)) {
 		if (local_enabled)
 			retval = 1;
-		if (global_irq_holder == (unsigned char) smp_processor_id())
+		if (global_irq_holder == cpu)
 			retval = 0;
 	}
+	preempt_enable();
 	return retval;
 }
 
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/ppc/kernel/mk_defs.c linux-2.4.27-leo/arch/ppc/kernel/mk_defs.c
--- linux-2.4.27/arch/ppc/kernel/mk_defs.c	2003-11-28 18:26:19.000000000 +0000
+++ linux-2.4.27-leo/arch/ppc/kernel/mk_defs.c	2004-09-17 03:19:36.000000000 +0100
@@ -39,6 +39,9 @@
 	DEFINE(SIGPENDING, offsetof(struct task_struct, sigpending));
 	DEFINE(THREAD, offsetof(struct task_struct, thread));
 	DEFINE(MM, offsetof(struct task_struct, mm));
+#ifdef CONFIG_PREEMPT
+	DEFINE(PREEMPT_COUNT, offsetof(struct task_struct, preempt_count));
+#endif
 	DEFINE(ACTIVE_MM, offsetof(struct task_struct, active_mm));
 	DEFINE(TASK_STRUCT_SIZE, sizeof(struct task_struct));
 	DEFINE(KSP, offsetof(struct thread_struct, ksp));
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/ppc/kernel/open_pic.c linux-2.4.27-leo/arch/ppc/kernel/open_pic.c
--- linux-2.4.27/arch/ppc/kernel/open_pic.c	2004-02-20 14:11:39.000000000 +0000
+++ linux-2.4.27-leo/arch/ppc/kernel/open_pic.c	2004-09-17 03:19:36.000000000 +0100
@@ -601,19 +601,24 @@
 void __init do_openpic_setup_cpu(void)
 {
  	int i;
-	u32 msk = 1 << smp_hw_index[smp_processor_id()];
+#ifdef CONFIG_IRQ_ALL_CPUS
+	u32 msk;
+#endif /* CONFIG_IRQ_ALL_CPUS */
 
 	spin_lock(&openpic_setup_lock);
 
 #ifdef CONFIG_IRQ_ALL_CPUS
+	msk = 1 << smp_hw_index[smp_processor_id()];
+
  	/* let the openpic know we want intrs. default affinity
  	 * is 0xffffffff until changed via /proc
  	 * That's how it's done on x86. If we want it differently, then
  	 * we should make sure we also change the default values of irq_affinity
  	 * in irq.c.
  	 */
- 	for (i = 0; i < NumSources; i++)
+ 	for (i = 0; i < NumSources; i++) {
 		openpic_mapirq(i, msk, ~0U);
+	}
 #endif /* CONFIG_IRQ_ALL_CPUS */
  	openpic_set_priority(0);
 
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/ppc/kernel/ptrace.c linux-2.4.27-leo/arch/ppc/kernel/ptrace.c
--- linux-2.4.27/arch/ppc/kernel/ptrace.c	2003-08-25 12:44:40.000000000 +0100
+++ linux-2.4.27-leo/arch/ppc/kernel/ptrace.c	2004-09-17 03:19:58.000000000 +0100
@@ -24,6 +24,7 @@
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
+#include <linux/grsecurity.h>
 
 #include <asm/uaccess.h>
 #include <asm/page.h>
@@ -195,6 +196,9 @@
 	if (pid == 1)		/* you may not mess with init */
 		goto out_tsk;
 
+	if (gr_handle_ptrace(child, request))
+		goto out_tsk;
+
 	if (request == PTRACE_ATTACH) {
 		ret = ptrace_attach(child);
 		goto out_tsk;
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/ppc/kernel/setup.c linux-2.4.27-leo/arch/ppc/kernel/setup.c
--- linux-2.4.27/arch/ppc/kernel/setup.c	2004-05-19 21:34:36.000000000 +0100
+++ linux-2.4.27-leo/arch/ppc/kernel/setup.c	2004-09-17 03:19:36.000000000 +0100
@@ -502,6 +502,20 @@
 	strcpy(cmd_line, CONFIG_CMDLINE);
 #endif /* CONFIG_CMDLINE */
 
+#ifdef CONFIG_PREEMPT
+	/* Override the irq routines for external & timer interrupts here,
+	 * as the MMU has only been minimally setup at this point and
+	 * there are no protections on page zero.
+	 */
+	{
+		extern int preempt_intercept(struct pt_regs *);
+	
+		do_IRQ_intercept = (unsigned long) &preempt_intercept;
+		timer_interrupt_intercept = (unsigned long) &preempt_intercept;
+
+	}
+#endif /* CONFIG_PREEMPT */
+
 	platform_init(r3, r4, r5, r6, r7);
 
 	if (ppc_md.progress)
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/ppc/kernel/syscalls.c linux-2.4.27-leo/arch/ppc/kernel/syscalls.c
--- linux-2.4.27/arch/ppc/kernel/syscalls.c	2003-11-28 18:26:19.000000000 +0000
+++ linux-2.4.27-leo/arch/ppc/kernel/syscalls.c	2004-09-17 03:19:58.000000000 +0100
@@ -35,6 +35,7 @@
 #include <linux/ipc.h>
 #include <linux/utsname.h>
 #include <linux/file.h>
+#include <linux/grsecurity.h>
 
 #include <asm/uaccess.h>
 #include <asm/ipc.h>
@@ -191,12 +192,23 @@
 	struct file * file = NULL;
 	int ret = -EBADF;
 
+#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC
+	if (flags & MAP_MIRROR)
+		return -EINVAL;
+#endif
+
 	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 	if (!(flags & MAP_ANONYMOUS)) {
 		if (!(file = fget(fd)))
 			goto out;
 	}
 
+	if (gr_handle_mmap(file, prot)) {
+		fput(file);
+		ret = -EACCES;
+		goto out;
+	}
+
 	ret = -EINVAL;
 	if ((! allow_mmap_address(addr)) && (flags & MAP_FIXED))
 		goto out;
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/ppc/kernel/temp.c linux-2.4.27-leo/arch/ppc/kernel/temp.c
--- linux-2.4.27/arch/ppc/kernel/temp.c	2003-08-25 12:44:40.000000000 +0100
+++ linux-2.4.27-leo/arch/ppc/kernel/temp.c	2004-09-17 03:19:36.000000000 +0100
@@ -138,7 +138,7 @@
 
 static void tau_timeout(void * info)
 {
-	unsigned long cpu = smp_processor_id();
+	unsigned long cpu;
 	unsigned long flags;
 	int size;
 	int shrink;
@@ -146,6 +146,8 @@
 	/* disabling interrupts *should* be okay */
 	save_flags(flags); cli();
 
+	cpu = smp_processor_id();
+
 #ifndef CONFIG_TAU_INT
 	TAUupdate(cpu);
 #endif
@@ -191,13 +193,15 @@
 
 static void tau_timeout_smp(unsigned long unused)
 {
-
 	/* schedule ourselves to be run again */
 	mod_timer(&tau_timer, jiffies + shrink_timer) ;
+
+	preempt_disable();
 #ifdef CONFIG_SMP
 	smp_call_function(tau_timeout, NULL, 1, 0);
 #endif
 	tau_timeout(NULL);
+	preempt_enable();
 }
 
 /*
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/ppc/lib/dec_and_lock.c linux-2.4.27-leo/arch/ppc/lib/dec_and_lock.c
--- linux-2.4.27/arch/ppc/lib/dec_and_lock.c	2001-11-16 18:10:08.000000000 +0000
+++ linux-2.4.27-leo/arch/ppc/lib/dec_and_lock.c	2004-09-17 03:19:36.000000000 +0100
@@ -1,4 +1,5 @@
 #include <linux/module.h>
+#include <linux/sched.h>
 #include <linux/spinlock.h>
 #include <asm/atomic.h>
 #include <asm/system.h>
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/ppc/mm/fault.c linux-2.4.27-leo/arch/ppc/mm/fault.c
--- linux-2.4.27/arch/ppc/mm/fault.c	2003-11-28 18:26:19.000000000 +0000
+++ linux-2.4.27-leo/arch/ppc/mm/fault.c	2004-09-17 03:19:58.000000000 +0100
@@ -26,6 +26,9 @@
 #include <linux/mman.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/pagemap.h>
+#include <linux/compiler.h>
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
@@ -52,6 +55,360 @@
 void bad_page_fault(struct pt_regs *, unsigned long, int sig);
 void do_page_fault(struct pt_regs *, unsigned long, unsigned long);
 
+#ifdef CONFIG_GRKERNSEC_PAX_EMUSIGRT
+void pax_syscall_close(struct vm_area_struct * vma)
+{
+	vma->vm_mm->call_syscall = 0UL;
+}
+
+static struct page* pax_syscall_nopage(struct vm_area_struct *vma, unsigned long address, int write_access)
+{
+	struct page* page;
+	unsigned int *kaddr;
+
+	page = alloc_page(GFP_HIGHUSER);
+	if (!page)
+		return page;
+
+	kaddr = kmap(page);
+	memset(kaddr, 0, PAGE_SIZE);
+	kaddr[0] = 0x44000002U; /* sc */
+	__flush_dcache_icache(kaddr);
+	kunmap(page);
+	return page;
+}
+
+static struct vm_operations_struct pax_vm_ops = {
+	close:		pax_syscall_close,
+	nopage:		pax_syscall_nopage,
+};
+
+static void pax_insert_vma(struct vm_area_struct *vma, unsigned long addr)
+{
+	vma->vm_mm = current->mm;
+	vma->vm_start = addr;
+	vma->vm_end = addr + PAGE_SIZE;
+	vma->vm_flags = VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYEXEC;
+	vma->vm_page_prot = protection_map[vma->vm_flags & 0x0f];
+	vma->vm_ops = &pax_vm_ops;
+	vma->vm_pgoff = 0UL;
+	vma->vm_file = NULL;
+	vma->vm_private_data = NULL;
+	insert_vm_struct(current->mm, vma);
+	++current->mm->total_vm;
+}
+#endif
+
+#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC
+/*
+ * PaX: decide what to do with offenders (regs->nip = fault address)
+ *
+ * returns 1 when task should be killed
+ *         2 when patched GOT trampoline was detected
+ *         3 when patched PLT trampoline was detected
+ *         4 when unpatched PLT trampoline was detected
+ *         5 when legitimate ET_EXEC was detected
+ *         6 when sigreturn trampoline was detected
+ *         7 when rt_sigreturn trampoline was detected
+ */
+static int pax_handle_fetch_fault(struct pt_regs *regs)
+{
+	int err;
+
+#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC
+	if (current->flags & PF_PAX_RANDEXEC) {
+		if (regs->nip >= current->mm->start_code &&
+		    regs->nip < current->mm->end_code)
+		{
+			if (regs->link == regs->nip)
+				return 1;
+
+			regs->nip += current->mm->delta_exec;
+			return 5;
+		}
+	}
+#endif
+
+#ifdef CONFIG_GRKERNSEC_PAX_EMUPLT
+	do { /* PaX: patched GOT emulation */
+		unsigned int blrl;
+
+		err = get_user(blrl, (unsigned int*)regs->nip);
+
+		if (!err && blrl == 0x4E800021U) {
+			unsigned long temp = regs->nip;
+
+			regs->nip = regs->link & 0xFFFFFFFCUL;
+			regs->link = temp + 4UL;
+			return 2;
+		}
+	} while (0);
+
+	do { /* PaX: patched PLT emulation #1 */
+		unsigned int b;
+
+		err = get_user(b, (unsigned int *)regs->nip);
+
+		if (!err && (b & 0xFC000003U) == 0x48000000U) {
+			regs->nip += (((b | 0xFC000000UL) ^ 0x02000000UL) + 0x02000000UL);
+			return 3;
+		}
+	} while (0);
+
+	do { /* PaX: unpatched PLT emulation #1 */
+		unsigned int li, b;
+
+		err = get_user(li, (unsigned int *)regs->nip);
+		err |= get_user(b, (unsigned int *)(regs->nip+4));
+
+		if (!err && (li & 0xFFFF0000U) == 0x39600000U && (b & 0xFC000003U) == 0x48000000U) {
+			unsigned int rlwinm, add, li2, addis2, mtctr, li3, addis3, bctr;
+                        unsigned long addr = b | 0xFC000000UL;
+
+                        addr = regs->nip + 4 + ((addr ^ 0x02000000UL) + 0x02000000UL);
+			err = get_user(rlwinm, (unsigned int*)addr);
+			err |= get_user(add, (unsigned int*)(addr+4));
+			err |= get_user(li2, (unsigned int*)(addr+8));
+			err |= get_user(addis2, (unsigned int*)(addr+12));
+			err |= get_user(mtctr, (unsigned int*)(addr+16));
+			err |= get_user(li3, (unsigned int*)(addr+20));
+			err |= get_user(addis3, (unsigned int*)(addr+24));
+			err |= get_user(bctr, (unsigned int*)(addr+28));
+
+			if (err)
+				break;
+
+			if (rlwinm == 0x556C083CU &&
+			    add == 0x7D6C5A14U &&
+			    (li2 & 0xFFFF0000U) == 0x39800000U &&
+			    (addis2 & 0xFFFF0000U) == 0x3D8C0000U &&
+			    mtctr == 0x7D8903A6U &&
+			    (li3 & 0xFFFF0000U) == 0x39800000U &&
+			    (addis3 & 0xFFFF0000U) == 0x3D8C0000U &&
+			    bctr == 0x4E800420U)
+			{
+				regs->gpr[PT_R11] = 3 * (((li | 0xFFFF0000UL) ^ 0x00008000UL) + 0x00008000UL);
+				regs->gpr[PT_R12] = (((li3 | 0xFFFF0000UL) ^ 0x00008000UL) + 0x00008000UL);
+				regs->gpr[PT_R12] += (addis3 & 0xFFFFU) << 16;
+				regs->ctr = (((li2 | 0xFFFF0000UL) ^ 0x00008000UL) + 0x00008000UL);
+				regs->ctr += (addis2 & 0xFFFFU) << 16;
+				regs->nip = regs->ctr;
+				return 4;
+			}
+		}
+	} while (0);
+
+#if 0
+	do { /* PaX: unpatched PLT emulation #2 */
+		unsigned int lis, lwzu, b, bctr;
+
+		err = get_user(lis, (unsigned int *)regs->nip);
+		err |= get_user(lwzu, (unsigned int *)(regs->nip+4));
+		err |= get_user(b, (unsigned int *)(regs->nip+8));
+		err |= get_user(bctr, (unsigned int *)(regs->nip+12));
+
+		if (err)
+			break;
+
+		if ((lis & 0xFFFF0000U) == 0x39600000U &&
+		    (lwzu & 0xU) == 0xU &&
+		    (b & 0xFC000003U) == 0x48000000U &&
+		    bctr == 0x4E800420U)
+		{
+			unsigned int addis, addi, rlwinm, add, li2, addis2, mtctr, li3, addis3, bctr;
+                        unsigned long addr = b | 0xFC000000UL;
+
+                        addr = regs->nip + 12 + ((addr ^ 0x02000000UL) + 0x02000000UL);
+			err = get_user(addis, (unsigned int*)addr);
+			err |= get_user(addi, (unsigned int*)(addr+4));
+			err |= get_user(rlwinm, (unsigned int*)(addr+8));
+			err |= get_user(add, (unsigned int*)(addr+12));
+			err |= get_user(li2, (unsigned int*)(addr+16));
+			err |= get_user(addis2, (unsigned int*)(addr+20));
+			err |= get_user(mtctr, (unsigned int*)(addr+24));
+			err |= get_user(li3, (unsigned int*)(addr+28));
+			err |= get_user(addis3, (unsigned int*)(addr+32));
+			err |= get_user(bctr, (unsigned int*)(addr+36));
+
+			if (err)
+				break;
+
+			if ((addis & 0xFFFF0000U) == 0x3D6B0000U &&
+			    (addi & 0xFFFF0000U) == 0x396B0000U &&
+			    rlwinm == 0x556C083CU &&
+			    add == 0x7D6C5A14U &&
+			    (li2 & 0xFFFF0000U) == 0x39800000U &&
+			    (addis2 & 0xFFFF0000U) == 0x3D8C0000U &&
+			    mtctr == 0x7D8903A6U &&
+			    (li3 & 0xFFFF0000U) == 0x39800000U &&
+			    (addis3 & 0xFFFF0000U) == 0x3D8C0000U &&
+			    bctr == 0x4E800420U)
+			{
+				regs->gpr[PT_R11] = 
+				regs->gpr[PT_R11] = 3 * (((li | 0xFFFF0000UL) ^ 0x00008000UL) + 0x00008000UL);
+				regs->gpr[PT_R12] = (((li3 | 0xFFFF0000UL) ^ 0x00008000UL) + 0x00008000UL);
+				regs->gpr[PT_R12] += (addis3 & 0xFFFFU) << 16;
+				regs->ctr = (((li2 | 0xFFFF0000UL) ^ 0x00008000UL) + 0x00008000UL);
+				regs->ctr += (addis2 & 0xFFFFU) << 16;
+				regs->nip = regs->ctr;
+				return 4;
+			}
+		}
+	} while (0);
+#endif
+
+	do { /* PaX: unpatched PLT emulation #3 */
+		unsigned int li, b;
+
+		err = get_user(li, (unsigned int *)regs->nip);
+		err |= get_user(b, (unsigned int *)(regs->nip+4));
+
+		if (!err && (li & 0xFFFF0000U) == 0x39600000U && (b & 0xFC000003U) == 0x48000000U) {
+			unsigned int addis, lwz, mtctr, bctr;
+			unsigned long addr = b | 0xFC000000UL;
+
+			addr = regs->nip + 4 + ((addr ^ 0x02000000UL) + 0x02000000UL);
+			err = get_user(addis, (unsigned int*)addr);
+			err |= get_user(lwz, (unsigned int*)(addr+4));
+			err |= get_user(mtctr, (unsigned int*)(addr+8));
+			err |= get_user(bctr, (unsigned int*)(addr+12));
+
+			if (err)
+				break;
+
+			if ((addis & 0xFFFF0000U) == 0x3D6B0000U &&
+			    (lwz & 0xFFFF0000U) == 0x816B0000U &&
+			    mtctr == 0x7D6903A6U &&
+			    bctr == 0x4E800420U)
+			{
+				unsigned int r11;
+
+				addr = (addis << 16) + (((li | 0xFFFF0000UL) ^ 0x00008000UL) + 0x00008000UL);
+				addr += (((lwz | 0xFFFF0000UL) ^ 0x00008000UL) + 0x00008000UL);
+
+				err = get_user(r11, (unsigned int*)addr);
+				if (err)
+					break;
+
+				regs->gpr[PT_R11] = r11;
+				regs->ctr = r11;
+				regs->nip = r11;
+				return 4;
+			}
+		}
+	} while (0);
+#endif
+
+#ifdef CONFIG_GRKERNSEC_PAX_EMUSIGRT
+	do { /* PaX: sigreturn emulation */
+		unsigned int li, sc;
+
+		err = get_user(li, (unsigned int *)regs->nip);
+		err |= get_user(sc, (unsigned int *)(regs->nip+4));
+
+		if (!err && li == 0x38007777U && sc == 0x44000002U) {
+			struct vm_area_struct *vma;
+			unsigned long call_syscall;
+
+			down_read(&current->mm->mmap_sem);
+			call_syscall = current->mm->call_syscall;
+			up_read(&current->mm->mmap_sem);
+			if (likely(call_syscall))
+				goto emulate;
+
+			vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
+
+			down_write(&current->mm->mmap_sem);
+			if (current->mm->call_syscall) {
+				call_syscall = current->mm->call_syscall;
+				up_write(&current->mm->mmap_sem);
+				if (vma) kmem_cache_free(vm_area_cachep, vma);
+				goto emulate;
+			}
+
+			call_syscall = get_unmapped_area(NULL, 0UL, PAGE_SIZE, 0UL, MAP_PRIVATE);
+			if (!vma || (call_syscall & ~PAGE_MASK)) {
+				up_write(&current->mm->mmap_sem);
+				if (vma) kmem_cache_free(vm_area_cachep, vma);
+				return 1;
+			}
+
+			pax_insert_vma(vma, call_syscall);
+			current->mm->call_syscall = call_syscall;
+			up_write(&current->mm->mmap_sem);
+
+emulate:
+			regs->gpr[PT_R0] = 0x7777UL;
+			regs->nip = call_syscall;
+			return 6;
+		}
+	} while (0);
+
+	do { /* PaX: rt_sigreturn emulation */
+		unsigned int li, sc;
+
+		err = get_user(li, (unsigned int *)regs->nip);
+		err |= get_user(sc, (unsigned int *)(regs->nip+4));
+
+		if (!err && li == 0x38006666U && sc == 0x44000002U) {
+			struct vm_area_struct *vma;
+			unsigned int call_syscall;
+
+			down_read(&current->mm->mmap_sem);
+			call_syscall = current->mm->call_syscall;
+			up_read(&current->mm->mmap_sem);
+			if (likely(call_syscall))
+				goto rt_emulate;
+
+			vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
+
+			down_write(&current->mm->mmap_sem);
+			if (current->mm->call_syscall) {
+				call_syscall = current->mm->call_syscall;
+				up_write(&current->mm->mmap_sem);
+				if (vma) kmem_cache_free(vm_area_cachep, vma);
+				goto rt_emulate;
+			}
+
+			call_syscall = get_unmapped_area(NULL, 0UL, PAGE_SIZE, 0UL, MAP_PRIVATE);
+			if (!vma || (call_syscall & ~PAGE_MASK)) {
+				up_write(&current->mm->mmap_sem);
+				if (vma) kmem_cache_free(vm_area_cachep, vma);
+				return 1;
+			}
+
+			pax_insert_vma(vma, call_syscall);
+			current->mm->call_syscall = call_syscall;
+			up_write(&current->mm->mmap_sem);
+
+rt_emulate:
+			regs->gpr[PT_R0] = 0x6666UL;
+			regs->nip = call_syscall;
+			return 7;
+		}
+	} while (0);
+#endif
+
+        return 1;
+}
+
+void pax_report_insns(void *pc)
+{
+	unsigned long i;
+
+	printk(KERN_ERR "PAX: bytes at PC: ");
+	for (i = 0; i < 5; i++) {
+		unsigned int c;
+		if (get_user(c, (unsigned int*)pc+i)) {
+			printk("<invalid address>.");
+			break;
+		}
+		printk("%08x ", c);
+	}
+	printk("\n");
+}
+#endif
+
 /*
  * Check whether the instruction at regs->nip is a store using
  * an update addressing form which will update r1.
@@ -112,7 +469,7 @@
 	 * indicate errors in DSISR but can validly be set in SRR1.
 	 */
 	if (regs->trap == 0x400)
-		error_code &= 0x48200000;
+		error_code &= 0x58200000;
 	else
 		is_write = error_code & 0x02000000;
 #endif /* CONFIG_4xx || CONFIG_BOOKE */
@@ -245,6 +602,38 @@
 
 	/* User mode accesses cause a SIGSEGV */
 	if (user_mode(regs)) {
+
+#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC
+		if (current->flags & PF_PAX_PAGEEXEC) {
+			if ((regs->trap == 0x400) && (regs->nip == address)) {
+				switch (pax_handle_fetch_fault(regs)) {
+
+#ifdef CONFIG_GRKERNSEC_PAX_EMUPLT
+				case 2:
+				case 3:
+				case 4:
+					return;
+#endif
+
+#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC
+				case 5:
+					return;
+#endif
+
+#ifdef CONFIG_GRKERNSEC_PAX_EMUSIGRT
+				case 6:
+				case 7:
+					return;
+#endif
+
+				}
+
+				pax_report_fault(regs, (void*)regs->nip, (void*)regs->gpr[1]);
+				do_exit(SIGKILL);
+			}
+		}
+#endif
+
 		info.si_signo = SIGSEGV;
 		info.si_errno = 0;
 		info.si_code = code;
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/ppc/mm/init.c linux-2.4.27-leo/arch/ppc/mm/init.c
--- linux-2.4.27/arch/ppc/mm/init.c	2003-11-28 18:26:19.000000000 +0000
+++ linux-2.4.27-leo/arch/ppc/mm/init.c	2004-09-17 03:19:36.000000000 +0100
@@ -126,6 +126,9 @@
 int do_check_pgt_cache(int low, int high)
 {
 	int freed = 0;
+
+	preempt_disable();
+
 	if (pgtable_cache_size > high) {
 		do {
                         if (pgd_quicklist) {
@@ -138,6 +141,9 @@
 			}
 		} while (pgtable_cache_size > low);
 	}
+
+	preempt_enable();
+
 	return freed;
 }
 
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/ppc/mm/tlb.c linux-2.4.27-leo/arch/ppc/mm/tlb.c
--- linux-2.4.27/arch/ppc/mm/tlb.c	2003-08-25 12:44:40.000000000 +0100
+++ linux-2.4.27-leo/arch/ppc/mm/tlb.c	2004-09-17 03:19:36.000000000 +0100
@@ -58,11 +58,14 @@
 	 * we can and should dispense with flush_tlb_all().
 	 *  -- paulus.
 	 */
+
+	preempt_disable();
 	local_flush_tlb_range(&init_mm, TASK_SIZE, ~0UL);
 
 #ifdef CONFIG_SMP
 	smp_send_tlb_invalidate(0);
 #endif /* CONFIG_SMP */
+	preempt_enable();
 }
 
 /*
@@ -73,8 +76,10 @@
 void
 local_flush_tlb_mm(struct mm_struct *mm)
 {
+	preempt_disable();
 	if (Hash == 0) {
 		_tlbia();
+		preempt_enable();
 		return;
 	}
 
@@ -88,6 +93,7 @@
 #ifdef CONFIG_SMP
 	smp_send_tlb_invalidate(0);
 #endif
+	preempt_enable();
 }
 
 void
@@ -97,8 +103,10 @@
 	pmd_t *pmd;
 	pte_t *pte;
 
+	preempt_disable();
 	if (Hash == 0) {
 		_tlbie(vmaddr);
+		preempt_enable();
 		return;
 	}
 	mm = (vmaddr < TASK_SIZE)? vma->vm_mm: &init_mm;
@@ -111,6 +119,7 @@
 #ifdef CONFIG_SMP
 	smp_send_tlb_invalidate(0);
 #endif
+	preempt_enable();
 }
 
 
@@ -127,13 +136,17 @@
 	unsigned long pmd_end;
 	unsigned int ctx = mm->context;
 
+	preempt_disable();
 	if (Hash == 0) {
 		_tlbia();
+		preempt_enable();
 		return;
 	}
 	start &= PAGE_MASK;
-	if (start >= end)
+	if (start >= end) {
+		preempt_enable();
 		return;
+	}
 	pmd = pmd_offset(pgd_offset(mm, start), start);
 	do {
 		pmd_end = (start + PGDIR_SIZE) & PGDIR_MASK;
@@ -156,4 +169,5 @@
 #ifdef CONFIG_SMP
 	smp_send_tlb_invalidate(0);
 #endif
+	preempt_enable();
 }
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/ppc64/kernel/ioctl32.c linux-2.4.27-leo/arch/ppc64/kernel/ioctl32.c
--- linux-2.4.27/arch/ppc64/kernel/ioctl32.c	2004-02-20 14:11:39.000000000 +0000
+++ linux-2.4.27-leo/arch/ppc64/kernel/ioctl32.c	2004-09-17 03:19:58.000000000 +0100
@@ -66,6 +66,7 @@
 #if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE)
 #include <linux/lvm.h>
 #endif /* LVM */
+#include <linux/dm-ioctl.h>
 
 #include <scsi/scsi.h>
 /* Ugly hack. */
@@ -1824,7 +1825,11 @@
 	 * To have permissions to do most of the vt ioctls, we either have
 	 * to be the owner of the tty, or super-user.
 	 */
+#ifdef CONFIG_GRKERNSEC
+	if (current->tty == tty || capable(CAP_SYS_TTY_CONFIG))
+#else
 	if (current->tty == tty || suser())
+#endif
 		return 1;
 	return 0;                                                    
 }
@@ -4408,6 +4413,22 @@
 COMPATIBLE_IOCTL(NBD_PRINT_DEBUG),
 COMPATIBLE_IOCTL(NBD_SET_SIZE_BLOCKS),
 COMPATIBLE_IOCTL(NBD_DISCONNECT),
+/* device-mapper */
+#if defined(CONFIG_BLK_DEV_DM) || defined(CONFIG_BLK_DEV_DM_MODULE)
+COMPATIBLE_IOCTL(DM_VERSION),
+COMPATIBLE_IOCTL(DM_REMOVE_ALL),
+COMPATIBLE_IOCTL(DM_DEV_CREATE),
+COMPATIBLE_IOCTL(DM_DEV_REMOVE),
+COMPATIBLE_IOCTL(DM_TABLE_LOAD),
+COMPATIBLE_IOCTL(DM_DEV_SUSPEND),
+COMPATIBLE_IOCTL(DM_DEV_RENAME),
+COMPATIBLE_IOCTL(DM_TABLE_DEPS),
+COMPATIBLE_IOCTL(DM_DEV_STATUS),
+COMPATIBLE_IOCTL(DM_TABLE_STATUS),
+COMPATIBLE_IOCTL(DM_DEV_WAIT),
+COMPATIBLE_IOCTL(DM_LIST_DEVICES),
+COMPATIBLE_IOCTL(DM_TABLE_CLEAR),
+#endif /* CONFIG_BLK_DEV_DM */
 /* Remove *PRIVATE in 2.5 */
 COMPATIBLE_IOCTL(SIOCDEVPRIVATE),
 COMPATIBLE_IOCTL(SIOCDEVPRIVATE+1),
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/s390/config.in linux-2.4.27-leo/arch/s390/config.in
--- linux-2.4.27/arch/s390/config.in	2003-11-28 18:26:19.000000000 +0000
+++ linux-2.4.27-leo/arch/s390/config.in	2004-09-17 03:19:58.000000000 +0100
@@ -87,3 +87,11 @@
 
 source crypto/Config.in
 source lib/Config.in
+
+mainmenu_option next_comment
+comment 'Grsecurity'
+bool 'Grsecurity' CONFIG_GRKERNSEC
+if [ "$CONFIG_GRKERNSEC" = "y" ]; then
+	source grsecurity/Config.in
+fi
+endmenu
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/s390x/config.in linux-2.4.27-leo/arch/s390x/config.in
--- linux-2.4.27/arch/s390x/config.in	2003-11-28 18:26:19.000000000 +0000
+++ linux-2.4.27-leo/arch/s390x/config.in	2004-09-17 03:19:58.000000000 +0100
@@ -91,3 +91,11 @@
 
 source crypto/Config.in
 source lib/Config.in
+
+mainmenu_option next_comment
+comment 'Grsecurity'
+bool 'Grsecurity' CONFIG_GRKERNSEC
+if [ "$CONFIG_GRKERNSEC" = "y" ]; then
+	source grsecurity/Config.in
+fi
+endmenu
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/s390x/kernel/ioctl32.c linux-2.4.27-leo/arch/s390x/kernel/ioctl32.c
--- linux-2.4.27/arch/s390x/kernel/ioctl32.c	2003-08-25 12:44:40.000000000 +0100
+++ linux-2.4.27-leo/arch/s390x/kernel/ioctl32.c	2004-09-17 03:19:08.000000000 +0100
@@ -30,6 +30,7 @@
 #include <linux/blk.h>
 #include <linux/elevator.h>
 #include <linux/raw.h>
+#include <linux/dm-ioctl.h>
 #include <asm/types.h>
 #include <asm/uaccess.h>
 #include <asm/dasd.h>
@@ -627,6 +628,20 @@
 
 	IOCTL32_DEFAULT(SIOCGSTAMP),
 
+	IOCTL32_DEFAULT(DM_VERSION),
+	IOCTL32_DEFAULT(DM_REMOVE_ALL),
+	IOCTL32_DEFAULT(DM_DEV_CREATE),
+	IOCTL32_DEFAULT(DM_DEV_REMOVE),
+	IOCTL32_DEFAULT(DM_TABLE_LOAD),
+	IOCTL32_DEFAULT(DM_DEV_SUSPEND),
+	IOCTL32_DEFAULT(DM_DEV_RENAME),
+	IOCTL32_DEFAULT(DM_TABLE_DEPS),
+	IOCTL32_DEFAULT(DM_DEV_STATUS),
+	IOCTL32_DEFAULT(DM_TABLE_STATUS),
+	IOCTL32_DEFAULT(DM_DEV_WAIT),
+	IOCTL32_DEFAULT(DM_LIST_DEVICES),
+	IOCTL32_DEFAULT(DM_TABLE_CLEAR),
+
 	IOCTL32_DEFAULT(LOOP_SET_FD),
 	IOCTL32_DEFAULT(LOOP_CLR_FD),
 
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/sh/config.in linux-2.4.27-leo/arch/sh/config.in
--- linux-2.4.27/arch/sh/config.in	2004-02-20 14:11:39.000000000 +0000
+++ linux-2.4.27-leo/arch/sh/config.in	2004-09-17 03:19:58.000000000 +0100
@@ -493,3 +493,11 @@
 
 source crypto/Config.in
 source lib/Config.in
+
+mainmenu_option next_comment
+comment 'Grsecurity'
+bool 'Grsecurity' CONFIG_GRKERNSEC
+if [ "$CONFIG_GRKERNSEC" = "y" ]; then
+	source grsecurity/Config.in
+fi
+endmenu
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/sparc/boot/Makefile linux-2.4.27-leo/arch/sparc/boot/Makefile
--- linux-2.4.27/arch/sparc/boot/Makefile	2002-08-03 01:39:43.000000000 +0100
+++ linux-2.4.27-leo/arch/sparc/boot/Makefile	2004-09-17 03:19:58.000000000 +0100
@@ -24,7 +24,7 @@
 
 BTOBJS := $(HEAD) init/main.o init/version.o init/do_mounts.o
 BTLIBS := $(CORE_FILES_NO_BTFIX) $(FILESYSTEMS) \
-	$(DRIVERS) $(NETWORKS)
+	$(DRIVERS) $(NETWORKS) $(GRSECURITY)
 
 # I wanted to make this depend upon BTOBJS so that a parallel
 # build would work, but this fails because $(HEAD) cannot work
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/sparc/config.in linux-2.4.27-leo/arch/sparc/config.in
--- linux-2.4.27/arch/sparc/config.in	2004-02-20 14:11:40.000000000 +0000
+++ linux-2.4.27-leo/arch/sparc/config.in	2004-09-17 03:19:58.000000000 +0100
@@ -282,3 +282,11 @@
 
 source crypto/Config.in
 source lib/Config.in
+
+mainmenu_option next_comment
+comment 'Grsecurity'
+bool 'Grsecurity' CONFIG_GRKERNSEC
+if [ "$CONFIG_GRKERNSEC" = "y" ]; then
+	source grsecurity/Config.in
+fi
+endmenu
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/sparc/kernel/ptrace.c linux-2.4.27-leo/arch/sparc/kernel/ptrace.c
--- linux-2.4.27/arch/sparc/kernel/ptrace.c	2002-08-03 01:39:43.000000000 +0100
+++ linux-2.4.27-leo/arch/sparc/kernel/ptrace.c	2004-09-17 03:19:58.000000000 +0100
@@ -17,6 +17,7 @@
 #include <linux/user.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
+#include <linux/grsecurity.h>
 
 #include <asm/pgtable.h>
 #include <asm/system.h>
@@ -310,6 +311,9 @@
 		goto out;
 	}
 
+	if(gr_handle_ptrace(child, request))
+		goto out_tsk;
+
 	if ((current->personality == PER_SUNOS && request == PTRACE_SUNATTACH)
 	    || (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) {
 		if (ptrace_attach(child)) {
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/sparc/kernel/sys_sparc.c linux-2.4.27-leo/arch/sparc/kernel/sys_sparc.c
--- linux-2.4.27/arch/sparc/kernel/sys_sparc.c	2003-08-25 12:44:40.000000000 +0100
+++ linux-2.4.27-leo/arch/sparc/kernel/sys_sparc.c	2004-09-17 03:19:58.000000000 +0100
@@ -20,6 +20,7 @@
 #include <linux/utsname.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
+#include <linux/grsecurity.h>
 
 #include <asm/uaccess.h>
 #include <asm/ipc.h>
@@ -54,6 +55,13 @@
 		return -ENOMEM;
 	if (ARCH_SUN4C_SUN4 && len > 0x20000000)
 		return -ENOMEM;
+
+#ifdef CONFIG_GRKERNSEC_PAX_RANDMMAP
+	if ((current->flags & PF_PAX_RANDMMAP) && (!addr || filp))
+		addr = TASK_UNMAPPED_BASE + current->mm->delta_mmap;
+	else
+#endif
+
 	if (!addr)
 		addr = TASK_UNMAPPED_BASE;
 
@@ -225,6 +233,11 @@
 	struct file * file = NULL;
 	unsigned long retval = -EBADF;
 
+#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC
+	if (flags & MAP_MIRROR)
+		return -EINVAL;
+#endif
+
 	if (!(flags & MAP_ANONYMOUS)) {
 		file = fget(fd);
 		if (!file)
@@ -243,6 +256,12 @@
 	if (len > TASK_SIZE - PAGE_SIZE || addr + len > TASK_SIZE - PAGE_SIZE)
 		goto out_putf;
 
+	if (gr_handle_mmap(file, prot)) {
+		fput(file);
+		retval = -EACCES;
+		goto out;
+	}
+
 	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 
 	down_write(&current->mm->mmap_sem);
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/sparc/kernel/sys_sunos.c linux-2.4.27-leo/arch/sparc/kernel/sys_sunos.c
--- linux-2.4.27/arch/sparc/kernel/sys_sunos.c	2004-05-19 21:34:36.000000000 +0100
+++ linux-2.4.27-leo/arch/sparc/kernel/sys_sunos.c	2004-09-17 03:19:58.000000000 +0100
@@ -68,6 +68,11 @@
 	struct file * file = NULL;
 	unsigned long retval, ret_type;
 
+#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC
+	if (flags & MAP_MIRROR)
+		return -EINVAL;
+#endif
+
 	if(flags & MAP_NORESERVE) {
 		static int cnt;
 		if (cnt++ < 10)
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/sparc/mm/fault.c linux-2.4.27-leo/arch/sparc/mm/fault.c
--- linux-2.4.27/arch/sparc/mm/fault.c	2004-09-17 02:38:43.000000000 +0100
+++ linux-2.4.27-leo/arch/sparc/mm/fault.c	2004-09-17 03:19:58.000000000 +0100
@@ -19,6 +19,9 @@
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/pagemap.h>
+#include <linux/compiler.h>
 
 #include <asm/system.h>
 #include <asm/segment.h>
@@ -219,6 +222,264 @@
 	return safe_compute_effective_address(regs, insn);
 }
 
+#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC
+void pax_emuplt_close(struct vm_area_struct * vma)
+{
+	vma->vm_mm->call_dl_resolve = 0UL;
+}
+
+static struct page* pax_emuplt_nopage(struct vm_area_struct *vma, unsigned long address, int write_access)
+{
+	struct page* page;
+	unsigned int *kaddr;
+
+	page = alloc_page(GFP_HIGHUSER);
+	if (!page)
+		return page;
+
+	kaddr = kmap(page);
+	memset(kaddr, 0, PAGE_SIZE);
+	kaddr[0] = 0x9DE3BFA8U; /* save */
+	flush_dcache_page(page);
+	kunmap(page);
+	return page;
+}
+
+static struct vm_operations_struct pax_vm_ops = {
+	close:		pax_emuplt_close,
+	nopage:		pax_emuplt_nopage,
+};
+
+static void pax_insert_vma(struct vm_area_struct *vma, unsigned long addr)
+{
+	vma->vm_mm = current->mm;
+	vma->vm_start = addr;
+	vma->vm_end = addr + PAGE_SIZE;
+	vma->vm_flags = VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYEXEC;
+	vma->vm_page_prot = protection_map[vma->vm_flags & 0x0f];
+	vma->vm_ops = &pax_vm_ops;
+	vma->vm_pgoff = 0UL;
+	vma->vm_file = NULL;
+	vma->vm_private_data = NULL;
+	insert_vm_struct(current->mm, vma);
+	++current->mm->total_vm;
+}
+
+/*
+ * PaX: decide what to do with offenders (regs->pc = fault address)
+ *
+ * returns 1 when task should be killed
+ *         2 when patched PLT trampoline was detected
+ *         3 when unpatched PLT trampoline was detected
+ *	   4 when legitimate ET_EXEC was detected
+ */
+static int pax_handle_fetch_fault(struct pt_regs *regs)
+{
+	int err;
+
+#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC
+	if (current->flags & PF_PAX_RANDEXEC) {
+		if (regs->pc >= current->mm->start_code &&
+		    regs->pc < current->mm->end_code)
+		{
+			if (regs->u_regs[UREG_RETPC] + 8UL == regs->pc)
+				return 1;
+
+			regs->pc += current->mm->delta_exec;
+			if (regs->npc >= current->mm->start_code &&
+			    regs->npc < current->mm->end_code)
+				regs->npc += current->mm->delta_exec;
+			return 4;
+		}
+		if (regs->pc >= current->mm->start_code + current->mm->delta_exec &&
+		    regs->pc < current->mm->end_code + current->mm->delta_exec)
+		{
+			regs->pc -= current->mm->delta_exec;
+			if (regs->npc >= current->mm->start_code + current->mm->delta_exec &&
+			    regs->npc < current->mm->end_code + current->mm->delta_exec)
+				regs->npc -= current->mm->delta_exec;
+		}
+	}
+#endif
+
+#ifdef CONFIG_GRKERNSEC_PAX_EMUPLT
+	do { /* PaX: patched PLT emulation #1 */
+		unsigned int sethi1, sethi2, jmpl;
+
+		err = get_user(sethi1, (unsigned int *)regs->pc);
+		err |= get_user(sethi2, (unsigned int *)(regs->pc+4));
+		err |= get_user(jmpl, (unsigned int *)(regs->pc+8));
+
+		if (err)
+			break;
+
+		if ((sethi1 & 0xFFC00000U) == 0x03000000U &&
+		    (sethi2 & 0xFFC00000U) == 0x03000000U &&
+		    (jmpl & 0xFFFFE000U) == 0x81C06000U)
+		{
+			unsigned int addr;
+
+			regs->u_regs[UREG_G1] = (sethi2 & 0x003FFFFFU) << 10;
+			addr = regs->u_regs[UREG_G1];
+			addr += (((jmpl | 0xFFFFE000U) ^ 0x00001000U) + 0x00001000U);
+			regs->pc = addr;
+			regs->npc = addr+4;
+			return 2;
+		}
+	} while (0);
+
+	{ /* PaX: patched PLT emulation #2 */
+		unsigned int ba;
+
+		err = get_user(ba, (unsigned int *)regs->pc);
+
+		if (!err && (ba & 0xFFC00000U) == 0x30800000U) {
+			unsigned int addr;
+
+			addr = regs->pc + 4 + (((ba | 0xFFC00000U) ^ 0x00200000U) + 0x00200000U);
+			regs->pc = addr;
+			regs->npc = addr+4;
+			return 2;
+		}
+	}
+
+	do { /* PaX: patched PLT emulation #3 */
+		unsigned int sethi, jmpl, nop;
+
+		err = get_user(sethi, (unsigned int*)regs->pc);
+		err |= get_user(jmpl, (unsigned int*)(regs->pc+4));
+		err |= get_user(nop, (unsigned int*)(regs->pc+8));
+
+		if (err)
+			break;
+		if ((sethi & 0xFFC00000U) == 0x03000000U &&
+		    (jmpl & 0xFFFFE000U) == 0x81C06000U &&
+		    nop == 0x01000000U)
+		{
+			unsigned int addr;
+
+			addr = (sethi & 0x003FFFFFU) << 10;
+			regs->u_regs[UREG_G1] = addr;
+			addr += (((jmpl | 0xFFFFE000U) ^ 0x00001000U) + 0x00001000U);
+			regs->pc = addr;
+			regs->npc = addr+4;
+			return 2;
+		}
+	} while (0);
+
+	do { /* PaX: unpatched PLT emulation step 1 */
+		unsigned int sethi, ba, nop;
+
+		err = get_user(sethi, (unsigned int *)regs->pc);
+		err |= get_user(ba, (unsigned int *)(regs->pc+4));
+		err |= get_user(nop, (unsigned int *)(regs->pc+8));
+
+		if (err)
+			break;
+		if ((sethi & 0xFFC00000U) == 0x03000000U &&
+		    ((ba & 0xFFC00000U) == 0x30800000U || (ba & 0xFFF80000U) == 0x30680000U) &&
+		    nop == 0x01000000U)
+		{
+			unsigned int addr, save, call;
+
+			if ((ba & 0xFFC00000U) == 0x30800000U)
+				addr = regs->pc + 4 + ((((ba | 0xFFC00000U) ^ 0x00200000U) + 0x00200000U) << 2);
+			else
+				addr = regs->pc + 4 + ((((ba | 0xFFF80000U) ^ 0x00040000U) + 0x00040000U) << 2);
+
+			err = get_user(save, (unsigned int *)addr);
+			err |= get_user(call, (unsigned int *)(addr+4));
+			err |= get_user(nop, (unsigned int *)(addr+8)); 
+			if (err)
+				break;
+
+			if (save == 0x9DE3BFA8U &&
+			    (call & 0xC0000000U) == 0x40000000U &&
+			    nop == 0x01000000U)
+			{
+				struct vm_area_struct *vma;
+				unsigned long call_dl_resolve;
+
+				down_read(&current->mm->mmap_sem);
+				call_dl_resolve = current->mm->call_dl_resolve;
+				up_read(&current->mm->mmap_sem);
+				if (likely(call_dl_resolve))
+					goto emulate;
+
+				vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
+
+				down_write(&current->mm->mmap_sem);
+				if (current->mm->call_dl_resolve) {
+					call_dl_resolve = current->mm->call_dl_resolve;
+					up_write(&current->mm->mmap_sem);
+					if (vma) kmem_cache_free(vm_area_cachep, vma);
+					goto emulate;
+				}
+
+				call_dl_resolve = get_unmapped_area(NULL, 0UL, PAGE_SIZE, 0UL, MAP_PRIVATE);
+				if (!vma || (call_dl_resolve & ~PAGE_MASK)) {
+					up_write(&current->mm->mmap_sem);
+					if (vma) kmem_cache_free(vm_area_cachep, vma);
+					return 1;
+				}
+
+				pax_insert_vma(vma, call_dl_resolve);
+				current->mm->call_dl_resolve = call_dl_resolve;
+				up_write(&current->mm->mmap_sem);
+
+emulate:
+				regs->u_regs[UREG_G1] = (sethi & 0x003FFFFFU) << 10;
+				regs->pc = call_dl_resolve;
+				regs->npc = addr+4;
+				return 3;
+			}
+		}
+	} while (0);
+
+	do { /* PaX: unpatched PLT emulation step 2 */
+		unsigned int save, call, nop;
+
+		err = get_user(save, (unsigned int*)(regs->pc-4));
+		err |= get_user(call, (unsigned int*)regs->pc);
+		err |= get_user(nop, (unsigned int*)(regs->pc+4));
+		if (err)
+			break;
+
+		if (save == 0x9DE3BFA8U &&
+		    (call & 0xC0000000U) == 0x40000000U &&
+		    nop == 0x01000000U)
+		{
+			unsigned int dl_resolve = regs->pc + ((((call | 0xC0000000U) ^ 0x20000000U) + 0x20000000U) << 2);
+
+			regs->u_regs[UREG_RETPC] = regs->pc;
+			regs->pc = dl_resolve;
+			regs->npc = dl_resolve+4;
+			return 3;
+		}
+	} while (0);
+
+#endif
+
+	return 1;
+}
+
+void pax_report_insns(void *pc)
+{
+	unsigned long i;
+
+	printk(KERN_ERR "PAX: bytes at PC: ");
+	for (i = 0; i < 5; i++) {
+		unsigned int c;
+		if (get_user(c, (unsigned int*)pc+i)) {
+			printk("<invalid address>.");
+			break;
+		}
+		printk("%08x ", c);
+	}
+	printk("\n");
+}
+#endif
+
 asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write,
 			       unsigned long address)
 {
@@ -282,6 +543,29 @@
 		if(!(vma->vm_flags & VM_WRITE))
 			goto bad_area;
 	} else {
+
+#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC
+		if ((current->flags & PF_PAX_PAGEEXEC) && text_fault && !(vma->vm_flags & VM_EXEC)) {
+			up_read(&mm->mmap_sem);
+			switch (pax_handle_fetch_fault(regs)) {
+
+#ifdef CONFIG_GRKERNSEC_PAX_EMUPLT
+			case 2:
+			case 3:
+				return;
+#endif
+
+#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC
+			case 4:
+				return;
+#endif
+
+			}
+			pax_report_fault(regs, (void*)regs->pc, (void*)regs->u_regs[UREG_FP]);
+			do_exit(SIGKILL);
+		}
+#endif
+
 		/* Allow reads even for write-only mappings */
 		if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
 			goto bad_area;
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/sparc/mm/init.c linux-2.4.27-leo/arch/sparc/mm/init.c
--- linux-2.4.27/arch/sparc/mm/init.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.27-leo/arch/sparc/mm/init.c	2004-09-17 03:19:58.000000000 +0100
@@ -350,17 +350,17 @@
 
 	/* Initialize the protection map with non-constant, MMU dependent values. */
 	protection_map[0] = PAGE_NONE;
-	protection_map[1] = PAGE_READONLY;
-	protection_map[2] = PAGE_COPY;
-	protection_map[3] = PAGE_COPY;
+	protection_map[1] = PAGE_READONLY_NOEXEC;
+	protection_map[2] = PAGE_COPY_NOEXEC;
+	protection_map[3] = PAGE_COPY_NOEXEC;
 	protection_map[4] = PAGE_READONLY;
 	protection_map[5] = PAGE_READONLY;
 	protection_map[6] = PAGE_COPY;
 	protection_map[7] = PAGE_COPY;
 	protection_map[8] = PAGE_NONE;
-	protection_map[9] = PAGE_READONLY;
-	protection_map[10] = PAGE_SHARED;
-	protection_map[11] = PAGE_SHARED;
+	protection_map[9] = PAGE_READONLY_NOEXEC;
+	protection_map[10] = PAGE_SHARED_NOEXEC;
+	protection_map[11] = PAGE_SHARED_NOEXEC;
 	protection_map[12] = PAGE_READONLY;
 	protection_map[13] = PAGE_READONLY;
 	protection_map[14] = PAGE_SHARED;
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/sparc/mm/srmmu.c linux-2.4.27-leo/arch/sparc/mm/srmmu.c
--- linux-2.4.27/arch/sparc/mm/srmmu.c	2003-11-28 18:26:19.000000000 +0000
+++ linux-2.4.27-leo/arch/sparc/mm/srmmu.c	2004-09-17 03:19:58.000000000 +0100
@@ -2047,6 +2047,13 @@
 	BTFIXUPSET_INT(page_shared, pgprot_val(SRMMU_PAGE_SHARED));
 	BTFIXUPSET_INT(page_copy, pgprot_val(SRMMU_PAGE_COPY));
 	BTFIXUPSET_INT(page_readonly, pgprot_val(SRMMU_PAGE_RDONLY));
+
+#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC
+	BTFIXUPSET_INT(page_shared_noexec, pgprot_val(SRMMU_PAGE_SHARED_NOEXEC));
+	BTFIXUPSET_INT(page_copy_noexec, pgprot_val(SRMMU_PAGE_COPY_NOEXEC));
+	BTFIXUPSET_INT(page_readonly_noexec, pgprot_val(SRMMU_PAGE_RDONLY_NOEXEC));
+#endif
+
 	BTFIXUPSET_INT(page_kernel, pgprot_val(SRMMU_PAGE_KERNEL));
 	page_kernel = pgprot_val(SRMMU_PAGE_KERNEL);
 	pg_iobits = SRMMU_VALID | SRMMU_WRITE | SRMMU_REF;
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/sparc64/config.in linux-2.4.27-leo/arch/sparc64/config.in
--- linux-2.4.27/arch/sparc64/config.in	2004-09-17 02:38:43.000000000 +0100
+++ linux-2.4.27-leo/arch/sparc64/config.in	2004-09-17 03:19:58.000000000 +0100
@@ -320,3 +320,11 @@
 
 source crypto/Config.in
 source lib/Config.in
+
+mainmenu_option next_comment
+comment 'Grsecurity'
+bool 'Grsecurity' CONFIG_GRKERNSEC
+if [ "$CONFIG_GRKERNSEC" = "y" ]; then
+	source grsecurity/Config.in
+fi
+endmenu
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/sparc64/kernel/ioctl32.c linux-2.4.27-leo/arch/sparc64/kernel/ioctl32.c
--- linux-2.4.27/arch/sparc64/kernel/ioctl32.c	2004-09-17 02:38:43.000000000 +0100
+++ linux-2.4.27-leo/arch/sparc64/kernel/ioctl32.c	2004-09-17 03:19:58.000000000 +0100
@@ -56,6 +56,7 @@
 #if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE)
 #include <linux/lvm.h>
 #endif /* LVM */
+#include <linux/dm-ioctl.h>
 
 #include <scsi/scsi.h>
 /* Ugly hack. */
@@ -2048,7 +2049,11 @@
 	 * To have permissions to do most of the vt ioctls, we either have
 	 * to be the owner of the tty, or super-user.
 	 */
+#ifdef CONFIG_GRKERNSEC
+	if (current->tty == tty || capable(CAP_SYS_TTY_CONFIG))
+#else
 	if (current->tty == tty || suser())
+#endif
 		return 1;
 	return 0;                                                    
 }
@@ -5090,6 +5095,22 @@
 COMPATIBLE_IOCTL(NBD_PRINT_DEBUG)
 COMPATIBLE_IOCTL(NBD_SET_SIZE_BLOCKS)
 COMPATIBLE_IOCTL(NBD_DISCONNECT)
+/* device-mapper */
+#if defined(CONFIG_BLK_DEV_DM) || defined(CONFIG_BLK_DEV_DM_MODULE)
+COMPATIBLE_IOCTL(DM_VERSION)
+COMPATIBLE_IOCTL(DM_REMOVE_ALL)
+COMPATIBLE_IOCTL(DM_DEV_CREATE)
+COMPATIBLE_IOCTL(DM_DEV_REMOVE)
+COMPATIBLE_IOCTL(DM_TABLE_LOAD)
+COMPATIBLE_IOCTL(DM_DEV_SUSPEND)
+COMPATIBLE_IOCTL(DM_DEV_RENAME)
+COMPATIBLE_IOCTL(DM_TABLE_DEPS)
+COMPATIBLE_IOCTL(DM_DEV_STATUS)
+COMPATIBLE_IOCTL(DM_TABLE_STATUS)
+COMPATIBLE_IOCTL(DM_DEV_WAIT)
+COMPATIBLE_IOCTL(DM_LIST_DEVICES)
+COMPATIBLE_IOCTL(DM_TABLE_CLEAR)
+#endif /* CONFIG_BLK_DEV_DM */
 /* Linux-1394 */
 #if defined(CONFIG_IEEE1394) || defined(CONFIG_IEEE1394_MODULE)
 COMPATIBLE_IOCTL(AMDTP_IOC_CHANNEL)
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/sparc64/kernel/itlb_base.S linux-2.4.27-leo/arch/sparc64/kernel/itlb_base.S
--- linux-2.4.27/arch/sparc64/kernel/itlb_base.S	2003-06-13 15:51:32.000000000 +0100
+++ linux-2.4.27-leo/arch/sparc64/kernel/itlb_base.S	2004-09-17 03:19:58.000000000 +0100
@@ -41,7 +41,9 @@
 	CREATE_VPTE_OFFSET2(%g4, %g6)			! Create VPTE offset
 	ldxa		[%g3 + %g6] ASI_P, %g5		! Load VPTE
 1:	brgez,pn	%g5, 3f				! Not valid, branch out
-	 nop						! Delay-slot
+	and		%g5, _PAGE_EXEC, %g4
+	brz,pn		%g4, 3f				! Not executable, branch out
+	nop						! Delay-slot
 2:	stxa		%g5, [%g0] ASI_ITLB_DATA_IN	! Load PTE into TLB
 	retry						! Trap return
 3:	rdpr		%pstate, %g4			! Move into alternate globals
@@ -74,8 +76,6 @@
 	nop
 	nop
 	nop
-	nop
-	nop
 	CREATE_VPTE_NOP
 
 #undef CREATE_VPTE_OFFSET1
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/sparc64/kernel/ptrace.c linux-2.4.27-leo/arch/sparc64/kernel/ptrace.c
--- linux-2.4.27/arch/sparc64/kernel/ptrace.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.27-leo/arch/sparc64/kernel/ptrace.c	2004-09-17 03:19:58.000000000 +0100
@@ -18,6 +18,7 @@
 #include <linux/user.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
+#include <linux/grsecurity.h>
 
 #include <asm/asi.h>
 #include <asm/pgtable.h>
@@ -161,6 +162,11 @@
 		goto out;
 	}
 
+	if (gr_handle_ptrace(child, (long)request)) {
+		pt_error_return(regs, EPERM);
+		goto out_tsk;
+	}
+
 	if ((current->personality == PER_SUNOS && request == PTRACE_SUNATTACH)
 	    || (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) {
 		if (ptrace_attach(child)) {
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/sparc64/kernel/sys_sparc32.c linux-2.4.27-leo/arch/sparc64/kernel/sys_sparc32.c
--- linux-2.4.27/arch/sparc64/kernel/sys_sparc32.c	2004-09-17 02:38:43.000000000 +0100
+++ linux-2.4.27-leo/arch/sparc64/kernel/sys_sparc32.c	2004-09-17 03:19:58.000000000 +0100
@@ -52,6 +52,8 @@
 #include <linux/sysctl.h>
 #include <linux/dnotify.h>
 #include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/random.h>
+#include <linux/grsecurity.h>
 
 #include <asm/types.h>
 #include <asm/ipc.h>
@@ -3239,8 +3241,18 @@
 	struct file * file;
 	int retval;
 	int i;
+#ifdef CONFIG_GRKERNSEC
+	struct file *old_exec_file;
+	struct acl_subject_label *old_acl;
+	struct rlimit old_rlim[RLIM_NLIMITS];
+#endif
 
 	bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
+
+#ifdef CONFIG_GRKERNSEC_PAX_RANDUSTACK
+	bprm.p -= (get_random_long() & ~(sizeof(void *)-1)) & ~PAGE_MASK;
+#endif
+
 	memset(bprm.page, 0, MAX_ARG_PAGES * sizeof(bprm.page[0]));
 
 	file = open_exec(filename);
@@ -3249,6 +3261,20 @@
 	if (IS_ERR(file))
 		return retval;
 
+	gr_learn_resource(current, RLIMIT_NPROC, atomic_read(&current->user->processes), 1);
+
+	if (gr_handle_nproc()) {
+		allow_write_access(file);
+		fput(file);
+		return -EAGAIN;
+	}
+
+	if (!gr_acl_handle_execve(file->f_dentry, file->f_vfsmnt)) {
+		allow_write_access(file);
+		fput(file);
+		return -EACCES;
+	}
+
 	bprm.file = file;
 	bprm.filename = filename;
 	bprm.sh_bang = 0;
@@ -3269,11 +3295,24 @@
 	if (retval < 0)
 		goto out;
 	
+	if(!gr_tpe_allow(file)) {
+		retval = -EACCES;
+		goto out;
+	}
+
+	if (gr_check_crash_exec(file)) {
+		retval = -EACCES;
+		goto out;
+	}
+
 	retval = copy_strings_kernel(1, &bprm.filename, &bprm);
 	if (retval < 0)
 		goto out;
 
 	bprm.exec = bprm.p;
+
+	gr_log_chroot_exec(file->f_dentry, file->f_vfsmnt);
+
 	retval = copy_strings32(bprm.envc, envp, &bprm);
 	if (retval < 0)
 		goto out;
@@ -3282,11 +3321,32 @@
 	if (retval < 0)
 		goto out;
 
+#ifdef CONFIG_GRKERNSEC
+	old_acl = current->acl;
+	memcpy(old_rlim, current->rlim, sizeof(old_rlim));
+	old_exec_file = current->exec_file;
+	get_file(file);
+	current->exec_file = file;
+#endif
+
+        gr_set_proc_label(file->f_dentry, file->f_vfsmnt);
+
 	retval = search_binary_handler(&bprm, regs);
-	if (retval >= 0)
+	if (retval >= 0) {
+#ifdef CONFIG_GRKERNSEC
+		if (old_exec_file)
+			fput(old_exec_file);
+#endif
 		/* execve success */
 		return retval;
+	}
 
+#ifdef CONFIG_GRKERNSEC
+	current->acl = old_acl;
+	memcpy(current->rlim, old_rlim, sizeof(old_rlim));
+	fput(current->exec_file);
+	current->exec_file = old_exec_file;
+#endif
 out:
 	/* Something went wrong, return the inode and free the argument pages*/
 	allow_write_access(bprm.file);
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/sparc64/kernel/sys_sparc.c linux-2.4.27-leo/arch/sparc64/kernel/sys_sparc.c
--- linux-2.4.27/arch/sparc64/kernel/sys_sparc.c	2003-08-25 12:44:40.000000000 +0100
+++ linux-2.4.27-leo/arch/sparc64/kernel/sys_sparc.c	2004-09-17 03:19:58.000000000 +0100
@@ -24,6 +24,7 @@
 #include <linux/slab.h>
 #include <linux/ipc.h>
 #include <linux/personality.h>
+#include <linux/grsecurity.h>
 
 #include <asm/uaccess.h>
 #include <asm/ipc.h>
@@ -63,6 +64,13 @@
 		task_size = 0xf0000000UL;
 	if (len > task_size || len > -PAGE_OFFSET)
 		return -ENOMEM;
+
+#ifdef CONFIG_GRKERNSEC_PAX_RANDMMAP
+	if ((current->flags & PF_PAX_RANDMMAP) && (!addr || filp))
+		addr = TASK_UNMAPPED_BASE + current->mm->delta_mmap;
+	else
+#endif
+
 	if (!addr)
 		addr = TASK_UNMAPPED_BASE;
 
@@ -289,11 +297,22 @@
 	struct file * file = NULL;
 	unsigned long retval = -EBADF;
 
+#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC
+	if (flags & MAP_MIRROR)
+		return -EINVAL;
+#endif
+
 	if (!(flags & MAP_ANONYMOUS)) {
 		file = fget(fd);
 		if (!file)
 			goto out;
 	}
+
+	if (gr_handle_mmap(file, prot)) {
+		retval = -EACCES;
+		goto out_putf;
+	}
+
 	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 	len = PAGE_ALIGN(len);
 	retval = -EINVAL;
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/sparc64/kernel/sys_sunos32.c linux-2.4.27-leo/arch/sparc64/kernel/sys_sunos32.c
--- linux-2.4.27/arch/sparc64/kernel/sys_sunos32.c	2004-09-17 02:38:43.000000000 +0100
+++ linux-2.4.27-leo/arch/sparc64/kernel/sys_sunos32.c	2004-09-17 03:19:58.000000000 +0100
@@ -68,6 +68,11 @@
 	struct file *file = NULL;
 	unsigned long retval, ret_type;
 
+#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC
+	if (flags & MAP_MIRROR)
+		return -EINVAL;
+#endif
+
 	if(flags & MAP_NORESERVE) {
 		static int cnt;
 		if (cnt++ < 10)
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/sparc64/mm/fault.c linux-2.4.27-leo/arch/sparc64/mm/fault.c
--- linux-2.4.27/arch/sparc64/mm/fault.c	2004-09-17 02:38:43.000000000 +0100
+++ linux-2.4.27-leo/arch/sparc64/mm/fault.c	2004-09-17 03:19:58.000000000 +0100
@@ -16,6 +16,9 @@
 #include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/pagemap.h>
+#include <linux/compiler.h>
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
@@ -306,6 +309,363 @@
 	unhandled_fault (address, current, regs);
 }
 
+#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC
+#ifdef CONFIG_GRKERNSEC_PAX_EMUPLT
+static void pax_emuplt_close(struct vm_area_struct * vma)
+{
+	vma->vm_mm->call_dl_resolve = 0UL;
+}
+
+static struct page* pax_emuplt_nopage(struct vm_area_struct *vma, unsigned long address, int write_access)
+{
+	struct page* page;
+	unsigned int *kaddr;
+
+	page = alloc_page(GFP_HIGHUSER);
+	if (!page)
+		return page;
+
+	kaddr = kmap(page);
+	memset(kaddr, 0, PAGE_SIZE);
+	kaddr[0] = 0x9DE3BFA8U; /* save */
+	flush_dcache_page(page);
+	kunmap(page);
+	return page;
+}
+
+static struct vm_operations_struct pax_vm_ops = {
+	close:		pax_emuplt_close,
+	nopage:		pax_emuplt_nopage,
+};
+
+static void pax_insert_vma(struct vm_area_struct *vma, unsigned long addr)
+{
+	vma->vm_mm = current->mm;
+	vma->vm_start = addr;
+	vma->vm_end = addr + PAGE_SIZE;
+	vma->vm_flags = VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYEXEC;
+	vma->vm_page_prot = protection_map[vma->vm_flags & 0x0f];
+	vma->vm_ops = &pax_vm_ops;
+	vma->vm_pgoff = 0UL; 
+	vma->vm_file = NULL;
+	vma->vm_private_data = NULL;
+	insert_vm_struct(current->mm, vma);
+	++current->mm->total_vm;
+}
+#endif
+
+/*
+ * PaX: decide what to do with offenders (regs->tpc = fault address)
+ *
+ * returns 1 when task should be killed
+ *         2 when patched PLT trampoline was detected
+ *         3 when unpatched PLT trampoline was detected
+ *	   4 when legitimate ET_EXEC was detected
+ */
+static int pax_handle_fetch_fault(struct pt_regs *regs)
+{
+
+#ifdef CONFIG_GRKERNSEC_PAX_EMUPLT
+	int err;
+#endif
+
+#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC
+	if (current->flags & PF_PAX_RANDEXEC) {
+		if (regs->tpc >= current->mm->start_code &&
+		    regs->tpc < current->mm->end_code)
+		{
+			if (regs->u_regs[UREG_RETPC] + 8UL == regs->tpc)
+				return 1;
+
+			regs->tpc += current->mm->delta_exec;
+			if (regs->tnpc >= current->mm->start_code &&
+			    regs->tnpc < current->mm->end_code)
+				regs->tnpc += current->mm->delta_exec;
+			return 4;
+		}
+		if (regs->tpc >= current->mm->start_code + current->mm->delta_exec &&
+		    regs->tpc < current->mm->end_code + current->mm->delta_exec)
+		{
+			regs->tpc -= current->mm->delta_exec;
+			if (regs->tnpc >= current->mm->start_code + current->mm->delta_exec &&
+			    regs->tnpc < current->mm->end_code + current->mm->delta_exec)
+				regs->tnpc -= current->mm->delta_exec;
+		}
+	}
+#endif
+
+#ifdef CONFIG_GRKERNSEC_PAX_EMUPLT
+	do { /* PaX: patched PLT emulation #1 */
+		unsigned int sethi1, sethi2, jmpl;
+
+		err = get_user(sethi1, (unsigned int*)regs->tpc);
+		err |= get_user(sethi2, (unsigned int*)(regs->tpc+4));
+		err |= get_user(jmpl, (unsigned int*)(regs->tpc+8));
+
+		if (err)
+			break;
+
+		if ((sethi1 & 0xFFC00000U) == 0x03000000U &&
+		    (sethi2 & 0xFFC00000U) == 0x03000000U &&
+		    (jmpl & 0xFFFFE000U) == 0x81C06000U)
+		{
+			unsigned long addr;
+
+			regs->u_regs[UREG_G1] = (sethi2 & 0x003FFFFFU) << 10;
+			addr = regs->u_regs[UREG_G1];
+			addr += (((jmpl | 0xFFFFFFFFFFFFE000UL) ^ 0x00001000UL) + 0x00001000UL);
+			regs->tpc = addr;
+			regs->tnpc = addr+4;
+			return 2;
+		}
+	} while (0);
+
+	{ /* PaX: patched PLT emulation #2 */
+		unsigned int ba;
+
+		err = get_user(ba, (unsigned int*)regs->tpc);
+
+		if (!err && (ba & 0xFFC00000U) == 0x30800000U) {
+			unsigned long addr;
+
+			addr = regs->tpc + 4 + (((ba | 0xFFFFFFFFFFC00000UL) ^ 0x00200000UL) + 0x00200000UL);
+			regs->tpc = addr;
+			regs->tnpc = addr+4;
+			return 2;
+		}
+	}
+
+	do { /* PaX: patched PLT emulation #3 */
+		unsigned int sethi, jmpl, nop;
+
+		err = get_user(sethi, (unsigned int*)regs->tpc);
+		err |= get_user(jmpl, (unsigned int*)(regs->tpc+4));
+		err |= get_user(nop, (unsigned int*)(regs->tpc+8));
+
+		if (err)
+			break;
+
+		if ((sethi & 0xFFC00000U) == 0x03000000U &&
+		    (jmpl & 0xFFFFE000U) == 0x81C06000U &&
+		    nop == 0x01000000U)
+		{
+			unsigned long addr;
+
+			addr = (sethi & 0x003FFFFFU) << 10;
+			regs->u_regs[UREG_G1] = addr;
+			addr += (((jmpl | 0xFFFFFFFFFFFFE000UL) ^ 0x00001000UL) + 0x00001000UL);
+			regs->tpc = addr;
+			regs->tnpc = addr+4;
+			return 2;
+		}
+	} while (0);
+
+	do { /* PaX: patched PLT emulation #4 */
+		unsigned int mov1, call, mov2;
+
+		err = get_user(mov1, (unsigned int*)regs->tpc);
+		err |= get_user(call, (unsigned int*)(regs->tpc+4));
+		err |= get_user(mov2, (unsigned int*)(regs->tpc+8));
+
+		if (err)
+			break;
+
+		if (mov1 == 0x8210000FU &&
+		    (call & 0xC0000000U) == 0x40000000U &&
+		    mov2 == 0x9E100001U)
+		{
+			unsigned long addr;
+
+			regs->u_regs[UREG_G1] = regs->u_regs[UREG_RETPC];
+			addr = regs->tpc + 4 + ((((call | 0xFFFFFFFFC0000000UL) ^ 0x20000000UL) + 0x20000000UL) << 2);
+			regs->tpc = addr;
+			regs->tnpc = addr+4;
+			return 2;
+		}
+	} while (0);
+
+	do { /* PaX: patched PLT emulation #5 */
+		unsigned int sethi1, sethi2, or1, or2, sllx, jmpl, nop;
+
+		err = get_user(sethi1, (unsigned int*)regs->tpc);
+		err |= get_user(sethi2, (unsigned int*)(regs->tpc+4));
+		err |= get_user(or1, (unsigned int*)(regs->tpc+8));
+		err |= get_user(or2, (unsigned int*)(regs->tpc+12));
+		err |= get_user(sllx, (unsigned int*)(regs->tpc+16));
+		err |= get_user(jmpl, (unsigned int*)(regs->tpc+20));
+		err |= get_user(nop, (unsigned int*)(regs->tpc+24));
+
+		if (err)
+			break;
+
+		if ((sethi1 & 0xFFC00000U) == 0x03000000U &&
+		    (sethi2 & 0xFFC00000U) == 0x0B000000U &&
+		    (or1 & 0xFFFFE000U) == 0x82106000U &&
+		    (or2 & 0xFFFFE000U) == 0x8A116000U &&
+		    sllx == 0x83287020 &&
+		    jmpl == 0x81C04005U &&
+		    nop == 0x01000000U)
+		{
+			unsigned long addr;
+
+			regs->u_regs[UREG_G1] = ((sethi1 & 0x003FFFFFU) << 10) | (or1 & 0x000003FFU);
+			regs->u_regs[UREG_G1] <<= 32;
+			regs->u_regs[UREG_G5] = ((sethi2 & 0x003FFFFFU) << 10) | (or2 & 0x000003FFU);
+			addr = regs->u_regs[UREG_G1] + regs->u_regs[UREG_G5];
+			regs->tpc = addr;
+			regs->tnpc = addr+4;
+			return 2;
+		}
+	} while (0);
+
+	do { /* PaX: patched PLT emulation #6 */
+		unsigned int sethi1, sethi2, sllx, or,  jmpl, nop;
+
+		err = get_user(sethi1, (unsigned int*)regs->tpc);
+		err |= get_user(sethi2, (unsigned int*)(regs->tpc+4));
+		err |= get_user(sllx, (unsigned int*)(regs->tpc+8));
+		err |= get_user(or, (unsigned int*)(regs->tpc+12));
+		err |= get_user(jmpl, (unsigned int*)(regs->tpc+16));
+		err |= get_user(nop, (unsigned int*)(regs->tpc+20));
+
+		if (err)
+			break;
+
+		if ((sethi1 & 0xFFC00000U) == 0x03000000U &&
+		    (sethi2 & 0xFFC00000U) == 0x0B000000U &&
+		    sllx == 0x83287020 &&
+		    (or & 0xFFFFE000U) == 0x8A116000U &&
+		    jmpl == 0x81C04005U &&
+		    nop == 0x01000000U)
+		{
+			unsigned long addr;
+
+			regs->u_regs[UREG_G1] = (sethi1 & 0x003FFFFFU) << 10;
+			regs->u_regs[UREG_G1] <<= 32;
+			regs->u_regs[UREG_G5] = ((sethi2 & 0x003FFFFFU) << 10) | (or & 0x3FFU);
+			addr = regs->u_regs[UREG_G1] + regs->u_regs[UREG_G5];
+			regs->tpc = addr;
+			regs->tnpc = addr+4;
+			return 2;
+		}
+	} while (0);
+
+	do { /* PaX: unpatched PLT emulation step 1 */
+		unsigned int sethi, ba, nop;
+
+		err = get_user(sethi, (unsigned int*)regs->tpc);
+		err |= get_user(ba, (unsigned int*)(regs->tpc+4));
+		err |= get_user(nop, (unsigned int*)(regs->tpc+8));
+
+		if (err)
+			break;
+
+		if ((sethi & 0xFFC00000U) == 0x03000000U &&
+		    ((ba & 0xFFC00000U) == 0x30800000U || (ba & 0xFFF80000U) == 0x30680000U) &&
+		    nop == 0x01000000U)
+		{
+			unsigned long addr;
+			unsigned int save, call;
+
+			if ((ba & 0xFFC00000U) == 0x30800000U)
+				addr = regs->tpc + 4 + ((((ba | 0xFFFFFFFFFFC00000UL) ^ 0x00200000UL) + 0x00200000UL) << 2);
+			else
+				addr = regs->tpc + 4 + ((((ba | 0xFFFFFFFFFFF80000UL) ^ 0x00040000UL) + 0x00040000UL) << 2);
+
+			err = get_user(save, (unsigned int*)addr);
+			err |= get_user(call, (unsigned int*)(addr+4));
+			err |= get_user(nop, (unsigned int*)(addr+8));
+
+			if (err)
+				break;
+
+			if (save == 0x9DE3BFA8U &&
+			    (call & 0xC0000000U) == 0x40000000U &&
+			    nop == 0x01000000U)
+			{
+				struct vm_area_struct *vma;
+				unsigned long call_dl_resolve;
+
+				down_read(&current->mm->mmap_sem);
+				call_dl_resolve = current->mm->call_dl_resolve;
+				up_read(&current->mm->mmap_sem);
+				if (likely(call_dl_resolve))
+					goto emulate;
+
+				vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
+
+				down_write(&current->mm->mmap_sem);
+				if (current->mm->call_dl_resolve) {
+					call_dl_resolve = current->mm->call_dl_resolve;
+					up_write(&current->mm->mmap_sem);
+					if (vma) kmem_cache_free(vm_area_cachep, vma);
+					goto emulate;
+				}
+
+				call_dl_resolve = get_unmapped_area(NULL, 0UL, PAGE_SIZE, 0UL, MAP_PRIVATE);
+				if (!vma || (call_dl_resolve & ~PAGE_MASK)) {
+					up_write(&current->mm->mmap_sem);
+					if (vma) kmem_cache_free(vm_area_cachep, vma);
+					return 1;
+				}
+
+				pax_insert_vma(vma, call_dl_resolve);
+				current->mm->call_dl_resolve = call_dl_resolve;
+				up_write(&current->mm->mmap_sem);
+
+emulate:
+				regs->u_regs[UREG_G1] = (sethi & 0x003FFFFFU) << 10;
+				regs->tpc = call_dl_resolve;
+				regs->tnpc = addr+4;
+				return 3;
+			}
+		}
+	} while (0);
+
+	do { /* PaX: unpatched PLT emulation step 2 */
+		unsigned int save, call, nop;
+
+		err = get_user(save, (unsigned int*)(regs->tpc-4));
+		err |= get_user(call, (unsigned int*)regs->tpc);
+		err |= get_user(nop, (unsigned int*)(regs->tpc+4));
+		if (err)
+			break;
+
+		if (save == 0x9DE3BFA8U &&
+		    (call & 0xC0000000U) == 0x40000000U &&
+		    nop == 0x01000000U)
+		{
+			unsigned long dl_resolve = regs->tpc + ((((call | 0xFFFFFFFFC0000000UL) ^ 0x20000000UL) + 0x20000000UL) << 2);
+
+			regs->u_regs[UREG_RETPC] = regs->tpc;
+			regs->tpc = dl_resolve;
+			regs->tnpc = dl_resolve+4;
+			return 3;
+		}
+	} while (0);
+#endif
+
+	return 1;
+}
+
+void pax_report_insns(void *pc)
+{
+	unsigned long i;
+
+	printk(KERN_ERR "PAX: bytes at PC: ");
+	for (i = 0; i < 5; i++) {
+		unsigned int c;
+		if (get_user(c, (unsigned int*)pc+i)) {
+			printk("<invalid address>.");
+			break;
+		}
+		printk("%08x ", c);
+	}
+	printk("\n");
+}
+#endif  
+
+
 asmlinkage void do_sparc64_fault(struct pt_regs *regs)
 {
 	struct mm_struct *mm = current->mm;
@@ -345,6 +705,7 @@
 
 	if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
 		regs->tpc &= 0xffffffff;
+		regs->tnpc &= 0xffffffff;
 		address &= 0xffffffff;
 	}
 
@@ -353,6 +714,34 @@
 	if (!vma)
 		goto bad_area;
 
+	/* PaX: detect ITLB misses on non-exec pages */
+#ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC
+	if ((current->flags & PF_PAX_PAGEEXEC) && vma->vm_start <= address && 
+	    !(vma->vm_flags & VM_EXEC) && (fault_code & FAULT_CODE_ITLB))
+	{
+		if (address != regs->tpc)
+			goto good_area;
+
+		up_read(&mm->mmap_sem);
+		switch (pax_handle_fetch_fault(regs)) {
+
+#ifdef CONFIG_GRKERNSEC_PAX_EMUPLT
+		case 2:
+		case 3:
+			goto fault_done;
+#endif
+
+#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC
+		case 4:
+			goto fault_done;
+#endif
+
+		}
+		pax_report_fault(regs, (void*)regs->tpc, (void*)(regs->u_regs[UREG_FP] + STACK_BIAS));
+		do_exit(SIGKILL);
+	}
+#endif
+
 	/* Pure DTLB misses do not tell us whether the fault causing
 	 * load/store/atomic was a write or not, it only says that there
 	 * was no match.  So in such a case we (carefully) read the
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/sparc64/solaris/misc.c linux-2.4.27-leo/arch/sparc64/solaris/misc.c
--- linux-2.4.27/arch/sparc64/solaris/misc.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.27-leo/arch/sparc64/solaris/misc.c	2004-09-17 03:19:58.000000000 +0100
@@ -53,6 +53,11 @@
 	struct file *file = NULL;
 	unsigned long retval, ret_type;
 
+#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC
+	if (flags & MAP_MIRROR)
+		return -EINVAL;
+#endif
+
 	/* Do we need it here? */
 	set_personality(PER_SVR4);
 	if (flags & MAP_NORESERVE) {
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/x86_64/ia32/ia32_ioctl.c linux-2.4.27-leo/arch/x86_64/ia32/ia32_ioctl.c
--- linux-2.4.27/arch/x86_64/ia32/ia32_ioctl.c	2004-05-19 21:34:37.000000000 +0100
+++ linux-2.4.27-leo/arch/x86_64/ia32/ia32_ioctl.c	2004-09-17 03:19:58.000000000 +0100
@@ -68,6 +68,7 @@
 #define max max
 #include <linux/lvm.h>
 #endif /* LVM */
+#include <linux/dm-ioctl.h>
 
 #include <scsi/scsi.h>
 /* Ugly hack. */
@@ -1950,7 +1951,11 @@
 	 * To have permissions to do most of the vt ioctls, we either have
 	 * to be the owner of the tty, or super-user.
 	 */
+#ifdef CONFIG_GRKERNSEC
+	if (current->tty == tty || capable(CAP_SYS_TTY_CONFIG))
+#else
 	if (current->tty == tty || suser())
+#endif
 		return 1;
 	return 0;                                                    
 }
@@ -4140,6 +4145,22 @@
 COMPATIBLE_IOCTL(LV_BMAP)
 COMPATIBLE_IOCTL(LV_SNAPSHOT_USE_RATE)
 #endif /* LVM */
+/* Device-Mapper */
+#if defined(CONFIG_BLK_DEV_DM) || defined(CONFIG_BLK_DEV_DM_MODULE)
+COMPATIBLE_IOCTL(DM_VERSION)
+COMPATIBLE_IOCTL(DM_REMOVE_ALL)
+COMPATIBLE_IOCTL(DM_DEV_CREATE)
+COMPATIBLE_IOCTL(DM_DEV_REMOVE)
+COMPATIBLE_IOCTL(DM_TABLE_LOAD)
+COMPATIBLE_IOCTL(DM_DEV_SUSPEND)
+COMPATIBLE_IOCTL(DM_DEV_RENAME)
+COMPATIBLE_IOCTL(DM_TABLE_DEPS)
+COMPATIBLE_IOCTL(DM_DEV_STATUS)
+COMPATIBLE_IOCTL(DM_TABLE_STATUS)
+COMPATIBLE_IOCTL(DM_DEV_WAIT)
+COMPATIBLE_IOCTL(DM_LIST_DEVICES)
+COMPATIBLE_IOCTL(DM_TABLE_CLEAR)
+#endif /* CONFIG_BLK_DEV_DM */
 #ifdef CONFIG_AUTOFS_FS
 COMPATIBLE_IOCTL(AUTOFS_IOC_READY)
 COMPATIBLE_IOCTL(AUTOFS_IOC_FAIL)
diff -urN --exclude-from=diff-exclude linux-2.4.27/arch/x86_64/ia32/sys_ia32.c linux-2.4.27-leo/arch/x86_64/ia32/sys_ia32.c
--- linux-2.4.27/arch/x86_64/ia32/sys_ia32.c	2004-05-19 21:34:37.000000000 +0100
+++ linux-2.4.27-leo/arch/x86_64/ia32/sys_ia32.c	2004-09-17 03:19:58.000000000 +0100
@@ -327,6 +327,11 @@
 	if (a.offset & ~PAGE_MASK)
 		return -EINVAL; 
 
+#ifdef CONFIG_GRKERNSEC_PAX_RANDEXEC
+	if (a.flags & MAP_MIRROR)
+		return -EINVAL;
+#endif
+
 	if (!(a.flags & MAP_ANONYMOUS)) {
 		file = fget(a.fd);
 		if (!file)
diff -urN --exclude-from=diff-exclude linux-2.4.27/CREDITS linux-2.4.27-leo/CREDITS
--- linux-2.4.27/CREDITS	2004-09-17 02:38:42.000000000 +0100
+++ linux-2.4.27-leo/CREDITS	2004-09-17 03:19:36.000000000 +0100
@@ -999,8 +999,8 @@
 
 N: Nigel Gamble
 E: nigel@nrg.org
-E: nigel@sgi.com
 D: Interrupt-driven printer driver
+D: Preemptible kernel
 S: 120 Alley Way
 S: Mountain View, California 94040
 S: USA
diff -urN --exclude-from=diff-exclude linux-2.4.27/crypto/Config.in linux-2.4.27-leo/crypto/Config.in
--- linux-2.4.27/crypto/Config.in	2004-09-17 02:38:43.000000000 +0100
+++ linux-2.4.27-leo/crypto/Config.in	2004-09-17 03:19:04.000000000 +0100
@@ -4,7 +4,9 @@
 mainmenu_option next_comment
 comment 'Cryptographic options'
 
-if [ "$CONFIG_INET_AH" = "y" -o \
+if [ "$CONFIG_BLK_DEV_CRYPTOLOOP" = "y" -o \
+     "$CONFIG_BLK_DEV_CRYPTOLOOP" = "m" -o \
+     "$CONFIG_INET_AH" = "y" -o \
      "$CONFIG_INET_AH" = "m" -o \
      "$CONFIG_INET_ESP" = "y" -o \
      "$CONFIG_INET_ESP" = "m" -o \
diff -urN --exclude-from=diff-exclude linux-2.4.27/Documentation/Configure.help linux-2.4.27-leo/Documentation/Configure.help
--- linux-2.4.27/Documentation/Configure.help	2004-09-17 02:38:42.000000000 +0100
+++ linux-2.4.27-leo/Documentation/Configure.help	2004-09-20 21:34:47.000000000 +0100
@@ -296,6 +296,17 @@
   If you have a system with several CPUs, you do not need to say Y
   here: the local APIC will be used automatically.
 
+Preemptible Kernel
+CONFIG_PREEMPT
+  This option reduces the latency of the kernel when reacting to
+  real-time or interactive events by allowing a low priority process to
+  be preempted even if it is in kernel mode executing a system call.
+  This allows applications to run more reliably even when the system is
+  under load.
+
+  Say Y here if you are building a kernel for a desktop, embedded or
+  real-time system.  Say N if you are unsure.
+
 Kernel math emulation
 CONFIG_MATH_EMULATION
   Linux can emulate a math coprocessor (used for floating point
@@ -1953,6 +1964,20 @@
   want), say M here and read <file:Documentation/modules.txt>.  The
   module will be called lvm-mod.o.
 
+Device-mapper support
+CONFIG_BLK_DEV_DM
+  Device-mapper is a low level volume manager.  It works by allowing
+  people to specify mappings for ranges of logical sectors.  Various
+  mapping types are available, in addition people may write their own
+  modules containing custom mappings if they wish.
+
+  Higher level volume managers such as LVM2 use this driver.
+
+  If you want to compile this as a module, say M here and read 
+  <file:Documentation/modules.txt>.  The module will be called dm-mod.o.
+
+  If unsure, say N.
+
 Multiple devices driver support (RAID and LVM)
 CONFIG_MD
   Support multiple physical spindles through a single logical device.
@@ -2061,6 +2086,18 @@
 
   If unsure, say Y.
 
+Verbose startup / shutdown messages
+CONFIG_MD_VERBMSG
+  If set, display verbose messages on kernel startup about RAID
+  device initialisation. This can slow down startup by a few seconds,
+  especially on framebuffer terminal types, or if a lot of RAID
+  devices are present, and also fills up space in the dmesg buffer
+  that could be useful elsewhere. However, it aids tracking down 
+  certain RAID problems. It adds about 1k to the kernel size.
+
+  If unsure, say Y. Even if un-set, error messages are still
+  reported
+
 Multipath I/O support
 CONFIG_MD_MULTIPATH
   Multipath-IO is the ability of certain devices to address the same
@@ -2874,6 +2911,20 @@
   If you want to compile it as a module, say M here and read
   Documentation/modules.txt.  If unsure, say `N'.
 
+stealth networking support
+CONFIG_IP_NF_MATCH_STEALTH
+  Enabling this option will drop all syn packets coming to unserved tcp
+  ports as well as all packets coming to unserved udp ports.  If you
+  are using your system to route any type of packets (ie. via NAT)
+  you should put this module at the end of your ruleset, since it will 
+  drop packets that aren't going to ports that are listening on your 
+  machine itself, it doesn't take into account that the packet might be 
+  destined for someone on your internal network if you're using NAT for 
+  instance.
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
+
 MAC address match support
 CONFIG_IP_NF_MATCH_MAC
   MAC matching allows you to match packets based on the source
@@ -19326,6 +19377,16 @@
   <file:Documentation/modules.txt>.
   The module will be called i2c-velleman.o.
 
+Basic I2C on Parallel Port adapter
+CONFIG_I2C_PPORT
+  This supports directly connecting I2C devices to the parallel port.
+  See <file:Documentation/i2c/i2c-pport> for more information.
+
+  This driver is also available as a module.  If you want to compile
+  it as a module, say M here and read
+  <file:Documentation/modules.txt>.
+  The module will be called i2c-pport.o.
+
 I2C PCF 8584 interfaces
 CONFIG_I2C_ALGOPCF
   This allows you to use a range of I2C adapters called PCF adapters.
@@ -19347,6 +19408,15 @@
   <file:Documentation/modules.txt>.
   The module will be called i2c-elektor.o.
 
+PCF on the EPP Parallel Port
+CONFIG_I2C_PCFEPP
+  This supports the PCF8584 connected to the parallel port.
+
+  This driver is also available as a module.  If you want to compile
+  it as a module, say M here and read
+  <file:Documentation/modules.txt>.
+  The module will be called i2c-pcf-epp.o.
+
 ITE I2C Algorithm
 CONFIG_ITE_I2C_ALGO
   This supports the use the ITE8172 I2C interface found on some MIPS
@@ -19384,6 +19454,51 @@
   Supports the SGI interfaces like the ones found on SGI Indy VINO
   or SGI O2 MACE.
 
+Motorola 8xx I2C algorithm
+CONFIG_I2C_ALGO8XX
+  This is the algorithm that allows you to use Motorola 8xx I2C adapters.
+
+  This driver is also available as a module.  If you want to compile
+  it as a module, say M here and read
+  <file:Documentation/modules.txt>.
+  The module will be called i2c-algo-8xx.o.
+
+Motorola 8xx I2C interface
+CONFIG_I2C_RPXLITE
+  This supports the Motorola 8xx I2C device.
+
+  This driver is also available as a module.  If you want to compile
+  it as a module, say M here and read
+  <file:Documentation/modules.txt>.
+  The module will be called i2c-rpx.o.
+
+IBM 405 I2C algorithm
+CONFIG_I2C_IBM_OCP_ALGO
+  This is the algorithm that allows you to use IBM 405 I2C adapters.
+
+  This driver is also available as a module.  If you want to compile
+  it as a module, say M here and read
+  <file:Documentation/modules.txt>.
+  The module will be called i2c-algo-ibm_ocp.o.
+
+IBM 405 I2C interface
+CONFIG_I2C_IBM_OCP_ADAP
+  This supports the IBM 405 I2C device.
+
+  This driver is also available as a module.  If you want to compile
+  it as a module, say M here and read
+  <file:Documentation/modules.txt>.
+  The module will be called i2c-adap-ibm_ocp.o.
+
+StrongARM SA-1110 interface
+CONFIG_I2C_FRODO
+  This supports the StrongARM SA-1110 Development Board.
+
+  This driver is also available as a module.  If you want to compile
+  it as a module, say M here and read
+  <file:Documentation/modules.txt>.
+  The module will be called i2c-frodo.o.
+
 I2C device interface
 CONFIG_I2C_CHARDEV
   Say Y here to use i2c-* device files, usually found in the /dev
@@ -23388,6 +23503,946 @@
 
   "Area6" will work for most boards. For ADX, select "Area5".
 
+Grsecurity
+CONFIG_GRKERNSEC
+  If you say Y here, you will be able to configure many features that
+  will enhance the security of your system.  It is highly recommended
+  that you say Y here and read through the help for each option so
+  you fully understand the features and can evaluate their usefulness
+  for your machine.
+
+Additional security levels
+CONFIG_GRKERNSEC_LOW
+
+  Low additional security
+  -----------------------------------------------------------------------
+  If you choose this option, several of the grsecurity options will
+  be enabled that will give you greater protection against a number
+  of attacks, while assuring that none of your software will have any 
+  conflicts with the additional security measures.  If you run a lot of 
+  unusual software, or you are having problems with the higher security 
+  levels, you should say Y here.  With this option, the following features
+  are enabled:
+  
+  linking restrictions
+  fifo restrictions
+  random pids
+  enforcing nproc on execve()
+  restricted dmesg
+  random ip ids
+  enforced chdir("/") on chroot
+
+  Medium additional security
+  -----------------------------------------------------------------------
+  If you say Y here, several features in addition to those included in the 
+  low additional security level will be enabled.  These features provide
+  even more security to your system, though in rare cases they may
+  be incompatible with very old or poorly written software.  If you 
+  enable this option, make sure that your auth service (identd) is 
+  running as gid 10 (usually group wheel). With this option the following 
+  features (in addition to those provided in the low additional security 
+  level) will be enabled:
+
+  random tcp source ports
+  failed fork logging
+  time change logging
+  signal logging
+  deny mounts in chroot
+  deny double chrooting
+  deny sysctl writes in chroot
+  deny mknod in chroot
+  deny access to abstract AF_UNIX sockets out of chroot
+  deny pivot_root in chroot
+  denied writes of /dev/kmem, /dev/mem, and /dev/port
+  /proc restrictions with special gid set to 10 (usually wheel)
+  address space layout randomization
+  removal of addresses from /proc/<pid>/[maps|stat]
+
+  High additional security
+  ----------------------------------------------------------------------
+  If you say Y here, many of the features of grsecurity will be enabled,
+  that will protect you against many kinds of attacks against
+  your system.  The heightened security comes at a cost of an 
+  increased chance of incompatibilities with rare software on your 
+  machine.  Since this security level enables PaX, you should view 
+  <http://pax.grsecurity.net> and read about the PaX project.  While 
+  you are there, download chpax and run it on binaries that cause 
+  problems with PaX.  Also remember that since the /proc restrictions are 
+  enabled, you must run your identd as group wheel (gid 10).  
+  This security level enables the following features in addition to those
+  listed in the low and medium security levels:
+
+  additional /proc restrictions
+  chmod restrictions in chroot
+  no signals, ptrace, or viewing processes outside of chroot
+  capability restrictions in chroot
+  deny fchdir out of chroot
+  priority restrictions in chroot
+  segmentation-based implementation of PaX
+  mprotect restrictions
+  kernel stack randomization
+  mount/unmount/remount logging
+  kernel symbol hiding
+
+Customized additional security
+CONFIG_GRKERNSEC_CUSTOM
+  If you say Y here, you will be able to configure every grsecurity 
+  option, which allows you to enable many more features that aren't 
+  covered in the basic security levels.  These additional features include 
+  TPE, socket restrictions, and the sysctl system for grsecurity.  It is 
+  advised that you read through the help for each option to determine its 
+  usefulness in your situation.
+
+Support soft mode
+CONFIG_GRKERNSEC_PAX_SOFTMODE
+  Enabling this option will allow you to run PaX in soft mode, that
+  is, PaX features will not be enforced by default, only on executables
+  marked explicitly.  You must also enable PT_PAX_FLAGS support as it
+  is the only way to mark executables for soft mode use.
+
+  Soft mode can be activated by using the "pax_softmode=1" kernel command
+  line option on boot.  Furthermore you can control various PaX features
+  at runtime via the entries in /proc/sys/kernel/pax.
+
+Use legacy ELF header marking
+CONFIG_GRKERNSEC_PAX_EI_PAX
+  Enabling this option will allow you to control PaX features on
+  a per executable basis via the 'chpax' utility available at
+  http://pax.grsecurity.net/.  The control flags will be read from
+  an otherwise reserved part of the ELF header.  This marking has
+  numerous drawbacks (no support for soft-mode, toolchain does not
+  know about the non-standard use of the ELF header) therefore it
+  has been deprecated in favour of PT_PAX_FLAGS support.
+
+  You should enable this option only if your toolchain does not yet
+  support the new control flag location (PT_PAX_FLAGS) or you still
+  have applications not marked by PT_PAX_FLAGS.
+
+  Note that if you enable PT_PAX_FLAGS marking support as well,
+  it will override the legacy EI_PAX marks.
+
+Use ELF program header marking
+CONFIG_GRKERNSEC_PAX_PT_PAX_FLAGS
+  Enabling this option will allow you to control PaX features on
+  a per executable basis via the 'paxctl' utility available at
+  http://pax.grsecurity.net/.  The control flags will be read from
+  a PaX specific ELF program header (PT_PAX_FLAGS).  This marking
+  has the benefits of supporting both soft mode and being fully
+  integrated into the toolchain (the binutils patch is available
+  from http://pax.grsecurity.net).
+
+  Note that if you enable the legacy EI_PAX marking support as well,
+  it will be overridden by the PT_PAX_FLAGS marking.
+
+MAC system integration
+CONFIG_GRKERNSEC_PAX_NO_ACL_FLAGS
+  Mandatory Access Control systems have the option of controlling
+  PaX flags on a per executable basis, choose the method supported
+  by your particular system.
+
+  - "none": if your MAC system does not interact with PaX,
+  - "direct": if your MAC system defines pax_set_flags() itself,
+  - "hook": if your MAC system uses the pax_set_flags_func callback.
+
+  NOTE: this option is for developers/integrators only.
+
+Enforce non-executable pages
+CONFIG_GRKERNSEC_PAX_NOEXEC
+  By design some architectures do not allow for protecting memory
+  pages against execution or even if they do, Linux does not make
+  use of this feature.  In practice this means that if a page is
+  readable (such as the stack or heap) it is also executable.
+
+  There is a well known exploit technique that makes use of this
+  fact and a common programming mistake where an attacker can
+  introduce code of his choice somewhere in the attacked program's
+  memory (typically the stack or the heap) and then execute it.
+
+  If the attacked program was running with different (typically
+  higher) privileges than that of the attacker, then he can elevate
+  his own privilege level (e.g. get a root shell, write to files for
+  which he does not have write access to, etc).
+
+  Enabling this option will let you choose from various features
+  that prevent the injection and execution of 'foreign' code in
+  a program.
+
+  This will also break programs that rely on the old behaviour and
+  expect that dynamically allocated memory via the malloc() family
+  of functions is executable (which it is not).  Notable examples
+  are the XFree86 4.x server, the java runtime and wine.
+
+Paging based non-executable pages
+CONFIG_GRKERNSEC_PAX_PAGEEXEC
+  This implementation is based on the paging feature of the CPU.
+  On i386 it has a variable performance impact on applications
+  depending on their memory usage pattern.  You should carefully
+  test your applications before using this feature in production.
+  On alpha, parisc, sparc and sparc64 there is no performance
+  impact.  On ppc there is a slight performance impact.
+
+Segmentation based non-executable pages
+CONFIG_GRKERNSEC_PAX_SEGMEXEC
+  This implementation is based on the segmentation feature of the
+  CPU and has little performance impact, however applications will
+  be limited to a 1.5 GB address space instead of the normal 3 GB.
+
+Emulate trampolines
+CONFIG_GRKERNSEC_PAX_EMUTRAMP
+  There are some programs and libraries that for one reason or
+  another attempt to execute special small code snippets from
+  non-executable memory pages.  Most notable examples are the
+  signal handler return code generated by the kernel itself and
+  the GCC trampolines.
+
+  If you enabled CONFIG_GRKERNSEC_PAX_PAGEEXEC or 
+  CONFIG_GRKERNSEC_PAX_SEGMEXEC then such programs will no longer
+  work under your kernel.
+
+  As a remedy you can say Y here and use the 'chpax' or 'paxctl'
+  utilities to enable trampoline emulation for the affected programs
+  yet still have the protection provided by the non-executable pages.
+
+  On parisc and ppc you MUST enable this option and EMUSIGRT as
+  well, otherwise your system will not even boot.
+
+  Alternatively you can say N here and use the 'chpax' or 'paxctl'
+  utilities to disable CONFIG_GRKERNSEC_PAX_PAGEEXEC and 
+  CONFIG_GRKERNSEC_PAX_SEGMEXEC for the affected files.
+
+  NOTE: enabling this feature *may* open up a loophole in the
+  protection provided by non-executable pages that an attacker
+  could abuse.  Therefore the best solution is to not have any
+  files on your system that would require this option.  This can
+  be achieved by not using libc5 (which relies on the kernel
+  signal handler return code) and not using or rewriting programs
+  that make use of the nested function implementation of GCC.
+  Skilled users can just fix GCC itself so that it implements
+  nested function calls in a way that does not interfere with PaX.
+
+Automatically emulate sigreturn trampolines
+CONFIG_GRKERNSEC_PAX_EMUSIGRT
+  Enabling this option will have the kernel automatically detect
+  and emulate signal return trampolines executing on the stack
+  that would otherwise lead to task termination.
+
+  This solution is intended as a temporary one for users with
+  legacy versions of libc (libc5, glibc 2.0, uClibc before 0.9.17,
+  Modula-3 runtime, etc) or executables linked to such, basically
+  everything that does not specify its own SA_RESTORER function in
+  normal executable memory like glibc 2.1+ does.
+
+  On parisc and ppc you MUST enable this option, otherwise your
+  system will not even boot.
+
+  NOTE: this feature cannot be disabled on a per executable basis
+  and since it *does* open up a loophole in the protection provided
+  by non-executable pages, the best solution is to not have any
+  files on your system that would require this option.
+
+Restrict mprotect()
+CONFIG_GRKERNSEC_PAX_MPROTECT
+  Enabling this option will prevent programs from
+   - changing the executable status of memory pages that were
+     not originally created as executable,
+   - making read-only executable pages writable again,
+   - creating executable pages from anonymous memory.
+
+  You should say Y here to complete the protection provided by
+  the enforcement of non-executable pages.
+
+  NOTE: you can use the 'chpax' utility to control this
+  feature on a per file basis. chpax is available at
+  <http://pax.grsecurity.net>
+
+Disallow ELF text relocations
+CONFIG_GRKERNSEC_PAX_NOELFRELOCS
+  Non-executable pages and mprotect() restrictions are effective
+  in preventing the introduction of new executable code into an
+  attacked task's address space.  There remain only two venues
+  for this kind of attack: if the attacker can execute already
+  existing code in the attacked task then he can either have it
+  create and mmap() a file containing his code or have it mmap()
+  an already existing ELF library that does not have position
+  independent code in it and use mprotect() on it to make it
+  writable and copy his code there.  While protecting against
+  the former approach is beyond PaX, the latter can be prevented
+  by having only PIC ELF libraries on one's system (which do not
+  need to relocate their code).  If you are sure this is your case,
+  then enable this option otherwise be careful as you may not even
+  be able to boot or log on your system (for example, some PAM
+  modules are erroneously compiled as non-PIC by default).
+
+  NOTE: if you are using dynamic ELF executables (as suggested
+  when using ASLR) then you must have made sure that you linked
+  your files using the PIC version of crt1 (the et_dyn.zip package
+  referenced there has already been updated to support this).
+
+Enforce non-executable kernel pages
+CONFIG_GRKERNSEC_PAX_KERNEXEC
+  This is the kernel land equivalent of PAGEEXEC and MPROTECT,
+  that is, enabling this option will make it harder to inject
+  and execute 'foreign' code in kernel memory itself.
+
+Address Space Layout Randomization
+CONFIG_GRKERNSEC_PAX_ASLR
+  Many if not most exploit techniques rely on the knowledge of
+  certain addresses in the attacked program.  The following options
+  will allow the kernel to apply a certain amount of randomization
+  to specific parts of the program thereby forcing an attacker to
+  guess them in most cases.  Any failed guess will most likely crash
+  the attacked program which allows the kernel to detect such attempts
+  and react on them.  PaX itself provides no reaction mechanisms,
+  instead it is strongly encouraged that you make use of grsecurity's
+  built-in crash detection features or develop one yourself.
+
+  By saying Y here you can choose to randomize the following areas:
+   - top of the task's kernel stack
+   - top of the task's userland stack
+   - base address for mmap() requests that do not specify one
+     (this includes all libraries)
+   - base address of the main executable
+
+  It is strongly recommended to say Y here as address space layout
+  randomization has negligible impact on performance yet it provides
+  a very effective protection.
+
+  NOTE: you can use the 'chpax' or 'paxctl' utilities to control most
+  of these features on a per file basis.
+
+Randomize kernel stack base
+CONFIG_GRKERNSEC_PAX_RANDKSTACK
+  By saying Y here the kernel will randomize every task's kernel
+  stack on every system call.  This will not only force an attacker
+  to guess it but also prevent him from making use of possible
+  leaked information about it.
+
+  Since the kernel stack is a rather scarce resource, randomization
+  may cause unexpected stack overflows, therefore you should very
+  carefully test your system.  Note that once enabled in the kernel
+  configuration, this feature cannot be disabled on a per file basis.
+
+Randomize user stack base
+CONFIG_GRKERNSEC_PAX_RANDUSTACK
+  By saying Y here the kernel will randomize every task's userland
+  stack.  The randomization is done in two steps where the second
+  one may apply a big amount of shift to the top of the stack and
+  cause problems for programs that want to use lots of memory (more
+  than 2.5 GB if SEGMEXEC is not active, or 1.25 GB when it is).
+  For this reason the second step can be controlled by 'chpax' or
+  'paxctl' on a per file basis.
+
+Randomize ET_EXEC base
+CONFIG_GRKERNSEC_PAX_RANDEXEC     
+  By saying Y here the kernel will randomize the base address of normal
+  ET_EXEC ELF executables as well.  This is accomplished by mapping the
+  executable in memory in a special way which also allows for detecting
+  attackers who attempt to execute its code for their purposes.  Since
+  this special mapping causes performance degradation and the attack
+  detection may create false alarms as well, you should carefully test
+  your executables when this feature is enabled.
+
+  This solution is intended only as a temporary one until you relink
+  your programs as a dynamic ELF file.
+
+  NOTE: you can use the 'chpax' or 'paxctl' utilities to control
+  this feature on a per file basis.
+
+Allow ELF ET_EXEC text relocations
+CONFIG_GRKERNSEC_PAX_ETEXECRELOCS
+  On some architectures like the alpha there are incorrectly
+  created applications that require text relocations and would
+  not work without enabling this option.  If you are an alpha
+  user, you should enable this option and disable it once you
+  have made sure that none of your applications need it.
+
+Automatically emulate ELF PLT
+CONFIG_GRKERNSEC_PAX_EMUPLT
+  Enabling this option will have the kernel automatically detect
+  and emulate the Procedure Linkage Table entries in ELF files.
+  On some architectures such entries are in writable memory, and
+  become non-executable leading to task termination.  Therefore
+  it is mandatory that you enable this option on alpha, parisc, ppc,
+  sparc and sparc64, otherwise your system would not even boot.
+
+  NOTE: this feature *does* open up a loophole in the protection
+  provided by the non-executable pages, therefore the proper
+  solution is to modify the toolchain to produce a PLT that does
+  not need to be writable.
+
+Randomize mmap() base
+CONFIG_GRKERNSEC_PAX_RANDMMAP
+  By saying Y here the kernel will use a randomized base address for
+  mmap() requests that do not specify one themselves.  As a result
+  all dynamically loaded libraries will appear at random addresses
+  and therefore be harder to exploit by a technique where an attacker
+  attempts to execute library code for his purposes (e.g. spawn a
+  shell from an exploited program that is running at an elevated
+  privilege level).
+
+  Furthermore, if a program is relinked as a dynamic ELF file, its
+  base address will be randomized as well, completing the full
+  randomization of the address space layout.  Attacking such programs
+  becomes a guess game.  You can find an example of doing this at
+  <http://pax.grsecurity.net/et_dyn.zip> and practical samples at
+  <http://www.grsecurity.net/grsec-gcc-specs.tar.gz> .
+
+  NOTE: you can use the 'chpax' or 'paxctl' utilities to control this
+  feature on a per file basis.
+
+Deny writing to /dev/kmem and /dev/mem
+CONFIG_GRKERNSEC_KMEM
+  If you say Y here, /dev/kmem and /dev/mem won't be allowed to
+  be written to via mmap or otherwise to modify the running kernel.
+  If you have module support disabled, enabling this, along with /dev/port
+  (below) will close up four ways that are currently used to insert 
+  malicious code into the running kernel. Even with all these features 
+  enabled, we still highly recommend that you use the ACL system, as it
+  is still possible for an attacker to modify the running kernel 
+  through privileged I/O granted by ioperm/iopl. 
+  If you are not using XFree86, you may be able to stop this additional
+  case by enabling the 'Disable privileged I/O' option. Though nothing
+  legitimately writes to /dev/kmem, XFree86 does need to write to /dev/mem,
+  but only to video memory, which is the only writing we allow in this
+  case.  If /dev/kmem or /dev/mem are mmaped without PROT_WRITE, they will
+  not be allowed to mprotect it with PROT_WRITE later.
+  Enabling this feature could make certain apps like VMWare stop working,
+  as they need to write to other locations in /dev/mem.
+  It is highly recommended that you say Y here if you meet all the 
+  conditions above.
+
+Deny access to /dev/port
+CONFIG_GRKERNSEC_PORT
+  If you say Y here, /dev/port will not be able to be opened. This option
+  is normally used in conjunction with /dev/kmem (above). It is seperated
+  here because it breaks certain utilities (for example, kbdrate).
+  Is is highly recommended that you say Y here.
+
+Disable privileged I/O
+CONFIG_GRKERNSEC_IO
+  If you say Y here, all ioperm and iopl calls will return an error.
+  Ioperm and iopl can be used to modify the running kernel.
+  Unfortunately, some programs need this access to operate properly,
+  the most notable of which are XFree86 and hwclock.  hwclock can be
+  remedied by having RTC support in the kernel, so CONFIG_RTC is
+  enabled if this option is enabled, to ensure that hwclock operates
+  correctly.  XFree86 still will not operate correctly with this option
+  enabled, so DO NOT CHOOSE Y IF YOU USE XFree86.  If you use XFree86
+  and you still want to protect your kernel against modification,
+  use the ACL system.
+
+Hide kernel symbols
+CONFIG_GRKERNSEC_HIDESYM
+  If you say Y here, getting information on loaded modules, and 
+  displaying all kernel symbols through a syscall will be restricted
+  to users with CAP_SYS_MODULE.  This option is only effective 
+  provided the following conditions are met:
+  1) The kernel using grsecurity is not precompiled by some distribution
+  2) You are using the ACL system and hiding other files such as your
+     kernel image and System.map
+  3) You have the additional /proc restrictions enabled, which removes
+     /proc/kcore
+  If the above conditions are met, this option will aid to provide a
+  useful protection against local and remote kernel exploitation of
+  overflows and arbitrary read/write vulnerabilities.
+
+Deter exploit bruteforcing
+CONFIG_GRKERNSEC_BRUTE
+  If you say Y here, attempts to bruteforce exploits against forking
+  daemons such as apache or sshd will be deterred.  When a child of a 
+  forking daemon is killed by PaX or crashes due to an illegal 
+  instruction, the parent process will be delayed 30 seconds upon every
+  subsequent fork until the administrator is able to assess the 
+  situation and restart the daemon.  It is recommended that you also 
+  enable signal logging in the auditing section so that logs are 
+  generated when a process performs an illegal instruction.
+
+/proc/<pid>/ipaddr support
+CONFIG_GRKERNSEC_PROC_IPADDR
+  If you say Y here, a new entry will be added to each /proc/<pid>
+  directory that contains the IP address of the person using the task.
+  The IP is carried across local TCP and AF_UNIX stream sockets.
+  This information can be useful for IDS/IPSes to perform remote response
+  to a local attack.  The entry is readable by only the owner of the 
+  process (and root if he has CAP_DAC_OVERRIDE, which can be removed via
+  the RBAC system), and thus does not create privacy concerns.
+
+Proc Restrictions
+CONFIG_GRKERNSEC_PROC
+  If you say Y here, the permissions of the /proc filesystem
+  will be altered to enhance system security and privacy.  Depending
+  upon the options you choose, you can either restrict users to see
+  only the processes they themselves run, or choose a group that can
+  view all processes and files normally restricted to root if you choose
+  the "restrict to user only" option.  NOTE: If you're running identd as 
+  a non-root user, you will have to run it as the group you specify here.
+
+Restrict /proc to user only
+CONFIG_GRKERNSEC_PROC_USER
+  If you say Y here, non-root users will only be able to view their own 
+  processes, and restricts them from viewing network-related information,  
+  and viewing kernel symbol and module information.
+
+Restrict /proc to user and group
+CONFIG_GRKERNSEC_PROC_USERGROUP
+  If you say Y here, you will be able to select a group that will be
+  able to view all processes, network-related information, and
+  kernel and symbol information.  This option is useful if you want
+  to run identd as a non-root user.
+
+Remove addresses from /proc/pid/[maps|stat]
+CONFIG_GRKERNSEC_PROC_MEMMAP
+  If you say Y here, the /proc/<pid>/maps and /proc/<pid>/stat files will
+  give no information about the addresses of its mappings if
+  PaX features that rely on random addresses are enabled on the task.
+  If you use PaX it is greatly recommended that you say Y here as it 
+  closes up a hole that makes the full ASLR useless for suid 
+  binaries.
+
+Additional proc restrictions
+CONFIG_GRKERNSEC_PROC_ADD
+  If you say Y here, additional restrictions will be placed on
+  /proc that keep normal users from viewing cpu and device information.
+
+Dmesg(8) Restriction
+CONFIG_GRKERNSEC_DMESG
+  If you say Y here, non-root users will not be able to use dmesg(8)
+  to view up to the last 4kb of messages in the kernel's log buffer.
+  If the sysctl option is enabled, a sysctl option with name "dmesg" is 
+  created.
+
+Linking restrictions
+CONFIG_GRKERNSEC_LINK
+  If you say Y here, /tmp race exploits will be prevented, since users
+  will no longer be able to follow symlinks owned by other users in 
+  world-writable +t directories (i.e. /tmp), unless the owner of the 
+  symlink is the owner of the directory. users will also not be
+  able to hardlink to files they do not own.  If the sysctl option is
+  enabled, a sysctl option with name "linking_restrictions" is created.
+
+FIFO restrictions
+CONFIG_GRKERNSEC_FIFO
+  If you say Y here, users will not be able to write to FIFOs they don't
+  own in world-writable +t directories (i.e. /tmp), unless the owner of
+  the FIFO is the same owner of the directory it's held in.  If the sysctl
+  option is enabled, a sysctl option with name "fifo_restrictions" is 
+  created.
+
+Enforce RLIMIT_NPROC on execs
+CONFIG_GRKERNSEC_EXECVE
+  If you say Y here, users with a resource limit on processes will
+  have the value checked during execve() calls.  The current system
+  only checks the system limit during fork() calls.  If the sysctl option
+  is enabled, a sysctl option with name "execve_limiting" is created.
+
+Single group for auditing
+CONFIG_GRKERNSEC_AUDIT_GROUP
+  If you say Y here, the exec, chdir, (un)mount, and ipc logging features
+  will only operate on a group you specify.  This option is recommended
+  if you only want to watch certain users instead of having a large
+  amount of logs from the entire system.  If the sysctl option is enabled,
+  a sysctl option with name "audit_group" is created.
+
+GID for auditing
+CONFIG_GRKERNSEC_AUDIT_GID
+  Here you can choose the GID that will be the target of kernel auditing.
+  Remember to add the users you want to log to the GID specified here.
+  If the sysctl option is enabled, whatever you choose here won't matter. 
+  You'll have to specify the GID in your bootup script by echoing the GID 
+  to the proper /proc entry.  View the help on the sysctl option for more 
+  information.  If the sysctl option is enabled, a sysctl option with name 
+  "audit_gid" is created.
+
+Chdir logging
+CONFIG_GRKERNSEC_AUDIT_CHDIR
+  If you say Y here, all chdir() calls will be logged.  If the sysctl 
+  option is enabled, a sysctl option with name "audit_chdir" is created.
+
+(Un)Mount logging
+CONFIG_GRKERNSEC_AUDIT_MOUNT
+  If you say Y here, all mounts and unmounts will be logged.  If the 
+  sysctl option is enabled, a sysctl option with name "audit_mount" is 
+  created.
+
+IPC logging
+CONFIG_GRKERNSEC_AUDIT_IPC
+  If you say Y here, creation and removal of message queues, semaphores,
+  and shared memory will be logged.  If the sysctl option is enabled, a
+  sysctl option with name "audit_ipc" is created.
+
+Exec logging
+CONFIG_GRKERNSEC_EXECLOG
+  If you say Y here, all execve() calls will be logged (since the
+  other exec*() calls are frontends to execve(), all execution
+  will be logged).  Useful for shell-servers that like to keep track
+  of their users.  If the sysctl option is enabled, a sysctl option with
+  name "exec_logging" is created.
+  WARNING: This option when enabled will produce a LOT of logs, especially
+  on an active system.
+
+Resource logging
+CONFIG_GRKERNSEC_RESLOG
+  If you say Y here, all attempts to overstep resource limits will
+  be logged with the resource name, the requested size, and the current
+  limit.  It is highly recommended that you say Y here.
+
+Signal logging
+CONFIG_GRKERNSEC_SIGNAL
+  If you say Y here, certain important signals will be logged, such as
+  SIGSEGV, which will as a result inform you of when a error in a program
+  occurred, which in some cases could mean a possible exploit attempt.
+  If the sysctl option is enabled, a sysctl option with name 
+  "signal_logging" is created.
+
+Fork failure logging
+CONFIG_GRKERNSEC_FORKFAIL
+  If you say Y here, all failed fork() attempts will be logged.
+  This could suggest a fork bomb, or someone attempting to overstep
+  their process limit.  If the sysctl option is enabled, a sysctl option
+  with name "forkfail_logging" is created.
+
+Time change logging
+CONFIG_GRKERNSEC_TIME
+  If you say Y here, any changes of the system clock will be logged.
+  If the sysctl option is enabled, a sysctl option with name 
+  "timechange_logging" is created.
+
+ELF text relocations logging
+CONFIG_GRKERNSEC_AUDIT_TEXTREL
+  If you say Y here, text relocations will be logged with the filename 
+  of the offending library or binary.  The purpose of the feature is 
+  to help Linux distribution developers get rid of libraries and 
+  binaries that need text relocations which hinder the future progress 
+  of PaX.  Only Linux distribution developers should say Y here, and 
+  never on a production machine, as this option creates an information 
+  leak that could aid an attacker in defeating the randomization of
+  a single memory region.  If the sysctl option is enabled, a sysctl
+  option with name "audit_textrel" is created.
+
+Chroot jail restrictions
+CONFIG_GRKERNSEC_CHROOT
+  If you say Y here, you will be able to choose several options that will
+  make breaking out of a chrooted jail much more difficult.  If you
+  encounter no software incompatibilities with the following options, it
+  is recommended that you enable each one.
+
+Deny access to abstract AF_UNIX sockets out of chroot
+CONFIG_GRKERNSEC_CHROOT_UNIX
+  If you say Y here, processes inside a chroot will not be able to
+  connect to abstract (meaning not belonging to a filesystem) Unix
+  domain sockets that were bound outside of a chroot.  It is recommended
+  that you say Y here.  If the sysctl option is enabled, a sysctl option
+  with name "chroot_deny_unix" is created.
+
+Deny shmat() out of chroot
+CONFIG_GRKERNSEC_CHROOT_SHMAT
+  If you say Y here, processes inside a chroot will not be able to attach
+  to shared memory segments that were created outside of the chroot jail.
+  It is recommended that you say Y here.  If the sysctl option is enabled,
+  a sysctl option with name "chroot_deny_shmat" is created.
+
+Protect outside processes
+CONFIG_GRKERNSEC_CHROOT_FINDTASK
+  If you say Y here, processes inside a chroot will not be able to
+  kill, send signals with fcntl, ptrace, capget, setpgid, getpgid, 
+  getsid, or view any process outside of the chroot.  If the sysctl 
+  option is enabled, a sysctl option with name "chroot_findtask" is 
+  created.
+
+Deny mounts in chroot
+CONFIG_GRKERNSEC_CHROOT_MOUNT
+  If you say Y here, processes inside a chroot will not be able to
+  mount or remount filesystems.  If the sysctl option is enabled, a 
+  sysctl option with name "chroot_deny_mount" is created.
+
+Deny pivot_root in chroot
+CONFIG_GRKERNSEC_CHROOT_PIVOT
+  If you say Y here, processes inside a chroot will not be able to use
+  a function called pivot_root() that was introduced in Linux 2.3.41.  It 
+  works similar to chroot in that it changes the root filesystem.  This 
+  function could be misused in a chrooted process to attempt to break out 
+  of the chroot, and therefore should not be allowed.  If the sysctl 
+  option is enabled, a sysctl option with name "chroot_deny_pivot" is 
+  created.
+
+Deny double-chroots
+CONFIG_GRKERNSEC_CHROOT_DOUBLE
+  If you say Y here, processes inside a chroot will not be able to chroot
+  again outside of the chroot.  This is a widely used method of breaking 
+  out of a chroot jail and should not be allowed.  If the sysctl option 
+  is enabled, a sysctl option with name "chroot_deny_chroot" is created.
+
+Deny fchdir outside of chroot
+CONFIG_GRKERNSEC_CHROOT_FCHDIR
+  If you say Y here, a well-known method of breaking chroots by fchdir'ing
+  to a file descriptor of the chrooting process that points to a directory
+  outside the filesystem will be stopped.  If the sysctl option
+  is enabled, a sysctl option with name "chroot_deny_fchdir" is created.
+
+Enforce chdir("/") on all chroots
+CONFIG_GRKERNSEC_CHROOT_CHDIR
+  If you say Y here, the current working directory of all newly-chrooted
+  applications will be set to the the root directory of the chroot.
+  The man page on chroot(2) states:
+  Note that this call does not change  the  current  working
+  directory,  so  that `.' can be outside the tree rooted at
+  `/'.  In particular, the  super-user  can  escape  from  a
+  `chroot jail' by doing `mkdir foo; chroot foo; cd ..'.  
+
+  It is recommended that you say Y here, since it's not known to break
+  any software.  If the sysctl option is enabled, a sysctl option with
+  name "chroot_enforce_chdir" is created.
+
+Deny (f)chmod +s in chroot
+CONFIG_GRKERNSEC_CHROOT_CHMOD
+  If you say Y here, processes inside a chroot will not be able to chmod
+  or fchmod files to make them have suid or sgid bits.  This protects 
+  against another published method of breaking a chroot.  If the sysctl 
+  option is enabled, a sysctl option with name "chroot_deny_chmod" is
+  created.
+
+Deny mknod in chroot
+CONFIG_GRKERNSEC_CHROOT_MKNOD
+  If you say Y here, processes inside a chroot will not be allowed to
+  mknod.  The problem with using mknod inside a chroot is that it
+  would allow an attacker to create a device entry that is the same
+  as one on the physical root of your system, which could range from
+  anything from the console device to a device for your harddrive (which
+  they could then use to wipe the drive or steal data).  It is recommended
+  that you say Y here, unless you run into software incompatibilities.
+  If the sysctl option is enabled, a sysctl option with name
+  "chroot_deny_mknod" is created.
+
+Restrict priority changes in chroot
+CONFIG_GRKERNSEC_CHROOT_NICE
+  If you say Y here, processes inside a chroot will not be able to raise
+  the priority of processes in the chroot, or alter the priority of 
+  processes outside the chroot.  This provides more security than simply
+  removing CAP_SYS_NICE from the process' capability set.  If the
+  sysctl option is enabled, a sysctl option with name "chroot_restrict_nice"
+  is created.
+
+Log all execs within chroot
+CONFIG_GRKERNSEC_CHROOT_EXECLOG
+  If you say Y here, all executions inside a chroot jail will be logged 
+  to syslog.  This can cause a large amount of logs if certain
+  applications (eg. djb's daemontools) are installed on the system, and
+  is therefore left as an option.  If the sysctl option is enabled, a 
+  sysctl option with name "chroot_execlog" is created.
+
+Deny sysctl writes in chroot
+CONFIG_GRKERNSEC_CHROOT_SYSCTL
+  If you say Y here, an attacker in a chroot will not be able to
+  write to sysctl entries, either by sysctl(2) or through a /proc
+  interface.  It is strongly recommended that you say Y here. If the
+  sysctl option is enabled, a sysctl option with name 
+  "chroot_deny_sysctl" is created.
+
+Chroot jail capability restrictions
+CONFIG_GRKERNSEC_CHROOT_CAPS
+  If you say Y here, the capabilities on all root processes within a
+  chroot jail will be lowered to stop module insertion, raw i/o,
+  system and net admin tasks, rebooting the system, modifying immutable 
+  files, modifying IPC owned by another, and changing the system time.
+  This is left an option because it can break some apps.  Disable this
+  if your chrooted apps are having problems performing those kinds of
+  tasks.  If the sysctl option is enabled, a sysctl option with
+  name "chroot_caps" is created.
+
+Trusted path execution
+CONFIG_GRKERNSEC_TPE
+  If you say Y here, you will be able to choose a gid to add to the
+  supplementary groups of users you want to mark as "untrusted."
+  These users will not be able to execute any files that are not in
+  root-owned directories writable only by root.  If the sysctl option
+  is enabled, a sysctl option with name "tpe" is created.
+
+Group for trusted path execution
+CONFIG_GRKERNSEC_TPE_GID
+  Here you can choose the GID to enable trusted path protection for.
+  Remember to add the users you want protection enabled for to the GID 
+  specified here.  If the sysctl option is enabled, whatever you choose
+  here won't matter. You'll have to specify the GID in your bootup 
+  script by echoing the GID to the proper /proc entry.  View the help
+  on the sysctl option for more information.  If the sysctl option is
+  enabled, a sysctl option with name "tpe_gid" is created.
+
+Partially restrict non-root users
+CONFIG_GRKERNSEC_TPE_ALL
+  If you say Y here, All non-root users other than the ones in the 
+  group specified in the main TPE option will only be allowed to
+  execute files in directories they own that are not group or
+  world-writable, or in directories owned by root and writable only by
+  root.  If the sysctl option is enabled, a sysctl option with name 
+  "tpe_restrict_all" is created.
+
+Randomized PIDs
+CONFIG_GRKERNSEC_RANDPID
+  If you say Y here, all PIDs created on the system will be
+  pseudo-randomly generated.  This is extremely effective along
+  with the /proc restrictions to disallow an attacker from guessing
+  pids of daemons, etc.  PIDs are also used in some cases as part
+  of a naming system for temporary files, so this option would keep
+  those filenames from being predicted as well.  We also use code
+  to make sure that PID numbers aren't reused too soon.  If the sysctl
+  option is enabled, a sysctl option with name "rand_pids" is created.
+
+Larger entropy pools
+CONFIG_GRKERNSEC_RANDNET
+  If you say Y here, the entropy pools used for many features of Linux
+  and grsecurity will be doubled in size.  Since several grsecurity 
+  features use additional randomness, it is recommended that you say Y 
+  here.  Saying Y here has a similar effect as modifying
+  /proc/sys/kernel/random/poolsize.
+
+Truly random TCP ISN selection
+CONFIG_GRKERNSEC_RANDISN
+  If you say Y here, Linux's default selection of TCP Initial Sequence
+  Numbers (ISNs) will be replaced with that of OpenBSD.  Linux uses
+  an MD4 hash based on the connection plus a time value to create the
+  ISN, while OpenBSD's selection is random.  If the sysctl option is 
+  enabled, a sysctl option with name "rand_isns" is created.
+
+Randomized IP IDs
+CONFIG_GRKERNSEC_RANDID
+  If you say Y here, all the id field on all outgoing packets
+  will be randomized.  This hinders os fingerprinters and
+  keeps your machine from being used as a bounce for an untraceable
+  portscan.  Ids are used for fragmented packets, fragments belonging
+  to the same packet have the same id.  By default linux only
+  increments the id value on each packet sent to an individual host.
+  We use a port of the OpenBSD random ip id code to achieve the
+  randomness, while keeping the possibility of id duplicates to
+  near none.  If the sysctl option is enabled, a sysctl option with name
+  "rand_ip_ids" is created.
+
+Randomized TCP source ports
+CONFIG_GRKERNSEC_RANDSRC
+  If you say Y here, situations where a source port is generated on the
+  fly for the TCP protocol (ie. with connect() ) will be altered so that
+  the source port is generated at random, instead of a simple incrementing
+  algorithm.  If the sysctl option is enabled, a sysctl option with name
+  "rand_tcp_src_ports" is created.
+
+Randomized RPC XIDs
+CONFIG_GRKERNSEC_RANDRPC
+  If you say Y here, the method of determining XIDs for RPC requests will
+  be randomized, instead of using linux's default behavior of simply
+  incrementing the XID.  If you want your RPC connections to be more
+  secure, say Y here.  If the sysctl option is enabled, a sysctl option 
+  with name "rand_rpc" is created.
+
+Socket restrictions
+CONFIG_GRKERNSEC_SOCKET
+  If you say Y here, you will be able to choose from several options.
+  If you assign a GID on your system and add it to the supplementary
+  groups of users you want to restrict socket access to, this patch
+  will perform up to three things, based on the option(s) you choose.
+
+Deny all socket access
+CONFIG_GRKERNSEC_SOCKET_ALL
+  If you say Y here, you will be able to choose a GID of whose users will
+  be unable to connect to other hosts from your machine or run server
+  applications from your machine.  If the sysctl option is enabled, a
+  sysctl option with name "socket_all" is created.
+
+Group for disabled socket access
+CONFIG_GRKERNSEC_SOCKET_ALL_GID
+  Here you can choose the GID to disable socket access for. Remember to 
+  add the users you want socket access disabled for to the GID 
+  specified here.  If the sysctl option is enabled, whatever you choose
+  here won't matter. You'll have to specify the GID in your bootup 
+  script by echoing the GID to the proper /proc entry.  View the help
+  on the sysctl option for more information.  If the sysctl option is
+  enabled, a sysctl option with name "socket_all_gid" is created.
+
+Deny all client socket access
+CONFIG_GRKERNSEC_SOCKET_CLIENT
+  If you say Y here, you will be able to choose a GID of whose users will
+  be unable to connect to other hosts from your machine, but will be
+  able to run servers.  If this option is enabled, all users in the group
+  you specify will have to use passive mode when initiating ftp transfers
+  from the shell on your machine.  If the sysctl option is enabled, a
+  sysctl option with name "socket_client" is created.
+
+Group for disabled client socket access
+CONFIG_GRKERNSEC_SOCKET_CLIENT_GID
+  Here you can choose the GID to disable client socket access for. 
+  Remember to add the users you want client socket access disabled for to 
+  the GID specified here.  If the sysctl option is enabled, whatever you 
+  choose here won't matter. You'll have to specify the GID in your bootup 
+  script by echoing the GID to the proper /proc entry.  View the help
+  on the sysctl option for more information.  If the sysctl option is
+  enabled, a sysctl option with name "socket_client_gid" is created.
+
+Deny all server socket access
+CONFIG_GRKERNSEC_SOCKET_SERVER
+  If you say Y here, you will be able to choose a GID of whose users will
+  be unable to run server applications from your machine.  If the sysctl 
+  option is enabled, a sysctl option with name "socket_server" is created.
+
+Group for disabled server socket access
+CONFIG_GRKERNSEC_SOCKET_SERVER_GID
+  Here you can choose the GID to disable server socket access for. 
+  Remember to add the users you want server socket access disabled for to 
+  the GID specified here.  If the sysctl option is enabled, whatever you 
+  choose here won't matter. You'll have to specify the GID in your bootup 
+  script by echoing the GID to the proper /proc entry.  View the help
+  on the sysctl option for more information.  If the sysctl option is
+  enabled, a sysctl option with name "socket_server_gid" is created.
+
+Sysctl support
+CONFIG_GRKERNSEC_SYSCTL
+  If you say Y here, you will be able to change the options that
+  grsecurity runs with at bootup, without having to recompile your
+  kernel.  You can echo values to files in /proc/sys/kernel/grsecurity
+  to enable (1) or disable (0) various features.  All the sysctl entries
+  are mutable until the "grsec_lock" entry is set to a non-zero value.
+  All features are disabled by default. Please note that this option could 
+  reduce the effectiveness of the added security of this patch if an ACL 
+  system is not put in place.  Your init scripts should be read-only, and 
+  root should not have access to adding modules or performing raw i/o 
+  operations.  All options should be set at startup, and the grsec_lock 
+  entry should be set to a non-zero value after all the options are set.  
+  *THIS IS EXTREMELY IMPORTANT*
+
+Number of burst messages
+CONFIG_GRKERNSEC_FLOODBURST
+  This option allows you to choose the maximum number of messages allowed
+  within the flood time interval you chose in a separate option.  The 
+  default should be suitable for most people, however if you find that 
+  many of your logs are being interpreted as flooding, you may want to 
+  raise this value.
+
+Seconds in between log messages
+CONFIG_GRKERNSEC_FLOODTIME
+  This option allows you to enforce the number of seconds between
+  grsecurity log messages.  The default should be suitable for most 
+  people, however, if you choose to change it, choose a value small enough
+  to allow informative logs to be produced, but large enough to
+  prevent flooding.
+
+Hide kernel processes
+CONFIG_GRKERNSEC_ACL_HIDEKERN
+  If you say Y here, when the ACL system is enabled via gradm -E,
+  an additional ACL will be passed to the kernel that hides all kernel
+  processes.  These processes will only be viewable by the authenticated
+  admin, or processes that have viewing access set.
+
+Maximum tries before password lockout
+CONFIG_GRKERNSEC_ACL_MAXTRIES
+  This option enforces the maximum number of times a user can attempt
+  to authorize themselves with the grsecurity ACL system before being
+  denied the ability to attempt authorization again for a specified time.  
+  The lower the number, the harder it will be to brute-force a password.
+
+Time to wait after max password tries, in seconds
+CONFIG_GRKERNSEC_ACL_TIMEOUT
+  This option specifies the time the user must wait after attempting to 
+  authorize to the ACL system with the maximum number of invalid 
+  passwords.  The higher the number, the harder it will be to brute-force 
+  a password.
+
 Disable data cache
 CONFIG_DCACHE_DISABLE
   This option allows you to run the kernel with data cache disabled.
@@ -29304,4 +30359,505 @@
 # fill-prefix:"  "
 # adaptive-fill:nil
 # fill-column:70
+I2C mainboard interfaces
+CONFIG_I2C_MAINBOARD
+  Many modern mainboards have some kind of I2C interface integrated. This
+  is often in the form of a SMBus, or System Management Bus, which is
+  basically the same as I2C but which uses only a subset of the I2C
+  protocol.
+
+  You will also want the latest user-space utilties: you can find them
+  in the lm_sensors package, which you can download at 
+  http://www.lm-sensors.nu
+
+Acer Labs ALI 1535
+CONFIG_I2C_ALI1535
+  If you say yes to this option, support will be included for the Acer
+  Labs ALI 1535 mainboard I2C interface. This can also be 
+  built as a module.
+
+Acer Labs ALI 1533 and 1543C
+CONFIG_I2C_ALI15X3
+  If you say yes to this option, support will be included for the Acer
+  Labs ALI 1533 and 1543C mainboard I2C interfaces. This can also be 
+  built as a module which can be inserted and removed while the kernel
+  is running.
+
+AMD 756/766/768/8111
+CONFIG_I2C_AMD756
+  If you say yes to this option, support will be included for the AMD
+  756/766/768/8111 mainboard I2C interfaces. This can also be 
+  built as a module which can be inserted and removed while the kernel
+  is running.
+
+AMD 8111 SMBus 2.0
+CONFIG_I2C_AMD8111
+  If you say yes to this option, support will be included for the AMD
+  8111 mainboard SMBus 2.0 interface. This can also be 
+  built as a module which can be inserted and removed while the kernel
+  is running.
+
+Apple Hydra Mac I/O
+CONFIG_I2C_HYDRA
+  If you say yes to this option, support will be included for the 
+  Hydra mainboard I2C interface. This can also be built as a module 
+  which can be inserted and removed while the kernel is running.
+
+Intel I801
+CONFIG_I2C_I801
+  If you say yes to this option, support will be included for the 
+  Intel I801 mainboard I2C interfaces. "I810" mainboard sensor chips are
+  generally located on the I801's I2C bus. This can also be
+  built as a module which can be inserted and removed while the kernel
+  is running.
+
+Intel I810/I815 based Mainboard
+CONFIG_I2C_I810
+  If you say yes to this option, support will be included for the 
+  Intel I810/I815 mainboard I2C interfaces. The I2C busses these chips
+  are generally used only for video devices. For "810" mainboard sensor
+  chips, use the I801 I2C driver instead. This can also be
+  built as a module which can be inserted and removed while the kernel
+  is running.
+
+Intel 82371AB PIIX4(E) / ServerWorks OSB4 and CSB5
+CONFIG_I2C_PIIX4
+  If you say yes to this option, support will be included for the 
+  Intel PIIX4, PIIX4E, and 443MX, Serverworks OSB4/CSB5,
+  and SMSC Victory66 mainboard
+  I2C interfaces. This can also be
+  built as a module which can be inserted and removed while the kernel
+  is running.
+
+Nvidia Nforce2 based Mainboard
+CONFIG_I2C_NFORCE2
+  If you say yes to this option, support will be included for the 
+  Nvidia Nforce2 family of mainboard I2C interfaces. This can also be
+  built as a module which can be inserted and removed while the kernel
+  is running.
+
+Silicon Integrated Systems Corp. SiS5595 based Mainboard
+CONFIG_I2C_SIS5595
+  If you say yes to this option, support will be included for the 
+  SiS5595 mainboard I2C interfaces. For integrated sensors on the
+  Sis5595, use CONFIG_SENSORS_SIS5595. This can also be
+  built as a module which can be inserted and removed while the kernel
+  is running.
+
+Silicon Integrated Systems Corp. SiS630/730 based Mainboard
+CONFIG_I2C_SIS630
+  If you say yes to this option, support will be included for the SiS 630
+  and 730 mainboard I2C interfaces. This can also be built as a module 
+  which can be inserted and removed while the kernel is running.
+
+Silicon Integrated Systems Corp. SiS645/961,645DX/961,735 based Mainboard
+CONFIG_I2C_SIS645
+  If you say yes to this option, support will be included for the SiS 645/961,
+  645DX/961 and 735 mainboard I2C interfaces. This can also be built as a module
+  which can be inserted and removed while the kernel is running.
+
+VIA Technologies, Inc. VT82C586B
+CONFIG_I2C_VIA
+  If you say yes to this option, support will be included for the VIA
+  Technologies I2C adapter found on some motherboards. This can also 
+  be built as a module which can be inserted and removed while the 
+  kernel is running.
+
+VIA Technologies, Inc. VT82C596, 596B, 686A/B, 8233, 8235
+CONFIG_I2C_VIAPRO
+  If you say yes to this option, support will be included for the VIA
+  Technologies I2C adapter on these chips. For integrated sensors on the
+  Via 686A/B, use CONFIG_SENSORS_VIA686A. This can also be
+  be built as a module which can be inserted and removed while the 
+  kernel is running.
+
+3DFX Banshee / Voodoo3
+CONFIG_I2C_VOODOO3
+  If you say yes to this option, support will be included for the 
+  3DFX Banshee and Voodoo3 I2C interfaces. The I2C busses on the these
+  chips are generally used only for video devices.
+  This can also be
+  built as a module which can be inserted and removed while the kernel
+  is running.
+
+DEC Tsunami 21272
+CONFIG_I2C_TSUNAMI
+  If you say yes to this option, support will be included for the DEC
+  Tsunami chipset I2C adapter. Requires the Alpha architecture;
+  do not enable otherwise. This can also be built as a module which
+  can be inserted and removed while the kernel is running.
+
+Pseudo ISA adapter (for hardware sensors modules)
+CONFIG_I2C_ISA
+  This provides support for accessing some hardware sensor chips over
+  the ISA bus rather than the I2C or SMBus. If you want to do this, 
+  say yes here. This feature can also be built as a module which can 
+  be inserted and removed while the kernel is running.
+
+  You will also need the latest user-space utilties: you can find them
+  in the lm_sensors package, which you can download at 
+  http://www.lm-sensors.nu
+
+Analog Devices ADM1021 and compatibles
+CONFIG_SENSORS_ADM1021 
+  If you say yes here you get support for Analog Devices ADM1021 
+  and ADM1023 sensor chips and clones: Maxim MAX1617 and MAX1617A,
+  Genesys Logic GL523SM, National Semi LM84, TI THMC10, Onsemi MC1066
+  and the XEON processor built-in sensor. This can also 
+  be built as a module which can be inserted and removed while the 
+  kernel is running.
+
+  You will also need the latest user-space utilties: you can find them
+  in the lm_sensors package, which you can download at 
+  http://www.lm-sensors.nu
+
+Analog Devices ADM1024
+CONFIG_SENSORS_ADM1024
+  If you say yes here you get support for Analog Devices ADM1024 sensor
+  chips.  This can also be built as a module.
+
+  You will also need the latest user-space utilties: you can find them
+  in the lm_sensors package, which you can download at 
+  http://www.lm-sensors.nu
+
+Analog Devices ADM1025
+CONFIG_SENSORS_ADM1025
+  If you say yes here you get support for Analog Devices ADM1025 sensor
+  chips.  This can also be built as a module which can be inserted and
+  removed while the kernel is running.
+
+  You will also need the latest user-space utilties: you can find them
+  in the lm_sensors package, which you can download at 
+  http://www.lm-sensors.nu
+
+Analog Devices ADM1026
+CONFIG_SENSORS_ADM1026
+  If you say yes here you get support for Analog Devices ADM1026 sensor
+  chips.  This can also be built as a module which can be inserted and
+  removed while the kernel is running.
+
+  You will also need the latest user-space utilties: you can find them
+  in the lm_sensors package, which you can download at 
+  http://www.lm-sensors.nu
+
+Analog Devices ADM9240 and compatibles
+CONFIG_SENSORS_ADM9240
+  If you say yes here you get support for Analog Devices ADM9240 
+  sensor chips and clones: the Dallas Semiconductor DS1780 and
+  the National Semiconductor LM81. This can also be built as a 
+  module which can be inserted and removed while the kernel is
+  running.
+
+  You will also need the latest user-space utilties: you can find them
+  in the lm_sensors package, which you can download at 
+  http://www.lm-sensors.nu
+
+Asus ASB100
+CONFIG_SENSORS_ASB100
+  If you say yes here you get support for the Asus ASB100 (aka
+  "Bach") sensor chip.  This can also be built as a module.
+
+  You will also need the latest user-space utilities: you can find
+  them in the lm_sensors package, which you can download at
+  http://www.lm-sensors.nu/
+
+Dallas DS1621 and DS1625
+CONFIG_SENSORS_DS1621
+  If you say yes here you get support for the Dallas DS1621 and DS1625x
+  sensor chips.  This can also be built as a module.
+
+  You will also need the latest user-space utilties: you can find them
+  in the lm_sensors package, which you can download at 
+  http://www.lm-sensors.nu
+
+Fujitsu-Siemens Poseidon
+CONFIG_SENSORS_FSCPOS
+  If you say yes here you get support for the Fujitsu-Siemens Poseidon
+  sensor chip.  This can also be built as a module.
+
+  You will also need the latest user-space utilties: you can find them
+  in the lm_sensors package, which you can download at 
+  http://www.lm-sensors.nu
+
+Fujitsu-Siemens Scylla
+CONFIG_SENSORS_FSCSCY
+  If you say yes here you get support for the Fujitsu-Siemens Scylla
+  sensor chip.  This can also be built as a module. This driver may/should
+  also work with the following Fujitsu-Siemens chips: "Poseidon",
+  "Poseidon II" and "Hydra". You may have to force loading of the module
+  for motherboards in these cases. Be careful - those motherboards have
+  not been tested with this driver.
+
+  You will also need the latest user-space utilties: you can find them
+  in the lm_sensors package, which you can download at 
+  http://www.lm-sensors.nu
+
+Genesys Logic GL518SM
+CONFIG_SENSORS_GL518SM
+  If you say yes here you get support for Genesys Logic GL518SM sensor
+  chips.  This can also be built as a module which can be inserted and
+  removed while the kernel is running.
+
+  You will also need the latest user-space utilties: you can find them
+  in the lm_sensors package, which you can download at 
+  http://www.lm-sensors.nu
+
+Genesys Logic GL520SM
+CONFIG_SENSORS_GL520SM
+  If you say yes here you get support for Genesys Logic GL518SM sensor
+  chips.  This can also be built as a module which can be inserted and
+  removed while the kernel is running.
+
+  You will also need the latest user-space utilties: you can find them
+  in the lm_sensors package, which you can download at 
+  http://www.lm-sensors.nu
+
+HP Maxilife
+CONFIG_SENSORS_MAXILIFE
+  If you say yes here you get support for the HP Maxilife
+  sensor chip.  This can also be built as a module.
+
+  You will also need the latest user-space utilties: you can find them
+  in the lm_sensors package, which you can download at 
+  http://www.lm-sensors.nu
+
+ITE 8705, 8712, Sis950
+CONFIG_SENSORS_IT87
+  If you say yes here you get support for the ITE 8705 and 8712 and
+  SiS950 sensor chips.  This can also be built as a module.
+
+  You will also need the latest user-space utilties: you can find them
+  in the lm_sensors package, which you can download at 
+  http://www.lm-sensors.nu
+
+Maxim MAX6650, MAX6651
+CONFIG_SENSORS_MAX6650
+  If you say yes here you get support for the Maxim MAX6650 and
+  MAX6651 sensor chips.  This can also be built as a module.
+
+  You will also need the latest user-space utilties: you can find them
+  in the lm_sensors package, which you can download at 
+  http://www.lm-sensors.nu
+
+Myson MTP008
+CONFIG_SENSORS_MTP008
+  If you say yes here you get support for the Myson MTP008
+  sensor chip.  This can also be built as a module.
+
+  You will also need the latest user-space utilties: you can find them
+  in the lm_sensors package, which you can download at 
+  http://www.lm-sensors.nu
+
+National Semiconductor LM75 and compatibles
+CONFIG_SENSORS_LM75 
+  If you say yes here you get support for National Semiconductor LM75
+  sensor chips and clones: Dallas Semi DS75 and DS1775, TelCon
+  TCN75, and National Semi LM77. This can also be built as a module which
+  can be inserted and removed while the kernel is running.
+
+  You will also need the latest user-space utilties: you can find them
+  in the lm_sensors package, which you can download at 
+  http://www.lm-sensors.nu
+
+National Semiconductor LM78
+CONFIG_SENSORS_LM78
+  If you say yes here you get support for National Semiconductor LM78
+  sensor chips family: the LM78-J and LM79. Many clone chips will
+  also work at least somewhat with this driver. This can also be built
+  as a module which can be inserted and removed while the kernel is 
+  running.
+
+  You will also need the latest user-space utilties: you can find them
+  in the lm_sensors package, which you can download at 
+  http://www.lm-sensors.nu
+
+National Semiconductor LM80
+CONFIG_SENSORS_LM80
+  If you say yes here you get support for National Semiconductor LM80
+  sensor chips. This can also be built as a module which can be 
+  inserted and removed while the kernel is running.
+
+  You will also need the latest user-space utilties: you can find them
+  in the lm_sensors package, which you can download at 
+  http://www.lm-sensors.nu
+
+National Semiconductor LM83
+CONFIG_SENSORS_LM83
+  If you say yes here you get support for the National Semiconductor
+  LM83 sensor chip.  This can also be built as a module.
+
+  You will also need the latest user-space utilities: you can find
+  them in the lm_sensors package, which you can download at
+  http://www.lm-sensors.nu/
+
+National Semiconductor LM85
+CONFIG_SENSORS_LM85
+  If you say yes here you get support for National Semiconductor LM85
+  sensor chips and compatibles.  Compatible chips include the Analog
+  Devices ADM1027 and ADT7463 and SMSC EMC6D100 and EMC6D101.  This
+  can also be built as a module which can be inserted and removed
+  while the kernel is running.
+
+  You will also need the latest user-space utilties: you can find them
+  in the lm_sensors package, which you can download at 
+  http://www.lm-sensors.nu
+
+National Semiconductor LM87
+CONFIG_SENSORS_LM87
+  If you say yes here you get support for National Semiconductor LM87
+  sensor chips. This can also be built as a module which can be 
+  inserted and removed while the kernel is running.
+
+  You will also need the latest user-space utilties: you can find them
+  in the lm_sensors package, which you can download at 
+  http://www.lm-sensors.nu
+
+National Semiconductor LM90
+CONFIG_SENSORS_LM90
+  If you say yes here you get support for the National Semiconductor
+  LM90, LM89 and LM99, and Analog Devices ADM1032 sensor chips.  This
+  can also be built as a module.
+
+  You will also need the latest user-space utilities: you can find
+  them in the lm_sensors package, which you can download at
+  http://www.lm-sensors.nu/
+
+National Semiconductor LM92
+CONFIG_SENSORS_LM92
+  If you say yes here you get support for National Semiconductor LM92
+  sensor chips. This can also be built as a module which can be 
+  inserted and removed while the kernel is running.
+
+  You will also need the latest user-space utilties: you can find them
+  in the lm_sensors package, which you can download at 
+  http://www.lm-sensors.nu
+
+Philips PCF8574
+CONFIG_SENSORS_PCF8574
+  If you say yes here you get support for the Philips PCF8574
+  I2C 8-bit Parallel I/O device.
+  This can also be built as a module which can be 
+  inserted and removed while the kernel is running.
+
+  You will also need the latest user-space utilties: you can find them
+  in the lm_sensors package, which you can download at 
+  http://www.lm-sensors.nu
+
+Philips PCF8591
+CONFIG_SENSORS_PCF8591
+  If you say yes here you get support for the Philips PCF8591
+  I2C Quad D/A + Single A/D I/O device.
+  This can also be built as a module which can be 
+  inserted and removed while the kernel is running.
+
+  You will also need the latest user-space utilties: you can find them
+  in the lm_sensors package, which you can download at 
+  http://www.lm-sensors.nu
+
+Silicon Integrated Systems Corp. SiS5595 Sensor
+CONFIG_SENSORS_SIS5595
+  If you say yes here you get support for the integrated sensors in 
+  SiS5595 South Bridges. This can also be built as a module 
+  which can be inserted and removed while the kernel is running.
+
+  You will also need the latest user-space utilties: you can find them
+  in the lm_sensors package, which you can download at 
+  http://www.lm-sensors.nu
+
+SMSC47M1xx Super I/O Fan Support
+CONFIG_SENSORS_SMSC47M1
+  If you say yes here you get support for the integrated fan
+  monitoring and control in the SMSC 47M1xx Super I/O chips.
+  This can also be built as a module 
+  which can be inserted and removed while the kernel is running.
+
+  You will also need the latest user-space utilties: you can find them
+  in the lm_sensors package, which you can download at 
+  http://www.lm-sensors.nu
+
+Texas Instruments THMC50 / Analog Devices ADM1022
+CONFIG_SENSORS_THMC50
+  If you say yes here you get support for Texas Instruments THMC50
+  sensor chips and clones: the Analog Devices ADM1022.
+  This can also be built as a module which
+  can be inserted and removed while the kernel is running.
+
+  You will also need the latest user-space utilties: you can find them
+  in the lm_sensors package, which you can download at 
+  http://www.lm-sensors.nu
+
+Via VT82C686A/B
+CONFIG_SENSORS_VIA686A
+  If you say yes here you get support for the integrated sensors in 
+  Via 686A/B South Bridges. This can also be built as a module 
+  which can be inserted and removed while the kernel is running.
+
+  You will also need the latest user-space utilties: you can find them
+  in the lm_sensors package, which you can download at 
+  http://www.lm-sensors.nu
+
+Via VT1211 Sensors
+CONFIG_SENSORS_VT1211
+  If you say yes here you get support for the integrated sensors in 
+  the Via VT1211 Super I/O device. This can also be built as a module 
+  which can be inserted and removed while the kernel is running.
+
+  You will also need the latest user-space utilties: you can find them
+  in the lm_sensors package, which you can download at 
+  http://www.lm-sensors.nu
+
+Via VT8231 Sensors
+CONFIG_SENSORS_VT8231
+  If you say yes here you get support for the integrated sensors in 
+  the Via VT8231 device. This can also be built as a module 
+  which can be inserted and removed while the kernel is running.
+
+  You will also need the latest user-space utilties: you can find them
+  in the lm_sensors package, which you can download at 
+  http://www.lm-sensors.nu
+
+Winbond W83781D, W83782D, W83783S, W83627HF, AS99127F
+CONFIG_SENSORS_W83781D
+  If you say yes here you get support for the Winbond W8378x series 
+  of sensor chips: the W83781D, W83782D, W83783S and W83682HF,
+  and the similar Asus AS99127F. This
+  can also be built as a module which can be inserted and removed
+  while the kernel is running.
+
+  You will also need the latest user-space utilties: you can find them
+  in the lm_sensors package, which you can download at 
+  http://www.lm-sensors.nu
+
+Winbond W83627HF, W83627THF, W83697HF
+CONFIG_SENSORS_W83627HF
+  If you say yes here you get support for the Winbond W836x7 series 
+  of sensor chips: the Winbond W83627HF, W83627THF and W83697HF. This
+  can also be built as a module which can be inserted and removed
+  while the kernel is running.
+
+  You will also need the latest user-space utilities: you can find
+  them in the lm_sensors package, which you can download at
+  http://www.lm-sensors.nu/
+
+Winbond W83L785TS-S
+CONFIG_SENSORS_W83L785TS
+  If you say yes here you get support for the Winbond W83L785TS-S
+  sensor chip.  This can also be built as a module.
+
+  You will also need the latest user-space utilities: you can find
+  them in the lm_sensors package, which you can download at
+  http://www.lm-sensors.nu/
+
+EEprom (DIMM) reader
+CONFIG_SENSORS_EEPROM
+  If you say yes here you get read-only access to the EEPROM data 
+  available on modern memory DIMMs, and which could theoretically
+  also be available on other devices. This can also be built as a 
+  module which can be inserted and removed while the kernel is 
+  running.
+
+  You will also need the latest user-space utilties: you can find them
+  in the lm_sensors package, which you can download at 
+  http://www.lm-sensors.nu
+
 # End:
diff -urN --exclude-from=diff-exclude linux-2.4.27/Documentation/i2c/dev-interface linux-2.4.27-leo/Documentation/i2c/dev-interface
--- linux-2.4.27/Documentation/i2c/dev-interface	2004-02-20 14:11:36.000000000 +0000
+++ linux-2.4.27-leo/Documentation/i2c/dev-interface	2004-09-20 21:34:38.000000000 +0100
@@ -89,6 +89,11 @@
   Selects ten bit addresses if select not equals 0, selects normal 7 bit
   addresses if select equals 0. Default 0.
 
+ioctl(file,I2C_PEC,long select)
+  Selects SMBus PEC (packet error checking) generation and verification
+  if select not equals 0, disables if select equals 0. Default 0.
+  Used only for SMBus transactions.
+
 ioctl(file,I2C_FUNCS,unsigned long *funcs)
   Gets the adapter functionality and puts it in *funcs.
 
diff -urN --exclude-from=diff-exclude linux-2.4.27/Documentation/i2c/i2c-pport linux-2.4.27-leo/Documentation/i2c/i2c-pport
--- linux-2.4.27/Documentation/i2c/i2c-pport	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.27-leo/Documentation/i2c/i2c-pport	2004-09-20 21:34:38.000000000 +0100
@@ -0,0 +1,67 @@
+Parallel Port Adapters
+----------------------
+If you are installing parallel port adapters it means you are probably messing 
+around with wires and IC's and the like. If you have purchased a card that 
+provides an external i2c/smbus this will require combined algorithm and 
+adapter code in a single module.
+If you are doing it yourself by using the parallel port there 
+are basically 2 options.
+
+1) Using the parallel port and using the i2c-pport adapter module and the 
+i2c-algo-bit algorithm module together to enable you to wire up your parallel 
+port to act as an i2c/smbus. This provides a bus that will enable most 
+sensors to work but doesn't support the entire i2c/smbus capability.
+
+2) Using the parallel port to interface to a Philips PCF8584 parallel to i2c 
+adapter chip. You will need to build a bit of a circuit to do this. This 
+configuration needs the i2c-pcf-epp adapter module and the i2c-algo-pcf 
+algorithm module. This support almost all of the i2c/smbus capabilities.
+
+
+i2c-pport Documentation
+-----------------------
+This is a primitive parallel port driver for the i2c bus, which exploits 
+features of modern bidirectional parallel ports. 
+
+Bidirectional ports have particular bits connected in following way:
+   
+                        |
+            /-----|     R
+         --o|     |-----|
+      read  \-----|     /------- Out pin
+                      |/
+                   - -|\
+                write   V
+                        |
+                       ---  
+
+
+It means when output is set to 1 we can read the port. Therefore 
+we can use 2 pins of parallel port as SDA and SCL for i2c bus. It 
+is not necessary to add any external - additional parts, we can 
+read and write the same port simultaneously.
+	I only use register base+2 so it is possible to use all 
+8 data bits of parallel port for other applications (I have 
+connected EEPROM and LCD display). I do not use bit Enable Bi-directional
+ Port. The only disadvantage is we can only support 5V chips.
+
+Layout:
+
+Cannon 25 pin
+
+SDA - connect to pin 14 (Auto Linefeed)
+SCL - connect to pin 16 (Initialize Printer)
+GND - connect to pin 18-25
++5V - use external supply (I use 5V from 3.5" floppy connector)
+      
+no pullups  requied
+
+Module parameters:
+
+base = 0xXXX
+XXX - 278 or 378
+
+That's all.
+
+Daniel Smolik
+marvin@sitour.cz
diff -urN --exclude-from=diff-exclude linux-2.4.27/Documentation/i2c/i2c-protocol linux-2.4.27-leo/Documentation/i2c/i2c-protocol
--- linux-2.4.27/Documentation/i2c/i2c-protocol	2004-02-20 14:11:36.000000000 +0000
+++ linux-2.4.27-leo/Documentation/i2c/i2c-protocol	2004-09-20 21:34:38.000000000 +0100
@@ -65,3 +65,12 @@
     need to emit an Rd instead of a Wr, or vice versa, you set this
     flag. For example:
       S Addr Rd [A] Data [A] Data [A] ... [A] Data [A] P
+
+  Flags I2C_M_IGNORE_NAK
+    Normally message is interrupted immediately if there is [NA] from the
+    client. Setting this flag treats any [NA] as [A], and all of
+    message is sent.
+    These messages may still fail to SCL lo->hi timeout.
+
+  Flags I2C_M_NO_RD_ACK
+    In a read message, master A/NA bit is skipped.
diff -urN --exclude-from=diff-exclude linux-2.4.27/Documentation/i2c/summary linux-2.4.27-leo/Documentation/i2c/summary
--- linux-2.4.27/Documentation/i2c/summary	2004-02-20 14:11:36.000000000 +0000
+++ linux-2.4.27-leo/Documentation/i2c/summary	2004-09-20 21:34:38.000000000 +0100
@@ -59,16 +59,16 @@
 i2c-algo-8xx:    An algorithm for CPM's I2C device in Motorola 8xx processors (NOT BUILT BY DEFAULT)
 i2c-algo-bit:    A bit-banging algorithm
 i2c-algo-pcf:    A PCF 8584 style algorithm
-i2c-algo-ppc405: An algorithm for the I2C device in IBM 405xx processors (NOT BUILT BY DEFAULT)
+i2c-algo-ibm_ocp: An algorithm for the I2C device in IBM 4xx processors (NOT BUILT BY DEFAULT)
 
 Adapter drivers
 ---------------
 
 i2c-elektor:     Elektor ISA card (uses i2c-algo-pcf)
 i2c-elv:         ELV parallel port adapter (uses i2c-algo-bit)
-i2c-pcf-epp:     PCF8584 on a EPP parallel port (uses i2c-algo-pcf) (BROKEN - missing i2c-pcf-epp.h)
+i2c-pcf-epp:     PCF8584 on a EPP parallel port (uses i2c-algo-pcf) (NOT mkpatched)
 i2c-philips-par: Philips style parallel port adapter (uses i2c-algo-bit)
-i2c-ppc405:      IBM 405xx processor I2C device (uses i2c-algo-ppc405) (NOT BUILT BY DEFAULT)
+i2c-adap-ibm_ocp: IBM 4xx processor I2C device (uses i2c-algo-ibm_ocp) (NOT BUILT BY DEFAULT)
 i2c-pport:       Primitive parallel port adapter (uses i2c-algo-bit)
 i2c-rpx:         RPX board Motorola 8xx I2C device (uses i2c-algo-8xx) (NOT BUILT BY DEFAULT)
 i2c-velleman:    Velleman K8000 parallel port adapter (uses i2c-algo-bit)
diff -urN --exclude-from=diff-exclude linux-2.4.27/Documentation/i2c/writing-clients linux-2.4.27-leo/Documentation/i2c/writing-clients
--- linux-2.4.27/Documentation/i2c/writing-clients	2004-02-20 14:11:36.000000000 +0000
+++ linux-2.4.27-leo/Documentation/i2c/writing-clients	2004-09-20 21:34:38.000000000 +0100
@@ -24,16 +24,14 @@
 routines, a client structure specific information like the actual I2C
 address.
 
-  struct i2c_driver foo_driver
-  {  
-    /* name           */  "Foo version 2.3 and later driver",
-    /* id             */  I2C_DRIVERID_FOO,
-    /* flags          */  I2C_DF_NOTIFY,
-    /* attach_adapter */  &foo_attach_adapter,
-    /* detach_client  */  &foo_detach_client,
-    /* command        */  &foo_command,   /* May be NULL */
-    /* inc_use        */  &foo_inc_use,   /* May be NULL */
-    /* dec_use        */  &foo_dec_use    /* May be NULL */
+  static struct i2c_driver foo_driver = {
+    .owner          = THIS_MODULE,
+    .name           = "Foo version 2.3 driver",
+    .id             = I2C_DRIVERID_FOO, /* usually from i2c-id.h */
+    .flags          = I2C_DF_NOTIFY,
+    .attach_adapter = &foo_attach_adapter,
+    .detach_client  = &foo_detach_client,
+    .command        = &foo_command /* may be NULL */
   }
  
 The name can be chosen freely, and may be upto 40 characters long. Please
@@ -50,43 +48,8 @@
 All other fields are for call-back functions which will be explained 
 below.
 
-
-Module usage count
-==================
-
-If your driver can also be compiled as a module, there are moments at 
-which the module can not be removed from memory. For example, when you
-are doing a lengthy transaction, or when you create a /proc directory,
-and some process has entered that directory (this last case is the
-main reason why these call-backs were introduced).
-
-To increase or decrease the module usage count, you can use the
-MOD_{INC,DEC}_USE_COUNT macros. They must be called from the module
-which needs to get its usage count changed; that is why each driver
-module has to implement its own callback.
-
-  void foo_inc_use (struct i2c_client *client)
-  {
-  #ifdef MODULE
-    MOD_INC_USE_COUNT;
-  #endif
-  }
-
-  void foo_dec_use (struct i2c_client *client)
-  {
-  #ifdef MODULE
-    MOD_DEC_USE_COUNT;
-  #endif
-  }
-
-Do not call these call-back functions directly; instead, use one of the
-following functions defined in i2c.h:
-  void i2c_inc_use_client(struct i2c_client *);
-  void i2c_dec_use_client(struct i2c_client *);
-
-You should *not* increase the module count just because a device is
-detected and a client created. This would make it impossible to remove
-an adapter driver! 
+There use to be two additional fields in this structure, inc_use et dec_use,
+for module usage count, but these fields were obsoleted and removed.
 
 
 Extra client data
diff -urN --exclude-from=diff-exclude linux-2.4.27/Documentation/preempt-locking.txt linux-2.4.27-leo/Documentation/preempt-locking.txt
--- linux-2.4.27/Documentation/preempt-locking.txt	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.27-leo/Documentation/preempt-locking.txt	2004-09-17 03:19:36.000000000 +0100
@@ -0,0 +1,104 @@
+		  Proper Locking Under a Preemptible Kernel:
+		       Keeping Kernel Code Preempt-Safe
+			  Robert Love <rml@tech9.net>
+			   Last Updated: 22 Jan 2002
+
+
+INTRODUCTION
+
+
+A preemptible kernel creates new locking issues.  The issues are the same as
+those under SMP: concurrency and reentrancy.  Thankfully, the Linux preemptible
+kernel model leverages existing SMP locking mechanisms.  Thus, the kernel
+requires explicit additional locking for very few additional situations.
+
+This document is for all kernel hackers.  Developing code in the kernel
+requires protecting these situations.
+ 
+
+RULE #1: Per-CPU data structures need explicit protection
+
+
+Two similar problems arise. An example code snippet:
+
+	struct this_needs_locking tux[NR_CPUS];
+	tux[smp_processor_id()] = some_value;
+	/* task is preempted here... */
+	something = tux[smp_processor_id()];
+
+First, since the data is per-CPU, it may not have explicit SMP locking, but
+require it otherwise.  Second, when a preempted task is finally rescheduled,
+the previous value of smp_processor_id may not equal the current.  You must
+protect these situations by disabling preemption around them.
+
+
+RULE #2: CPU state must be protected.
+
+
+Under preemption, the state of the CPU must be protected.  This is arch-
+dependent, but includes CPU structures and state not preserved over a context
+switch.  For example, on x86, entering and exiting FPU mode is now a critical
+section that must occur while preemption is disabled.  Think what would happen
+if the kernel is executing a floating-point instruction and is then preempted.
+Remember, the kernel does not save FPU state except for user tasks.  Therefore,
+upon preemption, the FPU registers will be sold to the lowest bidder.  Thus,
+preemption must be disabled around such regions.
+
+Note, some FPU functions are already explicitly preempt safe.  For example,
+kernel_fpu_begin and kernel_fpu_end will disable and enable preemption.
+However, math_state_restore must be called with preemption disabled.
+
+
+RULE #3: Lock acquire and release must be performed by same task
+
+
+A lock acquired in one task must be released by the same task.  This
+means you can't do oddball things like acquire a lock and go off to
+play while another task releases it.  If you want to do something
+like this, acquire and release the task in the same code path and
+have the caller wait on an event by the other task.
+
+
+SOLUTION
+
+
+Data protection under preemption is achieved by disabling preemption for the
+duration of the critical region.
+
+preempt_enable()		decrement the preempt counter
+preempt_disable()		increment the preempt counter
+preempt_enable_no_resched()	decrement, but do not immediately preempt
+preempt_get_count()		return the preempt counter
+
+The functions are nestable.  In other words, you can call preempt_disable
+n-times in a code path, and preemption will not be reenabled until the n-th
+call to preempt_enable.  The preempt statements define to nothing if
+preemption is not enabled.
+
+Note that you do not need to explicitly prevent preemption if you are holding
+any locks or interrupts are disabled, since preemption is implicitly disabled
+in those cases.
+
+Example:
+
+	cpucache_t *cc; /* this is per-CPU */
+	preempt_disable();
+	cc = cc_data(searchp);
+	if (cc && cc->avail) {
+		__free_block(searchp, cc_entry(cc), cc->avail);
+		cc->avail = 0;
+	}
+	preempt_enable();
+	return 0;
+
+Notice how the preemption statements must encompass every reference of the
+critical variables.  Another example:
+
+	int buf[NR_CPUS];
+	set_cpu_val(buf);
+	if (buf[smp_processor_id()] == -1) printf(KERN_INFO "wee!\n");
+	spin_lock(&buf_lock);
+	/* ... */
+
+This code is not preempt-safe, but see how easily we can fix it by simply
+moving the spin_lock up two lines.
diff -urN --exclude-from=diff-exclude linux-2.4.27/drivers/block/Config.in linux-2.4.27-leo/drivers/block/Config.in
--- linux-2.4.27/drivers/block/Config.in	2004-09-17 02:38:43.000000000 +0100
+++ linux-2.4.27-leo/drivers/block/Config.in	2004-09-17 03:19:04.000000000 +0100
@@ -42,6 +42,7 @@
 dep_tristate 'Promise SATA SX8 support' CONFIG_BLK_DEV_SX8 $CONFIG_PCI
 
 tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
+dep_tristate '  Cryptoloop support' CONFIG_BLK_DEV_CRYPTOLOOP $CONFIG_BLK_DEV_LOOP
 dep_tristate 'Network block device support' CONFIG_BLK_DEV_NBD $CONFIG_NET
 
 tristate 'RAM disk support' CONFIG_BLK_DEV_RAM
diff -urN --exclude-from=diff-exclude linux-2.4.27/drivers/block/cryptoloop.c linux-2.4.27-leo/drivers/block/cryptoloop.c
--- linux-2.4.27/drivers/block/cryptoloop.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.27-leo/drivers/block/cryptoloop.c	2004-09-17 03:19:04.000000000 +0100
@@ -0,0 +1,179 @@
+/*
+   Linux loop encryption enabling module
+
+   Copyright (C)  2002 Herbert Valerio Riedel <hvr@gnu.org>
+   Copyright (C)  2003 Fruhwirth Clemens <clemens@endorphin.org>
+
+   This module 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 module 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 module; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/crypto.h>
+#include <linux/blkdev.h>
+#include <linux/loop.h>
+#include <asm/semaphore.h>
+#include <asm/uaccess.h>
+#include <asm/scatterlist.h>
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("loop blockdevice transferfunction adaptor / CryptoAPI");
+MODULE_AUTHOR("Herbert Valerio Riedel <hvr@gnu.org>");
+
+static int
+cryptoloop_init(struct loop_device *lo, /* const */ struct loop_info *info)
+{
+	int err = -EINVAL;
+	char cms[LO_NAME_SIZE];			/* cipher-mode string */
+	char *cipher;
+	char *mode;
+	char *cmsp = cms;			/* c-m string pointer */
+	struct crypto_tfm *tfm = NULL;
+
+	/* encryption breaks for non sector aligned offsets */
+
+	if (info->lo_offset % LOOP_IV_SECTOR_SIZE)
+		goto out;
+
+	strncpy(cms, info->lo_name, LO_NAME_SIZE);
+	cms[LO_NAME_SIZE - 1] = 0;
+	cipher = strsep(&cmsp, "-");
+	mode = strsep(&cmsp, "-");
+
+	if (mode == NULL || strcmp(mode, "cbc") == 0)
+		tfm = crypto_alloc_tfm(cipher, CRYPTO_TFM_MODE_CBC);
+	else if (strcmp(mode, "ecb") == 0)
+		tfm = crypto_alloc_tfm(cipher, CRYPTO_TFM_MODE_ECB);
+	if (tfm == NULL)
+		return -EINVAL;
+
+	err = tfm->crt_u.cipher.cit_setkey(tfm, info->lo_encrypt_key,
+					   info->lo_encrypt_key_size);
+	
+	if (err != 0)
+		goto out_free_tfm;
+
+	lo->key_data = tfm;
+	return 0;
+
+ out_free_tfm:
+	crypto_free_tfm(tfm);
+
+ out:
+	return err;
+}
+
+typedef int (*encdec_t)(struct crypto_tfm *tfm,
+			struct scatterlist *sg_out,
+			struct scatterlist *sg_in,
+			unsigned int nsg, u8 *iv);
+
+static int
+cryptoloop_transfer(struct loop_device *lo, int cmd, char *raw_buf,
+		     char *loop_buf, int size, sector_t IV)
+{
+	struct crypto_tfm *tfm = (struct crypto_tfm *) lo->key_data;
+	struct scatterlist sg_out = { 0, };
+	struct scatterlist sg_in = { 0, };
+
+	encdec_t encdecfunc;
+	char const *in;
+	char *out;
+
+	if (cmd == READ) {
+		in = raw_buf;
+		out = loop_buf;
+		encdecfunc = tfm->crt_u.cipher.cit_decrypt_iv;
+	} else {
+		in = loop_buf;
+		out = raw_buf;
+		encdecfunc = tfm->crt_u.cipher.cit_encrypt_iv;
+	}
+
+	while (size > 0) {
+		const int sz = min(size, LOOP_IV_SECTOR_SIZE);
+		u32 iv[4] = { 0, };
+		iv[0] = cpu_to_le32(IV & 0xffffffff);
+
+		sg_in.page = virt_to_page(in);
+		sg_in.offset = (unsigned long)in & ~PAGE_MASK;
+		sg_in.length = sz;
+
+		sg_out.page = virt_to_page(out);
+		sg_out.offset = (unsigned long)out & ~PAGE_MASK;
+		sg_out.length = sz;
+
+		encdecfunc(tfm, &sg_out, &sg_in, sz, (u8 *)iv);
+
+		IV++;
+		size -= sz;
+		in += sz;
+		out += sz;
+	}
+
+	return 0;
+}
+
+
+static int
+cryptoloop_ioctl(struct loop_device *lo, int cmd, unsigned long arg)
+{
+	return -EINVAL;
+}
+
+static int
+cryptoloop_release(struct loop_device *lo)
+{
+	struct crypto_tfm *tfm = (struct crypto_tfm *) lo->key_data;
+	if (tfm != NULL) {
+		crypto_free_tfm(tfm);
+		lo->key_data = NULL;
+		return 0;
+	}
+	printk(KERN_ERR "cryptoloop_release(): tfm == NULL?\n");
+	return -EINVAL;
+}
+
+static struct loop_func_table cryptoloop_funcs = {
+	.number = LO_CRYPT_CRYPTOAPI,
+	.init = cryptoloop_init,
+	.ioctl = cryptoloop_ioctl,
+	.transfer = cryptoloop_transfer,
+	.release = cryptoloop_release,
+	/* .owner = THIS_MODULE */
+};
+
+static int __init
+init_cryptoloop(void)
+{
+	int rc = loop_register_transfer(&cryptoloop_funcs);
+
+	if (rc)
+		printk(KERN_ERR "cryptoloop: loop_register_transfer failed\n");
+	return rc;
+}
+
+static void __exit
+cleanup_cryptoloop(void)
+{
+	if (loop_unregister_transfer(LO_CRYPT_CRYPTOAPI))
+		printk(KERN_ERR
+			"cryptoloop: loop_unregister_transfer failed\n");
+}
+
+module_init(init_cryptoloop);
+module_exit(cleanup_cryptoloop);
diff -urN --exclude-from=diff-exclude linux-2.4.27/drivers/block/loop.c linux-2.4.27-leo/drivers/block/loop.c
--- linux-2.4.27/drivers/block/loop.c	2003-08-25 12:44:41.000000000 +0100
+++ linux-2.4.27-leo/drivers/block/loop.c	2004-09-17 03:19:04.000000000 +0100
@@ -88,7 +88,7 @@
  * Transfer functions
  */
 static int transfer_none(struct loop_device *lo, int cmd, char *raw_buf,
-			 char *loop_buf, int size, int real_block)
+			 char *loop_buf, int size, sector_t IV)
 {
 	if (raw_buf != loop_buf) {
 		if (cmd == READ)
@@ -101,7 +101,7 @@
 }
 
 static int transfer_xor(struct loop_device *lo, int cmd, char *raw_buf,
-			char *loop_buf, int size, int real_block)
+			char *loop_buf, int size, sector_t IV)
 {
 	char	*in, *out, *key;
 	int	i, keysize;
@@ -189,7 +189,7 @@
 	len = bh->b_size;
 	data = bh->b_data;
 	while (len > 0) {
-		int IV = index * (PAGE_CACHE_SIZE/bsize) + offset/bsize;
+		const sector_t IV = (index << (PAGE_CACHE_SHIFT - LOOP_IV_SECTOR_BITS)) + (offset >> LOOP_IV_SECTOR_BITS);
 		int transfer_result;
 
 		size = PAGE_CACHE_SIZE - offset;
@@ -249,7 +249,7 @@
 	unsigned long count = desc->count;
 	struct lo_read_data *p = (struct lo_read_data*)desc->buf;
 	struct loop_device *lo = p->lo;
-	int IV = page->index * (PAGE_CACHE_SIZE/p->bsize) + offset/p->bsize;
+	const sector_t IV = (page->index << (PAGE_CACHE_SHIFT - LOOP_IV_SECTOR_BITS)) + (offset >> LOOP_IV_SECTOR_BITS);
 
 	if (size > count)
 		size = count;
@@ -301,20 +301,6 @@
 	return bs;
 }
 
-static inline unsigned long loop_get_iv(struct loop_device *lo,
-					unsigned long sector)
-{
-	int bs = loop_get_bs(lo);
-	unsigned long offset, IV;
-
-	IV = sector / (bs >> 9) + lo->lo_offset / bs;
-	offset = ((sector % (bs >> 9)) << 9) + lo->lo_offset % bs;
-	if (offset >= bs)
-		IV++;
-
-	return IV;
-}
-
 static int do_bh_filebacked(struct loop_device *lo, struct buffer_head *bh, int rw)
 {
 	loff_t pos;
@@ -462,7 +448,7 @@
 {
 	struct buffer_head *bh = NULL;
 	struct loop_device *lo;
-	unsigned long IV;
+	sector_t IV;
 
 	if (!buffer_locked(rbh))
 		BUG();
@@ -507,7 +493,7 @@
 	 * piggy old buffer on original, and submit for I/O
 	 */
 	bh = loop_get_buffer(lo, rbh);
-	IV = loop_get_iv(lo, rbh->b_rsector);
+	IV = rbh->b_rsector + (lo->lo_offset >> LOOP_IV_SECTOR_BITS);
 	if (rw == WRITE) {
 		set_bit(BH_Dirty, &bh->b_state);
 		if (lo_do_transfer(lo, WRITE, bh->b_data, rbh->b_data,
@@ -544,7 +530,7 @@
 		bh->b_end_io(bh, !ret);
 	} else {
 		struct buffer_head *rbh = bh->b_private;
-		unsigned long IV = loop_get_iv(lo, rbh->b_rsector);
+		const sector_t IV = rbh->b_rsector + (lo->lo_offset >> LOOP_IV_SECTOR_BITS);
 
 		ret = lo_do_transfer(lo, READ, bh->b_data, rbh->b_data,
 				     bh->b_size, IV);
diff -urN --exclude-from=diff-exclude linux-2.4.27/drivers/block/Makefile linux-2.4.27-leo/drivers/block/Makefile
--- linux-2.4.27/drivers/block/Makefile	2004-09-17 02:59:19.000000000 +0100
+++ linux-2.4.27-leo/drivers/block/Makefile	2004-09-17 03:19:04.000000000 +0100
@@ -33,6 +33,7 @@
 obj-$(CONFIG_BLK_DEV_NBD)	+= nbd.o
 obj-$(CONFIG_BLK_DEV_SX8)	+= sx8.o
 obj-$(CONFIG_BLK_DEV_CRYPTOLOOP) += cryptoloop.o
+obj-$(CONFIG_BLK_DEV_CRYPTOLOOP) += cryptoloop.o
 
 subdir-$(CONFIG_PARIDE) += paride
 
diff -urN --exclude-from=diff-exclude linux-2.4.27/drivers/char/Config.in linux-2.4.27-leo/drivers/char/Config.in
--- linux-2.4.27/drivers/char/Config.in	2004-09-17 02:38:43.000000000 +0100
+++ linux-2.4.27-leo/drivers/char/Config.in	2004-09-20 21:34:47.000000000 +0100
@@ -190,6 +190,8 @@
 
 source drivers/i2c/Config.in
 
+source drivers/sensors/Config.in
+
 mainmenu_option next_comment
 comment 'Mice'
 tristate 'Bus Mouse Support' CONFIG_BUSMOUSE
diff -urN --exclude-from=diff-exclude linux-2.4.27/drivers/char/keyboard.c linux-2.4.27-leo/drivers/char/keyboard.c
--- linux-2.4.27/drivers/char/keyboard.c	2003-11-28 18:26:20.000000000 +0000
+++ linux-2.4.27-leo/drivers/char/keyboard.c	2004-09-17 03:19:58.000000000 +0100
@@ -545,6 +545,16 @@
 	if ((kbd->kbdmode == VC_RAW || kbd->kbdmode == VC_MEDIUMRAW) &&
 	    !(SPECIALS_ALLOWED_IN_RAW_MODE & (1 << value)))
 		return;
+
+#if defined(CONFIG_GRKERNSEC_PROC) || defined(CONFIG_GRKERNSEC_PROC_MEMMAP)
+	{
+		void *func = spec_fn_table[value];
+		if (func == show_state || func == show_ptregs ||
+		    func == show_mem)
+			return;
+	}
+#endif
+
 	spec_fn_table[value]();
 }
 
diff -urN --exclude-from=diff-exclude linux-2.4.27/drivers/char/mem.c linux-2.4.27-leo/drivers/char/mem.c
--- linux-2.4.27/drivers/char/mem.c	2004-09-17 02:38:44.000000000 +0100
+++ linux-2.4.27-leo/drivers/char/mem.c	2004-09-17 03:20:32.000000000 +0100
@@ -22,6 +22,7 @@
 #include <linux/tty.h>
 #include <linux/capability.h>
 #include <linux/ptrace.h>
+#include <linux/grsecurity.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -42,6 +43,10 @@
 #if defined(CONFIG_S390_TAPE) && defined(CONFIG_S390_TAPE_CHAR)
 extern void tapechar_init(void);
 #endif
+
+#ifdef CONFIG_GRKERNSEC
+extern struct file_operations grsec_fops;
+#endif
      
 static ssize_t do_write_mem(struct file * file, void *p, unsigned long realp,
 			    const char * buf, size_t count, loff_t *ppos)
@@ -115,6 +120,11 @@
 	unsigned long p = *ppos;
 	unsigned long end_mem;
 
+#ifdef CONFIG_GRKERNSEC_KMEM
+	gr_handle_mem_write();
+	return -EPERM;
+#endif
+
 	end_mem = __pa(high_memory);
 	if (p >= end_mem)
 		return 0;
@@ -187,6 +197,12 @@
 {
 	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
 
+#ifdef CONFIG_GRKERNSEC_KMEM
+	if (gr_handle_mem_mmap(offset, vma))
+		return -EPERM;
+#endif
+
+
 	/*
 	 * Accessing memory above the top the kernel knows about or
 	 * through a file pointer that was marked O_SYNC will be
@@ -286,6 +302,11 @@
 	ssize_t virtr = 0;
 	char * kbuf; /* k-addr because vwrite() takes vmlist_lock rwlock */
 
+#ifdef CONFIG_GRKERNSEC_KMEM
+	gr_handle_kmem_write();
+	return -EPERM;
+#endif
+
 	if (p < (unsigned long) high_memory) {
 		wrote = count;
 		if (count > (unsigned long) high_memory - p)
@@ -402,7 +423,23 @@
 			count = size;
 
 		zap_page_range(mm, addr, count);
-        	zeromap_page_range(addr, count, PAGE_COPY);
+	        zeromap_page_range(addr, count, vma->vm_page_prot); 
+
+#if defined(CONFIG_GRKERNSEC_PAX_SEGMEXEC) || defined(CONFIG_GRKERNSEC_PAX_RANDEXEC)
+		if (vma->vm_flags & VM_MIRROR) {
+			unsigned long addr_m;
+			struct vm_area_struct * vma_m;
+
+			addr_m = vma->vm_start + (unsigned long)vma->vm_private_data;
+			vma_m = find_vma(mm, addr_m);
+			if (vma_m && vma_m->vm_start == addr_m && (vma_m->vm_flags & VM_MIRROR)) {
+				addr_m = addr + (unsigned long)vma->vm_private_data;
+				zap_page_range(mm, addr_m, count);
+			} else
+				printk(KERN_ERR "PAX: VMMIRROR: read_zero bug, %08lx, %08lx\n",
+				       addr, vma->vm_start);
+		}
+#endif
 
 		size -= count;
 		buf += count;
@@ -525,6 +562,15 @@
 
 static int open_port(struct inode * inode, struct file * filp)
 {
+#ifdef CONFIG_GRKERNSEC_PORT
+	gr_handle_open_port();
+	return -EPERM;
+#endif
+	return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
+}
+
+static int open_mem(struct inode * inode, struct file * filp)
+{
 	return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
 }
 
@@ -582,6 +628,11 @@
 	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
 	unsigned long size = vma->vm_end - vma->vm_start;
 
+#ifdef CONFIG_GRKERNSEC_KMEM
+	if (gr_handle_mem_mmap(offset, vma))
+		return -EPERM;
+#endif
+
 	/*
 	 * If the user is not attempting to mmap a high memory address then
 	 * the standard mmap_mem mechanism will work.  High memory addresses
@@ -617,7 +668,6 @@
 #define full_lseek      null_lseek
 #define write_zero	write_null
 #define read_full       read_zero
-#define open_mem	open_port
 #define open_kmem	open_mem
 
 static struct file_operations mem_fops = {
@@ -693,6 +743,11 @@
 		case 9:
 			filp->f_op = &urandom_fops;
 			break;
+#ifdef CONFIG_GRKERNSEC
+		case 12:
+			filp->f_op = &grsec_fops;
+			break;
+#endif
 		default:
 			return -ENXIO;
 	}
@@ -719,7 +774,10 @@
 	{5, "zero",    S_IRUGO | S_IWUGO,           &zero_fops},
 	{7, "full",    S_IRUGO | S_IWUGO,           &full_fops},
 	{8, "random",  S_IRUGO | S_IWUSR,           &random_fops},
-	{9, "urandom", S_IRUGO | S_IWUSR,           &urandom_fops}
+	{9, "urandom", S_IRUGO | S_IWUSR,           &urandom_fops},
+#ifdef CONFIG_GRKERNSEC
+	{12,"grsec",   S_IRUSR | S_IWUGO,	    &grsec_fops}
+#endif
     };
     int i;
 
diff -urN --exclude-from=diff-exclude linux-2.4.27/drivers/char/random.c linux-2.4.27-leo/drivers/char/random.c
--- linux-2.4.27/drivers/char/random.c	2004-02-20 14:11:41.000000000 +0000
+++ linux-2.4.27-leo/drivers/char/random.c	2004-09-17 03:19:58.000000000 +0100
@@ -262,9 +262,15 @@
 /*
  * Configuration information
  */
+#ifdef CONFIG_GRKERNSEC_RANDNET
+#define DEFAULT_POOL_SIZE 1024
+#define SECONDARY_POOL_SIZE 256
+#define BATCH_ENTROPY_SIZE 512
+#else
 #define DEFAULT_POOL_SIZE 512
 #define SECONDARY_POOL_SIZE 128
 #define BATCH_ENTROPY_SIZE 256
+#endif
 #define USE_SHA
 
 /*
@@ -389,6 +395,7 @@
 /*
  * Static global variables
  */
+
 static struct entropy_store *random_state; /* The default global store */
 static struct entropy_store *sec_random_state; /* secondary store */
 static DECLARE_WAIT_QUEUE_HEAD(random_read_wait);
@@ -2210,6 +2217,29 @@
 	return halfMD4Transform(hash, keyptr->secret);
 }
 
+#ifdef CONFIG_GRKERNSEC
+/* the following function is provided by PaX under the GPL */
+unsigned long get_random_long(void)
+{       
+	static time_t rekey_time;
+	static __u32 secret[12];
+	time_t t;
+
+	/*
+	 * Pick a random secret every REKEY_INTERVAL seconds
+	 */
+	t = CURRENT_TIME;
+	if (!rekey_time || (t - rekey_time) > REKEY_INTERVAL) {
+		rekey_time = t;
+		get_random_bytes(secret, sizeof(secret));
+	}
+
+	secret[1] = halfMD4Transform(secret+8, secret);
+	secret[0] = halfMD4Transform(secret+8, secret);
+	return *(unsigned long *)secret;
+}
+#endif
+
 #ifdef CONFIG_SYN_COOKIES
 /*
  * Secure SYN cookie computation. This is the algorithm worked out by
diff -urN --exclude-from=diff-exclude linux-2.4.27/drivers/char/tty_io.c linux-2.4.27-leo/drivers/char/tty_io.c
--- linux-2.4.27/drivers/char/tty_io.c	2004-05-19 21:34:38.000000000 +0100
+++ linux-2.4.27-leo/drivers/char/tty_io.c	2004-09-17 03:19:58.000000000 +0100
@@ -1404,7 +1404,11 @@
 		retval = -ENODEV;
 	filp->f_flags = saved_flags;
 
+#ifdef CONFIG_GRKERNSEC
+	if (!retval && test_bit(TTY_EXCLUSIVE, &tty->flags) && !capable(CAP_SYS_TTY_CONFIG))
+#else
 	if (!retval && test_bit(TTY_EXCLUSIVE, &tty->flags) && !suser())
+#endif
 		retval = -EBUSY;
 
 	if (retval) {
@@ -1506,7 +1510,11 @@
 {
 	char ch, mbz = 0;
 
+#ifdef CONFIG_GRKERNSEC
+	if ((current->tty != tty) && !capable(CAP_SYS_TTY_CONFIG))
+#else
 	if ((current->tty != tty) && !suser())
+#endif
 		return -EPERM;
 	if (get_user(ch, arg))
 		return -EFAULT;
@@ -1544,7 +1552,11 @@
 	if (inode->i_rdev == SYSCONS_DEV ||
 	    inode->i_rdev == CONSOLE_DEV) {
 		struct file *f;
+#ifdef CONFIG_GRKERNSEC
+		if (!capable(CAP_SYS_TTY_CONFIG))
+#else
 		if (!suser())
+#endif
 			return -EPERM;
 		spin_lock(&redirect_lock);
 		f = redirect;
@@ -1596,7 +1608,11 @@
 		 * This tty is already the controlling
 		 * tty for another session group!
 		 */
+#ifdef CONFIG_GRKERNSEC
+		if ((arg == 1) && capable(CAP_SYS_ADMIN)) {
+#else
 		if ((arg == 1) && suser()) {
+#endif
 			/*
 			 * Steal it away
 			 */
diff -urN --exclude-from=diff-exclude linux-2.4.27/drivers/char/vt.c linux-2.4.27-leo/drivers/char/vt.c
--- linux-2.4.27/drivers/char/vt.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.27-leo/drivers/char/vt.c	2004-09-17 03:19:58.000000000 +0100
@@ -179,6 +179,11 @@
 	case KDSKBENT:
 		if (!perm)
 			return -EPERM;
+#ifdef CONFIG_GRKERNSEC
+		if (!capable(CAP_SYS_TTY_CONFIG))
+			return -EPERM;
+#endif
+
 		if (!i && v == K_NOSUCHMAP) {
 			/* disallocate map */
 			key_map = key_maps[s];
@@ -301,6 +306,11 @@
 		if (!perm)
 			return -EPERM;
 
+#ifdef CONFIG_GRKERNSEC
+		if (!capable(CAP_SYS_TTY_CONFIG))
+			return -EPERM;
+#endif
+
 		q = func_table[i];
 		first_free = funcbufptr + (funcbufsize - funcbufleft);
 		for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++) 
@@ -443,7 +453,11 @@
 	 * to be the owner of the tty, or super-user.
 	 */
 	perm = 0;
+#ifdef CONFIG_GRKERNSEC
+	if (current->tty == tty || capable(CAP_SYS_TTY_CONFIG))
+#else
 	if (current->tty == tty || suser())
+#endif
 		perm = 1;
  
 	kbd = kbd_table + console;
@@ -1038,12 +1052,20 @@
 		return do_unimap_ioctl(cmd, (struct unimapdesc *)arg, perm);
 
 	case VT_LOCKSWITCH:
+#ifdef CONFIG_GRKERNSEC
+		if (!capable(CAP_SYS_TTY_CONFIG))
+#else
 		if (!suser())
+#endif
 		   return -EPERM;
 		vt_dont_switch = 1;
 		return 0;
 	case VT_UNLOCKSWITCH:
+#ifdef CONFIG_GRKERNSEC
+		if (!capable(CAP_SYS_TTY_CONFIG))
+#else
 		if (!suser())
+#endif
 		   return -EPERM;
 		vt_dont_switch = 0;
 		return 0;
diff -urN --exclude-from=diff-exclude linux-2.4.27/drivers/i2c/Config.in linux-2.4.27-leo/drivers/i2c/Config.in
--- linux-2.4.27/drivers/i2c/Config.in	2004-05-19 21:34:38.000000000 +0100
+++ linux-2.4.27-leo/drivers/i2c/Config.in	2004-09-20 21:34:47.000000000 +0100
@@ -59,6 +59,30 @@
    fi
  
 # This is needed for automatic patch generation: sensors code starts here
+  bool 'I2C mainboard interfaces' CONFIG_I2C_MAINBOARD 
+  if [ "$CONFIG_I2C_MAINBOARD" = "y" ]; then
+    dep_tristate '  Acer Labs ALI 1535' CONFIG_I2C_ALI1535 $CONFIG_I2C
+    dep_tristate '  Acer Labs ALI 1533 and 1543C' CONFIG_I2C_ALI15X3 $CONFIG_I2C
+    dep_tristate '  Apple Hydra Mac I/O' CONFIG_I2C_HYDRA $CONFIG_I2C_ALGOBIT
+    dep_tristate '  AMD 756/766/768/8111' CONFIG_I2C_AMD756 $CONFIG_I2C
+    dep_tristate '  AMD 8111 SMBus 2.0' CONFIG_I2C_AMD8111 $CONFIG_I2C
+    if [ "$CONFIG_ALPHA" = "y" ]; then
+      dep_tristate '  DEC Tsunami I2C interface' CONFIG_I2C_TSUNAMI $CONFIG_I2C_ALGOBIT
+    fi
+    dep_tristate '  Intel 82801AA, AB, BA, DB' CONFIG_I2C_I801 $CONFIG_I2C
+    dep_tristate '  Intel i810AA/AB/E and i815' CONFIG_I2C_I810 $CONFIG_I2C_ALGOBIT
+    dep_tristate '  Intel 82371AB PIIX4(E), 443MX, ServerWorks OSB4/CSB5, SMSC Victory66' CONFIG_I2C_PIIX4 $CONFIG_I2C
+    dep_tristate '  Nvidia Nforce2' CONFIG_I2C_NFORCE2 $CONFIG_I2C
+    dep_tristate '  SiS 5595' CONFIG_I2C_SIS5595 $CONFIG_I2C
+    dep_tristate '  SiS 630/730' CONFIG_I2C_SIS630 $CONFIG_I2C
+    dep_tristate '  SiS 645/961,645DX/961,735' CONFIG_I2C_SIS645 $CONFIG_I2C $CONFIG_HOTPLUG
+    dep_tristate '  Savage 4' CONFIG_I2C_SAVAGE4 $CONFIG_I2C_ALGOBIT
+    dep_tristate '  VIA Technologies, Inc. VT82C586B' CONFIG_I2C_VIA $CONFIG_I2C_ALGOBIT
+    dep_tristate '  VIA Technologies, Inc. VT596A/B, 686A/B, 8231, 8233, 8233A, 8235' CONFIG_I2C_VIAPRO $CONFIG_I2C
+    dep_tristate '  Voodoo3 I2C interface' CONFIG_I2C_VOODOO3 $CONFIG_I2C_ALGOBIT
+    dep_tristate '  Pseudo ISA adapter (for some hardware sensors)' CONFIG_I2C_ISA $CONFIG_I2C
+  fi
+
 # This is needed for automatic patch generation: sensors code ends here
 
    dep_tristate 'I2C device interface' CONFIG_I2C_CHARDEV $CONFIG_I2C
diff -urN --exclude-from=diff-exclude linux-2.4.27/drivers/i2c/i2c-adap-ibm_ocp.c linux-2.4.27-leo/drivers/i2c/i2c-adap-ibm_ocp.c
--- linux-2.4.27/drivers/i2c/i2c-adap-ibm_ocp.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.27-leo/drivers/i2c/i2c-adap-ibm_ocp.c	2004-09-20 21:34:38.000000000 +0100
@@ -0,0 +1,346 @@
+/*
+   -------------------------------------------------------------------------
+   i2c-adap-ibm_ocp.c i2c-hw access for the IIC peripheral on the IBM PPC 405
+   -------------------------------------------------------------------------
+  
+   Ian DaSilva, MontaVista Software, Inc.
+   idasilva@mvista.com or source@mvista.com
+
+   Copyright 2000 MontaVista Software Inc.
+
+   Changes made to support the IIC peripheral on the IBM PPC 405 
+
+
+   ----------------------------------------------------------------------------
+   This file was highly leveraged from i2c-elektor.c, which was created
+   by Simon G. Vogl and Hans Berglund:
+
+ 
+     Copyright (C) 1995-97 Simon G. Vogl
+                   1998-99 Hans Berglund
+
+   With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
+   Frodo Looijaard <frodol@dds.nl>
+
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   ----------------------------------------------------------------------------
+
+   History: 01/20/12 - Armin
+   	akuster@mvista.com
+   	ported up to 2.4.16+	
+
+   Version 02/03/25 - Armin
+       converted to ocp format
+       removed commented out or #if 0 code
+
+   TODO: convert to ocp_register
+         add PM hooks
+
+*/
+
+
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-ibm_ocp.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/ocp.h>
+
+/*
+ * This next section is configurable, and it is used to set the number
+ * of i2c controllers in the system.  The default number of instances is 1,
+ * however, this should be changed to reflect your system's configuration.
+ */ 
+
+/*
+ * The STB03xxx, with a PPC405 core, has two i2c controllers.
+ */
+//(sizeof(IIC_ADDR)/sizeof(struct iic_regs))
+extern iic_t *IIC_ADDR[];
+static struct iic_ibm iic_ibmocp_adaps[IIC_NUMS][5];
+
+static struct i2c_algo_iic_data *iic_ibmocp_data[IIC_NUMS];
+static struct i2c_adapter *iic_ibmocp_ops[IIC_NUMS];
+
+static int i2c_debug=0;
+static wait_queue_head_t iic_wait[IIC_NUMS];
+static int iic_pending;
+static spinlock_t irq_driver_lock = SPIN_LOCK_UNLOCKED;
+
+
+/* ----- global defines -----------------------------------------------	*/
+#define DEB(x)	if (i2c_debug>=1) x
+#define DEB2(x) if (i2c_debug>=2) x
+#define DEB3(x) if (i2c_debug>=3) x
+#define DEBE(x)	x	/* error messages 				*/
+
+/* ----- local functions ----------------------------------------------	*/
+
+//
+// Description: Write a byte to IIC hardware
+//
+static void iic_ibmocp_setbyte(void *data, int ctl, int val)
+{
+   // writeb resolves to a write to the specified memory location
+   // plus a call to eieio.  eieio ensures that all instructions
+   // preceding it are completed before any further stores are
+   // completed.
+   // Delays at this level (to protect writes) are not needed here.
+   writeb(val, ctl);
+}
+
+
+//
+// Description: Read a byte from IIC hardware
+//
+static int iic_ibmocp_getbyte(void *data, int ctl)
+{
+   int val;
+
+   val = readb(ctl);
+   return (val);
+}
+
+
+//
+// Description: Return our slave address.  This is the address
+// put on the I2C bus when another master on the bus wants to address us
+// as a slave
+//
+static int iic_ibmocp_getown(void *data)
+{
+   return(((struct iic_ibm *)(data))->iic_own);
+}
+
+
+//
+// Description: Return the clock rate
+//
+static int iic_ibmocp_getclock(void *data)
+{
+   return(((struct iic_ibm *)(data))->iic_clock);
+}
+
+
+
+//
+// Description:  Put this process to sleep.  We will wake up when the
+// IIC controller interrupts.
+//
+static void iic_ibmocp_waitforpin(void *data) {
+
+   int timeout = 2;
+   struct iic_ibm *priv_data = data;
+
+   //
+   // If interrupts are enabled (which they are), then put the process to
+   // sleep.  This process will be awakened by two events -- either the
+   // the IIC peripheral interrupts or the timeout expires. 
+   //
+   if (priv_data->iic_irq > 0) {
+      spin_lock_irq(&irq_driver_lock);
+      if (iic_pending == 0) {
+  	 interruptible_sleep_on_timeout(&(iic_wait[priv_data->index]), timeout*HZ );
+      } else
+ 	 iic_pending = 0;
+      spin_unlock_irq(&irq_driver_lock);
+   } else {
+      //
+      // If interrupts are not enabled then delay for a reasonable amount
+      // of time and return.  We expect that by time we return to the calling
+      // function that the IIC has finished our requested transaction and
+      // the status bit reflects this.
+      //
+      // udelay is probably not the best choice for this since it is
+      // the equivalent of a busy wait
+      //
+      udelay(100);
+   }
+   //printk("iic_ibmocp_waitforpin: exitting\n");
+}
+
+
+//
+// Description: The registered interrupt handler
+//
+static void iic_ibmocp_handler(int this_irq, void *dev_id, struct pt_regs *regs) 
+{
+   int ret;
+   struct iic_regs *iic;
+   struct iic_ibm *priv_data = dev_id;
+   iic = (struct iic_regs *) priv_data->iic_base;
+   iic_pending = 1;
+   DEB2(printk("iic_ibmocp_handler: in interrupt handler\n"));
+   // Read status register
+   ret = readb((int) &(iic->sts));
+   DEB2(printk("iic_ibmocp_handler: status = %x\n", ret));
+   // Clear status register.  See IBM PPC 405 reference manual for details
+   writeb(0x0a, (int) &(iic->sts));
+   wake_up_interruptible(&(iic_wait[priv_data->index]));
+}
+
+
+//
+// Description: This function is very hardware dependent.  First, we lock
+// the region of memory where out registers exist.  Next, we request our
+// interrupt line and register its associated handler.  Our IIC peripheral
+// uses interrupt number 2, as specified by the 405 reference manual.
+//
+static int iic_hw_resrc_init(int instance)
+{
+
+   DEB(printk("iic_hw_resrc_init: Physical Base address: 0x%x\n", (u32) IIC_ADDR[instance] ));
+   iic_ibmocp_adaps[instance]->iic_base = (u32)ioremap((unsigned long)IIC_ADDR[instance],PAGE_SIZE);
+
+   DEB(printk("iic_hw_resrc_init: ioremapped base address: 0x%x\n", iic_ibmocp_adaps[instance]->iic_base));
+
+   if (iic_ibmocp_adaps[instance]->iic_irq > 0) {
+	
+      if (request_irq(iic_ibmocp_adaps[instance]->iic_irq, iic_ibmocp_handler,
+       0, "IBM OCP IIC", iic_ibmocp_adaps[instance]) < 0) {
+         printk(KERN_ERR "iic_hw_resrc_init: Request irq%d failed\n",
+          iic_ibmocp_adaps[instance]->iic_irq);
+	 iic_ibmocp_adaps[instance]->iic_irq = 0;
+      } else {
+         DEB3(printk("iic_hw_resrc_init: Enabled interrupt\n"));
+      }
+   }
+   return 0;
+}
+
+
+//
+// Description: Release irq and memory
+//
+static void iic_ibmocp_release(void)
+{
+   int i;
+
+   for(i=0; i<IIC_NUMS; i++) {
+      struct iic_ibm *priv_data = (struct iic_ibm *)iic_ibmocp_data[i]->data;
+      if (priv_data->iic_irq > 0) {
+         disable_irq(priv_data->iic_irq);
+         free_irq(priv_data->iic_irq, 0);
+      }
+      kfree(iic_ibmocp_data[i]);
+      kfree(iic_ibmocp_ops[i]);
+   }
+}
+
+
+//
+// Description: Called when the module is loaded.  This function starts the
+// cascade of calls up through the heirarchy of i2c modules (i.e. up to the
+//  algorithm layer and into to the core layer)
+//
+static int __init iic_ibmocp_init(void) 
+{
+   int i;
+
+   printk(KERN_INFO "iic_ibmocp_init: IBM on-chip iic adapter module\n");
+ 
+   for(i=0; i<IIC_NUMS; i++) {
+      iic_ibmocp_data[i] = kmalloc(sizeof(struct i2c_algo_iic_data),GFP_KERNEL);
+      if(iic_ibmocp_data[i] == NULL) {
+         return -ENOMEM;
+      }
+      memset(iic_ibmocp_data[i], 0, sizeof(struct i2c_algo_iic_data));
+      
+      switch (i) {
+	      case 0:
+	       iic_ibmocp_adaps[i]->iic_irq = IIC_IRQ(0);
+	      break;
+	      case 1:
+	       iic_ibmocp_adaps[i]->iic_irq = IIC_IRQ(1);
+	      break;
+      }
+      iic_ibmocp_adaps[i]->iic_clock = IIC_CLOCK;
+      iic_ibmocp_adaps[i]->iic_own = IIC_OWN; 
+      iic_ibmocp_adaps[i]->index = i;
+ 
+      DEB(printk("irq %x\n", iic_ibmocp_adaps[i]->iic_irq));
+      DEB(printk("clock %x\n", iic_ibmocp_adaps[i]->iic_clock));
+      DEB(printk("own %x\n", iic_ibmocp_adaps[i]->iic_own));
+      DEB(printk("index %x\n", iic_ibmocp_adaps[i]->index));
+
+
+      iic_ibmocp_data[i]->data = (struct iic_regs *)iic_ibmocp_adaps[i]; 
+      iic_ibmocp_data[i]->setiic = iic_ibmocp_setbyte;
+      iic_ibmocp_data[i]->getiic = iic_ibmocp_getbyte;
+      iic_ibmocp_data[i]->getown = iic_ibmocp_getown;
+      iic_ibmocp_data[i]->getclock = iic_ibmocp_getclock;
+      iic_ibmocp_data[i]->waitforpin = iic_ibmocp_waitforpin;
+      iic_ibmocp_data[i]->udelay = 80;
+      iic_ibmocp_data[i]->mdelay = 80;
+      iic_ibmocp_data[i]->timeout = HZ;
+      
+            iic_ibmocp_ops[i] = kmalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
+      if(iic_ibmocp_ops[i] == NULL) {
+         return -ENOMEM;
+      }
+      memset(iic_ibmocp_ops[i], 0, sizeof(struct i2c_adapter));
+      strcpy(iic_ibmocp_ops[i]->name, "IBM OCP IIC adapter");
+      iic_ibmocp_ops[i]->owner = THIS_MODULE;
+      iic_ibmocp_ops[i]->id = I2C_HW_OCP;
+      iic_ibmocp_ops[i]->algo = NULL;
+      iic_ibmocp_ops[i]->algo_data = iic_ibmocp_data[i];
+       
+      
+      init_waitqueue_head(&(iic_wait[i]));
+      if (iic_hw_resrc_init(i) == 0) {
+         if (i2c_ocp_add_bus(iic_ibmocp_ops[i]) < 0)
+         return -ENODEV;
+      } else {
+         return -ENODEV;
+      }
+      DEB(printk(KERN_INFO "iic_ibmocp_init: found device at %#x.\n\n", iic_ibmocp_adaps[i]->iic_base));
+   }
+   return 0;
+}
+
+
+static void __exit iic_ibmocp_exit(void)
+{
+   int i;
+
+   for(i=0; i<IIC_NUMS; i++) {
+      i2c_ocp_del_bus(iic_ibmocp_ops[i]);
+   }
+   iic_ibmocp_release();
+}
+
+//
+// If modules is NOT defined when this file is compiled, then the MODULE_*
+// macros will resolve to nothing
+//
+MODULE_AUTHOR("MontaVista Software <www.mvista.com>");
+MODULE_DESCRIPTION("I2C-Bus adapter routines for PPC 405 IIC bus adapter");
+MODULE_LICENSE("GPL");
+
+MODULE_PARM(base, "i");
+MODULE_PARM(irq, "i");
+MODULE_PARM(clock, "i");
+MODULE_PARM(own, "i");
+MODULE_PARM(i2c_debug,"i");
+
+
+module_init(iic_ibmocp_init);
+module_exit(iic_ibmocp_exit); 
diff -urN --exclude-from=diff-exclude linux-2.4.27/drivers/i2c/i2c-algo-8xx.c linux-2.4.27-leo/drivers/i2c/i2c-algo-8xx.c
--- linux-2.4.27/drivers/i2c/i2c-algo-8xx.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.27-leo/drivers/i2c/i2c-algo-8xx.c	2004-09-20 21:34:38.000000000 +0100
@@ -0,0 +1,616 @@
+/*
+ * i2c-algo-8xx.c i2x driver algorithms for MPC8XX CPM
+ * Copyright (c) 1999 Dan Malek (dmalek@jlc.net).
+ *
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * moved into proper i2c interface; separated out platform specific 
+ * parts into i2c-rpx.c
+ * Brad Parker (brad@heeltoe.com)
+ */
+
+// XXX todo
+// timeout sleep?
+
+/* $Id: i2c-algo-8xx.c,v 1.14 2003/07/25 07:56:42 khali Exp $ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-8xx.h>
+#include <asm/mpc8xx.h>
+#include <asm/commproc.h>
+
+
+#define CPM_MAX_READ	513
+/* #define I2C_CHIP_ERRATA */ /* Try uncomment this if you have an older CPU(earlier than rev D4) */
+static wait_queue_head_t iic_wait;
+static ushort r_tbase, r_rbase;
+
+int cpm_debug = 0;
+
+static  void
+cpm_iic_interrupt(void *dev_id, struct pt_regs *regs)
+{
+	volatile i2c8xx_t *i2c = (i2c8xx_t *)dev_id;
+	if (cpm_debug > 1)
+		printk("cpm_iic_interrupt(dev_id=%p)\n", dev_id);
+#if 0
+	/* Chip errata, clear enable. This is not needed on rev D4 CPUs */
+        /* This should probably be removed and replaced by I2C_CHIP_ERRATA stuff */
+        /* Someone with a buggy CPU needs to confirm that */
+	i2c->i2c_i2mod &= ~1;
+#endif
+	/* Clear interrupt.
+	*/
+	i2c->i2c_i2cer = 0xff;
+
+	/* Get 'me going again.
+	*/
+	wake_up_interruptible(&iic_wait);
+}
+
+static void
+cpm_iic_init(struct i2c_algo_8xx_data *cpm)
+{
+	volatile iic_t		*iip = cpm->iip;
+	volatile i2c8xx_t	*i2c = cpm->i2c;
+	unsigned char brg;
+	bd_t *bd = (bd_t *)__res;
+
+	if (cpm_debug) printk(KERN_DEBUG "cpm_iic_init()\n");
+
+	/* Initialize the parameter ram.
+	 * We need to make sure many things are initialized to zero,
+	 * especially in the case of a microcode patch.
+	 */
+	iip->iic_rstate = 0;
+	iip->iic_rdp = 0;
+	iip->iic_rbptr = 0;
+	iip->iic_rbc = 0;
+	iip->iic_rxtmp = 0;
+	iip->iic_tstate = 0;
+	iip->iic_tdp = 0;
+	iip->iic_tbptr = 0;
+	iip->iic_tbc = 0;
+	iip->iic_txtmp = 0;
+
+	/* Set up the IIC parameters in the parameter ram.
+	*/
+	iip->iic_tbase = r_tbase = cpm->dp_addr;
+	iip->iic_rbase = r_rbase = cpm->dp_addr + sizeof(cbd_t)*2;
+
+	iip->iic_tfcr = SMC_EB;
+	iip->iic_rfcr = SMC_EB;
+
+	/* Set maximum receive size.
+	*/
+	iip->iic_mrblr = CPM_MAX_READ;
+
+	/* Initialize Tx/Rx parameters.
+	*/
+	if (cpm->reloc == 0) {
+		volatile cpm8xx_t *cp = cpm->cp;
+
+		cp->cp_cpcr =
+			mk_cr_cmd(CPM_CR_CH_I2C, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+		while (cp->cp_cpcr & CPM_CR_FLG);
+	} else {
+		iip->iic_rbptr = iip->iic_rbase;
+		iip->iic_tbptr = iip->iic_tbase;
+		iip->iic_rstate	= 0;
+		iip->iic_tstate	= 0;
+	}
+
+	/* Select an arbitrary address.  Just make sure it is unique.
+	*/
+	i2c->i2c_i2add = 0xfe;
+
+	/* Make clock run at 60 KHz.
+	*/
+	brg = (unsigned char) (bd->bi_intfreq/(32*2*60000) -3);
+	i2c->i2c_i2brg = brg;
+
+	i2c->i2c_i2mod = 0x00; 
+	i2c->i2c_i2com = 0x01; /* Master mode */
+
+	/* Disable interrupts.
+	*/
+	i2c->i2c_i2cmr = 0;
+	i2c->i2c_i2cer = 0xff;
+
+	init_waitqueue_head(&iic_wait);
+
+	/* Install interrupt handler.
+	*/
+	if (cpm_debug) {
+		printk ("%s[%d] Install ISR for IRQ %d\n",
+			__func__,__LINE__, CPMVEC_I2C);
+	}
+	(*cpm->setisr)(CPMVEC_I2C, cpm_iic_interrupt, (void *)i2c);
+}
+
+
+static int
+cpm_iic_shutdown(struct i2c_algo_8xx_data *cpm)
+{
+	volatile i2c8xx_t *i2c = cpm->i2c;
+
+	/* Shut down IIC.
+	*/
+	i2c->i2c_i2mod &= ~1;
+	i2c->i2c_i2cmr = 0;
+	i2c->i2c_i2cer = 0xff;
+
+	return(0);
+}
+
+static void 
+cpm_reset_iic_params(volatile iic_t *iip)
+{
+	iip->iic_tbase = r_tbase;
+	iip->iic_rbase = r_rbase;
+
+	iip->iic_tfcr = SMC_EB;
+	iip->iic_rfcr = SMC_EB;
+
+	iip->iic_mrblr = CPM_MAX_READ;
+
+	iip->iic_rstate = 0;
+	iip->iic_rdp = 0;
+	iip->iic_rbptr = iip->iic_rbase;
+	iip->iic_rbc = 0;
+	iip->iic_rxtmp = 0;
+	iip->iic_tstate = 0;
+	iip->iic_tdp = 0;
+	iip->iic_tbptr = iip->iic_tbase;
+	iip->iic_tbc = 0;
+	iip->iic_txtmp = 0;
+}
+
+#define BD_SC_NAK		((ushort)0x0004) /* NAK - did not respond */
+#define BD_SC_OV		((ushort)0x0002) /* OV - receive overrun */
+#define CPM_CR_CLOSE_RXBD	((ushort)0x0007)
+
+static void force_close(struct i2c_algo_8xx_data *cpm)
+{
+	volatile i2c8xx_t *i2c = cpm->i2c;
+	if (cpm->reloc == 0) { /* micro code disabled */
+		volatile cpm8xx_t *cp = cpm->cp;
+
+		if (cpm_debug) printk("force_close()\n");
+		cp->cp_cpcr =
+			mk_cr_cmd(CPM_CR_CH_I2C, CPM_CR_CLOSE_RXBD) |
+			CPM_CR_FLG;
+
+		while (cp->cp_cpcr & CPM_CR_FLG);
+	}
+	i2c->i2c_i2cmr = 0x00;	/* Disable all interrupts */
+	i2c->i2c_i2cer = 0xff; 
+}
+
+
+/* Read from IIC...
+ * abyte = address byte, with r/w flag already set
+ */
+static int
+cpm_iic_read(struct i2c_algo_8xx_data *cpm, u_char abyte, char *buf, int count)
+{
+	volatile iic_t *iip = cpm->iip;
+	volatile i2c8xx_t *i2c = cpm->i2c;
+	volatile cpm8xx_t *cp = cpm->cp;
+	volatile cbd_t	*tbdf, *rbdf;
+	u_char *tb;
+	unsigned long flags, tmo;
+
+	if (count >= CPM_MAX_READ)
+		return -EINVAL;
+
+	/* check for and use a microcode relocation patch */
+	if (cpm->reloc) {
+		cpm_reset_iic_params(iip);
+	}
+
+	tbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_tbase];
+	rbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_rbase];
+
+	/* To read, we need an empty buffer of the proper length.
+	 * All that is used is the first byte for address, the remainder
+	 * is just used for timing (and doesn't really have to exist).
+	 */
+	tb = cpm->temp;
+	tb = (u_char *)(((uint)tb + 15) & ~15);
+	tb[0] = abyte;		/* Device address byte w/rw flag */
+
+	flush_dcache_range((unsigned long) tb, (unsigned long) (tb+1));
+
+	if (cpm_debug) printk("cpm_iic_read(abyte=0x%x)\n", abyte);
+
+	tbdf->cbd_bufaddr = __pa(tb);
+	tbdf->cbd_datlen = count + 1;
+	tbdf->cbd_sc =
+		BD_SC_READY | BD_SC_LAST |
+		BD_SC_WRAP | BD_IIC_START;
+
+	iip->iic_mrblr = count +1; /* prevent excessive read, +1
+				      is needed otherwise will the
+				      RXB interrupt come too early */
+
+	/* flush will invalidate too. */
+	flush_dcache_range((unsigned long) buf, (unsigned long) (buf+count));
+
+	rbdf->cbd_datlen = 0;
+	rbdf->cbd_bufaddr = __pa(buf);
+	rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP| BD_SC_INTRPT;
+	if(count > 16){
+		/* Chip bug, set enable here */
+		local_irq_save(flags);
+		i2c->i2c_i2cmr = 0x13;	/* Enable some interupts */
+		i2c->i2c_i2cer = 0xff;
+		i2c->i2c_i2mod |= 1;	/* Enable */
+		i2c->i2c_i2com |= 0x80;	/* Begin transmission */
+
+		/* Wait for IIC transfer */
+		tmo = interruptible_sleep_on_timeout(&iic_wait,1*HZ);
+		local_irq_restore(flags);
+	} else { /* busy wait for small transfers, its faster */
+		i2c->i2c_i2cmr = 0x00;	/* Disable I2C interupts */
+		i2c->i2c_i2cer = 0xff;
+		i2c->i2c_i2mod |= 1;	/* Enable */
+		i2c->i2c_i2com |= 0x80;	/* Begin transmission */
+		tmo = jiffies + 1*HZ; 
+		while(!(i2c->i2c_i2cer & 0x11 || time_after(jiffies, tmo))); /* Busy wait, with a timeout */
+	}		
+
+	if (signal_pending(current) || !tmo){
+		force_close(cpm);
+		if(cpm_debug) 
+			printk("IIC read: timeout!\n");
+		return -EIO;
+	}
+#ifdef I2C_CHIP_ERRATA
+	/* Chip errata, clear enable. This is not needed on rev D4 CPUs.
+	 Disabling I2C too early may cause too short stop condition */
+	udelay(4);
+	i2c->i2c_i2mod &= ~1;
+#endif
+	if (cpm_debug) {
+		printk("tx sc %04x, rx sc %04x\n",
+		       tbdf->cbd_sc, rbdf->cbd_sc);
+	}
+
+	if (tbdf->cbd_sc & BD_SC_READY) {
+		printk("IIC read; complete but tbuf ready\n");
+		force_close(cpm);
+		printk("tx sc %04x, rx sc %04x\n",
+		       tbdf->cbd_sc, rbdf->cbd_sc);
+	}
+
+	if (tbdf->cbd_sc & BD_SC_NAK) {
+		if (cpm_debug)
+			printk("IIC read; no ack\n");
+		return -EREMOTEIO;
+	}
+
+	if (rbdf->cbd_sc & BD_SC_EMPTY) {
+		/* force_close(cpm); */
+		if (cpm_debug){
+			printk("IIC read; complete but rbuf empty\n");
+			printk("tx sc %04x, rx sc %04x\n",
+			       tbdf->cbd_sc, rbdf->cbd_sc);
+		}
+		return -EREMOTEIO;
+	}
+
+	if (rbdf->cbd_sc & BD_SC_OV) {
+		if (cpm_debug)
+			printk("IIC read; Overrun\n");
+		return -EREMOTEIO;;
+	}
+
+	if (cpm_debug) printk("read %d bytes\n", rbdf->cbd_datlen);
+
+	if (rbdf->cbd_datlen < count) {
+		if (cpm_debug)
+			printk("IIC read; short, wanted %d got %d\n",
+			       count, rbdf->cbd_datlen);
+		return 0;
+	}
+
+	return count;
+}
+
+/* Write to IIC...
+ * addr = address byte, with r/w flag already set
+ */
+static int
+cpm_iic_write(struct i2c_algo_8xx_data *cpm, u_char abyte, char *buf,int count)
+{
+	volatile iic_t *iip = cpm->iip;
+	volatile i2c8xx_t *i2c = cpm->i2c;
+	volatile cpm8xx_t *cp = cpm->cp;
+	volatile cbd_t	*tbdf;
+	u_char *tb;
+	unsigned long flags, tmo;
+
+	/* check for and use a microcode relocation patch */
+	if (cpm->reloc) {
+		cpm_reset_iic_params(iip);
+	}
+	tb = cpm->temp;
+	tb = (u_char *)(((uint)tb + 15) & ~15);
+	*tb = abyte;		/* Device address byte w/rw flag */
+
+	flush_dcache_range((unsigned long) tb, (unsigned long) (tb+1));
+	flush_dcache_range((unsigned long) buf, (unsigned long) (buf+count));
+
+	if (cpm_debug) printk("cpm_iic_write(abyte=0x%x)\n", abyte);
+
+	/* set up 2 descriptors */
+	tbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_tbase];
+
+	tbdf[0].cbd_bufaddr = __pa(tb);
+	tbdf[0].cbd_datlen = 1;
+	tbdf[0].cbd_sc = BD_SC_READY | BD_IIC_START;
+
+	tbdf[1].cbd_bufaddr = __pa(buf);
+	tbdf[1].cbd_datlen = count;
+	tbdf[1].cbd_sc = BD_SC_READY | BD_SC_INTRPT | BD_SC_LAST | BD_SC_WRAP;
+
+	if(count > 16){
+		/* Chip bug, set enable here */
+		local_irq_save(flags);
+		i2c->i2c_i2cmr = 0x13;	/* Enable some interupts */
+		i2c->i2c_i2cer = 0xff;
+		i2c->i2c_i2mod |= 1;	/* Enable */
+		i2c->i2c_i2com |= 0x80;	/* Begin transmission */
+		
+		/* Wait for IIC transfer */
+		tmo = interruptible_sleep_on_timeout(&iic_wait,1*HZ);
+		local_irq_restore(flags);
+	} else {  /* busy wait for small transfers, its faster */
+		i2c->i2c_i2cmr = 0x00;	/* Disable I2C interupts */
+		i2c->i2c_i2cer = 0xff;
+		i2c->i2c_i2mod |= 1;	/* Enable */
+		i2c->i2c_i2com |= 0x80;	/* Begin transmission */
+		tmo = jiffies + 1*HZ; 
+		while(!(i2c->i2c_i2cer & 0x12 || time_after(jiffies, tmo))); /* Busy wait, with a timeout */
+	}		
+
+	if (signal_pending(current) || !tmo){
+		force_close(cpm);
+		if(cpm_debug && !tmo) 
+			printk("IIC write: timeout!\n");
+		return -EIO;
+	}
+	
+#if I2C_CHIP_ERRATA
+	/* Chip errata, clear enable. This is not needed on rev D4 CPUs.
+	 Disabling I2C too early may cause too short stop condition */
+	udelay(4);
+	i2c->i2c_i2mod &= ~1;
+#endif
+	if (cpm_debug) {
+		printk("tx0 sc %04x, tx1 sc %04x\n",
+		       tbdf[0].cbd_sc, tbdf[1].cbd_sc);
+	}
+
+	if (tbdf->cbd_sc & BD_SC_NAK) {
+		if (cpm_debug) 
+			printk("IIC write; no ack\n");
+		return 0;
+	}
+	  
+	if (tbdf->cbd_sc & BD_SC_READY) {
+		if (cpm_debug)
+			printk("IIC write; complete but tbuf ready\n");
+		return 0;
+	}
+
+	return count;
+}
+
+/* See if an IIC address exists..
+ * addr = 7 bit address, unshifted
+ */
+static int
+cpm_iic_tryaddress(struct i2c_algo_8xx_data *cpm, int addr)
+{
+	volatile iic_t *iip = cpm->iip;
+	volatile i2c8xx_t *i2c = cpm->i2c;
+	volatile cpm8xx_t *cp = cpm->cp;
+	volatile cbd_t *tbdf, *rbdf;
+	u_char *tb;
+	unsigned long flags, len, tmo;
+
+	if (cpm_debug > 1)
+		printk("cpm_iic_tryaddress(cpm=%p,addr=%d)\n", cpm, addr);
+
+	/* check for and use a microcode relocation patch */
+	if (cpm->reloc) {
+		cpm_reset_iic_params(iip);
+	}
+
+	if (cpm_debug && addr == 0) {
+		printk("iip %p, dp_addr 0x%x\n", cpm->iip, cpm->dp_addr);
+		printk("iic_tbase %d, r_tbase %d\n", iip->iic_tbase, r_tbase);
+	}
+
+	tbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_tbase];
+	rbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_rbase];
+
+	tb = cpm->temp;
+	tb = (u_char *)(((uint)tb + 15) & ~15);
+
+	/* do a simple read */
+	tb[0] = (addr << 1) | 1;	/* device address (+ read) */
+	len = 2;
+
+	flush_dcache_range((unsigned long) tb, (unsigned long) (tb+2));
+
+	tbdf->cbd_bufaddr = __pa(tb);
+	tbdf->cbd_datlen = len;
+	tbdf->cbd_sc =
+		BD_SC_READY | BD_SC_LAST |
+		BD_SC_WRAP | BD_IIC_START;
+
+	rbdf->cbd_datlen = 0;
+	rbdf->cbd_bufaddr = __pa(tb+2);
+	rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP | BD_SC_INTRPT;
+
+	local_irq_save(flags);
+	i2c->i2c_i2cmr = 0x13;	/* Enable some interupts */
+	i2c->i2c_i2cer = 0xff;
+	i2c->i2c_i2mod |= 1;	/* Enable */
+	i2c->i2c_i2com |= 0x80;	/* Begin transmission */
+
+	if (cpm_debug > 1) printk("about to sleep\n");
+
+	/* wait for IIC transfer */
+	tmo = interruptible_sleep_on_timeout(&iic_wait,1*HZ);
+	local_irq_restore(flags);
+
+#ifdef I2C_CHIP_ERRATA
+	/* Chip errata, clear enable. This is not needed on rev D4 CPUs.
+	 Disabling I2C too early may cause too short stop condition */
+	udelay(4);
+	i2c->i2c_i2mod &= ~1;
+#endif
+
+	if (signal_pending(current) || !tmo){
+		force_close(cpm);
+		if(cpm_debug && !tmo) 
+			printk("IIC tryaddress: timeout!\n");
+		return -EIO;
+	}
+
+	if (cpm_debug > 1) printk("back from sleep\n");
+
+	if (tbdf->cbd_sc & BD_SC_NAK) {
+		if (cpm_debug > 1) printk("IIC try; no ack\n");
+		return 0;
+	}
+	  
+	if (tbdf->cbd_sc & BD_SC_READY) {
+		printk("IIC try; complete but tbuf ready\n");
+	}
+	
+	return 1;
+}
+
+static int cpm_xfer(struct i2c_adapter *adap,
+		    struct i2c_msg msgs[], 
+		    int num)
+{
+	struct i2c_algo_8xx_data *cpm = adap->algo_data;
+	struct i2c_msg *pmsg;
+	int i, ret;
+	u_char addr;
+    
+	for (i = 0; i < num; i++) {
+		pmsg = &msgs[i];
+
+		if (cpm_debug)
+			printk("i2c-algo-8xx.o: "
+			       "#%d addr=0x%x flags=0x%x len=%d\n buf=%lx\n",
+			       i, pmsg->addr, pmsg->flags, pmsg->len, (unsigned long)pmsg->buf);
+
+		addr = pmsg->addr << 1;
+		if (pmsg->flags & I2C_M_RD )
+			addr |= 1;
+		if (pmsg->flags & I2C_M_REV_DIR_ADDR )
+			addr ^= 1;
+    
+		if (!(pmsg->flags & I2C_M_NOSTART)) {
+		}
+		if (pmsg->flags & I2C_M_RD ) {
+			/* read bytes into buffer*/
+			ret = cpm_iic_read(cpm, addr, pmsg->buf, pmsg->len);
+			if (cpm_debug)
+				printk("i2c-algo-8xx.o: read %d bytes\n", ret);
+			if (ret < pmsg->len ) {
+				return (ret<0)? ret : -EREMOTEIO;
+			}
+		} else {
+			/* write bytes from buffer */
+			ret = cpm_iic_write(cpm, addr, pmsg->buf, pmsg->len);
+			if (cpm_debug)
+				printk("i2c-algo-8xx.o: wrote %d\n", ret);
+			if (ret < pmsg->len ) {
+				return (ret<0) ? ret : -EREMOTEIO;
+			}
+		}
+	}
+	return (num);
+}
+
+static u32 cpm_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | 
+	       I2C_FUNC_PROTOCOL_MANGLING; 
+}
+
+/* -----exported algorithm data: -------------------------------------	*/
+
+static struct i2c_algorithm cpm_algo = {
+	.owner		= THIS_MODULE,
+	.name		= "MPC8xx CPM algorithm",
+	.id		= I2C_ALGO_MPC8XX,
+	.master_xfer	= cpm_xfer,
+	.functionality	= cpm_func,
+};
+
+/* 
+ * registering functions to load algorithms at runtime 
+ */
+int i2c_8xx_add_bus(struct i2c_adapter *adap)
+{
+	int i;
+	struct i2c_algo_8xx_data *cpm = adap->algo_data;
+
+	if (cpm_debug)
+		printk("i2c-algo-8xx.o: hw routines for %s registered.\n",
+		       adap->name);
+
+	/* register new adapter to i2c module... */
+
+	adap->id |= cpm_algo.id;
+	adap->algo = &cpm_algo;
+
+	i2c_add_adapter(adap);
+	cpm_iic_init(cpm);
+}
+
+
+int i2c_8xx_del_bus(struct i2c_adapter *adap)
+{
+	struct i2c_algo_8xx_data *cpm = adap->algo_data;
+
+	cpm_iic_shutdown(cpm);
+
+	return i2c_del_adapter(adap);
+}
+
+EXPORT_SYMBOL(i2c_8xx_add_bus);
+EXPORT_SYMBOL(i2c_8xx_del_bus);
+
+MODULE_AUTHOR("Brad Parker <brad@heeltoe.com>");
+MODULE_DESCRIPTION("I2C-Bus MPC8XX algorithm");
+MODULE_LICENSE("GPL");
diff -urN --exclude-from=diff-exclude linux-2.4.27/drivers/i2c/i2c-algo-bit.c linux-2.4.27-leo/drivers/i2c/i2c-algo-bit.c
--- linux-2.4.27/drivers/i2c/i2c-algo-bit.c	2004-02-20 14:11:41.000000000 +0000
+++ linux-2.4.27-leo/drivers/i2c/i2c-algo-bit.c	2004-09-20 21:34:38.000000000 +0100
@@ -18,24 +18,22 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.		     */
 /* ------------------------------------------------------------------------- */
 
-/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
-   Frodo Looijaard <frodol@dds.nl> */
+/* With some changes from Frodo Looijaard <frodol@dds.nl>, Kyösti Mälkki
+   <kmalkki@cc.hut.fi> and Jean Delvare <khali@linux-fr.org> */
 
-/* $Id: i2c-algo-bit.c,v 1.30 2001/07/29 02:44:25 mds Exp $ */
+/* $Id: i2c-algo-bit.c,v 1.50 2003/12/22 20:03:39 khali Exp $ */
 
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/init.h>
-#include <asm/uaccess.h>
-#include <linux/ioport.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
-
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
 
+
 /* ----- global defines ----------------------------------------------- */
 #define DEB(x) if (i2c_debug>=1) x;
 #define DEB2(x) if (i2c_debug>=2) x;
@@ -43,27 +41,13 @@
 #define DEBPROTO(x) if (i2c_debug>=9) { x; }
  	/* debug the protocol by showing transferred bits */
 
-/* debugging - slow down transfer to have a look at the data .. 	*/
-/* I use this with two leds&resistors, each one connected to sda,scl 	*/
-/* respectively. This makes sure that the algorithm works. Some chips   */
-/* might not like this, as they have an internal timeout of some mils	*/
-/*
-#define SLO_IO      jif=jiffies;while(time_before_eq(jiffies, jif+i2c_table[minor].veryslow))\
-                        if (need_resched) schedule();
-*/
-
 
 /* ----- global variables ---------------------------------------------	*/
 
-#ifdef SLO_IO
-	int jif;
-#endif
-
 /* module parameters:
  */
 static int i2c_debug;
 static int bit_test;	/* see if the line-setting functions work	*/
-static int bit_scan;	/* have a look at what's hanging 'round		*/
 
 /* --- setting states on the bus with the right timing: ---------------	*/
 
@@ -88,9 +72,6 @@
 {
 	setscl(adap,0);
 	udelay(adap->udelay);
-#ifdef SLO_IO
-	SLO_IO
-#endif
 }
 
 /*
@@ -99,33 +80,35 @@
  */
 static inline int sclhi(struct i2c_algo_bit_data *adap)
 {
-	int start=jiffies;
+	int start;
 
 	setscl(adap,1);
 
-	udelay(adap->udelay);
-
 	/* Not all adapters have scl sense line... */
-	if (adap->getscl == NULL )
+	if (adap->getscl == NULL ) {
+		udelay(adap->udelay);
 		return 0;
+	}
 
- 	while (! getscl(adap) ) {	
+	start=jiffies;
+	while (! getscl(adap) ) {	
  		/* the hw knows how to read the clock line,
  		 * so we wait until it actually gets high.
  		 * This is safer as some chips may hold it low
  		 * while they are processing data internally. 
  		 */
-		setscl(adap,1);
 		if (time_after_eq(jiffies, start+adap->timeout)) {
 			return -ETIMEDOUT;
 		}
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
 		if (current->need_resched)
 			schedule();
+#else
+		cond_resched();
+#endif
 	}
 	DEBSTAT(printk(KERN_DEBUG "needed %ld jiffies\n", jiffies-start));
-#ifdef SLO_IO
-	SLO_IO
-#endif
+	udelay(adap->udelay);
 	return 0;
 } 
 
@@ -144,7 +127,7 @@
 	/* scl, sda may not be high */
 	DEBPROTO(printk(" Sr "));
 	setsda(adap,1);
-	setscl(adap,1);
+	sclhi(adap);
 	udelay(adap->udelay);
 	
 	sdalo(adap);
@@ -178,7 +161,6 @@
 	struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
 
 	/* assert: scl is low */
-	DEB2(printk(KERN_DEBUG " i2c_outb:%2.2X\n",c&0xff));
 	for ( i=7 ; i>=0 ; i-- ) {
 		sb = c & ( 1 << i );
 		setsda(adap,sb);
@@ -186,6 +168,7 @@
 		DEBPROTO(printk(KERN_DEBUG "%d",sb!=0));
 		if (sclhi(adap)<0) { /* timed out */
 			sdahi(adap); /* we don't want to block the net */
+			DEB2(printk(KERN_DEBUG " i2c_outb: 0x%02x, timeout at bit #%d\n", c&0xff, i));
 			return -ETIMEDOUT;
 		};
 		/* do arbitration here: 
@@ -196,11 +179,12 @@
 	}
 	sdahi(adap);
 	if (sclhi(adap)<0){ /* timeout */
+		DEB2(printk(KERN_DEBUG " i2c_outb: 0x%02x, timeout at ack\n", c&0xff));
 		return -ETIMEDOUT;
 	};
 	/* read ack: SDA should be pulled down by slave */
 	ack=getsda(adap);	/* ack: sda is pulled low ->success.	 */
-	DEB2(printk(KERN_DEBUG " i2c_outb: getsda() =  0x%2.2x\n", ~ack ));
+	DEB2(printk(KERN_DEBUG " i2c_outb: 0x%02x , getsda() = %d\n", c & 0xff, ack));
 
 	DEBPROTO( printk(KERN_DEBUG "[%2.2x]",c&0xff) );
 	DEBPROTO(if (0==ack){ printk(KERN_DEBUG " A ");} else printk(KERN_DEBUG " NA ") );
@@ -219,11 +203,10 @@
 	struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
 
 	/* assert: scl is low */
-	DEB2(printk(KERN_DEBUG "i2c_inb.\n"));
-
 	sdahi(adap);
 	for (i=0;i<8;i++) {
 		if (sclhi(adap)<0) { /* timeout */
+			DEB2(printk(KERN_DEBUG " i2c_inb: timeout at bit #%d\n", 7-i));
 			return -ETIMEDOUT;
 		};
 		indata *= 2;
@@ -232,6 +215,8 @@
 		scllo(adap);
 	}
 	/* assert: scl is low */
+	DEB2(printk(KERN_DEBUG "i2c_inb: 0x%02x\n", indata & 0xff));
+
 	DEBPROTO(printk(KERN_DEBUG " 0x%02x", indata & 0xff));
 	return (int) (indata & 0xff);
 }
@@ -242,71 +227,75 @@
  */
 static int test_bus(struct i2c_algo_bit_data *adap, char* name) {
 	int scl,sda;
+
+	if (adap->getscl==NULL)
+		printk(KERN_INFO "i2c-algo-bit.o: Testing SDA only, "
+			"SCL is not readable.\n");
+
 	sda=getsda(adap);
-	if (adap->getscl==NULL) {
-		printk("i2c-algo-bit.o: Warning: Adapter can't read from clock line - skipping test.\n");
-		return 0;		
-	}
-	scl=getscl(adap);
-	printk("i2c-algo-bit.o: Adapter: %s scl: %d  sda: %d -- testing...\n",
-	       name,getscl(adap),getsda(adap));
+	scl=(adap->getscl==NULL?1:getscl(adap));
+	printk(KERN_DEBUG "i2c-algo-bit.o: (0) scl=%d, sda=%d\n",scl,sda);
 	if (!scl || !sda ) {
-		printk("i2c-algo-bit.o: %s seems to be busy.\n",name);
+		printk(KERN_WARNING "i2c-algo-bit.o: %s seems to be busy.\n", name);
 		goto bailout;
 	}
+
 	sdalo(adap);
-	printk("i2c-algo-bit.o:1 scl: %d  sda: %d \n",getscl(adap),
-	       getsda(adap));
-	if ( 0 != getsda(adap) ) {
-		printk("i2c-algo-bit.o: %s SDA stuck high!\n",name);
-		sdahi(adap);
+	sda=getsda(adap);
+	scl=(adap->getscl==NULL?1:getscl(adap));
+	printk(KERN_DEBUG "i2c-algo-bit.o: (1) scl=%d, sda=%d\n",scl,sda);
+	if ( 0 != sda ) {
+		printk(KERN_WARNING "i2c-algo-bit.o: SDA stuck high!\n");
 		goto bailout;
 	}
-	if ( 0 == getscl(adap) ) {
-		printk("i2c-algo-bit.o: %s SCL unexpected low while pulling SDA low!\n",
-			name);
+	if ( 0 == scl ) {
+		printk(KERN_WARNING "i2c-algo-bit.o: SCL unexpected low "
+			"while pulling SDA low!\n");
 		goto bailout;
 	}		
+
 	sdahi(adap);
-	printk("i2c-algo-bit.o:2 scl: %d  sda: %d \n",getscl(adap),
-	       getsda(adap));
-	if ( 0 == getsda(adap) ) {
-		printk("i2c-algo-bit.o: %s SDA stuck low!\n",name);
-		sdahi(adap);
+	sda=getsda(adap);
+	scl=(adap->getscl==NULL?1:getscl(adap));
+	printk(KERN_DEBUG "i2c-algo-bit.o: (2) scl=%d, sda=%d\n",scl,sda);
+	if ( 0 == sda ) {
+		printk(KERN_WARNING "i2c-algo-bit.o: SDA stuck low!\n");
 		goto bailout;
 	}
-	if ( 0 == getscl(adap) ) {
-		printk("i2c-algo-bit.o: %s SCL unexpected low while SDA high!\n",
-		       name);
-	goto bailout;
+	if ( 0 == scl ) {
+		printk(KERN_WARNING "i2c-algo-bit.o: SCL unexpected low "
+			"while pulling SDA high!\n");
+		goto bailout;
 	}
+
 	scllo(adap);
-	printk("i2c-algo-bit.o:3 scl: %d  sda: %d \n",getscl(adap),
-	       getsda(adap));
-	if ( 0 != getscl(adap) ) {
-		printk("i2c-algo-bit.o: %s SCL stuck high!\n",name);
-		sclhi(adap);
+	sda=getsda(adap);
+	scl=(adap->getscl==NULL?0:getscl(adap));
+	printk(KERN_DEBUG "i2c-algo-bit.o: (3) scl=%d, sda=%d\n",scl,sda);
+	if ( 0 != scl ) {
+		printk(KERN_WARNING "i2c-algo-bit.o: SCL stuck high!\n");
 		goto bailout;
 	}
-	if ( 0 == getsda(adap) ) {
-		printk("i2c-algo-bit.o: %s SDA unexpected low while pulling SCL low!\n",
-			name);
+	if ( 0 == sda ) {
+		printk(KERN_WARNING "i2c-algo-bit.o: SDA unexpected low "
+			"while pulling SCL low!\n");
 		goto bailout;
 	}
+	
 	sclhi(adap);
-	printk("i2c-algo-bit.o:4 scl: %d  sda: %d \n",getscl(adap),
-	       getsda(adap));
-	if ( 0 == getscl(adap) ) {
-		printk("i2c-algo-bit.o: %s SCL stuck low!\n",name);
-		sclhi(adap);
+	sda=getsda(adap);
+	scl=(adap->getscl==NULL?1:getscl(adap));
+	printk(KERN_DEBUG "i2c-algo-bit.o: (4) scl=%d, sda=%d\n",scl,sda);
+	if ( 0 == scl ) {
+		printk(KERN_WARNING "i2c-algo-bit.o: SCL stuck low!\n");
 		goto bailout;
 	}
-	if ( 0 == getsda(adap) ) {
-		printk("i2c-algo-bit.o: %s SDA unexpected low while SCL high!\n",
-			name);
+	if ( 0 == sda ) {
+		printk(KERN_WARNING "i2c-algo-bit.o: SDA unexpected low "
+			"while pulling SCL high!\n");
 		goto bailout;
 	}
-	printk("i2c-algo-bit.o: %s passed test.\n",name);
+	printk(KERN_INFO "i2c-algo-bit.o: %s passed test.\n",name);
 	return 0;
 bailout:
 	sdahi(adap);
@@ -340,16 +329,21 @@
 		i2c_start(adap);
 		udelay(adap->udelay);
 	}
-	DEB2(if (i) printk(KERN_DEBUG "i2c-algo-bit.o: needed %d retries for %d\n",
-	                   i,addr));
+	DEB2(if (i)
+	     printk(KERN_DEBUG "i2c-algo-bit.o: Used %d tries to %s client at 0x%02x : %s\n",
+		    i+1, addr & 1 ? "read" : "write", addr>>1,
+		    ret==1 ? "success" : ret==0 ? "no ack" : "failed, timeout?" )
+	    );
 	return ret;
 }
 
-static int sendbytes(struct i2c_adapter *i2c_adap,const char *buf, int count)
+static int sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
 {
 	struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
 	char c;
-	const char *temp = buf;
+	const char *temp = msg->buf;
+	int count = msg->len;
+	unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK; 
 	int retval;
 	int wrcount=0;
 
@@ -358,7 +352,7 @@
 		DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: %s sendbytes: writing %2.2X\n",
 			    i2c_adap->name, c&0xff));
 		retval = i2c_outb(i2c_adap,c);
-		if (retval>0) {
+		if ((retval>0) || (nak_ok && (retval==0)))  { /* ok or ignored NAK */
 			count--; 
 			temp++;
 			wrcount++;
@@ -377,12 +371,18 @@
 	return wrcount;
 }
 
-static inline int readbytes(struct i2c_adapter *i2c_adap,char *buf,int count)
+static inline int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
 {
-	char *temp = buf;
 	int inval;
 	int rdcount=0;   	/* counts bytes read */
 	struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+	char *temp = msg->buf;
+	int count = msg->len;
+	int recv_len = 0;
+
+	/* Receive [Count] for I2C_SMBUS_BLOCK_DATA or I2C_SMBUS_BLOCK_PROC_CALL protocol */
+	if (msg->flags & I2C_M_RECV_LEN)
+		recv_len = 1;
 
 	while (count > 0) {
 		inval = i2c_inb(i2c_adap);
@@ -395,6 +395,20 @@
 			break;
 		}
 
+		if (recv_len) {
+			recv_len = 0;
+			/* [Count] should be between 1 and 31 (I2C_SMBUS_BLOCK_MAX - 1). */
+			if (inval > 0 && inval < I2C_SMBUS_BLOCK_MAX) {
+				count = inval + 1;	/* plus one for [Count] itself */
+				msg->len = count;
+				if (msg->flags & I2C_M_RECV_PEC)
+					count++; /* plus one for PEC */
+			} else {
+				printk(KERN_ERR "i2c-algo-bit.o: readbytes: bad block count (%d).\n", inval);
+				break;
+			}
+		}
+		
 		if ( count > 1 ) {		/* send ack */
 			sdalo(adap);
 			DEBPROTO(printk(" Am "));
@@ -419,31 +433,34 @@
  * try_address) and transmits the address in the necessary format to handle
  * reads, writes as well as 10bit-addresses.
  * returns:
- *  0 everything went okay, the chip ack'ed
+ *  0 everything went okay, the chip ack'ed, or IGNORE_NAK flag was set
  * -x an error occurred (like: -EREMOTEIO if the device did not answer, or
  *	-ETIMEDOUT, for example if the lines are stuck...) 
  */
-static inline int bit_doAddress(struct i2c_adapter *i2c_adap,
-                                struct i2c_msg *msg, int retries) 
+static inline int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) 
 {
 	unsigned short flags = msg->flags;
+	unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK;
 	struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
 
 	unsigned char addr;
-	int ret;
+	int ret, retries;
+
+	retries = nak_ok ? 0 : i2c_adap->retries;
+	
 	if ( (flags & I2C_M_TEN)  ) { 
 		/* a ten bit address */
 		addr = 0xf0 | (( msg->addr >> 7) & 0x03);
 		DEB2(printk(KERN_DEBUG "addr0: %d\n",addr));
 		/* try extended address code...*/
 		ret = try_address(i2c_adap, addr, retries);
-		if (ret!=1) {
+		if ((ret != 1) && !nak_ok)  {
 			printk(KERN_ERR "died at extended address code.\n");
 			return -EREMOTEIO;
 		}
 		/* the remaining 8 bit address */
 		ret = i2c_outb(i2c_adap,msg->addr & 0x7f);
-		if (ret != 1) {
+		if ((ret != 1) && !nak_ok) {
 			/* the chip did not ack / xmission error occurred */
 			printk(KERN_ERR "died at 2nd address code.\n");
 			return -EREMOTEIO;
@@ -453,7 +470,7 @@
 			/* okay, now switch into reading mode */
 			addr |= 0x01;
 			ret = try_address(i2c_adap, addr, retries);
-			if (ret!=1) {
+			if ((ret!=1) && !nak_ok) {
 				printk(KERN_ERR "died at extended address code.\n");
 				return -EREMOTEIO;
 			}
@@ -465,10 +482,10 @@
 		if (flags & I2C_M_REV_DIR_ADDR )
 			addr ^= 1;
 		ret = try_address(i2c_adap, addr, retries);
-		if (ret!=1) {
+		if ((ret!=1) && !nak_ok)
 			return -EREMOTEIO;
-		}
 	}
+
 	return 0;
 }
 
@@ -479,16 +496,18 @@
 	struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
 	
 	int i,ret;
+	unsigned short nak_ok;
 
 	i2c_start(adap);
 	for (i=0;i<num;i++) {
 		pmsg = &msgs[i];
+		nak_ok = pmsg->flags & I2C_M_IGNORE_NAK; 
 		if (!(pmsg->flags & I2C_M_NOSTART)) {
 			if (i) {
 				i2c_repstart(adap);
 			}
-			ret = bit_doAddress(i2c_adap,pmsg,i2c_adap->retries);
-			if (ret != 0) {
+			ret = bit_doAddress(i2c_adap, pmsg);
+			if ((ret != 0) && !nak_ok) {
 				DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: NAK from device addr %2.2x msg #%d\n",
 					msgs[i].addr,i));
 				return (ret<0) ? ret : -EREMOTEIO;
@@ -496,14 +515,14 @@
 		}
 		if (pmsg->flags & I2C_M_RD ) {
 			/* read bytes into buffer*/
-			ret = readbytes(i2c_adap,pmsg->buf,pmsg->len);
+			ret = readbytes(i2c_adap, pmsg);
 			DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: read %d bytes.\n",ret));
 			if (ret < pmsg->len ) {
 				return (ret<0)? ret : -EREMOTEIO;
 			}
 		} else {
 			/* write bytes from buffer */
-			ret = sendbytes(i2c_adap,pmsg->buf,pmsg->len);
+			ret = sendbytes(i2c_adap, pmsg);
 			DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: wrote %d bytes.\n",ret));
 			if (ret < pmsg->len ) {
 				return (ret<0) ? ret : -EREMOTEIO;
@@ -514,30 +533,25 @@
 	return num;
 }
 
-static int algo_control(struct i2c_adapter *adapter, 
-	unsigned int cmd, unsigned long arg)
-{
-	return 0;
-}
-
-static u32 bit_func(struct i2c_adapter *adap)
+static u32 bit_func(struct i2c_adapter *i2c_adap)
 {
 	return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | 
-	       I2C_FUNC_PROTOCOL_MANGLING;
+	       I2C_FUNC_PROTOCOL_MANGLING |
+	       I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
+	       I2C_FUNC_SMBUS_READ_BLOCK_DATA |
+	       I2C_FUNC_SMBUS_BLOCK_PROC_CALL_PEC |
+	       I2C_FUNC_SMBUS_READ_BLOCK_DATA_PEC;
 }
 
 
 /* -----exported algorithm data: -------------------------------------	*/
 
 static struct i2c_algorithm i2c_bit_algo = {
-	"Bit-shift algorithm",
-	I2C_ALGO_BIT,
-	bit_xfer,
-	NULL,
-	NULL,				/* slave_xmit		*/
-	NULL,				/* slave_recv		*/
-	algo_control,			/* ioctl		*/
-	bit_func,			/* functionality	*/
+	.owner		= THIS_MODULE,
+	.name		= "Bit-shift algorithm",
+	.id		= I2C_ALGO_BIT,
+	.master_xfer	= bit_xfer,
+	.functionality	= bit_func,
 };
 
 /* 
@@ -545,7 +559,6 @@
  */
 int i2c_bit_add_bus(struct i2c_adapter *adap)
 {
-	int i;
 	struct i2c_algo_bit_data *bit_adap = adap->algo_data;
 
 	if (bit_test) {
@@ -565,78 +578,26 @@
 	adap->timeout = 100;	/* default values, should	*/
 	adap->retries = 3;	/* be replaced by defines	*/
 
-	/* scan bus */
-	if (bit_scan) {
-		int ack;
-		printk(KERN_INFO " i2c-algo-bit.o: scanning bus %s.\n",
-		       adap->name);
-		for (i = 0x00; i < 0xff; i+=2) {
-			i2c_start(bit_adap);
-			ack = i2c_outb(adap,i);
-			i2c_stop(bit_adap);
-			if (ack>0) {
-				printk("(%02x)",i>>1); 
-			} else 
-				printk("."); 
-		}
-		printk("\n");
-	}
-
-#ifdef MODULE
-	MOD_INC_USE_COUNT;
-#endif
 	i2c_add_adapter(adap);
-
 	return 0;
 }
 
 
 int i2c_bit_del_bus(struct i2c_adapter *adap)
 {
-	int res;
-
-	if ((res = i2c_del_adapter(adap)) < 0)
-		return res;
-
-	DEB2(printk("i2c-algo-bit.o: adapter unregistered: %s\n",adap->name));
-
-#ifdef MODULE
-	MOD_DEC_USE_COUNT;
-#endif
-	return 0;
-}
-
-int __init i2c_algo_bit_init (void)
-{
-	printk(KERN_INFO "i2c-algo-bit.o: i2c bit algorithm module\n");
-	return 0;
+	return i2c_del_adapter(adap);
 }
 
-
-
 EXPORT_SYMBOL(i2c_bit_add_bus);
 EXPORT_SYMBOL(i2c_bit_del_bus);
 
-#ifdef MODULE
 MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
 MODULE_DESCRIPTION("I2C-Bus bit-banging algorithm");
 MODULE_LICENSE("GPL");
 
 MODULE_PARM(bit_test, "i");
-MODULE_PARM(bit_scan, "i");
 MODULE_PARM(i2c_debug,"i");
 
 MODULE_PARM_DESC(bit_test, "Test the lines of the bus to see if it is stuck");
-MODULE_PARM_DESC(bit_scan, "Scan for active chips on the bus");
 MODULE_PARM_DESC(i2c_debug,
             "debug level - 0 off; 1 normal; 2,3 more verbose; 9 bit-protocol");
-
-int init_module(void) 
-{
-	return i2c_algo_bit_init();
-}
-
-void cleanup_module(void) 
-{
-}
-#endif
diff -urN --exclude-from=diff-exclude linux-2.4.27/drivers/i2c/i2c-algo-ibm_ocp.c linux-2.4.27-leo/drivers/i2c/i2c-algo-ibm_ocp.c
--- linux-2.4.27/drivers/i2c/i2c-algo-ibm_ocp.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.27-leo/drivers/i2c/i2c-algo-ibm_ocp.c	2004-09-20 21:34:38.000000000 +0100
@@ -0,0 +1,901 @@
+/*
+   -------------------------------------------------------------------------
+   i2c-algo-ibm_ocp.c i2c driver algorithms for IBM PPC 405 adapters	    
+   -------------------------------------------------------------------------
+      
+   Ian DaSilva, MontaVista Software, Inc.
+   idasilva@mvista.com or source@mvista.com
+
+   Copyright 2000 MontaVista Software Inc.
+
+   Changes made to support the IIC peripheral on the IBM PPC 405
+
+
+   ---------------------------------------------------------------------------
+   This file was highly leveraged from i2c-algo-pcf.c, which was created
+   by Simon G. Vogl and Hans Berglund:
+
+
+     Copyright (C) 1995-1997 Simon G. Vogl
+                   1998-2000 Hans Berglund
+
+   With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and 
+   Frodo Looijaard <frodol@dds.nl> ,and also from Martin Bailey
+   <mbailey@littlefeet-inc.com>
+
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   ---------------------------------------------------------------------------
+
+   History: 01/20/12 - Armin
+   	akuster@mvista.com
+   	ported up to 2.4.16+	
+
+   Version 02/03/25 - Armin
+       converted to ocp format
+       removed commented out or #if 0 code
+       added Gérard Basler's fix to iic_combined_transaction() such that it 
+       returns the number of successfully completed transfers .
+*/
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-ibm_ocp.h>
+#include <asm/ocp.h>
+
+
+/* ----- global defines ----------------------------------------------- */
+#define DEB(x) if (i2c_debug>=1) x
+#define DEB2(x) if (i2c_debug>=2) x
+#define DEB3(x) if (i2c_debug>=3) x /* print several statistical values*/
+#define DEBPROTO(x) if (i2c_debug>=9) x;
+ 	/* debug the protocol by showing transferred bits */
+#define DEF_TIMEOUT 5
+
+
+/* ----- global variables ---------------------------------------------	*/
+
+
+/* module parameters:
+ */
+static int i2c_debug=0;
+
+/* --- setting states on the bus with the right timing: ---------------	*/
+
+#define iic_outb(adap, reg, val) adap->setiic(adap->data, (int) &(reg), val)
+#define iic_inb(adap, reg) adap->getiic(adap->data, (int) &(reg))
+
+#define IICO_I2C_SDAHIGH	0x0780
+#define IICO_I2C_SDALOW		0x0781
+#define IICO_I2C_SCLHIGH	0x0782
+#define IICO_I2C_SCLLOW		0x0783
+#define IICO_I2C_LINEREAD	0x0784
+
+#define IIC_SINGLE_XFER		0
+#define IIC_COMBINED_XFER	1
+
+#define IIC_ERR_LOST_ARB        -2
+#define IIC_ERR_INCOMPLETE_XFR  -3
+#define IIC_ERR_NACK            -1
+
+/* --- other auxiliary functions --------------------------------------	*/
+
+
+//
+// Description: Puts this process to sleep for a period equal to timeout 
+//
+static inline void iic_sleep(unsigned long timeout)
+{
+	schedule_timeout( timeout * HZ);
+}
+
+
+//
+// Description: This performs the IBM PPC 405 IIC initialization sequence
+// as described in the PPC405GP data book.
+//
+static int iic_init (struct i2c_algo_iic_data *adap)
+{
+	struct iic_regs *iic;	
+	struct iic_ibm *adap_priv_data = adap->data;
+	unsigned short	retval;
+	iic = (struct iic_regs *) adap_priv_data->iic_base;
+
+        /* Clear master low master address */
+        iic_outb(adap,iic->lmadr, 0);
+
+        /* Clear high master address */
+        iic_outb(adap,iic->hmadr, 0);
+
+        /* Clear low slave address */
+        iic_outb(adap,iic->lsadr, 0);
+
+        /* Clear high slave address */
+        iic_outb(adap,iic->hsadr, 0);
+
+        /* Clear status */
+        iic_outb(adap,iic->sts, 0x0a);
+
+        /* Clear extended status */
+        iic_outb(adap,iic->extsts, 0x8f);
+
+        /* Set clock division */
+        iic_outb(adap,iic->clkdiv, 0x04);
+
+	retval = iic_inb(adap, iic->clkdiv);
+	DEB(printk("iic_init: CLKDIV register = %x\n", retval));
+
+        /* Enable interrupts on Requested Master Transfer Complete */
+        iic_outb(adap,iic->intmsk, 0x01);
+
+        /* Clear transfer count */
+        iic_outb(adap,iic->xfrcnt, 0x0);
+
+        /* Clear extended control and status */
+        iic_outb(adap,iic->xtcntlss, 0xf0);
+
+        /* Set mode control (flush master data buf, enable hold SCL, exit */
+        /* unknown state.                                                 */
+        iic_outb(adap,iic->mdcntl, 0x47);
+
+        /* Clear control register */
+        iic_outb(adap,iic->cntl, 0x0);
+
+        DEB2(printk(KERN_DEBUG "iic_init: Initialized IIC on PPC 405\n"));
+        return 0;
+}
+
+
+//
+// Description: After we issue a transaction on the IIC bus, this function
+// is called.  It puts this process to sleep until we get an interrupt from
+// from the controller telling us that the transaction we requested in complete.
+//
+static int wait_for_pin(struct i2c_algo_iic_data *adap, int *status) 
+{
+
+	int timeout = DEF_TIMEOUT;
+	int retval;
+	struct iic_regs *iic;
+	struct iic_ibm *adap_priv_data = adap->data;
+	iic = (struct iic_regs *) adap_priv_data->iic_base;
+
+
+	*status = iic_inb(adap, iic->sts);
+#ifndef STUB_I2C
+
+	while (timeout-- && (*status & 0x01)) {
+	   adap->waitforpin(adap->data);
+	   *status = iic_inb(adap, iic->sts);
+	}
+#endif
+	if (timeout <= 0) {
+	   /* Issue stop signal on the bus, and force an interrupt */
+           retval = iic_inb(adap, iic->cntl);
+           iic_outb(adap, iic->cntl, retval | 0x80);
+           /* Clear status register */
+	   iic_outb(adap, iic->sts, 0x0a);
+	   /* Exit unknown bus state */
+	   retval = iic_inb(adap, iic->mdcntl);
+	   iic_outb(adap, iic->mdcntl, (retval | 0x02));
+
+	   // Check the status of the controller.  Does it still see a
+	   // pending transfer, even though we've tried to stop any
+	   // ongoing transaction?
+           retval = iic_inb(adap, iic->sts);
+           retval = retval & 0x01;
+           if(retval) {
+	      // The iic controller is hosed.  It is not responding to any
+	      // of our commands.  We have already tried to force it into
+	      // a known state, but it has not worked.  Our only choice now
+	      // is a soft reset, which will clear all registers, and force
+	      // us to re-initialize the controller.
+	      /* Soft reset */
+              iic_outb(adap, iic->xtcntlss, 0x01);
+              udelay(500);
+              iic_init(adap);
+	      /* Is the pending transfer bit in the sts reg finally cleared? */
+              retval = iic_inb(adap, iic->sts);
+              retval = retval & 0x01;
+              if(retval) {
+                 printk(KERN_CRIT "The IIC Controller is hosed.  A processor reset is required\n");
+              }
+	      // For some reason, even though the interrupt bit in this
+	      // register was set during iic_init, it didn't take.  We
+	      // need to set it again.  Don't ask me why....this is just what
+	      // I saw when testing timeouts.
+              iic_outb(adap, iic->intmsk, 0x01);
+           }
+	   return(-1);
+	}
+	else
+	   return(0);
+}
+
+
+//------------------------------------
+// Utility functions
+//
+
+
+//
+// Description: Look at the status register to see if there was an error
+// in the requested transaction.  If there is, look at the extended status
+// register and determine the exact cause.
+//
+int analyze_status(struct i2c_algo_iic_data *adap, int *error_code)
+{
+   int ret;
+   struct iic_regs *iic;
+   struct iic_ibm *adap_priv_data = adap->data;
+   iic = (struct iic_regs *) adap_priv_data->iic_base;
+
+	
+   ret = iic_inb(adap, iic->sts);
+   if(ret & 0x04) {
+      // Error occurred
+      ret = iic_inb(adap, iic->extsts);
+      if(ret & 0x04) {
+         // Lost arbitration
+         *error_code =  IIC_ERR_LOST_ARB;
+      }
+      if(ret & 0x02) {
+         // Incomplete transfer
+         *error_code = IIC_ERR_INCOMPLETE_XFR;
+      }
+      if(ret & 0x01) {
+         // Master transfer aborted by a NACK during the transfer of the 
+	 // address byte
+         *error_code = IIC_ERR_NACK;
+      }
+      return -1;
+   }
+   return 0;
+}
+
+
+//
+// Description: This function is called by the upper layers to do the
+// grunt work for a master send transaction
+//
+static int iic_sendbytes(struct i2c_adapter *i2c_adap,const char *buf,
+                         int count, int xfer_flag)
+{
+	struct iic_regs *iic;
+	struct i2c_algo_iic_data *adap = i2c_adap->algo_data;
+	struct iic_ibm *adap_priv_data = adap->data;
+	int wrcount, status, timeout;
+	int loops, remainder, i, j;
+	int ret, error_code;
+  	iic = (struct iic_regs *) adap_priv_data->iic_base;
+
+ 
+	if( count == 0 ) return 0;
+	wrcount = 0;
+	loops =  count / 4;
+	remainder = count % 4;
+
+	if((loops > 1) && (remainder == 0)) {
+	   for(i=0; i<(loops-1); i++) {
+       	      //
+   	      // Write four bytes to master data buffer
+	      //
+	      for(j=0; j<4; j++) {
+   	         iic_outb(adap, iic->mdbuf, 
+	         buf[wrcount++]);
+  	      }
+	      //
+	      // Issue command to IICO device to begin transmission
+	      //
+	      iic_outb(adap, iic->cntl, 0x35);
+	      //
+	      // Wait for transmission to complete.  When it does, 
+	      //loop to the top of the for statement and write the 
+	      // next four bytes.
+	      //
+	      timeout = wait_for_pin(adap, &status);
+	      if(timeout < 0) {
+	         //
+	         // Error handling
+	         //
+                 //printk(KERN_ERR "Error: write timeout\n");
+                 return wrcount;
+	      }
+	      ret = analyze_status(adap, &error_code);
+	      if(ret < 0) {
+                 if(error_code == IIC_ERR_INCOMPLETE_XFR) {
+                    // Return the number of bytes transferred
+                    ret = iic_inb(adap, iic->xfrcnt);
+                    ret = ret & 0x07;
+                    return (wrcount-4+ret);
+                 }
+                 else return error_code;
+              }
+           }
+	}
+	else if((loops >= 1) && (remainder > 0)){
+	   //printk(KERN_DEBUG "iic_sendbytes: (loops >= 1)\n");
+	   for(i=0; i<loops; i++) {
+              //
+              // Write four bytes to master data buffer
+              //
+              for(j=0; j<4; j++) {
+                 iic_outb(adap, iic->mdbuf,
+                 buf[wrcount++]);
+              }
+              //
+              // Issue command to IICO device to begin transmission
+              //
+              iic_outb(adap, iic->cntl, 0x35);
+              //
+              // Wait for transmission to complete.  When it does,
+              //loop to the top of the for statement and write the
+              // next four bytes.
+              //
+              timeout = wait_for_pin(adap, &status);
+              if(timeout < 0) {
+                 //
+                 // Error handling
+                 //
+                 //printk(KERN_ERR "Error: write timeout\n");
+                 return wrcount;
+              }
+              ret = analyze_status(adap, &error_code);
+              if(ret < 0) {
+                 if(error_code == IIC_ERR_INCOMPLETE_XFR) {
+                    // Return the number of bytes transferred
+                    ret = iic_inb(adap, iic->xfrcnt);
+                    ret = ret & 0x07;
+                    return (wrcount-4+ret);
+                 }
+                 else return error_code;
+              }
+           }
+        }
+
+	//printk(KERN_DEBUG "iic_sendbytes: expedite write\n");
+	if(remainder == 0) remainder = 4;
+	// remainder = remainder - 1;
+	//
+	// Write the remaining bytes (less than or equal to 4)
+	//
+	for(i=0; i<remainder; i++) {
+	   iic_outb(adap, iic->mdbuf, buf[wrcount++]);
+	   //printk(KERN_DEBUG "iic_sendbytes:  data transferred = %x, wrcount = %d\n", buf[wrcount-1], (wrcount-1));
+	}
+        //printk(KERN_DEBUG "iic_sendbytes: Issuing write\n");
+
+        if(xfer_flag == IIC_COMBINED_XFER) {
+           iic_outb(adap, iic->cntl, (0x09 | ((remainder-1) << 4)));
+        }
+	else {
+           iic_outb(adap, iic->cntl, (0x01 | ((remainder-1) << 4)));
+        }
+	DEB2(printk(KERN_DEBUG "iic_sendbytes: Waiting for interrupt\n"));
+	timeout = wait_for_pin(adap, &status);
+        if(timeout < 0) {
+       	   //
+           // Error handling
+           //
+           //printk(KERN_ERR "Error: write timeout\n");
+           return wrcount;
+        }
+        ret = analyze_status(adap, &error_code);
+        if(ret < 0) {
+           if(error_code == IIC_ERR_INCOMPLETE_XFR) {
+              // Return the number of bytes transferred
+              ret = iic_inb(adap, iic->xfrcnt);
+              ret = ret & 0x07;
+              return (wrcount-4+ret);
+           }
+           else return error_code;
+        }
+	DEB2(printk(KERN_DEBUG "iic_sendbytes: Got interrupt\n"));
+	return wrcount;
+}
+
+
+//
+// Description: Called by the upper layers to do the grunt work for
+// a master read transaction.
+//
+static int iic_readbytes(struct i2c_adapter *i2c_adap, char *buf, int count, int xfer_type)
+{
+	struct iic_regs *iic;
+	int rdcount=0, i, status, timeout;
+	struct i2c_algo_iic_data *adap = i2c_adap->algo_data;
+	struct iic_ibm *adap_priv_data = adap->data;
+	int loops, remainder, j;
+        int ret, error_code;
+	iic = (struct iic_regs *) adap_priv_data->iic_base;
+
+	if(count == 0) return 0;
+	loops = count / 4;
+	remainder = count % 4;
+
+	//printk(KERN_DEBUG "iic_readbytes: loops = %d, remainder = %d\n", loops, remainder);
+
+	if((loops > 1) && (remainder == 0)) {
+	//printk(KERN_DEBUG "iic_readbytes: (loops > 1) && (remainder == 0)\n");
+	   for(i=0; i<(loops-1); i++) {
+	      //
+              // Issue command to begin master read (4 bytes maximum)
+              //
+	      //printk(KERN_DEBUG "--->Issued read command\n");
+	      iic_outb(adap, iic->cntl, 0x37);
+	      //
+              // Wait for transmission to complete.  When it does,
+              // loop to the top of the for statement and write the
+              // next four bytes.
+              //
+	      //printk(KERN_DEBUG "--->Waiting for interrupt\n");
+              timeout = wait_for_pin(adap, &status);
+              if(timeout < 0) {
+	         // Error Handler
+		 //printk(KERN_ERR "Error: read timed out\n");
+                 return rdcount;
+	      }
+              //printk(KERN_DEBUG "--->Got interrupt\n");
+
+              ret = analyze_status(adap, &error_code);
+	      if(ret < 0) {
+                 if(error_code == IIC_ERR_INCOMPLETE_XFR)
+                    return rdcount;
+                 else
+                    return error_code;
+              }
+
+	      for(j=0; j<4; j++) {
+                 // Wait for data to shuffle to top of data buffer
+                 // This value needs to optimized.
+		 udelay(1);
+	         buf[rdcount] = iic_inb(adap, iic->mdbuf);
+	         rdcount++;
+		 //printk(KERN_DEBUG "--->Read one byte\n");
+              }
+           }
+	}
+
+	else if((loops >= 1) && (remainder > 0)){
+	//printk(KERN_DEBUG "iic_readbytes: (loops >=1) && (remainder > 0)\n");
+	   for(i=0; i<loops; i++) {
+              //
+              // Issue command to begin master read (4 bytes maximum)
+              //
+              //printk(KERN_DEBUG "--->Issued read command\n");
+              iic_outb(adap, iic->cntl, 0x37);
+              //
+              // Wait for transmission to complete.  When it does,
+              // loop to the top of the for statement and write the
+              // next four bytes.
+              //
+              //printk(KERN_DEBUG "--->Waiting for interrupt\n");
+              timeout = wait_for_pin(adap, &status);
+              if(timeout < 0) {
+                 // Error Handler
+                 //printk(KERN_ERR "Error: read timed out\n");
+                 return rdcount;
+              }
+              //printk(KERN_DEBUG "--->Got interrupt\n");
+
+              ret = analyze_status(adap, &error_code);
+              if(ret < 0) {
+                 if(error_code == IIC_ERR_INCOMPLETE_XFR)
+                    return rdcount;
+                 else
+                    return error_code;
+              }
+
+              for(j=0; j<4; j++) {
+                 // Wait for data to shuffle to top of data buffer
+                 // This value needs to optimized.
+                 udelay(1);
+                 buf[rdcount] = iic_inb(adap, iic->mdbuf);
+                 rdcount++;
+                 //printk(KERN_DEBUG "--->Read one byte\n");
+              }
+           }
+        }
+
+	//printk(KERN_DEBUG "iic_readbytes: expedite read\n");
+	if(remainder == 0) remainder = 4;
+	DEB2(printk(KERN_DEBUG "iic_readbytes: writing %x to IICO_CNTL\n", (0x03 | ((remainder-1) << 4))));
+
+	if(xfer_type == IIC_COMBINED_XFER) {
+	   iic_outb(adap, iic->cntl, (0x0b | ((remainder-1) << 4)));
+        }
+        else {
+	   iic_outb(adap, iic->cntl, (0x03 | ((remainder-1) << 4)));
+        }
+	DEB2(printk(KERN_DEBUG "iic_readbytes: Wait for pin\n"));
+        timeout = wait_for_pin(adap, &status);
+	DEB2(printk(KERN_DEBUG "iic_readbytes: Got the interrupt\n"));
+        if(timeout < 0) {
+           // Error Handler
+	   //printk(KERN_ERR "Error: read timed out\n");
+           return rdcount;
+        }
+
+        ret = analyze_status(adap, &error_code);
+        if(ret < 0) {
+           if(error_code == IIC_ERR_INCOMPLETE_XFR)
+              return rdcount;
+           else
+              return error_code;
+        }
+
+	//printk(KERN_DEBUG "iic_readbyte: Begin reading data buffer\n");
+	for(i=0; i<remainder; i++) {
+	   buf[rdcount] = iic_inb(adap, iic->mdbuf);
+	   // printk(KERN_DEBUG "iic_readbytes:  Character read = %x\n", buf[rdcount]);
+           rdcount++;
+	}
+
+	return rdcount;
+}
+
+
+//
+// Description:  This function implements combined transactions.  Combined
+// transactions consist of combinations of reading and writing blocks of data.
+// Each transfer (i.e. a read or a write) is separated by a repeated start
+// condition.
+//
+static int iic_combined_transaction(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) 
+{
+   int i;
+   struct i2c_msg *pmsg;
+   int ret;
+
+   DEB2(printk(KERN_DEBUG "Beginning combined transaction\n"));
+	for(i=0; i < num; i++) {
+		pmsg = &msgs[i];
+		if(pmsg->flags & I2C_M_RD) {
+
+			// Last read or write segment needs to be terminated with a stop
+			if(i < num-1) {
+				DEB2(printk(KERN_DEBUG "This one is a read\n"));
+			}
+			else {
+				DEB2(printk(KERN_DEBUG "Doing the last read\n"));
+			}
+			ret = iic_readbytes(i2c_adap, pmsg->buf, pmsg->len, (i < num-1) ? IIC_COMBINED_XFER : IIC_SINGLE_XFER);
+
+			if (ret != pmsg->len) {
+				DEB2(printk("i2c-algo-ppc405.o: fail: "
+							"only read %d bytes.\n",ret));
+				return i;
+			}
+			else {
+				DEB2(printk("i2c-algo-ppc405.o: read %d bytes.\n",ret));
+			}
+		}
+		else if(!(pmsg->flags & I2C_M_RD)) {
+
+			// Last read or write segment needs to be terminated with a stop
+			if(i < num-1) {
+				DEB2(printk(KERN_DEBUG "This one is a write\n"));
+			}
+			else {
+				DEB2(printk(KERN_DEBUG "Doing the last write\n"));
+			}
+			ret = iic_sendbytes(i2c_adap, pmsg->buf, pmsg->len, (i < num-1) ? IIC_COMBINED_XFER : IIC_SINGLE_XFER);
+
+			if (ret != pmsg->len) {
+				DEB2(printk("i2c-algo-ppc405.o: fail: "
+							"only wrote %d bytes.\n",ret));
+				return i;
+			}
+			else {
+				DEB2(printk("i2c-algo-ppc405.o: wrote %d bytes.\n",ret));
+			}
+		}
+	}
+ 
+	return num;
+}
+
+
+//
+// Description: Whenever we initiate a transaction, the first byte clocked
+// onto the bus after the start condition is the address (7 bit) of the
+// device we want to talk to.  This function manipulates the address specified
+// so that it makes sense to the hardware when written to the IIC peripheral.
+//
+// Note: 10 bit addresses are not supported in this driver, although they are
+// supported by the hardware.  This functionality needs to be implemented.
+//
+static inline int iic_doAddress(struct i2c_algo_iic_data *adap,
+                                struct i2c_msg *msg, int retries) 
+{
+	struct iic_regs *iic;
+	unsigned short flags = msg->flags;
+	unsigned char addr;
+	struct iic_ibm *adap_priv_data = adap->data;
+	iic = (struct iic_regs *) adap_priv_data->iic_base;
+
+//
+// The following segment for 10 bit addresses needs to be ported
+//
+/* Ten bit addresses not supported right now
+	if ( (flags & I2C_M_TEN)  ) { 
+		// a ten bit address
+		addr = 0xf0 | (( msg->addr >> 7) & 0x03);
+		DEB2(printk(KERN_DEBUG "addr0: %d\n",addr));
+		// try extended address code...
+		ret = try_address(adap, addr, retries);
+		if (ret!=1) {
+			printk(KERN_ERR "iic_doAddress: died at extended address code.\n");
+			return -EREMOTEIO;
+		}
+		// the remaining 8 bit address
+		iic_outb(adap,msg->addr & 0x7f);
+		// Status check comes here
+		if (ret != 1) {
+			printk(KERN_ERR "iic_doAddress: died at 2nd address code.\n");
+			return -EREMOTEIO;
+		}
+		if ( flags & I2C_M_RD ) {
+			i2c_repstart(adap);
+			// okay, now switch into reading mode
+			addr |= 0x01;
+			ret = try_address(adap, addr, retries);
+			if (ret!=1) {
+				printk(KERN_ERR "iic_doAddress: died at extended address code.\n");
+				return -EREMOTEIO;
+			}
+		}
+	} else ----------> // normal 7 bit address
+
+Ten bit addresses not supported yet */
+
+	addr = ( msg->addr << 1 );
+	if (flags & I2C_M_RD )
+		addr |= 1;
+	if (flags & I2C_M_REV_DIR_ADDR )
+		addr ^= 1;
+	//
+	// Write to the low slave address
+	//
+	iic_outb(adap, iic->lmadr, addr);
+	//
+	// Write zero to the high slave register since we are
+	// only using 7 bit addresses
+	//
+	iic_outb(adap, iic->hmadr, 0);
+
+	return 0;
+}
+
+
+//
+// Description: Prepares the controller for a transaction (clearing status
+// registers, data buffers, etc), and then calls either iic_readbytes or
+// iic_sendbytes to do the actual transaction.
+//
+static int iic_xfer(struct i2c_adapter *i2c_adap,
+		    struct i2c_msg msgs[], 
+		    int num)
+{
+	struct iic_regs *iic;
+	struct i2c_algo_iic_data *adap = i2c_adap->algo_data;
+	struct iic_ibm *adap_priv_data = adap->data;
+	struct i2c_msg *pmsg;
+	int i = 0;
+	int ret;
+	iic = (struct iic_regs *) adap_priv_data->iic_base;
+
+	pmsg = &msgs[i];
+
+	//
+	// Clear status register
+	//
+	DEB2(printk(KERN_DEBUG "iic_xfer: iic_xfer: Clearing status register\n"));
+	iic_outb(adap, iic->sts, 0x0a);
+
+	//
+	// Wait for any pending transfers to complete
+	//
+	DEB2(printk(KERN_DEBUG "iic_xfer: Waiting for any pending transfers to complete\n"));
+	while((ret = iic_inb(adap, iic->sts)) == 0x01) {
+		;
+	}
+
+	//
+	// Flush master data buf
+	//
+	DEB2(printk(KERN_DEBUG "iic_xfer: Clearing master data buffer\n"));		
+	ret = iic_inb(adap, iic->mdcntl);
+	iic_outb(adap, iic->mdcntl, ret | 0x40);
+
+	//
+	// Load slave address
+	//
+	DEB2(printk(KERN_DEBUG "iic_xfer: Loading slave address\n"));
+	ret = iic_doAddress(adap, pmsg, i2c_adap->retries);
+
+        //
+        // Check to see if the bus is busy
+        //
+        ret = iic_inb(adap, iic->extsts);
+        // Mask off the irrelevent bits
+        ret = ret & 0x70;
+        // When the bus is free, the BCS bits in the EXTSTS register are 0b100
+        if(ret != 0x40) return IIC_ERR_LOST_ARB;
+
+	//
+	// Combined transaction (read and write)
+	//
+	if(num > 1) {
+           DEB2(printk(KERN_DEBUG "iic_xfer: Call combined transaction\n"));
+           ret = iic_combined_transaction(i2c_adap, msgs, num);
+        }
+	//
+	// Read only
+	//
+	else if((num == 1) && (pmsg->flags & I2C_M_RD)) {
+	   //
+	   // Tell device to begin reading data from the  master data 
+	   //
+	   DEB2(printk(KERN_DEBUG "iic_xfer: Call adapter's read\n"));
+	   ret = iic_readbytes(i2c_adap, pmsg->buf, pmsg->len, IIC_SINGLE_XFER);
+	} 
+        //
+	// Write only
+	//
+	else if((num == 1 ) && (!(pmsg->flags & I2C_M_RD))) {
+	   //
+	   // Write data to master data buffers and tell our device
+	   // to begin transmitting
+	   //
+	   DEB2(printk(KERN_DEBUG "iic_xfer: Call adapter's write\n"));
+	   ret = iic_sendbytes(i2c_adap, pmsg->buf, pmsg->len, IIC_SINGLE_XFER);
+	}	
+
+	return ret;   
+}
+
+
+//
+// Description: Implements device specific ioctls.  Higher level ioctls can
+// be found in i2c-core.c and are typical of any i2c controller (specifying
+// slave address, timeouts, etc).  These ioctls take advantage of any hardware
+// features built into the controller for which this algorithm-adapter set
+// was written.  These ioctls allow you to take control of the data and clock
+// lines on the IBM PPC 405 IIC controller and set the either high or low,
+// similar to a GPIO pin.
+//
+static int algo_control(struct i2c_adapter *adapter, 
+	unsigned int cmd, unsigned long arg)
+{
+	struct iic_regs *iic;
+	struct i2c_algo_iic_data *adap = adapter->algo_data;
+	struct iic_ibm *adap_priv_data = adap->data;
+	int ret=0;
+	int lines;
+	iic = (struct iic_regs *) adap_priv_data->iic_base;
+
+	lines = iic_inb(adap, iic->directcntl);
+
+	if (cmd == IICO_I2C_SDAHIGH) {
+	      lines = lines & 0x01;
+	      if( lines ) lines = 0x04;
+	      else lines = 0;
+	      iic_outb(adap, iic->directcntl,(0x08|lines));
+	}
+	else if (cmd == IICO_I2C_SDALOW) {
+	      lines = lines & 0x01;
+	      if( lines ) lines = 0x04;
+              else lines = 0;
+              iic_outb(adap, iic->directcntl,(0x00|lines));
+	}
+	else if (cmd == IICO_I2C_SCLHIGH) {
+              lines = lines & 0x02;
+              if( lines ) lines = 0x08;
+              else lines = 0;
+              iic_outb(adap, iic->directcntl,(0x04|lines));
+	}
+	else if (cmd == IICO_I2C_SCLLOW) {
+              lines = lines & 0x02;
+	      if( lines ) lines = 0x08;
+              else lines = 0;
+              iic_outb(adap, iic->directcntl,(0x00|lines));
+	}
+	else if (cmd == IICO_I2C_LINEREAD) {
+	      ret = lines;
+	}
+	return ret;
+}
+
+
+static u32 iic_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | 
+	       I2C_FUNC_PROTOCOL_MANGLING; 
+}
+
+
+/* -----exported algorithm data: -------------------------------------	*/
+
+static struct i2c_algorithm iic_algo = {
+	.owner		= THIS_MODULE,
+	.name		= "IBM on-chip IIC algorithm",
+	.id		= I2C_ALGO_OCP,
+	.master_xfer	= iic_xfer,
+	.algo_control	= algo_control,
+	.functionality	= iic_func,
+};
+
+/* 
+ * registering functions to load algorithms at runtime 
+ */
+
+
+//
+// Description: Register bus structure
+//
+int i2c_ocp_add_bus(struct i2c_adapter *adap)
+{
+	struct i2c_algo_iic_data *iic_adap = adap->algo_data;
+
+	DEB2(printk(KERN_DEBUG "i2c-algo-iic.o: hw routines for %s registered.\n",
+	            adap->name));
+
+	/* register new adapter to i2c module... */
+
+	adap->id |= iic_algo.id;
+	adap->algo = &iic_algo;
+
+	adap->timeout = 100;	/* default values, should	*/
+	adap->retries = 3;		/* be replaced by defines	*/
+
+	iic_init(iic_adap);
+	i2c_add_adapter(adap);
+	return 0;
+}
+
+
+//
+// Done
+//
+int i2c_ocp_del_bus(struct i2c_adapter *adap)
+{
+	return i2c_del_adapter(adap);
+}
+
+
+EXPORT_SYMBOL(i2c_ocp_add_bus);
+EXPORT_SYMBOL(i2c_ocp_del_bus);
+
+//
+// The MODULE_* macros resolve to nothing if MODULES is not defined
+// when this file is compiled.
+//
+MODULE_AUTHOR("MontaVista Software <www.mvista.com>");
+MODULE_DESCRIPTION("PPC 405 iic algorithm");
+MODULE_LICENSE("GPL");
+
+MODULE_PARM(i2c_debug,"i");
+
+MODULE_PARM_DESC(i2c_debug,
+        "debug level - 0 off; 1 normal; 2,3 more verbose; 9 iic-protocol");
+
diff -urN --exclude-from=diff-exclude linux-2.4.27/drivers/i2c/i2c-algo-pcf.c linux-2.4.27-leo/drivers/i2c/i2c-algo-pcf.c
--- linux-2.4.27/drivers/i2c/i2c-algo-pcf.c	2004-02-20 14:11:41.000000000 +0000
+++ linux-2.4.27-leo/drivers/i2c/i2c-algo-pcf.c	2004-09-20 21:34:38.000000000 +0100
@@ -32,14 +32,11 @@
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/init.h>
-#include <asm/uaccess.h>
-#include <linux/ioport.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
-
 #include <linux/i2c.h>
 #include <linux/i2c-algo-pcf.h>
-#include "i2c-pcf8584.h"
+
 
 /* ----- global defines ----------------------------------------------- */
 #define DEB(x) if (i2c_debug>=1) x
@@ -52,7 +49,6 @@
 /* module parameters:
  */
 static int i2c_debug=0;
-static int pcf_scan=0;	/* have a look at what's hanging 'round		*/
 
 /* --- setting states on the bus with the right timing: ---------------	*/
 
@@ -149,8 +145,7 @@
 	set_pcf(adap, 1, I2C_PCF_PIN);
 	/* check to see S1 now used as R/W ctrl -
 	   PCF8584 does that when ESO is zero */
-	/* PCF also resets PIN bit */
-	if ((temp = get_pcf(adap, 1)) != (0)) {
+	if (((temp = get_pcf(adap, 1)) & 0x7f) != (0)) {
 		DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S0 (0x%02x).\n", temp));
 		return -ENXIO; /* definetly not PCF8584 */
 	}
@@ -166,7 +161,7 @@
 	/* S1=0xA0, next byte in S2					*/
 	set_pcf(adap, 1, I2C_PCF_PIN | I2C_PCF_ES1);
 	/* check to see S2 now selected */
-	if ((temp = get_pcf(adap, 1)) != I2C_PCF_ES1) {
+	if (((temp = get_pcf(adap, 1)) & 0x7f) != I2C_PCF_ES1) {
 		DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S2 (0x%02x).\n", temp));
 		return -ENXIO;
 	}
@@ -427,12 +422,6 @@
 	return (i);
 }
 
-static int algo_control(struct i2c_adapter *adapter, 
-	unsigned int cmd, unsigned long arg)
-{
-	return 0;
-}
-
 static u32 pcf_func(struct i2c_adapter *adap)
 {
 	return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | 
@@ -442,14 +431,11 @@
 /* -----exported algorithm data: -------------------------------------	*/
 
 static struct i2c_algorithm pcf_algo = {
-	"PCF8584 algorithm",
-	I2C_ALGO_PCF,
-	pcf_xfer,
-	NULL,
-	NULL,				/* slave_xmit		*/
-	NULL,				/* slave_recv		*/
-	algo_control,			/* ioctl		*/
-	pcf_func,			/* functionality	*/
+	.owner		= THIS_MODULE,
+	.name		= "PCF8584 algorithm",
+	.id		= I2C_ALGO_PCF,
+	.master_xfer	= pcf_xfer,
+	.functionality	= pcf_func,
 };
 
 /* 
@@ -457,7 +443,7 @@
  */
 int i2c_pcf_add_bus(struct i2c_adapter *adap)
 {
-	int i, status;
+	int i;
 	struct i2c_algo_pcf_data *pcf_adap = adap->algo_data;
 
 	DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: hw routines for %s registered.\n",
@@ -475,81 +461,23 @@
 		return i;
 	}
 
-#ifdef MODULE
-	MOD_INC_USE_COUNT;
-#endif
-
 	i2c_add_adapter(adap);
-
-	/* scan bus */
-	if (pcf_scan) {
-		printk(KERN_INFO " i2c-algo-pcf.o: scanning bus %s.\n",
-		       adap->name);
-		for (i = 0x00; i < 0xff; i+=2) {
-			if (wait_for_bb(pcf_adap)) {
-    			printk(KERN_INFO " i2c-algo-pcf.o: scanning bus %s - TIMEOUTed.\n",
-		           adap->name);
-			    break;
-			}
-			i2c_outb(pcf_adap, i);
-			i2c_start(pcf_adap);
-			if ((wait_for_pin(pcf_adap, &status) >= 0) && 
-			    ((status & I2C_PCF_LRB) == 0)) { 
-				printk("(%02x)",i>>1); 
-			} else {
-				printk("."); 
-			}
-			i2c_stop(pcf_adap);
-			udelay(pcf_adap->udelay);
-		}
-		printk("\n");
-	}
 	return 0;
 }
 
 
 int i2c_pcf_del_bus(struct i2c_adapter *adap)
 {
-	int res;
-	if ((res = i2c_del_adapter(adap)) < 0)
-		return res;
-	DEB2(printk("i2c-algo-pcf.o: adapter unregistered: %s\n",adap->name));
-
-#ifdef MODULE
-	MOD_DEC_USE_COUNT;
-#endif
-	return 0;
-}
-
-int __init i2c_algo_pcf_init (void)
-{
-	printk("i2c-algo-pcf.o: i2c pcf8584 algorithm module\n");
-	return 0;
+	return i2c_del_adapter(adap);
 }
 
-
 EXPORT_SYMBOL(i2c_pcf_add_bus);
 EXPORT_SYMBOL(i2c_pcf_del_bus);
 
-#ifdef MODULE
 MODULE_AUTHOR("Hans Berglund <hb@spacetec.no>");
 MODULE_DESCRIPTION("I2C-Bus PCF8584 algorithm");
 MODULE_LICENSE("GPL");
 
-MODULE_PARM(pcf_scan, "i");
 MODULE_PARM(i2c_debug,"i");
-
-MODULE_PARM_DESC(pcf_scan, "Scan for active chips on the bus");
 MODULE_PARM_DESC(i2c_debug,
         "debug level - 0 off; 1 normal; 2,3 more verbose; 9 pcf-protocol");
-
-
-int init_module(void) 
-{
-	return i2c_algo_pcf_init();
-}
-
-void cleanup_module(void) 
-{
-}
-#endif
diff -urN --exclude-from=diff-exclude linux-2.4.27/drivers/i2c/i2c-ali1535.c linux-2.4.27-leo/drivers/i2c/i2c-ali1535.c
--- linux-2.4.27/drivers/i2c/i2c-ali1535.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.27-leo/drivers/i2c/i2c-ali1535.c	2004-09-20 21:34:47.000000000 +0100
@@ -0,0 +1,601 @@
+/*
+    i2c-ali1535.c - Part of lm_sensors, Linux kernel modules for hardware
+                    monitoring
+    Copyright (c) 2000  Frodo Looijaard <frodol@dds.nl>, 
+                        Philip Edelbrock <phil@netroedge.com>, 
+                        Mark D. Studebaker <mdsxyz123@yahoo.com>,
+                        Dan Eaton <dan.eaton@rocketlogix.com> and 
+                        Stephen Rousset<stephen.rousset@rocketlogix.com> 
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+    This is the driver for the SMB Host controller on
+    Acer Labs Inc. (ALI) M1535 South Bridge.
+
+    The M1535 is a South bridge for portable systems.
+    It is very similar to the M15x3 South bridges also produced
+    by Acer Labs Inc.  Some of the registers within the part
+    have moved and some have been redefined slightly. Additionally,
+    the sequencing of the SMBus transactions has been modified
+    to be more consistent with the sequencing recommended by
+    the manufacturer and observed through testing.  These
+    changes are reflected in this driver and can be identified
+    by comparing this driver to the i2c-ali15x3 driver.
+    For an overview of these chips see http://www.acerlabs.com
+
+    The SMB controller is part of the 7101 device, which is an
+    ACPI-compliant Power Management Unit (PMU).
+
+    The whole 7101 device has to be enabled for the SMB to work.
+    You can't just enable the SMB alone.
+    The SMB and the ACPI have separate I/O spaces.
+    We make sure that the SMB is enabled. We leave the ACPI alone.
+
+    This driver controls the SMB Host only.
+
+    This driver does not use interrupts.
+*/
+
+
+/* Note: we assume there can only be one ALI1535, with one SMBus interface */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include <asm/semaphore.h>
+#define LM_DATE "20040611"
+#define LM_VERSION "2.8.7"
+
+
+/* ALI1535 SMBus address offsets */
+#define SMBHSTSTS (0 + ali1535_smba)
+#define SMBHSTTYP (1 + ali1535_smba)
+#define SMBHSTPORT (2 + ali1535_smba)
+#define SMBHSTCMD (7 + ali1535_smba)
+#define SMBHSTADD (3 + ali1535_smba)
+#define SMBHSTDAT0 (4 + ali1535_smba)
+#define SMBHSTDAT1 (5 + ali1535_smba)
+#define SMBBLKDAT (6 + ali1535_smba)
+
+/* PCI Address Constants */
+#define SMBCOM    0x004
+#define SMBREV    0x008
+#define SMBCFG    0x0D1
+#define SMBBA     0x0E2
+#define SMBHSTCFG 0x0F0
+#define SMBCLK    0x0F2
+
+/* Other settings */
+#define MAX_TIMEOUT 500		/* times 1/100 sec */
+#define ALI1535_SMB_IOSIZE 32
+
+/* 
+*/
+#define ALI1535_SMB_DEFAULTBASE 0x8040
+
+/* ALI1535 address lock bits */
+#define ALI1535_LOCK	0x06 < dwe >
+
+/* ALI1535 command constants */
+#define ALI1535_QUICK      0x00
+#define ALI1535_BYTE       0x10
+#define ALI1535_BYTE_DATA  0x20
+#define ALI1535_WORD_DATA  0x30
+#define ALI1535_BLOCK_DATA 0x40
+#define ALI1535_I2C_READ   0x60
+
+#define	ALI1535_DEV10B_EN	0x80	/* Enable 10-bit addressing in */
+                                        /*  I2C read                   */
+#define	ALI1535_T_OUT		0x08	/* Time-out Command (write)    */
+#define	ALI1535_A_HIGH_BIT9	0x08	/* Bit 9 of 10-bit address in  */
+                                        /* Alert-Response-Address      */
+                                        /* (read)                      */
+#define	ALI1535_KILL		0x04	/* Kill Command (write)        */
+#define	ALI1535_A_HIGH_BIT8	0x04	/* Bit 8 of 10-bit address in  */
+                                        /*  Alert-Response-Address     */
+                                        /*  (read)                     */
+
+#define	ALI1535_D_HI_MASK	0x03	/* Mask for isolating bits 9-8 */
+                                        /*  of 10-bit address in I2C   */ 
+                                        /*  Read Command               */
+
+/* ALI1535 status register bits */
+#define ALI1535_STS_IDLE	0x04
+#define ALI1535_STS_BUSY	0x08	/* host busy */
+#define ALI1535_STS_DONE	0x10	/* transaction complete */
+#define ALI1535_STS_DEV		0x20	/* device error */
+#define ALI1535_STS_BUSERR	0x40	/* bus error    */
+#define ALI1535_STS_FAIL	0x80    /* failed bus transaction */
+#define ALI1535_STS_ERR		0xE0	/* all the bad error bits */
+
+#define ALI1535_BLOCK_CLR	0x04	/* reset block data index */
+
+/* ALI1535 device address register bits */
+#define	ALI1535_RD_ADDR		0x01	/* Read/Write Bit in Device    */
+                                        /*  Address field              */
+                                        /*  -> Write = 0               */
+                                        /*  -> Read  = 1               */
+#define	ALI1535_SMBIO_EN	0x04	/* SMB I/O Space enable        */
+
+static int ali1535_transaction(void);
+
+static unsigned short ali1535_smba = 0;
+DECLARE_MUTEX(i2c_ali1535_sem);
+
+
+/* Detect whether a ALI1535 can be found, and initialize it, where necessary.
+   Note the differences between kernels with the old PCI BIOS interface and
+   newer kernels with the real PCI interface. In compat.h some things are
+   defined to make the transition easier. */
+int ali1535_setup(struct pci_dev *ALI1535_dev)
+{
+	int error_return = 0;
+	unsigned char temp;
+
+/* Check the following things:
+	- SMB I/O address is initialized
+	- Device is enabled
+	- We can use the addresses
+*/
+
+/* Determine the address of the SMBus area */
+	pci_read_config_word(ALI1535_dev, SMBBA, &ali1535_smba);
+	ali1535_smba &= (0xffff & ~(ALI1535_SMB_IOSIZE - 1));
+	if (ali1535_smba == 0) {
+		printk
+		    ("i2c-ali1535.o: ALI1535_smb region uninitialized - upgrade BIOS?\n");
+		error_return = -ENODEV;
+	}
+
+	if (error_return == -ENODEV)
+		goto END;
+
+	if (check_region(ali1535_smba, ALI1535_SMB_IOSIZE)) {
+		printk
+		    ("i2c-ali1535.o: ALI1535_smb region 0x%x already in use!\n",
+		     ali1535_smba);
+		error_return = -ENODEV;
+	}
+
+	if (error_return == -ENODEV)
+		goto END;
+
+	/* check if whole device is enabled */
+	pci_read_config_byte(ALI1535_dev, SMBCFG, &temp);
+	if ((temp & ALI1535_SMBIO_EN) == 0) {
+		printk
+		    ("i2c-ali1535.o: SMB device not enabled - upgrade BIOS?\n");
+		error_return = -ENODEV;
+		goto END;
+	}
+
+/* Is SMB Host controller enabled? */
+	pci_read_config_byte(ALI1535_dev, SMBHSTCFG, &temp);
+	if ((temp & 1) == 0) {
+		printk
+		    ("i2c-ali1535.o: SMBus controller not enabled - upgrade BIOS?\n");
+		error_return = -ENODEV;
+		goto END;
+	}
+
+/* set SMB clock to 74KHz as recommended in data sheet */
+	pci_write_config_byte(ALI1535_dev, SMBCLK, 0x20);
+
+	/* Everything is happy, let's grab the memory and set things up. */
+	request_region(ali1535_smba, ALI1535_SMB_IOSIZE, "ali1535-smb");
+
+#ifdef DEBUG
+/*
+  The interrupt routing for SMB is set up in register 0x77 in the
+  1533 ISA Bridge device, NOT in the 7101 device.
+  Don't bother with finding the 1533 device and reading the register.
+  if ((....... & 0x0F) == 1)
+     printk("i2c-ali1535.o: ALI1535 using Interrupt 9 for SMBus.\n");
+*/
+	pci_read_config_byte(ALI1535_dev, SMBREV, &temp);
+	printk("i2c-ali1535.o: SMBREV = 0x%X\n", temp);
+	printk("i2c-ali1535.o: ALI1535_smba = 0x%X\n", ali1535_smba);
+#endif				/* DEBUG */
+
+      END:
+	return error_return;
+}
+
+
+/* Another internally used function */
+int ali1535_transaction(void)
+{
+	int temp;
+	int result = 0;
+	int timeout = 0;
+
+#ifdef DEBUG
+	printk
+	    ("i2c-ali1535.o: Transaction (pre): STS=%02x, TYP=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, "
+	     "DAT1=%02x\n", inb_p(SMBHSTSTS), inb_p(SMBHSTTYP),
+	     inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
+	     inb_p(SMBHSTDAT1));
+#endif
+
+	/* get status */
+	temp = inb_p(SMBHSTSTS);
+
+	/* Make sure the SMBus host is ready to start transmitting */
+	/* Check the busy bit first */
+	if (temp & ALI1535_STS_BUSY) {
+/*
+   If the host controller is still busy, it may have timed out in the previous transaction,
+   resulting in a "SMBus Timeout" printk.
+   I've tried the following to reset a stuck busy bit.
+	1. Reset the controller with an KILL command.
+	   (this doesn't seem to clear the controller if an external device is hung)
+	2. Reset the controller and the other SMBus devices with a T_OUT command.
+	   (this clears the host busy bit if an external device is hung,
+	   but it comes back upon a new access to a device)
+	3. Disable and reenable the controller in SMBHSTCFG
+   Worst case, nothing seems to work except power reset.
+*/
+/* Abort - reset the host controller */
+/*
+#ifdef DEBUG
+    printk("i2c-ali1535.o: Resetting host controller to clear busy condition\n",temp);
+#endif
+    outb_p(ALI1535_KILL, SMBHSTTYP);
+    temp = inb_p(SMBHSTSTS);
+    if (temp & ALI1535_STS_BUSY) {
+*/
+
+/*
+   Try resetting entire SMB bus, including other devices -
+   This may not work either - it clears the BUSY bit but
+   then the BUSY bit may come back on when you try and use the chip again.
+   If that's the case you are stuck.
+*/
+		printk
+		    ("i2c-ali1535.o: Resetting entire SMB Bus to clear busy condition (%02x)\n",
+		     temp);
+		outb_p(ALI1535_T_OUT, SMBHSTTYP);
+		temp = inb_p(SMBHSTSTS);
+	}
+/*
+  }
+*/
+
+	/* now check the error bits and the busy bit */
+	if (temp & (ALI1535_STS_ERR | ALI1535_STS_BUSY)) {
+		/* do a clear-on-write */
+		outb_p(0xFF, SMBHSTSTS);
+		if ((temp = inb_p(SMBHSTSTS)) &
+		    (ALI1535_STS_ERR | ALI1535_STS_BUSY)) {
+			/* this is probably going to be correctable only by a power reset
+			   as one of the bits now appears to be stuck */
+			/* This may be a bus or device with electrical problems. */
+			printk
+			    ("i2c-ali1535.o: SMBus reset failed! (0x%02x) - controller or device on bus is probably hung\n",
+			     temp);
+			return -1;
+		}
+	} else {
+		/* check and clear done bit */
+		if (temp & ALI1535_STS_DONE) {
+			outb_p(temp, SMBHSTSTS);
+		}
+	}
+
+	/* start the transaction by writing anything to the start register */
+	outb_p(0xFF, SMBHSTPORT);
+
+	/* We will always wait for a fraction of a second! */
+	timeout = 0;
+	do {
+		i2c_delay(1);
+		temp = inb_p(SMBHSTSTS);
+	} while (((temp & ALI1535_STS_BUSY) && !(temp & ALI1535_STS_IDLE))
+		 && (timeout++ < MAX_TIMEOUT));
+
+	/* If the SMBus is still busy, we give up */
+	if (timeout >= MAX_TIMEOUT) {
+		result = -1;
+		printk("i2c-ali1535.o: SMBus Timeout!\n");
+	}
+
+	if (temp & ALI1535_STS_FAIL) {
+		result = -1;
+#ifdef DEBUG
+		printk("i2c-ali1535.o: Error: Failed bus transaction\n");
+#endif
+	}
+
+/*
+  Unfortunately the ALI SMB controller maps "no response" and "bus collision"
+  into a single bit. No reponse is the usual case so don't do a printk.
+  This means that bus collisions go unreported.
+*/
+	if (temp & ALI1535_STS_BUSERR) {
+		result = -1;
+#ifdef DEBUG
+		printk
+		    ("i2c-ali1535.o: Error: no response or bus collision ADD=%02x\n",
+		     inb_p(SMBHSTADD));
+#endif
+	}
+
+/* haven't ever seen this */
+	if (temp & ALI1535_STS_DEV) {
+		result = -1;
+		printk("i2c-ali1535.o: Error: device error\n");
+	}
+
+/* 
+   check to see if the "command complete" indication is set
+ */
+	if (!(temp & ALI1535_STS_DONE)) {
+		result = -1;
+		printk("i2c-ali1535.o: Error: command never completed\n");
+	}
+#ifdef DEBUG
+	printk
+	    ("i2c-ali1535.o: Transaction (post): STS=%02x, TYP=%02x, CMD=%02x, ADD=%02x, "
+	     "DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTSTS), inb_p(SMBHSTTYP),
+	     inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
+	     inb_p(SMBHSTDAT1));
+#endif
+
+/* 
+    take consequent actions for error conditions
+ */
+        if (!(temp & ALI1535_STS_DONE)) {
+	  /* issue "kill" to reset host controller */
+	  outb_p(ALI1535_KILL,SMBHSTTYP);
+	  outb_p(0xFF,SMBHSTSTS);
+	}	  
+	else if (temp & ALI1535_STS_ERR) {
+	  /* issue "timeout" to reset all devices on bus */
+	  outb_p(ALI1535_T_OUT,SMBHSTTYP);
+	  outb_p(0xFF,SMBHSTSTS);
+	}
+        
+	return result;
+}
+
+/* Return -1 on error. */
+s32 ali1535_access(struct i2c_adapter * adap, u16 addr,
+		   unsigned short flags, char read_write, u8 command,
+		   int size, union i2c_smbus_data * data)
+{
+	int i, len;
+	int temp;
+	int timeout;
+	s32 result = 0;
+
+	down(&i2c_ali1535_sem);
+/* make sure SMBus is idle */
+	temp = inb_p(SMBHSTSTS);
+	for (timeout = 0;
+	     (timeout < MAX_TIMEOUT) && !(temp & ALI1535_STS_IDLE);
+	     timeout++) {
+		i2c_delay(1);
+		temp = inb_p(SMBHSTSTS);
+	}
+	if (timeout >= MAX_TIMEOUT) {
+		printk("i2c-ali1535.o: Idle wait Timeout! STS=0x%02x\n",
+		       temp);
+	}
+
+/* clear status register (clear-on-write) */
+	outb_p(0xFF, SMBHSTSTS);
+
+	switch (size) {
+	case I2C_SMBUS_QUICK:
+		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+		       SMBHSTADD);
+		size = ALI1535_QUICK;
+                outb_p(size, SMBHSTTYP);	/* output command */
+                break;
+	case I2C_SMBUS_BYTE:
+		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+		       SMBHSTADD);
+		size = ALI1535_BYTE;
+                outb_p(size, SMBHSTTYP);	/* output command */
+		if (read_write == I2C_SMBUS_WRITE)
+			outb_p(command, SMBHSTCMD);
+		break;
+	case I2C_SMBUS_BYTE_DATA:
+		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+		       SMBHSTADD);
+		size = ALI1535_BYTE_DATA;
+                outb_p(size, SMBHSTTYP);	/* output command */
+		outb_p(command, SMBHSTCMD);
+		if (read_write == I2C_SMBUS_WRITE)
+			outb_p(data->byte, SMBHSTDAT0);
+		break;
+	case I2C_SMBUS_WORD_DATA:
+		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+		       SMBHSTADD);
+		size = ALI1535_WORD_DATA;
+                outb_p(size, SMBHSTTYP);	/* output command */
+		outb_p(command, SMBHSTCMD);
+		if (read_write == I2C_SMBUS_WRITE) {
+			outb_p(data->word & 0xff, SMBHSTDAT0);
+			outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1);
+		}
+		break;
+	case I2C_SMBUS_BLOCK_DATA:
+		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+		       SMBHSTADD);
+		size = ALI1535_BLOCK_DATA;
+                outb_p(size, SMBHSTTYP);	/* output command */
+		outb_p(command, SMBHSTCMD);
+		if (read_write == I2C_SMBUS_WRITE) {
+			len = data->block[0];
+			if (len < 0) {
+				len = 0;
+				data->block[0] = len;
+			}
+			if (len > 32) {
+				len = 32;
+				data->block[0] = len;
+			}
+			outb_p(len, SMBHSTDAT0);
+			outb_p(inb_p(SMBHSTTYP) | ALI1535_BLOCK_CLR, SMBHSTTYP);	/* Reset SMBBLKDAT */
+			for (i = 1; i <= len; i++)
+				outb_p(data->block[i], SMBBLKDAT);
+		}
+		break;
+	default:
+		printk
+		    (KERN_WARNING "i2c-ali1535.o: Unsupported transaction %d\n", size);
+		result = -1;
+		goto EXIT;
+	}
+
+	if (ali1535_transaction())	/* Error in transaction */
+	  {
+		result = -1;
+		goto EXIT;
+          }
+
+	if ((read_write == I2C_SMBUS_WRITE) || (size == ALI1535_QUICK))
+	  {
+		result = 0;
+		goto EXIT;
+          }
+
+	switch (size) {
+	case ALI1535_BYTE:	/* Result put in SMBHSTDAT0 */
+		data->byte = inb_p(SMBHSTDAT0);
+		break;
+	case ALI1535_BYTE_DATA:
+		data->byte = inb_p(SMBHSTDAT0);
+		break;
+	case ALI1535_WORD_DATA:
+		data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);
+		break;
+	case ALI1535_BLOCK_DATA:
+		len = inb_p(SMBHSTDAT0);
+		if (len > 32)
+			len = 32;
+		data->block[0] = len;
+		outb_p(inb_p(SMBHSTTYP) | ALI1535_BLOCK_CLR, SMBHSTTYP);	/* Reset SMBBLKDAT */
+		for (i = 1; i <= data->block[0]; i++) {
+			data->block[i] = inb_p(SMBBLKDAT);
+#ifdef DEBUG
+			printk
+			    ("i2c-ali1535.o: Blk: len=%d, i=%d, data=%02x\n",
+			     len, i, data->block[i]);
+#endif	/* DEBUG */
+		}
+		break;
+	}
+EXIT:
+	up(&i2c_ali1535_sem);
+	return result;
+}
+
+
+u32 ali1535_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+	    I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+	    I2C_FUNC_SMBUS_BLOCK_DATA;
+}
+
+static struct i2c_algorithm smbus_algorithm = {
+	.name		= "Non-i2c SMBus adapter",
+	.id		= I2C_ALGO_SMBUS,
+	.smbus_xfer	= ali1535_access,
+	.functionality	= ali1535_func,
+};
+
+static struct i2c_adapter ali1535_adapter = {
+	.owner		= THIS_MODULE,
+	.name		= "unset",
+	.id		= I2C_ALGO_SMBUS | I2C_HW_SMBUS_ALI1535,
+	.algo		= &smbus_algorithm,
+};
+
+
+static struct pci_device_id ali1535_ids[] __devinitdata = {
+	{
+	.vendor =	PCI_VENDOR_ID_AL,
+	.device =	PCI_DEVICE_ID_AL_M7101,
+	.subvendor =	PCI_ANY_ID,
+	.subdevice =	PCI_ANY_ID,
+	},
+	{ 0, }
+};
+
+static int __devinit ali1535_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	if (ali1535_setup(dev)) {
+		printk
+		    ("i2c-ali1535.o: ALI1535 not detected, module not inserted.\n");
+		return -ENODEV;
+	}
+
+	sprintf(ali1535_adapter.name, "SMBus ALI1535 adapter at %04x",
+		ali1535_smba);
+	return i2c_add_adapter(&ali1535_adapter);
+}
+
+static void __devexit ali1535_remove(struct pci_dev *dev)
+{
+	i2c_del_adapter(&ali1535_adapter);
+	release_region(ali1535_smba, ALI1535_SMB_IOSIZE);
+}
+
+
+static struct pci_driver ali1535_driver = {
+	.name		= "ali1535 smbus",
+	.id_table	= ali1535_ids,
+	.probe		= ali1535_probe,
+	.remove		= __devexit_p(ali1535_remove),
+};
+
+static int __init i2c_ali1535_init(void)
+{
+	printk("i2c-ali1535.o version %s (%s)\n", LM_VERSION, LM_DATE);
+	return pci_module_init(&ali1535_driver);
+}
+
+
+static void __exit i2c_ali1535_exit(void)
+{
+	pci_unregister_driver(&ali1535_driver);
+}
+
+#ifdef RLX
+EXPORT_SYMBOL(ali1535_smba);
+EXPORT_SYMBOL(ali1535_access);
+EXPORT_SYMBOL(i2c_ali1535_sem);
+#endif
+
+MODULE_AUTHOR
+    ("Frodo Looijaard <frodol@dds.nl>, Philip Edelbrock <phil@netroedge.com>, "
+     "Mark D. Studebaker <mdsxyz123@yahoo.com> and Dan Eaton <dan.eaton@rocketlogix.com>");
+MODULE_DESCRIPTION("ALI1535 SMBus driver");
+MODULE_LICENSE("GPL");
+
+module_init(i2c_ali1535_init);
+module_exit(i2c_ali1535_exit);
+
diff -urN --exclude-from=diff-exclude linux-2.4.27/drivers/i2c/i2c-ali15x3.c linux-2.4.27-leo/drivers/i2c/i2c-ali15x3.c
--- linux-2.4.27/drivers/i2c/i2c-ali15x3.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.27-leo/drivers/i2c/i2c-ali15x3.c	2004-09-20 21:34:47.000000000 +0100
@@ -0,0 +1,533 @@
+/*
+    ali15x3.c - Part of lm_sensors, Linux kernel modules for hardware
+              monitoring
+    Copyright (c) 1999  Frodo Looijaard <frodol@dds.nl> and
+    Philip Edelbrock <phil@netroedge.com> and
+    Mark D. Studebaker <mdsxyz123@yahoo.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+    This is the driver for the SMB Host controller on
+    Acer Labs Inc. (ALI) M1541 and M1543C South Bridges.
+
+    The M1543C is a South bridge for desktop systems.
+    The M1533 is a South bridge for portable systems.
+    They are part of the following ALI chipsets:
+       "Aladdin Pro 2": Includes the M1621 Slot 1 North bridge
+       with AGP and 100MHz CPU Front Side bus
+       "Aladdin V": Includes the M1541 Socket 7 North bridge
+       with AGP and 100MHz CPU Front Side bus
+       "Aladdin IV": Includes the M1541 Socket 7 North bridge
+       with host bus up to 83.3 MHz.
+    For an overview of these chips see http://www.acerlabs.com
+
+    The M1533/M1543C devices appear as FOUR separate devices
+    on the PCI bus. An output of lspci will show something similar
+    to the following:
+
+	00:02.0 USB Controller: Acer Laboratories Inc. M5237
+	00:03.0 Bridge: Acer Laboratories Inc. M7101
+	00:07.0 ISA bridge: Acer Laboratories Inc. M1533
+	00:0f.0 IDE interface: Acer Laboratories Inc. M5229
+
+    The SMB controller is part of the 7101 device, which is an
+    ACPI-compliant Power Management Unit (PMU).
+
+    The whole 7101 device has to be enabled for the SMB to work.
+    You can't just enable the SMB alone.
+    The SMB and the ACPI have separate I/O spaces.
+    We make sure that the SMB is enabled. We leave the ACPI alone.
+
+    This driver controls the SMB Host only.
+    The SMB Slave controller on the M15X3 is not enabled.
+
+    This driver does not use interrupts.
+*/
+
+/* Note: we assume there can only be one ALI15X3, with one SMBus interface */
+
+/* #define DEBUG 1 */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#define LM_DATE "20040611"
+#define LM_VERSION "2.8.7"
+#include <linux/sensors_compat.h>
+
+/* ALI15X3 SMBus address offsets */
+#define SMBHSTSTS	(0 + ali15x3_smba)
+#define SMBHSTCNT	(1 + ali15x3_smba)
+#define SMBHSTSTART	(2 + ali15x3_smba)
+#define SMBHSTCMD	(7 + ali15x3_smba)
+#define SMBHSTADD	(3 + ali15x3_smba)
+#define SMBHSTDAT0	(4 + ali15x3_smba)
+#define SMBHSTDAT1	(5 + ali15x3_smba)
+#define SMBBLKDAT	(6 + ali15x3_smba)
+
+/* PCI Address Constants */
+#define SMBCOM		0x004
+#define SMBBA		0x014
+#define SMBATPC		0x05B	/* used to unlock xxxBA registers */
+#define SMBHSTCFG	0x0E0
+#define SMBSLVC		0x0E1
+#define SMBCLK		0x0E2
+#define SMBREV		0x008
+
+/* Other settings */
+#define MAX_TIMEOUT		200	/* times 1/100 sec */
+#define ALI15X3_SMB_IOSIZE	32
+
+/* this is what the Award 1004 BIOS sets them to on a ASUS P5A MB.
+   We don't use these here. If the bases aren't set to some value we
+   tell user to upgrade BIOS and we fail.
+*/
+#define ALI15X3_SMB_DEFAULTBASE	0xE800
+
+/* ALI15X3 address lock bits */
+#define ALI15X3_LOCK		0x06
+
+/* ALI15X3 command constants */
+#define ALI15X3_ABORT		0x02
+#define ALI15X3_T_OUT		0x04
+#define ALI15X3_QUICK		0x00
+#define ALI15X3_BYTE		0x10
+#define ALI15X3_BYTE_DATA	0x20
+#define ALI15X3_WORD_DATA	0x30
+#define ALI15X3_BLOCK_DATA	0x40
+#define ALI15X3_BLOCK_CLR	0x80
+
+/* ALI15X3 status register bits */
+#define ALI15X3_STS_IDLE	0x04
+#define ALI15X3_STS_BUSY	0x08
+#define ALI15X3_STS_DONE	0x10
+#define ALI15X3_STS_DEV		0x20	/* device error */
+#define ALI15X3_STS_COLL	0x40	/* collision or no response */
+#define ALI15X3_STS_TERM	0x80	/* terminated by abort */
+#define ALI15X3_STS_ERR		0xE0	/* all the bad error bits */
+
+
+/* If force_addr is set to anything different from 0, we forcibly enable
+   the device at the given address. */
+static int force_addr = 0;
+MODULE_PARM(force_addr, "i");
+MODULE_PARM_DESC(force_addr,
+		 "Initialize the base address of the i2c controller");
+
+static unsigned short ali15x3_smba = 0;
+
+static int ali15x3_setup(struct pci_dev *ALI15X3_dev)
+{
+	u16 a;
+	unsigned char temp;
+
+	/* Check the following things:
+		- SMB I/O address is initialized
+		- Device is enabled
+		- We can use the addresses
+	*/
+
+	/* Unlock the register.
+	   The data sheet says that the address registers are read-only
+	   if the lock bits are 1, but in fact the address registers
+	   are zero unless you clear the lock bits.
+	*/
+	pci_read_config_byte(ALI15X3_dev, SMBATPC, &temp);
+	if (temp & ALI15X3_LOCK) {
+		temp &= ~ALI15X3_LOCK;
+		pci_write_config_byte(ALI15X3_dev, SMBATPC, temp);
+	}
+
+	/* Determine the address of the SMBus area */
+	pci_read_config_word(ALI15X3_dev, SMBBA, &ali15x3_smba);
+	ali15x3_smba &= (0xffff & ~(ALI15X3_SMB_IOSIZE - 1));
+	if (ali15x3_smba == 0 && force_addr == 0) {
+		dev_err(ALI15X3_dev, "ALI15X3_smb region uninitialized "
+			"- upgrade BIOS or use force_addr=0xaddr\n");
+		return -ENODEV;
+	}
+
+	if(force_addr)
+		ali15x3_smba = force_addr & ~(ALI15X3_SMB_IOSIZE - 1);
+
+	if (!request_region(ali15x3_smba, ALI15X3_SMB_IOSIZE, "ali15x3-smb")) {
+		dev_err(ALI15X3_dev,
+			"ALI15X3_smb region 0x%x already in use!\n",
+			ali15x3_smba);
+		return -ENODEV;
+	}
+
+	if(force_addr) {
+		dev_info(ALI15X3_dev, "forcing ISA address 0x%04X\n",
+			ali15x3_smba);
+		if (PCIBIOS_SUCCESSFUL !=
+		    pci_write_config_word(ALI15X3_dev, SMBBA, ali15x3_smba))
+			return -ENODEV;
+		if (PCIBIOS_SUCCESSFUL !=
+		    pci_read_config_word(ALI15X3_dev, SMBBA, &a))
+			return -ENODEV;
+		if ((a & ~(ALI15X3_SMB_IOSIZE - 1)) != ali15x3_smba) {
+			/* make sure it works */
+			dev_err(ALI15X3_dev,
+				"force address failed - not supported?\n");
+			return -ENODEV;
+		}
+	}
+	/* check if whole device is enabled */
+	pci_read_config_byte(ALI15X3_dev, SMBCOM, &temp);
+	if ((temp & 1) == 0) {
+		dev_info(ALI15X3_dev, "enabling SMBus device\n");
+		pci_write_config_byte(ALI15X3_dev, SMBCOM, temp | 0x01);
+	}
+
+	/* Is SMB Host controller enabled? */
+	pci_read_config_byte(ALI15X3_dev, SMBHSTCFG, &temp);
+	if ((temp & 1) == 0) {
+		dev_info(ALI15X3_dev, "enabling SMBus controller\n");
+		pci_write_config_byte(ALI15X3_dev, SMBHSTCFG, temp | 0x01);
+	}
+
+	/* set SMB clock to 74KHz as recommended in data sheet */
+	pci_write_config_byte(ALI15X3_dev, SMBCLK, 0x20);
+
+	/*
+	  The interrupt routing for SMB is set up in register 0x77 in the
+	  1533 ISA Bridge device, NOT in the 7101 device.
+	  Don't bother with finding the 1533 device and reading the register.
+	if ((....... & 0x0F) == 1)
+		dev_dbg(ALI15X3_dev, "ALI15X3 using Interrupt 9 for SMBus.\n");
+	*/
+	pci_read_config_byte(ALI15X3_dev, SMBREV, &temp);
+	dev_dbg(ALI15X3_dev, "SMBREV = 0x%X\n", temp);
+	dev_dbg(ALI15X3_dev, "iALI15X3_smba = 0x%X\n", ali15x3_smba);
+
+	return 0;
+}
+
+/* Another internally used function */
+static int ali15x3_transaction(struct i2c_adapter *adap)
+{
+	int temp;
+	int result = 0;
+	int timeout = 0;
+
+	dev_dbg(adap, "Transaction (pre): STS=%02x, CNT=%02x, CMD=%02x, "
+		"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTSTS),
+		inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD),
+		inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1));
+
+	/* get status */
+	temp = inb_p(SMBHSTSTS);
+
+	/* Make sure the SMBus host is ready to start transmitting */
+	/* Check the busy bit first */
+	if (temp & ALI15X3_STS_BUSY) {
+	/*
+	   If the host controller is still busy, it may have timed out in the
+	   previous transaction, resulting in a "SMBus Timeout" Dev.
+	   I've tried the following to reset a stuck busy bit.
+		1. Reset the controller with an ABORT command.
+		   (this doesn't seem to clear the controller if an external
+		   device is hung)
+		2. Reset the controller and the other SMBus devices with a
+		   T_OUT command.  (this clears the host busy bit if an
+		   external device is hung, but it comes back upon a new access
+		   to a device)
+		3. Disable and reenable the controller in SMBHSTCFG
+	   Worst case, nothing seems to work except power reset.
+	*/
+	/* Abort - reset the host controller */
+	/*
+	   Try resetting entire SMB bus, including other devices -
+	   This may not work either - it clears the BUSY bit but
+	   then the BUSY bit may come back on when you try and use the chip again.
+	   If that's the case you are stuck.
+	*/
+		dev_info(adap, "Resetting entire SMB Bus to "
+			"clear busy condition (%02x)\n", temp);
+		outb_p(ALI15X3_T_OUT, SMBHSTCNT);
+		temp = inb_p(SMBHSTSTS);
+	}
+
+	/* now check the error bits and the busy bit */
+	if (temp & (ALI15X3_STS_ERR | ALI15X3_STS_BUSY)) {
+		/* do a clear-on-write */
+		outb_p(0xFF, SMBHSTSTS);
+		if ((temp = inb_p(SMBHSTSTS)) &
+		    (ALI15X3_STS_ERR | ALI15X3_STS_BUSY)) {
+			/* this is probably going to be correctable only by a power reset
+			   as one of the bits now appears to be stuck */
+			/* This may be a bus or device with electrical problems. */
+			dev_err(adap, "SMBus reset failed! (0x%02x) - "
+				"controller or device on bus is probably hung\n",
+				temp);
+			return -1;
+		}
+	} else {
+		/* check and clear done bit */
+		if (temp & ALI15X3_STS_DONE) {
+			outb_p(temp, SMBHSTSTS);
+		}
+	}
+
+	/* start the transaction by writing anything to the start register */
+	outb_p(0xFF, SMBHSTSTART);
+
+	/* We will always wait for a fraction of a second! */
+	timeout = 0;
+	do {
+		i2c_delay(1);
+		temp = inb_p(SMBHSTSTS);
+	} while ((!(temp & (ALI15X3_STS_ERR | ALI15X3_STS_DONE)))
+		 && (timeout++ < MAX_TIMEOUT));
+
+	/* If the SMBus is still busy, we give up */
+	if (timeout >= MAX_TIMEOUT) {
+		result = -1;
+		dev_err(adap, "SMBus Timeout!\n");
+	}
+
+	if (temp & ALI15X3_STS_TERM) {
+		result = -1;
+		dev_dbg(adap, "Error: Failed bus transaction\n");
+	}
+
+	/*
+	  Unfortunately the ALI SMB controller maps "no response" and "bus
+	  collision" into a single bit. No reponse is the usual case so don't
+	  do a printk.
+	  This means that bus collisions go unreported.
+	*/
+	if (temp & ALI15X3_STS_COLL) {
+		result = -1;
+		dev_dbg(adap,
+			"Error: no response or bus collision ADD=%02x\n",
+			inb_p(SMBHSTADD));
+	}
+
+	/* haven't ever seen this */
+	if (temp & ALI15X3_STS_DEV) {
+		result = -1;
+		dev_err(adap, "Error: device error\n");
+	}
+	dev_dbg(adap, "Transaction (post): STS=%02x, CNT=%02x, CMD=%02x, "
+		"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTSTS),
+		inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD),
+		inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1));
+	return result;
+}
+
+/* Return -1 on error. */
+static s32 ali15x3_access(struct i2c_adapter * adap, u16 addr,
+		   unsigned short flags, char read_write, u8 command,
+		   int size, union i2c_smbus_data * data)
+{
+	int i, len;
+	int temp;
+	int timeout;
+
+	/* clear all the bits (clear-on-write) */
+	outb_p(0xFF, SMBHSTSTS);
+	/* make sure SMBus is idle */
+	temp = inb_p(SMBHSTSTS);
+	for (timeout = 0;
+	     (timeout < MAX_TIMEOUT) && !(temp & ALI15X3_STS_IDLE);
+	     timeout++) {
+		i2c_delay(1);
+		temp = inb_p(SMBHSTSTS);
+	}
+	if (timeout >= MAX_TIMEOUT) {
+		dev_err(adap, "Idle wait Timeout! STS=0x%02x\n", temp);
+	}
+
+	switch (size) {
+	case I2C_SMBUS_QUICK:
+		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+		       SMBHSTADD);
+		size = ALI15X3_QUICK;
+		break;
+	case I2C_SMBUS_BYTE:
+		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+		       SMBHSTADD);
+		if (read_write == I2C_SMBUS_WRITE)
+			outb_p(command, SMBHSTCMD);
+		size = ALI15X3_BYTE;
+		break;
+	case I2C_SMBUS_BYTE_DATA:
+		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+		       SMBHSTADD);
+		outb_p(command, SMBHSTCMD);
+		if (read_write == I2C_SMBUS_WRITE)
+			outb_p(data->byte, SMBHSTDAT0);
+		size = ALI15X3_BYTE_DATA;
+		break;
+	case I2C_SMBUS_WORD_DATA:
+		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+		       SMBHSTADD);
+		outb_p(command, SMBHSTCMD);
+		if (read_write == I2C_SMBUS_WRITE) {
+			outb_p(data->word & 0xff, SMBHSTDAT0);
+			outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1);
+		}
+		size = ALI15X3_WORD_DATA;
+		break;
+	case I2C_SMBUS_BLOCK_DATA:
+		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+		       SMBHSTADD);
+		outb_p(command, SMBHSTCMD);
+		if (read_write == I2C_SMBUS_WRITE) {
+			len = data->block[0];
+			if (len < 0) {
+				len = 0;
+				data->block[0] = len;
+			}
+			if (len > 32) {
+				len = 32;
+				data->block[0] = len;
+			}
+			outb_p(len, SMBHSTDAT0);
+			/* Reset SMBBLKDAT */
+			outb_p(inb_p(SMBHSTCNT) | ALI15X3_BLOCK_CLR, SMBHSTCNT);
+			for (i = 1; i <= len; i++)
+				outb_p(data->block[i], SMBBLKDAT);
+		}
+		size = ALI15X3_BLOCK_DATA;
+		break;
+	default:
+		printk
+		    (KERN_WARNING "i2c-ali15x3.o: Unsupported transaction %d\n", size);
+		return -1;
+	}
+
+	outb_p(size, SMBHSTCNT);	/* output command */
+
+	if (ali15x3_transaction(adap))	/* Error in transaction */
+		return -1;
+
+	if ((read_write == I2C_SMBUS_WRITE) || (size == ALI15X3_QUICK))
+		return 0;
+
+
+	switch (size) {
+	case ALI15X3_BYTE:	/* Result put in SMBHSTDAT0 */
+		data->byte = inb_p(SMBHSTDAT0);
+		break;
+	case ALI15X3_BYTE_DATA:
+		data->byte = inb_p(SMBHSTDAT0);
+		break;
+	case ALI15X3_WORD_DATA:
+		data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);
+		break;
+	case ALI15X3_BLOCK_DATA:
+		len = inb_p(SMBHSTDAT0);
+		if (len > 32)
+			len = 32;
+		data->block[0] = len;
+		/* Reset SMBBLKDAT */
+		outb_p(inb_p(SMBHSTCNT) | ALI15X3_BLOCK_CLR, SMBHSTCNT);
+		for (i = 1; i <= data->block[0]; i++) {
+			data->block[i] = inb_p(SMBBLKDAT);
+			dev_dbg(adap, "Blk: len=%d, i=%d, data=%02x\n",
+				len, i, data->block[i]);
+		}
+		break;
+	}
+	return 0;
+}
+
+static u32 ali15x3_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+	    I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+	    I2C_FUNC_SMBUS_BLOCK_DATA;
+}
+
+static struct i2c_algorithm smbus_algorithm = {
+	.name		= "Non-I2C SMBus adapter",
+	.id		= I2C_ALGO_SMBUS,
+	.smbus_xfer	= ali15x3_access,
+	.functionality	= ali15x3_func,
+};
+
+static struct i2c_adapter ali15x3_adapter = {
+	.owner		= THIS_MODULE,
+	.id		= I2C_ALGO_SMBUS | I2C_HW_SMBUS_ALI15X3,
+	.algo		= &smbus_algorithm,
+	.name	= "unset",
+};
+
+static struct pci_device_id ali15x3_ids[] __devinitdata = {
+	{
+	.vendor =	PCI_VENDOR_ID_AL,
+	.device =	PCI_DEVICE_ID_AL_M7101,
+	.subvendor =	PCI_ANY_ID,
+	.subdevice =	PCI_ANY_ID,
+	},
+	{ 0, }
+};
+
+static int __devinit ali15x3_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	if (ali15x3_setup(dev)) {
+		dev_err(dev,
+			"ALI15X3 not detected, module not inserted.\n");
+		return -ENODEV;
+	}
+
+	snprintf(ali15x3_adapter.name, 32,
+		"SMBus ALI15X3 adapter at %04x", ali15x3_smba);
+	return i2c_add_adapter(&ali15x3_adapter);
+}
+
+static void __devexit ali15x3_remove(struct pci_dev *dev)
+{
+	i2c_del_adapter(&ali15x3_adapter);
+	release_region(ali15x3_smba, ALI15X3_SMB_IOSIZE);
+}
+
+static struct pci_driver ali15x3_driver = {
+	.name		= "ali15x3 smbus",
+	.id_table	= ali15x3_ids,
+	.probe		= ali15x3_probe,
+	.remove		= __devexit_p(ali15x3_remove),
+};
+
+static int __init i2c_ali15x3_init(void)
+{
+	printk("i2c-ali15x3.o version %s (%s)\n", LM_VERSION, LM_DATE);
+	return pci_module_init(&ali15x3_driver);
+}
+
+static void __exit i2c_ali15x3_exit(void)
+{
+	pci_unregister_driver(&ali15x3_driver);
+}
+
+MODULE_AUTHOR ("Frodo Looijaard <frodol@dds.nl>, "
+		"Philip Edelbrock <phil@netroedge.com>, "
+		"and Mark D. Studebaker <mdsxyz123@yahoo.com>");
+MODULE_DESCRIPTION("ALI15X3 SMBus driver");
+MODULE_LICENSE("GPL");
+
+module_init(i2c_ali15x3_init);
+module_exit(i2c_ali15x3_exit);
diff -urN --exclude-from=diff-exclude linux-2.4.27/drivers/i2c/i2c-amd756.c linux-2.4.27-leo/drivers/i2c/i2c-amd756.c
--- linux-2.4.27/drivers/i2c/i2c-amd756.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.27-leo/drivers/i2c/i2c-amd756.c	2004-09-20 21:34:47.000000000 +0100
@@ -0,0 +1,425 @@
+/*
+    amd756.c - Part of lm_sensors, Linux kernel modules for hardware
+              monitoring
+
+    Copyright (c) 1999-2002 Merlin Hughes <merlin@merlin.org>
+
+    Shamelessly ripped from i2c-piix4.c:
+
+    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl> and
+    Philip Edelbrock <phil@netroedge.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+    2002-04-08: Added nForce support. (Csaba Halasz)
+    2002-10-03: Fixed nForce PnP I/O port. (Michael Steil)
+    2002-12-28: Rewritten into something that resembles a Linux driver (hch)
+    2003-11-29: Added back AMD8111 removed by the previous rewrite.
+                (Philip Pokorny)
+    2004-02-15: Don't register driver to avoid driver conflicts.
+                (Daniel Rune Jensen)
+*/
+
+/*
+   Supports AMD756, AMD766, AMD768, AMD8111 and nVidia nForce
+   Note: we assume there can only be one device, with one SMBus interface.
+*/
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#define LM_DATE "20040611"
+#define LM_VERSION "2.8.7"
+
+#define DRV_NAME	"i2c-amd756"
+
+/* AMD756 SMBus address offsets */
+#define SMB_ADDR_OFFSET        0xE0
+#define SMB_IOSIZE             16
+#define SMB_GLOBAL_STATUS      (0x0 + amd756_ioport)
+#define SMB_GLOBAL_ENABLE      (0x2 + amd756_ioport)
+#define SMB_HOST_ADDRESS       (0x4 + amd756_ioport)
+#define SMB_HOST_DATA          (0x6 + amd756_ioport)
+#define SMB_HOST_COMMAND       (0x8 + amd756_ioport)
+#define SMB_HOST_BLOCK_DATA    (0x9 + amd756_ioport)
+#define SMB_HAS_DATA           (0xA + amd756_ioport)
+#define SMB_HAS_DEVICE_ADDRESS (0xC + amd756_ioport)
+#define SMB_HAS_HOST_ADDRESS   (0xE + amd756_ioport)
+#define SMB_SNOOP_ADDRESS      (0xF + amd756_ioport)
+
+/* PCI Address Constants */
+
+/* address of I/O space */
+#define SMBBA     0x058		/* mh */
+#define SMBBANFORCE     0x014
+
+/* general configuration */
+#define SMBGCFG   0x041		/* mh */
+
+/* silicon revision code */
+#define SMBREV    0x008
+
+/* Other settings */
+#define MAX_TIMEOUT 500
+
+/* AMD756 constants */
+#define AMD756_QUICK        0x00
+#define AMD756_BYTE         0x01
+#define AMD756_BYTE_DATA    0x02
+#define AMD756_WORD_DATA    0x03
+#define AMD756_PROCESS_CALL 0x04
+#define AMD756_BLOCK_DATA   0x05
+
+
+static unsigned short amd756_ioport = 0;
+
+/* 
+  SMBUS event = I/O 28-29 bit 11
+     see E0 for the status bits and enabled in E2
+     
+*/
+
+#define GS_ABRT_STS (1 << 0)
+#define GS_COL_STS (1 << 1)
+#define GS_PRERR_STS (1 << 2)
+#define GS_HST_STS (1 << 3)
+#define GS_HCYC_STS (1 << 4)
+#define GS_TO_STS (1 << 5)
+#define GS_SMB_STS (1 << 11)
+
+#define GS_CLEAR_STS (GS_ABRT_STS | GS_COL_STS | GS_PRERR_STS | \
+  GS_HCYC_STS | GS_TO_STS )
+
+#define GE_CYC_TYPE_MASK (7)
+#define GE_HOST_STC (1 << 3)
+#define GE_ABORT (1 << 5)
+
+
+static int amd756_transaction(void)
+{
+	int temp;
+	int result = 0;
+	int timeout = 0;
+
+	pr_debug(DRV_NAME
+	       ": Transaction (pre): GS=%04x, GE=%04x, ADD=%04x, DAT=%04x\n",
+	       inw_p(SMB_GLOBAL_STATUS), inw_p(SMB_GLOBAL_ENABLE),
+	       inw_p(SMB_HOST_ADDRESS), inb_p(SMB_HOST_DATA));
+
+	/* Make sure the SMBus host is ready to start transmitting */
+	if ((temp = inw_p(SMB_GLOBAL_STATUS)) & (GS_HST_STS | GS_SMB_STS)) {
+		pr_debug(DRV_NAME ": SMBus busy (%04x). Waiting... \n", temp);
+		do {
+			i2c_delay(1);
+			temp = inw_p(SMB_GLOBAL_STATUS);
+		} while ((temp & (GS_HST_STS | GS_SMB_STS)) &&
+		         (timeout++ < MAX_TIMEOUT));
+		/* If the SMBus is still busy, we give up */
+		if (timeout >= MAX_TIMEOUT) {
+			pr_debug(DRV_NAME ": Busy wait timeout (%04x)\n", temp);
+			goto abort;
+		}
+		timeout = 0;
+	}
+
+	/* start the transaction by setting the start bit */
+	outw_p(inw(SMB_GLOBAL_ENABLE) | GE_HOST_STC, SMB_GLOBAL_ENABLE);
+
+	/* We will always wait for a fraction of a second! */
+	do {
+		i2c_delay(1);
+		temp = inw_p(SMB_GLOBAL_STATUS);
+	} while ((temp & GS_HST_STS) && (timeout++ < MAX_TIMEOUT));
+
+	/* If the SMBus is still busy, we give up */
+	if (timeout >= MAX_TIMEOUT) {
+		pr_debug(DRV_NAME ": Completion timeout!\n");
+		goto abort;
+	}
+
+	if (temp & GS_PRERR_STS) {
+		result = -1;
+		pr_debug(DRV_NAME ": SMBus Protocol error (no response)!\n");
+	}
+
+	if (temp & GS_COL_STS) {
+		result = -1;
+		printk(KERN_WARNING DRV_NAME ": SMBus collision!\n");
+	}
+
+	if (temp & GS_TO_STS) {
+		result = -1;
+		pr_debug(DRV_NAME ": SMBus protocol timeout!\n");
+	}
+
+	if (temp & GS_HCYC_STS)
+		pr_debug(DRV_NAME ": SMBus protocol success!\n");
+
+	outw_p(GS_CLEAR_STS, SMB_GLOBAL_STATUS);
+
+#ifdef DEBUG
+	if (((temp = inw_p(SMB_GLOBAL_STATUS)) & GS_CLEAR_STS) != 0x00) {
+		pr_debug(DRV_NAME
+		         ": Failed reset at end of transaction (%04x)\n", temp);
+	}
+
+	pr_debug(DRV_NAME
+		 ": Transaction (post): GS=%04x, GE=%04x, ADD=%04x, DAT=%04x\n",
+		 inw_p(SMB_GLOBAL_STATUS), inw_p(SMB_GLOBAL_ENABLE),
+		 inw_p(SMB_HOST_ADDRESS), inb_p(SMB_HOST_DATA));
+#endif
+
+	return result;
+
+ abort:
+	printk(KERN_WARNING DRV_NAME ": Sending abort.\n");
+	outw_p(inw(SMB_GLOBAL_ENABLE) | GE_ABORT, SMB_GLOBAL_ENABLE);
+	i2c_delay(100);
+	outw_p(GS_CLEAR_STS, SMB_GLOBAL_STATUS);
+	return -1;
+}
+
+/* Return -1 on error. */
+
+static s32 amd756_access(struct i2c_adapter * adap, u16 addr,
+		  unsigned short flags, char read_write,
+		  u8 command, int size, union i2c_smbus_data * data)
+{
+	int i, len;
+
+	/** TODO: Should I supporte the 10-bit transfers? */
+	switch (size) {
+	/* TODO: proc call is supported, I'm just not sure what to do here... */
+	case I2C_SMBUS_QUICK:
+		outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+		       SMB_HOST_ADDRESS);
+		size = AMD756_QUICK;
+		break;
+	case I2C_SMBUS_BYTE:
+		outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+		       SMB_HOST_ADDRESS);
+		if (read_write == I2C_SMBUS_WRITE)
+			outb_p(command, SMB_HOST_DATA);
+		size = AMD756_BYTE;
+		break;
+	case I2C_SMBUS_BYTE_DATA:
+		outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+		       SMB_HOST_ADDRESS);
+		outb_p(command, SMB_HOST_COMMAND);
+		if (read_write == I2C_SMBUS_WRITE)
+			outw_p(data->byte, SMB_HOST_DATA);
+		size = AMD756_BYTE_DATA;
+		break;
+	case I2C_SMBUS_WORD_DATA:
+		outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+		       SMB_HOST_ADDRESS);
+		outb_p(command, SMB_HOST_COMMAND);
+		if (read_write == I2C_SMBUS_WRITE)
+			outw_p(data->word, SMB_HOST_DATA);	/* TODO: endian???? */
+		size = AMD756_WORD_DATA;
+		break;
+	case I2C_SMBUS_BLOCK_DATA:
+		outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+		       SMB_HOST_ADDRESS);
+		outb_p(command, SMB_HOST_COMMAND);
+		if (read_write == I2C_SMBUS_WRITE) {
+			len = data->block[0];
+			if (len < 0)
+				len = 0;
+			if (len > 32)
+				len = 32;
+			outw_p(len, SMB_HOST_DATA);
+			/* i = inw_p(SMBHSTCNT); Reset SMBBLKDAT */
+			for (i = 1; i <= len; i++)
+				outb_p(data->block[i],
+				       SMB_HOST_BLOCK_DATA);
+		}
+		size = AMD756_BLOCK_DATA;
+		break;
+	default:
+		printk
+		    (KERN_WARNING "i2c-amd756.o: Unsupported transaction %d\n", size);
+		return -1;
+	}
+
+	/* How about enabling interrupts... */
+	outw_p(size & GE_CYC_TYPE_MASK, SMB_GLOBAL_ENABLE);
+
+	if (amd756_transaction())	/* Error in transaction */
+		return -1;
+
+	if ((read_write == I2C_SMBUS_WRITE) || (size == AMD756_QUICK))
+		return 0;
+
+
+	switch (size) {
+	case AMD756_BYTE:
+		data->byte = inw_p(SMB_HOST_DATA);
+		break;
+	case AMD756_BYTE_DATA:
+		data->byte = inw_p(SMB_HOST_DATA);
+		break;
+	case AMD756_WORD_DATA:
+		data->word = inw_p(SMB_HOST_DATA);	/* TODO: endian???? */
+		break;
+	case AMD756_BLOCK_DATA:
+		data->block[0] = inw_p(SMB_HOST_DATA) & 0x3f;
+		if(data->block[0] > 32)
+			data->block[0] = 32;
+		/* i = inw_p(SMBHSTCNT); Reset SMBBLKDAT */
+		for (i = 1; i <= data->block[0]; i++)
+			data->block[i] = inb_p(SMB_HOST_BLOCK_DATA);
+		break;
+	}
+
+	return 0;
+}
+
+static u32 amd756_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+	    I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+	    I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_PROC_CALL;
+}
+
+static struct i2c_algorithm smbus_algorithm = {
+	.name		= "Non-I2C SMBus adapter",
+	.id		= I2C_ALGO_SMBUS,
+	.smbus_xfer	= amd756_access,
+	.functionality	= amd756_func,
+};
+
+static struct i2c_adapter amd756_adapter = {
+	.owner		= THIS_MODULE,
+	.name		= "unset",
+	.id		= I2C_ALGO_SMBUS | I2C_HW_SMBUS_AMD756,
+	.algo		= &smbus_algorithm,
+};
+
+enum chiptype { AMD756, AMD766, AMD768, NFORCE, AMD8111 };
+
+static struct pci_device_id amd756_ids[] __devinitdata = {
+	{PCI_VENDOR_ID_AMD, 0x740B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD756 },
+	{PCI_VENDOR_ID_AMD, 0x7413, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD766 },
+	{PCI_VENDOR_ID_AMD, 0x7443, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD768 },
+	{PCI_VENDOR_ID_AMD, 0x746B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD8111 },
+	{PCI_VENDOR_ID_NVIDIA, 0x01B4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE },
+	{ 0, }
+};
+
+static int __devinit amd756_probe(struct pci_dev *pdev,
+				  const struct pci_device_id *id)
+{
+	int nforce = (id->driver_data == NFORCE);
+	int error;
+	u8 temp;
+	
+	if (amd756_ioport) {
+		printk(KERN_ERR DRV_NAME ": Only one device supported. "
+		       "(you have a strange motherboard, btw..)\n");
+		return -ENODEV;
+	}
+
+	if (nforce) {
+		if (PCI_FUNC(pdev->devfn) != 1)
+			return -ENODEV;
+
+		pci_read_config_word(pdev, SMBBANFORCE, &amd756_ioport);
+		amd756_ioport &= 0xfffc;
+	} else { /* amd */
+		if (PCI_FUNC(pdev->devfn) != 3)
+			return -ENODEV;
+
+		pci_read_config_byte(pdev, SMBGCFG, &temp);
+		if ((temp & 128) == 0) {
+			printk(KERN_ERR DRV_NAME
+			       ": Error: SMBus controller I/O not enabled!\n");
+			return -ENODEV;
+		}
+
+		/* Determine the address of the SMBus areas */
+		/* Technically it is a dword but... */
+		pci_read_config_word(pdev, SMBBA, &amd756_ioport);
+		amd756_ioport &= 0xff00;
+		amd756_ioport += SMB_ADDR_OFFSET;
+	}
+
+	if (!request_region(amd756_ioport, SMB_IOSIZE, "amd756-smbus")) {
+		printk(KERN_ERR DRV_NAME
+		       ": SMB region 0x%x already in use!\n", amd756_ioport);
+		return -ENODEV;
+	}
+
+#ifdef DEBUG
+	pci_read_config_byte(pdev, SMBREV, &temp);
+	printk(KERN_DEBUG DRV_NAME ": SMBREV = 0x%X\n", temp);
+	printk(KERN_DEBUG DRV_NAME ": AMD756_smba = 0x%X\n", amd756_ioport);
+#endif
+
+	sprintf(amd756_adapter.name,
+		"SMBus AMD756 adapter at %04x", amd756_ioport);
+
+	error = i2c_add_adapter(&amd756_adapter);
+	if (error) {
+		printk(KERN_ERR DRV_NAME
+		       ": Adapter registration failed, module not inserted.\n");
+		goto out_err;
+	}
+
+	return 0;
+
+ out_err:
+	release_region(amd756_ioport, SMB_IOSIZE);
+	return error;
+}
+
+
+static int __init i2c_amd756_init(void)
+{
+	struct pci_dev *dev;
+	const struct pci_device_id *id;
+
+	printk(KERN_INFO "i2c-amd756.o version %s (%s)\n", LM_VERSION, LM_DATE);
+
+ 	pci_for_each_dev(dev) {
+		id = pci_match_device(amd756_ids, dev);
+		if (id && amd756_probe(dev, id) >= 0)
+			return 0; 
+	}
+
+	return -ENODEV;
+}
+
+
+static void __exit i2c_amd756_exit(void)
+{
+	i2c_del_adapter(&amd756_adapter);
+	release_region(amd756_ioport, SMB_IOSIZE);
+}
+
+MODULE_AUTHOR("Merlin Hughes <merlin@merlin.org>");
+MODULE_DESCRIPTION("AMD756/766/768/8111 and nVidia nForce SMBus driver");
+MODULE_LICENSE("GPL");
+
+module_init(i2c_amd756_init)
+module_exit(i2c_amd756_exit)
diff -urN --exclude-from=diff-exclude linux-2.4.27/drivers/i2c/i2c-amd8111.c linux-2.4.27-leo/drivers/i2c/i2c-amd8111.c
--- linux-2.4.27/drivers/i2c/i2c-amd8111.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.27-leo/drivers/i2c/i2c-amd8111.c	2004-09-20 21:34:47.000000000 +0100
@@ -0,0 +1,421 @@
+/*
+ * SMBus 2.0 driver for AMD-8111 IO-Hub.
+ *
+ * Copyright (c) 2002 Vojtech Pavlik
+ *
+ * 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 version 2.
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <asm/io.h>
+#define LM_DATE "20040611"
+#define LM_VERSION "2.8.7"
+
+#ifndef I2C_HW_SMBUS_AMD8111
+#error Your i2c is too old - i2c-2.7.0 or greater required!
+#endif
+
+/* kernel 2.4.9 needs this */
+#ifndef min_t
+#define min_t(type,x,y) min(type,x,y)
+#endif
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR ("Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_DESCRIPTION("AMD8111 SMBus 2.0 driver");
+
+struct amd_smbus {
+	struct pci_dev *dev;
+	struct i2c_adapter adapter;
+	int base;
+	int size;
+};
+
+/*
+ * AMD PCI control registers definitions.
+ */
+
+#define AMD_PCI_MISC	0x48
+
+#define AMD_PCI_MISC_SCI	0x04	/* deliver SCI */
+#define AMD_PCI_MISC_INT	0x02	/* deliver PCI IRQ */
+#define AMD_PCI_MISC_SPEEDUP	0x01	/* 16x clock speedup */
+
+/*
+ * ACPI 2.0 chapter 13 PCI interface definitions.
+ */
+
+#define AMD_EC_DATA	0x00	/* data register */
+#define AMD_EC_SC	0x04	/* status of controller */
+#define AMD_EC_CMD	0x04	/* command register */
+#define AMD_EC_ICR	0x08	/* interrupt control register */
+
+#define AMD_EC_SC_SMI	0x04	/* smi event pending */
+#define AMD_EC_SC_SCI	0x02	/* sci event pending */
+#define AMD_EC_SC_BURST	0x01	/* burst mode enabled */
+#define AMD_EC_SC_CMD	0x08	/* byte in data reg is command */
+#define AMD_EC_SC_IBF	0x02	/* data ready for embedded controller */
+#define AMD_EC_SC_OBF	0x01	/* data ready for host */
+
+#define AMD_EC_CMD_RD	0x80	/* read EC */
+#define AMD_EC_CMD_WR	0x81	/* write EC */
+#define AMD_EC_CMD_BE	0x82	/* enable burst mode */
+#define AMD_EC_CMD_BD	0x83	/* disable burst mode */
+#define AMD_EC_CMD_QR	0x84	/* query EC */
+
+/*
+ * ACPI 2.0 chapter 13 access of registers of the EC
+ */
+
+unsigned int amd_ec_wait_write(struct amd_smbus *smbus)
+{
+	int timeout = 500;
+
+	while (timeout-- && (inb(smbus->base + AMD_EC_SC) & AMD_EC_SC_IBF))
+		udelay(1);
+
+	if (!timeout) {
+		printk(KERN_WARNING "i2c-amd8111.c: Timeout while waiting for IBF to clear\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+unsigned int amd_ec_wait_read(struct amd_smbus *smbus)
+{
+	int timeout = 500;
+
+	while (timeout-- && (~inb(smbus->base + AMD_EC_SC) & AMD_EC_SC_OBF))
+		udelay(1);
+
+	if (!timeout) {
+		printk(KERN_WARNING "i2c-amd8111.c: Timeout while waiting for OBF to set\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+unsigned int amd_ec_read(struct amd_smbus *smbus, unsigned char address, unsigned char *data)
+{
+	if (amd_ec_wait_write(smbus))
+		return -1;
+	outb(AMD_EC_CMD_RD, smbus->base + AMD_EC_CMD);
+
+	if (amd_ec_wait_write(smbus))
+		return -1;
+	outb(address, smbus->base + AMD_EC_DATA);
+
+	if (amd_ec_wait_read(smbus))
+		return -1;
+	*data = inb(smbus->base + AMD_EC_DATA);
+
+	return 0;
+}
+
+unsigned int amd_ec_write(struct amd_smbus *smbus, unsigned char address, unsigned char data)
+{
+	if (amd_ec_wait_write(smbus))
+		return -1;
+	outb(AMD_EC_CMD_WR, smbus->base + AMD_EC_CMD);
+
+	if (amd_ec_wait_write(smbus))
+		return -1;
+	outb(address, smbus->base + AMD_EC_DATA);
+
+	if (amd_ec_wait_write(smbus))
+		return -1;
+	outb(data, smbus->base + AMD_EC_DATA);
+
+	return 0;
+}
+
+/*
+ * ACPI 2.0 chapter 13 SMBus 2.0 EC register model
+ */
+
+#define AMD_SMB_PRTCL	0x00	/* protocol, PEC */
+#define AMD_SMB_STS	0x01	/* status */
+#define AMD_SMB_ADDR	0x02	/* address */
+#define AMD_SMB_CMD	0x03	/* command */
+#define AMD_SMB_DATA	0x04	/* 32 data registers */
+#define AMD_SMB_BCNT	0x24	/* number of data bytes */
+#define AMD_SMB_ALRM_A	0x25	/* alarm address */
+#define AMD_SMB_ALRM_D	0x26	/* 2 bytes alarm data */
+
+#define AMD_SMB_STS_DONE	0x80
+#define AMD_SMB_STS_ALRM	0x40
+#define AMD_SMB_STS_RES		0x20
+#define AMD_SMB_STS_STATUS	0x1f
+
+#define AMD_SMB_STATUS_OK	0x00
+#define AMD_SMB_STATUS_FAIL	0x07
+#define AMD_SMB_STATUS_DNAK	0x10
+#define AMD_SMB_STATUS_DERR	0x11
+#define AMD_SMB_STATUS_CMD_DENY	0x12
+#define AMD_SMB_STATUS_UNKNOWN	0x13
+#define AMD_SMB_STATUS_ACC_DENY	0x17
+#define AMD_SMB_STATUS_TIMEOUT	0x18
+#define AMD_SMB_STATUS_NOTSUP	0x19
+#define AMD_SMB_STATUS_BUSY	0x1A
+#define AMD_SMB_STATUS_PEC	0x1F
+
+#define AMD_SMB_PRTCL_WRITE		0x00
+#define AMD_SMB_PRTCL_READ		0x01
+#define AMD_SMB_PRTCL_QUICK		0x02
+#define AMD_SMB_PRTCL_BYTE		0x04
+#define AMD_SMB_PRTCL_BYTE_DATA		0x06
+#define AMD_SMB_PRTCL_WORD_DATA		0x08
+#define AMD_SMB_PRTCL_BLOCK_DATA	0x0a
+#define AMD_SMB_PRTCL_PROC_CALL		0x0c
+#define AMD_SMB_PRTCL_BLOCK_PROC_CALL	0x0d
+#define AMD_SMB_PRTCL_I2C_BLOCK_DATA	0x4a
+#define AMD_SMB_PRTCL_PEC		0x80
+
+
+s32 amd8111_access(struct i2c_adapter * adap, u16 addr, unsigned short flags,
+		char read_write, u8 command, int size, union i2c_smbus_data * data)
+{
+	struct amd_smbus *smbus = adap->algo_data;
+	unsigned char protocol, len, pec, temp[2];
+	int i;
+
+	protocol = (read_write == I2C_SMBUS_READ) ? AMD_SMB_PRTCL_READ : AMD_SMB_PRTCL_WRITE;
+	pec = (flags & I2C_CLIENT_PEC) ? AMD_SMB_PRTCL_PEC : 0;
+
+	switch (size) {
+
+		case I2C_SMBUS_QUICK:
+			protocol |= AMD_SMB_PRTCL_QUICK;
+			read_write = I2C_SMBUS_WRITE;
+			break;
+
+		case I2C_SMBUS_BYTE:
+			if (read_write == I2C_SMBUS_WRITE)
+				amd_ec_write(smbus, AMD_SMB_CMD, command);
+			protocol |= AMD_SMB_PRTCL_BYTE;
+			break;
+
+		case I2C_SMBUS_BYTE_DATA:
+			amd_ec_write(smbus, AMD_SMB_CMD, command);
+			if (read_write == I2C_SMBUS_WRITE)
+				amd_ec_write(smbus, AMD_SMB_DATA, data->byte);
+			protocol |= AMD_SMB_PRTCL_BYTE_DATA;
+			break;
+
+		case I2C_SMBUS_WORD_DATA:
+			amd_ec_write(smbus, AMD_SMB_CMD, command);
+			if (read_write == I2C_SMBUS_WRITE) {
+				amd_ec_write(smbus, AMD_SMB_DATA, data->word);
+				amd_ec_write(smbus, AMD_SMB_DATA + 1, data->word >> 8);
+			}
+			protocol |= AMD_SMB_PRTCL_WORD_DATA | pec;
+			break;
+
+		case I2C_SMBUS_BLOCK_DATA:
+			amd_ec_write(smbus, AMD_SMB_CMD, command);
+			if (read_write == I2C_SMBUS_WRITE) {
+				len = min_t(u8, data->block[0], 32);
+				amd_ec_write(smbus, AMD_SMB_BCNT, len);
+				for (i = 0; i < len; i++)
+					amd_ec_write(smbus, AMD_SMB_DATA + i, data->block[i + 1]);
+			}
+			protocol |= AMD_SMB_PRTCL_BLOCK_DATA | pec;
+			break;
+
+		case I2C_SMBUS_I2C_BLOCK_DATA:
+			len = min_t(u8, data->block[0], 32);
+			amd_ec_write(smbus, AMD_SMB_CMD, command);
+			amd_ec_write(smbus, AMD_SMB_BCNT, len);
+			if (read_write == I2C_SMBUS_WRITE)
+				for (i = 0; i < len; i++)
+					amd_ec_write(smbus, AMD_SMB_DATA + i, data->block[i + 1]);
+			protocol |= AMD_SMB_PRTCL_I2C_BLOCK_DATA;
+			break;
+
+		case I2C_SMBUS_PROC_CALL:
+			amd_ec_write(smbus, AMD_SMB_CMD, command);
+			amd_ec_write(smbus, AMD_SMB_DATA, data->word);
+			amd_ec_write(smbus, AMD_SMB_DATA + 1, data->word >> 8);
+			protocol = AMD_SMB_PRTCL_PROC_CALL | pec;
+			read_write = I2C_SMBUS_READ;
+			break;
+
+		case I2C_SMBUS_BLOCK_PROC_CALL:
+			protocol |= pec;
+			len = min_t(u8, data->block[0], 31);
+			amd_ec_write(smbus, AMD_SMB_CMD, command);
+			amd_ec_write(smbus, AMD_SMB_BCNT, len);
+			for (i = 0; i < len; i++)
+				amd_ec_write(smbus, AMD_SMB_DATA + i, data->block[i + 1]);
+			protocol = AMD_SMB_PRTCL_BLOCK_PROC_CALL | pec;
+			read_write = I2C_SMBUS_READ;
+			break;
+
+		case I2C_SMBUS_WORD_DATA_PEC:
+		case I2C_SMBUS_BLOCK_DATA_PEC:
+		case I2C_SMBUS_PROC_CALL_PEC:
+		case I2C_SMBUS_BLOCK_PROC_CALL_PEC:
+			printk(KERN_WARNING "i2c-amd8111.c: Unexpected software PEC transaction %d\n.", size);
+			return -1;
+
+		default:
+			printk(KERN_WARNING "i2c-amd8111.c: Unsupported transaction %d\n", size);
+			return -1;
+	}
+
+	amd_ec_write(smbus, AMD_SMB_ADDR, addr << 1);
+	amd_ec_write(smbus, AMD_SMB_PRTCL, protocol);
+
+	amd_ec_read(smbus, AMD_SMB_STS, temp + 0);
+
+	if (~temp[0] & AMD_SMB_STS_DONE) {
+		udelay(500);
+		amd_ec_read(smbus, AMD_SMB_STS, temp + 0);
+	}
+
+	if (~temp[0] & AMD_SMB_STS_DONE) {
+		i2c_delay(HZ/100);
+		amd_ec_read(smbus, AMD_SMB_STS, temp + 0);
+	}
+
+	if ((~temp[0] & AMD_SMB_STS_DONE) || (temp[0] & AMD_SMB_STS_STATUS))
+		return -1;
+
+	if (read_write == I2C_SMBUS_WRITE)
+		return 0;
+
+	switch (size) {
+
+		case I2C_SMBUS_BYTE:
+		case I2C_SMBUS_BYTE_DATA:
+			amd_ec_read(smbus, AMD_SMB_DATA, &data->byte);
+			break;
+
+		case I2C_SMBUS_WORD_DATA:
+		case I2C_SMBUS_PROC_CALL:
+			amd_ec_read(smbus, AMD_SMB_DATA, temp + 0);
+			amd_ec_read(smbus, AMD_SMB_DATA + 1, temp + 1);
+			data->word = (temp[1] << 8) | temp[0];
+			break;
+
+		case I2C_SMBUS_BLOCK_DATA:
+		case I2C_SMBUS_BLOCK_PROC_CALL:
+			amd_ec_read(smbus, AMD_SMB_BCNT, &len);
+			len = min_t(u8, len, 32);
+		case I2C_SMBUS_I2C_BLOCK_DATA:
+			for (i = 0; i < len; i++)
+				amd_ec_read(smbus, AMD_SMB_DATA + i, data->block + i + 1);
+			data->block[0] = len;
+			break;
+	}
+
+	return 0;
+}
+
+
+u32 amd8111_func(struct i2c_adapter *adapter)
+{
+	return	I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA |
+		I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA |
+		I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
+		I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_HWPEC_CALC;
+}
+
+static struct i2c_algorithm smbus_algorithm = {
+	.name = "Non-I2C SMBus 2.0 adapter",
+	.id = I2C_ALGO_SMBUS,
+	.smbus_xfer = amd8111_access,
+	.functionality = amd8111_func,
+};
+
+
+static struct pci_device_id amd8111_ids[] __devinitdata = {
+	{ 0x1022, 0x746a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ 0, }
+};
+
+static int __devinit amd8111_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	struct amd_smbus *smbus;
+	int error;
+
+	if (~pci_resource_flags(dev, 0) & IORESOURCE_IO)
+		return -1;
+
+	if (!(smbus = (void*)kmalloc(sizeof(struct amd_smbus), GFP_KERNEL)))
+		return -1;
+	memset(smbus, 0, sizeof(struct amd_smbus));
+
+	pci_set_drvdata(dev, smbus);
+	smbus->dev = dev;
+	smbus->base = pci_resource_start(dev, 0);
+	smbus->size = pci_resource_len(dev, 0);
+
+	if (!request_region(smbus->base, smbus->size, "amd8111 SMBus 2.0")) {
+		kfree(smbus);
+		return -1;
+	}
+
+	smbus->adapter.owner = THIS_MODULE;
+	sprintf(smbus->adapter.name, "SMBus2 AMD8111 adapter at %04x", smbus->base);
+	smbus->adapter.id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_AMD8111;
+	smbus->adapter.algo = &smbus_algorithm;
+	smbus->adapter.algo_data = smbus;
+
+	error = i2c_add_adapter(&smbus->adapter);
+	if (error) {
+		printk(KERN_WARNING "i2c-amd8111.c: Failed to register adapter.\n");
+		release_region(smbus->base, smbus->size);
+		kfree(smbus);
+		return -1;
+	}
+
+	pci_write_config_dword(smbus->dev, AMD_PCI_MISC, 0);
+
+	printk(KERN_INFO "i2c-amd8111.c: AMD8111 SMBus 2.0 adapter at %#x\n", smbus->base);
+	return 0;
+}
+
+
+static void __devexit amd8111_remove(struct pci_dev *dev)
+{
+	struct amd_smbus *smbus = (void*) pci_get_drvdata(dev);
+	i2c_del_adapter(&smbus->adapter);
+	release_region(smbus->base, smbus->size);
+	kfree(smbus);
+}
+
+static struct pci_driver amd8111_driver = {
+	.name		= "amd8111 smbus 2.0",
+	.id_table	= amd8111_ids,
+	.probe		= amd8111_probe,
+	.remove		= __devexit_p(amd8111_remove),
+};
+
+static int __init i2c_amd8111_init(void)
+{
+	printk(KERN_INFO "i2c-amd8111.o version %s (%s)\n", LM_VERSION, LM_DATE);
+	return pci_module_init(&amd8111_driver);
+}
+
+
+static void __exit i2c_amd8111_exit(void)
+{
+	pci_unregister_driver(&amd8111_driver);
+}
+
+module_init(i2c_amd8111_init);
+module_exit(i2c_amd8111_exit);
diff -urN --exclude-from=diff-exclude linux-2.4.27/drivers/i2c/i2c-core.c linux-2.4.27-leo/drivers/i2c/i2c-core.c
--- linux-2.4.27/drivers/i2c/i2c-core.c	2004-02-20 14:11:41.000000000 +0000
+++ linux-2.4.27-leo/drivers/i2c/i2c-core.c	2004-09-20 21:34:38.000000000 +0100
@@ -18,56 +18,33 @@
 /* ------------------------------------------------------------------------- */
 
 /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi>.
-   All SMBus-related things are written by Frodo Looijaard <frodol@dds.nl> */
+   All SMBus-related things are written by Frodo Looijaard <frodol@dds.nl>
+   SMBus 2.0 support by Mark Studebaker <mdsxyz123@yahoo.com>                */
 
-/* $Id: i2c-core.c,v 1.64 2001/08/13 01:35:56 mds Exp $ */
+/* i2c-core.c,v 1.91.2.2 2003/01/21 10:00:19 kmalkki Exp */
 
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/proc_fs.h>
-#include <linux/config.h>
-
-#include <linux/i2c.h>
-
-/* ----- compatibility stuff ----------------------------------------------- */
-
 #include <linux/init.h>
-
+#include <linux/i2c.h>
 #include <asm/uaccess.h>
 
 /* ----- global defines ---------------------------------------------------- */
 
-/* exclusive access to the bus */
-#define I2C_LOCK(adap) down(&adap->lock)
-#define I2C_UNLOCK(adap) up(&adap->lock) 
-
-#define ADAP_LOCK()	down(&adap_lock)
-#define ADAP_UNLOCK()	up(&adap_lock)
-
-#define DRV_LOCK()	down(&driver_lock)
-#define DRV_UNLOCK()	up(&driver_lock)
-
 #define DEB(x) if (i2c_debug>=1) x;
 #define DEB2(x) if (i2c_debug>=2) x;
 
 /* ----- global variables -------------------------------------------------- */
 
-/**** lock for writing to global variables: the adapter & driver list */
-struct semaphore adap_lock;
-struct semaphore driver_lock;
-
-/**** adapter list */
+DECLARE_MUTEX(core_lists);
 static struct i2c_adapter *adapters[I2C_ADAP_MAX];
-static int adap_count;
-
-/**** drivers list */
 static struct i2c_driver *drivers[I2C_DRIVER_MAX];
-static int driver_count;
 
 /**** debug level */
-static int i2c_debug=1;
+static int i2c_debug;
 
 /* ---------------------------------------------------
  * /proc entry declarations
@@ -75,10 +52,6 @@
  */
 
 #ifdef CONFIG_PROC_FS
-
-static int i2cproc_init(void);
-static int i2cproc_cleanup(void);
-
 static ssize_t i2cproc_bus_read(struct file * file, char * buf,size_t count, 
                                 loff_t *ppos);
 static int read_bus_i2c(char *buf, char **start, off_t offset, int len,
@@ -87,15 +60,11 @@
 /* To implement the dynamic /proc/bus/i2c-? files, we need our own 
    implementation of the read hook */
 static struct file_operations i2cproc_operations = {
-	read:		i2cproc_bus_read,
+	.read		= i2cproc_bus_read,
 };
 
-static int i2cproc_initialized = 0;
-
-#else /* undef CONFIG_PROC_FS */
-
-#define i2cproc_init() 0
-#define i2cproc_cleanup() 0
+static int i2cproc_register(struct i2c_adapter *adap, int bus);
+static void i2cproc_remove(int bus);
 
 #endif /* CONFIG_PROC_FS */
 
@@ -112,9 +81,9 @@
  */
 int i2c_add_adapter(struct i2c_adapter *adap)
 {
-	int i,j,res;
+	int i,j,res = 0;
 
-	ADAP_LOCK();
+	down(&core_lists);
 	for (i = 0; i < I2C_ADAP_MAX; i++)
 		if (NULL == adapters[i])
 			break;
@@ -125,68 +94,39 @@
 		res = -ENOMEM;
 		goto ERROR0;
 	}
+	
+#ifdef CONFIG_PROC_FS
+	res = i2cproc_register(adap, i);
+	if (res<0)
+	    goto ERROR0;
+#endif /* def CONFIG_PROC_FS */
 
 	adapters[i] = adap;
-	adap_count++;
-	ADAP_UNLOCK();
 	
 	/* init data types */
-	init_MUTEX(&adap->lock);
-
-#ifdef CONFIG_PROC_FS
-
-	if (i2cproc_initialized) {
-		char name[8];
-		struct proc_dir_entry *proc_entry;
-
-		sprintf(name,"i2c-%d", i);
-
-		proc_entry = create_proc_entry(name,0,proc_bus);
-		if (! proc_entry) {
-			printk("i2c-core.o: Could not create /proc/bus/%s\n",
-			       name);
-			res = -ENOENT;
-			goto ERROR1;
-		}
-
-		proc_entry->proc_fops = &i2cproc_operations;
-		proc_entry->owner = THIS_MODULE;
-		adap->inode = proc_entry->low_ino;
-	}
-
-#endif /* def CONFIG_PROC_FS */
+	init_MUTEX(&adap->bus);
+	init_MUTEX(&adap->list);
 
 	/* inform drivers of new adapters */
-	DRV_LOCK();	
 	for (j=0;j<I2C_DRIVER_MAX;j++)
 		if (drivers[j]!=NULL && 
 		    (drivers[j]->flags&(I2C_DF_NOTIFY|I2C_DF_DUMMY)))
 			/* We ignore the return code; if it fails, too bad */
 			drivers[j]->attach_adapter(adap);
-	DRV_UNLOCK();
 	
 	DEB(printk(KERN_DEBUG "i2c-core.o: adapter %s registered as adapter %d.\n",
 	           adap->name,i));
-
-	return 0;	
-
-
-ERROR1:
-	ADAP_LOCK();
-	adapters[i] = NULL;
-	adap_count--;
 ERROR0:
-	ADAP_UNLOCK();
+	up(&core_lists);
 	return res;
 }
 
 
 int i2c_del_adapter(struct i2c_adapter *adap)
 {
-	int i,j,res;
-
-	ADAP_LOCK();
+	int i,j,res = 0;
 
+	down(&core_lists);
 	for (i = 0; i < I2C_ADAP_MAX; i++)
 		if (adap == adapters[i])
 			break;
@@ -202,20 +142,17 @@
 	 * *detach* it! Of course, each dummy driver should know about
 	 * this or hell will break loose...
 	 */
-	DRV_LOCK();
 	for (j = 0; j < I2C_DRIVER_MAX; j++) 
 		if (drivers[j] && (drivers[j]->flags & I2C_DF_DUMMY))
 			if ((res = drivers[j]->attach_adapter(adap))) {
 				printk(KERN_WARNING "i2c-core.o: can't detach adapter %s "
 				       "while detaching driver %s: driver not "
 				       "detached!",adap->name,drivers[j]->name);
-				goto ERROR1;	
+				goto ERROR0;
 			}
-	DRV_UNLOCK();
-
 
 	/* detach any active clients. This must be done first, because
-	 * it can fail; in which case we give upp. */
+	 * it can fail; in which case we give up. */
 	for (j=0;j<I2C_CLIENT_MAX;j++) {
 		struct i2c_client *client = adap->clients[j];
 		if (client!=NULL)
@@ -231,26 +168,15 @@
 				goto ERROR0;
 			}
 	}
+
 #ifdef CONFIG_PROC_FS
-	if (i2cproc_initialized) {
-		char name[8];
-		sprintf(name,"i2c-%d", i);
-		remove_proc_entry(name,proc_bus);
-	}
+	i2cproc_remove(i);
 #endif /* def CONFIG_PROC_FS */
 
 	adapters[i] = NULL;
-	adap_count--;
-	
-	ADAP_UNLOCK();	
 	DEB(printk(KERN_DEBUG "i2c-core.o: adapter unregistered: %s\n",adap->name));
-	return 0;
-
 ERROR0:
-	ADAP_UNLOCK();
-	return res;
-ERROR1:
-	DRV_UNLOCK();
+	up(&core_lists);
 	return res;
 }
 
@@ -264,7 +190,8 @@
 int i2c_add_driver(struct i2c_driver *driver)
 {
 	int i;
-	DRV_LOCK();
+
+	down(&core_lists);
 	for (i = 0; i < I2C_DRIVER_MAX; i++)
 		if (NULL == drivers[i])
 			break;
@@ -273,19 +200,12 @@
 		       " i2c-core.o: register_driver(%s) "
 		       "- enlarge I2C_DRIVER_MAX.\n",
 			driver->name);
-		DRV_UNLOCK();
+		up(&core_lists);
 		return -ENOMEM;
 	}
-
 	drivers[i] = driver;
-	driver_count++;
-	
-	DRV_UNLOCK();	/* driver was successfully added */
-	
 	DEB(printk(KERN_DEBUG "i2c-core.o: driver %s registered.\n",driver->name));
 	
-	ADAP_LOCK();
-
 	/* now look for instances of driver on our adapters
 	 */
 	if (driver->flags& (I2C_DF_NOTIFY|I2C_DF_DUMMY)) {
@@ -294,15 +214,15 @@
 				/* Ignore errors */
 				driver->attach_adapter(adapters[i]);
 	}
-	ADAP_UNLOCK();
+	up(&core_lists);
 	return 0;
 }
 
 int i2c_del_driver(struct i2c_driver *driver)
 {
-	int i,j,k,res;
+	int i,j,k,res = 0;
 
-	DRV_LOCK();
+	down(&core_lists);
 	for (i = 0; i < I2C_DRIVER_MAX; i++)
 		if (driver == drivers[i])
 			break;
@@ -310,7 +230,7 @@
 		printk(KERN_WARNING " i2c-core.o: unregister_driver: "
 				    "[%s] not found\n",
 			driver->name);
-		DRV_UNLOCK();
+		up(&core_lists);
 		return -ENODEV;
 	}
 	/* Have a look at each adapter, if clients of this driver are still
@@ -322,7 +242,6 @@
 	 * invalid operation might (will!) result, when using stale client
 	 * pointers.
 	 */
-	ADAP_LOCK(); /* should be moved inside the if statement... */
 	for (k=0;k<I2C_ADAP_MAX;k++) {
 		struct i2c_adapter *adap = adapters[k];
 		if (adap == NULL) /* skip empty entries. */
@@ -341,8 +260,7 @@
 				       "not be detached properly; driver "
 				       "not unloaded!",driver->name,
 				       adap->name);
-				ADAP_UNLOCK();
-				return res;
+				goto ERROR0;
 			}
 		} else {
 			for (j=0;j<I2C_CLIENT_MAX;j++) { 
@@ -359,37 +277,47 @@
 						       "unregistering driver "
 						       "`%s', the client at "
 						       "address %02x of "
-						       "adapter `%s' could not"
-						       "be detached; driver"
+						       "adapter `%s' could not "
+						       "be detached; driver "
 						       "not unloaded!",
 						       driver->name,
 						       client->addr,
 						       adap->name);
-						ADAP_UNLOCK();
-						return res;
+						goto ERROR0;
 					}
 				}
 			}
 		}
 	}
-	ADAP_UNLOCK();
 	drivers[i] = NULL;
-	driver_count--;
-	DRV_UNLOCK();
-	
 	DEB(printk(KERN_DEBUG "i2c-core.o: driver unregistered: %s\n",driver->name));
-	return 0;
+
+ERROR0:
+	up(&core_lists);
+	return res;
 }
 
-int i2c_check_addr (struct i2c_adapter *adapter, int addr)
+static int __i2c_check_addr (struct i2c_adapter *adapter, int addr)
 {
 	int i;
 	for (i = 0; i < I2C_CLIENT_MAX ; i++) 
 		if (adapter->clients[i] && (adapter->clients[i]->addr == addr))
 			return -EBUSY;
+
 	return 0;
 }
 
+int i2c_check_addr (struct i2c_adapter *adapter, int addr)
+{
+	int rval;
+
+	down(&adapter->list);
+	rval = __i2c_check_addr(adapter, addr);
+	up(&adapter->list);
+
+	return rval;
+}
+
 int i2c_attach_client(struct i2c_client *client)
 {
 	struct i2c_adapter *adapter = client->adapter;
@@ -398,6 +326,7 @@
 	if (i2c_check_addr(client->adapter,client->addr))
 		return -EBUSY;
 
+	down(&adapter->list);
 	for (i = 0; i < I2C_CLIENT_MAX; i++)
 		if (NULL == adapter->clients[i])
 			break;
@@ -405,11 +334,11 @@
 		printk(KERN_WARNING 
 		       " i2c-core.o: attach_client(%s) - enlarge I2C_CLIENT_MAX.\n",
 			client->name);
+		up(&adapter->list);
 		return -ENOMEM;
 	}
-
 	adapter->clients[i] = client;
-	adapter->client_count++;
+	up(&adapter->list);
 	
 	if (adapter->client_register) 
 		if (adapter->client_register(client)) 
@@ -431,16 +360,6 @@
 	struct i2c_adapter *adapter = client->adapter;
 	int i,res;
 
-	for (i = 0; i < I2C_CLIENT_MAX; i++)
-		if (client == adapter->clients[i])
-			break;
-	if (I2C_CLIENT_MAX == i) {
-		printk(KERN_WARNING " i2c-core.o: unregister_client "
-				    "[%s] not found\n",
-			client->name);
-		return -ENODEV;
-	}
-	
 	if( (client->flags & I2C_CLIENT_ALLOW_USE) && 
 	    (client->usage_count>0))
 		return -EBUSY;
@@ -452,33 +371,41 @@
 			return res;
 		}
 
+	down(&adapter->list);
+	for (i = 0; i < I2C_CLIENT_MAX; i++)
+		if (client == adapter->clients[i])
+			break;
+	if (I2C_CLIENT_MAX == i) {
+		printk(KERN_WARNING " i2c-core.o: unregister_client "
+				    "[%s] not found\n",
+			client->name);
+		up(&adapter->list);
+		return -ENODEV;
+	}
 	adapter->clients[i] = NULL;
-	adapter->client_count--;
+	up(&adapter->list);
 
 	DEB(printk(KERN_DEBUG "i2c-core.o: client [%s] unregistered.\n",client->name));
 	return 0;
 }
 
-void i2c_inc_use_client(struct i2c_client *client)
+static void i2c_inc_use_client(struct i2c_client *client)
 {
-
-	if (client->driver->inc_use != NULL)
-		client->driver->inc_use(client);
-
-	if (client->adapter->inc_use != NULL)
-		client->adapter->inc_use(client->adapter);
+	if(client->driver->owner)
+		__MOD_INC_USE_COUNT(client->driver->owner);
+	if(client->adapter->owner)
+		__MOD_INC_USE_COUNT(client->adapter->owner);
 }
 
-void i2c_dec_use_client(struct i2c_client *client)
+static void i2c_dec_use_client(struct i2c_client *client)
 {
-	
-	if (client->driver->dec_use != NULL)
-		client->driver->dec_use(client);
-
-	if (client->adapter->dec_use != NULL)
-		client->adapter->dec_use(client->adapter);
+	if(client->driver->owner)
+		__MOD_DEC_USE_COUNT(client->driver->owner);
+	if(client->adapter->owner)
+		__MOD_DEC_USE_COUNT(client->adapter->owner);
 }
 
+#if 0 /* just forget about this for now --km */
 struct i2c_client *i2c_get_client(int driver_id, int adapter_id, 
 					struct i2c_client *prev)
 {
@@ -545,18 +472,17 @@
 
 	return 0;
 }
+#endif
 
 int i2c_use_client(struct i2c_client *client)
 {
-	if(client->flags & I2C_CLIENT_ALLOW_USE) {
-		if (client->flags & I2C_CLIENT_ALLOW_MULTIPLE_USE) 
+	if (client->flags & I2C_CLIENT_ALLOW_USE) {
+		if (client->flags & I2C_CLIENT_ALLOW_MULTIPLE_USE)
+			client->usage_count++;
+		else if (client->usage_count > 0) 
+			return -EBUSY;
+		else 
 			client->usage_count++;
-		else {
-			if(client->usage_count > 0) 
-				return -EBUSY;
-			 else 
-				client->usage_count++;
-		}
 	}
 
 	i2c_inc_use_client(client);
@@ -589,12 +515,13 @@
 #ifdef CONFIG_PROC_FS
 
 /* This function generates the output for /proc/bus/i2c */
-int read_bus_i2c(char *buf, char **start, off_t offset, int len, int *eof, 
+static int read_bus_i2c(char *buf, char **start, off_t offset, int len, int *eof, 
                  void *private)
 {
 	int i;
 	int nr = 0;
 	/* Note that it is safe to write a `little' beyond len. Yes, really. */
+	down(&core_lists);
 	for (i = 0; (i < I2C_ADAP_MAX) && (nr < len); i++)
 		if (adapters[i]) {
 			nr += sprintf(buf+nr, "i2c-%d\t", i);
@@ -611,6 +538,7 @@
 			              adapters[i]->name,
 			              adapters[i]->algo->name);
 		}
+	up(&core_lists);
 	return nr;
 }
 
@@ -621,98 +549,125 @@
 	struct inode * inode = file->f_dentry->d_inode;
 	char *kbuf;
 	struct i2c_client *client;
+	struct i2c_adapter *adap;
 	int i,j,k,order_nr,len=0;
 	size_t len_total;
 	int order[I2C_CLIENT_MAX];
+#define OUTPUT_LENGTH_PER_LINE 70
 
-	if (count > 4000)
-		return -EINVAL; 
 	len_total = file->f_pos + count;
-	/* Too bad if this gets longer (unlikely) */
-	if (len_total > 4000)
-		len_total = 4000;
-	for (i = 0; i < I2C_ADAP_MAX; i++)
-		if (adapters[i]->inode == inode->i_ino) {
-		/* We need a bit of slack in the kernel buffer; this makes the
-		   sprintf safe. */
-			if (! (kbuf = kmalloc(count + 80,GFP_KERNEL)))
-				return -ENOMEM;
-			/* Order will hold the indexes of the clients
-			   sorted by address */
-			order_nr=0;
-			for (j = 0; j < I2C_CLIENT_MAX; j++) {
-				if ((client = adapters[i]->clients[j]) && 
-				    (client->driver->id != I2C_DRIVERID_I2CDEV))  {
-					for(k = order_nr; 
-					    (k > 0) && 
-					    adapters[i]->clients[order[k-1]]->
-					             addr > client->addr; 
-					    k--)
-						order[k] = order[k-1];
-					order[k] = j;
-					order_nr++;
-				}
-			}
-
-
-			for (j = 0; (j < order_nr) && (len < len_total); j++) {
-				client = adapters[i]->clients[order[j]];
-				len += sprintf(kbuf+len,"%02x\t%-32s\t%-32s\n",
-				              client->addr,
-				              client->name,
-				              client->driver->name);
-			}
-			len = len - file->f_pos;
-			if (len > count)
-				len = count;
-			if (len < 0) 
-				len = 0;
-			if (copy_to_user (buf,kbuf+file->f_pos, len)) {
-				kfree(kbuf);
-				return -EFAULT;
-			}
-			file->f_pos += len;
-			kfree(kbuf);
-			return len;
-		}
-	return -ENOENT;
+	if (len_total > (I2C_CLIENT_MAX * OUTPUT_LENGTH_PER_LINE) )
+		/* adjust to maximum file size */
+		len_total = (I2C_CLIENT_MAX * OUTPUT_LENGTH_PER_LINE);
+
+	down(&core_lists);
+	/* adap = file->private_data; ?? --km */
+	for (i = 0; i < I2C_ADAP_MAX; i++) {
+	    adap = adapters[i];
+	    if (adap && (adap->inode == inode->i_ino))
+		break;
+	}
+	if ( I2C_ADAP_MAX == i ) {
+	    up(&core_lists);
+	    return -ENOENT;
+	}
+
+	/* We need a bit of slack in the kernel buffer; this makes the
+	   sprintf safe. */
+	if (! (kbuf = kmalloc(len_total +
+			      OUTPUT_LENGTH_PER_LINE,
+			      GFP_KERNEL)))
+	    return -ENOMEM;
+
+	/* Order will hold the indexes of the clients
+	   sorted by address */
+	order_nr=0;
+	down(&adap->list);
+	for (j = 0; j < I2C_CLIENT_MAX; j++) {
+	    if ((client = adap->clients[j]) && 
+		(client->driver->id != I2C_DRIVERID_I2CDEV))  {
+		for(k = order_nr; 
+		    (k > 0) && 
+			adap->clients[order[k-1]]->
+			addr > client->addr; 
+		    k--)
+		    order[k] = order[k-1];
+		order[k] = j;
+		order_nr++;
+	    }
+	}
+
+
+	for (j = 0; (j < order_nr) && (len < len_total); j++) {
+	    client = adap->clients[order[j]];
+	    len += sprintf(kbuf+len,"%02x\t%-32s\t%-32s\n",
+			   client->addr,
+			   client->name,
+			   client->driver->name);
+	}
+	up(&adap->list);
+	up(&core_lists);
+	
+	len = len - file->f_pos;
+	if (len > count)
+	    len = count;
+	if (len < 0) 
+	    len = 0;
+	if (copy_to_user (buf,kbuf+file->f_pos, len)) {
+	    kfree(kbuf);
+	    return -EFAULT;
+	}
+	file->f_pos += len;
+	kfree(kbuf);
+	return len;
+}
+
+static int i2cproc_register(struct i2c_adapter *adap, int bus)
+{
+	char name[8];
+	struct proc_dir_entry *proc_entry;
+
+	sprintf(name,"i2c-%d", bus);
+	proc_entry = create_proc_entry(name,0,proc_bus);
+	if (! proc_entry) {
+		printk(KERN_ERR "i2c-core.o: Could not create /proc/bus/%s\n",
+		       name);
+		return -ENOENT;
+	}
+	    
+	proc_entry->proc_fops = &i2cproc_operations;
+	proc_entry->owner = adap->owner;
+	adap->inode = proc_entry->low_ino;
+	return 0;
 }
 
-int i2cproc_init(void)
+static void i2cproc_remove(int bus)
 {
+	char name[8];
+	sprintf(name,"i2c-%d", bus);
+	remove_proc_entry(name, proc_bus);
+}
 
+static int __init i2cproc_init(void)
+{
 	struct proc_dir_entry *proc_bus_i2c;
 
-	i2cproc_initialized = 0;
-
-	if (! proc_bus) {
-		printk("i2c-core.o: /proc/bus/ does not exist");
-		i2cproc_cleanup();
-		return -ENOENT;
- 	} 
 	proc_bus_i2c = create_proc_entry("i2c",0,proc_bus);
 	if (!proc_bus_i2c) {
 		printk(KERN_ERR "i2c-core.o: Could not create /proc/bus/i2c");
-		i2cproc_cleanup();
 		return -ENOENT;
  	}
+
 	proc_bus_i2c->read_proc = &read_bus_i2c;
 	proc_bus_i2c->owner = THIS_MODULE;
-	i2cproc_initialized += 2;
 	return 0;
 }
 
-int i2cproc_cleanup(void)
+static void __exit i2cproc_cleanup(void)
 {
-
-	if (i2cproc_initialized >= 1) {
-		remove_proc_entry("i2c",proc_bus);
-		i2cproc_initialized -= 2;
-	}
-	return 0;
+	remove_proc_entry("i2c",proc_bus);
 }
 
-
 #endif /* def CONFIG_PROC_FS */
 
 /* ----------------------------------------------------
@@ -728,9 +683,9 @@
  	 	DEB2(printk(KERN_DEBUG "i2c-core.o: master_xfer: %s with %d msgs.\n",
 		            adap->name,num));
 
-		I2C_LOCK(adap);
+		down(&adap->bus);
 		ret = adap->algo->master_xfer(adap,msgs,num);
-		I2C_UNLOCK(adap);
+		up(&adap->bus);
 
 		return ret;
 	} else {
@@ -755,9 +710,9 @@
 		DEB2(printk(KERN_DEBUG "i2c-core.o: master_send: writing %d bytes on %s.\n",
 			count,client->adapter->name));
 	
-		I2C_LOCK(adap);
+		down(&adap->bus);
 		ret = adap->algo->master_xfer(adap,&msg,1);
-		I2C_UNLOCK(adap);
+		up(&adap->bus);
 
 		/* if everything went ok (i.e. 1 msg transmitted), return #bytes
 		 * transmitted, else error code.
@@ -785,9 +740,9 @@
 		DEB2(printk(KERN_DEBUG "i2c-core.o: master_recv: reading %d bytes on %s.\n",
 			count,client->adapter->name));
 	
-		I2C_LOCK(adap);
+		down(&adap->bus);
 		ret = adap->algo->master_xfer(adap,&msg,1);
-		I2C_UNLOCK(adap);
+		up(&adap->bus);
 	
 		DEB2(printk(KERN_DEBUG "i2c-core.o: master_recv: return:%d (count:%d, addr:0x%02x)\n",
 			ret, count, client->addr));
@@ -965,6 +920,123 @@
 
 /* The SMBus parts */
 
+#define POLY    (0x1070U << 3) 
+static u8
+crc8(u16 data)
+{
+	int i;
+  
+	for(i = 0; i < 8; i++) {
+		if (data & 0x8000) 
+			data = data ^ POLY;
+		data = data << 1;
+	}
+	return (u8)(data >> 8);
+}
+
+/* CRC over count bytes in the first array plus the bytes in the rest
+   array if it is non-null. rest[0] is the (length of rest) - 1
+   and is included. */
+u8 i2c_smbus_partial_pec(u8 crc, int count, u8 *first, u8 *rest)
+{
+	int i;
+
+	for(i = 0; i < count; i++)
+		crc = crc8((crc ^ first[i]) << 8);
+	if(rest != NULL)
+		for(i = 0; i <= rest[0]; i++)
+			crc = crc8((crc ^ rest[i]) << 8);
+	return crc;
+}
+
+u8 i2c_smbus_pec(int count, u8 *first, u8 *rest)
+{
+	return i2c_smbus_partial_pec(0, count, first, rest);
+}
+
+/* Returns new "size" (transaction type)
+   Note that we convert byte to byte_data and byte_data to word_data
+   rather than invent new xxx_PEC transactions. */
+int i2c_smbus_add_pec(u16 addr, u8 command, int size,
+                      union i2c_smbus_data *data)
+{
+	u8 buf[3];
+
+	buf[0] = addr << 1;
+	buf[1] = command;
+	switch(size) {
+		case I2C_SMBUS_BYTE:
+			data->byte = i2c_smbus_pec(2, buf, NULL);
+			size = I2C_SMBUS_BYTE_DATA;
+			break;
+		case I2C_SMBUS_BYTE_DATA:
+			buf[2] = data->byte;
+			data->word = buf[2] ||
+			            (i2c_smbus_pec(3, buf, NULL) << 8);
+			size = I2C_SMBUS_WORD_DATA;
+			break;
+		case I2C_SMBUS_WORD_DATA:
+			/* unsupported */
+			break;
+		case I2C_SMBUS_BLOCK_DATA:
+			data->block[data->block[0] + 1] =
+			             i2c_smbus_pec(2, buf, data->block);
+			size = I2C_SMBUS_BLOCK_DATA_PEC;
+			break;
+	}
+	return size;	
+}
+
+int i2c_smbus_check_pec(u16 addr, u8 command, int size, u8 partial,
+                        union i2c_smbus_data *data)
+{
+	u8 buf[3], rpec, cpec;
+
+	buf[1] = command;
+	switch(size) {
+		case I2C_SMBUS_BYTE_DATA:
+			buf[0] = (addr << 1) | 1;
+			cpec = i2c_smbus_pec(2, buf, NULL);
+			rpec = data->byte;
+			break;
+		case I2C_SMBUS_WORD_DATA:
+			buf[0] = (addr << 1) | 1;
+			buf[2] = data->word & 0xff;
+			cpec = i2c_smbus_pec(3, buf, NULL);
+			rpec = data->word >> 8;
+			break;
+		case I2C_SMBUS_WORD_DATA_PEC:
+			/* unsupported */
+			cpec = rpec = 0;
+			break;
+		case I2C_SMBUS_PROC_CALL_PEC:
+			/* unsupported */
+			cpec = rpec = 0;
+			break;
+		case I2C_SMBUS_BLOCK_DATA_PEC:
+			buf[0] = (addr << 1);
+			buf[2] = (addr << 1) | 1;
+			cpec = i2c_smbus_pec(3, buf, data->block);
+			rpec = data->block[data->block[0] + 1];
+			break;
+		case I2C_SMBUS_BLOCK_PROC_CALL_PEC:
+			buf[0] = (addr << 1) | 1;
+			rpec = i2c_smbus_partial_pec(partial, 1,
+			                             buf, data->block);
+			cpec = data->block[data->block[0] + 1];
+			break;
+		default:
+			cpec = rpec = 0;
+			break;
+	}
+	if(rpec != cpec) {
+		DEB(printk(KERN_DEBUG "i2c-core.o: Bad PEC 0x%02x vs. 0x%02x\n",
+		           rpec, cpec));
+		return -1;
+	}
+	return 0;	
+}
+
 extern s32 i2c_smbus_write_quick(struct i2c_client * client, u8 value)
 {
 	return i2c_smbus_xfer(client->adapter,client->addr,client->flags,
@@ -983,8 +1055,9 @@
 
 extern s32 i2c_smbus_write_byte(struct i2c_client * client, u8 value)
 {
+	union i2c_smbus_data data;	/* only for PEC */
 	return i2c_smbus_xfer(client->adapter,client->addr,client->flags,
-	                      I2C_SMBUS_WRITE,value, I2C_SMBUS_BYTE,NULL);
+	                      I2C_SMBUS_WRITE,value, I2C_SMBUS_BYTE,&data);
 }
 
 extern s32 i2c_smbus_read_byte_data(struct i2c_client * client, u8 command)
@@ -1072,6 +1145,43 @@
 	                      I2C_SMBUS_BLOCK_DATA,&data);
 }
 
+/* Returns the number of read bytes */
+extern s32 i2c_smbus_block_process_call(struct i2c_client * client,
+                                        u8 command, u8 length, u8 *values)
+{
+	union i2c_smbus_data data;
+	int i;
+	if (length > I2C_SMBUS_BLOCK_MAX - 1)
+		return -1;
+	data.block[0] = length;
+	for (i = 1; i <= length; i++)
+		data.block[i] = values[i-1];
+	if(i2c_smbus_xfer(client->adapter,client->addr,client->flags,
+	                  I2C_SMBUS_WRITE, command,
+	                  I2C_SMBUS_BLOCK_PROC_CALL, &data))
+		return -1;
+	for (i = 1; i <= data.block[0]; i++)
+		values[i-1] = data.block[i];
+	return data.block[0];
+}
+
+/* Returns the number of read bytes */
+extern s32 i2c_smbus_read_i2c_block_data(struct i2c_client * client,
+                                         u8 command, u8 *values)
+{
+	union i2c_smbus_data data;
+	int i;
+	if (i2c_smbus_xfer(client->adapter,client->addr,client->flags,
+	                      I2C_SMBUS_READ,command,
+	                      I2C_SMBUS_I2C_BLOCK_DATA,&data))
+		return -1;
+	else {
+		for (i = 1; i <= data.block[0]; i++)
+			values[i-1] = data.block[i];
+		return data.block[0];
+	}
+}
+
 extern s32 i2c_smbus_write_i2c_block_data(struct i2c_client * client,
                                           u8 command, u8 length, u8 *values)
 {
@@ -1098,13 +1208,13 @@
 	  need to use only one message; when reading, we need two. We initialize
 	  most things with sane defaults, to keep the code below somewhat
 	  simpler. */
-	unsigned char msgbuf0[34];
-	unsigned char msgbuf1[34];
+	unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX+2];
+	unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX+2];
 	int num = read_write == I2C_SMBUS_READ?2:1;
 	struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 }, 
 	                          { addr, flags | I2C_M_RD, 0, msgbuf1 }
 	                        };
-	int i;
+	int i, len;
 
 	msgbuf0[0] = command;
 	switch(size) {
@@ -1140,16 +1250,30 @@
 		break;
 	case I2C_SMBUS_PROC_CALL:
 		num = 2; /* Special case */
+		read_write = I2C_SMBUS_READ;
 		msg[0].len = 3;
 		msg[1].len = 2;
 		msgbuf0[1] = data->word & 0xff;
 		msgbuf0[2] = (data->word >> 8) & 0xff;
 		break;
 	case I2C_SMBUS_BLOCK_DATA:
+	case I2C_SMBUS_BLOCK_DATA_PEC:
 		if (read_write == I2C_SMBUS_READ) {
-			printk(KERN_ERR "i2c-core.o: Block read not supported "
-			       "under I2C emulation!\n");
-			return -1;
+			/* I2C_FUNC_SMBUS_EMUL doesn't include I2C_FUNC_SMBUS_READ_BLOCK_DATA */
+			if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BLOCK_DATA)) {
+				printk(KERN_ERR "i2c-core.o: Block read not supported "
+				       "under I2C emulation!\n");
+				return -1;
+			}
+			/* set send message */
+			msg[0].len = 1;
+			/* set recv message */
+			msg[1].flags |= I2C_M_RECV_LEN;
+			msg[1].len = I2C_SMBUS_BLOCK_MAX + 1;
+			if (size == I2C_SMBUS_BLOCK_DATA_PEC) {
+				msg[1].len++;
+				msg[1].flags |= I2C_M_RECV_PEC;
+			}
 		} else {
 			msg[0].len = data->block[0] + 2;
 			if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) {
@@ -1158,10 +1282,57 @@
 				       data->block[0]);
 				return -1;
 			}
+			if(size == I2C_SMBUS_BLOCK_DATA_PEC)
+				(msg[0].len)++;
 			for (i = 1; i <= msg[0].len; i++)
 				msgbuf0[i] = data->block[i-1];
 		}
 		break;
+	case I2C_SMBUS_BLOCK_PROC_CALL:
+	case I2C_SMBUS_BLOCK_PROC_CALL_PEC:
+		/* I2C_FUNC_SMBUS_EMUL doesn't include I2C_FUNC_SMBUS_BLOCK_PROC_CALL */
+		if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BLOCK_PROC_CALL)) {
+			printk(KERN_ERR "i2c-core.o: adapter doesn't support block process call!\n");
+			return -1;
+		}
+
+		/* Another special case */
+		num = 2;
+		read_write = I2C_SMBUS_READ;
+		
+		/* set send message */
+		msg[0].len = data->block[0] + 2;
+		if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) {
+			printk(KERN_ERR "i2c-core.o: smbus_access called with "
+				"invalid block write size (%d)\n", data->block[0]);
+			return -1;
+		}
+		for (i = 1; i <= msg[0].len; i++)
+			msgbuf0[i] = data->block[i-1];
+		
+		/* set recv message */
+		msg[1].flags |= I2C_M_RECV_LEN;
+		msg[1].len = I2C_SMBUS_BLOCK_MAX + 1;
+		if (size == I2C_SMBUS_BLOCK_PROC_CALL_PEC) {
+			msg[1].len++;
+			msg[1].flags |= I2C_M_RECV_PEC;
+		}
+		break;
+	case I2C_SMBUS_I2C_BLOCK_DATA:
+		if (read_write == I2C_SMBUS_READ) {
+			msg[1].len = I2C_SMBUS_I2C_BLOCK_MAX;
+		} else {
+			msg[0].len = data->block[0] + 1;
+			if (msg[0].len > I2C_SMBUS_I2C_BLOCK_MAX + 1) {
+				printk("i2c-core.o: i2c_smbus_xfer_emulated called with "
+				       "invalid block write size (%d)\n",
+				       data->block[0]);
+				return -1;
+			}
+			for (i = 1; i <= data->block[0]; i++)
+				msgbuf0[i] = data->block[i];
+		}
+		break;
 	default:
 		printk(KERN_ERR "i2c-core.o: smbus_access called with invalid size (%d)\n",
 		       size);
@@ -1183,25 +1354,72 @@
 			case I2C_SMBUS_PROC_CALL:
 				data->word = msgbuf1[0] | (msgbuf1[1] << 8);
 				break;
+			case I2C_SMBUS_I2C_BLOCK_DATA:
+				/* fixed at 32 for now */
+				data->block[0] = I2C_SMBUS_I2C_BLOCK_MAX;
+				for (i = 0; i < I2C_SMBUS_I2C_BLOCK_MAX; i++)
+					data->block[i+1] = msgbuf1[i];
+				break;
+			case I2C_SMBUS_BLOCK_DATA:
+			case I2C_SMBUS_BLOCK_PROC_CALL:
+			case I2C_SMBUS_BLOCK_DATA_PEC:
+			case I2C_SMBUS_BLOCK_PROC_CALL_PEC:
+				len = msgbuf1[0] + 1;
+				if(size == I2C_SMBUS_BLOCK_DATA_PEC ||
+				   size == I2C_SMBUS_BLOCK_PROC_CALL_PEC)
+					len++;
+				for (i = 0; i < len; i++)
+					data->block[i] = msgbuf1[i];
+				break;
 		}
 	return 0;
 }
 
 
-s32 i2c_smbus_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags,
+s32 i2c_smbus_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags,
                    char read_write, u8 command, int size, 
                    union i2c_smbus_data * data)
 {
 	s32 res;
-	flags = flags & I2C_M_TEN;
-	if (adapter->algo->smbus_xfer) {
-		I2C_LOCK(adapter);
-		res = adapter->algo->smbus_xfer(adapter,addr,flags,read_write,
+	int swpec = 0;
+	u8 partial = 0;
+
+	flags &= I2C_M_TEN | I2C_CLIENT_PEC;
+	if((flags & I2C_CLIENT_PEC) &&
+	   !(i2c_check_functionality(adap, I2C_FUNC_SMBUS_HWPEC_CALC))) {
+		swpec = 1;
+		if(read_write == I2C_SMBUS_READ &&
+		   size == I2C_SMBUS_BLOCK_DATA)
+			size = I2C_SMBUS_BLOCK_DATA_PEC;
+		else if(size == I2C_SMBUS_PROC_CALL)
+			size = I2C_SMBUS_PROC_CALL_PEC;
+		else if(size == I2C_SMBUS_BLOCK_PROC_CALL) {
+			i2c_smbus_add_pec(addr, command,
+		                          I2C_SMBUS_BLOCK_DATA, data);
+			partial = data->block[data->block[0] + 1];
+			size = I2C_SMBUS_BLOCK_PROC_CALL_PEC;
+		} else if(read_write == I2C_SMBUS_WRITE &&
+		          size != I2C_SMBUS_QUICK &&
+		          size != I2C_SMBUS_I2C_BLOCK_DATA)
+			size = i2c_smbus_add_pec(addr, command, size, data);
+	}
+
+	if (adap->algo->smbus_xfer) {
+		down(&adap->bus);
+		res = adap->algo->smbus_xfer(adap,addr,flags,read_write,
 		                                command,size,data);
-		I2C_UNLOCK(adapter);
+		up(&adap->bus);
 	} else
-		res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write,
+		res = i2c_smbus_xfer_emulated(adap,addr,flags,read_write,
 	                                      command,size,data);
+
+	if(res >= 0 && swpec &&
+	   size != I2C_SMBUS_QUICK && size != I2C_SMBUS_I2C_BLOCK_DATA &&
+	   (read_write == I2C_SMBUS_READ || size == I2C_SMBUS_PROC_CALL_PEC ||
+	    size == I2C_SMBUS_BLOCK_PROC_CALL_PEC)) {
+		if(i2c_smbus_check_pec(addr, command, size, partial, data))
+			return -1;
+	}
 	return res;
 }
 
@@ -1228,136 +1446,37 @@
 	printk(KERN_INFO "i2c-core.o: i2c core module version %s (%s)\n", I2C_VERSION, I2C_DATE);
 	memset(adapters,0,sizeof(adapters));
 	memset(drivers,0,sizeof(drivers));
-	adap_count=0;
-	driver_count=0;
 
-	init_MUTEX(&adap_lock);
-	init_MUTEX(&driver_lock);
-	
-	i2cproc_init();
-	
+#ifdef CONFIG_PROC_FS
+	return i2cproc_init();
+#else
 	return 0;
-}
-
-#ifndef MODULE
-#ifdef CONFIG_I2C_CHARDEV
-	extern int i2c_dev_init(void);
-#endif
-#ifdef CONFIG_I2C_ALGOBIT
-	extern int i2c_algo_bit_init(void);
-#endif
-#ifdef CONFIG_I2C_PHILIPSPAR
-	extern int i2c_bitlp_init(void);
-#endif
-#ifdef CONFIG_I2C_ELV
-	extern int i2c_bitelv_init(void);
-#endif
-#ifdef CONFIG_I2C_VELLEMAN
-	extern int i2c_bitvelle_init(void);
-#endif
-#ifdef CONFIG_I2C_BITVIA
-	extern int i2c_bitvia_init(void);
-#endif
-
-#ifdef CONFIG_I2C_ALGOPCF
-	extern int i2c_algo_pcf_init(void);	
-#endif
-#ifdef CONFIG_I2C_ELEKTOR
-	extern int i2c_pcfisa_init(void);
-#endif
-
-#ifdef CONFIG_I2C_ALGO8XX
-	extern int i2c_algo_8xx_init(void);
-#endif
-#ifdef CONFIG_I2C_RPXLITE
-	extern int i2c_rpx_init(void);
-#endif
-
-#ifdef CONFIG_I2C_ALGO_SIBYTE
-	extern int i2c_algo_sibyte_init(void);
-	extern int i2c_sibyte_init(void);
-#endif
-#ifdef CONFIG_I2C_MAX1617
-	extern int i2c_max1617_init(void);
 #endif
+}
 
-#ifdef CONFIG_I2C_PROC
-	extern int sensors_init(void);
+static void __exit i2c_exit(void) 
+{
+#ifdef CONFIG_PROC_FS
+	i2cproc_cleanup();
 #endif
+}
 
-/* This is needed for automatic patch generation: sensors code starts here */
-/* This is needed for automatic patch generation: sensors code ends here   */
-
+/* leave this in for now simply to make patching easier so we don't have
+   to remove the call in drivers/char/mem.c */
 int __init i2c_init_all(void)
 {
-	/* --------------------- global ----- */
-	i2c_init();
-
-#ifdef CONFIG_I2C_CHARDEV
-	i2c_dev_init();
-#endif
-	/* --------------------- bit -------- */
-#ifdef CONFIG_I2C_ALGOBIT
-	i2c_algo_bit_init();
-#endif
-#ifdef CONFIG_I2C_PHILIPSPAR
-	i2c_bitlp_init();
-#endif
-#ifdef CONFIG_I2C_ELV
-	i2c_bitelv_init();
-#endif
-#ifdef CONFIG_I2C_VELLEMAN
-	i2c_bitvelle_init();
-#endif
-
-	/* --------------------- pcf -------- */
-#ifdef CONFIG_I2C_ALGOPCF
-	i2c_algo_pcf_init();	
-#endif
-#ifdef CONFIG_I2C_ELEKTOR
-	i2c_pcfisa_init();
-#endif
-
-	/* --------------------- 8xx -------- */
-#ifdef CONFIG_I2C_ALGO8XX
-	i2c_algo_8xx_init();
-#endif
-#ifdef CONFIG_I2C_RPXLITE
-	i2c_rpx_init();
-#endif
-
-	/* --------------------- SiByte -------- */
-#ifdef CONFIG_I2C_ALGO_SIBYTE
-	i2c_algo_sibyte_init();
-	i2c_sibyte_init();
-#endif
-#ifdef CONFIG_I2C_MAX1617
-	i2c_max1617_init();
-#endif
-
-	/* -------------- proc interface ---- */
-#ifdef CONFIG_I2C_PROC
-	sensors_init();
-#endif
-/* This is needed for automatic patch generation: sensors code starts here */
-/* This is needed for automatic patch generation: sensors code ends here */
-
 	return 0;
 }
 
-#endif
-
-
-
 EXPORT_SYMBOL(i2c_add_adapter);
 EXPORT_SYMBOL(i2c_del_adapter);
 EXPORT_SYMBOL(i2c_add_driver);
 EXPORT_SYMBOL(i2c_del_driver);
 EXPORT_SYMBOL(i2c_attach_client);
 EXPORT_SYMBOL(i2c_detach_client);
-EXPORT_SYMBOL(i2c_inc_use_client);
-EXPORT_SYMBOL(i2c_dec_use_client);
+#if 0
 EXPORT_SYMBOL(i2c_get_client);
+#endif
 EXPORT_SYMBOL(i2c_use_client);
 EXPORT_SYMBOL(i2c_release_client);
 EXPORT_SYMBOL(i2c_check_addr);
@@ -1381,11 +1500,12 @@
 EXPORT_SYMBOL(i2c_smbus_process_call);
 EXPORT_SYMBOL(i2c_smbus_read_block_data);
 EXPORT_SYMBOL(i2c_smbus_write_block_data);
+EXPORT_SYMBOL(i2c_smbus_read_i2c_block_data);
+EXPORT_SYMBOL(i2c_smbus_write_i2c_block_data);
 
 EXPORT_SYMBOL(i2c_get_functionality);
 EXPORT_SYMBOL(i2c_check_functionality);
 
-#ifdef MODULE
 MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
 MODULE_DESCRIPTION("I2C-Bus main module");
 MODULE_LICENSE("GPL");
@@ -1393,13 +1513,5 @@
 MODULE_PARM(i2c_debug, "i");
 MODULE_PARM_DESC(i2c_debug,"debug level");
 
-int init_module(void) 
-{
-	return i2c_init();
-}
-
-void cleanup_module(void) 
-{
-	i2cproc_cleanup();
-}
-#endif
+module_init(i2c_init);
+module_exit(i2c_exit);
diff -urN --exclude-from=diff-exclude linux-2.4.27/drivers/i2c/i2c-dev.c linux-2.4.27-leo/drivers/i2c/i2c-dev.c
--- linux-2.4.27/drivers/i2c/i2c-dev.c	2004-02-20 14:11:41.000000000 +0000
+++ linux-2.4.27-leo/drivers/i2c/i2c-dev.c	2004-09-20 21:34:38.000000000 +0100
@@ -28,9 +28,8 @@
 /* The devfs code is contributed by Philipp Matthias Hahn 
    <pmhahn@titan.lahn.de> */
 
-/* $Id: i2c-dev.c,v 1.40 2001/08/25 01:28:01 mds Exp $ */
+/* $Id: i2c-dev.c,v 1.57 2003/12/22 20:03:39 khali Exp $ */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/fs.h>
@@ -39,21 +38,14 @@
 #ifdef CONFIG_DEVFS_FS
 #include <linux/devfs_fs_kernel.h>
 #endif
-
-
-/* If you want debugging uncomment: */
-/* #define DEBUG */
-
 #include <linux/init.h>
-#include <asm/uaccess.h>
-
 #include <linux/i2c.h>
 #include <linux/i2c-dev.h>
+#include <asm/uaccess.h>
+
+/* If you want debugging uncomment: */
+/* #define DEBUG */
 
-#ifdef MODULE
-extern int init_module(void);
-extern int cleanup_module(void);
-#endif /* def MODULE */
 
 /* struct file_operations changed too often in the 2.1 series for nice code */
 
@@ -73,22 +65,14 @@
 static int i2cdev_command(struct i2c_client *client, unsigned int cmd,
                            void *arg);
 
-#ifdef MODULE
-static
-#else
-extern
-#endif
-       int __init i2c_dev_init(void);
-static int i2cdev_cleanup(void);
-
 static struct file_operations i2cdev_fops = {
-	owner:		THIS_MODULE,
-	llseek:		no_llseek,
-	read:		i2cdev_read,
-	write:		i2cdev_write,
-	ioctl:		i2cdev_ioctl,
-	open:		i2cdev_open,
-	release:	i2cdev_release,
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.read		= i2cdev_read,
+	.write		= i2cdev_write,
+	.ioctl		= i2cdev_ioctl,
+	.open		= i2cdev_open,
+	.release	= i2cdev_release,
 };
 
 #define I2CDEV_ADAPS_MAX I2C_ADAP_MAX
@@ -99,28 +83,22 @@
 #endif
 
 static struct i2c_driver i2cdev_driver = {
-	name:		"i2c-dev dummy driver",
-	id:		I2C_DRIVERID_I2CDEV,
-	flags:		I2C_DF_DUMMY,
-	attach_adapter:	i2cdev_attach_adapter,
-	detach_client:	i2cdev_detach_client,
-	command:	i2cdev_command,
-/*	inc_use:	NULL,
-	dec_use:	NULL, */
+	.owner		= THIS_MODULE, /* not really used */
+	.name		= "i2c-dev dummy driver",
+	.id		= I2C_DRIVERID_I2CDEV,
+	.flags		= I2C_DF_DUMMY,
+	.attach_adapter	= i2cdev_attach_adapter,
+	.detach_client	= i2cdev_detach_client,
+	.command	= i2cdev_command,
 };
 
 static struct i2c_client i2cdev_client_template = {
-	name:		"I2C /dev entry",
-	id:		1,
-	flags:		0,
-	addr:		-1,
-/*	adapter:	NULL, */
-	driver:		&i2cdev_driver,
-/*	data:		NULL */
+	.name		= "I2C /dev entry",
+	.id		= 1,
+	.addr		= -1,
+	.driver		= &i2cdev_driver,
 };
 
-static int i2cdev_initialized;
-
 static ssize_t i2cdev_read (struct file *file, char *buf, size_t count,
                             loff_t *offset)
 {
@@ -142,7 +120,7 @@
 		return -ENOMEM;
 
 #ifdef DEBUG
-	printk(KERN_DEBUG "i2c-dev.o: i2c-%d reading %d bytes.\n",MINOR(inode->i_rdev),
+	printk(KERN_DEBUG "i2c-dev.o: i2c-%d reading %d bytes.\n",minor(inode->i_rdev),
 	       count);
 #endif
 
@@ -177,7 +155,7 @@
 	}
 
 #ifdef DEBUG
-	printk(KERN_DEBUG "i2c-dev.o: i2c-%d writing %d bytes.\n",MINOR(inode->i_rdev),
+	printk(KERN_DEBUG "i2c-dev.o: i2c-%d writing %d bytes.\n",minor(inode->i_rdev),
 	       count);
 #endif
 	ret = i2c_master_send(client,tmp,count);
@@ -199,7 +177,7 @@
 
 #ifdef DEBUG
 	printk(KERN_DEBUG "i2c-dev.o: i2c-%d ioctl, cmd: 0x%x, arg: %lx.\n", 
-	       MINOR(inode->i_rdev),cmd, arg);
+	       minor(inode->i_rdev),cmd, arg);
 #endif /* DEBUG */
 
 	switch ( cmd ) {
@@ -218,6 +196,12 @@
 		else
 			client->flags &= ~I2C_M_TEN;
 		return 0;
+	case I2C_PEC:
+		if (arg)
+			client->flags |= I2C_CLIENT_PEC;
+		else
+			client->flags &= ~I2C_CLIENT_PEC;
+		return 0;
 	case I2C_FUNCS:
 		funcs = i2c_get_functionality(client->adapter);
 		return (copy_to_user((unsigned long *)arg,&funcs,
@@ -318,7 +302,8 @@
 		    (data_arg.size != I2C_SMBUS_WORD_DATA) &&
 		    (data_arg.size != I2C_SMBUS_PROC_CALL) &&
 		    (data_arg.size != I2C_SMBUS_BLOCK_DATA) &&
-		    (data_arg.size != I2C_SMBUS_I2C_BLOCK_DATA)) {
+		    (data_arg.size != I2C_SMBUS_I2C_BLOCK_DATA) &&
+		    (data_arg.size != I2C_SMBUS_BLOCK_PROC_CALL)) {
 #ifdef DEBUG
 			printk(KERN_DEBUG "i2c-dev.o: size out of range (%x) in ioctl I2C_SMBUS.\n",
 			       data_arg.size);
@@ -361,10 +346,11 @@
 		else if ((data_arg.size == I2C_SMBUS_WORD_DATA) || 
 		         (data_arg.size == I2C_SMBUS_PROC_CALL))
 			datasize = sizeof(data_arg.data->word);
-		else /* size == I2C_SMBUS_BLOCK_DATA */
+		else /* size == smbus block, i2c block, or block proc. call */
 			datasize = sizeof(data_arg.data->block);
 
 		if ((data_arg.size == I2C_SMBUS_PROC_CALL) || 
+		    (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) || 
 		    (data_arg.read_write == I2C_SMBUS_WRITE)) {
 			if (copy_from_user(&temp, data_arg.data, datasize))
 				return -EFAULT;
@@ -373,6 +359,7 @@
 		      data_arg.read_write,
 		      data_arg.command,data_arg.size,&temp);
 		if (! res && ((data_arg.size == I2C_SMBUS_PROC_CALL) || 
+		              (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) || 
 			      (data_arg.read_write == I2C_SMBUS_READ))) {
 			if (copy_to_user(data_arg.data, &temp, datasize))
 				return -EFAULT;
@@ -387,7 +374,7 @@
 
 int i2cdev_open (struct inode *inode, struct file *file)
 {
-	unsigned int minor = MINOR(inode->i_rdev);
+	unsigned int minor = minor(inode->i_rdev);
 	struct i2c_client *client;
 
 	if ((minor >= I2CDEV_ADAPS_MAX) || ! (i2cdev_adaps[minor])) {
@@ -403,11 +390,13 @@
 	if(! (client = kmalloc(sizeof(struct i2c_client),GFP_KERNEL)))
 		return -ENOMEM;
 	memcpy(client,&i2cdev_client_template,sizeof(struct i2c_client));
+
+	/* registered with adapter, passed as client to user */
 	client->adapter = i2cdev_adaps[minor];
 	file->private_data = client;
 
-	if (i2cdev_adaps[minor]->inc_use)
-		i2cdev_adaps[minor]->inc_use(i2cdev_adaps[minor]);
+	if(client->adapter->owner)
+		__MOD_INC_USE_COUNT(client->adapter->owner);
 
 #ifdef DEBUG
 	printk(KERN_DEBUG "i2c-dev.o: opened i2c-%d\n",minor);
@@ -417,16 +406,19 @@
 
 static int i2cdev_release (struct inode *inode, struct file *file)
 {
-	unsigned int minor = MINOR(inode->i_rdev);
-	kfree(file->private_data);
-	file->private_data=NULL;
+	struct i2c_client *client;
+#ifdef DEBUG
+	unsigned int minor = minor(inode->i_rdev);
+#endif
+
+	client = file->private_data;
+	file->private_data = NULL;
+	if(client->adapter->owner)
+		__MOD_DEC_USE_COUNT(client->adapter->owner);
+	kfree(client);
 #ifdef DEBUG
 	printk(KERN_DEBUG "i2c-dev.o: Closed: i2c-%d\n", minor);
 #endif
-	lock_kernel();
-	if (i2cdev_adaps[minor]->dec_use)
-		i2cdev_adaps[minor]->dec_use(i2cdev_adaps[minor]);
-	unlock_kernel();
 	return 0;
 }
 
@@ -451,7 +443,7 @@
 		devfs_i2c[i] = devfs_register (devfs_handle, name,
 			DEVFS_FL_DEFAULT, I2C_MAJOR, i,
 			S_IFCHR | S_IRUSR | S_IWUSR,
-			&i2cdev_fops, NULL);
+			&i2cdev_fops, adap);
 #endif
 		printk(KERN_DEBUG "i2c-dev.o: Registered '%s' as minor %d\n",adap->name,i);
 	} else {
@@ -479,13 +471,12 @@
 	return -1;
 }
 
-int __init i2c_dev_init(void)
+static int __init i2c_dev_init(void)
 {
 	int res;
 
 	printk(KERN_INFO "i2c-dev.o: i2c /dev entries driver module version %s (%s)\n", I2C_VERSION, I2C_DATE);
 
-	i2cdev_initialized = 0;
 #ifdef CONFIG_DEVFS_FS
 	if (devfs_register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops)) {
 #else
@@ -498,63 +489,31 @@
 #ifdef CONFIG_DEVFS_FS
 	devfs_handle = devfs_mk_dir(NULL, "i2c", NULL);
 #endif
-	i2cdev_initialized ++;
-
 	if ((res = i2c_add_driver(&i2cdev_driver))) {
 		printk(KERN_ERR "i2c-dev.o: Driver registration failed, module not inserted.\n");
-		i2cdev_cleanup();
+#ifdef CONFIG_DEVFS_FS
+		devfs_unregister(devfs_handle);
+#endif
+		unregister_chrdev(I2C_MAJOR,"i2c");
 		return res;
 	}
-	i2cdev_initialized ++;
 	return 0;
 }
 
-int i2cdev_cleanup(void)
+static void __exit i2c_dev_exit(void)
 {
-	int res;
-
-	if (i2cdev_initialized >= 2) {
-		if ((res = i2c_del_driver(&i2cdev_driver))) {
-			printk("i2c-dev.o: Driver deregistration failed, "
-			       "module not removed.\n");
-			return res;
-		}
-	i2cdev_initialized --;
-	}
-
-	if (i2cdev_initialized >= 1) {
+	i2c_del_driver(&i2cdev_driver);
 #ifdef CONFIG_DEVFS_FS
-		devfs_unregister(devfs_handle);
-		if ((res = devfs_unregister_chrdev(I2C_MAJOR, "i2c"))) {
-#else
-		if ((res = unregister_chrdev(I2C_MAJOR,"i2c"))) {
+	devfs_unregister(devfs_handle);
 #endif
-			printk("i2c-dev.o: unable to release major %d for i2c bus\n",
-			       I2C_MAJOR);
-			return res;
-		}
-		i2cdev_initialized --;
-	}
-	return 0;
+	unregister_chrdev(I2C_MAJOR,"i2c");
 }
 
 EXPORT_NO_SYMBOLS;
 
-#ifdef MODULE
-
 MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and Simon G. Vogl <simon@tk.uni-linz.ac.at>");
 MODULE_DESCRIPTION("I2C /dev entries driver");
 MODULE_LICENSE("GPL");
 
-int init_module(void)
-{
-	return i2c_dev_init();
-}
-
-int cleanup_module(void)
-{
-	return i2cdev_cleanup();
-}
-
-#endif /* def MODULE */
-
+module_init(i2c_dev_init);
+module_exit(i2c_dev_exit);
diff -urN --exclude-from=diff-exclude linux-2.4.27/drivers/i2c/i2c-elektor.c linux-2.4.27-leo/drivers/i2c/i2c-elektor.c
--- linux-2.4.27/drivers/i2c/i2c-elektor.c	2004-02-20 14:11:41.000000000 +0000
+++ linux-2.4.27-leo/drivers/i2c/i2c-elektor.c	2004-09-20 21:34:38.000000000 +0100
@@ -31,23 +31,22 @@
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/pci.h>
-#include <asm/irq.h>
-#include <asm/io.h>
-
+#include <linux/wait.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-pcf.h>
-#include <linux/i2c-elektor.h>
-#include "i2c-pcf8584.h"
+#include <asm/io.h>
+#include <asm/irq.h>
 
 #define DEFAULT_BASE 0x330
 
-static int base   = 0;
-static int irq    = 0;
+static int base;
+static int irq;
 static int clock  = 0x1c;
 static int own    = 0x55;
-static int mmapped = 0;
-static int i2c_debug = 0;
+static int mmapped;
+static int i2c_debug;
 
 /* vdovikin: removed static struct i2c_pcf_isa gpi; code - 
   this module in real supports only one device, due to missing arguments
@@ -56,6 +55,7 @@
 
 static wait_queue_head_t pcf_wait;
 static int pcf_pending;
+static spinlock_t irq_driver_lock = SPIN_LOCK_UNLOCKED;
 
 /* ----- global defines -----------------------------------------------	*/
 #define DEB(x)	if (i2c_debug>=1) x
@@ -63,13 +63,24 @@
 #define DEB3(x) if (i2c_debug>=3) x
 #define DEBE(x)	x	/* error messages 				*/
 
+
+/* compatibility */
+#ifndef isa_readb
+#define isa_readb readb
+#endif
+
+#ifndef isa_writeb
+#define isa_writeb writeb
+#endif
+
 /* ----- local functions ----------------------------------------------	*/
 
 static void pcf_isa_setbyte(void *data, int ctl, int val)
 {
 	int address = ctl ? (base + 1) : base;
 
-	if (ctl && irq) {
+	/* enable irq if any specified for serial operation */
+	if (ctl && irq && (val & I2C_PCF_ESO)) {
 		val |= I2C_PCF_ENI;
 	}
 
@@ -81,10 +92,10 @@
 		break;
 	case 2: /* double mapped I/O needed for UP2000 board,
                    I don't know why this... */
-		writeb(val, address);
+		isa_writeb(val, address);
 		/* fall */
 	case 1: /* memory mapped I/O */
-		writeb(val, address);
+		isa_writeb(val, address);
 		break;
 	}
 }
@@ -92,7 +103,7 @@
 static int pcf_isa_getbyte(void *data, int ctl)
 {
 	int address = ctl ? (base + 1) : base;
-	int val = mmapped ? readb(address) : inb(address);
+	int val = mmapped ? isa_readb(address) : inb(address);
 
 	DEB3(printk(KERN_DEBUG "i2c-elektor.o: Read 0x%X 0x%02X\n", address, val));
 
@@ -115,12 +126,12 @@
 	int timeout = 2;
 
 	if (irq > 0) {
-		cli();
+		spin_lock_irq(&irq_driver_lock);
 		if (pcf_pending == 0) {
 			interruptible_sleep_on_timeout(&pcf_wait, timeout*HZ );
 		} else
 			pcf_pending = 0;
-		sti();
+		spin_unlock_irq(&irq_driver_lock);
 	} else {
 		udelay(100);
 	}
@@ -136,13 +147,11 @@
 static int pcf_isa_init(void)
 {
 	if (!mmapped) {
-		if (check_region(base, 2) < 0 ) {
+		if (!request_region(base, 2, "i2c (isa bus adapter)")) {
 			printk(KERN_ERR
 			       "i2c-elektor.o: requested I/O region (0x%X:2) "
 			       "is in use.\n", base);
 			return -ENODEV;
-		} else {
-			request_region(base, 2, "i2c (isa bus adapter)");
 		}
 	}
 	if (irq > 0) {
@@ -156,70 +165,29 @@
 }
 
 
-static void __exit pcf_isa_exit(void)
-{
-	if (irq > 0) {
-		disable_irq(irq);
-		free_irq(irq, 0);
-	}
-	if (!mmapped) {
-		release_region(base , 2);
-	}
-}
-
-
-static int pcf_isa_reg(struct i2c_client *client)
-{
-	return 0;
-}
-
-
-static int pcf_isa_unreg(struct i2c_client *client)
-{
-	return 0;
-}
-
-static void pcf_isa_inc_use(struct i2c_adapter *adap)
-{
-#ifdef MODULE
-	MOD_INC_USE_COUNT;
-#endif
-}
-
-static void pcf_isa_dec_use(struct i2c_adapter *adap)
-{
-#ifdef MODULE
-	MOD_DEC_USE_COUNT;
-#endif
-}
-
-
 /* ------------------------------------------------------------------------
  * Encapsulate the above functions in the correct operations structure.
  * This is only done when more than one hardware adapter is supported.
  */
 static struct i2c_algo_pcf_data pcf_isa_data = {
-	NULL,
-	pcf_isa_setbyte,
-	pcf_isa_getbyte,
-	pcf_isa_getown,
-	pcf_isa_getclock,
-	pcf_isa_waitforpin,
-	10, 10, 100,		/*	waits, timeout */
+	.setpcf	    = pcf_isa_setbyte,
+	.getpcf	    = pcf_isa_getbyte,
+	.getown	    = pcf_isa_getown,
+	.getclock   = pcf_isa_getclock,
+	.waitforpin = pcf_isa_waitforpin,
+	.udelay	    = 10,
+	.mdelay	    = 10,
+	.timeout    = HZ,
 };
 
 static struct i2c_adapter pcf_isa_ops = {
-	"PCF8584 ISA adapter",
-	I2C_HW_P_ELEK,
-	NULL,
-	&pcf_isa_data,
-	pcf_isa_inc_use,
-	pcf_isa_dec_use,
-	pcf_isa_reg,
-	pcf_isa_unreg,
+	.owner		   = THIS_MODULE,
+	.name		   = "PCF8584 ISA adapter",
+	.id		   = I2C_HW_P_ELEK,
+	.algo_data	   = &pcf_isa_data,
 };
 
-int __init i2c_pcfisa_init(void) 
+static int __init i2c_pcfisa_init(void) 
 {
 #ifdef __alpha__
 	/* check to see we have memory mapped PCF8584 connected to the 
@@ -277,22 +245,41 @@
 	}
 
 	init_waitqueue_head(&pcf_wait);
-	if (pcf_isa_init() == 0) {
-		if (i2c_pcf_add_bus(&pcf_isa_ops) < 0)
-			return -ENODEV;
-	} else {
+	if (pcf_isa_init())
 		return -ENODEV;
-	}
+	if (i2c_pcf_add_bus(&pcf_isa_ops) < 0)
+		goto fail;
 	
 	printk(KERN_DEBUG "i2c-elektor.o: found device at %#x.\n", base);
 
 	return 0;
+
+ fail:
+	if (irq > 0) {
+		disable_irq(irq);
+		free_irq(irq, 0);
+	}
+
+	if (!mmapped)
+		release_region(base , 2);
+	return -ENODEV;
 }
 
+static void __exit i2c_pcfisa_exit(void)
+{
+	i2c_pcf_del_bus(&pcf_isa_ops);
+
+	if (irq > 0) {
+		disable_irq(irq);
+		free_irq(irq, 0);
+	}
+
+	if (!mmapped)
+		release_region(base , 2);
+}
 
 EXPORT_NO_SYMBOLS;
 
-#ifdef MODULE
 MODULE_AUTHOR("Hans Berglund <hb@spacetec.no>");
 MODULE_DESCRIPTION("I2C-Bus adapter routines for PCF8584 ISA bus adapter");
 MODULE_LICENSE("GPL");
@@ -304,15 +291,5 @@
 MODULE_PARM(mmapped, "i");
 MODULE_PARM(i2c_debug, "i");
 
-int init_module(void) 
-{
-	return i2c_pcfisa_init();
-}
-
-void cleanup_module(void) 
-{
-	i2c_pcf_del_bus(&pcf_isa_ops);
-	pcf_isa_exit();
-}
-
-#endif
+module_init(i2c_pcfisa_init);
+module_exit(i2c_pcfisa_exit);
diff -urN --exclude-from=diff-exclude linux-2.4.27/drivers/i2c/i2c-elv.c linux-2.4.27-leo/drivers/i2c/i2c-elv.c
--- linux-2.4.27/drivers/i2c/i2c-elv.c	2004-02-20 14:11:41.000000000 +0000
+++ linux-2.4.27-leo/drivers/i2c/i2c-elv.c	2004-09-20 21:34:38.000000000 +0100
@@ -21,21 +21,18 @@
 /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
    Frodo Looijaard <frodol@dds.nl> */
 
-/* $Id: i2c-elv.c,v 1.17 2001/07/29 02:44:25 mds Exp $ */
+/* $Id: i2c-elv.c,v 1.29 2003/12/22 20:03:11 khali Exp $ */
 
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/init.h>
-
-#include <asm/uaccess.h>
-
 #include <linux/ioport.h>
-#include <asm/io.h>
 #include <linux/errno.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
+#include <asm/io.h>
 
 #define DEFAULT_BASE 0x378
 static int base=0;
@@ -89,58 +86,31 @@
 
 static int bit_elv_init(void)
 {
-	if (check_region(base,(base == 0x3bc)? 3 : 8) < 0 ) {
-		return -ENODEV;	
-	} else {
-						/* test for ELV adap. 	*/
-		if (inb(base+1) & 0x80) {	/* BUSY should be high	*/
-			DEBINIT(printk(KERN_DEBUG "i2c-elv.o: Busy was low.\n"));
-			return -ENODEV;
-		} else {
-			outb(0x0c,base+2);	/* SLCT auf low		*/
-			udelay(400);
-			if ( !(inb(base+1) && 0x10) ) {
-				outb(0x04,base+2);
-				DEBINIT(printk(KERN_DEBUG "i2c-elv.o: Select was high.\n"));
-				return -ENODEV;
-			}
-		}
-		request_region(base,(base == 0x3bc)? 3 : 8,
-			"i2c (ELV adapter)");
-		PortData = 0;
-		bit_elv_setsda((void*)base,1);
-		bit_elv_setscl((void*)base,1);
+	if (!request_region(base, (base == 0x3bc) ? 3 : 8,
+				"i2c (ELV adapter)"))
+		return -ENODEV;
+
+	if (inb(base+1) & 0x80) {	/* BUSY should be high	*/
+		DEBINIT(printk(KERN_DEBUG "i2c-elv.o: Busy was low.\n"));
+		goto fail;
+	} 
+
+	outb(0x0c,base+2);	/* SLCT auf low		*/
+	udelay(400);
+	if (!(inb(base+1) && 0x10)) {
+		outb(0x04,base+2);
+		DEBINIT(printk(KERN_DEBUG "i2c-elv.o: Select was high.\n"));
+		goto fail;
 	}
-	return 0;
-}
-
-static void __exit bit_elv_exit(void)
-{
-	release_region( base , (base == 0x3bc)? 3 : 8 );
-}
-
-static int bit_elv_reg(struct i2c_client *client)
-{
-	return 0;
-}
 
-static int bit_elv_unreg(struct i2c_client *client)
-{
+	PortData = 0;
+	bit_elv_setsda((void*)base,1);
+	bit_elv_setscl((void*)base,1);
 	return 0;
-}
 
-static void bit_elv_inc_use(struct i2c_adapter *adap)
-{
-#ifdef MODULE
-	MOD_INC_USE_COUNT;
-#endif
-}
-
-static void bit_elv_dec_use(struct i2c_adapter *adap)
-{
-#ifdef MODULE
-	MOD_DEC_USE_COUNT;
-#endif
+fail:
+	release_region(base , (base == 0x3bc) ? 3 : 8);
+	return -ENODEV;
 }
 
 /* ------------------------------------------------------------------------
@@ -148,26 +118,23 @@
  * This is only done when more than one hardware adapter is supported.
  */
 static struct i2c_algo_bit_data bit_elv_data = {
-	NULL,
-	bit_elv_setsda,
-	bit_elv_setscl,
-	bit_elv_getsda,
-	bit_elv_getscl,
-	80, 80, 100,		/*	waits, timeout */
+	.setsda		= bit_elv_setsda,
+	.setscl		= bit_elv_setscl,
+	.getsda		= bit_elv_getsda,
+	.getscl		= bit_elv_getscl,
+	.udelay		= 80,
+	.mdelay		= 80,
+	.timeout	= HZ
 };
 
 static struct i2c_adapter bit_elv_ops = {
-	"ELV Parallel port adaptor",
-	I2C_HW_B_ELV,
-	NULL,
-	&bit_elv_data,
-	bit_elv_inc_use,
-	bit_elv_dec_use,
-	bit_elv_reg,
-	bit_elv_unreg,	
+	.owner		= THIS_MODULE,
+	.name		= "ELV Parallel port adaptor",
+	.id		= I2C_HW_B_ELV,
+	.algo_data	= &bit_elv_data,
 };
 
-int __init i2c_bitelv_init(void)
+static int __init i2c_bitelv_init(void)
 {
 	printk(KERN_INFO "i2c-elv.o: i2c ELV parallel port adapter module version %s (%s)\n", I2C_VERSION, I2C_DATE);
 	if (base==0) {
@@ -193,25 +160,19 @@
 	return 0;
 }
 
+static void __exit i2c_bitelv_exit(void)
+{
+	i2c_bit_del_bus(&bit_elv_ops);
+	release_region(base, (base == 0x3bc) ? 3 : 8);
+}
 
 EXPORT_NO_SYMBOLS;
 
-#ifdef MODULE
 MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
 MODULE_DESCRIPTION("I2C-Bus adapter routines for ELV parallel port adapter");
 MODULE_LICENSE("GPL");
 
 MODULE_PARM(base, "i");
 
-int init_module(void)
-{
-	return i2c_bitelv_init();
-}
-
-void cleanup_module(void)
-{
-	i2c_bit_del_bus(&bit_elv_ops);
-	bit_elv_exit();
-}
-
-#endif
+module_init(i2c_bitelv_init);
+module_exit(i2c_bitelv_exit);
diff -urN --exclude-from=diff-exclude linux-2.4.27/drivers/i2c/i2c-frodo.c linux-2.4.27-leo/drivers/i2c/i2c-frodo.c
--- linux-2.4.27/drivers/i2c/i2c-frodo.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.27-leo/drivers/i2c/i2c-frodo.c	2004-09-20 21:34:38.000000000 +0100
@@ -0,0 +1,83 @@
+
+/*
+ * linux/drivers/i2c/i2c-frodo.c
+ *
+ * Author: Abraham van der Merwe <abraham@2d3d.co.za>
+ *
+ * An I2C adapter driver for the 2d3D, Inc. StrongARM SA-1110
+ * Development board (Frodo).
+ *
+ * This source code is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <asm/hardware.h>
+
+
+static void frodo_setsda (void *data,int state)
+{
+	if (state)
+		FRODO_CPLD_I2C |= FRODO_I2C_SDA_OUT;
+	else
+		FRODO_CPLD_I2C &= ~FRODO_I2C_SDA_OUT;
+}
+
+static void frodo_setscl (void *data,int state)
+{
+	if (state)
+		FRODO_CPLD_I2C |= FRODO_I2C_SCL_OUT;
+	else
+		FRODO_CPLD_I2C &= ~FRODO_I2C_SCL_OUT;
+}
+
+static int frodo_getsda (void *data)
+{
+	return ((FRODO_CPLD_I2C & FRODO_I2C_SDA_IN) != 0);
+}
+
+static int frodo_getscl (void *data)
+{
+	return ((FRODO_CPLD_I2C & FRODO_I2C_SCL_IN) != 0);
+}
+
+static struct i2c_algo_bit_data bit_frodo_data = {
+	.setsda		= frodo_setsda,
+	.setscl		= frodo_setscl,
+	.getsda		= frodo_getsda,
+	.getscl		= frodo_getscl,
+	.udelay		= 80,
+	.mdelay		= 80,
+	.timeout	= HZ
+};
+
+static struct i2c_adapter frodo_ops = {
+	.owner			= THIS_MODULE,
+	.name			= "Frodo adapter driver",
+	.id			= I2C_HW_B_FRODO,
+	.algo_data		= &bit_frodo_data,
+};
+
+static int __init i2c_frodo_init (void)
+{
+	return i2c_bit_add_bus(&frodo_ops);
+}
+
+static void __exit i2c_frodo_exit (void)
+{
+	i2c_bit_del_bus(&frodo_ops);
+}
+
+MODULE_AUTHOR ("Abraham van der Merwe <abraham@2d3d.co.za>");
+MODULE_DESCRIPTION ("I2C-Bus adapter routines for Frodo");
+MODULE_LICENSE ("GPL");
+
+module_init (i2c_frodo_init);
+module_exit (i2c_frodo_exit);
+
diff -urN --exclude-from=diff-exclude linux-2.4.27/drivers/i2c/i2c-hydra.c linux-2.4.27-leo/drivers/i2c/i2c-hydra.c
--- linux-2.4.27/drivers/i2c/i2c-hydra.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.27-leo/drivers/i2c/i2c-hydra.c	2004-09-20 21:34:47.000000000 +0100
@@ -0,0 +1,175 @@
+/*
+    i2c-hydra.c - Part of lm_sensors,  Linux kernel modules
+                  for hardware monitoring
+
+    i2c Support for the Apple `Hydra' Mac I/O
+
+    Copyright (c) 1999 Geert Uytterhoeven <geert@linux-m68k.org>
+
+    Based on i2c Support for Via Technologies 82C586B South Bridge
+    Copyright (c) 1998, 1999 Kyösti Mälkki <kmalkki@cc.hut.fi>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/param.h>	/* for HZ */
+
+MODULE_LICENSE("GPL");
+
+
+#define HYDRA_CACHE_PD	0x00000030
+
+#define HYDRA_CPD_PD0	0x00000001	/* CachePD lines */
+#define HYDRA_CPD_PD1	0x00000002
+#define HYDRA_CPD_PD2	0x00000004
+#define HYDRA_CPD_PD3	0x00000008
+
+#define HYDRA_SCLK	HYDRA_CPD_PD0
+#define HYDRA_SDAT	HYDRA_CPD_PD1
+#define HYDRA_SCLK_OE	0x00000010
+#define HYDRA_SDAT_OE	0x00000020
+
+static unsigned long hydra_base;
+
+static inline void pdregw(u32 val)
+{
+	writel(val, hydra_base + HYDRA_CACHE_PD);
+}
+
+static inline u32 pdregr(void)
+{
+	u32 val = readl(hydra_base + HYDRA_CACHE_PD);
+	return val;
+}
+
+static void bit_hydra_setscl(void *data, int state)
+{
+	u32 val = pdregr();
+	if (state)
+		val &= ~HYDRA_SCLK_OE;
+	else {
+		val &= ~HYDRA_SCLK;
+		val |= HYDRA_SCLK_OE;
+	}
+	pdregw(val);
+	pdregr();	/* flush posted write */
+}
+
+static void bit_hydra_setsda(void *data, int state)
+{
+	u32 val = pdregr();
+	if (state)
+		val &= ~HYDRA_SDAT_OE;
+	else {
+		val &= ~HYDRA_SDAT;
+		val |= HYDRA_SDAT_OE;
+	}
+	pdregw(val);
+	pdregr();	/* flush posted write */
+}
+
+static int bit_hydra_getscl(void *data)
+{
+	return (pdregr() & HYDRA_SCLK) != 0;
+}
+
+static int bit_hydra_getsda(void *data)
+{
+	return (pdregr() & HYDRA_SDAT) != 0;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static struct i2c_algo_bit_data bit_hydra_data = {
+	.setsda		= bit_hydra_setsda,
+	.setscl		= bit_hydra_setscl,
+	.getsda		= bit_hydra_getsda,
+	.getscl		= bit_hydra_getscl,
+	.udelay		= 5,
+	.mdelay		= 5,
+	.timeout	= HZ
+};
+
+static struct i2c_adapter bit_hydra_ops = {
+	.owner		= THIS_MODULE,
+	.name		= "Hydra i2c",
+	.id		= I2C_HW_B_HYDRA,
+	.algo_data		= &bit_hydra_data,
+};
+
+static struct pci_device_id hydra_ids[] __devinitdata = {
+	{
+		.vendor =	PCI_VENDOR_ID_APPLE,
+		.device =	PCI_DEVICE_ID_APPLE_HYDRA,
+		.subvendor =	PCI_ANY_ID,
+		.subdevice =	PCI_ANY_ID,
+	},
+	{ 0, }
+};
+
+static int __devinit hydra_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	unsigned int base_addr;
+
+	base_addr = dev->resource[0].start;
+	hydra_base = (unsigned long) ioremap(base_addr, 0x100);
+
+	pdregw(0);		/* clear SCLK_OE and SDAT_OE */
+ 	return i2c_bit_add_bus(&bit_hydra_ops);
+}
+
+static void __devexit hydra_remove(struct pci_dev *dev)
+{
+	pdregw(0);	/* clear SCLK_OE and SDAT_OE */
+	i2c_bit_del_bus(&bit_hydra_ops);
+	iounmap((void *) hydra_base);
+}
+
+
+static struct pci_driver hydra_driver = {
+	.name		= "hydra smbus",
+	.id_table	= hydra_ids,
+	.probe		= hydra_probe,
+	.remove		= __devexit_p(hydra_remove),
+};
+
+static int __init i2c_hydra_init(void)
+{
+	return pci_module_init(&hydra_driver);
+}
+
+
+static void __exit i2c_hydra_exit(void)
+{
+	pci_unregister_driver(&hydra_driver);
+}
+
+
+
+MODULE_AUTHOR("Geert Uytterhoeven <geert@linux-m68k.org>");
+MODULE_DESCRIPTION("i2c for Apple Hydra Mac I/O");
+
+module_init(i2c_hydra_init);
+module_exit(i2c_hydra_exit);
+
diff -urN --exclude-from=diff-exclude linux-2.4.27/drivers/i2c/i2c-i801.c linux-2.4.27-leo/drivers/i2c/i2c-i801.c
--- linux-2.4.27/drivers/i2c/i2c-i801.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.27-leo/drivers/i2c/i2c-i801.c	2004-09-20 21:34:47.000000000 +0100
@@ -0,0 +1,656 @@
+/*
+    i801.c - Part of lm_sensors, Linux kernel modules for hardware
+              monitoring
+    Copyright (c) 1998 - 2002  Frodo Looijaard <frodol@dds.nl>,
+    Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker
+    <mdsxyz123@yahoo.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+    SUPPORTED DEVICES	PCI ID
+    82801AA		2413           
+    82801AB		2423           
+    82801BA		2443           
+    82801CA/CAM		2483           
+    82801DB		24C3   (HW PEC supported, 32 byte buffer not supported)
+    82801EB		24D3   (HW PEC supported, 32 byte buffer not supported)
+    6300ESB		25A4   ("")
+    ICH6		266A
+    This driver supports several versions of Intel's I/O Controller Hubs (ICH).
+    For SMBus support, they are similar to the PIIX4 and are part
+    of Intel's '810' and other chipsets.
+    See the doc/busses/i2c-i801 file for details.
+    I2C Block Read and Process Call are not supported.
+*/
+
+/* Note: we assume there can only be one I801, with one SMBus interface */
+
+/* #define DEBUG 1 */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <asm/io.h>
+#define LM_DATE "20040611"
+#define LM_VERSION "2.8.7"
+#include <linux/sensors_compat.h>
+
+/* 82801DB is undefined before kernel 2.4.19 */
+#ifndef PCI_DEVICE_ID_INTEL_82801DB_3
+#define PCI_DEVICE_ID_INTEL_82801DB_3      0x24c3
+#endif
+
+#ifdef I2C_FUNC_SMBUS_BLOCK_DATA_PEC
+#define HAVE_PEC
+#endif
+
+/* I801 SMBus address offsets */
+#define SMBHSTSTS	(0 + i801_smba)
+#define SMBHSTCNT	(2 + i801_smba)
+#define SMBHSTCMD	(3 + i801_smba)
+#define SMBHSTADD	(4 + i801_smba)
+#define SMBHSTDAT0	(5 + i801_smba)
+#define SMBHSTDAT1	(6 + i801_smba)
+#define SMBBLKDAT	(7 + i801_smba)
+#define SMBPEC		(8 + i801_smba)	/* ICH4 only */
+#define SMBAUXSTS	(12 + i801_smba)	/* ICH4 only */
+#define SMBAUXCTL	(13 + i801_smba)	/* ICH4 only */
+
+/* PCI Address Constants */
+#define SMBBA		0x020
+#define SMBHSTCFG	0x040
+#define SMBREV		0x008
+
+/* Host configuration bits for SMBHSTCFG */
+#define SMBHSTCFG_HST_EN	1
+#define SMBHSTCFG_SMB_SMI_EN	2
+#define SMBHSTCFG_I2C_EN	4
+
+/* Other settings */
+#define MAX_TIMEOUT		100
+#define ENABLE_INT9		0	/* set to 0x01 to enable - untested */
+
+/* I801 command constants */
+#define I801_QUICK		0x00
+#define I801_BYTE		0x04
+#define I801_BYTE_DATA		0x08
+#define I801_WORD_DATA		0x0C
+#define I801_PROC_CALL		0x10	/* later chips only, unimplemented */
+#define I801_BLOCK_DATA		0x14
+#define I801_I2C_BLOCK_DATA	0x18	/* unimplemented */
+#define I801_BLOCK_LAST		0x34
+#define I801_I2C_BLOCK_LAST	0x38	/* unimplemented */
+#define I801_START		0x40
+#define I801_PEC_EN		0x80	/* ICH4 only */
+
+/* insmod parameters */
+
+/* If force_addr is set to anything different from 0, we forcibly enable
+   the I801 at the given address. VERY DANGEROUS! */
+static int force_addr = 0;
+MODULE_PARM(force_addr, "i");
+MODULE_PARM_DESC(force_addr,
+		 "Forcibly enable the I801 at the given address. "
+		 "EXTREMELY DANGEROUS!");
+
+static int i801_transaction(void);
+static int i801_block_transaction(union i2c_smbus_data *data,
+				  char read_write, int command);
+
+static unsigned short i801_smba;
+static struct pci_dev *I801_dev;
+static int isich4;
+
+static int i801_setup(struct pci_dev *dev)
+{
+	int error_return = 0;
+	unsigned char temp;
+
+	/* Note: we keep on searching until we have found 'function 3' */
+	if(PCI_FUNC(dev->devfn) != 3)
+		return -ENODEV;
+
+	I801_dev = dev;
+	if (dev->device == PCI_DEVICE_ID_INTEL_82801DB_3 ||
+	    dev->device == 0x24d3 ||
+	    dev->device == 0x25a4)
+		isich4 = 1;
+	else
+		isich4 = 0;
+
+	/* Determine the address of the SMBus areas */
+	if (force_addr) {
+		i801_smba = force_addr & 0xfff0;
+	} else {
+		pci_read_config_word(I801_dev, SMBBA, &i801_smba);
+		i801_smba &= 0xfff0;
+		if(i801_smba == 0) {
+			dev_err(dev, "SMB base address uninitialized"
+				"- upgrade BIOS or use force_addr=0xaddr\n");
+			return -ENODEV;
+		}
+	}
+
+	if (!request_region(i801_smba, (isich4 ? 16 : 8), "i801-smbus")) {
+		dev_err(dev, "I801_smb region 0x%x already in use!\n",
+			i801_smba);
+		error_return = -EBUSY;
+		goto END;
+	}
+
+	pci_read_config_byte(I801_dev, SMBHSTCFG, &temp);
+	temp &= ~SMBHSTCFG_I2C_EN;	/* SMBus timing */
+	pci_write_config_byte(I801_dev, SMBHSTCFG, temp);
+
+	/* If force_addr is set, we program the new address here. Just to make
+	   sure, we disable the device first. */
+	if (force_addr) {
+		pci_write_config_byte(I801_dev, SMBHSTCFG, temp & 0xfe);
+		pci_write_config_word(I801_dev, SMBBA, i801_smba);
+		pci_write_config_byte(I801_dev, SMBHSTCFG, temp | 0x01);
+		dev_warn(dev, "WARNING: I801 SMBus interface set to "
+			"new address %04x!\n", i801_smba);
+	} else if ((temp & 1) == 0) {
+		pci_write_config_byte(I801_dev, SMBHSTCFG, temp | 1);
+		dev_warn(dev, "enabling SMBus device\n");
+	}
+
+	if (temp & 0x02)
+		dev_dbg(dev, "I801 using Interrupt SMI# for SMBus.\n");
+	else
+		dev_dbg(dev, "I801 using PCI Interrupt for SMBus.\n");
+
+	pci_read_config_byte(I801_dev, SMBREV, &temp);
+	dev_dbg(dev, "SMBREV = 0x%X\n", temp);
+	dev_dbg(dev, "I801_smba = 0x%X\n", i801_smba);
+
+END:
+	return error_return;
+}
+
+
+static int i801_transaction(void)
+{
+	int temp;
+	int result = 0;
+	int timeout = 0;
+
+	dev_dbg(I801_dev, "Transaction (pre): CNT=%02x, CMD=%02x,"
+		"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT),
+		inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
+		inb_p(SMBHSTDAT1));
+
+	/* Make sure the SMBus host is ready to start transmitting */
+	/* 0x1f = Failed, Bus_Err, Dev_Err, Intr, Host_Busy */
+	if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) {
+		dev_dbg(I801_dev, "SMBus busy (%02x). Resetting... \n",
+			temp);
+		outb_p(temp, SMBHSTSTS);
+		if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) {
+			dev_dbg(I801_dev, "Failed! (%02x)\n", temp);
+			return -1;
+		} else {
+			dev_dbg(I801_dev, "Successfull!\n");
+		}
+	}
+
+	outb_p(inb(SMBHSTCNT) | I801_START, SMBHSTCNT);
+
+	/* We will always wait for a fraction of a second! */
+	do {
+		i2c_delay(1);
+		temp = inb_p(SMBHSTSTS);
+	} while ((temp & 0x01) && (timeout++ < MAX_TIMEOUT));
+
+	/* If the SMBus is still busy, we give up */
+	if (timeout >= MAX_TIMEOUT) {
+		dev_dbg(I801_dev, "SMBus Timeout!\n");
+		result = -1;
+	}
+
+	if (temp & 0x10) {
+		result = -1;
+		dev_dbg(I801_dev, "Error: Failed bus transaction\n");
+	}
+
+	if (temp & 0x08) {
+		result = -1;
+		dev_err(I801_dev, "Bus collision! SMBus may be locked "
+			"until next hard reset. (sorry!)\n");
+		/* Clock stops and slave is stuck in mid-transmission */
+	}
+
+	if (temp & 0x04) {
+		result = -1;
+		dev_dbg(I801_dev, "Error: no response!\n");
+	}
+
+	if ((inb_p(SMBHSTSTS) & 0x1f) != 0x00)
+		outb_p(inb(SMBHSTSTS), SMBHSTSTS);
+
+	if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) {
+		dev_dbg(I801_dev, "Failed reset at end of transaction"
+			"(%02x)\n", temp);
+	}
+	dev_dbg(I801_dev, "Transaction (post): CNT=%02x, CMD=%02x, "
+		"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT),
+		inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
+		inb_p(SMBHSTDAT1));
+	return result;
+}
+
+/* All-inclusive block transaction function */
+static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
+				  int command)
+{
+	int i, len;
+	int smbcmd;
+	int temp;
+	int result = 0;
+	int timeout;
+	unsigned char hostc, errmask;
+
+	if (command == I2C_SMBUS_I2C_BLOCK_DATA) {
+		if (read_write == I2C_SMBUS_WRITE) {
+			/* set I2C_EN bit in configuration register */
+			pci_read_config_byte(I801_dev, SMBHSTCFG, &hostc);
+			pci_write_config_byte(I801_dev, SMBHSTCFG,
+					      hostc | SMBHSTCFG_I2C_EN);
+		} else {
+			dev_err(I801_dev,
+				"I2C_SMBUS_I2C_BLOCK_READ not DB!\n");
+			return -1;
+		}
+	}
+
+	if (read_write == I2C_SMBUS_WRITE) {
+		len = data->block[0];
+		if (len < 1)
+			len = 1;
+		if (len > 32)
+			len = 32;
+		outb_p(len, SMBHSTDAT0);
+		outb_p(data->block[1], SMBBLKDAT);
+	} else {
+		len = 32;	/* max for reads */
+	}
+
+	if(isich4 && command != I2C_SMBUS_I2C_BLOCK_DATA) {
+		/* set 32 byte buffer */
+	}
+
+	for (i = 1; i <= len; i++) {
+		if (i == len && read_write == I2C_SMBUS_READ)
+			smbcmd = I801_BLOCK_LAST;
+		else
+			smbcmd = I801_BLOCK_DATA;
+		outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT);
+
+		dev_dbg(I801_dev, "Block (pre %d): CNT=%02x, CMD=%02x, "
+			"ADD=%02x, DAT0=%02x, BLKDAT=%02x\n", i,
+			inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD),
+			inb_p(SMBHSTDAT0), inb_p(SMBBLKDAT));
+
+		/* Make sure the SMBus host is ready to start transmitting */
+		temp = inb_p(SMBHSTSTS);
+		if (i == 1) {
+			/* Erronenous conditions before transaction: 
+			 * Byte_Done, Failed, Bus_Err, Dev_Err, Intr, Host_Busy */
+			errmask=0x9f; 
+		} else {
+			/* Erronenous conditions during transaction: 
+			 * Failed, Bus_Err, Dev_Err, Intr */
+			errmask=0x1e; 
+		}
+		if (temp & errmask) {
+			dev_dbg(I801_dev, "SMBus busy (%02x). "
+				"Resetting... \n", temp);
+			outb_p(temp, SMBHSTSTS);
+			if (((temp = inb_p(SMBHSTSTS)) & errmask) != 0x00) {
+				dev_err(I801_dev,
+					"Reset failed! (%02x)\n", temp);
+				result = -1;
+                                goto END;
+			}
+			if (i != 1) {
+				/* if die in middle of block transaction, fail */
+				result = -1;
+				goto END;
+			}
+		}
+
+		if (i == 1)
+			outb_p(inb(SMBHSTCNT) | I801_START, SMBHSTCNT);
+
+		/* We will always wait for a fraction of a second! */
+		timeout = 0;
+		do {
+			temp = inb_p(SMBHSTSTS);
+			i2c_delay(1);
+		}
+		    while ((!(temp & 0x80))
+			   && (timeout++ < MAX_TIMEOUT));
+
+		/* If the SMBus is still busy, we give up */
+		if (timeout >= MAX_TIMEOUT) {
+			result = -1;
+			dev_dbg(I801_dev, "SMBus Timeout!\n");
+		}
+
+		if (temp & 0x10) {
+			result = -1;
+			dev_dbg(I801_dev,
+				"Error: Failed bus transaction\n");
+		} else if (temp & 0x08) {
+			result = -1;
+			dev_err(I801_dev, "Bus collision!\n");
+		} else if (temp & 0x04) {
+			result = -1;
+			dev_dbg(I801_dev, "Error: no response!\n");
+		}
+
+		if (i == 1 && read_write == I2C_SMBUS_READ) {
+			len = inb_p(SMBHSTDAT0);
+			if (len < 1)
+				len = 1;
+			if (len > 32)
+				len = 32;
+			data->block[0] = len;
+		}
+
+		/* Retrieve/store value in SMBBLKDAT */
+		if (read_write == I2C_SMBUS_READ)
+			data->block[i] = inb_p(SMBBLKDAT);
+		if (read_write == I2C_SMBUS_WRITE && i+1 <= len)
+			outb_p(data->block[i+1], SMBBLKDAT);
+		if ((temp & 0x9e) != 0x00)
+			outb_p(temp, SMBHSTSTS);  /* signals SMBBLKDAT ready */
+
+		if ((temp = (0x1e & inb_p(SMBHSTSTS))) != 0x00) {
+			dev_dbg(I801_dev,
+				"Bad status (%02x) at end of transaction\n",
+				temp);
+		}
+		dev_dbg(I801_dev, "Block (post %d): CNT=%02x, CMD=%02x, "
+			"ADD=%02x, DAT0=%02x, BLKDAT=%02x\n", i,
+			inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD),
+			inb_p(SMBHSTDAT0), inb_p(SMBBLKDAT));
+
+		if (result < 0)
+			goto END;
+	}
+
+#ifdef HAVE_PEC
+	if(isich4 && command == I2C_SMBUS_BLOCK_DATA_PEC) {
+		/* wait for INTR bit as advised by Intel */
+		timeout = 0;
+		do {
+			temp = inb_p(SMBHSTSTS);
+			i2c_delay(1);
+		} while ((!(temp & 0x02))
+			   && (timeout++ < MAX_TIMEOUT));
+
+		if (timeout >= MAX_TIMEOUT) {
+			dev_dbg(I801_dev, "PEC Timeout!\n");
+		}
+		outb_p(temp, SMBHSTSTS); 
+	}
+#endif
+	result = 0;
+END:
+	if (command == I2C_SMBUS_I2C_BLOCK_DATA) {
+		/* restore saved configuration register value */
+		pci_write_config_byte(I801_dev, SMBHSTCFG, hostc);
+	}
+	return result;
+}
+
+/* Return -1 on error. */
+static s32 i801_access(struct i2c_adapter * adap, u16 addr,
+		       unsigned short flags, char read_write, u8 command,
+		       int size, union i2c_smbus_data * data)
+{
+	int hwpec = 0;
+	int block = 0;
+	int ret, xact = 0;
+
+#ifdef HAVE_PEC
+	if(isich4)
+		hwpec = (flags & I2C_CLIENT_PEC) != 0;
+#endif
+
+	switch (size) {
+	case I2C_SMBUS_QUICK:
+		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+		       SMBHSTADD);
+		xact = I801_QUICK;
+		break;
+	case I2C_SMBUS_BYTE:
+		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+		       SMBHSTADD);
+		if (read_write == I2C_SMBUS_WRITE)
+			outb_p(command, SMBHSTCMD);
+		xact = I801_BYTE;
+		break;
+	case I2C_SMBUS_BYTE_DATA:
+		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+		       SMBHSTADD);
+		outb_p(command, SMBHSTCMD);
+		if (read_write == I2C_SMBUS_WRITE)
+			outb_p(data->byte, SMBHSTDAT0);
+		xact = I801_BYTE_DATA;
+		break;
+	case I2C_SMBUS_WORD_DATA:
+		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+		       SMBHSTADD);
+		outb_p(command, SMBHSTCMD);
+		if (read_write == I2C_SMBUS_WRITE) {
+			outb_p(data->word & 0xff, SMBHSTDAT0);
+			outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1);
+		}
+		xact = I801_WORD_DATA;
+		break;
+	case I2C_SMBUS_BLOCK_DATA:
+	case I2C_SMBUS_I2C_BLOCK_DATA:
+#ifdef HAVE_PEC
+	case I2C_SMBUS_BLOCK_DATA_PEC:
+		if(hwpec && size == I2C_SMBUS_BLOCK_DATA)
+			size = I2C_SMBUS_BLOCK_DATA_PEC;
+#endif
+		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+		       SMBHSTADD);
+		outb_p(command, SMBHSTCMD);
+		block = 1;
+		break;
+	case I2C_SMBUS_PROC_CALL:
+	default:
+		dev_err(I801_dev, "Unsupported transaction %d\n", size);
+		return -1;
+	}
+
+#ifdef HAVE_PEC
+	if(isich4 && hwpec) {
+		if(size != I2C_SMBUS_QUICK &&
+		   size != I2C_SMBUS_I2C_BLOCK_DATA)
+			outb_p(1, SMBAUXCTL);	/* enable HW PEC */
+	}
+#endif
+	if(block)
+		ret = i801_block_transaction(data, read_write, size);
+	else {
+		outb_p(xact | ENABLE_INT9, SMBHSTCNT);
+		ret = i801_transaction();
+	}
+
+#ifdef HAVE_PEC
+	if(isich4 && hwpec) {
+		if(size != I2C_SMBUS_QUICK &&
+		   size != I2C_SMBUS_I2C_BLOCK_DATA)
+			outb_p(0, SMBAUXCTL);
+	}
+#endif
+
+	if(block)
+		return ret;
+	if(ret)
+		return -1;
+	if ((read_write == I2C_SMBUS_WRITE) || (xact == I801_QUICK))
+		return 0;
+
+	switch (xact & 0x7f) {
+	case I801_BYTE:	/* Result put in SMBHSTDAT0 */
+	case I801_BYTE_DATA:
+		data->byte = inb_p(SMBHSTDAT0);
+		break;
+	case I801_WORD_DATA:
+		data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);
+		break;
+	}
+	return 0;
+}
+
+
+static u32 i801_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+	    I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+	    I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK
+#ifdef HAVE_PEC
+	     | (isich4 ? I2C_FUNC_SMBUS_BLOCK_DATA_PEC |
+	                 I2C_FUNC_SMBUS_HWPEC_CALC
+	               : 0)
+#endif
+	    ;
+}
+
+static struct i2c_algorithm smbus_algorithm = {
+	.name		= "Non-I2C SMBus adapter",
+	.id		= I2C_ALGO_SMBUS,
+	.smbus_xfer	= i801_access,
+	.functionality	= i801_func,
+};
+
+static struct i2c_adapter i801_adapter = {
+	.owner		= THIS_MODULE,
+	.id		= I2C_ALGO_SMBUS | I2C_HW_SMBUS_I801,
+	.algo		= &smbus_algorithm,
+	.name	= "unset",
+};
+
+static struct pci_device_id i801_ids[] __devinitdata = {
+	{
+		.vendor =	PCI_VENDOR_ID_INTEL,
+		.device =	PCI_DEVICE_ID_INTEL_82801AA_3,
+		.subvendor =	PCI_ANY_ID,
+		.subdevice =	PCI_ANY_ID,
+	},
+	{
+		.vendor =	PCI_VENDOR_ID_INTEL,
+		.device =	PCI_DEVICE_ID_INTEL_82801AB_3,
+		.subvendor =	PCI_ANY_ID,
+		.subdevice =	PCI_ANY_ID,
+	},
+	{
+		.vendor =	PCI_VENDOR_ID_INTEL,
+		.device =	PCI_DEVICE_ID_INTEL_82801BA_2,
+		.subvendor =	PCI_ANY_ID,
+		.subdevice =	PCI_ANY_ID,
+	},
+	{
+		.vendor =	PCI_VENDOR_ID_INTEL,
+		.device =	PCI_DEVICE_ID_INTEL_82801CA_3,
+		.subvendor =	PCI_ANY_ID,
+		.subdevice =	PCI_ANY_ID,
+	},
+	{
+		.vendor =	PCI_VENDOR_ID_INTEL,
+		.device =	PCI_DEVICE_ID_INTEL_82801DB_3,
+		.subvendor =	PCI_ANY_ID,
+		.subdevice =	PCI_ANY_ID,
+	},
+	{
+		.vendor =	PCI_VENDOR_ID_INTEL,
+		.device =	0x24d3,	/* 82801EB ICH5 */
+		.subvendor =	PCI_ANY_ID,
+		.subdevice =	PCI_ANY_ID,
+	},
+	{
+		.vendor =	PCI_VENDOR_ID_INTEL,
+		.device =	0x25a4, /* PCI_DEVICE_ID_INTEL_ESB_4 */
+		.subvendor =	PCI_ANY_ID,
+		.subdevice = 	PCI_ANY_ID,
+	},
+	{
+		.vendor =	PCI_VENDOR_ID_INTEL,
+		.device =	0x266a, /* PCI_DEVICE_ID_INTEL_ICH6_16 */
+		.subvendor =	PCI_ANY_ID,
+		.subdevice =	PCI_ANY_ID,
+  	},
+	{ 0, }
+};
+
+static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+
+	if (i801_setup(dev)) {
+		dev_warn(dev,
+			"I801 not detected, module not inserted.\n");
+		return -ENODEV;
+	}
+
+	snprintf(i801_adapter.name, 32,
+		"SMBus I801 adapter at %04x", i801_smba);
+	return i2c_add_adapter(&i801_adapter);
+}
+
+static void __devexit i801_remove(struct pci_dev *dev)
+{
+	i2c_del_adapter(&i801_adapter);
+	release_region(i801_smba, (isich4 ? 16 : 8));
+}
+
+static struct pci_driver i801_driver = {
+	.name		= "i801 smbus",
+	.id_table	= i801_ids,
+	.probe		= i801_probe,
+	.remove		= __devexit_p(i801_remove),
+};
+
+static int __init i2c_i801_init(void)
+{
+	printk(KERN_INFO "i2c-i801 version %s (%s)\n", LM_VERSION, LM_DATE);
+	return pci_module_init(&i801_driver);
+}
+
+static void __exit i2c_i801_exit(void)
+{
+	pci_unregister_driver(&i801_driver);
+}
+
+MODULE_AUTHOR ("Frodo Looijaard <frodol@dds.nl>, "
+		"Philip Edelbrock <phil@netroedge.com>, "
+		"and Mark D. Studebaker <mdsxyz123@yahoo.com>");
+MODULE_DESCRIPTION("I801 SMBus driver");
+MODULE_LICENSE("GPL");
+
+module_init(i2c_i801_init);
+module_exit(i2c_i801_exit);
diff -urN --exclude-from=diff-exclude linux-2.4.27/drivers/i2c/i2c-i810.c linux-2.4.27-leo/drivers/i2c/i2c-i810.c
--- linux-2.4.27/drivers/i2c/i2c-i810.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.27-leo/drivers/i2c/i2c-i810.c	2004-09-20 21:34:47.000000000 +0100
@@ -0,0 +1,310 @@
+/*
+    i2c-i810.c - Part of lm_sensors, Linux kernel modules for hardware
+              monitoring
+    Copyright (c) 1998, 1999, 2000  Frodo Looijaard <frodol@dds.nl>,
+    Philip Edelbrock <phil@netroedge.com>,
+    Ralph Metzler <rjkm@thp.uni-koeln.de>, and
+    Mark D. Studebaker <mdsxyz123@yahoo.com>
+    
+    Based on code written by Ralph Metzler <rjkm@thp.uni-koeln.de> and
+    Simon Vogl
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+/*
+   This interfaces to the I810/I815 to provide access to
+   the DDC Bus and the I2C Bus.
+
+   SUPPORTED DEVICES	PCI ID
+   i810AA		7121           
+   i810AB		7123           
+   i810E		7125           
+   i815			1132           
+*/
+
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include <asm/param.h>	/* for HZ */
+#define LM_DATE "20040611"
+#define LM_VERSION "2.8.7"
+
+MODULE_LICENSE("GPL");
+
+#ifndef PCI_DEVICE_ID_INTEL_82815_2
+#define PCI_DEVICE_ID_INTEL_82815_2   0x1132
+#endif
+
+/* GPIO register locations */
+#define I810_IOCONTROL_OFFSET 0x5000
+#define I810_HVSYNC	0x00	/* not used */
+#define I810_GPIOA	0x10
+#define I810_GPIOB	0x14
+
+/* bit locations in the registers */
+#define SCL_DIR_MASK	0x0001
+#define SCL_DIR		0x0002
+#define SCL_VAL_MASK	0x0004
+#define SCL_VAL_OUT	0x0008
+#define SCL_VAL_IN	0x0010
+#define SDA_DIR_MASK	0x0100
+#define SDA_DIR		0x0200
+#define SDA_VAL_MASK	0x0400
+#define SDA_VAL_OUT	0x0800
+#define SDA_VAL_IN	0x1000
+
+/* initialization states */
+#define INIT1	0x1
+#define INIT2	0x2
+#define INIT3	0x4
+
+/* delays */
+#define CYCLE_DELAY		10
+#define TIMEOUT			(HZ / 2)
+
+
+static void config_i810(struct pci_dev *dev);
+
+
+static unsigned long ioaddr;
+
+/* The i810 GPIO registers have individual masks for each bit
+   so we never have to read before writing. Nice. */
+
+static void bit_i810i2c_setscl(void *data, int val)
+{
+	writel((val ? SCL_VAL_OUT : 0) | SCL_DIR | SCL_DIR_MASK | SCL_VAL_MASK,
+	     ioaddr + I810_GPIOB);
+	readl(ioaddr + I810_GPIOB);	/* flush posted write */
+}
+
+static void bit_i810i2c_setsda(void *data, int val)
+{
+ 	writel((val ? SDA_VAL_OUT : 0) | SDA_DIR | SDA_DIR_MASK | SDA_VAL_MASK,
+	     ioaddr + I810_GPIOB);
+	readl(ioaddr + I810_GPIOB);	/* flush posted write */
+}
+
+/* The GPIO pins are open drain, so the pins could always remain outputs.
+   However, some chip versions don't latch the inputs unless they
+   are set as inputs.
+   We rely on the i2c-algo-bit routines to set the pins high before
+   reading the input from other chips. Following guidance in the 815
+   prog. ref. guide, we do a "dummy write" of 0 to the register before
+   reading which forces the input value to be latched. We presume this
+   applies to the 810 as well; shouldn't hurt anyway. This is necessary to get
+   i2c_algo_bit bit_test=1 to pass. */
+
+static int bit_i810i2c_getscl(void *data)
+{
+	writel(SCL_DIR_MASK, ioaddr + I810_GPIOB);
+	writel(0, ioaddr + I810_GPIOB);
+	return (0 != (readl(ioaddr + I810_GPIOB) & SCL_VAL_IN));
+}
+
+static int bit_i810i2c_getsda(void *data)
+{
+	writel(SDA_DIR_MASK, ioaddr + I810_GPIOB);
+	writel(0, ioaddr + I810_GPIOB);
+	return (0 != (readl(ioaddr + I810_GPIOB) & SDA_VAL_IN));
+}
+
+static void bit_i810ddc_setscl(void *data, int val)
+{
+	writel((val ? SCL_VAL_OUT : 0) | SCL_DIR | SCL_DIR_MASK | SCL_VAL_MASK,
+	     ioaddr + I810_GPIOA);
+	readl(ioaddr + I810_GPIOA);	/* flush posted write */
+}
+
+static void bit_i810ddc_setsda(void *data, int val)
+{
+ 	writel((val ? SDA_VAL_OUT : 0) | SDA_DIR | SDA_DIR_MASK | SDA_VAL_MASK,
+	     ioaddr + I810_GPIOA);
+	readl(ioaddr + I810_GPIOA);	/* flush posted write */
+}
+
+static int bit_i810ddc_getscl(void *data)
+{
+	writel(SCL_DIR_MASK, ioaddr + I810_GPIOA);
+	writel(0, ioaddr + I810_GPIOA);
+	return (0 != (readl(ioaddr + I810_GPIOA) & SCL_VAL_IN));
+}
+
+static int bit_i810ddc_getsda(void *data)
+{
+	writel(SDA_DIR_MASK, ioaddr + I810_GPIOA);
+	writel(0, ioaddr + I810_GPIOA);
+	return (0 != (readl(ioaddr + I810_GPIOA) & SDA_VAL_IN));
+}
+
+
+/* Configures the chip */
+void config_i810(struct pci_dev *dev)
+{
+	unsigned long cadr;
+
+	/* map I810 memory */
+	cadr = dev->resource[1].start;
+	cadr += I810_IOCONTROL_OFFSET;
+	cadr &= PCI_BASE_ADDRESS_MEM_MASK;
+	ioaddr = (unsigned long)ioremap_nocache(cadr, 0x1000);
+	if(ioaddr) {
+		bit_i810i2c_setscl(NULL, 1);
+		bit_i810i2c_setsda(NULL, 1);
+		bit_i810ddc_setscl(NULL, 1);
+		bit_i810ddc_setsda(NULL, 1);
+	}
+}
+
+
+static struct i2c_algo_bit_data i810_i2c_bit_data = {
+	.setsda		= bit_i810i2c_setsda,
+	.setscl		= bit_i810i2c_setscl,
+	.getsda		= bit_i810i2c_getsda,
+	.getscl		= bit_i810i2c_getscl,
+	.udelay		= CYCLE_DELAY,
+	.mdelay		= CYCLE_DELAY,
+	.timeout	= TIMEOUT,
+};
+
+static struct i2c_adapter i810_i2c_adapter = {
+	.owner		= THIS_MODULE,
+	.name		= "I810/I815 I2C Adapter",
+	.id		= I2C_HW_B_I810,
+	.algo_data	= &i810_i2c_bit_data,
+};
+
+static struct i2c_algo_bit_data i810_ddc_bit_data = {
+	.setsda		= bit_i810ddc_setsda,
+	.setscl		= bit_i810ddc_setscl,
+	.getsda		= bit_i810ddc_getsda,
+	.getscl		= bit_i810ddc_getscl,
+	.udelay		= CYCLE_DELAY,
+	.mdelay		= CYCLE_DELAY,
+	.timeout	= TIMEOUT,
+};
+
+static struct i2c_adapter i810_ddc_adapter = {
+	.owner		= THIS_MODULE,
+	.name		= "I810/I815 DDC Adapter",
+	.id		= I2C_HW_B_I810,
+	.algo_data	= &i810_ddc_bit_data,
+};
+
+
+static struct pci_device_id i810_ids[] __devinitdata = {
+	{
+		.vendor =	PCI_VENDOR_ID_INTEL,
+		.device =	PCI_DEVICE_ID_INTEL_82810_IG1,
+		.subvendor =	PCI_ANY_ID,
+		.subdevice =	PCI_ANY_ID,
+	},
+	{
+		.vendor =	PCI_VENDOR_ID_INTEL,
+		.device =	PCI_DEVICE_ID_INTEL_82810_IG3,
+		.subvendor =	PCI_ANY_ID,
+		.subdevice =	PCI_ANY_ID,
+	},
+	{
+		.vendor =	PCI_VENDOR_ID_INTEL,
+		.device =	0x7125,
+		.subvendor =	PCI_ANY_ID,
+		.subdevice =	PCI_ANY_ID,
+	},
+	{
+		.vendor =	PCI_VENDOR_ID_INTEL,
+		.device =	PCI_DEVICE_ID_INTEL_82815_2,
+		.subvendor =	PCI_ANY_ID,
+		.subdevice =	PCI_ANY_ID,
+	},
+	{
+		.vendor =	PCI_VENDOR_ID_INTEL,
+		.device =	0x2562,
+		.subvendor =	PCI_ANY_ID,
+		.subdevice =	PCI_ANY_ID,
+	},
+	{ 0, }
+};
+
+static int __devinit i810_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	int retval;
+
+	config_i810(dev);
+	printk("i2c-i810.o: i810/i815 found.\n");
+
+	retval = i2c_bit_add_bus(&i810_i2c_adapter);
+	if(retval)
+		return retval;
+	retval = i2c_bit_add_bus(&i810_ddc_adapter);
+	if(retval)
+		i2c_bit_del_bus(&i810_i2c_adapter);
+	return retval;
+}
+
+static void __devexit i810_remove(struct pci_dev *dev)
+{
+	i2c_bit_del_bus(&i810_ddc_adapter);
+	i2c_bit_del_bus(&i810_i2c_adapter);
+}
+
+
+/* Don't register driver to avoid driver conflicts */
+/*
+static struct pci_driver i810_driver = {
+	.name		= "i810 smbus",
+	.id_table	= i810_ids,
+	.probe		= i810_probe,
+	.remove		= __devexit_p(i810_remove),
+};
+*/
+
+static int __init i2c_i810_init(void)
+{
+	struct pci_dev *dev;
+	const struct pci_device_id *id;
+
+	printk("i2c-i810.o version %s (%s)\n", LM_VERSION, LM_DATE);
+/*
+	return pci_module_init(&i810_driver);
+*/
+	pci_for_each_dev(dev) {
+		id = pci_match_device(i810_ids, dev);
+		if(id)
+			if(i810_probe(dev, id) >= 0)
+				return 0;
+	}
+	return -ENODEV;
+}
+
+static void __exit i2c_i810_exit(void)
+{
+/*
+	pci_unregister_driver(&i810_driver);
+*/
+	i810_remove(NULL);
+	iounmap((void *)ioaddr);
+}
+
+MODULE_AUTHOR
+    ("Frodo Looijaard <frodol@dds.nl>, Philip Edelbrock <phil@netroedge.com>, Ralph Metzler <rjkm@thp.uni-koeln.de>, and Mark D. Studebaker <mdsxyz123@yahoo.com>");
+MODULE_DESCRIPTION("I810/I815 I2C/DDC driver");
+
+module_init(i2c_i810_init);
+module_exit(i2c_i810_exit);
diff -urN --exclude-from=diff-exclude linux-2.4.27/drivers/i2c/i2c-isa.c linux-2.4.27-leo/drivers/i2c/i2c-isa.c
--- linux-2.4.27/drivers/i2c/i2c-isa.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.27-leo/drivers/i2c/i2c-isa.c	2004-09-20 21:34:47.000000000 +0100
@@ -0,0 +1,74 @@
+/*
+    i2c-isa.c - Part of lm_sensors, Linux kernel modules for hardware
+            monitoring
+    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl> 
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* This implements an i2c algorithm/adapter for ISA bus. Not that this is
+   on first sight very useful; almost no functionality is preserved.
+   Except that it makes writing drivers for chips which can be on both
+   the SMBus and the ISA bus very much easier. See lm78.c for an example
+   of this. */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#define LM_DATE "20040611"
+#define LM_VERSION "2.8.7"
+
+static u32 isa_func(struct i2c_adapter *adapter);
+
+/* This is the actual algorithm we define */
+static struct i2c_algorithm isa_algorithm = {
+	.name		= "ISA bus algorithm",
+	.id		= I2C_ALGO_ISA,
+	.functionality	= isa_func,
+};
+
+/* There can only be one... */
+static struct i2c_adapter isa_adapter = {
+	.owner		= THIS_MODULE,
+	.name		= "ISA main adapter",
+	.id		= I2C_ALGO_ISA | I2C_HW_ISA,
+	.algo		= &isa_algorithm,
+};
+
+/* We can't do a thing... */
+static u32 isa_func(struct i2c_adapter *adapter)
+{
+	return 0;
+}
+
+static int __init i2c_isa_init(void)
+{
+	printk("i2c-isa.o version %s (%s)\n", LM_VERSION, LM_DATE);
+	return i2c_add_adapter(&isa_adapter);
+}
+
+static void __exit i2c_isa_exit(void)
+{
+	i2c_del_adapter(&isa_adapter);
+}
+
+MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");
+MODULE_DESCRIPTION("ISA bus access through i2c");
+MODULE_LICENSE("GPL");
+
+module_init(i2c_isa_init);
+module_exit(i2c_isa_exit);
diff -urN --exclude-from=diff-exclude linux-2.4.27/drivers/i2c/i2c-nforce2.c linux-2.4.27-leo/drivers/i2c/i2c-nforce2.c
--- linux-2.4.27/drivers/i2c/i2c-nforce2.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.27-leo/drivers/i2c/i2c-nforce2.c	2004-09-20 21:34:47.000000000 +0100
@@ -0,0 +1,409 @@
+/*
+    SMBus driver for nVidia nForce2 MCP
+
+    Copyright (c) 2003  Hans-Frieder Vogt <hfvogt@arcor.de>,
+    Based on
+    SMBus 2.0 driver for AMD-8111 IO-Hub
+    Copyright (c) 2002 Vojtech Pavlik
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+    SUPPORTED DEVICES	PCI ID
+    nForce2 MCP		0064       
+
+    This driver supports the 2 SMBuses that are included in the MCP2 of the
+    nForce2 chipset.
+*/
+
+/* Note: we assume there can only be one nForce2, with two SMBus interfaces */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <asm/io.h>
+#define LM_DATE "20040611"
+#define LM_VERSION "2.8.7"
+
+/* kernel 2.4.9 needs this */
+#ifndef min_t
+#define min_t(type,x,y) min(type,x,y)
+#endif
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR ("Hans-Frieder Vogt <hfvogt@arcor.de>");
+MODULE_DESCRIPTION("nForce2 SMBus driver");
+
+#ifndef PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS
+#define PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS   0x0064
+#endif
+
+
+struct nforce2_smbus {
+	struct pci_dev *dev;
+	struct i2c_adapter adapter;
+	int base;
+	int size;
+};
+
+
+/*
+ * nVidia nForce2 SMBus control register definitions
+ */
+#define NFORCE_PCI_SMB1	0x50
+#define NFORCE_PCI_SMB2	0x54
+
+
+/*
+ * ACPI 2.0 chapter 13 SMBus 2.0 EC register model
+ */
+#define NVIDIA_SMB_PRTCL	(smbus->base + 0x00)	/* protocol, PEC */
+#define NVIDIA_SMB_STS		(smbus->base + 0x01)	/* status */
+#define NVIDIA_SMB_ADDR		(smbus->base + 0x02)	/* address */
+#define NVIDIA_SMB_CMD		(smbus->base + 0x03)	/* command */
+#define NVIDIA_SMB_DATA		(smbus->base + 0x04)	/* 32 data registers */
+#define NVIDIA_SMB_BCNT		(smbus->base + 0x24)	/* number of data bytes */
+#define NVIDIA_SMB_ALRM_A	(smbus->base + 0x25)	/* alarm address */
+#define NVIDIA_SMB_ALRM_D	(smbus->base + 0x26)	/* 2 bytes alarm data */
+
+#define NVIDIA_SMB_STS_DONE	0x80
+#define NVIDIA_SMB_STS_ALRM	0x40
+#define NVIDIA_SMB_STS_RES	0x20
+#define NVIDIA_SMB_STS_STATUS	0x1f
+
+#define NVIDIA_SMB_PRTCL_WRITE			0x00
+#define NVIDIA_SMB_PRTCL_READ			0x01
+#define NVIDIA_SMB_PRTCL_QUICK			0x02
+#define NVIDIA_SMB_PRTCL_BYTE			0x04
+#define NVIDIA_SMB_PRTCL_BYTE_DATA		0x06
+#define NVIDIA_SMB_PRTCL_WORD_DATA		0x08
+#define NVIDIA_SMB_PRTCL_BLOCK_DATA		0x0a
+#define NVIDIA_SMB_PRTCL_PROC_CALL		0x0c
+#define NVIDIA_SMB_PRTCL_BLOCK_PROC_CALL	0x0d
+#define NVIDIA_SMB_PRTCL_I2C_BLOCK_DATA		0x4a
+#define NVIDIA_SMB_PRTCL_PEC			0x80
+
+
+/* Other settings */
+#define MAX_TIMEOUT 256
+
+
+
+static s32 nforce2_access(struct i2c_adapter *adap, u16 addr,
+		       unsigned short flags, char read_write,
+		       u8 command, int size, union i2c_smbus_data *data);
+/*
+static int nforce2_block_transaction(union i2c_smbus_data *data,
+				  char read_write, int i2c_enable);
+ */
+static u32 nforce2_func(struct i2c_adapter *adapter);
+
+
+static struct i2c_algorithm smbus_algorithm = {
+	.name = "Non-I2C SMBus adapter",
+	.id = I2C_ALGO_SMBUS,
+	.smbus_xfer = nforce2_access,
+	.functionality = nforce2_func,
+};
+
+/* Return -1 on error. See smbus.h for more information */
+s32 nforce2_access(struct i2c_adapter * adap, u16 addr, unsigned short flags,
+		char read_write, u8 command, int size,
+		union i2c_smbus_data * data)
+{
+	struct nforce2_smbus *smbus = adap->algo_data;
+	unsigned char protocol, pec, temp;
+	unsigned char len = 0; /* to keep the compiler quiet */
+	int timeout = 0;
+	int i;
+
+	protocol = (read_write == I2C_SMBUS_READ) ? NVIDIA_SMB_PRTCL_READ : NVIDIA_SMB_PRTCL_WRITE;
+	pec = (flags & I2C_CLIENT_PEC) ? NVIDIA_SMB_PRTCL_PEC : 0;
+
+	switch (size) {
+
+		case I2C_SMBUS_QUICK:
+			protocol |= NVIDIA_SMB_PRTCL_QUICK;
+			read_write = I2C_SMBUS_WRITE;
+			break;
+
+		case I2C_SMBUS_BYTE:
+			if (read_write == I2C_SMBUS_WRITE)
+				outb_p(command, NVIDIA_SMB_CMD);
+			protocol |= NVIDIA_SMB_PRTCL_BYTE;
+			break;
+
+		case I2C_SMBUS_BYTE_DATA:
+			outb_p(command, NVIDIA_SMB_CMD);
+			if (read_write == I2C_SMBUS_WRITE)
+				outb_p(data->byte, NVIDIA_SMB_DATA);
+			protocol |= NVIDIA_SMB_PRTCL_BYTE_DATA;
+			break;
+
+		case I2C_SMBUS_WORD_DATA:
+			outb_p(command, NVIDIA_SMB_CMD);
+			if (read_write == I2C_SMBUS_WRITE) {
+				 outb_p(data->word, NVIDIA_SMB_DATA);
+				 outb_p(data->word >> 8, NVIDIA_SMB_DATA+1);
+			}
+			protocol |= NVIDIA_SMB_PRTCL_WORD_DATA | pec;
+			break;
+
+		case I2C_SMBUS_BLOCK_DATA:
+			outb_p(command, NVIDIA_SMB_CMD);
+			if (read_write == I2C_SMBUS_WRITE) {
+				len = min_t(u8, data->block[0], 32);
+				outb_p(len, NVIDIA_SMB_BCNT);
+				for (i = 0; i < len; i++)
+					outb_p(data->block[i + 1], NVIDIA_SMB_DATA+i);
+			}
+			protocol |= NVIDIA_SMB_PRTCL_BLOCK_DATA | pec;
+			break;
+
+		case I2C_SMBUS_I2C_BLOCK_DATA:
+			len = min_t(u8, data->block[0], 32);
+			outb_p(command, NVIDIA_SMB_CMD);
+			outb_p(len, NVIDIA_SMB_BCNT);
+			if (read_write == I2C_SMBUS_WRITE)
+				for (i = 0; i < len; i++)
+					outb_p(data->block[i + 1], NVIDIA_SMB_DATA+i);
+			protocol |= NVIDIA_SMB_PRTCL_I2C_BLOCK_DATA;
+			break;
+
+		case I2C_SMBUS_PROC_CALL:
+			printk(KERN_WARNING "i2c-nforce2.o: I2C_SMBUS_PROC_CALL not supported!\n");
+			return -1;
+			/*
+			outb_p(command, NVIDIA_SMB_CMD);
+			outb_p(data->word, NVIDIA_SMB_DATA);
+			outb_p(data->word >> 8, NVIDIA_SMB_DATA + 1);
+			protocol = NVIDIA_SMB_PRTCL_PROC_CALL | pec;
+			read_write = I2C_SMBUS_READ;
+			break;
+			 */
+
+		case I2C_SMBUS_BLOCK_PROC_CALL:
+			printk(KERN_WARNING "i2c-nforce2.o: I2C_SMBUS_BLOCK_PROC_CALL not supported!\n");
+			return -1;
+			/*
+			protocol |= pec;
+			len = min_t(u8, data->block[0], 31);
+			outb_p(command, NVIDIA_SMB_CMD);
+			outb_p(len, NVIDIA_SMB_BCNT);
+			for (i = 0; i < len; i++)
+				outb_p(data->block[i + 1], NVIDIA_SMB_DATA + i);
+			protocol = NVIDIA_SMB_PRTCL_BLOCK_PROC_CALL | pec;
+			read_write = I2C_SMBUS_READ;
+			break;
+			*/
+
+		case I2C_SMBUS_WORD_DATA_PEC:
+		case I2C_SMBUS_BLOCK_DATA_PEC:
+		case I2C_SMBUS_PROC_CALL_PEC:
+		case I2C_SMBUS_BLOCK_PROC_CALL_PEC:
+			printk(KERN_WARNING "i2c-nforce2.c: Unexpected software PEC transaction %d\n.", size);
+			return -1;
+
+		default:
+			printk(KERN_WARNING "i2c-nforce2.c: Unsupported transaction %d\n", size);
+			return -1;
+	}
+
+	outb_p((addr & 0x7f) << 1, NVIDIA_SMB_ADDR);
+	outb_p(protocol, NVIDIA_SMB_PRTCL);
+
+	temp = inb_p(NVIDIA_SMB_STS);
+
+#if 0
+	do {
+		i2c_delay(1);
+		temp = inb_p(NVIDIA_SMB_STS);
+	} while (((temp & NVIDIA_SMB_STS_DONE) == 0) && (timeout++ < MAX_TIMEOUT));
+#endif
+	if (~temp & NVIDIA_SMB_STS_DONE) {
+		udelay(500);
+		temp = inb_p(NVIDIA_SMB_STS);
+	}
+	if (~temp & NVIDIA_SMB_STS_DONE) {
+		i2c_delay(HZ/100);
+		temp = inb_p(NVIDIA_SMB_STS);
+	}
+
+	if ((timeout >= MAX_TIMEOUT) || (~temp & NVIDIA_SMB_STS_DONE) || (temp & NVIDIA_SMB_STS_STATUS))
+		return -1;
+
+	if (read_write == I2C_SMBUS_WRITE)
+		return 0;
+
+	switch (size) {
+
+		case I2C_SMBUS_BYTE:
+		case I2C_SMBUS_BYTE_DATA:
+			data->byte = inb_p(NVIDIA_SMB_DATA);
+			break;
+
+		case I2C_SMBUS_WORD_DATA:
+		/* case I2C_SMBUS_PROC_CALL: not supported */
+			data->word = inb_p(NVIDIA_SMB_DATA) | (inb_p(NVIDIA_SMB_DATA+1) << 8);
+			break;
+
+		case I2C_SMBUS_BLOCK_DATA:
+		/* case I2C_SMBUS_BLOCK_PROC_CALL: not supported */
+			len = inb_p(NVIDIA_SMB_BCNT);
+			len = min_t(u8, len, 32);
+		case I2C_SMBUS_I2C_BLOCK_DATA:
+			for (i = 0; i < len; i++)
+				data->block[i+1] = inb_p(NVIDIA_SMB_DATA + i);
+			data->block[0] = len;
+			break;
+	}
+
+	return 0;
+}
+
+
+u32 nforce2_func(struct i2c_adapter *adapter)
+{
+	/* other functionality might be possible, but is not tested */
+	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+	    I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA /* |
+	    I2C_FUNC_SMBUS_BLOCK_DATA */;
+}
+
+
+static struct pci_device_id nforce2_ids[] = {
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS,
+	       	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ 0 }
+};
+
+
+static int __devinit nforce2_probe_smb (struct pci_dev *dev, int reg, struct nforce2_smbus *smbus, char *name)
+{
+	u16 iobase;
+	int error;
+
+	if (pci_read_config_word(dev, reg, &iobase) != PCIBIOS_SUCCESSFUL) {
+		printk (KERN_ERR "i2c-nforce2.o: Error reading PCI config for %s\n", name);
+		return -1;
+	}
+	smbus->dev  = dev;
+	smbus->base = iobase & 0xfffc;
+	smbus->size = 8;
+
+	if (!request_region(smbus->base, smbus->size, "nForce2 SMBus")) {
+		printk (KERN_ERR "i2c-nforce2.o: Error requesting region %02x .. %02X for %s\n", smbus->base, smbus->base+smbus->size-1, name);
+		return -1;
+	}
+
+	/* TODO: find a better way to find out whether this file is compiled
+	 * with i2c 2.7.0 of earlier
+	 */
+#ifdef I2C_HW_SMBUS_AMD8111
+	smbus->adapter.owner = THIS_MODULE;
+#endif
+	sprintf(smbus->adapter.name, "SMBus nForce2 adapter at %04x", smbus->base);
+	smbus->adapter.id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_NFORCE2;
+	smbus->adapter.algo = &smbus_algorithm;
+	smbus->adapter.algo_data = smbus;
+
+	error = i2c_add_adapter(&smbus->adapter);
+	if (error) {
+		printk(KERN_WARNING "i2c-nforce2.o: Failed to register adapter.\n");
+		release_region(smbus->base, smbus->size);
+		return -1;
+	}
+	printk(KERN_INFO "i2c-nforce2.o: nForce2 SMBus adapter at %#x\n", smbus->base);
+	return 0;
+}
+
+
+static int __devinit nforce2_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	struct nforce2_smbus *smbuses;
+	int res1, res2;
+
+	/* we support 2 SMBus adapters */
+	if (!(smbuses = (void *)kmalloc(2*sizeof(struct nforce2_smbus),
+				       	GFP_KERNEL)))
+		return -ENOMEM;
+	memset (smbuses, 0, 2*sizeof(struct nforce2_smbus));
+	pci_set_drvdata(dev, smbuses);
+
+	/* SMBus adapter 1 */
+	res1 = nforce2_probe_smb (dev, NFORCE_PCI_SMB1, &smbuses[0], "SMB1");
+	if (res1 < 0) {
+		printk (KERN_ERR "i2c-nforce2.o: Error probing SMB1.\n");
+		smbuses[0].base = 0;	/* to have a check value */
+	}
+	res2 = nforce2_probe_smb (dev, NFORCE_PCI_SMB2, &smbuses[1], "SMB2");
+	if (res2 < 0) {
+		printk (KERN_ERR "i2c-nforce2.o: Error probing SMB2.\n");
+		smbuses[1].base = 0;	/* to have a check value */
+	}
+	if ((res1 < 0) && (res2 < 0)) {
+		/* we did not find even one of the SMBuses, so we give up */
+		kfree(smbuses);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+
+static void __devexit nforce2_remove(struct pci_dev *dev)
+{
+	struct nforce2_smbus *smbuses = (void*) pci_get_drvdata(dev);
+
+	if (smbuses[0].base) {
+		i2c_del_adapter(&smbuses[0].adapter);
+		release_region(smbuses[0].base, smbuses[0].size);
+	}
+	if (smbuses[1].base) {
+		i2c_del_adapter(&smbuses[1].adapter);
+		release_region(smbuses[1].base, smbuses[1].size);
+	}
+	kfree(smbuses);
+}
+
+static struct pci_driver nforce2_driver = {
+	.name		= "nForce2 SMBus",
+	.id_table	= nforce2_ids,
+	.probe		= nforce2_probe,
+	.remove		= __devexit_p(nforce2_remove),
+};
+
+int __init nforce2_init(void)
+{
+	printk(KERN_INFO "i2c-nforce2.o version %s (%s)\n", LM_VERSION, LM_DATE);
+	return pci_module_init(&nforce2_driver);
+}
+
+void __exit nforce2_exit(void)
+{
+	pci_unregister_driver(&nforce2_driver);
+}
+
+module_init(nforce2_init);
+module_exit(nforce2_exit);
+
diff -urN --exclude-from=diff-exclude linux-2.4.27/drivers/i2c/i2c-pcf-epp.c linux-2.4.27-leo/drivers/i2c/i2c-pcf-epp.c
--- linux-2.4.27/drivers/i2c/i2c-pcf-epp.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.27-leo/drivers/i2c/i2c-pcf-epp.c	2004-09-20 21:34:38.000000000 +0100
@@ -0,0 +1,281 @@
+/* ------------------------------------------------------------------------- */
+/* i2c-pcf-epp.c i2c-hw access for PCF8584 style EPP parallel port adapters  */
+/* ------------------------------------------------------------------------- */
+/*   Copyright (C) 1998-99 Hans Berglund
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.		     */
+/* ------------------------------------------------------------------------- */
+
+/* With some changes from Ryosuke Tajima <rosk@jsk.t.u-tokyo.ac.jp> */
+
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/parport.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-pcf.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+
+struct  i2c_pcf_epp {
+  int pe_base;
+  int pe_irq;
+  int pe_clock;
+  int pe_own;
+} ;
+
+#define DEFAULT_BASE 0x378
+#define DEFAULT_IRQ      7
+#define DEFAULT_CLOCK 0x1c
+#define DEFAULT_OWN   0x55
+
+static int base  = 0;
+static int irq   = 0;
+static int clock = 0;
+static int own   = 0;
+static int i2c_debug=0;
+static struct i2c_pcf_epp gpe;
+static wait_queue_head_t pcf_wait;
+static int pcf_pending;
+static spinlock_t irq_driver_lock = SPIN_LOCK_UNLOCKED;
+
+/* ----- global defines -----------------------------------------------	*/
+#define DEB(x)	if (i2c_debug>=1) x
+#define DEB2(x) if (i2c_debug>=2) x
+#define DEB3(x) if (i2c_debug>=3) x
+#define DEBE(x)	x	/* error messages 				*/
+
+/* --- Convenience defines for the EPP/SPP port:			*/
+#define BASE	((struct i2c_pcf_epp *)(data))->pe_base
+// #define DATA	BASE			/* SPP data port */
+#define STAT	(BASE+1)		/* SPP status port */
+#define CTRL	(BASE+2)		/* SPP control port */
+#define EADD	(BASE+3)		/* EPP address port */
+#define EDAT	(BASE+4)		/* EPP data port */
+
+/* ----- local functions ----------------------------------------------	*/
+
+static void pcf_epp_setbyte(void *data, int ctl, int val)
+{
+  if (ctl) {
+    if (gpe.pe_irq > 0) {
+      DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: Write control 0x%x\n",
+		  val|I2C_PCF_ENI));
+      // set A0 pin HIGH
+      outb(inb(CTRL) | PARPORT_CONTROL_INIT, CTRL);
+      // DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: CTRL port = 0x%x\n", inb(CTRL)));
+      // DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: STAT port = 0x%x\n", inb(STAT)));
+      
+      // EPP write data cycle
+      outb(val | I2C_PCF_ENI, EDAT);
+    } else {
+      DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: Write control 0x%x\n", val));
+      // set A0 pin HIGH
+      outb(inb(CTRL) | PARPORT_CONTROL_INIT, CTRL);
+      outb(val, CTRL);
+    }
+  } else {
+    DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: Write data 0x%x\n", val));
+    // set A0 pin LO
+    outb(inb(CTRL) & ~PARPORT_CONTROL_INIT, CTRL);
+    // DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: CTRL port = 0x%x\n", inb(CTRL)));
+    // DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: STAT port = 0x%x\n", inb(STAT)));
+    outb(val, EDAT);
+  }
+}
+
+static int pcf_epp_getbyte(void *data, int ctl)
+{
+  int val;
+
+  if (ctl) {
+    // set A0 pin HIGH
+    outb(inb(CTRL) | PARPORT_CONTROL_INIT, CTRL);
+    val = inb(EDAT);
+    DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: Read control 0x%x\n", val));
+  } else {
+    // set A0 pin LOW
+    outb(inb(CTRL) & ~PARPORT_CONTROL_INIT, CTRL);
+    val = inb(EDAT);
+    DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: Read data 0x%x\n", val));
+  }
+  return (val);
+}
+
+static int pcf_epp_getown(void *data)
+{
+  return (gpe.pe_own);
+}
+
+
+static int pcf_epp_getclock(void *data)
+{
+  return (gpe.pe_clock);
+}
+
+#if 0
+static void pcf_epp_sleep(unsigned long timeout)
+{
+  schedule_timeout( timeout * HZ);
+}
+#endif
+
+static void pcf_epp_waitforpin(void) {
+  int timeout = 10;
+
+  if (gpe.pe_irq > 0) {
+    spin_lock_irq(&irq_driver_lock);
+    if (pcf_pending == 0) {
+      interruptible_sleep_on_timeout(&pcf_wait, timeout*HZ);
+      //udelay(100);
+    } else {
+      pcf_pending = 0;
+    }
+    spin_unlock_irq(&irq_driver_lock);
+  } else {
+    udelay(100);
+  }
+}
+
+static void pcf_epp_handler(int this_irq, void *dev_id, struct pt_regs *regs) {
+  pcf_pending = 1;
+  wake_up_interruptible(&pcf_wait);
+  DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: in interrupt handler.\n"));
+}
+
+
+static int pcf_epp_init(void *data)
+{
+  if (check_region(gpe.pe_base, 5) < 0 ) {
+    
+    printk(KERN_WARNING "Could not request port region with base 0x%x\n", gpe.pe_base);
+    return -ENODEV;
+  } else {
+    request_region(gpe.pe_base, 5, "i2c (EPP parallel port adapter)");
+  }
+
+  DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: init status port = 0x%x\n", inb(0x379)));
+  
+  if (gpe.pe_irq > 0) {
+    if (request_irq(gpe.pe_irq, pcf_epp_handler, 0, "PCF8584", 0) < 0) {
+      printk(KERN_NOTICE "i2c-pcf-epp.o: Request irq%d failed\n", gpe.pe_irq);
+      gpe.pe_irq = 0;
+    } else
+      disable_irq(gpe.pe_irq);
+      enable_irq(gpe.pe_irq);
+  }
+  // EPP mode initialize
+  // enable interrupt from nINTR pin
+  outb(inb(CTRL)|0x14, CTRL);
+  // clear ERROR bit of STAT
+  outb(inb(STAT)|0x01, STAT);
+  outb(inb(STAT)&~0x01,STAT);
+  
+  return 0;
+}
+
+/* --------------------------------------------------------------
