diff -ruN linux-2.6.0.org/arch/m32r/Kconfig linux-2.6.0/arch/m32r/Kconfig
--- linux-2.6.0.org/arch/m32r/Kconfig	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.0/arch/m32r/Kconfig	2004-03-16 19:34:57.000000000 +0900
@@ -0,0 +1,581 @@
+#
+# 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 MMU
+	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 "Mappi1"
+
+config PLAT_USRV
+	bool "uServer"
+
+config PLAT_M32700UT
+	bool "M32700UT"
+
+endchoice
+
+choice
+	prompt "Processor family"
+	default CHIP_M32700
+
+config CHIP_M32700
+	bool "M32700 (Chaos)"
+
+endchoice
+
+config ISA_M32R2
+	bool
+	depends on CHIP_M32700
+	default y
+
+config ISA_DSP_LEVEL2
+	bool
+	depends on CHIP_M32700
+	default y
+
+config ISA_DUAL_ISSUE
+	bool
+	depends on CHIP_M32700
+	default y
+
+config HAVE_M32R_MMU
+	bool
+	depends on CHIP_M32700
+	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
+
+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"
+
+config MEMORY_SIZE
+	hex "Physical memory size (hex)"
+	default "04000000" if PLAT_MAPPI
+	default "02000000" if PLAT_USRV
+	default "01000000" if PLAT_M32700UT
+
+config NOHIGHMEM
+	bool
+	default y
+
+config DISCONTIGMEM
+	bool "Internal RAM Support"
+	depends on CHIP_M32700
+	default y
+
+config IRAM_START
+	hex "Internal memory start address (hex)"
+	default "00f00000"
+	depends on (CHIP_M32700 && DISCONTIGMEM)
+
+config IRAM_SIZE
+	hex "Internal memory size (hex)"
+	default "00080000"
+	depends on (CHIP_M32700 && DISCONTIGMEM)
+
+#
+# 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 "M32700 TS1 chip bug"
+	depends on (CHIP_M32700 && SMP)
+	default n
+
+config NR_CPUS
+	int "Maximum number of CPUs (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"
+
+config HOTPLUG
+	bool "Support for hot-pluggable devices"
+	---help---
+	  Say Y here if you want to plug devices into your computer while
+	  the system is running, and be able to use them quickly.  In many
+	  cases, the devices can likewise be unplugged at any time too.
+
+	  One well known example of this is PCMCIA- or PC-cards, credit-card
+	  size devices such as network cards, modems or hard drives which are
+	  plugged into slots found on all modern laptop computers.  Another
+	  example, used on modern desktops as well as laptops, is USB.
+
+	  Enable HOTPLUG and KMOD, and build a modular kernel.  Get agent
+	  software (at <http://linux-hotplug.sourceforge.net/>) and install it.
+	  Then your kernel will automatically call out to a user mode "policy
+	  agent" (/sbin/hotplug) to load modules and set up software needed
+	  to use devices as you hotplug them.
+
+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"
+
+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_HIGHMEM
+	bool "Highmem debugging"
+	depends on DEBUG_KERNEL && HIGHMEM
+	help
+	  This options enables addition error checking for high memory systems.
+	  Disable for production systems.
+
+config KALLSYMS
+	bool "Load all symbols for debugging/kksymoops"
+	help
+	  Say Y here to let the kernel print out symbolic crash information and
+	  symbolic stack backtraces. This increases the size of the kernel
+	  somewhat, as all symbols have to be loaded into the kernel image.
+
+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.0.org/arch/m32r/Makefile linux-2.6.0/arch/m32r/Makefile
--- linux-2.6.0.org/arch/m32r/Makefile	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.0/arch/m32r/Makefile	2004-02-04 18:57:33.000000000 +0900
@@ -0,0 +1,29 @@
+#
+# m32r/Makefile
+# 
+
+LDFLAGS		:=
+OBJCOPYFLAGS	:= -O binary -R .note -R .comment -S
+LDFLAGS_vmlinux	:= -e startup_32
+LDFLAGS_BLOB	:= --format binary --oformat elf32-m32r
+
+CFLAGS += -g -pipe -fno-schedule-insns
+CFLAGS_KERNEL += -mmodel=medium
+CFLAGS_MODULE += -mmodel=large
+
+cflags-$(CONFIG_CHIP_M32700)	+= -DNO_FPU -m32r2
+aflags-$(CONFIG_CHIP_M32700)	+= -DNO_FPU -m32r2
+
+CFLAGS += $(cflags-y)
+AFLAGS += $(aflags-y)
+
+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/	\
+	   arch/m32r/drivers/
+
diff -ruN linux-2.6.0.org/arch/m32r/boot/Makefile linux-2.6.0/arch/m32r/boot/Makefile
--- linux-2.6.0.org/arch/m32r/boot/Makefile	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.0/arch/m32r/boot/Makefile	2003-09-09 10:15:02.000000000 +0900
@@ -0,0 +1,6 @@
+#
+# arch/m32r/boot/Makefile
+#
+
+obj-y	:= setup.o
+
diff -ruN linux-2.6.0.org/arch/m32r/boot/compressed/Makefile linux-2.6.0/arch/m32r/boot/compressed/Makefile
--- linux-2.6.0.org/arch/m32r/boot/compressed/Makefile	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.0/arch/m32r/boot/compressed/Makefile	2003-09-09 10:15:02.000000000 +0900
@@ -0,0 +1,36 @@
+#
+# linux/arch/sh/boot/compressed/Makefile
+#
+# create a compressed vmlinux image from the original vmlinux
+#
+
+.S.o:
+	$(CC) $(AFLAGS) -traditional -c $< -o $*.o
+
+HEAD = head.o
+SYSTEM = $(TOPDIR)/vmlinux
+
+OBJECTS = $(HEAD) misc.o m32r_sio.o
+
+ZLDFLAGS = -e startup
+ZLINKFLAGS = $(ZLDFLAGS)
+
+all: vmlinux
+
+vmlinux: piggy.o $(OBJECTS) vmlinux.lds
+	$(LD) $(ZLINKFLAGS) -o vmlinux $(OBJECTS) piggy.o -T vmlinux.lds
+
+piggy.o: $(SYSTEM)
+	$(OBJCOPY) $(SYSTEM) piggy
+	gzip -f -9 < piggy > piggy.gz
+	$(LD) -r -o $@ -b binary piggy.gz
+
+vmlinux.lds: vmlinux.lds.S
+	$(CPP) $(AFLAGS) -traditional -C -P -I$(HPATH) \
+	    vmlinux.lds.S > vmlinux.lds
+
+clean:
+	rm -f vmlinux piggy.o piggy.gz $(OBJECTS)
+
+include $(TOPDIR)/Rules.make
+
diff -ruN linux-2.6.0.org/arch/m32r/boot/compressed/boot.h linux-2.6.0/arch/m32r/boot/compressed/boot.h
--- linux-2.6.0.org/arch/m32r/boot/compressed/boot.h	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.0/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.0.org/arch/m32r/boot/compressed/head.S linux-2.6.0/arch/m32r/boot/compressed/head.S
--- linux-2.6.0.org/arch/m32r/boot/compressed/head.S	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.0/arch/m32r/boot/compressed/head.S	2004-03-16 19:34:57.000000000 +0900
@@ -0,0 +1,193 @@
+/*
+ *  linux/arch/m32r/boot/compressed/head.S
+ *
+ *  Copyright (c) 2001-2003	Hiroyuki Kondo, Hirokazu Takata,
+ *				Hitoshi Yamamoto, Takeo Takahashi
+ */
+
+	.text
+#include <linux/config.h>
+#include <linux/linkage.h>
+#include <asm/addrspace.h>
+#include <asm/page.h>
+#include <asm/assembler.h>
+#include "boot.h"
+
+	.global	startup
+startup:
+	ldi	r0, #0x0000			/* SPI, disable EI */
+	mvtc	r0, psw
+
+/*
+ * Clear BSS first so that there are no surprises...
+ */
+#ifdef CONFIG_ISA_DUAL_ISSUE
+
+	LDIMM	(r2, SYMBOL_NAME(__bss_start))
+	LDIMM	(r3, SYMBOL_NAME(_end))
+	sub	r3, r2		; BSS size in bytes
+	; R4 = BSS size in longwords (rounded down)
+	mv	r4, r3		    ||	ldi	r1, #0
+	srli	r4, #4		    ||	addi	r2, #-4	
+	beqz	r4, .Lendloop1
+.Lloop1:	
+#ifndef CONFIG_CHIP_M32310
+	; Touch memory for the no-write-allocating cache.
+	ld	r0, @(4,r2)
+#endif
+	st	r1, @+r2	    ||	addi	r4, #-1
+	st	r1, @+r2
+	st	r1, @+r2
+	st	r1, @+r2	    ||	cmpeq	r1, r4	; R4 = 0?
+	bnc	.Lloop1
+.Lendloop1:
+	and3	r4, r3, #15
+	addi	r2, #4
+	beqz	r4, .Lendloop2
+.Lloop2:
+	stb	r1, @r2		    ||	addi	r4, #-1
+	addi	r2, #1
+	bnez	r4, .Lloop2
+.Lendloop2:
+
+#else /* not CONFIG_ISA_DUAL_ISSUE */
+
+	LDIMM	(r2, SYMBOL_NAME(__bss_start))
+	LDIMM	(r3, SYMBOL_NAME(_end))
+	sub	r3, r2		; BSS size in bytes
+	mv	r4, r3
+	srli	r4, #2		; R4 = BSS size in longwords (rounded down)
+	ldi	r1, #0		; clear R1 for longwords store
+	addi	r2, #-4		; account for pre-inc store
+	beqz	r4, .Lendloop1	; any more to go?
+.Lloop1:	
+	st	r1, @+r2	; yep, zero out another longword
+	addi	r4, #-1		; decrement count
+	bnez	r4, .Lloop1	; go do some more
+.Lendloop1:
+	and3	r4, r3, #3	; get no. of remaining BSS bytes to clear
+	addi	r2, #4		; account for pre-inc store
+	beqz	r4, .Lendloop2	; any more to go?
+.Lloop2:
+	stb	r1, @r2		; yep, zero out another byte
+	addi	r2, #1		; bump address
+	addi	r4, #-1		; decrement count
+	bnez	r4, .Lloop2	; go do some more
+.Lendloop2:		
+
+#endif /* not CONFIG_ISA_DUAL_ISSUE */
+
+	seth	r0, #shigh(stack_start)
+	ld	sp, @(r0, low(stack_start))	/* set stack point */
+
+/*
+ * decompress the kernel
+ */
+	bl	decompress_kernel
+	mv	r12, r0 		/* size of decompressed kernel */
+
+/*
+ * relocate copy routine & jump routine
+ */
+	LDIMM	(r1, BOOT_RELOC_ADDR)
+	mv	r5, r1		; save reloc addr to jump
+
+	LDIMM	(r2, SYMBOL_NAME(startup_reloc))
+	LDIMM	(r3, SYMBOL_NAME(exit_reloc))
+	sub	r3, r2		; relocated code size in bytes
+	mv	r4, r3
+	srli	r4, #2		; R4 = code size in longwords (rounded down)
+	addi	r1, #-4		; account for pre-inc store
+	beqz	r4, 2f		; any more to go?
+1:	
+	ld	r6, @r2+	; code to be relocated
+	st	r6, @+r1	; relocate code
+	addi	r4, #-1		; decrement count
+	bnez	r4, 1b		; go do some more
+2:
+	and3	r4, r3, #3	; get no. of remaining bytes
+	addi	r1, #4		; account for pre-inc store
+	beqz	r4, 4f		; any more to go?
+3:
+	ldb	r6, @r2		; code to be relocated
+	stb	r6, @r1		; relocate code
+	addi	r1, #1		; bump address
+	addi	r2, #1		; bump address
+	addi	r4, #-1		; decrement count
+	bnez	r4, 3b		; go do some more
+4:		
+	jmp	r5		; jump to relocated code
+
+/*
+ * startup_reloc runs on BOOT_RELOC_ADDR.
+ * copy decompressed kernel to original location
+ */
+	.text
+	__ALIGN
+startup_reloc:
+	LDIMM	(r1, CONFIG_MEMORY_START)
+	LDIMM	(r2, KERNEL_DECOMPRESS_ADDR)
+	mv	r4, r12		; r12 holds size of decompressed kernel
+	srli	r4, #2		; R4 = code size in longwords (rounded down)
+	addi	r1, #-4		; account for pre-inc store
+	beqz	r4, 2f		; any more to go?
+1:	
+	ld	r6, @r2+	; code to be relocated
+	st	r6, @+r1	; relocate code
+	addi	r4, #-1		; decrement count
+	bnez	r4, 1b		; go do some more
+2:
+	and3	r4, r12, #3	; get no. of remaining bytes
+	addi	r1, #4		; account for pre-inc store
+	beqz	r4, 4f		; any more to go?
+3:
+	ldb	r6, @r2		; code to be relocated
+	stb	r6, @r1		; relocate code
+	addi	r1, #1		; bump address
+	addi	r2, #1		; bump address
+	addi	r4, #-1		; decrement count
+	bnez	r4, 3b		; go do some more
+4:		
+	/*
+	 * invalidate i-cache before jump to kernel
+	 */
+#if defined(CONFIG_CHIP_VDEC2)
+	ldi	r0, #-1
+	ldi	r1, #0xc0	; invalidate i-cache
+	stb	r1, @r0
+#elif defined(CONFIG_CHIP_XNUX2)
+	ldi	r0, #-2
+	ldi	r1, #0x0100	; invalidate
+	sth	r1, @r0
+#elif defined(CONFIG_CHIP_M32700)
+	ldi	r0, #-1		; MCCR(cache control register)
+	ldi	r1, #0xc0	; invalidate i-cache
+	stb	r1, @r0
+#else
+#error unknown chip configuration
+#endif
+	LDIMM	(r0, KERNEL_ENTRY)
+	jmp	r0				/* jump to kernel */
+
+	__ALIGN
+exit_reloc:
+
+	.balign 4096
+.fake_empty_zero_page:
+	/* FIXME: correct table value */
+	.word	0
+	.ascii	"HdrS"
+	.word	0x0202
+	.word	0
+	.word	0
+	.word	0x1000
+	.word	0
+	.byte	0
+	.byte	1
+	.word	0x8000
+	.long	0
+	.long	0
+
+	.section	.fake_eit_vector, "aw"
+	.long	0
+
diff -ruN linux-2.6.0.org/arch/m32r/boot/compressed/install.sh linux-2.6.0/arch/m32r/boot/compressed/install.sh
--- linux-2.6.0.org/arch/m32r/boot/compressed/install.sh	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.0/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.0.org/arch/m32r/boot/compressed/m32r_sio.c linux-2.6.0/arch/m32r/boot/compressed/m32r_sio.c
--- linux-2.6.0.org/arch/m32r/boot/compressed/m32r_sio.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.0/arch/m32r/boot/compressed/m32r_sio.c	2003-09-09 10:15:02.000000000 +0900
@@ -0,0 +1,50 @@
+/*
+ * arch/m32r/boot/compressed/m32r_sio.c
+ * 
+ * 2003-02-12:	Takeo Takahashi
+ *
+ */
+
+#include <linux/config.h>
+#include <asm/m32r.h>
+#include <asm/io.h>
+
+void putc(char c);
+
+void puts(char *s)
+{
+	char c;
+	while ((c = *s++)) putc(c);
+}
+
+#if defined(CONFIG_PLAT_M32700UT_Alpha) || defined(CONFIG_PLAT_M32700UT)
+#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
+#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.0.org/arch/m32r/boot/compressed/misc.c linux-2.6.0/arch/m32r/boot/compressed/misc.c
--- linux-2.6.0.org/arch/m32r/boot/compressed/misc.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.0/arch/m32r/boot/compressed/misc.c	2003-09-09 10:15:02.000000000 +0900
@@ -0,0 +1,224 @@
+/*
+ * arch/m32r/boot/compressed/misc.c
+ * 
+ * This is a collection of several routines from gzip-1.0.3 
+ * adapted for Linux.
+ *
+ * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
+ *
+ * Adapted for SH by Stuart Menefy, Aug 1999
+ *
+ * Modified to use standard LinuxSH BIOS by Greg Banks 7Jul2000
+ *
+ * 2003-02-12:	Support M32R by Takeo Takahashi
+ * 		This is based on arch/sh/boot/compressed/misc.c.
+ */
+
+#include <linux/config.h>
+#include <asm/uaccess.h>
+#include "boot.h"
+
+/*
+ * gzip declarations
+ */
+
+#define OF(args)  args
+#define STATIC static
+
+#undef memset
+#undef memcpy
+#define memzero(s, n)     memset ((s), 0, (n))
+
+typedef unsigned char  uch;
+typedef unsigned short ush;
+typedef unsigned long  ulg;
+
+#define WSIZE 0x8000		/* Window size must be at least 32k, */
+				/* and a power of two */
+
+static uch *inbuf;	     /* input buffer */
+static uch window[WSIZE];    /* Sliding window buffer */
+
+static unsigned insize;  /* valid bytes in inbuf */
+static unsigned inptr;   /* index of next byte to be processed in inbuf */
+static unsigned outcnt;  /* bytes in output buffer */
+
+/* gzip flag byte */
+#define ASCII_FLAG   0x01 /* bit 0 set: file probably ASCII text */
+#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
+#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
+#define COMMENT      0x10 /* bit 4 set: file comment present */
+#define ENCRYPTED    0x20 /* bit 5 set: file is encrypted */
+#define RESERVED     0xC0 /* bit 6,7:   reserved */
+
+#define get_byte()  (inptr < insize ? inbuf[inptr++] : fill_inbuf())
+		
+/* Diagnostic functions */
+#ifdef DEBUG
+#  define Assert(cond,msg) {if(!(cond)) error(msg);}
+#  define Trace(x) fprintf x
+#  define Tracev(x) {if (verbose) fprintf x ;}
+#  define Tracevv(x) {if (verbose>1) fprintf x ;}
+#  define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
+#  define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
+#else
+#  define Assert(cond,msg)
+#  define Trace(x)
+#  define Tracev(x)
+#  define Tracevv(x)
+#  define Tracec(c,x)
+#  define Tracecv(c,x)
+#endif
+
+static int  fill_inbuf(void);
+static void flush_window(void);
+static void error(char *m);
+static void gzip_mark(void **);
+static void gzip_release(void **);
+  
+extern char input_data[];
+extern int input_len;
+
+static long bytes_out;
+static uch *output_data;
+static unsigned long output_ptr;
+
+ 
+static void *malloc(int size);
+static void free(void *where);
+static void error(char *m);
+static void gzip_mark(void **);
+static void gzip_release(void **);
+ 
+extern void puts(const char *);
+  
+extern int _text;		/* Defined in vmlinux.lds.S */
+extern int _end;
+static unsigned long free_mem_ptr;
+static unsigned long free_mem_end_ptr;
+ 
+#define HEAP_SIZE             0x10000
+
+#include "../../../../lib/inflate.c"
+
+static void *malloc(int size)
+{
+	void *p;
+
+	if (size <0) error("Malloc error\n");
+	if (free_mem_ptr == 0) error("Memory error\n");
+
+	free_mem_ptr = (free_mem_ptr + 3) & ~3;	/* Align */
+
+	p = (void *)free_mem_ptr;
+	free_mem_ptr += size;
+
+	if (free_mem_ptr >= free_mem_end_ptr)
+		error("\nOut of memory\n");
+
+	return p;
+}
+
+static void free(void *where)
+{	/* Don't care */
+}
+
+static void gzip_mark(void **ptr)
+{
+	*ptr = (void *) free_mem_ptr;
+}
+
+static void gzip_release(void **ptr)
+{
+	free_mem_ptr = (long) *ptr;
+}
+
+void* memset(void* s, int c, size_t n)
+{
+	int i;
+	char *ss = (char*)s;
+
+	for (i=0;i<n;i++) ss[i] = c;
+	return s;
+}
+
+void* memcpy(void* __dest, __const void* __src,
+			    size_t __n)
+{
+	int i;
+	char *d = (char *)__dest, *s = (char *)__src;
+
+	for (i=0;i<__n;i++) d[i] = s[i];
+	return __dest;
+}
+
+/* ===========================================================================
+ * Fill the input buffer. This is called only when the buffer is empty
+ * and at least one byte is really needed.
+ */
+static int fill_inbuf(void)
+{
+	if (insize != 0) {
+		error("ran out of input data\n");
+	}
+
+	inbuf = input_data;
+	insize = input_len;
+	inptr = 1;
+	return inbuf[0];
+}
+
+/* ===========================================================================
+ * Write the output window window[0..outcnt-1] and update crc and bytes_out.
+ * (Used for the decompressed data only.)
+ */
+static void flush_window(void)
+{
+    ulg c = crc;         /* temporary variable */
+    unsigned n;
+    uch *in, *out, ch;
+    
+    in = window;
+    out = &output_data[output_ptr]; 
+    for (n = 0; n < outcnt; n++) {
+	    ch = *out++ = *in++;
+	    c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
+    }
+    crc = c;
+    bytes_out += (ulg)outcnt;
+    output_ptr += (ulg)outcnt;
+    outcnt = 0;
+}
+
+static void error(char *x)
+{
+	puts("\n\n");
+	puts(x);
+	puts("\n\n -- System halted");
+
+	while(1);	/* Halt */
+}
+
+#define STACK_SIZE (4096)
+long user_stack [STACK_SIZE];
+long* stack_start = &user_stack[STACK_SIZE];
+
+/* return decompressed size */
+long decompress_kernel(void)
+{
+	insize = 0;
+	inptr = 0;
+	bytes_out = 0;
+	outcnt = 0;
+	output_data = 0;
+	output_ptr = (unsigned long)KERNEL_DECOMPRESS_ADDR;
+	free_mem_ptr = (unsigned long)&_end;
+	free_mem_end_ptr = free_mem_ptr + HEAP_SIZE;
+
+	makecrc();
+	puts("Uncompressing Linux... ");
+	gunzip();
+	puts("Ok, booting the kernel.\n");
+	return bytes_out;
+}
diff -ruN linux-2.6.0.org/arch/m32r/boot/compressed/vmlinux.lds.S linux-2.6.0/arch/m32r/boot/compressed/vmlinux.lds.S
--- linux-2.6.0.org/arch/m32r/boot/compressed/vmlinux.lds.S	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.0/arch/m32r/boot/compressed/vmlinux.lds.S	2003-12-15 15:48:06.000000000 +0900
@@ -0,0 +1,107 @@
+#include <linux/config.h>
+#include <asm/addrspace.h>
+#include <asm/page.h>
+
+OUTPUT_ARCH(m32r)
+ENTRY(startup)
+SECTIONS
+{
+  . = CONFIG_MEMORY_START + 0x00000000;
+  .fake_eit_vector : { *(.fake_eit_vector) }
+  
+  /* boot runs in physical address space */
+  . = ALIGN(4096);
+  _text = .;
+  .text      :
+  {
+    *(.text)
+    *(.fixup)
+    *(.stub)
+    /* .gnu.warning sections are handled specially by elf32.em.  */
+    *(.gnu.warning)
+  } = 0
+  .text.lock : { *(.text.lock) }	/* out-of-line lock text */
+  .rodata : { *(.rodata) }
+  .kstrtab : { *(.kstrtab) }
+  _etext = .;			/* End of text section */
+
+  /* Adjust the address for the data segment.  We want to adjust up to
+     the same address within the page on the next page up.  */
+  . = ALIGN(32) + (. & (32 - 1));
+  .data    :
+  {
+    input_len = .;
+    LONG(input_data_end - input_data)
+    input_data = .;
+    piggy.o(.data)
+    input_data_end = .;
+    misc.o(.data)
+    m32r_sio.o(.data)
+  }
+  /* We want the small data sections together, so single-instruction offsets
+     can access them all, and initialized data all before uninitialized, so
+     we can shorten the on-disk segment size.  */
+  .sdata     : { *(.sdata) *(.sdata.*) }
+  _edata  =  .;
+
+  . = ALIGN(32 / 8);
+  __bss_start = .;		/* BSS */
+  .sbss      : { *(.sbss) *(.scommon) }
+  .bss       :
+  {
+   *(.bss)
+   *(COMMON)
+   /* Align here to ensure that the .bss section occupies space up to
+      _end.  Align after .bss to ensure correct alignment even if the
+      .bss section disappears because there are no input sections.  */
+   . = ALIGN(32 / 8);
+  }
+  . = ALIGN(32 / 8);
+  _end = . ;
+
+  /* When something in the kernel is NOT compiled as a module, the
+   * module cleanup code and data are put into these segments.  Both
+   * can then be thrown away, as cleanup code is never called unless
+   * it's a module.
+   */
+  /DISCARD/ : {
+    *(.text.exit)
+    *(.data.exit)
+    *(.exitcall.exit)
+  }
+
+  /* Stabs debugging sections.  */
+  .stab 0 : { *(.stab) }
+  .stabstr 0 : { *(.stabstr) }
+  .stab.excl 0 : { *(.stab.excl) }
+  .stab.exclstr 0 : { *(.stab.exclstr) }
+  .stab.index 0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment 0 : { *(.comment) }
+  /* DWARF debug sections.
+     Symbols in the DWARF debugging sections are relative to the beginning
+     of the section so we begin them at 0.  */
+  /* DWARF 1 */
+  .debug          0 : { *(.debug) }
+  .line           0 : { *(.line) }
+  /* GNU DWARF 1 extensions */
+  .debug_srcinfo  0 : { *(.debug_srcinfo) }
+  .debug_sfnames  0 : { *(.debug_sfnames) }
+  /* DWARF 1.1 and DWARF 2 */
+  .debug_aranges  0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+  /* DWARF 2 */
+  .debug_info     0 : { *(.debug_info) }
+  .debug_abbrev   0 : { *(.debug_abbrev) }
+  .debug_line     0 : { *(.debug_line) }
+  .debug_frame    0 : { *(.debug_frame) }
+  .debug_str      0 : { *(.debug_str) }
+  .debug_loc      0 : { *(.debug_loc) }
+  .debug_macinfo  0 : { *(.debug_macinfo) }
+  /* SGI/MIPS DWARF 2 extensions */
+  .debug_weaknames 0 : { *(.debug_weaknames) }
+  .debug_funcnames 0 : { *(.debug_funcnames) }
+  .debug_typenames 0 : { *(.debug_typenames) }
+  .debug_varnames  0 : { *(.debug_varnames) }
+  /* These must appear regardless of  .  */
+}
diff -ruN linux-2.6.0.org/arch/m32r/boot/setup.S linux-2.6.0/arch/m32r/boot/setup.S
--- linux-2.6.0.org/arch/m32r/boot/setup.S	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.0/arch/m32r/boot/setup.S	2004-03-16 19:34:57.000000000 +0900
@@ -0,0 +1,204 @@
+/*
+ *  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_MCCR 	 0xfffffffc
+#define M32R_BSCR0	 0xffffffd2
+
+;BSEL
+#define BSEL0CR0	 0x00ef5000
+#define	BSEL0CR1	 0x00ef5004
+#define BSEL1CR0	 0x00ef5100
+#define BSEL1CR1	 0x00ef5104
+#define BSEL0CR0_VAL	 0x00000000
+#define BSEL0CR1_VAL	 0x01200100
+#define BSEL1CR0_VAL	 0x01018000
+#define BSEL1CR1_VAL	 0x00200001
+
+;SDRAMC
+#define SDRAMC_SDRF0	 0x00ef6000
+#define SDRAMC_SDRF1	 0x00ef6004
+#define SDRAMC_SDIR0	 0x00ef6008
+#define SDRAMC_SDIR1	 0x00ef600c
+#define SDRAMC_SD0ADR	 0x00ef6020
+#define SDRAMC_SD0ER	 0x00ef6024
+#define SDRAMC_SD0TR	 0x00ef6028
+#define SDRAMC_SD0MOD	 0x00ef602c
+#define SDRAMC_SD1ADR	 0x00ef6040
+#define SDRAMC_SD1ER	 0x00ef6044
+#define SDRAMC_SD1TR	 0x00ef6048
+#define SDRAMC_SD1MOD	 0x00ef604c
+#define SDRAM0		 0x18000000
+#define SDRAM1		 0x1c000000
+
+/*------------------------------------------------------------------------
+ * start up
+ */
+
+/*------------------------------------------------------------------------
+ * Kernel entry
+ */
+	.section .boot,"ax"
+ENTRY(boot)
+
+/* Set cache mode */
+#if defined(CONFIG_CHIP_XNUX2)
+	ldi	r0, #-2              ;LDIMM	(r0, M32R_MCCR)
+	ldi	r1, #0x0101		; cache on (with invalidation)
+;	ldi	r1, #0x00		; cache off
+	sth	r1, @r0
+#elif defined(CONFIG_CHIP_VDEC2)
+	; cache condition is controlled by loader
+	; r13 = pointer to kernel parameter passed from loader
+	beqz	r13, param_skip
+	ldi	r2, #4096				; size
+	seth	r1, #high(empty_zero_page)
+	or3	r1, r1, #low(empty_zero_page)
+	seth	r3, #high(__PAGE_OFFSET)
+	or3	r3, r3, #low(__PAGE_OFFSET)
+	not	r3, r3
+	and	r1, r3
+	addi	r1, #-4
+param_loop:
+	ld	r3, @r13+
+	st	r3, @+r1
+	addi	r2, #-4
+	bnez	r2, param_loop
+	bra	param_end
+param_skip:
+	ldi	r0, #-1              ;LDIMM	(r0, M32R_MCCR)
+	ldi	r1, #0x63      		; cache on
+;	ldi	r1, #0x00		; cache off
+	stb	r1, @r0
+param_end:
+
+#elif defined(CONFIG_CHIP_M32700) && (defined(CONFIG_PLAT_M32700UT) \
+	|| defined(CONFIG_PLAT_USRV))
+	; cache condition is controlled by loader
+	; r13 = pointer to kernel parameter passed from loader
+	ldi     r0, #-4
+	ldi     r1, #0x63		;  cache Ion/Don
+	st      r1, @r0
+#if defined(CONFIG_SMP) && !defined(CONFIG_PLAT_USRV)
+	seth    r5, #high(M32R_CPUID_PORTL)
+	or3     r5, r5, #low(M32R_CPUID_PORTL)
+	ld      r5, @r5
+	bnez    r5, param_end
+		;;  boot AP
+	ld24    r5, #0xeff2f8		;  IPICR7
+	ldi     r6, #0x2		;  IPI to CPU1
+	st      r6, @r5
+#endif
+	beqz	r13, param_end
+	ldi	r2, #4096				; size
+	seth	r1, #high(empty_zero_page)
+	or3	r1, r1, #low(empty_zero_page)
+	seth	r3, #high(__PAGE_OFFSET)
+	or3	r3, r3, #low(__PAGE_OFFSET)
+	not	r3, r3
+	and	r1, r3
+	addi	r1, #-4
+param_loop:
+	ld	r3, @r13+
+	st	r3, @+r1
+	addi	r2, #-4
+	bnez	r2, param_loop
+param_end:
+#elif defined(CONFIG_CHIP_M32700)
+	ldi	r0, #-4			;LDIMM	(r0, M32R_MCCR)
+	ldi	r1, #0x63		; cache Ion/Don (with invalidation)
+;	ldi	r1, #0x00		; cache off
+	st	r1, @r0
+#else
+#error unknown chip configuration
+#endif
+
+#ifdef CONFIG_SMP
+	;; if not BSP (CPU#0) goto AP_loop
+	seth	r5, #shigh(M32R_CPUID_PORTL)
+	ld      r5, @(low(M32R_CPUID_PORTL), r5)
+	bnez	r5, AP_loop
+#endif
+
+/*
+ *  Now, Jump to stext 
+ *        if with MMU,    TLB on.
+ *        if with no MMU, only jump.
+ */
+mmu_on:
+	LDIMM	(r13, stext)
+#ifdef CONFIG_HAVE_M32R_MMU
+	LDIMM	(r2, _RE)			; set EVB(cr5)
+	mvtc    r2, cr5	
+	seth	r0, #high(MMU_REG_BASE)		; Set MMU_REG_BASE higher
+	or3     r0, r0, #low(MMU_REG_BASE)	; Set MMU_REG_BASE lower
+	ldi     r1, #0x01    
+	st      r1, @(MATM_offset,r0)		; Set MATM (T bit ON)
+	ld      r0, @(MATM_offset,r0)		; Check
+#endif	/* CONFIG_HAVE_M32R_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.0.org/arch/m32r/defconfig linux-2.6.0/arch/m32r/defconfig
--- linux-2.6.0.org/arch/m32r/defconfig	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.0/arch/m32r/defconfig	2004-03-16 22:14:53.000000000 +0900
@@ -0,0 +1,620 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_M32R=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_GENERIC_ISA_DMA=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_STANDALONE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_SYSCTL=y
+CONFIG_LOG_BUF_SHIFT=14
+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
+
+#
+# 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_CHIP_M32700=y
+CONFIG_ISA_M32R2=y
+CONFIG_ISA_DSP_LEVEL2=y
+CONFIG_ISA_DUAL_ISSUE=y
+CONFIG_HAVE_M32R_MMU=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_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
+CONFIG_HOTPLUG=y
+
+#
+# PCMCIA/CardBus support
+#
+CONFIG_PCMCIA=y
+# 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_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
+#
+# CONFIG_PNP is not set
+
+#
+# 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_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_IDEDISK_STROKE 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_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_DMA_NONPCI 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_REPORT_LUNS=y
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_AIC7XXX is not set
+# 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
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# 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 is not set
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_IPV6 is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NETFILTER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+CONFIG_IPV6_SCTP__=y
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q 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_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETDEVICES is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BT is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN_BOOL 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=y
+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_UNIX98_PTY_COUNT=256
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# I2C Algorithms
+#
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C Hardware Sensors Chip support
+#
+# CONFIG_I2C_SENSOR is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_SYNCLINK_CS is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=y
+
+#
+# Video For Linux
+#
+
+#
+# Video Adapters
+#
+# CONFIG_VIDEO_CPIA is not set
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_RADIO_MAESTRO is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+# CONFIG_VIDEO_BTCX is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB 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_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
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS=y
+# 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_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_SUNRPC_GSS 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_INTERMEZZO_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# 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_CRC32=y
diff -ruN linux-2.6.0.org/arch/m32r/drivers/8390.c linux-2.6.0/arch/m32r/drivers/8390.c
--- linux-2.6.0.org/arch/m32r/drivers/8390.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.0/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.0.org/arch/m32r/drivers/8390.h linux-2.6.0/arch/m32r/drivers/8390.h
--- linux-2.6.0.org/arch/m32r/drivers/8390.h	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.0/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.0.org/arch/m32r/drivers/Kconfig linux-2.6.0/arch/m32r/drivers/Kconfig
--- linux-2.6.0.org/arch/m32r/drivers/Kconfig	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.0/arch/m32r/drivers/Kconfig	2004-02-17 17:31:39.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
+
+config M32R_CFC
+	bool "CF I/F Controller"
+	depends on PLAT_USRV || PLAT_M32700UT
+
+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
+
+config MTD_M32R
+	bool "Flash device mapped on M32R"
+	depends on PLAT_USRV
+
+config M32R_SMC91111
+	bool "On board SMC91111 Network Interface Chip"
+	depends on PLAT_M32700UT
+
+config M32700UT_DS1302
+	bool "DS1302 Real Time Clock support"
+	depends on PLAT_M32700UT
+
+endmenu
diff -ruN linux-2.6.0.org/arch/m32r/drivers/Makefile linux-2.6.0/arch/m32r/drivers/Makefile
--- linux-2.6.0.org/arch/m32r/drivers/Makefile	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.0/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.0.org/arch/m32r/drivers/cs_internal.h linux-2.6.0/arch/m32r/drivers/cs_internal.h
--- linux-2.6.0.org/arch/m32r/drivers/cs_internal.h	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.0/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.0.org/arch/m32r/drivers/ds1302.c linux-2.6.0/arch/m32r/drivers/ds1302.c
--- linux-2.6.0.org/arch/m32r/drivers/ds1302.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.0/arch/m32r/drivers/ds1302.c	2004-02-17 17:31:39.000000000 +0900
@@ -0,0 +1,434 @@
+/*!***************************************************************************
+*!
+*! 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.1  2004/02/17 08:31:39  fujiwara
+*! Add Real Time Clock driver for M32700UT
+*!
+*! 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.1 2004/02/17 08:31:39 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/m32700ut/m32700ut_pld.h>
+
+#define RTC_MAJOR_NR 121 /* local major, change later */
+
+static const char ds1302_name[] = "ds1302";
+
+/* Send 8 bits. */
+static void
+out_byte_rtc(unsigned int reg_addr, unsigned char x) 
+{
+	//RST H
+	outw(0x0001,(unsigned long)PLD_RTCRSTODT);
+	//write data
+	outw(((x<<8)|(reg_addr&0xff)),(unsigned long)PLD_RTCWRDATA);
+	//WE
+	outw(0x0002,(unsigned long)PLD_RTCCR);
+	//wait
+	while(inw((unsigned long)PLD_RTCCR));
+	
+	//RST L
+	outw(0x0000,(unsigned long)PLD_RTCRSTODT);
+
+}
+
+static unsigned char
+in_byte_rtc(unsigned int reg_addr) 
+{
+	unsigned char retval;
+	
+	//RST H
+	outw(0x0001,(unsigned long)PLD_RTCRSTODT);
+	//write data
+	outw((reg_addr&0xff),(unsigned long)PLD_RTCRDDATA);
+	//RE
+	outw(0x0001,(unsigned long)PLD_RTCCR);
+	//wait
+	while(inw((unsigned long)PLD_RTCCR));
+
+	//read data
+	retval=(inw((unsigned long)PLD_RTCRDDATA) & 0xff00)>>8;
+
+	//RST L
+	outw(0x0000,(unsigned long)PLD_RTCRSTODT);
+
+	return retval;
+}
+
+/* Enable writing. */
+
+static void
+ds1302_wenable(void) 
+{
+	out_byte_rtc(0x8e,0x00);
+}
+
+/* Disable writing. */
+
+static void
+ds1302_wdisable(void) 
+{
+	out_byte_rtc(0x8e,0x80);
+}
+
+
+
+/* Read a byte from the selected register in the DS1302. */
+
+unsigned char
+ds1302_readreg(int reg) 
+{
+	unsigned char x;
+
+	x=in_byte_rtc((0x81 | (reg << 1))); /* read register */
+
+	return x;
+}
+
+/* Write a byte to the selected register. */
+
+void
+ds1302_writereg(int reg, unsigned char val) 
+{
+	ds1302_wenable();
+	out_byte_rtc((0x80 | (reg << 1)),val);
+	ds1302_wdisable();
+}
+
+void
+get_rtc_time(struct rtc_time *rtc_tm) 
+{
+	unsigned long flags;
+
+	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;
+						
+			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.0.org/arch/m32r/drivers/m32r-pldsio.c linux-2.6.0/arch/m32r/drivers/m32r-pldsio.c
--- linux-2.6.0.org/arch/m32r/drivers/m32r-pldsio.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.0/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.0.org/arch/m32r/drivers/m32r_cfc.c linux-2.6.0/arch/m32r/drivers/m32r_cfc.c
--- linux-2.6.0.org/arch/m32r/drivers/m32r_cfc.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.0/arch/m32r/drivers/m32r_cfc.c	2004-03-16 19:34:57.000000000 +0900
@@ -0,0 +1,903 @@
+/*  
+ *  linux/arch/m32r/drivers/m32r_cfc.c
+ *  
+ *  Device driver for the CFC functionality of M32R.
+ *  
+ *  Copyright (c) 2001, 2002, 2003  Hiroyuki Kondo, Sugai Naoto
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/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>
+#include <pcmcia/bulkmem.h>
+#include <pcmcia/cistpl.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_PARM(m32r_cfc_debug, "i");
+#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)
+	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)
+	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)
+	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)
+	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 */
+
+/*======================================================================
+
+	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);
+
+/*====================================================================*/
+
+#if 0
+#define LOCKED(x) return x
+#else
+#define LOCKED(x) do { \
+	int retval; \
+	unsigned long flags; \
+	spin_lock_irqsave(&pcc_lock, flags); \
+	retval = x; \
+	spin_unlock_irqrestore(&pcc_lock, flags); \
+	return retval; \
+} while (0)
+#endif
+
+static int pcc_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;
+
+#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");
+		return -ENODEV;
+	}
+
+	platform_device_register(&pcc_device);
+
+	/* 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;
+		}
+		class_device_create_file(&socket[i].socket.dev,
+			&class_device_attr_info);
+		class_device_create_file(&socket[i].socket.dev,
+			&class_device_attr_exca);
+	}
+
+	/* 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);
+
+/*
+ ***  Emacs  Setting ***
+ * Local Variables:
+ * c-basic-offset:4
+ * tab-width:4
+ * End:
+ */
+
diff -ruN linux-2.6.0.org/arch/m32r/drivers/m32r_cfc.h linux-2.6.0/arch/m32r/drivers/m32r_cfc.h
--- linux-2.6.0.org/arch/m32r/drivers/m32r_cfc.h	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.0/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.0.org/arch/m32r/drivers/m32r_pcc.c linux-2.6.0/arch/m32r/drivers/m32r_pcc.c
--- linux-2.6.0.org/arch/m32r/drivers/m32r_pcc.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.0/arch/m32r/drivers/m32r_pcc.c	2003-09-09 15:03:40.000000000 +0900
@@ -0,0 +1,859 @@
+/*======================================================================
+
+	Device driver for the PCMCIA functionality of M32R.
+
+======================================================================*/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/proc_fs.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <asm/addrspace.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+#include <asm/system.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/bulkmem.h>
+#include <pcmcia/cistpl.h>
+
+#define PCMCIA_DEBUG   0
+
+#include "cs_internal.h"
+#include "m32r_pcc.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
+
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+#else
+#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;
+
+	/* pcc_set(sockets,PCCR,1); */
+	/* pcc_set(sockets,PCIRC,3); */
+
+	/* 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; /*  */
+	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;
+#if 0
+			if (i365_get(i, I365_INTCTL) & I365_PC_IOCARD)
+				events |= (csc & I365_CSC_STSCHG) ? SS_STSCHG : 0;
+			else {
+				events |= (csc & I365_CSC_BVD1) ? SS_BATDEAD : 0;
+				events |= (csc & I365_CSC_BVD2) ? SS_BATWARN : 0;
+				events |= (csc & I365_CSC_READY) ? SS_READY : 0;
+			}
+			DEBUG(2, "m32r-pcc:interrput: socket %d event 0x%02x\n", i, events);
+#endif
+			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;
+		
+#if 0
+	if (i365_get(sock, I365_INTCTL) & I365_PC_IOCARD)
+		*value |= (status & I365_CS_STSCHG) ? 0 : SS_STSCHG;
+	else {
+		*value |= (status & I365_CS_BVD1) ? 0 : SS_BATDEAD;
+		*value |= (status & I365_CS_BVD2) ? 0 : SS_BATWARN;
+	}
+	*value |= (status & I365_CS_WRPROT) ? SS_WRPROT : 0;
+#endif
+	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)
+{
+#if 0
+	pcc_socket_t *t = &socket[sock];
+	u_char reg, vcc, vpp;
+	
+	reg = i365_get(sock, I365_POWER);
+	state->flags = (reg & I365_PWR_AUTO) ? SS_PWR_AUTO : 0;
+	state->flags |= (reg & I365_PWR_OUT) ? SS_OUTPUT_ENA : 0;
+
+	vcc = reg & I365_VCC_MASK; vpp = reg & I365_VPP1_MASK;
+	state->Vcc = state->Vpp = 0;
+	if (reg & I365_VCC_5V) {
+		state->Vcc = 50;
+		if (vpp == I365_VPP1_5V) state->Vpp = 50;
+		if (vpp == I365_VPP1_12V) state->Vpp = 120;
+	}
+
+	/* IO card, RESET flags, IO interrupt */
+	reg = i365_get(sock, I365_INTCTL);
+	state->flags |= (reg & I365_PC_RESET) ? 0 : SS_RESET;
+	if (reg & I365_PC_IOCARD) state->flags |= SS_IOCARD;
+	state->io_irq = reg & I365_IRQ_MASK;
+	
+	/* Card status change mask */
+	reg = i365_get(sock, I365_CSCINT);
+	state->csc_mask = (reg & I365_CSC_DETECT) ? SS_DETECT : 0;
+	if (state->flags & SS_IOCARD)
+		state->csc_mask |= (reg & I365_CSC_STSCHG) ? SS_STSCHG : 0;
+	else {
+		state->csc_mask |= (reg & I365_CSC_BVD1) ? SS_BATDEAD : 0;
+		state->csc_mask |= (reg & I365_CSC_BVD2) ? SS_BATWARN : 0;
+		state->csc_mask |= (reg & I365_CSC_READY) ? SS_READY : 0;
+	}
+#endif
+	
+	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");
+		reg |= PCCSIGCR_CRST;
+	}
+	if (state->flags & SS_OUTPUT_ENA){
+		DEBUG(3, ":OUTPUT_ENA");
+		/* 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 */
+
+/*======================================================================
+
+	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(exca, S_IRUGO, show_exca, NULL);
+static CLASS_DEVICE_ATTR(info, S_IRUGO, show_info, NULL);
+
+/*====================================================================*/
+
+#if 0
+#define LOCKED(x) return x
+#else
+#define LOCKED(x) do {					\
+	int retval;					\
+	unsigned long flags;				\
+	spin_lock_irqsave(&pcc_lock, flags);		\
+	retval = x;					\
+	spin_unlock_irqrestore(&pcc_lock, flags);	\
+	return retval;					\
+} while (0)
+#endif
+
+static int pcc_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 struct device_driver pcc_driver = {
+	.name = "pcc",
+	.bus = &platform_bus_type,
+	.suspend = pcmcia_socket_dev_suspend,
+	.resume = pcmcia_socket_dev_resume,
+};
+
+static struct platform_device pcc_device = {
+	.name = "pcc",
+	.id = 0,
+};
+
+/*====================================================================*/
+
+static int __init init_m32r_pcc(void)
+{
+	int i, ret;
+
+	if (driver_register(&pcc_driver))
+		return -1;
+
+	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("not found.\n");
+		driver_unregister(&pcc_driver);
+		return -ENODEV;
+	}
+
+	platform_device_register(&pcc_device);
+
+	/* 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;
+		}
+		class_device_create_file(&socket[i].socket.dev,
+			&class_device_attr_info);
+		class_device_create_file(&socket[i].socket.dev,
+			&class_device_attr_exca);
+	}
+
+	/* Finally, schedule a polling interrupt */
+#if 0
+	poll_interval = HZ;
+#endif
+	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);
+
+/*
+ ***  Emacs  Setting ***
+ * Local Variables:
+ * c-basic-offset:4
+ * tab-width:4
+ * End:
+ */
+
diff -ruN linux-2.6.0.org/arch/m32r/drivers/m32r_pcc.h linux-2.6.0/arch/m32r/drivers/m32r_pcc.h
--- linux-2.6.0.org/arch/m32r/drivers/m32r_pcc.h	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.0/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.0.org/arch/m32r/drivers/m5.c linux-2.6.0/arch/m32r/drivers/m5.c
--- linux-2.6.0.org/arch/m32r/drivers/m5.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.0/arch/m32r/drivers/m5.c	2003-09-09 10:15:02.000000000 +0900
@@ -0,0 +1,913 @@
+/*
+ * Flash Memory Driver for M32700UT-CPU
+ *
+ * [support chips]
+ *  	- M5M29GT320VP
+ *
+ * Copyright (C) 2003   Takeo Takahashi
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * 2003-02-01: Takeo Takahashi, support M5M29GT320VP page program.
+ *
+ */
+
+#ifndef __KERNEL__
+#  define __KERNEL__
+#endif
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ioctl.h>
+#include <linux/blkpg.h>
+#include <linux/fs.h>
+#include <linux/proc_fs.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/delay.h>
+#include <asm/m32r.h>
+#include <asm/io.h>
+
+#include "m5.h"
+
+static const char version[] = "M5 Flash Driver";
+static const char date[] = __DATE__;
+static const char time[] = __TIME__;
+
+/*
+ * Special function
+ */
+#define M5_SUPPORT_PROBE	1
+#define M5_MAX_ERROR		5
+
+/*
+ * flash memory start address:
+ */
+//#define M5_BASE_ADDR         (0x00000000 + NONCACHE_OFFSET)
+#define M5_BASE_ADDR         (0x00000000 + PAGE_OFFSET)
+#define M5_IDENT_ADDR        (M5_BASE_ADDR + 0)
+
+/*
+ * This driver does not have a real partition block, but
+ * it can support simulation of partition in single chip.
+ */
+#define M5_PARTITIONS        (3)
+static int m5_len[M5_PARTITIONS] = {
+	192 * 1024,	/* 192kB:	0x00000000 - 0x0002ffff */	
+	1088 * 1024,	/* 1088kB:	0x00030000 - 0x0013ffff */
+	2816 * 1024	/* 2816kB:	0x00140000 - 0x003fffff */
+};
+
+static int major = 240;
+static int debug = 2;
+static int led=0;
+static int m5_addr[M5_PARTITIONS];
+static int m5_blk_size[M5_PARTITIONS];
+static int m5_blksize_size[M5_PARTITIONS];
+static int m5_hardsect_size[M5_PARTITIONS];
+static int m5_read_ahead = 1;
+MODULE_PARM(major, "i");
+//MODULE_PARM_DESC(major, "major number");
+MODULE_PARM(debug, "i");
+//MODULE_PARM_DESC(debug, "debug flag");
+MODULE_PARM(led, "i");
+//MODULE_PARM_DESC(led, "LED2 support");
+
+static devfs_handle_t	devfs_handle = NULL;
+#ifdef CONFIG_PROC_FS
+static struct proc_dir_entry *proc_m5;
+#endif
+
+#define MAJOR_NR		major
+#define DEVICE_NAME 		"m5"
+#define DEVICE_NR(device) 	MINOR(device)
+#define DEVICE_NO_RANDOM
+#define DEVICE_OFF(device)
+#define DEVICE_ON(device)
+#define DEVICE_REQUEST 		m5_request
+#include <linux/blk.h>
+
+#define WAIT_TIME	10			/* 10 usec */
+#define WAIT_COUNT	(50000/WAIT_TIME)	/* 50ms = 10us*5000times */
+
+#define SUCCESS 0
+#define FAILED  (-1)
+
+/*
+ * definitions for cache
+ */
+static struct cache {
+	int blk;	/* block number, -1:invalid */
+	int status;	/* cache status */
+#define B_CLEAN	0
+#define B_DIRTY	1
+	m5_t *addr;	/* block base address */
+	m5_t cache[M5_BLOCK_SIZE64];
+} m5_cache;
+#define M5_BLK_NOCACHED()		(m5_cache.blk == -1)
+#define M5_BLK_CACHED(blk)		(m5_cache.blk == (blk))
+#define M5_STATE_DIRTY()		(m5_cache.status == B_DIRTY)
+#define M5_STATE_CLEAN()		(m5_cache.status == B_CLEAN)
+#define M5_MARK_DIRTY()			(m5_cache.status = B_DIRTY)
+#define M5_MARK_CLEAN()			(m5_cache.status = B_CLEAN)
+#define M5_MARK_NOCACHED()		(m5_cache.blk = -1)
+#define M5_MARK_CACHED(blk, addr)	(m5_cache.blk = (blk), \
+					 m5_cache.addr = (addr))
+#define M5_CACHED_BLK			m5_cache.blk
+#define M5_CACHED_ADDR			m5_cache.addr
+#define M5_CACHED_BASE			m5_cache.cache
+
+/*
+ * Prototype declarations
+ */
+static int m5_erase_blk(m5_t *reg);
+static void m5_led_toggle(void);
+static void m5_led_on(void);
+static void m5_led_off(void);
+static m5_t m5_in(m5_t *addr);
+static void m5_out(m5_t val, m5_t *addr);
+static int m5_probe(m5_t *addr);
+static int m5_get_blk_num(m5_t *addr);
+static int m5_get_blk_offset(int blk, m5_t *addr);
+static int m5_get_blk_size(int blk);
+static int m5_read_blk_cache(m5_t *addr);
+static int m5_write_blk_cache(void);
+static int m5_full_status_check(m5_t status, m5_t *reg);
+static void m5_clear_status(m5_t *reg);
+#if 0
+static int m5_status_check(m5_t *reg);
+#endif
+static int m5_wait_for_ready(m5_t *reg);
+static int m5_write_page(m5_t *addr, const m5_t *buf);
+static int m5_write(const m5_t *buf, int offset, int len);
+static int m5_read_page(m5_t *buf, m5_t *addr);
+static int m5_read(m5_t *buf, int offset, int len);
+static int m5_erase_blk(m5_t *addr);
+static void m5_request(request_queue_t *req);
+static int m5_ioctl(struct inode *inode, struct file *fp, unsigned int cmd, unsigned long arg);
+static int m5_open(struct inode *inode, struct file *fp);
+static int m5_release(struct inode *inode, struct file *fp);
+static int proc_m5_read(char *buf, char **start, off_t offset, int len, int *eof, void *unused);
+static int __init m5_init(void);
+static int __init m5_init_module(void);
+static void __exit m5_cleanup_module(void);
+
+/*
+ * special function
+ */
+static inline void m5_led_toggle(void)
+{
+	unsigned short status;
+	if (!led) return;
+	status = inw((unsigned long)PLD_IOLEDCR);
+	if (status & PLD_IOLED_2_ON)
+		status &= ~PLD_IOLED_2_ON;
+	else
+		status |= PLD_IOLED_2_ON;
+	outw(status, (unsigned long)PLD_IOLEDCR);
+}
+
+static inline void m5_led_on(void)
+{
+	unsigned short status;
+	if (!led) return;
+	status = inw((unsigned long)PLD_IOLEDCR);
+	status |= PLD_IOLED_2_ON;
+	outw(status, (unsigned long)PLD_IOLEDCR);
+}
+
+static inline void m5_led_off(void)
+{
+	unsigned short status;
+	if (!led) return;
+	status = inw((unsigned long)PLD_IOLEDCR);
+	status &= ~PLD_IOLED_2_ON;
+	outw(status, (unsigned long)PLD_IOLEDCR);
+}
+
+/*
+ * I/O function
+ */
+static inline m5_t m5_in(m5_t *addr)
+{
+	return *addr;
+}
+
+static inline void m5_out(m5_t val, m5_t *addr)
+{
+	*addr = val;
+}
+
+#if M5_SUPPORT_PROBE
+/*
+ * int m5_probe()
+ *	m5_t *addr:	probed address
+ * 	int SUCCESS: 	supported device
+ *	int FAILED: 	unsupported device
+ */
+static int m5_probe(m5_t *addr)
+{
+#if 1
+	/*
+	 * FIXME: cannot read maker & device codes.
+	 */
+	m5_t val;
+	m5_out(M5_CMD_DEVICE_IDENT, addr);
+	val = m5_in((m5_t *)M5_IDENT_ADDR);
+	val &= 0xff;
+	if (val == M5_MAKER)
+		printk("m5: detected M5M29GT320VP\n");
+	else
+		printk("m5: unknown maker(0x%02x)\n", val);
+	m5_out(M5_CMD_READ_ARRAY, addr);	/* array mode */
+	/* always success */
+	return SUCCESS;
+#else
+
+	int result;
+	m5_t val;
+	unsigned char maker, device;
+
+	result = SUCCESS;
+	m5_out(M5_CMD_DEVICE_IDENT, addr);
+	val = m5_in((m5_t *)M5_IDENT_ADDR);
+	maker = (val >> 16);
+	device = (val & 0xff);
+	if (maker != M5_MAKER) {
+		printk("m5: unknown maker(0x%02x)\n", maker);
+		// result = FAILED;
+		// ignore error
+	}
+ 	if (device != M5_M5M29GT320VP) {
+		printk("m5: unknown device(0x%02x)\n", device);
+		// result = FAILED;
+		// ignore error
+	}
+	if (result != FAILED)
+		printk("m5: detected M5M29GT320VP\n");
+	m5_out(M5_CMD_READ_ARRAY, addr);
+	return result;
+#endif
+}
+#endif	/* M5_SUPPORT_PROBE */
+
+/*
+ * int m5_get_blk_num()
+ *	m5_t *addr:
+ *	blk:	OK, return block number
+ *	-1:	NG
+ */
+static int m5_get_blk_num(m5_t *addr)
+{
+	int blk;
+
+	blk = (((int)addr & 0x0fff0000) >> 16);
+	if (blk > 0x3f) {
+		printk("m5: out of block address (0x%08x)\n", (int)addr);
+		return -1; 
+	}
+	if (blk == 0x3f)
+		blk += (int)(((int)addr & 0x0000e000) >> 13);
+	if (blk > MAX_BLOCK_NUM) {
+		printk("m5: out of block address (addr=0x%08x, blk=%d)\n",
+				(int)addr, blk);
+		return -1;
+	}
+	return blk;
+}
+
+/*
+ * m5_t *m5_get_blk_base()
+ *	return block base address
+ */
+static inline m5_t *m5_get_blk_base(int blk, m5_t *addr)
+{
+	if (blk < 0x3f) return (m5_t *)((int)addr & 0xffff0000);
+	return (m5_t *)((int)addr & 0xffffe000);
+}
+
+/*
+ * int m5_get_blk_offset()
+ *	return offset of specified address in blk
+ */
+static inline int m5_get_blk_offset(int blk, m5_t *addr)
+{
+	if (blk < 0x3f) return ((int)addr & 0xffff);
+	return ((int)addr & 0x1fff);
+}
+
+/*
+ * int m5_get_blk_size()
+ *	return block size in byte
+ */
+static inline int m5_get_blk_size(int blk)
+{
+	if (blk >= 63) return M5_BLOCK_SIZE8;
+	return M5_BLOCK_SIZE64;
+}
+
+/*
+ * cache operations 
+ */
+static int m5_read_blk_cache(m5_t *addr)
+{
+	int blk;
+	int size;
+	int result;
+
+	result = SUCCESS;
+	blk = m5_get_blk_num(addr);
+	if (blk < 0) return FAILED;
+	if (M5_BLK_CACHED(blk))
+		return result;
+	if (M5_STATE_DIRTY()) {		/* cached other block */
+		result = m5_write_blk_cache();
+		if (result != SUCCESS) return result;
+	}
+	/* ok, we can use cache */
+	size = m5_get_blk_size(blk);
+	addr = m5_get_blk_base(blk, addr);
+	memcpy((void *)M5_CACHED_BASE, (void *)addr, size);
+	M5_MARK_CACHED(blk, addr);
+	M5_MARK_CLEAN();
+	return result;
+}
+
+static int m5_write_blk_cache(void)
+{
+	int size;
+	int pages;
+	int i;
+	m5_t *reg, *addr, *buf;
+	int result;
+
+	result = SUCCESS;
+
+	if (M5_BLK_NOCACHED()) 
+		return result;
+	if (! M5_STATE_DIRTY())
+		return result;
+
+	/* we have to write cache */
+	m5_led_on();
+	size = m5_get_blk_size(M5_CACHED_BLK);
+	addr = M5_CACHED_ADDR;
+	buf = M5_CACHED_BASE;
+	reg = addr;
+
+	result = m5_erase_blk(reg);
+	if (result != SUCCESS) return result;
+
+	DEBUG(1, "m5: wrting addr=0x%08x, buf=0x%08x, size=%d\n",\
+		(int)addr, (int)buf, size);
+	for (pages = 0; pages < (size/M5_PAGE_SIZE); pages++) {
+		m5_out(M5_CMD_PROGRAM_PAGE, reg);
+		for (i = 0; i < (M5_PAGE_SIZE/sizeof(m5_t)); i++)
+			*addr++ = *buf++;
+		if (m5_wait_for_ready(reg) != SUCCESS)
+			result = FAILED;
+		reg = addr;
+	}
+	m5_out(M5_CMD_READ_ARRAY, reg);	/* array mode */
+	if (result == SUCCESS)
+		M5_MARK_CLEAN();
+	m5_led_off();
+	return result;	/* SUCCESS or FAILED */
+}
+
+/*
+ * int m5_full_status_check()
+ *	m5_t status:	status
+ *	m5_t *reg:	bank address
+ *	SUCCESS:	no error
+ *	FAILED:		error happen
+ */
+static inline int m5_full_status_check(m5_t status, m5_t *reg)
+{
+	if ((status & M5_STATUS_PROGRAM) &&
+	    (status & M5_STATUS_ERASE)) {
+		printk("m5: command sequence error (addr=0x%08x, sts=0x%02x).\n",
+			(int)reg, status);
+		return FAILED;
+	}
+   	if(status & M5_STATUS_ERASE){
+      		printk("m5: erase error (addr=0x%08x, sts=0x%02x).\n",
+			(int)reg, status);
+      		return FAILED;
+   	}
+   	if(status & M5_STATUS_PROGRAM){
+      		printk("m5: program write error (addr=0x%08x, sts=0x%02x).\n",
+			(int)reg, status);
+      		return FAILED;
+   	}
+   	if(status & M5_STATUS_BLOCK){
+      		printk("m5: block write error (addr=0x%08x, sts=0x%02x).\n",
+			(int)reg, status);
+      		return FAILED;
+   	}
+	/* passed */
+   	return SUCCESS;
+}                     
+
+/*
+ * void m5_clear_status()
+ *	m5_t *reg:	address of status register
+ */
+static inline void m5_clear_status(m5_t *reg)
+{
+	m5_out(M5_CMD_CLEAR_STATUS, reg);
+}
+
+#if 0
+/*
+ * int m5_status_check()
+ *	m5_t *reg:	address of command register
+ *	SUCCESS:	ready now
+ *	FAILED:		error happen while waiting
+ */
+static int m5_status_check(m5_t *reg)
+{
+	m5_t status;
+	int result;
+	int n;
+	static int error_count = 0;
+
+	m5_out(M5_CMD_READ_STATUS, reg);
+	for (n = WAIT_COUNT; n > 0; n--) {
+		status = m5_in(reg);
+		if (status & M5_STATUS_READY)
+			break;
+		udelay(WAIT_TIME);
+	}
+	if (n <= 0) {
+		if (error_count++ < M5_MAX_ERROR)
+			printk("m5: time out (sts=0x%02x).\n", status);
+		m5_clear_status(reg);
+		return FAILED;
+	}
+	result = m5_full_status_check(status, reg);
+	if (result != SUCCESS) {
+		m5_clear_status(reg);
+		return FAILED;
+	}
+	m5_clear_status(reg);
+	return SUCCESS;
+}
+#endif
+
+/*
+ * int m5_wait_for_ready()
+ *	m5_t *reg:	address of command register
+ *	SUCCESS:	ready now
+ *	FAILED:		error happen while waiting
+ */
+static int m5_wait_for_ready(m5_t *reg)
+{
+	m5_t status;
+	int result;
+	int n;
+	static int error_count = 0;
+
+	for (n = WAIT_COUNT; n > 0; n--) {
+		status = m5_in(reg);
+		if (status & M5_STATUS_READY)
+			break;
+		udelay(WAIT_TIME);
+	}
+	if (n <= 0) {
+		if (error_count++ < M5_MAX_ERROR)
+			printk("m5: time out (sts=0x%02x).\n", status);
+		m5_clear_status(reg);
+		return FAILED;
+	}
+	result = m5_full_status_check(status, reg);
+	if (result != SUCCESS) {
+		m5_clear_status(reg);
+		return FAILED;
+	}
+	return SUCCESS;
+}
+
+/*
+ * int m5_write_page(m5_t *addr, const m5_t *buf)
+ *	m5_t *addr:	sector address
+ *	m5_t *buf:	buffer address
+ *	SUCCESS:	ok
+ *	FAILED:		error
+ */
+static int m5_write_page(m5_t *addr, const m5_t *buf)
+{
+	int blk;
+	int offset;
+
+	if (((int)addr % M5_PAGE_SIZE) != 0)
+		printk("m5: invalid sector addres (0x%08x)\n", (int)addr);
+
+	if (m5_read_blk_cache(addr) != SUCCESS)
+		return FAILED;
+	if ((blk = m5_get_blk_num(addr)) < 0)
+		return FAILED;
+	offset = m5_get_blk_offset(blk, addr);
+	memcpy((void *)M5_CACHED_BASE + offset, (void *)buf, M5_PAGE_SIZE);
+	M5_MARK_DIRTY();
+	return SUCCESS;
+}
+	
+/*
+ * int m5_write(const m5_t *buf, int offset, int len)
+ *	m5_t *buf:	write buffer address
+ *	int offset:	offset from flash base address
+ *	int len:	write length
+ *	SUCCESS:	ok
+ *	FAILE:		error
+ */
+static int m5_write(const m5_t *buf, int offset, int len)
+{
+	m5_t *addr;
+	int result;
+
+	if (len % M5_PAGE_SIZE) {
+		printk("m5: invalid write size (%d).\n", len);
+		return FAILED;
+	}
+	addr = (m5_t *)(m5_addr[MINOR(CURRENT_DEV)] + offset);
+
+	DEBUG(1, "m5: writing 0x%08x - 0x%08x\n", \
+		(int)addr, (int)addr + len);
+
+	for (; len > 0; len -= M5_PAGE_SIZE) {
+		result = m5_write_page(addr, buf);
+		if (result != SUCCESS)
+			return result;
+		addr = (m5_t *)((int)addr + M5_PAGE_SIZE);
+		buf = (m5_t *)((int)buf + M5_PAGE_SIZE);
+	}
+	return SUCCESS;
+}
+
+/*
+ * int m5_read_page()
+ *	m5_t *buf:	read buffer address
+ *	m5_t *addr:	page address
+ *	SUCCESS:	ok
+ *	FAILED:		error
+ */
+static int m5_read_page(m5_t *buf, m5_t *addr)
+{
+	int blk;
+	int offset;
+
+	if ((blk = m5_get_blk_num(addr)) < 0)
+		return FAILED;
+	if (M5_BLK_CACHED(blk)) {
+		offset = m5_get_blk_offset(blk, addr);
+		memcpy((void *)buf, (void *)M5_CACHED_BASE + offset,
+				M5_PAGE_SIZE);
+	} else {
+		/* read from flash memory directory */
+		memcpy((void *)buf, (void *)addr, M5_PAGE_SIZE);
+	}
+	return SUCCESS;
+}
+
+/*
+ * int m5_read()
+ *	m5_t *buf:		read buffer address
+ *	int offset:		offset from flash base address
+ *	int len:		read length
+ *	SUCCESS:		ok
+ *	FAILED:			error
+ */
+static int m5_read(m5_t *buf, int offset, int len)
+{
+	m5_t *addr;
+
+	if (len % M5_PAGE_SIZE) {
+		printk("m5: invalid read size (%d).\n", len);
+		return FAILED;
+	}
+
+	addr = (m5_t *)(m5_addr[MINOR(CURRENT_DEV)] + offset);
+
+	DEBUG(1, "m5: reading 0x%08x - 0x%08x\n", \
+		(int)addr, (int)addr + len);
+
+	for (; len > 0; len -= M5_PAGE_SIZE) {
+		if (m5_read_page(buf, addr) != SUCCESS)
+			return FAILED;
+		buf = (m5_t *)((int)buf + M5_PAGE_SIZE);
+		addr = (m5_t *)((int)addr + M5_PAGE_SIZE);
+	}
+	return SUCCESS;
+}
+
+/*
+ * int m5_erase_blk()
+ *	m5_t *addr:
+ */
+static int m5_erase_blk(m5_t *addr)
+{
+	int result;
+
+	DEBUG(1, "m5: erasing addr=0x%08x\n", (int)addr);
+	m5_out(M5_CMD_BLOCK_ERASE, addr);
+	m5_out(M5_CMD_CONFIRM, addr);
+	result = m5_wait_for_ready(addr);
+	return result;
+}
+
+/*
+ * void m5_request()
+ *	request_queue_t *req:	I/O request
+ *	end_request(0):	error (-EIO)
+ *	end_request(1): ok
+ */
+static void m5_request(request_queue_t *req)
+{
+    	unsigned int minor;
+    	int offset;
+	int len;
+	static int error_count = 0;
+
+	sti();
+	while (1) {
+		INIT_REQUEST;
+		minor = MINOR(CURRENT_DEV);
+		if (minor >= M5_PARTITIONS) {
+	    		printk( "m5: out of partition (%d)\n", minor );
+	    		end_request(0);
+	    		continue;
+		}
+		offset = CURRENT->sector * m5_hardsect_size[minor];
+		len = (CURRENT->current_nr_sectors *
+			m5_hardsect_size[minor]);
+		if ((offset + len) > m5_len[minor]) {
+	    		printk( "m5: out of sector (sector=%d, nr=%d)\n",
+				(int)(CURRENT->sector),
+				(int)(CURRENT->current_nr_sectors));
+	    		end_request(0);
+	    		continue;
+		}
+		switch(CURRENT->cmd) {
+	    	case READ:
+			if (m5_read((m5_t *)CURRENT->buffer,
+					offset, len) != SUCCESS)
+		    		end_request(0);
+			else
+		    		end_request(1);
+			break;
+	    	case WRITE:
+			if (m5_write((m5_t *)(CURRENT->buffer),
+					offset, len) != SUCCESS)
+		    		end_request(0);
+			else
+		    		end_request(1);
+                	break;
+	    	default:
+			if (error_count++ < M5_MAX_ERROR) {
+				printk("m5: invalid I/O request(%d)\n",
+					CURRENT->cmd);
+			}
+			end_request(0);
+			break;
+		}
+	}
+}
+
+/*
+ * int m5_ioctl()
+ *	struct inode *inode:
+ *	struct file *file:
+ *	unsigned int cmd:
+ *	unsigned long arg:
+ */
+static int m5_ioctl(struct inode *inode, struct file *fp, unsigned int cmd, unsigned long arg)
+{
+	int size;
+
+	DEBUG(2, "m5_ioctl()\n");
+    	switch (cmd) {
+      	case BLKGETSIZE:
+		if (!arg) return -EINVAL;
+		size = (1024 * m5_blk_size[MINOR(inode->i_rdev)] /
+			m5_hardsect_size[MINOR(inode->i_rdev)]);
+		return put_user(size, (long *)arg);
+      	case BLKFLSBUF:
+		if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+		fsync_dev(inode->i_rdev);
+		invalidate_buffers(inode->i_rdev);
+		return 0;
+	case BLKRRPART:
+		return -EINVAL;
+
+	case BLKRAGET:
+	case BLKRASET:
+	case BLKGETSIZE64:
+	case BLKROSET:
+	case BLKROGET:
+      	case BLKSSZGET:
+		return blk_ioctl(inode->i_rdev, cmd, arg);
+      	default:
+		printk( "m5: unsupported ioctl(0x%08x)\n", cmd);
+		return -EINVAL;
+    	}
+    	return 0;
+}
+
+/*
+ * int m5_open()
+ *	struct inode *inode:
+ *	struct file *fp:
+ */
+static int m5_open(struct inode *inode, struct file *fp)
+{
+    	if (DEVICE_NR(inode->i_rdev) >= M5_PARTITIONS) return -ENXIO;
+    	MOD_INC_USE_COUNT;
+    	return 0;
+}
+
+/*
+ * int m5_release()
+ *	struct inode *inode:
+ *	struct file *fp:
+ */
+static int m5_release(struct inode *inode, struct file *fp)
+{
+    	sync_dev(inode->i_rdev);
+    	MOD_DEC_USE_COUNT;
+    	return 0;
+}
+
+#ifdef CONFIG_PROC_FS
+/*
+ * int proc_m5_read()
+ *	char *buf:
+ *	char **start:
+ *	off_t offset:
+ *	int len:
+ *	int *eof:
+ *	void *unused:
+ */
+static int proc_m5_read(char *buf, char **start, off_t offset, int len, int *eof, void *unused)
+{
+	len = sprintf(buf, "partition: %d\n", M5_PARTITIONS);
+	return len;
+}
+#endif
+
+static struct block_device_operations m5_fops = {
+	open:		m5_open,
+	release:	m5_release,
+	ioctl:		m5_ioctl,
+	/* check_media_change: */
+	/* revalidate: */
+	owner:		THIS_MODULE,
+};
+
+/*
+ * int m5_init()
+ */
+static int __init m5_init(void)
+{
+	int i;
+	int result;
+
+	result = -EIO;
+
+	printk("%s (%s %s)\n", version, date, time);
+#if M5_SUPPORT_PROBE
+	if (m5_probe((m5_t *)M5_BASE_ADDR) != SUCCESS)
+		return result;
+#endif	/* M5_SUPPORT_PROBE */
+
+	if (register_blkdev(major, DEVICE_NAME, &m5_fops) ) {
+		printk("m5: can not not get major %d", major);
+		return result;
+	}
+
+	if (devfs_register_blkdev(major, DEVICE_NAME, &m5_fops) ) {
+		printk("m5: can not not get major %d", major);
+		goto fail_devfs;
+	}
+	devfs_handle = devfs_mk_dir(NULL, "m5", NULL);
+	devfs_register_series(devfs_handle, "%u", M5_PARTITIONS,
+			      DEVFS_FL_DEFAULT, major, 0,
+			      S_IFBLK | S_IRUSR | S_IWUSR,
+			      &m5_fops, NULL);
+
+	for (i = 0; i < M5_PARTITIONS; i++) {
+		if (i) {
+			m5_addr[i] = m5_addr[i-1] + m5_len[i-1];
+		} else { 
+			m5_addr[i] = M5_BASE_ADDR;
+		}
+		m5_blk_size[i] = m5_len[i]/1024;	/* KB order */
+		m5_blksize_size[i] = BLOCK_SIZE;  	/* 1024 byte */
+		m5_hardsect_size[i] = BLOCK_SIZE/2;	/* 512 byte */
+	}
+	/* defined in ll_rw_blk.c */
+	blk_size[major] = m5_blk_size;
+	blksize_size[major] = m5_blksize_size;
+	hardsect_size[major] = m5_hardsect_size;
+	read_ahead[major] = m5_read_ahead;
+
+	blk_init_queue(BLK_DEFAULT_QUEUE(major), &m5_request);
+
+	for (i = 0; i < M5_PARTITIONS; i++)
+		register_disk(  NULL, MKDEV(major,i), 1, 
+				&m5_fops, m5_len[i]>>9 );
+
+#ifdef CONFIG_PROC_FS
+#if	1
+	proc_m5 = proc_mkdir("m5", proc_root_driver);
+	if (!proc_m5) {
+		printk(KERN_ERR "m5: unable to register driver/m5\n");
+		goto fail_proc;
+	}
+	create_proc_read_entry("0", 0, proc_m5, proc_m5_read, 0);
+	create_proc_read_entry("1", 0, proc_m5, proc_m5_read, 0);
+	create_proc_read_entry("2", 0, proc_m5, proc_m5_read, 0);
+#else
+	proc_m5 = create_proc_entry("driver/m5", 666, 0);
+	if (!proc_m5) {
+		printk(KERN_ERR "m5: unable to register driver/m5\n");
+		goto fail_proc;
+	}
+	proc_m5->read_proc = proc_m5_read;
+#endif
+#endif
+
+	printk("m5: Major=%d Partitions=%d\n", major,M5_PARTITIONS);
+	for (i = 0; i < M5_PARTITIONS; i++) {
+	printk("  %d: 0x%08x-0x%08x (all=%dKB,blk=%dB,sect=%dB,ahead=%d)\n",
+	        i, m5_addr[i],
+		m5_addr[i] + m5_len[i], 
+		m5_blk_size[i],
+		m5_blksize_size[i],
+		m5_hardsect_size[i],
+		m5_read_ahead);
+	}
+
+	/* clear cache */
+	M5_MARK_CLEAN();
+	M5_MARK_NOCACHED();
+
+	m5_led_off();
+	return 0;
+
+fail_proc:
+	devfs_unregister(devfs_handle);
+fail_devfs:
+	unregister_blkdev(major, DEVICE_NAME);
+	return result;
+}
+
+static int __init m5_init_module(void)
+{
+    return m5_init();
+}
+
+static void __exit m5_cleanup_module(void)
+{
+    	int i;
+ 
+    	for (i = 0 ; i < M5_PARTITIONS; i++) {
+		fsync_dev(MKDEV(major, i));	/* flush buffer */
+      		destroy_buffers(MKDEV(major, i));
+	}
+	m5_write_blk_cache();		/* flush m5 cache */
+    	devfs_unregister(devfs_handle);
+    	unregister_blkdev(major, DEVICE_NAME);
+#ifdef CONFIG_PROC_FS
+	remove_proc_entry("0", proc_m5);
+	remove_proc_entry("1", proc_m5);
+	remove_proc_entry("2", proc_m5);
+	remove_proc_entry("m5", proc_root_driver);
+#endif
+    	blk_cleanup_queue(BLK_DEFAULT_QUEUE(major));
+	blk_size[major] = NULL;
+	blksize_size[major] = NULL;
+	hardsect_size[major] = NULL;
+	read_ahead[major] = 0;
+}
+
+module_init(m5_init_module);
+module_exit(m5_cleanup_module);
+
+MODULE_AUTHOR("Takeo Takahashi");
+MODULE_DESCRIPTION("M5 Flash Driver for M32700UT-CPU");
+MODULE_LICENSE("GPL");
+EXPORT_NO_SYMBOLS;
+
diff -ruN linux-2.6.0.org/arch/m32r/drivers/m5.h linux-2.6.0/arch/m32r/drivers/m5.h
--- linux-2.6.0.org/arch/m32r/drivers/m5.h	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.0/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.0.org/arch/m32r/drivers/m5drv.c linux-2.6.0/arch/m32r/drivers/m5drv.c
--- linux-2.6.0.org/arch/m32r/drivers/m5drv.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.0/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.0.org/arch/m32r/drivers/mappi_ne.c linux-2.6.0/arch/m32r/drivers/mappi_ne.c
--- linux-2.6.0.org/arch/m32r/drivers/mappi_ne.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.0/arch/m32r/drivers/mappi_ne.c	2003-09-09 10:15:02.000000000 +0900
@@ -0,0 +1,828 @@
+/* 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 */
+
+int ne_probe(struct net_device *dev);
+static int ne_probe1(struct net_device *dev, int ioaddr);
+static int ne_probe_isapnp(struct net_device *dev);
+
+static int ne_open(struct net_device *dev);
+static int ne_close(struct net_device *dev);
+
+static void ne_reset_8390(struct net_device *dev);
+static void ne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
+			  int ring_page);
+static void ne_block_input(struct net_device *dev, int count,
+			  struct sk_buff *skb, int ring_offset);
+static void ne_block_output(struct net_device *dev, const int count,
+		const unsigned char *buf, const int start_page);
+
+
+/*  Probe for various non-shared-memory ethercards.
+
+   NEx000-clone boards have a Station Address PROM (SAPROM) in the packet
+   buffer memory space.  NE2000 clones have 0x57,0x57 in bytes 0x0e,0x0f of
+   the SAPROM, while other supposed NE2000 clones must be detected by their
+   SA prefix.
+
+   Reading the SAPROM from a word-wide card with the 8390 set in byte-wide
+   mode results in doubled values, which can be detected and compensated for.
+
+   The probe is also responsible for initializing the card and filling
+   in the 'dev' and 'ei_status' structures.
+
+   We use the minimum memory size for some ethercard product lines, iff we can't
+   distinguish models.  You can increase the packet buffer size by setting
+   PACKETBUF_MEMSIZE.  Reported Cabletron packet buffer locations are:
+	E1010   starts at 0x100 and ends at 0x2000.
+	E1010-x starts at 0x100 and ends at 0x8000. ("-x" means "more memory")
+	E2010	 starts at 0x100 and ends at 0x4000.
+	E2010-x starts at 0x100 and ends at 0xffff.  */
+
+int __init ne_probe(struct net_device *dev)
+{
+	unsigned int base_addr = dev->base_addr;
+
+	SET_MODULE_OWNER(dev);
+
+	/* First check any supplied i/o locations. User knows best. <cough> */
+	if (base_addr > 0x1ff)	/* Check a single specified location. */
+		return ne_probe1(dev, base_addr);
+	else if (base_addr != 0)	/* Don't probe at all. */
+		return -ENXIO;
+
+	/* Then look for any installed ISAPnP clones */
+	if (isapnp_present() && (ne_probe_isapnp(dev) == 0))
+		return 0;
+
+#ifndef MODULE
+	/* Last resort. The semi-risky ISA auto-probe. */
+	for (base_addr = 0; netcard_portlist[base_addr] != 0; base_addr++) {
+		int ioaddr = netcard_portlist[base_addr];
+		if (ne_probe1(dev, ioaddr) == 0)
+			return 0;
+	}
+#endif
+
+	return -ENODEV;
+}
+
+static int __init ne_probe_isapnp(struct net_device *dev)
+{
+	int i;
+
+	for (i = 0; isapnp_clone_list[i].vendor != 0; i++) {
+		struct 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);
+#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;
+	}
+
+#ifdef CONFIG_PLAT_MAPPI
+	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;
+	}
+
+	/* Allocate dev->priv and fill in 8390 specific dev fields. */
+	if (ethdev_init(dev))
+	{
+        	printk (" unable to get memory for dev->priv.\n");
+        	ret = -ENOMEM;
+		goto err_out;
+	}
+
+	/* Snarf the interrupt now.  There's no point in waiting since we cannot
+	   share and the board will usually be enabled. */
+	ret = request_irq(dev->irq, ei_interrupt, 0, name, dev);
+	if (ret) {
+		printk (" unable to get IRQ %d (errno=%d).\n", dev->irq, ret);
+		goto err_out_kfree;
+	}
+
+	dev->base_addr = ioaddr;
+
+#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;
+	ei_status.word16 = (wordlength == 2);
+
+	ei_status.rx_start_page = start_page + TX_PAGES;
+#ifdef PACKETBUF_MEMSIZE
+	 /* Allow the packet buffer size to be overridden by know-it-alls. */
+	ei_status.stop_page = ei_status.tx_start_page + PACKETBUF_MEMSIZE;
+#endif
+
+	ei_status.reset_8390 = &ne_reset_8390;
+	ei_status.block_input = &ne_block_input;
+	ei_status.block_output = &ne_block_output;
+	ei_status.get_8390_hdr = &ne_get_8390_hdr;
+	ei_status.priv = 0;
+	dev->open = &ne_open;
+	dev->stop = &ne_close;
+	NS8390_init(dev, 0);
+	return 0;
+
+err_out_kfree:
+	kfree(dev->priv);
+	dev->priv = NULL;
+err_out:
+	release_region(ioaddr, NE_IO_EXTENT);
+	return ret;
+}
+
+static int ne_open(struct net_device *dev)
+{
+	ei_open(dev);
+	return 0;
+}
+
+static int ne_close(struct net_device *dev)
+{
+	if (ei_debug > 1)
+		printk(KERN_DEBUG "%s: Shutting down ethercard.\n", dev->name);
+	ei_close(dev);
+	return 0;
+}
+
+/* Hard reset the card.  This used to pause for the same period that a
+   8390 reset command required, but that shouldn't be necessary. */
+
+static void ne_reset_8390(struct net_device *dev)
+{
+	unsigned long reset_start_time = jiffies;
+
+	if (ei_debug > 1)
+		printk(KERN_DEBUG "resetting the 8390 t=%ld...", jiffies);
+
+	/* DON'T change these to inb_p/outb_p or reset will fail on clones. */
+	outb(inb(NE_BASE + NE_RESET), NE_BASE + NE_RESET);
+
+	ei_status.txing = 0;
+	ei_status.dmaing = 0;
+
+	/* This check _should_not_ be necessary, omit eventually. */
+	while ((inb_p(NE_BASE+EN0_ISR) & ENISR_RESET) == 0)
+		if (jiffies - reset_start_time > 2*HZ/100) {
+			printk(KERN_WARNING "%s: ne_reset_8390() did not complete.\n", dev->name);
+			break;
+		}
+	outb_p(ENISR_RESET, NE_BASE + EN0_ISR);	/* Ack intr. */
+}
+
+/* Grab the 8390 specific header. Similar to the block_input routine, but
+   we don't need to be concerned with ring wrap as the header will be at
+   the start of a page, so we optimize accordingly. */
+
+static void ne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
+{
+	int nic_base = dev->base_addr;
+
+	/* This *shouldn't* happen. If it does, it's the last thing you'll see */
+
+	if (ei_status.dmaing)
+	{
+		printk(KERN_EMERG "%s: DMAing conflict in ne_get_8390_hdr "
+			"[DMAstat:%d][irqlock:%d].\n",
+			dev->name, ei_status.dmaing, ei_status.irqlock);
+		return;
+	}
+
+	ei_status.dmaing |= 0x01;
+	outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
+	outb_p(sizeof(struct e8390_pkt_hdr), nic_base + EN0_RCNTLO);
+	outb_p(0, nic_base + EN0_RCNTHI);
+	outb_p(0, nic_base + EN0_RSARLO);		/* On page boundary */
+	outb_p(ring_page, nic_base + EN0_RSARHI);
+	outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD);
+
+	if (ei_status.word16)
+		insw(NE_BASE + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)>>1);
+	else
+		insb(NE_BASE + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr));
+
+	outb_p(ENISR_RDC, nic_base + EN0_ISR);	/* Ack intr. */
+	ei_status.dmaing &= ~0x01;
+
+	le16_to_cpus(&hdr->count);
+}
+
+/* Block input and output, similar to the Crynwr packet driver.  If you
+   are porting to a new ethercard, look at the packet driver source for hints.
+   The NEx000 doesn't share the on-board packet memory -- you have to put
+   the packet out through the "remote DMA" dataport using outb. */
+
+static void ne_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
+{
+#ifdef NE_SANITY_CHECK
+	int xfer_count = count;
+#endif
+	int nic_base = dev->base_addr;
+	char *buf = skb->data;
+
+	/* This *shouldn't* happen. If it does, it's the last thing you'll see */
+	if (ei_status.dmaing)
+	{
+		printk(KERN_EMERG "%s: DMAing conflict in ne_block_input "
+			"[DMAstat:%d][irqlock:%d].\n",
+			dev->name, ei_status.dmaing, ei_status.irqlock);
+		return;
+	}
+	ei_status.dmaing |= 0x01;
+	outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
+	outb_p(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 = &dev_ne[this_dev];
+		dev->irq = irq[this_dev];
+		dev->mem_end = bad[this_dev];
+		dev->base_addr = io[this_dev];
+		dev->init = ne_probe;
+		if (register_netdev(dev) == 0) {
+			found++;
+			continue;
+		}
+		if (found != 0) { 	/* Got at least one. */
+			return 0;
+		}
+		if (io[this_dev] != 0)
+			printk(KERN_WARNING "ne.c: No NE*000 card found at i/o = %#x\n", io[this_dev]);
+		else
+			printk(KERN_NOTICE "ne.c: You must supply \"io=0xNNN\" value(s) for ISA cards.\n");
+		return -ENXIO;
+	}
+	return 0;
+}
+
+void cleanup_module(void)
+{
+	int this_dev;
+
+	for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) {
+		struct net_device *dev = &dev_ne[this_dev];
+		if (dev->priv != NULL) {
+			void *priv = dev->priv;
+			struct 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);
+			unregister_netdev(dev);
+			kfree(priv);
+		}
+	}
+}
+#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.0.org/arch/m32r/drivers/smc91111.c linux-2.6.0/arch/m32r/drivers/smc91111.c
--- linux-2.6.0.org/arch/m32r/drivers/smc91111.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.0/arch/m32r/drivers/smc91111.c	2004-03-16 19:34:57.000000000 +0900
@@ -0,0 +1,3893 @@
+/*------------------------------------------------------------------------
+ . 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)
+#define NO_AUTOPROBE
+#endif
+
+// Use power-down feature of the chip
+#define POWER_DOWN	0
+
+
+static const char version[] =
+	"SMSC LAN91C111 Driver (v2.0), (Linux Kernel 2.4 + Support for Odd Byte) 09/24/01 -      by Pramod Bhardwaj (pramod.bhardwaj@smsc.com)\n\n";
+
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#endif
+
+#include <linux/kernel.h>
+#include <linux/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.
+*/
+int smc_init(struct net_device *dev);
+
+/*
+ . This is called by  unregister_netdev().  It is responsible for
+ . cleaning up before the driver is finally unregistered and discarded.
+*/
+void smc_destructor(struct net_device *dev);
+
+/*
+ . The kernel calls this function when someone wants to use the net_device,
+ . typically 'ifconfig ethX up'.
+*/
+static int smc_open(struct net_device *dev);
+
+/*
+ . This is called by the kernel to send a packet out into the net.  it's
+ . responsible for doing a best-effort send, but if it's simply not possible
+ . to send it, the packet gets dropped.
+*/
+static void smc_timeout (struct net_device *dev);
+/*
+ . This is called by the kernel in response to 'ifconfig ethX down'.  It
+ . is responsible for cleaning up everything that the open routine
+ . does, and maybe putting the card into a powerdown state.
+*/
+static int smc_close(struct net_device *dev);
+
+/*
+ . This routine allows the proc file system to query the driver's
+ . statistics.
+*/
+static struct net_device_stats * smc_query_statistics( struct net_device *dev);
+
+/*
+ . Finally, a call to set promiscuous mode ( for TCPDUMP and related
+ . programs ) and multicast modes.
+*/
+static void smc_set_multicast_list(struct net_device *dev);
+
+/*
+ . Configures the PHY through the MII Management interface
+*/
+static void smc_phy_configure(struct net_device* dev);
+
+/*---------------------------------------------------------------
+ .
+ . Interrupt level calls..
+ .
+ ----------------------------------------------------------------*/
+
+/*
+ . Handles the actual interrupt
+*/
+static 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
+*/
+inline static void smc_rcv( struct net_device *dev );
+/*
+ . This handles a TX interrupt, which is only called when an error
+ . relating to a packet is sent.
+*/
+inline static void smc_tx( struct net_device * dev );
+
+/*
+ . This handles interrupts generated from PHY register 18
+*/
+static void smc_phy_interrupt(struct net_device* dev);
+
+/*
+ ------------------------------------------------------------
+ .
+ . Internal routines
+ .
+ ------------------------------------------------------------
+*/
+
+/*
+ . Test if a given location contains a chip, trying to cause as
+ . little damage as possible if it's not a SMC chip.
+*/
+static int smc_probe(struct net_device *dev, int ioaddr);
+
+/*
+ . A rather simple routine to print out a packet for debugging purposes.
+*/
+#if SMC_DEBUG > 2
+static void print_packet( byte *, int );
+#endif
+
+#define tx_done(dev) 1
+
+/* this is called to actually send the packet to the chip */
+static void smc_hardware_send_packet( struct net_device * dev );
+
+/* Since I am not sure if I will have enough room in the chip's ram
+ . to store the packet, I call this routine, which either sends it
+ . now, or generates an interrupt when the card is ready for the
+ . packet */
+static int  smc_wait_to_send_packet( struct sk_buff * skb, struct net_device *dev );
+
+/* this does a soft reset on the device */
+static void smc_reset( struct net_device* dev );
+
+/* Enable Interrupts, Receive, and Transmit */
+static void smc_enable( struct net_device *dev );
+
+/* this puts the device in an inactive state */
+static void smc_shutdown( int ioaddr );
+
+#ifndef NO_AUTOPROBE
+/* This routine will find the IRQ of the driver if one is not
+ . specified in the input to the device.  */
+static int smc_findirq( int ioaddr );
+#endif
+
+/*
+  this routine will set the hardware multicast table to the specified
+  values given it by the higher level routines
+*/
+static void smc_setmulticast( int ioaddr, int count, struct dev_mc_list *  );
+static int crc32( char *, int );
+
+/* Routines to Read and Write the PHY Registers across the
+   MII Management Interface
+*/
+
+static word smc_read_phy_register(int ioaddr, byte phyaddr, byte phyreg);
+static void smc_write_phy_register(int ioaddr, byte phyaddr, byte phyreg, word phydata);
+
+/* Initilizes our device's sysctl proc filesystem */
+
+#ifdef CONFIG_SYSCTL
+static void smc_sysctl_register(struct net_device *);
+static void smc_sysctl_unregister(struct net_device *);
+#endif /* CONFIG_SYSCTL */ 
+
+/*
+ . Function: smc_reset( struct device* dev )
+ . Purpose:
+ .  	This sets the SMC91111 chip to its normal state, hopefully from whatever
+ . 	mess that any other DOS driver has put it in.
+ .
+ . Maybe I should reset more registers to defaults in here?  SOFTRST  should
+ . do that for me.
+ .
+ . Method:
+ .	1.  send a SOFT RESET
+ .	2.  wait for it to finish
+ .	3.  enable autorelease mode
+ .	4.  reset the memory management unit
+ .	5.  clear all interrupts
+ .
+*/
+static void smc_reset( struct net_device* dev )
+{
+	//struct smc_local *lp 	= (struct smc_local *)dev->priv;
+	int	ioaddr = dev->base_addr;
+
+	PRINTK2("%s:smc_reset\n", dev->name);
+
+	/* This resets the registers mostly to defaults, but doesn't
+	   affect EEPROM.  That seems unnecessary */
+	SMC_SELECT_BANK( 0 );
+	outw( RCR_SOFTRST, ioaddr + RCR_REG );
+
+	/* Setup the Configuration Register */
+	/* This is necessary because the CONFIG_REG is not affected */
+	/* by a soft reset */
+
+	SMC_SELECT_BANK( 1 );
+	outw( CONFIG_DEFAULT, ioaddr + CONFIG_REG);
+
+	/* Setup for fast accesses if requested */
+	/* If the card/system can't handle it then there will */
+	/* be no recovery except for a hard reset or power cycle */
+
+	if (dev->dma)
+		outw( inw( ioaddr + CONFIG_REG ) | CONFIG_NO_WAIT,
+			ioaddr + CONFIG_REG );
+
+#ifdef POWER_DOWN
+	/* Release from possible power-down state */
+	/* Configuration register is not affected by Soft Reset */
+	SMC_SELECT_BANK( 1 );
+	outw( inw( ioaddr + CONFIG_REG ) | CONFIG_EPH_POWER_EN,
+		ioaddr + CONFIG_REG  );
+#endif
+
+	SMC_SELECT_BANK( 0 );
+
+	/* this should pause enough for the chip to be happy */
+	mdelay(10);
+
+	/* Disable transmit and receive functionality */
+	outw( RCR_CLEAR, ioaddr + RCR_REG );
+	outw( TCR_CLEAR, ioaddr + TCR_REG );
+
+	/* set the control register to automatically
+	   release successfully transmitted packets, to make the best
+	   use out of our limited memory */
+	SMC_SELECT_BANK( 1 );
+#if ! THROTTLE_TX_PKTS
+	outw( inw( ioaddr + CTL_REG ) | CTL_AUTO_RELEASE , ioaddr + CTL_REG );
+#else
+	outw( inw( ioaddr + CTL_REG ) & ~CTL_AUTO_RELEASE , ioaddr + CTL_REG );
+#endif
+
+	/* Reset the MMU */
+	SMC_SELECT_BANK( 2 );
+	outw( MC_RESET, ioaddr + MMU_CMD_REG );
+
+	/* Note:  It doesn't seem that waiting for the MMU busy is needed here,
+	   but this is a place where future chipsets _COULD_ break.  Be wary
+ 	   of issuing another MMU command right after this */
+
+	/* Disable all interrupts */
+	outb( 0, ioaddr + IM_REG );
+}
+
+/*
+ . Function: smc_enable
+ . Purpose: let the chip talk to the outside work
+ . Method:
+ .	1.  Enable the transmitter
+ .	2.  Enable the receiver
+ .	3.  Enable interrupts
+*/
+static void smc_enable( struct net_device *dev )
+{
+	unsigned short ioaddr 	= dev->base_addr;
+	struct smc_local *lp 	= (struct smc_local *)dev->priv;
+
+	PRINTK2("%s:smc_enable\n", dev->name);
+
+	SMC_SELECT_BANK( 0 );
+	/* see the header file for options in TCR/RCR DEFAULT*/
+	outw( lp->tcr_cur_mode, ioaddr + TCR_REG );
+	outw( lp->rcr_cur_mode, ioaddr + RCR_REG );
+
+	/* now, enable interrupts */
+	SMC_SELECT_BANK( 2 );
+	outb( SMC_INTERRUPT_MASK, ioaddr + IM_REG );
+}
+
+/*
+ . Function: smc_shutdown
+ . Purpose:  closes down the SMC91xxx chip.
+ . Method:
+ .	1. zero the interrupt mask
+ .	2. clear the enable receive flag
+ .	3. clear the enable xmit flags
+ .
+ . TODO:
+ .   (1) maybe utilize power down mode.
+ .	Why not yet?  Because while the chip will go into power down mode,
+ .	the manual says that it will wake up in response to any I/O requests
+ .	in the register space.   Empirical results do not show this working.
+*/
+static void smc_shutdown( int ioaddr )
+{
+	PRINTK2("CARDNAME:smc_shutdown\n");
+
+	/* no more interrupts for me */
+	SMC_SELECT_BANK( 2 );
+	outb( 0, ioaddr + IM_REG );
+
+	/* and tell the card to stay away from that nasty outside world */
+	SMC_SELECT_BANK( 0 );
+	outb( RCR_CLEAR, ioaddr + RCR_REG );
+	outb( TCR_CLEAR, ioaddr + TCR_REG );
+
+#ifdef POWER_DOWN
+	/* finally, shut the chip down */
+	SMC_SELECT_BANK( 1 );
+	outw( inw( ioaddr + CONFIG_REG ) & ~CONFIG_EPH_POWER_EN,
+		ioaddr + CONFIG_REG  );
+#endif
+}
+
+
+/*
+ . Function: smc_setmulticast( int ioaddr, int count, dev_mc_list * adds )
+ . Purpose:
+ .    This sets the internal hardware table to filter out unwanted multicast
+ .    packets before they take up memory.
+ .
+ .    The SMC chip uses a hash table where the high 6 bits of the CRC of
+ .    address are the offset into the table.  If that bit is 1, then the
+ .    multicast packet is accepted.  Otherwise, it's dropped silently.
+ .
+ .    To use the 6 bits as an offset into the table, the high 3 bits are the
+ .    number of the 8 bit register, while the low 3 bits are the bit within
+ .    that register.
+ .
+ . This routine is based very heavily on the one provided by Peter Cammaert.
+*/
+
+
+static void smc_setmulticast( int ioaddr, int count, struct dev_mc_list * addrs ) {
+	int			i;
+	unsigned char		multicast_table[ 8 ];
+	struct dev_mc_list	* cur_addr;
+	/* table for flipping the order of 3 bits */
+	unsigned char invert3[] = { 0, 4, 2, 6, 1, 5, 3, 7 };
+
+	PRINTK2("CARDNAME:smc_setmulticast\n");
+
+	/* start with a table of all zeros: reject all */
+	memset( multicast_table, 0, sizeof( multicast_table ) );
+
+	cur_addr = addrs;
+	for ( i = 0; i < count ; i ++, cur_addr = cur_addr->next  ) {
+		int position;
+
+		/* do we have a pointer here? */
+		if ( !cur_addr )
+			break;
+		/* make sure this is a multicast address - shouldn't this
+		   be a given if we have it here ? */
+		if ( !( *cur_addr->dmi_addr & 1 ) )
+			continue;
+
+		/* only use the low order bits */
+		position = crc32( cur_addr->dmi_addr, 6 ) & 0x3f;
+
+		/* do some messy swapping to put the bit in the right spot */
+		multicast_table[invert3[position&7]] |=
+					(1<<invert3[(position>>3)&7]);
+
+	}
+	/* now, the table can be loaded into the chipset */
+	SMC_SELECT_BANK( 3 );
+
+	for ( i = 0; i < 8 ; i++ ) {
+		outb( multicast_table[i], ioaddr + MCAST_REG1 + i );
+	}
+}
+
+/*
+  Finds the CRC32 of a set of bytes.
+  Again, from Peter Cammaert's code.
+*/
+static int crc32( char * s, int length ) {
+	/* indices */
+	int perByte;
+	int perBit;
+	/* crc polynomial for Ethernet */
+	const unsigned long poly = 0xedb88320;
+	/* crc value - preinitialized to all 1's */
+	unsigned long crc_value = 0xffffffff;
+
+	for ( perByte = 0; perByte < length; perByte ++ ) {
+		unsigned char	c;
+
+		c = *(s++);
+		for ( perBit = 0; perBit < 8; perBit++ ) {
+			crc_value = (crc_value>>1)^
+				(((crc_value^c)&0x01)?poly:0);
+			c >>= 1;
+		}
+	}
+	return	crc_value;
+}
+
+
+/*
+ . Function: smc_wait_to_send_packet( struct sk_buff * skb, struct device * )
+ . Purpose:
+ .    Attempt to allocate memory for a packet, if chip-memory is not
+ .    available, then tell the card to generate an interrupt when it
+ .    is available.
+ .
+ . Algorithm:
+ .
+ . o	if the saved_skb is not currently null, then drop this packet
+ .	on the floor.  This should never happen, because of TBUSY.
+ . o	if the saved_skb is null, then replace it with the current packet,
+ . o	See if I can sending it now.
+ . o 	(NO): Enable interrupts and let the interrupt handler deal with it.
+ . o	(YES):Send it now.
+*/
+static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * dev )
+{
+	struct smc_local *lp 	= (struct smc_local *)dev->priv;
+	unsigned short ioaddr 	= dev->base_addr;
+	word 			length;
+	unsigned short 		numPages;
+	word			time_out;
+	word			status;
+	unsigned long flags;
+
+	PRINTK3("%s:smc_wait_to_send_packet\n", dev->name);
+
+	spin_lock_irqsave(&lp->lock, flags);
+
+	if ( lp->saved_skb) {
+		/* THIS SHOULD NEVER HAPPEN. */
+		lp->stats.tx_aborted_errors++;
+		printk("%s: Bad Craziness - sent packet while busy.\n",
+			dev->name);
+		spin_unlock_irqrestore(&lp->lock, flags);
+		return 1;
+	}
+	lp->saved_skb = skb;
+
+	length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+		
+	/*
+	** The MMU wants the number of pages to be the number of 256 bytes
+	** 'pages', minus 1 ( since a packet can't ever have 0 pages :) )
+	**
+	** The 91C111 ignores the size bits, but the code is left intact
+	** for backwards and future compatibility.
+	**
+	** Pkt size for allocating is data length +6 (for additional status
+	** words, length and ctl!)
+	**
+	** If odd size then last byte is included in this header.
+	*/
+	numPages =   ((length & 0xfffe) + 6);
+	numPages >>= 8; // Divide by 256
+
+	if (numPages > 7 ) {
+		printk("%s: Far too big packet error. \n", dev->name);
+		/* freeing the packet is a good thing here... but should
+		 . any packets of this size get down here?   */
+		dev_kfree_skb (skb);
+		lp->saved_skb = NULL;
+		/* this IS an error, but, i don't want the skb saved */
+		netif_wake_queue(dev);
+		spin_unlock_irqrestore(&lp->lock, flags);
+		return 0;
+	}
+	/* either way, a packet is waiting now */
+	lp->packets_waiting++;
+
+	/* now, try to allocate the memory */
+	SMC_SELECT_BANK( 2 );
+	outw( MC_ALLOC | numPages, ioaddr + MMU_CMD_REG );
+	/*
+ 	. Performance Hack
+	.
+ 	. wait a short amount of time.. if I can send a packet now, I send
+	. it now.  Otherwise, I enable an interrupt and wait for one to be
+	. available.
+	.
+	. I could have handled this a slightly different way, by checking to
+	. see if any memory was available in the FREE MEMORY register.  However,
+	. either way, I need to generate an allocation, and the allocation works
+	. no matter what, so I saw no point in checking free memory.
+	*/
+	time_out = MEMORY_WAIT_TIME;
+	do {
+		status = inb( ioaddr + INT_REG );
+		if ( status & IM_ALLOC_INT ) {
+			/* acknowledge the interrupt */
+			outb( IM_ALLOC_INT, ioaddr + INT_REG );
+  			break;
+		}
+   	} while ( -- time_out );
+
+   	if ( !time_out ) {
+#if defined(__m32r__)
+//		netif_stop_queue(dev); 	// 2003-07-13 by takeo
+#endif
+		/* oh well, wait until the chip finds memory later */
+		SMC_ENABLE_INT( IM_ALLOC_INT );
+
+		/* Check the status bit one more time just in case */
+		/* it snuk in between the time we last checked it */
+		/* and when we set the interrupt bit */
+		status = inb( ioaddr + INT_REG );
+		if ( !(status & IM_ALLOC_INT) ) {
+      			PRINTK2("%s: memory allocation deferred. \n",
+				dev->name);
+			/* it's deferred, but I'll handle it later */
+			spin_unlock_irqrestore(&lp->lock, flags);
+      			return 0;
+		}
+
+		/* Looks like it did sneak in, so disable */
+		/* the interrupt */
+		SMC_DISABLE_INT( IM_ALLOC_INT );
+	}
+	/* or YES! I can send the packet now.. */
+#if THROTTLE_TX_PKTS
+                netif_stop_queue(dev);
+#endif
+	smc_hardware_send_packet(dev);
+//	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( struct device * dev )
+ |   Input parameters:
+ |	dev->base_addr == 0, try to find all possible locations
+ |	dev->base_addr == 1, return failure code
+ |	dev->base_addr == 2, always allocate space,  and return success
+ |	dev->base_addr == <anything else>   this is the address to check
+ |
+ |   Output:
+ |	0 --> there is a device
+ |	anything else, error
+ |
+ ---------------------------------------------------------------------------
+*/
+int __init smc_init(struct net_device *dev)
+{
+	int i;
+	int base_addr = dev ? dev->base_addr : 0;
+
+	PRINTK2("CARDNAME:smc_init\n");
+
+#ifdef MODULE
+	SET_MODULE_OWNER (dev);
+#endif
+
+	/*  try a specific location */
+	if (base_addr > 0x1ff)
+		return smc_probe(dev, base_addr);
+	else if ( 0 != base_addr ) 
+			return -ENXIO;
+		
+	/* check every ethernet address */
+	for (i = 0; smc_portlist[i]; i++) 
+		if ( smc_probe(dev,smc_portlist[i]) ==0)
+			return 0;
+		
+	/* couldn't find anything */
+	return -ENODEV;
+}
+
+
+/*-------------------------------------------------------------------------
+ |
+ | smc_destructor( struct device * dev )
+ |   Input parameters:
+ |	dev, pointer to the device structure
+ |
+ |   Output:
+ |	None.
+ |
+ ---------------------------------------------------------------------------
+*/
+void smc_destructor(struct net_device *dev)
+{
+	PRINTK2("CARDNAME:smc_destructor\n");
+}
+
+
+#ifndef NO_AUTOPROBE
+/*----------------------------------------------------------------------
+ . smc_findirq
+ .
+ . This routine has a simple purpose -- make the SMC chip generate an
+ . interrupt, so an auto-detect routine can detect it, and find the IRQ,
+ ------------------------------------------------------------------------
+*/
+int __init smc_findirq( int ioaddr )
+{
+	int	timeout = 20;
+	unsigned long cookie;
+
+	PRINTK2("CARDNAME:smc_findirq\n");
+
+	/* I have to do a STI() here, because this is called from
+	   a routine that does an CLI during this process, making it
+	   rather difficult to get interrupts for auto detection */
+	sti();
+
+	cookie = probe_irq_on();
+
+	/*
+	 * What I try to do here is trigger an ALLOC_INT. This is done
+	 * by allocating a small chunk of memory, which will give an interrupt
+	 * when done.
+	 */
+
+
+	SMC_SELECT_BANK(2);
+	/* enable ALLOCation interrupts ONLY */
+	outb( IM_ALLOC_INT, ioaddr + IM_REG );
+
+	/*
+ 	 . Allocate 512 bytes of memory.  Note that the chip was just
+	 . reset so all the memory is available
+	*/
+	outw( MC_ALLOC | 1, ioaddr + MMU_CMD_REG );
+
+	/*
+	 . Wait until positive that the interrupt has been generated
+	*/
+	while ( timeout ) {
+		byte	int_status;
+
+		int_status = inb( ioaddr + INT_REG );
+
+		if ( int_status & IM_ALLOC_INT )
+			break;		/* got the interrupt */
+		timeout--;
+	}
+
+	/* there is really nothing that I can do here if timeout fails,
+	   as autoirq_report will return a 0 anyway, which is what I
+	   want in this case.   Plus, the clean up is needed in both
+	   cases.  */
+
+	/* DELAY HERE!
+	   On a fast machine, the status might change before the interrupt
+	   is given to the processor.  This means that the interrupt was
+	   never detected, and autoirq_report fails to report anything.
+	   This should fix autoirq_* problems.
+	*/
+	mdelay(10);
+
+	/* and disable all interrupts again */
+	outb( 0, ioaddr + IM_REG );
+
+	/* clear hardware interrupts again, because that's how it
+	   was when I was called... */
+	cli();
+	
+	/* and return what I found */
+	return probe_irq_off(cookie);
+}
+#endif
+
+/*----------------------------------------------------------------------
+ . Function: smc_probe( int ioaddr )
+ .
+ . Purpose:
+ .	Tests to see if a given ioaddr points to an SMC91111 chip.
+ .	Returns a 0 on success
+ .
+ . Algorithm:
+ .	(1) see if the high byte of BANK_SELECT is 0x33
+ . 	(2) compare the ioaddr with the base register's address
+ .	(3) see if I recognize the chip ID in the appropriate register
+ .
+ .---------------------------------------------------------------------
+ */
+/*---------------------------------------------------------------
+ . Here I do typical initialization tasks.
+ .
+ . o  Initialize the structure if needed
+ . o  print out my vanity message if not done so already
+ . o  print out what type of hardware is detected
+ . o  print out the ethernet address
+ . o  find the IRQ
+ . o  set up my private data
+ . o  configure the dev structure with my subroutines
+ . o  actually GRAB the irq.
+ . o  GRAB the region
+ .-----------------------------------------------------------------*/
+
+static int __init smc_probe(struct net_device *dev, int ioaddr )
+{
+	int i, memory, retval;
+	static unsigned version_printed = 0;
+	unsigned int	bank;
+
+        const char *version_string;
+
+	/*registers */
+	word	revision_register;
+	word	base_address_register;
+	word  	memory_info_register;
+	/*=> Pramod */
+	struct smc_local *lp;
+	/*<= Pramod */
+
+	PRINTK2("CARDNAME:smc_probe\n");
+
+	/* Grab the region so that no one else tries to probe our ioports. */
+	if (!request_region(ioaddr, SMC_IO_EXTENT, dev->name)) return -EBUSY;
+
+	/* First, see if the high byte is 0x33 */
+	bank = inw( ioaddr + BANK_SELECT );
+	if ( (bank & 0xFF00) != 0x3300 ) return -ENODEV;
+
+	/* The above MIGHT indicate a device, but I need to write to further test this.  */
+	outw( 0x0, ioaddr + BANK_SELECT );
+	bank = inw( ioaddr + BANK_SELECT );
+	if ( (bank & 0xFF00 ) != 0x3300 )
+	{
+		retval = -ENODEV;
+		goto err_out;
+	}
+
+	/* well, we've already written once, so hopefully another time won't
+ 	   hurt.  This time, I need to switch the bank register to bank 1,
+	   so I can access the base address register */
+	SMC_SELECT_BANK(1);
+	base_address_register = inw( ioaddr + BASE_REG );
+	if ( ioaddr != ( base_address_register >> 3 & 0x3E0 ) )
+	{
+		printk("CARDNAME: IOADDR %x doesn't match configuration (%x)."
+			"Probably not a SMC chip\n",
+			ioaddr, base_address_register >> 3 & 0x3E0 );
+		/* well, the base address register didn't match.  Must not have
+		   been a SMC chip after all. */
+		retval = -ENODEV;
+		goto err_out;
+	}
+
+	/*  check if the revision register is something that I recognize.
+	    These might need to be added to later, as future revisions
+	    could be added.  */
+	SMC_SELECT_BANK(3);
+	revision_register  = inw( ioaddr + REV_REG );
+	if ( !chip_ids[ ( revision_register  >> 4 ) & 0xF  ] )
+	{
+		/* I don't recognize this chip, so... */
+		printk("CARDNAME: IO %x: Unrecognized revision register:"
+			" %x, Contact author. \n",
+			ioaddr, revision_register );
+		retval =  -ENODEV;
+		goto err_out;
+	}
+
+	/* at this point I'll assume that the chip is an SMC9xxx.
+	   It might be prudent to check a listing of MAC addresses
+	   against the hardware address, or do some other tests. */
+
+	if (version_printed++ == 0)
+		printk("%s", version);
+
+	/* fill in some of the fields */
+	dev->base_addr = ioaddr;
+
+	/*
+ 	 . 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
+#ifndef NO_AUTOPROBE	// by takeo
+	if ( dev->irq < 2 ) {
+		int	trials;
+
+		trials = 3;
+		while ( trials-- ) {
+			dev->irq = smc_findirq( ioaddr );
+			if ( dev->irq )
+				break;
+			/* kick the card and try again */
+			smc_reset( dev );
+		}
+	}
+
+	if (dev->irq == 0 ) {
+		printk("%s: Couldn't autodetect your IRQ. Use irq=xx.\n",
+			dev->name);
+		retval =  -ENODEV;
+		goto err_out;
+	}
+
+	if (dev->irq == 2) {
+		/* Fixup for users that don't know that IRQ 2 is really IRQ 9,
+		 * or don't know which one to set.
+		 */
+		dev->irq = 9;
+	}
+#endif
+
+	/* now, print out the card info, in a short format.. */
+
+	printk("%s: %s(rev:%d) at %#3x IRQ:%d MEMSIZE:%db NOWAIT:%d ",
+		dev->name,
+		version_string, revision_register & 0xF, ioaddr, dev->irq,
+		memory, dev->dma);
+	/*
+	 . Print the Ethernet address
+	*/
+	printk("ADDR: ");
+	for (i = 0; i < 5; i++)
+		printk("%2.2x:", dev->dev_addr[i] );
+	printk("%2.2x \n", dev->dev_addr[5] );
+
+
+	/* Initialize the private structure. */
+	if (dev->priv == NULL) {
+		dev->priv = kmalloc(sizeof(struct smc_local), GFP_KERNEL);
+		if (dev->priv == NULL) {
+			retval = -ENOMEM;
+			goto err_out;
+		}
+	}
+	/* set the private data to zero by default */
+	memset(dev->priv, 0, sizeof(struct smc_local));
+
+	/* Fill in the fields of the device structure with ethernet values. */
+	ether_setup(dev);
+
+	/* Grab the IRQ */
+    retval = request_irq(dev->irq, &smc_interrupt, 0, dev->name, dev);
+    if (retval) {
+       	  printk("%s: unable to get IRQ %d (irqval=%d).\n",
+		dev->name, dev->irq, retval);
+		  kfree (dev->priv);
+		  dev->priv = NULL;
+		  goto err_out;
+      	}
+
+	dev->open		        = smc_open;
+	dev->stop		        = smc_close;
+	dev->hard_start_xmit   	= smc_wait_to_send_packet;
+	dev->tx_timeout			= smc_timeout;
+	dev->get_stats			= smc_query_statistics;
+#ifdef	HAVE_MULTICAST
+	dev->set_multicast_list 	= &smc_set_multicast_list;
+#endif
+
+	/* => Store the ChipRevision and ChipID, to be used in resolving the Odd-Byte issue in RevB of LAN91C111; Pramod */
+	SMC_SELECT_BANK(3);
+	revision_register  = inw( ioaddr + REV_REG );
+	lp = (struct smc_local *)dev->priv;
+	lp->ChipID = (revision_register >> 4) & 0xF;
+	lp->ChipRev = revision_register & 0xF;
+
+        spin_lock_init(&lp->lock);
+
+	return 0;
+
+err_out:
+	release_region (ioaddr, SMC_IO_EXTENT);
+	return retval;
+}
+
+#if SMC_DEBUG > 2
+static void print_packet( byte * buf, int length )
+{
+#if 1
+	int i;
+	int remainder;
+	int lines;
+
+	printk("Packet of length %d \n", length );
+
+#if SMC_DEBUG > 3
+	lines = length / 16;
+	remainder = length % 16;
+
+	for ( i = 0; i < lines ; i ++ ) {
+		int cur;
+
+		for ( cur = 0; cur < 8; cur ++ ) {
+			byte a, b;
+
+			a = *(buf ++ );
+			b = *(buf ++ );
+			printk("%02x%02x ", a, b );
+		}
+		printk("\n");
+	}
+	for ( i = 0; i < remainder/2 ; i++ ) {
+		byte a, b;
+
+		a = *(buf ++ );
+		b = *(buf ++ );
+		printk("%02x%02x ", a, b );
+	}
+	printk("\n");
+#endif
+#endif
+}
+#endif
+
+
+/*
+ * Open and Initialize the board
+ *
+ * Set up everything, reset the card, etc ..
+ *
+ */
+static int smc_open(struct net_device *dev)
+{
+	struct smc_local *lp 	= (struct smc_local *)dev->priv;
+	int	ioaddr = dev->base_addr;
+	int	i;	/* used to set hw ethernet address */
+
+	PRINTK2("%s:smc_open\n", dev->name);
+
+#if 0
+	/* clear out all the junk that was put here before... */
+	memset(dev->priv, 0, sizeof(struct smc_local));
+#endif
+
+	netif_start_queue(dev);
+#ifdef MODULE
+	MOD_INC_USE_COUNT;
+#endif
+
+	// Setup the default Register Modes
+	lp->tcr_cur_mode = TCR_DEFAULT;
+	lp->rcr_cur_mode = RCR_DEFAULT;
+	lp->rpc_cur_mode = RPC_DEFAULT;
+
+	// Set default parameters (files)
+	lp->ctl_swfdup = 0;
+	lp->ctl_ephloop = 0;
+	lp->ctl_miiop = 0;
+	lp->ctl_autoneg = 1;
+	lp->ctl_rfduplx = 1;
+	lp->ctl_rspeed = 100;
+	lp->ctl_afduplx = 1;
+	lp->ctl_aspeed = 100;
+	lp->ctl_lnkfail = 1;
+	lp->ctl_forcol = 0;
+	lp->ctl_filtcar = 0;
+
+	/* reset the hardware */
+
+	smc_reset( dev );
+	smc_enable( dev );
+
+	/* Configure the PHY */
+	smc_phy_configure(dev);
+
+	/*
+  		According to Becker, I have to set the hardware address
+		at this point, because the (l)user can set it with an
+		ioctl.  Easily done...
+	*/
+	SMC_SELECT_BANK( 1 );
+	for ( i = 0; i < 6; i += 2 ) {
+		word	address;
+
+		address = dev->dev_addr[ i + 1 ] << 8 ;
+		address  |= dev->dev_addr[ i ];
+		outw( address, ioaddr + ADDR0_REG + i );
+	}
+
+#ifdef CONFIG_SYSCTL
+	smc_sysctl_register(dev);
+#endif /* CONFIG_SYSCTL */ 
+
+	netif_start_queue(dev);
+	return 0;
+}
+
+/*--------------------------------------------------------
+ . Called by the kernel to send a packet out into the void
+ . of the net.  This routine is largely based on
+ . skeleton.c, from Becker.
+ .--------------------------------------------------------
+*/
+static void smc_timeout (struct net_device *dev)
+{
+
+        struct smc_local *lp = (struct smc_local *)dev->priv;
+        unsigned long flags;
+
+        /*
+         *      Best would be to use synchronize_irq(); spin_lock() here
+         *      lets make it work first..
+         */
+         
+        spin_lock_irqsave(&lp->lock, flags);
+
+	PRINTK3("%s:smc_send_packet\n", dev->name);
+
+	/* If we get here, some higher level has decided we are broken.
+	There should really be a "kick me" function call instead. */
+	printk(KERN_WARNING "%s: transmit timed out, %s?\n",dev->name, tx_done(dev) ? "IRQ conflict" :"network cable problem");
+	/* "kick" the adaptor */
+	smc_reset( dev );
+	smc_enable( dev );
+
+	/* Reconfigure the PHY */
+	smc_phy_configure(dev);
+
+	dev->trans_start = jiffies;
+	/* clear anything saved */
+	((struct smc_local *)dev->priv)->saved_skb = NULL;
+
+	spin_unlock_irqrestore(&lp->lock, flags);
+
+	netif_wake_queue(dev);
+}
+
+/*--------------------------------------------------------------------
+ .
+ . This is the main routine of the driver, to handle the net_device when
+ . it needs some attention.
+ .
+ . So:
+ .   first, save state of the chipset
+ .   branch off into routines to handle each case, and acknowledge
+ .	    each to the interrupt register
+ .   and finally restore state.
+ .
+ ---------------------------------------------------------------------*/
+static 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 void smc_rcv(struct net_device *dev)
+{
+	struct smc_local *lp = (struct smc_local *)dev->priv;
+	int 	ioaddr = dev->base_addr;
+	int 	packet_number;
+	word	status;
+	word	packet_length;
+
+	PRINTK3("%s:smc_rcv\n", dev->name);
+
+	/* assume bank 2 */
+
+	packet_number = inw( ioaddr + RXFIFO_REG );
+
+	if ( packet_number & RXFIFO_REMPTY ) {
+
+		/* we got called , but nothing was on the FIFO */
+		PRINTK("%s: WARNING: smc_rcv with nothing on FIFO. \n",
+			dev->name);
+		/* don't need to restore anything */
+		return;
+	}
+
+	/*  start reading from the start of the packet */
+	outw( PTR_READ | PTR_RCV | PTR_AUTOINC, ioaddr + PTR_REG );
+
+	/* First two words are status and packet_length */
+	status 		= inw( ioaddr + DATA_REG );
+	packet_length 	= inw( ioaddr + DATA_REG );
+
+	packet_length &= 0x07ff;  /* mask off top bits */
+
+	PRINTK2("RCV: STATUS %4x LENGTH %4x\n", status, packet_length );
+
+	if ( !(status & RS_ERRORS ) ){
+		/* do stuff to make a new packet */
+		struct sk_buff  * skb;
+		byte		* data;
+
+		/* set multicast stats */
+		if ( status & RS_MULTICAST )
+			lp->stats.multicast++;
+
+		// Allocate enough memory for entire receive frame, to be safe
+		skb = dev_alloc_skb( packet_length );
+
+		/* Adjust for having already read the first two words */
+		packet_length -= 4;
+
+		if ( skb == NULL ) {
+			printk(KERN_NOTICE "%s: Low memory, packet dropped.\n",
+				dev->name);
+			lp->stats.rx_dropped++;
+			goto done;
+		}
+
+		/*
+		 ! This should work without alignment, but it could be
+		 ! in the worse case
+		*/
+		/* TODO: Should I use 32bit alignment here ? */
+		skb_reserve( skb, 2 );   /* 16 bit alignment */
+
+		skb->dev = dev;
+
+		/* =>
+    ODD-BYTE ISSUE : The odd byte problem has been fixed in the LAN91C111 Rev B.
+		So we check if the Chip Revision, stored in smsc_local->ChipRev, is = 1.
+		If so then we increment the packet length only if RS_ODDFRAME is set.
+		If the Chip's revision is equal to 0, then we blindly increment the packet length
+		by 1, thus always assuming that the packet is odd length, leaving the higher layer
+		to decide the actual length.
+			-- Pramod
+		<= */
+		if ((9 == lp->ChipID) && (1 == lp->ChipRev))
+		{
+			if (status & RS_ODDFRAME)
+				data = skb_put( skb, packet_length + 1 );	
+			else
+				data = skb_put( skb, packet_length);			
+			
+		}
+		else
+		{
+			// set odd length for bug in LAN91C111, REV A
+			// which never sets RS_ODDFRAME
+			data = skb_put( skb, packet_length + 1 );
+		}
+
+#ifdef USE_32_BIT
+		PRINTK3(" Reading %d dwords (and %d bytes) \n",
+			packet_length >> 2, packet_length & 3 );
+		/* QUESTION:  Like in the TX routine, do I want
+		   to send the DWORDs or the bytes first, or some
+		   mixture.  A mixture might improve already slow PIO
+		   performance  */
+		insl(ioaddr + DATA_REG , data, packet_length >> 2 );
+		/* read the left over bytes */
+		insb( ioaddr + DATA_REG, data + (packet_length & 0xFFFFFC),
+			packet_length & 0x3  );
+#else
+		PRINTK3(" Reading %d words and %d byte(s) \n",
+			(packet_length >> 1 ), packet_length & 1 );
+		insw(ioaddr + DATA_REG , data, packet_length >> 1);
+
+#endif // USE_32_BIT
+
+#if	SMC_DEBUG > 2
+		printk("Receiving Packet\n");
+		print_packet( data, packet_length );
+#endif
+
+		skb->protocol = eth_type_trans(skb, dev );
+		netif_rx(skb);
+		lp->stats.rx_packets++;
+#if defined(__m32r__)
+		lp->stats.rx_bytes += packet_length;
+#endif
+	} else {
+		/* error ... */
+		lp->stats.rx_errors++;
+
+		if ( status & RS_ALGNERR )  lp->stats.rx_frame_errors++;
+		if ( status & (RS_TOOSHORT | RS_TOOLONG ) )
+			lp->stats.rx_length_errors++;
+		if ( status & RS_BADCRC)	lp->stats.rx_crc_errors++;
+	}
+
+	while ( inw( ioaddr + MMU_CMD_REG ) & MC_BUSY )
+		udelay(1); // Wait until not busy
+done:
+	/*  error or good, tell the card to get rid of this packet */
+	outw( MC_RELEASE, ioaddr + MMU_CMD_REG );
+
+	return;
+}
+
+
+/*************************************************************************
+ . smc_tx
+ .
+ . Purpose:  Handle a transmit error message.   This will only be called
+ .   when an error, because of the AUTO_RELEASE mode.
+ .
+ . Algorithm:
+ .	Save pointer and packet no
+ .	Get the packet no from the top of the queue
+ .	check if it's valid ( if not, is this an error??? )
+ .	read the status word
+ .	record the error
+ .	( resend?  Not really, since we don't want old packets around )
+ .	Restore saved values
+ ************************************************************************/
+static void smc_tx( struct net_device * dev )
+{
+	int	ioaddr = dev->base_addr;
+	struct smc_local *lp = (struct smc_local *)dev->priv;
+	byte saved_packet;
+	byte packet_no;
+	word tx_status;
+
+
+	PRINTK3("%s:smc_tx\n", dev->name);
+
+	/* assume bank 2  */
+
+	saved_packet = inb( ioaddr + PN_REG );
+	packet_no = inw( ioaddr + RXFIFO_REG );
+#if defined(__m32r__)
+	/* If the TX FIFO is empty then nothing to do */
+	if ( packet_no & TXFIFO_TEMPTY )
+		return;
+
+	packet_no &= 0x7F;
+#else
+	packet_no &= 0x7F;
+
+	/* If the TX FIFO is empty then nothing to do */
+	if ( packet_no & TXFIFO_TEMPTY )
+		return;
+#endif
+
+	/* select this as the packet to read from */
+	outb( packet_no, ioaddr + PN_REG );
+
+	/* read the first word (status word) from this packet */
+	outw( PTR_AUTOINC | PTR_READ, ioaddr + PTR_REG );
+
+	tx_status = inw( ioaddr + DATA_REG );
+	PRINTK3("%s: TX DONE STATUS: %4x \n", dev->name, tx_status);
+
+	lp->stats.tx_errors++;
+	if ( tx_status & TS_LOSTCAR ) lp->stats.tx_carrier_errors++;
+	if ( tx_status & TS_LATCOL  ) {
+		printk(KERN_DEBUG
+			"%s: Late collision occurred on last xmit.\n",
+			dev->name);
+		lp->stats.tx_window_errors++;
+		lp->ctl_forcol = 0; // Reset forced collsion
+	}
+#if 0
+	if ( tx_status & TS_16COL ) { ... }
+#endif
+
+	if ( tx_status & TS_SUCCESS ) {
+	  //	  	printk("%s: Successful packet caused interrupt \n", dev->name);
+	}
+	/* re-enable transmit */
+	SMC_SELECT_BANK( 0 );
+	outw( inw( ioaddr + TCR_REG ) | TCR_ENABLE, ioaddr + TCR_REG );
+
+	/* kill the packet */
+	SMC_SELECT_BANK( 2 );
+	outw( MC_FREEPKT, ioaddr + MMU_CMD_REG );
+
+	/* one less packet waiting for me */
+	lp->packets_waiting--;
+
+	/* Don't change Packet Number Reg until busy bit is cleared */
+	/* Per LAN91C111 Spec, Page 50 */
+	while ( inw( ioaddr + MMU_CMD_REG ) & MC_BUSY );
+
+	outb( saved_packet, ioaddr + PN_REG );
+	return;
+}
+
+
+/*----------------------------------------------------
+ . smc_close
+ .
+ . this makes the board clean up everything that it can
+ . and not talk to the outside world.   Caused by
+ . an 'ifconfig ethX down'
+ .
+ -----------------------------------------------------*/
+static int smc_close(struct net_device *dev)
+{
+	netif_stop_queue(dev);
+	//dev->start = 0;
+
+	PRINTK2("%s:smc_close\n", dev->name);
+
+#ifdef CONFIG_SYSCTL
+	smc_sysctl_unregister(dev);
+#endif /* CONFIG_SYSCTL */ 
+
+	/* clear everything */
+	smc_shutdown( dev->base_addr );
+
+	/* Update the statistics here. */
+#ifdef MODULE
+	MOD_DEC_USE_COUNT;
+#endif
+
+	return 0;
+}
+
+/*------------------------------------------------------------
+ . Get the current statistics.
+ . This may be called with the card open or closed.
+ .-------------------------------------------------------------*/
+static struct net_device_stats* smc_query_statistics(struct net_device *dev) {
+	struct smc_local *lp = (struct smc_local *)dev->priv;
+
+	PRINTK2("%s:smc_query_statistics\n", dev->name);
+
+	return &lp->stats;
+}
+
+/*-----------------------------------------------------------
+ . smc_set_multicast_list
+ .
+ . This routine will, depending on the values passed to it,
+ . either make it accept multicast packets, go into
+ . promiscuous mode ( for TCPDUMP and cousins ) or accept
+ . a select set of multicast packets
+*/
+static void smc_set_multicast_list(struct net_device *dev)
+{
+	short ioaddr = dev->base_addr;
+
+	PRINTK2("%s:smc_set_multicast_list\n", dev->name);
+
+	SMC_SELECT_BANK(0);
+	if ( dev->flags & IFF_PROMISC )
+		{
+		PRINTK2("%s:smc_set_multicast_list:RCR_PRMS\n", dev->name);
+		outw( inw(ioaddr + RCR_REG ) | RCR_PRMS, ioaddr + RCR_REG );
+		}
+
+/* BUG?  I never disable promiscuous mode if multicasting was turned on.
+   Now, I turn off promiscuous mode, but I don't do anything to multicasting
+   when promiscuous mode is turned on.
+*/
+
+	/* Here, I am setting this to accept all multicast packets.
+	   I don't need to zero the multicast table, because the flag is
+	   checked before the table is
+	*/
+	else if (dev->flags & IFF_ALLMULTI)
+		{
+		outw( inw(ioaddr + RCR_REG ) | RCR_ALMUL, ioaddr + RCR_REG );
+		PRINTK2("%s:smc_set_multicast_list:RCR_ALMUL\n", dev->name);
+		}
+
+	/* We just get all multicast packets even if we only want them
+	 . from one source.  This will be changed at some future
+	 . point. */
+	else if (dev->mc_count )  {
+		/* support hardware multicasting */
+
+		/* be sure I get rid of flags I might have set */
+		outw( inw( ioaddr + RCR_REG ) & ~(RCR_PRMS | RCR_ALMUL),
+			ioaddr + RCR_REG );
+		/* NOTE: this has to set the bank, so make sure it is the
+		   last thing called.  The bank is set to zero at the top */
+		smc_setmulticast( ioaddr, dev->mc_count, dev->mc_list );
+	} else  {
+		PRINTK2("%s:smc_set_multicast_list:~(RCR_PRMS|RCR_ALMUL)\n",
+			dev->name);
+		outw( inw( ioaddr + RCR_REG ) & ~(RCR_PRMS | RCR_ALMUL),
+			ioaddr + RCR_REG );
+
+		/*
+		  since I'm disabling all multicast entirely, I need to
+		  clear the multicast list
+		*/
+		SMC_SELECT_BANK( 3 );
+		outw( 0, ioaddr + MCAST_REG1 );
+		outw( 0, ioaddr + MCAST_REG2 );
+		outw( 0, ioaddr + MCAST_REG3 );
+		outw( 0, ioaddr + MCAST_REG4 );
+	}
+}
+
+#ifdef MODULE
+
+static struct net_device devSMC91111;
+int io = 0;
+int irq = 0;
+int nowait = 0;
+
+MODULE_PARM(io, "i");
+MODULE_PARM(irq, "i");
+MODULE_PARM(nowait, "i");
+
+/*------------------------------------------------------------
+ . Module initialization function
+ .-------------------------------------------------------------*/
+int init_module(void)
+{
+	int result;
+
+	PRINTK2("CARDNAME:init_module\n");
+	if (io == 0)
+		printk(KERN_WARNING
+		CARDNAME": You shouldn't use auto-probing with insmod!\n" );
+
+	/* copy the parameters from insmod into the device structure */
+	devSMC91111.base_addr	= io;
+	devSMC91111.irq		= irq;
+	devSMC91111.dma		= nowait; // Use DMA field for nowait		
+	devSMC91111.init	= smc_init;/* Kernel 2.4 Changes - Pramod */
+	if ((result = register_netdev(&devSMC91111)) != 0)
+		return result;
+	
+	return 0;
+}
+
+/*------------------------------------------------------------
+ . Cleanup when module is removed with rmmod
+ .-------------------------------------------------------------*/
+void cleanup_module(void)
+{
+	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
+	unregister_netdev(&devSMC91111);
+
+	free_irq(devSMC91111.irq, &devSMC91111);
+	release_region(devSMC91111.base_addr, SMC_IO_EXTENT);
+
+	if (devSMC91111.priv)
+		kfree(devSMC91111.priv); /* Kernel 2.4 Changes - Pramod */
+}
+
+#endif /* MODULE */
+
+
+#ifdef CONFIG_SYSCTL
+
+
+/*------------------------------------------------------------
+ . Modify a bit in the LAN91C111 register set
+ .-------------------------------------------------------------*/
+static word smc_modify_regbit(int bank, int ioaddr, int reg,
+	unsigned int bit, int val)
+{
+	word regval;
+
+	SMC_SELECT_BANK( bank );
+
+	regval = inw( ioaddr+reg );
+	if (val)
+		regval |= bit;
+	else
+		regval &= ~bit;
+
+	outw( regval, ioaddr );
+	return(regval);
+}
+
+
+/*------------------------------------------------------------
+ . Retrieve a bit in the LAN91C111 register set
+ .-------------------------------------------------------------*/
+static int smc_get_regbit(int bank, int ioaddr, int reg, unsigned int bit)
+{
+	SMC_SELECT_BANK( bank );
+	if ( inw( ioaddr+reg ) & bit)
+		return(1);
+	else
+		return(0);
+}
+
+
+/*------------------------------------------------------------
+ . Modify a LAN91C111 register (word access only)
+ .-------------------------------------------------------------*/
+static void smc_modify_reg(int bank, int ioaddr, int reg, word val)
+{
+	SMC_SELECT_BANK( bank );
+	outw( val, ioaddr+reg );
+}
+
+
+/*------------------------------------------------------------
+ . Retrieve a LAN91C111 register (word access only)
+ .-------------------------------------------------------------*/
+static int smc_get_reg(int bank, int ioaddr, int reg)
+{
+	SMC_SELECT_BANK( bank );
+	return(inw( ioaddr+reg ));
+}
+
+
+static const char smc_info_string[] =
+"\n"
+"info           Provides this information blurb\n"
+"swver          Prints the software version information of this driver\n"
+"autoneg        Auto-negotiate Mode = 1\n"
+"rspeed         Requested Speed, 100=100Mbps, 10=10Mpbs\n"
+"rfduplx        Requested Full Duplex Operation\n"
+"aspeed         Actual Speed, 100=100Mbps, 10=10Mpbs\n"
+"afduplx        Actual Full Duplex Operation\n"
+"lnkfail        PHY Link Failure when 1\n"
+"miiop          External MII when 1, Internal PHY when 0\n"
+"swfdup         Switched Full Duplex Mode (allowed only in MII operation)\n"
+"ephloop        EPH Block Loopback\n"
+"forcol         Force a collision\n"
+"filtcar        Filter leading edge of carrier sense for 12 bit times\n"
+"freemem        Free buffer memory in bytes\n"
+"totmem         Total buffer memory in bytes\n"
+"leda           Output of LED-A (green)\n"
+"ledb           Output of LED-B (yellow)\n"
+"chiprev        Revision ID of the LAN91C111 chip\n"
+"";
+
+/*------------------------------------------------------------
+ . Sysctl handler for all integer parameters
+ .-------------------------------------------------------------*/
+static int smc_sysctl_handler(ctl_table *ctl, int write, struct file * filp,
+				void *buffer, size_t *lenp)
+{
+	struct net_device *dev = (struct net_device*)ctl->extra1;
+	struct smc_local *lp = (struct smc_local *)ctl->extra2;
+	int ioaddr = dev->base_addr;
+	int *valp = ctl->data;
+	int val;
+	int ret;
+
+	// Update parameters from the real registers
+	switch (ctl->ctl_name)
+	{
+	case CTL_SMC_FORCOL:
+		*valp = smc_get_regbit(0, ioaddr, TCR_REG, TCR_FORCOL);
+		break;
+
+	case CTL_SMC_FREEMEM:
+		*valp = ( (word)smc_get_reg(0, ioaddr, MIR_REG) >> 8 )
+			* LAN91C111_MEMORY_MULTIPLIER;
+		break;
+
+
+	case CTL_SMC_TOTMEM:
+		*valp = ( smc_get_reg(0, ioaddr, MIR_REG) & (word)0x00ff )
+			* LAN91C111_MEMORY_MULTIPLIER;
+		break;
+
+	case CTL_SMC_CHIPREV:
+		*valp = smc_get_reg(3, ioaddr, REV_REG);
+		break;
+
+	case CTL_SMC_AFDUPLX:
+		*valp = (lp->lastPhy18 & PHY_INT_DPLXDET) ? 1 : 0;
+		break;
+
+	case CTL_SMC_ASPEED:
+		*valp = (lp->lastPhy18 & PHY_INT_SPDDET) ? 100 : 10;
+		break;
+
+	case CTL_SMC_LNKFAIL:
+		*valp = (lp->lastPhy18 & PHY_INT_LNKFAIL) ? 1 : 0;
+		break;
+
+	case CTL_SMC_LEDA:
+		*valp = (lp->rpc_cur_mode >> RPC_LSXA_SHFT) & (word)0x0007;
+		break;
+
+	case CTL_SMC_LEDB:
+		*valp = (lp->rpc_cur_mode >> RPC_LSXB_SHFT) & (word)0x0007;
+		break;
+
+	case CTL_SMC_MIIOP:
+		*valp = smc_get_regbit(1, ioaddr, CONFIG_REG, CONFIG_EXT_PHY);
+		break;
+
+#ifdef SMC_DEBUG
+	case CTL_SMC_REG_BSR:	// Bank Select
+		*valp = smc_get_reg(0, ioaddr, BSR_REG);
+		break;
+
+	case CTL_SMC_REG_TCR:	// Transmit Control
+		*valp = smc_get_reg(0, ioaddr, TCR_REG);
+		break;
+
+	case CTL_SMC_REG_ESR:	// EPH Status
+		*valp = smc_get_reg(0, ioaddr, EPH_STATUS_REG);
+		break;
+
+	case CTL_SMC_REG_RCR:	// Receive Control
+		*valp = smc_get_reg(0, ioaddr, RCR_REG);
+		break;
+
+	case CTL_SMC_REG_CTRR:	// Counter
+		*valp = smc_get_reg(0, ioaddr, COUNTER_REG);
+		break;
+
+	case CTL_SMC_REG_MIR:	// Memory Information
+		*valp = smc_get_reg(0, ioaddr, MIR_REG);
+		break;
+
+	case CTL_SMC_REG_RPCR:	// Receive/Phy Control
+		*valp = smc_get_reg(0, ioaddr, RPC_REG);
+		break;
+
+	case CTL_SMC_REG_CFGR:	// Configuration
+		*valp = smc_get_reg(1, ioaddr, CONFIG_REG);
+		break;
+
+	case CTL_SMC_REG_BAR:	// Base Address
+		*valp = smc_get_reg(1, ioaddr, BASE_REG);
+		break;
+
+	case CTL_SMC_REG_IAR0:	// Individual Address
+		*valp = smc_get_reg(1, ioaddr, ADDR0_REG);
+		break;
+
+	case CTL_SMC_REG_IAR1:	// Individual Address
+		*valp = smc_get_reg(1, ioaddr, ADDR1_REG);
+		break;
+
+	case CTL_SMC_REG_IAR2:	// Individual Address
+		*valp = smc_get_reg(1, ioaddr, ADDR2_REG);
+		break;
+
+	case CTL_SMC_REG_GPR:	// General Purpose
+		*valp = smc_get_reg(1, ioaddr, GP_REG);
+		break;
+
+	case CTL_SMC_REG_CTLR:	// Control
+		*valp = smc_get_reg(1, ioaddr, CTL_REG);
+		break;
+
+	case CTL_SMC_REG_MCR:	// MMU Command
+		*valp = smc_get_reg(2, ioaddr, MMU_CMD_REG);
+		break;
+
+	case CTL_SMC_REG_PNR:	// Packet Number
+		*valp = smc_get_reg(2, ioaddr, PN_REG);
+		break;
+
+	case CTL_SMC_REG_FPR:	// Allocation Result/FIFO Ports
+		*valp = smc_get_reg(2, ioaddr, RXFIFO_REG);
+		break;
+
+	case CTL_SMC_REG_PTR:	// Pointer
+		*valp = smc_get_reg(2, ioaddr, PTR_REG);
+		break;
+
+	case CTL_SMC_REG_DR:	// Data 
+		*valp = smc_get_reg(2, ioaddr, DATA_REG);
+		break;
+
+	case CTL_SMC_REG_ISR:	// Interrupt Status/Mask
+		*valp = smc_get_reg(2, ioaddr, INT_REG);
+		break;
+
+	case CTL_SMC_REG_MTR1:	// Multicast Table Entry 1
+		*valp = smc_get_reg(3, ioaddr, MCAST_REG1);
+		break;
+
+	case CTL_SMC_REG_MTR2:	// Multicast Table Entry 2
+		*valp = smc_get_reg(3, ioaddr, MCAST_REG2);
+		break;
+
+	case CTL_SMC_REG_MTR3:	// Multicast Table Entry 3
+		*valp = smc_get_reg(3, ioaddr, MCAST_REG3);
+		break;
+
+	case CTL_SMC_REG_MTR4:	// Multicast Table Entry 4
+		*valp = smc_get_reg(3, ioaddr, MCAST_REG4);
+		break;
+
+	case CTL_SMC_REG_MIIR:	// Management Interface
+		*valp = smc_get_reg(3, ioaddr, MII_REG);
+		break;
+
+	case CTL_SMC_REG_REVR:	// Revision
+		*valp = smc_get_reg(3, ioaddr, REV_REG);
+		break;
+
+	case CTL_SMC_REG_ERCVR:	// Early RCV
+		*valp = smc_get_reg(3, ioaddr, ERCV_REG);
+		break;
+
+	case CTL_SMC_REG_EXTR:	// External
+		*valp = smc_get_reg(7, ioaddr, EXT_REG);
+		break;
+
+	case CTL_SMC_PHY_CTRL:
+		*valp = smc_read_phy_register(ioaddr, lp->phyaddr,
+			PHY_CNTL_REG);
+		break;
+
+	case CTL_SMC_PHY_STAT:
+		*valp = smc_read_phy_register(ioaddr, lp->phyaddr,
+			PHY_STAT_REG);
+		break;
+
+	case CTL_SMC_PHY_ID1:
+		*valp = smc_read_phy_register(ioaddr, lp->phyaddr,
+			PHY_ID1_REG);
+		break;
+
+	case CTL_SMC_PHY_ID2:
+		*valp = smc_read_phy_register(ioaddr, lp->phyaddr,
+			PHY_ID2_REG);
+		break;
+
+	case CTL_SMC_PHY_ADC:
+		*valp = smc_read_phy_register(ioaddr, lp->phyaddr,
+			PHY_AD_REG);
+		break;
+
+	case CTL_SMC_PHY_REMC:
+		*valp = smc_read_phy_register(ioaddr, lp->phyaddr,
+			PHY_RMT_REG);
+		break;
+
+	case CTL_SMC_PHY_CFG1:
+		*valp = smc_read_phy_register(ioaddr, lp->phyaddr,
+			PHY_CFG1_REG);
+		break;
+
+	case CTL_SMC_PHY_CFG2:
+		*valp = smc_read_phy_register(ioaddr, lp->phyaddr,
+			PHY_CFG2_REG);
+		break;
+
+	case CTL_SMC_PHY_INT:
+		*valp = smc_read_phy_register(ioaddr, lp->phyaddr,
+			PHY_INT_REG);
+		break;
+
+	case CTL_SMC_PHY_MASK:
+		*valp = smc_read_phy_register(ioaddr, lp->phyaddr,
+			PHY_MASK_REG);
+		break;
+
+#endif // SMC_DEBUG
+
+	default:
+		// Just ignore unsupported parameters
+		break;
+	}
+
+	// Save old state
+	val = *valp;
+
+	// Perform the generic integer operation	
+	if ((ret = proc_dointvec(ctl, write, filp, buffer, lenp)) != 0)
+		return(ret);
+
+	// Write changes out to the registers
+	if (write && *valp != val) {
+
+		val = *valp;
+		switch (ctl->ctl_name) {
+
+		case CTL_SMC_SWFDUP:
+			if (val)
+				lp->tcr_cur_mode |= TCR_SWFDUP;
+			else
+				lp->tcr_cur_mode &= ~TCR_SWFDUP;
+
+			smc_modify_regbit(0, ioaddr, TCR_REG, TCR_SWFDUP, val);
+			break;
+
+		case CTL_SMC_EPHLOOP:
+			if (val)
+				lp->tcr_cur_mode |= TCR_EPH_LOOP;
+			else
+				lp->tcr_cur_mode &= ~TCR_EPH_LOOP;
+
+			smc_modify_regbit(0, ioaddr, TCR_REG, TCR_EPH_LOOP, val);
+			break;
+
+		case CTL_SMC_FORCOL:
+			if (val)
+				lp->tcr_cur_mode |= TCR_FORCOL;
+			else
+				lp->tcr_cur_mode &= ~TCR_FORCOL;
+
+			// Update the EPH block
+			smc_modify_regbit(0, ioaddr, TCR_REG, TCR_FORCOL, val);
+			break;
+
+		case CTL_SMC_FILTCAR:
+			if (val)
+				lp->rcr_cur_mode |= RCR_FILT_CAR;
+			else
+				lp->rcr_cur_mode &= ~RCR_FILT_CAR;
+
+			// Update the EPH block
+			smc_modify_regbit(0, ioaddr, RCR_REG, RCR_FILT_CAR, val);
+			break;
+
+		case CTL_SMC_RFDUPLX:
+			// Disallow changes if in auto-negotiation mode
+			if (lp->ctl_autoneg)
+				break;
+
+			if (val)
+				{
+				lp->rpc_cur_mode |= RPC_DPLX;
+				}
+			else
+				{
+				lp->rpc_cur_mode &= ~RPC_DPLX;
+				}
+
+			// Reconfigure the PHY
+			smc_phy_configure(dev);
+
+			break;
+
+		case CTL_SMC_RSPEED:
+			// Disallow changes if in auto-negotiation mode
+			if (lp->ctl_autoneg)
+				break;
+
+			if (val > 10)
+				lp->rpc_cur_mode |= RPC_SPEED;
+			else
+				lp->rpc_cur_mode &= ~RPC_SPEED;
+
+			// Reconfigure the PHY
+			smc_phy_configure(dev);
+
+			break;
+
+		case CTL_SMC_AUTONEG:
+			if (val)
+				lp->rpc_cur_mode |= RPC_ANEG;
+			else
+				lp->rpc_cur_mode &= ~RPC_ANEG;
+
+			// Reconfigure the PHY
+			smc_phy_configure(dev);
+
+			break;
+
+		case CTL_SMC_LEDA:
+			val &= 0x07; // Restrict to 3 ls bits
+			lp->rpc_cur_mode &= ~(word)(0x07<<RPC_LSXA_SHFT);
+			lp->rpc_cur_mode |= (word)(val<<RPC_LSXA_SHFT);
+
+			// Update the Internal PHY block
+			smc_modify_reg(0, ioaddr, RPC_REG, lp->rpc_cur_mode);
+			break;
+
+		case CTL_SMC_LEDB:
+			val &= 0x07; // Restrict to 3 ls bits
+			lp->rpc_cur_mode &= ~(word)(0x07<<RPC_LSXB_SHFT);
+			lp->rpc_cur_mode |= (word)(val<<RPC_LSXB_SHFT);
+
+			// Update the Internal PHY block
+			smc_modify_reg(0, ioaddr, RPC_REG, lp->rpc_cur_mode);
+			break;
+
+		case CTL_SMC_MIIOP:
+			// Update the Internal PHY block
+			smc_modify_regbit(1, ioaddr, CONFIG_REG,
+				CONFIG_EXT_PHY, val);
+			break;
+
+#ifdef SMC_DEBUG
+		case CTL_SMC_REG_BSR:	// Bank Select
+			smc_modify_reg(0, ioaddr, BSR_REG, val);
+			break;
+
+		case CTL_SMC_REG_TCR:	// Transmit Control
+			smc_modify_reg(0, ioaddr, TCR_REG, val);
+			break;
+
+		case CTL_SMC_REG_ESR:	// EPH Status
+			smc_modify_reg(0, ioaddr, EPH_STATUS_REG, val);
+			break;
+
+		case CTL_SMC_REG_RCR:	// Receive Control
+			smc_modify_reg(0, ioaddr, RCR_REG, val);
+			break;
+
+		case CTL_SMC_REG_CTRR:	// Counter
+			smc_modify_reg(0, ioaddr, COUNTER_REG, val);
+			break;
+
+		case CTL_SMC_REG_MIR:	// Memory Information
+			smc_modify_reg(0, ioaddr, MIR_REG, val);
+			break;
+
+		case CTL_SMC_REG_RPCR:	// Receive/Phy Control
+			smc_modify_reg(0, ioaddr, RPC_REG, val);
+			break;
+
+		case CTL_SMC_REG_CFGR:	// Configuration
+			smc_modify_reg(1, ioaddr, CONFIG_REG, val);
+			break;
+
+		case CTL_SMC_REG_BAR:	// Base Address
+			smc_modify_reg(1, ioaddr, BASE_REG, val);
+			break;
+
+		case CTL_SMC_REG_IAR0:	// Individual Address
+			smc_modify_reg(1, ioaddr, ADDR0_REG, val);
+			break;
+
+		case CTL_SMC_REG_IAR1:	// Individual Address
+			smc_modify_reg(1, ioaddr, ADDR1_REG, val);
+			break;
+
+		case CTL_SMC_REG_IAR2:	// Individual Address
+			smc_modify_reg(1, ioaddr, ADDR2_REG, val);
+			break;
+
+		case CTL_SMC_REG_GPR:	// General Purpose
+			smc_modify_reg(1, ioaddr, GP_REG, val);
+			break;
+
+		case CTL_SMC_REG_CTLR:	// Control
+			smc_modify_reg(1, ioaddr, CTL_REG, val);
+			break;
+
+		case CTL_SMC_REG_MCR:	// MMU Command
+			smc_modify_reg(2, ioaddr, MMU_CMD_REG, val);
+			break;
+
+		case CTL_SMC_REG_PNR:	// Packet Number
+			smc_modify_reg(2, ioaddr, PN_REG, val);
+			break;
+
+		case CTL_SMC_REG_FPR:	// Allocation Result/FIFO Ports
+			smc_modify_reg(2, ioaddr, RXFIFO_REG, val);
+			break;
+
+		case CTL_SMC_REG_PTR:	// Pointer
+			smc_modify_reg(2, ioaddr, PTR_REG, val);
+			break;
+
+		case CTL_SMC_REG_DR:	// Data 
+			smc_modify_reg(2, ioaddr, DATA_REG, val);
+			break;
+
+		case CTL_SMC_REG_ISR:	// Interrupt Status/Mask
+			smc_modify_reg(2, ioaddr, INT_REG, val);
+			break;
+
+		case CTL_SMC_REG_MTR1:	// Multicast Table Entry 1
+			smc_modify_reg(3, ioaddr, MCAST_REG1, val);
+			break;
+
+		case CTL_SMC_REG_MTR2:	// Multicast Table Entry 2
+			smc_modify_reg(3, ioaddr, MCAST_REG2, val);
+			break;
+
+		case CTL_SMC_REG_MTR3:	// Multicast Table Entry 3
+			smc_modify_reg(3, ioaddr, MCAST_REG3, val);
+			break;
+
+		case CTL_SMC_REG_MTR4:	// Multicast Table Entry 4
+			smc_modify_reg(3, ioaddr, MCAST_REG4, val);
+			break;
+
+		case CTL_SMC_REG_MIIR:	// Management Interface
+			smc_modify_reg(3, ioaddr, MII_REG, val);
+			break;
+
+		case CTL_SMC_REG_REVR:	// Revision
+			smc_modify_reg(3, ioaddr, REV_REG, val);
+			break;
+
+		case CTL_SMC_REG_ERCVR:	// Early RCV
+			smc_modify_reg(3, ioaddr, ERCV_REG, val);
+			break;
+
+		case CTL_SMC_REG_EXTR:	// External
+			smc_modify_reg(7, ioaddr, EXT_REG, val);
+			break;
+
+		case CTL_SMC_PHY_CTRL:
+			smc_write_phy_register(ioaddr, lp->phyaddr,
+				PHY_CNTL_REG, val);
+			break;
+
+		case CTL_SMC_PHY_STAT:
+			smc_write_phy_register(ioaddr, lp->phyaddr,
+				PHY_STAT_REG, val);
+			break;
+
+		case CTL_SMC_PHY_ID1:
+			smc_write_phy_register(ioaddr, lp->phyaddr,
+				PHY_ID1_REG, val);
+			break;
+
+		case CTL_SMC_PHY_ID2:
+			smc_write_phy_register(ioaddr, lp->phyaddr,
+				PHY_ID2_REG, val);
+			break;
+
+		case CTL_SMC_PHY_ADC:
+			smc_write_phy_register(ioaddr, lp->phyaddr,
+				PHY_AD_REG, val);
+			break;
+
+		case CTL_SMC_PHY_REMC:
+			smc_write_phy_register(ioaddr, lp->phyaddr,
+				PHY_RMT_REG, val);
+			break;
+
+		case CTL_SMC_PHY_CFG1:
+			smc_write_phy_register(ioaddr, lp->phyaddr,
+				PHY_CFG1_REG, val);
+			break;
+
+		case CTL_SMC_PHY_CFG2:
+			smc_write_phy_register(ioaddr, lp->phyaddr,
+				PHY_CFG2_REG, val);
+			break;
+
+		case CTL_SMC_PHY_INT:
+			smc_write_phy_register(ioaddr, lp->phyaddr,
+				PHY_INT_REG, val);
+			break;
+
+		case CTL_SMC_PHY_MASK:
+			smc_write_phy_register(ioaddr, lp->phyaddr,
+				PHY_MASK_REG, val);
+			break;
+
+#endif // SMC_DEBUG
+
+		default:
+			// Just ignore unsupported parameters
+			break;
+		} // end switch
+
+	} // end if
+
+        return ret;
+}
+
+/*------------------------------------------------------------
+ . Sysctl registration function for all parameters (files)
+ .-------------------------------------------------------------*/
+static void smc_sysctl_register(struct net_device *dev)
+{
+	struct smc_local *lp = (struct smc_local *)dev->priv;
+	static int ctl_name = CTL_SMC;
+	ctl_table* ct;
+	int i;
+
+	// Make sure the ctl_tables start out as all zeros
+	memset(lp->root_table, 0, sizeof lp->root_table);
+	memset(lp->eth_table, 0, sizeof lp->eth_table);
+	memset(lp->param_table, 0, sizeof lp->param_table);
+
+	// Initialize the root table
+	ct = lp->root_table;
+	ct->ctl_name = CTL_DEV;
+	ct->procname = "dev";
+	ct->maxlen = 0;
+	ct->mode = 0555;
+	ct->child = lp->eth_table;
+	// remaining fields are zero
+
+	// Initialize the ethX table (this device's table)
+	ct = lp->eth_table;
+	ct->ctl_name = ctl_name++; // Must be unique
+	ct->procname = dev->name;
+	ct->maxlen = 0;
+	ct->mode = 0555;
+	ct->child = lp->param_table;
+	// remaining fields are zero
+
+	// Initialize the parameter (files) table
+	// Make sure the last entry remains null
+	ct = lp->param_table;
+	for (i = 0; i < (CTL_SMC_LAST_ENTRY-1); ++i)
+		{
+		// Initialize fields common to all table entries
+		ct[i].proc_handler = smc_sysctl_handler;
+		ct[i].extra1 = (void*)dev; // Save our device pointer
+		ct[i].extra2 = (void*)lp;  // Save our smc_local data pointer
+		}
+
+	// INFO - this is our only string parameter
+	i = 0;
+	ct[i].proc_handler = proc_dostring; // use default handler
+	ct[i].ctl_name = CTL_SMC_INFO;
+	ct[i].procname = "info";
+	ct[i].data = (void*)smc_info_string;
+	ct[i].maxlen = sizeof smc_info_string;
+	ct[i].mode = 0444; // Read only
+
+	// SWVER
+	++i;
+	ct[i].proc_handler = proc_dostring; // use default handler
+	ct[i].ctl_name = CTL_SMC_SWVER;
+	ct[i].procname = "swver";
+	ct[i].data = (void*)version;
+	ct[i].maxlen = sizeof version;
+	ct[i].mode = 0444; // Read only
+
+	// SWFDUP
+	++i;
+	ct[i].ctl_name = CTL_SMC_SWFDUP;
+	ct[i].procname = "swfdup";
+	ct[i].data = (void*)&(lp->ctl_swfdup);
+	ct[i].maxlen = 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.0.org/arch/m32r/drivers/smc91111.copying linux-2.6.0/arch/m32r/drivers/smc91111.copying
--- linux-2.6.0.org/arch/m32r/drivers/smc91111.copying	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.0/arch/m32r/drivers/smc91111.copying	2003-09-09 10:15:02.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.0.org/arch/m32r/drivers/smc91111.h linux-2.6.0/arch/m32r/drivers/smc91111.h
--- linux-2.6.0.org/arch/m32r/drivers/smc91111.h	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.0/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.0.org/arch/m32r/drivers/smc91111.readme.txt linux-2.6.0/arch/m32r/drivers/smc91111.readme.txt
--- linux-2.6.0.org/arch/m32r/drivers/smc91111.readme.txt	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.0/arch/m32r/drivers/smc91111.readme.txt	2003-09-09 10:15:02.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.0.org/arch/m32r/drivers/video/Config.in linux-2.6.0/arch/m32r/drivers/video/Config.in
--- linux-2.6.0.org/arch/m32r/drivers/video/Config.in	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.0/arch/m32r/drivers/video/Config.in	2003-09-09 10:15:02.000000000 +0900
@@ -0,0 +1,550 @@
+#
+# Video configuration
+#
+
+mainmenu_option next_comment
+comment 'Frame-buffer support'
+
+bool 'Support for frame buffer devices (EXPERIMENTAL)' CONFIG_FB
+
+if [ "$CONFIG_FB" = "y" ]; then
+   define_bool CONFIG_DUMMY_CONSOLE y
+   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      if [ "$CONFIG_PCI" = "y" ]; then
+         tristate '  nVidia Riva support (EXPERIMENTAL)' CONFIG_FB_RIVA
+      fi
+      if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_PCI" = "y" ]; then
+	 tristate '  Cirrus Logic support (EXPERIMENTAL)' CONFIG_FB_CLGEN
+	 tristate '  Permedia2 support (EXPERIMENTAL)' CONFIG_FB_PM2
+	 if [ "$CONFIG_FB_PM2" = "y" -o "$CONFIG_FB_PM2" = "m" ]; then
+	    if [ "$CONFIG_PCI" = "y" ]; then
+	       bool '    enable FIFO disconnect feature' CONFIG_FB_PM2_FIFO_DISCONNECT
+	       bool '    generic Permedia2 PCI board support' CONFIG_FB_PM2_PCI
+	    fi
+	    if [ "$CONFIG_AMIGA" = "y" ]; then
+	       bool '    Phase5 CVisionPPC/BVisionPPC support' CONFIG_FB_PM2_CVPPC
+	    fi
+	 fi
+      fi
+      if [ "$CONFIG_PCI" = "y" ]; then
+         tristate '  Permedia3 support (EXPERIMENTAL)' CONFIG_FB_PM3
+      fi
+   fi
+   if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
+      bool '  Acorn VIDC support' CONFIG_FB_ACORN
+   fi
+   dep_tristate '  Cyber2000 support' CONFIG_FB_CYBER2000 $CONFIG_PCI
+   if [ "$CONFIG_ARCH_SA1100" = "y" ]; then
+      bool '  SA-1100 LCD support' CONFIG_FB_SA1100
+   fi
+   if [ "$CONFIG_APOLLO" = "y" ]; then
+      define_bool CONFIG_FB_APOLLO y
+   fi
+   if [ "$CONFIG_Q40" = "y" ]; then
+      define_bool CONFIG_FB_Q40 y
+   fi
+   if [ "$CONFIG_AMIGA" = "y" ]; then
+      tristate '  Amiga native chipset support' CONFIG_FB_AMIGA
+      if [ "$CONFIG_FB_AMIGA" != "n" ]; then
+	 bool '    Amiga OCS chipset support' CONFIG_FB_AMIGA_OCS
+	 bool '    Amiga ECS chipset support' CONFIG_FB_AMIGA_ECS
+	 bool '    Amiga AGA chipset support' CONFIG_FB_AMIGA_AGA
+      fi
+   fi
+   if [ "$CONFIG_ZORRO" = "y" ]; then
+      tristate '  Amiga CyberVision support' CONFIG_FB_CYBER
+      if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+	 bool '  Amiga CyberVision3D support (EXPERIMENTAL)' CONFIG_FB_VIRGE
+	 tristate '  Amiga RetinaZ3 support (EXPERIMENTAL)' CONFIG_FB_RETINAZ3
+	 bool '  Amiga FrameMaster II/Rainbow II support (EXPERIMENTAL)' CONFIG_FB_FM2
+      fi
+   fi
+   if [ "$CONFIG_ATARI" = "y" ]; then
+      bool '  Atari native chipset support' CONFIG_FB_ATARI
+      tristate '  ATI Mach64 display support' CONFIG_FB_ATY
+      if [ "$CONFIG_FB_ATY" != "n" ]; then
+	 define_bool CONFIG_FB_ATY_GX y
+      fi
+   fi
+   if [ "$CONFIG_PPC" = "y" ]; then
+      dep_bool '  Open Firmware frame buffer device support' CONFIG_FB_OF $CONFIG_ALL_PPC
+      dep_bool '  Apple "control" display support' CONFIG_FB_CONTROL $CONFIG_ALL_PPC
+      dep_bool '  Apple "platinum" display support' CONFIG_FB_PLATINUM $CONFIG_ALL_PPC
+      dep_bool '  Apple "valkyrie" display support' CONFIG_FB_VALKYRIE $CONFIG_ALL_PPC
+      bool '  Chips 65550 display support' CONFIG_FB_CT65550
+      bool '  IMS Twin Turbo display support' CONFIG_FB_IMSTT
+      bool '  S3 Trio display support' CONFIG_FB_S3TRIO
+      tristate '  VGA 16-color graphics console' CONFIG_FB_VGA16
+   fi
+   if [ "$CONFIG_PARISC" = "y" ]; then
+      bool '  Generic STI frame buffer device support' CONFIG_FB_STI
+   fi
+   if [ "$CONFIG_MAC" = "y" ]; then
+      define_bool CONFIG_FB_MAC y
+      bool '  Apple "valkyrie" display support' CONFIG_FB_VALKYRIE
+#      bool '  Apple DAFB display support' CONFIG_FB_DAFB
+   fi
+   if [ "$CONFIG_HP300" = "y" ]; then
+      define_bool CONFIG_FB_HP300 y
+   fi
+   if [ "$ARCH" = "alpha" ]; then
+      tristate '  TGA framebuffer support' CONFIG_FB_TGA
+   fi
+   if [ "$ARCH" = "i386" ]; then
+      bool '  VESA VGA graphics console' CONFIG_FB_VESA
+      tristate '  VGA 16-color graphics console' CONFIG_FB_VGA16
+      tristate '  Hercules mono graphics console (EXPERIMENTAL)' CONFIG_FB_HGA
+      define_bool CONFIG_VIDEO_SELECT y
+   fi
+   if [ "$CONFIG_VISWS" = "y" ]; then
+      tristate '  SGI Visual Workstation framebuffer support' CONFIG_FB_SGIVW
+      define_bool CONFIG_BUS_I2C y
+   fi
+   if [ "$CONFIG_SUN3" = "y" -o "$CONFIG_SUN3X" = "y" ]; then
+      bool '  Sun3 framebuffer support' CONFIG_FB_SUN3
+      if [ "$CONFIG_FB_SUN3" != "n" ]; then
+         bool '    BWtwo support' CONFIG_FB_BWTWO
+         bool '    CGsix (GX,TurboGX) support' CONFIG_FB_CGSIX
+      fi
+   fi
+   if [ "$CONFIG_SH_DREAMCAST" = "y" ]; then
+      tristate '  NEC PowerVR 2 display support' CONFIG_FB_PVR2
+      dep_bool '    Debug pvr2fb' CONFIG_FB_PVR2_DEBUG $CONFIG_FB_PVR2
+   fi
+   if [ "$CONFIG_SUPERH" = "y" ]; then
+      bool '  Epson 1355 framebuffer support' CONFIG_FB_E1355
+      if [ "$CONFIG_FB_E1355" = "y" ]; then
+         hex '    Register Base Address' CONFIG_E1355_REG_BASE a8000000
+         hex '    Framebuffer Base Address' CONFIG_E1355_FB_BASE a8200000
+      fi
+   fi
+   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+
+
+bool 'Epson LCD/CRT/TV controller support' CONFIG_FB_EPSON
+if [ "$CONFIG_FB_EPSON" != "n" ]; then
+	define_bool CONFIG_FBCON_EPSON y
+	bool '  Epson S1D13504 Support' CONFIG_FB_EPSON_S1D13504
+	if [ "$CONFIG_FB_EPSON_S1D13504" = "y" ]; then
+		define_bool CONFIG_FBCON_EPSON_S1D13504 y
+		define_bool CONFIG_FBCON_EPSON_PCI n
+	fi
+	bool '  Epson S1D13505 Support' CONFIG_FB_EPSON_S1D13505
+	if [ "$CONFIG_FB_EPSON_S1D13505" = "y" ]; then
+         define_bool CONFIG_FBCON_EPSON_S1D13505 y
+         define_bool CONFIG_FBCON_EPSON_PCI n
+	fi
+	bool '  Epson S1D13506 Support' CONFIG_FB_EPSON_S1D13506
+	if [ "$CONFIG_FB_EPSON_S1D13506" = "y" ]; then
+		define_bool CONFIG_FBCON_EPSON_S1D13506 y
+		if [ "$CONFIG_PCI" != "n" ]; then
+			bool '      Epson PCI Bridge adapter support' CONFIG_FB_EPSON_PCI
+			if [ "$CONFIG_FB_EPSON_PCI" = "y" ]; then
+				define_bool CONFIG_FBCON_EPSON_PCI y
+			fi
+		fi
+	fi
+
+	bool '  Epson S1D13704 Support' CONFIG_FB_EPSON_S1D13704
+	if [ "$CONFIG_FB_EPSON_S1D13704" = "y" ]; then
+		define_bool CONFIG_FBCON_EPSON_S1D13704 y
+		define_bool CONFIG_FBCON_EPSON_PCI n
+	fi
+	bool '  Epson S1D13705 Support' CONFIG_FB_EPSON_S1D13705
+	if [ "$CONFIG_FB_EPSON_S1D13705" = "y" ]; then
+		define_bool CONFIG_FBCON_EPSON_S1D13705 y
+		define_bool CONFIG_FBCON_EPSON_PCI n
+	fi
+	bool '  Epson S1D13706 Support' CONFIG_FB_EPSON_S1D13706
+	if [ "$CONFIG_FB_EPSON_S1D13706" = "y" ]; then
+		define_bool CONFIG_FBCON_EPSON_S1D13706 y
+		if [ "$CONFIG_PCI" != "n" ]; then
+			bool '      Epson PCI Bridge adapter support' CONFIG_FB_EPSON_PCI
+			if [ "$CONFIG_FB_EPSON_PCI" = "y" ]; then
+				define_bool CONFIG_FBCON_EPSON_PCI y
+			fi
+		fi
+	fi
+	bool '  Epson S1D13806 Support' CONFIG_FB_EPSON_S1D13806
+	if [ "$CONFIG_FB_EPSON_S1D13806" = "y" ]; then
+		define_bool CONFIG_FBCON_EPSON_S1D13806 y
+		if [ "$CONFIG_PCI" != "n" ]; then
+			bool '      Epson PCI Bridge adapter support' CONFIG_FB_EPSON_PCI
+			if [ "$CONFIG_FB_EPSON_PCI" = "y" ]; then
+				define_bool CONFIG_FBCON_EPSON_PCI y
+			fi
+		fi
+	fi
+
+	bool '  Epson S1D13A03 Support' CONFIG_FB_EPSON_S1D13A03
+	if [ "$CONFIG_FB_EPSON_S1D13A03" = "y" ]; then
+		define_bool CONFIG_FBCON_EPSON_S1D13A03 y
+		if [ "$CONFIG_PCI" != "n" ]; then
+			bool '      Epson PCI Bridge adapter support' CONFIG_FB_EPSON_PCI
+			if [ "$CONFIG_FB_EPSON_PCI" = "y" ]; then
+				define_bool CONFIG_FBCON_EPSON_PCI y
+			fi
+		fi
+	fi
+fi
+
+    # -------------------------------------------------
+    # End of Epson LCD/CRT/TV controllers configuration
+    # -------------------------------------------------
+
+
+
+
+      if [ "$CONFIG_PCI" != "n" ]; then
+	 tristate '  Matrox acceleration (EXPERIMENTAL)' CONFIG_FB_MATROX
+	 if [ "$CONFIG_FB_MATROX" != "n" ]; then
+	    bool '    Millennium I/II support' CONFIG_FB_MATROX_MILLENIUM
+	    bool '    Mystique support' CONFIG_FB_MATROX_MYSTIQUE
+	    bool '    G100/G200/G400/G450/G550 support' CONFIG_FB_MATROX_G100
+            if [ "$CONFIG_I2C" != "n" ]; then
+	       dep_tristate '      Matrox I2C support' CONFIG_FB_MATROX_I2C $CONFIG_FB_MATROX $CONFIG_I2C_ALGOBIT
+	       if [ "$CONFIG_FB_MATROX_G100" = "y" ]; then
+	          dep_tristate '      G400 second head support' CONFIG_FB_MATROX_MAVEN $CONFIG_FB_MATROX_I2C
+	       fi
+            fi
+            dep_tristate '      G450/G550 second head support (mandatory for G550)' CONFIG_FB_MATROX_G450 $CONFIG_FB_MATROX_G100
+	    bool '    Multihead support' CONFIG_FB_MATROX_MULTIHEAD
+	 fi
+	 tristate '  ATI Mach64 display support (EXPERIMENTAL)' CONFIG_FB_ATY
+	 if [ "$CONFIG_FB_ATY" != "n" ]; then
+	    bool '    Mach64 GX support (EXPERIMENTAL)' CONFIG_FB_ATY_GX
+	    bool '    Mach64 CT/VT/GT/LT (incl. 3D RAGE) support' CONFIG_FB_ATY_CT
+	 fi
+ 	 tristate '  ATI Radeon display support (EXPERIMENTAL)' CONFIG_FB_RADEON
+	 tristate '  ATI Rage128 display support (EXPERIMENTAL)' CONFIG_FB_ATY128
+	 tristate '  SIS acceleration (EXPERIMENTAL)' CONFIG_FB_SIS
+	 if [ "$CONFIG_FB_SIS" != "n" ]; then
+	    bool '    SIS 630/540/730 support' CONFIG_FB_SIS_300
+	    bool '    SIS 315H/315 support' CONFIG_FB_SIS_315
+	 fi
+	 tristate '  NeoMagic display support (EXPERIMENTAL)' CONFIG_FB_NEOMAGIC
+	 tristate '  3Dfx Banshee/Voodoo3 display support (EXPERIMENTAL)' CONFIG_FB_3DFX
+	 tristate '  3Dfx Voodoo Graphics (sst1) support (EXPERIMENTAL)' CONFIG_FB_VOODOO1
+	 tristate '  Trident support (EXPERIMENTAL)' CONFIG_FB_TRIDENT
+      fi
+   fi
+   if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
+      bool '  SBUS and UPA framebuffers' CONFIG_FB_SBUS
+      if [ "$CONFIG_FB_SBUS" != "n" ]; then
+	 if [ "$ARCH" = "sparc64" ]; then
+	    bool '    Creator/Creator3D support' CONFIG_FB_CREATOR
+	 fi
+	 bool '    CGsix (GX,TurboGX) support' CONFIG_FB_CGSIX
+	 bool '    BWtwo support' CONFIG_FB_BWTWO
+	 bool '    CGthree support' CONFIG_FB_CGTHREE
+	 if [ "$ARCH" = "sparc" ]; then
+	    bool '    TCX (SS4/SS5 only) support' CONFIG_FB_TCX
+	    bool '    CGfourteen (SX) support' CONFIG_FB_CGFOURTEEN
+	    bool '    P9100 (Sparcbook 3 only) support' CONFIG_FB_P9100
+	 fi
+	 bool '    Leo (ZX) support' CONFIG_FB_LEO
+      fi
+   fi
+   if [ "$ARCH" = "sparc" ]; then
+      if [ "$CONFIG_PCI" != "n" ]; then
+	 bool '  PCI framebuffers' CONFIG_FB_PCI
+	 if [ "$CONFIG_FB_PCI" != "n" ]; then
+	    bool '    IGA 168x display support' CONFIG_FB_IGA
+	 fi
+      fi
+   fi
+   if [ "$ARCH" = "sparc64" ]; then
+      if [ "$CONFIG_PCI" != "n" ]; then
+	 bool '  PCI framebuffers' CONFIG_FB_PCI
+	 if [ "$CONFIG_FB_PCI" != "n" ]; then
+	    tristate '    ATI Mach64 display support' CONFIG_FB_ATY
+	    if [ "$CONFIG_FB_ATY" != "n" ]; then
+	       define_bool CONFIG_FB_ATY_CT y
+	    fi
+	 fi
+      fi
+   fi
+   if [ "$CONFIG_HD64461" = "y" ]; then
+      tristate '  HD64461 Frame Buffer support' CONFIG_FB_HIT
+   fi
+   if [ "$CONFIG_DECSTATION" = "y" ]; then
+     if [ "$CONFIG_TC" = "y" ]; then
+       bool '  PMAG-BA TURBOchannel framebuffer support' CONFIG_FB_PMAG_BA
+       bool '  PMAGB-B TURBOchannel framebuffer spport' CONFIG_FB_PMAGB_B
+       bool '  Maxine (Personal DECstation) onboard framebuffer spport' CONFIG_FB_MAXINE
+     fi
+   fi
+   if [ "$CONFIG_NINO" = "y" ]; then
+      bool '  TMPTX3912/PR31700 frame buffer support' CONFIG_FB_TX3912
+   fi
+   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      tristate '  Virtual Frame Buffer support (ONLY FOR TESTING!)' CONFIG_FB_VIRTUAL
+   fi
+
+   bool '  Advanced low level driver options' CONFIG_FBCON_ADVANCED
+   if [ "$CONFIG_FBCON_ADVANCED" = "y" ]; then
+      tristate '    Monochrome support' CONFIG_FBCON_MFB
+      tristate '    2 bpp packed pixels support' CONFIG_FBCON_CFB2
+      tristate '    4 bpp packed pixels support' CONFIG_FBCON_CFB4
+      tristate '    8 bpp packed pixels support' CONFIG_FBCON_CFB8
+      tristate '    16 bpp packed pixels support' CONFIG_FBCON_CFB16
+      tristate '    24 bpp packed pixels support' CONFIG_FBCON_CFB24
+      tristate '    32 bpp packed pixels support' CONFIG_FBCON_CFB32
+      tristate '    Amiga bitplanes support' CONFIG_FBCON_AFB
+      tristate '    Amiga interleaved bitplanes support' CONFIG_FBCON_ILBM
+      tristate '    Atari interleaved bitplanes (2 planes) support' CONFIG_FBCON_IPLAN2P2
+      tristate '    Atari interleaved bitplanes (4 planes) support' CONFIG_FBCON_IPLAN2P4
+      tristate '    Atari interleaved bitplanes (8 planes) support' CONFIG_FBCON_IPLAN2P8
+#      tristate '    Atari interleaved bitplanes (16 planes) support' CONFIG_FBCON_IPLAN2P16
+      tristate '    Mac variable bpp packed pixels support' CONFIG_FBCON_MAC
+      tristate '    VGA 16-color planar support' CONFIG_FBCON_VGA_PLANES
+      tristate '    VGA characters/attributes support' CONFIG_FBCON_VGA
+      tristate '    HGA monochrome support (EXPERIMENTAL)' CONFIG_FBCON_HGA
+   else
+      # Guess what we need
+      if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_AMIGA" = "y" -o \
+	   "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_CYBER" = "y" -o \
+	   "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_RETINAZ3" = "y" -o \
+	   "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
+	   "$CONFIG_FB_BWTWO" = "y" -o "$CONFIG_FB_CLGEN" = "y"  -o \
+	   "$CONFIG_FB_TX3912" = "y" ]; then
+	 define_tristate CONFIG_FBCON_MFB y
+      else
+	 if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_AMIGA" = "m" -o \
+	      "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \
+	      "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_RETINAZ3" = "m" -o \
+	      "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
+	      "$CONFIG_FB_BWTWO" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \
+	      "$CONFIG_FB_TX3912" = "m" ]; then
+	    define_tristate CONFIG_FBCON_MFB m
+	 fi
+      fi
+      if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_MAC" = "y" -o \
+	   "$CONFIG_FB_SA1100" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
+	   "$CONFIG_FB_TX3912" = "y" ]; then
+	 define_tristate CONFIG_FBCON_CFB2 y
+	 define_tristate CONFIG_FBCON_CFB4 y
+      else
+	 if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_MAC" = "m" -o \
+	      "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
+	      "$CONFIG_FB_TX3912" = "m" ]; then
+	    define_tristate CONFIG_FBCON_CFB2 m
+	    define_tristate CONFIG_FBCON_CFB4 m
+	 fi
+      fi
+      if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_ATARI" = "y" -o \
+	   "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_MAC" = "y" -o \
+	   "$CONFIG_FB_OF" = "y" -o "$CONFIG_FB_TGA" = "y" -o \
+	   "$CONFIG_FB_VESA" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
+	   "$CONFIG_FB_TCX" = "y" -o "$CONFIG_FB_CGTHREE" = "y" -o \
+	   "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \
+	   "$CONFIG_FB_CGFOURTEEN" = "y" -o "$CONFIG_FB_G364" = "y" -o \
+	   "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_CYBER" = "y" -o \
+	   "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \
+           "$CONFIG_FB_IGA" = "y" -o "$CONFIG_FB_MATROX" = "y" -o \
+	   "$CONFIG_FB_CT65550" = "y" -o "$CONFIG_FB_PM2" = "y" -o \
+           "$CONFIG_FB_PM3" = "y" -o \
+	   "$CONFIG_FB_P9100" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \
+	   "$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_RADEON" = "y" -o \
+	   "$CONFIG_FB_SGIVW" = "y" -o "$CONFIG_FB_CYBER2000" = "y" -o \
+	   "$CONFIG_FB_SA1100" = "y" -o "$CONFIG_FB_3DFX" = "y" -o \
+	   "$CONFIG_FB_PMAG_BA" = "y" -o "$CONFIG_FB_PMAGB_B" = "y" -o \
+	   "$CONFIG_FB_MAXINE" = "y" -o "$CONFIG_FB_TX3912" = "y" -o \
+	   "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_NEOMAGIC" = "y" ]; then
+	 define_tristate CONFIG_FBCON_CFB8 y
+      else
+	 if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \
+	      "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_MAC" = "m" -o \
+	      "$CONFIG_FB_OF" = "m" -o "$CONFIG_FB_TGA" = "m" -o \
+	      "$CONFIG_FB_VESA" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
+	      "$CONFIG_FB_TCX" = "m" -o "$CONFIG_FB_CGTHREE" = "m" -o \
+	      "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \
+	      "$CONFIG_FB_CGFOURTEEN" = "m" -o "$CONFIG_FB_G364" = "m" -o \
+	      "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \
+	      "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \
+              "$CONFIG_FB_IGA" = "m" -o "$CONFIG_FB_MATROX" = "m" -o \
+	      "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
+              "$CONFIG_FB_PM3" = "m" -o \
+	      "$CONFIG_FB_P9100" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \
+	      "$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_3DFX" = "m" -o \
+	      "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_CYBER2000" = "m" -o \
+	      "$CONFIG_FB_PMAG_BA" = "m" -o "$CONFIG_FB_PMAGB_B" = "m" -o \
+	      "$CONFIG_FB_MAXINE" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
+	      "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_SIS" = "m" -o \
+	      "$CONFIG_FB_TX3912" = "m" -o "$CONFIG_FB_NEOMAGIC" = "m" ]; then
+	    define_tristate CONFIG_FBCON_CFB8 m
+	 fi
+      fi
+      if [ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATY" = "y" -o \
+	   "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_VESA" = "y" -o \
+	   "$CONFIG_FB_VIRTUAL" = "y" -o "$CONFIG_FB_TBOX" = "y" -o \
+	   "$CONFIG_FB_Q40" = "y" -o "$CONFIG_FB_RADEON" = "y" -o \
+	   "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \
+	   "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_CYBER" = "y" -o \
+	   "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \
+	   "$CONFIG_FB_CT65550" = "y" -o "$CONFIG_FB_MATROX" = "y" -o \
+	   "$CONFIG_FB_PM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" -o \
+           "$CONFIG_FB_PM3" = "y" -o \
+	   "$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \
+	   "$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_3DFX" = "y"  -o \
+	   "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_SA1100" = "y" -o \
+	   "$CONFIG_FB_PVR2" = "y" -o "$CONFIG_FB_VOODOO1" = "y" -o \
+	   "$CONFIG_FB_NEOMAGIC" = "y" ]; then
+	 define_tristate CONFIG_FBCON_CFB16 y
+      else
+	 if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \
+	      "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_VESA" = "m" -o \
+	      "$CONFIG_FB_VIRTUAL" = "m" -o "$CONFIG_FB_TBOX" = "m" -o \
+	      "$CONFIG_FB_Q40" = "m" -o "$CONFIG_FB_3DFX" = "m" -o \
+	      "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \
+	      "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \
+	      "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \
+	      "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_MATROX" = "m" -o \
+	      "$CONFIG_FB_PM2" = "m" -o "$CONFIG_FB_SGIVW" = "m" -o \
+              "$CONFIG_FB_PM3" = "m" -o \
+	      "$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \
+	      "$CONFIG_FB_CYBER2000" = "m" -o "$CONFIG_FB_SIS" = "m" -o \
+	      "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
+	      "$CONFIG_FB_PVR2" = "m" -o "$CONFIG_FB_VOODOO1" = "m" -o \
+	      "$CONFIG_FB_NEOMAGIC" = "m" ]; then
+	    define_tristate CONFIG_FBCON_CFB16 m
+	 fi
+      fi
+      if [ "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
+	   "$CONFIG_FB_CLGEN" = "y" -o "$CONFIG_FB_VESA" = "y" -o \
+	   "$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" -o \
+           "$CONFIG_FB_ATY128" = "y" -o "$CONFIG_FB_RADEON" = "y" -o \
+	   "$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_PVR2" = "y" -o \
+	   "$CONFIG_FB_VOODOO1" = "y" -o "$CONFIG_FB_NEOMAGIC" = "y" ]; then
+	 define_tristate CONFIG_FBCON_CFB24 y
+      else
+	 if [ "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
+	      "$CONFIG_FB_CLGEN" = "m" -o "$CONFIG_FB_VESA" = "m" -o \
+	      "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
+	      "$CONFIG_FB_ATY128" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
+	      "$CONFIG_FB_CYBER2000" = "m" -o "$CONFIG_FB_PVR2" = "m" -o \
+	      "$CONFIG_FB_VOODOO1" = "m" -o "$CONFIG_FB_NEOMAGIC" = "m" ]; then
+	    define_tristate CONFIG_FBCON_CFB24 m
+	 fi
+      fi
+      if [ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATY" = "y" -o \
+	   "$CONFIG_FB_VESA" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
+	   "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \
+	   "$CONFIG_FB_TGA" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \
+	   "$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" -o \
+           "$CONFIG_FB_PM3" = "y" -o \
+	   "$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \
+	   "$CONFIG_FB_FM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" -o \
+	   "$CONFIG_FB_RADEON" = "y" -o "$CONFIG_FB_PVR2" = "y" -o \
+	   "$CONFIG_FB_3DFX" = "y" -o "$CONFIG_FB_SIS" = "y" -o \
+	   "$CONFIG_FB_VOODOO1" = "y" -o "$CONFIG_FB_CYBER2000" = "y" ]; then
+	 define_tristate CONFIG_FBCON_CFB32 y
+      else
+	 if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \
+	      "$CONFIG_FB_VESA" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
+	      "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \
+	      "$CONFIG_FB_TGA" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \
+	      "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
+              "$CONFIG_FB_PM3" = "m" -o \
+	      "$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \
+	      "$CONFIG_FB_3DFX" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
+	      "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_SIS" = "m" -o \
+	      "$CONFIG_FB_PVR2" = "m" -o "$CONFIG_FB_VOODOO1" = "m" -o \
+	      "$CONFIG_FB_CYBER2000" = "m" ]; then
+	    define_tristate CONFIG_FBCON_CFB32 m
+	 fi
+      fi
+      if [ "$CONFIG_FB_AMIGA" = "y" ]; then
+	 define_tristate CONFIG_FBCON_AFB y
+	 define_tristate CONFIG_FBCON_ILBM y
+      else
+	 if [ "$CONFIG_FB_AMIGA" = "m" ]; then
+	    define_tristate CONFIG_FBCON_AFB m
+	    define_tristate CONFIG_FBCON_ILBM m
+	 fi
+      fi
+      if [ "$CONFIG_FB_ATARI" = "y" ]; then
+	 define_tristate CONFIG_FBCON_IPLAN2P2 y
+	 define_tristate CONFIG_FBCON_IPLAN2P4 y
+	 define_tristate CONFIG_FBCON_IPLAN2P8 y
+#	 define_tristate CONFIG_FBCON_IPLAN2P16 y
+      else
+	 if [ "$CONFIG_FB_ATARI" = "m" ]; then
+	    define_tristate CONFIG_FBCON_IPLAN2P2 m
+	    define_tristate CONFIG_FBCON_IPLAN2P4 m
+	    define_tristate CONFIG_FBCON_IPLAN2P8 m
+#	    define_tristate CONFIG_FBCON_IPLAN2P16 m
+	 fi
+      fi
+      if [ "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" ]; then
+	 define_tristate CONFIG_FBCON_MAC  y
+      else
+	 if [ "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" ]; then
+	    define_tristate CONFIG_FBCON_MAC  m
+	 fi
+      fi
+      if [ "$CONFIG_FB_VGA16" = "y" ]; then
+	 define_tristate CONFIG_FBCON_VGA_PLANES y
+      else
+	 if [ "$CONFIG_FB_VGA16" = "m" ]; then
+	    define_tristate CONFIG_FBCON_VGA_PLANES m
+	 fi
+      fi
+      if [ "$CONFIG_FB_HGA" = "y" ]; then
+	 define_tristate CONFIG_FBCON_HGA y
+      else
+	 if [ "$CONFIG_FB_HGA" = "m" ]; then
+	    define_tristate CONFIG_FBCON_HGA m
+	 fi
+      fi
+      if [ "$CONFIG_FB_STI" = "y" ]; then
+	 define_tristate CONFIG_FBCON_STI y
+      fi
+   fi
+   bool '  Support only 8 pixels wide fonts' CONFIG_FBCON_FONTWIDTH8_ONLY
+   if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
+      bool '  Sparc console 8x16 font' CONFIG_FONT_SUN8x16
+      if [ "$CONFIG_FBCON_FONTWIDTH8_ONLY" = "n" ]; then
+	 bool '  Sparc console 12x22 font (not supported by all drivers)' CONFIG_FONT_SUN12x22
+      fi
+      bool '  Select other fonts' CONFIG_FBCON_FONTS
+      if [ "$CONFIG_FBCON_FONTS" = "y" ]; then
+	 bool '    VGA 8x8 font' CONFIG_FONT_8x8
+	 bool '    VGA 8x16 font' CONFIG_FONT_8x16
+	 if [ "$CONFIG_FBCON_FONTWIDTH8_ONLY" = "n" ]; then
+	    bool '    Mac console 6x11 font (not supported by all drivers)' CONFIG_FONT_6x11
+	 fi
+	 bool '    Pearl (old m68k) console 8x8 font' CONFIG_FONT_PEARL_8x8
+	 bool '    Acorn console 8x8 font' CONFIG_FONT_ACORN_8x8
+      fi
+   else
+      bool '  Select compiled-in fonts' CONFIG_FBCON_FONTS
+      if [ "$CONFIG_FBCON_FONTS" = "y" ]; then
+	 bool '    VGA 8x8 font' CONFIG_FONT_8x8
+	 bool '    VGA 8x16 font' CONFIG_FONT_8x16
+	 bool '    Sparc console 8x16 font' CONFIG_FONT_SUN8x16
+	 if [ "$CONFIG_FBCON_FONTWIDTH8_ONLY" = "n" ]; then
+	    bool '    Sparc console 12x22 font (not supported by all drivers)' CONFIG_FONT_SUN12x22
+	    bool '    Mac console 6x11 font (not supported by all drivers)' CONFIG_FONT_6x11
+	 fi
+	 bool '    Pearl (old m68k) console 8x8 font' CONFIG_FONT_PEARL_8x8
+	 bool '    Acorn console 8x8 font' CONFIG_FONT_ACORN_8x8
+      else
+	 define_bool CONFIG_FONT_8x8 y
+	 define_bool CONFIG_FONT_8x16 y
+	 if [ "$CONFIG_MAC" = "y" ]; then
+	    if [ "$CONFIG_FBCON_FONTWIDTH8_ONLY" = "n" ]; then
+	       define_bool CONFIG_FONT_6x11 y
+	    fi
+	 fi
+	 if [ "$CONFIG_AMIGA" = "y" ]; then
+	    define_bool CONFIG_FONT_PEARL_8x8 y
+	 fi
+	 if [ "$CONFIG_ARM" = "y" -a "$CONFIG_ARCH_ACORN" = "y" ]; then
+	    define_bool CONFIG_FONT_ACORN_8x8 y
+	 fi
+      fi
+   fi
+fi
+
+endmenu
diff -ruN linux-2.6.0.org/arch/m32r/drivers/video/Makefile linux-2.6.0/arch/m32r/drivers/video/Makefile
--- linux-2.6.0.org/arch/m32r/drivers/video/Makefile	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.0/arch/m32r/drivers/video/Makefile	2003-09-09 10:15:02.000000000 +0900
@@ -0,0 +1,161 @@
+# Makefile for the Linux video drivers.
+# 5 Aug 1999, James Simmons, <mailto:jsimmons@edgeglobal.com>
+# Rewritten to use lists instead of if-statements.
+
+O_TARGET := video.o
+
+mod-subdirs	:= matrox
+
+# All of the (potential) objects that export symbols.
+# This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
+
+export-objs    := fbmem.o fbcmap.o fbcon.o fbmon.o modedb.o \
+		  fbcon-afb.o fbcon-ilbm.o \
+		  fbcon-vga.o fbcon-iplan2p2.o fbcon-iplan2p4.o \
+		  fbcon-iplan2p8.o fbcon-vga-planes.o fbcon-cfb16.o \
+		  fbcon-cfb2.o fbcon-cfb24.o fbcon-cfb32.o fbcon-cfb4.o \
+		  fbcon-cfb8.o fbcon-mac.o fbcon-mfb.o \
+		  cyber2000fb.o sa1100fb.o fbcon-hga.o fbgen.o
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_DUMMY_CONSOLE)       += dummycon.o
+obj-$(CONFIG_SGI_NEWPORT_CONSOLE) += newport_con.o
+obj-$(CONFIG_PROM_CONSOLE)        += promcon.o promcon_tbl.o
+obj-$(CONFIG_STI_CONSOLE)         += sticon.o sticon-bmode.o sticore.o
+obj-$(CONFIG_VGA_CONSOLE)         += vgacon.o
+obj-$(CONFIG_MDA_CONSOLE)         += mdacon.o
+
+obj-$(CONFIG_FONT_SUN8x16)        += font_sun8x16.o
+obj-$(CONFIG_FONT_SUN12x22)       += font_sun12x22.o
+obj-$(CONFIG_FONT_8x8)            += font_8x8.o
+obj-$(CONFIG_FONT_8x16)           += font_8x16.o
+obj-$(CONFIG_FONT_6x11)           += font_6x11.o
+obj-$(CONFIG_FONT_PEARL_8x8)      += font_pearl_8x8.o
+obj-$(CONFIG_FONT_ACORN_8x8)      += font_acorn_8x8.o
+
+# Add fbmon.o back into obj-$(CONFIG_FB) in 2.5.x
+obj-$(CONFIG_FB)                  += fbmem.o fbcmap.o modedb.o fbcon.o fonts.o
+# Only include macmodes.o if we have FB support and are PPC
+ifeq ($(CONFIG_FB),y)
+obj-$(CONFIG_PPC)                 += macmodes.o
+endif
+
+obj-$(CONFIG_FB_ACORN)            += acornfb.o
+obj-$(CONFIG_FB_AMIGA)            += amifb.o
+obj-$(CONFIG_FB_PM2)              += pm2fb.o fbgen.o
+obj-$(CONFIG_FB_PM3)              += pm3fb.o fbgen.o
+obj-$(CONFIG_FB_APOLLO)           += dnfb.o
+obj-$(CONFIG_FB_Q40)              += q40fb.o
+obj-$(CONFIG_FB_ATARI)            += atafb.o
+obj-$(CONFIG_FB_ATY128)           += aty128fb.o
+obj-$(CONFIG_FB_RADEON)		  += radeonfb.o
+obj-$(CONFIG_FB_NEOMAGIC)         += neofb.o
+obj-$(CONFIG_FB_IGA)              += igafb.o
+obj-$(CONFIG_FB_CONTROL)          += controlfb.o
+obj-$(CONFIG_FB_PLATINUM)         += platinumfb.o
+obj-$(CONFIG_FB_VALKYRIE)         += valkyriefb.o
+obj-$(CONFIG_FB_CT65550)          += chipsfb.o
+obj-$(CONFIG_FB_CYBER)            += cyberfb.o
+obj-$(CONFIG_FB_CYBER2000)        += cyber2000fb.o
+obj-$(CONFIG_FB_SGIVW)            += sgivwfb.o
+obj-$(CONFIG_FB_3DFX)             += tdfxfb.o
+obj-$(CONFIG_FB_MAC)              += macfb.o macmodes.o
+obj-$(CONFIG_FB_HP300)            += hpfb.o
+obj-$(CONFIG_FB_OF)               += offb.o
+obj-$(CONFIG_FB_IMSTT)            += imsttfb.o
+obj-$(CONFIG_FB_RETINAZ3)         += retz3fb.o
+obj-$(CONFIG_FB_CLGEN)            += clgenfb.o fbgen.o
+obj-$(CONFIG_FB_TRIDENT)          += tridentfb.o fbgen.o
+obj-$(CONFIG_FB_S3TRIO)           += S3triofb.o
+obj-$(CONFIG_FB_TGA)              += tgafb.o fbgen.o
+obj-$(CONFIG_FB_VESA)             += vesafb.o 
+obj-$(CONFIG_FB_VGA16)            += vga16fb.o fbcon-vga-planes.o
+obj-$(CONFIG_FB_VIRGE)            += virgefb.o
+obj-$(CONFIG_FB_G364)             += g364fb.o
+obj-$(CONFIG_FB_FM2)              += fm2fb.o
+obj-$(CONFIG_FB_CREATOR)          += creatorfb.o sbusfb.o
+obj-$(CONFIG_FB_CGSIX)            += cgsixfb.o sbusfb.o
+obj-$(CONFIG_FB_BWTWO)            += bwtwofb.o sbusfb.o
+obj-$(CONFIG_FB_CGTHREE)          += cgthreefb.o sbusfb.o
+obj-$(CONFIG_FB_TCX)              += tcxfb.o sbusfb.o
+obj-$(CONFIG_FB_CGFOURTEEN)       += cgfourteenfb.o sbusfb.o
+obj-$(CONFIG_FB_P9100)            += p9100fb.o sbusfb.o
+obj-$(CONFIG_FB_LEO)              += leofb.o sbusfb.o
+obj-$(CONFIG_FB_STI)	          += stifb.o sticore.o fbgen.o
+obj-$(CONFIG_FB_PMAG_BA)          += pmag-ba-fb.o
+obj-$(CONFIG_FB_PMAGB_B)          += pmagb-b-fb.o
+obj-$(CONFIG_FB_MAXINE)           += maxinefb.o
+obj-$(CONFIG_FB_TX3912)           += tx3912fb.o
+
+
+subdir-$(CONFIG_FB_MATROX)	  += matrox
+ifeq ($(CONFIG_FB_MATROX),y)
+obj-y				  += matrox/matrox.o
+endif
+
+subdir-$(CONFIG_FB_RIVA)	  += riva
+ifeq ($(CONFIG_FB_RIVA),y)
+obj-y				  += riva/rivafb.o
+endif
+
+subdir-$(CONFIG_FB_SIS)		  += sis
+ifeq ($(CONFIG_FB_SIS),y)
+obj-y				  += sis/sisfb.o
+endif
+
+subdir-$(CONFIG_FB_ATY)		  += aty
+ifeq ($(CONFIG_FB_ATY),y)
+obj-y				  += aty/atyfb.o
+endif
+
+#if 1 /* 020117 */
+obj-$(CONFIG_FB_EPSON)            += s1d13xxxfb.o fbgen.o fbcon-cfb8.o
+#endif /* 020117 */
+
+
+obj-$(CONFIG_FB_SUN3)             += sun3fb.o
+obj-$(CONFIG_FB_BWTWO)            += bwtwofb.o
+obj-$(CONFIG_FB_HGA)              += hgafb.o  
+obj-$(CONFIG_FB_SA1100)           += sa1100fb.o
+obj-$(CONFIG_FB_VIRTUAL)          += vfb.o  
+obj-$(CONFIG_FB_HIT)              += hitfb.o fbgen.o
+obj-$(CONFIG_FB_E1355)            += epson1355fb.o fbgen.o
+obj-$(CONFIG_FB_PVR2)             += pvr2fb.o
+obj-$(CONFIG_FB_VOODOO1)          += sstfb.o
+
+# Generic Low Level Drivers
+
+obj-$(CONFIG_FBCON_AFB)           += fbcon-afb.o
+obj-$(CONFIG_FBCON_CFB2)          += fbcon-cfb2.o
+obj-$(CONFIG_FBCON_CFB4)          += fbcon-cfb4.o
+obj-$(CONFIG_FBCON_CFB8)          += fbcon-cfb8.o
+obj-$(CONFIG_FBCON_CFB16)         += fbcon-cfb16.o
+obj-$(CONFIG_FBCON_CFB24)         += fbcon-cfb24.o
+obj-$(CONFIG_FBCON_CFB32)         += fbcon-cfb32.o
+obj-$(CONFIG_FBCON_ILBM)          += fbcon-ilbm.o
+obj-$(CONFIG_FBCON_IPLAN2P2)      += fbcon-iplan2p2.o
+obj-$(CONFIG_FBCON_IPLAN2P4)      += fbcon-iplan2p4.o
+obj-$(CONFIG_FBCON_IPLAN2P8)      += fbcon-iplan2p8.o
+obj-$(CONFIG_FBCON_IPLAN2P16)     += fbcon-iplan2p16.o
+obj-$(CONFIG_FBCON_MAC)           += fbcon-mac.o
+obj-$(CONFIG_FBCON_MFB)           += fbcon-mfb.o
+obj-$(CONFIG_FBCON_VGA)           += fbcon-vga.o
+obj-$(CONFIG_FBCON_HGA)           += fbcon-hga.o
+obj-$(CONFIG_FBCON_STI)           += fbcon-sti.o
+
+include $(TOPDIR)/Rules.make
+
+clean:
+	rm -f core *.o *.a *.s
+
+../conmakehash: ../conmakehash.c
+	$(HOSTCC) $(HOSTCFLAGS) -o ../conmakehash ../conmakehash.c
+
+promcon_tbl.c: prom.uni ../char/conmakehash
+	../char/conmakehash prom.uni | \
+	sed -e '/#include <[^>]*>/p' -e 's/types/init/' \
+	    -e 's/dfont\(_uni.*\]\)/promfont\1 __initdata/' > promcon_tbl.c
+
+promcon_tbl.o: promcon_tbl.c $(TOPDIR)/include/linux/types.h
+
diff -ruN linux-2.6.0.org/arch/m32r/drivers/video/README linux-2.6.0/arch/m32r/drivers/video/README
--- linux-2.6.0.org/arch/m32r/drivers/video/README	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.0/arch/m32r/drivers/video/README	2003-09-09 10:15:02.000000000 +0900
@@ -0,0 +1,41 @@
+EPSON S1D13806 driver for Mappi and M32700UT
+
+installing driver
+=================
+
+ $ cd arch/m32r/drivers/video
+ $ sh setup_video
+
+make xconfig
+============
+
+Character devices
+ [*] Virtual terminal
+ [*]   Support for console on virtual terminal
+
+Console drivers
+Frame-buffer support --->
+ [*] Support for frame buffer devices (EXPERIMENTAL)
+ [*] Epson LCD/CRT/TV controller support
+ [*]    Epson S1D13806 Support
+        [*] Advanced low level driver options
+        [*] 8 bpp packed pixels support		# say y if you use mappi
+        [*] 16 bpp packed pixels support	# say y if you use m32700ut
+
+
+.config
+=======
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_VGA_CONSOLE=y
+CONFIG_FB=y
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FB_EPSON=y
+CONFIG_FBCON_EPSON=y
+CONFIG_FB_EPSON_S1D13806=y
+CONFIG_FBCON_EPSON_S1D13806=y
+CONFIG_FBCON_ADVANCED=y
+CONFIG_FBCON_CFB8=y		# say y if you use mappi
+CONFIG_FBCON_CFB16=y		# say y if you use m32700ut
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
diff -ruN linux-2.6.0.org/arch/m32r/drivers/video/console.c linux-2.6.0/arch/m32r/drivers/video/console.c
--- linux-2.6.0.org/arch/m32r/drivers/video/console.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.0/arch/m32r/drivers/video/console.c	2003-09-09 10:15:02.000000000 +0900
@@ -0,0 +1,3085 @@
+/*
+ *  linux/drivers/char/console.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+/*
+ * Hopefully this will be a rather complete VT102 implementation.
+ *
+ * Beeping thanks to John T Kohl.
+ *
+ * Virtual Consoles, Screen Blanking, Screen Dumping, Color, Graphics
+ *   Chars, and VT100 enhancements by Peter MacDonald.
+ *
+ * Copy and paste function by Andrew Haylett,
+ *   some enhancements by Alessandro Rubini.
+ *
+ * Code to check for different video-cards mostly by Galen Hunt,
+ * <g-hunt@ee.utah.edu>
+ *
+ * Rudimentary ISO 10646/Unicode/UTF-8 character set support by
+ * Markus Kuhn, <mskuhn@immd4.informatik.uni-erlangen.de>.
+ *
+ * Dynamic allocation of consoles, aeb@cwi.nl, May 1994
+ * Resizing of consoles, aeb, 940926
+ *
+ * Code for xterm like mouse click reporting by Peter Orbaek 20-Jul-94
+ * <poe@daimi.aau.dk>
+ *
+ * User-defined bell sound, new setterm control sequences and printk
+ * redirection by Martin Mares <mj@k332.feld.cvut.cz> 19-Nov-95
+ *
+ * APM screenblank bug fixed Takashi Manabe <manabe@roy.dsl.tutics.tut.jp>
+ *
+ * Merge with the abstract console driver by Geert Uytterhoeven
+ * <geert@linux-m68k.org>, Jan 1997.
+ *
+ *   Original m68k console driver modifications by
+ *
+ *     - Arno Griffioen <arno@usn.nl>
+ *     - David Carter <carter@cs.bris.ac.uk>
+ * 
+ *   Note that the abstract console driver allows all consoles to be of
+ *   potentially different sizes, so the following variables depend on the
+ *   current console (currcons):
+ *
+ *     - video_num_columns
+ *     - video_num_lines
+ *     - video_size_row
+ *     - can_do_color
+ *
+ *   The abstract console driver provides a generic interface for a text
+ *   console. It supports VGA text mode, frame buffer based graphical consoles
+ *   and special graphics processors that are only accessible through some
+ *   registers (e.g. a TMS340x0 GSP).
+ *
+ *   The interface to the hardware is specified using a special structure
+ *   (struct consw) which contains function pointers to console operations
+ *   (see <linux/console.h> for more information).
+ *
+ * Support for changeable cursor shape
+ * by Pavel Machek <pavel@atrey.karlin.mff.cuni.cz>, August 1997
+ *
+ * Ported to i386 and con_scrolldelta fixed
+ * by Emmanuel Marty <core@ggi-project.org>, April 1998
+ *
+ * Resurrected character buffers in videoram plus lots of other trickery
+ * by Martin Mares <mj@atrey.karlin.mff.cuni.cz>, July 1998
+ *
+ * Removed old-style timers, introduced console_timer, made timer
+ * deletion SMP-safe.  17Jun00, Andrew Morton <andrewm@uow.edu.au>
+ *
+ * Removed console_lock, enabled interrupts across all console operations
+ * 13 March 2001, Andrew Morton
+ *
+ * Fix over-execution of ksoftirq_CPUx for the Mappi/M32R target
+ * by Hirokazu Takata, January 2003.
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/kd.h>
+#include <linux/slab.h>
+#include <linux/major.h>
+#include <linux/mm.h>
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/vt_kern.h>
+#include <linux/selection.h>
+#include <linux/console_struct.h>
+#include <linux/kbd_kern.h>
+#include <linux/consolemap.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/tqueue.h>
+#include <linux/bootmem.h>
+#include <linux/pm.h>
+#include <linux/smp_lock.h>
+
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+
+#include "console_macros.h"
+
+#ifdef CONFIG_PLAT_MAPPI
+#define set_leds()
+#endif
+#ifdef CONFIG_PLAT_M32700UT
+#define set_leds()
+#endif
+
+const struct consw *conswitchp;
+
+/* A bitmap for codes <32. A bit of 1 indicates that the code
+ * corresponding to that bit number invokes some special action
+ * (such as cursor movement) and should not be displayed as a
+ * glyph unless the disp_ctrl mode is explicitly enabled.
+ */
+#define CTRL_ACTION 0x0d00ff81
+#define CTRL_ALWAYS 0x0800f501	/* Cannot be overridden by disp_ctrl */
+
+/*
+ * Here is the default bell parameters: 750HZ, 1/8th of a second
+ */
+#define DEFAULT_BELL_PITCH	750
+#define DEFAULT_BELL_DURATION	(HZ/8)
+
+extern void vcs_make_devfs (unsigned int index, int unregister);
+
+#ifndef MIN
+#define MIN(a,b)	((a) < (b) ? (a) : (b))
+#endif
+
+static struct tty_struct *console_table[MAX_NR_CONSOLES];
+static struct termios *console_termios[MAX_NR_CONSOLES];
+static struct termios *console_termios_locked[MAX_NR_CONSOLES];
+struct vc vc_cons [MAX_NR_CONSOLES];
+
+#ifndef VT_SINGLE_DRIVER
+static const struct consw *con_driver_map[MAX_NR_CONSOLES];
+#endif
+
+static int con_open(struct tty_struct *, struct file *);
+static void vc_init(unsigned int console, unsigned int rows,
+		    unsigned int cols, int do_clear);
+static void blank_screen(unsigned long dummy);
+static void gotoxy(int currcons, int new_x, int new_y);
+static void save_cur(int currcons);
+static void reset_terminal(int currcons, int do_clear);
+static void con_flush_chars(struct tty_struct *tty);
+static void set_vesa_blanking(unsigned long arg);
+static void set_cursor(int currcons);
+static void hide_cursor(int currcons);
+static void unblank_screen_t(unsigned long dummy);
+static void console_callback(void *ignored);
+
+static int printable;		/* Is console ready for printing? */
+
+int do_poke_blanked_console;
+int console_blanked;
+
+static int vesa_blank_mode; /* 0:none 1:suspendV 2:suspendH 3:powerdown */
+static int blankinterval = 10*60*HZ;
+static int vesa_off_interval;
+
+static struct tq_struct console_callback_tq = {
+	routine: console_callback,
+};
+
+/*
+ * fg_console is the current virtual console,
+ * last_console is the last used one,
+ * want_console is the console we want to switch to,
+ * kmsg_redirect is the console for kernel messages,
+ */
+int fg_console;
+int last_console;
+int want_console = -1;
+int kmsg_redirect;
+
+/*
+ * For each existing display, we have a pointer to console currently visible
+ * on that display, allowing consoles other than fg_console to be refreshed
+ * appropriately. Unless the low-level driver supplies its own display_fg
+ * variable, we use this one for the "master display".
+ */
+static struct vc_data *master_display_fg;
+
+/*
+ * Unfortunately, we need to delay tty echo when we're currently writing to the
+ * console since the code is (and always was) not re-entrant, so we schedule
+ * all flip requests to process context with schedule-task() and run it from
+ * console_callback().
+ */
+
+/*
+ * For the same reason, we defer scrollback to the console callback.
+ */
+static int scrollback_delta;
+
+/*
+ * Hook so that the power management routines can (un)blank
+ * the console on our behalf.
+ */
+int (*console_blank_hook)(int);
+
+static struct timer_list console_timer;
+
+/*
+ *	Low-Level Functions
+ */
+
+#define IS_FG (currcons == fg_console)
+#define IS_VISIBLE CON_IS_VISIBLE(vc_cons[currcons].d)
+
+#ifdef VT_BUF_VRAM_ONLY
+#define DO_UPDATE 0
+#else
+#define DO_UPDATE IS_VISIBLE
+#endif
+
+static int pm_con_request(struct pm_dev *dev, pm_request_t rqst, void *data);
+static struct pm_dev *pm_con;
+
+static inline unsigned short *screenpos(int currcons, int offset, int viewed)
+{
+	unsigned short *p;
+	
+	if (!viewed)
+		p = (unsigned short *)(origin + offset);
+	else if (!sw->con_screen_pos)
+		p = (unsigned short *)(visible_origin + offset);
+	else
+		p = sw->con_screen_pos(vc_cons[currcons].d, offset);
+	return p;
+}
+
+static inline void scrolldelta(int lines)
+{
+	scrollback_delta += lines;
+	schedule_console_callback();
+}
+
+void schedule_console_callback(void)
+{
+	schedule_task(&console_callback_tq);
+}
+
+static void scrup(int currcons, unsigned int t, unsigned int b, int nr)
+{
+	unsigned short *d, *s;
+
+	if (t+nr >= b)
+		nr = b - t - 1;
+	if (b > video_num_lines || t >= b || nr < 1)
+		return;
+	if (IS_VISIBLE && sw->con_scroll(vc_cons[currcons].d, t, b, SM_UP, nr))
+		return;
+	d = (unsigned short *) (origin+video_size_row*t);
+	s = (unsigned short *) (origin+video_size_row*(t+nr));
+	scr_memcpyw(d, s, (b-t-nr) * video_size_row);
+	scr_memsetw(d + (b-t-nr) * video_num_columns, video_erase_char, video_size_row*nr);
+}
+
+static void
+scrdown(int currcons, unsigned int t, unsigned int b, int nr)
+{
+	unsigned short *s;
+	unsigned int step;
+
+	if (t+nr >= b)
+		nr = b - t - 1;
+	if (b > video_num_lines || t >= b || nr < 1)
+		return;
+	if (IS_VISIBLE && sw->con_scroll(vc_cons[currcons].d, t, b, SM_DOWN, nr))
+		return;
+	s = (unsigned short *) (origin+video_size_row*t);
+	step = video_num_columns * nr;
+	scr_memmovew(s + step, s, (b-t-nr)*video_size_row);
+	scr_memsetw(s, video_erase_char, 2*step);
+}
+
+static void do_update_region(int currcons, unsigned long start, int count)
+{
+#ifndef VT_BUF_VRAM_ONLY
+	unsigned int xx, yy, offset;
+	u16 *p;
+
+	p = (u16 *) start;
+	if (!sw->con_getxy) {
+		offset = (start - origin) / 2;
+		xx = offset % video_num_columns;
+		yy = offset / video_num_columns;
+	} else {
+		int nxx, nyy;
+		start = sw->con_getxy(vc_cons[currcons].d, start, &nxx, &nyy);
+		xx = nxx; yy = nyy;
+	}
+	for(;;) {
+		u16 attrib = scr_readw(p) & 0xff00;
+		int startx = xx;
+		u16 *q = p;
+		while (xx < video_num_columns && count) {
+			if (attrib != (scr_readw(p) & 0xff00)) {
+				if (p > q)
+					sw->con_putcs(vc_cons[currcons].d, q, p-q, yy, startx);
+				startx = xx;
+				q = p;
+				attrib = scr_readw(p) & 0xff00;
+			}
+			p++;
+			xx++;
+			count--;
+		}
+		if (p > q)
+			sw->con_putcs(vc_cons[currcons].d, q, p-q, yy, startx);
+		if (!count)
+			break;
+		xx = 0;
+		yy++;
+		if (sw->con_getxy) {
+			p = (u16 *)start;
+			start = sw->con_getxy(vc_cons[currcons].d, start, NULL, NULL);
+		}
+	}
+#endif
+}
+
+void update_region(int currcons, unsigned long start, int count)
+{
+	if (DO_UPDATE) {
+		hide_cursor(currcons);
+		do_update_region(currcons, start, count);
+		set_cursor(currcons);
+	}
+}
+
+/* Structure of attributes is hardware-dependent */
+
+static u8 build_attr(int currcons, u8 _color, u8 _intensity, u8 _blink, u8 _underline, u8 _reverse)
+{
+	if (sw->con_build_attr)
+		return sw->con_build_attr(vc_cons[currcons].d, _color, _intensity, _blink, _underline, _reverse);
+
+#ifndef VT_BUF_VRAM_ONLY
+/*
+ * ++roman: I completely changed the attribute format for monochrome
+ * mode (!can_do_color). The formerly used MDA (monochrome display
+ * adapter) format didn't allow the combination of certain effects.
+ * Now the attribute is just a bit vector:
+ *  Bit 0..1: intensity (0..2)
+ *  Bit 2   : underline
+ *  Bit 3   : reverse
+ *  Bit 7   : blink
+ */
+	{
+	u8 a = color;
+	if (!can_do_color)
+		return _intensity |
+		       (_underline ? 4 : 0) |
+		       (_reverse ? 8 : 0) |
+		       (_blink ? 0x80 : 0);
+	if (_underline)
+		a = (a & 0xf0) | ulcolor;
+	else if (_intensity == 0)
+		a = (a & 0xf0) | halfcolor;
+	if (_reverse)
+		a = ((a) & 0x88) | ((((a) >> 4) | ((a) << 4)) & 0x77);
+	if (_blink)
+		a ^= 0x80;
+	if (_intensity == 2)
+		a ^= 0x08;
+	if (hi_font_mask == 0x100)
+		a <<= 1;
+	return a;
+	}
+#else
+	return 0;
+#endif
+}
+
+static void update_attr(int currcons)
+{
+	attr = build_attr(currcons, color, intensity, blink, underline, reverse ^ decscnm);
+	video_erase_char = (build_attr(currcons, color, 1, blink, 0, decscnm) << 8) | ' ';
+}
+
+/* Note: inverting the screen twice should revert to the original state */
+
+void invert_screen(int currcons, int offset, int count, int viewed)
+{
+	unsigned short *p;
+
+	count /= 2;
+	p = screenpos(currcons, offset, viewed);
+	if (sw->con_invert_region)
+		sw->con_invert_region(vc_cons[currcons].d, p, count);
+#ifndef VT_BUF_VRAM_ONLY
+	else {
+		u16 *q = p;
+		int cnt = count;
+		u16 a;
+
+		if (!can_do_color) {
+			while (cnt--) {
+			    a = scr_readw(q);
+			    a ^= 0x0800;
+			    scr_writew(a, q);
+			    q++;
+			}
+		} else if (hi_font_mask == 0x100) {
+			while (cnt--) {
+				a = scr_readw(q);
+				a = ((a) & 0x11ff) | (((a) & 0xe000) >> 4) | (((a) & 0x0e00) << 4);
+				scr_writew(a, q);
+				q++;
+			}
+		} else {
+			while (cnt--) {
+				a = scr_readw(q);
+				a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4);
+				scr_writew(a, q);
+				q++;
+			}
+		}
+	}
+#endif
+	if (DO_UPDATE)
+		do_update_region(currcons, (unsigned long) p, count);
+}
+
+/* used by selection: complement pointer position */
+void complement_pos(int currcons, int offset)
+{
+	static unsigned short *p;
+	static unsigned short old;
+	static unsigned short oldx, oldy;
+
+	if (p) {
+		scr_writew(old, p);
+		if (DO_UPDATE)
+			sw->con_putc(vc_cons[currcons].d, old, oldy, oldx);
+	}
+	if (offset == -1)
+		p = NULL;
+	else {
+		unsigned short new;
+		p = screenpos(currcons, offset, 1);
+		old = scr_readw(p);
+		new = old ^ complement_mask;
+		scr_writew(new, p);
+		if (DO_UPDATE) {
+			oldx = (offset >> 1) % video_num_columns;
+			oldy = (offset >> 1) / video_num_columns;
+			sw->con_putc(vc_cons[currcons].d, new, oldy, oldx);
+		}
+	}
+}
+
+static void insert_char(int currcons, unsigned int nr)
+{
+	unsigned short *p, *q = (unsigned short *) pos;
+
+	p = q + video_num_columns - nr - x;
+	while (--p >= q)
+		scr_writew(scr_readw(p), p + nr);
+	scr_memsetw(q, video_erase_char, nr*2);
+	need_wrap = 0;
+	if (DO_UPDATE) {
+		unsigned short oldattr = attr;
+		sw->con_bmove(vc_cons[currcons].d,y,x,y,x+nr,1,
+			      video_num_columns-x-nr);
+		attr = video_erase_char >> 8;
+		while (nr--)
+			sw->con_putc(vc_cons[currcons].d,
+				     video_erase_char,y,x+nr);
+		attr = oldattr;
+	}
+}
+
+static void delete_char(int currcons, unsigned int nr)
+{
+	unsigned int i = x;
+	unsigned short *p = (unsigned short *) pos;
+
+	while (++i <= video_num_columns - nr) {
+		scr_writew(scr_readw(p+nr), p);
+		p++;
+	}
+	scr_memsetw(p, video_erase_char, nr*2);
+	need_wrap = 0;
+	if (DO_UPDATE) {
+		unsigned short oldattr = attr;
+		sw->con_bmove(vc_cons[currcons].d, y, x+nr, y, x, 1,
+			      video_num_columns-x-nr);
+		attr = video_erase_char >> 8;
+		while (nr--)
+			sw->con_putc(vc_cons[currcons].d,
+				     video_erase_char, y,
+				     video_num_columns-1-nr);
+		attr = oldattr;
+	}
+}
+
+static int softcursor_original;
+
+static void add_softcursor(int currcons)
+{
+	int i = scr_readw((u16 *) pos);
+	u32 type = cursor_type;
+
+	if (! (type & 0x10)) return;
+	if (softcursor_original != -1) return;
+	softcursor_original = i;
+	i |= ((type >> 8) & 0xff00 );
+	i ^= ((type) & 0xff00 );
+	if ((type & 0x20) && ((softcursor_original & 0x7000) == (i & 0x7000))) i ^= 0x7000;
+	if ((type & 0x40) && ((i & 0x700) == ((i & 0x7000) >> 4))) i ^= 0x0700;
+	scr_writew(i, (u16 *) pos);
+	if (DO_UPDATE)
+		sw->con_putc(vc_cons[currcons].d, i, y, x);
+}
+
+static void hide_cursor(int currcons)
+{
+	if (currcons == sel_cons)
+		clear_selection();
+	if (softcursor_original != -1) {
+		scr_writew(softcursor_original,(u16 *) pos);
+		if (DO_UPDATE)
+			sw->con_putc(vc_cons[currcons].d, softcursor_original, y, x);
+		softcursor_original = -1;
+	}
+	sw->con_cursor(vc_cons[currcons].d,CM_ERASE);
+}
+
+static void set_cursor(int currcons)
+{
+    if (!IS_FG || console_blanked || vcmode == KD_GRAPHICS)
+	return;
+    if (deccm) {
+	if (currcons == sel_cons)
+		clear_selection();
+	add_softcursor(currcons);
+	if ((cursor_type & 0x0f) != 1)
+	    sw->con_cursor(vc_cons[currcons].d,CM_DRAW);
+    } else
+	hide_cursor(currcons);
+}
+
+static void set_origin(int currcons)
+{
+#if 1
+	if (!IS_VISIBLE ||
+	    !sw->con_set_origin ||
+	    !sw->con_set_origin(vc_cons[currcons].d))
+		origin = (unsigned long) screenbuf;
+#else
+	if (!IS_VISIBLE)
+		origin = (unsigned long) screenbuf; 
+	if( !sw->con_set_origin) 
+		origin = (unsigned long) screenbuf;
+	if(!sw->con_set_origin(vc_cons[currcons].d))
+		origin = (unsigned long) screenbuf;
+#endif
+	visible_origin = origin;
+	scr_end = origin + screenbuf_size;
+	pos = origin + video_size_row*y + 2*x;
+}
+
+static inline void save_screen(int currcons)
+{
+	if (sw->con_save_screen)
+		sw->con_save_screen(vc_cons[currcons].d);
+}
+
+/*
+ *	Redrawing of screen
+ */
+
+void redraw_screen(int new_console, int is_switch)
+{
+	int redraw = 1;
+	int currcons, old_console;
+
+	if (!vc_cons_allocated(new_console)) {
+		/* strange ... */
+		/* printk("redraw_screen: tty %d not allocated ??\n", new_console+1); */
+		return;
+	}
+
+	if (is_switch) {
+		currcons = fg_console;
+		hide_cursor(currcons);
+		if (fg_console != new_console) {
+			struct vc_data **display = vc_cons[new_console].d->vc_display_fg;
+			old_console = (*display) ? (*display)->vc_num : fg_console;
+			*display = vc_cons[new_console].d;
+			fg_console = new_console;
+			currcons = old_console;
+			if (!IS_VISIBLE) {
+				save_screen(currcons);
+				set_origin(currcons);
+			}
+			currcons = new_console;
+			if (old_console == new_console)
+				redraw = 0;
+		}
+	} else {
+		currcons = new_console;
+		hide_cursor(currcons);
+	}
+
+	if (redraw) {
+		int update;
+		set_origin(currcons);
+		update = sw->con_switch(vc_cons[currcons].d);
+		set_palette(currcons);
+		if (update && vcmode != KD_GRAPHICS)
+			do_update_region(currcons, origin, screenbuf_size/2);
+	}
+	set_cursor(currcons);
+	if (is_switch) {
+		set_leds();
+		compute_shiftstate();
+	}
+}
+
+/*
+ *	Allocation, freeing and resizing of VTs.
+ */
+
+int vc_cons_allocated(unsigned int i)
+{
+	return (i < MAX_NR_CONSOLES && vc_cons[i].d);
+}
+
+static void visual_init(int currcons, int init)
+{
+    /* ++Geert: sw->con_init determines console size */
+    sw = conswitchp;
+#ifndef VT_SINGLE_DRIVER
+    if (con_driver_map[currcons])
+	sw = con_driver_map[currcons];
+#endif
+    cons_num = currcons;
+    display_fg = &master_display_fg;
+    vc_cons[currcons].d->vc_uni_pagedir_loc = &vc_cons[currcons].d->vc_uni_pagedir;
+    vc_cons[currcons].d->vc_uni_pagedir = 0;
+    hi_font_mask = 0;
+    complement_mask = 0;
+    can_do_color = 0;
+    sw->con_init(vc_cons[currcons].d, init);
+    if (!complement_mask)
+        complement_mask = can_do_color ? 0x7700 : 0x0800;
+    s_complement_mask = complement_mask;
+    video_size_row = video_num_columns<<1;
+    screenbuf_size = video_num_lines*video_size_row;
+}
+
+int vc_allocate(unsigned int currcons)	/* return 0 on success */
+{
+	if (currcons >= MAX_NR_CONSOLES)
+		return -ENXIO;
+	if (!vc_cons[currcons].d) {
+	    long p, q;
+
+	    /* prevent users from taking too much memory */
+	    if (currcons >= MAX_NR_USER_CONSOLES && !capable(CAP_SYS_RESOURCE))
+	      return -EPERM;
+
+	    /* due to the granularity of kmalloc, we waste some memory here */
+	    /* the alloc is done in two steps, to optimize the common situation
+	       of a 25x80 console (structsize=216, screenbuf_size=4000) */
+	    /* although the numbers above are not valid since long ago, the
+	       point is still up-to-date and the comment still has its value
+	       even if only as a historical artifact.  --mj, July 1998 */
+	    p = (long) kmalloc(structsize, GFP_KERNEL);
+	    if (!p)
+		return -ENOMEM;
+	    memset((void *)p, 0, structsize);
+	    vc_cons[currcons].d = (struct vc_data *)p;
+	    vt_cons[currcons] = (struct vt_struct *)(p+sizeof(struct vc_data));
+	    visual_init(currcons, 1);
+	    if (!*vc_cons[currcons].d->vc_uni_pagedir_loc)
+		con_set_default_unimap(currcons);
+	    q = (long)kmalloc(screenbuf_size, GFP_KERNEL);
+	    if (!q) {
+		kfree((char *) p);
+		vc_cons[currcons].d = NULL;
+		vt_cons[currcons] = NULL;
+		return -ENOMEM;
+	    }
+	    screenbuf = (unsigned short *) q;
+	    kmalloced = 1;
+	    vc_init(currcons, video_num_lines, video_num_columns, 1);
+
+	    if (!pm_con) {
+		    pm_con = pm_register(PM_SYS_DEV,
+					 PM_SYS_VGA,
+					 pm_con_request);
+	    }
+	}
+	return 0;
+}
+
+/*
+ * Change # of rows and columns (0 means unchanged/the size of fg_console)
+ * [this is to be used together with some user program
+ * like resize that changes the hardware videomode]
+ */
+int vc_resize(unsigned int lines, unsigned int cols,
+	      unsigned int first, unsigned int last)
+{
+	unsigned int cc, ll, ss, sr, todo = 0;
+	unsigned int currcons = fg_console, i;
+	unsigned short *newscreens[MAX_NR_CONSOLES];
+
+	cc = (cols ? cols : video_num_columns);
+	ll = (lines ? lines : video_num_lines);
+	sr = cc << 1;
+	ss = sr * ll;
+
+ 	for (currcons = first; currcons <= last; currcons++) {
+		if (!vc_cons_allocated(currcons) ||
+		    (cc == video_num_columns && ll == video_num_lines))
+			newscreens[currcons] = NULL;
+		else {
+			unsigned short *p = (unsigned short *) kmalloc(ss, GFP_USER);
+			if (!p) {
+				for (i = first; i < currcons; i++)
+					if (newscreens[i])
+						kfree(newscreens[i]);
+				return -ENOMEM;
+			}
+			newscreens[currcons] = p;
+			todo++;
+		}
+	}
+	if (!todo)
+		return 0;
+
+	for (currcons = first; currcons <= last; currcons++) {
+		unsigned int occ, oll, oss, osr;
+		unsigned long ol, nl, nlend, rlth, rrem;
+		if (!newscreens[currcons] || !vc_cons_allocated(currcons))
+			continue;
+
+		oll = video_num_lines;
+		occ = video_num_columns;
+		osr = video_size_row;
+		oss = screenbuf_size;
+
+		video_num_lines = ll;
+		video_num_columns = cc;
+		video_size_row = sr;
+		screenbuf_size = ss;
+
+		rlth = MIN(osr, sr);
+		rrem = sr - rlth;
+		ol = origin;
+		nl = (long) newscreens[currcons];
+		nlend = nl + ss;
+		if (ll < oll)
+			ol += (oll - ll) * osr;
+
+		update_attr(currcons);
+
+		while (ol < scr_end) {
+			scr_memcpyw((unsigned short *) nl, (unsigned short *) ol, rlth);
+			if (rrem)
+				scr_memsetw((void *)(nl + rlth), video_erase_char, rrem);
+			ol += osr;
+			nl += sr;
+		}
+		if (nlend > nl)
+			scr_memsetw((void *) nl, video_erase_char, nlend - nl);
+		if (kmalloced)
+			kfree(screenbuf);
+		screenbuf = newscreens[currcons];
+		kmalloced = 1;
+		screenbuf_size = ss;
+		set_origin(currcons);
+
+		/* do part of a reset_terminal() */
+		top = 0;
+		bottom = video_num_lines;
+		gotoxy(currcons, x, y);
+		save_cur(currcons);
+
+		if (console_table[currcons]) {
+			struct winsize ws, *cws = &console_table[currcons]->winsize;
+			memset(&ws, 0, sizeof(ws));
+			ws.ws_row = video_num_lines;
+			ws.ws_col = video_num_columns;
+			if ((ws.ws_row != cws->ws_row || ws.ws_col != cws->ws_col) &&
+			    console_table[currcons]->pgrp > 0)
+				kill_pg(console_table[currcons]->pgrp, SIGWINCH, 1);
+			*cws = ws;
+		}
+
+		if (IS_VISIBLE)
+			update_screen(currcons);
+	}
+
+	return 0;
+}
+
+
+void vc_disallocate(unsigned int currcons)
+{
+	acquire_console_sem();
+	if (vc_cons_allocated(currcons)) {
+	    sw->con_deinit(vc_cons[currcons].d);
+	    if (kmalloced)
+		kfree(screenbuf);
+	    if (currcons >= MIN_NR_CONSOLES)
+		kfree(vc_cons[currcons].d);
+	    vc_cons[currcons].d = NULL;
+	}
+	release_console_sem();
+}
+
+/*
+ *	VT102 emulator
+ */
+
+#define set_kbd(x) set_vc_kbd_mode(kbd_table+currcons,x)
+#define clr_kbd(x) clr_vc_kbd_mode(kbd_table+currcons,x)
+#define is_kbd(x) vc_kbd_mode(kbd_table+currcons,x)
+
+#define decarm		VC_REPEAT
+#define decckm		VC_CKMODE
+#define kbdapplic	VC_APPLIC
+#define lnm		VC_CRLF
+
+/*
+ * this is what the terminal answers to a ESC-Z or csi0c query.
+ */
+#define VT100ID "\033[?1;2c"
+#define VT102ID "\033[?6c"
+
+unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7,
+				       8,12,10,14, 9,13,11,15 };
+
+/* the default colour table, for VGA+ colour systems */
+int default_red[] = {0x00,0xaa,0x00,0xaa,0x00,0xaa,0x00,0xaa,
+    0x55,0xff,0x55,0xff,0x55,0xff,0x55,0xff};
+int default_grn[] = {0x00,0x00,0xaa,0x55,0x00,0x00,0xaa,0xaa,
+    0x55,0x55,0xff,0xff,0x55,0x55,0xff,0xff};
+int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,
+    0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff};
+
+/*
+ * gotoxy() must verify all boundaries, because the arguments
+ * might also be negative. If the given position is out of
+ * bounds, the cursor is placed at the nearest margin.
+ */
+static void gotoxy(int currcons, int new_x, int new_y)
+{
+	int min_y, max_y;
+
+	if (new_x < 0)
+		x = 0;
+	else
+		if (new_x >= video_num_columns)
+			x = video_num_columns - 1;
+		else
+			x = new_x;
+ 	if (decom) {
+		min_y = top;
+		max_y = bottom;
+	} else {
+		min_y = 0;
+		max_y = video_num_lines;
+	}
+	if (new_y < min_y)
+		y = min_y;
+	else if (new_y >= max_y)
+		y = max_y - 1;
+	else
+		y = new_y;
+	pos = origin + y*video_size_row + (x<<1);
+	need_wrap = 0;
+}
+
+/* for absolute user moves, when decom is set */
+static void gotoxay(int currcons, int new_x, int new_y)
+{
+	gotoxy(currcons, new_x, decom ? (top+new_y) : new_y);
+}
+
+void scrollback(int lines)
+{
+	int currcons = fg_console;
+
+	if (!lines)
+		lines = video_num_lines/2;
+	scrolldelta(-lines);
+}
+
+void scrollfront(int lines)
+{
+	int currcons = fg_console;
+
+	if (!lines)
+		lines = video_num_lines/2;
+	scrolldelta(lines);
+}
+
+static void lf(int currcons)
+{
+    	/* don't scroll if above bottom of scrolling region, or
+	 * if below scrolling region
+	 */
+    	if (y+1 == bottom)
+		scrup(currcons,top,bottom,1);
+	else if (y < video_num_lines-1) {
+	    	y++;
+		pos += video_size_row;
+	}
+	need_wrap = 0;
+}
+
+static void ri(int currcons)
+{
+    	/* don't scroll if below top of scrolling region, or
+	 * if above scrolling region
+	 */
+	if (y == top)
+		scrdown(currcons,top,bottom,1);
+	else if (y > 0) {
+		y--;
+		pos -= video_size_row;
+	}
+	need_wrap = 0;
+}
+
+static inline void cr(int currcons)
+{
+	pos -= x<<1;
+	need_wrap = x = 0;
+}
+
+static inline void bs(int currcons)
+{
+	if (x) {
+		pos -= 2;
+		x--;
+		need_wrap = 0;
+	}
+}
+
+static inline void del(int currcons)
+{
+	/* ignored */
+}
+
+static void csi_J(int currcons, int vpar)
+{
+	unsigned int count;
+	unsigned short * start;
+
+	switch (vpar) {
+		case 0:	/* erase from cursor to end of display */
+			count = (scr_end-pos)>>1;
+			start = (unsigned short *) pos;
+			if (DO_UPDATE) {
+				/* do in two stages */
+				sw->con_clear(vc_cons[currcons].d, y, x, 1,
+					      video_num_columns-x);
+				sw->con_clear(vc_cons[currcons].d, y+1, 0,
+					      video_num_lines-y-1,
+					      video_num_columns);
+			}
+			break;
+		case 1:	/* erase from start to cursor */
+			count = ((pos-origin)>>1)+1;
+			start = (unsigned short *) origin;
+			if (DO_UPDATE) {
+				/* do in two stages */
+				sw->con_clear(vc_cons[currcons].d, 0, 0, y,
+					      video_num_columns);
+				sw->con_clear(vc_cons[currcons].d, y, 0, 1,
+					      x + 1);
+			}
+			break;
+		case 2: /* erase whole display */
+			count = video_num_columns * video_num_lines;
+			start = (unsigned short *) origin;
+			if (DO_UPDATE)
+				sw->con_clear(vc_cons[currcons].d, 0, 0,
+					      video_num_lines,
+					      video_num_columns);
+			break;
+		default:
+			return;
+	}
+	scr_memsetw(start, video_erase_char, 2*count);
+	need_wrap = 0;
+}
+
+static void csi_K(int currcons, int vpar)
+{
+	unsigned int count;
+	unsigned short * start;
+
+	switch (vpar) {
+		case 0:	/* erase from cursor to end of line */
+			count = video_num_columns-x;
+			start = (unsigned short *) pos;
+			if (DO_UPDATE)
+				sw->con_clear(vc_cons[currcons].d, y, x, 1,
+					      video_num_columns-x);
+			break;
+		case 1:	/* erase from start of line to cursor */
+			start = (unsigned short *) (pos - (x<<1));
+			count = x+1;
+			if (DO_UPDATE)
+				sw->con_clear(vc_cons[currcons].d, y, 0, 1,
+					      x + 1);
+			break;
+		case 2: /* erase whole line */
+			start = (unsigned short *) (pos - (x<<1));
+			count = video_num_columns;
+			if (DO_UPDATE)
+				sw->con_clear(vc_cons[currcons].d, y, 0, 1,
+					      video_num_columns);
+			break;
+		default:
+			return;
+	}
+	scr_memsetw(start, video_erase_char, 2 * count);
+	need_wrap = 0;
+}
+
+static void csi_X(int currcons, int vpar) /* erase the following vpar positions */
+{					  /* not vt100? */
+	int count;
+
+	if (!vpar)
+		vpar++;
+	count = (vpar > video_num_columns-x) ? (video_num_columns-x) : vpar;
+
+	scr_memsetw((unsigned short *) pos, video_erase_char, 2 * count);
+	if (DO_UPDATE)
+		sw->con_clear(vc_cons[currcons].d, y, x, 1, count);
+	need_wrap = 0;
+}
+
+static void default_attr(int currcons)
+{
+	intensity = 1;
+	underline = 0;
+	reverse = 0;
+	blink = 0;
+	color = def_color;
+}
+
+/* console_sem is held */
+static void csi_m(int currcons)
+{
+	int i;
+
+	for (i=0;i<=npar;i++)
+		switch (par[i]) {
+			case 0:	/* all attributes off */
+				default_attr(currcons);
+				break;
+			case 1:
+				intensity = 2;
+				break;
+			case 2:
+				intensity = 0;
+				break;
+			case 4:
+				underline = 1;
+				break;
+			case 5:
+				blink = 1;
+				break;
+			case 7:
+				reverse = 1;
+				break;
+			case 10: /* ANSI X3.64-1979 (SCO-ish?)
+				  * Select primary font, don't display
+				  * control chars if defined, don't set
+				  * bit 8 on output.
+				  */
+				translate = set_translate(charset == 0
+						? G0_charset
+						: G1_charset,currcons);
+				disp_ctrl = 0;
+				toggle_meta = 0;
+				break;
+			case 11: /* ANSI X3.64-1979 (SCO-ish?)
+				  * Select first alternate font, lets
+				  * chars < 32 be displayed as ROM chars.
+				  */
+				translate = set_translate(IBMPC_MAP,currcons);
+				disp_ctrl = 1;
+				toggle_meta = 0;
+				break;
+			case 12: /* ANSI X3.64-1979 (SCO-ish?)
+				  * Select second alternate font, toggle
+				  * high bit before displaying as ROM char.
+				  */
+				translate = set_translate(IBMPC_MAP,currcons);
+				disp_ctrl = 1;
+				toggle_meta = 1;
+				break;
+			case 21:
+			case 22:
+				intensity = 1;
+				break;
+			case 24:
+				underline = 0;
+				break;
+			case 25:
+				blink = 0;
+				break;
+			case 27:
+				reverse = 0;
+				break;
+			case 38: /* ANSI X3.64-1979 (SCO-ish?)
+				  * Enables underscore, white foreground
+				  * with white underscore (Linux - use
+				  * default foreground).
+				  */
+				color = (def_color & 0x0f) | background;
+				underline = 1;
+				break;
+			case 39: /* ANSI X3.64-1979 (SCO-ish?)
+				  * Disable underline option.
+				  * Reset colour to default? It did this
+				  * before...
+				  */
+				color = (def_color & 0x0f) | background;
+				underline = 0;
+				break;
+			case 49:
+				color = (def_color & 0xf0) | foreground;
+				break;
+			default:
+				if (par[i] >= 30 && par[i] <= 37)
+					color = color_table[par[i]-30]
+						| background;
+				else if (par[i] >= 40 && par[i] <= 47)
+					color = (color_table[par[i]-40]<<4)
+						| foreground;
+				break;
+		}
+	update_attr(currcons);
+}
+
+static void respond_string(const char * p, struct tty_struct * tty)
+{
+	while (*p) {
+		tty_insert_flip_char(tty, *p, 0);
+		p++;
+	}
+	con_schedule_flip(tty);
+}
+
+static void cursor_report(int currcons, struct tty_struct * tty)
+{
+	char buf[40];
+
+	sprintf(buf, "\033[%d;%dR", y + (decom ? top+1 : 1), x+1);
+	respond_string(buf, tty);
+}
+
+static inline void status_report(struct tty_struct * tty)
+{
+	respond_string("\033[0n", tty);	/* Terminal ok */
+}
+
+static inline void respond_ID(struct tty_struct * tty)
+{
+	respond_string(VT102ID, tty);
+}
+
+void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry)
+{
+	char buf[8];
+
+	sprintf(buf, "\033[M%c%c%c", (char)(' ' + butt), (char)('!' + mrx),
+		(char)('!' + mry));
+	respond_string(buf, tty);
+}
+
+/* invoked via ioctl(TIOCLINUX) and through set_selection */
+int mouse_reporting(void)
+{
+	int currcons = fg_console;
+
+	return report_mouse;
+}
+
+/* console_sem is held */
+static void set_mode(int currcons, int on_off)
+{
+	int i;
+
+	for (i=0; i<=npar; i++)
+		if (ques) switch(par[i]) {	/* DEC private modes set/reset */
+			case 1:			/* Cursor keys send ^[Ox/^[[x */
+				if (on_off)
+					set_kbd(decckm);
+				else
+					clr_kbd(decckm);
+				break;
+			case 3:	/* 80/132 mode switch unimplemented */
+				deccolm = on_off;
+#if 0
+				(void) vc_resize(video_num_lines, deccolm ? 132 : 80);
+				/* this alone does not suffice; some user mode
+				   utility has to change the hardware regs */
+#endif
+				break;
+			case 5:			/* Inverted screen on/off */
+				if (decscnm != on_off) {
+					decscnm = on_off;
+					invert_screen(currcons, 0, screenbuf_size, 0);
+					update_attr(currcons);
+				}
+				break;
+			case 6:			/* Origin relative/absolute */
+				decom = on_off;
+				gotoxay(currcons,0,0);
+				break;
+			case 7:			/* Autowrap on/off */
+				decawm = on_off;
+				break;
+			case 8:			/* Autorepeat on/off */
+				if (on_off)
+					set_kbd(decarm);
+				else
+					clr_kbd(decarm);
+				break;
+			case 9:
+				report_mouse = on_off ? 1 : 0;
+				break;
+			case 25:		/* Cursor on/off */
+				deccm = on_off;
+				break;
+			case 1000:
+				report_mouse = on_off ? 2 : 0;
+				break;
+		} else switch(par[i]) {		/* ANSI modes set/reset */
+			case 3:			/* Monitor (display ctrls) */
+				disp_ctrl = on_off;
+				break;
+			case 4:			/* Insert Mode on/off */
+				decim = on_off;
+				break;
+			case 20:		/* Lf, Enter == CrLf/Lf */
+				if (on_off)
+					set_kbd(lnm);
+				else
+					clr_kbd(lnm);
+				break;
+		}
+}
+
+/* console_sem is held */
+static void setterm_command(int currcons)
+{
+	switch(par[0]) {
+		case 1:	/* set color for underline mode */
+			if (can_do_color && par[1] < 16) {
+				ulcolor = color_table[par[1]];
+				if (underline)
+					update_attr(currcons);
+			}
+			break;
+		case 2:	/* set color for half intensity mode */
+			if (can_do_color && par[1] < 16) {
+				halfcolor = color_table[par[1]];
+				if (intensity == 0)
+					update_attr(currcons);
+			}
+			break;
+		case 8:	/* store colors as defaults */
+			def_color = attr;
+			if (hi_font_mask == 0x100)
+				def_color >>= 1;
+			default_attr(currcons);
+			update_attr(currcons);
+			break;
+		case 9:	/* set blanking interval */
+			blankinterval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ;
+			poke_blanked_console();
+			break;
+		case 10: /* set bell frequency in Hz */
+			if (npar >= 1)
+				bell_pitch = par[1];
+			else
+				bell_pitch = DEFAULT_BELL_PITCH;
+			break;
+		case 11: /* set bell duration in msec */
+			if (npar >= 1)
+				bell_duration = (par[1] < 2000) ?
+					par[1]*HZ/1000 : 0;
+			else
+				bell_duration = DEFAULT_BELL_DURATION;
+			break;
+		case 12: /* bring specified console to the front */
+			if (par[1] >= 1 && vc_cons_allocated(par[1]-1))
+				set_console(par[1] - 1);
+			break;
+		case 13: /* unblank the screen */
+			poke_blanked_console();
+			break;
+		case 14: /* set vesa powerdown interval */
+			vesa_off_interval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ;
+			break;
+	}
+}
+
+/* console_sem is held */
+static void csi_at(int currcons, unsigned int nr)
+{
+	if (nr > video_num_columns - x)
+		nr = video_num_columns - x;
+	else if (!nr)
+		nr = 1;
+	insert_char(currcons, nr);
+}
+
+/* console_sem is held */
+static void csi_L(int currcons, unsigned int nr)
+{
+	if (nr > video_num_lines - y)
+		nr = video_num_lines - y;
+	else if (!nr)
+		nr = 1;
+	scrdown(currcons,y,bottom,nr);
+	need_wrap = 0;
+}
+
+/* console_sem is held */
+static void csi_P(int currcons, unsigned int nr)
+{
+	if (nr > video_num_columns - x)
+		nr = video_num_columns - x;
+	else if (!nr)
+		nr = 1;
+	delete_char(currcons, nr);
+}
+
+/* console_sem is held */
+static void csi_M(int currcons, unsigned int nr)
+{
+	if (nr > video_num_lines - y)
+		nr = video_num_lines - y;
+	else if (!nr)
+		nr=1;
+	scrup(currcons,y,bottom,nr);
+	need_wrap = 0;
+}
+
+/* console_sem is held (except via vc_init->reset_terminal */
+static void save_cur(int currcons)
+{
+	saved_x		= x;
+	saved_y		= y;
+	s_intensity	= intensity;
+	s_underline	= underline;
+	s_blink		= blink;
+	s_reverse	= reverse;
+	s_charset	= charset;
+	s_color		= color;
+	saved_G0	= G0_charset;
+	saved_G1	= G1_charset;
+}
+
+/* console_sem is held */
+static void restore_cur(int currcons)
+{
+	gotoxy(currcons,saved_x,saved_y);
+	intensity	= s_intensity;
+	underline	= s_underline;
+	blink		= s_blink;
+	reverse		= s_reverse;
+	charset		= s_charset;
+	color		= s_color;
+	G0_charset	= saved_G0;
+	G1_charset	= saved_G1;
+	translate	= set_translate(charset ? G1_charset : G0_charset,currcons);
+	update_attr(currcons);
+	need_wrap = 0;
+}
+
+enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey,
+	EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd,
+	ESpalette };
+
+/* console_sem is held (except via vc_init()) */
+static void reset_terminal(int currcons, int do_clear)
+{
+	top		= 0;
+	bottom		= video_num_lines;
+	vc_state	= ESnormal;
+	ques		= 0;
+	translate	= set_translate(LAT1_MAP,currcons);
+	G0_charset	= LAT1_MAP;
+	G1_charset	= GRAF_MAP;
+	charset		= 0;
+	need_wrap	= 0;
+	report_mouse	= 0;
+	utf             = 0;
+	utf_count       = 0;
+
+	disp_ctrl	= 0;
+	toggle_meta	= 0;
+
+	decscnm		= 0;
+	decom		= 0;
+	decawm		= 1;
+	deccm		= 1;
+	decim		= 0;
+
+	set_kbd(decarm);
+	clr_kbd(decckm);
+	clr_kbd(kbdapplic);
+	clr_kbd(lnm);
+	kbd_table[currcons].lockstate = 0;
+	kbd_table[currcons].slockstate = 0;
+	kbd_table[currcons].ledmode = LED_SHOW_FLAGS;
+	kbd_table[currcons].ledflagstate = kbd_table[currcons].default_ledflagstate;
+	set_leds();
+
+	cursor_type = CUR_DEFAULT;
+	complement_mask = s_complement_mask;
+
+	default_attr(currcons);
+	update_attr(currcons);
+
+	tab_stop[0]	= 0x01010100;
+	tab_stop[1]	=
+	tab_stop[2]	=
+	tab_stop[3]	=
+	tab_stop[4]	= 0x01010101;
+
+	bell_pitch = DEFAULT_BELL_PITCH;
+	bell_duration = DEFAULT_BELL_DURATION;
+
+	gotoxy(currcons,0,0);
+	save_cur(currcons);
+	if (do_clear)
+	    csi_J(currcons,2);
+}
+
+/* console_sem is held */
+static void do_con_trol(struct tty_struct *tty, unsigned int currcons, int c)
+{
+	/*
+	 *  Control characters can be used in the _middle_
+	 *  of an escape sequence.
+	 */
+	switch (c) {
+	case 0:
+		return;
+	case 7:
+		if (bell_duration)
+			kd_mksound(bell_pitch, bell_duration);
+		return;
+	case 8:
+		bs(currcons);
+		return;
+	case 9:
+		pos -= (x << 1);
+		while (x < video_num_columns - 1) {
+			x++;
+			if (tab_stop[x >> 5] & (1 << (x & 31)))
+				break;
+		}
+		pos += (x << 1);
+		return;
+	case 10: case 11: case 12:
+		lf(currcons);
+		if (!is_kbd(lnm))
+			return;
+	case 13:
+		cr(currcons);
+		return;
+	case 14:
+		charset = 1;
+		translate = set_translate(G1_charset,currcons);
+		disp_ctrl = 1;
+		return;
+	case 15:
+		charset = 0;
+		translate = set_translate(G0_charset,currcons);
+		disp_ctrl = 0;
+		return;
+	case 24: case 26:
+		vc_state = ESnormal;
+		return;
+	case 27:
+		vc_state = ESesc;
+		return;
+	case 127:
+		del(currcons);
+		return;
+	case 128+27:
+		vc_state = ESsquare;
+		return;
+	}
+	switch(vc_state) {
+	case ESesc:
+		vc_state = ESnormal;
+		switch (c) {
+		case '[':
+			vc_state = ESsquare;
+			return;
+		case ']':
+			vc_state = ESnonstd;
+			return;
+		case '%':
+			vc_state = ESpercent;
+			return;
+		case 'E':
+			cr(currcons);
+			lf(currcons);
+			return;
+		case 'M':
+			ri(currcons);
+			return;
+		case 'D':
+			lf(currcons);
+			return;
+		case 'H':
+			tab_stop[x >> 5] |= (1 << (x & 31));
+			return;
+		case 'Z':
+			respond_ID(tty);
+			return;
+		case '7':
+			save_cur(currcons);
+			return;
+		case '8':
+			restore_cur(currcons);
+			return;
+		case '(':
+			vc_state = ESsetG0;
+			return;
+		case ')':
+			vc_state = ESsetG1;
+			return;
+		case '#':
+			vc_state = EShash;
+			return;
+		case 'c':
+			reset_terminal(currcons,1);
+			return;
+		case '>':  /* Numeric keypad */
+			clr_kbd(kbdapplic);
+			return;
+		case '=':  /* Appl. keypad */
+			set_kbd(kbdapplic);
+			return;
+		}
+		return;
+	case ESnonstd:
+		if (c=='P') {   /* palette escape sequence */
+			for (npar=0; npar<NPAR; npar++)
+				par[npar] = 0 ;
+			npar = 0 ;
+			vc_state = ESpalette;
+			return;
+		} else if (c=='R') {   /* reset palette */
+			reset_palette(currcons);
+			vc_state = ESnormal;
+		} else
+			vc_state = ESnormal;
+		return;
+	case ESpalette:
+		if ( (c>='0'&&c<='9') || (c>='A'&&c<='F') || (c>='a'&&c<='f') ) {
+			par[npar++] = (c>'9' ? (c&0xDF)-'A'+10 : c-'0') ;
+			if (npar==7) {
+				int i = par[0]*3, j = 1;
+				palette[i] = 16*par[j++];
+				palette[i++] += par[j++];
+				palette[i] = 16*par[j++];
+				palette[i++] += par[j++];
+				palette[i] = 16*par[j++];
+				palette[i] += par[j];
+				set_palette(currcons);
+				vc_state = ESnormal;
+			}
+		} else
+			vc_state = ESnormal;
+		return;
+	case ESsquare:
+		for(npar = 0 ; npar < NPAR ; npar++)
+			par[npar] = 0;
+		npar = 0;
+		vc_state = ESgetpars;
+		if (c == '[') { /* Function key */
+			vc_state=ESfunckey;
+			return;
+		}
+		ques = (c=='?');
+		if (ques)
+			return;
+	case ESgetpars:
+		if (c==';' && npar<NPAR-1) {
+			npar++;
+			return;
+		} else if (c>='0' && c<='9') {
+			par[npar] *= 10;
+			par[npar] += c-'0';
+			return;
+		} else vc_state=ESgotpars;
+	case ESgotpars:
+		vc_state = ESnormal;
+		switch(c) {
+		case 'h':
+			set_mode(currcons,1);
+			return;
+		case 'l':
+			set_mode(currcons,0);
+			return;
+		case 'c':
+			if (ques) {
+				if (par[0])
+					cursor_type = par[0] | (par[1]<<8) | (par[2]<<16);
+				else
+					cursor_type = CUR_DEFAULT;
+				return;
+			}
+			break;
+		case 'm':
+			if (ques) {
+				clear_selection();
+				if (par[0])
+					complement_mask = par[0]<<8 | par[1];
+				else
+					complement_mask = s_complement_mask;
+				return;
+			}
+			break;
+		case 'n':
+			if (!ques) {
+				if (par[0] == 5)
+					status_report(tty);
+				else if (par[0] == 6)
+					cursor_report(currcons,tty);
+			}
+			return;
+		}
+		if (ques) {
+			ques = 0;
+			return;
+		}
+		switch(c) {
+		case 'G': case '`':
+			if (par[0]) par[0]--;
+			gotoxy(currcons,par[0],y);
+			return;
+		case 'A':
+			if (!par[0]) par[0]++;
+			gotoxy(currcons,x,y-par[0]);
+			return;
+		case 'B': case 'e':
+			if (!par[0]) par[0]++;
+			gotoxy(currcons,x,y+par[0]);
+			return;
+		case 'C': case 'a':
+			if (!par[0]) par[0]++;
+			gotoxy(currcons,x+par[0],y);
+			return;
+		case 'D':
+			if (!par[0]) par[0]++;
+			gotoxy(currcons,x-par[0],y);
+			return;
+		case 'E':
+			if (!par[0]) par[0]++;
+			gotoxy(currcons,0,y+par[0]);
+			return;
+		case 'F':
+			if (!par[0]) par[0]++;
+			gotoxy(currcons,0,y-par[0]);
+			return;
+		case 'd':
+			if (par[0]) par[0]--;
+			gotoxay(currcons,x,par[0]);
+			return;
+		case 'H': case 'f':
+			if (par[0]) par[0]--;
+			if (par[1]) par[1]--;
+			gotoxay(currcons,par[1],par[0]);
+			return;
+		case 'J':
+			csi_J(currcons,par[0]);
+			return;
+		case 'K':
+			csi_K(currcons,par[0]);
+			return;
+		case 'L':
+			csi_L(currcons,par[0]);
+			return;
+		case 'M':
+			csi_M(currcons,par[0]);
+			return;
+		case 'P':
+			csi_P(currcons,par[0]);
+			return;
+		case 'c':
+			if (!par[0])
+				respond_ID(tty);
+			return;
+		case 'g':
+			if (!par[0])
+				tab_stop[x >> 5] &= ~(1 << (x & 31));
+			else if (par[0] == 3) {
+				tab_stop[0] =
+					tab_stop[1] =
+					tab_stop[2] =
+					tab_stop[3] =
+					tab_stop[4] = 0;
+			}
+			return;
+		case 'm':
+			csi_m(currcons);
+			return;
+		case 'q': /* DECLL - but only 3 leds */
+			/* map 0,1,2,3 to 0,1,2,4 */
+			if (par[0] < 4)
+				setledstate(kbd_table + currcons,
+					    (par[0] < 3) ? par[0] : 4);
+			return;
+		case 'r':
+			if (!par[0])
+				par[0]++;
+			if (!par[1])
+				par[1] = video_num_lines;
+			/* Minimum allowed region is 2 lines */
+			if (par[0] < par[1] &&
+			    par[1] <= video_num_lines) {
+				top=par[0]-1;
+				bottom=par[1];
+				gotoxay(currcons,0,0);
+			}
+			return;
+		case 's':
+			save_cur(currcons);
+			return;
+		case 'u':
+			restore_cur(currcons);
+			return;
+		case 'X':
+			csi_X(currcons, par[0]);
+			return;
+		case '@':
+			csi_at(currcons,par[0]);
+			return;
+		case ']': /* setterm functions */
+			setterm_command(currcons);
+			return;
+		}
+		return;
+	case ESpercent:
+		vc_state = ESnormal;
+		switch (c) {
+		case '@':  /* defined in ISO 2022 */
+			utf = 0;
+			return;
+		case 'G':  /* prelim official escape code */
+		case '8':  /* retained for compatibility */
+			utf = 1;
+			return;
+		}
+		return;
+	case ESfunckey:
+		vc_state = ESnormal;
+		return;
+	case EShash:
+		vc_state = ESnormal;
+		if (c == '8') {
+			/* DEC screen alignment test. kludge :-) */
+			video_erase_char =
+				(video_erase_char & 0xff00) | 'E';
+			csi_J(currcons, 2);
+			video_erase_char =
+				(video_erase_char & 0xff00) | ' ';
+			do_update_region(currcons, origin, screenbuf_size/2);
+		}
+		return;
+	case ESsetG0:
+		if (c == '0')
+			G0_charset = GRAF_MAP;
+		else if (c == 'B')
+			G0_charset = LAT1_MAP;
+		else if (c == 'U')
+			G0_charset = IBMPC_MAP;
+		else if (c == 'K')
+			G0_charset = USER_MAP;
+		if (charset == 0)
+			translate = set_translate(G0_charset,currcons);
+		vc_state = ESnormal;
+		return;
+	case ESsetG1:
+		if (c == '0')
+			G1_charset = GRAF_MAP;
+		else if (c == 'B')
+			G1_charset = LAT1_MAP;
+		else if (c == 'U')
+			G1_charset = IBMPC_MAP;
+		else if (c == 'K')
+			G1_charset = USER_MAP;
+		if (charset == 1)
+			translate = set_translate(G1_charset,currcons);
+		vc_state = ESnormal;
+		return;
+	default:
+		vc_state = ESnormal;
+	}
+}
+
+/* This is a temporary buffer used to prepare a tty console write
+ * so that we can easily avoid touching user space while holding the
+ * console spinlock.  It is allocated in con_init and is shared by
+ * this code and the vc_screen read/write tty calls.
+ *
+ * We have to allocate this statically in the kernel data section
+ * since console_init (and thus con_init) are called before any
+ * kernel memory allocation is available.
+ */
+char con_buf[PAGE_SIZE];
+#define CON_BUF_SIZE	PAGE_SIZE
+DECLARE_MUTEX(con_buf_sem);
+
+/* acquires console_sem */
+static int do_con_write(struct tty_struct * tty, int from_user,
+			const unsigned char *buf, int count)
+{
+#ifdef VT_BUF_VRAM_ONLY
+#define FLUSH do { } while(0);
+#else
+#define FLUSH if (draw_x >= 0) { \
+	sw->con_putcs(vc_cons[currcons].d, (u16 *)draw_from, (u16 *)draw_to-(u16 *)draw_from, y, draw_x); \
+	draw_x = -1; \
+	}
+#endif
+
+	int c, tc, ok, n = 0, draw_x = -1;
+	unsigned int currcons;
+	unsigned long draw_from = 0, draw_to = 0;
+	struct vt_struct *vt = (struct vt_struct *)tty->driver_data;
+	u16 himask, charmask;
+	const unsigned char *orig_buf = NULL;
+	int orig_count;
+
+	if (in_interrupt())
+		return count;
+		
+	currcons = vt->vc_num;
+	if (!vc_cons_allocated(currcons)) {
+	    /* could this happen? */
+	    static int error = 0;
+	    if (!error) {
+		error = 1;
+		printk("con_write: tty %d not allocated\n", currcons+1);
+	    }
+	    return 0;
+	}
+
+	orig_buf = buf;
+	orig_count = count;
+
+	if (from_user) {
+		down(&con_buf_sem);
+
+again:
+		if (count > CON_BUF_SIZE)
+			count = CON_BUF_SIZE;
+		console_conditional_schedule();
+		if (copy_from_user(con_buf, buf, count)) {
+			n = 0; /* ?? are error codes legal here ?? */
+			goto out;
+		}
+
+		buf = con_buf;
+	}
+
+	/* At this point 'buf' is guarenteed to be a kernel buffer
+	 * and therefore no access to userspace (and therefore sleeping)
+	 * will be needed.  The con_buf_sem serializes all tty based
+	 * console rendering and vcs write/read operations.  We hold
+	 * the console spinlock during the entire write.
+	 */
+
+	acquire_console_sem();
+
+	himask = hi_font_mask;
+	charmask = himask ? 0x1ff : 0xff;
+
+	/* undraw cursor first */
+	if (IS_FG)
+		hide_cursor(currcons);
+
+	while (!tty->stopped && count) {
+		c = *buf;
+		buf++;
+		n++;
+		count--;
+
+		if (utf) {
+		    /* Combine UTF-8 into Unicode */
+		    /* Incomplete characters silently ignored */
+		    if(c > 0x7f) {
+			if (utf_count > 0 && (c & 0xc0) == 0x80) {
+				utf_char = (utf_char << 6) | (c & 0x3f);
+				utf_count--;
+				if (utf_count == 0)
+				    tc = c = utf_char;
+				else continue;
+			} else {
+				if ((c & 0xe0) == 0xc0) {
+				    utf_count = 1;
+				    utf_char = (c & 0x1f);
+				} else if ((c & 0xf0) == 0xe0) {
+				    utf_count = 2;
+				    utf_char = (c & 0x0f);
+				} else if ((c & 0xf8) == 0xf0) {
+				    utf_count = 3;
+				    utf_char = (c & 0x07);
+				} else if ((c & 0xfc) == 0xf8) {
+				    utf_count = 4;
+				    utf_char = (c & 0x03);
+				} else if ((c & 0xfe) == 0xfc) {
+				    utf_count = 5;
+				    utf_char = (c & 0x01);
+				} else
+				    utf_count = 0;
+				continue;
+			      }
+		    } else {
+		      tc = c;
+		      utf_count = 0;
+		    }
+		} else {	/* no utf */
+		  tc = translate[toggle_meta ? (c|0x80) : c];
+		}
+
+                /* If the original code was a control character we
+                 * only allow a glyph to be displayed if the code is
+                 * not normally used (such as for cursor movement) or
+                 * if the disp_ctrl mode has been explicitly enabled.
+                 * Certain characters (as given by the CTRL_ALWAYS
+                 * bitmap) are always displayed as control characters,
+                 * as the console would be pretty useless without
+                 * them; to display an arbitrary font position use the
+                 * direct-to-font zone in UTF-8 mode.
+                 */
+                ok = tc && (c >= 32 ||
+                            (!utf && !(((disp_ctrl ? CTRL_ALWAYS
+                                         : CTRL_ACTION) >> c) & 1)))
+                        && (c != 127 || disp_ctrl)
+			&& (c != 128+27);
+
+		if (vc_state == ESnormal && ok) {
+			/* Now try to find out how to display it */
+			tc = conv_uni_to_pc(vc_cons[currcons].d, tc);
+			if ( tc == -4 ) {
+                                /* If we got -4 (not found) then see if we have
+                                   defined a replacement character (U+FFFD) */
+                                tc = conv_uni_to_pc(vc_cons[currcons].d, 0xfffd);
+
+				/* One reason for the -4 can be that we just
+				   did a clear_unimap();
+				   try at least to show something. */
+				if (tc == -4)
+				     tc = c;
+              
