diff -ruN linux-2.6.8.1.org/arch/m32r/Kconfig linux-2.6.8.1/arch/m32r/Kconfig
--- linux-2.6.8.1.org/arch/m32r/Kconfig	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.8.1/arch/m32r/Kconfig	2004-07-27 15:54:20.000000000 +0900
@@ -0,0 +1,621 @@
+#
+# For a description of the syntax of this configuration file,
+# see Documentation/kbuild/kconfig-language.txt.
+#
+
+mainmenu "Linux Kernel Configuration"
+
+config M32R
+	bool
+	default y
+
+config SBUS
+	bool
+
+config UID16
+	bool
+	default y
+
+config GENERIC_ISA_DMA
+	bool
+	default y
+
+source "init/Kconfig"
+
+
+menu "Processor type and features"
+
+choice
+	prompt "Platform Type"
+	default PLAT_MAPPI
+
+config PLAT_MAPPI
+	bool "Mappi-I"
+	help
+	  The Mappi-I is an FPGA board for SOC (System-On-a-Chip) prototyping.
+	  You can operate a Linux system on this board by using an M32R
+	  softmacro core, which is a fully-synthesizable functional model 
+	  described in Verilog-HDL.
+
+	  The Mappi-I board was the first platform, which had been used 
+	  to port and develop a Linux system for the M32R processor.  
+	  Currently, the Mappi-II, an heir to the Mappi-I, is available.
+
+config PLAT_USRV
+	bool "uServer"
+
+config PLAT_M32700UT
+	bool "M32700UT"
+	help
+	  The M3T-M32700UT is an evaluation board based on uT-Engine
+	  specification.  This board has an M32700 (Chaos) evaluation chip.
+	  You can say Y for SMP, because the M32700 is a single chip 
+	  multiprocessor.
+
+config PLAT_OPSPUT
+	bool "OPSPUT"
+	help
+	  The OPSPUT is an evaluation board based on uT-Engine
+	  specification.  This board has a OPSP-REP chip.
+
+config PLAT_OAKS32R
+	bool "OAKS32R"
+	help
+	  The OAKS32R is a tiny, inexpensive evaluation board.
+	  Please note that if you say Y here and choose chip "M32102", 
+	  say N for MMU and select a no-MMU version kernel, otherwise 
+	  a kernel with MMU support will not work, because the M32102 
+	  is a microcontroller for embedded systems and it has no MMU.
+
+config PLAT_MAPPI2
+       bool "Mappi-II(M3A-ZA36/M3A-ZA52)"
+
+endchoice
+
+choice
+	prompt "Processor family"
+	default CHIP_M32700
+
+config CHIP_M32700
+	bool "M32700 (Chaos)"
+
+config CHIP_M32102
+	bool "M32102"
+
+config CHIP_VDEC2
+       bool "VDEC2"
+
+config CHIP_OPSP
+       bool "OPSP"
+
+endchoice
+
+config MMU
+	bool "Support for memory management hardware"
+	depends on CHIP_M32700 || CHIP_VDEC2 || CHIP_OPSP
+	default y
+
+config TLB_ENTRIES
+       int "TLB Entries"
+       depends on CHIP_M32700 || CHIP_VDEC2 || CHIP_OPSP
+       default 32 if CHIP_M32700 || CHIP_OPSP
+       default 16 if CHIP_VDEC2 
+       
+
+config ISA_M32R
+        bool
+	depends on CHIP_M32102
+	default y
+
+config ISA_M32R2
+	bool
+	depends on CHIP_M32700 || CHIP_VDEC2 || CHIP_OPSP
+	default y
+
+config ISA_DSP_LEVEL2
+	bool
+	depends on CHIP_M32700 || CHIP_OPSP
+	default y
+
+config ISA_DUAL_ISSUE
+	bool
+	depends on CHIP_M32700 || CHIP_OPSP
+	default y
+
+config BUS_CLOCK
+	int "Bus Clock [Hz] (integer)"
+	default "70000000" if PLAT_MAPPI
+	default "25000000" if PLAT_USRV
+	default "50000000" if PLAT_M32700UT
+	default "50000000" if PLAT_OPSPUT
+	default "33333333" if PLAT_OAKS32R
+	default "20000000" if PLAT_MAPPI2
+
+config TIMER_DIVIDE
+	int "Timer divider (integer)"
+	default "128"
+
+config CPU_LITTLE_ENDIAN
+        bool "Generate little endian code"
+	default n
+
+config MEMORY_START
+	hex "Physical memory start address (hex)"
+	default "08000000" if PLAT_MAPPI || PLAT_MAPPI2
+	default "08000000" if PLAT_USRV
+	default "08000000" if PLAT_M32700UT
+	default "08000000" if PLAT_OPSPUT
+	default "01000000" if PLAT_OAKS32R
+
+config MEMORY_SIZE
+	hex "Physical memory size (hex)"
+	default "04000000" if PLAT_MAPPI || PLAT_MAPPI2
+	default "02000000" if PLAT_USRV
+	default "01000000" if PLAT_M32700UT
+	default "01000000" if PLAT_OPSPUT
+	default "00800000" if PLAT_OAKS32R
+
+config NOHIGHMEM
+	bool
+	default y
+
+config DISCONTIGMEM
+	bool "Internal RAM Support"
+	depends on CHIP_M32700 || CHIP_M32102 || CHIP_VDEC2 || CHIP_OPSP
+	default y
+
+config IRAM_START
+	hex "Internal memory start address (hex)"
+	default "00f00000"
+	depends on (CHIP_M32700 || CHIP_M32102 || CHIP_VDEC2 || CHIP_OPSP) && DISCONTIGMEM
+
+config IRAM_SIZE
+	hex "Internal memory size (hex)"
+	depends on (CHIP_M32700 || CHIP_M32102 || CHIP_VDEC2 || CHIP_OPSP) && DISCONTIGMEM
+	default "00080000" if CHIP_M32700 
+	default "00010000" if CHIP_M32102 || CHIP_OPSP
+	default "00008000" if CHIP_VDEC2
+
+#
+# Define implied options from the CPU selection here
+#
+
+config RWSEM_GENERIC_SPINLOCK
+	bool
+	depends on M32R
+	default y
+
+config RWSEM_XCHGADD_ALGORITHM
+	bool
+	default n
+
+config PREEMPT
+	bool "Preemptible Kernel"
+	help
+	  This option reduces the latency of the kernel when reacting to
+	  real-time or interactive events by allowing a low priority process to
+	  be preempted even if it is in kernel mode executing a system call.
+	  This allows applications to run more reliably even when the system is
+	  under load.
+
+	  Say Y here if you are building a kernel for a desktop, embedded
+	  or real-time system.  Say N if you are unsure.
+
+config HAVE_DEC_LOCK
+	bool
+	depends on (SMP || PREEMPT)
+	default n
+
+config SMP
+	bool "Symmetric multi-processing support"
+	---help---
+	  This enables support for systems with more than one CPU. If you have
+	  a system with only one CPU, like most personal computers, say N. If
+	  you have a system with more than one CPU, say Y.
+
+	  If you say N here, the kernel will run on single and multiprocessor
+	  machines, but will use only one CPU of a multiprocessor machine. If
+	  you say Y here, the kernel will run on many, but not all,
+	  singleprocessor machines. On a singleprocessor machine, the kernel
+	  will run faster if you say N here.
+
+	  Note that if you say Y here and choose architecture "586" or
+	  "Pentium" under "Processor family", the kernel will not work on 486
+	  architectures. Similarly, multiprocessor kernels for the "PPro"
+	  architecture may not work on all Pentium based boards.
+
+	  People using multiprocessor machines who say Y here should also say
+	  Y to "Enhanced Real Time Clock Support", below. The "Advanced Power
+	  Management" code will be disabled if you say Y here.
+
+	  See also the <file:Documentation/smp.tex>,
+	  <file:Documentation/smp.txt>, <file:Documentation/i386/IO-APIC.txt>,
+	  <file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO available at
+	  <http://www.linuxdoc.org/docs.html#howto>.
+
+	  If you don't know what to do here, say N.
+
+config CHIP_M32700_TS1
+	bool "Workaround code for the M32700 TS1 chip's bug"
+	depends on (CHIP_M32700 && SMP)
+	default n
+
+config NR_CPUS
+	int "Maximum number of CPUs (2-32)"
+	range 2 32
+	depends on SMP
+	default "2"
+	help
+	  This allows you to specify the maximum number of CPUs which this
+	  kernel will support.  The maximum supported value is 32 and the
+	  minimum value which makes sense is 2.
+
+	  This is purely to save memory - each supported CPU adds
+	  approximately eight kilobytes to the kernel image.
+
+# Common NUMA Features
+config NUMA
+	bool "Numa Memory Allocation Support"
+	depends on SMP
+	default n
+
+source "arch/m32r/drivers/Kconfig"
+
+# turning this on wastes a bunch of space.
+# Summit needs it only when NUMA is on
+config BOOT_IOREMAP
+	bool
+	depends on NUMA
+	default n
+
+endmenu
+
+
+menu "Power management options (ACPI, APM)"
+
+source kernel/power/Kconfig
+
+config APM
+	tristate "Advanced Power Management BIOS support"
+	depends on PM
+	---help---
+	  APM is a BIOS specification for saving power using several different
+	  techniques. This is mostly useful for battery powered laptops with
+	  APM compliant BIOSes. If you say Y here, the system time will be
+	  reset after a RESUME operation, the /proc/apm device will provide
+	  battery status information, and user-space programs will receive
+	  notification of APM "events" (e.g. battery status change).
+
+	  If you select "Y" here, you can disable actual use of the APM
+	  BIOS by passing the "apm=off" option to the kernel at boot time.
+
+	  Note that the APM support is almost completely disabled for
+	  machines with more than one CPU.
+
+	  In order to use APM, you will need supporting software. For location
+	  and more information, read <file:Documentation/pm.txt> and the
+	  Battery Powered Linux mini-HOWTO, available from
+	  <http://www.linuxdoc.org/docs.html#howto>.
+
+	  This driver does not spin down disk drives (see the hdparm(8)
+	  manpage ("man 8 hdparm") for that), and it doesn't turn off
+	  VESA-compliant "green" monitors.
+
+	  This driver does not support the TI 4000M TravelMate and the ACER
+	  486/DX4/75 because they don't have compliant BIOSes. Many "green"
+	  desktop machines also don't have compliant BIOSes, and this driver
+	  may cause those machines to panic during the boot phase.
+
+	  Generally, if you don't have a battery in your machine, there isn't
+	  much point in using this driver and you should say N. If you get
+	  random kernel OOPSes or reboots that don't seem to be related to
+	  anything, try disabling/enabling this option (or disabling/enabling
+	  APM in your BIOS).
+
+	  Some other things you should try when experiencing seemingly random,
+	  "weird" problems:
+
+	  1) make sure that you have enough swap space and that it is
+	  enabled.
+	  2) pass the "no-hlt" option to the kernel
+	  3) switch on floating point emulation in the kernel and pass
+	  the "no387" option to the kernel
+	  4) pass the "floppy=nodma" option to the kernel
+	  5) pass the "mem=4M" option to the kernel (thereby disabling
+	  all but the first 4 MB of RAM)
+	  6) make sure that the CPU is not over clocked.
+	  7) read the sig11 FAQ at <http://www.bitwizard.nl/sig11/>
+	  8) disable the cache from your BIOS settings
+	  9) install a fan for the video card or exchange video RAM
+	  10) install a better fan for the CPU
+	  11) exchange RAM chips
+	  12) exchange the motherboard.
+
+	  To compile this driver as a module ( = code which can be inserted in
+	  and removed from the running kernel whenever you want), say M here
+	  and read <file:Documentation/modules.txt>. The module will be called
+	  apm.
+
+config APM_IGNORE_USER_SUSPEND
+	bool "Ignore USER SUSPEND"
+	depends on APM
+	help
+	  This option will ignore USER SUSPEND requests. On machines with a
+	  compliant APM BIOS, you want to say N. However, on the NEC Versa M
+	  series notebooks, it is necessary to say Y because of a BIOS bug.
+
+config APM_DO_ENABLE
+	bool "Enable PM at boot time"
+	depends on APM
+	---help---
+	  Enable APM features at boot time. From page 36 of the APM BIOS
+	  specification: "When disabled, the APM BIOS does not automatically
+	  power manage devices, enter the Standby State, enter the Suspend
+	  State, or take power saving steps in response to CPU Idle calls."
+	  This driver will make CPU Idle calls when Linux is idle (unless this
+	  feature is turned off -- see "Do CPU IDLE calls", below). This
+	  should always save battery power, but more complicated APM features
+	  will be dependent on your BIOS implementation. You may need to turn
+	  this option off if your computer hangs at boot time when using APM
+	  support, or if it beeps continuously instead of suspending. Turn
+	  this off if you have a NEC UltraLite Versa 33/C or a Toshiba
+	  T400CDT. This is off by default since most machines do fine without
+	  this feature.
+
+config APM_CPU_IDLE
+	bool "Make CPU Idle calls when idle"
+	depends on APM
+	help
+	  Enable calls to APM CPU Idle/CPU Busy inside the kernel's idle loop.
+	  On some machines, this can activate improved power savings, such as
+	  a slowed CPU clock rate, when the machine is idle. These idle calls
+	  are made after the idle loop has run for some length of time (e.g.,
+	  333 mS). On some machines, this will cause a hang at boot time or
+	  whenever the CPU becomes idle. (On machines with more than one CPU,
+	  this option does nothing.)
+
+config APM_DISPLAY_BLANK
+	bool "Enable console blanking using APM"
+	depends on APM
+	help
+	  Enable console blanking using the APM. Some laptops can use this to
+	  turn off the LCD backlight when the screen blanker of the Linux
+	  virtual console blanks the screen. Note that this is only used by
+	  the virtual console screen blanker, and won't turn off the backlight
+	  when using the X Window system. This also doesn't have anything to
+	  do with your VESA-compliant power-saving monitor. Further, this
+	  option doesn't work for all laptops -- it might not turn off your
+	  backlight at all, or it might print a lot of errors to the console,
+	  especially if you are using gpm.
+
+config APM_RTC_IS_GMT
+	bool "RTC stores time in GMT"
+	depends on APM
+	help
+	  Say Y here if your RTC (Real Time Clock a.k.a. hardware clock)
+	  stores the time in GMT (Greenwich Mean Time). Say N if your RTC
+	  stores localtime.
+
+	  It is in fact recommended to store GMT in your RTC, because then you
+	  don't have to worry about daylight savings time changes. The only
+	  reason not to use GMT in your RTC is if you also run a broken OS
+	  that doesn't understand GMT.
+
+config APM_ALLOW_INTS
+	bool "Allow interrupts during APM BIOS calls"
+	depends on APM
+	help
+	  Normally we disable external interrupts while we are making calls to
+	  the APM BIOS as a measure to lessen the effects of a badly behaving
+	  BIOS implementation.  The BIOS should reenable interrupts if it
+	  needs to.  Unfortunately, some BIOSes do not -- especially those in
+	  many of the newer IBM Thinkpads.  If you experience hangs when you
+	  suspend, try setting this to Y.  Otherwise, say N.
+
+config APM_REAL_MODE_POWER_OFF
+	bool "Use real mode APM BIOS call to power off"
+	depends on APM
+	help
+	  Use real mode APM BIOS calls to switch off the computer. This is
+	  a work-around for a number of buggy BIOSes. Switch this option on if
+	  your computer crashes instead of powering off properly.
+
+endmenu
+
+
+menu "Bus options (PCI, PCMCIA, EISA, MCA, ISA)"
+
+config PCI
+	bool "PCI support"
+	default n
+	help
+	  Find out whether you have a PCI motherboard. PCI is the name of a
+	  bus system, i.e. the way the CPU talks to the other stuff inside
+	  your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
+	  VESA. If you have PCI, say Y, otherwise N.
+
+	  The PCI-HOWTO, available from
+	  <http://www.linuxdoc.org/docs.html#howto>, contains valuable
+	  information about which PCI hardware does work under Linux and which
+	  doesn't.
+
+choice
+	prompt "PCI access mode"
+	depends on PCI
+	default PCI_GOANY
+
+config PCI_GOBIOS
+	bool "BIOS"
+	---help---
+	  On PCI systems, the BIOS can be used to detect the PCI devices and
+	  determine their configuration. However, some old PCI motherboards
+	  have BIOS bugs and may crash if this is done. Also, some embedded
+	  PCI-based systems don't have any BIOS at all. Linux can also try to
+	  detect the PCI hardware directly without using the BIOS.
+
+	  With this option, you can specify how Linux should detect the PCI
+	  devices. If you choose "BIOS", the BIOS will be used, if you choose
+	  "Direct", the BIOS won't be used, and if you choose "Any", the
+	  kernel will try the direct access method and falls back to the BIOS
+	  if that doesn't work. If unsure, go with the default, which is
+	  "Any".
+
+config PCI_GODIRECT
+	bool "Direct"
+
+config PCI_GOANY
+	bool "Any"
+
+endchoice
+
+config PCI_BIOS
+	bool
+	depends on PCI && (PCI_GOBIOS || PCI_GOANY)
+	default y
+
+config PCI_DIRECT
+	bool
+ 	depends on PCI && (PCI_GODIRECT || PCI_GOANY)
+	default y
+
+source "drivers/pci/Kconfig"
+
+config ISA
+	bool "ISA support"
+	help
+	  Find out whether you have ISA slots on your motherboard.  ISA is the
+	  name of a bus system, i.e. the way the CPU talks to the other stuff
+	  inside your box.  Other bus systems are PCI, EISA, MicroChannel
+	  (MCA) or VESA.  ISA is an older system, now being displaced by PCI;
+	  newer boards don't support it.  If you have ISA, say Y, otherwise N.
+
+config EISA
+	bool "EISA support"
+	depends on ISA
+	---help---
+	  The Extended Industry Standard Architecture (EISA) bus was
+	  developed as an open alternative to the IBM MicroChannel bus.
+
+	  The EISA bus provided some of the features of the IBM MicroChannel
+	  bus while maintaining backward compatibility with cards made for
+	  the older ISA bus.  The EISA bus saw limited use between 1988 and
+	  1995 when it was made obsolete by the PCI bus.
+
+	  Say Y here if you are building a kernel for an EISA-based machine.
+
+	  Otherwise, say N.
+
+source "drivers/eisa/Kconfig"
+
+source "drivers/pcmcia/Kconfig"
+
+source "drivers/pci/hotplug/Kconfig"
+
+endmenu
+
+
+menu "Executable file formats"
+
+source "fs/Kconfig.binfmt"
+
+endmenu
+
+source "drivers/Kconfig"
+
+source "fs/Kconfig"
+
+source "arch/m32r/oprofile/Kconfig"
+
+menu "Kernel hacking"
+
+config DEBUG_KERNEL
+	bool "Kernel debugging"
+	help
+	  Say Y here if you are developing drivers or trying to debug and
+	  identify kernel problems.
+
+config DEBUG_STACKOVERFLOW
+	bool "Check for stack overflows"
+	depends on DEBUG_KERNEL
+
+config DEBUG_SLAB
+	bool "Debug memory allocations"
+	depends on DEBUG_KERNEL
+	help
+	  Say Y here to have the kernel do limited verification on memory
+	  allocation as well as poisoning memory on free to catch use of freed
+	  memory.
+
+config DEBUG_IOVIRT
+	bool "Memory mapped I/O debugging"
+	depends on DEBUG_KERNEL
+	help
+	  Say Y here to get warned whenever an attempt is made to do I/O on
+	  obviously invalid addresses such as those generated when ioremap()
+	  calls are forgotten.  Memory mapped I/O will go through an extra
+	  check to catch access to unmapped ISA addresses, an access method
+	  that can still be used by old drivers that are being ported from
+	  2.0/2.2.
+
+config MAGIC_SYSRQ
+	bool "Magic SysRq key"
+	depends on DEBUG_KERNEL
+	help
+	  If you say Y here, you will have some control over the system even
+	  if the system crashes for example during kernel debugging (e.g., you
+	  will be able to flush the buffer cache to disk, reboot the system
+	  immediately or dump some status information). This is accomplished
+	  by pressing various keys while holding SysRq (Alt+PrintScreen). It
+	  also works on a serial console (on PC hardware at least), if you
+	  send a BREAK and then within 5 seconds a command keypress. The
+	  keys are documented in <file:Documentation/sysrq.txt>. Don't say Y
+	  unless you really know what this hack does.
+
+config DEBUG_SPINLOCK
+	bool "Spinlock debugging"
+	depends on DEBUG_KERNEL
+	help
+	  Say Y here and build SMP to catch missing spinlock initialization
+	  and certain other kinds of spinlock errors commonly made.  This is
+	  best used in conjunction with the NMI watchdog so that spinlock
+	  deadlocks are also debuggable.
+
+config DEBUG_PAGEALLOC
+	bool "Page alloc debugging"
+	depends on DEBUG_KERNEL
+	help
+	  Unmap pages from the kernel linear mapping after free_pages().
+	  This results in a large slowdown, but helps to find certain types
+	  of memory corruptions.
+
+config DEBUG_INFO
+	bool "Compile the kernel with debug info"
+	depends on DEBUG_KERNEL
+	help
+          If you say Y here the resulting kernel image will include
+	  debugging info resulting in a larger kernel image.
+	  Say Y here only if you plan to use gdb to debug the kernel.
+	  If you don't debug the kernel, you can say N.
+
+config DEBUG_SPINLOCK_SLEEP
+	bool "Sleep-inside-spinlock checking"
+	help
+	  If you say Y here, various routines which may sleep will become very
+	  noisy if they are called with a spinlock held.	
+
+config FRAME_POINTER
+	bool "Compile the kernel with frame pointers"
+	help
+	  If you say Y here the resulting kernel image will be slightly larger
+	  and slower, but it will give very useful debugging information.
+	  If you don't debug the kernel, you can say N, but we may not be able
+	  to solve problems without frame pointers.
+
+endmenu
+
+source "security/Kconfig"
+
+source "crypto/Kconfig"
+
+source "lib/Kconfig"
+
diff -ruN linux-2.6.8.1.org/arch/m32r/Makefile linux-2.6.8.1/arch/m32r/Makefile
--- linux-2.6.8.1.org/arch/m32r/Makefile	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.8.1/arch/m32r/Makefile	2004-08-30 10:23:53.000000000 +0900
@@ -0,0 +1,56 @@
+#
+# m32r/Makefile
+# 
+
+LDFLAGS		:=
+OBJCOPYFLAGS	:= -O binary -R .note -R .comment -S
+LDFLAGS_vmlinux	:= -e startup_32
+LDFLAGS_BLOB	:= --format binary --oformat elf32-m32r
+
+CFLAGS += -pipe -fno-schedule-insns
+CFLAGS_KERNEL += -mmodel=medium
+CFLAGS_MODULE += -mmodel=large
+
+ifdef CONFIG_CHIP_VDEC2
+cflags-$(CONFIG_ISA_M32R2)	+= -DNO_FPU -Wa,-bitinst
+aflags-$(CONFIG_ISA_M32R2)	+= -DNO_FPU -Wa,-bitinst
+else
+cflags-$(CONFIG_ISA_M32R2)	+= -DNO_FPU -m32r2
+aflags-$(CONFIG_ISA_M32R2)	+= -DNO_FPU -m32r2
+endif
+
+cflags-$(CONFIG_ISA_M32R)	+= -DNO_FPU 
+aflags-$(CONFIG_ISA_M32R)	+= -DNO_FPU -Wa,-no-bitinst
+
+CFLAGS += $(cflags-y)
+AFLAGS += $(aflags-y)
+
+CHECK	:= $(CHECK) -D__m32r__=1
+
+head-y	:= arch/m32r/kernel/head.o arch/m32r/kernel/init_task.o
+
+LIBGCC	:= $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
+
+libs-y	+= arch/m32r/lib/ $(LIBGCC)
+core-y	+= arch/m32r/kernel/	\
+	   arch/m32r/mm/	\
+	   arch/m32r/boot/
+
+drivers-y			+= arch/m32r/drivers/
+drivers-$(CONFIG_OPROFILE)	+= arch/m32r/oprofile/
+
+boot := arch/m32r/boot
+
+.PHONY: zImage
+
+zImage: vmlinux
+	$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
+
+compressed: zImage
+
+archclean:
+	$(Q)$(MAKE) $(clean)=$(boot)
+
+define archhelp
+	@echo '  zImage			- Compressed kernel image (arch/m32r/boot/zImage)'
+endef
diff -ruN linux-2.6.8.1.org/arch/m32r/boot/Makefile linux-2.6.8.1/arch/m32r/boot/Makefile
--- linux-2.6.8.1.org/arch/m32r/boot/Makefile	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.8.1/arch/m32r/boot/Makefile	2004-07-29 22:07:12.000000000 +0900
@@ -0,0 +1,19 @@
+#
+# 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.
+
+targets := zImage
+subdir- := compressed
+
+obj-y	:= setup.o
+
+$(obj)/zImage: $(obj)/compressed/vmlinux FORCE
+	$(call if_changed,objcopy)
+	@echo 'Kernel: $@ is ready'
+
+$(obj)/compressed/vmlinux: FORCE
+	$(Q)$(MAKE) $(build)=$(obj)/compressed $@
+
diff -ruN linux-2.6.8.1.org/arch/m32r/boot/compressed/Makefile linux-2.6.8.1/arch/m32r/boot/compressed/Makefile
--- linux-2.6.8.1.org/arch/m32r/boot/compressed/Makefile	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.8.1/arch/m32r/boot/compressed/Makefile	2004-08-24 21:17:44.000000000 +0900
@@ -0,0 +1,38 @@
+#
+# linux/arch/sh/boot/compressed/Makefile
+#
+# create a compressed vmlinux image from the original vmlinux
+#
+
+targets		:= vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o \
+		   m32r-sio.o piggy.o vmlinux.lds
+EXTRA_AFLAGS	:= -traditional
+
+OBJECTS = $(obj)/head.o $(obj)/misc.o $(obj)/m32r_sio.o
+
+#
+# IMAGE_OFFSET is the load offset of the compression loader
+#
+#IMAGE_OFFSET := $(shell printf "0x%08x" $$[$(CONFIG_MEMORY_START)+0x2000])
+#IMAGE_OFFSET := $(shell printf "0x%08x" $$[$(CONFIG_MEMORY_START)+0x00400000])
+
+LDFLAGS_vmlinux := -T 
+
+$(obj)/vmlinux: $(obj)/vmlinux.lds $(OBJECTS) $(obj)/piggy.o FORCE
+	$(call if_changed,ld)
+	@:
+
+$(obj)/vmlinux.bin: vmlinux FORCE
+	$(call if_changed,objcopy)
+
+$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
+	$(call if_changed,gzip)
+
+$(obj)/vmlinux.lds: $(obj)/vmlinux.lds.S FORCE
+	$(CPP) $(EXTRA_AFLAGS) -C -P -I include $< >$@
+
+LDFLAGS_piggy.o := -r --format binary --oformat elf32-m32r-linux -T
+OBJCOPYFLAGS += -R .empty_zero_page
+
+$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE
+	$(call if_changed,ld)
diff -ruN linux-2.6.8.1.org/arch/m32r/boot/compressed/boot.h linux-2.6.8.1/arch/m32r/boot/compressed/boot.h
--- linux-2.6.8.1.org/arch/m32r/boot/compressed/boot.h	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.8.1/arch/m32r/boot/compressed/boot.h	2003-09-09 10:15:02.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.6.8.1.org/arch/m32r/boot/compressed/head.S linux-2.6.8.1/arch/m32r/boot/compressed/head.S
--- linux-2.6.8.1.org/arch/m32r/boot/compressed/head.S	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.8.1/arch/m32r/boot/compressed/head.S	2004-08-24 14:42:30.000000000 +0900
@@ -0,0 +1,115 @@
+/*
+ *  linux/arch/m32r/boot/compressed/head.S
+ *
+ *  Copyright (c) 2001-2003	Hiroyuki Kondo, Hirokazu Takata,
+ *				Hitoshi Yamamoto, Takeo Takahashi
+ *  Copyright (c) 2004		Hirokazu Takata
+ */
+
+	.text
+#include <linux/config.h>
+#include <linux/linkage.h>
+#include <asm/addrspace.h>
+#include <asm/page.h>
+#include <asm/assembler.h>
+
+	.global	startup
+	__ALIGN
+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, __bss_start)
+	LDIMM	(r3, _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, __bss_start)
+	LDIMM	(r3, _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
+
+#if defined(CONFIG_CHIP_M32700)
+	/* Cache flush */
+	ldi	r0, -1
+	ldi	r1, 0xd0	; invalidate i-cache, copy back d-cache
+	stb	r1, @r0
+#else
+#error "put your cache flush function, please"
+#endif
+        seth	r0, #high(CONFIG_MEMORY_START)
+        or3	r0, r0, #0x2000
+        jmp	r0
+
+	.balign 512
+fake_headers_as_bzImage:
+	.short	0
+	.ascii	"HdrS"
+	.short	0x0202
+	.short	0
+	.short	0
+	.byte	0x00, 0x10
+	.short	0
+	.byte	0
+	.byte	1
+	.byte	0x00, 0x80
+	.long	0
+	.long	0
+
diff -ruN linux-2.6.8.1.org/arch/m32r/boot/compressed/install.sh linux-2.6.8.1/arch/m32r/boot/compressed/install.sh
--- linux-2.6.8.1.org/arch/m32r/boot/compressed/install.sh	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.8.1/arch/m32r/boot/compressed/install.sh	2003-09-09 10:15:02.000000000 +0900
@@ -0,0 +1,57 @@
+#!/bin/sh
+#
+# arch/sh/boot/install.sh
+#
+# 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) 1995 by Linus Torvalds
+#
+# Adapted from code in arch/i386/boot/Makefile by H. Peter Anvin
+# Adapted from code in arch/i386/boot/install.sh by Russell King
+# Adapted from code in arch/arm/boot/install.sh by Stuart Menefy
+# Adapted from code in arch/sh/boot/install.sh by Takeo Takahashi
+#
+# "make install" script for sh architecture
+#
+# Arguments:
+#   $1 - kernel version
+#   $2 - kernel image file
+#   $3 - kernel map file
+#   $4 - default install path (blank if root directory)
+#
+
+# User may have a custom install script
+
+if [ -x /sbin/installkernel ]; then
+  exec /sbin/installkernel "$@"
+fi
+
+if [ "$2" = "zImage" ]; then
+# Compressed install
+  echo "Installing compressed kernel"
+  if [ -f $4/vmlinuz-$1 ]; then
+    mv $4/vmlinuz-$1 $4/vmlinuz.old
+  fi
+
+  if [ -f $4/System.map-$1 ]; then
+    mv $4/System.map-$1 $4/System.old
+  fi
+
+  cat $2 > $4/vmlinuz-$1
+  cp $3 $4/System.map-$1
+else
+# Normal install
+  echo "Installing normal kernel"
+  if [ -f $4/vmlinux-$1 ]; then
+    mv $4/vmlinux-$1 $4/vmlinux.old
+  fi
+
+  if [ -f $4/System.map ]; then
+    mv $4/System.map $4/System.old
+  fi
+
+  cat $2 > $4/vmlinux-$1
+  cp $3 $4/System.map
+fi
diff -ruN linux-2.6.8.1.org/arch/m32r/boot/compressed/m32r_sio.c linux-2.6.8.1/arch/m32r/boot/compressed/m32r_sio.c
--- linux-2.6.8.1.org/arch/m32r/boot/compressed/m32r_sio.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.8.1/arch/m32r/boot/compressed/m32r_sio.c	2004-08-24 14:21:43.000000000 +0900
@@ -0,0 +1,53 @@
+/*
+ * 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);
+
+int puts(const char *s)
+{
+	char c;
+	while ((c = *s++)) putc(c);
+	return 0;
+}
+
+#if defined(CONFIG_PLAT_M32700UT_Alpha) || defined(CONFIG_PLAT_M32700UT)
+#define USE_FPGA_MAP	0
+
+#if USE_FPGA_MAP
+/*
+ * fpga configuration program uses MMU, and define map as same as
+ * M32104 uT-Engine board.
+ */
+#define BOOT_SIO0STS	(volatile unsigned short *)(0x02c00000 + 0x20006)
+#define BOOT_SIO0TXB	(volatile unsigned short *)(0x02c00000 + 0x2000c)
+#else
+#undef PLD_BASE
+#define PLD_BASE	0xa4c00000
+#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.6.8.1.org/arch/m32r/boot/compressed/misc.c linux-2.6.8.1/arch/m32r/boot/compressed/misc.c
--- linux-2.6.8.1.org/arch/m32r/boot/compressed/misc.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.8.1/arch/m32r/boot/compressed/misc.c	2004-08-24 20:18:39.000000000 +0900
@@ -0,0 +1,223 @@
+/*
+ * 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 <linux/string.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 int 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 = CONFIG_MEMORY_START + 0x2000;
+	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.6.8.1.org/arch/m32r/boot/compressed/vmlinux.lds.S linux-2.6.8.1/arch/m32r/boot/compressed/vmlinux.lds.S
--- linux-2.6.8.1.org/arch/m32r/boot/compressed/vmlinux.lds.S	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.8.1/arch/m32r/boot/compressed/vmlinux.lds.S	2004-08-23 20:53:31.000000000 +0900
@@ -0,0 +1,23 @@
+#include <linux/config.h>
+
+OUTPUT_ARCH(m32r)
+ENTRY(startup)
+SECTIONS
+{
+  . = CONFIG_MEMORY_START + 0x00400000;
+  
+  _text = .;
+  .text : { *(.text) } = 0
+  .rodata : { *(.rodata) }
+  _etext = .;
+
+  . = ALIGN(32) + (. & (32 - 1));
+  .data : { *(.data) }
+  _edata  =  .;
+
+  . = ALIGN(32 / 8);
+  __bss_start = .;
+  .bss : { *(.bss) }
+  . = ALIGN(32 / 8);
+  _end = . ;
+}
diff -ruN linux-2.6.8.1.org/arch/m32r/boot/compressed/vmlinux.scr linux-2.6.8.1/arch/m32r/boot/compressed/vmlinux.scr
--- linux-2.6.8.1.org/arch/m32r/boot/compressed/vmlinux.scr	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.8.1/arch/m32r/boot/compressed/vmlinux.scr	2004-07-29 22:07:12.000000000 +0900
@@ -0,0 +1,9 @@
+SECTIONS
+{
+  .data : { 
+	input_len = .;
+	LONG(input_data_end - input_data) input_data = .; 
+	*(.data) 
+	input_data_end = .; 
+	}
+}
diff -ruN linux-2.6.8.1.org/arch/m32r/boot/setup.S linux-2.6.8.1/arch/m32r/boot/setup.S
--- linux-2.6.8.1.org/arch/m32r/boot/setup.S	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.8.1/arch/m32r/boot/setup.S	2004-08-24 20:18:01.000000000 +0900
@@ -0,0 +1,162 @@
+/*
+ *  linux/arch/m32r/boot/setup.S -- A setup code.
+ *
+ *  Copyright (C) 2001, 2002  Hiroyuki Kondo, Hirokazu Takata,
+ *  and Hitoshi Yamamoto
+ *
+ */
+/* $Id$ */
+
+#include <linux/linkage.h>
+#include <asm/segment.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+	
+#include <linux/config.h>
+#include <asm/assembler.h>
+#include <asm/mmu_context.h>
+#include <asm/m32r.h>
+
+/*
+ * References to members of the boot_cpu_data structure.
+ */
+
+#define CPU_PARAMS	boot_cpu_data
+#define M32R_MCICAR	 0xfffffff0	
+#define M32R_MCDCAR	 0xfffffff4	
+#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_M32700) || defined(CONFIG_CHIP_VDEC2) \
+    || defined(CONFIG_CHIP_OPSP)
+	ldi	r0, #-4              ;LDIMM	(r0, M32R_MCCR)
+	ldi	r1, #0x73		; cache on (with invalidation)
+;	ldi	r1, #0x00		; cache off
+	st	r1, @r0
+#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
+#if !defined(CONFIG_PLAT_USRV)
+	;; boot AP
+	ld24	r5, #0xeff2f8		; IPICR7
+	ldi	r6, #0x2		; IPI to CPU1
+	st	r6, @r5
+#endif
+#endif
+
+/*
+ *  Now, Jump to stext 
+ *        if with MMU,    TLB on.
+ *        if with no MMU, only jump.
+ */
+ 	.global	eit_vector
+mmu_on:
+	LDIMM	(r13, stext)
+#ifdef CONFIG_MMU
+	bl	init_tlb
+	LDIMM	(r2, eit_vector)		; 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
+#else
+	seth	r0,#high(M32R_MCDCAR)
+	or3	r0,r0,#low(M32R_MCDCAR)
+	ld24	r1,#0x8080
+	st	r1,@r0
+#endif	/* CONFIG_MMU */
+	jmp	r13
+	nop
+	nop
+
+#ifdef CONFIG_SMP
+/* 
+ * AP wait loop
+ */
+ENTRY(AP_loop)
+	;; disable interrupt
+	clrpsw	#0x40
+	;; reset EVB
+	LDIMM	(r4, _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	#0x40
+    	;; 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.6.8.1.org/arch/m32r/defconfig linux-2.6.8.1/arch/m32r/defconfig
--- linux-2.6.8.1.org/arch/m32r/defconfig	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.8.1/arch/m32r/defconfig	2004-08-30 10:23:53.000000000 +0900
@@ -0,0 +1,635 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_M32R=y
+CONFIG_UID16=y
+CONFIG_GENERIC_ISA_DMA=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_HOTPLUG=y
+CONFIG_IKCONFIG=y
+# CONFIG_IKCONFIG_PROC is not set
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# Processor type and features
+#
+# CONFIG_PLAT_MAPPI is not set
+# CONFIG_PLAT_USRV is not set
+CONFIG_PLAT_M32700UT=y
+# CONFIG_PLAT_OPSPUT is not set
+# CONFIG_PLAT_OAKS32R is not set
+# CONFIG_PLAT_MAPPI2 is not set
+CONFIG_CHIP_M32700=y
+# CONFIG_CHIP_M32102 is not set
+# CONFIG_CHIP_VDEC2 is not set
+# CONFIG_CHIP_OPSP is not set
+CONFIG_MMU=y
+CONFIG_TLB_ENTRIES=32
+CONFIG_ISA_M32R2=y
+CONFIG_ISA_DSP_LEVEL2=y
+CONFIG_ISA_DUAL_ISSUE=y
+CONFIG_BUS_CLOCK=50000000
+CONFIG_TIMER_DIVIDE=128
+# CONFIG_CPU_LITTLE_ENDIAN is not set
+CONFIG_MEMORY_START=0x08000000
+CONFIG_MEMORY_SIZE=0x01000000
+CONFIG_NOHIGHMEM=y
+# CONFIG_DISCONTIGMEM is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_PREEMPT=y
+# CONFIG_HAVE_DEC_LOCK is not set
+# CONFIG_SMP is not set
+
+#
+# M32R drivers
+#
+# CONFIG_M32RPCC is not set
+CONFIG_M32R_CFC=y
+CONFIG_M32700UT_CFC=y
+CONFIG_CFC_NUM=1
+# CONFIG_MTD_M32R is not set
+CONFIG_M32R_SMC91111=y
+CONFIG_M32700UT_DS1302=y
+
+#
+# Power management options (ACPI, APM)
+#
+# CONFIG_PM is not set
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+# CONFIG_PCI is not set
+# CONFIG_ISA is not set
+
+#
+# PCMCIA/CardBus support
+#
+CONFIG_PCMCIA=y
+# CONFIG_PCMCIA_DEBUG is not set
+# CONFIG_TCIC is not set
+
+#
+# PCI Hotplug Support
+#
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+CONFIG_BLK_DEV_NBD=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_INITRD is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_BLK_DEV_IDECS=y
+CONFIG_BLK_DEV_IDECD=m
+# 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
+# CONFIG_IDE_TASKFILE_IO is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+# CONFIG_IDE_ARM is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=m
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_CHR_DEV_SG=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# PCMCIA SCSI adapter support
+#
+# CONFIG_PCMCIA_AHA152X is not set
+# CONFIG_PCMCIA_FDOMAIN is not set
+# CONFIG_PCMCIA_NINJA_SCSI is not set
+# CONFIG_PCMCIA_QLOGIC is not set
+# CONFIG_PCMCIA_SYM53C500 is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+# CONFIG_NETLINK_DEV is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+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_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_NETDEVICES is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_CT82C710 is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_M32R_SIO is not set
+CONFIG_SERIAL_M32R_PLDSIO=y
+CONFIG_SERIAL_M32R_PLDSIO_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_QIC02_TAPE is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_SYNCLINK_CS is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=y
+
+#
+# Video For Linux
+#
+
+#
+# Video Adapters
+#
+# CONFIG_VIDEO_CPIA is not set
+CONFIG_M32R_AR=y
+CONFIG_M32R_AR_VGA=y
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_MAESTRO is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=m
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=m
+CONFIG_JBD_DEBUG=y
+CONFIG_FS_MBCACHE=y
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_REISERFS_FS_XATTR is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+# CONFIG_EXPORTFS is not set
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+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_ASCII 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
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_FRAME_POINTER is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
diff -ruN linux-2.6.8.1.org/arch/m32r/drivers/8390.c linux-2.6.8.1/arch/m32r/drivers/8390.c
--- linux-2.6.8.1.org/arch/m32r/drivers/8390.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.8.1/arch/m32r/drivers/8390.c	2003-09-09 10:15:02.000000000 +0900
@@ -0,0 +1 @@
+#include "../../../drivers/net/8390.c"
diff -ruN linux-2.6.8.1.org/arch/m32r/drivers/8390.h linux-2.6.8.1/arch/m32r/drivers/8390.h
--- linux-2.6.8.1.org/arch/m32r/drivers/8390.h	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.8.1/arch/m32r/drivers/8390.h	2003-09-09 10:15:02.000000000 +0900
@@ -0,0 +1 @@
+#include "../../../drivers/net/8390.h"
diff -ruN linux-2.6.8.1.org/arch/m32r/drivers/Kconfig linux-2.6.8.1/arch/m32r/drivers/Kconfig
--- linux-2.6.8.1.org/arch/m32r/drivers/Kconfig	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.8.1/arch/m32r/drivers/Kconfig	2004-08-03 17:21:10.000000000 +0900
@@ -0,0 +1,42 @@
+#
+# For a description of the syntax of this configuration file,
+# see Documentation/kbuild/kconfig-language.txt.
+#
+
+menu "M32R drivers"
+
+config M32RPCC
+	bool "M32R PCMCIA I/F"
+	depends on CHIP_M32700
+
+config M32R_NE2000
+	bool "On board NE2000 Network Interface Chip"
+	depends on PLAT_MAPPI || PLAT_OAKS32R
+
+config M32R_CFC
+	bool "CF I/F Controller"
+	depends on PLAT_USRV || PLAT_M32700UT || PLAT_MAPPI2 || PLAT_OPSPUT
+
+config M32700UT_CFC
+	bool
+	depends on M32R_CFC
+	default y
+
+config CFC_NUM
+	int "CF I/F number"
+	depends on PLAT_USRV || PLAT_M32700UT
+	default "1" if PLAT_USRV || PLAT_M32700UT || PLAT_MAPPI2 || PLAT_OPSPUT
+
+config MTD_M32R
+	bool "Flash device mapped on M32R"
+	depends on PLAT_USRV || PLAT_M32700UT || PLAT_MAPPI2
+
+config M32R_SMC91111
+	bool "On board SMC91111 Network Interface Chip"
+	depends on PLAT_M32700UT || PLAT_MAPPI2 || PLAT_OPSPUT
+
+config M32700UT_DS1302
+	bool "DS1302 Real Time Clock support"
+	depends on PLAT_M32700UT || PLAT_OPSPUT
+
+endmenu
diff -ruN linux-2.6.8.1.org/arch/m32r/drivers/Makefile linux-2.6.8.1/arch/m32r/drivers/Makefile
--- linux-2.6.8.1.org/arch/m32r/drivers/Makefile	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.8.1/arch/m32r/drivers/Makefile	2004-02-17 17:31:39.000000000 +0900
@@ -0,0 +1,9 @@
+#
+# Makefile for the Linux/M32R driver
+#
+
+obj-$(CONFIG_M32R_SMC91111)	+= smc91111.o
+obj-$(CONFIG_M32R_NE2000)	+= mappi_ne.o 8390.o
+obj-$(CONFIG_M32RPCC)		+= m32r_pcc.o
+obj-$(CONFIG_M32R_CFC)		+= m32r_cfc.o
+obj-$(CONFIG_M32700UT_DS1302)	+= ds1302.o
diff -ruN linux-2.6.8.1.org/arch/m32r/drivers/cs_internal.h linux-2.6.8.1/arch/m32r/drivers/cs_internal.h
--- linux-2.6.8.1.org/arch/m32r/drivers/cs_internal.h	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.8.1/arch/m32r/drivers/cs_internal.h	2003-09-09 10:15:02.000000000 +0900
@@ -0,0 +1,2 @@
+#include "../../../drivers/pcmcia/cs_internal.h"
+
diff -ruN linux-2.6.8.1.org/arch/m32r/drivers/ds1302.c linux-2.6.8.1/arch/m32r/drivers/ds1302.c
--- linux-2.6.8.1.org/arch/m32r/drivers/ds1302.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.8.1/arch/m32r/drivers/ds1302.c	2004-08-03 17:21:10.000000000 +0900
@@ -0,0 +1,432 @@
+/*!***************************************************************************
+*!
+*! 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.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.2 2003/10/29 08:42:58 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 <linux/bcd.h>
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/rtc.h>
+#include <asm/m32r.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;
+
+	local_irq_save(flags);
+	local_irq_disable();
+
+	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);
+
+	local_irq_restore(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);
+
+			local_irq_save(flags);
+			local_irq_disable();
+			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);
+			local_irq_restore(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;
+	}
+}
+
+int
+get_rtc_status(char *buf) 
+{
+	char *p;
+	struct rtc_time tm;
+
+	p = buf;
+
+	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.
+	 */
+
+	p += sprintf(p,
+		"rtc_time\t: %02d:%02d:%02d\n"
+		"rtc_date\t: %04d-%02d-%02d\n",
+		tm.tm_hour, tm.tm_min, tm.tm_sec,
+		tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
+
+	return  p - buf;
+}
+
+
+/* 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) {
+		char buf[100];
+		ds1302_wdisable();
+		printk("%s: RTC found.\n", ds1302_name);
+                get_rtc_status(buf);
+                printk(buf);
+		retval = 1;
+	} else {
+		printk("%s: RTC not found.\n", ds1302_name);
+		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()) {
+    		return -1;
+  	}
+	return 0;
+}
+
+static int __init ds1302_register(void)
+{
+        ds1302_init();
+	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_register);
diff -ruN linux-2.6.8.1.org/arch/m32r/drivers/m32r-pldsio.c linux-2.6.8.1/arch/m32r/drivers/m32r-pldsio.c
--- linux-2.6.8.1.org/arch/m32r/drivers/m32r-pldsio.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.8.1/arch/m32r/drivers/m32r-pldsio.c	2003-09-09 10:15:02.000000000 +0900
@@ -0,0 +1,3067 @@
+/* $Id$
+ *
+ * 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 1996, 2001, Mitsubishi Electric Corporation 
+ *  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;
+
+	if (info->xmit.head == info->xmit.tail
+		|| tty->stopped
+		|| tty->hw_stopped
+		|| !info->xmit.buf)
+		return;
+
+	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->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.6.8.1.org/arch/m32r/drivers/m32r_cfc.c linux-2.6.8.1/arch/m32r/drivers/m32r_cfc.c
--- linux-2.6.8.1.org/arch/m32r/drivers/m32r_cfc.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.8.1/arch/m32r/drivers/m32r_cfc.c	2004-07-27 15:54:20.000000000 +0900
@@ -0,0 +1,910 @@
+/*  
+ *  linux/arch/m32r/drivers/m32r_cfc.c
+ *  
+ *  Device driver for the CFC functionality of M32R.
+ *  
+ *  Copyright (c) 2001, 2002, 2003, 2004
+ *   Hiroyuki Kondo, Sugai Naotom, Hayato Fujiwara
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.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/ioport.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+#include <linux/device.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>
+
+#undef MAX_IO_WIN	/* FIXME */
+#define MAX_IO_WIN 1
+#undef MAX_WIN	/* FIXME */
+#define MAX_WIN 1
+
+#include "m32r_cfc.h"
+
+#if !defined(COFIG_PLAT_USRV)
+#define PCMCIA_DEBUG   3
+#endif	/* COFIG_PLAT_USRV */
+
+#ifdef PCMCIA_DEBUG
+int m32r_cfc_debug = PCMCIA_DEBUG;
+module_param(m32r_cfc_debug, int, 0444);
+#define DEBUG(n, args...) if (m32r_cfc_debug>(n)) printk(args)
+#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 {
+	u_short			type, flags;
+	struct pcmcia_socket	socket;
+	unsigned int		number;
+ 	ioaddr_t		ioaddr;
+	u_long			mapaddr;
+	u_long			base;	/* PCC register base */
+	u_char			cs_irq1, cs_irq2, intr;
+	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_t;
+
+static int pcc_sockets = 0;
+static pcc_socket_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 port 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 irqreturn_t 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_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("pcc at 0x%08lx\n", t->base);
+
+	/* Update socket interrupt information, capabilities */
+	t->socket.features |= (SS_CAP_PCCARD | SS_CAP_STATIC_MAP);
+	t->socket.map_size = M32R_PCC_MAPSIZE;
+	t->socket.io_offset = ioaddr;	/* use for io access offset */
+	t->socket.irq_mask = 0;
+#if !defined(CONFIG_PLAT_USRV)
+	t->socket.pci_irq = PLD_IRQ_CFIREQ ;	/* card interrupt */
+#else	/* CONFIG_PLAT_USRV */
+	t->socket.pci_irq = PLD_IRQ_CF0 + pcc_sockets;
+#endif	/* CONFIG_PLAT_USRV */
+
+#ifndef 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) || defined(CONFIG_PLAT_USRV) || defined(CONFIG_PLAT_OPSPUT)
+	pcc_set(pcc_sockets, (unsigned int)PLD_CFCR1, 0x0200); 
+#endif
+	pcc_sockets++;
+
+	return;
+}
+
+
+/*====================================================================*/
+
+static irqreturn_t pcc_interrupt(int irq, void *dev, struct pt_regs *regs)
+{
+	int i;
+	u_int events = 0;
+	int handled = 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;
+
+		handled = 1;
+		DEBUG(3, "m32r_cfc: pcc_interrupt: socket %d irq 0x%02x ",
+			i, irq);
+		events |= SS_DETECT;	/* insert or eject */
+		if (events)
+			pcmcia_parse_events(&socket[i].socket, events);
+	}
+	DEBUG(3, "m32r_cfc: pcc_interrupt: done\n");
+
+	return IRQ_RETVAL(handled);
+} /* pcc_interrupt */
+
+static void pcc_interrupt_wrapper(u_long data)
+{
+	DEBUG(3, "m32r_cfc: pcc_interrupt_wrapper:\n");
+	pcc_interrupt(0, NULL, NULL);
+	init_timer(&poll_timer);
+	poll_timer.expires = jiffies + poll_interval;
+	add_timer(&poll_timer);
+}
+
+/*====================================================================*/
+
+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) || defined(CONFIG_PLAT_USRV) || defined(CONFIG_PLAT_OPSPUT)
+	if ( status ) {
+		/* 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);
+		}
+		*value |= SS_POWERON;
+
+		pcc_set(sock, (unsigned int)PLD_CFBUFCR,0);/* enable buffer */
+		udelay(100);
+
+		*value |= SS_READY; 		/* always ready */
+		*value |= SS_3VCARD; 
+	} else {
+		/* 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);
+	}
+#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_t *t = &socket[sock];
+	
+#if 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) || defined(CONFIG_PLAT_USRV) || defined(CONFIG_PLAT_OPSPUT)
+	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_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_set_mem_map(u_short sock, struct pccard_mem_map *mem)
+{
+
+	u_char map = mem->map;
+	u_long mode;
+	u_long addr;
+	pcc_socket_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 */
+
+#if 0 /* driver model ordering issue */
+/*======================================================================
+
+	Routines for accessing socket information and register dumps via
+	/proc/bus/pccard/...
+	
+======================================================================*/
+
+static ssize_t show_info(struct class_device *class_dev, char *buf)
+{
+	pcc_socket_t *s = container_of(class_dev, struct pcc_socket, 
+		socket.dev);
+
+	return sprintf(buf, "type:     %s\nbase addr:    0x%08lx\n",
+		pcc[s->type].name, s->base);
+}
+
+static ssize_t show_exca(struct class_device *class_dev, char *buf)
+{
+	/* FIXME */
+
+	return 0;
+}
+
+static CLASS_DEVICE_ATTR(info, S_IRUGO, show_info, NULL);
+static CLASS_DEVICE_ATTR(exca, S_IRUGO, show_exca, NULL);
+#endif
+
+/*====================================================================*/
+
+/* this is horribly ugly... proper locking needs to be done here at 
+ * some time... */
+#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)
+
+
+static int pcc_get_status(struct pcmcia_socket *s, u_int *value)
+{
+	unsigned int sock = container_of(s, struct pcc_socket, socket)->number;
+
+	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(struct pcmcia_socket *s, socket_state_t *state)
+{
+	unsigned int sock = container_of(s, struct pcc_socket, socket)->number;
+
+	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(struct pcmcia_socket *s, socket_state_t *state)
+{
+	unsigned int sock = container_of(s, struct pcc_socket, socket)->number;
+
+	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_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io)
+{
+	unsigned int sock = container_of(s, struct pcc_socket, socket)->number;
+
+	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_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *mem)
+{
+	unsigned int sock = container_of(s, struct pcc_socket, socket)->number;
+
+	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(struct pcmcia_socket *s)
+{
+	DEBUG(3, "m32r_cfc: pcc_init()\n");
+	return 0;
+}
+
+static int pcc_suspend(struct pcmcia_socket *sock)
+{
+	DEBUG(3, "m32r_cfc: pcc_suspend()\n");
+	return pcc_set_socket(sock, &dead_socket);
+}
+
+static struct pccard_operations pcc_operations = {
+	.init			= pcc_init,
+	.suspend		= pcc_suspend,
+	.get_status		= pcc_get_status,
+	.get_socket		= pcc_get_socket,
+	.set_socket		= pcc_set_socket,
+	.set_io_map		= pcc_set_io_map,
+	.set_mem_map		= pcc_set_mem_map,
+};
+
+/*====================================================================*/
+
+static int m32rpcc_suspend(struct device *dev, u32 state, u32 level)
+{
+	int ret = 0;
+	if (level == SUSPEND_SAVE_STATE)
+		ret = pcmcia_socket_dev_suspend(dev, state);
+	return ret;
+}
+
+static int m32rpcc_resume(struct device *dev, u32 level)
+{
+	int ret = 0;
+	if (level == RESUME_RESTORE_STATE)
+		ret = pcmcia_socket_dev_resume(dev);
+	return ret;
+}
+
+
+static struct device_driver pcc_driver = {
+	.name = "cfc",
+	.bus = &platform_bus_type,
+	.suspend = m32rpcc_suspend,
+	.resume = m32rpcc_resume,
+};
+
+static struct platform_device pcc_device = {
+	.name = "cfc",
+	.id = 0,
+};
+
+/*====================================================================*/
+
+#define UT_CFC
+static int __init init_m32r_pcc(void)
+{
+	int i, ret;
+
+	ret = driver_register(&pcc_driver);
+	if (ret)
+		return ret;
+
+	ret = platform_device_register(&pcc_device);
+	if (ret){
+		driver_unregister(&pcc_driver);
+		return ret;
+	}
+
+#if defined(CONFIG_PLAT_MAPPI2)
+        pcc_set(0, (unsigned int)PLD_CFCR0, 0x0f0f);
+        pcc_set(0, (unsigned int)PLD_CFCR1, 0x0200);
+#endif
+
+	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 */
+	{
+		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");
+		platform_device_unregister(&pcc_device);
+		driver_unregister(&pcc_driver);
+		return -ENODEV;
+	}
+
+	/* Set up interrupt handler(s) */
+
+	for (i = 0 ; i < pcc_sockets ; i++) {
+		socket[i].socket.dev.dev = &pcc_device.dev;
+		socket[i].socket.ops = &pcc_operations;
+		socket[i].socket.owner = THIS_MODULE;
+		socket[i].number = i;
+		ret = pcmcia_register_socket(&socket[i].socket);
+		if (ret && i--) {
+			for (; i>= 0; i--)
+				pcmcia_unregister_socket(&socket[i].socket);
+			break;
+		}
+#if 0	/* driver model ordering issue */
+		class_device_create_file(&socket[i].socket.dev,
+					 &class_device_attr_info);
+		class_device_create_file(&socket[i].socket.dev,
+					 &class_device_attr_exca);
+#endif
+	}
+
+	/* 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)
+{
+	int i;
+
+	for (i = 0; i < pcc_sockets; i++)
+		pcmcia_unregister_socket(&socket[i].socket);
+
+	platform_device_unregister(&pcc_device);
+	if (poll_interval != 0)
+		del_timer_sync(&poll_timer);
+
+	driver_unregister(&pcc_driver);
+} /* exit_m32r_pcc */
+
+module_init(init_m32r_pcc);
+module_exit(exit_m32r_pcc);
+MODULE_LICENSE("Dual MPL/GPL");
+/*====================================================================*/
diff -ruN linux-2.6.8.1.org/arch/m32r/drivers/m32r_cfc.h linux-2.6.8.1/arch/m32r/drivers/m32r_cfc.h
--- linux-2.6.8.1.org/arch/m32r/drivers/m32r_cfc.h	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.8.1/arch/m32r/drivers/m32r_cfc.h	2003-12-15 15:48:06.000000000 +0900
@@ -0,0 +1,85 @@
+/*
+ *  $Id$
+ *
+ * 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.6.8.1.org/arch/m32r/drivers/m32r_pcc.c linux-2.6.8.1/arch/m32r/drivers/m32r_pcc.c
--- linux-2.6.8.1.org/arch/m32r/drivers/m32r_pcc.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.8.1/arch/m32r/drivers/m32r_pcc.c	2004-07-15 13:43:14.000000000 +0900
@@ -0,0 +1,818 @@
+/*======================================================================
+
+	Device driver for the PCMCIA functionality of M32R.
+
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/moduleparam.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/ioport.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+#include <asm/system.h>
+#include <asm/addrspace.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/cs.h>
+
+/* XXX: should be moved into asm/irq.h */
+#define PCC0_IRQ 24
+#define PCC1_IRQ 25
+
+#define CHAOS_PCC_DEBUG
+#ifdef CHAOS_PCC_DEBUG
+	static volatile u_short dummy_readbuf;
+#endif
+
+#define PCC_DEBUG_DBEX
+
+#define PCMCIA_DEBUG   0
+
+#include "m32r_pcc.h"
+
+#ifdef PCMCIA_DEBUG
+int pc_debug = PCMCIA_DEBUG;
+module_param(pc_debug, int, 0444);
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(args)
+#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 {
+	u_short			type, flags;
+	struct pcmcia_socket	socket;
+	unsigned int		number;
+ 	ioaddr_t		ioaddr;
+	u_long			mapaddr;
+	u_long			base;	/* PCC register base */
+	u_char			cs_irq, intr;
+	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_t;
+
+static int pcc_sockets = 0;
+static pcc_socket_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;
+
+void pcc_iorw(int sock, unsigned long port, void *buf, size_t size, size_t nmemb, int wr, int flag)
+{
+	u_long addr;
+	u_long flags;
+	int need_ex;
+#ifdef PCC_DEBUG_DBEX
+	int _dbex;
+#endif
+	pcc_socket_t *t = &socket[sock];
+#ifdef CHAOS_PCC_DEBUG
+	int map_changed = 0;
+#endif
+
+	/* Need lock ? */
+	spin_lock_irqsave(&pcc_lock, flags);
+
+	/*
+	 * Check if need dbex
+	 */
+	need_ex = (size > 1 && flag == 0) ? PCMOD_DBEX : 0;
+#ifdef PCC_DEBUG_DBEX
+	_dbex = need_ex;
+	need_ex = 0;
+#endif
+
+	/*
+	 * calculate access address
+	 */
+	addr = t->mapaddr + port - t->ioaddr + KSEG1; /* XXX */
+
+	/*
+	 * Check current mapping
+	 */
+	if (t->current_space != as_io || t->last_iodbex != need_ex) {
+
+		u_long cbsz;
+
+		/*
+		 * Disable first
+		 */
+		pcc_set(sock, PCCR, 0);
+
+		/*
+		 * Set mode and io address
+		 */
+		cbsz = (t->flags & MAP_16BIT) ? 0 : PCMOD_CBSZ;
+		pcc_set(sock, PCMOD, PCMOD_AS_IO | cbsz | need_ex);
+		pcc_set(sock, PCADR, addr & 0x1ff00000);
+
+		/*
+		 * Enable and read it
+		 */
+		pcc_set(sock, PCCR, 1);
+
+#ifdef CHAOS_PCC_DEBUG
+#if 0
+		map_changed = (t->current_space == as_attr && size == 2); /* XXX */
+#else
+		map_changed = 1;
+#endif
+#endif
+		t->current_space = as_io;
+	}
+
+	/*
+	 * access to IO space
+	 */
+	if (size == 1) {
+		/* Byte */
+		unsigned char *bp = (unsigned char *)buf;
+
+#ifdef CHAOS_DEBUG
+		if (map_changed) {
+			dummy_readbuf = readb(addr);
+		}
+#endif
+		if (wr) {
+			/* write Byte */
+			while (nmemb--) {
+				writeb(*bp++, addr);
+			}
+		} else {
+			/* read Byte */
+			while (nmemb--) {
+	    		*bp++ = readb(addr);
+			}
+		}
+	} else {
+		/* Word */
+		unsigned short *bp = (unsigned short *)buf;
+
+#ifdef CHAOS_PCC_DEBUG
+		if (map_changed) {
+			dummy_readbuf = readw(addr);
+		}
+#endif
+		if (wr) {
+			/* write Word */
+			while (nmemb--) {
+#ifdef PCC_DEBUG_DBEX
+				if (_dbex) {
+					unsigned char *cp = (unsigned char *)bp;
+					unsigned short tmp;
+					tmp = cp[1] << 8 | cp[0];
+					writew(tmp, addr);
+					bp++;
+				} else 
+#endif
+				writew(*bp++, addr);
+	    	}
+	    } else {
+	    	/* read Word */
+	    	while (nmemb--) {
+#ifdef  PCC_DEBUG_DBEX
+				if (_dbex) {
+					unsigned char *cp = (unsigned char *)bp;
+					unsigned short tmp;
+					tmp = readw(addr);
+					cp[0] = tmp & 0xff;
+					cp[1] = (tmp >> 8) & 0xff;
+					bp++;
+				} else 
+#endif
+				*bp++ = readw(addr);
+	    	}
+	    }
+	}
+
+#if 1
+	/* addr is no longer used */
+	if ((addr = pcc_get(sock, PCIRC)) & PCIRC_BWERR) {
+	  printk("m32r_pcc: BWERR detected : port 0x%04lx : iosize %dbit\n",
+			 port, size * 8);
+	  pcc_set(sock, PCIRC, addr);
+	}
+#endif
+	/*
+	 * save state
+	 */
+	t->last_iosize = size;
+	t->last_iodbex = need_ex;
+
+	/* Need lock ? */
+
+	spin_unlock_irqrestore(&pcc_lock,flags);
+
+	return;
+}
+
+void pcc_ioread(int sock, unsigned long port, void *buf, size_t size, size_t nmemb, int flag) {
+	pcc_iorw(sock, port, buf, size, nmemb, 0, flag);
+}
+
+void pcc_iowrite(int sock, unsigned long port, void *buf, size_t size, size_t nmemb, int flag) {
+    pcc_iorw(sock, port, buf, size, nmemb, 1, flag);
+}
+
+/*====================================================================*/
+
+#define IS_ALIVE		0x8000
+
+typedef struct pcc_t {
+	char				*name;
+	u_short				flags;
+} pcc_t;
+
+static pcc_t pcc[] = {
+	{ "xnux2", 0 }, { "xnux2", 0 },
+};
+
+static irqreturn_t pcc_interrupt(int, void *, struct pt_regs *);
+
+/*====================================================================*/
+
+static struct timer_list poll_timer;
+
+static unsigned int pcc_get(u_short sock, unsigned int reg)
+{
+	return inl(socket[sock].base + reg);
+}
+
+
+static void pcc_set(u_short sock, unsigned int reg, unsigned int data)
+{
+  	outl(data, socket[sock].base + reg);
+}
+
+/*======================================================================
+
+	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;
+	unsigned int f;
+	
+	stat = pcc_get(sock, PCIRC);
+	f = (stat & (PCIRC_CDIN1 | PCIRC_CDIN2)) >> 16;
+	if(!f){
+		printk("m32r_pcc: No Card is detected at socket %d : stat = 0x%08x\n",stat,sock);
+		return 0;
+	}
+	if(f!=3)
+		printk("m32r_pcc: Insertion fail (%.8x) at socket %d\n",stat,sock);
+	else
+		printk("m32r_pcc: Card is Inserted at socket %d(%.8x)\n",sock,stat);
+	return 0;
+}
+
+static void add_pcc_socket(ulong base, int irq, ulong mapaddr, ioaddr_t ioaddr)
+{
+  	pcc_socket_t *t = &socket[pcc_sockets];
+
+	/* add sockets */
+	t->ioaddr = ioaddr;
+	t->mapaddr = mapaddr;
+	t->base = base;
+#ifdef CHAOS_PCC_DEBUG
+	t->flags = MAP_16BIT;
+#else
+	t->flags = 0;
+#endif
+	if (is_alive(pcc_sockets))
+		t->flags |= IS_ALIVE;
+
+	/* add pcc */
+	if (t->base > 0) {
+		request_region(t->base, 0x20, "m32r-pcc");
+	}
+
+	printk(KERN_INFO "  %s ", pcc[pcc_sockets].name);
+	printk("pcc at 0x%08lx\n", t->base);
+
+	/* Update socket interrupt information, capabilities */
+	t->socket.features |= (SS_CAP_PCCARD | SS_CAP_STATIC_MAP);
+	t->socket.map_size = M32R_PCC_MAPSIZE;
+	t->socket.io_offset = ioaddr;	/* use for io access offset */
+	t->socket.irq_mask = 0;
+	t->socket.pci_irq = 2 + pcc_sockets; /* XXX */
+
+	request_irq(irq, pcc_interrupt, 0, "m32r-pcc", pcc_interrupt);
+
+	pcc_sockets++;
+
+	return;
+}
+
+
+/*====================================================================*/
+
+static irqreturn_t pcc_interrupt(int irq, void *dev, struct pt_regs *regs)
+{
+	int i, j, irc;
+	u_int events, active;
+	int handled = 0;
+	
+	DEBUG(4, "m32r: pcc_interrupt(%d)\n", irq);
+
+	for (j = 0; j < 20; j++) {
+		active = 0;
+		for (i = 0; i < pcc_sockets; i++) {
+			if ((socket[i].cs_irq != irq) &&
+				(socket[i].socket.pci_irq != irq))
+				continue;
+			handled = 1;
+			irc = pcc_get(i, PCIRC);
+			irc >>=16;
+			DEBUG(2, "m32r-pcc:interrput: socket %d pcirc 0x%02x ", i, irc);
+			if (!irc)
+				continue;
+
+			events = (irc) ? SS_DETECT : 0;
+			events |= (pcc_get(i,PCCR) & PCCR_PCEN) ? SS_READY : 0;
+			DEBUG(2, " event 0x%02x\n", events);
+
+			if (events)
+				pcmcia_parse_events(&socket[i].socket, events);
+
+			active |= events;
+			active = 0;
+		}
+		if (!active) break;
+	}
+	if (j == 20)
+		printk(KERN_NOTICE "m32r-pcc: infinite loop in interrupt handler\n");
+
+	DEBUG(4, "m32r-pcc: interrupt done\n");
+
+	return IRQ_RETVAL(handled);
+} /* pcc_interrupt */
+
+static void pcc_interrupt_wrapper(u_long data)
+{
+	pcc_interrupt(0, NULL, NULL);
+	init_timer(&poll_timer);
+	poll_timer.expires = jiffies + poll_interval;
+	add_timer(&poll_timer);
+}
+
+/*====================================================================*/
+
+static int _pcc_get_status(u_short sock, u_int *value)
+{
+	u_int status;
+	
+	status = pcc_get(sock,PCIRC);
+	*value = ((status & PCIRC_CDIN1) && (status & PCIRC_CDIN2))
+		? SS_DETECT : 0;
+		
+	status = pcc_get(sock,PCCR);
+
+#if 0
+	*value |= (status & PCCR_PCEN) ? SS_READY : 0;
+#else
+	*value |= SS_READY; /* XXX: always */
+#endif
+
+	status = pcc_get(sock,PCCSIGCR);
+	*value |= (status & PCCSIGCR_VEN) ? SS_POWERON : 0;
+
+	DEBUG(3, "m32r-pcc: GetStatus(%d) = %#4.4x\n", sock, *value);
+	return 0;
+} /* _get_status */
+
+/*====================================================================*/
+
+static int _pcc_get_socket(u_short sock, socket_state_t *state)
+{
+	DEBUG(3, "m32r-pcc: 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)
+{
+	u_long reg = 0;
+	
+	DEBUG(3, "m32r-pcc: SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "
+		  "io_irq %d, csc_mask %#2.2x)", sock, state->flags,
+		  state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
+
+	if (state->Vcc) {
+		/*
+		 * 5V only
+		 */
+		if (state->Vcc == 50) {
+			reg |= PCCSIGCR_VEN;
+		} else {
+			return -EINVAL;
+		}
+	}
+
+	if (state->flags & SS_RESET) {
+		DEBUG(3, ":RESET\n");
+		reg |= PCCSIGCR_CRST;
+	}
+	if (state->flags & SS_OUTPUT_ENA){
+		DEBUG(3, ":OUTPUT_ENA\n");
+		/* bit clear */
+	} else {
+		reg |= PCCSIGCR_SEN;
+	}
+
+	pcc_set(sock,PCCSIGCR,reg);
+
+#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_set_io_map(u_short sock, struct pccard_io_map *io)
+{
+	u_char map;
+	
+	DEBUG(3, "m32r-pcc: 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_set_mem_map(u_short sock, struct pccard_mem_map *mem)
+{
+
+	u_char map = mem->map;
+	u_long mode;
+	u_long addr;
+	pcc_socket_t *t = &socket[sock];
+#ifdef CHAOS_PCC_DEBUG
+#if 0
+	pcc_as_t last = t->current_space;
+#endif
+#endif
+
+	DEBUG(3, "m32r-pcc: 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);
+
+	/*
+	 * Enable again
+	 */
+	pcc_set(sock, PCCR, 1);
+
+#ifdef CHAOS_PCC_DEBUG
+#if 0
+	if (last != as_attr) {
+#else
+	if (1) {
+#endif
+
+		dummy_readbuf = *(u_char *)(addr + KSEG1);
+	}
+#endif
+
+	return 0;
+
+} /* _set_mem_map */
+
+#if 0 /* driver model ordering issue */
+/*======================================================================
+
+	Routines for accessing socket information and register dumps via
+	/proc/bus/pccard/...
+	
+======================================================================*/
+
+static ssize_t show_info(struct class_device *class_dev, char *buf)
+{
+	pcc_socket_t *s = container_of(class_dev, struct pcc_socket, 
+		socket.dev);
+
+	return sprintf(buf, "type:     %s\nbase addr:    0x%08lx\n",
+		pcc[s->type].name, s->base);
+}
+
+static ssize_t show_exca(struct class_device *class_dev, char *buf)
+{
+	/* FIXME */
+
+	return 0;
+}
+
+static CLASS_DEVICE_ATTR(info, S_IRUGO, show_info, NULL);
+static CLASS_DEVICE_ATTR(exca, S_IRUGO, show_exca, NULL);
+#endif
+
+/*====================================================================*/
+
+/* this is horribly ugly... proper locking needs to be done here at 
+ * some time... */
+#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)
+
+
+static int pcc_get_status(struct pcmcia_socket *s, u_int *value)
+{
+	unsigned int sock = container_of(s, struct pcc_socket, socket)->number;
+
+	if (socket[sock].flags & IS_ALIVE) {
+		*value = 0;
+		return -EINVAL;
+	}
+	LOCKED(_pcc_get_status(sock, value));
+}
+
+static int pcc_get_socket(struct pcmcia_socket *s, socket_state_t *state)
+{
+	unsigned int sock = container_of(s, struct pcc_socket, socket)->number;
+
+	if (socket[sock].flags & IS_ALIVE)
+		return -EINVAL;
+	LOCKED(_pcc_get_socket(sock, state));
+}
+
+static int pcc_set_socket(struct pcmcia_socket *s, socket_state_t *state)
+{
+	unsigned int sock = container_of(s, struct pcc_socket, socket)->number;
+
+	if (socket[sock].flags & IS_ALIVE)
+		return -EINVAL;
+
+	LOCKED(_pcc_set_socket(sock, state));
+}
+
+static int pcc_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io)
+{
+	unsigned int sock = container_of(s, struct pcc_socket, socket)->number;
+
+	if (socket[sock].flags & IS_ALIVE)
+		return -EINVAL;
+	LOCKED(_pcc_set_io_map(sock, io));
+}
+
+static int pcc_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *mem)
+{
+	unsigned int sock = container_of(s, struct pcc_socket, socket)->number;
+
+	if (socket[sock].flags & IS_ALIVE)
+		return -EINVAL;
+	LOCKED(_pcc_set_mem_map(sock, mem));
+}
+
+static int pcc_init(struct pcmcia_socket *s)
+{
+	DEBUG(4, "m32r-pcc: init call\n");
+	return 0;
+}
+
+static int pcc_suspend(struct pcmcia_socket *sock)
+{
+	return pcc_set_socket(sock, &dead_socket);
+}
+
+static struct pccard_operations pcc_operations = {
+	.init			= pcc_init,
+	.suspend		= pcc_suspend,
+	.get_status		= pcc_get_status,
+	.get_socket		= pcc_get_socket,
+	.set_socket		= pcc_set_socket,
+	.set_io_map		= pcc_set_io_map,
+	.set_mem_map		= pcc_set_mem_map,
+};
+
+/*====================================================================*/
+
+static int m32r_pcc_suspend(struct device *dev, u32 state, u32 level)
+{
+	int ret = 0;
+	if (level == SUSPEND_SAVE_STATE)
+		ret = pcmcia_socket_dev_suspend(dev, state);
+	return ret;
+}
+
+static int m32r_pcc_resume(struct device *dev, u32 level)
+{
+	int ret = 0;
+	if (level == RESUME_RESTORE_STATE)
+		ret = pcmcia_socket_dev_resume(dev);
+	return ret;
+}
+
+
+static struct device_driver pcc_driver = {
+	.name = "pcc",
+	.bus = &platform_bus_type,
+	.suspend = m32r_pcc_suspend,
+	.resume = m32r_pcc_resume,
+};
+
+static struct platform_device pcc_device = {
+	.name = "pcc",
+	.id = 0,
+};
+
+/*====================================================================*/
+
+static int __init init_m32r_pcc(void)
+{
+	int i, ret;
+
+	ret = driver_register(&pcc_driver);
+	if (ret)
+		return ret;
+
+	ret = platform_device_register(&pcc_device);
+	if (ret){
+		driver_unregister(&pcc_driver);
+		return ret;
+	}
+
+	printk(KERN_INFO "m32r PCC probe:\n");
+
+	pcc_sockets = 0;
+
+	add_pcc_socket(M32R_PCC0_BASE, PCC0_IRQ, M32R_PCC0_MAPBASE, 0x1000);
+
+#ifdef CONFIG_M32RPCC_SLOT2
+	add_pcc_socket(M32R_PCC1_BASE, PCC1_IRQ, M32R_PCC1_MAPBASE, 0x2000);
+#endif
+
+	if (pcc_sockets == 0) {
+		printk("socket is not found.\n");
+		platform_device_unregister(&pcc_device);
+		driver_unregister(&pcc_driver);
+		return -ENODEV;
+	}
+
+	/* Set up interrupt handler(s) */
+
+	for (i = 0 ; i < pcc_sockets ; i++) {
+		socket[i].socket.dev.dev = &pcc_device.dev;
+		socket[i].socket.ops = &pcc_operations;
+		socket[i].socket.owner = THIS_MODULE;
+		socket[i].number = i;
+		ret = pcmcia_register_socket(&socket[i].socket);
+		if (ret && i--) {
+			for (; i>= 0; i--)
+				pcmcia_unregister_socket(&socket[i].socket);
+			break;
+		}
+#if 0	/* driver model ordering issue */
+		class_device_create_file(&socket[i].socket.dev,
+					 &class_device_attr_info);
+		class_device_create_file(&socket[i].socket.dev,
+					 &class_device_attr_exca);
+#endif
+	}
+
+	/* 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)
+{
+	int i;
+
+	for (i = 0; i < pcc_sockets; i++)
+		pcmcia_unregister_socket(&socket[i].socket);
+
+	platform_device_unregister(&pcc_device);
+	if (poll_interval != 0)
+		del_timer_sync(&poll_timer);
+
+	driver_unregister(&pcc_driver);
+} /* exit_m32r_pcc */
+
+module_init(init_m32r_pcc);
+module_exit(exit_m32r_pcc);
+MODULE_LICENSE("Dual MPL/GPL");
+/*====================================================================*/
diff -ruN linux-2.6.8.1.org/arch/m32r/drivers/m32r_pcc.h linux-2.6.8.1/arch/m32r/drivers/m32r_pcc.h
--- linux-2.6.8.1.org/arch/m32r/drivers/m32r_pcc.h	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.8.1/arch/m32r/drivers/m32r_pcc.h	2003-09-09 10:15:02.000000000 +0900
@@ -0,0 +1,70 @@
+/*
+ *  $Id$
+ *
+ * Copyright (C) 2001 by Hiroyuki Kondo
+ */
+
+
+
+#define M32R_MAX_PCC	2
+
+/*
+ * 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))
+
diff -ruN linux-2.6.8.1.org/arch/m32r/drivers/m5.c linux-2.6.8.1/arch/m32r/drivers/m5.c
--- linux-2.6.8.1.org/arch/m32r/drivers/m5.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.8.1/arch/m32r/drivers/m5.c	2004-07-15 13:43:14.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 __user *)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.6.8.1.org/arch/m32r/drivers/m5.h linux-2.6.8.1/arch/m32r/drivers/m5.h
--- linux-2.6.8.1.org/arch/m32r/drivers/m5.h	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.8.1/arch/m32r/drivers/m5.h	2003-09-09 10:15:02.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.6.8.1.org/arch/m32r/drivers/m5drv.c linux-2.6.8.1/arch/m32r/drivers/m5drv.c
--- linux-2.6.8.1.org/arch/m32r/drivers/m5drv.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.8.1/arch/m32r/drivers/m5drv.c	2003-09-09 10:15:02.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$
+ */
+
+#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.6.8.1.org/arch/m32r/drivers/mappi_ne.c linux-2.6.8.1/arch/m32r/drivers/mappi_ne.c
--- linux-2.6.8.1.org/arch/m32r/drivers/mappi_ne.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.8.1/arch/m32r/drivers/mappi_ne.c	2004-04-01 16:29:44.000000000 +0900
@@ -0,0 +1,861 @@
+/* mappi_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[] =
+"Last modified Nov 1, 2000 by Paul Gortmaker\n";
+
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/isapnp.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+
+#include "8390.h"
+
+/* 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_CARD_ID('A','X','E',0x2011),
+		ISAPNP_VENDOR('A','X','E'), ISAPNP_FUNCTION(0x2011),
+		(long) "NetGear EA201" },
+	{	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 */
+
+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.  */
+
+static int __init do_ne_probe(struct net_device *dev)
+{
+	unsigned int base_addr = dev->base_addr;
+#ifndef MODULE
+	int orig_irq = dev->irq;
+#endif
+
+	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];
+		dev->irq = orig_irq;
+		if (ne_probe1(dev, ioaddr) == 0)
+			return 0;
+	}
+#endif
+
+	return -ENODEV;
+}
+
+static void cleanup_card(struct net_device *dev)
+{
+	struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv;
+	if (idev)
+		pnp_device_detach(idev);
+	free_irq(dev->irq, dev);
+	release_region(dev->base_addr, NE_IO_EXTENT);
+}
+
+struct net_device * __init ne_probe(int unit)
+{
+	struct net_device *dev = alloc_ei_netdev();
+	int err;
+
+	if (!dev)
+		return ERR_PTR(-ENOMEM);
+
+	sprintf(dev->name, "eth%d", unit);
+	netdev_boot_setup_check(dev);
+
+	err = do_ne_probe(dev);
+	if (err)
+		goto out;
+	err = register_netdev(dev);
+	if (err)
+		goto out1;
+	return dev;
+out1:
+	cleanup_card(dev);
+out:
+	free_netdev(dev);
+	return ERR_PTR(err);
+}
+
+static int __init ne_probe_isapnp(struct net_device *dev)
+{
+	int i;
+
+	for (i = 0; isapnp_clone_list[i].vendor != 0; i++) {
+		struct pnp_dev *idev = NULL;
+
+		while ((idev = pnp_find_dev(NULL,
+					    isapnp_clone_list[i].vendor,
+					    isapnp_clone_list[i].function,
+					    idev))) {
+			/* Avoid already found cards from previous calls */
+			if (pnp_device_attach(idev) < 0)
+				continue;
+			if (pnp_activate_dev(idev) < 0) {
+			      	pnp_device_detach(idev);
+			      	continue;
+			}
+			/* if no io and irq, search for next */
+			if (!pnp_port_valid(idev, 0) || !pnp_irq_valid(idev, 0)) {
+				pnp_device_detach(idev);
+				continue;
+			}
+			/* found it */
+			dev->base_addr = pnp_port_start(idev, 0);
+			dev->irq = pnp_irq(idev, 0);
+			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);
+				pnp_device_detach(idev);
+				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. */
+#ifdef CONFIG_PLAT_MAPPI
+		outb_p(0x4b, ioaddr + EN0_DCFG);
+#elif CONFIG_PLAT_OAKS32R
+		outb_p(0x48, ioaddr + EN0_DCFG);
+#else
+		outb_p(0x49, ioaddr + EN0_DCFG);
+#endif
+		start_page = NESM_START_PG;
+		stop_page = NESM_STOP_PG;
+	} else {
+		start_page = NE1SM_START_PG;
+		stop_page = NE1SM_STOP_PG;
+	}
+
+#if  defined(CONFIG_PLAT_MAPPI) || defined(CONFIG_PLAT_OAKS32R)
+	neX000 = ((SA_prom[14] == 0x57  &&  SA_prom[15] == 0x57) 
+		|| (SA_prom[14] == 0x42 && SA_prom[15] == 0x42));
+#else
+	neX000 = (SA_prom[14] == 0x57  &&  SA_prom[15] == 0x57);
+#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) {
+		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;
+	}
+
+	/* 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;
+	}
+
+	dev->base_addr = ioaddr;
+
+#ifdef CONFIG_PLAT_MAPPI
+	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;
+#ifdef CONFIG_PLAT_OAKS32R
+	ei_status.word16 = 0;
+#else
+	ei_status.word16 = (wordlength == 2);
+#endif
+
+	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:
+	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(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, "I/O base address(es),required");
+MODULE_PARM_DESC(irq, "IRQ number(s)");
+MODULE_PARM_DESC(bad, "Accept card(s) with bad signatures");
+MODULE_DESCRIPTION("NE1000/NE2000 ISA/PnP Ethernet driver");
+MODULE_LICENSE("GPL");
+
+/* 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 = alloc_ei_netdev();
+		if (!dev)
+			break;
+		dev->irq = irq[this_dev];
+		dev->mem_end = bad[this_dev];
+		dev->base_addr = io[this_dev];
+		if (do_ne_probe(dev) == 0) {
+			if (register_netdev(dev) == 0) {
+				dev_ne[found++] = dev;
+				continue;
+			}
+			cleanup_card(dev);
+		}
+		free_netdev(dev);
+		if (found)
+			break;
+		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;
+	}
+	if (found)
+		return 0;
+	return -ENODEV;
+}
+
+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) {
+			unregister_netdev(dev);
+			cleanup_card(dev);
+			free_netdev(dev);
+		}
+	}
+}
+#endif /* MODULE */
+
+
+/*
+ * 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.6.8.1.org/arch/m32r/drivers/smc91111.c linux-2.6.8.1/arch/m32r/drivers/smc91111.c
--- linux-2.6.8.1.org/arch/m32r/drivers/smc91111.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.8.1/arch/m32r/drivers/smc91111.c	2004-08-30 10:23:53.000000000 +0900
@@ -0,0 +1,3894 @@
+/*------------------------------------------------------------------------
+ . 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) || defined(CONFIG_PLAT_MAPPI2) || 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";
+
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#endif
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.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.
+*/
+struct net_device *smc_init(int unit);
+
+/*
+ . 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 irqreturn_t 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
+*/
+static inline 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.
+*/
+static inline 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);
+//	netif_wake_queue(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( int unit )
+ |   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:
+ |	pointer to net_device or ERR_PTR(error)
+ |
+ ---------------------------------------------------------------------------
+*/
+static int io;
+static int irq;
+static int ifport;
+
+struct net_device * __init smc_init(int unit)
+{
+	struct net_device *dev = alloc_etherdev(sizeof(struct smc_local));
+	unsigned int *port;
+	int err = 0;
+
+	if (!dev)
+		return ERR_PTR(-ENODEV);
+
+	if (unit >= 0) {
+	      sprintf(dev->name, "eth%d", unit);
+	      netdev_boot_setup_check(dev);
+	      io = dev->base_addr;
+	      irq = dev->irq;
+	}
+
+#ifdef MODULE
+	SET_MODULE_OWNER (dev);
+#endif
+	if (io > 0x1ff) {	/* Check a single specified location. */
+		err = smc_probe(dev, io);
+	} else if (io != 0) {	/* Don't probe at all. */
+		err = -ENXIO;
+	} else {
+		for (port = smc_portlist; *port; port++) {
+			if (smc_probe(dev, *port) == 0)
+				break;
+		}
+		if (!*port)
+			err = -ENODEV;
+	}
+	if (err)
+		goto out;
+	err = register_netdev(dev);
+	if (err)
+		goto out1;
+	return dev;
+out1:
+	free_irq(dev->irq, dev);
+	release_region(dev->base_addr, SMC_IO_EXTENT);
+out:
+	free_netdev(dev);
+	return ERR_PTR(err);
+}
+
+
+/*-------------------------------------------------------------------------
+ |
+ | 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;
+
+	dev->irq = irq;
+	dev->if_port = ifport;
+
+	/* 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;
+
+	/*
+ 	 . 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_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] );
+
+	/* set the private data to zero by default */
+	memset(dev->priv, 0, sizeof(struct smc_local));
+
+	/* 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);
+		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 irqreturn_t 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;
+	int handled = 0;
+
+	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 IRQ_RETVAL(handled);
+	}
+
+/* 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;
+
+		handled = 1;
+
+		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 IRQ_RETVAL(handled);
+}
+
+/*-------------------------------------------------------------
+ .
+ . 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 inline 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 inline 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 nowait = 0;
+
+MODULE_PARM(io, "i");
+MODULE_PARM(irq, "i");
+MODULE_PARM(nowait, "i");
+
+/*------------------------------------------------------------
+ . Module initialization function
+ .-------------------------------------------------------------*/
+int init_module(void)
+{
+	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 = smc_init(-1);
+	if (IS_ERR(devSMC91111))
+		return PTR_ERR(devSMC91111);
+
+	return 0;
+}
+
+/*------------------------------------------------------------
+ . Cleanup when module is removed with rmmod
+ .-------------------------------------------------------------*/
+void cleanup_module(void)
+{
+	unregister_netdev(devSMC91111);
+	free_irq(devSMC91111->irq, devSMC91111);
+	release_region(devSMC91111->base_addr, SMC_IO_EXTENT);
+	free_netdev(devSMC91111);
+}
+
+#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, loff_t *ppos)
+{
+	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, ppos)) != 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 = sizeof lp->ctl_swfdup;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// EPHLOOP
+	++i;
+	ct[i].ctl_name = CTL_SMC_EPHLOOP;
+	ct[i].procname = "ephloop";
+	ct[i].data = (void*)&(lp->ctl_ephloop);
+	ct[i].maxlen = sizeof lp->ctl_ephloop;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// MIIOP
+	++i;
+	ct[i].ctl_name = CTL_SMC_MIIOP;
+	ct[i].procname = "miiop";
+	ct[i].data = (void*)&(lp->ctl_miiop);
+	ct[i].maxlen = sizeof lp->ctl_miiop;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// AUTONEG
+	++i;
+	ct[i].ctl_name = CTL_SMC_AUTONEG;
+	ct[i].procname = "autoneg";
+	ct[i].data = (void*)&(lp->ctl_autoneg);
+	ct[i].maxlen = sizeof lp->ctl_autoneg;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// RFDUPLX
+	++i;
+	ct[i].ctl_name = CTL_SMC_RFDUPLX;
+	ct[i].procname = "rfduplx";
+	ct[i].data = (void*)&(lp->ctl_rfduplx);
+	ct[i].maxlen = sizeof lp->ctl_rfduplx;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// RSPEED
+	++i;
+	ct[i].ctl_name = CTL_SMC_RSPEED;
+	ct[i].procname = "rspeed";
+	ct[i].data = (void*)&(lp->ctl_rspeed);
+	ct[i].maxlen = sizeof lp->ctl_rspeed;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// AFDUPLX
+	++i;
+	ct[i].ctl_name = CTL_SMC_AFDUPLX;
+	ct[i].procname = "afduplx";
+	ct[i].data = (void*)&(lp->ctl_afduplx);
+	ct[i].maxlen = sizeof lp->ctl_afduplx;
+	ct[i].mode = 0444; // Read only
+
+	// ASPEED
+	++i;
+	ct[i].ctl_name = CTL_SMC_ASPEED;
+	ct[i].procname = "aspeed";
+	ct[i].data = (void*)&(lp->ctl_aspeed);
+	ct[i].maxlen = sizeof lp->ctl_aspeed;
+	ct[i].mode = 0444; // Read only
+
+	// LNKFAIL
+	++i;
+	ct[i].ctl_name = CTL_SMC_LNKFAIL;
+	ct[i].procname = "lnkfail";
+	ct[i].data = (void*)&(lp->ctl_lnkfail);
+	ct[i].maxlen = sizeof lp->ctl_lnkfail;
+	ct[i].mode = 0444; // Read only
+
+	// FORCOL
+	++i;
+	ct[i].ctl_name = CTL_SMC_FORCOL;
+	ct[i].procname = "forcol";
+	ct[i].data = (void*)&(lp->ctl_forcol);
+	ct[i].maxlen = sizeof lp->ctl_forcol;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// FILTCAR
+	++i;
+	ct[i].ctl_name = CTL_SMC_FILTCAR;
+	ct[i].procname = "filtcar";
+	ct[i].data = (void*)&(lp->ctl_filtcar);
+	ct[i].maxlen = sizeof lp->ctl_filtcar;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// FREEMEM
+	++i;
+	ct[i].ctl_name = CTL_SMC_FREEMEM;
+	ct[i].procname = "freemem";
+	ct[i].data = (void*)&(lp->ctl_freemem);
+	ct[i].maxlen = sizeof lp->ctl_freemem;
+	ct[i].mode = 0444; // Read only
+
+	// TOTMEM
+	++i;
+	ct[i].ctl_name = CTL_SMC_TOTMEM;
+	ct[i].procname = "totmem";
+	ct[i].data = (void*)&(lp->ctl_totmem);
+	ct[i].maxlen = sizeof lp->ctl_totmem;
+	ct[i].mode = 0444; // Read only
+
+	// LEDA
+	++i;
+	ct[i].ctl_name = CTL_SMC_LEDA;
+	ct[i].procname = "leda";
+	ct[i].data = (void*)&(lp->ctl_leda);
+	ct[i].maxlen = sizeof lp->ctl_leda;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// LEDB
+	++i;
+	ct[i].ctl_name = CTL_SMC_LEDB;
+	ct[i].procname = "ledb";
+	ct[i].data = (void*)&(lp->ctl_ledb);
+	ct[i].maxlen = sizeof lp->ctl_ledb;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// CHIPREV
+	++i;
+	ct[i].ctl_name = CTL_SMC_CHIPREV;
+	ct[i].procname = "chiprev";
+	ct[i].data = (void*)&(lp->ctl_chiprev);
+	ct[i].maxlen = sizeof lp->ctl_chiprev;
+	ct[i].mode = 0444; // Read only
+
+#ifdef SMC_DEBUG
+	// REG_BSR
+	++i;
+	ct[i].ctl_name = CTL_SMC_REG_BSR;
+	ct[i].procname = "reg_bsr";
+	ct[i].data = (void*)&(lp->ctl_reg_bsr);
+	ct[i].maxlen = sizeof lp->ctl_reg_bsr;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// REG_TCR
+	++i;
+	ct[i].ctl_name = CTL_SMC_REG_TCR;
+	ct[i].procname = "reg_tcr";
+	ct[i].data = (void*)&(lp->ctl_reg_tcr);
+	ct[i].maxlen = sizeof lp->ctl_reg_tcr;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// REG_ESR
+	++i;
+	ct[i].ctl_name = CTL_SMC_REG_ESR;
+	ct[i].procname = "reg_esr";
+	ct[i].data = (void*)&(lp->ctl_reg_esr);
+	ct[i].maxlen = sizeof lp->ctl_reg_esr;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// REG_RCR
+	++i;
+	ct[i].ctl_name = CTL_SMC_REG_RCR;
+	ct[i].procname = "reg_rcr";
+	ct[i].data = (void*)&(lp->ctl_reg_rcr);
+	ct[i].maxlen = sizeof lp->ctl_reg_rcr;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// REG_CTRR
+	++i;
+	ct[i].ctl_name = CTL_SMC_REG_CTRR;
+	ct[i].procname = "reg_ctrr";
+	ct[i].data = (void*)&(lp->ctl_reg_ctrr);
+	ct[i].maxlen = sizeof lp->ctl_reg_ctrr;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// REG_MIR
+	++i;
+	ct[i].ctl_name = CTL_SMC_REG_MIR;
+	ct[i].procname = "reg_mir";
+	ct[i].data = (void*)&(lp->ctl_reg_mir);
+	ct[i].maxlen = sizeof lp->ctl_reg_mir;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// REG_RPCR
+	++i;
+	ct[i].ctl_name = CTL_SMC_REG_RPCR;
+	ct[i].procname = "reg_rpcr";
+	ct[i].data = (void*)&(lp->ctl_reg_rpcr);
+	ct[i].maxlen = sizeof lp->ctl_reg_rpcr;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// REG_CFGR
+	++i;
+	ct[i].ctl_name = CTL_SMC_REG_CFGR;
+	ct[i].procname = "reg_cfgr";
+	ct[i].data = (void*)&(lp->ctl_reg_cfgr);
+	ct[i].maxlen = sizeof lp->ctl_reg_cfgr;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// REG_BAR
+	++i;
+	ct[i].ctl_name = CTL_SMC_REG_BAR;
+	ct[i].procname = "reg_bar";
+	ct[i].data = (void*)&(lp->ctl_reg_bar);
+	ct[i].maxlen = sizeof lp->ctl_reg_bar;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// REG_IAR0
+	++i;
+	ct[i].ctl_name = CTL_SMC_REG_IAR0;
+	ct[i].procname = "reg_iar0";
+	ct[i].data = (void*)&(lp->ctl_reg_iar0);
+	ct[i].maxlen = sizeof lp->ctl_reg_iar0;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// REG_IAR1
+	++i;
+	ct[i].ctl_name = CTL_SMC_REG_IAR1;
+	ct[i].procname = "reg_iar1";
+	ct[i].data = (void*)&(lp->ctl_reg_iar1);
+	ct[i].maxlen = sizeof lp->ctl_reg_iar1;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// REG_IAR2
+	++i;
+	ct[i].ctl_name = CTL_SMC_REG_IAR2;
+	ct[i].procname = "reg_iar2";
+	ct[i].data = (void*)&(lp->ctl_reg_iar2);
+	ct[i].maxlen = sizeof lp->ctl_reg_iar2;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// REG_GPR
+	++i;
+	ct[i].ctl_name = CTL_SMC_REG_GPR;
+	ct[i].procname = "reg_gpr";
+	ct[i].data = (void*)&(lp->ctl_reg_gpr);
+	ct[i].maxlen = sizeof lp->ctl_reg_gpr;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// REG_CTLR
+	++i;
+	ct[i].ctl_name = CTL_SMC_REG_CTLR;
+	ct[i].procname = "reg_ctlr";
+	ct[i].data = (void*)&(lp->ctl_reg_ctlr);
+	ct[i].maxlen = sizeof lp->ctl_reg_ctlr;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// REG_MCR
+	++i;
+	ct[i].ctl_name = CTL_SMC_REG_MCR;
+	ct[i].procname = "reg_mcr";
+	ct[i].data = (void*)&(lp->ctl_reg_mcr);
+	ct[i].maxlen = sizeof lp->ctl_reg_mcr;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// REG_PNR
+	++i;
+	ct[i].ctl_name = CTL_SMC_REG_PNR;
+	ct[i].procname = "reg_pnr";
+	ct[i].data = (void*)&(lp->ctl_reg_pnr);
+	ct[i].maxlen = sizeof lp->ctl_reg_pnr;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// REG_FPR
+	++i;
+	ct[i].ctl_name = CTL_SMC_REG_FPR;
+	ct[i].procname = "reg_fpr";
+	ct[i].data = (void*)&(lp->ctl_reg_fpr);
+	ct[i].maxlen = sizeof lp->ctl_reg_fpr;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// REG_PTR
+	++i;
+	ct[i].ctl_name = CTL_SMC_REG_PTR;
+	ct[i].procname = "reg_ptr";
+	ct[i].data = (void*)&(lp->ctl_reg_ptr);
+	ct[i].maxlen = sizeof lp->ctl_reg_ptr;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// REG_DR
+	++i;
+	ct[i].ctl_name = CTL_SMC_REG_DR;
+	ct[i].procname = "reg_dr";
+	ct[i].data = (void*)&(lp->ctl_reg_dr);
+	ct[i].maxlen = sizeof lp->ctl_reg_dr;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// REG_ISR
+	++i;
+	ct[i].ctl_name = CTL_SMC_REG_ISR;
+	ct[i].procname = "reg_isr";
+	ct[i].data = (void*)&(lp->ctl_reg_isr);
+	ct[i].maxlen = sizeof lp->ctl_reg_isr;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// REG_MTR1
+	++i;
+	ct[i].ctl_name = CTL_SMC_REG_MTR1;
+	ct[i].procname = "reg_mtr1";
+	ct[i].data = (void*)&(lp->ctl_reg_mtr1);
+	ct[i].maxlen = sizeof lp->ctl_reg_mtr1;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// REG_MTR2
+	++i;
+	ct[i].ctl_name = CTL_SMC_REG_MTR2;
+	ct[i].procname = "reg_mtr2";
+	ct[i].data = (void*)&(lp->ctl_reg_mtr2);
+	ct[i].maxlen = sizeof lp->ctl_reg_mtr2;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// REG_MTR3
+	++i;
+	ct[i].ctl_name = CTL_SMC_REG_MTR3;
+	ct[i].procname = "reg_mtr3";
+	ct[i].data = (void*)&(lp->ctl_reg_mtr3);
+	ct[i].maxlen = sizeof lp->ctl_reg_mtr3;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// REG_MTR4
+	++i;
+	ct[i].ctl_name = CTL_SMC_REG_MTR4;
+	ct[i].procname = "reg_mtr4";
+	ct[i].data = (void*)&(lp->ctl_reg_mtr4);
+	ct[i].maxlen = sizeof lp->ctl_reg_mtr4;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// REG_MIIR
+	++i;
+	ct[i].ctl_name = CTL_SMC_REG_MIIR;
+	ct[i].procname = "reg_miir";
+	ct[i].data = (void*)&(lp->ctl_reg_miir);
+	ct[i].maxlen = sizeof lp->ctl_reg_miir;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// REG_REVR
+	++i;
+	ct[i].ctl_name = CTL_SMC_REG_REVR;
+	ct[i].procname = "reg_revr";
+	ct[i].data = (void*)&(lp->ctl_reg_revr);
+	ct[i].maxlen = sizeof lp->ctl_reg_revr;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// REG_ERCVR
+	++i;
+	ct[i].ctl_name = CTL_SMC_REG_ERCVR;
+	ct[i].procname = "reg_ercvr";
+	ct[i].data = (void*)&(lp->ctl_reg_ercvr);
+	ct[i].maxlen = sizeof lp->ctl_reg_ercvr;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// REG_EXTR
+	++i;
+	ct[i].ctl_name = CTL_SMC_REG_EXTR;
+	ct[i].procname = "reg_extr";
+	ct[i].data = (void*)&(lp->ctl_reg_extr);
+	ct[i].maxlen = sizeof lp->ctl_reg_extr;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// PHY Control
+	++i;
+	ct[i].ctl_name = CTL_SMC_PHY_CTRL;
+	ct[i].procname = "phy_ctrl";
+	ct[i].data = (void*)&(lp->ctl_phy_ctrl);
+	ct[i].maxlen = sizeof lp->ctl_phy_ctrl;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// PHY Status
+	++i;
+	ct[i].ctl_name = CTL_SMC_PHY_STAT;
+	ct[i].procname = "phy_stat";
+	ct[i].data = (void*)&(lp->ctl_phy_stat);
+	ct[i].maxlen = sizeof lp->ctl_phy_stat;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// PHY ID1
+	++i;
+	ct[i].ctl_name = CTL_SMC_PHY_ID1;
+	ct[i].procname = "phy_id1";
+	ct[i].data = (void*)&(lp->ctl_phy_id1);
+	ct[i].maxlen = sizeof lp->ctl_phy_id1;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// PHY ID2
+	++i;
+	ct[i].ctl_name = CTL_SMC_PHY_ID2;
+	ct[i].procname = "phy_id2";
+	ct[i].data = (void*)&(lp->ctl_phy_id2);
+	ct[i].maxlen = sizeof lp->ctl_phy_id2;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// PHY Advertise Capabilities
+	++i;
+	ct[i].ctl_name = CTL_SMC_PHY_ADC;
+	ct[i].procname = "phy_adc";
+	ct[i].data = (void*)&(lp->ctl_phy_adc);
+	ct[i].maxlen = sizeof lp->ctl_phy_adc;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// PHY Remote Capabilities
+	++i;
+	ct[i].ctl_name = CTL_SMC_PHY_REMC;
+	ct[i].procname = "phy_remc";
+	ct[i].data = (void*)&(lp->ctl_phy_remc);
+	ct[i].maxlen = sizeof lp->ctl_phy_remc;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// PHY Configuration 1
+	++i;
+	ct[i].ctl_name = CTL_SMC_PHY_CFG1;
+	ct[i].procname = "phy_cfg1";
+	ct[i].data = (void*)&(lp->ctl_phy_cfg1);
+	ct[i].maxlen = sizeof lp->ctl_phy_cfg1;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// PHY Configuration 2
+	++i;
+	ct[i].ctl_name = CTL_SMC_PHY_CFG2;
+	ct[i].procname = "phy_cfg2";
+	ct[i].data = (void*)&(lp->ctl_phy_cfg2);
+	ct[i].maxlen = sizeof lp->ctl_phy_cfg2;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// PHY Interrupt/Status Output
+	++i;
+	ct[i].ctl_name = CTL_SMC_PHY_INT;
+	ct[i].procname = "phy_int";
+	ct[i].data = (void*)&(lp->ctl_phy_int);
+	ct[i].maxlen = sizeof lp->ctl_phy_int;
+	ct[i].mode = 0644; // Read by all, write by root
+
+	// PHY Interrupt/Status Mask
+	++i;
+	ct[i].ctl_name = CTL_SMC_PHY_MASK;
+	ct[i].procname = "phy_mask";
+	ct[i].data = (void*)&(lp->ctl_phy_mask);
+	ct[i].maxlen = sizeof lp->ctl_phy_mask;
+	ct[i].mode = 0644; // Read by all, write by root
+
+#endif // SMC_DEBUG
+
+	// Register /proc/sys/dev/ethX
+	lp->sysctl_header = register_sysctl_table(lp->root_table, 1);
+}
+
+
+/*------------------------------------------------------------
+ . Sysctl unregistration when driver is closed
+ .-------------------------------------------------------------*/
+static void smc_sysctl_unregister(struct net_device *dev)
+{
+	struct smc_local *lp = (struct smc_local *)dev->priv;
+
+	unregister_sysctl_table(lp->sysctl_header);
+}
+
+#endif /* endif CONFIG_SYSCTL */
+
+
+//---PHY CONTROL AND CONFIGURATION-----------------------------------------
+
+#if (SMC_DEBUG > 2 )
+
+/*------------------------------------------------------------
+ . Debugging function for viewing MII Management serial bitstream
+ .-------------------------------------------------------------*/
+static void smc_dump_mii_stream(byte* bits, int size)
+{
+	int i;
+
+	printk("BIT#:");
+	for (i = 0; i < size; ++i)
+		{
+		printk("%d", i%10);
+		}
+
+	printk("\nMDOE:");
+	for (i = 0; i < size; ++i)
+		{
+		if (bits[i] & MII_MDOE)
+			printk("1");
+		else
+			printk("0");
+		}
+
+	printk("\nMDO :");
+	for (i = 0; i < size; ++i)
+		{
+		if (bits[i] & MII_MDO)
+			printk("1");
+		else
+			printk("0");
+		}
+
+	printk("\nMDI :");
+	for (i = 0; i < size; ++i)
+		{
+		if (bits[i] & MII_MDI)
+			printk("1");
+		else
+			printk("0");
+		}
+
+	printk("\n");
+}
+#endif
+
+/*------------------------------------------------------------
+ . Reads a register from the MII Management serial interface
+ .-------------------------------------------------------------*/
+static word smc_read_phy_register(int ioaddr, byte phyaddr, byte phyreg)
+{
+	int oldBank;
+	int i;
+	byte mask;
+	word mii_reg;
+	byte bits[64];
+	int clk_idx = 0;
+	int input_idx;
+	word phydata;
+
+	// 32 consecutive ones on MDO to establish sync
+	for (i = 0; i < 32; ++i)
+		bits[clk_idx++] = MII_MDOE | MII_MDO;
+
+	// Start code <01>
+	bits[clk_idx++] = MII_MDOE;
+	bits[clk_idx++] = MII_MDOE | MII_MDO;
+
+	// Read command <10>
+	bits[clk_idx++] = MII_MDOE | MII_MDO;
+	bits[clk_idx++] = MII_MDOE;
+
+	// Output the PHY address, msb first
+	mask = (byte)0x10;
+	for (i = 0; i < 5; ++i)
+		{
+		if (phyaddr & mask)
+			bits[clk_idx++] = MII_MDOE | MII_MDO;
+		else
+			bits[clk_idx++] = MII_MDOE;
+
+		// Shift to next lowest bit
+		mask >>= 1;
+		}
+
+	// Output the phy register number, msb first
+	mask = (byte)0x10;
+	for (i = 0; i < 5; ++i)
+		{
+		if (phyreg & mask)
+			bits[clk_idx++] = MII_MDOE | MII_MDO;
+		else
+			bits[clk_idx++] = MII_MDOE;
+
+		// Shift to next lowest bit
+		mask >>= 1;
+		}
+
+	// Tristate and turnaround (2 bit times)
+	bits[clk_idx++] = 0;
+	//bits[clk_idx++] = 0;
+
+	// Input starts at this bit time
+	input_idx = clk_idx;
+
+	// Will input 16 bits
+	for (i = 0; i < 16; ++i)
+		bits[clk_idx++] = 0;
+
+	// Final clock bit
+	bits[clk_idx++] = 0;
+
+	// Save the current bank
+	oldBank = inw( ioaddr+BANK_SELECT );
+
+	// Select bank 3
+	SMC_SELECT_BANK( 3 );
+
+	// Get the current MII register value
+	mii_reg = inw( ioaddr+MII_REG );
+
+	// Turn off all MII Interface bits
+	mii_reg &= ~(MII_MDOE|MII_MCLK|MII_MDI|MII_MDO);
+
+	// Clock all 64 cycles
+	for (i = 0; i < sizeof bits; ++i)
+		{
+		// Clock Low - output data
+		outw( mii_reg | bits[i], ioaddr+MII_REG );
+		udelay(50);
+
+
+		// Clock Hi - input data
+		outw( mii_reg | bits[i] | MII_MCLK, ioaddr+MII_REG );
+		udelay(50);
+		bits[i] |= inw( ioaddr+MII_REG ) & MII_MDI;
+		}
+
+	// Return to idle state
+	// Set clock to low, data to low, and output tristated
+	outw( mii_reg, ioaddr+MII_REG );
+	udelay(50);
+
+	// Restore original bank select
+	SMC_SELECT_BANK( oldBank );
+
+	// Recover input data
+	phydata = 0;
+	for (i = 0; i < 16; ++i)
+		{
+		phydata <<= 1;
+
+		if (bits[input_idx++] & MII_MDI)
+			phydata |= 0x0001;
+		}
+
+#if (SMC_DEBUG > 2 )
+	printk("smc_read_phy_register(): phyaddr=%x,phyreg=%x,phydata=%x\n",
+		phyaddr, phyreg, phydata);
+	smc_dump_mii_stream(bits, sizeof bits);
+#endif
+
+	return(phydata);
+}
+
+
+/*------------------------------------------------------------
+ . Writes a register to the MII Management serial interface
+ .-------------------------------------------------------------*/
+static void smc_write_phy_register(int ioaddr,
+	byte phyaddr, byte phyreg, word phydata)
+{
+	int oldBank;
+	int i;
+	word mask;
+	word mii_reg;
+	byte bits[65];
+	int clk_idx = 0;
+
+	// 32 consecutive ones on MDO to establish sync
+	for (i = 0; i < 32; ++i)
+		bits[clk_idx++] = MII_MDOE | MII_MDO;
+
+	// Start code <01>
+	bits[clk_idx++] = MII_MDOE;
+	bits[clk_idx++] = MII_MDOE | MII_MDO;
+
+	// Write command <01>
+	bits[clk_idx++] = MII_MDOE;
+	bits[clk_idx++] = MII_MDOE | MII_MDO;
+
+	// Output the PHY address, msb first
+	mask = (byte)0x10;
+	for (i = 0; i < 5; ++i)
+		{
+		if (phyaddr & mask)
+			bits[clk_idx++] = MII_MDOE | MII_MDO;
+		else
+			bits[clk_idx++] = MII_MDOE;
+
+		// Shift to next lowest bit
+		mask >>= 1;
+		}
+
+	// Output the phy register number, msb first
+	mask = (byte)0x10;
+	for (i = 0; i < 5; ++i)
+		{
+		if (phyreg & mask)
+			bits[clk_idx++] = MII_MDOE | MII_MDO;
+		else
+			bits[clk_idx++] = MII_MDOE;
+
+		// Shift to next lowest bit
+		mask >>= 1;
+		}
+
+	// Tristate and turnaround (2 bit times)
+	bits[clk_idx++] = 0;
+	bits[clk_idx++] = 0;
+
+	// Write out 16 bits of data, msb first
+	mask = 0x8000;
+	for (i = 0; i < 16; ++i)
+		{
+		if (phydata & mask)
+			bits[clk_idx++] = MII_MDOE | MII_MDO;
+		else
+			bits[clk_idx++] = MII_MDOE;
+
+		// Shift to next lowest bit
+		mask >>= 1;
+		}
+
+	// Final clock bit (tristate)
+	bits[clk_idx++] = 0;
+
+	// Save the current bank
+	oldBank = inw( ioaddr+BANK_SELECT );
+
+	// Select bank 3
+	SMC_SELECT_BANK( 3 );
+
+	// Get the current MII register value
+	mii_reg = inw( ioaddr+MII_REG );
+
+	// Turn off all MII Interface bits
+	mii_reg &= ~(MII_MDOE|MII_MCLK|MII_MDI|MII_MDO);
+
+	// Clock all cycles
+	for (i = 0; i < sizeof bits; ++i)
+		{
+		// Clock Low - output data
+		outw( mii_reg | bits[i], ioaddr+MII_REG );
+		udelay(50);
+
+
+		// Clock Hi - input data
+		outw( mii_reg | bits[i] | MII_MCLK, ioaddr+MII_REG );
+		udelay(50);
+		bits[i] |= inw( ioaddr+MII_REG ) & MII_MDI;
+		}
+
+	// Return to idle state
+	// Set clock to low, data to low, and output tristated
+	outw( mii_reg, ioaddr+MII_REG );
+	udelay(50);
+
+	// Restore original bank select
+	SMC_SELECT_BANK( oldBank );
+
+#if (SMC_DEBUG > 2 )
+	printk("smc_write_phy_register(): phyaddr=%x,phyreg=%x,phydata=%x\n",
+		phyaddr, phyreg, phydata);
+	smc_dump_mii_stream(bits, sizeof bits);
+#endif
+}
+
+
+/*------------------------------------------------------------
+ . Finds and reports the PHY address
+ .-------------------------------------------------------------*/
+static int smc_detect_phy(struct net_device* dev)
+{
+	struct smc_local *lp = (struct smc_local *)dev->priv;
+	int ioaddr = dev->base_addr;
+	word phy_id1 = 0;
+	word phy_id2 = 0;
+	int phyaddr;
+	int found = 0;
+
+	PRINTK3("%s:smc_detect_phy()\n", dev->name);
+
+	// Scan all 32 PHY addresses if necessary
+	for (phyaddr = 0; phyaddr < 32; ++phyaddr)
+		{
+		// Read the PHY identifiers
+		phy_id1  = smc_read_phy_register(ioaddr, phyaddr, PHY_ID1_REG);
+		phy_id2  = smc_read_phy_register(ioaddr, phyaddr, PHY_ID2_REG);
+
+		PRINTK3("%s: phy_id1=%x, phy_id2=%x\n",
+			dev->name, phy_id1, phy_id2);
+
+		// Make sure it is a valid identifier
+		if ((phy_id2 > 0x0000) && (phy_id2 < 0xffff) &&
+		    (phy_id1 > 0x0000) && (phy_id1 < 0xffff))
+			{
+			if ((phy_id1 != 0x8000) && (phy_id2 != 0x8000))
+				{
+				// Save the PHY's address
+				lp->phyaddr = phyaddr;
+				found = 1;
+				break;
+				}
+			}
+		}
+
+	if (!found)
+		{
+		PRINTK("%s: No PHY found\n", dev->name);
+		return(0);
+		}
+
+	// Set the PHY type
+	if ( (phy_id1 == 0x0016) && ((phy_id2 & 0xFFF0) == 0xF840 ) )
+		{
+		lp->phytype = PHY_LAN83C183;
+		PRINTK("%s: PHY=LAN83C183 (LAN91C111 Internal)\n", dev->name);
+		}
+
+	if ( (phy_id1 == 0x0282) && ((phy_id2 & 0xFFF0) == 0x1C50) )
+		{
+		lp->phytype = PHY_LAN83C180;
+		PRINTK("%s: PHY=LAN83C180\n", dev->name);
+		}
+
+	return(1);
+}
+
+/*------------------------------------------------------------
+ . Waits the specified number of milliseconds - kernel friendly
+ .-------------------------------------------------------------*/
+static void smc_wait_ms(unsigned int ms)
+{
+
+	if (!in_interrupt())
+		{
+		current->state = TASK_UNINTERRUPTIBLE;
+		schedule_timeout(1 + ms * HZ / 1000);
+		}
+	else
+		{
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(1 + ms * HZ / 1000);
+		current->state = TASK_RUNNING;
+		}
+}
+
+/*------------------------------------------------------------
+ . Sets the PHY to a configuration as determined by the user
+ .-------------------------------------------------------------*/
+static int smc_phy_fixed(struct net_device* dev)
+{
+	int ioaddr = dev->base_addr;
+	struct smc_local *lp = (struct smc_local *)dev->priv;
+	byte phyaddr = lp->phyaddr;
+	word my_fixed_caps;
+	word cfg1;
+
+	PRINTK3("%s:smc_phy_fixed()\n", dev->name);
+
+	// Enter Link Disable state
+	cfg1 = smc_read_phy_register(ioaddr, phyaddr, PHY_CFG1_REG);
+	cfg1 |= PHY_CFG1_LNKDIS;
+	smc_write_phy_register(ioaddr, phyaddr, PHY_CFG1_REG, cfg1);
+
+	// Set our fixed capabilities
+	// Disable auto-negotiation
+	my_fixed_caps = 0;
+
+	if (lp->ctl_rfduplx)
+		my_fixed_caps |= PHY_CNTL_DPLX;
+
+	if (lp->ctl_rspeed == 100)
+		my_fixed_caps |= PHY_CNTL_SPEED;
+
+	// Write our capabilities to the phy control register
+	smc_write_phy_register(ioaddr, phyaddr, PHY_CNTL_REG, my_fixed_caps);
+
+	// Re-Configure the Receive/Phy Control register
+	outw( lp->rpc_cur_mode, ioaddr + RPC_REG );
+
+	// Success
+	return(1);
+}
+
+
+/*------------------------------------------------------------
+ . Configures the specified PHY using Autonegotiation. Calls
+ . smc_phy_fixed() if the user has requested a certain config.
+ .-------------------------------------------------------------*/
+static void smc_phy_configure(struct net_device* dev)
+{
+	int ioaddr = dev->base_addr;
+	struct smc_local *lp = (struct smc_local *)dev->priv;
+	int timeout;
+	byte phyaddr;
+	word my_phy_caps; // My PHY capabilities
+	word my_ad_caps; // My Advertised capabilities
+	word status;
+	int failed = 0;
+
+	PRINTK3("%s:smc_program_phy()\n", dev->name);
+
+	// Set the blocking flag
+	lp->autoneg_active = 1;
+
+	// Find the address and type of our phy
+	if (!smc_detect_phy(dev))
+		{
+		goto smc_phy_configure_exit;
+		}
+
+	// Get the detected phy address
+	phyaddr = lp->phyaddr;
+
+	// Reset the PHY, setting all other bits to zero
+	smc_write_phy_register(ioaddr, phyaddr, PHY_CNTL_REG, PHY_CNTL_RST);
+
+	// Wait for the reset to complete, or time out
+	timeout = 6; // Wait up to 3 seconds
+	while (timeout--)
+		{
+		if (!(smc_read_phy_register(ioaddr, phyaddr, PHY_CNTL_REG)
+		    & PHY_CNTL_RST))
+			{
+			// reset complete
+			break;
+			}
+
+		smc_wait_ms(500); // wait 500 millisecs
+		if (signal_pending(current)) // Exit anyway if signaled
+			{
+			PRINTK2("%s:PHY reset interrupted by signal\n",
+				dev->name);
+			timeout = 0;
+			break;
+			}
+		}
+
+	if (timeout < 1)
+		{
+		PRINTK2("%s:PHY reset timed out\n", dev->name);
+		goto smc_phy_configure_exit;
+		}
+
+	// Read PHY Register 18, Status Output
+	lp->lastPhy18 = smc_read_phy_register(ioaddr, phyaddr, PHY_INT_REG);
+
+	// Enable PHY Interrupts (for register 18)
+	// Interrupts listed here are disabled
+	smc_write_phy_register(ioaddr, phyaddr, PHY_MASK_REG, 
+		PHY_INT_LOSSSYNC | PHY_INT_CWRD | PHY_INT_SSD |
+		PHY_INT_ESD | PHY_INT_RPOL | PHY_INT_JAB |
+		PHY_INT_SPDDET | PHY_INT_DPLXDET);
+
+	/* Configure the Receive/Phy Control register */
+	SMC_SELECT_BANK( 0 );
+	outw( lp->rpc_cur_mode, ioaddr + RPC_REG );
+
+	// Copy our capabilities from PHY_STAT_REG to PHY_AD_REG
+	my_phy_caps = smc_read_phy_register(ioaddr, phyaddr, PHY_STAT_REG);
+	my_ad_caps  = PHY_AD_CSMA; // I am CSMA capable
+
+	if (my_phy_caps & PHY_STAT_CAP_T4)
+		my_ad_caps |= PHY_AD_T4;
+
+	if (my_phy_caps & PHY_STAT_CAP_TXF)
+		my_ad_caps |= PHY_AD_TX_FDX;
+
+	if (my_phy_caps & PHY_STAT_CAP_TXH)
+		my_ad_caps |= PHY_AD_TX_HDX;
+
+	if (my_phy_caps & PHY_STAT_CAP_TF)
+		my_ad_caps |= PHY_AD_10_FDX;
+
+	if (my_phy_caps & PHY_STAT_CAP_TH)
+		my_ad_caps |= PHY_AD_10_HDX;
+
+	// Disable capabilities not selected by our user
+	if (lp->ctl_rspeed != 100)
+		{
+		my_ad_caps &= ~(PHY_AD_T4|PHY_AD_TX_FDX|PHY_AD_TX_HDX);
+		}
+
+	if (!lp->ctl_rfduplx)
+		{
+		my_ad_caps &= ~(PHY_AD_TX_FDX|PHY_AD_10_FDX);
+		}
+
+	// Update our Auto-Neg Advertisement Register
+	smc_write_phy_register(ioaddr, phyaddr, PHY_AD_REG, my_ad_caps);
+
+	PRINTK2("%s:phy caps=%x\n", dev->name, my_phy_caps);
+	PRINTK2("%s:phy advertised caps=%x\n", dev->name, my_ad_caps);
+
+	// If the user requested no auto neg, then go set his request
+	if (!(lp->ctl_autoneg))
+		{
+		smc_phy_fixed(dev);
+		goto smc_phy_configure_exit;
+		}
+
+	// Restart auto-negotiation process in order to advertise my caps
+	smc_write_phy_register( ioaddr, phyaddr, PHY_CNTL_REG,
+		PHY_CNTL_ANEG_EN | PHY_CNTL_ANEG_RST );
+
+	// Wait for the auto-negotiation to complete.  This may take from
+	// 2 to 3 seconds.
+	// Wait for the reset to complete, or time out
+	timeout = 20; // Wait up to 10 seconds
+	while (timeout--)
+		{
+		status = smc_read_phy_register(ioaddr, phyaddr, PHY_STAT_REG);
+		if (status & PHY_STAT_ANEG_ACK)
+			{
+			// auto-negotiate complete
+			break;
+			}
+
+		smc_wait_ms(500); // wait 500 millisecs
+		if (signal_pending(current)) // Exit anyway if signaled
+			{
+			printk(KERN_DEBUG
+				"%s:PHY auto-negotiate interrupted by signal\n",
+				dev->name);
+			timeout = 0;
+			break;
+			}
+	PRINTK3("%s:phy phy_fixed\n", dev->name);
+
+
+		// Restart auto-negotiation if remote fault
+		if (status & PHY_STAT_REM_FLT)
+			{
+			PRINTK2("%s:PHY remote fault detected\n", dev->name);
+
+			// Restart auto-negotiation
+			PRINTK2("%s:PHY restarting auto-negotiation\n",
+				dev->name);
+			smc_write_phy_register( ioaddr, phyaddr, PHY_CNTL_REG,
+				PHY_CNTL_ANEG_EN | PHY_CNTL_ANEG_RST |
+				PHY_CNTL_SPEED | PHY_CNTL_DPLX);
+			}
+		}
+
+	if (timeout < 1)
+		{
+		printk(KERN_DEBUG "%s:PHY auto-negotiate timed out\n",
+			dev->name);
+		PRINTK2("%s:PHY auto-negotiate timed out\n", dev->name);
+		failed = 1;
+		}
+
+	// Fail if we detected an auto-negotiate remote fault
+	if (status & PHY_STAT_REM_FLT)
+		{
+		printk(KERN_DEBUG "%s:PHY remote fault detected\n", dev->name);
+		PRINTK2("%s:PHY remote fault detected\n", dev->name);
+		failed = 1;
+		}
+
+	// The smc_phy_interrupt() routine will be called to update lastPhy18
+
+	// Set our sysctl parameters to match auto-negotiation results
+	if ( lp->lastPhy18 & PHY_INT_SPDDET )
+		{
+		PRINTK2("%s:PHY 100BaseT\n", dev->name);
+		lp->rpc_cur_mode |= RPC_SPEED;
+		}
+	else
+		{
+		PRINTK2("%s:PHY 10BaseT\n", dev->name);
+		lp->rpc_cur_mode &= ~RPC_SPEED;
+		}
+
+	if ( lp->lastPhy18 & PHY_INT_DPLXDET )
+		{
+		PRINTK2("%s:PHY Full Duplex\n", dev->name);
+		lp->rpc_cur_mode |= RPC_DPLX;
+		}
+	else
+		{
+		PRINTK2("%s:PHY Half Duplex\n", dev->name);
+		lp->rpc_cur_mode &= ~RPC_DPLX;
+		}
+
+	// Re-Configure the Receive/Phy Control register
+	outw( lp->rpc_cur_mode, ioaddr + RPC_REG );
+
+  smc_phy_configure_exit:
+
+	// Exit auto-negotiation
+	lp->autoneg_active = 0;
+}
+
+
+
+/*************************************************************************
+ . smc_phy_interrupt
+ .
+ . Purpose:  Handle interrupts relating to PHY register 18. This is
+ .  called from the "hard" interrupt handler.
+ .
+ ************************************************************************/
+static void smc_phy_interrupt(struct net_device* dev)
+{
+	int ioaddr 		= dev->base_addr;
+	struct smc_local *lp 	= (struct smc_local *)dev->priv;
+	byte phyaddr = lp->phyaddr;
+	word phy18;
+
+	PRINTK2("%s: smc_phy_interrupt\n", dev->name);
+
+	while (1) { 
+		// Read PHY Register 18, Status Output
+		phy18 = smc_read_phy_register(ioaddr, phyaddr, PHY_INT_REG);
+
+		// Exit if not more changes
+		if (phy18 == lp->lastPhy18)
+			break;
+
+#if (SMC_DEBUG > 1 )
+
+		PRINTK2("%s:     phy18=0x%x\n", dev->name, phy18);
+		PRINTK2("%s: lastPhy18=0x%x\n", dev->name, lp->lastPhy18);
+
+		// Handle events
+		if ((phy18 & PHY_INT_LNKFAIL) != (lp->lastPhy18 & PHY_INT_LNKFAIL))
+		{
+			PRINTK2("%s: PHY Link Fail=%x\n", dev->name,
+				phy18 & PHY_INT_LNKFAIL);
+		}
+
+		if ((phy18 & PHY_INT_LOSSSYNC) != (lp->lastPhy18 & PHY_INT_LOSSSYNC))
+		{
+			PRINTK2("%s: PHY LOSS SYNC=%x\n", dev->name,
+				phy18 & PHY_INT_LOSSSYNC);
+		}
+
+		if ((phy18 & PHY_INT_CWRD) != (lp->lastPhy18 & PHY_INT_CWRD))
+		{
+			PRINTK2("%s: PHY INVALID 4B5B code=%x\n", dev->name,
+				phy18 & PHY_INT_CWRD);
+		}
+
+		if ((phy18 & PHY_INT_SSD) != (lp->lastPhy18 & PHY_INT_SSD))
+		{
+			PRINTK2("%s: PHY No Start Of Stream=%x\n", dev->name,
+				phy18 & PHY_INT_SSD);
+		}
+
+		if ((phy18 & PHY_INT_ESD) != (lp->lastPhy18 & PHY_INT_ESD))
+		{
+			PRINTK2("%s: PHY No End Of Stream=%x\n", dev->name,
+				phy18 & PHY_INT_ESD);
+		}
+
+		if ((phy18 & PHY_INT_RPOL) != (lp->lastPhy18 & PHY_INT_RPOL))
+		{
+			PRINTK2("%s: PHY Reverse Polarity Detected=%x\n", dev->name,
+				phy18 & PHY_INT_RPOL);
+		}
+
+		if ((phy18 & PHY_INT_JAB) != (lp->lastPhy18 & PHY_INT_JAB))
+		{
+			PRINTK2("%s: PHY Jabber Detected=%x\n", dev->name,
+				phy18 & PHY_INT_JAB);
+		}
+
+		if ((phy18 & PHY_INT_SPDDET) != (lp->lastPhy18 & PHY_INT_SPDDET))
+		{
+			PRINTK2("%s: PHY Speed Detect=%x\n", dev->name,
+				phy18 & PHY_INT_SPDDET);
+		}
+
+		if ((phy18 & PHY_INT_DPLXDET) != (lp->lastPhy18 & PHY_INT_DPLXDET))
+		{
+			PRINTK2("%s: PHY Duplex Detect=%x\n", dev->name,
+				phy18 & PHY_INT_DPLXDET);
+		}
+#endif
+
+		// Update the last phy 18 variable
+		lp->lastPhy18 = phy18;
+
+	} // end while
+}
+
+
diff -ruN linux-2.6.8.1.org/arch/m32r/drivers/smc91111.copying linux-2.6.8.1/arch/m32r/drivers/smc91111.copying
--- linux-2.6.8.1.org/arch/m32r/drivers/smc91111.copying	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.8.1/arch/m32r/drivers/smc91111.copying	2004-03-16 22:11:26.000000000 +0900
@@ -0,0 +1,352 @@
+
+   NOTE! This copyright does *not* cover user programs that use kernel
+ services by normal system calls - this is merely considered normal use
+ of the kernel, and does *not* fall under the heading of "derived work".
+ Also note that the GPL below is copyrighted by the Free Software
+ Foundation, but the instance of code that it refers to (the Linux
+ kernel) is copyrighted by me and others who actually wrote it.
+
+			Linus Torvalds
+
+----------------------------------------
+
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    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
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff -ruN linux-2.6.8.1.org/arch/m32r/drivers/smc91111.h linux-2.6.8.1/arch/m32r/drivers/smc91111.h
--- linux-2.6.8.1.org/arch/m32r/drivers/smc91111.h	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.8.1/arch/m32r/drivers/smc91111.h	2003-09-09 10:15:02.000000000 +0900
@@ -0,0 +1,570 @@
+/*------------------------------------------------------------------------
+ . smc91111.h - macros for the LAN91C111 Ethernet Driver
+ .
+ . 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
+ .
+ . This file contains register information and access macros for 
+ . the LAN91C111 single chip ethernet controller.  It is a modified
+ . version of the smc9194.h file.
+ . 
+ . 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.
+ . 
+ . Authors
+ . 	Erik Stahlman				( erik@vt.edu )
+ .	Daris A Nevil				( dnevil@snmc.com )
+ .
+ . History
+ . 03/16/01		Daris A Nevil	Modified for use with LAN91C111 device
+ .
+ ---------------------------------------------------------------------------*/
+#ifndef _SMC91111_H_
+#define _SMC91111_H_
+
+/* I want some simple types */
+
+typedef unsigned char			byte;
+typedef unsigned short			word;
+typedef unsigned long int 		dword;
+
+
+/* Because of bank switching, the LAN91xxx uses only 16 I/O ports */
+
+#define SMC_IO_EXTENT	16
+
+
+/*---------------------------------------------------------------
+ .  
+ . A description of the SMSC registers is probably in order here,
+ . although for details, the SMC datasheet is invaluable.  
+ . 
+ . Basically, the chip has 4 banks of registers ( 0 to 3 ), which
+ . are accessed by writing a number into the BANK_SELECT register
+ . ( I also use a SMC_SELECT_BANK macro for this ).
+ . 
+ . The banks are configured so that for most purposes, bank 2 is all
+ . that is needed for simple run time tasks.  
+ -----------------------------------------------------------------------*/
+
+/*
+ . Bank Select Register: 
+ .
+ .		yyyy yyyy 0000 00xx  
+ .		xx 		= bank number
+ .		yyyy yyyy	= 0x33, for identification purposes.
+*/
+#define	BANK_SELECT		14
+
+// Transmit Control Register
+/* BANK 0  */
+#define	TCR_REG 	0x0000 	// transmit control register 
+#define TCR_ENABLE	0x0001	// When 1 we can transmit
+#define TCR_LOOP	0x0002	// Controls output pin LBK
+#define TCR_FORCOL	0x0004	// When 1 will force a collision
+#define TCR_PAD_EN	0x0080	// When 1 will pad tx frames < 64 bytes w/0
+#define TCR_NOCRC	0x0100	// When 1 will not append CRC to tx frames
+#define TCR_MON_CSN	0x0400	// When 1 tx monitors carrier
+#define TCR_FDUPLX    	0x0800  // When 1 enables full duplex operation
+#define TCR_STP_SQET	0x1000	// When 1 stops tx if Signal Quality Error
+#define	TCR_EPH_LOOP	0x2000	// When 1 enables EPH block loopback
+#define	TCR_SWFDUP	0x8000	// When 1 enables Switched Full Duplex mode
+
+#define	TCR_CLEAR	0	/* do NOTHING */
+/* the default settings for the TCR register : */ 
+/* QUESTION: do I want to enable padding of short packets ? */
+#define	TCR_DEFAULT  	TCR_ENABLE 
+
+
+// EPH Status Register
+/* BANK 0  */
+#define EPH_STATUS_REG	0x0002
+#define ES_TX_SUC	0x0001	// Last TX was successful
+#define ES_SNGL_COL	0x0002	// Single collision detected for last tx
+#define ES_MUL_COL	0x0004	// Multiple collisions detected for last tx
+#define ES_LTX_MULT	0x0008	// Last tx was a multicast
+#define ES_16COL	0x0010	// 16 Collisions Reached
+#define ES_SQET		0x0020	// Signal Quality Error Test
+#define ES_LTXBRD	0x0040	// Last tx was a broadcast
+#define ES_TXDEFR	0x0080	// Transmit Deferred
+#define ES_LATCOL	0x0200	// Late collision detected on last tx
+#define ES_LOSTCARR	0x0400	// Lost Carrier Sense
+#define ES_EXC_DEF	0x0800	// Excessive Deferral
+#define ES_CTR_ROL	0x1000	// Counter Roll Over indication
+#define ES_LINK_OK	0x4000	// Driven by inverted value of nLNK pin
+#define ES_TXUNRN	0x8000	// Tx Underrun
+
+
+// Receive Control Register
+/* BANK 0  */
+#define	RCR_REG		0x0004
+#define	RCR_RX_ABORT	0x0001	// Set if a rx frame was aborted
+#define	RCR_PRMS	0x0002	// Enable promiscuous mode
+#define	RCR_ALMUL	0x0004	// When set accepts all multicast frames
+#define RCR_RXEN	0x0100	// IFF this is set, we can receive packets
+#define	RCR_STRIP_CRC	0x0200	// When set strips CRC from rx packets
+#define	RCR_ABORT_ENB	0x0200	// When set will abort rx on collision 
+#define	RCR_FILT_CAR	0x0400	// When set filters leading 12 bit s of carrier
+#define RCR_SOFTRST	0x8000 	// resets the chip
+
+/* the normal settings for the RCR register : */
+#define	RCR_DEFAULT	(RCR_STRIP_CRC | RCR_RXEN)
+#define RCR_CLEAR	0x0	// set it to a base state
+
+// Counter Register
+/* BANK 0  */
+#define	COUNTER_REG	0x0006
+
+// Memory Information Register
+/* BANK 0  */
+#define	MIR_REG		0x0008
+
+// Receive/Phy Control Register
+/* BANK 0  */
+#define	RPC_REG		0x000A
+#define	RPC_SPEED	0x2000	// When 1 PHY is in 100Mbps mode.
+#define	RPC_DPLX	0x1000	// When 1 PHY is in Full-Duplex Mode
+#define	RPC_ANEG	0x0800	// When 1 PHY is in Auto-Negotiate Mode
+#define	RPC_LSXA_SHFT	5	// Bits to shift LS2A,LS1A,LS0A to lsb
+#define	RPC_LSXB_SHFT	2	// Bits to get LS2B,LS1B,LS0B to lsb
+#define RPC_LED_100_10	(0x00)	// LED = 100Mbps OR's with 10Mbps link detect
+#define RPC_LED_RES	(0x01)	// LED = Reserved
+#define RPC_LED_10	(0x02)	// LED = 10Mbps link detect
+#define RPC_LED_FD	(0x03)	// LED = Full Duplex Mode
+#define RPC_LED_TX_RX	(0x04)	// LED = TX or RX packet occurred
+#define RPC_LED_100	(0x05)	// LED = 100Mbps link dectect
+#define RPC_LED_TX	(0x06)	// LED = TX packet occurred
+#define RPC_LED_RX	(0x07)	// LED = RX packet occurred
+#if defined(__m32r__)
+#define RPC_DEFAULT (RPC_ANEG | (RPC_LED_TX_RX << RPC_LSXA_SHFT) | (RPC_LED_100_10 << RPC_LSXB_SHFT) | RPC_SPEED | RPC_DPLX)
+#else
+#define RPC_DEFAULT (RPC_ANEG | (RPC_LED_100 << RPC_LSXA_SHFT) | (RPC_LED_FD << RPC_LSXB_SHFT) | RPC_SPEED | RPC_DPLX)
+#endif
+
+/* Bank 0 0x000C is reserved */
+
+// Bank Select Register
+/* All Banks */
+#define BSR_REG	0x000E
+
+
+// Configuration Reg
+/* BANK 1 */
+#define CONFIG_REG	0x0000
+#define CONFIG_EXT_PHY	0x0200	// 1=external MII, 0=internal Phy
+#define CONFIG_GPCNTRL	0x0400	// Inverse value drives pin nCNTRL
+#define CONFIG_NO_WAIT	0x1000	// When 1 no extra wait states on ISA bus
+#define CONFIG_EPH_POWER_EN 0x8000 // When 0 EPH is placed into low power mode.
+
+// Default is powered-up, Internal Phy, Wait States, and pin nCNTRL=low
+#define CONFIG_DEFAULT	(CONFIG_EPH_POWER_EN)
+
+
+// Base Address Register
+/* BANK 1 */
+#define	BASE_REG	0x0002
+
+
+// Individual Address Registers
+/* BANK 1 */
+#define	ADDR0_REG	0x0004
+#define	ADDR1_REG	0x0006
+#define	ADDR2_REG	0x0008
+
+
+// General Purpose Register
+/* BANK 1 */
+#define	GP_REG		0x000A
+
+
+// Control Register
+/* BANK 1 */
+#define	CTL_REG		0x000C
+#define CTL_RCV_BAD	0x4000 // When 1 bad CRC packets are received
+#define CTL_AUTO_RELEASE 0x0800 // When 1 tx pages are released automatically
+#define	CTL_LE_ENABLE	0x0080 // When 1 enables Link Error interrupt
+#define	CTL_CR_ENABLE	0x0040 // When 1 enables Counter Rollover interrupt
+#define	CTL_TE_ENABLE	0x0020 // When 1 enables Transmit Error interrupt
+#define	CTL_EEPROM_SELECT 0x0004 // Controls EEPROM reload & store
+#define	CTL_RELOAD	0x0002 // When set reads EEPROM into registers
+#define	CTL_STORE	0x0001 // When set stores registers into EEPROM
+
+
+// MMU Command Register
+/* BANK 2 */
+#define MMU_CMD_REG	0x0000
+#define MC_BUSY		1	// When 1 the last release has not completed
+#define MC_NOP		(0<<5)	// No Op
+#define	MC_ALLOC	(1<<5) 	// OR with number of 256 byte packets
+#define	MC_RESET	(2<<5)	// Reset MMU to initial state
+#define	MC_REMOVE	(3<<5) 	// Remove the current rx packet
+#define MC_RELEASE  	(4<<5) 	// Remove and release the current rx packet
+#define MC_FREEPKT  	(5<<5) 	// Release packet in PNR register
+#define MC_ENQUEUE	(6<<5)	// Enqueue the packet for transmit
+#define MC_RSTTXFIFO	(7<<5)	// Reset the TX FIFOs
+
+
+// Packet Number Register
+/* BANK 2 */
+#define	PN_REG		0x0002
+
+
+// Allocation Result Register
+/* BANK 2 */
+#define	AR_REG		0x0003
+#define AR_FAILED	0x80	// Alocation Failed
+
+
+// RX FIFO Ports Register
+/* BANK 2 */
+#define RXFIFO_REG	0x0004	// Must be read as a word
+#define RXFIFO_REMPTY	0x8000	// RX FIFO Empty
+
+
+// TX FIFO Ports Register
+/* BANK 2 */
+#define TXFIFO_REG	RXFIFO_REG	// Must be read as a word
+#define TXFIFO_TEMPTY	0x80	// TX FIFO Empty
+
+
+// Pointer Register
+/* BANK 2 */
+#define PTR_REG		0x0006
+#define	PTR_RCV		0x8000 // 1=Receive area, 0=Transmit area
+#define	PTR_AUTOINC 	0x4000 // Auto increment the pointer on each access
+#define PTR_READ	0x2000 // When 1 the operation is a read
+
+
+// Data Register
+/* BANK 2 */
+#define	DATA_REG	0x0008
+
+
+// Interrupt Status/Acknowledge Register
+/* BANK 2 */
+#define	INT_REG		0x000C
+
+
+// Interrupt Mask Register
+/* BANK 2 */
+#define IM_REG		0x000D
+#define	IM_MDINT	0x80 // PHY MI Register 18 Interrupt
+#define	IM_ERCV_INT	0x40 // Early Receive Interrupt
+#define	IM_EPH_INT	0x20 // Set by Etheret Protocol Handler section
+#define	IM_RX_OVRN_INT	0x10 // Set by Receiver Overruns
+#define	IM_ALLOC_INT	0x08 // Set when allocation request is completed
+#define	IM_TX_EMPTY_INT	0x04 // Set if the TX FIFO goes empty
+#define	IM_TX_INT	0x02 // Transmit Interrrupt
+#define IM_RCV_INT	0x01 // Receive Interrupt
+
+
+// Multicast Table Registers
+/* BANK 3 */
+#define	MCAST_REG1	0x0000
+#define	MCAST_REG2	0x0002
+#define	MCAST_REG3	0x0004
+#define	MCAST_REG4	0x0006
+
+
+// Management Interface Register (MII)
+/* BANK 3 */
+#define	MII_REG		0x0008
+#define MII_MSK_CRS100	0x4000 // Disables CRS100 detection during tx half dup
+#define MII_MDOE	0x0008 // MII Output Enable
+#define MII_MCLK	0x0004 // MII Clock, pin MDCLK
+#define MII_MDI		0x0002 // MII Input, pin MDI
+#define MII_MDO		0x0001 // MII Output, pin MDO
+
+
+// Revision Register
+/* BANK 3 */
+#define	REV_REG		0x000A /* ( hi: chip id   low: rev # ) */
+
+
+// Early RCV Register
+/* BANK 3 */
+/* this is NOT on SMC9192 */
+#define	ERCV_REG	0x000C
+#define ERCV_RCV_DISCRD	0x0080 // When 1 discards a packet being received
+#define ERCV_THRESHOLD	0x001F // ERCV Threshold Mask
+
+// External Register
+/* BANK 7 */
+#define	EXT_REG		0x0000
+
+
+#define CHIP_9192	3
+#define CHIP_9194	4
+#define CHIP_9195	5
+#define CHIP_9196	6
+#define CHIP_91100	7
+#define CHIP_91100FD	8
+#define CHIP_91111FD	9
+
+static const char * chip_ids[ 15 ] =  { 
+	NULL, NULL, NULL, 
+	/* 3 */ "SMC91C90/91C92",
+	/* 4 */ "SMC91C94",
+	/* 5 */ "SMC91C95",
+	/* 6 */ "SMC91C96",
+	/* 7 */ "SMC91C100", 
+	/* 8 */ "SMC91C100FD", 
+	/* 9 */ "SMC91C11xFD", 
+	NULL, NULL, 
+	NULL, NULL, NULL};  
+
+/* 
+ . Transmit status bits 
+*/
+#define TS_SUCCESS 0x0001
+#define TS_LOSTCAR 0x0400
+#define TS_LATCOL  0x0200
+#define TS_16COL   0x0010
+
+/*
+ . Receive status bits
+*/
+#define RS_ALGNERR	0x8000
+#define RS_BRODCAST	0x4000
+#define RS_BADCRC	0x2000
+#define RS_ODDFRAME	0x1000	// bug: the LAN91C111 never sets this on receive
+#define RS_TOOLONG	0x0800
+#define RS_TOOSHORT	0x0400
+#define RS_MULTICAST	0x0001
+#define RS_ERRORS	(RS_ALGNERR | RS_BADCRC | RS_TOOLONG | RS_TOOSHORT) 
+
+
+// PHY Types
+enum {
+	PHY_LAN83C183 = 1,	// LAN91C111 Internal PHY
+	PHY_LAN83C180
+};
+
+
+// PHY Register Addresses (LAN91C111 Internal PHY)
+
+// PHY Control Register
+#define PHY_CNTL_REG		0x00
+#define PHY_CNTL_RST		0x8000	// 1=PHY Reset
+#define PHY_CNTL_LPBK		0x4000	// 1=PHY Loopback
+#define PHY_CNTL_SPEED		0x2000	// 1=100Mbps, 0=10Mpbs
+#define PHY_CNTL_ANEG_EN	0x1000 // 1=Enable Auto negotiation
+#define PHY_CNTL_PDN		0x0800	// 1=PHY Power Down mode
+#define PHY_CNTL_MII_DIS	0x0400	// 1=MII 4 bit interface disabled
+#define PHY_CNTL_ANEG_RST	0x0200 // 1=Reset Auto negotiate
+#define PHY_CNTL_DPLX		0x0100	// 1=Full Duplex, 0=Half Duplex
+#define PHY_CNTL_COLTST		0x0080	// 1= MII Colision Test
+
+// PHY Status Register
+#define PHY_STAT_REG		0x01
+#define PHY_STAT_CAP_T4		0x8000	// 1=100Base-T4 capable
+#define PHY_STAT_CAP_TXF	0x4000	// 1=100Base-X full duplex capable
+#define PHY_STAT_CAP_TXH	0x2000	// 1=100Base-X half duplex capable
+#define PHY_STAT_CAP_TF		0x1000	// 1=10Mbps full duplex capable
+#define PHY_STAT_CAP_TH		0x0800	// 1=10Mbps half duplex capable
+#define PHY_STAT_CAP_SUPR	0x0040	// 1=recv mgmt frames with not preamble
+#define PHY_STAT_ANEG_ACK	0x0020	// 1=ANEG has completed
+#define PHY_STAT_REM_FLT	0x0010	// 1=Remote Fault detected
+#define PHY_STAT_CAP_ANEG	0x0008	// 1=Auto negotiate capable
+#define PHY_STAT_LINK		0x0004	// 1=valid link
+#define PHY_STAT_JAB		0x0002	// 1=10Mbps jabber condition
+#define PHY_STAT_EXREG		0x0001	// 1=extended registers implemented
+
+// PHY Identifier Registers
+#define PHY_ID1_REG		0x02	// PHY Identifier 1
+#define PHY_ID2_REG		0x03	// PHY Identifier 2
+
+// PHY Auto-Negotiation Advertisement Register
+#define PHY_AD_REG		0x04
+#define PHY_AD_NP		0x8000	// 1=PHY requests exchange of Next Page
+#define PHY_AD_ACK		0x4000	// 1=got link code word from remote
+#define PHY_AD_RF		0x2000	// 1=advertise remote fault
+#define PHY_AD_T4		0x0200	// 1=PHY is capable of 100Base-T4
+#define PHY_AD_TX_FDX		0x0100	// 1=PHY is capable of 100Base-TX FDPLX
+#define PHY_AD_TX_HDX		0x0080	// 1=PHY is capable of 100Base-TX HDPLX
+#define PHY_AD_10_FDX		0x0040	// 1=PHY is capable of 10Base-T FDPLX
+#define PHY_AD_10_HDX		0x0020	// 1=PHY is capable of 10Base-T HDPLX
+#define PHY_AD_CSMA		0x0001	// 1=PHY is capable of 802.3 CMSA
+
+// PHY Auto-negotiation Remote End Capability Register
+#define PHY_RMT_REG		0x05
+// Uses same bit definitions as PHY_AD_REG
+
+// PHY Configuration Register 1
+#define PHY_CFG1_REG		0x10
+#define PHY_CFG1_LNKDIS		0x8000	// 1=Rx Link Detect Function disabled
+#define PHY_CFG1_XMTDIS		0x4000	// 1=TP Transmitter Disabled
+#define PHY_CFG1_XMTPDN		0x2000	// 1=TP Transmitter Powered Down
+#define PHY_CFG1_BYPSCR		0x0400	// 1=Bypass scrambler/descrambler
+#define PHY_CFG1_UNSCDS		0x0200	// 1=Unscramble Idle Reception Disable
+#define PHY_CFG1_EQLZR		0x0100	// 1=Rx Equalizer Disabled
+#define PHY_CFG1_CABLE		0x0080	// 1=STP(150ohm), 0=UTP(100ohm)
+#define PHY_CFG1_RLVL0		0x0040	// 1=Rx Squelch level reduced by 4.5db
+#define PHY_CFG1_TLVL_SHIFT	2	// Transmit Output Level Adjust
+#define PHY_CFG1_TLVL_MASK	0x003C
+#define PHY_CFG1_TRF_MASK	0x0003	// Transmitter Rise/Fall time
+
+
+// PHY Configuration Register 2
+#define PHY_CFG2_REG		0x11
+#define PHY_CFG2_APOLDIS	0x0020	// 1=Auto Polarity Correction disabled
+#define PHY_CFG2_JABDIS		0x0010	// 1=Jabber disabled
+#define PHY_CFG2_MREG		0x0008	// 1=Multiple register access (MII mgt)
+#define PHY_CFG2_INTMDIO	0x0004	// 1=Interrupt signaled with MDIO pulseo
+
+// PHY Status Output (and Interrupt status) Register
+#define PHY_INT_REG		0x12	// Status Output (Interrupt Status)
+#define PHY_INT_INT		0x8000	// 1=bits have changed since last read
+#define	PHY_INT_LNKFAIL		0x4000	// 1=Link Not detected
+#define PHY_INT_LOSSSYNC	0x2000	// 1=Descrambler has lost sync
+#define PHY_INT_CWRD		0x1000	// 1=Invalid 4B5B code detected on rx
+#define PHY_INT_SSD		0x0800	// 1=No Start Of Stream detected on rx
+#define PHY_INT_ESD		0x0400	// 1=No End Of Stream detected on rx
+#define PHY_INT_RPOL		0x0200	// 1=Reverse Polarity detected
+#define PHY_INT_JAB		0x0100	// 1=Jabber detected
+#define PHY_INT_SPDDET		0x0080	// 1=100Base-TX mode, 0=10Base-T mode
+#define PHY_INT_DPLXDET		0x0040	// 1=Device in Full Duplex
+
+// PHY Interrupt/Status Mask Register
+#define PHY_MASK_REG		0x13	// Interrupt Mask
+// Uses the same bit definitions as PHY_INT_REG
+
+
+
+/*-------------------------------------------------------------------------
+ .  I define some macros to make it easier to do somewhat common
+ . or slightly complicated, repeated tasks. 
+ --------------------------------------------------------------------------*/
+
+/* select a register bank, 0 to 3  */
+
+#define SMC_SELECT_BANK(x)  { outw( x, ioaddr + BANK_SELECT ); } 
+
+/* this enables an interrupt in the interrupt mask register */
+#define SMC_ENABLE_INT(x) {\
+		unsigned char mask;\
+		SMC_SELECT_BANK(2);\
+		mask = inb( ioaddr + IM_REG );\
+		mask |= (x);\
+		outb( mask, ioaddr + IM_REG ); \
+}
+
+/* this disables an interrupt from the interrupt mask register */
+
+#define SMC_DISABLE_INT(x) {\
+		unsigned char mask;\
+		SMC_SELECT_BANK(2);\
+		mask = inb( ioaddr + IM_REG );\
+		mask &= ~(x);\
+		outb( mask, ioaddr + IM_REG ); \
+}
+
+/*----------------------------------------------------------------------
+ . Define the interrupts that I want to receive from the card
+ . 
+ . I want: 
+ .  IM_EPH_INT, for nasty errors
+ .  IM_RCV_INT, for happy received packets
+ .  IM_RX_OVRN_INT, because I have to kick the receiver
+ .  IM_MDINT, for PHY Register 18 Status Changes
+ --------------------------------------------------------------------------*/
+#define SMC_INTERRUPT_MASK   (IM_EPH_INT | IM_RX_OVRN_INT | IM_RCV_INT | \
+	IM_MDINT) 
+
+
+#ifdef CONFIG_SYSCTL
+
+
+/*
+ * Declarations for the sysctl interface, which allows users the ability to
+ * control the finer aspects of the LAN91C111 chip.  Since the smc
+ * module currently registers its sysctl table dynamically, the sysctl path
+ * for module FOO is /proc/sys/dev/ethX/FOO
+ */
+#define CTL_SMC         (CTL_BUS+1389)      // arbitrary and hopefully unused
+
+enum {
+	CTL_SMC_INFO = 1,	// Sysctl files information
+	CTL_SMC_SWVER,		// Driver Software Version Info
+	CTL_SMC_SWFDUP,		// Switched Full Duplex Mode
+	CTL_SMC_EPHLOOP,	// EPH Block Internal Loopback
+	CTL_SMC_MIIOP,		// MII Operation
+	CTL_SMC_AUTONEG,	// Auto-negotiate Mode
+	CTL_SMC_RFDUPLX,	// Request Full Duplex Mode
+	CTL_SMC_RSPEED,		// Request Speed Selection
+	CTL_SMC_AFDUPLX,	// Actual Full Duplex Mode
+	CTL_SMC_ASPEED,		// Actual Speed Selection
+	CTL_SMC_LNKFAIL,	// Link Failed
+	CTL_SMC_FORCOL,		// Force a Collision
+	CTL_SMC_FILTCAR,	// Filter Carrier
+	CTL_SMC_FREEMEM,	// Free Buffer Memory
+	CTL_SMC_TOTMEM,		// Total Buffer Memory
+	CTL_SMC_LEDA,		// Output of LED-A
+	CTL_SMC_LEDB,		// Output of LED-B
+	CTL_SMC_CHIPREV,	// LAN91C111 Chip Revision ID
+#ifdef SMC_DEBUG
+	// Register access for debugging
+	CTL_SMC_REG_BSR,	// Bank Select
+	CTL_SMC_REG_TCR,	// Transmit Control
+	CTL_SMC_REG_ESR,	// EPH Status
+	CTL_SMC_REG_RCR,	// Receive Control
+	CTL_SMC_REG_CTRR,	// Counter
+	CTL_SMC_REG_MIR,	// Memory Information
+	CTL_SMC_REG_RPCR,	// Receive/Phy Control
+	CTL_SMC_REG_CFGR,	// Configuration
+	CTL_SMC_REG_BAR,	// Base Address
+	CTL_SMC_REG_IAR0,	// Individual Address 0
+	CTL_SMC_REG_IAR1,	// Individual Address 1 
+	CTL_SMC_REG_IAR2,	// Individual Address 2
+	CTL_SMC_REG_GPR,	// General Purpose
+	CTL_SMC_REG_CTLR,	// Control
+	CTL_SMC_REG_MCR,	// MMU Command
+	CTL_SMC_REG_PNR,	// Packet Number
+	CTL_SMC_REG_FPR,	// FIFO Ports
+	CTL_SMC_REG_PTR,	// Pointer
+	CTL_SMC_REG_DR,		// Data 
+	CTL_SMC_REG_ISR,	// Interrupt Status
+	CTL_SMC_REG_MTR1,	// Multicast Table Entry 1
+	CTL_SMC_REG_MTR2,	// Multicast Table Entry 2
+	CTL_SMC_REG_MTR3,	// Multicast Table Entry 3
+	CTL_SMC_REG_MTR4,	// Multicast Table Entry 4
+	CTL_SMC_REG_MIIR,	// Management Interface
+	CTL_SMC_REG_REVR,	// Revision
+	CTL_SMC_REG_ERCVR,	// Early RCV
+	CTL_SMC_REG_EXTR,	// External
+	CTL_SMC_PHY_CTRL,	// PHY Control
+	CTL_SMC_PHY_STAT,	// PHY Status
+	CTL_SMC_PHY_ID1,	// PHY ID1
+	CTL_SMC_PHY_ID2,	// PHY ID2
+	CTL_SMC_PHY_ADC,	// PHY Advertise Capability
+	CTL_SMC_PHY_REMC,	// PHY Advertise Capability
+	CTL_SMC_PHY_CFG1,	// PHY Configuration 1
+	CTL_SMC_PHY_CFG2,	// PHY Configuration 2
+	CTL_SMC_PHY_INT,	// PHY Interrupt/Status Output
+	CTL_SMC_PHY_MASK,	// PHY Interrupt/Status Mask
+#endif
+	// ---------------------------------------------------
+	CTL_SMC_LAST_ENTRY	// Add new entries above the line
+};
+
+#endif // CONFIG_SYSCTL
+ 
+#endif  /* _SMC_91111_H_ */
+
+
diff -ruN linux-2.6.8.1.org/arch/m32r/drivers/smc91111.readme.txt linux-2.6.8.1/arch/m32r/drivers/smc91111.readme.txt
--- linux-2.6.8.1.org/arch/m32r/drivers/smc91111.readme.txt	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.8.1/arch/m32r/drivers/smc91111.readme.txt	2004-03-16 22:11:26.000000000 +0900
@@ -0,0 +1,561 @@
+SMSC LAN91C111 Driver
+Revision 2.0
+9/24/01
+Copyright (C) 2001 Standard Microsystems Corporation (SMSC)
+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
+
+This file contains the instructions, test methods, and caveats for the
+smc91111.c driver.  You may not be using the driver without reading this file.  
+
+Driver Description:
+===================
+This driver has been modified to work on kernel 2.4. And it also contains the
+latest SMSC updates for the Odd Byte issue. Important thing to note about this
+is that, this driver might not compile on kernel version older than 2.4.
+  Please visit the SMSC website (http://www.smsc.com) for latest updates on the
+drivers.
+
+
+Things to note about installation:
+==================================
+
+  1.  This is designed to be compiled and loaded as a module.  While putting
+     it into your kernel should be possible, it has not yet been tested.  
+ 
+  2.  The driver will only load on recent kernels because of changes to
+     the network driver interface.  I have compiled this under kernel 2.4.   
+	
+ 
+  3.  To compile, run 'make' .   
+
+  4.  Loading the driver:
+
+	use:   insmod smc91111.o 
+	optional parameters:
+		io=0x###   : your base address
+		irq=##	   : your irq 
+		nowait=x   :	0 for standard I/O access (IOCHRDY wait states)
+				1 for fast access (no IOCHRDY wait states)
+
+  5. To allow automatic loading and intialization of the driver at boot-up
+     add the following line to /etc/modules.conf (in RedHat 7.0):
+
+	alias eth0 smc91111
+        options eth0 io=0x### irq=##
+
+     See the man pages on module.conf.  You must also be sure to copy the
+     smc91111.o file to the modules directory:
+
+         su
+         cd /lib/modules/YOUR_CURRENT_KERNEL_VERSION/net
+         cp 'directory where the file resides'/smc91111.o .
+         chown root:root smc91111.o
+         chmod a+r smc91111.o
+
+     Then you must update the module dependencies (as root):
+
+         /sbin/depmod
+
+
+
+Advanced Features:
+==================
+
+If your Linux Kernel was compiled with the configuration options CONFIG_PROC_FS
+and CONFIG_SYSCTL enabled then the smc91111 driver provides several sysctl
+files for accessing extended features. These files can be found in
+/proc/sys/dev/ethX, where X is the interface number of the ethernet port. For
+example, if your SMC91C111 card is the only one in the system then your sysctl
+files will be located at /proc/sys/dev/eth0.
+
+The following lists the files supported by the driver.
+
+ sysctl file                       Description
+-------------   --------------------------------------------------------------
+ info           Prints a list of supported files along with a terse
+                description of each one.
+
+ swver          Prints the software version information of the driver.
+
+ autoneg        When set to 1 enables auto negotiation mode.  The LAN91C111
+                supports auto negotiation per IEEE 802.3 Clause 28.  When auto
+                negotiation is set the files "rspeed" and "rfduplx" (below)
+                limit what capabilities are broadcast to the remote end.
+                When "autoneg" is set to 0 the auto-negotiation feature
+                is disabled, and the speed and duplex can be controlled
+                directly and immediately with "rspeed" and "rfduplx".
+                You can change the value of this file by issuing the command
+                "echo 0 > autoneg", assuming that you are in the directory
+                /proc/sys/dev/ethX.
+                The default value of "autoneg" is 1.
+
+ aspeed         Reports the actual speed of the link.  This file is read-only.
+
+ afduplx        Reports the actual duplex of the link. A value of 1 indicates
+                the link is currently operating in full duplex.  This file
+                is read-only.
+
+ rspeed         Requested speed, controls the speed of the interface.  The
+                behavior invoked by this file depends on the value of
+                the "autoneg" file. See the "autoneg" description above. A value
+                of 100 indicates 100Mpbs, and a speed of 10 indicates 10Mbps.
+                You cannot change the value of "rspeed" when "autoneg" is
+                set to 1.  You can issue the following commands to restrict
+                the LAN91C111 to 10Mbps operation:
+                   cd /proc/sys/dev/eth0
+                   echo 0 > autoneg
+                   echo 10 > speed
+                   echo 1 > autoneg
+                The default value of "speed" is 100.
+
+ rfduplx        Requested duplex, controls the duplex operation of the
+                interface.  The behavior invoked by this file depends on the
+                value of the "autoneg" file.  See the "autoneg" description
+                above.  A value of 1 indicates full duplex, while a value of 0
+                indicates half duplex operation.  You cannot change the value
+                of "rfduplx" when "autoneg" is set to 1.  The default value of
+                "rfduplx" is 1.
+
+ lnkfail        When 1 indicates the PHY link is in a failure state (i.e.
+                not connected to a valid LAN).  A value of 0 indicates
+                normal operation.
+
+ miiop          When set to 1 selects an external PHY.  This feature has not
+                yet been tested.  The default value of "miiop" is 0.
+
+ swfdup         When set to 1 enables Switched Full Duplex Operation.  This
+                is to be used only when miiop is set to 1 (according to the
+                LAN91C111 documentation).  This feature has not yet been
+                tested.  The default value of "swfdup" is 0.
+
+ ephloop        When set to 1 enables a loopback in the EPH block.  This feature
+                has not yet been tested.  The default value of "ephloop" is 0.
+
+ forcol         When set to 1 forces a collision.  This feature has not yet been
+                tested.  The default value of "forcol" is 0.
+
+ filtcar        When set to 1 the LAN91C111 filters the leading edge of carrier
+                sense for 12 bit times.  This feature has not yet been tested.
+                The default value of "filtcar" is 0.
+
+ freemem        Reports the amount of buffer memory currently free, in bytes.
+
+ totmem         Reports the total amount of buffer memory contained in the
+                LAN91C111, in bytes.
+
+ leda           Reports and controls which line condition is reported on
+                LEDA.  I tested this feature with the SMSC EVB111-ISA board.
+                LED A on this card is green and is labelled "100".  This
+                file accepts values from 0 thru 7.
+
+                      Value              Line Condition Reported
+                      -----    ----------------------------------------------
+                        0      Logical OR of 100Mbps and 10Mbps link detected
+                        1      Reserved
+                        2      10Mpbs link detected
+                        3      Full Duplex Mode Enabled
+                        4      Transmit or Receive packet occurred
+                        5      100Mbps Link Detected
+                        6      Transmit packet occurred
+                        7      Receive packet occurred
+
+                The default value of "leda" is 5.
+
+ ledb           Reports and controls which line condition is reported on
+                LEDB.  I tested this feature with the SMSC EVB111-ISA board.
+                LED B on this card is yellow and is labelled "FD".  This
+                file accepts values from 0 thru 7 (see above).
+                The default value of "ledb" is 3.
+
+ chiprev        Reports the chip revision number of the LAN91C111.
+
+
+Testing Methodology and Report:
+===============================
+
+I tested the smc91111.c driver using RedHat 7.1.  The version I tested with
+came with kernel version 2.4.2.  I updated the gcc tools because of
+known bugs in this version of the RedHat distribution.  It should not have
+made a difference though, as the module is actually compiled using the "kgcc"
+compiler provided by RedHat 7.1 (you have to manually install the kgcc rpm
+from the CDROM).
+
+I used two machines to perform tests. The first is an AST Bravo MS-T PRO 6200,
+Model 2500C.  It contains a PentiumPro w/integrated 256KB L2 cache, 64Mbytes of
+EDO DRAM, and a 2.5GB EIDE hard drive.
+
+The second machine is a generic Pentium II running at 360MHz.  It contains
+64Mbytes of SDRAM, and a 30GB hard drive. I used a NetGear FA311 PCI Ethernet
+card in this machine.  I compiled and installed the fa311.c driver provided
+with the card.
+
+I tested in two configurations.  The first was in isolation, where the two
+machines were connected to each other with a CAT5 crossover cable.  The second
+configuration connected both machines to a local area network running at
+10Mbps.  This lan containes three Windows machines and an Efficient Networks
+SpeedStream router, connected to the Internet through an IDSL (today it is
+served by Northpoint, tomorrow it is serviced by ????)
+
+Test Scenerio #1
+Testing in Isolated Network
+
+The PentiumPro machine with the EVB111-ISA card is named "LOCAL", with IP address 216.36.95.135, netmask 255.255.255.240.
+
+The PentiumII machine with the NetGear FA311 is named "REMOTE", with IP address of 216.36.95.134, netmask 255.255.255.240.
+
+1. Bring the interface up.
+
+   The insmod and ifconfig programs must be executed as root.
+
+   LOCAL: /sbin/insmod smc91111.o
+   Check /var/log/messages (at end) for results. You should see the I/O address
+   and IRQ assigned to the card by the auto probe function.
+
+   LOCAL: /sbin/ifconfig eth0 216.36.95.135 netmask 255.255.255.240
+   Verify that the interace is up by checking the results of ifconfig:
+
+   LOCAL: /sbin/ifconfig
+   Verify that the Ethernet MAC address reported by ifconfig looks reasonable.
+   The card I tested with contained the address "00:80:0F:6A:00:00".  Beware
+   of addresses with all zeros, all ones, or repeating bytes.
+
+   Test Result: Passed
+
+
+2. Ping Remote Side
+
+   LOCAL: ping -c5 216.36.95.134
+   Verify that 5 pings were returned.
+
+   Test Result: Passed
+
+
+3. Check sysctl variables
+
+   LOCAL: cd /proc/sys/dev/eth0
+   LOCAL: ls
+   Verify that the following files are shown:
+      afduplx autoneg  ephloop  forcol   info  ledb    miiop   rspeed swver
+      aspeed  chiprev  filtcar  freemem  leda  lnkfail rfduplx swfdup totmem
+
+   LOCAL: more autoneg
+   Verify that the value printed is 1.
+
+   LOCAL: more rspeed
+   Verify that the value printed is 100.
+
+   LOCAL: more rfduplx
+   Verify that the value printed is 1.
+
+   LOCAL: more aspeed
+   Verify that the value printed is 100.
+
+   LOCAL: more afduplx
+   Verify that the value printed is 1.
+
+   LOCAL: more lnkfail
+   Verify that the value printed is 0.
+
+   LOCAL: more totmem
+   Verify that the value printed is 8192.
+
+   LOCAL: more freemem
+   Verify that the value printed is 8192.
+
+   LOCAL: more leda
+   Verify that the value printed is 5
+
+   LOCAL: more ledb
+   Verify that the value printed is 3
+
+   Test Result: Passed
+
+
+4. Check LEDs
+
+   You may not be able to do this depending on the LEDs supported on your
+   card.
+
+   Verify that the "100" LED is on, indicating a 100Mbps connection.
+
+   Verify that the "FD" LED is on, indicating Full-Duplex connection.
+
+   Test Result: Passed
+
+
+5. Check Transport - use ftp to transport a large file across the ethernet
+
+   Obtain a large file, preferably several megabytes in size. I used the
+   file XFree86-4.0.1-1.i386.rpm from Disk 1 of the RedHat 7.0 distribution
+   because it was 15Mbytes in size.
+
+   REMOTE: ftp 216.36.95.135
+   REMOTE: bin
+   REMOTE: put large_file
+   REMOTE: get large_file large_file_ftp
+   REMOTE: quit
+   REMOTE: diff large_file large_file_ftp
+   Verify that the transfer occurred correctly, and that the file was not
+   modified after transport.
+
+   Test Result: Passed
+
+
+6. Disable Auto-Negotiate, Force Half Duplex, 100Mbps
+
+   The files in /proc/sys/dev/ethX can only be changed by root.
+
+   LOCAL: echo 0 > autoneg
+   Wait 5 seconds.
+   LOCAL: echo 0 > rfduplx
+   Wait 5 seconds.
+   LOCAL: more rfduplx
+   Verify that the result printed is 0.
+   LOCAL: more afduplx
+   Verify that the result printed is 0.  Verify that the "100" LED is on,
+   and the "FD" LED is off.
+   Perform Test #2 (Ping Remote Side) to verify connection.
+   Perform Test #5 (Check Transport).
+
+   Test Result: Passed
+
+
+7. Eanble Auto-Negotiate, Advertising Half Duplex, 100Mbps
+
+   LOCAL: echo 1 > autoneg
+   Wait 5 seconds.
+   Verify that the "100" LED is on, and the "FD" LED is off.
+   LOCAL: more autoneg
+   Verify that the result printed is 1.
+   LOCAL: more afduplx
+   Verify that the result printed is 0.
+   LOCAL: more aspeed
+   Verify that the result printed is 100.
+   Perform Test #2 (Ping Remote Side) to verify connection.
+   LOCAL: more lnkfail
+   Verify that the result printed is 0.
+   Remove the ethernet cable from the RJ-45 connector.
+   LOCAL: more lnkfail
+   Verify that the result printed is 1.
+   Reinsert the ethernet cable into the RJ-45 connector. 
+   LOCAL: more lnkfail
+   Verify that the result printed is 0.
+   LOCAL: more afduplx
+   Verify that the result printed is 0.
+   LOCAL: more aspeed
+   Verify that the result printed is 100.
+   Perform Test #2 (Ping Remote Side) to verify connection.
+
+   Test Result: Passed
+
+
+8. Force Half Duplex, 10Mbps
+
+   LOCAL: echo 0 > autoneg
+   Wait 5 seconds.
+   LOCAL: echo 10 > rspeed
+   Wait 5 seconds.
+   LOCAL: more aspeed
+   Verify that the result printed is 10.  Verify that the "100" LED is off,
+   and the "FD" LED is off.
+   LOCAL: more afduplx
+   Verify that the result printed is 0.
+   Perform Test #2 (Ping Remote Side) to verify connection.
+   Perform Test #5 (Check Transport).
+
+   Test Result: Passed
+
+
+9. Eanble Auto-Negotiate, Advertising Half Duplex, 10Mbps
+
+   LOCAL: echo 1 > autoneg
+   Wait 5 seconds.
+   Verify that the "100" LED is off, and the "FD" LED is off.
+   LOCAL: more autoneg
+   Verify that the result printed is 1.
+   LOCAL: more afduplx
+   Verify that the result printed is 0.
+   LOCAL: more aspeed
+   Verify that the result printed is 10.
+   Perform Test #2 (Ping Remote Side) to verify connection.
+   LOCAL: more lnkfail
+   Verify that the result printed is 0.
+   Remove the ethernet cable from the RJ-45 connector.
+   LOCAL: more lnkfail
+   Verify that the result printed is 1.
+   Reinsert the ethernet cable into the RJ-45 connector. 
+   LOCAL: more lnkfail
+   Verify that the result printed is 0.
+   LOCAL: more afduplx
+   Verify that the result printed is 0.
+   LOCAL: more aspeed
+   Verify that the result printed is 10.
+   Perform Test #2 (Ping Remote Side) to verify connection.
+
+   Test Result: Passed
+
+
+10. Force Full Duplex, 10Mbps
+
+   LOCAL: echo 0 > autoneg
+   Wait 5 seconds.
+   LOCAL: echo 1 > rfduplx
+   Wait 5 seconds.
+   LOCAL: more afduplx
+   Verify that the result printed is 1.  Verify that the "100" LED is off,
+   and the "FD" LED is on.
+   LOCAL: more aspeed
+   Verify that the result printed is 10.
+   Perform Test #2 (Ping Remote Side) to verify connection.
+   Perform Test #5 (Check Transport).
+
+   Test Result: Passed
+
+
+11. Eanble Auto-Negotiate, Advertising Full Duplex, 10Mbps
+
+   LOCAL: echo 1 > autoneg
+   Wait 5 seconds.
+   Verify that the "100" LED is off, and the "FD" LED is on.
+   LOCAL: more autoneg
+   Verify that the result printed is 1.
+   LOCAL: more afduplx
+   Verify that the result printed is 1.
+   LOCAL: more aspeed
+   Verify that the result printed is 10.
+   Perform Test #2 (Ping Remote Side) to verify connection.
+
+   Test Result: Passed
+
+
+
+12. Return to Full Duplex, 100Mbps
+
+   LOCAL: echo 0 > autoneg
+   Wait 5 seconds.
+   LOCAL: echo 1 > rfduplx
+   Wait 5 seconds.
+   LOCAL: more afduplx
+   Verify that the result printed is 1.
+   LOCAL: echo 100 > rspeed
+   Wait 5 seconds.
+   LOCAL: more espeed
+   Verify that the result printed is 100.
+   Verify that the "100" LED is on, and the "FD" LED is on.
+   Perform Test #2 (Ping Remote Side) to verify connection.
+   LOCAL: echo 1 > autoneg
+   Wait 5 seconds.
+   Verify that the "100" LED is on, and the "FD" LED is on.
+   LOCAL: more autoneg
+   Verify that the result printed is 1.
+   LOCAL: more afduplx
+   Verify that the result printed is 1.
+   LOCAL: more aspeed
+   Verify that the result printed is 100.
+   Perform Test #2 (Ping Remote Side) to verify connection.
+
+   Test Result: Passed
+
+
+
+Test Scenerio #2
+Testing in a Mixed-Mode 10Mbps LAN
+
+This section of testing was perform in a 10Mbps LAN with mixed 10Base2 and
+10BaseT interfaces.  The LAN was interconnected with a D-Link HUB, and a
+connection to the Internet was secured through an Efficient Networks
+SpeedStream router. The address of the router is 216.36.95.129.
+
+
+13. Connect to LAN
+
+   Connect both the LOCAL and REMOTE ethernet cards to the non-isolated LAN.
+   Verify that the "100" LED is off, and the "FD" LED is off.
+   LOCAL: more lnkfail
+   Verify that the result printed is 0.
+   LOCAL: more afduplx
+   Verify that the result printed is 0.
+   LOCAL: more aspeed
+   Verify that the result printed is 10.
+   Perform Test #2 (Ping Remote Side) to verify connection.
+
+   Test Results: Passed
+
+
+14. Test Promiscuous Mode
+
+   LOCAL: /usr/sbin/tcpdump -p -i eth0 host 216.36.95.129
+   REMOTE: ping -c5 216.36.95.129
+   Verify that the LOCAL "tcpdump" program sees the pings to 216.36.95.129.
+
+   Test Results: Passed
+
+15. Test Multicast Mode
+
+   The "route" command must be executed as root.
+   LOCAL: route add -net 224.0.0.0 netmask 240.0.0.0 dev eth0
+   REMOTE: route add -net 224.0.0.0 netmask 240.0.0.0 dev eth0
+   LOCAL: /usr/sbin/tcpdump -p -i eth0 host 216.36.95.129
+   REMOTE: ping 224.0.0.1
+   Verify that the REMOTE machine gets at least one ICMP response from
+   216.36.95.135. You will probably also see ICMP responses from other
+   Linux machines listening on the LAN.
+   Also, by inspecting the output of the LOCAL "tcpdump" you can see which
+   packets are Broadcast (B), Multicast (M), or Point-to-point (P).
+
+   Test Results:  Passed
+
+16. Test LED Control
+
+   LOCAL: echo 6 > leda
+   LOCAL: echo 7 > ledb
+   LOCAL: more leda
+   Verify that the result printed is 6.
+   LOCAL: more ledb
+   Verify that the result printed is 7.
+   Perform Test #2 (Ping Remote Side) to verify connection.
+   Verify that the two LEDs toggle when packets are received and transmitted.
+
+   Test Results:  Passed
+
+
+
+How to obtain the latest version:
+=================================
+	
+	http://www.smsc.com
+
+
+Known bugs:
+===========
+
+   1.   You cannot yet set the hardware address.  
+
+   2.	Hardware multicast filtering is not yet supported.
+
+   3.	The driver does not support multiple cards in a system (yet)
+
+   4.   One anomoly was observed during testing with an Athlon Thunderbird 1GHz system
+        during FTP uploads to a Pentim 4 1.3GHz system running Windows 2000 Adv Server,
+        where FTP transfer speed were observed to be 40-50% below normal. The cause
+        of the anomoly is unknown.
+
+
+Contacting me:
+==============
+   Pramod Bhardwaj, pramod.bhardwaj@smsc.com
+ 
diff -ruN linux-2.6.8.1.org/arch/m32r/kernel/Makefile linux-2.6.8.1/arch/m32r/kernel/Makefile
--- linux-2.6.8.1.org/arch/m32r/kernel/Makefile	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.8.1/arch/m32r/kernel/Makefile	2004-07-27 15:54:20.000000000 +0900
@@ -0,0 +1,20 @@
+# 
+# Makefile for the Linux/M32R kernel.
+#
+
+extra-y	:= head.o init_task.o vmlinux.lds.s
+
+obj-y	:= process.o entry.o traps.o align.o irq.o setup.o time.o \
+	m32r_ksyms.o sys_m32r.o semaphore.o signal.o ptrace.o
+
+obj-$(CONFIG_SMP)		+= smp.o smpboot.o
+obj-$(CONFIG_PLAT_MAPPI)	+= setup_mappi.o io_mappi.o
+obj-$(CONFIG_PLAT_MAPPI2)	+= setup_mappi2.o io_mappi2.o
+obj-$(CONFIG_PLAT_USRV)		+= setup_usrv.o io_usrv.o
+obj-$(CONFIG_PLAT_M32700UT)	+= setup_m32700ut.o io_m32700ut.o
+obj-$(CONFIG_PLAT_OPSPUT)	+= setup_opsput.o io_opsput.o
+obj-$(CONFIG_MODULES)		+= module.o
+obj-$(CONFIG_PLAT_OAKS32R)	+= setup_oaks32r.o io_oaks32r.o
+
+EXTRA_AFLAGS	:= -traditional
+
diff -ruN linux-2.6.8.1.org/arch/m32r/kernel/align.c linux-2.6.8.1/arch/m32r/kernel/align.c
--- linux-2.6.8.1.org/arch/m32r/kernel/align.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.8.1/arch/m32r/kernel/align.c	2003-09-09 10:26:52.000000000 +0900
@@ -0,0 +1,585 @@
+/*
+ * align.c - address exception handler for M32R
+ * 
+ * Copyright (c) 2003 Hitoshi Yamamoto
+ */
+
+#include <linux/config.h>
+#include <asm/ptrace.h>
+#include <asm/uaccess.h>
+
+static int get_reg(struct pt_regs *regs, int nr)
+{
+	int val;
+
+	if (nr < 4)
+		val = *(unsigned long *)(&regs->r0 + nr);
+	else if (nr < 7)
+		val = *(unsigned long *)(&regs->r4 + (nr - 4));
+	else if (nr < 13)
+		val = *(unsigned long *)(&regs->r7 + (nr - 7));
+	else 
+		val = *(unsigned long *)(&regs->fp + (nr - 13));
+
+	return val;
+}
+
+static void set_reg(struct pt_regs *regs, int nr, int val)
+{
+	if (nr < 4)
+		*(unsigned long *)(&regs->r0 + nr) = val;
+	else if (nr < 7)
+		*(unsigned long *)(&regs->r4 + (nr - 4)) = val;
+	else if (nr < 13)
+		*(unsigned long *)(&regs->r7 + (nr - 7)) = val;
+	else 
+		*(unsigned long *)(&regs->fp + (nr - 13)) = val;
+}
+
+#define REG1(insn)	(((insn) & 0x0f00) >> 8)
+#define REG2(insn)	((insn) & 0x000f)
+#define PSW_BC		0x100
+
+/* O- instruction */
+#define ISA_LD1		0x20c0	/* ld Rdest, @Rsrc */
+#define ISA_LD2		0x20e0	/* ld Rdest, @Rsrc+ */
+#define ISA_LDH		0x20a0	/* ldh Rdest, @Rsrc */
+#define ISA_LDUH	0x20b0	/* lduh Rdest, @Rsrc */
+#define ISA_ST1		0x2040	/* st Rsrc1, @Rsrc2 */
+#define ISA_ST2		0x2060	/* st Rsrc1, @+Rsrc2 */
+#define ISA_ST3		0x2070	/* st Rsrc1, @-Rsrc2 */
+#define ISA_STH1	0x2020	/* sth Rsrc1, @Rsrc2 */
+#define ISA_STH2	0x2030	/* sth Rsrc1, @Rsrc2+ */
+
+#ifdef CONFIG_ISA_DUAL_ISSUE
+
+/* OS instruction */
+#define ISA_ADD		0x00a0	/* add Rdest, Rsrc */
+#define ISA_ADDI	0x4000	/* addi Rdest, #imm8 */
+#define ISA_ADDX	0x0090	/* addx Rdest, Rsrc */
+#define ISA_AND		0x00c0	/* and Rdest, Rsrc */
+#define ISA_CMP		0x0040	/* cmp Rsrc1, Rsrc2 */
+#define ISA_CMPEQ	0x0060	/* cmpeq Rsrc1, Rsrc2 */
+#define ISA_CMPU	0x0050	/* cmpu Rsrc1, Rsrc2 */
+#define ISA_CMPZ	0x0070	/* cmpz Rsrc */
+#define ISA_LDI		0x6000	/* ldi Rdest, #imm8 */
+#define ISA_MV		0x1080	/* mv Rdest, Rsrc */
+#define ISA_NEG		0x0030	/* neg Rdest, Rsrc */
+#define ISA_NOP		0x7000	/* nop */
+#define ISA_NOT		0x00b0	/* not Rdest, Rsrc */
+#define ISA_OR		0x00e0	/* or Rdest, Rsrc */
+#define ISA_SUB		0x0020	/* sub Rdest, Rsrc */
+#define ISA_SUBX	0x0010	/* subx Rdest, Rsrc */
+#define ISA_XOR		0x00d0	/* xor Rdest, Rsrc */
+
+/* -S instruction */
+#define ISA_MUL		0x1060	/* mul Rdest, Rsrc */
+#define ISA_MULLO_A0	0x3010	/* mullo Rsrc1, Rsrc2, A0 */
+#define ISA_MULLO_A1	0x3090	/* mullo Rsrc1, Rsrc2, A1 */
+#define ISA_MVFACMI_A0	0x50f2	/* mvfacmi Rdest, A0 */
+#define ISA_MVFACMI_A1	0x50f6	/* mvfacmi Rdest, A1 */
+
+static int emu_addi(unsigned short insn, struct pt_regs *regs)
+{
+	char imm = (char)(insn & 0xff);
+	int dest = REG1(insn);
+	int val;
+
+	val = get_reg(regs, dest);
+	val += imm;
+	set_reg(regs, dest, val);
+
+	return 0;
+}
+
+static int emu_ldi(unsigned short insn, struct pt_regs *regs)
+{
+	char imm = (char)(insn & 0xff);
+
+	set_reg(regs, REG1(insn), (int)imm);
+
+	return 0;
+}
+
+static int emu_add(unsigned short insn, struct pt_regs *regs)
+{
+	int dest = REG1(insn);
+	int src = REG2(insn);
+	int val;
+
+	val = get_reg(regs, dest);
+	val += get_reg(regs, src);
+	set_reg(regs, dest, val);
+
+	return 0;
+}
+
+static int emu_addx(unsigned short insn, struct pt_regs *regs)
+{
+	int dest = REG1(insn);
+	unsigned int val, tmp;
+
+	val = regs->psw & PSW_BC ? 1 : 0;
+	tmp = get_reg(regs, dest);
+	val += tmp;
+	val += (unsigned int)get_reg(regs, REG2(insn));
+	set_reg(regs, dest, val);
+
+	/* C bit set */
+	if (val < tmp)
+		regs->psw |= PSW_BC;
+	else
+		regs->psw &= ~(PSW_BC);
+
+	return 0;
+}
+
+static int emu_and(unsigned short insn, struct pt_regs *regs)
+{
+	int dest = REG1(insn);
+	int val;
+
+	val = get_reg(regs, dest);
+	val &= get_reg(regs, REG2(insn));
+	set_reg(regs, dest, val);
+
+	return 0;
+}
+
+static int emu_cmp(unsigned short insn, struct pt_regs *regs)
+{
+	if (get_reg(regs, REG1(insn)) < get_reg(regs, REG2(insn)))
+		regs->psw |= PSW_BC;
+	else
+		regs->psw &= ~(PSW_BC);
+
+	return 0;
+}
+
+static int emu_cmpeq(unsigned short insn, struct pt_regs *regs)
+{
+	if (get_reg(regs, REG1(insn)) == get_reg(regs, REG2(insn)))
+		regs->psw |= PSW_BC;
+	else
+		regs->psw &= ~(PSW_BC);
+
+	return 0;
+}
+
+static int emu_cmpu(unsigned short insn, struct pt_regs *regs)
+{
+	if ((unsigned int)get_reg(regs, REG1(insn))
+		< (unsigned int)get_reg(regs, REG2(insn)))
+		regs->psw |= PSW_BC;
+	else
+		regs->psw &= ~(PSW_BC);
+
+	return 0;
+}
+
+static int emu_cmpz(unsigned short insn, struct pt_regs *regs)
+{
+	if (!get_reg(regs, REG2(insn)))
+		regs->psw |= PSW_BC;
+	else
+		regs->psw &= ~(PSW_BC);
+
+	return 0;
+}
+
+static int emu_mv(unsigned short insn, struct pt_regs *regs)
+{
+	int val;
+
+	val = get_reg(regs, REG2(insn));
+	set_reg(regs, REG1(insn), val);
+
+	return 0;
+}
+
+static int emu_neg(unsigned short insn, struct pt_regs *regs)
+{
+	int val;
+
+	val = get_reg(regs, REG2(insn));
+	set_reg(regs, REG1(insn), 0 - val);
+
+	return 0;
+}
+
+static int emu_not(unsigned short insn, struct pt_regs *regs)
+{
+	int val;
+
+	val = get_reg(regs, REG2(insn));
+	set_reg(regs, REG1(insn), ~val);
+
+	return 0;
+}
+
+static int emu_or(unsigned short insn, struct pt_regs *regs)
+{
+	int dest = REG1(insn);
+	int val;
+
+	val = get_reg(regs, dest);
+	val |= get_reg(regs, REG2(insn));
+	set_reg(regs, dest, val);
+
+	return 0;
+}
+
+static int emu_sub(unsigned short insn, struct pt_regs *regs)
+{
+	int dest = REG1(insn);
+	int val;
+
+	val = get_reg(regs, dest);
+	val -= get_reg(regs, REG2(insn));
+	set_reg(regs, dest, val);
+
+	return 0;
+}
+
+static int emu_subx(unsigned short insn, struct pt_regs *regs)
+{
+	int dest = REG1(insn);
+	unsigned int val, tmp;
+
+	val = tmp = get_reg(regs, dest);
+	val -= (unsigned int)get_reg(regs, REG2(insn));
+	val -= regs->psw & PSW_BC ? 1 : 0;
+	set_reg(regs, dest, val);
+
+	/* C bit set */
+	if (val > tmp)
+		regs->psw |= PSW_BC;
+	else
+		regs->psw &= ~(PSW_BC);
+
+	return 0;
+}
+
+static int emu_xor(unsigned short insn, struct pt_regs *regs)
+{
+	int dest = REG1(insn);
+	unsigned int val;
+
+	val = (unsigned int)get_reg(regs, dest);
+	val ^= (unsigned int)get_reg(regs, REG2(insn));
+	set_reg(regs, dest, val);
+
+	return 0;
+}
+
+static int emu_mul(unsigned short insn, struct pt_regs *regs)
+{
+	int dest = REG1(insn);
+	int reg1, reg2;
+
+	reg1 = get_reg(regs, dest);
+	reg2 = get_reg(regs, REG2(insn));
+
+	__asm__ __volatile__ (
+		"mul	%0, %1;		\n\t"
+		: "+r" (reg1) : "r" (reg2)
+	);
+
+	set_reg(regs, dest, reg1);
+
+	return 0;
+}
+
+static int emu_mullo_a0(unsigned short insn, struct pt_regs *regs)
+{
+	int reg1, reg2;
+
+	reg1 = get_reg(regs, REG1(insn));
+	reg2 = get_reg(regs, REG2(insn));
+
+	__asm__ __volatile__ (
+		"mullo		%0, %1, a0;	\n\t"
+		"mvfachi	%0, a0;		\n\t"
+		"mvfaclo	%1, a0;		\n\t"
+		: "+r" (reg1), "+r" (reg2)
+	);
+
+	regs->acc0h = reg1;
+	regs->acc0l = reg2;
+
+	return 0;
+}
+
+static int emu_mullo_a1(unsigned short insn, struct pt_regs *regs)
+{
+	int reg1, reg2;
+
+	reg1 = get_reg(regs, REG1(insn));
+	reg2 = get_reg(regs, REG2(insn));
+
+	__asm__ __volatile__ (
+		"mullo		%0, %1, a0;	\n\t"
+		"mvfachi	%0, a0;		\n\t"
+		"mvfaclo	%1, a0;		\n\t"
+		: "+r" (reg1), "+r" (reg2)
+	);
+
+	regs->acc1h = reg1;
+	regs->acc1l = reg2;
+
+	return 0;
+}
+
+static int emu_mvfacmi_a0(unsigned short insn, struct pt_regs *regs)
+{
+	unsigned long val;
+
+	val = (regs->acc0h << 16) | (regs->acc0l >> 16);
+	set_reg(regs, REG1(insn), (int)val);
+
+	return 0;
+}
+
+static int emu_mvfacmi_a1(unsigned short insn, struct pt_regs *regs)
+{
+	unsigned long val;
+
+	val = (regs->acc1h << 16) | (regs->acc1l >> 16);
+	set_reg(regs, REG1(insn), (int)val);
+
+	return 0;
+}
+
+static int emu_m32r2(unsigned short insn, struct pt_regs *regs)
+{
+	int res = -1;
+
+	if ((insn & 0x7fff) == ISA_NOP)	/* nop */
+		return 0;
+
+	switch(insn & 0x7000) {
+	case ISA_ADDI:		/* addi Rdest, #imm8 */
+		res = emu_addi(insn, regs);
+		break;
+	case ISA_LDI:		/* ldi Rdest, #imm8 */
+		res = emu_ldi(insn, regs);
+		break;
+	default:
+		break;
+	}
+
+	if (!res)
+		return 0;
+
+	switch(insn & 0x70f0) {
+	case ISA_ADD:		/* add Rdest, Rsrc */
+		res = emu_add(insn, regs);
+		break;
+	case ISA_ADDX:		/* addx Rdest, Rsrc */
+		res = emu_addx(insn, regs);
+		break;
+	case ISA_AND:		/* and Rdest, Rsrc */
+		res = emu_and(insn, regs);
+		break;
+	case ISA_CMP:		/* cmp Rsrc1, Rsrc2 */
+		res = emu_cmp(insn, regs);
+		break;
+	case ISA_CMPEQ:		/* cmpeq Rsrc1, Rsrc2 */
+		res = emu_cmpeq(insn, regs);
+		break;
+	case ISA_CMPU:		/* cmpu Rsrc1, Rsrc2 */
+		res = emu_cmpu(insn, regs);
+		break;
+	case ISA_CMPZ:		/* cmpz Rsrc */
+		res = emu_cmpz(insn, regs);
+		break;
+	case ISA_MV:		/* mv Rdest, Rsrc */
+		res = emu_mv(insn, regs);
+		break;
+	case ISA_NEG:		/* neg Rdest, Rsrc */
+		res = emu_neg(insn, regs);
+		break;
+	case ISA_NOT:		/* not Rdest, Rsrc */
+		res = emu_not(insn, regs);
+		break;
+	case ISA_OR:		/* or Rdest, Rsrc */
+		res = emu_or(insn, regs);
+		break;
+	case ISA_SUB:		/* sub Rdest, Rsrc */
+		res = emu_sub(insn, regs);
+		break;
+	case ISA_SUBX:		/* subx Rdest, Rsrc */
+		res = emu_subx(insn, regs);
+		break;
+	case ISA_XOR:		/* xor Rdest, Rsrc */
+		res = emu_xor(insn, regs);
+		break;
+	case ISA_MUL:		/* mul Rdest, Rsrc */
+		res = emu_mul(insn, regs);
+		break;
+	case ISA_MULLO_A0:	/* mullo Rsrc1, Rsrc2 */
+		res = emu_mullo_a0(insn, regs);
+		break;
+	case ISA_MULLO_A1:	/* mullo Rsrc1, Rsrc2 */
+		res = emu_mullo_a1(insn, regs);
+		break;
+	default:
+		break;
+	}
+
+	if (!res)
+		return 0;
+
+	switch(insn & 0x70ff) {
+	case ISA_MVFACMI_A0:	/* mvfacmi Rdest */
+		res = emu_mvfacmi_a0(insn, regs);
+		break;
+	case ISA_MVFACMI_A1:	/* mvfacmi Rdest */
+		res = emu_mvfacmi_a1(insn, regs);
+		break;
+	default:
+		break;
+	}
+
+	return res;
+}
+
+#endif	/* CONFIG_ISA_DUAL_ISSUE */
+
+/*
+ * ld   : ?010 dest 1100 src
+ *        0010 dest 1110 src : ld Rdest, @Rsrc+
+ * ldh  : ?010 dest 1010 src
+ * lduh : ?010 dest 1011 src
+ * st   : ?010 src1 0100 src2
+ *        0010 src1 0110 src2 : st Rsrc1, @+Rsrc2
+ *        0010 src1 0111 src2 : st Rsrc1, @-Rsrc2
+ * sth  : ?010 src1 0010 src2
+ */
+
+static int insn_check(unsigned long insn, struct pt_regs *regs, 
+	unsigned char **ucp)
+{
+	int res = 0;
+
+	/*
+	 * 32bit insn
+	 *  ld Rdest, @(disp16, Rsrc)
+	 *  st Rdest, @(disp16, Rsrc)
+	 */
+	if (insn & 0x80000000) {	/* 32bit insn */
+		*ucp += (short)(insn & 0x0000ffff);
+		regs->bpc += 4;
+	} else {			/* 16bit insn */
+#ifdef CONFIG_ISA_DUAL_ISSUE
+		/* parallel exec check */
+		if (!(regs->bpc & 0x2) && insn & 0x8000) {
+			res = emu_m32r2((unsigned short)insn, regs);
+			regs->bpc += 4;
+		} else
+#endif	/* CONFIG_ISA_DUAL_ISSUE */
+			regs->bpc += 2;
+	}
+
+	return res;
+}
+
+static int emu_ld(unsigned long insn32, struct pt_regs *regs)
+{
+	unsigned char *ucp;
+	unsigned long val;
+	unsigned short insn16;
+	int size, src;
+
+	insn16 = insn32 >> 16;
+	src = REG2(insn16);
+	ucp = (unsigned char *)get_reg(regs, src);
+
+	if (insn_check(insn32, regs, &ucp))
+		return -1;
+
+	size = insn16 & 0x0040 ? 4 : 2;
+	if (copy_from_user(&val, ucp, size))
+		return -1;
+
+	if (size == 2)
+		val >>= 16;
+
+	/* ldh sign check */
+	if ((insn16 & 0x00f0) == 0x00a0 && (val & 0x8000))
+		val |= 0xffff0000;
+
+	set_reg(regs, REG1(insn16), val);
+
+	/* ld increment check */
+	if ((insn16 & 0xf0f0) == ISA_LD2)	/* ld Rdest, @Rsrc+ */
+		set_reg(regs, src, (unsigned long)(ucp + 4));
+
+	return 0;
+}
+
+static int emu_st(unsigned long insn32, struct pt_regs *regs)
+{
+	unsigned char *ucp;
+	unsigned long val;
+	unsigned short insn16;
+	int size, src2;
+
+	insn16 = insn32 >> 16;
+	src2 = REG2(insn16);
+
+	ucp = (unsigned char *)get_reg(regs, src2);
+
+	if (insn_check(insn32, regs, &ucp))
+		return -1;
+
+	size = insn16 & 0x0040 ? 4 : 2;
+	val = get_reg(regs, REG1(insn16));
+	if (size == 2)
+		val <<= 16;
+
+	/* st inc/dec check */
+	if ((insn16 & 0xf0e0) == 0x2060) {
+		if (insn16 & 0x0010)
+			ucp -= 4;
+		else
+			ucp += 4;
+
+		set_reg(regs, src2, (unsigned long)ucp);
+	}
+
+	if (copy_to_user(ucp, &val, size))
+		return -1;
+
+	/* sth inc check */
+	if ((insn16 & 0xf0f0) == ISA_STH2) {
+		ucp += 2;
+		set_reg(regs, src2, (unsigned long)ucp);
+	}
+
+	return 0;
+}
+
+int handle_unaligned_access(unsigned long insn32, struct pt_regs *regs)
+{
+	unsigned short insn16;
+	int res;
+
+	insn16 = insn32 >> 16;
+
+	/* ld or st check */
+	if ((insn16 & 0x7000) != 0x2000)
+		return -1;
+
+	/* insn alignment check */
+	if ((insn16 & 0x8000) && (regs->bpc & 3))
+		return -1;
+
+	if (insn16 & 0x0080)	/* ld */
+		res = emu_ld(insn32, regs);
+	else			/* st */
+		res = emu_st(insn32, regs);
+
+	return res;
+}
+
diff -ruN linux-2.6.8.1.org/arch/m32r/kernel/entry.S linux-2.6.8.1/arch/m32r/kernel/entry.S
--- linux-2.6.8.1.org/arch/m32r/kernel/entry.S	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.8.1/arch/m32r/kernel/entry.S	2004-08-23 20:53:31.000000000 +0900
@@ -0,0 +1,997 @@
+/*
+ *  linux/arch/m32r/kernel/entry.S
+ *
+ *  Copyright (c) 2001, 2002  Hirokazu Takata, Hitoshi Yamamoto, H. Kondo
+ *  Copyright (c) 2003  Hitoshi Yamamoto
+ *
+ *  Taken from i386 version.
+ *    Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+/*
+ * entry.S contains the system-call and fault low-level handling routines.
+ * This also contains the timer-interrupt handler, as well as all interrupts
+ * and faults that can result in a task-switch.
+ *
+ * NOTE: This code handles signal-recognition, which happens every time
+ * after a timer-interrupt and after each system call.
+ *
+ * Stack layout in 'ret_from_system_call':
+ * 	ptrace needs to have all regs on the stack.
+ *	if the order here is changed, it needs to be
+ *	updated in fork.c:copy_process, signal.c:do_signal,
+ *	ptrace.c and ptrace.h
+ *
+ * M32Rx/M32R2				M32R
+ *       @(sp)      - r4		ditto
+ *       @(0x04,sp) - r5		ditto
+ *       @(0x08,sp) - r6		ditto
+ *       @(0x0c,sp) - *pt_regs		ditto
+ *       @(0x10,sp) - r0		ditto
+ *       @(0x14,sp) - r1		ditto
+ *       @(0x18,sp) - r2		ditto
+ *       @(0x1c,sp) - r3		ditto
+ *       @(0x20,sp) - r7		ditto
+ *       @(0x24,sp) - r8		ditto
+ *       @(0x28,sp) - r9		ditto
+ *       @(0x2c,sp) - r10		ditto
+ *       @(0x30,sp) - r11		ditto
+ *       @(0x34,sp) - r12		ditto
+ *       @(0x38,sp) - syscall_nr	ditto
+ *       @(0x3c,sp) - acc0h		@(0x3c,sp) - acch
+ *       @(0x40,sp) - acc0l		@(0x40,sp) - accl
+ *       @(0x44,sp) - acc1h		@(0x44,sp) - psw
+ *       @(0x48,sp) - acc1l		@(0x48,sp) - bpc
+ *       @(0x4c,sp) - psw		@(0x4c,sp) - bbpsw
+ *       @(0x50,sp) - bpc		@(0x50,sp) - bbpc
+ *       @(0x54,sp) - bbpsw		@(0x54,sp) - spu (cr3)
+ *       @(0x58,sp) - bbpc		@(0x58,sp) - fp (r13)
+ *       @(0x5c,sp) - spu (cr3)		@(0x5c,sp) - lr (r14)
+ *       @(0x60,sp) - fp (r13)		@(0x60,sp) - spi (cr12)
+ *       @(0x64,sp) - lr (r14)		@(0x64,sp) - orig_r0
+ *       @(0x68,sp) - spi (cr2)
+ *       @(0x6c,sp) - orig_r0
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/linkage.h>
+#include <asm/irq.h>
+#include <asm/unistd.h>
+#include <asm/assembler.h>
+#include <asm/thread_info.h>
+#include <asm/errno.h>
+#include <asm/segment.h>
+#include <asm/smp.h>
+#include <asm/page.h>
+#include <asm/m32r.h>
+#include <asm/mmu_context.h>
+
+#if !defined(CONFIG_MMU)
+#define sys_madvise             sys_ni_syscall
+#define sys_readahead           sys_ni_syscall
+#define sys_mprotect            sys_ni_syscall
+#define sys_msync               sys_ni_syscall
+#define sys_mlock               sys_ni_syscall
+#define sys_munlock             sys_ni_syscall
+#define sys_mlockall            sys_ni_syscall
+#define sys_munlockall          sys_ni_syscall
+#define sys_mremap              sys_ni_syscall
+#define sys_mincore             sys_ni_syscall
+#endif /* CONFIG_MMU */
+		
+#define R4(reg)			@reg
+#define R5(reg)			@(0x04,reg)
+#define R6(reg)			@(0x08,reg)
+#define PTREGS(reg)		@(0x0C,reg)
+#define R0(reg)			@(0x10,reg)
+#define R1(reg)			@(0x14,reg)
+#define R2(reg)			@(0x18,reg)
+#define R3(reg)			@(0x1C,reg)
+#define R7(reg)			@(0x20,reg)
+#define R8(reg)			@(0x24,reg)
+#define R9(reg)			@(0x28,reg)
+#define R10(reg)		@(0x2C,reg)
+#define R11(reg)		@(0x30,reg)
+#define R12(reg)		@(0x34,reg)
+#define SYSCALL_NR(reg)		@(0x38,reg)
+#if defined(CONFIG_ISA_M32R2) && defined(CONFIG_ISA_DSP_LEVEL2)
+#define ACC0H(reg)		@(0x3C,reg)
+#define ACC0L(reg)		@(0x40,reg)
+#define ACC1H(reg)		@(0x44,reg)
+#define ACC1L(reg)		@(0x48,reg)
+#define PSW(reg)		@(0x4C,reg)
+#define BPC(reg)		@(0x50,reg)
+#define BBPSW(reg)		@(0x54,reg)
+#define BBPC(reg)		@(0x58,reg)
+#define SPU(reg)		@(0x5C,reg)
+#define FP(reg)			@(0x60,reg)  /* FP = R13 */
+#define LR(reg)			@(0x64,reg)
+#define SP(reg)			@(0x68,reg)
+#define ORIG_R0(reg)		@(0x6C,reg)
+#elif defined(CONFIG_ISA_M32R2) || defined(CONFIG_ISA_M32R)
+#define ACCH(reg)		@(0x3C,reg)
+#define ACCL(reg)		@(0x40,reg)
+#define PSW(reg)		@(0x44,reg)
+#define BPC(reg)		@(0x48,reg)
+#define BBPSW(reg)		@(0x4C,reg)
+#define BBPC(reg)		@(0x50,reg)
+#define SPU(reg)		@(0x54,reg)
+#define FP(reg)			@(0x58,reg)  /* FP = R13 */
+#define LR(reg)			@(0x5C,reg)
+#define SP(reg)			@(0x60,reg)
+#define ORIG_R0(reg)		@(0x64,reg)
+#else
+#error unknown isa configuration
+#endif
+
+CF_MASK		= 0x00000001
+TF_MASK		= 0x00000100
+IF_MASK		= 0x00000200
+DF_MASK		= 0x00000400 
+NT_MASK		= 0x00004000
+VM_MASK		= 0x00020000
+
+#ifdef CONFIG_PREEMPT
+#define preempt_stop(x)		CLI(x)
+#else
+#define preempt_stop(x)
+#define resume_kernel		restore_all
+#endif
+
+ENTRY(ret_from_fork)
+	ld	r0, @sp+
+	bl	schedule_tail
+	GET_THREAD_INFO(r8)
+	bra	syscall_exit
+
+/*
+ * Return to user mode is not as complex as all this looks,
+ * but we want the default path for a system call return to
+ * go as quickly as possible which is why some of this is
+ * less clear than it otherwise should be.
+ */
+
+	; userspace resumption stub bypassing syscall exit tracing
+	ALIGN
+ret_from_exception:
+	preempt_stop(r4)
+ret_from_intr:
+	ld	r4, PSW(sp)
+#ifdef CONFIG_ISA_M32R2
+	and3	r4, r4, #0x8800		; check BSM and BPM bits
+#else
+	and3	r4, r4, #0x8000		; check BSM bit
+#endif
+	beqz	r4, resume_kernel
+ENTRY(resume_userspace)
+	CLI(r4)				; make sure we don't miss an interrupt
+					; setting need_resched or sigpending
+					; between sampling and the iret
+	GET_THREAD_INFO(r8)
+	ld	r9, @(TI_FLAGS, r8)
+	and3	r4, r9, #_TIF_WORK_MASK	; is there any work to be done on
+					; int/exception return?
+	bnez	r4, work_pending
+	bra	restore_all
+
+#ifdef CONFIG_PREEMPT
+ENTRY(resume_kernel)
+	GET_THREAD_INFO(r8)
+	ld	r9, @(TI_PRE_COUNT, r8)	; non-zero preempt_count ?
+	bnez	r9, restore_all
+need_resched:
+	ld	r9, @(TI_FLAGS, r8)	; need_resched set ?
+	and3	r4, r9, #_TIF_NEED_RESCHED
+	beqz	r4, restore_all
+	ld	r4, PSW(sp)		; interrupts off (exception path) ?
+	and3	r4, r4, #0x4000
+	beqz	r4, restore_all
+	LDIMM	(r4, PREEMPT_ACTIVE)
+	st	r4, @(TI_PRE_COUNT, r8)
+	STI(r4)
+	bl	schedule
+	ldi	r4, #0
+	st	r4, @(TI_PRE_COUNT, r8)
+	CLI(r4)
+	bra	need_resched
+#endif
+
+	; system call handler stub
+ENTRY(system_call)
+	SWITCH_TO_KERNEL_STACK
+	SAVE_ALL
+	STI(r4)				; Enable interrupt
+	st	sp, PTREGS(sp)		; implicit pt_regs parameter
+	cmpui	r7, #NR_syscalls
+	bnc	syscall_badsys
+	st	r7, SYSCALL_NR(sp)	; syscall_nr
+					; system call tracing in operation
+	GET_THREAD_INFO(r8)
+	ld	r9, @(TI_FLAGS, r8)
+	and3	r4, r9, #_TIF_SYSCALL_TRACE
+	bnez	r4, syscall_trace_entry
+syscall_call:
+	slli	r7, #2			; table jump for the system call
+	LDIMM	(r4, sys_call_table)
+	add	r7, r4
+	ld	r7, @r7
+	jl	r7			; execute system call
+	st	r0, R0(sp)		; save the return value
+syscall_exit:
+	CLI(r4)				; make sure we don't miss an interrupt
+					; setting need_resched or sigpending
+					; between sampling and the iret
+	ld	r9, @(TI_FLAGS, r8)
+	and3	r4, r9, #_TIF_ALLWORK_MASK	; current->work
+	bnez	r4, syscall_exit_work
+restore_all:
+	RESTORE_ALL
+
+	# perform work that needs to be done immediately before resumption
+	# r9 : frags
+	ALIGN
+work_pending:
+	and3	r4, r9, #_TIF_NEED_RESCHED
+	beqz	r4, work_notifysig
+work_resched:
+	bl	schedule
+	CLI(r4)				; make sure we don't miss an interrupt
+					; setting need_resched or sigpending
+					; between sampling and the iret
+	ld	r9, @(TI_FLAGS, r8)
+	and3	r4, r9, #_TIF_WORK_MASK	; is there any work to be done other
+					; than syscall tracing?
+	beqz	r4, restore_all
+	and3	r4, r4, #_TIF_NEED_RESCHED
+	bnez	r4, work_resched
+
+work_notifysig:				; deal with pending signals and
+					; notify-resume requests
+	mv	r0, sp			; arg1 : struct pt_regs *regs
+	ldi	r1, #0			; arg2 : sigset_t *oldset
+	mv	r2, r9			; arg3 : __u32 thread_info_flags
+	bl	do_notify_resume
+	bra	restore_all
+
+	; perform syscall exit tracing
+	ALIGN
+syscall_trace_entry:
+	ldi	r4, #-ENOSYS
+	st	r4, R0(sp)
+	bl	do_syscall_trace
+	ld	r0, ORIG_R0(sp)
+	ld	r1, R1(sp)
+	ld	r2, R2(sp)
+	ld	r3, R3(sp)
+	ld	r4, R4(sp)
+	ld	r5, R5(sp)
+	ld	r6, R6(sp)
+	ld	r7, SYSCALL_NR(sp)
+	cmpui	r7, #NR_syscalls
+	bc	syscall_call
+	bra	syscall_exit
+
+	; perform syscall exit tracing
+	ALIGN
+syscall_exit_work:
+	ld	r9, @(TI_FLAGS, r8)
+	and3	r4, r9, #_TIF_SYSCALL_TRACE
+	beqz	r4, work_pending
+	STI(r4)				; could let do_syscall_trace() call
+					; schedule() instead
+	bl	do_syscall_trace
+	bra	resume_userspace
+
+	ALIGN
+syscall_fault:
+	SAVE_ALL
+	GET_THREAD_INFO(r8)
+	ldi	r4, #-EFAULT
+	st	r4, R0(sp)
+	bra	resume_userspace
+
+	ALIGN
+syscall_badsys:
+	ldi	r4, #-ENOSYS
+	st	r4, R0(sp)
+	bra	resume_userspace
+
+	.global	eit_vector
+
+	.equ ei_vec_table, eit_vector + 0x0200
+
+/* 
+ * EI handler routine
+ */
+ENTRY(ei_handler)
+#if defined(CONFIG_CHIP_M32700) 
+	SWITCH_TO_KERNEL_STACK
+	; WORKAROUND: force to clear SM bit and use the kernel stack (SPI).
+#endif
+	SAVE_ALL
+	mv	r1, sp			; arg1(regs)
+#if defined(CONFIG_CHIP_VDEC2) || defined(CONFIG_CHIP_XNUX2) \
+	|| defined(CONFIG_CHIP_M32700) || defined(CONFIG_CHIP_M32102) \
+	|| defined(CONFIG_CHIP_OPSP)
+
+;    GET_ICU_STATUS;
+	seth	r0, #shigh(M32R_ICU_ISTS_ADDR)
+	ld	r0, @(low(M32R_ICU_ISTS_ADDR),r0)
+	st	r0, @-sp
+#if defined(CONFIG_SMP)
+	/*
+	 * If IRQ == 0      --> Nothing to do,  Not write IMASK
+	 * If IRQ == IPI    --> Do IPI handler, Not write IMASK
+	 * If IRQ != 0, IPI --> Do do_IRQ(),    Write IMASK
+	 */
+	slli	r0, #4
+	srli	r0, #24			; r0(irq_num<<2)
+	;; IRQ exist check
+#if defined(CONFIG_CHIP_M32700)
+	/* WORKAROUND: IMASK bug M32700-TS1, TS2 chip. */
+	beqz	r0, 3f			; if (!irq_num) goto exit
+#else
+	beqz	r0, 1f			; if (!irq_num) goto exit
+#endif	/* WORKAROUND */
+	;; IPI check
+	cmpi	r0, #(M32R_IRQ_IPI0<<2)	; ISN < IPI0 check
+	bc	2f
+	cmpi	r0, #((M32R_IRQ_IPI7+1)<<2)	; ISN > IPI7 check
+	bnc	2f
+	LDIMM	(r2, ei_vec_table)
+	add	r2, r0
+	ld	r2, @r2
+	beqz	r2, 1f			; if (no IPI handler) goto exit
+	mv	r0, r1			; arg0(regs)
+	jl	r2
+	.fillinsn
+1:
+	addi	sp, #4
+	bra	ret_to_intr
+#if defined(CONFIG_CHIP_M32700)
+	/* WORKAROUND: IMASK bug M32700-TS1, TS2 chip. */
+	.fillinsn
+3:
+	ld24	r14, #0x00070000
+	seth	r0, #shigh(M32R_ICU_IMASK_ADDR)
+	st	r14, @(low(M32R_ICU_IMASK_ADDR), r0)
+	addi	sp, #4
+	bra	ret_to_intr
+#endif	/* WORKAROUND */
+	;; do_IRQ
+	.fillinsn
+2:
+	srli	r0, #2
+#if defined(CONFIG_PLAT_USRV)
+	add3	r2, r0, #-(M32R_IRQ_INT1)	; INT1# interrupt
+	bnez	r2, 9f
+	; read ICU status register of PLD
+	seth	r0, #high(PLD_ICUISTS)
+	or3	r0, r0, #low(PLD_ICUISTS)
+	lduh	r0, @r0
+	slli	r0, #21
+	srli	r0, #27				; ISN
+	addi	r0, #(M32700UT_PLD_IRQ_BASE)
+	.fillinsn
+9:
+#elif defined(CONFIG_PLAT_M32700UT)
+	add3	r2, r0, #-(M32R_IRQ_INT1)       ; INT1# interrupt
+	bnez	r2, check_int0
+	; read ICU status register of PLD
+	seth	r0, #high(PLD_ICUISTS)
+	or3	r0, r0, #low(PLD_ICUISTS)
+	lduh	r0, @r0
+	slli	r0, #21
+	srli	r0, #27                         ; ISN
+	addi	r0, #(M32700UT_PLD_IRQ_BASE)
+	bra	check_end
+	.fillinsn
+check_int0:
+	add3	r2, r0, #-(M32R_IRQ_INT0)       ; INT0# interrupt
+	bnez	r2, check_int2
+	; read ICU status of LAN-board
+	seth	r0, #high(M32700UT_LAN_ICUISTS)
+	or3	r0, r0, #low(M32700UT_LAN_ICUISTS)
+	lduh	r0, @r0
+	slli	r0, #21
+	srli	r0, #27                         ; ISN
+	add3	r0, r0, #(M32700UT_LAN_PLD_IRQ_BASE)
+	bra	check_end
+	.fillinsn
+check_int2:
+	add3	r2, r0, #-(M32R_IRQ_INT2)       ; INT2# interrupt
+	bnez	r2, check_end
+	; read ICU status of LCD-board
+	seth	r0, #high(M32700UT_LCD_ICUISTS)
+	or3	r0, r0, #low(M32700UT_LCD_ICUISTS)
+	lduh	r0, @r0
+	slli	r0, #21
+	srli	r0, #27                         ; ISN
+	add3	r0, r0, #(M32700UT_LCD_PLD_IRQ_BASE)
+	bra	check_end
+	.fillinsn
+check_end:
+#elif defined(CONFIG_PLAT_OPSPUT)
+	add3	r2, r0, #-(M32R_IRQ_INT1)       ; INT1# interrupt
+	bnez	r2, check_int0
+	; read ICU status register of PLD
+	seth	r0, #high(PLD_ICUISTS)
+	or3	r0, r0, #low(PLD_ICUISTS)
+	lduh	r0, @r0
+	slli	r0, #21
+	srli	r0, #27                         ; ISN
+	addi	r0, #(OPSPUT_PLD_IRQ_BASE)
+	bra	check_end
+	.fillinsn
+check_int0:
+	add3	r2, r0, #-(M32R_IRQ_INT0)       ; INT0# interrupt
+	bnez	r2, check_int2
+	; read ICU status of LAN-board
+	seth	r0, #high(OPSPUT_LAN_ICUISTS)
+	or3	r0, r0, #low(OPSPUT_LAN_ICUISTS)
+	lduh	r0, @r0
+	slli	r0, #21
+	srli	r0, #27                         ; ISN
+	add3	r0, r0, #(OPSPUT_LAN_PLD_IRQ_BASE)
+	bra	check_end
+	.fillinsn
+check_int2:
+	add3	r2, r0, #-(M32R_IRQ_INT2)       ; INT2# interrupt
+	bnez	r2, check_end
+	; read ICU status of LCD-board
+	seth	r0, #high(OPSPUT_LCD_ICUISTS)
+	or3	r0, r0, #low(OPSPUT_LCD_ICUISTS)
+	lduh	r0, @r0
+	slli	r0, #21
+	srli	r0, #27                         ; ISN
+	add3	r0, r0, #(OPSPUT_LCD_PLD_IRQ_BASE)
+	bra	check_end
+	.fillinsn
+check_end:
+#endif  /* CONFIG_PLAT_OPSPUT */
+	bl	do_IRQ			; r0(irq), r1(regs)
+#else  /* not CONFIG_SMP */
+	srli	r0, #22			; r0(irq)
+#if defined(CONFIG_PLAT_USRV)
+	add3	r2, r0, #-(M32R_IRQ_INT1)	; INT1# interrupt
+	bnez	r2, 1f
+	; read ICU status register of PLD
+	seth	r0, #high(PLD_ICUISTS)
+	or3	r0, r0, #low(PLD_ICUISTS)
+	lduh	r0, @r0
+	slli	r0, #21
+	srli	r0, #27				; ISN
+	addi	r0, #(M32700UT_PLD_IRQ_BASE)
+	.fillinsn
+1:
+#elif defined(CONFIG_PLAT_M32700UT) 
+	add3	r2, r0, #-(M32R_IRQ_INT1)       ; INT1# interrupt
+	bnez	r2, check_int0
+	; read ICU status register of PLD
+	seth	r0, #high(PLD_ICUISTS)
+	or3	r0, r0, #low(PLD_ICUISTS)
+	lduh	r0, @r0
+	slli	r0, #21
+	srli	r0, #27                         ; ISN
+	addi	r0, #(M32700UT_PLD_IRQ_BASE)
+	bra	check_end
+	.fillinsn
+check_int0:
+	add3	r2, r0, #-(M32R_IRQ_INT0)       ; INT0# interrupt
+	bnez	r2, check_int2
+	; read ICU status of LAN-board
+	seth	r0, #high(M32700UT_LAN_ICUISTS)
+	or3	r0, r0, #low(M32700UT_LAN_ICUISTS)
+	lduh	r0, @r0
+	slli	r0, #21
+	srli	r0, #27                         ; ISN
+	add3	r0, r0, #(M32700UT_LAN_PLD_IRQ_BASE)
+	bra	check_end
+	.fillinsn
+check_int2:
+	add3	r2, r0, #-(M32R_IRQ_INT2)       ; INT2# interrupt
+	bnez	r2, check_end
+	; read ICU status of LCD-board
+	seth	r0, #high(M32700UT_LCD_ICUISTS)
+	or3	r0, r0, #low(M32700UT_LCD_ICUISTS)
+	lduh	r0, @r0
+	slli	r0, #21
+	srli	r0, #27                         ; ISN
+	add3	r0, r0, #(M32700UT_LCD_PLD_IRQ_BASE)
+	bra	check_end
+	.fillinsn
+check_end:
+#elif defined(CONFIG_PLAT_OPSPUT)
+	add3	r2, r0, #-(M32R_IRQ_INT1)       ; INT1# interrupt
+	bnez	r2, check_int0
+	; read ICU status register of PLD
+	seth	r0, #high(PLD_ICUISTS)
+	or3	r0, r0, #low(PLD_ICUISTS)
+	lduh	r0, @r0
+	slli	r0, #21
+	srli	r0, #27                         ; ISN
+	addi	r0, #(OPSPUT_PLD_IRQ_BASE)
+	bra	check_end
+	.fillinsn
+check_int0:
+	add3	r2, r0, #-(M32R_IRQ_INT0)       ; INT0# interrupt
+	bnez	r2, check_int2
+	; read ICU status of LAN-board
+	seth	r0, #high(OPSPUT_LAN_ICUISTS)
+	or3	r0, r0, #low(OPSPUT_LAN_ICUISTS)
+	lduh	r0, @r0
+	slli	r0, #21
+	srli	r0, #27                         ; ISN
+	add3	r0, r0, #(OPSPUT_LAN_PLD_IRQ_BASE)
+	bra	check_end
+	.fillinsn
+check_int2:
+	add3	r2, r0, #-(M32R_IRQ_INT2)       ; INT2# interrupt
+	bnez	r2, check_end
+	; read ICU status of LCD-board
+	seth	r0, #high(OPSPUT_LCD_ICUISTS)
+	or3	r0, r0, #low(OPSPUT_LCD_ICUISTS)
+	lduh	r0, @r0
+	slli	r0, #21
+	srli	r0, #27                         ; ISN
+	add3	r0, r0, #(OPSPUT_LCD_PLD_IRQ_BASE)
+	bra	check_end
+	.fillinsn
+check_end:
+#endif  /* CONFIG_PLAT_OPSPUT */
+	bl	do_IRQ
+#endif  /* CONFIG_SMP */
+	ld	r14, @sp+
+	seth	r0, #shigh(M32R_ICU_IMASK_ADDR)
+	st	r14, @(low(M32R_ICU_IMASK_ADDR),r0)
+#else
+#error no chip configuration
+#endif
+ret_to_intr:
+	bra  ret_from_intr
+
+/* 
+ * Default EIT handler
+ */
+	ALIGN
+int_msg:
+	.asciz  "Unknown interrupt\n"
+	.byte	0
+
+ENTRY(default_eit_handler)
+	push	r0
+	mvfc	r0, psw
+	push	r1
+	push	r2
+	push	r3
+	push	r0
+	LDIMM	(r0, __KERNEL_DS)
+	mv	r0, r1
+	mv	r0, r2
+	LDIMM	(r0, int_msg)
+	bl	printk
+	pop	r0
+	pop	r3
+	pop	r2
+	pop	r1
+	mvtc	r0, psw
+	pop	r0
+infinit:
+	bra	infinit
+
+#ifdef CONFIG_MMU
+/* 
+ * Access Exception handler
+ */
+ENTRY(ace_handler)
+	SWITCH_TO_KERNEL_STACK
+	SAVE_ALL
+
+	seth	r2, #shigh(MMU_REG_BASE)	/* Check status register */
+	ld	r4, @(low(MESTS_offset),r2)
+	st	r4, @(low(MESTS_offset),r2)
+	srl3	r1, r4, #4
+#ifdef CONFIG_CHIP_M32700 
+	and3	r1, r1, #0x0000ffff
+	; WORKAROUND: ignore TME bit for the M32700(TS1).
+#endif /* CONFIG_CHIP_M32700 */
+	beqz	r1, inst
+oprand:
+	ld	r2, @(low(MDEVA_offset),r2)	; set address
+	srli	r2, #12
+	slli	r2, #12
+	srli	r1, #1
+	bra	1f
+inst:
+	and3	r1, r4, #2
+	srli	r1, #1
+	or3	r1, r1, #8
+	mvfc	r2, bpc				; set address
+	.fillinsn
+1:
+	mvfc	r3, psw
+	mv	r0, sp
+	and3	r3, r3, 0x800
+	srli	r3, #9
+	or	r1, r3
+	/*
+	 * do_page_fault():
+	 *    r0 : struct pt_regs *regs
+	 *    r1 : unsigned long error-code
+	 *    r2 : unsigned long address
+	 * error-code:
+	 *    +------+------+------+------+
+	 *    | bit3 | bit2 | bit1 | bit0 |
+	 *    +------+------+------+------+
+	 *    bit 3 == 0:means data,          1:means instruction
+	 *    bit 2 == 0:means kernel,        1:means user-mode
+	 *    bit 1 == 0:means read,          1:means write
+	 *    bit 0 == 0:means no page found  1:means protection fault
+	 *
+	 */
+	bl	do_page_fault
+	bra	ret_from_intr
+#endif  /* CONFIG_MMU */
+
+
+ENTRY(alignment_check)
+/* void alignment_check(int error_code) */
+	SWITCH_TO_KERNEL_STACK
+	SAVE_ALL
+	ldi	r1, #0x30			; error_code
+	mv	r0, sp				; pt_regs
+	bl	do_alignment_check
+error_code:
+	bra	ret_from_exception
+
+ENTRY(rie_handler)
+/* void rie_handler(int error_code) */
+	SWITCH_TO_KERNEL_STACK
+	SAVE_ALL
+	mvfc	r0, bpc
+	ld	r1, @r0
+	seth	r0, #0xa0f0
+	st	r1, @r0
+	ldi	r1, #0x20			; error_code
+	mv	r0, sp				; pt_regs
+	bl	do_rie_handler
+	bra	error_code
+
+ENTRY(pie_handler)
+/* void pie_handler(int error_code) */
+	SWITCH_TO_KERNEL_STACK
+	SAVE_ALL
+	ldi	r1, #0				; error_code ; FIXME
+	mv	r0, sp				; pt_regs
+	bl	do_pie_handler
+	bra	error_code
+
+ENTRY(debug_trap)
+	.global	withdraw_debug_trap
+	/* void debug_trap(void) */
+	SWITCH_TO_KERNEL_STACK
+	SAVE_ALL
+	mv	r0, sp				; pt_regs
+	bl	withdraw_debug_trap		
+	ldi	r1, #0				; error_code
+	mv	r0, sp				; pt_regs
+	bl	do_debug_trap
+	bra	error_code
+
+
+/* Cache flushing handler */
+ENTRY(cache_flushing_handler)
+	.global	_flush_cache_all
+	/* void _flush_cache_all(void); */
+	SWITCH_TO_KERNEL_STACK
+	push	r0
+	push	r1
+	push	r2
+	push	r3
+	push	r4
+	push	r5
+	push	r6
+	push	r7
+	push	lr
+	bl	_flush_cache_all
+	pop	lr
+	pop	r7
+	pop	r6
+	pop	r5
+	pop	r4
+	pop	r3
+	pop	r2
+	pop	r1
+	pop	r0
+	rte
+
+.data
+ENTRY(sys_call_table)
+	.long sys_restart_syscall	/* 0  -  old "setup()" system call*/
+	.long sys_exit
+	.long sys_fork
+	.long sys_read
+	.long sys_write
+	.long sys_open			/* 5 */
+	.long sys_close
+	.long sys_waitpid
+	.long sys_creat
+	.long sys_link
+	.long sys_unlink		/* 10 */
+	.long sys_execve
+	.long sys_chdir
+	.long sys_time
+	.long sys_mknod
+	.long sys_chmod			/* 15 */
+	.long sys_lchown
+	.long sys_ni_syscall		/* old break syscall holder */
+	.long sys_stat
+	.long sys_lseek
+	.long sys_getpid		/* 20 */
+	.long sys_mount
+	.long sys_oldumount
+	.long sys_setuid
+	.long sys_getuid
+	.long sys_stime			/* 25 */
+	.long sys_ptrace
+	.long sys_alarm
+	.long sys_fstat
+	.long sys_pause
+	.long sys_utime			/* 30 */
+	.long sys_cacheflush		/* for M32R */ /* old stty syscall holder */
+	.long sys_cachectl		/* for M32R */ /* old gtty syscall holder */
+	.long sys_access
+	.long sys_nice
+	.long sys_ni_syscall		/* 35  -  old ftime syscall holder */
+	.long sys_sync
+	.long sys_kill
+	.long sys_rename
+	.long sys_mkdir
+	.long sys_rmdir			/* 40 */
+	.long sys_dup
+	.long sys_pipe
+	.long sys_times
+	.long sys_ni_syscall		/* old prof syscall holder */
+	.long sys_brk			/* 45 */
+	.long sys_setgid
+	.long sys_getgid
+	.long sys_signal
+	.long sys_geteuid
+	.long sys_getegid		/* 50 */
+	.long sys_acct
+	.long sys_umount		/* recycled never used phys() */
+	.long sys_ni_syscall		/* old lock syscall holder */
+	.long sys_ioctl
+	.long sys_fcntl			/* 55 */
+	.long sys_ni_syscall		/* old mpx syscall holder */
+	.long sys_setpgid
+	.long sys_ni_syscall		/* old ulimit syscall holder */
+	.long sys_ni_syscall		/* sys_olduname */
+	.long sys_umask			/* 60 */
+	.long sys_chroot
+	.long sys_ustat
+	.long sys_dup2
+	.long sys_getppid
+	.long sys_getpgrp		/* 65 */
+	.long sys_setsid
+	.long sys_sigaction
+	.long sys_sgetmask
+	.long sys_ssetmask
+	.long sys_setreuid		/* 70 */
+	.long sys_setregid
+	.long sys_sigsuspend
+	.long sys_sigpending
+	.long sys_sethostname
+	.long sys_setrlimit		/* 75 */
+	.long sys_getrlimit
+	.long sys_getrusage
+	.long sys_gettimeofday
+	.long sys_settimeofday
+	.long sys_getgroups		/* 80 */
+	.long sys_setgroups
+	.long sys_ni_syscall		/* sys_oldselect */
+	.long sys_symlink
+	.long sys_lstat
+	.long sys_readlink		/* 85 */
+	.long sys_uselib
+	.long sys_swapon
+	.long sys_reboot
+	.long old_readdir
+	.long old_mmap			/* 90 */
+	.long sys_munmap
+	.long sys_truncate
+	.long sys_ftruncate
+	.long sys_fchmod
+	.long sys_fchown		/* 95 */
+	.long sys_getpriority
+	.long sys_setpriority
+	.long sys_ni_syscall		/* old profil syscall holder */
+	.long sys_statfs
+	.long sys_fstatfs		/* 100 */
+	.long sys_ni_syscall		/* ioperm */
+	.long sys_socketcall
+	.long sys_syslog
+	.long sys_setitimer
+	.long sys_getitimer		/* 105 */
+	.long sys_newstat
+	.long sys_newlstat
+	.long sys_newfstat
+	.long sys_uname
+	.long sys_ni_syscall		/* 110  -  iopl */
+	.long sys_vhangup
+	.long sys_ni_syscall		/* for idle */
+	.long sys_ni_syscall		/* for vm86old */
+	.long sys_wait4
+	.long sys_swapoff		/* 115 */
+	.long sys_sysinfo
+	.long sys_ipc
+	.long sys_fsync
+	.long sys_sigreturn
+	.long sys_clone			/* 120 */
+	.long sys_setdomainname
+	.long sys_newuname
+	.long sys_ni_syscall		/* sys_modify_ldt */
+	.long sys_adjtimex
+	.long sys_mprotect		/* 125 */
+	.long sys_sigprocmask
+	.long sys_ni_syscall		/* sys_create_module */
+	.long sys_init_module
+	.long sys_delete_module
+	.long sys_ni_syscall		/* 130 sys_get_kernel_syms */
+	.long sys_quotactl
+	.long sys_getpgid
+	.long sys_fchdir
+	.long sys_bdflush
+	.long sys_sysfs			/* 135 */
+	.long sys_personality
+	.long sys_ni_syscall		/* for afs_syscall */
+	.long sys_setfsuid
+	.long sys_setfsgid
+	.long sys_llseek		/* 140 */
+	.long sys_getdents
+	.long sys_select
+	.long sys_flock
+	.long sys_msync
+	.long sys_readv			/* 145 */
+	.long sys_writev
+	.long sys_getsid
+	.long sys_fdatasync
+	.long sys_sysctl
+	.long sys_mlock			/* 150 */
+	.long sys_munlock
+	.long sys_mlockall
+	.long sys_munlockall
+	.long sys_sched_setparam
+	.long sys_sched_getparam	/* 155 */
+	.long sys_sched_setscheduler
+	.long sys_sched_getscheduler
+	.long sys_sched_yield
+	.long sys_sched_get_priority_max
+	.long sys_sched_get_priority_min	/* 160 */
+	.long sys_sched_rr_get_interval
+	.long sys_nanosleep
+	.long sys_mremap
+	.long sys_setresuid
+	.long sys_getresuid		/* 165 */
+	.long sys_tas			/* vm86 */
+	.long sys_ni_syscall		/* sys_query_module */
+	.long sys_poll
+	.long sys_nfsservctl
+	.long sys_setresgid		/* 170 */
+	.long sys_getresgid
+	.long sys_prctl
+	.long sys_rt_sigreturn
+	.long sys_rt_sigaction
+	.long sys_rt_sigprocmask	/* 175 */
+	.long sys_rt_sigpending
+	.long sys_rt_sigtimedwait
+	.long sys_rt_sigqueueinfo
+	.long sys_rt_sigsuspend
+	.long sys_pread64		/* 180 */
+	.long sys_pwrite64
+	.long sys_chown
+	.long sys_getcwd
+	.long sys_capget
+	.long sys_capset		/* 185 */
+	.long sys_sigaltstack
+	.long sys_sendfile
+	.long sys_ni_syscall		/* streams1 */
+	.long sys_ni_syscall		/* streams2 */
+	.long sys_vfork			/* 190 */
+	.long sys_getrlimit
+	.long sys_mmap2
+	.long sys_truncate64
+	.long sys_ftruncate64
+	.long sys_stat64		/* 195 */
+	.long sys_lstat64
+	.long sys_fstat64
+	.long sys_lchown
+	.long sys_getuid
+	.long sys_getgid		/* 200 */
+	.long sys_geteuid
+	.long sys_getegid
+	.long sys_setreuid
+	.long sys_setregid
+	.long sys_getgroups		/* 205 */
+	.long sys_setgroups
+	.long sys_fchown
+	.long sys_setresuid
+	.long sys_getresuid
+	.long sys_setresgid		/* 210 */
+	.long sys_getresgid
+	.long sys_chown
+	.long sys_setuid
+	.long sys_setgid
+	.long sys_setfsuid		/* 215 */
+	.long sys_setfsgid
+	.long sys_pivot_root
+	.long sys_mincore
+	.long sys_madvise
+	.long sys_getdents64		/* 220 */
+	.long sys_fcntl64
+	.long sys_ni_syscall		/* reserved for TUX */
+	.long sys_ni_syscall		/* Reserved for Security */
+	.long sys_gettid
+	.long sys_readahead		/* 225 */
+	.long sys_setxattr
+	.long sys_lsetxattr
+	.long sys_fsetxattr
+	.long sys_getxattr
+	.long sys_lgetxattr		/* 230 */
+	.long sys_fgetxattr
+	.long sys_listxattr
+	.long sys_llistxattr
+	.long sys_flistxattr
+	.long sys_removexattr		/* 235 */
+	.long sys_lremovexattr
+	.long sys_fremovexattr
+	.long sys_tkill
+	.long sys_sendfile64
+	.long sys_futex			/* 240 */
+	.long sys_sched_setaffinity
+	.long sys_sched_getaffinity
+	.long sys_ni_syscall		/* reserved for "set_thread_area" system call */
+	.long sys_ni_syscall		/* reserved for "get_thread_area" system call */
+	.long sys_io_setup		/* 245 */
+	.long sys_io_destroy
+	.long sys_io_getevents
+	.long sys_io_submit
+	.long sys_io_cancel
+	.long sys_fadvise64		/* 250 */
+	.long sys_ni_syscall
+	.long sys_exit_group
+	.long sys_lookup_dcookie
+	.long sys_epoll_create
+	.long sys_epoll_ctl		/* 255 */
+	.long sys_epoll_wait
+ 	.long sys_remap_file_pages
+ 	.long sys_set_tid_address
+ 	.long sys_timer_create
+ 	.long sys_timer_settime		/* 260 */
+ 	.long sys_timer_gettime
+ 	.long sys_timer_getoverrun
+ 	.long sys_timer_delete
+ 	.long sys_clock_settime
+ 	.long sys_clock_gettime		/* 265 */
+ 	.long sys_clock_getres
+ 	.long sys_clock_nanosleep
+	.long sys_statfs64
+	.long sys_fstatfs64     
+	.long sys_tgkill		/* 270 */
+	.long sys_utimes
+ 	.long sys_fadvise64_64
+	.long sys_ni_syscall		/* Reserved for sys_vserver */
+        .long sys_ni_syscall		/* Reserved for sys_mbind */
+        .long sys_ni_syscall		/* Reserved for sys_get_mempolicy */
+        .long sys_ni_syscall		/* Reserved for sys_set_mempolicy */
+        .long sys_mq_open
+        .long sys_mq_unlink
+        .long sys_mq_timedsend
+        .long sys_mq_timedreceive       /* 280 */
+        .long sys_mq_notify
+        .long sys_mq_getsetattr
+        .long sys_ni_syscall            /* reserved for kexec */
+
+syscall_table_size=(.-sys_call_table)
+
diff -ruN linux-2.6.8.1.org/arch/m32r/kernel/head.S linux-2.6.8.1/arch/m32r/kernel/head.S
--- linux-2.6.8.1.org/arch/m32r/kernel/head.S	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.8.1/arch/m32r/kernel/head.S	2004-08-23 20:53:31.000000000 +0900
@@ -0,0 +1,287 @@
+/*  
+ *  linux/arch/m32r/kernel/head.S
+ *  
+ *  M32R startup code.
+ *  
+ *  Copyright (c) 2001, 2002  Hiroyuki Kondo, Hirokazu Takata,
+ *                            Hitoshi Yamamoto                
+ */
+
+/* $Id$ */
+
+#include <linux/init.h>
+__INIT
+__INITDATA
+
+	.text
+#include <linux/config.h>
+#include <linux/linkage.h>
+#include <asm/segment.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/assembler.h>
+#include <asm/m32r.h>
+#include <asm/mmu_context.h>
+
+/*
+ * References to members of the boot_cpu_data structure.
+ */
+	.text
+	.global	start_kernel
+	.global __bss_start
+	.global _end
+ENTRY(stext)
+ENTRY(_stext)
+ENTRY(startup_32)
+	/* Setup up the stack pointer */
+	LDIMM	(r0, spi_stack_top)
+	LDIMM	(r1, spu_stack_top)
+	mvtc	r0, spi
+	mvtc	r1, spu
+
+	/* Initilalize PSW */
+	ldi	r0, #0x0000		/* use SPI, disable EI */
+	mvtc	r0, psw	
+
+	/* Set up the stack pointer */
+	LDIMM	(r0, stack_start)
+	ld	r0, @r0
+	mvtc	r0, spi
+
+/*
+ * Clear BSS first so that there are no surprises...
+ */
+#ifdef CONFIG_ISA_DUAL_ISSUE
+
+	LDIMM	(r2, __bss_start)
+	LDIMM	(r3, _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, __bss_start)
+	LDIMM	(r3, _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 */
+
+#if 0  /* M32R_FIXME */
+/* 
+ * Copy data segment from ROM to RAM.
+ */
+	.global ROM_D, TOP_DATA, END_DATA
+	
+	LDIMM	(r1, ROM_D)
+	LDIMM	(r2, TOP_DATA)
+	LDIMM	(r3, END_DATA)
+	addi	r2, #-4
+	addi	r3, #-4
+loop1:
+	ld	r0, @r1+
+	st	r0, @+r2
+	cmp	r2, r3
+	bc	loop1
+#endif /* 0 */
+		
+/* Jump to kernel */
+	LDIMM	(r2, start_kernel)
+	jl	r2
+	.fillinsn
+1:
+	bra	1b		; main should never return here, but
+				; just in case, we know what happens.
+
+#ifdef CONFIG_SMP
+/* 
+ * AP startup routine
+ */
+	.text
+	.global	eit_vector
+ENTRY(startup_AP)
+;; setup EVB
+	LDIMM  (r4, eit_vector)
+	mvtc   r4, cr5
+	
+;; enable MMU
+	LDIMM	(r2, init_tlb)
+	jl	r2
+	seth  r4, #high(MATM)
+	or3   r4, r4, #low(MATM)
+	ldi   r5, #0x01
+	st    r5, @r4            ; Set MATM Reg(T bit ON)
+	ld    r6, @r4            ; MATM Check
+	LDIMM (r5, 1f)
+	jmp   r5                 ; enable MMU
+	nop   
+	.fillinsn
+1:  
+;; ISN check
+	ld    r6, @r4            ; MATM Check
+	seth  r4, #high(M32R_ICU_ISTS_ADDR)
+	or3   r4, r4, #low(M32R_ICU_ISTS_ADDR)
+	ld    r5, @r4		; Read ISTSi reg.
+	mv    r6, r5
+	slli  r5, #13  ; PIML check
+	srli  r5, #13  ; 
+	seth  r4, #high(M32R_ICU_IMASK_ADDR)
+	or3   r4, r4, #low(M32R_ICU_IMASK_ADDR)
+	st    r5, @r4		; Write IMASKi reg.
+	slli  r6, #4   ; ISN check
+	srli  r6, #26  ; 
+	seth  r4, #high(M32R_IRQ_IPI5)
+	or3   r4, r4, #low(M32R_IRQ_IPI5)
+	bne   r4, r6, 2f  ; if (ISN != CPU_BOOT_IPI) goto sleep;
+	
+;; check cpu_bootout_map and set cpu_bootin_map
+	LDIMM (r4, cpu_bootout_map)
+	ld    r4, @r4
+	seth  r5, #high(M32R_CPUID_PORTL)
+	or3   r5, r5, #low(M32R_CPUID_PORTL)
+	ld    r5, @r5
+	ldi   r6, #1
+	sll   r6, r5
+	and   r4, r6
+	beqz  r4, 2f
+	LDIMM (r4, cpu_bootin_map)
+	ld    r5, @r4
+	or    r5, r6
+	st    r6, @r4
+	
+;; clear PSW
+	ldi   r4, #0
+	mvtc  r4, psw
+	
+;; setup SPI
+	LDIMM (r4, stack_start)
+	ld    r4, @r4
+	mvtc  r4, spi
+	
+;; setup BPC (start_secondary)
+	LDIMM (r4, start_secondary)
+	mvtc  r4, bpc
+	
+	rte  ; goto startup_secondary
+	nop
+	nop
+	
+	.fillinsn
+2:  
+	;; disable MMU
+	seth  r4, #high(MATM)
+	or3   r4, r4, #low(MATM)
+	ldi   r5, #0
+    	st    r5, @r4            ; Set MATM Reg(T bit OFF)
+    	ld    r6, @r4            ; MATM Check
+	LDIMM (r4, 3f)
+	seth  r5, #high(__PAGE_OFFSET)
+	or3   r5, r5, #low(__PAGE_OFFSET)
+	not   r5, r5
+	and   r4, r5
+	jmp   r4                 ; disable MMU
+	nop   
+	.fillinsn
+3:
+	;; SLEEP and wait IPI
+	LDIMM (r4, AP_loop)
+	seth  r5, #high(__PAGE_OFFSET)
+	or3   r5, r5, #low(__PAGE_OFFSET)
+	not   r5, r5
+	and   r4, r5
+	jmp   r4
+	nop
+	nop
+#endif  /* CONFIG_SMP */
+
+ENTRY(stack_start)
+	.long	init_thread_union+8192
+	.long	__KERNEL_DS
+
+/*
+ * This is initialized to create a identity-mapping at 0-4M (for bootup
+ * purposes) and another mapping of the 0-4M area at virtual address
+ * PAGE_OFFSET.
+ */
+	.text
+
+#define  MOUNT_ROOT_RDONLY    1
+#define  RAMDISK_FLAGS        0		; 1024KB
+#define  ORIG_ROOT_DEV        0x0100	; /dev/ram0 (major:01, minor:00)
+#define  LOADER_TYPE          1		; (??? - non-zero value seems 
+					; to be needed to boot from initrd)
+
+#define  COMMAND_LINE ""
+
+	.section	.empty_zero_page, "aw"
+ENTRY(empty_zero_page)
+	.long	MOUNT_ROOT_RDONLY		/* offset: +0x00 */
+	.long	RAMDISK_FLAGS
+	.long	ORIG_ROOT_DEV
+	.long	LOADER_TYPE
+	.long	0	/* INITRD_START */	/* +0x10 */
+	.long	0	/* INITRD_SIZE */
+	.long	0	/* CPU_CLOCK */
+	.long	0	/* BUS_CLOCK */
+	.long	0	/* TIMER_DIVIDE */	/* +0x20 */
+	.balign	256,0
+	.asciz	COMMAND_LINE
+  	.byte	0
+	.balign	4096,0,4096
+
+/*------------------------------------------------------------------------
+ * Stack area
+ */
+	.section .spi	
+	ALIGN
+	.global spi_stack_top
+	.zero	1024
+spi_stack_top:
+
+	.section .spu
+	ALIGN
+	.global spu_stack_top
+	.zero	1024
+spu_stack_top:
+
+	.end
diff -ruN linux-2.6.8.1.org/arch/m32r/kernel/init_task.c linux-2.6.8.1/arch/m32r/kernel/init_task.c
--- linux-2.6.8.1.org/arch/m32r/kernel/init_task.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.8.1/arch/m32r/kernel/init_task.c	2004-08-30 10:23:53.000000000 +0900
@@ -0,0 +1,41 @@
+/* orig : i386 init_task.c */
+
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/init_task.h>
+#include <linux/fs.h>
+#include <linux/mqueue.h>
+
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+
+static struct fs_struct init_fs = INIT_FS;
+static struct files_struct init_files = INIT_FILES;
+static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
+static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
+struct mm_struct init_mm = INIT_MM(init_mm);
+
+EXPORT_SYMBOL(init_mm);
+
+/*
+ * Initial thread structure.
+ *
+ * We need to make sure that this is 8192-byte aligned due to the
+ * way process stacks are handled. This is done by having a special
+ * "init_task" linker map entry..
+ */
+union thread_union init_thread_union 
+	__attribute__((__section__(".data.init_task"))) =
+		{ INIT_THREAD_INFO(init_task) };
+
+/*
+ * Initial task structure.
+ *
+ * All other task structs will be allocated on slabs in fork.c
+ */
+struct task_struct init_task = INIT_TASK(init_task);
+
+EXPORT_SYMBOL(init_task);
+
diff -ruN linux-2.6.8.1.org/arch/m32r/kernel/io_m32102.c linux-2.6.8.1/arch/m32r/kernel/io_m32102.c
--- linux-2.6.8.1.org/arch/m32r/kernel/io_m32102.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.8.1/arch/m32r/kernel/io_m32102.c	2003-09-09 10:15:02.000000000 +0900
@@ -0,0 +1,277 @@
+/* 
+ * Mitsubishi M32R 32102 group
+ * Typical I/O routines.
+ *
+ * Copyright (c) 2001 Hitoshi Yamamoto
+ */
+
+/* $Id$ */
+
+#include <linux/config.h>
+#include <asm/page.h>
+
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC)
+#include <linux/types.h>
+
+#define M32R_PCC_IOMAP_SIZE 0x1000
+
+#define M32R_PCC_IOSTART0 0x1000
+#define M32R_PCC_IOEND0   (M32R_PCC_IOSTART0 + M32R_PCC_IOMAP_SIZE - 1)
+#define M32R_PCC_IOSTART1 0x2000
+#define M32R_PCC_IOEND1   (M32R_PCC_IOSTART1 + M32R_PCC_IOMAP_SIZE - 1)
+
+extern void pcc_ioread(int, unsigned long, void *, size_t, size_t, int);
+extern void pcc_iowrite(int, unsigned long, void *, size_t, size_t, int);
+#endif /* CONFIG_PCMCIA && CONFIG_M32RPCC */
+
+
+/* 
+ * Function prototypes
+ */
+unsigned char  ne_inb(unsigned long);
+void  ne_outb(unsigned char, unsigned long);
+void  ne_insb(unsigned int, void *, unsigned long);
+void  ne_insw(unsigned int, void *, unsigned long);
+void  ne_outsb(unsigned int, const void *, unsigned long);
+void  ne_outsw(unsigned int, const void *, unsigned long);
+
+#define PORT2ADDR(port)  m32102_port2addr(port)
+
+static __inline__ unsigned long
+m32102_port2addr(unsigned long port)
+{
+	unsigned long  ul;
+	ul = port + PAGE_OFFSET + 0x20000000;
+	return (ul);
+}
+
+unsigned char
+m32102_inb(unsigned long port)
+{
+#ifdef CONFIG_PLAT_MAPPI
+	if(port >= 0x300 && port < 0x320)
+		return ne_inb(port);
+	else
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC)
+	if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+	   unsigned char b;
+	   pcc_ioread(0, port, &b, sizeof(b), 1, 0);
+	   return b;
+	} else 	if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
+	  unsigned char b;
+	   pcc_ioread(1, port, &b, sizeof(b), 1, 0);
+	   return b;
+	} else
+#endif
+#endif /*  CONFIG_PLAT_MAPPI  */
+	return *(unsigned char *)PORT2ADDR(port);
+}
+
+unsigned short
+m32102_inw(unsigned long port)
+{
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC)
+	if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+	   unsigned short w;
+	   pcc_ioread(0, port, &w, sizeof(w), 1, 0);
+	   return w;
+	} else 	if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
+	   unsigned short w;
+	   pcc_ioread(1, port, &w, sizeof(w), 1, 0);
+	   return w;
+	} else
+#endif
+	return *(unsigned short *)PORT2ADDR(port);
+}
+
+unsigned long
+m32102_inl(unsigned long port)
+{
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC)
+	if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+	   unsigned long l;
+	   pcc_ioread(0, port, &l, sizeof(l), 1, 0);
+	   return l;
+	} else 	if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
+	   unsigned short l;
+	   pcc_ioread(1, port, &l, sizeof(l), 1, 0);
+	   return l;
+	} else
+#endif
+	return *(unsigned long *)PORT2ADDR(port);
+}
+
+void
+m32102_outb(unsigned char b, unsigned long port)
+{
+#ifdef CONFIG_PLAT_MAPPI
+	if(port >= 0x300 && port < 0x320)
+		ne_outb(b,port);
+	else
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC)
+	if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+	   pcc_iowrite(0, port, &b, sizeof(b), 1, 0);
+	} else 	if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
+	   pcc_iowrite(1, port, &b, sizeof(b), 1, 0);
+	} else
+#endif
+#endif /*  CONFIG_PLAT_MAPPI  */
+	*(unsigned volatile char *)PORT2ADDR(port) = b;
+}
+
+void
+m32102_outw(unsigned short w, unsigned long port)
+{
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC)
+	if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+	   pcc_iowrite(0, port, &w, sizeof(w), 1, 0);
+	} else 	if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
+	   pcc_iowrite(1, port, &w, sizeof(w), 1, 0);
+	} else
+#endif
+*(unsigned volatile short *)PORT2ADDR(port) = w;
+}
+
+void
+m32102_outl(unsigned long l, unsigned long port)
+{
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC)
+	if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+	   pcc_iowrite(0, port, &l, sizeof(l), 1, 0);
+	} else 	if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
+	   pcc_iowrite(1, port, &l, sizeof(l), 1, 0);
+	} else
+#endif
+	*(unsigned volatile long *)PORT2ADDR(port) = l;
+}
+
+void
+m32102_insb(unsigned int port, void * addr, unsigned long count)
+{
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC)
+	if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+	   pcc_ioread(0, port, (void *)addr, sizeof(unsigned char), count, 1);
+	} else 	if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
+	   pcc_ioread(1, port, (void *)addr, sizeof(unsigned char), count, 1);
+	} else
+#endif
+	while(count--){
+		*(unsigned char *)addr = *(unsigned volatile char *)PORT2ADDR(port);
+		addr+=1;
+	}
+}
+
+void
+m32102_insw(unsigned int port, void * addr, unsigned long count) 
+{
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC)
+	if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+	   pcc_ioread(0, port, (void *)addr, sizeof(unsigned short), count, 1);
+	} else 	if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
+	   pcc_ioread(1, port, (void *)addr, sizeof(unsigned short), count, 1);
+	} else
+#endif
+while(count--){
+		*(unsigned short *)addr = *(unsigned volatile short *)PORT2ADDR(port);
+		addr+=2;
+	}
+}
+
+void
+m32102_outsb(unsigned int port, const void * addr, unsigned long count) 
+{
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC)
+	if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+	   pcc_iowrite(0, port, (void *)addr, sizeof(unsigned char), count, 1);
+	} else 	if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
+	   pcc_iowrite(1, port, (void *)addr, sizeof(unsigned char), count, 1);
+	} else
+#endif
+while(count--){
+		*(unsigned volatile char *)PORT2ADDR(port) = *(unsigned char *)addr;
+		addr+=1;
+	}
+}
+void
+m32102_outsw(unsigned int port, const void * addr, unsigned long count) 
+{
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC)
+	if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+	   pcc_iowrite(0, port, (void *)addr, sizeof(unsigned short), count, 1);
+	} else 	if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
+	   pcc_iowrite(1, port, (void *)addr, sizeof(unsigned short), count, 1);
+	} else
+#endif
+while(count--){
+		*(unsigned volatile short *)PORT2ADDR(port) = *(unsigned short *)addr;
+		addr+=2;
+	}
+}
+
+#ifdef CONFIG_PLAT_MAPPI
+unsigned char
+ne_inb(unsigned long port)
+{
+	unsigned short tmp;
+	port <<= 1;
+	port+= PAGE_OFFSET + 0x20000000 + 0x0c000000;
+	tmp = *(unsigned short *)port;
+	return (unsigned char)tmp;
+}
+void
+ne_outb(unsigned char b, unsigned long port)
+{
+	port <<= 1;
+	port += PAGE_OFFSET + 0x20000000 + 0x0c000000;
+	*(unsigned volatile short *)port = (unsigned short)b;
+}
+void
+ne_insb(unsigned int port, void * addr, unsigned long count) 
+{
+
+	unsigned short tmp;
+	port <<= 1;
+	port+= PAGE_OFFSET + 0x20000000 + 0x0c000000;
+	tmp = *(unsigned short *)port;
+	while(count--){
+		*(unsigned char *)addr = *(unsigned volatile char *)port;
+		addr+=1;
+	}
+}
+
+void
+ne_insw(unsigned int port, void * addr, unsigned long count) {
+	unsigned short tmp;
+	port <<= 1;
+	port+= PAGE_OFFSET + 0x20000000 + 0x0c000000;
+	while(count--){
+		tmp = *(unsigned volatile short *)port;
+		*(unsigned short *)addr = (tmp>>8) | (tmp <<8);
+		addr+=2;
+	}
+}
+
+void
+ne_outsb(unsigned int port, const void * addr, unsigned long count) 
+{
+	port <<= 1;
+	port += PAGE_OFFSET + 0x20000000 + 0x0c000000;
+	while(count--){
+		*(unsigned volatile short *)port = *(unsigned char *)addr;
+		addr+=1;
+	}
+}
+void
+ne_outsw(unsigned int port, const void * addr, unsigned long count) 
+{
+	unsigned short tmp;
+	port <<= 1;
+	port += PAGE_OFFSET + 0x20000000 + 0x0c000000;
+	while(count--){
+		tmp = *(unsigned short *)addr;
+		*(unsigned volatile short *)port = (tmp>>8)|(tmp<<8);
+		addr+=2;
+	}
+}
+
+#endif /*  CONFIG_PLAT_MAPPI  */
diff -ruN linux-2.6.8.1.org/arch/m32r/kernel/io_m32700ut.c linux-2.6.8.1/arch/m32r/kernel/io_m32700ut.c
--- linux-2.6.8.1.org/arch/m32r/kernel/io_m32700ut.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.8.1/arch/m32r/kernel/io_m32700ut.c	2004-08-23 20:53:31.000000000 +0900
@@ -0,0 +1,455 @@
+/*  
+ *  linux/arch/m32r/kernel/io_mappi.c
+ *   
+ *  Typical I/O routines for M32700UT board.
+ *  
+ *  Copyright (c) 2001, 2002  Hiroyuki Kondo, Hirokazu Takata, 
+ *                            Hitoshi Yamamoto, Takeo Takahashi
+ *
+ *  This file is subject to the terms and conditions of the GNU General
+ *  Public License.  See the file "COPYING" in the main directory of this
+ *  archive for more details.
+ *
+ */
+
+#include <linux/config.h>
+#include <asm/m32r.h>
+#include <asm/page.h>
+#include <asm/io.h>
+#include <asm/byteorder.h>
+
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+#include <linux/types.h>
+
+#define M32R_PCC_IOMAP_SIZE 0x1000
+
+#define M32R_PCC_IOSTART0 0x1000
+#define M32R_PCC_IOEND0   (M32R_PCC_IOSTART0 + M32R_PCC_IOMAP_SIZE - 1)
+
+extern void pcc_ioread_byte(int, unsigned long, void *, size_t, size_t, int);
+extern void pcc_ioread_word(int, unsigned long, void *, size_t, size_t, int);
+extern void pcc_iowrite_byte(int, unsigned long, void *, size_t, size_t, int);
+extern void pcc_iowrite_word(int, unsigned long, void *, size_t, size_t, int);
+#endif /* CONFIG_PCMCIA && CONFIG_M32R_CFC */
+
+#define PORT2ADDR(port)  _port2addr(port)
+#define PORT2ADDR_USB(port) _port2addr_usb(port)
+
+static __inline__ void *_port2addr(unsigned long port)
+{
+	return (void *)(port + NONCACHE_OFFSET);
+}
+
+#if defined(CONFIG_IDE)
+static __inline__ void *__port2addr_ata(unsigned long port)
+{
+	static int	dummy_reg;
+
+	switch (port) {
+	case 0x1f0:	return (void *)0xac002000;
+	case 0x1f1:	return (void *)0xac012800;
+	case 0x1f2:	return (void *)0xac012002;
+	case 0x1f3:	return (void *)0xac012802;
+	case 0x1f4:	return (void *)0xac012004;
+	case 0x1f5:	return (void *)0xac012804;
+	case 0x1f6:	return (void *)0xac012006;
+	case 0x1f7:	return (void *)0xac012806;
+	case 0x3f6:	return (void *)0xac01200e;
+	default: 	return (void *)&dummy_reg;
+	}
+}
+#endif
+
+/*
+ * M32700UT-LAN is located in the extended bus space
+ * from 0x10000000 to 0x13ffffff on physical address.
+ * The base address of LAN controller(LAN91C111) is 0x300.
+ */
+#define LAN_IOSTART	0x300
+#define LAN_IOEND	0x320
+static __inline__ void *_port2addr_ne(unsigned long port)
+{
+	return (void *)(port + NONCACHE_OFFSET + 0x10000000);
+}
+static __inline__ void *_port2addr_usb(unsigned long port)
+{
+  return (void *)((port & 0x0f) + NONCACHE_OFFSET + 0x10303000);
+}
+
+static __inline__ void delay(void)
+{
+	__asm__ __volatile__ ("push r0; \n\t pop r0;" : : :"memory");	
+}
+
+/* 
+ * NIC I/O function 
+ */
+
+#define PORT2ADDR_NE(port)  _port2addr_ne(port)
+
+static __inline__ unsigned char _ne_inb(void *portp)
+{
+	return *(volatile unsigned char *)portp;
+}
+
+static __inline__ unsigned short _ne_inw(void *portp)
+{
+	return (unsigned short)le16_to_cpu(*(volatile unsigned short *)portp);
+}
+
+static __inline__ void _ne_insb(void *portp, void * addr, unsigned long count) 
+{
+	unsigned char *buf = (unsigned char *)addr;
+	
+	while (count--) *buf++ = _ne_inb(portp);
+}
+
+static __inline__ void _ne_outb(unsigned char b, void *portp)
+{
+	*(volatile unsigned char *)portp = b;
+}
+
+static __inline__ void _ne_outw(unsigned short w, void *portp)
+{
+	*(volatile unsigned short *)portp = cpu_to_le16(w);
+}
+
+unsigned char _inb(unsigned long port)
+{
+	if (port >= LAN_IOSTART && port < LAN_IOEND)
+		return _ne_inb(PORT2ADDR_NE(port));
+
+#if defined(CONFIG_IDE)
+	else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+		return *(volatile unsigned char *)__port2addr_ata(port);
+	}
+#endif
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+	else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+	   unsigned char b;
+	   pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0);
+	   return b;
+	} else
+#endif
+
+	return *(volatile unsigned char *)PORT2ADDR(port);
+}
+
+unsigned short _inw(unsigned long port)
+{
+	if (port >= LAN_IOSTART && port < LAN_IOEND)
+		return _ne_inw(PORT2ADDR_NE(port));
+#if defined(CONFIG_IDE)
+	else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+		return *(volatile unsigned short *)__port2addr_ata(port);
+	}
+#endif
+#if defined(CONFIG_USB)
+	else if(port >= 0x340 && port < 0x3a0)
+	  return *(volatile unsigned short *)PORT2ADDR_USB(port);
+#endif
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+	else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+	   unsigned short w;
+	   pcc_ioread_word(0, port, &w, sizeof(w), 1, 0);
+	   return w;
+	} else
+#endif
+	return *(volatile unsigned short *)PORT2ADDR(port);
+}
+
+unsigned long _inl(unsigned long port)
+{
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+	if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+	   unsigned long l;
+	   pcc_ioread_word(0, port, &l, sizeof(l), 1, 0);
+	   return l;
+	} else
+#endif
+	return *(volatile unsigned long *)PORT2ADDR(port);
+}
+
+unsigned char _inb_p(unsigned long port)
+{
+	unsigned char  v;
+	
+	if (port >= LAN_IOSTART && port < LAN_IOEND)
+		v = _ne_inb(PORT2ADDR_NE(port));
+	else
+#if defined(CONFIG_IDE)
+	if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+		return *(volatile unsigned char *)__port2addr_ata(port);
+	} else
+#endif
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+	if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+	   unsigned char b;
+	   pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0);
+	   return b;
+	} else
+#endif
+		v = *(volatile unsigned char *)PORT2ADDR(port);
+	
+	delay();
+	return (v);
+}
+
+unsigned short _inw_p(unsigned long port)
+{
+	unsigned short  v;
+	
+	if (port >= LAN_IOSTART && port < LAN_IOEND)
+		v = _ne_inw(PORT2ADDR_NE(port));
+	else
+#if defined(CONFIG_IDE)
+	if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+		return *(volatile unsigned short *)__port2addr_ata(port);
+	} else
+#endif
+#if defined(CONFIG_USB)
+	  if(port >= 0x340 && port < 0x3a0)
+	    return *(volatile unsigned short *)PORT2ADDR_USB(port);
+	else
+#endif
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+	if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+	   unsigned short w;
+	   pcc_ioread_word(0, port, &w, sizeof(w), 1, 0);
+	   return w;
+	} else
+#endif
+		v = *(volatile unsigned short *)PORT2ADDR(port);
+	
+	delay();
+	return (v);
+}
+
+unsigned long _inl_p(unsigned long port)
+{
+	unsigned long  v;
+	
+	v = *(volatile unsigned long *)PORT2ADDR(port);
+	delay();
+	return (v);
+}
+
+void _outb(unsigned char b, unsigned long port)
+{
+	if (port >= LAN_IOSTART && port < LAN_IOEND)
+		_ne_outb(b, PORT2ADDR_NE(port));
+	else
+#if defined(CONFIG_IDE)
+	if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+		*(volatile unsigned char *)__port2addr_ata(port) = b;
+	} else
+#endif
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+	if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+	   pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0);
+	} else
+#endif
+		*(volatile unsigned char *)PORT2ADDR(port) = b;
+}
+
+void _outw(unsigned short w, unsigned long port)
+{
+	if (port >= LAN_IOSTART && port < LAN_IOEND)
+		_ne_outw(w, PORT2ADDR_NE(port));
+	else
+#if defined(CONFIG_IDE)
+	if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+		*(volatile unsigned short *)__port2addr_ata(port) = w;
+	} else
+#endif
+#if defined(CONFIG_USB)
+	if(port >= 0x340 && port < 0x3a0)
+	  *(volatile unsigned short *)PORT2ADDR_USB(port) = w;
+	else
+#endif
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+	if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+	   pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0);
+	} else
+#endif
+		*(volatile unsigned short *)PORT2ADDR(port) = w;
+}
+
+void _outl(unsigned long l, unsigned long port)
+{
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+	if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+	   pcc_iowrite_word(0, port, &l, sizeof(l), 1, 0);
+	} else
+#endif
+	*(volatile unsigned long *)PORT2ADDR(port) = l;
+}
+
+void _outb_p(unsigned char b, unsigned long port)
+{
+	if (port >= LAN_IOSTART && port < LAN_IOEND)
+		_ne_outb(b, PORT2ADDR_NE(port));
+	else
+#if defined(CONFIG_IDE)
+	if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+		*(volatile unsigned char *)__port2addr_ata(port) = b;
+	} else
+#endif
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+	if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+	   pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0);
+	} else
+#endif
+		*(volatile unsigned char *)PORT2ADDR(port) = b;
+	
+	delay();
+}
+
+void _outw_p(unsigned short w, unsigned long port)
+{
+	if (port >= LAN_IOSTART && port < LAN_IOEND)
+		_ne_outw(w, PORT2ADDR_NE(port));
+	else
+#if defined(CONFIG_IDE)
+	if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+		*(volatile unsigned short *)__port2addr_ata(port) = w;
+	} else
+#endif
+#if defined(CONFIG_USB)
+	  if(port >= 0x340 && port < 0x3a0)
+	    *(volatile unsigned short *)PORT2ADDR_USB(port) = w;
+	else
+#endif
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+	if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+	   pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0);
+	} else
+#endif
+		*(volatile unsigned short *)PORT2ADDR(port) = w;
+	
+	delay();
+}
+
+void _outl_p(unsigned long l, unsigned long port)
+{
+	*(volatile unsigned long *)PORT2ADDR(port) = l;
+	delay();
+}
+
+void _insb(unsigned int port, void * addr, unsigned long count)
+{
+	if (port >= LAN_IOSTART && port < LAN_IOEND)
+		_ne_insb(PORT2ADDR_NE(port), addr, count);
+#if defined(CONFIG_IDE)
+	else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+		unsigned char *buf = addr;
+		unsigned char *portp = __port2addr_ata(port);
+		while(count--) *buf++ = *(volatile unsigned char *)portp;
+	}
+#endif
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+	  else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+	   pcc_ioread_byte(0, port, (void *)addr, sizeof(unsigned char), count, 1);
+	} 
+#endif
+	else {
+		unsigned char *buf = addr;
+		unsigned char *portp = PORT2ADDR(port);
+		while(count--) *buf++ = *(volatile unsigned char *)portp;
+	}
+}
+
+void _insw(unsigned int port, void * addr, unsigned long count)
+{
+	unsigned short *buf = addr;
+	unsigned short *portp;
+
+	if (port >= LAN_IOSTART && port < LAN_IOEND) {
+		/*
+		 * This portion is only used by smc91111.c to read data
+		 * from the DATA_REG. Do not swap the data.
+		 */
+		portp = PORT2ADDR_NE(port);
+		while (count--) *buf++ = *(volatile unsigned short *)portp;
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+	} else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+	   pcc_ioread_word(9, port, (void *)addr, sizeof(unsigned short), count, 1);
+#endif
+#if defined(CONFIG_IDE)
+	} else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+		portp = __port2addr_ata(port);
+		while (count--) *buf++ = *(volatile unsigned short *)portp;
+#endif
+	} else {
+		portp = PORT2ADDR(port);
+		while (count--) *buf++ = *(volatile unsigned short *)portp;
+	}
+}
+
+void _insl(unsigned int port, void * addr, unsigned long count)
+{
+	unsigned long *buf = addr;
+	unsigned long *portp;
+
+	portp = PORT2ADDR(port);
+	while (count--) *buf++ = *(volatile unsigned long *)portp;
+}
+
+void _outsb(unsigned int port, const void * addr, unsigned long count)
+{
+	const unsigned char *buf = addr;
+	unsigned char *portp;
+
+	if (port >= LAN_IOSTART && port < LAN_IOEND) {
+		portp = PORT2ADDR_NE(port);
+		while (count--) _ne_outb(*buf++, portp);
+#if defined(CONFIG_IDE)
+	} else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+		portp = __port2addr_ata(port);
+		while(count--) *(volatile unsigned char *)portp = *buf++;
+#endif
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+	} else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+	   pcc_iowrite_byte(0, port, (void *)addr, sizeof(unsigned char), count, 1);
+#endif
+	} else {
+		portp = PORT2ADDR(port);
+		while(count--) *(volatile unsigned char *)portp = *buf++;
+	}
+}
+
+void _outsw(unsigned int port, const void * addr, unsigned long count)
+{
+	const unsigned short *buf = addr;
+	unsigned short *portp;
+
+	if (port >= LAN_IOSTART && port < LAN_IOEND) {
+		/*
+		 * This portion is only used by smc91111.c to write data
+		 * into the DATA_REG. Do not swap the data.
+		 */
+		portp = PORT2ADDR_NE(port);
+		while(count--) *(volatile unsigned short *)portp = *buf++;
+#if defined(CONFIG_IDE)
+	} else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+		portp = __port2addr_ata(port);
+		while(count--) *(volatile unsigned short *)portp = *buf++;
+#endif
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+	} else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+	   pcc_iowrite_word(9, port, (void *)addr, sizeof(unsigned short), count, 1);
+#endif
+	} else {
+		portp = PORT2ADDR(port);
+		while(count--) *(volatile unsigned short *)portp = *buf++;
+	}
+}
+
+void _outsl(unsigned int port, const void * addr, unsigned long count)
+{
+	const unsigned long *buf = addr;
+	unsigned char *portp;
+
+	portp = PORT2ADDR(port);
+	while(count--) *(volatile unsigned long *)portp = *buf++;
+}
diff -ruN linux-2.6.8.1.org/arch/m32r/kernel/io_mappi.c linux-2.6.8.1/arch/m32r/kernel/io_mappi.c
--- linux-2.6.8.1.org/arch/m32r/kernel/io_mappi.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.8.1/arch/m32r/kernel/io_mappi.c	2004-06-22 18:42:09.000000000 +0900
@@ -0,0 +1,368 @@
+/*  
+ *  linux/arch/m32r/kernel/io_mappi.c
+ *   
+ *  Typical I/O routines for Mappi board.
+ *  
+ *  Copyright (c) 2001, 2002  Hiroyuki Kondo, Hirokazu Takata, 
+ *                            Hitoshi Yamamoto
+ */
+
+/* $Id: io_mappi.c,v 1.9 2003/12/02 07:18:08 fujiwara Exp $ */
+
+#include <linux/config.h>
+#include <asm/m32r.h>
+#include <asm/page.h>
+#include <asm/io.h>
+#include <asm/byteorder.h>
+
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC)
+#include <linux/types.h>
+
+#define M32R_PCC_IOMAP_SIZE 0x1000
+
+#define M32R_PCC_IOSTART0 0x1000
+#define M32R_PCC_IOEND0   (M32R_PCC_IOSTART0 + M32R_PCC_IOMAP_SIZE - 1)
+#define M32R_PCC_IOSTART1 0x2000
+#define M32R_PCC_IOEND1   (M32R_PCC_IOSTART1 + M32R_PCC_IOMAP_SIZE - 1)
+
+extern void pcc_ioread(int, unsigned long, void *, size_t, size_t, int);
+extern void pcc_iowrite(int, unsigned long, void *, size_t, size_t, int);
+#endif /* CONFIG_PCMCIA && CONFIG_M32RPCC */
+
+#define PORT2ADDR(port)  _port2addr(port)
+
+static __inline__ void *_port2addr(unsigned long port)
+{
+	return (void *)(port + NONCACHE_OFFSET);
+}
+
+static __inline__ void *_port2addr_ne(unsigned long port)
+{
+	return (void *)((port<<1) + NONCACHE_OFFSET + 0x0C000000);
+}
+
+static __inline__ void delay(void)
+{
+	__asm__ __volatile__ ("push r0; \n\t pop r0;" : : :"memory");	
+}
+
+/* 
+ * NIC I/O function 
+ */
+
+#define PORT2ADDR_NE(port)  _port2addr_ne(port)
+
+static __inline__ unsigned char _ne_inb(void *portp)
+{
+	return (unsigned char) *(volatile unsigned short *)portp;
+}
+
+static __inline__ unsigned short _ne_inw(void *portp)
+{
+	unsigned short tmp;
+	
+	tmp = *(volatile unsigned short *)portp;
+	return le16_to_cpu(tmp);
+}
+
+static __inline__ void _ne_outb(unsigned char b, void *portp)
+{
+	*(volatile unsigned short *)portp = (unsigned short)b;
+}
+
+static __inline__ void _ne_outw(unsigned short w, void *portp)
+{
+	*(volatile unsigned short *)portp = cpu_to_le16(w);
+}
+
+unsigned char _inb(unsigned long port)
+{
+	if (port >= 0x300 && port < 0x320)
+		return _ne_inb(PORT2ADDR_NE(port));
+	else
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC)
+        if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+	   unsigned char b;
+	   pcc_ioread(0, port, &b, sizeof(b), 1, 0);
+	   return b;
+	} else 	if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
+	  unsigned char b;
+	   pcc_ioread(1, port, &b, sizeof(b), 1, 0);
+	   return b;
+	} else
+#endif
+
+	return *(volatile unsigned char *)PORT2ADDR(port);
+}
+
+unsigned short _inw(unsigned long port)
+{
+	if (port >= 0x300 && port < 0x320)
+		return _ne_inw(PORT2ADDR_NE(port));
+	else
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC)
+	if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+	   unsigned short w;
+	   pcc_ioread(0, port, &w, sizeof(w), 1, 0);
+	   return w;
+	} else 	if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
+	   unsigned short w;
+	   pcc_ioread(1, port, &w, sizeof(w), 1, 0);
+	   return w;
+	} else
+#endif
+	return *(volatile unsigned short *)PORT2ADDR(port);
+}
+
+unsigned long _inl(unsigned long port)
+{
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC)
+	if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+	   unsigned long l;
+	   pcc_ioread(0, port, &l, sizeof(l), 1, 0);
+	   return l;
+	} else 	if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
+	   unsigned short l;
+	   pcc_ioread(1, port, &l, sizeof(l), 1, 0);
+	   return l;
+	} else
+#endif
+	return *(volatile unsigned long *)PORT2ADDR(port);
+}
+
+unsigned char _inb_p(unsigned long port)
+{
+	unsigned char  v;
+	
+	if (port >= 0x300 && port < 0x320)
+		v = _ne_inb(PORT2ADDR_NE(port));
+	else
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC)
+	if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+	   unsigned char b;
+	   pcc_ioread(0, port, &b, sizeof(b), 1, 0);
+	   return b;
+	} else 	if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
+	  unsigned char b;
+	   pcc_ioread(1, port, &b, sizeof(b), 1, 0);
+	   return b;
+	} else
+#endif
+		v = *(volatile unsigned char *)PORT2ADDR(port);
+	
+	delay();
+	return (v);
+}
+
+unsigned short _inw_p(unsigned long port)
+{
+	unsigned short  v;
+	
+	if (port >= 0x300 && port < 0x320)
+		v = _ne_inw(PORT2ADDR_NE(port));
+	else
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC)
+	if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+	   unsigned short w;
+	   pcc_ioread(0, port, &w, sizeof(w), 1, 0);
+	   return w;
+	} else 	if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
+	   unsigned short w;
+	   pcc_ioread(1, port, &w, sizeof(w), 1, 0);
+	   return w;
+	} else
+#endif
+		v = *(volatile unsigned short *)PORT2ADDR(port);
+	
+	delay();
+	return (v);
+}
+
+unsigned long _inl_p(unsigned long port)
+{
+	unsigned long  v;
+	
+	v = *(volatile unsigned long *)PORT2ADDR(port);
+	delay();
+	return (v);
+}
+
+void _outb(unsigned char b, unsigned long port)
+{
+	if (port >= 0x300 && port < 0x320)
+		_ne_outb(b, PORT2ADDR_NE(port));
+	else
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC)
+	if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+	   pcc_iowrite(0, port, &b, sizeof(b), 1, 0);
+	} else 	if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
+	   pcc_iowrite(1, port, &b, sizeof(b), 1, 0);
+	} else
+#endif
+		*(volatile unsigned char *)PORT2ADDR(port) = b;
+}
+
+void _outw(unsigned short w, unsigned long port)
+{
+	if (port >= 0x300 && port < 0x320)
+		_ne_outw(w, PORT2ADDR_NE(port));
+	else
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC)
+	if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+	   pcc_iowrite(0, port, &w, sizeof(w), 1, 0);
+	} else 	if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
+	   pcc_iowrite(1, port, &w, sizeof(w), 1, 0);
+	} else
+#endif
+		*(volatile unsigned short *)PORT2ADDR(port) = w;
+}
+
+void _outl(unsigned long l, unsigned long port)
+{
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC)
+	if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+	   pcc_iowrite(0, port, &l, sizeof(l), 1, 0);
+	} else 	if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
+	   pcc_iowrite(1, port, &l, sizeof(l), 1, 0);
+	} else
+#endif
+	*(volatile unsigned long *)PORT2ADDR(port) = l;
+}
+
+void _outb_p(unsigned char b, unsigned long port)
+{
+	if (port >= 0x300 && port < 0x320)
+		_ne_outb(b, PORT2ADDR_NE(port));
+	else
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC)
+	if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+	   pcc_iowrite(0, port, &b, sizeof(b), 1, 0);
+	} else 	if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
+	   pcc_iowrite(1, port, &b, sizeof(b), 1, 0);
+	} else
+#endif
+		*(volatile unsigned char *)PORT2ADDR(port) = b;
+	
+	delay();
+}
+
+void _outw_p(unsigned short w, unsigned long port)
+{
+	if (port >= 0x300 && port < 0x320)
+		_ne_outw(w, PORT2ADDR_NE(port));
+	else
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC)
+	if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+	   pcc_iowrite(0, port, &w, sizeof(w), 1, 0);
+	} else 	if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
+	   pcc_iowrite(1, port, &w, sizeof(w), 1, 0);
+	} else
+#endif
+		*(volatile unsigned short *)PORT2ADDR(port) = w;
+	
+	delay();
+}
+
+void _outl_p(unsigned long l, unsigned long port)
+{
+	*(volatile unsigned long *)PORT2ADDR(port) = l;
+	delay();
+}
+
+void _insb(unsigned int port, void * addr, unsigned long count)
+{
+	unsigned short *buf = addr;
+	unsigned short *portp;
+
+	if (port >= 0x300 && port < 0x320){
+		portp = PORT2ADDR_NE(port);
+		while(count--) *buf++ = *(volatile unsigned char *)portp;
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC)
+	} else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+	   pcc_ioread(0, port, (void *)addr, sizeof(unsigned char), count, 1);
+	} else 	if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
+	   pcc_ioread(1, port, (void *)addr, sizeof(unsigned char), count, 1);
+#endif	
+	} else {
+		portp = PORT2ADDR(port);
+		while(count--) *buf++ = *(volatile unsigned char *)portp;
+	}
+}
+
+void _insw(unsigned int port, void * addr, unsigned long count)
+{
+	unsigned short *buf = addr;
+	unsigned short *portp;
+
+	if (port >= 0x300 && port < 0x320) {
+		portp = PORT2ADDR_NE(port);
+		while (count--) *buf++ = _ne_inw(portp);
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC)
+	} else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+	   pcc_ioread(0, port, (void *)addr, sizeof(unsigned short), count, 1);
+	} else 	if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
+	   pcc_ioread(1, port, (void *)addr, sizeof(unsigned short), count, 1);
+#endif
+	} else {
+		portp = PORT2ADDR(port);
+		while (count--) *buf++ = *(volatile unsigned short *)portp;
+	}
+}
+
+void _insl(unsigned int port, void * addr, unsigned long count)
+{
+	unsigned long *buf = addr;
+	unsigned long *portp;
+
+	portp = PORT2ADDR(port);
+	while (count--) *buf++ = *(volatile unsigned long *)portp;
+}
+
+void _outsb(unsigned int port, const void * addr, unsigned long count)
+{
+	const unsigned char *buf = addr;
+	unsigned char *portp;
+
+	if (port >= 0x300 && port < 0x320) {
+		portp = PORT2ADDR_NE(port);
+		while (count--) _ne_outb(*buf++, portp);
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC)
+	} else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+	   pcc_iowrite(0, port, (void *)addr, sizeof(unsigned char), count, 1);
+	} else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
+	   pcc_iowrite(1, port, (void *)addr, sizeof(unsigned char), count, 1);
+#endif
+	} else {
+		portp = PORT2ADDR(port);
+		while(count--) *(volatile unsigned char *)portp = *buf++;
+	}
+}
+
+void _outsw(unsigned int port, const void * addr, unsigned long count)
+{
+	const unsigned short *buf = addr;
+	unsigned short *portp;
+
+	if (port >= 0x300 && port < 0x320) {
+		portp = PORT2ADDR_NE(port);
+		while (count--) _ne_outw(*buf++, portp);
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC)
+	} else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+	   pcc_iowrite(0, port, (void *)addr, sizeof(unsigned short), count, 1);
+	} else 	if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
+	   pcc_iowrite(1, port, (void *)addr, sizeof(unsigned short), count, 1);
+#endif
+	} else {
+		portp = PORT2ADDR(port);
+		while(count--) *(volatile unsigned short *)portp = *buf++;
+	}
+}
+
+void _outsl(unsigned int port, const void * addr, unsigned long count)
+{
+	const unsigned long *buf = addr;
+	unsigned char *portp;
+
+	portp = PORT2ADDR(port);
+	while(count--) *(volatile unsigned long *)portp = *buf++;
+}
diff -ruN linux-2.6.8.1.org/arch/m32r/kernel/io_mappi2.c linux-2.6.8.1/arch/m32r/kernel/io_mappi2.c
--- linux-2.6.8.1.org/arch/m32r/kernel/io_mappi2.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.8.1/arch/m32r/kernel/io_mappi2.c	2004-06-22 18:42:09.000000000 +0900
@@ -0,0 +1,367 @@
+/*  
+ *  linux/arch/m32r/kernel/io_mappi2.c
+ *   
+ *  Typical I/O routines for Mappi2 board.
+ *  
+ *  Copyright (c) 2001-2003  Hiroyuki Kondo, Hirokazu Takata, 
+ *                            Hitoshi Yamamoto, Mamoru Sakugawa
+ */
+
+/* $Id:$ */
+
+#include <linux/config.h>
+#include <asm/m32r.h>
+#include <asm/page.h>
+#include <asm/io.h>
+
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+#include <linux/types.h>
+
+#define M32R_PCC_IOMAP_SIZE 0x1000
+
+#define M32R_PCC_IOSTART0 0x1000
+#define M32R_PCC_IOEND0   (M32R_PCC_IOSTART0 + M32R_PCC_IOMAP_SIZE - 1)
+
+extern void pcc_ioread_byte(int, unsigned long, void *, size_t, size_t, int);
+extern void pcc_ioread_word(int, unsigned long, void *, size_t, size_t, int);
+extern void pcc_iowrite_byte(int, unsigned long, void *, size_t, size_t, int);
+extern void pcc_iowrite_word(int, unsigned long, void *, size_t, size_t, int);
+#endif /* CONFIG_PCMCIA && CONFIG_MAPPI2_CFC */
+
+#define PORT2ADDR(port)      _port2addr(port)
+#define PORT2ADDR_NE(port)   _port2addr_ne(port)
+#define PORT2ADDR_USB(port)  _port2addr_usb(port)
+
+static __inline__ void *_port2addr(unsigned long port)
+{
+	return (void *)(port + NONCACHE_OFFSET);
+}
+#ifdef CONFIG_CHIP_OPSP
+static __inline__ void *_port2addr_ne(unsigned long port)
+{
+	return (void *)(port + NONCACHE_OFFSET + 0x10000000);
+}
+#else
+static __inline__ void *_port2addr_ne(unsigned long port)
+{
+	return (void *)(port + NONCACHE_OFFSET + 0x04000000);
+}
+#endif
+static __inline__ void *_port2addr_usb(unsigned long port)
+{
+	return (void *)(port + NONCACHE_OFFSET + 0x14000000);
+}
+static __inline__ void delay(void)
+{
+	__asm__ __volatile__ ("push r0; \n\t pop r0;" : : :"memory");	
+}
+
+/* 
+ * NIC I/O function 
+ */
+
+static __inline__ unsigned char _ne_inb(void *portp)
+{
+	return (unsigned char) *(volatile unsigned char *)portp;
+}
+
+static __inline__ unsigned short _ne_inw(void *portp)
+{
+#if 1  /* byte swap */
+	unsigned short tmp,tmp2;
+	tmp = *(volatile unsigned short *)portp;
+	tmp2 = (tmp>>8|tmp<<8);
+	return tmp2;
+#else
+	return *(volatile unsigned short *)portp;
+#endif
+}
+
+static __inline__ void _ne_insb(void *portp, void * addr, unsigned long count) 
+{
+	unsigned short tmp;
+	unsigned char *buf = addr;
+	
+	tmp = *(volatile unsigned char *)portp;
+	while (count--) *buf++ = *(volatile unsigned char *)portp;
+}
+
+static __inline__ void _ne_outb(unsigned char b, void *portp)
+{
+	*(volatile unsigned char *)portp = (unsigned char)b;
+}
+
+static __inline__ void _ne_outw(unsigned short w, void *portp)
+{
+	*(volatile unsigned short *)portp = (w>>8|w<<8);
+}
+
+unsigned char _inb(unsigned long port)
+{
+	if (port >= 0x300 && port < 0x320)
+		return _ne_inb(PORT2ADDR_NE(port));
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+	else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+	   unsigned char b;
+	   pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0);
+	   return b;
+	} else
+#endif
+
+	return *(volatile unsigned char *)PORT2ADDR(port);
+}
+
+unsigned short _inw(unsigned long port)
+{
+	if (port >= 0x300 && port < 0x320)
+		return _ne_inw(PORT2ADDR_NE(port));
+#if defined(CONFIG_USB)
+        else if (port >= 0x340 && port < 0x3a0)
+	  return *(volatile unsigned short *)PORT2ADDR_USB(port);
+#endif
+	
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+	  else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+	   unsigned short w;
+	   pcc_ioread_word(0, port, &w, sizeof(w), 1, 0);
+	   return w;
+	} else
+#endif
+	return *(volatile unsigned short *)PORT2ADDR(port);
+}
+
+unsigned long _inl(unsigned long port)
+{
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+	if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+	   unsigned long l;
+	   pcc_ioread_word(0, port, &l, sizeof(l), 1, 0);
+	   return l;
+	} else
+#endif
+	return *(volatile unsigned long *)PORT2ADDR(port);
+}
+
+unsigned char _inb_p(unsigned long port)
+{
+	unsigned char  v;
+	
+	if (port >= 0x300 && port < 0x320)
+		v = _ne_inb(PORT2ADDR_NE(port));
+	else
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+	if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+	 
