diff -ruN linux-2.4.26.org/arch/m32r/Makefile linux-2.4.26/arch/m32r/Makefile
--- linux-2.4.26.org/arch/m32r/Makefile	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/arch/m32r/Makefile	2004-01-21 18:15:45.000000000 +0900
@@ -0,0 +1,133 @@
+# $Id: Makefile,v 1.18 2004/01/21 09:15:45 takata Exp $
+
+#
+# m32r/Makefile
+#
+# This file is included by the global makefile so that you can add your own
+# architecture-specific flags and dependencies. Remember to do have actions
+# for "archclean" and "archdep" for cleaning up and making dependencies for
+# this architecture
+#
+# 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.
+#
+# Copyright (C) 1994  Linus Torvalds
+# Copyright (C) 1999  Kaz Kojima
+# Copyright (C) 2001  Hiroyuki Kondo, Hirokazu Takata, and Hitoshi Yamamoto
+#
+
+#
+# Select the object file format to substitute into the linker script.
+#
+ifdef CONFIG_CPU_LITTLE_ENDIAN
+tool_prefix	= m32rle-linux-
+else
+tool_prefix	= m32r-linux-
+endif
+
+CFLAGS := $(CFLAGS) -pipe -g -fno-schedule-insns
+
+CFLAGS_KERNEL += -mmodel=medium
+
+ifndef CONFIG_HAVE_M32R_MMU
+CFLAGS := $(CFLAGS) -DNO_MM
+AFLAGS := $(AFLAGS) -DNO_MM
+endif
+
+ifdef CONFIG_ISA_M32R2
+# M32700, XNUX2
+CFLAGS := $(CFLAGS) -DNO_FPU -m32r2
+AFLAGS := $(AFLAGS) -DNO_FPU -m32r2
+else
+# VDEC2
+CFLAGS := $(CFLAGS) -DNO_FPU -m32r -Wa,-bitinst
+AFLAGS := $(AFLAGS) -DNO_FPU -m32r -Wa,-bitinst
+endif
+
+# ifdef CONFIG_CROSSCOMPILE
+CROSS_COMPILE = $(tool_prefix)
+# endif
+
+LD	= $(CROSS_COMPILE)ld $(LDFLAGS)
+OBJDUMP	= $(CROSS_COMPILE)objdump
+OBJCOPY	= $(CROSS_COMPILE)objcopy -O binary \
+	-R .note -R .comment -R .stab -R .stabstr -S
+
+MODFLAGS	+= -mmodel=large -fno-builtin
+
+#
+# Choosing incompatible machines durings configuration will result in
+# error messages during linking.  Select a default linkscript if
+# none has been choosen above.
+#
+LINKSCRIPT	= arch/m32r/vmlinux.lds
+LINKFLAGS	+= -T $(word 1,$(LINKSCRIPT)) -e _stext
+
+ifdef LOADADDR
+LINKFLAGS	+= -Ttext $(word 1,$(LOADADDR))
+endif
+
+HEAD := arch/m32r/kernel/head.o arch/m32r/kernel/init_task.o
+
+SUBDIRS := $(SUBDIRS) $(addprefix arch/m32r/, kernel mm lib boot)
+CORE_FILES := arch/m32r/boot/boot.o arch/m32r/kernel/kernel.o \
+  arch/m32r/mm/mm.o $(CORE_FILES)
+
+LIBGCC := $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
+LIBS := $(TOPDIR)/arch/m32r/lib/lib.a $(LIBS) $(LIBGCC)
+
+ifdef CONFIG_MATH_EMULATION
+SUBDIRS += arch/m32r/math-emu
+DRIVERS += arch/m32r/math-emu/math.o
+endif
+
+SUBDIRS	+= arch/m32r/drivers
+DRIVERS += arch/m32r/drivers/m32r_drivers.o
+
+MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
+
+vmlinux.lis: vmlinux
+	$(OBJDUMP) -DS vmlinux >vmlinux.lis
+
+vmlinux.mot: vmlinux
+	$(OBJCOPY) -O srec vmlinux vmlinux.mot
+
+vmlinux: arch/m32r/vmlinux.lds
+
+arch/m32r/vmlinux.lds: arch/m32r/vmlinux.lds.S FORCE
+	$(CPP) $(AFLAGS) -traditional -C -P -I$(HPATH) \
+	    arch/m32r/vmlinux.lds.S >arch/m32r/vmlinux.lds
+
+FORCE: ;
+
+.PHONY: zImage bzImage compressed zdisk bzdisk install \
+		clean archclean archmrproper archdep
+
+zImage: vmlinux
+	@$(MAKEBOOT) zImage
+
+bzImage: vmlinux
+	@$(MAKEBOOT) bzImage
+
+compressed: zImage
+
+zdisk: vmlinux
+	@$(MAKEBOOT) BOOTIMAGE=zImage zdisk
+
+bzdisk: vmlinux
+	@$(MAKEBOOT) BOOTIMAGE=bzImage zdisk
+
+install: vmlinux
+	@$(MAKEBOOT) BOOTIMAGE=bzImage install
+
+archclean:
+	@$(MAKEBOOT) clean
+	$(MAKE) -C arch/$(ARCH)/kernel clean
+#	$(MAKE) -C arch/$(ARCH)/tools clean
+
+archmrproper:
+	rm -f arch/m32r/vmlinux.lds
+
+archdep:
+	@$(MAKEBOOT) dep
diff -ruN linux-2.4.26.org/arch/m32r/boot/Makefile linux-2.4.26/arch/m32r/boot/Makefile
--- linux-2.4.26.org/arch/m32r/boot/Makefile	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/arch/m32r/boot/Makefile	2003-12-17 10:10:26.000000000 +0900
@@ -0,0 +1,42 @@
+#
+# arch/m32r/boot/Makefile
+#
+# 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.
+#
+#
+
+.S.o:
+	$(CC) $(AFLAGS) -traditional -c $< -o $*.o
+
+all:	boot.o
+
+O_TARGET := boot.o
+
+obj-y	:= setup.o
+
+SYSTEM  =$(TOPDIR)/vmlinux
+
+Image:	$(SYSTEM)
+	$(OBJCOPY) $(SYSTEM) Image
+
+zImage: compressed/vmlinux
+	$(OBJCOPY) compressed/vmlinux zImage
+
+compressed/vmlinux: $(TOPDIR)/vmlinux
+	$(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" -C compressed vmlinux
+
+install: Image
+	sh -x ./install.sh $(KERNELRELEASE) Image $(TOPDIR)/System.map "$(INSTALL_PATH)"
+
+zinstall: zImage
+	sh -x ./install.sh $(KERNELRELEASE) zImage $(TOPDIR)/System.map "$(INSTALL_PATH)"
+
+dep:
+
+clean:
+	rm -f zImage
+	@$(MAKE) -C compressed clean
+
+include $(TOPDIR)/Rules.make
diff -ruN linux-2.4.26.org/arch/m32r/boot/compressed/Makefile linux-2.4.26/arch/m32r/boot/compressed/Makefile
--- linux-2.4.26.org/arch/m32r/boot/compressed/Makefile	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/arch/m32r/boot/compressed/Makefile	2004-01-21 03:20:52.000000000 +0900
@@ -0,0 +1,38 @@
+#
+# linux/arch/m32r/boot/compressed/Makefile
+#
+# create a compressed vmlinux image from the original vmlinux
+#
+
+.S.o:
+	$(CC) $(AFLAGS) -traditional -c $< -o $*.o
+
+HEAD = head.o
+SYSTEM = $(TOPDIR)/vmlinux
+
+OBJECTS = $(HEAD) misc.o m32r_sio.o
+
+ZLDFLAGS = -e startup
+ZLINKFLAGS = $(ZLDFLAGS)
+
+all: vmlinux
+
+vmlinux: piggy.o $(OBJECTS) vmlinux.lds
+	$(LD) $(ZLINKFLAGS) -o vmlinux $(OBJECTS) piggy.o -T vmlinux.lds
+
+piggy.o: $(SYSTEM)
+	$(OBJCOPY) $(SYSTEM) piggy
+	gzip -f -9 < piggy > piggy.gz
+	$(LD) -r -o $@ -b binary piggy.gz
+
+vmlinux.lds: vmlinux.lds.S FORCE
+	$(CPP) $(AFLAGS) -traditional -C -P -I$(HPATH) \
+	    vmlinux.lds.S > vmlinux.lds
+
+FORCE: ;
+
+clean:
+	rm -f vmlinux vmlinux.lds piggy piggy.o piggy.gz $(OBJECTS)
+
+include $(TOPDIR)/Rules.make
+
diff -ruN linux-2.4.26.org/arch/m32r/boot/compressed/boot.h linux-2.4.26/arch/m32r/boot/compressed/boot.h
--- linux-2.4.26.org/arch/m32r/boot/compressed/boot.h	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/arch/m32r/boot/compressed/boot.h	2003-03-31 11:31:16.000000000 +0900
@@ -0,0 +1,59 @@
+/*
+ * 1. load vmlinuz
+ *
+ * CONFIG_MEMORY_START  	+-----------------------+
+ *				|        vmlinuz	|
+ *				+-----------------------+
+ * 2. decompressed
+ *
+ * CONFIG_MEMORY_START  	+-----------------------+
+ *				|        vmlinuz	|
+ *				+-----------------------+
+ *				|			|
+ * BOOT_RELOC_ADDR		+-----------------------+
+ *				|		 	|
+ * KERNEL_DECOMPRESS_ADDR 	+-----------------------+
+ *				|  	vmlinux		|
+ *				+-----------------------+
+ *
+ * 3. relocate copy & jump code
+ *		
+ * CONFIG_MEMORY_START  	+-----------------------+
+ *				|        vmlinuz	|
+ *				+-----------------------+
+ *				|			|
+ * BOOT_RELOC_ADDR		+-----------------------+
+ *				|    boot(copy&jump)	|
+ * KERNEL_DECOMPRESS_ADDR 	+-----------------------+
+ *				|  	vmlinux		|
+ *				+-----------------------+
+ *
+ * 4. relocate decompressed kernel
+ *
+ * CONFIG_MEMORY_START  	+-----------------------+
+ *				|        vmlinux	|
+ *				+-----------------------+
+ *				|			|
+ * BOOT_RELOC_ADDR		+-----------------------+
+ *				|     boot(copy&jump) 	|
+ * KERNEL_DECOMPRESS_ADDR 	+-----------------------+
+ *				|  			|
+ *				+-----------------------+
+ *
+ */
+#ifdef __ASSEMBLY__
+#define __val(x)	x
+#else
+#define __val(x)	(x)
+#endif
+
+#define DECOMPRESS_OFFSET_BASE	__val(0x00900000)
+#define BOOT_RELOC_SIZE		__val(0x00001000)
+
+#define KERNEL_EXEC_ADDR	__val(CONFIG_MEMORY_START)
+#define KERNEL_DECOMPRESS_ADDR	__val(CONFIG_MEMORY_START + \
+				      DECOMPRESS_OFFSET_BASE + BOOT_RELOC_SIZE)
+#define KERNEL_ENTRY		__val(CONFIG_MEMORY_START + 0x1000)
+
+#define BOOT_EXEC_ADDR		__val(CONFIG_MEMORY_START)
+#define BOOT_RELOC_ADDR		__val(CONFIG_MEMORY_START + DECOMPRESS_OFFSET_BASE)
diff -ruN linux-2.4.26.org/arch/m32r/boot/compressed/head.S linux-2.4.26/arch/m32r/boot/compressed/head.S
--- linux-2.4.26.org/arch/m32r/boot/compressed/head.S	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/arch/m32r/boot/compressed/head.S	2004-06-01 13:04:21.000000000 +0900
@@ -0,0 +1,209 @@
+/*
+ *  linux/arch/m32r/boot/compressed/head.S
+ *
+ *  Copyright (c) 2001-2003	Hiroyuki Kondo, Hirokazu Takata,
+ *				Hitoshi Yamamoto, Takeo Takahashi
+ */
+
+	.text
+#include <linux/config.h>
+#include <linux/linkage.h>
+#include <asm/addrspace.h>
+#include <asm/page.h>
+#include <asm/assembler.h>
+#include "boot.h"
+
+	.global	startup
+startup:
+	ldi	r0, #0x0000			/* SPI, disable EI */
+	mvtc	r0, psw
+
+/*
+ * Clear BSS first so that there are no surprises...
+ */
+#ifdef CONFIG_ISA_DUAL_ISSUE
+
+	LDIMM	(r2, SYMBOL_NAME(__bss_start))
+	LDIMM	(r3, SYMBOL_NAME(_end))
+	sub	r3, r2		; BSS size in bytes
+	; R4 = BSS size in longwords (rounded down)
+	mv	r4, r3		    ||	ldi	r1, #0
+	srli	r4, #4		    ||	addi	r2, #-4	
+	beqz	r4, .Lendloop1
+.Lloop1:	
+#ifndef CONFIG_CHIP_M32310
+	; Touch memory for the no-write-allocating cache.
+	ld	r0, @(4,r2)
+#endif
+	st	r1, @+r2	    ||	addi	r4, #-1
+	st	r1, @+r2
+	st	r1, @+r2
+	st	r1, @+r2	    ||	cmpeq	r1, r4	; R4 = 0?
+	bnc	.Lloop1
+.Lendloop1:
+	and3	r4, r3, #15
+	addi	r2, #4
+	beqz	r4, .Lendloop2
+.Lloop2:
+	stb	r1, @r2		    ||	addi	r4, #-1
+	addi	r2, #1
+	bnez	r4, .Lloop2
+.Lendloop2:
+
+#else /* not CONFIG_ISA_DUAL_ISSUE */
+
+	LDIMM	(r2, SYMBOL_NAME(__bss_start))
+	LDIMM	(r3, SYMBOL_NAME(_end))
+	sub	r3, r2		; BSS size in bytes
+	mv	r4, r3
+	srli	r4, #2		; R4 = BSS size in longwords (rounded down)
+	ldi	r1, #0		; clear R1 for longwords store
+	addi	r2, #-4		; account for pre-inc store
+	beqz	r4, .Lendloop1	; any more to go?
+.Lloop1:	
+	st	r1, @+r2	; yep, zero out another longword
+	addi	r4, #-1		; decrement count
+	bnez	r4, .Lloop1	; go do some more
+.Lendloop1:
+	and3	r4, r3, #3	; get no. of remaining BSS bytes to clear
+	addi	r2, #4		; account for pre-inc store
+	beqz	r4, .Lendloop2	; any more to go?
+.Lloop2:
+	stb	r1, @r2		; yep, zero out another byte
+	addi	r2, #1		; bump address
+	addi	r4, #-1		; decrement count
+	bnez	r4, .Lloop2	; go do some more
+.Lendloop2:		
+
+#endif /* not CONFIG_ISA_DUAL_ISSUE */
+
+	seth	r0, #shigh(stack_start)
+	ld	sp, @(r0, low(stack_start))	/* set stack point */
+
+/*
+ * decompress the kernel
+ */
+	bl	decompress_kernel
+	mv	r12, r0 		/* size of decompressed kernel */
+
+/*
+ * relocate copy routine & jump routine
+ */
+	LDIMM	(r1, BOOT_RELOC_ADDR)
+	mv	r5, r1		; save reloc addr to jump
+
+	LDIMM	(r2, SYMBOL_NAME(startup_reloc))
+	LDIMM	(r3, SYMBOL_NAME(exit_reloc))
+	sub	r3, r2		; relocated code size in bytes
+	mv	r4, r3
+	srli	r4, #2		; R4 = code size in longwords (rounded down)
+	addi	r1, #-4		; account for pre-inc store
+	beqz	r4, 2f		; any more to go?
+	.fillinsn
+1:	
+	ld	r6, @r2+	; code to be relocated
+	st	r6, @+r1	; relocate code
+	addi	r4, #-1		; decrement count
+	bnez	r4, 1b		; go do some more
+	.fillinsn
+2:
+	and3	r4, r3, #3	; get no. of remaining bytes
+	addi	r1, #4		; account for pre-inc store
+	beqz	r4, 4f		; any more to go?
+	.fillinsn
+3:
+	ldb	r6, @r2		; code to be relocated
+	stb	r6, @r1		; relocate code
+	addi	r1, #1		; bump address
+	addi	r2, #1		; bump address
+	addi	r4, #-1		; decrement count
+	bnez	r4, 3b		; go do some more
+	.fillinsn
+4:		
+	jmp	r5		; jump to relocated code
+
+/*
+ * startup_reloc runs on BOOT_RELOC_ADDR.
+ * copy decompressed kernel to original location
+ */
+	.text
+	__ALIGN
+startup_reloc:
+	LDIMM	(r1, CONFIG_MEMORY_START)
+	LDIMM	(r2, KERNEL_DECOMPRESS_ADDR)
+	mv	r4, r12		; r12 holds size of decompressed kernel
+	srli	r4, #2		; R4 = code size in longwords (rounded down)
+	addi	r1, #-4		; account for pre-inc store
+	beqz	r4, 2f		; any more to go?
+	.fillinsn
+1:	
+	ld	r6, @r2+	; code to be relocated
+	st	r6, @+r1	; relocate code
+	addi	r4, #-1		; decrement count
+	bnez	r4, 1b		; go do some more
+	.fillinsn
+2:
+	and3	r4, r12, #3	; get no. of remaining bytes
+	addi	r1, #4		; account for pre-inc store
+	beqz	r4, 4f		; any more to go?
+	.fillinsn
+3:
+	ldb	r6, @r2		; code to be relocated
+	stb	r6, @r1		; relocate code
+	addi	r1, #1		; bump address
+	addi	r2, #1		; bump address
+	addi	r4, #-1		; decrement count
+	bnez	r4, 3b		; go do some more
+	.fillinsn
+4:		
+	/*
+	 * invalidate i-cache before jump to kernel
+	 */
+#if defined(CONFIG_CHIP_XNUX)
+	ldi	r0, #-2
+	ldi	r1, #0x0100	; invalidate
+	sth	r1, @r0
+#elif defined(CONFIG_CHIP_XNUX2)
+	ldi	r0, #-2
+	ldi	r1, #0x0100	; invalidate
+	sth	r1, @r0
+#elif defined(CONFIG_CHIP_M32700)
+	ldi	r0, #-1		; MCCR(cache control register)
+	ldi	r1, #0xc0	; invalidate i-cache
+	stb	r1, @r0
+#elif defined(CONFIG_CHIP_M32310)
+	ldi	r0, #-1
+	ldi	r1, #0xc0	; invalidate i-cache
+	stb	r1, #r0
+#elif defined(CONFIG_CHIP_NUX)
+	ldi	r0, #-1
+	ldi	r1, #0xc0	; invalidate i-cache
+	stb	r1, @r0
+#else
+#error unknown chip configuration
+#endif
+	LDIMM	(r0, KERNEL_ENTRY)
+	jmp	r0				/* jump to kernel */
+
+	__ALIGN
+exit_reloc:
+
+	.balign 4096
+.fake_empty_zero_page:
+	/* FIXME: correct table value */
+	.word	0
+	.ascii	"HdrS"
+	.word	0x0202
+	.word	0
+	.word	0
+	.word	0x1000
+	.word	0
+	.byte	0
+	.byte	1
+	.word	0x8000
+	.long	0
+	.long	0
+
+	.section	.fake_eit_vector, "aw"
+	.long	0
+
diff -ruN linux-2.4.26.org/arch/m32r/boot/compressed/m32r_sio.c linux-2.4.26/arch/m32r/boot/compressed/m32r_sio.c
--- linux-2.4.26.org/arch/m32r/boot/compressed/m32r_sio.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/arch/m32r/boot/compressed/m32r_sio.c	2003-09-16 19:24:21.000000000 +0900
@@ -0,0 +1,45 @@
+/*
+ * arch/m32r/boot/compressed/m32r_sio.c
+ * 
+ * 2003-02-12:	Takeo Takahashi
+ *
+ */
+
+#include <linux/config.h>
+#include <asm/m32r.h>
+#include <asm/io.h>
+
+void putc(char c);
+
+void puts(char *s)
+{
+	char c;
+	while ((c = *s++)) putc(c);
+}
+
+#if defined(CONFIG_PLAT_M32700UT_Alpha) || defined(CONFIG_PLAT_M32700UT)
+
+#if defined(CONFIG_PLAT_M32700UT_Alpha)
+#define BOOT_SIO0STS	(volatile unsigned short *)(0x02c00000 + 0x20006)
+#define BOOT_SIO0TXB	(volatile unsigned short *)(0x02c00000 + 0x2000c)
+#elif defined(CONFIG_PLAT_M32700UT)
+#define BOOT_SIO0STS	PLD_ESIO0STS
+#define BOOT_SIO0TXB	PLD_ESIO0TXB
+#endif
+
+void putc(char c)
+{
+
+	while ((*BOOT_SIO0STS & 0x3) != 0x3) ;
+	if (c == '\n') {
+		*BOOT_SIO0TXB = '\r';
+		while ((*BOOT_SIO0STS & 0x3) != 0x3) ;
+	}
+	*BOOT_SIO0TXB = c;
+}
+#else
+void putc(char c)
+{
+	/* do nothing */
+}
+#endif
diff -ruN linux-2.4.26.org/arch/m32r/boot/compressed/misc.c linux-2.4.26/arch/m32r/boot/compressed/misc.c
--- linux-2.4.26.org/arch/m32r/boot/compressed/misc.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/arch/m32r/boot/compressed/misc.c	2003-03-31 11:31:16.000000000 +0900
@@ -0,0 +1,224 @@
+/*
+ * arch/m32r/boot/compressed/misc.c
+ * 
+ * This is a collection of several routines from gzip-1.0.3 
+ * adapted for Linux.
+ *
+ * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
+ *
+ * Adapted for SH by Stuart Menefy, Aug 1999
+ *
+ * Modified to use standard LinuxSH BIOS by Greg Banks 7Jul2000
+ *
+ * 2003-02-12:	Support M32R by Takeo Takahashi
+ * 		This is based on arch/sh/boot/compressed/misc.c.
+ */
+
+#include <linux/config.h>
+#include <asm/uaccess.h>
+#include "boot.h"
+
+/*
+ * gzip declarations
+ */
+
+#define OF(args)  args
+#define STATIC static
+
+#undef memset
+#undef memcpy
+#define memzero(s, n)     memset ((s), 0, (n))
+
+typedef unsigned char  uch;
+typedef unsigned short ush;
+typedef unsigned long  ulg;
+
+#define WSIZE 0x8000		/* Window size must be at least 32k, */
+				/* and a power of two */
+
+static uch *inbuf;	     /* input buffer */
+static uch window[WSIZE];    /* Sliding window buffer */
+
+static unsigned insize;  /* valid bytes in inbuf */
+static unsigned inptr;   /* index of next byte to be processed in inbuf */
+static unsigned outcnt;  /* bytes in output buffer */
+
+/* gzip flag byte */
+#define ASCII_FLAG   0x01 /* bit 0 set: file probably ASCII text */
+#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
+#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
+#define COMMENT      0x10 /* bit 4 set: file comment present */
+#define ENCRYPTED    0x20 /* bit 5 set: file is encrypted */
+#define RESERVED     0xC0 /* bit 6,7:   reserved */
+
+#define get_byte()  (inptr < insize ? inbuf[inptr++] : fill_inbuf())
+		
+/* Diagnostic functions */
+#ifdef DEBUG
+#  define Assert(cond,msg) {if(!(cond)) error(msg);}
+#  define Trace(x) fprintf x
+#  define Tracev(x) {if (verbose) fprintf x ;}
+#  define Tracevv(x) {if (verbose>1) fprintf x ;}
+#  define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
+#  define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
+#else
+#  define Assert(cond,msg)
+#  define Trace(x)
+#  define Tracev(x)
+#  define Tracevv(x)
+#  define Tracec(c,x)
+#  define Tracecv(c,x)
+#endif
+
+static int  fill_inbuf(void);
+static void flush_window(void);
+static void error(char *m);
+static void gzip_mark(void **);
+static void gzip_release(void **);
+  
+extern char input_data[];
+extern int input_len;
+
+static long bytes_out;
+static uch *output_data;
+static unsigned long output_ptr;
+
+ 
+static void *malloc(int size);
+static void free(void *where);
+static void error(char *m);
+static void gzip_mark(void **);
+static void gzip_release(void **);
+ 
+extern void puts(const char *);
+  
+extern int _text;		/* Defined in vmlinux.lds.S */
+extern int _end;
+static unsigned long free_mem_ptr;
+static unsigned long free_mem_end_ptr;
+ 
+#define HEAP_SIZE             0x10000
+
+#include "../../../../lib/inflate.c"
+
+static void *malloc(int size)
+{
+	void *p;
+
+	if (size <0) error("Malloc error\n");
+	if (free_mem_ptr == 0) error("Memory error\n");
+
+	free_mem_ptr = (free_mem_ptr + 3) & ~3;	/* Align */
+
+	p = (void *)free_mem_ptr;
+	free_mem_ptr += size;
+
+	if (free_mem_ptr >= free_mem_end_ptr)
+		error("\nOut of memory\n");
+
+	return p;
+}
+
+static void free(void *where)
+{	/* Don't care */
+}
+
+static void gzip_mark(void **ptr)
+{
+	*ptr = (void *) free_mem_ptr;
+}
+
+static void gzip_release(void **ptr)
+{
+	free_mem_ptr = (long) *ptr;
+}
+
+void* memset(void* s, int c, size_t n)
+{
+	int i;
+	char *ss = (char*)s;
+
+	for (i=0;i<n;i++) ss[i] = c;
+	return s;
+}
+
+void* memcpy(void* __dest, __const void* __src,
+			    size_t __n)
+{
+	int i;
+	char *d = (char *)__dest, *s = (char *)__src;
+
+	for (i=0;i<__n;i++) d[i] = s[i];
+	return __dest;
+}
+
+/* ===========================================================================
+ * Fill the input buffer. This is called only when the buffer is empty
+ * and at least one byte is really needed.
+ */
+static int fill_inbuf(void)
+{
+	if (insize != 0) {
+		error("ran out of input data\n");
+	}
+
+	inbuf = input_data;
+	insize = input_len;
+	inptr = 1;
+	return inbuf[0];
+}
+
+/* ===========================================================================
+ * Write the output window window[0..outcnt-1] and update crc and bytes_out.
+ * (Used for the decompressed data only.)
+ */
+static void flush_window(void)
+{
+    ulg c = crc;         /* temporary variable */
+    unsigned n;
+    uch *in, *out, ch;
+    
+    in = window;
+    out = &output_data[output_ptr]; 
+    for (n = 0; n < outcnt; n++) {
+	    ch = *out++ = *in++;
+	    c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
+    }
+    crc = c;
+    bytes_out += (ulg)outcnt;
+    output_ptr += (ulg)outcnt;
+    outcnt = 0;
+}
+
+static void error(char *x)
+{
+	puts("\n\n");
+	puts(x);
+	puts("\n\n -- System halted");
+
+	while(1);	/* Halt */
+}
+
+#define STACK_SIZE (4096)
+long user_stack [STACK_SIZE];
+long* stack_start = &user_stack[STACK_SIZE];
+
+/* return decompressed size */
+long decompress_kernel(void)
+{
+	insize = 0;
+	inptr = 0;
+	bytes_out = 0;
+	outcnt = 0;
+	output_data = 0;
+	output_ptr = (unsigned long)KERNEL_DECOMPRESS_ADDR;
+	free_mem_ptr = (unsigned long)&_end;
+	free_mem_end_ptr = free_mem_ptr + HEAP_SIZE;
+
+	makecrc();
+	puts("Uncompressing Linux... ");
+	gunzip();
+	puts("Ok, booting the kernel.\n");
+	return bytes_out;
+}
diff -ruN linux-2.4.26.org/arch/m32r/boot/compressed/vmlinux.lds.S linux-2.4.26/arch/m32r/boot/compressed/vmlinux.lds.S
--- linux-2.4.26.org/arch/m32r/boot/compressed/vmlinux.lds.S	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/arch/m32r/boot/compressed/vmlinux.lds.S	2003-12-17 10:10:26.000000000 +0900
@@ -0,0 +1,107 @@
+#include <linux/config.h>
+#include <asm/addrspace.h>
+#include <asm/page.h>
+
+OUTPUT_ARCH(m32r)
+ENTRY(startup)
+SECTIONS
+{
+  . = CONFIG_MEMORY_START + 0x00000000;
+  .fake_eit_vector : { *(.fake_eit_vector) }
+  
+  /* boot runs in physical address space */
+  . = ALIGN(4096);
+  _text = .;
+  .text      :
+  {
+    *(.text)
+    *(.fixup)
+    *(.stub)
+    /* .gnu.warning sections are handled specially by elf32.em.  */
+    *(.gnu.warning)
+  } = 0
+  .text.lock : { *(.text.lock) }	/* out-of-line lock text */
+  .rodata : { *(.rodata) }
+  .kstrtab : { *(.kstrtab) }
+  _etext = .;			/* End of text section */
+
+  /* Adjust the address for the data segment.  We want to adjust up to
+     the same address within the page on the next page up.  */
+  . = ALIGN(32) + (. & (32 - 1));
+  .data    :
+  {
+    input_len = .;
+    LONG(input_data_end - input_data)
+    input_data = .;
+    piggy.o(.data)
+    input_data_end = .;
+    misc.o(.data)
+    m32r_sio.o(.data)
+  }
+  /* We want the small data sections together, so single-instruction offsets
+     can access them all, and initialized data all before uninitialized, so
+     we can shorten the on-disk segment size.  */
+  .sdata     : { *(.sdata) *(.sdata.*) }
+  _edata  =  .;
+
+  . = ALIGN(32 / 8);
+  __bss_start = .;		/* BSS */
+  .sbss      : { *(.sbss) *(.scommon) }
+  .bss       :
+  {
+   *(.bss)
+   *(COMMON)
+   /* Align here to ensure that the .bss section occupies space up to
+      _end.  Align after .bss to ensure correct alignment even if the
+      .bss section disappears because there are no input sections.  */
+   . = ALIGN(32 / 8);
+  }
+  . = ALIGN(32 / 8);
+  _end = . ;
+
+  /* When something in the kernel is NOT compiled as a module, the
+   * module cleanup code and data are put into these segments.  Both
+   * can then be thrown away, as cleanup code is never called unless
+   * it's a module.
+   */
+  /DISCARD/ : {
+    *(.text.exit)
+    *(.data.exit)
+    *(.exitcall.exit)
+  }
+
+  /* Stabs debugging sections.  */
+  .stab 0 : { *(.stab) }
+  .stabstr 0 : { *(.stabstr) }
+  .stab.excl 0 : { *(.stab.excl) }
+  .stab.exclstr 0 : { *(.stab.exclstr) }
+  .stab.index 0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment 0 : { *(.comment) }
+  /* DWARF debug sections.
+     Symbols in the DWARF debugging sections are relative to the beginning
+     of the section so we begin them at 0.  */
+  /* DWARF 1 */
+  .debug          0 : { *(.debug) }
+  .line           0 : { *(.line) }
+  /* GNU DWARF 1 extensions */
+  .debug_srcinfo  0 : { *(.debug_srcinfo) }
+  .debug_sfnames  0 : { *(.debug_sfnames) }
+  /* DWARF 1.1 and DWARF 2 */
+  .debug_aranges  0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+  /* DWARF 2 */
+  .debug_info     0 : { *(.debug_info) }
+  .debug_abbrev   0 : { *(.debug_abbrev) }
+  .debug_line     0 : { *(.debug_line) }
+  .debug_frame    0 : { *(.debug_frame) }
+  .debug_str      0 : { *(.debug_str) }
+  .debug_loc      0 : { *(.debug_loc) }
+  .debug_macinfo  0 : { *(.debug_macinfo) }
+  /* SGI/MIPS DWARF 2 extensions */
+  .debug_weaknames 0 : { *(.debug_weaknames) }
+  .debug_funcnames 0 : { *(.debug_funcnames) }
+  .debug_typenames 0 : { *(.debug_typenames) }
+  .debug_varnames  0 : { *(.debug_varnames) }
+  /* These must appear regardless of  .  */
+}
diff -ruN linux-2.4.26.org/arch/m32r/boot/setup.S linux-2.4.26/arch/m32r/boot/setup.S
--- linux-2.4.26.org/arch/m32r/boot/setup.S	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/arch/m32r/boot/setup.S	2004-05-27 13:34:41.000000000 +0900
@@ -0,0 +1,251 @@
+/*
+ *  linux/arch/m32r/boot/setup.S -- A setup code.
+ *
+ *  Copyright (C) 2001, 2002  Hiroyuki Kondo, Hirokazu Takata,
+ *  and Hitoshi Yamamoto
+ *
+ */
+/* $Id: setup.S,v 1.27 2004/05/27 04:34:41 sakugawa Exp $ */
+
+#include <linux/linkage.h>
+#include <asm/segment.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/assembler.h>		/* LDIMM() */
+#include <asm/mmu_context.h>		/* MMU_REG_BASE */
+
+#include <linux/config.h>
+#include <asm/m32r.h>
+
+/*
+ * References to members of the boot_cpu_data structure.
+ */
+
+#define CPU_PARAMS	SYMBOL_NAME(boot_cpu_data)
+	
+#define	M32R_MCCR 	 0xfffffffc
+#define M32R_BSCR0	 0xffffffd2
+
+;BSEL
+#define BSEL0CR0	 0x00ef5000
+#define	BSEL0CR1	 0x00ef5004
+#define BSEL1CR0	 0x00ef5100
+#define BSEL1CR1	 0x00ef5104
+#define BSEL0CR0_VAL	 0x00000000
+#define BSEL0CR1_VAL	 0x01200100
+#define BSEL1CR0_VAL	 0x01018000
+#define BSEL1CR1_VAL	 0x00200001
+
+;SDRAMC
+#define SDRAMC_SDRF0	 0x00ef6000
+#define SDRAMC_SDRF1	 0x00ef6004
+#define SDRAMC_SDIR0	 0x00ef6008
+#define SDRAMC_SDIR1	 0x00ef600c
+#define SDRAMC_SD0ADR	 0x00ef6020
+#define SDRAMC_SD0ER	 0x00ef6024
+#define SDRAMC_SD0TR	 0x00ef6028
+#define SDRAMC_SD0MOD	 0x00ef602c
+#define SDRAMC_SD1ADR	 0x00ef6040
+#define SDRAMC_SD1ER	 0x00ef6044
+#define SDRAMC_SD1TR	 0x00ef6048
+#define SDRAMC_SD1MOD	 0x00ef604c
+#define SDRAM0		 0x18000000
+#define SDRAM1		 0x1c000000
+
+/*------------------------------------------------------------------------
+ * start up
+ */
+
+/*------------------------------------------------------------------------
+ * Kernel entry
+ */
+	.section .boot,"ax"
+ENTRY(boot)
+
+/* Set cache mode */
+#if defined(CONFIG_CHIP_XNUX2)
+	ldi	r0, #-2              ;LDIMM	(r0, M32R_MCCR)
+	ldi	r1, #0x0101		; cache on (with invalidation)
+;	ldi	r1, #0x00		; cache off
+	sth	r1, @r0
+#elif defined(CONFIG_CHIP_VDEC2)
+	; cache condition is controlled by loader
+	; r13 = pointer to kernel parameter passed from loader
+	beqz	r13, param_skip
+	ldi	r2, #4096				; size
+	seth	r1, #high(empty_zero_page)
+	or3	r1, r1, #low(empty_zero_page)
+	seth	r3, #high(__PAGE_OFFSET)
+	or3	r3, r3, #low(__PAGE_OFFSET)
+	not	r3, r3
+	and	r1, r3
+	addi	r1, #-4
+param_loop:
+	ld	r3, @r13+
+	st	r3, @+r1
+	addi	r2, #-4
+	bnez	r2, param_loop
+	bra	param_end
+param_skip:
+	ldi	r0, #-1              ;LDIMM	(r0, M32R_MCCR)
+	ldi	r1, #0x63      		; cache on
+;	ldi	r1, #0x00		; cache off
+	stb	r1, @r0
+param_end:
+#elif defined(CONFIG_CHIP_M32700) && (defined(CONFIG_PLAT_M32700UT) \
+	|| defined(CONFIG_PLAT_M32700UT_Alpha) || defined(CONFIG_PLAT_USRV))
+	; cache condition is controlled by loader
+	; r13 = pointer to kernel parameter passed from loader
+        ldi     r0, #-4
+	ldi     r1, #0x63               ; cache Ion/Don
+	st     	r1, @r0
+#if defined(CONFIG_SMP) && !defined(CONFIG_PLAT_USRV)
+	seth	r5, #high(M32R_CPUID_PORTL)
+	or3	r5, r5, #low(M32R_CPUID_PORTL)
+	ld	r5, @r5
+	bnez	r5, param_end
+	;; boot AP
+	ld24	r5, #0xeff2f8		; IPICR7
+	ldi	r6, #0x2		; IPI to CPU1
+	st	r6, @r5
+#endif
+	beqz	r13, param_end
+	ldi	r2, #4096				; size
+	seth	r1, #high(empty_zero_page)
+	or3	r1, r1, #low(empty_zero_page)
+	seth	r3, #high(__PAGE_OFFSET)
+	or3	r3, r3, #low(__PAGE_OFFSET)
+	not	r3, r3
+	and	r1, r3
+	addi	r1, #-4
+param_loop:
+	ld	r3, @r13+
+	st	r3, @+r1
+	addi	r2, #-4
+	bnez	r2, param_loop
+param_end:
+#elif defined(CONFIG_CHIP_M32700)
+	ldi	r0, #-4              ;LDIMM	(r0, M32R_MCCR)
+	ldi	r1, #0x63		; cache Ion/Don (with invalidation)
+;	ldi	r1, #0x00		; cache off
+	st	r1, @r0
+#elif defined(CONFIG_CHIP_OPSP) && defined(CONFIG_PLAT_OPSPUT)
+        ldi     r0, #-4
+	ldi     r1, #0x63               ; cache Ion/Don
+;; 	st     	r1, @r0		
+	beqz	r13, param_end
+	ldi	r2, #4096				; size
+	seth	r1, #high(empty_zero_page)
+	or3	r1, r1, #low(empty_zero_page)
+	seth	r3, #high(__PAGE_OFFSET)
+	or3	r3, r3, #low(__PAGE_OFFSET)
+	not	r3, r3
+	and	r1, r3
+	addi	r1, #-4
+param_loop:
+	ld	r3, @r13+
+	st	r3, @+r1
+	addi	r2, #-4
+	bnez	r2, param_loop
+param_end:
+#elif defined(CONFIG_CHIP_OPSP)
+	; cache condition is controlled by loader
+	; r13 = pointer to kernel parameter passed from loader
+	beqz	r13, param_skip
+	ldi	r2, #4096				; size
+	seth	r1, #high(empty_zero_page)
+	or3	r1, r1, #low(empty_zero_page)
+	seth	r3, #high(__PAGE_OFFSET)
+	or3	r3, r3, #low(__PAGE_OFFSET)
+	not	r3, r3
+	and	r1, r3
+	addi	r1, #-4
+param_loop:
+	ld	r3, @r13+
+	st	r3, @+r1
+	addi	r2, #-4
+	bnez	r2, param_loop
+	bra	param_end
+param_skip:
+	ldi	r0, #-1              ;LDIMM	(r0, M32R_MCCR)
+	ldi	r1, #0x63      		; cache on
+;	ldi	r1, #0x00		; cache off
+	stb	r1, @r0
+param_end:
+#else
+#error unknown chip configuration
+#endif
+
+#ifdef CONFIG_SMP
+	;; if not BSP (CPU#0) goto AP_loop
+	seth	r5, #shigh(M32R_CPUID_PORTL)
+	ld	r5, @(low(M32R_CPUID_PORTL), r5)
+	bnez	r5, AP_loop
+#endif
+
+/*
+ *  Now, Jump to stext 
+ *        if with MMU,    TLB on.
+ *        if with no MMU, only jump.
+ */
+mmu_on:
+	LDIMM	(r13,SYMBOL_NAME(stext))
+#ifdef CONFIG_HAVE_M32R_MMU
+	bl	init_tlb
+	LDIMM	(r2,SYMBOL_NAME(_RE))		; set EVB(cr5)
+	mvtc    r2, cr5	
+	seth	r0, #high(MMU_REG_BASE)		; Set MMU_REG_BASE higher
+	or3     r0, r0, #low(MMU_REG_BASE)	; Set MMU_REG_BASE lower
+	ldi     r1, #0x01    
+	st      r1, @(MATM_offset,r0)		; Set MATM (T bit ON)
+	ld      r0, @(MATM_offset,r0)		; Check
+#endif
+	jmp	r13
+	nop
+	nop
+	
+
+#ifdef CONFIG_SMP
+
+/* 
+ * AP wait loop
+ */
+
+ENTRY(AP_loop)
+	;; disable interrupt
+	clrpsw  #0x0040
+	;; reset EVB
+	LDIMM  (r4, SYMBOL_NAME(_AP_RE))
+	seth  r5, #high(__PAGE_OFFSET)
+	or3   r5, r5, #low(__PAGE_OFFSET)
+	not   r5, r5
+	and   r4, r5
+	mvtc  r4, cr5
+	;; disable maskable interrupt
+	seth  r4, #high(M32R_ICU_IMASK_PORTL)
+	or3   r4, r4, #low(M32R_ICU_IMASK_PORTL)
+	ldi   r5, #0
+	st    r5, @r4
+	ld    r5, @r4
+	;; enable only IPI
+	setpsw  #0x0040
+    	;; LOOOOOOOOOOOOOOP!!!
+	.fillinsn
+2:
+	nop
+	nop
+	bra   2b
+	nop
+	nop
+
+#ifdef CONFIG_CHIP_M32700_TS1
+	.global	dcache_dummy
+	.balign	16, 0
+dcache_dummy:
+	.byte	16
+#endif	/* CONFIG_CHIP_M32700_TS1 */
+
+#endif  /* CONFIG_SMP */
+
+	.end
+	
diff -ruN linux-2.4.26.org/arch/m32r/config.in linux-2.4.26/arch/m32r/config.in
--- linux-2.4.26.org/arch/m32r/config.in	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/arch/m32r/config.in	2004-06-24 19:45:44.000000000 +0900
@@ -0,0 +1,384 @@
+#
+# For a description of the syntax of this configuration file,
+# see Documentation/kbuild/config-language.txt.
+#
+mainmenu_name "Linux/M32R Kernel Configuration"
+
+define_bool CONFIG_M32R y
+
+define_bool CONFIG_UID16 y
+define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
+
+mainmenu_option next_comment
+comment 'Code maturity level options'
+bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
+endmenu
+
+mainmenu_option next_comment
+comment 'Loadable module support'
+bool 'Enable loadable module support' CONFIG_MODULES
+if [ "$CONFIG_MODULES" = "y" ]; then
+   bool '  Set version information on all module symbols' CONFIG_MODVERSIONS
+   bool '  Kernel module loader' CONFIG_KMOD
+fi
+endmenu
+
+mainmenu_option next_comment
+comment 'Target processor type and platforms'
+choice 'Target platform (eva. board)' \
+	"Mappi		CONFIG_PLAT_MAPPI \
+	 Mappi2		CONFIG_PLAT_MAPPI2 \
+	 M32700UT_Alpha	CONFIG_PLAT_M32700UT_Alpha \
+	 M32700UT	CONFIG_PLAT_M32700UT \
+	 OPSPUT		CONFIG_PLAT_OPSPUT \
+	 uServer	CONFIG_PLAT_USRV" M32700UT
+
+choice 'Processor type' \
+	"M32700		CONFIG_CHIP_M32700 \
+	 XNUX2		CONFIG_CHIP_XNUX2 \
+	 OPSP		CONFIG_CHIP_OPSP \
+	 VDEC2		CONFIG_CHIP_VDEC2" M32700
+
+# ISA
+if [ "$CONFIG_CHIP_XNUX2" = "y" -o \
+     "$CONFIG_CHIP_OPSP"  = "y" -o \
+     "$CONFIG_CHIP_M32700" = "y" ]; then
+   define_bool CONFIG_HAVE_M32R_MMU y
+   define_bool CONFIG_ISA_M32R2 y
+   define_bool CONFIG_ISA_DSP_LEVEL2 y
+else
+   define_bool CONFIG_HAVE_M32R_MMU y
+   define_bool CONFIG_ISA_M32R2 n
+   define_bool CONFIG_ISA_M32R y
+   define_bool CONFIG_ISA_DSP_LEVEL2 n
+fi
+
+# TLB
+if [ "$CONFIG_CHIP_OPSP"  = "y" -o \
+     "$CONFIG_CHIP_M32700" = "y" ]; then
+     int 'TLB Entries' CONFIG_TLB_ENTRIES 32
+else
+     define_int CONFIG_TLB_ENTRIES 16
+fi
+
+# Dual issue
+if [ "$CONFIG_CHIP_XNUX2" = "y" -o \
+     "$CONFIG_CHIP_OPSP"  = "y" -o \
+     "$CONFIG_CHIP_M32700" = "y" ]; then
+    bool 'Instruction dual issuing support' CONFIG_ISA_DUAL_ISSUE
+fi
+
+# Platform-specific memory start and size definitions
+if [ "$CONFIG_PLAT_MAPPI" = "y" ]; then
+   define_hex CONFIG_MEMORY_START 08000000
+   define_hex CONFIG_MEMORY_SIZE 04000000
+   define_int CONFIG_CPU_CLOCK 10000000
+   define_int CONFIG_BUS_CLOCK 10000000
+   define_int CONFIG_TIMER_DIVIDE 128
+fi
+if [ "$CONFIG_PLAT_MAPPI2" = "y" ]; then
+   define_hex CONFIG_MEMORY_START 08000000
+   define_hex CONFIG_MEMORY_SIZE 04000000
+   define_int CONFIG_CPU_CLOCK 25000000
+   define_int CONFIG_BUS_CLOCK 25000000
+   define_int CONFIG_TIMER_DIVIDE 128
+fi
+if [ "$CONFIG_PLAT_M32700UT_Alpha" = "y" ]; then
+   define_hex CONFIG_MEMORY_START 04000000
+   define_hex CONFIG_MEMORY_SIZE 01000000
+   define_int CONFIG_CPU_CLOCK 300000000
+   define_int CONFIG_BUS_CLOCK 100000000
+   define_int CONFIG_TIMER_DIVIDE 128
+fi
+if [ "$CONFIG_PLAT_M32700UT" = "y" ]; then
+   define_hex CONFIG_MEMORY_START 08000000
+   define_hex CONFIG_MEMORY_SIZE 01000000
+   define_int CONFIG_CPU_CLOCK 300000000
+   define_int CONFIG_BUS_CLOCK 100000000
+   define_int CONFIG_TIMER_DIVIDE 128
+fi
+if [ "$CONFIG_PLAT_OPSPUT" = "y" ]; then
+   define_hex CONFIG_MEMORY_START 08000000
+   define_hex CONFIG_MEMORY_SIZE 01000000
+   define_int CONFIG_CPU_CLOCK 200000000
+   define_int CONFIG_BUS_CLOCK 50000000
+   define_int CONFIG_TIMER_DIVIDE 128
+fi
+if [ "$CONFIG_PLAT_OPSPEVA" = "y" ]; then
+   define_hex CONFIG_MEMORY_START 08000000
+   define_hex CONFIG_MEMORY_SIZE 04000000
+   define_int CONFIG_CPU_CLOCK 200000000
+   define_int CONFIG_BUS_CLOCK 100000000
+   define_int CONFIG_TIMER_DIVIDE 128
+fi
+if [ "$CONFIG_PLAT_USRV" = "y" ]; then
+   define_hex CONFIG_MEMORY_START 08000000
+   define_hex CONFIG_MEMORY_SIZE 02000000
+   define_int CONFIG_CPU_CLOCK 200000000
+   define_int CONFIG_BUS_CLOCK 25000000
+   define_int CONFIG_TIMER_DIVIDE 128
+fi
+
+bool 'Generate little endian code' CONFIG_CPU_LITTLE_ENDIAN
+
+bool 'Use initrd' CONFIG_USE_INITRD y
+if [ "$CONFIG_USE_INITRD" = "y" ]; then
+   if [ "$CONFIG_PLAT_MAPPI" = "y" ]; then
+      define_hex CONFIG_INITRD_START 082A0000
+      define_hex CONFIG_INITRD_SIZE 0015F000
+   fi
+   if [ "$CONFIG_PLAT_M32700UT_Alpha" = "y" ]; then
+      define_hex CONFIG_INITRD_START 04300000
+      define_hex CONFIG_INITRD_SIZE 00400000
+   fi
+   if [ "$CONFIG_PLAT_M32700UT" = "y" ]; then
+      define_hex CONFIG_INITRD_START 08300000
+      define_hex CONFIG_INITRD_SIZE 00400000
+   fi
+   if [ "$CONFIG_PLAT_OPSPUT" = "y" ]; then
+      define_hex CONFIG_INITRD_START 08300000
+      define_hex CONFIG_INITRD_SIZE 00400000
+   fi
+   if [ "$CONFIG_PLAT_OPSPEVA" = "y" ]; then
+      define_hex CONFIG_INITRD_START 08300000
+      define_hex CONFIG_INITRD_SIZE 00400000
+   fi
+   if [ "$CONFIG_PLAT_USRV" = "y" ]; then
+      define_hex CONFIG_INITRD_START 08300000
+      define_hex CONFIG_INITRD_SIZE 00400000
+   fi
+   bool 'Initrd address user definition' CONFIG_INITRD_ADDR y
+   if [ "$CONFIG_INITRD_ADDR" = "y" ]; then
+      hex 'Initrd start physical address' CONFIG_INITRD_START 0
+      hex 'Initrd size' CONFIG_INITRD_SIZE 0
+   fi
+fi
+
+#bool 'Math emulation' CONFIG_MATH_EMULATION
+
+if [ "$CONFIG_CHIP_XNUX2" = "y" -o \
+     "$CONFIG_CHIP_M32700" = "y" ]; then
+   bool 'Symmetric multi-processing support' CONFIG_SMP
+fi
+if [ "$CONFIG_SMP" = "y" ]; then
+   int  'Maximum number of CPUs (2-32)' CONFIG_NR_CPUS 2
+   if [ "$CONFIG_CHIP_M32700" = "y" ]; then
+       bool 'M32700 TS1 chip bug' CONFIG_CHIP_M32700_TS1
+   fi
+fi
+
+source arch/m32r/drivers/Config.in
+
+endmenu
+
+
+mainmenu_option next_comment
+comment 'General setup'
+
+bool 'Networking support' CONFIG_NET
+
+bool 'PCI support' CONFIG_PCI
+if [ "$CONFIG_PCI" = "y" ]; then
+   choice '  PCI access mode' \
+	"BIOS        	CONFIG_PCI_GOBIOS	\
+	 Direct		CONFIG_PCI_GODIRECT	\
+	 Any		CONFIG_PCI_GOANY"	Any
+   if [ "$CONFIG_PCI_GOBIOS" = "y" -o "$CONFIG_PCI_GOANY" = "y" ]; then
+      define_bool CONFIG_PCI_BIOS y
+   fi
+   if [ "$CONFIG_PCI_GODIRECT" = "y" -o "$CONFIG_PCI_GOANY" = "y" ]; then
+      define_bool CONFIG_PCI_DIRECT y
+   fi
+fi
+
+source drivers/pci/Config.in
+
+bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG
+
+if [ "$CONFIG_HOTPLUG" = "y" ] ; then
+   source drivers/pcmcia/Config.in
+   source drivers/hotplug/Config.in
+#   source drivers/mmc/Config.in
+else
+   define_bool CONFIG_PCMCIA n
+   define_bool CONFIG_HOTPLUG_PCI n
+#   define_bool CONFIG_MMC n
+fi
+
+bool 'System V IPC' CONFIG_SYSVIPC
+bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
+bool 'Sysctl support' CONFIG_SYSCTL
+if [ "$CONFIG_PROC_FS" = "y" ]; then
+   choice 'Kernel core (/proc/kcore) format' \
+        "ELF		CONFIG_KCORE_ELF	\
+         A.OUT		CONFIG_KCORE_AOUT" ELF
+fi
+tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
+tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
+tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
+
+bool 'Power Management support' CONFIG_PM
+
+#if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+#   dep_bool '  ACPI support' CONFIG_ACPI $CONFIG_PM
+#
+#   if [ "$CONFIG_ACPI" != "n" ]; then
+#      source drivers/acpi/Config.in
+#   fi
+#fi
+
+#bool 'Advanced Power Management BIOS support' CONFIG_APM
+#if [ "$CONFIG_APM" != "n" ]; then
+#  bool '   Ignore USER SUSPEND' CONFIG_APM_IGNORE_USER_SUSPEND
+#  bool '   Enable PM at boot time' CONFIG_APM_DO_ENABLE
+#  bool '   Make CPU Idle calls when idle' CONFIG_APM_CPU_IDLE
+#  bool '   Enable console blanking using APM' CONFIG_APM_DISPLAY_BLANK
+#  bool '   Ignore multiple suspend/resume cycles' CONFIG_APM_IGNORE_SUSPEND_BOUNCE
+#  bool '   RTC stores time in GMT' CONFIG_APM_RTC_IS_GMT
+#  bool '   Allow interrupts during APM BIOS calls' CONFIG_APM_ALLOW_INTS
+#  bool '   Use real mode APM BIOS call to power off' CONFIG_APM_REAL_MODE_POWER_OFF
+#fi
+
+endmenu
+
+source drivers/mtd/Config.in
+
+source drivers/parport/Config.in
+
+source drivers/pnp/Config.in
+
+source drivers/block/Config.in
+
+source drivers/md/Config.in
+
+if [ "$CONFIG_NET" = "y" ]; then
+   source net/Config.in
+fi
+
+source drivers/telephony/Config.in
+
+mainmenu_option next_comment
+comment 'ATA/IDE/MFM/RLL support'
+
+tristate 'ATA/IDE/MFM/RLL support' CONFIG_IDE
+
+if [ "$CONFIG_IDE" != "n" ]; then
+   source drivers/ide/Config.in
+else
+   define_bool CONFIG_BLK_DEV_HD n
+fi
+endmenu
+
+mainmenu_option next_comment
+comment 'SCSI support'
+
+tristate 'SCSI support' CONFIG_SCSI
+
+if [ "$CONFIG_SCSI" != "n" ]; then
+   source drivers/scsi/Config.in
+fi
+endmenu
+
+source drivers/message/fusion/Config.in
+
+source drivers/ieee1394/Config.in
+
+source drivers/message/i2o/Config.in
+
+if [ "$CONFIG_NET" = "y" ]; then
+   mainmenu_option next_comment
+   comment 'Network device support'
+
+   bool 'Network device support' CONFIG_NETDEVICES
+   if [ "$CONFIG_NETDEVICES" = "y" ]; then
+      source drivers/net/Config.in
+      if [ "$CONFIG_ATM" = "y" ]; then
+         source drivers/atm/Config.in
+      fi
+   fi
+   endmenu
+fi
+
+source net/ax25/Config.in
+
+source net/irda/Config.in
+
+mainmenu_option next_comment
+comment 'ISDN subsystem'
+if [ "$CONFIG_NET" != "n" ]; then
+   tristate 'ISDN support' CONFIG_ISDN
+   if [ "$CONFIG_ISDN" != "n" ]; then
+      source drivers/isdn/Config.in
+   fi
+fi
+endmenu
+
+mainmenu_option next_comment
+comment 'Old CD-ROM drivers (not SCSI, not IDE)'
+
+bool 'Support non-SCSI/IDE/ATAPI CDROM drives' CONFIG_CD_NO_IDESCSI
+if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
+   source drivers/cdrom/Config.in
+fi
+endmenu
+
+#
+# input before char - char/joystick depends on it. As does USB.
+#
+source drivers/input/Config.in
+source drivers/char/Config.in
+
+#source drivers/misc/Config.in
+
+source drivers/media/Config.in
+
+source fs/Config.in
+
+if [ "$CONFIG_VT" = "y" ]; then
+   mainmenu_option next_comment
+   comment 'Console drivers'
+   bool 'VGA text console' CONFIG_VGA_CONSOLE
+   bool 'Video mode selection support' CONFIG_VIDEO_SELECT
+   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      tristate 'MDA text console (dual-headed) (EXPERIMENTAL)' CONFIG_MDA_CONSOLE
+      source drivers/video/Config.in
+   fi
+   endmenu
+fi
+
+mainmenu_option next_comment
+comment 'Sound'
+
+tristate 'Sound card support' CONFIG_SOUND
+if [ "$CONFIG_SOUND" != "n" ]; then
+   source drivers/sound/Config.in
+fi
+endmenu
+
+source drivers/usb/Config.in
+
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+   source net/bluetooth/Config.in
+
+   source drivers/mmc/Config.in
+fi
+
+mainmenu_option next_comment
+comment 'Kernel hacking'
+
+bool 'Kernel debugging' CONFIG_DEBUG_KERNEL
+if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then
+   bool '  Debug memory allocations' CONFIG_DEBUG_SLAB
+   bool '  Memory mapped I/O debugging' CONFIG_DEBUG_IOVIRT
+   bool '  Magic SysRq key' CONFIG_MAGIC_SYSRQ
+   bool '  Spinlock debugging' CONFIG_DEBUG_SPINLOCK
+   bool '  Verbose BUG() reporting (adds 70K)' CONFIG_DEBUG_BUGVERBOSE
+   bool '  Compile the kernel with frame pointers' CONFIG_FRAME_POINTER
+fi
+
+int 'Kernel messages buffer length shift (0 = default)' CONFIG_LOG_BUF_SHIFT 0
+
+endmenu
+
+source crypto/Config.in
+source lib/Config.in
diff -ruN linux-2.4.26.org/arch/m32r/defconfig linux-2.4.26/arch/m32r/defconfig
--- linux-2.4.26.org/arch/m32r/defconfig	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/arch/m32r/defconfig	2004-07-09 22:22:07.000000000 +0900
@@ -0,0 +1,841 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_M32R=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# Target processor type and platforms
+#
+# CONFIG_PLAT_MAPPI is not set
+# CONFIG_PLAT_MAPPI2 is not set
+# CONFIG_PLAT_M32700UT_Alpha is not set
+CONFIG_PLAT_M32700UT=y
+# CONFIG_PLAT_OPSPUT is not set
+# CONFIG_PLAT_USRV is not set
+CONFIG_CHIP_M32700=y
+# CONFIG_CHIP_XNUX2 is not set
+# CONFIG_CHIP_OPSP is not set
+# CONFIG_CHIP_VDEC2 is not set
+CONFIG_HAVE_M32R_MMU=y
+CONFIG_ISA_M32R2=y
+CONFIG_ISA_DSP_LEVEL2=y
+CONFIG_TLB_ENTRIES=32
+CONFIG_ISA_DUAL_ISSUE=y
+CONFIG_MEMORY_START=08000000
+CONFIG_MEMORY_SIZE=01000000
+CONFIG_CPU_CLOCK=300000000
+CONFIG_BUS_CLOCK=100000000
+CONFIG_TIMER_DIVIDE=128
+# CONFIG_CPU_LITTLE_ENDIAN is not set
+CONFIG_USE_INITRD=y
+CONFIG_INITRD_START=08300000
+CONFIG_INITRD_SIZE=00400000
+# CONFIG_INITRD_ADDR is not set
+# CONFIG_SMP is not set
+
+#
+# Devices for M32R
+#
+CONFIG_M32R_SERIAL=y
+# CONFIG_M32R_USE_DBG_CONSOLE is not set
+CONFIG_M32R_PLD_SERIAL=y
+CONFIG_M32R_ETHERNET=y
+# CONFIG_M32R_NE2000 is not set
+CONFIG_M32R_SMC91111=y
+CONFIG_MAPPI2_SMC91111=y
+CONFIG_M32700UT_SMC91111=y
+# CONFIG_M32R_FLASH is not set
+CONFIG_M32R_MTD=y
+CONFIG_MTD_M32R=y
+# CONFIG_MTD_M5 is not set
+CONFIG_M32R_CFC=y
+CONFIG_MAPPI2_CFC=y
+CONFIG_M32700UT_CFC=y
+CONFIG_CFC_NUM=1
+CONFIG_M32R_AR=y
+CONFIG_M32R_AR_VGA=y
+# CONFIG_M32700UT_DS1302 is not set
+# CONFIG_USRV_DIPSW is not set
+# CONFIG_IDC_AK4524 is not set
+# CONFIG_IDC_PARPORT is not set
+# CONFIG_IDC_PWRSRC is not set
+# CONFIG_M32700UT_MCU is not set
+# CONFIG_M32700UT_TS is not set
+
+#
+# General setup
+#
+CONFIG_NET=y
+# CONFIG_PCI is not set
+CONFIG_HOTPLUG=y
+
+#
+# PCMCIA/CardBus support
+#
+CONFIG_PCMCIA=y
+# CONFIG_TCIC is not set
+# CONFIG_I82092 is not set
+# CONFIG_I82365 is not set
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+# CONFIG_HOTPLUG_PCI_COMPAQ is not set
+# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_KCORE_ELF=y
+# CONFIG_KCORE_AOUT is not set
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_PM is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_REDBOOT_PARTS=y
+# CONFIG_MTD_CMDLINE_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+# CONFIG_MTD_CHAR is not set
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+CONFIG_MTD_JEDECPROBE=y
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+# CONFIG_MTD_CFI_NOSWAP is not set
+CONFIG_MTD_CFI_BE_BYTE_SWAP=y
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+# CONFIG_MTD_CFI_B1 is not set
+CONFIG_MTD_CFI_B2=y
+# CONFIG_MTD_CFI_B4 is not set
+# CONFIG_MTD_CFI_B8 is not set
+CONFIG_MTD_CFI_I1=y
+# CONFIG_MTD_CFI_I2 is not set
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+# CONFIG_MTD_AMDSTD is not set
+# CONFIG_MTD_SHARP is not set
+# CONFIG_MTD_JEDEC is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_PCI is not set
+# CONFIG_MTD_PCMCIA is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC1000 is not set
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOCPROBE is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
+# CONFIG_CISS_MONITOR_THREAD is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_STATS is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
+# Networking options
+#
+# CONFIG_PACKET is not set
+# CONFIG_NETLINK_DEV is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+
+#
+#    SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+# CONFIG_PHONE_IXJ is not set
+# CONFIG_PHONE_IXJ_PCMCIA is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+CONFIG_IDE=m
+
+#
+# IDE, ATA and ATAPI Block devices
+#
+CONFIG_BLK_DEV_IDE=m
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_BLK_DEV_IDEDISK=m
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_IDEDISK_STROKE is not set
+CONFIG_BLK_DEV_IDECS=m
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+# CONFIG_BLK_DEV_ISAPNP is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_DMA_NONPCI is not set
+# CONFIG_BLK_DEV_ATARAID is not set
+# CONFIG_BLK_DEV_ATARAID_PDC is not set
+# CONFIG_BLK_DEV_ATARAID_HPT is not set
+# CONFIG_BLK_DEV_ATARAID_MEDLEY is not set
+# CONFIG_BLK_DEV_ATARAID_SII is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_BOOT is not set
+# CONFIG_FUSION_ISENSE is not set
+# CONFIG_FUSION_CTL is not set
+# CONFIG_FUSION_LAN is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+CONFIG_DUMMY=y
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_SUNLANCE is not set
+# CONFIG_SUNBMAC is not set
+# CONFIG_SUNQE is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+# CONFIG_STRIP is not set
+# CONFIG_WAVELAN is not set
+# CONFIG_ARLAN is not set
+# CONFIG_AIRONET4500 is not set
+# CONFIG_AIRONET4500_NONCS is not set
+# CONFIG_AIRONET4500_PROC is not set
+# CONFIG_HERMES is not set
+
+#
+# Wireless Pcmcia cards support
+#
+# CONFIG_PCMCIA_HERMES is not set
+# CONFIG_AIRO_CS is not set
+# CONFIG_PCMCIA_ATMEL is not set
+CONFIG_NET_WIRELESS=y
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# PCMCIA network device support
+#
+# CONFIG_NET_PCMCIA is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Input core support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_UINPUT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=64
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+# CONFIG_INPUT_NS558 is not set
+# CONFIG_INPUT_LIGHTNING is not set
+# CONFIG_INPUT_PCIGAME is not set
+# CONFIG_INPUT_CS461X is not set
+# CONFIG_INPUT_EMU10K1 is not set
+# CONFIG_INPUT_SERIO is not set
+# CONFIG_INPUT_SERPORT is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_ANALOG is not set
+# CONFIG_INPUT_A3D is not set
+# CONFIG_INPUT_ADI is not set
+# CONFIG_INPUT_COBRA is not set
+# CONFIG_INPUT_GF2K is not set
+# CONFIG_INPUT_GRIP is not set
+# CONFIG_INPUT_INTERACT is not set
+# CONFIG_INPUT_TMDC is not set
+# CONFIG_INPUT_SIDEWINDER is not set
+# CONFIG_INPUT_IFORCE_USB is not set
+# CONFIG_INPUT_IFORCE_232 is not set
+# CONFIG_INPUT_WARRIOR is not set
+# CONFIG_INPUT_MAGELLAN is not set
+# CONFIG_INPUT_SPACEORB is not set
+# CONFIG_INPUT_SPACEBALL is not set
+# CONFIG_INPUT_STINGER is not set
+# CONFIG_INPUT_DB9 is not set
+# CONFIG_INPUT_GAMECON is not set
+# CONFIG_INPUT_TURBOGRAFX is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_SCx200 is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+
+#
+# Direct Rendering Manager (XFree86 DRI support)
+#
+# CONFIG_DRM is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_PCMCIA_SERIAL_CS is not set
+# CONFIG_SYNCLINK_CS is not set
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=y
+
+#
+# Video For Linux
+#
+CONFIG_VIDEO_PROC_FS=y
+# CONFIG_I2C_PARPORT is not set
+
+#
+# Video Adapters
+#
+# CONFIG_VIDEO_BT848 is not set
+# CONFIG_VIDEO_PMS is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_VIDEO_STRADIS is not set
+# CONFIG_VIDEO_ZORAN is not set
+# CONFIG_VIDEO_ZORAN_BUZ is not set
+# CONFIG_VIDEO_ZORAN_DC10 is not set
+# CONFIG_VIDEO_ZORAN_LML33 is not set
+# CONFIG_VIDEO_ZR36120 is not set
+# CONFIG_VIDEO_MEYE is not set
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_GEMTEK_PCI is not set
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_RADIO_MAESTRO is not set
+# CONFIG_RADIO_MIROPCM20 is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_QFMT_V2 is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BEFS_DEBUG is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+# CONFIG_UMSDOS_FS is not set
+CONFIG_VFAT_FS=y
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_CRAMFS=y
+CONFIG_TMPFS=y
+CONFIG_RAMFS=y
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_MINIX_FS=y
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_TRACE is not set
+# CONFIG_XFS_DEBUG is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_SMB_NLS is not set
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Console drivers
+#
+CONFIG_VGA_CONSOLE=y
+# CONFIG_VIDEO_SELECT is not set
+# CONFIG_MDA_CONSOLE is not set
+
+#
+# Frame-buffer support
+#
+CONFIG_FB=y
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FB_CYBER2000 is not set
+CONFIG_FB_EPSON=y
+CONFIG_FBCON_EPSON=y
+# CONFIG_FB_EPSON_S1D13504 is not set
+# CONFIG_FB_EPSON_S1D13505 is not set
+# CONFIG_FB_EPSON_S1D13506 is not set
+# CONFIG_FB_EPSON_S1D13704 is not set
+# CONFIG_FB_EPSON_S1D13705 is not set
+# CONFIG_FB_EPSON_S1D13706 is not set
+CONFIG_FB_EPSON_S1D13806=y
+CONFIG_FBCON_EPSON_S1D13806=y
+# CONFIG_FB_EPSON_S1D13A03 is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FBCON_ADVANCED=y
+# CONFIG_FBCON_MFB is not set
+# CONFIG_FBCON_CFB2 is not set
+# CONFIG_FBCON_CFB4 is not set
+# CONFIG_FBCON_CFB8 is not set
+CONFIG_FBCON_CFB16=y
+# CONFIG_FBCON_CFB24 is not set
+# CONFIG_FBCON_CFB32 is not set
+# CONFIG_FBCON_AFB is not set
+# CONFIG_FBCON_ILBM is not set
+# CONFIG_FBCON_IPLAN2P2 is not set
+# CONFIG_FBCON_IPLAN2P4 is not set
+# CONFIG_FBCON_IPLAN2P8 is not set
+# CONFIG_FBCON_MAC is not set
+# CONFIG_FBCON_VGA_PLANES is not set
+# CONFIG_FBCON_VGA is not set
+# CONFIG_FBCON_HGA is not set
+# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
+CONFIG_FBCON_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_M32R_USB=y
+# CONFIG_USB is not set
+
+#
+# Support for USB gadgets
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=0
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_CRC32=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+# CONFIG_FW_LOADER is not set
diff -ruN linux-2.4.26.org/arch/m32r/drivers/8390.h linux-2.4.26/arch/m32r/drivers/8390.h
--- linux-2.4.26.org/arch/m32r/drivers/8390.h	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/arch/m32r/drivers/8390.h	2003-06-13 22:17:09.000000000 +0900
@@ -0,0 +1 @@
+#include "../../../drivers/net/8390.h"
diff -ruN linux-2.4.26.org/arch/m32r/drivers/Config.in linux-2.4.26/arch/m32r/drivers/Config.in
--- linux-2.4.26.org/arch/m32r/drivers/Config.in	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/arch/m32r/drivers/Config.in	2004-04-20 15:50:13.000000000 +0900
@@ -0,0 +1,62 @@
+#
+# Device configuration for M32R platform
+#
+mainmenu_option next_comment
+comment 'Devices for M32R'
+
+bool 'Character devices' CONFIG_M32R_SERIAL
+if [ "$CONFIG_M32R_SERIAL" = "y" ]; then
+   bool '    Use M32R Dbg_console' CONFIG_M32R_USE_DBG_CONSOLE n
+   bool '    Use onboard PLD serial' CONFIG_M32R_PLD_SERIAL n
+fi
+
+bool 'Network devices'  CONFIG_M32R_ETHERNET
+if [ "$CONFIG_M32R_ETHERNET" = "y" ]; then 
+   tristate '    Use onboard NIC(NE2000)' CONFIG_M32R_NE2000
+   tristate '    Use onboard NIC(SMC91111)' CONFIG_M32R_SMC91111
+fi
+# workaround for
+#	arch/m32r/kernel/setup_mappi.c
+#	arch/m32r/kernel/setup_mappi2.c
+if [ "$CONFIG_M32R_NE2000" = "y" ]; then
+   define_bool CONFIG_MAPPI_NE2000 y
+fi
+if [ "$CONFIG_M32R_SMC91111" = "y" ]; then
+   define_bool CONFIG_MAPPI2_SMC91111 y
+   define_bool CONFIG_M32700UT_SMC91111 y
+fi
+
+bool 'Block devices' CONFIG_M32R_FLASH
+if [ "$CONFIG_M32R_FLASH" = "y" ]; then
+   tristate '    Use onboard Flash Memory(M5M29GT320)' CONFIG_M32R_M5
+fi
+
+bool 'Memory Technology Devices(MTD)' CONFIG_M32R_MTD
+if [ "$CONFIG_M32R_MTD" = "y" ]; then
+   dep_tristate '    Flash device mapped on M32R' CONFIG_MTD_M32R $CONFIG_MTD
+   dep_tristate '    Support for Renesas flash chips' CONFIG_MTD_M5 $CONFIG_MTD
+fi
+
+dep_bool     'Use onboard PLD CompactFlash (CFC)' CONFIG_M32R_CFC $CONFIG_PCMCIA
+if [ "$CONFIG_M32R_CFC" = "y" ]; then
+   define_bool CONFIG_MAPPI2_CFC y
+   define_bool CONFIG_M32700UT_CFC y
+   int '  CF slot number' CONFIG_CFC_NUM 1
+fi
+
+bool 'AR devices' CONFIG_M32R_AR
+if [ "$CONFIG_M32R_AR" = "y" ]; then
+   tristate '    Use Colour AR module (VGA)' CONFIG_M32R_AR_VGA
+fi
+
+bool 'DS1302 Real Time Clock support' CONFIG_M32700UT_DS1302
+
+tristate 'uServer dip switch driver' CONFIG_USRV_DIPSW
+tristate 'uServer (IDC-R) AK4524 CODEC chip driver' CONFIG_IDC_AK4524
+tristate 'uServer (IDC-R) parallel port driver' CONFIG_IDC_PARPORT
+tristate 'uServer (IDC-R) power source check driver' CONFIG_IDC_PWRSRC
+
+bool 'Battery Control MCU driver' CONFIG_M32700UT_MCU
+dep_tristate 'Touch Screen driver for M32700UT' CONFIG_M32700UT_TS $CONFIG_M32700UT_MCU
+
+endmenu
diff -ruN linux-2.4.26.org/arch/m32r/drivers/Makefile linux-2.4.26/arch/m32r/drivers/Makefile
--- linux-2.4.26.org/arch/m32r/drivers/Makefile	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/arch/m32r/drivers/Makefile	2004-04-20 15:50:13.000000000 +0900
@@ -0,0 +1,34 @@
+#
+# $Id: Makefile,v 1.5 2004/04/20 06:50:13 takeo Exp $
+# 
+# Makefile for the Linux/M32R kernel.
+#
+# 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).
+#
+
+O_TARGET 	:= m32r_drivers.o
+
+export-objs	:= 
+
+obj-y		:= 
+
+obj-$(CONFIG_M32R_USE_DBG_CONSOLE) 	+= dbg_console.o
+obj-$(CONFIG_M32R_PLD_SERIAL)	+= m32r-pldsio.o
+obj-$(CONFIG_M32R_NE2000)	+= mappi_ne.o
+obj-$(CONFIG_M32R_SMC91111)	+= smc91111.o
+obj-$(CONFIG_M32R_M5)		+= m5.o
+obj-$(CONFIG_M32R_CFC)		+= m32r_cfc.o
+obj-$(CONFIG_MTD_M5)		+= m5drv.o
+obj-$(CONFIG_MTD_M32R)		+= m32r-flash.o
+obj-$(CONFIG_M32R_AR_VGA)	+= arv.o
+obj-$(CONFIG_M32700UT_DS1302)	+= ds1302.o
+obj-$(CONFIG_USRV_DIPSW)	+= usrv_dipsw.o
+obj-$(CONFIG_IDC_AK4524)	+= idc_ak4524.o
+obj-$(CONFIG_IDC_PARPORT)	+= idc_parport.o
+obj-$(CONFIG_IDC_PWRSRC)	+= idc_pwrsrc.o
+obj-$(CONFIG_M32700UT_MCU)	+= m32700ut_mcu.o
+obj-$(CONFIG_M32700UT_TS)	+= m32700ut_ts.o
+
+include $(TOPDIR)/Rules.make
diff -ruN linux-2.4.26.org/arch/m32r/drivers/arv.c linux-2.4.26/arch/m32r/drivers/arv.c
--- linux-2.4.26.org/arch/m32r/drivers/arv.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/arch/m32r/drivers/arv.c	2003-09-16 19:18:54.000000000 +0900
@@ -0,0 +1,827 @@
+/*
+ * Colour AR M64278(VGA) driver for Video4Linux
+ *
+ * Copyright (C) 2003	Takeo Takahashi <takahashi.takeo@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.  
+ *
+ * Some code is taken from AR driver sample program for M3T-M32700UT.
+ *
+ * AR driver sample (M32R SDK):
+ *     Copyright (c) 2003 RENESAS TECHNOROGY CORPORATION
+ *     AND RENESAS SOLUTIONS CORPORATION
+ *     All Rights Reserved.
+ *
+ * 2003-09-01:	Support w3cam by Takeo Takahashi
+ *
+ * $Id: arv.c,v 1.1 2003/09/16 10:18:54 takata Exp $
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/videodev.h>
+
+#include <asm/semaphore.h>
+#include <asm/uaccess.h>
+#include <asm/m32r.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/byteorder.h>
+
+#include "arv.h"
+
+#if 0
+#define DEBUG(n, args...) printk(args)
+#define CHECK_LOST	1
+#else
+#define DEBUG(n, args...)
+#define CHECK_LOST	0
+#endif
+
+/*
+ * USE_INT is always 0, interrupt mode is not available
+ * on linux due to lack of speed
+ */
+#define USE_INT		0	/* Don't modify */
+
+#define VERSION	"0.01"
+
+#define ar_inl(addr) 		inl((unsigned long)(addr))
+#define ar_outl(val, addr)	outl((unsigned long)(val),(unsigned long)(addr))
+
+extern struct cpuinfo_m32r	boot_cpu_data;
+
+/*
+ * CCD pixel size
+ *	Note that M32700UT does not support CIF mode, but QVGA is
+ *	supported by M32700UT hardware using VGA mode of AR LSI.
+ *
+ * 	Supported: VGA  (Normal mode, Interlace mode)
+ *		   QVGA (Always Interlace mode of VGA)
+ *
+ */
+#define AR_WIDTH_VGA	640
+#define AR_HEIGHT_VGA	480
+#define AR_WIDTH_QVGA	320
+#define AR_HEIGHT_QVGA	240
+#define MIN_AR_WIDTH	AR_WIDTH_QVGA
+#define MIN_AR_HEIGHT	AR_HEIGHT_QVGA
+#define MAX_AR_WIDTH	AR_WIDTH_VGA
+#define MAX_AR_HEIGHT	AR_HEIGHT_VGA
+
+/* bits & bytes per pixel */
+#define AR_BITS_PER_PIXEL	16
+#define AR_BYTES_PER_PIXEL	(AR_BITS_PER_PIXEL/8)
+
+/* line buffer size */
+#define AR_LINE_BYTES_VGA	(AR_WIDTH_VGA * AR_BYTES_PER_PIXEL)
+#define AR_LINE_BYTES_QVGA	(AR_WIDTH_QVGA * AR_BYTES_PER_PIXEL)
+#define MAX_AR_LINE_BYTES	AR_LINE_BYTES_VGA
+
+/* frame size & type */
+#define AR_FRAME_BYTES_VGA	(AR_WIDTH_VGA * AR_HEIGHT_VGA * \
+				 AR_BYTES_PER_PIXEL)
+#define AR_FRAME_BYTES_QVGA	(AR_WIDTH_QVGA * AR_HEIGHT_QVGA * \
+				 AR_BYTES_PER_PIXEL)
+#define MAX_AR_FRAME_BYTES	(MAX_AR_WIDTH * MAX_AR_HEIGHT * \
+				 AR_BYTES_PER_PIXEL)
+	
+/* capture size */
+#define AR_SIZE_VGA	0
+#define AR_SIZE_QVGA	1
+
+/* capture mode */
+#define AR_MODE_INTERLACE	0
+#define AR_MODE_NORMAL		1
+
+struct ar_device {
+	struct video_device vdev;
+	unsigned int start_capture;		// duaring capture in INT. mode.
+#if USE_INT
+	unsigned char *line_buff;		// DMA line buffer
+#endif
+	unsigned char *frame[MAX_AR_HEIGHT];	// frame data
+	short size;				// capture size
+	short mode;				// capture mode
+	int width, height;
+	int frame_bytes, line_bytes;
+	wait_queue_head_t wait;
+	struct semaphore lock;
+};
+
+static int video_nr = -1;	/* video device number (first free) */
+static unsigned char	yuv[MAX_AR_FRAME_BYTES];
+
+/* module parameters */
+/* default frequency */
+#define DEFAULT_FREQ	50	// 50 or 75 (MHz) is available as BCLK
+static int freq = DEFAULT_FREQ;	/* BCLK: available 50 or 70 (MHz) */
+static int vga = 0;		/* default mode(0:QVGA mode, other:VGA mode) */
+static int vga_interlace = 0;	/* 0 is normal mode for, else interlace mode */
+MODULE_PARM(freq, "i");
+MODULE_PARM(vga, "i");
+MODULE_PARM(vga_interlace, "i");
+
+static int ar_initialize(struct video_device *dev);
+
+/*******************************************************************
+ * I2C functions
+ *******************************************************************/
+void iic(int n, unsigned long addr, unsigned long data1, unsigned long data2, unsigned long data3)
+{
+	int i;
+
+  	/* Slave Address */
+  	ar_outl(addr, PLDI2CDATA);
+
+	while ( ar_inl(ARVCR0) & ARVCR0_VDS ); 	  // wait for VSYNC
+	while ( !(ar_inl(ARVCR0) & ARVCR0_VDS) ); // wait for VSYNC
+  	/* Start */
+  	ar_outl(1, PLDI2CCND);
+
+  	for(i=0; i<1000; i++);
+  	while( ar_inl(PLDI2CSTS) & PLDI2CSTS_NOACK );
+  
+  	/* Trasfer data 1 */
+  	ar_outl(data1, PLDI2CDATA);
+	while ( ar_inl(ARVCR0) & ARVCR0_VDS ); 	  // wait for VSYNC
+	while ( !(ar_inl(ARVCR0) & ARVCR0_VDS) ); // wait for VSYNC
+  	ar_outl(PLDI2CSTEN_STEN, PLDI2CSTEN);
+
+  	/* Ack wait */
+  	for(i=0; i<1000; i++);
+  	while( ar_inl(PLDI2CSTS) & PLDI2CSTS_NOACK );
+
+  	/* Trasfer data 2 */
+  	ar_outl(data2, PLDI2CDATA);
+	while ( ar_inl(ARVCR0) & ARVCR0_VDS ); 	  // wait for VSYNC
+	while ( !(ar_inl(ARVCR0) & ARVCR0_VDS) ); // wait for VSYNC
+  	ar_outl(PLDI2CSTEN_STEN, PLDI2CSTEN);
+
+  	/* Ack wait */
+  	for(i=0; i<1000; i++);
+
+  	while( ar_inl(PLDI2CSTS) & PLDI2CSTS_NOACK );
+
+  	if(n==3){
+    		/* Trasfer data 3 */
+	  	ar_outl(data3, PLDI2CDATA);
+		while ( ar_inl(ARVCR0) & ARVCR0_VDS );    // wait for VSYNC
+		while ( !(ar_inl(ARVCR0) & ARVCR0_VDS) ); // wait for VSYNC
+	  	ar_outl(PLDI2CSTEN_STEN, PLDI2CSTEN);
+
+    		/* Ack wait */
+    		for(i=0; i<10000; i++);
+
+  		while( ar_inl(PLDI2CSTS) & PLDI2CSTS_NOACK );
+  	}
+
+  	/* Stop */
+  	for(i=0; i<100; i++);
+  	ar_outl(2, PLDI2CCND);
+  	ar_outl(2, PLDI2CCND);
+
+  	while( ar_inl(PLDI2CSTS) & PLDI2CSTS_BB );
+}
+
+
+void init_iic(void)
+{
+	DEBUG(1, "init_iic:\n");
+
+  	/*
+	 * ICU Setting (iic)
+	 */
+  	/* I2C Setting */
+  	ar_outl(0x0, PLDI2CCR);      	/* I2CCR Disable                   */
+  	ar_outl(0x0300, PLDI2CMOD); 	/* I2CMOD ACK/8b-data/7b-addr/auto */
+  	ar_outl(0x1, PLDI2CACK);	/* I2CACK ACK                      */
+
+    	/* I2C CLK */
+   	/* 50MH-100k */
+	if (freq == 75) {
+  		ar_outl(369, PLDI2CFREQ);	/* BCLK = 75MHz */
+	} else if (freq == 50) {
+		ar_outl(244, PLDI2CFREQ);	/* BCLK = 50MHz */
+	} else {
+		ar_outl(244, PLDI2CFREQ);	/* default:BCLK = 50MHz */
+	}
+  	ar_outl(0x1, PLDI2CCR); 	/* I2CCR Enable */
+}
+
+/**************************************************************************
+ *
+ * Video4Linux Interface functions
+ *
+ **************************************************************************/
+static int ar_open(struct video_device *dev, int flags)
+{
+	DEBUG(1, "ar_open()\n");
+	return 0;
+}
+
+static void ar_close(struct video_device *dev)
+{
+	DEBUG(1, "ar_close()\n");
+	ar_outl(0, ARVCR1);		// disable AR interrupt
+}
+
+static __inline__ void wait_for_vertical_sync(int exp_line)
+{
+#if CHECK_LOST
+	int tmout = 10000;	/* FIXME */
+	int l;
+
+	/*
+ 	 * check HCOUNT because we can not check vertual sync.
+ 	 */
+	for (; tmout >= 0; tmout--) {
+		l = ar_inl(ARVHCOUNT);
+		if (l == exp_line) break;
+	}
+	if (tmout < 0)
+		printk("arv: lost %d -> %d\n", exp_line, l);
+#else
+	while (ar_inl(ARVHCOUNT) != exp_line) ;
+#endif
+}
+
+static long ar_read(struct video_device *dev, char *buf, unsigned long count,  int noblock)
+{
+	struct ar_device *ar = (struct ar_device *)dev->priv;
+	long ret = ar->frame_bytes;		/* return read bytes */
+	unsigned long arvcr1 = 0;
+	unsigned long flags;
+	unsigned char *p;
+	int h, w;
+	unsigned char *py, *pu, *pv;
+#if ! USE_INT
+	int l;
+#endif
+
+	DEBUG(1, "ar_read()\n");
+
+	if (ar->size == AR_SIZE_QVGA) arvcr1 |= ARVCR1_QVGA;
+	if (ar->mode == AR_MODE_NORMAL) arvcr1 |= ARVCR1_NORMAL;
+
+	down(&ar->lock);
+
+#if USE_INT
+	save_and_cli(flags);
+	ar_outl(0x80000, M32700_DMAEN);		// disable DMA0
+	ar_outl(0xa1871300, M32700_DMA0CR0);
+	ar_outl(0x01000000, M32700_DMA0CR1);
+
+	// set AR FIFO address as source(BSEL5¤ÎÎÎ°è¤ò»ÈÍÑ)
+	ar_outl(ARDATA32, M32700_DMA0CSA);	// ÊªÍý¥¢¥É¥ì¥¹¤òÀßÄê
+	ar_outl(ARDATA32, M32700_DMA0RSA);	// ÊªÍý¥¢¥É¥ì¥¹¤òÀßÄê
+	ar_outl(ar->line_buff, M32700_DMA0CDA);	// destination address
+	ar_outl(ar->line_buff, M32700_DMA0RDA); // reload address
+	ar_outl(ar->line_bytes, M32700_DMA0CBCUT); 	// byte count(bytes)
+	ar_outl(ar->line_bytes, M32700_DMA0RBCUT); 	// reload count (bytes)
+
+	/*
+	 * Okey , kicks AR LSI to invoke an interrupt
+	 */
+	ar->start_capture = 0;
+	ar_outl(arvcr1 | ARVCR1_HIEN, ARVCR1);
+	restore_flags(flags);
+	/* .... AR interrupts .... */
+	interruptible_sleep_on(&ar->wait);
+	if (signal_pending(current)) {
+		printk("arv: interrupted while get frame data.\n");
+		ret = -EINTR;
+		goto out_up;
+	}
+#else	/* ! USE_INT */
+	/* polling */
+	ar_outl(arvcr1, ARVCR1);
+	ar_outl(0x80000, M32700_DMAEN);		// disable DMA0
+	ar_outl(0x8000, M32700_DMAEDET);
+	ar_outl(0xa0861300, M32700_DMA0CR0);
+	ar_outl(0x01000000, M32700_DMA0CR1);
+	ar_outl(ARDATA32, M32700_DMA0CSA);
+	ar_outl(ARDATA32, M32700_DMA0RSA);
+	ar_outl(ar->line_bytes, M32700_DMA0CBCUT); 
+	ar_outl(ar->line_bytes, M32700_DMA0RBCUT); 
+
+	save_and_cli(flags);
+	while (ar_inl(ARVHCOUNT) != 0) ; // wait for 0
+	if (ar->mode == AR_MODE_INTERLACE && ar->size == AR_SIZE_VGA) {
+		for (h = 0; h < ar->height; h++) {
+			wait_for_vertical_sync(h);
+			if (h < (AR_HEIGHT_VGA/2))
+				l = h << 1;
+			else
+				l = (((h - (AR_HEIGHT_VGA/2)) << 1) + 1);
+			ar_outl(virt_to_phys(ar->frame[l]), M32700_DMA0CDA);
+			ar_outl(0x8080, M32700_DMAEN);	// enable DMA0
+			while (!(ar_inl(M32700_DMAEDET) & 0x8000)) ;
+			ar_outl(0x80000, M32700_DMAEN);	// disable DMA0
+			ar_outl(0x8000, M32700_DMAEDET);// clear status
+			ar_outl(0xa0861300, M32700_DMA0CR0);
+		}
+	} else {
+		for (h = 0; h < ar->height; h++) {
+			wait_for_vertical_sync(h);
+			ar_outl(virt_to_phys(ar->frame[h]), M32700_DMA0CDA);
+			ar_outl(0x8080, M32700_DMAEN);	// enable DMA0
+			while (!(ar_inl(M32700_DMAEDET) & 0x8000)) ;
+			ar_outl(0x80000, M32700_DMAEN);	// disable DMA0
+			ar_outl(0x8000, M32700_DMAEDET);// clear status
+			ar_outl(0xa0861300, M32700_DMA0CR0);
+		}
+	}
+	restore_flags(flags);
+#endif	/* ! USE_INT */
+
+	/*
+	 * convert YUV422 to YUV422P
+	 * 	+--------------------+
+	 *	|  Y0,Y1,...	     |
+	 *	|  ..............Yn  |
+	 *	+--------------------+
+	 *	|  U0,U1,........Un  |
+	 *	+--------------------+
+	 *	|  V0,V1,........Vn  |
+	 *	+--------------------+
+	 */
+	py = yuv;
+	pu = py + (ar->frame_bytes / 2);
+	pv = pu + (ar->frame_bytes / 4);
+	for (h = 0; h < ar->height; h++) {
+		p = ar->frame[h];
+		for (w = 0; w < ar->line_bytes; w += 4) {
+			*py++ = *p++;
+	        	*pu++ = *p++;
+			*py++ = *p++;
+			*pv++ = *p++;
+		}
+	}
+	if (copy_to_user(buf, yuv, ar->frame_bytes)) {
+		printk("arv: failed while copy_to_user yuv.\n");
+		ret = -EFAULT;
+		goto out_up;
+	}
+	DEBUG(1, "ret = %d\n", ret);
+out_up:
+	up(&ar->lock);
+	return ret;
+}
+
+static long ar_write(struct video_device *v, const char *buf, unsigned long count, int noblock)
+{
+	DEBUG(1, "ar_write()\n");
+	return -EINVAL;
+}
+
+static int ar_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
+{
+	struct ar_device *ar=(struct ar_device *)dev;
+	
+	DEBUG(1, "ar_ioctl()\n");
+	switch(cmd) {
+	case VIDIOCGCAP:
+	{
+		struct video_capability b;
+		DEBUG(1, "VIDIOCGCAP:\n");
+		strcpy(b.name, ar->vdev.name);
+		b.type = VID_TYPE_CAPTURE;
+		b.channels = 0;
+		b.audios = 0;
+		b.maxwidth = MAX_AR_WIDTH;
+		b.maxheight = MAX_AR_HEIGHT;
+		b.minwidth = MIN_AR_WIDTH;
+		b.minheight = MIN_AR_HEIGHT;
+		if (copy_to_user(arg, &b, sizeof(b)))
+			return -EFAULT;
+		return 0;
+	}
+	case VIDIOCGCHAN:
+		DEBUG(1, "VIDIOCGCHAN:\n");
+		return 0;
+	case VIDIOCSCHAN:
+		DEBUG(1, "VIDIOCSCHAN:\n");
+		return 0;
+	case VIDIOCGTUNER:
+		DEBUG(1, "VIDIOCGTUNER:\n");
+		return 0;
+	case VIDIOCSTUNER:
+		DEBUG(1, "VIDIOCSTUNER:\n");
+		return 0;
+	case VIDIOCGPICT:
+		DEBUG(1, "VIDIOCGPICT:\n");
+		return 0;
+	case VIDIOCSPICT:
+		DEBUG(1, "VIDIOCSPICT:\n");
+		return 0;
+	case VIDIOCCAPTURE:
+		DEBUG(1, "VIDIOCCAPTURE:\n");
+		return -EINVAL;
+	case VIDIOCGWIN:
+	{
+		struct video_window w;
+		DEBUG(1, "VIDIOCGWIN:\n");
+		memset(&w, 0, sizeof(w));
+		w.width = ar->width;
+		w.height = ar->height;
+		if (copy_to_user(arg, &w, sizeof(w)))
+			return -EFAULT;
+		return 0;
+	}
+	case VIDIOCSWIN:
+	{
+		struct video_window w;
+		DEBUG(1, "VIDIOCSWIN:\n");
+		if (copy_from_user(&w, arg, sizeof(w)))
+			return -EFAULT;
+		down(&ar->lock);
+		if (w.width != AR_WIDTH_QVGA &&
+		    w.height != AR_HEIGHT_QVGA) {
+			if (w.width != AR_WIDTH_VGA &&
+			    w.height != AR_HEIGHT_VGA) {
+				up(&ar->lock);
+				return -EINVAL;
+			}
+		}
+		ar->width = w.width;
+		ar->height = w.height;
+		if (ar->width == AR_WIDTH_VGA) {
+			ar->size = AR_SIZE_VGA;
+			ar->frame_bytes = AR_FRAME_BYTES_VGA;
+			ar->line_bytes = AR_LINE_BYTES_VGA;
+			if (vga_interlace)
+				ar->mode = AR_MODE_INTERLACE;
+			else
+				ar->mode = AR_MODE_NORMAL;
+		} else {
+			ar->size = AR_SIZE_QVGA;
+			ar->frame_bytes = AR_FRAME_BYTES_QVGA;
+			ar->line_bytes = AR_LINE_BYTES_QVGA;
+			ar->mode = AR_MODE_INTERLACE;
+		}
+		up(&ar->lock);
+		return 0;
+	}
+	case VIDIOCGFBUF:
+		DEBUG(1, "VIDIOCGFBUF:\n");
+		return -EINVAL;
+	case VIDIOCSFBUF:
+		DEBUG(1, "VIDIOCSFBUF:\n");
+		return -EINVAL;
+	case VIDIOCKEY:
+		DEBUG(1, "VIDIOCKEY:\n");
+		return 0;
+	case VIDIOCGFREQ:
+		DEBUG(1, "VIDIOCGFREQ:\n");
+		return -EINVAL;
+	case VIDIOCSFREQ:
+		DEBUG(1, "VIDIOCSFREQ:\n");
+		return -EINVAL;
+	case VIDIOCGAUDIO:
+		DEBUG(1, "VIDIOCGAUDIO:\n");
+		return -EINVAL;
+	case VIDIOCSAUDIO:
+		DEBUG(1, "VIDIOCSAUDIO:\n");
+		return -EINVAL;
+	case VIDIOCSYNC:
+		DEBUG(1, "VIDIOCSYNC:\n");
+		return -EINVAL;
+	case VIDIOCMCAPTURE:
+		DEBUG(1, "VIDIOCMCAPTURE:\n");
+		return -EINVAL;
+	case VIDIOCGMBUF:
+		DEBUG(1, "VIDIOCGMBUF:\n");
+		return -EINVAL;
+	case VIDIOCGUNIT:
+		DEBUG(1, "VIDIOCGUNIT:\n");
+		return -EINVAL;
+	case VIDIOCGCAPTURE:
+		DEBUG(1, "VIDIOCGCAPTURE:\n");
+		return -EINVAL;
+	case VIDIOCSCAPTURE:
+		DEBUG(1, "VIDIOCSCAPTURE:\n");
+		return -EINVAL;
+	case VIDIOCSPLAYMODE:
+		DEBUG(1, "VIDIOCSPLAYMODE:\n");
+		return -EINVAL;
+	case VIDIOCSWRITEMODE:
+		DEBUG(1, "VIDIOCSWRITEMODE:\n");
+		return -EINVAL;
+	case VIDIOCGPLAYINFO:
+		DEBUG(1, "VIDIOCGPLAYINFO:\n");
+		return -EINVAL;
+	case VIDIOCSMICROCODE:
+		DEBUG(1, "VIDIOCSMICROCODE:\n");
+		return -EINVAL;
+	case VIDIOCGVBIFMT:
+		DEBUG(1, "VIDIOCGVBIFMT:\n");
+		return -EINVAL;
+	case VIDIOCSVBIFMT:
+		DEBUG(1, "VIDIOCSVBIFMT:\n");
+		return -EINVAL;
+	default:
+		DEBUG(1, "Unknown ioctl(0x%08x)\n", cmd);
+		return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+#if USE_INT
+/*
+ * Interrupt handler
+ */
+static void ar_interrupt(int irq, void *dev, struct pt_regs *regs)
+{
+	struct ar_device *ar = dev;
+	unsigned int line_count;
+	unsigned int line_number;
+	unsigned int arvcr1;
+
+	line_count = ar_inl(ARVHCOUNT);		// line number
+	if (ar->mode == AR_MODE_INTERLACE && ar->size == AR_SIZE_VGA) {
+		/* operations for interlace mode */
+		if ( line_count < (AR_HEIGHT_VGA/2) ) 	/* even line */
+			line_number = (line_count << 1);
+		else 		  			/* odd line */
+ 			line_number =
+			(((line_count - (AR_HEIGHT_VGA/2)) << 1) + 1);
+	} else {
+		line_number = line_count;
+	}
+
+	if (line_number == 0) {
+		/*
+		 * It is an interrupt for line 0. 
+		 * we have to start capture.
+		 */
+		ar_outl(0x8000, M32700_DMAEN);		// disable DMA0
+		//ar_outl(ar->line_buff, M32700_DMA0CDA);	// needless?
+		memcpy(ar->frame[0], ar->line_buff, ar->line_bytes);
+		//ar_outl(0xa1861300, M32700_DMA0CR0);
+		ar_outl(0x8080, M32700_DMAEN);		// enable DMA0
+		ar->start_capture = 1;			// during capture
+		return;
+	}
+
+	if (ar->start_capture == 1 && line_number <= (ar->height - 1)) {
+		ar_outl(0x8000, M32700_DMAEN);		// disable DMA0
+		memcpy(ar->frame[line_number], ar->line_buff, ar->line_bytes);
+
+		/*
+		 * if captured all line of a frame, disable AR interrupt
+		 * and wake a process up.
+		 */
+		if (line_number == (ar->height - 1)) { 	/* end  of line */
+
+			ar->start_capture = 0;
+
+			/* disable AR interrupt request */
+			arvcr1 = ar_inl(ARVCR1);
+			arvcr1 &= ~ARVCR1_HIEN;		// clear int. flag
+			ar_outl(arvcr1, ARVCR1);	// disable
+			wake_up_interruptible(&ar->wait);
+		} else {
+			//ar_outl(ar->line_buff, M32700_DMA0CDA);
+			//ar_outl(0xa1861300, M32700_DMA0CR0);
+			ar_outl(0x8080, M32700_DMAEN);		// enable DMA
+		}
+	}
+}
+#endif
+
+/*
+ * ar_initialize()
+ * 	ar_initialize() is called by video_register_device() and
+ *	initializes AR LSI and peripherals.
+ *
+ *	-1 is returned in all failures.
+ *	0 is returned in success.
+ *
+ */
+static int ar_initialize(struct video_device *dev)
+{
+	struct ar_device *ar = (struct ar_device *)dev->priv;
+	unsigned long cr = 0;
+	int i;
+
+	DEBUG(1, "ar_initialize:\n");
+
+	/*
+	 * initialize AR LSI
+	 */
+	ar_outl(0, ARVCR0);		// assert reset of AR LSI
+	for( i=0; i<0x10; i++);		// wait for over 10 cycles
+	ar_outl(ARVCR0_RST, ARVCR0);	// negate reset of AR LSI (enable)
+	for( i=0; i<0x200; i++);	// wait for over 420 cycles
+
+	/* AR uses INT3 of CPU as interrupt pin. */
+	ar_outl(ARINTSEL_INT3, ARINTSEL);
+	
+	if (ar->size == AR_SIZE_QVGA) cr |= ARVCR1_QVGA;
+	if (ar->mode == AR_MODE_NORMAL) cr |= ARVCR1_NORMAL;
+	ar_outl(cr, ARVCR1);
+
+  	/*
+	 * Initialize IIC so that CPU can communicate with AR LSI,
+	 * and send boot commands to AR LSI.
+	 */
+	init_iic();
+	iic(2,0x78,0x11,0x01,0x00);
+	iic(3,0x78,0x12,0x00,0x06); 
+	iic(3,0x78,0x12,0x12,0x30); 
+	iic(3,0x78,0x12,0x15,0x58); 
+	iic(3,0x78,0x12,0x17,0x30);
+	iic(3,0x78,0x12,0x1a,0x97);
+	iic(3,0x78,0x12,0x1b,0xff);
+	iic(3,0x78,0x12,0x1c,0xff);
+	iic(3,0x78,0x12,0x26,0x10);
+	iic(3,0x78,0x12,0x27,0x00);
+	iic(2,0x78,0x34,0x02,0x00); 
+	iic(2,0x78,0x7a,0x10,0x00);
+	iic(2,0x78,0x80,0x39,0x00); 
+	iic(2,0x78,0x81,0xe6,0x00); 
+	iic(2,0x78,0x8d,0x00,0x00);
+	iic(2,0x78,0x8e,0x0c,0x00);
+	iic(2,0x78,0x8f,0x00,0x00);
+	iic(2,0x78,0x93,0x01,0x00);
+	iic(2,0x78,0x94,0xcd,0x00);
+	iic(2,0x78,0x95,0x00,0x00);
+	iic(2,0x78,0x96,0xa0,0x00); 
+	iic(2,0x78,0x97,0x00,0x00);
+	iic(2,0x78,0x98,0x60,0x00);
+	iic(2,0x78,0x99,0x01,0x00);
+	iic(2,0x78,0x9a,0x19,0x00);
+	iic(2,0x78,0x9b,0x02,0x00);
+	iic(2,0x78,0x9c,0xe8,0x00);
+	iic(2,0x78,0x9d,0x02,0x00);
+	iic(2,0x78,0x9e,0x2e,0x00);
+	iic(2,0x78,0xb8,0x78,0x00);
+	iic(2,0x78,0xba,0x05,0x00);
+//	iic(2,0x78,0x83,0x8a,0x00);	// ÌÀ¤ë¤µÀßÄê
+	iic(2,0x78,0x11,0x00,0x00);	// ÀßÄê½ªÎ»
+	return 0;
+}
+
+/****************************************************************************
+ *
+ * Video4Linux Module functions
+ *
+ ****************************************************************************/
+static struct video_device ar_template = {
+	owner:		THIS_MODULE,
+	name:		"Colour AR VGA",
+	type:		VID_TYPE_CAPTURE,
+	hardware:	52,
+	open:		ar_open,
+	close:		ar_close,
+	read:		ar_read,
+	write:		ar_write,
+	ioctl:		ar_ioctl,
+	initialize:	ar_initialize,
+};
+
+#define ALIGN4(x)	((((int)(x)) & 0x3) == 0)
+static struct ar_device ardev;
+
+static int __init ar_init(void)
+{
+	struct ar_device *ar;
+	int ret;
+	int i;
+
+	DEBUG(1, "ar_init:\n");
+	ret = -EIO;
+	printk(KERN_INFO "%s: Colour AR VGA driver %s\n", __FILE__, VERSION);
+
+	ar = &ardev;
+	memset(ar, 0, sizeof(struct ar_device));
+	memcpy(&ar->vdev, &ar_template, sizeof(ar_template));
+
+#if USE_INT
+	/* allocate a DMA buffer for 1 line.  */
+	ar->line_buff = kmalloc(MAX_AR_LINE_BYTES, GFP_KERNEL | GFP_DMA);
+	if (ar->line_buff == NULL || ! ALIGN4(ar->line_buff)) {
+		printk("arv: buffer allocation failed for DMA.\n");
+		ret = -ENOMEM;
+		goto out_end;
+	}
+#endif
+	/* allocate buffers for a frame */
+	for (i = 0; i < MAX_AR_HEIGHT; i++) {
+		ar->frame[i] = kmalloc(MAX_AR_LINE_BYTES, GFP_KERNEL);
+		if (ar->frame[i] == NULL || ! ALIGN4(ar->frame[i])) {
+			printk("arv: buffer allocation failed for frame.\n");
+			ret = -ENOMEM;
+			goto out_line_buff;
+		}
+	}
+	ar->vdev.priv 	= ar;
+	if (vga) {
+        	ar->width 	= AR_WIDTH_VGA;
+        	ar->height 	= AR_HEIGHT_VGA;
+		ar->size 	= AR_SIZE_VGA;
+		ar->frame_bytes = AR_FRAME_BYTES_VGA;
+		ar->line_bytes	= AR_LINE_BYTES_VGA;
+		if (vga_interlace)
+			ar->mode = AR_MODE_INTERLACE;
+		else
+			ar->mode = AR_MODE_NORMAL;
+	} else {
+        	ar->width 	= AR_WIDTH_QVGA;
+        	ar->height 	= AR_HEIGHT_QVGA;
+		ar->size 	= AR_SIZE_QVGA;
+		ar->frame_bytes = AR_FRAME_BYTES_QVGA;
+		ar->line_bytes	= AR_LINE_BYTES_QVGA;
+		ar->mode	= AR_MODE_INTERLACE;
+	}
+	init_MUTEX(&ar->lock);
+	init_waitqueue_head(&ar->wait);
+
+#if USE_INT
+        if (request_irq(M32R_IRQ_INT3, ar_interrupt, 0, "arv", ar)){
+                printk("arv: request_irq(%d) failed.\n", M32R_IRQ_INT3);
+		ret = -EIO;
+		goto out_irq;
+        }
+#endif
+
+	/*
+	 * ok, we can initialize h/w according to parameters,
+	 * so register video device as a frame grabber type.
+	 * device is named "video[0-64]".
+	 * video_register_device() initializes h/w using ar_initialize().
+ 	 */
+	if (video_register_device(&ar->vdev, VFL_TYPE_GRABBER, video_nr)!=0) {
+		/* return -1, -ENFILE(full) or others */
+		printk("arv: register video (Colour AR) failed.\n");
+		ret = -ENODEV;
+		goto out_dev;
+	}
+	printk("video%d: Found M64278 VGA (IRQ %d, Freq %dMHz).\n",
+		ar->vdev.minor, M32R_IRQ_INT3, freq);
+	return 0;
+
+out_dev:
+#if USE_INT
+	free_irq(M32R_IRQ_INT3, ar);
+out_irq:
+#endif
+	for (i = 0; i < MAX_AR_HEIGHT; i++)
+		if (ar->frame[i]) kfree(ar->frame[i]);
+out_line_buff:
+#if USE_INT
+	kfree(ar->line_buff);
+out_end:
+#endif
+	return ret;
+}
+
+static int __init ar_init_module(void)
+{
+	freq = (boot_cpu_data.bus_clock / 1000000);
+	printk("arv: Bus clock %d\n", freq);
+	if (freq != 50 || freq != 70)
+		freq = DEFAULT_FREQ;
+	return ar_init();
+}
+
+static void __exit ar_cleanup_module(void)
+{
+	struct ar_device *ar;
+	int i;
+
+	ar = &ardev;
+	video_unregister_device(&ar->vdev);
+#if USE_INT
+	free_irq(M32R_IRQ_INT3, ar);
+#endif
+	for (i = 0; i < MAX_AR_HEIGHT; i++)
+		if (ar->frame[i]) kfree(ar->frame[i]);
+#if USE_INT
+	kfree(ar->line_buff);
+#endif
+}
+
+module_init(ar_init_module);
+module_exit(ar_cleanup_module);
+
+MODULE_AUTHOR("Takeo Takahashi <takahashi.takeo@renesas.com>");
+MODULE_DESCRIPTION("Colour AR M64278(VGA) for Video4Linux");
+MODULE_LICENSE("GPL");
+EXPORT_NO_SYMBOLS;
diff -ruN linux-2.4.26.org/arch/m32r/drivers/arv.h linux-2.4.26/arch/m32r/drivers/arv.h
--- linux-2.4.26.org/arch/m32r/drivers/arv.h	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/arch/m32r/drivers/arv.h	2003-09-16 19:18:54.000000000 +0900
@@ -0,0 +1,384 @@
+/*
+ * include/asm/m32700.h
+ *
+ * Control registers and Special function registers of M32700
+ *
+ * Copyright (c) 2003	Takeo Takahashi
+ *
+ * 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.
+ *
+ * $Id: arv.h,v 1.1 2003/09/16 10:18:54 takata Exp $
+ *
+ * 2003-08-26: Bug fixed.  M32700_DMA0BCUT => M32700_DMA0CBCUT
+ * 	       by Takeo Takahashi
+ *
+ */
+
+#ifndef _M32700_H
+#define _M32700_H
+
+#ifndef M32700_IAMOD
+#define M32700_IAMOD	0	/* default IAMOD=0 */
+#endif
+
+#if M32700_IAMOD
+#define M32700_IAMOD_SFR	(0x03e00000)
+#else
+#define M32700_IAMOD_SFR	(0x00e00000)
+#endif
+
+#ifndef __ASSEMBLY__
+#define M32700_SFR_BASE		(M32700_IAMOD_SFR)
+#define __reg8			(volatile unsigned char *)
+#define __reg16			(volatile unsigned short *)
+#define __reg32			(volatile unsigned int *)
+#else
+#define M32700_SFR_BASE		(M32700_IAMOD_SFR)
+#define __reg8
+#define __reg16
+#define __reg32
+#endif	/* __ASSEMBLY__ */
+
+/*************************************************
+ * Control Registers accessed directly
+ *************************************************/
+/*
+ * Instruction TLB table
+ */
+#define M32700_ITBL_NUMS	32
+#define M32700_ITBL_BASE	(0xfe000000)
+#define M32700_DTBL_NUMS	32
+#define M32700_DTBL_BASE	(0xfe000800)
+
+/*
+ * MMU
+ */
+#define M32700_MMU_BASE		(0xffff0000)
+#define M32700_MMU_MATM		__reg32(M32700_MMU_BASE + 0x00000000)
+#define M32700_MMU_MPSZ		__reg32(M32700_MMU_BASE + 0x00000004)
+#define M32700_MMU_MASID	__reg32(M32700_MMU_BASE + 0x00000008)
+#define M32700_MMU_MESTS	__reg32(M32700_MMU_BASE + 0x0000000c)
+#define M32700_MMU_MDEVA	__reg32(M32700_MMU_BASE + 0x00000010)
+#define M32700_MMU_MDEVP	__reg32(M32700_MMU_BASE + 0x00000014)
+#define M32700_MMU_MSVA		__reg32(M32700_MMU_BASE + 0x00000020)
+#define M32700_MMU_MTOP		__reg32(M32700_MMU_BASE + 0x00000024)
+#define M32700_MMU_MIDXI	__reg32(M32700_MMU_BASE + 0x00000028)
+#define M32700_MMU_MIDXD	__reg32(M32700_MMU_BASE + 0x0000002c)
+
+/*
+ * Cache
+ */
+#define M32700_CACHE_BASE	(0xfffffff0)
+#define M32700_CACHE_MCICAR	__reg32(M32700_CACHE_BASE + 0x00000000)
+#define M32700_CACHE_MCDCAR	__reg32(M32700_CACHE_BASE + 0x00000004)
+#define M32700_CACHE_MCCR	__reg32(M32700_CACHE_BASE + 0x0000000c)
+
+/*
+ * EIT
+ */
+#define M32700_EIT_RI		(0x00000000)
+#define M32700_EIT_EVB		(0x00000000)	/* this means offset */
+#define M32700_EIT_SBI		__reg32(M32700_EIT_EVB + 0x00000010)
+#define M32700_EIT_RIE		__reg32(M32700_EIT_EVB + 0x00000020)
+#define M32700_EIT_AE		__reg32(M32700_EIT_EVB + 0x00000030)
+#define M32700_EIT_TRAP0	__reg32(M32700_EIT_EVB + 0x00000040)
+#define M32700_EIT_TRAP1	__reg32(M32700_EIT_EVB + 0x00000044)
+#define M32700_EIT_TRAP2	__reg32(M32700_EIT_EVB + 0x00000048)
+#define M32700_EIT_TRAP3	__reg32(M32700_EIT_EVB + 0x0000004c)
+#define M32700_EIT_TRAP4	__reg32(M32700_EIT_EVB + 0x00000050)
+#define M32700_EIT_TRAP5	__reg32(M32700_EIT_EVB + 0x00000054)
+#define M32700_EIT_TRAP6	__reg32(M32700_EIT_EVB + 0x00000058)
+#define M32700_EIT_TRAP7	__reg32(M32700_EIT_EVB + 0x0000005c)
+#define M32700_EIT_TRAP8	__reg32(M32700_EIT_EVB + 0x00000060)
+#define M32700_EIT_TRAP9	__reg32(M32700_EIT_EVB + 0x00000064)
+#define M32700_EIT_TRAP10	__reg32(M32700_EIT_EVB + 0x00000068)
+#define M32700_EIT_TRAP11	__reg32(M32700_EIT_EVB + 0x0000006c)
+#define M32700_EIT_TRAP12	__reg32(M32700_EIT_EVB + 0x00000070)
+#define M32700_EIT_TRAP13	__reg32(M32700_EIT_EVB + 0x00000074)
+#define M32700_EIT_TRAP14	__reg32(M32700_EIT_EVB + 0x00000078)
+#define M32700_EIT_TRAP15	__reg32(M32700_EIT_EVB + 0x0000007c)
+#define M32700_EIT_EI		__reg32(M32700_EIT_EVB + 0x00000080)
+#define M32700_EIT_PIE		__reg32(M32700_EIT_EVB + 0x00000100)
+#define M32700_EIT_IACE		__reg32(M32700_EIT_EVB + 0x00000110)
+#define M32700_EIT_DACE		__reg32(M32700_EIT_EVB + 0x00000110)
+#define M32700_EIT_ITME		__reg32(M32700_EIT_EVB + 0x00000120)
+#define M32700_EIT_DTME		__reg32(M32700_EIT_EVB + 0x00000120)
+
+/*
+ * Multi-Processor
+ */
+#define M32700_MP_BASE		(0xffffffe0)
+#define M32700_MP_CPUID		__reg32(M32700_MP_BASE + 0x00000000)
+
+/*************************************************
+ * Special Function Registers accessed by io/out
+ *************************************************/
+
+/*
+ * Programable Port
+ */
+#define M32700_P0IEN		__reg8(M32700_SFR_BASE + 0x000f1000)
+#define M32700_P1IEN		__reg8(M32700_SFR_BASE + 0x000f1001)
+#define M32700_P2IEN		__reg8(M32700_SFR_BASE + 0x000f1002)
+#define M32700_P3IEN		__reg8(M32700_SFR_BASE + 0x000f1003)
+#define M32700_P4IEN		__reg8(M32700_SFR_BASE + 0x000f1004)
+#define M32700_P5IEN		__reg8(M32700_SFR_BASE + 0x000f1005)
+#define M32700_P6IEN		__reg8(M32700_SFR_BASE + 0x000f1006)
+#define M32700_P7IEN		__reg8(M32700_SFR_BASE + 0x000f1007)
+#define M32700_P8IEN		__reg8(M32700_SFR_BASE + 0x000f1008)
+
+#define M32700_P0DIR		__reg8(M32700_SFR_BASE + 0x000f1010)
+#define M32700_P1DIR		__reg8(M32700_SFR_BASE + 0x000f1011)
+#define M32700_P2DIR		__reg8(M32700_SFR_BASE + 0x000f1012)
+#define M32700_P3DIR		__reg8(M32700_SFR_BASE + 0x000f1013)
+#define M32700_P4DIR		__reg8(M32700_SFR_BASE + 0x000f1014)
+#define M32700_P5DIR		__reg8(M32700_SFR_BASE + 0x000f1015)
+#define M32700_P6DIR		__reg8(M32700_SFR_BASE + 0x000f1016)
+#define M32700_P7DIR		__reg8(M32700_SFR_BASE + 0x000f1017)
+#define M32700_P8DIR		__reg8(M32700_SFR_BASE + 0x000f1018)
+
+#define M32700_P0PDCR		__reg16(M32700_SFR_BASE + 0x000f1020)
+#define M32700_P1PDCR		__reg16(M32700_SFR_BASE + 0x000f1022)
+#define M32700_P2PDCR		__reg16(M32700_SFR_BASE + 0x000f1024)
+#define M32700_P3PDCR		__reg16(M32700_SFR_BASE + 0x000f1026)
+#define M32700_P4PDCR		__reg16(M32700_SFR_BASE + 0x000f1028)
+#define M32700_P5PDCR		__reg16(M32700_SFR_BASE + 0x000f102a)
+#define M32700_P6PDCR		__reg16(M32700_SFR_BASE + 0x000f102c)
+#define M32700_P7PDCR		__reg16(M32700_SFR_BASE + 0x000f102e)
+#define M32700_P8PDCR		__reg16(M32700_SFR_BASE + 0x000f1030)
+
+#define M32700_P0OCR		__reg16(M32700_SFR_BASE + 0x000f1040)
+#define M32700_P1OCR		__reg16(M32700_SFR_BASE + 0x000f1042)
+#define M32700_P2OCR		__reg16(M32700_SFR_BASE + 0x000f1044)
+#define M32700_P3OCR		__reg16(M32700_SFR_BASE + 0x000f1046)
+#define M32700_P4OCR		__reg16(M32700_SFR_BASE + 0x000f1048)
+#define M32700_P5OCR		__reg16(M32700_SFR_BASE + 0x000f104a)
+#define M32700_P6OCR		__reg16(M32700_SFR_BASE + 0x000f104c)
+#define M32700_P7OCR		__reg16(M32700_SFR_BASE + 0x000f104e)
+#define M32700_P8OCR		__reg16(M32700_SFR_BASE + 0x000f1050)
+
+#define M32700_P0MOD		__reg16(M32700_SFR_BASE + 0x000f1060)
+#define M32700_P1MOD		__reg16(M32700_SFR_BASE + 0x000f1062)
+#define M32700_P2MOD		__reg16(M32700_SFR_BASE + 0x000f1064)
+#define M32700_P3MOD		__reg16(M32700_SFR_BASE + 0x000f1066)
+#define M32700_P4MOD		__reg16(M32700_SFR_BASE + 0x000f1068)
+#define M32700_P5MOD		__reg16(M32700_SFR_BASE + 0x000f106a)
+#define M32700_P6MOD		__reg16(M32700_SFR_BASE + 0x000f106c)
+#define M32700_P7MOD		__reg16(M32700_SFR_BASE + 0x000f106e)
+#define M32700_P8MOD		__reg16(M32700_SFR_BASE + 0x000f1070)
+
+#define M32700_P0DATA		__reg8(M32700_SFR_BASE + 0x000f1080)
+#define M32700_P1DATA		__reg8(M32700_SFR_BASE + 0x000f1081)
+#define M32700_P2DATA		__reg8(M32700_SFR_BASE + 0x000f1082)
+#define M32700_P3DATA		__reg8(M32700_SFR_BASE + 0x000f1083)
+#define M32700_P4DATA		__reg8(M32700_SFR_BASE + 0x000f1084)
+#define M32700_P5DATA		__reg8(M32700_SFR_BASE + 0x000f1085)
+#define M32700_P6DATA		__reg8(M32700_SFR_BASE + 0x000f1086)
+#define M32700_P7DATA		__reg8(M32700_SFR_BASE + 0x000f1087)
+#define M32700_P8DATA		__reg8(M32700_SFR_BASE + 0x000f1088)
+
+/*
+ * ICU
+ */
+#define M32700_ICUISTS		__reg32(M32700_SFR_BASE + 0x000ff004)
+#define M32700_ICUIREQ0		__reg32(M32700_SFR_BASE + 0x000ff008)
+#define M32700_ICUIREQ1		__reg32(M32700_SFR_BASE + 0x000ff00c)
+
+#define M32700_ICUSBICR		__reg32(M32700_SFR_BASE + 0x000ff018)
+#define M32700_ICUIMASK		__reg32(M32700_SFR_BASE + 0x000ff01c)
+
+#define M32700_ICUCR1		__reg32(M32700_SFR_BASE + 0x000ff200)
+#define M32700_ICUCR2		__reg32(M32700_SFR_BASE + 0x000ff204)
+#define M32700_ICUCR3		__reg32(M32700_SFR_BASE + 0x000ff208)
+#define M32700_ICUCR4		__reg32(M32700_SFR_BASE + 0x000ff20c)
+#define M32700_ICUCR5		__reg32(M32700_SFR_BASE + 0x000ff210)
+#define M32700_ICUCR6		__reg32(M32700_SFR_BASE + 0x000ff214)
+#define M32700_ICUCR7		__reg32(M32700_SFR_BASE + 0x000ff218)
+#define M32700_ICUCR8		__reg32(M32700_SFR_BASE + 0x000ff21c)
+#define M32700_ICUCR16		__reg32(M32700_SFR_BASE + 0x000ff23c)
+#define M32700_ICUCR17		__reg32(M32700_SFR_BASE + 0x000ff24c)
+#define M32700_ICUCR18		__reg32(M32700_SFR_BASE + 0x000ff244)
+#define M32700_ICUCR19		__reg32(M32700_SFR_BASE + 0x000ff248)
+#define M32700_ICUCR20		__reg32(M32700_SFR_BASE + 0x000ff24c)
+#define M32700_ICUCR21		__reg32(M32700_SFR_BASE + 0x000ff250)
+#define M32700_ICUCR32		__reg32(M32700_SFR_BASE + 0x000ff27c)
+#define M32700_ICUCR33		__reg32(M32700_SFR_BASE + 0x000ff280)
+#define M32700_ICUCR48		__reg32(M32700_SFR_BASE + 0x000ff2bc)
+#define M32700_ICUCR49		__reg32(M32700_SFR_BASE + 0x000ff2c0)
+#define M32700_ICUCR50		__reg32(M32700_SFR_BASE + 0x000ff2c4)
+#define M32700_ICUCR51		__reg32(M32700_SFR_BASE + 0x000ff2c8)
+
+#define M32700_WKUPCR		__reg32(M32700_SFR_BASE + 0x000ff2d8)
+#define M32700_IPICR0		__reg32(M32700_SFR_BASE + 0x000ff2dc)
+#define M32700_IPICR1		__reg32(M32700_SFR_BASE + 0x000ff2e0)
+#define M32700_IPICR2		__reg32(M32700_SFR_BASE + 0x000ff2e4)
+#define M32700_IPICR3		__reg32(M32700_SFR_BASE + 0x000ff2e8)
+#define M32700_IPICR4		__reg32(M32700_SFR_BASE + 0x000ff2ec)
+#define M32700_IPICR5		__reg32(M32700_SFR_BASE + 0x000ff2f0)
+#define M32700_IPICR6		__reg32(M32700_SFR_BASE + 0x000ff2f4)
+#define M32700_IPICR7		__reg32(M32700_SFR_BASE + 0x000ff2f8)
+
+/*
+ * Block Select Controller
+ */
+#define M32700_BSEL0CR0		__reg32(M32700_SFR_BASE + 0x000f5000)
+#define M32700_BSEL1CR0		__reg32(M32700_SFR_BASE + 0x000f5100)
+#define M32700_BSEL2CR0		__reg32(M32700_SFR_BASE + 0x000f5200)
+#define M32700_BSEL3CR0		__reg32(M32700_SFR_BASE + 0x000f5300)
+#define M32700_BSEL4CR0		__reg32(M32700_SFR_BASE + 0x000f5400)
+#define M32700_BSEL5CR0		__reg32(M32700_SFR_BASE + 0x000f5500)
+#define M32700_BSEL6CR0		__reg32(M32700_SFR_BASE + 0x000f5600)
+#define M32700_BSEL7CR0		__reg32(M32700_SFR_BASE + 0x000f5700)
+
+#define M32700_BSEL0CR1		__reg32(M32700_SFR_BASE + 0x000f5004)
+#define M32700_BSEL1CR1		__reg32(M32700_SFR_BASE + 0x000f5104)
+#define M32700_BSEL2CR1		__reg32(M32700_SFR_BASE + 0x000f5204)
+#define M32700_BSEL3CR1		__reg32(M32700_SFR_BASE + 0x000f5304)
+#define M32700_BSEL4CR1		__reg32(M32700_SFR_BASE + 0x000f5404)
+#define M32700_BSEL5CR1		__reg32(M32700_SFR_BASE + 0x000f5504)
+#define M32700_BSEL6CR1		__reg32(M32700_SFR_BASE + 0x000f5604)
+#define M32700_BSEL7CR1		__reg32(M32700_SFR_BASE + 0x000f5704)
+
+/*
+ * SDRAMC
+ */
+#define M32700_SDRF0		__reg32(M32700_SFR_BASE + 0x000f6000)
+#define M32700_SDRF1		__reg32(M32700_SFR_BASE + 0x000f6004)
+#define M32700_SDIR0		__reg32(M32700_SFR_BASE + 0x000f6008)
+#define M32700_SDIR1		__reg32(M32700_SFR_BASE + 0x000f600c)
+
+#define M32700_SD0ADR		__reg32(M32700_SFR_BASE + 0x000f6020)
+#define M32700_SD0ER		__reg32(M32700_SFR_BASE + 0x000f6024)
+#define M32700_SD0TR		__reg32(M32700_SFR_BASE + 0x000f6028)
+#define M32700_SD0MOD		__reg32(M32700_SFR_BASE + 0x000f602c)
+
+#define M32700_SD1ADR		__reg32(M32700_SFR_BASE + 0x000f6040)
+#define M32700_SD1ER		__reg32(M32700_SFR_BASE + 0x000f6044)
+#define M32700_SD1TR		__reg32(M32700_SFR_BASE + 0x000f6048)
+#define M32700_SD1MOD		__reg32(M32700_SFR_BASE + 0x000f604c)
+
+/*
+ * PCC
+ */
+#define M32700_PCCR		__reg32(M32700_SFR_BASE + 0x000f7000)
+#define M32700_PCADR		__reg32(M32700_SFR_BASE + 0x000f7004)
+#define M32700_PCMOD		__reg32(M32700_SFR_BASE + 0x000f7008)
+#define M32700_PCIRC		__reg32(M32700_SFR_BASE + 0x000f700c)
+#define M32700_PCCSIGCR		__reg32(M32700_SFR_BASE + 0x000f7010)
+#define M32700_PCATCR		__reg32(M32700_SFR_BASE + 0x000f7014)
+
+/*
+ * DMAC
+ */
+#define M32700_DMAEN		__reg32(M32700_SFR_BASE + 0x000f8000)
+#define M32700_DMAISTS		__reg32(M32700_SFR_BASE + 0x000f8004)
+#define M32700_DMAEDET		__reg32(M32700_SFR_BASE + 0x000f8008)
+#define M32700_DMAASTS		__reg32(M32700_SFR_BASE + 0x000f800c)
+
+#define M32700_DMA0CR0		__reg32(M32700_SFR_BASE + 0x000f8100)
+#define M32700_DMA0CR1		__reg32(M32700_SFR_BASE + 0x000f8104)
+#define M32700_DMA0CSA		__reg32(M32700_SFR_BASE + 0x000f8108)
+#define M32700_DMA0RSA		__reg32(M32700_SFR_BASE + 0x000f810c)
+#define M32700_DMA0CDA		__reg32(M32700_SFR_BASE + 0x000f8110)
+#define M32700_DMA0RDA		__reg32(M32700_SFR_BASE + 0x000f8114)
+#define M32700_DMA0CBCUT	__reg32(M32700_SFR_BASE + 0x000f8118)
+#define M32700_DMA0RBCUT	__reg32(M32700_SFR_BASE + 0x000f811c)
+
+#define M32700_DMA1CR0		__reg32(M32700_SFR_BASE + 0x000f8200)
+#define M32700_DMA1CR1		__reg32(M32700_SFR_BASE + 0x000f8204)
+#define M32700_DMA1CSA		__reg32(M32700_SFR_BASE + 0x000f8208)
+#define M32700_DMA1RSA		__reg32(M32700_SFR_BASE + 0x000f820c)
+#define M32700_DMA1CDA		__reg32(M32700_SFR_BASE + 0x000f8210)
+#define M32700_DMA1RDA		__reg32(M32700_SFR_BASE + 0x000f8214)
+#define M32700_DMA1CBCUT	__reg32(M32700_SFR_BASE + 0x000f8218)
+#define M32700_DMA1RBCUT	__reg32(M32700_SFR_BASE + 0x000f821c)
+
+/*
+ * MFT
+ */
+#define M32700_MFTCR		__reg32(M32700_SFR_BASE + 0x000fc000)
+#define M32700_MFTRPR		__reg32(M32700_SFR_BASE + 0x000fc004)
+
+#define M32700_MFT0MOD		__reg32(M32700_SFR_BASE + 0x000fc100)
+#define M32700_MFT0OS		__reg32(M32700_SFR_BASE + 0x000fc104)
+#define M32700_MFT0CUT		__reg32(M32700_SFR_BASE + 0x000fc108)
+#define M32700_MFT0RLD		__reg32(M32700_SFR_BASE + 0x000fc10c)
+#define M32700_MFT0CMPRLD	__reg32(M32700_SFR_BASE + 0x000fc110)
+
+#define M32700_MFT1MOD		__reg32(M32700_SFR_BASE + 0x000fc200)
+#define M32700_MFT1OS		__reg32(M32700_SFR_BASE + 0x000fc204)
+#define M32700_MFT1CUT		__reg32(M32700_SFR_BASE + 0x000fc208)
+#define M32700_MFT1RLD		__reg32(M32700_SFR_BASE + 0x000fc20c)
+#define M32700_MFT1CMPRLD	__reg32(M32700_SFR_BASE + 0x000fc210)
+
+#define M32700_MFT2MOD		__reg32(M32700_SFR_BASE + 0x000fc300)
+#define M32700_MFT2OS		__reg32(M32700_SFR_BASE + 0x000fc304)
+#define M32700_MFT2CUT		__reg32(M32700_SFR_BASE + 0x000fc308)
+#define M32700_MFT2RLD		__reg32(M32700_SFR_BASE + 0x000fc30c)
+#define M32700_MFT2CMPRLD	__reg32(M32700_SFR_BASE + 0x000fc310)
+
+#define M32700_MFT3MOD		__reg32(M32700_SFR_BASE + 0x000fc400)
+#define M32700_MFT3OS		__reg32(M32700_SFR_BASE + 0x000fc404)
+#define M32700_MFT3CUT		__reg32(M32700_SFR_BASE + 0x000fc408)
+#define M32700_MFT3RLD		__reg32(M32700_SFR_BASE + 0x000fc40c)
+#define M32700_MFT3CMPRLD	__reg32(M32700_SFR_BASE + 0x000fc410)
+
+#define M32700_MFT4MOD		__reg32(M32700_SFR_BASE + 0x000fc500)
+#define M32700_MFT4OS		__reg32(M32700_SFR_BASE + 0x000fc504)
+#define M32700_MFT4CUT		__reg32(M32700_SFR_BASE + 0x000fc508)
+#define M32700_MFT4RLD		__reg32(M32700_SFR_BASE + 0x000fc50c)
+#define M32700_MFT4CMPRLD	__reg32(M32700_SFR_BASE + 0x000fc510)
+
+#define M32700_MFT5MOD		__reg32(M32700_SFR_BASE + 0x000fc600)
+#define M32700_MFT5OS		__reg32(M32700_SFR_BASE + 0x000fc604)
+#define M32700_MFT5CUT		__reg32(M32700_SFR_BASE + 0x000fc608)
+#define M32700_MFT5RLD		__reg32(M32700_SFR_BASE + 0x000fc60c)
+#define M32700_MFT5CMPRLD	__reg32(M32700_SFR_BASE + 0x000fc610)
+
+/*
+ * SIO
+ */
+#define M32700_SIO0CR		__reg32(M32700_SFR_BASE + 0x000fd000)
+#define M32700_SIO0MOD0		__reg32(M32700_SFR_BASE + 0x000fd004)
+#define M32700_SIO0MOD1		__reg32(M32700_SFR_BASE + 0x000fd008)
+#define M32700_SIO0STS		__reg32(M32700_SFR_BASE + 0x000fd00c)
+#define M32700_SIO0TRCR		__reg32(M32700_SFR_BASE + 0x000fd010)
+#define M32700_SIO0BAUR		__reg32(M32700_SFR_BASE + 0x000fd014)
+#define M32700_SIO0RBAUR	__reg32(M32700_SFR_BASE + 0x000fd018)
+#define M32700_SIO0TXB		__reg32(M32700_SFR_BASE + 0x000fd01c)
+#define M32700_SIO0RXB		__reg32(M32700_SFR_BASE + 0x000fd020)
+
+#define M32700_SIO1CR		__reg32(M32700_SFR_BASE + 0x000fd100)
+#define M32700_SIO1MOD0		__reg32(M32700_SFR_BASE + 0x000fd104)
+#define M32700_SIO1MOD1		__reg32(M32700_SFR_BASE + 0x000fd108)
+#define M32700_SIO1STS		__reg32(M32700_SFR_BASE + 0x000fd10c)
+#define M32700_SIO1TRCR		__reg32(M32700_SFR_BASE + 0x000fd110)
+#define M32700_SIO1BAUR		__reg32(M32700_SFR_BASE + 0x000fd114)
+#define M32700_SIO1RBAUR	__reg32(M32700_SFR_BASE + 0x000fd118)
+#define M32700_SIO1TXB		__reg32(M32700_SFR_BASE + 0x000fd11c)
+#define M32700_SIO1RXB		__reg32(M32700_SFR_BASE + 0x000fd120)
+
+/*
+ * WDT
+ */
+#define M32700_WDTCR		__reg32(M32700_SFR_BASE + 0x000f2000)
+
+/*
+ * Clock
+ */
+#define M32700_PLLCR		__reg32(M32700_SFR_BASE + 0x000f4004)
+#define M32700_MASTERCR		__reg32(M32700_SFR_BASE + 0x000f4008)
+#define M32700_CPU0DIV		__reg32(M32700_SFR_BASE + 0x000f4010)
+#define M32700_CPU1DIV		__reg32(M32700_SFR_BASE + 0x000f4014)
+#define M32700_BIFDIV		__reg32(M32700_SFR_BASE + 0x000f4020)
+#define M32700_BCLKDIV		__reg32(M32700_SFR_BASE + 0x000f4024)
+#define M32700_FCLKSEL		__reg32(M32700_SFR_BASE + 0x000f4028)
+#define M32700_CPU0STOP		__reg32(M32700_SFR_BASE + 0x000f4030)
+#define M32700_CPU1STOP		__reg32(M32700_SFR_BASE + 0x000f4034)
+#define M32700_STNBY		__reg32(M32700_SFR_BASE + 0x000f404c)
+#define M32700_CDIVST		__reg32(M32700_SFR_BASE + 0x000f4050)
+
+#endif	/* _M32700_H */
diff -ruN linux-2.4.26.org/arch/m32r/drivers/dbg_console.c linux-2.4.26/arch/m32r/drivers/dbg_console.c
--- linux-2.4.26.org/arch/m32r/drivers/dbg_console.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/arch/m32r/drivers/dbg_console.c	2004-01-06 21:43:54.000000000 +0900
@@ -0,0 +1,3609 @@
+/* $Id: dbg_console.c,v 1.4 2004/01/06 12:43:54 takeo Exp $
+ *
+ * Much of the design and some of the code came from serial.c:
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *  Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997,
+ *              1998, 1999  Theodore Ts'o
+ *
+ * M32R work:
+ *  Copyright (C) 2000,2001  by Hiro Kondo, Hiro Takata, and Hitoshi Yamamoto.
+ *
+ */
+
+static char *serial_version = "kondo";
+static char *serial_revdate = "2002-09-11";
+static char *serial_name = "M32R Serial driver";
+
+#define LOCAL_VERSTRING ""
+
+#undef DC_DEBUG
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/tty_driver.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+#include <linux/major.h>
+#include <linux/console.h>
+#include <linux/kdev_t.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/serial.h>
+#include <linux/serialP.h>  /* serial_state */
+#include <linux/slab.h>  /* kmalloc */
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/serial.h>
+#include <asm/m32r.h>
+
+#if defined(CONFIG_PLAT_USRV)
+#undef SERIAL_BH
+#define SERIAL_BH	MACSERIAL_BH
+#endif
+
+extern struct console  console_for_debug;
+
+static int dc_write(struct tty_struct *tty, int from_user, 
+			const unsigned char *buf, int count);
+static int dc_write_room(struct tty_struct *tty);
+static int dc_chars_in_buffer(struct tty_struct *tty);
+
+static void dbg_console_write(struct console *, const char *, unsigned);
+static kdev_t dbg_console_device(struct console *c);
+void dc_interrupt_single(int, void *, struct pt_regs *);
+static void dc_receive_chars(struct async_struct *, int *);
+
+static void dc_wait_until_sent(struct tty_struct *, int);
+static void change_speed(struct async_struct *,struct termios *);
+static void autoconfig(struct serial_state *);
+static unsigned detect_uart_irq (struct serial_state *);
+
+static struct tty_driver dc_driver;
+static int dc_refcount;
+
+#define RS_STROBE_TIME (10*HZ)
+#define RS_ISR_PASS_LIMIT 256
+
+/* number of characters left in xmit buffer before we ask for more */
+#define WAKEUP_CHARS 256
+
+static struct async_struct *IRQ_ports[NR_IRQS];
+static int IRQ_timeout[NR_IRQS];
+#ifdef CONFIG_SERIAL_CONSOLE
+static struct console cons;
+static int lsr_break_flag;
+#endif
+
+#define BAUDRATE  38400        /* Set Baudrate */
+#define BAUDRATE 115200        /* Set Baudrate */
+#define BAUDRATE  19200        /* Set Baudrate */
+
+/*
+ * Here we define the default xmit fifo size used for each type of
+ * UART
+ */
+static struct serial_uart_config uart_config[] = {
+	{ "unknown", 1, 0 },
+	{ "8250", 1, 0 },
+	{ "16450", 1, 0 },
+	{ "16550", 1, 0 },
+	{ "16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO },
+	{ "cirrus", 1, 0 },     /* usurped by cyclades.c */
+	{ "ST16650", 1, UART_CLEAR_FIFO | UART_STARTECH },
+	{ "ST16650V2", 32, UART_CLEAR_FIFO | UART_USE_FIFO |
+		UART_STARTECH },
+	{ "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO},
+	{ "Startech", 1, 0},    /* usurped by cyclades.c */
+	{ "16C950/954", 128, UART_CLEAR_FIFO | UART_USE_FIFO},
+	{ "ST16654", 64, UART_CLEAR_FIFO | UART_USE_FIFO |
+		UART_STARTECH },
+	{ "XR16850", 128, UART_CLEAR_FIFO | UART_USE_FIFO |
+		UART_STARTECH },
+	{ "RSA", 2048, UART_CLEAR_FIFO | UART_USE_FIFO },
+	{ "m32102", 1, 0 },
+	{ 0, 0}
+};
+
+#ifdef CONFIG_LINUX_2_2
+static struct serial_state rs_table[] = {
+	{ 0, BAUD9600, 0x3F8, 4, STD_COM_FLAGS }, 
+};
+#else
+static struct serial_state rs_table[RS_TABLE_SIZE] = {
+/*    UART CLK        PORT        IRQ   FLAGS        */ 
+	{ 0,   BAUDRATE, 0xa0efd000, 48,   STD_COM_FLAGS }, 
+	{ 0,   BAUDRATE, 0xa0efd100, 50,   STD_COM_FLAGS }, 
+#if 0
+	SERIAL_PORT_DFNS  /* Defined in serial.h */
+#endif
+};
+#endif
+#define NR_PORTS    (sizeof(rs_table)/sizeof(struct serial_state))
+
+
+#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
+
+static DECLARE_TASK_QUEUE(tq_dc_serial);
+static struct tty_struct *dc_table[NR_PORTS];
+static struct termios *dc_termios[NR_PORTS];
+static struct termios *dc_termios_locked[NR_PORTS];
+
+#if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT)
+#define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \
+ kdevname(tty->device), (info->flags), serial_refcount,info->count,tty->count,s
+)
+#else
+#define DBG_CNT(s)
+#endif
+
+
+static struct timer_list serial_timer;
+
+static unsigned char *tmp_buf;
+#ifdef DECLARE_MUTEX
+static DECLARE_MUTEX(tmp_buf_sem);
+#else
+static struct semaphore tmp_buf_sem = MUTEX;
+#endif
+
+#if defined(CONFIG_PLAT_MAPPI) || defined(CONFIG_PLAT_MAPPI2) \
+	|| defined(CONFIG_PLAT_USRV)
+static int dbg_console_setup(struct console *console, char *options);
+static int sio_putchar(int);
+
+#if defined(CONFIG_CHIP_XNUX_MP) || defined(CONFIG_CHIP_XNUX2_MP)
+#include <asm/page.h>
+#define _X(x) ((volatile unsigned long *)((x) + __PAGE_OFFSET))
+#define SIO0CR     _X(M32R_SIO0_CR_PORTL)
+#define SIO0MOD0   _X(M32R_SIO0_MOD0_PORTL)
+#define SIO0MOD1   _X(M32R_SIO0_MOD1_PORTL)
+#define SIO0STS    _X(M32R_SIO0_STS_PORTL)
+#define SIO0IMASK  _X(M32R_SIO0_TRCR_PORTL)
+#define SIO0BAUR   _X(M32R_SIO0_BAUR_PORTL)
+#define SIO0RBAUR  _X(M32R_SIO0_RBAUR_PORTL)
+#define SIO0TXB    _X(M32R_SIO0_TXB_PORTL)
+#define SIO0RXB    _X(M32R_SIO0_RXB_PORTL)
+#endif 
+
+
+#define SIO_IMASK_TEMPIE       (1UL<<0)  /* b31: enable */
+#define SIO_IMASK_RXCEN        (1UL<<2)  /* b29: enable */
+#define SIO_IMASK_REIE         (1UL<<3)  /* b28: enable */
+#define	SIO_SIO0STS_TEMP       (1UL<<0)  /* Transmitter Register Empty */
+#define	SIO_SIO0STS_TXCP       (1UL<<1)
+#define	SIO_SIO0STS_RXCP       (1UL<<2)
+#define	SIO_SIO0STS_OERR       (1UL<<5)
+#define	SIO_SIO0STS_PERR       (1UL<<6)
+#define	SIO_SIO0STS_FERR       (1UL<<7)
+#define	SIO_SIO0MOD0_RTSS      (1UL<<7)
+#define	SIO_SIO0MOD0_CTSS      (1UL<<6)
+#define	SIO_NONE               (0UL)
+
+#define	UART_TX                ((unsigned char *)SIO0TXB - (unsigned char *)SIO0CR)
+#define	UART_RX                ((unsigned char *)SIO0RXB - (unsigned char *)SIO0CR)
+#define	UART_IER               ((unsigned char *)SIO0IMASK - (unsigned char *)SIO0CR)
+#define UART_IER_THRI          SIO_IMASK_TEMPIE
+#define UART_IER_MSI           SIO_NONE
+#define UART_IER_RLSI          SIO_IMASK_REIE
+#define UART_IER_RDI           SIO_IMASK_RXCEN
+#define	UART_LSR               ((unsigned char *)SIO0STS - (unsigned char *)SIO0CR)
+#define	UART_LSR_DR            SIO_SIO0STS_RXCP
+#define	UART_LSR_THRE          SIO_SIO0STS_TEMP
+#define	UART_LSR_TEMT          SIO_SIO0STS_TXCP
+#define	UART_LSR_BI            SIO_NONE
+#define	UART_LSR_PE            SIO_SIO0STS_PERR
+#define	UART_LSR_FE            SIO_SIO0STS_FERR
+#define	UART_LSR_OE            SIO_SIO0STS_OERR
+#define	UART_IIR               ((unsigned char *)SIO0STS - (unsigned char *)SIO0CR)
+#define UART_IIR_NO_INT        0x01    /* No interrupts pending */
+#define	UART_LCR               ((unsigned char *)SIO0CR - (unsigned char *)SIO0CR)
+#define	UART_LCR_SBC           SIO_NONE
+#define	UART_LCR_PARITY        SIO_NONE
+#define	UART_LCR_EPAR          SIO_NONE
+#define	UART_LCR_SPAR          SIO_NONE
+#define	UART_MCR               ((unsigned char *)SIO0MOD0 - (unsigned char *)SIO0CR)
+#ifdef CONFIG_CHIP_M32700
+#define	UART_MCR_RTS           SIO_SIO0MOD0_RTSS
+#define	UART_MCR_DTR           SIO_NONE
+#else /* not CONFIG_CHIP_M32700 */
+#define	UART_MCR_RTS           SIO_SIO0MOD0_RTSS
+#define	UART_MCR_DTR           SIO_SIO0MOD0_CTSS
+#endif /* not CONFIG_CHIP_M32700 */
+#define	UART_MCR_LOOP          SIO_NONE
+#define	UART_MCR_OUT1          SIO_NONE
+#define	UART_MCR_OUT2          SIO_NONE
+#define	UART_MSR               ((unsigned char *)SIO0MOD0 - (unsigned char *)SIO0CR)
+#define	UART_MSR_DCD           SIO_NONE
+#define	UART_MSR_RI            SIO_NONE
+#define	UART_MSR_DSR           SIO_NONE
+#define	UART_MSR_CTS           SIO_NONE
+
+#define	UART_BAUR              ((unsigned char *)SIO0BAUR - (unsigned char *)SIO0CR)
+#define	UART_RBAUR             ((unsigned char *)SIO0RBAUR - (unsigned char *)SIO0CR)
+#define	UART_MOD0              ((unsigned char *)SIO0MOD0 - (unsigned char *)SIO0CR)
+#define	UART_MOD1              ((unsigned char *)SIO0MOD1 - (unsigned char *)SIO0CR)
+
+static  inline unsigned int dc_in(struct async_struct *info,int offset)
+{
+	return *(volatile unsigned int *)(info->port + offset);
+}
+static inline void dc_out(struct async_struct *info,int offset,int value)
+{
+	*(volatile unsigned int *)(info->port + offset) = value;
+}
+
+#define serial_in(info, offset)            dc_in(info,(int)offset)
+#define serial_out(info, offset, value)    dc_out(info,(int)offset, value)
+#define serial_inp(info, offset)           dc_in(info,(int)offset)
+#define serial_outp(info, offset, value)   dc_out(info,(int)offset, value)
+
+
+static inline int sio_putchar(int c)
+{
+	int save_psw;
+
+	if(c){
+	__asm__ __volatile__ (
+		"mvfc  r1,psw\n\t"
+		"mv    %0,r1\n\t"
+		"and3  r1,r1,#0x0000ffbf\n\t"
+		"mvtc  r1,psw\n"
+		:"=r" (save_psw):: "r1");
+
+	if(c < 0x80){
+		while((*SIO0STS & SIO_SIO0STS_TEMP) == 0);
+		*SIO0TXB = c;
+	}
+
+	__asm__ __volatile__ (
+		"mv    r1,%0\n\t"
+		"mvtc  r1,psw\n"
+		::"r" (save_psw): "r1");
+	}
+	return(c);
+}
+
+#endif /* CONFIG_PLAT_MAPPI */
+
+static inline int serial_paranoia_check(struct async_struct *info,
+				        kdev_t device, const char *routine)
+{
+#ifdef SERIAL_PARANOIA_CHECK
+	static const char *badmagic =
+		"Warning: bad magic number for serial struct (%s) in %s\n";
+	static const char *badinfo =
+		"Warning: null async_struct for (%s) in %s\n";
+
+	if (!info) {
+		printk(badinfo, kdevname(device), routine);
+		return 1;
+	}
+	if (info->magic != SERIAL_MAGIC) {
+		printk(badmagic, kdevname(device), routine);
+		return 1;
+	}
+#endif
+	return 0;
+}
+
+/*
+ * ------------------------------------------------------------
+ * dc_stop() and dc_start()
+ *
+ * This routines are called before setting or resetting tty->stopped.
+ * They enable or disable transmitter interrupts, as necessary.
+ * ------------------------------------------------------------
+ */
+static void dc_stop(struct tty_struct *tty)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	unsigned long flags;
+
+	if (serial_paranoia_check(info, tty->device, "dc_stop"))
+		return;
+	
+	save_flags(flags); cli();
+	if (info->IER & UART_IER_THRI) {
+		info->IER &= ~UART_IER_THRI;
+		serial_out(info, UART_IER, info->IER);
+	}
+#if 0  /* m32102_sio */ 
+	if (info->state->type == PORT_16C950) {
+		info->ACR |= UART_ACR_TXDIS;
+		serial_icr_write(info, UART_ACR, info->ACR);
+	}
+#endif  /* m32102_sio */
+	restore_flags(flags);
+
+}
+
+static void dc_start(struct tty_struct *tty)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	unsigned long flags;
+	
+	if (serial_paranoia_check(info, tty->device, "dc_start"))
+		return;
+	
+	save_flags(flags); cli();
+	if (info->xmit.head != info->xmit.tail
+		&& info->xmit.buf
+		&& !(info->IER & UART_IER_THRI)) {
+		info->IER |= UART_IER_THRI;
+		serial_out(info, UART_IER, info->IER);
+	}
+#if 0  /* m32102_sio */
+	if (info->state->type == PORT_16C950) {
+		info->ACR &= ~UART_ACR_TXDIS;
+		serial_icr_write(info, UART_ACR, info->ACR);
+	}
+#endif  /* m32102_sio */
+	restore_flags(flags);
+}
+
+
+/*
+ * This routine is used by the interrupt handler to schedule
+ * processing in the software interrupt portion of the driver.
+ */
+static inline void dc_sched_event(struct async_struct *info,int event)
+{
+	info->event |= 1 << event;
+	queue_task(&info->tqueue, &tq_dc_serial);
+	mark_bh(SERIAL_BH);
+}
+
+static inline void dc_receive_chars(struct async_struct *info,int *status)
+{
+	struct tty_struct *tty = info->tty;
+	unsigned char ch;
+	struct  async_icount *icount;
+	int max_count = 256;
+
+	icount = &info->state->icount;
+	do {
+		if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+			tty->flip.tqueue.routine((void *) tty);
+			if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+				return;     // if TTY_DONT_FLIP is set
+		}
+		ch = serial_inp(info, UART_RX);
+		*tty->flip.char_buf_ptr = ch;
+		icount->rx++;
+	
+#ifdef SERIAL_DEBUG_INTR
+		printk("DR%02x:%02x...", ch, *status);
+#endif
+		*tty->flip.flag_buf_ptr = 0;
+		if (*status & (UART_LSR_BI | UART_LSR_PE |
+			       UART_LSR_FE | UART_LSR_OE)) {
+			/*
+			 * For statistics only
+			 */
+			if (*status & UART_LSR_BI) {
+				*status &= ~(UART_LSR_FE | UART_LSR_PE);
+				icount->brk++;
+				/*
+				 * We do the SysRQ and SAK checking
+				 * here because otherwise the break
+				 * may get masked by ignore_status_mask
+				 * or read_status_mask.
+				 */
+#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+				if (info->line == cons.index) {
+					if (!break_pressed) {
+						break_pressed = jiffies;
+						goto ignore_char;
+					}
+					break_pressed = 0;
+				}
+#endif
+			        if (info->flags & ASYNC_SAK)
+					do_SAK(tty);
+			} else if (*status & UART_LSR_PE)
+				icount->parity++;
+			else if (*status & UART_LSR_FE)
+				icount->frame++;
+			if (*status & UART_LSR_OE)
+				icount->overrun++;
+
+			/*
+			 * Mask off conditions which should be ignored.
+			 */
+			*status &= info->read_status_mask;
+
+#ifdef CONFIG_SERIAL_CONSOLE
+			if (info->line == cons.index) {
+				/* Recover the break flag from console xmit */
+				*status |= lsr_break_flag;
+				lsr_break_flag = 0;
+			}
+#endif
+			if (*status & (UART_LSR_BI)) {
+#ifdef SERIAL_DEBUG_INTR
+				printk("handling break....");
+#endif
+				*tty->flip.flag_buf_ptr = TTY_BREAK;
+			} else if (*status & UART_LSR_PE)
+				*tty->flip.flag_buf_ptr = TTY_PARITY;
+			else if (*status & UART_LSR_FE)
+				*tty->flip.flag_buf_ptr = TTY_FRAME;
+		}
+#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+		if (break_pressed && info->line == cons.index) {
+			if (ch != 0 &&
+				time_before(jiffies, break_pressed + HZ*5)) {
+				handle_sysrq(ch, regs, NULL, NULL);
+				break_pressed = 0;
+				goto ignore_char;
+			}
+			break_pressed = 0;
+		}
+#endif
+		if ((*status & info->ignore_status_mask) == 0) {
+			tty->flip.flag_buf_ptr++;
+			tty->flip.char_buf_ptr++;
+			tty->flip.count++;
+		}
+#if 0 /* debug 020115 */
+		if ((*status & UART_LSR_OE) &&
+			(tty->flip.count < TTY_FLIPBUF_SIZE)) {
+			/*
+			 * Overrun is special, since it's reported
+			 * immediately, and doesn't affect the current
+			 * character
+			 */
+			*tty->flip.flag_buf_ptr = TTY_OVERRUN;
+			tty->flip.count++;
+			tty->flip.flag_buf_ptr++;
+			tty->flip.char_buf_ptr++;
+		}
+		if ((*status & info->ignore_status_mask) == 0) {
+			tty->flip.flag_buf_ptr++;
+			tty->flip.char_buf_ptr++;
+			tty->flip.count++;
+		}
+		if ((*status & UART_LSR_OE) &&
+			(tty->flip.count < TTY_FLIPBUF_SIZE)) {
+			/*
+			 * Overrun is special, since it's reported
+			 * immediately, and doesn't affect the current
+			 * character
+			 */
+			*tty->flip.flag_buf_ptr = TTY_OVERRUN;
+			tty->flip.count++;
+			tty->flip.flag_buf_ptr++;
+			tty->flip.char_buf_ptr++;
+		}
+#endif /* debug 020115 */
+#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+	ignore_char:
+#endif
+		*status = serial_inp(info, UART_LSR);
+	} while ((*status & UART_LSR_DR) && (max_count-- > 0));
+#if (LINUX_VERSION_CODE > 131394) /* 2.1.66 */
+	tty_flip_buffer_push(tty);
+#else
+	queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
+#endif
+}
+
+static void transmit_chars(struct async_struct *info, int *intr_done)
+{
+	int count;
+
+	if (info->x_char) {
+		serial_outp(info, UART_TX, info->x_char);
+		info->state->icount.tx++;
+		info->x_char = 0;
+		if (intr_done)
+			*intr_done = 0;
+		while((serial_in(info,UART_LSR) & UART_LSR_TEMT) == 0);
+		return;
+	}
+	if (info->xmit.head == info->xmit.tail
+		|| info->tty->stopped
+		|| info->tty->hw_stopped) {
+		info->IER &= ~UART_IER_THRI;
+		serial_out(info, UART_IER, info->IER);
+		return;
+	}
+	count = info->xmit_fifo_size;
+	count = SERIAL_XMIT_SIZE-1;
+	do {
+		serial_out(info, UART_TX, info->xmit.buf[info->xmit.tail]);
+		info->xmit.tail = (info->xmit.tail + 1) & (SERIAL_XMIT_SIZE-1);
+		info->state->icount.tx++;
+
+		if (info->xmit.head == info->xmit.tail)
+			break;
+
+		while((serial_in(info,UART_LSR) & UART_LSR_THRE) == 0);
+	} while (--count > 0);
+	while((serial_in(info,UART_LSR) & UART_LSR_TEMT) == 0);
+
+	if (CIRC_CNT(info->xmit.head,
+			 info->xmit.tail,
+			 SERIAL_XMIT_SIZE) < WAKEUP_CHARS)
+		dc_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+
+#ifdef SERIAL_DEBUG_INTR
+	printk("THRE...");
+#endif
+	if (intr_done)
+		*intr_done = 0;
+
+	if (info->xmit.head == info->xmit.tail) {
+		info->IER &= ~UART_IER_THRI;
+		serial_out(info, UART_IER, info->IER);
+	}
+}
+
+
+/*
+static _INLINE_ void check_modem_status(struct async_struct *info)
+
+#ifdef CONFIG_SERIAL_SHARE_IRQ
+static void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+#endif 
+*/
+
+static void sio_reset(struct async_struct *info)
+{
+#if defined(CONFIG_PLAT_MAPPI) || defined(CONFIG_PLAT_MAPPI2) \
+	|| defined(CONFIG_PLAT_USRV)
+	unsigned int dummy;
+	/* reset sio */
+	dummy=*(volatile char *)(info->port + 0x20);
+	dummy=*(volatile char *)(info->port + 0x20);
+	dummy=*(volatile char *)(info->port + 0x0c);
+	*(volatile char *)(info->port + 0x02) = 3;
+	*(volatile char *)(info->port + 0x03) = 3;
+#endif
+}
+
+static void sio_error(struct async_struct *info,int status)
+{
+#if defined(CONFIG_PLAT_MAPPI) || defined(CONFIG_PLAT_MAPPI2) \
+	|| defined(CONFIG_PLAT_USRV)
+	unsigned int dummy;
+	/* reset sio */
+	// printk("sio[%d] error[%04x]\n", info->line,status);
+	dummy=*(volatile char *)(info->port + 0x20);
+	dummy=*(volatile char *)(info->port + 0x20);
+	dummy=*(volatile char *)(info->port + 0x0c);
+	*(volatile char *)(info->port + 0x02) = 3;
+	*(volatile char *)(info->port + 0x03) = 3;
+#endif
+}
+
+static void dc_interrupt_single(int irq, void *dev_id, struct pt_regs * regs)
+{
+	int status, iir;
+	// int pass_counter = 0;
+	struct async_struct * info;
+
+#ifdef CONFIG_SERIAL_MULTIPORT
+	int first_multi = 0;
+	struct rs_multiport_struct *multi;
+#endif
+
+#ifdef SERIAL_DEBUG_INTR
+	printk("dc_interrupt_single(%d)...", irq);
+#endif
+	
+	info = IRQ_ports[irq&(~1)];
+	if (!info || !info->tty)
+		return;
+
+#ifdef CONFIG_SERIAL_MULTIPORT
+	multi = &rs_multiport[irq];
+	if (multi->port_monitor)
+		first_multi = inb(multi->port_monitor);
+#endif
+
+	{
+		status = serial_inp(info, UART_LSR);
+#ifdef SERIAL_DEBUG_INTR
+		printk("status = %x...", status);
+#endif
+		if (status & UART_LSR_DR){
+			dc_receive_chars(info, &status);
+		}
+		if (status & 0x0f0f0) {
+			sio_error(info,status);
+		}else if(*(volatile unsigned int *)(info->port) !=3){
+			sio_error(info,0x666);
+		}
+		if (status & UART_LSR_THRE)
+			transmit_chars(info, 0);
+#ifdef SERIAL_DEBUG_INTR
+		printk("IIR = %x...", serial_in(info, UART_IIR));
+#endif
+	}
+
+	info->last_active = jiffies;
+#ifdef CONFIG_SERIAL_MULTIPORT
+	if (multi->port_monitor)
+			printk("rs port monitor (single) irq %d: 0x%x, 0x%x\n",
+			info->state->irq, first_multi,
+			inb(multi->port_monitor));
+#endif
+#ifdef SERIAL_DEBUG_INTR
+	printk("end.\n");
+#endif
+}
+#ifdef CONFIG_SERIAL_MULTIPORT
+static void rs_interrupt_multi(int irq, void *dev_id, struct pt_regs * regs)
+{}
+#endif
+
+static void do_dc_serial_bh(void)
+{
+	run_task_queue(&tq_dc_serial);
+}
+
+static void do_softint(void *private_)
+{
+	struct async_struct *info = (struct async_struct *) private_;
+	struct tty_struct *tty;
+	
+	tty = info->tty;
+	if (!tty)
+		return;
+
+	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
+		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+			tty->ldisc.write_wakeup)
+			(tty->ldisc.write_wakeup)(tty);
+		wake_up_interruptible(&tty->write_wait);
+#ifdef SERIAL_HAVE_POLL_WAIT
+		wake_up_interruptible(&tty->poll_wait);
+#endif
+	}
+}
+
+static void dc_timer(void)
+{
+	static unsigned long last_strobe = 0;
+	struct async_struct *info;
+	unsigned int  i;
+	unsigned long flags;
+
+	if ((jiffies - last_strobe) >= RS_STROBE_TIME) {
+		for (i=0; i < NR_IRQS; i++) {
+			info = IRQ_ports[i];
+			if (!info)
+				continue;
+			save_flags(flags); cli();
+			dc_interrupt_single(i, NULL, NULL);
+			restore_flags(flags);
+		}
+	}
+	last_strobe = jiffies;
+
+#ifdef CONFIG_LINUX_2_2
+//  timer_table[RS_TIMER].expires = jiffies + RS_STROBE_TIME;
+	timer_table[RS_TIMER].expires = jiffies + 10;
+	timer_active |= 1 << RS_TIMER;
+#else /* not CONFIG_LINUX_2_2 */
+#if 1
+	mod_timer(&serial_timer, jiffies + 10);
+#else 
+	mod_timer(&serial_timer, jiffies + RS_STROBE_TIME);
+#endif
+#endif /* not CONFIG_LINUX_2_2 */
+
+	if (IRQ_ports[0]) {
+		save_flags(flags); cli();
+#ifdef CONFIG_SERIAL_SHARE_IRQ
+		dc_interrupt(0, NULL, NULL);
+#else
+		dc_interrupt_single(0, NULL, NULL);
+#endif
+		restore_flags(flags);
+
+		mod_timer(&serial_timer, jiffies + IRQ_timeout[0]);
+	}
+}
+
+/*
+ * ---------------------------------------------------------------
+ * Low level utility subroutines for the serial driver:  routines to
+ * figure out the appropriate timeout for an interrupt chain, routines
+ * to initialize and startup a serial port, and routines to shutdown a
+ * serial port.  Useful stuff like that.
+ * ---------------------------------------------------------------
+ */
+
+/*
+ * This routine figures out the correct timeout for a particular IRQ.
+ * It uses the smallest timeout of all of the serial ports in a
+ * particular interrupt chain.  Now only used for IRQ 0....
+ */
+static void figure_IRQ_timeout(int irq)
+{
+	struct  async_struct    *info;
+	int timeout = 60*HZ;    /* 60 seconds === a long time :-) */
+
+	info = IRQ_ports[irq];
+	if (!info) {
+		IRQ_timeout[irq] = 60*HZ;
+		return;
+	}
+	while (info) {
+		if (info->timeout < timeout)
+			timeout = info->timeout;
+		info = info->next_port;
+	}
+	if (!irq)
+		timeout = timeout / 2;
+	IRQ_timeout[irq] = timeout ? timeout : 1;
+}
+
+#ifdef CONFIG_SERIAL_RSA
+/* Attempts to turn on the RSA FIFO.  Returns zero on failure */
+static int enable_rsa(struct async_struct *info) {}
+
+/* Attempts to turn off the RSA FIFO.  Returns zero on failure */
+static int disable_rsa(struct async_struct *info) { }
+#endif /* CONFIG_SERIAL_RSA */
+
+static int startup(struct async_struct * info)
+{
+	unsigned long flags;
+	int retval=0;
+	void (*handler)(int, void *, struct pt_regs *);
+	struct serial_state *state= info->state;
+	unsigned long page;
+#ifdef CONFIG_SERIAL_MANY_PORTS
+	unsigned short ICP;
+#endif
+
+	page = get_zeroed_page(GFP_KERNEL);
+	if (!page)
+		return -ENOMEM;
+
+	save_flags(flags); cli();
+
+	if (info->flags & ASYNC_INITIALIZED) {
+		free_page(page);
+		goto errout;
+	}
+#if 0 /* 020113 fix*/
+	if (!CONFIGURED_SERIAL_PORT(state) || !state->type) {
+		if (info->tty)
+			set_bit(TTY_IO_ERROR, &info->tty->flags);
+		free_page(page);
+		goto errout;
+	}
+#endif
+	if (info->xmit.buf)
+		free_page(page);
+	else
+		info->xmit.buf = (unsigned char *) page;
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("starting up ttyD%d (irq %d)...", info->line, state->irq);
+#endif
+
+	/*
+	 * Clear the FIFO buffers and disable them
+	 * (they will be reenabled in change_speed())
+	 */
+
+	/*
+	 * Clear the interrupt registers.
+	 */
+#if 1 /* for m32r @020114 */
+	sio_reset(info);
+#else
+	(void) serial_inp(info, UART_LSR);
+	(void) serial_inp(info, UART_RX);
+	(void) serial_inp(info, UART_IIR);
+	(void) serial_inp(info, UART_MSR);
+#endif
+
+#if 0 /* 020114 */
+	/*
+	 * At this point there's no way the LSR could still be 0xFF;
+	 * if it is, then bail out, because there's likely no UART
+	 * here.
+	 */
+	/* m32102 note: don't set ASYNC_BUGGY_UART at info->flags */
+	if (!(info->flags & ASYNC_BUGGY_UART) &&
+		(serial_inp(info, UART_LSR) == 0xff)) {
+			printk("ttyS%d: LSR safety check engaged!\n", state->line);
+		if (capable(CAP_SYS_ADMIN)) {
+			if (info->tty)
+				set_bit(TTY_IO_ERROR, &info->tty->flags);
+		} else
+			retval = -ENODEV;
+			goto errout;
+	}
+#endif /* 020114 */
+
+	/*
+	 * Allocate the IRQ if necessary
+	 */
+	if (state->irq && (!IRQ_ports[state->irq] ||
+			   !IRQ_ports[state->irq]->next_port)) {
+		if (IRQ_ports[state->irq]) {
+#ifdef CONFIG_SERIAL_SHARE_IRQ
+			free_irq(state->irq, &IRQ_ports[state->irq]);
+#if 1 /* 020116 */
+			free_irq(state->irq+1, &IRQ_ports[state->irq]);
+#endif
+#ifdef CONFIG_SERIAL_MULTIPORT
+			if (rs_multiport[state->irq].port1)
+				handler = rs_interrupt_multi;
+			else
+#endif
+				handler = dc_interrupt;
+#else
+			retval = -EBUSY;
+			goto errout;
+#endif /* CONFIG_SERIAL_SHARE_IRQ */
+		} else
+			handler = dc_interrupt_single;
+
+#if 1 /* 020116 */
+		retval = request_irq(state->irq, handler, SA_SHIRQ,
+			"serial_rx", &IRQ_ports[state->irq]);
+		retval = request_irq(state->irq+1, handler, SA_SHIRQ,
+			"serial_tx", &IRQ_ports[state->irq]);
+#else
+			retval = request_irq(state->irq, handler, SA_SHIRQ,
+	   			"serial_rx", &IRQ_ports[state->irq]);
+#endif
+		if (retval) {
+			if (capable(CAP_SYS_ADMIN)) {
+				if (info->tty)
+					set_bit(TTY_IO_ERROR,
+						&info->tty->flags);
+				retval = 0;
+			}
+			goto errout;
+		}
+	}
+
+	/*
+	 * Insert serial port into IRQ chain.
+	 */
+	info->prev_port = 0;
+	info->next_port = IRQ_ports[state->irq];
+	if (info->next_port)
+		info->next_port->prev_port = info;
+	IRQ_ports[state->irq] = info;
+	figure_IRQ_timeout(state->irq);
+
+	/*
+	 * Now, initialize the UART
+	 */
+#if 1 /* for m32r @020113 */
+	sio_reset(info);
+#else
+	serial_outp(info, UART_LCR, UART_LCR_WLEN8);    /* reset DLAB */
+#endif /* for m32r @020113 */
+
+	info->MCR = 0;
+	if (info->tty->termios->c_cflag & CBAUD)
+		info->MCR = UART_MCR_DTR | UART_MCR_RTS;
+#ifdef CONFIG_SERIAL_MANY_PORTS
+	if (info->flags & ASYNC_FOURPORT) {
+		if (state->irq == 0)
+			info->MCR |= UART_MCR_OUT1;
+	} else
+#endif
+	{
+		if (state->irq != 0)
+			info->MCR |= UART_MCR_OUT2;
+	}
+	info->MCR |= ALPHA_KLUDGE_MCR;      /* Don't ask */
+	serial_outp(info, UART_MCR, info->MCR);
+
+	/*
+	 * Finally, enable interrupts
+	 */
+	info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
+	serial_outp(info, UART_IER, info->IER); /* enable interrupts */
+
+#ifdef CONFIG_SERIAL_MANY_PORTS
+	if (info->flags & ASYNC_FOURPORT) {
+		/* Enable interrupts on the AST Fourport board */
+		ICP = (info->port & 0xFE0) | 0x01F;
+		outb_p(0x80, ICP);
+		(void) inb_p(ICP);
+	}
+#endif
+
+	/*
+	 * And clear the interrupt registers again for luck.
+	 */
+	(void)serial_inp(info, UART_LSR);
+	(void)serial_inp(info, UART_RX);
+	(void)serial_inp(info, UART_IIR);
+	(void)serial_inp(info, UART_MSR);
+
+	if (info->tty)
+		clear_bit(TTY_IO_ERROR, &info->tty->flags);
+	info->xmit.head = info->xmit.tail = 0;
+
+	/*
+	 * Set up serial timers...
+	 */
+#ifdef CONFIG_LINUX_2_2
+	timer_table[RS_TIMER].expires = jiffies + 2*HZ/100;
+	timer_active |= 1 << RS_TIMER;
+#else
+	mod_timer(&serial_timer, jiffies + 2*HZ/100);
+#endif
+
+	/*
+	 * Set up the tty->alt_speed kludge
+	 */
+#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
+	if (info->tty) {
+		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+			info->tty->alt_speed = 57600;
+		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+			info->tty->alt_speed = 115200;
+		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+			info->tty->alt_speed = 230400;
+		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+			info->tty->alt_speed = 460800;
+	}
+#endif
+
+	/*
+	 * and set the speed of the serial port
+	 */
+	change_speed(info, 0);
+
+	info->flags |= ASYNC_INITIALIZED;
+	restore_flags(flags);
+	return 0;
+
+errout:
+	restore_flags(flags);
+	return retval;
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ */
+static void shutdown(struct async_struct * info)
+{
+	unsigned long   flags;
+	struct serial_state *state;
+	int     retval;
+
+	if (!(info->flags & ASYNC_INITIALIZED))
+		return;
+
+	state = info->state;
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("Shutting down serial port %d (irq %d)....", info->line,
+		   state->irq);
+#endif
+
+	save_flags(flags); cli(); /* Disable interrupts */
+
+	/*
+	 * clear delta_msr_wait queue to avoid mem leaks: we may free the irq
+	 * here so the queue might never be waken up
+	 */
+	wake_up_interruptible(&info->delta_msr_wait);
+
+	/*
+	 * First unlink the serial port from the IRQ chain...
+	 */
+	if (info->next_port)
+		info->next_port->prev_port = info->prev_port;
+	if (info->prev_port)
+		info->prev_port->next_port = info->next_port;
+	else
+		IRQ_ports[state->irq] = info->next_port;
+	figure_IRQ_timeout(state->irq);
+
+	/*
+	 * Free the IRQ, if necessary
+	 */
+	if (state->irq && (!IRQ_ports[state->irq] ||
+			  !IRQ_ports[state->irq]->next_port)) {
+		if (IRQ_ports[state->irq]) {
+#if 1 /* 020116 */
+			free_irq(state->irq+1, &IRQ_ports[state->irq]);
+			retval = request_irq(state->irq+1, dc_interrupt_single,
+				         SA_SHIRQ, "serial_xx",
+				         &IRQ_ports[state->irq]);
+#endif /* 020116 */
+			free_irq(state->irq, &IRQ_ports[state->irq]);
+			retval = request_irq(state->irq, dc_interrupt_single,
+				         SA_SHIRQ, "serial",
+				         &IRQ_ports[state->irq]);
+
+			if (retval)
+				printk("serial shutdown: request_irq: error %d"
+				       "  Couldn't reacquire IRQ.\n", retval);
+		} else{
+			free_irq(state->irq, &IRQ_ports[state->irq]);
+#if 1 /* 020116 */
+			free_irq(state->irq+1, &IRQ_ports[state->irq]);
+#endif /* 020116 */
+		}
+	}
+	if (info->xmit.buf) {
+		unsigned long pg = (unsigned long) info->xmit.buf;
+		info->xmit.buf = 0;
+		free_page(pg);
+	}
+
+	info->IER = 0;
+	serial_outp(info, UART_IER, 0x00);  /* disable all intrs */
+#ifdef CONFIG_SERIAL_MANY_PORTS
+	if (info->flags & ASYNC_FOURPORT) {
+		/* reset interrupts on the AST Fourport board */
+		(void) inb((info->port & 0xFE0) | 0x01F);
+		info->MCR |= UART_MCR_OUT1;
+	} else
+#endif
+#if 0 /* 020113 */
+		info->MCR &= ~UART_MCR_OUT2;
+	info->MCR |= ALPHA_KLUDGE_MCR;      /* Don't ask */
+
+	/* disable break condition */
+	serial_out(info, UART_LCR, serial_inp(info, UART_LCR) & ~UART_LCR_SBC);
+#endif /* 020113 */
+
+	if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
+		info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
+	serial_outp(info, UART_MCR, info->MCR);
+
+#if 0 /* 020113 */
+	/* disable FIFO's */
+	serial_outp(info, UART_FCR, (UART_FCR_ENABLE_FIFO |
+				     UART_FCR_CLEAR_RCVR |
+				     UART_FCR_CLEAR_XMIT));
+	serial_outp(info, UART_FCR, 0);
+#endif /* 020113 */
+
+#ifdef CONFIG_SERIAL_RSA
+	/*
+	 * Reset the RSA board back to 115kbps compat mode.
+	 */
+	if ((state->type == PORT_RSA) &&
+		(state->baud_base == SERIAL_RSA_BAUD_BASE &&
+		 disable_rsa(info)))
+		state->baud_base = SERIAL_RSA_BAUD_BASE_LO;
+#endif
+
+
+	(void)serial_in(info, UART_RX);    /* read data port to reset things */
+
+	if (info->tty)
+		set_bit(TTY_IO_ERROR, &info->tty->flags);
+
+#if 0 /* 020113 */
+	if (uart_config[info->state->type].flags & UART_STARTECH) {
+		/* Arrange to enter sleep mode */
+		serial_outp(info, UART_LCR, 0xBF);
+		serial_outp(info, UART_EFR, UART_EFR_ECB);
+		serial_outp(info, UART_LCR, 0);
+		serial_outp(info, UART_IER, UART_IERX_SLEEP);
+		serial_outp(info, UART_LCR, 0xBF);
+		serial_outp(info, UART_EFR, 0);
+		serial_outp(info, UART_LCR, 0);
+	}
+	if (info->state->type == PORT_16750) {
+		/* Arrange to enter sleep mode */
+		serial_outp(info, UART_IER, UART_IERX_SLEEP);
+	}
+#endif /* 020113 */
+	sio_reset(info);
+
+	info->flags &= ~ASYNC_INITIALIZED;
+	restore_flags(flags);
+}
+
+static void change_speed(struct async_struct *info,struct termios *old_termios)
+{
+	int quot = 0, baud_base, baud;
+	unsigned cflag, cval = 0;
+	int bits;
+	unsigned long   flags;
+	unsigned mod0, mod1 , adj;
+
+	if (!info->tty || !info->tty->termios)
+		return;
+	cflag = info->tty->termios->c_cflag;
+	if (!CONFIGURED_SERIAL_PORT(info))
+		return;
+
+	/* byte size and parity */
+	switch (cflag & CSIZE) {
+		  case CS5: mod1 = 0x05; bits = 7; break;
+		  case CS6: mod1 = 0x06; bits = 8; break;
+		  case CS7: mod1 = 0x07; bits = 9; break;
+		  case CS8: mod1 = 0x08; bits = 10; break;
+		  /* Never happens, but GCC is too dumb to figure it out */
+		  default:  mod1 = 0x05; bits = 7; break;
+	}
+	mod1 <<= 8;
+	mod0 = 0;
+	if (cflag & CSTOPB) {
+		mod0 |= 0x03;
+		bits++;
+	}
+	if (cflag & PARENB) {
+		mod0 |= 0x10;
+		bits++;
+	}
+	if (!(cflag & PARODD)) {
+		mod0 |= 0x4;
+	}
+#if defined(CONFIG_CHIP_M32700)
+	if (cflag & CRTSCTS) {
+		mod0 |= 0x180;	/* Use RTS# output only */
+	}
+#else
+	mod0 |= 0xc0;
+#endif
+
+#if 1 /* 020907 by kondo */
+#if 0
+	if(info->line == 0) {
+		mod0 |= 0xc0;
+	}
+#endif
+	serial_outp(info, UART_MOD0, mod0);      /* */
+	serial_outp(info, UART_MOD1, mod1);      /* */
+	mod1 = 0;
+	info->LCR = mod1;               /* Save LCR */
+#endif
+
+	/* Determine divisor based on baud rate */
+	baud = tty_get_baud_rate(info->tty);
+	if (!baud)
+		baud = 9600;    /* B0 transition handled in rs_set_termios */
+#ifdef CONFIG_SERIAL_RSA
+	if ((info->state->type == PORT_RSA) &&
+		(info->state->baud_base != SERIAL_RSA_BAUD_BASE) &&
+		enable_rsa(info))
+		info->state->baud_base = SERIAL_RSA_BAUD_BASE;
+#endif
+	baud_base = info->state->baud_base;
+
+#if 0 /* 020114 */
+	if (info->state->type == PORT_16C950) {
+		if (baud <= baud_base)
+			serial_icr_write(info, UART_TCR, 0);
+		else if (baud <= 2*baud_base) {
+			serial_icr_write(info, UART_TCR, 0x8);
+			baud_base = baud_base * 2;
+		} else if (baud <= 4*baud_base) {
+			serial_icr_write(info, UART_TCR, 0x4);
+			baud_base = baud_base * 4;
+		} else
+			serial_icr_write(info, UART_TCR, 0);
+	}
+#endif /* 020114 */
+
+	if (baud == 38400 &&
+		((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))
+		quot = info->state->custom_divisor;
+	else {
+		if (baud == 134)
+			/* Special case since 134 is really 134.5 */
+			quot = (2*baud_base / 269);
+		else if (baud)
+			quot = baud_base / baud;
+	}
+	/* If the quotient is zero refuse the change */
+	if (!quot && old_termios) {
+		info->tty->termios->c_cflag &= ~CBAUD;
+		info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD);
+		baud = tty_get_baud_rate(info->tty);
+		if (!baud)
+			baud = 9600;
+		if (baud == 38400 &&
+			((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))
+			quot = info->state->custom_divisor;
+		else {
+			if (baud == 134)
+				/* Special case since 134 is really 134.5 */
+				quot = (2*baud_base / 269);
+			else if (baud)
+				quot = baud_base / baud ;
+		}
+	}
+	quot = baud_base / (baud*16) ;
+	/* As a last resort, if the quotient is zero, default to 9600 bps */
+	if (!quot)
+		quot = baud_base / 9600;
+	/*
+	 * Work around a bug in the Oxford Semiconductor 952 rev B
+	 * chip which causes it to seriously miscalculate baud rates
+	 * when DLL is 0.
+	 */
+	if (((quot & 0xFF) == 0) && (info->state->type == PORT_16C950) &&
+		(info->state->revision == 0x5201))
+		quot++;
+
+	info->quot = quot;
+	info->timeout = ((info->xmit_fifo_size*HZ*bits*quot) / baud_base);
+	info->timeout += HZ/50;     /* Add .02 seconds of slop */
+
+#if 0 /* 020114 */
+	/* Set up FIFO's */
+	if (uart_config[info->state->type].flags & UART_USE_FIFO) {
+		if ((info->state->baud_base / quot) < 2400)
+			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
+#ifdef CONFIG_SERIAL_RSA
+		else if (info->state->type == PORT_RSA)
+			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_14;
+#endif
+		else
+			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;
+	}
+	if (info->state->type == PORT_16750)
+		fcr |= UART_FCR7_64BYTE;
+
+#endif /* 020114 */
+
+	/* CTS flow control flag and modem status interrupts */
+	info->IER &= ~UART_IER_MSI;
+	if (info->flags & ASYNC_HARDPPS_CD)
+		info->IER |= UART_IER_MSI;
+	if (cflag & CRTSCTS) {
+		info->flags |= ASYNC_CTS_FLOW;
+		info->IER |= UART_IER_MSI;
+	} else
+		info->flags &= ~ASYNC_CTS_FLOW;
+	if (cflag & CLOCAL)
+		info->flags &= ~ASYNC_CHECK_CD;
+	else {
+		info->flags |= ASYNC_CHECK_CD;
+		info->IER |= UART_IER_MSI;
+	}
+	serial_out(info, UART_IER, info->IER);
+
+	/*
+	 * Set up parity check flag
+	 */
+#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
+	info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
+	if (I_INPCK(info->tty))
+		info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
+	if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
+		info->read_status_mask |= UART_LSR_BI;
+
+	/*
+	 * Characters to ignore
+	 */
+	info->ignore_status_mask = 0;
+	if (I_IGNPAR(info->tty))
+		info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
+	if (I_IGNBRK(info->tty)) {
+		info->ignore_status_mask |= UART_LSR_BI;
+		/*
+		 * If we're ignore parity and break indicators, ignore
+		 * overruns too.  (For real raw support).
+		 */
+		if (I_IGNPAR(info->tty))
+			info->ignore_status_mask |= UART_LSR_OE;
+	}
+	/*
+	 * !!! ignore all characters if CREAD is not set
+	 */
+	if ((cflag & CREAD) == 0)
+		info->ignore_status_mask |= UART_LSR_DR;
+	/* setup m32102 sio baur register */
+	{	
+		cval =baud_base/(baud*16);
+		adj=(baud_base-cval*baud*16)/baud;
+		cval-=1;
+		adj=(adj+1) >> 1;
+	}
+	save_flags(flags); cli();
+#if 1 /* 020906 */
+	serial_outp(info, UART_BAUR, cval );  /* set baurate reg */
+	serial_outp(info, UART_RBAUR, adj );  /* set adj baurate reg */
+	serial_outp(info, UART_LCR, 0x03);
+#else
+	if (uart_config[info->state->type].flags & UART_STARTECH) {
+		serial_outp(info, UART_LCR, 0xBF);
+		serial_outp(info, UART_EFR,(cflag & CRTSCTS) ? UART_EFR_CTS : 0);
+	}
+	serial_outp(info, UART_LCR, cval | UART_LCR_DLAB);  /* set DLAB */
+	serial_outp(info, UART_DLL, quot & 0xff);   /* LS of divisor */
+	serial_outp(info, UART_DLM, quot >> 8);     /* MS of divisor */
+	if (info->state->type == PORT_16750)
+		serial_outp(info, UART_FCR, fcr);   /* set fcr */
+	serial_outp(info, UART_LCR, cval);      /* reset DLAB */
+	info->LCR = cval;               /* Save LCR */
+	if (info->state->type != PORT_16750) {
+		if (fcr & UART_FCR_ENABLE_FIFO) {
+			/* emulated UARTs (Lucent Venus 167x) need two steps */
+			serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
+		}
+		serial_outp(info, UART_FCR, fcr);   /* set fcr */
+	}
+#endif
+	restore_flags(flags);
+}
+
+static void dc_put_char(struct tty_struct *tty, unsigned char ch)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	unsigned long flags;
+
+	if (serial_paranoia_check(info, tty->device, "dc_put_char"))
+		return;
+
+	if (!tty || !info->xmit.buf)
+		return;
+
+	save_flags(flags); cli();
+	if (CIRC_SPACE(info->xmit.head,
+			   info->xmit.tail,
+			   SERIAL_XMIT_SIZE) == 0) {
+		restore_flags(flags);
+		return;
+	}
+
+	info->xmit.buf[info->xmit.head] = ch;
+	info->xmit.head = (info->xmit.head + 1) & (SERIAL_XMIT_SIZE-1);
+	restore_flags(flags);
+}
+
+static void dc_flush_chars(struct tty_struct *tty)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	unsigned long flags;
+
+	if (serial_paranoia_check(info, tty->device, "dc_flush_chars"))
+		return;
+
+	if (info->xmit.head == info->xmit.tail
+		|| tty->stopped
+		|| tty->hw_stopped
+		|| !info->xmit.buf)
+		return;
+
+	save_flags(flags); cli();
+	info->IER |= UART_IER_THRI;
+	serial_out(info, UART_IER, info->IER);
+	restore_flags(flags);
+}
+
+static int dc_write(struct tty_struct *tty, int from_user, 
+		    const unsigned char *buf, int count)
+{
+	int c, ret = 0;
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	unsigned long flags;
+		
+	if (serial_paranoia_check(info, tty->device, "dc_write"))
+		return 0;
+
+	if (!tty || !info->xmit.buf || !tmp_buf)
+		return 0;
+
+	save_flags(flags);
+	if (from_user) {
+		down(&tmp_buf_sem);
+		while (1) {
+			int c1;
+			c = CIRC_SPACE_TO_END(info->xmit.head,
+					info->xmit.tail,
+					SERIAL_XMIT_SIZE);
+			if (count < c)
+				c = count;
+			if (c <= 0)
+				break;
+
+			c -= copy_from_user(tmp_buf, buf, c);
+			if (!c) {
+				if (!ret)
+					ret = -EFAULT;
+				break;
+			}
+			cli();
+			c1 = CIRC_SPACE_TO_END(info->xmit.head,
+					info->xmit.tail,
+					SERIAL_XMIT_SIZE);
+			if (c1 < c)
+				c = c1;
+			memcpy(info->xmit.buf + info->xmit.head, tmp_buf, c);
+			info->xmit.head = ((info->xmit.head + c) &
+					(SERIAL_XMIT_SIZE-1));
+			restore_flags(flags);
+			buf += c;
+			count -= c;
+			ret += c;
+		}
+		up(&tmp_buf_sem);
+	} else {
+		cli();
+		while (1) {
+			c = CIRC_SPACE_TO_END(info->xmit.head,
+					info->xmit.tail,
+					SERIAL_XMIT_SIZE);
+			if (count < c)
+				c = count;
+			if (c <= 0) {
+				break;
+			}
+			memcpy(info->xmit.buf + info->xmit.head, buf, c);
+			info->xmit.head = ((info->xmit.head + c) &
+				 (SERIAL_XMIT_SIZE-1));
+			buf += c;
+			count -= c;
+			ret += c;
+		}
+		restore_flags(flags);
+	}
+	if (info->xmit.head != info->xmit.tail
+		&& !tty->stopped
+		&& !tty->hw_stopped
+		&& !(info->IER & UART_IER_THRI)) {
+		info->IER |= UART_IER_THRI;
+		serial_out(info, UART_IER, info->IER);
+	}
+	return ret;
+}
+
+static int dc_write_room(struct tty_struct *tty)
+{
+#ifdef CONFIG_LINUX_2_2
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	int ret;
+	
+	ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
+	if (ret < 0)
+		ret = 0;
+	return ret;
+#else   /* CONFIG_LINUX_2_2 */
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+
+	if (serial_paranoia_check(info, tty->device, "dc_write_room"))
+		return 0;
+	return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
+#endif  /* CONFIG_LINUX_2_2 */
+}
+
+static int dc_chars_in_buffer(struct tty_struct *tty)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+		
+	if (serial_paranoia_check(info, tty->device, "dc_chars_in_buffer"))
+		return 0;
+#ifdef CONFIG_LINUX_2_2
+	return info->xmit_cnt;
+#else
+	return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
+#endif
+}
+
+static void dc_flush_buffer(struct tty_struct *tty)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	unsigned long flags;
+
+	if (serial_paranoia_check(info, tty->device, "dc_flush_buffer"))
+		return;
+	save_flags(flags); cli();
+	info->xmit.head = info->xmit.tail = 0;
+	restore_flags(flags);
+	wake_up_interruptible(&tty->write_wait);
+#ifdef SERIAL_HAVE_POLL_WAIT
+	wake_up_interruptible(&tty->poll_wait);
+#endif
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+			 tty->ldisc.write_wakeup)
+		(tty->ldisc.write_wakeup)(tty);
+}
+
+/*
+ * This function is used to send a high-priority XON/XOFF character to
+ * the device
+ */
+static void dc_send_xchar(struct tty_struct *tty, char ch)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+
+	if (serial_paranoia_check(info, tty->device, "dc_send_char"))
+		return;
+
+	info->x_char = ch;
+	if (ch) {
+		/* Make sure transmit interrupts are on */
+	   	info->IER |= UART_IER_THRI;
+		serial_out(info, UART_IER, info->IER);
+	}
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_throttle()
+ *
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled.
+ * ------------------------------------------------------------
+ */
+static void dc_throttle(struct tty_struct * tty)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	unsigned long flags;
+#ifdef SERIAL_DEBUG_THROTTLE
+	char    buf[64];
+
+	printk("throttle %s: %d....\n", tty_name(tty, buf),
+		tty->ldisc.chars_in_buffer(tty));
+#endif
+
+	if (serial_paranoia_check(info, tty->device, "dc_throttle"))
+		return;
+
+	if (I_IXOFF(tty))
+		dc_send_xchar(tty, STOP_CHAR(tty));
+
+	if (tty->termios->c_cflag & CRTSCTS)
+		info->MCR &= ~UART_MCR_RTS;
+
+	save_flags(flags); cli();
+	serial_out(info, UART_MCR, info->MCR);
+	restore_flags(flags);
+}
+
+static void dc_unthrottle(struct tty_struct * tty)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	unsigned long flags;
+#ifdef SERIAL_DEBUG_THROTTLE
+	char    buf[64];
+
+	printk("unthrottle %s: %d....\n", tty_name(tty, buf),
+		tty->ldisc.chars_in_buffer(tty));
+#endif
+
+	if (serial_paranoia_check(info, tty->device, "dc_unthrottle"))
+		return;
+
+	if (I_IXOFF(tty)) {
+		if (info->x_char)
+			info->x_char = 0;
+		else
+			dc_send_xchar(tty, START_CHAR(tty));
+	}
+	if (tty->termios->c_cflag & CRTSCTS)
+		info->MCR |= UART_MCR_RTS;
+	save_flags(flags); cli();
+	serial_out(info, UART_MCR, info->MCR);
+	restore_flags(flags);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_ioctl() and friends
+ * ------------------------------------------------------------
+ */
+
+static int get_serial_info(struct async_struct * info,
+			   struct serial_struct * retinfo)
+{
+	struct serial_struct tmp;
+	struct serial_state *state = info->state;
+
+	if (!retinfo)
+		return -EFAULT;
+	memset(&tmp, 0, sizeof(tmp));
+	tmp.type = state->type;
+	tmp.line = state->line;
+	tmp.port = state->port;
+	if (HIGH_BITS_OFFSET)
+		tmp.port_high = state->port >> HIGH_BITS_OFFSET;
+	else
+		tmp.port_high = 0;
+	tmp.irq = state->irq;
+	tmp.flags = state->flags;
+	tmp.xmit_fifo_size = state->xmit_fifo_size;
+	tmp.baud_base = state->baud_base;
+	tmp.close_delay = state->close_delay;
+	tmp.closing_wait = state->closing_wait;
+	tmp.custom_divisor = state->custom_divisor;
+	tmp.hub6 = state->hub6;
+	tmp.io_type = state->io_type;
+	if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
+		return -EFAULT;
+	return 0;
+}
+
+static int set_serial_info(struct async_struct * info,
+			   struct serial_struct * new_info)
+{
+	struct serial_struct new_serial;
+	struct serial_state old_state, *state;
+	unsigned int		i,change_irq,change_port;
+	int			retval = 0;
+	unsigned long		new_port;
+
+	if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
+		return -EFAULT;
+	state = info->state;
+	old_state = *state;
+
+	new_port = new_serial.port;
+	if (HIGH_BITS_OFFSET)
+		new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET;
+
+	change_irq = new_serial.irq != state->irq;
+	change_port = (new_port != ((int) state->port)) ||
+		(new_serial.hub6 != state->hub6);
+
+	if (!capable(CAP_SYS_ADMIN)) {
+		if (change_irq || change_port ||
+		    (new_serial.baud_base != state->baud_base) ||
+		    (new_serial.type != state->type) ||
+		    (new_serial.close_delay != state->close_delay) ||
+		    (new_serial.xmit_fifo_size != state->xmit_fifo_size) ||
+		    ((new_serial.flags & ~ASYNC_USR_MASK) !=
+		    (state->flags & ~ASYNC_USR_MASK)))
+			return -EPERM;
+		state->flags = ((state->flags & ~ASYNC_USR_MASK) |
+					(new_serial.flags & ASYNC_USR_MASK));
+		info->flags = ((info->flags & ~ASYNC_USR_MASK) |
+				   (new_serial.flags & ASYNC_USR_MASK));
+		state->custom_divisor = new_serial.custom_divisor;
+		goto check_and_exit;
+	}
+
+	new_serial.irq = irq_cannonicalize(new_serial.irq);
+
+	if ((new_serial.irq >= NR_IRQS) || (new_serial.irq < 0) ||
+	    (new_serial.baud_base < 9600)|| (new_serial.type < PORT_UNKNOWN) ||
+	    (new_serial.type > PORT_MAX) || (new_serial.type == PORT_CIRRUS) ||
+	    (new_serial.type == PORT_STARTECH)) {
+		return -EINVAL;
+	}
+
+	if ((new_serial.type != state->type) ||
+		(new_serial.xmit_fifo_size <= 0))
+		new_serial.xmit_fifo_size =
+			uart_config[new_serial.type].dfl_xmit_fifo_size;
+
+	/* Make sure address is not already in use */
+	if (new_serial.type) {
+		for (i = 0 ; i < NR_PORTS; i++)
+			if ((state != &rs_table[i]) &&
+			    (rs_table[i].port == new_port) &&
+			    rs_table[i].type)
+				return -EADDRINUSE;
+	}
+
+	if ((change_port || change_irq) && (state->count > 1))
+		return -EBUSY;
+
+	/*
+	 * OK, past this point, all the error checking has been done.
+	 * At this point, we start making changes.....
+	 */
+
+	state->baud_base = new_serial.baud_base;
+	state->flags = ((state->flags & ~ASYNC_FLAGS) |
+			(new_serial.flags & ASYNC_FLAGS));
+	info->flags = ((state->flags & ~ASYNC_INTERNAL_FLAGS) |
+			   (info->flags & ASYNC_INTERNAL_FLAGS));
+	state->custom_divisor = new_serial.custom_divisor;
+	state->close_delay = new_serial.close_delay * HZ/100;
+	state->closing_wait = new_serial.closing_wait * HZ/100;
+#if (LINUX_VERSION_CODE > 0x20100)
+	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+#endif
+	info->xmit_fifo_size = state->xmit_fifo_size =
+		new_serial.xmit_fifo_size;
+
+	if ((state->type != PORT_UNKNOWN) && state->port) {
+#ifdef CONFIG_SERIAL_RSA
+		if (old_state.type == PORT_RSA)
+			release_region(state->port + UART_RSA_BASE, 16);
+		else
+#endif
+		release_region(state->port,8);
+	}
+	state->type = new_serial.type;
+	if (change_port || change_irq) {
+		/*
+		 * We need to shutdown the serial port at the old
+		 * port/irq combination.
+		 */
+		shutdown(info);
+		state->irq = new_serial.irq;
+		info->port = state->port = new_port;
+		info->hub6 = state->hub6 = new_serial.hub6;
+		if (info->hub6)
+			info->io_type = state->io_type = SERIAL_IO_HUB6;
+		else if (info->io_type == SERIAL_IO_HUB6)
+			info->io_type = state->io_type = SERIAL_IO_PORT;
+	}
+	if ((state->type != PORT_UNKNOWN) && state->port) {
+#ifdef CONFIG_SERIAL_RSA
+		if (state->type == PORT_RSA)
+			request_region(state->port + UART_RSA_BASE,
+				       16, "serial_rsa(set)");
+		else
+#endif
+			request_region(state->port,8,"serial(set)");
+	}
+
+
+check_and_exit:
+	if (!state->port || !state->type)
+		return 0;
+	if (info->flags & ASYNC_INITIALIZED) {
+		if (((old_state.flags & ASYNC_SPD_MASK) !=
+			 (state->flags & ASYNC_SPD_MASK)) ||
+			(old_state.custom_divisor != state->custom_divisor)) {
+#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
+			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+				info->tty->alt_speed = 57600;
+			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+				info->tty->alt_speed = 115200;
+			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+				info->tty->alt_speed = 230400;
+			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+				info->tty->alt_speed = 460800;
+#endif
+			change_speed(info, 0);
+		}
+	} else
+		retval = startup(info);
+	return retval;
+}
+
+/*
+ * get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ *      is emptied.  On bus types like RS485, the transmitter must
+ *      release the bus after transmitting. This must be done when
+ *      the transmit shift register is empty, not be done when the
+ *      transmit holding register is empty.  This functionality
+ *      allows an RS485 driver to be written in user space.
+ */
+static int get_lsr_info(struct async_struct * info, unsigned int *value)
+{
+	unsigned char status;
+	unsigned int result;
+	unsigned long flags;
+
+	save_flags(flags); cli();
+	status = serial_in(info, UART_LSR);
+	restore_flags(flags);
+	result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
+
+	/*
+	 * If we're about to load something into the transmit
+	 * register, we'll pretend the transmitter isn't empty to
+	 * avoid a race condition (depending on when the transmit
+	 * interrupt happens).
+	 */
+	if (info->x_char ||
+		((CIRC_CNT(info->xmit.head, info->xmit.tail,
+			   SERIAL_XMIT_SIZE) > 0) &&
+		 !info->tty->stopped && !info->tty->hw_stopped))
+		result &= ~TIOCSER_TEMT;
+
+	if (copy_to_user(value, &result, sizeof(int)))
+		return -EFAULT;
+	return 0;
+}
+
+
+static int get_modem_info(struct async_struct * info, unsigned int *value)
+{
+	unsigned char control, status;
+	unsigned int result;
+	unsigned long flags;
+
+	control = info->MCR;
+	save_flags(flags); cli();
+	status = serial_in(info, UART_MSR);
+	restore_flags(flags);
+	result =  ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
+		| ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
+#ifdef TIOCM_OUT1
+		| ((control & UART_MCR_OUT1) ? TIOCM_OUT1 : 0)
+		| ((control & UART_MCR_OUT2) ? TIOCM_OUT2 : 0)
+#endif
+		| ((status  & UART_MSR_DCD) ? TIOCM_CAR : 0)
+		| ((status  & UART_MSR_RI) ? TIOCM_RNG : 0)
+		| ((status  & UART_MSR_DSR) ? TIOCM_DSR : 0)
+		| ((status  & UART_MSR_CTS) ? TIOCM_CTS : 0);
+
+	if (copy_to_user(value, &result, sizeof(int)))
+		return -EFAULT;
+	return 0;
+}
+static int set_modem_info(struct async_struct * info, unsigned int cmd,
+			  unsigned int *value)
+{
+	unsigned int arg;
+	unsigned long flags;
+
+	if (copy_from_user(&arg, value, sizeof(int)))
+		return -EFAULT;
+
+	switch (cmd) {
+	case TIOCMBIS:
+		if (arg & TIOCM_RTS)
+			info->MCR |= UART_MCR_RTS;
+		if (arg & TIOCM_DTR)
+			info->MCR |= UART_MCR_DTR;
+#ifdef TIOCM_OUT1
+		if (arg & TIOCM_OUT1)
+			info->MCR |= UART_MCR_OUT1;
+		if (arg & TIOCM_OUT2)
+			info->MCR |= UART_MCR_OUT2;
+#endif
+		if (arg & TIOCM_LOOP)
+			info->MCR |= UART_MCR_LOOP;
+		break;
+	case TIOCMBIC:
+		if (arg & TIOCM_RTS)
+			info->MCR &= ~UART_MCR_RTS;
+		if (arg & TIOCM_DTR)
+			info->MCR &= ~UART_MCR_DTR;
+#ifdef TIOCM_OUT1
+		if (arg & TIOCM_OUT1)
+			info->MCR &= ~UART_MCR_OUT1;
+		if (arg & TIOCM_OUT2)
+			info->MCR &= ~UART_MCR_OUT2;
+#endif
+		if (arg & TIOCM_LOOP)
+			info->MCR &= ~UART_MCR_LOOP;
+		break;
+	case TIOCMSET:
+		info->MCR = ((info->MCR & ~(UART_MCR_RTS |
+#ifdef TIOCM_OUT1
+				        UART_MCR_OUT1 |
+				        UART_MCR_OUT2 |
+#endif
+				        UART_MCR_LOOP |
+				        UART_MCR_DTR))
+				 | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0)
+#ifdef TIOCM_OUT1
+				 | ((arg & TIOCM_OUT1) ? UART_MCR_OUT1 : 0)
+				 | ((arg & TIOCM_OUT2) ? UART_MCR_OUT2 : 0)
+#endif
+				 | ((arg & TIOCM_LOOP) ? UART_MCR_LOOP : 0)
+				 | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));
+		break;
+	default:
+		return -EINVAL;
+	}
+	save_flags(flags); cli();
+	info->MCR |= ALPHA_KLUDGE_MCR;      /* Don't ask */
+	serial_out(info, UART_MCR, info->MCR);
+	restore_flags(flags);
+	return 0;
+}
+
+static int do_autoconfig(struct async_struct * info)
+{
+	int irq, retval;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	if (info->state->count > 1)
+		return -EBUSY;
+
+	shutdown(info);
+
+	autoconfig(info->state);
+	if ((info->state->flags & ASYNC_AUTO_IRQ) &&
+		(info->state->port != 0  || info->state->iomem_base != 0) &&
+		(info->state->type != PORT_UNKNOWN)) {
+		irq = detect_uart_irq(info->state);
+		if (irq > 0)
+			info->state->irq = irq;
+	}
+
+	retval = startup(info);
+	if (retval)
+		return retval;
+	return 0;
+}
+
+/*
+ * rs_break() --- routine which turns the break handling on or off
+ */
+#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
+static void send_break( struct async_struct * info, int duration)
+{
+	if (!CONFIGURED_SERIAL_PORT(info))
+		return;
+	current->state = TASK_INTERRUPTIBLE;
+	current->timeout = jiffies + duration;
+	cli();
+	info->LCR |= UART_LCR_SBC;
+#if 0
+	serial_out(info, UART_LCR, info->LCR);
+#else
+	serial_out(info, UART_LCR, 0x3);
+#endif
+	schedule();
+	info->LCR &= ~UART_LCR_SBC;
+#if 0
+	serial_out(info, UART_LCR, info->LCR);
+#else
+	serial_out(info, UART_LCR, 0x3);
+#endif
+	sti();
+}
+#else
+static void dc_break(struct tty_struct *tty, int break_state)
+{
+	struct async_struct * info = (struct async_struct *)tty->driver_data;
+	unsigned long flags;
+
+	if (serial_paranoia_check(info, tty->device, "rs_break"))
+		return;
+
+	if (!CONFIGURED_SERIAL_PORT(info))
+		return;
+	save_flags(flags); cli();
+	if (break_state == -1)
+		info->LCR |= UART_LCR_SBC;
+	else
+		info->LCR &= ~UART_LCR_SBC;
+#if 0 /* 020114 */
+	serial_out(info, UART_LCR, info->LCR);
+#endif /* 020114 */
+	restore_flags(flags);
+}
+#endif
+
+#ifdef CONFIG_SERIAL_MULTIPORT
+static int get_multiport_struct(struct async_struct * info,
+				struct serial_multiport_struct *retinfo)
+{
+	struct serial_multiport_struct ret;
+	struct rs_multiport_struct *multi;
+
+	multi = &rs_multiport[info->state->irq];
+
+	ret.port_monitor = multi->port_monitor;
+
+	ret.port1 = multi->port1;
+	ret.mask1 = multi->mask1;
+	ret.match1 = multi->match1;
+
+	ret.port2 = multi->port2;
+	ret.mask2 = multi->mask2;
+	ret.match2 = multi->match2;
+
+	ret.port3 = multi->port3;
+	ret.mask3 = multi->mask3;
+	ret.match3 = multi->match3;
+
+	ret.port4 = multi->port4;
+	ret.mask4 = multi->mask4;
+	ret.match4 = multi->match4;
+
+	ret.irq = info->state->irq;
+
+	if (copy_to_user(retinfo,&ret,sizeof(*retinfo)))
+		return -EFAULT;
+	return 0;
+}
+
+static int set_multiport_struct(struct async_struct * info,
+				struct serial_multiport_struct *in_multi)
+{
+	struct serial_multiport_struct new_multi;
+	struct rs_multiport_struct *multi;
+	struct serial_state *state;
+	int was_multi, now_multi;
+	int retval;
+	void (*handler)(int, void *, struct pt_regs *);
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	state = info->state;
+
+	if (copy_from_user(&new_multi, in_multi,
+			   sizeof(struct serial_multiport_struct)))
+		return -EFAULT;
+
+	if (new_multi.irq != state->irq || state->irq == 0 ||
+		!IRQ_ports[state->irq])
+		return -EINVAL;
+
+	multi = &rs_multiport[state->irq];
+	was_multi = (multi->port1 != 0);
+
+	multi->port_monitor = new_multi.port_monitor;
+
+	if (multi->port1)
+		release_region(multi->port1,1);
+	multi->port1 = new_multi.port1;
+	multi->mask1 = new_multi.mask1;
+	multi->match1 = new_multi.match1;
+	if (multi->port1)
+		request_region(multi->port1,1,"serial(multiport1)");
+
+	if (multi->port2)
+		release_region(multi->port2,1);
+	multi->port2 = new_multi.port2;
+	multi->mask2 = new_multi.mask2;
+	multi->match2 = new_multi.match2;
+	if (multi->port2)
+		request_region(multi->port2,1,"serial(multiport2)");
+
+	if (multi->port3)
+		release_region(multi->port3,1);
+	multi->port3 = new_multi.port3;
+	multi->mask3 = new_multi.mask3;
+	multi->match3 = new_multi.match3;
+	if (multi->port3)
+		request_region(multi->port3,1,"serial(multiport3)");
+
+	if (multi->port4)
+		release_region(multi->port4,1);
+	multi->port4 = new_multi.port4;
+	multi->mask4 = new_multi.mask4;
+	multi->match4 = new_multi.match4;
+	if (multi->port4)
+		request_region(multi->port4,1,"serial(multiport4)");
+
+	now_multi = (multi->port1 != 0);
+
+	if (IRQ_ports[state->irq]->next_port &&
+		(was_multi != now_multi)) {
+		free_irq(state->irq, &IRQ_ports[state->irq]);
+		if (now_multi)
+			handler = rs_interrupt_multi;
+		else
+			handler = rs_interrupt;
+
+		retval = request_irq(state->irq, handler, SA_SHIRQ,
+				     "serial", &IRQ_ports[state->irq]);
+		if (retval) {
+			printk("Couldn't reallocate serial interrupt "
+				   "driver!!\n");
+		}
+	}
+	return 0;
+}
+#endif
+
+static int dc_ioctl(struct tty_struct *tty, struct file * file,
+		    unsigned int cmd, unsigned long arg)
+{
+	struct async_struct * info = (struct async_struct *)tty->driver_data;
+	struct async_icount cprev, cnow;    /* kernel counter temps */
+	struct serial_icounter_struct icount;
+	unsigned long flags;
+#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
+	int retval, tmp;
+#endif
+
+	if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
+		return -ENODEV;
+
+	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+		(cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
+		(cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
+		if (tty->flags & (1 << TTY_IO_ERROR))
+			return -EIO;
+	}
+
+	switch (cmd) {
+#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
+		case TCSBRK:    /* SVID version: non-zero arg --> no break */
+			retval = tty_check_change(tty);
+			if (retval)
+				return retval;
+			tty_wait_until_sent(tty, 0);
+			if (signal_pending(current))
+				return -EINTR;
+			if (!arg) {
+				send_break(info, HZ/4); /* 1/4 second */
+				if (signal_pending(current))
+				    return -EINTR;
+			}
+			return 0;
+		case TCSBRKP:   /* support for POSIX tcsendbreak() */
+			retval = tty_check_change(tty);
+			if (retval)
+				return retval;
+			tty_wait_until_sent(tty, 0);
+			if (signal_pending(current))
+				return -EINTR;
+			send_break(info, arg ? arg*(HZ/10) : HZ/4);
+			if (signal_pending(current))
+				return -EINTR;
+			return 0;
+		case TIOCGSOFTCAR:
+			tmp = C_CLOCAL(tty) ? 1 : 0;
+			if (copy_to_user((void *)arg, &tmp, sizeof(int)))
+				return -EFAULT;
+			return 0;
+		case TIOCSSOFTCAR:
+			if (copy_from_user(&tmp, (void *)arg, sizeof(int)))
+				return -EFAULT;
+
+			tty->termios->c_cflag =
+				((tty->termios->c_cflag & ~CLOCAL) |
+				 (tmp ? CLOCAL : 0));
+			return 0;
+#endif
+		case TIOCMGET:
+			return get_modem_info(info, (unsigned int *) arg);
+		case TIOCMBIS:
+		case TIOCMBIC:
+		case TIOCMSET:
+			return set_modem_info(info, cmd, (unsigned int *) arg);
+		case TIOCGSERIAL:
+			return get_serial_info(info,
+					       (struct serial_struct *) arg);
+		case TIOCSSERIAL:
+			return set_serial_info(info,
+				               (struct serial_struct *) arg);
+		case TIOCSERCONFIG:
+			return do_autoconfig(info);
+
+		case TIOCSERGETLSR: /* Get line status register */
+			return get_lsr_info(info, (unsigned int *) arg);
+
+		case TIOCSERGSTRUCT:
+			if (copy_to_user((struct async_struct *) arg,
+			    info, sizeof(struct async_struct)))
+				return -EFAULT;
+			return 0;
+
+#ifdef CONFIG_SERIAL_MULTIPORT
+		case TIOCSERGETMULTI:
+			return get_multiport_struct(info,
+				       (struct serial_multiport_struct *) arg);
+		case TIOCSERSETMULTI:
+			return set_multiport_struct(info,
+				       (struct serial_multiport_struct *) arg);
+#endif
+
+		/*
+		 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
+		 * - mask passed in arg for lines of interest
+		 *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
+		 * Caller should use TIOCGICOUNT to see which one it was
+		 */
+		case TIOCMIWAIT:
+			save_flags(flags); cli();
+			/* note the counters on entry */
+			cprev = info->state->icount;
+			restore_flags(flags);
+			/* Force modem status interrupts on */
+			info->IER |= UART_IER_MSI;
+			serial_out(info, UART_IER, info->IER);
+			while (1) {
+				interruptible_sleep_on(&info->delta_msr_wait);
+				/* see if a signal did it */
+				if (signal_pending(current))
+				    return -ERESTARTSYS;
+				save_flags(flags); cli();
+				cnow = info->state->icount; /* atomic copy */
+				restore_flags(flags);
+				if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
+				    cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
+				    return -EIO; /* no change => error */
+				if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
+				     ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
+				     ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
+				     ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
+				    return 0;
+				}
+				cprev = cnow;
+			}
+			/* NOTREACHED */
+
+		/*
+		 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
+		 * Return: write counters to the user passed counter struct
+		 * NB: both 1->0 and 0->1 transitions are counted except for
+		 *     RI where only 0->1 is counted.
+		 */
+		case TIOCGICOUNT:
+			save_flags(flags); cli();
+			cnow = info->state->icount;
+			restore_flags(flags);
+			icount.cts = cnow.cts;
+			icount.dsr = cnow.dsr;
+			icount.rng = cnow.rng;
+			icount.dcd = cnow.dcd;
+			icount.rx = cnow.rx;
+			icount.tx = cnow.tx;
+			icount.frame = cnow.frame;
+			icount.overrun = cnow.overrun;
+			icount.parity = cnow.parity;
+			icount.brk = cnow.brk;
+			icount.buf_overrun = cnow.buf_overrun;
+
+			if (copy_to_user((void *)arg, &icount, sizeof(icount)))
+				return -EFAULT;
+			return 0;
+		case TIOCSERGWILD:
+		case TIOCSERSWILD:
+			/* "setserial -W" is called in Debian boot */
+			printk ("TIOCSER?WILD ioctl obsolete, ignored.\n");
+			return 0;
+
+		default:
+			return -ENOIOCTLCMD;
+		}
+	return 0;
+}
+
+static void dc_set_termios(struct tty_struct *tty, struct termios *old_termios)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	unsigned long flags;
+	unsigned int cflag = tty->termios->c_cflag;
+
+	if (   (cflag == old_termios->c_cflag)
+		&& (   RELEVANT_IFLAG(tty->termios->c_iflag)
+		== RELEVANT_IFLAG(old_termios->c_iflag)))
+	  return;
+
+	change_speed(info, old_termios);
+
+	/* Handle transition to B0 status */
+	if ((old_termios->c_cflag & CBAUD) &&
+		!(cflag & CBAUD)) {
+		info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
+		save_flags(flags); cli();
+		serial_out(info, UART_MCR, info->MCR);
+		restore_flags(flags);
+	}
+
+	/* Handle transition away from B0 status */
+	if (!(old_termios->c_cflag & CBAUD) &&
+		(cflag & CBAUD)) {
+		info->MCR |= UART_MCR_DTR;
+		if (!(tty->termios->c_cflag & CRTSCTS) ||
+			!test_bit(TTY_THROTTLED, &tty->flags)) {
+			info->MCR |= UART_MCR_RTS;
+		}
+		save_flags(flags); cli();
+		serial_out(info, UART_MCR, info->MCR);
+		restore_flags(flags);
+	}
+
+	/* Handle turning off CRTSCTS */
+	if ((old_termios->c_cflag & CRTSCTS) &&
+		!(tty->termios->c_cflag & CRTSCTS)) {
+		tty->hw_stopped = 0;
+		dc_start(tty);
+	}
+
+#if 0
+	/*
+	 * No need to wake up processes in open wait, since they
+	 * sample the CLOCAL flag once, and don't recheck it.
+	 * XXX  It's not clear whether the current behavior is correct
+	 * or not.  Hence, this may change.....
+	 */
+	if (!(old_termios->c_cflag & CLOCAL) &&
+		(tty->termios->c_cflag & CLOCAL))
+		wake_up_interruptible(&info->open_wait);
+#endif
+}
+
+/*
+ * -----------------------------------------------------------
+ * dc_close()
+ *
+ * This routine is called when the debug console port gets closed.  
+ * First, we wait for the last remaining data to be sent.  Then, we unlink 
+ * its async structure from the interrupt chain if necessary, and we free
+ * that IRQ if nothing is left in the chain.
+ * -----------------------------------------------------------
+ */
+static void dc_close(struct tty_struct *tty, struct file *filp)
+{
+	struct async_struct * info = (struct async_struct *)tty->driver_data;
+	struct serial_state *state;
+	unsigned long flags;
+
+	if (!info || serial_paranoia_check(info, tty->device, "rs_close"))
+		return;
+
+	state = info->state;
+
+	save_flags(flags); cli();
+
+	if (tty_hung_up_p(filp)) {
+		DBG_CNT("before DEC-hung");
+		MOD_DEC_USE_COUNT;
+		restore_flags(flags);
+		return;
+	}
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("dc_close ttyD%d, count = %d\n", info->line, state->count);
+#endif
+	if ((tty->count == 1) && (state->count != 1)) {
+		/*
+		 * Uh, oh.  tty->count is 1, which means that the tty
+		 * structure will be freed.  state->count should always
+		 * be one in these conditions.  If it's greater than
+		 * one, we've got real problems, since it means the
+		 * serial port won't be shutdown.
+		 */
+		printk("rs_close: bad serial port count; tty->count is 1, "
+			   "state->count is %d\n", state->count);
+		state->count = 1;
+	}
+	if (--state->count < 0) {
+		printk("dc_close: bad serial port count for ttyD%d: %d\n",
+			   info->line, state->count);
+		state->count = 0;
+	}
+	if (state->count) {
+		DBG_CNT("before DEC-2");
+		MOD_DEC_USE_COUNT;
+		restore_flags(flags);
+		return;
+	}
+	info->flags |= ASYNC_CLOSING;
+	restore_flags(flags);
+	/*
+	 * Save the termios structure, since this port may have
+	 * separate termios for callout and dialin.
+	 */
+	if (info->flags & ASYNC_NORMAL_ACTIVE)
+		info->state->normal_termios = *tty->termios;
+	if (info->flags & ASYNC_CALLOUT_ACTIVE)
+		info->state->callout_termios = *tty->termios;
+	/*
+	 * Now we wait for the transmit buffer to clear; and we notify
+	 * the line discipline to only process XON/XOFF characters.
+	 */
+	tty->closing = 1;
+	if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+		tty_wait_until_sent(tty, info->closing_wait);
+	/*
+	 * At this point we stop accepting input.  To do this, we
+	 * disable the receive line status interrupts, and tell the
+	 * interrupt driver to stop checking the data ready bit in the
+	 * line status register.
+	 */
+	info->IER &= ~UART_IER_RLSI;
+	info->read_status_mask &= ~UART_LSR_DR;
+	if (info->flags & ASYNC_INITIALIZED) {
+		serial_out(info, UART_IER, info->IER);
+		/*
+		 * Before we drop DTR, make sure the UART transmitter
+		 * has completely drained; this is especially
+		 * important if there is a transmit FIFO!
+		 */
+		dc_wait_until_sent(tty, info->timeout);
+	}
+	shutdown(info);
+	if (tty->driver.flush_buffer)
+		tty->driver.flush_buffer(tty);
+	if (tty->ldisc.flush_buffer)
+		tty->ldisc.flush_buffer(tty);
+	tty->closing = 0;
+	info->event = 0;
+	info->tty = 0;
+	if (info->blocked_open) {
+		if (info->close_delay) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(info->close_delay);
+		}
+		wake_up_interruptible(&info->open_wait);
+	}
+	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
+			 ASYNC_CLOSING);
+	wake_up_interruptible(&info->close_wait);
+	MOD_DEC_USE_COUNT;
+}
+
+/*
+ * rs_wait_until_sent() --- wait until the transmitter is empty
+ */
+static void dc_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+	struct async_struct * info = (struct async_struct *)tty->driver_data;
+	unsigned long orig_jiffies, char_time;
+	int lsr;
+
+	if (serial_paranoia_check(info, tty->device, "dc_wait_until_sent"))
+		return;
+
+	if (info->state->type == PORT_UNKNOWN)
+		return;
+
+	if (info->xmit_fifo_size == 0)
+		return; /* Just in case.... */
+
+	orig_jiffies = jiffies;
+	/*
+	 * Set the check interval to be 1/5 of the estimated time to
+	 * send a single character, and make it at least 1.  The check
+	 * interval should also be less than the timeout.
+	 *
+	 * Note: we have to use pretty tight timings here to satisfy
+	 * the NIST-PCTS.
+	 */
+	char_time = (info->timeout - HZ/50) / info->xmit_fifo_size;
+	char_time = char_time / 5;
+	if (char_time == 0)
+		char_time = 1;
+	if (timeout && timeout < char_time)
+		char_time = timeout;
+	/*
+	 * If the transmitter hasn't cleared in twice the approximate
+	 * amount of time to send the entire FIFO, it probably won't
+	 * ever clear.  This assumes the UART isn't doing flow
+	 * control, which is currently the case.  Hence, if it ever
+	 * takes longer than info->timeout, this is probably due to a
+	 * UART bug of some kind.  So, we clamp the timeout parameter at
+	 * 2*info->timeout.
+	 */
+	if (!timeout || timeout > 2*info->timeout)
+		timeout = 2*info->timeout;
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+	printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time);
+	printk("jiff=%lu...", jiffies);
+#endif
+	while (!((lsr = serial_inp(info, UART_LSR)) & UART_LSR_TEMT)) {
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+		printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
+#endif
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(char_time);
+		if (signal_pending(current))
+			break;
+		if (timeout && time_after(jiffies, orig_jiffies + timeout))
+			break;
+	}
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+	printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
+#endif
+}
+
+/*
+ * dc_hangup() --- called by tty_hangup() when a hangup is signaled.
+ */
+static void dc_hangup(struct tty_struct *tty)
+{
+	struct async_struct * info = (struct async_struct *)tty->driver_data;
+	struct serial_state *state = info->state;
+
+	if (serial_paranoia_check(info, tty->device, "dc_hangup"))
+		return;
+
+	state = info->state;
+
+	dc_flush_buffer(tty);
+	if (info->flags & ASYNC_CLOSING)
+		return;
+	shutdown(info);
+	info->event = 0;
+	state->count = 0;
+	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+	info->tty = 0;
+	wake_up_interruptible(&info->open_wait);
+}
+
+
+
+/*
+static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
+static void rs_hangup(struct tty_struct *tty)
+*/
+
+/*
+ * ------------------------------------------------------------
+ * dc_open() and friends
+ * ------------------------------------------------------------
+ */
+#define SERIAL_DEBUG_OPEN
+static int block_til_ready(struct tty_struct *tty, struct file * filp,
+			   struct async_struct *info)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	struct serial_state *state = info->state;
+	int     retval;
+	int     do_clocal = 0, extra_count = 0;
+	unsigned long   flags;
+
+	/*
+	 * If the device is in the middle of being closed, then block
+	 * until it's done, and then try again.
+	 */
+	if (tty_hung_up_p(filp) ||
+		(info->flags & ASYNC_CLOSING)) {
+		if (info->flags & ASYNC_CLOSING)
+			interruptible_sleep_on(&info->close_wait);
+#ifdef SERIAL_DO_RESTART
+		return ((info->flags & ASYNC_HUP_NOTIFY) ?
+			-EAGAIN : -ERESTARTSYS);
+#else
+		return -EAGAIN;
+#endif
+	}
+
+	/*
+	 * If this is a callout device, then just make sure the normal
+	 * device isn't being used.
+	 */
+	if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
+		if (info->flags & ASYNC_NORMAL_ACTIVE)
+			return -EBUSY;
+		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+			(info->flags & ASYNC_SESSION_LOCKOUT) &&
+			(info->session != current->session))
+			return -EBUSY;
+		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+			(info->flags & ASYNC_PGRP_LOCKOUT) &&
+			(info->pgrp != current->pgrp))
+			return -EBUSY;
+		info->flags |= ASYNC_CALLOUT_ACTIVE;
+		return 0;
+	}
+
+#if 1 /* ? 020906 */
+filp->f_flags |= O_NONBLOCK;
+#endif /* ? 020906 */
+	/*
+	 * If non-blocking mode is set, or the port is not enabled,
+	 * then make the check up front and then exit.
+	 */
+	if ((filp->f_flags & O_NONBLOCK) ||
+		(tty->flags & (1 << TTY_IO_ERROR))) {
+		if (info->flags & ASYNC_CALLOUT_ACTIVE)
+			return -EBUSY;
+		info->flags |= ASYNC_NORMAL_ACTIVE;
+		return 0;
+	}
+
+	if (info->flags & ASYNC_CALLOUT_ACTIVE) {
+		if (state->normal_termios.c_cflag & CLOCAL)
+			do_clocal = 1;
+	} else {
+		if (tty->termios->c_cflag & CLOCAL)
+			do_clocal = 1;
+	}
+
+	/*
+	 * Block waiting for the carrier detect and the line to become
+	 * free (i.e., not in use by the callout).  While we are in
+	 * this loop, state->count is dropped by one, so that
+	 * rs_close() knows when to free things.  We restore it upon
+	 * exit, either normal or abnormal.
+	 */
+	retval = 0;
+	add_wait_queue(&info->open_wait, &wait);
+#ifdef SERIAL_DEBUG_OPEN
+	printk("block_til_ready before block: ttyD%d, count = %d\n",
+		   state->line, state->count);
+#endif
+	save_flags(flags); cli();
+	if (!tty_hung_up_p(filp)) {
+		extra_count = 1;
+		state->count--;
+	}
+	restore_flags(flags);
+	info->blocked_open++;
+	while (1) {
+		save_flags(flags); cli();
+		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
+			(tty->termios->c_cflag & CBAUD))
+			serial_out(info, UART_MCR,
+				   serial_inp(info, UART_MCR) |
+				   (UART_MCR_DTR | UART_MCR_RTS));
+		restore_flags(flags);
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (tty_hung_up_p(filp) ||
+			!(info->flags & ASYNC_INITIALIZED)) {
+#ifdef SERIAL_DO_RESTART
+			if (info->flags & ASYNC_HUP_NOTIFY)
+				retval = -EAGAIN;
+			else
+				retval = -ERESTARTSYS;
+#else
+			retval = -EAGAIN;
+#endif
+			break;
+		}
+		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
+			!(info->flags & ASYNC_CLOSING) &&
+			(do_clocal || (serial_in(info, UART_MSR) &
+				   UART_MSR_DCD)))
+			break;
+		if (signal_pending(current)) {
+			retval = -ERESTARTSYS;
+			break;
+		}
+#ifdef SERIAL_DEBUG_OPEN
+		printk("block_til_ready blocking: ttyD%d, count = %d\n",
+			   info->line, state->count);
+#endif
+		schedule();
+	}
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&info->open_wait, &wait);
+	if (extra_count)
+		state->count++;
+	info->blocked_open--;
+#ifdef SERIAL_DEBUG_OPEN
+	printk("block_til_ready after blocking: ttyD%d, count = %d\n",
+		   info->line, state->count);
+#endif
+	if (retval)
+		return retval;
+	info->flags |= ASYNC_NORMAL_ACTIVE;
+	return 0;
+}
+#undef SERIAL_DEBUG_OPEN
+
+
+static int get_async_struct(int line, struct async_struct **ret_info)
+{
+	struct async_struct *info;
+	struct serial_state *sstate;
+
+	sstate = rs_table + line;
+	sstate->count++;
+	if (sstate->info) {
+		*ret_info = sstate->info;
+		return 0;
+	}
+	info = kmalloc(sizeof(struct async_struct), GFP_KERNEL);
+	if (!info) {
+		sstate->count--;
+		return -ENOMEM;
+	}
+	memset(info, 0, sizeof(struct async_struct));
+	init_waitqueue_head(&info->open_wait);
+	init_waitqueue_head(&info->close_wait);
+	init_waitqueue_head(&info->delta_msr_wait);
+	info->magic = SERIAL_MAGIC;
+	info->port = sstate->port;
+	info->flags = sstate->flags;
+	info->io_type = sstate->io_type;
+	info->iomem_base = sstate->iomem_base;
+	info->iomem_reg_shift = sstate->iomem_reg_shift;
+	info->xmit_fifo_size = sstate->xmit_fifo_size=0;
+	info->line = line;
+	info->tqueue.routine = do_softint;
+	info->tqueue.data = info;
+	info->state = sstate;
+
+	if (sstate->info) {
+#ifdef CONFIG_LINUX_2_2
+		kfree_s(info, sizeof(struct async_struct));
+#else
+		kfree(info);
+#endif
+
+		*ret_info = sstate->info;
+		return 0;
+	}
+	*ret_info = sstate->info = info;
+	return 0;
+}
+
+/*
+ * -----------------------------------------------------------
+ * dc_open()
+ *
+ * This routine is called whenever a debug console port is opened.  It
+ * enables interrupts for a serial port, linking in its async structure into
+ * the IRQ chain.  It also performs the serial-specific
+ * initialization for the tty structure.
+ * -----------------------------------------------------------
+ */
+static int dc_open(struct tty_struct *tty, struct file *filp)
+{
+	struct async_struct *info;
+	int retval,line=0;
+	unsigned long   page;
+
+	MOD_INC_USE_COUNT;
+	line = MINOR(tty->device) - tty->driver.minor_start;
+	if ((line < 0) || (line >= NR_PORTS)) {
+		MOD_DEC_USE_COUNT;
+		return -ENODEV;
+	}
+
+	retval = get_async_struct(line, &info);
+	if (retval) {
+		printk("dc_open ttyD%d fail...",line);
+		MOD_DEC_USE_COUNT;
+		return retval;
+	}
+	tty->driver_data = info;
+	info->tty = tty;
+	if (serial_paranoia_check(info, tty->device, "dc_open"))
+		return -ENODEV;
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("dc_open %s%d, count = %d\n", tty->driver.name, info->line,
+		   info->state->count);
+#endif
+	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+
+	/*
+	 *  This relies on lock_kernel() stuff so wants tidying for 2.5
+	 */
+	if (!tmp_buf) {
+		page = get_zeroed_page(GFP_KERNEL);
+		if (!page)
+			return -ENOMEM;
+		if (tmp_buf)
+			free_page(page);
+		else
+			tmp_buf = (unsigned char *) page;
+	}
+	/*
+	 * If the port is the middle of closing, bail out now
+	 */
+	if (tty_hung_up_p(filp) ||
+	  (info->flags & ASYNC_CLOSING)) {
+	if (info->flags & ASYNC_CLOSING)
+	  interruptible_sleep_on(&info->close_wait);
+#ifdef SERIAL_DO_RESTART
+	return ((info->flags & ASYNC_HUP_NOTIFY) ?
+	  -EAGAIN : -ERESTARTSYS);
+#else
+	return -EAGAIN;
+#endif
+	}
+
+	/*
+	 * Start up serial port
+	 */
+	retval=startup(info);
+	if (retval)
+		return retval;
+
+	retval = block_til_ready(tty, filp, info);
+	if (retval) {
+#ifdef SERIAL_DEBUG_OPEN
+		printk("dc_open returning after block_til_ready with %d\n",
+			   retval);
+#endif
+		return retval;
+	}
+
+	if ((info->state->count == 1) &&
+		(info->flags & ASYNC_SPLIT_TERMIOS)) {
+		if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+			*tty->termios = info->state->normal_termios;
+		else
+			*tty->termios = info->state->callout_termios;
+		change_speed(info, 0);
+	}
+#ifdef CONFIG_SERIAL_CONSOLE
+	if (cons.cflag && cons.index == line) {
+		tty->termios->c_cflag = cons.cflag;
+		cons.cflag = 0;
+		change_speed(info, 0);
+	}
+#endif
+	info->session = current->session;
+	info->pgrp = current->pgrp;
+
+#ifdef DC_DEBUG_OPEN
+	printk("dc_open ttyD0 successful...");
+#endif
+	return 0;
+}
+
+/*
+ * /proc fs routines....
+ */
+static inline int line_info(char *buf, struct serial_state *state)
+{
+	struct async_struct *info = state->info, scr_info;
+	char  stat_buf[30], control, status;
+	int ret;
+	unsigned long flags;
+
+	ret = sprintf(buf, "%d: uart:%s port:%lX irq:%d",
+		  state->line, uart_config[state->type].name, 
+		  state->port, state->irq);
+
+	if (!state->port || (state->type == PORT_UNKNOWN)) {
+		ret += sprintf(buf+ret, "\n");
+		return ret;
+	}
+
+	/*
+	 * Figure out the current RS-232 lines
+	 */
+	if (!info) {
+		info = &scr_info; /* This is just for serial_{in,out} */
+
+		info->magic = SERIAL_MAGIC;
+		info->port = state->port;
+		info->flags = state->flags;
+		info->hub6 = state->hub6;
+		info->io_type = state->io_type;
+		info->iomem_base = state->iomem_base;
+		info->iomem_reg_shift = state->iomem_reg_shift;
+		info->quot = 0;
+		info->tty = 0;
+	}
+	save_flags(flags); cli();
+	status = serial_in(info, UART_MSR);
+	control = info != &scr_info ? info->MCR : serial_in(info, UART_MCR);
+	restore_flags(flags); 
+
+	stat_buf[0] = 0;
+	stat_buf[1] = 0;
+	if (control & UART_MCR_RTS)
+	strcat(stat_buf, "|RTS");
+	if (status & UART_MSR_CTS)
+	strcat(stat_buf, "|CTS");
+	if (control & UART_MCR_DTR)
+	strcat(stat_buf, "|DTR");
+	if (status & UART_MSR_DSR)
+	strcat(stat_buf, "|DSR");
+	if (status & UART_MSR_DCD)
+	strcat(stat_buf, "|CD");
+	if (status & UART_MSR_RI)
+	strcat(stat_buf, "|RI");
+
+	if (info->quot) {
+		ret += sprintf(buf+ret, " baud:%d",
+			 state->baud_base / (16*info->quot));
+	}
+
+	ret += sprintf(buf+ret, " tx:%d rx:%d",
+		  state->icount.tx, state->icount.rx);
+
+	if (state->icount.frame)
+		ret += sprintf(buf+ret, " fe:%d", state->icount.frame);
+	
+	if (state->icount.parity)
+		ret += sprintf(buf+ret, " pe:%d", state->icount.parity);
+	
+	if (state->icount.brk)
+		ret += sprintf(buf+ret, " brk:%d", state->icount.brk);  
+
+	if (state->icount.overrun)
+		ret += sprintf(buf+ret, " oe:%d", state->icount.overrun);
+
+	/*
+	 * Last thing is the RS-232 status lines
+	 */
+	ret += sprintf(buf+ret, " %s\n", stat_buf+1);
+	return ret;
+}
+
+
+
+int dc_read_proc(char *page, char **start, off_t off, int count,
+		 int *eof, void *data)
+{
+	int i, len = 0, l;
+	off_t begin = 0;
+
+	len += sprintf(page, "sioinfo:1.0 driver:%s%s revision:%s\n",
+		   serial_version, LOCAL_VERSTRING, serial_revdate);
+	for (i = 0; i < NR_PORTS && len < 4000; i++) {
+		l = line_info(page + len, &rs_table[i]);
+		len += l;
+		if (len+begin > off+count)
+			goto done;
+		if (len+begin < off) {
+			begin += len;
+			len = 0;
+		}
+	}
+	*eof = 1;
+done:
+	if (off >= len+begin)
+		return 0;
+	*start = page + (off-begin);
+	return ((count < begin+len-off) ? count : begin+len-off);
+}
+
+static char serial_options[] __initdata =
+	   " no serial options enabled\n";
+
+
+static inline void show_serial_version(void)
+{
+	printk(KERN_INFO "%s version %s%s (%s) with%s", serial_name,
+		serial_version, LOCAL_VERSTRING, serial_revdate,
+		serial_options);
+}
+static unsigned detect_uart_irq (struct serial_state * state)
+{
+	if(! state->irq)
+		printk(KERN_INFO "detect_uart_irq: Ohh irq = 0\n");
+		
+	return state->irq;
+}
+#if 0
+static int size_fifo(struct async_struct *info)
+{
+	return 0;
+}
+#endif  /* 0 */
+
+static void autoconfig(struct serial_state * state)
+{
+	struct async_struct *info, scr_info;
+	unsigned long flags;
+
+	state->type = PORT_UNKNOWN;
+
+#ifdef SERIAL_DEBUG_AUTOCONF
+	printk("Testing ttyS%d (0x%04lx, 0x%04x)...\n", state->line,
+		   state->port, (unsigned) state->iomem_base);
+#endif
+
+	if (!CONFIGURED_SERIAL_PORT(state))
+		return;
+
+	info = &scr_info;   /* This is just for serial_{in,out} */
+
+	info->magic = SERIAL_MAGIC;
+	info->state = state;
+	info->port = state->port;
+	info->flags = state->flags;
+#if 0 /* 020114 */
+#ifdef CONFIG_HUB6
+	info->hub6 = state->hub6;
+#endif
+	info->io_type = state->io_type;
+	info->iomem_base = state->iomem_base;
+	info->iomem_reg_shift = state->iomem_reg_shift;
+
+	save_flags(flags); cli();
+
+	if (!(state->flags & ASYNC_BUGGY_UART) &&
+		!state->iomem_base) {
+		/*
+		 * Do a simple existence test first; if we fail this,
+		 * there's no point trying anything else.
+		 *
+		 * 0x80 is used as a nonsense port to prevent against
+		 * false positives due to ISA bus float.  The
+		 * assumption is that 0x80 is a non-existent port;
+		 * which should be safe since include/asm/io.h also
+		 * makes this assumption.
+		 */
+		scratch = serial_inp(info, UART_IER);
+		serial_outp(info, UART_IER, 0);
+		scratch2 = serial_inp(info, UART_IER);
+		serial_outp(info, UART_IER, 0x0F);
+		scratch3 = serial_inp(info, UART_IER);
+		serial_outp(info, UART_IER, scratch);
+		if (scratch2 || scratch3 != 0x0F) {
+#ifdef SERIAL_DEBUG_AUTOCONF
+			printk("serial: ttyD%d: simple autoconfig failed "
+				   "(%02x, %02x)\n", state->line,
+				   scratch2, scratch3);
+#endif
+			restore_flags(flags);
+			return;     /* We failed; there's nothing here */
+		}
+	}
+
+	save_mcr = serial_in(info, UART_MCR);
+	save_lcr = serial_in(info, UART_LCR);
+
+	/*
+	 * Check to see if a UART is really there.  Certain broken
+	 * internal modems based on the Rockwell chipset fail this
+	 * test, because they apparently don't implement the loopback
+	 * test mode.  So this test is skipped on the COM 1 through
+	 * COM 4 ports.  This *should* be safe, since no board
+	 * manufacturer would be stupid enough to design a board
+	 * that conflicts with COM 1-4 --- we hope!
+	 */
+	if (!(state->flags & ASYNC_SKIP_TEST)) {
+		serial_outp(info, UART_MCR, UART_MCR_LOOP | 0x0A);
+		status1 = serial_inp(info, UART_MSR) & 0xF0;
+		serial_outp(info, UART_MCR, save_mcr);
+		if (status1 != 0x90) {
+#ifdef SERIAL_DEBUG_AUTOCONF
+			printk("serial: ttyS%d: no UART loopback failed\n",
+				   state->line);
+#endif
+			restore_flags(flags);
+			return;
+		}
+	}
+	serial_outp(info, UART_LCR, 0xBF); /* set up for StarTech test */
+	serial_outp(info, UART_EFR, 0); /* EFR is the same as FCR */
+	serial_outp(info, UART_LCR, 0);
+	serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
+	scratch = serial_in(info, UART_IIR) >> 6;
+	switch (scratch) {
+		case 0:
+			state->type = PORT_16450;
+			break;
+		case 1:
+			state->type = PORT_UNKNOWN;
+			break;
+		case 2:
+			state->type = PORT_16550;
+			break;
+		case 3:
+			state->type = PORT_16550A;
+			break;
+	}
+	if (state->type == PORT_16550A) {
+		/* Check for Startech UART's */
+		serial_outp(info, UART_LCR, UART_LCR_DLAB);
+		if (serial_in(info, UART_EFR) == 0) {
+			state->type = PORT_16650;
+		} else {
+			serial_outp(info, UART_LCR, 0xBF);
+			if (serial_in(info, UART_EFR) == 0)
+				autoconfig_startech_uarts(info, state, flags);
+		}
+	}
+	if (state->type == PORT_16550A) {
+		/* Check for TI 16750 */
+		serial_outp(info, UART_LCR, save_lcr | UART_LCR_DLAB);
+		serial_outp(info, UART_FCR,
+				UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
+		scratch = serial_in(info, UART_IIR) >> 5;
+		if (scratch == 7) {
+			/*
+			 * If this is a 16750, and not a cheap UART
+			 * clone, then it should only go into 64 byte
+			 * mode if the UART_FCR7_64BYTE bit was set
+			 * while UART_LCR_DLAB was latched.
+			 */
+			serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
+			serial_outp(info, UART_LCR, 0);
+			serial_outp(info, UART_FCR,
+				    UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
+			scratch = serial_in(info, UART_IIR) >> 5;
+			if (scratch == 6)
+				state->type = PORT_16750;
+		}
+		serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
+	}
+#if defined(CONFIG_SERIAL_RSA) && defined(MODULE)
+	if (state->type == PORT_16550A) {
+		int i;
+
+		for (i = 0 ; i < PORT_RSA_MAX ; ++i) {
+			if (!probe_rsa[i] && !force_rsa[i])
+				break;
+			if (((probe_rsa[i] != state->port) ||
+				 check_region(state->port + UART_RSA_BASE, 16)) &&
+				(force_rsa[i] != state->port))
+				continue;
+			if (!enable_rsa(info))
+				continue;
+			state->type = PORT_RSA;
+			state->baud_base = SERIAL_RSA_BAUD_BASE;
+			break;
+		}
+	}
+#endif
+	serial_outp(info, UART_LCR, save_lcr);
+	serial_outp(info, UART_LCR, 0x3);
+	if (state->type == PORT_16450) {
+		scratch = serial_in(info, UART_SCR);
+		serial_outp(info, UART_SCR, 0xa5);
+		status1 = serial_in(info, UART_SCR);
+		serial_outp(info, UART_SCR, 0x5a);
+		status2 = serial_in(info, UART_SCR);
+		serial_outp(info, UART_SCR, scratch);
+
+		if ((status1 != 0xa5) || (status2 != 0x5a))
+			state->type = PORT_8250;
+	}
+	state->xmit_fifo_size = uart_config[state->type].dfl_xmit_fifo_size;
+
+	if (state->type == PORT_UNKNOWN) {
+		restore_flags(flags);
+		return;
+	}
+
+	if (info->port) {
+#ifdef CONFIG_SERIAL_RSA
+		if (state->type == PORT_RSA)
+			request_region(info->port + UART_RSA_BASE, 16,
+				       "serial_rsa(auto)");
+		else
+#endif
+			request_region(info->port,8,"serial(auto)");
+	}
+
+	/*
+	 * Reset the UART.
+	 */
+#ifdef CONFIG_SERIAL_RSA
+	if (state->type == PORT_RSA)
+		serial_outp(info, UART_RSA_FRR, 0);
+#endif
+	serial_outp(info, UART_MCR, save_mcr);
+	serial_outp(info, UART_FCR, (UART_FCR_ENABLE_FIFO |
+				     UART_FCR_CLEAR_RCVR |
+				     UART_FCR_CLEAR_XMIT));
+	serial_outp(info, UART_FCR, 0);
+	(void)serial_in(info, UART_RX);
+	serial_outp(info, UART_IER, 0);
+
+	restore_flags(flags);
+#endif /* 020114 */
+	sio_reset(info);
+}
+
+/*
+ * The debug console driver boot-time initialization code!
+ */
+/* 20020830 */
+int __init dc_init(void)
+{
+	int i;
+	struct serial_state * state;
+
+	init_bh(SERIAL_BH, do_dc_serial_bh);
+#ifdef CONFIG_LINUX_2_2
+	timer_table[RS_TIMER].fn = dc_timer;
+	timer_table[RS_TIMER].expires = 0;
+#else /* not CONFIG_LINUX_2_2 */
+	init_timer(&serial_timer);
+	serial_timer.function = (void *)dc_timer;
+#if 1
+	mod_timer(&serial_timer, jiffies + 10);
+#else /* 1 */
+	mod_timer(&serial_timer, jiffies + RS_STROBE_TIME);
+#endif /* 1 */
+#endif /*  not CONFIG_LINUX_2_2 */
+
+	for (i = 0; i < NR_IRQS; i++) {
+		IRQ_ports[i] = 0;
+		IRQ_timeout[i] = 0;
+	}
+
+	/*
+	 * Initialize the tty_driver structure 
+	 */
+	memset(&dc_driver, 0, sizeof(struct tty_driver));
+	dc_driver.magic = TTY_DRIVER_MAGIC;
+	dc_driver.driver_name = "dconsole";
+	dc_driver.name = "ttyD";
+
+	dc_driver.major = TTY_MAJOR;
+	dc_driver.minor_start = 80;
+	dc_driver.name_base = 0;
+	dc_driver.num = NR_PORTS;
+	dc_driver.type = TTY_DRIVER_TYPE_SERIAL;
+ 
+	dc_driver.subtype = SERIAL_TYPE_NORMAL;
+	dc_driver.init_termios = tty_std_termios;
+	dc_driver.init_termios.c_cflag =
+		B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	dc_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
+	dc_driver.refcount = &dc_refcount;
+	dc_driver.table = dc_table;
+	dc_driver.termios = dc_termios;
+	dc_driver.termios_locked = dc_termios_locked;
+
+	dc_driver.open = dc_open;
+	dc_driver.close = dc_close;
+	dc_driver.write = dc_write;
+	dc_driver.put_char = dc_put_char;
+	dc_driver.flush_chars = dc_flush_chars;
+	dc_driver.write_room = dc_write_room;
+	dc_driver.chars_in_buffer = dc_chars_in_buffer;
+	dc_driver.flush_buffer = dc_flush_buffer;
+	dc_driver.ioctl = dc_ioctl;
+	dc_driver.throttle = dc_throttle;
+	dc_driver.unthrottle = dc_unthrottle;
+	dc_driver.set_termios = dc_set_termios;
+	dc_driver.stop = dc_stop;
+	dc_driver.start = dc_start;
+	dc_driver.hangup = dc_hangup;
+
+#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
+	dc_driver.break_ctl = dc_break;
+#endif
+#if (LINUX_VERSION_CODE >= 131343)
+	dc_driver.send_xchar = dc_send_xchar;
+	dc_driver.wait_until_sent = dc_wait_until_sent;
+	dc_driver.read_proc = dc_read_proc;
+#endif
+
+	if (tty_register_driver(&dc_driver))
+		panic("Couldn't register debug console driver\n");
+
+	for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
+		state->magic = SSTATE_MAGIC;
+		state->line = i;
+		state->type = 14;
+		state->custom_divisor = 0;
+		state->close_delay = 5*HZ/10;
+		state->closing_wait = 30*HZ;
+		state->callout_termios = dc_driver.init_termios;
+		state->normal_termios = dc_driver.init_termios;
+		state->icount.cts = state->icount.dsr =
+			state->icount.rng = state->icount.dcd = 0;
+		state->icount.rx = state->icount.tx = 0;
+		state->icount.frame = state->icount.parity = 0;
+		state->icount.overrun = state->icount.brk = 0;
+		state->irq = irq_cannonicalize(state->irq);
+
+#if 0
+		if (check_region(state->port,8))
+			continue;
+		if (state->flags & ASYNC_BOOT_AUTOCONF)
+			autoconfig(dc_table);
+#endif
+		state->baud_base = boot_cpu_data.bus_clock;
+		printk(KERN_INFO "ttyD%d initialized.\n",i);
+	   		tty_register_devfs(&dc_driver, 0,
+						   dc_driver.minor_start + state->line);
+	}
+
+	return 0;
+}
+
+#if 0
+int register_dc(struct dc_struct *req)
+{
+}
+#endif
+
+/* 20020830 */
+static void __exit dc_fini(void)
+{
+	unsigned long flags;
+	// int e1, e2;
+	int e1;
+	// int i;
+	// struct async_struct *info;
+
+	/* printk("Unloading %s: version %s\n", serial_name, serial_version); */
+	del_timer_sync(&serial_timer);
+	save_flags(flags); cli();
+		remove_bh(SERIAL_BH);
+	if ((e1 = tty_unregister_driver(&dc_driver)))
+		printk("dc_serial: failed to unregister serial driver (%d)\n",e1);
+#if 0 /* 020114 */
+	if ((e2 = tty_unregister_driver(&callout_driver)))
+		printk("serial: failed to unregister callout driver (%d)\n",e2);
+#endif /* 020114 */
+	restore_flags(flags);
+
+#if 0 /* 020114 */
+	for (i = 0; i < NR_PORTS; i++) {
+		if ((info = rs_table[i].info)) {
+			rs_table[i].info = NULL;
+			kfree(info);
+		}
+		if ((rs_table[i].type != PORT_UNKNOWN) && rs_table[i].port) {
+#ifdef CONFIG_SERIAL_RSA
+			if (rs_table[i].type == PORT_RSA)
+				release_region(rs_table[i].port +
+				           UART_RSA_BASE, 16);
+			else
+#endif
+				release_region(rs_table[i].port, 8);
+		}
+#if defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP)
+		if (rs_table[i].iomem_base)
+			iounmap(rs_table[i].iomem_base);
+#endif
+	}
+#endif /* 020114 */
+#if 0 /* 020114 */
+#if defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP)
+	for (i=0; i < NR_PCI_BOARDS; i++) {
+		struct pci_board_inst *brd = &serial_pci_board[i];
+
+		if (serial_pci_board[i].dev == 0)
+			continue;
+		if (brd->board.init_fn)
+			(brd->board.init_fn)(brd->dev, &brd->board, 0);
+		if (DEACTIVATE_FUNC(brd->dev))
+			(DEACTIVATE_FUNC(brd->dev))(brd->dev);
+	}
+#endif
+#endif /* 020114 */
+	if (tmp_buf) {
+		unsigned long pg = (unsigned long) tmp_buf;
+		tmp_buf = NULL;
+		free_page(pg);
+	}
+
+#if 0 /* 020114 */
+#ifdef ENABLE_SERIAL_PCI
+	if (serial_pci_driver.name[0])
+		pci_unregister_driver (&serial_pci_driver);
+#endif
+#endif /* 020114 */
+}
+
+module_init(dc_init);
+module_exit(dc_fini);
+MODULE_DESCRIPTION("M32R/m32102 (dumb) serial driver");
+MODULE_AUTHOR("Hiroyuki Kondo <kondo@lsi.melco.co.jp>");
+MODULE_LICENSE("GPL");
+
+
+/*
+ * -----------------------------------------------------------
+ * Debug console driver
+ * -----------------------------------------------------------
+ */
+
+#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+
+static struct async_struct async_dbgcons;
+
+/*
+ *  Wait for transmitter & holding register to empty
+ */
+static inline void wait_for_xmitr(struct async_struct *info)
+{
+	unsigned int status, tmout = 1000000;
+
+	do {
+		status = serial_in(info, UART_LSR);
+
+		if (status & UART_LSR_BI)
+			lsr_break_flag = UART_LSR_BI;
+	
+		if (--tmout == 0)
+			break;
+	} while((status & BOTH_EMPTY) != BOTH_EMPTY);
+
+	/* Wait for flow control if necessary */
+	if (info->flags & ASYNC_CONS_FLOW) {
+		tmout = 1000000;
+		while (--tmout &&
+			((serial_in(info, UART_MSR) & UART_MSR_CTS) == 0));
+	} 
+}
+static void dbg_console_write(struct console *co, const char *s, 
+				unsigned count)
+{
+	static struct async_struct *info = &async_dbgcons;
+	int ier;
+	unsigned i;
+
+	/*
+	 *  First save the IER then disable the interrupts
+	 */
+	ier = serial_in(info, UART_IER);
+	serial_out(info, UART_IER, 0x00);
+
+	/*
+	 *  Now, do each character
+	 */
+	for (i = 0; i < count; i++, s++) {
+		wait_for_xmitr(info);
+
+		/*
+		 *	Send the character out.
+		 *	If a LF, also do CR...
+		 */
+		serial_out(info, UART_TX, *s);
+		if (*s == 10) {
+			wait_for_xmitr(info);
+			serial_out(info, UART_TX, 13);
+		}
+	}
+
+	/*
+	 *	Finally, Wait for transmitter & holding register to empty
+	 *	and restore the IER
+	 */
+	wait_for_xmitr(info);
+	serial_out(info, UART_IER, ier);
+}
+
+#if (LINUX_VERSION_CODE <= 132114) /* Linux 2.4.18 */
+/*
+ *  Receive character from the serial port
+ */
+static int dbg_console_wait_key(struct console *console)
+{
+	static struct async_struct *info;
+	int ier, c;
+
+	info = &async_dbgcons;
+
+	/*
+	 *  First save the IER then disable the interrupts so
+	 *  that the real driver for the port does not get the
+	 *  character.
+	 */
+	ier = serial_in(info, UART_IER);
+	serial_out(info, UART_IER, 0x00);
+ 
+	while ((serial_in(info, UART_LSR) & UART_LSR_DR) == 0);
+	c = serial_in(info, UART_RX);
+
+	/*
+	 *  Restore the interrupts
+	 */
+	serial_out(info, UART_IER, ier);
+
+	return c;
+}
+#endif
+
+static kdev_t dbg_console_device(struct console *c)
+{
+	return MKDEV(TTY_MAJOR, 80 + c->index);
+}
+
+
+static int __init dbg_console_setup(struct console *co, char *options)
+{
+	static struct async_struct *info;
+	struct serial_state *state;
+	int baud = BAUDRATE;
+	int baud_base= boot_cpu_data.bus_clock;
+	int bits = 8;
+	int parity = 'n';
+	int doflow = 0;
+	unsigned int cflag = CREAD | HUPCL | CLOCAL | CRTSCTS;
+	int cval,adj = 0;
+	char *s;
+
+	if (options) {
+		baud = simple_strtoul(options, NULL, 10);
+		s = options;
+		while(*s >= '0' && *s <= '9')
+			s++;
+		if (*s) parity = *s++;
+		if (*s) bits   = *s++ - '0';
+		if (*s) doflow = (*s++ == 'r');
+	}
+
+	co->flags |= CON_ENABLED;
+
+	/*
+	 * 	Now construct a cflag setting.
+	 */
+	switch(baud) {
+		case 1200:
+			cflag |= B1200;
+			break;
+		case 2400:
+			cflag |= B2400;
+			break;
+		case 4800:
+			cflag |= B4800;
+			break;
+		case 19200:
+			cflag |= B19200;
+			break;
+		case 38400:
+			cflag |= B38400;
+			break;
+		case 57600:
+			cflag |= B57600;
+			break;
+		case 115200:
+			cflag |= B115200;
+			break;
+		case 9600:
+		default:
+			cflag |= B9600;
+			baud  = 9600;
+			break;
+	}
+	switch(bits) {
+		case 7:
+			cflag |= CS7;
+			break;
+		default:
+		case 8:
+			cflag |= CS8;
+			break;
+	}
+	switch(parity) {
+		case 'o': case 'O':
+			cflag |= PARODD;
+			break;
+		case 'e': case 'E':
+			cflag |= PARENB;
+			break;
+	}
+	co->cflag = cflag;
+
+	state = rs_table + co->index;
+	if (doflow)
+		state->flags |= ASYNC_CONS_FLOW;
+	info = &async_dbgcons;
+	info->magic = SERIAL_MAGIC;
+	info->state = state;
+	info->port = state->port;
+	info->flags = state->flags;
+	info->io_type = state->io_type;
+	info->iomem_base = state->iomem_base;
+	info->iomem_reg_shift = state->iomem_reg_shift;
+
+	cval=baud_base/(baud*16);
+	adj=(baud_base-cval*baud*16)/baud;
+	cval-=1;
+	adj=(adj+1) >> 1;
+
+	serial_outp(info, UART_LCR,  0x0300);  /* init status         */
+	serial_outp(info, UART_MOD1, 0x0800);  /* 8bit                */
+#if defined(CONFIG_CHIP_M32700)
+	serial_outp(info, UART_MOD0, 0x180);    /* rts 1stop nonpari */
+#else
+	serial_outp(info, UART_MOD0, 0xc0);    /* cts/rts 1stop nonpari */
+#endif
+
+	serial_outp(info, UART_BAUR, cval);    /* set baurate reg     */
+	serial_outp(info, UART_RBAUR, adj);    /* set adj baurate reg */
+	serial_outp(info, UART_IER, 0x00);     /* intr mask           */
+	serial_outp(info, UART_LCR, 0x03);
+
+	return 0;
+}
+
+static struct console cons = {
+	name:		"ttyD",
+	write:		dbg_console_write,
+	device:		dbg_console_device,
+#if (LINUX_VERSION_CODE <= 132114) /* Linux 2.4.18 */
+	wait_key:	dbg_console_wait_key,
+#endif
+	setup:		dbg_console_setup,
+	flags:		CON_PRINTBUFFER,
+	index:		-1,
+};
+
+
+#ifdef DC_DEBUG
+void
+dc_int_chk(int irq, void *dev_id, struct pt_regs * regs)
+{
+	unsigned short  us;
+	
+	us = *(volatile unsigned short *)0x85001000;  /* [hy] IRQ */
+	
+	printk("dc_int_chk:irq[%d]:us[%04x]\n", irq, us);
+	
+	*(volatile unsigned short *)0x85001008 = us;  /* [hy] IMASK */
+}
+
+struct irqaction irq1  = { dc_int_chk, SA_INTERRUPT, 0, \
+	"uart0", NULL, NULL};
+#endif  /* DC_DEBUG */
+
+
+/* 
+ *	Register console.
+ */
+void __init dbg_console_init(void)
+{
+	register_console(&cons);
+}
+
+
diff -ruN linux-2.4.26.org/arch/m32r/drivers/ds1302.c linux-2.4.26/arch/m32r/drivers/ds1302.c
--- linux-2.4.26.org/arch/m32r/drivers/ds1302.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/arch/m32r/drivers/ds1302.c	2004-03-22 10:55:18.000000000 +0900
@@ -0,0 +1,421 @@
+/*!***************************************************************************
+*!
+*! FILE NAME  : ds1302.c
+*!
+*! DESCRIPTION: Implements an interface for the DS1302 RTC through Etrax I/O
+*!
+*! Functions exported: ds1302_readreg, ds1302_writereg, ds1302_init, get_rtc_status
+*!
+*! $Log: ds1302.c,v $
+*! Revision 1.3  2004/03/22 01:55:18  fujiwara
+*! Merge linux-2.4.25
+*!
+*! Revision 1.2  2003/10/29 08:42:58  fujiwara
+*! Set PLD_RTCBAUR from bus clock
+*!
+*! Revision 1.12  2002/04/10 15:35:25  johana
+*! Moved probe function closer to init function and marked it __init.
+*!
+*! Revision 1.11  2001/06/14 12:35:52  jonashg
+*! The ATA hack is back. It is unfortunately the only way to set g27 to output.
+*!
+*! Revision 1.9  2001/06/14 10:00:14  jonashg
+*! No need for tempudelay to be inline anymore (had to adjust the usec to
+*! loops conversion because of this to make it slow enough to be a udelay).
+*!
+*! Revision 1.8  2001/06/14 08:06:32  jonashg
+*! Made tempudelay delay usecs (well, just a tad more).
+*!
+*! Revision 1.7  2001/06/13 14:18:11  jonashg
+*! Only allow processes with SYS_TIME capability to set time and charge.
+*!
+*! Revision 1.6  2001/06/12 15:22:07  jonashg
+*! * Made init function __init.
+*! * Parameter to out_byte() is unsigned char.
+*! * The magic number 42 has got a name.
+*! * Removed comment about /proc (nothing is exported there).
+*!
+*! Revision 1.5  2001/06/12 14:35:13  jonashg
+*! Gave the module a name and added it to printk's.
+*!
+*! Revision 1.4  2001/05/31 14:53:40  jonashg
+*! Made tempudelay() inline so that the watchdog doesn't reset (see
+*! function comment).
+*!
+*! Revision 1.3  2001/03/26 16:03:06  bjornw
+*! Needs linux/config.h
+*!
+*! Revision 1.2  2001/03/20 19:42:00  bjornw
+*! Use the ETRAX prefix on the DS1302 options
+*!
+*! Revision 1.1  2001/03/20 09:13:50  magnusmn
+*! Linux 2.4 port
+*!
+*! Revision 1.10  2000/07/05 15:38:23  bjornw
+*! Dont update kernel time when a RTC_SET_TIME is done
+*!
+*! Revision 1.9  2000/03/02 15:42:59  macce
+*! * Hack to make RTC work on all 2100/2400
+*!
+*! Revision 1.8  2000/02/23 16:59:18  torbjore
+*! added setup of R_GEN_CONFIG when RTC is connected to the generic port.
+*!
+*! Revision 1.7  2000/01/17 15:51:43  johana
+*! Added RTC_SET_CHARGE ioctl to enable trickle charger.
+*!
+*! Revision 1.6  1999/10/27 13:19:47  bjornw
+*! Added update_xtime_from_cmos which reads back the updated RTC into the kernel.
+*! /dev/rtc calls it now.
+*!
+*! Revision 1.5  1999/10/27 12:39:37  bjornw
+*! Disabled superuser check. Anyone can now set the time.
+*!
+*! Revision 1.4  1999/09/02 13:27:46  pkj
+*! Added shadow for R_PORT_PB_CONFIG.
+*! Renamed port_g_shadow to port_g_data_shadow.
+*!
+*! Revision 1.3  1999/09/02 08:28:06  pkj
+*! Made it possible to select either port PB or the generic port for the RST
+*! signal line to the DS1302 RTC.
+*! Also make sure the RST bit is configured as output on Port PB (if used).
+*!
+*! Revision 1.2  1999/09/01 14:47:20  bjornw
+*! Added support for /dev/rtc operations with ioctl RD_TIME and SET_TIME to read
+*! and set the date. Register as major 121.
+*!
+*! Revision 1.1  1999/09/01 09:45:29  bjornw
+*! Implemented a DS1302 RTC driver.
+*!
+*!
+*! ---------------------------------------------------------------------------
+*!
+*! (C) Copyright 1999, 2000, 2001  Axis Communications AB, LUND, SWEDEN
+*!
+*! $Id: ds1302.c,v 1.3 2004/03/22 01:55:18 fujiwara Exp $
+*!
+*!***************************************************************************/
+
+#include <linux/config.h>
+
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/delay.h>
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/rtc.h>
+#include <asm/m32700ut/m32700ut_pld.h>
+
+#define RTC_MAJOR_NR 121 /* local major, change later */
+
+static const char ds1302_name[] = "ds1302";
+
+/* Send 8 bits. */
+static void
+out_byte_rtc(unsigned int reg_addr, unsigned char x) 
+{
+	//RST H
+	outw(0x0001,(unsigned long)PLD_RTCRSTODT);
+	//write data
+	outw(((x<<8)|(reg_addr&0xff)),(unsigned long)PLD_RTCWRDATA);
+	//WE
+	outw(0x0002,(unsigned long)PLD_RTCCR);
+	//wait
+	while(inw((unsigned long)PLD_RTCCR));
+	
+	//RST L
+	outw(0x0000,(unsigned long)PLD_RTCRSTODT);
+
+}
+
+static unsigned char
+in_byte_rtc(unsigned int reg_addr) 
+{
+	unsigned char retval;
+	
+	//RST H
+	outw(0x0001,(unsigned long)PLD_RTCRSTODT);
+	//write data
+	outw((reg_addr&0xff),(unsigned long)PLD_RTCRDDATA);
+	//RE
+	outw(0x0001,(unsigned long)PLD_RTCCR);
+	//wait
+	while(inw((unsigned long)PLD_RTCCR));
+
+	//read data
+	retval=(inw((unsigned long)PLD_RTCRDDATA) & 0xff00)>>8;
+
+	//RST L
+	outw(0x0000,(unsigned long)PLD_RTCRSTODT);
+
+	return retval;
+}
+
+/* Enable writing. */
+
+static void
+ds1302_wenable(void) 
+{
+	out_byte_rtc(0x8e,0x00);
+}
+
+/* Disable writing. */
+
+static void
+ds1302_wdisable(void) 
+{
+	out_byte_rtc(0x8e,0x80);
+}
+
+
+
+/* Read a byte from the selected register in the DS1302. */
+
+unsigned char
+ds1302_readreg(int reg) 
+{
+	unsigned char x;
+
+	x=in_byte_rtc((0x81 | (reg << 1))); /* read register */
+
+	return x;
+}
+
+/* Write a byte to the selected register. */
+
+void
+ds1302_writereg(int reg, unsigned char val) 
+{
+	ds1302_wenable();
+	out_byte_rtc((0x80 | (reg << 1)),val);
+	ds1302_wdisable();
+}
+
+void
+get_rtc_time(struct rtc_time *rtc_tm) 
+{
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+
+	rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS);
+	rtc_tm->tm_min = CMOS_READ(RTC_MINUTES);
+	rtc_tm->tm_hour = CMOS_READ(RTC_HOURS);
+	rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH);
+	rtc_tm->tm_mon = CMOS_READ(RTC_MONTH);
+	rtc_tm->tm_year = CMOS_READ(RTC_YEAR);
+
+	restore_flags(flags);
+	
+	BCD_TO_BIN(rtc_tm->tm_sec);
+	BCD_TO_BIN(rtc_tm->tm_min);
+	BCD_TO_BIN(rtc_tm->tm_hour);
+	BCD_TO_BIN(rtc_tm->tm_mday);
+	BCD_TO_BIN(rtc_tm->tm_mon);
+	BCD_TO_BIN(rtc_tm->tm_year);
+
+	/*
+	 * Account for differences between how the RTC uses the values
+	 * and how they are defined in a struct rtc_time;
+	 */
+
+	if (rtc_tm->tm_year <= 69)
+		rtc_tm->tm_year += 100;
+
+	rtc_tm->tm_mon--;
+}
+
+static unsigned char days_in_mo[] = 
+    {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+/* ioctl that supports RTC_RD_TIME and RTC_SET_TIME (read and set time/date). */
+
+static int
+rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	  unsigned long arg) 
+{
+        unsigned long flags;
+
+	switch(cmd) {
+		case RTC_RD_TIME:	/* read the time/date from RTC	*/
+		{
+			struct rtc_time rtc_tm;
+						
+			memset(&rtc_tm, 0, sizeof (struct rtc_time));
+			get_rtc_time(&rtc_tm);						
+			if (copy_to_user((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time)))
+				return -EFAULT;	
+			return 0;
+		}
+
+		case RTC_SET_TIME:	/* set the RTC */
+		{
+			struct rtc_time rtc_tm;
+			unsigned char mon, day, hrs, min, sec, leap_yr;
+			unsigned int yrs;
+
+			if (!capable(CAP_SYS_TIME))
+				return -EPERM;
+
+			if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time)))
+				return -EFAULT;    	
+
+			yrs = rtc_tm.tm_year + 1900;
+			mon = rtc_tm.tm_mon + 1;   /* tm_mon starts at zero */
+			day = rtc_tm.tm_mday;
+			hrs = rtc_tm.tm_hour;
+			min = rtc_tm.tm_min;
+			sec = rtc_tm.tm_sec;
+			
+			
+			if ((yrs < 1970) || (yrs > 2069))
+				return -EINVAL;
+
+			leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400));
+
+			if ((mon > 12) || (day == 0))
+				return -EINVAL;
+
+			if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr)))
+				return -EINVAL;
+			
+			if ((hrs >= 24) || (min >= 60) || (sec >= 60))
+				return -EINVAL;
+
+			if (yrs >= 2000)
+				yrs -= 2000;	/* RTC (0, 1, ... 69) */
+			else
+				yrs -= 1900;	/* RTC (70, 71, ... 99) */
+
+			BIN_TO_BCD(sec);
+			BIN_TO_BCD(min);
+			BIN_TO_BCD(hrs);
+			BIN_TO_BCD(day);
+			BIN_TO_BCD(mon);
+			BIN_TO_BCD(yrs);
+
+			save_flags(flags);
+			cli();
+			CMOS_WRITE(yrs, RTC_YEAR);
+			CMOS_WRITE(mon, RTC_MONTH);
+			CMOS_WRITE(day, RTC_DAY_OF_MONTH);
+			CMOS_WRITE(hrs, RTC_HOURS);
+			CMOS_WRITE(min, RTC_MINUTES);
+			CMOS_WRITE(sec, RTC_SECONDS);
+			restore_flags(flags);
+
+			/* Notice that at this point, the RTC is updated but
+			 * the kernel is still running with the old time.
+			 * You need to set that separately with settimeofday
+			 * or adjtimex.
+			 */
+			return 0;
+		}
+
+		case RTC_SET_CHARGE: /* set the RTC TRICKLE CHARGE register */
+		{
+			int tcs_val;                        
+
+			if (!capable(CAP_SYS_TIME))
+				return -EPERM;
+			
+			if(copy_from_user(&tcs_val, (int*)arg, sizeof(int)))
+				return -EFAULT;
+
+			tcs_val = RTC_TCR_PATTERN | (tcs_val & 0x0F);
+			ds1302_writereg(RTC_TRICKLECHARGER, tcs_val);
+			return 0;
+		}
+		default:
+			return -EINVAL;
+	}
+}
+
+static void
+print_rtc_status(void) 
+{
+	struct rtc_time tm;
+
+	get_rtc_time(&tm);
+
+	/*
+	 * There is no way to tell if the luser has the RTC set for local
+	 * time or for Universal Standard Time (GMT). Probably local though.
+	 */
+
+	printk(KERN_INFO "rtc_time\t: %02d:%02d:%02d\n",
+	       tm.tm_hour, tm.tm_min, tm.tm_sec);
+	printk(KERN_INFO "rtc_date\t: %04d-%02d-%02d\n",
+	       tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
+}
+
+
+/* The various file operations we support. */
+
+static struct file_operations rtc_fops = {
+        owner:          THIS_MODULE,
+        ioctl:          rtc_ioctl,	
+}; 
+
+/* Probe for the chip by writing something to its RAM and try reading it back. */
+
+#define MAGIC_PATTERN 0x42
+
+static int __init
+ds1302_probe(void) 
+{
+	int retval, res, baur; 
+
+	baur=(boot_cpu_data.bus_clock/(2*1000*1000));
+
+	printk("%s: Set PLD_RTCBAUR = %d\n", ds1302_name,baur);
+
+	outw(0x0000,(unsigned long)PLD_RTCCR);
+	outw(0x0000,(unsigned long)PLD_RTCRSTODT);
+	outw(baur,(unsigned long)PLD_RTCBAUR);
+
+	/* Try to talk to timekeeper. */
+
+	ds1302_wenable();  
+	/* write RAM byte 0 */	
+	/* write something magic */
+	out_byte_rtc(0xc0,MAGIC_PATTERN);
+	
+	/* read RAM byte 0 */
+	if((res = in_byte_rtc(0xc1)) == MAGIC_PATTERN) {
+		ds1302_wdisable();
+		printk(KERN_INFO "%s: RTC found.\n", ds1302_name);
+                print_rtc_status();
+		retval = 1;
+	} else {
+		retval = 0;
+	}
+
+	return retval;
+}
+
+
+/* Just probe for the RTC and register the device to handle the ioctl needed. */
+
+int __init
+ds1302_init(void) 
+{ 
+	if (!ds1302_probe()) {
+		printk(KERN_WARNING "%s: RTC not found.\n", ds1302_name);
+    		return -1;
+  	}
+  
+	if (register_chrdev(RTC_MAJOR_NR, ds1302_name, &rtc_fops)) {
+		printk(KERN_INFO "%s: unable to get major %d for rtc\n", 
+		       ds1302_name, RTC_MAJOR_NR);
+		return -1;
+	}
+	return 0;
+}
+
+module_init(ds1302_init);
diff -ruN linux-2.4.26.org/arch/m32r/drivers/idc_ak4524.c linux-2.4.26/arch/m32r/drivers/idc_ak4524.c
--- linux-2.4.26.org/arch/m32r/drivers/idc_ak4524.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/arch/m32r/drivers/idc_ak4524.c	2004-05-17 17:12:18.000000000 +0900
@@ -0,0 +1,637 @@
+/*
+ * idc_ak4524.c
+ *  IDC-R (uServer) AK4524 CODEC chip driver
+ *
+ * Copyright (c) 2003 Hitoshi Yamamoto
+ */
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+
+#include <asm/io.h>
+#include <asm/m32r.h>
+#include <asm/uaccess.h>
+#include <asm/idc/idc_ak4524.h>
+
+#undef AK4524_DEBUG
+#undef USE_ISRAM
+
+#ifdef USE_ISRAM
+#define IRAM_ADDR	0xa0f00000
+#define IRAM_SIZE	0x00080000
+#define MAX(a, b)	((a) > (b) ? (a) : (b))
+#define MIN(a, b)	((a) < (b) ? (a) : (b))
+static __inline__ void port_to_iram(unsigned long port)
+{
+	short *dest = (short *)IRAM_ADDR;
+	short *src = (short *)(port + NONCACHE_OFFSET);
+	int n = IRAM_SIZE;
+
+	__asm__ __volatile__ (
+		"beqz	%2, 2f;			\n\t"
+		".fillinsn			\n"
+		"1:				\n\t"
+		"lduh	r7, @%0;		\n\t"
+		"lduh	r4, @%1;		\n\t"
+		"lduh	r5, @%1;		\n\t"
+		"lduh	r6, @%1;		\n\t"
+		"lduh	r7, @%1;		\n\t"
+		"sth	r4, @%0+;		\n\t"
+		"sth	r5, @%0+;		\n\t"
+		"sth	r6, @%0+;		\n\t"
+		"sth	r7, @%0+;		\n\t"
+		"lduh	r4, @%1;		\n\t"
+		"lduh	r5, @%1;		\n\t"
+		"lduh	r6, @%1;		\n\t"
+		"lduh	r7, @%1;		\n\t"
+		"sth	r4, @%0+;		\n\t"
+		"sth	r5, @%0+;		\n\t"
+		"sth	r6, @%0+;		\n\t"
+		"sth	r7, @%0+;		\n\t"
+		"addi	%2, #-16;		\n\t"
+		"bnez	%2, 1b;			\n\t"
+		".fillinsn			\n"
+		"2:				\n\t"
+		: /* no outputs */
+		: "r" (dest), "r" (src), "r" (n)
+		: "r4", "r5", "r6", "r7", "memory"
+	);
+}
+
+static __inline__ void iram_to_port(unsigned long port)
+{
+	short *dest = (short *)(port + NONCACHE_OFFSET);
+	short *src = (short *)IRAM_ADDR;
+	int n = IRAM_SIZE;
+
+	__asm__ __volatile__ (
+		"beqz	%2, 2f;			\n\t"
+		".fillinsn			\n"
+		"1:				\n\t"
+		"ld	r5, @%1+;		\n\t"
+		"ld	r7, @%1+;		\n\t"
+		"srl3	r4, r5, #16;		\n\t"
+		"sth	r4, @%0;		\n\t"
+		"sth	r5, @%0;		\n\t"
+		"srl3	r6, r7, #16;		\n\t"
+		"sth	r6, @%0;		\n\t"
+		"sth	r7, @%0;		\n\t"
+		"ld	r5, @%1+;		\n\t"
+		"ld	r7, @%1+;		\n\t"
+		"srl3	r4, r5, #16;		\n\t"
+		"sth	r4, @%0;		\n\t"
+		"sth	r5, @%0;		\n\t"
+		"srl3	r6, r7, #16;		\n\t"
+		"sth	r6, @%0;		\n\t"
+		"sth	r7, @%0;		\n\t"
+		"addi	%2, #-16;		\n\t"
+		"bnez	%2, 1b;			\n\t"
+		".fillinsn			\n"
+		"2:				\n\t"
+		: /* no outputs */
+		: "r" (dest), "r" (src), "r" (n)
+		: "r4", "r5", "r6", "r7", "memory"
+	);
+}
+#endif	/* USE_ISRAM */
+
+#undef Dprintk
+#ifdef AK4524_DEBUG
+#define Dprintk(x...)	do { printk(x); } while (0)
+#else	/* !AK4524_DEBUG */
+#define Dprintk(x...)	do { } while (0)
+#endif	/* !AK4524_DEBUG */
+
+#define AK_NAME		"idc_ak4524"
+#define AK_MAJOR	240
+
+/* I/O functions */
+#define akinw(x)		inw((x))
+#define akinsw(x, y, z)		insw((x), (y), (z))
+#define akoutw(x, y)		outw((x), (y))
+#define akoutsw(x, y, z)	outsw((x), (y), (z))
+
+typedef struct {
+	wait_queue_head_t wait;
+	int use_count;
+	ak4524_cmd_t cmd;
+	ak4524_mode_t mode;
+	ak4524_mode_t mode_save;
+} ak4524_t;
+
+static ak4524_t ak4524;
+
+static int ak4524_status(ak4524_t *ak)
+{
+	int status = AK_STATUS_READY;
+
+	/* Data transfer inprogress check */
+	if (akinw(IDCMDST) & AK_STATUS_BUSY)
+		status = AK_STATUS_BUSY;
+	else
+		wake_up_interruptible(&ak->wait);
+
+	Dprintk("ak4524_status status:%d\n", status);
+
+	return status;
+}
+
+/* IOCTL AKRESET command */
+static void ak4524_reset(ak4524_t *ak)
+{
+	Dprintk("ak4524_reset\n");
+
+	if (ak4524_status(ak) != AK_STATUS_READY)
+		akoutw(0x0000, IDCMDST);	/* Stop */
+
+#if 1	/* Work around for H/W bug */
+	akoutw(0x0003, IDCRESET);	/* PD = 1, RST = 1 */
+	akoutw(0x0000, IDCRESET);	/* PD = 0, RST = 0 */
+#endif
+	/* Setup AK4524 register */
+	akoutw(0x0700, AK4524_REG0);	/* Power Down Control */
+	akoutw(0x0000, AK4524_REG2);	/* Clock and Format Control */
+	akoutw(0x0300, AK4524_REG1);	/* Reset Control */
+	akoutw(0x1100, AK4524_REG3);	/* Deem and Volume Control */
+
+	akoutw(AK_IPG_DEF << 8, AK4524_REG4);	/* Lch IPGA Control */
+	akoutw(AK_IPG_DEF << 8, AK4524_REG5);	/* Rch IPGA Control */
+	akoutw(AK_IPG_DEF << 8, AK4524_REG6);	/* Lch OATT Control */
+	akoutw(AK_IPG_DEF << 8, AK4524_REG7);	/* Rch OATT Control */
+
+	ak->mode_save.ipgl = AK_IPG_DEF;
+	ak->mode_save.ipgr = AK_IPG_DEF;
+	ak->mode_save.attl = AK_ATT_DEF;
+	ak->mode_save.attr = AK_ATT_DEF;
+
+	/* wait 30ms */
+	interruptible_sleep_on_timeout(&ak->wait, (30 * HZ) / 1000);
+}
+
+/* IOCTL AKCMD command */
+static int ak4524_cmd(ak4524_t *ak)
+{
+	ak4524_cmd_t *akc = &ak->cmd;
+	unsigned short us;
+
+	Dprintk("ak4524_cmd cmd:%d addr:0x%04x, leng:0x%x, smpl:%d\n",
+		akc->cmd, akc->addr, akc->leng, akc->smpl);
+
+	/* Stop command */
+	if (akc->cmd == AK_CMD_STOP) {
+		us = akinw(IDCMDST);
+		us &= ~1UL;		/* Clear STRT bit */
+		akoutw(us, IDCMDST);
+		return 0;
+	}
+
+	/* Condition check */
+	if (ak4524_status(ak) != AK_STATUS_READY) {
+		Dprintk("ak4524_cmd: device busy\n");
+		return -EBUSY;
+	}
+
+	/* Argument check */
+	if (!akc->leng || akc->addr > AK_ADDR_MAX || akc->leng > AK_LENG_MAX
+		|| ADDR2BYTE(akc->addr) + LENG2BYTE(akc->leng) > IDCSRAM_SIZE)
+	{
+		Dprintk("ak4524_cmd: invalid argument addr:%d, leng:%d\n",
+			akc->addr, akc->leng);
+		return -EINVAL;
+	}
+
+	switch (akc->smpl) {
+	case AK_SMPL_44100:
+	case AK_SMPL_22050:
+	case AK_SMPL_11025:
+	case AK_SMPL_05125:
+		break;
+	default:
+		Dprintk("ak4524_cmd: invalid argument smpl:%d\n", akc->smpl);
+		return -EINVAL;
+	}
+
+	switch (akc->cmd) {
+	case AK_CMD_PLAY:
+	case AK_CMD_REC:
+	case AK_CMD_PLAYL:
+	case AK_CMD_RECL:
+		break;
+	default:
+		Dprintk("ak4524_cmd: invalid argument cmd:%d\n", akc->cmd);
+		return -EINVAL;
+	}
+
+	/* Execute command */
+	akoutw(akc->smpl, IDCSMPL);	/* must SMPL --> ADRS */
+	akoutw(akc->addr, IDCADRS);
+	akoutw(akc->leng, IDCLENG);
+	akoutw(akc->cmd, IDCMDST);
+
+	return 0;
+}
+
+/* IOCTL AKMODE_GET command */
+static int ak4524_mode_get(ak4524_t *ak)
+{
+	ak4524_mode_t *akm = &ak->mode;
+
+	akm->ipgl = ak->mode_save.ipgl;
+	akm->ipgr = ak->mode_save.ipgr;
+	akm->attl = ak->mode_save.attl;
+	akm->attr = ak->mode_save.attr;
+
+	Dprintk("ak4524_mode_get ipgl:0x%x ipgr:0x%x attl:0x%x attr:0x%x\n",
+		akm->ipgl, akm->ipgr, akm->attl, akm->attr);
+
+	return 0;
+}
+
+/* IOCTL AKMODE_SET command */
+static int ak4524_mode_set(ak4524_t *ak)
+{
+	ak4524_mode_t *akm = &ak->mode;
+
+	Dprintk("ak4524_mode_set ipgl:0x%x ipgr:0x%x attl:0x%x attr:0x%x\n",
+		akm->ipgl, akm->ipgr, akm->attl, akm->attr);
+
+	/* Condition check */
+	if (ak4524_status(ak) != AK_STATUS_READY) {
+		Dprintk("ak4524_mode_set: device busy\n");
+		return -EBUSY;
+	}
+
+	/* Argument check */
+	if (akm->ipgl > AK_IPG_MAX || akm->ipgr > AK_IPG_MAX) {
+		Dprintk("ak4524_mode_set: invalid argument ipgl:%d ipgr:%d\n",
+			akm->ipgl, akm->ipgr);
+		return -EINVAL;
+	}
+
+	if (akm->attl > AK_ATT_MAX || akm->attr > AK_ATT_MAX) {
+		Dprintk("ak4524_mode_set: invalid argument attl:%d attr:%d\n",
+			akm->attl, akm->attr);
+		return -EINVAL;
+	}
+
+	/* Set AK4524 registers */
+	akoutw(akm->ipgl << 8, AK4524_REG4);	/* Lch IPGA Control */
+	akoutw(akm->ipgr << 8, AK4524_REG5);	/* Rch IPGA Control */
+	akoutw(akm->attl << 8, AK4524_REG6);	/* Lch OATT Control */
+	akoutw(akm->attr << 8, AK4524_REG7);	/* Rch OATT Control */
+
+	ak->mode_save.ipgl = akm->ipgl;
+	ak->mode_save.ipgr = akm->ipgr;
+	ak->mode_save.attl = akm->attl;
+	ak->mode_save.attr = akm->attr;
+
+	return 0;
+}
+
+static void ak4524_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	ak4524_t *ak = (ak4524_t *)dev_id;
+
+	Dprintk("ak4524_interrupt: GET!\n");
+	if (ak4524_status(ak) == AK_STATUS_BUSY) {
+		Dprintk("ak4524_interrupt: ignore interrupt!\n");
+		return;
+	}
+}
+
+/*
+ * Driver method
+ */
+static loff_t ak4524_llseek(struct file *filp, loff_t offset, int orig)
+{
+	loff_t pos;
+
+	Dprintk("ak4524_llseek offset:0x%08x, orig:%d\n", (int)offset, orig);
+
+	switch (orig) {
+	case 0:		/* SEEK_SET */
+		pos = offset;
+		break;
+	case 1:		/* SEEK_CUR */
+		pos = filp->f_pos + offset;
+		break;
+	case 2:		/* SEEK_END */
+		pos = IDCSRAM_SIZE - IDCSRAM_ALIGN;
+		break;
+	default:
+		Dprintk("ak4524_llseek: invalid argument orig:%d\n", orig);
+		return -EINVAL;
+	}
+
+	if (pos % IDCSRAM_ALIGN) {
+		Dprintk("ak4524_llseek: invalid argument pos:%d\n", (int)pos);
+		return -EINVAL;
+	}
+
+	filp->f_pos = pos;
+
+	return pos;
+}
+
+static ssize_t ak4524_read(struct file *filp, char *buf, size_t count, 
+	loff_t *ppos)
+{
+	ak4524_t *ak = (ak4524_t *)filp->private_data;
+	off_t pos = *ppos;
+	size_t len = 0;
+
+	Dprintk("ak4524_read buf:0x%p, count:%d, ppos:0x%08x\n", buf, count, 
+		(unsigned int)pos);
+
+	/* Argument check */
+	if (count < 2 || pos >= IDCSRAM_SIZE)
+		return 0;
+
+	if (pos % IDCSRAM_ALIGN) {
+		Dprintk("ak4524_read: invalid argument pos:%d\n", (int)pos);
+		return -EINVAL;
+	}
+
+	count &= ~1UL;
+
+	/* Condition check */
+	if (filp->f_flags & O_NONBLOCK)
+		if (ak4524_status(ak) == AK_STATUS_BUSY)
+			return -EAGAIN;
+
+	while (ak4524_status(ak) != AK_STATUS_READY)
+		interruptible_sleep_on(&ak->wait);
+			if (signal_pending(current))
+				return -EINTR;
+
+	akoutw(BYTE2ADDR(pos), IDCADRS);
+
+#ifndef USE_ISRAM
+	while (count > len) {
+		unsigned short us;
+
+		if (pos + len + 2 > IDCSRAM_SIZE)
+			break;
+
+		us = akinw(IDCDATA);
+		if (copy_to_user(buf, &us, 2))
+			return -EFAULT;
+		buf += 2;
+		len += 2;
+	}
+#else	/* USE_ISRAM */
+	{
+		int i, loops;
+
+		len = count = MIN(count, IDCSRAM_SIZE - pos);
+		loops = count / IRAM_SIZE;
+
+		for (i = 0 ; i < loops ; i++) {
+			port_to_iram(IDCDATA);
+			if (copy_to_user(buf, (void *)IRAM_ADDR, IRAM_SIZE))
+				return -EFAULT;
+			count -= IRAM_SIZE;
+		}
+
+		if (count) {
+			akinsw(IDCDATA, (void *)IRAM_ADDR, count / 2);
+			if (copy_to_user(buf, (void *)IRAM_ADDR, count))
+				return -EFAULT;
+		}
+	}
+#endif	/* USE_ISRAM */
+
+	*ppos += len;
+
+	return len;
+}
+
+static ssize_t ak4524_write(struct file *filp, const char *buf, size_t count,
+	loff_t *ppos)
+{
+	ak4524_t *ak = (ak4524_t *)filp->private_data;
+	off_t pos = *ppos;
+	size_t len = 0;
+
+	Dprintk("ak4524_write buf:0x%p, count:%d, ppos:0x%08x\n", buf, count, 
+		(unsigned int)pos);
+
+	/* Argument check */
+	if (count < 2 || pos >= IDCSRAM_SIZE)
+		return 0;
+
+	if (pos % IDCSRAM_ALIGN) {
+		Dprintk("ak4524_write: invalid argument pos:%d\n", (int)pos);
+		return -EINVAL;
+	}
+
+	count &= ~1UL;
+
+	/* Condition check */
+	if (filp->f_flags & O_NONBLOCK)
+		if (ak4524_status(ak) == AK_STATUS_BUSY) 
+			return -EAGAIN;
+
+	while (ak4524_status(ak) != AK_STATUS_READY)
+		interruptible_sleep_on(&ak->wait);
+			if (signal_pending(current))
+				return -EINTR;
+
+	akoutw(BYTE2ADDR(pos), IDCADRS);
+
+#ifndef USE_ISRAM
+	while (count > len) {
+		unsigned short us;
+
+		if (pos + len + 2 > IDCSRAM_SIZE)
+			break;
+
+		if (copy_from_user(&us, buf, 2))
+			return -EFAULT;
+		akoutw(us, IDCDATA);
+		buf += 2;
+		len += 2;
+	}
+#else	/* USE_ISRAM */
+	{
+		unsigned long len;
+		int i, loops;
+
+		len = count = MIN(count, IDCSRAM_SIZE - pos);
+		loops = count / IRAM_SIZE;
+
+		for (i = 0 ; i < loops ; i++) {
+			if (copy_from_user((void *)IRAM_ADDR, buf, IRAM_SIZE))
+				return -EFAULT;
+			iram_to_port(IDCDATA);
+			count -= IRAM_SIZE;
+		}
+
+		if (count) {
+			if (copy_from_user((void *)IRAM_ADDR, buf, count))
+				return -EFAULT;
+			akoutsw(IDCDATA, (void *)IRAM_ADDR, count / 2);
+		}
+	}
+#endif	/* USE_ISRAM */
+
+	*ppos += len;
+
+	return len;
+}
+
+static unsigned int ak4524_poll(struct file *filp, poll_table *wait)
+{
+	ak4524_t *ak = (ak4524_t *)filp->private_data;
+
+	Dprintk("ak4524_poll\n");
+
+	poll_wait(filp, &ak->wait, wait);
+
+	if (ak4524_status(ak) == AK_STATUS_READY)
+		return POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM;
+
+	return 0;
+}
+
+static int ak4524_ioctl(struct inode *inode, struct file *filp,
+	unsigned int cmd, unsigned long arg)
+{
+	ak4524_t *ak = (ak4524_t *)filp->private_data;
+	int ret = 0;
+	int status;
+
+	Dprintk("ak4524_ioctl cmd:0x%08x\n", cmd);
+
+	/* Argument check */
+	if (_IOC_TYPE(cmd) != AK_IOCTL)
+		return -ENOTTY;
+
+	if (_IOC_NR(cmd) > AK_IOCTL_MAXNR)
+		return -ENOTTY;
+
+	switch (cmd) {
+	case AKRESET:
+		ak4524_reset(ak);
+		break;
+	case AKCMD:
+		if (copy_from_user(&ak->cmd, (void *)arg,
+			sizeof (ak4524_cmd_t)))
+			return -EFAULT;
+		ret = ak4524_cmd(ak);
+		break;
+	case AKMODE_GET:
+		ak4524_mode_get(ak);
+		if (copy_to_user((void *)arg, &ak->mode,
+			sizeof (ak4524_mode_t)))
+			return -EFAULT;
+		break;
+	case AKMODE_SET:
+		if (copy_from_user(&ak->mode, (void *)arg,
+			sizeof (ak4524_mode_t)))
+			return -EFAULT;
+		ret = ak4524_mode_set(ak);
+		break;
+	case AKSTATUS:
+		status = ak4524_status(ak);
+		if (copy_to_user((void *)arg, &status, sizeof (int)))
+			return -EFAULT;
+		break;
+	default:
+		Dprintk("ak4524_ioctl: invalid argument cmd:%d\n", cmd);
+		return -ENOTTY;
+	}
+
+	return ret;
+}
+
+static int ak4524_open(struct inode *inode, struct file *filp)
+{
+	ak4524_t *ak = &ak4524;
+
+	Dprintk("ak4524_open\n");
+
+	if (ak->use_count)
+		return -EBUSY;
+
+	ak->use_count++;
+	filp->private_data = ak;
+
+	return 0;
+}
+
+static int ak4524_release(struct inode *inode, struct file *filp)
+{
+	ak4524_t *ak = (ak4524_t *)filp->private_data;
+
+	Dprintk("ak4524_release\n");
+
+	ak->use_count--;
+	filp->private_data = NULL;
+
+	return 0;
+}
+
+static struct file_operations ak4524_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= ak4524_llseek,
+	.read		= ak4524_read,
+	.write		= ak4524_write,
+	.poll		= ak4524_poll,
+	.ioctl		= ak4524_ioctl,
+	.open		= ak4524_open,
+	.release	= ak4524_release,
+};
+
+/*
+ * Module init/exit function.
+ */
+static int __init idc_ak4524_init(void)
+{
+	ak4524_t *ak = &ak4524;
+	int ret = 0;
+
+	Dprintk("ak4524_init\n");
+
+	printk(KERN_INFO "idc_ak4524: uServer codec chip driver\n");
+
+	if ((ret = register_chrdev(AK_MAJOR, AK_NAME, &ak4524_fops)) < 0)
+		return ret;
+
+	memset(ak, 0, sizeof (ak4524_t));
+	init_waitqueue_head(&ak->wait);
+	if ((ret = request_irq(PLD_IRQ_SNDINT, ak4524_interrupt, SA_INTERRUPT,
+		AK_NAME, NULL)))
+		return ret;
+
+	ak4524_reset(ak);
+
+	return 0;
+}
+
+static void __exit idc_ak4524_exit(void)
+{
+	ak4524_t *ak = &ak4524;
+
+	Dprintk("ak4524_exit\n");
+
+	ak4524_reset(ak);
+	free_irq(PLD_IRQ_SNDINT, NULL);
+	unregister_chrdev(AK_MAJOR, AK_NAME);
+}
+
+module_init(idc_ak4524_init);
+module_exit(idc_ak4524_exit);
+EXPORT_NO_SYMBOLS;
+
+/* Module information */
+MODULE_AUTHOR("Hitoshi Yamamoto");
+MODULE_DESCRIPTION("uServer AK4524 driver");
+MODULE_LICENSE("GPL");
+
diff -ruN linux-2.4.26.org/arch/m32r/drivers/idc_parport.c linux-2.4.26/arch/m32r/drivers/idc_parport.c
--- linux-2.4.26.org/arch/m32r/drivers/idc_parport.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/arch/m32r/drivers/idc_parport.c	2003-12-17 10:10:26.000000000 +0900
@@ -0,0 +1,208 @@
+/*
+ * idc_parport.c
+ *  IDC-R (uServer) parallel port driver
+ *
+ * Copyright (c) 2003 Hitoshi Yamamoto
+ */
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/idc/idc_parport.h>
+
+#undef PL_DEBUG
+
+#undef Dprintk
+#ifdef PL_DEBUG
+#define Dprintk(x...)	do { printk(x); } while (0)
+#else	/* !PL_DEBUG */
+#define Dprintk(x...)	do { } while (0)
+#endif	/* !PL_DEBUG */
+
+#define PL_NAME		"idc_parport"
+#define PL_MAJOR	241
+#define PL_MINOR_OUT	0	/* Output only */
+#define PL_MINOR_IN	1	/* Input only */
+#define PL_MINOR_NUM	2
+
+/* I/O functions */
+
+#define parportinw(x)		inw((x))
+#define parportoutw(x, y)	outw((x), (y))
+
+typedef struct {
+	unsigned int val;
+	int mode;
+	struct semaphore sem;
+} parport_t;
+
+static parport_t parport[PL_MINOR_NUM];
+
+/*
+ * Driver method
+ */
+
+static unsigned int plout_calc(plout_t plout, unsigned int cmd,
+	unsigned int oldval)
+{
+	unsigned int val = 0;
+
+	switch (cmd) {
+	case PLOUT_SET:
+		val = (oldval & ~plout.mask) | (plout.val & plout.mask);
+		break;
+	case PLOUT_AND:
+		val = oldval & ((plout.val & plout.mask) | ~plout.mask);
+		break;
+	case PLOUT_OR:
+		val = oldval | (plout.val & plout.mask);
+		break;
+	case PLOUT_EXOR:
+		val = (oldval & ~plout.mask)
+			| ((oldval ^ plout.val) & plout.mask);
+		break;
+	}
+
+	return val;
+}
+
+static int parport_ioctl(struct inode *inode, struct file *filp,
+	unsigned int cmd, unsigned long arg)
+{
+	parport_t *pp = (parport_t *)filp->private_data;
+	unsigned int minor = MINOR(inode->i_rdev);
+	int ret = 0;
+	plout_t plout;
+	unsigned int val;
+
+	Dprintk("parport_ioctl cmd:0x%08x\n", cmd);
+
+	/* Argument check */
+	if (_IOC_TYPE(cmd) != PL_IOCTL)
+		return -ENOTTY;
+
+	if (_IOC_NR(cmd) > PL_IOCTL_MAXNR)
+		return -ENOTTY;
+
+	if (_IOC_DIR(cmd) & _IOC_WRITE) {
+		if (minor == PL_MINOR_IN)
+			return -EACCES;
+		if (copy_from_user(&plout, (void *)arg, sizeof (plout_t)))
+			return -EFAULT;
+	}
+
+	switch (cmd) {
+	case PLOUT_SET:
+	case PLOUT_AND:
+	case PLOUT_OR:
+	case PLOUT_EXOR:
+		val = plout_calc(plout, cmd, pp->val);
+		plout.val = val;
+		if (copy_to_user((void *)arg, &plout, sizeof (plout_t)))
+			return -EFAULT;
+		if (down_interruptible(&pp->sem))
+			return -ERESTARTSYS;
+		parportoutw(val, IDCPLOT);
+		pp->val = val;
+		up(&pp->sem);
+		break;
+	case PLIN:
+		if (minor == PL_MINOR_IN) {
+			if (down_interruptible(&pp->sem))
+				return -ERESTARTSYS;
+			val = (unsigned int)parportinw(IDCPLIN);
+			pp->val = val;
+			up(&pp->sem);
+		} else
+			val = pp->val;
+		if (copy_to_user((void *)arg, &val, sizeof (unsigned int)))
+			return -EFAULT;
+		break;
+	default:
+		Dprintk("parport_ioctl: invalid argument cmd:0x%08x\n", cmd);
+		return -ENOTTY;
+	}
+
+	return ret;
+}
+
+static int parport_open(struct inode *inode, struct file *filp)
+{
+	unsigned int minor = MINOR(inode->i_rdev);
+
+	Dprintk("parport_open\n");
+
+	if (minor >= PL_MINOR_NUM)
+		return -ENODEV;
+
+	filp->private_data = &parport[minor];
+
+	return 0;
+}
+
+static int parport_release(struct inode *inode, struct file *filp)
+{
+	Dprintk("parport_release\n");
+
+	filp->private_data = NULL;
+
+	return 0;
+}
+
+static struct file_operations parport_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.ioctl		= parport_ioctl,
+	.open		= parport_open,
+	.release	= parport_release,
+};
+
+/*
+ * Module init/exit function.
+ */
+static int __init idc_parport_init(void)
+{
+	int ret = 0;
+	int i;
+
+	Dprintk("parport_init\n");
+
+	printk(KERN_INFO "idc_parport: uServer parallel port driver\n");
+
+	if ((ret = register_chrdev(PL_MAJOR, PL_NAME, &parport_fops)) < 0)
+		return ret;
+
+	for (i = 0 ; i < PL_MINOR_NUM ; i++) {
+		memset(&parport[i], 0, sizeof (parport_t));
+		init_MUTEX(&parport[i].sem);
+	}
+
+	parport[PL_MINOR_OUT].mode = O_RDWR;	/* Output only */
+	parport[PL_MINOR_OUT].val = 0x0000;
+	parport[PL_MINOR_IN].mode = O_RDONLY;	/* Input only */
+	parport[PL_MINOR_IN].val = parportinw(IDCPLIN);
+
+	return 0;
+}
+
+static void __exit idc_parport_exit(void)
+{
+	Dprintk("parport_exit\n");
+
+	unregister_chrdev(PL_MAJOR, PL_NAME);
+}
+
+module_init(idc_parport_init);
+module_exit(idc_parport_exit);
+EXPORT_NO_SYMBOLS;
+
+/* Module information */
+MODULE_AUTHOR("Hitoshi Yamamoto");
+MODULE_DESCRIPTION("uServer parallel port driver");
+MODULE_LICENSE("GPL");
+
diff -ruN linux-2.4.26.org/arch/m32r/drivers/idc_pwrsrc.c linux-2.4.26/arch/m32r/drivers/idc_pwrsrc.c
--- linux-2.4.26.org/arch/m32r/drivers/idc_pwrsrc.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/arch/m32r/drivers/idc_pwrsrc.c	2003-12-17 10:10:26.000000000 +0900
@@ -0,0 +1,181 @@
+/*
+ * idc_pwrsrc.c
+ *  IDC-R (uServer) Power source check driver
+ *
+ * Copyright (c) 2003 Hitoshi Yamamoto
+ */
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/idc/idc_pwrsrc.h>
+
+#undef PS_DEBUG
+
+#undef Dprintk
+#ifdef PS_DEBUG
+#define Dprintk(x...)	do { printk(x); } while (0)
+#else	/* !PS_DEBUG */
+#define Dprintk(x...)	do { } while (0)
+#endif	/* !PS_DEBUG */
+
+#define PS_NAME		"idc_pwrsrc"
+#define PS_MAJOR	242
+#define PS_MASK		1
+
+/* I/O functions */
+
+#define psinw(x)	inw((x))
+#define psoutw(x, y)	outw((x), (y))
+
+typedef struct {
+	int use_count;
+} ps_t;
+
+static ps_t ps;
+
+/*
+ * Driver method
+ */
+
+static ssize_t ps_read(struct file *filp, char *buf, size_t count,
+	loff_t *ppos)
+{
+	char pwrsrc[2];
+
+	if (*ppos >= sizeof (pwrsrc))
+		return 0;
+
+	if (*ppos + count > sizeof (pwrsrc))
+		count = sizeof (pwrsrc) - *ppos;
+
+	if (!*ppos)
+		pwrsrc[0] = (psinw(IDCACIN) & PS_MASK) ? '1' : '0';
+
+	pwrsrc[1] = '\n';
+
+	if (copy_to_user(buf, &pwrsrc[*ppos], count))
+		return -EFAULT;
+
+	*ppos += count;
+
+	return count;
+}
+
+static int ps_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+	unsigned long arg)
+{
+	unsigned int val;
+
+	Dprintk("ps_ioctl cmd:0x%08x\n", cmd);
+
+	/* Argument check */
+	if (_IOC_TYPE(cmd) != PS_IOCTL)
+		return -ENOTTY;
+
+	if (_IOC_NR(cmd) > PS_IOCTL_MAXNR)
+		return -ENOTTY;
+
+	switch (cmd) {
+	case PSTATUS:
+		val = (unsigned int)psinw(IDCACIN) & PS_MASK;
+		if (copy_to_user((void *)arg, &val, sizeof (unsigned int)))
+			return -EFAULT;
+		break;
+	default:
+		Dprintk("ps_ioctl: invalid cmd cmd:0x%08x\n", cmd);
+		return -ENOTTY;
+	}
+
+	return 0;
+}
+
+static int ps_open(struct inode *inode, struct file *filp)
+{
+	Dprintk("ps_open\n");
+
+	ps.use_count++;
+	filp->private_data = &ps;
+
+	return 0;
+}
+
+static int ps_release(struct inode *inode, struct file *filp)
+{
+	ps_t *ps = (ps_t *)filp->private_data;
+
+	Dprintk("ps_release\n");
+
+	ps->use_count--;
+	filp->private_data = NULL;
+
+	return 0;
+}
+
+static struct file_operations ps_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.read		= ps_read,
+	.ioctl		= ps_ioctl,
+	.open		= ps_open,
+	.release	= ps_release,
+};
+
+#ifdef CONFIG_PROC_FS
+static struct proc_dir_entry *proc_root_ps;
+#endif	/* CONFIG_PROC_FS */
+
+/*
+ * Module init/exit function.
+ */
+
+static int __init idc_pwrsrc_init(void)
+{
+	int ret = 0;
+
+	Dprintk("ps_init\n");
+
+	printk(KERN_INFO "idc_pwrsrc: uServer power source driver\n");
+
+	if ((ret = register_chrdev(PS_MAJOR, PS_NAME, &ps_fops)) < 0)
+		return ret;
+
+	memset(&ps, 0, sizeof (ps_t));
+
+#ifdef CONFIG_PROC_FS
+	proc_root_ps = create_proc_entry("idc-pwrsrc", S_IRUGO, &proc_root);
+	if (proc_root_ps) {
+		proc_root_ps->owner = THIS_MODULE;
+		proc_root_ps->proc_fops = &ps_fops;
+	}
+#endif	/* CONFIG_PROC_FS */
+
+	return 0;
+}
+
+static void __exit idc_pwrsrc_exit(void)
+{
+	Dprintk("ps_exit\n");
+
+#ifdef CONFIG_PROC_FS
+	remove_proc_entry("idc-pwrsrc", &proc_root);
+#endif	/* CONFIG_PROC_FS */
+
+	unregister_chrdev(PS_MAJOR, PS_NAME);
+}
+
+module_init(idc_pwrsrc_init);
+module_exit(idc_pwrsrc_exit);
+EXPORT_NO_SYMBOLS;
+
+/* Module information */
+MODULE_AUTHOR("Hitoshi Yamamoto");
+MODULE_DESCRIPTION("uServer Power source check driver");
+MODULE_LICENSE("GPL");
+
diff -ruN linux-2.4.26.org/arch/m32r/drivers/m32700ut_mcu.c linux-2.4.26/arch/m32r/drivers/m32700ut_mcu.c
--- linux-2.4.26.org/arch/m32r/drivers/m32700ut_mcu.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/arch/m32r/drivers/m32700ut_mcu.c	2004-04-20 18:48:07.000000000 +0900
@@ -0,0 +1,177 @@
+/*
+ * m32700ut_mcu.c
+ *
+ * Copyright (C) 2004 Takeo Takahashi
+ *
+ * Simple I/O routines to communicate with battery control MCU(M16C),
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <asm/system.h>
+#include <asm/m32r.h>
+#include <asm/io.h>
+#include <asm/param.h>
+
+#undef M32700UT_MCU_DEBUG
+
+#ifdef M32700UT_MCU_DEBUG
+#define DPRINTK(s)	do { printk s; } while(0)
+#else
+#define DPRINTK(s)
+#endif
+
+#ifdef M32700UT_MCU_DEBUG
+void print_mcureg(void)
+{
+	printk("BATSIOCR = 0x%04x\n", inw_p(BATSIOCR));
+	printk("BATSIOMOD = 0x%04x\n", inw_p(BATSIOMOD));
+	printk("BATSIOSTS = 0x%04x\n", inw_p(BATSIOSTS));
+	printk("BATSIOINTCR = 0x%04x\n", inw_p(BATSIOINTCR));
+	printk("BATSIOBAUR = 0x%04x\n", inw_p(BATSIOBAUR));
+}
+#endif
+
+static void mcu_outb(unsigned char ch)
+{
+	/* wait for buffer empty */
+	while ((inw_p(BATSIOSTS) & BATSIOSTS_TEMP) == 0) ;
+	outw_p((unsigned short)ch, BATSIOTXB);
+	DPRINTK(("0x%02x ", ch));
+}
+
+static unsigned char mcu_inb(void)
+{
+	unsigned char ch;
+
+	/* wait for receive data ready */
+	while ((inw_p(BATSIOSTS) & BATSIOSTS_RXCP) == 0) ;
+	ch = (unsigned char)inw_p(BATSIORXB);
+	DPRINTK(("0x%02x ", ch));
+	return ch;
+}
+
+void mcu_in(unsigned char *buf, unsigned int len, unsigned short reg)
+{
+	unsigned char ch;
+	unsigned int i;
+	unsigned long flags;
+
+	DPRINTK(("mcu_in(0x%p, %d, 0x%04x): ", buf, len, reg));
+
+	if (len > 0xfff) {
+		printk("mcu_in: data length too long\n");
+		return;
+	}
+
+	save_flags(flags); cli();
+
+ 	/* start code */
+	mcu_outb(MCU_CMD_START);
+
+	/* function code */
+	if (len > 0xf) {
+		mcu_outb((unsigned char)(0x90 | len >> 8));
+		mcu_outb((unsigned char)len);
+	} else {
+		mcu_outb((unsigned char)(0x80 | len));
+	}
+
+	/* register address */
+	mcu_outb((unsigned char)(reg >> 8));
+	mcu_outb((unsigned char)reg);
+
+ 	/* ACK/NAK */
+	ch = mcu_inb();
+	if (ch == MCU_CMD_NAK) {
+		ch = mcu_inb();		/* error code */
+		printk("mcu_in: received NAK (%02x)\n", ch);
+		goto end_restore_flags;
+	}
+	if (ch != MCU_CMD_ACK) {
+		printk("mcu_in: received invalid ACK code(0x%02x)\n", ch);
+		goto end_restore_flags;
+	}
+	/* receive function code and register address */
+	for (i = ((len > 0xf)? 4:3); i > 0; i--) 
+		(void)mcu_inb();
+	for (i = 0; i < len; i++) {
+		*buf = mcu_inb();
+		buf++;
+	}
+end_restore_flags:
+	restore_flags(flags);
+	DPRINTK(("\n"));
+}
+
+void mcu_out(unsigned char *buf, unsigned int len, unsigned short reg)
+{
+	unsigned char ch;
+	unsigned int i;
+	unsigned long flags;
+
+	DPRINTK(("mcu_out(0x%p, %d, 0x%04x): ", buf, len, reg));
+
+	if (len > 0xfff) {
+		printk("mcu_out: data length too long\n");
+		return;
+	}
+
+	save_flags(flags); cli();
+
+ 	/* start code */
+	mcu_outb(MCU_CMD_START);
+
+ 	/* function code */
+	if (len > 0xf) {
+		mcu_outb((unsigned char)(0xd0 | len >> 8));
+		mcu_outb((unsigned char)len);
+	} else {
+		mcu_outb((unsigned char)(0xc0 | len));
+	}
+
+	/* register address */
+	mcu_outb((unsigned char)(reg >> 8));
+	mcu_outb((unsigned char)reg);
+
+	for (i = 0; i < len; i++) {
+		mcu_outb(*buf);
+		buf++;
+	}
+
+ 	/* ACK/NAK */
+	ch = mcu_inb();
+	if (ch == MCU_CMD_NAK) {
+		ch = mcu_inb();		/* error code */
+		printk("mcu_out: received NAK (%02x)\n", ch);
+		goto end_restore_flags;
+	}
+	if (ch != MCU_CMD_ACK) {
+		printk("mcu_out: received invalid ACK code(0x%02x)\n", ch);
+		goto end_restore_flags;
+	}
+	/* receive function code/register address/write data */
+	for (i = (((len > 0xf)? 4:3) + len); i > 0; i--)
+		(void)mcu_inb();
+end_restore_flags:
+	restore_flags(flags);
+	DPRINTK(("\n"));
+}
+
+void __init init_mcu_hw(void)
+{
+	printk("Initialize serial port for battery control MCU.\n");
+	outw_p(0, BATSIOCR);		/* disable */
+	outw_p(BATSIOMOD_CTSS, BATSIOMOD);
+	outw_p(0, BATSIOINTCR);		/* disable int. */
+	outw_p(0x125, BATSIOBAUR);	/* 38400bps */
+	outw_p(BATSIOCR_TXEN | BATSIOCR_RXEN, BATSIOCR);	/* enable */
+#if M32700UT_MCU_DEBUG
+	print_mcureg();
+#endif
+}
+
diff -ruN linux-2.4.26.org/arch/m32r/drivers/m32700ut_ts.c linux-2.4.26/arch/m32r/drivers/m32700ut_ts.c
--- linux-2.4.26.org/arch/m32r/drivers/m32700ut_ts.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/arch/m32r/drivers/m32700ut_ts.c	2004-04-20 18:48:07.000000000 +0900
@@ -0,0 +1,503 @@
+/*
+ * m32700ut_ts.c -- Touch screen driver for M32700UT
+ *
+ * Copyright (c) 2994 Takeo Takahashi
+ *
+ * Based on linux/drivers/char/ms77xxxx_ts.c
+ * Copyright (c) 2003 Lineo Solutions, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * Touch screen driver for M32700UT.
+ *
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/string.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/m32r.h>
+
+#define ts_in(buf, len, addr)	mcu_in((buf), (len), (addr))
+#define ts_out(buf, len, addr)	mcu_out((buf), (len), (addr))
+
+#undef TS_DEBUG
+#ifdef TS_DEBUG
+#define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+#define TS_NAME "ts"
+#define TS_MAJOR 253
+
+#define BUFSIZE 128
+
+#ifdef CONFIG_PM
+#include <linux/pm.h>
+static struct pm_dev* m32700ut_ts_pm_dev;
+#endif
+
+/* From Compaq's Touch Screen Specification version 0.2 (draft) */
+typedef struct {
+	short pressure;
+	short x;
+	short y;
+  	short millisecs;
+} TS_EVENT;
+
+static DECLARE_WAIT_QUEUE_HEAD(queue);
+static struct fasync_struct* fasync;
+static int raw_max_x, raw_max_y;
+static int res_x, res_y;
+static int raw_min_x, raw_min_y;
+static int cal_ok, x_rev, y_rev, xyswap;
+static int head = 0, tail = 0;
+static TS_EVENT cur_data, buf[BUFSIZE];
+static int ts_state = 0;
+static int ts_open_count;
+
+
+static struct fasync_struct* fasync;
+
+static void print_par(void)
+{
+	printk(KERN_INFO " Kernel ==> cal_ok = %d\n",cal_ok);
+	printk(KERN_INFO " Kernel ==> raw_max_x = %d\n",raw_max_x);
+	printk(KERN_INFO " Kernel ==> raw_max_y = %d\n",raw_max_y);
+	printk(KERN_INFO " Kernel ==> res_x = %d\n",res_x);
+	printk(KERN_INFO " Kernel ==> res_y = %d\n",res_y);
+	printk(KERN_INFO " Kernel ==> raw_min_x = %d\n",raw_min_x);
+	printk(KERN_INFO " Kernel ==> raw_min_y = %d\n",raw_min_y);
+	printk(KERN_INFO " Kernel ==> xyswap = %d\n",xyswap);
+	printk(KERN_INFO " Kernel ==> x_rev = %d\n",x_rev);
+	printk(KERN_INFO " Kernel ==> y_rev = %d\n",y_rev);
+}
+
+static void ts_clear(void)
+{
+	int i;
+
+	head = tail = 0;
+	for (i = 0; i < BUFSIZE; i++) {
+		buf[i].pressure = 0;
+		buf[i].x = 0;
+		buf[i].y = 0;
+		buf[i].millisecs = 0;
+	}
+}
+
+#if 0
+#define AVERAGE 3
+static int avg = 0;
+static int avx = 0;
+static int avy = 0;
+static int b_state = 0;
+#endif
+
+static void new_data(void)
+{
+#if 0
+	cur_data.x = 4000 - cur_data.x;
+	cur_data.y = 4000 - cur_data.y;
+
+	if (cur_data.pressure) {
+		b_state = 1;
+		avx += cur_data.x;
+		avy += cur_data.y;
+		avg++;
+		if (avg == AVERAGE) {
+			cur_data.x = avx / AVERAGE;
+			cur_data.y = avy / AVERAGE;
+			avx = 0;
+			avy = 0;
+			avg = 0;
+		}
+		else
+			return;
+	}
+	else {
+		if (b_state == 0)
+			return;
+		
+		b_state = 0;
+		avx = 0;
+		avy = 0;
+		avg = 0;
+	}
+
+	cur_data.millisecs = (short)jiffies;
+#endif
+	buf[head] = cur_data;
+
+	if (++head >= BUFSIZE) {
+		head = 0;
+	}
+	if ((head == tail) && (++tail >= BUFSIZE)) {
+	  	tail = 0;
+	}
+
+	if (fasync) {
+		kill_fasync(&fasync, SIGIO, POLL_IN); 
+	}
+	wake_up_interruptible(&queue);
+}
+
+static TS_EVENT get_data(void)
+{
+	int last = tail;
+
+	if (++tail == BUFSIZE) {
+		tail = 0;
+	}
+	return buf[last];
+}
+
+static void wait_for_action(void)
+{
+	unsigned char val = 0;
+	ts_out(&val, 1, MCU_TPLCR); /* TP stop */
+	ts_out(&val, 1, MCU_TPLSR); /* clear status */
+
+	ts_open_count = 0;
+}
+
+static void start_wait_for_action(void)
+{
+	unsigned char val;
+
+	//val = TPLSCR_100MS;
+	val = TPLSCR_20MS;
+	ts_out(&val, 1, MCU_TPLSCR); /* Sampling 100ms */
+	val = TPLCR_TP_STR | TPLCR_PEN_ONI
+			   | TPLCR_PEN_OFFI | TPLCR_PEN_ONRE;
+	ts_out(&val, 1, MCU_TPLCR); /* TP start, down IE, up IE */
+	val = 0;
+	ts_out(&val, 1, MCU_TPLSR); /* clear status */
+}
+
+static void stop_wait_for_action(void)
+{
+	unsigned char val = 0;
+	ts_out(&val, 1, MCU_TPLCR); /* TP stop */
+}
+
+static ssize_t m32700ut_ts_read(struct file* filp, char* buf, size_t count, loff_t* l)
+{
+	TS_EVENT t, out;
+	DECLARE_WAITQUEUE(wait, current);
+	int i;
+
+	if (head == tail) {
+		if (filp->f_flags & O_NONBLOCK)
+		  	return -EAGAIN;
+		add_wait_queue(&queue, &wait);
+		current->state = TASK_INTERRUPTIBLE;
+		while ((head == tail) && !signal_pending(current)) {
+			schedule();
+			current->state = TASK_INTERRUPTIBLE;
+		}
+		current->state = TASK_RUNNING;
+		remove_wait_queue(&queue, &wait);
+	}
+
+	for (i = count; i >= sizeof(out);
+		     i -= sizeof(out), buf += sizeof(out)) {
+		if (head == tail)
+		  	break;
+		t = get_data();
+		out.pressure = t.pressure;
+		if (cal_ok) {
+		  out.x = (x_rev) ?
+		    ((raw_max_x - t.x) * res_x) / (raw_max_x - raw_min_x) :
+		    ((t.x - raw_min_x) * res_x) / (raw_max_x - raw_min_x);
+		  out.y = (y_rev) ?
+		    ((raw_max_y - t.y) * res_y) / (raw_max_y - raw_min_y) :
+		    ((t.y - raw_min_y) * res_y) / (raw_max_y - raw_min_y);
+		}
+		else {
+			out.x = t.x;
+			out.y = t.y;
+		}
+		out.millisecs = t.millisecs;
+
+		copy_to_user(buf, &out, sizeof(out));
+	}
+	DPRINTK("read(0x%04d, 0x%04d)\n", out.x, out.y);
+
+	return count - i;
+}
+
+static unsigned int m32700ut_ts_poll(struct file* filp, poll_table* wait)
+{
+	poll_wait(filp, &queue, wait);
+	if (head != tail) {
+		return POLLIN | POLLRDNORM;
+	}
+	return 0;
+}
+
+static int m32700ut_ts_fasync(int fd, struct file* filp, int on)
+{
+	int ret = fasync_helper(fd, filp, on, &fasync);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+#if 0
+static ssize_t m32700ut_ts_write(struct file* filp, const char* buf, size_t count, loff_t* l)
+{
+	ssize_t rc = 0;
+
+	return rc;
+}
+#endif
+
+static int m32700ut_ts_ioctl(struct inode* inode, struct file* filp, unsigned int cmd, unsigned long arg)
+{
+	switch (cmd) {
+	case 3:
+	  	raw_max_x = arg;
+		break;
+	case 4:
+	  	raw_max_y = arg;
+		break;
+	case 5:
+	  	res_x = arg;
+		break;
+	case 6:
+	  	res_y = arg;
+		break;
+	case 10:
+	  	raw_min_x = arg;
+		break;
+	case 11:
+	  	raw_min_y = arg;
+		break;
+	case 12:
+		xyswap = arg;
+	case 13:
+	  	/* 0 = Enable calibration ; 1 = Calibration OK */
+	  	cal_ok = arg;
+	case 14:
+		ts_clear();
+		break;
+	case 15:
+		x_rev = arg;
+		break;
+	case 16:
+	  	y_rev = arg;
+		break;
+	case 17:
+		print_par();
+		break;
+	}
+	return 0;
+}
+
+static int m32700ut_ts_open(struct inode* inode, struct file* filp)
+{
+	if (!ts_open_count++)
+		start_wait_for_action();
+
+	ts_clear();
+
+	MOD_INC_USE_COUNT;
+
+	return 0;
+}
+
+static int m32700ut_ts_release(struct inode* inode, struct file* filp)
+{
+	if (!--ts_open_count)
+		stop_wait_for_action();
+
+	ts_clear();
+
+	m32700ut_ts_fasync(-1, filp, 0);
+
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+}
+
+static void m32700ut_ts_interrupt(int irq, void *ptr, struct pt_regs *regs)
+{
+	unsigned char rtkisr;
+	unsigned char tplsr;
+
+DPRINTK("m32700ut_ts_interrupt: ");
+	ts_in(&rtkisr, 1, MCU_RTKISR);
+#ifdef TS_DEBUG
+printk("0x%08x\n",rtkisr);
+#endif
+	if (!(rtkisr & RTKISR_TPIF))
+		return;
+	//rtkisr &= ~RTKISR_TPIF;
+
+	ts_in(&tplsr, 1, MCU_TPLSR);
+	/* FIXME:
+	 * clear an unknown spec bit in order to avoid iteration
+	 * of interrupt caused by unknown bit.
+	 */
+	tplsr &= ~0x08;
+	if (tplsr & TPLSR_PEN_ONIF) { /* PEN_ON */
+		tplsr &= ~TPLSR_PEN_ONIF;
+		cur_data.pressure = 1000;
+		ts_state = 1;
+		DPRINTK("Pen ON : ");
+	}
+	else if (tplsr & TPLSR_PEN_OFFIF) { /* PEN_OFF */
+		tplsr &= ~TPLSR_PEN_OFFIF;
+		cur_data.pressure = 0;
+		ts_state = 0;
+		DPRINTK("Pen OFF: ");
+	}
+	else {
+		printk("Pen ???: %02x\n", tplsr);
+		tplsr &= ~(TPLSR_PEN_ONIF | TPLSR_PEN_OFFIF);
+		goto update_status;
+	}
+
+	ts_in((unsigned char *)&cur_data.x, 2, MCU_XPAR);
+	ts_in((unsigned char *)&cur_data.y, 2, MCU_YPAR);
+	cur_data.x = be16_to_cpu(cur_data.x);
+	cur_data.y = be16_to_cpu(cur_data.y);
+#ifdef TS_DEBUG
+	printk("(0x%04x,0x%04x)\n",
+		(unsigned short)cur_data.x, (unsigned short)cur_data.y);
+#endif
+
+	cur_data.millisecs = (short)jiffies;
+
+	new_data();
+
+update_status:
+	ts_out(&tplsr, 1, MCU_TPLSR);
+	if (tplsr == 0) 
+		rtkisr &= ~RTKISR_TPIF;
+	ts_out(&rtkisr, 1, MCU_RTKISR);
+}
+
+static struct file_operations m32700ut_ts_fops = {
+	read:	 m32700ut_ts_read,
+	poll:	 m32700ut_ts_poll,
+	ioctl:	 m32700ut_ts_ioctl,
+	fasync:	 m32700ut_ts_fasync,
+	open:	 m32700ut_ts_open,
+	release: m32700ut_ts_release,
+};
+
+#ifdef CONFIG_PM
+static int m32700ut_ts_pm_callback(struct pm_dev* pm_dev,
+				 pm_request_t req, void* data)
+{
+	switch (req) {
+	case PM_SUSPEND:
+		break;
+	case PM_RESUME:
+		head = tail = 0;
+                break;
+	}
+	return 0;
+}
+#endif
+
+int __init m32700ut_ts_init(void)
+{
+	int rc;
+
+	wait_for_action();
+
+	rc = devfs_register_chrdev(TS_MAJOR, TS_NAME, &m32700ut_ts_fops);
+	if (rc < 0) {
+		printk(KERN_ERR "m32700ut_ts: failed to register char dev\n");
+		return rc;
+	}
+	devfs_register(NULL, TS_NAME, DEVFS_FL_NONE, TS_MAJOR, 0,
+		       0444 | S_IFCHR, &m32700ut_ts_fops, NULL);
+
+	if ((rc = request_irq(M32700UT_LCD_IRQ_BAT_INT, m32700ut_ts_interrupt,
+			   SA_SHIRQ, TS_NAME, m32700ut_ts_interrupt))) {
+		printk(KERN_ERR "m32700ut_ts: failed to register BAT_INT\n");
+		return rc;
+	}
+
+	raw_max_x = 4000;
+	raw_max_y = 4000;
+	raw_min_x = 200;
+	raw_min_y = 200;
+
+	res_x     = 240;
+	res_y     = 320;
+
+	head = 0;
+	tail = 0;
+	xyswap = 0;
+
+	cal_ok = 0;
+	x_rev = 0;
+	y_rev = 0;
+#if 1
+	/* default setting (should be fixed by calibration utility) */
+	raw_max_x = 0x076e;
+	raw_max_y = 0x0748;
+	raw_min_x = 0x00b2;
+	raw_min_y = 0x0074;
+	cal_ok = 1;
+	x_rev = 1;
+	y_rev = 1;
+#endif
+
+	ts_clear();
+	
+	init_waitqueue_head(&queue);
+	
+#ifdef CONFIG_PM
+	m32700ut_ts_pm_dev = pm_register(PM_SYS_DEV, 0,
+					 m32700ut_ts_pm_callback);
+#endif
+	// wait_for_action();
+
+	printk(KERN_INFO "M32700UT tocuh screen driver initialized.\n"); 
+	return 0;
+}
+
+#ifdef MODULE
+void __exit m32700ut_ts_cleanup(void)
+{
+#ifdef CONFIG_PM
+	pm_unregister_all(m32700ut_ts_pm_callback);
+#endif
+	free_irq(M32700UT_LCD_IRQ_BAT_INT, m32700ut_ts_interrupt);
+	//stop_wait_for_action();
+	devfs_unregister_chrdev(TS_MAJOR, TS_NAME);
+
+	printk(KERN_INFO "M32700UT touch screen driver removed.\n"); 
+}
+#endif
+
+module_init(m32700ut_ts_init);
+#ifdef MODULE
+module_exit(m32700ut_ts_cleanup);
+#endif
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Takeo Takahashi <takahashi.takeo@renesas.com>");
+MODULE_DESCRIPTION("Touch screen driver for M32700UT");
+
diff -ruN linux-2.4.26.org/arch/m32r/drivers/m32r-flash.c linux-2.4.26/arch/m32r/drivers/m32r-flash.c
--- linux-2.4.26.org/arch/m32r/drivers/m32r-flash.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/arch/m32r/drivers/m32r-flash.c	2003-12-17 10:10:26.000000000 +0900
@@ -0,0 +1,355 @@
+/*
+ * Flash memory access on M32R based devices
+ * 
+ * Copyright (C) 2003	Takeo Takahashi, Hitoshi Yamamoto
+ *			Takeshi Aoki
+ * 
+ * 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.
+ *
+ * $Id: m32r-flash.c,v 1.4 2003/12/17 01:10:26 hitoshiy Exp $
+ *
+ * 2003-06-13:  Support M3A-ZA36 (CONFIG_PLAT_MAPPI2) platform.
+ * 2003-09-02: 	Support uServer (CONFIG_PLAT_USVR) platform and Fujitsu
+ *	       	flash memory (MBM29DL640E).
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/m32r.h>
+#include <asm/io.h>
+
+#define WINDOW_ADDR (0xa0000000)	/* start of flash memory */
+
+static __u8 m32r_read8(struct map_info *map, unsigned long ofs)
+{
+	return readb(map->map_priv_1 + ofs);
+}
+
+static __u16 m32r_read16(struct map_info *map, unsigned long ofs)
+{
+	return readw(map->map_priv_1 + ofs);
+}
+
+static __u32 m32r_read32(struct map_info *map, unsigned long ofs)
+{
+	return readl(map->map_priv_1 + ofs);
+}
+
+static void m32r_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	memcpy(to, (void *)(map->map_priv_1 + from), len);
+}
+
+static void m32r_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+	writeb(d, map->map_priv_1 + adr);
+}
+
+static void m32r_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+	writew(d, map->map_priv_1 + adr);
+}
+
+static void m32r_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+	writel(d, map->map_priv_1 + adr);
+}
+
+static void m32r_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	memcpy((void *)(map->map_priv_1 + to), from, len);
+}
+
+static struct map_info m32r_map = {
+	name:		"M32R flash",
+	read8:		m32r_read8,
+	read16:		m32r_read16,
+	read32:		m32r_read32,
+	copy_from:	m32r_copy_from,
+	write8:		m32r_write8,
+	write16:	m32r_write16,
+	write32:	m32r_write32,
+	copy_to:	m32r_copy_to,
+
+	map_priv_1:	WINDOW_ADDR,
+	map_priv_2:	-1,
+};
+
+static int flash_write = 0;
+
+static int __init flash_write_setup(char *str)
+{
+	flash_write = 1;
+	printk("Flash ROM write enabled\n");
+	return 1;
+}
+
+__setup("flash_write", flash_write_setup);
+
+#if defined(CONFIG_PLAT_M32700UT_Alpha)
+#define M32700UT_FLASH_SIZE		0x00400000
+static struct mtd_partition m32700ut_partitions[] = {
+	{
+		name:		"M32700UT boot firmware",
+		size:		0x30000,		/* 192KB */
+		offset:		0,
+		mask_flags:	MTD_WRITEABLE,  	/* force read-only */
+	}, {
+		name:		"M32700UT kernel",
+		size:		0xd0000,		/* 832KB */
+		offset:		MTDPART_OFS_APPEND,
+	}, {
+		name:		"M32700UT root",
+		size:		0x2f0000,		/* 3008KB */
+		offset:		MTDPART_OFS_APPEND,
+	}, {
+		name:		"M32700UT params",
+		size:		MTDPART_SIZ_FULL,	/* 64KB */
+		offset:		MTDPART_OFS_APPEND,
+	}
+};
+#elif defined(CONFIG_PLAT_M32700UT)
+#define M32700UT_FLASH_SIZE		0x00800000
+static struct mtd_partition m32700ut_partitions[] = {
+	{
+		name:		"M32700UT boot firmware",
+		size:		0x30000,		/* 192KB */
+		offset:		0,
+		mask_flags:	MTD_WRITEABLE,  	/* force read-only */
+	}, {
+		name:		"M32700UT kernel",
+		size:		0xd0000,		/* 832KB */
+		offset:		MTDPART_OFS_APPEND,
+		mask_flags:	MTD_WRITEABLE,  	/* force read-only */
+	}, {
+		name:		"M32700UT root",
+		size:		0x6f0000,		/* 7104KB */
+		offset:		MTDPART_OFS_APPEND,
+	}, {
+		name:		"M32700UT params",
+		size:		MTDPART_SIZ_FULL,	/* 64KB */
+		offset:		MTDPART_OFS_APPEND,
+		mask_flags:	MTD_WRITEABLE,  	/* force read-only */
+	}
+};
+#elif defined(CONFIG_PLAT_MAPPI2)
+#define M32700UT_FLASH_SIZE		0x00400000
+static struct mtd_partition m32700ut_partitions[] = {
+	{
+		name:		"M3A-ZA36 boot firmware",
+		size:		0x30000,		/* 192KB */
+		offset:		0,
+		mask_flags:	MTD_WRITEABLE,  	/* force read-only */
+	}, {
+		name:		"M3A-ZA36 kernel",
+		size:		0xd0000,		/* 832KB */
+		offset:		MTDPART_OFS_APPEND,
+	}, {
+		name:		"M3A-ZA36 root",
+		size:		0x2f0000,		/* 3008KB */
+		offset:		MTDPART_OFS_APPEND,
+	}, {
+		name:		"M3A-ZA36 params",
+		size:		MTDPART_SIZ_FULL,	/* 64KB */
+		offset:		MTDPART_OFS_APPEND,
+	}
+};
+#elif defined(CONFIG_PLAT_USRV)
+#define USRV_FLASH_SIZE		0x00800000
+/* 
+ * chip : MBM29DL640E (Fujitsu)
+ *  phys addr : 0x00000000
+ *  size      : 0x00800000 (8MB)
+ *  0x00000000 - 0x0000ffff :  8KB sector :   64KB
+ *  0x00010000 - 0x007effff : 64KB sector : 8064KB
+ *  0x007f0000 - 0x007fffff :  8KB sector :   64KB
+ */
+
+static struct mtd_partition usrv_partitions[] = {
+	{
+		name:		"Boot loader",
+		size:		0xe000,			/* 56KB */
+		offset:		0,
+		.mask_flags	= MTD_WRITEABLE,	/* force read-only */
+	}, {
+		name:		"Kernel parameter",
+		size:		0x2000,			/* 8KB */
+		offset:		MTDPART_OFS_APPEND,
+	}, {
+		name:		"Kernel",
+		size:		0x200000,		/* 2MB */
+		offset:		MTDPART_OFS_APPEND,
+		.mask_flags	= MTD_WRITEABLE,	/* force read-only */
+	}, {
+		name:		"INITRD",
+		size:		0xe0000,		/* 896KB */
+		offset:		MTDPART_OFS_APPEND,
+		.mask_flags	= MTD_WRITEABLE,	/* force read-only */
+	}, {
+		name:		"User FS",
+		size:		0x500000,		/* 5MB */
+		offset:		MTDPART_OFS_APPEND,
+	}, {
+		name:		"User parameter",
+		size:		0x10000,		/* 64KB */
+		offset:		MTDPART_OFS_APPEND,
+	}
+};
+#else
+#error no platform configuration
+#endif
+
+extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts);
+extern int parse_bootldr_partitions(struct mtd_info *master, struct mtd_partition **pparts);
+
+static struct mtd_partition *parsed_parts;
+static struct mtd_info *mymtd;
+
+int __init m32r_mtd_init(void)
+{
+	struct mtd_partition *parts;
+	int nb_parts = 0, ret;
+	int parsed_nr_parts = 0;
+	const char *part_type;
+	unsigned long base = -1UL;
+	int i;
+
+
+	/* Default flash buswidth */
+	m32r_map.buswidth = 2;
+
+	/*
+	 * Static partition definition selection
+	 */
+	part_type = "static";
+
+#if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_M32700UT_Alpha)
+	parts = m32700ut_partitions;
+	nb_parts = ARRAY_SIZE(m32700ut_partitions);
+	m32r_map.size = M32700UT_FLASH_SIZE;
+	m32r_map.buswidth = 2;
+#endif
+#if defined(CONFIG_PLAT_MAPPI2)
+	parts = m32700ut_partitions;
+	nb_parts = ARRAY_SIZE(m32700ut_partitions);
+	m32r_map.size = M32700UT_FLASH_SIZE;
+	m32r_map.buswidth = 2;
+#endif
+#if defined(CONFIG_PLAT_USRV)
+	parts = usrv_partitions;
+	nb_parts = ARRAY_SIZE(usrv_partitions);
+	m32r_map.size = USRV_FLASH_SIZE;
+	m32r_map.buswidth = 2;
+#endif
+
+	if (flash_write)
+		for (i = 0 ; i < nb_parts ; i++)
+			parts[i].mask_flags = 0;
+
+	/*
+	 * For simple flash devices, use ioremap to map the flash.
+	 */
+	if (base != (unsigned long)-1) {
+		if (!request_mem_region(base, m32r_map.size, "flash"))
+			return -EBUSY;
+		m32r_map.map_priv_2 = base;
+		m32r_map.map_priv_1 = (unsigned long)
+				ioremap(base, m32r_map.size);
+		ret = -ENOMEM;
+		if (!m32r_map.map_priv_1)
+			goto out_err;
+	}
+
+	/*
+	 * Now let's probe for the actual flash.  Do it here since
+	 * specific machine settings might have been set above.
+	 */
+	printk(KERN_NOTICE "M32R flash: probing %d-bit flash bus\n", m32r_map.buswidth*8);
+#ifdef CONFIG_MTD_M5
+	mymtd = do_map_probe("m5drv", &m32r_map);
+#elif CONFIG_MTD_CFI
+	mymtd = do_map_probe("cfi_probe", &m32r_map);
+#else
+	mymtd = NULL;
+#endif
+	ret = -ENXIO;
+	if (!mymtd)
+		goto out_err;
+	mymtd->module = THIS_MODULE;
+
+	/*
+	 * Dynamic partition selection stuff (might override the static ones)
+	 */
+#ifdef CONFIG_MTD_REDBOOT_PARTS
+	if (parsed_nr_parts == 0) {
+		ret = parse_redboot_partitions(mymtd, &parsed_parts);
+
+		if (ret > 0) {
+			part_type = "RedBoot";
+			parsed_nr_parts = ret;
+		}
+	}
+#endif
+#ifdef CONFIG_MTD_BOOTLDR_PARTS
+	if (parsed_nr_parts == 0) {
+		ret = parse_bootldr_partitions(mymtd, &parsed_parts);
+		if (ret > 0) {
+			part_type = "Compaq bootldr";
+			parsed_nr_parts = ret;
+		}
+	}
+#endif
+
+	if (parsed_nr_parts > 0) {
+		parts = parsed_parts;
+		nb_parts = parsed_nr_parts;
+	}
+
+	if (nb_parts == 0) {
+		printk(KERN_NOTICE "M32R flash: no partition info available, registering whole flash at once\n");
+		add_mtd_device(mymtd);
+	} else {
+		printk(KERN_NOTICE "Using %s partition definition\n", part_type);
+		add_mtd_partitions(mymtd, parts, nb_parts);
+	}
+	return 0;
+
+ out_err:
+	if (m32r_map.map_priv_2 != -1) {
+		iounmap((void *)m32r_map.map_priv_1);
+		release_mem_region(m32r_map.map_priv_2, m32r_map.size);
+	}
+	return ret;
+}
+
+static void __exit m32r_mtd_cleanup(void)
+{
+	if (mymtd) {
+		del_mtd_partitions(mymtd);
+		map_destroy(mymtd);
+		if (parsed_parts)
+			kfree(parsed_parts);
+	}
+	if (m32r_map.map_priv_2 != -1) {
+		iounmap((void *)m32r_map.map_priv_1);
+		release_mem_region(m32r_map.map_priv_2, m32r_map.size);
+	}
+}
+
+module_init(m32r_mtd_init);
+module_exit(m32r_mtd_cleanup);
+
+MODULE_AUTHOR("Takeo Takahashi");
+MODULE_DESCRIPTION("M32R Flash map driver");
+MODULE_LICENSE("GPL");
diff -ruN linux-2.4.26.org/arch/m32r/drivers/m32r-pldsio.c linux-2.4.26/arch/m32r/drivers/m32r-pldsio.c
--- linux-2.4.26.org/arch/m32r/drivers/m32r-pldsio.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/arch/m32r/drivers/m32r-pldsio.c	2004-03-22 10:55:18.000000000 +0900
@@ -0,0 +1,3068 @@
+/* $Id: m32r-pldsio.c,v 1.4 2004/03/22 01:55:18 fujiwara Exp $
+ *
+ * M32R onboard PLD serial module support.
+ * 
+ * Much of the design and some of the code came from serial.c:
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *  Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997,
+ *              1998, 1999  Theodore Ts'o
+ *
+ * M32R work:
+ *  Copyright (C) 2000,2001  by Hiro Kondo, Hiro Takata, and Hitoshi Yamamoto.
+ *
+ *  2002-12-25: Support M32700UT Platform by Takeo Takahashi
+ *  		Derived from dbg_console.c.
+ */
+
+static char *serial_version = "kondo";
+static char *serial_revdate = "2002-09-11";
+static char *serial_name = "M32R Serial driver";
+
+#define LOCAL_VERSTRING ""
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/tty_driver.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+#include <linux/major.h>
+#include <linux/console.h>
+#include <linux/kdev_t.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/serial.h>
+#include <linux/serialP.h>  /* serial_state */
+#include <linux/slab.h>  /* kmalloc */
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/serial.h>
+#include <asm/m32r.h>
+
+extern struct console  console_for_debug;
+
+static int psio_write(struct tty_struct *tty, int from_user, 
+			const unsigned char *buf, int count);
+static int psio_write_room(struct tty_struct *tty);
+static int psio_chars_in_buffer(struct tty_struct *tty);
+
+static void dbg_console_write(struct console *, const char *, unsigned);
+static kdev_t dbg_console_device(struct console *c);
+//static void psio_interrupt_single(int, void *, struct pt_regs *);
+void psio_interrupt_single(int, void *, struct pt_regs *);
+static void psio_receive_chars(struct async_struct *, int *);
+
+static void psio_wait_until_sent(struct tty_struct *, int);
+static void change_speed(struct async_struct *,struct termios *);
+static void autoconfig(struct serial_state *);
+static unsigned detect_uart_irq (struct serial_state *);
+
+static struct tty_driver psio_driver;
+static int psio_refcount;
+
+#define RS_STROBE_TIME (10*HZ)
+#define RS_ISR_PASS_LIMIT 256
+
+/* number of characters left in xmit buffer before we ask for more */
+#define WAKEUP_CHARS 256
+
+static struct async_struct *IRQ_ports[NR_IRQS];
+static int IRQ_timeout[NR_IRQS];
+#ifdef CONFIG_SERIAL_CONSOLE
+static struct console cons;
+static int lsr_break_flag;
+#endif
+
+#define BAUDRATE 115200        /* Set Baudrate */
+
+/*
+ * Here we define the default xmit fifo size used for each type of
+ * UART
+ */
+static struct serial_uart_config uart_config[] = {
+	{ "unknown", 1, 0 },
+	{ "8250", 1, 0 },
+	{ "16450", 1, 0 },
+	{ "16550", 1, 0 },
+	{ "16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO },
+	{ "cirrus", 1, 0 },     /* usurped by cyclades.c */
+	{ "ST16650", 1, UART_CLEAR_FIFO | UART_STARTECH },
+	{ "ST16650V2", 32, UART_CLEAR_FIFO | UART_USE_FIFO |
+		UART_STARTECH },
+	{ "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO},
+	{ "Startech", 1, 0},    /* usurped by cyclades.c */
+	{ "16C950/954", 128, UART_CLEAR_FIFO | UART_USE_FIFO},
+	{ "ST16654", 64, UART_CLEAR_FIFO | UART_USE_FIFO |
+		UART_STARTECH },
+	{ "XR16850", 128, UART_CLEAR_FIFO | UART_USE_FIFO |
+		UART_STARTECH },
+	{ "RSA", 2048, UART_CLEAR_FIFO | UART_USE_FIFO },
+	{ "m32102", 1, 0 },
+	{ 0, 0}
+};
+
+static struct serial_state rs_table[RS_TABLE_SIZE] = {
+/*    UART CLK        PORT        IRQ   FLAGS        */ 
+      { 0,   BAUDRATE, ((int)PLD_ESIO0CR + NONCACHE_OFFSET), PLD_IRQ_SIO0_RCV,   STD_COM_FLAGS }, 
+};
+#define NR_PORTS    (sizeof(rs_table)/sizeof(struct serial_state))
+
+
+#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
+
+static DECLARE_TASK_QUEUE(tq_psio_serial);
+static struct tty_struct *psio_table[NR_PORTS];
+static struct termios *psio_termios[NR_PORTS];
+static struct termios *psio_termios_locked[NR_PORTS];
+
+#if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT)
+#define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \
+ kdevname(tty->device), (info->flags), serial_refcount,info->count,tty->count,s
+)
+#else
+#define DBG_CNT(s)
+#endif
+
+
+static struct timer_list serial_timer;
+
+static unsigned char *tmp_buf;
+#ifdef DECLARE_MUTEX
+static DECLARE_MUTEX(tmp_buf_sem);
+#else
+static struct semaphore tmp_buf_sem = MUTEX;
+#endif
+
+static int dbg_console_setup(struct console *console, char *options);
+
+#undef SIO0CR
+#undef SIO0MOD0
+#undef SIO0MOD1
+#undef SIO0STS
+#undef SIO0IMASK
+#undef SIO0BAUR
+#undef SIO0TXB
+#undef SIO0RXB
+#define SIO0CR     PLD_ESIO0CR
+#define SIO0MOD0   PLD_ESIO0MOD0
+#define SIO0MOD1   PLD_ESIO0MOD1
+#define SIO0STS    PLD_ESIO0STS
+#define SIO0IMASK  PLD_ESIO0INTCR
+#define SIO0BAUR   PLD_ESIO0BAUR
+#define SIO0TXB    PLD_ESIO0TXB
+#define SIO0RXB    PLD_ESIO0RXB
+
+#define SIO_IMASK_TEMPIE       (1UL<<1)  /* b14: enable */
+#define SIO_IMASK_RXCEN        (1UL<<2)  /* b13: enable */
+#define SIO_IMASK_REIE         (0UL)
+#define	SIO_SIO0STS_TEMP       (1UL<<0)  /* Transmitter Register Empty */
+#define	SIO_SIO0STS_TXCP       (1UL<<1)
+#define	SIO_SIO0STS_RXCP       (1UL<<2)
+#define	SIO_SIO0STS_OERR       (0UL)
+#define	SIO_SIO0STS_PERR       (0UL)
+#define	SIO_SIO0STS_FERR       (0UL)
+#define	SIO_SIO0MOD0_CTSS      (1UL<<6)
+#define	SIO_SIO0MOD0_RTSS      (1UL<<7)
+#define	SIO_NONE               (0UL)
+
+#define	UART_TX   	((unsigned char *)SIO0TXB - (unsigned char *)SIO0CR)
+#define	UART_RX         ((unsigned char *)SIO0RXB - (unsigned char *)SIO0CR)
+#define	UART_IER        ((unsigned char *)SIO0IMASK - (unsigned char *)SIO0CR)
+#define UART_IER_THRI   	SIO_IMASK_TEMPIE
+#define UART_IER_MSI    	SIO_NONE
+#define UART_IER_RLSI   	SIO_IMASK_RXCEN
+#define UART_IER_RDI    	SIO_IMASK_REIE
+#define	UART_LSR        ((unsigned char *)SIO0STS - (unsigned char *)SIO0CR)
+#define	UART_LSR_DR     	SIO_SIO0STS_RXCP
+#define	UART_LSR_THRE   	SIO_SIO0STS_TEMP
+#define	UART_LSR_TEMT   	SIO_SIO0STS_TXCP
+#define UART_EMPTY		(UART_LSR_TEMT | UART_LSR_THRE)
+#define	UART_LSR_BI     	SIO_NONE
+#define	UART_LSR_PE     	SIO_SIO0STS_PERR
+#define	UART_LSR_FE     	SIO_SIO0STS_FERR
+#define	UART_LSR_OE     	SIO_SIO0STS_OERR
+#define	UART_IIR	((unsigned char *)SIO0STS - (unsigned char *)SIO0CR)
+#define	UART_LCR        ((unsigned char *)SIO0CR - (unsigned char *)SIO0CR)
+#define	UART_LCR_SBC    	SIO_NONE
+#define	UART_LCR_PARITY 	SIO_NONE
+#define	UART_LCR_EPAR   	SIO_NONE
+#define	UART_LCR_SPAR   	SIO_NONE
+#define	UART_MCR        ((unsigned char *)SIO0MOD0 - (unsigned char *)SIO0CR)
+#define	UART_MCR_RTS    	SIO_SIO0MOD0_RTSS
+#define	UART_MCR_DTR    	SIO_NONE	/* SIO_SIO0MOD0_CTSS */
+#define	UART_MCR_LOOP   	SIO_NONE
+#define	UART_MCR_OUT1   	SIO_NONE
+#define	UART_MCR_OUT2   	SIO_NONE
+#define	UART_MSR        ((unsigned char *)SIO0MOD0 - (unsigned char *)SIO0CR)
+#define	UART_MSR_DCD           	SIO_NONE
+#define	UART_MSR_RI            	SIO_NONE
+#define	UART_MSR_DSR           	SIO_NONE
+#define	UART_MSR_CTS           	SIO_NONE
+
+#define	UART_BAUR       ((unsigned char *)SIO0BAUR - (unsigned char *)SIO0CR)
+#define	UART_MOD0   	((unsigned char *)SIO0MOD0 - (unsigned char *)SIO0CR)
+#define	UART_MOD1       ((unsigned char *)SIO0MOD1 - (unsigned char *)SIO0CR)
+
+static  inline unsigned int psio_in(struct async_struct *info,int offset)
+{
+	return *(volatile unsigned short *)(info->port + offset);
+}
+static inline void psio_out(struct async_struct *info,int offset,int value)
+{
+	*(volatile unsigned short *)(info->port + offset) = value;
+}
+
+#define serial_in(info, offset)            psio_in(info,(int)offset)
+#define serial_out(info, offset, value)    psio_out(info,(int)offset, value)
+#define serial_inp(info, offset)           psio_in(info,(int)offset)
+#define serial_outp(info, offset, value)   psio_out(info,(int)offset, value)
+
+
+static inline int serial_paranoia_check(struct async_struct *info,
+				        kdev_t device, const char *routine)
+{
+#ifdef SERIAL_PARANOIA_CHECK
+	static const char *badmagic =
+		"Warning: bad magic number for serial struct (%s) in %s\n";
+	static const char *badinfo =
+		"Warning: null async_struct for (%s) in %s\n";
+
+	if (!info) {
+		printk(badinfo, kdevname(device), routine);
+		return 1;
+	}
+	if (info->magic != SERIAL_MAGIC) {
+		printk(badmagic, kdevname(device), routine);
+		return 1;
+	}
+#endif
+	return 0;
+}
+
+/*
+ * ------------------------------------------------------------
+ * psio_stop() and psio_start()
+ *
+ * This routines are called before setting or resetting tty->stopped.
+ * They enable or disable transmitter interrupts, as necessary.
+ * ------------------------------------------------------------
+ */
+static void psio_stop(struct tty_struct *tty)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	unsigned long flags;
+
+	if (serial_paranoia_check(info, tty->device, "psio_stop"))
+		return;
+	
+	save_flags(flags); cli();
+	if (info->IER & UART_IER_THRI) {
+		info->IER &= ~UART_IER_THRI;
+		serial_out(info, UART_IER, info->IER);
+	}
+	restore_flags(flags);
+
+}
+
+static void psio_start(struct tty_struct *tty)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	unsigned long flags;
+	
+	if (serial_paranoia_check(info, tty->device, "psio_start"))
+		return;
+	
+	save_flags(flags); cli();
+	if (info->xmit.head != info->xmit.tail
+		&& info->xmit.buf
+		&& !(info->IER & UART_IER_THRI)) {
+		info->IER |= UART_IER_THRI;
+		serial_out(info, UART_IER, info->IER);
+		serial_out(info, UART_TX, info->xmit.buf[info->xmit.tail]);
+		info->xmit.tail = (info->xmit.tail + 1) & (SERIAL_XMIT_SIZE-1);
+		info->state->icount.tx++;
+	}
+	restore_flags(flags);
+}
+
+
+/*
+ * This routine is used by the interrupt handler to schedule
+ * processing in the software interrupt portion of the driver.
+ */
+static inline void psio_sched_event(struct async_struct *info,int event)
+{
+	info->event |= 1 << event;
+	queue_task(&info->tqueue, &tq_psio_serial);
+	mark_bh(SERIAL_BH);
+}
+
+static inline void psio_receive_chars(struct async_struct *info,int *status)
+{
+	struct tty_struct *tty = info->tty;
+	unsigned char ch;
+	struct  async_icount *icount;
+	int max_count = 256;
+
+	icount = &info->state->icount;
+	do {
+		if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+			tty->flip.tqueue.routine((void *) tty);
+			if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+				return;     // if TTY_DONT_FLIP is set
+		}
+		ch = serial_inp(info, UART_RX);
+		*tty->flip.char_buf_ptr = ch;
+		icount->rx++;
+	
+#ifdef SERIAL_DEBUG_INTR
+		printk("DR%02x:%02x...", ch, *status);
+#endif
+		*tty->flip.flag_buf_ptr = 0;
+		if (*status & (UART_LSR_BI | UART_LSR_PE |
+			       UART_LSR_FE | UART_LSR_OE)) {
+			/*
+			 * For statistics only
+			 */
+			if (*status & UART_LSR_BI) {
+				*status &= ~(UART_LSR_FE | UART_LSR_PE);
+				icount->brk++;
+				/*
+				 * We do the SysRQ and SAK checking
+				 * here because otherwise the break
+				 * may get masked by ignore_status_mask
+				 * or read_status_mask.
+				 */
+#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+				if (info->line == cons.index) {
+					if (!break_pressed) {
+						break_pressed = jiffies;
+						goto ignore_char;
+					}
+					break_pressed = 0;
+				}
+#endif
+			        if (info->flags & ASYNC_SAK)
+					do_SAK(tty);
+			} else if (*status & UART_LSR_PE)
+				icount->parity++;
+			else if (*status & UART_LSR_FE)
+				icount->frame++;
+			if (*status & UART_LSR_OE)
+				icount->overrun++;
+
+			/*
+			 * Mask off conditions which should be ignored.
+			 */
+			*status &= info->read_status_mask;
+
+#ifdef CONFIG_SERIAL_CONSOLE
+			if (info->line == cons.index) {
+				/* Recover the break flag from console xmit */
+				*status |= lsr_break_flag;
+				lsr_break_flag = 0;
+			}
+#endif
+			if (*status & (UART_LSR_BI)) {
+#ifdef SERIAL_DEBUG_INTR
+				printk("handling break....");
+#endif
+				*tty->flip.flag_buf_ptr = TTY_BREAK;
+			} else if (*status & UART_LSR_PE)
+				*tty->flip.flag_buf_ptr = TTY_PARITY;
+			else if (*status & UART_LSR_FE)
+				*tty->flip.flag_buf_ptr = TTY_FRAME;
+		}
+#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+		if (break_pressed && info->line == cons.index) {
+			if (ch != 0 &&
+				time_before(jiffies, break_pressed + HZ*5)) {
+				handle_sysrq(ch, regs, NULL, NULL);
+				break_pressed = 0;
+				goto ignore_char;
+			}
+			break_pressed = 0;
+		}
+#endif
+		if ((*status & info->ignore_status_mask) == 0) {
+			tty->flip.flag_buf_ptr++;
+			tty->flip.char_buf_ptr++;
+			tty->flip.count++;
+		}
+#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+	ignore_char:
+#endif
+		*status = serial_inp(info, UART_LSR);
+	} while ((*status & UART_LSR_DR) && (max_count-- > 0));
+#if (LINUX_VERSION_CODE > 131394) /* 2.1.66 */
+	tty_flip_buffer_push(tty);
+#else
+	queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
+#endif
+}
+
+static void transmit_chars(struct async_struct *info, int *intr_done)
+{
+	int count;
+
+	if (info->x_char) {
+		// for M32102 serial
+		// serial_outp(info, UART_TX, info->x_char);
+		info->state->icount.tx++;
+		info->x_char = 0;
+		if (intr_done)
+			*intr_done = 0;
+		while((serial_in(info,UART_LSR) & UART_LSR_TEMT) == 0);
+		return;
+	}
+	if (info->xmit.head == info->xmit.tail
+		|| info->tty->stopped
+		|| info->tty->hw_stopped) {
+		info->IER &= ~UART_IER_THRI;
+		serial_out(info, UART_IER, info->IER);
+		return;
+	}
+	count = info->xmit_fifo_size;
+	count = SERIAL_XMIT_SIZE-1;
+	do {
+		serial_out(info, UART_TX, info->xmit.buf[info->xmit.tail]);
+		info->xmit.tail = (info->xmit.tail + 1) & (SERIAL_XMIT_SIZE-1);
+		info->state->icount.tx++;
+
+		if (info->xmit.head == info->xmit.tail)
+			break;
+
+		while((serial_in(info,UART_LSR) & UART_LSR_THRE) == 0);
+	} while (--count > 0);
+	while((serial_in(info,UART_LSR) & UART_LSR_TEMT) == 0);
+
+	if (CIRC_CNT(info->xmit.head,
+			 info->xmit.tail,
+			 SERIAL_XMIT_SIZE) < WAKEUP_CHARS)
+		psio_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+
+#ifdef SERIAL_DEBUG_INTR
+	printk("THRE...");
+#endif
+	if (intr_done)
+		*intr_done = 0;
+
+	if (info->xmit.head == info->xmit.tail) {
+		info->IER &= ~UART_IER_THRI;
+		serial_out(info, UART_IER, info->IER);
+	}
+}
+
+
+/*
+
+#ifdef CONFIG_SERIAL_SHARE_IRQ
+static void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+#endif 
+*/
+
+static void sio_reset(struct async_struct *info)
+{
+	unsigned int dummy;
+	/* reset sio */
+	/* read receive buffer */
+	dummy = serial_inp(info, UART_RX);
+	dummy = serial_inp(info, UART_RX);
+	dummy = serial_inp(info, UART_LSR);
+	serial_outp(info, UART_LCR, 0x0300);	/* RSCLR:1, TSCLR:1 */
+	serial_outp(info, UART_LCR, 0x0003);	/* RSEN:1, TXEN:1 */
+}
+
+static void sio_error(struct async_struct *info,int status)
+{
+	unsigned int dummy;
+	/* reset sio */
+	printk("sio[%d] error[%04x]\n", info->line,status);
+	/* read receive buffer */
+	dummy = serial_inp(info, UART_RX);
+	dummy = serial_inp(info, UART_RX);
+	dummy = serial_inp(info, UART_LSR);
+	serial_outp(info, UART_LCR, 0x0300);	/* RSCLR:1, TSCLR:1 */
+	serial_outp(info, UART_LCR, 0x0003);	/* RSEN:1, TXEN:1 */
+}
+
+//static void psio_interrupt_single(int irq, void *dev_id, struct pt_regs * regs)
+void psio_interrupt_single(int irq, void *dev_id, struct pt_regs * regs)
+{
+	int status;
+	// int pass_counter = 0;
+	struct async_struct * info;
+
+#ifdef CONFIG_SERIAL_MULTIPORT
+	int first_multi = 0;
+	struct rs_multiport_struct *multi;
+#endif
+
+#ifdef SERIAL_DEBUG_INTR
+	printk("psio_interrupt_single(%d)...", irq);
+#endif
+	
+	info = IRQ_ports[irq&(~1)];
+	if (!info || !info->tty)
+		return;
+
+#ifdef CONFIG_SERIAL_MULTIPORT
+	multi = &rs_multiport[irq];
+	if (multi->port_monitor)
+		first_multi = inb(multi->port_monitor);
+#endif
+
+	{
+		status = serial_inp(info, UART_LSR);
+#ifdef SERIAL_DEBUG_INTR
+		printk("status = %x...", status);
+#endif
+		if (status & UART_LSR_DR){
+			psio_receive_chars(info, &status);
+		}
+		if ((serial_in(info,UART_LSR) & UART_EMPTY) != UART_EMPTY)
+			sio_error(info, status);
+		if (status & UART_LSR_THRE)
+			transmit_chars(info, 0);
+#ifdef SERIAL_DEBUG_INTR
+		printk("IIR = %x...", serial_in(info, UART_IIR));
+#endif
+	}
+
+	info->last_active = jiffies;
+#ifdef CONFIG_SERIAL_MULTIPORT
+	if (multi->port_monitor)
+			printk("rs port monitor (single) irq %d: 0x%x, 0x%x\n",
+			info->state->irq, first_multi,
+			inb(multi->port_monitor));
+#endif
+#ifdef SERIAL_DEBUG_INTR
+	printk("end.\n");
+#endif
+}
+#ifdef CONFIG_SERIAL_MULTIPORT
+static void rs_interrupt_multi(int irq, void *dev_id, struct pt_regs * regs)
+{}
+#endif
+
+static void do_psio_serial_bh(void)
+{
+	run_task_queue(&tq_psio_serial);
+}
+
+static void do_softint(void *private_)
+{
+	struct async_struct *info = (struct async_struct *) private_;
+	struct tty_struct *tty;
+	
+	tty = info->tty;
+	if (!tty)
+		return;
+
+	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
+		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+			tty->ldisc.write_wakeup)
+			(tty->ldisc.write_wakeup)(tty);
+		wake_up_interruptible(&tty->write_wait);
+#ifdef SERIAL_HAVE_POLL_WAIT
+		wake_up_interruptible(&tty->poll_wait);
+#endif
+	}
+}
+
+static void psio_timer(void)
+{
+	static unsigned long last_strobe = 0;
+	struct async_struct *info;
+	unsigned int  i;
+	unsigned long flags;
+
+	if ((jiffies - last_strobe) >= RS_STROBE_TIME) {
+		for (i=0; i < NR_IRQS; i++) {
+			info = IRQ_ports[i];
+			if (!info)
+				continue;
+			save_flags(flags); cli();
+			psio_interrupt_single(i, NULL, NULL);
+			restore_flags(flags);
+		}
+	}
+	last_strobe = jiffies;
+
+#if 1
+	mod_timer(&serial_timer, jiffies + 10);
+#else 
+	mod_timer(&serial_timer, jiffies + RS_STROBE_TIME);
+#endif
+
+	if (IRQ_ports[0]) {
+		save_flags(flags); cli();
+#ifdef CONFIG_SERIAL_SHARE_IRQ
+		psio_interrupt(0, NULL, NULL);
+#else
+		psio_interrupt_single(0, NULL, NULL);
+#endif
+		restore_flags(flags);
+
+		mod_timer(&serial_timer, jiffies + IRQ_timeout[0]);
+	}
+}
+
+/*
+ * ---------------------------------------------------------------
+ * Low level utility subroutines for the serial driver:  routines to
+ * figure out the appropriate timeout for an interrupt chain, routines
+ * to initialize and startup a serial port, and routines to shutdown a
+ * serial port.  Useful stuff like that.
+ * ---------------------------------------------------------------
+ */
+
+/*
+ * This routine figures out the correct timeout for a particular IRQ.
+ * It uses the smallest timeout of all of the serial ports in a
+ * particular interrupt chain.  Now only used for IRQ 0....
+ */
+static void figure_IRQ_timeout(int irq)
+{
+	struct  async_struct    *info;
+	int timeout = 60*HZ;    /* 60 seconds === a long time :-) */
+
+	info = IRQ_ports[irq];
+	if (!info) {
+		IRQ_timeout[irq] = 60*HZ;
+		return;
+	}
+	while (info) {
+		if (info->timeout < timeout)
+			timeout = info->timeout;
+		info = info->next_port;
+	}
+	if (!irq)
+		timeout = timeout / 2;
+	IRQ_timeout[irq] = timeout ? timeout : 1;
+}
+
+#ifdef CONFIG_SERIAL_RSA
+/* Attempts to turn on the RSA FIFO.  Returns zero on failure */
+static int enable_rsa(struct async_struct *info) {}
+
+/* Attempts to turn off the RSA FIFO.  Returns zero on failure */
+static int disable_rsa(struct async_struct *info) { }
+#endif /* CONFIG_SERIAL_RSA */
+
+static int startup(struct async_struct * info)
+{
+	unsigned long flags;
+	int retval=0;
+	void (*handler)(int, void *, struct pt_regs *);
+	struct serial_state *state= info->state;
+	unsigned long page;
+#ifdef CONFIG_SERIAL_MANY_PORTS
+	unsigned short ICP;
+#endif
+
+	page = get_zeroed_page(GFP_KERNEL);
+	if (!page)
+		return -ENOMEM;
+
+	save_flags(flags); cli();
+
+	if (info->flags & ASYNC_INITIALIZED) {
+		free_page(page);
+		goto errout;
+	}
+	if (info->xmit.buf)
+		free_page(page);
+	else
+		info->xmit.buf = (unsigned char *) page;
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("starting up ttyD%d (irq %d)...", info->line, state->irq);
+#endif
+
+	/*
+	 * Clear the FIFO buffers and disable them
+	 * (they will be reenabled in change_speed())
+	 */
+
+	/*
+	 * Clear the interrupt registers.
+	 */
+	sio_reset(info);
+
+	/*
+	 * Allocate the IRQ if necessary
+	 */
+	if (state->irq && (!IRQ_ports[state->irq] ||
+			   !IRQ_ports[state->irq]->next_port)) {
+		if (IRQ_ports[state->irq]) {
+#ifdef CONFIG_SERIAL_SHARE_IRQ
+			free_irq(state->irq, &IRQ_ports[state->irq]);
+			free_irq(state->irq+1, &IRQ_ports[state->irq]);
+#ifdef CONFIG_SERIAL_MULTIPORT
+			if (rs_multiport[state->irq].port1)
+				handler = rs_interrupt_multi;
+			else
+#endif
+				handler = psio_interrupt;
+#else
+			retval = -EBUSY;
+			goto errout;
+#endif /* CONFIG_SERIAL_SHARE_IRQ */
+		} else
+			handler = psio_interrupt_single;
+
+		/* 020116 */
+		retval = request_irq(state->irq, handler, SA_SHIRQ,
+			"serial_rx", &IRQ_ports[state->irq]);
+		retval = request_irq(state->irq+1, handler, SA_SHIRQ,
+			"serial_tx", &IRQ_ports[state->irq]);
+		if (retval) {
+			if (capable(CAP_SYS_ADMIN)) {
+				if (info->tty)
+					set_bit(TTY_IO_ERROR,
+						&info->tty->flags);
+				retval = 0;
+			}
+			goto errout;
+		}
+	}
+
+	/*
+	 * Insert serial port into IRQ chain.
+	 */
+	info->prev_port = 0;
+	info->next_port = IRQ_ports[state->irq];
+	if (info->next_port)
+		info->next_port->prev_port = info;
+	IRQ_ports[state->irq] = info;
+	figure_IRQ_timeout(state->irq);
+
+	/*
+	 * Now, initialize the UART
+	 */
+	/* for m32r @020113 */
+	sio_reset(info);
+
+	info->MCR = 0;
+	if (info->tty->termios->c_cflag & CBAUD)
+		info->MCR = UART_MCR_DTR | UART_MCR_RTS;
+#ifdef CONFIG_SERIAL_MANY_PORTS
+	if (info->flags & ASYNC_FOURPORT) {
+		if (state->irq == 0)
+			info->MCR |= UART_MCR_OUT1;
+	} else
+#endif
+	{
+		if (state->irq != 0)
+			info->MCR |= UART_MCR_OUT2;
+	}
+	info->MCR |= ALPHA_KLUDGE_MCR;      /* Don't ask */
+	serial_outp(info, UART_MCR, info->MCR);
+
+	/*
+	 * Finally, enable interrupts
+	 */
+	info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
+	serial_outp(info, UART_IER, info->IER); /* enable interrupts */
+
+#ifdef CONFIG_SERIAL_MANY_PORTS
+	if (info->flags & ASYNC_FOURPORT) {
+		/* Enable interrupts on the AST Fourport board */
+		ICP = (info->port & 0xFE0) | 0x01F;
+		outb_p(0x80, ICP);
+		(void) inb_p(ICP);
+	}
+#endif
+
+	/*
+	 * And clear the interrupt registers again for luck.
+	 */
+	(void)serial_inp(info, UART_LSR);
+	(void)serial_inp(info, UART_RX);
+	(void)serial_inp(info, UART_IIR);
+	(void)serial_inp(info, UART_MSR);
+
+	if (info->tty)
+		clear_bit(TTY_IO_ERROR, &info->tty->flags);
+	info->xmit.head = info->xmit.tail = 0;
+
+	/*
+	 * Set up serial timers...
+	 */
+	mod_timer(&serial_timer, jiffies + 2*HZ/100);
+
+	/*
+	 * Set up the tty->alt_speed kludge
+	 */
+#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
+	if (info->tty) {
+		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+			info->tty->alt_speed = 57600;
+		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+			info->tty->alt_speed = 115200;
+		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+			info->tty->alt_speed = 230400;
+		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+			info->tty->alt_speed = 460800;
+	}
+#endif
+
+	/*
+	 * and set the speed of the serial port
+	 */
+	change_speed(info, 0);
+
+	info->flags |= ASYNC_INITIALIZED;
+	restore_flags(flags);
+	return 0;
+
+errout:
+	restore_flags(flags);
+	return retval;
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ */
+static void shutdown(struct async_struct * info)
+{
+	unsigned long   flags;
+	struct serial_state *state;
+	int     retval;
+
+	if (!(info->flags & ASYNC_INITIALIZED))
+		return;
+
+	state = info->state;
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("Shutting down serial port %d (irq %d)....", info->line,
+		   state->irq);
+#endif
+
+	save_flags(flags); cli(); /* Disable interrupts */
+
+	/*
+	 * clear delta_msr_wait queue to avoid mem leaks: we may free the irq
+	 * here so the queue might never be waken up
+	 */
+	wake_up_interruptible(&info->delta_msr_wait);
+
+	/*
+	 * First unlink the serial port from the IRQ chain...
+	 */
+	if (info->next_port)
+		info->next_port->prev_port = info->prev_port;
+	if (info->prev_port)
+		info->prev_port->next_port = info->next_port;
+	else
+		IRQ_ports[state->irq] = info->next_port;
+	figure_IRQ_timeout(state->irq);
+
+	/*
+	 * Free the IRQ, if necessary
+	 */
+	if (state->irq && (!IRQ_ports[state->irq] ||
+			  !IRQ_ports[state->irq]->next_port)) {
+		if (IRQ_ports[state->irq]) {
+			/* 020116 */
+			free_irq(state->irq+1, &IRQ_ports[state->irq]);
+			retval = request_irq(state->irq+1, psio_interrupt_single,
+				         SA_SHIRQ, "serial_xx",
+				         &IRQ_ports[state->irq]);
+			free_irq(state->irq, &IRQ_ports[state->irq]);
+			retval = request_irq(state->irq, psio_interrupt_single,
+				         SA_SHIRQ, "serial",
+				         &IRQ_ports[state->irq]);
+
+			if (retval)
+				printk("serial shutdown: request_irq: error %d"
+				       "  Couldn't reacquire IRQ.\n", retval);
+		} else{
+			free_irq(state->irq, &IRQ_ports[state->irq]);
+			/* 020116 */
+			free_irq(state->irq+1, &IRQ_ports[state->irq]);
+		}
+	}
+	if (info->xmit.buf) {
+		unsigned long pg = (unsigned long) info->xmit.buf;
+		info->xmit.buf = 0;
+		free_page(pg);
+	}
+
+	info->IER = 0;
+	serial_outp(info, UART_IER, 0x00);  /* disable all intrs */
+#ifdef CONFIG_SERIAL_MANY_PORTS
+	if (info->flags & ASYNC_FOURPORT) {
+		/* reset interrupts on the AST Fourport board */
+		(void) inb((info->port & 0xFE0) | 0x01F);
+		info->MCR |= UART_MCR_OUT1;
+	} else
+#endif
+	if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
+		info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
+	serial_outp(info, UART_MCR, info->MCR);
+
+#ifdef CONFIG_SERIAL_RSA
+	/*
+	 * Reset the RSA board back to 115kbps compat mode.
+	 */
+	if ((state->type == PORT_RSA) &&
+		(state->baud_base == SERIAL_RSA_BAUD_BASE &&
+		 disable_rsa(info)))
+		state->baud_base = SERIAL_RSA_BAUD_BASE_LO;
+#endif
+
+
+	(void)serial_in(info, UART_RX);    /* read data port to reset things */
+
+	if (info->tty)
+		set_bit(TTY_IO_ERROR, &info->tty->flags);
+
+	sio_reset(info);
+
+	info->flags &= ~ASYNC_INITIALIZED;
+	restore_flags(flags);
+}
+
+static void change_speed(struct async_struct *info,struct termios *old_termios)
+{
+	int quot = 0, baud_base, baud;
+	unsigned cflag, cval = 0;
+	int bits;
+	unsigned long   flags;
+	unsigned mod0, mod1;
+
+	if (!info->tty || !info->tty->termios)
+		return;
+	cflag = info->tty->termios->c_cflag;
+	if (!CONFIGURED_SERIAL_PORT(info))
+		return;
+
+	/* byte size and parity */
+	switch (cflag & CSIZE) {
+		  case CS5: mod1 = 0x05; bits = 7; break;
+		  case CS6: mod1 = 0x06; bits = 8; break;
+		  case CS7: mod1 = 0x07; bits = 9; break;
+		  case CS8: mod1 = 0x08; bits = 10; break;
+		  /* Never happens, but GCC is too dumb to figure it out */
+		  default:  mod1 = 0x05; bits = 7; break;
+	}
+	mod1 <<= 8;
+	mod0 = 0;
+	if (cflag & CSTOPB) {
+		mod0 |= 0x03;
+		bits++;
+	}
+	if (cflag & PARENB) {
+		mod0 |= 0x10;
+		bits++;
+	}
+	if (!(cflag & PARODD)) {
+		mod0 |= 0x4;
+	}
+	mod0 = 0x80;	/* Use RTS# output only */
+
+	serial_outp(info, UART_MOD0, mod0);      /* */
+	//serial_outp(info, UART_MOD1, mod1); 
+	//mod1 = 0;
+	info->LCR = mod1;               /* Save LCR */
+
+	/* Determine divisor based on baud rate */
+	baud = tty_get_baud_rate(info->tty);
+	if (!baud)
+		baud = 9600;    /* B0 transition handled in rs_set_termios */
+#ifdef CONFIG_SERIAL_RSA
+	if ((info->state->type == PORT_RSA) &&
+		(info->state->baud_base != SERIAL_RSA_BAUD_BASE) &&
+		enable_rsa(info))
+		info->state->baud_base = SERIAL_RSA_BAUD_BASE;
+#endif
+	baud_base = info->state->baud_base;
+
+	if (baud == 38400 &&
+		((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))
+		quot = info->state->custom_divisor;
+	else {
+		if (baud == 134)
+			/* Special case since 134 is really 134.5 */
+			quot = (2*baud_base / 269);
+		else if (baud)
+			quot = baud_base / baud;
+	}
+	/* If the quotient is zero refuse the change */
+	if (!quot && old_termios) {
+		info->tty->termios->c_cflag &= ~CBAUD;
+		info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD);
+		baud = tty_get_baud_rate(info->tty);
+		if (!baud)
+			baud = 9600;
+		if (baud == 38400 &&
+			((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))
+			quot = info->state->custom_divisor;
+		else {
+			if (baud == 134)
+				/* Special case since 134 is really 134.5 */
+				quot = (2*baud_base / 269);
+			else if (baud)
+				quot = baud_base / baud ;
+		}
+	}
+	quot = baud_base / (baud*4) ;
+	/* As a last resort, if the quotient is zero, default to 9600 bps */
+	if (!quot)
+		quot = baud_base / 9600;
+	/*
+	 * Work around a bug in the Oxford Semiconductor 952 rev B
+	 * chip which causes it to seriously miscalculate baud rates
+	 * when DLL is 0.
+	 */
+	if (((quot & 0xFF) == 0) && (info->state->type == PORT_16C950) &&
+		(info->state->revision == 0x5201))
+		quot++;
+
+	info->quot = quot;
+	info->timeout = ((info->xmit_fifo_size*HZ*bits*quot) / baud_base);
+	info->timeout += HZ/50;     /* Add .02 seconds of slop */
+
+	/* CTS flow control flag and modem status interrupts */
+	info->IER &= ~UART_IER_MSI;
+	if (info->flags & ASYNC_HARDPPS_CD)
+		info->IER |= UART_IER_MSI;
+	if (cflag & CRTSCTS) {
+		info->flags |= ASYNC_CTS_FLOW;
+		info->IER |= UART_IER_MSI;
+	} else
+		info->flags &= ~ASYNC_CTS_FLOW;
+	if (cflag & CLOCAL)
+		info->flags &= ~ASYNC_CHECK_CD;
+	else {
+		info->flags |= ASYNC_CHECK_CD;
+		info->IER |= UART_IER_MSI;
+	}
+	serial_out(info, UART_IER, info->IER);
+
+	/*
+	 * Set up parity check flag
+	 */
+#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
+	info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
+	if (I_INPCK(info->tty))
+		info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
+	if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
+		info->read_status_mask |= UART_LSR_BI;
+
+	/*
+	 * Characters to ignore
+	 */
+	info->ignore_status_mask = 0;
+	if (I_IGNPAR(info->tty))
+		info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
+	if (I_IGNBRK(info->tty)) {
+		info->ignore_status_mask |= UART_LSR_BI;
+		/*
+		 * If we're ignore parity and break indicators, ignore
+		 * overruns too.  (For real raw support).
+		 */
+		if (I_IGNPAR(info->tty))
+			info->ignore_status_mask |= UART_LSR_OE;
+	}
+	/*
+	 * !!! ignore all characters if CREAD is not set
+	 */
+	if ((cflag & CREAD) == 0)
+		info->ignore_status_mask |= UART_LSR_DR;
+	cval = (baud_base / (baud * 4)) - 1;
+
+	save_flags(flags); cli();
+	serial_outp(info, UART_BAUR, cval );  /* set baurate reg */
+	serial_outp(info, UART_LCR, 0x03);
+	restore_flags(flags);
+}
+
+static void psio_put_char(struct tty_struct *tty, unsigned char ch)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	unsigned long flags;
+
+	if (serial_paranoia_check(info, tty->device, "psio_put_char"))
+		return;
+
+	if (!tty || !info->xmit.buf)
+		return;
+
+	save_flags(flags); cli();
+	if (CIRC_SPACE(info->xmit.head,
+			   info->xmit.tail,
+			   SERIAL_XMIT_SIZE) == 0) {
+		restore_flags(flags);
+		return;
+	}
+
+	info->xmit.buf[info->xmit.head] = ch;
+	info->xmit.head = (info->xmit.head + 1) & (SERIAL_XMIT_SIZE-1);
+	restore_flags(flags);
+}
+
+static void psio_flush_chars(struct tty_struct *tty)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	unsigned long flags;
+
+	if (serial_paranoia_check(info, tty->device, "psio_flush_chars"))
+		return;
+
+	save_flags(flags); cli();
+	if (info->xmit.head == info->xmit.tail
+		|| tty->stopped
+		|| tty->hw_stopped
+		|| !info->xmit.buf) {
+		restore_flags(flags); 
+ 		return;
+	}
+
+	if (!(info->IER & UART_IER_THRI)) {
+		info->IER |= UART_IER_THRI;
+		serial_out(info, UART_IER, info->IER);
+		serial_out(info, UART_TX, info->xmit.buf[info->xmit.tail]);
+		info->xmit.tail = (info->xmit.tail + 1) & (SERIAL_XMIT_SIZE-1);
+		info->state->icount.tx++;
+	}
+	restore_flags(flags);
+	while((serial_in(info,UART_LSR) & UART_EMPTY) != UART_EMPTY);
+}
+
+static int psio_write(struct tty_struct *tty, int from_user, 
+		    const unsigned char *buf, int count)
+{
+	int c, ret = 0;
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	unsigned long flags;
+		
+	if (serial_paranoia_check(info, tty->device, "psio_write"))
+		return 0;
+
+	if (!tty || !info->xmit.buf || !tmp_buf)
+		return 0;
+
+	save_flags(flags);
+	if (from_user) {
+		down(&tmp_buf_sem);
+		while (1) {
+			int c1;
+			c = CIRC_SPACE_TO_END(info->xmit.head,
+					info->xmit.tail,
+					SERIAL_XMIT_SIZE);
+			if (count < c)
+				c = count;
+			if (c <= 0)
+				break;
+
+			c -= copy_from_user(tmp_buf, buf, c);
+			if (!c) {
+				if (!ret)
+					ret = -EFAULT;
+				break;
+			}
+			cli();
+			c1 = CIRC_SPACE_TO_END(info->xmit.head,
+					info->xmit.tail,
+					SERIAL_XMIT_SIZE);
+			if (c1 < c)
+				c = c1;
+			memcpy(info->xmit.buf + info->xmit.head, tmp_buf, c);
+			info->xmit.head = ((info->xmit.head + c) &
+					(SERIAL_XMIT_SIZE-1));
+			restore_flags(flags);
+			buf += c;
+			count -= c;
+			ret += c;
+		}
+		up(&tmp_buf_sem);
+	} else {
+		cli();
+		while (1) {
+			c = CIRC_SPACE_TO_END(info->xmit.head,
+					info->xmit.tail,
+					SERIAL_XMIT_SIZE);
+			if (count < c)
+				c = count;
+			if (c <= 0) {
+				break;
+			}
+			memcpy(info->xmit.buf + info->xmit.head, buf, c);
+			info->xmit.head = ((info->xmit.head + c) &
+				 (SERIAL_XMIT_SIZE-1));
+			buf += c;
+			count -= c;
+			ret += c;
+		}
+		restore_flags(flags);
+	}
+	save_flags(flags); cli();
+	if (info->xmit.head != info->xmit.tail
+		&& !tty->stopped
+		&& !tty->hw_stopped
+		&& !(info->IER & UART_IER_THRI)) {
+		info->IER |= UART_IER_THRI;
+		serial_out(info, UART_IER, info->IER);
+		serial_out(info, UART_TX, info->xmit.buf[info->xmit.tail]);
+		info->xmit.tail = (info->xmit.tail + 1) & (SERIAL_XMIT_SIZE-1);
+		info->state->icount.tx++;
+	}
+	restore_flags(flags);
+	while((serial_in(info,UART_LSR) & UART_EMPTY) != UART_EMPTY);
+	return ret;
+}
+
+static int psio_write_room(struct tty_struct *tty)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+
+	if (serial_paranoia_check(info, tty->device, "psio_write_room"))
+		return 0;
+	return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
+}
+
+static int psio_chars_in_buffer(struct tty_struct *tty)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+		
+	if (serial_paranoia_check(info, tty->device, "psio_chars_in_buffer"))
+		return 0;
+	return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
+}
+
+static void psio_flush_buffer(struct tty_struct *tty)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	unsigned long flags;
+
+	if (serial_paranoia_check(info, tty->device, "psio_flush_buffer"))
+		return;
+	save_flags(flags); cli();
+	info->xmit.head = info->xmit.tail = 0;
+	restore_flags(flags);
+	wake_up_interruptible(&tty->write_wait);
+#ifdef SERIAL_HAVE_POLL_WAIT
+	wake_up_interruptible(&tty->poll_wait);
+#endif
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+			 tty->ldisc.write_wakeup)
+		(tty->ldisc.write_wakeup)(tty);
+}
+
+/*
+ * This function is used to send a high-priority XON/XOFF character to
+ * the device
+ */
+static void psio_send_xchar(struct tty_struct *tty, char ch)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+
+	if (serial_paranoia_check(info, tty->device, "psio_send_char"))
+		return;
+
+	info->x_char = ch;
+	if (ch) {
+		unsigned long flags;
+		save_flags(flags); cli();
+		if (!(info->IER & UART_IER_THRI)) {
+	   		info->IER |= UART_IER_THRI;
+			serial_out(info, UART_IER, info->IER);
+			serial_out(info, UART_TX, info->x_char);
+		}
+		restore_flags(flags);
+	}
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_throttle()
+ *
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled.
+ * ------------------------------------------------------------
+ */
+static void psio_throttle(struct tty_struct * tty)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	unsigned long flags;
+#ifdef SERIAL_DEBUG_THROTTLE
+	char    buf[64];
+
+	printk("throttle %s: %d....\n", tty_name(tty, buf),
+		tty->ldisc.chars_in_buffer(tty));
+#endif
+
+	if (serial_paranoia_check(info, tty->device, "psio_throttle"))
+		return;
+
+	if (I_IXOFF(tty))
+		psio_send_xchar(tty, STOP_CHAR(tty));
+
+	if (tty->termios->c_cflag & CRTSCTS)
+		info->MCR &= ~UART_MCR_RTS;
+
+	save_flags(flags); cli();
+	serial_out(info, UART_MCR, info->MCR);
+	restore_flags(flags);
+}
+
+static void psio_unthrottle(struct tty_struct * tty)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	unsigned long flags;
+#ifdef SERIAL_DEBUG_THROTTLE
+	char    buf[64];
+
+	printk("unthrottle %s: %d....\n", tty_name(tty, buf),
+		tty->ldisc.chars_in_buffer(tty));
+#endif
+
+	if (serial_paranoia_check(info, tty->device, "psio_unthrottle"))
+		return;
+
+	if (I_IXOFF(tty)) {
+		if (info->x_char) info->x_char = 0;
+	}
+	if (tty->termios->c_cflag & CRTSCTS)
+		info->MCR |= UART_MCR_RTS;
+	save_flags(flags); cli();
+	serial_out(info, UART_MCR, info->MCR);
+	restore_flags(flags);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_ioctl() and friends
+ * ------------------------------------------------------------
+ */
+
+static int get_serial_info(struct async_struct * info,
+			   struct serial_struct * retinfo)
+{
+	struct serial_struct tmp;
+	struct serial_state *state = info->state;
+
+	if (!retinfo)
+		return -EFAULT;
+	memset(&tmp, 0, sizeof(tmp));
+	tmp.type = state->type;
+	tmp.line = state->line;
+	tmp.port = state->port;
+	if (HIGH_BITS_OFFSET)
+		tmp.port_high = state->port >> HIGH_BITS_OFFSET;
+	else
+		tmp.port_high = 0;
+	tmp.irq = state->irq;
+	tmp.flags = state->flags;
+	tmp.xmit_fifo_size = state->xmit_fifo_size;
+	tmp.baud_base = state->baud_base;
+	tmp.close_delay = state->close_delay;
+	tmp.closing_wait = state->closing_wait;
+	tmp.custom_divisor = state->custom_divisor;
+	tmp.hub6 = state->hub6;
+	tmp.io_type = state->io_type;
+	if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
+		return -EFAULT;
+	return 0;
+}
+
+static int set_serial_info(struct async_struct * info,
+			   struct serial_struct * new_info)
+{
+	struct serial_struct new_serial;
+	struct serial_state old_state, *state;
+	unsigned int		i,change_irq,change_port;
+	int			retval = 0;
+	unsigned long		new_port;
+
+	if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
+		return -EFAULT;
+	state = info->state;
+	old_state = *state;
+
+	new_port = new_serial.port;
+	if (HIGH_BITS_OFFSET)
+		new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET;
+
+	change_irq = new_serial.irq != state->irq;
+	change_port = (new_port != ((int) state->port)) ||
+		(new_serial.hub6 != state->hub6);
+
+	if (!capable(CAP_SYS_ADMIN)) {
+		if (change_irq || change_port ||
+		    (new_serial.baud_base != state->baud_base) ||
+		    (new_serial.type != state->type) ||
+		    (new_serial.close_delay != state->close_delay) ||
+		    (new_serial.xmit_fifo_size != state->xmit_fifo_size) ||
+		    ((new_serial.flags & ~ASYNC_USR_MASK) !=
+		    (state->flags & ~ASYNC_USR_MASK)))
+			return -EPERM;
+		state->flags = ((state->flags & ~ASYNC_USR_MASK) |
+					(new_serial.flags & ASYNC_USR_MASK));
+		info->flags = ((info->flags & ~ASYNC_USR_MASK) |
+				   (new_serial.flags & ASYNC_USR_MASK));
+		state->custom_divisor = new_serial.custom_divisor;
+		goto check_and_exit;
+	}
+
+	new_serial.irq = irq_cannonicalize(new_serial.irq);
+
+	if ((new_serial.irq >= NR_IRQS) || (new_serial.irq < 0) ||
+	    (new_serial.baud_base < 9600)|| (new_serial.type < PORT_UNKNOWN) ||
+	    (new_serial.type > PORT_MAX) || (new_serial.type == PORT_CIRRUS) ||
+	    (new_serial.type == PORT_STARTECH)) {
+		return -EINVAL;
+	}
+
+	if ((new_serial.type != state->type) ||
+		(new_serial.xmit_fifo_size <= 0))
+		new_serial.xmit_fifo_size =
+			uart_config[new_serial.type].dfl_xmit_fifo_size;
+
+	/* Make sure address is not already in use */
+	if (new_serial.type) {
+		for (i = 0 ; i < NR_PORTS; i++)
+			if ((state != &rs_table[i]) &&
+			    (rs_table[i].port == new_port) &&
+			    rs_table[i].type)
+				return -EADDRINUSE;
+	}
+
+	if ((change_port || change_irq) && (state->count > 1))
+		return -EBUSY;
+
+	/*
+	 * OK, past this point, all the error checking has been done.
+	 * At this point, we start making changes.....
+	 */
+
+	state->baud_base = new_serial.baud_base;
+	state->flags = ((state->flags & ~ASYNC_FLAGS) |
+			(new_serial.flags & ASYNC_FLAGS));
+	info->flags = ((state->flags & ~ASYNC_INTERNAL_FLAGS) |
+			   (info->flags & ASYNC_INTERNAL_FLAGS));
+	state->custom_divisor = new_serial.custom_divisor;
+	state->close_delay = new_serial.close_delay * HZ/100;
+	state->closing_wait = new_serial.closing_wait * HZ/100;
+#if (LINUX_VERSION_CODE > 0x20100)
+	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+#endif
+	info->xmit_fifo_size = state->xmit_fifo_size =
+		new_serial.xmit_fifo_size;
+
+	if ((state->type != PORT_UNKNOWN) && state->port) {
+#ifdef CONFIG_SERIAL_RSA
+		if (old_state.type == PORT_RSA)
+			release_region(state->port + UART_RSA_BASE, 16);
+		else
+#endif
+		release_region(state->port,8);
+	}
+	state->type = new_serial.type;
+	if (change_port || change_irq) {
+		/*
+		 * We need to shutdown the serial port at the old
+		 * port/irq combination.
+		 */
+		shutdown(info);
+		state->irq = new_serial.irq;
+		info->port = state->port = new_port;
+		info->hub6 = state->hub6 = new_serial.hub6;
+		if (info->hub6)
+			info->io_type = state->io_type = SERIAL_IO_HUB6;
+		else if (info->io_type == SERIAL_IO_HUB6)
+			info->io_type = state->io_type = SERIAL_IO_PORT;
+	}
+	if ((state->type != PORT_UNKNOWN) && state->port) {
+#ifdef CONFIG_SERIAL_RSA
+		if (state->type == PORT_RSA)
+			request_region(state->port + UART_RSA_BASE,
+				       16, "serial_rsa(set)");
+		else
+#endif
+			request_region(state->port,8,"serial(set)");
+	}
+
+
+check_and_exit:
+	if (!state->port || !state->type)
+		return 0;
+	if (info->flags & ASYNC_INITIALIZED) {
+		if (((old_state.flags & ASYNC_SPD_MASK) !=
+			 (state->flags & ASYNC_SPD_MASK)) ||
+			(old_state.custom_divisor != state->custom_divisor)) {
+#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
+			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+				info->tty->alt_speed = 57600;
+			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+				info->tty->alt_speed = 115200;
+			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+				info->tty->alt_speed = 230400;
+			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+				info->tty->alt_speed = 460800;
+#endif
+			change_speed(info, 0);
+		}
+	} else
+		retval = startup(info);
+	return retval;
+}
+
+/*
+ * get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ *      is emptied.  On bus types like RS485, the transmitter must
+ *      release the bus after transmitting. This must be done when
+ *      the transmit shift register is empty, not be done when the
+ *      transmit holding register is empty.  This functionality
+ *      allows an RS485 driver to be written in user space.
+ */
+static int get_lsr_info(struct async_struct * info, unsigned int *value)
+{
+	unsigned char status;
+	unsigned int result;
+	unsigned long flags;
+
+	save_flags(flags); cli();
+	status = serial_in(info, UART_LSR);
+	restore_flags(flags);
+	result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
+
+	/*
+	 * If we're about to load something into the transmit
+	 * register, we'll pretend the transmitter isn't empty to
+	 * avoid a race condition (depending on when the transmit
+	 * interrupt happens).
+	 */
+	if (info->x_char ||
+		((CIRC_CNT(info->xmit.head, info->xmit.tail,
+			   SERIAL_XMIT_SIZE) > 0) &&
+		 !info->tty->stopped && !info->tty->hw_stopped))
+		result &= ~TIOCSER_TEMT;
+
+	if (copy_to_user(value, &result, sizeof(int)))
+		return -EFAULT;
+	return 0;
+}
+
+
+static int get_modem_info(struct async_struct * info, unsigned int *value)
+{
+	unsigned char control, status;
+	unsigned int result;
+	unsigned long flags;
+
+	control = info->MCR;
+	save_flags(flags); cli();
+	status = serial_in(info, UART_MSR);
+	restore_flags(flags);
+	result =  ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
+		| ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
+#ifdef TIOCM_OUT1
+		| ((control & UART_MCR_OUT1) ? TIOCM_OUT1 : 0)
+		| ((control & UART_MCR_OUT2) ? TIOCM_OUT2 : 0)
+#endif
+		| ((status  & UART_MSR_DCD) ? TIOCM_CAR : 0)
+		| ((status  & UART_MSR_RI) ? TIOCM_RNG : 0)
+		| ((status  & UART_MSR_DSR) ? TIOCM_DSR : 0)
+		| ((status  & UART_MSR_CTS) ? TIOCM_CTS : 0);
+
+	if (copy_to_user(value, &result, sizeof(int)))
+		return -EFAULT;
+	return 0;
+}
+static int set_modem_info(struct async_struct * info, unsigned int cmd,
+			  unsigned int *value)
+{
+	unsigned int arg;
+	unsigned long flags;
+
+	if (copy_from_user(&arg, value, sizeof(int)))
+		return -EFAULT;
+
+	switch (cmd) {
+	case TIOCMBIS:
+		if (arg & TIOCM_RTS)
+			info->MCR |= UART_MCR_RTS;
+		if (arg & TIOCM_DTR)
+			info->MCR |= UART_MCR_DTR;
+#ifdef TIOCM_OUT1
+		if (arg & TIOCM_OUT1)
+			info->MCR |= UART_MCR_OUT1;
+		if (arg & TIOCM_OUT2)
+			info->MCR |= UART_MCR_OUT2;
+#endif
+		if (arg & TIOCM_LOOP)
+			info->MCR |= UART_MCR_LOOP;
+		break;
+	case TIOCMBIC:
+		if (arg & TIOCM_RTS)
+			info->MCR &= ~UART_MCR_RTS;
+		if (arg & TIOCM_DTR)
+			info->MCR &= ~UART_MCR_DTR;
+#ifdef TIOCM_OUT1
+		if (arg & TIOCM_OUT1)
+			info->MCR &= ~UART_MCR_OUT1;
+		if (arg & TIOCM_OUT2)
+			info->MCR &= ~UART_MCR_OUT2;
+#endif
+		if (arg & TIOCM_LOOP)
+			info->MCR &= ~UART_MCR_LOOP;
+		break;
+	case TIOCMSET:
+		info->MCR = ((info->MCR & ~(UART_MCR_RTS |
+#ifdef TIOCM_OUT1
+				        UART_MCR_OUT1 |
+				        UART_MCR_OUT2 |
+#endif
+				        UART_MCR_LOOP |
+				        UART_MCR_DTR))
+				 | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0)
+#ifdef TIOCM_OUT1
+				 | ((arg & TIOCM_OUT1) ? UART_MCR_OUT1 : 0)
+				 | ((arg & TIOCM_OUT2) ? UART_MCR_OUT2 : 0)
+#endif
+				 | ((arg & TIOCM_LOOP) ? UART_MCR_LOOP : 0)
+				 | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));
+		break;
+	default:
+		return -EINVAL;
+	}
+	save_flags(flags); cli();
+	info->MCR |= ALPHA_KLUDGE_MCR;      /* Don't ask */
+	serial_out(info, UART_MCR, info->MCR);
+	restore_flags(flags);
+	return 0;
+}
+
+static int do_autoconfig(struct async_struct * info)
+{
+	int irq, retval;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	if (info->state->count > 1)
+		return -EBUSY;
+
+	shutdown(info);
+
+	autoconfig(info->state);
+	if ((info->state->flags & ASYNC_AUTO_IRQ) &&
+		(info->state->port != 0  || info->state->iomem_base != 0) &&
+		(info->state->type != PORT_UNKNOWN)) {
+		irq = detect_uart_irq(info->state);
+		if (irq > 0)
+			info->state->irq = irq;
+	}
+
+	retval = startup(info);
+	if (retval)
+		return retval;
+	return 0;
+}
+
+/*
+ * rs_break() --- routine which turns the break handling on or off
+ */
+#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
+static void send_break( struct async_struct * info, int duration)
+{
+	if (!CONFIGURED_SERIAL_PORT(info))
+		return;
+	current->state = TASK_INTERRUPTIBLE;
+	current->timeout = jiffies + duration;
+	cli();
+	info->LCR |= UART_LCR_SBC;
+	serial_out(info, UART_LCR, 0x3);
+	schedule();
+	info->LCR &= ~UART_LCR_SBC;
+	serial_out(info, UART_LCR, 0x3);
+	sti();
+}
+#else
+static void psio_break(struct tty_struct *tty, int break_state)
+{
+	struct async_struct * info = (struct async_struct *)tty->driver_data;
+	unsigned long flags;
+
+	if (serial_paranoia_check(info, tty->device, "rs_break"))
+		return;
+
+	if (!CONFIGURED_SERIAL_PORT(info))
+		return;
+	save_flags(flags); cli();
+	if (break_state == -1)
+		info->LCR |= UART_LCR_SBC;
+	else
+		info->LCR &= ~UART_LCR_SBC;
+	restore_flags(flags);
+}
+#endif
+
+#ifdef CONFIG_SERIAL_MULTIPORT
+static int get_multiport_struct(struct async_struct * info,
+				struct serial_multiport_struct *retinfo)
+{
+	struct serial_multiport_struct ret;
+	struct rs_multiport_struct *multi;
+
+	multi = &rs_multiport[info->state->irq];
+
+	ret.port_monitor = multi->port_monitor;
+
+	ret.port1 = multi->port1;
+	ret.mask1 = multi->mask1;
+	ret.match1 = multi->match1;
+
+	ret.port2 = multi->port2;
+	ret.mask2 = multi->mask2;
+	ret.match2 = multi->match2;
+
+	ret.port3 = multi->port3;
+	ret.mask3 = multi->mask3;
+	ret.match3 = multi->match3;
+
+	ret.port4 = multi->port4;
+	ret.mask4 = multi->mask4;
+	ret.match4 = multi->match4;
+
+	ret.irq = info->state->irq;
+
+	if (copy_to_user(retinfo,&ret,sizeof(*retinfo)))
+		return -EFAULT;
+	return 0;
+}
+
+static int set_multiport_struct(struct async_struct * info,
+				struct serial_multiport_struct *in_multi)
+{
+	struct serial_multiport_struct new_multi;
+	struct rs_multiport_struct *multi;
+	struct serial_state *state;
+	int was_multi, now_multi;
+	int retval;
+	void (*handler)(int, void *, struct pt_regs *);
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	state = info->state;
+
+	if (copy_from_user(&new_multi, in_multi,
+			   sizeof(struct serial_multiport_struct)))
+		return -EFAULT;
+
+	if (new_multi.irq != state->irq || state->irq == 0 ||
+		!IRQ_ports[state->irq])
+		return -EINVAL;
+
+	multi = &rs_multiport[state->irq];
+	was_multi = (multi->port1 != 0);
+
+	multi->port_monitor = new_multi.port_monitor;
+
+	if (multi->port1)
+		release_region(multi->port1,1);
+	multi->port1 = new_multi.port1;
+	multi->mask1 = new_multi.mask1;
+	multi->match1 = new_multi.match1;
+	if (multi->port1)
+		request_region(multi->port1,1,"serial(multiport1)");
+
+	if (multi->port2)
+		release_region(multi->port2,1);
+	multi->port2 = new_multi.port2;
+	multi->mask2 = new_multi.mask2;
+	multi->match2 = new_multi.match2;
+	if (multi->port2)
+		request_region(multi->port2,1,"serial(multiport2)");
+
+	if (multi->port3)
+		release_region(multi->port3,1);
+	multi->port3 = new_multi.port3;
+	multi->mask3 = new_multi.mask3;
+	multi->match3 = new_multi.match3;
+	if (multi->port3)
+		request_region(multi->port3,1,"serial(multiport3)");
+
+	if (multi->port4)
+		release_region(multi->port4,1);
+	multi->port4 = new_multi.port4;
+	multi->mask4 = new_multi.mask4;
+	multi->match4 = new_multi.match4;
+	if (multi->port4)
+		request_region(multi->port4,1,"serial(multiport4)");
+
+	now_multi = (multi->port1 != 0);
+
+	if (IRQ_ports[state->irq]->next_port &&
+		(was_multi != now_multi)) {
+		free_irq(state->irq, &IRQ_ports[state->irq]);
+		if (now_multi)
+			handler = rs_interrupt_multi;
+		else
+			handler = rs_interrupt;
+
+		retval = request_irq(state->irq, handler, SA_SHIRQ,
+				     "serial", &IRQ_ports[state->irq]);
+		if (retval) {
+			printk("Couldn't reallocate serial interrupt "
+				   "driver!!\n");
+		}
+	}
+	return 0;
+}
+#endif
+
+static int psio_ioctl(struct tty_struct *tty, struct file * file,
+		    unsigned int cmd, unsigned long arg)
+{
+	struct async_struct * info = (struct async_struct *)tty->driver_data;
+	struct async_icount cprev, cnow;    /* kernel counter temps */
+	struct serial_icounter_struct icount;
+	unsigned long flags;
+#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
+	int retval, tmp;
+#endif
+
+	if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
+		return -ENODEV;
+
+	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+		(cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
+		(cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
+		if (tty->flags & (1 << TTY_IO_ERROR))
+			return -EIO;
+	}
+
+	switch (cmd) {
+#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
+		case TCSBRK:    /* SVID version: non-zero arg --> no break */
+			retval = tty_check_change(tty);
+			if (retval)
+				return retval;
+			tty_wait_until_sent(tty, 0);
+			if (signal_pending(current))
+				return -EINTR;
+			if (!arg) {
+				send_break(info, HZ/4); /* 1/4 second */
+				if (signal_pending(current))
+				    return -EINTR;
+			}
+			return 0;
+		case TCSBRKP:   /* support for POSIX tcsendbreak() */
+			retval = tty_check_change(tty);
+			if (retval)
+				return retval;
+			tty_wait_until_sent(tty, 0);
+			if (signal_pending(current))
+				return -EINTR;
+			send_break(info, arg ? arg*(HZ/10) : HZ/4);
+			if (signal_pending(current))
+				return -EINTR;
+			return 0;
+		case TIOCGSOFTCAR:
+			tmp = C_CLOCAL(tty) ? 1 : 0;
+			if (copy_to_user((void *)arg, &tmp, sizeof(int)))
+				return -EFAULT;
+			return 0;
+		case TIOCSSOFTCAR:
+			if (copy_from_user(&tmp, (void *)arg, sizeof(int)))
+				return -EFAULT;
+
+			tty->termios->c_cflag =
+				((tty->termios->c_cflag & ~CLOCAL) |
+				 (tmp ? CLOCAL : 0));
+			return 0;
+#endif
+		case TIOCMGET:
+			return get_modem_info(info, (unsigned int *) arg);
+		case TIOCMBIS:
+		case TIOCMBIC:
+		case TIOCMSET:
+			return set_modem_info(info, cmd, (unsigned int *) arg);
+		case TIOCGSERIAL:
+			return get_serial_info(info,
+					       (struct serial_struct *) arg);
+		case TIOCSSERIAL:
+			return set_serial_info(info,
+				               (struct serial_struct *) arg);
+		case TIOCSERCONFIG:
+			return do_autoconfig(info);
+
+		case TIOCSERGETLSR: /* Get line status register */
+			return get_lsr_info(info, (unsigned int *) arg);
+
+		case TIOCSERGSTRUCT:
+			if (copy_to_user((struct async_struct *) arg,
+			    info, sizeof(struct async_struct)))
+				return -EFAULT;
+			return 0;
+
+#ifdef CONFIG_SERIAL_MULTIPORT
+		case TIOCSERGETMULTI:
+			return get_multiport_struct(info,
+				       (struct serial_multiport_struct *) arg);
+		case TIOCSERSETMULTI:
+			return set_multiport_struct(info,
+				       (struct serial_multiport_struct *) arg);
+#endif
+
+		/*
+		 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
+		 * - mask passed in arg for lines of interest
+		 *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
+		 * Caller should use TIOCGICOUNT to see which one it was
+		 */
+		case TIOCMIWAIT:
+			save_flags(flags); cli();
+			/* note the counters on entry */
+			cprev = info->state->icount;
+			restore_flags(flags);
+			/* Force modem status interrupts on */
+			info->IER |= UART_IER_MSI;
+			serial_out(info, UART_IER, info->IER);
+			while (1) {
+				interruptible_sleep_on(&info->delta_msr_wait);
+				/* see if a signal did it */
+				if (signal_pending(current))
+				    return -ERESTARTSYS;
+				save_flags(flags); cli();
+				cnow = info->state->icount; /* atomic copy */
+				restore_flags(flags);
+				if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
+				    cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
+				    return -EIO; /* no change => error */
+				if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
+				     ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
+				     ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
+				     ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
+				    return 0;
+				}
+				cprev = cnow;
+			}
+			/* NOTREACHED */
+
+		/*
+		 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
+		 * Return: write counters to the user passed counter struct
+		 * NB: both 1->0 and 0->1 transitions are counted except for
+		 *     RI where only 0->1 is counted.
+		 */
+		case TIOCGICOUNT:
+			save_flags(flags); cli();
+			cnow = info->state->icount;
+			restore_flags(flags);
+			icount.cts = cnow.cts;
+			icount.dsr = cnow.dsr;
+			icount.rng = cnow.rng;
+			icount.dcd = cnow.dcd;
+			icount.rx = cnow.rx;
+			icount.tx = cnow.tx;
+			icount.frame = cnow.frame;
+			icount.overrun = cnow.overrun;
+			icount.parity = cnow.parity;
+			icount.brk = cnow.brk;
+			icount.buf_overrun = cnow.buf_overrun;
+
+			if (copy_to_user((void *)arg, &icount, sizeof(icount)))
+				return -EFAULT;
+			return 0;
+		case TIOCSERGWILD:
+		case TIOCSERSWILD:
+			/* "setserial -W" is called in Debian boot */
+			printk ("TIOCSER?WILD ioctl obsolete, ignored.\n");
+			return 0;
+
+		default:
+			return -ENOIOCTLCMD;
+		}
+	return 0;
+}
+
+static void psio_set_termios(struct tty_struct *tty, struct termios *old_termios)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	unsigned long flags;
+	unsigned int cflag = tty->termios->c_cflag;
+
+	if (   (cflag == old_termios->c_cflag)
+		&& (   RELEVANT_IFLAG(tty->termios->c_iflag)
+		== RELEVANT_IFLAG(old_termios->c_iflag)))
+	  return;
+
+	change_speed(info, old_termios);
+
+	/* Handle transition to B0 status */
+	if ((old_termios->c_cflag & CBAUD) &&
+		!(cflag & CBAUD)) {
+		info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
+		save_flags(flags); cli();
+		serial_out(info, UART_MCR, info->MCR);
+		restore_flags(flags);
+	}
+
+	/* Handle transition away from B0 status */
+	if (!(old_termios->c_cflag & CBAUD) &&
+		(cflag & CBAUD)) {
+		info->MCR |= UART_MCR_DTR;
+		if (!(tty->termios->c_cflag & CRTSCTS) ||
+			!test_bit(TTY_THROTTLED, &tty->flags)) {
+			info->MCR |= UART_MCR_RTS;
+		}
+		save_flags(flags); cli();
+		serial_out(info, UART_MCR, info->MCR);
+		restore_flags(flags);
+	}
+
+	/* Handle turning off CRTSCTS */
+	if ((old_termios->c_cflag & CRTSCTS) &&
+		!(tty->termios->c_cflag & CRTSCTS)) {
+		tty->hw_stopped = 0;
+		psio_start(tty);
+	}
+}
+
+/*
+ * -----------------------------------------------------------
+ * psio_close()
+ *
+ * This routine is called when the debug console port gets closed.  
+ * First, we wait for the last remaining data to be sent.  Then, we unlink 
+ * its async structure from the interrupt chain if necessary, and we free
+ * that IRQ if nothing is left in the chain.
+ * -----------------------------------------------------------
+ */
+static void psio_close(struct tty_struct *tty, struct file *filp)
+{
+	struct async_struct * info = (struct async_struct *)tty->driver_data;
+	struct serial_state *state;
+	unsigned long flags;
+
+	if (!info || serial_paranoia_check(info, tty->device, "rs_close"))
+		return;
+
+	state = info->state;
+
+	save_flags(flags); cli();
+
+	if (tty_hung_up_p(filp)) {
+		DBG_CNT("before DEC-hung");
+		MOD_DEC_USE_COUNT;
+		restore_flags(flags);
+		return;
+	}
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("psio_close ttyD%d, count = %d\n", info->line, state->count);
+#endif
+	if ((tty->count == 1) && (state->count != 1)) {
+		/*
+		 * Uh, oh.  tty->count is 1, which means that the tty
+		 * structure will be freed.  state->count should always
+		 * be one in these conditions.  If it's greater than
+		 * one, we've got real problems, since it means the
+		 * serial port won't be shutdown.
+		 */
+		printk("rs_close: bad serial port count; tty->count is 1, "
+			   "state->count is %d\n", state->count);
+		state->count = 1;
+	}
+	if (--state->count < 0) {
+		printk("psio_close: bad serial port count for ttyD%d: %d\n",
+			   info->line, state->count);
+		state->count = 0;
+	}
+	if (state->count) {
+		DBG_CNT("before DEC-2");
+		MOD_DEC_USE_COUNT;
+		restore_flags(flags);
+		return;
+	}
+	info->flags |= ASYNC_CLOSING;
+	restore_flags(flags);
+	/*
+	 * Save the termios structure, since this port may have
+	 * separate termios for callout and dialin.
+	 */
+	if (info->flags & ASYNC_NORMAL_ACTIVE)
+		info->state->normal_termios = *tty->termios;
+	if (info->flags & ASYNC_CALLOUT_ACTIVE)
+		info->state->callout_termios = *tty->termios;
+	/*
+	 * Now we wait for the transmit buffer to clear; and we notify
+	 * the line discipline to only process XON/XOFF characters.
+	 */
+	tty->closing = 1;
+	if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+		tty_wait_until_sent(tty, info->closing_wait);
+	/*
+	 * At this point we stop accepting input.  To do this, we
+	 * disable the receive line status interrupts, and tell the
+	 * interrupt driver to stop checking the data ready bit in the
+	 * line status register.
+	 */
+	info->IER &= ~UART_IER_RLSI;
+	info->read_status_mask &= ~UART_LSR_DR;
+	if (info->flags & ASYNC_INITIALIZED) {
+		serial_out(info, UART_IER, info->IER);
+		/*
+		 * Before we drop DTR, make sure the UART transmitter
+		 * has completely drained; this is especially
+		 * important if there is a transmit FIFO!
+		 */
+		psio_wait_until_sent(tty, info->timeout);
+	}
+	shutdown(info);
+	if (tty->driver.flush_buffer)
+		tty->driver.flush_buffer(tty);
+	if (tty->ldisc.flush_buffer)
+		tty->ldisc.flush_buffer(tty);
+	tty->closing = 0;
+	info->event = 0;
+	info->tty = 0;
+	if (info->blocked_open) {
+		if (info->close_delay) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(info->close_delay);
+		}
+		wake_up_interruptible(&info->open_wait);
+	}
+	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
+			 ASYNC_CLOSING);
+	wake_up_interruptible(&info->close_wait);
+	MOD_DEC_USE_COUNT;
+}
+
+/*
+ * rs_wait_until_sent() --- wait until the transmitter is empty
+ */
+static void psio_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+	struct async_struct * info = (struct async_struct *)tty->driver_data;
+	unsigned long orig_jiffies, char_time;
+	int lsr;
+
+	if (serial_paranoia_check(info, tty->device, "psio_wait_until_sent"))
+		return;
+
+	if (info->state->type == PORT_UNKNOWN)
+		return;
+
+	if (info->xmit_fifo_size == 0)
+		return; /* Just in case.... */
+
+	orig_jiffies = jiffies;
+	/*
+	 * Set the check interval to be 1/5 of the estimated time to
+	 * send a single character, and make it at least 1.  The check
+	 * interval should also be less than the timeout.
+	 *
+	 * Note: we have to use pretty tight timings here to satisfy
+	 * the NIST-PCTS.
+	 */
+	char_time = (info->timeout - HZ/50) / info->xmit_fifo_size;
+	char_time = char_time / 5;
+	if (char_time == 0)
+		char_time = 1;
+	if (timeout && timeout < char_time)
+		char_time = timeout;
+	/*
+	 * If the transmitter hasn't cleared in twice the approximate
+	 * amount of time to send the entire FIFO, it probably won't
+	 * ever clear.  This assumes the UART isn't doing flow
+	 * control, which is currently the case.  Hence, if it ever
+	 * takes longer than info->timeout, this is probably due to a
+	 * UART bug of some kind.  So, we clamp the timeout parameter at
+	 * 2*info->timeout.
+	 */
+	if (!timeout || timeout > 2*info->timeout)
+		timeout = 2*info->timeout;
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+	printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time);
+	printk("jiff=%lu...", jiffies);
+#endif
+	while (!((lsr = serial_inp(info, UART_LSR)) & UART_LSR_TEMT)) {
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+		printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
+#endif
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(char_time);
+		if (signal_pending(current))
+			break;
+		if (timeout && time_after(jiffies, orig_jiffies + timeout))
+			break;
+	}
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+	printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
+#endif
+}
+
+/*
+ * psio_hangup() --- called by tty_hangup() when a hangup is signaled.
+ */
+static void psio_hangup(struct tty_struct *tty)
+{
+	struct async_struct * info = (struct async_struct *)tty->driver_data;
+	struct serial_state *state = info->state;
+
+	if (serial_paranoia_check(info, tty->device, "psio_hangup"))
+		return;
+
+	state = info->state;
+
+	psio_flush_buffer(tty);
+	if (info->flags & ASYNC_CLOSING)
+		return;
+	shutdown(info);
+	info->event = 0;
+	state->count = 0;
+	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+	info->tty = 0;
+	wake_up_interruptible(&info->open_wait);
+}
+
+
+
+/*
+static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
+static void rs_hangup(struct tty_struct *tty)
+*/
+
+/*
+ * ------------------------------------------------------------
+ * psio_open() and friends
+ * ------------------------------------------------------------
+ */
+#define SERIAL_DEBUG_OPEN
+static int block_til_ready(struct tty_struct *tty, struct file * filp,
+			   struct async_struct *info)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	struct serial_state *state = info->state;
+	int     retval;
+	int     do_clocal = 0, extra_count = 0;
+	unsigned long   flags;
+
+	/*
+	 * If the device is in the middle of being closed, then block
+	 * until it's done, and then try again.
+	 */
+	if (tty_hung_up_p(filp) ||
+		(info->flags & ASYNC_CLOSING)) {
+		if (info->flags & ASYNC_CLOSING)
+			interruptible_sleep_on(&info->close_wait);
+#ifdef SERIAL_DO_RESTART
+		return ((info->flags & ASYNC_HUP_NOTIFY) ?
+			-EAGAIN : -ERESTARTSYS);
+#else
+		return -EAGAIN;
+#endif
+	}
+
+	/*
+	 * If this is a callout device, then just make sure the normal
+	 * device isn't being used.
+	 */
+	if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
+		if (info->flags & ASYNC_NORMAL_ACTIVE)
+			return -EBUSY;
+		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+			(info->flags & ASYNC_SESSION_LOCKOUT) &&
+			(info->session != current->session))
+			return -EBUSY;
+		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+			(info->flags & ASYNC_PGRP_LOCKOUT) &&
+			(info->pgrp != current->pgrp))
+			return -EBUSY;
+		info->flags |= ASYNC_CALLOUT_ACTIVE;
+		return 0;
+	}
+
+#if 1 /* ? 020906 */
+filp->f_flags |= O_NONBLOCK;
+#endif /* ? 020906 */
+	/*
+	 * If non-blocking mode is set, or the port is not enabled,
+	 * then make the check up front and then exit.
+	 */
+	if ((filp->f_flags & O_NONBLOCK) ||
+		(tty->flags & (1 << TTY_IO_ERROR))) {
+		if (info->flags & ASYNC_CALLOUT_ACTIVE)
+			return -EBUSY;
+		info->flags |= ASYNC_NORMAL_ACTIVE;
+		return 0;
+	}
+
+	if (info->flags & ASYNC_CALLOUT_ACTIVE) {
+		if (state->normal_termios.c_cflag & CLOCAL)
+			do_clocal = 1;
+	} else {
+		if (tty->termios->c_cflag & CLOCAL)
+			do_clocal = 1;
+	}
+
+	/*
+	 * Block waiting for the carrier detect and the line to become
+	 * free (i.e., not in use by the callout).  While we are in
+	 * this loop, state->count is dropped by one, so that
+	 * rs_close() knows when to free things.  We restore it upon
+	 * exit, either normal or abnormal.
+	 */
+	retval = 0;
+	add_wait_queue(&info->open_wait, &wait);
+#ifdef SERIAL_DEBUG_OPEN
+	printk("block_til_ready before block: ttyD%d, count = %d\n",
+		   state->line, state->count);
+#endif
+	save_flags(flags); cli();
+	if (!tty_hung_up_p(filp)) {
+		extra_count = 1;
+		state->count--;
+	}
+	restore_flags(flags);
+	info->blocked_open++;
+	while (1) {
+		save_flags(flags); cli();
+		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
+			(tty->termios->c_cflag & CBAUD))
+			serial_out(info, UART_MCR,
+				   serial_inp(info, UART_MCR) |
+				   (UART_MCR_DTR | UART_MCR_RTS));
+		restore_flags(flags);
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (tty_hung_up_p(filp) ||
+			!(info->flags & ASYNC_INITIALIZED)) {
+#ifdef SERIAL_DO_RESTART
+			if (info->flags & ASYNC_HUP_NOTIFY)
+				retval = -EAGAIN;
+			else
+				retval = -ERESTARTSYS;
+#else
+			retval = -EAGAIN;
+#endif
+			break;
+		}
+		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
+			!(info->flags & ASYNC_CLOSING) &&
+			(do_clocal || (serial_in(info, UART_MSR) &
+				   UART_MSR_DCD)))
+			break;
+		if (signal_pending(current)) {
+			retval = -ERESTARTSYS;
+			break;
+		}
+#ifdef SERIAL_DEBUG_OPEN
+		printk("block_til_ready blocking: ttyD%d, count = %d\n",
+			   info->line, state->count);
+#endif
+		schedule();
+	}
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&info->open_wait, &wait);
+	if (extra_count)
+		state->count++;
+	info->blocked_open--;
+#ifdef SERIAL_DEBUG_OPEN
+	printk("block_til_ready after blocking: ttyD%d, count = %d\n",
+		   info->line, state->count);
+#endif
+	if (retval)
+		return retval;
+	info->flags |= ASYNC_NORMAL_ACTIVE;
+	return 0;
+}
+#undef SERIAL_DEBUG_OPEN
+
+
+static int get_async_struct(int line, struct async_struct **ret_info)
+{
+	struct async_struct *info;
+	struct serial_state *sstate;
+
+	sstate = rs_table + line;
+	sstate->count++;
+	if (sstate->info) {
+		*ret_info = sstate->info;
+		return 0;
+	}
+	info = kmalloc(sizeof(struct async_struct), GFP_KERNEL);
+	if (!info) {
+		sstate->count--;
+		return -ENOMEM;
+	}
+	memset(info, 0, sizeof(struct async_struct));
+	init_waitqueue_head(&info->open_wait);
+	init_waitqueue_head(&info->close_wait);
+	init_waitqueue_head(&info->delta_msr_wait);
+	info->magic = SERIAL_MAGIC;
+	info->port = sstate->port;
+	info->flags = sstate->flags;
+	info->io_type = sstate->io_type;
+	info->iomem_base = sstate->iomem_base;
+	info->iomem_reg_shift = sstate->iomem_reg_shift;
+	info->xmit_fifo_size = sstate->xmit_fifo_size=0;
+	info->line = line;
+	info->tqueue.routine = do_softint;
+	info->tqueue.data = info;
+	info->state = sstate;
+
+	if (sstate->info) {
+		kfree(info);
+
+		*ret_info = sstate->info;
+		return 0;
+	}
+	*ret_info = sstate->info = info;
+	return 0;
+}
+
+/*
+ * -----------------------------------------------------------
+ * psio_open()
+ *
+ * This routine is called whenever a debug console port is opened.  It
+ * enables interrupts for a serial port, linking in its async structure into
+ * the IRQ chain.  It also performs the serial-specific
+ * initialization for the tty structure.
+ * -----------------------------------------------------------
+ */
+static int psio_open(struct tty_struct *tty, struct file *filp)
+{
+	struct async_struct *info;
+	int retval,line=0;
+	unsigned long   page;
+
+	MOD_INC_USE_COUNT;
+	line = MINOR(tty->device) - tty->driver.minor_start;
+	if ((line < 0) || (line >= NR_PORTS)) {
+		MOD_DEC_USE_COUNT;
+		return -ENODEV;
+	}
+
+	retval = get_async_struct(line, &info);
+	if (retval) {
+		printk("psio_open ttyD%d fail...",line);
+		MOD_DEC_USE_COUNT;
+		return retval;
+	}
+	tty->driver_data = info;
+	info->tty = tty;
+	if (serial_paranoia_check(info, tty->device, "psio_open"))
+		return -ENODEV;
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("psio_open %s%d, count = %d\n", tty->driver.name, info->line,
+		   info->state->count);
+#endif
+	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+
+	/*
+	 *  This relies on lock_kernel() stuff so wants tidying for 2.5
+	 */
+	if (!tmp_buf) {
+		page = get_zeroed_page(GFP_KERNEL);
+		if (!page)
+			return -ENOMEM;
+		if (tmp_buf)
+			free_page(page);
+		else
+			tmp_buf = (unsigned char *) page;
+	}
+	/*
+	 * If the port is the middle of closing, bail out now
+	 */
+	if (tty_hung_up_p(filp) ||
+	  (info->flags & ASYNC_CLOSING)) {
+	if (info->flags & ASYNC_CLOSING)
+	  interruptible_sleep_on(&info->close_wait);
+#ifdef SERIAL_DO_RESTART
+	return ((info->flags & ASYNC_HUP_NOTIFY) ?
+	  -EAGAIN : -ERESTARTSYS);
+#else
+	return -EAGAIN;
+#endif
+	}
+
+	/*
+	 * Start up serial port
+	 */
+	retval=startup(info);
+	if (retval)
+		return retval;
+
+	retval = block_til_ready(tty, filp, info);
+	if (retval) {
+#ifdef SERIAL_DEBUG_OPEN
+		printk("psio_open returning after block_til_ready with %d\n",
+			   retval);
+#endif
+		return retval;
+	}
+
+	if ((info->state->count == 1) &&
+		(info->flags & ASYNC_SPLIT_TERMIOS)) {
+		if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+			*tty->termios = info->state->normal_termios;
+		else
+			*tty->termios = info->state->callout_termios;
+		change_speed(info, 0);
+	}
+#ifdef CONFIG_SERIAL_CONSOLE
+	if (cons.cflag && cons.index == line) {
+		tty->termios->c_cflag = cons.cflag;
+		cons.cflag = 0;
+		change_speed(info, 0);
+	}
+#endif
+	info->session = current->session;
+	info->pgrp = current->pgrp;
+
+	return 0;
+}
+
+/*
+ * /proc fs routines....
+ */
+static inline int line_info(char *buf, struct serial_state *state)
+{
+	struct async_struct *info = state->info, scr_info;
+	char  stat_buf[30], control, status;
+	int ret;
+	unsigned long flags;
+
+	ret = sprintf(buf, "%d: uart:%s port:%lX irq:%d",
+		  state->line, uart_config[state->type].name, 
+		  state->port, state->irq);
+
+	if (!state->port || (state->type == PORT_UNKNOWN)) {
+		ret += sprintf(buf+ret, "\n");
+		return ret;
+	}
+
+	/*
+	 * Figure out the current RS-232 lines
+	 */
+	if (!info) {
+		info = &scr_info; /* This is just for serial_{in,out} */
+
+		info->magic = SERIAL_MAGIC;
+		info->port = state->port;
+		info->flags = state->flags;
+		info->hub6 = state->hub6;
+		info->io_type = state->io_type;
+		info->iomem_base = state->iomem_base;
+		info->iomem_reg_shift = state->iomem_reg_shift;
+		info->quot = 0;
+		info->tty = 0;
+	}
+	save_flags(flags); cli();
+	status = serial_in(info, UART_MSR);
+	control = info != &scr_info ? info->MCR : serial_in(info, UART_MCR);
+	restore_flags(flags); 
+
+	stat_buf[0] = 0;
+	stat_buf[1] = 0;
+	if (control & UART_MCR_RTS)
+	strcat(stat_buf, "|RTS");
+	if (status & UART_MSR_CTS)
+	strcat(stat_buf, "|CTS");
+	if (control & UART_MCR_DTR)
+	strcat(stat_buf, "|DTR");
+	if (status & UART_MSR_DSR)
+	strcat(stat_buf, "|DSR");
+	if (status & UART_MSR_DCD)
+	strcat(stat_buf, "|CD");
+	if (status & UART_MSR_RI)
+	strcat(stat_buf, "|RI");
+
+	if (info->quot) {
+		ret += sprintf(buf+ret, " baud:%d",
+			 state->baud_base / (16*info->quot));
+	}
+
+	ret += sprintf(buf+ret, " tx:%d rx:%d",
+		  state->icount.tx, state->icount.rx);
+
+	if (state->icount.frame)
+		ret += sprintf(buf+ret, " fe:%d", state->icount.frame);
+	
+	if (state->icount.parity)
+		ret += sprintf(buf+ret, " pe:%d", state->icount.parity);
+	
+	if (state->icount.brk)
+		ret += sprintf(buf+ret, " brk:%d", state->icount.brk);  
+
+	if (state->icount.overrun)
+		ret += sprintf(buf+ret, " oe:%d", state->icount.overrun);
+
+	/*
+	 * Last thing is the RS-232 status lines
+	 */
+	ret += sprintf(buf+ret, " %s\n", stat_buf+1);
+	return ret;
+}
+
+
+
+int psio_read_proc(char *page, char **start, off_t off, int count,
+		 int *eof, void *data)
+{
+	int i, len = 0, l;
+	off_t begin = 0;
+
+	len += sprintf(page, "sioinfo:1.0 driver:%s%s revision:%s\n",
+		   serial_version, LOCAL_VERSTRING, serial_revdate);
+	for (i = 0; i < NR_PORTS && len < 4000; i++) {
+		l = line_info(page + len, &rs_table[i]);
+		len += l;
+		if (len+begin > off+count)
+			goto done;
+		if (len+begin < off) {
+			begin += len;
+			len = 0;
+		}
+	}
+	*eof = 1;
+done:
+	if (off >= len+begin)
+		return 0;
+	*start = page + (off-begin);
+	return ((count < begin+len-off) ? count : begin+len-off);
+}
+
+static char serial_options[] __initdata =
+	   " no serial options enabled\n";
+
+
+static inline void show_serial_version(void)
+{
+	printk(KERN_INFO "%s version %s%s (%s) with%s", serial_name,
+		serial_version, LOCAL_VERSTRING, serial_revdate,
+		serial_options);
+}
+static unsigned detect_uart_irq (struct serial_state * state)
+{
+	if(! state->irq)
+		printk(KERN_INFO "detect_uart_irq: Ohh irq = 0\n");
+		
+	return state->irq;
+}
+
+static void autoconfig(struct serial_state * state)
+{
+	struct async_struct *info, scr_info;
+	//unsigned long flags;
+
+	state->type = PORT_UNKNOWN;
+
+#ifdef SERIAL_DEBUG_AUTOCONF
+	printk("Testing ttyD%d (0x%04lx, 0x%04x)...\n", state->line,
+		   state->port, (unsigned) state->iomem_base);
+#endif
+
+	if (!CONFIGURED_SERIAL_PORT(state))
+		return;
+
+	info = &scr_info;   /* This is just for serial_{in,out} */
+
+	info->magic = SERIAL_MAGIC;
+	info->state = state;
+	info->port = state->port;
+	info->flags = state->flags;
+	sio_reset(info);
+}
+
+/*
+ * The debug console driver boot-time initialization code!
+ */
+/* 20020830 */
+int __init psio_init(void)
+{
+	int i;
+	struct serial_state * state;
+
+	init_bh(SERIAL_BH, do_psio_serial_bh);
+	init_timer(&serial_timer);
+	serial_timer.function = (void *)psio_timer;
+#if 1
+	mod_timer(&serial_timer, jiffies + 10);
+#else /* 1 */
+	mod_timer(&serial_timer, jiffies + RS_STROBE_TIME);
+#endif /* 1 */
+
+	for (i = 0; i < NR_IRQS; i++) {
+		IRQ_ports[i] = 0;
+		IRQ_timeout[i] = 0;
+	}
+
+	/*
+	 * Initialize the tty_driver structure 
+	 */
+	memset(&psio_driver, 0, sizeof(struct tty_driver));
+	psio_driver.magic = TTY_DRIVER_MAGIC;
+#if (LINUX_VERSION_CODE > 0x20100)
+	psio_driver.driver_name = "serial_m32102";
+#endif
+#if 1
+	psio_driver.name = "ttyD";
+#else
+#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS))
+	psio_driver.name = "ttyd/%d";
+#else
+	psio_driver.name = "ttyD";
+#endif
+#endif	/* 1 */
+
+	psio_driver.major = TTY_MAJOR;
+	psio_driver.minor_start = 80;
+	psio_driver.name_base = 0;
+	psio_driver.num = NR_PORTS;
+	psio_driver.type = TTY_DRIVER_TYPE_SERIAL;
+ 
+	psio_driver.subtype = SERIAL_TYPE_NORMAL;
+	psio_driver.init_termios = tty_std_termios;
+	psio_driver.init_termios.c_cflag =
+		B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	psio_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
+	psio_driver.refcount = &psio_refcount;
+	psio_driver.table = psio_table;
+	psio_driver.termios = psio_termios;
+	psio_driver.termios_locked = psio_termios_locked;
+
+	psio_driver.open = psio_open;
+	psio_driver.close = psio_close;
+	psio_driver.write = psio_write;
+	psio_driver.put_char = psio_put_char;
+	psio_driver.flush_chars = psio_flush_chars;
+	psio_driver.write_room = psio_write_room;
+	psio_driver.chars_in_buffer = psio_chars_in_buffer;
+	psio_driver.flush_buffer = psio_flush_buffer;
+	psio_driver.ioctl = psio_ioctl;
+	psio_driver.throttle = psio_throttle;
+	psio_driver.unthrottle = psio_unthrottle;
+	psio_driver.set_termios = psio_set_termios;
+	psio_driver.stop = psio_stop;
+	psio_driver.start = psio_start;
+	psio_driver.hangup = psio_hangup;
+
+#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
+	psio_driver.break_ctl = psio_break;
+#endif
+#if (LINUX_VERSION_CODE >= 131343)
+	psio_driver.send_xchar = psio_send_xchar;
+	psio_driver.wait_until_sent = psio_wait_until_sent;
+	psio_driver.read_proc = psio_read_proc;
+#endif
+
+	if (tty_register_driver(&psio_driver))
+		panic("Couldn't register debug console driver\n");
+
+	for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
+		state->magic = SSTATE_MAGIC;
+		state->line = i;
+		state->type = 14;
+		state->custom_divisor = 0;
+		state->close_delay = 5*HZ/10;
+		state->closing_wait = 30*HZ;
+		state->callout_termios = psio_driver.init_termios;
+		state->normal_termios = psio_driver.init_termios;
+		state->icount.cts = state->icount.dsr =
+			state->icount.rng = state->icount.dcd = 0;
+		state->icount.rx = state->icount.tx = 0;
+		state->icount.frame = state->icount.parity = 0;
+		state->icount.overrun = state->icount.brk = 0;
+		state->irq = irq_cannonicalize(state->irq);
+
+#if 0
+		if (check_region(state->port,8))
+			continue;
+		if (state->flags & ASYNC_BOOT_AUTOCONF)
+			autoconfig(psio_table);
+#endif
+		state->baud_base = boot_cpu_data.bus_clock;
+		printk(KERN_INFO "ttyD%d initialized.\n",i);
+	   		tty_register_devfs(&psio_driver, 0,
+						   psio_driver.minor_start + state->line);
+	}
+
+	return 0;
+}
+
+/* 20020830 */
+static void __exit psio_fini(void)
+{
+	unsigned long flags;
+	// int e1, e2;
+	int e1;
+	// int i;
+	// struct async_struct *info;
+
+	/* printk("Unloading %s: version %s\n", serial_name, serial_version); */
+	del_timer_sync(&serial_timer);
+	save_flags(flags); cli();
+		remove_bh(SERIAL_BH);
+	if ((e1 = tty_unregister_driver(&psio_driver)))
+		printk("psio_serial: failed to unregister serial driver (%d)\n",e1);
+	restore_flags(flags);
+
+	if (tmp_buf) {
+		unsigned long pg = (unsigned long) tmp_buf;
+		tmp_buf = NULL;
+		free_page(pg);
+	}
+}
+
+module_init(psio_init);
+module_exit(psio_fini);
+MODULE_DESCRIPTION("M32R/M32102 (dumb) serial driver");
+MODULE_AUTHOR("Hiroyuki Kondo <kondo.hiroyuki@renesas.com>, Takeo Takahashi <takahashi.takeo@renesas.com>");
+MODULE_LICENSE("GPL");
+
+
+/*
+ * -----------------------------------------------------------
+ * Debug console driver
+ * -----------------------------------------------------------
+ */
+
+#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+
+static struct async_struct async_dbgcons;
+
+/*
+ *  Wait for transmitter & holding register to empty
+ */
+static inline void wait_for_xmitr(struct async_struct *info)
+{
+	unsigned int status, tmout = 1000000;
+
+	do {
+		status = serial_in(info, UART_LSR);
+
+		if (status & UART_LSR_BI)
+			lsr_break_flag = UART_LSR_BI;
+	
+		if (--tmout == 0)
+			break;
+	} while((status & BOTH_EMPTY) != BOTH_EMPTY);
+
+	/* Wait for flow control if necessary */
+	if (info->flags & ASYNC_CONS_FLOW) {
+		tmout = 1000000;
+		while (--tmout &&
+			((serial_in(info, UART_MSR) & UART_MSR_CTS) == 0));
+	} 
+}
+static void dbg_console_write(struct console *co, const char *s, 
+				unsigned count)
+{
+	static struct async_struct *info = &async_dbgcons;
+	int ier;
+	unsigned i;
+
+	/*
+	 *  First save the IER then disable the interrupts
+	 */
+	ier = serial_in(info, UART_IER);
+	serial_out(info, UART_IER, 0x00);
+
+	/*
+	 *  Now, do each character
+	 */
+	for (i = 0; i < count; i++, s++) {
+		wait_for_xmitr(info);
+
+		/*
+		 *	Send the character out.
+		 *	If a LF, also do CR...
+		 */
+		serial_out(info, UART_TX, *s);
+		if (*s == 10) {
+			wait_for_xmitr(info);
+			serial_out(info, UART_TX, 13);
+		}
+	}
+
+	/*
+	 *	Finally, Wait for transmitter & holding register to empty
+	 *	and restore the IER
+	 */
+	wait_for_xmitr(info);
+	serial_out(info, UART_IER, ier);
+}
+
+#if (LINUX_VERSION_CODE <= 132114) /* Linux 2.4.18 */
+/*
+ *  Receive character from the serial port
+ */
+static int dbg_console_wait_key(struct console *console)
+{
+	static struct async_struct *info;
+	int ier, c;
+
+	info = &async_dbgcons;
+
+	/*
+	 *  First save the IER then disable the interrupts so
+	 *  that the real driver for the port does not get the
+	 *  character.
+	 */
+	ier = serial_in(info, UART_IER);
+	serial_out(info, UART_IER, 0x00);
+ 
+	while ((serial_in(info, UART_LSR) & UART_LSR_DR) == 0);
+	c = serial_in(info, UART_RX);
+
+	/*
+	 *  Restore the interrupts
+	 */
+	serial_out(info, UART_IER, ier);
+
+	return c;
+}
+#endif
+
+static kdev_t dbg_console_device(struct console *c)
+{
+	return MKDEV(TTY_MAJOR, 80 + c->index);
+}
+
+
+static int __init dbg_console_setup(struct console *co, char *options)
+{
+	static struct async_struct *info;
+	struct serial_state *state;
+	int baud = BAUDRATE;
+	int baud_base= boot_cpu_data.bus_clock;
+	int bits = 8;
+	int parity = 'n';
+	int doflow = 0;
+	unsigned int cflag = CREAD | HUPCL | CLOCAL | CRTSCTS;
+	int cval;
+	char *s;
+
+	if (options) {
+		baud = simple_strtoul(options, NULL, 10);
+		s = options;
+		while(*s >= '0' && *s <= '9')
+			s++;
+		if (*s) parity = *s++;
+		if (*s) bits   = *s++ - '0';
+		if (*s) doflow = (*s++ == 'r');
+	}
+
+	co->flags |= CON_ENABLED;
+
+	/*
+	 * 	Now construct a cflag setting.
+	 */
+	switch(baud) {
+		case 1200:
+			cflag |= B1200;
+			break;
+		case 2400:
+			cflag |= B2400;
+			break;
+		case 4800:
+			cflag |= B4800;
+			break;
+		case 19200:
+			cflag |= B19200;
+			break;
+		case 38400:
+			cflag |= B38400;
+			break;
+		case 57600:
+			cflag |= B57600;
+			break;
+		case 115200:
+			cflag |= B115200;
+			break;
+		case 9600:
+		default:
+			cflag |= B9600;
+			baud  = 9600;
+			break;
+	}
+	switch(bits) {
+		case 7:
+			cflag |= CS7;
+			break;
+		default:
+		case 8:
+			cflag |= CS8;
+			break;
+	}
+	switch(parity) {
+		case 'o': case 'O':
+			cflag |= PARODD;
+			break;
+		case 'e': case 'E':
+			cflag |= PARENB;
+			break;
+	}
+	co->cflag = cflag;
+
+	state = rs_table + co->index;
+	if (doflow)
+		state->flags |= ASYNC_CONS_FLOW;
+	info = &async_dbgcons;
+	info->magic = SERIAL_MAGIC;
+	info->state = state;
+	info->port = state->port;
+	info->flags = state->flags;
+	info->io_type = state->io_type;
+	info->iomem_base = state->iomem_base;
+	info->iomem_reg_shift = state->iomem_reg_shift;
+
+	cval = (baud_base / (baud * 4)) - 1;
+
+	serial_outp(info, UART_LCR,  0x0300);  /* init status         */
+	//serial_outp(info, UART_MOD1, 0x0800);  /* 8bit                */
+	serial_outp(info, UART_MOD0, 0x80);    /* cts/rts 1stop nonpari */
+	//serial_outp(info, UART_MOD0, 0x180);    /* rts 1stop nonpari */
+	//serial_outp(info, UART_MOD0, 0xc0);    /* cts/rts 1stop nonpari */
+
+	serial_outp(info, UART_BAUR, cval);    /* set baurate reg     */
+	//serial_outp(info, UART_RBAUR, adj);    /* set adj baurate reg */
+	serial_outp(info, UART_IER, 0x00);     /* intr mask           */
+	serial_outp(info, UART_LCR, 0x03);
+
+	return 0;
+}
+
+static struct console cons = {
+	name:		"ttyD",
+	write:		dbg_console_write,
+	device:		dbg_console_device,
+#if (LINUX_VERSION_CODE <= 132114) /* Linux 2.4.18 */
+	wait_key:	dbg_console_wait_key,
+#endif
+	setup:		dbg_console_setup,
+	flags:		CON_PRINTBUFFER,
+	index:		-1,
+};
+
+
+/* 
+ *	Register console.
+ */
+void __init psio_console_init(void)
+{
+	register_console(&cons);
+}
+
+
diff -ruN linux-2.4.26.org/arch/m32r/drivers/m32r_cfc.c linux-2.4.26/arch/m32r/drivers/m32r_cfc.c
--- linux-2.4.26.org/arch/m32r/drivers/m32r_cfc.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/arch/m32r/drivers/m32r_cfc.c	2004-05-21 17:19:25.000000000 +0900
@@ -0,0 +1,1004 @@
+/*  
+ *  linux/arch/m32r/kernel/setup_mappi.c
+ *  
+ *  Device driver for the CFC functionality of M32R.
+ *  
+ *  Copyright (c) 2001, 2002 ,2003 Hiroyuki Kondo
+ *                                 Sugai Naoto
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/proc_fs.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+#include <asm/system.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/bulkmem.h>
+#include <pcmcia/cistpl.h>
+
+#define MAX_IO_WIN 1
+#define MAX_WIN 1
+
+#include "m32r_cfc.h"
+
+#if !defined(CONFIG_PLAT_USRV)
+#define PCMCIA_DEBUG   3
+#endif	/* CONFIG_PLAT_USRV */
+
+#ifdef PCMCIA_DEBUG
+int m32r_cfc_debug = PCMCIA_DEBUG;
+MODULE_PARM(m32r_cfc_debug, "i");
+#define DEBUG(n, args...) if (m32r_cfc_debug>(n)) printk(args)
+
+static const char *version =
+"m32r_cfc.c 0.002 2003/05/22 12:10:24 (Hiroyuki Kondo)";
+#else
+#define DEBUG(n, args...) do { } while (0)
+#endif
+
+/* Poll status interval -- 0 means default to interrupt */
+static int poll_interval = 0;
+
+typedef enum pcc_space { as_none = 0, as_comm, as_attr, as_io } pcc_as_t;
+
+typedef struct pcc_socket_info_t {
+	u_short			type, flags;
+	socket_cap_t	cap;
+ 	ioaddr_t		ioaddr;
+	u_long			mapaddr;
+	u_long			base;	/* PCC register base */
+	u_char			cs_irq1, cs_irq2, intr;
+	void			(*handler)(void *info, u_int events);
+	void			*info;
+	pccard_io_map	io_map[MAX_IO_WIN];
+	pccard_mem_map	mem_map[MAX_WIN];
+	u_char			io_win;
+	u_char			mem_win;
+	pcc_as_t		current_space;
+	u_char			last_iodbex;
+#ifdef CHAOS_PCC_DEBUG
+	u_char			last_iosize;
+#endif
+#ifdef CONFIG_PROC_FS
+	struct proc_dir_entry *proc;
+#endif
+} pcc_socket_info_t;
+
+static int pcc_sockets = 0;
+static pcc_socket_info_t socket[M32R_MAX_PCC] = {
+	{ 0, }, /* ... */
+};
+
+#define ISA_LOCK(n, f) do { } while (0)
+#define ISA_UNLOCK(n, f) do { } while (0)
+
+/*====================================================================*/
+
+static unsigned int pcc_get(u_short, unsigned int);
+static void pcc_set(u_short, unsigned int , unsigned int );
+
+static spinlock_t pcc_lock = SPIN_LOCK_UNLOCKED;
+
+#if !defined(CONFIG_PLAT_USRV)
+static __inline__ u_long pcc_port2addr(unsigned long port, int size) {
+	u_long addr = 0;
+	u_long odd;
+
+	if (size == 1) {	/* byte access */
+		odd=(port&1) << 11;
+		port -= port & 1;
+		addr = CFC_IO_MAPBASE_BYTE - CFC_IOPORT_BASE + odd + port;
+	} else if (size == 2)
+		addr = CFC_IO_MAPBASE_WORD - CFC_IOPORT_BASE + port;
+
+	return addr;
+}
+#else	/* CONFIG_PLAT_USRV */
+static __inline__ u_long pcc_port2addr(unsigned long port, int size) {
+	u_long odd;
+	u_long addr = ((port - CFC_IOPORT_BASE) & 0xf000) << 8;
+
+	if (size == 1) {	/* byte access */
+		odd = port & 1;
+		port -= odd;
+		odd <<= 11;
+		addr = (addr | CFC_IO_MAPBASE_BYTE) + odd + (port & 0xfff);
+	} else if (size == 2)	/* word access */
+		addr = (addr | CFC_IO_MAPBASE_WORD) + (port & 0xfff);
+
+	return addr;
+}
+#endif	/* CONFIG_PLAT_USRV */
+
+void pcc_ioread_byte(int sock, unsigned long port, void *buf, size_t size, size_t nmemb, int flag) {
+	u_long addr;
+	unsigned char *bp = (unsigned char *)buf;
+	unsigned long flags;
+
+	DEBUG(3, "m32r_cfc: pcc_ioread_byte: sock=%d, port=%#lx, buf=%p, "
+		 "size=%u, nmemb=%d, flag=%d\n",
+		  sock, port, buf, size, nmemb, flag);
+
+	addr = pcc_port2addr(port, 1);
+	if(!addr){
+		printk("m32r_cfc:ioread_byte null port :%#lx\n",port);
+		return;
+	}
+	DEBUG(3, "m32r_cfc: pcc_ioread_byte: addr=%#lx\n", addr);
+
+	spin_lock_irqsave(&pcc_lock, flags);
+	/* read Byte */
+	while (nmemb--) {
+	   	*bp++ = readb(addr);
+	}
+	spin_unlock_irqrestore(&pcc_lock, flags);
+}
+
+void pcc_ioread_word(int sock, unsigned long port, void *buf, size_t size, size_t nmemb, int flag) {
+	u_long addr;
+	unsigned short *bp = (unsigned short *)buf;
+	unsigned long flags;
+
+	DEBUG(3, "m32r_cfc: pcc_ioread_word: sock=%d, port=%#lx, "
+		 "buf=%p, size=%u, nmemb=%d, flag=%d\n",
+		 sock, port, buf, size, nmemb, flag);
+
+	if(size != 2)
+		printk("m32r_cfc: ioread_word :illigal size %u : %#lx\n",size,port);
+	if(size == 9)
+		printk("m32r_cfc: ioread_word :insw \n");
+
+	addr = pcc_port2addr(port, 2);
+	if(!addr){
+		printk("m32r_cfc:ioread_word null port :%#lx\n",port);
+		return;
+	}
+
+	DEBUG(3, "m32r_cfc: pcc_ioread_word: addr=%#lx\n", addr);
+	spin_lock_irqsave(&pcc_lock, flags);
+   	/* read Word */
+   	while (nmemb--) {
+		*bp++ = readw(addr);
+	}
+	spin_unlock_irqrestore(&pcc_lock, flags);
+}
+
+void pcc_iowrite_byte(int sock, unsigned long port, void *buf, size_t size, size_t nmemb, int flag) {
+	u_long addr;
+	unsigned char *bp = (unsigned char *)buf;
+	unsigned long flags;
+
+	DEBUG(3, "m32r_cfc: pcc_iowrite_byte: sock=%d, port=%#lx, "
+		 "buf=%p, size=%u, nmemb=%d, flag=%d\n",
+		 sock, port, buf, size, nmemb, flag);
+
+	/* write Byte */
+	addr = pcc_port2addr(port, 1);
+	if(!addr){
+		printk("m32r_cfc:iowrite_byte null port:%#lx\n",port);
+		return;
+	}
+	DEBUG(3, "m32r_cfc: pcc_iowrite_byte: addr=%#lx\n", addr);
+	spin_lock_irqsave(&pcc_lock, flags);
+	while (nmemb--) {
+		writeb(*bp++, addr);
+	}
+	spin_unlock_irqrestore(&pcc_lock, flags);
+}
+
+void pcc_iowrite_word(int sock, unsigned long port, void *buf, size_t size, size_t nmemb, int flag) {
+	u_long addr;
+	unsigned short *bp = (unsigned short *)buf;
+	unsigned long flags;
+
+	DEBUG(3, "m32r_cfc: pcc_iowrite_word: sock=%d, port=%#lx, "
+		 "buf=%p, size=%u, nmemb=%d, flag=%d\n",
+		 sock, port, buf, size, nmemb, flag);
+
+	if(size != 2)
+		printk("m32r_cfc: iowrite_word :illigal size %u : %#lx\n",size,port);
+	if(size == 9)
+		printk("m32r_cfc: iowrite_word :outsw \n");
+
+	addr = pcc_port2addr(port, 2);
+	if(!addr){
+		printk("m32r_cfc:iowrite_word null addr :%#lx\n",port);
+		return;
+	}
+#if 1
+	if(addr&1){
+		printk("m32r_cfc:iowrite_word odd addr (%#lx):%#lx\n",port,addr);
+		return;
+	}
+#endif
+	DEBUG(3, "m32r_cfc: pcc_iowrite_word: addr=%#lx\n", addr);
+	spin_lock_irqsave(&pcc_lock, flags);
+	while (nmemb--) {
+		writew(*bp++, addr);
+   	}
+	spin_unlock_irqrestore(&pcc_lock, flags);
+}
+
+/*====================================================================*/
+
+#define IS_ALIVE		0x8000
+
+typedef struct pcc_t {
+	char				*name;
+	u_short				flags;
+} pcc_t;
+
+static pcc_t pcc[] = {
+#if !defined(CONFIG_PLAT_USRV)
+	{ "m32r_cfc", 0 }, { "", 0 },
+#else	/* CONFIG_PLAT_USRV */
+	{ "m32r_cfc", 0 }, { "m32r_cfc", 0 }, { "m32r_cfc", 0 }, 
+	{ "m32r_cfc", 0 }, { "m32r_cfc", 0 }, { "", 0 }, 
+#endif	/* CONFIG_PLAT_USRV */
+};
+
+static void pcc_interrupt(int, void *, struct pt_regs *regs);
+
+/*====================================================================*/
+
+static struct timer_list poll_timer;
+
+static unsigned int pcc_get(u_short sock, unsigned int reg)
+{
+	unsigned int val = inw(reg);
+	DEBUG(3, "m32r_cfc: pcc_get: reg(0x%08x)=0x%04x\n", reg, val);
+	return val;
+}
+
+
+static void pcc_set(u_short sock, unsigned int reg, unsigned int data)
+{
+	outw(data, reg);
+	DEBUG(3, "m32r_cfc: pcc_set: reg(0x%08x)=0x%04x\n", reg, data);
+}
+
+/*======================================================================
+
+	See if a card is present, powered up, in IO mode, and already
+	bound to a (non PC Card) Linux driver.  We leave these alone.
+
+	We make an exception for cards that seem to be serial devices.
+	
+======================================================================*/
+
+static int __init is_alive(u_short sock)
+{
+	unsigned int stat;
+	
+	DEBUG(3, "m32r_cfc: is_alive:\n");
+
+	printk("CF: ");
+	stat = pcc_get(sock, (unsigned int)PLD_CFSTS);
+	if (!stat)
+		printk("No ");
+	printk("Card is detected at socket %d : stat = 0x%08x\n", sock, stat);
+
+	DEBUG(3, "m32r_cfc: is_alive: sock stat is 0x%04x\n", stat);
+
+	return 0;
+}
+
+static void add_pcc_socket(ulong base, int irq, ulong mapaddr, ioaddr_t ioaddr)
+{
+  	pcc_socket_info_t *t = &socket[pcc_sockets];
+
+	DEBUG(3, "m32r_cfc: add_pcc_socket: base=%#lx, irq=%d, "
+		 "mapaddr=%#lx, ioaddr=%08x\n",
+		 base, irq, mapaddr, ioaddr);
+
+	/* add sockets */
+	t->ioaddr = ioaddr;
+	t->mapaddr = mapaddr;
+#if !defined(CONFIG_PLAT_USRV)
+	t->base = 0;
+	t->flags = 0;
+	t->cs_irq1 = irq;		// insert irq
+	t->cs_irq2 = irq + 1;		// eject irq
+#else	/* CONFIG_PLAT_USRV */
+	t->base = base;
+	t->flags = 0;
+	t->cs_irq1 = 0;			// insert irq
+	t->cs_irq2 = 0;			// eject irq
+#endif	/* CONFIG_PLAT_USRV */
+
+	if (is_alive(pcc_sockets))
+		t->flags |= IS_ALIVE;
+
+	/* add pcc */
+#if !defined(CONFIG_PLAT_USRV)
+	request_region((unsigned int)PLD_CFRSTCR, 0x20, "m32r_cfc");
+#else	/* CONFIG_PLAT_USRV */
+	{
+		unsigned int reg_base;
+
+		reg_base = (unsigned int)PLD_CFRSTCR;
+		reg_base |= pcc_sockets << 8;
+		request_region(reg_base, 0x20, "m32r_cfc");
+	}
+#endif	/* CONFIG_PLAT_USRV */
+
+	printk(KERN_INFO "  %s ", pcc[pcc_sockets].name);
+	printk("cfc at 0x%08lx\n", t->base);
+
+	/* Update socket interrupt information, capabilities */
+	t->cap.features |= (SS_CAP_PCCARD | SS_CAP_STATIC_MAP);
+	t->cap.map_size = M32R_PCC_MAPSIZE;
+	t->cap.io_offset = ioaddr;              /* use for io access offset */
+	t->cap.irq_mask = 0;
+#if !defined(CONFIG_PLAT_USRV)
+	t->cap.pci_irq = PLD_IRQ_CFIREQ ;       /* card interrupt */
+#else	/* CONFIG_PLAT_USRV */
+	t->cap.pci_irq = PLD_IRQ_CF0 + pcc_sockets;	/* card interrupt */
+#endif	/* CONFIG_PLAT_USRV */
+
+#if !defined(CONFIG_PLAT_USRV)
+	/* insert interrupt */
+	request_irq(irq, pcc_interrupt, 0, "m32r_cfc", pcc_interrupt);
+	/* eject interrupt */
+	request_irq(irq+1, pcc_interrupt, 0, "m32r_cfc", pcc_interrupt);
+
+	DEBUG(3, "m32r_cfc: enable CFMSK, RDYSEL\n");
+	pcc_set(pcc_sockets, (unsigned int)PLD_CFIMASK, 0x01);
+#endif	/* CONFIG_PLAT_USRV */
+#if defined(CONFIG_PLAT_M32700UT_Alpha) || defined(CONFIG_PLAT_M32700UT) \
+	|| defined(CONFIG_PLAT_USRV) || defined(CONFIG_PLAT_OPSPUT)
+	pcc_set(pcc_sockets, (unsigned int)PLD_CFCR1, 0x0200); 
+#endif
+	pcc_sockets++;
+
+	return;
+}
+
+
+/*====================================================================*/
+
+static u_int pending_events[8];
+static spinlock_t pending_event_lock = SPIN_LOCK_UNLOCKED;
+
+static void pcc_bh(void *dummy)
+{
+	u_int events;
+	int i;
+
+	DEBUG(3, "m32r_cfc: pcc_bh:\n");
+
+	for (i=0; i < pcc_sockets; i++) {
+		spin_lock_irq(&pending_event_lock);
+		events = pending_events[i];
+		pending_events[i] = 0;
+		spin_unlock_irq(&pending_event_lock);
+	/* 
+	 * SS_DETECT events need a small delay here. The reason for this is that 
+	 * the "is there a card" electronics need time to see the card after the
+	 * "we have a card coming in" electronics have seen it. 
+	 */
+		if (events & SS_DETECT) 
+			mdelay(4);
+		if (socket[i].handler) {
+			DEBUG(3, "m32r_cfc: pcc_bh: call handler"
+				 "(%d, events=0x%08x)\n", i, events);
+			socket[i].handler(socket[i].info, events);
+		}
+	}
+}
+
+static struct tq_struct pcc_task = {
+		routine:		pcc_bh
+};
+
+//static unsigned long last_detect_jiffies;
+
+static void pcc_interrupt(int irq, void *dev, struct pt_regs *regs)
+{
+	int i;
+	u_int events = 0;
+	
+	DEBUG(3, "m32r_cfc: pcc_interrupt: irq=%d, dev=%p, regs=%p\n",
+		irq, dev, regs);
+	for (i = 0; i < pcc_sockets; i++) {
+		if (socket[i].cs_irq1 != irq && socket[i].cs_irq2 != irq)
+			continue;
+		if (!socket[i].handler) continue;
+		DEBUG(3, "m32r_cfc: pcc_interrupt: socket %d irq 0x%02x ",
+			i, irq);
+		events |= SS_DETECT;	/* insert or eject */
+		if (events) {
+			spin_lock(&pending_event_lock);
+			pending_events[i] |= events;
+			spin_unlock(&pending_event_lock);
+			schedule_task(&pcc_task);
+		}
+	}
+	DEBUG(3, "m32r_cfc: pcc_interrupt: done\n");
+} /* pcc_interrupt */
+
+static void pcc_interrupt_wrapper(u_long data)
+{
+	DEBUG(3, "m32r_cfc: pcc_interrupt_wrapper:\n");
+	pcc_interrupt(0, NULL, NULL);
+#if 1
+	poll_timer.expires = jiffies + poll_interval;
+	add_timer(&poll_timer);
+#endif
+}
+
+/*====================================================================*/
+
+static int _pcc_get_status(u_short sock, u_int *value)
+{
+	u_int status;
+	
+	DEBUG(3, "m32r_cfc: _pcc_get_status:\n");
+	status = pcc_get(sock, (unsigned int)PLD_CFSTS);
+	*value = (status) ? SS_DETECT : 0;
+ 	DEBUG(3, "m32r_cfc: _pcc_get_status: status=0x%08x\n", status);
+
+#if defined(CONFIG_PLAT_M32700UT_Alpha) || defined(CONFIG_PLAT_M32700UT) \
+	|| defined(CONFIG_PLAT_USRV) || defined(CONFIG_PLAT_OPSPUT)
+	if ( status ) {
+#if !defined(CONFIG_PLAT_USRV)
+		/* enable CF power */
+		status = inw((unsigned int)PLD_CPCR);
+		if (!(status & PLD_CPCR_CF)) {
+			DEBUG(3, "m32r_cfc: _pcc_get_status: "
+				 "power on (CPCR=0x%08x)\n", status);
+			status |= PLD_CPCR_CF;
+			outw(status, (unsigned int)PLD_CPCR);
+			udelay(100);
+		}
+#endif	/* !CONFIG_PLAT_USRV */
+		*value |= SS_POWERON;
+
+		pcc_set(sock, (unsigned int)PLD_CFBUFCR,0);/* enable buffer */
+		udelay(100);
+
+		*value |= SS_READY; 		/* always ready */
+		*value |= SS_3VCARD; 
+	} else {
+#if !defined(CONFIG_PLAT_USRV)
+		/* disable CF power */
+		status = inw((unsigned int)PLD_CPCR);
+		status &= ~PLD_CPCR_CF;
+		outw(status, (unsigned int)PLD_CPCR);
+		udelay(100);
+		DEBUG(3, "m32r_cfc: _pcc_get_status: "
+			 "power off (CPCR=0x%08x)\n", status);
+#endif	/* !CONFIG_PLAT_USRV */
+	}
+#elif defined(CONFIG_PLAT_MAPPI2)
+	if ( status ) {
+                status = pcc_get(sock, (unsigned int)PLD_CPCR);
+                if (status == 0) { /* power off */
+                        pcc_set(sock, (unsigned int)PLD_CPCR, 1);
+                        pcc_set(sock, (unsigned int)PLD_CFBUFCR,0); /* force buffer off for ZA-36 */
+                        udelay(50);
+                }
+                status = pcc_get(sock, (unsigned int)PLD_CFBUFCR);
+                if (status != 0) { /* buffer off */
+                                pcc_set(sock, (unsigned int)PLD_CFBUFCR,0);
+                                udelay(50);
+                                pcc_set(sock, (unsigned int)PLD_CFRSTCR, 0x0101);
+                                udelay(25); /* for IDE reset */
+                                pcc_set(sock, (unsigned int)PLD_CFRSTCR, 0x0100);
+                                mdelay(2);  /* for IDE reset */
+                } else {
+                        *value |= SS_POWERON;
+                        *value |= SS_READY;
+                }
+	}
+#else
+#error no platform configuration
+#endif
+	DEBUG(3, "m32r_cfc: _pcc_get_status: GetStatus(%d) = %#4.4x\n",
+		 sock, *value);
+	return 0;
+} /* _get_status */
+
+/*====================================================================*/
+
+static int _pcc_get_socket(u_short sock, socket_state_t *state)
+{
+//	pcc_socket_info_t *t = &socket[sock];
+	
+#if defined(CONFIG_PLAT_M32700UT_Alpha) || defined(CONFIG_PLAT_M32700UT) \
+	|| defined(CONFIG_PLAT_USRV) || defined(CONFIG_PLAT_OPSPUT)
+	state->flags = 0;
+	state->csc_mask = SS_DETECT;	/* ??? */
+	state->csc_mask |= SS_READY;	/* ??? */
+	state->io_irq = 0;
+	state->Vcc = 33;	/* 3.3V fixed */
+	state->Vpp = 33;
+#endif
+	DEBUG(3, "m32r_cfc:  GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d, "
+		  "io_irq %d, csc_mask %#2.2x\n", sock, state->flags,
+		  state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
+	return 0;
+} /* _get_socket */
+
+/*====================================================================*/
+
+static int _pcc_set_socket(u_short sock, socket_state_t *state)
+{
+#if defined(CONFIG_PLAT_MAPPI2)
+	u_long reg = 0;
+#endif
+	DEBUG(3, "m32r_cfc: SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "
+		  "io_irq %d, csc_mask %#2.2x)\n", sock, state->flags,
+		  state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
+
+#if defined(CONFIG_PLAT_M32700UT_Alpha) || defined(CONFIG_PLAT_M32700UT) \
+	|| defined(CONFIG_PLAT_USRV) || defined(CONFIG_PLAT_OPSP)
+	if (state->Vcc) {
+		if ((state->Vcc != 50) && (state->Vcc != 33))
+			return -EINVAL;
+		/* accept 5V and 3.3V */
+	}
+#elif defined(CONFIG_PLAT_MAPPI2)
+        if (state->Vcc) {
+                /*
+                 * 5V only
+                 */
+                if (state->Vcc == 50) {
+                        reg |= PCCSIGCR_VEN;
+                } else {
+                        return -EINVAL;
+                }
+        }
+#endif
+
+	if (state->flags & SS_RESET) {
+		DEBUG(3, ":RESET\n");
+		pcc_set(sock,(unsigned int)PLD_CFRSTCR,0x101);
+	}else{
+		pcc_set(sock,(unsigned int)PLD_CFRSTCR,0x100);
+	}
+	if (state->flags & SS_OUTPUT_ENA){
+		DEBUG(3, ":OUTPUT_ENA\n");
+		/* bit clear */
+		pcc_set(sock,(unsigned int)PLD_CFBUFCR,0);
+	} else {
+		pcc_set(sock,(unsigned int)PLD_CFBUFCR,1);
+	}
+
+#ifdef PCMCIA_DEBUG
+	if(state->flags & SS_IOCARD){
+		DEBUG(3, ":IOCARD");
+	}
+	if (state->flags & SS_PWR_AUTO) {
+		DEBUG(3, ":PWR_AUTO");
+	}
+	if (state->csc_mask & SS_DETECT)
+		DEBUG(3, ":csc-SS_DETECT");
+	if (state->flags & SS_IOCARD) {
+		if (state->csc_mask & SS_STSCHG) 
+			DEBUG(3, ":STSCHG");
+	} else {
+		if (state->csc_mask & SS_BATDEAD)
+			DEBUG(3, ":BATDEAD");
+		if (state->csc_mask & SS_BATWARN)
+			DEBUG(3, ":BATWARN");
+		if (state->csc_mask & SS_READY)
+			DEBUG(3, ":READY");
+	}
+	DEBUG(3, "\n");
+#endif
+	return 0;
+} /* _set_socket */
+
+/*====================================================================*/
+
+static int _pcc_get_io_map(u_short sock, struct pccard_io_map *io)
+{
+	u_char map;
+	
+	map = io->map;
+
+	DEBUG(3, "m32r_cfc: GetIOMap(%d, %d) = %#2.2x, %d ns, "
+		  "%#4.4x-%#4.4x\n", sock, map, io->flags, io->speed,
+		  io->start, io->stop);
+	return 0;
+} /* _get_io_map */
+
+/*====================================================================*/
+
+static int _pcc_set_io_map(u_short sock, struct pccard_io_map *io)
+{
+	u_char map;
+	
+	DEBUG(3, "m32r_cfc: SetIOMap(%d, %d, %#2.2x, %d ns, "
+		  "%#4.4x-%#4.4x)\n", sock, io->map, io->flags,
+		  io->speed, io->start, io->stop);
+	map = io->map;
+
+	return 0;
+} /* _set_io_map */
+
+/*====================================================================*/
+
+static int _pcc_get_mem_map(u_short sock, struct pccard_mem_map *mem)
+{
+	u_char map;
+	
+	map = mem->map;
+
+	DEBUG(3, "m32r_cfc: GetMemMap(%d, %d) = %#2.2x, %d ns, %#5.5lx-%#5."
+		  "5lx, %#5.5x\n", sock, mem->map, mem->flags, mem->speed,
+		  mem->sys_start, mem->sys_stop, mem->card_start);
+	return 0;
+} /* _get_mem_map */
+
+/*====================================================================*/
+
+  
+static int _pcc_set_mem_map(u_short sock, struct pccard_mem_map *mem)
+{
+
+	u_char map = mem->map;
+	u_long mode;
+	u_long addr;
+	pcc_socket_info_t *t = &socket[sock];
+
+	DEBUG(3, "m32r_cfc: SetMemMap(%d, %d, %#2.2x, %d ns, %#5.5lx-%#5.5"
+		  "lx, %#5.5x)\n", sock, map, mem->flags, mem->speed,
+		  mem->sys_start, mem->sys_stop, mem->card_start);
+
+	/*
+	 * sanity check
+	 */
+	if ((map > MAX_WIN) || (mem->card_start > 0x3ffffff) ||	 
+		(mem->sys_start > mem->sys_stop)) {
+		return -EINVAL;
+	}
+
+	/*
+	 * de-activate
+	 */
+	if ((mem->flags & MAP_ACTIVE) == 0) {
+		t->current_space = as_none;
+		return 0;
+	}
+
+	/*
+	 * Disable first
+	 */
+//	pcc_set(sock, PCCR, 0);
+
+	/*
+	 * Set mode
+	 */
+	if (mem->flags & MAP_ATTRIB) {
+		mode = PCMOD_AS_ATTRIB | PCMOD_CBSZ;
+		t->current_space = as_attr;
+	} else {
+		mode = 0; /* common memory */
+		t->current_space = as_comm;
+	}
+//	pcc_set(sock, PCMOD, mode);
+
+	/*
+	 * Set address
+	 */
+	addr = t->mapaddr + (mem->card_start & M32R_PCC_MAPMASK);
+//	pcc_set(sock, PCADR, addr);
+
+	mem->sys_start = addr + mem->card_start;
+	mem->sys_stop = mem->sys_start + (M32R_PCC_MAPSIZE - 1);
+
+	/*
+	 * Set timing
+	 */
+//	pcc_set(sock, PCATCR, pcc_access_timing);
+
+	/*
+	 * Enable again
+	 */
+//	pcc_set(sock, PCCR, 1);
+
+	return 0;
+
+} /* _set_mem_map */
+
+/*======================================================================
+
+	Routines for accessing socket information and register dumps via
+	/proc/bus/pccard/...
+	
+======================================================================*/
+
+#ifdef CONFIG_PROC_FS
+
+static int proc_read_info(char *buf, char **start, off_t pos,
+				  int count, int *eof, void *data)
+{
+	pcc_socket_info_t *s = data;
+	char *p = buf;
+	p += sprintf(p, "type:	 %s\nbase addr:	0x%08lx\n",
+				 pcc[s->type].name, s->base);
+	return (p - buf);
+}
+
+static int proc_read_exca(char *buf, char **start, off_t pos,
+				  int count, int *eof, void *data)
+{
+	char *p = buf;
+	int i, top;
+	
+	/* FIXME */
+	ISA_LOCK(sock, flags);
+	top = 0x40;
+	for (i = 0; i < top; i += 4) {
+		if (i == 0x50) {
+			p += sprintf(p, "\n");
+			i = 0x100;
+		}
+	}
+	ISA_UNLOCK(sock, flags);
+	return (p - buf);
+}
+
+static void pcc_proc_setup(unsigned int sock, struct proc_dir_entry *base)
+{
+	pcc_socket_info_t *s = &socket[sock];
+
+	if (s->flags & IS_ALIVE)
+			return;
+
+	create_proc_read_entry("info", 0, base, proc_read_info, s);
+	create_proc_read_entry("exca", 0, base, proc_read_exca, s);
+	s->proc = base;
+}
+
+static void pcc_proc_remove(u_short sock)
+{
+	struct proc_dir_entry *base = socket[sock].proc;
+	if (base == NULL) return;
+	remove_proc_entry("info", base);
+	remove_proc_entry("exca", base);
+}
+
+#else
+
+#define pcc_proc_setup NULL
+
+#endif /* CONFIG_PROC_FS */
+
+/*====================================================================*/
+
+#if 0
+#define LOCKED(x) return x
+#else
+#define LOCKED(x) do { \
+	int retval; \
+	unsigned long flags; \
+	spin_lock_irqsave(&pcc_lock, flags); \
+	retval = x; \
+	spin_unlock_irqrestore(&pcc_lock, flags); \
+	return retval; \
+} while (0)
+#endif
+
+static int pcc_register_callback(unsigned int sock, void (*handler)(void *, unsigned int), void * info)
+{
+	DEBUG(3, "m32r_cfc: pcc_register_callback: sock=%d, handler=%p\n", sock, handler);
+
+	socket[sock].handler = handler;
+	socket[sock].info = info;
+	if (handler == NULL) {
+		MOD_DEC_USE_COUNT;
+	} else {
+		MOD_INC_USE_COUNT;
+	}
+	return 0;
+} /* pcc_register_callback */
+
+static int pcc_inquire_socket(unsigned int sock, socket_cap_t *cap)
+{
+	DEBUG(3, "m32r_cfc: pcc_inquire_socket: sock=%d, cap=%p\n", sock, cap);
+	*cap = socket[sock].cap;
+	return 0;
+} /* pcc_inquire_socket */
+
+static int pcc_get_status(unsigned int sock, u_int *value)
+{
+	if (socket[sock].flags & IS_ALIVE) {
+		DEBUG(3, "m32r_cfc: pcc_get_status: sock(%d) -EINVAL\n", sock);
+		*value = 0;
+		return -EINVAL;
+	}
+	DEBUG(3, "m32r_cfc: pcc_get_status: sock(%d)\n", sock);
+	LOCKED(_pcc_get_status(sock, value));
+}
+
+static int pcc_get_socket(unsigned int sock, socket_state_t *state)
+{
+	if (socket[sock].flags & IS_ALIVE) {
+		DEBUG(3, "m32r_cfc: pcc_get_socket: sock(%d) -EINVAL\n", sock);
+		return -EINVAL;
+	}
+	DEBUG(3, "m32r_cfc: pcc_get_socket: sock(%d)\n", sock);
+	LOCKED(_pcc_get_socket(sock, state));
+}
+
+static int pcc_set_socket(unsigned int sock, socket_state_t *state)
+{
+	if (socket[sock].flags & IS_ALIVE) {
+		DEBUG(3, "m32r_cfc: pcc_set_socket: sock(%d) -EINVAL\n", sock);
+		return -EINVAL;
+	}
+	DEBUG(3, "m32r_cfc: pcc_set_socket: sock(%d)\n", sock);
+	LOCKED(_pcc_set_socket(sock, state));
+}
+
+static int pcc_get_io_map(unsigned int sock, struct pccard_io_map *io)
+{
+	if (socket[sock].flags & IS_ALIVE) {
+		DEBUG(3, "m32r_cfc: pcc_get_io_map: sock(%d) -EINVAL\n", sock);
+		return -EINVAL;
+	}
+	DEBUG(3, "m32r_cfc: pcc_get_io_map: sock(%d)\n", sock);
+	LOCKED(_pcc_get_io_map(sock, io));
+}
+
+static int pcc_set_io_map(unsigned int sock, struct pccard_io_map *io)
+{
+	if (socket[sock].flags & IS_ALIVE) {
+		DEBUG(3, "m32r_cfc: pcc_set_io_map: sock(%d) -EINVAL\n", sock);
+		return -EINVAL;
+	}
+	DEBUG(3, "m32r_cfc: pcc_set_io_map: sock(%d)\n", sock);
+	LOCKED(_pcc_set_io_map(sock, io));
+}
+
+static int pcc_get_mem_map(unsigned int sock, struct pccard_mem_map *mem)
+{
+	if (socket[sock].flags & IS_ALIVE) {
+		DEBUG(3, "m32r_cfc: pcc_get_mem_map: sock(%d) -EINVAL\n", sock);
+		return -EINVAL;
+	}
+	DEBUG(3, "m32r_cfc: pcc_get_mem_map: sock(%d)\n", sock);
+	LOCKED(_pcc_get_mem_map(sock, mem));
+}
+
+static int pcc_set_mem_map(unsigned int sock, struct pccard_mem_map *mem)
+{
+	if (socket[sock].flags & IS_ALIVE) {
+		DEBUG(3, "m32r_cfc: pcc_set_mem_map: sock(%d) -EINVAL\n", sock);
+		return -EINVAL;
+	}
+	DEBUG(3, "m32r_cfc: pcc_set_mem_map: sock(%d)\n", sock);
+	LOCKED(_pcc_set_mem_map(sock, mem));
+}
+
+static int pcc_init(unsigned int s)
+{
+	DEBUG(3, "m32r_cfc: pcc_init()\n");
+	return 0;
+}
+
+static int pcc_suspend(unsigned int sock)
+{
+	DEBUG(3, "m32r_cfc: pcc_suspend()\n");
+	return pcc_set_socket(sock, &dead_socket);
+}
+
+
+static struct pccard_operations pcc_operations = {
+	pcc_init,
+	pcc_suspend,
+	pcc_register_callback,
+	pcc_inquire_socket,
+	pcc_get_status,
+	pcc_get_socket,
+	pcc_set_socket,
+	pcc_get_io_map,
+	pcc_set_io_map,
+	pcc_get_mem_map,
+	pcc_set_mem_map,
+	pcc_proc_setup
+};
+
+/*====================================================================*/
+
+#define UT_CFC
+static int __init init_m32r_pcc(void)
+{
+	servinfo_t serv;
+
+	pcmcia_get_card_services_info(&serv);
+	if (serv.Revision != CS_RELEASE_CODE) {
+		printk(KERN_NOTICE "m32r-pcc: Card Services release "
+			   "does not match!\n");
+		return -1;
+	}
+#if defined(CONFIG_PLAT_MAPPI2)
+        pcc_set(0, (unsigned int)PLD_CFCR0, 0x0f0f);
+        pcc_set(0, (unsigned int)PLD_CFCR1, 0x0200);
+#endif
+
+	DEBUG(0, "%s\n", version);
+
+	pcc_sockets = 0;
+
+#if !defined(CONFIG_PLAT_USRV)
+	add_pcc_socket(M32R_PCC0_BASE, PLD_IRQ_CFC_INSERT, CFC_ATTR_MAPBASE, CFC_IOPORT_BASE);
+#else	/* CONFIG_PLAT_USRV */
+	{
+		int i;
+		ulong base, mapaddr;
+		ioaddr_t ioaddr;
+
+		for (i = 0 ; i < M32R_MAX_PCC ; i++) {
+			base = (ulong)PLD_CFRSTCR;
+			base = base | (i << 8);
+			ioaddr = (i + 1) << 12;
+			mapaddr = CFC_ATTR_MAPBASE | (i << 20);
+			add_pcc_socket(base, 0, mapaddr, ioaddr);
+		}
+	}
+#endif	/* CONFIG_PLAT_USRV */
+
+	if (pcc_sockets == 0) {
+		printk("socket is not found.\n");
+		return -ENODEV;
+	}
+	/* Set up interrupt handler(s) */
+
+	if (register_ss_entry(pcc_sockets, &pcc_operations) != 0)
+		printk(KERN_NOTICE "m32r_pcc: register_ss_entry() failed\n");
+
+	/* Finally, schedule a polling interrupt */
+	if (poll_interval != 0) {
+		poll_timer.function = pcc_interrupt_wrapper;
+		poll_timer.data = 0;
+		init_timer(&poll_timer);
+		poll_timer.expires = jiffies + poll_interval;
+		add_timer(&poll_timer);
+	}
+
+	return 0;
+} /* init_m32r_pcc */
+
+static void __exit exit_m32r_pcc(void)
+{
+#ifdef CONFIG_PROC_FS
+	int i;
+	for (i = 0; i < pcc_sockets; i++) pcc_proc_remove(i);
+#endif
+	unregister_ss_entry(&pcc_operations);
+
+} /* exit_m32r_pcc */
+
+module_init(init_m32r_pcc);
+module_exit(exit_m32r_pcc);
+
+/*
+ ***  Emacs  Setting ***
+ * Local Variables:
+ * c-basic-offset:4
+ * tab-width:4
+ * End:
+ */
+
diff -ruN linux-2.4.26.org/arch/m32r/drivers/m32r_cfc.h linux-2.4.26/arch/m32r/drivers/m32r_cfc.h
--- linux-2.4.26.org/arch/m32r/drivers/m32r_cfc.h	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/arch/m32r/drivers/m32r_cfc.h	2003-12-17 10:10:26.000000000 +0900
@@ -0,0 +1,85 @@
+/*
+ *  $Id: m32r_cfc.h,v 1.3 2003/12/17 01:10:26 hitoshiy Exp $
+ *
+ * Copyright (C) 2001 by Hiroyuki Kondo
+ */
+
+#if !defined(CONFIG_PLAT_USRV)
+#define M32R_MAX_PCC	2
+#else	/* CONFIG_PLAT_USRV */
+#define M32R_MAX_PCC	CONFIG_CFC_NUM
+#endif	/* CONFIG_PLAT_USRV */
+
+/*
+ * M32R PC Card Controler
+ */
+#define M32R_PCC0_BASE        0x00ef7000
+#define M32R_PCC1_BASE        0x00ef7020
+
+/*
+ * Register offsets
+ */
+#define PCCR            0x00
+#define PCADR           0x04
+#define PCMOD           0x08
+#define PCIRC           0x0c
+#define PCCSIGCR        0x10
+#define PCATCR          0x14
+
+/*
+ * PCCR
+ */
+#define PCCR_PCEN       (1UL<<(31-31))
+
+/*
+ * PCIRC
+ */
+#define PCIRC_BWERR     (1UL<<(31-7))
+#define PCIRC_CDIN1     (1UL<<(31-14))
+#define PCIRC_CDIN2     (1UL<<(31-15))
+#define PCIRC_BEIEN     (1UL<<(31-23))
+#define PCIRC_CIIEN     (1UL<<(31-30))
+#define PCIRC_COIEN     (1UL<<(31-31))
+
+/*
+ * PCCSIGCR
+ */
+#define PCCSIGCR_SEN    (1UL<<(31-3))
+#define PCCSIGCR_VEN    (1UL<<(31-7))
+#define PCCSIGCR_CRST   (1UL<<(31-15))
+#define PCCSIGCR_COCR   (1UL<<(31-31))
+
+/*
+ *
+ */
+#define PCMOD_AS_ATTRIB	(1UL<<(31-19))
+#define PCMOD_AS_IO	(1UL<<(31-18))
+
+#define PCMOD_CBSZ	(1UL<<(31-23)) /* set for 8bit */
+
+#define PCMOD_DBEX	(1UL<<(31-31)) /* set for excahnge */
+
+/*
+ * M32R PCC Map addr
+ */
+
+#define M32R_PCC0_MAPBASE        0x14000000
+#define M32R_PCC1_MAPBASE        0x16000000
+
+#define M32R_PCC_MAPMAX		 0x02000000
+
+#define M32R_PCC_MAPSIZE	 0x00001000 /* XXX */
+#define M32R_PCC_MAPMASK     	(~(M32R_PCC_MAPMAX-1))
+
+#define CFC_IOPORT_BASE		0x1000
+
+#if !defined(CONFIG_PLAT_USRV)
+#define CFC_ATTR_MAPBASE        0x0c014000
+#define CFC_IO_MAPBASE_BYTE     0xac012000
+#define CFC_IO_MAPBASE_WORD     0xac002000
+#else	/* CONFIG_PLAT_USRV */
+#define CFC_ATTR_MAPBASE	0x04014000
+#define CFC_IO_MAPBASE_BYTE	0xa4012000
+#define CFC_IO_MAPBASE_WORD	0xa4002000
+#endif	/* CONFIG_PLAT_USRV */
+
diff -ruN linux-2.4.26.org/arch/m32r/drivers/m5.c linux-2.4.26/arch/m32r/drivers/m5.c
--- linux-2.4.26.org/arch/m32r/drivers/m5.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/arch/m32r/drivers/m5.c	2003-06-13 22:17:10.000000000 +0900
@@ -0,0 +1,913 @@
+/*
+ * Flash Memory Driver for M32700UT-CPU
+ *
+ * [support chips]
+ *  	- M5M29GT320VP
+ *
+ * Copyright (C) 2003   Takeo Takahashi
+ *
+ * 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.
+ *
+ * 2003-02-01: Takeo Takahashi, support M5M29GT320VP page program.
+ *
+ */
+
+#ifndef __KERNEL__
+#  define __KERNEL__
+#endif
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ioctl.h>
+#include <linux/blkpg.h>
+#include <linux/fs.h>
+#include <linux/proc_fs.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/delay.h>
+#include <asm/m32r.h>
+#include <asm/io.h>
+
+#include "m5.h"
+
+static const char version[] = "M5 Flash Driver";
+static const char date[] = __DATE__;
+static const char time[] = __TIME__;
+
+/*
+ * Special function
+ */
+#define M5_SUPPORT_PROBE	1
+#define M5_MAX_ERROR		5
+
+/*
+ * flash memory start address:
+ */
+//#define M5_BASE_ADDR         (0x00000000 + NONCACHE_OFFSET)
+#define M5_BASE_ADDR         (0x00000000 + PAGE_OFFSET)
+#define M5_IDENT_ADDR        (M5_BASE_ADDR + 0)
+
+/*
+ * This driver does not have a real partition block, but
+ * it can support simulation of partition in single chip.
+ */
+#define M5_PARTITIONS        (3)
+static int m5_len[M5_PARTITIONS] = {
+	192 * 1024,	/* 192kB:	0x00000000 - 0x0002ffff */	
+	1088 * 1024,	/* 1088kB:	0x00030000 - 0x0013ffff */
+	2816 * 1024	/* 2816kB:	0x00140000 - 0x003fffff */
+};
+
+static int major = 240;
+static int debug = 2;
+static int led=0;
+static int m5_addr[M5_PARTITIONS];
+static int m5_blk_size[M5_PARTITIONS];
+static int m5_blksize_size[M5_PARTITIONS];
+static int m5_hardsect_size[M5_PARTITIONS];
+static int m5_read_ahead = 1;
+MODULE_PARM(major, "i");
+//MODULE_PARM_DESC(major, "major number");
+MODULE_PARM(debug, "i");
+//MODULE_PARM_DESC(debug, "debug flag");
+MODULE_PARM(led, "i");
+//MODULE_PARM_DESC(led, "LED2 support");
+
+static devfs_handle_t	devfs_handle = NULL;
+#ifdef CONFIG_PROC_FS
+static struct proc_dir_entry *proc_m5;
+#endif
+
+#define MAJOR_NR		major
+#define DEVICE_NAME 		"m5"
+#define DEVICE_NR(device) 	MINOR(device)
+#define DEVICE_NO_RANDOM
+#define DEVICE_OFF(device)
+#define DEVICE_ON(device)
+#define DEVICE_REQUEST 		m5_request
+#include <linux/blk.h>
+
+#define WAIT_TIME	10			/* 10 usec */
+#define WAIT_COUNT	(50000/WAIT_TIME)	/* 50ms = 10us*5000times */
+
+#define SUCCESS 0
+#define FAILED  (-1)
+
+/*
+ * definitions for cache
+ */
+static struct cache {
+	int blk;	/* block number, -1:invalid */
+	int status;	/* cache status */
+#define B_CLEAN	0
+#define B_DIRTY	1
+	m5_t *addr;	/* block base address */
+	m5_t cache[M5_BLOCK_SIZE64];
+} m5_cache;
+#define M5_BLK_NOCACHED()		(m5_cache.blk == -1)
+#define M5_BLK_CACHED(blk)		(m5_cache.blk == (blk))
+#define M5_STATE_DIRTY()		(m5_cache.status == B_DIRTY)
+#define M5_STATE_CLEAN()		(m5_cache.status == B_CLEAN)
+#define M5_MARK_DIRTY()			(m5_cache.status = B_DIRTY)
+#define M5_MARK_CLEAN()			(m5_cache.status = B_CLEAN)
+#define M5_MARK_NOCACHED()		(m5_cache.blk = -1)
+#define M5_MARK_CACHED(blk, addr)	(m5_cache.blk = (blk), \
+					 m5_cache.addr = (addr))
+#define M5_CACHED_BLK			m5_cache.blk
+#define M5_CACHED_ADDR			m5_cache.addr
+#define M5_CACHED_BASE			m5_cache.cache
+
+/*
+ * Prototype declarations
+ */
+static int m5_erase_blk(m5_t *reg);
+static void m5_led_toggle(void);
+static void m5_led_on(void);
+static void m5_led_off(void);
+static m5_t m5_in(m5_t *addr);
+static void m5_out(m5_t val, m5_t *addr);
+static int m5_probe(m5_t *addr);
+static int m5_get_blk_num(m5_t *addr);
+static int m5_get_blk_offset(int blk, m5_t *addr);
+static int m5_get_blk_size(int blk);
+static int m5_read_blk_cache(m5_t *addr);
+static int m5_write_blk_cache(void);
+static int m5_full_status_check(m5_t status, m5_t *reg);
+static void m5_clear_status(m5_t *reg);
+#if 0
+static int m5_status_check(m5_t *reg);
+#endif
+static int m5_wait_for_ready(m5_t *reg);
+static int m5_write_page(m5_t *addr, const m5_t *buf);
+static int m5_write(const m5_t *buf, int offset, int len);
+static int m5_read_page(m5_t *buf, m5_t *addr);
+static int m5_read(m5_t *buf, int offset, int len);
+static int m5_erase_blk(m5_t *addr);
+static void m5_request(request_queue_t *req);
+static int m5_ioctl(struct inode *inode, struct file *fp, unsigned int cmd, unsigned long arg);
+static int m5_open(struct inode *inode, struct file *fp);
+static int m5_release(struct inode *inode, struct file *fp);
+static int proc_m5_read(char *buf, char **start, off_t offset, int len, int *eof, void *unused);
+static int __init m5_init(void);
+static int __init m5_init_module(void);
+static void __exit m5_cleanup_module(void);
+
+/*
+ * special function
+ */
+static inline void m5_led_toggle(void)
+{
+	unsigned short status;
+	if (!led) return;
+	status = inw((unsigned long)PLD_IOLEDCR);
+	if (status & PLD_IOLED_2_ON)
+		status &= ~PLD_IOLED_2_ON;
+	else
+		status |= PLD_IOLED_2_ON;
+	outw(status, (unsigned long)PLD_IOLEDCR);
+}
+
+static inline void m5_led_on(void)
+{
+	unsigned short status;
+	if (!led) return;
+	status = inw((unsigned long)PLD_IOLEDCR);
+	status |= PLD_IOLED_2_ON;
+	outw(status, (unsigned long)PLD_IOLEDCR);
+}
+
+static inline void m5_led_off(void)
+{
+	unsigned short status;
+	if (!led) return;
+	status = inw((unsigned long)PLD_IOLEDCR);
+	status &= ~PLD_IOLED_2_ON;
+	outw(status, (unsigned long)PLD_IOLEDCR);
+}
+
+/*
+ * I/O function
+ */
+static inline m5_t m5_in(m5_t *addr)
+{
+	return *addr;
+}
+
+static inline void m5_out(m5_t val, m5_t *addr)
+{
+	*addr = val;
+}
+
+#if M5_SUPPORT_PROBE
+/*
+ * int m5_probe()
+ *	m5_t *addr:	probed address
+ * 	int SUCCESS: 	supported device
+ *	int FAILED: 	unsupported device
+ */
+static int m5_probe(m5_t *addr)
+{
+#if 1
+	/*
+	 * FIXME: cannot read maker & device codes.
+	 */
+	m5_t val;
+	m5_out(M5_CMD_DEVICE_IDENT, addr);
+	val = m5_in((m5_t *)M5_IDENT_ADDR);
+	val &= 0xff;
+	if (val == M5_MAKER)
+		printk("m5: detected M5M29GT320VP\n");
+	else
+		printk("m5: unknown maker(0x%02x)\n", val);
+	m5_out(M5_CMD_READ_ARRAY, addr);	/* array mode */
+	/* always success */
+	return SUCCESS;
+#else
+
+	int result;
+	m5_t val;
+	unsigned char maker, device;
+
+	result = SUCCESS;
+	m5_out(M5_CMD_DEVICE_IDENT, addr);
+	val = m5_in((m5_t *)M5_IDENT_ADDR);
+	maker = (val >> 16);
+	device = (val & 0xff);
+	if (maker != M5_MAKER) {
+		printk("m5: unknown maker(0x%02x)\n", maker);
+		// result = FAILED;
+		// ignore error
+	}
+ 	if (device != M5_M5M29GT320VP) {
+		printk("m5: unknown device(0x%02x)\n", device);
+		// result = FAILED;
+		// ignore error
+	}
+	if (result != FAILED)
+		printk("m5: detected M5M29GT320VP\n");
+	m5_out(M5_CMD_READ_ARRAY, addr);
+	return result;
+#endif
+}
+#endif	/* M5_SUPPORT_PROBE */
+
+/*
+ * int m5_get_blk_num()
+ *	m5_t *addr:
+ *	blk:	OK, return block number
+ *	-1:	NG
+ */
+static int m5_get_blk_num(m5_t *addr)
+{
+	int blk;
+
+	blk = (((int)addr & 0x0fff0000) >> 16);
+	if (blk > 0x3f) {
+		printk("m5: out of block address (0x%08x)\n", (int)addr);
+		return -1; 
+	}
+	if (blk == 0x3f)
+		blk += (int)(((int)addr & 0x0000e000) >> 13);
+	if (blk > MAX_BLOCK_NUM) {
+		printk("m5: out of block address (addr=0x%08x, blk=%d)\n",
+				(int)addr, blk);
+		return -1;
+	}
+	return blk;
+}
+
+/*
+ * m5_t *m5_get_blk_base()
+ *	return block base address
+ */
+static inline m5_t *m5_get_blk_base(int blk, m5_t *addr)
+{
+	if (blk < 0x3f) return (m5_t *)((int)addr & 0xffff0000);
+	return (m5_t *)((int)addr & 0xffffe000);
+}
+
+/*
+ * int m5_get_blk_offset()
+ *	return offset of specified address in blk
+ */
+static inline int m5_get_blk_offset(int blk, m5_t *addr)
+{
+	if (blk < 0x3f) return ((int)addr & 0xffff);
+	return ((int)addr & 0x1fff);
+}
+
+/*
+ * int m5_get_blk_size()
+ *	return block size in byte
+ */
+static inline int m5_get_blk_size(int blk)
+{
+	if (blk >= 63) return M5_BLOCK_SIZE8;
+	return M5_BLOCK_SIZE64;
+}
+
+/*
+ * cache operations 
+ */
+static int m5_read_blk_cache(m5_t *addr)
+{
+	int blk;
+	int size;
+	int result;
+
+	result = SUCCESS;
+	blk = m5_get_blk_num(addr);
+	if (blk < 0) return FAILED;
+	if (M5_BLK_CACHED(blk))
+		return result;
+	if (M5_STATE_DIRTY()) {		/* cached other block */
+		result = m5_write_blk_cache();
+		if (result != SUCCESS) return result;
+	}
+	/* ok, we can use cache */
+	size = m5_get_blk_size(blk);
+	addr = m5_get_blk_base(blk, addr);
+	memcpy((void *)M5_CACHED_BASE, (void *)addr, size);
+	M5_MARK_CACHED(blk, addr);
+	M5_MARK_CLEAN();
+	return result;
+}
+
+static int m5_write_blk_cache(void)
+{
+	int size;
+	int pages;
+	int i;
+	m5_t *reg, *addr, *buf;
+	int result;
+
+	result = SUCCESS;
+
+	if (M5_BLK_NOCACHED()) 
+		return result;
+	if (! M5_STATE_DIRTY())
+		return result;
+
+	/* we have to write cache */
+	m5_led_on();
+	size = m5_get_blk_size(M5_CACHED_BLK);
+	addr = M5_CACHED_ADDR;
+	buf = M5_CACHED_BASE;
+	reg = addr;
+
+	result = m5_erase_blk(reg);
+	if (result != SUCCESS) return result;
+
+	DEBUG(1, "m5: wrting addr=0x%08x, buf=0x%08x, size=%d\n",\
+		(int)addr, (int)buf, size);
+	for (pages = 0; pages < (size/M5_PAGE_SIZE); pages++) {
+		m5_out(M5_CMD_PROGRAM_PAGE, reg);
+		for (i = 0; i < (M5_PAGE_SIZE/sizeof(m5_t)); i++)
+			*addr++ = *buf++;
+		if (m5_wait_for_ready(reg) != SUCCESS)
+			result = FAILED;
+		reg = addr;
+	}
+	m5_out(M5_CMD_READ_ARRAY, reg);	/* array mode */
+	if (result == SUCCESS)
+		M5_MARK_CLEAN();
+	m5_led_off();
+	return result;	/* SUCCESS or FAILED */
+}
+
+/*
+ * int m5_full_status_check()
+ *	m5_t status:	status
+ *	m5_t *reg:	bank address
+ *	SUCCESS:	no error
+ *	FAILED:		error happen
+ */
+static inline int m5_full_status_check(m5_t status, m5_t *reg)
+{
+	if ((status & M5_STATUS_PROGRAM) &&
+	    (status & M5_STATUS_ERASE)) {
+		printk("m5: command sequence error (addr=0x%08x, sts=0x%02x).\n",
+			(int)reg, status);
+		return FAILED;
+	}
+   	if(status & M5_STATUS_ERASE){
+      		printk("m5: erase error (addr=0x%08x, sts=0x%02x).\n",
+			(int)reg, status);
+      		return FAILED;
+   	}
+   	if(status & M5_STATUS_PROGRAM){
+      		printk("m5: program write error (addr=0x%08x, sts=0x%02x).\n",
+			(int)reg, status);
+      		return FAILED;
+   	}
+   	if(status & M5_STATUS_BLOCK){
+      		printk("m5: block write error (addr=0x%08x, sts=0x%02x).\n",
+			(int)reg, status);
+      		return FAILED;
+   	}
+	/* passed */
+   	return SUCCESS;
+}                     
+
+/*
+ * void m5_clear_status()
+ *	m5_t *reg:	address of status register
+ */
+static inline void m5_clear_status(m5_t *reg)
+{
+	m5_out(M5_CMD_CLEAR_STATUS, reg);
+}
+
+#if 0
+/*
+ * int m5_status_check()
+ *	m5_t *reg:	address of command register
+ *	SUCCESS:	ready now
+ *	FAILED:		error happen while waiting
+ */
+static int m5_status_check(m5_t *reg)
+{
+	m5_t status;
+	int result;
+	int n;
+	static int error_count = 0;
+
+	m5_out(M5_CMD_READ_STATUS, reg);
+	for (n = WAIT_COUNT; n > 0; n--) {
+		status = m5_in(reg);
+		if (status & M5_STATUS_READY)
+			break;
+		udelay(WAIT_TIME);
+	}
+	if (n <= 0) {
+		if (error_count++ < M5_MAX_ERROR)
+			printk("m5: time out (sts=0x%02x).\n", status);
+		m5_clear_status(reg);
+		return FAILED;
+	}
+	result = m5_full_status_check(status, reg);
+	if (result != SUCCESS) {
+		m5_clear_status(reg);
+		return FAILED;
+	}
+	m5_clear_status(reg);
+	return SUCCESS;
+}
+#endif
+
+/*
+ * int m5_wait_for_ready()
+ *	m5_t *reg:	address of command register
+ *	SUCCESS:	ready now
+ *	FAILED:		error happen while waiting
+ */
+static int m5_wait_for_ready(m5_t *reg)
+{
+	m5_t status;
+	int result;
+	int n;
+	static int error_count = 0;
+
+	for (n = WAIT_COUNT; n > 0; n--) {
+		status = m5_in(reg);
+		if (status & M5_STATUS_READY)
+			break;
+		udelay(WAIT_TIME);
+	}
+	if (n <= 0) {
+		if (error_count++ < M5_MAX_ERROR)
+			printk("m5: time out (sts=0x%02x).\n", status);
+		m5_clear_status(reg);
+		return FAILED;
+	}
+	result = m5_full_status_check(status, reg);
+	if (result != SUCCESS) {
+		m5_clear_status(reg);
+		return FAILED;
+	}
+	return SUCCESS;
+}
+
+/*
+ * int m5_write_page(m5_t *addr, const m5_t *buf)
+ *	m5_t *addr:	sector address
+ *	m5_t *buf:	buffer address
+ *	SUCCESS:	ok
+ *	FAILED:		error
+ */
+static int m5_write_page(m5_t *addr, const m5_t *buf)
+{
+	int blk;
+	int offset;
+
+	if (((int)addr % M5_PAGE_SIZE) != 0)
+		printk("m5: invalid sector addres (0x%08x)\n", (int)addr);
+
+	if (m5_read_blk_cache(addr) != SUCCESS)
+		return FAILED;
+	if ((blk = m5_get_blk_num(addr)) < 0)
+		return FAILED;
+	offset = m5_get_blk_offset(blk, addr);
+	memcpy((void *)M5_CACHED_BASE + offset, (void *)buf, M5_PAGE_SIZE);
+	M5_MARK_DIRTY();
+	return SUCCESS;
+}
+	
+/*
+ * int m5_write(const m5_t *buf, int offset, int len)
+ *	m5_t *buf:	write buffer address
+ *	int offset:	offset from flash base address
+ *	int len:	write length
+ *	SUCCESS:	ok
+ *	FAILE:		error
+ */
+static int m5_write(const m5_t *buf, int offset, int len)
+{
+	m5_t *addr;
+	int result;
+
+	if (len % M5_PAGE_SIZE) {
+		printk("m5: invalid write size (%d).\n", len);
+		return FAILED;
+	}
+	addr = (m5_t *)(m5_addr[MINOR(CURRENT_DEV)] + offset);
+
+	DEBUG(1, "m5: writing 0x%08x - 0x%08x\n", \
+		(int)addr, (int)addr + len);
+
+	for (; len > 0; len -= M5_PAGE_SIZE) {
+		result = m5_write_page(addr, buf);
+		if (result != SUCCESS)
+			return result;
+		addr = (m5_t *)((int)addr + M5_PAGE_SIZE);
+		buf = (m5_t *)((int)buf + M5_PAGE_SIZE);
+	}
+	return SUCCESS;
+}
+
+/*
+ * int m5_read_page()
+ *	m5_t *buf:	read buffer address
+ *	m5_t *addr:	page address
+ *	SUCCESS:	ok
+ *	FAILED:		error
+ */
+static int m5_read_page(m5_t *buf, m5_t *addr)
+{
+	int blk;
+	int offset;
+
+	if ((blk = m5_get_blk_num(addr)) < 0)
+		return FAILED;
+	if (M5_BLK_CACHED(blk)) {
+		offset = m5_get_blk_offset(blk, addr);
+		memcpy((void *)buf, (void *)M5_CACHED_BASE + offset,
+				M5_PAGE_SIZE);
+	} else {
+		/* read from flash memory directory */
+		memcpy((void *)buf, (void *)addr, M5_PAGE_SIZE);
+	}
+	return SUCCESS;
+}
+
+/*
+ * int m5_read()
+ *	m5_t *buf:		read buffer address
+ *	int offset:		offset from flash base address
+ *	int len:		read length
+ *	SUCCESS:		ok
+ *	FAILED:			error
+ */
+static int m5_read(m5_t *buf, int offset, int len)
+{
+	m5_t *addr;
+
+	if (len % M5_PAGE_SIZE) {
+		printk("m5: invalid read size (%d).\n", len);
+		return FAILED;
+	}
+
+	addr = (m5_t *)(m5_addr[MINOR(CURRENT_DEV)] + offset);
+
+	DEBUG(1, "m5: reading 0x%08x - 0x%08x\n", \
+		(int)addr, (int)addr + len);
+
+	for (; len > 0; len -= M5_PAGE_SIZE) {
+		if (m5_read_page(buf, addr) != SUCCESS)
+			return FAILED;
+		buf = (m5_t *)((int)buf + M5_PAGE_SIZE);
+		addr = (m5_t *)((int)addr + M5_PAGE_SIZE);
+	}
+	return SUCCESS;
+}
+
+/*
+ * int m5_erase_blk()
+ *	m5_t *addr:
+ */
+static int m5_erase_blk(m5_t *addr)
+{
+	int result;
+
+	DEBUG(1, "m5: erasing addr=0x%08x\n", (int)addr);
+	m5_out(M5_CMD_BLOCK_ERASE, addr);
+	m5_out(M5_CMD_CONFIRM, addr);
+	result = m5_wait_for_ready(addr);
+	return result;
+}
+
+/*
+ * void m5_request()
+ *	request_queue_t *req:	I/O request
+ *	end_request(0):	error (-EIO)
+ *	end_request(1): ok
+ */
+static void m5_request(request_queue_t *req)
+{
+    	unsigned int minor;
+    	int offset;
+	int len;
+	static int error_count = 0;
+
+	sti();
+	while (1) {
+		INIT_REQUEST;
+		minor = MINOR(CURRENT_DEV);
+		if (minor >= M5_PARTITIONS) {
+	    		printk( "m5: out of partition (%d)\n", minor );
+	    		end_request(0);
+	    		continue;
+		}
+		offset = CURRENT->sector * m5_hardsect_size[minor];
+		len = (CURRENT->current_nr_sectors *
+			m5_hardsect_size[minor]);
+		if ((offset + len) > m5_len[minor]) {
+	    		printk( "m5: out of sector (sector=%d, nr=%d)\n",
+				(int)(CURRENT->sector),
+				(int)(CURRENT->current_nr_sectors));
+	    		end_request(0);
+	    		continue;
+		}
+		switch(CURRENT->cmd) {
+	    	case READ:
+			if (m5_read((m5_t *)CURRENT->buffer,
+					offset, len) != SUCCESS)
+		    		end_request(0);
+			else
+		    		end_request(1);
+			break;
+	    	case WRITE:
+			if (m5_write((m5_t *)(CURRENT->buffer),
+					offset, len) != SUCCESS)
+		    		end_request(0);
+			else
+		    		end_request(1);
+                	break;
+	    	default:
+			if (error_count++ < M5_MAX_ERROR) {
+				printk("m5: invalid I/O request(%d)\n",
+					CURRENT->cmd);
+			}
+			end_request(0);
+			break;
+		}
+	}
+}
+
+/*
+ * int m5_ioctl()
+ *	struct inode *inode:
+ *	struct file *file:
+ *	unsigned int cmd:
+ *	unsigned long arg:
+ */
+static int m5_ioctl(struct inode *inode, struct file *fp, unsigned int cmd, unsigned long arg)
+{
+	int size;
+
+	DEBUG(2, "m5_ioctl()\n");
+    	switch (cmd) {
+      	case BLKGETSIZE:
+		if (!arg) return -EINVAL;
+		size = (1024 * m5_blk_size[MINOR(inode->i_rdev)] /
+			m5_hardsect_size[MINOR(inode->i_rdev)]);
+		return put_user(size, (long *)arg);
+      	case BLKFLSBUF:
+		if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+		fsync_dev(inode->i_rdev);
+		invalidate_buffers(inode->i_rdev);
+		return 0;
+	case BLKRRPART:
+		return -EINVAL;
+
+	case BLKRAGET:
+	case BLKRASET:
+	case BLKGETSIZE64:
+	case BLKROSET:
+	case BLKROGET:
+      	case BLKSSZGET:
+		return blk_ioctl(inode->i_rdev, cmd, arg);
+      	default:
+		printk( "m5: unsupported ioctl(0x%08x)\n", cmd);
+		return -EINVAL;
+    	}
+    	return 0;
+}
+
+/*
+ * int m5_open()
+ *	struct inode *inode:
+ *	struct file *fp:
+ */
+static int m5_open(struct inode *inode, struct file *fp)
+{
+    	if (DEVICE_NR(inode->i_rdev) >= M5_PARTITIONS) return -ENXIO;
+    	MOD_INC_USE_COUNT;
+    	return 0;
+}
+
+/*
+ * int m5_release()
+ *	struct inode *inode:
+ *	struct file *fp:
+ */
+static int m5_release(struct inode *inode, struct file *fp)
+{
+    	sync_dev(inode->i_rdev);
+    	MOD_DEC_USE_COUNT;
+    	return 0;
+}
+
+#ifdef CONFIG_PROC_FS
+/*
+ * int proc_m5_read()
+ *	char *buf:
+ *	char **start:
+ *	off_t offset:
+ *	int len:
+ *	int *eof:
+ *	void *unused:
+ */
+static int proc_m5_read(char *buf, char **start, off_t offset, int len, int *eof, void *unused)
+{
+	len = sprintf(buf, "partition: %d\n", M5_PARTITIONS);
+	return len;
+}
+#endif
+
+static struct block_device_operations m5_fops = {
+	open:		m5_open,
+	release:	m5_release,
+	ioctl:		m5_ioctl,
+	/* check_media_change: */
+	/* revalidate: */
+	owner:		THIS_MODULE,
+};
+
+/*
+ * int m5_init()
+ */
+static int __init m5_init(void)
+{
+	int i;
+	int result;
+
+	result = -EIO;
+
+	printk("%s (%s %s)\n", version, date, time);
+#if M5_SUPPORT_PROBE
+	if (m5_probe((m5_t *)M5_BASE_ADDR) != SUCCESS)
+		return result;
+#endif	/* M5_SUPPORT_PROBE */
+
+	if (register_blkdev(major, DEVICE_NAME, &m5_fops) ) {
+		printk("m5: can not not get major %d", major);
+		return result;
+	}
+
+	if (devfs_register_blkdev(major, DEVICE_NAME, &m5_fops) ) {
+		printk("m5: can not not get major %d", major);
+		goto fail_devfs;
+	}
+	devfs_handle = devfs_mk_dir(NULL, "m5", NULL);
+	devfs_register_series(devfs_handle, "%u", M5_PARTITIONS,
+			      DEVFS_FL_DEFAULT, major, 0,
+			      S_IFBLK | S_IRUSR | S_IWUSR,
+			      &m5_fops, NULL);
+
+	for (i = 0; i < M5_PARTITIONS; i++) {
+		if (i) {
+			m5_addr[i] = m5_addr[i-1] + m5_len[i-1];
+		} else { 
+			m5_addr[i] = M5_BASE_ADDR;
+		}
+		m5_blk_size[i] = m5_len[i]/1024;	/* KB order */
+		m5_blksize_size[i] = BLOCK_SIZE;  	/* 1024 byte */
+		m5_hardsect_size[i] = BLOCK_SIZE/2;	/* 512 byte */
+	}
+	/* defined in ll_rw_blk.c */
+	blk_size[major] = m5_blk_size;
+	blksize_size[major] = m5_blksize_size;
+	hardsect_size[major] = m5_hardsect_size;
+	read_ahead[major] = m5_read_ahead;
+
+	blk_init_queue(BLK_DEFAULT_QUEUE(major), &m5_request);
+
+	for (i = 0; i < M5_PARTITIONS; i++)
+		register_disk(  NULL, MKDEV(major,i), 1, 
+				&m5_fops, m5_len[i]>>9 );
+
+#ifdef CONFIG_PROC_FS
+#if	1
+	proc_m5 = proc_mkdir("m5", proc_root_driver);
+	if (!proc_m5) {
+		printk(KERN_ERR "m5: unable to register driver/m5\n");
+		goto fail_proc;
+	}
+	create_proc_read_entry("0", 0, proc_m5, proc_m5_read, 0);
+	create_proc_read_entry("1", 0, proc_m5, proc_m5_read, 0);
+	create_proc_read_entry("2", 0, proc_m5, proc_m5_read, 0);
+#else
+	proc_m5 = create_proc_entry("driver/m5", 666, 0);
+	if (!proc_m5) {
+		printk(KERN_ERR "m5: unable to register driver/m5\n");
+		goto fail_proc;
+	}
+	proc_m5->read_proc = proc_m5_read;
+#endif
+#endif
+
+	printk("m5: Major=%d Partitions=%d\n", major,M5_PARTITIONS);
+	for (i = 0; i < M5_PARTITIONS; i++) {
+	printk("  %d: 0x%08x-0x%08x (all=%dKB,blk=%dB,sect=%dB,ahead=%d)\n",
+	        i, m5_addr[i],
+		m5_addr[i] + m5_len[i], 
+		m5_blk_size[i],
+		m5_blksize_size[i],
+		m5_hardsect_size[i],
+		m5_read_ahead);
+	}
+
+	/* clear cache */
+	M5_MARK_CLEAN();
+	M5_MARK_NOCACHED();
+
+	m5_led_off();
+	return 0;
+
+fail_proc:
+	devfs_unregister(devfs_handle);
+fail_devfs:
+	unregister_blkdev(major, DEVICE_NAME);
+	return result;
+}
+
+static int __init m5_init_module(void)
+{
+    return m5_init();
+}
+
+static void __exit m5_cleanup_module(void)
+{
+    	int i;
+ 
+    	for (i = 0 ; i < M5_PARTITIONS; i++) {
+		fsync_dev(MKDEV(major, i));	/* flush buffer */
+      		destroy_buffers(MKDEV(major, i));
+	}
+	m5_write_blk_cache();		/* flush m5 cache */
+    	devfs_unregister(devfs_handle);
+    	unregister_blkdev(major, DEVICE_NAME);
+#ifdef CONFIG_PROC_FS
+	remove_proc_entry("0", proc_m5);
+	remove_proc_entry("1", proc_m5);
+	remove_proc_entry("2", proc_m5);
+	remove_proc_entry("m5", proc_root_driver);
+#endif
+    	blk_cleanup_queue(BLK_DEFAULT_QUEUE(major));
+	blk_size[major] = NULL;
+	blksize_size[major] = NULL;
+	hardsect_size[major] = NULL;
+	read_ahead[major] = 0;
+}
+
+module_init(m5_init_module);
+module_exit(m5_cleanup_module);
+
+MODULE_AUTHOR("Takeo Takahashi");
+MODULE_DESCRIPTION("M5 Flash Driver for M32700UT-CPU");
+MODULE_LICENSE("GPL");
+EXPORT_NO_SYMBOLS;
+
diff -ruN linux-2.4.26.org/arch/m32r/drivers/m5.h linux-2.4.26/arch/m32r/drivers/m5.h
--- linux-2.4.26.org/arch/m32r/drivers/m5.h	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/arch/m32r/drivers/m5.h	2003-06-13 22:17:10.000000000 +0900
@@ -0,0 +1,73 @@
+/*
+ * Flash Memory Driver for M32700UT-CPU
+ *
+ * Copyright 2003 (C)   Takeo Takahashi
+ *
+ * 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.
+ *
+ * 2003-02-01: 	Takeo Takahashi, support M5M29GT320VP.
+ */
+
+#include <asm/m32r.h>
+
+#ifdef __KERNEL__
+#undef DEBUG
+/* debug routine:
+ *   0x00000001: print debug information
+ */
+#  define DEBUG(n, args...) if ((n) & debug) \
+	printk(KERN_DEBUG args)
+#endif	/* __KERNEL__ */
+
+/*
+ * data type to access flash memory
+ */
+typedef volatile unsigned short m5_t;
+
+/*
+ * - Page program buffer size in byte
+ * - block size in byte
+ * - number of block
+ */
+#define M5_PAGE_SIZE		(256)
+#define M5_BLOCK_SIZE8		(8*1024)
+#define M5_BLOCK_SIZE64		(64*1024)
+#define MAX_BLOCK_NUM		70
+
+/*
+ * Software commands
+ */
+#define M5_CMD_READ_ARRAY            0xff
+#define M5_CMD_DEVICE_IDENT          0x90
+#define M5_CMD_READ_STATUS           0x70
+#define M5_CMD_CLEAR_STATUS          0x50
+#define M5_CMD_BLOCK_ERASE           0x20
+#define M5_CMD_CONFIRM               0xd0
+#define M5_CMD_PROGRAM_BYTE          0x40
+#define M5_CMD_PROGRAM_WORD          M5_CMD_PROGRAM_BYTE
+#define M5_CMD_PROGRAM_PAGE          0x41
+#define M5_CMD_SINGLE_LOAD_DATA      0x74
+#define M5_CMD_BUFF2FLASH            0x0e
+#define M5_CMD_FLASH2BUFF            0xf1
+#define M5_CMD_CLEAR_BUFF            0x55
+#define M5_CMD_SUSPEND               0xb0
+#define M5_CMD_RESUME                0xd0
+
+/*
+ * Status
+ */
+#define M5_STATUS_READY              0x80 /* 0:busy 1:ready */
+#define M5_STATUS_SUSPEND            0x40 /* 0:progress/complete 1:suspend */
+#define M5_STATUS_ERASE              0x20 /* 0:pass 1:error */
+#define M5_STATUS_PROGRAM            0x10 /* 0:pass 1:error */
+#define M5_STATUS_BLOCK              0x08 /* 0:pass 1:error */
+
+/*
+ * Device Code
+ */
+#define M5_MAKER		(0x1c)
+#define M5_M5M29GT320VP		(0x20)
+#define M5_M5M29GB320VP		(0x21)
diff -ruN linux-2.4.26.org/arch/m32r/drivers/m5drv.c linux-2.4.26/arch/m32r/drivers/m5drv.c
--- linux-2.4.26.org/arch/m32r/drivers/m5drv.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/arch/m32r/drivers/m5drv.c	2003-06-13 22:17:10.000000000 +0900
@@ -0,0 +1,664 @@
+/*
+ * MTD chip driver for M5M29GT320VP
+ *
+ * Copyright (C) 2003   Takeo Takahashi
+ *
+ * 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.
+ *
+ * $Id: m5drv.c,v 1.1 2003/06/13 13:17:10 takata Exp $
+ */
+
+#ifndef __KERNEL__
+#  define __KERNEL__
+#endif
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/cfi.h>
+#include <linux/delay.h>
+
+#define M5DRV_DEBUG(n, args...) if ((n) & m5drv_debug) printk(KERN_DEBUG args)
+
+#undef UNLOCK_BEFORE_ERASE
+
+#define M5DRV_PAGE_SIZE		(256)		/* page program size */
+#define M5DRV_BLOCK_SIZE8	(8*1024)	/* 8K block size in byte */
+#define M5DRV_BLOCK_SIZE64	(64*1024)	/* 64K block size in byte */
+#define M5DRV_MAX_BLOCK_NUM	70		/* number of blocks */
+#define M5DRV_ERASE_REGION	2		/* 64KB and 8KB */
+
+/*
+ * Software commands
+ */
+#define CMD_READ_ARRAY          0xff
+#define CMD_DEVICE_IDENT        0x90
+#define CMD_READ_STATUS         0x70
+#define CMD_CLEAR_STATUS        0x50
+#define CMD_BLOCK_ERASE         0x20
+#define CMD_CONFIRM             0xd0
+#define CMD_PROGRAM_BYTE        0x40
+#define CMD_PROGRAM_WORD        CMD_PROGRAM_BYTE
+#define CMD_PROGRAM_PAGE        0x41
+#define CMD_SINGLE_LOAD_DATA    0x74
+#define CMD_BUFF2FLASH          0x0e
+#define CMD_FLASH2BUFF          0xf1
+#define CMD_CLEAR_BUFF          0x55
+#define CMD_SUSPEND             0xb0
+#define CMD_RESUME              0xd0
+#define IDENT_OFFSET        	0	/* indent command offset */
+
+/*
+ * Status
+ */
+#define STATUS_READY              0x80 /* 0:busy 1:ready */
+#define STATUS_SUSPEND            0x40 /* 0:progress/complete 1:suspend */
+#define STATUS_ERASE              0x20 /* 0:pass 1:error */
+#define STATUS_PROGRAM            0x10 /* 0:pass 1:error */
+#define STATUS_BLOCK              0x08 /* 0:pass 1:error */
+
+/*
+ * Device Code
+ */
+#define MAKER		(0x1c)
+#define M5M29GT320VP	(0x20)
+#define M5M29GB320VP	(0x21)
+
+static const char version[] = "M5DRV Flash Driver";
+static const char date[] = __DATE__;
+static const char time[] = __TIME__;
+static int m5drv_debug = 0;
+MODULE_PARM(m5drv_debug, "i");
+
+struct m5drv_info {
+	struct flchip *chip;
+	int chipshift;
+	int numchips;
+	struct flchip chips[1];
+	unsigned char buf[M5DRV_BLOCK_SIZE64];
+#define M5BUF	(m5drv->buf)
+};
+
+struct mtd_info *m5drv_probe(struct map_info *map);
+static int m5drv_probe_map(struct map_info *map, struct mtd_info *mtd);
+static int m5drv_wait(struct map_info *map, struct flchip *chip, loff_t adr);
+static void m5drv_release(struct flchip *chip);
+static int m5drv_query_blksize(loff_t ofs);
+static int m5drv_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
+static int m5drv_read_oneblock(struct map_info *map, loff_t from);
+static int m5drv_write(struct mtd_info *mtd, loff_t adr, size_t len, size_t *retlen, const u_char *buf);
+static int m5drv_write_oneblock(struct map_info *map, loff_t adr, size_t len, const u_char *buf);
+static int m5drv_write_onepage(struct map_info *map, struct flchip *chip, unsigned long adr, const u_char *buf);
+static int m5drv_erase(struct mtd_info *mtd, struct erase_info *instr);
+static int m5drv_do_wait_for_ready(struct map_info *map, struct flchip *chip, unsigned long adr);
+static int m5drv_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr);
+static void m5drv_sync(struct mtd_info *mtd);
+static int m5drv_suspend(struct mtd_info *mtd);
+static void m5drv_resume(struct mtd_info *mtd);
+static void m5drv_destroy(struct mtd_info *mtd);
+#ifdef UNLOCK_BEFORE_ERASE
+static void m5drv_unlock_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr);
+#endif
+
+static struct mtd_chip_driver m5drv_chipdrv = {
+	probe:		m5drv_probe,
+	destroy:	m5drv_destroy,
+	name:		"m5drv",
+	module:		THIS_MODULE
+};
+	
+struct mtd_info *m5drv_probe(struct map_info *map)
+{
+	struct mtd_info *mtd = NULL;
+	struct m5drv_info *m5drv = NULL;
+	int width;
+
+	mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
+	if (!mtd) {
+		printk("m5drv: can not allocate memory for mtd_info\n");
+		return NULL;
+	}
+
+	m5drv = kmalloc(sizeof(*m5drv), GFP_KERNEL);
+	if (!m5drv) {
+		printk("m5drv: can not allocate memory for m5drv_info\n");
+		kfree(mtd);
+		return NULL;
+	}
+
+	memset(mtd, 0, sizeof(*mtd));
+	width = m5drv_probe_map(map, mtd);
+	if (!width) {
+		printk("m5drv: m5drv_probe_map error (width=%d)\n", width);
+		kfree(mtd);
+		kfree(m5drv);
+		return NULL;
+	}
+	mtd->priv = map;
+	mtd->type = MTD_OTHER;
+	mtd->erase = m5drv_erase;
+	mtd->read = m5drv_read;
+	mtd->write = m5drv_write;
+	mtd->sync = m5drv_sync;
+	mtd->suspend = m5drv_suspend;
+	mtd->resume = m5drv_resume;
+	mtd->flags = MTD_CAP_NORFLASH;	/* ??? */
+	mtd->name = map->name;
+
+	memset(m5drv, 0, sizeof(*m5drv));
+	m5drv->chipshift = 23;
+	m5drv->numchips = 1;
+	m5drv->chips[0].start = 0;
+	m5drv->chips[0].state = FL_READY;
+	m5drv->chips[0].mutex = &m5drv->chips[0]._spinlock;
+	m5drv->chips[0].word_write_time = 0;
+	init_waitqueue_head(&m5drv->chips[0].wq);
+	spin_lock_init(&m5drv->chips[0]._spinlock);
+
+	map->fldrv = &m5drv_chipdrv;
+	map->fldrv_priv = m5drv;
+
+	MOD_INC_USE_COUNT;
+	return mtd;
+}
+
+static int m5drv_probe_map(struct map_info *map, struct mtd_info *mtd)
+{
+	u16 tmp;
+	u16 maker, device;
+	int width = 2;
+	struct mtd_erase_region_info *einfo;
+
+	map->write16(map, CMD_READ_ARRAY, IDENT_OFFSET);
+	tmp = map->read16(map, IDENT_OFFSET);
+	map->write16(map, CMD_DEVICE_IDENT, IDENT_OFFSET);
+	maker = map->read16(map, IDENT_OFFSET);
+	maker &= 0xff;
+	if (maker == MAKER) {
+		/* FIXME: check device */
+		device = maker >> 8;
+		printk("m5drv: detected M5M29GT320VP\n");
+		einfo = kmalloc(sizeof(*einfo) * M5DRV_ERASE_REGION, GFP_KERNEL);
+		if (!einfo) {
+			printk("m5drv: cannot allocate memory for erase_region\n");
+			return 0;
+		}
+		/* 64KB erase block (blk no# 0-62) */
+		einfo[0].offset = 0;
+		einfo[0].erasesize = 0x8000 * width;
+		einfo[0].numblocks = (7 + 8 + 24 + 24);
+		/* 8KB erase block (blk no# 63-70) */
+		einfo[1].offset = 0x3f0000;
+		einfo[1].erasesize = 0x1000 * width;
+		einfo[1].numblocks = (2 + 8);
+		mtd->numeraseregions = M5DRV_ERASE_REGION;
+		mtd->eraseregions = einfo;
+		mtd->size = 0x200000 * width;		/* total 4MB */
+		/*
+		 * mtd->erasesize is used in parse_xxx_partitions.
+		 * last erase block has a partition table.
+		 */
+		mtd->erasesize = 0x8000 * width;
+		return width;
+	} else if (map->read16(map, IDENT_OFFSET) == CMD_DEVICE_IDENT) {
+		printk("m5drv: looks like RAM\n");
+		map->write16(map, tmp, IDENT_OFFSET);
+	} else {
+		printk("m5drv: can not detect flash memory (0x%04x)\n", maker);
+	}
+	map->write16(map, CMD_READ_ARRAY, IDENT_OFFSET);
+	return 0;
+}
+ 
+static int m5drv_query_blksize(loff_t ofs)
+{
+	int blk;
+	
+	blk = ofs >> 16;
+	if (blk > 0x3f) {
+		printk("m5drv: out of block address (0x%08x)\n", (u32)ofs);
+		return M5DRV_BLOCK_SIZE64;
+	}
+	if (blk == 63) blk += ((ofs & 0x0000e000) >> 13);
+	if (blk > M5DRV_MAX_BLOCK_NUM) {
+		printk("m5drv: out of block address (0x%08x)\n", (u32)ofs);
+		return M5DRV_BLOCK_SIZE64;
+	}
+	return ((blk >= 63)? M5DRV_BLOCK_SIZE8:M5DRV_BLOCK_SIZE64);
+}
+
+static int m5drv_wait(struct map_info *map, struct flchip *chip, loff_t adr)
+{
+	__u16 status;
+	unsigned long timeo;
+	DECLARE_WAITQUEUE(wait, current);
+
+ 	timeo = jiffies + HZ;
+	adr &= ~1;	/* align 2 */
+
+retry:
+	spin_lock_bh(chip->mutex);
+
+	switch (chip->state) {
+	case FL_READY:
+		map->write16(map, CMD_READ_STATUS, adr);
+		chip->state = FL_STATUS;
+	case FL_STATUS:
+		status = map->read16(map, adr);
+		if ((status & STATUS_READY) != STATUS_READY) {
+			udelay(100);
+		}
+		break;
+	default:
+		printk("m5drv: waiting for chip\n");
+		if (time_after(jiffies, timeo)) { /* jiffies is after timeo */
+			set_current_state(TASK_INTERRUPTIBLE);
+			add_wait_queue(&chip->wq, &wait);
+			spin_unlock_bh(chip->mutex);
+			schedule();
+			remove_wait_queue(&chip->wq, &wait);
+			spin_lock_bh(chip->mutex);	// by takeo
+			if (signal_pending(current)) {
+				printk("m5drv: canceled\n");
+				map->write16(map, CMD_CLEAR_STATUS, adr);
+				map->write16(map, CMD_READ_ARRAY, adr);
+				chip->state = FL_READY;
+				return -EINTR;
+			}
+		}
+		timeo = jiffies + HZ;
+		goto retry;
+	}
+	map->write16(map, CMD_READ_ARRAY, adr);
+	chip->state = FL_READY;
+	return 0;
+}
+
+static void m5drv_release(struct flchip *chip)
+{
+	M5DRV_DEBUG(1, "m5drv_release\n");
+	wake_up(&chip->wq);
+	spin_unlock_bh(chip->mutex);
+}
+
+static int m5drv_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
+{
+	struct map_info *map = mtd->priv;
+	struct m5drv_info *m5drv = map->fldrv_priv;
+	int chipnum;
+	int ret;
+
+	*retlen = 0;
+
+	chipnum = (from >> m5drv->chipshift);
+	if (chipnum >= m5drv->numchips) {
+		printk("m5drv: out of chip number (%d)\n", chipnum);
+		return -EIO;
+	}
+
+	/* We don't support erase suspend */
+	ret = m5drv_wait(map, &m5drv->chips[chipnum], from);
+	if (ret < 0) return ret;
+
+	map->copy_from(map, buf, from, len);
+
+	m5drv_release(&m5drv->chips[chipnum]);
+	*retlen = len;
+	return 0;
+}
+
+static int m5drv_read_oneblock(struct map_info *map, loff_t from)
+{
+	struct m5drv_info *m5drv = map->fldrv_priv;
+	int ofs;
+	int ret;
+	int blksize;
+	int chipnum;
+
+	M5DRV_DEBUG(1, "m5drv_read_oneblock(0x%08x)\n", (u32)from);
+	chipnum = (from >> m5drv->chipshift);
+	blksize = m5drv_query_blksize(from);
+	ofs = (from & ~(blksize - 1));
+
+	ret = m5drv_wait(map, &m5drv->chips[chipnum], from);
+	if (ret < 0) return ret;
+
+	map->copy_from(map, M5BUF, ofs, blksize);
+
+	m5drv_release(&m5drv->chips[chipnum]);
+	return 0;
+}
+
+static int m5drv_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
+{
+	struct map_info *map = mtd->priv;
+	struct m5drv_info *m5drv = map->fldrv_priv;
+	int ret = 0;
+	int blksize;
+	int chipnum;
+	int thislen;
+
+	M5DRV_DEBUG(1, "m5drv_write(to=0x%08x, len=%d, buf=0x%08x\n", (u32)to, (u32)len, (u32)buf);
+	*retlen = 0;
+	blksize = m5drv_query_blksize(to);
+	chipnum = (to >> m5drv->chipshift);
+
+	/*
+	 * we does not support byte/word program yet.
+	 */
+	for (thislen = len; thislen > 0; thislen -= blksize) {
+		thislen = ((thislen >= blksize)? blksize:thislen);
+		ret = m5drv_write_oneblock(map, to, thislen, buf);
+		if (ret < 0) return ret;
+		to += blksize;
+		buf += blksize;
+		*retlen += thislen;
+	}
+	return 0;
+}
+
+static int m5drv_write_oneblock(struct map_info *map, loff_t adr, size_t len, const u_char *buf)
+{
+	struct m5drv_info *m5drv = map->fldrv_priv;
+	int ofs;
+	int blksize;
+	int ret;
+	int chipnum;
+	int i;
+
+	M5DRV_DEBUG(1, "m5drv_write_oneblock(0x%08x, %d)\n", (u32)adr, (u32)len);
+	chipnum = (adr >> m5drv->chipshift);
+	ret = m5drv_read_oneblock(map, adr);
+	if (ret < 0) return ret;
+	blksize = m5drv_query_blksize(adr);
+	ofs = (adr & (blksize - 1));
+	adr = adr & ~(blksize - 1);
+	memcpy(M5BUF + ofs, buf, len);	/* copy to block buffer */
+#if 0	/*
+	 * FIXME: erasing is unnecessary.
+	 */
+	ret = m5drv_erase_oneblock(map, &m5drv->chips[chipnum], adr);
+	if (ret < 0) return ret;
+#endif
+	for (i = 0; i < len; i += M5DRV_PAGE_SIZE) {
+		ret = m5drv_write_onepage(map, &m5drv->chips[chipnum], adr, M5BUF+i);
+		if (ret < 0) return ret;
+		adr += M5DRV_PAGE_SIZE;
+	}
+	return 0;
+}
+
+static int m5drv_write_onepage(struct map_info *map, struct flchip *chip, unsigned long adr, const u_char *buf)
+{
+	int ret;
+	int i;
+	u_short data;
+	long padr;	/* page address */
+	u_short status;
+	int chipnum;
+	struct m5drv_info *m5drv = map->fldrv_priv;
+
+	M5DRV_DEBUG(1, "m5drv_write_onepage(0x%08x, 0x%08x)\n", (u32)adr, (u32)buf);
+	padr = adr;
+	padr &= ~1;	/* align 2 */
+	chipnum = (adr >> m5drv->chipshift);
+
+	ret = m5drv_wait(map, chip, padr);
+	if (ret < 0) return ret;
+
+	map->write16(map, CMD_PROGRAM_PAGE, padr);
+	chip->state = FL_WRITING;
+	for (i = 0; i < M5DRV_PAGE_SIZE; i += map->buswidth) {
+		data = ((*buf << 8)| *(buf + 1));
+		/*
+		 * FIXME: convert be->le ?
+		 */
+		map->write16(map, data, adr);
+		adr += map->buswidth;
+		buf += map->buswidth;
+	}
+
+	ret = m5drv_do_wait_for_ready(map, chip, padr);
+	if (ret < 0) {
+		m5drv_release(&m5drv->chips[chipnum]);
+		return ret;
+	}
+
+	status = map->read16(map, padr);
+	if ((status & STATUS_READY) != STATUS_READY) {
+		printk("m5drv: error page writing at addr=0x%08x status=0x%08x\n",
+			(u32)padr, (u32)status);
+		map->write16(map, CMD_CLEAR_STATUS, padr);
+	}
+	map->write16(map, CMD_READ_ARRAY, padr);
+	chip->state = FL_READY;
+	m5drv_release(&m5drv->chips[chipnum]);
+	return 0;
+}
+
+static int m5drv_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+	struct map_info *map = mtd->priv;
+	struct m5drv_info *m5drv = map->fldrv_priv;
+	unsigned long adr,len;
+	int chipnum, ret=0;
+	int erasesize = 0;
+	int i;
+
+	M5DRV_DEBUG(2, "m5drv_erase(0x%08x)\n", instr->addr);
+	chipnum = instr->addr >> m5drv->chipshift;
+	if (chipnum >= m5drv->numchips) {
+		printk("m5drv: out of chip number (%d)\n", chipnum);
+		return -EIO;
+	}
+	adr = instr->addr & ((1<<m5drv->chipshift)-1);
+	len = instr->len;
+	if (mtd->numeraseregions == 0) {
+		erasesize = mtd->erasesize;
+	} else if (mtd->numeraseregions == 1) {
+		erasesize = mtd->eraseregions->erasesize;
+	} else {
+		for (i = 0; i < (mtd->numeraseregions - 1); i++) {
+			if (adr < mtd->eraseregions[i+1].offset) {
+				erasesize = mtd->eraseregions[i].erasesize;
+				break;
+			}
+		}
+		if (i == (mtd->numeraseregions - 1)) {	/* last region */
+			erasesize = mtd->eraseregions[i].erasesize;
+		}
+	}
+	M5DRV_DEBUG(2, "erasesize=%d, len=%ld\n", erasesize, len);
+	if (erasesize == 0) return -EINVAL;
+	if(instr->addr & (erasesize - 1))
+		return -EINVAL;
+	if(instr->len & (erasesize - 1))
+		return -EINVAL;
+	if(instr->len + instr->addr > mtd->size)
+		return -EINVAL;
+
+	while (len) {
+		ret = m5drv_erase_oneblock(map, &m5drv->chips[chipnum], adr);
+		if (ret < 0) return ret;
+
+		adr += erasesize;
+		len -= erasesize;
+		if(adr >> m5drv->chipshift){
+			adr = 0;
+			chipnum++;
+			if(chipnum >= m5drv->numchips)
+				break;
+		}
+	}
+	instr->state = MTD_ERASE_DONE;
+	if(instr->callback) {
+		M5DRV_DEBUG(1, "m5drv: call callback\n");
+		instr->callback(instr);
+	}
+	return 0;
+}
+
+static int m5drv_do_wait_for_ready(struct map_info *map, struct flchip *chip, unsigned long adr)
+{
+	int ret;
+	int timeo;
+	u_short status;
+	DECLARE_WAITQUEUE(wait, current);
+
+	/* unnecessary CMD_READ_STATUS */
+/*
+	map->write16(map, CMD_READ_STATUS, adr);
+	status = map->read16(map, adr);
+*/
+
+	timeo = jiffies + HZ;
+
+	while (time_before(jiffies, timeo)) {
+/*
+		map->write16(map, CMD_READ_STATUS, adr);
+*/
+		status = map->read16(map, adr);
+		if ((status & STATUS_READY) == STATUS_READY) {
+			M5DRV_DEBUG(1, "m5drv_wait_for_ready: ok, ready\n");
+			/*
+		 	 * FIXME: do full status check
+		 	 */
+			ret = 0;
+			goto out;
+		}
+		set_current_state(TASK_INTERRUPTIBLE);
+		add_wait_queue(&chip->wq, &wait);
+
+		// enabled by takeo
+		spin_unlock_bh(chip->mutex);
+
+		schedule_timeout(1);
+		schedule();
+		remove_wait_queue(&chip->wq, &wait);
+
+		// enabled by takeo
+		spin_lock_bh(chip->mutex);
+		
+		if (signal_pending(current)) {
+			ret = -EINTR;
+			goto out;
+		}
+		//timeo = jiffies + HZ;
+	}
+	ret = -ETIME;
+out:
+	if (ret < 0) {
+		map->write16(map, CMD_CLEAR_STATUS, adr);
+		map->write16(map, CMD_READ_ARRAY, adr);
+		chip->state = FL_READY;
+	}
+	return ret;
+}
+
+static int m5drv_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr)
+{
+	int ret;
+	u_short status;
+	struct m5drv_info *m5drv = map->fldrv_priv;
+	int chipnum;
+
+	M5DRV_DEBUG(1, "m5drv_erase_oneblock()\n");
+
+#ifdef UNLOCK_BEFORE_ERASE
+	m5drv_unlock_oneblock(map, chip, adr);
+#endif
+
+	chipnum = (adr >> m5drv->chipshift);
+	adr &= ~1;		/* align 2 */
+
+	ret = m5drv_wait(map, chip, adr);
+	if (ret < 0) return ret;
+
+	map->write16(map, CMD_BLOCK_ERASE, adr);
+	map->write16(map, CMD_CONFIRM, adr);
+	chip->state = FL_ERASING;
+
+	ret = m5drv_do_wait_for_ready(map, chip, adr);
+	if(ret < 0) {
+		m5drv_release(&m5drv->chips[chipnum]);
+		return ret;
+	}
+
+	status = map->read16(map, adr);
+	if ((status & STATUS_READY) == STATUS_READY) {
+		M5DRV_DEBUG(1, "m5drv: erase completed status=%04x\n", status);
+		map->write16(map, CMD_READ_ARRAY, adr);
+		chip->state = FL_READY;
+		m5drv_release(&m5drv->chips[chipnum]);
+		return 0;		/* ok, erasing completed */
+	}
+
+	printk("m5drv: error erasing block at addr=%08lx status=%08x\n",
+		adr,status);
+	map->write16(map, CMD_READ_ARRAY, adr);		/* cancel erasing */
+	chip->state = FL_READY;
+	m5drv_release(&m5drv->chips[chipnum]);
+	return -EIO;
+}
+
+
+#ifdef UNLOCK_BEFORE_ERASE
+/*
+ * we don't support unlock yet
+ */
+static void m5drv_unlock_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr)
+{
+	M5DRV_DEBUG(1, "m5drv_unlock_oneblock\n");
+}
+#endif
+
+static void m5drv_sync(struct mtd_info *mtd)
+{
+	M5DRV_DEBUG(1, "m5drv_sync()\n");
+}
+
+static int m5drv_suspend(struct mtd_info *mtd)
+{
+	M5DRV_DEBUG(1, "m5drv_suspend()\n");
+	return -EINVAL;
+}
+
+static void m5drv_resume(struct mtd_info *mtd)
+{
+	M5DRV_DEBUG(1, "m5drv_resume()\n");
+}
+
+static void m5drv_destroy(struct mtd_info *mtd)
+{
+	M5DRV_DEBUG(1, "m5drv_destroy()\n");
+}
+
+int __init m5drv_probe_init(void)
+{
+	printk("MTD chip driver\n");
+	register_mtd_chip_driver(&m5drv_chipdrv);
+	return 0;
+}
+
+static void __exit m5drv_probe_exit(void)
+{
+	M5DRV_DEBUG(1, "m5drv_probe_exit()\n");
+	unregister_mtd_chip_driver(&m5drv_chipdrv);
+}
+
+module_init(m5drv_probe_init);
+module_exit(m5drv_probe_exit);
+
+MODULE_AUTHOR("Takeo Takahashi");
+MODULE_DESCRIPTION("MTD chip driver for M5M29GT320VP");
+MODULE_LICENSE("GPL");
+EXPORT_NO_SYMBOLS;
diff -ruN linux-2.4.26.org/arch/m32r/drivers/mappi_ne.c linux-2.4.26/arch/m32r/drivers/mappi_ne.c
--- linux-2.4.26.org/arch/m32r/drivers/mappi_ne.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/arch/m32r/drivers/mappi_ne.c	2003-06-13 22:17:10.000000000 +0900
@@ -0,0 +1,821 @@
+/* ne.c: A general non-shared-memory NS8390 ethernet driver for linux. */
+/*
+    Written 1992-94 by Donald Becker.
+
+    Copyright 1993 United States Government as represented by the
+    Director, National Security Agency.
+
+    This software may be used and distributed according to the terms
+    of the GNU General Public License, incorporated herein by reference.
+
+    The author may be reached as becker@scyld.com, or C/O
+    Scyld Computing Corporation, 410 Severn Ave., Suite 210, Annapolis MD 21403
+
+    This driver should work with many programmed-I/O 8390-based ethernet
+    boards.  Currently it supports the NE1000, NE2000, many clones,
+    and some Cabletron products.
+
+    Changelog:
+
+    Paul Gortmaker	: use ENISR_RDC to monitor Tx PIO uploads, made
+			  sanity checks and bad clone support optional.
+    Paul Gortmaker	: new reset code, reset card after probe at boot.
+    Paul Gortmaker	: multiple card support for module users.
+    Paul Gortmaker	: Support for PCI ne2k clones, similar to lance.c
+    Paul Gortmaker	: Allow users with bad cards to avoid full probe.
+    Paul Gortmaker	: PCI probe changes, more PCI cards supported.
+    rjohnson@analogic.com : Changed init order so an interrupt will only
+    occur after memory is allocated for dev->priv. Deallocated memory
+    last in cleanup_modue()
+    Richard Guenther    : Added support for ISAPnP cards
+    Paul Gortmaker	: Discontinued PCI support - use ne2k-pci.c instead.
+*/
+
+/* Routines for the NatSemi-based designs (NE[12]000). */
+
+static const char version1[] =
+"ne.c:v1.10 9/23/94 Donald Becker (becker@scyld.com)\n";
+static const char version2[] =
+"mappi_ne.c: 1/08/01 by Hiroyuki Kondo\n";
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/isapnp.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <asm/system.h>
+#include <asm/io.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include "8390.h"
+
+#define ne_probe mappi_ne_probe
+
+/* Some defines that people can play with if so inclined. */
+
+/* Do we support clones that don't adhere to 14,15 of the SAprom ? */
+#define SUPPORT_NE_BAD_CLONES
+
+/* Do we perform extra sanity checks on stuff ? */
+/* #define NE_SANITY_CHECK */
+
+/* Do we implement the read before write bugfix ? */
+/* #define NE_RW_BUGFIX */
+
+/* Do we have a non std. amount of memory? (in units of 256 byte pages) */
+/* #define PACKETBUF_MEMSIZE	0x40 */
+
+/* A zero-terminated list of I/O addresses to be probed at boot. */
+#ifndef MODULE
+static unsigned int netcard_portlist[] __initdata = {
+	0x300, 0x280, 0x320, 0x340, 0x360, 0x380, 0
+};
+#endif
+
+static struct isapnp_device_id isapnp_clone_list[] __initdata = {
+	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
+		ISAPNP_VENDOR('E','D','I'), ISAPNP_FUNCTION(0x0216),
+		(long) "NN NE2000" },
+	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
+		ISAPNP_VENDOR('P','N','P'), ISAPNP_FUNCTION(0x80d6),
+		(long) "Generic PNP" },
+	{ }	/* terminate list */
+};
+
+MODULE_DEVICE_TABLE(isapnp, isapnp_clone_list);
+
+#ifdef SUPPORT_NE_BAD_CLONES
+/* A list of bad clones that we none-the-less recognize. */
+static struct { const char *name8, *name16; unsigned char SAprefix[4];}
+bad_clone_list[] __initdata = {
+    {"DE100", "DE200", {0x00, 0xDE, 0x01,}},
+    {"DE120", "DE220", {0x00, 0x80, 0xc8,}},
+    {"DFI1000", "DFI2000", {'D', 'F', 'I',}}, /* Original, eh?  */
+    {"EtherNext UTP8", "EtherNext UTP16", {0x00, 0x00, 0x79}},
+    {"NE1000","NE2000-invalid", {0x00, 0x00, 0xd8}}, /* Ancient real NE1000. */
+    {"NN1000", "NN2000",  {0x08, 0x03, 0x08}}, /* Outlaw no-name clone. */
+    {"4-DIM8","4-DIM16", {0x00,0x00,0x4d,}},  /* Outlaw 4-Dimension cards. */
+    {"Con-Intl_8", "Con-Intl_16", {0x00, 0x00, 0x24}}, /* Connect Int'nl */
+    {"ET-100","ET-200", {0x00, 0x45, 0x54}}, /* YANG and YA clone */
+    {"COMPEX","COMPEX16",{0x00,0x80,0x48}}, /* Broken ISA Compex cards */
+    {"E-LAN100", "E-LAN200", {0x00, 0x00, 0x5d}}, /* Broken ne1000 clones */
+    {"PCM-4823", "PCM-4823", {0x00, 0xc0, 0x6c}}, /* Broken Advantech MoBo */
+    {"REALTEK", "RTL8019", {0x00, 0x00, 0xe8}}, /* no-name with Realtek chip */
+    {"LCS-8834", "LCS-8836", {0x04, 0x04, 0x37}}, /* ShinyNet (SET) */
+    {0,}
+};
+#endif
+
+/* ---- No user-serviceable parts below ---- */
+
+#define NE_BASE	 (dev->base_addr)
+#define NE_CMD	 	0x00
+#define NE_DATAPORT	0x10	/* NatSemi-defined port window offset. */
+#define NE_RESET	0x1f	/* Issue a read to reset, a write to clear. */
+#define NE_IO_EXTENT	0x20
+
+#define NE1SM_START_PG	0x20	/* First page of TX buffer */
+#define NE1SM_STOP_PG 	0x40	/* Last page +1 of RX ring */
+#define NESM_START_PG	0x40	/* First page of TX buffer */
+#define NESM_STOP_PG	0x80	/* Last page +1 of RX ring */
+
+int ne_probe(struct net_device *dev);
+static int ne_probe1(struct net_device *dev, int ioaddr);
+static int ne_probe_isapnp(struct net_device *dev);
+
+static int ne_open(struct net_device *dev);
+static int ne_close(struct net_device *dev);
+
+static void ne_reset_8390(struct net_device *dev);
+static void ne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
+			  int ring_page);
+static void ne_block_input(struct net_device *dev, int count,
+			  struct sk_buff *skb, int ring_offset);
+static void ne_block_output(struct net_device *dev, const int count,
+		const unsigned char *buf, const int start_page);
+
+
+/*  Probe for various non-shared-memory ethercards.
+
+   NEx000-clone boards have a Station Address PROM (SAPROM) in the packet
+   buffer memory space.  NE2000 clones have 0x57,0x57 in bytes 0x0e,0x0f of
+   the SAPROM, while other supposed NE2000 clones must be detected by their
+   SA prefix.
+
+   Reading the SAPROM from a word-wide card with the 8390 set in byte-wide
+   mode results in doubled values, which can be detected and compensated for.
+
+   The probe is also responsible for initializing the card and filling
+   in the 'dev' and 'ei_status' structures.
+
+   We use the minimum memory size for some ethercard product lines, iff we can't
+   distinguish models.  You can increase the packet buffer size by setting
+   PACKETBUF_MEMSIZE.  Reported Cabletron packet buffer locations are:
+	E1010   starts at 0x100 and ends at 0x2000.
+	E1010-x starts at 0x100 and ends at 0x8000. ("-x" means "more memory")
+	E2010	 starts at 0x100 and ends at 0x4000.
+	E2010-x starts at 0x100 and ends at 0xffff.  */
+
+int __init ne_probe(struct net_device *dev)
+{
+	unsigned int base_addr = dev->base_addr;
+
+	SET_MODULE_OWNER(dev);
+
+	/* First check any supplied i/o locations. User knows best. <cough> */
+	if (base_addr > 0x1ff)	/* Check a single specified location. */
+		return ne_probe1(dev, base_addr);
+	else if (base_addr != 0)	/* Don't probe at all. */
+		return -ENXIO;
+
+	/* Then look for any installed ISAPnP clones */
+	if (isapnp_present() && (ne_probe_isapnp(dev) == 0))
+		return 0;
+
+#ifndef MODULE
+	/* Last resort. The semi-risky ISA auto-probe. */
+	for (base_addr = 0; netcard_portlist[base_addr] != 0; base_addr++) {
+		int ioaddr = netcard_portlist[base_addr];
+		if (ne_probe1(dev, ioaddr) == 0)
+			return 0;
+	}
+#endif
+
+	return -ENODEV;
+}
+
+static int __init ne_probe_isapnp(struct net_device *dev)
+{
+	int i;
+
+	for (i = 0; isapnp_clone_list[i].vendor != 0; i++) {
+		struct pci_dev *idev = NULL;
+
+		while ((idev = isapnp_find_dev(NULL,
+					       isapnp_clone_list[i].vendor,
+					       isapnp_clone_list[i].function,
+					       idev))) {
+			/* Avoid already found cards from previous calls */
+			if (idev->prepare(idev))
+				continue;
+			if (idev->activate(idev))
+				continue;
+			/* if no irq, search for next */
+			if (idev->irq_resource[0].start == 0)
+				continue;
+			/* found it */
+			dev->base_addr = idev->resource[0].start;
+			dev->irq = idev->irq_resource[0].start;
+			printk(KERN_INFO "ne.c: ISAPnP reports %s at i/o %#lx, irq %d.\n",
+				(char *) isapnp_clone_list[i].driver_data,
+
+				dev->base_addr, dev->irq);
+			if (ne_probe1(dev, dev->base_addr) != 0) {	/* Shouldn't happen. */
+				printk(KERN_ERR "ne.c: Probe of ISAPnP card at %#lx failed.\n", dev->base_addr);
+				return -ENXIO;
+			}
+			ei_status.priv = (unsigned long)idev;
+			break;
+		}
+		if (!idev)
+			continue;
+		return 0;
+	}
+
+	return -ENODEV;
+}
+
+static int __init ne_probe1(struct net_device *dev, int ioaddr)
+{
+	int i;
+	unsigned char SA_prom[32];
+	int wordlength = 2;
+	const char *name = NULL;
+	int start_page, stop_page;
+	int neX000, ctron, copam, bad_card;
+	int reg0, ret;
+	static unsigned version_printed;
+
+	if (!request_region(ioaddr, NE_IO_EXTENT, dev->name))
+		return -EBUSY;
+
+	reg0 = inb_p(ioaddr);
+	if (reg0 == 0xFF) {
+		ret = -ENODEV;
+		goto err_out;
+	}
+
+	/* Do a preliminary verification that we have a 8390. */
+	{
+		int regd;
+		outb_p(E8390_NODMA+E8390_PAGE1+E8390_STOP, ioaddr + E8390_CMD);
+		regd = inb_p(ioaddr + 0x0d);
+		outb_p(0xff, ioaddr + 0x0d);
+		outb_p(E8390_NODMA+E8390_PAGE0, ioaddr + E8390_CMD);
+		inb_p(ioaddr + EN0_COUNTER0); /* Clear the counter by reading. */
+		if (inb_p(ioaddr + EN0_COUNTER0) != 0) {
+			outb_p(reg0, ioaddr);
+			outb_p(regd, ioaddr + 0x0d);	/* Restore the old values. */
+			ret = -ENODEV;
+			goto err_out;
+		}
+	}
+
+	if (ei_debug  &&  version_printed++ == 0)
+		printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
+
+	printk(KERN_INFO "NE*000 ethercard probe at %#3x:", ioaddr);
+
+	/* A user with a poor card that fails to ack the reset, or that
+	   does not have a valid 0x57,0x57 signature can still use this
+	   without having to recompile. Specifying an i/o address along
+	   with an otherwise unused dev->mem_end value of "0xBAD" will
+	   cause the driver to skip these parts of the probe. */
+
+	bad_card = ((dev->base_addr != 0) && (dev->mem_end == 0xbad));
+
+	/* Reset card. Who knows what dain-bramaged state it was left in. */
+
+	{
+		unsigned long reset_start_time = jiffies;
+
+		/* DON'T change these to inb_p/outb_p or reset will fail on clones. */
+		outb(inb(ioaddr + NE_RESET), ioaddr + NE_RESET);
+
+		while ((inb_p(ioaddr + EN0_ISR) & ENISR_RESET) == 0)
+		if (jiffies - reset_start_time > 2*HZ/100) {
+			if (bad_card) {
+				printk(" (warning: no reset ack)");
+				break;
+			} else {
+				printk(" not found (no reset ack).\n");
+				ret = -ENODEV;
+				goto err_out;
+			}
+		}
+
+		outb_p(0xff, ioaddr + EN0_ISR);		/* Ack all intr. */
+	}
+
+	/* Read the 16 bytes of station address PROM.
+	   We must first initialize registers, similar to NS8390_init(eifdev, 0).
+	   We can't reliably read the SAPROM address without this.
+	   (I learned the hard way!). */
+	{
+		struct {unsigned char value, offset; } program_seq[] =
+		{
+			{E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/
+			{0x48,	EN0_DCFG},	/* Set byte-wide (0x48) access. */
+			{0x00,	EN0_RCNTLO},	/* Clear the count regs. */
+			{0x00,	EN0_RCNTHI},
+			{0x00,	EN0_IMR},	/* Mask completion irq. */
+			{0xFF,	EN0_ISR},
+			{E8390_RXOFF, EN0_RXCR},	/* 0x20  Set to monitor */
+			{E8390_TXOFF, EN0_TXCR},	/* 0x02  and loopback mode. */
+			{32,	EN0_RCNTLO},
+			{0x00,	EN0_RCNTHI},
+			{0x00,	EN0_RSARLO},	/* DMA starting at 0x0000. */
+			{0x00,	EN0_RSARHI},
+			{E8390_RREAD+E8390_START, E8390_CMD},
+		};
+
+		for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++)
+			outb_p(program_seq[i].value, ioaddr + program_seq[i].offset);
+
+	}
+	for(i = 0; i < 32 /*sizeof(SA_prom)*/; i+=2) {
+		SA_prom[i] = inb(ioaddr + NE_DATAPORT);
+		SA_prom[i+1] = inb(ioaddr + NE_DATAPORT);
+		if (SA_prom[i] != SA_prom[i+1])
+			wordlength = 1;
+	}
+
+	if (wordlength == 2)
+	{
+		for (i = 0; i < 16; i++)
+			SA_prom[i] = SA_prom[i+i];
+		/* We must set the 8390 for word mode. */
+#if 0   /* by kondo for big endian */
+		outb_p(0x49, ioaddr + EN0_DCFG);
+#else
+		outb_p(0x4b, ioaddr + EN0_DCFG);
+#endif  /* by kondo */
+		start_page = NESM_START_PG;
+		stop_page = NESM_STOP_PG;
+	} else {
+		start_page = NE1SM_START_PG;
+		stop_page = NE1SM_STOP_PG;
+	}
+
+#if 0 /* by kondo for mappi */
+	neX000 = (SA_prom[14] == 0x57  &&  SA_prom[15] == 0x57);
+#else
+	neX000 = ((SA_prom[14] == 0x57  &&  SA_prom[15] == 0x57) || (SA_prom[14] == 0x42  &&  SA_prom[15] == 0x42));
+#endif
+	ctron =  (SA_prom[0] == 0x00 && SA_prom[1] == 0x00 && SA_prom[2] == 0x1d);
+	copam =  (SA_prom[14] == 0x49 && SA_prom[15] == 0x00);
+
+	/* Set up the rest of the parameters. */
+	if (neX000 || bad_card || copam) {
+		printk(" (signature %2.2x) ",SA_prom[14]);
+		name = (wordlength == 2) ? "NE2000" : "NE1000";
+	}
+	else if (ctron)
+	{
+		name = (wordlength == 2) ? "Ctron-8" : "Ctron-16";
+		start_page = 0x01;
+		stop_page = (wordlength == 2) ? 0x40 : 0x20;
+	}
+	else
+	{
+#ifdef SUPPORT_NE_BAD_CLONES
+		/* Ack!  Well, there might be a *bad* NE*000 clone there.
+		   Check for total bogus addresses. */
+		for (i = 0; bad_clone_list[i].name8; i++)
+		{
+			if (SA_prom[0] == bad_clone_list[i].SAprefix[0] &&
+				SA_prom[1] == bad_clone_list[i].SAprefix[1] &&
+				SA_prom[2] == bad_clone_list[i].SAprefix[2])
+			{
+				if (wordlength == 2)
+				{
+					name = bad_clone_list[i].name16;
+				} else {
+					name = bad_clone_list[i].name8;
+				}
+				break;
+			}
+		}
+		if (bad_clone_list[i].name8 == NULL)
+		{
+			printk(" not found (invalid signature %2.2x %2.2x).\n",
+				SA_prom[14], SA_prom[15]);
+			ret = -ENXIO;
+			goto err_out;
+		}
+#else
+		printk(" not found.\n");
+		ret = -ENXIO;
+		goto err_out;
+#endif
+	}
+
+	if (dev->irq < 2)
+	{
+		unsigned long cookie = probe_irq_on();
+		outb_p(0x50, ioaddr + EN0_IMR);	/* Enable one interrupt. */
+		outb_p(0x00, ioaddr + EN0_RCNTLO);
+		outb_p(0x00, ioaddr + EN0_RCNTHI);
+		outb_p(E8390_RREAD+E8390_START, ioaddr); /* Trigger it... */
+		mdelay(10);		/* wait 10ms for interrupt to propagate */
+		outb_p(0x00, ioaddr + EN0_IMR); 		/* Mask it again. */
+		dev->irq = probe_irq_off(cookie);
+		if (ei_debug > 2)
+			printk(" autoirq is %d\n", dev->irq);
+	} else if (dev->irq == 2)
+		/* Fixup for users that don't know that IRQ 2 is really IRQ 9,
+		   or don't know which one to set. */
+		dev->irq = 9;
+
+	if (! dev->irq) {
+		printk(" failed to detect IRQ line.\n");
+		ret = -EAGAIN;
+		goto err_out;
+	}
+
+	/* Allocate dev->priv and fill in 8390 specific dev fields. */
+	if (ethdev_init(dev))
+	{
+        	printk (" unable to get memory for dev->priv.\n");
+        	ret = -ENOMEM;
+		goto err_out;
+	}
+
+	/* Snarf the interrupt now.  There's no point in waiting since we cannot
+	   share and the board will usually be enabled. */
+	ret = request_irq(dev->irq, ei_interrupt, 0, name, dev);
+	if (ret) {
+		printk (" unable to get IRQ %d (errno=%d).\n", dev->irq, ret);
+		goto err_out_kfree;
+	}
+
+	dev->base_addr = ioaddr;
+
+#if 1 /* by kondo */
+{
+	outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP, ioaddr+E8390_CMD); /* 0x61 */
+	for(i = 0; i < ETHER_ADDR_LEN; i++) {
+		dev->dev_addr[i] = SA_prom[i] = inb_p(ioaddr + EN1_PHYS_SHIFT(i));
+		printk(" %2.2x", SA_prom[i]);
+	}
+}
+#else
+	for(i = 0; i < ETHER_ADDR_LEN; i++) {
+		printk(" %2.2x", SA_prom[i]);
+		dev->dev_addr[i] = SA_prom[i];
+	}
+#endif
+
+	printk("\n%s: %s found at %#x, using IRQ %d.\n",
+		dev->name, name, ioaddr, dev->irq);
+
+	ei_status.name = name;
+	ei_status.tx_start_page = start_page;
+	ei_status.stop_page = stop_page;
+	ei_status.word16 = (wordlength == 2);
+
+	ei_status.rx_start_page = start_page + TX_PAGES;
+#ifdef PACKETBUF_MEMSIZE
+	 /* Allow the packet buffer size to be overridden by know-it-alls. */
+	ei_status.stop_page = ei_status.tx_start_page + PACKETBUF_MEMSIZE;
+#endif
+
+	ei_status.reset_8390 = &ne_reset_8390;
+	ei_status.block_input = &ne_block_input;
+	ei_status.block_output = &ne_block_output;
+	ei_status.get_8390_hdr = &ne_get_8390_hdr;
+	ei_status.priv = 0;
+	dev->open = &ne_open;
+	dev->stop = &ne_close;
+	NS8390_init(dev, 0);
+	return 0;
+
+err_out_kfree:
+	kfree(dev->priv);
+	dev->priv = NULL;
+err_out:
+	release_region(ioaddr, NE_IO_EXTENT);
+	return ret;
+}
+
+static int ne_open(struct net_device *dev)
+{
+	ei_open(dev);
+	return 0;
+}
+
+static int ne_close(struct net_device *dev)
+{
+	if (ei_debug > 1)
+		printk(KERN_DEBUG "%s: Shutting down ethercard.\n", dev->name);
+	ei_close(dev);
+	return 0;
+}
+
+/* Hard reset the card.  This used to pause for the same period that a
+   8390 reset command required, but that shouldn't be necessary. */
+
+static void ne_reset_8390(struct net_device *dev)
+{
+	unsigned long reset_start_time = jiffies;
+
+	if (ei_debug > 1)
+		printk(KERN_DEBUG "resetting the 8390 t=%ld...", jiffies);
+
+	/* DON'T change these to inb_p/outb_p or reset will fail on clones. */
+	outb(inb(NE_BASE + NE_RESET), NE_BASE + NE_RESET);
+
+	ei_status.txing = 0;
+	ei_status.dmaing = 0;
+
+	/* This check _should_not_ be necessary, omit eventually. */
+	while ((inb_p(NE_BASE+EN0_ISR) & ENISR_RESET) == 0)
+		if (jiffies - reset_start_time > 2*HZ/100) {
+			printk(KERN_WARNING "%s: ne_reset_8390() did not complete.\n", dev->name);
+			break;
+		}
+	outb_p(ENISR_RESET, NE_BASE + EN0_ISR);	/* Ack intr. */
+}
+
+/* Grab the 8390 specific header. Similar to the block_input routine, but
+   we don't need to be concerned with ring wrap as the header will be at
+   the start of a page, so we optimize accordingly. */
+
+static void ne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
+{
+	int nic_base = dev->base_addr;
+
+	/* This *shouldn't* happen. If it does, it's the last thing you'll see */
+
+	if (ei_status.dmaing)
+	{
+		printk(KERN_EMERG "%s: DMAing conflict in ne_get_8390_hdr "
+			"[DMAstat:%d][irqlock:%d].\n",
+			dev->name, ei_status.dmaing, ei_status.irqlock);
+		return;
+	}
+
+	ei_status.dmaing |= 0x01;
+	outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
+	outb_p(sizeof(struct e8390_pkt_hdr), nic_base + EN0_RCNTLO);
+	outb_p(0, nic_base + EN0_RCNTHI);
+	outb_p(0, nic_base + EN0_RSARLO);		/* On page boundary */
+	outb_p(ring_page, nic_base + EN0_RSARHI);
+	outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD);
+
+	if (ei_status.word16)
+		insw(NE_BASE + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)>>1);
+	else
+		insb(NE_BASE + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr));
+
+	outb_p(ENISR_RDC, nic_base + EN0_ISR);	/* Ack intr. */
+	ei_status.dmaing &= ~0x01;
+
+	le16_to_cpus(&hdr->count);
+}
+
+/* Block input and output, similar to the Crynwr packet driver.  If you
+   are porting to a new ethercard, look at the packet driver source for hints.
+   The NEx000 doesn't share the on-board packet memory -- you have to put
+   the packet out through the "remote DMA" dataport using outb. */
+
+static void ne_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
+{
+#ifdef NE_SANITY_CHECK
+	int xfer_count = count;
+#endif
+	int nic_base = dev->base_addr;
+	char *buf = skb->data;
+
+	/* This *shouldn't* happen. If it does, it's the last thing you'll see */
+	if (ei_status.dmaing)
+	{
+		printk(KERN_EMERG "%s: DMAing conflict in ne_block_input "
+			"[DMAstat:%d][irqlock:%d].\n",
+			dev->name, ei_status.dmaing, ei_status.irqlock);
+		return;
+	}
+	ei_status.dmaing |= 0x01;
+	outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
+		outb_p(0x49, nic_base + EN0_DCFG);
+	outb_p(count & 0xff, nic_base + EN0_RCNTLO);
+	outb_p(count >> 8, nic_base + EN0_RCNTHI);
+	outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO);
+	outb_p(ring_offset >> 8, nic_base + EN0_RSARHI);
+	outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD);
+	if (ei_status.word16)
+	{
+		insw(NE_BASE + NE_DATAPORT,buf,count>>1);
+
+		if (count & 0x01)
+		{
+			buf[count-1] = inb(NE_BASE + NE_DATAPORT);
+#ifdef NE_SANITY_CHECK
+			xfer_count++;
+#endif
+		}
+	} else {
+		insb(NE_BASE + NE_DATAPORT, buf, count);
+	}
+
+#ifdef NE_SANITY_CHECK
+	/* This was for the ALPHA version only, but enough people have
+	   been encountering problems so it is still here.  If you see
+	   this message you either 1) have a slightly incompatible clone
+	   or 2) have noise/speed problems with your bus. */
+
+	if (ei_debug > 1)
+	{
+		/* DMA termination address check... */
+		int addr, tries = 20;
+		do {
+			/* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here
+			   -- it's broken for Rx on some cards! */
+			int high = inb_p(nic_base + EN0_RSARHI);
+			int low = inb_p(nic_base + EN0_RSARLO);
+			addr = (high << 8) + low;
+			if (((ring_offset + xfer_count) & 0xff) == low)
+				break;
+		} while (--tries > 0);
+	 	if (tries <= 0)
+			printk(KERN_WARNING "%s: RX transfer address mismatch,"
+				"%#4.4x (expected) vs. %#4.4x (actual).\n",
+				dev->name, ring_offset + xfer_count, addr);
+	}
+#endif
+	outb_p(ENISR_RDC, nic_base + EN0_ISR);	/* Ack intr. */
+	ei_status.dmaing &= ~0x01;
+}
+
+static void ne_block_output(struct net_device *dev, int count,
+		const unsigned char *buf, const int start_page)
+{
+	int nic_base = NE_BASE;
+	unsigned long dma_start;
+#ifdef NE_SANITY_CHECK
+	int retries = 0;
+#endif
+
+	/* Round the count up for word writes.  Do we need to do this?
+	   What effect will an odd byte count have on the 8390?
+	   I should check someday. */
+
+	if (ei_status.word16 && (count & 0x01))
+		count++;
+
+	/* This *shouldn't* happen. If it does, it's the last thing you'll see */
+	if (ei_status.dmaing)
+	{
+		printk(KERN_EMERG "%s: DMAing conflict in ne_block_output."
+			"[DMAstat:%d][irqlock:%d]\n",
+			dev->name, ei_status.dmaing, ei_status.irqlock);
+		return;
+	}
+	ei_status.dmaing |= 0x01;
+	/* We should already be in page 0, but to be safe... */
+	outb_p(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base + NE_CMD);
+
+#ifdef NE_SANITY_CHECK
+retry:
+#endif
+
+#ifdef NE8390_RW_BUGFIX
+	/* Handle the read-before-write bug the same way as the
+	   Crynwr packet driver -- the NatSemi method doesn't work.
+	   Actually this doesn't always work either, but if you have
+	   problems with your NEx000 this is better than nothing! */
+
+	outb_p(0x42, nic_base + EN0_RCNTLO);
+	outb_p(0x00,   nic_base + EN0_RCNTHI);
+	outb_p(0x42, nic_base + EN0_RSARLO);
+	outb_p(0x00, nic_base + EN0_RSARHI);
+	outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD);
+	/* Make certain that the dummy read has occurred. */
+	udelay(6);
+#endif
+
+	outb_p(ENISR_RDC, nic_base + EN0_ISR);
+
+	/* Now the normal output. */
+	outb_p(count & 0xff, nic_base + EN0_RCNTLO);
+	outb_p(count >> 8,   nic_base + EN0_RCNTHI);
+	outb_p(0x00, nic_base + EN0_RSARLO);
+	outb_p(start_page, nic_base + EN0_RSARHI);
+
+	outb_p(E8390_RWRITE+E8390_START, nic_base + NE_CMD);
+	if (ei_status.word16) {
+		outsw(NE_BASE + NE_DATAPORT, buf, count>>1);
+	} else {
+		outsb(NE_BASE + NE_DATAPORT, buf, count);
+	}
+
+	dma_start = jiffies;
+
+#ifdef NE_SANITY_CHECK
+	/* This was for the ALPHA version only, but enough people have
+	   been encountering problems so it is still here. */
+
+	if (ei_debug > 1)
+	{
+		/* DMA termination address check... */
+		int addr, tries = 20;
+		do {
+			int high = inb_p(nic_base + EN0_RSARHI);
+			int low = inb_p(nic_base + EN0_RSARLO);
+			addr = (high << 8) + low;
+			if ((start_page << 8) + count == addr)
+				break;
+		} while (--tries > 0);
+
+		if (tries <= 0)
+		{
+			printk(KERN_WARNING "%s: Tx packet transfer address mismatch,"
+				"%#4.4x (expected) vs. %#4.4x (actual).\n",
+				dev->name, (start_page << 8) + count, addr);
+			if (retries++ == 0)
+				goto retry;
+		}
+	}
+#endif
+
+	while ((inb_p(nic_base + EN0_ISR) & ENISR_RDC) == 0)
+		if (jiffies - dma_start > 2*HZ/100) {		/* 20ms */
+			printk(KERN_WARNING "%s: timeout waiting for Tx RDC.\n", dev->name);
+			ne_reset_8390(dev);
+			NS8390_init(dev,1);
+			break;
+		}
+
+	outb_p(ENISR_RDC, nic_base + EN0_ISR);	/* Ack intr. */
+	ei_status.dmaing &= ~0x01;
+	return;
+}
+
+
+#ifdef MODULE
+#define MAX_NE_CARDS	4	/* Max number of NE cards per module */
+static struct net_device dev_ne[MAX_NE_CARDS];
+static int io[MAX_NE_CARDS];
+static int irq[MAX_NE_CARDS];
+static int bad[MAX_NE_CARDS];	/* 0xbad = bad sig or no reset ack */
+
+MODULE_PARM(io, "1-" __MODULE_STRING(MAX_NE_CARDS) "i");
+MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_NE_CARDS) "i");
+MODULE_PARM(bad, "1-" __MODULE_STRING(MAX_NE_CARDS) "i");
+MODULE_PARM_DESC(io, "NEx000 I/O base address(es),required");
+MODULE_PARM_DESC(irq, "NEx000 IRQ number(s)");
+MODULE_PARM_DESC(bad, "NEx000 accept bad clone(s)");
+
+/* This is set up so that no ISA autoprobe takes place. We can't guarantee
+that the ne2k probe is the last 8390 based probe to take place (as it
+is at boot) and so the probe will get confused by any other 8390 cards.
+ISA device autoprobes on a running machine are not recommended anyway. */
+
+int init_module(void)
+{
+	int this_dev, found = 0;
+
+	for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) {
+		struct net_device *dev = &dev_ne[this_dev];
+		dev->irq = irq[this_dev];
+		dev->mem_end = bad[this_dev];
+		dev->base_addr = io[this_dev];
+		dev->init = ne_probe;
+		if (register_netdev(dev) == 0) {
+			found++;
+			continue;
+		}
+		if (found != 0) { 	/* Got at least one. */
+			return 0;
+		}
+		if (io[this_dev] != 0)
+			printk(KERN_WARNING "ne.c: No NE*000 card found at i/o = %#x\n", io[this_dev]);
+		else
+			printk(KERN_NOTICE "ne.c: You must supply \"io=0xNNN\" value(s) for ISA cards.\n");
+		return -ENXIO;
+	}
+	return 0;
+}
+
+void cleanup_module(void)
+{
+	int this_dev;
+
+	for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) {
+		struct net_device *dev = &dev_ne[this_dev];
+		if (dev->priv != NULL) {
+			void *priv = dev->priv;
+			struct pci_dev *idev = (struct pci_dev *)ei_status.priv;
+			if (idev)
+				idev->deactivate(idev);
+			free_irq(dev->irq, dev);
+			release_region(dev->base_addr, NE_IO_EXTENT);
+			unregister_netdev(dev);
+			kfree(priv);
+		}
+	}
+}
+#endif /* MODULE */
+MODULE_LICENSE("GPL");
+
+
+/*
+ * Local variables:
+ *  compile-command: "gcc -DKERNEL -Wall -O6 -fomit-frame-pointer -I/usr/src/linux/net/tcp -c ne.c"
+ *  version-control: t
+ *  kept-new-versions: 5
+ * End:
+ */
diff -ruN linux-2.4.26.org/arch/m32r/drivers/smc91111.c linux-2.4.26/arch/m32r/drivers/smc91111.c
--- linux-2.4.26.org/arch/m32r/drivers/smc91111.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/arch/m32r/drivers/smc91111.c	2004-05-21 17:19:25.000000000 +0900
@@ -0,0 +1,3903 @@
+/*------------------------------------------------------------------------
+ . smc91111.c
+ . This is a driver for SMSC's 91C111 single-chip Ethernet device.
+ .
+ . Copyright (C) 2001 Standard Microsystems Corporation (SMSC)
+ .       Developed by Simple Network Magic Corporation (SNMC)
+ . Copyright (C) 1996 by Erik Stahlman (ES)
+ .
+ . This program is free software; you can redistribute it and/or modify
+ . it under the terms of the GNU General Public License as published by
+ . the Free Software Foundation; either version 2 of the License, or
+ . (at your option) any later version.
+ .
+ . This program is distributed in the hope that it will be useful,
+ . but WITHOUT ANY WARRANTY; without even the implied warranty of
+ . MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ . GNU General Public License for more details.
+ .
+ . You should have received a copy of the GNU General Public License
+ . along with this program; if not, write to the Free Software
+ . Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ .
+ . Information contained in this file was obtained from the LAN91C111
+ . manual from SMC.  To get a copy, if you really want one, you can find 
+ . information under www.smsc.com.
+ . 
+ .
+ . "Features" of the SMC chip:
+ .   Integrated PHY/MAC for 10/100BaseT Operation
+ .   Supports internal and external MII
+ .   Integrated 8K packet memory
+ .   EEPROM interface for configuration
+ .
+ . Arguments:
+ . 	io	= for the base address
+ .	irq	= for the IRQ
+ .	nowait	= 0 for normal wait states, 1 eliminates additional wait states
+ .
+ . author:
+ . 	Erik Stahlman				( erik@vt.edu )
+ . 	Daris A Nevil				( dnevil@snmc.com )
+ .  	Pramod B Bhardwaj   			(pramod.bhardwaj@smsc.com)
+ .
+ .
+ . Hardware multicast code from Peter Cammaert ( pc@denkart.be )
+ .
+ . Sources:
+ .    o   SMSC LAN91C111 databook (www.smsc.com)
+ .    o   smc9194.c by Erik Stahlman
+ .    o   skeleton.c by Donald Becker ( becker@cesdis.gsfc.nasa.gov )
+ .
+ . History:
+ .    09/24/01  Pramod B Bhardwaj, Added the changes for Kernel 2.4
+ .    08/21/01  Pramod B Bhardwaj Added support for RevB of LAN91C111
+ .    04/25/01  Daris A Nevil  Initial public release through SMSC
+ .    03/16/01  Daris A Nevil  Modified smc9194.c for use with LAN91C111
+ .    01/14/03  Takeo Takahashi Support M32RUT-LAN(Rev.B)
+ .    02/25/04  Hirokazu Takata, Hayato Fujiwara, Mamoru Sakugawa, 
+ .              SMP support for Linux/M32R.
+ ----------------------------------------------------------------------------*/
+#include <linux/config.h>
+#if defined(__m32r__)
+#define SMC_DEBUG 0
+#define smc_init	m32r_smc_init
+#endif
+#if defined(CONFIG_PLAT_M32700UT_Alpha)
+#define NO_AUTOPROBE
+#elif defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_OPSPUT)
+#define NO_AUTOPROBE
+#endif
+
+// Use power-down feature of the chip
+#define POWER_DOWN	0
+
+
+static const char version[] =
+	"SMSC LAN91C111 Driver (v2.0), (Linux Kernel 2.4 + Support for Odd Byte) 09/24/01 -      by Pramod Bhardwaj (pramod.bhardwaj@smsc.com)\n\n";
+
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#endif
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#if defined(__m32r__)
+#include <linux/slab.h>
+#else	/* Not __m32r__ */
+#include <linux/malloc.h>
+#endif
+#include <linux/string.h>
+#include <linux/init.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+//#include <linux/kcomp.h>
+
+#include <linux/spinlock.h>
+
+
+#ifdef CONFIG_SYSCTL
+#include <linux/proc_fs.h>
+#include <linux/sysctl.h>
+#endif
+
+#include "smc91111.h"
+/*------------------------------------------------------------------------
+ .
+ . Configuration options, for the experienced user to change.
+ .
+ -------------------------------------------------------------------------*/
+
+/*
+ . Do you want to use 32 bit xfers?  This should work on all chips, as
+ . the chipset is designed to accommodate them.
+*/
+#if !defined(__m32r__)
+#define USE_32_BIT 1
+#endif
+
+
+/*
+ .the LAN91C111 can be at any of the following port addresses.  To change,
+ .for a slightly different card, you can add it to the array.  Keep in
+ .mind that the array must end in zero.
+*/
+static unsigned int smc_portlist[] __initdata =
+   { 0x200, 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x2E0,
+	 0x300, 0x320, 0x340, 0x360, 0x380, 0x3A0, 0x3C0, 0x3E0, 0};
+
+
+/*
+ . Wait time for memory to be free.  This probably shouldn't be
+ . tuned that much, as waiting for this means nothing else happens
+ . in the system
+*/
+#define MEMORY_WAIT_TIME 16
+
+/*
+ . This selects whether TX packets are sent one by one to the SMC91x internal
+ . memory ans throttled until transmission completes.  This may prevent
+ . RX overruns a litle by keeping much of the memory free for RX packets
+ . but to the expense of reduced TX throughput and increased IRQ overhead.
+ . Note this is not a cure for a too slow data bus or too high IRQ latency.
+ */
+#define THROTTLE_TX_PKTS        1
+
+/*
+ . DEBUGGING LEVELS
+ .
+ . 0 for normal operation
+ . 1 for slightly more details
+ . >2 for various levels of increasingly useless information
+ .    2 for interrupt tracking, status flags
+ .    3 for packet info
+ .    4 for complete packet dumps
+*/
+//#define SMC_DEBUG 3 // Must be defined in makefile
+
+#if (SMC_DEBUG > 2 )
+#define PRINTK3(args...) printk(args)
+#else
+#define PRINTK3(args...)
+#endif
+
+#if SMC_DEBUG > 1
+#define PRINTK2(args...) printk(args)
+#else
+#define PRINTK2(args...)
+#endif
+
+#ifdef SMC_DEBUG
+#define PRINTK(args...) printk(args)
+#else
+#define PRINTK(args...)
+#endif
+
+
+/*------------------------------------------------------------------------
+ .
+ . The internal workings of the driver.  If you are changing anything
+ . here with the SMC stuff, you should have the datasheet and know
+ . what you are doing.
+ .
+ -------------------------------------------------------------------------*/
+#define CARDNAME "LAN91C111"
+
+// Memory sizing constant
+#define LAN91C111_MEMORY_MULTIPLIER	(1024*2)
+
+/* store this information for the driver.. */
+struct smc_local {
+
+ 	// these are things that the kernel wants me to keep, so users
+	// can find out semi-useless statistics of how well the card is
+	// performing
+	struct net_device_stats stats;
+
+	// If I have to wait until memory is available to send
+	// a packet, I will store the skbuff here, until I get the
+	// desired memory.  Then, I'll send it out and free it.
+	struct sk_buff * saved_skb;
+
+ 	// This keeps track of how many packets that I have
+ 	// sent out.  When an TX_EMPTY interrupt comes, I know
+	// that all of these have been sent.
+	int	packets_waiting;
+
+	// Set to true during the auto-negotiation sequence
+	int	autoneg_active;
+
+	// Address of our PHY port
+	word	phyaddr;
+
+	// Type of PHY
+	word	phytype;
+
+	// Last contents of PHY Register 18
+	word	lastPhy18;
+
+	// Contains the current active transmission mode
+	word	tcr_cur_mode;
+
+	// Contains the current active receive mode
+	word	rcr_cur_mode;
+
+	// Contains the current active receive/phy mode
+	word	rpc_cur_mode;
+
+	/* => Pramod, Odd Byte issue */
+	// Contains the Current ChipID
+	unsigned short ChipID;
+
+	//Contains the Current ChipRevision
+	unsigned short ChipRev;
+	/* <= Pramod, Odd Byte issue */
+
+        spinlock_t lock;
+
+#ifdef CONFIG_SYSCTL
+
+	// Root directory /proc/sys/dev
+	// Second entry must be null to terminate the table
+	ctl_table root_table[2];
+
+	// Directory for this device /proc/sys/dev/ethX
+	// Again the second entry must be zero to terminate
+	ctl_table eth_table[2];
+
+	// This is the parameters (file) table
+	ctl_table param_table[CTL_SMC_LAST_ENTRY];
+
+	// Saves the sysctl header returned by register_sysctl_table()
+	// we send this to unregister_sysctl_table()
+	struct ctl_table_header *sysctl_header;
+
+	// Parameter variables (files) go here
+	char ctl_info[1024];
+	int ctl_swfdup;
+	int ctl_ephloop;
+	int ctl_miiop;
+	int ctl_autoneg;
+	int ctl_rfduplx;
+	int ctl_rspeed;
+	int ctl_afduplx;
+	int ctl_aspeed;
+	int ctl_lnkfail;
+	int ctl_forcol;
+	int ctl_filtcar;
+	int ctl_freemem;
+	int ctl_totmem;
+	int ctl_leda;
+	int ctl_ledb;
+	int ctl_chiprev;
+#ifdef SMC_DEBUG
+	int ctl_reg_bsr;
+	int ctl_reg_tcr;
+	int ctl_reg_esr;
+	int ctl_reg_rcr;
+	int ctl_reg_ctrr;
+	int ctl_reg_mir;
+	int ctl_reg_rpcr;
+	int ctl_reg_cfgr;
+	int ctl_reg_bar;
+	int ctl_reg_iar0;
+	int ctl_reg_iar1;
+	int ctl_reg_iar2;
+	int ctl_reg_gpr;
+	int ctl_reg_ctlr;
+	int ctl_reg_mcr;
+	int ctl_reg_pnr;
+	int ctl_reg_fpr;
+	int ctl_reg_ptr;
+	int ctl_reg_dr;
+	int ctl_reg_isr;
+	int ctl_reg_mtr1;
+	int ctl_reg_mtr2;
+	int ctl_reg_mtr3;
+	int ctl_reg_mtr4;
+	int ctl_reg_miir;
+	int ctl_reg_revr;
+	int ctl_reg_ercvr;
+	int ctl_reg_extr;
+	int ctl_phy_ctrl;
+	int ctl_phy_stat;
+	int ctl_phy_id1;
+	int ctl_phy_id2;
+	int ctl_phy_adc;
+	int ctl_phy_remc;
+	int ctl_phy_cfg1;
+	int ctl_phy_cfg2;
+	int ctl_phy_int;
+	int ctl_phy_mask;
+#endif // SMC_DEBUG
+
+
+#endif // CONFIG_SYSCTL
+
+};
+
+
+/*-----------------------------------------------------------------
+ .
+ .  The driver can be entered at any of the following entry points.
+ .
+ .------------------------------------------------------------------  */
+
+/*
+ . This is called by  register_netdev().  It is responsible for
+ . checking the portlist for the SMC9000 series chipset.  If it finds
+ . one, then it will initialize the device, find the hardware information,
+ . and sets up the appropriate device parameters.
+ . NOTE: Interrupts are *OFF* when this procedure is called.
+ .
+ . NB:This shouldn't be static since it is referred to externally.
+*/
+int smc_init(struct net_device *dev);
+
+/*
+ . This is called by  unregister_netdev().  It is responsible for
+ . cleaning up before the driver is finally unregistered and discarded.
+*/
+void smc_destructor(struct net_device *dev);
+
+/*
+ . The kernel calls this function when someone wants to use the net_device,
+ . typically 'ifconfig ethX up'.
+*/
+static int smc_open(struct net_device *dev);
+
+/*
+ . This is called by the kernel to send a packet out into the net.  it's
+ . responsible for doing a best-effort send, but if it's simply not possible
+ . to send it, the packet gets dropped.
+*/
+static void smc_timeout (struct net_device *dev);
+/*
+ . This is called by the kernel in response to 'ifconfig ethX down'.  It
+ . is responsible for cleaning up everything that the open routine
+ . does, and maybe putting the card into a powerdown state.
+*/
+static int smc_close(struct net_device *dev);
+
+/*
+ . This routine allows the proc file system to query the driver's
+ . statistics.
+*/
+static struct net_device_stats * smc_query_statistics( struct net_device *dev);
+
+/*
+ . Finally, a call to set promiscuous mode ( for TCPDUMP and related
+ . programs ) and multicast modes.
+*/
+static void smc_set_multicast_list(struct net_device *dev);
+
+/*
+ . Configures the PHY through the MII Management interface
+*/
+static void smc_phy_configure(struct net_device* dev);
+
+/*---------------------------------------------------------------
+ .
+ . Interrupt level calls..
+ .
+ ----------------------------------------------------------------*/
+
+/*
+ . Handles the actual interrupt
+*/
+static void smc_interrupt(int irq, void *, struct pt_regs *regs);
+/*
+ . This is a separate procedure to handle the receipt of a packet, to
+ . leave the interrupt code looking slightly cleaner
+*/
+inline static void smc_rcv( struct net_device *dev );
+/*
+ . This handles a TX interrupt, which is only called when an error
+ . relating to a packet is sent.
+*/
+inline static void smc_tx( struct net_device * dev );
+
+/*
+ . This handles interrupts generated from PHY register 18
+*/
+static void smc_phy_interrupt(struct net_device* dev);
+
+/*
+ ------------------------------------------------------------
+ .
+ . Internal routines
+ .
+ ------------------------------------------------------------
+*/
+
+/*
+ . Test if a given location contains a chip, trying to cause as
+ . little damage as possible if it's not a SMC chip.
+*/
+static int smc_probe(struct net_device *dev, int ioaddr);
+
+/*
+ . A rather simple routine to print out a packet for debugging purposes.
+*/
+#if SMC_DEBUG > 2
+static void print_packet( byte *, int );
+#endif
+
+#define tx_done(dev) 1
+
+/* this is called to actually send the packet to the chip */
+static void smc_hardware_send_packet( struct net_device * dev );
+
+/* Since I am not sure if I will have enough room in the chip's ram
+ . to store the packet, I call this routine, which either sends it
+ . now, or generates an interrupt when the card is ready for the
+ . packet */
+static int  smc_wait_to_send_packet( struct sk_buff * skb, struct net_device *dev );
+
+/* this does a soft reset on the device */
+static void smc_reset( struct net_device* dev );
+
+/* Enable Interrupts, Receive, and Transmit */
+static void smc_enable( struct net_device *dev );
+
+/* this puts the device in an inactive state */
+static void smc_shutdown( int ioaddr );
+
+#ifndef NO_AUTOPROBE
+/* This routine will find the IRQ of the driver if one is not
+ . specified in the input to the device.  */
+static int smc_findirq( int ioaddr );
+#endif
+
+/*
+  this routine will set the hardware multicast table to the specified
+  values given it by the higher level routines
+*/
+static void smc_setmulticast( int ioaddr, int count, struct dev_mc_list *  );
+static int crc32( char *, int );
+
+/* Routines to Read and Write the PHY Registers across the
+   MII Management Interface
+*/
+
+static word smc_read_phy_register(int ioaddr, byte phyaddr, byte phyreg);
+static void smc_write_phy_register(int ioaddr, byte phyaddr, byte phyreg, word phydata);
+
+/* Initilizes our device's sysctl proc filesystem */
+
+#ifdef CONFIG_SYSCTL
+static void smc_sysctl_register(struct net_device *);
+static void smc_sysctl_unregister(struct net_device *);
+#endif /* CONFIG_SYSCTL */ 
+
+/*
+ . Function: smc_reset( struct device* dev )
+ . Purpose:
+ .  	This sets the SMC91111 chip to its normal state, hopefully from whatever
+ . 	mess that any other DOS driver has put it in.
+ .
+ . Maybe I should reset more registers to defaults in here?  SOFTRST  should
+ . do that for me.
+ .
+ . Method:
+ .	1.  send a SOFT RESET
+ .	2.  wait for it to finish
+ .	3.  enable autorelease mode
+ .	4.  reset the memory management unit
+ .	5.  clear all interrupts
+ .
+*/
+static void smc_reset( struct net_device* dev )
+{
+	//struct smc_local *lp 	= (struct smc_local *)dev->priv;
+	int	ioaddr = dev->base_addr;
+
+	PRINTK2("%s:smc_reset\n", dev->name);
+
+	/* This resets the registers mostly to defaults, but doesn't
+	   affect EEPROM.  That seems unnecessary */
+	SMC_SELECT_BANK( 0 );
+	outw( RCR_SOFTRST, ioaddr + RCR_REG );
+
+	/* Setup the Configuration Register */
+	/* This is necessary because the CONFIG_REG is not affected */
+	/* by a soft reset */
+
+	SMC_SELECT_BANK( 1 );
+	outw( CONFIG_DEFAULT, ioaddr + CONFIG_REG);
+
+	/* Setup for fast accesses if requested */
+	/* If the card/system can't handle it then there will */
+	/* be no recovery except for a hard reset or power cycle */
+
+	if (dev->dma)
+		outw( inw( ioaddr + CONFIG_REG ) | CONFIG_NO_WAIT,
+			ioaddr + CONFIG_REG );
+
+#ifdef POWER_DOWN
+	/* Release from possible power-down state */
+	/* Configuration register is not affected by Soft Reset */
+	SMC_SELECT_BANK( 1 );
+	outw( inw( ioaddr + CONFIG_REG ) | CONFIG_EPH_POWER_EN,
+		ioaddr + CONFIG_REG  );
+#endif
+
+	SMC_SELECT_BANK( 0 );
+
+	/* this should pause enough for the chip to be happy */
+	mdelay(10);
+
+	/* Disable transmit and receive functionality */
+	outw( RCR_CLEAR, ioaddr + RCR_REG );
+	outw( TCR_CLEAR, ioaddr + TCR_REG );
+
+	/* set the control register to automatically
+	   release successfully transmitted packets, to make the best
+	   use out of our limited memory */
+	SMC_SELECT_BANK( 1 );
+#if ! THROTTLE_TX_PKTS
+	outw( inw( ioaddr + CTL_REG ) | CTL_AUTO_RELEASE , ioaddr + CTL_REG );
+#else
+	outw( inw( ioaddr + CTL_REG ) & ~CTL_AUTO_RELEASE , ioaddr + CTL_REG );
+#endif
+
+	/* Reset the MMU */
+	SMC_SELECT_BANK( 2 );
+	outw( MC_RESET, ioaddr + MMU_CMD_REG );
+
+	/* Note:  It doesn't seem that waiting for the MMU busy is needed here,
+	   but this is a place where future chipsets _COULD_ break.  Be wary
+ 	   of issuing another MMU command right after this */
+
+	/* Disable all interrupts */
+	outb( 0, ioaddr + IM_REG );
+}
+
+/*
+ . Function: smc_enable
+ . Purpose: let the chip talk to the outside work
+ . Method:
+ .	1.  Enable the transmitter
+ .	2.  Enable the receiver
+ .	3.  Enable interrupts
+*/
+static void smc_enable( struct net_device *dev )
+{
+	unsigned short ioaddr 	= dev->base_addr;
+	struct smc_local *lp 	= (struct smc_local *)dev->priv;
+
+	PRINTK2("%s:smc_enable\n", dev->name);
+
+	SMC_SELECT_BANK( 0 );
+	/* see the header file for options in TCR/RCR DEFAULT*/
+	outw( lp->tcr_cur_mode, ioaddr + TCR_REG );
+	outw( lp->rcr_cur_mode, ioaddr + RCR_REG );
+
+	/* now, enable interrupts */
+	SMC_SELECT_BANK( 2 );
+	outb( SMC_INTERRUPT_MASK, ioaddr + IM_REG );
+}
+
+/*
+ . Function: smc_shutdown
+ . Purpose:  closes down the SMC91xxx chip.
+ . Method:
+ .	1. zero the interrupt mask
+ .	2. clear the enable receive flag
+ .	3. clear the enable xmit flags
+ .
+ . TODO:
+ .   (1) maybe utilize power down mode.
+ .	Why not yet?  Because while the chip will go into power down mode,
+ .	the manual says that it will wake up in response to any I/O requests
+ .	in the register space.   Empirical results do not show this working.
+*/
+static void smc_shutdown( int ioaddr )
+{
+	PRINTK2("CARDNAME:smc_shutdown\n");
+
+	/* no more interrupts for me */
+	SMC_SELECT_BANK( 2 );
+	outb( 0, ioaddr + IM_REG );
+
+	/* and tell the card to stay away from that nasty outside world */
+	SMC_SELECT_BANK( 0 );
+	outb( RCR_CLEAR, ioaddr + RCR_REG );
+	outb( TCR_CLEAR, ioaddr + TCR_REG );
+
+#ifdef POWER_DOWN
+	/* finally, shut the chip down */
+	SMC_SELECT_BANK( 1 );
+	outw( inw( ioaddr + CONFIG_REG ) & ~CONFIG_EPH_POWER_EN,
+		ioaddr + CONFIG_REG  );
+#endif
+}
+
+
+/*
+ . Function: smc_setmulticast( int ioaddr, int count, dev_mc_list * adds )
+ . Purpose:
+ .    This sets the internal hardware table to filter out unwanted multicast
+ .    packets before they take up memory.
+ .
+ .    The SMC chip uses a hash table where the high 6 bits of the CRC of
+ .    address are the offset into the table.  If that bit is 1, then the
+ .    multicast packet is accepted.  Otherwise, it's dropped silently.
+ .
+ .    To use the 6 bits as an offset into the table, the high 3 bits are the
+ .    number of the 8 bit register, while the low 3 bits are the bit within
+ .    that register.
+ .
+ . This routine is based very heavily on the one provided by Peter Cammaert.
+*/
+
+
+static void smc_setmulticast( int ioaddr, int count, struct dev_mc_list * addrs ) {
+	int			i;
+	unsigned char		multicast_table[ 8 ];
+	struct dev_mc_list	* cur_addr;
+	/* table for flipping the order of 3 bits */
+	unsigned char invert3[] = { 0, 4, 2, 6, 1, 5, 3, 7 };
+
+	PRINTK2("CARDNAME:smc_setmulticast\n");
+
+	/* start with a table of all zeros: reject all */
+	memset( multicast_table, 0, sizeof( multicast_table ) );
+
+	cur_addr = addrs;
+	for ( i = 0; i < count ; i ++, cur_addr = cur_addr->next  ) {
+		int position;
+
+		/* do we have a pointer here? */
+		if ( !cur_addr )
+			break;
+		/* make sure this is a multicast address - shouldn't this
+		   be a given if we have it here ? */
+		if ( !( *cur_addr->dmi_addr & 1 ) )
+			continue;
+
+		/* only use the low order bits */
+		position = crc32( cur_addr->dmi_addr, 6 ) & 0x3f;
+
+		/* do some messy swapping to put the bit in the right spot */
+		multicast_table[invert3[position&7]] |=
+					(1<<invert3[(position>>3)&7]);
+
+	}
+	/* now, the table can be loaded into the chipset */
+	SMC_SELECT_BANK( 3 );
+
+	for ( i = 0; i < 8 ; i++ ) {
+		outb( multicast_table[i], ioaddr + MCAST_REG1 + i );
+	}
+}
+
+/*
+  Finds the CRC32 of a set of bytes.
+  Again, from Peter Cammaert's code.
+*/
+static int crc32( char * s, int length ) {
+	/* indices */
+	int perByte;
+	int perBit;
+	/* crc polynomial for Ethernet */
+	const unsigned long poly = 0xedb88320;
+	/* crc value - preinitialized to all 1's */
+	unsigned long crc_value = 0xffffffff;
+
+	for ( perByte = 0; perByte < length; perByte ++ ) {
+		unsigned char	c;
+
+		c = *(s++);
+		for ( perBit = 0; perBit < 8; perBit++ ) {
+			crc_value = (crc_value>>1)^
+				(((crc_value^c)&0x01)?poly:0);
+			c >>= 1;
+		}
+	}
+	return	crc_value;
+}
+
+
+/*
+ . Function: smc_wait_to_send_packet( struct sk_buff * skb, struct device * )
+ . Purpose:
+ .    Attempt to allocate memory for a packet, if chip-memory is not
+ .    available, then tell the card to generate an interrupt when it
+ .    is available.
+ .
+ . Algorithm:
+ .
+ . o	if the saved_skb is not currently null, then drop this packet
+ .	on the floor.  This should never happen, because of TBUSY.
+ . o	if the saved_skb is null, then replace it with the current packet,
+ . o	See if I can sending it now.
+ . o 	(NO): Enable interrupts and let the interrupt handler deal with it.
+ . o	(YES):Send it now.
+*/
+static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * dev )
+{
+	struct smc_local *lp 	= (struct smc_local *)dev->priv;
+	unsigned short ioaddr 	= dev->base_addr;
+	word 			length;
+	unsigned short 		numPages;
+	word			time_out;
+	word			status;
+        unsigned long flags;
+
+	PRINTK3("%s:smc_wait_to_send_packet\n", dev->name);
+
+	spin_lock_irqsave(&lp->lock, flags);
+
+	if ( lp->saved_skb) {
+		/* THIS SHOULD NEVER HAPPEN. */
+		lp->stats.tx_aborted_errors++;
+		printk("%s: Bad Craziness - sent packet while busy.\n",
+			dev->name);
+		spin_unlock_irqrestore(&lp->lock, flags);
+		return 1;
+	}
+	lp->saved_skb = skb;
+
+	length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+
+		
+	/*
+	** The MMU wants the number of pages to be the number of 256 bytes
+	** 'pages', minus 1 ( since a packet can't ever have 0 pages :) )
+	**
+	** The 91C111 ignores the size bits, but the code is left intact
+	** for backwards and future compatibility.
+	**
+	** Pkt size for allocating is data length +6 (for additional status
+	** words, length and ctl!)
+	**
+	** If odd size then last byte is included in this header.
+	*/
+	numPages =   ((length & 0xfffe) + 6);
+	numPages >>= 8; // Divide by 256
+
+	if (numPages > 7 ) {
+		printk("%s: Far too big packet error. \n", dev->name);
+		/* freeing the packet is a good thing here... but should
+		 . any packets of this size get down here?   */
+		dev_kfree_skb (skb);
+		lp->saved_skb = NULL;
+		/* this IS an error, but, i don't want the skb saved */
+		netif_wake_queue(dev);
+		spin_unlock_irqrestore(&lp->lock, flags);
+		return 0;
+	}
+	/* either way, a packet is waiting now */
+	lp->packets_waiting++;
+
+	/* now, try to allocate the memory */
+	SMC_SELECT_BANK( 2 );
+	outw( MC_ALLOC | numPages, ioaddr + MMU_CMD_REG );
+	/*
+ 	. Performance Hack
+	.
+ 	. wait a short amount of time.. if I can send a packet now, I send
+	. it now.  Otherwise, I enable an interrupt and wait for one to be
+	. available.
+	.
+	. I could have handled this a slightly different way, by checking to
+	. see if any memory was available in the FREE MEMORY register.  However,
+	. either way, I need to generate an allocation, and the allocation works
+	. no matter what, so I saw no point in checking free memory.
+	*/
+	time_out = MEMORY_WAIT_TIME;
+	do {
+		status = inb( ioaddr + INT_REG );
+		if ( status & IM_ALLOC_INT ) {
+			/* acknowledge the interrupt */
+			outb( IM_ALLOC_INT, ioaddr + INT_REG );
+  			break;
+		}
+   	} while ( -- time_out );
+
+   	if ( !time_out ) {
+#if defined(__m32r__)
+//		netif_stop_queue(dev); 	// 2003-07-13 by takeo
+#endif
+		/* oh well, wait until the chip finds memory later */
+		SMC_ENABLE_INT( IM_ALLOC_INT );
+
+		/* Check the status bit one more time just in case */
+		/* it snuk in between the time we last checked it */
+		/* and when we set the interrupt bit */
+		status = inb( ioaddr + INT_REG );
+		if ( !(status & IM_ALLOC_INT) ) {
+      			PRINTK2("%s: memory allocation deferred. \n",
+				dev->name);
+			/* it's deferred, but I'll handle it later */
+			spin_unlock_irqrestore(&lp->lock, flags);
+      			return 0;
+			}
+
+		/* Looks like it did sneak in, so disable */
+		/* the interrupt */
+		SMC_DISABLE_INT( IM_ALLOC_INT );
+	}
+	/* or YES! I can send the packet now.. */
+#if THROTTLE_TX_PKTS
+                netif_stop_queue(dev);
+#endif
+	smc_hardware_send_packet(dev);
+
+	spin_unlock_irqrestore(&lp->lock, flags);
+
+	return 0;
+}
+
+/*
+ . Function:  smc_hardware_send_packet(struct device * )
+ . Purpose:
+ .	This sends the actual packet to the SMC9xxx chip.
+ .
+ . Algorithm:
+ . 	First, see if a saved_skb is available.
+ .		( this should NOT be called if there is no 'saved_skb'
+ .	Now, find the packet number that the chip allocated
+ .	Point the data pointers at it in memory
+ .	Set the length word in the chip's memory
+ .	Dump the packet to chip memory
+ .	Check if a last byte is needed ( odd length packet )
+ .		if so, set the control flag right
+ . 	Tell the card to send it
+ .	Enable the transmit interrupt, so I know if it failed
+ . 	Free the kernel data if I actually sent it.
+*/
+static void smc_hardware_send_packet( struct net_device * dev )
+{
+	struct smc_local *lp = (struct smc_local *)dev->priv;
+	byte	 		packet_no;
+	struct sk_buff * 	skb = lp->saved_skb;
+	word			length;
+	unsigned short		ioaddr;
+	byte			* buf;
+
+	PRINTK3("%s:smc_hardware_send_packet\n", dev->name);
+
+	ioaddr = dev->base_addr;
+
+	if ( !skb ) {
+		PRINTK("%s: In XMIT with no packet to send \n", dev->name);
+		return;
+	}
+	length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+	buf = skb->data;
+
+	/* If I get here, I _know_ there is a packet slot waiting for me */
+	packet_no = inb( ioaddr + AR_REG );
+	if ( packet_no & AR_FAILED ) {
+		/* or isn't there?  BAD CHIP! */
+		printk(KERN_DEBUG "%s: Memory allocation failed. \n",
+			dev->name);
+		dev_kfree_skb_any (skb);
+		lp->saved_skb = NULL;
+		netif_wake_queue(dev);
+		return;
+	}
+
+	/* we have a packet address, so tell the card to use it */
+	outb( packet_no, ioaddr + PN_REG );
+
+	/* point to the beginning of the packet */
+	outw( PTR_AUTOINC , ioaddr + PTR_REG );
+
+   	PRINTK3("%s: Trying to xmit packet of length %x\n",
+		dev->name, length);
+
+#if SMC_DEBUG > 2
+	printk("Transmitting Packet\n");
+	print_packet( buf, length );
+#endif
+
+	/* send the packet length ( +6 for status, length and ctl byte )
+ 	   and the status word ( set to zeros ) */
+#ifdef USE_32_BIT
+	outl(  (length +6 ) << 16 , ioaddr + DATA_REG );
+#else
+	outw( 0, ioaddr + DATA_REG );
+	/* send the packet length ( +6 for status words, length, and ctl*/
+	outb( (length+6) & 0xFF,ioaddr + DATA_REG );
+	outb( (length+6) >> 8 , ioaddr + DATA_REG );
+#endif
+
+	/* send the actual data
+	 . I _think_ it's faster to send the longs first, and then
+	 . mop up by sending the last word.  It depends heavily
+ 	 . on alignment, at least on the 486.  Maybe it would be
+ 	 . a good idea to check which is optimal?  But that could take
+	 . almost as much time as is saved?
+	*/
+#ifdef USE_32_BIT
+	outsl(ioaddr + DATA_REG, buf,  length >> 2 );
+	if ( length & 0x2  )
+		outw(*((word *)(buf + (length & 0xFFFFFFFC))),ioaddr +DATA_REG);
+#else
+	outsw(ioaddr + DATA_REG , buf, (length ) >> 1);
+#endif // USE_32_BIT
+
+	/* Send the last byte, if there is one.   */
+	if ( (length & 1) == 0 ) {
+		outw( 0, ioaddr + DATA_REG );
+	} else {
+		outb( buf[length -1 ], ioaddr + DATA_REG );
+		outb( 0x20, ioaddr + DATA_REG); // Set odd bit in CONTROL BYTE
+	}
+
+	/* and let the chipset deal with it */
+	outw( MC_ENQUEUE , ioaddr + MMU_CMD_REG );
+
+	/* enable the interrupts */
+	SMC_ENABLE_INT( (IM_TX_INT | IM_TX_EMPTY_INT) );
+
+	PRINTK2("%s: Sent packet of length %d \n", dev->name, length);
+#if defined(__m32r__)
+	lp->stats.tx_bytes += length;
+#endif
+
+	lp->saved_skb = NULL;
+	dev_kfree_skb_any (skb);
+
+	dev->trans_start = jiffies;
+
+	/* we can send another packet */
+	//	netif_wake_queue(dev);
+
+
+	return;
+}
+
+/*-------------------------------------------------------------------------
+ |
+ | smc_init( struct device * dev )
+ |   Input parameters:
+ |	dev->base_addr == 0, try to find all possible locations
+ |	dev->base_addr == 1, return failure code
+ |	dev->base_addr == 2, always allocate space,  and return success
+ |	dev->base_addr == <anything else>   this is the address to check
+ |
+ |   Output:
+ |	0 --> there is a device
+ |	anything else, error
+ |
+ ---------------------------------------------------------------------------
+*/
+int __init smc_init(struct net_device *dev)
+{
+	int i;
+	int base_addr = dev ? dev->base_addr : 0;
+
+	PRINTK2("CARDNAME:smc_init\n");
+
+#ifdef MODULE
+	SET_MODULE_OWNER (dev);
+#endif
+
+	/*  try a specific location */
+	if (base_addr > 0x1ff)
+		return smc_probe(dev, base_addr);
+	else if ( 0 != base_addr ) 
+			return -ENXIO;
+		
+	/* check every ethernet address */
+	for (i = 0; smc_portlist[i]; i++) 
+		if ( smc_probe(dev,smc_portlist[i]) ==0)
+			return 0;
+		
+	/* couldn't find anything */
+	return -ENODEV;
+}
+
+
+/*-------------------------------------------------------------------------
+ |
+ | smc_destructor( struct device * dev )
+ |   Input parameters:
+ |	dev, pointer to the device structure
+ |
+ |   Output:
+ |	None.
+ |
+ ---------------------------------------------------------------------------
+*/
+void smc_destructor(struct net_device *dev)
+{
+	PRINTK2("CARDNAME:smc_destructor\n");
+}
+
+
+#ifndef NO_AUTOPROBE
+/*----------------------------------------------------------------------
+ . smc_findirq
+ .
+ . This routine has a simple purpose -- make the SMC chip generate an
+ . interrupt, so an auto-detect routine can detect it, and find the IRQ,
+ ------------------------------------------------------------------------
+*/
+int __init smc_findirq( int ioaddr )
+{
+	int	timeout = 20;
+	unsigned long cookie;
+
+	PRINTK2("CARDNAME:smc_findirq\n");
+
+	/* I have to do a STI() here, because this is called from
+	   a routine that does an CLI during this process, making it
+	   rather difficult to get interrupts for auto detection */
+	sti();
+
+	cookie = probe_irq_on();
+
+	/*
+	 * What I try to do here is trigger an ALLOC_INT. This is done
+	 * by allocating a small chunk of memory, which will give an interrupt
+	 * when done.
+	 */
+
+
+	SMC_SELECT_BANK(2);
+	/* enable ALLOCation interrupts ONLY */
+	outb( IM_ALLOC_INT, ioaddr + IM_REG );
+
+	/*
+ 	 . Allocate 512 bytes of memory.  Note that the chip was just
+	 . reset so all the memory is available
+	*/
+	outw( MC_ALLOC | 1, ioaddr + MMU_CMD_REG );
+
+	/*
+	 . Wait until positive that the interrupt has been generated
+	*/
+	while ( timeout ) {
+		byte	int_status;
+
+		int_status = inb( ioaddr + INT_REG );
+
+		if ( int_status & IM_ALLOC_INT )
+			break;		/* got the interrupt */
+		timeout--;
+	}
+
+	/* there is really nothing that I can do here if timeout fails,
+	   as autoirq_report will return a 0 anyway, which is what I
+	   want in this case.   Plus, the clean up is needed in both
+	   cases.  */
+
+	/* DELAY HERE!
+	   On a fast machine, the status might change before the interrupt
+	   is given to the processor.  This means that the interrupt was
+	   never detected, and autoirq_report fails to report anything.
+	   This should fix autoirq_* problems.
+	*/
+	mdelay(10);
+
+	/* and disable all interrupts again */
+	outb( 0, ioaddr + IM_REG );
+
+	/* clear hardware interrupts again, because that's how it
+	   was when I was called... */
+	cli();
+
+	/* and return what I found */
+	return probe_irq_off(cookie);
+}
+#endif
+
+/*----------------------------------------------------------------------
+ . Function: smc_probe( int ioaddr )
+ .
+ . Purpose:
+ .	Tests to see if a given ioaddr points to an SMC91111 chip.
+ .	Returns a 0 on success
+ .
+ . Algorithm:
+ .	(1) see if the high byte of BANK_SELECT is 0x33
+ . 	(2) compare the ioaddr with the base register's address
+ .	(3) see if I recognize the chip ID in the appropriate register
+ .
+ .---------------------------------------------------------------------
+ */
+/*---------------------------------------------------------------
+ . Here I do typical initialization tasks.
+ .
+ . o  Initialize the structure if needed
+ . o  print out my vanity message if not done so already
+ . o  print out what type of hardware is detected
+ . o  print out the ethernet address
+ . o  find the IRQ
+ . o  set up my private data
+ . o  configure the dev structure with my subroutines
+ . o  actually GRAB the irq.
+ . o  GRAB the region
+ .-----------------------------------------------------------------*/
+
+static int __init smc_probe(struct net_device *dev, int ioaddr )
+{
+	int i, memory, retval;
+	static unsigned version_printed = 0;
+	unsigned int	bank;
+
+        const char *version_string;
+
+	/*registers */
+	word	revision_register;
+	word	base_address_register;
+	word  	memory_info_register;
+	/*=> Pramod */
+	struct smc_local *lp;
+	/*<= Pramod */
+
+	PRINTK2("CARDNAME:smc_probe\n");
+
+	/* Grab the region so that no one else tries to probe our ioports. */
+	if (!request_region(ioaddr, SMC_IO_EXTENT, dev->name)) return -EBUSY;
+
+	/* First, see if the high byte is 0x33 */
+	bank = inw( ioaddr + BANK_SELECT );
+	if ( (bank & 0xFF00) != 0x3300 ) return -ENODEV;
+
+	/* The above MIGHT indicate a device, but I need to write to further test this.  */
+	outw( 0x0, ioaddr + BANK_SELECT );
+	bank = inw( ioaddr + BANK_SELECT );
+	if ( (bank & 0xFF00 ) != 0x3300 )
+	{
+		retval = -ENODEV;
+		goto err_out;
+	}
+
+	/* well, we've already written once, so hopefully another time won't
+ 	   hurt.  This time, I need to switch the bank register to bank 1,
+	   so I can access the base address register */
+	SMC_SELECT_BANK(1);
+	base_address_register = inw( ioaddr + BASE_REG );
+	if ( ioaddr != ( base_address_register >> 3 & 0x3E0 ) )
+	{
+		printk("CARDNAME: IOADDR %x doesn't match configuration (%x)."
+			"Probably not a SMC chip\n",
+			ioaddr, base_address_register >> 3 & 0x3E0 );
+		/* well, the base address register didn't match.  Must not have
+		   been a SMC chip after all. */
+		retval = -ENODEV;
+		goto err_out;
+	}
+
+	/*  check if the revision register is something that I recognize.
+	    These might need to be added to later, as future revisions
+	    could be added.  */
+	SMC_SELECT_BANK(3);
+	revision_register  = inw( ioaddr + REV_REG );
+	if ( !chip_ids[ ( revision_register  >> 4 ) & 0xF  ] )
+	{
+		/* I don't recognize this chip, so... */
+		printk("CARDNAME: IO %x: Unrecognized revision register:"
+			" %x, Contact author. \n",
+			ioaddr, revision_register );
+		retval =  -ENODEV;
+		goto err_out;
+	}
+
+	/* at this point I'll assume that the chip is an SMC9xxx.
+	   It might be prudent to check a listing of MAC addresses
+	   against the hardware address, or do some other tests. */
+
+	if (version_printed++ == 0)
+		printk("%s", version);
+
+	/* fill in some of the fields */
+	dev->base_addr = ioaddr;
+
+	//	dev->dma=1;
+
+	/*
+ 	 . Get the MAC address ( bank 1, regs 4 - 9 )
+	*/
+	SMC_SELECT_BANK( 1 );
+	for ( i = 0; i < 6; i += 2 )
+	{
+		word	address;
+
+		address = inw( ioaddr + ADDR0_REG + i  );
+		dev->dev_addr[ i + 1] = address >> 8;
+		dev->dev_addr[ i ] = address & 0xFF;
+	}
+
+	/* get the memory information */
+
+	SMC_SELECT_BANK( 0 );
+	memory_info_register = inw( ioaddr + MIR_REG );
+	memory = memory_info_register & (word)0x00ff;
+	memory *= LAN91C111_MEMORY_MULTIPLIER;
+
+	/*
+	 Now, I want to find out more about the chip.  This is sort of
+ 	 redundant, but it's cleaner to have it in both, rather than having
+ 	 one VERY long probe procedure.
+	*/
+	SMC_SELECT_BANK(3);
+	revision_register  = inw( ioaddr + REV_REG );
+	version_string = chip_ids[ ( revision_register  >> 4 ) & 0xF  ];
+	if ( !version_string )
+	{
+		/* I shouldn't get here because this call was done before.... */
+		retval =  -ENODEV;
+		goto err_out;
+	}
+
+	/* now, reset the chip, and put it into a known state */
+	smc_reset( dev );
+
+	/*
+	 . If dev->irq is 0, then the device has to be banged on to see
+	 . what the IRQ is.
+ 	 .
+	 . This banging doesn't always detect the IRQ, for unknown reasons.
+	 . a workaround is to reset the chip and try again.
+	 .
+	 . Interestingly, the DOS packet driver *SETS* the IRQ on the card to
+	 . be what is requested on the command line.   I don't do that, mostly
+	 . because the card that I have uses a non-standard method of accessing
+	 . the IRQs, and because this _should_ work in most configurations.
+	 .
+	 . Specifying an IRQ is done with the assumption that the user knows
+	 . what (s)he is doing.  No checking is done!!!!
+ 	 .
+	*/
+#if defined(CONFIG_PLAT_M32700UT) && defined(NO_AUTOPROBE)
+	dev->irq = M32700UT_LAN_IRQ_LAN;
+#endif
+#if defined(CONFIG_PLAT_M32700UT_Alpha) && defined(NO_AUTOPROBE)
+	dev->irq = M32R_IRQ_INT0;
+#endif
+#if defined(CONFIG_PLAT_OPSPUT) && defined(NO_AUTOPROBE)
+	dev->irq = OPSPUT_LAN_IRQ_LAN;
+#endif
+#ifndef NO_AUTOPROBE	// by takeo
+	if ( dev->irq < 2 ) {
+		int	trials;
+
+		trials = 3;
+		while ( trials-- ) {
+			dev->irq = smc_findirq( ioaddr );
+			if ( dev->irq )
+				break;
+			/* kick the card and try again */
+			smc_reset( dev );
+		}
+	}
+
+	if (dev->irq == 0 ) {
+		printk("%s: Couldn't autodetect your IRQ. Use irq=xx.\n",
+			dev->name);
+		retval =  -ENODEV;
+		goto err_out;
+	}
+
+	if (dev->irq == 2) {
+		/* Fixup for users that don't know that IRQ 2 is really IRQ 9,
+		 * or don't know which one to set.
+		 */
+		dev->irq = 9;
+	}
+#endif
+
+	/* now, print out the card info, in a short format.. */
+
+	printk("%s: %s(rev:%d) at %#3x IRQ:%d MEMSIZE:%db NOWAIT:%d ",
+		dev->name,
+		version_string, revision_register & 0xF, ioaddr, dev->irq,
+		memory, dev->dma);
+	/*
+	 . Print the Ethernet address
+	*/
+	printk("ADDR: ");
+	for (i = 0; i < 5; i++)
+		printk("%2.2x:", dev->dev_addr[i] );
+	printk("%2.2x \n", dev->dev_addr[5] );
+
+	/* Initialize the private structure. */
+	if (dev->priv == NULL) {
+		dev->priv = kmalloc(sizeof(struct smc_local), GFP_KERNEL);
+		if (dev->priv == NULL) {
+			retval = -ENOMEM;
+			goto err_out;
+		}
+	}
+	/* set the private data to zero by default */
+	memset(dev->priv, 0, sizeof(struct smc_local));
+
+	/* Fill in the fields of the device structure with ethernet values. */
+	ether_setup(dev);
+
+	/* Grab the IRQ */
+    retval = request_irq(dev->irq, &smc_interrupt, 0, dev->name, dev);
+    if (retval) {
+       	  printk("%s: unable to get IRQ %d (irqval=%d).\n",
+		dev->name, dev->irq, retval);
+		  kfree (dev->priv);
+		  dev->priv = NULL;
+		  goto err_out;
+      	}
+
+	dev->open		        = smc_open;
+	dev->stop		        = smc_close;
+	dev->hard_start_xmit   	= smc_wait_to_send_packet;
+	dev->tx_timeout			= smc_timeout;
+	dev->get_stats			= smc_query_statistics;
+#ifdef	HAVE_MULTICAST
+	dev->set_multicast_list 	= &smc_set_multicast_list;
+#endif
+
+	/* => Store the ChipRevision and ChipID, to be used in resolving the Odd-Byte issue in RevB of LAN91C111; Pramod */
+	SMC_SELECT_BANK(3);
+	revision_register  = inw( ioaddr + REV_REG );
+	lp = (struct smc_local *)dev->priv;
+	lp->ChipID = (revision_register >> 4) & 0xF;
+	lp->ChipRev = revision_register & 0xF;
+
+        spin_lock_init(&lp->lock);
+
+	return 0;
+
+err_out:
+	release_region (ioaddr, SMC_IO_EXTENT);
+	return retval;
+}
+
+#if SMC_DEBUG > 2
+static void print_packet( byte * buf, int length )
+{
+#if 1
+	int i;
+	int remainder;
+	int lines;
+
+	printk("Packet of length %d \n", length );
+
+#if SMC_DEBUG > 3
+	lines = length / 16;
+	remainder = length % 16;
+
+	for ( i = 0; i < lines ; i ++ ) {
+		int cur;
+
+		for ( cur = 0; cur < 8; cur ++ ) {
+			byte a, b;
+
+			a = *(buf ++ );
+			b = *(buf ++ );
+			printk("%02x%02x ", a, b );
+		}
+		printk("\n");
+	}
+	for ( i = 0; i < remainder/2 ; i++ ) {
+		byte a, b;
+
+		a = *(buf ++ );
+		b = *(buf ++ );
+		printk("%02x%02x ", a, b );
+	}
+	printk("\n");
+#endif
+#endif
+}
+#endif
+
+
+/*
+ * Open and Initialize the board
+ *
+ * Set up everything, reset the card, etc ..
+ *
+ */
+static int smc_open(struct net_device *dev)
+{
+	struct smc_local *lp 	= (struct smc_local *)dev->priv;
+	int	ioaddr = dev->base_addr;
+	int	i;	/* used to set hw ethernet address */
+
+	PRINTK2("%s:smc_open\n", dev->name);
+
+#if 0
+	/* clear out all the junk that was put here before... */
+	memset(dev->priv, 0, sizeof(struct smc_local));
+#endif
+
+	netif_start_queue(dev);
+#ifdef MODULE
+	MOD_INC_USE_COUNT;
+#endif
+
+	// Setup the default Register Modes
+	lp->tcr_cur_mode = TCR_DEFAULT;
+	lp->rcr_cur_mode = RCR_DEFAULT;
+	lp->rpc_cur_mode = RPC_DEFAULT;
+
+	// Set default parameters (files)
+	lp->ctl_swfdup = 0;
+	lp->ctl_ephloop = 0;
+	lp->ctl_miiop = 0;
+	lp->ctl_autoneg = 1;
+	lp->ctl_rfduplx = 1;
+	lp->ctl_rspeed = 100;
+	lp->ctl_afduplx = 1;
+	lp->ctl_aspeed = 100;
+	lp->ctl_lnkfail = 1;
+	lp->ctl_forcol = 0;
+	lp->ctl_filtcar = 0;
+
+	/* reset the hardware */
+
+	smc_reset( dev );
+	smc_enable( dev );
+
+	/* Configure the PHY */
+	smc_phy_configure(dev);
+
+	/*
+  		According to Becker, I have to set the hardware address
+		at this point, because the (l)user can set it with an
+		ioctl.  Easily done...
+	*/
+	SMC_SELECT_BANK( 1 );
+	for ( i = 0; i < 6; i += 2 ) {
+		word	address;
+
+		address = dev->dev_addr[ i + 1 ] << 8 ;
+		address  |= dev->dev_addr[ i ];
+		outw( address, ioaddr + ADDR0_REG + i );
+	}
+
+#ifdef CONFIG_SYSCTL
+	smc_sysctl_register(dev);
+#endif /* CONFIG_SYSCTL */ 
+
+	netif_start_queue(dev);
+	return 0;
+}
+
+/*--------------------------------------------------------
+ . Called by the kernel to send a packet out into the void
+ . of the net.  This routine is largely based on
+ . skeleton.c, from Becker.
+ .--------------------------------------------------------
+*/
+static void smc_timeout (struct net_device *dev)
+{
+
+        struct smc_local *lp = (struct smc_local *)dev->priv;
+        unsigned long flags;
+
+        /*
+         *      Best would be to use synchronize_irq(); spin_lock() here
+         *      lets make it work first..
+         */
+         
+	spin_lock_irqsave(&lp->lock, flags);
+
+	PRINTK3("%s:smc_send_packet\n", dev->name);
+
+	/* If we get here, some higher level has decided we are broken.
+	There should really be a "kick me" function call instead. */
+	printk(KERN_WARNING "%s: transmit timed out, %s?\n",dev->name, tx_done(dev) ? "IRQ conflict" :"network cable problem");
+	/* "kick" the adaptor */
+	smc_reset( dev );
+	smc_enable( dev );
+
+	/* Reconfigure the PHY */
+	smc_phy_configure(dev);
+
+	dev->trans_start = jiffies;
+	/* clear anything saved */
+	((struct smc_local *)dev->priv)->saved_skb = NULL;
+
+	spin_unlock_irqrestore(&lp->lock, flags);
+
+	netif_wake_queue(dev);
+}
+
+/*--------------------------------------------------------------------
+ .
+ . This is the main routine of the driver, to handle the net_device when
+ . it needs some attention.
+ .
+ . So:
+ .   first, save state of the chipset
+ .   branch off into routines to handle each case, and acknowledge
+ .	    each to the interrupt register
+ .   and finally restore state.
+ .
+ ---------------------------------------------------------------------*/
+static void smc_interrupt(int irq, void * dev_id,  struct pt_regs * regs)
+{
+	struct net_device *dev 	= dev_id;
+	int ioaddr 		= dev->base_addr;
+	struct smc_local *lp 	= (struct smc_local *)dev->priv;
+
+	byte	status;
+	word	card_stats;
+	byte	mask;
+	int	timeout;
+	/* state registers */
+	word	saved_bank;
+	word	saved_pointer;
+
+	PRINTK3("%s: SMC interrupt started \n", dev->name);
+
+	if (dev == NULL) {
+		printk(KERN_WARNING "%s: irq %d for unknown device.\n",
+			dev->name, irq);
+		return;
+	}
+
+/* will Linux let this happen ??  If not, this costs some speed 
+	if ( dev->interrupt ) {
+		printk(KERN_WARNING "%s: interrupt inside interrupt.\n",
+			dev->name);
+		return;
+	}
+	dev->interrupt = 1; */
+
+	spin_lock(&lp->lock);
+
+	saved_bank = inw( ioaddr + BANK_SELECT );
+
+	SMC_SELECT_BANK(2);
+	saved_pointer = inw( ioaddr + PTR_REG );
+
+	/* read the interrupt status register */
+	mask = inb( ioaddr + IM_REG );
+
+	/* disable all interrupts */
+	outb( 0, ioaddr + IM_REG );
+
+
+	/* set a timeout value, so I don't stay here forever */
+	timeout = 8;
+
+	PRINTK2(KERN_WARNING "%s: MASK IS %x \n", dev->name, mask);
+	do {
+		/* read the status flag, and mask it */
+		status = inb( ioaddr + INT_REG ) & mask;
+		if (!status )
+			break;
+
+		PRINTK3(KERN_WARNING "%s: Handling interrupt status %x \n",
+			dev->name, status);
+
+		if (status & IM_RCV_INT) {
+			/* Got a packet(s). */
+			PRINTK2(KERN_WARNING
+				"%s: Receive Interrupt\n", dev->name);
+			smc_rcv(dev);
+		} else if (status & IM_TX_INT ) {
+			PRINTK2(KERN_WARNING "%s: TX ERROR handled\n",
+				dev->name);
+			smc_tx(dev);
+			// Acknowledge the interrupt
+			outb(IM_TX_INT, ioaddr + INT_REG );
+#if THROTTLE_TX_PKTS
+                        netif_wake_queue(dev);
+#endif
+		} else if (status & IM_TX_EMPTY_INT ) {
+			/* update stats */
+			SMC_SELECT_BANK( 0 );
+			card_stats = inw( ioaddr + COUNTER_REG );
+			/* single collisions */
+			lp->stats.collisions += card_stats & 0xF;
+			card_stats >>= 4;
+			/* multiple collisions */
+			lp->stats.collisions += card_stats & 0xF;
+
+			/* these are for when linux supports these statistics */
+#if 0
+			card_stats >>= 4;
+			/* deferred */
+			card_stats >>= 4;
+			/* excess deferred */
+#endif
+			SMC_SELECT_BANK( 2 );
+			PRINTK2(KERN_WARNING "%s: TX_BUFFER_EMPTY handled\n",
+				dev->name);
+			// Acknowledge the interrupt
+			outb( IM_TX_EMPTY_INT, ioaddr + INT_REG );
+			mask &= ~IM_TX_EMPTY_INT;
+			lp->stats.tx_packets += lp->packets_waiting;
+			lp->packets_waiting = 0;
+
+		} else if (status & IM_ALLOC_INT ) {
+			PRINTK2(KERN_DEBUG "%s: Allocation interrupt \n",
+				dev->name);
+			/* clear this interrupt so it doesn't happen again */
+			mask &= ~IM_ALLOC_INT;
+
+			smc_hardware_send_packet( dev );
+
+			/* enable xmit interrupts based on this */
+			mask |= ( IM_TX_EMPTY_INT | IM_TX_INT );
+
+			/* and let the card send more packets to me */
+#if ! THROTTLE_TX_PKTS
+                        netif_wake_queue(dev);
+#endif
+
+			PRINTK2("%s: Handoff done successfully.\n",
+				dev->name);
+		} else if (status & IM_RX_OVRN_INT ) {
+			PRINTK2("%s: IM_RX_OVRN_INT \n",dev->name);
+			lp->stats.rx_errors++;
+			lp->stats.rx_fifo_errors++;
+			// Acknowledge the interrupt
+			outb( IM_RX_OVRN_INT, ioaddr + INT_REG );
+		} else if (status & IM_EPH_INT ) {
+			PRINTK("%s: UNSUPPORTED: EPH INTERRUPT \n",
+				dev->name);
+		} else if (status & IM_MDINT ) {
+			smc_phy_interrupt(dev);
+			// Acknowledge the interrupt
+			outb(IM_MDINT, ioaddr + INT_REG );
+		} else if (status & IM_ERCV_INT ) {
+			PRINTK("%s: UNSUPPORTED: ERCV INTERRUPT \n",
+				dev->name);
+			// Acknowledge the interrupt
+			outb( IM_ERCV_INT, ioaddr + INT_REG );
+		}
+	} while ( timeout -- );
+
+
+	/* restore register states */
+
+	SMC_SELECT_BANK( 2 );
+
+	outb( mask, ioaddr + IM_REG );
+
+	PRINTK3( KERN_WARNING "%s: MASK is now %x \n", dev->name, mask);
+	outw( saved_pointer, ioaddr + PTR_REG );
+
+	SMC_SELECT_BANK( saved_bank );
+
+	//dev->interrupt = 0;
+	PRINTK3("%s: Interrupt done\n", dev->name);
+
+	spin_unlock(&lp->lock);
+
+	return;
+}
+
+/*-------------------------------------------------------------
+ .
+ . smc_rcv -  receive a packet from the card
+ .
+ . There is ( at least ) a packet waiting to be read from
+ . chip-memory.
+ .
+ . o Read the status
+ . o If an error, record it
+ . o otherwise, read in the packet
+ --------------------------------------------------------------
+*/
+static void smc_rcv(struct net_device *dev)
+{
+	struct smc_local *lp = (struct smc_local *)dev->priv;
+	int 	ioaddr = dev->base_addr;
+	int 	packet_number;
+	word	status;
+	word	packet_length;
+
+	PRINTK3("%s:smc_rcv\n", dev->name);
+
+	/* assume bank 2 */
+
+	packet_number = inw( ioaddr + RXFIFO_REG );
+
+	if ( packet_number & RXFIFO_REMPTY ) {
+
+		/* we got called , but nothing was on the FIFO */
+		PRINTK("%s: WARNING: smc_rcv with nothing on FIFO. \n",
+			dev->name);
+		/* don't need to restore anything */
+		return;
+	}
+
+	/*  start reading from the start of the packet */
+	outw( PTR_READ | PTR_RCV | PTR_AUTOINC, ioaddr + PTR_REG );
+
+	/* First two words are status and packet_length */
+	status 		= inw( ioaddr + DATA_REG );
+	packet_length 	= inw( ioaddr + DATA_REG );
+
+	packet_length &= 0x07ff;  /* mask off top bits */
+
+	PRINTK2("RCV: STATUS %4x LENGTH %4x\n", status, packet_length );
+
+	if ( !(status & RS_ERRORS ) ){
+		/* do stuff to make a new packet */
+		struct sk_buff  * skb;
+		byte		* data;
+
+		/* set multicast stats */
+		if ( status & RS_MULTICAST )
+			lp->stats.multicast++;
+
+		// Allocate enough memory for entire receive frame, to be safe
+		skb = dev_alloc_skb( packet_length );
+
+		/* Adjust for having already read the first two words */
+		packet_length -= 4;
+
+		if ( skb == NULL ) {
+			printk(KERN_NOTICE "%s: Low memory, packet dropped.\n",
+				dev->name);
+			lp->stats.rx_dropped++;
+			goto done;
+		}
+
+		/*
+		 ! This should work without alignment, but it could be
+		 ! in the worse case
+		*/
+		/* TODO: Should I use 32bit alignment here ? */
+		skb_reserve( skb, 2 );   /* 16 bit alignment */
+
+		skb->dev = dev;
+
+		/* =>
+    ODD-BYTE ISSUE : The odd byte problem has been fixed in the LAN91C111 Rev B.
+		So we check if the Chip Revision, stored in smsc_local->ChipRev, is = 1.
+		If so then we increment the packet length only if RS_ODDFRAME is set.
+		If the Chip's revision is equal to 0, then we blindly increment the packet length
+		by 1, thus always assuming that the packet is odd length, leaving the higher layer
+		to decide the actual length.
+			-- Pramod
+		<= */
+		if ((9 == lp->ChipID) && (1 == lp->ChipRev))
+		{
+			if (status & RS_ODDFRAME)
+				data = skb_put( skb, packet_length + 1 );	
+			else
+				data = skb_put( skb, packet_length);			
+			
+		}
+		else
+		{
+			// set odd length for bug in LAN91C111, REV A
+			// which never sets RS_ODDFRAME
+			data = skb_put( skb, packet_length + 1 );
+		}
+
+#ifdef USE_32_BIT
+		PRINTK3(" Reading %d dwords (and %d bytes) \n",
+			packet_length >> 2, packet_length & 3 );
+		/* QUESTION:  Like in the TX routine, do I want
+		   to send the DWORDs or the bytes first, or some
+		   mixture.  A mixture might improve already slow PIO
+		   performance  */
+		insl(ioaddr + DATA_REG , data, packet_length >> 2 );
+		/* read the left over bytes */
+		insb( ioaddr + DATA_REG, data + (packet_length & 0xFFFFFC),
+			packet_length & 0x3  );
+#else
+		PRINTK3(" Reading %d words and %d byte(s) \n",
+			(packet_length >> 1 ), packet_length & 1 );
+		insw(ioaddr + DATA_REG , data, packet_length >> 1);
+
+#endif // USE_32_BIT
+
+#if	SMC_DEBUG > 2
+		printk("Receiving Packet\n");
+		print_packet( data, packet_length );
+#endif
+
+		skb->protocol = eth_type_trans(skb, dev );
+		netif_rx(skb);
+		lp->stats.rx_packets++;
+#if defined(__m32r__)
+		lp->stats.rx_bytes += packet_length;
+#endif
+	} else {
+		/* error ... */
+		lp->stats.rx_errors++;
+
+		if ( status & RS_ALGNERR )  lp->stats.rx_frame_errors++;
+		if ( status & (RS_TOOSHORT | RS_TOOLONG ) )
+			lp->stats.rx_length_errors++;
+		if ( status & RS_BADCRC)	lp->stats.rx_crc_errors++;
+	}
+
+	while ( inw( ioaddr + MMU_CMD_REG ) & MC_BUSY )
+		udelay(1); // Wait until not busy
+done:
+	/*  error or good, tell the card to get rid of this packet */
+	outw( MC_RELEASE, ioaddr + MMU_CMD_REG );
+
+
+	return;
+}
+
+
+/*************************************************************************
+ . smc_tx
+ .
+ . Purpose:  Handle a transmit error message.   This will only be called
+ .   when an error, because of the AUTO_RELEASE mode.
+ .
+ . Algorithm:
+ .	Save pointer and packet no
+ .	Get the packet no from the top of the queue
+ .	check if it's valid ( if not, is this an error??? )
+ .	read the status word
+ .	record the error
+ .	( resend?  Not really, since we don't want old packets around )
+ .	Restore saved values
+ ************************************************************************/
+static void smc_tx( struct net_device * dev )
+{
+	int	ioaddr = dev->base_addr;
+	struct smc_local *lp = (struct smc_local *)dev->priv;
+	byte saved_packet;
+	byte packet_no;
+	word tx_status;
+
+
+	PRINTK3("%s:smc_tx\n", dev->name);
+
+	/* assume bank 2  */
+
+	saved_packet = inb( ioaddr + PN_REG );
+	packet_no = inw( ioaddr + RXFIFO_REG );
+#if defined(__m32r__)
+	/* If the TX FIFO is empty then nothing to do */
+	if ( packet_no & TXFIFO_TEMPTY )
+		return;
+
+	packet_no &= 0x7F;
+#else
+	packet_no &= 0x7F;
+
+	/* If the TX FIFO is empty then nothing to do */
+	if ( packet_no & TXFIFO_TEMPTY )
+		return;
+#endif
+
+	/* select this as the packet to read from */
+	outb( packet_no, ioaddr + PN_REG );
+
+	/* read the first word (status word) from this packet */
+	outw( PTR_AUTOINC | PTR_READ, ioaddr + PTR_REG );
+
+	tx_status = inw( ioaddr + DATA_REG );
+	PRINTK3("%s: TX DONE STATUS: %4x \n", dev->name, tx_status);
+
+	lp->stats.tx_errors++;
+	if ( tx_status & TS_LOSTCAR ) lp->stats.tx_carrier_errors++;
+	if ( tx_status & TS_LATCOL  ) {
+		printk(KERN_DEBUG
+			"%s: Late collision occurred on last xmit.\n",
+			dev->name);
+		lp->stats.tx_window_errors++;
+		lp->ctl_forcol = 0; // Reset forced collsion
+	}
+#if 0
+	if ( tx_status & TS_16COL ) { ... }
+#endif
+
+	if ( tx_status & TS_SUCCESS ) {
+	  //	  	printk("%s: Successful packet caused interrupt \n", dev->name);
+	}
+	/* re-enable transmit */
+	SMC_SELECT_BANK( 0 );
+	outw( inw( ioaddr + TCR_REG ) | TCR_ENABLE, ioaddr + TCR_REG );
+
+	/* kill the packet */
+	SMC_SELECT_BANK( 2 );
+	outw( MC_FREEPKT, ioaddr + MMU_CMD_REG );
+
+	/* one less packet waiting for me */
+	lp->packets_waiting--;
+
+	/* Don't change Packet Number Reg until busy bit is cleared */
+	/* Per LAN91C111 Spec, Page 50 */
+	while ( inw( ioaddr + MMU_CMD_REG ) & MC_BUSY );
+
+	outb( saved_packet, ioaddr + PN_REG );
+	return;
+}
+
+
+/*----------------------------------------------------
+ . smc_close
+ .
+ . this makes the board clean up everything that it can
+ . and not talk to the outside world.   Caused by
+ . an 'ifconfig ethX down'
+ .
+ -----------------------------------------------------*/
+static int smc_close(struct net_device *dev)
+{
+	netif_stop_queue(dev);
+	//dev->start = 0;
+
+	PRINTK2("%s:smc_close\n", dev->name);
+
+#ifdef CONFIG_SYSCTL
+	smc_sysctl_unregister(dev);
+#endif /* CONFIG_SYSCTL */ 
+
+	/* clear everything */
+	smc_shutdown( dev->base_addr );
+
+	/* Update the statistics here. */
+#ifdef MODULE
+	MOD_DEC_USE_COUNT;
+#endif
+
+	return 0;
+}
+
+/*------------------------------------------------------------
+ . Get the current statistics.
+ . This may be called with the card open or closed.
+ .-------------------------------------------------------------*/
+static struct net_device_stats* smc_query_statistics(struct net_device *dev) {
+	struct smc_local *lp = (struct smc_local *)dev->priv;
+
+	PRINTK2("%s:smc_query_statistics\n", dev->name);
+
+	return &lp->stats;
+}
+
+/*-----------------------------------------------------------
+ . smc_set_multicast_list
+ .
+ . This routine will, depending on the values passed to it,
+ . either make it accept multicast packets, go into
+ . promiscuous mode ( for TCPDUMP and cousins ) or accept
+ . a select set of multicast packets
+*/
+static void smc_set_multicast_list(struct net_device *dev)
+{
+	short ioaddr = dev->base_addr;
+
+	PRINTK2("%s:smc_set_multicast_list\n", dev->name);
+
+	SMC_SELECT_BANK(0);
+	if ( dev->flags & IFF_PROMISC )
+		{
+		PRINTK2("%s:smc_set_multicast_list:RCR_PRMS\n", dev->name);
+		outw( inw(ioaddr + RCR_REG ) | RCR_PRMS, ioaddr + RCR_REG );
+		}
+
+/* BUG?  I never disable promiscuous mode if multicasting was turned on.
+   Now, I turn off promiscuous mode, but I don't do anything to multicasting
+   when promiscuous mode is turned on.
+*/
+
+	/* Here, I am setting this to accept all multicast packets.
+	   I don't need to zero the multicast table, because the flag is
+	   checked before the table is
+	*/
+	else if (dev->flags & IFF_ALLMULTI)
+		{
+		outw( inw(ioaddr + RCR_REG ) | RCR_ALMUL, ioaddr + RCR_REG );
+		PRINTK2("%s:smc_set_multicast_list:RCR_ALMUL\n", dev->name);
+		}
+
+	/* We just get all multicast packets even if we only want them
+	 . from one source.  This will be changed at some future
+	 . point. */
+	else if (dev->mc_count )  {
+		/* support hardware multicasting */
+
+		/* be sure I get rid of flags I might have set */
+		outw( inw( ioaddr + RCR_REG ) & ~(RCR_PRMS | RCR_ALMUL),
+			ioaddr + RCR_REG );
+		/* NOTE: this has to set the bank, so make sure it is the
+		   last thing called.  The bank is set to zero at the top */
+		smc_setmulticast( ioaddr, dev->mc_count, dev->mc_list );
+	} else  {
+		PRINTK2("%s:smc_set_multicast_list:~(RCR_PRMS|RCR_ALMUL)\n",
+			dev->name);
+		outw( inw( ioaddr + RCR_REG ) & ~(RCR_PRMS | RCR_ALMUL),
+			ioaddr + RCR_REG );
+
+		/*
+		  since I'm disabling all multicast entirely, I need to
+		  clear the multicast list
+		*/
+		SMC_SELECT_BANK( 3 );
+		outw( 0, ioaddr + MCAST_REG1 );
+		outw( 0, ioaddr + MCAST_REG2 );
+		outw( 0, ioaddr + MCAST_REG3 );
+		outw( 0, ioaddr + MCAST_REG4 );
+	}
+}
+
+#ifdef MODULE
+
+static struct net_device devSMC91111;
+int io = 0;
+int irq = 0;
+int nowait = 0;
+
+MODULE_PARM(io, "i");
+MODULE_PARM(irq, "i");
+MODULE_PARM(nowait, "i");
+
+/*------------------------------------------------------------
+ . Module initialization function
+ .-------------------------------------------------------------*/
+int init_module(void)
+{
+	int result;
+
+	PRINTK2("CARDNAME:init_module\n");
+	if (io == 0)
+		printk(KERN_WARNING
+		CARDNAME": You shouldn't use auto-probing with insmod!\n" );
+
+	/* copy the parameters from insmod into the device structure */
+	devSMC91111.base_addr	= io;
+	devSMC91111.irq		= irq;
+	devSMC91111.dma		= nowait; // Use DMA field for nowait		
+	devSMC91111.init	= smc_init;/* Kernel 2.4 Changes - Pramod */
+	if ((result = register_netdev(&devSMC91111)) != 0)
+		return result;
+	
+	return 0;
+}
+
+/*------------------------------------------------------------
+ . Cleanup when module is removed with rmmod
+ .-------------------------------------------------------------*/
+void cleanup_module(void)
+{
+	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
+	unregister_netdev(&devSMC91111);
+
+	free_irq(devSMC91111.irq, &devSMC91111);
+	release_region(devSMC91111.base_addr, SMC_IO_EXTENT);
+
+	if (devSMC91111.priv)
+		kfree(devSMC91111.priv); /* Kernel 2.4 Changes - Pramod */
+}
+
+#endif /* MODULE */
+
+
+#ifdef CONFIG_SYSCTL
+
+
+/*------------------------------------------------------------
+ . Modify a bit in the LAN91C111 register set
+ .-------------------------------------------------------------*/
+static word smc_modify_regbit(int bank, int ioaddr, int reg,
+	unsigned int bit, int val)
+{
+	word regval;
+
+	SMC_SELECT_BANK( bank );
+
+	regval = inw( ioaddr+reg );
+	if (val)
+		regval |= bit;
+	else
+		regval &= ~bit;
+
+	outw( regval, ioaddr );
+	return(regval);
+}
+
+
+/*------------------------------------------------------------
+ . Retrieve a bit in the LAN91C111 register set
+ .-------------------------------------------------------------*/
+static int smc_get_regbit(int bank, int ioaddr, int reg, unsigned int bit)
+{
+	SMC_SELECT_BANK( bank );
+	if ( inw( ioaddr+reg ) & bit)
+		return(1);
+	else
+		return(0);
+}
+
+
+/*------------------------------------------------------------
+ . Modify a LAN91C111 register (word access only)
+ .-------------------------------------------------------------*/
+static void smc_modify_reg(int bank, int ioaddr, int reg, word val)
+{
+	SMC_SELECT_BANK( bank );
+	outw( val, ioaddr+reg );
+}
+
+
+/*------------------------------------------------------------
+ . Retrieve a LAN91C111 register (word access only)
+ .-------------------------------------------------------------*/
+static int smc_get_reg(int bank, int ioaddr, int reg)
+{
+	SMC_SELECT_BANK( bank );
+	return(inw( ioaddr+reg ));
+}
+
+
+static const char smc_info_string[] =
+"\n"
+"info           Provides this information blurb\n"
+"swver          Prints the software version information of this driver\n"
+"autoneg        Auto-negotiate Mode = 1\n"
+"rspeed         Requested Speed, 100=100Mbps, 10=10Mpbs\n"
+"rfduplx        Requested Full Duplex Operation\n"
+"aspeed         Actual Speed, 100=100Mbps, 10=10Mpbs\n"
+"afduplx        Actual Full Duplex Operation\n"
+"lnkfail        PHY Link Failure when 1\n"
+"miiop          External MII when 1, Internal PHY when 0\n"
+"swfdup         Switched Full Duplex Mode (allowed only in MII operation)\n"
+"ephloop        EPH Block Loopback\n"
+"forcol         Force a collision\n"
+"filtcar        Filter leading edge of carrier sense for 12 bit times\n"
+"freemem        Free buffer memory in bytes\n"
+"totmem         Total buffer memory in bytes\n"
+"leda           Output of LED-A (green)\n"
+"ledb           Output of LED-B (yellow)\n"
+"chiprev        Revision ID of the LAN91C111 chip\n"
+"";
+
+/*------------------------------------------------------------
+ . Sysctl handler for all integer parameters
+ .-------------------------------------------------------------*/
+static int smc_sysctl_handler(ctl_table *ctl, int write, struct file * filp,
+				void *buffer, size_t *lenp)
+{
+	struct net_device *dev = (struct net_device*)ctl->extra1;
+	struct smc_local *lp = (struct smc_local *)ctl->extra2;
+	int ioaddr = dev->base_addr;
+	int *valp = ctl->data;
+	int val;
+	int ret;
+
+	// Update parameters from the real registers
+	switch (ctl->ctl_name)
+	{
+	case CTL_SMC_FORCOL:
+		*valp = smc_get_regbit(0, ioaddr, TCR_REG, TCR_FORCOL);
+		break;
+
+	case CTL_SMC_FREEMEM:
+		*valp = ( (word)smc_get_reg(0, ioaddr, MIR_REG) >> 8 )
+			* LAN91C111_MEMORY_MULTIPLIER;
+		break;
+
+
+	case CTL_SMC_TOTMEM:
+		*valp = ( smc_get_reg(0, ioaddr, MIR_REG) & (word)0x00ff )
+			* LAN91C111_MEMORY_MULTIPLIER;
+		break;
+
+	case CTL_SMC_CHIPREV:
+		*valp = smc_get_reg(3, ioaddr, REV_REG);
+		break;
+
+	case CTL_SMC_AFDUPLX:
+		*valp = (lp->lastPhy18 & PHY_INT_DPLXDET) ? 1 : 0;
+		break;
+
+	case CTL_SMC_ASPEED:
+		*valp = (lp->lastPhy18 & PHY_INT_SPDDET) ? 100 : 10;
+		break;
+
+	case CTL_SMC_LNKFAIL:
+		*valp = (lp->lastPhy18 & PHY_INT_LNKFAIL) ? 1 : 0;
+		break;
+
+	case CTL_SMC_LEDA:
+		*valp = (lp->rpc_cur_mode >> RPC_LSXA_SHFT) & (word)0x0007;
+		break;
+
+	case CTL_SMC_LEDB:
+		*valp = (lp->rpc_cur_mode >> RPC_LSXB_SHFT) & (word)0x0007;
+		break;
+
+	case CTL_SMC_MIIOP:
+		*valp = smc_get_regbit(1, ioaddr, CONFIG_REG, CONFIG_EXT_PHY);
+		break;
+
+#ifdef SMC_DEBUG
+	case CTL_SMC_REG_BSR:	// Bank Select
+		*valp = smc_get_reg(0, ioaddr, BSR_REG);
+		break;
+
+	case CTL_SMC_REG_TCR:	// Transmit Control
+		*valp = smc_get_reg(0, ioaddr, TCR_REG);
+		break;
+
+	case CTL_SMC_REG_ESR:	// EPH Status
+		*valp = smc_get_reg(0, ioaddr, EPH_STATUS_REG);
+		break;
+
+	case CTL_SMC_REG_RCR:	// Receive Control
+		*valp = smc_get_reg(0, ioaddr, RCR_REG);
+		break;
+
+	case CTL_SMC_REG_CTRR:	// Counter
+		*valp = smc_get_reg(0, ioaddr, COUNTER_REG);
+		break;
+
+	case CTL_SMC_REG_MIR:	// Memory Information
+		*valp = smc_get_reg(0, ioaddr, MIR_REG);
+		break;
+
+	case CTL_SMC_REG_RPCR:	// Receive/Phy Control
+		*valp = smc_get_reg(0, ioaddr, RPC_REG);
+		break;
+
+	case CTL_SMC_REG_CFGR:	// Configuration
+		*valp = smc_get_reg(1, ioaddr, CONFIG_REG);
+		break;
+
+	case CTL_SMC_REG_BAR:	// Base Address
+		*valp = smc_get_reg(1, ioaddr, BASE_REG);
+		break;
+
+	case CTL_SMC_REG_IAR0:	// Individual Address
+		*valp = smc_get_reg(1, ioaddr, ADDR0_REG);
+		break;
+
+	case CTL_SMC_REG_IAR1:	// Individual Address
+		*valp = smc_get_reg(1, ioaddr, ADDR1_REG);
+		break;
+
+	case CTL_SMC_REG_IAR2:	// Individual Address
+		*valp = smc_get_reg(1, ioaddr, ADDR2_REG);
+		break;
+
+	case CTL_SMC_REG_GPR:	// General Purpose
+		*valp = smc_get_reg(1, ioaddr, GP_REG);
+		break;
+
+	case CTL_SMC_REG_CTLR:	// Control
+		*valp = smc_get_reg(1, ioaddr, CTL_REG);
+		break;
+
+	case CTL_SMC_REG_MCR:	// MMU Command
+		*valp = smc_get_reg(2, ioaddr, MMU_CMD_REG);
+		break;
+
+	case CTL_SMC_REG_PNR:	// Packet Number
+		*valp = smc_get_reg(2, ioaddr, PN_REG);
+		break;
+
+	case CTL_SMC_REG_FPR:	// Allocation Result/FIFO Ports
+		*valp = smc_get_reg(2, ioaddr, RXFIFO_REG);
+		break;
+
+	case CTL_SMC_REG_PTR:	// Pointer
+		*valp = smc_get_reg(2, ioaddr, PTR_REG);
+		break;
+
+	case CTL_SMC_REG_DR:	// Data 
+		*valp = smc_get_reg(2, ioaddr, DATA_REG);
+		break;
+
+	case CTL_SMC_REG_ISR:	// Interrupt Status/Mask
+		*valp = smc_get_reg(2, ioaddr, INT_REG);
+		break;
+
+	case CTL_SMC_REG_MTR1:	// Multicast Table Entry 1
+		*valp = smc_get_reg(3, ioaddr, MCAST_REG1);
+		break;
+
+	case CTL_SMC_REG_MTR2:	// Multicast Table Entry 2
+		*valp = smc_get_reg(3, ioaddr, MCAST_REG2);
+		break;
+
+	case CTL_SMC_REG_MTR3:	// Multicast Table Entry 3
+		*valp = smc_get_reg(3, ioaddr, MCAST_REG3);
+		break;
+
+	case CTL_SMC_REG_MTR4:	// Multicast Table Entry 4
+		*valp = smc_get_reg(3, ioaddr, MCAST_REG4);
+		break;
+
+	case CTL_SMC_REG_MIIR:	// Management Interface
+		*valp = smc_get_reg(3, ioaddr, MII_REG);
+		break;
+
+	case CTL_SMC_REG_REVR:	// Revision
+		*valp = smc_get_reg(3, ioaddr, REV_REG);
+		break;
+
+	case CTL_SMC_REG_ERCVR:	// Early RCV
+		*valp = smc_get_reg(3, ioaddr, ERCV_REG);
+		break;
+
+	case CTL_SMC_REG_EXTR:	// External
+		*valp = smc_get_reg(7, ioaddr, EXT_REG);
+		break;
+
+	case CTL_SMC_PHY_CTRL:
+		*valp = smc_read_phy_register(ioaddr, lp->phyaddr,
+			PHY_CNTL_REG);
+		break;
+
+	case CTL_SMC_PHY_STAT:
+		*valp = smc_read_phy_register(ioaddr, lp->phyaddr,
+			PHY_STAT_REG);
+		break;
+
+	case CTL_SMC_PHY_ID1:
+		*valp = smc_read_phy_register(ioaddr, lp->phyaddr,
+			PHY_ID1_REG);
+		break;
+
+	case CTL_SMC_PHY_ID2:
+		*valp = smc_read_phy_register(ioaddr, lp->phyaddr,
+			PHY_ID2_REG);
+		break;
+
+	case CTL_SMC_PHY_ADC:
+		*valp = smc_read_phy_register(ioaddr, lp->phyaddr,
+			PHY_AD_REG);
+		break;
+
+	case CTL_SMC_PHY_REMC:
+		*valp = smc_read_phy_register(ioaddr, lp->phyaddr,
+			PHY_RMT_REG);
+		break;
+
+	case CTL_SMC_PHY_CFG1:
+		*valp = smc_read_phy_register(ioaddr, lp->phyaddr,
+			PHY_CFG1_REG);
+		break;
+
+	case CTL_SMC_PHY_CFG2:
+		*valp = smc_read_phy_register(ioaddr, lp->phyaddr,
+			PHY_CFG2_REG);
+		break;
+
+	case CTL_SMC_PHY_INT:
+		*valp = smc_read_phy_register(ioaddr, lp->phyaddr,
+			PHY_INT_REG);
+		break;
+
+	case CTL_SMC_PHY_MASK:
+		*valp = smc_read_phy_register(ioaddr, lp->phyaddr,
+			PHY_MASK_REG);
+		break;
+
+#endif // SMC_DEBUG
+
+	default:
+		// Just ignore unsupported parameters
+		break;
+	}
+
+	// Save old state
+	val = *valp;
+
+	// Perform the generic integer operation	
+	if ((ret = proc_dointvec(ctl, write, filp, buffer, lenp)) != 0)
+		return(ret);
+
+	// Write changes out to the registers
+	if (write && *valp != val) {
+
+		val = *valp;
+		switch (ctl->ctl_name) {
+
+		case CTL_SMC_SWFDUP:
+			if (val)
+				lp->tcr_cur_mode |= TCR_SWFDUP;
+			else
+				lp->tcr_cur_mode &= ~TCR_SWFDUP;
+
+			smc_modify_regbit(0, ioaddr, TCR_REG, TCR_SWFDUP, val);
+			break;
+
+		case CTL_SMC_EPHLOOP:
+			if (val)
+				lp->tcr_cur_mode |= TCR_EPH_LOOP;
+			else
+				lp->tcr_cur_mode &= ~TCR_EPH_LOOP;
+
+			smc_modify_regbit(0, ioaddr, TCR_REG, TCR_EPH_LOOP, val);
+			break;
+
+		case CTL_SMC_FORCOL:
+			if (val)
+				lp->tcr_cur_mode |= TCR_FORCOL;
+			else
+				lp->tcr_cur_mode &= ~TCR_FORCOL;
+
+			// Update the EPH block
+			smc_modify_regbit(0, ioaddr, TCR_REG, TCR_FORCOL, val);
+			break;
+
+		case CTL_SMC_FILTCAR:
+			if (val)
+				lp->rcr_cur_mode |= RCR_FILT_CAR;
+			else
+				lp->rcr_cur_mode &= ~RCR_FILT_CAR;
+
+			// Update the EPH block
+			smc_modify_regbit(0, ioaddr, RCR_REG, RCR_FILT_CAR, val);
+			break;
+
+		case CTL_SMC_RFDUPLX:
+			// Disallow changes if in auto-negotiation mode
+			if (lp->ctl_autoneg)
+				break;
+
+			if (val)
+				{
+				lp->rpc_cur_mode |= RPC_DPLX;
+				}
+			else
+				{
+				lp->rpc_cur_mode &= ~RPC_DPLX;
+				}
+
+			// Reconfigure the PHY
+			smc_phy_configure(dev);
+
+			break;
+
+		case CTL_SMC_RSPEED:
+			// Disallow changes if in auto-negotiation mode
+			if (lp->ctl_autoneg)
+				break;
+
+			if (val > 10)
+				lp->rpc_cur_mode |= RPC_SPEED;
+			else
+				lp->rpc_cur_mode &= ~RPC_SPEED;
+
+			// Reconfigure the PHY
+			smc_phy_configure(dev);
+
+			break;
+
+		case CTL_SMC_AUTONEG:
+			if (val)
+				lp->rpc_cur_mode |= RPC_ANEG;
+			else
+				lp->rpc_cur_mode &= ~RPC_ANEG;
+
+			// Reconfigure the PHY
+			smc_phy_configure(dev);
+
+			break;
+
+		case CTL_SMC_LEDA:
+			val &= 0x07; // Restrict to 3 ls bits
+			lp->rpc_cur_mode &= ~(word)(0x07<<RPC_LSXA_SHFT);
+			lp->rpc_cur_mode |= (word)(val<<RPC_LSXA_SHFT);
+
+			// Update the Internal PHY block
+			smc_modify_reg(0, ioaddr, RPC_REG, lp->rpc_cur_mode);
+			break;
+
+		case CTL_SMC_LEDB:
+			val &= 0x07; // Restrict to 3 ls bits
+			lp->rpc_cur_mode &= ~(word)(0x07<<RPC_LSXB_SHFT);
+			lp->rpc_cur_mode |= (word)(val<<RPC_LSXB_SHFT);
+
+			// Update the Internal PHY block
+			smc_modify_reg(0, ioaddr, RPC_REG, lp->rpc_cur_mode);
+			break;
+
+		case CTL_SMC_MIIOP:
+			// Update the Internal PHY block
+			smc_modify_regbit(1, ioaddr, CONFIG_REG,
+				CONFIG_EXT_PHY, val);
+			break;
+
+#ifdef SMC_DEBUG
+		case CTL_SMC_REG_BSR:	// Bank Select
+			smc_modify_reg(0, ioaddr, BSR_REG, val);
+			break;
+
+		case CTL_SMC_REG_TCR:	// Transmit Control
+			smc_modify_reg(0, ioaddr, TCR_REG, val);
+			break;
+
+		case CTL_SMC_REG_ESR:	// EPH Status
+			smc_modify_reg(0, ioaddr, EPH_STATUS_REG, val);
+			break;
+
+		case CTL_SMC_REG_RCR:	// Receive Control
+			smc_modify_reg(0, ioaddr, RCR_REG, val);
+			break;
+
+		case CTL_SMC_REG_CTRR:	// Counter
+			smc_modify_reg(0, ioaddr, COUNTER_REG, val);
+			break;
+
+		case CTL_SMC_REG_MIR:	// Memory Information
+			smc_modify_reg(0, ioaddr, MIR_REG, val);
+			break;
+
+		case CTL_SMC_REG_RPCR:	// Receive/Phy Control
+			smc_modify_reg(0, ioaddr, RPC_REG, val);
+			break;
+
+		case CTL_SMC_REG_CFGR:	// Configuration
+			smc_modify_reg(1, ioaddr, CONFIG_REG, val);
+			break;
+
+		case CTL_SMC_REG_BAR:	// Base Address
+			smc_modify_reg(1, ioaddr, BASE_REG, val);
+			break;
+
+		case CTL_SMC_REG_IAR0:	// Individual Address
+			smc_modify_reg(1, ioaddr, ADDR0_REG, val);
+			break;
+
+		case CTL_SMC_REG_IAR1:	// Individual Address
+			smc_modify_reg(1, ioaddr, ADDR1_REG, val);
+			break;
+
+		case CTL_SMC_REG_IAR2:	// Individual Address
+			smc_modify_reg(1, ioaddr, ADDR2_REG, val);
+			break;
+
+		case CTL_SMC_REG_GPR:	// General Purpose
+			smc_modify_reg(1, ioaddr, GP_REG, val);
+			break;
+
+		case CTL_SMC_REG_CTLR:	// Control
+			smc_modify_reg(1, ioaddr, CTL_REG, val);
+			break;
+
+		case CTL_SMC_REG_MCR:	// MMU Command
+			smc_modify_reg(2, ioaddr, MMU_CMD_REG, val);
+			break;
+
+		case CTL_SMC_REG_PNR:	// Packet Number
+			smc_modify_reg(2, ioaddr, PN_REG, val);
+			break;
+
+		case CTL_SMC_REG_FPR:	// Allocation Result/FIFO Ports
+			smc_modify_reg(2, ioaddr, RXFIFO_REG, val);
+			break;
+
+		case CTL_SMC_REG_PTR:	// Pointer
+			smc_modify_reg(2, ioaddr, PTR_REG, val);
+			break;
+
+		case CTL_SMC_REG_DR:	// Data 
+			smc_modify_reg(2, ioaddr, DATA_REG, val);
+			break;
+
+		case CTL_SMC_REG_ISR:	// Interrupt Status/Mask
+			smc_modify_reg(2, ioaddr, INT_REG, val);
+			break;
+
+		case CTL_SMC_REG_MTR1:	// Multicast Table Entry 1
+			smc_modify_reg(3, ioaddr, MCAST_REG1, val);
+			break;
+
+		case CTL_SMC_REG_MTR2:	// Multicast Table Entry 2
+			smc_modify_reg(3, ioaddr, MCAST_REG2, val);
+			break;
+
+		case CTL_SMC_REG_MTR3:	// Multicast Table Entry 3
+			smc_modify_reg(3, ioaddr, MCAST_REG3, val);
+			break;
+
+		case CTL_SMC_REG_MTR4:	// Multicast Table Entry 4
+			smc_modify_reg(3, ioaddr, MCAST_REG4, val);
+			break;
+
+		case CTL_SMC_REG_MIIR:	// Management Interface
+			smc_modify_reg(3, ioaddr, MII_REG, val);
+			break;
+
+		case CTL_SMC_REG_REVR:	// Revision
+			smc_modify_reg(3, ioaddr, REV_REG, val);
+			break;
+
+		case CTL_SMC_REG_ERCVR:	// Early RCV
+			smc_modify_reg(3, ioaddr, ERCV_REG, val);
+			break;
+
+		case CTL_SMC_REG_EXTR:	// External
+			smc_modify_reg(7, ioaddr, EXT_REG, val);
+			break;
+
+		case CTL_SMC_PHY_CTRL:
+			smc_write_phy_register(ioaddr, lp->phyaddr,
+				PHY_CNTL_REG, val);
+			break;
+
+		case CTL_SMC_PHY_STAT:
+			smc_write_phy_register(ioaddr, lp->phyaddr,
+				PHY_STAT_REG, val);
+			break;
+
+		case CTL_SMC_PHY_ID1:
+			smc_write_phy_register(ioaddr, lp->phyaddr,
+				PHY_ID1_REG, val);
+			break;
+
+		case CTL_SMC_PHY_ID2:
+			smc_write_phy_register(ioaddr, lp->phyaddr,
+				PHY_ID2_REG, val);
+			break;
+
+		case CTL_SMC_PHY_ADC:
+			smc_write_phy_register(ioaddr, lp->phyaddr,
+				PHY_AD_REG, val);
+			break;
+
+		case CTL_SMC_PHY_REMC:
+			smc_write_phy_register(ioaddr, lp->phyaddr,
+				PHY_RMT_REG, val);
+			break;
+
+		case CTL_SMC_PHY_CFG1:
+			smc_write_phy_register(ioaddr, lp->phyaddr,
+				PHY_CFG1_REG, val);
+			break;
+
+		case CTL_SMC_PHY_CFG2:
+			smc_write_phy_register(ioaddr, lp->phyaddr,
+				PHY_CFG2_REG, val);
+			break;
+
+		case CTL_SMC_PHY_INT:
+			smc_write_phy_register(ioaddr, lp->phyaddr,
+				PHY_INT_REG, val);
+			break;
+
+		case CTL_SMC_PHY_MASK:
+			smc_write_phy_register(ioaddr, lp->phyaddr,
+				PHY_MASK_REG, val);
+			break;
+
+#endif // SMC_DEBUG
+
+		default:
+			// Just ignore unsupported parameters
+			break;
+		} // end switch
+
+	} // end if
+
+        return ret;
+}
+
+/*------------------------------------------------------------
+ . Sysctl registration function for all parameters (files)
+ .-------------------------------------------------------------*/
+static void smc_sysctl_register(struct net_device *dev)
+{
+	struct smc_local *lp = (struct smc_local *)dev->priv;
+	static int ctl_name = CTL_SMC;
+	ctl_table* ct;
+	int i;
+
+	// Make sure the ctl_tables start out as all zeros
+	memset(lp->root_table, 0, sizeof lp->root_table);
+	memset(lp->eth_table, 0, sizeof lp->eth_table);
+	memset(lp->param_table, 0, sizeof lp->param_table);
+
+	// Initialize the root table
+	ct = lp->root_table;
+	ct->ctl_name = CTL_DEV;
+	ct->procname = "dev";
+	ct->maxlen = 0;
+	ct->mode = 0555;
+	ct->child = lp->eth_table;
+	// remaining fields are zero
+
+	// Initialize the ethX table (this device's table)
+	ct = lp->eth_table;
+	ct->ctl_name = ctl_name++; // Must be unique
+	ct->procname = dev->name;
+	ct->maxlen = 0;
+	ct->mode = 0555;
+	ct->child = lp->param_table;
+	// remaining fields are zero
+
+	// Initialize the parameter (files) table
+	// Make sure the last entry remains null
+	ct = lp->param_table;
+	for (i = 0; i < (CTL_SMC_LAST_ENTRY-1); ++i)
+		{
+		// Initialize fields common to all table entries
+		ct[i].proc_handler = smc_sysctl_handler;
+		ct[i].extra1 = (void*)dev; // Save our device pointer
+		ct[i].extra2 = (void*)lp;  // Save our smc_local data pointer
+		}
+
+	// INFO - this is our only string parameter
+	i = 0;
+	ct[i].proc_handler = proc_dostring; // use default handler
+	ct[i].ctl_name = CTL_SMC_INFO;
+	ct[i].procname = "info";
+	ct[i].data = (void*)smc_info_string;
+	ct[i].maxlen = sizeof smc_info_string;
+	ct[i].mode = 0444; // Read only
+
+	// SWVER
+	++i;
+	ct[i].proc_handler = proc_dostring; // use default handler
+	ct[i].ctl_name = CTL_SMC_SWVER;
+	ct[i].procname = "swver";
+	ct[i].data = (void*)version;
+	ct[i].maxlen = sizeof version;
+	ct[i].mode = 0444; // Read only
+
+	// SWFDUP
+	++i;
+	ct[i].ctl_name = CTL_SMC_SWFDUP;
+	ct[i].procname = "swfdup";
+	ct[i].data = (void*)&(lp->ctl_swfdup);
+	ct[i].maxlen = si
