diff -Naur linux-2.4.26/Documentation/Configure.help linux-2.4.26-m68k/Documentation/Configure.help
--- linux-2.4.26/Documentation/Configure.help	2004-04-14 23:05:24.000000000 +1000
+++ linux-2.4.26-m68k/Documentation/Configure.help	2004-04-15 06:41:29.000000000 +1000
@@ -17167,6 +17167,26 @@
   say M here and read <file:Documentation/modules.txt>.  If unsure,
   say N.
 
+Amiga SFS file system support
+CONFIG_ASFS_FS
+  The Amiga Smart FileSystem (SFS) is the file system used on hard 
+  disks by Amiga(tm) and MorphOS(tm) systems.  Say Y if you want 
+  to be able to read files from an Amiga SFS partition on your hard 
+  drive.  
+
+  This file system driver is in EXPERIMENTAL state. Use it with care. 
+  Although it CANNOT destroy your data (because it is a read-only 
+  driver) it MIGHT cause a crash in some circumstances.
+
+  For more information read <file:Documentation/filesystems/asfs.txt>
+
+  This file system is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module is called affs.o.  If you want to compile it as a module,
+  say M here and read <file:Documentation/modules.txt>.  
+
+  If unsure, say N.
+
 Apple HFS file system support
 CONFIG_HFS_FS
   If you say Y here, you will be able to mount Macintosh-formatted
@@ -23357,6 +23377,29 @@
 
   If you don't want to compile a kernel for a Sun 3x, say N.
 
+TekXpress XP2x support
+CONFIG_TEKXP
+   This option enables support for the TekXpress XP2x series of
+   X-Terminals made by Tektronix.
+   You will also want to enable 68030 support below.
+   Additional information about this port is available at
+   <http://www-users.rwth-aachen.de/Michael.Mueller4/tekxp/tekxp.html>.
+
+   If you don't want to compile a kernel for TekXpress XP2x, say N.
+
+Kernel command line
+CONFIG_BOOTCMD
+   You have to specify a kernel commandline here.
+   There will be no possiblity to change the content on run-time.
+
+Report as MVME160
+CONFIG_TEKXP_REPORT_MVME
+   Enabling this option the TekXpress X-Terminals report as
+   Motorola MVME160 in /proc/harware (if available).
+
+   Say Y, if you intend to use this kernel to install the
+   Debian/m68k Linux distribution. Otherwhise it is save to say N.
+
 Sun3x builtin serial support
 CONFIG_SUN3X_ZS
   ZS refers to a type of asynchronous serial port built in to the Sun3
@@ -23810,6 +23853,18 @@
   If you want to compile it as a module, say M here and read
   <file:Documentation/modules.txt>.
 
+TekXpress on-board Sonic support
+CONFIG_TEKSONIC
+  Say Y here if you want to use the integrated network controller of
+  the TekXpress X-Terminals. If you do not modify it it is unlikely
+  you will get Linux running without this selected.
+
+SCC2962 serial support
+CONFIG_SCC2692
+  Say Y here if you want to use the serial interfaces from user-space.
+  It is safe to say N here, if it will only be used for the output of
+  kernel messages.
+
 Support for early boot text console
 CONFIG_BOOTX_TEXT
   Say Y here to see progress messages from the boot firmware in text
diff -Naur linux-2.4.26/Documentation/filesystems/00-INDEX linux-2.4.26-m68k/Documentation/filesystems/00-INDEX
--- linux-2.4.26/Documentation/filesystems/00-INDEX	2004-02-19 00:36:30.000000000 +1100
+++ linux-2.4.26-m68k/Documentation/filesystems/00-INDEX	2004-02-19 09:11:42.000000000 +1100
@@ -6,6 +6,8 @@
 	- info and mount options for the Acorn Advanced Disc Filing System.
 affs.txt
 	- info and mount options for the Amiga Fast File System.
+asfs.txt
+	- info and mount options for the Amiga Smart File System.
 befs.txt
 	- info for the BeOS file system (BFS)
 bfs.txt
diff -Naur linux-2.4.26/Documentation/filesystems/asfs.txt linux-2.4.26-m68k/Documentation/filesystems/asfs.txt
--- linux-2.4.26/Documentation/filesystems/asfs.txt	1970-01-01 10:00:00.000000000 +1000
+++ linux-2.4.26-m68k/Documentation/filesystems/asfs.txt	2003-06-20 21:32:32.000000000 +1000
@@ -0,0 +1,40 @@
+
+Amiga SmartFileSystem, Linux implementation
+===========================================
+
+This is a simple read-only driver. It support reading files and directories.
+Symbolic links (called soft links) are not supported yet. Don't even try
+to read them.
+
+
+Mount options for the ASFS
+==========================
+
+setuid[=uid]	
+		This sets the owner of all files and directories in the file
+		system to uid or the uid of the current user, respectively.
+
+setgid[=gid]	
+		Same as above, but for gid.
+
+mode=mode	
+		Sets the mode flags to the given (octal) value. Directories 
+		will get an x permission if the corresponding r bit is set.
+		The default mode is 0444, which means all r bits are set
+		(for directories this means also that all x bits are set).
+
+
+Other information
+=================
+
+Supported block sizes are: 512, 1024, 2048 and 4096 bytes. Larger blocks
+speed up almost everything at the expense of wasted disk space. The speed
+gain above 4K seems not really worth the price, so you don't lose too
+much here, either.
+
+This file system hasn't been well tested yet. Athough it CANNOT destroy 
+your data, it MIGHT cause a crash. Sorry.
+
+This file system has been tested on Motorola PPC and Intel x86 systems.
+It SHOULD also work on Motorola 68k. It probably WON'T work on other 
+systems (especially 64bit).
diff -Naur linux-2.4.26/arch/m68k/Makefile linux-2.4.26-m68k/arch/m68k/Makefile
--- linux-2.4.26/arch/m68k/Makefile	2001-06-12 12:15:27.000000000 +1000
+++ linux-2.4.26-m68k/arch/m68k/Makefile	2003-07-22 07:26:06.000000000 +1000
@@ -119,6 +119,11 @@
 SUBDIRS := $(SUBDIRS) arch/m68k/sun3 arch/m68k/sun3/prom
 endif
 
+ifdef CONFIG_TEKXP
+CORE_FILES := $(CORE_FILES) arch/m68k/tekxp/tekxp.o
+SUBDIRS := $(SUBDIRS) arch/m68k/tekxp
+endif
+
 ifdef CONFIG_M68040
 CORE_FILES := $(CORE_FILES) arch/m68k/fpsp040/fpsp.o
 SUBDIRS := $(SUBDIRS) arch/m68k/fpsp040
@@ -172,5 +177,6 @@
 	rm -f arch/m68k/kernel/m68k_defs.h arch/m68k/kernel/m68k_defs.d
 
 archmrproper:
+	rm -f arch/m68k/boot/bootstrap bootstrap
 
 archdep:
diff -Naur linux-2.4.26/arch/m68k/boot/Makefile linux-2.4.26-m68k/arch/m68k/boot/Makefile
--- linux-2.4.26/arch/m68k/boot/Makefile	1970-01-01 10:00:00.000000000 +1000
+++ linux-2.4.26-m68k/arch/m68k/boot/Makefile	2003-07-22 07:26:07.000000000 +1000
@@ -0,0 +1,15 @@
+
+ifdef CONFIG_TEKXP
+.PHONY: bootstrap
+bootstrap: boot.o
+	$(LD) -T tekxp.ld -Ttext 0x1000 -o $@ $<
+	-rm -f ../../../bootstrap
+	dd if=$@ of=../../../bootstrap bs=4096 conv=sync
+	$(STRIP) -s -o vmlinux.s ../../../vmlinux
+	cat vmlinux.s >> ../../../bootstrap
+
+boot.o: boot.S
+	$(CC) -c -o $@ -m68030 -O2 -I$(HPATH) -D__ASSEMBLY__ -DDEBUG $<
+
+endif
+
diff -Naur linux-2.4.26/arch/m68k/boot/boot.S linux-2.4.26-m68k/arch/m68k/boot/boot.S
--- linux-2.4.26/arch/m68k/boot/boot.S	1970-01-01 10:00:00.000000000 +1000
+++ linux-2.4.26-m68k/arch/m68k/boot/boot.S	2003-07-22 07:26:07.000000000 +1000
@@ -0,0 +1,744 @@
+/*
+ *  linux/arch/m68k/boot/boot.S
+ *
+ *  Copyright (C) 2002,2003 Michael Mueller <malware@t-online.de>
+ *
+ *  Parts taken from head.S.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * license. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+/*
+ * This is a wrapper to the linux kernel. Compiled as a.out binary it can be
+ * used to bootstrap the Linux kernel using the TekXpress Boot Monitor.
+ *
+ * In general it does copy the kernel image to the end of the available
+ * memory and does rearrange it to the top memory as described within the
+ * ELF header of wrapped vmlinux file.
+ *
+ * On some of the TekXpress systems there is not enough continous memory
+ * available to fit the whole kernel into. Thus this code does enable the
+ * MMU which is rather unusual.
+ */
+ 
+#include <linux/config.h>
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <asm/bootinfo.h>
+#include <asm/setup.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+
+/***********************************************************************/
+
+/*
+ *  Little helpers for defining functions
+ */
+
+#ifdef __STDC__
+#define L(name) .L##name
+#else
+#define L(name) .L/**/name
+#endif
+
+#define STACK	%a6@(stackstart)
+#define ARG0	%a6@(4)
+#define ARG1	%a6@(8)
+#define ARG2	%a6@(12)
+#define ARG3	%a6@(16)
+#define ARG4	%a6@(20)
+
+.macro	func_start	name,saveregs,stack=0
+L(\name):
+	linkw	%a6,#-\stack
+	moveml	\saveregs,%sp@-
+.set	stackstart,-\stack
+
+.macro	func_return_\name
+	moveml	%sp@+,\saveregs
+	unlk	%a6
+	rts
+.endm
+.endm
+
+.macro	func_return	name
+	func_return_\name
+.endm
+
+.macro	func_call	name
+	jbsr	L(\name)
+.endm
+
+.macro	move_stack	nr,arg1,arg2,arg3,arg4
+.if	\nr
+	move_stack	"(\nr-1)",\arg2,\arg3,\arg4
+	movel	\arg1,%sp@-
+.endif
+.endm
+
+.macro	func_define	name,nr=0
+.macro	\name	arg1,arg2,arg3,arg4
+	move_stack	\nr,\arg1,\arg2,\arg3,\arg4
+	func_call	\name
+.if	\nr
+	lea	%sp@(\nr*4),%sp
+.endif
+.endm
+.endm
+
+/***********************************************************************/
+
+/*
+ * Start of the code (not entry point!)
+ */
+.text
+ENTRY(_stext)
+
+/*
+ * This is a faked a.out Header
+ */
+.long	0x10B			/* a.out magic number */
+.long	SYMBOL_NAME(__end) - header_end	
+				/* size of content = size of text segment */
+.long	0
+.long	0
+.long	0
+.long	SYMBOL_NAME(__start)	/* entry point */
+.long	0
+.long	0
+header_end:
+
+/*
+ * Platform specific constants
+ */
+#define	MEMSTART	0xF0000000	/* start address of CPU RAM */
+#define OPTRAMSTART	0xF4000000	/* start address of Option RAM */
+#define	MEMCHUNK	0x01000000	/* spacing beetween memory chunks */
+#define MEMORY_MAP_ENTRIES	8	/* number of memory chunks */
+
+/*
+ * MMU definitions
+ */
+PAGESIZE		= 4096
+PAGESHIFT		= 12
+ROOT_TABLE_SIZE		= 128
+PTR_TABLE_SIZE		= 128
+PAGE_TABLE_SIZE		= 64
+ROOT_INDEX_SHIFT	= 25
+PTR_INDEX_SHIFT		= 18
+PAGE_INDEX_SHIFT	= 12
+
+/*
+ * Function declarations
+ */
+func_define	mmu_map,4
+func_define	mmu_get_root_table_entry,1
+func_define	mmu_get_ptr_table_entry,2
+func_define	build_memory_list
+func_define	dump_memory_list
+func_define	get_kernel_size
+func_define	get_kernel_start
+func_define	get_kernel_physical_headers
+func_define	get_kernel_entry
+
+/*
+ * Translation tables.
+ *
+ * These have to be located at the same position as within head.S. As
+ * they are references from the kernel later.
+ */
+.equ	SYMBOL_NAME(kernel_pg_dir),SYMBOL_NAME(_stext)
+.equ	SYMBOL_NAME(kernel_ptr_dir1),SYMBOL_NAME(kernel_pg_dir)+ROOT_TABLE_SIZE*4
+.equ	SYMBOL_NAME(kernel_ptr_dir2),SYMBOL_NAME(kernel_ptr_dir1)+PTR_TABLE_SIZE*4
+.equ	SYMBOL_NAME(kernel_ptr_dir3),SYMBOL_NAME(kernel_ptr_dir2)+PTR_TABLE_SIZE*4
+.equ	SYMBOL_NAME(kernel_ptr_dir4),SYMBOL_NAME(kernel_ptr_dir3)+PTR_TABLE_SIZE*4
+.equ	.,SYMBOL_NAME(_stext)+PAGESIZE /* Skip to end of page */
+
+/*
+ * Functions for debugging output
+ */
+func_define serial_init
+func_define putc,1
+func_define putn,1
+func_define puts,1
+func_define dump,2
+
+.macro	dputc	ch
+#ifdef DEBUG
+	putc	\ch
+#endif
+.endm
+
+.macro putr
+	putc	'\r'
+	putc	'\n'
+.endm
+
+.macro dputr
+#ifdef DEBUG
+	putr
+#endif
+.endm
+
+.macro dputn	nr
+#ifdef DEBUG
+	putn	\nr
+#endif
+.endm
+
+.macro	puts	string
+	.data
+.Lstr\@:
+	.asciz	"\string"
+	.previous
+	pea	%pc@(.Lstr\@)
+	func_call	puts
+	addql	#4,%sp
+.endm
+
+.macro dputs	string
+#ifdef DEBUG
+	puts	"\string"
+#endif
+.endm
+
+func_start	puts,%d0/%a0
+	movl	ARG1,%a0
+1:
+	movb	%a0@+,%d0
+	beqs	2f
+	putc	%d0
+	bras	1b
+2:
+func_return	puts
+
+func_start	putn,%d0-%d2
+	movl	ARG1,%d0
+	movl	#7,%d1
+1:
+	roll	#4,%d0
+	movl	%d0,%d2
+	andb	#15,%d2
+	addb	#'0',%d2
+	cmpb	#'9',%d2
+	jls	2f
+	addb	#'A'-('9'+1),%d2
+2:
+	putc	%d2
+	dbra	%d1,1b
+	putc	#' '
+func_return	putn
+
+func_start	putc,%d0/%a0
+	movl	#0xFF800000,%a0
+1:
+	movb	4(%a0),%d0
+	andb	#4,%d0
+	tstb	%d0
+	bne	2f
+	bra	1b
+2:
+	movl	ARG1,%d0
+	movb	%d0,12(%a0)
+func_return	putc
+
+func_start	dump,%d0/%a0
+	movl	ARG1,%a0
+	movl	ARG2,%d0
+1:
+	putn	%a0
+	putn	%a0@
+	putn	%a0@(4)
+	putn	%a0@(8)
+	putn	%a0@(12)
+	putn	%a0@(16)
+	putn	%a0@(20)
+	putn	%a0@(24)
+	putn	%a0@(28)
+	putc	#'\r'	
+	putc	#'\n'	
+	addl	#32,%a0
+	subl	#32,%d0
+	bpl	1b
+func_return	dump
+
+func_start	serial_init,%a0
+        movl    #0xFF800000,%a0         /* address of UART */
+        clrb    0x34(%a0)
+        movb    #0x80,0x10(%a0)         /* ACR: baud rate set 2 */
+        clrb    0x14(%a0)               /* reset interrupt mask */
+        movb    #0x10,8(%a0)            /* CRA: reset MR pointer */
+        movb    #0x20,8(%a0)
+        movb    #0x30,8(%a0)
+        movb    #2,(%a0)                /* 7 bits per char */
+        movb    #7,(%a0)                /* one stop bit */
+        movb    #0xBB,4(%a0)            /* 9600 baud */
+        movb    #5,8(%a0)               /* enable tx and rx */
+func_return	serial_init
+
+.macro  putc	ch
+	pea	\ch
+	func_call	putc
+	addql	#4,%sp
+.endm
+
+
+
+/*
+ * Entry into the code
+ */
+ENTRY(__start)
+
+	/* Use the first 256 byte of memory as scratch area
+	 */
+	movl	#MEMSTART+0x100, %sp
+
+	/* Initialize the serial port
+	 */
+	serial_init
+	dputs	"\r\nLinux@TekXP starting...\r\n"
+
+	/* Build a memory map for later usage
+	 */
+	putc	'a'
+	build_memory_list
+/*	dump_memory_list	*/
+
+	/* Clear the translation tables 
+	 */
+	dputc	'b'
+	movl	#PAGESIZE/4-1,%d0
+	lea	%pc@(SYMBOL_NAME(kernel_pg_dir)),%a0
+1:
+	clrl	%a0@+
+	dbra	%d0,1b
+
+	/* Setup pointer tables for virtual addresses starting at 0 and
+	 * the current PC.
+	 * We need 4 pointer tables at maximum for 128MB.
+	 * Since both memory ranges should map equal we simple use the
+	 * same pointer tables for both.
+	 */
+	dputc	'c'
+	lea	%pc@(SYMBOL_NAME(_stext)),%a0
+	movl	%a0,%d0
+	movl	#ROOT_INDEX_SHIFT,%d1
+	lsrl	%d1,%d0
+
+	lea	%pc@(SYMBOL_NAME(kernel_pg_dir)),%a0
+	lea	%pc@(SYMBOL_NAME(kernel_ptr_dir1)+_PAGE_TABLE+_PAGE_ACCESSED),%a1
+	movl	%a1,%a0@(%d0:l:4)
+	movl	%a1,%a0@+
+	lea	%pc@(SYMBOL_NAME(kernel_ptr_dir2)+_PAGE_TABLE+_PAGE_ACCESSED),%a1
+	movl	%a1,%a0@(%d0:l:4)
+	movl	%a1,%a0@+
+	lea	%pc@(SYMBOL_NAME(kernel_ptr_dir3)+_PAGE_TABLE+_PAGE_ACCESSED),%a1
+	movl	%a1,%a0@(%d0:l:4)
+	movl	%a1,%a0@+
+	lea	%pc@(SYMBOL_NAME(kernel_ptr_dir4)+_PAGE_TABLE+_PAGE_ACCESSED),%a1
+	movl	%a1,%a0@(%d0:l:4)
+	movl	%a1,%a0@+
+
+	/* Setup early terminator pages for hardware access */
+	dputc	'd'
+	lea	%pc@(SYMBOL_NAME(kernel_pg_dir) + 127*4),%a1
+	movl	#0xFE000000+_PAGE_PRESENT+_PAGE_ACCESSED+_PAGE_DIRTY+_PAGE_NOCACHE030,%d1
+	movl	%d1,%a1@
+
+	/* Map the memory to appear linear
+	 */
+	dputc	'e'
+	clrl	%d0		/* virtual address */
+	lea	%pc@(Lmemory_list),%a0
+1:
+	movl	%a0@+,%a1	/* address */
+	movl	%a0@+,%d1	/* size */
+	tstl	%a1
+	beqs	2f
+	mmu_map	%d0,%a1,%d1,#_PAGE_NOCACHE030
+	addl	%d1,%d0
+	bras	1b
+2:
+	lea	%pc@(Lmemory_last),%a0
+	movl	%d0,%a0@
+
+#if 0
+	lea	%pc@(SYMBOL_NAME(kernel_pg_dir)),%a0
+	dump	%a0,#PAGESIZE
+#endif
+
+	/* Enable the MMU
+	 */
+	dputc	'f'
+	.chip	68030
+	lea	%pc@(Lmmu_engage_030_temp),%a0
+	movel	#0x80000002,%a0@
+	lea	%pc@(SYMBOL_NAME(kernel_pg_dir)),%a1
+	movl	%a1,%a0@(4)
+	movl	#0x0808,%d0
+	movec	%d0,%cacr
+	pmove	%a0@,%srp
+	pflusha
+	movl	#0x82c07760,%a0@(8)
+	pmove	%a0@(8),%tc
+	jmp	1f:l
+1:
+	movl	#0x0808,%d0
+	movec	%d0,%cacr
+	pflusha
+	.chip	68k
+
+	/* Fix the stack
+	 */
+	movl	#0x100,%sp
+
+	/* Remove the now unneeded mappings (5 mappings remain, 4 at top) */
+	dputc	'g'
+	movl	#SYMBOL_NAME(kernel_pg_dir)+16,%a0
+	movl	#ROOT_TABLE_SIZE-6,%d0
+1:
+	clrl	%a0@+
+	dbra	%d0,1b
+
+	/* Move yourself and the kernel to end of the memory
+	 */
+	dputc	'h'
+	get_kernel_size
+	addl	#SYMBOL_NAME(__end)+4095,%d0
+	andl	#-PAGESIZE,%d0
+	movl	Lmemory_last,%a1
+	subl	%d0,%a1
+	movl	%a1,Lmemory_last
+	movl	#0,%a0
+	lsrl	#2,%d0
+1:
+	subl	#1,%d0
+	bmi	2f
+	movl	%a0@+,%a1@+
+	bras	1b
+2:
+	movl	Lmemory_last,%a0
+	jmpl	%a0@(3f)
+
+3:
+	dputc	'i'
+
+	/*
+	 * Loop through the sections of the kernel and copy them over.
+	 */
+
+	get_kernel_start		/* in %a0 */
+	movel	%a0,%a1			/* offset of all numbers */
+	clrl	%d3			/* end of bss */
+
+	get_kernel_physical_headers	 /* count in d0, first in %a0 */
+	subl	#32,%a0
+
+1:
+	dputc	'j'
+	subl	#1,%d0
+	bmi	5f
+	addl	#32,%a0
+
+	movel	%a0@(4),%a2	/* file offset */
+	addl	%a1,%a2		/* current memory address */
+	
+	movel	%a0@(8),%a3	/* load memory address */
+	movel	%a0@(16),%d1	/* file size */
+	movel	%a0@(20),%d2	/* memory size */
+
+	cmpl	#SYMBOL_NAME(_stext)+PAGESIZE,%a3
+	bpl	2f
+
+	movl	#SYMBOL_NAME(_stext)+PAGESIZE,%d3
+	subl	%a3,%d3		/* how much is below */
+
+	addl	%d3,%a3		/* move it up */
+	addl	%d3,%a2		/* move it up */
+
+	subl	%d3,%d2
+	bmi	1b		/* nothing left */
+
+	subl	%d3,%d1
+	bmi	4f
+2:
+	subl	%d1,%d2		/* do not clear what is in file */
+	bpl	3f
+	addl	%d1,%d2
+	movl	%d2,%d1
+	clrl	%d2
+
+3:
+	subl	#1,%d1
+	bmi	4f
+	moveb	%a2@+,%a3@+
+	bras	3b
+
+4:	/* clear */
+	lea	%a3@(%d2),%a4
+	cmpl	%a4,%d3
+	bpl	4f
+	movl	%a4,%d3
+4:
+
+	subl	#1,%d2
+	bmi	1b
+	clrb	%a3@+
+	bras	4b
+5:
+
+	/*
+	 * Create a boot info record
+	 */
+	dputc	'k'
+	addl	#PAGESIZE-1,%d3
+	andl	#-PAGE_SIZE,%d3
+	movl	%d3,%a0
+
+	movw	#BI_MACHTYPE,%a0@+
+	movw	#8,%a0@+
+	movl	#MACH_TEKXP,%a0@+
+
+	movw	#BI_CPUTYPE,%a0@+
+	movw	#8,%a0@+
+	movl	#CPU_68030,%a0@+
+
+	movw	#BI_FPUTYPE,%a0@+
+	movw	#8,%a0@+
+	movl	#0,%a0@+
+
+	movw	#BI_MMUTYPE,%a0@+
+	movw	#8,%a0@+
+	movl	#MMU_68030,%a0@+
+
+	lea	%pc@(Lmemory_list),%a1
+1:
+	movel	%a1@+,%d1
+	movel	%a1@+,%d0
+	tstl	%d1
+	beqs	2f
+	movw	#BI_MEMCHUNK,%a0@+
+	movw	#12,%a0@+
+	movl	%d1,%a0@+
+	movl	%d0,%a0@+
+	bras	1b
+2:
+
+	movw	#BI_LAST,%a0@+
+	clrw	%a0@+
+
+	/* jump into the kernel */
+	dputc	'l'
+	get_kernel_entry
+	jmpl	%a0@
+
+/*
+ * Get the position of the kernels ELF header. It is located on the next
+ * page after this wrapper program.
+ */
+
+func_start	get_kernel_start,%d0
+	lea	%pc@(__end+PAGESIZE-1),%a0
+	movl	%a0,%d0
+	andl	#-PAGESIZE,%d0
+	movl	%d0,%a0
+func_return	get_kernel_start
+
+/*
+ * Read the entry point of the ELF executable.
+ */
+
+func_start	get_kernel_entry,%d0
+	get_kernel_start
+	movl	%a0@(0x18),%a0
+func_return	get_kernel_entry
+
+/*
+ * Get the address of the first physical header (into %a0) and the number
+ * of those headers present (into %d0).
+ */
+func_start	get_kernel_physical_headers,%d1
+	get_kernel_start
+	clrl	%d0
+	movw	%a0@(0x2C),%d0		/* Number of headers */
+	movl	%a0@(0x1C),%d1		/* Offset of the table */
+	lea	%a0@(%d1),%a0
+func_return	get_kernel_physical_headers
+
+/*
+ * Calculate the size kernel image. Notice this is not its final footprint.
+ */
+func_start	get_kernel_size,%d1/%d2/%a0
+	get_kernel_physical_headers
+	clrl	%d1
+1:
+	subl	#1,%d0
+	bmi	3f
+	movl	%a0@(4),%d2
+	addl	%a0@(16),%d2
+	cmpl	%d2,%d1
+	bpl	2f
+	movl	%d2,%d1
+2:
+	addl	#32,%a0
+	bras	1b
+3:
+	movl	%d1,%d0
+func_return	get_kernel_size
+
+
+/*
+ * Fetch the memory configuration and store it in a field for later
+ * retrieval.
+ */
+func_start	build_memory_list,%a2/%a4/%d0/%d1
+	lea	%pc@(Lmemory_list),%a4
+
+	movl	#MEMSTART,%a2
+	bfextu	0xFFD00003{4:4},%d0
+	movl	%pc@(Lcpsram_bitmap_table,%d0:l:4),%d0
+1:
+	tstl	%d0
+	beqs	2f
+	movl	%d0,%d1
+	andl	#3,%d1
+	movl	%pc@(Ldram_size_table,%d1:l:4),%d1
+	movl	%a2,%a4@+
+	movl	%d1,%a4@+
+	addl	#MEMCHUNK,%a2
+	lsrl	#2,%d0
+	bras	1b
+2:
+	bfextu	0xFFD00003{0:1},%d0
+	tstl	%d0
+	bnes	4f
+	movl	#OPTRAMSTART,%a2
+	bfextu	0xFFD00003{1:3},%d0
+	movl	%pc@(Lcporam_bitmap_table,%d0:l:4),%d0
+3:
+	tstl	%d0
+	beqs	4f
+	movl	%d0,%d1
+	andl	#3,%d1
+	movl	%pc@(Ldram_size_table,%d1:l:4),%d1
+	movl	%a2,%a4@+
+	movl	%d1,%a4@+
+	addl	#MEMCHUNK,%a2
+	lsrl	#2,%d0
+	bras	3b
+4:
+func_return	build_memory_list
+
+Ldram_size_table:
+	.long	0
+	.long	0x100000
+	.long	0x400000
+	.long	0x040000
+
+Lcporam_bitmap_table:
+	.long	0xAA
+	.long	0x2A
+	.long	0x0A
+	.long	0x02
+	.long	0x55
+	.long	0x05
+	.long	0x01
+	.long	0x15
+
+Lcpsram_bitmap_table:
+	.long	0x95
+	.long	0x01
+	.long	0x05
+	.long	0x15
+	.long	0x55
+	.long	0x06
+	.long	0x16
+	.long	0x56
+	.long	0x0A
+	.long	0x1A
+	.long	0x5A
+	.long	0xA5
+	.long	0x2A
+	.long	0x6A
+	.long	0x02
+	.long	0xAA
+
+
+/*
+ * Memory mapping functions from head.S. (shortened)
+ */
+
+func_start	mmu_map,%d0-%d4/%a0-%a4
+	/* Get the logical address, it is assumed to be rounded to 256KiB */
+	movl	ARG1,%a3
+
+	/* Get the end address. The length should be rounded to 256KiB */
+	movl	%a3,%a4
+	addl	ARG3,%a4
+	subql	#1,%a4
+
+	/* Get the physical address, assumed to be rounded to 256KiB too */
+	movl	ARG2,%a2
+
+	/* Augment the physical address with page attributes */
+	movl	ARG4,%d0
+	orw	#_PAGE_PRESENT+_PAGE_ACCESSED+_PAGE_DIRTY,%d0
+	addw	%d0,%a2
+
+1:
+	/* Calculate the offset into the root table */
+	movl	%a3,%d0
+	movl	#ROOT_INDEX_SHIFT,%d1
+	lsrl	%d1,%d0
+	mmu_get_root_table_entry	%d0
+
+	/* Calculate the offset into the pointer table */
+	movl	%a3,%d0
+	movl	#PTR_INDEX_SHIFT,%d1
+	lsrl	%d1,%d0
+	andl	#PTR_TABLE_SIZE-1,%d0
+	mmu_get_ptr_table_entry		%a0,%d0
+
+
+	movl	%a2,%a0@
+	addl	#PAGE_TABLE_SIZE*PAGESIZE,%a2
+	addl	#PAGE_TABLE_SIZE*PAGESIZE,%a3
+
+	lea	%a3@(-1),%a0
+	cmpl	%a0,%a4
+	jhi	1b
+	
+func_return	mmu_map
+	
+func_start	mmu_get_root_table_entry,%d0
+	movl	ARG1,%d0
+	lea	%pc@(SYMBOL_NAME(kernel_pg_dir),%d0:l:4),%a0
+func_return	mmu_get_root_table_entry
+
+func_start	mmu_get_ptr_table_entry,%d0
+	movl	ARG1,%a0
+	movl	%a0@,%d0
+	andw	#-PTR_TABLE_SIZE,%d0
+	movl	%d0,%a0
+	movl	ARG2,%d0
+	lea	%a0@(%d0:l:4),%a0
+func_return	mmu_get_ptr_table_entry
+	
+
+
+
+.data
+Lmmu_engage_030_temp:
+	.space 12
+
+Lmemory_last:
+	.long	0		/* end of virtual memory */
+
+Lmemory_list:
+	.rept	MEMORY_MAP_ENTRIES
+	.long	0			/* address */
+	.long	0			/* size */
+	.endr
+
diff -Naur linux-2.4.26/arch/m68k/boot/tekxp.ld linux-2.4.26-m68k/arch/m68k/boot/tekxp.ld
--- linux-2.4.26/arch/m68k/boot/tekxp.ld	1970-01-01 10:00:00.000000000 +1000
+++ linux-2.4.26-m68k/arch/m68k/boot/tekxp.ld	2003-07-22 07:26:07.000000000 +1000
@@ -0,0 +1,36 @@
+OUTPUT_FORMAT("binary")
+ENTRY(__start)
+SECTIONS
+{
+  .text :
+  {
+    *(.init)
+    *(.text)
+     ___CTOR_LIST__ = .;
+     LONG((___CTOR_END__ - ___CTOR_LIST__) / 4 - 2)
+     *(.ctors)
+     LONG(0)
+     ___CTOR_END__ = .;
+     ___DTOR_LIST__ = .;
+     LONG((___DTOR_END__ - ___DTOR_LIST__) / 4 - 2)
+     *(.dtors)
+     LONG(0)
+     ___DTOR_END__ = .;
+    *(.fini)
+     etext  =  .;
+     __etext  =  .;
+  }
+  .data  SIZEOF(.text) + ADDR(.text) :
+  {
+    *(.data .data2)
+     edata  =  .;
+     __edata  =  .;
+  }
+  .bss  SIZEOF(.data) + ADDR(.data) :
+  {
+    *(.bss)
+    *(COMMON)
+     end = .;
+     __end = .;
+  }
+}
diff -Naur linux-2.4.26/arch/m68k/config.in linux-2.4.26-m68k/arch/m68k/config.in
--- linux-2.4.26/arch/m68k/config.in	2004-02-19 00:36:30.000000000 +1100
+++ linux-2.4.26-m68k/arch/m68k/config.in	2004-02-19 09:12:42.000000000 +1100
@@ -56,7 +56,14 @@
 fi
 bool 'Sun3x support' CONFIG_SUN3X
 bool 'Sun3 support' CONFIG_SUN3
-  
+bool 'TekXpress 2x support' CONFIG_TEKXP
+if [ "$CONFIG_TEKXP" = "y" ] ; then
+   define_bool CONFIG_PSMOUSE y
+   define_bool CONFIG_NO_CMDLINE y
+   string '  Kernel command line' CONFIG_BOOTCMD "root=nfs ip=192.168.3.10:192.168.2.1:192.168.3.1:255.255.255.0:tek.malware.de:eth0:none nfsroot=192.168.2.1:/tftpboot/XP20"
+   bool '  Report as MVME160' CONFIG_TEKXP_REPORT_MVME
+fi
+ 
 bool 'Q40/Q60 support' CONFIG_Q40
 
 comment 'Processor type'
@@ -365,6 +372,9 @@
 	 fi
          dep_tristate 'NE2000/NE1000 support' CONFIG_NE2000 m
       fi
+      if [ "$CONFIG_TEKXP" = "y" ]; then
+        bool '  TekXpress on-board Sonic support' CONFIG_TEKSONIC
+      fi
    fi
    endmenu
 
@@ -474,6 +484,10 @@
    define_tristate CONFIG_SERIAL $CONFIG_DN_SERIAL
 fi 
 
+if [ "$CONFIG_TEKXP" = "y" ] ; then
+   tristate 'SCC2962 serial support' CONFIG_SCC2692
+fi
+
 if [ "$CONFIG_SUN3" = "y" -o "$CONFIG_SUN3X" = "y" ]; then
    bool 'Sun3/3x builtin serial support' CONFIG_SUN3X_ZS
 else
@@ -499,7 +513,7 @@
      "$CONFIG_SUN3X_ZS" = "y" -o "$CONFIG_SERIAL" = "y" -o \
      "$CONFIG_MVME147_SCC" -o "$CONFIG_SERIAL167" = "y" -o \
      "$CONFIG_MVME162_SCC" -o "$CONFIG_BVME6000_SCC" = "y" -o \
-     "$CONFIG_DN_SERIAL" ]; then
+     "$CONFIG_DN_SERIAL" = "y" -o "$CONFIG_SCC2692" = "y" ]; then
    bool 'Support for serial port console' CONFIG_SERIAL_CONSOLE
 fi
 bool 'Support for user serial device modules' CONFIG_USERIAL
diff -Naur linux-2.4.26/arch/m68k/kernel/head.S linux-2.4.26-m68k/arch/m68k/kernel/head.S
--- linux-2.4.26/arch/m68k/kernel/head.S	2003-06-14 00:51:31.000000000 +1000
+++ linux-2.4.26-m68k/arch/m68k/kernel/head.S	2003-07-22 07:21:27.000000000 +1000
@@ -39,6 +39,12 @@
  * Disabled caches
  * Put us in supervisor state.
  *
+ * On TekXpress (CONFIG_TEKXP) the boat loader enables the MMU since
+ * there might not be enough physically continues memory available
+ * for the kernel (e.g. 6 x 1MB memory configuration). The mapping is
+ * 1:1 for the first chunk of physical memory and does use the same
+ * table sizes as the temporary memory map used during enabling the MMU.
+ *
  * The kernel setup code takes the following steps:
  * .  Raise interrupt level
  * .  Set up initial kernel memory mapping.
@@ -480,6 +486,14 @@
 	addql	#4,%sp
 .endm
 
+.macro	get_bi_record_continue	record,recsize,binfo
+	movel	\binfo,%sp@-
+	movel	\recsize,%sp@-
+	pea	\record
+	func_call	get_bi_record_continue
+	addl	#12,%sp
+.endm
+
 func_define	serial_putc,1
 func_define	console_putc,1
 
@@ -543,6 +557,7 @@
 #define is_not_apollo(lab) cmpl &MACH_APOLLO,%pc@(m68k_machtype); jne lab
 #define is_not_q40(lab) cmpl &MACH_Q40,%pc@(m68k_machtype); jne lab
 #define is_not_sun3x(lab) cmpl &MACH_SUN3X,%pc@(m68k_machtype); jne lab
+#define is_not_tekxp(lab) cmpl &MACH_TEKXP,%pc@(m68k_machtype); jne lab
 
 #define hasnt_leds(lab) cmpl &MACH_HP300,%pc@(m68k_machtype); \
 			jeq 42f; \
@@ -587,6 +602,7 @@
 	.long	MACH_BVME6000, BVME6000_BOOTI_VERSION
 	.long	MACH_MAC, MAC_BOOTI_VERSION
 	.long	MACH_Q40, Q40_BOOTI_VERSION	
+	.long	MACH_TEKXP, TEKXP_BOOTI_VERSION
 	.long	0
 1:	jra	SYMBOL_NAME(__start)
 
@@ -993,6 +1009,40 @@
 
 	leds	0x4
 
+#ifdef CONFIG_TEKXP
+	is_not_tekxp(5f)
+
+	get_bi_record	BI_LAST
+	addw	#PAGESIZE-1,%a0
+	movel	%a0,%d2
+	andw	#-PAGESIZE,%d2
+
+	/* Convert it into a physical address */
+	movl	%d2,%d1
+	get_bi_record	BI_MEMCHUNK
+1:
+	cmpl	#-1,%d0
+	beqs	2f
+	subl	%a0@(4),%d1
+	bcs	4f
+	get_bi_record_continue	BI_MEMCHUNK,%d0,%a0
+	bras	1b
+4:
+	movl	%d1,%d0
+	addl	%a0@(4),%d0
+	addl	%a0@,%d0
+	bras	3f
+2:
+	movl	%d2,%d0
+3:
+
+	movel	%d0,availmem
+
+	/* Skip all the MMU stuff here */
+	bra	L(engage_done)
+5:
+#endif
+
 /*
  *	mmu_init
  *
@@ -1310,11 +1360,22 @@
 
 	putc	'P'
 	mmu_map         #0x80000000,#0,#0x02000000,#_PAGE_NOCACHE030
-	
-L(notapollo):	
 	jbra	L(mmu_init_done)
+
+L(notapollo):	
 #endif
 
+#ifdef CONFIG_TEKXP
+	is_not_tekxp(L(nottekxp))
+
+	putc	'P'
+	mmu_map_tt	#0,#0xff000000,#0x01000000,#_PAGE_NOCACHE030
+
+L(nottekxp):
+#endif
+
+	jbra	L(mmu_init_done)
+
 L(mmu_init_done):
 
 	putc	'G'
@@ -1442,6 +1503,8 @@
 
 	movel	L(memory_start),availmem
 
+L(engage_done):
+
 #ifdef CONFIG_AMIGA
 	is_not_amiga(1f)
 	/* fixup the Amiga custom register location before printing */
@@ -1572,10 +1635,7 @@
  * Returns: d0: size (-1 if not found)
  *          a0: data pointer (end-of-records if not found)
  */
-func_start	get_bi_record,%d1
-
-	movel	ARG1,%d0
-	lea	%pc@(SYMBOL_NAME(_end)),%a0
+.macro get_bi_record_core
 #ifndef CONFIG_HP300
 1:	tstw	%a0@(BIR_TAG)
 	jeq	3f
@@ -1591,8 +1651,22 @@
 	lea	%a0@(BIR_SIZE),%a0
 4:
 #endif /* CONFIG_HP300 */
+.endm
+ 
+func_start	get_bi_record,%d1
+
+	movel	ARG1,%d0
+	lea	%pc@(SYMBOL_NAME(_end)),%a0
+	get_bi_record_core
 func_return	get_bi_record
 
+func_start	get_bi_record_continue,%d1
+	movl	ARG3,%a0
+	addl	ARG2,%a0
+	subl	#BIR_DATA,%a0
+	movl	ARG1,%d0
+	get_bi_record_core
+func_return	get_bi_record_continue
 
 /*
  *	MMU Initialization Begins Here
@@ -3020,6 +3094,27 @@
 /* We count on the PROM initializing SIO1 */
 #endif
 
+#ifdef CONFIG_TEKXP
+#if 0
+	is_not_tekxp(1f)
+	movl	%a0,-(%sp)
+        movl    #0xFF800000,%a0         /* address of UART */
+        clrb    0x34(%a0)
+        movb    #0x80,0x10(%a0)         /* ACR: baud rate set 2 */
+        clrb    0x14(%a0)               /* reset interrupt mask */
+        movb    #0x10,8(%a0)            /* CRA: reset MR pointer */
+        movb    #0x20,8(%a0)
+        movb    #0x30,8(%a0)
+        movb    #2,(%a0)                /* 7 bits per char */
+        movb    #7,(%a0)                /* one stop bit */
+        movb    #0xBB,4(%a0)            /* 9600 baud */
+        movb    #5,8(%a0)               /* enable tx and rx */
+	movl	(%sp)+,%a0
+	bras	L(serial_init_done)
+1:
+#endif
+#endif
+
 L(serial_init_done):
 func_return	serial_init
 
@@ -3215,6 +3310,23 @@
 2:
 #endif
 
+#ifdef CONFIG_TEKXP
+	is_not_tekxp(3f)
+	moveml	%a0/%d0-%d1,%sp@-
+	movl	#0xFF800000,%a0
+1:
+	movb	4(%a0),%d1
+	andb	#4,%d1
+	tstb	%d1
+	bne	2f
+	bra	1b
+2:
+	movb	%d0,12(%a0)
+	moveml	%sp@+,%d0-%d1/%a0
+	jbra	L(serial_putc_done)
+3:
+#endif
+
 L(serial_putc_done):
 func_return	serial_putc
 
diff -Naur linux-2.4.26/arch/m68k/kernel/m68k_ksyms.c linux-2.4.26-m68k/arch/m68k/kernel/m68k_ksyms.c
--- linux-2.4.26/arch/m68k/kernel/m68k_ksyms.c	2004-02-19 00:36:30.000000000 +1100
+++ linux-2.4.26-m68k/arch/m68k/kernel/m68k_ksyms.c	2003-11-12 22:57:01.000000000 +1100
@@ -53,6 +53,7 @@
 EXPORT_SYMBOL(mm_cachebits);
 #endif
 #endif /* !CONFIG_SUN3 */
+EXPORT_SYMBOL(flush_icache_user_range);
 EXPORT_SYMBOL(m68k_debug_device);
 EXPORT_SYMBOL(mach_hwclk);
 EXPORT_SYMBOL(mach_get_ss);
diff -Naur linux-2.4.26/arch/m68k/kernel/setup.c linux-2.4.26-m68k/arch/m68k/kernel/setup.c
--- linux-2.4.26/arch/m68k/kernel/setup.c	2003-06-14 00:51:31.000000000 +1000
+++ linux-2.4.26-m68k/arch/m68k/kernel/setup.c	2003-07-22 07:20:23.000000000 +1000
@@ -140,6 +140,7 @@
 extern void config_hp300(void);
 extern void config_q40(void);
 extern void config_sun3x(void);
+extern void config_tekxp(void);
 
 extern void mac_debugging_short (int, short);
 extern void mac_debugging_long  (int, long);
@@ -150,6 +151,10 @@
 
 static void __init m68k_parse_bootinfo(const struct bi_record *record)
 {
+#ifdef CONFIG_NO_CMDLINE
+    strncpy(m68k_command_line, CONFIG_BOOTCMD, CL_SIZE);
+#endif
+
     while (record->tag != BI_LAST) {
 	int unknown = 0;
 	const unsigned long *data = record->data;
@@ -354,6 +359,11 @@
 		config_sun3x();
 		break;
 #endif
+#ifdef CONFIG_TEKXP
+	    case MACH_TEKXP:
+		config_tekxp();
+		break;
+#endif
 	    default:
 		panic ("No configuration setup");
 	}
diff -Naur linux-2.4.26/arch/m68k/mac/iop.c linux-2.4.26-m68k/arch/m68k/mac/iop.c
--- linux-2.4.26/arch/m68k/mac/iop.c	2003-06-14 00:51:31.000000000 +1000
+++ linux-2.4.26-m68k/arch/m68k/mac/iop.c	2004-06-20 21:17:45.000000000 +1000
@@ -261,7 +261,7 @@
 		} else {
 			iop_base[IOP_NUM_ISM] = (struct mac_iop *) ISM_IOP_BASE_QUADRA;
 		}
-		iop_base[IOP_NUM_SCC]->status_ctrl = 0;
+		iop_base[IOP_NUM_ISM]->status_ctrl = 0;
 		iop_ism_present = 1;
 	} else {
 		iop_base[IOP_NUM_ISM] = NULL;
diff -Naur linux-2.4.26/arch/m68k/mm/Makefile linux-2.4.26-m68k/arch/m68k/mm/Makefile
--- linux-2.4.26/arch/m68k/mm/Makefile	2003-06-14 00:51:31.000000000 +1000
+++ linux-2.4.26-m68k/arch/m68k/mm/Makefile	2003-07-02 09:46:59.000000000 +1000
@@ -9,7 +9,7 @@
 
 O_TARGET := mm.o
 
-obj-y		:= init.o fault.o extable.o hwtest.o
+obj-y		:= cache.o init.o fault.o extable.o hwtest.o
 
 ifndef CONFIG_SUN3
 obj-y		+= kmap.o memory.o motorola.o
diff -Naur linux-2.4.26/arch/m68k/mm/cache.c linux-2.4.26-m68k/arch/m68k/mm/cache.c
--- linux-2.4.26/arch/m68k/mm/cache.c	1970-01-01 10:00:00.000000000 +1000
+++ linux-2.4.26-m68k/arch/m68k/mm/cache.c	2003-11-13 02:23:27.000000000 +1100
@@ -0,0 +1,161 @@
+/*
+ *  linux/arch/m68k/mm/cache.c
+ *
+ *  Instruction cache handling
+ *
+ *  Copyright (C) 1995  Hamish Macdonald
+ */
+
+#include <linux/pagemap.h>
+
+#include <asm/traps.h>
+
+
+static unsigned long virt_to_phys_slow(unsigned long vaddr, mm_segment_t fs)
+{
+	if (CPU_IS_060) {
+		mm_segment_t old_fs = get_fs();
+		unsigned long paddr;
+
+		set_fs(fs);
+
+		/* The PLPAR instruction causes an access error if the translation
+		 * is not possible. To catch this we use the same exception mechanism
+		 * as for user space accesses in <asm/uaccess.h>. */
+		asm volatile (".chip 68060\n"
+			      "1: plpar (%0)\n"
+			      ".chip 68k\n"
+			      "2:\n"
+			      ".section .fixup,\"ax\"\n"
+			      "   .even\n"
+			      "3: sub.l %0,%0\n"
+			      "   jra 2b\n"
+			      ".previous\n"
+			      ".section __ex_table,\"a\"\n"
+			      "   .align 4\n"
+			      "   .long 1b,3b\n"
+			      ".previous"
+			      : "=a" (paddr)
+			      : "0" (vaddr));
+		set_fs(old_fs);
+		return paddr;
+	} else if (CPU_IS_040) {
+		mm_segment_t old_fs = get_fs();
+		unsigned long mmusr;
+
+		set_fs(fs);
+		
+		asm volatile (".chip 68040\n\t"
+			      "ptestr (%1)\n\t"
+			      "movec %%mmusr, %0\n\t"
+			      ".chip 68k"
+			      : "=r" (mmusr)
+			      : "a" (vaddr));
+		set_fs(old_fs);
+
+		if (mmusr & MMU_R_040)
+			return (mmusr & PAGE_MASK) | (vaddr & ~PAGE_MASK);
+	} else {
+		unsigned short mmusr;
+		unsigned long *descaddr;
+
+		asm volatile ("ptestr %3,%2@,#7,%0\n\t"
+			      "pmove %%psr,%1@"
+			      : "=a&" (descaddr)
+			      : "a" (&mmusr), "a" (vaddr), "d" (fs.seg));
+		if (mmusr & (MMU_I|MMU_B|MMU_L))
+			return 0;
+		descaddr = phys_to_virt((unsigned long)descaddr);
+		switch (mmusr & MMU_NUM) {
+		case 1:
+			return (*descaddr & 0xfe000000) | (vaddr & 0x01ffffff);
+		case 2:
+			return (*descaddr & 0xfffc0000) | (vaddr & 0x0003ffff);
+		case 3:
+			return (*descaddr & PAGE_MASK) | (vaddr & ~PAGE_MASK);
+		}
+	}
+	return 0;
+}
+
+/* Push n pages at kernel virtual address and clear the icache */
+/* RZ: use cpush %bc instead of cpush %dc, cinv %ic */
+void flush_icache_range(unsigned long address, unsigned long endaddr)
+{
+	if (CPU_IS_040_OR_060) {
+		address &= PAGE_MASK;
+
+		if (address >= PAGE_OFFSET && address < (unsigned long)high_memory) {
+			do {
+				asm volatile ("nop\n\t"
+					      ".chip 68040\n\t"
+					      "cpushp %%bc,(%0)\n\t"
+					      ".chip 68k"
+					      : : "a" (virt_to_phys((void *)address)));
+				address += PAGE_SIZE;
+			} while (address < endaddr);
+		} else {
+			do {
+				asm volatile ("nop\n\t"
+					      ".chip 68040\n\t"
+					      "cpushp %%bc,(%0)\n\t"
+					      ".chip 68k"
+					      : : "a" (virt_to_phys_slow(address, KERNEL_DS)));
+				address += PAGE_SIZE;
+			} while (address < endaddr);
+		}
+	} else {
+		unsigned long tmp;
+		asm volatile ("movec %%cacr,%0\n\t"
+			      "orw %1,%0\n\t"
+			      "movec %0,%%cacr"
+			      : "=&d" (tmp)
+			      : "di" (FLUSH_I));
+	}
+}
+
+void flush_icache_user_range(void *addr, unsigned long size)
+{
+	unsigned long address = (unsigned long)addr;
+	unsigned long endaddr = address + size;
+
+	if (CPU_IS_040_OR_060) {
+		address &= PAGE_MASK;
+
+		do {
+			asm volatile ("nop\n\t"
+				      ".chip 68040\n\t"
+				      "cpushp %%bc,(%0)\n\t"
+				      ".chip 68k"
+				      : : "a" (virt_to_phys_slow(address, get_fs())));
+			address += PAGE_SIZE;
+		} while (address < endaddr);
+	} else {
+		unsigned long tmp;
+		asm volatile ("movec %%cacr,%0\n\t"
+			      "orw %1,%0\n\t"
+			      "movec %0,%%cacr"
+			      : "=&d" (tmp)
+			      : "di" (FLUSH_I));
+	}
+}
+
+void flush_icache_user_page(struct vm_area_struct *vma, struct page *page,
+			    unsigned long addr, int len)
+{
+	if (CPU_IS_040_OR_060) {
+		asm volatile ("nop\n\t"
+			      ".chip 68040\n\t"
+			      "cpushp %%bc,(%0)\n\t"
+			      ".chip 68k"
+			      : : "a" (page_to_phys(page)));
+	} else {
+		unsigned long tmp;
+		asm volatile ("movec %%cacr,%0\n\t"
+			      "orw %1,%0\n\t"
+			      "movec %0,%%cacr"
+			      : "=&d" (tmp)
+			      : "di" (FLUSH_I));
+	}
+}
+
diff -Naur linux-2.4.26/arch/m68k/tekxp/Makefile linux-2.4.26-m68k/arch/m68k/tekxp/Makefile
--- linux-2.4.26/arch/m68k/tekxp/Makefile	1970-01-01 10:00:00.000000000 +1000
+++ linux-2.4.26-m68k/arch/m68k/tekxp/Makefile	2003-07-22 07:20:23.000000000 +1000
@@ -0,0 +1,15 @@
+#
+# Makefile for Linux arch/m68k/tekxp source directory
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+O_TARGET := tekxp.o
+
+export-objs	:= tek_ksyms.o tekuart.o nvram.o
+obj-y		:= config.o tekuart.o nvram.o tek_ksyms.o
+
+include $(TOPDIR)/Rules.make
diff -Naur linux-2.4.26/arch/m68k/tekxp/config.c linux-2.4.26-m68k/arch/m68k/tekxp/config.c
--- linux-2.4.26/arch/m68k/tekxp/config.c	1970-01-01 10:00:00.000000000 +1000
+++ linux-2.4.26-m68k/arch/m68k/tekxp/config.c	2003-07-22 07:20:24.000000000 +1000
@@ -0,0 +1,199 @@
+/*
+ *  linux/arch/m68k/tekxp/config.c
+ *
+ *  Copyright (C) 2002,2003 Michael Mueller <malware@t-online.de>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/console.h>
+#include <linux/sched.h>
+
+#include <asm/machdep.h>
+#include <asm/irq.h>
+#include <asm/tekirq.h>
+#include <asm/tekuart.h>
+#include <asm/teknvram.h>
+
+unsigned char aux_device_present = 1;
+
+/*
+ * While the support for this platform is still under development we just
+ * spit out a stupid message whenever an unexpected IRQ does occur.
+ * This message when appearing once most possible will run forever,
+ * since we have no interrupt controller we can give an acknowledgement.
+ */
+
+static void tekxp_int_unhandled(int irq, void *dev_id, struct pt_regs *regs)
+{
+	printk(KERN_ERR "Unhandled IRQ %d\n", irq);
+}
+
+static void (*tekxp_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = {
+	tekxp_int_unhandled, tekxp_int_unhandled, tekxp_int_unhandled,
+	tekxp_int_unhandled, tekxp_int_unhandled, tekxp_int_unhandled,
+	tekxp_int_unhandled, tekxp_int_unhandled
+};
+
+/*
+ * Reset the machine.
+ */
+static void tekxp_reset(void)
+{
+	tek_uart_set_op(4);
+	__asm__ volatile("1:\tbras 1b\r\n");
+}
+
+#ifdef USE_VIDEO_REFRESH_AS_TIMER
+/*
+ * Timer interrupt handler
+ */
+
+static void tek_timer(int irq, void *dev_id, struct pt_regs *regs)
+{
+	register void (*handler)(int,void*,struct pt_regs*) = dev_id;
+
+	(*(volatile unsigned char *)(0xFFB00000))++;
+
+	handler(irq, NULL, regs);
+}
+#endif
+
+/*
+ * To initialize the scheduling we setup a timer on the DUART.
+ * The hardware offers a screen refresh interrupt but its rate varies with
+ * the display mode and in all cases is less than HZ.
+ */
+
+static void __init tek_sched_init(void (*handler)(int, void *, struct pt_regs *))
+{
+#ifdef USE_VIDEO_REFRESH_AS_TIMER
+	/*
+	 * Enable the timer
+	 */
+	(*(volatile unsigned char *)(0xFFB00000))++;
+
+	if ( request_irq(TEK_IRQ_VIDEO, tek_timer, IRQ_FLG_LOCK, "timer", handler) )
+		panic("Could not register timer interrupt");
+#else
+	tek_uart_setup_timer(handler);
+#endif
+}
+
+/*
+ * Currently there is no such function implemented.
+ * However one could read the counter registers of the DUART here.
+ */
+
+static unsigned long tek_gettimeoffset(void)
+{
+	return 0;
+}
+
+/*
+ * There is not much to do with the keyboard here.
+ * The TekXpress Bootmonitor did most of the work already. What is left
+ * will be done by the PC keyboard driver later.
+ */
+
+static int __init tek_dummy_keyb_init(void)
+{
+	return 0;
+}
+
+/*
+ * This function simply modifies the C character for a new line into the
+ * MSDOS-typical version of it.
+ */
+
+static void tek_serial_console_write(struct console *co, const char *s,
+                                       unsigned int count)
+{
+	while ( count-- )
+	{
+		char c = *s++;
+		if ( c == '\n' )
+			tek_uart_putchar(0, '\r', 1);
+		tek_uart_putchar(0, c, 1);
+	}
+}
+
+/*
+ */
+
+static struct console tekxp_console_driver = {
+        name:           "debug",
+        flags:          CON_PRINTBUFFER,
+        index:          -1,
+};
+
+/*
+ */
+static void __init tekxp_debug_init(void)
+{
+	extern char m68k_debug_device[];
+
+	if (!strcmp( m68k_debug_device, "ser" )) {
+		/* no initialization required (?) */
+		tekxp_console_driver.write = tek_serial_console_write;
+		register_console(&tekxp_console_driver);
+        }
+}
+
+/*
+ * Get the model number as stored in NVRAM and make it readable.
+ *
+ * FIXME: This does not work as expected.
+ */
+
+static void tekxp_get_model(char *model)
+{
+#ifdef CONFIG_TEKXP_REPORT_MVME
+    sprintf(model, "Motorola MVME160");
+#else
+    unsigned short m = nvram_readw(NVRAM_DISPLAY);
+    static const int model_number[] = {24,25,27,29,25,21,25,25};
+
+    if ( m < sizeof model_number )
+	sprintf(model, "TekXpress XP%02d", model_number[m]);
+    else
+	sprintf(model, "TekXpress");
+#endif
+}
+
+/*
+ * This basicly sets the machine dependent variables as needed by
+ * the m68k port of the linux kernel.
+ * Besides it initializes a console for kernel messages and the NVRAM
+ * routines.
+ */
+
+void __init config_tekxp(void)
+{
+	tekxp_debug_init();
+	init_nvram(NULL);
+
+	mach_get_model		= tekxp_get_model;
+	mach_sched_init		= tek_sched_init;
+#ifdef CONFIG_VT
+	mach_keyb_init		= tek_dummy_keyb_init;
+#endif
+	mach_init_IRQ		= tek_uart_init_IRQ;
+	mach_request_irq	= tek_uart_request_irq;
+	mach_free_irq		= tek_uart_free_irq;
+	enable_irq		= tek_uart_enable_irq;
+	disable_irq		= tek_uart_disable_irq;
+	mach_get_irq_list	= tek_uart_get_irq_list;
+	mach_gettimeoffset	= tek_gettimeoffset;
+	mach_max_dma_address	= 0xffffffff;
+#ifdef CONFIG_DUMMY_CONSOLE
+	conswitchp		= &dummy_con;
+#endif
+	mach_default_handler	= &tekxp_default_handler;
+	mach_reset		= tekxp_reset;
+}
+
diff -Naur linux-2.4.26/arch/m68k/tekxp/nvram.c linux-2.4.26-m68k/arch/m68k/tekxp/nvram.c
--- linux-2.4.26/arch/m68k/tekxp/nvram.c	1970-01-01 10:00:00.000000000 +1000
+++ linux-2.4.26-m68k/arch/m68k/tekxp/nvram.c	2003-07-22 07:20:24.000000000 +1000
@@ -0,0 +1,164 @@
+/*
+ *  linux/arch/m68k/tekxp/nvram.c
+ *
+ *  Copyright (C) 2002,2003 Michael Mueller <malware@t-online.de>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <asm/io.h>
+#include <asm/teknvram.h>
+#include <asm/tekuart.h>
+
+#define DEBUG
+
+#ifdef DEBUG
+static int nvram_init = 0;
+#endif
+static u_char *eeprom_ptr;
+static u_char nvram_copy[EEPROM_SIZE];
+
+static void ee_enable(void)
+{
+#if 0
+	// TODO: We still rely on the I/O being transparently mapped
+	// TODO: This might interfere with other code using the UART
+	*(volatile u_char*)0xFF800038 = (u_char)0x80;
+#else
+	tek_uart_set_op(7);
+#endif
+}
+
+static void ee_disable(void)
+{
+#if 0
+	// TODO: We still rely on the I/O being transparently mapped
+	// TODO: This might interfere with other code using the UART
+	*(volatile u_char*)0xFF80003C = (u_char)0x80;
+#else
+	tek_uart_clr_op(7);
+#endif
+}
+
+void init_nvram(unsigned long *mem_start)
+{
+	u_char chksum;
+	u_char chksum2;
+	u_short chksum_complete;
+	int i;
+
+	// FIXME: When this code is running ioremap* is not working yet.
+	//  So we access the EEPROM through the transparent mapping
+	//  established in head.S
+#if 0
+	// Map EEPROM into kernel memory space
+	eeprom_ptr = ioremap_writethrough(EEPROM_BASE, EEPROM_SIZE);
+	if ( !eeprom_ptr )
+	{
+		panic(KERN_ERR "Could not map NVRAM into kernel memory space\n");
+	}
+#else
+	eeprom_ptr = (u_char*)EEPROM_BASE;
+#endif
+
+	// Make a copy of the content to avoid access count excess
+	ee_enable();
+	memcpy(nvram_copy, eeprom_ptr, EEPROM_SIZE);
+	ee_disable();
+
+	// Check the checksum of the content
+	chksum = 0xFF;
+	chksum2 = 0xFF;
+	for ( i = EEPROM_SIZE-1; i >= 0 ; i-- )
+	{
+		u_long new_chk /* d0 */ = chksum + nvram_copy[i];
+		if ( new_chk > 0xFF )
+			new_chk++;
+		chksum = new_chk & 0xFF;
+
+		new_chk = chksum2 + chksum;
+		if ( new_chk > 0xFF )
+			new_chk++;
+		chksum2 = new_chk++;
+	}
+
+	chksum_complete = ((u_short)chksum2 << 8) + chksum;
+	if ( chksum_complete == 0xFFFF )
+	{
+		printk("NVRAM checksum is ok\n");
+	}
+	else
+	{
+		printk(KERN_WARNING "NVRAM checksum invalid!\n");
+	}
+
+#ifdef DEBUG
+	nvram_init++;
+#endif
+}
+
+u_char nvram_readb(int ofs)
+{
+#ifdef DEBUG
+	if ( !nvram_init )
+	{
+		printk(KERN_ERR "Trial to read uninitialized NVRAM\n");
+		return 0xFF;
+	}
+#endif
+	if ( ofs < 0 || ofs >= EEPROM_SIZE )
+		return 0xFF;
+
+	return nvram_copy[ofs];
+}
+
+u_short nvram_readw(int ofs)
+{
+#ifdef DEBUG
+	if ( !nvram_init )
+	{
+		printk(KERN_ERR "Trial to read uninitialized NVRAM\n");
+		return 0xFFFFU;
+	}
+	if ( ofs & 1 )
+	{
+		panic("Unaligned word access to NVRAM");
+		return 0xFFFFU;
+	}
+#endif
+	if ( ofs < 0 || ofs >= EEPROM_SIZE )
+		return 0xFFFFU;
+
+	return *(u_short*)(nvram_copy + ofs);
+}
+
+
+u_long nvram_readl(int ofs)
+{
+#ifdef DEBUG
+	if ( !nvram_init )
+	{
+		printk(KERN_ERR "Trial to read uninitialized NVRAM\n");
+		return 0xFFFFFFFFUL;
+	}
+	if ( ofs & 3 )
+	{
+		panic("Unaligned word access to NVRAM");
+		return 0xFFFFFFFFUL;
+	}
+#endif
+	if ( ofs < 0 || ofs >= EEPROM_SIZE )
+		return 0xFFFFFFFFUL;
+
+	return *(u_long*)(nvram_copy + ofs);
+}
+
+
diff -Naur linux-2.4.26/arch/m68k/tekxp/tek_ksyms.c linux-2.4.26-m68k/arch/m68k/tekxp/tek_ksyms.c
--- linux-2.4.26/arch/m68k/tekxp/tek_ksyms.c	1970-01-01 10:00:00.000000000 +1000
+++ linux-2.4.26-m68k/arch/m68k/tekxp/tek_ksyms.c	2003-07-22 07:20:24.000000000 +1000
@@ -0,0 +1,23 @@
+/*
+ *  linux/arch/m68k/tekxp/tek_ksyms.c
+ *
+ *  Copyright (C) 2002,2003 Michael Mueller <malware@t-online.de>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <asm/ptrace.h>
+#include <asm/tekuart.h>
+#include <asm/teknvram.h>
+
+EXPORT_SYMBOL(tek_uart_putchar);
+EXPORT_SYMBOL(tek_uart_lock);
+EXPORT_SYMBOL(nvram_readb);
+EXPORT_SYMBOL(nvram_readw);
+EXPORT_SYMBOL(nvram_readl);
+
diff -Naur linux-2.4.26/arch/m68k/tekxp/tekuart.c linux-2.4.26-m68k/arch/m68k/tekxp/tekuart.c
--- linux-2.4.26/arch/m68k/tekxp/tekuart.c	1970-01-01 10:00:00.000000000 +1000
+++ linux-2.4.26-m68k/arch/m68k/tekxp/tekuart.c	2003-07-22 07:20:24.000000000 +1000
@@ -0,0 +1,476 @@
+/*
+ *  linux/arch/m68k/tekxp/tekuart.c
+ *
+ *  Copyright (C) 2002,2003 Michael Mueller <malware@t-online.de>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+#include <linux/spinlock.h>
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/tekuart.h>
+#include <asm/tekirq.h>
+
+spinlock_t tek_uart_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t tek_irq_lock = SPIN_LOCK_UNLOCKED;
+
+/*
+ * Base address of the UART
+ *
+ * Initialized to the address accessable by a transparent mapping.
+ *
+ * FIXME: This is never mapped into the memory space of the kernel
+ *        since memory mapping is not available while initializing the
+ *        platform specific stuff.
+ */
+
+static tek_uart_t *uart = (tek_uart_t*)TEK_UART_BASE;
+
+/*
+ * Interrupt handler tables and call statistics
+ */
+
+static irq_handler_t irq_handlers[UART_IRQS];
+static int tek_irq_stat[UART_IRQS];
+
+#define IRQ_IDX(n) ((n)-SYS_IRQS)
+
+/*
+ * Dummy variable used as Lvalue when we need to read from the
+ * hardware without any need for the actual result value.
+ */
+
+static volatile u_char dummy;
+
+/*
+ * Variables used for the interrupt routine
+ */
+
+static u_char tek_uart_imr;		/* shadow Interrupt Mask Register   */
+static u_char tek_uart_isr;		/* shadow Interrupt Status Register */
+#ifndef USE_VIDEO_REFRESH_AS_TIMER
+static unsigned short tek_timer;	/* value to put into the counter    */
+#endif
+
+static u_char timer_mode = 0x80;	/* choose second baudrate set       */
+
+/*
+ * Set the interrupt mask register.
+ */
+
+static inline void __set_IMR(void)
+{
+	uart->wr.IMR = tek_uart_imr;
+}
+
+static void set_IMR(void)
+{
+	unsigned long flags;
+	spin_lock_irqsave(tek_uart_lock, flags);
+	__set_IMR();
+	spin_unlock_irqrestore(tek_uart_lock, flags);
+}
+
+/*
+ * Interrupt handler.
+ *
+ * Besides demultiplexing the interrupt sources of the DUART it does take
+ * care of the counter prior to calling the kernel handler.
+ */
+
+static void tek_irqhandler(int irq, void *dev_id, struct pt_regs *regs)
+{
+	int i;
+
+	/*
+	 * Read the ISR once. This does even clear all pending interrupts.
+	 */
+	unsigned char ISR = uart->rd.ISR;
+
+#ifndef USE_VIDEO_REFRESH_AS_TIMER
+	/*
+	 * Handle the counter.
+	 */
+	if ( ISR & (1<<IRQ_IDX(TEK_IRQ_TIMER_A)) )
+		dummy = uart->rd.CounterStop;	/* just ack */
+#endif
+
+#ifdef DEBUG
+	printk("tek_irqhandler: ISR=%02x IMR=%02x\n", ISR, tek_uart_imr);
+#endif
+
+	/*
+	 * Store the interrupt status for later usage.
+	 *
+	 * This does also queue disabled interrupts for later usage.
+	 */
+	ISR = (tek_uart_isr |= ISR) & tek_uart_imr;
+
+	/*
+	 * Run the handler for each interrupt source.
+	 */
+	for ( i=0; i<UART_IRQS; i++ )
+	{
+		if ( ISR & (1<<i) )
+		{
+			unsigned long flags;
+			spin_lock_irqsave(tek_irq_lock, flags);
+
+			tek_irq_stat[i]++;
+
+			if ( irq_handlers[i].handler )
+			{
+				irq_handler_t handler = irq_handlers[i];
+				spin_unlock_irqrestore(tek_irq_lock, flags);
+
+				handler.handler(i, handler.dev_id, regs);
+			}
+			else
+				spin_unlock_irqrestore(tek_irq_lock, flags);
+			tek_uart_isr &= ~(1<<i);
+		}
+	}
+}
+
+/*
+ * Set an output line (to Low)
+ *
+ * Following values for the line are of special use:
+ *	3	connected to internal beeper
+ *	4	will reset the machine
+ */
+
+void tek_uart_set_op(int nr)
+{
+	unsigned long flags;
+	spin_lock_irqsave(tek_uart_lock, flags);
+
+	uart->wr.OutputSet = 1 << nr;
+
+	spin_unlock_irqrestore(tek_uart_lock, flags);
+}
+
+/*
+ * Clear an output line (to High)
+ */
+
+void tek_uart_clr_op(int nr)
+{
+	unsigned long flags;
+	spin_lock_irqsave(tek_uart_lock, flags);
+
+	uart->wr.OutputClear = 1 << nr;
+
+	spin_unlock_irqrestore(tek_uart_lock, flags);
+}
+
+/*
+ * Setup an interrupt handler managing all interrupt sources of the DUART.
+ */
+
+void __init tek_uart_init_IRQ(void)
+{
+	unsigned long flags;
+	spin_lock_irqsave(tek_uart_lock, flags);
+
+	/*
+	 * Disable all interrupts
+	 */
+	tek_uart_imr = 0;
+	__set_IMR();
+
+
+	/*
+	 * Clear pending interrupts
+	 */
+	tek_uart_isr = 0;
+	dummy = uart->rd.ISR;
+
+	spin_unlock_irqrestore(tek_uart_lock, flags);
+
+	/*
+	 * Register the interrupt handler
+	 */
+	if ( request_irq(TEK_IRQ_UART, tek_irqhandler, IRQ_FLG_LOCK, "UART demux", NULL) )
+	{
+		panic("Could not register UART demux interrupt handler");
+	}
+}
+
+/*
+ * Enable a specific interrupt source of the DUART.
+ */
+
+static inline void enable_uart_irq(unsigned int irq)
+{
+	unsigned long flags;
+	spin_lock_irqsave(tek_uart_lock, flags);
+
+	tek_uart_imr |= (1<<irq);
+	__set_IMR();
+
+	spin_unlock_irqrestore(tek_uart_lock, flags);
+}
+
+/*
+ * Disable a specific interrupt source of the DUART.
+ */
+
+static inline void disable_uart_irq(unsigned int irq)
+{
+	unsigned long flags;
+	spin_lock_irqsave(tek_uart_lock, flags);
+
+	tek_uart_imr &= ~(1<<irq);
+	__set_IMR();
+
+	spin_unlock_irqrestore(tek_uart_lock, flags);
+}
+
+/*
+ * Register an interrupt handler for an interrupt source of the DUART.
+ *
+ * This is also called for system interrupts. These requests are passed
+ * to the generic function made available by the m68k port.
+ */
+
+int tek_uart_request_irq(unsigned int irq,
+                          void (*handler)(int, void *, struct pt_regs *),
+                          unsigned long flags,
+                          const char *devname, void *dev_id)
+{
+	unsigned long _flags;
+
+	if ( irq < SYS_IRQS )
+		return sys_request_irq(irq, handler, flags, devname, dev_id);
+	irq -= SYS_IRQS;
+
+	if ( irq >= UART_IRQS )
+		return -ENXIO;
+	if ( !handler )
+		return -EINVAL;
+
+	spin_lock_irqsave(tek_irq_lock, _flags);
+
+	if ( irq_handlers[irq].handler && (irq_handlers[irq].dev_id != dev_id) )	{
+		spin_unlock_irqrestore(tek_irq_lock, _flags);
+		return -EBUSY;
+	}
+
+	irq_handlers[irq].handler = handler;
+	irq_handlers[irq].flags	  = flags;
+	irq_handlers[irq].devname = devname;
+	irq_handlers[irq].dev_id  = dev_id;
+
+	spin_unlock_irqrestore(tek_irq_lock, _flags);
+
+	enable_uart_irq(irq);
+
+	return 0;
+}
+
+/*
+ * Unregister an interrupt handler for an interrupt source of the DUART.
+ *
+ * This is also called for system interrupts. These requests are passed
+ * to the generic function made available by the m68k port.
+ */
+
+void tek_uart_free_irq(unsigned int irq, void *dev_id)
+{
+	unsigned long flags;
+
+	if ( irq < SYS_IRQS )
+		return sys_free_irq(irq, dev_id);
+	irq -= SYS_IRQS;
+
+	if ( irq >= UART_IRQS )
+		return /* -ENXIO */;
+
+	spin_lock_irqsave(tek_irq_lock, flags);
+
+	if ( !irq_handlers[irq].handler )
+		return /* -EINVAL */;
+
+	if ( dev_id != irq_handlers[irq].dev_id )
+		return /* -EPERM */;
+
+	disable_uart_irq(irq);
+	irq_handlers[irq].handler = NULL;
+
+	spin_unlock_irqrestore(tek_irq_lock, flags);
+}
+
+/*
+ * Wrapper for enabling an IRQ.
+ */
+
+void tek_uart_enable_irq(unsigned int irq)
+{
+	if ( irq < SYS_IRQS )
+		return;
+
+	enable_uart_irq(irq - SYS_IRQS);
+}
+
+/*
+ * Wrapper for disabling an IRQ.
+ */
+
+void tek_uart_disable_irq(unsigned int irq)
+{
+	if ( irq < SYS_IRQS )
+		return;
+
+	disable_uart_irq(irq - SYS_IRQS);
+}
+
+/*
+ * Build an ASCII list of the interrupt handlers registered and the call
+ * statistics. This part of the content of /proc/interrupts.
+ */
+
+int tek_uart_get_irq_list(char *buf)
+{
+	int i, len = 0;
+	unsigned long flags;
+	spin_lock_irqsave(tek_irq_lock, flags);
+
+	for ( i=0; i < UART_IRQS; i++ )
+	{
+		if ( irq_handlers[i].handler )
+		{
+			len += sprintf(buf+len, "uart %2d: %10u ", i, tek_irq_stat[i]);
+			len += sprintf(buf+len, "  ");
+			len += sprintf(buf+len, "%s\n", irq_handlers[i].devname);
+		}
+	}
+	spin_unlock_irqrestore(tek_irq_lock, flags);
+	return len;
+}
+
+#ifndef USE_VIDEO_REFRESH_AS_TIMER
+
+static void tek_irq2(int irq, void *dev_id, struct pt_regs *regs)
+{
+	/*
+	 * Acknowledge the interrupt
+	 */
+	(*(volatile unsigned char *)(0xFFB00000))++;
+
+}
+
+/*
+ * Setup a timer interrupt.
+ */
+void __init tek_uart_setup_timer(void (*handler)(int, void *, struct pt_regs *))
+{
+	unsigned long flags;
+
+	/*
+	 * Calculate the divider of the clock interval
+	 */
+	if ( HZ < 32 )
+	{
+		/*
+		 * Use 115.2k base clock.
+		 *
+		 * Do not permit frequencies <2Hz, they can be provided
+		 * by further software dividing only and are not very
+		 * usefull.
+		 */
+		if ( HZ < 2 )
+			panic("I will not provide such a slow timer");
+
+		timer_mode |= 0x70;
+		tek_timer = 115200 / HZ;
+	}
+	else if ( HZ <= 57600 )
+	{
+		/*
+		 * Use 115.2k * 16 base clock
+		 */
+		timer_mode |= 0x60;
+		tek_timer = (115200*16) / HZ;
+	}
+	else
+		/*
+		 * We can not provide a faster timer.
+		 */
+		panic("Old hardware is no ferrari");
+
+	/*
+	 * And setup an handler for the video refresh.
+	 */
+	if ( request_irq(TEK_IRQ_VIDEO, tek_irq2, IRQ_FLG_LOCK, "display", NULL) )
+		panic("Could not register display interrupt");
+
+	/*
+	 * Setup an handler for the timer interrupt.
+	 */
+        if ( request_irq(TEK_IRQ_TIMER_A, handler, IRQ_FLG_LOCK, "timer", NULL) )
+		panic("Could not register timer interrupt");
+
+	spin_lock_irqsave(tek_uart_lock, flags);
+
+	/*
+	 * Start the timer.
+	 */
+	dummy = uart->rd.CounterStop;
+	uart->wr.ACR = timer_mode;
+	uart->wr.CRUR = tek_timer >> 8;
+	uart->wr.CTLR = tek_timer & 255;
+	dummy = uart->rd.CounterStart;
+
+	spin_unlock_irqrestore(tek_uart_lock, flags);
+
+	/*
+	 * Enable the video refresh interrupt
+	 */
+	(*(volatile unsigned char *)(0xFFB00000))++;
+}
+#endif
+
+/*
+ * Output a character on the serial port A.
+ *
+ * This routine is called from interrupt and non-interrupt contexts.
+ */
+
+void tek_uart_putchar(int channel, int c, int waitloop)
+{
+	unsigned long flags;
+	spin_lock_irqsave(tek_uart_lock, flags);
+
+	channel &= 1;
+
+	if ( waitloop )
+	{
+//		disable_uart_irq(channel ? 4 : 0);
+		while ( !((channel ? uart->rd.SRB : uart->rd.SRA) & 4) )
+			;
+	}
+
+	(channel ? uart->wr.THRB : uart->wr.THRA) = (u_char)c;
+
+        if ( waitloop )
+	{
+		while ( !((channel ? uart->rd.SRB : uart->rd.SRA) & 4) )
+                        ;
+//		enable_uart_irq(channel ? 4 : 0);
+	}
+
+	spin_unlock_irqrestore(tek_uart_lock, flags);
+}
+
diff -Naur linux-2.4.26/drivers/char/16c552.h linux-2.4.26-m68k/drivers/char/16c552.h
--- linux-2.4.26/drivers/char/16c552.h	1970-01-01 10:00:00.000000000 +1000
+++ linux-2.4.26-m68k/drivers/char/16c552.h	2001-10-22 19:34:32.000000000 +1000
@@ -0,0 +1,165 @@
+/*
+ * Definitions for the 16c552 DACE
+ * (dual-asynchronous-communications-element) used on the GVP
+ * IO-Extender. 
+ *
+ * Basically this is two 16c550 uarts's and a parallel port, which is
+ * why the serial definitions should be valid for the 16c550 uart
+ * aswell.
+ *
+ * Data was taken from National Semiconductors duart 16c552
+ * data-sheets and the Texas Instruments DACE 16c552 data-sheets (the
+ * NS version of the chip is _non_ standard and their data-sheets did
+ * cost me several wasted hours of work).
+ *
+ * This file is (C) 1995 Jes Sorensen (jds@kom.auc.dk)
+ *
+ * Moved from drivers/char/ to include/linux/, because it's useful
+ * on more than just the one card. I'm using it on the hp300 DCA
+ * serial driver, for example.  
+ *      -- Peter Maydell <pmaydell@chiark.greenend.org.uk> 05/1998
+ */
+
+#ifndef _16C552_H_
+#define _16C552_H_
+
+/* Serial stuff */
+
+struct uart_16c550 {
+	volatile u_char skip0;
+	volatile u_char RBR;
+	volatile u_char skip1;
+	volatile u_char IER;
+	volatile u_char skip2;
+	volatile u_char IIR;
+	volatile u_char skip3;
+	volatile u_char LCR;
+	volatile u_char skip4;
+	volatile u_char MCR;
+	volatile u_char skip5;
+	volatile u_char LSR;
+	volatile u_char skip6;
+	volatile u_char MSR;
+	volatile u_char skip7;
+	volatile u_char SCR;
+};
+
+#define THR RBR
+#define FCR IIR
+#define DLL RBR
+#define DLM IER
+#define AFR IIR
+
+/*
+ * Bit-defines for the various registers.
+ */
+
+
+/* IER */
+
+#define ERDAI         (1<<0)
+#define ETHREI        (1<<1)
+#define ELSI          (1<<2)
+#define EMSI          (1<<3)
+
+/* IIR - Interrupt Ident. Register */
+
+#define IRQ_PEND      (1<<0) /* NOTE: IRQ_PEND=0 implies irq pending */
+#define IRQ_ID1       (1<<1)
+#define IRQ_ID2       (1<<2)
+#define IRQ_ID3       (1<<3)
+#define FIFO_ENA0     (1<<6) /* Both these are set when FCR(1<<0)=1 */
+#define FIFO_ENA1     (1<<7)
+
+#define IRQ_RLS  (IRQ_ID1 | IRQ_ID2)
+#define IRQ_RDA  (IRQ_ID2)
+#define IRQ_CTI  (IRQ_ID2 | IRQ_ID3)
+#define IRQ_THRE (IRQ_ID1)
+#define IRQ_MS   0
+
+/* FCR - FIFO Control Register */
+
+#define FIFO_ENA      (1<<0)
+#define RCVR_FIFO_RES (1<<1)
+#define XMIT_FIFO_RES (1<<2)
+#define DMA_MODE_SEL  (1<<3)
+#define RCVR_TRIG_LSB (1<<6)
+#define RCVR_TRIG_MSB (1<<7)
+
+#define FIFO_TRIG_1   0x00
+#define FIFO_TRIG_4   RCVR_TRIG_LSB
+#define FIFO_TRIG_8   RCVR_TRIG_MSB
+#define FIFO_TRIG_14  RCVR_TRIG_LSB|RCVR_TRIG_MSB
+
+/* LCR - Line Control Register */
+
+#define WLS0          (1<<0)
+#define WLS1          (1<<1)
+#define STB           (1<<2)
+#define PEN           (1<<3)
+#define EPS           (1<<4)
+#define STICK_PARITY  (1<<5)
+#define SET_BREAK     (1<<6)
+#define DLAB          (1<<7)
+
+#define data_5bit      0x00
+#define data_6bit      0x01
+#define data_7bit      0x02
+#define data_8bit      0x03
+
+
+/* MCR - Modem Control Register */
+
+#define DTR           (1<<0)
+#define RTS           (1<<1)
+#define OUT1          (1<<2)
+#define OUT2          (1<<3)
+#define LOOP          (1<<4)
+
+/* LSR - Line Status Register */
+
+#define DR            (1<<0)
+#define OE            (1<<1)
+#define PE            (1<<2)
+#define FE            (1<<3)
+#define BI            (1<<4)
+#define THRE          (1<<5)
+#define TEMT          (1<<6)
+#define RCVR_FIFO_ERR (1<<7)
+
+/* MSR - Modem Status Register */
+
+#define DCTS          (1<<0)
+#define DDSR          (1<<1)
+#define TERI          (1<<2)
+#define DDCD          (1<<3)
+#define CTS           (1<<4)
+#define DSR           (1<<5)
+#define RING_I        (1<<6)
+#define DCD           (1<<7)
+
+/* AFR - Alternate Function Register */
+
+#define CONCUR_WRITE  (1<<0)
+#define BAUDOUT       (1<<1)
+#define RXRDY         (1<<2)
+
+/* Parallel stuff */
+
+/*
+ * Unfortunately National Semiconductors did not supply the
+ * specifications for the parallel port in the chip :-(
+ * TI succed though, so here they are :-)
+ *
+ * Defines for the bits can be found by including <linux/lp.h>
+ */
+struct IOEXT_par {
+	volatile u_char skip0;
+	volatile u_char DATA;
+	volatile u_char skip1;
+	volatile u_char STATUS;
+	volatile u_char skip2;
+	volatile u_char CTRL;
+};
+
+#endif
diff -Naur linux-2.4.26/drivers/char/Makefile linux-2.4.26-m68k/drivers/char/Makefile
--- linux-2.4.26/drivers/char/Makefile	2004-02-19 00:36:31.000000000 +1100
+++ linux-2.4.26-m68k/drivers/char/Makefile	2004-02-19 09:16:15.000000000 +1100
@@ -321,6 +321,7 @@
 obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o
 obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o
 obj-$(CONFIG_AMD7XX_TCO) += amd7xx_tco.o
+obj-$(CONFIG_SCC2692) += generic_serial.o scc2692.o
 obj-$(CONFIG_INDYDOG) += indydog.o
 obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o
 
diff -Naur linux-2.4.26/drivers/char/ioext.h linux-2.4.26-m68k/drivers/char/ioext.h
--- linux-2.4.26/drivers/char/ioext.h	1970-01-01 10:00:00.000000000 +1000
+++ linux-2.4.26-m68k/drivers/char/ioext.h	2001-10-22 19:34:32.000000000 +1000
@@ -0,0 +1,108 @@
+/*
+ * Shared data structure for GVP IO-Extender support.
+ *
+ * Merge of ioext.h and ser_ioext.h
+ */
+#ifndef _IOEXT_H_
+#define _IOEXT_H_
+
+#include <linux/config.h>
+#include <linux/netdevice.h>
+
+#include "16c552.h"
+
+#define MAX_IOEXT 5 /*
+		     * The maximum number of io-extenders is 5, as you
+		     * can't have more than 5 ZII boards in any Amiga.
+		     */
+
+#define UART_CLK 7372800
+
+#define IOEXT_BAUD_BASE (UART_CLK / 16)
+
+#define IOEXT_MAX_LINES 2
+
+#define IOEXT_PAR_PLIP  0x0001
+#define IOEXT_PAR_LP    0x0002
+
+
+/*
+ * Macros for the serial driver.
+ */
+#define curruart(info) ((struct uart_16c550 *)(info->port))
+
+#define ser_DTRon(info)  curruart(info)->MCR |=  DTR
+#define ser_RTSon(info)  curruart(info)->MCR |=  RTS
+#define ser_DTRoff(info) curruart(info)->MCR &= ~DTR
+#define ser_RTSoff(info) curruart(info)->MCR &= ~RTS
+
+
+/*
+ * CNTR defines (copied from the GVP SCSI-driver file gvp11.h
+ */
+#define GVP_BUSY	(1<<0)
+#define GVP_IRQ_PEND	(1<<1)
+#define GVP_IRQ_ENA 	(1<<3)
+#define GVP_DIR_WRITE   (1<<4)
+
+
+/*
+ * CTRL defines 
+ */
+#define PORT0_MIDI   (1<<0)  /* CLR = DRIVERS         SET = MIDI      */
+#define PORT1_MIDI   (1<<1)  /* CLR = DRIVERS         SET = MIDI      */
+#define PORT0_DRIVER (1<<2)  /* CLR = RS232,          SET = MIDI      */
+#define PORT1_DRIVER (1<<3)  /* CLR = RS232,          SET = MIDI      */
+#define IRQ_SEL      (1<<4)  /* CLR = INT2,           SET = INT6      */
+#define ROM_BANK_SEL (1<<5)  /* CLR = LOW 32K,        SET = HIGH 32K  */
+#define PORT0_CTRL   (1<<6)  /* CLR = RTSx or RXRDYx, SET = RTSx ONLY */
+#define PORT1_CTRL   (1<<7)  /* CLR = RTSx or RXRDYx, SET = RTSx ONLY */
+
+
+/*
+ * This is the struct describing the registers on the IO-Extender.
+ * NOTE: The board uses a dual uart (16c552), which should be equal to
+ * two 16c550 uarts.
+ */
+typedef struct {
+	char gap0[0x41];
+	volatile unsigned char CNTR;	/* GVP DMAC CNTR (status register)   */
+	char gap1[0x11e];
+	struct uart_16c550 uart0;	/* The first uart                    */
+	char gap2[0xf0];
+	struct uart_16c550 uart1;	/* The second uart                   */
+	char gap3[0xf0];
+	struct IOEXT_par par;		/* The parallel port                 */
+	char gap4[0xfb];
+	volatile unsigned char CTRL;	/* The control-register on the board */
+} IOEXT_struct;
+
+
+typedef struct {
+	int num_uarts;
+	int line[IOEXT_MAX_LINES];
+	volatile struct uart_16c550 *uart[IOEXT_MAX_LINES];
+	IOEXT_struct *board;
+	int spurious_count;
+	unsigned char par_use;		/* IOEXT_PAR_xxx */
+#if defined(CONFIG_GVPIOEXT_PLIP) || defined(CONFIG_GVPIOEXT_PLIP_MODULE)
+	struct nt_device *dev;
+#endif
+#if defined(CONFIG_GVPIOEXT_LP) || defined(CONFIG_GVPIOEXT_LP_MODULE)
+	struct lp_struct *lp_table;
+	int lp_dev;
+	int lp_interrupt;
+#endif
+} IOExtInfoType;
+
+/* Number of detected boards.  */
+extern int ioext_num;
+extern IOExtInfoType ioext_info[MAX_IOEXT];
+
+void ioext_plip_interrupt(struct net_device *dev, int *spurious_count);
+void ioext_lp_interrupt(int dev, int *spurious_count);
+
+extern struct net_device ioext_dev_plip[3];
+extern struct lp_struct ioext_lp_table[1];
+
+#endif
diff -Naur linux-2.4.26/drivers/char/mc68681.h linux-2.4.26-m68k/drivers/char/mc68681.h
--- linux-2.4.26/drivers/char/mc68681.h	1970-01-01 10:00:00.000000000 +1000
+++ linux-2.4.26-m68k/drivers/char/mc68681.h	2001-10-22 19:34:32.000000000 +1000
@@ -0,0 +1,131 @@
+#ifndef _MC68681_H_
+#define _MC68681_H_
+
+/* 
+ * This describes an MC68681 DUART. It has almost only overlayed registers, which
+ * the structure very ugly.
+ * Note that the ri-register isn't really a register of the duart but a kludge of bsc
+ * to make the ring indicator available.
+ * 
+ * The data came from the MFC-31-Developer Kit (from Ralph Seidel,
+ * zodiac@darkness.gun.de) and the data sheet of Phillip's clone device (SCN68681)
+ * (from Richard Hirst, srh@gpt.co.uk)
+ *
+ * 11.11.95 copyright Joerg Dorchain (dorchain@mpi-sb.mpg.de)
+ *
+ */
+
+struct duarthalf {
+union {
+volatile u_char mr1; /* rw */
+volatile u_char mr2; /* rw */
+}  mr;
+volatile u_char ri;   /* special, read */
+union {
+volatile u_char sr;  /* read */
+volatile u_char csr; /* write */
+} sr_csr;
+u_char pad1;
+volatile u_char cr; /* write */
+u_char pad2;
+union {
+volatile u_char rhr; /* read */
+volatile u_char thr; /* write */
+} hr;
+u_char pad3;
+};
+
+struct duart {
+struct duarthalf pa;
+union {
+volatile u_char ipcr; /* read */
+volatile u_char acr;  /* write */
+} ipcr_acr;
+u_char pad1;
+union {
+volatile u_char isr; /* read */
+volatile u_char imr; /* write */
+} ir;
+u_char pad2;
+volatile u_char ctu;
+u_char pad3;
+volatile u_char ctl;
+u_char pad4;
+struct duarthalf pb;
+volatile u_char ivr;
+u_char pad5;
+union {
+volatile u_char ipr; /* read */
+volatile u_char opcr; /* write */
+} ipr_opcr;
+u_char pad6;
+union {
+volatile u_char start; /* read */
+volatile u_char sopc; /* write */
+} start_sopc;
+u_char pad7;
+union {
+volatile u_char stop; /* read */
+volatile u_char ropc; /* write */
+} stop_ropc;
+u_char pad8;
+};
+
+#define MR1_BITS 3
+#define MR1_5BITS 0
+#define MR1_6BITS 1
+#define MR1_7BITS 2
+#define MR1_8BITS 3
+
+#define MR1_PARITY_ODD 4
+
+#define MR1_PARITY 24
+#define MR1_PARITY_WITH 0
+#define MR1_PARITY_FORCE 8
+#define MR1_PARITY_NO 16
+#define MR1_PARITY_MULTIDROP 24
+
+#define MR1_ERROR_BLOCK 32
+#define MR1_FFULL_IRQ 64
+#define MR1_RxRTS_ON 128
+
+#define MR2_STOPS 15
+#define MR2_1STOP 7
+#define MR2_2STOP 15
+
+#define MR2_CTS_ON 16
+#define MR2_TxRTS_ON 32
+
+#define MR2_MODE 192
+#define MR2_NORMAL 0
+#define MR2_ECHO 64
+#define MR2_LOCALLOOP 128
+#define MR2_REMOTELOOP 192
+
+#define CR_RXCOMMAND 3
+#define CR_NONE 0
+#define CR_RX_ON 1
+#define CR_RX_OFF 2
+#define CR_TXCOMMAND 12
+#define CR_TX_ON 4
+#define CR_TX_OFF 8
+#define CR_MISC 112
+#define CR_RESET_MR 16
+#define CR_RESET_RX 32
+#define CR_RESET_TX 48
+#define CR_RESET_ERR 64
+#define CR_RESET_BREAK 80
+#define CR_START_BREAK 96
+#define CR_STOP_BREAK 112
+
+#define SR_RXRDY 1
+#define SR_FFULL 2
+#define SR_TXRDY 4
+#define SR_TXEMPT 8
+#define SR_OVERRUN 16
+#define SR_PARITY 32
+#define SR_FRAMING 64
+#define SR_BREAK 128
+
+
+#endif
diff -Naur linux-2.4.26/drivers/char/pc_keyb.c linux-2.4.26-m68k/drivers/char/pc_keyb.c
--- linux-2.4.26/drivers/char/pc_keyb.c	2002-11-29 10:53:12.000000000 +1100
+++ linux-2.4.26-m68k/drivers/char/pc_keyb.c	2003-07-22 07:33:07.000000000 +1000
@@ -898,6 +898,8 @@
 
 void __init pckbd_init_hw(void)
 {
+	unsigned long flags;
+
 	if (!kbd_controller_present()) {
 		kbd_exists = 0;
 		return;
@@ -905,6 +907,9 @@
 
 	kbd_request_region();
 
+	save_flags(flags);
+	cli();
+
 	/* Flush any pending input. */
 	kbd_clear_input();
 
@@ -922,6 +927,8 @@
 
 	/* Ok, finally allocate the IRQ, and off we go.. */
 	kbd_request_irq(keyboard_interrupt);
+
+	restore_flags(flags);
 }
 
 #if defined CONFIG_PSMOUSE
diff -Naur linux-2.4.26/drivers/char/plip_ioext.c linux-2.4.26-m68k/drivers/char/plip_ioext.c
--- linux-2.4.26/drivers/char/plip_ioext.c	1970-01-01 10:00:00.000000000 +1000
+++ linux-2.4.26-m68k/drivers/char/plip_ioext.c	2001-11-02 07:04:56.000000000 +1100
@@ -0,0 +1,1065 @@
+/*
+ * plip_ioext: A parallel port "network" driver for GVP IO-Extender.
+ *
+ * Authors:	See drivers/net/plip.c
+ *              IO-Extender version by Steve Bennett, <msteveb@ozemail.com.au>
+ *
+ * This driver is for use with a 5-bit cable (LapLink (R) cable).
+ */
+
+static const char *version = "NET3 PLIP version 2.2/m68k";
+
+#define __NO_VERSION__
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/termios.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+
+#include <asm/setup.h>
+#include <asm/irq.h>
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+#include <linux/zorro.h>
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/fcntl.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/if_ether.h>
+
+#include <asm/system.h>
+
+#include <linux/in.h>
+#include <linux/delay.h>
+/*#include <linux/lp_m68k.h>*/
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_plip.h>
+
+#include <linux/tqueue.h>
+#include <linux/ioport.h>
+#include <asm/bitops.h>
+#include <asm/byteorder.h>
+
+#include "ioext.h"
+
+#define DEBUG 0
+
+/* Map 'struct device *' to our control structure */
+#define PLIP_DEV(DEV) (&ioext_info[(DEV)->irq])
+
+/************************************************************************
+**
+** PLIP definitions
+**
+*************************************************************************
+*/
+
+/* Use 0 for production, 1 for verification, >2 for debug */
+#ifndef NET_DEBUG
+#define NET_DEBUG 2
+#endif
+static unsigned int net_debug = NET_DEBUG;
+
+/* In micro second */
+#define PLIP_DELAY_UNIT       1
+
+/* Connection time out = PLIP_TRIGGER_WAIT * PLIP_DELAY_UNIT usec */
+#define PLIP_TRIGGER_WAIT	 500
+
+/* Nibble time out = PLIP_NIBBLE_WAIT * PLIP_DELAY_UNIT usec */
+#define PLIP_NIBBLE_WAIT        3000
+
+#define PAR_DATA(dev)     ((dev)->base_addr+0)
+#define PAR_STATUS(dev)   ((dev)->base_addr+2)
+#define PAR_CONTROL(dev)  ((dev)->base_addr+4)
+
+static void enable_par_irq(struct device *dev, int on);
+static int plip_init(struct device *dev);
+
+/* Bottom halfs */
+static void plip_kick_bh(struct device *dev);
+static void plip_bh(struct device *dev);
+
+/* Functions for DEV methods */
+static int plip_rebuild_header(struct sk_buff *skb);
+static int plip_tx_packet(struct sk_buff *skb, struct device *dev);
+static int plip_open(struct device *dev);
+static int plip_close(struct device *dev);
+static struct enet_statistics *plip_get_stats(struct device *dev);
+static int plip_config(struct device *dev, struct ifmap *map);
+static int plip_ioctl(struct device *dev, struct ifreq *ifr, int cmd);
+
+enum plip_connection_state {
+	PLIP_CN_NONE=0,
+	PLIP_CN_RECEIVE,
+	PLIP_CN_SEND,
+	PLIP_CN_CLOSING,
+	PLIP_CN_ERROR
+};
+
+enum plip_packet_state {
+	PLIP_PK_DONE=0,
+	PLIP_PK_TRIGGER,
+	PLIP_PK_LENGTH_LSB,
+	PLIP_PK_LENGTH_MSB,
+	PLIP_PK_DATA,
+	PLIP_PK_CHECKSUM
+};
+
+enum plip_nibble_state {
+	PLIP_NB_BEGIN,
+	PLIP_NB_1,
+	PLIP_NB_2,
+};
+
+struct plip_local {
+	enum plip_packet_state state;
+	enum plip_nibble_state nibble;
+	union {
+		struct {
+#if defined(__LITTLE_ENDIAN)
+			unsigned char lsb;
+			unsigned char msb;
+#elif defined(__BIG_ENDIAN)
+			unsigned char msb;
+			unsigned char lsb;
+#else
+#error  "Please fix the endianness defines in <asm/byteorder.h>"
+#endif            
+		} b;
+		unsigned short h;
+	} length;
+	unsigned short byte;
+	unsigned char  checksum;
+	unsigned char  data;
+	struct sk_buff *skb;
+};
+
+struct net_local {
+	struct enet_statistics enet_stats;
+	struct tq_struct immediate;
+	struct tq_struct deferred;
+	struct plip_local snd_data;
+	struct plip_local rcv_data;
+	unsigned long  trigger;
+	unsigned long  nibble;
+	enum plip_connection_state connection;
+	unsigned short timeout_count;
+	char is_deferred;
+	int (*orig_rebuild_header)(struct sk_buff *skb);
+};
+
+struct device ioext_dev_plip[] = {
+	{
+		"plip0",
+		0, 0, 0, 0,    /* memory */
+		0, 0,    /* base, irq */
+		0, 0, 0, NULL, plip_init 
+	},
+	{
+		"plip1",
+		0, 0, 0, 0,    /* memory */
+		0, 0,    /* base, irq */
+		0, 0, 0, NULL, plip_init 
+	},
+	{
+		"plip2",
+		0, 0, 0, 0,    /* memory */
+		0, 0,    /* base, irq */
+		0, 0, 0, NULL, plip_init 
+	}
+};
+
+/*
+ * Check for and handle an interrupt for this PLIP device.
+ *
+ */
+void ioext_plip_interrupt(struct device *dev, int *spurious_count)
+{
+	struct net_local *nl;
+	struct plip_local *rcv;
+	unsigned char c0;
+	unsigned long flags;
+
+	nl = (struct net_local *)dev->priv;
+	rcv = &nl->rcv_data;
+
+	c0 = z_readb(PAR_STATUS(dev));
+
+	if (dev->interrupt) {
+		return;
+	}
+
+	if ((c0 & 0xf8) != 0xc0) {
+		/* Not for us */
+		++*spurious_count;
+		return;
+	}
+
+	*spurious_count = 0;
+	dev->interrupt = 1;
+
+	save_flags(flags);
+	cli();
+
+	switch (nl->connection) {
+	case PLIP_CN_CLOSING:
+		dev->tbusy = 0;
+	case PLIP_CN_NONE:
+	case PLIP_CN_SEND:
+		dev->last_rx = jiffies;
+		rcv->state = PLIP_PK_TRIGGER;
+		nl->connection = PLIP_CN_RECEIVE;
+		nl->timeout_count = 0;
+		queue_task(&nl->immediate, &tq_immediate);
+		mark_bh(IMMEDIATE_BH);
+		restore_flags(flags);
+#if 0
+		printk("%s: receive irq in SEND/NONE/CLOSING (%d) ok\n",
+		       dev->name, nl->connection);
+#endif
+		break;
+
+	case PLIP_CN_RECEIVE:
+		restore_flags(flags);
+		printk("%s: receive interrupt when receiving packet\n",
+		       dev->name);
+		break;
+
+	case PLIP_CN_ERROR:
+		restore_flags(flags);
+		printk("%s: receive interrupt in error state\n", dev->name);
+		break;
+	}
+}
+
+
+/* Bottom half handler for the delayed request.
+   This routine is kicked by do_timer().
+   Request `plip_bh' to be invoked. */
+static void
+plip_kick_bh(struct device *dev)
+{
+	struct net_local *nl = (struct net_local *)dev->priv;
+
+	if (nl->is_deferred) {
+		queue_task(&nl->immediate, &tq_immediate);
+		mark_bh(IMMEDIATE_BH);
+	}
+}
+
+/* Forward declarations of internal routines */
+static int plip_none(struct device *, struct net_local *,
+		     struct plip_local *, struct plip_local *);
+static int plip_receive_packet(struct device *, struct net_local *,
+			       struct plip_local *, struct plip_local *);
+static int plip_send_packet(struct device *, struct net_local *,
+			    struct plip_local *, struct plip_local *);
+static int plip_connection_close(struct device *, struct net_local *,
+				 struct plip_local *, struct plip_local *);
+static int plip_error(struct device *, struct net_local *,
+		      struct plip_local *, struct plip_local *);
+static int plip_bh_timeout_error(struct device *dev, struct net_local *nl,
+				 struct plip_local *snd,
+				 struct plip_local *rcv,
+				 int error);
+
+#define OK        0
+#define TIMEOUT   1
+#define ERROR     2
+
+typedef int (*plip_func)(struct device *dev, struct net_local *nl,
+			 struct plip_local *snd, struct plip_local *rcv);
+
+static plip_func connection_state_table[] =
+{
+	plip_none,
+	plip_receive_packet,
+	plip_send_packet,
+	plip_connection_close,
+	plip_error
+};
+
+/*
+** enable_par_irq()
+** 
+** Enable or disable parallel irq for 'dev' according to 'on'.
+**
+** It is NOT possible to disable only the parallel irq.
+** So we disable the board interrupt instead. This means that
+** during reception of a PLIP packet, no serial interrupts can
+** happen. Sorry.
+*/
+static void enable_par_irq(struct device *dev, int on)
+{
+	if (on) {
+		PLIP_DEV(dev)->board->CNTR |= GVP_IRQ_ENA;
+	}
+	else {
+		PLIP_DEV(dev)->board->CNTR &= ~GVP_IRQ_ENA;
+	}
+}
+
+/* Bottom half handler of PLIP. */
+static void
+plip_bh(struct device *dev)
+{
+	struct net_local *nl = (struct net_local *)dev->priv;
+	struct plip_local *snd = &nl->snd_data;
+	struct plip_local *rcv = &nl->rcv_data;
+	plip_func f;
+	int r;
+
+	nl->is_deferred = 0;
+	f = connection_state_table[nl->connection];
+	if ((r = (*f)(dev, nl, snd, rcv)) != OK
+	    && (r = plip_bh_timeout_error(dev, nl, snd, rcv, r)) != OK) {
+		nl->is_deferred = 1;
+		queue_task(&nl->deferred, &tq_timer);
+	}
+}
+
+static int
+plip_bh_timeout_error(struct device *dev, struct net_local *nl,
+		      struct plip_local *snd, struct plip_local *rcv,
+		      int error)
+{
+	unsigned char c0;
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	if (nl->connection == PLIP_CN_SEND) {
+
+		if (error != ERROR) { /* Timeout */
+			nl->timeout_count++;
+			if ((snd->state == PLIP_PK_TRIGGER
+			     && nl->timeout_count <= 10)
+			    || nl->timeout_count <= 3) {
+				restore_flags(flags);
+				/* Try again later */
+				return TIMEOUT;
+			}
+			c0 = z_readb(PAR_STATUS(dev));
+			printk(KERN_INFO "%s: transmit timeout(%d,%02x)\n",
+			       dev->name, snd->state, c0);
+		}
+		nl->enet_stats.tx_errors++;
+		nl->enet_stats.tx_aborted_errors++;
+	} else if (nl->connection == PLIP_CN_RECEIVE) {
+		if (rcv->state == PLIP_PK_TRIGGER) {
+			/* Transmission was interrupted. */
+			restore_flags(flags);
+			return OK;
+		}
+		if (error != ERROR) { /* Timeout */
+			if (++nl->timeout_count <= 3) {
+				restore_flags(flags);
+				/* Try again later */
+				return TIMEOUT;
+			}
+			c0 = z_readb(PAR_STATUS(dev));
+			printk(KERN_INFO "%s: receive timeout(%d,%02x)\n",
+			       dev->name, rcv->state, c0);
+		}
+		nl->enet_stats.rx_dropped++;
+	}
+	rcv->state = PLIP_PK_DONE;
+	if (rcv->skb) {
+		kfree_skb(rcv->skb);
+		rcv->skb = NULL;
+	}
+	snd->state = PLIP_PK_DONE;
+	if (snd->skb) {
+		dev_kfree_skb(snd->skb);
+		snd->skb = NULL;
+	}
+	enable_par_irq(dev, 0);
+	dev->tbusy = 1;
+	nl->connection = PLIP_CN_ERROR;
+	z_writeb(0x00, PAR_DATA(dev));
+	restore_flags(flags);
+
+	return TIMEOUT;
+}
+
+static int
+plip_none(struct device *dev, struct net_local *nl,
+	  struct plip_local *snd, struct plip_local *rcv)
+{
+	return OK;
+}
+
+/* PLIP_RECEIVE --- receive a byte(two nibbles)
+   Returns OK on success, TIMEOUT on timeout */
+inline static int
+plip_receive(struct device *dev, unsigned short nibble_timeout, 
+	     enum plip_nibble_state *ns_p, unsigned char *data_p)
+{
+	unsigned char c0, c1;
+	unsigned int cx;
+
+	switch (*ns_p) {
+	case PLIP_NB_BEGIN:
+		cx = nibble_timeout;
+		while (1) {
+			c0 = z_readb(PAR_STATUS(dev));
+			udelay(PLIP_DELAY_UNIT);
+			if ((c0 & 0x80) == 0) {
+				c1 = z_readb(PAR_STATUS(dev));
+				if (c0 == c1)
+					break;
+			}
+			if (--cx == 0)
+				return TIMEOUT;
+		}
+#if 0
+		printk("received first nybble: %02X -> %02X\n",
+		       c0, (c0 >> 3) & 0x0F);
+#endif
+		*data_p = (c0 >> 3) & 0x0f;
+		z_writeb(0x10, PAR_DATA(dev)); /* send ACK */
+		*ns_p = PLIP_NB_1;
+
+	case PLIP_NB_1:
+		cx = nibble_timeout;
+		while (1) {
+			c0 = z_readb(PAR_STATUS(dev));
+			udelay(PLIP_DELAY_UNIT);
+			if (c0 & 0x80) {
+				c1 = z_readb(PAR_STATUS(dev));
+				if (c0 == c1)
+					break;
+			}
+			if (--cx == 0)
+				return TIMEOUT;
+		}
+#if 0
+		printk("received second nybble: %02X -> %02X\n",
+		       c0, (c0 << 1) & 0xF0);
+#endif
+		*data_p |= (c0 << 1) & 0xf0;
+		z_writeb(0x00, PAR_DATA(dev)); /* send ACK */
+		*ns_p = PLIP_NB_BEGIN;
+	case PLIP_NB_2:
+		break;
+	}
+	return OK;
+}
+
+/* PLIP_RECEIVE_PACKET --- receive a packet */
+static int
+plip_receive_packet(struct device *dev, struct net_local *nl,
+		    struct plip_local *snd, struct plip_local *rcv)
+{
+	unsigned short nibble_timeout = nl->nibble;
+	unsigned char *lbuf;
+	unsigned long flags;
+
+	switch (rcv->state) {
+	case PLIP_PK_TRIGGER:
+		enable_par_irq(dev, 0);
+		dev->interrupt = 0;
+		z_writeb(0x01, PAR_DATA(dev)); /* send ACK */
+		if (net_debug > 2)
+			printk(KERN_DEBUG "%s: receive start\n", dev->name);
+		rcv->state = PLIP_PK_LENGTH_LSB;
+		rcv->nibble = PLIP_NB_BEGIN;
+
+	case PLIP_PK_LENGTH_LSB:
+		if (snd->state != PLIP_PK_DONE) {
+			if (plip_receive(dev, nl->trigger,
+					 &rcv->nibble, &rcv->length.b.lsb)) {
+				/* collision, here dev->tbusy == 1 */
+				rcv->state = PLIP_PK_DONE;
+				nl->is_deferred = 1;
+				nl->connection = PLIP_CN_SEND;
+				queue_task(&nl->deferred, &tq_timer);
+				enable_par_irq(dev, 1);
+				return OK;
+			}
+		} else {
+			if (plip_receive(dev, nibble_timeout, 
+					 &rcv->nibble, &rcv->length.b.lsb))
+				return TIMEOUT;
+		}
+		rcv->state = PLIP_PK_LENGTH_MSB;
+
+	case PLIP_PK_LENGTH_MSB:
+		if (plip_receive(dev, nibble_timeout, 
+				 &rcv->nibble, &rcv->length.b.msb))
+			return TIMEOUT;
+		if (rcv->length.h > dev->mtu + dev->hard_header_len
+		    || rcv->length.h < 8) {
+			printk(KERN_INFO "%s: bogus packet size %d.\n",
+			       dev->name, rcv->length.h);
+			return ERROR;
+		}
+		/* Malloc up new buffer. */
+		rcv->skb = dev_alloc_skb(rcv->length.h);
+		if (rcv->skb == NULL) {
+			printk(KERN_INFO "%s: Memory squeeze.\n", dev->name);
+			return ERROR;
+		}
+		skb_put(rcv->skb,rcv->length.h);
+		rcv->skb->dev = dev;
+		rcv->state = PLIP_PK_DATA;
+		rcv->byte = 0;
+		rcv->checksum = 0;
+
+	case PLIP_PK_DATA:
+		lbuf = rcv->skb->data;
+		do
+			if (plip_receive(dev, nibble_timeout, 
+					 &rcv->nibble, &lbuf[rcv->byte]))
+				return TIMEOUT;
+		while (++rcv->byte < rcv->length.h);
+		do
+			rcv->checksum += lbuf[--rcv->byte];
+		while (rcv->byte);
+		rcv->state = PLIP_PK_CHECKSUM;
+
+	case PLIP_PK_CHECKSUM:
+		if (plip_receive(dev, nibble_timeout, 
+				 &rcv->nibble, &rcv->data))
+			return TIMEOUT;
+		if (rcv->data != rcv->checksum) {
+			nl->enet_stats.rx_crc_errors++;
+			if (net_debug)
+				printk(KERN_INFO "%s: checksum error\n",
+				       dev->name);
+			return ERROR;
+		}
+		rcv->state = PLIP_PK_DONE;
+
+	case PLIP_PK_DONE:
+		/* Inform the upper layer for the arrival of a packet. */
+		rcv->skb->protocol=eth_type_trans(rcv->skb, dev);
+		netif_rx(rcv->skb);
+		nl->enet_stats.rx_packets++;
+		rcv->skb = NULL;
+		if (net_debug > 2)
+			printk(KERN_DEBUG "%s: receive end\n", dev->name);
+
+		/* Close the connection. */
+		z_writeb (0x00, PAR_DATA(dev));
+
+		save_flags(flags);
+		cli();
+		if (snd->state != PLIP_PK_DONE) {
+			nl->connection = PLIP_CN_SEND;
+			restore_flags(flags);
+			queue_task(&nl->immediate, &tq_immediate);
+			mark_bh(IMMEDIATE_BH);
+			enable_par_irq(dev, 1);
+			return OK;
+		} else {
+			nl->connection = PLIP_CN_NONE;
+			restore_flags(flags);
+			enable_par_irq(dev, 1);
+			return OK;
+		}
+	}
+	return OK;
+}
+
+/* PLIP_SEND --- send a byte (two nibbles) 
+   Returns OK on success, TIMEOUT when timeout    */
+inline static int
+plip_send(struct device *dev, unsigned short nibble_timeout, 
+	  enum plip_nibble_state *ns_p, unsigned char data)
+{
+	unsigned char c0;
+	unsigned int cx;
+
+	switch (*ns_p) {
+	case PLIP_NB_BEGIN:
+		z_writeb((data & 0x0f), PAR_DATA(dev));
+		*ns_p = PLIP_NB_1;
+
+	case PLIP_NB_1:
+		z_writeb(0x10 | (data & 0x0f), PAR_DATA(dev));
+		cx = nibble_timeout;
+		while (1) {
+			c0 = z_readb(PAR_STATUS(dev));
+			if ((c0 & 0x80) == 0) 
+				break;
+			if (--cx == 0)
+				return TIMEOUT;
+			udelay(PLIP_DELAY_UNIT);
+		}
+		z_writeb(0x10 | (data >> 4), PAR_DATA(dev));
+		*ns_p = PLIP_NB_2;
+
+	case PLIP_NB_2:
+		z_writeb((data >> 4), PAR_DATA(dev));
+		cx = nibble_timeout;
+		while (1) {
+			c0 = z_readb(PAR_STATUS(dev));
+			if (c0 & 0x80)
+				break;
+			if (--cx == 0)
+				return TIMEOUT;
+			udelay(PLIP_DELAY_UNIT);
+		}
+		*ns_p = PLIP_NB_BEGIN;
+		return OK;
+	}
+	return OK;
+}
+
+/* PLIP_SEND_PACKET --- send a packet */
+static int
+plip_send_packet(struct device *dev, struct net_local *nl,
+		 struct plip_local *snd, struct plip_local *rcv)
+{
+	unsigned short nibble_timeout = nl->nibble;
+	unsigned char *lbuf;
+	unsigned char c0;
+	unsigned int cx;
+	unsigned long flags;
+
+	if (snd->skb == NULL || (lbuf = snd->skb->data) == NULL) {
+		printk(KERN_INFO "%s: send skb lost\n", dev->name);
+		snd->state = PLIP_PK_DONE;
+		snd->skb = NULL;
+		return ERROR;
+	}
+
+	if (snd->length.h == 0) {
+		return OK;
+	}
+
+	switch (snd->state) {
+	case PLIP_PK_TRIGGER:
+		if ((z_readb(PAR_STATUS(dev)) & 0xf8) != 0x80)
+			return TIMEOUT;
+
+		/* Trigger remote rx interrupt. */
+		z_writeb(0x08, PAR_DATA(dev));
+		cx = nl->trigger;
+		while (1) {
+			udelay(PLIP_DELAY_UNIT);
+                        save_flags(flags);
+			cli();
+			if (nl->connection == PLIP_CN_RECEIVE) {
+				restore_flags(flags);
+				/* interrupted */
+				nl->enet_stats.collisions++;
+				if (net_debug > 1)
+					printk(KERN_INFO "%s: collision.\n",
+					       dev->name);
+				return OK;
+			}
+			c0 = z_readb(PAR_STATUS(dev));
+			if (c0 & 0x08) {
+				enable_par_irq(dev, 0);
+				if (net_debug > 2)
+					printk(KERN_DEBUG "%s: send start\n",
+					       dev->name);
+				snd->state = PLIP_PK_LENGTH_LSB;
+				snd->nibble = PLIP_NB_BEGIN;
+				nl->timeout_count = 0;
+				restore_flags(flags);
+				break;
+			}
+			restore_flags(flags);
+			if (--cx == 0) {
+				z_writeb(0x00, PAR_DATA(dev));
+				return TIMEOUT;
+			}
+		}
+
+	case PLIP_PK_LENGTH_LSB:
+		if (plip_send(dev, nibble_timeout, 
+			      &snd->nibble, snd->length.b.lsb))
+			return TIMEOUT;
+		snd->state = PLIP_PK_LENGTH_MSB;
+
+	case PLIP_PK_LENGTH_MSB:
+		if (plip_send(dev, nibble_timeout, 
+			      &snd->nibble, snd->length.b.msb))
+			return TIMEOUT;
+		snd->state = PLIP_PK_DATA;
+		snd->byte = 0;
+		snd->checksum = 0;
+
+	case PLIP_PK_DATA:
+		do
+			if (plip_send(dev, nibble_timeout, 
+				      &snd->nibble, lbuf[snd->byte]))
+				return TIMEOUT;
+		while (++snd->byte < snd->length.h);
+		do
+			snd->checksum += lbuf[--snd->byte];
+		while (snd->byte);
+		snd->state = PLIP_PK_CHECKSUM;
+
+	case PLIP_PK_CHECKSUM:
+		if (plip_send(dev, nibble_timeout, 
+			      &snd->nibble, snd->checksum))
+			return TIMEOUT;
+
+		dev_kfree_skb(snd->skb);
+		nl->enet_stats.tx_packets++;
+		snd->state = PLIP_PK_DONE;
+
+	case PLIP_PK_DONE:
+		/* Close the connection */
+		z_writeb (0x00, PAR_DATA(dev));
+		snd->skb = NULL;
+		if (net_debug > 2)
+			printk(KERN_DEBUG "%s: send end\n", dev->name);
+		nl->connection = PLIP_CN_CLOSING;
+		nl->is_deferred = 1;
+		queue_task(&nl->deferred, &tq_timer);
+		enable_par_irq(dev, 1);
+		return OK;
+	}
+	return OK;
+}
+
+static int
+plip_connection_close(struct device *dev, struct net_local *nl,
+		      struct plip_local *snd, struct plip_local *rcv)
+{
+	unsigned long flags;
+
+        save_flags(flags);
+	cli();
+	if (nl->connection == PLIP_CN_CLOSING) {
+		nl->connection = PLIP_CN_NONE;
+		dev->tbusy = 0;
+		mark_bh(NET_BH);
+	}
+	restore_flags(flags);
+	return OK;
+}
+
+/* PLIP_ERROR --- wait till other end settled */
+static int
+plip_error(struct device *dev, struct net_local *nl,
+	   struct plip_local *snd, struct plip_local *rcv)
+{
+	unsigned char status;
+
+	status = z_readb(PAR_STATUS(dev));
+	if ((status & 0xf8) == 0x80) {
+		if (net_debug > 2)
+			printk(KERN_DEBUG "%s: reset interface.\n", dev->name);
+		nl->connection = PLIP_CN_NONE;
+		dev->tbusy = 0;
+		dev->interrupt = 0;
+		enable_par_irq(dev, 1);
+		mark_bh(NET_BH);
+	} else {
+		nl->is_deferred = 1;
+		queue_task(&nl->deferred, &tq_timer);
+	}
+
+	return OK;
+}
+
+/* We don't need to send arp, for plip is point-to-point. */
+static int
+plip_rebuild_header(struct sk_buff *skb)
+{
+	struct device *dev = skb->dev;
+	struct net_local *nl = (struct net_local *)dev->priv;
+	struct ethhdr *eth = (struct ethhdr *)skb->data;
+	int i;
+
+	if ((dev->flags & IFF_NOARP)==0)
+		return nl->orig_rebuild_header(skb);
+
+	if (eth->h_proto != __constant_htons(ETH_P_IP)
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+	    && eth->h_proto != __constant_htons(ETH_P_IPV6)
+#endif
+		) {
+		printk(KERN_ERR "plip_rebuild_header: Don't know how to resolve type %d addresses?\n", (int)eth->h_proto);
+		memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
+		return 0;
+	}
+
+	for (i=0; i < ETH_ALEN - sizeof(u32); i++)
+		eth->h_dest[i] = 0xfc;
+#if 0
+	*(u32 *)(eth->h_dest+i) = dst;
+#else
+	/* Do not want to include net/route.h here.
+	 * In any case, it is TOP of silliness to emulate
+	 * hardware addresses on PtP link. --ANK
+	 */
+	*(u32 *)(eth->h_dest+i) = 0;
+#endif
+	return 0;
+}
+
+static int
+plip_tx_packet(struct sk_buff *skb, struct device *dev)
+{
+	struct net_local *nl = (struct net_local *)dev->priv;
+	struct plip_local *snd = &nl->snd_data;
+	unsigned long flags;
+
+	if (dev->tbusy)
+		return 1;
+
+	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
+		printk(KERN_ERR "%s: Transmitter access conflict.\n",
+		       dev->name);
+		return 1;
+	}
+
+	if (skb->len > dev->mtu + dev->hard_header_len) {
+		printk(KERN_ERR "%s: packet too big, %d.\n",
+		       dev->name, (int)skb->len);
+		dev->tbusy = 0;
+		return 0;
+	}
+
+	if (net_debug > 2)
+		printk(KERN_DEBUG "%s: send request\n", dev->name);
+
+	save_flags(flags);
+	cli();
+	dev->trans_start = jiffies;
+	snd->skb = skb;
+	snd->length.h = skb->len;
+	snd->state = PLIP_PK_TRIGGER;
+	if (nl->connection == PLIP_CN_NONE) {
+		nl->connection = PLIP_CN_SEND;
+		nl->timeout_count = 0;
+	}
+	queue_task(&nl->immediate, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+	restore_flags(flags);
+
+	return 0;
+}
+
+/* Open/initialize the board.  This is called (in the current kernel)
+   sometime after booting when the 'ifconfig' program is run.
+
+ */
+static int
+plip_open(struct device *dev)
+{
+	struct net_local *nl = (struct net_local *)dev->priv;
+	struct in_device *in_dev;
+
+#if defined(CONFIG_GVPIOEXT_LP) || defined(CONFIG_GVPIOEXT_LP_MODULE)
+	/* Yes, there is a race condition here. Fix it later */
+	if (PLIP_DEV(dev)->par_use & IOEXT_PAR_LP) {
+		/* Can't open if lp is in use */
+#if DEBUG
+		printk("par is in use by lp\n");
+#endif
+		return(-EBUSY);
+	}
+#endif
+	PLIP_DEV(dev)->par_use |= IOEXT_PAR_PLIP;
+
+#if DEBUG
+	printk("plip_open(): sending 00 to data port\n");
+#endif
+
+	/* Clear the data port. */
+	z_writeb (0x00, PAR_DATA(dev));
+
+#if DEBUG
+	printk("plip_open(): sent\n");
+#endif
+
+	/* Initialize the state machine. */
+	nl->rcv_data.state = nl->snd_data.state = PLIP_PK_DONE;
+	nl->rcv_data.skb = nl->snd_data.skb = NULL;
+	nl->connection = PLIP_CN_NONE;
+	nl->is_deferred = 0;
+
+	/* Fill in the MAC-level header.
+	   (ab)Use "dev->broadcast" to store point-to-point MAC address.
+
+	   PLIP doesn't have a real mac address, but we need to create one
+	   to be DOS compatible.  */
+	memset(dev->dev_addr,  0xfc, ETH_ALEN);
+	memset(dev->broadcast, 0xfc, ETH_ALEN);
+
+	if ((in_dev=dev->ip_ptr) != NULL) {
+		/*
+		 *	Any address will do - we take the first
+		 */
+		struct in_ifaddr *ifa=in_dev->ifa_list;
+		if (ifa != NULL) {
+			memcpy(dev->dev_addr+2, &ifa->ifa_local, 4);
+			memcpy(dev->broadcast+2, &ifa->ifa_address, 4);
+		}
+	}
+
+	dev->interrupt = 0;
+	dev->start = 1;
+	dev->tbusy = 0;
+
+	MOD_INC_USE_COUNT;
+
+	/* Enable rx interrupt. */
+	enable_par_irq(dev, 1);
+
+	return 0;
+}
+
+/* The inverse routine to plip_open (). */
+static int
+plip_close(struct device *dev)
+{
+	struct net_local *nl = (struct net_local *)dev->priv;
+	struct plip_local *snd = &nl->snd_data;
+	struct plip_local *rcv = &nl->rcv_data;
+	unsigned long flags;
+
+	dev->tbusy = 1;
+	dev->start = 0;
+        save_flags(flags);
+	cli();
+	nl->is_deferred = 0;
+	nl->connection = PLIP_CN_NONE;
+	restore_flags(flags);
+	z_writeb(0x00, PAR_DATA(dev));
+
+	snd->state = PLIP_PK_DONE;
+	if (snd->skb) {
+		dev_kfree_skb(snd->skb);
+		snd->skb = NULL;
+	}
+	rcv->state = PLIP_PK_DONE;
+	if (rcv->skb) {
+		kfree_skb(rcv->skb);
+		rcv->skb = NULL;
+	}
+
+	PLIP_DEV(dev)->par_use &= ~IOEXT_PAR_PLIP;
+
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static struct enet_statistics *
+plip_get_stats(struct device *dev)
+{
+	struct net_local *nl = (struct net_local *)dev->priv;
+	struct enet_statistics *r = &nl->enet_stats;
+
+	return r;
+}
+
+static int
+plip_config(struct device *dev, struct ifmap *map)
+{
+	if (dev->flags & IFF_UP)
+		return -EBUSY;
+
+	printk(KERN_INFO "%s: This interface is autodetected (ignored).\n",
+	       dev->name);
+
+	return 0;
+}
+
+static int
+plip_ioctl(struct device *dev, struct ifreq *rq, int cmd)
+{
+	struct net_local *nl = (struct net_local *) dev->priv;
+	struct plipconf *pc = (struct plipconf *) &rq->ifr_data;
+  
+	switch(pc->pcmd) {
+	case PLIP_GET_TIMEOUT:
+		pc->trigger = nl->trigger;
+		pc->nibble  = nl->nibble;
+		break;
+	case PLIP_SET_TIMEOUT:
+		nl->trigger = pc->trigger;
+		nl->nibble  = pc->nibble;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+	return 0;
+}
+
+/*
+ * Detect and initialize all IO-Extenders in this system.
+ *
+ * Both PLIP and serial devices are configured.
+ */
+int plip_init(struct device *dev)
+{
+	IOEXT_struct *board;
+	struct net_local *nl;
+
+	if (ioext_num == 0) {
+		printk(KERN_INFO "%s\n", version);
+	}
+
+	board = PLIP_DEV(dev)->board;
+	dev->base_addr = (unsigned long)&board->par.DATA;
+
+	/* Cheat and use irq to index into our table */
+	dev->irq = ioext_num;
+
+	printk(KERN_INFO "%s: IO-Extender parallel port at 0x%08lX\n", dev->name, dev->base_addr);
+
+	/* Fill in the generic fields of the device structure. */
+	ether_setup(dev);
+
+	/* Then, override parts of it */
+	dev->hard_start_xmit  = plip_tx_packet;
+	dev->open    = plip_open;
+	dev->stop    = plip_close;
+	dev->get_stats     = plip_get_stats;
+	dev->set_config    = plip_config;
+	dev->do_ioctl    = plip_ioctl;
+	dev->tx_queue_len  = 10;
+	dev->flags          = IFF_POINTOPOINT|IFF_NOARP;
+
+	/* Set the private structure */
+	dev->priv = kmalloc(sizeof (struct net_local), GFP_KERNEL);
+	if (dev->priv == NULL) {
+		printk(KERN_ERR "%s: out of memory\n", dev->name);
+		return -ENOMEM;
+	}
+	memset(dev->priv, 0, sizeof(struct net_local));
+	nl = (struct net_local *) dev->priv;
+
+	nl->orig_rebuild_header = dev->rebuild_header;
+	dev->rebuild_header   = plip_rebuild_header;
+
+	/* Initialize constants */
+	nl->trigger  = PLIP_TRIGGER_WAIT;
+	nl->nibble  = PLIP_NIBBLE_WAIT;
+
+	/* Initialize task queue structures */
+	nl->immediate.next = NULL;
+	nl->immediate.sync = 0;
+	nl->immediate.routine = (void *)(void *)plip_bh;
+	nl->immediate.data = dev;
+
+	nl->deferred.next = NULL;
+	nl->deferred.sync = 0;
+	nl->deferred.routine = (void *)(void *)plip_kick_bh;
+	nl->deferred.data = dev;
+
+	/* Don't enable interrupts yet */
+
+	return 0;
+}
diff -Naur linux-2.4.26/drivers/char/scc2692.c linux-2.4.26-m68k/drivers/char/scc2692.c
--- linux-2.4.26/drivers/char/scc2692.c	1970-01-01 10:00:00.000000000 +1000
+++ linux-2.4.26-m68k/drivers/char/scc2692.c	2003-07-22 07:31:02.000000000 +1000
@@ -0,0 +1,617 @@
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/kdev_t.h>
+#include <asm/io.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/mm.h>
+#include <linux/serial.h>
+#include <linux/fcntl.h>
+#include <linux/major.h>
+#include <linux/delay.h>
+#include <linux/tqueue.h>
+#include <linux/version.h>
+#include <linux/slab.h>
+#include <linux/miscdevice.h>
+#include <linux/console.h>
+#include <linux/init.h>
+#include <asm/setup.h>
+#include <asm/bootinfo.h>
+
+#include <asm/tekuart.h>
+#include <asm/tekirq.h>
+
+#include <linux/generic_serial.h>
+
+#define NR_PORTS 2
+
+static struct scc_port
+{
+	struct gs_port	gs;
+	unsigned long	base;
+	int		irq_rx, irq_tx;
+	unsigned char	channel;
+	unsigned long	scale;
+} scc_ports[NR_PORTS];
+
+#define STATUS(scc)	((scc)->base + (((scc)->channel * 8 + 1) * (scc)->scale))
+#define CSR(scc)	STATUS(scc)
+
+#define RECEIVE(scc)	((scc)->base + (((scc)->channel * 8 + 3) * (scc)->scale))
+#define TRANSMIT(scc)	RECEIVE(scc)
+
+#define COMMAND(scc)	((scc)->base + (((scc)->channel * 8 + 2) * (scc)->scale))
+
+#define MR(scc)		((scc)->base + (((scc)->channel * 8 + 0) * (scc)->scale))
+
+
+static struct tty_driver scc_driver, scc_callout_driver;
+static struct tty_struct *scc_table[NR_PORTS] = { NULL, NULL };
+static struct termios *scc_termios[NR_PORTS];
+static struct termios *scc_termios_locked[NR_PORTS];
+
+int scc_refcount;
+
+#define SCC_MINOR_BASE        64
+#define SCC_MAGIC 0x52696368
+
+static inline void scc_disable_tx_interrupts(void *ptr)
+{
+	struct scc_port *port = ptr;
+	disable_irq(port->irq_tx);
+	port->gs.flags &= ~GS_TX_INTEN;
+}
+
+static inline void scc_enable_tx_interrupts(void *ptr)
+{
+	struct scc_port *port = ptr;
+        enable_irq(port->irq_tx);
+}
+
+static inline void scc_disable_rx_interrupts(void *ptr)
+{
+	struct scc_port *port = ptr;
+        disable_irq(port->irq_rx);
+}
+
+static inline void scc_enable_rx_interrupts(void *ptr)
+{
+	struct scc_port *port = ptr;
+        enable_irq(port->irq_rx);
+}
+
+
+/*
+ * Receiver Interrupt
+ */
+static void scc_rx_int(int irq, void *data, struct pt_regs *fp)
+{
+	struct scc_port *port = data;
+	struct tty_struct *tty = port->gs.tty;
+	unsigned long flags;
+	volatile unsigned char ch;
+
+	spin_lock_irqsave(tek_uart_lock, flags);
+	while ( *(volatile unsigned char *)STATUS(port) & 0x1 )
+	{
+		ch = *(volatile unsigned char *)RECEIVE(port);
+
+		if (!tty)
+			/*
+			 * FIXME: It might be a bad idea to call printk
+			 *        with the lock held.
+			 */
+			printk(KERN_WARNING "scc_rx_int with NULL tty!\n");
+		else if (tty->flip.count < TTY_FLIPBUF_SIZE) {
+			*tty->flip.char_buf_ptr = ch;
+			*tty->flip.flag_buf_ptr = 0;
+			tty->flip.flag_buf_ptr++;
+			tty->flip.char_buf_ptr++;
+			tty->flip.count++;
+		}
+	}
+	spin_unlock_irqrestore(tek_uart_lock, flags);
+
+	tty_flip_buffer_push(tty);
+}
+
+/*
+ * Transmitter interrupt
+ */
+static void scc_tx_int(int irq, void *data, struct pt_regs *fp)
+{
+	struct scc_port *port = data;
+	struct tty_struct *tty = port->gs.tty;
+	unsigned long flags;
+
+	if ( !tty )
+	{
+		scc_disable_tx_interrupts(port);
+		return;
+	}
+	
+	spin_lock_irqsave(tek_uart_lock, flags);
+	while ( *(volatile unsigned char *)STATUS(port) & 0x4 )
+	{
+		*(volatile unsigned char *)TRANSMIT(port) =
+			port->gs.xmit_buf[port->gs.xmit_tail++];
+		port->gs.xmit_tail = port->gs.xmit_tail & (SERIAL_XMIT_SIZE-1);
+		if (--port->gs.xmit_cnt <= 0)
+			break;
+	}
+	spin_unlock_irqrestore(tek_uart_lock, flags);
+
+	if ((port->gs.xmit_cnt <= 0) || (tty && (tty->stopped || tty->hw_stopped)) )
+	{
+		scc_disable_tx_interrupts(port);
+	}
+
+        if (tty && port->gs.xmit_cnt <= port->gs.wakeup_chars) {
+                if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
+                        (tty->ldisc.write_wakeup)(port->gs.tty);
+                wake_up_interruptible(&tty->write_wait);
+        }
+}
+
+/*---------------------------------------------------------------------------
+ * generic_serial.c callback funtions
+ *--------------------------------------------------------------------------*/
+
+static int scc_get_CD(void *ptr)
+{
+	return 1;
+}
+
+static void scc_shutdown_port(void *ptr)
+{
+        struct scc_port *port = ptr;
+
+        port->gs.flags &= ~ GS_ACTIVE;
+}
+
+static const int baudrates[B38400] = {
+	[B19200]	13,
+	[B9600]		12,
+	[B4800]		10,
+	[B2400]		9,
+	[B1200]		7,
+	[B600]		6,
+	[B300]		5,
+	[B134]		3,
+	[B110]		2,
+	[B75]		1
+};
+
+static int scc_set_real_termios(void *ptr)
+{
+	struct scc_port *port = ptr;
+	unsigned long flags;
+	unsigned int cflag;
+	unsigned char baudrate = 0;
+	unsigned char mr1 = 0x80, mr2 = 0;
+	int baud;
+
+	if (!port->gs.tty || !port->gs.tty->termios)
+		return 0;
+
+	cflag = port->gs.tty->termios->c_cflag;
+	baud = cflag & (CBAUD | CBAUDEX);
+
+	if (baud == B0)
+	{
+		// TODO: hangup
+		return 0;
+	}
+
+	if ((baud >= sizeof baudrates/sizeof baudrates[0]) || !baudrates[baud])
+		return -EINVAL;
+	baudrate = baudrates[baud] - 1;
+
+	if ( cflag & CSTOPB )
+		mr2 |= 0x7;	/* 1 stop bit */
+
+	if ( !(cflag & PARENB) )
+		mr1 |= 0x10;	/* no parity */
+	else if ( cflag & PARODD )
+		mr1 |= 0x04;
+
+	switch (cflag & CSIZE)
+	{
+	case CS5:
+		break;
+	case CS6:
+		mr1 |= 0x01;
+		break;
+	case CS7:
+		mr1 |= 0x02;
+		break;
+	case CS8:
+		mr1 |= 0x03;
+		break;
+	default:
+		return -EINVAL;
+	}
+	
+/*
+	printk("scc2692: real_termios line=%d baudrate=%02x mr1=%02x mr2=%02x\n", port->channel, baudrate, mr1, mr2);
+*/
+
+	spin_lock_irqsave(tek_uart_lock, flags);
+
+	// Set baudrate into register CSRA
+	*(volatile unsigned char *)CSR(port) = (baudrate << 4) | (baudrate & 0xf);
+	// Reset MR pointer
+	*(volatile unsigned char *)COMMAND(port) = 1 << 4;
+	// Set MR1
+	*(volatile unsigned char *)MR(port) = mr1;
+	// Set MR2
+	*(volatile unsigned char *)MR(port) = mr2;
+
+	spin_unlock_irqrestore(tek_uart_lock, flags);
+
+	return 0;
+}
+
+static int scc_chars_in_buffer(void *ptr)
+{
+	struct scc_port *port = ptr;
+	int res;
+	unsigned long flags;
+
+	spin_lock_irqsave(tek_uart_lock, flags);
+	res = !(*(volatile unsigned char *)STATUS(port) & 4);
+	spin_unlock_irqrestore(tek_uart_lock, flags);
+
+	return res;
+}
+
+static void scc_hungup(void *ptr)
+{
+        scc_disable_tx_interrupts(ptr);
+        scc_disable_rx_interrupts(ptr);
+        MOD_DEC_USE_COUNT;
+}
+
+static void scc_close(void *ptr)
+{
+        scc_disable_tx_interrupts(ptr);
+        scc_disable_rx_interrupts(ptr);
+        MOD_DEC_USE_COUNT;
+}
+
+/*---------------------------------------------------------------------------
+ * Driver entrypoints referenced from above
+ *--------------------------------------------------------------------------*/
+
+static int scc_open (struct tty_struct * tty, struct file * filp)
+{
+        int line = MINOR(tty->device) - SCC_MINOR_BASE;
+        int retval;
+        struct scc_port *port = &scc_ports[line];
+
+        if ( line >= 2 )
+		return -ENXIO;
+
+        tty->driver_data = port;
+        port->gs.tty = tty;
+        port->gs.count++;
+        retval = gs_init_port(&port->gs);
+        if (retval) {
+                port->gs.count--;
+                return retval;
+        }
+        port->gs.flags |= GS_ACTIVE;
+        if (port->gs.count == 1) {
+                MOD_INC_USE_COUNT;
+        }
+        retval = gs_block_til_ready(port, filp);
+
+        if (retval) {
+                MOD_DEC_USE_COUNT;
+                port->gs.count--;
+                return retval;
+        }
+
+        if ((port->gs.count == 1) && (port->gs.flags & ASYNC_SPLIT_TERMIOS)) {
+                if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+                        *tty->termios = port->gs.normal_termios;
+                else
+                        *tty->termios = port->gs.callout_termios;
+                scc_set_real_termios (port);
+//		scc_disable_tx_interrupts(ptr);
+        }
+
+        port->gs.session = current->session;
+        port->gs.pgrp = current->pgrp;
+
+        scc_enable_rx_interrupts(port);
+
+        return 0;
+}
+
+static void scc_throttle (struct tty_struct * tty)
+{
+/*
+        struct scc_port *port = (struct scc_port *)tty->driver_data;
+        unsigned long   flags;
+        SCC_ACCESS_INIT(port);
+
+        if (tty->termios->c_cflag & CRTSCTS) {
+                save_flags(flags);
+                cli();
+                SCCmod(TX_CTRL_REG, ~TCR_RTS, 0);
+                restore_flags(flags);
+        }
+        if (I_IXOFF(tty))
+                scc_send_xchar(tty, STOP_CHAR(tty));
+*/
+}
+
+static void scc_unthrottle (struct tty_struct * tty)
+{
+}
+
+static int scc_ioctl(struct tty_struct *tty, struct file *file,
+                     unsigned int cmd, unsigned long arg)
+{
+        return -ENOIOCTLCMD;
+}
+
+static void scc_break_ctl(struct tty_struct *tty, int break_state)
+{
+}
+
+/*---------------------------------------------------------------------------
+ * Interface from generic_serial.c back here
+ *--------------------------------------------------------------------------*/
+
+static struct real_driver scc_real_driver = {
+        scc_disable_tx_interrupts,
+        scc_enable_tx_interrupts,
+        scc_disable_rx_interrupts,
+        scc_enable_rx_interrupts,
+        scc_get_CD,
+        scc_shutdown_port,
+        scc_set_real_termios,
+        scc_chars_in_buffer,
+        scc_close,
+        scc_hungup,
+        NULL
+};
+
+
+int __devinit scc_register_chip(struct scc_port *port)
+{
+	port->gs.callout_termios = tty_std_termios;
+	port->gs.normal_termios = tty_std_termios;
+	port->gs.magic = SCC_MAGIC;
+	port->gs.close_delay = HZ/2;
+	port->gs.closing_wait = 30 * HZ;
+	port->gs.rd = &scc_real_driver;
+#ifdef NEW_WRITE_LOCKING
+	port->gs.port_write_sem = MUTEX;
+#endif
+
+	init_waitqueue_head(&port->gs.open_wait);
+	init_waitqueue_head(&port->gs.close_wait);
+
+	return 0;
+}
+
+static int __devinit scc_chip_init(unsigned long base, int irq_rxa, int irq_txa,
+			 int irq_rxb, int irq_txb)
+{
+	int err = 0;
+	unsigned long flags;
+
+	scc_ports[0].base   = base;
+	scc_ports[0].scale  = 4;
+	scc_ports[0].irq_rx = irq_rxa;
+	scc_ports[0].irq_tx = irq_txa;
+	scc_ports[0].channel = 0;
+
+	scc_ports[1].base   = base;
+	scc_ports[1].scale  = 4;
+	scc_ports[1].irq_rx = irq_rxb;
+	scc_ports[1].irq_tx = irq_txb;
+	scc_ports[1].channel = 1;
+
+	save_flags(flags);
+	cli();
+
+	err = request_irq(irq_rxa, scc_rx_int, SA_INTERRUPT, "SCC-A RX", &scc_ports[0]);
+	if ( err < 0 )
+		return err;
+
+	err = request_irq(irq_txa, scc_tx_int, SA_INTERRUPT, "SCC-A TX", &scc_ports[0]);
+	if ( err < 0 )
+	{
+		free_irq(irq_rxa, &scc_ports[0]);
+		return err;
+	}
+
+	err = request_irq(irq_rxb, scc_rx_int, SA_INTERRUPT, "SCC-B RX", &scc_ports[1]);
+	if ( err < 0 )
+	{
+		free_irq(irq_rxa, &scc_ports[0]);
+		free_irq(irq_txa, &scc_ports[0]);
+		return err;
+	}
+
+	err = request_irq(irq_txb, scc_tx_int, SA_INTERRUPT, "SCC-B TX", &scc_ports[1]);
+	if ( err < 0 )
+	{
+		free_irq(irq_rxa, &scc_ports[0]);
+		free_irq(irq_txa, &scc_ports[0]);
+		free_irq(irq_rxb, &scc_ports[1]);
+		return err;
+	}
+
+	disable_irq(irq_rxa);
+	disable_irq(irq_txa);
+	disable_irq(irq_rxb);
+	disable_irq(irq_txb);
+
+	restore_flags(flags);
+
+	scc_register_chip(&scc_ports[0]);
+	scc_register_chip(&scc_ports[1]);
+
+	return 0;
+}
+
+int __devinit tekscc_init(void)
+{
+	int err = -ENXIO;
+
+#ifdef CONFIG_TEKXP
+	err = scc_chip_init(TEK_UART_BASE, TEK_IRQ_RXRDY_A, TEK_IRQ_TXRDY_A,
+			    TEK_IRQ_RXRDY_B, TEK_IRQ_TXRDY_B);
+#endif
+	if ( err < 0 )
+		return err;
+
+	memset(&scc_driver, 0, sizeof(scc_driver));
+	scc_driver.magic = TTY_DRIVER_MAGIC;
+	scc_driver.driver_name = "scc2692";
+#ifdef CONFIG_DEVFS_FS
+	scc_driver.name = "tts/%d";
+#else
+	scc_driver.name = "ttyS";
+#endif
+	scc_driver.major = TTY_MAJOR;
+	scc_driver.minor_start = SCC_MINOR_BASE;
+	scc_driver.num = 2;
+	scc_driver.type = TTY_DRIVER_TYPE_SERIAL;
+	scc_driver.subtype = SERIAL_TYPE_NORMAL;
+	scc_driver.init_termios = tty_std_termios;
+	scc_driver.init_termios.c_cflag = B9600 | PARENB | CSTOPB | CS7 | CREAD | HUPCL | CLOCAL;
+	scc_driver.flags = TTY_DRIVER_REAL_RAW;
+	scc_driver.refcount = &scc_refcount;
+	scc_driver.table = scc_table;
+	scc_driver.termios = scc_termios;
+	scc_driver.termios_locked = scc_termios_locked;
+	scc_driver.open = scc_open;
+	scc_driver.close = gs_close;
+	scc_driver.write = gs_write;
+	scc_driver.put_char = gs_put_char;
+	scc_driver.flush_chars = gs_flush_chars;
+	scc_driver.write_room = gs_write_room;
+	scc_driver.chars_in_buffer = gs_chars_in_buffer;
+	scc_driver.flush_buffer = gs_flush_buffer;
+	scc_driver.ioctl = scc_ioctl;
+	scc_driver.throttle = scc_throttle;
+	scc_driver.unthrottle = scc_unthrottle;
+	scc_driver.set_termios = gs_set_termios;
+	scc_driver.stop = gs_stop;
+	scc_driver.start = gs_start;
+	scc_driver.hangup = gs_hangup;
+	scc_driver.break_ctl = scc_break_ctl;
+
+	scc_callout_driver = scc_driver;
+#ifdef CONFIG_DEVFS_FS
+	scc_callout_driver.driver_name = "cua/%d";
+#else
+	scc_callout_driver.driver_name = "cua";
+#endif
+	scc_callout_driver.major = TTYAUX_MAJOR;
+	scc_callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+
+	if ((err = tty_register_driver(&scc_driver))) {
+		printk(KERN_ERR "scc2692: Couldn't register scc driver, error = %d\n", err);
+		return -EBUSY;
+	}
+	if ((err = tty_register_driver(&scc_callout_driver))) {
+		printk(KERN_ERR "scc2692: Couldn't register scc callout driver, error = %d\n", err);
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+static void __devexit tekscc_exit(void)
+{
+	struct scc_port *port = &scc_ports[0];
+        scc_disable_tx_interrupts(port);
+        scc_disable_rx_interrupts(port);
+        free_irq(port->irq_rx, port);
+        free_irq(port->irq_tx, port);
+
+        port = &scc_ports[1];
+        scc_disable_tx_interrupts(port);
+        scc_disable_rx_interrupts(port);
+        free_irq(port->irq_rx, port);
+        free_irq(port->irq_tx, port);
+
+	if ( tty_unregister_driver(&scc_driver) )
+		printk(KERN_ERR "Could not unregister SCC2692 serial driver\n");
+	if ( tty_unregister_driver(&scc_callout_driver) )
+		printk(KERN_ERR "Could not unregister SCC2692 callout driver\n");
+}
+
+module_init(tekscc_init);
+module_exit(tekscc_exit);
+MODULE_LICENSE("GPL");
+
+#ifdef CONFIG_SERIAL_CONSOLE
+
+/*---------------------------------------------------------------------------
+ * Serial console stuff...
+ *--------------------------------------------------------------------------*/
+
+#define scc_delay() do { __asm__ __volatile__ (" nop; nop"); } while (0)
+
+static void scc_ch_write (char ch)
+{
+	tek_uart_putchar(0, ch, 1);
+}
+
+static void scc_console_write (struct console *co, const char *str, unsigned count)
+{
+        unsigned long   flags;
+
+        save_flags(flags);
+        cli();
+
+        while (count--)
+        {
+                if (*str == '\n')
+                        scc_ch_write ('\r');
+                scc_ch_write (*str++);
+        }
+        restore_flags(flags);
+}
+
+static kdev_t scc_console_device(struct console *c)
+{
+        return MKDEV(TTY_MAJOR, SCC_MINOR_BASE + c->index);
+}
+
+
+static int __devinit scc_console_setup(struct console *co, char *options)
+{
+        return 0;
+}
+
+static struct console sercons = {
+        name:           "ttyS",
+        write:          scc_console_write,
+        device:         scc_console_device,
+        setup:          scc_console_setup,
+        flags:          CON_PRINTBUFFER,
+        index:          -1,
+};
+
+
+void __init tekscc_console_init(void)
+{
+                register_console(&sercons);
+}
+
+#endif
+
diff -Naur linux-2.4.26/drivers/char/tty_io.c linux-2.4.26-m68k/drivers/char/tty_io.c
--- linux-2.4.26/drivers/char/tty_io.c	2004-04-14 23:05:29.000000000 +1000
+++ linux-2.4.26-m68k/drivers/char/tty_io.c	2004-04-15 06:42:20.000000000 +1000
@@ -138,7 +138,9 @@
 	      unsigned int cmd, unsigned long arg);
 static int tty_fasync(int fd, struct file * filp, int on);
 extern int vme_scc_init (void);
+extern int tekscc_init (void);
 extern long vme_scc_console_init(void);
+extern long tekscc_console_init(void);
 extern int serial167_init(void);
 extern long serial167_console_init(void);
 extern void console_8xx_init(void);
@@ -2269,6 +2271,9 @@
 #if defined(CONFIG_SERIAL167)
 	serial167_console_init();
 #endif
+#if defined(CONFIG_SCC2692)
+	tekscc_console_init();
+#endif
 #if defined(CONFIG_SH_SCI)
 	sci_console_init();
 #endif
@@ -2408,6 +2413,9 @@
 #if defined(CONFIG_MVME162_SCC) || defined(CONFIG_BVME6000_SCC) || defined(CONFIG_MVME147_SCC)
 	vme_scc_init();
 #endif
+#ifdef CONFIG_SCC2692
+	tekscc_init();
+#endif
 #ifdef CONFIG_SERIAL_TX3912
 	tx3912_rs_init();
 #endif
diff -Naur linux-2.4.26/drivers/ide/ide-probe.c linux-2.4.26-m68k/drivers/ide/ide-probe.c
--- linux-2.4.26/drivers/ide/ide-probe.c	2004-04-14 23:05:29.000000000 +1000
+++ linux-2.4.26-m68k/drivers/ide/ide-probe.c	2004-04-15 06:42:24.000000000 +1000
@@ -350,6 +350,7 @@
 		rc = 0;
 		/* clear drive IRQ */
 		(void) hwif->INB(IDE_STATUS_REG);
+		(void) ide_ack_intr(hwif);
 		local_irq_restore(flags);
 	} else {
 		/* drive refused ID */
@@ -503,6 +504,7 @@
 				drive->name, hwif->INB(IDE_STATUS_REG));
 		/* ensure drive irq is clear */
 		(void) hwif->INB(IDE_STATUS_REG);
+		(void) ide_ack_intr(hwif);
 	} else {
 		/* not present or maybe ATAPI */
 		rc = 3;
@@ -513,6 +515,7 @@
 		ide_delay_50ms();
 		/* ensure drive irq is clear */
 		(void) hwif->INB(IDE_STATUS_REG);
+		(void) ide_ack_intr(hwif);
 	}
 	return rc;
 }
diff -Naur linux-2.4.26/drivers/macintosh/adb.c linux-2.4.26-m68k/drivers/macintosh/adb.c
--- linux-2.4.26/drivers/macintosh/adb.c	2003-08-25 21:44:42.000000000 +1000
+++ linux-2.4.26-m68k/drivers/macintosh/adb.c	2003-10-21 07:14:22.000000000 +1000
@@ -35,6 +35,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/completion.h>
+
 #include <asm/uaccess.h>
 #ifdef CONFIG_PPC
 #include <asm/prom.h>
@@ -380,14 +381,14 @@
 	
 	if (adb_controller == NULL)
 		return -ENXIO;
-		
+	
 	if (adb_controller->autopoll)
 		adb_controller->autopoll(0);
 
 	nret = notifier_call_chain(&adb_client_list, ADB_MSG_PRE_RESET, NULL);
 	if (nret & NOTIFY_STOP_MASK) {
 		if (adb_controller->autopoll)
-			adb_controller->autopoll(devs);
+			adb_controller->autopoll(0);
 		return -EBUSY;
 	}
 
@@ -467,13 +468,15 @@
 		use_sreq = 1;
 	} else
 		use_sreq = 0;
-	req->nbytes = nbytes+1;
+	i = (flags & ADBREQ_RAW) ? 0 : 1;
+	req->nbytes = nbytes+i;
 	req->done = done;
 	req->reply_expected = flags & ADBREQ_REPLY;
 	req->data[0] = ADB_PACKET;
 	va_start(list, nbytes);
-	for (i = 0; i < nbytes; ++i)
-		req->data[i+1] = va_arg(list, int);
+	while (i < req->nbytes) {
+		req->data[i++] = va_arg(list, int);
+	}
 	va_end(list);
 
 	if (flags & ADBREQ_NOSEND)
diff -Naur linux-2.4.26/drivers/mtd/maps/Config.in linux-2.4.26-m68k/drivers/mtd/maps/Config.in
--- linux-2.4.26/drivers/mtd/maps/Config.in	2003-06-14 00:51:34.000000000 +1000
+++ linux-2.4.26-m68k/drivers/mtd/maps/Config.in	2003-07-22 07:32:35.000000000 +1000
@@ -96,6 +96,10 @@
    dep_tristate '  Generic uClinux RAM/ROM filesystem support' CONFIG_MTD_UCLINUX $CONFIG_MTD_PARTITIONS
 fi
 
+if [ "$CONFIG_TEKXP" = "y" ]; then
+   dep_tristate '  TekXpress optional ROM support' CONFIG_MTD_TEKXP_OPTROM $CONFIG_MTD_ROM
+fi
+
 # This needs CFI or JEDEC, depending on the cards found.
 dep_tristate '  PCI MTD driver' CONFIG_MTD_PCI $CONFIG_MTD $CONFIG_PCI
 dep_tristate '  PCMCIA MTD driver' CONFIG_MTD_PCMCIA $CONFIG_MTD $CONFIG_PCMCIA
diff -Naur linux-2.4.26/drivers/mtd/maps/Makefile linux-2.4.26-m68k/drivers/mtd/maps/Makefile
--- linux-2.4.26/drivers/mtd/maps/Makefile	2003-06-14 00:51:34.000000000 +1000
+++ linux-2.4.26-m68k/drivers/mtd/maps/Makefile	2003-07-22 07:32:35.000000000 +1000
@@ -22,6 +22,7 @@
 obj-$(CONFIG_MTD_L440GX)	+= l440gx.o
 obj-$(CONFIG_MTD_AMD76XROM)	+= amd76xrom.o
 obj-$(CONFIG_MTD_ICH2ROM)	+= ich2rom.o
+obj-$(CONFIG_MTD_TEKXP_OPTROM)	+= tekxp_optrom.o
 obj-$(CONFIG_MTD_TSUNAMI)	+= tsunami_flash.o
 obj-$(CONFIG_MTD_MBX860)	+= mbx860.o
 obj-$(CONFIG_MTD_NORA)		+= nora.o
diff -Naur linux-2.4.26/drivers/mtd/maps/tekxp_optrom.c linux-2.4.26-m68k/drivers/mtd/maps/tekxp_optrom.c
--- linux-2.4.26/drivers/mtd/maps/tekxp_optrom.c	1970-01-01 10:00:00.000000000 +1000
+++ linux-2.4.26-m68k/drivers/mtd/maps/tekxp_optrom.c	2003-07-22 07:32:35.000000000 +1000
@@ -0,0 +1,177 @@
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/config.h>
+
+/*
+ * Maximum number of ROMS supported by this drivers.
+ *
+ * There will be definitely be no more, since the address space for them
+ * is restricted to what those 16 may span.
+ */
+#define MAX_NUM_OPTROM	16
+
+/*
+ * Virtual address of the address space potentially used by the ROMs.
+ */
+static unsigned long possible_rom_memory;
+
+/*
+ * Structure holding just the information needed for the MTD framework.
+ * The driver itself needs no further information about a single ROM.
+ */
+typedef struct {
+	struct map_info		map;
+	struct mtd_info		*mtd;
+} optrom_desc_t;
+
+static int num_optrom;
+static optrom_desc_t optrom_desc[MAX_NUM_OPTROM];
+
+/*
+ * Check if a ROM is present and determinate its size.
+ */
+static unsigned int __init detect_optrom_size(unsigned long start_address)
+{
+	unsigned long original = *(unsigned long *)start_address;
+
+	/*
+	 * We try to write into the ROM. It will not fault on us.
+	 */
+	*(volatile unsigned long *)start_address = ~original;
+
+	/*
+	 * If the write did not change there is a ROM or nothing.
+	 */
+	if ( *(volatile unsigned long *)start_address == original )
+	{
+		/*
+		 * But the Nothing will fail to report a correct size.
+		 *
+		 * Yes, the size is stored at a given position within the
+		 * ROM. So if someone did create ROMs on his own behalf
+		 * not following the "specification" this driver will
+		 * fail to detect them.
+		 *
+		 * Do NOT fix this! It is intended behaviour since the
+		 * future goal of this driver is to present the filesystem
+		 * stored in the original ROMs.
+		 */
+		unsigned short size = *(unsigned short *)(start_address + 6);
+		if ( size == 0x80 || size == 0x100 || size == 0x200 || size == 0x400 )
+			return size * 1024;
+	}
+
+	/*
+	 * If we hit something else try to restore the original content.
+	 */
+	*(unsigned long *)start_address = original;
+
+	return 0;
+}
+
+/*
+ * Just the obvious way to copy memory around.
+ */
+static void optrom_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	memcpy(to, (char *)map->map_priv_1 + from, len);
+}
+
+/*
+ * We can not write into the ROMs.
+ */
+static void optrom_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+}
+
+/*
+ * Initialization
+ */
+static int __init init_optrom(void)
+{
+	int i;
+
+	/*
+	 * Get all memory mapped that may hold a ROM. This might have to
+	 * be switched to a less gready sheme if causing any problems.
+	 */
+	possible_rom_memory = (unsigned long)ioremap_nocache(0x1000000, MAX_NUM_OPTROM * 0x100000);
+	if ( !possible_rom_memory )
+	{
+		printk(KERN_WARNING "Could not map optroms into the virtual memory space\n");
+		return -ENXIO;
+	}
+
+	/*
+	 * Search through the complete address space for any ROM.
+	 * If any ROM is found register it with the MTD framework.
+	 */
+	for ( i=0; i<MAX_NUM_OPTROM; i++ )
+	{
+		unsigned int size = detect_optrom_size(possible_rom_memory + i * 0x100000);
+		if ( size > 0 )
+		{
+			optrom_desc_t *desc = &optrom_desc[num_optrom];
+
+			printk(KERN_INFO "Found optional ROM of size %u at %08x\n", size, 0x1000000 + i * 0x100000);
+
+			desc->map.name = "TekXpress optional ROM";
+			desc->map.size = size;
+			desc->map.map_priv_1 = possible_rom_memory + i * 0x100000;
+			desc->map.copy_from = optrom_copy_from;
+			desc->map.copy_to = optrom_copy_to;
+
+			desc->mtd = do_map_probe("map_rom", &desc->map);
+			if ( !desc->mtd )
+			{
+				printk(KERN_ERR "Could not allocate MTD structure\n");
+				continue;
+			}
+
+			desc->mtd->module = THIS_MODULE;
+			add_mtd_device(desc->mtd);
+
+			num_optrom++;
+		}
+
+	}
+
+	if ( num_optrom <= 0 )
+	{
+		iounmap((void *)possible_rom_memory);
+		printk(KERN_WARNING "No optional rom found\n");
+		return -ENXIO;
+	}
+
+	return 0;
+}
+
+/*
+ * Unregister all ROMs found from the MTD framework.
+ */
+void __exit cleanup_optrom(void)
+{
+	while ( num_optrom-- )
+	{
+		optrom_desc_t *desc = &optrom_desc[num_optrom];
+
+		del_mtd_device(desc->mtd);
+		map_destroy(desc->mtd);
+	}
+
+	iounmap((void*)possible_rom_memory);
+}
+
+
+
+module_init(init_optrom);
+module_exit(cleanup_optrom);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Michael Mueller <malware@t-online.de>");
+MODULE_DESCRIPTION("MTD map driver for optional ROM of the TekXpress XP2x X-Terminals");
+
diff -Naur linux-2.4.26/drivers/net/Makefile linux-2.4.26-m68k/drivers/net/Makefile
--- linux-2.4.26/drivers/net/Makefile	2004-04-14 23:05:30.000000000 +1000
+++ linux-2.4.26-m68k/drivers/net/Makefile	2004-04-15 06:42:31.000000000 +1000
@@ -95,6 +95,7 @@
 obj-$(CONFIG_FEALNX) += fealnx.o mii.o
 obj-$(CONFIG_TC35815) += tc35815.o
 obj-$(CONFIG_TIGON3) += tg3.o
+obj-$(CONFIG_TEKSONIC) += teksonic.o
 
 ifeq ($(CONFIG_E100),y)
   obj-y += e100/e100.o
diff -Naur linux-2.4.26/drivers/net/Space.c linux-2.4.26-m68k/drivers/net/Space.c
--- linux-2.4.26/drivers/net/Space.c	2004-02-19 00:36:31.000000000 +1100
+++ linux-2.4.26-m68k/drivers/net/Space.c	2004-02-19 09:16:53.000000000 +1100
@@ -101,6 +101,7 @@
 extern int mac8390_probe(struct net_device *dev);
 extern int mac89x0_probe(struct net_device *dev);
 extern int mc32_probe(struct net_device *dev);
+extern int teksonic_probe(struct net_device *dev);
   
 /* Detachable devices ("pocket adaptors") */
 extern int de600_probe(struct net_device *);
@@ -326,6 +327,9 @@
 };
 
 static struct devprobe m68k_probes[] __initdata = {
+#ifdef CONFIG_TEKSONIC
+	{teksonic_probe, 0},
+#endif
 #ifdef CONFIG_ATARILANCE	/* Lance-based Atari ethernet boards */
 	{atarilance_probe, 0},
 #endif
diff -Naur linux-2.4.26/drivers/net/a2065.c linux-2.4.26-m68k/drivers/net/a2065.c
--- linux-2.4.26/drivers/net/a2065.c	2003-06-14 00:51:34.000000000 +1000
+++ linux-2.4.26-m68k/drivers/net/a2065.c	2004-04-16 21:37:49.000000000 +1000
@@ -284,6 +284,7 @@
 	struct sk_buff *skb = 0;	/* XXX shut up gcc warnings */
 
 #ifdef TEST_HITS
+	int i;
 	printk ("[");
 	for (i = 0; i < RX_RING_SIZE; i++) {
 		if (i == lp->rx_new)
diff -Naur linux-2.4.26/drivers/net/macsonic.c linux-2.4.26-m68k/drivers/net/macsonic.c
--- linux-2.4.26/drivers/net/macsonic.c	2003-08-25 21:44:42.000000000 +1000
+++ linux-2.4.26-m68k/drivers/net/macsonic.c	2004-06-20 21:17:28.000000000 +1000
@@ -199,6 +199,7 @@
 	if ((lp->rba = (char *)
 	     kmalloc(SONIC_NUM_RRS * SONIC_RBSIZE, GFP_KERNEL | GFP_DMA)) == NULL) {
 		printk(KERN_ERR "%s: couldn't allocate receive buffers\n", dev->name);
+		kfree(lp);
 		return -ENOMEM;
 	}
 
@@ -635,19 +636,14 @@
 }
 
 #ifdef MODULE
-static char namespace[16] = "";
 static struct net_device dev_macsonic;
 
 MODULE_PARM(sonic_debug, "i");
 MODULE_PARM_DESC(sonic_debug, "macsonic debug level (1-4)");
-MODULE_LICENSE("GPL");
-
-EXPORT_NO_SYMBOLS;
 
 int
 init_module(void)
 {
-        dev_macsonic.name = namespace;
         dev_macsonic.init = macsonic_probe;
 
         if (register_netdev(&dev_macsonic) != 0) {
diff -Naur linux-2.4.26/drivers/net/teksonic.c linux-2.4.26-m68k/drivers/net/teksonic.c
--- linux-2.4.26/drivers/net/teksonic.c	1970-01-01 10:00:00.000000000 +1000
+++ linux-2.4.26-m68k/drivers/net/teksonic.c	2003-07-22 07:28:08.000000000 +1000
@@ -0,0 +1,310 @@
+/*
+ *  linux/drivers/net/teksonic.c
+ *
+ * (C) 2003 Michael Mueller <malware@t-online.de>
+ *
+ * based on the macsonic driver:
+ *
+ * (C) 1998 Alan Cox
+ *
+ * Debugging Andreas Ehliar, Michael Schmitz
+ *
+ * Based on code
+ * (C) 1996 by Thomas Bogendoerfer (tsbogend@bigbug.franken.de)
+ *
+ * This driver is based on work from Andreas Busse, but most of
+ * the code is rewritten.
+ *
+ * (C) 1995 by Andreas Busse (andy@waldorf-gmbh.de)
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/ctype.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/pgtable.h>
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/dma.h>
+
+#include <linux/errno.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/module.h>
+#include <asm/teknvram.h>
+
+/*
+ * All registers are located at addresses dividable by 4.
+ */
+
+#define SREGS_PAD(n)    u16 n;
+
+/*
+ * This is a hack to get the endianness stuff done correctly.
+ */
+
+#define CONFIG_MACSONIC
+
+/*
+ * Generic Sonic definitions
+ */
+#include "sonic.h"
+
+#ifdef DEBUG
+
+#define SONIC_READ(reg) _SONIC_READ(base_addr, reg)
+#define SONIC_WRITE(reg,val) do { _SONIC_WRITE(base_addr, reg, val); } while(0)
+
+static inline unsigned short _SONIC_READ(unsigned long base_addr, int reg)
+{
+	unsigned short val = *((volatile unsigned long*)(base_addr + 4*(reg))) & 0xffff;
+	printk("sonic_read(%08x) = %02x\n", base_addr + 4*(reg), val);
+	return val;
+}
+
+static inline void _SONIC_WRITE(unsigned long base_addr, int reg, unsigned short val)
+{
+	printk("sonic_write(%08x,%04x)\n", base_addr + 4*(reg), val);
+	*((volatile unsigned long*)(base_addr + 4*(reg))) = (val) & 0xffff;
+}
+
+static inline unsigned short sonic_read(struct net_device *dev, int reg)
+{
+        unsigned short val = *((volatile unsigned long*)(dev->base_addr + 4*(reg))) & 0xffff;
+        printk("sonic_read(%08x) = %02x\n", dev->base_addr + 4*(reg), val);
+	return val;
+}
+
+static inline void sonic_write(struct net_device *dev, int reg, unsigned short val)
+{
+        printk("sonic_write(%08x,%04x)\n", dev->base_addr + 4*(reg), val);
+        *((volatile unsigned long*)(dev->base_addr + 4*(reg))) = (val) & 0xffff;
+}
+
+#else
+
+#define SONIC_READ(reg) ((unsigned short)(*(volatile unsigned long *)((base_addr) + 4*(reg))) & 0xffff)
+
+#define SONIC_WRITE(reg, val) do { *(volatile unsigned long*)((base_addr) + 4*(reg)) = (val)& 0xffff; } while (0)
+
+#define sonic_read(dev,reg) ((unsigned short)(*(volatile unsigned long *)((dev)->base_addr + 4*(reg))) & 0xffff)
+
+#define sonic_write(dev, reg, val) do { *(volatile unsigned long*)((dev)->base_addr + 4*(reg)) = (val)& 0xffff; } while (0)
+
+#endif
+
+static int sonic_debug = 0;
+static int sonic_version_printed;
+
+static int reg_offset;
+
+int teksonic_init(struct net_device* dev)
+{
+	int i,j;
+	struct sonic_local* lp_alloc[20];
+	struct sonic_local* lp;
+
+        /* Allocate the entire chunk of memory for the descriptors.
+           Note that this cannot cross a 64K boundary. */
+        for (i = 0; i < 20; i++) {
+		unsigned long desc_base, desc_top, desc_top2;
+                if((lp_alloc[i] = kmalloc(sizeof(struct sonic_local), GFP_KERNEL)) == NULL) {
+                        printk(KERN_ERR "%s: couldn't allocate descriptor buffers\n", dev->name);
+                        return -ENOMEM;
+		}
+		desc_base = (unsigned long)virt_to_phys(lp_alloc[i]);
+		desc_top = desc_base + sizeof(struct sonic_local);
+		desc_top2 = (unsigned long)virt_to_phys(lp_alloc[i] + 1);
+
+		if ( (desc_top == desc_top2) && (desc_top & 0xffff) >= (desc_base & 0xffff))
+			break;
+
+		/* Hmm. try again (FIXME: does this actually work?) */
+		/* Note: It did not work when freeing the memory allocated
+		         previously since it got the same memory again. */
+/*              kfree(lp);	*/
+		printk(KERN_DEBUG
+		       "%s: didn't get continguous chunk [%08lx - %08lx], trying again\n",
+                       dev->name, desc_base, desc_top);
+
+        }
+
+	/* Deallocate what was allocated just to get the alignment done. */
+	for ( j = i-1; j >= 0; j-- )
+		kfree(lp_alloc[j]);
+
+        if (i==20) {
+		/* Note: Do not free dev->priv, it is deallocated later! */
+                printk(KERN_ERR "%s: tried 20 times to allocate descriptor buffers, giving up.\n",
+                       dev->name);
+                return -ENOMEM;
+        }
+
+	dev->priv = lp = lp_alloc[i];
+
+	memset(lp, 0, sizeof(struct sonic_local));
+
+	lp->cda_laddr = virt_to_phys(&(lp->cda));
+	lp->tda_laddr = virt_to_phys(lp->tda);
+	lp->rra_laddr = virt_to_phys(lp->rra);
+	lp->rda_laddr = virt_to_phys(lp->rda);
+
+        /* FIXME, maybe we should use skbs */
+	if ((lp->rba = (char *)kmalloc(SONIC_NUM_RRS * SONIC_RBSIZE, GFP_KERNEL)) == NULL) {
+		printk(KERN_ERR "%s: couldn't allocate receive buffers\n", dev->name);
+		return -ENOMEM;
+	}
+	lp->rba_laddr = virt_to_phys(lp->rba);
+
+#if 0
+	{
+		int rs, ds;
+
+		/* almost always 12*4096, but let's not take chances */
+		rs = ((SONIC_NUM_RRS * SONIC_RBSIZE + 4095) / 4096) * 4096;
+		/* almost always under a page, but let's not take chances */
+		ds = ((sizeof(struct sonic_local) + 4095) / 4096) * 4096;
+		kernel_set_cachemode(lp->rba, rs, IOMAP_NOCACHE_SER);
+		kernel_set_cachemode(lp, ds, IOMAP_NOCACHE_SER);
+	}
+#endif
+
+
+#if 0
+	flush_cache_all();
+#endif
+
+	dev->open = sonic_open;
+	dev->stop = sonic_close;
+	dev->hard_start_xmit = sonic_send_packet;
+	dev->get_stats = sonic_get_stats;
+	dev->set_multicast_list = &sonic_multicast_list;
+
+	/*
+	 * clear tally counter
+	 */
+	sonic_write(dev, SONIC_CRCT, 0xffff);
+	sonic_write(dev, SONIC_FAET, 0xffff);
+	sonic_write(dev, SONIC_MPT, 0xffff);
+
+	/* Fill in the fields of the device structure with ethernet values. */
+	ether_setup(dev);
+	return 0;
+}
+
+int teksonic_ethernet_addr(struct net_device* dev)
+{
+	int i;
+
+	/* On NuBus boards we can sometimes look in the ROM resources.
+	   No such luck for comm-slot/onboard. */
+	for(i = 0; i < 6; i++)
+		dev->dev_addr[i] = nvram_readb(NVRAM_SONIC_MAC+i);
+
+	return 0;
+}
+
+int teksonic_probe(struct net_device* dev)
+{
+	/* Bwahahaha */
+	static int once_is_more_than_enough;
+	int i;
+	int dma_bitmode;
+
+	if (once_is_more_than_enough)
+		return -ENODEV;
+	once_is_more_than_enough = 1;
+
+	if (dev) {
+		dev = init_etherdev(dev, sizeof(struct sonic_local));
+		if (!dev)
+			return -ENOMEM;
+	} else {
+		dev = init_etherdev(NULL, sizeof(struct sonic_local));
+	}
+	if (dev->priv != NULL) {
+		kfree(dev->priv);
+		dev->priv = NULL;
+	}
+
+	if (dev == NULL)
+		return -ENOMEM;
+
+	/* Danger!  My arms are flailing wildly!  You *must* set this
+           before using sonic_read() */
+
+	dev->base_addr = 0xFFC00000;	// FIXME: This does rely on transparent translation
+	dev->irq = IRQ6;
+
+	if (!sonic_version_printed) {
+		printk(KERN_INFO "%s", version);
+		sonic_version_printed = 1;
+	}
+	printk(KERN_INFO "%s: SONIC at 0x%08lx\n",
+	       dev->name, dev->base_addr);
+
+	reg_offset = 0;
+	dma_bitmode = 1;
+
+	/* Software reset, then initialize control registers. */
+	sonic_write(dev, SONIC_CMD, SONIC_CR_RST);
+
+	sonic_write(dev, SONIC_DCR, SONIC_DCR_BMS |
+		    SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | SONIC_DCR_EXBUS |
+		    (dma_bitmode ? SONIC_DCR_DW : 0));
+#if 0
+	sonic_write(dev, SONIC_DCR, 0x3F);
+#endif
+
+	/* This *must* be written back to in order to restore the
+           extended programmable output bits */
+	sonic_write(dev, SONIC_DCR2, 0);
+
+	sonic_write(dev, SONIC_CMD, 0);
+
+	/* Clear *and* disable interrupts to be on the safe side */
+	sonic_write(dev, SONIC_ISR,0x7fff);
+	sonic_write(dev, SONIC_IMR,0);
+
+	/* Now look for the MAC address. */
+	if (teksonic_ethernet_addr(dev) != 0)
+		return -ENODEV;
+
+	printk(KERN_INFO "MAC ");
+	for (i = 0; i < 6; i++) {
+		printk("%2.2x", dev->dev_addr[i]);
+		if (i < 5)
+			printk(":");
+	}
+
+	printk(" IRQ %d\n", dev->irq);
+
+	/* Shared init code */
+	return teksonic_init(dev);
+}
+
+
+#define vdma_alloc(foo, bar) ((u32)(foo))
+#define vdma_free(baz)
+#define sonic_chiptomem(bat) (phys_to_virt(bat))
+#define PHYSADDR(quux) (virt_to_phys((void*)(quux)))
+
+#define sonic_request_irq       request_irq
+#define sonic_free_irq          free_irq
+
+#include "sonic.c"
+
diff -Naur linux-2.4.26/drivers/sbus/char/sunkbd.c linux-2.4.26-m68k/drivers/sbus/char/sunkbd.c
--- linux-2.4.26/drivers/sbus/char/sunkbd.c	2002-08-03 10:39:44.000000000 +1000
+++ linux-2.4.26-m68k/drivers/sbus/char/sunkbd.c	2002-08-06 00:37:03.000000000 +1000
@@ -761,6 +761,7 @@
 
 static void boot_it(void)
 {
+#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X)
 	extern int obp_system_intr(void);
 
 	if (!obp_system_intr())
@@ -768,6 +769,7 @@
 	/* sigh.. attempt to prevent multiple entry */
 	last_keycode=1;
 	rep = 0;
+#endif
 }
 
 static void compose(void)
@@ -1232,7 +1234,7 @@
 
 int __init sun_kbd_init(void)
 {
-	int i, opt_node;
+	int i;
 	struct kbd_struct kbd0;
 	extern struct tty_driver console_driver;
 
@@ -1250,18 +1252,22 @@
 
 	kd_mksound = sunkbd_kd_mksound;
 
+#ifndef CONFIG_SUN3X_ZS
 	/* XXX Check keyboard-click? property in 'options' PROM node XXX */
 	if(sparc_cpu_model != sun4) {
-		opt_node = prom_getchild(prom_root_node);
+		int opt_node = prom_getchild(prom_root_node);
 		opt_node = prom_searchsiblings(opt_node, "options");
 		i = prom_getintdefault(opt_node, "keyboard-click?", -1);
 		if(i != -1)
 			sunkbd_clickp = 1;
 		else
 			sunkbd_clickp = 0;
-	} else {
+	} else
+#else
+	{
 		sunkbd_clickp = 0;
 	}
+#endif
 
 	keyboard_tasklet.func = sun_kbd_bh;
 
diff -Naur linux-2.4.26/drivers/sbus/char/sunserial.c linux-2.4.26-m68k/drivers/sbus/char/sunserial.c
--- linux-2.4.26/drivers/sbus/char/sunserial.c	2002-08-03 10:39:44.000000000 +1000
+++ linux-2.4.26-m68k/drivers/sbus/char/sunserial.c	2002-08-03 22:45:22.000000000 +1000
@@ -10,6 +10,13 @@
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/tty.h>
+
+#ifdef CONFIG_SUN3
+#include <linux/sched.h>
+#include <asm/ptrace.h>
+#include <linux/interrupt.h>
+#endif
+
 #include <linux/serial.h>
 #include <linux/serialP.h>
 #include <linux/string.h>
@@ -228,6 +235,7 @@
 void
 sunserial_console_termios(struct console *con)
 {
+#ifndef CONFIG_SUN3X_ZS
 	char mode[16], buf[16], *s;
 	char *mode_prop = "ttyX-mode";
 	char *cd_prop = "ttyX-ignore-cd";
@@ -331,6 +339,9 @@
 	}
 
 	con->cflag = cflag;
+#else /* CONFIG_SUN3 */
+	con->cflag = CREAD | HUPCL | CLOCAL | B9600 | CS8;
+#endif /* CONFIG_SUN3 */
 }
 
 void
@@ -452,6 +463,9 @@
 	}
 #endif
 
+#ifndef CONFIG_SUN3X_ZS
 	prom_printf("No serial devices found, bailing out.\n");
 	prom_halt();
+#endif
+	
 }
diff -Naur linux-2.4.26/drivers/sbus/char/zs.c linux-2.4.26-m68k/drivers/sbus/char/zs.c
--- linux-2.4.26/drivers/sbus/char/zs.c	2002-08-03 10:39:44.000000000 +1000
+++ linux-2.4.26-m68k/drivers/sbus/char/zs.c	2002-08-06 00:37:04.000000000 +1000
@@ -11,6 +11,8 @@
  * /proc/tty/driver/serial now exists and is readable.
  *   Alex Buell <alex.buell@tahallah.demon.co.uk>, 2001-12-23
  *
+ * Tweaks for sun3x by Oliver Jowett <oliver@jowett.manawatu.gen.nz>
+ *
  */
 
 #include <linux/errno.h>
@@ -39,23 +41,39 @@
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/bitops.h>
+
+#include <asm/sbus.h>
+#ifndef CONFIG_SUN3X_ZS
 #include <asm/kdebug.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 
-#include <asm/sbus.h>
 #ifdef __sparc_v9__
 #include <asm/fhc.h>
 #endif
 #ifdef CONFIG_PCI
 #include <linux/pci.h>
 #endif
+#else /* CONFIG_SUN3X_ZS */
+#include <linux/ioport.h>
+#ifndef CONFIG_SUN3X
+#include <asm/sun3mmu.h>
+#else
+#include <asm/sun3xprom.h>
+#endif
+#endif /* CONFIG_SUN3X_ZS */
 
 #include "sunserial.h"
 #include "zs.h"
 #include "sunkbd.h"
 #include "sunmouse.h"
 
+/* some sun3 boxen always use vectors */
+#ifdef CONFIG_SUN3
+#undef NV
+#define NV 0
+#endif
+
 static int num_serial = 2; /* sun4/sun4c/sun4m - Two chips on board. */
 #define NUM_SERIAL num_serial
 #define NUM_CHANNELS (NUM_SERIAL * 2)
@@ -425,6 +443,7 @@
  */
 void batten_down_hatches(void)
 {
+#ifndef CONFIG_SUN3X_ZS
 	if (!stop_a_enabled)
 		return;
 	/* If we are doing kadb, we call the debugger
@@ -448,6 +467,13 @@
 	 */
 
 	return;
+#else /* CONFIG_SUN3X_ZS */
+#ifndef CONFIG_SUN3X
+	prom_reboot("");
+#else
+	sun3x_reboot();
+#endif
+#endif /* CONFIG_SUN3X_ZS */
 }
 
 
@@ -550,7 +576,9 @@
 		 * arch/sparc/kernel/sparc-stub.c to see how all this works.
 		 */
 		if (info->kgdb_channel && (ch =='\003')) {
+#ifndef CONFIG_SUN3X_ZS
 			breakpoint();
+#endif
 			return;
 		}
 #endif
@@ -683,6 +711,23 @@
 	for (i = 0; i < NUM_SERIAL; i++) {
 		unsigned char r3 = read_zsreg(info->zs_channel, 3);
 
+		/* some sun3's need the pending flags cleared */
+#ifdef CONFIG_SUN3
+		unsigned char r2 = read_zsreg(info->zs_next->zs_channel, 2);
+		r2 &= STATUS_MASK;
+		if(r2 & 0x8) {
+			sbus_writeb(RES_H_IUS, &info->zs_channel->control);
+			ZSDELAY();
+			ZS_WSYNC(info->zs_channel);
+			ZSLOG(REGCTRL, RES_H_IUS, 1);
+		} else {
+			sbus_writeb(RES_H_IUS, &info->zs_next->zs_channel->control);
+			ZSDELAY();
+			ZS_WSYNC(info->zs_next->zs_channel);
+			ZSLOG(REGCTRL, RES_H_IUS, 1);
+		}
+#endif
+
 		/* Channel A -- /dev/ttya or /dev/kbd, could be the console */
 		if (r3 & (CHAEXT | CHATxIP | CHARxIP)) {
 			sbus_writeb(RES_H_IUS, &info->zs_channel->control);
@@ -1964,6 +2009,88 @@
 
 /* Finally, routines used to initialize the serial driver. */
 
+
+#ifdef CONFIG_SUN3X_ZS
+
+static void show_serial_version(void)
+{
+	char *revision = "$Revision: 1.5 $";
+	char *version, *p;
+
+	version = strchr(revision, ' ');
+	p = strchr(++version, ' ');
+	*p = '\0';
+	printk("sun3/3x Zilog8530 serial driver version %s\n", version);
+	*p = ' ';
+}
+
+static struct sun_zslayout * __init  
+	   get_zs(int chip)
+{
+	unsigned int vaddr = 0;
+	unsigned long iopte;
+	static int irq = 0;
+
+	if(chip < 0 || chip >= NUM_SERIAL)
+		panic("get_zs bogon zs chip number");
+
+#ifndef CONFIG_SUN3X 
+	/* sun3 OBIO version */
+        /* Grrr, these have to be hardcoded aieee */
+ 	switch(chip) {
+ 	case 0:
+ 		for(vaddr = 0xfe00000; vaddr < (0xfe00000 +
+						SUN3_PMEG_SIZE); vaddr += SUN3_PTE_SIZE) {
+			
+ 			iopte = sun3_get_pte(vaddr);
+ 			if(!(iopte & SUN3_PAGE_TYPE_IO)) /* this an io page? */
+ 				continue;
+ 			
+ 			if(((iopte & SUN3_PAGE_PGNUM_MASK) << PAGE_SHIFT) ==
+ 			   0x20000) {
+ 				break;
+ 			}
+ 		}
+ 		break;
+ 	case 1:
+ 		for(vaddr = 0xfe00000; vaddr < (0xfe00000 +
+ 						SUN3_PMEG_SIZE); vaddr += SUN3_PTE_SIZE) {
+  		  
+ 			iopte = sun3_get_pte(vaddr);
+ 			if(!(iopte & SUN3_PAGE_TYPE_IO)) /* this an io page? */
+ 				continue;
+  		  
+ 			if(((iopte & SUN3_PAGE_PGNUM_MASK) << PAGE_SHIFT) ==
+ 			   0) {
+ 				break;
+ 			}
+ 		}
+ 		break;
+ 	};
+#else
+	/* sun3x is a wee bit cleaner. :) */
+	switch(chip) {
+	case 0:
+		vaddr = SUN3X_ZS2;
+		break;
+
+	case 1:
+		vaddr = SUN3X_ZS1;
+		break;
+	}
+#endif	
+ 	
+ 	zs_nodes[chip] = 0;
+	zilog_irq = irq = 6;
+ 	
+ 	if(!vaddr)
+ 		panic("get_zs whee no serial chip mappable");
+ 	
+ 	return (struct sun_zslayout *)(unsigned long) vaddr;
+}
+ 
+#else /* !CONFIG_SUN3X_ZS */
+
 static void show_serial_version(void)
 {
 	char *revision = "$Revision: 1.68.2.2 $";
@@ -2224,6 +2351,9 @@
 	return (struct sun_zslayout *)(unsigned long) vaddr[0];
 }
 #endif
+
+#endif /* !CONFIG_SUN3X_ZS */
+        
 /* This is for the auto baud rate detection in the mouse driver. */
 void zs_change_mouse_baud(int newbaud)
 {
@@ -2292,6 +2422,8 @@
 
 int __init zs_probe(void)
 {
+#ifndef CONFIG_SUN3X_ZS
+
 	int node;
 
 	if(sparc_cpu_model == sun4)
@@ -2344,6 +2476,8 @@
 	NUM_SERIAL = 2;
 
 no_probe:
+#endif /* !CONFIG_SUN3X_ZS */
+
 	zs_alloc_tables();
 
 	/* Fill in rs_ops struct... */
@@ -2501,6 +2635,7 @@
 	/* Initialize Softinfo */
 	zs_prepare();
 
+#ifndef CONFIG_SUN3X_ZS
 	/* Grab IRQ line before poking the chips so we do
 	 * not lose any interrupts.
 	 */
@@ -2509,6 +2644,7 @@
 		prom_printf("Unable to attach zs intr\n");
 		prom_halt();
 	}
+#endif /* !CONFIG_SUN3X_ZS */
 
 	/* Initialize Hardware */
 	for(channel = 0; channel < NUM_CHANNELS; channel++) {
@@ -2517,6 +2653,10 @@
 			write_zsreg(zs_soft[channel].zs_channel, R9, FHWRES);
 			ZSDELAY_LONG();
 			dummy = read_zsreg(zs_soft[channel].zs_channel, R0);
+#ifdef CONFIG_SUN3
+			/* program the int vector */
+			write_zsreg(zs_soft[channel].zs_channel, R2, 0x18+zilog_irq);
+#endif
 		}
 
 		if(channel == KEYBOARD_LINE) {
@@ -2676,11 +2816,23 @@
 		info->normal_termios = serial_driver.init_termios;
 		init_waitqueue_head(&info->open_wait);
 		init_waitqueue_head(&info->close_wait);
+#ifdef CONFIG_SUN3X_ZS
+		printk("tty%02d at 0x%04x (irq = %d)", info->line, 
+		       info->port, info->irq);
+#else /* !CONFIG_SUN3X_ZS */
 		printk("tty%02d at 0x%04x (irq = %s)", info->line, 
 		       info->port, __irq_itoa(info->irq));
+#endif /* !CONFIG_SUN3X_ZS */
 		printk(" is a Zilog8530\n");
 	}
 
+#ifdef CONFIG_SUN3X_ZS
+	if (request_irq(zilog_irq, zs_interrupt,
+			(SA_INTERRUPT),
+			"Zilog8530", zs_chain))
+		panic("Unable to attach zs intr\n");
+#endif /* CONFIG_SUN3X_ZS */
+
 	restore_flags(flags);
 
 	keyboard_zsinit(kbd_put_char);
@@ -2881,10 +3033,15 @@
 {
 	extern int con_is_present(void);
 
+#ifndef CONFIG_SUN3X_ZS
 	if (con_is_present())
 		return 0;
 
 	zs_console.index = serial_console - 1;
+#else /* CONFIG_SUN3X_ZS */
+	zs_console.index = 0;
+#endif /* CONFIG_SUN3X_ZS */
+
 	register_console(&zs_console);
 	return 0;
 }
diff -Naur linux-2.4.26/drivers/scsi/NCR53C9x.c linux-2.4.26-m68k/drivers/scsi/NCR53C9x.c
--- linux-2.4.26/drivers/scsi/NCR53C9x.c	2002-11-29 10:53:14.000000000 +1100
+++ linux-2.4.26-m68k/drivers/scsi/NCR53C9x.c	2003-06-14 21:46:22.000000000 +1000
@@ -917,7 +917,7 @@
 		if (esp->dma_mmu_get_scsi_one)
 			esp->dma_mmu_get_scsi_one(esp, sp);
 		else
-			sp->SCp.have_data_in = (int) sp->SCp.ptr =
+			sp->SCp.ptr =
 				(char *) virt_to_phys(sp->request_buffer);
 	} else {
 		sp->SCp.buffer = (struct scatterlist *) sp->buffer;
diff -Naur linux-2.4.26/drivers/scsi/oktagon_esp.c linux-2.4.26-m68k/drivers/scsi/oktagon_esp.c
--- linux-2.4.26/drivers/scsi/oktagon_esp.c	2002-08-03 10:39:44.000000000 +1000
+++ linux-2.4.26-m68k/drivers/scsi/oktagon_esp.c	2003-06-14 21:46:22.000000000 +1000
@@ -548,7 +548,7 @@
 
 void dma_mmu_get_scsi_one(struct NCR_ESP *esp, Scsi_Cmnd *sp)
 {
-        sp->SCp.have_data_in = (int) sp->SCp.ptr =
+        sp->SCp.ptr =
                 sp->request_buffer;
 }
 
diff -Naur linux-2.4.26/drivers/video/Config.in linux-2.4.26-m68k/drivers/video/Config.in
--- linux-2.4.26/drivers/video/Config.in	2004-02-19 00:36:31.000000000 +1100
+++ linux-2.4.26-m68k/drivers/video/Config.in	2004-02-19 09:17:54.000000000 +1100
@@ -43,6 +43,9 @@
    if [ "$CONFIG_Q40" = "y" ]; then
       define_bool CONFIG_FB_Q40 y
    fi
+   if [ "$CONFIG_TEKXP" = "y" ]; then
+      define_bool CONFIG_FB_TEKXP y
+   fi
    if [ "$CONFIG_AMIGA" = "y" ]; then
       tristate '  Amiga native chipset support' CONFIG_FB_AMIGA
       if [ "$CONFIG_FB_AMIGA" != "n" ]; then
@@ -107,6 +110,7 @@
       bool '  Sun3 framebuffer support' CONFIG_FB_SUN3
       if [ "$CONFIG_FB_SUN3" != "n" ]; then
          bool '    BWtwo support' CONFIG_FB_BWTWO
+         bool '    CGthree support' CONFIG_FB_CGTHREE
          bool '    CGsix (GX,TurboGX) support' CONFIG_FB_CGSIX
       fi
    fi
@@ -265,7 +269,7 @@
 	   "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_RETINAZ3" = "y" -o \
 	   "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
 	   "$CONFIG_FB_BWTWO" = "y" -o "$CONFIG_FB_CLGEN" = "y"  -o \
-	   "$CONFIG_FB_TX3912" = "y" ]; then
+	   "$CONFIG_FB_TX3912" = "y" -o "$CONFIG_FB_TEKXP" = "y" ]; then
 	 define_tristate CONFIG_FBCON_MFB y
       else
 	 if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_AMIGA" = "m" -o \
@@ -281,12 +285,21 @@
 	   "$CONFIG_FB_SA1100" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
 	   "$CONFIG_FB_TX3912" = "y" ]; then
 	 define_tristate CONFIG_FBCON_CFB2 y
-	 define_tristate CONFIG_FBCON_CFB4 y
       else
-	 if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_MAC" = "m" -o \
+ 	 if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_MAC" = "m" -o \
 	      "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
 	      "$CONFIG_FB_TX3912" = "m" ]; then
 	    define_tristate CONFIG_FBCON_CFB2 m
+	 fi
+      fi
+      if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_MAC" = "y" -o \
+	   "$CONFIG_FB_SA1100" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
+	   "$CONFIG_FB_TX3912" = "y" -o "$CONFIG_FB_TEKXP" = "y" ]; then
+	 define_tristate CONFIG_FBCON_CFB4 y
+      else
+ 	 if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_MAC" = "m" -o \
+	      "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
+	      "$CONFIG_FB_TX3912" = "m" ]; then
 	    define_tristate CONFIG_FBCON_CFB4 m
 	 fi
       fi
@@ -312,7 +325,7 @@
 	   "$CONFIG_FB_TX3912" = "y" -o \
 	   "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_NEOMAGIC" = "y" -o \
 	   "$CONFIG_FB_STI" = "y" -o "$CONFIG_FB_HP300" = "y" -o \
-	   "$CONFIG_FB_INTEL" = "y" ]; then
+	   "$CONFIG_FB_INTEL" = "y" -o "$CONFIG_FB_TEKXP" = "y" ]; then
 	 define_tristate CONFIG_FBCON_CFB8 y
       else
 	 if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \
diff -Naur linux-2.4.26/drivers/video/Makefile linux-2.4.26-m68k/drivers/video/Makefile
--- linux-2.4.26/drivers/video/Makefile	2004-02-19 00:36:31.000000000 +1100
+++ linux-2.4.26-m68k/drivers/video/Makefile	2004-02-19 09:17:54.000000000 +1100
@@ -73,14 +73,22 @@
 obj-$(CONFIG_FB_VIRGE)            += virgefb.o
 obj-$(CONFIG_FB_G364)             += g364fb.o
 obj-$(CONFIG_FB_FM2)              += fm2fb.o
-obj-$(CONFIG_FB_CREATOR)          += creatorfb.o sbusfb.o
-obj-$(CONFIG_FB_CGSIX)            += cgsixfb.o sbusfb.o
-obj-$(CONFIG_FB_BWTWO)            += bwtwofb.o sbusfb.o
-obj-$(CONFIG_FB_CGTHREE)          += cgthreefb.o sbusfb.o
-obj-$(CONFIG_FB_TCX)              += tcxfb.o sbusfb.o
-obj-$(CONFIG_FB_CGFOURTEEN)       += cgfourteenfb.o sbusfb.o
-obj-$(CONFIG_FB_P9100)            += p9100fb.o sbusfb.o
-obj-$(CONFIG_FB_LEO)              += leofb.o sbusfb.o
+
+SBUSFB	=
+ifneq ($(CONFIG_SUN3),y)
+ifneq ($(CONFIG_SUN3X),y)
+    SBUSFB	= sbusfb.o
+endif
+endif
+
+obj-$(CONFIG_FB_CREATOR)          += creatorfb.o $(SBUSFB)
+obj-$(CONFIG_FB_CGSIX)            += cgsixfb.o $(SBUSFB)
+obj-$(CONFIG_FB_BWTWO)            += bwtwofb.o $(SBUSFB)
+obj-$(CONFIG_FB_CGTHREE)          += cgthreefb.o $(SBUSFB)
+obj-$(CONFIG_FB_TCX)              += tcxfb.o $(SBUSFB)
+obj-$(CONFIG_FB_CGFOURTEEN)       += cgfourteenfb.o $(SBUSFB)
+obj-$(CONFIG_FB_P9100)            += p9100fb.o $(SBUSFB)
+obj-$(CONFIG_FB_LEO)              += leofb.o $(SBUSFB)
 obj-$(CONFIG_FB_PMAG_AA)          += pmag-aa-fb.o
 obj-$(CONFIG_FB_PMAG_BA)          += pmag-ba-fb.o
 obj-$(CONFIG_FB_PMAGB_B)          += pmagb-b-fb.o
@@ -125,7 +133,6 @@
 endif
 
 obj-$(CONFIG_FB_SUN3)             += sun3fb.o
-obj-$(CONFIG_FB_BWTWO)            += bwtwofb.o
 obj-$(CONFIG_FB_HGA)              += hgafb.o  
 obj-$(CONFIG_FB_SA1100)           += sa1100fb.o
 obj-$(CONFIG_FB_VIRTUAL)          += vfb.o  
@@ -134,6 +141,7 @@
 obj-$(CONFIG_FB_E1356)            += epson1356fb.o
 obj-$(CONFIG_FB_PVR2)             += pvr2fb.o
 obj-$(CONFIG_FB_VOODOO1)          += sstfb.o
+obj-$(CONFIG_FB_TEKXP)            += tek_fb.o
 
 # Generic Low Level Drivers
 
diff -Naur linux-2.4.26/drivers/video/cgthreefb.c linux-2.4.26-m68k/drivers/video/cgthreefb.c
--- linux-2.4.26/drivers/video/cgthreefb.c	2001-09-21 07:11:58.000000000 +1000
+++ linux-2.4.26-m68k/drivers/video/cgthreefb.c	2001-10-22 19:34:33.000000000 +1000
@@ -178,13 +178,16 @@
 	struct display *disp = &fb->disp;
 	struct fbtype *type = &fb->type;
 	struct sbus_dev *sdev = fb->sbdp;
+#ifndef CONFIG_SUN3
 	unsigned long phys = sdev->reg_addrs[0].phys_addr;
 	int cgRDI = strstr(fb->sbdp->prom_name, "cgRDI") != NULL;
+#endif
 
 #ifndef FBCON_HAS_CFB8
 	return NULL;
 #endif
 
+#ifndef CONFIG_SUN3
 	if (!fb->s.cg3.regs) {
 		fb->s.cg3.regs = (struct cg3_regs *)
 			sbus_ioremap(&sdev->resource[0], CG3_REGS_OFFSET,
@@ -211,6 +214,9 @@
 			}
 		}
 	}
+#else
+	fb->s.cg3.regs = (struct cg3_regs *)0x0fe0e000;
+#endif
 
 	strcpy(fb->info.modename, "CGthree");
 	strcpy(fix->id, "CGthree");
@@ -218,12 +224,19 @@
 	fix->accel = FB_ACCEL_SUN_CGTHREE;
 	
 	disp->scrollmode = SCROLL_YREDRAW;
+#ifndef CONFIG_SUN3
 	if (!disp->screen_base) {
 		disp->screen_base = (char *)
 			sbus_ioremap(&sdev->resource[0], CG3_RAM_OFFSET,
 				     type->fb_size, "cg3 ram");
 	}
-	disp->screen_base += fix->line_length * fb->y_margin + fb->x_margin;
+	fb->physbase = phys;
+#else
+	disp->screen_base = (char *)0x0fd00000;
+	fb->physbase = (unsigned long)0x0fd00000;
+#endif
+
+//	disp->screen_base += fix->line_length * fb->y_margin + fb->x_margin;
 	fb->dispsw = fbcon_cfb8;
 
 	fb->margins = cg3_margins;
@@ -231,9 +244,9 @@
 	fb->blank = cg3_blank;
 	fb->unblank = cg3_unblank;
 	
-	fb->physbase = phys;
 	fb->mmap_map = cg3_mmap_map;
-	
+
+#ifndef CONFIG_SUN3	
 #ifdef __sparc_v9__	
 	sprintf(idstring, "%s at %016lx", cgRDI ? "cgRDI" : "cgthree", phys);
 #else
@@ -279,6 +292,22 @@
 			sbus_writeb(p[1], regp);
 		}
 	}
+#else
+	sprintf(idstring, "%s: mem %x regs %x", "cgthree", fb->physbase, fb->s.cg3.regs);
+
+	/* kick up the sun3 -- 66hz prom mode only */
+	/* this also turns off the overlay in case it's really a cg4 */
+	
+	fb->s.cg3.regs->cmap.addr = 4;
+	fb->s.cg3.regs->cmap.control = 0xff; 
+	fb->s.cg3.regs->cmap.addr = 5;
+	fb->s.cg3.regs->cmap.control = 0;
+	fb->s.cg3.regs->cmap.addr = 6;
+	fb->s.cg3.regs->cmap.control = 0x40; 
+	fb->s.cg3.regs->cmap.addr = 7;
+	fb->s.cg3.regs->cmap.control = 0;
+
+#endif
 
 	return idstring;
 }
diff -Naur linux-2.4.26/drivers/video/fbcon.c linux-2.4.26-m68k/drivers/video/fbcon.c
--- linux-2.4.26/drivers/video/fbcon.c	2003-08-25 21:44:42.000000000 +1000
+++ linux-2.4.26-m68k/drivers/video/fbcon.c	2003-08-26 13:13:09.000000000 +1000
@@ -2340,6 +2340,27 @@
 	    done = 1;
 	}
 #endif
+#ifdef CONFIG_HP300
+    if (depth == 6 && p->type == FB_TYPE_PACKED_PIXELS) {
+	/* depth 6 or more, packed, with color registers */
+		
+	src = logo;
+	for( y1 = 0; y1 < LOGO_H; y1++ ) {
+	    int c;
+	    dst = fb + y1*line;
+	    for( x1 = 0; x1 < LOGO_W / 2; x1++ ) {
+		fb_writeb((*src >> 4) + 16, dst++);
+		fb_writeb(((*src++) & 0xf) + 16, dst++);
+	    }
+	    dst += 8;
+	    for (c = 0; c < 32; c++)
+	      for (x1 = 0; x1 < 24; x1++)
+		*dst++ = c;
+	}
+
+	done = 1;
+    }
+#endif /* CONFIG_HP300 */
 #if defined(CONFIG_FBCON_AFB) || defined(CONFIG_FBCON_ILBM) || \
     defined(CONFIG_FBCON_IPLAN2P2) || defined(CONFIG_FBCON_IPLAN2P4) || \
     defined(CONFIG_FBCON_IPLAN2P8)
@@ -2412,8 +2433,22 @@
 		    dst = fb + (y1%4)*8192 + (y1>>2)*line + x/8;
 		else
 		    dst = fb + y1*line + x/8;
-		for( x1 = 0; x1 < LOGO_LINE; ++x1 )
+		for( x1 = 0; x1 < LOGO_LINE; ++x1 ) {
+#ifndef CONFIG_HP300
 		    fb_writeb(*src++ ^ inverse, dst++);
+#else /* CONFIG_HP300 */
+		    /* hack hack -- make it work with topcat in pseudomono mode */
+		    char c = *src++ ^ inverse;
+		    fb_writeb((c >> 7) & 1, dst++);
+		    fb_writeb((c >> 6) & 1, dst++);
+		    fb_writeb((c >> 5) & 1, dst++);
+		    fb_writeb((c >> 4) & 1, dst++);
+		    fb_writeb((c >> 3) & 1, dst++);
+		    fb_writeb((c >> 2) & 1, dst++);
+		    fb_writeb((c >> 1) & 1, dst++);
+		    fb_writeb((c >> 0) & 1, dst++);
+#endif /* CONFIG_HP300 */
+		}
 	    }
 	    done = 1;
 	}
diff -Naur linux-2.4.26/drivers/video/fbmem.c linux-2.4.26-m68k/drivers/video/fbmem.c
--- linux-2.4.26/drivers/video/fbmem.c	2004-02-19 00:36:31.000000000 +1100
+++ linux-2.4.26-m68k/drivers/video/fbmem.c	2004-02-19 09:17:54.000000000 +1100
@@ -53,6 +53,7 @@
 extern int amifb_setup(char*);
 extern int atafb_init(void);
 extern int atafb_setup(char*);
+extern int tekfb_init(void);
 extern int macfb_init(void);
 extern int macfb_setup(char*);
 extern int cyberfb_init(void);
@@ -271,6 +272,9 @@
 #ifdef CONFIG_FB_ATARI
 	{ "atafb", atafb_init, atafb_setup },
 #endif
+#ifdef CONFIG_FB_TEKXP
+	{ "tekfb", tekfb_init, NULL },
+#endif
 #ifdef CONFIG_FB_MAC
 	{ "macfb", macfb_init, macfb_setup },
 #endif
@@ -964,9 +968,9 @@
 					    fb_drivers[i].init;
 				    fb_drivers[i].init = NULL;
 			    }
-			    if (fb_drivers[i].setup)
-				    fb_drivers[i].setup(options+j+1);
 		    }
+		    if (fb_drivers[i].setup)
+			    fb_drivers[i].setup(options+j+1);
 		    return 0;
 	    }
     }
diff -Naur linux-2.4.26/drivers/video/sun3fb.c linux-2.4.26-m68k/drivers/video/sun3fb.c
--- linux-2.4.26/drivers/video/sun3fb.c	2001-10-01 05:26:08.000000000 +1000
+++ linux-2.4.26-m68k/drivers/video/sun3fb.c	2003-06-14 21:44:17.000000000 +1000
@@ -48,6 +48,8 @@
 
 #ifdef CONFIG_SUN3
 #include <asm/oplib.h>
+#include <asm/machines.h>
+#include <asm/idprom.h>
 #endif
 #ifdef CONFIG_SUN3X
 #include <asm/sun3x.h>
@@ -59,12 +61,14 @@
 #define CURSOR_SHAPE			1
 #define CURSOR_BLINK			2
 
+#define mymemset(x,y) memset(x,0,y)
+
     /*
      *  Interface used by the world
      */
 
 int sun3fb_init(void);
-int sun3fb_setup(char *options);
+void sun3fb_setup(char *options);
 
 static int currcon;
 static char fontname[40] __initdata = { 0 };
@@ -115,6 +119,8 @@
 static void sun3fb_clear_margin(struct display *p, int s)
 {
 	struct fb_info_sbusfb *fb = sbusfbinfod(p);
+	
+	return;
 
 	if (fb->switch_from_graph)
 		(*fb->switch_from_graph)(fb);
@@ -354,7 +360,7 @@
 		p++;
 	}
 
-	return 0;
+	return;
 }
 
 static int sun3fbcon_switch(int con, struct fb_info *info)
@@ -523,7 +529,7 @@
      */
 static int __init sun3fb_init_fb(int fbtype, unsigned long addr)
 {
-	static struct linux_sbus_device sdb;
+	static struct sbus_dev sdb;
 	struct fb_fix_screeninfo *fix;
 	struct fb_var_screeninfo *var;
 	struct display *disp;
@@ -531,7 +537,7 @@
 	struct fbtype *type;
 	int linebytes, w, h, depth;
 	char *p = NULL;
-
+	
 	fb = kmalloc(sizeof(struct fb_info_sbusfb), GFP_ATOMIC);
 	if (!fb)
 		return -ENOMEM;
@@ -600,8 +606,13 @@
 	case FBTYPE_SUN2BW:
 		p = bwtwofb_init(fb); break;
 #endif
+#ifdef CONFIG_FB_CGTHREE
+	case FBTYPE_SUN4COLOR:
+	case FBTYPE_SUN3COLOR:
+		p = cgthreefb_init(fb); break;
+#endif
 	}
-	fix->smem_start = fb->disp.screen_base;
+	fix->smem_start = (unsigned long)fb->disp.screen_base;
 	
 	if (!p) {
 		kfree(fb);
@@ -656,17 +667,25 @@
 	unsigned long addr;
 	char p4id;
 	
-	if (!con_is_present()) return;
-	printk("sun3fb_init()\n");
+	if (!con_is_present()) return -ENXIO;
 #ifdef CONFIG_SUN3
-	addr = 0xfe20000;
         switch(*(romvec->pv_fbtype))
         {
-		case FBTYPE_SUN2BW:
-			return sun3fb_init_fb(FBTYPE_SUN2BW, addr);
-		case FBTYPE_SUN3COLOR:
-			printk("cg3 detected but not supported\n");
-			return -EINVAL;
+	case FBTYPE_SUN2BW:
+		addr = 0xfe20000;
+		return sun3fb_init_fb(FBTYPE_SUN2BW, addr);
+	case FBTYPE_SUN3COLOR:
+	case FBTYPE_SUN4COLOR:
+		if(idprom->id_machtype != (SM_SUN3|SM_3_60)) {
+			printk("sun3fb: cgthree/four only supported on 3/60\n");
+			return -ENODEV;
+		}
+		
+		addr = 0xfd00000;
+		return sun3fb_init_fb(*(romvec->pv_fbtype), addr);
+	default:
+		printk("sun3fb: unsupported framebuffer\n");
+		return -ENODEV;
 	}
 #else
 	addr = SUN3X_VIDEO_BASE;
diff -Naur linux-2.4.26/drivers/video/tek_fb.c linux-2.4.26-m68k/drivers/video/tek_fb.c
--- linux-2.4.26/drivers/video/tek_fb.c	1970-01-01 10:00:00.000000000 +1000
+++ linux-2.4.26-m68k/drivers/video/tek_fb.c	2003-07-22 07:31:52.000000000 +1000
@@ -0,0 +1,442 @@
+/*
+ *   linux/drivers/video/tek_fb.c
+ *
+ *   Copyright (C) 2002,2003 Michael Mueller <malware@t-online.de>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ *
+ *
+ * It is basicly a hack to get the console working. So if someone feels
+ * familiar with the framebuffer API a rework would be welcome.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+
+#include <linux/fb.h>
+
+#include <video/fbcon.h>
+#ifdef CONFIG_FBCON_CFB8
+#include <video/fbcon-cfb8.h>
+#endif
+#ifdef CONFIG_FBCON_CFB4
+#include <video/fbcon-cfb4.h>
+#endif
+#ifdef CONFIG_FBCON_MFB
+#include <video/fbcon-mfb.h>
+#endif
+
+#include <asm/setup.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/irq.h>
+
+#include <asm/teknvram.h>
+
+#define MAX_TEKFB_SIZE	(1280*1024+0x100)
+#define TEKFP_BASE	(0xDE000000UL)
+
+struct tekfb_priv {
+	u_char*		frameptr;
+	int		display_type;
+	int		display_height;
+	int		display_width;
+	int		display_coldepth;
+	int		display_fps;
+
+	u_char *	ptr;
+	u_char *	ptr_ramdac;
+	int		ramdac_type;
+	u_char *	ramdac_regs[5];
+};
+
+#define arraysize(x) (sizeof (x)/sizeof (x)[0])
+
+   /*
+    *    Interface used by the world
+    */
+
+void tekxp_video_setup(char *options, int *ints)
+{
+	// There is nothing we can do currently
+}
+
+   /*
+    *    Interface to the low level console driver
+    */
+
+static struct fb_info fb_info;
+//static int tekfb_switch(int con, struct fb_info *);
+static int tekfb_update_var(int con, struct fb_info *);
+static void tekfb_blank(int, struct fb_info *);
+
+static int tekfb_get_fix(struct fb_fix_screeninfo *, int, struct fb_info *);
+static int tekfb_get_var(struct fb_var_screeninfo *, int, struct fb_info *);
+static int tekfb_set_var(struct fb_var_screeninfo *, int, struct fb_info *);
+static int tekfb_get_cmap(struct fb_cmap *, int, int, struct fb_info *);
+static int tekfb_set_cmap(struct fb_cmap *, int, int, struct fb_info *);
+
+static struct fb_ops tekfb_ops = {
+	fb_get_fix: tekfb_get_fix,
+	fb_get_var: tekfb_get_var,
+	fb_set_var: tekfb_set_var,
+	fb_get_cmap: tekfb_get_cmap,
+	fb_set_cmap: tekfb_set_cmap,
+};
+
+static struct display disp;
+
+//static struct fb_var_screeninfo tekfb_predefined;
+
+struct fb_var_screeninfo tekfb_fixed =
+{
+	xres: 1152, yres: 900,	/* visible resolution */
+	xres_virtual: 1152, yres_virtual: 900,	/* virtual resolution */
+	xoffset: 0, yoffset: 0,		/* offset of visible within virtual */
+	bits_per_pixel: 8,		/* bits per pixel */
+	grayscale: 0,		/* grayscale */
+	red: {0, 6, 0},	/* red */
+	green: {0, 6, 0},	/* green */
+	blue: {0, 6, 0},	/* blue */
+	transp: {0, 0, 0},	/* transp */
+	nonstd: 0,		/* no non-standard pixel format */
+	activate: 0,		/* activate */
+	height: -1,		/* height in mm */
+	width: -1,		/* width in mm */
+	accel_flags: FB_ACCEL_NONE,	/* accel */
+};
+
+static const char* ramdac_names[4] = { "???", "???", "Bt459", "???" };
+
+static int get_private(struct tekfb_priv *priv)
+{
+	priv->ptr = ioremap_writethrough(0xD8200000, 0x100);
+	priv->ptr_ramdac = ioremap_writethrough(0xD8100000, 0x100);
+	if ( !priv->ptr || !priv->ptr_ramdac )
+	{
+		printk("tek_fb: Could not map ramdac into kernel memory space\n");
+		return -ENOMEM;
+	}
+
+	/*
+	 * Maybe sometime I will understand how a bit field is organized.
+	 * Meanwhile this assembler stuff will do the trick.
+	 */
+	__asm__("bfextu %1{#6:#2}, %0\n"
+	        : "=r" (priv->ramdac_type)
+	        : "m" (*(priv->ptr + 1)) );
+	printk("tek_fb: RAMDAC: %d (%s)\n",
+	       priv->ramdac_type, ramdac_names[priv->ramdac_type]);
+
+	if ( priv->ramdac_type & 1 )
+	{
+		priv->ramdac_regs[0] = priv->ptr_ramdac + 0;
+		priv->ramdac_regs[1] = priv->ptr_ramdac + 4;
+		priv->ramdac_regs[2] = priv->ptr_ramdac + 8;
+		priv->ramdac_regs[3] = priv->ptr_ramdac + 12;
+		priv->ramdac_regs[4] = NULL;
+	}
+	else
+	{
+		priv->ramdac_regs[0] = priv->ptr_ramdac + 0;
+		priv->ramdac_regs[1] = NULL;
+		priv->ramdac_regs[2] = priv->ptr_ramdac + 8;
+		priv->ramdac_regs[3] = priv->ptr_ramdac + 4;
+		priv->ramdac_regs[4] = priv->ptr_ramdac + 12;
+	}
+
+	priv->display_type = nvram_readw(NVRAM_DISPLAY);
+	switch ( priv->display_type )
+	{
+		case 0:
+			priv->display_width = 1280;
+			priv->display_height = 1024;
+			priv->display_coldepth = 4;
+			priv->display_fps = 72;
+			break;
+		case 1:
+			priv->display_width = 1152;
+			priv->display_height = 900;
+			priv->display_coldepth = 8;
+			priv->display_fps = 60;
+			break;
+		case 3:
+			priv->display_width = 1280;
+			priv->display_height = 1024;
+			priv->display_coldepth = 8;
+			priv->display_fps = 72;
+			break;
+		case 4:
+			priv->display_width = 1024;
+			priv->display_height = 768;
+			priv->display_coldepth = 8;
+			priv->display_fps = 70;
+			break;
+		case 5:
+			priv->display_width = 1024;
+			priv->display_height = 768;
+			priv->display_coldepth = 8;
+			priv->display_fps = 60;
+			break;
+		case 6:	// note: it is not really the same as above
+			priv->display_width = 1024;
+			priv->display_height = 768;
+			priv->display_coldepth = 8;
+			priv->display_fps = 60;
+			break;
+		case 7:
+			priv->display_width = 1152;
+			priv->display_height = 900;
+			priv->display_coldepth = 1;
+			priv->display_fps = 72;
+			break;
+		case 8:
+			priv->display_width = 1280;
+			priv->display_height = 1024;
+			priv->display_coldepth = 1;
+			priv->display_fps = 72;
+			break;
+		case 9:
+			priv->display_width = 1280;
+			priv->display_height = 864;
+			priv->display_coldepth = 8;
+			priv->display_fps = 60;
+			break;
+		default:
+			priv->display_width = 1152;
+			priv->display_height = 900;
+			priv->display_coldepth = 8;
+			priv->display_fps = 72;
+	}
+	printk("tek_fb: display type: %d (%dx%dx%d@%d)\n",
+	       priv->display_type, priv->display_width,
+	       priv->display_height, priv->display_coldepth,
+	       priv->display_fps);
+
+	return 0;
+}
+
+static inline void set_ramdac_addr(struct tekfb_priv *priv, int addr)
+{
+	*(volatile int *)(priv->ramdac_regs[0]) = addr;
+	if ( priv->ramdac_type & 1 )
+		*(volatile int *)(priv->ramdac_regs[1]) = (addr >> 8) & 0xff;
+}
+
+static inline unsigned long get_fb_size(struct tekfb_priv *priv)
+{
+	return (priv->display_width * priv->display_height * priv->display_coldepth) / 8;
+}
+
+int __devinit tekfb_init(void)
+{
+	int err;
+	struct tekfb_priv *priv = kmalloc(sizeof (*priv), GFP_KERNEL);
+	if ( !priv )
+	{
+		printk(KERN_ERR "tek_fb: Could not allocate memory for private device data\n");
+		return -ENOMEM;
+	}
+	memset(priv, 0, sizeof (*priv));
+
+	priv->frameptr = (u_char*)ioremap_writethrough(TEKFP_BASE, MAX_TEKFB_SIZE);
+	if ( !priv->frameptr )
+	{
+		printk(KERN_ERR "tek_fb: Frame buffer did not map into kernel memory space\n");
+		return -ENOMEM;
+	}
+
+	err = get_private(priv);
+	if ( err < 0 )
+		return err;
+
+	strcpy(fb_info.modename, "TekXpress");
+	fb_info.changevar = NULL;
+	fb_info.node = -1;
+	fb_info.fbops = &tekfb_ops;
+	fb_info.disp = &disp;
+//	fb_info.switch_con = tekfb_switch;
+	fb_info.switch_con = NULL;
+        fb_info.updatevar=tekfb_update_var;
+        fb_info.blank=&tekfb_blank;
+	fb_info.flags = FBINFO_FLAG_DEFAULT;
+	fb_info.fontname[0] = 0;
+	fb_info.par = priv;
+	if ( fb_alloc_cmap(&fb_info.cmap, 1 << 8, 0) < 0 )
+	{
+		printk("tek_fb: Could not allocate color map\n");
+		return -ENOMEM;
+	}
+
+	tekfb_get_var(&disp.var, 0, &fb_info);
+	disp.screen_base = priv->frameptr + 0x100;
+	disp.type = FB_TYPE_PACKED_PIXELS;
+	disp.line_length = 0;
+	disp.can_soft_blank = 0;
+	disp.inverse = 0;
+	disp.ypanstep = 0;
+	disp.ywrapstep = 0;
+	switch ( priv->display_coldepth )
+	{
+#ifdef CONFIG_FBCON_CFB8
+	case 8:
+		disp.visual = FB_VISUAL_PSEUDOCOLOR;
+		disp.dispsw = &fbcon_cfb8;
+		break;
+#endif
+#ifdef CONFIG_FBCON_CFB4
+	case 4:
+		disp.visual = FB_VISUAL_PSEUDOCOLOR;
+		disp.dispsw = &fbcon_cfb4;
+		break;
+#endif
+#ifdef CONFIG_FBCON_MFB
+	case 1:
+		disp.visual = FB_VISUAL_MONO10;
+		disp.dispsw = &fbcon_mfb;
+		break;
+#endif
+	default:
+		panic("tek_fb: unknown/unsupported color depth %d", priv->display_coldepth);
+	}
+
+	memset(priv->frameptr + 0x100, 0, get_fb_size(priv));
+
+	return register_framebuffer(&fb_info);
+}
+
+/*
+static int tekfb_switch(int con, struct fb_info *info)
+{
+	return 0;
+}
+*/
+
+static int tekfb_update_var(int con, struct fb_info *info)
+{
+	return 0;
+}
+
+static void tekfb_blank(int m, struct fb_info *info)
+{
+}
+
+static int tekfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
+{
+	int i;
+	struct tekfb_priv *priv = info->par;
+
+	strcpy(fix->id, "TekXpress");
+	fix->smem_start = (unsigned long)priv->frameptr + 0x100;
+	fix->smem_len	= MAX_TEKFB_SIZE - 0x100;
+	fix->type	= FB_TYPE_PACKED_PIXELS;
+	switch ( priv->display_coldepth )
+	{
+	case 8:
+	case 4:
+		fix->visual = FB_VISUAL_PSEUDOCOLOR;
+		break;
+	case 1:
+		fix->visual = FB_VISUAL_MONO10;
+		break;
+	default:
+		panic("tek_fb: unknown color depth");
+	}
+	fix->xpanstep = 0;
+        fix->ypanstep = 0;
+        fix->ywrapstep = 0;
+        fix->line_length = 0;
+        for (i=0; i<arraysize(fix->reserved); i++)
+                fix->reserved[i]=0;
+        return 0;
+
+}
+
+static int tekfb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
+{
+	struct tekfb_priv *priv = info->par;
+
+	*var = tekfb_fixed;
+
+	var->xres_virtual = var->xres = priv->display_width;
+	var->yres_virtual = var->yres = priv->display_height;
+	var->xoffset = var->yoffset = 0;
+	var->bits_per_pixel = priv->display_coldepth;
+
+	return 0;
+}
+
+static int tekfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
+{
+	return 0;
+}
+
+static int tekfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
+{
+	struct tekfb_priv *priv = info->par;
+	int iCol;
+
+	set_ramdac_addr(priv, info->cmap.start);
+	for ( iCol=0; iCol < info->cmap.len; iCol++ )
+	{
+		unsigned long r,g,b;
+
+		r = *(volatile u_long *)(priv->ramdac_regs[3]);
+		if ( priv->ramdac_type )
+		{
+			g = *(volatile u_long *)(priv->ramdac_regs[3]);
+			b = *(volatile u_long *)(priv->ramdac_regs[3]);
+		}
+		else
+			b = g = r;
+
+		info->cmap.red[iCol] = r;
+		info->cmap.green[iCol] = g;
+		info->cmap.blue[iCol] = b;
+	}
+
+	fb_copy_cmap(&info->cmap, cmap, kspc ? 0 : 2);
+
+	return 0;
+}
+
+static int tekfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
+{
+	struct tekfb_priv *priv = info->par;
+	if ( priv )
+	{
+		int iCol;
+
+		fb_copy_cmap(cmap, &info->cmap, kspc ? 0 : 1);
+
+		set_ramdac_addr(priv, info->cmap.start);
+		for ( iCol = 0; iCol < info->cmap.len; iCol++ )
+		{
+			int r = info->cmap.red[iCol];
+			int g = info->cmap.green[iCol];
+			int b = info->cmap.blue[iCol];
+
+			if ( !priv->ramdac_type )
+				r = g = b = (38 * r + 90 * g + 128 * b) / 256;
+
+			*(volatile u_long *)(priv->ramdac_regs[3]) = r;
+			if ( priv->ramdac_type )
+			{
+				*(volatile u_long *)(priv->ramdac_regs[3]) = g;
+				*(volatile u_long *)(priv->ramdac_regs[3]) = b;
+			}
+
+		}
+	}
+	return 0;
+}
+
diff -Naur linux-2.4.26/fs/Config.in linux-2.4.26-m68k/fs/Config.in
--- linux-2.4.26/fs/Config.in	2004-02-19 00:36:31.000000000 +1100
+++ linux-2.4.26-m68k/fs/Config.in	2004-02-19 09:18:00.000000000 +1100
@@ -19,6 +19,8 @@
 
 dep_tristate 'Amiga FFS file system support (EXPERIMENTAL)' CONFIG_AFFS_FS $CONFIG_EXPERIMENTAL
 
+dep_tristate 'Amiga SFS file system support (read-only) (EXPERIMENTAL)' CONFIG_ASFS_FS $CONFIG_EXPERIMENTAL
+
 dep_tristate 'Apple HFS file system support (EXPERIMENTAL)' CONFIG_HFS_FS $CONFIG_EXPERIMENTAL
 
 dep_tristate 'Apple HFS+ (Extended HFS) file system support (EXPERIMENTAL)' CONFIG_HFSPLUS_FS $CONFIG_EXPERIMENTAL
diff -Naur linux-2.4.26/fs/Makefile linux-2.4.26-m68k/fs/Makefile
--- linux-2.4.26/fs/Makefile	2004-02-19 00:36:31.000000000 +1100
+++ linux-2.4.26-m68k/fs/Makefile	2004-02-19 09:18:00.000000000 +1100
@@ -55,6 +55,7 @@
 subdir-$(CONFIG_JFFS_FS)	+= jffs
 subdir-$(CONFIG_JFFS2_FS)	+= jffs2
 subdir-$(CONFIG_AFFS_FS)	+= affs
+subdir-$(CONFIG_ASFS_FS)	+= asfs
 subdir-$(CONFIG_ROMFS_FS)	+= romfs
 subdir-$(CONFIG_QNX4FS_FS)	+= qnx4
 subdir-$(CONFIG_UDF_FS)		+= udf
diff -Naur linux-2.4.26/fs/affs/amigaffs.c linux-2.4.26-m68k/fs/affs/amigaffs.c
--- linux-2.4.26/fs/affs/amigaffs.c	2001-09-12 01:19:35.000000000 +1000
+++ linux-2.4.26-m68k/fs/affs/amigaffs.c	2004-06-11 07:01:42.000000000 +1000
@@ -458,7 +458,6 @@
 	if (!(sb->s_flags & MS_RDONLY))
 		printk(KERN_WARNING "AFFS: Remounting filesystem read-only\n");
 	sb->s_flags |= MS_RDONLY;
-	AFFS_SB->s_flags |= SF_READONLY;	/* Don't allow to remount rw */
 }
 
 void
diff -Naur linux-2.4.26/fs/affs/bitmap.c linux-2.4.26-m68k/fs/affs/bitmap.c
--- linux-2.4.26/fs/affs/bitmap.c	2002-02-26 06:38:07.000000000 +1100
+++ linux-2.4.26-m68k/fs/affs/bitmap.c	2004-06-11 07:01:42.000000000 +1000
@@ -268,8 +268,7 @@
 	return 0;
 }
 
-int
-affs_init_bitmap(struct super_block *sb)
+int affs_init_bitmap(struct super_block *sb, int *flags)
 {
 	struct affs_bm_info *bm;
 	struct buffer_head *bmap_bh = NULL, *bh = NULL;
@@ -277,13 +276,13 @@
 	u32 size, blk, end, offset, mask;
 	int i, res = 0;
 
-	if (sb->s_flags & MS_RDONLY)
+	if (*flags & MS_RDONLY)
 		return 0;
 
 	if (!AFFS_ROOT_TAIL(sb, AFFS_SB->s_root_bh)->bm_flag) {
 		printk(KERN_NOTICE "AFFS: Bitmap invalid - mounting %s read only\n",
 			kdevname(sb->s_dev));
-		sb->s_flags |= MS_RDONLY;
+		*flags |= MS_RDONLY;
 		return 0;
 	}
 
@@ -296,7 +295,7 @@
 	bm = AFFS_SB->s_bitmap = kmalloc(size, GFP_KERNEL);
 	if (!AFFS_SB->s_bitmap) {
 		printk(KERN_ERR "AFFS: Bitmap allocation failed\n");
-		return 1;
+		return -ENOMEM;
 	}
 	memset(AFFS_SB->s_bitmap, 0, size);
 
@@ -311,13 +310,13 @@
 		bh = affs_bread(sb, bm->bm_key);
 		if (!bh) {
 			printk(KERN_ERR "AFFS: Cannot read bitmap\n");
-			res = 1;
+			res = -EIO;
 			goto out;
 		}
 		if (affs_checksum_block(sb, bh)) {
 			printk(KERN_WARNING "AFFS: Bitmap %u invalid - mounting %s read only.\n",
 			       bm->bm_key, kdevname(sb->s_dev));
-			sb->s_flags |= MS_RDONLY;
+			*flags |= MS_RDONLY;
 			goto out;
 		}
 		pr_debug("AFFS: read bitmap block %d: %d\n", blk, bm->bm_key);
@@ -333,7 +332,7 @@
 		bmap_bh = affs_bread(sb, be32_to_cpu(bmap_blk[blk]));
 		if (!bmap_bh) {
 			printk(KERN_ERR "AFFS: Cannot read bitmap extension\n");
-			res = 1;
+			res = -EIO;
 			goto out;
 		}
 		bmap_blk = (u32 *)bmap_bh->b_data;
@@ -378,3 +377,15 @@
 	affs_brelse(bmap_bh);
 	return res;
 }
+
+void affs_free_bitmap(struct super_block *sb)
+{
+	if (!AFFS_SB->s_bitmap)
+		return;
+
+	affs_brelse(AFFS_SB->s_bmap_bh);
+	AFFS_SB->s_bmap_bh = NULL;
+	AFFS_SB->s_last_bmap = ~0;
+	kfree(AFFS_SB->s_bitmap);
+	AFFS_SB->s_bitmap = NULL;
+}
diff -Naur linux-2.4.26/fs/affs/super.c linux-2.4.26-m68k/fs/affs/super.c
--- linux-2.4.26/fs/affs/super.c	2002-02-26 06:38:07.000000000 +1100
+++ linux-2.4.26-m68k/fs/affs/super.c	2004-06-11 07:01:42.000000000 +1000
@@ -48,10 +48,9 @@
 		mark_buffer_dirty(AFFS_SB->s_root_bh);
 	}
 
-	affs_brelse(AFFS_SB->s_bmap_bh);
 	if (AFFS_SB->s_prefix)
 		kfree(AFFS_SB->s_prefix);
-	kfree(AFFS_SB->s_bitmap);
+	affs_free_bitmap(sb);
 	affs_brelse(AFFS_SB->s_root_bh);
 
 	return;
@@ -235,6 +234,7 @@
 	gid_t			 gid;
 	int			 reserved;
 	unsigned long		 mount_flags;
+	int			 tmp_flags;	/* fix remount prototype... */
 
 	pr_debug("AFFS: read_super(%s)\n",data ? (const char *)data : "no options");
 
@@ -349,7 +349,6 @@
 		printk(KERN_NOTICE "AFFS: Dircache FS - mounting %s read only\n",
 			kdevname(dev));
 		sb->s_flags |= MS_RDONLY;
-		AFFS_SB->s_flags |= SF_READONLY;
 	}
 	switch (chksum) {
 		case MUFS_FS:
@@ -405,8 +404,10 @@
 	AFFS_SB->s_root_bh = root_bh;
 	/* N.B. after this point s_root_bh must be released */
 
-	if (affs_init_bitmap(sb))
+	tmp_flags = sb->s_flags;
+	if (affs_init_bitmap(sb, &tmp_flags))
 		goto out_error;
+	sb->s_flags = tmp_flags;
 
 	/* set up enough so that it can read an inode */
 
@@ -445,14 +446,14 @@
 	int			 reserved;
 	int			 root_block;
 	unsigned long		 mount_flags;
-	unsigned long		 read_only = AFFS_SB->s_flags & SF_READONLY;
+	int			 res = 0;
 
 	pr_debug("AFFS: remount(flags=0x%x,opts=\"%s\")\n",*flags,data);
 
 	if (!parse_options(data,&uid,&gid,&mode,&reserved,&root_block,
 	    &blocksize,&AFFS_SB->s_prefix,AFFS_SB->s_volume,&mount_flags))
 		return -EINVAL;
-	AFFS_SB->s_flags = mount_flags | read_only;
+	AFFS_SB->s_flags = mount_flags;
 	AFFS_SB->s_mode  = mode;
 	AFFS_SB->s_uid   = uid;
 	AFFS_SB->s_gid   = gid;
@@ -463,14 +464,11 @@
 		sb->s_dirt = 1;
 		while (sb->s_dirt)
 			affs_write_super(sb);
-		sb->s_flags |= MS_RDONLY;
-	} else if (!(AFFS_SB->s_flags & SF_READONLY)) {
-		sb->s_flags &= ~MS_RDONLY;
-	} else {
-		affs_warning(sb,"remount","Cannot remount fs read/write because of errors");
-		return -EINVAL;
-	}
-	return 0;
+		affs_free_bitmap(sb);
+	} else
+		res = affs_init_bitmap(sb, flags);
+
+	return res;
 }
 
 static int
diff -Naur linux-2.4.26/fs/asfs/Makefile linux-2.4.26-m68k/fs/asfs/Makefile
--- linux-2.4.26/fs/asfs/Makefile	1970-01-01 10:00:00.000000000 +1000
+++ linux-2.4.26-m68k/fs/asfs/Makefile	2003-06-20 21:32:40.000000000 +1000
@@ -0,0 +1,15 @@
+#
+# Makefile for the linux asfs filesystem routines.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile.
+
+O_TARGET := asfs.o
+
+obj-y  := inode.o
+obj-m  := $(O_TARGET)
+
+include $(TOPDIR)/Rules.make
diff -Naur linux-2.4.26/fs/asfs/inode.c linux-2.4.26-m68k/fs/asfs/inode.c
--- linux-2.4.26/fs/asfs/inode.c	1970-01-01 10:00:00.000000000 +1000
+++ linux-2.4.26-m68k/fs/asfs/inode.c	2003-07-01 05:16:14.000000000 +1000
@@ -0,0 +1,664 @@
+/*
+ *
+ * Amiga Smart File System, Linux implementation
+ *
+ * version: 0.3beta (16.06.2003)
+ *  
+ * Copyright (C) 2003  Marek 'March' Szyprowski <marek@amiga.pl>
+ *
+ *
+ * Thanks to Marcin Kurek (Morgoth/Dreamolers-CAPS) for help.
+ *
+ * Based on the Linux implementation of the ROMFS file system
+ * Copyright (C) 1997-1999  Janos Farkas <chexum@shadow.banki.hu>
+ *
+ * Using parts of the Amiga FFS filesystem
+ * Copyright (C) 1993  Ray Burr
+ * Copyright (C) 1996  Hans-Joachim Widmaier
+ *
+ * and parts of the smbfs filesystem additionally
+ * Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
+ * Copyright (C) 1997 by Volker Lendecke
+ *
+ *
+ * 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.
+ *
+ *
+ * History:
+ *
+ * v0.3beta (17.06.2003)
+ * - second code clean-up
+ *
+ * v0.2beta2 (15.06.2003)
+ * - fixed yet another stupid bug - driver can't read root block on little-endian systems
+ * v0.2beta (15.06.2003)
+ * - fixed stupid bug - now files have 'file' flag (S_IFREG) set...
+ * - added mount options to set uid, gid and mode of files and dirs
+ * - made hidden files & dirs really hidden (= not listed in directories)
+ * - code clean-up
+ *
+ * v0.1beta (11.06.2003) 
+ * - after many kernel crashes, finally got it! 
+ * - first working read-only filesystem driver
+ *
+ */
+
+/* todo:
+ *	- remove bugs
+ *	- considering write access...
+ *	- speed-up entry lookup (use HashTables...)
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/asfs_fs.h>
+#include <linux/fs.h>
+#include <linux/locks.h>
+#include <linux/init.h>
+#include <linux/smp_lock.h>
+
+#include <asm/byteorder.h>
+#include <asm/uaccess.h>
+
+static struct inode *asfs_iget_from_fsObject(struct super_block *sb, struct fsObject *obj);
+
+static u32 asfs_calcchecksum(struct fsBlockHeader *block, u32 blocksize)
+{
+	u32 *data=(void *)block, checksum = 1, tmpchecksum = block->checksum;
+
+	block->checksum=0;
+	while(blocksize > 0) {
+		checksum+=be32_to_cpu(*data++);
+		blocksize-=4;
+	}
+	block->checksum=tmpchecksum;
+	return(-checksum);
+}
+
+static inline int asfs_check_block(struct fsBlockHeader *block, u32 blocksize, u32 n)
+{
+	if (asfs_calcchecksum((struct fsBlockHeader *)block, blocksize) == be32_to_cpu(((struct fsBlockHeader *)block)->checksum) && n == be32_to_cpu(((struct fsBlockHeader *)block)->ownblock))
+		return 1;
+	return 0;
+}
+
+/* get fs structure from block and do some checks... */
+static int asfs_get_contblock(struct super_block *sb, u32 n, void *dest)
+{
+	struct buffer_head *bh;
+
+	bh = sb_bread(sb, n);
+	if (!bh)
+		return -1;		/* error */
+	memcpy(dest, ((char *)bh->b_data), sb->s_blocksize);
+	brelse(bh);
+
+	if (asfs_check_block(dest, sb->s_blocksize, n)) {
+		from32be(((struct fsBlockHeader *)dest)->ownblock);
+		return 1; /* all okay */
+	}
+	return -1; /* error */
+}
+
+/* get data from block without checks... */
+/*static int asfs_get_datablock (struct super_block *sb, u32 n, void *dest, int len)
+{
+	struct buffer_head *bh;
+	bh = sb_bread(sb, n);
+	if (!bh)
+		return -1;
+	memcpy(dest, ((char *)bh->b_data), len);
+	brelse(bh);
+	return 1;
+}
+*/
+static inline struct inode *asfs_get_root_inode(struct super_block *sb)
+{
+	struct inode *result = NULL;
+	void *block;
+	struct fsObject *obj;
+
+	asfs_debug("asfs_get_root_inode\n");
+
+	block = kmalloc(sb->s_blocksize, GFP_KERNEL);
+	if (asfs_get_contblock(sb, sb->u.asfs_sb.rootobjectcontainer, block) < 0)
+		goto free_and_return;
+
+	obj = &(((struct fsObjectContainer *)block)->object[0]);
+	from32be(obj->objectnode);
+	from32be(obj->object.dir.firstdirblock);
+
+	if (obj->objectnode > 0)
+		result = asfs_iget_from_fsObject(sb, obj);
+
+free_and_return:
+	kfree(block);
+	return result;
+}
+
+static struct super_operations asfs_ops;
+
+static int asfs_parse_options(char *options, struct super_block *sb)
+{
+	char *this_char, *value, *optn;
+	int f;
+
+	/* Fill in defaults */
+	sb->u.asfs_sb.uid = ASFS_DEFAULT_UID;
+	sb->u.asfs_sb.gid = ASFS_DEFAULT_GID;
+	sb->u.asfs_sb.mode = ASFS_DEFAULT_MODE;
+
+	if (!options)
+		return 1;
+	for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) {
+		f = 0;
+		if ((value = strchr(this_char,'=')) != NULL)
+			*value++ = 0;
+		if ((f = !strcmp(this_char,"setuid")) || !strcmp(this_char,"setgid")) {
+			if (value) {
+				if (!*value) {
+					printk("ASFS: Argument for set[ug]id option missing\n");
+					return 0;
+				} else {
+					(f ? sb->u.asfs_sb.uid : sb->u.asfs_sb.gid) = simple_strtoul(value,&value,0);
+					if (*value) {
+						printk("ASFS: Bad set[ug]id argument\n");
+						return 0;
+					}
+				}
+			}
+		} else if (!strcmp(this_char,"mode")) {
+			optn = "mode";
+			if (!value || !*value)
+				goto out_no_arg;
+			sb->u.asfs_sb.mode = simple_strtoul(value,&value,8) & 0777;
+			if (*value)
+				return 0;
+		} else {
+			printk("ASFS: Unrecognized mount option %s\n", this_char);
+			return 0;
+		}
+	}
+	return 1;
+
+out_no_arg:
+	printk("ASFS: The %s option requires an argument\n", optn);
+	return 0;
+}
+
+static struct super_block *asfs_read_super(struct super_block *sb, void *data, int silent)
+{
+	struct buffer_head *bh;
+	kdev_t dev = sb->s_dev;
+	struct fsRootBlock *rootblock;
+
+	if (!asfs_parse_options(data, sb)) {
+		printk(KERN_ERR "ASFS: Error parsing options\n");
+		return NULL;
+	}
+
+	if (!sb_set_blocksize(sb, 512))
+		return NULL;
+	sb->s_maxbytes = 0xFFFFFFFF;
+
+	bh = sb_bread(sb, 0);
+	if (!bh) {
+		printk(KERN_ERR "ASFS: unable to read superblock\n");
+		goto outnobh;
+	}
+
+	rootblock = (struct fsRootBlock *)bh->b_data;
+
+	if (be32_to_cpu(rootblock->bheader.id) == ASFS_ROOTID && be16_to_cpu(rootblock->version) == ASFS_STRUCTURE_VERISON) {
+		sb->s_blocksize = be32_to_cpu(rootblock->blocksize);
+		sb->u.asfs_sb.totalblocks = be32_to_cpu(rootblock->totalblocks);
+		sb->u.asfs_sb.rootobjectcontainer = be32_to_cpu(rootblock->rootobjectcontainer);
+		sb->u.asfs_sb.extentbnoderoot = be32_to_cpu(rootblock->extentbnoderoot);
+
+		brelse(bh);
+
+		if (!sb_set_blocksize(sb, sb->s_blocksize)) {
+			printk(KERN_ERR "ASFS: Found Amiga SFS RootBlock on dev %s, but blocksize %ld is not supported!\n", bdevname(dev), sb->s_blocksize);
+			return NULL;
+		}
+
+		bh = sb_bread(sb, 0);
+		if (!bh) {
+			printk(KERN_ERR "ASFS: unable to read superblock\n");
+			goto out;
+		}
+		rootblock = (struct fsRootBlock *)bh->b_data;
+
+		if (asfs_check_block((void *)rootblock, sb->s_blocksize, 0))
+			printk(KERN_NOTICE "ASFS: Found Amiga SFS RootBlock on dev %s. Checksum okay. Mounting...\n", bdevname(dev));
+		else {
+			if (!silent)
+				printk(KERN_ERR "ASFS: Found something like Amiga SFS RootBlock on dev %s, but it has checksum error!\n", bdevname(dev));
+			goto out;
+		}
+	} else {
+		if (!silent)
+			printk(KERN_ERR "ASFS: Can't find a valid Amiga SFS filesystem on dev %s.\n", bdevname(dev));
+		goto out;
+	}
+
+	brelse(bh);
+
+	sb->s_magic = ASFS_MAGIC;
+	sb->s_flags |= MS_RDONLY | MS_NODEV | MS_NOSUID;
+	sb->s_op = &asfs_ops;
+	sb->s_root = d_alloc_root(asfs_get_root_inode(sb));
+	if (!sb->s_root)
+		goto outnobh;
+
+	/* Ehrhm; sorry.. :) */
+	if (0) {
+out:
+		brelse(bh);
+outnobh:
+		sb = NULL;
+	}
+	return sb;
+}
+
+/* That's simple too. */
+
+static int asfs_statfs(struct super_block *sb, struct statfs *buf)
+{
+	buf->f_type = ASFS_MAGIC;
+	buf->f_bsize = sb->s_blocksize;
+	buf->f_bfree = buf->f_bavail = buf->f_ffree;
+	buf->f_blocks = sb->u.asfs_sb.totalblocks;
+	buf->f_namelen = ASFS_MAXFN;
+	return 0;
+}
+
+static int asfs_get_fsObject_varlen(struct fsObject *obj)
+{
+	int len, i;
+	u8 *p = obj->name;
+	for (i=2; i > 0; p++)
+		if (*p == '\0')
+			i--;
+	len = (p - (u8 *)obj);
+	if (len & 1)
+		len++;
+	return len;
+}
+
+static int asfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
+{
+	struct inode *diri = filp->f_dentry->d_inode;
+	unsigned long f_pos;
+	int stored = 0;
+	int obj_skip;
+
+	struct fsObjectContainer *objcont;
+	struct fsObject *obj;
+	int i;
+	unsigned long block;
+
+	asfs_debug("asfs_readdir:\n");
+
+	if (filp->f_pos == diri->i_sb->u.asfs_sb.totalblocks)
+		return stored;
+
+	f_pos = filp->f_pos;
+
+	if (f_pos == 0) {
+		filp->private_data = (void *)0;
+		if (filldir(dirent, ".", 1, f_pos, diri->i_ino, DT_DIR) < 0)
+			return 0;
+		filp->f_pos = f_pos = 1;
+		stored++;
+	}
+	if (f_pos == 1) {
+		if (filldir(dirent, "..", 2, f_pos, filp->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0)
+			return stored;
+		filp->f_pos = f_pos = 2;
+		stored++;
+	}
+
+	if (diri->u.asfs_i.firstdirblock == 0) {	/* empty directory */
+		filp->f_pos = diri->i_sb->u.asfs_sb.totalblocks;
+		return stored;
+	}
+
+	objcont = kmalloc(diri->i_sb->s_blocksize, GFP_KERNEL);
+
+	if (f_pos == 2) {	/* reading directory from its beginning */
+		block = diri->u.asfs_i.firstdirblock;
+		do {
+			if (asfs_get_contblock(diri->i_sb, block, (void *)objcont) < 0)
+				goto free_and_end;
+			from32be(objcont->previous);
+			from32be(objcont->next);
+			block = objcont->previous;
+		} while (objcont->previous != 0);
+		obj_skip = 0;
+	} else {
+		block = f_pos;
+		if (asfs_get_contblock(diri->i_sb, block, (void *)objcont) < 0)
+			goto free_and_end;
+		from32be(objcont->previous);
+		from32be(objcont->next);
+		obj_skip = (int)filp->private_data;
+	}
+
+	i=0;
+	block = ((struct fsBlockHeader *)objcont)->ownblock;
+
+	do {
+		if (i != 0) {
+			if (asfs_get_contblock(diri->i_sb, block, (void *)objcont) < 0)
+				goto free_and_end;
+			from32be(objcont->previous);
+			from32be(objcont->next);
+		}
+
+		i = 0;
+		obj = &(objcont->object[0]);
+		from32be(obj->objectnode);
+
+		while (obj->objectnode > 0 && ((char *)obj - (char *)objcont) + sizeof(struct fsObject) < diri->i_sb->s_blocksize) {
+			if (obj_skip > 0)
+				obj_skip--;
+			else if (!(obj->bits & OTYPE_HIDDEN)) {
+				asfs_debug("ASFS: DirFilling: entry #%d (in_cont: %d) \"%s\" (node %lu offset %lu), type %d\n", stored, i, obj->name, (unsigned long) obj->objectnode, block, obj->bits);
+				filp->f_pos = block;
+				if (filldir(dirent, obj->name, strlen(obj->name), block, obj->objectnode, ((obj->bits & OTYPE_DIR) ? DT_DIR : DT_REG)) < 0) {
+					filp->private_data = (void *)i;
+					asfs_debug("ASFS: DirFilling: to be continued...\n");
+					goto free_and_end;
+				}
+				stored++;
+			}
+			obj = (struct fsObject *)((char *)(obj) + asfs_get_fsObject_varlen(obj));
+			i++;
+		}
+		block = objcont->next;
+
+	} while (objcont->next != 0);
+
+	filp->f_pos = diri->i_sb->u.asfs_sb.totalblocks;
+
+free_and_end:
+	kfree(objcont);
+	return stored;
+}
+
+static inline u8 upperchar(u8 c)
+{
+	if((c>=224 && c<=254 && c!=247) || (c>='a' && c<='z'))
+		c-=32;
+	return(c);
+}
+
+static int namecmp(u8 *s, u8 *ct)
+{
+	while (upperchar(*s) == upperchar(*ct) && *ct != '\0' && *ct != '/') {
+		s++; ct++;
+	}
+	return (*s == '\0' && (*ct == '\0' || *ct == '/')) ? 0 : *ct - *s;
+}
+
+
+static struct dentry *asfs_lookup(struct inode *dir, struct dentry *dentry)
+{
+	int res;
+	struct inode *inode;
+	unsigned char *name;		/* got from dentry */
+
+	struct fsObjectContainer *objcont;
+	struct fsObject *obj;
+	int i;
+	unsigned long block;
+
+	name = (unsigned char *)dentry->d_name.name;
+	res = -EACCES;			/* placeholder for "no data here" */
+
+	asfs_debug("asfs_lookup: (searching \"%s\"...) ", name);
+
+	objcont = kmalloc(dir->i_sb->s_blocksize, GFP_KERNEL);
+
+	block = dir->u.asfs_i.firstdirblock;
+
+	do {
+		if (asfs_get_contblock(dir->i_sb, block, (void *)objcont) < 0)
+			goto free_and_error;
+		from32be(objcont->previous);
+		from32be(objcont->next);
+		block = objcont->previous;
+	} while (objcont->previous != 0);
+
+	i=0;
+	block = ((struct fsBlockHeader *)objcont)->ownblock;
+
+	do {
+		if (i != 0) {
+			if (asfs_get_contblock(dir->i_sb, block, (void *)objcont) < 0)
+				goto free_and_error;
+			from32be(objcont->previous);
+			from32be(objcont->next);
+		}
+
+		i = 0;
+		obj = &(objcont->object[0]);
+		while (be32_to_cpu(obj->objectnode) > 0 && ((char *)obj - (char *)objcont) + sizeof(struct fsObject) < dir->i_sb->s_blocksize) {
+			if (namecmp(obj->name, name) == 0) {
+				from32be(obj->objectnode);
+				from32be(obj->object.dir.firstdirblock); /* it also corrects file.size and file.firstdatablock */
+				from32be(obj->object.dir.hashtable);     /* because they are union */
+				from32be(obj->datemodified);
+				asfs_debug("Object found! #%d: Node %u, Name %s, Type: %d, inCont %lu\n", i, obj->objectnode, obj->name, obj->bits, block);
+
+				if ((inode = asfs_iget_from_fsObject(dir->i_sb, obj)))
+					goto found_inode;
+
+				asfs_debug("ASFS: Strange - no inode allocated... :(\n");
+				goto free_and_error;
+			}
+			obj = (struct fsObject *)((char *)(obj) + asfs_get_fsObject_varlen(obj));
+			i++;
+		}
+		block = objcont->next;
+
+	} while (objcont->next != 0);
+
+	/*
+	 * it's a bit funky, _lookup needs to return an error code
+	 * (negative) or a NULL, both as a dentry.  ENOENT should not
+	 * be returned, instead we need to create a negative dentry by
+	 * d_add(dentry, NULL); and return 0 as no error.
+	 * (Although as I see, it only matters on writable file
+	 * systems).
+	 */
+
+	inode = NULL;
+	asfs_debug("ASFS: object not found.\n");
+found_inode:
+	res = 0;
+	d_add(dentry, inode);
+free_and_error:
+	kfree(objcont);
+	return ERR_PTR(res);
+}
+
+static struct fsExtentBNode asfs_search_BNodeTree(struct super_block *sb, u32 key)
+{
+	struct fsBNodeContainer *bnodecont;
+	struct fsExtentBNode result;
+	unsigned long block = sb->u.asfs_sb.extentbnoderoot;
+
+	bnodecont = kmalloc(sb->s_blocksize, GFP_KERNEL);
+	while (asfs_get_contblock(sb, block, bnodecont) > 0) {
+		from16be(bnodecont->btc.nodecount);
+		if (bnodecont->btc.isleaf) {
+			int i;
+			struct fsExtentBNode *exbnode;
+			exbnode = (void *)bnodecont->btc.bnode;
+			for (i=0; i < bnodecont->btc.nodecount; i++) {
+				from32be(exbnode->key);
+				from32be(exbnode->next);
+				from32be(exbnode->prev);
+				from16be(exbnode->blocks);
+				if (exbnode->key == key) {
+					result = *exbnode;
+					goto found;
+				}
+				exbnode = (void *)exbnode + bnodecont->btc.nodesize;
+			}
+		} else {
+			int i;
+			struct BNode *bnode;
+			bnode = (void *)bnodecont->btc.bnode;
+			for (i=0; i < bnodecont->btc.nodecount && key >= be32_to_cpu(bnode->key); i++)
+				bnode = (void *)bnode + bnodecont->btc.nodesize;
+
+			bnode = (void *)bnode - bnodecont->btc.nodesize;
+			block = be32_to_cpu(bnode->data);
+		}
+	}
+	/* read error or key not found */
+	result = (struct fsExtentBNode){0, 0, 0, 0};
+found:
+	kfree(bnodecont);
+	return result;
+}
+
+static int
+asfs_get_block(struct inode *inode, long block, struct buffer_head *bh_result, int create)
+{
+	struct fsExtentBNode extend;
+	u32 filedata = inode->u.asfs_i.firstdatablock;
+	unsigned long pos = 0;
+
+	asfs_debug("ASFS: get_block(%lu, %ld)\n", inode->i_ino, block);
+
+	if (block < 0) {
+		printk(KERN_ERR "ASFS: asfsget_block: requested block (%ld) < 0!\n", block);
+		return -EIO;
+	}
+
+	if (block >= inode->i_blocks) {
+		printk(KERN_ERR "ASFS: asfsget_block: strange block request %ld!\n", block);
+		return -EIO;
+	}
+
+	do {
+		extend = asfs_search_BNodeTree(inode->i_sb, filedata);
+		if (extend.key == 0)
+			goto error;
+		filedata = extend.next;
+		if (pos + extend.blocks > block) {
+			bh_result->b_blocknr = extend.key + block - pos;
+			bh_result->b_dev = inode->i_dev;
+			bh_result->b_state |= (1UL << BH_Mapped);
+			return 0;
+		}
+		pos += extend.blocks;
+	} while (extend.next != 0 && pos < inode->i_blocks);
+error:
+	return -EIO;
+}
+
+static int asfs_readpage(struct file *file, struct page *page)
+{
+	return block_read_full_page(page, asfs_get_block);
+}
+static int asfs_bmap(struct address_space *mapping, long block)
+{
+	return generic_block_bmap(mapping,block,asfs_get_block);
+}
+
+/* Mapping from our types to the kernel */
+
+static struct address_space_operations asfs_aops = {
+	.readpage	= asfs_readpage,
+	.sync_page	= block_sync_page,
+	.bmap		= asfs_bmap,
+};
+
+struct file_operations asfs_file_operations = {
+	.llseek		= generic_file_llseek,
+	.read		= generic_file_read,
+	.mmap		= generic_file_mmap,
+};
+
+static struct file_operations asfs_dir_operations = {
+	.read		= generic_read_dir,
+	.readdir	= asfs_readdir,
+};
+
+static struct inode_operations asfs_dir_inode_operations = {
+	.lookup		= asfs_lookup,
+};
+
+static struct inode *asfs_iget_from_fsObject(struct super_block *sb, struct fsObject *obj)
+{
+	struct inode *result;
+
+	result = new_inode(sb);
+	if (!result)
+		return result;
+
+	result->i_ino = obj->objectnode;
+	result->i_mode = sb->u.asfs_sb.mode;
+	result->i_mtime = result->i_atime = result->i_ctime = obj->datemodified + (365*8+2)*24*60*60;  /* Linux: seconds since 01-01-1970, AmigaSFS: seconds since 01-01-1978 */
+	result->i_uid = sb->u.asfs_sb.uid;
+	result->i_gid = sb->u.asfs_sb.gid;
+
+	asfs_debug("asfs_iget_from_fsObject: Setting-up node %lu... ", result->i_ino);
+
+	if (obj->bits & OTYPE_DIR) {
+		asfs_debug("dir (FirstdirBlock: %u, HashTable %u)\n", obj->object.dir.firstdirblock, obj->object.dir.hashtable);
+
+		result->i_size = 0;
+		result->i_op = &asfs_dir_inode_operations;
+		result->i_fop = &asfs_dir_operations;
+		result->i_mode |= S_IFDIR | ((result->i_mode & 0400) ? 0100 : 0) | ((result->i_mode & 0040) ? 0010 : 0) | ((result->i_mode & 0004) ? 0001 : 0);
+		result->u.asfs_i.firstdirblock = obj->object.dir.firstdirblock;
+		result->u.asfs_i.hashtable = obj->object.dir.hashtable;
+	} else {
+		asfs_debug("file (Size: %u, FirstBlock: %u)\n", obj->object.file.size, obj->object.file.data);
+
+		result->i_size = obj->object.file.size;
+		result->i_blocks = (obj->object.file.size + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
+		result->i_fop = &asfs_file_operations;
+		result->i_mapping->a_ops = &asfs_aops;
+		result->i_mode |= S_IFREG;
+		result->u.asfs_i.firstdatablock = obj->object.file.data;
+	}
+	insert_inode_hash(result);
+	return result;
+}
+
+static struct super_operations asfs_ops = {
+	.statfs		= asfs_statfs,
+};
+
+static DECLARE_FSTYPE_DEV(asfs_fs_type, "asfs", asfs_read_super);
+
+static int __init init_asfs_fs(void)
+{
+	return register_filesystem(&asfs_fs_type);
+}
+
+static void __exit exit_asfs_fs(void)
+{
+	unregister_filesystem(&asfs_fs_type);
+}
+
+/* Yes, works even as a module... :) */
+
+EXPORT_NO_SYMBOLS;
+MODULE_DESCRIPTION("Amiga Smart File System support for Linux");
+
+module_init(init_asfs_fs)
+module_exit(exit_asfs_fs)
+MODULE_LICENSE("GPL");
diff -Naur linux-2.4.26/fs/binfmt_aout.c linux-2.4.26-m68k/fs/binfmt_aout.c
--- linux-2.4.26/fs/binfmt_aout.c	2001-11-03 12:39:20.000000000 +1100
+++ linux-2.4.26-m68k/fs/binfmt_aout.c	2003-04-07 09:23:02.000000000 +1000
@@ -349,7 +349,7 @@
 			return error;
 		}
 			 
-		flush_icache_range(text_addr, text_addr+ex.a_text+ex.a_data);
+		flush_icache_user_range((void *)text_addr, ex.a_text + ex.a_data);
 	} else {
 		static unsigned long error_time, error_time2;
 		if ((ex.a_text & 0xfff || ex.a_data & 0xfff) &&
@@ -373,9 +373,7 @@
 			do_brk(N_TXTADDR(ex), ex.a_text+ex.a_data);
 			bprm->file->f_op->read(bprm->file,(char *)N_TXTADDR(ex),
 					ex.a_text+ex.a_data, &pos);
-			flush_icache_range((unsigned long) N_TXTADDR(ex),
-					   (unsigned long) N_TXTADDR(ex) +
-					   ex.a_text+ex.a_data);
+			flush_icache_user_range((void *)N_TXTADDR(ex), ex.a_text + ex.a_data);
 			goto beyond_if;
 		}
 
@@ -471,8 +469,7 @@
 		
 		file->f_op->read(file, (char *)start_addr,
 			ex.a_text + ex.a_data, &pos);
-		flush_icache_range((unsigned long) start_addr,
-				   (unsigned long) start_addr + ex.a_text + ex.a_data);
+		flush_icache_user_range((void *)start_addr, ex.a_text + ex.a_data);
 
 		retval = 0;
 		goto out;
diff -Naur linux-2.4.26/fs/binfmt_elf.c linux-2.4.26-m68k/fs/binfmt_elf.c
--- linux-2.4.26/fs/binfmt_elf.c	2004-04-14 23:05:40.000000000 +1000
+++ linux-2.4.26-m68k/fs/binfmt_elf.c	2004-04-15 06:42:54.000000000 +1000
@@ -403,8 +403,7 @@
 	retval = interpreter->f_op->read(interpreter, addr, text_data, &offset);
 	if (retval < 0)
 		goto out;
-	flush_icache_range((unsigned long)addr,
-	                   (unsigned long)addr + text_data);
+	flush_icache_user_range(addr, text_data);
 
 	do_brk(ELF_PAGESTART(text_data + ELF_MIN_ALIGN - 1),
 		interp_ex->a_bss);
diff -Naur linux-2.4.26/fs/fat/inode.c linux-2.4.26-m68k/fs/fat/inode.c
--- linux-2.4.26/fs/fat/inode.c	2004-04-14 23:05:40.000000000 +1000
+++ linux-2.4.26-m68k/fs/fat/inode.c	2004-04-15 06:42:55.000000000 +1000
@@ -11,6 +11,8 @@
  */
 
 #include <linux/module.h>
+
+#include <linux/config.h>
 #include <linux/msdos_fs.h>
 #include <linux/nls.h>
 #include <linux/kernel.h>
@@ -226,6 +228,13 @@
 	opts->shortname = 0;
 	opts->utf8 = 0;
 	opts->iocharset = NULL;
+	opts->atari = 0;
+
+#ifdef CONFIG_ATARI
+	if(MACH_IS_ATARI)
+	/* make Atari GEMDOS format the default if machine is an Atari */
+		opts->atari = 1;
+#endif
 	*debug = *fat = 0;
 
 	if (!options)
@@ -324,6 +333,11 @@
 			if (value) ret = 0;
 			else opts->sys_immutable = 1;
 		}
+		else if (!strcmp(this_char,"atari")) {
+			if (!value || !strcmp(value,"yes")) opts->atari = 1;
+			else if (!strcmp(value,"no")) opts->atari = 0;
+			else ret = 0;
+		}
 		else if (!strcmp(this_char,"codepage") && value) {
 			opts->codepage = simple_strtoul(value,&value,0);
 			if (*value) ret = 0;
@@ -716,16 +730,41 @@
 
 	error = 0;
 	if (!error) {
-		sbi->fat_bits = fat32 ? 32 :
+ 		if (!opts.atari)
+			sbi->fat_bits = fat32 ? 32 :
 			(fat ? fat :
 			 (sbi->clusters > MSDOS_FAT12 ? 16 : 12));
+ 		else {
+ 			int sectors;
+ 			/* Atari GEMDOS partitions always have 16-bit fat */
+ 			sbi->fat_bits = fat32 ? 32 : (fat ? fat : 16);
+ 			/* If more clusters than fat entries in 16-bit fat, we assume
+ 			 * it's a real MSDOS partition with 12-bit fat.
+ 			 */
+ 			if (!fat32 && sbi->clusters+2 > sbi->
+ 				fat_length*SECTOR_SIZE*8/sbi->fat_bits)
+ 				sbi->fat_bits = 12;
+ 			/* if it's a floppy disk --> 12bit fat */
+ 			if (!fat32 && MAJOR(sb->s_dev) == FLOPPY_MAJOR)
+ 				sbi->fat_bits = 12;
+ 			/* if it's a ramdisk or loopback device and has one of the usual
+ 			 * floppy sizes -> 12bit FAT  */
+ 			sectors = total_sectors + sbi->data_start;
+ 			if (!fat32 && (MAJOR(sb->s_dev) == RAMDISK_MAJOR ||
+ 				 MAJOR(sb->s_dev) == LOOP_MAJOR) &&
+ 				(sectors == 720 || sectors == 1440 || sectors == 2880))
+ 				sbi->fat_bits = 12;
+ 		}
 		fat_clusters =
 			sbi->fat_length * logical_sector_size * 8 / sbi->fat_bits;
 		error = !sbi->fats || (sbi->dir_entries & (sbi->dir_per_block - 1))
 			|| sbi->clusters + 2 > fat_clusters + MSDOS_MAX_EXTRA
 			|| logical_sector_size < 512
 			|| PAGE_CACHE_SIZE < logical_sector_size
-			|| !b->secs_track || !b->heads;
+			/* secs_track and heads may be arbitrary on GEMDOS
+			   partitions, it depends on partitioning software
+			   used.  */
+			|| (!opts.atari && (!b->secs_track || !b->heads));
 	}
 	brelse(bh);
 
@@ -744,10 +783,10 @@
 		error = cvf_formats[i]->mount_cvf(sb, cvf_options);
 	if (error || debug) {
 		/* The MSDOS_CAN_BMAP is obsolete, but left just to remember */
-		printk("[MS-DOS FS Rel. 12,FAT %d,check=%c,conv=%c,"
+		printk("[MS-DOS FS Rel. 12,FAT %d,check=%c,conv=%c,atari=%c,"
 		       "uid=%d,gid=%d,umask=%03o%s]\n",
-		       sbi->fat_bits,opts.name_check,
-		       opts.conversion,opts.fs_uid,opts.fs_gid,opts.fs_umask,
+		       sbi->fat_bits,opts.name_check,opts.conversion,
+		       opts.atari?'y':'n',opts.fs_uid,opts.fs_gid,opts.fs_umask,
 		       MSDOS_CAN_BMAP(sbi) ? ",bmap" : "");
 		printk("[me=0x%x,cs=%d,#f=%d,fs=%d,fl=%ld,ds=%ld,de=%d,data=%ld,"
 		       "se=%u,ts=%u,ls=%d,rc=%ld,fc=%u]\n",
diff -Naur linux-2.4.26/include/asm-m68k/bootinfo.h linux-2.4.26-m68k/include/asm-m68k/bootinfo.h
--- linux-2.4.26/include/asm-m68k/bootinfo.h	2001-04-19 04:49:13.000000000 +1000
+++ linux-2.4.26-m68k/include/asm-m68k/bootinfo.h	2003-07-22 07:20:24.000000000 +1000
@@ -255,6 +255,7 @@
 #define MVME16x_BOOTI_VERSION  MK_BI_VERSION( 2, 0 )
 #define BVME6000_BOOTI_VERSION MK_BI_VERSION( 2, 0 )
 #define Q40_BOOTI_VERSION      MK_BI_VERSION( 2, 0 )
+#define TEKXP_BOOTI_VERSION    MK_BI_VERSION( 2, 0 )
 
 #ifdef BOOTINFO_COMPAT_1_0
 
diff -Naur linux-2.4.26/include/asm-m68k/keyboard.h linux-2.4.26-m68k/include/asm-m68k/keyboard.h
--- linux-2.4.26/include/asm-m68k/keyboard.h	2004-04-14 23:05:40.000000000 +1000
+++ linux-2.4.26-m68k/include/asm-m68k/keyboard.h	2004-02-10 07:24:32.000000000 +1100
@@ -13,6 +13,58 @@
 
 #ifdef __KERNEL__
 
+#ifdef CONFIG_TEKXP
+
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+
+#define KEYBOARD_IRQ			4
+#define DISABLE_KBD_DURING_INTERRUPTS	0
+
+extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int pckbd_getkeycode(unsigned int scancode);
+extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+			   char raw_mode);
+extern char pckbd_unexpected_up(unsigned char keycode);
+extern void pckbd_leds(unsigned char leds);
+extern void pckbd_init_hw(void);
+extern unsigned char pckbd_sysrq_xlate[128];
+
+#define kbd_setkeycode		pckbd_setkeycode
+#define kbd_getkeycode		pckbd_getkeycode
+#define kbd_translate		pckbd_translate
+#define kbd_unexpected_up	pckbd_unexpected_up
+#define kbd_leds		pckbd_leds
+#define kbd_init_hw		pckbd_init_hw
+#define kbd_sysrq_xlate		pckbd_sysrq_xlate
+
+#define SYSRQ_KEY 0x54
+
+/* resource allocation */
+#define kbd_request_region()
+#define kbd_request_irq(handler) request_irq(KEYBOARD_IRQ, handler, 0, \
+                                             "keyboard", NULL)
+
+/* How to access the keyboard macros on this platform.  */
+#define kbd_read_input() (*(volatile unsigned char*)0xff900000)
+#define kbd_read_status() (*(volatile unsigned char*)0xff900004)
+#define kbd_write_output(val) do { *(volatile unsigned char*)0xff900000 = (val); } while(0)
+#define kbd_write_command(val) do { *(volatile unsigned char*)0xff900004 = (val); } while(0)
+
+/* Some stoneage hardware needs delays after some operations.  */
+#define kbd_pause() do { } while(0)
+
+/*
+ * Machine specific bits for the PS/2 driver
+ */
+
+#define AUX_IRQ 4
+#define aux_request_irq(hand, dev_id) (0)
+#define aux_free_irq(dev_id)	do { } while (0)
+
+#else	/* !CONFIG_TEKXP */
+
 #include <linux/config.h>
 #include <linux/kd.h>
 #include <asm/machdep.h>
@@ -72,6 +124,8 @@
 #define kbd_write_command(val) out_8(KBD_CNTL_REG, val)
 extern unsigned int SYSRQ_KEY;
 
+#endif	/* !CONFIG_TEKXP */
+
 #endif /* __KERNEL__ */
 
 #endif /* __M68K_KEYBOARD_H */
diff -Naur linux-2.4.26/include/asm-m68k/motorola_pgalloc.h linux-2.4.26-m68k/include/asm-m68k/motorola_pgalloc.h
--- linux-2.4.26/include/asm-m68k/motorola_pgalloc.h	2004-02-19 00:36:32.000000000 +1100
+++ linux-2.4.26-m68k/include/asm-m68k/motorola_pgalloc.h	2004-04-06 03:59:32.000000000 +1000
@@ -231,20 +231,24 @@
 
 static inline void flush_tlb_mm(struct mm_struct *mm)
 {
-	if (mm == current->mm)
+	if (mm == current->active_mm)
 		__flush_tlb();
 }
 
 static inline void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
 {
-	if (vma->vm_mm == current->mm)
+	if (vma->vm_mm == current->active_mm) {
+		mm_segment_t old_fs = get_fs();
+		set_fs(USER_DS);
 		__flush_tlb_one(addr);
+		set_fs(old_fs);
+	}
 }
 
 static inline void flush_tlb_range(struct mm_struct *mm,
 				   unsigned long start, unsigned long end)
 {
-	if (mm == current->mm)
+	if (mm == current->active_mm)
 		__flush_tlb();
 }
 
diff -Naur linux-2.4.26/include/asm-m68k/pgalloc.h linux-2.4.26-m68k/include/asm-m68k/pgalloc.h
--- linux-2.4.26/include/asm-m68k/pgalloc.h	2004-02-19 00:36:32.000000000 +1100
+++ linux-2.4.26-m68k/include/asm-m68k/pgalloc.h	2003-12-01 06:18:08.000000000 +1100
@@ -126,35 +126,12 @@
 
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_icache_page(vma,pg)              do { } while (0)
-#define flush_icache_user_range(vma,pg,adr,len)	do { } while (0)
-
-/* Push n pages at kernel virtual address and clear the icache */
-/* RZ: use cpush %bc instead of cpush %dc, cinv %ic */
-extern inline void flush_icache_range (unsigned long address,
-				       unsigned long endaddr)
-{
-	if (CPU_IS_040_OR_060) {
-		short n = (endaddr - address + PAGE_SIZE - 1) / PAGE_SIZE;
-
-		while (--n >= 0) {
-			__asm__ __volatile__("nop\n\t"
-					     ".chip 68040\n\t"
-					     "cpushp %%bc,(%0)\n\t"
-					     ".chip 68k"
-					     : : "a" (virt_to_phys((void *)address)));
-			address += PAGE_SIZE;
-		}
-	} else {
-		unsigned long tmp;
-		__asm__ __volatile__("movec %%cacr,%0\n\t"
-				     "orw %1,%0\n\t"
-				     "movec %0,%%cacr"
-				     : "=&d" (tmp)
-				     : "di" (FLUSH_I));
-	}
-}
 
+extern void flush_icache_user_page(struct vm_area_struct *vma, struct page *page,
+				   unsigned long addr, int len);
 
+extern void flush_icache_range(unsigned long address, unsigned long endaddr);
+extern void flush_icache_user_range(void *address, unsigned long size);
 
 
 #ifdef CONFIG_SUN3
diff -Naur linux-2.4.26/include/asm-m68k/setup.h linux-2.4.26-m68k/include/asm-m68k/setup.h
--- linux-2.4.26/include/asm-m68k/setup.h	2000-01-27 07:44:21.000000000 +1100
+++ linux-2.4.26-m68k/include/asm-m68k/setup.h	2003-07-22 07:34:11.000000000 +1000
@@ -41,6 +41,7 @@
 #define MACH_HP300    9
 #define MACH_Q40     10
 #define MACH_SUN3X   11
+#define MACH_TEKXP   12
 
 #ifdef __KERNEL__
 
@@ -53,7 +54,8 @@
 #elif defined(CONFIG_ATARI) || defined(CONFIG_MAC) || defined(CONFIG_APOLLO) \
 	|| defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000)               \
 	|| defined(CONFIG_HP300) || defined(CONFIG_Q40)                      \
-	|| defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)
+	|| defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)                  \
+        || defined(CONFIG_TEKXP)
 #  define MACH_IS_AMIGA (m68k_machtype == MACH_AMIGA)
 #else
 #  define MACH_AMIGA_ONLY
@@ -66,7 +68,8 @@
 #elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_APOLLO) \
 	|| defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000)               \
 	|| defined(CONFIG_HP300) || defined(CONFIG_Q40)                      \
-	|| defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)
+	|| defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)                  \
+        || defined(CONFIG_TEKXP)
 #  define MACH_IS_ATARI (m68k_machtype == MACH_ATARI)
 #else
 #  define MACH_ATARI_ONLY
@@ -79,7 +82,8 @@
 #elif defined(CONFIG_AMIGA) || defined(CONFIG_ATARI) || defined(CONFIG_APOLLO) \
 	|| defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000)                 \
 	|| defined(CONFIG_HP300) || defined(CONFIG_Q40)                        \
-	|| defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)
+	|| defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)                    \
+        || defined(CONFIG_TEKXP)
 #  define MACH_IS_MAC (m68k_machtype == MACH_MAC)
 #else
 #  define MACH_MAC_ONLY
@@ -100,7 +104,8 @@
 #elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
 	|| defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000)              \
 	|| defined(CONFIG_HP300) || defined(CONFIG_Q40)                     \
-	|| defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)
+	|| defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)                 \
+        || defined(CONFIG_TEKXP)
 #  define MACH_IS_APOLLO (m68k_machtype == MACH_APOLLO)
 #else
 #  define MACH_APOLLO_ONLY
@@ -113,7 +118,8 @@
 #elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
 	|| defined(CONFIG_APOLLO) || defined(CONFIG_BVME6000)               \
 	|| defined(CONFIG_HP300) || defined(CONFIG_Q40)                     \
-	|| defined(CONFIG_SUN3X) || defined(CONFIG_MVME16x)
+	|| defined(CONFIG_SUN3X) || defined(CONFIG_MVME16x)                 \
+        || defined(CONFIG_TEKXP)
 #  define MACH_IS_MVME147 (m68k_machtype == MACH_MVME147)
 #else
 #  define MACH_MVME147_ONLY
@@ -126,7 +132,8 @@
 #elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
 	|| defined(CONFIG_APOLLO) || defined(CONFIG_BVME6000)               \
 	|| defined(CONFIG_HP300) || defined(CONFIG_Q40)                     \
-	|| defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)
+	|| defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)                 \
+        || defined(CONFIG_TEKXP)
 #  define MACH_IS_MVME16x (m68k_machtype == MACH_MVME16x)
 #else
 #  define MACH_MVME16x_ONLY
@@ -139,7 +146,8 @@
 #elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
 	|| defined(CONFIG_APOLLO) || defined(CONFIG_MVME16x)                \
 	|| defined(CONFIG_HP300) || defined(CONFIG_Q40)                     \
-	|| defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)
+	|| defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)                 \
+        || defined(CONFIG_TEKXP)
 #  define MACH_IS_BVME6000 (m68k_machtype == MACH_BVME6000)
 #else
 #  define MACH_BVME6000_ONLY
@@ -152,7 +160,8 @@
 #elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
 	|| defined(CONFIG_APOLLO) || defined(CONFIG_MVME16x) \
 	|| defined(CONFIG_BVME6000) || defined(CONFIG_Q40) \
-	|| defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)
+	|| defined(CONFIG_SUN3X) || defined(CONFIG_MVME147) \
+        || defined(CONFIG_TEKXP)
 #  define MACH_IS_HP300 (m68k_machtype == MACH_HP300)
 #else
 #  define MACH_HP300_ONLY
@@ -165,7 +174,8 @@
 #elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
 	|| defined(CONFIG_APOLLO) || defined(CONFIG_MVME16x)                \
 	|| defined(CONFIG_BVME6000) || defined(CONFIG_HP300)                \
-	|| defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)
+	|| defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)                 \
+        || defined(CONFIG_TEKXP)
 #  define MACH_IS_Q40 (m68k_machtype == MACH_Q40)
 #else
 #  define MACH_Q40_ONLY
@@ -178,7 +188,8 @@
 #elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
 	|| defined(CONFIG_APOLLO) || defined(CONFIG_MVME16x)                \
 	|| defined(CONFIG_BVME6000) || defined(CONFIG_HP300)                \
-	|| defined(CONFIG_Q40) || defined(CONFIG_MVME147)
+	|| defined(CONFIG_Q40) || defined(CONFIG_MVME147)                   \
+        || defined(CONFIG_TEKXP)
 #  define MACH_IS_SUN3X (m68k_machtype == MACH_SUN3X)
 #else
 #  define CONFIG_SUN3X_ONLY
@@ -186,6 +197,20 @@
 #  define MACH_TYPE (MACH_SUN3X)
 #endif
 
+#if !defined (CONFIG_TEKXP)
+#  define MACH_IS_TEKXP (0)
+#elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
+	|| defined(CONFIG_APOLLO) || defined(CONFIG_MVME16x)                \
+	|| defined(CONFIG_BVME6000) || defined(CONFIG_HP300)                \
+	|| defined(CONFIG_Q40) || defined(CONFIG_MVME147)                   \
+        || defined(CONFIG_SUN3X)
+#  define MACH_IS_TEKXP (m68k_machtype == MACH_TEKXP)
+#else
+#  define CONFIG_TEKXP_ONLY
+#  define MACH_IS_TEKXP (1)
+#  define MACH_TYPE (MACH_TEKXP)
+#endif
+
 #ifndef MACH_TYPE
 #  define MACH_TYPE (m68k_machtype)
 #endif
@@ -355,7 +380,7 @@
      *  Miscellaneous
      */
 
-#define NUM_MEMINFO	4
+#define NUM_MEMINFO	8
 #define CL_SIZE		256
 
 #ifndef __ASSEMBLY__
diff -Naur linux-2.4.26/include/asm-m68k/tekirq.h linux-2.4.26-m68k/include/asm-m68k/tekirq.h
--- linux-2.4.26/include/asm-m68k/tekirq.h	1970-01-01 10:00:00.000000000 +1000
+++ linux-2.4.26-m68k/include/asm-m68k/tekirq.h	2003-07-22 07:20:24.000000000 +1000
@@ -0,0 +1,27 @@
+/*
+ *  linux/include/asm-m68k/tekirq.h
+ *
+ *  Copyright (C) 2002,2003 Michael Mueller <malware@t-online.de>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * license. See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef _ASM_TEKIRQ_H_
+#define _ASM_TEKIRQ_H_
+
+#include <asm/irq.h>
+
+#define TEK_IRQ_VIDEO		(IRQ2)
+#define TEK_IRQ_KEYB		(IRQ4)
+#define TEK_IRQ_UART		(IRQ5)
+#define TEK_IRQ_NET		(IRQ6)
+
+#define TEK_IRQ_TIMER_A		(SYS_IRQS + 3)
+#define TEK_IRQ_TXRDY_A		(SYS_IRQS + 0)
+#define TEK_IRQ_RXRDY_A		(SYS_IRQS + 1)
+#define TEK_IRQ_TXRDY_B		(SYS_IRQS + 4)
+#define TEK_IRQ_RXRDY_B		(SYS_IRQS + 5)
+
+#endif	/* !defined(_ASM_TEKIRQ_H_) */
diff -Naur linux-2.4.26/include/asm-m68k/teknvram.h linux-2.4.26-m68k/include/asm-m68k/teknvram.h
--- linux-2.4.26/include/asm-m68k/teknvram.h	1970-01-01 10:00:00.000000000 +1000
+++ linux-2.4.26-m68k/include/asm-m68k/teknvram.h	2003-07-22 07:20:24.000000000 +1000
@@ -0,0 +1,31 @@
+/*
+ *  linux/include/asm-m68k/teknvram.h
+ *
+ *  Copyright (C) 2002,2003 Michael Mueller <malware@t-online.de>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#ifndef _ASM_TEKNVRAM_H_
+#define _ASM_TEKNVRAM_H_
+
+#define EEPROM_BASE	0xFFF00000UL
+#define EEPROM_SIZE	0x800
+
+extern void init_nvram(unsigned long* memstart);
+
+extern u_char	nvram_readb(int);
+extern u_short	nvram_readw(int);
+extern u_long	nvram_readl(int);
+
+
+/*
+ * Some known data locations within the NVRAM
+ */
+#define NVRAM_SONIC_MAC		4	/* 6 bytes MAC address for sonic */
+#define NVRAM_DISPLAY		0x1c	/* Display type */
+
+#endif	/* !defined(_ASM_TEKNVRAM_H_) */
+
diff -Naur linux-2.4.26/include/asm-m68k/tekuart.h linux-2.4.26-m68k/include/asm-m68k/tekuart.h
--- linux-2.4.26/include/asm-m68k/tekuart.h	1970-01-01 10:00:00.000000000 +1000
+++ linux-2.4.26-m68k/include/asm-m68k/tekuart.h	2003-07-22 07:20:24.000000000 +1000
@@ -0,0 +1,118 @@
+/*
+ *  linux/include/asm-m68k/tekuart.h
+ *
+ *  Copyright (C) 2002,2003 Michael Mueller <malware@t-online.de>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#ifndef ASM_TEKUART
+#define ASM_TEKUART
+
+extern spinlock_t tek_uart_lock;
+
+#define TEK_UART_BASE	(0xFF800000UL)
+
+#define UART_IRQS 8
+
+void tek_uart_init_IRQ(void);
+int tek_uart_request_irq(unsigned int irq,
+                          void (*handler)(int, void *, struct pt_regs *),
+                          unsigned long flags,
+                          const char *devname, void *dev_id);
+void tek_uart_free_irq(unsigned int irq, void *dev_id);
+void tek_uart_enable_irq(unsigned int irq);
+void tek_uart_disable_irq(unsigned int irq);
+int tek_uart_get_irq_list(char *buf);
+
+void tek_uart_setup_timer(void (*handler)(int, void *, struct pt_regs *));
+void tek_uart_putchar(int channel, int c, int waitloop);
+
+void tek_uart_set_op(int nr);
+void tek_uart_clr_op(int nr);
+
+/*
+ * Structures describing the register set of the Motorola 68681 DUART.
+ */
+
+struct tek_uart_rd {
+	unsigned char	MRxA;
+	unsigned short	_pad1;
+	unsigned char	SRA;
+	unsigned short	_pad2;
+	unsigned char	BRG_Test;
+	unsigned short	_pad3;
+	unsigned char	RHRA;
+	unsigned short	_pad4;
+	unsigned char	IPCR;
+	unsigned short	_pad5;
+	unsigned char	ISR;
+	unsigned short	_pad6;
+	unsigned char	CTU;
+	unsigned short	_pad7;
+	unsigned char	CTL;
+	unsigned short	_pad8;
+	unsigned char	MRxB;
+	unsigned short	_pad9;
+	unsigned char	SRB;
+	unsigned short	_pad10;
+	unsigned char	x1x16_Test;
+	unsigned short	_pad11;
+	unsigned char	RHRB;
+	unsigned short	_pad12;
+	unsigned char	res1;
+	unsigned short	_pad13;
+	unsigned char	IP;
+	unsigned short	_pad14;
+	unsigned char	CounterStart;
+	unsigned short	_pad15;
+	unsigned char	CounterStop;
+	unsigned short	_pad16;
+};
+
+struct tek_uart_wr {
+	unsigned char	MRxA;
+	unsigned short	_pad1;
+	unsigned char	CSRA;
+	unsigned short	_pad2;
+	unsigned char	CRA;
+	unsigned short	_pad3;
+	unsigned char	THRA;
+	unsigned short	_pad4;
+	unsigned char	ACR;
+	unsigned short	_pad5;
+	unsigned char	IMR;
+	unsigned short	_pad6;
+	unsigned char	CRUR;
+	unsigned short	_pad7;
+	unsigned char	CTLR;
+	unsigned short	_pad8;
+	unsigned char	MRxB;
+	unsigned short	_pad9;
+	unsigned char	CSRB;
+	unsigned short	_pad10;
+	unsigned char	CRB;
+	unsigned short	_pad11;
+	unsigned char	THRB;
+	unsigned short	_pad12;
+	unsigned char	res1;
+	unsigned short	_pad13;
+	unsigned char	OPCR;
+	unsigned short	_pad14;
+	unsigned char	OutputSet;
+	unsigned short	_pad15;
+	unsigned char	OutputClear;
+	unsigned short	_pad16;
+};
+
+union tek_uart {
+	struct tek_uart_rd rd;
+	struct tek_uart_wr wr;
+};
+
+typedef union tek_uart tek_uart_t;
+
+#endif	/* defined(ASM_TEKUART) */
+
diff -Naur linux-2.4.26/include/linux/adb.h linux-2.4.26-m68k/include/linux/adb.h
--- linux-2.4.26/include/linux/adb.h	2003-08-25 21:44:44.000000000 +1000
+++ linux-2.4.26-m68k/include/linux/adb.h	2003-08-26 13:18:04.000000000 +1000
@@ -76,6 +76,7 @@
 #define ADBREQ_REPLY	1	/* expect reply */
 #define ADBREQ_SYNC	2	/* poll until done */
 #define ADBREQ_NOSEND	4	/* build the request, but don't send it */
+#define ADBREQ_RAW	8	/* send raw packet (don't prepend ADB_PACKET) */
 
 /* Messages sent thru the client_list notifier. You should NOT stop
    the operation, at least not with this version */
diff -Naur linux-2.4.26/include/linux/affs_fs.h linux-2.4.26-m68k/include/linux/affs_fs.h
--- linux-2.4.26/include/linux/affs_fs.h	2001-04-20 15:57:06.000000000 +1000
+++ linux-2.4.26-m68k/include/linux/affs_fs.h	2004-06-11 07:01:42.000000000 +1000
@@ -33,7 +33,8 @@
 extern u32	affs_count_free_blocks(struct super_block *s);
 extern void	affs_free_block(struct super_block *sb, u32 block);
 extern u32	affs_alloc_block(struct inode *inode, u32 goal);
-extern int	affs_init_bitmap(struct super_block *sb);
+extern int	affs_init_bitmap(struct super_block *sb, int *flags);
+extern void	affs_free_bitmap(struct super_block *sb);
 
 /* namei.c */
 
diff -Naur linux-2.4.26/include/linux/affs_fs_sb.h linux-2.4.26-m68k/include/linux/affs_fs_sb.h
--- linux-2.4.26/include/linux/affs_fs_sb.h	2001-04-20 15:57:06.000000000 +1000
+++ linux-2.4.26-m68k/include/linux/affs_fs_sb.h	2004-06-11 07:01:42.000000000 +1000
@@ -47,7 +47,6 @@
 #define SF_OFS		0x0200		/* Old filesystem */
 #define SF_PREFIX	0x0400		/* Buffer for prefix is allocated */
 #define SF_VERBOSE	0x0800		/* Talk about fs when mounting */
-#define SF_READONLY	0x1000		/* Don't allow to remount rw */
 
 /* short cut to get to the affs specific sb data */
 #define AFFS_SB		(&sb->u.affs_sb)
diff -Naur linux-2.4.26/include/linux/asfs_fs.h linux-2.4.26-m68k/include/linux/asfs_fs.h
--- linux-2.4.26/include/linux/asfs_fs.h	1970-01-01 10:00:00.000000000 +1000
+++ linux-2.4.26-m68k/include/linux/asfs_fs.h	2003-07-01 05:16:14.000000000 +1000
@@ -0,0 +1,151 @@
+#ifndef __LINUX_ASFS_FS_H
+#define __LINUX_ASFS_FS_H
+
+#include <linux/types.h>
+#include <asm/byteorder.h>
+
+#define asfs_debug(fmt,arg...) pr_debug(fmt,##arg)
+//#define asfs_debug(fmt,arg...) printk(fmt,##arg)
+
+/* some helper macros... */
+
+#define from32be(t) ((t)=be32_to_cpu(t))
+#define from16be(t) ((t)=be16_to_cpu(t))
+
+#define ASFS_MAKE_ID(a,b,c,d) (((a)&0xff)<<24|((b)&0xff)<<16|((c)&0xff)<<8|((d)&0xff))
+
+/* Amiga SFS defines */
+
+#define ASFS_MAGIC 0xa0ff
+#define ASFS_MAXFN 105
+
+#define ASFS_ROOTID ASFS_MAKE_ID('S','F','S',0)
+
+#define ASFS_DEFAULT_UID 0 
+#define ASFS_DEFAULT_GID 0
+#define ASFS_DEFAULT_MODE 0444 /* default permission bits for files, dirs have same permission, but with "x" set */ 
+
+#define ASFS_STRUCTURE_VERISON (3)
+
+#define OTYPE_HIDDEN      (1)
+#define OTYPE_LINK        (64)
+#define OTYPE_DIR         (128)
+
+#define MSB_MASK (1ul << 31)
+
+/* Each block has its own header with checksum and id, its called fsBlockHeader */
+
+struct fsBlockHeader {
+	u32 id;				/* 4 character id string of this block */
+	u32 checksum;			/* The checksum */
+	u32 ownblock;			/* The blocknumber of the block this block is stored at */
+};
+
+/* On-disk "super block", called fsRootBlock */
+
+struct fsRootBlock {
+	struct fsBlockHeader bheader;
+
+	u16 version;			/* Version number of the filesystem block structure */
+	u16 sequencenumber;		/* The Root with the highest sequencenumber is valid */
+
+	u32 datecreated;		/* Creation date (when first formatted).  Cannot be changed. */
+	u8 bits;			/* various settings, see defines below. */
+	u8 pad1;
+	u16 pad2;
+
+	u32 reserved1[2];
+
+	u64 firstbyte;			/* The first byte of our partition from the start of the disk. */
+
+	u64 lastbyte;			/* The last byte of our partition, excluding this one. */
+
+	u32 totalblocks;		/* size of this partition in blocks */
+	u32 blocksize;			/* blocksize used */
+
+	u32 reserved2[2];
+	u32 reserved3[8];
+
+	u32 bitmapbase;			/* location of the bitmap */
+	u32 adminspacecontainer;	/* location of first adminspace container */
+	u32 rootobjectcontainer;	/* location of the root objectcontainer */
+	u32 extentbnoderoot;		/* location of the root of the extentbnode B-tree */
+	u32 objectnoderoot;		/* location of the root of the objectnode tree */
+
+	u32 reserved4[3];
+};
+
+/* On disk inode, called fsObject */
+
+struct fsObject {
+	u16 owneruid;
+	u16 ownergid;
+	u32 objectnode;
+	u32 protection;
+
+	union {
+		struct {
+			u32 data;
+			u32 size;
+		} file;
+
+		struct {
+			u32 hashtable;	/* for directories & root, 0 means no hashblock */
+			u32 firstdirblock;
+		} dir;
+	} object;
+
+	u32 datemodified;
+	u8 bits;
+
+	u8 name[0];
+	u8 comment[0];
+};
+
+/* On disk block containging a number of fsObjects */
+
+struct fsObjectContainer {
+	struct fsBlockHeader bheader;
+
+	u32 parent;
+	u32 next;
+	u32 previous;			/* 0 for the first block in the directory chain */
+
+	struct fsObject object[0];
+};
+
+/* BTree structures, used to collect file data position on disk */
+
+struct fsExtentBNode {
+	u32 key;			/* data! */
+	u32 next;
+	u32 prev;
+	u16 blocks;			/* The size in blocks of the region this Extent controls */
+};
+
+struct BNode {
+	u32 key;
+	u32 data;
+};
+
+struct BTreeContainer {
+	u16 nodecount;
+	u8 isleaf;
+	u8 nodesize;			/* Must be a multiple of 2 */
+
+	struct BNode bnode[0];
+};
+
+/* On disk block with BTreeContainer */
+
+struct fsBNodeContainer {
+	struct fsBlockHeader bheader;
+	struct BTreeContainer btc;
+};
+
+#ifdef __KERNEL__
+
+/* Not much now */
+
+#endif /* __KERNEL__ */
+#endif
diff -Naur linux-2.4.26/include/linux/asfs_fs_i.h linux-2.4.26-m68k/include/linux/asfs_fs_i.h
--- linux-2.4.26/include/linux/asfs_fs_i.h	1970-01-01 10:00:00.000000000 +1000
+++ linux-2.4.26-m68k/include/linux/asfs_fs_i.h	2003-07-01 05:16:14.000000000 +1000
@@ -0,0 +1,12 @@
+#ifndef __ASFS_FS_I
+#define __ASFS_FS_I
+
+/* inode in-kernel data */
+
+struct asfs_inode_info {
+	u32 firstdirblock;
+	u32 firstdatablock;
+	u32 hashtable;
+};
+
+#endif
diff -Naur linux-2.4.26/include/linux/asfs_fs_sb.h linux-2.4.26-m68k/include/linux/asfs_fs_sb.h
--- linux-2.4.26/include/linux/asfs_fs_sb.h	1970-01-01 10:00:00.000000000 +1000
+++ linux-2.4.26-m68k/include/linux/asfs_fs_sb.h	2003-07-01 05:16:14.000000000 +1000
@@ -0,0 +1,15 @@
+#ifndef __ASFS_FS_SB
+#define __ASFS_FS_SB
+
+/* Amiga SFS superblock in-core data */
+
+struct asfs_sb_info {
+	u32 totalblocks;
+	u32 rootobjectcontainer;
+	u32 extentbnoderoot;
+	uid_t uid;
+	gid_t gid;
+	umode_t mode;
+};
+
+#endif
diff -Naur linux-2.4.26/include/linux/bootmem.h linux-2.4.26-m68k/include/linux/bootmem.h
--- linux-2.4.26/include/linux/bootmem.h	2002-11-29 10:53:15.000000000 +1100
+++ linux-2.4.26-m68k/include/linux/bootmem.h	2002-12-01 01:59:10.000000000 +1100
@@ -38,11 +38,11 @@
 #define alloc_bootmem(x) \
 	__alloc_bootmem((x), SMP_CACHE_BYTES, __pa(MAX_DMA_ADDRESS))
 #define alloc_bootmem_low(x) \
-	__alloc_bootmem((x), SMP_CACHE_BYTES, 0)
+	__alloc_bootmem((x), SMP_CACHE_BYTES, __pa(PAGE_OFFSET))
 #define alloc_bootmem_pages(x) \
 	__alloc_bootmem((x), PAGE_SIZE, __pa(MAX_DMA_ADDRESS))
 #define alloc_bootmem_low_pages(x) \
-	__alloc_bootmem((x), PAGE_SIZE, 0)
+	__alloc_bootmem((x), PAGE_SIZE, __pa(PAGE_OFFSET))
 extern unsigned long __init free_all_bootmem (void);
 
 extern unsigned long __init init_bootmem_node (pg_data_t *pgdat, unsigned long freepfn, unsigned long startpfn, unsigned long endpfn);
diff -Naur linux-2.4.26/include/linux/fs.h linux-2.4.26-m68k/include/linux/fs.h
--- linux-2.4.26/include/linux/fs.h	2004-02-19 00:36:32.000000000 +1100
+++ linux-2.4.26-m68k/include/linux/fs.h	2004-02-19 09:19:03.000000000 +1100
@@ -307,6 +307,7 @@
 #include <linux/nfs_fs_i.h>
 #include <linux/sysv_fs_i.h>
 #include <linux/affs_fs_i.h>
+#include <linux/asfs_fs_i.h>
 #include <linux/ufs_fs_i.h>
 #include <linux/efs_fs_i.h>
 #include <linux/coda_fs_i.h>
@@ -502,6 +503,7 @@
 		struct nfs_inode_info		nfs_i;
 		struct sysv_inode_info		sysv_i;
 		struct affs_inode_info		affs_i;
+		struct asfs_inode_info		asfs_i;
 		struct ufs_inode_info		ufs_i;
 		struct efs_inode_info		efs_i;
 		struct romfs_inode_info		romfs_i;
@@ -719,6 +721,7 @@
 #include <linux/nfs_fs_sb.h>
 #include <linux/sysv_fs_sb.h>
 #include <linux/affs_fs_sb.h>
+#include <linux/asfs_fs_sb.h>
 #include <linux/ufs_fs_sb.h>
 #include <linux/efs_fs_sb.h>
 #include <linux/romfs_fs_sb.h>
@@ -777,6 +780,7 @@
 		struct nfs_sb_info	nfs_sb;
 		struct sysv_sb_info	sysv_sb;
 		struct affs_sb_info	affs_sb;
+		struct asfs_sb_info	asfs_sb;
 		struct ufs_sb_info	ufs_sb;
 		struct efs_sb_info	efs_sb;
 		struct shmem_sb_info	shmem_sb;
diff -Naur linux-2.4.26/include/linux/module.h linux-2.4.26-m68k/include/linux/module.h
--- linux-2.4.26/include/linux/module.h	2004-04-14 23:05:40.000000000 +1000
+++ linux-2.4.26-m68k/include/linux/module.h	2004-05-04 21:21:50.000000000 +1000
@@ -284,7 +284,7 @@
  */
  
 #define MODULE_LICENSE(license) 	\
-static const char __module_license[] __attribute__((section(".modinfo"))) =   \
+static const char __module_license[] __attribute_used__ __attribute__((section(".modinfo"))) =   \
 "license=" license
 
 /* Define the module variable, and usage macros.  */
@@ -296,10 +296,10 @@
 #define MOD_IN_USE		__MOD_IN_USE(THIS_MODULE)
 
 #include <linux/version.h>
-static const char __module_kernel_version[] __attribute__((section(".modinfo"))) =
+static const char __module_kernel_version[] __attribute_used__ __attribute__((section(".modinfo"))) =
 "kernel_version=" UTS_RELEASE;
 #ifdef MODVERSIONS
-static const char __module_using_checksums[] __attribute__((section(".modinfo"))) =
+static const char __module_using_checksums[] __attribute_used__ __attribute__((section(".modinfo"))) =
 "using_checksums=1";
 #endif
 
diff -Naur linux-2.4.26/include/linux/pc_keyb.h linux-2.4.26-m68k/include/linux/pc_keyb.h
--- linux-2.4.26/include/linux/pc_keyb.h	1999-10-12 03:15:40.000000000 +1000
+++ linux-2.4.26-m68k/include/linux/pc_keyb.h	2003-07-22 07:33:33.000000000 +1000
@@ -14,7 +14,11 @@
 #define KBD_REPORT_UNKN			/* Report unknown scan codes */
 #define KBD_REPORT_TIMEOUTS		/* Report keyboard timeouts */
 #undef KBD_IS_FOCUS_9000		/* We have the brain-damaged FOCUS-9000 keyboard */
+#ifndef CONFIG_TEKXP
 #undef INITIALIZE_MOUSE			/* Define if your PS/2 mouse needs initialization. */
+#else
+#define INITIALIZE_MOUSE 1
+#endif
 
 
 
diff -Naur linux-2.4.26/kernel/ptrace.c linux-2.4.26-m68k/kernel/ptrace.c
--- linux-2.4.26/kernel/ptrace.c	2003-08-25 21:44:44.000000000 +1000
+++ linux-2.4.26-m68k/kernel/ptrace.c	2003-08-26 13:18:26.000000000 +1000
@@ -165,7 +165,7 @@
 		if (write) {
 			memcpy(maddr + offset, buf, bytes);
 			flush_page_to_ram(page);
-			flush_icache_user_range(vma, page, addr, len);
+			flush_icache_user_page(vma, page, addr, len);
 			set_page_dirty(page);
 		} else {
 			memcpy(buf, maddr + offset, bytes);
diff -Naur linux-2.4.26/mm/bootmem.c linux-2.4.26-m68k/mm/bootmem.c
--- linux-2.4.26/mm/bootmem.c	2002-11-29 10:53:15.000000000 +1100
+++ linux-2.4.26-m68k/mm/bootmem.c	2002-12-01 01:59:34.000000000 +1100
@@ -244,7 +244,7 @@
 
 static unsigned long __init free_all_bootmem_core(pg_data_t *pgdat)
 {
-	struct page *page = pgdat->node_mem_map;
+	struct page *page;
 	bootmem_data_t *bdata = pgdat->bdata;
 	unsigned long i, count, total = 0;
 	unsigned long idx;
@@ -253,8 +253,10 @@
 
 	count = 0;
 	idx = bdata->node_low_pfn - (bdata->node_boot_start >> PAGE_SHIFT);
-	for (i = 0; i < idx; i++, page++) {
+	for (i = 0; i < idx; i++) {
 		if (!test_bit(i, bdata->node_bootmem_map)) {
+			page = virt_to_page(phys_to_virt((i << PAGE_SHIFT) +
+							 bdata->node_boot_start));
 			count++;
 			ClearPageReserved(page);
 			set_page_count(page, 1);
diff -Naur linux-2.4.26/mm/page_alloc.c linux-2.4.26-m68k/mm/page_alloc.c
--- linux-2.4.26/mm/page_alloc.c	2004-02-19 00:36:32.000000000 +1100
+++ linux-2.4.26-m68k/mm/page_alloc.c	2004-02-19 09:19:12.000000000 +1100
@@ -720,7 +720,7 @@
  *   - clear the memory bitmaps
  */
 void __init free_area_init_core(int nid, pg_data_t *pgdat, struct page **gmap,
-	unsigned long *zones_size, unsigned long zone_start_paddr, 
+	unsigned long *zones_size, unsigned long zone_start_vaddr, 
 	unsigned long *zholes_size, struct page *lmem_map)
 {
 	unsigned long i, j;
@@ -728,7 +728,7 @@
 	unsigned long totalpages, offset, realtotalpages;
 	const unsigned long zone_required_alignment = 1UL << (MAX_ORDER-1);
 
-	if (zone_start_paddr & ~PAGE_MASK)
+	if (zone_start_vaddr & ~PAGE_MASK)
 		BUG();
 
 	totalpages = 0;
@@ -758,7 +758,7 @@
 	}
 	*gmap = pgdat->node_mem_map = lmem_map;
 	pgdat->node_size = totalpages;
-	pgdat->node_start_paddr = zone_start_paddr;
+	pgdat->node_start_paddr = __pa(zone_start_vaddr);
 	pgdat->node_start_mapnr = (lmem_map - mem_map);
 	pgdat->nr_zones = 0;
 
@@ -835,9 +835,9 @@
 
 		zone->zone_mem_map = mem_map + offset;
 		zone->zone_start_mapnr = offset;
-		zone->zone_start_paddr = zone_start_paddr;
+		zone->zone_start_paddr = __pa(zone_start_vaddr);
 
-		if ((zone_start_paddr >> PAGE_SHIFT) & (zone_required_alignment-1))
+		if ((zone_start_vaddr >> PAGE_SHIFT) & (zone_required_alignment-1))
 			printk("BUG: wrong zone alignment, it will crash\n");
 
 		/*
@@ -852,8 +852,9 @@
 			SetPageReserved(page);
 			INIT_LIST_HEAD(&page->list);
 			if (j != ZONE_HIGHMEM)
-				set_page_address(page, __va(zone_start_paddr));
-			zone_start_paddr += PAGE_SIZE;
+				set_page_address(page,
+						 (void *)zone_start_vaddr);
+			zone_start_vaddr += PAGE_SIZE;
 		}
 
 		offset += size;
@@ -900,7 +901,7 @@
 
 void __init free_area_init(unsigned long *zones_size)
 {
-	free_area_init_core(0, &contig_page_data, &mem_map, zones_size, 0, 0, 0);
+	free_area_init_core(0, &contig_page_data, &mem_map, zones_size, PAGE_OFFSET, 0, 0);
 }
 
 static int __init setup_mem_frac(char *str)
